blob: 0ee6b9636028f5433218de539232b148dc098e7e [file] [log] [blame]
//===----------- JavaJIT.cpp - Java just in time compiler -----------------===//
//
// The VMKit project
//
// 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/Analysis/DebugInfo.h>
#include <llvm/Support/CFG.h>
#include "mvm/JIT.h"
#include "debug.h"
#include "JavaArray.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 "j3/JavaLLVMCompiler.h"
#include "j3/J3Intrinsics.h"
using namespace j3;
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);
bool canBeDirect = false;
Value* val = NULL; // The return from the method.
if ((cl && isFinal(cl->access)) ||
(meth && (isFinal(meth->access) || isPrivate(meth->access)))) {
canBeDirect = true;
}
// 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) {
canBeDirect = true;
CommonClass* sourceClass = source->getClass();
Class* lookup = sourceClass->isArray() ? sourceClass->super :
sourceClass->asClass();
meth = lookup->lookupMethodDontThrow(name, signature->keyName, false,
true, 0);
}
if (TheCompiler->isStaticCompiling()) {
CommonClass* unique = TheCompiler->getUniqueBaseClass(cl);
if (unique) {
canBeDirect = true;
Class* lookup = unique->isArray() ? unique->super : unique->asClass();
meth = lookup->lookupMethodDontThrow(name, signature->keyName, false,
true, 0);
}
}
#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]);
bool needsInit = false;
if (canBeDirect && meth && !TheCompiler->needsCallback(meth, &needsInit)) {
val = invoke(TheCompiler->getMethod(meth), args, "", currentBlock);
} else {
BasicBlock* endBlock = 0;
PHINode* node = 0;
#if 0
// TODO: enable this only when inlining?
if (meth && !isAbstract(meth->access)) {
Value* cl = CallInst::Create(intrinsics->GetClassFunction, args[0], "",
currentBlock);
Value* cl2 = intrinsics->getNativeClass(meth->classDef);
if (cl2->getType() != intrinsics->JavaCommonClassType) {
cl2 = new BitCastInst(cl2, intrinsics->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 = intrinsics->getMethod(meth);
res = invoke(func, args, "", currentBlock);
}
BranchInst::Create(endBlock, currentBlock);
if (retType != Type::getVoidTy(*llvmContext)) {
node = PHINode::Create(virtualType->getReturnType(), "", endBlock);
node->addIncoming(res, currentBlock);
}
currentBlock = falseBlock;
}
#endif
Value* VT = CallInst::Create(intrinsics->GetVTFunction, args[0], "",
currentBlock);
Value* indexes2[2];
indexes2[0] = intrinsics->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(*llvmContext),
Offset->getZExtValue() * -1);
#endif
} else {
GlobalVariable* GV = new GlobalVariable(*llvmFunction->getParent(),
Type::getInt32Ty(*llvmContext),
false,
GlobalValue::ExternalLinkage,
intrinsics->constantZero, "");
BasicBlock* resolveVirtual = createBasicBlock("resolveVirtual");
BasicBlock* endResolveVirtual = createBasicBlock("endResolveVirtual");
PHINode* node = PHINode::Create(Type::getInt32Ty(*llvmContext), "",
endResolveVirtual);
Value* load = new LoadInst(GV, "", false, currentBlock);
Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, load,
intrinsics->constantZero, "");
BranchInst::Create(resolveVirtual, endResolveVirtual, test, currentBlock);
node->addIncoming(load, currentBlock);
currentBlock = resolveVirtual;
std::vector<Value*> Args;
Args.push_back(TheCompiler->getNativeClass(compilingClass));
Args.push_back(ConstantInt::get(Type::getInt32Ty(*llvmContext), index));
Args.push_back(GV);
Args.push_back(args[0]);
load = invoke(intrinsics->VirtualLookupFunction, Args, "", currentBlock);
node->addIncoming(load, currentBlock);
BranchInst::Create(endResolveVirtual, currentBlock);
currentBlock = endResolveVirtual;
indexes2[1] = node;
#ifdef ISOLATE_SHARING
Value* mul = BinaryOperator::CreateMul(val, intrinsics->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, intrinsics->ConstantPoolType, "", currentBlock);
args.push_back(CTP);
#endif
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(*llvmContext)) {
if (retType == intrinsics->JavaObjectType) {
JnjvmClassLoader* JCL = compilingClass->classLoader;
push(val, false, signature->getReturnType()->findAssocClass(JCL));
} else {
push(val, retTypedef->isUnsigned());
if (retType == Type::getDoubleTy(*llvmContext) || retType == Type::getInt64Ty(*llvmContext)) {
push(intrinsics->constantZero, false);
}
}
}
#else
return invokeInterface(index);
#endif
}
llvm::Value* JavaJIT::getCurrentThread(const llvm::Type* Ty) {
Value* FrameAddr = CallInst::Create(intrinsics->llvm_frameaddress,
intrinsics->constantZero, "", currentBlock);
Value* threadId = new PtrToIntInst(FrameAddr, intrinsics->pointerSizeType, "",
currentBlock);
threadId = BinaryOperator::CreateAnd(threadId, intrinsics->constantThreadIDMask,
"", currentBlock);
threadId = new IntToPtrInst(threadId, Ty, "", currentBlock);
return threadId;
}
extern "C" void j3ThrowExceptionFromJIT();
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 j3 = 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, j3,
functionName);
if (!natPtr && !TheCompiler->isStaticCompiling()) {
currentBlock = createBasicBlock("start");
CallInst::Create(intrinsics->ThrowExceptionFromJITFunction, "", currentBlock);
if (returnType != Type::getVoidTy(*llvmContext))
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 (j3) {
compilingMethod->setCompiledPtr((void*)natPtr, functionName);
llvmFunction->clearGC();
return llvmFunction;
}
currentExceptionBlock = endExceptionBlock = 0;
currentBlock = createBasicBlock("start");
endBlock = createBasicBlock("end block");
if (returnType != Type::getVoidTy(*llvmContext)) {
endNode = PHINode::Create(returnType, "", endBlock);
}
// Allocate currentLocalIndexNumber pointer
Value* temp = new AllocaInst(Type::getInt32Ty(*llvmContext), "",
currentBlock);
new StoreInst(intrinsics->constantZero, temp, false, currentBlock);
// Allocate oldCurrentLocalIndexNumber pointer
Value* oldCLIN = new AllocaInst(PointerType::getUnqual(Type::getInt32Ty(*llvmContext)), "",
currentBlock);
Constant* sizeF = ConstantInt::get(Type::getInt32Ty(*llvmContext), 2 * sizeof(void*));
Value* Frame = new AllocaInst(Type::getInt8Ty(*llvmContext), sizeF, "", currentBlock);
// Synchronize before saying we're entering native
if (isSynchro(compilingMethod->access))
beginSynchronize();
uint32 nargs = func->arg_size() + 1 + (stat ? 1 : 0);
std::vector<Value*> nativeArgs;
Value* threadId = getCurrentThread(intrinsics->JavaThreadType);
Value* geps[2] = { intrinsics->constantZero,
intrinsics->OffsetJNIInThreadConstant };
Value* jniEnv = GetElementPtrInst::Create(threadId, geps, geps + 2, "",
currentBlock);
jniEnv = new BitCastInst(jniEnv, intrinsics->ptrType, "", currentBlock);
nativeArgs.push_back(jniEnv);
uint32 index = 0;
if (stat) {
#ifdef ISOLATE_SHARING
Value* val = getClassCtp();
Value* cl = CallInst::Create(intrinsics->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() == intrinsics->JavaObjectType) {
BasicBlock* BB = createBasicBlock("");
BasicBlock* NotZero = createBasicBlock("");
const Type* Ty = PointerType::getUnqual(intrinsics->JavaObjectType);
PHINode* node = PHINode::Create(Ty, "", BB);
Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, i,
intrinsics->JavaObjectNullConstant, "");
node->addIncoming(Constant::getNullValue(Ty), currentBlock);
BranchInst::Create(BB, NotZero, test, currentBlock);
currentBlock = NotZero;
Instruction* temp = new AllocaInst(intrinsics->JavaObjectType, "",
func->begin()->getTerminator());
if (TheCompiler->useCooperativeGC()) {
Value* GCArgs[2] = {
new BitCastInst(temp, intrinsics->ptrPtrType, "",
func->begin()->getTerminator()),
intrinsics->constantPtrNull
};
CallInst::Create(intrinsics->llvm_gc_gcroot, GCArgs, GCArgs + 2, "",
func->begin()->getTerminator());
}
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);
}
}
Instruction* ResultObject = 0;
if (returnType == intrinsics->JavaObjectType) {
ResultObject = new AllocaInst(intrinsics->JavaObjectType, "",
func->begin()->begin());
if (TheCompiler->useCooperativeGC()) {
Value* GCArgs[2] = {
new BitCastInst(ResultObject, intrinsics->ptrPtrType, "", currentBlock),
intrinsics->constantPtrNull
};
CallInst::Create(intrinsics->llvm_gc_gcroot, GCArgs, GCArgs + 2, "",
currentBlock);
} else {
new StoreInst(intrinsics->JavaObjectNullConstant, ResultObject, "",
currentBlock);
}
}
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[3] = { temp, oldCLIN, Frame };
CallInst::Create(intrinsics->StartJNIFunction, Args4, Args4 + 3, "",
currentBlock);
Value* result = llvm::CallInst::Create(nativeFunc, nativeArgs.begin(),
nativeArgs.end(), "", currentBlock);
if (returnType == intrinsics->JavaObjectType) {
const Type* Ty = PointerType::getUnqual(intrinsics->JavaObjectType);
Constant* C = Constant::getNullValue(Ty);
Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, result, C, "");
BasicBlock* loadBlock = createBasicBlock("");
endNode->addIncoming(intrinsics->JavaObjectNullConstant, currentBlock);
BranchInst::Create(endBlock, loadBlock, cmp, currentBlock);
currentBlock = loadBlock;
result = new LoadInst(result, "", currentBlock);
new StoreInst(result, ResultObject, "", currentBlock);
endNode->addIncoming(result, currentBlock);
} else if (returnType != Type::getVoidTy(*llvmContext)) {
endNode->addIncoming(result, currentBlock);
}
BranchInst::Create(endBlock, currentBlock);
currentBlock = endBlock;
Value* Args2[1] = { oldCLIN };
CallInst::Create(intrinsics->EndJNIFunction, Args2, Args2 + 1, "", currentBlock);
// Synchronize after leaving native.
if (isSynchro(compilingMethod->access))
endSynchronize();
if (returnType != Type::getVoidTy(*llvmContext))
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(intrinsics->constantZero);
gep.push_back(intrinsics->JavaObjectLockOffsetConstant);
Value* lockPtr = GetElementPtrInst::Create(obj, gep.begin(), gep.end(), "",
currentBlock);
Value* lock = new LoadInst(lockPtr, "", currentBlock);
lock = new PtrToIntInst(lock, intrinsics->pointerSizeType, "", currentBlock);
Value* GCMask = ConstantInt::get(intrinsics->pointerSizeType,
mvm::GCMask);
lock = BinaryOperator::CreateAnd(lock, GCMask, "", currentBlock);
lockPtr = new BitCastInst(lockPtr,
PointerType::getUnqual(intrinsics->pointerSizeType),
"", currentBlock);
Value* threadId = getCurrentThread(intrinsics->MutatorThreadType);
threadId = new PtrToIntInst(threadId, intrinsics->pointerSizeType, "",
currentBlock);
Value* newValMask = BinaryOperator::CreateOr(threadId, lock, "",
currentBlock);
std::vector<Value*> atomicArgs;
atomicArgs.push_back(lockPtr);
atomicArgs.push_back(lock);
atomicArgs.push_back(newValMask);
// Do the atomic compare and swap.
Value* atomic = CallInst::Create(intrinsics->llvm_atomic_lcs_ptr,
atomicArgs.begin(), atomicArgs.end(), "",
currentBlock);
Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, atomic,
lock, "");
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, intrinsics->constantFatMask, "",
currentBlock);
cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, isThin,
intrinsics->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(intrinsics->pointerSizeType, mvm::Thread::IDMask);
Value* cptMask = ConstantInt::get(intrinsics->pointerSizeType, mvm::ThinCountMask);
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* One = ConstantInt::get(intrinsics->pointerSizeType, mvm::ThinCountAdd);
Value* Add = BinaryOperator::CreateAdd(One, 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(intrinsics->OverflowThinLockFunction, obj, "",
currentBlock);
BranchInst::Create(OK, currentBlock);
currentBlock = FatLockBB;
// Either it's a fat lock or there is contention.
CallInst::Create(intrinsics->AquireObjectFunction, obj, "", currentBlock);
BranchInst::Create(OK, currentBlock);
currentBlock = OK;
}
void JavaJIT::monitorExit(Value* obj) {
std::vector<Value*> gep;
gep.push_back(intrinsics->constantZero);
gep.push_back(intrinsics->JavaObjectLockOffsetConstant);
Value* lockPtr = GetElementPtrInst::Create(obj, gep.begin(), gep.end(), "",
currentBlock);
lockPtr = new BitCastInst(lockPtr,
PointerType::getUnqual(intrinsics->pointerSizeType),
"", currentBlock);
Value* lock = new LoadInst(lockPtr, "", currentBlock);
Value* GCMask = ConstantInt::get(intrinsics->pointerSizeType, ~mvm::GCMask);
Value* lockedMask = BinaryOperator::CreateAnd(lock, GCMask, "", currentBlock);
Value* threadId = getCurrentThread(intrinsics->MutatorThreadType);
threadId = new PtrToIntInst(threadId, intrinsics->pointerSizeType, "",
currentBlock);
Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, lockedMask,
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;
GCMask = ConstantInt::get(intrinsics->pointerSizeType, mvm::GCMask);
lockedMask = BinaryOperator::CreateAnd(lock, GCMask, "", currentBlock);
new StoreInst(lockedMask, lockPtr, false, currentBlock);
BranchInst::Create(EndUnlock, currentBlock);
currentBlock = NotLockedOnceBB;
// Look if the lock is thin.
Value* isThin = BinaryOperator::CreateAnd(lock, intrinsics->constantFatMask, "",
currentBlock);
cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, isThin,
intrinsics->constantPtrZero, "");
BranchInst::Create(ThinLockBB, FatLockBB, cmp, currentBlock);
currentBlock = ThinLockBB;
// Decrement the counter.
Value* One = ConstantInt::get(intrinsics->pointerSizeType, mvm::ThinCountAdd);
Value* Sub = BinaryOperator::CreateSub(lock, One, "", 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(intrinsics->ReleaseObjectFunction, obj, "", currentBlock);
BranchInst::Create(EndUnlock, currentBlock);
currentBlock = EndUnlock;
}
#ifdef ISOLATE_SHARING
Value* JavaJIT::getStaticInstanceCtp() {
Value* cl = getClassCtp();
Value* indexes[2] = { intrinsics->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 = intrinsics->constantOne;
Value* arg1 = GetElementPtrInst::Create(ctpCache, indexes.begin(),
indexes.end(), "", currentBlock);
arg1 = new LoadInst(arg1, "", false, currentBlock);
arg1 = new BitCastInst(arg1, intrinsics->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;
unsigned uses = temp->getNumUses();
if (!uses) {
temp->eraseFromParent();
} else if (uses == 1 && dyn_cast<StoreInst>(temp->use_begin())) {
dyn_cast<StoreInst>(temp->use_begin())->eraseFromParent();
temp->eraseFromParent();
}
}
}
static void removeUnusedObjects(std::vector<AllocaInst*>& objects,
J3Intrinsics* intrinsics, bool coop) {
for (std::vector<AllocaInst*>::iterator i = objects.begin(),
e = objects.end(); i != e; ++i) {
AllocaInst* temp = *i;
unsigned uses = temp->getNumUses();
if (!uses) {
temp->eraseFromParent();
} else if (uses == 1 && dyn_cast<StoreInst>(temp->use_begin())) {
dyn_cast<StoreInst>(temp->use_begin())->eraseFromParent();
temp->eraseFromParent();
} else {
if (coop) {
Instruction* I = new BitCastInst(temp, intrinsics->ptrPtrType, "");
I->insertAfter(temp);
Value* GCArgs[2] = { I, intrinsics->constantPtrNull };
Instruction* C = CallInst::Create(intrinsics->llvm_gc_gcroot, GCArgs,
GCArgs + 2, "");
C->insertAfter(I);
}
}
}
}
Instruction* JavaJIT::inlineCompile(BasicBlock*& curBB,
BasicBlock* endExBlock,
std::vector<Value*>& args) {
DbgSubprogram = TheCompiler->GetDbgSubprogram(compilingMethod);
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 = new Opinfo[codeLen];
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(*llvmContext), "", firstInstruction));
new StoreInst(Constant::getNullValue(Type::getInt32Ty(*llvmContext)), intLocals.back(), false, firstInstruction);
doubleLocals.push_back(new AllocaInst(Type::getDoubleTy(*llvmContext), "",
firstInstruction));
new StoreInst(Constant::getNullValue(Type::getDoubleTy(*llvmContext)), doubleLocals.back(), false, firstInstruction);
longLocals.push_back(new AllocaInst(Type::getInt64Ty(*llvmContext), "", firstInstruction));
new StoreInst(Constant::getNullValue(Type::getInt64Ty(*llvmContext)), longLocals.back(), false, firstInstruction);
floatLocals.push_back(new AllocaInst(Type::getFloatTy(*llvmContext), "", firstInstruction));
new StoreInst(Constant::getNullValue(Type::getFloatTy(*llvmContext)), floatLocals.back(), false, firstInstruction);
objectLocals.push_back(new AllocaInst(intrinsics->JavaObjectType, "",
firstInstruction));
// The GCStrategy will already initialize the value.
if (!TheCompiler->useCooperativeGC())
new StoreInst(Constant::getNullValue(intrinsics->JavaObjectType), objectLocals.back(), false, firstInstruction);
}
for (int i = 0; i < maxStack; i++) {
objectStack.push_back(new AllocaInst(intrinsics->JavaObjectType, "",
firstInstruction));
addHighLevelType(objectStack.back(), upcalls->OfObject);
intStack.push_back(new AllocaInst(Type::getInt32Ty(*llvmContext), "", firstInstruction));
doubleStack.push_back(new AllocaInst(Type::getDoubleTy(*llvmContext), "",
firstInstruction));
longStack.push_back(new AllocaInst(Type::getInt64Ty(*llvmContext), "", firstInstruction));
floatStack.push_back(new AllocaInst(Type::getFloatTy(*llvmContext), "", firstInstruction));
}
} else {
for (int i = 0; i < maxLocals; i++) {
intLocals.push_back(new AllocaInst(Type::getInt32Ty(*llvmContext), "", firstBB));
new StoreInst(Constant::getNullValue(Type::getInt32Ty(*llvmContext)), intLocals.back(), false, firstBB);
doubleLocals.push_back(new AllocaInst(Type::getDoubleTy(*llvmContext), "", firstBB));
new StoreInst(Constant::getNullValue(Type::getDoubleTy(*llvmContext)), doubleLocals.back(), false, firstBB);
longLocals.push_back(new AllocaInst(Type::getInt64Ty(*llvmContext), "", firstBB));
new StoreInst(Constant::getNullValue(Type::getInt64Ty(*llvmContext)), longLocals.back(), false, firstBB);
floatLocals.push_back(new AllocaInst(Type::getFloatTy(*llvmContext), "", firstBB));
new StoreInst(Constant::getNullValue(Type::getFloatTy(*llvmContext)), floatLocals.back(), false, firstBB);
objectLocals.push_back(new AllocaInst(intrinsics->JavaObjectType, "",
firstBB));
// The GCStrategy will already initialize the value.
if (!TheCompiler->useCooperativeGC())
new StoreInst(Constant::getNullValue(intrinsics->JavaObjectType), objectLocals.back(), false, firstBB);
}
for (int i = 0; i < maxStack; i++) {
objectStack.push_back(new AllocaInst(intrinsics->JavaObjectType, "",
firstBB));
addHighLevelType(objectStack.back(), upcalls->OfObject);
intStack.push_back(new AllocaInst(Type::getInt32Ty(*llvmContext), "", firstBB));
doubleStack.push_back(new AllocaInst(Type::getDoubleTy(*llvmContext), "", firstBB));
longStack.push_back(new AllocaInst(Type::getInt64Ty(*llvmContext), "", firstBB));
floatStack.push_back(new AllocaInst(Type::getFloatTy(*llvmContext), "", 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)) {
Instruction* V = new StoreInst(*i, objectLocals[0], false, currentBlock);
addHighLevelType(V, compilingClass);
++i;
++index;
++count;
}
for (;count < max; ++i, ++index, ++count, ++type) {
const Typedef* cur = arguments[type];
const Type* curType = (*i)->getType();
if (curType == Type::getInt64Ty(*llvmContext)){
new StoreInst(*i, longLocals[index], false, currentBlock);
++index;
} else if (cur->isUnsigned()) {
new StoreInst(new ZExtInst(*i, Type::getInt32Ty(*llvmContext), "", currentBlock),
intLocals[index], false, currentBlock);
} else if (curType == Type::getInt8Ty(*llvmContext) || curType == Type::getInt16Ty(*llvmContext)) {
new StoreInst(new SExtInst(*i, Type::getInt32Ty(*llvmContext), "", currentBlock),
intLocals[index], false, currentBlock);
} else if (curType == Type::getInt32Ty(*llvmContext)) {
new StoreInst(*i, intLocals[index], false, currentBlock);
} else if (curType == Type::getDoubleTy(*llvmContext)) {
new StoreInst(*i, doubleLocals[index], false, currentBlock);
++index;
} else if (curType == Type::getFloatTy(*llvmContext)) {
new StoreInst(*i, floatLocals[index], false, currentBlock);
} else {
Instruction* V = new StoreInst(*i, objectLocals[index], false, currentBlock);
addHighLevelType(V, cur->findAssocClass(compilingClass->classLoader));
}
}
readExceptionTable(reader, codeLen);
// Lookup line number table attribute.
uint16 nba = reader.readU2();
for (uint16 i = 0; i < nba; ++i) {
const UTF8* attName = compilingClass->ctpInfo->UTF8At(reader.readU2());
uint32 attLen = reader.readU4();
if (attName->equals(Attribut::lineNumberTableAttribut)) {
uint16 lineLength = reader.readU2();
for (uint16 i = 0; i < lineLength; ++i) {
uint16 pc = reader.readU2();
uint16 ln = reader.readU2();
opcodeInfos[pc].lineNumber = ln;
}
} else {
reader.seek(attLen, Reader::SeekCur);
}
}
exploreOpcodes(&compilingClass->bytes->elements[start], codeLen);
if (returnType != Type::getVoidTy(*llvmContext)) {
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, intrinsics, TheCompiler->useCooperativeGC());
removeUnusedObjects(objectStack, intrinsics, TheCompiler->useCooperativeGC());
delete[] opcodeInfos;
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());
DbgSubprogram = TheCompiler->GetDbgSubprogram(compilingMethod);
Attribut* codeAtt = compilingMethod->lookupAttribut(Attribut::codeAttribut);
if (!codeAtt) {
fprintf(stderr, "I haven't verified your class file and it's malformed:"
" no code attribute 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 = new Opinfo[codeLen];
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(intrinsics->PrintMethodStartFunction, arg, "",
currentBlock);
}
#endif
for (int i = 0; i < maxLocals; i++) {
intLocals.push_back(new AllocaInst(Type::getInt32Ty(*llvmContext), "", currentBlock));
new StoreInst(Constant::getNullValue(Type::getInt32Ty(*llvmContext)), intLocals.back(), false, currentBlock);
doubleLocals.push_back(new AllocaInst(Type::getDoubleTy(*llvmContext), "", currentBlock));
new StoreInst(Constant::getNullValue(Type::getDoubleTy(*llvmContext)), doubleLocals.back(), false, currentBlock);
longLocals.push_back(new AllocaInst(Type::getInt64Ty(*llvmContext), "", currentBlock));
new StoreInst(Constant::getNullValue(Type::getInt64Ty(*llvmContext)), longLocals.back(), false, currentBlock);
floatLocals.push_back(new AllocaInst(Type::getFloatTy(*llvmContext), "", currentBlock));
new StoreInst(Constant::getNullValue(Type::getFloatTy(*llvmContext)), floatLocals.back(), false, currentBlock);
objectLocals.push_back(new AllocaInst(intrinsics->JavaObjectType, "",
currentBlock));
// The GCStrategy will already initialize the value.
if (!TheCompiler->useCooperativeGC())
new StoreInst(Constant::getNullValue(intrinsics->JavaObjectType), objectLocals.back(), false, currentBlock);
}
for (int i = 0; i < maxStack; i++) {
objectStack.push_back(new AllocaInst(intrinsics->JavaObjectType, "",
currentBlock));
addHighLevelType(objectStack.back(), upcalls->OfObject);
intStack.push_back(new AllocaInst(Type::getInt32Ty(*llvmContext), "", currentBlock));
doubleStack.push_back(new AllocaInst(Type::getDoubleTy(*llvmContext), "", currentBlock));
longStack.push_back(new AllocaInst(Type::getInt64Ty(*llvmContext), "", currentBlock));
floatStack.push_back(new AllocaInst(Type::getFloatTy(*llvmContext), "", 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)) {
Instruction* V = new StoreInst(i, objectLocals[0], false, currentBlock);
addHighLevelType(V, compilingClass);
++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(*llvmContext)){
new StoreInst(i, longLocals[index], false, currentBlock);
++index;
} else if (cur->isUnsigned()) {
new StoreInst(new ZExtInst(i, Type::getInt32Ty(*llvmContext), "", currentBlock),
intLocals[index], false, currentBlock);
} else if (curType == Type::getInt8Ty(*llvmContext) || curType == Type::getInt16Ty(*llvmContext)) {
new StoreInst(new SExtInst(i, Type::getInt32Ty(*llvmContext), "", currentBlock),
intLocals[index], false, currentBlock);
} else if (curType == Type::getInt32Ty(*llvmContext)) {
new StoreInst(i, intLocals[index], false, currentBlock);
} else if (curType == Type::getDoubleTy(*llvmContext)) {
new StoreInst(i, doubleLocals[index], false, currentBlock);
++index;
} else if (curType == Type::getFloatTy(*llvmContext)) {
new StoreInst(i, floatLocals[index], false, currentBlock);
} else {
Instruction* V = new StoreInst(i, objectLocals[index], false, currentBlock);
addHighLevelType(V, cur->findAssocClass(compilingClass->classLoader));
}
}
#if defined(ISOLATE_SHARING)
ctpCache = i;
Value* addrCtpCache = new AllocaInst(intrinsics->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(intrinsics->MutatorThreadType);
IsolateIDPtr = GetElementPtrInst::Create(threadId, intrinsics->constantThree,
"", currentBlock);
const Type* realType = PointerType::getUnqual(intrinsics->pointerSizeType);
IsolateIDPtr = new BitCastInst(IsolateIDPtr, realType, "",
currentBlock);
OldIsolateID = new LoadInst(IsolateIDPtr, "", currentBlock);
Value* MyID = ConstantInt::get(intrinsics->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, intrinsics->constantFour, "",
currentBlock);
OldIsolate = new LoadInst(IsolatePtr, "", currentBlock);
NewIsolate = intrinsics->getIsolate(loader->getIsolate(), currentBlock);
new StoreInst(NewIsolate, IsolatePtr, currentBlock);
#if DEBUG
Value* GEP[2] = { OldIsolate, NewIsolate };
CallInst::Create(intrinsics->ServiceCallStartFunction, GEP, GEP + 2,
"", currentBlock);
#endif
BranchInst::Create(EndBB, currentBlock);
currentBlock = EndBB;
}
#endif
readExceptionTable(reader, codeLen);
// Lookup line number table attribute.
uint16 nba = reader.readU2();
for (uint16 i = 0; i < nba; ++i) {
const UTF8* attName = compilingClass->ctpInfo->UTF8At(reader.readU2());
uint32 attLen = reader.readU4();
if (attName->equals(Attribut::lineNumberTableAttribut)) {
uint16 lineLength = reader.readU2();
for (uint16 i = 0; i < lineLength; ++i) {
uint16 pc = reader.readU2();
uint16 ln = reader.readU2();
opcodeInfos[pc].lineNumber = ln;
}
} else {
reader.seek(attLen, Reader::SeekCur);
}
}
exploreOpcodes(&compilingClass->bytes->elements[start], codeLen);
endBlock = createBasicBlock("end");
if (returnType != Type::getVoidTy(*llvmContext)) {
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(intrinsics->llvm_frameaddress,
intrinsics->constantZero, "", currentBlock);
FrameAddr = new PtrToIntInst(FrameAddr, intrinsics->pointerSizeType, "",
currentBlock);
Value* stackCheck =
BinaryOperator::CreateAnd(FrameAddr, intrinsics->constantStackOverflowMask,
"", currentBlock);
stackCheck = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, stackCheck,
intrinsics->constantPtrZero, "");
BasicBlock* stackOverflow = createBasicBlock("stack overflow");
BasicBlock* noStackOverflow = createBasicBlock("no stack overflow");
BranchInst::Create(stackOverflow, noStackOverflow, stackCheck,
currentBlock);
currentBlock = stackOverflow;
throwException(intrinsics->StackOverflowErrorFunction, 0, 0);
currentBlock = noStackOverflow;
}
if (TheCompiler->useCooperativeGC()) {
Value* threadId = getCurrentThread(intrinsics->MutatorThreadType);
Value* GEP[2] = { intrinsics->constantZero,
intrinsics->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(intrinsics->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(*llvmContext)) {
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(intrinsics->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(intrinsics->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(*llvmContext))
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, intrinsics, TheCompiler->useCooperativeGC());
removeUnusedObjects(objectStack, intrinsics, TheCompiler->useCooperativeGC());
delete[] opcodeInfos;
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
Attribut* annotationsAtt =
compilingMethod->lookupAttribut(Attribut::annotationsAttribut);
if (annotationsAtt) {
Reader reader(annotationsAtt, &(compilingClass->bytes));
AnnotationReader AR(reader, compilingClass);
uint16 numAnnotations = reader.readU2();
for (uint16 i = 0; i < numAnnotations; ++i) {
AR.readAnnotation();
const UTF8* name =
compilingClass->ctpInfo->UTF8At(AR.AnnotationNameIndex);
if (name->equals(TheCompiler->InlinePragma)) {
llvmFunction->addFnAttr(Attribute::AlwaysInline);
} else if (name->equals(TheCompiler->NoInlinePragma)) {
llvmFunction->addFnAttr(Attribute::NoInline);
}
}
}
return llvmFunction;
}
void JavaJIT::compareFP(Value* val1, Value* val2, const Type* ty, bool l) {
Value* one = intrinsics->constantOne;
Value* zero = intrinsics->constantZero;
Value* minus = intrinsics->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, upcalls->newString);
} else {
JavaString** str = (JavaString**)ctpInfo->ctpRes[index];
if (str) {
Value* val = TheCompiler->getStringPtr(str);
val = new LoadInst(val, "", currentBlock);
push(val, false, upcalls->newString);
} else {
// Lookup the constant pool cache
const llvm::Type* Ty = PointerType::getUnqual(intrinsics->JavaObjectType);
Value* val = getConstantPoolAt(index, intrinsics->StringLookupFunction,
Ty, 0, false);
val = new LoadInst(val, "", currentBlock);
push(val, false, upcalls->newString);
}
}
#endif
} else if (type == JavaConstantPool::ConstantLong) {
push(ConstantInt::get(Type::getInt64Ty(*llvmContext), ctpInfo->LongAt(index)),
false);
} else if (type == JavaConstantPool::ConstantDouble) {
push(ConstantFP::get(Type::getDoubleTy(*llvmContext), ctpInfo->DoubleAt(index)),
false);
} else if (type == JavaConstantPool::ConstantInteger) {
push(ConstantInt::get(Type::getInt32Ty(*llvmContext), ctpInfo->IntegerAt(index)),
false);
} else if (type == JavaConstantPool::ConstantFloat) {
push(ConstantFP::get(Type::getFloatTy(*llvmContext), ctpInfo->FloatAt(index)),
false);
} else if (type == JavaConstantPool::ConstantClass) {
UserCommonClass* cl = 0;
Value* res = getResolvedCommonClass(index, false, &cl);
res = CallInst::Create(intrinsics->GetClassDelegateeFunction, res, "",
currentBlock);
push(res, false, upcalls->newClass);
} 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 = intrinsics->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(intrinsics->NullPointerExceptionFunction, 0, 0);
currentBlock = cont;
}
}
Value* JavaJIT::verifyAndComputePtr(Value* obj, Value* index,
const Type* arrayType, bool verif) {
JITVerifyNull(obj);
if (index->getType() != Type::getInt32Ty(*llvmContext)) {
index = new SExtInst(index, Type::getInt32Ty(*llvmContext), "", 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(intrinsics->IndexOutOfBoundsExceptionFunction, args, 2);
currentBlock = ifTrue;
}
Constant* zero = intrinsics->constantZero;
Value* val = new BitCastInst(obj, arrayType, "", currentBlock);
Value* indexes[3] = { zero, intrinsics->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(*llvmContext) || it->get() == Type::getDoubleTy(*llvmContext)) {
pop();
}
Value* tmp = pop();
const Type* type = it->get();
if (tmp->getType() != type) { // int8 or int16
convertValue(tmp, type, currentBlock, false);
}
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) {
JnjvmBootstrapLoader* loader = compilingClass->classLoader->bootstrapLoader;
if (name->equals(loader->abs)) {
const Type* Ty = args[0]->getType();
if (Ty == Type::getInt32Ty(*llvmContext)) {
Constant* const_int32_9 = intrinsics->constantZero;
Constant* const_int32_10 = intrinsics->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(*llvmContext)) {
Constant* const_int64_9 = intrinsics->constantLongZero;
Constant* const_int64_10 = intrinsics->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(*llvmContext)) {
return llvm::CallInst::Create(intrinsics->func_llvm_fabs_f32, args[0],
"tmp1", currentBlock);
} else if (Ty == Type::getDoubleTy(*llvmContext)) {
return llvm::CallInst::Create(intrinsics->func_llvm_fabs_f64, args[0],
"tmp1", currentBlock);
}
} else if (name->equals(loader->sqrt)) {
return llvm::CallInst::Create(intrinsics->func_llvm_sqrt_f64, args[0],
"tmp1", currentBlock);
} else if (name->equals(loader->sin)) {
return llvm::CallInst::Create(intrinsics->func_llvm_sin_f64, args[0],
"tmp1", currentBlock);
} else if (name->equals(loader->cos)) {
return llvm::CallInst::Create(intrinsics->func_llvm_cos_f64, args[0],
"tmp1", currentBlock);
} else if (name->equals(loader->tan)) {
return llvm::CallInst::Create(intrinsics->func_llvm_tan_f64, args[0],
"tmp1", currentBlock);
} else if (name->equals(loader->asin)) {
return llvm::CallInst::Create(intrinsics->func_llvm_asin_f64, args[0],
"tmp1", currentBlock);
} else if (name->equals(loader->acos)) {
return llvm::CallInst::Create(intrinsics->func_llvm_acos_f64, args[0],
"tmp1", currentBlock);
} else if (name->equals(loader->atan)) {
return llvm::CallInst::Create(intrinsics->func_llvm_atan_f64, args[0],
"tmp1", currentBlock);
} else if (name->equals(loader->atan2)) {
return llvm::CallInst::Create(intrinsics->func_llvm_atan2_f64,
args.begin(), args.end(), "tmp1",
currentBlock);
} else if (name->equals(loader->exp)) {
return llvm::CallInst::Create(intrinsics->func_llvm_exp_f64, args[0],
"tmp1", currentBlock);
} else if (name->equals(loader->log)) {
return llvm::CallInst::Create(intrinsics->func_llvm_log_f64, args[0],
"tmp1", currentBlock);
} else if (name->equals(loader->pow)) {
return llvm::CallInst::Create(intrinsics->func_llvm_pow_f64, args.begin(),
args.end(), "tmp1", currentBlock);
} else if (name->equals(loader->ceil)) {
return llvm::CallInst::Create(intrinsics->func_llvm_ceil_f64, args[0], "tmp1",
currentBlock);
} else if (name->equals(loader->floor)) {
return llvm::CallInst::Create(intrinsics->func_llvm_floor_f64, args[0],
"tmp1", currentBlock);
} else if (name->equals(loader->rint)) {
return llvm::CallInst::Create(intrinsics->func_llvm_rint_f64, args[0],
"tmp1", currentBlock);
} else if (name->equals(loader->cbrt)) {
return llvm::CallInst::Create(intrinsics->func_llvm_cbrt_f64, args[0], "tmp1",
currentBlock);
} else if (name->equals(loader->cosh)) {
return llvm::CallInst::Create(intrinsics->func_llvm_cosh_f64, args[0], "tmp1",
currentBlock);
} else if (name->equals(loader->expm1)) {
return llvm::CallInst::Create(intrinsics->func_llvm_expm1_f64, args[0],
"tmp1", currentBlock);
} else if (name->equals(loader->hypot)) {
return llvm::CallInst::Create(intrinsics->func_llvm_hypot_f64, args[0],
"tmp1", currentBlock);
} else if (name->equals(loader->log10)) {
return llvm::CallInst::Create(intrinsics->func_llvm_log10_f64, args[0],
"tmp1", currentBlock);
} else if (name->equals(loader->log1p)) {
return llvm::CallInst::Create(intrinsics->func_llvm_log1p_f64, args[0],
"tmp1", currentBlock);
} else if (name->equals(loader->sinh)) {
return llvm::CallInst::Create(intrinsics->func_llvm_sinh_f64, args[0],
"tmp1", currentBlock);
} else if (name->equals(loader->tanh)) {
return llvm::CallInst::Create(intrinsics->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) {
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);
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 = intrinsics->ConstantPoolType;
Constant* Nil = Constant::getNullValue(Ty);
GlobalVariable* GV = new GlobalVariable(*llvmFunction->getParent(),Ty, false,
GlobalValue::ExternalLinkage, Nil,
"");
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(*llvmContext), index));
Args.push_back(GV);
res = CallInst::Create(intrinsics->SpecialCtpLookupFunction, Args.begin(),
Args.end(), "", falseCl);
node->addIncoming(res, falseCl);
BranchInst::Create(trueCl, falseCl);
currentBlock = trueCl;
args.push_back(node);
#endif
if (meth && canBeInlined(meth)) {
val = invokeInline(meth, args);
} else {
Value* func = 0;
bool needsInit = false;
if (TheCompiler->needsCallback(meth, &needsInit)) {
if (needsInit) {
// 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(intrinsics->ForceLoadedCheckFunction, Cl, "",
currentBlock);
}
}
func = TheCompiler->addCallback(compilingClass, index, signature, false,
currentBlock);
} else {
func = TheCompiler->getMethod(meth);
}
val = invoke(func, args, "", currentBlock);
}
const llvm::Type* retType = virtualType->getReturnType();
if (retType != Type::getVoidTy(*llvmContext)) {
if (retType == intrinsics->JavaObjectType) {
JnjvmClassLoader* JCL = compilingClass->classLoader;
push(val, false, signature->getReturnType()->findAssocClass(JCL));
} else {
push(val, signature->getReturnType()->isUnsigned());
if (retType == Type::getDoubleTy(*llvmContext) ||
retType == Type::getInt64Ty(*llvmContext)) {
push(intrinsics->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);
#if defined(ISOLATE_SHARING)
Value* newCtpCache = getConstantPoolAt(index,
intrinsics->StaticCtpLookupFunction,
intrinsics->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(intrinsics->ForceInitialisationCheckFunction, Cl, "",
currentBlock);
}
if (meth && canBeInlined(meth)) {
val = invokeInline(meth, args);
} else {
Value* func = 0;
bool needsInit = false;
if (TheCompiler->needsCallback(meth, &needsInit)) {
func = TheCompiler->addCallback(compilingClass, index, signature,
true, currentBlock);
} else {
/*if (meth == upcalls->SystemArraycopy ||
meth == upcalls->VMSystemArraycopy) {
lowerArraycopy(args);
return;
}*/
func = TheCompiler->getMethod(meth);
}
val = invoke(func, args, "", currentBlock);
}
}
const llvm::Type* retType = staticType->getReturnType();
if (retType != Type::getVoidTy(*llvmContext)) {
if (retType == intrinsics->JavaObjectType) {
JnjvmClassLoader* JCL = compilingClass->classLoader;
push(val, false, signature->getReturnType()->findAssocClass(JCL));
} else {
push(val, signature->getReturnType()->isUnsigned());
if (retType == Type::getDoubleTy(*llvmContext) ||
retType == Type::getInt64Ty(*llvmContext)) {
push(intrinsics->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, intrinsics->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(*llvmContext), index));
if (additionalArg) Args.push_back(additionalArg);
Value* res = 0;
if (doThrow) {
res = invoke(intrinsics->GetConstantPoolAtFunction, Args, "",
currentBlock);
} else {
res = CallInst::Create(intrinsics->GetConstantPoolAtFunction, Args.begin(),
Args.end(), "", currentBlock);
}
const Type* realType =
intrinsics->GetConstantPoolAtFunction->getReturnType();
if (returnType == Type::getInt32Ty(*llvmContext)) {
return new PtrToIntInst(res, Type::getInt32Ty(*llvmContext), "", 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() != intrinsics->JavaClassArrayType) {
node = new LoadInst(node, "", currentBlock);
}
if (node->getType() != intrinsics->JavaCommonClassType) {
node = new BitCastInst(node, intrinsics->JavaCommonClassType, "",
currentBlock);
}
} else {
node = getConstantPoolAt(index, intrinsics->ClassLookupFunction,
intrinsics->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, intrinsics->ClassLookupFunction,
intrinsics->JavaClassType, 0, doThrow);
}
if (clinit && needsInit) {
if (node->getType() != intrinsics->JavaClassType) {
node = new BitCastInst(node, intrinsics->JavaClassType, "", currentBlock);
}
return invoke(intrinsics->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(intrinsics->ForceInitialisationCheckFunction, Cl, "",
currentBlock);
}
} else {
VT = CallInst::Create(intrinsics->GetVTFromClassFunction, Cl, "",
currentBlock);
Size = CallInst::Create(intrinsics->GetObjectSizeFromClassFunction, Cl,
"", currentBlock);
}
VT = new BitCastInst(VT, intrinsics->ptrType, "", currentBlock);
Instruction* val = invoke(cl ? intrinsics->AllocateFunction :
intrinsics->AllocateUnresolvedFunction,
Size, VT, "", currentBlock);
if (cl && cl->virtualVT->destructor) {
CallInst::Create(intrinsics->AddFinalizationCandidate, val, "", currentBlock);
}
addHighLevelType(val, cl ? cl : upcalls->OfObject);
val = new BitCastInst(val, intrinsics->JavaObjectType, "", currentBlock);
push(val, false, cl ? cl : upcalls->OfObject);
}
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(intrinsics->InitialisationCheckFunction, Cl, "",
currentBlock);
}
#if !defined(ISOLATE) && !defined(ISOLATE_SHARING)
if (needsCheck) {
CallInst::Create(intrinsics->ForceInitialisationCheckFunction, Cl, "",
currentBlock);
}
object = TheCompiler->getStaticInstance(field->classDef);
#else
object = CallInst::Create(intrinsics->GetStaticInstanceFunction, Cl, "",
currentBlock);
#endif
} else {
type = LCI->getVirtualType();
}
Value* objectConvert = new BitCastInst(object, type, "", currentBlock);
Value* args[2] = { intrinsics->constantZero, LFI->getOffset() };
Value* ptr = llvm::GetElementPtrInst::Create(objectConvert,
args, args + 2, "",
currentBlock);
return ptr;
}
const Type* Pty = intrinsics->arrayPtrType;
Constant* zero = intrinsics->constantZero;
Function* func = stat ? intrinsics->StaticFieldLookupFunction :
intrinsics->VirtualFieldLookupFunction;
const Type* returnType = 0;
if (stat)
returnType = intrinsics->ptrType;
else
returnType = Type::getInt32Ty(*llvmContext);
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->isIntegerTy() && t2->isIntegerTy()) {
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->isFloatTy() && t2->isFloatTy()) {
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) {
Value* val = pop();
Typedef* sign = compilingClass->ctpInfo->infoOfField(index);
LLVMAssessorInfo& LAI = TheCompiler->getTypedefInfo(sign);
const Type* type = LAI.llvmType;
if (type == Type::getInt64Ty(*llvmContext) || type == Type::getDoubleTy(*llvmContext)) {
val = pop();
}
Value* ptr = ldResolved(index, true, 0, type, LAI.llvmTypePtr);
if (type != val->getType()) { // int1, int8, int16
convertValue(val, type, currentBlock, false);
}
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(*llvmContext), val), false);
} else if (prim->isByte()) {
sint8 val = (sint8)field->getInt8Field(Obj);
push(ConstantInt::get(Type::getInt8Ty(*llvmContext), val), false);
} else if (prim->isBool()) {
uint8 val = (uint8)field->getInt8Field(Obj);
push(ConstantInt::get(Type::getInt8Ty(*llvmContext), val), true);
} else if (prim->isShort()) {
sint16 val = (sint16)field->getInt16Field(Obj);
push(ConstantInt::get(Type::getInt16Ty(*llvmContext), val), false);
} else if (prim->isChar()) {
uint16 val = (uint16)field->getInt16Field(Obj);
push(ConstantInt::get(Type::getInt16Ty(*llvmContext), val), true);
} else if (prim->isLong()) {
sint64 val = (sint64)field->getLongField(Obj);
push(ConstantInt::get(Type::getInt64Ty(*llvmContext), val), false);
} else if (prim->isFloat()) {
float val = (float)field->getFloatField(Obj);
push(ConstantFP::get(Type::getFloatTy(*llvmContext), val), false);
} else if (prim->isDouble()) {
double val = (double)field->getDoubleField(Obj);
push(ConstantFP::get(Type::getDoubleTy(*llvmContext), val), false);
} else {
abort();
}
} else {
if (TheCompiler->isStaticCompiling()) {
JavaObject* val = field->getObjectField(Obj);
JnjvmClassLoader* JCL = field->classDef->classLoader;
Value* V = TheCompiler->getFinalObject(val, sign->assocClass(JCL));
CommonClass* cl = mvm::Collector::begOf(val) ? val->getClass() : NULL;
push(V, false, cl);
} else {
Value* V = CallInst::Create(intrinsics->GetFinalObjectFieldFunction, ptr,
"", currentBlock);
JnjvmClassLoader* JCL = compilingClass->classLoader;
push(V, false, sign->findAssocClass(JCL));
}
}
}
}
#endif
if (!final) {
JnjvmClassLoader* JCL = compilingClass->classLoader;
CommonClass* cl = sign->findAssocClass(JCL);
push(new LoadInst(ptr, "", currentBlock), sign->isUnsigned(), cl);
}
if (type == Type::getInt64Ty(*llvmContext) ||
type == Type::getDoubleTy(*llvmContext)) {
push(intrinsics->constantZero, false);
}
}
void JavaJIT::setVirtualField(uint16 index) {
Value* val = pop();
Typedef* sign = compilingClass->ctpInfo->infoOfField(index);
LLVMAssessorInfo& LAI = TheCompiler->getTypedefInfo(sign);
const Type* type = LAI.llvmType;
if (type == Type::getInt64Ty(*llvmContext) ||
type == Type::getDoubleTy(*llvmContext)) {
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, false);
}
new StoreInst(val, ptr, false, currentBlock);
}
void JavaJIT::getVirtualField(uint16 index) {
Typedef* sign = compilingClass->ctpInfo->infoOfField(index);
JnjvmClassLoader* JCL = compilingClass->classLoader;
CommonClass* cl = sign->findAssocClass(JCL);
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;
// In init methods, the fields have not been set yet.
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 = intrinsics->GetFinalInt32FieldFunction;
} else if (prim->isByte()) {
F = intrinsics->GetFinalInt8FieldFunction;
} else if (prim->isBool()) {
F = intrinsics->GetFinalInt8FieldFunction;
} else if (prim->isShort()) {
F = intrinsics->GetFinalInt16FieldFunction;
} else if (prim->isChar()) {
F = intrinsics->GetFinalInt16FieldFunction;
} else if (prim->isLong()) {
F = intrinsics->GetFinalLongFieldFunction;
} else if (prim->isFloat()) {
F = intrinsics->GetFinalFloatFieldFunction;
} else if (prim->isDouble()) {
F = intrinsics->GetFinalDoubleFieldFunction;
} else {
abort();
}
} else {
F = intrinsics->GetFinalObjectFieldFunction;
}
push(CallInst::Create(F, ptr, "", currentBlock), sign->isUnsigned(), cl);
}
}
if (!final) push(new LoadInst(ptr, "", currentBlock), sign->isUnsigned(), cl);
if (type == Type::getInt64Ty(*llvmContext) ||
type == Type::getDoubleTy(*llvmContext)) {
push(intrinsics->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 interface invoke");
PHINode * node = 0;
if (retType != Type::getVoidTy(*llvmContext)) {
node = PHINode::Create(retType, "", endBlock);
}
JITVerifyNull(args[0]);
CommonClass* cl = 0;
JavaMethod* meth = 0;
ctpInfo->infoOfMethod(index, ACC_VIRTUAL, cl, meth);
Value* Meth = 0;
if (meth) {
Meth = TheCompiler->getMethodInClass(meth);
} else {
Meth = getConstantPoolAt(index, intrinsics->InterfaceLookupFunction,
intrinsics->JavaMethodType, 0, false);
}
BasicBlock* label_bb = createBasicBlock("bb");
BasicBlock* label_bb4 = createBasicBlock("bb4");
BasicBlock* label_bb6 = createBasicBlock("bb6");
BasicBlock* label_bb7 = createBasicBlock("bb7");
// Block entry (label_entry)
Value* VT = CallInst::Create(intrinsics->GetVTFunction, args[0], "",
currentBlock);
Value* IMT = CallInst::Create(intrinsics->GetIMTFunction, VT, "",
currentBlock);
uint32_t tableIndex = InterfaceMethodTable::getIndex(name, signature->keyName);
Constant* Index = ConstantInt::get(Type::getInt32Ty(*llvmContext),
tableIndex);
Value* indices[2] = { intrinsics->constantZero, Index };
Instruction* ptr_18 = GetElementPtrInst::Create(IMT, indices, indices + 2, "",
currentBlock);
Instruction* int32_19 = new LoadInst(ptr_18, "", false, currentBlock);
int32_19 = new PtrToIntInst(int32_19, intrinsics->pointerSizeType, "",
currentBlock);
Value* one = ConstantInt::get(intrinsics->pointerSizeType, 1);
Value* zero = ConstantInt::get(intrinsics->pointerSizeType, 0);
BinaryOperator* int32_20 = BinaryOperator::Create(Instruction::And, int32_19,
one, "", currentBlock);
ICmpInst* int1_toBool = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ,
int32_20, zero, "toBool");
BranchInst::Create(label_bb, label_bb4, int1_toBool, currentBlock);
// Block bb (label_bb)
currentBlock = label_bb;
CastInst* ptr_22 = new IntToPtrInst(int32_19, virtualPtrType, "", currentBlock);
Value* ret = invoke(ptr_22, args, "", currentBlock);
if (node) node->addIncoming(ret, currentBlock);
BranchInst::Create(endBlock, currentBlock);
// Block bb4 (label_bb4)
currentBlock = label_bb4;
Constant* MinusTwo = ConstantInt::get(intrinsics->pointerSizeType, -2);
BinaryOperator* int32_25 = BinaryOperator::Create(Instruction::And, int32_19,
MinusTwo, "", currentBlock);
const PointerType* Ty = PointerType::getUnqual(intrinsics->JavaMethodType);
CastInst* ptr_26 = new IntToPtrInst(int32_25, Ty, "", currentBlock);
LoadInst* int32_27 = new LoadInst(ptr_26, "", false, currentBlock);
ICmpInst* int1_28 = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, int32_27,
Meth, "");
BranchInst::Create(label_bb6, label_bb7, int1_28, currentBlock);
// Block bb6 (label_bb6)
currentBlock = label_bb6;
PHINode* ptr_table_0_lcssa = PHINode::Create(Ty, "table.0.lcssa",
currentBlock);
ptr_table_0_lcssa->reserveOperandSpace(2);
ptr_table_0_lcssa->addIncoming(ptr_26, label_bb4);
GetElementPtrInst* ptr_31 = GetElementPtrInst::Create(ptr_table_0_lcssa,
intrinsics->constantOne, "",
currentBlock);
LoadInst* int32_32 = new LoadInst(ptr_31, "", false, currentBlock);
CastInst* ptr_33 = new BitCastInst(int32_32, virtualPtrType, "",
currentBlock);
ret = invoke(ptr_33, args, "", currentBlock);
if (node) node->addIncoming(ret, currentBlock);
BranchInst::Create(endBlock, currentBlock);
// Block bb7 (label_bb7)
currentBlock = label_bb7;
PHINode* int32_indvar = PHINode::Create(Type::getInt32Ty(*llvmContext),
"indvar", currentBlock);
int32_indvar->reserveOperandSpace(2);
int32_indvar->addIncoming(intrinsics->constantZero, label_bb4);
BinaryOperator* int32_table_010_rec =
BinaryOperator::Create(Instruction::Shl, int32_indvar, intrinsics->constantOne,
"table.010.rec", currentBlock);
BinaryOperator* int32__rec =
BinaryOperator::Create(Instruction::Add, int32_table_010_rec,
intrinsics->constantTwo, ".rec", currentBlock);
GetElementPtrInst* ptr_37 = GetElementPtrInst::Create(ptr_26, int32__rec, "",
currentBlock);
LoadInst* int32_38 = new LoadInst(ptr_37, "", false, currentBlock);
ICmpInst* int1_39 = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, int32_38,
Meth, "");
BinaryOperator* int32_indvar_next =
BinaryOperator::Create(Instruction::Add, int32_indvar, intrinsics->constantOne,
"indvar.next", currentBlock);
BranchInst::Create(label_bb6, label_bb7, int1_39, currentBlock);
int32_indvar->addIncoming(int32_indvar_next, currentBlock);
ptr_table_0_lcssa->addIncoming(ptr_37, currentBlock);
currentBlock = endBlock;
if (node) {
if (node->getType() == intrinsics->JavaObjectType) {
JnjvmClassLoader* JCL = compilingClass->classLoader;
push(node, false, signature->getReturnType()->findAssocClass(JCL));
} else {
push(node, signature->getReturnType()->isUnsigned());
if (retType == Type::getDoubleTy(*llvmContext) ||
retType == Type::getInt64Ty(*llvmContext)) {
push(intrinsics->constantZero, false);
}
}
}
}
void JavaJIT::lowerArraycopy(std::vector<Value*>& args) {
Function* meth = TheCompiler->getMethod(upcalls->VMSystemArraycopy);
Value* ptr_src = args[0];
Value* int32_start = args[1];
Value* ptr_dst = args[2];
Value* int32_start2 = args[3];
Value* int32_length = args[4];
JITVerifyNull(ptr_src);
JITVerifyNull(ptr_dst);
BasicBlock* label_entry = currentBlock;
BasicBlock* label_bb = createBasicBlock("bb");
BasicBlock* label_bb2 = createBasicBlock("bb2");
BasicBlock* label_bb4 = createBasicBlock("bb4");
BasicBlock* label_bb5 = createBasicBlock("bb5");
BasicBlock* label_bb12_preheader = createBasicBlock("bb12.preheader");
BasicBlock* label_bb7 = createBasicBlock("bb7");
BasicBlock* label_bb11 = createBasicBlock("bb11");
BasicBlock* label_memmove = createBasicBlock("memmove");
BasicBlock* label_backward = createBasicBlock("backward");
BasicBlock* label_return = createBasicBlock("return");
BasicBlock* log_label_entry = createBasicBlock("log_entry");
BasicBlock* log_label_bb = createBasicBlock("log_bb");
// Block entry (label_entry)
CallInst* ptr_16 = CallInst::Create(intrinsics->GetVTFunction, ptr_src, "",
label_entry);
CallInst* ptr_17 = CallInst::Create(intrinsics->GetVTFunction, ptr_dst, "",
label_entry);
ICmpInst* int1_18 = new ICmpInst(*label_entry, ICmpInst::ICMP_EQ, ptr_16,
ptr_17, "");
BranchInst::Create(label_bb, label_bb2, int1_18, label_entry);
// Block bb (label_bb)
currentBlock = label_bb;
CallInst* ptr_20 = CallInst::Create(intrinsics->GetClassFunction, ptr_src, "",
label_bb);
std::vector<Value*> ptr_21_indices;
ptr_21_indices.push_back(intrinsics->constantZero);
ptr_21_indices.push_back(intrinsics->OffsetAccessInCommonClassConstant);
Instruction* ptr_21 =
GetElementPtrInst::Create(ptr_20, ptr_21_indices.begin(),
ptr_21_indices.end(), "", label_bb);
LoadInst* int32_22 = new LoadInst(ptr_21, "", false, label_bb);
Value* cmp = BinaryOperator::CreateAnd(int32_22, intrinsics->IsArrayConstant, "",
label_bb);
Value* zero = ConstantInt::get(Type::getInt16Ty(*llvmContext), 0);
ICmpInst* int1_23 = new ICmpInst(*label_bb, ICmpInst::ICMP_NE, cmp, zero, "");
BranchInst::Create(label_bb4, label_bb2, int1_23, label_bb);
// Block bb2 (label_bb2)
currentBlock = label_bb2;
invoke(meth, args, "", label_bb2);
BranchInst::Create(label_return, currentBlock);
// Block bb4 (label_bb4)
currentBlock = label_bb4;
BinaryOperator* int32_27 = BinaryOperator::Create(Instruction::Add,
int32_length, int32_start,
"", label_bb4);
Value* int32_28 = arraySize(ptr_src);
ICmpInst* int1_29 = new ICmpInst(*label_bb4, ICmpInst::ICMP_ULE, int32_27,
int32_28, "");
BranchInst::Create(label_bb5, label_bb7, int1_29, label_bb4);
// Block bb5 (label_bb5)
currentBlock = label_bb5;
BinaryOperator* int32_31 = BinaryOperator::Create(Instruction::Add,
int32_length, int32_start2,
"", label_bb5);
Value* int32_32 = arraySize(ptr_dst);
ICmpInst* int1_33 = new ICmpInst(*label_bb5, ICmpInst::ICMP_ULE, int32_31,
int32_32, "");
BranchInst::Create(label_bb12_preheader, label_bb7, int1_33, label_bb5);
// Block bb12.preheader (label_bb12_preheader)
currentBlock = label_bb12_preheader;
ICmpInst* int1_35 = new ICmpInst(*label_bb12_preheader, ICmpInst::ICMP_UGT,
int32_length, intrinsics->constantZero, "");
BranchInst::Create(log_label_entry, label_return, int1_35, label_bb12_preheader);
// Block bb7 (label_bb7)
currentBlock = label_bb7;
Value* VTArgs[1] = { Constant::getNullValue(intrinsics->VTType) };
throwException(intrinsics->ArrayStoreExceptionFunction, VTArgs, 1);
// Block entry (label_entry)
currentBlock = log_label_entry;
Value* ptr_10_indices[2] = { intrinsics->constantZero,
intrinsics->OffsetBaseClassInArrayClassConstant };
Instruction* temp = new BitCastInst(ptr_20, intrinsics->JavaClassArrayType, "",
log_label_entry);
Instruction* ptr_10 = GetElementPtrInst::Create(temp, ptr_10_indices,
ptr_10_indices + 2, "",
log_label_entry);
LoadInst* ptr_11 = new LoadInst(ptr_10, "", false, log_label_entry);
Value* ptr_12_indices[2] = { intrinsics->constantZero,
intrinsics->OffsetAccessInCommonClassConstant };
Instruction* ptr_12 = GetElementPtrInst::Create(ptr_11, ptr_12_indices,
ptr_12_indices + 2, "",
log_label_entry);
LoadInst* int16_13 = new LoadInst(ptr_12, "", false, log_label_entry);
BinaryOperator* int32_15 = BinaryOperator::Create(Instruction::And, int16_13,
intrinsics->IsPrimitiveConstant,
"", log_label_entry);
ICmpInst* int1_16 = new ICmpInst(*log_label_entry, ICmpInst::ICMP_EQ,
int32_15, zero, "");
BranchInst::Create(label_bb2, log_label_bb, int1_16, log_label_entry);
// Block bb (log_label_bb)
currentBlock = log_label_bb;
Value* ptr_11_indices[2] = { intrinsics->constantZero,
intrinsics->OffsetLogSizeInPrimitiveClassConstant };
temp = new BitCastInst(ptr_11, intrinsics->JavaClassPrimitiveType, "",
log_label_bb);
GetElementPtrInst* ptr_18 = GetElementPtrInst::Create(temp, ptr_11_indices,
ptr_11_indices + 2, "",
log_label_bb);
LoadInst* int32_20 = new LoadInst(ptr_18, "", false, log_label_bb);
int32_start = BinaryOperator::CreateShl(int32_start, int32_20, "",
log_label_bb);
int32_start2 = BinaryOperator::CreateShl(int32_start2, int32_20, "",
log_label_bb);
int32_length = BinaryOperator::CreateShl(int32_length, int32_20, "",
log_label_bb);
ptr_src = new BitCastInst(ptr_src, intrinsics->JavaArrayUInt8Type, "",
log_label_bb);
ptr_dst = new BitCastInst(ptr_dst, intrinsics->JavaArrayUInt8Type, "",
log_label_bb);
Value* indexes[3] = { intrinsics->constantZero,
intrinsics->JavaArrayElementsOffsetConstant,
int32_start };
Instruction* ptr_42 = GetElementPtrInst::Create(ptr_src, indexes, indexes + 3,
"", log_label_bb);
indexes[2] = int32_start2;
Instruction* ptr_44 = GetElementPtrInst::Create(ptr_dst, indexes, indexes + 3,
"", log_label_bb);
BranchInst::Create(label_memmove, log_label_bb);
// Block memmove
currentBlock = label_memmove;
Value* src_int = new PtrToIntInst(ptr_42, intrinsics->pointerSizeType, "",
currentBlock);
Value* dst_int = new PtrToIntInst(ptr_44, intrinsics->pointerSizeType, "",
currentBlock);
cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_ULT, dst_int, src_int, "");
Value* increment = SelectInst::Create(cmp, intrinsics->constantOne,
intrinsics->constantMinusOne, "",
currentBlock);
BranchInst::Create(label_bb11, label_backward, cmp, currentBlock);
PHINode* phi_dst_ptr = PHINode::Create(ptr_44->getType(), "", label_bb11);
PHINode* phi_src_ptr = PHINode::Create(ptr_44->getType(), "", label_bb11);
phi_dst_ptr->addIncoming(ptr_44, currentBlock);
phi_src_ptr->addIncoming(ptr_42, currentBlock);
// Block backward
currentBlock = label_backward;
ptr_42 = GetElementPtrInst::Create(ptr_42, int32_length, "",
currentBlock);
ptr_44 = GetElementPtrInst::Create(ptr_44, int32_length, "",
currentBlock);
ptr_42 = GetElementPtrInst::Create(ptr_42, intrinsics->constantMinusOne, "",
currentBlock);
ptr_44 = GetElementPtrInst::Create(ptr_44, intrinsics->constantMinusOne, "",
currentBlock);
phi_dst_ptr->addIncoming(ptr_44, currentBlock);
phi_src_ptr->addIncoming(ptr_42, currentBlock);
BranchInst::Create(label_bb11, currentBlock);
// Block bb11 (label_bb11)
currentBlock = label_bb11;
Argument* fwdref_39 = new Argument(Type::getInt32Ty(*llvmContext));
PHINode* int32_i_016 = PHINode::Create(Type::getInt32Ty(*llvmContext),
"i.016", label_bb11);
int32_i_016->reserveOperandSpace(2);
int32_i_016->addIncoming(fwdref_39, label_bb11);
int32_i_016->addIncoming(intrinsics->constantZero, log_label_bb);
LoadInst* ptr_43 = new LoadInst(phi_src_ptr, "", false, label_bb11);
new StoreInst(ptr_43, phi_dst_ptr, false, label_bb11);
ptr_42 = GetElementPtrInst::Create(phi_src_ptr, increment, "",
label_bb11);
ptr_44 = GetElementPtrInst::Create(phi_dst_ptr, increment, "",
label_bb11);
phi_dst_ptr->addIncoming(ptr_44, label_bb11);
phi_src_ptr->addIncoming(ptr_42, label_bb11);
BinaryOperator* int32_indvar_next =
BinaryOperator::Create(Instruction::Add, int32_i_016, intrinsics->constantOne,
"indvar.next", label_bb11);
ICmpInst* int1_exitcond = new ICmpInst(*label_bb11, ICmpInst::ICMP_EQ,
int32_indvar_next, int32_length,
"exitcond");
BranchInst::Create(label_return, label_bb11, int1_exitcond, label_bb11);
// Resolve Forward References
fwdref_39->replaceAllUsesWith(int32_indvar_next); delete fwdref_39;
currentBlock = label_return;
}
MDNode* JavaJIT::CreateLocation() {
uint32_t first = currentLineNumber | (currentBytecodeIndex << 16);
uint32_t second = currentCtpIndex | (callNumber << 16);
DILocation Location = TheCompiler->getDebugFactory()->CreateLocation(
first, second, DIScope(DbgSubprogram));
callNumber++;
return Location.getNode();
}
#ifdef DWARF_EXCEPTIONS
#include "ExceptionsDwarf.inc"
#else
#include "ExceptionsCheck.inc"
#endif