| #include <stdio.h> |
| |
| #include "j3/j3.h" |
| #include "j3/j3thread.h" |
| #include "j3/j3reader.h" |
| #include "j3/j3codegen.h" |
| #include "j3/j3class.h" |
| #include "j3/j3constants.h" |
| #include "j3/j3classloader.h" |
| #include "j3/j3method.h" |
| #include "j3/j3mangler.h" |
| #include "j3/j3jni.h" |
| #include "j3/j3object.h" |
| #include "j3/j3field.h" |
| #include "j3/j3attribute.h" |
| |
| #include "llvm/ExecutionEngine/ExecutionEngine.h" |
| |
| #include "llvm/IR/Function.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/IR/Argument.h" |
| #include "llvm/IR/Intrinsics.h" |
| |
| #include "llvm/Transforms/Utils/Cloning.h" |
| #include "llvm/Support/CallSite.h" |
| |
| #include "llvm/DebugInfo.h" |
| #include "llvm/DIBuilder.h" |
| |
| using namespace j3; |
| |
| #define _onEndPoint() ({ if(onEndPoint()) return; }) |
| |
| J3CodeGen::J3CodeGen(vmkit::BumpAllocator* _allocator, J3Method* m, uint32_t _mode) : |
| builder(J3Thread::get()->vm()->llvmContext()), |
| exceptions(this) { |
| |
| allocator = _allocator; |
| mode = _mode; |
| |
| method = m; |
| cl = method->cl()->asClass(); |
| signature = method->signature(); |
| loader = cl->loader(); |
| vm = J3Thread::get()->vm(); |
| access = method->access(); |
| |
| #if 0 |
| /* usefull to debug a single function */ |
| if( cl->name() == vm->names()->get("java.lang.Class") && |
| method->name() == vm->names()->get("asSubclass") && |
| method->signature()->name() == vm->names()->get("(IIILsun/util/calendar/BaseCalendar$Date;)J") ) { |
| vm->options()->genDebugExecute = 2; |
| vm->options()->debugTranslate = 3; |
| vm->options()->debugExecute = 5; |
| } else { |
| vm->options()->genDebugExecute = 0; |
| vm->options()->debugTranslate = 0; |
| //vm->options()->debugExecute = 0; |
| } |
| #endif |
| |
| if(vm->options()->debugTranslate) |
| fprintf(stderr, " translating bytecode of: %s::%s%s\n", |
| cl->name()->cStr(), |
| method->name()->cStr(), |
| method->signature()->name()->cStr()); |
| |
| llvmFunction = method->llvmFunction(); |
| module = llvmFunction ? llvmFunction->getParent() : new llvm::Module(method->llvmFunctionName(), builder.getContext()); |
| |
| bbCheckCastFailed = 0; |
| bbNullCheckFailed = 0; |
| topPendingBranchs = 0; |
| isWide = 0; |
| |
| uintPtrTy = vm->dataLayout()->getIntPtrType(module->getContext()); |
| nullValue = llvm::ConstantPointerNull::get((llvm::PointerType*)vm->typeJ3ObjectPtr); |
| |
| #define _x(name, id, forceInline) \ |
| name = vm->introspectFunction(module, id); |
| #include "j3/j3meta.def" |
| #undef _x |
| |
| gvTypeInfo = vm->introspectGlobalValue(module, "typeinfo for void*"); |
| |
| gcRoot = vm->getGCRoot(module); |
| |
| #if 0 |
| //stackMap = llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::experimental_stackmap); |
| //patchPointVoid = llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::experimental_patchpoint_i64); |
| { |
| llvm::Type* ins[] = { |
| builder.getInt64Ty(), |
| builder.getInt32Ty(), |
| builder.getInt8PtrTy(), |
| builder.getInt32Ty() |
| }; |
| patchPointVoid = (llvm::Function*) |
| module->getOrInsertFunction(llvm::Intrinsic::getName(llvm::Intrinsic::experimental_patchpoint_void), |
| llvm::FunctionType::get(builder.getVoidTy(), ins, 1)); |
| } |
| #endif |
| |
| /* only translate of requested and not already translated */ |
| if(withMethod() && !llvmFunction) { |
| llvmFunction = buildFunction(method, 0); |
| |
| if(needGC()) |
| llvmFunction->setGC("vmkit"); |
| |
| if(J3Cst::isNative(access)) |
| generateNative(); |
| else |
| generateJava(); |
| |
| if(vm->options()->debugTranslate > 2) |
| llvmFunction->dump(); |
| } |
| |
| loader->prepareModule(module); |
| |
| uint32_t needsCaller = withCaller() && !signature->caller(access); |
| |
| if(needsCaller) |
| signature->generateCallerIR(access, this, module, "generic-caller"); |
| |
| /* compile only if requested and not already compiled */ |
| void* fnPtr; |
| if(withMethod() && !onlyTranslate() && !method->fnPtr()) { |
| loader->compileModule(module); |
| fnPtr = (void*)loader->ee()->getFunctionAddress(llvmFunction->getName().data()); |
| } else |
| fnPtr = method->fnPtr(); |
| |
| if(needsCaller) |
| signature->setCaller(access, (J3Signature::function_t)loader->ee()->getFunctionAddress("generic-caller")); |
| |
| method->markCompiled(llvmFunction, fnPtr); |
| |
| if(vm->options()->debugTranslate > 2) |
| llvmFunction->dump(); |
| } |
| |
| J3CodeGen::~J3CodeGen() { |
| } |
| |
| void* J3CodeGen::operator new(size_t n, vmkit::BumpAllocator* _allocator) { |
| return _allocator->allocate(n); |
| } |
| |
| void J3CodeGen::operator delete(void* ptr) { |
| } |
| |
| void J3CodeGen::translate(J3Method* method, uint32_t mode) { |
| J3Thread::get()->vm()->lockCompiler(); |
| |
| vmkit::BumpAllocator* allocator = vmkit::BumpAllocator::create(); |
| delete new(allocator) J3CodeGen(allocator, method, mode); |
| vmkit::BumpAllocator::destroy(allocator); |
| |
| J3Thread::get()->vm()->unlockCompiler(); |
| } |
| |
| uint32_t J3CodeGen::wideReadU1() { |
| if(isWide) { |
| isWide = 0; |
| return codeReader->readU2(); |
| } else |
| return codeReader->readU1(); |
| } |
| |
| uint32_t J3CodeGen::wideReadS1() { |
| if(isWide) { |
| isWide = 0; |
| return codeReader->readS2(); |
| } else |
| return codeReader->readS1(); |
| } |
| |
| llvm::Value* J3CodeGen::flatten(llvm::Value* v) { |
| llvm::Type* type = v->getType(); |
| |
| if(type == vm->typeInteger->llvmType() || type == vm->typeLong->llvmType() || |
| type == vm->typeFloat->llvmType() || type == vm->typeDouble->llvmType() || |
| (type->isPointerTy() && (v->getType() == vm->typeJ3ObjectPtr))) |
| return v; |
| else if(type == vm->typeBoolean->llvmType() || type == vm->typeByte->llvmType() || type == vm->typeShort->llvmType()) |
| return builder.CreateSExt(v, vm->typeInteger->llvmType()); |
| else if(type == vm->typeCharacter->llvmType()) |
| return builder.CreateZExt(v, vm->typeInteger->llvmType()); |
| |
| fprintf(stderr, " v: "); |
| v->getType()->dump(); |
| fprintf(stderr, "\n type: "); |
| type->dump(); |
| fprintf(stderr, "\n"); |
| J3::internalError("should not happen"); |
| } |
| |
| llvm::Value* J3CodeGen::unflatten(llvm::Value* v, llvm::Type* type) { |
| if(type == vm->typeInteger->llvmType() || type == vm->typeLong->llvmType() || |
| type == vm->typeFloat->llvmType() || type == vm->typeDouble->llvmType() || |
| (type->isPointerTy() && type == v->getType())) |
| return v; |
| else if(type == vm->typeBoolean->llvmType() || type == vm->typeByte->llvmType() || type == vm->typeShort->llvmType()) |
| return builder.CreateSExtOrTrunc(v, type); |
| else if(type == vm->typeCharacter->llvmType()) |
| return builder.CreateZExtOrTrunc(v, type); |
| |
| fprintf(stderr, " v: "); |
| v->getType()->dump(); |
| fprintf(stderr, "\n type: "); |
| type->dump(); |
| fprintf(stderr, "\n"); |
| J3::internalError("should not happen"); |
| } |
| |
| llvm::Function* J3CodeGen::buildFunction(J3Method* method, bool isStub) { |
| const char* id = (useStub() && isStub && !method->fnPtr()) ? method->llvmStubName(cl) : method->llvmFunctionName(cl); |
| loader->addSymbol(id, method); |
| return (llvm::Function*)module->getOrInsertFunction(id, method->signature()->functionType(method->access())); |
| } |
| |
| llvm::Value* J3CodeGen::typeDescriptor(J3ObjectType* objectType, llvm::Type* type) { |
| const char* id = objectType->nativeName(); |
| loader->addSymbol(id, objectType); |
| llvm::Value* v = module->getOrInsertGlobal(id, vm->typeJ3ObjectType); |
| return type == vm->typeJ3ObjectTypePtr ? v : builder.CreateBitCast(v, type); |
| } |
| |
| llvm::Value* J3CodeGen::currentThread() { |
| return builder.CreateCall(funcJ3ThreadGet); |
| } |
| |
| void J3CodeGen::monitorEnter(llvm::Value* obj) { |
| builder.CreateCall2(funcJ3ObjectMonitorEnter, obj, builder.CreateAlloca(vm->typeJ3LockRecord)); |
| } |
| |
| void J3CodeGen::monitorExit(llvm::Value* obj) { |
| builder.CreateCall(funcJ3ObjectMonitorExit, obj); |
| } |
| |
| void J3CodeGen::resolveJ3ObjectType(J3ObjectType* cl) { |
| if(!supposeClinited() && !cl->isResolved()) |
| builder.CreateCall(funcJ3ObjectTypeResolve, typeDescriptor(cl, vm->typeJ3TypePtr)); |
| } |
| |
| void J3CodeGen::initialiseJ3ObjectType(J3ObjectType* cl) { |
| if(!supposeClinited() && !cl->isInitialised()) |
| builder.CreateCall(funcJ3ObjectTypeInitialise, typeDescriptor(cl, vm->typeJ3TypePtr)); |
| } |
| |
| llvm::Value* J3CodeGen::javaClass(J3ObjectType* type, bool doPush) { |
| return builder.CreateCall3(funcJ3TypeJavaClass, |
| typeDescriptor(type, vm->typeJ3TypePtr), |
| builder.getInt1(doPush), |
| builder.CreateIntToPtr(llvm::ConstantInt::get(uintPtrTy, (uintptr_t)0), |
| vm->typeJ3ObjectHandlePtr)); |
| } |
| |
| llvm::Value* J3CodeGen::handleToObject(llvm::Value* obj) { |
| llvm::Value* gep[] = { builder.getInt32(0), builder.getInt32(J3ObjectHandle::gepObj) }; |
| return builder.CreateLoad(builder.CreateGEP(obj, gep)); |
| } |
| |
| llvm::Value* J3CodeGen::staticObject(J3Class* cl) { |
| initialiseJ3ObjectType(cl); |
| const char* id = cl->staticObjectId(); |
| loader->addSymbol(id, cl->staticObjectSymbol()); |
| return handleToObject(module->getOrInsertGlobal(id, vm->typeJ3ObjectHandle)); |
| } |
| |
| llvm::Value* J3CodeGen::vt(llvm::Value* obj) { |
| llvm::Value* gepVT[] = { builder.getInt32(0), |
| builder.getInt32(J3Object::gepVT) }; |
| llvm::Instruction* res = builder.CreateLoad(builder.CreateGEP(obj, gepVT)); |
| res->setDebugLoc(llvm::DebugLoc::get(javaPC, 1, dbgInfo)); |
| return res; |
| } |
| |
| llvm::Value* J3CodeGen::vt(J3ObjectType* type) { |
| type->resolve(); |
| const char* id = type->vtId(); |
| loader->addSymbol(id, type->vtSymbol()); |
| return module->getOrInsertGlobal(id, vm->typeJ3VirtualTable); |
| } |
| |
| llvm::Value* J3CodeGen::nullCheck(llvm::Value* obj) { |
| if(!noRuntimeCheck() && exceptions.nodes[curExceptionNode]->landingPad) { |
| llvm::BasicBlock* succeed = newBB("nullcheck-succeed"); |
| |
| if(!bbNullCheckFailed) { |
| llvm::BasicBlock* prev = builder.GetInsertBlock(); |
| bbNullCheckFailed = newBB("nullcheck-failed"); |
| builder.SetInsertPoint(bbNullCheckFailed); |
| builder.CreateInvoke(funcNullPointerException, bbRet, exceptions.nodes[curExceptionNode]->landingPad); |
| builder.SetInsertPoint(prev); |
| } |
| |
| builder.CreateCondBr(builder.CreateIsNotNull(obj), succeed, bbNullCheckFailed); |
| builder.SetInsertPoint(succeed); |
| } |
| |
| return obj; |
| } |
| |
| #define nyi() J3::internalError("not yet implemented: '%s' (%d)", J3Cst::opcodeNames[bc], bc); |
| |
| void J3CodeGen::invoke(uint32_t access, J3Method* target, llvm::Value* func) { |
| J3Signature* type = target->signature(); |
| llvm::FunctionType* fType = target->signature()->functionType(access); |
| uint32_t n = fType->getNumParams(); |
| std::vector<llvm::Value*> args; |
| uint32_t i=n-1; |
| |
| for(llvm::FunctionType::param_iterator it=fType->param_begin(); it!=fType->param_end(); it++) |
| args.push_back(unflatten(stack.top(i--), *it)); |
| |
| stack.drop(n); |
| |
| llvm::Instruction* res; |
| |
| if(exceptions.nodes[curExceptionNode]->landingPad) { |
| //llvm::BasicBlock* after = forwardBranch("invoke-after", codeReader->tell(), 0, 0); |
| llvm::BasicBlock* after = newBB("invoke-after"); |
| res = builder.CreateInvoke(func, after, exceptions.nodes[curExceptionNode]->landingPad, args); |
| builder.SetInsertPoint(after); |
| } else { |
| res = builder.CreateCall(func, args); |
| } |
| |
| res->setDebugLoc(llvm::DebugLoc::get(javaPC, 0, dbgInfo)); |
| |
| if(!res->getType()->isVoidTy()) |
| stack.push(flatten(res)); |
| } |
| |
| void J3CodeGen::invokeInterface(uint32_t idx) { |
| J3Method* target = cl->interfaceMethodAt(idx, 0); |
| J3Signature* type = target->signature(); |
| |
| uint32_t index = target->interfaceIndex(); |
| llvm::Value* thread = currentThread(); |
| llvm::Value* gep[] = { builder.getInt32(0), builder.getInt32(J3Thread::gepInterfaceMethodIndex) }; |
| builder.CreateStore(builder.getInt32(index), builder.CreateGEP(thread, gep)); |
| |
| llvm::Value* obj = nullCheck(stack.top(type->nbIns())); |
| llvm::Value* gepFunc[] = { builder.getInt32(0), |
| builder.getInt32(J3VirtualTable::gepInterfaceMethods), |
| builder.getInt32(index % J3VirtualTable::nbInterfaceMethodTable) }; |
| llvm::Value* func = builder.CreateBitCast(builder.CreateLoad(builder.CreateGEP(vt(obj), gepFunc)), |
| target->signature()->functionType(target->access())->getPointerTo()); |
| |
| invoke(0, target, func); |
| } |
| |
| void J3CodeGen::invokeVirtual(uint32_t idx) { |
| J3Method* target = cl->methodAt(idx, 0); |
| |
| if(J3Cst::isFinal(target->cl()->access()) || J3Cst::isFinal(target->cl()->access())) |
| invoke(0, target, buildFunction(target)); /* do not remove this optimization, mandatory for mmtk */ |
| else { |
| J3Signature* type = target->signature(); |
| llvm::Value* funcEntry = funcEntry = builder.getInt32(target->index()); |
| |
| llvm::Value* obj = nullCheck(stack.top(type->nbIns())); |
| llvm::Value* gepFunc[] = { builder.getInt32(0), |
| builder.getInt32(J3VirtualTable::gepVirtualMethods), |
| funcEntry }; |
| llvm::Value* func = builder.CreateBitCast(builder.CreateLoad(builder.CreateGEP(vt(obj), gepFunc)), |
| target->signature()->functionType(target->access())->getPointerTo()); |
| |
| invoke(0, target, func); |
| } |
| } |
| |
| void J3CodeGen::invokeStatic(uint32_t idx) { |
| J3Method* target = cl->methodAt(idx, J3Cst::ACC_STATIC); |
| invoke(J3Cst::ACC_STATIC, target, buildFunction(target)); |
| } |
| |
| void J3CodeGen::invokeSpecial(uint32_t idx) { |
| J3Method* target = cl->methodAt(idx, 0); |
| invoke(0, target, buildFunction(target)); |
| } |
| |
| llvm::Value* J3CodeGen::fieldOffset(llvm::Value* obj, J3Field* f) { |
| return builder.CreateIntToPtr(builder.CreateAdd(builder.CreatePtrToInt(obj, uintPtrTy), |
| llvm::ConstantInt::get(uintPtrTy, f->offset())), |
| f->type()->llvmType()->getPointerTo()); |
| } |
| |
| void J3CodeGen::get(llvm::Value* src, J3Field* f) { |
| llvm::Value* res = flatten(builder.CreateLoad(fieldOffset(src, f))); |
| stack.push(res); |
| } |
| |
| void J3CodeGen::getField(uint32_t idx) { |
| llvm::Value* obj = stack.pop(); |
| J3Field* f = cl->fieldAt(idx, 0); |
| get(nullCheck(obj), f); |
| } |
| |
| void J3CodeGen::getStatic(uint32_t idx) { |
| J3Field* f = cl->fieldAt(idx, J3Cst::ACC_STATIC); |
| get(staticObject(f->layout()->asStaticLayout()->cl()), f); |
| } |
| |
| void J3CodeGen::put(llvm::Value* dest, llvm::Value* val, J3Field* f) { |
| builder.CreateStore(unflatten(val, f->type()->llvmType()), fieldOffset(dest, f)); |
| } |
| |
| void J3CodeGen::putStatic(uint32_t idx) { |
| J3Field* f = cl->fieldAt(idx, J3Cst::ACC_STATIC); |
| put(staticObject(f->layout()->asStaticLayout()->cl()), stack.pop(), f); |
| } |
| |
| void J3CodeGen::putField(uint32_t idx) { |
| J3Field* f = cl->fieldAt(idx, 0); |
| llvm::Value* val = stack.pop(); |
| llvm::Value* obj = nullCheck(stack.pop()); |
| put(obj, val, f); |
| } |
| |
| void J3CodeGen::arrayBoundCheck(llvm::Value* obj, llvm::Value* idx) { |
| if(!noRuntimeCheck()) { |
| /* implement me */ |
| } |
| } |
| |
| llvm::Value* J3CodeGen::arrayContent(J3Type* cType, llvm::Value* array, llvm::Value* idx) { |
| array = builder.CreateBitCast(array, vm->typeJ3ArrayObjectPtr); |
| return builder.CreateGEP(builder.CreateBitCast(builder.CreateGEP(array, builder.getInt32(1)), cType->llvmType()->getPointerTo()), |
| idx); |
| } |
| |
| void J3CodeGen::arrayStore(J3Type* cType) { |
| llvm::Value* val = stack.pop(); |
| llvm::Value* idx = stack.pop(); |
| llvm::Value* array = stack.pop(); |
| |
| arrayBoundCheck(array, idx); |
| builder.CreateStore(unflatten(val, cType->llvmType()), arrayContent(cType, array, idx)); |
| } |
| |
| void J3CodeGen::arrayLoad(J3Type* cType) { |
| llvm::Value* idx = stack.pop(); |
| llvm::Value* array = stack.pop(); |
| |
| arrayBoundCheck(array, idx); |
| stack.push(flatten(builder.CreateLoad(arrayContent(cType, array, idx)))); |
| } |
| |
| llvm::Value* J3CodeGen::arrayLengthPtr(llvm::Value* obj) { |
| llvm::Value* gep[2] = { builder.getInt32(0), builder.getInt32(J3ArrayObject::gepLength) }; |
| return builder.CreateGEP(builder.CreateBitCast(obj, vm->typeJ3ArrayObjectPtr), gep); |
| } |
| |
| llvm::Value* J3CodeGen::arrayLength(llvm::Value* obj) { |
| return builder.CreateLoad(arrayLengthPtr(obj)); |
| } |
| |
| void J3CodeGen::newArray(J3ArrayClass* array) { |
| initialiseJ3ObjectType(array); |
| llvm::Value* length = stack.pop(); |
| llvm::Value* nbb = |
| builder.CreateAdd(llvm::ConstantInt::get(uintPtrTy, sizeof(J3ArrayObject)), |
| builder.CreateMul(llvm::ConstantInt::get(uintPtrTy, 1 << array->component()->logSize()), |
| builder.CreateZExtOrBitCast(length, uintPtrTy))); |
| |
| llvm::Value* res = builder.CreateCall2(funcJ3ObjectAllocate, vt(array), nbb); |
| |
| builder.CreateStore(length, arrayLengthPtr(res)); |
| |
| stack.push(res); |
| } |
| |
| void J3CodeGen::newArray(uint8_t atype) { |
| J3Primitive* prim = 0; |
| |
| switch(atype) { |
| case J3Cst::T_BOOLEAN: prim = vm->typeBoolean; break; |
| case J3Cst::T_CHAR: prim = vm->typeCharacter; break; |
| case J3Cst::T_FLOAT: prim = vm->typeFloat; break; |
| case J3Cst::T_DOUBLE: prim = vm->typeDouble; break; |
| case J3Cst::T_BYTE: prim = vm->typeByte; break; |
| case J3Cst::T_SHORT: prim = vm->typeShort; break; |
| case J3Cst::T_INT: prim = vm->typeInteger; break; |
| case J3Cst::T_LONG: prim = vm->typeLong; break; |
| default: |
| J3::classFormatError(cl, "wrong atype: %d\n", atype); |
| } |
| |
| newArray(prim->getArray()); |
| } |
| |
| void J3CodeGen::multianewArray() { |
| J3ObjectType* base = cl->classAt(codeReader->readU2()); |
| uint32_t dim = codeReader->readU1(); |
| |
| llvm::Value* values = builder.CreateAlloca(builder.getInt32Ty(), builder.getInt32(dim)); |
| |
| for(uint32_t i=0; i<dim; i++) |
| builder.CreateStore(stack.pop(), builder.CreateGEP(values, builder.getInt32(dim-i-1))); |
| |
| stack.push(builder.CreateCall3(funcJ3ArrayObjectMultianewArray, |
| typeDescriptor(base, vm->typeJ3ArrayClassPtr), |
| builder.getInt32(dim), |
| values)); |
| } |
| |
| void J3CodeGen::newObject(J3Class* cl) { |
| initialiseJ3ObjectType(cl); |
| |
| llvm::Value* size; |
| |
| cl->resolve(); |
| size = builder.getInt64(cl->structSize()); |
| |
| llvm::Value* res = builder.CreateCall2(funcJ3ObjectAllocate, vt(cl), size); |
| |
| stack.push(res); |
| } |
| |
| llvm::CallInst* J3CodeGen::isAssignableTo(llvm::Value* obj, J3ObjectType* type) { |
| llvm::Value* vtType = vt(type); /* force the type resolution */ |
| llvm::Value* vtObj = vt(obj); |
| |
| if(type->vt()->isPrimaryChecker()) |
| return builder.CreateCall3(funcFastIsAssignableToPrimaryChecker, |
| vtObj, |
| vtType, |
| builder.getInt32(type->vt()->offset())); |
| else |
| return builder.CreateCall2(funcFastIsAssignableToNonPrimaryChecker, |
| vtObj, |
| vtType); |
| } |
| |
| void J3CodeGen::instanceof(llvm::Value* obj, J3ObjectType* type) { |
| llvm::BasicBlock* after = forwardBranch("instanceof-after", codeReader->tell(), 0, 0); |
| llvm::BasicBlock* nok = newBB("instanceof-null"); |
| llvm::BasicBlock* test = newBB("instanceof"); |
| |
| builder.CreateCondBr(builder.CreateIsNull(obj), nok, test); |
| |
| builder.SetInsertPoint(nok); |
| stack.push(builder.getInt32(0)); |
| builder.CreateBr(after); |
| |
| stack.drop(1); |
| builder.SetInsertPoint(test); |
| llvm::CallInst* is = isAssignableTo(obj, type); |
| stack.push(builder.CreateZExt(is, builder.getInt32Ty())); |
| builder.CreateBr(after); |
| } |
| |
| void J3CodeGen::checkCast(llvm::Value* obj, J3ObjectType* type) { |
| if(!noRuntimeCheck()) { |
| llvm::BasicBlock* succeed = forwardBranch("checkcast-succeed", codeReader->tell(), 0, 0); |
| llvm::BasicBlock* test = newBB("checkcast"); |
| |
| builder.CreateCondBr(builder.CreateIsNull(obj), succeed, test); |
| |
| if(!bbCheckCastFailed) { |
| bbCheckCastFailed = newBB("checkcast-failed"); |
| builder.SetInsertPoint(bbCheckCastFailed); |
| builder.CreateCall(funcClassCastException); |
| builder.CreateBr(bbRet); |
| } |
| |
| builder.SetInsertPoint(test); |
| |
| llvm::CallInst* is = isAssignableTo(obj, type); |
| builder.CreateCondBr(is, succeed, bbCheckCastFailed); |
| } |
| } |
| |
| void J3CodeGen::floatToInteger(J3Type* ftype, J3Type* itype) { |
| llvm::Value* min = llvm::ConstantFP::get(ftype->llvmType(), |
| llvm::APInt::getSignedMinValue(itype->llvmType()->getPrimitiveSizeInBits()).getSExtValue()); |
| llvm::Value* max = llvm::ConstantFP::get(ftype->llvmType(), |
| llvm::APInt::getSignedMaxValue(itype->llvmType()->getPrimitiveSizeInBits()).getZExtValue()); |
| llvm::Value* v = stack.pop(); |
| |
| llvm::Value* c = builder.CreateFCmpONE(v, v); |
| v = builder.CreateSelect(c, llvm::ConstantFP::get(ftype->llvmType(), 0), v); /* nan => 0 */ |
| |
| c = builder.CreateFCmpOGE(v, max); |
| v = builder.CreateSelect(c, max, v); |
| c = builder.CreateFCmpOLE(v, min); |
| v = builder.CreateSelect(c, min, v); |
| |
| stack.push(builder.CreateFPToSI(v, itype->llvmType())); |
| } |
| |
| void J3CodeGen::compareLong() { |
| llvm::Value* val2 = stack.pop(); |
| llvm::Value* val1 = stack.pop(); |
| llvm::Value* one = builder.getInt32(1); |
| llvm::Value* zero = builder.getInt32(0); |
| llvm::Value* minus = builder.getInt32(-1); |
| |
| llvm::Value* c = builder.CreateICmpSGT(val1, val2); |
| llvm::Value* r = builder.CreateSelect(c, one, zero); |
| c = builder.CreateICmpSLT(val1, val2); |
| r = builder.CreateSelect(c, minus, r); |
| |
| stack.push(r); |
| } |
| |
| void J3CodeGen::compareFP(bool isL) { |
| llvm::Value* val2 = stack.pop(); |
| llvm::Value* val1 = stack.pop(); |
| llvm::Value* one = builder.getInt32(1); |
| llvm::Value* zero = builder.getInt32(0); |
| llvm::Value* minus = builder.getInt32(-1); |
| |
| llvm::Value* c = builder.CreateFCmpUGT(val1, val2); |
| llvm::Value* r = builder.CreateSelect(c, one, zero); |
| c = builder.CreateFCmpULT(val1, val2); |
| r = builder.CreateSelect(c, minus, r); |
| c = builder.CreateFCmpUNO(val1, val2); |
| r = builder.CreateSelect(c, isL ? one : minus, r); |
| |
| stack.push(r); |
| } |
| |
| void J3CodeGen::ldc(uint32_t idx) { |
| llvm::Value* res; |
| |
| switch(cl->getCtpType(idx)) { |
| case J3Cst::CONSTANT_Long: res = builder.getInt64(cl->longAt(idx)); break; |
| case J3Cst::CONSTANT_Integer: res = builder.getInt32(cl->integerAt(idx)); break; |
| case J3Cst::CONSTANT_Float: res = llvm::ConstantFP::get(builder.getFloatTy(), cl->floatAt(idx)); break; |
| case J3Cst::CONSTANT_Double: res = llvm::ConstantFP::get(builder.getDoubleTy(), cl->doubleAt(idx)); break; |
| case J3Cst::CONSTANT_Class: res = handleToObject(javaClass(cl->classAt(idx), 0)); break; |
| case J3Cst::CONSTANT_String: |
| res = handleToObject(builder.CreateLoad(module->getOrInsertGlobal(cl->stringAt(idx)->id(), vm->typeJ3ObjectHandlePtr))); |
| break; |
| default: |
| J3::classFormatError(cl, "wrong ldc type: %d\n", cl->getCtpType(idx)); |
| } |
| stack.push(res); |
| } |
| |
| void J3CodeGen::lookupSwitch() { |
| codeReader->seek(((codeReader->tell() - 1) & -4) + 4, J3Reader::SeekSet); |
| llvm::Value* val = stack.pop(); |
| llvm::BasicBlock* def = forwardBranch("lookupswitch-default", javaPC + codeReader->readU4(), 1, 1); |
| uint32_t n = codeReader->readU4(); |
| |
| for(uint32_t i=0; i<n; i++) { |
| int32_t match = codeReader->readS4(); |
| llvm::BasicBlock* ok = forwardBranch("lookupswitch-match", javaPC + codeReader->readS4(), 1, 1); |
| llvm::BasicBlock* nok = i == (n - 1) ? def : newBB("lookupswitch-next"); |
| builder.CreateCondBr(builder.CreateICmpEQ(val, builder.getInt32(match)), ok, nok); |
| builder.SetInsertPoint(nok); |
| } |
| } |
| |
| void J3CodeGen::tableSwitch() { |
| codeReader->seek(((codeReader->tell() - 1) & -4) + 4, J3Reader::SeekSet); |
| llvm::Value* val = stack.pop(); |
| llvm::BasicBlock* def = forwardBranch("tableswitch-default", javaPC + codeReader->readU4(), 1, 1); |
| int32_t low = codeReader->readU4(); |
| int32_t high = codeReader->readU4(); |
| llvm::SwitchInst* dispatch = builder.CreateSwitch(val, def, high - low + 1); |
| |
| for(uint32_t i=low; i<=high; i++) |
| dispatch->addCase(builder.getInt32(i), |
| forwardBranch("tableswitch-match", javaPC + codeReader->readU4(), 1, 1)); |
| } |
| |
| llvm::BasicBlock* J3CodeGen::newBB(const char* name) { |
| return llvm::BasicBlock::Create(llvmFunction->getContext(), name, llvmFunction); |
| } |
| |
| void J3CodeGen::condBr(llvm::Value* op) { |
| builder.CreateCondBr(op, |
| forwardBranch("if-true", javaPC + codeReader->readS2(), 1, 1), |
| forwardBranch("if-false", codeReader->tell(), 0, 0)); |
| } |
| |
| llvm::BasicBlock* J3CodeGen::forwardBranch(const char* id, uint32_t pc, bool doAlloc, bool doPush) { |
| llvm::BasicBlock* res = opInfos[pc].bb; |
| |
| if(res) |
| return res; |
| |
| if(vm->options()->debugTranslate > 2) |
| fprintf(stderr, " forward branch at %d\n", pc); |
| |
| if(opInfos[pc].insn) { |
| //printf("split at %d (%s)\n", pc, id); |
| llvm::Instruction* insn = opInfos[pc].insn; |
| if(!insn) |
| J3::classFormatError(cl, "jmp: not to an instruction"); |
| insn = insn->getNextNode(); |
| //fprintf(stderr, "--- instruction ---\n"); |
| //insn->dump(); |
| llvm::BasicBlock* before = insn->getParent(); |
| llvm::BranchInst* fakeTerminator = 0; |
| bool isSelf = builder.GetInsertBlock() == before; |
| |
| //fprintf(stderr, "--- before split ---\n"); |
| //before->dump(); |
| if(!before->getTerminator()) |
| fakeTerminator = llvm::BranchInst::Create(bbRet, before); |
| |
| llvm::BasicBlock* after = before->splitBasicBlock(insn); |
| |
| if(fakeTerminator) |
| fakeTerminator->eraseFromParent(); |
| |
| if(isSelf) |
| builder.SetInsertPoint(after); |
| |
| //fprintf(stderr, "--- after split ---\n"); |
| //before->dump(); |
| //after->dump(); |
| |
| opInfos[pc].bb = after; |
| return after; |
| } else { |
| llvm::BasicBlock* res = newBB(id); |
| |
| if(doAlloc) { |
| opInfos[pc].metaStack = (llvm::Type**)allocator->allocate(sizeof(llvm::Type*)*stack.maxStack); |
| memcpy(opInfos[pc].metaStack, stack.metaStack, sizeof(llvm::Type*)*stack.topStack); |
| } |
| |
| opInfos[pc].bb = res; |
| opInfos[pc].topStack = stack.topStack; |
| if(doPush) |
| pendingBranchs[topPendingBranchs++] = pc; |
| |
| return res; |
| } |
| } |
| |
| bool J3CodeGen::onEndPoint() { |
| uint32_t pc; |
| do { |
| if(!topPendingBranchs) |
| return 1; |
| pc = pendingBranchs[--topPendingBranchs]; |
| } while(opInfos[pc].insn); |
| closeBB = 0; |
| codeReader->seek(pc, codeReader->SeekSet); |
| return 0; |
| } |
| |
| void J3CodeGen::selectExceptionNode(uint32_t idx) { |
| curExceptionNode = idx; |
| |
| if(!exceptions.nodes[idx]->isAdded) { |
| exceptions.nodes[idx]->isAdded = 1; |
| for(uint32_t i=0; i<exceptions.nodes[idx]->nbEntries; i++) { |
| J3ExceptionEntry* e = exceptions.nodes[idx]->entries[i]; |
| if(!e->isAdded) { |
| e->isAdded = 1; |
| pendingBranchs[topPendingBranchs++] = e->handlerPC; |
| } |
| } |
| } |
| } |
| |
| llvm::Value* J3CodeGen::buildString(const char* msg) { |
| std::vector<llvm::Constant*> elmts; |
| uint32_t n; |
| |
| for(n=0; msg[n]; n++) |
| elmts.push_back(builder.getInt8(msg[n])); |
| |
| elmts.push_back(builder.getInt8(0)); |
| |
| llvm::Constant* str = llvm::ConstantArray::get(llvm::ArrayType::get(builder.getInt8Ty(), n+1), elmts); |
| llvm::Value* var = new llvm::GlobalVariable(*module, |
| str->getType(), |
| 1, |
| llvm::GlobalVariable::InternalLinkage, |
| str); |
| llvm::Value* gep[] = { builder.getInt32(0), builder.getInt32(0) }; |
| |
| return builder.CreateGEP(var, gep); |
| } |
| |
| void J3CodeGen::translate() { |
| if(vm->options()->debugTranslate > 1) |
| exceptions.dump(vm->options()->debugTranslate-1); |
| |
| stack.topStack = 0; |
| _onEndPoint(); |
| closeBB = 1; |
| |
| selectExceptionNode(0); |
| |
| while(codeReader->remaining()) { |
| llvm::Value* val1; |
| llvm::Value* val2; |
| llvm::Value* val3; |
| |
| javaPC = codeReader->tell(); |
| |
| if(javaPC < exceptions.nodes[curExceptionNode]->pc || javaPC >= exceptions.nodes[curExceptionNode+1]->pc) { |
| if(javaPC == exceptions.nodes[curExceptionNode+1]->pc) |
| selectExceptionNode(curExceptionNode+1); |
| else |
| for(uint32_t i=0; i<exceptions.nbNodes; i++) |
| if(exceptions.nodes[i]->pc <= javaPC && javaPC < exceptions.nodes[i+1]->pc) { |
| selectExceptionNode(i); |
| break; |
| } |
| //printf("cur exception node: %d\n", curExceptionNode); |
| } |
| |
| if(opInfos[javaPC].insn || opInfos[javaPC].bb) { |
| if(closeBB && !builder.GetInsertBlock()->getTerminator()) { |
| if(!opInfos[javaPC].bb) |
| J3::internalError("random split???"); |
| builder.CreateBr(opInfos[javaPC].bb); |
| } |
| } |
| |
| if(opInfos[javaPC].insn) { |
| _onEndPoint(); |
| javaPC = codeReader->tell(); |
| } |
| |
| closeBB = 1; |
| |
| if(opInfos[javaPC].bb) { |
| builder.SetInsertPoint(opInfos[javaPC].bb); |
| //printf("Meta stack before: %p\n", metaStack); |
| if(opInfos[javaPC].metaStack) { |
| stack.metaStack = opInfos[javaPC].metaStack; |
| stack.topStack = opInfos[javaPC].topStack; |
| } else if(opInfos[javaPC].topStack == -1) { /* exception handling */ |
| stack.metaStack[0] = vm->typeJ3ObjectPtr; |
| stack.topStack = 1; |
| } |
| //printf("Meta stack after: %p\n", metaStack); |
| } |
| |
| if(opInfos[javaPC].bb || builder.GetInsertBlock()->empty()) |
| opInfos[javaPC].insn = builder.GetInsertBlock()->begin(); |
| else |
| opInfos[javaPC].insn = builder.GetInsertBlock()->end()->getPrevNode(); |
| |
| bc = codeReader->readU1(); |
| |
| switch(vm->options()->debugTranslate) { |
| default: |
| case 5: |
| fprintf(stderr, "--------------------------------------------\n"); |
| llvmFunction->dump(); |
| case 4: |
| stack.dump(); |
| case 3: |
| case 2: |
| fprintf(stderr, " [%4d] decoding: %s\n", javaPC, J3Cst::opcodeNames[bc]); |
| break; |
| case 1: |
| case 0: |
| break; |
| } |
| |
| genDebugOpcode(); |
| |
| switch(bc) { |
| case J3Cst::BC_nop: /* 0x00 */ |
| break; |
| |
| case J3Cst::BC_aconst_null: /* 0x01 */ |
| stack.push(nullValue); |
| break; |
| |
| case J3Cst::BC_iconst_m1: /* 0x02 */ |
| case J3Cst::BC_iconst_0: /* 0x03 */ |
| case J3Cst::BC_iconst_1: /* 0x04 */ |
| case J3Cst::BC_iconst_2: /* 0x05 */ |
| case J3Cst::BC_iconst_3: /* 0x06 */ |
| case J3Cst::BC_iconst_4: /* 0x07 */ |
| case J3Cst::BC_iconst_5: /* 0x08 */ |
| stack.push(builder.getInt32(bc - J3Cst::BC_iconst_0)); |
| break; |
| |
| case J3Cst::BC_lconst_0: /* 0x09 */ |
| case J3Cst::BC_lconst_1: /* 0x0a */ |
| stack.push(builder.getInt64(bc - J3Cst::BC_lconst_0)); |
| break; |
| |
| case J3Cst::BC_fconst_0: /* 0x0b */ |
| case J3Cst::BC_fconst_1: /* 0x0c */ |
| case J3Cst::BC_fconst_2: /* 0x0d */ |
| stack.push(llvm::ConstantFP::get(builder.getFloatTy(), (bc - J3Cst::BC_fconst_0))); |
| break; |
| |
| case J3Cst::BC_dconst_0: /* 0x0e */ |
| case J3Cst::BC_dconst_1: /* 0x0f */ |
| stack.push(llvm::ConstantFP::get(builder.getDoubleTy(), (bc - J3Cst::BC_dconst_0))); |
| break; |
| |
| case J3Cst::BC_bipush: /* 0x10 */ |
| stack.push(builder.getInt32(codeReader->readS1())); |
| break; |
| |
| case J3Cst::BC_sipush: /* 0x11 */ |
| stack.push(builder.getInt32(codeReader->readS2())); |
| break; |
| |
| case J3Cst::BC_ldc: /* 0x12 */ |
| ldc(codeReader->readU1()); |
| break; |
| |
| case J3Cst::BC_ldc_w: /* 0x13 */ |
| case J3Cst::BC_ldc2_w: /* 0x14 */ |
| ldc(codeReader->readU2()); |
| break; |
| |
| case J3Cst::BC_iload: /* 0x15 wide */ |
| stack.push(locals.at(wideReadU1(), vm->typeInteger->llvmType())); |
| break; |
| |
| case J3Cst::BC_lload: /* 0x16 wide */ |
| stack.push(locals.at(wideReadU1(), vm->typeLong->llvmType())); |
| break; |
| |
| case J3Cst::BC_fload: /* 0x17 wide */ |
| stack.push(locals.at(wideReadU1(), vm->typeFloat->llvmType())); |
| break; |
| |
| case J3Cst::BC_dload: /* 0x18 wide */ |
| stack.push(locals.at(wideReadU1(), vm->typeDouble->llvmType())); |
| break; |
| |
| case J3Cst::BC_aload: /* 0x19 wide */ |
| stack.push(locals.at(wideReadU1(), vm->objectClass->llvmType())); |
| break; |
| |
| case J3Cst::BC_iload_0: /* 0x1a */ |
| case J3Cst::BC_iload_1: /* 0x1b */ |
| case J3Cst::BC_iload_2: /* 0x1c */ |
| case J3Cst::BC_iload_3: /* 0x1d */ |
| stack.push(locals.at(bc - J3Cst::BC_iload_0, vm->typeInteger->llvmType())); |
| break; |
| |
| case J3Cst::BC_lload_0: /* 0x1e */ |
| case J3Cst::BC_lload_1: /* 0x1f */ |
| case J3Cst::BC_lload_2: /* 0x20 */ |
| case J3Cst::BC_lload_3: /* 0x21 */ |
| stack.push(locals.at(bc - J3Cst::BC_lload_0, vm->typeLong->llvmType())); |
| break; |
| |
| case J3Cst::BC_fload_0: /* 0x22 */ |
| case J3Cst::BC_fload_1: /* 0x23 */ |
| case J3Cst::BC_fload_2: /* 0x24 */ |
| case J3Cst::BC_fload_3: /* 0x25 */ |
| stack.push(locals.at(bc - J3Cst::BC_fload_0, vm->typeFloat->llvmType())); |
| break; |
| |
| case J3Cst::BC_dload_0: /* 0x26 */ |
| case J3Cst::BC_dload_1: /* 0x27 */ |
| case J3Cst::BC_dload_2: /* 0x28 */ |
| case J3Cst::BC_dload_3: /* 0x29 */ |
| stack.push(locals.at(bc - J3Cst::BC_dload_0, vm->typeDouble->llvmType())); |
| break; |
| |
| case J3Cst::BC_aload_0: /* 0x2a */ |
| case J3Cst::BC_aload_1: /* 0x2b */ |
| case J3Cst::BC_aload_2: /* 0x2c */ |
| case J3Cst::BC_aload_3: /* 0x2d */ |
| stack.push(locals.at(bc - J3Cst::BC_aload_0, vm->objectClass->llvmType())); |
| break; |
| |
| case J3Cst::BC_iaload: /* 0x2e */ |
| arrayLoad(vm->typeInteger); |
| break; |
| |
| case J3Cst::BC_laload: /* 0x2f */ |
| arrayLoad(vm->typeLong); |
| break; |
| |
| case J3Cst::BC_faload: /* 0x30 */ |
| arrayLoad(vm->typeFloat); |
| break; |
| |
| case J3Cst::BC_daload: /* 0x31 */ |
| arrayLoad(vm->typeDouble); |
| break; |
| |
| case J3Cst::BC_aaload: /* 0x32 */ |
| arrayLoad(vm->objectClass); |
| break; |
| |
| case J3Cst::BC_baload: /* 0x33 */ |
| arrayLoad(vm->typeByte); |
| break; |
| |
| case J3Cst::BC_caload: /* 0x34 */ |
| arrayLoad(vm->typeCharacter); |
| break; |
| |
| case J3Cst::BC_saload: /* 0x35 */ |
| arrayLoad(vm->typeShort); |
| break; |
| |
| case J3Cst::BC_istore: /* 0x36 wide */ |
| case J3Cst::BC_lstore: /* 0x37 wide */ |
| case J3Cst::BC_fstore: /* 0x38 wide */ |
| case J3Cst::BC_dstore: /* 0x39 wide */ |
| case J3Cst::BC_astore: /* 0x3a wide */ |
| locals.setAt(stack.pop(), wideReadU1()); |
| break; |
| |
| case J3Cst::BC_istore_0: /* 0x3b */ |
| case J3Cst::BC_istore_1: /* 0x3c */ |
| case J3Cst::BC_istore_2: /* 0x3d */ |
| case J3Cst::BC_istore_3: /* 0x3e */ |
| locals.setAt(stack.pop(), bc - J3Cst::BC_istore_0); |
| break; |
| |
| case J3Cst::BC_lstore_0: /* 0x3f */ |
| case J3Cst::BC_lstore_1: /* 0x40 */ |
| case J3Cst::BC_lstore_2: /* 0x41 */ |
| case J3Cst::BC_lstore_3: /* 0x42 */ |
| locals.setAt(stack.pop(), bc - J3Cst::BC_lstore_0); |
| break; |
| |
| case J3Cst::BC_fstore_0: /* 0x43 */ |
| case J3Cst::BC_fstore_1: /* 0x44 */ |
| case J3Cst::BC_fstore_2: /* 0x45 */ |
| case J3Cst::BC_fstore_3: /* 0x46 */ |
| locals.setAt(stack.pop(), bc - J3Cst::BC_fstore_0); |
| break; |
| |
| case J3Cst::BC_dstore_0: /* 0x47 */ |
| case J3Cst::BC_dstore_1: /* 0x48 */ |
| case J3Cst::BC_dstore_2: /* 0x49 */ |
| case J3Cst::BC_dstore_3: /* 0x4a */ |
| locals.setAt(stack.pop(), bc - J3Cst::BC_dstore_0); |
| break; |
| |
| case J3Cst::BC_astore_0: /* 0x4b */ |
| case J3Cst::BC_astore_1: /* 0x4c */ |
| case J3Cst::BC_astore_2: /* 0x4d */ |
| case J3Cst::BC_astore_3: /* 0x4e */ |
| locals.setAt(stack.pop(), bc - J3Cst::BC_astore_0); |
| break; |
| |
| case J3Cst::BC_iastore: /* 0x4f */ |
| arrayStore(vm->typeInteger); |
| break; |
| |
| case J3Cst::BC_lastore: /* 0x50 */ |
| arrayStore(vm->typeLong); |
| break; |
| |
| case J3Cst::BC_fastore: /* 0x51 */ |
| arrayStore(vm->typeFloat); |
| break; |
| |
| case J3Cst::BC_dastore: /* 0x52 */ |
| arrayStore(vm->typeDouble); |
| break; |
| |
| case J3Cst::BC_aastore: /* 0x53 */ |
| arrayStore(vm->objectClass); |
| break; |
| |
| case J3Cst::BC_bastore: /* 0x54 */ |
| arrayStore(vm->typeByte); |
| break; |
| |
| case J3Cst::BC_castore: /* 0x55 */ |
| arrayStore(vm->typeCharacter); |
| break; |
| |
| case J3Cst::BC_sastore: /* 0x56 */ |
| arrayStore(vm->typeShort); |
| break; |
| |
| case J3Cst::BC_pop: /* 0x57 */ |
| stack.pop(); |
| break; |
| |
| case J3Cst::BC_pop2: /* 0x58 */ |
| val1 = stack.pop(); |
| if(!val1->getType()->isDoubleTy() && !val1->getType()->isIntegerTy(64)) |
| stack.pop(); |
| break; |
| |
| case J3Cst::BC_dup: /* 0x59 */ |
| stack.push(stack.top()); |
| break; |
| |
| case J3Cst::BC_dup_x1: /* 0x5a */ |
| val1 = stack.pop(); val2 = stack.pop(); |
| stack.push(val1); stack.push(val2); stack.push(val1); |
| break; |
| |
| case J3Cst::BC_dup_x2: /* 0x5b */ |
| val1 = stack.pop(); |
| val2 = stack.pop(); |
| if(val2->getType()->isDoubleTy() || val2->getType()->isIntegerTy(64)) { |
| stack.push(val1); stack.push(val2); stack.push(val1); |
| } else { |
| val3 = stack.pop(); |
| stack.push(val1); stack.push(val3); stack.push(val2); stack.push(val1); |
| } |
| break; |
| |
| case J3Cst::BC_dup2: /* 0x5c */ |
| val1 = stack.top(); |
| if(val1->getType()->isDoubleTy() || val1->getType()->isIntegerTy(64)) { |
| stack.push(val1); |
| } else { |
| val2 = stack.top(1); |
| stack.push(val2); stack.push(val1); |
| } |
| break; |
| |
| case J3Cst::BC_dup2_x1: /* 0x5d */ |
| val1 = stack.pop(); |
| val2 = stack.pop(); |
| if(val1->getType()->isDoubleTy() || val1->getType()->isIntegerTy(64)) { |
| stack.push(val1); stack.push(val2); stack.push(val1); |
| } else { |
| val3 = stack.pop(); |
| stack.push(val2); stack.push(val1); stack.push(val3); stack.push(val2); stack.push(val1); |
| } |
| break; |
| |
| case J3Cst::BC_dup2_x2: /* 0x5e */ |
| val1 = stack.pop(); |
| val2 = stack.pop(); |
| val3 = stack.pop(); |
| if(val1->getType()->isDoubleTy() || val1->getType()->isIntegerTy(64)) { |
| stack.push(val1); stack.push(val3); stack.push(val2); stack.push(val1); |
| } else { |
| llvm::Value* val4 = stack.pop(); |
| stack.push(val2); stack.push(val1); stack.push(val4); stack.push(val3); stack.push(val2); stack.push(val1); |
| } |
| break; |
| |
| case J3Cst::BC_swap: /* 0x5f */ |
| val1 = stack.pop(); val2 = stack.pop(); stack.push(val1); stack.push(val2); |
| break; |
| |
| case J3Cst::BC_iadd: /* 0x60 */ |
| case J3Cst::BC_ladd: /* 0x61 */ |
| val2 = stack.pop(); val1 = stack.pop(); stack.push(builder.CreateAdd(val1, val2)); |
| break; |
| |
| case J3Cst::BC_fadd: /* 0x62 */ |
| case J3Cst::BC_dadd: /* 0x63 */ |
| val2 = stack.pop(); val1 = stack.pop(); stack.push(builder.CreateFAdd(val1, val2)); |
| break; |
| |
| case J3Cst::BC_isub: /* 0x64 */ |
| case J3Cst::BC_lsub: /* 0x65 */ |
| val2 = stack.pop(); val1 = stack.pop(); stack.push(builder.CreateSub(val1, val2)); |
| break; |
| |
| case J3Cst::BC_fsub: /* 0x66 */ |
| case J3Cst::BC_dsub: /* 0x67 */ |
| val2 = stack.pop(); val1 = stack.pop(); stack.push(builder.CreateFSub(val1, val2)); |
| break; |
| |
| case J3Cst::BC_imul: /* 0x68 */ |
| case J3Cst::BC_lmul: /* 0x69 */ |
| val2 = stack.pop(); val1 = stack.pop(); stack.push(builder.CreateMul(val1, val2)); |
| break; |
| |
| case J3Cst::BC_fmul: /* 0x6a */ |
| case J3Cst::BC_dmul: /* 0x6b */ |
| val2 = stack.pop(); val1 = stack.pop(); stack.push(builder.CreateFMul(val1, val2)); |
| break; |
| |
| case J3Cst::BC_idiv: /* 0x6c */ |
| case J3Cst::BC_ldiv: /* 0x6d */ |
| val2 = stack.pop(); val1 = stack.pop(); stack.push(builder.CreateSDiv(val1, val2)); |
| break; |
| |
| case J3Cst::BC_fdiv: /* 0x6e */ |
| case J3Cst::BC_ddiv: /* 0x6f */ |
| val2 = stack.pop(); val1 = stack.pop(); stack.push(builder.CreateFDiv(val1, val2)); |
| break; |
| |
| case J3Cst::BC_irem: /* 0x70 */ |
| case J3Cst::BC_lrem: /* 0x71 */ |
| val2 = stack.pop(); val1 = stack.pop(); stack.push(builder.CreateSRem(val1, val2)); |
| break; |
| |
| case J3Cst::BC_frem: /* 0x72 */ |
| case J3Cst::BC_drem: /* 0x73 */ |
| val2 = stack.pop(); val1 = stack.pop(); stack.push(builder.CreateFRem(val1, val2)); |
| break; |
| |
| case J3Cst::BC_ineg: /* 0x74 */ |
| case J3Cst::BC_lneg: /* 0x75 */ |
| stack.push(builder.CreateNeg(stack.pop())); |
| break; |
| |
| case J3Cst::BC_fneg: /* 0x76 */ |
| case J3Cst::BC_dneg: /* 0x77 */ |
| stack.push(builder.CreateFNeg(stack.pop())); |
| break; |
| |
| case J3Cst::BC_ishl: /* 0x78 */ |
| val2 = stack.pop(); val1 = stack.pop(); stack.push(builder.CreateShl(val1, builder.CreateAnd(val2, 0x1f))); |
| break; |
| |
| case J3Cst::BC_lshl: /* 0x79 */ |
| val2 = stack.pop(); val1 = stack.pop(); |
| stack.push(builder.CreateShl(val1, builder.CreateZExt(builder.CreateAnd(val2, 0x3f), builder.getInt64Ty()))); |
| break; |
| |
| case J3Cst::BC_ishr: /* 0x7a */ |
| val2 = stack.pop(); val1 = stack.pop(); stack.push(builder.CreateAShr(val1, builder.CreateAnd(val2, 0x1f))); |
| break; |
| |
| case J3Cst::BC_lshr: /* 0x7b */ |
| val2 = stack.pop(); val1 = stack.pop(); |
| stack.push(builder.CreateAShr(val1, builder.CreateZExt(builder.CreateAnd(val2, 0x3f), builder.getInt64Ty()))); |
| break; |
| |
| case J3Cst::BC_iushr: /* 0x7c */ |
| val2 = stack.pop(); val1 = stack.pop(); stack.push(builder.CreateLShr(val1, builder.CreateAnd(val2, 0x1f))); |
| break; |
| |
| case J3Cst::BC_lushr: /* 0x7d */ |
| val2 = stack.pop(); val1 = stack.pop(); |
| stack.push(builder.CreateLShr(val1, builder.CreateZExt(builder.CreateAnd(val2, 0x3f), builder.getInt64Ty()))); |
| break; |
| |
| case J3Cst::BC_iand: /* 0x7e */ |
| case J3Cst::BC_land: /* 0x7f */ |
| val2 = stack.pop(); val1 = stack.pop(); stack.push(builder.CreateAnd(val1, val2)); |
| break; |
| |
| case J3Cst::BC_ior: /* 0x80 */ |
| case J3Cst::BC_lor: /* 0x81 */ |
| val2 = stack.pop(); val1 = stack.pop(); stack.push(builder.CreateOr(val1, val2)); |
| break; |
| |
| case J3Cst::BC_ixor: /* 0x82 */ |
| case J3Cst::BC_lxor: /* 0x83 */ |
| val2 = stack.pop(); val1 = stack.pop(); stack.push(builder.CreateXor(val1, val2)); |
| break; |
| |
| case J3Cst::BC_iinc: /* 0x84 wide */ |
| { uint32_t idx = wideReadU1(); |
| int32_t val = wideReadS1(); |
| locals.setAt(builder.CreateAdd(locals.at(idx, vm->typeInteger->llvmType()), builder.getInt32(val)), idx); |
| } break; |
| |
| case J3Cst::BC_i2l: /* 0x85 */ |
| stack.push(builder.CreateSExt(stack.pop(), vm->typeLong->llvmType())); |
| break; |
| |
| case J3Cst::BC_i2f: /* 0x86 */ |
| stack.push(builder.CreateSIToFP(stack.pop(), vm->typeFloat->llvmType())); |
| break; |
| |
| case J3Cst::BC_i2d: /* 0x87 */ |
| stack.push(builder.CreateSIToFP(stack.pop(), vm->typeDouble->llvmType())); |
| break; |
| |
| case J3Cst::BC_l2i: /* 0x88 */ |
| stack.push(builder.CreateTruncOrBitCast(stack.pop(), builder.getInt32Ty())); |
| break; |
| |
| case J3Cst::BC_l2f: /* 0x89 */ |
| stack.push(builder.CreateSIToFP(stack.pop(), vm->typeFloat->llvmType())); |
| break; |
| |
| case J3Cst::BC_l2d: /* 0x8a */ |
| stack.push(builder.CreateSIToFP(stack.pop(), vm->typeDouble->llvmType())); |
| break; |
| |
| case J3Cst::BC_f2i: /* 0x8b */ |
| floatToInteger(vm->typeFloat, vm->typeInteger); |
| break; |
| |
| case J3Cst::BC_f2l: /* 0x8c */ |
| floatToInteger(vm->typeFloat, vm->typeLong); |
| break; |
| |
| case J3Cst::BC_f2d: /* 0x8d */ |
| stack.push(builder.CreateFPExt(stack.pop(), vm->typeDouble->llvmType())); |
| break; |
| |
| case J3Cst::BC_d2i: /* 0x8e */ |
| floatToInteger(vm->typeDouble, vm->typeInteger); |
| break; |
| |
| case J3Cst::BC_d2l: /* 0x8f */ |
| floatToInteger(vm->typeDouble, vm->typeLong); |
| break; |
| |
| case J3Cst::BC_d2f: /* 0x90 */ |
| stack.push(builder.CreateFPTrunc(stack.pop(), vm->typeFloat->llvmType())); |
| break; |
| |
| case J3Cst::BC_i2b: /* 0x91 */ |
| stack.push(builder.CreateSExt(builder.CreateTrunc(stack.pop(), builder.getInt8Ty()), builder.getInt32Ty())); |
| break; |
| |
| case J3Cst::BC_i2c: /* 0x92 */ |
| stack.push(builder.CreateZExt(builder.CreateTrunc(stack.pop(), builder.getInt16Ty()), builder.getInt32Ty())); |
| break; |
| |
| case J3Cst::BC_i2s: /* 0x93 */ |
| stack.push(builder.CreateSExt(builder.CreateTrunc(stack.pop(), builder.getInt16Ty()), builder.getInt32Ty())); |
| break; |
| |
| case J3Cst::BC_lcmp: /* 0x94 */ |
| compareLong(); |
| break; |
| |
| case J3Cst::BC_fcmpl: /* 0x95 */ |
| compareFP(1); |
| break; |
| |
| case J3Cst::BC_fcmpg: /* 0x96 */ |
| compareFP(0); |
| break; |
| |
| case J3Cst::BC_dcmpl: /* 0x97 */ |
| compareFP(0); |
| break; |
| |
| case J3Cst::BC_dcmpg: /* 0x98 */ |
| compareFP(1); |
| break; |
| |
| case J3Cst::BC_ifeq: /* 0x99 */ |
| condBr(builder.CreateICmpEQ(stack.pop(), builder.getInt32(0))); |
| break; |
| |
| case J3Cst::BC_ifne: /* 0x9a */ |
| condBr(builder.CreateICmpNE(stack.pop(), builder.getInt32(0))); |
| break; |
| |
| case J3Cst::BC_iflt: /* 0x9b */ |
| condBr(builder.CreateICmpSLT(stack.pop(), builder.getInt32(0))); |
| break; |
| |
| case J3Cst::BC_ifge: /* 0x9c */ |
| condBr(builder.CreateICmpSGE(stack.pop(), builder.getInt32(0))); |
| break; |
| |
| case J3Cst::BC_ifgt: /* 0x9d */ |
| condBr(builder.CreateICmpSGT(stack.pop(), builder.getInt32(0))); |
| break; |
| |
| case J3Cst::BC_ifle: /* 0x9e */ |
| condBr(builder.CreateICmpSLE(stack.pop(), builder.getInt32(0))); |
| break; |
| |
| case J3Cst::BC_if_icmpeq: /* 0x9f */ |
| val2 = stack.pop(); val1 = stack.pop(); condBr(builder.CreateICmpEQ(val1, val2)); |
| break; |
| |
| case J3Cst::BC_if_icmpne: /* 0xa0 */ |
| val2 = stack.pop(); val1 = stack.pop(); condBr(builder.CreateICmpNE(val1, val2)); |
| break; |
| |
| case J3Cst::BC_if_icmplt: /* 0xa1 */ |
| val2 = stack.pop(); val1 = stack.pop(); condBr(builder.CreateICmpSLT(val1, val2)); |
| break; |
| |
| case J3Cst::BC_if_icmpge: /* 0xa2 */ |
| val2 = stack.pop(); val1 = stack.pop(); condBr(builder.CreateICmpSGE(val1, val2)); |
| break; |
| |
| case J3Cst::BC_if_icmpgt: /* 0xa3 */ |
| val2 = stack.pop(); val1 = stack.pop(); condBr(builder.CreateICmpSGT(val1, val2)); |
| break; |
| |
| case J3Cst::BC_if_icmple: /* 0xa4 */ |
| val2 = stack.pop(); val1 = stack.pop(); condBr(builder.CreateICmpSLE(val1, val2)); |
| break; |
| |
| case J3Cst::BC_if_acmpeq: /* 0xa5 */ |
| val2 = stack.pop(); val1 = stack.pop(); condBr(builder.CreateICmpEQ(val1, val2)); |
| break; |
| |
| case J3Cst::BC_if_acmpne: /* 0xa6 */ |
| val2 = stack.pop(); val1 = stack.pop(); condBr(builder.CreateICmpNE(val1, val2)); |
| break; |
| |
| case J3Cst::BC_goto: /* 0xa7 */ |
| builder.CreateBr(forwardBranch("goto", javaPC + codeReader->readS2(), 0, 1)); |
| _onEndPoint(); |
| break; |
| |
| case J3Cst::BC_jsr: nyi(); /* 0xa8 */ |
| case J3Cst::BC_ret: /* wide */ nyi(); /* 0xa9 */ |
| case J3Cst::BC_tableswitch: /* 0xaa */ |
| tableSwitch(); |
| _onEndPoint(); |
| break; |
| |
| case J3Cst::BC_lookupswitch: |
| lookupSwitch(); |
| _onEndPoint(); |
| break; |
| |
| case J3Cst::BC_ireturn: /* 0xac */ |
| case J3Cst::BC_lreturn: /* 0xad */ |
| case J3Cst::BC_freturn: /* 0xae */ |
| case J3Cst::BC_dreturn: /* 0xaf */ |
| case J3Cst::BC_areturn: /* 0xb0 */ |
| ret.setAt(stack.pop(), 0); |
| builder.CreateBr(bbRet); |
| _onEndPoint(); |
| break; |
| |
| case J3Cst::BC_return: /* 0xb1 */ |
| builder.CreateBr(bbRet); |
| _onEndPoint(); |
| break; |
| |
| case J3Cst::BC_getstatic: /* 0xb2 */ |
| getStatic(codeReader->readU2()); |
| break; |
| |
| case J3Cst::BC_putstatic: /* 0xb3 */ |
| putStatic(codeReader->readU2()); |
| break; |
| |
| case J3Cst::BC_getfield: /* 0xb4 */ |
| getField(codeReader->readU2()); |
| break; |
| |
| case J3Cst::BC_putfield: /* 0xb5 */ |
| putField(codeReader->readU2()); |
| break; |
| |
| case J3Cst::BC_invokevirtual: /* 0xb6 */ |
| invokeVirtual(codeReader->readU2()); |
| break; |
| |
| case J3Cst::BC_invokespecial: /* 0xb7 */ |
| invokeSpecial(codeReader->readU2()); |
| break; |
| |
| case J3Cst::BC_invokestatic: /* 0xb8 */ |
| invokeStatic(codeReader->readU2()); |
| break; |
| |
| case J3Cst::BC_invokeinterface: /* 0xb9 */ |
| invokeInterface(codeReader->readU2()); |
| codeReader->readU2(); |
| break; |
| |
| case J3Cst::BC_new: /* 0xbb */ |
| newObject(cl->classAt(codeReader->readU2())->asClass()); |
| break; |
| |
| case J3Cst::BC_newarray: /* 0xbc */ |
| newArray(codeReader->readU1()); |
| break; |
| |
| case J3Cst::BC_anewarray: /* 0xbd */ |
| newArray(cl->classAt(codeReader->readU2())->getArray()); |
| break; |
| |
| case J3Cst::BC_arraylength: /* 0xbe */ |
| stack.push(arrayLength(stack.pop())); |
| break; |
| |
| case J3Cst::BC_athrow: /* 0xbf */ |
| { |
| llvm::Value* excp = builder.CreateBitCast(stack.pop(), funcThrowException->getFunctionType()->getParamType(0)); |
| if(exceptions.nodes[curExceptionNode]->landingPad) |
| builder.CreateInvoke(funcThrowException, bbRet, exceptions.nodes[curExceptionNode]->landingPad, excp); |
| else { |
| builder.CreateCall(funcThrowException, excp); |
| builder.CreateBr(bbRet); |
| } |
| _onEndPoint(); |
| } |
| break; |
| |
| case J3Cst::BC_checkcast: /* 0xc0 */ |
| checkCast(stack.top(), cl->classAt(codeReader->readU2())); |
| break; |
| |
| case J3Cst::BC_instanceof: /* 0xc1 */ |
| instanceof(stack.pop(), cl->classAt(codeReader->readU2())); |
| break; |
| |
| case J3Cst::BC_monitorenter: /* 0xc2 */ |
| monitorEnter(stack.pop()); |
| break; |
| |
| case J3Cst::BC_monitorexit: /* 0xc3 */ |
| monitorExit(stack.pop()); |
| break; |
| |
| case J3Cst::BC_wide: /* 0xc4 */ |
| isWide = 1; |
| break; |
| |
| case J3Cst::BC_multianewarray: /* 0xc5 */ |
| multianewArray(); |
| break; |
| |
| case J3Cst::BC_ifnull: /* 0xc6 */ |
| condBr(builder.CreateIsNull(stack.pop())); |
| break; |
| |
| case J3Cst::BC_ifnonnull: /* 0xc7 */ |
| condBr(builder.CreateIsNotNull(stack.pop())); |
| break; |
| |
| |
| case J3Cst::BC_goto_w: nyi(); /* 0xc8 */ |
| case J3Cst::BC_jsr_w: nyi(); /* 0xc9 */ |
| |
| case J3Cst::BC_breakpoint: /* 0xca */ |
| case J3Cst::BC_impdep1: /* 0xfe */ |
| case J3Cst::BC_impdep2: /* 0xff */ |
| case J3Cst::BC_xxxunusedxxx1: /* 0xba */ |
| default: |
| J3::classFormatError(cl, "unknow opcode '%s' (%d)", J3Cst::opcodeNames[bc], bc); |
| } |
| } |
| J3::classFormatError(cl, "the last bytecode does not return"); |
| } |
| |
| #if 0 |
| void J3CodeGen::explore() { |
| printf(" exploring bytecode of: %s::%s%s\n", cl->name()->cStr(), method->name()->cStr(), method->signature()->cStr()); |
| while(codeReader->remaining()) { |
| bc = codeReader->readU1(); |
| |
| printf(" exploring: %s (%d)\n", J3Cst::opcodeNames[bc], bc); |
| switch(bc) { |
| #define eat(n) codeReader->seek(n, codeReader->SeekCur); |
| #define defOpcode(id, val, effect) \ |
| case J3Cst::BC_##id: effect; break; |
| #include "j3/j3bc.def" |
| default: |
| J3::internalError("unknow opcode '%s' (%d)", J3Cst::opcodeNames[bc], bc); |
| } |
| } |
| } |
| #endif |
| |
| void J3CodeGen::generateJava() { |
| llvm::BasicBlock* entry = newBB("entry"); |
| builder.SetInsertPoint(entry); |
| |
| J3Attribute* attr = method->attributes()->lookup(vm->codeAttribute); |
| |
| if(!attr) |
| J3::classFormatError(cl, "No Code attribute in %s %s", method->name()->cStr(), method->signature()->name()->cStr()); |
| |
| J3Reader reader(cl->bytes()); |
| reader.seek(attr->offset(), reader.SeekSet); |
| |
| uint32_t length = reader.readU4(); |
| |
| if(!reader.adjustSize(length)) |
| J3::classFormatError(cl, "Code attribute of %s %s is too large (%d)", |
| method->name()->cStr(), |
| method->signature()->name()->cStr(), |
| length); |
| |
| llvm::DIBuilder* dbgBuilder = new llvm::DIBuilder(*module); |
| |
| dbgInfo = |
| dbgBuilder->createFunction(llvm::DIDescriptor(), // Function scope |
| llvmFunction->getName(), // Function name |
| llvmFunction->getName(), // Mangled name |
| llvm::DIFile(), // File where this variable is defined |
| 0, // Line number |
| dbgBuilder // Function type. |
| ->createSubroutineType(llvm::DIFile(), // File in which this subroutine is defined |
| llvm::DIArray()), // An array of subroutine parameter types. |
| // This includes return type at 0th index. |
| false, // True if this function is not externally visible |
| false, // True if this is a function definition |
| 0, // Set to the beginning of the scope this starts |
| 0, |
| false, |
| llvmFunction |
| ); |
| |
| uint32_t maxStack = reader.readU2(); |
| uint32_t nbLocals = reader.readU2(); |
| uint32_t codeLength = reader.readU4(); |
| |
| locals.init(this, nbLocals); |
| stack.init(this, maxStack); |
| ret.init(this, 1); |
| |
| genDebugEnterLeave(0); |
| |
| uint32_t n=0, pos=0; |
| for(llvm::Function::arg_iterator cur=llvmFunction->arg_begin(); cur!=llvmFunction->arg_end(); cur++) { |
| locals.setAt(flatten(cur), pos); |
| pos += (cur->getType() == vm->typeLong->llvmType() || cur->getType() == vm->typeDouble->llvmType()) ? 2 : 1; |
| } |
| |
| //builder.CreateCall(ziTry); |
| |
| pendingBranchs = (uint32_t*)allocator->allocate(sizeof(uint32_t) * codeLength); |
| opInfos = (J3OpInfo*)allocator->allocate(sizeof(J3OpInfo) * codeLength); |
| memset(opInfos, 0, sizeof(J3OpInfo) * codeLength); |
| |
| J3Reader codeReaderTmp(cl->bytes(), reader.tell(), codeLength); |
| codeReader = &codeReaderTmp; |
| |
| bbRet = newBB("ret"); |
| builder.SetInsertPoint(bbRet); |
| |
| genDebugEnterLeave(1); |
| |
| if(llvmFunction->getReturnType()->isVoidTy()) |
| builder.CreateRetVoid(); |
| else |
| builder.CreateRet(unflatten(ret.at(0, llvmFunction->getReturnType()), llvmFunction->getReturnType())); |
| |
| if(J3Cst::isSynchronized(access)) { |
| static bool echoDone = 0; |
| if(!echoDone) { |
| fprintf(stderr, "IMPLEMENT ME: synchronized java\n"); |
| echoDone = 1; |
| } |
| } |
| |
| reader.seek(codeLength, reader.SeekCur); |
| |
| exceptions.read(&reader, codeLength); |
| |
| pendingBranchs[topPendingBranchs++] = codeReader->tell(); |
| |
| builder.SetInsertPoint(entry); |
| |
| translate(); |
| |
| locals.killUnused(); |
| stack.killUnused(); |
| ret.killUnused(); |
| } |
| |
| llvm::Type* J3CodeGen::doNativeType(llvm::Type* type) { |
| return type->isPointerTy() ? vm->typeJ3ObjectHandlePtr : type; |
| } |
| |
| llvm::Function* J3CodeGen::lookupNative() { |
| J3Mangler mangler(cl); |
| |
| mangler.mangle(mangler.javaId)->mangle(cl->name(), method->name()); |
| uint32_t length = mangler.length(); |
| mangler.mangle(method->signature()); |
| |
| void* fnPtr = method->nativeFnPtr(); |
| |
| if(!fnPtr) |
| fnPtr = loader->lookupNativeFunctionPointer(method, mangler.cStr()); |
| |
| if(!fnPtr) { |
| mangler.cStr()[length] = 0; |
| fnPtr = loader->lookupNativeFunctionPointer(method, mangler.cStr()); |
| } |
| |
| if(!fnPtr) |
| J3::linkageError(method); |
| |
| std::vector<llvm::Type*> nativeIns; |
| llvm::Type* nativeOut; |
| |
| nativeIns.push_back(vm->typeJNIEnvPtr); |
| |
| if(J3Cst::isStatic(access)) |
| nativeIns.push_back(doNativeType(vm->classClass->llvmType())); |
| |
| llvm::FunctionType* origFType = method->signature()->functionType(access); |
| for(llvm::FunctionType::param_iterator it=origFType->param_begin(); it!=origFType->param_end(); it++) |
| nativeIns.push_back(doNativeType(*it)); |
| |
| nativeOut = doNativeType(origFType->getReturnType()); |
| |
| char* buf = (char*)loader->allocator()->allocate(mangler.length()+1); |
| memcpy(buf, mangler.cStr(), mangler.length()+1); |
| |
| llvm::FunctionType* fType = llvm::FunctionType::get(nativeOut, nativeIns, 0); |
| llvm::Function* res = llvm::Function::Create(fType, |
| llvm::GlobalValue::ExternalLinkage, |
| buf, |
| module); |
| |
| loader->addSymbol(buf, new(loader->allocator()) vmkit::NativeSymbol(0, fnPtr)); |
| |
| return res; |
| } |
| |
| void J3CodeGen::generateNative() { |
| builder.SetInsertPoint(newBB("entry")); |
| |
| std::vector<llvm::Value*> args; |
| |
| llvm::Function* nat = lookupNative(); |
| |
| llvm::Value* res; |
| llvm::Value* thread = currentThread(); |
| llvm::Value* frame = builder.CreateCall(funcJ3ThreadTell, thread); |
| |
| if(J3Cst::isSynchronized(access)) { |
| static bool echoDone = 0; |
| if(!echoDone) { |
| fprintf(stderr, "IMPLEMENT ME: synchronized java\n"); |
| echoDone = 1; |
| } |
| } |
| |
| args.push_back(builder.CreateCall(funcJniEnv)); |
| if(J3Cst::isStatic(access)) |
| args.push_back(javaClass(cl, 1)); |
| |
| uint32_t selfDone = 0; |
| |
| for(llvm::Function::arg_iterator cur=llvmFunction->arg_begin(); cur!=llvmFunction->arg_end(); cur++) { |
| llvm::Value* v = cur; |
| args.push_back(v->getType()->isPointerTy() ? |
| builder.CreateCall2(funcJ3ThreadPush, thread, v) : |
| v); |
| } |
| |
| res = builder.CreateCall(nat, args); |
| builder.CreateCall(funcReplayException); |
| |
| if(llvmFunction->getReturnType()->isVoidTy()) { |
| builder.CreateCall2(funcJ3ThreadRestore, thread, frame); |
| builder.CreateRetVoid(); |
| } else { |
| if(llvmFunction->getReturnType()->isPointerTy()) { |
| llvm::BasicBlock* ifnull = newBB("ifnull"); |
| llvm::BasicBlock* ifnotnull = newBB("ifnotnull"); |
| builder.CreateCondBr(builder.CreateIsNull(res), ifnull, ifnotnull); |
| |
| builder.SetInsertPoint(ifnull); |
| builder.CreateCall2(funcJ3ThreadRestore, thread, frame); |
| builder.CreateRet(nullValue); |
| |
| builder.SetInsertPoint(ifnotnull); |
| res = handleToObject(res); |
| builder.CreateCall2(funcJ3ThreadRestore, thread, frame); |
| } |
| builder.CreateRet(res); |
| } |
| } |