| // natVMClassLoader.cc - VMClassLoader native methods | |
| /* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation | |
| This file is part of libgcj. | |
| This software is copyrighted work licensed under the terms of the | |
| Libgcj License. Please consult the file "LIBGCJ_LICENSE" for | |
| details. */ | |
| /* Author: Kresten Krab Thorup <krab@gnu.org> */ | |
| #include <config.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <gcj/cni.h> | |
| #include <jvm.h> | |
| #include <java-threads.h> | |
| #include <java-interp.h> | |
| #include <java/lang/VMClassLoader.h> | |
| #include <java/lang/VMCompiler.h> | |
| #include <gnu/gcj/runtime/ExtensionClassLoader.h> | |
| #include <gnu/gcj/runtime/SystemClassLoader.h> | |
| #include <gnu/gcj/runtime/BootClassLoader.h> | |
| #include <java/lang/ClassLoader.h> | |
| #include <java/lang/Class.h> | |
| #include <java/lang/Throwable.h> | |
| #include <java/security/ProtectionDomain.h> | |
| #include <java/lang/ClassFormatError.h> | |
| #include <java/lang/StringBuffer.h> | |
| #include <java/lang/Runtime.h> | |
| #include <java/util/HashSet.h> | |
| #include <java/lang/VirtualMachineError.h> | |
| java::lang::Class * | |
| java::lang::VMClassLoader::defineClass (java::lang::ClassLoader *loader, | |
| jstring name, | |
| jbyteArray data, | |
| jint offset, | |
| jint length, | |
| java::security::ProtectionDomain *pd) | |
| { | |
| jclass klass = VMCompiler::compileClass(loader, name, data, | |
| offset, length, pd); | |
| #ifdef INTERPRETER | |
| if (klass == NULL) | |
| { | |
| klass = new java::lang::Class (); | |
| // Synchronize on the class, so that it is not attempted initialized | |
| // until we're done loading. | |
| JvSynchronize sync (klass); | |
| // Record the defining loader. For the bootstrap class loader, | |
| // we record NULL. | |
| if (loader != bootLoader) | |
| klass->loader = loader; | |
| if (name != 0) | |
| { | |
| _Jv_Utf8Const *name2 = _Jv_makeUtf8Const (name); | |
| if (! _Jv_VerifyClassName (name2)) | |
| throw new java::lang::ClassFormatError | |
| (JvNewStringLatin1 ("erroneous class name")); | |
| klass->name = name2; | |
| } | |
| _Jv_Utf8Const *found_name = NULL; | |
| try | |
| { | |
| _Jv_DefineClass (klass, data, offset, length, pd, &found_name); | |
| } | |
| catch (java::lang::Throwable *ex) | |
| { | |
| klass->state = JV_STATE_ERROR; | |
| klass->notifyAll (); | |
| if (found_name != NULL) | |
| _Jv_UnregisterInitiatingLoader (klass, klass->loader); | |
| // If EX is not a ClassNotFoundException, that's ok, because we | |
| // account for the possibility in defineClass(). | |
| throw ex; | |
| } | |
| // if everything proceeded sucessfully, we're loaded. | |
| JvAssert (klass->state == JV_STATE_LOADED); | |
| } | |
| #endif // INTERPRETER | |
| if (! klass) | |
| { | |
| StringBuffer *sb = new StringBuffer(); | |
| if (name) | |
| { | |
| sb->append(JvNewStringLatin1("found class file for class ")); | |
| sb->append(name); | |
| } | |
| else | |
| sb->append(JvNewStringLatin1("found unnamed class file")); | |
| sb->append(JvNewStringLatin1(", but no interpreter configured in this libgcj")); | |
| throw new VirtualMachineError(sb->toString()); | |
| } | |
| return klass; | |
| } | |
| java::lang::ClassLoader * | |
| java::lang::VMClassLoader::getSystemClassLoaderInternal() | |
| { | |
| _Jv_InitClass (&gnu::gcj::runtime::ExtensionClassLoader::class$); | |
| _Jv_CopyClassesToSystemLoader (gnu::gcj::runtime::ExtensionClassLoader::system_instance); | |
| return gnu::gcj::runtime::ExtensionClassLoader::system_instance; | |
| } | |
| jclass | |
| java::lang::VMClassLoader::getPrimitiveClass (jchar type) | |
| { | |
| char sig[2]; | |
| sig[0] = (char) type; | |
| sig[1] = '\0'; | |
| // Note: this cannot return NULL, since the input is always correct. | |
| return _Jv_FindClassFromSignature (sig, NULL); | |
| } | |
| void | |
| java::lang::VMClassLoader::initBootLoader(jstring libdir) | |
| { | |
| bootLoader = new gnu::gcj::runtime::BootClassLoader(libdir); | |
| } | |
| jclass | |
| java::lang::VMClassLoader::nativeFindClass (jstring name) | |
| { | |
| jclass klass = NULL; | |
| if (lib_control != LIB_NEVER) | |
| { | |
| // Turn `gnu.pkg.quux' into `lib-gnu-pkg-quux'. Then search for | |
| // a module named (eg, on Linux) `lib-gnu-pkg-quux.so', followed | |
| // by `lib-gnu-pkg.so' and `lib-gnu.so'. If loading one of | |
| // these causes the class to appear in the cache, then use it. | |
| java::lang::StringBuffer *sb | |
| = new java::lang::StringBuffer (JvNewStringLatin1("lib-")); | |
| // Skip inner classes | |
| jstring cn; | |
| jint ci = name->indexOf('$'); | |
| if (ci == -1) | |
| cn = name; | |
| else | |
| cn = name->substring (0, ci); | |
| jstring so_base_name | |
| = (sb->append (cn)->toString ())->replace ('.', '-'); | |
| using namespace ::java::lang; | |
| Runtime *rt = Runtime::getRuntime(); | |
| _Jv_Utf8Const *name_u = NULL; | |
| // Compare against `3' because that is the length of "lib". | |
| while (! klass && so_base_name && so_base_name->length() > 3) | |
| { | |
| if (lib_control == LIB_CACHE) | |
| { | |
| // If we've already tried this name, we're done. | |
| if (tried_libraries->contains(so_base_name)) | |
| break; | |
| tried_libraries->add(so_base_name); | |
| } | |
| jboolean loaded = rt->loadLibraryInternal (so_base_name); | |
| jint nd = so_base_name->lastIndexOf ('-'); | |
| if (nd == -1) | |
| so_base_name = NULL; | |
| else | |
| so_base_name = so_base_name->substring (0, nd); | |
| if (loaded) | |
| { | |
| if (name_u == NULL) | |
| name_u = _Jv_makeUtf8Const (name); | |
| klass = _Jv_FindClassInCache (name_u); | |
| } | |
| } | |
| } | |
| if (klass) | |
| definePackageForNative(name); | |
| return klass; | |
| } | |
| jclass | |
| java::lang::VMClassLoader::loadClass(jstring name, jboolean resolve) | |
| { | |
| // We try the boot loader first, so that the endorsed directory | |
| // overrides compiled-in classes. | |
| jclass klass = NULL; | |
| if (bootLoader) | |
| klass = bootLoader->bootLoadClass(name); | |
| if (! klass) | |
| { | |
| _Jv_Utf8Const *utf = _Jv_makeUtf8Const (name); | |
| klass = _Jv_FindClassInCache (utf); | |
| } | |
| if (! klass) | |
| klass = nativeFindClass(name); | |
| if (klass) | |
| { | |
| // We never want to return a class without its supers linked. | |
| // It isn't clear from the spec, but this is what other | |
| // implementations do in practice. | |
| if (resolve) | |
| resolveClass (klass); | |
| else | |
| _Jv_Linker::wait_for_state (klass, JV_STATE_LOADING); | |
| definePackageForNative(name); | |
| } | |
| return klass; | |
| } |