Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
| Download
GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
Project: cocalc-sagemath-dev-slelievre
Views: 418346/****************************************************************************1**2*W gasman.c GAP source Martin Schönert3**4**5*Y Copyright (C) 1996, Lehrstuhl D für Mathematik, RWTH Aachen, Germany6*Y (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland7*Y Copyright (C) 2002 The GAP Group8**9** This file contains the functions of Gasman, the GAP storage manager.10**11** {\Gasman} is a storage manager for applications written in C. That means12** that an application using {\Gasman} requests blocks of storage from13** {\Gasman}. Those blocks of storage are called *bags*. Then the14** application writes data into and reads data from the bags. Finally a bag15** is no longer needed and the application simply forgets it. We say that16** such a bag that is no longer needed is *dead*. {\Gasman} cares about the17** allocation of bags and deallocation of dead bags. Thus these operations18** are transparent to the application, enabling the programmer to19** concentrate on algorithms instead of caring about storage allocation and20** deallocation.21**22** {\Gasman} implements an automatic, cooperating, compacting, generational,23** conservative storage management24**25** *Automatic* means that the application only allocates bags. It need not26** explicitly deallocate them. {\Gasman} automatically determines which27** bags are dead and deallocates them. This is done by a process called28** *garbage collection*. Garbage refers to the bags that are dead, and29** collection refers to the process of deallocating them.30**31** *Cooperating* means that the application must cooperate with {\Gasman},32** that is it must follow two rules. One rule is that it must not remember33** the addresses of the data area of a bag for too long. The other rule is34** that it must inform {\Gasman} when it has changed a bag.35**36** *Compacting* means that after a garbage collection {\Gasman} compacts the37** bags that are still live, so that the storage made available by38** deallocating the dead bags becomes one large contiguous block. This39** helps to avoid *fragmentation* of the free storage. The downside is that40** the address of the data area of a bag may change during a garbage41** collection, which is the reason why the application must not remember42** this address for too long, i.e., must not keep pointers to or into the43** data area of a bag over a garbage collection.44**45** *Generational* means that {\Gasman} distinguishes between old and young46** bags. Old bags have been allocated some time ago, i.e., they survived at47** least one garbage collection. During a garbage collection {\Gasman} will48** first find and deallocate the dead young bags. Only if that does not49** produce enough free storage, {\Gasman} will find and deallocate the dead50** old bags. The idea behind this is that usually most bags have a very51** short life, so that they will die young. The downside is that this52** requires {\Gasman} to quickly find the young bags that are referenced53** from old bags, which is the reason why an application must inform54** {\Gasman} when it has changed a bag.55**56** *Conservative* means that there are situations in which {\Gasman} cannot57** decide with absolute certainty whether a bag is still live or already58** dead. In these situations {\Gasman} has to assume that the bag is still59** live, and may thus keep a bag longer than it is necessary.60**61** What follows describes the reasons for this design, and at the same time62** the assumptions that were made about the application. This is given so63** you can make an educated guess as to whether {\Gasman} is an appropriate64** storage manager for your application.65**66** {\Gasman} is automatic, because this makes it easier to use in large or67** complex applications. Namely in with a non-automatic storage manager the68** application must decide when to deallocate a bag. This requires in69** general global knowledge, i.e., it is not sufficient to know whether the70** current function may still need the bag, one also needs to know whether71** any other function may still need the bag. With growing size or72** complexity of the application it gets harder to obtain this knowledge.73**74** {\Gasman} is cooperating, because this is a requirement for compaction75** and generations (at least without cooperation, compaction and generations76** are very difficult). As described below, the former is important for77** storage efficiency, the latter for time efficiency. Note that the78** cooperation requires only local knowledge, i.e., whether or not a certain79** function of the application follows the two rules can be decided by just80** looking at the function without any knowledge about the rest of the81** application.82**83** {\Gasman} is compacting, because this allows the efficient usage of the84** available storage by applications where the ratio between the size of the85** smallest and the largest bag is large. Namely with a non-compacting86** storage manager, a part of the free storage may become unavailable87** because it is fragmented into many small pieces, each of which is too88** small to serve an allocation.89**90** {\Gasman} is generational, because this makes it very much faster, at91** least for those applications where most bags will indeed die young.92** Namely a non-generational storage manager must test for each bag whether93** or not it is still live during each garbage collection. However with94** many applications the probability that an old bag, i.e., one that95** survived at least one garbage collection, will also survive the next96** garbage collection is high. A generational storage manager simply97** assumes that each old bag is still live during most garbage collections.98** Thereby it avoids the expensive tests for most bags during most garbage99** collections.100**101** {\Gasman} is conservative, because for most applications only few bags102** are incorrectly assumed to be still live and the additional cooperation103** required to make {\Gasman} (more) precise would slow down the104** application. Note that the problem appears since the C compiler provides105** not enough information to distinguish between true references to bags and106** other values that just happen to look like references. Thus {\Gasman}107** has to assume that everything that could be interpreted as a reference to108** a bag is indeed such a reference, and that this bag is still live.109** Therefore some bags may be kept by {\Gasman}, even though they are110** already dead.111*/112#include <string.h>113#include <stdlib.h>114#include <stdio.h>115#include "system.h" /* Ints, UInts */116117118119#include "gasman.h" /* garbage collector */120121#ifdef BOEHM_GC122123#define LARGE_GC_SIZE (8192 * sizeof(UInt))124#define TL_GC_SIZE (256 * sizeof(UInt))125126#ifndef DISABLE_GC127#include <gc/gc.h>128#include <gc/gc_inline.h>129#include <gc/gc_typed.h>130#include <gc/gc_mark.h>131#else132#include <stdlib.h>133#endif134#endif135136137#include "objects.h" /* objects */138#include "scanner.h" /* scanner */139140#include "code.h" /* coder */141#include "thread.h" /* threads */142#include "tls.h" /* thread-local storage */143#ifdef TRACK_CREATOR144/* Need CURR_FUNC and NAME_FUNC() */145#include "calls.h" /* calls */146#include "vars.h" /* variables */147#endif148149150151/****************************************************************************152**153154*F WORDS_BAG( <size> ) . . . . . . . . . . words used by a bag of given size155**156** The structure of a bag is a follows{\:}157**158** <identifier>159** __/160** /161** V162** +---------+163** |<masterp>|164** +---------+165** \____________166** \167** V168** +---------+---------+--------------------------------------------+----+169** |<sz>.<tp>| <link> | . . . . | pad|170** +---------+---------+--------------------------------------------+----+171**172** A bag consists of a masterpointer, and a body.173**174** The *masterpointer* is a pointer to the data area of the bag. During a175** garbage collection the masterpointer is the only active pointer to the176** data area of the bag, because of the rule that no pointers to or into the177** data area of a bag may be remembered over calls to functions that may178** cause a garbage collection. It is the job of the garbage collection to179** update the masterpointer of a bag when it moves the bag.180**181** The *identifier* of the bag is a pointer to (the address of) the182** masterpointer of the bag. Thus 'PTR_BAG(<bag>)' is simply '\*<bag>'183** plus a cast.184**185** The *body* of a bag consists of the size-type word, the link word, the186** data area, and the padding.187**188** The *size-type word* contains the size of the bag in the upper (at least189** 24) bits, and the type (abbreviated as <tp> in the above picture) in the190** lower 8 bits. Thus 'SIZE_BAG' simply extracts the size-type word and191** shifts it 8 bits to the right, and 'TNUM_BAG' extracts the size-type word192** and masks out everything except the lower 8 bits.193**194** The *link word* usually contains the identifier of the bag, i.e., a195** pointer to the masterpointer of the bag. Thus the garbage collection can196** find the masterpointer of a bag through the link word if it knows the197** address of the data area of the bag. The link word is also used by198** {\Gasman} to keep bags on two linked lists (see "ChangedBags" and199** "MarkedBags").200**201** The *data area* of a bag is the area that contains the data stored by202** the application in this bag.203**204** The *padding* consists of up to 'sizeof(Bag)-1' bytes and pads the body205** so that the size of a body is always a multiple of 'sizeof(Bag)'. This206** is to ensure that bags are always aligned. The macro 'WORDS_BAG(<size>)'207** returns the number of words occupied by the data area and padding of a208** bag of size <size>.209**210** A body in the workspace whose size-type word contains the value 255 in211** the lower 8 bits is the remainder of a 'ResizeBag'. That is it consists212** either of the unused words after a bag has been shrunk or of the old body213** of the bag after the contents of the body have been copied elsewhere for214** an extension. The upper (at least 24) bits of the first word contain the215** number of bytes in this area excluding the first word itself. Note that216** such a body has no link word, because such a remainder does not217** correspond to a bag (see "Implementation of ResizeBag").218**219** A masterpointer with a value congruent to 1 mod 4 is the relic of an220** object that was weakly but not strongly marked in a recent garbage221** collection. These persist until after the next full garbage collection222** by which time all references to them should have been removed.223**224*/225226#define SIZE_MPTR_BAGS 1227#define WORDS_BAG(size) (((size) + (sizeof(Bag)-1)) / sizeof(Bag))228229#ifdef USE_NEWSHAPE230#define HEADER_SIZE 2231#else232#define HEADER_SIZE 3233#endif234235/* This could be 65536, but would waste memory in various tables */236237#define NTYPES 256238239/****************************************************************************240**241*V MptrBags . . . . . . . . . . . . . . beginning of the masterpointer area242*V OldBags . . . . . . . . . . . . . . . . . beginning of the old bags area243*V YoungBags . . . . . . . . . . . . . . . beginning of the young bags area244*V AllocBags . . . . . . . . . . . . . . . beginning of the allocation area245*V AllocSizeBags . . . . . . . . . . . . . . . . size of the allocation area246*V StopBags . . . . . . . . . . . . . . . beginning of the unavailable area247*V EndBags . . . . . . . . . . . . . . . . . . . . . . end of the workspace248**249** {\Gasman} manages one large block of storage called the *workspace*. The250** layout of the workspace is as follows{\:}251**252** +-------------+-----------------+------------+------------+-------------+253** |masterpointer| old bags | young bags | allocation | unavailable |254** | area | area | area | area | area |255** +-------------+-----------------+------------+------------+-------------+256** ^ ^ ^ ^ ^ ^257** MptrBags OldBags YoungBags AllocBags StopBags EndBags258**259** The *masterpointer area* contains all the masterpointers of the bags.260** 'MptrBags' points to the beginning of this area and 'OldBags' to the end.261**262** The *old bags area* contains the bodies of all the bags that survived at263** least one garbage collection. This area is only scanned for dead bags264** during a full garbage collection. 'OldBags' points to the beginning of265** this area and 'YoungBags' to the end.266**267** The *young bags area* contains the bodies of all the bags that have been268** allocated since the last garbage collection. This area is scanned for269** dead bags during each garbage collection. 'YoungBags' points to the270** beginning of this area and 'AllocBags' to the end.271**272** The *allocation area* is the storage that is available for allocation of273** new bags. When a new bag is allocated the storage for the body is taken274** from the beginning of this area, and this area is correspondingly275** reduced. If the body does not fit in the allocation area a garbage276** collection is performed. 'AllocBags' points to the beginning of this277** area and 'StopBags' to the end.278**279** The *unavailable area* is the free storage that is not available for280** allocation. 'StopBags' points to the beginning of this area and281** 'EndBags' to the end.282**283** If <cache-size> (see "InitBags") was 0, 'CollectBags' makes all of the284** free storage available for allocations by setting 'StopBags' to 'EndBags'285** after garbage collections. In this case garbage collections are only286** performed when no free storage is left. If <cache-size> was nonzero,287** 'CollectBags' makes 'AllocSizeBags' bytes available by setting 'StopBags'288** to 'AllocBags + 2+WORDS_BAG(<size>) + WORDS_BAG(AllocSizeBags)' after289** garbage collections, where <size> is the size of the bag 'NewBag' is290** currently allocating. 'AllocSizeBags' is usually <cache-size>, but is291** increased if only very few large bags have been allocated since the last292** garbage collection and decreased again if sufficiently many bags have293** been allocated since the last garbage collection. The idea is to keep294** the allocation area small enough so that it fits in the processor cache.295**296** Note that the borders between the areas are not static. In particular297** each allocation increases the size of the young bags area and reduces the298** size of the allocation area. On the other hand each garbage collection299** empties the young bags area.300*/301Bag * MptrBags;302Bag * OldBags;303Bag * YoungBags;304Bag * AllocBags;305UInt AllocSizeBags;306Bag * StopBags;307Bag * EndBags;308309#if defined(MEMORY_CANARY) && !defined(BOEHM_GC)310311#include <valgrind/valgrind.h>312#include <valgrind/memcheck.h>313Int canary_size() {314Int bufsize = (Int)StopBags - (Int)AllocBags;315return bufsize<4096?bufsize:4096;316}317318void ADD_CANARY() {319VALGRIND_MAKE_MEM_NOACCESS(AllocBags, canary_size());320}321void CLEAR_CANARY() {322VALGRIND_MAKE_MEM_DEFINED(AllocBags, canary_size());323}324#define CANARY_DISABLE_VALGRIND() VALGRIND_DISABLE_ERROR_REPORTING325#define CANARY_ENABLE_VALGRIND() VALGRIND_ENABLE_ERROR_REPORTING326327void CHANGED_BAG_IMPL(Bag bag) {328CANARY_DISABLE_VALGRIND();329if ( PTR_BAG(bag) <= YoungBags && PTR_BAG(bag)[-1] == (bag) ) {330PTR_BAG(bag)[-1] = ChangedBags;331ChangedBags = (bag);332}333CANARY_ENABLE_VALGRIND();334}335#else336#define ADD_CANARY()337#define CLEAR_CANARY()338#define CANARY_DISABLE_VALGRIND()339#define CANARY_ENABLE_VALGRIND()340#endif341342343/* These macros, are (a) for more readable code, but more importantly344(b) to ensure that unsigned subtracts and divides are used (since345we know the ordering of the pointers. This is needed on > 2GB346workspaces on 32 but systems. The Size****Area functions return an347answer in units of a word (ie sizeof(UInt) bytes), which should348therefore be small enough not to cause problems. */349350#define SpaceBetweenPointers(a,b) (((UInt)((UInt)(a) - (UInt)(b)))/sizeof(Bag))351352#define SizeMptrsArea SpaceBetweenPointers(OldBags, MptrBags)353#define SizeOldBagsArea SpaceBetweenPointers(YoungBags,OldBags)354#define SizeYoungBagsArea SpaceBetweenPointers(AllocBags, YoungBags)355#define SizeAllocationArea SpaceBetweenPointers(StopBags, AllocBags)356#define SizeUnavailableArea SpaceBetweenPointers(EndBags, StopBags)357358#define SizeAllBagsArea SpaceBetweenPointers(AllocBags, OldBags)359#define SizeWorkspace SpaceBetweenPointers(EndBags, MptrBags)360361/****************************************************************************362**363*V FreeMptrBags . . . . . . . . . . . . . . . list of free bag identifiers364**365** 'FreeMptrBags' is the first free bag identifier, i.e., it points to the366** first available masterpointer. If 'FreeMptrBags' is 0 there are no367** available masterpointers. The available masterpointers are managed in a368** forward linked list, i.e., each available masterpointer points to the369** next available masterpointer, except for the last, which contains 0.370**371** When a new bag is allocated it gets the identifier 'FreeMptrBags', and372** 'FreeMptrBags' is set to the value stored in this masterpointer, which is373** the next available masterpointer. When a bag is deallocated by a garbage374** collection its masterpointer is added to the list of available375** masterpointers again.376*/377Bag FreeMptrBags;378379380/****************************************************************************381**382*V ChangedBags . . . . . . . . . . . . . . . . . . list of changed old bags383**384** 'ChangedBags' holds a list of old bags that have been changed since the385** last garbage collection, i.e., for which either 'CHANGED_BAG' was called386** or which have been resized.387**388** This list starts with the bag whose identifier is 'ChangedBags', and the389** link word of each bag on the list contains the identifier of the next bag390** on the list. The link word of the last bag on the list contains 0. If391** 'ChangedBags' has the value 0, the list is empty.392**393** The garbage collection needs to know which young bags are subbags of old394** bags, since it must not throw those away in a partial garbage395** collection. Only those old bags that have been changed since the last396** garbage collection can contain references to young bags, which have been397** allocated since the last garbage collection. The application cooperates398** by informing {\Gasman} with 'CHANGED_BAG' which bags it has changed. The399** list of changed old bags is scanned by a partial garbage collection and400** the young subbags of the old bags on this list are marked with 'MARK_BAG'401** (see "MarkedBags"). Without this list 'CollectBags' would have to scan402** all old bags for references to young bags, which would take too much time403** (see "Implementation of CollectBags").404**405** 'CHANGED_BAG' puts a bag on the list of changed old bags. 'CHANGED_BAG'406** first checks that <bag> is an old bag by checking that 'PTR_BAG( <bag> )'407** is smaller than 'YoungBags'. Then it checks that the bag is not already408** on the list of changed bags by checking that the link word still contains409** the identifier of <bag>. If <bag> is an old bag that is not already on410** the list of changed bags, 'CHANGED_BAG' puts <bag> on the list of changed411** bags, by setting the link word of <bag> to the current value of412** 'ChangedBags' and then setting 'ChangedBags' to <bag>.413*/414Bag ChangedBags;415416417/****************************************************************************418**419*V MarkedBags . . . . . . . . . . . . . . . . . . . . . list of marked bags420**421** 'MarkedBags' holds a list of bags that have already been marked during a422** garbage collection by 'MARK_BAG'. This list is only used during garbage423** collections, so it is always empty outside of garbage collections (see424** "Implementation of CollectBags").425**426** This list starts with the bag whose identifier is 'MarkedBags', and the427** link word of each bag on the list contains the identifier of the next bag428** on the list. The link word of the last bag on the list contains 0. If429** 'MarkedBags' has the value 0, the list is empty.430**431** Note that some other storage managers do not use such a list during the432** mark phase. Instead they simply let the marking functions call each433** other. While this is somewhat simpler it may use an unbound amount of434** space on the stack. This is particularly bad on systems where the stack435** is not in a separate segment of the address space, and thus may grow into436** the workspace, causing disaster.437**438** 'MARK_BAG' puts a bag <bag> onto this list. 'MARK_BAG' has to be439** careful, because it can be called with an argument that is not really a440** bag identifier, and may point outside the programs address space. So441** 'MARK_BAG' first checks that <bag> points to a properly aligned location442** between 'MptrBags' and 'OldBags'. Then 'MARK_BAG' checks that <bag> is443** the identifier of a young bag by checking that the masterpointer points444** to a location between 'YoungBags' and 'AllocBags' (if <bag> is the445** identifier of an old bag, the masterpointer will point to a location446** between 'OldBags' and 'YoungBags', and if <bag> only appears to be an447** identifier, the masterpointer could be on the free list of masterpointers448** and point to a location between 'MptrBags' and 'OldBags'). Then449** 'MARK_BAG' checks that <bag> is not already marked by checking that the450** link word of <bag> contains the identifier of the bag. If any of the451** checks fails, 'MARK_BAG' does nothing. If all checks succeed, 'MARK_BAG'452** puts <bag> onto the list of marked bags by putting the current value of453** 'ChangedBags' into the link word of <bag> and setting 'ChangedBags' to454** <bag>. Note that since bags are always placed at the front of the list,455** 'CollectBags' will mark the bags in a depth-first order. This is456** probably good to improve the locality of reference.457*/458Bag MarkedBags;459460461/****************************************************************************462**463*V NrAllBags . . . . . . . . . . . . . . . . . number of all bags allocated464*V SizeAllBags . . . . . . . . . . . . . . total size of all bags allocated465*V NrLiveBags . . . . . . . . . . number of bags that survived the last gc466*V SizeLiveBags . . . . . . . total size of bags that survived the last gc467*V NrDeadBags . . . . . . . number of bags that died since the last full gc468*V SizeDeadBags . . . . total size of bags that died since the last full gc469*V NrHalfDeadBags . . . . . number of bags that died since the last full gc470** but may still be weakly pointed to471*/472UInt NrAllBags;473UInt SizeAllBags;474UInt NrLiveBags;475UInt SizeLiveBags;476UInt NrDeadBags;477UInt SizeDeadBags;478UInt NrHalfDeadBags;479480/****************************************************************************481**482*V InfoBags[<type>] . . . . . . . . . . . . . . . . . information for bags483*/484TNumInfoBags InfoBags [ NTYPES ];485486/****************************************************************************487**488*F IS_BAG -- check if a value looks like a masterpointer reference.489*/490static inline UInt IS_BAG (491UInt bid )492{493return (((UInt)MptrBags <= bid)494&& (bid < (UInt)OldBags)495&& (bid & (sizeof(Bag)-1)) == 0);496}497498/****************************************************************************499**500*F InitMsgsFuncBags(<msgs-func>) . . . . . . . . . install message function501**502** 'InitMsgsFuncBags' simply stores the printing function in a global503** variable.504*/505TNumMsgsFuncBags MsgsFuncBags;506507void InitMsgsFuncBags (508TNumMsgsFuncBags msgs_func )509{510#ifndef BOEHM_GC511MsgsFuncBags = msgs_func;512#endif513}514515516/****************************************************************************517**518*F InitSweepFuncBags(<type>,<mark-func>) . . . . install sweeping function519*/520521TNumSweepFuncBags TabSweepFuncBags [ NTYPES ];522523524void InitSweepFuncBags (525UInt type,526TNumSweepFuncBags sweep_func )527{528#ifndef BOEHM_GC529#ifdef CHECK_FOR_CLASH_IN_INIT_SWEEP_FUNC530char str[256];531532if ( TabSweepFuncBags[type] != 0 ) {533str[0] = 0;534strncat( str, "warning: sweep function for type ", 33 );535str[33] = '0' + ((type/100) % 10);536str[34] = '0' + ((type/ 10) % 10);537str[35] = '0' + ((type/ 1) % 10);538str[36] = 0;539strncat( str, " already installed\n", 19 );540SyFputs( str, 0 );541}542#endif543TabSweepFuncBags[type] = sweep_func;544#endif545}546547#if ITANIUM548extern void * ItaniumRegisterStackTop();549550static Bag* ItaniumRegisterStackBottom = (Bag *)0;551552static void ItaniumSpecialMarkingInit() {553ItaniumRegisterStackBottom = (Bag *)ItaniumRegisterStackTop();554}555556#endif557558/****************************************************************************559**560*F InitMarkFuncBags(<type>,<mark-func>) . . . . . install marking function561*F MarkNoSubBags(<bag>) . . . . . . . . marking function that marks nothing562*F MarkOneSubBags(<bag>) . . . . . . marking function that marks one subbag563*F MarkTwoSubBags(<bag>) . . . . . . marking function that marks two subbags564*F MarkThreeSubBags(<bag>) . . . . marking function that marks three subbags565*F MarkFourSubBags(<bag>) . . . . marking function that marks four subbags566*F MarkAllSubBags(<bag>) . . . . . . marking function that marks everything567**568** 'InitMarkFuncBags', 'MarkNoSubBags', 'MarkOneSubBags', 'MarkTwoSubBags',569** and 'MarkAllSubBags' are really too simple for an explanation.570**571** 'MarkAllSubBagsDefault' is the same as 'MarkAllSubBags' but is only used572** by GASMAN as default. This will allow to catch type clashes.573*/574TNumMarkFuncBags TabMarkFuncBags [ NTYPES ];575#ifdef BOEHM_GC576int TabMarkTypeBags [ NTYPES ];577#endif578579580void InitMarkFuncBags (581UInt type,582TNumMarkFuncBags mark_func )583{584#ifdef BOEHM_GC585int mark_type;586#endif587#ifdef CHECK_FOR_CLASH_IN_INIT_MARK_FUNC588char str[256];589590if ( TabMarkFuncBags[type] != MarkAllSubBagsDefault ) {591str[0] = 0;592strncat( str, "warning: mark function for type ", 32 );593str[32] = '0' + ((type/100) % 10);594str[33] = '0' + ((type/ 10) % 10);595str[34] = '0' + ((type/ 1) % 10);596str[35] = 0;597strncat( str, " already installed\n", 19 );598SyFputs( str, 0 );599}600#endif601TabMarkFuncBags[type] = mark_func;602#ifdef BOEHM_GC603if (mark_func == MarkNoSubBags)604mark_type = 0;605else if (mark_func == MarkAllSubBags)606mark_type = -1;607else if (mark_func == MarkOneSubBags)608mark_type = 1;609else if (mark_func == MarkTwoSubBags)610mark_type = 2;611else if (mark_func == MarkThreeSubBags)612mark_type = 3;613else if (mark_func == MarkFourSubBags)614mark_type = 4;615else616mark_type = -1;617TabMarkTypeBags[type] = mark_type;618#endif619}620621622void MarkNoSubBags (623Bag bag )624{625}626627void MarkOneSubBags (628Bag bag )629{630Bag sub; /* one subbag identifier */631sub = PTR_BAG(bag)[0];632MARK_BAG( sub );633}634635void MarkTwoSubBags (636Bag bag )637{638Bag sub; /* one subbag identifier */639sub = PTR_BAG(bag)[0];640MARK_BAG( sub );641sub = PTR_BAG(bag)[1];642MARK_BAG( sub );643}644645void MarkThreeSubBags (646Bag bag )647{648Bag sub; /* one subbag identifier */649sub = PTR_BAG(bag)[0];650MARK_BAG( sub );651sub = PTR_BAG(bag)[1];652MARK_BAG( sub );653sub = PTR_BAG(bag)[2];654MARK_BAG( sub );655}656657void MarkFourSubBags (658Bag bag )659{660Bag sub; /* one subbag identifier */661sub = PTR_BAG(bag)[0];662MARK_BAG( sub );663sub = PTR_BAG(bag)[1];664MARK_BAG( sub );665sub = PTR_BAG(bag)[2];666MARK_BAG( sub );667sub = PTR_BAG(bag)[3];668MARK_BAG( sub );669}670671void MarkAllSubBags (672Bag bag )673{674Bag * ptr; /* pointer into the bag */675Bag sub; /* one subbag identifier */676UInt i; /* loop variable */677678/* mark everything */679ptr = PTR_BAG( bag );680for ( i = SIZE_BAG(bag)/sizeof(Bag); 0 < i; i-- ) {681sub = ptr[i-1];682MARK_BAG( sub );683}684685}686687void MarkAllSubBagsDefault (688Bag bag )689{690Bag * ptr; /* pointer into the bag */691Bag sub; /* one subbag identifier */692UInt i; /* loop variable */693694/* mark everything */695ptr = PTR_BAG( bag );696for ( i = SIZE_BAG(bag)/sizeof(Bag); 0 < i; i-- ) {697sub = ptr[i-1];698MARK_BAG( sub );699}700701}702703704void MarkBagWeakly(705Bag bag )706{707if ( (((UInt)bag) & (sizeof(Bag)-1)) == 0 /* really looks like a pointer */708&& (Bag)MptrBags <= bag /* in plausible range */709&& bag < (Bag)OldBags /* " " " */710&& YoungBags < PTR_BAG(bag) /* points to a young bag */711&& PTR_BAG(bag) <= AllocBags /* " " " " " */712&& IS_MARKED_DEAD(bag) ) /* and not marked already */713{714LINK_BAG(bag) = (Bag)MARKED_HALFDEAD(bag); /* mark it now as we715don't have to recurse */716}717}718719720#ifdef BOEHM_GC721static GC_descr GCDesc[MAX_GC_PREFIX_DESC+1];722static unsigned GCKind[MAX_GC_PREFIX_DESC+1];723static GC_descr GCMDesc[MAX_GC_PREFIX_DESC+1];724static unsigned GCMKind[MAX_GC_PREFIX_DESC+1];725#endif726727728/****************************************************************************729**730*F CallbackForAllBags( <func> ) call a C function on all non-zero mptrs731**732** This calls a C function on every bag, including garbage ones, by simply733** walking the masterpointer area. Not terribly safe.734**735*/736737void CallbackForAllBags(738void (*func)(Bag) )739{740#ifndef BOEHM_GC741Bag ptr;742for (ptr = (Bag)MptrBags; ptr < (Bag)OldBags; ptr ++)743if (*ptr != 0 && !IS_WEAK_DEAD_BAG(ptr) && (Bag)(*ptr) >= (Bag)OldBags)744{745(*func)(ptr);746}747#endif748}749750751/****************************************************************************752**753*V GlobalBags . . . . . . . . . . . . . . . . . . . . . list of global bags754*/755TNumGlobalBags GlobalBags;756757758/****************************************************************************759**760*F InitGlobalBag(<addr>, <cookie>) inform Gasman about global bag identifier761**762** 'InitGlobalBag' simply leaves the address <addr> in a global array, where763** it is used by 'CollectBags'. <cookie> is also recorded to allow things to764** be matched up after loading a saved workspace.765*/766static UInt GlobalSortingStatus;767Int WarnInitGlobalBag;768769#ifndef BOEHM_GC770extern TNumAbortFuncBags AbortFuncBags;771772void ClearGlobalBags ( void )773{774UInt i;775for (i = 0; i < GlobalBags.nr; i++)776{777GlobalBags.addr[i] = 0L;778GlobalBags.cookie[i] = 0L;779}780GlobalBags.nr = 0;781GlobalSortingStatus = 0;782WarnInitGlobalBag = 0;783return;784}785#endif786787void InitGlobalBag (788Bag * addr,789const Char * cookie )790{791#ifndef BOEHM_GC792if ( GlobalBags.nr == NR_GLOBAL_BAGS ) {793(*AbortFuncBags)(794"Panic: Gasman cannot handle so many global variables" );795}796#ifdef DEBUG_GLOBAL_BAGS797{798UInt i;799if (cookie != (Char *)0)800for (i = 0; i < GlobalBags.nr; i++)801if ( 0 == strcmp(GlobalBags.cookie[i], cookie) )802if (GlobalBags.addr[i] == addr)803Pr("Duplicate global bag entry %s\n", (Int)cookie, 0L);804else805Pr("Duplicate global bag cookie %s\n", (Int)cookie, 0L);806}807#endif808if ( WarnInitGlobalBag ) {809Pr( "#W global bag '%s' initialized\n", (Int)cookie, 0L );810}811GlobalBags.addr[GlobalBags.nr] = addr;812GlobalBags.cookie[GlobalBags.nr] = cookie;813GlobalBags.nr++;814GlobalSortingStatus = 0;815#endif816}817818819820#ifndef BOEHM_GC821static Int IsLessGlobal (822const Char * cookie1,823const Char * cookie2,824UInt byWhat )825{826if (byWhat != 2)827{828(*AbortFuncBags)("can only sort globals by cookie");829}830if (cookie1 == 0L && cookie2 == 0L)831return 0;832if (cookie1 == 0L)833return -1;834if (cookie2 == 0L)835return 1;836return strcmp(cookie1, cookie2) < 0;837}838#endif839840841842void SortGlobals( UInt byWhat )843{844#ifndef BOEHM_GC845const Char *tmpcookie;846Bag * tmpaddr;847UInt len, h, i, k;848if (byWhat != 2)849{850(*AbortFuncBags)("can only sort globals by cookie");851}852if (GlobalSortingStatus == byWhat)853return;854len = GlobalBags.nr;855h = 1;856while ( 9*h + 4 < len )857{ h = 3*h + 1; }858while ( 0 < h ) {859for ( i = h; i < len; i++ ) {860tmpcookie = GlobalBags.cookie[i];861tmpaddr = GlobalBags.addr[i];862k = i;863while ( h <= k && IsLessGlobal(tmpcookie,864GlobalBags.cookie[k-h],865byWhat))866{867GlobalBags.cookie[k] = GlobalBags.cookie[k-h];868GlobalBags.addr[k] = GlobalBags.addr[k-h];869k -= h;870}871GlobalBags.cookie[k] = tmpcookie;872GlobalBags.addr[k] = tmpaddr;873}874h = h / 3;875}876GlobalSortingStatus = byWhat;877return;878#endif879}880881882883Bag * GlobalByCookie(884const Char * cookie )885{886#ifndef BOEHM_GC887UInt i,top,bottom,middle;888Int res;889if (cookie == 0L)890{891Pr("Panic -- 0L cookie passed to GlobalByCookie\n",0L,0L);892SyExit(2);893}894if (GlobalSortingStatus != 2)895{896for (i = 0; i < GlobalBags.nr; i++)897{898if (strcmp(cookie, GlobalBags.cookie[i]) == 0)899return GlobalBags.addr[i];900}901return (Bag *)0L;902}903else904{905top = GlobalBags.nr;906bottom = 0;907while (top >= bottom) {908middle = (top + bottom)/2;909res = strcmp(cookie,GlobalBags.cookie[middle]);910if (res < 0)911top = middle-1;912else if (res > 0)913bottom = middle+1;914else915return GlobalBags.addr[middle];916}917return (Bag *)0L;918}919#else920return (Bag *) 0;921#endif /* !BOEHM_GC */922}923924925static Bag NextMptrRestoring;926extern TNumAllocFuncBags AllocFuncBags;927928void StartRestoringBags( UInt nBags, UInt maxSize)929{930#ifndef BOEHM_GC931UInt target;932Bag *newmem;933/*Bag *ptr; */934target = (8*nBags)/7 + (8*maxSize)/7; /* ideal workspace size */935target = (target * sizeof (Bag) + (512L*1024L) - 1)/(512L*1024L)*(512L*1024L)/sizeof (Bag);936/* make sure that the allocated amount of memory is divisible by 512 * 1024 */937if (SizeWorkspace < target)938{939newmem = (*AllocFuncBags)(sizeof(Bag)*(target- SizeWorkspace)/1024, 0);940if (newmem == 0)941{942target = nBags + maxSize; /* absolute requirement */943target = (target * sizeof (Bag) + (512L*1024L) - 1)/(512L*1024L)*(512L*1024L)/sizeof (Bag);944/* make sure that the allocated amount of memory is divisible by 512 * 1024 */945if (SizeWorkspace < target)946(*AllocFuncBags)(sizeof(Bag)*(target- SizeWorkspace)/1024, 1);947}948EndBags = MptrBags + target;949}950OldBags = MptrBags + nBags + (SizeWorkspace - nBags - maxSize)/8;951AllocBags = OldBags;952NextMptrRestoring = (Bag)MptrBags;953SizeAllBags = 0;954NrAllBags = 0;955return;956#endif957}958959Bag NextBagRestoring( UInt size, UInt type)960{961#ifndef BOEHM_GC962Bag bag;963UInt i;964*(Bag **)NextMptrRestoring = (AllocBags+HEADER_SIZE);965bag = NextMptrRestoring;966#ifdef USE_NEWSHAPE967((UInt *)AllocBags)[0] = (size << 16 | type);968#else969((UInt *)AllocBags)[0] = type;970((UInt *)AllocBags)[1] = size;971#endif972973((Bag *)AllocBags)[HEADER_SIZE-1] = NextMptrRestoring;974NextMptrRestoring++;975#ifdef DEBUG_LOADING976if ((Bag *)NextMptrRestoring >= OldBags)977(*AbortFuncBags)("Overran Masterpointer area");978#endif979AllocBags += HEADER_SIZE;980981for (i = 0; i < WORDS_BAG(size); i++)982*AllocBags++ = (Bag)0;983984#ifdef DEBUG_LOADING985if (AllocBags > EndBags)986(*AbortFuncBags)("Overran data area");987#endif988#ifdef COUNT_BAGS989InfoBags[type].nrLive += 1;990InfoBags[type].nrAll += 1;991InfoBags[type].sizeLive += size;992InfoBags[type].sizeAll += size;993#endif994SizeAllBags += size;995NrAllBags ++;996return bag;997#else998return 0;999#endif1000}10011002void FinishedRestoringBags( void )1003{1004#ifndef BOEHM_GC1005Bag p;1006/* Bag *ptr; */1007YoungBags = AllocBags;1008StopBags = AllocBags + WORDS_BAG(AllocSizeBags);1009if (StopBags > EndBags)1010StopBags = EndBags;1011FreeMptrBags = NextMptrRestoring;1012for (p = NextMptrRestoring; p +1 < (Bag)OldBags; p++)1013*(Bag *)p = p+1;1014*p = 0;1015NrLiveBags = NrAllBags;1016SizeLiveBags = SizeAllBags;1017NrDeadBags = 0;1018SizeDeadBags = 0;1019NrHalfDeadBags = 0;1020ChangedBags = 0;1021return;1022#endif1023}102410251026#ifndef BOEHM_GC1027/****************************************************************************1028**1029*F InitFreeFuncBag(<type>,<free-func>) . . . . . . install freeing function1030**1031** 'InitFreeFuncBag' is really too simple for an explanation.1032*/1033TNumFreeFuncBags TabFreeFuncBags [ 256 ];10341035UInt NrTabFreeFuncBags;10361037void InitFreeFuncBag (1038UInt type,1039TNumFreeFuncBags free_func )1040{1041if ( free_func != 0 ) {1042NrTabFreeFuncBags = NrTabFreeFuncBags + 1;1043}1044else {1045NrTabFreeFuncBags = NrTabFreeFuncBags - 1;1046}1047TabFreeFuncBags[type] = free_func;1048}1049#endif105010511052/****************************************************************************1053**1054*F InitCollectFuncBags(<bfr-func>,<aft-func>) . install collection functions1055**1056** 'InitCollectFuncBags' is really too simple for an explanation.1057*/1058TNumCollectFuncBags BeforeCollectFuncBags;10591060TNumCollectFuncBags AfterCollectFuncBags;10611062void InitCollectFuncBags (1063TNumCollectFuncBags before_func,1064TNumCollectFuncBags after_func )1065{1066#ifndef BOEHM_GC1067BeforeCollectFuncBags = before_func;1068AfterCollectFuncBags = after_func;1069#endif1070}107110721073/****************************************************************************1074**1075*F FinishBags() . . . . . . . . . . . . . . . . . . . . . . .finalize GASMAN1076**1077** `FinishBags()' ends GASMAN and returns all memory to the OS pool1078**1079*/10801081void FinishBags( void )1082{1083#ifndef BOEHM_GC1084(*AllocFuncBags)(-(sizeof(Bag)*SizeWorkspace/1024),2);1085return;1086#endif1087}10881089/****************************************************************************1090**1091*F InitBags(...) . . . . . . . . . . . . . . . . . . . . . initialize Gasman1092**1093** 'InitBags' remembers <alloc-func>, <stack-func>, <stack-bottom>,1094** <stack-align>, <cache-size>, <dirty>, and <abort-func> in global1095** variables. It also allocates the initial workspace, and sets up the1096** linked list of available masterpointer.1097*/1098TNumAllocFuncBags AllocFuncBags;10991100TNumStackFuncBags StackFuncBags;11011102Bag * StackBottomBags;11031104UInt StackAlignBags;11051106UInt CacheSizeBags;11071108UInt DirtyBags;11091110TNumAbortFuncBags AbortFuncBags;11111112#ifdef BOEHM_GC11131114/*1115* Build memory layout information for Boehm GC.1116*1117* Bitmapped type descriptors have a bit set if the word at the1118* corresponding offset may contain a reference. This is done1119* by first creating a bitmap and then using GC_make_descriptor()1120* to build a descriptor from the bitmap. Memory for a specific1121* type layout can be allocated with GC_malloc_explicitly_typed()1122* and GC_malloc_explicitly_typed_ignore_off_page().1123*1124* We also create a new 'kind' for each collector. Kinds have their1125* own associated free lists and do not require to have type information1126* stored in each bag, thus potentially saving some memory. Allocating1127* memory of a specific kind is done with GC_generic_malloc(). There1128* is no public _ignore_off_page() version for this call, so we use1129* GC_malloc_explicitly_typed_ignore_off_page() instead, given that1130* the overhead is negligible for large objects.1131*/11321133void BuildPrefixGCDescriptor(unsigned prefix_len) {11341135if (prefix_len) {1136GC_word bits[1] = {0};1137unsigned i;1138for (i=0; i<prefix_len; i++)1139GC_set_bit(bits, (i + HEADER_SIZE));1140GCDesc[prefix_len] = GC_make_descriptor(bits, prefix_len + HEADER_SIZE);1141GC_set_bit(bits, 0);1142GCMDesc[prefix_len] = GC_make_descriptor(bits, prefix_len + HEADER_SIZE);1143} else {1144GCDesc[prefix_len] = GC_DS_LENGTH;1145GCMDesc[prefix_len] = GC_DS_LENGTH | sizeof(void *);1146}1147GCKind[prefix_len] = GC_new_kind(GC_new_free_list(), GCDesc[prefix_len],11480, 1);1149GCMKind[prefix_len] = GC_new_kind(GC_new_free_list(), GCMDesc[prefix_len],11500, 0);1151}11521153#endif11541155#ifdef BOEHM_GC1156static void TLAllocatorInit(void);1157#endif11581159void InitBags (1160TNumAllocFuncBags alloc_func,1161UInt initial_size,1162TNumStackFuncBags stack_func,1163Bag * stack_bottom,1164UInt stack_align,1165UInt cache_size,1166UInt dirty,1167TNumAbortFuncBags abort_func )1168{1169UInt i; /* loop variable */1170#ifndef BOEHM_GC1171Bag * p; /* loop variable */11721173ClearGlobalBags();1174WarnInitGlobalBag = 0;11751176/* install the allocator and the abort function */1177AllocFuncBags = alloc_func;1178AbortFuncBags = abort_func;11791180/* install the stack marking function and values */1181StackFuncBags = stack_func;1182StackBottomBags = stack_bottom;1183StackAlignBags = stack_align;1184#if ITANIUM1185ItaniumSpecialMarkingInit();1186#endif11871188/* first get some storage from the operating system */1189initial_size = (initial_size + 511) & ~(511);1190MptrBags = (*AllocFuncBags)( initial_size, 1 );1191if ( MptrBags == 0 )1192(*AbortFuncBags)("cannot get storage for the initial workspace.");1193EndBags = MptrBags + 1024*(initial_size / sizeof(Bag*));11941195/* 1/8th of the storage goes into the masterpointer area */1196FreeMptrBags = (Bag)MptrBags;1197for ( p = MptrBags;1198p + 2*(SIZE_MPTR_BAGS) <= MptrBags+1024*initial_size/8/sizeof(Bag*);1199p += SIZE_MPTR_BAGS )1200{1201*p = (Bag)(p + SIZE_MPTR_BAGS);1202}12031204/* the rest is for bags */1205OldBags = MptrBags + 1024*initial_size/8/sizeof(Bag*);1206YoungBags = OldBags;1207AllocBags = OldBags;12081209/* remember the cache size */1210CacheSizeBags = cache_size;1211if ( ! CacheSizeBags ) {1212AllocSizeBags = 256;1213StopBags = EndBags;1214}1215else {1216AllocSizeBags = (CacheSizeBags+1023)/1024;1217StopBags = AllocBags + WORDS_BAG(1024*AllocSizeBags) <= EndBags ?1218AllocBags + WORDS_BAG(1024*AllocSizeBags) : EndBags;1219}12201221/* remember whether bags should be clean */1222DirtyBags = dirty;12231224/* install the marking functions */1225for ( i = 0; i < 255; i++ ) {1226TabMarkFuncBags[i] = MarkAllSubBagsDefault;1227}12281229/* Set ChangedBags to a proper initial value */1230ChangedBags = 0;1231#else /* BOEHM_GC */1232/* install the marking functions */1233for ( i = 0; i < 255; i++ ) {1234TabMarkFuncBags[i] = MarkAllSubBagsDefault;1235TabMarkTypeBags[i] = -1;1236}1237#ifndef DISABLE_GC1238if (!getenv("GC_MARKERS")) {1239/* The Boehm GC does not have an API to set the number of1240* markers for the parallel mark and sweep implementation,1241* so we use the documented environment variable GC_MARKERS1242* instead. However, we do not override it if it's already1243* set.1244*/1245static char marker_env_str[32];1246unsigned num_markers = 2;1247extern UInt SyNumProcessors;1248extern UInt SyNumGCThreads;1249if (!SyNumGCThreads)1250SyNumGCThreads = SyNumProcessors;1251if (SyNumGCThreads) {1252if (SyNumGCThreads <= MAX_GC_THREADS)1253num_markers = (unsigned) SyNumProcessors;1254else1255num_markers = MAX_GC_THREADS;1256}1257sprintf(marker_env_str, "GC_MARKERS=%u", num_markers);1258putenv(marker_env_str);1259}1260GC_set_all_interior_pointers(0);1261GC_init();1262TLAllocatorInit();1263GC_register_displacement(0);1264GC_register_displacement(HEADER_SIZE*sizeof(Bag));1265initial_size *= 1024;1266if (GC_get_heap_size() < initial_size)1267GC_expand_hp(initial_size - GC_get_heap_size());1268if (SyStorKill)1269GC_set_max_heap_size(SyStorKill * 1024);1270AddGCRoots();1271CreateMainRegion();1272for (i=0; i<=MAX_GC_PREFIX_DESC; i++) {1273BuildPrefixGCDescriptor(i);1274/* This is necessary to initialize some internal structures1275* in the garbage collector: */1276GC_generic_malloc((HEADER_SIZE + i) * sizeof(UInt), GCMKind[i]);1277}1278#endif /* DISABLE_GC */1279#endif /* BOEHM_GC */1280}12811282#ifdef BOEHM_GC12831284#define GRANULE_SIZE (2 * sizeof(UInt))12851286static unsigned char TLAllocatorSeg[TL_GC_SIZE / GRANULE_SIZE + 1];1287static unsigned TLAllocatorSize[TL_GC_SIZE / GRANULE_SIZE];1288static UInt TLAllocatorMaxSeg;12891290static void TLAllocatorInit(void) {1291unsigned stage = 16;1292unsigned inc = 1;1293unsigned i = 0;1294unsigned k = 0;1295unsigned j;1296unsigned max = TL_GC_SIZE / GRANULE_SIZE;1297while (i <= max) {1298if (i == stage) {1299stage *= 2;1300inc *= 2;1301}1302TLAllocatorSize[k] = i * GRANULE_SIZE;1303TLAllocatorSeg[i] = k;1304for (j=1; j<inc; j++) {1305if (i + j <= max)1306TLAllocatorSeg[i+j] = k+1;1307}1308i += inc;1309k ++;1310}1311TLAllocatorMaxSeg = k;1312if (MAX_GC_PREFIX_DESC * sizeof(void *) > sizeof(TLS(FreeList)))1313abort();1314}13151316/****************************************************************************1317**1318*F AllocateBagMemory( <gc_type>, <type>, <size> )1319**1320** Allocate memory for a new bag.1321**1322** 'AllocateBagMemory' is an auxiliary routine for the Boehm GC that1323** allocates memory from the appropriate pool. 'gc_type' is -1 if all words1324** in the bag can refer to other bags, 0 if the bag will not contain any1325** references to other bags, and > 0 to indicate a specific memory layout1326** descriptor.1327**/1328void *AllocateBagMemory(int gc_type, int type, UInt size)1329{1330void *result = NULL;1331if (size <= TL_GC_SIZE) {1332UInt alloc_seg, alloc_size;1333alloc_size = (size + GRANULE_SIZE - 1 ) / GRANULE_SIZE;1334alloc_seg = TLAllocatorSeg[alloc_size];1335alloc_size = TLAllocatorSize[alloc_seg];1336if (!TLS(FreeList)[gc_type+1])1337TLS(FreeList)[gc_type+1] =1338GC_malloc(sizeof(void *) * TLAllocatorMaxSeg);1339if (!(result = TLS(FreeList)[gc_type+1][alloc_seg])) {1340if (gc_type < 0)1341TLS(FreeList)[0][alloc_seg] = GC_malloc_many(alloc_size);1342else1343GC_generic_malloc_many(alloc_size, GCMKind[gc_type],1344&TLS(FreeList)[gc_type+1][alloc_seg]);1345result = TLS(FreeList)[gc_type+1][alloc_seg];1346}1347TLS(FreeList)[gc_type+1][alloc_seg] = *(void **)result;1348memset(result, 0, alloc_size);1349} else {1350if (gc_type >= 0)1351result = GC_generic_malloc(size, GCKind[gc_type]);1352else1353result = GC_malloc(size);1354}1355if (TabFinalizerFuncBags[type])1356GC_register_finalizer_no_order(result, StandardFinalizer,1357NULL, NULL, NULL);1358return result;1359}1360#endif136113621363/****************************************************************************1364**1365*F NewBag( <type>, <size> ) . . . . . . . . . . . . . . allocate a new bag1366**1367** 'NewBag' is actually quite simple.1368**1369** It first tests whether enough storage is available in the allocation area1370** and whether a free masterpointer is available. If not, it starts a1371** garbage collection by calling 'CollectBags' passing <size> as the size of1372** the bag it is currently allocating and 0 to indicate that only a partial1373** garbage collection is called for. If 'CollectBags' fails and returns 0,1374** 'NewBag' also fails and also returns 0.1375**1376** Then it takes the first free masterpointer from the linked list of free1377** masterpointers (see "FreeMptrBags").1378**1379** Then it writes the size and the type into the word pointed to by1380** 'AllocBags'. Then it writes the identifier, i.e., the location of the1381** masterpointer, into the next word.1382**1383** Then it advances 'AllocBags' by '2 + WORDS_BAG(<size>)'.1384**1385** Finally it returns the identifier of the new bag.1386**1387** Note that 'NewBag' never initializes the new bag to contain only 0. If1388** this is desired because the initialization flag <dirty> (see "InitBags")1389** was 0, it is the job of 'CollectBags' to initialize the new free space1390** after a garbage collection.1391**1392** If {\Gasman} was compiled with the option 'COUNT_BAGS' then 'NewBag' also1393** updates the information in 'InfoBags' (see "InfoBags").1394**1395** 'NewBag' is implemented as a function instead of a macro for three1396** reasons. It reduces the size of the program, improving the instruction1397** cache hit ratio. The compiler can do anti-aliasing analysis for the1398** local variables of the function. To enable statistics only {\Gasman}1399** needs to be recompiled.1400*/1401Bag NewBag (1402UInt type,1403UInt size )1404{1405Bag bag; /* identifier of the new bag */1406Bag * dst; /* destination of the new bag */1407#ifdef BOEHM_GC1408UInt alloc_size;1409#endif14101411#ifndef BOEHM_GC1412#ifdef TREMBLE_HEAP1413CollectBags(0,0);1414#endif14151416/* check that a masterpointer and enough storage are available */1417if ( (FreeMptrBags == 0 || SizeAllocationArea < HEADER_SIZE+WORDS_BAG(size))1418&& CollectBags( size, 0 ) == 0 )1419{1420return 0;1421}14221423#ifdef COUNT_BAGS1424/* update the statistics */1425NrAllBags += 1;1426InfoBags[type].nrLive += 1;1427InfoBags[type].nrAll += 1;1428InfoBags[type].sizeLive += size;1429InfoBags[type].sizeAll += size;1430#endif1431SizeAllBags += size;14321433/* get the identifier of the bag and set 'FreeMptrBags' to the next */1434bag = FreeMptrBags;1435FreeMptrBags = *(Bag*)bag;1436CLEAR_CANARY();1437/* allocate the storage for the bag */1438dst = AllocBags;1439AllocBags = dst + HEADER_SIZE + WORDS_BAG(size);1440ADD_CANARY();1441#else /* BOEHM_GC */1442alloc_size = HEADER_SIZE*sizeof(Bag) + size;1443#ifndef DISABLE_GC1444#ifndef TRACK_CREATOR1445bag = GC_malloc(2*sizeof(Bag *));1446#else1447bag = GC_malloc(4*sizeof(Bag *));1448if (TLS(PtrLVars)) {1449bag[2] = (void *)(CURR_FUNC);1450if (TLS(CurrLVars) != TLS(BottomLVars)) {1451Obj plvars = ADDR_OBJ(TLS(CurrLVars))[2];1452bag[3] = (void *) (ADDR_OBJ(plvars)[0]);1453}1454}1455#endif1456/* If the size of an object is zero (such as an empty permutation),1457* and the header size is a multiple of twice the word size of the1458* architecture, then the master pointer will actually point past1459* the allocated area. Because this would result in the object1460* being freed prematurely, we will allocate at least one extra1461* byte so that the master pointer actually points to within an1462* allocated memory area.1463*/1464if (size == 0)1465alloc_size++;1466/* While we use the Boehm GC without the "all interior pointers"1467* option, stack references to the interior of an object will1468* still be valid from any reference on the stack. This can lead,1469* for example, to a 1GB string never being freed if there's an1470* integer on the stack that happens to also be a reference to1471* any character inside that string. The garbage collector does1472* this because after compiler optimizations (especially reduction1473* in strength) references to the beginning of an object may be1474* lost.1475*1476* However, this is not generally a risk with GAP objects, because1477* master pointers on the heap will always retain a reference to1478* the start of the object (or, more precisely, to the first byte1479* past the header area). Hence, compiler optimizations pose no1480* actual risk unless the master pointer is destroyed also.1481*1482* To avoid the scenario where large objects do not get deallocated,1483* we therefore use the _ignore_off_page() calls. One caveat here1484* is that these calls do not use thread-local allocation, making1485* them somewhat slower. Hence, we only use them for sufficiently1486* large objects.1487*/1488dst = AllocateBagMemory(TabMarkTypeBags[type], type, alloc_size);1489#else1490bag = malloc(2*sizeof(Bag *));1491dst = malloc(alloc_size);1492memset(dst, 0, alloc_size);1493#endif /* DISABLE_GC */1494#endif /* BOEHM_GC */14951496/* enter size-type words */1497#ifdef USE_NEWSHAPE1498*dst++ = (Bag)(size << 16 | type);1499#else1500*dst++ = (Bag)(type);1501*dst++ = (Bag)(size);1502#endif150315041505/* enter link word */1506*dst++ = bag;15071508/* set the masterpointer */1509PTR_BAG(bag) = dst;1510#if 01511{1512extern void * stderr;1513UInt i;1514for (i = 0; i < WORDS_BAG(size); i++)1515if (*dst++)1516fprintf(stderr, "dirty bag being returned\n");1517}1518#endif1519/* return the identifier of the new bag */1520return bag;1521}152215231524/****************************************************************************1525**1526*F RetypeBag(<bag>,<new>) . . . . . . . . . . . . change the type of a bag1527**1528** 'RetypeBag' is very simple.1529**1530** All it has to do is to change the size-type word of the bag.1531**1532** If {\Gasman} was compiled with the option 'COUNT_BAGS' then 'RetypeBag'1533** also updates the information in 'InfoBags' (see "InfoBags").1534*/1535void RetypeBag (1536Bag bag,1537UInt new_type )1538{15391540#ifdef COUNT_BAGS1541/* update the statistics */1542{1543UInt old_type; /* old type of the bag */1544UInt size;15451546old_type = TNUM_BAG(bag);1547size = SIZE_BAG(bag);1548InfoBags[old_type].nrLive -= 1;1549InfoBags[new_type].nrLive += 1;1550InfoBags[old_type].nrAll -= 1;1551InfoBags[new_type].nrAll += 1;1552InfoBags[old_type].sizeLive -= size;1553InfoBags[new_type].sizeLive += size;1554InfoBags[old_type].sizeAll -= size;1555InfoBags[new_type].sizeAll += size;1556}1557#else1558#ifdef BOEHM_GC1559UInt old_type = TNUM_BAG(bag);1560#endif1561#endif15621563/* change the size-type word */1564#ifdef USE_NEWSHAPE1565*(*bag-HEADER_SIZE) &= 0xFFFFFFFFFFFF0000L;1566*(*bag-HEADER_SIZE) |= new_type;1567#else1568*(*bag-HEADER_SIZE) = new_type;1569#endif1570#ifdef BOEHM_GC1571{1572int old_gctype, new_gctype;1573UInt size;1574void *new_mem, *old_mem;1575old_gctype = TabMarkTypeBags[old_type];1576new_gctype = TabMarkTypeBags[new_type];1577if (old_gctype != new_gctype) {1578size = SIZE_BAG(bag) + HEADER_SIZE * sizeof(Bag);1579new_mem = AllocateBagMemory(new_gctype, new_type, size);1580old_mem = PTR_BAG(bag);1581old_mem = ((char *) old_mem) - HEADER_SIZE * sizeof(Bag);1582memcpy(new_mem, old_mem, size);1583PTR_BAG(bag) = (void *)(((char *)new_mem) + HEADER_SIZE * sizeof(Bag));1584}1585}1586#endif1587}158815891590/****************************************************************************1591**1592*F ResizeBag(<bag>,<new>) . . . . . . . . . . . . change the size of a bag1593**1594** Basically 'ResizeBag' is rather simple, but there are a few traps that1595** must be avoided.1596**1597** If the size of the bag changes only a little bit, so that the number of1598** words needed for the data area does not change, 'ResizeBag' only changes1599** the size-type word of the bag.1600**1601** If the bag is to be shrunk and at least one word becomes free,1602** 'ResizeBag' changes the size-type word of the bag, and stores a magic1603** size-type word in the first free word. This magic size-type word has1604** type 255 and the size is the number of following free bytes, which is1605** always divisible by 'sizeof(Bag)'. The type 255 allows 'CollectBags' to1606** detect that this body is the remainder of a resize operation, and the1607** size allows it to know how many bytes there are in this body (see1608** "Implementation of CollectBags").1609**1610** So for example if 'ResizeBag' shrinks a bag of type 7 from 18 bytes to 101611** bytes the situation before 'ResizeBag' is as follows{\:}1612**1613** +---------+1614** |<masterp>|1615** +---------+1616** \_____________1617** \1618** V1619** +---------+---------+--------------------------------------------+----+1620** | 18 . 7 | <link> | . . . . | pad|1621** +---------+---------+--------------------------------------------+----+1622**1623** And after 'ResizeBag' the situation is as follows{\:}1624**1625** +---------+1626** |<masterp>|1627** +---------+1628** \_____________1629** \1630** V1631** +---------+---------+------------------------+----+---------+---------+1632** | 10 . 7 | <link> | . . | pad| 4 .255| |1633** +---------+---------+------------------------+----+---------+---------+1634**1635** If the bag is to be extended and it is that last allocated bag, so that1636** it is immediately adjacent to the allocation area, 'ResizeBag' simply1637** increments 'AllocBags' after making sure that enough space is available1638** in the allocation area (see "Layout of the Workspace").1639**1640** If the bag is to be extended and it is not the last allocated bag,1641** 'ResizeBag' first allocates a new bag similar to 'NewBag', but without1642** using a new masterpointer. Then it copies the old contents to the new1643** bag. Finally it resets the masterpointer of the bag to point to the new1644** address. Then it changes the type of the old body to 255, so that the1645** garbage collection can detect that this body is the remainder of a resize1646** (see "Implementation of NewBag" and "Implementation of CollectBags").1647**1648** When an old bag is extended, it will now reside in the young bags area,1649** and thus appear to be young. Since old bags are supposed to survive1650** partial garbage collections 'ResizeBag' must somehow protect this bag1651** from partial garbage collections. This is done by putting this bag onto1652** the linked list of changed bags (see "ChangedBags"). When a partial1653** garbage collection sees a young bag on the list of changed bags, it knows1654** that it is the result of 'ResizeBag' of an old bag, and does not throw it1655** away (see "Implementation of CollectBags"). Note that when 'ResizeBag'1656** tries this, the bag may already be on the linked list, either because it1657** has been resized earlier, or because it has been changed. In this case1658** 'ResizeBag' simply keeps the bag on this linked list.1659**1660** If {\Gasman} was compiled with the option 'COUNT_BAGS' then 'ResizeBag'1661** also updates the information in 'InfoBags' (see "InfoBags").1662*/16631664UInt ResizeBag (1665Bag bag,1666UInt new_size )1667{1668UInt type; /* type of the bag */1669UInt old_size; /* old size of the bag */1670Bag * dst; /* destination in copying */1671Bag * src; /* source in copying */1672#ifndef BOEHM_GC1673Bag * end; /* end in copying */1674#else1675UInt alloc_size;1676#endif16771678/* check the size */16791680#ifdef TREMBLE_HEAP1681CollectBags(0,0);1682#endif16831684/* get type and old size of the bag */1685type = TNUM_BAG(bag);1686old_size = SIZE_BAG(bag);16871688#ifdef COUNT_BAGS1689/* update the statistics */1690InfoBags[type].sizeLive += new_size - old_size;1691InfoBags[type].sizeAll += new_size - old_size;1692#endif1693SizeAllBags += new_size - old_size;16941695/* if the real size of the bag doesn't change */1696#ifndef BOEHM_GC1697if ( WORDS_BAG(new_size) == WORDS_BAG(old_size) ) {1698#else1699#ifndef DISABLE_GC1700alloc_size = GC_size(PTR_BAG(bag)-HEADER_SIZE);1701/* An alternative implementation would be to compare1702* new_size <= alloc_size in the following test in order1703* to avoid reallocations for alternating contractions1704* and expansions. However, typed allocation in the Boehm1705* GC stores layout information in the last word of a memory1706* block and we may accidentally overwrite this information,1707* because GC_size() includes that extraneous word when1708* returning the size of a memory block.1709*1710* This is technically a bug in GC_size(), but until and1711* unless there is an upstream fix, we'll do it the safe1712* way.1713*/1714if ( new_size <= old_size1715&& HEADER_SIZE*sizeof(Bag) + new_size >= alloc_size * 3/4) {1716#else1717if (new_size <= old_size) {1718#endif /* DISABLE_GC */1719#endif17201721/* change the size word */1722#ifdef USE_NEWSHAPE1723*(*bag-2) = (new_size << 16 | type);1724#else1725*(*bag-2) = new_size;1726#endif1727}17281729/* if the bag is shrunk */1730/* we must not shrink the last bag by moving 'AllocBags', */1731/* since the remainder may not be zero filled */1732#ifndef BOEHM_GC1733else if ( WORDS_BAG(new_size) < WORDS_BAG(old_size) ) {17341735/* leave magic size-type word for the sweeper, type must be 255 */1736if ((WORDS_BAG(old_size)-WORDS_BAG(new_size) == 1))1737*(UInt*)(PTR_BAG(bag) + WORDS_BAG(new_size)) = 1 << 8 | 255;1738else1739{1740#ifdef USE_NEWSHAPE1741*(UInt*)(PTR_BAG(bag) + WORDS_BAG(new_size)) =1742(WORDS_BAG(old_size)-WORDS_BAG(new_size)-1)*sizeof(Bag) << 16 | 255;1743#else1744*(UInt*)(PTR_BAG(bag) + WORDS_BAG(new_size)) = 255;1745*(UInt*)(PTR_BAG(bag) + WORDS_BAG(new_size) + 1) =1746(WORDS_BAG(old_size)-WORDS_BAG(new_size)-1)*sizeof(Bag);1747#endif1748}17491750/* change the size- word */1751#ifdef USE_NEWSHAPE1752*(*bag-2) = (new_size << 16 | type);1753#else1754*(*bag-2) = new_size;1755#endif175617571758}17591760/* if the last bag is to be enlarged */1761else if ( PTR_BAG(bag) + WORDS_BAG(old_size) == AllocBags ) {1762CLEAR_CANARY();1763/* check that enough storage for the new bag is available */1764if ( StopBags < PTR_BAG(bag)+WORDS_BAG(new_size)1765&& CollectBags( new_size-old_size, 0 ) == 0 ) {1766return 0;1767}17681769/* simply increase the free pointer */1770if ( YoungBags == AllocBags )1771YoungBags += WORDS_BAG(new_size) - WORDS_BAG(old_size);1772AllocBags += WORDS_BAG(new_size) - WORDS_BAG(old_size);17731774ADD_CANARY();1775/* change the size-type word */1776#ifdef USE_NEWSHAPE1777*(*bag-2) = (new_size << 16 | type);1778#else1779*(*bag-2) = new_size;1780#endif1781}1782#endif /* !BOEHM_GC */1783/* if the bag is enlarged */1784else {17851786#ifndef BOEHM_GC1787/* check that enough storage for the new bag is available */1788if ( SizeAllocationArea < HEADER_SIZE+WORDS_BAG(new_size)1789&& CollectBags( new_size, 0 ) == 0 ) {1790return 0;1791}1792CLEAR_CANARY();1793/* allocate the storage for the bag */1794dst = AllocBags;1795AllocBags = dst + HEADER_SIZE + WORDS_BAG(new_size);1796ADD_CANARY();1797#else1798alloc_size = HEADER_SIZE*sizeof(Bag) + new_size;1799if (new_size == 0)1800alloc_size++;1801#ifndef DISABLE_GC1802dst = AllocateBagMemory(TabMarkTypeBags[type], type, alloc_size);1803#else1804dst = malloc( alloc_size );1805memset(dst, 0, alloc_size);1806#endif1807#endif18081809/* leave magic size-type word for the sweeper, type must be 255 */1810#ifdef USE_NEWSHAPE1811#ifndef BOEHM_GC1812*(*bag-2) = (((WORDS_BAG(old_size)+1) * sizeof(Bag))) << 16 | 255;1813#endif1814*dst++ = (Bag)(new_size << 16 | type);1815#else1816#ifndef BOEHM_GC1817*(*bag-3) = 255;1818*(*bag-2) = (((WORDS_BAG(old_size)+2) * sizeof(Bag)));1819#endif18201821/* enter the new size-type word */18221823*dst++ = (Bag)type;1824*dst++ = (Bag)new_size;1825#endif182618271828#ifndef BOEHM_GC1829CANARY_DISABLE_VALGRIND();1830/* if the bag is already on the changed bags list, keep it there */1831if ( PTR_BAG(bag)[-1] != bag ) {1832*dst++ = PTR_BAG(bag)[-1];1833}18341835/* if the bag is old, put it onto the changed bags list */1836else if ( PTR_BAG(bag) <= YoungBags ) {1837*dst++ = ChangedBags; ChangedBags = bag;1838}18391840/* if the bag is young, enter the normal link word */1841else {1842*dst++ = bag;1843}1844CANARY_ENABLE_VALGRIND();1845#else1846*dst++ = bag;1847#endif1848/* set the masterpointer */1849src = PTR_BAG(bag);1850#ifndef BOEHM_GC1851end = src + WORDS_BAG(old_size);1852#endif1853PTR_BAG(bag) = dst;18541855#ifndef BOEHM_GC1856/* copy the contents of the bag */1857while ( src < end )1858*dst++ = *src++;1859#else1860if (dst != src) {1861memcpy( dst, src, old_size < new_size ? old_size : new_size );1862} else if (new_size < old_size) {1863memset(dst+new_size, 0, old_size - new_size);1864}1865#endif18661867}18681869/* return success */1870return 1;1871}187218731874/****************************************************************************1875**1876*F CollectBags( <size>, <full> ) . . . . . . . . . . . . . collect dead bags1877**1878** 'CollectBags' is the function that does most of the work of {\Gasman}.1879**1880** A partial garbage collection where every bag is young is clearly a full1881** garbage collection. So to perform a full garbage collection,1882** 'CollectBags' first sets 'YoungBags' to 'OldBags', making every bag1883** young, and empties the list of changed old bags, since there are no old1884** bags anymore, there can be no changed old bags anymore. So from now on1885** we can assume that 'CollectBags' is doing a partial garbage1886** collection. In addition, the values 'NewWeakDeadBagMarker' and1887** 'OldWeakDeadBagMarker' are exchanged, so that bag idnetifiers that have1888** been halfdead since before this full garbage collection cab be1889** distinguished from those which have died on this pass.1890**1891** Garbage collection is performed in three phases. The mark phase, the1892** sweep phase, and the check phase.1893**1894** In the *mark phase*, 'CollectBags' finds all young bags that are still1895** live and builds a linked list of those bags (see "MarkedBags"). A bag is1896** put on this list of marked bags by applying 'MARK_BAG' to its1897** identifier. Note that 'MARK_BAG' checks that a bag is not already on the1898** list of marked bags, before it puts it on the list, so no bag can be put1899** twice on this list.1900**1901** First, 'CollectBags' marks all young bags that are directly accessible1902** through global variables, i.e., it marks those young bags whose1903** identifiers appear in global variables. It does this by applying1904** 'MARK_BAG' to the values at the addresses of global variables that may1905** hold bag identifiers provided by 'InitGlobalBag' (see "InitGlobalBag").1906**1907** Next, 'CollectBags' marks all young bags that are directly accessible1908** through local variables, i.e., it marks those young bags whose1909** identifiers appear in the stack. It does this by calling the stack1910** marking function <stack-func> (see "InitBags"). The generic stack1911** marking function, which is called if <stack-func> (see "InitBags") was 0,1912** is described below. The problem is that there is usually not sufficient1913** information available to decide if a value on the stack is really the1914** identifier of a bag, or is a value of another type that only appears to1915** be the identifier of a bag. The position usually taken by the stack1916** marking function is that everything on the stack that could possibly be1917** interpreted as the identifier of a bag is an identifier of a bag, and1918** that this bag is therefore live. This position is what makes {\Gasman} a1919** conservative storage manager.1920**1921** The generic stack marking function 'GenStackFuncBags', which is called if1922** <stack-func> (see "InitBags") was 0, works by applying 'MARK_BAG' to all1923** the values on the stack, which is supposed to extend from <stack-start>1924** (see "InitBags") to the address of a local variable of the function.1925** Note that some local variables may not be stored on the stack, because1926** they are still in the processors registers. 'GenStackFuncBags' uses a1927** jump buffer 'RegsBags', filled by the C library function 'setjmp', marking1928** all bags whose identifiers appear in 'RegsBags'. This is a dirty hack,1929** that need not work, but actually works on a surprisingly large number of1930** machines. But it will not work on Sun Sparc machines, which have larger1931** register files, of which only the part visible to the current function1932** will be saved by 'setjmp'. For those machines 'GenStackFuncBags' first1933** calls the operating system to flush the whole register file. Note that a1934** compiler may save a register somewhere else if it wants to use this1935** register for something else. Usually this register is saved further up1936** the stack, i.e., beyond the address of the local variable, and1937** 'GenStackFuncBags' would not see this value any more. To deal with this1938** problem, 'setjmp' must be called *before* 'GenStackFuncBags' is entered,1939** i.e., before the registers may have been saved elsewhere. Thus it is1940** called from 'CollectBags'.1941**1942** Next 'CollectBags' marks all young bags that are directly accessible from1943** old bags, i.e., it marks all young bags whose identifiers appear in the1944** data areas of old bags. It does this by applying 'MARK_BAG' to each1945** identifier appearing in changed old bags, i.e., in those bags that appear1946** on the list of changed old bags (see "ChangedBags"). To be more precise1947** it calls the marking function for the appropriate type to each changed1948** old bag (see "InitMarkFuncBags"). It need not apply the marking function1949** to each old bag, because old bags that have not been changed since the1950** last garbage collection cannot contain identifiers of young bags, which1951** have been allocated since the last garbage collection. Of course marking1952** the subbags of only the changed old bags is more efficient than marking1953** the subbags of all old bags only if the number of changed old bags is1954** smaller than the total number of old bags, but this is a very reasonable1955** assumption.1956**1957** Note that there may also be bags that appear to be young on the list of1958** changed old bags. Those bags are old bags that were extended since the1959** last garbage collection and therefore have their body in the young bags1960** area (see "Implementation of ResizeBag"). When 'CollectBags' finds such1961** a bag on the list of changed old bags it applies 'MARK_BAG' to its1962** identifier and thereby ensures that this bag will not be thrown away by1963** this garbage collection.1964**1965** Next, 'CollectBags' marks all young bags that are *indirectly*1966** accessible, i.e., it marks the subbags of the already marked bags, their1967** subbags and so on. It does so by walking along the list of already1968** marked bags and applies the marking function of the appropriate type to1969** each bag on this list (see "InitMarkFuncBags"). Those marking functions1970** then apply 'MARK_BAG' or 'MarkBagWeakly' to each identifier appearing in1971** the bag.1972**1973** After the marking function has been applied to a bag on the list of1974** marked bag, this bag is removed from the list. Thus the marking phase is1975** over when the list of marked bags has become empty. Removing the bag1976** from the list of marked bags must be done at this time, because newly1977** marked bags are *prepended* to the list of marked bags. This is done to1978** ensure that bags are marked in a depth first order, which should usually1979** improve locality of reference. When a bag is taken from the list of1980** marked bags it is *tagged*. This tag serves two purposes. A bag that is1981** tagged is not put on the list of marked bags when 'MARK_BAG' is applied1982** to its identifier. This ensures that no bag is put more than once onto1983** the list of marked bags, otherwise endless marking loops could happen for1984** structures that contain circular references. Also the sweep phase later1985** uses the presence of the tag to decide the status of the bag. There are1986** three possible statuses: LIVE, DEAD and HALFDEAD. The default state of a1987** bag with its identifier in the link word, is the tag for DEAD. Live bags1988** are tagged with MARKED_ALIVE(<identifier>) in the link word, and1989** half-dead bags (ie bags pointed to weakly but not strongly) with the tage1990** MARKED_HALFDEAD(<identifier>).1991**1992** Note that 'CollectBags' cannot put a random or magic value into the link1993** word, because the sweep phase must be able to find the masterpointer of a1994** bag by only looking at the link word of a bag. This is done using the macros1995** UNMARKED_XXX(<link word contents>).1996**1997** In the *sweep phase*, 'CollectBags' deallocates all dead bags and1998** compacts the live bags at the beginning of the workspace.1999**2000** In this phase 'CollectBags' uses a destination pointer 'dst', which2001** points to the address a body will be copied to, and a source pointer2002** 'src', which points to the address a body currently has. Both pointers2003** initially point to the beginning of the young bags area. Then2004** 'CollectBags' looks at the body pointed to by the source pointer.2005**2006** If this body has type 255, it is the remainder of a resize operation. In2007** this case 'CollectBags' simply moves the source pointer to the next body2008** (see "Implementation of ResizeBag").2009**2010**2011** Otherwise, if the link word contains the identifier of the bag itself,20122013** marked dead, 'CollectBags' first adds the masterpointer to the list of2014** available masterpointers (see "FreeMptrBags") and then simply moves the2015** source pointer to the next bag.2016**2017** Otherwise, if the link word contains the identifier of the bag marked2018** alive, this bag is still live. In this case 'CollectBags' calls the2019** sweeping function for this bag, if one is installed, or otherwise copies2020** the body from the source address to the destination address, stores the2021** address of the masterpointer without the tag in the link word, and2022** updates the masterpointer to point to the new address of the data area of2023** the bag. After the copying the source pointer points to the next bag,2024** and the destination pointer points just past the copy.2025**2026** Finally, if the link word contains the identifier of the bag marked half2027** dead, then 'CollectBags' puts the special value 'NewWeakDeadBagMarker'2028** into the masterpointer corresponding to the bag, to signify that this bag2029** has been collected as garbage.2030**2031** This is repeated until the source pointer reaches the end of the young2032** bags area, i.e., reaches 'AllocBags'.2033**2034** The new free storage now is the area between the destination pointer and2035** the source pointer. If the initialization flag <dirty> (see "InitBags")2036** was 0, this area is now cleared.2037**2038** Next, 'CollectBags' sets 'YoungBags' and 'AllocBags' to the address2039** pointed to by the destination pointer. So all the young bags that have2040** survived this garbage collection are now promoted to be old bags, and2041** allocation of new bags will start at the beginning of the free storage.2042**2043** Finally, the *check phase* checks whether the garbage collection freed2044** enough storage and masterpointers.2045**2046** After a partial garbage collection, 'CollectBags' wants at least '<size>2047** + AllocSizeBags' bytes of free storage available, where <size> is the2048** size of the bag that 'NewBag' is currently trying to allocate. Also the2049** number of free masterpointers should be larger than the number of bags2050** allocated since the previous garbage collection plus 4096 more to be2051** safe. If less free storage or fewer masterpointers are available,2052** 'CollectBags' calls itself for a full garbage collection.2053**2054** After a full garbage collection, 'CollectBags' wants at least <size>2055** bytes of free storage available, where <size> is the size of the bag that2056** 'NewBag' is currently trying to allocate. Also it wants at least one2057** free masterpointer. If less free storage or no masterpointer are2058** available, 'CollectBags' tries to extend the workspace using the2059** allocation function <alloc-func> (see "InitBags"). If <alloc-func>2060** refuses to extend the workspace, 'CollectBags' returns 0 to indicate2061** failure to 'NewBag'. In any case 'CollectBags' will try to extend the2062** workspace so that at least one eigth of the storage is free, that is, one2063** eight of the storage between 'OldBags' and 'EndBags' shall be free. If2064** <alloc-func> refuses this extension of the workspace, 'CollectBags' tries2065** to get along with what it got. Also 'CollectBags' wants at least one2066** masterpointer per 8 words of free storage available. If this is not the2067** case, 'CollectBags' extends the masterpointer area by moving the bodies2068** of all bags and readjusting the masterpointers.2069**2070** Also, after a full garbage collection, 'CollectBags' scans the2071** masterpointer area for identifiers containing 'OldWeakDeadBagMarker'. If2072** the sweep functions have done their work then no references to these bag2073** identifiers can exist, and so 'CollectBags' frees these masterpointers.2074*/2075#ifndef BOEHM_GC20762077syJmp_buf RegsBags;20782079#if defined(SPARC) && SPARC2080void SparcStackFuncBags( void )2081{2082asm (" ta 0x3 ");2083asm (" mov %sp,%o0" );2084return;2085}2086#endif208720882089void GenStackFuncBags ( void )2090{2091Bag * top; /* top of stack */2092Bag * p; /* loop variable */2093UInt i; /* loop variable */20942095top = (Bag*)((void*)&top);2096if ( StackBottomBags < top ) {2097for ( i = 0; i < sizeof(Bag*); i += StackAlignBags ) {2098for ( p = (Bag*)((char*)StackBottomBags + i); p < top; p++ )2099MARK_BAG( *p );2100}2101}2102else {2103for ( i = 0; i < sizeof(Bag*); i += StackAlignBags ) {2104for ( p = (Bag*)((char*)StackBottomBags - i); top < p; p-- )2105MARK_BAG( *p );2106}2107}2108#if ITANIUM2109/* Itanium has two stacks */2110top = ItaniumRegisterStackTop();2111for ( i = 0; i < sizeof(Bag*); i += StackAlignBags ) {2112for ( p = (Bag*)((char*)ItaniumRegisterStackBottom + i); p < top; p++ )2113MARK_BAG( *p );2114}2115#endif21162117/* mark from registers, dirty dirty hack */2118for ( p = (Bag*)((void*)RegsBags);2119p < (Bag*)((void*)RegsBags)+sizeof(RegsBags)/sizeof(Bag);2120p++ )2121MARK_BAG( *p );21222123}21242125UInt FullBags;21262127/* These are used to overwrite masterpointers which may still be2128linked from weak pointer objects but whose bag bodies have been2129collected. Two values are used so that old masterpointers of this2130kind can be reclaimed after a full garbage collection. The values must2131not look like valid pointers, and should be congruent to 1 mod sizeof(Bag) */21322133Bag * NewWeakDeadBagMarker = (Bag *)(1000*sizeof(Bag) + 1L);2134Bag * OldWeakDeadBagMarker = (Bag *)(1001*sizeof(Bag) + 1L);21352136#endif /* !BOEHM_GC */2137213821392140UInt CollectBags (2141UInt size,2142UInt full )2143{2144#ifndef BOEHM_GC2145Bag first; /* first bag on a linked list */2146Bag * p; /* loop variable */2147Bag * dst; /* destination in sweeping */2148Bag * src; /* source in sweeping */2149Bag * end; /* end of a bag in sweeping */2150UInt nrLiveBags; /* number of live new bags */2151UInt sizeLiveBags; /* total size of live new bags */2152UInt nrDeadBags; /* number of dead new bags */2153UInt nrHalfDeadBags; /* number of dead new bags */2154UInt sizeDeadBags; /* total size of dead new bags */2155UInt done; /* do we have to make a full gc */2156UInt i; /* loop variable */21572158/* Bag * last;2159Char type; */21602161CANARY_DISABLE_VALGRIND();2162CLEAR_CANARY();2163#ifdef DEBUG_MASTERPOINTERS2164CheckMasterPointers();2165#endif216621672168/* call the before function (if any) */2169if ( BeforeCollectFuncBags != 0 )2170(*BeforeCollectFuncBags)();21712172/* copy 'full' into a global variable, to avoid warning from GNU C */2173FullBags = full;21742175/* do we want to make a full garbage collection? */2176again:2177if ( FullBags ) {21782179/* then every bag is considered to be a young bag */2180YoungBags = OldBags;2181NrLiveBags = 0;2182SizeLiveBags = 0;21832184/* empty the list of changed old bags */2185while ( ChangedBags != 0 ) {2186first = ChangedBags;2187ChangedBags = PTR_BAG(first)[-1];2188PTR_BAG(first)[-1] = first;2189}21902191/* Also time to change the tag for dead children of weak2192pointer objects. After this collection, there can be no more2193weak pointer objects pointing to anything with OldWeakDeadBagMarker2194in it */2195{2196Bag * t;2197t = OldWeakDeadBagMarker;2198OldWeakDeadBagMarker = NewWeakDeadBagMarker;2199NewWeakDeadBagMarker = t;2200}2201}22022203/* information at the beginning of garbage collections */2204if ( MsgsFuncBags )2205(*MsgsFuncBags)( FullBags, 0, 0 );22062207/* * * * * * * * * * * * * * * mark phase * * * * * * * * * * * * * * */22082209/* prepare the list of marked bags for the future */2210MarkedBags = 0;22112212/* mark from the static area */2213for ( i = 0; i < GlobalBags.nr; i++ )2214MARK_BAG( *GlobalBags.addr[i] );221522162217/* mark from the stack */2218if ( StackFuncBags ) {2219(*StackFuncBags)();2220}2221else {2222sySetjmp( RegsBags );2223#ifdef SPARC2224#if SPARC2225SparcStackFuncBags();2226#endif2227#endif2228GenStackFuncBags();2229}22302231/* mark the subbags of the changed old bags */2232while ( ChangedBags != 0 ) {2233first = ChangedBags;2234ChangedBags = PTR_BAG(first)[-1];2235PTR_BAG(first)[-1] = first;2236if ( PTR_BAG(first) <= YoungBags )2237(*TabMarkFuncBags[TNUM_BAG(first)])( first );2238else2239MARK_BAG(first);2240}224122422243/* tag all marked bags and mark their subbags */2244nrLiveBags = 0;2245sizeLiveBags = 0;2246while ( MarkedBags != 0 ) {2247first = MarkedBags;2248MarkedBags = PTR_BAG(first)[-1];2249PTR_BAG(first)[-1] = MARKED_ALIVE(first);2250(*TabMarkFuncBags[TNUM_BAG(first)])( first );2251nrLiveBags++;2252sizeLiveBags += SIZE_BAG(first);2253}22542255/* information after the mark phase */2256NrLiveBags += nrLiveBags;2257if ( MsgsFuncBags )2258(*MsgsFuncBags)( FullBags, 1, nrLiveBags );2259SizeLiveBags += sizeLiveBags;2260if ( MsgsFuncBags )2261(*MsgsFuncBags)( FullBags, 2, sizeLiveBags/1024 );22622263/* * * * * * * * * * * * * * * sweep phase * * * * * * * * * * * * * * */22642265#if 02266/* call freeing function for all dead bags */2267if ( NrTabFreeFuncBags ) {22682269/* run through the young generation */2270src = YoungBags;2271while ( src < AllocBags ) {22722273/* leftover of a resize of <n> bytes */2274if ( (*(UInt*)src & 0xFFL) == 255 ) {22752276if ((*(UInt *)src >> 16) == 1)2277src++;2278else2279src += WORDS_BAG(((UInt *)src)[1]);228022812282}22832284/* dead or half-dead (only weakly pointed to bag */2285/* here the usual check using UNMARKED_DEAD etc. is not2286safe, because we are looking at the bag body rather2287than its identifier, and a wrong guess for the bag2288status can involve following a misaligned pointer. It2289may cause bus errors or actual mistakes.22902291Instead we look directly at the value in the link word2292and check its least significant bits */22932294else if ( ((UInt)(src[HEADER_SIZE-1])) % sizeof(Bag) == 0 ||2295((UInt)(src[HEADER_SIZE-1])) % sizeof(Bag) == 2 )2296{2297#ifdef DEBUG_MASTERPOINTERS2298if ( (((UInt)(src[1])) % sizeof(Bag) == 0 &&2299PTR_BAG( UNMARKED_DEAD(src[1]) ) != src+HEADER_SIZE) ||2300(((UInt)(src[1])) % sizeof(Bag) == 2 &&2301PTR_BAG( UNMARKED_HALFDEAD(src[1])) != src+HEADER_SIZE))2302{2303(*AbortFuncBags)("incorrectly marked bag");2304}2305#endif23062307/* call freeing function */2308if ( TabFreeFuncBags[ *(UInt*)src & 0xFFL ] != 0 )2309(*TabFreeFuncBags[ *(UInt*)src & 0xFFL ])( src[HEADER_SIZE-1] );23102311/* advance src */2312src += HEADER_SIZE + WORDS_BAG( ((UInt*)src)[1] ) ;23132314}231523162317/* live bag */2318else if ( ((UInt)(src[HEADER_SIZE-1])) % sizeof(Bag) == 1 )2319{2320#ifdef DEBUG_MASTERPOINTERS2321if ( PTR_BAG( UNMARKED_ALIVE(src[HEADER_SIZE-1]) ) != src+HEADER_SIZE )2322{2323(*AbortFuncBags)("incorrectly marked bag");2324}2325#endif23262327/* advance src */2328#ifdef USE_NEWSHAPE2329src += HEADER_SIZE + WORDS_BAG( ((UInt*)src)[0] >>16 );2330#else2331src += HEADER_SIZE + WORDS_BAG( ((UInt*)src)[1] );2332#endif233323342335}23362337/* oops */2338else {2339(*AbortFuncBags)(2340"Panic: Gasman found a bogus header (looking for dead bags)");2341}23422343}23442345}2346#endif2347/* sweep through the young generation */2348nrDeadBags = 0;2349nrHalfDeadBags = 0;2350sizeDeadBags = 0;2351dst = YoungBags;2352src = YoungBags;2353while ( src < AllocBags ) {23542355/* leftover of a resize of <n> bytes */2356if ( (*(UInt*)src & 0xFFL) == 255 ) {23572358/* advance src */2359if ((*(UInt *) src) >> 8 == 1)2360src++;2361else2362#ifdef USE_NEWSHAPE2363src += 1 + WORDS_BAG(((UInt *)src)[0] >> 16);2364#else2365src += 1 + WORDS_BAG(((UInt *)src)[1]);2366#endif23672368}23692370/* dead bag */23712372else if ( ((UInt)(src[HEADER_SIZE-1])) % sizeof(Bag) == 0 )2373{2374#ifdef DEBUG_MASTERPOINTERS2375if ( PTR_BAG( UNMARKED_DEAD(src[HEADER_SIZE-1]) ) != src+HEADER_SIZE )2376{2377(*AbortFuncBags)("incorrectly marked bag");2378}2379#endif238023812382/* update count */2383if (TabFreeFuncBags[ *(UInt *)src & 0xFFL] != 0)2384(*TabFreeFuncBags[ *(UInt*)src & 0xFFL ])( src[HEADER_SIZE-1] );2385nrDeadBags += 1;2386#ifdef USE_NEWSHAPE2387sizeDeadBags += ((UInt *)src)[0] >> 16;2388#else2389sizeDeadBags += ((UInt *)src)[1];2390#endif23912392#ifdef COUNT_BAGS2393/* update the statistics */2394InfoBags[*(UInt*)src & 0xFFL].nrLive -= 1;2395#ifdef USE_NEWSHAPE2396InfoBags[*(UInt*)src & 0xFFL].sizeLive -=2397((UInt *)src)[0] >>16;2398#else2399InfoBags[*(UInt*)src & 0xFFL].sizeLive -=2400((UInt *)src)[1];2401#endif2402#endif24032404/* free the identifier */2405*(Bag*)(src[HEADER_SIZE-1]) = FreeMptrBags;2406FreeMptrBags = src[HEADER_SIZE-1];24072408/* advance src */2409#ifdef USE_NEWSHAPE2410src += HEADER_SIZE +2411WORDS_BAG( ((UInt*)src)[0] >> 16 ) ;2412#else2413src += HEADER_SIZE +2414WORDS_BAG( ((UInt*)src)[1] ) ;2415#endif24162417}24182419/* half-dead bag */2420else if ( ((UInt)(src[HEADER_SIZE-1])) % sizeof(Bag) == 2 )2421{2422#ifdef DEBUG_MASTERPOINTERS2423if ( PTR_BAG( UNMARKED_HALFDEAD(src[HEADER_SIZE-1]) ) != src+HEADER_SIZE )2424{2425(*AbortFuncBags)("incorrectly marked bag");2426}2427#endif242824292430/* update count */2431nrDeadBags += 1;2432#ifdef USE_NEWSHAPE2433sizeDeadBags += ((UInt *)src)[0] >> 16;2434#else2435sizeDeadBags += ((UInt *)src)[1];2436#endif24372438#ifdef COUNT_BAGS2439/* update the statistics */2440InfoBags[*(UInt*)src & 0xFFL].nrLive -= 1;2441#ifdef USE_NEWSHAPE2442InfoBags[*(UInt*)src & 0xFFL].sizeLive -=2443((UInt *)src)[0] >>16;2444#else2445InfoBags[*(UInt*)src & 0xFFL].sizeLive -=2446((UInt *)src)[1];2447#endif2448#endif24492450/* don't free the identifier */2451if (((UInt)UNMARKED_HALFDEAD(src[HEADER_SIZE-1])) % 4 != 0)2452(*AbortFuncBags)("align error in halfdead bag");24532454*(Bag**)(UNMARKED_HALFDEAD(src[HEADER_SIZE-1])) = NewWeakDeadBagMarker;2455nrHalfDeadBags ++;24562457/* advance src */2458#ifdef USE_NEWSHAPE2459src += HEADER_SIZE +2460WORDS_BAG( ((UInt*)src)[0] >> 16 ) ;2461#else2462src += HEADER_SIZE +2463WORDS_BAG( ((UInt*)src)[1] ) ;2464#endif24652466}24672468/* live bag */2469else if ( ((UInt)(src[HEADER_SIZE-1])) % sizeof(Bag) == 1 )2470{2471#ifdef DEBUG_MASTERPOINTERS2472if ( PTR_BAG( UNMARKED_ALIVE(src[HEADER_SIZE-1]) ) != src+HEADER_SIZE )2473{2474(*AbortFuncBags)("incorrectly marked bag");2475}2476#endif247724782479/* update identifier, copy size-type and link field */2480PTR_BAG( UNMARKED_ALIVE(src[HEADER_SIZE-1])) = dst+HEADER_SIZE;2481#ifdef USE_NEWSHAPE2482end = src + HEADER_SIZE +2483WORDS_BAG( ((UInt*)src)[0] >>16 ) ;2484#else2485end = src + HEADER_SIZE +2486WORDS_BAG( ((UInt*)src)[1] ) ;2487#endif2488*dst++ = *src++;2489#ifndef USE_NEWSHAPE2490*dst++ = *src++;2491#endif24922493*dst++ = (Bag)UNMARKED_ALIVE(*src++);24942495/* copy data area */2496if (TabSweepFuncBags[(UInt)(src[-HEADER_SIZE]) & 0xFFL] != 0)2497{2498/* Call the installed sweeping function */2499(*(TabSweepFuncBags[(UInt)(src[-HEADER_SIZE]) & 0xFFL]))(src,dst,end-src);2500dst += end-src;2501src = end;25022503}25042505/* Otherwise do the default thing */2506else if ( dst != src ) {2507memmove((void *)dst, (void *)src, (end - src)*sizeof(*src));2508dst += (end-src);2509src = end;25102511/*2512while ( src < end )2513*dst++ = *src++;2514*/2515}2516else {2517dst = end;2518src = end;2519}2520}25212522/* oops */2523else {25242525(*AbortFuncBags)("Panic: Gasman found a bogus header");25262527}25282529}25302531/* reset the pointer to the free storage */2532AllocBags = YoungBags = dst;25332534/* clear the new free area */2535if (!DirtyBags)2536memset((void *)dst, 0, ((Char *)src)-((Char *)dst));25372538/* if ( ! DirtyBags ) {2539while ( dst < src )2540*dst++ = 0;2541} */25422543/* information after the sweep phase */2544NrDeadBags += nrDeadBags;2545NrHalfDeadBags += nrHalfDeadBags;2546if ( MsgsFuncBags )2547(*MsgsFuncBags)( FullBags, 3,2548(FullBags ? NrDeadBags:nrDeadBags) );2549if ( FullBags )2550NrDeadBags = 0;2551SizeDeadBags += sizeDeadBags;2552if ( MsgsFuncBags )2553(*MsgsFuncBags)( FullBags, 4,2554(FullBags ? SizeDeadBags:sizeDeadBags)/1024 );2555if ( FullBags )2556SizeDeadBags = 0;25572558/* * * * * * * * * * * * * * * check phase * * * * * * * * * * * * * * */25592560/* temporarily store in 'StopBags' where this allocation takes us */2561StopBags = AllocBags + HEADER_SIZE + WORDS_BAG(size);2562256325642565/* if we only performed a partial garbage collection */2566if ( ! FullBags ) {25672568/* maybe adjust the size of the allocation area */2569if ( ! CacheSizeBags ) {2570if ( nrLiveBags+nrDeadBags +nrHalfDeadBags < 51225712572/* The test below should stop AllocSizeBags2573growing uncontrollably when all bags are big */2574&& StopBags > OldBags + 4*1024*WORDS_BAG(AllocSizeBags))2575AllocSizeBags += 256L;2576else if ( 4096 < nrLiveBags+nrDeadBags+nrHalfDeadBags2577&& 256 < AllocSizeBags )2578AllocSizeBags -= 256;2579}2580else {2581if ( nrLiveBags+nrDeadBags < 512 )2582AllocSizeBags += CacheSizeBags/1024;2583else if ( 4096 < nrLiveBags+nrDeadBags+nrHalfDeadBags2584&& CacheSizeBags < AllocSizeBags )2585AllocSizeBags -= CacheSizeBags/1024;2586}25872588/* if we dont get enough free storage or masterpointers do full gc */2589if ( EndBags < StopBags + WORDS_BAG(1024*AllocSizeBags)2590|| SizeMptrsArea <25912592/* nrLiveBags+nrDeadBags+nrHalfDeadBags+ 4096 */2593/* If this test triggered, but the one below didn't2594then a full collection would ensue which wouldn't2595do anything useful. Possibly a version of the2596above test should be moved into the full collection also2597but I wasn't sure it always made sense SL */25982599/* change the test to avoid subtracting unsigned integers */26002601WORDS_BAG(AllocSizeBags*1024)/7 +(NrLiveBags + NrHalfDeadBags)2602) {2603done = 0;2604}2605else {2606done = 1;2607}26082609}26102611/* if we already performed a full garbage collection */2612else {26132614/* Clean up old half-dead bags2615also reorder the free masterpointer linked list2616to get more locality */2617FreeMptrBags = (Bag)0L;2618for (p = MptrBags; p < OldBags; p+= SIZE_MPTR_BAGS)2619{2620Bag *mptr = (Bag *)*p;2621if ( mptr == OldWeakDeadBagMarker)2622NrHalfDeadBags--;2623if ( mptr == OldWeakDeadBagMarker || IS_BAG((UInt)mptr) || mptr == 0)2624{2625*p = FreeMptrBags;2626FreeMptrBags = (Bag)p;2627}2628}262926302631/* get the storage we absolutly need */2632while ( EndBags < StopBags2633&& (*AllocFuncBags)(512,1) )2634EndBags += WORDS_BAG(512*1024L);26352636/* if not enough storage is free, fail */2637if ( EndBags < StopBags )2638return 0;26392640/* if less than 1/8th is free, get more storage (in 1/2 MBytes) */2641while ( ( SpaceBetweenPointers(EndBags, StopBags) < SpaceBetweenPointers(StopBags, OldBags)/7 ||2642SpaceBetweenPointers(EndBags, StopBags) < WORDS_BAG(AllocSizeBags) )2643&& (*AllocFuncBags)(512,0) )2644EndBags += WORDS_BAG(512*1024L);26452646/* If we are having trouble, then cut our cap to fit our cloth *.2647if ( EndBags - StopBags < AllocSizeBags )2648AllocSizeBags = 7*(Endbags - StopBags)/8; */26492650/* if less than 1/16th is free, prepare for an interrupt */2651if (SpaceBetweenPointers(StopBags,OldBags)/15 < SpaceBetweenPointers(EndBags,StopBags) ) {2652/*N 1993/05/16 martin must change 'gap.c' */2653;2654}26552656/* if more than 1/8th is free, give back storage (in 1/2 MBytes) */2657while (SpaceBetweenPointers(StopBags,OldBags)/7 <= SpaceBetweenPointers(EndBags,StopBags)-WORDS_BAG(512*1024L)2658&& SpaceBetweenPointers(EndBags,StopBags) > WORDS_BAG(AllocSizeBags) + WORDS_BAG(512*1024L)2659&& (*AllocFuncBags)(-512,0) )2660EndBags -= WORDS_BAG(512*1024L);26612662/* if we want to increase the masterpointer area */2663if ( SpaceBetweenPointers(OldBags,MptrBags)-NrLiveBags < SpaceBetweenPointers(EndBags,StopBags)/7 ) {26642665/* this is how many new masterpointers we want */2666i = SpaceBetweenPointers(EndBags,StopBags)/7 - (SpaceBetweenPointers(OldBags,MptrBags)-NrLiveBags);26672668/* move the bags area */2669memmove((void *)(OldBags+i), (void *)OldBags, SpaceBetweenPointers(AllocBags,OldBags)*sizeof(*OldBags));26702671/* update the masterpointers */2672for ( p = MptrBags; p < OldBags; p++ ) {2673if ( (Bag)OldBags <= *p)2674*p += i;2675}26762677/* link the new part of the masterpointer area */2678for ( p = OldBags;2679p + 2*SIZE_MPTR_BAGS <= OldBags+i;2680p += SIZE_MPTR_BAGS ) {2681*p = (Bag)(p + SIZE_MPTR_BAGS);2682}2683*p = (Bag)FreeMptrBags;2684FreeMptrBags = (Bag)OldBags;26852686/* update 'OldBags', 'YoungBags', 'AllocBags', and 'StopBags' */2687OldBags += i;2688YoungBags += i;2689AllocBags += i;2690StopBags += i;26912692}26932694/* now we are done */2695done = 1;26962697}26982699/* information after the check phase */2700if ( MsgsFuncBags )2701(*MsgsFuncBags)( FullBags, 5,2702SpaceBetweenPointers(EndBags, StopBags)/(1024/sizeof(Bag)));2703if ( MsgsFuncBags )2704(*MsgsFuncBags)( FullBags, 6,2705SpaceBetweenPointers(EndBags, MptrBags)/(1024/sizeof(Bag)));27062707/* reset the stop pointer */2708if ( ! CacheSizeBags || EndBags < StopBags+WORDS_BAG(1024*AllocSizeBags) )2709StopBags = EndBags;2710else2711StopBags = StopBags + WORDS_BAG(1024*AllocSizeBags);27122713/* if we are not done, then true again */2714if ( ! done ) {2715FullBags = 1;2716goto again;2717}27182719/* call the after function (if any) */2720if ( AfterCollectFuncBags != 0 )2721(*AfterCollectFuncBags)();272227232724#ifdef DEBUG_MASTERPOINTERS2725CheckMasterPointers();2726#endif27272728/* Possibly advise the operating system about unused pages: */2729SyMAdviseFree();27302731CANARY_ENABLE_VALGRIND();27322733/* return success */2734return 1;2735#else2736#ifndef DISABLE_GC2737GC_gcollect();2738#endif2739return 1;2740#endif2741}274227432744/****************************************************************************2745**2746*F CheckMasterPointers() . . . . do consistency checks on the masterpointers2747**2748*/27492750#ifndef BOEHM_GC2751void CheckMasterPointers( void )2752{2753Bag *ptr;2754for (ptr = MptrBags; ptr < OldBags; ptr++)2755{2756if (*ptr != (Bag)0 && /* bottom of free chain */2757*ptr != (Bag)NewWeakDeadBagMarker &&2758*ptr != (Bag)OldWeakDeadBagMarker &&2759(((Bag *)*ptr < MptrBags &&2760(Bag *)*ptr > AllocBags) ||2761(UInt)(*ptr) % sizeof(Bag) != 0))2762(*AbortFuncBags)("Bad master pointer detected in check");2763}2764}2765#endif276627672768/****************************************************************************2769**2770*F SwapMasterPoint( <bag1>, <bag2> ) . . . swap pointer of <bag1> and <bag2>2771*/2772void SwapMasterPoint (2773Bag bag1,2774Bag bag2 )2775{2776Bag * ptr1;2777Bag * ptr2;27782779if ( bag1 == bag2 )2780return;27812782/* get the pointers */2783ptr1 = PTR_BAG(bag1);2784ptr2 = PTR_BAG(bag2);27852786/* check and update the link field and changed bags */2787if ( PTR_BAG(bag1)[-1] == bag1 && PTR_BAG(bag2)[-1] == bag2 ) {2788PTR_BAG(bag1)[-1] = bag2;2789PTR_BAG(bag2)[-1] = bag1;2790}2791else if ( PTR_BAG(bag1)[-1] == bag1 ) {2792PTR_BAG(bag1)[-1] = ChangedBags;2793ChangedBags = bag1;2794}2795else if ( PTR_BAG(bag2)[-1] == bag2 ) {2796PTR_BAG(bag2)[-1] = ChangedBags;2797ChangedBags = bag2;2798}27992800/* swap them */2801PTR_BAG(bag1) = ptr2;2802PTR_BAG(bag2) = ptr1;2803}2804280528062807/****************************************************************************2808**28092810*F BID(<bag>) . . . . . . . . . . . . bag identifier (as unsigned integer)2811*F IS_BAG(<bid>) . . . . . . test whether a bag identifier identifies a bag2812*F BAG(<bid>) . . . . . . . . . . . . . . . . . . bag (from bag identifier)2813*F TNUM_BAG(<bag>) . . . . . . . . . . . . . . . . . . . . . . type of a bag2814*F SIZE_BAG(<bag>) . . . . . . . . . . . . . . . . . . . . . . size of a bag2815*F PTR_BAG(<bag>) . . . . . . . . . . . . . . . . . . . . pointer to a bag2816*F ELM_BAG(<bag>,<i>) . . . . . . . . . . . . . . . <i>-th element of a bag2817*F SET_ELM_BAG(<bag>,<i>,<elm>) . . . . . . . . set <i>-th element of a bag2818**2819** 'BID', 'IS_BAG', 'BAG', 'TNUM_BAG', 'TNAM_BAG', 'PTR_BAG', 'ELM_BAG', and2820** 'SET_ELM_BAG' are functions to support debugging. They are not intended2821** to be used in an application using {\Gasman}. Note that the functions2822** 'TNUM_BAG', 'SIZE_BAG', and 'PTR_BAG' shadow the macros of the same name,2823** which are usually not available in a debugger.2824*/28252826#ifdef DEBUG_FUNCTIONS_BAGS28272828#undef TNUM_BAG2829#undef SIZE_BAG2830#undef PTR_BAG28312832UInt BID (2833Bag bag )2834{2835return (UInt) bag;2836}283728382839Bag BAG (2840UInt bid )2841{2842if ( IS_BAG(bid) )2843return (Bag) bid;2844else2845return (Bag) 0;2846}28472848UInt TNUM_BAG (2849Bag bag )2850{2851return (*(*(bag)-3) & 0xFFL);2852}28532854const Char * TNAM_BAG (2855Bag bag )2856{2857return InfoBags[ (*(*(bag)-3) & 0xFFL) ].name;2858}28592860UInt SIZE_BAG (2861Bag bag )2862{2863return (*(*(bag)-2));2864}28652866Bag * PTR_BAG (2867Bag bag )2868{2869return (*(Bag**)(bag));2870}28712872UInt ELM_BAG (2873Bag bag,2874UInt i )2875{2876return (UInt) ((*(Bag**)(bag))[i]);2877}28782879UInt SET_ELM_BAG (2880Bag bag,2881UInt i,2882UInt elm )2883{2884(*(Bag**)(bag))[i] = (Bag) elm;2885return elm;2886}28872888#endif288928902891/****************************************************************************2892**2893*E gasman.c . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here2894*/289528962897