| //===----------- JavaJIT.cpp - Java just in time compiler -----------------===// |
| // |
| // JnJVM |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| |
| #define DEBUG 0 |
| #define JNJVM_COMPILE 0 |
| #define JNJVM_EXECUTE 0 |
| |
| #include <string.h> |
| |
| #include <llvm/Type.h> |
| #include <llvm/Support/CFG.h> |
| #include <llvm/Module.h> |
| #include <llvm/Constants.h> |
| #include <llvm/Type.h> |
| #include <llvm/DerivedTypes.h> |
| #include <llvm/Function.h> |
| #include <llvm/Instructions.h> |
| #include <llvm/ModuleProvider.h> |
| #include <llvm/ExecutionEngine/JIT.h> |
| #include <llvm/ExecutionEngine/GenericValue.h> |
| #include <llvm/PassManager.h> |
| #include <llvm/Analysis/Verifier.h> |
| #include <llvm/Transforms/Scalar.h> |
| #include <llvm/Target/TargetData.h> |
| #include <llvm/Assembly/PrintModulePass.h> |
| #include <llvm/Target/TargetOptions.h> |
| #include <llvm/CodeGen/MachineCodeEmitter.h> |
| #include <llvm/CodeGen/MachineBasicBlock.h> |
| #include "llvm/Constants.h" |
| #include "llvm/DerivedTypes.h" |
| #include "llvm/Module.h" |
| #include "llvm/ModuleProvider.h" |
| #include "llvm/PassManager.h" |
| #include "llvm/ValueSymbolTable.h" |
| #include "llvm/Analysis/LoadValueNumbering.h" |
| #include "llvm/Analysis/LoopPass.h" |
| #include "llvm/Analysis/Verifier.h" |
| #include "llvm/Assembly/Writer.h" |
| #include "llvm/Assembly/PrintModulePass.h" |
| #include "llvm/Bitcode/ReaderWriter.h" |
| #include "llvm/CodeGen/RegAllocRegistry.h" |
| #include "llvm/CodeGen/SchedulerRegistry.h" |
| #include "llvm/CodeGen/ScheduleDAG.h" |
| #include "llvm/Target/SubtargetFeature.h" |
| #include "llvm/Target/TargetData.h" |
| #include "llvm/Target/TargetLowering.h" |
| #include "llvm/Target/TargetMachine.h" |
| #include "llvm/Target/TargetMachineRegistry.h" |
| #include "llvm/Transforms/Scalar.h" |
| #include "llvm/Transforms/IPO.h" |
| #include "llvm/ADT/StringExtras.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/Support/Streams.h" |
| #include "llvm/Support/ManagedStatic.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| |
| #include <llvm/Transforms/IPO.h> |
| |
| |
| #include "mvm/JIT.h" |
| #include "mvm/Method.h" |
| |
| #include "debug.h" |
| #include "JavaArray.h" |
| #include "JavaCache.h" |
| #include "JavaClass.h" |
| #include "JavaConstantPool.h" |
| #include "JavaObject.h" |
| #include "JavaJIT.h" |
| #include "JavaString.h" |
| #include "JavaThread.h" |
| #include "JavaTypes.h" |
| #include "JavaUpcalls.h" |
| #include "Jnjvm.h" |
| #include "JnjvmModuleProvider.h" |
| #include "NativeUtil.h" |
| #include "Reader.h" |
| #include "Zip.h" |
| |
| #include <iostream> |
| |
| |
| using namespace jnjvm; |
| using namespace llvm; |
| |
| void Exception::print(mvm::PrintBuffer* buf) const { |
| buf->write("Exception<>"); |
| } |
| |
| void JavaJIT::print(mvm::PrintBuffer* buf) const { |
| buf->write("JavaJIT<>"); |
| } |
| |
| BasicBlock* JavaJIT::createBasicBlock(const char* name) { |
| return new BasicBlock(name, llvmFunction); |
| } |
| |
| Value* JavaJIT::top() { |
| return stack.back().first; |
| } |
| |
| Value* JavaJIT::pop() { |
| llvm::Value * ret = top(); |
| stack.pop_back(); |
| return ret; |
| } |
| |
| Value* JavaJIT::popAsInt() { |
| llvm::Value * ret = top(); |
| const AssessorDesc* ass = topFunc(); |
| stack.pop_back(); |
| |
| if (ret->getType() != Type::Int32Ty) { |
| if (ass == AssessorDesc::dChar) { |
| ret = new ZExtInst(ret, Type::Int32Ty, "", currentBlock); |
| } else { |
| ret = new SExtInst(ret, Type::Int32Ty, "", currentBlock); |
| } |
| } |
| |
| return ret; |
| } |
| |
| void JavaJIT::push(llvm::Value* val, const AssessorDesc* ass) { |
| assert(ass->llvmType == val->getType()); |
| stack.push_back(std::make_pair(val, ass)); |
| } |
| |
| void JavaJIT::push(std::pair<llvm::Value*, const AssessorDesc*> pair) { |
| assert(pair.second->llvmType == pair.first->getType()); |
| stack.push_back(pair); |
| } |
| |
| |
| const AssessorDesc* JavaJIT::topFunc() { |
| return stack.back().second; |
| } |
| |
| uint32 JavaJIT::stackSize() { |
| return stack.size(); |
| } |
| |
| std::pair<llvm::Value*, const AssessorDesc*> JavaJIT::popPair() { |
| std::pair<Value*, const AssessorDesc*> ret = stack.back(); |
| stack.pop_back(); |
| return ret; |
| } |
| |
| llvm::Function* JavaJIT::nativeCompile(void* natPtr) { |
| |
| PRINT_DEBUG(JNJVM_COMPILE, 1, COLOR_NORMAL, "native compile %s\n", |
| compilingMethod->printString()); |
| |
| bool stat = isStatic(compilingMethod->access); |
| |
| const FunctionType *funcType = compilingMethod->llvmType; |
| |
| bool jnjvm = false; |
| natPtr = natPtr ? natPtr : |
| NativeUtil::nativeLookup(compilingClass, compilingMethod, jnjvm); |
| |
| |
| |
| compilingClass->isolate->protectModule->lock(); |
| Function* func = llvmFunction = new llvm::Function(funcType, |
| GlobalValue::ExternalLinkage, |
| compilingMethod->printString(), |
| compilingClass->isolate->module); |
| compilingClass->isolate->protectModule->unlock(); |
| |
| if (jnjvm) { |
| mvm::jit::executionEngine->addGlobalMapping(func, natPtr); |
| return llvmFunction; |
| } |
| |
| currentBlock = createBasicBlock("start"); |
| BasicBlock* executeBlock = createBasicBlock("execute"); |
| endBlock = createBasicBlock("end block"); |
| if (funcType->getReturnType() != Type::VoidTy) |
| endNode = new PHINode(funcType->getReturnType(), "", endBlock); |
| |
| Value* buf = new CallInst(getSJLJBufferLLVM, "", currentBlock); |
| Value* test = new CallInst(mvm::jit::setjmpLLVM, buf, "", currentBlock); |
| test = new ICmpInst(ICmpInst::ICMP_EQ, test, mvm::jit::constantZero, "", currentBlock); |
| new BranchInst(executeBlock, endBlock, test, currentBlock); |
| if (compilingMethod->signature->ret->funcs != AssessorDesc::dVoid) |
| endNode->addIncoming(compilingMethod->signature->ret->funcs->llvmNullConstant, currentBlock); |
| |
| currentBlock = executeBlock; |
| if (isSynchro(compilingMethod->access)) |
| beginSynchronize(); |
| |
| |
| uint32 nargs = func->arg_size() + 1 + (stat ? 1 : 0); // + vm + cl/obj |
| std::vector<Value*> nativeArgs; |
| |
| mvm::jit::protectConstants();//->lock(); |
| nativeArgs.push_back( |
| ConstantExpr::getIntToPtr(ConstantInt::get(Type::Int64Ty, |
| (int64_t)&(compilingClass->isolate->jniEnv)), |
| mvm::jit::ptrType)); |
| mvm::jit::unprotectConstants();//->unlock(); |
| |
| uint32 index = 0; |
| if (stat) { |
| #ifdef SINGLE_VM |
| nativeArgs.push_back(new LoadInst(compilingClass->llvmDelegatee(), "", currentBlock)); |
| #else |
| Value* ld = new LoadInst(compilingClass->llvmVar(compilingClass->isolate->module), "", currentBlock); |
| nativeArgs.push_back(new CallInst(getClassDelegateeLLVM, ld, "", currentBlock)); |
| #endif |
| index = 2; |
| } else { |
| index = 1; |
| } |
| for (Function::arg_iterator i = func->arg_begin(); |
| index < nargs; ++i, ++index) { |
| |
| nativeArgs.push_back(i); |
| } |
| |
| |
| const llvm::Type* valPtrType = compilingMethod->signature->nativeTypePtr; |
| mvm::jit::protectConstants();//->lock(); |
| Value* valPtr = |
| ConstantExpr::getIntToPtr(ConstantInt::get(Type::Int64Ty, (uint64)natPtr), |
| valPtrType); |
| mvm::jit::unprotectConstants();//->unlock(); |
| |
| Value* result = new CallInst(valPtr, nativeArgs.begin(), nativeArgs.end(), "", currentBlock); |
| if (funcType->getReturnType() != Type::VoidTy) |
| endNode->addIncoming(result, currentBlock); |
| new BranchInst(endBlock, currentBlock); |
| |
| currentBlock = endBlock; |
| if (isSynchro(compilingMethod->access)) |
| endSynchronize(); |
| |
| new CallInst(jniProceedPendingExceptionLLVM, "", currentBlock); |
| |
| if (funcType->getReturnType() != Type::VoidTy) |
| new ReturnInst(result, currentBlock); |
| else |
| new ReturnInst(currentBlock); |
| |
| PRINT_DEBUG(JNJVM_COMPILE, 1, COLOR_NORMAL, "end native compile %s\n", |
| compilingMethod->printString()); |
| |
| return llvmFunction; |
| } |
| |
| void JavaJIT::beginSynchronize() { |
| std::vector<Value*> argsSync; |
| if (isVirtual(compilingMethod->access)) { |
| argsSync.push_back(llvmFunction->arg_begin()); |
| } else { |
| Value* arg = new LoadInst(compilingClass->staticVar(compilingClass->isolate->module), "", currentBlock); |
| #ifndef SINGLE_VM |
| if (compilingClass->isolate == Jnjvm::bootstrapVM) { |
| arg = new CallInst(getStaticInstanceLLVM, arg, "", currentBlock); |
| } |
| #endif |
| argsSync.push_back(arg); |
| } |
| new CallInst(aquireObjectLLVM, argsSync.begin(), argsSync.end(), "", currentBlock); |
| } |
| |
| void JavaJIT::endSynchronize() { |
| std::vector<Value*> argsSync; |
| if (isVirtual(compilingMethod->access)) { |
| argsSync.push_back(llvmFunction->arg_begin()); |
| } else { |
| Value* arg = new LoadInst(compilingClass->staticVar(compilingClass->isolate->module), "", currentBlock); |
| #ifndef SINGLE_VM |
| if (compilingClass->isolate == Jnjvm::bootstrapVM) { |
| arg = new CallInst(getStaticInstanceLLVM, arg, "", currentBlock); |
| } |
| #endif |
| argsSync.push_back(arg); |
| } |
| new CallInst(releaseObjectLLVM, argsSync.begin(), argsSync.end(), "", currentBlock); |
| } |
| |
| |
| Instruction* JavaJIT::inlineCompile(Function* parentFunction, BasicBlock*& curBB, |
| BasicBlock* endExBlock, |
| std::vector<Value*>& args) { |
| PRINT_DEBUG(JNJVM_COMPILE, 1, COLOR_NORMAL, "inline compile %s\n", |
| compilingMethod->printString()); |
| |
| |
| Attribut* codeAtt = Attribut::lookup(&compilingMethod->attributs, |
| Attribut::codeAttribut); |
| |
| if (!codeAtt) |
| JavaThread::get()->isolate->unknownError("unable to find the code attribut in %s", |
| compilingMethod->printString()); |
| |
| Reader* reader = codeAtt->toReader(compilingClass->bytes, codeAtt); |
| maxStack = reader->readU2(); |
| maxLocals = reader->readU2(); |
| codeLen = reader->readU4(); |
| uint32 start = reader->cursor; |
| |
| reader->seek(codeLen, Reader::SeekCur); |
| |
| const FunctionType *funcType = compilingMethod->llvmType; |
| returnType = funcType->getReturnType(); |
| |
| llvmFunction = parentFunction; |
| currentBlock = curBB; |
| endExceptionBlock = 0; |
| |
| opcodeInfos = (Opinfo*)alloca(codeLen * sizeof(Opinfo)); |
| memset(opcodeInfos, 0, codeLen * sizeof(Opinfo)); |
| for (uint32 i = 0; i < codeLen; ++i) { |
| opcodeInfos[i].exceptionBlock = endExBlock; |
| } |
| |
| for (int i = 0; i < maxLocals; i++) { |
| intLocals.push_back(new AllocaInst(Type::Int32Ty, "", currentBlock)); |
| doubleLocals.push_back(new AllocaInst(Type::DoubleTy, "", currentBlock)); |
| longLocals.push_back(new AllocaInst(Type::Int64Ty, "", currentBlock)); |
| floatLocals.push_back(new AllocaInst(Type::FloatTy, "", currentBlock)); |
| objectLocals.push_back(new AllocaInst(JavaObject::llvmType, "", |
| currentBlock)); |
| } |
| |
| uint32 index = 0; |
| uint32 count = 0; |
| for (std::vector<Value*>::iterator i = args.begin(); |
| count < args.size(); ++i, ++index, ++count) { |
| |
| const Type* cur = (*i)->getType(); |
| |
| if (cur == Type::Int64Ty ){ |
| new StoreInst(*i, longLocals[index], false, currentBlock); |
| ++index; |
| } else if (cur == Type::Int8Ty || cur == Type::Int16Ty) { |
| new StoreInst(new ZExtInst(*i, Type::Int32Ty, "", currentBlock), |
| intLocals[index], false, currentBlock); |
| } else if (cur == Type::Int32Ty) { |
| new StoreInst(*i, intLocals[index], false, currentBlock); |
| } else if (cur == Type::DoubleTy) { |
| new StoreInst(*i, doubleLocals[index], false, currentBlock); |
| ++index; |
| } else if (cur == Type::FloatTy) { |
| new StoreInst(*i, floatLocals[index], false, currentBlock); |
| } else { |
| new StoreInst(*i, objectLocals[index], false, currentBlock); |
| } |
| } |
| |
| exploreOpcodes(&compilingClass->bytes->elements[start], codeLen); |
| |
| endBlock = createBasicBlock("end"); |
| |
| if (returnType != Type::VoidTy) { |
| endNode = new PHINode(returnType, "", endBlock); |
| } |
| |
| compileOpcodes(&compilingClass->bytes->elements[start], codeLen); |
| |
| PRINT_DEBUG(JNJVM_COMPILE, 1, COLOR_NORMAL, "--> end inline compiling %s\n", |
| compilingMethod->printString()); |
| |
| curBB = endBlock; |
| return endNode; |
| |
| } |
| |
| |
| llvm::Function* JavaJIT::javaCompile() { |
| PRINT_DEBUG(JNJVM_COMPILE, 1, COLOR_NORMAL, "compiling %s\n", |
| compilingMethod->printString()); |
| |
| |
| Attribut* codeAtt = Attribut::lookup(&compilingMethod->attributs, |
| Attribut::codeAttribut); |
| |
| if (!codeAtt) |
| JavaThread::get()->isolate->unknownError("unable to find the code attribut in %s", |
| compilingMethod->printString()); |
| |
| Reader* reader = codeAtt->toReader(compilingClass->bytes, codeAtt); |
| maxStack = reader->readU2(); |
| maxLocals = reader->readU2(); |
| codeLen = reader->readU4(); |
| uint32 start = reader->cursor; |
| |
| reader->seek(codeLen, Reader::SeekCur); |
| |
| const FunctionType *funcType = compilingMethod->llvmType; |
| returnType = funcType->getReturnType(); |
| |
| compilingClass->isolate->protectModule->lock(); |
| Function* func = llvmFunction = new llvm::Function(funcType, |
| GlobalValue::ExternalLinkage, |
| compilingMethod->printString(), |
| compilingClass->isolate->module); |
| compilingClass->isolate->protectModule->unlock(); |
| |
| currentBlock = createBasicBlock("start"); |
| endExceptionBlock = createBasicBlock("endExceptionBlock"); |
| unifiedUnreachable = createBasicBlock("unifiedUnreachable"); |
| |
| opcodeInfos = (Opinfo*)alloca(codeLen * sizeof(Opinfo)); |
| memset(opcodeInfos, 0, codeLen * sizeof(Opinfo)); |
| for (uint32 i = 0; i < codeLen; ++i) { |
| opcodeInfos[i].exceptionBlock = endExceptionBlock; |
| } |
| |
| #if JNJVM_EXECUTE > 0 |
| { |
| std::vector<llvm::Value*> args; |
| mvm::jit::protectConstants();//->lock(); |
| args.push_back(ConstantInt::get(Type::Int32Ty, (int64_t)compilingMethod)); |
| mvm::jit::unprotectConstants();//->unlock(); |
| new CallInst(printMethodStartLLVM, args.begin(), args.end(), "", currentBlock); |
| } |
| #endif |
| |
| unsigned nbe = readExceptionTable(reader); |
| |
| for (int i = 0; i < maxLocals; i++) { |
| intLocals.push_back(new AllocaInst(Type::Int32Ty, "", currentBlock)); |
| doubleLocals.push_back(new AllocaInst(Type::DoubleTy, "", currentBlock)); |
| longLocals.push_back(new AllocaInst(Type::Int64Ty, "", currentBlock)); |
| floatLocals.push_back(new AllocaInst(Type::FloatTy, "", currentBlock)); |
| objectLocals.push_back(new AllocaInst(JavaObject::llvmType, "", |
| currentBlock)); |
| } |
| |
| uint32 index = 0; |
| uint32 count = 0; |
| for (Function::arg_iterator i = func->arg_begin(); |
| count < func->arg_size(); ++i, ++index, ++count) { |
| |
| const Type* cur = i->getType(); |
| |
| if (cur == Type::Int64Ty ){ |
| new StoreInst(i, longLocals[index], false, currentBlock); |
| ++index; |
| } else if (cur == Type::Int8Ty || cur == Type::Int16Ty) { |
| new StoreInst(new ZExtInst(i, Type::Int32Ty, "", currentBlock), |
| intLocals[index], false, currentBlock); |
| } else if (cur == Type::Int32Ty) { |
| new StoreInst(i, intLocals[index], false, currentBlock); |
| } else if (cur == Type::DoubleTy) { |
| new StoreInst(i, doubleLocals[index], false, currentBlock); |
| ++index; |
| } else if (cur == Type::FloatTy) { |
| new StoreInst(i, floatLocals[index], false, currentBlock); |
| } else { |
| new StoreInst(i, objectLocals[index], false, currentBlock); |
| } |
| } |
| |
| |
| exploreOpcodes(&compilingClass->bytes->elements[start], codeLen); |
| |
| |
| |
| endBlock = createBasicBlock("end"); |
| |
| if (returnType != Type::VoidTy) { |
| endNode = new PHINode(returnType, "", endBlock); |
| } |
| |
| if (isSynchro(compilingMethod->access)) |
| beginSynchronize(); |
| |
| compileOpcodes(&compilingClass->bytes->elements[start], codeLen); |
| currentBlock = endBlock; |
| |
| if (isSynchro(compilingMethod->access)) |
| endSynchronize(); |
| |
| #if JNJVM_EXECUTE > 0 |
| { |
| std::vector<llvm::Value*> args; |
| mvm::jit::protectConstants();//->lock(); |
| args.push_back(ConstantInt::get(Type::Int32Ty, (int64_t)compilingMethod)); |
| mvm::jit::unprotectConstants();//->unlock(); |
| new CallInst(printMethodEndLLVM, args.begin(), args.end(), "", currentBlock); |
| } |
| #endif |
| |
| if (returnType != Type::VoidTy) |
| new ReturnInst(endNode, endBlock); |
| else |
| new ReturnInst(endBlock); |
| |
| pred_iterator PI = pred_begin(endExceptionBlock); |
| pred_iterator PE = pred_end(endExceptionBlock); |
| if (PI == PE) { |
| endExceptionBlock->eraseFromParent(); |
| } else { |
| CallInst* ptr_eh_ptr = new CallInst(getExceptionLLVM, "eh_ptr", |
| endExceptionBlock); |
| new CallInst(mvm::jit::unwindResume, ptr_eh_ptr, "", endExceptionBlock); |
| new UnreachableInst(endExceptionBlock); |
| } |
| |
| PI = pred_begin(unifiedUnreachable); |
| PE = pred_end(unifiedUnreachable); |
| if (PI == PE) { |
| unifiedUnreachable->eraseFromParent(); |
| } else { |
| new UnreachableInst(unifiedUnreachable); |
| } |
| |
| mvm::jit::runPasses(llvmFunction, JavaThread::get()->perFunctionPasses); |
| |
| /* |
| if (compilingMethod->name == compilingClass->isolate->asciizConstructUTF8("main")) { |
| llvmFunction->print(llvm::cout); |
| void* res = mvm::jit::executionEngine->getPointerToGlobal(llvmFunction); |
| void* base = res; |
| while (base < (void*)((char*)res + ((mvm::Code*)res)->objectSize())) { |
| printf("%08x\t", (unsigned)base); |
| int n= mvm::jit::disassemble((unsigned int *)base); |
| printf("\n"); |
| base= ((void *)((char *)base + n)); |
| } |
| printf("\n"); |
| fflush(stdout); |
| }*/ |
| |
| |
| PRINT_DEBUG(JNJVM_COMPILE, 1, COLOR_NORMAL, "--> end compiling %s\n", |
| compilingMethod->printString()); |
| |
| if (nbe == 0 && codeLen < 50) |
| compilingMethod->canBeInlined = false; |
| |
| return llvmFunction; |
| } |
| |
| |
| unsigned JavaJIT::readExceptionTable(Reader* reader) { |
| uint16 nbe = reader->readU2(); |
| unsigned sync = isSynchro(compilingMethod->access) ? 1 : 0; |
| nbe += sync; |
| JavaCtpInfo* ctpInfo = compilingClass->ctpInfo; |
| if (nbe) { |
| supplLocal = new AllocaInst(JavaObject::llvmType, "exceptionVar", |
| currentBlock); |
| } |
| |
| BasicBlock* realEndExceptionBlock = endExceptionBlock; |
| if (sync) { |
| BasicBlock* synchronizeExceptionBlock = createBasicBlock("synchronizeExceptionBlock"); |
| BasicBlock* trySynchronizeExceptionBlock = createBasicBlock("trySynchronizeExceptionBlock"); |
| realEndExceptionBlock = synchronizeExceptionBlock; |
| std::vector<Value*> argsSync; |
| if (isVirtual(compilingMethod->access)) { |
| argsSync.push_back(llvmFunction->arg_begin()); |
| } else { |
| Value* arg = new LoadInst(compilingClass->staticVar(compilingClass->isolate->module), "", currentBlock); |
| #ifndef SINGLE_VM |
| if (compilingClass->isolate == Jnjvm::bootstrapVM) { |
| arg = new CallInst(getStaticInstanceLLVM, arg, "", currentBlock); |
| } |
| #endif |
| argsSync.push_back(arg); |
| } |
| new CallInst(releaseObjectLLVM, argsSync.begin(), argsSync.end(), "", synchronizeExceptionBlock); |
| new BranchInst(endExceptionBlock, synchronizeExceptionBlock); |
| |
| const PointerType* PointerTy_0 = mvm::jit::ptrType; |
| std::vector<Value*> int32_eh_select_params; |
| Instruction* ptr_eh_ptr = new CallInst(mvm::jit::llvmGetException, "eh_ptr", trySynchronizeExceptionBlock); |
| int32_eh_select_params.push_back(ptr_eh_ptr); |
| int32_eh_select_params.push_back(ConstantExpr::getCast(Instruction::BitCast, mvm::jit::personality, PointerTy_0)); |
| int32_eh_select_params.push_back(mvm::jit::constantPtrNull); |
| new CallInst(mvm::jit::exceptionSelector, int32_eh_select_params.begin(), int32_eh_select_params.end(), "eh_select", trySynchronizeExceptionBlock); |
| new BranchInst(synchronizeExceptionBlock, trySynchronizeExceptionBlock); |
| |
| for (uint16 i = 0; i < codeLen; ++i) { |
| if (opcodeInfos[i].exceptionBlock == endExceptionBlock) { |
| opcodeInfos[i].exceptionBlock = trySynchronizeExceptionBlock; |
| } |
| } |
| } |
| |
| for (uint16 i = 0; i < nbe - sync; ++i) { |
| Exception* ex = gc_new(Exception)(); |
| ex->startpc = reader->readU2(); |
| ex->endpc = reader->readU2(); |
| ex->handlerpc = reader->readU2(); |
| |
| uint16 catche = reader->readU2(); |
| |
| if (catche) { |
| ex->catchClass = (Class*)ctpInfo->loadClass(catche); |
| } else { |
| ex->catchClass = Classpath::newThrowable; |
| } |
| |
| ex->test = createBasicBlock("testException"); |
| |
| // We can do this because readExceptionTable is the first function to be |
| // called after creation of Opinfos |
| for (uint16 i = ex->startpc; i < ex->endpc; ++i) { |
| if (opcodeInfos[i].exceptionBlock == realEndExceptionBlock) { |
| opcodeInfos[i].exceptionBlock = ex->test; |
| } |
| } |
| |
| if (!(opcodeInfos[ex->handlerpc].newBlock)) { |
| opcodeInfos[ex->handlerpc].newBlock = createBasicBlock("handlerException"); |
| } |
| |
| ex->handler = opcodeInfos[ex->handlerpc].newBlock; |
| opcodeInfos[ex->handlerpc].reqSuppl = true; |
| |
| exceptions.push_back(ex); |
| } |
| |
| bool first = true; |
| for (std::vector<Exception*>::iterator i = exceptions.begin(), |
| e = exceptions.end(); i!= e; ++i) { |
| |
| Exception* cur = *i; |
| Exception* next = 0; |
| if (i + 1 != e) { |
| next = *(i + 1); |
| } |
| |
| if (first) { |
| cur->realTest = createBasicBlock("realTestException"); |
| } else { |
| cur->realTest = cur->test; |
| } |
| |
| cur->exceptionPHI = new PHINode(mvm::jit::ptrType, "", cur->realTest); |
| |
| if (next && cur->startpc == next->startpc && cur->endpc == next->endpc) |
| first = false; |
| else |
| first = true; |
| |
| } |
| |
| for (std::vector<Exception*>::iterator i = exceptions.begin(), |
| e = exceptions.end(); i!= e; ++i) { |
| |
| Exception* cur = *i; |
| Exception* next = 0; |
| BasicBlock* bbNext = 0; |
| PHINode* nodeNext = 0; |
| if (i + 1 != e) { |
| next = *(i + 1); |
| if (!(cur->startpc >= next->startpc && cur->endpc <= next->endpc)) { |
| bbNext = realEndExceptionBlock; |
| } else { |
| bbNext = next->realTest; |
| nodeNext = next->exceptionPHI; |
| } |
| } else { |
| bbNext = realEndExceptionBlock; |
| } |
| |
| if (cur->realTest != cur->test) { |
| const PointerType* PointerTy_0 = mvm::jit::ptrType; |
| std::vector<Value*> int32_eh_select_params; |
| Instruction* ptr_eh_ptr = new CallInst(mvm::jit::llvmGetException, "eh_ptr", cur->test); |
| int32_eh_select_params.push_back(ptr_eh_ptr); |
| int32_eh_select_params.push_back(ConstantExpr::getCast(Instruction::BitCast, mvm::jit::personality, PointerTy_0)); |
| int32_eh_select_params.push_back(mvm::jit::constantPtrNull); |
| new CallInst(mvm::jit::exceptionSelector, int32_eh_select_params.begin(), int32_eh_select_params.end(), "eh_select", cur->test); |
| new BranchInst(cur->realTest, cur->test); |
| cur->exceptionPHI->addIncoming(ptr_eh_ptr, cur->test); |
| } |
| |
| Value* cl = new LoadInst(cur->catchClass->llvmVar(compilingClass->isolate->module), "", cur->realTest); |
| Value* cmp = new CallInst(compareExceptionLLVM, cl, "", cur->realTest); |
| new BranchInst(cur->handler, bbNext, cmp, cur->realTest); |
| if (nodeNext) |
| nodeNext->addIncoming(cur->exceptionPHI, cur->realTest); |
| |
| if (cur->handler->empty()) { |
| cur->handlerPHI = new PHINode(mvm::jit::ptrType, "", cur->handler); |
| cur->handlerPHI->addIncoming(cur->exceptionPHI, cur->realTest); |
| Value* exc = new CallInst(getJavaExceptionLLVM, "", cur->handler); |
| new CallInst(clearExceptionLLVM, "", cur->handler); |
| new CallInst(mvm::jit::exceptionBeginCatch, cur->handlerPHI, "tmp8", cur->handler); |
| std::vector<Value*> void_28_params; |
| new CallInst(mvm::jit::exceptionEndCatch, void_28_params.begin(), void_28_params.end(), "", cur->handler); |
| new StoreInst(exc, supplLocal, false, cur->handler); |
| } else { |
| Instruction* insn = cur->handler->begin(); |
| ((PHINode*)insn)->addIncoming(cur->exceptionPHI, cur->realTest); |
| } |
| |
| } |
| |
| return nbe; |
| |
| } |
| |
| void JavaJIT::compareFP(Value* val1, Value* val2, const Type* ty, bool l) { |
| Value* one = mvm::jit::constantOne; |
| Value* zero = mvm::jit::constantZero; |
| Value* minus = mvm::jit::constantMinusOne; |
| |
| Value* c = new FCmpInst(FCmpInst::FCMP_UGT, val1, val2, "", currentBlock); |
| Value* r = new SelectInst(c, one, zero, "", currentBlock); |
| c = new FCmpInst(FCmpInst::FCMP_ULT, val1, val2, "", currentBlock); |
| r = new SelectInst(c, minus, r, "", currentBlock); |
| c = new FCmpInst(FCmpInst::FCMP_UNO, val1, val2, "", currentBlock); |
| r = new SelectInst(c, l ? one : minus, r, "", currentBlock); |
| |
| push(r, AssessorDesc::dInt); |
| |
| } |
| |
| void JavaJIT::_ldc(uint16 index) { |
| JavaCtpInfo* ctpInfo = compilingClass->ctpInfo; |
| uint8 type = ctpInfo->typeAt(index); |
| |
| if (type == JavaCtpInfo::ConstantString) { |
| Value* toPush = 0; |
| if (ctpInfo->ctpRes[index] == 0) { |
| compilingClass->aquire(); |
| if (ctpInfo->ctpRes[index] == 0) { |
| const UTF8* utf8 = ctpInfo->UTF8At(ctpInfo->ctpDef[index]); |
| void* val = 0; |
| GlobalVariable* gv = 0; |
| #ifndef SINGLE_VM |
| if (compilingClass->isolate != Jnjvm::bootstrapVM) { |
| #endif |
| val = compilingClass->isolate->UTF8ToStr(utf8); |
| compilingClass->isolate->protectModule->lock(); |
| gv = |
| new GlobalVariable(JavaObject::llvmType, false, |
| GlobalValue::ExternalLinkage, |
| constantJavaObjectNull, "", |
| compilingClass->isolate->module); |
| compilingClass->isolate->protectModule->unlock(); |
| #ifndef SINGLE_VM |
| } else { |
| val = (void*)utf8; |
| compilingClass->isolate->protectModule->lock(); |
| gv = |
| new GlobalVariable(UTF8::llvmType, false, |
| GlobalValue::ExternalLinkage, |
| constantUTF8Null, "", |
| compilingClass->isolate->module); |
| compilingClass->isolate->protectModule->unlock(); |
| } |
| #endif |
| |
| // TODO: put an initializer in here |
| void* ptr = mvm::jit::executionEngine->getPointerToGlobal(gv); |
| GenericValue Val = GenericValue(val); |
| llvm::GenericValue * Ptr = (llvm::GenericValue*)ptr; |
| mvm::jit::executionEngine->StoreValueToMemory(Val, Ptr, JavaObject::llvmType); |
| toPush = new LoadInst(gv, "", currentBlock); |
| ctpInfo->ctpRes[index] = gv; |
| compilingClass->release(); |
| } else { |
| compilingClass->release(); |
| toPush = new LoadInst((GlobalVariable*)ctpInfo->ctpRes[index], "", currentBlock); |
| } |
| } else { |
| toPush = new LoadInst((GlobalVariable*)ctpInfo->ctpRes[index], "", currentBlock); |
| } |
| #ifndef SINGLE_VM |
| if (compilingClass->isolate == Jnjvm::bootstrapVM) |
| push(new CallInst(runtimeUTF8ToStrLLVM, toPush, "", currentBlock), AssessorDesc::dRef); |
| else |
| #endif |
| push(toPush, AssessorDesc::dRef); |
| } else if (type == JavaCtpInfo::ConstantLong) { |
| mvm::jit::protectConstants();//->lock(); |
| push(ConstantInt::get(Type::Int64Ty, ctpInfo->LongAt(index)), AssessorDesc::dLong); |
| mvm::jit::unprotectConstants();//->unlock(); |
| } else if (type == JavaCtpInfo::ConstantDouble) { |
| mvm::jit::protectConstants();//->lock(); |
| push(ConstantFP::get(Type::DoubleTy, APFloat(ctpInfo->DoubleAt(index))), AssessorDesc::dDouble); |
| mvm::jit::unprotectConstants();//->unlock(); |
| } else if (type == JavaCtpInfo::ConstantInteger) { |
| mvm::jit::protectConstants();//->lock(); |
| push(ConstantInt::get(Type::Int32Ty, ctpInfo->IntegerAt(index)), AssessorDesc::dInt); |
| mvm::jit::unprotectConstants();//->unlock(); |
| } else if (type == JavaCtpInfo::ConstantFloat) { |
| mvm::jit::protectConstants();//->lock(); |
| push(ConstantFP::get(Type::FloatTy, APFloat(ctpInfo->FloatAt(index))), AssessorDesc::dFloat); |
| mvm::jit::unprotectConstants();//->unlock(); |
| } else if (type == JavaCtpInfo::ConstantClass) { |
| assert(0 && "implement ConstantClass in ldc!"); |
| } else { |
| JavaThread::get()->isolate->unknownError("unknown type %d", type); |
| } |
| } |
| |
| void JavaJIT::JITVerifyNull(Value* obj) { |
| |
| JavaJIT* jit = this; |
| Constant* zero = constantJavaObjectNull; |
| Value* test = new ICmpInst(ICmpInst::ICMP_EQ, obj, zero, "", |
| jit->currentBlock); |
| |
| BasicBlock* exit = jit->createBasicBlock("verifyNullExit"); |
| BasicBlock* cont = jit->createBasicBlock("verifyNullCont"); |
| |
| new BranchInst(exit, cont, test, jit->currentBlock); |
| std::vector<Value*> args; |
| if (currentExceptionBlock != endExceptionBlock) { |
| new InvokeInst(JavaJIT::nullPointerExceptionLLVM, unifiedUnreachable, |
| currentExceptionBlock, args.begin(), |
| args.end(), "", exit); |
| } else { |
| new CallInst(JavaJIT::nullPointerExceptionLLVM, args.begin(), |
| args.end(), "", exit); |
| new UnreachableInst(exit); |
| } |
| |
| |
| jit->currentBlock = cont; |
| |
| } |
| |
| Value* JavaJIT::verifyAndComputePtr(Value* obj, Value* index, |
| const Type* arrayType, bool verif) { |
| JITVerifyNull(obj); |
| |
| if (index->getType() != Type::Int32Ty) { |
| index = new SExtInst(index, Type::Int32Ty, "", currentBlock); |
| } |
| |
| if (true) { |
| Value* size = arraySize(obj); |
| |
| Value* cmp = new ICmpInst(ICmpInst::ICMP_ULT, index, size, "", currentBlock); |
| |
| BasicBlock* ifTrue = createBasicBlock("true verifyAndComputePtr"); |
| BasicBlock* ifFalse = createBasicBlock("false verifyAndComputePtr"); |
| |
| branch(cmp, ifTrue, ifFalse, currentBlock); |
| |
| std::vector<Value*>args; |
| args.push_back(obj); |
| args.push_back(index); |
| if (currentExceptionBlock != endExceptionBlock) { |
| new InvokeInst(JavaJIT::indexOutOfBoundsExceptionLLVM, unifiedUnreachable, |
| currentExceptionBlock, args.begin(), |
| args.end(), "", ifFalse); |
| } else { |
| new CallInst(JavaJIT::indexOutOfBoundsExceptionLLVM, args.begin(), |
| args.end(), "", ifFalse); |
| new UnreachableInst(ifFalse); |
| } |
| |
| currentBlock = ifTrue; |
| } |
| |
| Constant* zero = mvm::jit::constantZero; |
| Value* val = new BitCastInst(obj, arrayType, "", currentBlock); |
| |
| std::vector<Value*> indexes; //[3]; |
| indexes.push_back(zero); |
| indexes.push_back(JavaArray::elementsOffset()); |
| indexes.push_back(index); |
| Value* ptr = new GetElementPtrInst(val, indexes.begin(), indexes.end(), |
| "", currentBlock); |
| |
| return ptr; |
| |
| } |
| |
| void JavaJIT::setCurrentBlock(BasicBlock* newBlock) { |
| |
| std::vector< std::pair<Value*, const AssessorDesc*> > newStack; |
| uint32 index = 0; |
| for (BasicBlock::iterator i = newBlock->begin(), e = newBlock->end(); i != e; |
| ++i, ++index) { |
| // case 2 happens with handlers |
| if (!(isa<PHINode>(i)) || i->getType() == mvm::jit::ptrType) { |
| break; |
| } else { |
| const llvm::Type* type = i->getType(); |
| if (type == Type::Int32Ty || type == Type::Int16Ty || |
| type == Type::Int8Ty) { |
| newStack.push_back(std::make_pair(i, AssessorDesc::dInt)); |
| } else { |
| newStack.push_back(std::make_pair(i, stack[index].second)); |
| } |
| } |
| } |
| |
| stack = newStack; |
| currentBlock = newBlock; |
| } |
| |
| static void testPHINodes(BasicBlock* dest, BasicBlock* insert, JavaJIT* jit) { |
| if(dest->empty()) { |
| for (std::vector< std::pair<Value*, const AssessorDesc*> >::iterator i = jit->stack.begin(), |
| e = jit->stack.end(); i!= e; ++i) { |
| Value* cur = i->first; |
| const AssessorDesc* func = i->second; |
| PHINode* node = 0; |
| if (func == AssessorDesc::dChar || func == AssessorDesc::dBool) { |
| node = new PHINode(Type::Int32Ty, "", dest); |
| cur = new ZExtInst(cur, Type::Int32Ty, "", jit->currentBlock); |
| } else if (func == AssessorDesc::dByte || func == AssessorDesc::dShort) { |
| node = new PHINode(Type::Int32Ty, "", dest); |
| cur = new SExtInst(cur, Type::Int32Ty, "", jit->currentBlock); |
| } else { |
| node = new PHINode(cur->getType(), "", dest); |
| } |
| node->addIncoming(cur, insert); |
| } |
| } else { |
| std::vector< std::pair<Value*, const AssessorDesc*> >::iterator stackit = jit->stack.begin(); |
| for (BasicBlock::iterator i = dest->begin(), e = dest->end(); i != e; |
| ++i) { |
| if (!(isa<PHINode>(i))) { |
| break; |
| } else { |
| Instruction* ins = i; |
| Value* cur = stackit->first; |
| const AssessorDesc* func = stackit->second; |
| |
| if (func == AssessorDesc::dChar || func == AssessorDesc::dBool) { |
| cur = new ZExtInst(cur, Type::Int32Ty, "", jit->currentBlock); |
| } else if (func == AssessorDesc::dByte || func == AssessorDesc::dShort) { |
| cur = new SExtInst(cur, Type::Int32Ty, "", jit->currentBlock); |
| } |
| |
| ((PHINode*)ins)->addIncoming(cur, insert); |
| ++stackit; |
| } |
| } |
| } |
| } |
| |
| void JavaJIT::branch(llvm::BasicBlock* dest, llvm::BasicBlock* insert) { |
| testPHINodes(dest, insert, this); |
| new BranchInst(dest, insert); |
| } |
| |
| void JavaJIT::branch(llvm::Value* test, llvm::BasicBlock* ifTrue, |
| llvm::BasicBlock* ifFalse, llvm::BasicBlock* insert) { |
| testPHINodes(ifTrue, insert, this); |
| testPHINodes(ifFalse, insert, this); |
| new BranchInst(ifTrue, ifFalse, test, insert); |
| } |
| |
| void JavaJIT::makeArgs(FunctionType::param_iterator it, |
| uint32 index, std::vector<Value*>& Args, uint32 nb) { |
| Args.reserve(nb + 2); |
| Value* args[nb]; |
| for (sint32 i = nb - 1; i >= 0; --i) { |
| it--; |
| if (it->get() == Type::Int64Ty || it->get() == Type::DoubleTy) { |
| pop(); |
| } |
| const AssessorDesc* func = topFunc(); |
| Value* tmp = pop(); |
| |
| const Type* type = it->get(); |
| if (tmp->getType() != type) { // int8 or int16 |
| if (type == Type::Int32Ty) { |
| if (func == AssessorDesc::dChar) { |
| tmp = new ZExtInst(tmp, type, "", currentBlock); |
| } else { |
| tmp = new SExtInst(tmp, type, "", currentBlock); |
| } |
| } else { |
| tmp = new TruncInst(tmp, type, "", currentBlock); |
| } |
| } |
| args[i] = tmp; |
| |
| } |
| |
| for (uint32 i = 0; i < nb; ++i) { |
| Args.push_back(args[i]); |
| } |
| |
| } |
| |
| Instruction* JavaJIT::lowerMathOps(const UTF8* name, |
| std::vector<Value*>& args) { |
| if (name == Jnjvm::abs) { |
| const Type* Ty = args[0]->getType(); |
| if (Ty == Type::Int32Ty) { |
| Constant* const_int32_9 = mvm::jit::constantZero; |
| ConstantInt* const_int32_10 = mvm::jit::constantMinusOne; |
| BinaryOperator* int32_tmpneg = BinaryOperator::create(Instruction::Sub, const_int32_9, args[0], "tmpneg", currentBlock); |
| ICmpInst* int1_abscond = new ICmpInst(ICmpInst::ICMP_SGT, args[0], const_int32_10, "abscond", currentBlock); |
| return new SelectInst(int1_abscond, args[0], int32_tmpneg, "abs", currentBlock); |
| } else if (Ty == Type::Int64Ty) { |
| Constant* const_int64_9 = mvm::jit::constantLongZero; |
| ConstantInt* const_int64_10 = mvm::jit::constantLongMinusOne; |
| BinaryOperator* int64_tmpneg = BinaryOperator::create(Instruction::Sub, const_int64_9, args[0], "tmpneg", currentBlock); |
| ICmpInst* int1_abscond = new ICmpInst(ICmpInst::ICMP_SGT, args[0], const_int64_10, "abscond", currentBlock); |
| return new SelectInst(int1_abscond, args[0], int64_tmpneg, "abs", currentBlock); |
| } else if (Ty == Type::FloatTy) { |
| return new CallInst(mvm::jit::func_llvm_fabs_f32, args[0], "tmp1", currentBlock); |
| } else if (Ty == Type::DoubleTy) { |
| return new CallInst(mvm::jit::func_llvm_fabs_f64, args[0], "tmp1", currentBlock); |
| } |
| } else if (name == Jnjvm::sqrt) { |
| return new CallInst(mvm::jit::func_llvm_sqrt_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::sin) { |
| return new CallInst(mvm::jit::func_llvm_sin_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::cos) { |
| return new CallInst(mvm::jit::func_llvm_cos_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::tan) { |
| return new CallInst(mvm::jit::func_llvm_tan_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::asin) { |
| return new CallInst(mvm::jit::func_llvm_asin_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::acos) { |
| return new CallInst(mvm::jit::func_llvm_acos_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::atan) { |
| return new CallInst(mvm::jit::func_llvm_atan_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::atan2) { |
| return new CallInst(mvm::jit::func_llvm_atan2_f64, args.begin(), args.end(), "tmp1", currentBlock); |
| } else if (name == Jnjvm::exp) { |
| return new CallInst(mvm::jit::func_llvm_exp_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::log) { |
| return new CallInst(mvm::jit::func_llvm_log_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::pow) { |
| return new CallInst(mvm::jit::func_llvm_pow_f64, args.begin(), args.end(), "tmp1", currentBlock); |
| } else if (name == Jnjvm::ceil) { |
| return new CallInst(mvm::jit::func_llvm_ceil_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::floor) { |
| return new CallInst(mvm::jit::func_llvm_floor_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::rint) { |
| return new CallInst(mvm::jit::func_llvm_rint_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::cbrt) { |
| return new CallInst(mvm::jit::func_llvm_cbrt_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::cosh) { |
| return new CallInst(mvm::jit::func_llvm_cosh_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::expm1) { |
| return new CallInst(mvm::jit::func_llvm_expm1_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::hypot) { |
| return new CallInst(mvm::jit::func_llvm_hypot_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::log10) { |
| return new CallInst(mvm::jit::func_llvm_log10_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::log1p) { |
| return new CallInst(mvm::jit::func_llvm_log1p_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::sinh) { |
| return new CallInst(mvm::jit::func_llvm_sinh_f64, args[0], "tmp1", currentBlock); |
| } else if (name == Jnjvm::tanh) { |
| return new CallInst(mvm::jit::func_llvm_tanh_f64, args[0], "tmp1", currentBlock); |
| } |
| |
| return 0; |
| |
| } |
| |
| |
| Instruction* JavaJIT::invokeInline(JavaMethod* meth, |
| std::vector<Value*>& args) { |
| JavaJIT* jit = gc_new(JavaJIT)(); |
| jit->compilingClass = meth->classDef; |
| jit->compilingMethod = meth; |
| jit->unifiedUnreachable = unifiedUnreachable; |
| jit->inlineMethods = inlineMethods; |
| jit->inlineMethods[meth] = true; |
| Instruction* ret = jit->inlineCompile(llvmFunction, currentBlock, |
| currentExceptionBlock, args); |
| inlineMethods[meth] = false; |
| return ret; |
| } |
| |
| void JavaJIT::invokeSpecial(uint16 index) { |
| JavaCtpInfo* ctpInfo = compilingClass->ctpInfo; |
| JavaMethod* meth = 0; |
| Signdef* signature = 0; |
| const UTF8* name = 0; |
| const UTF8* cl = 0; |
| ctpInfo->nameOfStaticOrSpecialMethod(index, cl, name, signature); |
| llvm::Instruction* val = 0; |
| |
| std::vector<Value*> args; |
| FunctionType::param_iterator it = signature->virtualType->param_end(); |
| makeArgs(it, index, args, signature->nbIn + 1); |
| JITVerifyNull(args[0]); |
| |
| if (cl == Jnjvm::mathName) { |
| val = lowerMathOps(name, args); |
| } |
| |
| if (!val) { |
| Function* func = ctpInfo->infoOfStaticOrSpecialMethod(index, ACC_VIRTUAL, |
| signature, meth); |
| |
| if (meth && meth->canBeInlined && meth != compilingMethod && |
| inlineMethods[meth] == 0) { |
| val = invokeInline(meth, args); |
| } else { |
| val = invoke(func, args, "", currentBlock); |
| } |
| } |
| |
| const llvm::Type* retType = signature->virtualType->getReturnType(); |
| if (retType != Type::VoidTy) { |
| push(val, signature->ret->funcs); |
| if (retType == Type::DoubleTy || retType == Type::Int64Ty) { |
| push(mvm::jit::constantZero, AssessorDesc::dInt); |
| } |
| } |
| |
| } |
| |
| void JavaJIT::invokeStatic(uint16 index) { |
| JavaCtpInfo* ctpInfo = compilingClass->ctpInfo; |
| JavaMethod* meth = 0; |
| Signdef* signature = 0; |
| const UTF8* name = 0; |
| const UTF8* cl = 0; |
| ctpInfo->nameOfStaticOrSpecialMethod(index, cl, name, signature); |
| llvm::Instruction* val = 0; |
| |
| std::vector<Value*> args; // size = [signature->nbIn + 2]; |
| FunctionType::param_iterator it = signature->staticType->param_end(); |
| makeArgs(it, index, args, signature->nbIn); |
| ctpInfo->markAsStaticCall(index); |
| |
| if (cl == Jnjvm::mathName) { |
| val = lowerMathOps(name, args); |
| } |
| |
| if (!val) { |
| Function* func = ctpInfo->infoOfStaticOrSpecialMethod(index, ACC_STATIC, |
| signature, meth); |
| |
| if (meth && meth->canBeInlined && meth != compilingMethod && |
| inlineMethods[meth] == 0) { |
| val = invokeInline(meth, args); |
| } else { |
| val = invoke(func, args, "", currentBlock); |
| } |
| } |
| |
| const llvm::Type* retType = signature->staticType->getReturnType(); |
| if (retType != Type::VoidTy) { |
| push(val, signature->ret->funcs); |
| if (retType == Type::DoubleTy || retType == Type::Int64Ty) { |
| push(mvm::jit::constantZero, AssessorDesc::dInt); |
| } |
| } |
| } |
| |
| Value* JavaJIT::getInitializedClass(uint16 index) { |
| const Type* PtrTy = mvm::jit::ptrType; |
| compilingClass->isolate->protectModule->lock(); |
| GlobalVariable * gv = |
| new GlobalVariable(PtrTy, false, |
| GlobalValue::ExternalLinkage, |
| mvm::jit::constantPtrNull, "", |
| compilingClass->isolate->module); |
| |
| compilingClass->isolate->protectModule->unlock(); |
| |
| Value* arg1 = new LoadInst(gv, "", false, currentBlock); |
| Value* test = new ICmpInst(ICmpInst::ICMP_EQ, arg1, |
| mvm::jit::constantPtrNull, "", currentBlock); |
| |
| BasicBlock* trueCl = createBasicBlock("Cl OK"); |
| BasicBlock* falseCl = createBasicBlock("Cl Not OK"); |
| PHINode* node = new PHINode(PtrTy, "", trueCl); |
| node->addIncoming(arg1, currentBlock); |
| new BranchInst(falseCl, trueCl, test, currentBlock); |
| |
| currentBlock = falseCl; |
| |
| std::vector<Value*> Args; |
| Value* v = |
| new LoadInst(compilingClass->llvmVar(compilingClass->isolate->module), |
| "", currentBlock); |
| Args.push_back(v); |
| mvm::jit::protectConstants(); |
| ConstantInt* CI = ConstantInt::get(Type::Int32Ty, index); |
| mvm::jit::unprotectConstants(); |
| Args.push_back(CI); |
| Args.push_back(gv); |
| Value* res = invoke(newLookupLLVM, Args, "", currentBlock); |
| node->addIncoming(res, currentBlock); |
| |
| new BranchInst(trueCl, currentBlock); |
| currentBlock = trueCl; |
| |
| return node; |
| } |
| |
| void JavaJIT::invokeNew(uint16 index) { |
| JavaCtpInfo* ctpInfo = compilingClass->ctpInfo; |
| ctpInfo->checkInfoOfClass(index); |
| |
| Class* cl = (Class*)(ctpInfo->getMethodClassIfLoaded(index)); |
| Value* val = 0; |
| if (!cl || !cl->isReady()) { |
| Value* node = getInitializedClass(index); |
| val = invoke(doNewUnknownLLVM, node, "", currentBlock); |
| } else { |
| Value* load = new LoadInst(cl->llvmVar(compilingClass->isolate->module), "", currentBlock); |
| val = invoke(doNewLLVM, load, "", currentBlock); |
| // give the real type info, escape analysis uses it |
| new BitCastInst(val, cl->virtualType, "", currentBlock); |
| } |
| |
| push(val, AssessorDesc::dRef); |
| |
| } |
| |
| Value* JavaJIT::arraySize(Value* val) { |
| return new CallInst(arrayLengthLLVM, val, "", currentBlock); |
| /* |
| Value* array = new BitCastInst(val, JavaArray::llvmType, "", currentBlock); |
| std::vector<Value*> args; //size= 2 |
| args.push_back(mvm::jit::constantZero); |
| args.push_back(JavaArray::sizeOffset()); |
| Value* ptr = new GetElementPtrInst(array, args.begin(), args.end(), |
| "", currentBlock); |
| return new LoadInst(ptr, "", currentBlock);*/ |
| } |
| |
| static llvm::Value* fieldGetter(JavaJIT* jit, const Type* type, Value* object, |
| Value* offset) { |
| llvm::Value* objectConvert = new BitCastInst(object, type, "", |
| jit->currentBlock); |
| |
| Constant* zero = mvm::jit::constantZero; |
| std::vector<Value*> args; // size = 2 |
| args.push_back(zero); |
| args.push_back(offset); |
| llvm::Value* ptr = new GetElementPtrInst(objectConvert, args.begin(), |
| args.end(), "", jit->currentBlock); |
| return ptr; |
| } |
| |
| Value* JavaJIT::ldResolved(uint16 index, bool stat, Value* object, |
| const Type* fieldType, const Type* fieldTypePtr) { |
| JavaCtpInfo* info = compilingClass->ctpInfo; |
| |
| JavaField* field = info->lookupField(index, stat); |
| if (field && field->classDef->isReady()) { |
| if (stat) object = new LoadInst(field->classDef->staticVar(compilingClass->isolate->module), "", |
| currentBlock); |
| const Type* type = stat ? field->classDef->staticType : |
| field->classDef->virtualType; |
| |
| #ifndef SINGLE_VM |
| if (stat && field->classDef->isolate == Jnjvm::bootstrapVM) { |
| object = new CallInst(getStaticInstanceLLVM, object, "", currentBlock); |
| } |
| #endif |
| return fieldGetter(this, type, object, field->offset); |
| } else { |
| const Type* Pty = mvm::jit::arrayPtrType; |
| compilingClass->isolate->protectModule->lock(); |
| GlobalVariable* gvStaticInstance = |
| new GlobalVariable(mvm::jit::ptrType, false, |
| GlobalValue::ExternalLinkage, |
| mvm::jit::constantPtrNull, |
| "", compilingClass->isolate->module); |
| |
| |
| Constant* zero = mvm::jit::constantZero; |
| GlobalVariable* gv = |
| new GlobalVariable(Type::Int32Ty, false, GlobalValue::ExternalLinkage, |
| zero, "", compilingClass->isolate->module); |
| compilingClass->isolate->protectModule->unlock(); |
| |
| // set is volatile |
| Value* val = new LoadInst(gv, "", true, currentBlock); |
| Value * cmp = new ICmpInst(ICmpInst::ICMP_NE, val, zero, "", currentBlock); |
| BasicBlock* ifTrue = createBasicBlock("true ldResolved"); |
| BasicBlock* ifFalse = createBasicBlock("false ldResolved"); |
| BasicBlock* endBlock = createBasicBlock("end ldResolved"); |
| PHINode * node = new PHINode(mvm::jit::ptrType, "", endBlock); |
| new BranchInst(ifTrue, ifFalse, cmp, currentBlock); |
| |
| // ---------- In case we already resolved something --------------------- // |
| currentBlock = ifTrue; |
| Value* resPtr = 0; |
| if (object) { |
| Value* ptr = new BitCastInst(object, Pty, "", currentBlock); |
| std::vector<Value*> gepArgs; // size = 1 |
| gepArgs.push_back(zero); |
| gepArgs.push_back(val); |
| resPtr = new GetElementPtrInst(ptr, gepArgs.begin(), gepArgs.end(), |
| "", currentBlock); |
| |
| } else { |
| resPtr = new LoadInst(gvStaticInstance, "", currentBlock); |
| } |
| |
| node->addIncoming(resPtr, currentBlock); |
| new BranchInst(endBlock, currentBlock); |
| |
| // ---------- In case we have to resolve -------------------------------- // |
| currentBlock = ifFalse; |
| std::vector<Value*> args; |
| if (object) { |
| args.push_back(object); |
| } else { |
| args.push_back(constantJavaObjectNull); |
| } |
| args.push_back(new LoadInst(compilingClass->llvmVar(compilingClass->isolate->module), "", |
| currentBlock)); |
| mvm::jit::protectConstants();//->lock(); |
| args.push_back(ConstantInt::get(Type::Int32Ty, index)); |
| mvm::jit::unprotectConstants();//->unlock(); |
| args.push_back(stat ? mvm::jit::constantOne : mvm::jit::constantZero); |
| args.push_back(gvStaticInstance); |
| args.push_back(gv); |
| Value* tmp = invoke(JavaJIT::fieldLookupLLVM, args, "", currentBlock); |
| node->addIncoming(tmp, currentBlock); |
| new BranchInst(endBlock, currentBlock); |
| |
| currentBlock = endBlock;; |
| return new BitCastInst(node, fieldTypePtr, "", currentBlock); |
| } |
| } |
| |
| extern void convertValue(Value*& val, const Type* t1, BasicBlock* currentBlock, bool usign); |
| |
| |
| void JavaJIT::setStaticField(uint16 index) { |
| const AssessorDesc* ass = topFunc(); |
| Value* val = pop(); |
| Typedef* sign = compilingClass->ctpInfo->infoOfField(index); |
| const Type* type = sign->funcs->llvmType; |
| if (type == Type::Int64Ty || type == Type::DoubleTy) { |
| val = pop(); |
| } |
| Value* ptr = ldResolved(index, true, 0, type, sign->funcs->llvmTypePtr); |
| |
| if (type != val->getType()) { // int1, int8, int16 |
| convertValue(val, type, currentBlock, |
| ass == AssessorDesc::dChar || ass == AssessorDesc::dBool); |
| } |
| |
| new StoreInst(val, ptr, false, currentBlock); |
| } |
| |
| void JavaJIT::getStaticField(uint16 index) { |
| Typedef* sign = compilingClass->ctpInfo->infoOfField(index); |
| Value* ptr = ldResolved(index, true, 0, sign->funcs->llvmType, |
| sign->funcs->llvmTypePtr); |
| push(new LoadInst(ptr, "", currentBlock), sign->funcs); |
| const Type* type = sign->funcs->llvmType; |
| if (type == Type::Int64Ty || type == Type::DoubleTy) { |
| push(mvm::jit::constantZero, AssessorDesc::dInt); |
| } |
| } |
| |
| void JavaJIT::setVirtualField(uint16 index) { |
| const AssessorDesc* ass = topFunc(); |
| Value* val = pop(); |
| Typedef* sign = compilingClass->ctpInfo->infoOfField(index); |
| const Type* type = sign->funcs->llvmType; |
| |
| if (type == Type::Int64Ty || type == Type::DoubleTy) { |
| val = pop(); |
| } |
| |
| Value* object = pop(); |
| JITVerifyNull(object); |
| Value* ptr = ldResolved(index, false, object, type, |
| sign->funcs->llvmTypePtr); |
| |
| if (type != val->getType()) { // int1, int8, int16 |
| convertValue(val, type, currentBlock, |
| ass == AssessorDesc::dChar || ass == AssessorDesc::dBool); |
| } |
| |
| new StoreInst(val, ptr, false, currentBlock); |
| } |
| |
| void JavaJIT::getVirtualField(uint16 index) { |
| Typedef* sign = compilingClass->ctpInfo->infoOfField(index); |
| Value* obj = pop(); |
| JITVerifyNull(obj); |
| Value* ptr = ldResolved(index, false, obj, sign->funcs->llvmType, |
| sign->funcs->llvmTypePtr); |
| push(new LoadInst(ptr, "", currentBlock), sign->funcs); |
| const Type* type = sign->funcs->llvmType; |
| if (type == Type::Int64Ty || type == Type::DoubleTy) { |
| push(mvm::jit::constantZero, AssessorDesc::dInt); |
| } |
| } |
| |
| |
| Instruction* JavaJIT::invoke(Value *F, std::vector<llvm::Value*>& args, |
| const char* Name, |
| BasicBlock *InsertAtEnd) { |
| |
| // means: is there a handler for me? |
| if (currentExceptionBlock != endExceptionBlock) { |
| BasicBlock* ifNormal = createBasicBlock("no exception block"); |
| currentBlock = ifNormal; |
| return new InvokeInst(F, ifNormal, currentExceptionBlock, args.begin(), |
| args.end(), Name, InsertAtEnd); |
| } else { |
| return new CallInst(F, args.begin(), args.end(), Name, InsertAtEnd); |
| } |
| } |
| |
| Instruction* JavaJIT::invoke(Value *F, Value* arg1, const char* Name, |
| BasicBlock *InsertAtEnd) { |
| |
| // means: is there a handler for me? |
| if (currentExceptionBlock != endExceptionBlock) { |
| BasicBlock* ifNormal = createBasicBlock("no exception block"); |
| currentBlock = ifNormal; |
| std::vector<Value*> arg; |
| arg.push_back(arg1); |
| return new InvokeInst(F, ifNormal, currentExceptionBlock, arg.begin(), |
| arg.end(), Name, InsertAtEnd); |
| } else { |
| return new CallInst(F, arg1, Name, InsertAtEnd); |
| } |
| } |
| |
| Instruction* JavaJIT::invoke(Value *F, Value* arg1, Value* arg2, |
| const char* Name, BasicBlock *InsertAtEnd) { |
| |
| std::vector<Value*> args; |
| args.push_back(arg1); |
| args.push_back(arg2); |
| |
| // means: is there a handler for me? |
| if (currentExceptionBlock != endExceptionBlock) { |
| BasicBlock* ifNormal = createBasicBlock("no exception block"); |
| currentBlock = ifNormal; |
| return new InvokeInst(F, ifNormal, currentExceptionBlock, args.begin(), |
| args.end(), Name, InsertAtEnd); |
| } else { |
| return new CallInst(F, args.begin(), args.end(), Name, InsertAtEnd); |
| } |
| } |
| |
| Instruction* JavaJIT::invoke(Value *F, const char* Name, |
| BasicBlock *InsertAtEnd) { |
| // means: is there a handler for me? |
| if (currentExceptionBlock != endExceptionBlock) { |
| BasicBlock* ifNormal = createBasicBlock("no exception block"); |
| currentBlock = ifNormal; |
| std::vector<Value*> args; |
| return new InvokeInst(F, ifNormal, currentExceptionBlock, args.begin(), |
| args.end(), Name, InsertAtEnd); |
| } else { |
| return new CallInst(F, Name, InsertAtEnd); |
| } |
| } |
| |
| |