blob: 384eed9e83c2d29af957f18f0dfc6163b5323c5b [file] [log] [blame]
//===-- JnjvmClassLoader.cpp - Jnjvm representation of a class loader ------===//
//
// The VMKit project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#define DEBUG_VERBOSE_CLASS_LOADER_UNLOADING 1
#include <iostream>
#include <climits>
#include <cstdlib>
// for strrchr
#include <cstring>
// for dlopen and dlsym
#include <dlfcn.h>
// for stat, S_IFMT and S_IFDIR
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string>
#include "debug.h"
#include "vmkit/Allocator.h"
#include "Classpath.h"
#include "ClasspathReflect.h"
#include "JavaClass.h"
#include "j3/JavaCompiler.h"
#include "JavaConstantPool.h"
#include "JavaString.h"
#include "JavaThread.h"
#include "JavaTypes.h"
#include "JavaUpcalls.h"
#include "Jnjvm.h"
#include "JnjvmClassLoader.h"
#include "LockedMap.h"
#include "Reader.h"
#include "Zip.h"
using namespace j3;
using namespace std;
typedef void (*static_init_t)(JnjvmClassLoader*);
const UTF8* JavaCompiler::InlinePragma = 0;
const UTF8* JavaCompiler::NoInlinePragma = 0;
JnjvmBootstrapLoader::JnjvmBootstrapLoader(vmkit::BumpPtrAllocator& Alloc,
JavaCompiler* Comp,
bool dlLoad) :
JnjvmClassLoader(Alloc) {
TheCompiler = Comp;
javaTypes = new(allocator, "TypeMap") TypeMap();
javaSignatures = new(allocator, "SignMap") SignMap();
strings = new(allocator, "StringList") StringList();
bootClasspathEnv = ClasslibBootEnv;
libClasspathEnv = ClasslibLibEnv;
upcalls = new(allocator, "Classpath") Classpath();
bootstrapLoader = this;
// Try to find if we have a pre-compiled rt.jar
bool bootLoaded = false;
if (dlLoad) {
bootLoaded = Precompiled::Init(this);
}
if (!bootLoaded) {
classes = new(allocator, "ClassMap") ClassMap();
hashUTF8 = new(allocator, "UTF8Map") UTF8Map(allocator);
// Analyze the boot classpath, we know bootstrap classes are not in the
// executable.
analyseClasspathEnv(bootClasspathEnv);
// Allocate the interfaces array for array classes, so that VT construction
// can use it right away.
ClassArray::InterfacesArray =
(Class**)allocator.Allocate(2 * sizeof(UserClass*), "Interface array");
// Create the primitive classes.
upcalls->OfChar = UPCALL_PRIMITIVE_CLASS(this, "char", 1);
upcalls->OfBool = UPCALL_PRIMITIVE_CLASS(this, "boolean", 0);
upcalls->OfShort = UPCALL_PRIMITIVE_CLASS(this, "short", 1);
upcalls->OfInt = UPCALL_PRIMITIVE_CLASS(this, "int", 2);
upcalls->OfLong = UPCALL_PRIMITIVE_CLASS(this, "long", 3);
upcalls->OfFloat = UPCALL_PRIMITIVE_CLASS(this, "float", 2);
upcalls->OfDouble = UPCALL_PRIMITIVE_CLASS(this, "double", 3);
upcalls->OfVoid = UPCALL_PRIMITIVE_CLASS(this, "void", 0);
upcalls->OfByte = UPCALL_PRIMITIVE_CLASS(this, "byte", 0);
}
// Create the primitive arrays.
upcalls->ArrayOfChar = constructArray(asciizConstructUTF8("[C"),
upcalls->OfChar);
upcalls->ArrayOfByte = constructArray(asciizConstructUTF8("[B"),
upcalls->OfByte);
upcalls->ArrayOfInt = constructArray(asciizConstructUTF8("[I"),
upcalls->OfInt);
upcalls->ArrayOfBool = constructArray(asciizConstructUTF8("[Z"),
upcalls->OfBool);
upcalls->ArrayOfLong = constructArray(asciizConstructUTF8("[J"),
upcalls->OfLong);
upcalls->ArrayOfFloat = constructArray(asciizConstructUTF8("[F"),
upcalls->OfFloat);
upcalls->ArrayOfDouble = constructArray(asciizConstructUTF8("[D"),
upcalls->OfDouble);
upcalls->ArrayOfShort = constructArray(asciizConstructUTF8("[S"),
upcalls->OfShort);
// Fill the maps.
primitiveMap[I_VOID] = upcalls->OfVoid;
primitiveMap[I_BOOL] = upcalls->OfBool;
primitiveMap[I_BYTE] = upcalls->OfByte;
primitiveMap[I_CHAR] = upcalls->OfChar;
primitiveMap[I_SHORT] = upcalls->OfShort;
primitiveMap[I_INT] = upcalls->OfInt;
primitiveMap[I_FLOAT] = upcalls->OfFloat;
primitiveMap[I_LONG] = upcalls->OfLong;
primitiveMap[I_DOUBLE] = upcalls->OfDouble;
arrayTable[JavaArray::T_BOOLEAN - 4] = upcalls->ArrayOfBool;
arrayTable[JavaArray::T_BYTE - 4] = upcalls->ArrayOfByte;
arrayTable[JavaArray::T_CHAR - 4] = upcalls->ArrayOfChar;
arrayTable[JavaArray::T_SHORT - 4] = upcalls->ArrayOfShort;
arrayTable[JavaArray::T_INT - 4] = upcalls->ArrayOfInt;
arrayTable[JavaArray::T_FLOAT - 4] = upcalls->ArrayOfFloat;
arrayTable[JavaArray::T_LONG - 4] = upcalls->ArrayOfLong;
arrayTable[JavaArray::T_DOUBLE - 4] = upcalls->ArrayOfDouble;
JavaAttribute::annotationsAttribute =
asciizConstructUTF8("RuntimeVisibleAnnotations");
JavaAttribute::codeAttribute = asciizConstructUTF8("Code");
JavaAttribute::exceptionsAttribute = asciizConstructUTF8("Exceptions");
JavaAttribute::constantAttribute = asciizConstructUTF8("ConstantValue");
JavaAttribute::lineNumberTableAttribute = asciizConstructUTF8("LineNumberTable");
JavaAttribute::innerClassesAttribute = asciizConstructUTF8("InnerClasses");
JavaAttribute::sourceFileAttribute = asciizConstructUTF8("SourceFile");
JavaAttribute::signatureAttribute = asciizConstructUTF8("Signature");
JavaAttribute::enclosingMethodAttribute = asciizConstructUTF8("EnclosingMethod");
JavaAttribute::paramAnnotationsAttribute = asciizConstructUTF8("RuntimeVisibleParameterAnnotations");
JavaAttribute::annotationDefaultAttribute = asciizConstructUTF8("AnnotationDefault");
JavaCompiler::InlinePragma =
asciizConstructUTF8("Lorg/vmmagic/pragma/Inline;");
JavaCompiler::NoInlinePragma =
asciizConstructUTF8("Lorg/vmmagic/pragma/NoInline;");
initName = asciizConstructUTF8("<init>");
initExceptionSig = asciizConstructUTF8("(Ljava/lang/String;)V");
clinitName = asciizConstructUTF8("<clinit>");
clinitType = asciizConstructUTF8("()V");
runName = asciizConstructUTF8("run");
prelib = asciizConstructUTF8("lib");
postlib = asciizConstructUTF8(vmkit::System::GetDyLibExtension());
mathName = asciizConstructUTF8("java/lang/Math");
VMFloatName = asciizConstructUTF8("java/lang/VMFloat");
VMDoubleName = asciizConstructUTF8("java/lang/VMDouble");
stackWalkerName = asciizConstructUTF8("gnu/classpath/VMStackWalker");
NoClassDefFoundError = asciizConstructUTF8("java/lang/NoClassDefFoundError");
#define DEF_UTF8(var) \
var = asciizConstructUTF8(#var)
DEF_UTF8(abs);
DEF_UTF8(sqrt);
DEF_UTF8(sin);
DEF_UTF8(cos);
DEF_UTF8(tan);
DEF_UTF8(asin);
DEF_UTF8(acos);
DEF_UTF8(atan);
DEF_UTF8(atan2);
DEF_UTF8(exp);
DEF_UTF8(log);
DEF_UTF8(pow);
DEF_UTF8(ceil);
DEF_UTF8(floor);
DEF_UTF8(rint);
DEF_UTF8(cbrt);
DEF_UTF8(cosh);
DEF_UTF8(expm1);
DEF_UTF8(hypot);
DEF_UTF8(log10);
DEF_UTF8(log1p);
DEF_UTF8(sinh);
DEF_UTF8(tanh);
DEF_UTF8(finalize);
DEF_UTF8(floatToRawIntBits);
DEF_UTF8(doubleToRawLongBits);
DEF_UTF8(intBitsToFloat);
DEF_UTF8(longBitsToDouble);
#undef DEF_UTF8
}
JnjvmClassLoader::JnjvmClassLoader(vmkit::BumpPtrAllocator& Alloc) :
allocator(Alloc)
{
}
JnjvmClassLoader::JnjvmClassLoader(
vmkit::BumpPtrAllocator& Alloc, JnjvmClassLoader& JCL, JavaObject* loader,
VMClassLoader* vmdata, Jnjvm* VM) :
allocator(Alloc)
{
llvm_gcroot(loader, 0);
llvm_gcroot(vmdata, 0);
bootstrapLoader = JCL.bootstrapLoader;
TheCompiler = bootstrapLoader->getCompiler()->Create(
"Applicative loader",
bootstrapLoader->getCompiler()->isCompilingGarbageCollector());
hashUTF8 = new(allocator, "UTF8Map") UTF8Map(allocator);
classes = new(allocator, "ClassMap") ClassMap();
javaTypes = new(allocator, "TypeMap") TypeMap();
javaSignatures = new(allocator, "SignMap") SignMap();
strings = new(allocator, "StringList") StringList();
vmdata->JCL = this;
vmkit::Collector::objectReferenceNonHeapWriteBarrier(
(gc**)&javaLoader, (gc*)loader);
vm = VM;
JavaMethod* meth = bootstrapLoader->upcalls->loadInClassLoader;
loadClassMethod =
JavaObject::getClass(loader)->asClass()->lookupMethodDontThrow(
meth->name, meth->type, false, true, &loadClass);
assert(loadClass && "Loader does not have a loadClass function");
}
void JnjvmClassLoader::setCompiler(JavaCompiler* Comp) {
// Set the new compiler.
TheCompiler = Comp;
}
ClassBytes* JnjvmBootstrapLoader::openName(const UTF8* utf8) {
ClassBytes* res = reinterpret_cast<ClassBytes*>(dlsym(vmkit::System::GetSelfHandle(),
UTF8Buffer(utf8).toCompileName("_bytes")->cString()));
if (res != NULL) return res;
vmkit::ThreadAllocator threadAllocator;
char* asciiz = (char*)threadAllocator.Allocate(utf8->size + 1);
for (sint32 i = 0; i < utf8->size; ++i)
asciiz[i] = utf8->elements[i];
asciiz[utf8->size] = 0;
uint32 alen = utf8->size;
for (std::vector<const char*>::iterator i = bootClasspath.begin(),
e = bootClasspath.end(); i != e; ++i) {
const char* str = *i;
unsigned int strLen = strlen(str);
char* buf = (char*)threadAllocator.Allocate(strLen + alen + 7);
sprintf(buf, "%s%s.class", str, asciiz);
res = Reader::openFile(this, buf);
if (res != NULL) return res;
}
for (std::vector<ZipArchive*>::iterator i = bootArchives.begin(),
e = bootArchives.end(); i != e; ++i) {
ZipArchive* archive = *i;
char* buf = (char*)threadAllocator.Allocate(alen + 7);
sprintf(buf, "%s.class", asciiz);
res = Reader::openZip(this, archive, buf);
if (res != NULL) return res;
}
return NULL;
}
UserClass* JnjvmBootstrapLoader::internalLoad(const UTF8* name,
bool doResolve,
JavaString* strName) {
ClassBytes* bytes = NULL;
llvm_gcroot(strName, 0);
UserCommonClass* cl = lookupClass(name);
if (!cl) {
bytes = openName(name);
if (bytes != NULL) {
cl = constructClass(name, bytes);
}
}
if (cl) {
assert(!cl->isArray());
if (doResolve) cl->asClass()->resolveClass();
}
if (cl) {
// If we don't have knowledge of the package containing this class,
// add it to the set of packages defined in this classLoader
UTF8Buffer buffer(name);
const char * cname = buffer.cString();
const char * slash = strrchr(cname, '/');
if (slash) {
int packagelen = slash - cname;
const UTF8 * package = name->extract(hashUTF8, 0, packagelen);
//classes->lock.lock();
lock.lock();
packages.insert(package);
lock.unlock();
//classes->lock.unlock();
}
}
return (UserClass*)cl;
}
UserCommonClass* JnjvmClassLoader::internalLoadCreateClass(const UTF8* name, JavaString* strName)
{
JavaObjectClass* jcl = 0;
JavaObject* obj = 0;
llvm_gcroot(strName, 0);
llvm_gcroot(obj, 0);
llvm_gcroot(jcl, 0);
UserClass* forCtp = loadClass;
if (strName == NULL) {
strName = JavaString::internalToJava(name, vm);
}
obj = loadClassMethod->invokeJavaObjectVirtual(vm, forCtp, javaLoader, &strName);
return JavaObjectClass::getClass(jcl = (JavaObjectClass*)obj);
}
UserClass* JnjvmClassLoader::internalLoad(const UTF8* name, bool doResolve,
JavaString* strName) {
llvm_gcroot(strName, 0);
UserCommonClass* cl = lookupClass(name);
if (!cl) {
cl = internalLoadCreateClass(name, strName);
}
if (cl && doResolve && cl->isClass()) {
cl->asClass()->resolveClass();
}
return (UserClass*)cl;
}
UserClass* JnjvmClassLoader::loadName(const UTF8* name, bool doResolve,
bool doThrow, JavaString* strName) {
llvm_gcroot(strName, 0);
UserClass* cl = internalLoad(name, doResolve, strName);
if (!cl && doThrow) {
Jnjvm* vm = JavaThread::get()->getJVM();
if (name->equals(bootstrapLoader->NoClassDefFoundError)) {
fprintf(stderr, "Unable to load NoClassDefFoundError");
abort();
}
if (TheCompiler->isStaticCompiling()) {
fprintf(stderr, "Could not find %s, needed for static compiling\n",
UTF8Buffer(name).cString());
abort();
}
vm->noClassDefFoundError(name);
}
ensureCached(cl);
return cl;
}
void JnjvmClassLoader::ensureCached(UserCommonClass* cl) {
if (cl && cl->classLoader != this) {
classes->lock.lock();
ClassMap::iterator End = classes->map.end();
ClassMap::iterator I = classes->map.find(cl->name);
if (I == End)
classes->map.insert(std::make_pair(cl->name, cl));
classes->lock.unlock();
}
}
const UTF8* JnjvmClassLoader::lookupComponentName(const UTF8* name,
UTF8* holder,
bool& prim) {
uint32 len = name->size;
uint32 start = 0;
uint32 origLen = len;
while (true) {
--len;
if (len == 0) {
return 0;
} else {
++start;
if (name->elements[start] != I_TAB) {
if (name->elements[start] == I_REF) {
uint32 size = (uint32)name->size;
if ((size == (start + 1)) || (size == (start + 2)) ||
(name->elements[start + 1] == I_TAB) ||
(name->elements[origLen - 1] != I_END_REF)) {
return 0;
} else {
const uint16* buf = &(name->elements[start + 1]);
uint32 bufLen = len - 2;
const UTF8* componentName = hashUTF8->lookupReader(buf, bufLen);
if (!componentName && holder) {
holder->size = len - 2;
for (uint32 i = 0; i < len - 2; ++i) {
holder->elements[i] = name->elements[start + 1 + i];
}
componentName = holder;
}
return componentName;
}
} else {
uint16 cur = name->elements[start];
if ((cur == I_BOOL || cur == I_BYTE ||
cur == I_CHAR || cur == I_SHORT ||
cur == I_INT || cur == I_FLOAT ||
cur == I_DOUBLE || cur == I_LONG)
&& ((uint32)name->size) == start + 1) {
prim = true;
}
return 0;
}
}
}
}
return 0;
}
UserCommonClass* JnjvmClassLoader::lookupClassOrArray(const UTF8* name) {
UserCommonClass* temp = lookupClass(name);
if (temp) return temp;
if (this != bootstrapLoader) {
temp = bootstrapLoader->lookupClassOrArray(name);
ensureCached(temp);
if (temp) return temp;
}
if (name->elements[0] == I_TAB) {
bool prim = false;
const UTF8* componentName = lookupComponentName(name, 0, prim);
if (prim) return constructArray(name);
if (componentName) {
UserCommonClass* temp = lookupClass(componentName);
if (temp) return constructArray(name);
}
}
return 0;
}
UserCommonClass* JnjvmClassLoader::loadClassFromUserUTF8(const UTF8* name,
bool doResolve,
bool doThrow,
JavaString* strName) {
llvm_gcroot(strName, 0);
if (name->size == 0) {
return 0;
} else if (name->elements[0] == I_TAB) {
vmkit::ThreadAllocator threadAllocator;
bool prim = false;
UTF8* holder = (UTF8*)threadAllocator.Allocate(
sizeof(UTF8) + name->size * sizeof(uint16));
if (!holder) return 0;
const UTF8* componentName = lookupComponentName(name, holder, prim);
if (prim) return constructArray(name);
if (componentName) {
UserCommonClass* temp = loadName(componentName, doResolve, doThrow, NULL);
ensureCached(temp);
if (temp) return constructArray(name);
}
} else {
return loadName(name, doResolve, doThrow, strName);
}
return NULL;
}
UserCommonClass* JnjvmClassLoader::loadClassFromAsciiz(const char* asciiz,
bool doResolve,
bool doThrow) {
const UTF8* name = hashUTF8->lookupAsciiz(asciiz);
vmkit::ThreadAllocator threadAllocator;
if (!name) name = bootstrapLoader->hashUTF8->lookupAsciiz(asciiz);
if (!name) {
uint32 size = strlen(asciiz);
UTF8* temp = (UTF8*)threadAllocator.Allocate(
sizeof(UTF8) + size * sizeof(uint16));
temp->size = size;
for (uint32 i = 0; i < size; ++i) {
temp->elements[i] = asciiz[i];
}
name = temp;
}
return loadClassFromUserUTF8(name, doResolve, doThrow, NULL);
}
UserCommonClass*
JnjvmClassLoader::loadClassFromJavaString(JavaString* str, bool doResolve,
bool doThrow) {
llvm_gcroot(str, 0);
vmkit::ThreadAllocator allocator;
UTF8* name = (UTF8*)allocator.Allocate(sizeof(UTF8) + str->count * sizeof(uint16));
name->size = str->count;
for (sint32 i = 0; i < str->count; ++i) {
uint16 cur = ArrayUInt16::getElement(JavaString::getValue(str), str->offset + i);
if (cur == '.') name->elements[i] = '/';
else if (cur == '/') {
return 0;
}
else name->elements[i] = cur;
}
return loadClassFromUserUTF8(name, doResolve, doThrow, str);
}
UserCommonClass* JnjvmClassLoader::lookupClassFromJavaString(JavaString* str) {
const ArrayUInt16* value = NULL;
llvm_gcroot(str, 0);
llvm_gcroot(value, 0);
value = JavaString::getValue(str);
vmkit::ThreadAllocator allocator;
UTF8* name = (UTF8*)allocator.Allocate(sizeof(UTF8) + str->count * sizeof(uint16));
name->size = str->count;
for (sint32 i = 0; i < str->count; ++i) {
uint16 cur = ArrayUInt16::getElement(value, str->offset + i);
if (cur == '.') name->elements[i] = '/';
else name->elements[i] = cur;
}
UserCommonClass* cls = lookupClass(name);
return cls;
}
UserCommonClass* JnjvmClassLoader::lookupClass(const UTF8* utf8) {
classes->lock.lock();
UserCommonClass* cl = classes->map.lookup(utf8);
classes->lock.unlock();
return cl;
}
UserCommonClass* JnjvmClassLoader::loadBaseClass(const UTF8* name,
uint32 start, uint32 len) {
if (name->elements[start] == I_TAB) {
UserCommonClass* baseClass = loadBaseClass(name, start + 1, len - 1);
JnjvmClassLoader* loader = baseClass->classLoader;
const UTF8* arrayName = name->extract(loader->hashUTF8, start, start + len);
return loader->constructArray(arrayName, baseClass);
} else if (name->elements[start] == I_REF) {
const UTF8* componentName = name->extract(hashUTF8,
start + 1, start + len - 1);
UserCommonClass* cl = loadName(componentName, false, true, NULL);
return cl;
} else {
Classpath* upcalls = bootstrapLoader->upcalls;
UserClassPrimitive* prim =
UserClassPrimitive::byteIdToPrimitive(name->elements[start], upcalls);
assert(prim && "No primitive found");
return prim;
}
}
UserClassArray* JnjvmClassLoader::constructArray(const UTF8* name) {
ClassArray* res = (ClassArray*)lookupClass(name);
if (res) return res;
UserCommonClass* cl = loadBaseClass(name, 1, name->size - 1);
assert(cl && "no base class for an array");
JnjvmClassLoader* ld = cl->classLoader;
res = ld->constructArray(name, cl);
ensureCached(res);
return res;
}
UserClass* JnjvmClassLoader::constructClass(const UTF8* name,
ClassBytes* bytes) {
JavaObject* excp = NULL;
llvm_gcroot(excp, 0);
UserClass* res = NULL;
lock2.lock();
classes->lock.lock();
res = (UserClass*) classes->map.lookup(name);
classes->lock.unlock();
if (res == NULL) {
TRY {
const UTF8* internalName = readerConstructUTF8(name->elements, name->size);
res = new(allocator, "Class") UserClass(this, internalName, bytes);
res->readClass();
res->makeVT();
getCompiler()->resolveVirtualClass(res);
getCompiler()->resolveStaticClass(res);
classes->lock.lock();
assert(res->getDelegatee() == NULL);
assert(res->getStaticInstance() == NULL);
assert(classes->map.lookup(internalName) == NULL);
classes->map[internalName] = res;
classes->lock.unlock();
} CATCH {
excp = JavaThread::get()->pendingException;
JavaThread::get()->clearException();
} END_CATCH;
}
lock2.unlock();
if (excp != NULL) {
JavaThread::get()->throwException(excp);
}
if (res->super == NULL) {
// java.lang.Object just got created, initialise VTs of arrays.
ClassArray::initialiseVT(res);
}
return res;
}
UserClassArray* JnjvmClassLoader::constructArray(const UTF8* name,
UserCommonClass* baseClass) {
assert(baseClass && "constructing an array class without a base class");
assert(baseClass->classLoader == this &&
"constructing an array with wrong loader");
UserClassArray* res = 0;
classes->lock.lock();
res = (UserClassArray*) classes->map.lookup(name);
if (res == NULL) {
const UTF8* internalName = readerConstructUTF8(name->elements, name->size);
res = new(allocator, "Array class") UserClassArray(this, internalName,
baseClass);
classes->map.insert(std::make_pair(internalName, res));
}
classes->lock.unlock();
return res;
}
Typedef* JnjvmClassLoader::internalConstructType(const UTF8* name) {
short int cur = name->elements[0];
Typedef* res = 0;
switch (cur) {
case I_TAB :
res = new(allocator, "ArrayTypedef") ArrayTypedef(name);
break;
case I_REF :
res = new(allocator, "ObjectTypedef") ObjectTypedef(name, hashUTF8);
break;
default :
UserClassPrimitive* cl =
bootstrapLoader->getPrimitiveClass((char)name->elements[0]);
assert(cl && "No primitive");
bool unsign = (cl == bootstrapLoader->upcalls->OfChar ||
cl == bootstrapLoader->upcalls->OfBool);
res = new(allocator, "PrimitiveTypedef") PrimitiveTypedef(name, cl,
unsign, cur);
}
return res;
}
Typedef* JnjvmClassLoader::constructType(const UTF8* name) {
javaTypes->lock.lock();
Typedef* res = javaTypes->map.lookup(name);
if (res == 0) {
res = internalConstructType(name);
javaTypes->map[name] = res;
}
javaTypes->lock.unlock();
return res;
}
static void typeError(const UTF8* name, short int l) {
if (l != 0) {
fprintf(stderr, "wrong type %d in %s", l, UTF8Buffer(name).cString());
} else {
fprintf(stderr, "wrong type %s", UTF8Buffer(name).cString());
}
abort();
}
static bool analyseIntern(const UTF8* name, uint32 pos, uint32 meth,
uint32& ret) {
short int cur = name->elements[pos];
switch (cur) {
case I_PARD :
ret = pos + 1;
return true;
case I_BOOL :
ret = pos + 1;
return false;
case I_BYTE :
ret = pos + 1;
return false;
case I_CHAR :
ret = pos + 1;
return false;
case I_SHORT :
ret = pos + 1;
return false;
case I_INT :
ret = pos + 1;
return false;
case I_FLOAT :
ret = pos + 1;
return false;
case I_DOUBLE :
ret = pos + 1;
return false;
case I_LONG :
ret = pos + 1;
return false;
case I_VOID :
ret = pos + 1;
return false;
case I_TAB :
if (meth == 1) {
pos++;
} else {
while (name->elements[++pos] == I_TAB) {}
analyseIntern(name, pos, 1, pos);
}
ret = pos;
return false;
case I_REF :
if (meth != 2) {
while (name->elements[++pos] != I_END_REF) {}
}
ret = pos + 1;
return false;
default :
typeError(name, cur);
}
return false;
}
Signdef* JnjvmClassLoader::constructSign(const UTF8* name) {
javaSignatures->lock.lock();
Signdef* res = javaSignatures->map.lookup(name);
if (res == 0) {
std::vector<Typedef*> buf;
uint32 len = (uint32)name->size;
uint32 pos = 1;
uint32 pred = 0;
while (pos < len) {
pred = pos;
bool end = analyseIntern(name, pos, 0, pos);
if (end) break;
else {
buf.push_back(constructType(name->extract(hashUTF8, pred, pos)));
}
}
if (pos == len) {
typeError(name, 0);
}
analyseIntern(name, pos, 0, pred);
if (pred != len) {
typeError(name, 0);
}
Typedef* ret = constructType(name->extract(hashUTF8, pos, pred));
res = new(allocator, buf.size()) Signdef(name, this, buf, ret);
javaSignatures->map[name] = res;
}
javaSignatures->lock.unlock();
return res;
}
JnjvmClassLoader* JnjvmClassLoader::createForJavaObject(
Jnjvm* vm, JavaObject* loader, VMClassLoader**vmdata)
{
llvm_gcroot(loader, 0);
*vmdata = VMClassLoader::allocate();
vmkit::BumpPtrAllocator* A = new vmkit::BumpPtrAllocator();
JnjvmClassLoader* JCL = new(*A, "Class loader")
JnjvmClassLoader(*A, *vm->bootstrapLoader, loader, *vmdata, vm);
Classpath* upcalls = vm->bootstrapLoader->upcalls;
upcalls->vmdataClassLoader->setInstanceObjectField(loader, *vmdata);
return JCL;
}
JnjvmClassLoader*
JnjvmClassLoader::getJnjvmLoaderFromJavaObject(JavaObject* loader, Jnjvm* vm) {
VMClassLoader* vmdata = 0;
llvm_gcroot(loader, 0);
llvm_gcroot(vmdata, 0);
if (loader == NULL)
return vm->bootstrapLoader;
JnjvmClassLoader* JCL = 0;
Classpath* upcalls = vm->bootstrapLoader->upcalls;
vmdata =
(VMClassLoader*)(upcalls->vmdataClassLoader->getInstanceObjectField(loader));
// If the vmdata field isn't set yet, or it's set to something other than
// a VMClassLoader (which happens in the OpenJDK port), then initialize
// the field now.
if (vmdata == NULL) {
JavaObject::acquire(loader);
vmdata =
(VMClassLoader*)(upcalls->vmdataClassLoader->getInstanceObjectField(loader));
if (!vmdata || !VMClassLoader::isVMClassLoader(vmdata)) {
JCL = JnjvmClassLoader::createForJavaObject(vm, loader, &vmdata);
}
JavaObject::release(loader);
}
else if (!VMClassLoader::isVMClassLoader(vmdata)) {
JavaObject::acquire(loader);
JCL = JnjvmClassLoader::createForJavaObject(vm, loader, &vmdata);
JavaObject::release(loader);
} else {
JCL = vmdata->getClassLoader();
assert(JCL->javaLoader == loader);
}
if (!JCL) {
assert( vmdata->getClassLoader() == JCL && "Loader is not equal to stored value");
fprintf(stderr, "Error in method %s, %d because condition 1: %d\n",
__FILE__, __LINE__, (vmdata == NULL || !VMClassLoader::isVMClassLoader(vmdata)));
}
return JCL;
}
const UTF8* JnjvmClassLoader::asciizConstructUTF8(const char* asciiz) {
return hashUTF8->lookupOrCreateAsciiz(asciiz);
}
const UTF8* JnjvmClassLoader::readerConstructUTF8(const uint16* buf,
uint32 size) {
return hashUTF8->lookupOrCreateReader(buf, size);
}
JnjvmClassLoader::~JnjvmClassLoader() {
if (vm) {
vm->removeFrameInfos(TheCompiler);
}
if (classes) {
classes->~ClassMap();
allocator.Deallocate(classes);
classes = NULL;
}
if (hashUTF8) {
hashUTF8->~UTF8Map();
allocator.Deallocate(hashUTF8);
hashUTF8 = NULL;
}
if (javaTypes) {
javaTypes->~TypeMap();
allocator.Deallocate(javaTypes);
javaTypes = NULL;
}
if (javaSignatures) {
javaSignatures->~SignMap();
allocator.Deallocate(javaSignatures);
javaSignatures = NULL;
}
for (std::vector<void*>::iterator
i = nativeLibs.begin(), e = nativeLibs.end(); i != e; ++i)
{
dlclose(*i);
}
nativeLibs.clear();
vm = NULL;
delete TheCompiler;
TheCompiler = NULL;
// Don't delete the allocator. The caller of this method must
// delete it after the current object is deleted.
}
JnjvmBootstrapLoader::~JnjvmBootstrapLoader() {
}
JavaString** JnjvmClassLoader::UTF8ToStr(const UTF8* val) {
JavaString* res = NULL;
llvm_gcroot(res, 0);
res = vm->internalUTF8ToStr(val);
return strings->addString(this, res);
}
JavaString** JnjvmBootstrapLoader::UTF8ToStr(const UTF8* val) {
JavaString* res = NULL;
llvm_gcroot(res, 0);
Jnjvm* vm = JavaThread::get()->getJVM();
res = vm->internalUTF8ToStr(val);
return strings->addString(this, res);
}
void JnjvmBootstrapLoader::analyseClasspathEnv(const char* str) {
ClassBytes* bytes = NULL;
vmkit::ThreadAllocator threadAllocator;
if (str != 0) {
unsigned int len = strlen(str);
char* buf = (char*)threadAllocator.Allocate((len + 1) * sizeof(char));
const char* cur = str;
int top = 0;
char c = 1;
while (c != 0) {
while (((c = cur[top]) != 0) && c != Jnjvm::envSeparator[0]) {
top++;
}
if (top != 0) {
memcpy(buf, cur, top);
buf[top] = 0;
char* rp = (char*)threadAllocator.Allocate(PATH_MAX);
memset(rp, 0, PATH_MAX);
rp = realpath(buf, rp);
if (rp && rp[PATH_MAX - 1] == 0 && strlen(rp) != 0) {
struct stat st;
stat(rp, &st);
if ((st.st_mode & S_IFMT) == S_IFDIR) {
unsigned int len = strlen(rp);
char* temp = (char*)allocator.Allocate(len + 2, "Boot classpath");
memcpy(temp, rp, len);
temp[len] = Jnjvm::dirSeparator[0];
temp[len + 1] = 0;
bootClasspath.push_back(temp);
} else {
bytes = Reader::openFile(this, rp);
if (bytes) {
ZipArchive *archive = new(allocator, "ZipArchive")
ZipArchive(bytes, allocator);
if (archive) {
bootArchives.push_back(archive);
}
}
}
}
}
cur = cur + top + 1;
top = 0;
}
}
}
// constructArrayName can allocate the UTF8 directly in the classloader
// memory because it is called by safe places, ie only valid names are
// created.
const UTF8* JnjvmClassLoader::constructArrayName(uint32 steps,
const UTF8* className) {
uint32 len = className->size;
uint32 pos = steps;
bool isTab = (className->elements[0] == I_TAB ? true : false);
uint32 n = steps + len + (isTab ? 0 : 2);
vmkit::ThreadAllocator allocator;
uint16* buf = (uint16*)allocator.Allocate(n * sizeof(uint16));
for (uint32 i = 0; i < steps; i++) {
buf[i] = I_TAB;
}
if (!isTab) {
++pos;
buf[steps] = I_REF;
}
for (uint32 i = 0; i < len; i++) {
buf[pos + i] = className->elements[i];
}
if (!isTab) {
buf[n - 1] = I_END_REF;
}
const UTF8* res = readerConstructUTF8(buf, n);
return res;
}
word_t JnjvmClassLoader::loadInLib(const char* buf, bool& j3) {
// Check 'self'. Should only check our process, however it's possible native
// code dlopen'd something itself (with RTLD_GLOBAL; OpenJDK does this).
// To handle this, we search both ourselves and the libraries we loaded.
word_t sym =
(word_t)TheCompiler->loadMethod(vmkit::System::GetSelfHandle(), buf);
// Search loaded libraries as well, both as fallback and to determine
// whether or not the symbol in question is defined by vmkit.
word_t symFromLib = 0;
for (std::vector<void*>::iterator i = nativeLibs.begin(),
e = nativeLibs.end(); i!= e; ++i) {
symFromLib = (word_t)TheCompiler->loadMethod((*i), buf);
if (symFromLib) break;
}
if (sym) {
// Always use the definition from 'self', if it exists.
// Furthermore, claim it's defined in j3 iff it wasn't found in one of our
// libraries. This might be wrong if we do a lookup on a symbol that's
// neither in vmkit nor a VM-loaded library (but /is/ in a different library
// that has been dlopen'd by native code), but that should never
// be called from java code anyway.
j3 = (sym != symFromLib);
return sym;
}
// Otherwise return what we found in the libraries, if anything
if (symFromLib) return symFromLib;
if (this != bootstrapLoader)
return bootstrapLoader->loadInLib(buf, j3);
return 0;
}
void* JnjvmClassLoader::loadLib(const char* buf) {
void* handle = dlopen(buf, RTLD_LAZY | RTLD_LOCAL);
if (handle) nativeLibs.push_back(handle);
return handle;
}
char* JnjvmClassLoader::getErrorMessage() {
return dlerror();
}
word_t JnjvmClassLoader::loadInLib(const char* name, void* handle) {
return (word_t)TheCompiler->loadMethod(handle, name);
}
word_t JnjvmClassLoader::nativeLookup(JavaMethod* meth, bool& j3,
char* buf) {
// Is this method defined via registerNatives()?
// If so, use that definition.
word_t res = getRegisteredNative(meth);
if (res != 0) return res;
// Otherwise, try to resolve the method with a symbol lookup
// First as the base method
meth->jniConsFromMeth(buf);
res = loadInLib(buf, j3);
if (!res) {
// Failing that, try the overloaded symbol name
meth->jniConsFromMethOverloaded(buf);
res = loadInLib(buf, j3);
}
return res;
}
JavaString** StringList::addString(JnjvmClassLoader* JCL, JavaString* obj, bool hasTheLock) {
llvm_gcroot(obj, 0);
if (!hasTheLock)
JCL->lockForStrings.lock();
if (length == MAXIMUM_STRINGS) {
StringList* next = new(JCL->allocator, "StringList") StringList();
next->prev = this;
JCL->strings = next;
JavaString** res = next->addString(JCL, obj, true);
if (!hasTheLock)
JCL->lockForStrings.unlock();
return res;
} else {
vmkit::Collector::objectReferenceNonHeapWriteBarrier(
(gc**)&(strings[length]), (gc*)obj);
JavaString** res = &strings[length++];
if (!hasTheLock)
JCL->lockForStrings.unlock();
return res;
}
}
void JnjvmClassLoader::registerNative(JavaMethod * meth, word_t fnPtr) {
nativesLock.lock();
// Don't support multiple levels of registerNatives
assert(registeredNatives.find(meth) == registeredNatives.end());
registeredNatives[meth] = fnPtr;
nativesLock.unlock();
}
word_t JnjvmClassLoader::getRegisteredNative(const JavaMethod * meth) {
nativesLock.lock();
word_t res = registeredNatives[meth];
nativesLock.unlock();
return res;
}
ArrayObject* JnjvmBootstrapLoader::getBootPackages(Jnjvm * vm) {
ArrayObject* res = 0;
llvm_gcroot(res, 0);
lock.lock();
res = (ArrayObject*)vm->upcalls->ArrayOfString->doNew(packages.size(), vm);
std::set<const UTF8*>::const_iterator I = packages.begin(),
E = packages.end();
for (int i = 0; I != E; ++I, ++i) {
ArrayObject::setElement(res, *UTF8ToStr(*I), i);
}
lock.unlock();
return res;
}