246 lines
6.4 KiB
C++
246 lines
6.4 KiB
C++
// 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/SecurityManager.h>
|
|
#include <java/lang/Runtime.h>
|
|
#include <java/util/HashSet.h>
|
|
#include <java/lang/SecurityException.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);
|
|
|
|
if (klass)
|
|
_Jv_RegisterInitiatingLoader (klass, klass->loader);
|
|
|
|
#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_READ);
|
|
}
|
|
#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)
|
|
{
|
|
using namespace ::java::lang;
|
|
|
|
SecurityManager *sm = (SecurityManager *)SecurityManager::current;
|
|
if (sm)
|
|
{
|
|
jint lastDot = name->lastIndexOf('.');
|
|
if (lastDot != -1)
|
|
sm->checkPackageAccess(name->substring(0, lastDot));
|
|
}
|
|
|
|
// 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;
|
|
}
|