X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=libjava%2Fjava%2Flang%2FnatClassLoader.cc;h=e62c6d392818b702e5b0a23c59af16b62be6b511;hb=62e761afd47d55fb2bcc32a97775e9cdad2ba7f6;hp=4c0f411a87764bb5a6e3ba48ebcf3d1c80921baf;hpb=1c3d0b79789773e24f107b582894fd0532368217;p=pf3gnuchains%2Fgcc-fork.git diff --git a/libjava/java/lang/natClassLoader.cc b/libjava/java/lang/natClassLoader.cc index 4c0f411a877..e62c6d39281 100644 --- a/libjava/java/lang/natClassLoader.cc +++ b/libjava/java/lang/natClassLoader.cc @@ -1,6 +1,6 @@ // natClassLoader.cc - Implementation of java.lang.ClassLoader native methods. -/* Copyright (C) 1999 Cygnus Solutions +/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation This file is part of libgcj. @@ -13,402 +13,358 @@ details. */ #include #include +#include #include -#include +#include #include +#include + +#include +#include + #include #include #include -#include #include #include #include -#include #include #include #include #include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include -#include +// Size of local hash table. +#define HASH_LEN 1013 -#define CloneableClass _CL_Q34java4lang9Cloneable -extern java::lang::Class CloneableClass; -#define ObjectClass _CL_Q34java4lang6Object -extern java::lang::Class ObjectClass; -#define ClassClass _CL_Q34java4lang5Class -extern java::lang::Class ClassClass; -#define VMClassLoaderClass _CL_Q34java4lang17VMClassLoader -extern java::lang::Class VMClassLoader; -#define ClassLoaderClass _CL_Q34java4lang11ClassLoader -extern java::lang::Class ClassLoaderClass; - -/////////// java.lang.ClassLoader native methods //////////// - -#ifdef INTERPRETER -gnu::gcj::runtime::VMClassLoader *redirect = 0; -#endif - -java::lang::ClassLoader* -java::lang::ClassLoader::getVMClassLoader0 () -{ -#ifdef INTERPRETER - if (redirect == 0) - redirect = new gnu::gcj::runtime::VMClassLoader; - return redirect; -#else - return 0; -#endif -} +// Hash function for Utf8Consts. +#define HASH_UTF(Utf) ((Utf)->hash16() % HASH_LEN) -void -java::lang::ClassLoader::defineClass2 (jclass klass, jbyteArray data, - jint offset, jint length) -{ -#ifdef INTERPRETER - _Jv_DefineClass (klass, data, offset, length); -#endif -} +// This records classes which will be registered with the system class +// loader when it is initialized. +static jclass system_class_list; -java::lang::Class * -java::lang::ClassLoader::defineClass0 (jstring name, - jbyteArray data, - jint offset, - jint length) -{ -#ifdef INTERPRETER - jclass klass; - klass = (jclass) JvAllocObject (&ClassClass, sizeof (_Jv_InterpClass)); +// 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) - // synchronize on the class, so that it is not - // attempted initialized until we're done loading. - _Jv_MonitorEnter (klass); +static jclass loaded_classes[HASH_LEN]; - // record which is the defining loader - klass->loader = this; +// This is the root of a linked list of classes +static jclass stack_head; - // register that we are the initiating loader... - if (name != 0) - { - _Jv_Utf8Const * name2 = _Jv_makeUtf8Const (name); +// 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; - _Jv_VerifyClassName (name2); - klass->name = name2; - } + - // this will do the magic. loadInto also operates - // as an exception trampoline for now... - Throwable *ex = defineClass1 (klass, data, offset, length); - - if (ex) // we failed to load it - { - klass->state = JV_STATE_ERROR; - klass->notifyAll (); - - _Jv_UnregisterClass (klass); - - _Jv_MonitorExit (klass); - - // FIXME: Here we may want to test that EX does - // indeed represent a valid exception. That is, - // anything but ClassNotFoundException, - // or some kind of Error. - - JvThrow (ex); - } - - // if everything proceeded sucessfully, we're loaded. - JvAssert (klass->state == JV_STATE_LOADED); +jclass +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; +} - // if an exception is generated, this is initially missed. - // however, we come back here in handleException0 below... - _Jv_MonitorExit (klass); + - return klass; +// 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); -#else // INTERPRETER + jclass klass; + for (klass = loaded_classes[hash]; klass; klass = klass->next_or_version) + { + if (_Jv_equalUtf8Consts (name, klass->name)) + break; + } - return 0; -#endif + return klass; } void -_Jv_WaitForState (jclass klass, int state) +_Jv_UnregisterClass (jclass the_class) { - if (klass->state >= state) + // This can happen if the class could not be defined properly. + if (! the_class->name) return; - - _Jv_MonitorEnter (klass) ; - - if (state == JV_STATE_LINKED) - { - _Jv_MonitorExit (klass); - _Jv_PrepareCompiledClass (klass); - return; - } - - java::lang::Thread *self = java::lang::Thread::currentThread(); - - // this is similar to the strategy for class initialization. - // if we already hold the lock, just leave. - while (klass->state <= state - && klass->thread - && klass->thread != self) - klass->wait (); - _Jv_MonitorExit (klass); + JvSynchronize sync (&java::lang::Class::class$); + jint hash = HASH_UTF(the_class->name); - if (klass->state == JV_STATE_ERROR) + jclass *klass = &(loaded_classes[hash]); + for ( ; *klass; klass = &((*klass)->next_or_version)) { - _Jv_Throw (new java::lang::LinkageError ()); + if (*klass == the_class) + { + *klass = (*klass)->next_or_version; + break; + } } } -// Finish linking a class. Only called from ClassLoader::resolveClass. +// Register an initiating class loader for a given class. void -java::lang::ClassLoader::linkClass0 (java::lang::Class *klass) +_Jv_RegisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader) { - if (klass->state >= JV_STATE_LINKED) - return; - -#ifdef INTERPRETER - if (_Jv_IsInterpretedClass (klass)) + if (! loader) + loader = java::lang::VMClassLoader::bootLoader; + if (! loader) { - _Jv_PrepareClass (klass); + // 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; } -#endif - - _Jv_PrepareCompiledClass (klass); + 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 -java::lang::ClassLoader::markClassErrorState0 (java::lang::Class *klass) +_Jv_UnregisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader) { - klass->state = JV_STATE_ERROR; - klass->notifyAll (); + if (! loader) + loader = java::lang::VMClassLoader::bootLoader; + loader->loadedClasses->remove(klass->name->toString()); } -/** this is the only native method in VMClassLoader, so - we define it here. */ -jclass -gnu::gcj::runtime::VMClassLoader::findSystemClass (jstring name) -{ - return _Jv_FindClassInCache (_Jv_makeUtf8Const (name), 0); -} +// Class registration. +// +// There are two kinds of functions that register classes. +// +// Type 1: +// +// These take the address of a class that is in an object file. +// Because these classes are not allocated on the heap, It is also +// necessary to register the address of the object for garbage +// collection. This is used with the "old" C++ ABI and with +// -findirect-dispatch -fno-indirect-classes. +// +// Type 2: +// +// These take an initializer struct, create the class, and return the +// address of the newly created class to their caller. These are used +// with -findirect-dispatch. +// +// _Jv_RegisterClasses() and _Jv_RegisterClasses_Counted() are +// functions of Type 1, and _Jv_NewClassFromInitializer() and +// _Jv_RegisterNewClasses() are of Type 2. -jclass -java::lang::ClassLoader::findLoadedClass (jstring name) + +// Check that the file we're trying to load has been compiled with a +// compatible version of gcj. In previous versions of libgcj we +// silently failed to register classes of an incompatible ABI version, +// but this was totally bogus. +void +_Jv_CheckABIVersion (unsigned long value) { - return _Jv_FindClassInCache (_Jv_makeUtf8Const (name), this); + // We are compatible with GCJ 4.0.0 BC-ABI classes. This release used a + // different format for the version ID string. + if (value == OLD_GCJ_40_BC_ABI_VERSION) + return; + + // The 20 low-end bits are used for the version number. + unsigned long version = value & 0xfffff; + + if (value & FLAG_BINARYCOMPAT_ABI) + { + int abi_rev = version % 100; + int abi_ver = version - abi_rev; + // We are compatible with abi_rev 0 and 1. + if (abi_ver == GCJ_40_BC_ABI_VERSION && abi_rev <= 1) + return; + } + else + { + // C++ ABI + if (version == GCJ_CXX_ABI_VERSION) + return; + + // If we've loaded a library that uses the C++ ABI, and this + // library is an incompatible version, then we're dead. There's + // no point throwing an exception: that will crash. + JvFail ("gcj linkage error.\n" + "Incorrect library ABI version detected. Aborting.\n"); + } + + throw new ::java::lang::ClassFormatError + (JvNewStringLatin1 ("Library compiled with later ABI version than" + " this version of libgcj supports")); } -static const int PUBLIC = 0x001; -static const int PRIVATE = 0x002; -static const int PROTECTED = 0x004; -static const int STATIC = 0x008; -static const int FINAL = 0x010; -static const int SYNCHRONIZED = 0x020; -static const int VOLATILE = 0x040; -static const int TRANSIENT = 0x080; -static const int NATIVE = 0x100; -static const int INTERFACE = 0x200; -static const int ABSTRACT = 0x400; -static const int ALL_FLAGS = 0x7FF; - - -/** This function does class-preparation for compiled classes. - NOTE: It contains replicated functionality from - _Jv_ResolvePoolEntry, and this is intentional, since that function - lives in resolve.cc which is entirely conditionally compiled. - */ +// This function is called many times during startup, before main() is +// run. At that point in time we know for certain we are running +// single-threaded, so we don't need to lock when adding classes to the +// class chain. At all other times, the caller should synchronize on +// Class::class$. void -_Jv_PrepareCompiledClass(jclass klass) +_Jv_RegisterClasses (const jclass *classes) { - if (klass->state >= JV_STATE_LINKED) - return; - - // short-circuit, so that mutually dependent classes are ok - klass->state = JV_STATE_LINKED; + _Jv_RegisterLibForGc (classes); - _Jv_Constants *pool = &klass->constants; - for (int index = 1; index < pool->size; ++index) + for (; *classes; ++classes) { - if (pool->tags[index] == JV_CONSTANT_Class) - { - _Jv_Utf8Const *name = pool->data[index].utf8; - - jclass found; - if (name->data[0] == '[') - found = _Jv_FindClassFromSignature (&name->data[0], - klass->loader); - else - found = _Jv_FindClass (name, klass->loader); - - if (! found) - { - jstring str = _Jv_NewStringUTF (name->data); - JvThrow (new java::lang::ClassNotFoundException (str)); - } + jclass klass = *classes; - pool->data[index].clazz = found; - pool->tags[index] |= JV_CONSTANT_ResolvedFlag; - } - - else if (pool->tags[index] == JV_CONSTANT_String) - { - jstring str; - str = _Jv_NewStringUtf8Const (pool->data[index].utf8); - pool->data[index].o = str; - pool->tags[index] |= JV_CONSTANT_ResolvedFlag; - } + _Jv_CheckABIVersion ((unsigned long) klass->next_or_version); + (*_Jv_RegisterClassHook) (klass); } - - klass->notifyAll (); } +// This is a version of _Jv_RegisterClasses that takes a count. +void +_Jv_RegisterClasses_Counted (const jclass * classes, size_t count) +{ + size_t i; -// -// 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. -// - + _Jv_RegisterLibForGc (classes); -// Size of local hash table. -#define HASH_LEN 1013 - -// Hash function for Utf8Consts. -#define HASH_UTF(Utf) (((Utf)->hash) % HASH_LEN) + for (i = 0; i < count; i++) + { + jclass klass = classes[i]; -struct _Jv_LoaderInfo { - _Jv_LoaderInfo *next; - java::lang::Class *klass; - java::lang::ClassLoader *loader; -}; + _Jv_CheckABIVersion ((unsigned long) klass->next_or_version); + (*_Jv_RegisterClassHook) (klass); + } +} -_Jv_LoaderInfo *initiated_classes[HASH_LEN]; -jclass loaded_classes[HASH_LEN]; +// Create a class on the heap from an initializer struct. +inline jclass +_Jv_NewClassFromInitializer (const char *class_initializer) +{ + const unsigned long version + = ((unsigned long) + ((::java::lang::Class *)class_initializer)->next_or_version); + _Jv_CheckABIVersion (version); + + /* We create an instance of java::lang::Class and copy all of its + fields except the first word (the vtable pointer) from + CLASS_INITIALIZER. This first word is pre-initialized by + _Jv_AllocObj, and we don't want to overwrite it. */ + + jclass new_class + = (jclass)_Jv_AllocObj (sizeof (::java::lang::Class), + &::java::lang::Class::class$); + const char *src = class_initializer + sizeof (void*); + char *dst = (char*)new_class + sizeof (void*); + size_t len = (::java::lang::Class::initializerSize (version) + - sizeof (void*)); + memcpy (dst, src, len); + + new_class->engine = &_Jv_soleIndirectCompiledEngine; + + (*_Jv_RegisterClassHook) (new_class); + + return new_class; +} -jclass -_Jv_FindClassInCache (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) +// 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 (char **classes) { - _Jv_MonitorEnter (&ClassClass); - jint hash = HASH_UTF (name); + _Jv_InitGC (); - // first, if LOADER is a defining loader, then it is also initiating - jclass klass; - for (klass = loaded_classes[hash]; klass; klass = klass->next) - { - if (loader == klass->loader && _Jv_equalUtf8Consts (name, klass->name)) - break; - } + const char *initializer; - // 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) + while ((initializer = *classes++)) { - _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; - } - } - } - - _Jv_MonitorExit (&ClassClass); - - return klass; + jclass *class_ptr = (jclass *)*classes++; + *class_ptr = _Jv_NewClassFromInitializer (initializer); + } } - + void -_Jv_UnregisterClass (jclass the_class) +_Jv_RegisterClassHookDefault (jclass klass) { - _Jv_MonitorEnter (&ClassClass); - jint hash = HASH_UTF(the_class->name); + // This is bogus, but there doesn't seem to be a better place to do + // it. + if (! klass->engine) + klass->engine = &_Jv_soleCompiledEngine; - jclass *klass = &(loaded_classes[hash]); - for ( ; *klass; klass = &((*klass)->next)) + if (system_class_list != SYSTEM_LOADER_INITIALIZED) { - if (*klass == the_class) + unsigned long abi = (unsigned long) klass->next_or_version; + if (! _Jv_ClassForBootstrapLoader (abi)) { - *klass = (*klass)->next; - break; + klass->next_or_version = system_class_list; + system_class_list = klass; + return; } } - _Jv_LoaderInfo **info = &(initiated_classes[hash]); - for ( ; *info; info = &((*info)->next)) + jint hash = HASH_UTF (klass->name); + + // If the class is already registered, don't re-register it. + for (jclass check_class = loaded_classes[hash]; + check_class != NULL; + check_class = check_class->next_or_version) { - while ((*info)->klass == the_class) + if (check_class == klass) { - *info = (*info)->next; + // If you get this, it means you have the same class in two + // different libraries. +#define TEXT "Duplicate class registration: " + // We size-limit MESSAGE so that you can't trash the stack. + char message[200]; + strcpy (message, TEXT); + strncpy (message + sizeof (TEXT) - 1, klass->name->chars(), + sizeof (message) - sizeof (TEXT)); + message[sizeof (message) - 1] = '\0'; + if (! gcj::runtimeInitialized) + JvFail (message); + else + { + java::lang::String *str = JvNewStringLatin1 (message); + throw new java::lang::VirtualMachineError (str); + } } } - _Jv_MonitorExit (&ClassClass); -} - -void -_Jv_RegisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader) -{ - _Jv_LoaderInfo *info = new _Jv_LoaderInfo; // non-gc alloc! - jint hash = HASH_UTF(klass->name); - - _Jv_MonitorEnter (&ClassClass); - info->loader = loader; - info->klass = klass; - info->next = initiated_classes[hash]; - initiated_classes[hash] = info; - _Jv_MonitorExit (&ClassClass); - + klass->next_or_version = loaded_classes[hash]; + loaded_classes[hash] = klass; } -// This function is called many times during startup, before main() is -// run. We do our runtime initialization here the very first time we -// are called. At that point in time we know for certain we are -// running single-threaded, so we don't need to lock when modifying -// `init'. CLASSES is NULL-terminated. -void -_Jv_RegisterClasses (jclass *classes) -{ - static bool init = false; +// A pointer to a function that actually registers a class. +// Normally _Jv_RegisterClassHookDefault, but could be some other function +// that registers the class in e.g. a ClassLoader-local table. +// Should synchronize on Class:class$ while setting/restore this variable. - if (! init) - { - init = true; - _Jv_InitThreads (); - _Jv_InitGC (); - _Jv_InitializeSyncMutex (); - } - - JvSynchronize sync (&ClassClass); - for (; *classes; ++classes) - { - jclass klass = *classes; - jint hash = HASH_UTF (klass->name); - klass->next = loaded_classes[hash]; - loaded_classes[hash] = klass; - - // registering a compiled class causes - // it to be immediately "prepared". - if (klass->state == JV_STATE_NOTHING) - klass->state = JV_STATE_COMPILED; - } -} +void (*_Jv_RegisterClassHook) (jclass cl) = _Jv_RegisterClassHookDefault; void _Jv_RegisterClass (jclass klass) @@ -419,171 +375,185 @@ _Jv_RegisterClass (jclass klass) _Jv_RegisterClasses (classes); } -#if 0 -// NOTE: this one is out of date with the new loader stuff... -jclass -_Jv_FindClassInCache (jstring name, java::lang::ClassLoader *loader) +// 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) { - JvSynchronize sync (&ClassClass); - jint hash = name->hashCode(); - jclass klass = loaded_classes[(_Jv_ushort) hash % HASH_LEN]; - for ( ; klass; klass = klass->next) + for (jclass klass = system_class_list; + klass; + klass = klass->next_or_version) { - if (loader == klass->loader - && _Jv_equal (klass->name, name, hash)) - break; + klass->loader = loader; + loader->addClass(klass); } - _Jv_MonitorExit (&ClassClass); - return klass; + system_class_list = SYSTEM_LOADER_INITIALIZED; } -#endif -jclass _Jv_FindClass (_Jv_Utf8Const *name, - java::lang::ClassLoader *loader) +// 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_FindClassNoException (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) { - jclass klass = _Jv_FindClassInCache (name, loader); + jclass klass; -#ifdef INTERPRETER - if (! klass) + try { - jstring sname = _Jv_NewStringUTF (name->data); - - if (loader) - { - // Load using a user-defined loader, jvmspec 5.3.2 - klass = loader->loadClass(sname, false); - - // if "loader" delegateted the loadClass operation - // to another loader, register explicitly - // that he is also an initiating loader of the - // given class. - - if (klass && (klass->getClassLoader () != loader)) - _Jv_RegisterInitiatingLoader (klass, 0); - } - else - { - if (redirect == NULL) - { - _Jv_InitClass (&ClassLoaderClass); - java::lang::ClassLoader::getSystemClassLoader (); - } - - // Load using the bootstrap loader jmspec 5.3.1 - klass = redirect -> loadClass (sname, false); - - // register that we're an initiating loader - if (klass) - { - _Jv_RegisterInitiatingLoader (klass, 0); - } - } + klass = _Jv_FindClass(name, loader); } - else + catch ( java::lang::NoClassDefFoundError *ncdfe ) { - // we need classes to be in the hash while - // we're loading, so that they can refer to themselves. - _Jv_WaitForState (klass, JV_STATE_LOADED); + return NULL; + } + catch ( java::lang::ClassNotFoundException *cnfe ) + { + return NULL; } -#endif return klass; } -#if 0 -// NOTE: this one is out of date with the new class loader stuff... jclass -_Jv_FindClass (jstring name, java::lang::ClassLoader *loader) +_Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) { - jclass klass = _Jv_FindClassInCache (name, 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) { - klass = loader->loadClass(name); + // 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 == boot + ? NULL + : loader); + if (klass && klass->getClassLoaderInternal () != delegate) + _Jv_RegisterInitiatingLoader (klass, loader); } - else + else if (boot) { - // jmspec 5.3.1.2 - - // delegate to the system loader - klass = java::lang::ClassLoader::system.loadClass (sname); - - // register that we're an initiating loader + // Load using the bootstrap loader jvmspec 5.3.1. + klass = java::lang::VMClassLoader::loadClass (sname, false); + + // Register that we're an initiating loader. if (klass) _Jv_RegisterInitiatingLoader (klass, 0); } + 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; + } + } + } } - else - { - _Jv_WaitForState (klass, JV_STATE_LOADED); - } - + return klass; } -#endif + +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) { - jclass ret = (jclass) JvAllocObject (&ClassClass); - - ret->next = NULL; + jclass ret = (jclass) _Jv_AllocObject (&java::lang::Class::class$); ret->name = name; - ret->accflags = 0; ret->superclass = superclass; - ret->constants.size = 0; - ret->constants.tags = NULL; - ret->constants.data = NULL; - ret->methods = NULL; - ret->method_count = 0; - ret->vtable_method_count = 0; - ret->fields = NULL; - ret->size_in_bytes = 0; - ret->field_count = 0; - ret->static_field_count = 0; - ret->vtable = NULL; - ret->interfaces = NULL; ret->loader = loader; - ret->interface_count = 0; - ret->state = JV_STATE_NOTHING; - ret->thread = NULL; - _Jv_RegisterClass (ret); + _Jv_RegisterInitiatingLoader (ret, loader); return ret; } -jclass -_Jv_FindArrayClass (jclass element, java::lang::ClassLoader *loader) +static _Jv_IDispatchTable *array_idt = NULL; +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 +// array class. This parameter is optional. +void +_Jv_NewArrayClass (jclass element, java::lang::ClassLoader *loader, + _Jv_VTable *array_vtable) +{ + JvSynchronize sync (element); + _Jv_Utf8Const *array_name; int len; + + if (element->arrayclass) + return; + if (element->isPrimitive()) { - // For primitive types the array is cached in the class. - jclass ret = (jclass) element->methods; - if (ret) - return ret; + if (element == JvPrimClass (void)) + throw new java::lang::ClassNotFoundException (); len = 3; } else - len = element->name->length + 5; + len = element->name->len() + 5; { char signature[len]; int index = 0; signature[index++] = '['; - // Compute name of array class to see if we've already cached it. + // Compute name of array class. if (element->isPrimitive()) { signature[index++] = (char) element->method_count; } else { - size_t length = element->name->length; - const char *const name = element->name->data; + size_t length = element->name->len(); + const char *const name = element->name->chars(); if (name[0] != '[') signature[index++] = 'L'; memcpy (&signature[index], name, length); @@ -594,58 +564,98 @@ _Jv_FindArrayClass (jclass element, java::lang::ClassLoader *loader) array_name = _Jv_makeUtf8Const (signature, index); } - jclass array_class = _Jv_FindClassInCache (array_name, element->loader); + // Create new array class. + jclass array_class = _Jv_NewClass (array_name, &java::lang::Object::class$, + element->loader); - if (! array_class) + // Note that `vtable_method_count' doesn't include the initial + // gc_descr slot. + int dm_count = java::lang::Object::class$.vtable_method_count; + + // Create a new vtable by copying Object's vtable. + _Jv_VTable *vtable; + if (array_vtable) + vtable = array_vtable; + else + vtable = _Jv_VTable::new_vtable (dm_count); + vtable->clas = array_class; + vtable->gc_descr = java::lang::Object::class$.vtable->gc_descr; + for (int i = 0; i < dm_count; ++i) + vtable->set_method (i, java::lang::Object::class$.vtable->get_method (i)); + + array_class->vtable = vtable; + array_class->vtable_method_count + = java::lang::Object::class$.vtable_method_count; + + // Stash the pointer to the element type. + array_class->element_type = element; + + // Register our interfaces. + array_class->interfaces = interfaces; + array_class->interface_count = sizeof interfaces / sizeof interfaces[0]; + + // Since all array classes have the same interface dispatch table, we can + // cache one and reuse it. It is not necessary to synchronize this. + if (!array_idt) { - // Create new array class. - array_class = _Jv_NewClass (array_name, &ObjectClass, element->loader); - - // Note that `vtable_method_count' doesn't include the initial - // NULL slot. - int dm_count = ObjectClass.vtable_method_count + 1; - - // Create a new vtable by copying Object's vtable (except the - // class pointer, of course). Note that we allocate this as - // unscanned memory -- the vtables are handled specially by the - // GC. - int size = (sizeof (_Jv_VTable) + - ((dm_count - 1) * sizeof (void *))); - _Jv_VTable *vtable = (_Jv_VTable *) _Jv_AllocBytes (size); - vtable->clas = array_class; - memcpy (vtable->method, ObjectClass.vtable->method, - dm_count * sizeof (void *)); - array_class->vtable = vtable; - array_class->vtable_method_count = ObjectClass.vtable_method_count; - - // Stash the pointer to the element type. - array_class->methods = (_Jv_Method *) element; - - // Register our interfaces. - // FIXME: for JDK 1.2 we need Serializable. - static jclass interfaces[] = { &CloneableClass }; - array_class->interfaces = interfaces; - array_class->interface_count = 1; - - // as per vmspec 5.3.3.2 - array_class->accflags = element->accflags; - - // FIXME: initialize other Class instance variables, - // e.g. `fields'. - - // say this class is initialized and ready to go! - array_class->state = JV_STATE_DONE; - - // vmspec, section 5.3.3 describes this - if (element->loader != loader) - _Jv_RegisterInitiatingLoader (array_class, loader); + _Jv_Linker::wait_for_state(array_class, JV_STATE_PREPARED); + array_idt = array_class->idt; + array_depth = array_class->depth; + array_ancestors = array_class->ancestors; + } + else + { + array_class->idt = array_idt; + array_class->depth = array_depth; + array_class->ancestors = array_ancestors; } - // For primitive types, point back at this array. - if (element->isPrimitive()) - element->methods = (_Jv_Method *) array_class; + using namespace java::lang::reflect; + { + // Array classes are "abstract final" and inherit accessibility + // from element type, per vmspec 5.3.3.2 + _Jv_ushort accflags = (Modifier::FINAL | Modifier::ABSTRACT + | (element->accflags + & (Modifier::PUBLIC | Modifier::PROTECTED + | Modifier::PRIVATE))); + array_class->accflags = accflags; + } + + // An array class has no visible instance fields. "length" is invisible to + // reflection. + + // Say this class is initialized and ready to go! + array_class->state = JV_STATE_DONE; + + // vmspec, section 5.3.3 describes this + if (element->loader != loader) + _Jv_RegisterInitiatingLoader (array_class, loader); - return array_class; + element->arrayclass = array_class; } +// These two functions form a stack of classes. When a class is loaded +// it is pushed onto the stack by the class loader; this is so that +// StackTrace can quickly determine which classes have been loaded. +jclass +_Jv_PopClass (void) +{ + JvSynchronize sync (&java::lang::Class::class$); + if (stack_head) + { + jclass tmp = stack_head; + stack_head = tmp->chain; + return tmp; + } + return NULL; +} + +void +_Jv_PushClass (jclass k) +{ + JvSynchronize sync (&java::lang::Class::class$); + jclass tmp = stack_head; + stack_head = k; + k->chain = tmp; +}