| //===---------- Jnjvm.cpp - Java virtual machine description --------------===// |
| // |
| // The VMKit project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #define JNJVM_LOAD 0 |
| |
| #include <cfloat> |
| #include <climits> |
| #include <cstdarg> |
| #include <cstdio> |
| #include <cstdlib> |
| #include <cstring> |
| #include <string> |
| #include "debug.h" |
| |
| #include "mvm/Threads/Thread.h" |
| #include "MvmGC.h" |
| |
| #include "ClasspathReflect.h" |
| #include "JavaArray.h" |
| #include "JavaClass.h" |
| #include "JavaCompiler.h" |
| #include "JavaConstantPool.h" |
| #include "JavaString.h" |
| #include "JavaThread.h" |
| #include "JavaTypes.h" |
| #include "JavaUpcalls.h" |
| #include "Jnjvm.h" |
| #include "LinkJavaRuntime.h" |
| #include "LockedMap.h" |
| #include "Reader.h" |
| #include "Zip.h" |
| |
| using namespace j3; |
| |
| const char* Jnjvm::dirSeparator = "/"; |
| const char* Jnjvm::envSeparator = ":"; |
| const unsigned int Jnjvm::Magic = 0xcafebabe; |
| |
| #ifdef ISOLATE |
| Jnjvm* Jnjvm::RunningIsolates[NR_ISOLATES]; |
| mvm::LockNormal Jnjvm::IsolateLock; |
| #endif |
| |
| |
| /// initialiseClass - Java class initialisation. Java specification §2.17.5. |
| |
| void UserClass::initialiseClass(Jnjvm* vm) { |
| |
| // Primitives are initialized at boot time, arrays are initialized directly. |
| |
| // Assumes that the Class object has already been verified and prepared and |
| // that the Class object contains state that can indicate one of four |
| // situations: |
| // |
| // * This Class object is verified and prepared but not initialized. |
| // * This Class object is being initialized by some particular thread T. |
| // * This Class object is fully initialized and ready for use. |
| // * This Class object is in an erroneous state, perhaps because the |
| // verification step failed or because initialization was attempted and |
| // failed. |
| |
| assert((isResolved() || getOwnerClass() || isReady() || |
| isErroneous()) && "Class in wrong state"); |
| |
| if (getInitializationState() != ready) { |
| |
| // 1. Synchronize on the Class object that represents the class or |
| // interface to be initialized. This involves waiting until the |
| // current thread can obtain the lock for that object |
| // (Java specification §8.13). |
| acquire(); |
| JavaThread* self = JavaThread::get(); |
| |
| if (getInitializationState() == inClinit) { |
| // 2. If initialization by some other thread is in progress for the |
| // class or interface, then wait on this Class object (which |
| // temporarily releases the lock). When the current thread awakens |
| // from the wait, repeat this step. |
| if (getOwnerClass() != self) { |
| while (getOwnerClass()) { |
| waitClass(); |
| } |
| } else { |
| // 3. If initialization is in progress for the class or interface by |
| // the current thread, then this must be a recursive request for |
| // initialization. Release the lock on the Class object and complete |
| // normally. |
| release(); |
| return; |
| } |
| } |
| |
| // 4. If the class or interface has already been initialized, then no |
| // further action is required. Release the lock on the Class object |
| // and complete normally. |
| if (getInitializationState() == ready) { |
| release(); |
| return; |
| } |
| |
| // 5. If the Class object is in an erroneous state, then initialization is |
| // not possible. Release the lock on the Class object and throw a |
| // NoClassDefFoundError. |
| if (isErroneous()) { |
| release(); |
| vm->noClassDefFoundError(name); |
| } |
| |
| // 6. Otherwise, record the fact that initialization of the Class object is |
| // now in progress by the current thread and release the lock on the |
| // Class object. |
| setOwnerClass(self); |
| bool vmjced = (getInitializationState() == vmjc); |
| setInitializationState(inClinit); |
| UserClass* cl = (UserClass*)this; |
| #if defined(ISOLATE) || defined(ISOLATE_SHARING) |
| // Isolate environments allocate the static instance on their own, not when |
| // the class is being resolved. |
| cl->allocateStaticInstance(vm); |
| #else |
| // Single environment allocates the static instance during resolution, so |
| // that compiled code can access it directly (with an initialization |
| // check just before the access) |
| if (!cl->getStaticInstance()) cl->allocateStaticInstance(vm); |
| #endif |
| release(); |
| |
| |
| // 7. Next, if the Class object represents a class rather than an interface, |
| // and the direct superclass of this class has not yet been initialized, |
| // then recursively perform this entire procedure for the uninitialized |
| // superclass. If the initialization of the direct superclass completes |
| // abruptly because of a thrown exception, then lock this Class object, |
| // label it erroneous, notify all waiting threads, release the lock, |
| // and complete abruptly, throwing the same exception that resulted from |
| // the initializing the superclass. |
| UserClass* super = getSuper(); |
| if (super) { |
| TRY { |
| super->initialiseClass(vm); |
| } CATCH { |
| acquire(); |
| setErroneous(); |
| setOwnerClass(0); |
| broadcastClass(); |
| release(); |
| } END_CATCH; |
| if (self->pendingException != NULL) { |
| self->throwPendingException(); |
| return; |
| } |
| } |
| |
| JavaObject* exc = 0; |
| JavaObject* obj = 0; |
| llvm_gcroot(exc, 0); |
| llvm_gcroot(obj, 0); |
| #ifdef SERVICE |
| if (classLoader == classLoader->bootstrapLoader || |
| classLoader->getIsolate() == vm) { |
| #endif |
| |
| // 8. Next, execute either the class variable initializers and static |
| // initializers of the class or the field initializers of the interface, |
| // in textual order, as though they were a single block, except that |
| // final static variables and fields of interfaces whose values are |
| // compile-time constants are initialized first. |
| |
| 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", mvm::PrintString(this).cString()); |
| |
| |
| |
| if (!vmjced) { |
| JavaField* fields = cl->getStaticFields(); |
| void* val = cl->getStaticInstance(); |
| for (uint32 i = 0; i < cl->nbStaticFields; ++i) { |
| fields[i].initField(val, vm); |
| } |
| } |
| |
| |
| |
| JavaMethod* meth = lookupMethodDontThrow(vm->bootstrapLoader->clinitName, |
| vm->bootstrapLoader->clinitType, |
| true, false, 0); |
| |
| if (meth) { |
| TRY { |
| meth->invokeIntStatic(vm, cl); |
| } CATCH { |
| exc = self->getJavaException(); |
| assert(exc && "no exception?"); |
| self->clearException(); |
| } END_CATCH; |
| } |
| #ifdef SERVICE |
| } |
| #endif |
| |
| // 9. If the execution of the initializers completes normally, then lock |
| // this Class object, label it fully initialized, notify all waiting |
| // threads, release the lock, and complete this procedure normally. |
| if (!exc) { |
| acquire(); |
| setInitializationState(ready); |
| setOwnerClass(0); |
| broadcastClass(); |
| release(); |
| return; |
| } |
| |
| // 10. Otherwise, the initializers must have completed abruptly by |
| // throwing some exception E. If the class of E is not Error or one |
| // of its subclasses, then create a new instance of the class |
| // ExceptionInInitializerError, with E as the argument, and use this |
| // object in place of E in the following step. But if a new instance of |
| // ExceptionInInitializerError cannot be created because an |
| // OutOfMemoryError occurs, then instead use an OutOfMemoryError object |
| // in place of E in the following step. |
| if (exc->getClass()->isAssignableFrom(vm->upcalls->newException)) { |
| Classpath* upcalls = classLoader->bootstrapLoader->upcalls; |
| UserClass* clExcp = upcalls->ExceptionInInitializerError; |
| Jnjvm* vm = self->getJVM(); |
| obj = clExcp->doNew(vm); |
| if (!obj) { |
| fprintf(stderr, "implement me"); |
| abort(); |
| } |
| JavaMethod* init = upcalls->ErrorWithExcpExceptionInInitializerError; |
| init->invokeIntSpecial(vm, clExcp, obj, &exc); |
| exc = obj; |
| } |
| |
| // 11. Lock the Class object, label it erroneous, notify all waiting |
| // threads, release the lock, and complete this procedure abruptly |
| // with reason E or its replacement as determined in the previous step. |
| acquire(); |
| setErroneous(); |
| setOwnerClass(0); |
| broadcastClass(); |
| release(); |
| self->throwException(exc); |
| return; |
| } |
| } |
| |
| void Jnjvm::errorWithExcp(UserClass* cl, JavaMethod* init, |
| const JavaObject* excp) { |
| JavaObject* obj = cl->doNew(this); |
| llvm_gcroot(obj, 0); |
| init->invokeIntSpecial(this, cl, obj, &excp); |
| JavaThread::get()->throwException(obj); |
| } |
| |
| JavaObject* Jnjvm::CreateError(UserClass* cl, JavaMethod* init, |
| const char* asciiz) { |
| JavaObject* obj = cl->doNew(this); |
| JavaString* str = 0; |
| llvm_gcroot(obj, 0); |
| llvm_gcroot(str, 0); |
| if (asciiz) str = asciizToStr(asciiz); |
| |
| init->invokeIntSpecial(this, cl, obj, &str); |
| return obj; |
| } |
| |
| JavaObject* Jnjvm::CreateError(UserClass* cl, JavaMethod* init, |
| JavaString* str) { |
| JavaObject* obj = 0; |
| llvm_gcroot(str, 0); |
| llvm_gcroot(obj, 0); |
| obj = cl->doNew(this); |
| init->invokeIntSpecial(this, cl, obj, &str); |
| return obj; |
| } |
| |
| void Jnjvm::error(UserClass* cl, JavaMethod* init, JavaString* str) { |
| JavaObject* obj = 0; |
| llvm_gcroot(obj, 0); |
| llvm_gcroot(str, 0); |
| obj = CreateError(cl, init, str); |
| JavaThread::get()->throwException(obj); |
| } |
| |
| void Jnjvm::arrayStoreException() { |
| error(upcalls->ArrayStoreException, |
| upcalls->InitArrayStoreException, (JavaString*)0); |
| } |
| |
| void Jnjvm::indexOutOfBounds(const JavaObject* obj, sint32 entry) { |
| JavaString* str = (JavaString*) |
| upcalls->IntToString->invokeJavaObjectStatic(this, upcalls->intClass, |
| entry, 10); |
| llvm_gcroot(str, 0); |
| error(upcalls->ArrayIndexOutOfBoundsException, |
| upcalls->InitArrayIndexOutOfBoundsException, str); |
| } |
| |
| void Jnjvm::negativeArraySizeException(sint32 size) { |
| JavaString* str = (JavaString*) |
| upcalls->IntToString->invokeJavaObjectStatic(this, upcalls->intClass, |
| size, 10); |
| llvm_gcroot(str, 0); |
| error(upcalls->NegativeArraySizeException, |
| upcalls->InitNegativeArraySizeException, str); |
| } |
| |
| void Jnjvm::nullPointerException() { |
| error(upcalls->NullPointerException, |
| upcalls->InitNullPointerException, (JavaString*)0); |
| } |
| |
| JavaObject* Jnjvm::CreateIndexOutOfBoundsException(sint32 entry) { |
| JavaString* str = (JavaString*) |
| upcalls->IntToString->invokeJavaObjectStatic(this, upcalls->intClass, |
| entry, 10); |
| llvm_gcroot(str, 0); |
| return CreateError(upcalls->ArrayIndexOutOfBoundsException, |
| upcalls->InitArrayIndexOutOfBoundsException, str); |
| } |
| |
| JavaObject* Jnjvm::CreateNegativeArraySizeException() { |
| return CreateError(upcalls->NegativeArraySizeException, |
| upcalls->InitNegativeArraySizeException, |
| (JavaString*)0); |
| } |
| |
| JavaObject* Jnjvm::CreateUnsatisfiedLinkError(JavaMethod* meth) { |
| JavaString* str = constructString(meth->toString()); |
| llvm_gcroot(str, 0); |
| return CreateError(upcalls->UnsatisfiedLinkError, |
| upcalls->InitUnsatisfiedLinkError, |
| str); |
| } |
| |
| JavaObject* Jnjvm::CreateArithmeticException() { |
| JavaString* str = asciizToStr("/ by zero"); |
| llvm_gcroot(str, 0); |
| return CreateError(upcalls->ArithmeticException, |
| upcalls->InitArithmeticException, str); |
| } |
| |
| JavaObject* Jnjvm::CreateNullPointerException() { |
| return CreateError(upcalls->NullPointerException, |
| upcalls->InitNullPointerException, |
| (JavaString*)0); |
| } |
| |
| JavaObject* Jnjvm::CreateOutOfMemoryError() { |
| JavaString* str = asciizToStr("Java heap space"); |
| llvm_gcroot(str, 0); |
| return CreateError(upcalls->OutOfMemoryError, |
| upcalls->InitOutOfMemoryError, str); |
| } |
| |
| JavaObject* Jnjvm::CreateStackOverflowError() { |
| // Don't call init, or else we'll get a new stack overflow error. |
| JavaObject* obj = upcalls->StackOverflowError->doNew(this); |
| llvm_gcroot(obj, 0); |
| ((JavaObjectThrowable*)obj)->fillInStackTrace(); |
| return obj; |
| } |
| |
| JavaObject* Jnjvm::CreateArrayStoreException(JavaVirtualTable* VT) { |
| JavaString* str = VT ? JavaString::internalToJava(VT->cl->name, this) : NULL; |
| llvm_gcroot(str, 0); |
| return CreateError(upcalls->ArrayStoreException, |
| upcalls->InitArrayStoreException, str); |
| } |
| |
| JavaObject* Jnjvm::CreateClassCastException(JavaObject* obj, |
| UserCommonClass* cl) { |
| llvm_gcroot(obj, 0); |
| return CreateError(upcalls->ClassCastException, |
| upcalls->InitClassCastException, |
| (JavaString*)0); |
| } |
| |
| JavaObject* Jnjvm::CreateLinkageError(const char* msg) { |
| JavaString* str = asciizToStr(msg); |
| llvm_gcroot(str, 0); |
| return CreateError(upcalls->LinkageError, |
| upcalls->InitLinkageError, str); |
| } |
| |
| void Jnjvm::illegalAccessException(const char* msg) { |
| JavaString* str = asciizToStr(msg); |
| llvm_gcroot(str, 0); |
| error(upcalls->IllegalAccessException, |
| upcalls->InitIllegalAccessException, str); |
| } |
| |
| void Jnjvm::illegalMonitorStateException(const JavaObject* obj) { |
| llvm_gcroot(obj, 0); |
| error(upcalls->IllegalMonitorStateException, |
| upcalls->InitIllegalMonitorStateException, |
| (JavaString*)0); |
| } |
| |
| void Jnjvm::interruptedException(const JavaObject* obj) { |
| llvm_gcroot(obj, 0); |
| error(upcalls->InterruptedException, |
| upcalls->InitInterruptedException, |
| (JavaString*)0); |
| } |
| |
| |
| void Jnjvm::initializerError(const JavaObject* excp) { |
| llvm_gcroot(excp, 0); |
| errorWithExcp(upcalls->ExceptionInInitializerError, |
| upcalls->ErrorWithExcpExceptionInInitializerError, |
| excp); |
| } |
| |
| void Jnjvm::invocationTargetException(const JavaObject* excp) { |
| llvm_gcroot(excp, 0); |
| errorWithExcp(upcalls->InvocationTargetException, |
| upcalls->ErrorWithExcpInvocationTargetException, |
| excp); |
| } |
| |
| void Jnjvm::outOfMemoryError() { |
| JavaString* str = asciizToStr("Java heap space"); |
| llvm_gcroot(str, 0); |
| error(upcalls->OutOfMemoryError, |
| upcalls->InitOutOfMemoryError, str); |
| } |
| |
| void Jnjvm::illegalArgumentException(const char* msg) { |
| JavaString* str = asciizToStr(msg); |
| llvm_gcroot(str, 0); |
| error(upcalls->IllegalArgumentException, |
| upcalls->InitIllegalArgumentException, str); |
| } |
| |
| void Jnjvm::classCastException(JavaObject* obj, UserCommonClass* cl) { |
| llvm_gcroot(obj, 0); |
| error(upcalls->ClassCastException, |
| upcalls->InitClassCastException, |
| (JavaString*)0); |
| } |
| |
| void Jnjvm::noClassDefFoundError(JavaObject* obj) { |
| llvm_gcroot(obj, 0); |
| errorWithExcp(upcalls->NoClassDefFoundError, |
| upcalls->ErrorWithExcpNoClassDefFoundError, |
| obj); |
| } |
| |
| void Jnjvm::instantiationException(UserCommonClass* cl) { |
| JavaString* str = internalUTF8ToStr(cl->name); |
| llvm_gcroot(str, 0); |
| error(upcalls->InstantiationException, upcalls->InitInstantiationException, |
| str); |
| } |
| |
| void Jnjvm::instantiationError(UserCommonClass* cl) { |
| JavaString* str = internalUTF8ToStr(cl->name); |
| llvm_gcroot(str, 0); |
| error(upcalls->InstantiationError, upcalls->InitInstantiationError, str); |
| } |
| |
| |
| static JavaString* CreateNoSuchMsg(CommonClass* cl, const UTF8* name, |
| Jnjvm* vm) { |
| ArrayUInt16* msg = (ArrayUInt16*) |
| vm->upcalls->ArrayOfChar->doNew(19 + cl->name->size + name->size, vm); |
| JavaString* str = 0; |
| llvm_gcroot(msg, 0); |
| llvm_gcroot(str, 0); |
| |
| uint32 i = 0; |
| |
| |
| msg->elements[i++] = 'u'; |
| msg->elements[i++] = 'n'; |
| msg->elements[i++] = 'a'; |
| msg->elements[i++] = 'b'; |
| msg->elements[i++] = 'l'; |
| msg->elements[i++] = 'e'; |
| msg->elements[i++] = ' '; |
| msg->elements[i++] = 't'; |
| msg->elements[i++] = 'o'; |
| msg->elements[i++] = ' '; |
| msg->elements[i++] = 'f'; |
| msg->elements[i++] = 'i'; |
| msg->elements[i++] = 'n'; |
| msg->elements[i++] = 'd'; |
| msg->elements[i++] = ' '; |
| |
| for (sint32 j = 0; j < name->size; ++j) |
| msg->elements[i++] = name->elements[j]; |
| |
| msg->elements[i++] = ' '; |
| msg->elements[i++] = 'i'; |
| msg->elements[i++] = 'n'; |
| msg->elements[i++] = ' '; |
| |
| for (sint32 j = 0; j < cl->name->size; ++j) { |
| if (cl->name->elements[j] == '/') msg->elements[i++] = '.'; |
| else msg->elements[i++] = cl->name->elements[j]; |
| } |
| |
| str = vm->constructString(msg); |
| |
| return str; |
| } |
| |
| void Jnjvm::noSuchFieldError(CommonClass* cl, const UTF8* name) { |
| JavaString* str = CreateNoSuchMsg(cl, name, this); |
| llvm_gcroot(str, 0); |
| error(upcalls->NoSuchFieldError, |
| upcalls->InitNoSuchFieldError, str); |
| } |
| |
| void Jnjvm::noSuchMethodError(CommonClass* cl, const UTF8* name) { |
| JavaString* str = CreateNoSuchMsg(cl, name, this); |
| llvm_gcroot(str, 0); |
| error(upcalls->NoSuchMethodError, |
| upcalls->InitNoSuchMethodError, str); |
| } |
| |
| void Jnjvm::abstractMethodError(CommonClass* cl, const UTF8* name) { |
| JavaString* str = CreateNoSuchMsg(cl, name, this); |
| llvm_gcroot(str, 0); |
| error(upcalls->AbstractMethodError, |
| upcalls->InitAbstractMethodError, str); |
| } |
| |
| static JavaString* CreateUnableToLoad(const UTF8* name, Jnjvm* vm) { |
| ArrayUInt16* msg = (ArrayUInt16*) |
| vm->upcalls->ArrayOfChar->doNew(15 + name->size, vm); |
| JavaString* str = 0; |
| llvm_gcroot(msg, 0); |
| llvm_gcroot(str, 0); |
| uint32 i = 0; |
| |
| |
| msg->elements[i++] = 'u'; |
| msg->elements[i++] = 'n'; |
| msg->elements[i++] = 'a'; |
| msg->elements[i++] = 'b'; |
| msg->elements[i++] = 'l'; |
| msg->elements[i++] = 'e'; |
| msg->elements[i++] = ' '; |
| msg->elements[i++] = 't'; |
| msg->elements[i++] = 'o'; |
| msg->elements[i++] = ' '; |
| msg->elements[i++] = 'l'; |
| msg->elements[i++] = 'o'; |
| msg->elements[i++] = 'a'; |
| msg->elements[i++] = 'd'; |
| msg->elements[i++] = ' '; |
| |
| for (sint32 j = 0; j < name->size; ++j) { |
| if (name->elements[j] == '/') msg->elements[i++] = '.'; |
| else msg->elements[i++] = name->elements[j]; |
| } |
| |
| str = vm->constructString(msg); |
| |
| return str; |
| } |
| |
| static JavaString* CreateUnableToLoad(JavaString* name, Jnjvm* vm) { |
| JavaString* str = 0; |
| ArrayUInt16* msg = (ArrayUInt16*) |
| vm->upcalls->ArrayOfChar->doNew(15 + name->count, vm); |
| llvm_gcroot(msg, 0); |
| llvm_gcroot(str, 0); |
| uint32 i = 0; |
| |
| |
| msg->elements[i++] = 'u'; |
| msg->elements[i++] = 'n'; |
| msg->elements[i++] = 'a'; |
| msg->elements[i++] = 'b'; |
| msg->elements[i++] = 'l'; |
| msg->elements[i++] = 'e'; |
| msg->elements[i++] = ' '; |
| msg->elements[i++] = 't'; |
| msg->elements[i++] = 'o'; |
| msg->elements[i++] = ' '; |
| msg->elements[i++] = 'l'; |
| msg->elements[i++] = 'o'; |
| msg->elements[i++] = 'a'; |
| msg->elements[i++] = 'd'; |
| msg->elements[i++] = ' '; |
| |
| for (sint32 j = name->offset; j < name->offset + name->count; ++j) { |
| if (name->value->elements[j] == '/') msg->elements[i++] = '.'; |
| else msg->elements[i++] = name->value->elements[j]; |
| } |
| |
| str = vm->constructString(msg); |
| |
| return str; |
| } |
| |
| |
| |
| void Jnjvm::noClassDefFoundError(const UTF8* name) { |
| JavaString* str = CreateUnableToLoad(name, this); |
| llvm_gcroot(str, 0); |
| error(upcalls->NoClassDefFoundError, |
| upcalls->InitNoClassDefFoundError, str); |
| } |
| |
| void Jnjvm::classNotFoundException(JavaString* name) { |
| JavaString* str = CreateUnableToLoad(name, this); |
| llvm_gcroot(str, 0); |
| error(upcalls->ClassNotFoundException, |
| upcalls->InitClassNotFoundException, str); |
| } |
| |
| void Jnjvm::noClassDefFoundError(UserClass* cl, const UTF8* name) { |
| uint32 size = 35 + name->size + cl->name->size; |
| ArrayUInt16* msg = (ArrayUInt16*)upcalls->ArrayOfChar->doNew(size, this); |
| JavaString* str = 0; |
| llvm_gcroot(msg, 0); |
| llvm_gcroot(str, 0); |
| uint32 i = 0; |
| |
| |
| msg->elements[i++] = 't'; |
| msg->elements[i++] = 'r'; |
| msg->elements[i++] = 'y'; |
| msg->elements[i++] = ' '; |
| msg->elements[i++] = 't'; |
| msg->elements[i++] = 'o'; |
| msg->elements[i++] = ' '; |
| msg->elements[i++] = 'l'; |
| msg->elements[i++] = 'o'; |
| msg->elements[i++] = 'a'; |
| msg->elements[i++] = 'd'; |
| msg->elements[i++] = ' '; |
| |
| for (sint32 j = 0; j < cl->name->size; ++j) { |
| if (cl->name->elements[j] == '/') msg->elements[i++] = '.'; |
| else msg->elements[i++] = cl->name->elements[j]; |
| } |
| |
| msg->elements[i++] = ' '; |
| msg->elements[i++] = 'a'; |
| msg->elements[i++] = 'n'; |
| msg->elements[i++] = 'd'; |
| msg->elements[i++] = ' '; |
| msg->elements[i++] = 'f'; |
| msg->elements[i++] = 'o'; |
| msg->elements[i++] = 'u'; |
| msg->elements[i++] = 'n'; |
| msg->elements[i++] = 'd'; |
| msg->elements[i++] = ' '; |
| msg->elements[i++] = 'c'; |
| msg->elements[i++] = 'l'; |
| msg->elements[i++] = 'a'; |
| msg->elements[i++] = 's'; |
| msg->elements[i++] = 's'; |
| msg->elements[i++] = ' '; |
| msg->elements[i++] = 'n'; |
| msg->elements[i++] = 'a'; |
| msg->elements[i++] = 'm'; |
| msg->elements[i++] = 'e'; |
| msg->elements[i++] = 'd'; |
| msg->elements[i++] = ' '; |
| |
| for (sint32 j = 0; j < name->size; ++j) { |
| if (name->elements[j] == '/') msg->elements[i++] = '.'; |
| else msg->elements[i++] = name->elements[j]; |
| } |
| |
| assert(i == size && "Array overflow"); |
| |
| str = constructString(msg); |
| error(upcalls->NoClassDefFoundError, upcalls->InitNoClassDefFoundError, str); |
| } |
| |
| |
| void Jnjvm::classFormatError(const char* msg) { |
| JavaString* str = asciizToStr(msg); |
| llvm_gcroot(str, 0); |
| error(upcalls->ClassFormatError, upcalls->InitClassFormatError, str); |
| } |
| |
| JavaString* Jnjvm::internalUTF8ToStr(const UTF8* utf8) { |
| uint32 size = utf8->size; |
| ArrayUInt16* tmp = (ArrayUInt16*)upcalls->ArrayOfChar->doNew(size, this); |
| llvm_gcroot(tmp, 0); |
| uint16* buf = tmp->elements; |
| |
| for (uint32 i = 0; i < size; i++) { |
| buf[i] = utf8->elements[i]; |
| } |
| |
| return hashStr.lookupOrCreate(const_cast<const ArrayUInt16*&>(tmp), this, |
| JavaString::stringDup); |
| } |
| |
| JavaString* Jnjvm::constructString(const ArrayUInt16* array) { |
| llvm_gcroot(array, 0); |
| JavaString* res = hashStr.lookupOrCreate(array, this, JavaString::stringDup); |
| return res; |
| } |
| |
| JavaString* Jnjvm::asciizToStr(const char* asciiz) { |
| assert(asciiz && "No asciiz given"); |
| ArrayUInt16* var = 0; |
| llvm_gcroot(var, 0); |
| var = asciizToArray(asciiz); |
| return constructString(var); |
| } |
| |
| void Jnjvm::addProperty(char* key, char* value) { |
| postProperties.push_back(std::make_pair(key, value)); |
| } |
| |
| // Mimic what's happening in Classpath when creating a java.lang.Class object. |
| JavaObject* UserCommonClass::getClassDelegatee(Jnjvm* vm, JavaObject* pd) { |
| JavaObjectClass* delegatee = 0; |
| JavaObjectClass* base = 0; |
| llvm_gcroot(pd, 0); |
| llvm_gcroot(delegatee, 0); |
| llvm_gcroot(base, 0); |
| |
| if (!getDelegatee()) { |
| UserClass* cl = vm->upcalls->newClass; |
| delegatee = (JavaObjectClass*)cl->doNew(vm); |
| delegatee->vmdata = this; |
| if (!pd && isArray()) { |
| base = (JavaObjectClass*) |
| asArrayClass()->baseClass()->getClassDelegatee(vm, pd); |
| delegatee->pd = base->pd; |
| } else { |
| delegatee->pd = pd; |
| } |
| setDelegatee(delegatee); |
| } |
| return getDelegatee(); |
| } |
| |
| JavaObject* const* UserCommonClass::getClassDelegateePtr(Jnjvm* vm, JavaObject* pd) { |
| llvm_gcroot(pd, 0); |
| // Make sure it's created. |
| getClassDelegatee(vm, pd); |
| return getDelegateePtr(); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // The command line parsing tool does not manipulate any GC-allocated objects. |
| // The ArrayUInt8 is allocated with malloc and free'd after parsing. |
| //===----------------------------------------------------------------------===// |
| |
| #define PATH_MANIFEST "META-INF/MANIFEST.MF" |
| #define MAIN_CLASS "Main-Class: " |
| #define MAIN_LOWER_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; |
| |
| void ClArgumentsInfo::javaAgent(char* cur) { |
| assert(0 && "implement me"); |
| } |
| |
| extern "C" int sys_strnstr(const char *haystack, const char *needle) { |
| const 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, "class name"); |
| memcpy(name, &(ptr[index]), length); |
| name[length] = 0; |
| return name; |
| } else { |
| return 0; |
| } |
| } |
| |
| void ClArgumentsInfo::extractClassFromJar(Jnjvm* vm, int argc, char** argv, |
| int i) { |
| jarFile = argv[i]; |
| |
| vm->setClasspath(jarFile); |
| |
| ArrayUInt8* bytes = Reader::openFile(vm->bootstrapLoader, jarFile, true); |
| |
| if (!bytes) { |
| printf("Unable to access jarfile %s\n", jarFile); |
| return; |
| } |
| |
| 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->allocator, |
| true); |
| int ok = archive.readFile(res, file); |
| if (ok) { |
| char* mainClass = findInformation(vm, res, MAIN_CLASS, |
| LENGTH_MAIN_CLASS); |
| if (!mainClass) |
| mainClass = findInformation(vm, res, MAIN_LOWER_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); |
| } |
| free(res); |
| } else { |
| printf("Can't find Manifest file in archive %s\n", jarFile); |
| } |
| } else { |
| printf("Can't find archive %s\n", jarFile); |
| } |
| free(bytes); |
| } |
| |
| void ClArgumentsInfo::nyi() { |
| fprintf(stdout, "Not yet implemented\n"); |
| } |
| |
| void ClArgumentsInfo::printVersion() { |
| fprintf(stdout, "J3 for Java 1.1 -- 1.5\n"); |
| } |
| |
| void ClArgumentsInfo::printInformation() { |
| fprintf(stdout, |
| "Usage: j3 [-options] class [args...] (to execute a class)\n" |
| "or j3 [-options] -jar jarfile [args...]\n" |
| "(to execute a jar file) where options include:\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(Jnjvm* vm) { |
| className = 0; |
| appArgumentsPos = 0; |
| sint32 i = 1; |
| if (i == argc) printInformation(); |
| while (i < argc) { |
| char* cur = argv[i]; |
| 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 (!(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"))) { |
| mvm::Collector::verbose = 1; |
| } 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; |
| } |
| } |
| |
| |
| JnjvmClassLoader* Jnjvm::loadAppClassLoader() { |
| JavaObject* loader = 0; |
| llvm_gcroot(loader, 0); |
| |
| if (appClassLoader == 0) { |
| UserClass* cl = upcalls->newClassLoader; |
| loader = upcalls->getSystemClassLoader->invokeJavaObjectStatic(this, cl); |
| appClassLoader = JnjvmClassLoader::getJnjvmLoaderFromJavaObject(loader, |
| this); |
| if (argumentsInfo.jarFile) |
| appClassLoader->loadLibFromJar(this, argumentsInfo.jarFile, |
| argumentsInfo.className); |
| else if (argumentsInfo.className) |
| appClassLoader->loadLibFromFile(this, argumentsInfo.className); |
| } |
| return appClassLoader; |
| } |
| |
| void Jnjvm::loadBootstrap() { |
| JnjvmClassLoader* loader = bootstrapLoader; |
| |
| // First create system threads. |
| finalizerThread = new JavaThread(0, 0, this); |
| finalizerThread->start((void (*)(mvm::Thread*))finalizerStart); |
| |
| enqueueThread = new JavaThread(0, 0, this); |
| enqueueThread->start((void (*)(mvm::Thread*))enqueueStart); |
| |
| // Initialise the bootstrap class loader if it's not |
| // done already. |
| if (!bootstrapLoader->upcalls->newString) |
| bootstrapLoader->upcalls->initialiseClasspath(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 define a new VT for strings that will be |
| // placed in the hashmap. This VT will have its destructor set so |
| // that the string is removed when deallocated. |
| upcalls->newString->resolveClass(); |
| if (!JavaString::internStringVT) { |
| JavaVirtualTable* stringVT = upcalls->newString->getVirtualVT(); |
| uint32 size = upcalls->newString->virtualTableSize * sizeof(uintptr_t); |
| |
| JavaString::internStringVT = |
| (JavaVirtualTable*)bootstrapLoader->allocator.Allocate(size, "String VT"); |
| |
| memcpy(JavaString::internStringVT, stringVT, size); |
| |
| JavaString::internStringVT->destructor = |
| (uintptr_t)JavaString::stringDestructor; |
| |
| // Tell the finalizer that this is a native destructor. |
| JavaString::internStringVT->operatorDelete = |
| (uintptr_t)JavaString::stringDestructor; |
| } |
| upcalls->newString->initialiseClass(this); |
| |
| #ifdef SERVICE |
| if (!IsolateID) |
| #endif |
| // The initialization code of the classes initialized below may require |
| // to get the Java thread, so we create the Java thread object first. |
| upcalls->InitializeThreading(this); |
| |
| LOAD_CLASS(upcalls->newClass); |
| LOAD_CLASS(upcalls->newConstructor); |
| LOAD_CLASS(upcalls->newField); |
| LOAD_CLASS(upcalls->newMethod); |
| LOAD_CLASS(upcalls->newVMThread); |
| 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); |
| LOAD_CLASS(upcalls->ArithmeticException); |
| LOAD_CLASS(upcalls->InstantiationException); |
| LOAD_CLASS(upcalls->SystemClass); |
| #undef LOAD_CLASS |
| |
| loadAppClassLoader(); |
| JavaObject* obj = JavaThread::get()->currentThread(); |
| JavaObject* javaLoader = appClassLoader->getJavaClassLoader(); |
| |
| #ifdef SERVICE |
| if (!IsolateID) |
| #endif |
| 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->asClass()->initialiseClass(this); |
| } |
| |
| void Jnjvm::executeClass(const char* className, ArrayObject* args) { |
| JavaObject* exc = 0; |
| JavaObject* obj = 0; |
| JavaObject* group = 0; |
| |
| llvm_gcroot(args, 0); |
| llvm_gcroot(exc, 0); |
| llvm_gcroot(obj, 0); |
| llvm_gcroot(group, 0); |
| |
| TRY { |
| // First try to see if we are a self-contained executable. |
| UserClass* cl = appClassLoader->loadClassFromSelf(this, className); |
| |
| // If not, load the class. |
| if (!cl) { |
| const UTF8* name = appClassLoader->asciizConstructUTF8(className); |
| cl = (UserClass*)appClassLoader->loadName(name, true, true); |
| } |
| |
| cl->initialiseClass(this); |
| |
| const UTF8* funcSign = |
| appClassLoader->asciizConstructUTF8("([Ljava/lang/String;)V"); |
| const UTF8* funcName = appClassLoader->asciizConstructUTF8("main"); |
| JavaMethod* method = cl->lookupMethod(funcName, funcSign, true, true, 0); |
| if (isPublic(method->access)) { |
| method->invokeIntStatic(this, method->classDef, &args); |
| } else { |
| fprintf(stderr, "Main method not public.\n"); |
| } |
| } CATCH { |
| } END_CATCH; |
| |
| exc = JavaThread::get()->pendingException; |
| if (exc) { |
| JavaThread* th = JavaThread::get(); |
| th->clearException(); |
| obj = th->currentThread(); |
| group = upcalls->group->getObjectField(obj); |
| TRY { |
| upcalls->uncaughtException->invokeIntSpecial(this, upcalls->threadGroup, |
| group, &obj, &exc); |
| } CATCH { |
| fprintf(stderr, "Exception in thread \"main\": " |
| "Can not print stack trace.\n"); |
| } END_CATCH; |
| } |
| } |
| |
| void Jnjvm::executePremain(const char* className, JavaString* args, |
| JavaObject* instrumenter) { |
| llvm_gcroot(instrumenter, 0); |
| TRY { |
| const UTF8* name = appClassLoader->asciizConstructUTF8(className); |
| UserClass* cl = (UserClass*)appClassLoader->loadName(name, true, true); |
| cl->initialiseClass(this); |
| |
| const UTF8* funcSign = appClassLoader->asciizConstructUTF8( |
| "(Ljava/lang/String;Ljava/lang/instrument/Instrumentation;)V"); |
| const UTF8* funcName = appClassLoader->asciizConstructUTF8("premain"); |
| JavaMethod* method = cl->lookupMethod(funcName, funcSign, true, true, 0); |
| |
| method->invokeIntStatic(this, method->classDef, &args, &instrumenter); |
| } IGNORE; |
| } |
| |
| void Jnjvm::waitForExit() { |
| |
| threadSystem.nonDaemonLock.lock(); |
| |
| while (threadSystem.nonDaemonThreads) { |
| threadSystem.nonDaemonVar.wait(&threadSystem.nonDaemonLock); |
| } |
| |
| threadSystem.nonDaemonLock.unlock(); |
| |
| return; |
| } |
| |
| void Jnjvm::mainJavaStart(JavaThread* thread) { |
| |
| JavaString* str = 0; |
| JavaObject* instrumenter = 0; |
| ArrayObject* args = 0; |
| JavaObject* exc = 0; |
| |
| llvm_gcroot(str, 0); |
| llvm_gcroot(instrumenter, 0); |
| llvm_gcroot(args, 0); |
| llvm_gcroot(exc, 0); |
| |
| Jnjvm* vm = thread->getJVM(); |
| vm->mainThread = thread; |
| |
| TRY { |
| vm->loadBootstrap(); |
| } CATCH { |
| exc = JavaThread::get()->pendingException; |
| } END_CATCH; |
| |
| if (exc != NULL) { |
| fprintf(stderr, "Exception %s while bootstrapping VM.", |
| UTF8Buffer(exc->getClass()->name).cString()); |
| } else { |
| #ifdef SERVICE |
| thread->ServiceException = vm->upcalls->newThrowable->doNew(vm); |
| #endif |
| |
| ClArgumentsInfo& info = vm->argumentsInfo; |
| |
| if (info.agents.size()) { |
| assert(0 && "implement me"); |
| instrumenter = 0;//createInstrumenter(); |
| for (std::vector< std::pair<char*, char*> >::iterator i = |
| info.agents.begin(), e = info.agents.end(); i!= e; ++i) { |
| str = vm->asciizToStr(i->second); |
| vm->executePremain(i->first, str, instrumenter); |
| } |
| } |
| |
| UserClassArray* array = vm->bootstrapLoader->upcalls->ArrayOfString; |
| args = (ArrayObject*)array->doNew(info.argc - 2, vm); |
| for (int i = 2; i < info.argc; ++i) { |
| args->elements[i - 2] = (JavaObject*)vm->asciizToStr(info.argv[i]); |
| } |
| |
| vm->executeClass(info.className, args); |
| } |
| vm->threadSystem.nonDaemonLock.lock(); |
| --(vm->threadSystem.nonDaemonThreads); |
| if (vm->threadSystem.nonDaemonThreads == 0) |
| vm->threadSystem.nonDaemonVar.signal(); |
| vm->threadSystem.nonDaemonLock.unlock(); |
| } |
| |
| #ifdef SERVICE |
| |
| #include <signal.h> |
| |
| extern void terminationHandler(int); |
| |
| static void serviceCPUMonitor(mvm::Thread* th) { |
| while (true) { |
| sleep(1); |
| for(JavaThread* cur = (Java*)th->next(); cur != th; |
| cur = (JavaThread*)cur->next()) { |
| JavaThread* th = (JavaThread*)cur; |
| if (!(th->StateWaiting)) { |
| mvm::VirtualMachine* executingVM = cur->MyVM; |
| assert(executingVM && "Thread with no VM!"); |
| ++executingVM->executionTime; |
| } |
| } |
| } |
| } |
| #endif |
| |
| void Jnjvm::runApplication(int argc, char** argv) { |
| argumentsInfo.argc = argc; |
| argumentsInfo.argv = argv; |
| argumentsInfo.readArgs(this); |
| if (argumentsInfo.className) { |
| int pos = argumentsInfo.appArgumentsPos; |
| |
| argumentsInfo.argv = argumentsInfo.argv + pos - 1; |
| argumentsInfo.argc = argumentsInfo.argc - pos + 1; |
| #ifdef SERVICE |
| struct sigaction sa; |
| sigset_t mask; |
| sigfillset(&mask); |
| sigaction(SIGUSR1, 0, &sa); |
| sa.sa_mask = mask; |
| sa.sa_handler = terminationHandler; |
| sa.sa_flags |= SA_RESTART; |
| sigaction(SIGUSR1, &sa, NULL); |
| |
| mvm::Thread* th = new JavaThread(0, 0, this); |
| th->start(serviceCPUMonitor); |
| #endif |
| |
| mainThread = new JavaThread(0, 0, this); |
| mainThread->start((void (*)(mvm::Thread*))mainJavaStart); |
| } else { |
| threadSystem.nonDaemonThreads = 0; |
| } |
| } |
| |
| Jnjvm::Jnjvm(mvm::BumpPtrAllocator& Alloc, JnjvmBootstrapLoader* loader) : |
| VirtualMachine(Alloc), lockSystem(this) { |
| |
| classpath = getenv("CLASSPATH"); |
| if (!classpath) classpath = "."; |
| |
| appClassLoader = 0; |
| jniEnv = &JNI_JNIEnvTable; |
| javavmEnv = &JNI_JavaVMTable; |
| |
| |
| bootstrapLoader = loader; |
| upcalls = bootstrapLoader->upcalls; |
| |
| throwable = upcalls->newThrowable; |
| |
| StringList* end = loader->strings; |
| while (end) { |
| for (uint32 i = 0; i < end->length; ++i) { |
| JavaString* obj = end->strings[i]; |
| hashStr.insert(obj); |
| } |
| end = end->prev; |
| } |
| |
| bootstrapLoader->insertAllMethodsInVM(this); |
| |
| #ifdef ISOLATE |
| IsolateLock.lock(); |
| for (uint32 i = 0; i < NR_ISOLATES; ++i) { |
| if (RunningIsolates[i] == 0) { |
| RunningIsolates[i] = this; |
| IsolateID = i; |
| break; |
| } |
| } |
| IsolateLock.unlock(); |
| #endif |
| |
| scanner = loader->getCompiler()->createStackScanner(); |
| } |
| |
| Jnjvm::~Jnjvm() { |
| #ifdef ISOLATE |
| RunningIsolates[IsolateID] = 0; |
| #endif |
| } |
| |
| 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; |
| |
| } |
| |
| ArrayUInt16* Jnjvm::asciizToArray(const char* asciiz) { |
| uint32 size = strlen(asciiz); |
| ArrayUInt16* tmp = (ArrayUInt16*)upcalls->ArrayOfChar->doNew(size, this); |
| uint16* buf = tmp->elements; |
| |
| for (uint32 i = 0; i < size; i++) { |
| buf[i] = asciiz[i]; |
| } |
| return tmp; |
| } |
| |
| void Jnjvm::internalRemoveMethods(JnjvmClassLoader* loader, mvm::FunctionMap& Map) { |
| // Loop over all methods in the map to find which ones belong |
| // to this class loader. |
| Map.FunctionMapLock.acquire(); |
| std::map<void*, mvm::MethodInfo*>::iterator temp; |
| for (std::map<void*, mvm::MethodInfo*>::iterator i = Map.Functions.begin(), |
| e = Map.Functions.end(); i != e;) { |
| mvm::MethodInfo* MI = i->second; |
| if (MI->MethodType == 1) { |
| JavaMethod* meth = (JavaMethod*)i->second->getMetaInfo(); |
| if (meth->classDef->classLoader == loader) { |
| temp = i; |
| ++i; |
| Map.Functions.erase(temp); |
| } else { |
| ++i; |
| } |
| } else { |
| ++i; |
| } |
| } |
| Map.FunctionMapLock.release(); |
| } |
| |
| void Jnjvm::removeMethodsInFunctionMaps(JnjvmClassLoader* loader) { |
| internalRemoveMethods(loader, RuntimeFunctions); |
| internalRemoveMethods(loader, StaticFunctions); |
| } |
| |
| |
| /// JavaStaticCompiler - Compiler for AOT-compiled programs that |
| /// do not use the JIT. |
| class JavaStaticCompiler : public JavaCompiler { |
| public: |
| #ifdef WITH_LLVM_GCC |
| virtual mvm::StackScanner* createStackScanner() { |
| return new mvm::PreciseStackScanner(); |
| } |
| #endif |
| }; |
| |
| |
| // Helper function to run Jnjvm without JIT. |
| extern "C" int StartJnjvmWithoutJIT(int argc, char** argv, char* mainClass) { |
| mvm::Collector::initialise(); |
| |
| char** newArgv = new char*[argc + 1]; |
| memcpy(newArgv + 1, argv, argc * sizeof(char*)); |
| newArgv[0] = newArgv[1]; |
| newArgv[1] = mainClass; |
| |
| JavaCompiler* Comp = new JavaStaticCompiler(); |
| JnjvmClassLoader* JCL = mvm::VirtualMachine::initialiseJVM(Comp); |
| mvm::VirtualMachine* vm = mvm::VirtualMachine::createJVM(JCL); |
| vm->runApplication(argc + 1, newArgv); |
| vm->waitForExit(); |
| |
| delete[] newArgv; |
| |
| return 0; |
| } |