blob: 98073e448cb0074fbbd60e71eb9914613b61a091 [file] [log] [blame]
//===---- JavaJITOpcodes.cpp - Reads and compiles opcodes -----------------===//
//
// The VMKit project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#define DEBUG 0
#define JNJVM_COMPILE 0
#define JNJVM_EXECUTE 0
#include <cstring>
#include <llvm/Constants.h>
#include <llvm/DerivedTypes.h>
#include <llvm/Function.h>
#include <llvm/Instructions.h>
#include <llvm/Module.h>
#include <llvm/Type.h>
#include "mvm/JIT.h"
#include "debug.h"
#include "JavaArray.h"
#include "JavaClass.h"
#include "JavaConstantPool.h"
#include "JavaObject.h"
#include "JavaJIT.h"
#include "JavaThread.h"
#include "JavaTypes.h"
#include "Jnjvm.h"
#include "j3/J3Intrinsics.h"
#if DEBUG > 0 && (JNJVM_COMPILE > 0 || JNJVM_EXECUTE > 0)
#include "j3/OpcodeNames.def"
#endif
using namespace j3;
using namespace llvm;
uint8 arrayType(JavaMethod* meth, unsigned int t) {
if (t == JavaArray::T_CHAR) {
return I_CHAR;
} else if (t == JavaArray::T_BOOLEAN) {
return I_BOOL;
} else if (t == JavaArray::T_INT) {
return I_INT;
} else if (t == JavaArray::T_SHORT) {
return I_SHORT;
} else if (t == JavaArray::T_BYTE) {
return I_BYTE;
} else if (t == JavaArray::T_FLOAT) {
return I_FLOAT;
} else if (t == JavaArray::T_LONG) {
return I_LONG;
} else if (t == JavaArray::T_DOUBLE) {
return I_DOUBLE;
} else {
fprintf(stderr, "I haven't verified your class file and it's malformed:"
" unknown array type %d in %s.%s!\n", t,
UTF8Buffer(meth->classDef->name).cString(),
UTF8Buffer(meth->name).cString());
abort();
}
}
static inline sint8 readS1(uint8* bytecode, uint32& i) {
return ((sint8*)bytecode)[++i];
}
static inline uint8 readU1(uint8* bytecode, uint32& i) {
return bytecode[++i];
}
static inline sint16 readS2(uint8* bytecode, uint32& i) {
sint16 val = readS1(bytecode, i) << 8;
return val | readU1(bytecode, i);
}
static inline uint16 readU2(uint8* bytecode, uint32& i) {
uint16 val = readU1(bytecode, i) << 8;
return val | readU1(bytecode, i);
}
static inline sint32 readS4(uint8* bytecode, uint32& i) {
sint32 val = readU2(bytecode, i) << 16;
return val | readU2(bytecode, i);
}
static inline uint32 readU4(uint8* bytecode, uint32& i) {
return readS4(bytecode, i);
}
static inline uint32 WREAD_U1(uint8* array, bool init, uint32 &i, bool& wide) {
if (wide) {
wide = init;
return readU2(array, i);
} else {
return readU1(array, i);
}
}
static inline sint32 WREAD_S1(uint8* array, bool init, uint32 &i, bool &wide) {
if (wide) {
wide = init;
return readS2(array, i);
} else {
return readS1(array, i);
}
}
static inline uint32 WCALC(uint32 n, bool& wide) {
if (wide) {
wide = false;
return n << 1;
} else {
return n;
}
}
void JavaJIT::compileOpcodes(uint8* bytecodes, uint32 codeLength) {
bool wide = false;
uint32 jsrIndex = 0;
for(uint32 i = 0; i < codeLength; ++i) {
PRINT_DEBUG(JNJVM_COMPILE, 1, COLOR_NORMAL, "\t[at %5d] %-5d ", i,
bytecodes[i]);
PRINT_DEBUG(JNJVM_COMPILE, 1, LIGHT_BLUE, "compiling ");
PRINT_DEBUG(JNJVM_COMPILE, 1, LIGHT_CYAN, OpcodeNames[bytecodes[i]]);
PRINT_DEBUG(JNJVM_COMPILE, 1, LIGHT_BLUE, "\n");
Opinfo* opinfo = &(opcodeInfos[i]);
if (opinfo->newBlock) {
if (currentBlock->getTerminator() == 0) {
// Load the exception object if we have branched to a handler.
if (opinfo->handler) {
Instruction* I = opinfo->newBlock->begin();
PHINode * node = dyn_cast<PHINode>(I);
assert(node && "Handler marlformed");
Value* obj = pop();
node->addIncoming(obj, currentBlock);
}
branch(*opinfo, currentBlock);
}
currentBlock = opinfo->newBlock;
stack.clear();
if (opinfo->handler) {
Instruction* I = opinfo->newBlock->begin();
assert(isa<PHINode>(I) && "Handler marlformed");
// If it's a handler, put the exception object in the stack.
new StoreInst(I, objectStack[0], "", currentBlock);
stack.push_back(upcalls->OfObject);
currentStackIndex = 1;
} else {
stack = opinfo->stack;
currentStackIndex = stack.size();
}
}
currentExceptionBlock = opinfo->exceptionBlock;
// Update the line number information.
if (opinfo->lineNumber)
currentLineNumber = opinfo->lineNumber;
currentCtpIndex = -1;
currentBytecodeIndex = i;
callNumber = 0;
// To prevent a gcj bug with useless goto
if (currentBlock->getTerminator() != 0) {
currentBlock = createBasicBlock("gcj bug");
}
#if JNJVM_EXECUTE > 1
{
Value* args[3] = {
ConstantInt::get(Type::getInt32Ty(*llvmContext), (int64_t)bytecodes[i]),
ConstantInt::get(Type::getInt32Ty(*llvmContext), (int64_t)i),
TheCompiler->getMethodInClass(compilingMethod)
};
CallInst::Create(intrinsics->PrintExecutionFunction, args, args + 3, "",
currentBlock);
}
#endif
switch (bytecodes[i]) {
case NOP : break;
case ACONST_NULL :
push(intrinsics->JavaObjectNullConstant, false);
break;
case ICONST_M1 :
push(intrinsics->constantMinusOne, false);
break;
case ICONST_0 :
push(intrinsics->constantZero, false);
break;
case ICONST_1 :
push(intrinsics->constantOne, false);
break;
case ICONST_2 :
push(intrinsics->constantTwo, false);
break;
case ICONST_3 :
push(intrinsics->constantThree, false);
break;
case ICONST_4 :
push(intrinsics->constantFour, false);
break;
case ICONST_5 :
push(intrinsics->constantFive, false);
break;
case LCONST_0 :
push(intrinsics->constantLongZero, false);
push(intrinsics->constantZero, false);
break;
case LCONST_1 :
push(intrinsics->constantLongOne, false);
push(intrinsics->constantZero, false);
break;
case FCONST_0 :
push(intrinsics->constantFloatZero, false);
break;
case FCONST_1 :
push(intrinsics->constantFloatOne, false);
break;
case FCONST_2 :
push(intrinsics->constantFloatTwo, false);
break;
case DCONST_0 :
push(intrinsics->constantDoubleZero, false);
push(intrinsics->constantZero, false);
break;
case DCONST_1 :
push(intrinsics->constantDoubleOne, false);
push(intrinsics->constantZero, false);
break;
case BIPUSH :
push(ConstantExpr::getSExt(ConstantInt::get(Type::getInt8Ty(*llvmContext),
bytecodes[++i]),
Type::getInt32Ty(*llvmContext)), false);
break;
case SIPUSH :
push(ConstantExpr::getSExt(ConstantInt::get(Type::getInt16Ty(*llvmContext),
readS2(bytecodes, i)),
Type::getInt32Ty(*llvmContext)), false);
break;
case LDC :
loadConstant(bytecodes[++i]);
break;
case LDC_W :
loadConstant(readS2(bytecodes, i));
break;
case LDC2_W :
loadConstant(readS2(bytecodes, i));
push(intrinsics->constantZero, false);
break;
case ILOAD :
push(new LoadInst(intLocals[WREAD_U1(bytecodes, false, i, wide)], "",
currentBlock), false);
break;
case LLOAD :
push(new LoadInst(longLocals[WREAD_U1(bytecodes, false, i, wide)], "",
currentBlock), false);
push(intrinsics->constantZero, false);
break;
case FLOAD :
push(new LoadInst(floatLocals[WREAD_U1(bytecodes, false, i, wide)], "",
currentBlock), false);
break;
case DLOAD :
push(new LoadInst(doubleLocals[WREAD_U1(bytecodes, false, i, wide)], "",
currentBlock), false);
push(intrinsics->constantZero, false);
break;
case ALOAD :
push(new LoadInst(objectLocals[WREAD_U1(bytecodes, false, i, wide)], "",
currentBlock), false);
break;
case ILOAD_0 :
push(new LoadInst(intLocals[0], "", currentBlock), false);
break;
case ILOAD_1 :
push(new LoadInst(intLocals[1], "", currentBlock), false);
break;
case ILOAD_2 :
push(new LoadInst(intLocals[2], "", currentBlock), false);
break;
case ILOAD_3 :
push(new LoadInst(intLocals[3], "", currentBlock), false);
break;
case LLOAD_0 :
push(new LoadInst(longLocals[0], "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case LLOAD_1 :
push(new LoadInst(longLocals[1], "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case LLOAD_2 :
push(new LoadInst(longLocals[2], "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case LLOAD_3 :
push(new LoadInst(longLocals[3], "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case FLOAD_0 :
push(new LoadInst(floatLocals[0], "", currentBlock),
false);
break;
case FLOAD_1 :
push(new LoadInst(floatLocals[1], "", currentBlock),
false);
break;
case FLOAD_2 :
push(new LoadInst(floatLocals[2], "", currentBlock),
false);
break;
case FLOAD_3 :
push(new LoadInst(floatLocals[3], "", currentBlock),
false);
break;
case DLOAD_0 :
push(new LoadInst(doubleLocals[0], "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case DLOAD_1 :
push(new LoadInst(doubleLocals[1], "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case DLOAD_2 :
push(new LoadInst(doubleLocals[2], "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case DLOAD_3 :
push(new LoadInst(doubleLocals[3], "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case ALOAD_0 :
push(new LoadInst(objectLocals[0], "", currentBlock),
false);
break;
case ALOAD_1 :
push(new LoadInst(objectLocals[1], "", currentBlock),
false);
break;
case ALOAD_2 :
push(new LoadInst(objectLocals[2], "", currentBlock),
false);
break;
case ALOAD_3 :
push(new LoadInst(objectLocals[3], "", currentBlock),
false);
break;
case IALOAD : {
Value* index = pop();
Value* obj = pop();
Value* ptr = verifyAndComputePtr(obj, index,
intrinsics->JavaArraySInt32Type);
push(new LoadInst(ptr, "", currentBlock), false);
break;
}
case LALOAD : {
Value* index = pop();
Value* obj = pop();
Value* ptr = verifyAndComputePtr(obj, index,
intrinsics->JavaArrayLongType);
push(new LoadInst(ptr, "", currentBlock), false);
push(intrinsics->constantZero, false);
break;
}
case FALOAD : {
Value* index = pop();
Value* obj = pop();
Value* ptr = verifyAndComputePtr(obj, index,
intrinsics->JavaArrayFloatType);
push(new LoadInst(ptr, "", currentBlock), false);
break;
}
case DALOAD : {
Value* index = pop();
Value* obj = pop();
Value* ptr = verifyAndComputePtr(obj, index,
intrinsics->JavaArrayDoubleType);
push(new LoadInst(ptr, "", currentBlock), false);
push(intrinsics->constantZero, false);
break;
}
case AALOAD : {
Value* index = pop();
CommonClass* cl = topTypeInfo();
Value* obj = pop();
Value* ptr = verifyAndComputePtr(obj, index,
intrinsics->JavaArrayObjectType);
if (cl->isArray()) cl = cl->asArrayClass()->baseClass();
push(new LoadInst(ptr, "", currentBlock), false, cl);
break;
}
case BALOAD : {
Value* index = pop();
Value* obj = pop();
Value* ptr = verifyAndComputePtr(obj, index,
intrinsics->JavaArraySInt8Type);
Value* val = new LoadInst(ptr, "", currentBlock);
push(new SExtInst(val, Type::getInt32Ty(*llvmContext), "", currentBlock),
false);
break;
}
case CALOAD : {
Value* index = pop();
Value* obj = pop();
Value* ptr = verifyAndComputePtr(obj, index,
intrinsics->JavaArrayUInt16Type);
Value* val = new LoadInst(ptr, "", currentBlock);
push(new ZExtInst(val, Type::getInt32Ty(*llvmContext), "", currentBlock),
false);
break;
}
case SALOAD : {
Value* index = pop();
Value* obj = pop();
Value* ptr = verifyAndComputePtr(obj, index,
intrinsics->JavaArraySInt16Type);
Value* val = new LoadInst(ptr, "", currentBlock);
push(new SExtInst(val, Type::getInt32Ty(*llvmContext), "", currentBlock),
false);
break;
}
case ISTORE : {
Value* val = popAsInt();
new StoreInst(val, intLocals[WREAD_U1(bytecodes, false, i, wide)],
false, currentBlock);
break;
}
case LSTORE :
pop(); // remove the 0 on the stack
new StoreInst(pop(), longLocals[WREAD_U1(bytecodes, false, i, wide)],
false, currentBlock);
break;
case FSTORE :
new StoreInst(pop(), floatLocals[WREAD_U1(bytecodes, false, i, wide)],
false, currentBlock);
break;
case DSTORE :
pop(); // remove the 0 on the stack
new StoreInst(pop(), doubleLocals[WREAD_U1(bytecodes, false, i, wide)],
false, currentBlock);
break;
case ASTORE : {
CommonClass* cl = topTypeInfo();
Instruction* V =
new StoreInst(pop(), objectLocals[WREAD_U1(bytecodes, false, i, wide)],
false, currentBlock);
addHighLevelType(V, cl);
break;
}
case ISTORE_0 : {
Value* val = pop();
if (val->getType() != Type::getInt32Ty(*llvmContext)) // int8 and int16
val = new ZExtInst(val, Type::getInt32Ty(*llvmContext), "", currentBlock);
new StoreInst(val, intLocals[0], false, currentBlock);
break;
}
case ISTORE_1 : {
Value* val = pop();
if (val->getType() != Type::getInt32Ty(*llvmContext)) // int8 and int16
val = new ZExtInst(val, Type::getInt32Ty(*llvmContext), "", currentBlock);
new StoreInst(val, intLocals[1], false, currentBlock);
break;
}
case ISTORE_2 : {
Value* val = pop();
if (val->getType() != Type::getInt32Ty(*llvmContext)) // int8 and int16
val = new ZExtInst(val, Type::getInt32Ty(*llvmContext), "", currentBlock);
new StoreInst(val, intLocals[2], false, currentBlock);
break;
}
case ISTORE_3 : {
Value* val = pop();
if (val->getType() != Type::getInt32Ty(*llvmContext)) // int8 and int16
val = new ZExtInst(val, Type::getInt32Ty(*llvmContext), "", currentBlock);
new StoreInst(val, intLocals[3], false, currentBlock);
break;
}
case LSTORE_0 :
pop(); // remove the 0 on the stack
new StoreInst(pop(), longLocals[0], false, currentBlock);
break;
case LSTORE_1 :
pop(); // remove the 0 on the stack
new StoreInst(pop(), longLocals[1], false, currentBlock);
break;
case LSTORE_2 :
pop(); // remove the 0 on the stack
new StoreInst(pop(), longLocals[2], false, currentBlock);
break;
case LSTORE_3 :
pop(); // remove the 0 on the stack
new StoreInst(pop(), longLocals[3], false, currentBlock);
break;
case FSTORE_0 :
new StoreInst(pop(), floatLocals[0], false, currentBlock);
break;
case FSTORE_1 :
new StoreInst(pop(), floatLocals[1], false, currentBlock);
break;
case FSTORE_2 :
new StoreInst(pop(), floatLocals[2], false, currentBlock);
break;
case FSTORE_3 :
new StoreInst(pop(), floatLocals[3], false, currentBlock);
break;
case DSTORE_0 :
pop(); // remove the 0 on the stack
new StoreInst(pop(), doubleLocals[0], false, currentBlock);
break;
case DSTORE_1 :
pop(); // remove the 0 on the stack
new StoreInst(pop(), doubleLocals[1], false, currentBlock);
break;
case DSTORE_2 :
pop(); // remove the 0 on the stack
new StoreInst(pop(), doubleLocals[2], false, currentBlock);
break;
case DSTORE_3 :
pop(); // remove the 0 on the stack
new StoreInst(pop(), doubleLocals[3], false, currentBlock);
break;
case ASTORE_0 : {
CommonClass* cl = topTypeInfo();
Instruction* V = new StoreInst(pop(), objectLocals[0], false,
currentBlock);
addHighLevelType(V, cl);
break;
}
case ASTORE_1 : {
CommonClass* cl = topTypeInfo();
Instruction* V = new StoreInst(pop(), objectLocals[1], false,
currentBlock);
addHighLevelType(V, cl);
break;
}
case ASTORE_2 : {
CommonClass* cl = topTypeInfo();
Instruction* V = new StoreInst(pop(), objectLocals[2], false,
currentBlock);
addHighLevelType(V, cl);
break;
}
case ASTORE_3 : {
CommonClass* cl = topTypeInfo();
Instruction* V = new StoreInst(pop(), objectLocals[3], false,
currentBlock);
addHighLevelType(V, cl);
break;
}
case IASTORE : {
Value* val = popAsInt();
Value* index = popAsInt();
Value* obj = pop();
Value* ptr = verifyAndComputePtr(obj, index,
intrinsics->JavaArraySInt32Type);
new StoreInst(val, ptr, false, currentBlock);
break;
}
case LASTORE : {
pop(); // remove the 0 on stack
Value* val = pop();
Value* index = pop();
Value* obj = pop();
Value* ptr = verifyAndComputePtr(obj, index,
intrinsics->JavaArrayLongType);
new StoreInst(val, ptr, false, currentBlock);
break;
}
case FASTORE : {
Value* val = pop();
Value* index = pop();
Value* obj = pop();
Value* ptr = verifyAndComputePtr(obj, index,
intrinsics->JavaArrayFloatType);
new StoreInst(val, ptr, false, currentBlock);
break;
}
case DASTORE : {
pop(); // remove the 0 on stack
Value* val = pop();
Value* index = pop();
Value* obj = pop();
Value* ptr = verifyAndComputePtr(obj, index,
intrinsics->JavaArrayDoubleType);
new StoreInst(val, ptr, false, currentBlock);
break;
}
case AASTORE : {
Value* val = pop();
Value* index = pop();
Value* obj = pop();
Value* ptr = verifyAndComputePtr(obj, index,
intrinsics->JavaArrayObjectType);
if (TheCompiler->hasExceptionsEnabled()) {
Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, val,
intrinsics->JavaObjectNullConstant, "");
BasicBlock* endBlock = createBasicBlock("end array store check");
BasicBlock* checkBlock = createBasicBlock("array store check");
BasicBlock* exceptionBlock =
createBasicBlock("array store exception");
BranchInst::Create(endBlock, checkBlock, cmp, currentBlock);
currentBlock = checkBlock;
Value* valVT = CallInst::Create(intrinsics->GetVTFunction, val, "",
currentBlock);
Value* objVT = CallInst::Create(intrinsics->GetVTFunction, obj, "",
currentBlock);
objVT = CallInst::Create(intrinsics->GetBaseClassVTFromVTFunction, objVT,
"", currentBlock);
Value* VTArgs[2] = { valVT, objVT };
Value* res = CallInst::Create(intrinsics->IsAssignableFromFunction,
VTArgs, VTArgs + 2, "", currentBlock);
BranchInst::Create(endBlock, exceptionBlock, res, currentBlock);
currentBlock = exceptionBlock;
throwException(intrinsics->ArrayStoreExceptionFunction, VTArgs, 1);
currentBlock = endBlock;
}
new StoreInst(val, ptr, false, currentBlock);
break;
}
case BASTORE : {
Value* val = pop();
if (val->getType() != Type::getInt8Ty(*llvmContext)) {
val = new TruncInst(val, Type::getInt8Ty(*llvmContext), "", currentBlock);
}
Value* index = pop();
Value* obj = pop();
Value* ptr = verifyAndComputePtr(obj, index,
intrinsics->JavaArraySInt8Type);
new StoreInst(val, ptr, false, currentBlock);
break;
}
case CASTORE : {
Value* val = pop();
const Type* type = val->getType();
if (type == Type::getInt32Ty(*llvmContext)) {
val = new TruncInst(val, Type::getInt16Ty(*llvmContext), "", currentBlock);
} else if (type == Type::getInt8Ty(*llvmContext)) {
val = new ZExtInst(val, Type::getInt16Ty(*llvmContext), "", currentBlock);
}
Value* index = pop();
Value* obj = pop();
Value* ptr = verifyAndComputePtr(obj, index,
intrinsics->JavaArrayUInt16Type);
new StoreInst(val, ptr, false, currentBlock);
break;
}
case SASTORE : {
Value* val = pop();
const Type* type = val->getType();
if (type == Type::getInt32Ty(*llvmContext)) {
val = new TruncInst(val, Type::getInt16Ty(*llvmContext), "", currentBlock);
} else if (type == Type::getInt8Ty(*llvmContext)) {
val = new SExtInst(val, Type::getInt16Ty(*llvmContext), "", currentBlock);
}
Value* index = pop();
Value* obj = pop();
Value* ptr = verifyAndComputePtr(obj, index,
intrinsics->JavaArraySInt16Type);
new StoreInst(val, ptr, false, currentBlock);
break;
}
case POP :
pop();
break;
case POP2 :
pop(); pop();
break;
case DUP :
push(top(), false, topTypeInfo());
break;
case DUP_X1 : {
CommonClass* oneCl = topTypeInfo();
Value* one = pop();
CommonClass* twoCl = topTypeInfo();
Value* two = pop();
push(one, false, oneCl);
push(two, false, twoCl);
push(one, false, oneCl);
break;
}
case DUP_X2 : {
CommonClass* oneCl = topTypeInfo();
Value* one = pop();
CommonClass* twoCl = topTypeInfo();
Value* two = pop();
CommonClass* threeCl = topTypeInfo();
Value* three = pop();
push(one, false, oneCl);
push(three, false, threeCl);
push(two, false, twoCl);
push(one, false, oneCl);
break;
}
case DUP2 : {
CommonClass* oneCl = topTypeInfo();
Value* one = pop();
CommonClass* twoCl = topTypeInfo();
Value* two = pop();
push(two, false, twoCl);
push(one, false, oneCl);
push(two, false, twoCl);
push(one, false, oneCl);
break;
}
case DUP2_X1 : {
CommonClass* oneCl = topTypeInfo();
Value* one = pop();
CommonClass* twoCl = topTypeInfo();
Value* two = pop();
CommonClass* threeCl = topTypeInfo();
Value* three = pop();
push(two, false, twoCl);
push(one, false, oneCl);
push(three, false, threeCl);
push(two, false, twoCl);
push(one, false, oneCl);
break;
}
case DUP2_X2 : {
CommonClass* oneCl = topTypeInfo();
Value* one = pop();
CommonClass* twoCl = topTypeInfo();
Value* two = pop();
CommonClass* threeCl = topTypeInfo();
Value* three = pop();
CommonClass* fourCl = topTypeInfo();
Value* four = pop();
push(two, false, twoCl);
push(one, false, oneCl);
push(four, false, fourCl);
push(three, false, threeCl);
push(two, false, twoCl);
push(one, false, oneCl);
break;
}
case SWAP : {
CommonClass* oneCl = topTypeInfo();
Value* one = pop();
CommonClass* twoCl = topTypeInfo();
Value* two = pop();
push(one, false, oneCl);
push(two, false, twoCl);
break;
}
case IADD : {
Value* val2 = popAsInt();
Value* val1 = popAsInt();
push(BinaryOperator::CreateAdd(val1, val2, "", currentBlock),
false);
break;
}
case LADD : {
pop();
llvm::Value* val2 = pop();
pop();
llvm::Value* val1 = pop();
push(BinaryOperator::CreateAdd(val1, val2, "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
}
case FADD : {
Value* val2 = pop();
Value* val1 = pop();
push(BinaryOperator::CreateFAdd(val1, val2, "", currentBlock),
false);
break;
}
case DADD : {
pop();
llvm::Value* val2 = pop();
pop();
llvm::Value* val1 = pop();
push(BinaryOperator::CreateFAdd(val1, val2, "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
}
case ISUB : {
Value* val2 = popAsInt();
Value* val1 = popAsInt();
push(BinaryOperator::CreateSub(val1, val2, "", currentBlock),
false);
break;
}
case LSUB : {
pop();
llvm::Value* val2 = pop();
pop();
llvm::Value* val1 = pop();
push(BinaryOperator::CreateSub(val1, val2, "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
}
case FSUB : {
Value* val2 = pop();
Value* val1 = pop();
push(BinaryOperator::CreateFSub(val1, val2, "", currentBlock),
false);
break;
}
case DSUB : {
pop();
llvm::Value* val2 = pop();
pop();
llvm::Value* val1 = pop();
push(BinaryOperator::CreateFSub(val1, val2, "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
}
case IMUL : {
Value* val2 = popAsInt();
Value* val1 = popAsInt();
push(BinaryOperator::CreateMul(val1, val2, "", currentBlock),
false);
break;
}
case LMUL : {
pop();
llvm::Value* val2 = pop();
pop();
llvm::Value* val1 = pop();
push(BinaryOperator::CreateMul(val1, val2, "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
}
case FMUL : {
Value* val2 = pop();
Value* val1 = pop();
push(BinaryOperator::CreateFMul(val1, val2, "", currentBlock),
false);
break;
}
case DMUL : {
pop();
llvm::Value* val2 = pop();
pop();
llvm::Value* val1 = pop();
push(BinaryOperator::CreateFMul(val1, val2, "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
}
case IDIV : {
Value* val2 = popAsInt();
Value* val1 = popAsInt();
if (TheCompiler->hasExceptionsEnabled()) {
Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, val2,
intrinsics->constantZero, "");
BasicBlock* ifFalse = createBasicBlock("non null div");
BasicBlock* ifTrue = createBasicBlock("null div");
BranchInst::Create(ifTrue, ifFalse, cmp, currentBlock);
currentBlock = ifTrue;
throwException(intrinsics->ArithmeticExceptionFunction, 0, 0);
currentBlock = ifFalse;
}
push(BinaryOperator::CreateSDiv(val1, val2, "", currentBlock),
false);
break;
}
case LDIV : {
pop();
llvm::Value* val2 = pop();
pop();
llvm::Value* val1 = pop();
if (TheCompiler->hasExceptionsEnabled()) {
Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, val2,
intrinsics->constantLongZero, "");
BasicBlock* ifFalse = createBasicBlock("non null div");
BasicBlock* ifTrue = createBasicBlock("null div");
BranchInst::Create(ifTrue, ifFalse, cmp, currentBlock);
currentBlock = ifTrue;
throwException(intrinsics->ArithmeticExceptionFunction, 0, 0);
currentBlock = ifFalse;
}
push(BinaryOperator::CreateSDiv(val1, val2, "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
}
case FDIV : {
Value* val2 = pop();
Value* val1 = pop();
push(BinaryOperator::CreateFDiv(val1, val2, "", currentBlock),
false);
break;
}
case DDIV : {
pop();
llvm::Value* val2 = pop();
pop();
llvm::Value* val1 = pop();
push(BinaryOperator::CreateFDiv(val1, val2, "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
}
case IREM : {
Value* val2 = popAsInt();
Value* val1 = popAsInt();
push(BinaryOperator::CreateSRem(val1, val2, "", currentBlock),
false);
break;
}
case LREM : {
pop();
llvm::Value* val2 = pop();
pop();
llvm::Value* val1 = pop();
push(BinaryOperator::CreateSRem(val1, val2, "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
}
case FREM : {
Value* val2 = pop();
Value* val1 = pop();
push(BinaryOperator::CreateFRem(val1, val2, "", currentBlock),
false);
break;
}
case DREM : {
pop();
llvm::Value* val2 = pop();
pop();
llvm::Value* val1 = pop();
push(BinaryOperator::CreateFRem(val1, val2, "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
}
case INEG :
push(BinaryOperator::CreateSub(
intrinsics->constantZero,
popAsInt(), "", currentBlock),
false);
break;
case LNEG : {
pop();
push(BinaryOperator::CreateSub(
intrinsics->constantLongZero,
pop(), "", currentBlock), false);
push(intrinsics->constantZero, false);
break;
}
case FNEG :
push(BinaryOperator::CreateSub(
intrinsics->constantFloatMinusZero,
pop(), "", currentBlock), false);
break;
case DNEG : {
pop();
push(BinaryOperator::CreateSub(
intrinsics->constantDoubleMinusZero,
pop(), "", currentBlock), false);
push(intrinsics->constantZero, false);
break;
}
case ISHL : {
Value* val2 = popAsInt();
Value* val1 = popAsInt();
push(BinaryOperator::CreateShl(val1, val2, "", currentBlock),
false);
break;
}
case LSHL : {
Value* val2 = new ZExtInst(pop(), Type::getInt64Ty(*llvmContext), "", currentBlock);
pop(); // remove the 0 on the stack
Value* val1 = pop();
push(BinaryOperator::CreateShl(val1, val2, "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
}
case ISHR : {
Value* val2 = popAsInt();
Value* val1 = popAsInt();
push(BinaryOperator::CreateAShr(val1, val2, "", currentBlock),
false);
break;
}
case LSHR : {
Value* val2 = new ZExtInst(pop(), Type::getInt64Ty(*llvmContext), "", currentBlock);
pop(); // remove the 0 on the stack
Value* val1 = pop();
push(BinaryOperator::CreateAShr(val1, val2, "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
}
case IUSHR : {
Value* val2 = popAsInt();
Value* val1 = popAsInt();
Value* mask = ConstantInt::get(Type::getInt32Ty(*llvmContext), 0x1F);
val2 = BinaryOperator::CreateAnd(val2, mask, "", currentBlock);
push(BinaryOperator::CreateLShr(val1, val2, "", currentBlock),
false);
break;
}
case LUSHR : {
Value* val2 = new ZExtInst(pop(), Type::getInt64Ty(*llvmContext), "", currentBlock);
Value* mask = ConstantInt::get(Type::getInt64Ty(*llvmContext), 0x3F);
val2 = BinaryOperator::CreateAnd(val2, mask, "", currentBlock);
pop(); // remove the 0 on the stack
Value* val1 = pop();
push(BinaryOperator::CreateLShr(val1, val2, "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
}
case IAND : {
Value* val2 = popAsInt();
Value* val1 = popAsInt();
push(BinaryOperator::CreateAnd(val1, val2, "", currentBlock),
false);
break;
}
case LAND : {
pop();
Value* val2 = pop();
pop(); // remove the 0 on the stack
Value* val1 = pop();
push(BinaryOperator::CreateAnd(val1, val2, "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
}
case IOR : {
Value* val2 = popAsInt();
Value* val1 = popAsInt();
push(BinaryOperator::CreateOr(val1, val2, "", currentBlock),
false);
break;
}
case LOR : {
pop();
Value* val2 = pop();
pop(); // remove the 0 on the stack
Value* val1 = pop();
push(BinaryOperator::CreateOr(val1, val2, "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
}
case IXOR : {
Value* val2 = popAsInt();
Value* val1 = popAsInt();
push(BinaryOperator::CreateXor(val1, val2, "", currentBlock),
false);
break;
}
case LXOR : {
pop();
Value* val2 = pop();
pop(); // remove the 0 on the stack
Value* val1 = pop();
push(BinaryOperator::CreateXor(val1, val2, "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
}
case IINC : {
uint16 idx = WREAD_U1(bytecodes, true, i, wide);
sint16 val = WREAD_S1(bytecodes, false, i, wide);
llvm::Value* add = BinaryOperator::CreateAdd(
new LoadInst(intLocals[idx], "", currentBlock),
ConstantInt::get(Type::getInt32Ty(*llvmContext), val), "",
currentBlock);
new StoreInst(add, intLocals[idx], false, currentBlock);
break;
}
case I2L :
push(new SExtInst(pop(), llvm::Type::getInt64Ty(*llvmContext), "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case I2F :
push(new SIToFPInst(pop(), llvm::Type::getFloatTy(*llvmContext), "", currentBlock),
false);
break;
case I2D :
push(new SIToFPInst(pop(), llvm::Type::getDoubleTy(*llvmContext), "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case L2I :
pop();
push(new TruncInst(pop(), llvm::Type::getInt32Ty(*llvmContext), "", currentBlock),
false);
break;
case L2F :
pop();
push(new SIToFPInst(pop(), llvm::Type::getFloatTy(*llvmContext), "", currentBlock),
false);
break;
case L2D :
pop();
push(new SIToFPInst(pop(), llvm::Type::getDoubleTy(*llvmContext), "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case F2I : {
llvm::Value* val = pop();
llvm::Value* test = new FCmpInst(*currentBlock, FCmpInst::FCMP_ONE,
val, val, "");
BasicBlock* res = createBasicBlock("F2I");
PHINode* node = PHINode::Create(llvm::Type::getInt32Ty(*llvmContext), "", res);
node->addIncoming(intrinsics->constantZero, currentBlock);
BasicBlock* cont = createBasicBlock("F2I");
BranchInst::Create(res, cont, test, currentBlock);
currentBlock = cont;
test = new FCmpInst(*currentBlock, FCmpInst::FCMP_OGE, val,
intrinsics->constantMaxIntFloat, "");
cont = createBasicBlock("F2I");
BranchInst::Create(res, cont, test, currentBlock);
node->addIncoming(intrinsics->constantMaxInt,
currentBlock);
currentBlock = cont;
test = new FCmpInst(*currentBlock, FCmpInst::FCMP_OLE, val,
intrinsics->constantMinIntFloat, "");
cont = createBasicBlock("F2I");
BranchInst::Create(res, cont, test, currentBlock);
node->addIncoming(intrinsics->constantMinInt, currentBlock);
currentBlock = cont;
llvm::Value* newVal = new FPToSIInst(val, Type::getInt32Ty(*llvmContext), "",
currentBlock);
BranchInst::Create(res, currentBlock);
node->addIncoming(newVal, currentBlock);
currentBlock = res;
push(node, false);
break;
}
case F2L : {
llvm::Value* val = pop();
llvm::Value* test = new FCmpInst(*currentBlock, FCmpInst::FCMP_ONE,
val, val, "");
BasicBlock* res = createBasicBlock("F2L");
PHINode* node = PHINode::Create(llvm::Type::getInt64Ty(*llvmContext), "", res);
node->addIncoming(intrinsics->constantLongZero, currentBlock);
BasicBlock* cont = createBasicBlock("F2L");
BranchInst::Create(res, cont, test, currentBlock);
currentBlock = cont;
test = new FCmpInst(*currentBlock, FCmpInst::FCMP_OGE, val,
intrinsics->constantMaxLongFloat, "");
cont = createBasicBlock("F2L");
BranchInst::Create(res, cont, test, currentBlock);
node->addIncoming(intrinsics->constantMaxLong, currentBlock);
currentBlock = cont;
test = new FCmpInst(*currentBlock, FCmpInst::FCMP_OLE, val,
intrinsics->constantMinLongFloat, "");
cont = createBasicBlock("F2L");
BranchInst::Create(res, cont, test, currentBlock);
node->addIncoming(intrinsics->constantMinLong, currentBlock);
currentBlock = cont;
llvm::Value* newVal = new FPToSIInst(val, Type::getInt64Ty(*llvmContext), "",
currentBlock);
BranchInst::Create(res, currentBlock);
node->addIncoming(newVal, currentBlock);
currentBlock = res;
push(node, false);
push(intrinsics->constantZero, false);
break;
}
case F2D :
push(new FPExtInst(pop(), llvm::Type::getDoubleTy(*llvmContext), "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case D2I : {
pop(); // remove the 0 on the stack
llvm::Value* val = pop();
llvm::Value* test = new FCmpInst(*currentBlock, FCmpInst::FCMP_ONE,
val, val, "");
BasicBlock* res = createBasicBlock("D2I");
PHINode* node = PHINode::Create(llvm::Type::getInt32Ty(*llvmContext), "", res);
node->addIncoming(intrinsics->constantZero, currentBlock);
BasicBlock* cont = createBasicBlock("D2I");
BranchInst::Create(res, cont, test, currentBlock);
currentBlock = cont;
test = new FCmpInst(*currentBlock, FCmpInst::FCMP_OGE, val,
intrinsics->constantMaxIntDouble, "");
cont = createBasicBlock("D2I");
BranchInst::Create(res, cont, test, currentBlock);
node->addIncoming(intrinsics->constantMaxInt, currentBlock);
currentBlock = cont;
test = new FCmpInst(*currentBlock, FCmpInst::FCMP_OLE, val,
intrinsics->constantMinIntDouble, "");
cont = createBasicBlock("D2I");
BranchInst::Create(res, cont, test, currentBlock);
node->addIncoming(intrinsics->constantMinInt, currentBlock);
currentBlock = cont;
llvm::Value* newVal = new FPToSIInst(val, Type::getInt32Ty(*llvmContext), "",
currentBlock);
BranchInst::Create(res, currentBlock);
node->addIncoming(newVal, currentBlock);
currentBlock = res;
push(node, false);
break;
}
case D2L : {
pop(); // remove the 0 on the stack
llvm::Value* val = pop();
llvm::Value* test = new FCmpInst(*currentBlock, FCmpInst::FCMP_ONE,
val, val, "");
BasicBlock* res = createBasicBlock("D2L");
PHINode* node = PHINode::Create(llvm::Type::getInt64Ty(*llvmContext), "", res);
node->addIncoming(intrinsics->constantLongZero, currentBlock);
BasicBlock* cont = createBasicBlock("D2L");
BranchInst::Create(res, cont, test, currentBlock);
currentBlock = cont;
test = new FCmpInst(*currentBlock, FCmpInst::FCMP_OGE, val,
intrinsics->constantMaxLongDouble, "");
cont = createBasicBlock("D2L");
BranchInst::Create(res, cont, test, currentBlock);
node->addIncoming(intrinsics->constantMaxLong, currentBlock);
currentBlock = cont;
test =
new FCmpInst(*currentBlock, FCmpInst::FCMP_OLE, val,
intrinsics->constantMinLongDouble, "");
cont = createBasicBlock("D2L");
BranchInst::Create(res, cont, test, currentBlock);
node->addIncoming(intrinsics->constantMinLong, currentBlock);
currentBlock = cont;
llvm::Value* newVal = new FPToSIInst(val, Type::getInt64Ty(*llvmContext), "",
currentBlock);
BranchInst::Create(res, currentBlock);
node->addIncoming(newVal, currentBlock);
currentBlock = res;
push(node, false);
push(intrinsics->constantZero, false);
break;
}
case D2F :
pop(); // remove the 0 on the stack
push(new FPTruncInst(pop(), llvm::Type::getFloatTy(*llvmContext), "", currentBlock),
false);
break;
case I2B : {
Value* val = pop();
if (val->getType() == Type::getInt32Ty(*llvmContext)) {
val = new TruncInst(val, llvm::Type::getInt8Ty(*llvmContext), "", currentBlock);
}
push(new SExtInst(val, llvm::Type::getInt32Ty(*llvmContext), "", currentBlock),
false);
break;
}
case I2C : {
Value* val = pop();
if (val->getType() == Type::getInt32Ty(*llvmContext)) {
val = new TruncInst(val, llvm::Type::getInt16Ty(*llvmContext), "", currentBlock);
}
push(new ZExtInst(val, llvm::Type::getInt32Ty(*llvmContext), "", currentBlock),
false);
break;
}
case I2S : {
Value* val = pop();
if (val->getType() == Type::getInt32Ty(*llvmContext)) {
val = new TruncInst(val, llvm::Type::getInt16Ty(*llvmContext), "", currentBlock);
}
push(new SExtInst(val, llvm::Type::getInt32Ty(*llvmContext), "", currentBlock),
false);
break;
}
case LCMP : {
pop();
llvm::Value* val2 = pop();
pop();
llvm::Value* val1 = pop();
llvm::Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, val1,
val2, "");
BasicBlock* cont = createBasicBlock("LCMP");
BasicBlock* res = createBasicBlock("LCMP");
PHINode* node = PHINode::Create(llvm::Type::getInt32Ty(*llvmContext), "", res);
node->addIncoming(intrinsics->constantZero, currentBlock);
BranchInst::Create(res, cont, test, currentBlock);
currentBlock = cont;
test = new ICmpInst(*currentBlock, ICmpInst::ICMP_SLT, val1, val2, "");
node->addIncoming(intrinsics->constantMinusOne, currentBlock);
cont = createBasicBlock("LCMP");
BranchInst::Create(res, cont, test, currentBlock);
currentBlock = cont;
node->addIncoming(intrinsics->constantOne, currentBlock);
BranchInst::Create(res, currentBlock);
currentBlock = res;
push(node, false);
break;
}
case FCMPL : {
llvm::Value* val2 = pop();
llvm::Value* val1 = pop();
compareFP(val1, val2, Type::getFloatTy(*llvmContext), false);
break;
}
case FCMPG : {
llvm::Value* val2 = pop();
llvm::Value* val1 = pop();
compareFP(val1, val2, Type::getFloatTy(*llvmContext), true);
break;
}
case DCMPL : {
pop();
llvm::Value* val2 = pop();
pop();
llvm::Value* val1 = pop();
compareFP(val1, val2, Type::getDoubleTy(*llvmContext), false);
break;
}
case DCMPG : {
pop();
llvm::Value* val2 = pop();
pop();
llvm::Value* val1 = pop();
compareFP(val1, val2, Type::getDoubleTy(*llvmContext), false);
break;
}
case IFEQ : {
uint32 tmp = i;
Opinfo& ifTrueInfo = opcodeInfos[tmp + readS2(bytecodes, i)];
BasicBlock* ifTrue = ifTrueInfo.newBlock;
Value* op = pop();
const Type* type = op->getType();
Constant* val = Constant::getNullValue(type);
llvm::Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, op,
val, "");
BasicBlock* ifFalse = createBasicBlock("false IFEQ");
branch(test, ifTrue, ifFalse, currentBlock, ifTrueInfo);
currentBlock = ifFalse;
break;
}
case IFNE : {
uint32 tmp = i;
Opinfo& ifTrueInfo = opcodeInfos[tmp + readS2(bytecodes, i)];
BasicBlock* ifTrue = ifTrueInfo.newBlock;
Value* op = pop();
const Type* type = op->getType();
Constant* val = Constant::getNullValue(type);
llvm::Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE, op,
val, "");
BasicBlock* ifFalse = createBasicBlock("false IFNE");
branch(test, ifTrue, ifFalse, currentBlock, ifTrueInfo);
currentBlock = ifFalse;
break;
}
case IFLT : {
uint32 tmp = i;
Opinfo& ifTrueInfo = opcodeInfos[tmp + readS2(bytecodes, i)];
BasicBlock* ifTrue = ifTrueInfo.newBlock;
Value* op = pop();
const Type* type = op->getType();
Constant* val = Constant::getNullValue(type);
llvm::Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_SLT, op,
val, "");
BasicBlock* ifFalse = createBasicBlock("false IFLT");
branch(test, ifTrue, ifFalse, currentBlock, ifTrueInfo);
currentBlock = ifFalse;
break;
}
case IFGE : {
uint32 tmp = i;
Opinfo& ifTrueInfo = opcodeInfos[tmp + readS2(bytecodes, i)];
BasicBlock* ifTrue = ifTrueInfo.newBlock;
Value* op = pop();
const Type* type = op->getType();
Constant* val = Constant::getNullValue(type);
llvm::Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_SGE, op,
val, "");
BasicBlock* ifFalse = createBasicBlock("false IFGE");
branch(test, ifTrue, ifFalse, currentBlock, ifTrueInfo);
currentBlock = ifFalse;
break;
}
case IFGT : {
uint32 tmp = i;
Opinfo& ifTrueInfo = opcodeInfos[tmp + readS2(bytecodes, i)];
BasicBlock* ifTrue = ifTrueInfo.newBlock;
Value* op = pop();
const Type* type = op->getType();
Constant* val = Constant::getNullValue(type);
llvm::Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_SGT, op,
val, "");
BasicBlock* ifFalse = createBasicBlock("false IFGT");
branch(test, ifTrue, ifFalse, currentBlock, ifTrueInfo);
currentBlock = ifFalse;
break;
}
case IFLE : {
uint32 tmp = i;
Opinfo& ifTrueInfo = opcodeInfos[tmp + readS2(bytecodes, i)];
BasicBlock* ifTrue = ifTrueInfo.newBlock;
Value* op = pop();
const Type* type = op->getType();
Constant* val = Constant::getNullValue(type);
llvm::Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_SLE, op,
val, "");
BasicBlock* ifFalse = createBasicBlock("false IFLE");
branch(test, ifTrue, ifFalse, currentBlock, ifTrueInfo);
currentBlock = ifFalse;
break;
}
case IF_ICMPEQ : {
Value *val2 = popAsInt();
Value *val1 = popAsInt();
uint32 tmp = i;
Opinfo& ifTrueInfo = opcodeInfos[tmp + readS2(bytecodes, i)];
BasicBlock* ifTrue = ifTrueInfo.newBlock;
llvm::Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, val1,
val2, "");
BasicBlock* ifFalse = createBasicBlock("false IF_ICMPEQ");
branch(test, ifTrue, ifFalse, currentBlock, ifTrueInfo);
currentBlock = ifFalse;
break;
}
case IF_ICMPNE : {
Value *val2 = popAsInt();
Value *val1 = popAsInt();
uint32 tmp = i;
Opinfo& ifTrueInfo = opcodeInfos[tmp + readS2(bytecodes, i)];
BasicBlock* ifTrue = ifTrueInfo.newBlock;
llvm::Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE, val1,
val2, "");
BasicBlock* ifFalse = createBasicBlock("false IF_ICMPNE");
branch(test, ifTrue, ifFalse, currentBlock, ifTrueInfo);
currentBlock = ifFalse;
break;
}
case IF_ICMPLT : {
Value *val2 = popAsInt();
Value *val1 = popAsInt();
uint32 tmp = i;
Opinfo& ifTrueInfo = opcodeInfos[tmp + readS2(bytecodes, i)];
BasicBlock* ifTrue = ifTrueInfo.newBlock;
llvm::Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_SLT,
val1, val2, "");
BasicBlock* ifFalse = createBasicBlock("false IF_IFCMPLT");
branch(test, ifTrue, ifFalse, currentBlock, ifTrueInfo);
currentBlock = ifFalse;
break;
}
case IF_ICMPGE : {
Value *val2 = popAsInt();
Value *val1 = popAsInt();
uint32 tmp = i;
Opinfo& ifTrueInfo = opcodeInfos[tmp + readS2(bytecodes, i)];
BasicBlock* ifTrue = ifTrueInfo.newBlock;
llvm::Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_SGE,
val1, val2, "");
BasicBlock* ifFalse = createBasicBlock("false IF_ICMPGE");
branch(test, ifTrue, ifFalse, currentBlock, ifTrueInfo);
currentBlock = ifFalse;
break;
}
case IF_ICMPGT : {
Value *val2 = popAsInt();
Value *val1 = popAsInt();
uint32 tmp = i;
Opinfo& ifTrueInfo = opcodeInfos[tmp + readS2(bytecodes, i)];
BasicBlock* ifTrue = ifTrueInfo.newBlock;
llvm::Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_SGT,
val1, val2, "");
BasicBlock* ifFalse = createBasicBlock("false IF_ICMPGT");
branch(test, ifTrue, ifFalse, currentBlock, ifTrueInfo);
currentBlock = ifFalse;
break;
}
case IF_ICMPLE : {
Value *val2 = popAsInt();
Value *val1 = popAsInt();
uint32 tmp = i;
Opinfo& ifTrueInfo = opcodeInfos[tmp + readS2(bytecodes, i)];
BasicBlock* ifTrue = ifTrueInfo.newBlock;
llvm::Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_SLE,
val1, val2, "");
BasicBlock* ifFalse = createBasicBlock("false IF_ICMPLE");
branch(test, ifTrue, ifFalse, currentBlock, ifTrueInfo);
currentBlock = ifFalse;
break;
}
case IF_ACMPEQ : {
Value *val2 = pop();
Value *val1 = pop();
uint32 tmp = i;
Opinfo& ifTrueInfo = opcodeInfos[tmp + readS2(bytecodes, i)];
BasicBlock* ifTrue = ifTrueInfo.newBlock;
llvm::Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ,
val1, val2, "");
BasicBlock* ifFalse = createBasicBlock("false IF_ACMPEQ");
branch(test, ifTrue, ifFalse, currentBlock, ifTrueInfo);
currentBlock = ifFalse;
break;
}
case IF_ACMPNE : {
Value *val2 = pop();
Value *val1 = pop();
uint32 tmp = i;
Opinfo& ifTrueInfo = opcodeInfos[tmp + readS2(bytecodes, i)];
BasicBlock* ifTrue = ifTrueInfo.newBlock;
llvm::Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE,
val1, val2, "");
BasicBlock* ifFalse = createBasicBlock("false IF_ACMPNE");
branch(test, ifTrue, ifFalse, currentBlock, ifTrueInfo);
currentBlock = ifFalse;
break;
}
case GOTO : {
uint32 tmp = i;
branch(opcodeInfos[tmp + readS2(bytecodes, i)],
currentBlock);
break;
}
case JSR : {
uint32 tmp = i;
uint32 index = jsrIndex | 1;
jsrIndex += 2;
Value* expr = ConstantExpr::getIntToPtr(
ConstantInt::get(Type::getInt64Ty(*llvmContext),
uint64_t (index)),
intrinsics->JavaObjectType);
push(expr, false);
branch(opcodeInfos[tmp + readS2(bytecodes, i)],
currentBlock);
break;
}
case RET : {
uint8 local = readU1(bytecodes, i);
Value* _val = new LoadInst(objectLocals[local], "", currentBlock);
Value* val = new PtrToIntInst(_val, Type::getInt32Ty(*llvmContext), "", currentBlock);
SwitchInst* inst = SwitchInst::Create(val, jsrs[0], jsrs.size(),
currentBlock);
uint32 index = 0;
for (std::vector<BasicBlock*>::iterator i = jsrs.begin(),
e = jsrs.end(); i!= e; ++i, index += 2) {
inst->addCase(ConstantInt::get(Type::getInt32Ty(*llvmContext), index | 1), *i);
}
break;
}
case TABLESWITCH : {
uint32 tmp = i;
uint32 reste = (i + 1) & 3;
uint32 filled = reste ? (4 - reste) : 0;
i += filled;
Opinfo& def = opcodeInfos[tmp + readU4(bytecodes, i)];
sint32 low = readS4(bytecodes, i);
sint32 high = readS4(bytecodes, i) + 1;
Value* index = pop();
const llvm::Type* type = index->getType();
for (sint32 cur = low; cur < high; ++cur) {
Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ,
ConstantInt::get(type, cur), index, "");
BasicBlock* falseBlock = createBasicBlock("continue tableswitch");
Opinfo& info = opcodeInfos[tmp + readU4(bytecodes, i)];
branch(cmp, info.newBlock, falseBlock, currentBlock, info);
currentBlock = falseBlock;
}
branch(def, currentBlock);
i = tmp + 12 + filled + ((high - low) << 2);
break;
}
case LOOKUPSWITCH : {
uint32 tmp = i;
uint32 filled = (3 - i) & 3;
i += filled;
Opinfo& def = opcodeInfos[tmp + readU4(bytecodes, i)];
uint32 nbs = readU4(bytecodes, i);
Value* key = pop();
for (uint32 cur = 0; cur < nbs; ++cur) {
Value* val = ConstantInt::get(Type::getInt32Ty(*llvmContext), readU4(bytecodes, i));
Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, val, key,
"");
BasicBlock* falseBlock = createBasicBlock("continue lookupswitch");
Opinfo& info = opcodeInfos[tmp + readU4(bytecodes, i)];
branch(cmp, info.newBlock, falseBlock, currentBlock, info);
currentBlock = falseBlock;
}
branch(def, currentBlock);
i = tmp + 8 + filled + (nbs << 3);
break;
}
case IRETURN : {
Value* val = pop();
assert(val->getType()->isIntegerTy());
convertValue(val, endNode->getType(), currentBlock, false);
endNode->addIncoming(val, currentBlock);
BranchInst::Create(endBlock, currentBlock);
break;
}
case LRETURN :
pop(); // remove the 0 on the stack
endNode->addIncoming(pop(), currentBlock);
BranchInst::Create(endBlock, currentBlock);
break;
case FRETURN :
endNode->addIncoming(pop(), currentBlock);
BranchInst::Create(endBlock, currentBlock);
break;
case DRETURN :
pop(); // remove the 0 on the stack
endNode->addIncoming(pop(), currentBlock);
BranchInst::Create(endBlock, currentBlock);
break;
case ARETURN :
endNode->addIncoming(pop(), currentBlock);
BranchInst::Create(endBlock, currentBlock);
break;
case RETURN : {
// Prevent a javac bug.
if (endNode != 0) {
endNode->addIncoming(Constant::getNullValue(endNode->getType()),
currentBlock);
}
BranchInst::Create(endBlock, currentBlock);
break;
}
case GETSTATIC : {
uint16 index = readU2(bytecodes, i);
getStaticField(index);
break;
}
case PUTSTATIC : {
uint16 index = readU2(bytecodes, i);
setStaticField(index);
break;
}
case GETFIELD : {
uint16 index = readU2(bytecodes, i);
getVirtualField(index);
break;
}
case PUTFIELD : {
uint16 index = readU2(bytecodes, i);
setVirtualField(index);
break;
}
case INVOKEVIRTUAL : {
uint16 index = readU2(bytecodes, i);
currentCtpIndex = index;
invokeVirtual(index);
break;
}
case INVOKESPECIAL : {
uint16 index = readU2(bytecodes, i);
currentCtpIndex = index;
invokeSpecial(index);
break;
}
case INVOKESTATIC : {
uint16 index = readU2(bytecodes, i);
currentCtpIndex = index;
invokeStatic(index);
break;
}
case INVOKEINTERFACE : {
uint16 index = readU2(bytecodes, i);
currentCtpIndex = index;
invokeInterface(index);
i += 2;
break;
}
case NEW : {
uint16 index = readU2(bytecodes, i);
invokeNew(index);
break;
}
case NEWARRAY :
case ANEWARRAY : {
Constant* sizeElement = 0;
Value* TheVT = 0;
Value* valCl = 0;
UserClassArray* dcl = 0;
if (bytecodes[i] == NEWARRAY) {
uint8 id = bytecodes[++i];
uint8 charId = arrayType(compilingMethod, id);
#ifndef ISOLATE_SHARING
JnjvmBootstrapLoader* loader =
compilingClass->classLoader->bootstrapLoader;
dcl = loader->getArrayClass(id);
valCl = TheCompiler->getNativeClass(dcl);
#else
Value* args[2] = { isolateLocal,
ConstantInt::get(Type::getInt32Ty(*llvmContext), id - 4) };
valCl = CallInst::Create(intrinsics->GetJnjvmArrayClassFunction,
args, args + 2, "", currentBlock);
#endif
LLVMAssessorInfo& LAI = TheCompiler->AssessorInfo[charId];
sizeElement = ConstantInt::get(Type::getInt32Ty(*llvmContext),
LAI.logSizeInBytesConstant);
if (TheCompiler->isStaticCompiling() &&
valCl->getType() != intrinsics->JavaClassArrayType) {
valCl = new LoadInst(valCl, "", currentBlock);
TheVT = CallInst::Create(intrinsics->GetVTFromClassArrayFunction,
valCl, "", currentBlock);
} else {
TheVT = TheCompiler->getVirtualTable(dcl->virtualVT);
}
} else {
uint16 index = readU2(bytecodes, i);
CommonClass* cl = 0;
valCl = getResolvedCommonClass(index, true, &cl);
if (cl) {
JnjvmClassLoader* JCL = cl->classLoader;
const UTF8* arrayName = JCL->constructArrayName(1, cl->name);
dcl = JCL->constructArray(arrayName);
valCl = TheCompiler->getNativeClass(dcl);
// If we're static compiling and the class is not a class we
// are compiling, the result of getNativeClass is a pointer to
// the class. Load it.
if (TheCompiler->isStaticCompiling() &&
valCl->getType() != intrinsics->JavaClassArrayType) {
valCl = new LoadInst(valCl, "", currentBlock);
TheVT = CallInst::Create(intrinsics->GetVTFromClassArrayFunction,
valCl, "", currentBlock);
} else {
TheVT = TheCompiler->getVirtualTable(dcl->virtualVT);
}
} else {
const llvm::Type* Ty =
PointerType::getUnqual(intrinsics->JavaClassArrayType);
Value* args[2]= { valCl, Constant::getNullValue(Ty) };
valCl = CallInst::Create(intrinsics->GetArrayClassFunction, args,
args + 2, "", currentBlock);
TheVT = CallInst::Create(intrinsics->GetVTFromClassArrayFunction, valCl, "",
currentBlock);
}
sizeElement = intrinsics->constantPtrLogSize;
}
Value* arg1 = popAsInt();
if (TheCompiler->hasExceptionsEnabled()) {
Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_SLT, arg1,
intrinsics->constantZero, "");
BasicBlock* BB1 = createBasicBlock("");
BasicBlock* BB2 = createBasicBlock("");
BranchInst::Create(BB1, BB2, cmp, currentBlock);
currentBlock = BB1;
throwException(intrinsics->NegativeArraySizeExceptionFunction, arg1);
currentBlock = BB2;
cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_SGT, arg1,
intrinsics->MaxArraySizeConstant, "");
BB1 = createBasicBlock("");
BB2 = createBasicBlock("");
BranchInst::Create(BB1, BB2, cmp, currentBlock);
currentBlock = BB1;
throwException(intrinsics->OutOfMemoryErrorFunction, arg1);
currentBlock = BB2;
}
Value* mult = BinaryOperator::CreateShl(arg1, sizeElement, "",
currentBlock);
Value* size =
BinaryOperator::CreateAdd(intrinsics->JavaArraySizeConstant, mult,
"", currentBlock);
TheVT = new BitCastInst(TheVT, intrinsics->ptrType, "", currentBlock);
Instruction* res = invoke(intrinsics->AllocateFunction, size, TheVT, "",
currentBlock);
Value* cast = new BitCastInst(res, intrinsics->JavaArrayType, "",
currentBlock);
// Set the size
Value* gep4[2] = { intrinsics->constantZero,
intrinsics->JavaArraySizeOffsetConstant };
Value* GEP = GetElementPtrInst::Create(cast, gep4, gep4 + 2,
"", currentBlock);
arg1 = new IntToPtrInst(arg1, intrinsics->ptrType, "", currentBlock);
new StoreInst(arg1, GEP, currentBlock);
addHighLevelType(res, dcl ? dcl : upcalls->ArrayOfObject);
res = new BitCastInst(res, intrinsics->JavaObjectType, "", currentBlock);
push(res, false, dcl ? dcl : upcalls->ArrayOfObject);
break;
}
case ARRAYLENGTH : {
Value* val = pop();
JITVerifyNull(val);
push(arraySize(val), false);
break;
}
case ATHROW : {
llvm::Value* arg = pop();
throwException(arg);
break;
}
case CHECKCAST :
if (!TheCompiler->hasExceptionsEnabled()) {
i += 2;
break;
}
case INSTANCEOF : {
bool checkcast = (bytecodes[i] == CHECKCAST);
BasicBlock* exceptionCheckcast = 0;
BasicBlock* endCheckcast = 0;
uint16 index = readU2(bytecodes, i);
UserCommonClass* cl = 0;
Value* clVar = getResolvedCommonClass(index, true, &cl);
Value* obj = top();
Value* args[2] = { obj, clVar };
Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, obj,
intrinsics->JavaObjectNullConstant, "");
BasicBlock* endBlock = createBasicBlock("end type compare");
PHINode* node = PHINode::Create(Type::getInt1Ty(*llvmContext), "", endBlock);
if (checkcast) {
exceptionCheckcast = createBasicBlock("false checkcast");
endCheckcast = createBasicBlock("null checkcast");
BasicBlock* ifFalse = createBasicBlock("non null checkcast");
BranchInst::Create(endCheckcast, ifFalse, cmp, currentBlock);
currentBlock = exceptionCheckcast;
throwException(intrinsics->ClassCastExceptionFunction, args, 2);
currentBlock = ifFalse;
} else {
BasicBlock* ifFalse = createBasicBlock("false type compare");
BranchInst::Create(endBlock, ifFalse, cmp, currentBlock);
node->addIncoming(ConstantInt::getFalse(*llvmContext), currentBlock);
currentBlock = ifFalse;
}
Value* TheVT = 0;
if (!cl || TheCompiler->isStaticCompiling()) {
TheVT = CallInst::Create(intrinsics->GetVTFromCommonClassFunction,
clVar, "", currentBlock);
} else {
TheVT = TheCompiler->getVirtualTable(cl->virtualVT);
}
Value* objVT = CallInst::Create(intrinsics->GetVTFunction, obj, "",
currentBlock);
Value* classArgs[2] = { objVT, TheVT };
Value* res = 0;
if (cl) {
if (cl->isSecondaryClass()) {
res = CallInst::Create(intrinsics->IsSecondaryClassFunction,
classArgs, classArgs + 2, "",
currentBlock);
} else {
Value* inDisplay = CallInst::Create(intrinsics->GetDisplayFunction,
objVT, "", currentBlock);
uint32 depth = cl->virtualVT->depth;
ConstantInt* CI = ConstantInt::get(Type::getInt32Ty(*llvmContext), depth);
Value* displayArgs[2] = { inDisplay, CI };
Value* VTInDisplay =
CallInst::Create(intrinsics->GetVTInDisplayFunction,
displayArgs, displayArgs + 2, "",
currentBlock);
res = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, VTInDisplay,
TheVT, "");
}
} else {
res = CallInst::Create(intrinsics->IsAssignableFromFunction,
classArgs, classArgs + 2, "",
currentBlock);
}
node->addIncoming(res, currentBlock);
BranchInst::Create(endBlock, currentBlock);
currentBlock = endBlock;
if (checkcast) {
BranchInst::Create(endCheckcast, exceptionCheckcast, node,
currentBlock);
currentBlock = endCheckcast;
} else {
pop();
push(new ZExtInst(node, Type::getInt32Ty(*llvmContext), "", currentBlock),
false);
}
break;
}
case MONITORENTER : {
Value* obj = pop();
JITVerifyNull(obj);
monitorEnter(obj);
break;
}
case MONITOREXIT : {
Value* obj = pop();
JITVerifyNull(obj);
monitorExit(obj);
break;
}
case MULTIANEWARRAY : {
uint16 index = readU2(bytecodes, i);
uint8 dim = readU1(bytecodes, i);
UserCommonClass* dcl = 0;
Value* valCl = getResolvedCommonClass(index, true, &dcl);
Value** args = (Value**)alloca(sizeof(Value*) * (dim + 2));
args[0] = valCl;
args[1] = ConstantInt::get(Type::getInt32Ty(*llvmContext), dim);
for (int cur = dim + 1; cur >= 2; --cur)
args[cur] = pop();
std::vector<Value*> Args;
for (sint32 v = 0; v < dim + 2; ++v) {
Args.push_back(args[v]);
}
push(invoke(intrinsics->MultiCallNewFunction, Args, "", currentBlock),
false, dcl ? dcl : upcalls->ArrayOfObject);
break;
}
case WIDE :
wide = true;
break;
case IFNULL : {
uint32 tmp = i;
llvm::Value* val = pop();
Constant* nil = Constant::getNullValue(val->getType());
llvm::Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, val,
nil, "");
BasicBlock* ifFalse = createBasicBlock("true IFNULL");
Opinfo& ifTrueInfo = opcodeInfos[tmp + readS2(bytecodes, i)];
BasicBlock* ifTrue = ifTrueInfo.newBlock;
branch(test, ifTrue, ifFalse, currentBlock, ifTrueInfo);
currentBlock = ifFalse;
break;
}
case IFNONNULL : {
uint32 tmp = i;
llvm::Value* val = pop();
Constant* nil = Constant::getNullValue(val->getType());
llvm::Value* test = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE, val,
nil, "");
BasicBlock* ifFalse = createBasicBlock("false IFNONNULL");
Opinfo& ifTrueInfo = opcodeInfos[tmp + readS2(bytecodes, i)];
BasicBlock* ifTrue = ifTrueInfo.newBlock;
branch(test, ifTrue, ifFalse, currentBlock, ifTrueInfo);
currentBlock = ifFalse;
break;
}
default : {
fprintf(stderr, "I haven't verified your class file and it's malformed:"
" unknown bytecode %d in %s.%s\n!", bytecodes[i],
UTF8Buffer(compilingClass->name).cString(),
UTF8Buffer(compilingMethod->name).cString());
abort();
}
}
}
}
void JavaJIT::exploreOpcodes(uint8* bytecodes, uint32 codeLength) {
bool wide = false;
for(uint32 i = 0; i < codeLength; ++i) {
PRINT_DEBUG(JNJVM_COMPILE, 1, COLOR_NORMAL, "\t[at %5d] %-5d ", i,
bytecodes[i]);
PRINT_DEBUG(JNJVM_COMPILE, 1, LIGHT_BLUE, "exploring ");
PRINT_DEBUG(JNJVM_COMPILE, 1, LIGHT_CYAN, OpcodeNames[bytecodes[i]]);
PRINT_DEBUG(JNJVM_COMPILE, 1, LIGHT_BLUE, "\n");
switch (bytecodes[i]) {
case NOP :
case ACONST_NULL :
case ICONST_M1 :
case ICONST_0 :
case ICONST_1 :
case ICONST_2 :
case ICONST_3 :
case ICONST_4 :
case ICONST_5 :
case LCONST_0 :
case LCONST_1 :
case FCONST_0 :
case FCONST_1 :
case FCONST_2 :
case DCONST_0 :
case DCONST_1 : break;
case BIPUSH : ++i; break;
case SIPUSH : i += 2; break;
case LDC : ++i; break;
case LDC_W :
case LDC2_W : i += 2; break;
case ILOAD :
case LLOAD :
case FLOAD :
case DLOAD :
case ALOAD :
i += WCALC(1, wide);
break;
case ILOAD_0 :
case ILOAD_1 :
case ILOAD_2 :
case ILOAD_3 :
case LLOAD_0 :
case LLOAD_1 :
case LLOAD_2 :
case LLOAD_3 :
case FLOAD_0 :
case FLOAD_1 :
case FLOAD_2 :
case FLOAD_3 :
case DLOAD_0 :
case DLOAD_1 :
case DLOAD_2 :
case DLOAD_3 :
case ALOAD_0 :
case ALOAD_1 :
case ALOAD_2 :
case ALOAD_3 :
case IALOAD :
case LALOAD :
case FALOAD :
case DALOAD :
case AALOAD :
case BALOAD :
case CALOAD :
case SALOAD : break;
case ISTORE :
case LSTORE :
case FSTORE :
case DSTORE :
case ASTORE :
i += WCALC(1, wide);
break;
case ISTORE_0 :
case ISTORE_1 :
case ISTORE_2 :
case ISTORE_3 :
case LSTORE_0 :
case LSTORE_1 :
case LSTORE_2 :
case LSTORE_3 :
case FSTORE_0 :
case FSTORE_1 :
case FSTORE_2 :
case FSTORE_3 :
case DSTORE_0 :
case DSTORE_1 :
case DSTORE_2 :
case DSTORE_3 :
case ASTORE_0 :
case ASTORE_1 :
case ASTORE_2 :
case ASTORE_3 :
case IASTORE :
case LASTORE :
case FASTORE :
case DASTORE :
case AASTORE :
case BASTORE :
case CASTORE :
case SASTORE :
case POP :
case POP2 :
case DUP :
case DUP_X1 :
case DUP_X2 :
case DUP2 :
case DUP2_X1 :
case DUP2_X2 :
case SWAP :
case IADD :
case LADD :
case FADD :
case DADD :
case ISUB :
case LSUB :
case FSUB :
case DSUB :
case IMUL :
case LMUL :
case FMUL :
case DMUL :
case IDIV :
case LDIV :
case FDIV :
case DDIV :
case IREM :
case LREM :
case FREM :
case DREM :
case INEG :
case LNEG :
case FNEG :
case DNEG :
case ISHL :
case LSHL :
case ISHR :
case LSHR :
case IUSHR :
case LUSHR :
case IAND :
case LAND :
case IOR :
case LOR :
case IXOR :
case LXOR : break;
case IINC :
i += WCALC(2, wide);
break;
case I2L :
case I2F :
case I2D :
case L2I :
case L2F :
case L2D :
case F2I :
case F2L :
case F2D :
case D2I :
case D2L :
case D2F :
case I2B :
case I2C :
case I2S :
case LCMP :
case FCMPL :
case FCMPG :
case DCMPL :
case DCMPG : break;
case IFEQ :
case IFNE :
case IFLT :
case IFGE :
case IFGT :
case IFLE :
case IF_ICMPEQ :
case IF_ICMPNE :
case IF_ICMPLT :
case IF_ICMPGE :
case IF_ICMPGT :
case IF_ICMPLE :
case IF_ACMPEQ :
case IF_ACMPNE :
case GOTO : {
uint32 tmp = i;
uint16 index = tmp + readU2(bytecodes, i);
if (!(opcodeInfos[index].newBlock))
opcodeInfos[index].newBlock = createBasicBlock("GOTO or IF*");
break;
}
case JSR : {
uint32 tmp = i;
uint16 index = tmp + readU2(bytecodes, i);
if (!(opcodeInfos[index].newBlock)) {
BasicBlock* block = createBasicBlock("JSR");
opcodeInfos[index].newBlock = block;
}
if (!(opcodeInfos[tmp + 3].newBlock)) {
BasicBlock* block = createBasicBlock("JSR2");
jsrs.push_back(block);
opcodeInfos[tmp + 3].newBlock = block;
} else {
jsrs.push_back(opcodeInfos[tmp + 3].newBlock);
}
break;
}
case RET : ++i; break;
case TABLESWITCH : {
uint32 tmp = i;
uint32 reste = (i + 1) & 3;
uint32 filled = reste ? (4 - reste) : 0;
i += filled;
uint32 index = tmp + readU4(bytecodes, i);
if (!(opcodeInfos[index].newBlock)) {
BasicBlock* block = createBasicBlock("tableswitch");
opcodeInfos[index].newBlock = block;
}
uint32 low = readU4(bytecodes, i);
uint32 high = readU4(bytecodes, i) + 1;
uint32 depl = high - low;
for (uint32 cur = 0; cur < depl; ++cur) {
uint32 index2 = tmp + readU4(bytecodes, i);
if (!(opcodeInfos[index2].newBlock)) {
BasicBlock* block = createBasicBlock("tableswitch");
opcodeInfos[index2].newBlock = block;
}
}
i = tmp + 12 + filled + (depl << 2);
break;
}
case LOOKUPSWITCH : {
uint32 tmp = i;
uint32 filled = (3 - i) & 3;
i += filled;
uint32 index = tmp + readU4(bytecodes, i);
if (!(opcodeInfos[index].newBlock)) {
BasicBlock* block = createBasicBlock("tableswitch");
opcodeInfos[index].newBlock = block;
}
uint32 nbs = readU4(bytecodes, i);
for (uint32 cur = 0; cur < nbs; ++cur) {
i += 4;
uint32 index2 = tmp + readU4(bytecodes, i);
if (!(opcodeInfos[index2].newBlock)) {
BasicBlock* block = createBasicBlock("tableswitch");
opcodeInfos[index2].newBlock = block;
}
}
i = tmp + 8 + filled + (nbs << 3);
break;
}
case IRETURN :
case LRETURN :
case FRETURN :
case DRETURN :
case ARETURN :
case RETURN : break;
case GETSTATIC :
case PUTSTATIC :
case GETFIELD :
case PUTFIELD :
case INVOKEVIRTUAL :
case INVOKESPECIAL :
case INVOKESTATIC :
i += 2;
break;
case INVOKEINTERFACE :
i += 4;
break;
case NEW :
i += 2;
break;
case NEWARRAY :
++i;
break;
case ANEWARRAY :
i += 2;
break;
case ARRAYLENGTH :
case ATHROW : break;
case CHECKCAST :
i += 2;
break;
case INSTANCEOF :
i += 2;
break;
case MONITORENTER :
break;
case MONITOREXIT :
break;
case MULTIANEWARRAY :
i += 3;
break;
case WIDE :
wide = true;
break;
case IFNULL :
case IFNONNULL : {
uint32 tmp = i;
uint16 index = tmp + readU2(bytecodes, i);
if (!(opcodeInfos[index].newBlock))
opcodeInfos[index].newBlock = createBasicBlock("true IF*NULL");
break;
}
default : {
fprintf(stderr, "I haven't verified your class file and it's malformed:"
" unknown bytecode %d in %s.%s!\n", bytecodes[i],
UTF8Buffer(compilingClass->name).cString(),
UTF8Buffer(compilingMethod->name).cString());
abort();
}
}
}
}