blob: 8a914719b8021d420006673ac085554b69fa7618 [file] [log] [blame]
//===---------- Jnjvm.cpp - Java virtual machine description --------------===//
//
// JnJVM
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#define JNJVM_LOAD 0
#include <float.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "debug.h"
#include "mvm/JIT.h"
#include "mvm/Threads/Thread.h"
#include "ClasspathReflect.h"
#include "JavaArray.h"
#include "JavaClass.h"
#include "JavaConstantPool.h"
#include "JavaJIT.h"
#include "JavaString.h"
#include "JavaThread.h"
#include "JavaTypes.h"
#include "JavaUpcalls.h"
#include "Jnjvm.h"
#include "JnjvmModuleProvider.h"
#include "LockedMap.h"
#include "Reader.h"
#ifdef SERVICE_VM
#include "ServiceDomain.h"
#endif
#include "Zip.h"
using namespace jnjvm;
#define DEF_UTF8(var) \
const UTF8* Jnjvm::var = 0
DEF_UTF8(NoClassDefFoundError);
DEF_UTF8(initName);
DEF_UTF8(clinitName);
DEF_UTF8(clinitType);
DEF_UTF8(runName);
DEF_UTF8(prelib);
DEF_UTF8(postlib);
DEF_UTF8(mathName);
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);
#undef DEF_UTF8
const char* Jnjvm::dirSeparator = "/";
const char* Jnjvm::envSeparator = ":";
const unsigned int Jnjvm::Magic = 0xcafebabe;
#ifndef ISOLATE
/// If we're not in a multi-vm environment, this can be made static.
std::vector<void*> Jnjvm::nativeLibs;
JnjvmBootstrapLoader* Jnjvm::bootstrapLoader;
std::map<const char, UserClassPrimitive*> Jnjvm::primitiveMap;
#endif
typedef void (*clinit_t)(Jnjvm* vm, UserConstantPool*);
void UserCommonClass::initialiseClass(Jnjvm* vm) {
// Primitives are initialized at boot time
if (isArray()) {
status = ready;
} else if (status != ready) {
acquire();
if (status == ready) {
release();
} else if (status >= resolved && status != clinitParent &&
status != inClinit) {
UserClass* cl = (UserClass*)this;
status = clinitParent;
release();
UserCommonClass* super = getSuper();
if (super) {
super->initialiseClass(vm);
}
cl->resolveStaticClass();
status = inClinit;
UserClass* methodCl;
JavaMethod* meth = lookupMethodDontThrow(Jnjvm::clinitName,
Jnjvm::clinitType, true,
false, methodCl);
PRINT_DEBUG(JNJVM_LOAD, 0, COLOR_NORMAL, "; ", 0);
PRINT_DEBUG(JNJVM_LOAD, 0, LIGHT_GREEN, "clinit ", 0);
PRINT_DEBUG(JNJVM_LOAD, 0, COLOR_NORMAL, "%s\n", printString());
JavaObject* val =
(JavaObject*)vm->gcAllocator.allocateManagedObject(cl->getStaticSize(),
cl->getStaticVT());
val->initialise(cl);
CommonClass::field_map* map = cl->getStaticFields();
for (CommonClass::field_iterator i = map->begin(), e = map->end(); i!= e;
++i) {
i->second->initField(val, vm);
}
cl->setStaticInstance(val);
if (meth) {
JavaObject* exc = 0;
try{
clinit_t pred = (clinit_t)(intptr_t)meth->compiledPtr();
pred(vm, cl->getConstantPool());
} catch(...) {
exc = JavaThread::getJavaException();
assert(exc && "no exception?");
JavaThread::clearException();
}
if (exc) {
if (exc->classOf->isAssignableFrom(vm->upcalls->newException)) {
vm->initializerError(exc);
} else {
JavaThread::throwException(exc);
}
}
}
status = ready;
broadcastClass();
} else if (status < resolved) {
release();
vm->unknownError("try to clinit a not-read class...");
} else {
if (!ownerClass()) {
while (status < ready) waitClass();
release();
initialiseClass(vm);
}
release();
}
}
}
void Jnjvm::errorWithExcp(UserClass* cl, JavaMethod* init, const JavaObject* excp) {
JavaObject* obj = cl->doNew(this);
init->invokeIntSpecial(this, cl, obj, excp);
JavaThread::throwException(obj);
}
void Jnjvm::error(UserClass* cl, JavaMethod* init, const char* fmt, ...) {
char* tmp = (char*)alloca(4096);
va_list ap;
va_start(ap, fmt);
vsnprintf(tmp, 4096, fmt, ap);
va_end(ap);
JavaObject* obj = cl->doNew(this);
init->invokeIntSpecial(this, cl, obj, asciizToStr(tmp));
JavaThread::throwException(obj);
}
void Jnjvm::arrayStoreException() {
error(upcalls->ArrayStoreException,
upcalls->InitArrayStoreException, "");
}
void Jnjvm::indexOutOfBounds(const JavaObject* obj, sint32 entry) {
error(upcalls->ArrayIndexOutOfBoundsException,
upcalls->InitArrayIndexOutOfBoundsException, "%d", entry);
}
void Jnjvm::negativeArraySizeException(sint32 size) {
error(upcalls->NegativeArraySizeException,
upcalls->InitNegativeArraySizeException, "%d", size);
}
void Jnjvm::nullPointerException(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
char* val = va_arg(ap, char*);
va_end(ap);
error(upcalls->NullPointerException,
upcalls->InitNullPointerException, fmt, val);
}
void Jnjvm::illegalAccessException(const char* msg) {
error(upcalls->IllegalAccessException,
upcalls->InitIllegalAccessException, msg);
}
void Jnjvm::illegalMonitorStateException(const JavaObject* obj) {
error(upcalls->IllegalMonitorStateException,
upcalls->InitIllegalMonitorStateException, "");
}
void Jnjvm::interruptedException(const JavaObject* obj) {
error(upcalls->InterruptedException,
upcalls->InitInterruptedException, "");
}
void Jnjvm::initializerError(const JavaObject* excp) {
errorWithExcp(upcalls->ExceptionInInitializerError,
upcalls->ErrorWithExcpExceptionInInitializerError,
excp);
}
void Jnjvm::invocationTargetException(const JavaObject* excp) {
errorWithExcp(upcalls->InvocationTargetException,
upcalls->ErrorWithExcpInvocationTargetException,
excp);
}
void Jnjvm::outOfMemoryError(sint32 n) {
error(upcalls->OutOfMemoryError,
upcalls->InitOutOfMemoryError, "%d", n);
}
void Jnjvm::illegalArgumentExceptionForMethod(JavaMethod* meth,
UserCommonClass* required,
UserCommonClass* given) {
error(upcalls->IllegalArgumentException,
upcalls->InitIllegalArgumentException,
"for method %s", meth->printString());
}
void Jnjvm::illegalArgumentExceptionForField(JavaField* field,
UserCommonClass* required,
UserCommonClass* given) {
error(upcalls->IllegalArgumentException,
upcalls->InitIllegalArgumentException,
"for field %s", field->printString());
}
void Jnjvm::illegalArgumentException(const char* msg) {
error(upcalls->IllegalArgumentException,
upcalls->InitIllegalArgumentException,
msg);
}
void Jnjvm::classCastException(JavaObject* obj, UserCommonClass* cl) {
error(upcalls->ClassCastException,
upcalls->InitClassCastException,
"");
}
void Jnjvm::noSuchFieldError(CommonClass* cl, const UTF8* name) {
error(upcalls->NoSuchFieldError,
upcalls->InitNoSuchFieldError,
"unable to find %s in %s",
name->UTF8ToAsciiz(), cl->name->UTF8ToAsciiz());
}
void Jnjvm::noSuchMethodError(CommonClass* cl, const UTF8* name) {
error(upcalls->NoSuchMethodError,
upcalls->InitNoSuchMethodError,
"unable to find %s in %s",
name->UTF8ToAsciiz(), cl->name->UTF8ToAsciiz());
}
void Jnjvm::classFormatError(const char* msg, ...) {
error(upcalls->ClassFormatError,
upcalls->InitClassFormatError,
msg);
}
void Jnjvm::noClassDefFoundError(JavaObject* obj) {
errorWithExcp(upcalls->NoClassDefFoundError,
upcalls->ErrorWithExcpNoClassDefFoundError,
obj);
}
void Jnjvm::noClassDefFoundError(const char* fmt, ...) {
error(upcalls->NoClassDefFoundError,
upcalls->InitNoClassDefFoundError,
fmt);
}
void Jnjvm::classNotFoundException(JavaString* str) {
error(upcalls->ClassNotFoundException,
upcalls->InitClassNotFoundException,
"unable to load %s",
str->strToAsciiz());
}
void Jnjvm::unknownError(const char* fmt, ...) {
error(upcalls->UnknownError,
upcalls->InitUnknownError,
fmt);
}
JavaString* Jnjvm::internalUTF8ToStr(const UTF8* utf8) {
JavaString* res = hashStr.lookup(utf8);
if (!res) {
uint32 size = utf8->size;
UTF8* tmp = (UTF8*)upcalls->ArrayOfChar->doNew(size, this);
uint16* buf = tmp->elements;
for (uint32 i = 0; i < size; i++) {
buf[i] = utf8->elements[i];
}
const UTF8* newUTF8 = (const UTF8*)tmp;
res = hashStr.lookupOrCreate(newUTF8, this, JavaString::stringDup);
}
return res;
}
JavaString* Jnjvm::UTF8ToStr(const UTF8* utf8) {
JavaString* res = hashStr.lookupOrCreate(utf8, this, JavaString::stringDup);
return res;
}
JavaString* Jnjvm::asciizToStr(const char* asciiz) {
const UTF8* var = asciizToUTF8(asciiz);
return UTF8ToStr(var);
}
void Jnjvm::addProperty(char* key, char* value) {
postProperties.push_back(std::make_pair(key, value));
}
JavaObject* UserCommonClass::getClassDelegatee(Jnjvm* vm, JavaObject* pd) {
acquire();
if (!(delegatee)) {
UserClass* cl = vm->upcalls->newClass;
JavaObject* delegatee = cl->doNew(vm);
if (!pd) {
vm->upcalls->initClass->invokeIntSpecial(vm, cl, delegatee, this);
} else {
vm->upcalls->initClassWithProtectionDomain->invokeIntSpecial(vm, cl,
delegatee,
this, pd);
}
this->delegatee = delegatee;
}
release();
return delegatee;
}
#define PATH_MANIFEST "META-INF/MANIFEST.MF"
#define MAIN_CLASS "Main-Class: "
#define PREMAIN_CLASS "Premain-Class: "
#define BOOT_CLASS_PATH "Boot-Class-Path: "
#define CAN_REDEFINE_CLASS_PATH "Can-Redefine-Classes: "
#define LENGTH_MAIN_CLASS 12
#define LENGTH_PREMAIN_CLASS 15
#define LENGTH_BOOT_CLASS_PATH 17
extern "C" struct JNINativeInterface JNI_JNIEnvTable;
extern "C" const struct JNIInvokeInterface JNI_JavaVMTable;
namespace jnjvm {
class ClArgumentsInfo {
public:
uint32 appArgumentsPos;
char* className;
std::vector< std::pair<char*, char*> > agents;
void readArgs(int argc, char** argv, Jnjvm *vm);
void extractClassFromJar(Jnjvm* vm, int argc, char** argv, int i);
void javaAgent(char* cur);
void printInformation();
void nyi();
void printVersion();
};
}
void ClArgumentsInfo::javaAgent(char* cur) {
assert(0 && "implement me");
}
extern "C" int sys_strnstr(const char *haystack, const char *needle) {
char * res = strstr(haystack, needle);
if (res) return res - haystack;
else return -1;
}
static char* findInformation(Jnjvm* vm, ArrayUInt8* manifest, const char* entry,
uint32 len) {
uint8* ptr = manifest->elements;
sint32 index = sys_strnstr((char*)ptr, entry);
if (index != -1) {
index += len;
sint32 end = sys_strnstr((char*)&(ptr[index]), "\n");
if (end == -1) end = manifest->size;
else end += index;
sint32 length = end - index - 1;
char* name = (char*)vm->allocator.Allocate(length + 1);
memcpy(name, &(ptr[index]), length);
name[length] = 0;
return name;
} else {
return 0;
}
}
void ClArgumentsInfo::extractClassFromJar(Jnjvm* vm, int argc, char** argv,
int i) {
char* jarFile = argv[i];
uint32 size = 2 + strlen(vm->classpath) + strlen(jarFile);
char* temp = (char*)vm->allocator.Allocate(size);
sprintf(temp, "%s:%s", vm->classpath, jarFile);
vm->setClasspath(temp);
ArrayUInt8* bytes = Reader::openFile(vm->bootstrapLoader, jarFile);
ZipArchive archive(bytes, vm->allocator);
if (archive.getOfscd() != -1) {
ZipFile* file = archive.getFile(PATH_MANIFEST);
if (file) {
UserClassArray* array = vm->bootstrapLoader->upcalls->ArrayOfByte;
ArrayUInt8* res = (ArrayUInt8*)array->doNew(file->ucsize, vm);
int ok = archive.readFile(res, file);
if (ok) {
char* mainClass = findInformation(vm, res, MAIN_CLASS, LENGTH_MAIN_CLASS);
if (mainClass) {
className = mainClass;
} else {
printf("No Main-Class: in Manifest of archive %s.\n", jarFile);
}
} else {
printf("Can't extract Manifest file from archive %s\n", jarFile);
}
} else {
printf("Can't find Manifest file in archive %s\n", jarFile);
}
} else {
printf("Can't find archive %s\n", jarFile);
}
}
void ClArgumentsInfo::nyi() {
fprintf(stdout, "Not yet implemented\n");
}
void ClArgumentsInfo::printVersion() {
fprintf(stdout, "JnJVM for Java 1.1 -- 1.5\n");
}
void ClArgumentsInfo::printInformation() {
fprintf(stdout,
"Usage: java [-options] class [args...] (to execute a class)\n"
"or java [-options] -jar jarfile [args...]\n"
"(to execute a jar file) where options include:\n"
"-client to select the \"client\" VM\n"
"-server to select the \"server\" VM\n"
"-hotspot is a synonym for the \"client\" VM [deprecated]\n"
" The default VM is client.\n"
"\n"
"-cp <class search path of directories and zip/jar files>\n"
"-classpath <class search path of directories and zip/jar files>\n"
" A : separated list of directories, JAR archives,\n"
" and ZIP archives to search for class files.\n"
"-D<name>=<value>\n"
" set a system property\n"
"-verbose[:class|gc|jni]\n"
" enable verbose output\n"
"-version print product version and exit\n"
"-version:<value>\n"
" require the specified version to run\n"
"-showversion print product version and continue\n"
"-jre-restrict-search | -jre-no-restrict-search\n"
" include/exclude user private JREs in the version search\n"
"-? -help print this help message\n"
"-X print help on non-standard options\n"
"-ea[:<packagename>...|:<classname>]\n"
"-enableassertions[:<packagename>...|:<classname>]\n"
" enable assertions\n"
"-da[:<packagename>...|:<classname>]\n"
"-disableassertions[:<packagename>...|:<classname>]\n"
" disable assertions\n"
"-esa | -enablesystemassertions\n"
" enable system assertions\n"
"-dsa | -disablesystemassertions\n"
" disable system assertions\n"
"-agentlib:<libname>[=<options>]\n"
" load native agent library <libname>, e.g. -agentlib:hprof\n"
" see also, -agentlib:jdwp=help and -agentlib:hprof=help\n"
"-agentpath:<pathname>[=<options>]\n"
" load native agent library by full pathname\n"
"-javaagent:<jarpath>[=<options>]\n"
" load Java programming language agent, see java.lang.instrument\n");
}
void ClArgumentsInfo::readArgs(int argc, char** argv, Jnjvm* vm) {
className = 0;
appArgumentsPos = 0;
sint32 i = 1;
if (i == argc) printInformation();
while (i < argc) {
char* cur = argv[i];
if (!(strcmp(cur, "-client"))) {
nyi();
} else if (!(strcmp(cur, "-server"))) {
nyi();
} else if (!(strcmp(cur, "-classpath"))) {
++i;
if (i == argc) printInformation();
else vm->setClasspath(argv[i]);
} else if (!(strcmp(cur, "-cp"))) {
++i;
if (i == argc) printInformation();
else vm->setClasspath(argv[i]);
} else if (!(strcmp(cur, "-debug"))) {
nyi();
} else if (!(strncmp(cur, "-D", 2))) {
uint32 len = strlen(cur);
if (len == 2) {
printInformation();
} else {
char* key = &cur[2];
char* value = strchr(key, '=');
if (!value) {
printInformation();
return;
} else {
value[0] = 0;
vm->addProperty(key, &value[1]);
}
}
} else if (!(strncmp(cur, "-Xbootclasspath:", 16))) {
uint32 len = strlen(cur);
if (len == 16) {
printInformation();
} else {
char* path = &cur[16];
vm->bootstrapLoader->analyseClasspathEnv(path);
}
} else if (!(strcmp(cur, "-enableassertions"))) {
nyi();
} else if (!(strcmp(cur, "-ea"))) {
nyi();
} else if (!(strcmp(cur, "-disableassertions"))) {
nyi();
} else if (!(strcmp(cur, "-da"))) {
nyi();
} else if (!(strcmp(cur, "-enablesystemassertions"))) {
nyi();
} else if (!(strcmp(cur, "-esa"))) {
nyi();
} else if (!(strcmp(cur, "-disablesystemassertions"))) {
nyi();
} else if (!(strcmp(cur, "-dsa"))) {
nyi();
} else if (!(strcmp(cur, "-jar"))) {
++i;
if (i == argc) {
printInformation();
} else {
extractClassFromJar(vm, argc, argv, i);
appArgumentsPos = i;
return;
}
} else if (!(strcmp(cur, "-jre-restrict-research"))) {
nyi();
} else if (!(strcmp(cur, "-jre-no-restrict-research"))) {
nyi();
} else if (!(strcmp(cur, "-noclassgc"))) {
nyi();
} else if (!(strcmp(cur, "-ms"))) {
nyi();
} else if (!(strcmp(cur, "-mx"))) {
nyi();
} else if (!(strcmp(cur, "-ss"))) {
nyi();
} else if (!(strcmp(cur, "-verbose"))) {
nyi();
} else if (!(strcmp(cur, "-verbose:class"))) {
nyi();
} else if (!(strcmp(cur, "-verbosegc"))) {
nyi();
} else if (!(strcmp(cur, "-verbose:gc"))) {
nyi();
} else if (!(strcmp(cur, "-verbose:jni"))) {
nyi();
} else if (!(strcmp(cur, "-version"))) {
printVersion();
} else if (!(strcmp(cur, "-showversion"))) {
nyi();
} else if (!(strcmp(cur, "-?"))) {
printInformation();
} else if (!(strcmp(cur, "-help"))) {
printInformation();
} else if (!(strcmp(cur, "-X"))) {
nyi();
} else if (!(strcmp(cur, "-agentlib"))) {
nyi();
} else if (!(strcmp(cur, "-agentpath"))) {
nyi();
} else if (cur[0] == '-') {
} else if (!(strcmp(cur, "-javaagent"))) {
javaAgent(cur);
} else {
className = cur;
appArgumentsPos = i;
return;
}
++i;
}
}
void Jnjvm::print(mvm::PrintBuffer* buf) const {
buf->write("Java isolate");
}
JnjvmClassLoader* Jnjvm::loadAppClassLoader() {
if (appClassLoader == 0) {
UserClass* cl = upcalls->newClassLoader;
JavaObject* loader =
upcalls->getSystemClassLoader->invokeJavaObjectStatic(this, cl);
appClassLoader = JnjvmClassLoader::getJnjvmLoaderFromJavaObject(loader,
this);
}
return appClassLoader;
}
void Jnjvm::mapInitialThread() {
upcalls->mapInitialThread(this);
}
void Jnjvm::loadBootstrap() {
JnjvmClassLoader* loader = bootstrapLoader;
#define LOAD_CLASS(cl) \
cl->resolveClass(); \
cl->initialiseClass(this);
// If a string belongs to the vm hashmap, we must remove it when
// it's destroyed. So we change the destructor of java.lang.String
// to perform this action.
LOAD_CLASS(upcalls->newString);
uintptr_t* ptr = ((uintptr_t*)upcalls->newString->getVirtualVT());
ptr[VT_DESTRUCTOR_OFFSET] = (uintptr_t)JavaString::stringDestructor;
// To make classes non GC-allocated, we have to bypass the tracer
// functions of java.lang.Class, java.lang.reflect.Field,
// java.lang.reflect.Method and java.lang.reflect.constructor. The new
// tracer functions trace the classloader instead of the class/field/method.
LOAD_CLASS(upcalls->newClass);
ptr = ((uintptr_t*)upcalls->newClass->getVirtualVT());
ptr[VT_TRACER_OFFSET] = (uintptr_t)JavaObjectClass::staticTracer;
LOAD_CLASS(upcalls->newConstructor);
ptr = ((uintptr_t*)upcalls->newConstructor->getVirtualVT());
ptr[VT_TRACER_OFFSET] = (uintptr_t)JavaObjectConstructor::staticTracer;
LOAD_CLASS(upcalls->newMethod);
ptr = ((uintptr_t*)upcalls->newMethod->getVirtualVT());
ptr[VT_TRACER_OFFSET] = (uintptr_t)JavaObjectMethod::staticTracer;
LOAD_CLASS(upcalls->newField);
ptr = ((uintptr_t*)upcalls->newField->getVirtualVT());
ptr[VT_TRACER_OFFSET] = (uintptr_t)JavaObjectField::staticTracer;
LOAD_CLASS(upcalls->newStackTraceElement);
LOAD_CLASS(upcalls->newVMThrowable);
LOAD_CLASS(upcalls->boolClass);
LOAD_CLASS(upcalls->byteClass);
LOAD_CLASS(upcalls->charClass);
LOAD_CLASS(upcalls->shortClass);
LOAD_CLASS(upcalls->intClass);
LOAD_CLASS(upcalls->longClass);
LOAD_CLASS(upcalls->floatClass);
LOAD_CLASS(upcalls->doubleClass);
LOAD_CLASS(upcalls->InvocationTargetException);
LOAD_CLASS(upcalls->ArrayStoreException);
LOAD_CLASS(upcalls->ClassCastException);
LOAD_CLASS(upcalls->IllegalMonitorStateException);
LOAD_CLASS(upcalls->IllegalArgumentException);
LOAD_CLASS(upcalls->InterruptedException);
LOAD_CLASS(upcalls->IndexOutOfBoundsException);
LOAD_CLASS(upcalls->ArrayIndexOutOfBoundsException);
LOAD_CLASS(upcalls->NegativeArraySizeException);
LOAD_CLASS(upcalls->NullPointerException);
LOAD_CLASS(upcalls->SecurityException);
LOAD_CLASS(upcalls->ClassFormatError);
LOAD_CLASS(upcalls->ClassCircularityError);
LOAD_CLASS(upcalls->NoClassDefFoundError);
LOAD_CLASS(upcalls->UnsupportedClassVersionError);
LOAD_CLASS(upcalls->NoSuchFieldError);
LOAD_CLASS(upcalls->NoSuchMethodError);
LOAD_CLASS(upcalls->InstantiationError);
LOAD_CLASS(upcalls->IllegalAccessError);
LOAD_CLASS(upcalls->IllegalAccessException);
LOAD_CLASS(upcalls->VerifyError);
LOAD_CLASS(upcalls->ExceptionInInitializerError);
LOAD_CLASS(upcalls->LinkageError);
LOAD_CLASS(upcalls->AbstractMethodError);
LOAD_CLASS(upcalls->UnsatisfiedLinkError);
LOAD_CLASS(upcalls->InternalError);
LOAD_CLASS(upcalls->OutOfMemoryError);
LOAD_CLASS(upcalls->StackOverflowError);
LOAD_CLASS(upcalls->UnknownError);
LOAD_CLASS(upcalls->ClassNotFoundException);
#undef LOAD_CLASS
mapInitialThread();
loadAppClassLoader();
JavaObject* obj = JavaThread::currentThread();
JavaObject* javaLoader = appClassLoader->getJavaClassLoader();
upcalls->setContextClassLoader->invokeIntSpecial(this, upcalls->newThread,
obj, javaLoader);
// load and initialise math since it is responsible for dlopen'ing
// libjavalang.so and we are optimizing some math operations
UserCommonClass* math =
loader->loadName(loader->asciizConstructUTF8("java/lang/Math"), true, true);
math->initialiseClass(this);
}
void Jnjvm::executeClass(const char* className, ArrayObject* args) {
try {
JavaJIT::invokeOnceVoid(this, appClassLoader, className, "main",
"([Ljava/lang/String;)V", ACC_STATIC, args);
}catch(...) {
}
JavaObject* exc = JavaThread::get()->pendingException;
if (exc) {
JavaThread::clearException();
JavaObject* obj = JavaThread::currentThread();
JavaObject* group =
upcalls->group->getObjectField(obj);
try{
upcalls->uncaughtException->invokeIntSpecial(this, upcalls->threadGroup,
group, obj, exc);
}catch(...) {
printf("Even uncaught exception throwed an exception!\n");
assert(0);
}
}
}
void Jnjvm::executePremain(const char* className, JavaString* args,
JavaObject* instrumenter) {
JavaJIT::invokeOnceVoid(this, appClassLoader, className, "premain",
"(Ljava/lang/String;Ljava/lang/instrument/Instrumentation;)V",
ACC_STATIC, args, instrumenter);
}
void Jnjvm::waitForExit() {
threadSystem.nonDaemonLock.lock();
--(threadSystem.nonDaemonThreads);
while (threadSystem.nonDaemonThreads) {
threadSystem.nonDaemonVar.wait(&threadSystem.nonDaemonLock);
}
threadSystem.nonDaemonLock.unlock();
return;
}
void Jnjvm::runApplication(int argc, char** argv) {
ClArgumentsInfo info;
info.readArgs(argc, argv, this);
if (info.className) {
int pos = info.appArgumentsPos;
//llvm::cl::ParseCommandLineOptions(pos, argv,
// " JnJVM Java Virtual Machine\n");
argv = argv + pos - 1;
argc = argc - pos + 1;
bootstrapThread = gc_new(JavaThread)(0, this, mvm::Thread::get()->baseSP);
loadBootstrap();
#ifdef SERVICE_VM
ServiceDomain::initialise((ServiceDomain*)this);
#endif
if (info.agents.size()) {
assert(0 && "implement me");
JavaObject* instrumenter = 0;//createInstrumenter();
for (std::vector< std::pair<char*, char*> >::iterator i =
info.agents.begin(),
e = info.agents.end(); i!= e; ++i) {
JavaString* args = asciizToStr(i->second);
executePremain(i->first, args, instrumenter);
}
}
UserClassArray* array = bootstrapLoader->upcalls->ArrayOfString;
ArrayObject* args = (ArrayObject*)array->doNew(argc - 2, this);
for (int i = 2; i < argc; ++i) {
args->elements[i - 2] = (JavaObject*)asciizToStr(argv[i]);
}
executeClass(info.className, args);
waitForExit();
}
}
Jnjvm::Jnjvm(uint32 memLimit) {
classpath = getenv("CLASSPATH");
if (!classpath) classpath = ".";
appClassLoader = 0;
jniEnv = &JNI_JNIEnvTable;
javavmEnv = &JNI_JavaVMTable;
#ifdef ISOLATE_SHARING
initialiseStatics();
#endif
upcalls = bootstrapLoader->upcalls;
#ifdef ISOLATE_SHARING
throwable = upcalls->newThrowable;
#endif
arrayClasses[JavaArray::T_BOOLEAN - 4] = upcalls->ArrayOfBool;
arrayClasses[JavaArray::T_BYTE - 4] = upcalls->ArrayOfByte;
arrayClasses[JavaArray::T_CHAR - 4] = upcalls->ArrayOfChar;
arrayClasses[JavaArray::T_SHORT - 4] = upcalls->ArrayOfShort;
arrayClasses[JavaArray::T_INT - 4] = upcalls->ArrayOfInt;
arrayClasses[JavaArray::T_FLOAT - 4] = upcalls->ArrayOfFloat;
arrayClasses[JavaArray::T_LONG - 4] = upcalls->ArrayOfLong;
arrayClasses[JavaArray::T_DOUBLE - 4] = upcalls->ArrayOfDouble;
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;
upcalls->initialiseClasspath(bootstrapLoader);
}
const UTF8* Jnjvm::asciizToInternalUTF8(const char* asciiz) {
uint32 size = strlen(asciiz);
UTF8* tmp = (UTF8*)upcalls->ArrayOfChar->doNew(size, this);
uint16* buf = tmp->elements;
for (uint32 i = 0; i < size; i++) {
if (asciiz[i] == '.') buf[i] = '/';
else buf[i] = asciiz[i];
}
return (const UTF8*)tmp;
}
const UTF8* Jnjvm::asciizToUTF8(const char* asciiz) {
uint32 size = strlen(asciiz);
UTF8* tmp = (UTF8*)upcalls->ArrayOfChar->doNew(size, this);
uint16* buf = tmp->elements;
for (uint32 i = 0; i < size; i++) {
buf[i] = asciiz[i];
}
return (const UTF8*)tmp;
}