From: Godmar Back (gback@marker.cs.utah.edu)
Date: Sun Jan 17 1999 - 19:25:43 EST
I'm almost done with it (if I could only compile and run kaffe!)
Basically, the gc subsystem does not have any clue about how to walk things.
Instead, a new file gcFuncs.c, which contains all the walk functions,
registers "allocation types" as follows:
void
initGCFuncs(void)
{
registerGcAllocTypeByIndex(GC_ALLOC_JAVASTRING,
stringWalk, GC_OBJECT_NORMAL, stringDestroy, "java.lang.String");
registerGcAllocTypeByIndex(GC_ALLOC_NOWALK,
walkNull, GC_OBJECT_NORMAL, 0, "other-nowalk");
registerGcAllocTypeByIndex(GC_ALLOC_NORMALOBJECT,
walkObject, GC_OBJECT_NORMAL, 0, "object-w/o-finalizer");
registerGcAllocTypeByIndex(GC_ALLOC_PRIMARRAY,
walkNull, GC_OBJECT_NORMAL, 0, "arrays-primitive");
registerGcAllocTypeByIndex(GC_ALLOC_REFARRAY,
walkRefArray, GC_OBJECT_NORMAL, 0, "arrays-ref");
registerGcAllocTypeByIndex(GC_ALLOC_CLASSOBJECT,
walkClass, GC_OBJECT_NORMAL, destroyClass, "java.lang.Class");
registerGcAllocTypeByIndex(GC_ALLOC_FINALIZEOBJECT,
walkObject, finalizeObject, 0, "objects-w-finalizer");
registerFixedAllocTypeByIndex(GC_ALLOC_BYTECODE, "java-bytecode");
registerFixedAllocTypeByIndex(GC_ALLOC_EXCEPTIONTABLE, "etable");
registerFixedAllocTypeByIndex(GC_ALLOC_JITCODE, "jitcode");
registerFixedAllocTypeByIndex(GC_ALLOC_STATICDATA, "static-data");
registerFixedAllocTypeByIndex(GC_ALLOC_CONSTANT, "constants");
registerFixedAllocTypeByIndex(GC_ALLOC_FIXED, "other-fixed");
registerFixedAllocTypeByIndex(GC_ALLOC_DISPATCHTABLE, "dtable");
registerFixedAllocTypeByIndex(GC_ALLOC_METHOD, "methods");
registerFixedAllocTypeByIndex(GC_ALLOC_FIELD, "fields");
registerFixedAllocTypeByIndex(GC_ALLOC_UTF8CONST, "utf8consts");
registerFixedAllocTypeByIndex(GC_ALLOC_INTERFACE, "interfaces");
registerFixedAllocTypeByIndex(GC_ALLOC_LOCK, "locks");
registerFixedAllocTypeByIndex(GC_ALLOC_THREADCTX, "thread-ctxts");
registerFixedAllocTypeByIndex(GC_ALLOC_REF, "gc-refs");
}
Note there's fixed and non-fixed types, as you would expect.
In order to implement walking, the gc exports these functions:
extern void markObject(const void* obj); /* prev. MARK_PRECISE_OBJECT */
extern void markAddress(const void* addr); /* prev. markObject */
extern void walkMemory(void* mem);
extern void walkNull(void*, uint32);
extern void walkConservative(void* base, uint32 size); /* for convenience */
(Note the change in meaning for markObject!)
The walk functions are only exported for convenience reasons.
[ Once everything runs, I am considering making these functions part of the
gc interface, although I still strongly oppose using run-time interfaces
for subsystems that are static singletons at run-time. Where, in other words,
you pay a significant performance penalty for no gain in robustness or
flexibility. ]
If somebody now wanted to implement a new non-incremental
collector for kaffe, all that would be required from him would be an
implementation of the malloc/free/realloc/invokegc/addref/rmref functions
plus:
registerGcAllocTypeByIndex
registerFixedAllocTypeByIndex
markObject
markAddress
walkMemory
walkNull
walkConservative.
Two more comments:
The register* functions are similar in spirit to the GC_make_descriptor
functions. Unlike them, however, they require the caller to specify the
index under which the allocation type should be registered. This is
a bug and a feature: it's a bug cause it requires the caller to sort
out its types, plus the number of types is currently statically limited.
It's a feature since it does not require the caller to store and pass around
pointers to descriptors, so it saves memory accesses.
One remaining dependence is that the gc still walks all threads.
I'm not sure if that's really necessary. An alternative solution
would register a thread as a root when its created und unregister it when
it exits. We've had nasty race conditions with walking threads before,
so I don't know whether my thinking here is correct.
However, getting this to work would be nice because it would mean that
we didn't have to fundamentally rely on the threading system's ability to
enumerate all threads. On the other hand, this is also necessary to realize
when you need to exit etc.
- Godmar
This archive was generated by hypermail 2b29 : Sat Sep 23 2000 - 19:57:44 EDT