| //===------ VirtualTables.cpp - Virtual methods for J3 objects ------------===// |
| // |
| // The VMKit project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file contains GC specific tracing functions. |
| // |
| // The file is divided into four parts: |
| // (1) Declaration of internal GC classes. |
| // (2) Tracing Java objects: regular object, native array, object array. |
| // (3) Tracing a class loader, which involves tracing the Java objects |
| // referenced by classes. |
| // (4) Tracing the roots of a program: the JVM and the threads. |
| // |
| // Additionnaly, all write of GC objets in J3 data structures must go through |
| // a write barrier. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "ClasspathReflect.h" |
| #include "JavaArray.h" |
| #include "JavaClass.h" |
| #include "JavaObject.h" |
| #include "JavaString.h" |
| #include "JavaThread.h" |
| #include "JavaUpcalls.h" |
| #include "Jnjvm.h" |
| #include "JnjvmClassLoader.h" |
| #include "LockedMap.h" |
| #include "JavaReferenceQueue.h" |
| #include "VMStaticInstance.h" |
| #include "Zip.h" |
| |
| using namespace j3; |
| |
| //===----------------------------------------------------------------------===// |
| // List of classes that will be GC-allocated. One should try to keep this |
| // list as minimal as possible, and a GC class must be defined only if |
| // absolutely necessary. If there is an easy way to avoid it, do it! Only |
| // Java classes should be GC classes. |
| // Having many GC classes gives more work to the GC for the scanning phase |
| // and for the relocation phase (for copying collectors). |
| // |
| // In J3, there is only one primary internal gc object, the class loader. |
| // We decided that this was the best solution because |
| // otherwise it would involve hacks on the java.lang.Classloader class. |
| // Therefore, we create a new GC class with a finalize method that will |
| // delete the internal class loader when the Java object class loader is |
| // not reachable anymore. This also relies on the java.lang.Classloader class |
| // referencing an object of type VMClassLoader (this is the case in GNU |
| // Classpath with the vmdata field). |
| // In addition, to handle support for sun.misc.Unsafe, we have a similar |
| // second clsas VMStaticInstance that wraps static instances for use |
| // in staticFieldBase and traces the owning ClassLoader to make sure |
| // the underlying instance and class don't get GC'd improperly. |
| //===----------------------------------------------------------------------===// |
| |
| VirtualTable VMClassLoader::VT((word_t)VMClassLoader::staticDestructor, |
| (word_t)VMClassLoader::staticDestructor, |
| (word_t)VMClassLoader::staticTracer); |
| |
| VirtualTable VMStaticInstance::VT((word_t)VMStaticInstance::staticDestructor, |
| (word_t)VMStaticInstance::staticDestructor, |
| (word_t)VMStaticInstance::staticTracer); |
| |
| //===----------------------------------------------------------------------===// |
| // Trace methods for Java objects. There are four types of objects: |
| // (1) java.lang.Object and primitive arrays: no need to trace anything. |
| // (2) Object whose class is not an array: needs to trace the classloader, and |
| // all the virtual fields. |
| // (3) Object whose class is an array of objects: needs to trace the class |
| // loader and all elements in the array. |
| // (4) Objects that extend java.lang.ref.Reference: must trace the class loader |
| // and all the fields except the referent. |
| //===----------------------------------------------------------------------===// |
| |
| /// Scanning java.lang.Object and primitive arrays. |
| extern "C" void JavaObjectTracer(JavaObject* obj, word_t closure) { |
| llvm_gcroot(obj, 0); |
| } |
| |
| /// Method for scanning regular objects. |
| extern "C" void RegularObjectTracer(JavaObject* obj, word_t closure) { |
| llvm_gcroot(obj, 0); |
| Class* cl = JavaObject::getClass(obj)->asClass(); |
| assert(cl && "Not a class in regular tracer"); |
| vmkit::Collector::markAndTraceRoot(obj, |
| cl->classLoader->getJavaClassLoaderPtr(), closure); |
| |
| while (cl->super != 0) { |
| for (uint32 i = 0; i < cl->nbVirtualFields; ++i) { |
| JavaField& field = cl->virtualFields[i]; |
| if (field.isReference()) { |
| JavaObject** ptr = field.getInstanceObjectFieldPtr(obj); |
| vmkit::Collector::markAndTrace(obj, ptr, closure); |
| } |
| } |
| cl = cl->super; |
| } |
| } |
| |
| /// Method for scanning an array whose elements are JavaObjects. This method is |
| /// called for all non-native Java arrays. |
| extern "C" void ArrayObjectTracer(ArrayObject* obj, word_t closure) { |
| JavaObject* elt = 0; |
| llvm_gcroot(elt, 0); |
| llvm_gcroot(obj, 0); |
| CommonClass* cl = JavaObject::getClass(obj); |
| assert(cl && "No class"); |
| vmkit::Collector::markAndTraceRoot(obj, |
| cl->classLoader->getJavaClassLoaderPtr(), closure); |
| |
| |
| for (sint32 i = 0; i < ArrayObject::getSize(obj); i++) { |
| elt = ArrayObject::getElement(obj, i); |
| if (elt != NULL) { |
| vmkit::Collector::markAndTrace( |
| obj, ArrayObject::getElements(obj) + i, closure); |
| } |
| } |
| } |
| |
| /// Method for scanning Java java.lang.ref.Reference objects. |
| extern "C" void ReferenceObjectTracer( |
| JavaObjectReference* obj, word_t closure) { |
| llvm_gcroot(obj, 0); |
| Class* cl = JavaObject::getClass(obj)->asClass(); |
| assert(cl && "Not a class in reference tracer"); |
| vmkit::Collector::markAndTraceRoot(obj, |
| cl->classLoader->getJavaClassLoaderPtr(), closure); |
| |
| bool found = false; |
| while (cl->super != 0) { |
| for (uint32 i = 0; i < cl->nbVirtualFields; ++i) { |
| JavaField& field = cl->virtualFields[i]; |
| if (field.isReference()) { |
| JavaObject** ptr = field.getInstanceObjectFieldPtr(obj); |
| if (ptr != JavaObjectReference::getReferentPtr(obj)) { |
| vmkit::Collector::markAndTrace(obj, ptr, closure); |
| } else { |
| found = true; |
| } |
| } |
| } |
| cl = cl->super; |
| } |
| assert(found && "No referent in a reference"); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Support for scanning Java objects referenced by classes. All classes must |
| // trace: |
| // (1) The classloader of the parents (super and interfaces) as well as its |
| // own class loader. |
| // (2) The delegatee object (java.lang.Class) if it exists. |
| // |
| // Additionaly, non-primitive and non-array classes must trace: |
| // (3) The static instance. |
| //===----------------------------------------------------------------------===// |
| |
| void CommonClass::tracer(word_t closure) { |
| |
| if (super != NULL && super->classLoader != NULL) { |
| JavaObject** Obj = super->classLoader->getJavaClassLoaderPtr(); |
| if (*Obj != NULL) vmkit::Collector::markAndTraceRoot(getDelegatee(), Obj, closure); |
| |
| for (uint32 i = 0; i < nbInterfaces; ++i) { |
| if (interfaces[i]->classLoader) { |
| JavaObject** Obj = interfaces[i]->classLoader->getJavaClassLoaderPtr(); |
| if (*Obj != NULL) vmkit::Collector::markAndTraceRoot(getDelegatee(), Obj, closure); |
| } |
| } |
| } |
| |
| if (classLoader != NULL) { |
| vmkit::Collector::markAndTraceRoot(getDelegatee(), |
| classLoader->getJavaClassLoaderPtr(), closure); |
| } |
| |
| for (uint32 i = 0; i < NR_ISOLATES; ++i) { |
| if (delegatee[i] != NULL) { |
| vmkit::Collector::markAndTraceRoot(NULL, delegatee + i, closure); |
| } |
| } |
| } |
| |
| void Class::tracer(word_t closure) { |
| CommonClass::tracer(closure); |
| |
| for (uint32 i = 0; i < NR_ISOLATES; ++i) { |
| TaskClassMirror &M = IsolateInfo[i]; |
| if (M.staticInstance != NULL) { |
| for (uint32 j = 0; j < nbStaticFields; ++j) { |
| JavaField& field = staticFields[j]; |
| if (field.isReference()) { |
| JavaObject** ptr = field.getStaticObjectFieldPtr(); |
| vmkit::Collector::markAndTraceRoot(delegatee[i], ptr, closure); |
| } |
| } |
| } |
| } |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Support for scanning a classloader. A classloader must trace: |
| // (1) All the classes it has loaded (located in the classmap). |
| // (2) All the class it has initiated loading and therefore references (located |
| // in the classmap). |
| // (3) All the strings referenced in class files. |
| // |
| // The class loader does not need to trace its java.lang.Classloader Java object |
| // because if we end up here, this means that the Java object is already being |
| // scanned. Only the Java object traces the class loader. |
| // |
| // Additionaly, the bootstrap loader must trace: |
| // (4) The delegatees of native array classes. Since these classes are not in |
| // the class map and they are not GC-allocated, we must trace the objects |
| // referenced by the delegatees. |
| //===----------------------------------------------------------------------===// |
| |
| void JnjvmClassLoader::tracer(word_t closure) { |
| |
| for (ClassMap::iterator i = classes->map.begin(), e = classes->map.end(); |
| i!= e; ++i) { |
| CommonClass* cl = i->second; |
| if (cl->isClass()) cl->asClass()->tracer(closure); |
| else cl->tracer(closure); |
| } |
| |
| StringList* end = strings; |
| while (end != NULL) { |
| for (uint32 i = 0; i < end->length; ++i) { |
| JavaString** obj = end->strings + i; |
| vmkit::Collector::markAndTraceRoot(getJavaClassLoader(), obj, closure); |
| } |
| end = end->prev; |
| } |
| |
| vmkit::Collector::markAndTraceRoot(NULL, &javaLoader, closure); |
| } |
| |
| void JnjvmBootstrapLoader::tracer(word_t closure) { |
| |
| JnjvmClassLoader::tracer(closure); |
| upcalls->OfVoid->tracer(closure); |
| upcalls->OfBool->tracer(closure); |
| upcalls->OfByte->tracer(closure); |
| upcalls->OfChar->tracer(closure); |
| upcalls->OfShort->tracer(closure); |
| upcalls->OfInt->tracer(closure); |
| upcalls->OfFloat->tracer(closure); |
| upcalls->OfLong->tracer(closure); |
| upcalls->OfDouble->tracer(closure); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Support for scanning the roots of a program: JVM and threads. The JVM |
| // must trace: |
| // (1) The bootstrap class loader: where core classes live. |
| // (2) The applicative class loader: the JVM may be the only one referencing it. |
| // (3) Global references from JNI. |
| // |
| // The threads must trace: |
| // (1) Their stack (already done by the GC in the case of GCMmap2 or Boehm) |
| // (2) Their pending exception if there is one. |
| // (3) The java.lang.Thread delegate. |
| //===----------------------------------------------------------------------===// |
| |
| |
| void Jnjvm::tracer(word_t closure) { |
| JavaObject* jThread = NULL; |
| llvm_gcroot(jThread, 0); |
| |
| // (1) Trace the bootstrap loader. |
| bootstrapLoader->tracer(closure); |
| |
| // (2) Trace the application class loader. |
| if (appClassLoader != NULL) { |
| vmkit::Collector::markAndTraceRoot(NULL, |
| appClassLoader->getJavaClassLoaderPtr(), closure); |
| } |
| |
| // (3) Trace JNI global references. |
| JNIGlobalReferences* start = &globalRefs; |
| while (start != NULL) { |
| for (uint32 i = 0; i < start->length; ++i) { |
| JavaObject** obj = start->globalReferences + i; |
| vmkit::Collector::markAndTraceRoot(NULL, obj, closure); |
| } |
| start = start->next; |
| } |
| |
| // (4) Trace the finalization queue. |
| for (uint32 i = 0; i < finalizerThread->CurrentFinalizedIndex; ++i) { |
| vmkit::Collector::markAndTraceRoot(NULL, finalizerThread->ToBeFinalized + i, closure); |
| } |
| |
| // (5) Trace the reference queue |
| for (uint32 i = 0; i < referenceThread->ToEnqueueIndex; ++i) { |
| vmkit::Collector::markAndTraceRoot(NULL, referenceThread->ToEnqueue + i, closure); |
| } |
| |
| // (6) Trace the locks and their associated object. |
| uint32 i = 0; |
| for (; i < vmkit::LockSystem::GlobalSize; i++) { |
| vmkit::FatLock** array = lockSystem.LockTable[i]; |
| if (array == NULL) break; |
| uint32 j = 0; |
| for (; j < vmkit::LockSystem::IndexSize; j++) { |
| if (array[j] == NULL) break; |
| vmkit::FatLock* lock = array[j]; |
| jThread = NULL; |
| if (vmkit::Thread *th = lock->getOwner()) { |
| if (th->isVmkitThread()) |
| jThread = ((JavaThread*)th)->currentThread(); |
| } |
| vmkit::Collector::markAndTraceRoot(jThread, lock->getAssociatedObjectPtr(), closure); |
| } |
| for (j = j + 1; j < vmkit::LockSystem::IndexSize; j++) { |
| assert(array[j] == NULL); |
| } |
| } |
| for (i = i + 1; i < vmkit::LockSystem::GlobalSize; i++) { |
| assert(lockSystem.LockTable[i] == NULL); |
| } |
| } |
| |
| void JavaThread::tracer(word_t closure) { |
| vmkit::Collector::markAndTraceRoot(javaThread, &pendingException, closure); |
| vmkit::Collector::markAndTraceRoot(NULL, &javaThread, closure); |
| vmkit::Collector::markAndTraceRoot(javaThread, &vmThread, closure); |
| |
| JNILocalReferences* end = localJNIRefs; |
| while (end != NULL) { |
| for (uint32 i = 0; i < end->length; ++i) { |
| JavaObject** obj = end->localReferences + i; |
| vmkit::Collector::markAndTraceRoot(javaThread, obj, closure); |
| } |
| end = end->prev; |
| } |
| } |