blob: ff54b7c2b19fd75a40bbd355f26f107eb3fe9260 [file] [log] [blame]
//===------ 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;
}
}