/****************************************************************************
* *
* * This file is part of GAP , a system for computational discrete algebra .
* *
* * Copyright of GAP belongs to its developers , whose names are too numerous
* * to list here . Please refer to the COPYRIGHT file for details .
* *
* * SPDX - License - Identifier : GPL - 2 . 0 - or - later
* *
* * This file declares the functions of Gasman , the GAP storage manager .
* *
* * { \ Gasman } is a storage manager for applications written in C . That means
* * that an application requests blocks of storage from { \ Gasman } , which are
* * called bags . After using a bag to store data , the application simply
* * forgets the bag , and we say that such a block is dead . { \ Gasman }
* * implements an automatic , cooperating , compacting , generational ,
* * conservative storage manager . Automatic means that the application only
* * allocates bags , but need not explicitly deallocate them . This is
* * important for large or complex application , where explicit deallocation
* * is difficult . Cooperating means that the allocation must cooperate with
* * { \ Gasman } , i . e . , must follow certain rules . This information provided by
* * the application makes { \ Gasman } use less storage and run faster .
* * Compacting means that { \ Gasman } always compacts live bags such that the
* * free storage is one large block . Because there is no fragmentation of
* * the free storage { \ Gasman } uses as little storage as possible .
* * Generational means that { \ Gasman } usually assumes that bags that have
* * been live for some time are still live . This means that it can avoid
* * most of the tests whether a bag is still live or already dead . Only when
* * not enough storage can be reclaimed under this assumption does it perform
* * all the tests . Conservative means that { \ Gasman } may keep bags longer
* * than necessary because the C compiler does not provide sufficient
* * information to distinguish true references to bags from other values that
* * happen to look like references .
*/
#ifndef GAP_GASMAN_H
#define GAP_GASMAN_H
#include "common.h"
/****************************************************************************
* *
* T Bag . . . . . . . . . . . . . . . . . . . type of the identifier of a bag
* *
* * Each bag is identified by its * bag identifier * . That is each bag has a
* * bag identifier and no two live bags have the same identifier . ' Bag ' is
* * the type of bag identifiers .
* *
* * 0 is a valid value of the type ' Bag ' , but is guaranteed not to be the
* * identifier of any bag .
* *
* * ' NewBag ' returns the identifier of the newly allocated bag and the
* * application passes this identifier to every { \ Gasman } function to tell it
* * which bag it should operate on ( see " NewBag " , " TNUM_BAG " , " SIZE_BAG " ,
* * " PTR_BAG " , " CHANGED_BAG " , " RetypeBag " , and " ResizeBag " ) .
* *
* * Note that the identifier of a bag is different from the address of the
* * data area of the bag . This address may change during a garbage
* * collection while the identifier of a bag never changes .
* *
* * Bags that contain references to other bags must always contain the
* * identifiers of these other bags , never the addresses of the data areas of
* * the bags .
* *
* * Note that bag identifiers are recycled . That means that after a bag dies
* * its identifier may be reused for a new bag .
* *
* * The following is defined in " common . h "
* *
typedef UInt * * Bag ;
*/
/****************************************************************************
* *
* T BagHeader
*/
typedef struct {
uint8_t type : 8 ;
uint8_t flags : 8 ;
// the following unnamed field ensures that on 32 bit systems,
// the 'size' field is aligned to a 32 bit boundary
uint16_t : (sizeof (UInt) == 8 ) ? 0 : 16 ;
uint64_t size : (sizeof (UInt) == 8 ) ? 48 : 32 ;
#ifdef USE_GASMAN
Bag link;
#endif
#if defined (GAP_MEMORY_CANARY)
// The following variable is marked as not readable or writable
// in valgrind, to check for code reading before the start of a Bag.
uint64_t memory_canary_padding[8 ];
#endif
} BagHeader;
/****************************************************************************
* *
* * ' NUM_TYPES ' is the maximal number of different types supported , and
* * depends on the number of bits in the type member of struct BagHeader .
* * It must be a power of two .
*/
enum {
NUM_TYPES = 256 ,
};
/****************************************************************************
* *
* F BAG_HEADER ( < bag > ) . . . . . . . . . . . . . . . . . . . . header of a bag
* F CONST_BAG_HEADER ( < bag > ) . . . . . . . . . . . . read - only header of a bag
* *
* * ' BAG_HEADER ' returns the header of the bag with the identifier < bag > .
*/
EXPORT_INLINE BagHeader * BAG_HEADER(Bag bag)
{
GAP_ASSERT(bag);
return ((*(BagHeader **)bag) - 1 );
}
EXPORT_INLINE const BagHeader * CONST_BAG_HEADER(Bag bag)
{
GAP_ASSERT(bag);
return ((*(const BagHeader **)bag) - 1 );
}
/****************************************************************************
* *
* F TNUM_BAG ( < bag > ) . . . . . . . . . . . . . . . . . . . . . . type of a bag
* *
* * ' TNUM_BAG ' returns the type of the bag with the identifier < bag > .
* *
* * Each bag has a certain type that identifies its structure . The type is a
* * integer between 0 and 253 . The types 254 and 255 are reserved for
* * { \ Gasman } . The application specifies the type of a bag when it allocates
* * it with ' NewBag ' and may later change it with ' RetypeBag ' ( see " NewBag "
* * and " RetypeBag " ) .
* *
* * { \ Gasman } needs to know the type of a bag so that it knows which function
* * to call to mark all subbags of a given bag ( see " InitMarkFuncBags " ) .
* * Apart from that { \ Gasman } does not care at all about types .
*/
EXPORT_INLINE UInt TNUM_BAG(Bag bag)
{
return CONST_BAG_HEADER(bag)->type;
}
/****************************************************************************
* *
* F TEST_BAG_FLAG ( < bag > , < flag > ) . . . . . . . . . . . . . . . test bag flag
* F SET_BAG_FLAG ( < bag > , < flag > ) . . . . . . . . . . . . . . . . set bag flag
* F CLEAR_BAG_FLAG ( < bag > , < flag > ) . . . . . . . . . . . . . . clear bag flag
* *
* * These three macros test , set , and clear bag flags , respectively .
* * Bag flags are stored in the bag header . Multiple flags can be ored
* * together using ' | ' to set or clear multiple flags at once .
* *
* * TEST_BAG_FLAG ( ) will return the ored version of all tested flags . To
* * test that one of them is set , check if the result is not equal to zero .
* * To test that all of them are set , compare the result to the original
* * flags , e . g .
* *
* * if ( TEST_BAG_FLAG ( obj , FLAG1 | FLAG2 ) = = ( FLAG1 | FLAG2 ) ) . . .
* *
* * Similarly , if you wish to test that FLAG1 is set and FLAG2 is not set ,
* * use :
* *
* * if ( TEST_BAG_FLAG ( obj , FLAG1 | FLAG2 ) = = FLAG1 ) . . .
* *
* * Each flag must be an integer with exactly one bit set , e . g . a value
* * of the form ( 1 < < i ) . Currently , ' i ' must be in the range from 0 to
* * 7 ( inclusive ) .
*/
EXPORT_INLINE uint8_t TEST_BAG_FLAG(Bag bag, uint8_t flag)
{
return CONST_BAG_HEADER(bag)->flags & flag;
}
EXPORT_INLINE void SET_BAG_FLAG(Bag bag, uint8_t flag)
{
BAG_HEADER(bag)->flags |= flag;
}
EXPORT_INLINE void CLEAR_BAG_FLAG(Bag bag, uint8_t flag)
{
BAG_HEADER(bag)->flags &= ~flag;
}
/****************************************************************************
* *
* F IS_BAG_REF ( < bag > ) . . . . . . verify that < bag > is a valid bag identifier
* *
* * ' IS_BAG_REF ' checks whether < bag > is a valid bag identifier , i . e . that
* * it is neither zero , nor an immediate object .
* *
* * See also ' IS_INTOBJ ' and ' IS_FFE ' .
*/
EXPORT_INLINE BOOL IS_BAG_REF(Obj bag)
{
return bag && !((Int )bag & 0 x03);
}
/****************************************************************************
* *
* F SIZE_BAG ( < bag > ) . . . . . . . . . . . . . . . . . . . . . . size of a bag
* *
* * ' SIZE_BAG ' returns the size of the bag with the identifier < bag > in
* * bytes .
* *
* * Each bag has a certain size . The size of a bag is measured in bytes .
* * The size must be a value between 0 and $ 2 ^ { 32 } - 1 $ ( on 32 bit systems )
* * respectively $ 2 ^ { 48 } - 1 $ ( on 64 bit systems ) . The application specifies
* * the size of a bag when it allocates it with ' NewBag ' and may later change
* * it with ' ResizeBag ' ( see " NewBag " and " ResizeBag " ) .
*/
EXPORT_INLINE UInt SIZE_BAG(Bag bag)
{
return CONST_BAG_HEADER(bag)->size;
}
/****************************************************************************
* *
* F SIZE_BAG_CONTENTS ( < ptr > ) . . . . . . . . . . . . . . . . . size of a bag
* *
* * ' SIZE_BAG_CONTENTS ' performs the same function as ' SIZE_BAG ' , but takes
* * a pointer to the contents of the bag instead . This is useful for certain
* * atomic operations that require a memory barrier in between dereferencing
* * the bag pointer and accessing the contents of the bag .
*/
EXPORT_INLINE UInt SIZE_BAG_CONTENTS(const void *ptr)
{
return ((const BagHeader *)ptr)[-1 ].size;
}
/****************************************************************************
* *
* F LINK_BAG ( < bag > ) . . . . . . . . . . . . . . . . . . link pointer of a bag
* *
* * ' LINK_BAG ' returns the link pointer of the bag with the identifier < bag > .
* *
* * Note that ' LINK_BAG ' is a macro , so do not call it with arguments that
* * have side effects .
*/
#ifdef USE_GASMAN
#define LINK_BAG(bag) (BAG_HEADER(bag)->link)
#endif
/****************************************************************************
* *
* F PTR_BAG ( < bag > ) . . . . . . . . . . . . . . . . . . . . . pointer to a bag
* F CONST_PTR_BAG ( < bag > ) . . . . . . . . . . . . . read - only pointer to a bag
* F SET_PTR_BAG ( < bag > ) . . . . . . . . . . . . . . . set the pointer to a bag
* *
* * ' PTR_BAG ' returns the address of the data area of the bag with identifier
* * < bag > . Using this pointer the application can then read data from the
* * bag or write data into it . The pointer is of type pointer to bag
* * identifier , i . e . , ' PTR_BAG ( < bag > ) [ 0 ] ' is the identifier of the first
* * subbag of the bag , etc . If the bag contains data in a different format ,
* * the application has to cast the pointer returned by ' PTR_BAG ' , e . g . ,
* * ' ( long \ * ) PTR_BAG ( < bag > ) ' .
* *
* * Note that the address of the data area of a bag may change during a
* * garbage collection . That is the value returned by ' PTR_BAG ' may differ
* * between two calls , if ' NewBag ' , ' ResizeBag ' , ' CollectBags ' , or any of the
* * application \ ' s functions or macros that may call those functions , is
* * called in between ( see " NewBag " , " ResizeBag " , " CollectBags " ) .
* *
* * The first rule for using { \ Gasman } is { \ : } * The application must not keep
* * any pointers to or into the data area of any bag over calls to functions
* * that may cause a garbage collection . *
* *
* * That means that the following code is incorrect { \ : }
* *
* * ptr = PTR_BAG ( old ) ;
* * new = NewBag ( typeNew , sizeNew ) ;
* * * ptr = new ;
* *
* * because the creation of the new bag may move the old bag , causing the
* * pointer to point no longer to the data area of the bag . It must be
* * written as follows { \ : }
* *
* * new = NewBag ( typeNew , sizeNew ) ;
* * ptr = PTR_BAG ( old ) ;
* * * ptr = new ;
* *
* * Note that even the following is incorrect { \ : }
* *
* * PTR_BAG ( old ) [ 0 ] = NewBag ( typeNew , sizeNew ) ;
* *
* * because a C compiler is free to compile it to a sequence of instructions
* * equivalent to first example . Thus whenever the evaluation of a function
* * or a macro may cause a garbage collection there must be no call to
* * ' PTR_BAG ' in the same expression , except as argument to this function or
* * macro .
* *
* * Note that after writing a bag identifier , e . g . , ' new ' in the above
* * example , into the data area of another bag , ' old ' in the above example ,
* * the application must inform { \ Gasman } that it has changed the bag , by
* * calling ' CHANGED_BAG ( old ) ' in the above example ( see " CHANGED_BAG " ) .
*/
EXPORT_INLINE Bag *PTR_BAG(Bag bag)
{
GAP_ASSERT(bag != 0 );
return *(Bag**)bag;
}
EXPORT_INLINE const Bag *CONST_PTR_BAG(Bag bag)
{
GAP_ASSERT(bag != 0 );
return *(const Bag * const *)bag;
}
#if defined (USE_BOEHM_GC)
void SET_PTR_BAG(Bag bag, Bag *val);
#endif
/****************************************************************************
* *
* F CHANGED_BAG ( < bag > ) . . . . . . . . notify Gasman that a bag has changed
* *
* * ' CHANGED_BAG ' informs { \ Gasman } that the bag with identifier < bag > has
* * been changed by an assignment of another bag identifier .
* *
* * The second rule for using { \ Gasman } is { \ : } * After each assignment of a
* * bag identifier into a bag the application must inform { \ Gasman } that it
* * has changed the bag before the next garbage collection can happen . *
* *
* * Note that the application need not inform { \ Gasman } if it changes a bag
* * by assigning something that is not an identifier of another bag .
* *
* * For example to copy all entries from one list into another the following
* * code must be used { \ : }
* *
* * for ( i = 0 ; i < SIZE - BAG ( old ) / sizeof ( Bag ) ; i + + )
* * PTR_BAG ( new ) [ i ] = PTR_BAG ( old ) [ i ] ;
* * CHANGED_BAG ( new ) ;
* *
* * On the other hand when the application allocates a matrix , where the
* * allocation of each row may cause a garbage collection , the following code
* * must be used { \ : }
* *
* * mat = NewBag ( T_MAT , n * sizeof ( Bag ) ) ;
* * for ( i = 0 ; i < n ; i + + ) {
* * row = NewBag ( T_ROW , n * sizeof ( Bag ) ) ;
* * PTR_BAG ( mat ) [ i ] = row ;
* * CHANGED_BAG ( mat ) ;
* * }
* *
* * Note that writing ' PTR_BAG ( mat ) [ i ] = NewBag ( T_ROW , n \ * \ sizeof ( Bag ) ) ; '
* * is incorrect as mentioned in the section for ' PTR_BAG ' ( see " PTR_BAG " ) .
*/
#if defined (USE_BOEHM_GC)
EXPORT_INLINE void CHANGED_BAG(Bag bag)
{
}
#elif defined (USE_JULIA_GC)
void CHANGED_BAG(Bag bag);
BOOL IsGapObj(void *);
#elif defined (GAP_MEMORY_CANARY)
/****************************************************************************
* *
* * GAP_MEMORY_CANARY provides ( basic ) support for catching out - of - bounds
* * memory problems in GAP . This is done through the excellent ' valgrind '
* * program . Valgrind is of limited use in GAP normally , because it doesn ' t
* * understand GAP ' s memory manager . Enabling GAP_MEMORY_CANARY will make an
* * executable where valgrind will detect memory issues .
* *
*/
void CHANGED_BAG(Bag b);
#elif defined (USE_GASMAN)
extern Bag * YoungBags;
extern Bag ChangedBags;
#ifdef GAP_KERNEL_DEBUG
BOOL InWorkspaceRestore(void );
#endif
EXPORT_INLINE void CHANGED_BAG(Bag bag)
{
GAP_ASSERT(!InWorkspaceRestore());
if (CONST_PTR_BAG(bag) <= YoungBags && LINK_BAG(bag) == bag) {
LINK_BAG(bag) = ChangedBags;
ChangedBags = bag;
}
}
#else
#error unknown garbage collector
#endif
/****************************************************************************
* *
* F NewBag ( < type > , < size > ) . . . . . . . . . . . . . . . . allocate a new bag
* *
* * ' NewBag ' allocates a new bag of type < type > and < size > bytes . ' NewBag '
* * returns the identifier of the new bag , which must be passed as first
* * argument to all other { \ Gasman } functions .
* *
* * < type > must be a value between 0 and 253 . The types 254 and 255 are
* * reserved for { \ Gasman } . The application can find the type of a bag with
* * ' TNUM_BAG ' and change it with ' RetypeBag ' ( see " TNUM_BAG " and
* * " RetypeBag " ) .
* *
* * It is probably a good idea to define symbolic constants for all types in
* * a system wide header file , e . g . , ' types . h ' , if only to avoid to
* * accidentally use the same value for two different types .
* *
* * < size > is the size of the new bag in bytes and must be a value between 0
* * and $ 2 ^ { 32 } - 1 $ ( on 32 bit systems ) resp . $ 2 ^ { 48 } - 1 $ ( on 64 bit systems ) .
* * The application can find the size of a bag with ' SIZE_BAG ' and change it
* * with ' ResizeBag ' ( see " SIZE_BAG " and " ResizeBag " ) .
* *
* * All entries of the new bag will be initialized to 0 .
* *
* * What happens if { \ Gasman } cannot get enough storage to perform an
* * allocation depends on the behavior of the allocation function
* * < alloc - func > . If < alloc - func > returns 0 when it cannot do a needed
* * extension of the workspace , then ' NewBag ' may return 0 to indicate
* * failure , and the application has to check the return value of ' NewBag '
* * for this . If < alloc - func > aborts when it cannot do a needed extension of
* * the workspace , then the application will abort if ' NewBag ' would not
* * succeed . So in this case whenever ' NewBag ' returns , it succeeded , and
* * the application need not check the return value of ' NewBag ' ( see
* * " InitBags " ) .
* *
* * Note that ' NewBag ' will perform a garbage collection if no free storage
* * is available . During the garbage collection the addresses of the data
* * areas of all bags may change . So you must not keep any pointers to or
* * into the data areas of bags over calls to ' NewBag ' ( see " PTR_BAG " ) .
*/
Bag NewBag(UInt type, UInt size);
// NewWordSizedBag is the same as NewBag, except it rounds 'size' up to
// the next multiple of sizeof(UInt)
EXPORT_INLINE Bag NewWordSizedBag(UInt type, UInt size)
{
UInt padding = 0 ;
if (size % sizeof (UInt) != 0 ) {
padding = sizeof (UInt) - (size % sizeof (UInt));
}
return NewBag(type, size + padding);
}
/****************************************************************************
* *
* F RetypeBag ( < bag > , < new > ) . . . . . . . . . . . . . change the type of a bag
* F RetypeBagIntern ( < bag > , < new > ) . . . . . . . . . . . . . internal interface
* *
* * ' RetypeBag ' changes the type of the bag with identifier < bag > to the new
* * type < new > . The identifier , the size , and also the address of the data
* * area of the bag do not change .
* *
* * ' Retype ' is usually used to set or reset flags that are stored in the
* * type of a bag . For example in { \ GAP } there are two types of large
* * integers , one for positive integers and one for negative integers . To
* * compute the difference of a positive integer and a negative , { \ GAP } uses
* * ' RetypeBag ' to temporarily change the second argument into a positive
* * integer , and then adds the two operands . For another example when { \ GAP }
* * detects that a list is sorted and contains no duplicates , it changes the
* * type of the bag with ' RetypeBag ' , and the new type indicates that this
* * list has this property , so that this need not be tested again .
* *
* * It is , as usual , the responsibility of the application to ensure that the
* * data stored in the bag makes sense when the bag is interpreted as a bag
* * of type < type > .
* *
* * ' RetypeBagIntern ' is the internal version of ' RetypeBag ' , implemented by
* * the GC backend . It is called by ' RetypeBag ' .
*/
void RetypeBagIntern(Bag bag, UInt new_type);
#ifdef HPCGAP
void RetypeBagIfWritable(Bag bag, UInt new_type);
#else
#define RetypeBagIfWritable(x,y) RetypeBag(x,y)
#endif
#ifdef GAP_KERNEL_DEBUG
// This helper tests whether the type change is "allowed". As such, it rejects
// attempts to retype an immutable list or record into a mutable one.
void PrecheckRetypeBag(Bag bag, UInt new_type);
#endif
EXPORT_INLINE void RetypeBag(Bag bag, UInt new_type)
{
#ifdef GAP_KERNEL_DEBUG
PrecheckRetypeBag(bag, new_type);
#endif
RetypeBagIntern(bag, new_type);
}
/****************************************************************************
* *
* * ' RetypeBagSM ' works like ' RetypeBag ' , but ensures that the given bag
* * retains the same mutability ( SM ) .
* *
* * FIXME : for now , this checks the tnums ; later , this will be turned
* * into a check for an object flag
*/
void RetypeBagSM(Bag bag, UInt new_type);
#ifdef HPCGAP
void RetypeBagSMIfWritable(Bag bag, UInt new_type);
#else
#define RetypeBagSMIfWritable(x,y) RetypeBagSM(x,y)
#endif
/****************************************************************************
* *
* F ResizeBag ( < bag > , < new > ) . . . . . . . . . . . . change the size of a bag
* *
* * ' ResizeBag ' changes the size of the bag with identifier < bag > to the new
* * size < new > . The identifier of the bag does not change , but the address
* * of the data area of the bag may change . If the new size < new > is less
* * than the old size , { \ Gasman } throws away any data in the bag beyond the
* * new size . If the new size < new > is larger than the old size , { \ Gasman }
* * extends the bag .
* *
* * All entries of an extension will be initialized to 0 .
* *
* * What happens if { \ Gasman } cannot get enough storage to perform an
* * extension depends on the behavior of the allocation function
* * < alloc - func > . If < alloc - func > returns 0 when it cannot do a needed
* * extension of the workspace , then ' ResizeBag ' may return 0 to indicate
* * failure , and the application has to check the return value of ' ResizeBag '
* * for this . If < alloc - func > aborts when it cannot do a needed extension of
* * the workspace , then the application will abort if ' ResizeBag ' would not
* * succeed . So in this case whenever ' ResizeBag ' returns , it succeeded , and
* * the application need not check the return value of ' ResizeBag ' ( see
* * " InitBags " ) .
* *
* * Note that ' ResizeBag ' will perform a garbage collection if no free
* * storage is available . During the garbage collection the addresses of the
* * data areas of all bags may change . So you must not keep any pointers to
* * or into the data areas of bags over calls to ' ResizeBag ' ( see " PTR_BAG " ) .
*/
UInt ResizeBag(Bag bag, UInt new_size);
// ResizedWordSizedBag is the same as ResizeBag, except it round 'size'
// up to the next multiple of sizeof(UInt)
EXPORT_INLINE UInt ResizeWordSizedBag(Bag bag, UInt size)
{
UInt padding = 0 ;
if (size % sizeof (UInt) != 0 ) {
padding = sizeof (UInt) - (size % sizeof (UInt));
}
return ResizeBag(bag, size + padding);
}
/****************************************************************************
* *
* F CollectBags ( < size > , < full > ) . . . . . . . . . . . . . . collect dead bags
* *
* * ' CollectBags ' performs a garbage collection . This means it deallocates
* * the dead bags and compacts the live bags at the beginning of the
* * workspace . If < full > is 0 , then only the dead young bags are
* * deallocated , otherwise all dead bags are deallocated .
* *
* * If the application calls ' CollectBags ' , < size > must be 0 , and < full > must
* * be 0 or 1 depending on whether it wants to perform a partial or a full
* * garbage collection .
* *
* * If ' CollectBags ' is called from ' NewBag ' or ' ResizeBag ' , < size > is the
* * size of the bag that is currently allocated , and < full > is zero .
* *
* * Note that during the garbage collection the addresses of the data areas
* * of all bags may change . So you must not keep any pointers to or into the
* * data areas of bags over calls to ' CollectBags ' ( see " PTR_BAG " ) .
*/
UInt CollectBags(UInt size, UInt full);
/****************************************************************************
* *
* F SwapMasterPoint ( < bag1 > , < bag2 > ) . . . swap pointer of < bag1 > and < bag2 >
*/
void SwapMasterPoint(Bag bag1, Bag bag2);
/****************************************************************************
* *
* V SizeAllBags . . . . . . . . . . . . . . total size of all bags allocated
* *
* * ' SizeAllBags ' is the total size of bags allocated since Gasman was
* * initialized . It is incremented for each ' NewBag ' call .
*/
extern UInt8 SizeAllBags;
/****************************************************************************
* *
* V InfoBags [ < type > ] . . . . . . . . . . . . . . . . . information for bags
* *
* * ' InfoBags [ < type > ] ' is a structure containing information for bags of the
* * type < type > .
* *
* * ' InfoBags [ < type > ] . nrLive ' is the number of bags of type < type > that are
* * currently live .
* *
* * ' InfoBags [ < type > ] . nrAll ' is the total number of all bags of < type > that
* * have been allocated .
* *
* * ' InfoBags [ < type > ] . sizeLive ' is the sum of the sizes of the bags of type
* * < type > that are currently live .
* *
* * ' InfoBags [ < type > ] . sizeAll ' is the sum of the sizes of all bags of type
* * < type > that have been allocated .
* *
* * This information is only kept if { \ Gasman } is compiled with the option
* * ' COUNT_BAGS ' defined .
*/
#ifdef COUNT_BAGS
typedef struct {
UInt nrLive;
UInt nrAll;
UInt sizeLive;
UInt sizeAll;
} TNumInfoBags;
extern TNumInfoBags InfoBags [ 256 ];
#endif
#ifdef HPCGAP
void MakeBagTypePublic(int type);
Bag MakeBagPublic(Bag bag);
Bag MakeBagReadOnly(Bag bag);
#endif
/****************************************************************************
* *
* F InitMarkFuncBags ( < type > , < mark - func > ) . . . . . install marking function
* *
* * ' InitMarkFuncBags ' installs the function < mark - func > as marking function
* * for bags of type < type > . The application * must * install a marking
* * function for a type before it allocates any bag of that type . It is
* * probably best to install all marking functions before allocating any bag .
* *
* * A marking function is a function that takes a two arguments , one of type
* * ' Bag ' and one of type ' void * ' and returns nothing , i . e . , has return type
* * ' void ' . Such a function must apply the function ' MarkBag ' to each bag
* * identifier that appears in the bag ( see below ) , passing on its ' void * '
* * argument unchanged to ' MarkBag ' as second argument .
* *
* * Those functions are applied during the garbage collection to each marked
* * bag , i . e . , bags that are assumed to be still live , to also mark their
* * subbags . The ability to use the correct marking function is the only use
* * that { \ Gasman } has for types .
* *
* * { \ Gasman } already provides several marking functions , see below .
*/
#define GAP_MARK_FUNC_WITH_REF 1
typedef void (* TNumMarkFuncBags )( Bag bag, void * ref );
void InitMarkFuncBags(UInt type, TNumMarkFuncBags mark_func);
#if !defined (USE_THREADSAFE_COPYING) && !defined (USE_BOEHM_GC)
extern TNumMarkFuncBags TabMarkFuncBags[NUM_TYPES];
#endif
/****************************************************************************
* *
* F MarkNoSubBags ( < bag > ) . . . . . . . . marking function that marks nothing
* *
* * ' MarkNoSubBags ' is a marking function for types whose bags contain no
* * identifier of other bags . It does nothing , as its name implies , and
* * simply returns . For example in { \ GAP } the bags for large integers
* * contain only the digits and no identifiers of bags .
*/
void MarkNoSubBags(Bag bag, void * ref);
/****************************************************************************
* *
* F MarkOneSubBags ( < bag > ) . . . . . . marking function that marks one subbag
* F MarkTwoSubBags ( < bag > ) . . . . . . marking function that marks two subbags
* F MarkThreeSubBags ( < bag > ) . . . . marking function that marks three subbags
* F MarkFourSubBags ( < bag > ) . . . . . marking function that marks four subbags
* *
* * These are marking functions for types whose bags contain exactly the
* * the indicated number as bag identifiers as their initial entries .
* * These functions mark those subbags and return .
*/
void MarkOneSubBags(Bag bag, void * ref);
void MarkTwoSubBags(Bag bag, void * ref);
void MarkThreeSubBags(Bag bag, void * ref);
void MarkFourSubBags(Bag bag, void * ref);
/****************************************************************************
* *
* F MarkAllSubBags ( < bag > ) . . . . . . marking function that marks everything
* *
* * ' MarkAllSubBags ' is the marking function for types whose bags contain
* * only identifier of other bags . It marks every entry of such a bag . Note
* * that ' MarkAllSubBags ' assumes that all identifiers are at offsets from
* * the address of the data area of < bag > that are divisible by
* * ' sizeof ( Bag ) ' . Note also that since it does not do any harm to mark
* * something which is not actually a bag identifier one could use
* * ' MarkAllSubBags ' for all types as long as the identifiers in the data
* * area are properly aligned as explained above . This would however slow
* * down ' CollectBags ' . For example in { \ GAP } bags for lists contain only
* * bag identifiers for the elements of the list or 0 if an entry has no
* * assigned value .
*/
void MarkAllSubBags(Bag bag, void * ref);
/****************************************************************************
* *
* F MarkAllButFirstSubBags ( < bag > ) . . . . marks all subbags except the first
*/
void MarkAllButFirstSubBags(Bag bag, void * ref);
/****************************************************************************
* *
* F MarkBag ( < bag > ) . . . . . . . . . . . . . . . . . . . mark a bag as live
* *
* * ' MarkBag ' marks the < bag > as live so that it is not thrown away during
* * a garbage collection . ' MarkBag ' should only be called from the marking
* * functions installed with ' InitMarkFuncBags ' .
* *
* * ' MarkBag ' tests if < bag > is a valid identifier of a bag in the young
* * bags area . If it is not , then ' MarkBag ' does nothing , so there is no
* * harm in calling ' MarkBag ' for something that is not actually a bag
* * identifier .
*/
#ifdef USE_BOEHM_GC
EXPORT_INLINE void MarkBag( Bag bag, void * ref )
{
}
#else
void MarkBag(Bag bag, void * ref);
#endif
/****************************************************************************
* *
* F MarkArrayOfBags ( < array > , < count > ) . . . . . . . mark all bags in an array
* *
* * ' MarkArrayOfBags ' iterates over < count > all bags in the given array ,
* * and marks each bag using MarkBag .
*/
extern void MarkArrayOfBags(const Bag array[], UInt count, void * ref);
/****************************************************************************
* *
* F InitGlobalBag ( < addr > , < cookie > ) inform Gasman about global bag identifier
* *
* * ' InitGlobalBag ' informs { \ Gasman } that there is a bag identifier at the
* * address < addr > , which must be of type ' ( Bag \ * ) ' . { \ Gasman } will look at
* * this address for a bag identifier during a garbage collection .
* *
* * The application * must * call ' InitGlobalBag ' for every global variable and
* * every entry of a global array that may hold a bag identifier . It is no
* * problem if such a variable does not actually hold a bag identifier ,
* * { \ Gasman } will simply ignore it then .
* *
* * There is a limit on the number of calls to ' InitGlobalBag ' , which is 20000
* * by default . If the application has more global variables that may hold
* * bag identifier , you have to compile { \ Gasman } with a higher value of
* * ' NR_GLOBAL_BAGS ' .
* *
* * < cookie > is a C string , which should uniquely identify this global
* * bag from all others . It is used in reconstructing the Workspace
* * after a save and load
*/
void InitGlobalBag(Bag * addr, const Char * cookie);
/****************************************************************************
* *
* F InitFreeFuncBag ( < type > , < free - func > ) . . . . . . install freeing function
* *
* * ' InitFreeFuncBag ' installs the function < free - func > as freeing function
* * for bags of type < type > .
* *
* * A freeing function is a function that takes a single argument of type
* * ' Bag ' and returns nothing , i . e . , has return type ' void ' . If such a
* * function is installed for a type < type > then it is called for each bag of
* * that type that is about to be deallocated .
* *
* * A freeing function must * not * call ' NewBag ' , ' ResizeBag ' , or ' RetypeBag ' .
* *
* * When such a function is called for a bag < bag > , its subbags are still
* * accessible . Note that it is not specified whether the freeing functions
* * for the subbags of < bag > ( if there are freeing functions for bags of
* * their types ) are called before or after the freeing function for < bag > .
*/
typedef void (* TNumFreeFuncBags ) (
Bag bag );
void InitFreeFuncBag(UInt type, TNumFreeFuncBags free_func);
/****************************************************************************
* *
* F RegisterBeforeCollectFuncBags ( < func > ) install before - collection function
* F RegisterAfterCollectFuncBags ( < func > ) . install after - collection function
* *
* * Register a callback to be called before respectively after each garbage
* * collection .
* *
* * One use of a < before - func > is to call ' CHANGED_BAG ' for bags that change
* * very often , so you do not have to call ' CHANGED_BAG ' for them every time
* * they change .
* *
* * One use of after - collection callbacks is to update a pointer for a bag ,
* * so you do not have to update that pointer after every operation that
* * might cause a garbage collection .
* *
* * The number of callbacks which can be registered is limited . If the
* * callback was successfully registered , 0 is returned , otherwise 1 .
*/
#ifdef USE_GASMAN
typedef void (* TNumCollectFuncBags) ( void );
int RegisterBeforeCollectFuncBags(TNumCollectFuncBags func);
int RegisterAfterCollectFuncBags(TNumCollectFuncBags func);
#endif
// ExtraMarkFuncBags, if not NULL, is called during garbage collection
// This is used for integrating GAP (possibly linked as a shared library) with
// other code bases which use their own form of garbage collection. For
// example, with Python (for SageMath).
typedef void (*TNumExtraMarkFuncBags)(void );
void SetExtraMarkFuncBags(TNumExtraMarkFuncBags func);
/****************************************************************************
* *
* F InitBags ( < initialSize > , < stackStart > ) . . . . . . . . . initialize Gasman
* *
* * ' InitBags ' initializes { \ Gasman } . It must be called from an application
* * using { \ Gasman } before any bags can be allocated .
* *
* * < initialSize > must be the size of the initial workspace that ' InitBags '
* * should allocate . This value is automatically rounded up to the next
* * multiple of 1 / 2 MByte by ' InitBags ' .
* *
* * < stackStart > must be the start of the stack . Note that the start of the
* * stack is either the bottom or the top of the stack , depending on whether
* * the stack grows upward or downward . A value that usually works is the
* * address of the argument ' argc ' of the ' main ' function of the application ,
* * i . e . , ' ( Bag \ * ) \ & argc ' .
*/
void InitBags(UInt initialSize, Bag * stackStart);
/****************************************************************************
* *
* F FinishBags ( ) end GASMAN and free memory
*/
void FinishBags(void );
#if !defined (USE_GASMAN)
void * AllocateMemoryBlock(UInt size);
#endif
/****************************************************************************
* *
* F TotalGCTime ( ) . . . . . . . . . . total time spent on garbage collection
*/
UInt TotalGCTime(void );
#endif // GAP_GASMAN_H
Messung V0.5 in Prozent C=95 H=100 G=97
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.76Bemerkung:
(vorverarbeitet am 2026-09-28)
¤
*Bot Zugriff