classpool.c
来自「kaffe Java 解释器语言,源码,Java的子集系统,开放源代码」· C语言 代码 · 共 648 行
C
648 行
/* * classPool.c * Methods dealing with the class entry pool * * Copyright (c) 1996, 1997 * Transvirtual Technologies, Inc. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file. */#include "config.h"#include "debug.h"#include "config-std.h"#include "config-mem.h"#include "errors.h"#include "itypes.h"#include "access.h"#include "file.h"#include "thread.h"#include "jthread.h"#include "classMethod.h"#include "md.h"#include "support.h"#include "stringSupport.h"#include "stats.h"#include "gc.h"#include "locks.h"#include "md.h"#define CLASSHASHSZ 256 /* Must be a power of two */static iStaticLock classHashLock;static classEntry* classEntryPool[CLASSHASHSZ];#if defined(KAFFE_STATS)statobject classStats;void statClassPool(void);#endif/* * Lookup an entry for a given (name, loader) pair. * Return null if none is found. */classEntry*lookupClassEntryInternal(Utf8Const* name, Hjava_lang_ClassLoader* loader){ classEntry* entry; entry = classEntryPool[utf8ConstHashValue(name) & (CLASSHASHSZ-1)]; for (; entry != 0; entry = entry->next) { if (utf8ConstEqual(name, entry->name) && loader == entry->loader) { return (entry); } } return (0);}/* * Lookup an entry for a given (name, loader) pair. * Create one if none is found. */classEntry*lookupClassEntry(Utf8Const* name, Hjava_lang_ClassLoader* loader, errorInfo *einfo){ classEntry* entry; classEntry** entryp; int iLockRoot; static int f = 0; if (f == 0) { f++; registerUserCounter(&classStats, "class-pool", statClassPool); } entry = lookupClassEntryInternal(name, loader); if (entry != 0) return (entry); /* Failed to find class entry - create a new one */ entry = gc_malloc(sizeof(classEntry), GC_ALLOC_CLASSPOOL); if (entry == 0) { postOutOfMemory(einfo); return (0); } entry->name = name; entry->loader = loader; entry->data.cl = 0; entry->next = 0; /* Lock the class table and insert entry into it (if not already there) */ lockStaticMutex(&classHashLock); entryp = &classEntryPool[utf8ConstHashValue(name) & (CLASSHASHSZ-1)]; for (; *entryp != 0; entryp = &(*entryp)->next) { if (utf8ConstEqual(name, (*entryp)->name) && loader == (*entryp)->loader) { /* Someone else added it - discard ours and return the new one. */ unlockStaticMutex(&classHashLock); KFREE(entry); return (*entryp); } } /* Add ours to end of hash */ *entryp = entry; addToCounter(&cpemem, "vmmem-class entry pool", 1, GCSIZEOF(entry)); /* * This reference to the utf8 name will be released if and when this * class entry is freed in destroyClassLoader. */ utf8ConstAddRef(entry->name); unlockStaticMutex(&classHashLock); return (entry);}#if 0#if defined(TRANSLATOR) && !defined(JIT3)/* * Find method containing pc. * This is the old version that linearly scans the class entry pool. * * It is only used in JIT2. JIT3 uses a faster implementation * in methodCache.c. JIT2 could use that implementation too if calls * to makeMethodActive are added. * * For now, let's leave this code here. It could be used a potential * fallback for gc systems that would not support gcGetObjectBase(). * * Note that the only reason this code is in this file is that * the classEntryPool is a private structure --- what we'd really need * here is an "map" function over the elements in the class entry pool. */Method*findMethodFromPC(uintp pc){ classEntry* entry; Method* ptr; int ipool; int imeth; for (ipool = CLASSHASHSZ; --ipool >= 0; ) { for (entry = classEntryPool[ipool]; entry != NULL; entry = entry->next) { if (entry->data.cl != 0) { imeth = CLASS_NMETHODS(entry->data.cl); ptr = CLASS_METHODS(entry->data.cl); for (; --imeth >= 0; ptr++) { uintp ncode; if (!METHOD_TRANSLATED(ptr)) { continue; } ncode = (uintp)METHOD_NATIVECODE(ptr); if (pc >= ncode && pc < (uintp)ptr->c.ncode.ncode_end) { return (ptr); } } } } } return (NULL);}#endif#endifvoidwalkClassEntries(Collector *collector, Hjava_lang_ClassLoader* loader){ classEntry* entry; int ipool; for (ipool = CLASSHASHSZ; --ipool >= 0; ) { for (entry = classEntryPool[ipool]; entry != NULL; entry = entry->next) { if (entry->loader == loader && entry->state >= NMS_LOADING) { GC_markObject(collector, entry->data.cl); } } }}/* * Remove all entries from the class entry pool that belong to a given * class. Return the number of entries removed. */intremoveClassEntries(Hjava_lang_ClassLoader* loader){ classEntry** entryp; classEntry* entry; int ipool; int totalent = 0; int iLockRoot; lockStaticMutex(&classHashLock); for (ipool = CLASSHASHSZ; --ipool >= 0; ) { entryp = &classEntryPool[ipool]; while (*entryp != NULL) { /* loop invariant: entryp points at the next non-null * entry that must be examined. */ entry = *entryp; if (entry->loader == loader) { /* * If class gc is turned off, no classloader * should ever be finalized because they're all * kept alive by their respective classes. */ assert(entry->data.cl == 0 || Kaffe_JavaVMArgs[0].enableClassGC != 0);DBG(CLASSGC, dprintf("removing %s l=%p/c=%p\n", entry->name->data, loader, entry->data.cl); ) /* release reference to name */ utf8ConstRelease(entry->name); (*entryp) = entry->next; addToCounter(&cpemem, "vmmem-class entry pool", 1, -(jlong)GCSIZEOF(entry)); gc_free(entry); totalent++; } else { entryp = &(*entryp)->next; } } } unlockStaticMutex(&classHashLock); return (totalent);}/* * Finalize a classloader and remove its entries in the class entry pool. */void/* ARGSUSED */destroyClassLoader(Collector *c, void* _loader){ Hjava_lang_ClassLoader* loader = _loader; int rmoved; rmoved = removeClassEntries(loader); if (Kaffe_JavaVMArgs[0].enableVerboseGC > 0) { dprintf("<GC: destroying classloader " "@%p (%d entries removed)>\n", loader, rmoved); }}static nameDependency *dependencies;static iStaticLock mappingLock;staticnameDependency *findNameDependency(jthread_t jt){ nameDependency *curr, *retval = 0; for( curr = dependencies; curr && !retval; curr = curr->next ) { if( curr->thread == jt ) { retval = curr; } } return( retval );}staticint addNameDependency(nameDependency *nd){ int retval = 1; int iLockRoot; assert(nd != 0); lockStaticMutex(&mappingLock); { nameDependency *curr; nd->next = dependencies; dependencies = nd; for( curr = findNameDependency(nd->mapping->data.thread); curr && retval; curr = findNameDependency(curr->mapping->data.thread) ) { if( curr->mapping->data.thread == nd->thread ) { retval = 0; } } } unlockStaticMutex(&mappingLock); return( retval );}staticvoid remNameDependency(classEntry *ce){ int iLockRoot; assert(ce != 0); lockStaticMutex(&mappingLock); { nameDependency **last, *curr; last = &dependencies; curr = dependencies; while( curr && (curr->mapping != ce) ) { last = &curr->next; curr = curr->next; } if( curr ) { *last = curr->next; } } unlockStaticMutex(&mappingLock);}int classMappingSearch(classEntry *ce, Hjava_lang_Class **out_cl, errorInfo *einfo){ int done = 0, retval = 1; nameDependency nd; jthread_t jt; int iLockRoot; jt = jthread_current(); while( !done ) { lockMutex(ce); switch( ce->state ) { case NMS_EMPTY: /* This thread's responsibility. */ ce->state = NMS_SEARCHING; ce->data.thread = jt; done = 1; break; case NMS_SEARCHING: if( ce->data.thread == jt ) { done = 1; break; } waitCond(ce, 0); break; case NMS_LOADING: /* * Another thread is loading it, make sure there is not * a cycle. */ nd.thread = jt; nd.mapping = ce; if( (ce->data.thread == jt) || !addNameDependency(&nd) ) { /* Circularity. */ done = 1; retval = 0; postExceptionMessage( einfo, JAVA_LANG(ClassCircularityError), "%s", ce->name->data); } else { waitCond(ce, 0); } remNameDependency(ce); break; case NMS_LOADED: /* * Another thread loaded it, however, its not finished * linking yet. */ waitCond(ce, 0); break; case NMS_DONE: /* Its already been loaded and linked. */ *out_cl = ce->data.cl; done = 1; break; } unlockMutex(ce); } return( retval );}int classMappingLoad(classEntry *ce, Hjava_lang_Class **out_cl, errorInfo *einfo){ int done = 0, retval = 1; nameDependency nd; jthread_t jt; int iLockRoot; *out_cl = 0; jt = jthread_current(); while( !done ) { lockMutex(ce); switch( ce->state ) { case NMS_EMPTY: case NMS_SEARCHING: /* This thread's responsibility. */ ce->state = NMS_LOADING; ce->data.thread = jt; done = 1; break; case NMS_LOADING: /* * Another thread is loading it, make sure there is not * a cycle. */ nd.thread = jt; nd.mapping = ce; if( (ce->data.thread == jt) || !addNameDependency(&nd) ) { /* Circularity. */ done = 1; retval = 0; postExceptionMessage( einfo, JAVA_LANG(ClassCircularityError), "%s", ce->name->data); } else { waitCond(ce, 0); } remNameDependency(ce); break; case NMS_LOADED: /* * Another thread loaded it, however, its not finished * linking yet. */ waitCond(ce, 0); break; case NMS_DONE: /* Its already been loaded and linked. */ *out_cl = ce->data.cl; done = 1; break; } unlockMutex(ce); } return( retval );}Hjava_lang_Class *classMappingLoaded(classEntry *ce, Hjava_lang_Class *cl){ Hjava_lang_Class *retval = 0; int iLockRoot; assert(ce != 0); assert(cl != 0); lockMutex(ce); { switch( ce->state ) { case NMS_LOADING: /* FALLTHROUGH */ case NMS_SEARCHING: if( cl->state < CSTATE_PREPARED ) { ce->state = NMS_LOADED; } else { ce->state = NMS_DONE; } ce->data.cl = cl; retval = cl; break; default: /* Ignore. */ retval = ce->data.cl; break; } broadcastCond(ce); } unlockMutex(ce); return( retval );}void setClassMappingState(classEntry *ce, name_mapping_state_t nms){ int iLockRoot; assert(ce != 0); lockMutex(ce); { switch( ce->state ) { case NMS_SEARCHING: ce->state = nms; break; case NMS_LOADING: /* FALLTHROUGH */ case NMS_LOADED: ce->state = nms; break; case NMS_DONE: break; case NMS_EMPTY: break; default: assert(0); break; } broadcastCond(ce); } unlockMutex(ce);}#if defined(KAFFE_STATS) || defined(KAFFE_PROFILER) || defined(KAFFE_VMDEBUG)/** * Walk the class pool and invoke walker() for each classes */voidwalkClassPool(int (*walker)(Hjava_lang_Class *clazz, void *), void *param){ int ipool; classEntry* entry; assert(walker != NULL); for (ipool = CLASSHASHSZ; --ipool >= 0; ) { entry = classEntryPool[ipool]; for (; entry != NULL; entry = entry->next) { if (entry->data.cl && entry->loader == entry->data.cl->loader) { walker(entry->data.cl, param); } } }}#endif#if defined(KAFFE_STATS)static voidstatClass(Hjava_lang_Class *clazz, int *total){ Collector *c = main_collector; int misc = 0; int miscfixed = 0; int bytecodemem = 0, jitmem = 0;#define SIZE_IFNONZERO(x) ((x) ? GC_getObjectSize(c, (x)) : 0) /* compute sizes of miscellaneous data */ /* we tally up the memory for KMALLOC'ed objects (they'll appear * under "other-fixed".) and the memory for other misc objects */ misc += SIZE_IFNONZERO(clazz); /* myself */ if (!CLASS_IS_PRIMITIVE(clazz)) { /* For primitives, dtable is -1 and methods is the * class of the corresponding array */ misc += SIZE_IFNONZERO(clazz->dtable); misc += SIZE_IFNONZERO(CLASS_CONSTANTS(clazz)->data); misc += SIZE_IFNONZERO(CLASS_FIELDS(clazz)); misc += SIZE_IFNONZERO(CLASS_STATICDATA(clazz)); miscfixed += SIZE_IFNONZERO(clazz->if2itable); miscfixed += SIZE_IFNONZERO(clazz->itable2dtable); miscfixed += SIZE_IFNONZERO(clazz->gc_layout); miscfixed += SIZE_IFNONZERO(clazz->sourcefile); miscfixed += SIZE_IFNONZERO(clazz->implementors); miscfixed += SIZE_IFNONZERO(clazz->inner_classes); } if (!CLASS_IS_ARRAY(clazz) && !CLASS_IS_PRIMITIVE(clazz)) { misc += SIZE_IFNONZERO(clazz->interfaces); } /* methods only if we have some */ if (!CLASS_IS_PRIMITIVE(clazz) && !CLASS_IS_ARRAY(clazz) && CLASS_METHODS(clazz) != 0) { Method *m = CLASS_METHODS(clazz); int i, n = CLASS_NMETHODS(clazz); misc += SIZE_IFNONZERO(CLASS_METHODS(clazz)); for (i = 0; i < n; m++, i++) { miscfixed += SIZE_IFNONZERO(m->parsed_sig); miscfixed += SIZE_IFNONZERO(m->lines); miscfixed += SIZE_IFNONZERO(m->declared_exceptions); misc += SIZE_IFNONZERO(m->exception_table); /* bytecode or jitted code */ if ((m->accflags & ACC_NATIVE) == 0) { if (METHOD_TRANSLATED(m)) { jitmem += SIZE_IFNONZERO(m->c.ncode.ncode_start); } else { bytecodemem += SIZE_IFNONZERO(m->c.bcode.code); } } } } dprintf("%7d %7d %7d %7d %s\n", misc, miscfixed, jitmem, bytecodemem, CLASS_CNAME(clazz)); total[0] += misc; total[1] += miscfixed; total[2] += jitmem; total[3] += bytecodemem;}voidstatClassPool(void){ int total[20]; memset(total, 0, sizeof total); dprintf("#DUMPING CLASSPOOL MEMORY\n"); dprintf("%-7s %-7s %-7s %-7s %-7s\n", "#MISC", "MISCFIX", "JCODE", "BCODE", "CLASS"); dprintf("%-7s %-7s %-7s %-7s %-7s\n", "#------", "-------", "-------", "-------", "--------------\n"); walkClassPool(statClass, total); dprintf("%7.2f %7.2f %7.2f %7.2f KBytes\n", total[0]/1024.0, total[1]/1024.0, total[2]/1024.0, total[3]/1024.0); fflush(stderr);}#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?