pluotsorbet/interpreter.ts

1109 строки
35 KiB
TypeScript
Исходник Обычный вид История

2014-11-27 12:15:46 +03:00
module J2ME {
declare var util;
declare var Long;
declare var JavaException;
import Bytecodes = Bytecode.Bytecodes;
import assert = Debug.assert;
export var interpreterCounter = null; new Metrics.Counter(true);
2014-11-27 12:15:46 +03:00
function traceArrayStore(idx: number, array: any [], value: any) {
traceWriter && traceWriter.writeLn(toDebugString(array) + "[" + idx + "] = " + toDebugString(value));
}
function traceArrayLoad(idx: number, array: any []) {
assert(array[idx] !== undefined);
traceWriter && traceWriter.writeLn(toDebugString(array) + "[" + idx + "] (" + toDebugString(array[idx]) + ")");
}
export function interpret(ctx: Context) {
var frame = ctx.current();
var cp = frame.cp;
var stack = frame.stack;
var returnValue = null;
if (traceWriter) {
for (var i = 0; i < ctx.frames.length; i++) {
var methodInfo = ctx.frames[i].methodInfo;
var localsStr = ctx.frames[i].locals.map(function (x) {
2014-11-27 12:15:46 +03:00
return toDebugString(x);
}).join(", ");
var stackStr = ctx.frames[i].stack.map(function (x) {
return toDebugString(x);
}).join(", ");
2014-11-27 12:15:46 +03:00
var printObj = "";
//if (!methodInfo.isStatic) {
// printObj = " <" + toDebugString(this) + "> ";
//}
traceWriter.enter("> " + MethodType[MethodType.Interpreted][0] + " " + methodInfo.classInfo.className + "/" + methodInfo.name + signatureToDefinition(methodInfo.signature, true, true) + printObj + " (" + localsStr + " | " + stackStr + ")");
2014-11-27 12:15:46 +03:00
}
}
interpreterCounter && interpreterCounter.count(frame.methodInfo.implKey);
2014-11-27 12:15:46 +03:00
function popFrame(consumes) {
if (frame.lockObject)
ctx.monitorExit(frame.lockObject);
var callee = frame;
frame = ctx.popFrame();
traceWriter && traceWriter.leave("< ");
if (frame === null) {
returnValue = null;
switch (consumes) {
case 2:
returnValue = callee.stack.pop2();
break;
case 1:
returnValue = callee.stack.pop();
break;
}
return true;
}
stack = frame.stack;
cp = frame.cp;
switch (consumes) {
case 2:
stack.push2(callee.stack.pop2());
break;
case 1:
stack.push(callee.stack.pop());
break;
}
return false;
}
function buildExceptionLog(ex, stackTrace) {
var className = ex.klass.classInfo.className;
var detailMessage = util.fromJavaString(CLASSES.getField(ex.klass.classInfo, "I.detailMessage.Ljava/lang/String;").get(ex));
return className + ": " + (detailMessage || "") + "\n" + stackTrace.join("\n") + "\n\n";
}
function throw_(ex, ctx) {
var exClass = ex.class;
var stackTrace = [];
do {
var exception_table = frame.methodInfo.exception_table;
var handler_pc = null;
for (var i=0; exception_table && i<exception_table.length; i++) {
2014-12-01 20:47:42 +03:00
if (frame.bci >= exception_table[i].start_pc && frame.bci <= exception_table[i].end_pc) {
2014-11-27 12:15:46 +03:00
if (exception_table[i].catch_type === 0) {
handler_pc = exception_table[i].handler_pc;
} else {
var classInfo = resolve(exception_table[i].catch_type);
if (isAssignableTo(ex.klass, classInfo.klass)) {
handler_pc = exception_table[i].handler_pc;
break;
}
}
}
}
var classInfo = frame.methodInfo.classInfo;
if (classInfo && classInfo.className) {
2014-12-01 20:47:42 +03:00
stackTrace.push(" - " + classInfo.className + "." + frame.methodInfo.name + "(), bci=" + frame.bci);
2014-11-27 12:15:46 +03:00
}
if (handler_pc != null) {
stack.length = 0;
stack.push(ex);
2014-12-01 20:47:42 +03:00
frame.bci = handler_pc;
2014-11-27 12:15:46 +03:00
if (VM.DEBUG_PRINT_ALL_EXCEPTIONS) {
console.error(buildExceptionLog(ex, stackTrace));
}
return;
}
if (ctx.frames.length == 1) {
break;
}
popFrame(0);
} while (frame);
ctx.kill();
if (ctx.thread && ctx.thread.waiting && ctx.thread.waiting.length > 0) {
console.error(buildExceptionLog(ex, stackTrace));
ctx.thread.waiting.forEach(function(waitingCtx, n) {
ctx.thread.waiting[n] = null;
waitingCtx.wakeup(ctx.thread);
});
} else {
throw new Error(buildExceptionLog(ex, stackTrace));
}
}
function checkArrayAccess(refArray, idx) {
if (!refArray) {
ctx.raiseExceptionAndYield("java/lang/NullPointerException");
}
if (idx < 0 || idx >= refArray.length) {
ctx.raiseExceptionAndYield("java/lang/ArrayIndexOutOfBoundsException", idx);
}
}
function classInitCheck(classInfo, ip) {
if (classInfo.isArrayClass || ctx.runtime.initialized[classInfo.className])
return;
try {
ctx.pushClassInitFrame(classInfo);
} catch (e) {
2014-12-01 20:47:42 +03:00
frame.bci = ip;
throwHelper(e);
2014-11-27 12:15:46 +03:00
}
}
function resolve(idx: number, isStatic?: boolean) {
try {
return ctx.resolve(cp, idx, isStatic);
} catch (e) {
if (e instanceof JavaException) {
ctx.raiseExceptionAndYield(e.javaClassName, e.message);
} else {
throwHelper(e);
2014-11-27 12:15:46 +03:00
}
}
}
var traceSourceLocation = true;
var lastSourceLocation;
2014-11-27 12:15:46 +03:00
while (true) {
var op: Bytecodes = frame.read8();
if (traceSourceLocation) {
if (frame.methodInfo) {
2014-12-01 20:47:42 +03:00
var sourceLocation = frame.methodInfo.getSourceLocationForBci(frame.bci - 1);
if (sourceLocation && !sourceLocation.equals(lastSourceLocation)) {
traceWriter && traceWriter.greenLn(sourceLocation.toString() + " " + CLASSES.getSourceLine(sourceLocation));
lastSourceLocation = sourceLocation;
}
}
}
interpreterCounter && interpreterCounter.count(Bytecodes[op]);
2014-12-01 20:47:42 +03:00
// console.trace(ctx.thread.pid, frame.methodInfo.classInfo.className + " " + frame.methodInfo.name + " " + (frame.bci - 1) + " " + OPCODES[op] + " " + stack.join(","));
2014-11-27 12:15:46 +03:00
switch (op) {
2014-11-27 12:32:07 +03:00
case Bytecodes.NOP:
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ACONST_NULL:
2014-11-27 12:15:46 +03:00
stack.push(null);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ICONST_M1:
2014-11-27 12:15:46 +03:00
stack.push(-1);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ICONST_0:
case Bytecodes.FCONST_0:
2014-11-27 12:15:46 +03:00
stack.push(0);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.DCONST_0:
2014-11-27 12:15:46 +03:00
stack.push2(0);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ICONST_1:
case Bytecodes.FCONST_1:
2014-11-27 12:15:46 +03:00
stack.push(1);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.DCONST_1:
2014-11-27 12:15:46 +03:00
stack.push2(1);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ICONST_2:
case Bytecodes.FCONST_2:
2014-11-27 12:15:46 +03:00
stack.push(2);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ICONST_3:
2014-11-27 12:15:46 +03:00
stack.push(3);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ICONST_4:
2014-11-27 12:15:46 +03:00
stack.push(4);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ICONST_5:
2014-11-27 12:15:46 +03:00
stack.push(5);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LCONST_0:
2014-11-27 12:15:46 +03:00
stack.push2(Long.fromInt(0));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LCONST_1:
2014-11-27 12:15:46 +03:00
stack.push2(Long.fromInt(1));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.BIPUSH:
2014-11-27 12:15:46 +03:00
stack.push(frame.read8signed());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.SIPUSH:
2014-11-27 12:15:46 +03:00
stack.push(frame.read16signed());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LDC:
case Bytecodes.LDC_W:
2014-11-27 12:15:46 +03:00
var idx = (op === 0x12) ? frame.read8() : frame.read16();
var constant = cp[idx];
if (constant.tag)
constant = resolve(idx);
stack.push(constant);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LDC2_W:
2014-11-27 12:15:46 +03:00
var idx = frame.read16();
var constant = cp[idx];
if (constant.tag)
constant = resolve(idx);
stack.push2(constant);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ILOAD:
case Bytecodes.FLOAD:
case Bytecodes.ALOAD:
2014-11-27 12:15:46 +03:00
stack.push(frame.getLocal(frame.read8()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LLOAD:
case Bytecodes.DLOAD:
2014-11-27 12:15:46 +03:00
stack.push2(frame.getLocal(frame.read8()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ILOAD_0:
case Bytecodes.FLOAD_0:
case Bytecodes.ALOAD_0:
2014-11-27 12:15:46 +03:00
stack.push(frame.getLocal(0));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ILOAD_1:
case Bytecodes.FLOAD_1:
case Bytecodes.ALOAD_1:
2014-11-27 12:15:46 +03:00
stack.push(frame.getLocal(1));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ILOAD_2:
case Bytecodes.FLOAD_2:
case Bytecodes.ALOAD_2:
2014-11-27 12:15:46 +03:00
stack.push(frame.getLocal(2));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ILOAD_3:
case Bytecodes.FLOAD_3:
case Bytecodes.ALOAD_3:
2014-11-27 12:15:46 +03:00
stack.push(frame.getLocal(3));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LLOAD_0:
case Bytecodes.DLOAD_0:
2014-11-27 12:15:46 +03:00
stack.push2(frame.getLocal(0));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LLOAD_1:
case Bytecodes.DLOAD_1:
2014-11-27 12:15:46 +03:00
stack.push2(frame.getLocal(1));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LLOAD_2:
case Bytecodes.DLOAD_2:
2014-11-27 12:15:46 +03:00
stack.push2(frame.getLocal(2));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LLOAD_3:
case Bytecodes.DLOAD_3:
2014-11-27 12:15:46 +03:00
stack.push2(frame.getLocal(3));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IALOAD:
case Bytecodes.FALOAD:
case Bytecodes.AALOAD:
case Bytecodes.BALOAD:
case Bytecodes.CALOAD:
case Bytecodes.SALOAD:
2014-11-27 12:15:46 +03:00
var idx = stack.pop();
var refArray = stack.pop();
checkArrayAccess(refArray, idx);
stack.push(refArray[idx]);
traceArrayLoad(idx, refArray);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LALOAD:
case Bytecodes.DALOAD:
2014-11-27 12:15:46 +03:00
var idx = stack.pop();
var refArray = stack.pop();
checkArrayAccess(refArray, idx);
stack.push2(refArray[idx]);
traceArrayLoad(idx, refArray);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ISTORE:
case Bytecodes.FSTORE:
case Bytecodes.ASTORE:
2014-11-27 12:15:46 +03:00
frame.setLocal(frame.read8(), stack.pop());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LSTORE:
case Bytecodes.DSTORE:
2014-11-27 12:15:46 +03:00
frame.setLocal(frame.read8(), stack.pop2());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ISTORE_0:
case Bytecodes.FSTORE_0:
case Bytecodes.ASTORE_0:
2014-11-27 12:15:46 +03:00
frame.setLocal(0, stack.pop());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ISTORE_1:
case Bytecodes.FSTORE_1:
case Bytecodes.ASTORE_1:
2014-11-27 12:15:46 +03:00
frame.setLocal(1, stack.pop());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ISTORE_2:
case Bytecodes.FSTORE_2:
case Bytecodes.ASTORE_2:
2014-11-27 12:15:46 +03:00
frame.setLocal(2, stack.pop());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ISTORE_3:
case Bytecodes.FSTORE_3:
case Bytecodes.ASTORE_3:
2014-11-27 12:15:46 +03:00
frame.setLocal(3, stack.pop());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LSTORE_0:
case Bytecodes.DSTORE_0:
2014-11-27 12:15:46 +03:00
frame.setLocal(0, stack.pop2());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LSTORE_1:
case Bytecodes.DSTORE_1:
2014-11-27 12:15:46 +03:00
frame.setLocal(1, stack.pop2());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LSTORE_2:
case Bytecodes.DSTORE_2:
2014-11-27 12:15:46 +03:00
frame.setLocal(2, stack.pop2());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LSTORE_3:
case Bytecodes.DSTORE_3:
2014-11-27 12:15:46 +03:00
frame.setLocal(3, stack.pop2());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IASTORE:
case Bytecodes.FASTORE:
case Bytecodes.BASTORE:
case Bytecodes.CASTORE:
case Bytecodes.SASTORE:
2014-11-27 12:15:46 +03:00
var val = stack.pop();
var idx = stack.pop();
var refArray = stack.pop();
checkArrayAccess(refArray, idx);
refArray[idx] = val;
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LASTORE:
case Bytecodes.DASTORE:
2014-11-27 12:15:46 +03:00
var val = stack.pop2();
var idx = stack.pop();
var refArray = stack.pop();
checkArrayAccess(refArray, idx);
refArray[idx] = val;
traceArrayStore(idx, refArray, val);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.AASTORE:
2014-11-27 12:15:46 +03:00
var val = stack.pop();
var idx = stack.pop();
var refArray = stack.pop();
checkArrayAccess(refArray, idx);
if (val && !isAssignableTo(val.klass, refArray.klass.elementKlass)) {
ctx.raiseExceptionAndYield("java/lang/ArrayStoreException");
}
refArray[idx] = val;
traceArrayStore(idx, refArray, val);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.POP:
2014-11-27 12:15:46 +03:00
stack.pop();
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.POP2:
2014-11-27 12:15:46 +03:00
stack.pop2();
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.DUP:
2014-11-27 12:15:46 +03:00
var val = stack.pop();
stack.push(val);
stack.push(val);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.DUP_X1:
2014-11-27 12:15:46 +03:00
var a = stack.pop();
var b = stack.pop();
stack.push(a);
stack.push(b);
stack.push(a);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.DUP_X2:
2014-11-27 12:15:46 +03:00
var a = stack.pop();
var b = stack.pop();
var c = stack.pop();
stack.push(a);
stack.push(c);
stack.push(b);
stack.push(a);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.DUP2:
2014-11-27 12:15:46 +03:00
var a = stack.pop();
var b = stack.pop();
stack.push(b);
stack.push(a);
stack.push(b);
stack.push(a);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.DUP2_X1:
2014-11-27 12:15:46 +03:00
var a = stack.pop();
var b = stack.pop();
var c = stack.pop();
stack.push(b);
stack.push(a);
stack.push(c);
stack.push(b);
stack.push(a);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.DUP2_X2:
2014-11-27 12:15:46 +03:00
var a = stack.pop();
var b = stack.pop();
var c = stack.pop();
var d = stack.pop();
stack.push(b);
stack.push(a);
stack.push(d);
stack.push(c);
stack.push(b);
stack.push(a);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.SWAP:
2014-11-27 12:15:46 +03:00
var a = stack.pop();
var b = stack.pop();
stack.push(a);
stack.push(b);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IINC:
2014-11-27 12:15:46 +03:00
var idx = frame.read8();
var val = frame.read8signed();
frame.setLocal(idx, frame.getLocal(idx) + val);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IADD:
2014-11-27 12:15:46 +03:00
stack.push((stack.pop() + stack.pop())|0);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LADD:
2014-11-27 12:15:46 +03:00
stack.push2(stack.pop2().add(stack.pop2()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.FADD:
2014-11-27 12:15:46 +03:00
stack.push(Math.fround(stack.pop() + stack.pop()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.DADD:
2014-11-27 12:15:46 +03:00
stack.push2(stack.pop2() + stack.pop2());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ISUB:
2014-11-27 12:15:46 +03:00
stack.push((- stack.pop() + stack.pop())|0);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LSUB:
2014-11-27 12:15:46 +03:00
stack.push2(stack.pop2().negate().add(stack.pop2()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.FSUB:
2014-11-27 12:15:46 +03:00
stack.push(Math.fround(- stack.pop() + stack.pop()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.DSUB:
2014-11-27 12:15:46 +03:00
stack.push2(- stack.pop2() + stack.pop2());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IMUL:
2014-11-27 12:15:46 +03:00
stack.push(Math.imul(stack.pop(), stack.pop()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LMUL:
2014-11-27 12:15:46 +03:00
stack.push2(stack.pop2().multiply(stack.pop2()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.FMUL:
2014-11-27 12:15:46 +03:00
stack.push(Math.fround(stack.pop() * stack.pop()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.DMUL:
2014-11-27 12:15:46 +03:00
stack.push2(stack.pop2() * stack.pop2());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IDIV:
2014-11-27 12:15:46 +03:00
var b = stack.pop();
var a = stack.pop();
if (!b) {
ctx.raiseExceptionAndYield("java/lang/ArithmeticException", "/ by zero");
}
stack.push((a === util.INT_MIN && b === -1) ? a : ((a / b)|0));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LDIV:
2014-11-27 12:15:46 +03:00
var b = stack.pop2();
var a = stack.pop2();
if (b.isZero()) {
ctx.raiseExceptionAndYield("java/lang/ArithmeticException", "/ by zero");
}
stack.push2(a.div(b));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.FDIV:
2014-11-27 12:15:46 +03:00
var b = stack.pop();
var a = stack.pop();
stack.push(Math.fround(a / b));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.DDIV:
2014-11-27 12:15:46 +03:00
var b = stack.pop2();
var a = stack.pop2();
stack.push2(a / b);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IREM:
2014-11-27 12:15:46 +03:00
var b = stack.pop();
var a = stack.pop();
if (!b) {
ctx.raiseExceptionAndYield("java/lang/ArithmeticException", "/ by zero");
}
stack.push(a % b);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LREM:
2014-11-27 12:15:46 +03:00
var b = stack.pop2();
var a = stack.pop2();
if (b.isZero()) {
ctx.raiseExceptionAndYield("java/lang/ArithmeticException", "/ by zero");
}
stack.push2(a.modulo(b));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.FREM:
2014-11-27 12:15:46 +03:00
var b = stack.pop();
var a = stack.pop();
stack.push(Math.fround(a % b));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.DREM:
2014-11-27 12:15:46 +03:00
var b = stack.pop2();
var a = stack.pop2();
stack.push2(a % b);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.INEG:
2014-11-27 12:15:46 +03:00
stack.push((- stack.pop())|0);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LNEG:
2014-11-27 12:15:46 +03:00
stack.push2(stack.pop2().negate());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.FNEG:
2014-11-27 12:15:46 +03:00
stack.push(- stack.pop());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.DNEG:
2014-11-27 12:15:46 +03:00
stack.push2(- stack.pop2());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ISHL:
2014-11-27 12:15:46 +03:00
var b = stack.pop();
var a = stack.pop();
stack.push(a << b);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LSHL:
2014-11-27 12:15:46 +03:00
var b = stack.pop();
var a = stack.pop2();
stack.push2(a.shiftLeft(b));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ISHR:
2014-11-27 12:15:46 +03:00
var b = stack.pop();
var a = stack.pop();
stack.push(a >> b);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LSHR:
2014-11-27 12:15:46 +03:00
var b = stack.pop();
var a = stack.pop2();
stack.push2(a.shiftRight(b));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IUSHR:
2014-11-27 12:15:46 +03:00
var b = stack.pop();
var a = stack.pop();
stack.push(a >>> b);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LUSHR:
2014-11-27 12:15:46 +03:00
var b = stack.pop();
var a = stack.pop2();
stack.push2(a.shiftRightUnsigned(b));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IAND:
2014-11-27 12:15:46 +03:00
stack.push(stack.pop() & stack.pop());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LAND:
2014-11-27 12:15:46 +03:00
stack.push2(stack.pop2().and(stack.pop2()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IOR:
2014-11-27 12:15:46 +03:00
stack.push(stack.pop() | stack.pop());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LOR:
2014-11-27 12:15:46 +03:00
stack.push2(stack.pop2().or(stack.pop2()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IXOR:
2014-11-27 12:15:46 +03:00
stack.push(stack.pop() ^ stack.pop());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LXOR:
2014-11-27 12:15:46 +03:00
stack.push2(stack.pop2().xor(stack.pop2()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LCMP:
2014-11-27 12:15:46 +03:00
var b = stack.pop2();
var a = stack.pop2();
if (a.greaterThan(b)) {
stack.push(1);
} else if (a.lessThan(b)) {
stack.push(-1);
} else {
stack.push(0);
}
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.FCMPL:
2014-11-27 12:15:46 +03:00
var b = stack.pop();
var a = stack.pop();
if (isNaN(a) || isNaN(b)) {
stack.push(-1);
} else if (a > b) {
stack.push(1);
} else if (a < b) {
stack.push(-1);
} else {
stack.push(0);
}
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.FCMPG:
2014-11-27 12:15:46 +03:00
var b = stack.pop();
var a = stack.pop();
if (isNaN(a) || isNaN(b)) {
stack.push(1);
} else if (a > b) {
stack.push(1);
} else if (a < b) {
stack.push(-1);
} else {
stack.push(0);
}
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.DCMPL:
2014-11-27 12:15:46 +03:00
var b = stack.pop2();
var a = stack.pop2();
if (isNaN(a) || isNaN(b)) {
stack.push(-1);
} else if (a > b) {
stack.push(1);
} else if (a < b) {
stack.push(-1);
} else {
stack.push(0);
}
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.DCMPG:
2014-11-27 12:15:46 +03:00
var b = stack.pop2();
var a = stack.pop2();
if (isNaN(a) || isNaN(b)) {
stack.push(1);
} else if (a > b) {
stack.push(1);
} else if (a < b) {
stack.push(-1);
} else {
stack.push(0);
}
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IFEQ:
2014-12-01 20:47:42 +03:00
var jmp = frame.bci - 1 + frame.read16signed();
frame.bci = stack.pop() === 0 ? jmp : frame.bci;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IFNE:
2014-12-01 20:47:42 +03:00
var jmp = frame.bci - 1 + frame.read16signed();
frame.bci = stack.pop() !== 0 ? jmp : frame.bci;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IFLT:
2014-12-01 20:47:42 +03:00
var jmp = frame.bci - 1 + frame.read16signed();
frame.bci = stack.pop() < 0 ? jmp : frame.bci;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IFGE:
2014-12-01 20:47:42 +03:00
var jmp = frame.bci - 1 + frame.read16signed();
frame.bci = stack.pop() >= 0 ? jmp : frame.bci;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IFGT:
2014-12-01 20:47:42 +03:00
var jmp = frame.bci - 1 + frame.read16signed();
frame.bci = stack.pop() > 0 ? jmp : frame.bci;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IFLE:
2014-12-01 20:47:42 +03:00
var jmp = frame.bci - 1 + frame.read16signed();
frame.bci = stack.pop() <= 0 ? jmp : frame.bci;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IF_ICMPEQ:
2014-12-01 20:47:42 +03:00
var jmp = frame.bci - 1 + frame.read16signed();
frame.bci = stack.pop() === stack.pop() ? jmp : frame.bci;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IF_ICMPNE:
2014-12-01 20:47:42 +03:00
var jmp = frame.bci - 1 + frame.read16signed();
frame.bci = stack.pop() !== stack.pop() ? jmp : frame.bci;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IF_ICMPLT:
2014-12-01 20:47:42 +03:00
var jmp = frame.bci - 1 + frame.read16signed();
frame.bci = stack.pop() > stack.pop() ? jmp : frame.bci;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IF_ICMPGE:
2014-12-01 20:47:42 +03:00
var jmp = frame.bci - 1 + frame.read16signed();
frame.bci = stack.pop() <= stack.pop() ? jmp : frame.bci;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IF_ICMPGT:
2014-12-01 20:47:42 +03:00
var jmp = frame.bci - 1 + frame.read16signed();
frame.bci = stack.pop() < stack.pop() ? jmp : frame.bci;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IF_ICMPLE:
2014-12-01 20:47:42 +03:00
var jmp = frame.bci - 1 + frame.read16signed();
frame.bci = stack.pop() >= stack.pop() ? jmp : frame.bci;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IF_ACMPEQ:
2014-12-01 20:47:42 +03:00
var jmp = frame.bci - 1 + frame.read16signed();
frame.bci = stack.pop() === stack.pop() ? jmp : frame.bci;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IF_ACMPNE:
2014-12-01 20:47:42 +03:00
var jmp = frame.bci - 1 + frame.read16signed();
frame.bci = stack.pop() !== stack.pop() ? jmp : frame.bci;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IFNULL:
2014-12-01 20:47:42 +03:00
var jmp = frame.bci - 1 + frame.read16signed();
frame.bci = !stack.pop() ? jmp : frame.bci;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IFNONNULL:
2014-12-01 20:47:42 +03:00
var jmp = frame.bci - 1 + frame.read16signed();
frame.bci = stack.pop() ? jmp : frame.bci;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.GOTO:
2014-12-01 20:47:42 +03:00
frame.bci += frame.read16signed() - 1;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.GOTO_W:
2014-12-01 20:47:42 +03:00
frame.bci += frame.read32signed() - 1;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.JSR:
2014-11-27 12:15:46 +03:00
var jmp = frame.read16();
2014-12-01 20:47:42 +03:00
stack.push(frame.bci);
frame.bci = jmp;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.JSR_W:
2014-11-27 12:15:46 +03:00
var jmp = frame.read32();
2014-12-01 20:47:42 +03:00
stack.push(frame.bci);
frame.bci = jmp;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.RET:
2014-12-01 20:47:42 +03:00
frame.bci = frame.getLocal(frame.read8());
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.I2L:
2014-11-27 12:15:46 +03:00
stack.push2(Long.fromInt(stack.pop()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.I2F:
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.I2D:
2014-11-27 12:15:46 +03:00
stack.push2(stack.pop());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.L2I:
2014-11-27 12:15:46 +03:00
stack.push(stack.pop2().toInt());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.L2F:
2014-11-27 12:15:46 +03:00
stack.push(Math.fround(stack.pop2().toNumber()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.L2D:
2014-11-27 12:15:46 +03:00
stack.push2(stack.pop2().toNumber());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.F2I:
2014-11-27 12:15:46 +03:00
stack.push(util.double2int(stack.pop()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.F2L:
2014-11-27 12:15:46 +03:00
stack.push2(Long.fromNumber(stack.pop()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.F2D:
2014-11-27 12:15:46 +03:00
stack.push2(stack.pop());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.D2I:
2014-11-27 12:15:46 +03:00
stack.push(util.double2int(stack.pop2()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.D2L:
2014-11-27 12:15:46 +03:00
stack.push2(util.double2long(stack.pop2()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.D2F:
2014-11-27 12:15:46 +03:00
stack.push(Math.fround(stack.pop2()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.I2B:
2014-11-27 12:15:46 +03:00
stack.push((stack.pop() << 24) >> 24);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.I2C:
2014-11-27 12:15:46 +03:00
stack.push(stack.pop() & 0xffff);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.I2S:
2014-11-27 12:15:46 +03:00
stack.push((stack.pop() << 16) >> 16);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.TABLESWITCH:
2014-12-01 20:47:42 +03:00
var startip: number = frame.bci;
while ((frame.bci & 3) != 0)
frame.bci++;
2014-11-27 12:15:46 +03:00
var def = frame.read32signed();
var low = frame.read32signed();
var high = frame.read32signed();
var val = stack.pop();
var jmp;
if (val < low || val > high) {
jmp = def;
} else {
2014-12-01 20:47:42 +03:00
frame.bci += (val - low) << 2;
2014-11-27 12:15:46 +03:00
jmp = frame.read32signed();
}
2014-12-01 20:47:42 +03:00
frame.bci = startip - 1 + jmp;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LOOKUPSWITCH:
2014-12-01 20:47:42 +03:00
var startip: number = frame.bci;
while ((frame.bci & 3) != 0)
frame.bci++;
2014-11-27 12:15:46 +03:00
var jmp = frame.read32signed();
var size = frame.read32();
var val = frame.stack.pop();
lookup:
for (var i=0; i<size; i++) {
var key = frame.read32signed();
var offset = frame.read32signed();
if (key === val) {
jmp = offset;
}
if (key >= val) {
break lookup;
}
}
2014-12-01 20:47:42 +03:00
frame.bci = startip - 1 + jmp;
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.NEWARRAY:
2014-11-27 12:15:46 +03:00
var type = frame.read8();
var size = stack.pop();
if (size < 0) {
ctx.raiseExceptionAndYield("java/lang/NegativeArraySizeException", size);
}
stack.push(util.newPrimitiveArray("????ZCFDBSIJ"[type], size));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ANEWARRAY:
2014-11-27 12:15:46 +03:00
var idx = frame.read16();
var classInfo = cp[idx];
if (classInfo.tag)
classInfo = resolve(idx);
var size = stack.pop();
if (size < 0) {
ctx.raiseExceptionAndYield("java/lang/NegativeArraySizeException", size);
}
stack.push(util.newArray(classInfo, size));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.MULTIANEWARRAY:
2014-11-27 12:15:46 +03:00
var idx = frame.read16();
var classInfo = cp[idx];
if (classInfo.tag)
classInfo = resolve(idx);
var dimensions = frame.read8();
var lengths = new Array(dimensions);
for (var i=0; i<dimensions; i++)
lengths[i] = stack.pop();
stack.push(util.newMultiArray(classInfo, lengths.reverse()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ARRAYLENGTH:
2014-11-27 12:15:46 +03:00
var obj = stack.pop();
if (!obj) {
ctx.raiseExceptionAndYield("java/lang/NullPointerException");
}
stack.push(obj.length);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.GETFIELD:
2014-11-27 12:15:46 +03:00
var idx = frame.read16();
var field = cp[idx];
if (field.tag)
field = resolve(idx, false);
var obj = stack.pop();
if (!obj) {
ctx.raiseExceptionAndYield("java/lang/NullPointerException");
}
stack.pushType(field.signature, field.get(obj));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.PUTFIELD:
2014-11-27 12:15:46 +03:00
var idx = frame.read16();
var field = cp[idx];
if (field.tag)
field = resolve(idx, false);
var val = stack.popType(field.signature);
var obj = stack.pop();
if (!obj) {
ctx.raiseExceptionAndYield("java/lang/NullPointerException");
}
field.set(obj, val);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.GETSTATIC:
2014-11-27 12:15:46 +03:00
var idx = frame.read16();
var field = cp[idx];
if (field.tag)
field = resolve(idx, true);
2014-12-01 20:47:42 +03:00
classInitCheck(field.classInfo, frame.bci-3);
var value = field.getStatic();
2014-11-27 12:15:46 +03:00
if (typeof value === "undefined") {
value = util.defaultValue(field.signature);
}
stack.pushType(field.signature, value);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.PUTSTATIC:
2014-11-27 12:15:46 +03:00
var idx = frame.read16();
var field = cp[idx];
if (field.tag)
field = resolve(idx, true);
2014-12-01 20:47:42 +03:00
classInitCheck(field.classInfo, frame.bci-3);
field.setStatic(stack.popType(field.signature));
2014-11-27 12:15:46 +03:00
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.NEW:
2014-11-27 12:15:46 +03:00
var idx = frame.read16();
var classInfo = cp[idx];
if (classInfo.tag)
classInfo = resolve(idx);
2014-12-01 20:47:42 +03:00
classInitCheck(classInfo, frame.bci-3);
2014-11-27 12:15:46 +03:00
stack.push(util.newObject(classInfo));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.CHECKCAST:
2014-11-27 12:15:46 +03:00
var idx = frame.read16();
var classInfo = cp[idx];
if (classInfo.tag)
classInfo = resolve(idx);
var obj = stack[stack.length - 1];
if (obj && !isAssignableTo(obj.klass, classInfo.klass)) {
ctx.raiseExceptionAndYield("java/lang/ClassCastException",
obj.klass.classInfo.className + " is not assignable to " +
classInfo.className);
}
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.INSTANCEOF:
2014-11-27 12:15:46 +03:00
var idx = frame.read16();
var classInfo = cp[idx];
if (classInfo.tag)
classInfo = resolve(idx);
var obj = stack.pop();
var result = !obj ? false : isAssignableTo(obj.klass, classInfo.klass);
stack.push(result ? 1 : 0);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ATHROW:
2014-11-27 12:15:46 +03:00
if (ctx.frameSets.length > 0) {
// Compiled code can't handle exceptions, so throw a yield to make all the compiled code bailout.
2014-12-01 20:47:42 +03:00
frame.bci--;
2014-11-27 12:15:46 +03:00
throw VM.Yield;
}
var obj = stack.pop();
if (!obj) {
ctx.raiseExceptionAndYield("java/lang/NullPointerException");
}
throw_(obj, ctx);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.MONITORENTER:
2014-11-27 12:15:46 +03:00
var obj = stack.pop();
if (!obj) {
ctx.raiseExceptionAndYield("java/lang/NullPointerException");
}
ctx.monitorEnter(obj);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.MONITOREXIT:
2014-11-27 12:15:46 +03:00
var obj = stack.pop();
if (!obj) {
ctx.raiseExceptionAndYield("java/lang/NullPointerException");
}
ctx.monitorExit(obj);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.WIDE:
2014-11-27 12:15:46 +03:00
switch (op = frame.read8()) {
2014-11-27 12:32:07 +03:00
case Bytecodes.ILOAD:
case Bytecodes.FLOAD:
case Bytecodes.ALOAD:
2014-11-27 12:15:46 +03:00
stack.push(frame.getLocal(frame.read16()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LLOAD:
case Bytecodes.DLOAD:
2014-11-27 12:15:46 +03:00
stack.push2(frame.getLocal(frame.read16()));
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.ISTORE:
case Bytecodes.FSTORE:
case Bytecodes.ASTORE:
2014-11-27 12:15:46 +03:00
frame.setLocal(frame.read16(), stack.pop());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LSTORE:
case Bytecodes.DSTORE:
2014-11-27 12:15:46 +03:00
frame.setLocal(frame.read16(), stack.pop2());
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IINC:
2014-11-27 12:15:46 +03:00
var idx = frame.read16();
var val = frame.read16signed();
frame.setLocal(idx, frame.getLocal(idx) + val);
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.RET:
2014-12-01 20:47:42 +03:00
frame.bci = frame.getLocal(frame.read16());
2014-11-27 12:15:46 +03:00
break;
default:
var opName = Bytecodes[op];
throw new Error("Wide opcode " + opName + " [" + op + "] not supported.");
}
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.INVOKEVIRTUAL:
case Bytecodes.INVOKESPECIAL:
case Bytecodes.INVOKESTATIC:
case Bytecodes.INVOKEINTERFACE:
2014-12-01 20:47:42 +03:00
var startip: number = frame.bci - 1;
2014-11-27 12:15:46 +03:00
var idx = frame.read16();
if (op === 0xb9) {
var argsNumber = frame.read8();
var zero = frame.read8();
}
var isStatic = (op === 0xb8);
var methodInfo = cp[idx];
if (methodInfo.tag) {
methodInfo = resolve(idx, isStatic);
if (isStatic)
classInitCheck(methodInfo.classInfo, startip);
}
var obj = null;
var fn;
if (!isStatic) {
obj = stack[stack.length - methodInfo.consumes];
if (!obj) {
ctx.raiseExceptionAndYield("java/lang/NullPointerException");
}
switch (op) {
case Bytecodes.INVOKEVIRTUAL:
case Bytecodes.INVOKEINTERFACE:
fn = obj[methodInfo.mangledName];
break;
case Bytecodes.INVOKESPECIAL:
fn = jsGlobal[methodInfo.mangledClassAndMethodName];
break;
}
} else {
fn = jsGlobal[methodInfo.mangledClassAndMethodName];
}
// Take off the arguments from the stack.
var args = stack.slice(stack.length - methodInfo.consumes + (obj ? 1 : 0));
stack.length -= methodInfo.consumes;
// Invoke the compiled function.
var returnValue = fn.apply(obj, args);
// Push return value back on the stack.
var returnType = methodInfo.signature[methodInfo.signature.length - 1];
var isArrayReturnType = methodInfo.signature[methodInfo.signature.length - 2] === "[";
if (isArrayReturnType) {
stack.push(returnValue);
} else {
switch (returnType) {
case 'V':
break;
case 'J':
case 'D':
stack.push2(returnValue);
break;
default:
stack.push(returnValue);
break;
}
2014-11-27 12:15:46 +03:00
}
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.RETURN:
2014-11-27 12:15:46 +03:00
var shouldReturn = popFrame(0);
if (shouldReturn) {
return returnValue;
}
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.IRETURN:
case Bytecodes.FRETURN:
case Bytecodes.ARETURN:
2014-11-27 12:15:46 +03:00
var shouldReturn = popFrame(1);
if (shouldReturn) {
return returnValue;
}
break;
2014-11-27 12:32:07 +03:00
case Bytecodes.LRETURN:
case Bytecodes.DRETURN:
2014-11-27 12:15:46 +03:00
var shouldReturn = popFrame(2);
if (shouldReturn) {
return returnValue;
}
break;
default:
var opName = Bytecodes[op];
throw new Error("Opcode " + opName + " [" + op + "] not supported.");
}
}
}
export class VM {
static execute = interpret;
static Yield = {};
static Pause = {};
static DEBUG = false;
static DEBUG_PRINT_ALL_EXCEPTIONS = false;
}
}
var VM = J2ME.VM;