| // 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; |
| } |