blob: 1494e84f2420d65c435206894c7b99a323b75d1d [file] [log] [blame]
#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);
}
}