| //===----------- 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 <cstring> |
| |
| #include <llvm/Constants.h> |
| #include <llvm/DerivedTypes.h> |
| #include <llvm/Function.h> |
| #include <llvm/Instructions.h> |
| #include <llvm/Module.h> |
| #include <llvm/Type.h> |
| #include <llvm/Support/CFG.h> |
| |
| #include "mvm/JIT.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 "Reader.h" |
| |
| #include "jnjvm/JnjvmModule.h" |
| #include "jnjvm/JnjvmModuleProvider.h" |
| |
| using namespace jnjvm; |
| using namespace llvm; |
| |
| static bool needsInitialisationCheck(Class* cl, Class* compilingClass) { |
| #ifdef SERVICE |
| return true; |
| #else |
| |
| if (cl->isReadyForCompilation() || |
| (!cl->isInterface() && compilingClass->isAssignableFrom(cl))) { |
| return false; |
| } |
| |
| if (!cl->needsInitialisationCheck()) { |
| if (!cl->isReady()) { |
| cl->setInitializationState(ready); |
| } |
| return false; |
| } |
| |
| return true; |
| #endif |
| } |
| |
| bool JavaJIT::canBeInlined(JavaMethod* meth) { |
| JnjvmClassLoader* loader = meth->classDef->classLoader; |
| return (meth->canBeInlined && |
| meth != compilingMethod && inlineMethods[meth] == 0 && |
| (loader == compilingClass->classLoader || |
| loader == compilingClass->classLoader->bootstrapLoader)); |
| } |
| |
| void JavaJIT::invokeVirtual(uint16 index) { |
| |
| JavaConstantPool* ctpInfo = compilingClass->ctpInfo; |
| CommonClass* cl = 0; |
| JavaMethod* meth = 0; |
| ctpInfo->infoOfMethod(index, ACC_VIRTUAL, cl, meth); |
| |
| if ((cl && isFinal(cl->access)) || |
| (meth && (isFinal(meth->access) || isPrivate(meth->access)))) { |
| return invokeSpecial(index); |
| } |
| |
| // If the method is in fact a method defined in an interface, |
| // call invokeInterface instead. |
| if (meth && isInterface(meth->classDef->access)) { |
| return invokeInterface(index, true); |
| } |
| |
| const UTF8* name = 0; |
| Signdef* signature = ctpInfo->infoOfInterfaceOrVirtualMethod(index, name); |
| |
| Value* obj = objectStack[stack.size() - signature->nbArguments - 1]; |
| JavaObject* source = TheCompiler->getFinalObject(obj); |
| if (source) { |
| return invokeSpecial(index, source->getClass()); |
| } |
| |
| #if !defined(WITHOUT_VTABLE) |
| Typedef* retTypedef = signature->getReturnType(); |
| std::vector<Value*> args; // size = [signature->nbIn + 3]; |
| LLVMSignatureInfo* LSI = TheCompiler->getSignatureInfo(signature); |
| const llvm::FunctionType* virtualType = LSI->getVirtualType(); |
| FunctionType::param_iterator it = virtualType->param_end(); |
| makeArgs(it, index, args, signature->nbArguments + 1); |
| const llvm::Type* retType = virtualType->getReturnType(); |
| |
| JITVerifyNull(args[0]); |
| |
| BasicBlock* endBlock = 0; |
| PHINode* node = 0; |
| #if 0 |
| if (meth && !isAbstract(meth->access)) { |
| Value* cl = CallInst::Create(module->GetClassFunction, args[0], "", |
| currentBlock); |
| Value* cl2 = module->getNativeClass(meth->classDef); |
| if (cl2->getType() != module->JavaCommonClassType) { |
| cl2 = new BitCastInst(cl2, module->JavaCommonClassType, "", currentBlock); |
| } |
| |
| Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, cl, cl2, ""); |
| |
| BasicBlock* trueBlock = createBasicBlock("true virtual invoke"); |
| BasicBlock* falseBlock = createBasicBlock("false virtual invoke"); |
| endBlock = createBasicBlock("end virtual invoke"); |
| BranchInst::Create(trueBlock, falseBlock, test, currentBlock); |
| currentBlock = trueBlock; |
| Value* res = 0; |
| if (canBeInlined(meth)) { |
| res = invokeInline(meth, args); |
| } else { |
| Function* func = module->getMethod(meth); |
| res = invoke(func, args, "", currentBlock); |
| } |
| BranchInst::Create(endBlock, currentBlock); |
| if (retType != Type::getVoidTy(getGlobalContext())) { |
| node = PHINode::Create(virtualType->getReturnType(), "", endBlock); |
| node->addIncoming(res, currentBlock); |
| } |
| currentBlock = falseBlock; |
| } |
| #endif |
| |
| Value* VT = CallInst::Create(module->GetVTFunction, args[0], "", |
| currentBlock); |
| Value* indexes2[2]; |
| indexes2[0] = module->constantZero; |
| |
| #ifdef ISOLATE_SHARING |
| Value* indexesCtp; //[3]; |
| #endif |
| if (meth) { |
| LLVMMethodInfo* LMI = TheCompiler->getMethodInfo(meth); |
| Constant* Offset = LMI->getOffset(); |
| indexes2[1] = Offset; |
| #ifdef ISOLATE_SHARING |
| indexesCtp = ConstantInt::get(Type::getInt32Ty(getGlobalContext()), |
| Offset->getZExtValue() * -1); |
| #endif |
| } else { |
| |
| Value* val = getConstantPoolAt(index, module->VirtualLookupFunction, |
| Type::getInt32Ty(getGlobalContext()), args[0], true); |
| indexes2[1] = val; |
| #ifdef ISOLATE_SHARING |
| Value* mul = BinaryOperator::CreateMul(val, module->constantMinusOne, |
| "", currentBlock); |
| indexesCtp = mul; |
| #endif |
| } |
| |
| Value* FuncPtr = GetElementPtrInst::Create(VT, indexes2, indexes2 + 2, "", |
| currentBlock); |
| |
| Value* Func = new LoadInst(FuncPtr, "", currentBlock); |
| |
| Func = new BitCastInst(Func, LSI->getVirtualPtrType(), "", currentBlock); |
| #ifdef ISOLATE_SHARING |
| Value* CTP = GetElementPtrInst::Create(VT, indexesCtp, "", currentBlock); |
| |
| CTP = new LoadInst(CTP, "", currentBlock); |
| CTP = new BitCastInst(CTP, module->ConstantPoolType, "", currentBlock); |
| args.push_back(CTP); |
| #endif |
| Value* val = invoke(Func, args, "", currentBlock); |
| |
| if (endBlock) { |
| if (node) { |
| node->addIncoming(val, currentBlock); |
| val = node; |
| } |
| BranchInst::Create(endBlock, currentBlock); |
| currentBlock = endBlock; |
| } |
| |
| if (retType != Type::getVoidTy(getGlobalContext())) { |
| push(val, retTypedef->isUnsigned()); |
| if (retType == Type::getDoubleTy(getGlobalContext()) || retType == Type::getInt64Ty(getGlobalContext())) { |
| push(module->constantZero, false); |
| } |
| } |
| |
| #else |
| return invokeInterface(index); |
| #endif |
| } |
| |
| llvm::Value* JavaJIT::getCurrentThread() { |
| Value* FrameAddr = CallInst::Create(module->llvm_frameaddress, |
| module->constantZero, "", currentBlock); |
| Value* threadId = new PtrToIntInst(FrameAddr, module->pointerSizeType, "", |
| currentBlock); |
| threadId = BinaryOperator::CreateAnd(threadId, module->constantThreadIDMask, |
| "", currentBlock); |
| threadId = new IntToPtrInst(threadId, module->JavaThreadType, "", |
| currentBlock); |
| |
| return threadId; |
| } |
| |
| extern "C" void jnjvmThrowExceptionFromJIT(); |
| |
| llvm::Function* JavaJIT::nativeCompile(intptr_t natPtr) { |
| |
| PRINT_DEBUG(JNJVM_COMPILE, 1, COLOR_NORMAL, "native compile %s.%s\n", |
| UTF8Buffer(compilingClass->name).cString(), |
| UTF8Buffer(compilingMethod->name).cString()); |
| |
| bool stat = isStatic(compilingMethod->access); |
| |
| const FunctionType *funcType = llvmFunction->getFunctionType(); |
| const llvm::Type* returnType = funcType->getReturnType(); |
| |
| bool jnjvm = false; |
| |
| const UTF8* jniConsClName = compilingClass->name; |
| const UTF8* jniConsName = compilingMethod->name; |
| const UTF8* jniConsType = compilingMethod->type; |
| sint32 clen = jniConsClName->size; |
| sint32 mnlen = jniConsName->size; |
| sint32 mtlen = jniConsType->size; |
| |
| char* functionName = (char*)alloca(3 + JNI_NAME_PRE_LEN + |
| ((mnlen + clen + mtlen) << 3)); |
| |
| if (!natPtr) |
| natPtr = compilingClass->classLoader->nativeLookup(compilingMethod, jnjvm, |
| functionName); |
| |
| if (!natPtr && !TheCompiler->isStaticCompiling()) { |
| currentBlock = createBasicBlock("start"); |
| CallInst::Create(module->ThrowExceptionFromJITFunction, "", currentBlock); |
| if (returnType != Type::getVoidTy(getGlobalContext())) |
| ReturnInst::Create(*llvmContext, Constant::getNullValue(returnType), currentBlock); |
| else |
| ReturnInst::Create(*llvmContext, currentBlock); |
| |
| PRINT_DEBUG(JNJVM_COMPILE, 1, COLOR_NORMAL, "end native compile %s.%s\n", |
| UTF8Buffer(compilingClass->name).cString(), |
| UTF8Buffer(compilingMethod->name).cString()); |
| |
| return llvmFunction; |
| } |
| |
| |
| Function* func = llvmFunction; |
| if (jnjvm) { |
| compilingMethod->setCompiledPtr((void*)natPtr, functionName); |
| return llvmFunction; |
| } |
| |
| |
| currentExceptionBlock = endExceptionBlock = 0; |
| currentBlock = createBasicBlock("start"); |
| BasicBlock* executeBlock = createBasicBlock("execute"); |
| endBlock = createBasicBlock("end block"); |
| |
| Constant* sizeB = ConstantInt::get(Type::getInt32Ty(getGlobalContext()), sizeof(jmp_buf)); |
| Value* oldJB = new AllocaInst(module->ptrType, "", currentBlock); |
| Value* newJB = new AllocaInst(Type::getInt8Ty(getGlobalContext()), sizeB, "", currentBlock); |
| |
| // Allocate currentLocalIndexNumber pointer |
| Value* temp = new AllocaInst(Type::getInt32Ty(getGlobalContext()), "", |
| currentBlock); |
| new StoreInst(module->constantZero, temp, false, currentBlock); |
| |
| // Allocate oldCurrentLocalIndexNumber pointer |
| Value* oldCLIN = new AllocaInst(PointerType::getUnqual(Type::getInt32Ty(getGlobalContext())), "", |
| currentBlock); |
| |
| Value* test = CallInst::Create(module->setjmpLLVM, newJB, "", |
| currentBlock); |
| |
| test = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, test, |
| module->constantZero, ""); |
| BranchInst::Create(executeBlock, endBlock, test, currentBlock); |
| |
| if (returnType != Type::getVoidTy(getGlobalContext())) { |
| endNode = PHINode::Create(returnType, "", endBlock); |
| endNode->addIncoming(Constant::getNullValue(returnType), |
| currentBlock); |
| } |
| |
| currentBlock = executeBlock; |
| if (isSynchro(compilingMethod->access)) |
| beginSynchronize(); |
| |
| |
| uint32 nargs = func->arg_size() + 1 + (stat ? 1 : 0); |
| std::vector<Value*> nativeArgs; |
| |
| |
| Value* threadId = getCurrentThread(); |
| |
| Value* geps[2] = { module->constantZero, module->OffsetJNIInThreadConstant }; |
| |
| Value* jniEnv = GetElementPtrInst::Create(threadId, geps, geps + 2, "", |
| currentBlock); |
| |
| jniEnv = new BitCastInst(jniEnv, module->ptrType, "", currentBlock); |
| |
| nativeArgs.push_back(jniEnv); |
| |
| uint32 index = 0; |
| if (stat) { |
| #ifdef ISOLATE_SHARING |
| Value* val = getClassCtp(); |
| Value* cl = CallInst::Create(module->GetClassDelegateePtrFunction, |
| val, "", currentBlock); |
| #else |
| Value* cl = TheCompiler->getJavaClassPtr(compilingClass); |
| #endif |
| nativeArgs.push_back(cl); |
| index = 2; |
| } else { |
| index = 1; |
| } |
| for (Function::arg_iterator i = func->arg_begin(); |
| index < nargs; ++i, ++index) { |
| |
| if (i->getType() == module->JavaObjectType) { |
| BasicBlock* BB = createBasicBlock(""); |
| BasicBlock* NotZero = createBasicBlock(""); |
| const Type* Ty = PointerType::getUnqual(module->JavaObjectType); |
| PHINode* node = PHINode::Create(Ty, "", BB); |
| |
| test = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, i, |
| module->JavaObjectNullConstant, ""); |
| |
| node->addIncoming(Constant::getNullValue(Ty), currentBlock); |
| BranchInst::Create(BB, NotZero, test, currentBlock); |
| |
| currentBlock = NotZero; |
| |
| Value* temp = new AllocaInst(module->JavaObjectType, "", |
| currentBlock); |
| Value* GCArgs[2] = { |
| new BitCastInst(temp, module->ptrPtrType, "", currentBlock), |
| module->constantPtrNull |
| }; |
| |
| if (TheCompiler->useCooperativeGC()) { |
| CallInst::Create(module->llvm_gc_gcroot, GCArgs, GCArgs + 2, "", |
| currentBlock); |
| } |
| |
| new StoreInst(i, temp, false, currentBlock); |
| node->addIncoming(temp, currentBlock); |
| BranchInst::Create(BB, currentBlock); |
| |
| currentBlock = BB; |
| |
| nativeArgs.push_back(node); |
| } else { |
| nativeArgs.push_back(i); |
| } |
| } |
| |
| Value* nativeFunc = TheCompiler->getNativeFunction(compilingMethod, |
| (void*)natPtr); |
| |
| if (TheCompiler->isStaticCompiling()) { |
| Value* Arg = TheCompiler->getMethodInClass(compilingMethod); |
| |
| // If the global variable is null, then load it. |
| BasicBlock* unloadedBlock = createBasicBlock(""); |
| BasicBlock* endBlock = createBasicBlock(""); |
| Value* test = new LoadInst(nativeFunc, "", currentBlock); |
| const llvm::Type* Ty = test->getType(); |
| PHINode* node = PHINode::Create(Ty, "", endBlock); |
| node->addIncoming(test, currentBlock); |
| Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, test, |
| Constant::getNullValue(Ty), ""); |
| BranchInst::Create(unloadedBlock, endBlock, cmp, currentBlock); |
| currentBlock = unloadedBlock; |
| |
| Value* res = CallInst::Create(TheCompiler->NativeLoader, Arg, "", |
| currentBlock); |
| |
| res = new BitCastInst(res, Ty, "", currentBlock); |
| new StoreInst(res, nativeFunc, currentBlock); |
| node->addIncoming(res, currentBlock); |
| BranchInst::Create(endBlock, currentBlock); |
| currentBlock = endBlock; |
| nativeFunc = node; |
| } |
| |
| Value* Args4[4] = { temp, oldCLIN, newJB, oldJB }; |
| |
| CallInst::Create(module->StartJNIFunction, Args4, Args4 + 4, "", |
| currentBlock); |
| |
| Value* FrameAddr = CallInst::Create(module->llvm_frameaddress, |
| module->constantZero, "", currentBlock); |
| |
| // When calling a native method, it may do whatever it wants with the |
| // frame pointer. Therefore make sure it's on the stack. x86_64 has |
| // this problem because it passes first arguments in registers. |
| // Therefore, it was overwriting the frame pointer when entering the |
| // native method. |
| Value* Temp = new AllocaInst(module->ptrType, "", currentBlock); |
| new StoreInst(FrameAddr, Temp, currentBlock); |
| Value* result = llvm::CallInst::Create(nativeFunc, nativeArgs.begin(), |
| nativeArgs.end(), "", currentBlock); |
| |
| if (returnType == module->JavaObjectType) { |
| const Type* Ty = PointerType::getUnqual(module->JavaObjectType); |
| Constant* C = Constant::getNullValue(Ty); |
| Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, result, C, ""); |
| BasicBlock* loadBlock = createBasicBlock(""); |
| |
| endNode->addIncoming(module->JavaObjectNullConstant, currentBlock); |
| BranchInst::Create(endBlock, loadBlock, cmp, currentBlock); |
| |
| currentBlock = loadBlock; |
| result = new LoadInst(result, "", currentBlock); |
| |
| endNode->addIncoming(result, currentBlock); |
| |
| } else if (returnType != Type::getVoidTy(getGlobalContext())) { |
| endNode->addIncoming(result, currentBlock); |
| } |
| |
| BranchInst::Create(endBlock, currentBlock); |
| |
| |
| currentBlock = endBlock; |
| if (isSynchro(compilingMethod->access)) |
| endSynchronize(); |
| |
| Value* Args2[2] = { oldCLIN, oldJB }; |
| |
| CallInst::Create(module->EndJNIFunction, Args2, Args2 + 2, "", currentBlock); |
| |
| if (returnType != Type::getVoidTy(getGlobalContext())) |
| ReturnInst::Create(*llvmContext, endNode, currentBlock); |
| else |
| ReturnInst::Create(*llvmContext, currentBlock); |
| |
| PRINT_DEBUG(JNJVM_COMPILE, 1, COLOR_NORMAL, "end native compile %s.%s\n", |
| UTF8Buffer(compilingClass->name).cString(), |
| UTF8Buffer(compilingMethod->name).cString()); |
| |
| |
| return llvmFunction; |
| } |
| void JavaJIT::monitorEnter(Value* obj) { |
| std::vector<Value*> gep; |
| gep.push_back(module->constantZero); |
| gep.push_back(module->JavaObjectLockOffsetConstant); |
| Value* lockPtr = GetElementPtrInst::Create(obj, gep.begin(), gep.end(), "", |
| currentBlock); |
| lockPtr = new BitCastInst(lockPtr, |
| PointerType::getUnqual(module->pointerSizeType), |
| "", currentBlock); |
| Value* threadId = getCurrentThread(); |
| threadId = new PtrToIntInst(threadId, module->pointerSizeType, "", |
| currentBlock); |
| |
| std::vector<Value*> atomicArgs; |
| atomicArgs.push_back(lockPtr); |
| atomicArgs.push_back(module->constantPtrZero); |
| atomicArgs.push_back(threadId); |
| |
| // Do the atomic compare and swap. |
| Value* atomic = CallInst::Create(module->llvm_atomic_lcs_ptr, |
| atomicArgs.begin(), atomicArgs.end(), "", |
| currentBlock); |
| |
| Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, atomic, |
| module->constantPtrZero, ""); |
| |
| BasicBlock* OK = createBasicBlock("synchronize passed"); |
| BasicBlock* NotOK = createBasicBlock("synchronize did not pass"); |
| BasicBlock* FatLockBB = createBasicBlock("fat lock"); |
| BasicBlock* ThinLockBB = createBasicBlock("thin lock"); |
| |
| BranchInst::Create(OK, NotOK, cmp, currentBlock); |
| |
| currentBlock = NotOK; |
| |
| // The compare and swap did not pass, look if it's a thin lock |
| Value* isThin = BinaryOperator::CreateAnd(atomic, module->constantFatMask, "", |
| currentBlock); |
| cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, isThin, |
| module->constantPtrZero, ""); |
| |
| BranchInst::Create(ThinLockBB, FatLockBB, cmp, currentBlock); |
| |
| // It's a thin lock. Look if we're the owner of this lock. |
| currentBlock = ThinLockBB; |
| Value* idMask = ConstantInt::get(module->pointerSizeType, 0x7FFFFF00); |
| Value* cptMask = ConstantInt::get(module->pointerSizeType, 0xFF); |
| Value* IdInLock = BinaryOperator::CreateAnd(atomic, idMask, "", currentBlock); |
| Value* owner = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, threadId, |
| IdInLock, ""); |
| |
| BasicBlock* OwnerBB = createBasicBlock("owner thread"); |
| |
| BranchInst::Create(OwnerBB, FatLockBB, owner, currentBlock); |
| currentBlock = OwnerBB; |
| |
| // OK, we are the owner, now check if the counter will overflow. |
| Value* count = BinaryOperator::CreateAnd(atomic, cptMask, "", currentBlock); |
| cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_ULT, count, cptMask, ""); |
| |
| BasicBlock* IncCounterBB = createBasicBlock("Increment counter"); |
| BasicBlock* OverflowCounterBB = createBasicBlock("Overflow counter"); |
| |
| BranchInst::Create(IncCounterBB, OverflowCounterBB, cmp, currentBlock); |
| currentBlock = IncCounterBB; |
| |
| // The counter will not overflow, increment it. |
| Value* Add = BinaryOperator::CreateAdd(module->constantPtrOne, atomic, "", |
| currentBlock); |
| new StoreInst(Add, lockPtr, false, currentBlock); |
| BranchInst::Create(OK, currentBlock); |
| |
| currentBlock = OverflowCounterBB; |
| |
| // The counter will overflow, call this function to create a new lock, |
| // lock it 0x101 times, and pass. |
| CallInst::Create(module->OverflowThinLockFunction, obj, "", |
| currentBlock); |
| BranchInst::Create(OK, currentBlock); |
| |
| currentBlock = FatLockBB; |
| |
| // Either it's a fat lock or there is contention. |
| CallInst::Create(module->AquireObjectFunction, obj, "", currentBlock); |
| BranchInst::Create(OK, currentBlock); |
| currentBlock = OK; |
| } |
| |
| void JavaJIT::monitorExit(Value* obj) { |
| std::vector<Value*> gep; |
| gep.push_back(module->constantZero); |
| gep.push_back(module->JavaObjectLockOffsetConstant); |
| Value* lockPtr = GetElementPtrInst::Create(obj, gep.begin(), gep.end(), "", |
| currentBlock); |
| lockPtr = new BitCastInst(lockPtr, |
| PointerType::getUnqual(module->pointerSizeType), |
| "", currentBlock); |
| Value* lock = new LoadInst(lockPtr, "", currentBlock); |
| |
| Value* threadId = getCurrentThread(); |
| threadId = new PtrToIntInst(threadId, module->pointerSizeType, "", |
| currentBlock); |
| |
| Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, lock, threadId, |
| ""); |
| |
| |
| BasicBlock* EndUnlock = createBasicBlock("end unlock"); |
| BasicBlock* LockedOnceBB = createBasicBlock("desynchronize thin lock"); |
| BasicBlock* NotLockedOnceBB = |
| createBasicBlock("simple desynchronize did not pass"); |
| BasicBlock* FatLockBB = createBasicBlock("fat lock"); |
| BasicBlock* ThinLockBB = createBasicBlock("thin lock"); |
| |
| BranchInst::Create(LockedOnceBB, NotLockedOnceBB, cmp, currentBlock); |
| |
| // Locked once, set zero |
| currentBlock = LockedOnceBB; |
| new StoreInst(module->constantPtrZero, lockPtr, false, currentBlock); |
| BranchInst::Create(EndUnlock, currentBlock); |
| |
| currentBlock = NotLockedOnceBB; |
| // Look if the lock is thin. |
| Value* isThin = BinaryOperator::CreateAnd(lock, module->constantFatMask, "", |
| currentBlock); |
| cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, isThin, |
| module->constantPtrZero, ""); |
| |
| BranchInst::Create(ThinLockBB, FatLockBB, cmp, currentBlock); |
| |
| currentBlock = ThinLockBB; |
| |
| // Decrement the counter. |
| Value* Sub = BinaryOperator::CreateSub(lock, module->constantPtrOne, "", |
| currentBlock); |
| new StoreInst(Sub, lockPtr, false, currentBlock); |
| BranchInst::Create(EndUnlock, currentBlock); |
| |
| currentBlock = FatLockBB; |
| |
| // Either it's a fat lock or there is contention. |
| CallInst::Create(module->ReleaseObjectFunction, obj, "", currentBlock); |
| BranchInst::Create(EndUnlock, currentBlock); |
| currentBlock = EndUnlock; |
| } |
| |
| |
| |
| #ifdef ISOLATE_SHARING |
| Value* JavaJIT::getStaticInstanceCtp() { |
| Value* cl = getClassCtp(); |
| Value* indexes[2] = { module->constantZero, module->constantSeven }; |
| Value* arg1 = GetElementPtrInst::Create(cl, indexes, indexes + 2, |
| "", currentBlock); |
| arg1 = new LoadInst(arg1, "", false, currentBlock); |
| return arg1; |
| |
| } |
| |
| Value* JavaJIT::getClassCtp() { |
| Value* indexes = module->constantOne; |
| Value* arg1 = GetElementPtrInst::Create(ctpCache, indexes.begin(), |
| indexes.end(), "", currentBlock); |
| arg1 = new LoadInst(arg1, "", false, currentBlock); |
| arg1 = new BitCastInst(arg1, module->JavaClassType, "", currentBlock); |
| return arg1; |
| } |
| #endif |
| |
| void JavaJIT::beginSynchronize() { |
| Value* obj = 0; |
| if (isVirtual(compilingMethod->access)) { |
| obj = llvmFunction->arg_begin(); |
| } else { |
| obj = TheCompiler->getJavaClass(compilingClass); |
| } |
| monitorEnter(obj); |
| } |
| |
| void JavaJIT::endSynchronize() { |
| Value* obj = 0; |
| if (isVirtual(compilingMethod->access)) { |
| obj = llvmFunction->arg_begin(); |
| } else { |
| obj = TheCompiler->getJavaClass(compilingClass); |
| } |
| monitorExit(obj); |
| } |
| |
| |
| static void removeUnusedLocals(std::vector<AllocaInst*>& locals) { |
| for (std::vector<AllocaInst*>::iterator i = locals.begin(), |
| e = locals.end(); i != e; ++i) { |
| AllocaInst* temp = *i; |
| if (!temp->getNumUses()) { |
| temp->eraseFromParent(); |
| } |
| } |
| } |
| |
| static void removeUnusedObjects(std::vector<AllocaInst*>& objects, |
| JnjvmModule* module, bool coop) { |
| for (std::vector<AllocaInst*>::iterator i = objects.begin(), |
| e = objects.end(); i != e; ++i) { |
| AllocaInst* temp = *i; |
| if (temp->getNumUses()) { |
| if (coop) { |
| Instruction* I = new BitCastInst(temp, module->ptrPtrType, ""); |
| I->insertAfter(temp); |
| Value* GCArgs[2] = { I, module->constantPtrNull }; |
| Instruction* C = CallInst::Create(module->llvm_gc_gcroot, GCArgs, |
| GCArgs + 2, ""); |
| C->insertAfter(I); |
| } |
| } else { |
| temp->eraseFromParent(); |
| } |
| } |
| } |
| |
| Instruction* JavaJIT::inlineCompile(BasicBlock*& curBB, |
| BasicBlock* endExBlock, |
| std::vector<Value*>& args) { |
| PRINT_DEBUG(JNJVM_COMPILE, 1, COLOR_NORMAL, "inline compile %s.%s\n", |
| UTF8Buffer(compilingClass->name).cString(), |
| UTF8Buffer(compilingMethod->name).cString()); |
| |
| Attribut* codeAtt = compilingMethod->lookupAttribut(Attribut::codeAttribut); |
| |
| if (!codeAtt) { |
| fprintf(stderr, "I haven't verified your class file and it's malformed:" |
| " no code attribut found for %s.%s!\n", |
| UTF8Buffer(compilingClass->name).cString(), |
| UTF8Buffer(compilingMethod->name).cString()); |
| abort(); |
| } |
| |
| Reader reader(codeAtt, &(compilingClass->bytes)); |
| uint16 maxStack = reader.readU2(); |
| uint16 maxLocals = reader.readU2(); |
| uint32 codeLen = reader.readU4(); |
| uint32 start = reader.cursor; |
| |
| reader.seek(codeLen, Reader::SeekCur); |
| |
| LLVMMethodInfo* LMI = TheCompiler->getMethodInfo(compilingMethod); |
| assert(LMI); |
| Function* func = LMI->getMethod(); |
| |
| const Type* returnType = func->getReturnType(); |
| endBlock = createBasicBlock("end"); |
| |
| currentBlock = curBB; |
| endExceptionBlock = endExBlock; |
| |
| opcodeInfos = (Opinfo*)alloca(codeLen * sizeof(Opinfo)); |
| memset(opcodeInfos, 0, codeLen * sizeof(Opinfo)); |
| for (uint32 i = 0; i < codeLen; ++i) { |
| opcodeInfos[i].exceptionBlock = endExBlock; |
| } |
| |
| BasicBlock* firstBB = llvmFunction->begin(); |
| |
| if (firstBB->begin() != firstBB->end()) { |
| Instruction* firstInstruction = firstBB->begin(); |
| |
| for (int i = 0; i < maxLocals; i++) { |
| intLocals.push_back(new AllocaInst(Type::getInt32Ty(getGlobalContext()), "", firstInstruction)); |
| doubleLocals.push_back(new AllocaInst(Type::getDoubleTy(getGlobalContext()), "", |
| firstInstruction)); |
| longLocals.push_back(new AllocaInst(Type::getInt64Ty(getGlobalContext()), "", firstInstruction)); |
| floatLocals.push_back(new AllocaInst(Type::getFloatTy(getGlobalContext()), "", firstInstruction)); |
| objectLocals.push_back(new AllocaInst(module->JavaObjectType, "", |
| firstInstruction)); |
| } |
| for (int i = 0; i < maxStack; i++) { |
| objectStack.push_back(new AllocaInst(module->JavaObjectType, "", |
| firstInstruction)); |
| intStack.push_back(new AllocaInst(Type::getInt32Ty(getGlobalContext()), "", firstInstruction)); |
| doubleStack.push_back(new AllocaInst(Type::getDoubleTy(getGlobalContext()), "", |
| firstInstruction)); |
| longStack.push_back(new AllocaInst(Type::getInt64Ty(getGlobalContext()), "", firstInstruction)); |
| floatStack.push_back(new AllocaInst(Type::getFloatTy(getGlobalContext()), "", firstInstruction)); |
| } |
| |
| } else { |
| for (int i = 0; i < maxLocals; i++) { |
| intLocals.push_back(new AllocaInst(Type::getInt32Ty(getGlobalContext()), "", firstBB)); |
| doubleLocals.push_back(new AllocaInst(Type::getDoubleTy(getGlobalContext()), "", firstBB)); |
| longLocals.push_back(new AllocaInst(Type::getInt64Ty(getGlobalContext()), "", firstBB)); |
| floatLocals.push_back(new AllocaInst(Type::getFloatTy(getGlobalContext()), "", firstBB)); |
| objectLocals.push_back(new AllocaInst(module->JavaObjectType, "", |
| firstBB)); |
| } |
| |
| for (int i = 0; i < maxStack; i++) { |
| objectStack.push_back(new AllocaInst(module->JavaObjectType, "", |
| firstBB)); |
| intStack.push_back(new AllocaInst(Type::getInt32Ty(getGlobalContext()), "", firstBB)); |
| doubleStack.push_back(new AllocaInst(Type::getDoubleTy(getGlobalContext()), "", firstBB)); |
| longStack.push_back(new AllocaInst(Type::getInt64Ty(getGlobalContext()), "", firstBB)); |
| floatStack.push_back(new AllocaInst(Type::getFloatTy(getGlobalContext()), "", firstBB)); |
| } |
| } |
| |
| |
| uint32 index = 0; |
| uint32 count = 0; |
| #if defined(ISOLATE_SHARING) |
| uint32 max = args.size() - 2; |
| #else |
| uint32 max = args.size(); |
| #endif |
| Signdef* sign = compilingMethod->getSignature(); |
| Typedef* const* arguments = sign->getArgumentsType(); |
| uint32 type = 0; |
| std::vector<Value*>::iterator i = args.begin(); |
| |
| if (isVirtual(compilingMethod->access)) { |
| new StoreInst(*i, objectLocals[0], false, currentBlock); |
| ++i; |
| ++index; |
| ++count; |
| } |
| |
| |
| for (;count < max; ++i, ++index, ++count, ++type) { |
| |
| const Typedef* cur = arguments[type]; |
| const Type* curType = (*i)->getType(); |
| |
| if (curType == Type::getInt64Ty(getGlobalContext())){ |
| new StoreInst(*i, longLocals[index], false, currentBlock); |
| ++index; |
| } else if (cur->isUnsigned()) { |
| new StoreInst(new ZExtInst(*i, Type::getInt32Ty(getGlobalContext()), "", currentBlock), |
| intLocals[index], false, currentBlock); |
| } else if (curType == Type::getInt8Ty(getGlobalContext()) || curType == Type::getInt16Ty(getGlobalContext())) { |
| new StoreInst(new SExtInst(*i, Type::getInt32Ty(getGlobalContext()), "", currentBlock), |
| intLocals[index], false, currentBlock); |
| } else if (curType == Type::getInt32Ty(getGlobalContext())) { |
| new StoreInst(*i, intLocals[index], false, currentBlock); |
| } else if (curType == Type::getDoubleTy(getGlobalContext())) { |
| new StoreInst(*i, doubleLocals[index], false, currentBlock); |
| ++index; |
| } else if (curType == Type::getFloatTy(getGlobalContext())) { |
| new StoreInst(*i, floatLocals[index], false, currentBlock); |
| } else { |
| new StoreInst(*i, objectLocals[index], false, currentBlock); |
| } |
| } |
| |
| readExceptionTable(reader, codeLen); |
| |
| exploreOpcodes(&compilingClass->bytes->elements[start], codeLen); |
| nbEnveloppes = 0; |
| |
| if (returnType != Type::getVoidTy(getGlobalContext())) { |
| endNode = PHINode::Create(returnType, "", endBlock); |
| } |
| |
| compileOpcodes(&compilingClass->bytes->elements[start], codeLen); |
| |
| PRINT_DEBUG(JNJVM_COMPILE, 1, COLOR_NORMAL, |
| "--> end inline compiling %s.%s\n", |
| UTF8Buffer(compilingClass->name).cString(), |
| UTF8Buffer(compilingMethod->name).cString()); |
| |
| curBB = endBlock; |
| |
| |
| removeUnusedLocals(intLocals); |
| removeUnusedLocals(doubleLocals); |
| removeUnusedLocals(floatLocals); |
| removeUnusedLocals(longLocals); |
| removeUnusedLocals(intStack); |
| removeUnusedLocals(doubleStack); |
| removeUnusedLocals(floatStack); |
| removeUnusedLocals(longStack); |
| |
| removeUnusedObjects(objectLocals, module, TheCompiler->useCooperativeGC()); |
| removeUnusedObjects(objectStack, module, TheCompiler->useCooperativeGC()); |
| |
| |
| return endNode; |
| |
| } |
| |
| llvm::Function* JavaJIT::javaCompile() { |
| PRINT_DEBUG(JNJVM_COMPILE, 1, COLOR_NORMAL, "compiling %s.%s\n", |
| UTF8Buffer(compilingClass->name).cString(), |
| UTF8Buffer(compilingMethod->name).cString()); |
| |
| |
| Attribut* codeAtt = compilingMethod->lookupAttribut(Attribut::codeAttribut); |
| |
| if (!codeAtt) { |
| fprintf(stderr, "I haven't verified your class file and it's malformed:" |
| " no code attribut found for %s.%s!\n", |
| UTF8Buffer(compilingClass->name).cString(), |
| UTF8Buffer(compilingMethod->name).cString()); |
| abort(); |
| } |
| |
| Reader reader(codeAtt, &(compilingClass->bytes)); |
| uint16 maxStack = reader.readU2(); |
| uint16 maxLocals = reader.readU2(); |
| uint32 codeLen = reader.readU4(); |
| uint32 start = reader.cursor; |
| |
| reader.seek(codeLen, Reader::SeekCur); |
| |
| const FunctionType *funcType = llvmFunction->getFunctionType(); |
| const Type* returnType = funcType->getReturnType(); |
| |
| Function* func = llvmFunction; |
| |
| 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 |
| { |
| Value* arg = TheCompiler->getMethodInClass(compilingMethod); |
| |
| llvm::CallInst::Create(module->PrintMethodStartFunction, arg, "", |
| currentBlock); |
| } |
| #endif |
| |
| |
| |
| for (int i = 0; i < maxLocals; i++) { |
| intLocals.push_back(new AllocaInst(Type::getInt32Ty(getGlobalContext()), "", currentBlock)); |
| doubleLocals.push_back(new AllocaInst(Type::getDoubleTy(getGlobalContext()), "", currentBlock)); |
| longLocals.push_back(new AllocaInst(Type::getInt64Ty(getGlobalContext()), "", currentBlock)); |
| floatLocals.push_back(new AllocaInst(Type::getFloatTy(getGlobalContext()), "", currentBlock)); |
| objectLocals.push_back(new AllocaInst(module->JavaObjectType, "", |
| currentBlock)); |
| } |
| |
| for (int i = 0; i < maxStack; i++) { |
| objectStack.push_back(new AllocaInst(module->JavaObjectType, "", |
| currentBlock)); |
| intStack.push_back(new AllocaInst(Type::getInt32Ty(getGlobalContext()), "", currentBlock)); |
| doubleStack.push_back(new AllocaInst(Type::getDoubleTy(getGlobalContext()), "", currentBlock)); |
| longStack.push_back(new AllocaInst(Type::getInt64Ty(getGlobalContext()), "", currentBlock)); |
| floatStack.push_back(new AllocaInst(Type::getFloatTy(getGlobalContext()), "", currentBlock)); |
| } |
| |
| uint32 index = 0; |
| uint32 count = 0; |
| #if defined(ISOLATE_SHARING) |
| uint32 max = func->arg_size() - 2; |
| #else |
| uint32 max = func->arg_size(); |
| #endif |
| Function::arg_iterator i = func->arg_begin(); |
| Signdef* sign = compilingMethod->getSignature(); |
| Typedef* const* arguments = sign->getArgumentsType(); |
| uint32 type = 0; |
| |
| if (isVirtual(compilingMethod->access)) { |
| new StoreInst(i, objectLocals[0], false, currentBlock); |
| ++i; |
| ++index; |
| ++count; |
| } |
| |
| for (;count < max; ++i, ++index, ++count, ++type) { |
| |
| const Typedef* cur = arguments[type]; |
| const llvm::Type* curType = i->getType(); |
| |
| if (curType == Type::getInt64Ty(getGlobalContext())){ |
| new StoreInst(i, longLocals[index], false, currentBlock); |
| ++index; |
| } else if (cur->isUnsigned()) { |
| new StoreInst(new ZExtInst(i, Type::getInt32Ty(getGlobalContext()), "", currentBlock), |
| intLocals[index], false, currentBlock); |
| } else if (curType == Type::getInt8Ty(getGlobalContext()) || curType == Type::getInt16Ty(getGlobalContext())) { |
| new StoreInst(new SExtInst(i, Type::getInt32Ty(getGlobalContext()), "", currentBlock), |
| intLocals[index], false, currentBlock); |
| } else if (curType == Type::getInt32Ty(getGlobalContext())) { |
| new StoreInst(i, intLocals[index], false, currentBlock); |
| } else if (curType == Type::getDoubleTy(getGlobalContext())) { |
| new StoreInst(i, doubleLocals[index], false, currentBlock); |
| ++index; |
| } else if (curType == Type::getFloatTy(getGlobalContext())) { |
| new StoreInst(i, floatLocals[index], false, currentBlock); |
| } else { |
| new StoreInst(i, objectLocals[index], false, currentBlock); |
| } |
| } |
| |
| #if defined(ISOLATE_SHARING) |
| ctpCache = i; |
| Value* addrCtpCache = new AllocaInst(module->ConstantPoolType, "", |
| currentBlock); |
| /// make it volatile to be sure it's on the stack |
| new StoreInst(ctpCache, addrCtpCache, true, currentBlock); |
| #endif |
| |
| |
| #if defined(SERVICE) |
| JnjvmClassLoader* loader = compilingClass->classLoader; |
| Value* Cmp = 0; |
| Value* threadId = 0; |
| Value* OldIsolateID = 0; |
| Value* IsolateIDPtr = 0; |
| Value* OldIsolate = 0; |
| Value* NewIsolate = 0; |
| Value* IsolatePtr = 0; |
| if (loader != loader->bootstrapLoader && isPublic(compilingMethod->access)) { |
| threadId = getCurrentThread(); |
| |
| IsolateIDPtr = GetElementPtrInst::Create(threadId, module->constantThree, |
| "", currentBlock); |
| const Type* realType = PointerType::getUnqual(module->pointerSizeType); |
| IsolateIDPtr = new BitCastInst(IsolateIDPtr, realType, "", |
| currentBlock); |
| OldIsolateID = new LoadInst(IsolateIDPtr, "", currentBlock); |
| |
| Value* MyID = ConstantInt::get(module->pointerSizeType, |
| loader->getIsolate()->IsolateID); |
| Cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, OldIsolateID, MyID, |
| ""); |
| |
| BasicBlock* EndBB = createBasicBlock("After service check"); |
| BasicBlock* ServiceBB = createBasicBlock("Begin service call"); |
| |
| BranchInst::Create(EndBB, ServiceBB, Cmp, currentBlock); |
| |
| currentBlock = ServiceBB; |
| |
| new StoreInst(MyID, IsolateIDPtr, currentBlock); |
| IsolatePtr = GetElementPtrInst::Create(threadId, module->constantFour, "", |
| currentBlock); |
| |
| OldIsolate = new LoadInst(IsolatePtr, "", currentBlock); |
| NewIsolate = module->getIsolate(loader->getIsolate(), currentBlock); |
| new StoreInst(NewIsolate, IsolatePtr, currentBlock); |
| |
| #if DEBUG |
| Value* GEP[2] = { OldIsolate, NewIsolate }; |
| CallInst::Create(module->ServiceCallStartFunction, GEP, GEP + 2, |
| "", currentBlock); |
| #endif |
| BranchInst::Create(EndBB, currentBlock); |
| currentBlock = EndBB; |
| } |
| #endif |
| |
| readExceptionTable(reader, codeLen); |
| |
| exploreOpcodes(&compilingClass->bytes->elements[start], codeLen); |
| compilingMethod->enveloppes = |
| new (compilingClass->classLoader->allocator, "Enveloppes") |
| Enveloppe[nbEnveloppes]; |
| compilingMethod->nbEnveloppes = nbEnveloppes; |
| nbEnveloppes = 0; |
| |
| endBlock = createBasicBlock("end"); |
| |
| if (returnType != Type::getVoidTy(getGlobalContext())) { |
| endNode = llvm::PHINode::Create(returnType, "", endBlock); |
| } |
| |
| if (isSynchro(compilingMethod->access)) |
| beginSynchronize(); |
| |
| if (TheCompiler->hasExceptionsEnabled()) { |
| // Variables have been allocated and the lock has been taken. Do the stack |
| // check now: if there is an exception, we will go to the lock release code. |
| currentExceptionBlock = opcodeInfos[0].exceptionBlock; |
| Value* FrameAddr = CallInst::Create(module->llvm_frameaddress, |
| module->constantZero, "", currentBlock); |
| FrameAddr = new PtrToIntInst(FrameAddr, module->pointerSizeType, "", |
| currentBlock); |
| Value* stackCheck = |
| BinaryOperator::CreateAnd(FrameAddr, module->constantStackOverflowMask, |
| "", currentBlock); |
| |
| stackCheck = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, stackCheck, |
| module->constantPtrZero, ""); |
| BasicBlock* stackOverflow = createBasicBlock("stack overflow"); |
| BasicBlock* noStackOverflow = createBasicBlock("no stack overflow"); |
| BranchInst::Create(stackOverflow, noStackOverflow, stackCheck, |
| currentBlock); |
| currentBlock = stackOverflow; |
| throwException(module->StackOverflowErrorFunction, 0, 0); |
| currentBlock = noStackOverflow; |
| } |
| |
| if (TheCompiler->useCooperativeGC()) { |
| Value* threadId = getCurrentThread(); |
| |
| Value* GEP[2] = { module->constantZero, |
| module->OffsetDoYieldInThreadConstant }; |
| |
| Value* YieldPtr = GetElementPtrInst::Create(threadId, GEP, GEP + 2, "", |
| currentBlock); |
| |
| Value* Yield = new LoadInst(YieldPtr, "", currentBlock); |
| |
| BasicBlock* continueBlock = createBasicBlock("After safe point"); |
| BasicBlock* yieldBlock = createBasicBlock("In safe point"); |
| BranchInst::Create(yieldBlock, continueBlock, Yield, currentBlock); |
| |
| currentBlock = yieldBlock; |
| CallInst::Create(module->conditionalSafePoint, "", currentBlock); |
| BranchInst::Create(continueBlock, currentBlock); |
| |
| currentBlock = continueBlock; |
| } |
| |
| compileOpcodes(&compilingClass->bytes->elements[start], codeLen); |
| |
| assert(stack.size() == 0 && "Stack not empty after compiling bytecode"); |
| // Fix a javac(?) bug where a method only throws an exception and does |
| // not return. |
| pred_iterator PI = pred_begin(endBlock); |
| pred_iterator PE = pred_end(endBlock); |
| if (PI == PE && returnType != Type::getVoidTy(getGlobalContext())) { |
| Instruction* I = currentBlock->getTerminator(); |
| |
| if (isa<UnreachableInst>(I)) { |
| I->eraseFromParent(); |
| BranchInst::Create(endBlock, currentBlock); |
| endNode->addIncoming(Constant::getNullValue(returnType), |
| currentBlock); |
| } else if (InvokeInst* II = dyn_cast<InvokeInst>(I)) { |
| II->setNormalDest(endBlock); |
| endNode->addIncoming(Constant::getNullValue(returnType), |
| currentBlock); |
| } |
| |
| } |
| currentBlock = endBlock; |
| |
| if (isSynchro(compilingMethod->access)) |
| endSynchronize(); |
| |
| #if JNJVM_EXECUTE > 0 |
| { |
| Value* arg = TheCompiler->getMethodInClass(compilingMethod); |
| CallInst::Create(module->PrintMethodEndFunction, arg, "", currentBlock); |
| } |
| #endif |
| |
| #if defined(SERVICE) |
| if (Cmp) { |
| BasicBlock* EndBB = createBasicBlock("After service check"); |
| BasicBlock* ServiceBB = createBasicBlock("End Service call"); |
| |
| BranchInst::Create(EndBB, ServiceBB, Cmp, currentBlock); |
| |
| currentBlock = ServiceBB; |
| |
| new StoreInst(OldIsolateID, IsolateIDPtr, currentBlock); |
| new StoreInst(OldIsolate, IsolatePtr, currentBlock); |
| |
| #if DEBUG |
| Value* GEP[2] = { OldIsolate, NewIsolate }; |
| CallInst::Create(module->ServiceCallStopFunction, GEP, GEP + 2, |
| "", currentBlock); |
| #endif |
| BranchInst::Create(EndBB, currentBlock); |
| currentBlock = EndBB; |
| } |
| #endif |
| |
| PI = pred_begin(currentBlock); |
| PE = pred_end(currentBlock); |
| if (PI == PE) { |
| currentBlock->eraseFromParent(); |
| } else { |
| if (returnType != Type::getVoidTy(getGlobalContext())) |
| ReturnInst::Create(*llvmContext, endNode, currentBlock); |
| else |
| ReturnInst::Create(*llvmContext, currentBlock); |
| } |
| |
| currentBlock = endExceptionBlock; |
| |
| finishExceptions(); |
| |
| removeUnusedLocals(intLocals); |
| removeUnusedLocals(doubleLocals); |
| removeUnusedLocals(floatLocals); |
| removeUnusedLocals(longLocals); |
| removeUnusedLocals(intStack); |
| removeUnusedLocals(doubleStack); |
| removeUnusedLocals(floatStack); |
| removeUnusedLocals(longStack); |
| |
| removeUnusedObjects(objectLocals, module, TheCompiler->useCooperativeGC()); |
| removeUnusedObjects(objectStack, module, TheCompiler->useCooperativeGC()); |
| |
| PRINT_DEBUG(JNJVM_COMPILE, 1, COLOR_NORMAL, "--> end compiling %s.%s\n", |
| UTF8Buffer(compilingClass->name).cString(), |
| UTF8Buffer(compilingMethod->name).cString()); |
| |
| #ifndef DWARF_EXCEPTIONS |
| if (codeLen < 5 && !callsStackWalker && !TheCompiler->isStaticCompiling()) |
| compilingMethod->canBeInlined = true; |
| #endif |
| |
| return llvmFunction; |
| } |
| |
| void JavaJIT::compareFP(Value* val1, Value* val2, const Type* ty, bool l) { |
| Value* one = module->constantOne; |
| Value* zero = module->constantZero; |
| Value* minus = module->constantMinusOne; |
| |
| Value* c = new FCmpInst(*currentBlock, FCmpInst::FCMP_UGT, val1, val2, ""); |
| Value* r = llvm::SelectInst::Create(c, one, zero, "", currentBlock); |
| c = new FCmpInst(*currentBlock, FCmpInst::FCMP_ULT, val1, val2, ""); |
| r = llvm::SelectInst::Create(c, minus, r, "", currentBlock); |
| c = new FCmpInst(*currentBlock, FCmpInst::FCMP_UNO, val1, val2, ""); |
| r = llvm::SelectInst::Create(c, l ? one : minus, r, "", currentBlock); |
| |
| push(r, false); |
| |
| } |
| |
| void JavaJIT::loadConstant(uint16 index) { |
| JavaConstantPool* ctpInfo = compilingClass->ctpInfo; |
| uint8 type = ctpInfo->typeAt(index); |
| |
| if (type == JavaConstantPool::ConstantString) { |
| #if defined(ISOLATE) |
| abort(); |
| #else |
| |
| if (TheCompiler->isStaticCompiling()) { |
| const UTF8* utf8 = ctpInfo->UTF8At(ctpInfo->ctpDef[index]); |
| JavaString* str = *(compilingClass->classLoader->UTF8ToStr(utf8)); |
| Value* val = TheCompiler->getString(str); |
| push(val, false); |
| } else { |
| JavaString** str = (JavaString**)ctpInfo->ctpRes[index]; |
| if (str) { |
| Value* val = TheCompiler->getStringPtr(str); |
| val = new LoadInst(val, "", currentBlock); |
| push(val, false); |
| } else { |
| // Lookup the constant pool cache |
| const llvm::Type* Ty = PointerType::getUnqual(module->JavaObjectType); |
| Value* val = getConstantPoolAt(index, module->StringLookupFunction, |
| Ty, 0, false); |
| val = new LoadInst(val, "", currentBlock); |
| push(val, false); |
| } |
| } |
| #endif |
| } else if (type == JavaConstantPool::ConstantLong) { |
| push(ConstantInt::get(Type::getInt64Ty(getGlobalContext()), ctpInfo->LongAt(index)), |
| false); |
| } else if (type == JavaConstantPool::ConstantDouble) { |
| push(ConstantFP::get(Type::getDoubleTy(getGlobalContext()), ctpInfo->DoubleAt(index)), |
| false); |
| } else if (type == JavaConstantPool::ConstantInteger) { |
| push(ConstantInt::get(Type::getInt32Ty(getGlobalContext()), ctpInfo->IntegerAt(index)), |
| false); |
| } else if (type == JavaConstantPool::ConstantFloat) { |
| push(ConstantFP::get(Type::getFloatTy(getGlobalContext()), ctpInfo->FloatAt(index)), |
| false); |
| } else if (type == JavaConstantPool::ConstantClass) { |
| UserCommonClass* cl = 0; |
| Value* res = getResolvedCommonClass(index, false, &cl); |
| |
| res = CallInst::Create(module->GetClassDelegateeFunction, res, "", |
| currentBlock); |
| push(res, false); |
| } else { |
| fprintf(stderr, "I haven't verified your class file and it's malformed:" |
| " unknown ldc %d in %s.%s!\n", type, |
| UTF8Buffer(compilingClass->name).cString(), |
| UTF8Buffer(compilingMethod->name).cString()); |
| abort(); |
| } |
| } |
| |
| void JavaJIT::JITVerifyNull(Value* obj) { |
| |
| if (TheCompiler->hasExceptionsEnabled()) { |
| Constant* zero = module->JavaObjectNullConstant; |
| Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, obj, zero, ""); |
| |
| BasicBlock* exit = createBasicBlock("verifyNullExit"); |
| BasicBlock* cont = createBasicBlock("verifyNullCont"); |
| |
| BranchInst::Create(exit, cont, test, currentBlock); |
| currentBlock = exit; |
| throwException(module->NullPointerExceptionFunction, 0, 0); |
| currentBlock = cont; |
| } |
| |
| } |
| |
| Value* JavaJIT::verifyAndComputePtr(Value* obj, Value* index, |
| const Type* arrayType, bool verif) { |
| JITVerifyNull(obj); |
| |
| if (index->getType() != Type::getInt32Ty(getGlobalContext())) { |
| index = new SExtInst(index, Type::getInt32Ty(getGlobalContext()), "", currentBlock); |
| } |
| |
| if (TheCompiler->hasExceptionsEnabled()) { |
| Value* size = arraySize(obj); |
| |
| Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_ULT, index, size, |
| ""); |
| |
| BasicBlock* ifTrue = createBasicBlock("true verifyAndComputePtr"); |
| BasicBlock* ifFalse = createBasicBlock("false verifyAndComputePtr"); |
| |
| BranchInst::Create(ifTrue, ifFalse, cmp, currentBlock); |
| |
| currentBlock = ifFalse; |
| Value* args[2] = { obj, index }; |
| throwException(module->IndexOutOfBoundsExceptionFunction, args, 2); |
| currentBlock = ifTrue; |
| } |
| |
| Constant* zero = module->constantZero; |
| Value* val = new BitCastInst(obj, arrayType, "", currentBlock); |
| |
| Value* indexes[3] = { zero, module->JavaArrayElementsOffsetConstant, index }; |
| Value* ptr = GetElementPtrInst::Create(val, indexes, indexes + 3, "", |
| currentBlock); |
| |
| return ptr; |
| |
| } |
| |
| void JavaJIT::makeArgs(FunctionType::param_iterator it, |
| uint32 index, std::vector<Value*>& Args, uint32 nb) { |
| #if defined(ISOLATE_SHARING) |
| nb += 1; |
| #endif |
| Args.reserve(nb + 2); |
| Value** args = (Value**)alloca(nb*sizeof(Value*)); |
| #if defined(ISOLATE_SHARING) |
| args[nb - 1] = isolateLocal; |
| sint32 start = nb - 2; |
| it--; |
| it--; |
| #else |
| sint32 start = nb - 1; |
| #endif |
| for (sint32 i = start; i >= 0; --i) { |
| it--; |
| if (it->get() == Type::getInt64Ty(getGlobalContext()) || it->get() == Type::getDoubleTy(getGlobalContext())) { |
| pop(); |
| } |
| bool unsign = topIsUnsigned(); |
| Value* tmp = pop(); |
| |
| const Type* type = it->get(); |
| if (tmp->getType() != type) { // int8 or int16 |
| convertValue(tmp, type, currentBlock, unsign); |
| } |
| args[i] = tmp; |
| |
| } |
| |
| for (uint32 i = 0; i < nb; ++i) { |
| Args.push_back(args[i]); |
| } |
| |
| } |
| |
| void JavaJIT::addFakePHINodes(BasicBlock* dest, BasicBlock* insert) { |
| if(dest->empty()) { |
| for (std::vector<StackTypeInfo>::iterator i = stack.begin(), |
| e = stack.end(); i!= e; ++i) { |
| switch (*i) { |
| case Int : { |
| PHINode* node = PHINode::Create(Type::getInt32Ty(getGlobalContext()), "", dest); |
| node->addIncoming(Constant::getNullValue(Type::getInt32Ty(getGlobalContext())), insert); |
| break; |
| } |
| case Float : { |
| PHINode* node = PHINode::Create(Type::getFloatTy(getGlobalContext()), "", dest); |
| node->addIncoming(Constant::getNullValue(Type::getFloatTy(getGlobalContext())), insert); |
| break; |
| } |
| case Double : { |
| PHINode* node = PHINode::Create(Type::getDoubleTy(getGlobalContext()), "", dest); |
| node->addIncoming(Constant::getNullValue(Type::getDoubleTy(getGlobalContext())), insert); |
| break; |
| } |
| case Long : { |
| PHINode* node = PHINode::Create(Type::getInt64Ty(getGlobalContext()), "", dest); |
| node->addIncoming(Constant::getNullValue(Type::getInt64Ty(getGlobalContext())), insert); |
| break; |
| } |
| case Object : { |
| PHINode* node = PHINode::Create(module->JavaObjectType, "", dest); |
| node->addIncoming(Constant::getNullValue(module->JavaObjectType), |
| insert); |
| break; |
| } |
| default : |
| abort(); |
| } |
| } |
| } else { |
| for (BasicBlock::iterator i = dest->begin(), e = dest->end(); i != e; ++i) { |
| if (PHINode* node = dyn_cast<PHINode>(i)) { |
| node->addIncoming(Constant::getNullValue(node->getType()), insert); |
| } else { |
| break; |
| } |
| } |
| } |
| } |
| |
| |
| Instruction* JavaJIT::lowerMathOps(const UTF8* name, |
| std::vector<Value*>& args) { |
| JnjvmBootstrapLoader* loader = compilingClass->classLoader->bootstrapLoader; |
| if (name->equals(loader->abs)) { |
| const Type* Ty = args[0]->getType(); |
| if (Ty == Type::getInt32Ty(getGlobalContext())) { |
| Constant* const_int32_9 = module->constantZero; |
| Constant* const_int32_10 = module->constantMinusOne; |
| BinaryOperator* int32_tmpneg = |
| BinaryOperator::Create(Instruction::Sub, const_int32_9, args[0], |
| "tmpneg", currentBlock); |
| ICmpInst* int1_abscond = |
| new ICmpInst(*currentBlock, ICmpInst::ICMP_SGT, args[0], const_int32_10, |
| "abscond"); |
| return llvm::SelectInst::Create(int1_abscond, args[0], int32_tmpneg, |
| "abs", currentBlock); |
| } else if (Ty == Type::getInt64Ty(getGlobalContext())) { |
| Constant* const_int64_9 = module->constantLongZero; |
| Constant* const_int64_10 = module->constantLongMinusOne; |
| |
| BinaryOperator* int64_tmpneg = |
| BinaryOperator::Create(Instruction::Sub, const_int64_9, args[0], |
| "tmpneg", currentBlock); |
| |
| ICmpInst* int1_abscond = new ICmpInst(*currentBlock, ICmpInst::ICMP_SGT, |
| args[0], const_int64_10, "abscond"); |
| |
| return llvm::SelectInst::Create(int1_abscond, args[0], int64_tmpneg, |
| "abs", currentBlock); |
| } else if (Ty == Type::getFloatTy(getGlobalContext())) { |
| return llvm::CallInst::Create(module->func_llvm_fabs_f32, args[0], |
| "tmp1", currentBlock); |
| } else if (Ty == Type::getDoubleTy(getGlobalContext())) { |
| return llvm::CallInst::Create(module->func_llvm_fabs_f64, args[0], |
| "tmp1", currentBlock); |
| } |
| } else if (name->equals(loader->sqrt)) { |
| return llvm::CallInst::Create(module->func_llvm_sqrt_f64, args[0], |
| "tmp1", currentBlock); |
| } else if (name->equals(loader->sin)) { |
| return llvm::CallInst::Create(module->func_llvm_sin_f64, args[0], |
| "tmp1", currentBlock); |
| } else if (name->equals(loader->cos)) { |
| return llvm::CallInst::Create(module->func_llvm_cos_f64, args[0], |
| "tmp1", currentBlock); |
| } else if (name->equals(loader->tan)) { |
| return llvm::CallInst::Create(module->func_llvm_tan_f64, args[0], |
| "tmp1", currentBlock); |
| } else if (name->equals(loader->asin)) { |
| return llvm::CallInst::Create(module->func_llvm_asin_f64, args[0], |
| "tmp1", currentBlock); |
| } else if (name->equals(loader->acos)) { |
| return llvm::CallInst::Create(module->func_llvm_acos_f64, args[0], |
| "tmp1", currentBlock); |
| } else if (name->equals(loader->atan)) { |
| return llvm::CallInst::Create(module->func_llvm_atan_f64, args[0], |
| "tmp1", currentBlock); |
| } else if (name->equals(loader->atan2)) { |
| return llvm::CallInst::Create(module->func_llvm_atan2_f64, |
| args.begin(), args.end(), "tmp1", |
| currentBlock); |
| } else if (name->equals(loader->exp)) { |
| return llvm::CallInst::Create(module->func_llvm_exp_f64, args[0], |
| "tmp1", currentBlock); |
| } else if (name->equals(loader->log)) { |
| return llvm::CallInst::Create(module->func_llvm_log_f64, args[0], |
| "tmp1", currentBlock); |
| } else if (name->equals(loader->pow)) { |
| return llvm::CallInst::Create(module->func_llvm_pow_f64, args.begin(), |
| args.end(), "tmp1", currentBlock); |
| } else if (name->equals(loader->ceil)) { |
| return llvm::CallInst::Create(module->func_llvm_ceil_f64, args[0], "tmp1", |
| currentBlock); |
| } else if (name->equals(loader->floor)) { |
| return llvm::CallInst::Create(module->func_llvm_floor_f64, args[0], |
| "tmp1", currentBlock); |
| } else if (name->equals(loader->rint)) { |
| return llvm::CallInst::Create(module->func_llvm_rint_f64, args[0], |
| "tmp1", currentBlock); |
| } else if (name->equals(loader->cbrt)) { |
| return llvm::CallInst::Create(module->func_llvm_cbrt_f64, args[0], "tmp1", |
| currentBlock); |
| } else if (name->equals(loader->cosh)) { |
| return llvm::CallInst::Create(module->func_llvm_cosh_f64, args[0], "tmp1", |
| currentBlock); |
| } else if (name->equals(loader->expm1)) { |
| return llvm::CallInst::Create(module->func_llvm_expm1_f64, args[0], |
| "tmp1", currentBlock); |
| } else if (name->equals(loader->hypot)) { |
| return llvm::CallInst::Create(module->func_llvm_hypot_f64, args[0], |
| "tmp1", currentBlock); |
| } else if (name->equals(loader->log10)) { |
| return llvm::CallInst::Create(module->func_llvm_log10_f64, args[0], |
| "tmp1", currentBlock); |
| } else if (name->equals(loader->log1p)) { |
| return llvm::CallInst::Create(module->func_llvm_log1p_f64, args[0], |
| "tmp1", currentBlock); |
| } else if (name->equals(loader->sinh)) { |
| return llvm::CallInst::Create(module->func_llvm_sinh_f64, args[0], |
| "tmp1", currentBlock); |
| } else if (name->equals(loader->tanh)) { |
| return llvm::CallInst::Create(module->func_llvm_tanh_f64, args[0], |
| "tmp1", currentBlock); |
| } |
| |
| return 0; |
| |
| } |
| |
| |
| Instruction* JavaJIT::invokeInline(JavaMethod* meth, |
| std::vector<Value*>& args) { |
| JavaJIT jit(TheCompiler, meth, llvmFunction); |
| jit.unifiedUnreachable = unifiedUnreachable; |
| jit.inlineMethods = inlineMethods; |
| jit.inlineMethods[meth] = true; |
| jit.inlining = true; |
| Instruction* ret = jit.inlineCompile(currentBlock, |
| currentExceptionBlock, args); |
| inlineMethods[meth] = false; |
| return ret; |
| } |
| |
| void JavaJIT::invokeSpecial(uint16 index, CommonClass* finalCl) { |
| JavaConstantPool* ctpInfo = compilingClass->ctpInfo; |
| JavaMethod* meth = 0; |
| Signdef* signature = 0; |
| const UTF8* name = 0; |
| const UTF8* cl = 0; |
| |
| ctpInfo->nameOfStaticOrSpecialMethod(index, cl, name, signature); |
| LLVMSignatureInfo* LSI = TheCompiler->getSignatureInfo(signature); |
| const llvm::FunctionType* virtualType = LSI->getVirtualType(); |
| llvm::Instruction* val = 0; |
| |
| std::vector<Value*> args; |
| FunctionType::param_iterator it = virtualType->param_end(); |
| makeArgs(it, index, args, signature->nbArguments + 1); |
| Value* func = 0; |
| |
| if (finalCl) { |
| Class* lookup = finalCl->isArray() ? finalCl->super : finalCl->asClass(); |
| |
| meth = lookup->lookupMethodDontThrow(name, signature->keyName, false, true, |
| 0); |
| } |
| |
| if (!meth) { |
| meth = ctpInfo->infoOfStaticOrSpecialMethod(index, ACC_VIRTUAL, signature); |
| } |
| |
| if (meth == compilingClass->classLoader->bootstrapLoader->upcalls->InitObject) |
| return; |
| |
| JITVerifyNull(args[0]); |
| |
| #if defined(ISOLATE_SHARING) |
| const Type* Ty = module->ConstantPoolType; |
| Constant* Nil = Constant::getNullValue(Ty); |
| GlobalVariable* GV = new GlobalVariable(Ty, false, |
| GlobalValue::ExternalLinkage, Nil, |
| "", module); |
| Value* res = new LoadInst(GV, "", false, currentBlock); |
| Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, res, Nil, ""); |
| |
| BasicBlock* trueCl = createBasicBlock("UserCtp OK"); |
| BasicBlock* falseCl = createBasicBlock("UserCtp Not OK"); |
| PHINode* node = llvm::PHINode::Create(Ty, "", trueCl); |
| node->addIncoming(res, currentBlock); |
| BranchInst::Create(falseCl, trueCl, test, currentBlock); |
| std::vector<Value*> Args; |
| Args.push_back(ctpCache); |
| Args.push_back(ConstantInt::get(Type::getInt32Ty(getGlobalContext()), index)); |
| Args.push_back(GV); |
| res = CallInst::Create(module->SpecialCtpLookupFunction, Args.begin(), |
| Args.end(), "", falseCl); |
| node->addIncoming(res, falseCl); |
| BranchInst::Create(trueCl, falseCl); |
| currentBlock = trueCl; |
| args.push_back(node); |
| #endif |
| |
| if (!meth) { |
| // Make sure the class is loaded before materializing the method. |
| uint32 clIndex = ctpInfo->getClassIndexFromMethod(index); |
| UserCommonClass* cl = 0; |
| Value* Cl = getResolvedCommonClass(clIndex, false, &cl); |
| if (!cl) { |
| CallInst::Create(module->ForceLoadedCheckFunction, Cl, "", currentBlock); |
| } |
| func = TheCompiler->addCallback(compilingClass, index, signature, false); |
| } else { |
| func = TheCompiler->getMethod(meth); |
| } |
| |
| if (meth && canBeInlined(meth)) { |
| val = invokeInline(meth, args); |
| } else { |
| val = invoke(func, args, "", currentBlock); |
| } |
| |
| const llvm::Type* retType = virtualType->getReturnType(); |
| if (retType != Type::getVoidTy(getGlobalContext())) { |
| push(val, signature->getReturnType()->isUnsigned()); |
| if (retType == Type::getDoubleTy(getGlobalContext()) || retType == Type::getInt64Ty(getGlobalContext())) { |
| push(module->constantZero, false); |
| } |
| } |
| |
| } |
| |
| void JavaJIT::invokeStatic(uint16 index) { |
| JavaConstantPool* ctpInfo = compilingClass->ctpInfo; |
| Signdef* signature = 0; |
| const UTF8* name = 0; |
| const UTF8* cl = 0; |
| ctpInfo->nameOfStaticOrSpecialMethod(index, cl, name, signature); |
| LLVMSignatureInfo* LSI = TheCompiler->getSignatureInfo(signature); |
| const llvm::FunctionType* staticType = LSI->getStaticType(); |
| llvm::Instruction* val = 0; |
| |
| std::vector<Value*> args; // size = [signature->nbIn + 2]; |
| FunctionType::param_iterator it = staticType->param_end(); |
| makeArgs(it, index, args, signature->nbArguments); |
| ctpInfo->markAsStaticCall(index); |
| |
| JnjvmBootstrapLoader* loader = compilingClass->classLoader->bootstrapLoader; |
| if (cl->equals(loader->mathName)) { |
| val = lowerMathOps(name, args); |
| } |
| |
| else if (cl->equals(loader->stackWalkerName)) { |
| callsStackWalker = true; |
| } |
| |
| if (!val) { |
| JavaMethod* meth = ctpInfo->infoOfStaticOrSpecialMethod(index, ACC_STATIC, |
| signature); |
| |
| Value* func = 0; |
| if (meth) { |
| func = TheCompiler->getMethod(meth); |
| } else { |
| func = TheCompiler->addCallback(compilingClass, index, signature, true); |
| } |
| |
| #if defined(ISOLATE_SHARING) |
| Value* newCtpCache = getConstantPoolAt(index, |
| module->StaticCtpLookupFunction, |
| module->ConstantPoolType, 0, |
| false); |
| args.push_back(newCtpCache); |
| #endif |
| |
| uint32 clIndex = ctpInfo->getClassIndexFromMethod(index); |
| UserClass* cl = 0; |
| Value* Cl = getResolvedClass(clIndex, true, true, &cl); |
| if (!meth || (cl && needsInitialisationCheck(cl, compilingClass))) { |
| CallInst::Create(module->ForceInitialisationCheckFunction, Cl, "", |
| currentBlock); |
| } |
| |
| if (meth && canBeInlined(meth)) { |
| val = invokeInline(meth, args); |
| } else { |
| val = invoke(func, args, "", currentBlock); |
| } |
| |
| } |
| |
| const llvm::Type* retType = staticType->getReturnType(); |
| if (retType != Type::getVoidTy(getGlobalContext())) { |
| push(val, signature->getReturnType()->isUnsigned()); |
| if (retType == Type::getDoubleTy(getGlobalContext()) || retType == Type::getInt64Ty(getGlobalContext())) { |
| push(module->constantZero, false); |
| } |
| } |
| } |
| |
| Value* JavaJIT::getConstantPoolAt(uint32 index, Function* resolver, |
| const Type* returnType, |
| Value* additionalArg, bool doThrow) { |
| |
| // This makes unswitch loop very unhappy time-wise, but makes GVN happy |
| // number-wise. IMO, it's better to have this than Unswitch. |
| #ifdef ISOLATE_SHARING |
| Value* CTP = ctpCache; |
| Value* Cl = GetElementPtrInst::Create(CTP, module->ConstantOne, "", |
| currentBlock); |
| Cl = new LoadInst(Cl, "", currentBlock); |
| #else |
| JavaConstantPool* ctp = compilingClass->ctpInfo; |
| Value* CTP = TheCompiler->getConstantPool(ctp); |
| Value* Cl = TheCompiler->getNativeClass(compilingClass); |
| #endif |
| |
| std::vector<Value*> Args; |
| Args.push_back(resolver); |
| Args.push_back(CTP); |
| Args.push_back(Cl); |
| Args.push_back(ConstantInt::get(Type::getInt32Ty(getGlobalContext()), index)); |
| if (additionalArg) Args.push_back(additionalArg); |
| |
| Value* res = 0; |
| if (doThrow) { |
| res = invoke(module->GetConstantPoolAtFunction, Args, "", |
| currentBlock); |
| } else { |
| res = CallInst::Create(module->GetConstantPoolAtFunction, Args.begin(), |
| Args.end(), "", currentBlock); |
| } |
| |
| const Type* realType = |
| module->GetConstantPoolAtFunction->getReturnType(); |
| if (returnType == Type::getInt32Ty(getGlobalContext())) { |
| return new PtrToIntInst(res, Type::getInt32Ty(getGlobalContext()), "", currentBlock); |
| } else if (returnType != realType) { |
| return new BitCastInst(res, returnType, "", currentBlock); |
| } |
| |
| return res; |
| } |
| |
| Value* JavaJIT::getResolvedCommonClass(uint16 index, bool doThrow, |
| UserCommonClass** alreadyResolved) { |
| |
| JavaConstantPool* ctpInfo = compilingClass->ctpInfo; |
| CommonClass* cl = ctpInfo->getMethodClassIfLoaded(index); |
| Value* node = 0; |
| if (cl && (!cl->isClass() || cl->asClass()->isResolved())) { |
| if (alreadyResolved) *alreadyResolved = cl; |
| node = TheCompiler->getNativeClass(cl); |
| // Since we only allocate for array classes that we own and |
| // ony primitive arrays are already allocated, verify that the class |
| // array is not external. |
| if (TheCompiler->isStaticCompiling() && cl->isArray() && |
| node->getType() != module->JavaClassArrayType) { |
| node = new LoadInst(node, "", currentBlock); |
| } |
| if (node->getType() != module->JavaCommonClassType) { |
| node = new BitCastInst(node, module->JavaCommonClassType, "", |
| currentBlock); |
| } |
| } else { |
| node = getConstantPoolAt(index, module->ClassLookupFunction, |
| module->JavaCommonClassType, 0, doThrow); |
| } |
| |
| return node; |
| } |
| |
| Value* JavaJIT::getResolvedClass(uint16 index, bool clinit, bool doThrow, |
| Class** alreadyResolved) { |
| |
| JavaConstantPool* ctpInfo = compilingClass->ctpInfo; |
| Class* cl = (Class*)(ctpInfo->getMethodClassIfLoaded(index)); |
| Value* node = 0; |
| bool needsInit = true; |
| if (cl && cl->isResolved()) { |
| if (alreadyResolved) (*alreadyResolved) = cl; |
| node = TheCompiler->getNativeClass(cl); |
| needsInit = needsInitialisationCheck(cl, compilingClass); |
| } else { |
| node = getConstantPoolAt(index, module->ClassLookupFunction, |
| module->JavaClassType, 0, doThrow); |
| } |
| |
| |
| if (clinit && needsInit) { |
| if (node->getType() != module->JavaClassType) { |
| node = new BitCastInst(node, module->JavaClassType, "", currentBlock); |
| } |
| return invoke(module->InitialisationCheckFunction, node, "", |
| currentBlock); |
| } else { |
| return node; |
| } |
| } |
| |
| void JavaJIT::invokeNew(uint16 index) { |
| |
| Class* cl = 0; |
| Value* Cl = getResolvedClass(index, true, true, &cl); |
| |
| Value* VT = 0; |
| Value* Size = 0; |
| |
| if (cl) { |
| VT = TheCompiler->getVirtualTable(cl->virtualVT); |
| LLVMClassInfo* LCI = TheCompiler->getClassInfo(cl); |
| Size = LCI->getVirtualSize(); |
| |
| bool needsCheck = needsInitialisationCheck(cl, compilingClass); |
| if (needsCheck) { |
| Cl = invoke(module->ForceInitialisationCheckFunction, Cl, "", |
| currentBlock); |
| } |
| |
| } else { |
| VT = CallInst::Create(module->GetVTFromClassFunction, Cl, "", |
| currentBlock); |
| Size = CallInst::Create(module->GetObjectSizeFromClassFunction, Cl, |
| "", currentBlock); |
| } |
| |
| Value* val = invoke(module->JavaObjectAllocateFunction, Size, VT, "", |
| currentBlock); |
| |
| push(val, false); |
| } |
| |
| Value* JavaJIT::ldResolved(uint16 index, bool stat, Value* object, |
| const Type* fieldType, const Type* fieldTypePtr) { |
| JavaConstantPool* info = compilingClass->ctpInfo; |
| |
| JavaField* field = info->lookupField(index, stat); |
| if (field && field->classDef->isResolved()) { |
| LLVMClassInfo* LCI = TheCompiler->getClassInfo(field->classDef); |
| LLVMFieldInfo* LFI = TheCompiler->getFieldInfo(field); |
| const Type* type = 0; |
| if (stat) { |
| type = LCI->getStaticType(); |
| Value* Cl = TheCompiler->getNativeClass(field->classDef); |
| bool needsCheck = needsInitialisationCheck(field->classDef, |
| compilingClass); |
| if (needsCheck) { |
| Cl = invoke(module->InitialisationCheckFunction, Cl, "", |
| currentBlock); |
| } |
| #if !defined(ISOLATE) && !defined(ISOLATE_SHARING) |
| if (needsCheck) { |
| CallInst::Create(module->ForceInitialisationCheckFunction, Cl, "", |
| currentBlock); |
| } |
| |
| object = TheCompiler->getStaticInstance(field->classDef); |
| #else |
| object = CallInst::Create(module->GetStaticInstanceFunction, Cl, "", |
| currentBlock); |
| #endif |
| } else { |
| type = LCI->getVirtualType(); |
| } |
| |
| Value* objectConvert = new BitCastInst(object, type, "", currentBlock); |
| |
| Value* args[2] = { module->constantZero, LFI->getOffset() }; |
| Value* ptr = llvm::GetElementPtrInst::Create(objectConvert, |
| args, args + 2, "", |
| currentBlock); |
| return ptr; |
| } |
| |
| const Type* Pty = module->arrayPtrType; |
| Constant* zero = module->constantZero; |
| |
| Function* func = stat ? module->StaticFieldLookupFunction : |
| module->VirtualFieldLookupFunction; |
| |
| const Type* returnType = 0; |
| if (stat) |
| returnType = module->ptrType; |
| else |
| returnType = Type::getInt32Ty(getGlobalContext()); |
| |
| Value* ptr = getConstantPoolAt(index, func, returnType, 0, true); |
| if (!stat) { |
| Value* tmp = new BitCastInst(object, Pty, "", currentBlock); |
| Value* args[2] = { zero, ptr }; |
| ptr = GetElementPtrInst::Create(tmp, args, args + 2, "", currentBlock); |
| } |
| |
| return new BitCastInst(ptr, fieldTypePtr, "", currentBlock); |
| } |
| |
| void JavaJIT::convertValue(Value*& val, const Type* t1, BasicBlock* currentBlock, |
| bool usign) { |
| const Type* t2 = val->getType(); |
| if (t1 != t2) { |
| if (t1->isInteger() && t2->isInteger()) { |
| if (t2->getPrimitiveSizeInBits() < t1->getPrimitiveSizeInBits()) { |
| if (usign) { |
| val = new ZExtInst(val, t1, "", currentBlock); |
| } else { |
| val = new SExtInst(val, t1, "", currentBlock); |
| } |
| } else { |
| val = new TruncInst(val, t1, "", currentBlock); |
| } |
| } else if (t1->isFloatingPoint() && t2->isFloatingPoint()) { |
| if (t2->getPrimitiveSizeInBits() < t1->getPrimitiveSizeInBits()) { |
| val = new FPExtInst(val, t1, "", currentBlock); |
| } else { |
| val = new FPTruncInst(val, t1, "", currentBlock); |
| } |
| } else if (isa<PointerType>(t1) && isa<PointerType>(t2)) { |
| val = new BitCastInst(val, t1, "", currentBlock); |
| } |
| } |
| } |
| |
| |
| void JavaJIT::setStaticField(uint16 index) { |
| bool unsign = topIsUnsigned(); |
| Value* val = pop(); |
| |
| Typedef* sign = compilingClass->ctpInfo->infoOfField(index); |
| LLVMAssessorInfo& LAI = TheCompiler->getTypedefInfo(sign); |
| const Type* type = LAI.llvmType; |
| |
| if (type == Type::getInt64Ty(getGlobalContext()) || type == Type::getDoubleTy(getGlobalContext())) { |
| val = pop(); |
| } |
| |
| Value* ptr = ldResolved(index, true, 0, type, LAI.llvmTypePtr); |
| |
| if (type != val->getType()) { // int1, int8, int16 |
| convertValue(val, type, currentBlock, unsign); |
| } |
| |
| new StoreInst(val, ptr, false, currentBlock); |
| } |
| |
| void JavaJIT::getStaticField(uint16 index) { |
| Typedef* sign = compilingClass->ctpInfo->infoOfField(index); |
| LLVMAssessorInfo& LAI = TheCompiler->getTypedefInfo(sign); |
| const Type* type = LAI.llvmType; |
| |
| Value* ptr = ldResolved(index, true, 0, type, LAI.llvmTypePtr); |
| |
| bool final = false; |
| #if !defined(ISOLATE) && !defined(ISOLATE_SHARING) |
| JnjvmBootstrapLoader* JBL = compilingClass->classLoader->bootstrapLoader; |
| if (!compilingMethod->name->equals(JBL->clinitName)) { |
| JavaField* field = compilingClass->ctpInfo->lookupField(index, true); |
| if (field && field->classDef->isReady()) final = isFinal(field->access); |
| if (final) { |
| void* Obj = field->classDef->getStaticInstance(); |
| if (sign->isPrimitive()) { |
| const PrimitiveTypedef* prim = (PrimitiveTypedef*)sign; |
| if (prim->isInt()) { |
| sint32 val = field->getInt32Field(Obj); |
| push(ConstantInt::get(Type::getInt32Ty(getGlobalContext()), val), false); |
| } else if (prim->isByte()) { |
| sint8 val = (sint8)field->getInt8Field(Obj); |
| push(ConstantInt::get(Type::getInt8Ty(getGlobalContext()), val), false); |
| } else if (prim->isBool()) { |
| uint8 val = (uint8)field->getInt8Field(Obj); |
| push(ConstantInt::get(Type::getInt8Ty(getGlobalContext()), val), true); |
| } else if (prim->isShort()) { |
| sint16 val = (sint16)field->getInt16Field(Obj); |
| push(ConstantInt::get(Type::getInt16Ty(getGlobalContext()), val), false); |
| } else if (prim->isChar()) { |
| uint16 val = (uint16)field->getInt16Field(Obj); |
| push(ConstantInt::get(Type::getInt16Ty(getGlobalContext()), val), true); |
| } else if (prim->isLong()) { |
| sint64 val = (sint64)field->getLongField(Obj); |
| push(ConstantInt::get(Type::getInt64Ty(getGlobalContext()), val), false); |
| } else if (prim->isFloat()) { |
| float val = (float)field->getFloatField(Obj); |
| push(ConstantFP::get(Type::getFloatTy(getGlobalContext()), val), false); |
| } else if (prim->isDouble()) { |
| double val = (double)field->getDoubleField(Obj); |
| push(ConstantFP::get(Type::getDoubleTy(getGlobalContext()), val), false); |
| } else { |
| abort(); |
| } |
| } else { |
| if (TheCompiler->isStaticCompiling()) { |
| JavaObject* val = field->getObjectField(Obj); |
| Value* V = TheCompiler->getFinalObject(val); |
| push(V, false); |
| } else { |
| Value* V = CallInst::Create(module->GetFinalObjectFieldFunction, ptr, |
| "", currentBlock); |
| |
| push(V, false); |
| } |
| } |
| } |
| } |
| #endif |
| |
| if (!final) push(new LoadInst(ptr, "", currentBlock), sign->isUnsigned()); |
| if (type == Type::getInt64Ty(getGlobalContext()) || type == Type::getDoubleTy(getGlobalContext())) { |
| push(module->constantZero, false); |
| } |
| } |
| |
| void JavaJIT::setVirtualField(uint16 index) { |
| bool unsign = topIsUnsigned(); |
| Value* val = pop(); |
| Typedef* sign = compilingClass->ctpInfo->infoOfField(index); |
| LLVMAssessorInfo& LAI = TheCompiler->getTypedefInfo(sign); |
| const Type* type = LAI.llvmType; |
| |
| if (type == Type::getInt64Ty(getGlobalContext()) || type == Type::getDoubleTy(getGlobalContext())) { |
| val = pop(); |
| } |
| |
| Value* object = pop(); |
| JITVerifyNull(object); |
| Value* ptr = ldResolved(index, false, object, type, LAI.llvmTypePtr); |
| |
| if (type != val->getType()) { // int1, int8, int16 |
| convertValue(val, type, currentBlock, unsign); |
| } |
| |
| new StoreInst(val, ptr, false, currentBlock); |
| } |
| |
| void JavaJIT::getVirtualField(uint16 index) { |
| Typedef* sign = compilingClass->ctpInfo->infoOfField(index); |
| LLVMAssessorInfo& LAI = TheCompiler->getTypedefInfo(sign); |
| const Type* type = LAI.llvmType; |
| Value* obj = pop(); |
| JITVerifyNull(obj); |
| |
| Value* ptr = ldResolved(index, false, obj, type, LAI.llvmTypePtr); |
| |
| JnjvmBootstrapLoader* JBL = compilingClass->classLoader->bootstrapLoader; |
| bool final = false; |
| if (!compilingMethod->name->equals(JBL->initName)) { |
| JavaField* field = compilingClass->ctpInfo->lookupField(index, false); |
| if (field) final = isFinal(field->access); |
| if (final) { |
| Function* F = 0; |
| if (sign->isPrimitive()) { |
| const PrimitiveTypedef* prim = (PrimitiveTypedef*)sign; |
| if (prim->isInt()) { |
| F = module->GetFinalInt32FieldFunction; |
| } else if (prim->isByte()) { |
| F = module->GetFinalInt8FieldFunction; |
| } else if (prim->isBool()) { |
| F = module->GetFinalInt8FieldFunction; |
| } else if (prim->isShort()) { |
| F = module->GetFinalInt16FieldFunction; |
| } else if (prim->isChar()) { |
| F = module->GetFinalInt16FieldFunction; |
| } else if (prim->isLong()) { |
| F = module->GetFinalLongFieldFunction; |
| } else if (prim->isFloat()) { |
| F = module->GetFinalFloatFieldFunction; |
| } else if (prim->isDouble()) { |
| F = module->GetFinalDoubleFieldFunction; |
| } else { |
| abort(); |
| } |
| } else { |
| F = module->GetFinalObjectFieldFunction; |
| } |
| push(CallInst::Create(F, ptr, "", currentBlock), sign->isUnsigned()); |
| } |
| } |
| |
| if (!final) push(new LoadInst(ptr, "", currentBlock), sign->isUnsigned()); |
| if (type == Type::getInt64Ty(getGlobalContext()) || type == Type::getDoubleTy(getGlobalContext())) { |
| push(module->constantZero, false); |
| } |
| } |
| |
| |
| void JavaJIT::invokeInterface(uint16 index, bool buggyVirtual) { |
| |
| // Do the usual |
| JavaConstantPool* ctpInfo = compilingClass->ctpInfo; |
| const UTF8* name = 0; |
| Signdef* signature = ctpInfo->infoOfInterfaceOrVirtualMethod(index, name); |
| |
| LLVMSignatureInfo* LSI = TheCompiler->getSignatureInfo(signature); |
| const llvm::FunctionType* virtualType = LSI->getVirtualType(); |
| const llvm::PointerType* virtualPtrType = LSI->getVirtualPtrType(); |
| |
| std::vector<Value*> args; // size = [signature->nbIn + 3]; |
| |
| FunctionType::param_iterator it = virtualType->param_end(); |
| makeArgs(it, index, args, signature->nbArguments + 1); |
| |
| const llvm::Type* retType = virtualType->getReturnType(); |
| BasicBlock* endBlock = createBasicBlock("end virtual invoke"); |
| PHINode * node = 0; |
| if (retType != Type::getVoidTy(getGlobalContext())) { |
| node = PHINode::Create(retType, "", endBlock); |
| } |
| |
| JITVerifyNull(args[0]); |
| |
| Value* zero = module->constantZero; |
| Value* one = module->constantOne; |
| |
| #ifndef ISOLATE_SHARING |
| // ok now the cache |
| Enveloppe& enveloppe = buggyVirtual ? |
| *(new (compilingClass->classLoader->allocator, "Enveloppe") Enveloppe()) : |
| compilingMethod->enveloppes[nbEnveloppes++]; |
| if (!inlining) |
| enveloppe.initialise(compilingClass, name, signature->keyName); |
| |
| Value* llvmEnv = TheCompiler->getEnveloppe(&enveloppe); |
| #else |
| Value* llvmEnv = getConstantPoolAt(index, |
| module->EnveloppeLookupFunction, |
| module->EnveloppeType, 0, false); |
| #endif |
| |
| Value* args1[2] = { zero, zero }; |
| Value* cachePtr = GetElementPtrInst::Create(llvmEnv, args1, args1 + 2, |
| "", currentBlock); |
| Value* cache = new LoadInst(cachePtr, "", currentBlock); |
| |
| Value* VT = CallInst::Create(module->GetVTFunction, args[0], "", |
| currentBlock); |
| Value* args3[2] = { zero, one }; |
| Value* lastCiblePtr = GetElementPtrInst::Create(cache, args3, args3 + 2, "", |
| currentBlock); |
| Value* lastCible = new LoadInst(lastCiblePtr, "", currentBlock); |
| |
| Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, VT, lastCible, |
| ""); |
| |
| BasicBlock* ifTrue = createBasicBlock("cache ok"); |
| BasicBlock* ifFalse = createBasicBlock("cache not ok"); |
| BranchInst::Create(ifTrue, ifFalse, cmp, currentBlock); |
| |
| currentBlock = ifFalse; |
| Value* _meth = invoke(module->InterfaceLookupFunction, cache, args[0], |
| "", ifFalse); |
| Value* meth = new BitCastInst(_meth, virtualPtrType, "", |
| currentBlock); |
| #ifdef ISOLATE_SHARING |
| Value* cache2 = new LoadInst(cachePtr, "", currentBlock); |
| Value* newCtpCache = CallInst::Create(module->GetCtpCacheNodeFunction, |
| cache2, "", currentBlock); |
| args.push_back(newCtpCache); |
| #endif |
| Value* ret = invoke(meth, args, "", currentBlock); |
| if (node) { |
| node->addIncoming(ret, currentBlock); |
| } |
| BranchInst::Create(endBlock, currentBlock); |
| |
| currentBlock = ifTrue; |
| |
| Value* methPtr = GetElementPtrInst::Create(cache, args1, args1 + 2, |
| "", currentBlock); |
| |
| _meth = new LoadInst(methPtr, "", currentBlock); |
| meth = new BitCastInst(_meth, virtualPtrType, "", currentBlock); |
| |
| #ifdef ISOLATE_SHARING |
| args.pop_back(); |
| cache = new LoadInst(cachePtr, "", currentBlock); |
| newCtpCache = CallInst::Create(module->GetCtpCacheNodeFunction, |
| cache, "", currentBlock); |
| args.push_back(newCtpCache); |
| #endif |
| ret = invoke(meth, args, "", currentBlock); |
| BranchInst::Create(endBlock, currentBlock); |
| |
| if (node) { |
| node->addIncoming(ret, currentBlock); |
| } |
| |
| currentBlock = endBlock; |
| if (node) { |
| push(node, signature->getReturnType()->isUnsigned()); |
| if (retType == Type::getDoubleTy(getGlobalContext()) || |
| retType == Type::getInt64Ty(getGlobalContext())) { |
| push(module->constantZero, false); |
| } |
| } |
| } |
| |
| |
| #ifdef DWARF_EXCEPTIONS |
| #include "ExceptionsDwarf.inc" |
| #else |
| #include "ExceptionsCheck.inc" |
| #endif |