blob: 66a6c705bbd407d71e70301987a190850aac08b4 [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 JNJVM_COMPILE 2
#define JNJVM_EXECUTE 1
#include <cstring>
#include <queue>
#include <llvm/IR/Constants.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Type.h>
#include "vmkit/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 "Reader.h"
#include "j3/J3Intrinsics.h"
#include "j3/OpcodeNames.def"
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 uint32 WREAD_U1(Reader& reader, bool init, uint32 &i, bool& wide) {
if (wide) {
wide = init;
i += 2;
return reader.readU2();
} else {
i += 1;
return reader.readU1();
}
}
static inline sint32 WREAD_S1(Reader& reader, bool init, uint32 &i, bool &wide) {
if (wide) {
wide = init;
i += 2;
return reader.readS2();
} else {
i += 1;
return reader.readS1();
}
}
static inline uint32 WCALC(uint32 n, bool& wide) {
if (wide) {
wide = false;
return n << 1;
} else {
return n;
}
}
/**
* Used in JavaJIT::findUnreachableCode to find the next instruction in the array of bytecode.
*/
static uint8 sum [] = {
2,
3,
2,
3,
3,
2,
2,
2,
2,
2
};
static uint8 sum2 [] = {
3,
3,
3,
3,
3,
3,
3,
5,
5,
3,
2,
3,
1,
1,
3,
3,
1,
1
};
void JavaJIT::findUnreachableCode(Reader& reader, uint32 codeLen) {
std::queue<uint32> queue;
queue.push(0);
opcodeInfos[0].isReachable = true;
for (unsigned i = 0; i < codeLen; ++i) {
if (opcodeInfos[i].isReachable)
queue.push(i);
}
uint32 start = reader.cursor;
while (queue.size()) {
// pick one index from the queue
uint32 i_opcode = queue.front();
queue.pop();
// read the opcode at this position
reader.cursor = start + i_opcode;
uint8 bytecode = reader.readU1();
// if the opcode is a section which has a handle other than the endBlockHandler then we must add the initial instruction of that handler to the queue
if (opcodeInfos[i_opcode].handlerPC) {
uint16 pc = opcodeInfos[i_opcode].handlerPC;
if (pc < codeLen && !opcodeInfos[pc].isReachable) {
opcodeInfos[pc].isReachable = true;
queue.push(pc);
}
}
//
// if the opcode does not involve a branch then mark the next instruction as reachable (DONE)
// if the opcode is an unconditional branch then mark the target as reachable (DONE)
// if the opcode is a conditional branch then mark the target and the next instruction as reachable (DONE)
// if it is a ret instruction then I don't know what to do.
// if it is a jsr instruction then mark the target as reachable (DONE)
// if it is tableswitch instruction then mark all cases as reachable (DONE)
// if it is lookupswitch instruction then mark all cases as reachable (DONE)
// wide instruction (DONE)
if (bytecode < IFEQ) {
uint32 next_index = 1;
if (bytecode >= BIPUSH && bytecode <= ALOAD)
next_index = sum[bytecode - BIPUSH];
else if (bytecode >= ISTORE && bytecode <= ASTORE)
next_index = 2;
else if (bytecode == IINC)
next_index = 3;
next_index += i_opcode;
if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
opcodeInfos[next_index].isReachable = true;
queue.push(next_index);
}
}
else if (bytecode >= IFEQ && bytecode <= IF_ACMPNE) {
uint32 next_index = 3 + i_opcode;
if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
opcodeInfos[next_index].isReachable = true;
queue.push(next_index);
}
uint16 b1 = reader.readU1();
uint8 b2 = reader.readU1();
sint16 step = (b1 << 8) | b2;
next_index = i_opcode + step;
if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
opcodeInfos[next_index].isReachable = true;
queue.push(next_index);
}
}
else if (bytecode >= GETSTATIC && bytecode <= MONITOREXIT && bytecode != ATHROW) {
uint32 next_index = sum2[bytecode - GETSTATIC] + i_opcode;
if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
opcodeInfos[next_index].isReachable = true;
queue.push(next_index);
}
}
else {
uint32 x;
sint32 defaultIndex,lowIndex, highIndex;
uint32 next_index = codeLen;
sint16 step;
sint32 step32;
uint16 b1;
uint8 b2,b3,b4;
switch (bytecode) {
case GOTO:
step = reader.readS2();
next_index = i_opcode + step;
break;
case GOTO_W:
step32 = reader.readS4();
next_index = step32 + i_opcode;
break;
case MULTIANEWARRAY:
next_index = i_opcode + 4;
break;
case IFNULL:
case IFNONNULL:
case JSR:
next_index = i_opcode + 3;
if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
opcodeInfos[next_index].isReachable = true;
queue.push(next_index);
}
step = reader.readS2();
next_index = i_opcode + step;
break;
case JSR_W:
next_index = i_opcode + 5;
if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
opcodeInfos[next_index].isReachable = true;
queue.push(next_index);
}
step32 = reader.readS4();
next_index = step32 + i_opcode;
break;
case WIDE:
if (i_opcode + 1 < codeLen && !opcodeInfos[i_opcode + 1].isReachable) {
opcodeInfos[i_opcode + 1].isReachable = true;
queue.push(i_opcode + 1);
}
b2 = reader.readU1();
next_index = i_opcode + ((b2 == IINC)?6:4);
break;
case TABLESWITCH:
//break;
x = i_opcode & 0x03; // remainder of division by 4
reader.cursor = start + 4 - x + i_opcode;
// default
step32 = reader.readS4();
defaultIndex = step32 + i_opcode;
if (defaultIndex < codeLen && !opcodeInfos[defaultIndex].isReachable) {
opcodeInfos[defaultIndex].isReachable = true;
queue.push(defaultIndex);
}
// low
lowIndex = reader.readS4();
// high
highIndex = reader.readS4();
// all options
for (int i = 0 ; i < highIndex - lowIndex + 1 ; i++) {
step32 = reader.readS4();
next_index = step32 + i_opcode;
if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
opcodeInfos[next_index].isReachable = true;
queue.push(next_index);
}
}
next_index = codeLen;
break;
case LOOKUPSWITCH:
//break;
x = i_opcode & 0x03; // remainder of division by 4
reader.cursor = start + 4 - x + i_opcode;
// default
step32 = reader.readS4();//(defaultIndex << 24) | (b2 << 16) | (b3 << 8) | b4;
defaultIndex = step32 + i_opcode;
if (defaultIndex < codeLen && !opcodeInfos[defaultIndex].isReachable) {
opcodeInfos[defaultIndex].isReachable = true;
queue.push(defaultIndex);
}
// npairs
lowIndex = reader.readS4();
// all options
for (int i = 0 ; i < lowIndex ; i++) {
reader.cursor += 4; // skipping match
// offset
step32 = reader.readS4();
next_index = step32 + i_opcode;
if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
opcodeInfos[next_index].isReachable = true;
queue.push(next_index);
}
}
next_index = codeLen;
break;
default:
break;
}
if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
opcodeInfos[next_index].isReachable = true;
queue.push(next_index);
}
}
} // end while
}
void JavaJIT::compileOpcodes(Reader& reader, uint32 codeLength) {
bool wide = false;
uint32 jsrIndex = 0;
uint32 start = reader.cursor;
// Some compilers like Scala and Kotlin produce unreachable code.
if (!opcodeInfos[0].isReachable) {
findUnreachableCode(reader, codeLength);
reader.cursor = start;
}
vmkit::ThreadAllocator allocator;
for(uint32 i = 0; i < codeLength; ++i) {
if (!opcodeInfos[i].isReachable && !opcodeInfos[i].handler) {
continue;
}
reader.cursor = start + i;
uint8 bytecode = reader.readU1();
PRINT_DEBUG(JNJVM_COMPILE, 1, DARK_BLUE, "\t[at %5d] %-5d ", i,
bytecode);
PRINT_DEBUG(JNJVM_COMPILE, 1, LIGHT_BLUE, " compiling ");
PRINT_DEBUG(JNJVM_COMPILE, 1, LIGHT_CYAN, OpcodeNames[bytecode]);
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.
bool b = false;
if (opinfo->handler) {
Instruction* I = opinfo->newBlock->begin();
PHINode * node = dyn_cast<PHINode>(I);
if (!node) {
//llvmFunction->dump();
//Value* obj = pop();
//PHINode* node = PHINode::Create(obj->getType(), 0, "jaja", opinfo->newBlock);
//node->addIncoming(obj, currentBlock);
// if we were in a handler and now we are in a new handler we simulate a throw
llvm::Value* arg = pop();
throwException(arg);
b = true;
// Original Code
//assert(node && "Handler marlformed");
}
else {
Value* obj = pop();
node->addIncoming(obj, currentBlock);
}
}
if (!b)
branch(*opinfo, currentBlock);
}
currentBlock = opinfo->newBlock;
stack.clear();
if (opinfo->handler) {
// If it's a handler, put the exception object in the stack.
Value* javaExceptionPtr = getJavaExceptionPtr(getJavaThreadPtr(getMutatorThreadPtr()));
Value* obj = new LoadInst(javaExceptionPtr, "pendingException", currentBlock);
new StoreInst(obj, objectStack[0], "", currentBlock);
// And clear the exception.
new StoreInst(intrinsics->JavaObjectNullConstant, javaExceptionPtr, currentBlock);
stack.push_back(MetaInfo(upcalls->OfObject, NOP));
currentStackIndex = 1;
} else {
stack = opinfo->stack;
currentStackIndex = stack.size();
}
if (opinfo->backEdge) {
checkYieldPoint();
}
}
currentExceptionBlock = opinfo->exceptionBlock;
currentBytecodeIndex = i;
currentBytecode = bytecode;
// 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)bytecode),
ConstantInt::get(Type::getInt32Ty(*llvmContext), (int64_t)i),
TheCompiler->getMethodInClass(compilingMethod)
};
CallInst::Create(intrinsics->PrintExecutionFunction, args, "",
currentBlock);
}
#endif
switch (bytecode) {
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),
reader.readU1()),
Type::getInt32Ty(*llvmContext)), false);
i++;
break;
case SIPUSH :
push(ConstantExpr::getSExt(ConstantInt::get(Type::getInt16Ty(*llvmContext),
reader.readS2()),
Type::getInt32Ty(*llvmContext)), false);
i += 2;
break;
case LDC :
loadConstant(reader.readU1());
i++;
break;
case LDC_W :
loadConstant(reader.readS2());
i += 2;
break;
case LDC2_W :
loadConstant(reader.readS2());
i += 2;
push(intrinsics->constantZero, false);
break;
case ILOAD :
push(new LoadInst(intLocals[WREAD_U1(reader, false, i, wide)], "", false,
currentBlock), false);
break;
case LLOAD :
push(new LoadInst(longLocals[WREAD_U1(reader, false, i, wide)], "", false,
currentBlock), false);
push(intrinsics->constantZero, false);
break;
case FLOAD :
push(new LoadInst(floatLocals[WREAD_U1(reader, false, i, wide)], "", false,
currentBlock), false);
break;
case DLOAD :
push(new LoadInst(doubleLocals[WREAD_U1(reader, false, i, wide)], "", false,
currentBlock), false);
push(intrinsics->constantZero, false);
break;
case ALOAD :
push(new LoadInst(objectLocals[WREAD_U1(reader, false, i, wide)], "",
false, currentBlock), false);
break;
case ILOAD_0 :
push(new LoadInst(intLocals[0], "", false, currentBlock), false);
break;
case ILOAD_1 :
push(new LoadInst(intLocals[1], "", false, currentBlock), false);
break;
case ILOAD_2 :
push(new LoadInst(intLocals[2], "", false, currentBlock), false);
break;
case ILOAD_3 :
push(new LoadInst(intLocals[3], "", false, currentBlock), false);
break;
case LLOAD_0 :
push(new LoadInst(longLocals[0], "", false, currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case LLOAD_1 :
push(new LoadInst(longLocals[1], "", false, currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case LLOAD_2 :
push(new LoadInst(longLocals[2], "", false, currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case LLOAD_3 :
push(new LoadInst(longLocals[3], "", false, currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case FLOAD_0 :
push(new LoadInst(floatLocals[0], "", false, currentBlock),
false);
break;
case FLOAD_1 :
push(new LoadInst(floatLocals[1], "", false, currentBlock),
false);
break;
case FLOAD_2 :
push(new LoadInst(floatLocals[2], "", false, currentBlock),
false);
break;
case FLOAD_3 :
push(new LoadInst(floatLocals[3], "", false, currentBlock),
false);
break;
case DLOAD_0 :
push(new LoadInst(doubleLocals[0], "", false, currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case DLOAD_1 :
push(new LoadInst(doubleLocals[1], "", false, currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case DLOAD_2 :
push(new LoadInst(doubleLocals[2], "", false, currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case DLOAD_3 :
push(new LoadInst(doubleLocals[3], "", false, currentBlock),
false);
push(intrinsics->constantZero, false);
break;
case ALOAD_0 :
push(new LoadInst(objectLocals[0], "", false, currentBlock),
false);
break;
case ALOAD_1 :
push(new LoadInst(objectLocals[1], "", false, currentBlock),
false);
break;
case ALOAD_2 :
push(new LoadInst(objectLocals[2], "", false, currentBlock),
false);
break;
case ALOAD_3 :
push(new LoadInst(objectLocals[3], "", false, 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(reader, false, i, wide)],
false, currentBlock);
break;
}
case LSTORE :
pop(); // remove the 0 on the stack
new StoreInst(pop(), longLocals[WREAD_U1(reader, false, i, wide)],
false, currentBlock);
break;
case FSTORE :
new StoreInst(pop(), floatLocals[WREAD_U1(reader, false, i, wide)],
false, currentBlock);
break;
case DSTORE :
pop(); // remove the 0 on the stack
new StoreInst(pop(), doubleLocals[WREAD_U1(reader, false, i, wide)],
false, currentBlock);
break;
case ASTORE : {
CommonClass* cl = topTypeInfo();
Instruction* V =
new StoreInst(pop(), objectLocals[WREAD_U1(reader, 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 : {
if (TheCompiler->hasExceptionsEnabled()) {
// Get val and object and don't pop them: IsSubclassOfFunction
// may go into runtime and we don't want values in registers at that
// point.
Value* val = new LoadInst(objectStack[currentStackIndex - 1], "",
false,
currentBlock);
Value* obj = new LoadInst(objectStack[currentStackIndex - 3], "",
false,
currentBlock);
JITVerifyNull(obj);
Value* res = 0;
if (TheCompiler->isStaticCompiling()) {
BasicBlock* endBlock = createBasicBlock("end array store check");
BasicBlock* checkBlock = createBasicBlock("array store check");
BasicBlock* exceptionBlock =
createBasicBlock("array store exception");
Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, val,
intrinsics->JavaObjectNullConstant, "");
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 };
res = CallInst::Create(
(TheCompiler->isStaticCompiling())?
intrinsics->IsSubclassOfFunction:
intrinsics->IsSubclassOfFunctionInner,
VTArgs, "", currentBlock);
BranchInst::Create(endBlock, exceptionBlock, res, currentBlock);
currentBlock = exceptionBlock;
throwRuntimeException(intrinsics->ArrayStoreExceptionFunction, VTArgs, 2);
currentBlock = endBlock;
}
else {
Value* objects[2] = {val, obj};
res = CallInst::Create(intrinsics->CheckIfAssignable, objects, "", currentBlock);
}
}
Value* val = pop();
Value* index = pop();
Value* obj = pop();
Value* ptr = verifyAndComputePtr(obj, index,
intrinsics->JavaArrayObjectType, false);
if (vmkit::Collector::needsWriteBarrier()) {
ptr = new BitCastInst(ptr, intrinsics->ptrPtrType, "", currentBlock);
val = new BitCastInst(val, intrinsics->ptrType, "", currentBlock);
obj = new BitCastInst(obj, intrinsics->ptrType, "", currentBlock);
Value* args[3] = { obj, ptr, val };
CallInst::Create(intrinsics->ArrayWriteBarrierFunction, args, "", currentBlock);
} else {
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();
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();
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 :
// TODO: The following bytecodes should push a MetaInfo.
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;
throwRuntimeException(intrinsics->ArithmeticExceptionFunction, 0, 0);
currentBlock = ifFalse;
}
Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, val2,
intrinsics->constantMinusOne, "");
BasicBlock* ifFalse = createBasicBlock("non -1 div");
BasicBlock* ifTrue = createBasicBlock("-1 div");
BasicBlock* endBlock = createBasicBlock("End division");
PHINode* node = PHINode::Create(val1->getType(), 2, "", endBlock);
BranchInst::Create(ifTrue, ifFalse, cmp, currentBlock);
currentBlock = ifTrue;
node->addIncoming(BinaryOperator::CreateSub(intrinsics->constantZero,
val1, "", currentBlock),
currentBlock);
BranchInst::Create(endBlock, currentBlock);
currentBlock = ifFalse;
node->addIncoming(
BinaryOperator::CreateSDiv(val1, val2, "", currentBlock),
currentBlock);
BranchInst::Create(endBlock, currentBlock);
currentBlock = endBlock;
push(node, 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;
throwRuntimeException(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();
if (TheCompiler->hasExceptionsEnabled()) {
Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, val2,
intrinsics->constantZero, "");
BasicBlock* ifFalse = createBasicBlock("non null rem");
BasicBlock* ifTrue = createBasicBlock("null rem");
BranchInst::Create(ifTrue, ifFalse, cmp, currentBlock);
currentBlock = ifTrue;
throwRuntimeException(intrinsics->ArithmeticExceptionFunction, 0, 0);
currentBlock = ifFalse;
}
Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, val2,
intrinsics->constantMinusOne, "");
BasicBlock* ifFalse = createBasicBlock("non -1 rem");
BasicBlock* endBlock = createBasicBlock("end block");
PHINode* node = PHINode::Create(val1->getType(), 2, "", endBlock);
node->addIncoming(intrinsics->constantZero, currentBlock);
BranchInst::Create(endBlock, ifFalse, cmp, currentBlock);
currentBlock = ifFalse;
node->addIncoming(
BinaryOperator::CreateSRem(val1, val2, "", currentBlock),
currentBlock);
BranchInst::Create(endBlock, currentBlock);
currentBlock = endBlock;
push(node, false);
break;
}
case LREM : {
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;
throwRuntimeException(intrinsics->ArithmeticExceptionFunction, 0, 0);
currentBlock = ifFalse;
}
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::CreateFSub(
intrinsics->constantFloatMinusZero,
pop(), "", currentBlock), false);
break;
case DNEG : {
pop();
push(BinaryOperator::CreateFSub(
intrinsics->constantDoubleMinusZero,
pop(), "", currentBlock), false);
push(intrinsics->constantZero, false);
break;
}
case ISHL : {
Value* val2 = popAsInt();
Value* val1 = popAsInt();
Value* mask = ConstantInt::get(Type::getInt32Ty(*llvmContext), 0x1F);
val2 = BinaryOperator::CreateAnd(val2, mask, "", currentBlock);
push(BinaryOperator::CreateShl(val1, val2, "", currentBlock),
false);
break;
}
case LSHL : {
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::CreateShl(val1, val2, "", currentBlock),
false);
push(intrinsics->constantZero, false);
break;
}
case ISHR : {
Value* val2 = popAsInt();
Value* val1 = popAsInt();
Value* mask = ConstantInt::get(Type::getInt32Ty(*llvmContext), 0x1F);
val2 = BinaryOperator::CreateAnd(val2, mask, "", currentBlock);
push(BinaryOperator::CreateAShr(val1, val2, "", currentBlock),
false);
break;
}
case LSHR : {
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::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(reader, true, i, wide);
sint16 val = WREAD_S1(reader, 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), 4, "", 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(Type::getInt64Ty(*llvmContext), 4, "", 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(Type::getInt32Ty(*llvmContext), 4, "", 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(Type::getInt64Ty(*llvmContext), 4, "", 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(Type::getInt32Ty(*llvmContext), 2, "", 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 + reader.readS2()];
i += 2;
BasicBlock* ifTrue = ifTrueInfo.newBlock;
Value* op = pop();
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 + reader.readS2()];
i += 2;
BasicBlock* ifTrue = ifTrueInfo.newBlock;
Value* op = pop();
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 + reader.readS2()];
i += 2;
BasicBlock* ifTrue = ifTrueInfo.newBlock;
Value* op = pop();
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 + reader.readS2()];
i += 2;
BasicBlock* ifTrue = ifTrueInfo.newBlock;
Value* op = pop();
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 + reader.readS2()];
i += 2;
BasicBlock* ifTrue = ifTrueInfo.newBlock;
Value* op = pop();
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 + reader.readS2()];
i += 2;
BasicBlock* ifTrue = ifTrueInfo.newBlock;
Value* op = pop();
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 + reader.readS2()];
i += 2;
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 + reader.readS2()];
i += 2;
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 + reader.readS2()];
i += 2;
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 + reader.readS2()];
i += 2;
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 + reader.readS2()];
i += 2;
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 + reader.readS2()];
i += 2;
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 + reader.readS2()];
i += 2;
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 + reader.readS2()];
i += 2;
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 + reader.readS2()],
currentBlock);
i += 2;
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 + reader.readS2()], currentBlock);
i += 2;
break;
}
case RET : {
uint8 local = reader.readU1();
i += 1;
Value* _val = new LoadInst(
objectLocals[local], "", false, 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;
reader.cursor += filled;
Opinfo& def = opcodeInfos[tmp + reader.readU4()];
i += 4;
sint32 low = reader.readS4();
i += 4;
sint32 high = reader.readS4() + 1;
i += 4;
Value* index = pop();
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 + reader.readU4()];
i += 4;
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;
reader.cursor += filled;
Opinfo& def = opcodeInfos[tmp + reader.readU4()];
i += 4;
uint32 nbs = reader.readU4();
i += 4;
Value* key = pop();
for (uint32 cur = 0; cur < nbs; ++cur) {
Value* val = ConstantInt::get(Type::getInt32Ty(*llvmContext), reader.readU4());
i += 4;
Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, val, key,
"");
BasicBlock* falseBlock = createBasicBlock("continue lookupswitch");
Opinfo& info = opcodeInfos[tmp + reader.readU4()];
i += 4;
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 = reader.readU2();
i += 2;
getStaticField(index);
break;
}
case PUTSTATIC : {
uint16 index = reader.readU2();
i += 2;
setStaticField(index);
break;
}
case GETFIELD : {
uint16 index = reader.readU2();
i += 2;
getVirtualField(index);
break;
}
case PUTFIELD : {
uint16 index = reader.readU2();
i += 2;
setVirtualField(index);
break;
}
case INVOKEVIRTUAL : {
uint16 index = reader.readU2();
i += 2;
invokeVirtual(index);
break;
}
case INVOKESPECIAL : {
uint16 index = reader.readU2();
i += 2;
invokeSpecial(index);
break;
}
case INVOKESTATIC : {
uint16 index = reader.readU2();
i += 2;
invokeStatic(index);
break;
}
case INVOKEINTERFACE : {
uint16 index = reader.readU2();
i += 2;
invokeInterface(index);
i += 2;
break;
}
case NEW : {
uint16 index = reader.readU2();
i += 2;
invokeNew(index);
break;
}
case NEWARRAY :
case ANEWARRAY : {
Constant* sizeElement = 0;
Value* TheVT = 0;
Value* valCl = 0;
UserClassArray* dcl = 0;
if (bytecode == NEWARRAY) {
uint8 id = reader.readU1();
i += 1;
uint8 charId = arrayType(compilingMethod, id);
JnjvmBootstrapLoader* loader =
compilingClass->classLoader->bootstrapLoader;
dcl = loader->getArrayClass(id);
valCl = TheCompiler->getNativeClass(dcl);
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 = reader.readU2();
i += 2;
CommonClass* cl =
compilingClass->ctpInfo->getMethodClassIfLoaded(index);
if (cl && (!cl->isClass() || cl->asClass()->isResolved())) {
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 {
Type* Ty =
PointerType::getUnqual(intrinsics->VTType);
Value* args[3]= { TheCompiler->getNativeClass(compilingClass),
ConstantInt::get(Type::getInt32Ty(*llvmContext), index),
Constant::getNullValue(Ty) };
TheVT = CallInst::Create(intrinsics->GetArrayClassFunction, args,
"", 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;
throwRuntimeException(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;
throwRuntimeException(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->VTAllocateFunction, 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, "", 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;
reader.cursor += 2;
break;
}
case INSTANCEOF : {
bool checkcast = (bytecode == CHECKCAST);
BasicBlock* exceptionCheckcast = 0;
BasicBlock* endCheckcast = 0;
uint16 index = reader.readU2();
i += 2;
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), 2, "", 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;
throwRuntimeException(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()) {
if (TheCompiler->isStaticCompiling())
res = CallInst::Create(intrinsics->IsSecondaryClassFunction,
classArgs, "", currentBlock);
else
res = CallInst::Create(intrinsics->IsSecondaryClassFunctionInner,
classArgs, "", 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, "", currentBlock);
res = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, VTInDisplay,
TheVT, "");
}
} else {
if (TheCompiler->isStaticCompiling())
res = CallInst::Create(intrinsics->IsSubclassOfFunction,
classArgs, "", currentBlock);
else
res = CallInst::Create(intrinsics->IsSubclassOfFunctionInner,
classArgs, "", 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 : {
bool thisReference = isThisReference(currentStackIndex - 1);
Value* obj = pop();
if (!thisReference) JITVerifyNull(obj);
monitorEnter(obj);
break;
}
case MONITOREXIT : {
bool thisReference = isThisReference(currentStackIndex - 1);
Value* obj = pop();
if (!thisReference) JITVerifyNull(obj);
monitorExit(obj);
break;
}
case MULTIANEWARRAY : {
uint16 index = reader.readU2();
i += 2;
uint8 dim = reader.readU1();
i += 1;
UserCommonClass* dcl = 0;
Value* valCl = getResolvedCommonClass(index, true, &dcl);
Value** args = (Value**)allocator.Allocate(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 + reader.readS2()];
i += 2;
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 + reader.readS2()];
i += 2;
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!", bytecode,
UTF8Buffer(compilingClass->name).cString(),
UTF8Buffer(compilingMethod->name).cString());
abort();
}
}
}
}
void JavaJIT::exploreOpcodes(Reader& reader, uint32 codeLength) {
PRINT_DEBUG(JNJVM_COMPILE, 1, DARK_YELLOW, "exploreOpcodes %d \n", codeLength);
bool wide = false;
uint32 start = reader.cursor;
for(uint32 i = 0; i < codeLength; ++i) {
reader.cursor = start + i;
uint8 bytecode = reader.readU1();
PRINT_DEBUG(JNJVM_COMPILE, 1, DARK_CYAN, "\t[at %5d] %-5d ", i,
bytecode);
PRINT_DEBUG(JNJVM_COMPILE, 1, LIGHT_BLUE, "exploring ");
PRINT_DEBUG(JNJVM_COMPILE, 1, LIGHT_CYAN, OpcodeNames[bytecode]);
PRINT_DEBUG(JNJVM_COMPILE, 1, LIGHT_BLUE, "\n");
switch (bytecode) {
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_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 ASTORE_0 :
if (!isStatic(compilingMethod->access)) overridesThis = true;
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 :
case IFNULL :
case IFNONNULL : {
uint32 tmp = i;
uint16 index = tmp + reader.readU2();
if (index < i) opcodeInfos[index].backEdge = true;
i += 2;
if (!(opcodeInfos[index].newBlock))
opcodeInfos[index].newBlock = createBasicBlock("");
break;
}
case JSR : {
uint32 tmp = i;
uint16 index = tmp + reader.readU2();
i += 2;
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;
reader.cursor += filled;
uint32 index = tmp + reader.readU4();
i += 4;
if (!(opcodeInfos[index].newBlock)) {
BasicBlock* block = createBasicBlock("tableswitch");
opcodeInfos[index].newBlock = block;
}
uint32 low = reader.readU4();
i += 4;
uint32 high = reader.readU4() + 1;
i += 4;
uint32 depl = high - low;
for (uint32 cur = 0; cur < depl; ++cur) {
uint32 index2 = tmp + reader.readU4();
i += 4;
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;
reader.cursor += filled;
uint32 index = tmp + reader.readU4();
i += 4;
if (!(opcodeInfos[index].newBlock)) {
BasicBlock* block = createBasicBlock("tableswitch");
opcodeInfos[index].newBlock = block;
}
uint32 nbs = reader.readU4();
i += 4;
for (uint32 cur = 0; cur < nbs; ++cur) {
i += 4;
reader.cursor += 4;
uint32 index2 = tmp + reader.readU4();
i += 4;
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;
default : {
fprintf(stderr, "I haven't verified your class file and it's malformed:"
" unknown bytecode %d in %s.%s!\n", bytecode,
UTF8Buffer(compilingClass->name).cString(),
UTF8Buffer(compilingMethod->name).cString());
abort();
}
}
}
}
bool JavaJIT::canInlineLoadConstant(uint16 index) {
JavaConstantPool* ctpInfo = compilingClass->ctpInfo;
uint8 type = ctpInfo->typeAt(index);
if (type == JavaConstantPool::ConstantString
|| type == JavaConstantPool::ConstantClass) {
return false;
} else {
return true;
}
}
static uint8 getReceiver(const std::vector<uint8>& stack, Signdef* signature) {
uint32_t index = stack.size() - 1;
Typedef* const* arguments = signature->getArgumentsType();
for (uint32 i = 0; i < signature->nbArguments; i++) {
index--;
if (arguments[i]->isDouble() || arguments[i]->isLong()) {
index--;
}
}
return stack[index];
}
static void updateStack(std::vector<uint8>& stack, Signdef* signature, uint8 bytecode) {
Typedef* const* arguments = signature->getArgumentsType();
if (bytecode != INVOKESTATIC) {
stack.pop_back();
}
for (uint32 i = 0; i < signature->nbArguments; i++) {
stack.pop_back();
if (arguments[i]->isDouble() || arguments[i]->isLong()) {
stack.pop_back();
}
}
if (!signature->getReturnType()->isVoid()) {
stack.push_back(bytecode);
if (signature->getReturnType()->isLong()
|| signature->getReturnType()->isDouble()) {
stack.push_back(bytecode);
}
}
}
bool JavaJIT::analyzeForInlining(Reader& reader, uint32 codeLength) {
JavaConstantPool* ctpInfo = compilingClass->ctpInfo;
bool wide = false;
uint32 start = reader.cursor;
std::vector<uint8_t> stack;
for(uint32 i = 0; i < codeLength; ++i) {
reader.cursor = start + i;
uint8 bytecode = reader.readU1();
switch (bytecode) {
case NOP :
break;
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 FCONST_0 :
case FCONST_1 :
case FCONST_2 :
stack.push_back(bytecode);
break;
case LCONST_0 :
case LCONST_1 :
case DCONST_0 :
case DCONST_1 :
stack.push_back(bytecode);
stack.push_back(bytecode);
break;
case BIPUSH :
++i;
stack.push_back(bytecode);
break;
case SIPUSH :
i += 2;
stack.push_back(bytecode);
break;
case LDC :
i++;
stack.push_back(bytecode);
if (!canInlineLoadConstant(reader.readU1())) return false;
break;
case LDC_W :
i += 2;
stack.push_back(bytecode);
if (!canInlineLoadConstant(reader.readS2())) return false;
break;
case LDC2_W :
i += 2;
stack.push_back(bytecode);
stack.push_back(bytecode);
if (!canInlineLoadConstant(reader.readS2())) return false;
break;
case ILOAD :
case FLOAD :
case ALOAD :
i += WCALC(1, wide);
stack.push_back(bytecode);
break;
case LLOAD :
case DLOAD :
i += WCALC(1, wide);
stack.push_back(bytecode);
stack.push_back(bytecode);
break;
case ILOAD_0 :
case ILOAD_1 :
case ILOAD_2 :
case ILOAD_3 :
case FLOAD_0 :
case FLOAD_1 :
case FLOAD_2 :
case FLOAD_3 :
case ALOAD_0 :
case ALOAD_1 :
case ALOAD_2 :
case ALOAD_3 :
stack.push_back(bytecode);
break;
case LLOAD_0 :
case LLOAD_1 :
case LLOAD_2 :
case LLOAD_3 :
case DLOAD_0 :
case DLOAD_1 :
case DLOAD_2 :
case DLOAD_3 :
stack.push_back(bytecode);
stack.push_back(bytecode);
break;
case IALOAD :
case FALOAD :
case AALOAD :
case BALOAD :
case CALOAD :
case SALOAD :
stack.pop_back();
stack.pop_back();
stack.push_back(bytecode);
return false;
case LALOAD :
case DALOAD :
stack.pop_back();
stack.pop_back();
stack.push_back(bytecode);
stack.push_back(bytecode);
return false;
case ISTORE :
case FSTORE :
case ASTORE :
stack.pop_back();
i += WCALC(1, wide);
break;
case LSTORE :
case DSTORE :
stack.pop_back();
stack.pop_back();
i += WCALC(1, wide);
break;
case ISTORE_0 :
case ISTORE_1 :
case ISTORE_2 :
case ISTORE_3 :
case FSTORE_0 :
case FSTORE_1 :
case FSTORE_2 :
case FSTORE_3 :
case ASTORE_1 :
case ASTORE_2 :
case ASTORE_3 :
stack.pop_back();
break;
case ASTORE_0 :
stack.pop_back();
if (!isStatic(compilingMethod->access)) return false;
break;
case DSTORE_0 :
case DSTORE_1 :
case DSTORE_2 :
case DSTORE_3 :
case LSTORE_0 :
case LSTORE_1 :
case LSTORE_2 :
case LSTORE_3 :
stack.pop_back();
stack.pop_back();
break;
case IASTORE :
case FASTORE :
case AASTORE :
case BASTORE :
case CASTORE :
case SASTORE :
stack.pop_back();
stack.pop_back();
stack.pop_back();
return false;
case LASTORE :
case DASTORE :
stack.pop_back();
stack.pop_back();
stack.pop_back();
stack.pop_back();
return false;
case POP :
stack.pop_back();
break;
case POP2 :
stack.pop_back();
stack.pop_back();
break;
case DUP :
stack.push_back(stack.back());
break;
case DUP_X1 : {
uint8 one = stack.back(); stack.pop_back();
uint8 two = stack.back(); stack.pop_back();
stack.push_back(one);
stack.push_back(two);
stack.push_back(one);
break;
}
case DUP_X2 : {
uint8 one = stack.back(); stack.pop_back();
uint8 two = stack.back(); stack.pop_back();
uint8 three = stack.back(); stack.pop_back();
stack.push_back(one);
stack.push_back(three);
stack.push_back(two);
stack.push_back(one);
break;
}
case DUP2 : {
uint8 one = stack.back(); stack.pop_back();
uint8 two = stack.back(); stack.pop_back();
stack.push_back(two);
stack.push_back(one);
stack.push_back(two);
stack.push_back(one);
break;
}
case DUP2_X1 : {
uint8 one = stack.back(); stack.pop_back();
uint8 two = stack.back(); stack.pop_back();
uint8 three = stack.back(); stack.pop_back();
stack.push_back(two);
stack.push_back(one);
stack.push_back(three);
stack.push_back(two);
stack.push_back(one);
break;
}
case DUP2_X2 : {
uint8 one = stack.back(); stack.pop_back();
uint8 two = stack.back(); stack.pop_back();
uint8 three = stack.back(); stack.pop_back();
uint8 four = stack.back(); stack.pop_back();
stack.push_back(two);
stack.push_back(one);
stack.push_back(four);
stack.push_back(three);
stack.push_back(two);
stack.push_back(one);
break;
}
case SWAP : {
uint8 one = stack.back(); stack.pop_back();
uint8 two = stack.back(); stack.pop_back();
stack.push_back(one);
stack.push_back(two);
break;
}
case IADD :
case FADD :
case ISUB :
case FSUB :
case IMUL :
case FMUL :
case FDIV :
case FREM :
case ISHL :
case ISHR :
case IUSHR :
case IAND :
case IOR :
case IXOR :
stack.pop_back();
stack.pop_back();
stack.push_back(bytecode);
break;
case LADD :
case DADD :
case DDIV :
case LMUL :
case DMUL :
case DREM :
case LSUB :
case DSUB :
stack.pop_back();
stack.pop_back();
stack.push_back(bytecode);
stack.push_back(bytecode);
break;
case IREM :
case IDIV :
case LREM :
case LDIV :
return false;
case INEG :
case FNEG :
stack.pop_back();
stack.push_back(bytecode);
break;
case LNEG :
case DNEG :
stack.pop_back();
stack.pop_back();
stack.push_back(bytecode);
stack.push_back(bytecode);
break;
case LSHL :
case LSHR :
case LUSHR :
case LAND :
case LOR :
case LXOR :
stack.pop_back();
stack.pop_back();
stack.pop_back();
stack.push_back(bytecode);
stack.push_back(bytecode);
break;
case IINC :
i += WCALC(2, wide);
break;
case I2L :
case I2D :
case F2L :
case F2D :
stack.pop_back();
stack.push_back(bytecode);
stack.push_back(bytecode);
break;
case I2F :
case F2I :
case I2B :
case I2C :
case I2S :
stack.pop_back();
stack.push_back(bytecode);
break;
case L2I :
case L2F :
case D2I :
case D2F :
stack.pop_back();
stack.pop_back();
stack.push_back(bytecode);
break;
case L2D :
case D2L :
stack.pop_back();
stack.pop_back();
stack.push_back(bytecode);
stack.push_back(bytecode);
break;
case FCMPL :
case FCMPG :
stack.pop_back();
stack.pop_back();
stack.push_back(bytecode);
break;
case LCMP :
case DCMPL :
case DCMPG :
stack.pop_back();
stack.pop_back();
stack.pop_back();
stack.pop_back();
stack.push_back(bytecode);
break;
case IFEQ :
case IFNE :
case IFLT :
case IFGE :
case IFGT :
case IFLE : {
i += 2;
stack.pop_back();
if (stack.size() > 0) return false;
break;
}
case IF_ICMPEQ :
case IF_ICMPNE :
case IF_ICMPLT :
case IF_ICMPGE :
case IF_ICMPGT :
case IF_ICMPLE :
case IF_ACMPEQ :
case IF_ACMPNE : {
i += 2;
stack.pop_back();
stack.pop_back();
if (stack.size() > 0) return false;
break;
}
case GOTO : {
i += 2;
if (stack.size() > 0) return false;
break;
}
case JSR : {
i += 2;
return false;
}
case RET : {
++i;
return false;
}
case TABLESWITCH : {
stack.pop_back();
if (stack.size() > 0) return false;
uint32 tmp = i;
uint32 reste = (i + 1) & 3;
uint32 filled = reste ? (4 - reste) : 0;
i += filled;
reader.cursor += filled;
reader.readU4();
i += 4;
sint32 low = reader.readS4();
i += 4;
sint32 high = reader.readS4() + 1;
i += 4;
for (sint32 cur = low; cur < high; ++cur) {
reader.readU4();
i += 4;
}
i = tmp + 12 + filled + ((high - low) << 2);
break;
}
case LOOKUPSWITCH : {
stack.pop_back();
if (stack.size() > 0) return false;
uint32 tmp = i;
uint32 filled = (3 - i) & 3;
i += filled;
reader.cursor += filled;
reader.readU4();
i += 4;
uint32 nbs = reader.readU4();
i += 4;
for (uint32 cur = 0; cur < nbs; ++cur) {
i += 4;
reader.cursor += 4;
reader.readU4();
i += 4;
}
i = tmp + 8 + filled + (nbs << 3);
break;
}
case IRETURN :
case FRETURN :
case ARETURN :
stack.pop_back();
break;
case RETURN :
break;
case LRETURN :
case DRETURN :
stack.pop_back();
stack.pop_back();
break;
case GETSTATIC :
case PUTSTATIC : {
uint16 index = reader.readU2();
Typedef* sign = ctpInfo->infoOfField(index);
JavaField* field = ctpInfo->lookupField(index, true);
if (field == NULL) return false;
if (needsInitialisationCheck(field->classDef)) return false;
if (bytecode == GETSTATIC) {
stack.push_back(bytecode);
if (sign->isDouble() || sign->isLong()) {
stack.push_back(bytecode);
}
} else {
stack.pop_back();
if (sign->isDouble() || sign->isLong()) {
stack.pop_back();
}
}
i += 2;
break;
}
case PUTFIELD : {
if (isStatic(compilingMethod->access)) return false;
i += 2;
stack.pop_back(); // value
uint16 index = reader.readU2();
Typedef* sign = ctpInfo->infoOfField(index);
if (sign->isDouble() || sign->isLong()) {
stack.pop_back(); // value
}
if (stack.back() != ALOAD_0) return false;
stack.pop_back(); // object
break;
}
case GETFIELD : {
if (isStatic(compilingMethod->access)) return false;
if (stack.back() != ALOAD_0) return false;
i += 2;
stack.pop_back(); // object
uint16 index = reader.readU2();
Typedef* sign = ctpInfo->infoOfField(index);
stack.push_back(bytecode);
if (sign->isDouble() || sign->isLong()) {
stack.push_back(bytecode);
}
break;
}
case INVOKEVIRTUAL : {
if (isStatic(compilingMethod->access)) return false;
uint16 index = reader.readU2();
CommonClass* cl = NULL;
JavaMethod* meth = NULL;
ctpInfo->infoOfMethod(index, ACC_VIRTUAL, cl, meth);
i += 2;
if (meth == NULL) return false;
if (getReceiver(stack, meth->getSignature()) != ALOAD_0) return false;
bool customized = false;
if (!(isFinal(cl->access) || isFinal(meth->access))) {
if (customizeFor == NULL) return false;
if (!customizeFor->isSubclassOf(cl)) return false;
meth = customizeFor->lookupMethodDontThrow(
meth->name, meth->type, false, true, NULL);
assert(meth);
assert(!meth->classDef->isInterface());
assert(!isAbstract(meth->access));
customized = true;
}
if (!canBeInlined(meth, customized)) return false;
updateStack(stack, meth->getSignature(), bytecode);
break;
}
case INVOKESPECIAL : {
if (isStatic(compilingMethod->access)) return false;
uint16 index = reader.readU2();
CommonClass* cl = NULL;
JavaMethod* meth = NULL;
ctpInfo->infoOfMethod(index, ACC_VIRTUAL, cl, meth);
i += 2;
if (meth == NULL) return false;
if (getReceiver(stack, meth->getSignature()) != ALOAD_0) return false;
if (!canBeInlined(meth, false)) return false;
updateStack(stack, meth->getSignature(), bytecode);
break;
}
case INVOKESTATIC : {
uint16 index = reader.readU2();
CommonClass* cl = NULL;
JavaMethod* meth = NULL;
ctpInfo->infoOfMethod(index, ACC_STATIC, cl, meth);
i += 2;
if (meth == NULL) return false;
if (!canBeInlined(meth, false)) return false;
if (needsInitialisationCheck(cl->asClass())) return false;
updateStack(stack, meth->getSignature(), bytecode);
break;
}
case INVOKEINTERFACE :
i += 4;
return false;
case NEW :
i += 2;
return false;
case NEWARRAY :
++i;
return false;
case ANEWARRAY :
i += 2;
return false;
case ARRAYLENGTH :
stack.pop_back();
stack.push_back(bytecode);
return false;
case ATHROW :
return false;
case CHECKCAST :
i += 2;
return false;
case INSTANCEOF :
i += 2;
return false;
case MONITORENTER :
case MONITOREXIT :
return false;
case MULTIANEWARRAY :
i += 3;
return false;
case WIDE :
wide = true;
break;
case IFNULL :
case IFNONNULL :
stack.pop_back();
i += 2;
if (stack.size() > 0) return false;
break;
default :
return false;
}
}
return true;
}