📄 gc-incremental.c
字号:
/* gc-incremental.c * The garbage collector. * The name is misleading. GC is non-incremental at this point. * * Copyright (c) 1996, 1997 * Transvirtual Technologies, Inc. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file. *//* XXX this should be controllable, somehow. */#define SUPPORT_VERBOSEMEM#include "config.h"#include "debug.h"#include "config-std.h"#include "config-mem.h"#include "gtypes.h"#include "gc.h"#include "gc-mem.h"#include "locks.h"#include "thread.h"#include "jthread.h"#include "errors.h"#include "md.h"#include "stats.h"#include "classMethod.h"#include "jvmpi_kaffe.h"/* Avoid recursively allocating OutOfMemoryError */#define OOM_ALLOCATING ((void *) -1)#define GCSTACKSIZE 16384#define FINALIZERSTACKSIZE THREADSTACKSIZE/* * Object implementing the collector interface. */static struct CollectorImpl { Collector collector; /* XXX include static below here for encapsulation */} gc_obj;/* XXX don't use these types ! */Hjava_lang_Thread* garbageman;static Hjava_lang_Thread* finalman;static gcList gclists[6];static const int nofin_white = 5;static const int fin_white = 4;static const int grey = 3;static const int nofin_black = 2;static const int fin_black = 1;static const int finalise = 0;static int gc_init = 0;static volatile int gcDisabled = 0;static volatile int gcRunning = 0;static volatile bool finalRunning = false;static void (*walkRootSet)(Collector*);#if defined(KAFFE_STATS)static timespent gc_time;static timespent sweep_time;static counter gcgcablemem;static counter gcfixedmem;#endif /* KAFFE_STATS *//* Is this pointer within our managed heap? */#define IS_A_HEAP_POINTER(from) \ ((uintp) (from) >= gc_heap_base && \ (uintp) (from) < gc_heap_base + gc_heap_range)static void *reserve;static void *outOfMem;static void *outOfMem_allocator;#if defined(SUPPORT_VERBOSEMEM)static struct { int size; int count; uint64 total;} objectSizes[] = {#define OBJECTSIZE(SZ) { SZ, 0, 0 }, /* The smaller sizes should match what's in the freelist[] array defined in gc-mem.c */ OBJECTSIZE(16) OBJECTSIZE(24) OBJECTSIZE(32) OBJECTSIZE(40) OBJECTSIZE(48) OBJECTSIZE(56) OBJECTSIZE(64) OBJECTSIZE(80) OBJECTSIZE(96) OBJECTSIZE(112) OBJECTSIZE(128) OBJECTSIZE(160) OBJECTSIZE(192) OBJECTSIZE(224) OBJECTSIZE(240) OBJECTSIZE(496) OBJECTSIZE(1000) OBJECTSIZE(2016) OBJECTSIZE(4040) OBJECTSIZE(8192) OBJECTSIZE(12288) OBJECTSIZE(16483) OBJECTSIZE(32768) OBJECTSIZE(65536) OBJECTSIZE(131072) OBJECTSIZE(262144) OBJECTSIZE(524288) OBJECTSIZE(1048576) OBJECTSIZE(0x7FFFFFFF)#undef OBJECTSIZE { -1, -1, -1 }};static void objectStatsChange(gc_unit*, int);static void objectStatsPrint(void);static void objectSizesAdd(size_t);static void objectSizesPrint(void);#define OBJECTSTATSADD(M) objectStatsChange(M, 1)#define OBJECTSTATSREMOVE(M) objectStatsChange(M, -1)#define OBJECTSTATSPRINT() objectStatsPrint()#define OBJECTSIZESADD(S) objectSizesAdd(S)#else#define OBJECTSTATSADD(M)#define OBJECTSTATSREMOVE(M)#define OBJECTSTATSPRINT()#define OBJECTSIZESADD(S)#endif/* For statistics gathering, record how many objects and how * much memory was marked. */static inlinevoid record_marked(int nr_of_objects, uint32 size){ gcStats.markedobj += nr_of_objects; gcStats.markedmem += size;} static iStaticLock gcman;static iStaticLock finman;static iStaticLock gc_lock; /* allocator mutex */static void gcFree(Collector* gcif, void* mem);/* Standard GC function sets. We call them "allocation types" now */static gcFuncs gcFunctions[GC_ALLOC_MAX_INDEX];/* Number of registered allocation types */static int nrTypes;/* * register an allocation type under a certain index * NB: we could instead return a pointer to the record describing the * allocation type. This would give us more flexibility, but it wouldn't * allow us to use compile-time constants. */static voidregisterTypeByIndex(int index, walk_func_t walk, final_func_t final, destroy_func_t destroy, const char *description){ /* once only, please */ assert (gcFunctions[index].description == 0); /* don't exceed bounds */ assert (index >= 0 && index < sizeof(gcFunctions)/sizeof(gcFunctions[0])); gcFunctions[index].walk = walk; gcFunctions[index].final = final; gcFunctions[index].destroy = destroy; gcFunctions[index].description = description; if (index >= nrTypes) { nrTypes = index + 1; }}/* * Register a fixed allocation type. The only reason we tell them apart * is for statistical purposes. */static voidgcRegisterFixedTypeByIndex(Collector* gcif, int index, const char *description){ registerTypeByIndex(index, 0, GC_OBJECT_FIXED, 0, description);}/* * Register a allocation type that is subject to gc. */static voidgcRegisterGcTypeByIndex(Collector* gcif, int index, walk_func_t walk, final_func_t final, destroy_func_t destroy, const char *description){ registerTypeByIndex(index, walk, final, destroy, description);}struct _gcStats gcStats;static void startGC(Collector *gcif);static void finishGC(Collector *gcif);static void startFinalizer(void);static void markObjectDontCheck(gc_unit *unit, gc_block *info, int idx);/* Return true if gc_unit is pointer to an allocated object */static inline intgc_heap_isobject(gc_block *info, gc_unit *unit){ uintp p = (uintp) UTOMEM(unit) - gc_heap_base; int idx; if (!(p & (MEMALIGN - 1)) && p < gc_heap_range && GCBLOCKINUSE(info)) { /* Make sure 'unit' refers to the beginning of an * object. We do this by making sure it is correctly * aligned within the block. */ idx = GCMEM2IDX(info, unit); if (idx < info->nr && GCBLOCK2MEM(info, idx) == unit && (GC_GET_COLOUR(info, idx) & GC_COLOUR_INUSE) == GC_COLOUR_INUSE) { return 1; } } return 0;}static inline voidmarkObjectDontCheck(gc_unit *unit, gc_block *info, int idx){ /* If the object has been traced before, don't do it again. */ if (GC_GET_COLOUR(info, idx) != GC_COLOUR_WHITE) { return; }DBG(GCWALK, dprintf(" marking @%p: %s\n", UTOMEM(unit), describeObject(UTOMEM(unit))); ) DBG(GCSTAT, switch (GC_GET_FUNCS(info, idx)) { case GC_ALLOC_NORMALOBJECT: case GC_ALLOC_FINALIZEOBJECT: case GC_ALLOC_PRIMARRAY: case GC_ALLOC_REFARRAY: { Hjava_lang_Object *obj; obj = (Hjava_lang_Object *)(unit+1); if (obj->dtable != NULL) { Hjava_lang_Class *c; c = OBJECT_CLASS(obj); if (c) c->live_count++; } }}); /* If we found a new white object, mark it as grey and * move it into the grey list. */ GC_SET_COLOUR(info, idx, GC_COLOUR_GREY); UREMOVELIST(unit); UAPPENDLIST(gclists[grey], unit);}/* * Mark the memory given by an address if it really is an object. */static voidgcMarkAddress(Collector* gcif, const void* mem){ gc_block* info; gc_unit* unit; /* * First we check to see if the memory 'mem' is in fact the * beginning of an object. If not we just return. */ /* Get block info for this memory - if it exists */ info = GCMEM2BLOCK(mem); unit = UTOUNIT(mem); if (gc_heap_isobject(info, unit)) { markObjectDontCheck(unit, info, GCMEM2IDX(info, unit)); }}/* * Mark an object. Argument is assumed to point to a valid object, * and never, ever, be null. */static voidgcMarkObject(Collector* gcif, const void* objp){ gc_unit *unit = UTOUNIT(objp); gc_block *info = GCMEM2BLOCK(unit); DBG(GCDIAG, assert(gc_heap_isobject(info, unit))); markObjectDontCheck(unit, info, GCMEM2IDX(info, unit));}static voidgcWalkConservative(Collector* gcif, const void* base, uint32 size){ int8* mem;DBG(GCWALK, dprintf("scanning %d bytes conservatively from %p-%p\n", size, base, base+size); ) record_marked(1, size); if (size > 0) { for (mem = ((int8*)base) + (size & -ALIGNMENTOF_VOIDP) - sizeof(void*); (void*)mem >= base; mem -= ALIGNMENTOF_VOIDP) { void *p = *(void **)mem; if (p) { gcMarkAddress(gcif, p); } } }}/* * Like walkConservative, except that length is computed from the block size * of the object. Must be called with pointer to object allocated by gc. */staticuint32gcGetObjectSize(Collector* gcif, const void* mem){ return (GCBLOCKSIZE(GCMEM2BLOCK(UTOUNIT(mem))));}staticintgcGetObjectIndex(Collector* gcif, const void* mem){ gc_unit* unit = UTOUNIT(mem); gc_block* info = GCMEM2BLOCK(unit); if (!gc_heap_isobject(info, unit)) { return (-1); } else { return (GC_GET_FUNCS(info, GCMEM2IDX(info, unit))); }}/* * Given a pointer within an object, find the base of the object. * This works for both gcable and fixed object types. * * This method uses many details of the allocator implementation. * Specifically, it relies on the contiguous layout of block infos * and the way GCMEM2BLOCK and GCMEM2IDX are implemented. */staticvoid*gcGetObjectBase(Collector *gcif, const void* mem){ int idx; gc_block* info; /* quickly reject pointers that are not part of this heap */ if (!IS_A_HEAP_POINTER(mem)) { return (0); } info = GCMEM2BLOCK(mem); if (!GCBLOCKINUSE(info)) { /* go down block list to find out whether we were hitting * in a large object */ while (!GCBLOCKINUSE(info) && (uintp)info > (uintp)gc_block_base) { info--; } /* must be a large block, hence nr must be 1 */ if (!GCBLOCKINUSE(info) || info->nr != 1) { return (0); } } idx = GCMEM2IDX(info, mem); /* report fixed objects as well */ if (idx < info->nr && ((GC_GET_COLOUR(info, idx) & GC_COLOUR_INUSE) || (GC_GET_COLOUR(info, idx) & GC_COLOUR_FIXED))) { return (UTOMEM(GCBLOCK2MEM(info, idx))); } return (0);}staticconst char*gcGetObjectDescription(Collector* gcif, const void* mem){ return (gcFunctions[gcGetObjectIndex(gcif, mem)].description);}/* * Walk a bit of memory. */staticvoidgcWalkMemory(Collector* gcif, void* mem){ gc_block* info; int idx; gc_unit* unit; uint32 size; walk_func_t walkf; unit = UTOUNIT(mem); info = GCMEM2BLOCK(unit); idx = GCMEM2IDX(info, unit); if (GC_GET_COLOUR(info, idx) == GC_COLOUR_BLACK) { return; } UREMOVELIST(unit); /* if the object is about to be finalized, put it directly * into the finalise list, otherwise put it into the black * list. */ if (GC_GET_STATE(info, idx) == GC_STATE_INFINALIZE) { gcStats.finalobj += 1; gcStats.finalmem += GCBLOCKSIZE(info); UAPPENDLIST(gclists[finalise], unit); } else if (GC_GET_STATE(info, idx) == GC_STATE_NEEDFINALIZE) { UAPPENDLIST(gclists[fin_black], unit); } else { UAPPENDLIST(gclists[nofin_black], unit); } GC_SET_COLOUR(info, idx, GC_COLOUR_BLACK); assert(GC_GET_FUNCS(info, idx) < sizeof(gcFunctions)/sizeof(gcFunctions[0])); size = GCBLOCKSIZE(info); record_marked(1, size); walkf = gcFunctions[GC_GET_FUNCS(info, idx)].walk; if (walkf != 0) {DBG(GCWALK, dprintf("walking %d bytes @%p: %s\n", size, mem, describeObject(mem)); ) walkf(gcif, mem, size); }}#if !(defined(NDEBUG) || !defined(KAFFE_VMDEBUG))static intgcClearCounts(Hjava_lang_Class *c, void *_){ c->live_count = 0; return 0;}static intgcDumpCounts(Hjava_lang_Class *c, void *_){ if (c->live_count) dprintf("%7d %s\n", c->live_count, c->name->data); return 0;}#endif /* !(defined(NDEBUG) || !defined(KAFFE_VMDEBUG)) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -