blob: f48a4daf9d54a6da919b5b62e94145aa387e45af [file] [log] [blame]
//===-- JnjvmClassLoader.cpp - Jnjvm representation of a class loader ------===//
//
// Jnjvm
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <limits.h>
#include <unistd.h>
#include <sys/stat.h>
#include "debug.h"
#include "JavaAllocator.h"
#include "JavaClass.h"
#include "JavaConstantPool.h"
#include "JavaThread.h"
#include "JavaUpcalls.h"
#include "Jnjvm.h"
#include "JnjvmClassLoader.h"
#include "JnjvmModule.h"
#include "JnjvmModuleProvider.h"
#include "LockedMap.h"
#include "Reader.h"
using namespace jnjvm;
#ifndef MULTIPLE_VM
JnjvmBootstrapLoader* JnjvmClassLoader::bootstrapLoader = 0;
UserClass* JnjvmBootstrapLoader::SuperArray = 0;
std::vector<UserClass*> JnjvmBootstrapLoader::InterfacesArray;
#endif
extern const char* GNUClasspathGlibj;
extern const char* GNUClasspathLibs;
JnjvmBootstrapLoader* JnjvmBootstrapLoader::createBootstrapLoader() {
JnjvmBootstrapLoader* JCL = gc_new(JnjvmBootstrapLoader)();
JCL->TheModule = new JnjvmModule("Bootstrap JnJVM");
JCL->TheModuleProvider = new JnjvmModuleProvider(JCL->TheModule);
JCL->TheModule->initialise();
JCL->allocator = new JavaAllocator();
JCL->hashUTF8 = new UTF8Map(JCL->allocator, 0);
JCL->classes = allocator_new(allocator, ClassMap)();
JCL->javaTypes = new TypeMap();
JCL->javaSignatures = new SignMap();
JCL->bootClasspathEnv = getenv("JNJVM_BOOTCLASSPATH");
if (!JCL->bootClasspathEnv) {
JCL->bootClasspathEnv = GNUClasspathGlibj;
}
JCL->libClasspathEnv = getenv("JNJVM_LIBCLASSPATH");
if (!JCL->libClasspathEnv) {
JCL->libClasspathEnv = GNUClasspathLibs;
}
JCL->analyseClasspathEnv(JCL->bootClasspathEnv);
JCL->upcalls = new Classpath();
JCL->bootstrapLoader = JCL;
return JCL;
}
JnjvmClassLoader::JnjvmClassLoader(JnjvmClassLoader& JCL, JavaObject* loader,
Jnjvm* I) {
TheModule = JCL.TheModule;
TheModuleProvider = JCL.TheModuleProvider;
bootstrapLoader = JCL.bootstrapLoader;
allocator = &(isolate->allocator);
hashUTF8 = JCL.hashUTF8;
classes = allocator_new(allocator, ClassMap)();
javaTypes = JCL.javaTypes;
javaSignatures = JCL.javaSignatures;
javaLoader = loader;
isolate = I;
#ifdef MULTIPLE_VM
JavaMethod* meth = bootstrapLoader->upcalls->loadInClassLoader;
loader->classOf->lookupMethodDontThrow(meth->name, meth->type, false, true,
loadClass);
assert(loadClass && "Loader does not have a loadClass function");
#endif
}
ArrayUInt8* JnjvmBootstrapLoader::openName(const UTF8* utf8) {
char* asciiz = utf8->UTF8ToAsciiz();
uint32 alen = strlen(asciiz);
ArrayUInt8* res = 0;
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*)alloca(strLen + alen + 7);
sprintf(buf, "%s%s.class", str, asciiz);
res = Reader::openFile(this, buf);
if (res) return res;
}
for (std::vector<ZipArchive*>::iterator i = bootArchives.begin(),
e = bootArchives.end(); i != e; ++i) {
ZipArchive* archive = *i;
char* buf = (char*)alloca(alen + 7);
sprintf(buf, "%s.class", asciiz);
res = Reader::openZip(this, archive, buf);
if (res) return res;
}
return 0;
}
UserClass* JnjvmBootstrapLoader::internalLoad(const UTF8* name) {
UserCommonClass* cl = lookupClass(name);
if (!cl) {
ArrayUInt8* bytes = openName(name);
if (bytes) {
cl = constructClass(name, bytes);
}
}
if (cl) assert(!cl->isArray());
return (UserClass*)cl;
}
UserClass* JnjvmClassLoader::internalLoad(const UTF8* name) {
UserCommonClass* cl = lookupClass(name);
if (!cl) {
const UTF8* javaName = name->internalToJava(hashUTF8, 0, name->size);
JavaString* str = isolate->UTF8ToStr(javaName);
Classpath* upcalls = bootstrapLoader->upcalls;
UserClass* forCtp = 0;
#ifdef MULTIPLE_VM
forCtp = loadClass;
#else
forCtp = upcalls->loadInClassLoader->classDef;
#endif
JavaObject* obj = (JavaObject*)
upcalls->loadInClassLoader->invokeJavaObjectVirtual(isolate, forCtp,
javaLoader, str);
cl = (UserCommonClass*)(upcalls->vmdataClass->getObjectField(obj));
}
if (cl) assert(!cl->isArray());
return (UserClass*)cl;
}
UserClass* JnjvmClassLoader::loadName(const UTF8* name, bool doResolve,
bool doThrow) {
UserClass* cl = internalLoad(name);
if (!cl && doThrow) {
if (!(name->equals(Jnjvm::NoClassDefFoundError))) {
JavaThread::get()->isolate->unknownError("Unable to load NoClassDefFoundError");
}
JavaThread::get()->isolate->noClassDefFoundError("unable to load %s", name->printString());
}
if (cl && doResolve) cl->resolveClass();
return cl;
}
UserCommonClass* JnjvmClassLoader::lookupClassFromUTF8(const UTF8* name,
bool doResolve,
bool doThrow) {
uint32 len = name->size;
uint32 start = 0;
uint32 origLen = len;
bool doLoop = true;
UserCommonClass* ret = 0;
if (len == 0) {
return 0;
} else if (name->elements[0] == I_TAB) {
while (doLoop) {
--len;
if (len == 0) {
doLoop = false;
} 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)) {
doLoop = false;
} else {
const UTF8* componentName = name->javaToInternal(hashUTF8,
start + 1,
len - 2);
if (loadName(componentName, doResolve, doThrow)) {
ret = constructArray(name);
if (doResolve) ret->resolveClass();
doLoop = false;
} else {
doLoop = false;
}
}
} 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) {
ret = constructArray(name);
ret->resolveClass();
doLoop = false;
} else {
doLoop = false;
}
}
}
}
}
return ret;
} else {
return loadName(name, doResolve, doThrow);
}
}
UserCommonClass* JnjvmClassLoader::lookupClassFromJavaString(JavaString* str,
bool doResolve, bool doThrow) {
const UTF8* name = 0;
if (str->value->elements[str->offset] != I_TAB)
name = str->value->checkedJavaToInternal(hashUTF8, str->offset,
str->count);
else
name = str->value->javaToInternal(hashUTF8, str->offset, str->count);
if (name)
return lookupClassFromUTF8(name, doResolve, doThrow);
return 0;
}
UserCommonClass* JnjvmClassLoader::lookupClass(const UTF8* utf8) {
return classes->lookup(utf8);
}
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);
} else if (name->elements[start] == I_REF) {
const UTF8* componentName = name->extract(hashUTF8,
start + 1, start + len - 1);
UserCommonClass* cl = loadName(componentName, false, true);
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) {
UserCommonClass* cl = loadBaseClass(name, 1, name->size - 1);
assert(cl && "no base class for an array");
JnjvmClassLoader* ld = cl->classLoader;
return ld->constructArray(name, cl);
}
UserClass* JnjvmClassLoader::constructClass(const UTF8* name, ArrayUInt8* bytes) {
assert(bytes && "constructing a class without bytes");
classes->lock->lock();
ClassMap::iterator End = classes->map.end();
ClassMap::iterator I = classes->map.find(name);
UserClass* res = 0;
if (I == End) {
res = allocator_new(allocator, UserClass)(this, name, bytes);
classes->map.insert(std::make_pair(name, res));
} else {
res = ((UserClass*)(I->second));
}
classes->lock->unlock();
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");
classes->lock->lock();
ClassMap::iterator End = classes->map.end();
ClassMap::iterator I = classes->map.find(name);
UserClassArray* res = 0;
if (I == End) {
res = allocator_new(allocator, UserClassArray)(this, name, baseClass);
classes->map.insert(std::make_pair(name, res));
} else {
res = ((UserClassArray*)(I->second));
}
classes->lock->unlock();
return res;
}
Typedef* JnjvmClassLoader::constructType(const UTF8* name) {
Typedef* res = javaTypes->lookup(name);
if (res == 0) {
res = Typedef::constructType(name, hashUTF8, isolate);
javaTypes->lock->lock();
Typedef* tmp = javaTypes->lookup(name);
if (tmp == 0) javaTypes->hash(name, res);
else {
delete res;
res = tmp;
}
javaTypes->lock->unlock();
}
return res;
}
Signdef* JnjvmClassLoader::constructSign(const UTF8* name) {
Signdef* res = javaSignatures->lookup(name);
if (res == 0) {
res = new Signdef(name, this);
javaSignatures->lock->lock();
Signdef* tmp = javaSignatures->lookup(name);
if (tmp == 0) javaSignatures->hash(name, res);
else {
delete res;
res = tmp;
}
javaSignatures->lock->unlock();
}
return res;
}
JnjvmClassLoader* JnjvmClassLoader::getJnjvmLoaderFromJavaObject(JavaObject* loader, Jnjvm* vm) {
if (loader == 0)
return vm->bootstrapLoader;
Classpath* upcalls = vm->bootstrapLoader->upcalls;
JnjvmClassLoader* JCL =
(JnjvmClassLoader*)(upcalls->vmdataClassLoader->getObjectField(loader));
if (!JCL) {
JCL = gc_new(JnjvmClassLoader)(*vm->bootstrapLoader, loader, JavaThread::get()->isolate);
(upcalls->vmdataClassLoader->setObjectField(loader, (JavaObject*)JCL));
}
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() {
/*delete hashUTF8;
delete javaTypes;
delete javaSignatures;
delete TheModuleProvider;*/
}
void JnjvmBootstrapLoader::analyseClasspathEnv(const char* str) {
if (str != 0) {
unsigned int len = strlen(str);
char* buf = (char*)alloca(len + 1);
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*)alloca(PATH_MAX);
memset(rp, 0, PATH_MAX);
rp = realpath(buf, rp);
if (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*)malloc(len + 2);
memcpy(temp, rp, len);
temp[len] = Jnjvm::dirSeparator[0];
temp[len + 1] = 0;
bootClasspath.push_back(temp);
} else {
ArrayUInt8* bytes =
Reader::openFile(this, rp);
if (bytes) {
ZipArchive *archive = new ZipArchive(bytes);
if (archive) {
bootArchives.push_back(archive);
}
}
}
}
}
cur = cur + top + 1;
top = 0;
}
}
}
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);
uint16* buf = (uint16*)alloca(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;
}
return readerConstructUTF8(buf, n);
}