/**************************************************************************** ** ** 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 stores code only required by the boehm garbage collector ** ** The definitions of methods in this file can be found in gasman.h, ** where the non-boehm versions of these methods live.
**/
/* * Build memory layout information for Boehm GC. * * Bitmapped type descriptors have a bit set if the word at the * corresponding offset may contain a reference. This is done * by first creating a bitmap and then using GC_make_descriptor() * to build a descriptor from the bitmap. Memory for a specific * type layout can be allocated with GC_malloc_explicitly_typed() * and GC_malloc_explicitly_typed_ignore_off_page(). * * We also create a new 'kind' for each collector. Kinds have their * own associated free lists and do not require to have type information * stored in each bag, thus potentially saving some memory. Allocating * memory of a specific kind is done with GC_generic_malloc(). There * is no public _ignore_off_page() version for this call, so we use * GC_malloc_explicitly_typed_ignore_off_page() instead, given that * the overhead is negligible for large objects.
*/
staticvoid TLAllocatorInit(void)
{ unsigned stage = 16; unsigned inc = 1; unsigned i = 0; unsigned k = 0; unsigned j; unsigned max = TL_GC_SIZE / GRANULE_SIZE; while (i <= max) { if (i == stage) {
stage *= 2;
inc *= 2;
}
TLAllocatorSize[k] = i * GRANULE_SIZE;
TLAllocatorSeg[i] = k; for (j = 1; j < inc; j++) { if (i + j <= max)
TLAllocatorSeg[i + j] = k + 1;
}
i += inc;
k++;
}
TLAllocatorMaxSeg = k; if (MAX_GC_PREFIX_DESC * sizeof(void *) > sizeof(STATE(FreeList)))
abort();
}
/**************************************************************************** ** *F AllocateBagMemory( <gc_type>, <type>, <size> ) ** ** Allocate memory for a new bag. ** ** 'AllocateBagMemory' is an auxiliary routine for the Boehm GC that ** allocates memory from the appropriate pool. 'gc_type' is -1 if all words ** in the bag can refer to other bags, 0 if the bag will not contain any ** references to other bags, and > 0 to indicate a specific memory layout ** descriptor.
**/ staticvoid * AllocateBagMemory(int gc_type, int type, UInt size)
{
assert(gc_type >= -1); void * result = NULL; if (size <= TL_GC_SIZE) {
UInt alloc_seg, alloc_size;
alloc_size = (size + GRANULE_SIZE - 1) / GRANULE_SIZE;
alloc_seg = TLAllocatorSeg[alloc_size];
alloc_size = TLAllocatorSize[alloc_seg]; void *** freeList = STATE(FreeList); if (!freeList[gc_type + 1]) {
freeList[gc_type + 1] =
GC_malloc(sizeof(void *) * TLAllocatorMaxSeg);
} void ** freeListForType = freeList[gc_type + 1];
result = freeListForType[alloc_seg]; if (!result) { if (gc_type < 0)
freeListForType[alloc_seg] = GC_malloc_many(alloc_size); else
GC_generic_malloc_many(alloc_size, GCMKind[gc_type],
&freeListForType[alloc_seg]);
result = freeListForType[alloc_seg];
}
freeListForType[alloc_seg] = *(void **)result;
memset(result, 0, alloc_size);
} else { if (gc_type >= 0)
result = GC_generic_malloc(size, GCKind[gc_type]); else
result = GC_malloc(size);
} if (TabFreeFuncBags[type])
GC_register_finalizer_no_order(result, StandardFinalizer, NULL, NULL,
NULL); return result;
}
// install the marking functions for (i = 0; i < NUM_TYPES; i++) {
TabMarkTypeBags[i] = -1;
} #ifndef DISABLE_GC #ifdef HPCGAP if (!getenv("GC_MARKERS")) { /* The Boehm GC does not have an API to set the number of * markers for the parallel mark and sweep implementation, * so we use the documented environment variable GC_MARKERS * instead. However, we do not override it if it's already * set.
*/ staticchar marker_env_str[32]; unsigned num_markers = 2; if (!SyNumGCThreads)
SyNumGCThreads = SyNumProcessors; if (SyNumGCThreads) { if (SyNumGCThreads <= MAX_GC_THREADS)
num_markers = (unsigned)SyNumProcessors; else
num_markers = MAX_GC_THREADS;
}
sprintf(marker_env_str, "GC_MARKERS=%u", num_markers);
putenv(marker_env_str);
} #endif
GC_set_all_interior_pointers(0);
GC_set_handle_fork(1);
GC_init();
GC_set_free_space_divisor(1);
TLAllocatorInit();
GC_register_displacement(0);
GC_register_displacement(sizeof(BagHeader));
initial_size *= 1024; if (GC_get_heap_size() < initial_size)
GC_expand_hp(initial_size - GC_get_heap_size()); if (SyStorKill)
GC_set_max_heap_size(SyStorKill * 1024); #ifdef HPCGAP
AddGCRoots();
CreateMainRegion(); #else void * p = ActiveGAPState();
GC_add_roots(p, (char *)p + sizeof(GAPState)); #endif for (i = 0; i <= MAX_GC_PREFIX_DESC; i++) {
BuildPrefixGCDescriptor(i); /* This is necessary to initialize some internal structures
* in the garbage collector: */
GC_generic_malloc(sizeof(BagHeader) + i * sizeof(Bag), GCMKind[i]);
} #endif// DISABLE_GC
}
UInt TotalGCTime(void)
{ // TODO: implement this? However, this is non-trivial: while we can of // course measure how much time is spent in CollectBags(), I am not // aware of a way to decide whether an allocation registered trigger a // collection, and how long that took. return 0;
}
/* If the size of an object is zero (such as an empty permutation), * and the header size is a multiple of twice the word size of the * architecture, then the master pointer will actually point past * the allocated area. Because this would result in the object * being freed prematurely, we will allocate at least one extra * byte so that the master pointer actually points to within an * allocated memory area.
*/ if (size == 0)
alloc_size++; /* While we use the Boehm GC without the "all interior pointers" * option, stack references to the interior of an object will * still be valid from any reference on the stack. This can lead, * for example, to a 1GB string never being freed if there's an * integer on the stack that happens to also be a reference to * any character inside that string. The garbage collector does * this because after compiler optimizations (especially reduction * in strength) references to the beginning of an object may be * lost. * * However, this is not generally a risk with GAP objects, because * master pointers on the heap will always retain a reference to * the start of the object (or, more precisely, to the first byte * past the header area). Hence, compiler optimizations pose no * actual risk unless the master pointer is destroyed also. * * To avoid the scenario where large objects do not get deallocated, * we therefore use the _ignore_off_page() calls. One caveat here * is that these calls do not use thread-local allocation, making * them somewhat slower. Hence, we only use them for sufficiently * large objects.
*/
BagHeader * header =
AllocateBagMemory(TabMarkTypeBags[type], type, alloc_size); #else
bag = malloc(sizeof(struct OpaqueBag));
BagHeader * header = calloc(1, alloc_size); #endif// DISABLE_GC
// set the masterpointer
SET_PTR_BAG(bag, DATA(header)); #ifdef HPCGAP switch (DSInfoBags[type]) { case DSI_TL:
SET_REGION(bag, CurrentRegion()); break; case DSI_PUBLIC:
SET_REGION(bag, NULL); break;
} #endif
// return the identifier of the new bag return bag;
}
UInt ResizeBag(Bag bag, UInt new_size)
{
UInt type; // type of the bag
UInt flags;
UInt old_size; // old size of the bag
Bag * src; // source in copying
UInt alloc_size;
// check the size
#ifdef TREMBLE_HEAP
CollectBags(0, 0); #endif
BagHeader * header = BAG_HEADER(bag);
// get type and old size of the bag
type = header->type;
flags = header->flags;
old_size = header->size;
#ifndef DISABLE_GC
alloc_size = GC_size(header); /* An alternative implementation would be to compare * new_size <= alloc_size in the following test in order * to avoid reallocations for alternating contractions * and expansions. However, typed allocation in the Boehm * GC stores layout information in the last word of a memory * block and we may accidentally overwrite this information, * because GC_size() includes that extraneous word when * returning the size of a memory block. * * This is technically a bug in GC_size(), but until and * unless there is an upstream fix, we'll do it the safe * way.
*/ if (new_size <= old_size && sizeof(BagHeader) + new_size >= alloc_size * 3 / 4) { #else if (new_size <= old_size) { #endif// DISABLE_GC
// change the size word
header->size = new_size;
}
// if the bag is enlarged else {
alloc_size = sizeof(BagHeader) + new_size; if (new_size == 0)
alloc_size++; #ifndef DISABLE_GC
header = AllocateBagMemory(TabMarkTypeBags[type], type, alloc_size); #else
header = calloc(1, alloc_size); #endif
// copy data and update the masterpointer
src = PTR_BAG(bag);
memcpy(DATA(header), src, old_size < new_size ? old_size : new_size);
SET_PTR_BAG(bag, DATA(header));
} return 1;
}
/***************************************************************************** ** The following functions are not required respectively supported, so empty ** implementations are provided **
*/
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.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.