blob: 35221051c5078e4d41216a0ed4bd58c07efd807a [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. It is used by the
// GCMmap2 garbage collector and may be of use for other GCs. Boehm GC does
// not use these 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.
//
//===----------------------------------------------------------------------===//
#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"
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 JnJVM, there is only one 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).
//===----------------------------------------------------------------------===//
VirtualTable VMClassLoader::VT((uintptr_t)VMClassLoader::staticDestructor,
(uintptr_t)VMClassLoader::staticDestructor,
(uintptr_t)VMClassLoader::staticTracer);
//===----------------------------------------------------------------------===//
// Empty tracer for static tracers of classes that do not declare static
// variables.
//===----------------------------------------------------------------------===//
extern "C" void EmptyTracer(void*) {}
//===----------------------------------------------------------------------===//
// Trace methods for Java objects. There are four types of objects:
// (1) Base object whose class is not an array: needs to trace the classloader
// and the lock.
// (1) Object whose class is not an array: needs to trace the classloader, the
// lock and all the virtual fields.
// (2) Object whose class is an array of objects: needs to trace root (1) and
// all elements in the array.
// (3) Object whose class is a native array: only needs to trace the lock. The
// classloader is the bootstrap loader and is traced by the JVM.
//===----------------------------------------------------------------------===//
/// Method for scanning the root of an object.
extern "C" void JavaObjectTracer(JavaObject* obj) {
CommonClass* cl = obj->getClass();
assert(cl && "No class");
mvm::Collector::markAndTraceRoot(cl->classLoader->getJavaClassLoaderPtr());
}
/// Method for scanning an array whose elements are JavaObjects. This method is
/// called by all non-native Java arrays.
extern "C" void ArrayObjectTracer(ArrayObject* obj) {
CommonClass* cl = obj->getClass();
assert(cl && "No class");
mvm::Collector::markAndTraceRoot(cl->classLoader->getJavaClassLoaderPtr());
for (sint32 i = 0; i < obj->size; i++) {
if (obj->elements[i]) {
mvm::Collector::markAndTrace(obj, obj->elements + i);
}
}
}
/// Method for scanning a native array. Only scan the lock. The classloader of
/// the class is the bootstrap loader and therefore does not need to be
/// scanned here.
extern "C" void JavaArrayTracer(JavaArray* obj) {
}
/// Method for scanning regular objects.
extern "C" void RegularObjectTracer(JavaObject* obj) {
Class* cl = obj->getClass()->asClass();
assert(cl && "Not a class in regular tracer");
mvm::Collector::markAndTraceRoot(cl->classLoader->getJavaClassLoaderPtr());
while (cl->super != 0) {
for (uint32 i = 0; i < cl->nbVirtualFields; ++i) {
JavaField& field = cl->virtualFields[i];
if (field.isReference()) {
JavaObject** ptr = field.getObjectFieldPtr(obj);
mvm::Collector::markAndTrace(obj, ptr);
}
}
cl = cl->super;
}
}
//===----------------------------------------------------------------------===//
// 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 bytes that represent the class file.
// (4) The static instance.
//===----------------------------------------------------------------------===//
void CommonClass::tracer() {
if (super && super->classLoader) {
JavaObject** Obj = super->classLoader->getJavaClassLoaderPtr();
if (*Obj) mvm::Collector::markAndTraceRoot(Obj);
for (uint32 i = 0; i < nbInterfaces; ++i) {
if (interfaces[i]->classLoader) {
JavaObject** Obj = interfaces[i]->classLoader->getJavaClassLoaderPtr();
if (*Obj) mvm::Collector::markAndTraceRoot(Obj);
}
}
}
if (classLoader)
mvm::Collector::markAndTraceRoot(classLoader->getJavaClassLoaderPtr());
for (uint32 i = 0; i < NR_ISOLATES; ++i) {
// If the delegatee was static allocated, we want to trace its fields.
if (delegatee[i]) {
delegatee[i]->tracer();
mvm::Collector::markAndTraceRoot(delegatee + i);
}
}
}
void Class::tracer() {
CommonClass::tracer();
if (classLoader != classLoader->bootstrapLoader)
mvm::Collector::markAndTraceRoot(&bytes);
for (uint32 i =0; i < NR_ISOLATES; ++i) {
TaskClassMirror &M = IsolateInfo[i];
if (M.staticInstance) {
for (uint32 i = 0; i < nbStaticFields; ++i) {
JavaField& field = staticFields[i];
if (field.isReference()) {
JavaObject** ptr = field.getObjectFieldPtr(M.staticInstance);
mvm::Collector::markAndTraceRoot(ptr);
}
}
}
}
}
//===----------------------------------------------------------------------===//
// 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() {
for (ClassMap::iterator i = classes->map.begin(), e = classes->map.end();
i!= e; ++i) {
CommonClass* cl = i->second;
if (cl->isClass()) cl->asClass()->tracer();
else cl->tracer();
}
StringList* end = strings;
while (end) {
for (uint32 i = 0; i < end->length; ++i) {
JavaString** obj = end->strings + i;
mvm::Collector::markAndTraceRoot(obj);
}
end = end->prev;
}
}
void JnjvmBootstrapLoader::tracer() {
JnjvmClassLoader::tracer();
#define TRACE_DELEGATEE(prim) \
prim->tracer();
TRACE_DELEGATEE(upcalls->OfVoid);
TRACE_DELEGATEE(upcalls->OfBool);
TRACE_DELEGATEE(upcalls->OfByte);
TRACE_DELEGATEE(upcalls->OfChar);
TRACE_DELEGATEE(upcalls->OfShort);
TRACE_DELEGATEE(upcalls->OfInt);
TRACE_DELEGATEE(upcalls->OfFloat);
TRACE_DELEGATEE(upcalls->OfLong);
TRACE_DELEGATEE(upcalls->OfDouble);
#undef TRACE_DELEGATEE
}
//===----------------------------------------------------------------------===//
// 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 ony 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() {
VirtualMachine::tracer();
bootstrapLoader->tracer();
if (appClassLoader)
mvm::Collector::markAndTraceRoot(appClassLoader->getJavaClassLoaderPtr());
JNIGlobalReferences* start = &globalRefs;
while (start) {
for (uint32 i = 0; i < start->length; ++i) {
JavaObject** obj = start->globalReferences + i;
mvm::Collector::markAndTraceRoot(obj);
}
start = start->next;
}
for (StringMap::iterator i = hashStr.map.begin(), e = hashStr.map.end();
i!= e; ++i) {
JavaString** str = &(i->second);
mvm::Collector::markAndTraceRoot(str);
}
#if defined(ISOLATE_SHARING)
mvm::Collector::markAndTraceRoot(&JnjvmSharedLoader::sharedLoader);
#endif
#ifdef SERVICE
parent->tracer();
#endif
}
void JavaThread::tracer() {
if (pendingException) mvm::Collector::markAndTraceRoot(&pendingException);
mvm::Collector::markAndTraceRoot(&javaThread);
#ifdef SERVICE
mvm::Collector::markAndTraceRoot(&ServiceException);
#endif
JNILocalReferences* end = localJNIRefs;
while (end) {
for (uint32 i = 0; i < end->length; ++i) {
JavaObject** obj = end->localReferences + i;
mvm::Collector::markAndTraceRoot(obj);
}
end = end->prev;
}
}