| //===-------- LLVMMaterializer.cpp - LLVM Materializer for J3 -------------===// |
| // |
| // The VMKit project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/Constants.h" |
| #include "llvm/Module.h" |
| #include "llvm/ExecutionEngine/ExecutionEngine.h" |
| |
| #include "mvm/JIT.h" |
| |
| #include "JavaAccess.h" |
| #include "JavaClass.h" |
| #include "JavaConstantPool.h" |
| #include "JavaThread.h" |
| #include "JavaTypes.h" |
| #include "Jnjvm.h" |
| |
| #include "j3/J3Intrinsics.h" |
| #include "j3/LLVMMaterializer.h" |
| |
| using namespace llvm; |
| using namespace j3; |
| |
| |
| JavaLLVMLazyJITCompiler::JavaLLVMLazyJITCompiler(const std::string& ModuleID) |
| : JavaJITCompiler(ModuleID) { |
| TheMaterializer = new LLVMMaterializer(TheModule, this); |
| } |
| |
| JavaLLVMLazyJITCompiler::~JavaLLVMLazyJITCompiler() { |
| // The module already destroys the materializer. |
| } |
| |
| void* JavaLLVMLazyJITCompiler::loadMethod(void* handle, const char* symbol) { |
| Function* F = mvm::MvmModule::globalModule->getFunction(symbol); |
| if (F) { |
| void* res = mvm::MvmModule::executionEngine->getPointerToFunctionOrStub(F); |
| return res; |
| } |
| |
| return JavaCompiler::loadMethod(handle, symbol); |
| } |
| |
| uintptr_t JavaLLVMLazyJITCompiler::getPointerOrStub(JavaMethod& meth, |
| int side) { |
| ExecutionEngine* EE = mvm::MvmModule::executionEngine; |
| LLVMMethodInfo* LMI = getMethodInfo(&meth); |
| Function* func = LMI->getMethod(); |
| return (uintptr_t)EE->getPointerToFunctionOrStub(func); |
| } |
| |
| static JavaMethod* staticLookup(CallbackInfo& F) { |
| Class* caller = F.cl; |
| uint16 index = F.index; |
| bool isStatic = F.stat; |
| JavaConstantPool* ctpInfo = caller->getConstantPool(); |
| |
| CommonClass* cl = 0; |
| const UTF8* utf8 = 0; |
| Signdef* sign = 0; |
| |
| ctpInfo->resolveMethod(index, cl, utf8, sign); |
| UserClass* lookup = cl->isArray() ? cl->super : cl->asClass(); |
| JavaMethod* meth = lookup->lookupMethod(utf8, sign->keyName, isStatic, true, |
| 0); |
| |
| assert(lookup->isInitializing() && "Class not ready"); |
| |
| return meth; |
| } |
| |
| |
| Value* JavaLLVMLazyJITCompiler::addCallback(Class* cl, uint16 index, |
| Signdef* sign, bool stat, |
| BasicBlock* insert) { |
| |
| Function* F = 0; |
| LLVMSignatureInfo* LSI = getSignatureInfo(sign); |
| |
| const UTF8* name = cl->name; |
| char* key = (char*)alloca(name->size + 16); |
| for (sint32 i = 0; i < name->size; ++i) |
| key[i] = name->elements[i]; |
| sprintf(key + name->size, "%d", index); |
| F = TheModule->getFunction(key); |
| if (F) return F; |
| |
| const FunctionType* type = stat ? LSI->getStaticType() : |
| LSI->getVirtualType(); |
| |
| F = Function::Create(type, GlobalValue::ExternalWeakLinkage, key, TheModule); |
| |
| CallbackInfo A(cl, index, stat); |
| callbacks.insert(std::make_pair(F, A)); |
| |
| return F; |
| } |
| |
| |
| bool LLVMMaterializer::Materialize(GlobalValue *GV, std::string *ErrInfo) { |
| |
| Function* F = dyn_cast<Function>(GV); |
| assert(F && "Not a function"); |
| if (F->getLinkage() == GlobalValue::ExternalLinkage) return false; |
| |
| // The caller of materializeFunction *must* always hold the JIT lock. |
| // Because we are materializing a function here, we must release the |
| // JIT lock and get the global vmkit lock to be thread-safe. |
| // This prevents jitting the function while someone else is doing it. |
| mvm::MvmModule::executionEngine->lock.release(); |
| mvm::MvmModule::protectIR(); |
| |
| // Don't use hasNotBeenReadFromBitcode: materializeFunction is called |
| // by the pass manager, and we don't want another thread to JIT the |
| // function while all passes have not been run. |
| if (!(F->isDeclaration())) { |
| mvm::MvmModule::unprotectIR(); |
| // Reacquire and go back to the JIT function. |
| mvm::MvmModule::executionEngine->lock.acquire(); |
| return false; |
| } |
| |
| if (mvm::MvmModule::executionEngine->getPointerToGlobalIfAvailable(F)) { |
| mvm::MvmModule::unprotectIR(); |
| // Reacquire and go back to the JIT function. |
| mvm::MvmModule::executionEngine->lock.acquire(); |
| return false; |
| } |
| |
| JavaMethod* meth = Comp->getJavaMethod(F); |
| |
| if (!meth) { |
| // It's a callback |
| JavaLLVMLazyJITCompiler::callback_iterator I = Comp->callbacks.find(F); |
| assert(I != Comp->callbacks.end() && "No callbacks found"); |
| meth = staticLookup(I->second); |
| } |
| |
| void* val = meth->compiledPtr(); |
| |
| if (isVirtual(meth->access)) { |
| LLVMMethodInfo* LMI = Comp->getMethodInfo(meth); |
| uint64_t offset = dyn_cast<ConstantInt>(LMI->getOffset())->getZExtValue(); |
| assert(meth->classDef->isResolved() && "Class not resolved"); |
| #if !defined(ISOLATE_SHARING) && !defined(SERVICE) |
| assert(meth->classDef->isInitializing() && "Class not ready"); |
| #endif |
| assert(meth->classDef->virtualVT && "Class has no VT"); |
| assert(meth->classDef->virtualTableSize > offset && |
| "The method's offset is greater than the virtual table size"); |
| ((void**)meth->classDef->virtualVT)[offset] = val; |
| } else { |
| assert(meth->classDef->isInitializing() && "Class not ready"); |
| } |
| |
| mvm::MvmModule::unprotectIR(); |
| |
| // Reacquire to go back to the JIT function. |
| mvm::MvmModule::executionEngine->lock.acquire(); |
| |
| if (F->isDeclaration()) |
| mvm::MvmModule::executionEngine->updateGlobalMapping(F, val); |
| |
| return false; |
| } |
| |
| bool LLVMMaterializer::isMaterializable(const llvm::GlobalValue* GV) const { |
| return GV->getLinkage() == GlobalValue::ExternalWeakLinkage; |
| } |
| |
| |
| LLVMMaterializer::LLVMMaterializer( |
| llvm::Module* m, JavaLLVMLazyJITCompiler* C) { |
| Comp = C; |
| TheModule = m; |
| m->setMaterializer(this); |
| } |