// natClassLoader.cc - Implementation of java.lang.ClassLoader native methods.
-/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation
This file is part of libgcj.
#include <java/lang/Character.h>
#include <java/lang/Thread.h>
#include <java/lang/ClassLoader.h>
-#include <gnu/gcj/runtime/VMClassLoader.h>
#include <java/lang/InternalError.h>
#include <java/lang/IllegalAccessError.h>
#include <java/lang/LinkageError.h>
#include <java/lang/StringBuffer.h>
#include <java/io/Serializable.h>
#include <java/lang/Cloneable.h>
-
-//
-// A single class can have many "initiating" class loaders,
-// and a single "defining" class loader. The Defining
-// class loader is what is returned from Class.getClassLoader()
-// and is used when loading dependent classes during resolution.
-// The set of initiating class loaders are used to ensure
-// safety of linking, and is maintained in the hash table
-// "initiated_classes". A defining classloader is by definition also
-// initiating, so we only store classes in this table if they have more
-// than one class loader associated.
-//
-
+#include <java/util/HashMap.h>
+#include <gnu/gcj/runtime/BootClassLoader.h>
+#include <gnu/gcj/runtime/SystemClassLoader.h>
// Size of local hash table.
#define HASH_LEN 1013
// Hash function for Utf8Consts.
#define HASH_UTF(Utf) ((Utf)->hash16() % HASH_LEN)
-struct _Jv_LoaderInfo
-{
- _Jv_LoaderInfo *next;
- java::lang::Class *klass;
- java::lang::ClassLoader *loader;
-};
+// This records classes which will be registered with the system class
+// loader when it is initialized.
+static jclass system_class_list;
+
+// This is used as the value of system_class_list after we have
+// initialized the system class loader; it lets us know that we should
+// no longer pay attention to the system abi flag.
+#define SYSTEM_LOADER_INITIALIZED ((jclass) -1)
-static _Jv_LoaderInfo *initiated_classes[HASH_LEN];
static jclass loaded_classes[HASH_LEN];
// This is the root of a linked list of classes
static jclass stack_head;
+// While bootstrapping we keep a list of classes we found, so that we
+// can register their packages. There aren't many of these so we
+// just keep a small buffer here and abort if we overflow.
+#define BOOTSTRAP_CLASS_LIST_SIZE 20
+static jclass bootstrap_class_list[BOOTSTRAP_CLASS_LIST_SIZE];
+static int bootstrap_index;
+
\f
jclass
-_Jv_FindClassInCache (_Jv_Utf8Const *name, java::lang::ClassLoader *loader)
+java::lang::ClassLoader::loadClassFromSig(jstring name)
+{
+ int len = _Jv_GetStringUTFLength (name);
+ char sig[len + 1];
+ _Jv_GetStringUTFRegion (name, 0, name->length(), sig);
+ jclass result = _Jv_FindClassFromSignature(sig, this);
+ if (result == NULL)
+ throw new ClassNotFoundException(name);
+ return result;
+}
+
+\f
+
+// This tries to find a class in our built-in cache. This cache is
+// used only for classes which are linked in to the executable or
+// loaded via dlopen().
+jclass
+_Jv_FindClassInCache (_Jv_Utf8Const *name)
{
JvSynchronize sync (&java::lang::Class::class$);
jint hash = HASH_UTF (name);
- if (loader && loader == java::lang::ClassLoader::getSystemClassLoader())
- loader = NULL;
-
- // first, if LOADER is a defining loader, then it is also initiating
jclass klass;
- for (klass = loaded_classes[hash]; klass; klass = klass->next)
+ for (klass = loaded_classes[hash]; klass; klass = klass->next_or_version)
{
- if (loader == klass->loader && _Jv_equalUtf8Consts (name, klass->name))
+ if (_Jv_equalUtf8Consts (name, klass->name))
break;
}
- // otherwise, it may be that the class in question was defined
- // by some other loader, but that the loading was initiated by
- // the loader in question.
- if (!klass)
- {
- _Jv_LoaderInfo *info;
- for (info = initiated_classes[hash]; info; info = info->next)
- {
- if (loader == info->loader
- && _Jv_equalUtf8Consts (name, info->klass->name))
- {
- klass = info->klass;
- break;
- }
- }
- }
-
return klass;
}
void
_Jv_UnregisterClass (jclass the_class)
{
+ // This can happen if the class could not be defined properly.
+ if (! the_class->name)
+ return;
+
JvSynchronize sync (&java::lang::Class::class$);
jint hash = HASH_UTF(the_class->name);
jclass *klass = &(loaded_classes[hash]);
- for ( ; *klass; klass = &((*klass)->next))
+ for ( ; *klass; klass = &((*klass)->next_or_version))
{
if (*klass == the_class)
{
- *klass = (*klass)->next;
+ *klass = (*klass)->next_or_version;
break;
}
}
+}
- _Jv_LoaderInfo **info = &(initiated_classes[hash]);
- for ( ; ; info = &((*info)->next))
+// Register an initiating class loader for a given class.
+void
+_Jv_RegisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader)
+{
+ if (! loader)
+ loader = java::lang::VMClassLoader::bootLoader;
+ if (! loader)
{
- while (*info && (*info)->klass == the_class)
- {
- _Jv_LoaderInfo *old = *info;
- *info = (*info)->next;
- _Jv_Free (old);
- }
-
- if (*info == NULL)
- break;
+ // Very early in the bootstrap process, the Bootstrap classloader may
+ // not exist yet.
+ // FIXME: We could maintain a list of these and come back and register
+ // them later.
+ return;
}
+ loader->loadedClasses->put(klass->name->toString(), klass);
}
+// If we found an error while defining an interpreted class, we must
+// go back and unregister it.
void
-_Jv_RegisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader)
+_Jv_UnregisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader)
{
- if (loader && loader == java::lang::ClassLoader::getSystemClassLoader())
- loader = NULL;
-
- // This information can't be visible to the GC.
- _Jv_LoaderInfo *info
- = (_Jv_LoaderInfo *) _Jv_Malloc (sizeof(_Jv_LoaderInfo));
- jint hash = HASH_UTF(klass->name);
-
- JvSynchronize sync (&java::lang::Class::class$);
- info->loader = loader;
- info->klass = klass;
- info->next = initiated_classes[hash];
- initiated_classes[hash] = info;
+ if (! loader)
+ loader = java::lang::VMClassLoader::bootLoader;
+ loader->loadedClasses->remove(klass->name->toString());
}
// This function is called many times during startup, before main() is
void
_Jv_RegisterClasses (const jclass *classes)
{
+ _Jv_RegisterLibForGc (classes);
+
for (; *classes; ++classes)
{
jclass klass = *classes;
- (*_Jv_RegisterClassHook) (klass);
+ if (_Jv_CheckABIVersion ((unsigned long) klass->next_or_version))
+ (*_Jv_RegisterClassHook) (klass);
}
}
_Jv_RegisterClasses_Counted (const jclass * classes, size_t count)
{
size_t i;
+
+ _Jv_RegisterLibForGc (classes);
+
for (i = 0; i < count; i++)
{
jclass klass = classes[i];
- (*_Jv_RegisterClassHook) (klass);
+ if (_Jv_CheckABIVersion ((unsigned long) klass->next_or_version))
+ (*_Jv_RegisterClassHook) (klass);
}
}
+// Create a class on the heap from an initializer struct.
+jclass
+_Jv_NewClassFromInitializer (const jclass class_initializer)
+{
+ jclass new_class = (jclass)_Jv_AllocObj (sizeof *new_class,
+ &java::lang::Class::class$);
+ memcpy ((void*)new_class, (void*)class_initializer, sizeof *new_class);
+
+ if (_Jv_CheckABIVersion ((unsigned long) new_class->next_or_version))
+ (*_Jv_RegisterClassHook) (new_class);
+
+ return new_class;
+}
+
+// Called by compiler-generated code at DSO initialization. CLASSES
+// is an array of pairs: the first item of each pair is a pointer to
+// the initialized data that is a class initializer in a DSO, and the
+// second is a pointer to a class reference.
+// _Jv_NewClassFromInitializer() creates the new class (on the Java
+// heap) and we write the address of the new class into the address
+// pointed to by the second word.
+void
+_Jv_RegisterNewClasses (void **classes)
+{
+ _Jv_InitGC ();
+
+ jclass initializer;
+
+ while ((initializer = (jclass)*classes++))
+ {
+ jclass *class_ptr = (jclass *)*classes++;
+ *class_ptr = _Jv_NewClassFromInitializer (initializer);
+ }
+}
+
void
_Jv_RegisterClassHookDefault (jclass klass)
{
+ // This is bogus, but there doesn't seem to be a better place to do
+ // it.
+ if (! klass->engine)
+ klass->engine = &_Jv_soleCompiledEngine;
+
+ if (system_class_list != SYSTEM_LOADER_INITIALIZED)
+ {
+ unsigned long abi = (unsigned long) klass->next_or_version;
+ if (! _Jv_ClassForBootstrapLoader (abi))
+ {
+ klass->next_or_version = system_class_list;
+ system_class_list = klass;
+ return;
+ }
+ }
+
jint hash = HASH_UTF (klass->name);
- // The BC ABI makes this check unnecessary: we always resolve all
- // data references via the appropriate class loader, so the kludge
- // that required this check has gone.
// If the class is already registered, don't re-register it.
- jclass check_class = klass->next;
- while (check_class != NULL)
+ for (jclass check_class = loaded_classes[hash];
+ check_class != NULL;
+ check_class = check_class->next_or_version)
{
if (check_class == klass)
{
throw new java::lang::VirtualMachineError (str);
}
}
-
- check_class = check_class->next;
}
- // FIXME: this is really bogus!
- if (! klass->engine)
- klass->engine = &_Jv_soleCompiledEngine;
- klass->next = loaded_classes[hash];
+ klass->next_or_version = loaded_classes[hash];
loaded_classes[hash] = klass;
}
_Jv_RegisterClasses (classes);
}
+// This is used during initialization to register all compiled-in
+// classes that are not part of the core with the system class loader.
+void
+_Jv_CopyClassesToSystemLoader (gnu::gcj::runtime::SystemClassLoader *loader)
+{
+ for (jclass klass = system_class_list;
+ klass;
+ klass = klass->next_or_version)
+ {
+ klass->loader = loader;
+ loader->addClass(klass);
+ }
+ system_class_list = SYSTEM_LOADER_INITIALIZED;
+}
+
+// An internal variant of _Jv_FindClass which simply swallows a
+// NoClassDefFoundError or a ClassNotFoundException. This gives the
+// caller a chance to evaluate the situation and behave accordingly.
jclass
-_Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader)
+_Jv_FindClassNoException (_Jv_Utf8Const *name, java::lang::ClassLoader *loader)
{
- jclass klass = _Jv_FindClassInCache (name, loader);
+ jclass klass;
- if (! klass)
+ try
{
- jstring sname = name->toString();
+ klass = _Jv_FindClass(name, loader);
+ }
+ catch ( java::lang::NoClassDefFoundError *ncdfe )
+ {
+ return NULL;
+ }
+ catch ( java::lang::ClassNotFoundException *cnfe )
+ {
+ return NULL;
+ }
+
+ return klass;
+}
- java::lang::ClassLoader *sys
- = java::lang::ClassLoader::getSystemClassLoader ();
+jclass
+_Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader)
+{
+ // See if the class was already loaded by this loader. This handles
+ // initiating loader checks, as we register classes with their
+ // initiating loaders.
+
+ java::lang::ClassLoader *boot = java::lang::VMClassLoader::bootLoader;
+ java::lang::ClassLoader *real = loader;
+ if (! real)
+ real = boot;
+ jstring sname = name->toString();
+ // We might still be bootstrapping the VM, in which case there
+ // won't be a bootstrap class loader yet.
+ jclass klass = real ? real->findLoadedClass (sname) : NULL;
+ if (! klass)
+ {
if (loader)
{
- // Load using a user-defined loader, jvmspec 5.3.2
- klass = loader->loadClass(sname, false);
+ // Load using a user-defined loader, jvmspec 5.3.2.
+ // Note that we explicitly must call the single-argument form.
+ klass = loader->loadClass(sname);
// If "loader" delegated the loadClass operation to another
// loader, explicitly register that it is also an initiating
// loader of the given class.
- java::lang::ClassLoader *delegate = (loader == sys
+ java::lang::ClassLoader *delegate = (loader == boot
? NULL
: loader);
if (klass && klass->getClassLoaderInternal () != delegate)
_Jv_RegisterInitiatingLoader (klass, loader);
}
- else
+ else if (boot)
{
// Load using the bootstrap loader jvmspec 5.3.1.
- klass = sys->loadClass (sname, false);
+ klass = java::lang::VMClassLoader::loadClass (sname, false);
// Register that we're an initiating loader.
if (klass)
_Jv_RegisterInitiatingLoader (klass, 0);
}
- }
- else
- {
- // we need classes to be in the hash while
- // we're loading, so that they can refer to themselves.
- _Jv_Linker::wait_for_state (klass, JV_STATE_LOADED);
+ else
+ {
+ // Not even a bootstrap loader, try the built-in cache.
+ klass = _Jv_FindClassInCache (name);
+
+ if (klass)
+ {
+ bool found = false;
+ for (int i = 0; i < bootstrap_index; ++i)
+ {
+ if (bootstrap_class_list[i] == klass)
+ {
+ found = true;
+ break;
+ }
+ }
+ if (! found)
+ {
+ if (bootstrap_index == BOOTSTRAP_CLASS_LIST_SIZE)
+ abort ();
+ bootstrap_class_list[bootstrap_index++] = klass;
+ }
+ }
+ }
}
return klass;
}
+void
+_Jv_RegisterBootstrapPackages ()
+{
+ for (int i = 0; i < bootstrap_index; ++i)
+ java::lang::VMClassLoader::definePackageForNative(bootstrap_class_list[i]->getName());
+}
+
jclass
_Jv_NewClass (_Jv_Utf8Const *name, jclass superclass,
java::lang::ClassLoader *loader)
ret->superclass = superclass;
ret->loader = loader;
- _Jv_RegisterClass (ret);
+ _Jv_RegisterInitiatingLoader (ret, loader);
return ret;
}
static jshort array_depth = 0;
static jclass *array_ancestors = NULL;
+static jclass interfaces[] =
+{
+ &java::lang::Cloneable::class$,
+ &java::io::Serializable::class$
+};
+
// Create a class representing an array of ELEMENT and store a pointer to it
// in element->arrayclass. LOADER is the ClassLoader which _initiated_ the
// instantiation of this array. ARRAY_VTABLE is the vtable to use for the new
// Note that `vtable_method_count' doesn't include the initial
// gc_descr slot.
- JvAssert (java::lang::Object::class$.vtable_method_count
- == NUM_OBJECT_METHODS);
int dm_count = java::lang::Object::class$.vtable_method_count;
// Create a new vtable by copying Object's vtable.
= java::lang::Object::class$.vtable_method_count;
// Stash the pointer to the element type.
- array_class->methods = (_Jv_Method *) element;
+ array_class->element_type = element;
// Register our interfaces.
- static jclass interfaces[] =
- {
- &java::lang::Cloneable::class$,
- &java::io::Serializable::class$
- };
array_class->interfaces = interfaces;
array_class->interface_count = sizeof interfaces / sizeof interfaces[0];