| //===-------------------- JavaRuntimeJIT.cpp ------------------------------===// |
| //=== ---- Runtime functions called by code compiled by the JIT -----------===// |
| // |
| // JnJVM |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include <stdarg.h> |
| |
| #include "mvm/JIT.h" |
| #include "mvm/Threads/Thread.h" |
| |
| #include "JavaArray.h" |
| #include "JavaCache.h" |
| #include "JavaClass.h" |
| #include "JavaConstantPool.h" |
| #include "JavaJIT.h" |
| #include "JavaString.h" |
| #include "JavaThread.h" |
| #include "JavaTypes.h" |
| #include "Jnjvm.h" |
| #include "LockedMap.h" |
| |
| using namespace jnjvm; |
| |
| extern "C" void* jnjvmVirtualLookup(CacheNode* cache, JavaObject *obj) { |
| Enveloppe* enveloppe = cache->enveloppe; |
| UserConstantPool* ctpInfo = enveloppe->ctpInfo; |
| UserCommonClass* ocl = obj->classOf; |
| UserCommonClass* cl = 0; |
| const UTF8* utf8 = 0; |
| Signdef* sign = 0; |
| uint32 index = enveloppe->index; |
| |
| ctpInfo->resolveMethod(index, cl, utf8, sign); |
| #ifndef SERVICE |
| assert(obj->classOf->isInitializing() && |
| "Class not ready in a virtual lookup."); |
| #endif |
| |
| enveloppe->cacheLock.lock(); |
| CacheNode* rcache = 0; |
| CacheNode* tmp = enveloppe->firstCache; |
| CacheNode* last = tmp; |
| |
| while (tmp) { |
| if (ocl == tmp->lastCible) { |
| rcache = tmp; |
| break; |
| } else { |
| last = tmp; |
| tmp = tmp->next; |
| } |
| } |
| |
| if (!rcache) { |
| UserClass* methodCl = 0; |
| JavaMethod* dmeth = ocl->lookupMethod(utf8, sign->keyName, false, true, |
| &methodCl); |
| #if !defined(ISOLATE_SHARING) && !defined(SERVICE) |
| assert(dmeth->classDef->isInitializing() && |
| "Class not ready in a virtual lookup."); |
| #endif |
| if (cache->methPtr) { |
| JnjvmClassLoader* loader = ctpInfo->classDef->classLoader; |
| rcache = new(loader->allocator) CacheNode(enveloppe); |
| } else { |
| rcache = cache; |
| } |
| |
| rcache->methPtr = dmeth->compiledPtr(); |
| rcache->lastCible = (UserClass*)ocl; |
| #ifdef ISOLATE_SHARING |
| rcache->definingCtp = methodCl->getConstantPool(); |
| #endif |
| |
| } |
| |
| if (enveloppe->firstCache != rcache) { |
| CacheNode *f = enveloppe->firstCache; |
| enveloppe->firstCache = rcache; |
| last->next = rcache->next; |
| rcache->next = f; |
| } |
| |
| enveloppe->cacheLock.unlock(); |
| |
| return rcache->methPtr; |
| } |
| |
| extern "C" void* virtualFieldLookup(UserClass* caller, uint32 index) { |
| UserConstantPool* ctpInfo = caller->getConstantPool(); |
| if (ctpInfo->ctpRes[index]) { |
| return ctpInfo->ctpRes[index]; |
| } |
| |
| UserCommonClass* cl = 0; |
| const UTF8* utf8 = 0; |
| Typedef* sign = 0; |
| |
| ctpInfo->resolveField(index, cl, utf8, sign); |
| |
| JavaField* field = cl->lookupField(utf8, sign->keyName, false, true, 0); |
| |
| ctpInfo->ctpRes[index] = (void*)field->ptrOffset; |
| |
| return (void*)field->ptrOffset; |
| } |
| |
| extern "C" void* staticFieldLookup(UserClass* caller, uint32 index) { |
| UserConstantPool* ctpInfo = caller->getConstantPool(); |
| |
| if (ctpInfo->ctpRes[index]) { |
| return ctpInfo->ctpRes[index]; |
| } |
| |
| UserCommonClass* cl = 0; |
| UserCommonClass* fieldCl = 0; |
| const UTF8* utf8 = 0; |
| Typedef* sign = 0; |
| |
| ctpInfo->resolveField(index, cl, utf8, sign); |
| |
| JavaField* field = cl->lookupField(utf8, sign->keyName, true, true, &fieldCl); |
| |
| fieldCl->initialiseClass(JavaThread::get()->getJVM()); |
| JavaObject* obj = ((UserClass*)fieldCl)->getStaticInstance(); |
| |
| assert(obj && "No static instance in static field lookup"); |
| |
| void* ptr = (void*)((uint64)obj + field->ptrOffset); |
| ctpInfo->ctpRes[index] = ptr; |
| |
| return ptr; |
| } |
| |
| #ifdef ISOLATE |
| extern "C" void* stringLookup(UserClass* cl, uint32 index) { |
| UserConstantPool* ctpInfo = cl->getConstantPool(); |
| const UTF8* utf8 = ctpInfo->UTF8AtForString(index); |
| JavaString* str = JavaThread::get()->getJVM()->internalUTF8ToStr(utf8); |
| #ifdef ISOLATE_SHARING |
| ctpInfo->ctpRes[index] = str; |
| #endif |
| return (void*)str; |
| } |
| |
| #ifdef ISOLATE_SHARING |
| extern "C" void* enveloppeLookup(UserClass* cl, uint32 index) { |
| UserConstantPool* ctpInfo = cl->getConstantPool(); |
| mvm::Allocator* allocator = cl->classLoader->allocator; |
| Enveloppe* enveloppe = new(allocator) Enveloppe(ctpInfo, index); |
| ctpInfo->ctpRes[index] = enveloppe; |
| return (void*)enveloppe; |
| } |
| |
| extern "C" void* staticCtpLookup(UserClass* cl, uint32 index) { |
| UserConstantPool* ctpInfo = cl->getConstantPool(); |
| JavaConstantPool* shared = ctpInfo->getSharedPool(); |
| uint32 clIndex = shared->getClassIndexFromMethod(index); |
| UserClass* refCl = (UserClass*)ctpInfo->loadClass(clIndex); |
| refCl->initialiseClass(JavaThread::get()->getJVM()); |
| |
| CommonClass* baseCl = 0; |
| const UTF8* utf8 = 0; |
| Signdef* sign = 0; |
| |
| shared->resolveMethod(index, baseCl, utf8, sign); |
| UserClass* methodCl = 0; |
| refCl->lookupMethod(utf8, sign->keyName, true, true, &methodCl); |
| ctpInfo->ctpRes[index] = methodCl->getConstantPool(); |
| shared->ctpRes[clIndex] = refCl->classDef; |
| return (void*)methodCl->getConstantPool(); |
| } |
| |
| extern "C" UserConstantPool* specialCtpLookup(UserConstantPool* ctpInfo, |
| uint32 index, |
| UserConstantPool** res) { |
| JavaConstantPool* shared = ctpInfo->getSharedPool(); |
| uint32 clIndex = shared->getClassIndexFromMethod(index); |
| UserClass* refCl = (UserClass*)ctpInfo->loadClass(clIndex); |
| |
| CommonClass* baseCl = 0; |
| const UTF8* utf8 = 0; |
| Signdef* sign = 0; |
| |
| shared->resolveMethod(index, baseCl, utf8, sign); |
| UserClass* methodCl = 0; |
| refCl->lookupMethod(utf8, sign->keyName, false, true, &methodCl); |
| shared->ctpRes[clIndex] = refCl->classDef; |
| *res = methodCl->getConstantPool(); |
| return methodCl->getConstantPool(); |
| } |
| |
| #endif |
| |
| #endif |
| |
| #ifndef WITHOUT_VTABLE |
| extern "C" void* vtableLookup(UserClass* caller, uint32 index, ...) { |
| UserCommonClass* cl = 0; |
| const UTF8* utf8 = 0; |
| Signdef* sign = 0; |
| |
| caller->getConstantPool()->resolveMethod(index, cl, utf8, sign); |
| JavaMethod* dmeth = cl->lookupMethodDontThrow(utf8, sign->keyName, false, |
| true, 0); |
| if (!dmeth) { |
| va_list ap; |
| va_start(ap, index); |
| JavaObject* obj = va_arg(ap, JavaObject*); |
| va_end(ap); |
| assert(obj->classOf->isInitializing() && |
| "Class not ready in a virtual lookup."); |
| // Arg, the bytecode is buggy! Perform the lookup on the object class |
| // and do not update offset. |
| dmeth = obj->classOf->lookupMethod(utf8, sign->keyName, false, true, 0); |
| } else { |
| caller->getConstantPool()->ctpRes[index] = (void*)dmeth->offset; |
| } |
| |
| #if !defined(ISOLATE_SHARING) && !defined(SERVICE) |
| assert(dmeth->classDef->isInitializing() && |
| "Class not ready in a virtual lookup."); |
| #endif |
| |
| return (void*)dmeth->offset; |
| } |
| #endif |
| |
| extern "C" void* classLookup(UserClass* caller, uint32 index) { |
| UserConstantPool* ctpInfo = caller->getConstantPool(); |
| UserClass* cl = (UserClass*)ctpInfo->loadClass(index); |
| // We can not initialize here, because bytecodes such as CHECKCAST |
| // or classes used in catch clauses do not trigger class initialization. |
| // This is really sad, because we need to insert class initialization checks |
| // in the LLVM code. |
| return (void*)cl; |
| } |
| |
| |
| extern "C" void printMethodStart(JavaMethod* meth) { |
| printf("[%p] executing %s\n", (void*)mvm::Thread::get(), |
| meth->printString()); |
| fflush(stdout); |
| } |
| |
| extern "C" void printMethodEnd(JavaMethod* meth) { |
| printf("[%p] return from %s\n", (void*)mvm::Thread::get(), |
| meth->printString()); |
| fflush(stdout); |
| } |
| |
| extern "C" void printExecution(char* opcode, uint32 index, JavaMethod* meth) { |
| printf("[%p] executing %s %s at %d\n", (void*)mvm::Thread::get(), |
| meth->printString(), opcode, index); |
| fflush(stdout); |
| } |
| |
| extern "C" void jniProceedPendingException() { |
| JavaThread* th = JavaThread::get(); |
| jmp_buf* buf = th->sjlj_buffers.back(); |
| th->sjlj_buffers.pop_back(); |
| mvm::Allocator& allocator = th->getJVM()->gcAllocator; |
| allocator.freeTemporaryMemory(buf); |
| if (JavaThread::get()->pendingException) { |
| th->throwPendingException(); |
| } |
| } |
| |
| extern "C" void* getSJLJBuffer() { |
| JavaThread* th = JavaThread::get(); |
| mvm::Allocator& allocator = th->getJVM()->gcAllocator; |
| void** buf = (void**)allocator.allocateTemporaryMemory(sizeof(jmp_buf)); |
| th->sjlj_buffers.push_back((jmp_buf*)buf); |
| return (void*)buf; |
| } |
| |
| extern "C" void jnjvmNullPointerException() { |
| JavaThread::get()->getJVM()->nullPointerException("null"); |
| } |
| |
| extern "C" void negativeArraySizeException(sint32 val) { |
| JavaThread::get()->getJVM()->negativeArraySizeException(val); |
| } |
| |
| extern "C" void outOfMemoryError(sint32 val) { |
| JavaThread::get()->getJVM()->outOfMemoryError(val); |
| } |
| |
| extern "C" void jnjvmClassCastException(JavaObject* obj, UserCommonClass* cl) { |
| JavaThread::get()->getJVM()->classCastException(obj, cl); |
| } |
| |
| extern "C" void indexOutOfBoundsException(JavaObject* obj, sint32 index) { |
| JavaThread::get()->getJVM()->indexOutOfBounds(obj, index); |
| } |
| |
| extern "C" UserCommonClass* jnjvmRuntimeInitialiseClass(UserCommonClass* cl) { |
| cl->initialiseClass(JavaThread::get()->getJVM()); |
| return cl; |
| } |
| |
| extern "C" JavaObject* getClassDelegatee(UserCommonClass* cl) { |
| Jnjvm* vm = JavaThread::get()->getJVM(); |
| return cl->getClassDelegatee(vm); |
| } |
| |
| static JavaArray* multiCallNewIntern(UserClassArray* cl, uint32 len, |
| sint32* dims, Jnjvm* vm) { |
| if (len <= 0) JavaThread::get()->getJVM()->unknownError("Can not happen"); |
| JavaArray* _res = cl->doNew(dims[0], vm); |
| if (len > 1) { |
| ArrayObject* res = (ArrayObject*)_res; |
| UserCommonClass* _base = cl->baseClass(); |
| if (_base->isArray()) { |
| UserClassArray* base = (UserClassArray*)_base; |
| if (dims[0] > 0) { |
| for (sint32 i = 0; i < dims[0]; ++i) { |
| res->elements[i] = multiCallNewIntern(base, (len - 1), |
| &dims[1], vm); |
| } |
| } else { |
| for (uint32 i = 1; i < len; ++i) { |
| sint32 p = dims[i]; |
| if (p < 0) JavaThread::get()->getJVM()->negativeArraySizeException(p); |
| } |
| } |
| } else { |
| JavaThread::get()->getJVM()->unknownError("Can not happen"); |
| } |
| } |
| return _res; |
| } |
| |
| extern "C" JavaArray* multiCallNew(UserClassArray* cl, uint32 len, ...) { |
| va_list ap; |
| va_start(ap, len); |
| sint32* dims = (sint32*)alloca(sizeof(sint32) * len); |
| for (uint32 i = 0; i < len; ++i){ |
| dims[i] = va_arg(ap, int); |
| } |
| Jnjvm* vm = JavaThread::get()->getJVM(); |
| return multiCallNewIntern(cl, len, dims, vm); |
| } |
| |
| extern "C" UserClassArray* getArrayClass(UserCommonClass* cl, |
| UserClassArray** dcl) { |
| JnjvmClassLoader* JCL = cl->classLoader; |
| cl->resolveClass(); |
| const UTF8* arrayName = JCL->constructArrayName(1, cl->getName()); |
| |
| UserClassArray* result = JCL->constructArray(arrayName); |
| if (dcl) *dcl = result; |
| return result; |
| } |
| |
| extern "C" void JavaObjectAquire(JavaObject* obj) { |
| obj->acquire(); |
| } |
| |
| |
| extern "C" void JavaObjectRelease(JavaObject* obj) { |
| obj->release(); |
| } |
| |
| extern "C" bool instanceOf(JavaObject* obj, UserCommonClass* cl) { |
| return obj->instanceOf(cl); |
| } |
| |
| extern "C" bool instantiationOfArray(UserCommonClass* cl1, |
| UserClassArray* cl2) { |
| return cl1->instantiationOfArray(cl2); |
| } |
| |
| extern "C" bool implements(UserCommonClass* cl1, UserCommonClass* cl2) { |
| return cl1->implements(cl2); |
| } |
| |
| extern "C" bool isAssignableFrom(UserCommonClass* cl1, UserCommonClass* cl2) { |
| return cl1->isAssignableFrom(cl2); |
| } |
| |
| extern "C" void* JavaThreadGetException() { |
| return JavaThread::getException(); |
| } |
| |
| extern "C" void JavaThreadThrowException(JavaObject* obj) { |
| return JavaThread::throwException(obj); |
| } |
| |
| extern "C" JavaObject* JavaThreadGetJavaException() { |
| return JavaThread::getJavaException(); |
| } |
| |
| extern "C" bool JavaThreadCompareException(UserClass* cl) { |
| return JavaThread::compareException(cl); |
| } |
| |
| extern "C" void JavaThreadClearException() { |
| return JavaThread::clearException(); |
| } |
| |
| extern "C" void overflowThinLock(JavaObject* obj) { |
| obj->overflowThinlock(); |
| } |
| |
| #ifdef SERVICE |
| |
| extern "C" void serviceCallStart(Jnjvm* OldService, |
| Jnjvm* NewService) { |
| fprintf(stderr, "I have switched from %d to %d\n", OldService->IsolateID, |
| NewService->IsolateID); |
| |
| fprintf(stderr, "Now the thread id is %d\n", mvm::Thread::get()->IsolateID); |
| } |
| |
| extern "C" void serviceCallStop(Jnjvm* OldService, |
| Jnjvm* NewService) { |
| fprintf(stderr, "End service call\n"); |
| } |
| |
| #endif |