2015-04-30 19:51:47 +03:00
|
|
|
module J2ME {
|
2015-05-05 05:46:26 +03:00
|
|
|
|
2015-05-08 01:17:05 +03:00
|
|
|
declare var ASM;
|
|
|
|
|
2015-05-05 05:46:26 +03:00
|
|
|
import assert = Debug.assert;
|
2015-04-30 19:51:47 +03:00
|
|
|
import Bytecodes = Bytecode.Bytecodes;
|
|
|
|
import toHEX = IntegerUtilities.toHEX;
|
|
|
|
|
2015-05-08 03:31:22 +03:00
|
|
|
var buffer = ASM.buffer;
|
2015-04-30 19:51:47 +03:00
|
|
|
|
2015-05-08 03:31:22 +03:00
|
|
|
var i32: Int32Array = ASM.HEAP32;
|
|
|
|
var u32: Uint32Array = ASM.HEAPU32;
|
|
|
|
var f32: Float32Array = ASM.HEAPF32;
|
|
|
|
var ref = ArrayUtilities.makeDenseArray(buffer.byteLength >> 2, null);
|
2015-04-30 19:51:47 +03:00
|
|
|
|
2015-05-08 01:17:05 +03:00
|
|
|
function toName(o) {
|
|
|
|
if (o instanceof MethodInfo) {
|
|
|
|
return o.implKey;
|
|
|
|
}
|
|
|
|
if (o && o.klass === Klasses.java.lang.Class) {
|
|
|
|
return "[" + fromUTF8(o.klass.classInfo.utf8Name) + "] " + o.runtimeKlass.templateKlass.classInfo.getClassNameSlow();
|
|
|
|
}
|
|
|
|
if (o && o.klass === Klasses.java.lang.String) {
|
|
|
|
return "[" + fromUTF8(o.klass.classInfo.utf8Name) + "] \"" + fromJavaString(o) + "\"";
|
|
|
|
}
|
|
|
|
return o ? ("[" + fromUTF8(o.klass.classInfo.utf8Name) + "]") : "null";
|
|
|
|
}
|
|
|
|
|
2015-05-08 03:31:22 +03:00
|
|
|
/**
|
|
|
|
* The number of opcodes executed thus far.
|
|
|
|
*/
|
|
|
|
export var bytecodeCount = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The number of times the interpreter method was called thus far.
|
|
|
|
*/
|
|
|
|
export var interpreterCount = 0;
|
|
|
|
|
|
|
|
export var onStackReplacementCount = 0;
|
|
|
|
|
2015-04-30 19:51:47 +03:00
|
|
|
/*
|
2015-05-06 11:26:46 +03:00
|
|
|
* +--------------------------------+
|
|
|
|
* | Parameter 0 |
|
|
|
|
* +--------------------------------+
|
|
|
|
* | ... |
|
|
|
|
* +--------------------------------+
|
|
|
|
* | Parameter (P-1) |
|
|
|
|
* +--------------------------------+
|
2015-04-30 19:51:47 +03:00
|
|
|
* | Non-Parameter Local 0 |
|
|
|
|
* +--------------------------------+
|
|
|
|
* | ... |
|
|
|
|
* +--------------------------------+
|
|
|
|
* | Non-Parameter Local (L-1) |
|
2015-05-06 11:26:46 +03:00
|
|
|
* FP ---> +--------------------------------+
|
|
|
|
* | Caller Return Address |
|
|
|
|
* +--------------------------------+
|
|
|
|
* | Caller FP |
|
|
|
|
* +--------------------------------+
|
|
|
|
* | Callee Method Info |
|
2015-04-30 19:51:47 +03:00
|
|
|
* +--------------------------------+
|
|
|
|
* | Stack slot 0 |
|
|
|
|
* +--------------------------------+
|
|
|
|
* | ... |
|
|
|
|
* +--------------------------------+
|
|
|
|
* | Stack slot (S-1) |
|
|
|
|
* SP ---> +--------------------------------+
|
|
|
|
*/
|
|
|
|
|
|
|
|
enum FrameLayout {
|
2015-05-06 11:26:46 +03:00
|
|
|
CalleeMethodInfoOffset = 2,
|
|
|
|
CallerFPOffset = 1,
|
|
|
|
CallerRAOffset = 0,
|
|
|
|
CallerSaveSize = 3
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
export class FrameView {
|
|
|
|
public fp: number;
|
|
|
|
public sp: number;
|
|
|
|
public pc: number;
|
|
|
|
constructor() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
set(fp: number, sp: number, pc: number) {
|
|
|
|
this.fp = fp;
|
|
|
|
this.sp = sp;
|
|
|
|
this.pc = pc;
|
2015-05-05 05:46:26 +03:00
|
|
|
|
|
|
|
if (!release) {
|
2015-05-08 03:31:22 +03:00
|
|
|
var callee = ref[this.fp + FrameLayout.CalleeMethodInfoOffset];
|
2015-05-05 05:46:26 +03:00
|
|
|
assert(
|
|
|
|
callee === null ||
|
|
|
|
callee instanceof MethodInfo,
|
2015-05-08 01:17:05 +03:00
|
|
|
"Callee @" + (this.fp + FrameLayout.CalleeMethodInfoOffset) + " is not a MethodInfo, " + toName(callee)
|
2015-05-05 05:46:26 +03:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setParameter(kind: Kind, i: number, v: any) {
|
|
|
|
switch (kind) {
|
|
|
|
case Kind.Reference:
|
2015-05-08 03:31:22 +03:00
|
|
|
ref[this.fp + this.parameterOffset + i] = v;
|
2015-05-05 05:46:26 +03:00
|
|
|
break;
|
|
|
|
case Kind.Int:
|
2015-05-08 03:31:22 +03:00
|
|
|
i32[this.fp + this.parameterOffset + i] = v;
|
2015-05-05 05:46:26 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Debug.assert(false);
|
|
|
|
}
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
setParameterO4(v: Object, i: number) {
|
2015-05-06 11:26:46 +03:00
|
|
|
// traceWriter.writeLn("Set Parameter: " + i + ", from: " + toHEX(fp + this.parameterOffset + i));
|
2015-05-08 03:31:22 +03:00
|
|
|
ref[this.fp + this.parameterOffset + i] = v;
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
get methodInfo(): MethodInfo {
|
2015-05-08 03:31:22 +03:00
|
|
|
return ref[this.fp + FrameLayout.CalleeMethodInfoOffset];
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
set methodInfo(methodInfo: MethodInfo) {
|
2015-05-08 03:31:22 +03:00
|
|
|
ref[this.fp + FrameLayout.CalleeMethodInfoOffset] = methodInfo;
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
2015-05-06 11:26:46 +03:00
|
|
|
get parameterOffset() {
|
|
|
|
return this.methodInfo ? -this.methodInfo.codeAttribute.max_locals : 0;
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
2015-05-06 11:26:46 +03:00
|
|
|
get stackOffset(): number {
|
|
|
|
return FrameLayout.CallerSaveSize;
|
2015-05-05 05:46:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
traceStack(writer: IndentingWriter) {
|
|
|
|
var fp = this.fp;
|
|
|
|
var sp = this.sp;
|
|
|
|
var pc = this.pc;
|
|
|
|
while (this.fp > FrameLayout.CallerSaveSize) {
|
|
|
|
writer.writeLn((this.methodInfo ? this.methodInfo.implKey : "null") + ", FP: " + this.fp + ", SP: " + this.sp + ", PC: " + this.pc);
|
2015-05-08 03:31:22 +03:00
|
|
|
this.set(i32[this.fp + FrameLayout.CallerFPOffset],
|
2015-05-06 11:26:46 +03:00
|
|
|
this.fp + this.parameterOffset,
|
2015-05-08 03:31:22 +03:00
|
|
|
i32[this.fp + FrameLayout.CallerRAOffset]);
|
2015-05-05 05:46:26 +03:00
|
|
|
|
|
|
|
}
|
|
|
|
this.fp = fp;
|
|
|
|
this.sp = sp;
|
|
|
|
this.pc = pc;
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
trace(writer: IndentingWriter, fieldInfo: FieldInfo) {
|
|
|
|
function toNumber(v) {
|
|
|
|
if (v < 0) {
|
|
|
|
return String(v);
|
|
|
|
} else if (v === 0) {
|
|
|
|
return " 0";
|
|
|
|
} else {
|
|
|
|
return "+" + v;
|
|
|
|
}
|
|
|
|
}
|
2015-05-08 01:17:05 +03:00
|
|
|
|
2015-04-30 19:51:47 +03:00
|
|
|
var details = " ";
|
|
|
|
if (fieldInfo) {
|
2015-05-08 01:17:05 +03:00
|
|
|
details += "FieldInfo: " + fromUTF8(fieldInfo.utf8Name) + ", kind: " + Kind[fieldInfo.kind];
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
writer.writeLn("Frame: " + this.methodInfo.implKey + ", FP: " + this.fp + ", SP: " + this.sp + ", PC: " + this.pc + ", BC: " + Bytecodes[this.methodInfo.codeAttribute.code[this.pc]] + details);
|
2015-05-06 11:26:46 +03:00
|
|
|
for (var i = Math.max(0, this.fp + this.parameterOffset); i < this.sp; i++) {
|
2015-04-30 19:51:47 +03:00
|
|
|
var prefix = " ";
|
|
|
|
if (i >= this.fp + this.stackOffset) {
|
|
|
|
prefix = "S" + (i - (this.fp + this.stackOffset)) + ": ";
|
2015-05-05 05:46:26 +03:00
|
|
|
} else if (i === this.fp + FrameLayout.CalleeMethodInfoOffset) {
|
2015-04-30 19:51:47 +03:00
|
|
|
prefix = "MI: ";
|
2015-05-05 05:46:26 +03:00
|
|
|
} else if (i === this.fp + FrameLayout.CallerFPOffset) {
|
|
|
|
prefix = "CF: ";
|
|
|
|
} else if (i === this.fp + FrameLayout.CallerRAOffset) {
|
2015-04-30 19:51:47 +03:00
|
|
|
prefix = "RA: ";
|
2015-05-06 11:26:46 +03:00
|
|
|
} else if (i >= this.fp + this.parameterOffset) {
|
|
|
|
prefix = "L" + (i - (this.fp + this.parameterOffset)) + ": ";
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
2015-05-08 03:31:22 +03:00
|
|
|
writer.writeLn(" " + prefix + " " + toNumber(i - this.fp).padLeft(' ', 3) + " " + String(i).padLeft(' ', 4) + " " + toHEX(i << 2) + ": " +
|
|
|
|
String(i32[i]).padLeft(' ', 10) + " " +
|
|
|
|
toName(ref[i]));
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export class Thread {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Thread base pointer.
|
|
|
|
*/
|
|
|
|
tp: number;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stack base pointer.
|
|
|
|
*/
|
|
|
|
bp: number
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Current frame pointer.
|
|
|
|
*/
|
|
|
|
fp: number
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Current stack pointer.
|
|
|
|
*/
|
|
|
|
sp: number
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Current program counter.
|
|
|
|
*/
|
|
|
|
pc: number
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Context associated with this thread.
|
|
|
|
*/
|
|
|
|
ctx: Context;
|
|
|
|
|
2015-05-05 05:46:26 +03:00
|
|
|
view: FrameView;
|
|
|
|
|
2015-04-30 19:51:47 +03:00
|
|
|
constructor(ctx: Context) {
|
2015-05-08 03:31:22 +03:00
|
|
|
this.tp = ASM._malloc(1024 * 128);
|
2015-05-05 05:46:26 +03:00
|
|
|
this.bp = this.tp;
|
2015-05-06 11:26:46 +03:00
|
|
|
this.fp = this.bp;
|
|
|
|
this.sp = this.fp;
|
2015-05-05 05:46:26 +03:00
|
|
|
this.pc = -1;
|
|
|
|
this.view = new FrameView();
|
2015-04-30 19:51:47 +03:00
|
|
|
this.ctx = ctx;
|
|
|
|
}
|
2015-05-05 05:46:26 +03:00
|
|
|
|
|
|
|
set(fp: number, sp: number, pc: number) {
|
|
|
|
this.fp = fp;
|
|
|
|
this.sp = sp;
|
|
|
|
this.pc = pc;
|
|
|
|
}
|
|
|
|
|
2015-05-06 11:26:46 +03:00
|
|
|
get frame(): FrameView {
|
2015-05-05 05:46:26 +03:00
|
|
|
this.view.set(this.fp, this.sp, this.pc);
|
|
|
|
return this.view;
|
|
|
|
}
|
|
|
|
|
|
|
|
pushFrame(methodInfo: MethodInfo) {
|
2015-05-06 11:26:46 +03:00
|
|
|
var fp = this.fp;
|
2015-05-05 05:46:26 +03:00
|
|
|
if (methodInfo) {
|
2015-05-06 11:26:46 +03:00
|
|
|
this.fp = this.sp + methodInfo.codeAttribute.max_locals;
|
|
|
|
} else {
|
|
|
|
this.fp = this.sp;
|
2015-05-05 05:46:26 +03:00
|
|
|
}
|
2015-05-06 11:26:46 +03:00
|
|
|
this.sp = this.fp;
|
2015-05-08 03:31:22 +03:00
|
|
|
i32[this.sp++] = this.pc; // Caller RA
|
|
|
|
i32[this.sp++] = fp; // Caller FP
|
|
|
|
ref[this.sp++] = methodInfo; // Callee
|
2015-05-05 05:46:26 +03:00
|
|
|
this.pc = 0;
|
|
|
|
}
|
|
|
|
|
2015-05-08 01:17:05 +03:00
|
|
|
popFrame(methodInfo: MethodInfo): MethodInfo {
|
2015-05-08 03:31:22 +03:00
|
|
|
var mi = ref[this.fp + FrameLayout.CalleeMethodInfoOffset];
|
2015-05-06 11:26:46 +03:00
|
|
|
release || assert(mi === methodInfo);
|
2015-05-08 03:31:22 +03:00
|
|
|
this.pc = i32[this.fp + FrameLayout.CallerRAOffset];
|
2015-05-06 11:26:46 +03:00
|
|
|
var maxLocals = mi ? mi.codeAttribute.max_locals : 0;
|
|
|
|
this.sp = this.fp - maxLocals;
|
2015-05-08 03:31:22 +03:00
|
|
|
this.fp = i32[this.fp + FrameLayout.CallerFPOffset];
|
|
|
|
return ref[this.fp + FrameLayout.CalleeMethodInfoOffset]
|
2015-05-05 05:46:26 +03:00
|
|
|
}
|
|
|
|
|
2015-05-06 11:26:46 +03:00
|
|
|
run() {
|
|
|
|
return interpret(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
tryCatch(e: java.lang.Exception) {
|
2015-05-08 01:17:05 +03:00
|
|
|
traceWriter && traceWriter.writeLn("tryCatch: " + toName(e));
|
|
|
|
var pc = -1;
|
2015-05-06 11:26:46 +03:00
|
|
|
var classInfo;
|
2015-05-08 03:31:22 +03:00
|
|
|
var mi = ref[this.fp + FrameLayout.CalleeMethodInfoOffset];
|
2015-05-08 01:17:05 +03:00
|
|
|
while (mi) {
|
|
|
|
traceWriter && traceWriter.writeLn(mi.implKey);
|
2015-05-06 11:26:46 +03:00
|
|
|
for (var i = 0; i < mi.exception_table_length; i++) {
|
|
|
|
var exceptionEntryView = mi.getExceptionEntryViewByIndex(i);
|
|
|
|
if (this.pc >= exceptionEntryView.start_pc && this.pc < exceptionEntryView.end_pc) {
|
|
|
|
if (exceptionEntryView.catch_type === 0) {
|
2015-05-08 01:17:05 +03:00
|
|
|
pc = exceptionEntryView.handler_pc;
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
classInfo = resolveClass(exceptionEntryView.catch_type, mi.classInfo);
|
|
|
|
if (isAssignableTo(e.klass, classInfo.klass)) {
|
2015-05-08 01:17:05 +03:00
|
|
|
pc = exceptionEntryView.handler_pc;
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-05-08 01:17:05 +03:00
|
|
|
if (pc >= 0) {
|
|
|
|
this.pc = pc;
|
|
|
|
this.sp = this.fp + FrameLayout.CallerSaveSize;
|
2015-05-08 03:31:22 +03:00
|
|
|
ref[this.sp++] = e;
|
2015-05-06 11:26:46 +03:00
|
|
|
return;
|
|
|
|
}
|
2015-05-08 01:17:05 +03:00
|
|
|
mi = this.popFrame(mi);
|
|
|
|
}
|
|
|
|
traceWriter && traceWriter.writeLn("Cannot catch: " + toName(e));
|
|
|
|
throw e;
|
2015-05-05 05:46:26 +03:00
|
|
|
}
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
2015-05-05 05:46:26 +03:00
|
|
|
export function prepareInterpretedMethod(methodInfo: MethodInfo): Function {
|
|
|
|
var method = function fastInterpreterFrameAdapter() {
|
|
|
|
var thread = $.ctx.nativeThread;
|
2015-05-08 01:17:05 +03:00
|
|
|
var fp = thread.fp;
|
|
|
|
traceWriter && traceWriter.writeLn(">> Interpreter Enter");
|
2015-05-05 05:46:26 +03:00
|
|
|
thread.pushFrame(null);
|
|
|
|
thread.pushFrame(methodInfo);
|
2015-05-06 11:26:46 +03:00
|
|
|
var frame = thread.frame;
|
2015-05-05 05:46:26 +03:00
|
|
|
var kinds = methodInfo.signatureKinds;
|
|
|
|
var index = 0;
|
|
|
|
if (!methodInfo.isStatic) {
|
2015-05-06 11:26:46 +03:00
|
|
|
frame.setParameter(Kind.Reference, index++, this);
|
2015-05-05 05:46:26 +03:00
|
|
|
}
|
|
|
|
for (var i = 1; i < kinds.length; i++) {
|
2015-05-06 11:26:46 +03:00
|
|
|
frame.setParameter(kinds[i], index++, arguments[i - 1]);
|
2015-05-05 05:46:26 +03:00
|
|
|
}
|
2015-05-08 01:17:05 +03:00
|
|
|
var v = interpret(thread);
|
|
|
|
release || assert(fp === thread.fp);
|
|
|
|
traceWriter && traceWriter.writeLn("<< Interpreter Exit");
|
|
|
|
return v;
|
2015-05-05 05:46:26 +03:00
|
|
|
};
|
|
|
|
(<any>method).methodInfo = methodInfo;
|
|
|
|
return method;
|
|
|
|
}
|
2015-04-30 19:51:47 +03:00
|
|
|
|
2015-05-05 05:46:26 +03:00
|
|
|
function resolveClass(index: number, classInfo: ClassInfo): ClassInfo {
|
|
|
|
var classInfo = classInfo.constantPool.resolveClass(index);
|
|
|
|
linkKlass(classInfo);
|
|
|
|
return classInfo;
|
|
|
|
}
|
|
|
|
|
2015-04-30 19:51:47 +03:00
|
|
|
export function interpret(thread: Thread) {
|
2015-05-06 11:26:46 +03:00
|
|
|
var frame = thread.frame;
|
|
|
|
|
|
|
|
var mi = frame.methodInfo;
|
2015-05-08 03:31:22 +03:00
|
|
|
var maxLocals = mi.codeAttribute.max_locals;
|
2015-04-30 19:51:47 +03:00
|
|
|
var ci = mi.classInfo;
|
|
|
|
var cp = ci.constantPool;
|
|
|
|
|
|
|
|
var code = mi ? mi.codeAttribute.code : null;
|
|
|
|
|
|
|
|
var fp = thread.fp;
|
|
|
|
var sp = thread.sp;
|
|
|
|
var pc = thread.pc;
|
|
|
|
|
2015-05-05 05:46:26 +03:00
|
|
|
var tag: TAGS;
|
2015-04-30 19:51:47 +03:00
|
|
|
var type, size;
|
2015-05-08 01:17:05 +03:00
|
|
|
var value, index, array, object, result, constant, targetPC, returnValue, kind;
|
2015-05-05 05:46:26 +03:00
|
|
|
|
|
|
|
|
|
|
|
var ia = 0, ib = 0; // Integer Operands
|
|
|
|
var fa = 0, fb = 0; // Float / Double Operands
|
2015-04-30 19:51:47 +03:00
|
|
|
|
2015-05-05 05:46:26 +03:00
|
|
|
var classInfo: ClassInfo;
|
|
|
|
var fieldInfo: FieldInfo;
|
2015-04-30 19:51:47 +03:00
|
|
|
|
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function popI32() {
|
|
|
|
return i32[--sp];
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function popF32() {
|
|
|
|
return f32[--sp];
|
2015-05-05 05:46:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function popF64() {
|
|
|
|
return --sp, f32[--sp];
|
2015-05-05 05:46:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function pushI32(v: number) {
|
|
|
|
i32[sp++] = v;
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function pushI64(h: number, l: number) {
|
|
|
|
i32[sp++] = h;
|
|
|
|
i32[sp++] = l;
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
2015-05-08 01:17:05 +03:00
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function pushF32(v: number) {
|
|
|
|
return f32[sp++];
|
2015-05-08 01:17:05 +03:00
|
|
|
}
|
|
|
|
|
2015-05-05 05:46:26 +03:00
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function loadW32(i: number) {
|
|
|
|
i32[sp++] = i32[fp + localFramePointerOffset(i)];
|
2015-05-05 05:46:26 +03:00
|
|
|
}
|
|
|
|
|
2015-05-08 01:17:05 +03:00
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function loadW64(i: number) {
|
2015-05-08 01:17:05 +03:00
|
|
|
var offset = localFramePointerOffset(i);
|
2015-05-08 03:31:22 +03:00
|
|
|
i32[sp++] = i32[fp + offset];
|
|
|
|
i32[sp++] = i32[fp + offset + 1];
|
2015-05-08 01:17:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function storeW32(i: number) {
|
|
|
|
i32[fp + localFramePointerOffset(i)] = i32[--sp];
|
2015-05-08 01:17:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function storeW64(i: number) {
|
2015-05-08 01:17:05 +03:00
|
|
|
var offset = localFramePointerOffset(i);
|
2015-05-08 03:31:22 +03:00
|
|
|
i32[fp + offset + 1] = i32[--sp];
|
|
|
|
i32[fp + offset] = i32[--sp];
|
2015-05-08 01:17:05 +03:00
|
|
|
}
|
|
|
|
|
2015-05-05 05:46:26 +03:00
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function pushF64(v: number) {
|
|
|
|
f32[sp++], sp++;
|
2015-05-05 05:46:26 +03:00
|
|
|
}
|
|
|
|
|
2015-04-30 19:51:47 +03:00
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function popRef() {
|
|
|
|
return ref[--sp];
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function pushRef(v: Object | java.lang.Object) {
|
|
|
|
ref[sp++] = v;
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
2015-05-08 01:17:05 +03:00
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function peekRef() {
|
|
|
|
return ref[sp - 1];
|
2015-05-08 01:17:05 +03:00
|
|
|
}
|
|
|
|
|
2015-04-30 19:51:47 +03:00
|
|
|
/** @inline */
|
|
|
|
function localFramePointerOffset(i: number) {
|
2015-05-08 03:31:22 +03:00
|
|
|
return -maxLocals + i;
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function getLocalRef(i: number) {
|
|
|
|
return ref[fp + localFramePointerOffset(i)];
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function setLocalRef(v: Object, i: number) {
|
|
|
|
ref[fp + localFramePointerOffset(i)] = v;
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function getLocalI32(i: number) {
|
|
|
|
return i32[fp + localFramePointerOffset(i)];
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
2015-05-08 01:17:05 +03:00
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function getLocalF32(i: number) {
|
|
|
|
return f32[fp + localFramePointerOffset(i)];
|
2015-05-08 01:17:05 +03:00
|
|
|
}
|
|
|
|
|
2015-04-30 19:51:47 +03:00
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function setLocalI32(v: number, i: number) {
|
|
|
|
i32[fp + localFramePointerOffset(i)] = v;
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
2015-05-08 01:17:05 +03:00
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function setLocalF32(v: number, i: number) {
|
|
|
|
f32[fp + localFramePointerOffset(i)] = v;
|
2015-05-08 01:17:05 +03:00
|
|
|
}
|
|
|
|
|
2015-04-30 19:51:47 +03:00
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function readI16() {
|
2015-04-30 19:51:47 +03:00
|
|
|
return (code[pc++] << 8 | code[pc++]) << 16 >> 16;
|
|
|
|
}
|
2015-05-08 01:17:05 +03:00
|
|
|
|
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function readI8() {
|
2015-05-08 01:17:05 +03:00
|
|
|
return code[pc++] << 24 >> 24;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function readU16() {
|
2015-05-08 01:17:05 +03:00
|
|
|
return code[pc++] << 8 | code[pc++];
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @inline */
|
2015-05-08 03:31:22 +03:00
|
|
|
function readU8() {
|
2015-05-08 01:17:05 +03:00
|
|
|
return code[pc++];
|
|
|
|
}
|
2015-05-05 05:46:26 +03:00
|
|
|
|
|
|
|
function saveThreadState() {
|
|
|
|
thread.fp = fp;
|
|
|
|
thread.sp = sp;
|
|
|
|
thread.pc = pc;
|
|
|
|
}
|
|
|
|
|
2015-05-08 01:17:05 +03:00
|
|
|
function saveThreadStateBefore() {
|
|
|
|
thread.fp = fp;
|
|
|
|
thread.sp = sp;
|
|
|
|
thread.pc = opPC;
|
|
|
|
}
|
|
|
|
|
2015-05-05 05:46:26 +03:00
|
|
|
function loadThreadState() {
|
|
|
|
fp = thread.fp;
|
|
|
|
sp = thread.sp;
|
|
|
|
pc = thread.pc;
|
|
|
|
}
|
2015-04-30 19:51:47 +03:00
|
|
|
|
|
|
|
/** @inline */
|
|
|
|
function readTargetPC() {
|
|
|
|
var offset = (code[pc] << 8 | code[pc + 1]) << 16 >> 16;
|
|
|
|
var target = pc - 1 + offset;
|
|
|
|
pc += 2;
|
|
|
|
return target;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @inline */
|
|
|
|
function popKind(kind: Kind) {
|
|
|
|
switch(kind) {
|
|
|
|
case Kind.Reference:
|
2015-05-08 03:31:22 +03:00
|
|
|
return ref[--sp];
|
2015-05-05 05:46:26 +03:00
|
|
|
case Kind.Int:
|
|
|
|
case Kind.Char:
|
|
|
|
case Kind.Short:
|
|
|
|
case Kind.Boolean:
|
2015-05-08 03:31:22 +03:00
|
|
|
return i32[--sp];
|
2015-05-05 05:46:26 +03:00
|
|
|
case Kind.Float:
|
2015-05-08 03:31:22 +03:00
|
|
|
return f32[--sp];
|
2015-05-08 01:17:05 +03:00
|
|
|
case Kind.Long:
|
|
|
|
case Kind.Double:
|
|
|
|
sp--;
|
2015-05-08 03:31:22 +03:00
|
|
|
return f32[--sp]; // REDUX:
|
2015-05-08 01:17:05 +03:00
|
|
|
case Kind.Void:
|
|
|
|
return;
|
2015-04-30 19:51:47 +03:00
|
|
|
default:
|
2015-05-05 05:46:26 +03:00
|
|
|
Debug.assert(false, "Cannot Pop Kind: " + Kind[kind]);
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-05 05:46:26 +03:00
|
|
|
var values = new Array(8);
|
|
|
|
|
2015-05-08 01:17:05 +03:00
|
|
|
function popArguments(mi: MethodInfo) {
|
|
|
|
var signatureKinds = mi.signatureKinds;
|
|
|
|
var args = [];
|
|
|
|
for (var i = signatureKinds.length - 1; i > 0; i--) {
|
|
|
|
var kind = signatureKinds[i];
|
|
|
|
if (isTwoSlot(kind)) {
|
|
|
|
args.unshift(undefined);
|
|
|
|
}
|
|
|
|
args.unshift(popKind(kind));
|
|
|
|
}
|
|
|
|
return args;
|
|
|
|
}
|
|
|
|
|
2015-05-05 05:46:26 +03:00
|
|
|
function popKinds(kinds: Kind [], offset: number) {
|
|
|
|
values.length = kinds.length - offset;
|
|
|
|
var j = 0;
|
|
|
|
for (var i = offset; i < kinds.length; i++) {
|
|
|
|
values[j++] = popKind(kinds[i]);
|
|
|
|
}
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
|
2015-04-30 19:51:47 +03:00
|
|
|
/** @inline */
|
|
|
|
function pushKind(kind: Kind, v: any) {
|
2015-05-06 11:26:46 +03:00
|
|
|
switch (kind) {
|
2015-04-30 19:51:47 +03:00
|
|
|
case Kind.Reference:
|
2015-05-08 03:31:22 +03:00
|
|
|
ref[sp++] = v;
|
2015-05-06 11:26:46 +03:00
|
|
|
return;
|
|
|
|
case Kind.Int:
|
|
|
|
case Kind.Char:
|
|
|
|
case Kind.Short:
|
|
|
|
case Kind.Boolean:
|
2015-05-08 03:31:22 +03:00
|
|
|
i32[sp++] = v;
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
case Kind.Float:
|
2015-05-08 03:31:22 +03:00
|
|
|
f32[sp++] = v;
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Kind.Long:
|
2015-04-30 19:51:47 +03:00
|
|
|
case Kind.Double:
|
2015-05-08 03:31:22 +03:00
|
|
|
f32[sp++] = v;
|
2015-05-06 11:26:46 +03:00
|
|
|
sp++;
|
|
|
|
break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Kind.Void:
|
|
|
|
break;
|
2015-04-30 19:51:47 +03:00
|
|
|
default:
|
2015-05-06 11:26:46 +03:00
|
|
|
Debug.assert(false, "Cannot Pop Kind: " + Kind[kind]);
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-08 01:17:05 +03:00
|
|
|
function classInitAndUnwindCheck(classInfo: ClassInfo, pc: number) {
|
|
|
|
saveThreadState();
|
|
|
|
classInitCheck(classInfo);
|
|
|
|
loadThreadState();
|
|
|
|
//if (U) {
|
|
|
|
// $.ctx.current().pc = pc;
|
|
|
|
// return;
|
|
|
|
//}
|
|
|
|
}
|
|
|
|
|
2015-04-30 19:51:47 +03:00
|
|
|
while (true) {
|
2015-05-05 05:46:26 +03:00
|
|
|
|
2015-05-08 01:17:05 +03:00
|
|
|
// saveThreadState();
|
|
|
|
// thread.frame.trace(traceWriter, null);
|
|
|
|
|
|
|
|
release || assert(code === mi.codeAttribute.code, "Bad Code.");
|
|
|
|
release || assert(ci === mi.classInfo, "Bad Class Info.");
|
|
|
|
release || assert(cp === ci.constantPool, "Bad Constant Pool.");
|
2015-05-05 05:46:26 +03:00
|
|
|
|
2015-04-30 19:51:47 +03:00
|
|
|
fieldInfo = null;
|
|
|
|
var opPC = pc;
|
|
|
|
var op = code[pc++];
|
|
|
|
|
2015-05-08 03:31:22 +03:00
|
|
|
// traceWriter.writeLn(bytecodeCount++ + " " + mi.implKey + ": PC: " + opPC + ", FP: " + fp + ", " + Bytecodes[op]);
|
2015-05-05 05:46:26 +03:00
|
|
|
|
2015-05-06 11:26:46 +03:00
|
|
|
try {
|
|
|
|
switch (op) {
|
|
|
|
case Bytecodes.NOP:
|
|
|
|
break;
|
|
|
|
case Bytecodes.ACONST_NULL:
|
2015-05-08 03:31:22 +03:00
|
|
|
ref[sp++] = null;
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.ICONST_M1:
|
|
|
|
case Bytecodes.ICONST_0:
|
|
|
|
case Bytecodes.ICONST_1:
|
|
|
|
case Bytecodes.ICONST_2:
|
|
|
|
case Bytecodes.ICONST_3:
|
|
|
|
case Bytecodes.ICONST_4:
|
|
|
|
case Bytecodes.ICONST_5:
|
2015-05-08 03:31:22 +03:00
|
|
|
pushI32(op - Bytecodes.ICONST_0);
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.FCONST_0:
|
|
|
|
case Bytecodes.FCONST_1:
|
|
|
|
case Bytecodes.FCONST_2:
|
2015-05-08 03:31:22 +03:00
|
|
|
pushI32(op - Bytecodes.FCONST_0);
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
// case Bytecodes.DCONST_0:
|
|
|
|
// case Bytecodes.DCONST_1:
|
|
|
|
// stack.push2(op - Bytecodes.DCONST_0);
|
|
|
|
// break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Bytecodes.LCONST_0:
|
|
|
|
case Bytecodes.LCONST_1:
|
2015-05-08 03:31:22 +03:00
|
|
|
pushI64(0, op - Bytecodes.LCONST_0);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
case Bytecodes.BIPUSH:
|
2015-05-08 03:31:22 +03:00
|
|
|
pushI32(code[pc++] << 24 >> 24);
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.SIPUSH:
|
2015-05-08 03:31:22 +03:00
|
|
|
pushI32(readI16());
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.LDC:
|
|
|
|
case Bytecodes.LDC_W:
|
2015-05-08 03:31:22 +03:00
|
|
|
index = (op === Bytecodes.LDC) ? code[pc++] : readI16();
|
2015-05-06 11:26:46 +03:00
|
|
|
tag = ci.constantPool.peekTag(index);
|
|
|
|
constant = ci.constantPool.resolve(index, tag, false);
|
|
|
|
if (tag === TAGS.CONSTANT_Integer) {
|
2015-05-08 03:31:22 +03:00
|
|
|
pushI32(constant);
|
2015-05-06 11:26:46 +03:00
|
|
|
} else if (tag === TAGS.CONSTANT_Float) {
|
2015-05-08 03:31:22 +03:00
|
|
|
pushF32(constant);
|
2015-05-06 11:26:46 +03:00
|
|
|
} else if (tag === TAGS.CONSTANT_String) {
|
2015-05-08 03:31:22 +03:00
|
|
|
pushRef(constant);
|
2015-05-06 11:26:46 +03:00
|
|
|
} else {
|
|
|
|
assert(false, TAGS[tag]);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.LDC2_W:
|
2015-05-08 03:31:22 +03:00
|
|
|
index = (op === Bytecodes.LDC) ? code[pc++] : readI16();
|
2015-05-06 11:26:46 +03:00
|
|
|
tag = ci.constantPool.peekTag(index);
|
|
|
|
constant = ci.constantPool.resolve(index, tag, false);
|
|
|
|
if (tag === TAGS.CONSTANT_Long) {
|
2015-05-08 03:31:22 +03:00
|
|
|
pushI32(constant);
|
2015-05-06 11:26:46 +03:00
|
|
|
} else if (tag === TAGS.CONSTANT_Double) {
|
2015-05-08 03:31:22 +03:00
|
|
|
pushF64(constant);
|
2015-05-06 11:26:46 +03:00
|
|
|
} else {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Bytecodes.ILOAD:
|
|
|
|
case Bytecodes.FLOAD:
|
2015-05-08 03:31:22 +03:00
|
|
|
loadW32(code[pc++]);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.ALOAD:
|
2015-05-08 03:31:22 +03:00
|
|
|
pushRef(getLocalRef(code[pc++]));
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.LLOAD:
|
|
|
|
case Bytecodes.DLOAD:
|
2015-05-08 03:31:22 +03:00
|
|
|
loadW64(code[pc++]);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.ILOAD_0:
|
|
|
|
case Bytecodes.ILOAD_1:
|
|
|
|
case Bytecodes.ILOAD_2:
|
|
|
|
case Bytecodes.ILOAD_3:
|
2015-05-08 03:31:22 +03:00
|
|
|
loadW32(op - Bytecodes.ILOAD_0);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.FLOAD_0:
|
|
|
|
case Bytecodes.FLOAD_1:
|
|
|
|
case Bytecodes.FLOAD_2:
|
|
|
|
case Bytecodes.FLOAD_3:
|
2015-05-08 03:31:22 +03:00
|
|
|
loadW32(op - Bytecodes.FLOAD_0);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
case Bytecodes.ALOAD_0:
|
|
|
|
case Bytecodes.ALOAD_1:
|
|
|
|
case Bytecodes.ALOAD_2:
|
|
|
|
case Bytecodes.ALOAD_3:
|
2015-05-08 03:31:22 +03:00
|
|
|
pushRef(getLocalRef(op - Bytecodes.ALOAD_0));
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Bytecodes.LLOAD_0:
|
|
|
|
case Bytecodes.LLOAD_1:
|
|
|
|
case Bytecodes.LLOAD_2:
|
|
|
|
case Bytecodes.LLOAD_3:
|
2015-05-08 03:31:22 +03:00
|
|
|
loadW64(op - Bytecodes.LLOAD_0);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.DLOAD_0:
|
|
|
|
case Bytecodes.DLOAD_1:
|
|
|
|
case Bytecodes.DLOAD_2:
|
|
|
|
case Bytecodes.DLOAD_3:
|
2015-05-08 03:31:22 +03:00
|
|
|
loadW64(op - Bytecodes.DLOAD_0);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.IALOAD:
|
2015-05-08 03:31:22 +03:00
|
|
|
index = popI32();
|
|
|
|
array = popRef();
|
|
|
|
checkArrayBounds(array, index);
|
|
|
|
pushI32(array[index]);
|
|
|
|
break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Bytecodes.BALOAD:
|
2015-05-08 03:31:22 +03:00
|
|
|
index = popI32();
|
|
|
|
array = popRef();
|
|
|
|
checkArrayBounds(array, index);
|
|
|
|
pushI32(array[index]);
|
|
|
|
break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Bytecodes.CALOAD:
|
2015-05-08 03:31:22 +03:00
|
|
|
index = popI32();
|
|
|
|
array = popRef();
|
|
|
|
checkArrayBounds(array, index);
|
|
|
|
pushI32(array[index]);
|
|
|
|
break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Bytecodes.SALOAD:
|
2015-05-08 03:31:22 +03:00
|
|
|
index = popI32();
|
|
|
|
array = popRef();
|
2015-05-08 01:17:05 +03:00
|
|
|
checkArrayBounds(array, index);
|
2015-05-08 03:31:22 +03:00
|
|
|
pushI32(array[index]);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
// case Bytecodes.FALOAD:
|
|
|
|
// case Bytecodes.AALOAD:
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.LALOAD:
|
|
|
|
// case Bytecodes.DALOAD:
|
|
|
|
// index = stack.pop();
|
|
|
|
// array = stack.pop();
|
|
|
|
// checkArrayBounds(array, index);
|
|
|
|
// stack.push2(array[index]);
|
|
|
|
// break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Bytecodes.ISTORE:
|
|
|
|
case Bytecodes.FSTORE:
|
2015-05-08 03:31:22 +03:00
|
|
|
storeW32(code[pc++]);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.ASTORE:
|
2015-05-08 03:31:22 +03:00
|
|
|
setLocalRef(popRef(), code[pc++]);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.LSTORE:
|
|
|
|
case Bytecodes.DSTORE:
|
2015-05-08 03:31:22 +03:00
|
|
|
storeW64(code[pc++]);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
case Bytecodes.ISTORE_0:
|
|
|
|
case Bytecodes.ISTORE_1:
|
|
|
|
case Bytecodes.ISTORE_2:
|
|
|
|
case Bytecodes.ISTORE_3:
|
2015-05-08 03:31:22 +03:00
|
|
|
storeW32(op - Bytecodes.ISTORE_0);
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.FSTORE_0:
|
|
|
|
case Bytecodes.FSTORE_1:
|
|
|
|
case Bytecodes.FSTORE_2:
|
|
|
|
case Bytecodes.FSTORE_3:
|
2015-05-08 03:31:22 +03:00
|
|
|
storeW32(op - Bytecodes.FSTORE_0);
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.ASTORE_0:
|
|
|
|
case Bytecodes.ASTORE_1:
|
|
|
|
case Bytecodes.ASTORE_2:
|
|
|
|
case Bytecodes.ASTORE_3:
|
2015-05-08 03:31:22 +03:00
|
|
|
setLocalRef(popRef(), op - Bytecodes.ASTORE_0);
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Bytecodes.LSTORE_0:
|
|
|
|
case Bytecodes.DSTORE_0:
|
2015-05-08 03:31:22 +03:00
|
|
|
storeW64(0);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.LSTORE_1:
|
|
|
|
case Bytecodes.DSTORE_1:
|
2015-05-08 03:31:22 +03:00
|
|
|
storeW64(1);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.LSTORE_2:
|
|
|
|
case Bytecodes.DSTORE_2:
|
2015-05-08 03:31:22 +03:00
|
|
|
storeW64(2);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.LSTORE_3:
|
|
|
|
case Bytecodes.DSTORE_3:
|
2015-05-08 03:31:22 +03:00
|
|
|
storeW64(3);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
case Bytecodes.IASTORE:
|
2015-05-08 03:31:22 +03:00
|
|
|
value = popI32();
|
|
|
|
index = popI32();
|
|
|
|
array = popRef();
|
|
|
|
checkArrayBounds(array, index);
|
|
|
|
array[index] = value;
|
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
case Bytecodes.FASTORE:
|
2015-05-08 03:31:22 +03:00
|
|
|
value = popI32();
|
|
|
|
index = popI32();
|
|
|
|
array = popRef();
|
|
|
|
checkArrayBounds(array, index);
|
|
|
|
array[index] = value;
|
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
case Bytecodes.BASTORE:
|
2015-05-08 03:31:22 +03:00
|
|
|
value = popI32();
|
|
|
|
index = popI32();
|
|
|
|
array = popRef();
|
|
|
|
checkArrayBounds(array, index);
|
|
|
|
array[index] = value;
|
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
case Bytecodes.CASTORE:
|
2015-05-08 03:31:22 +03:00
|
|
|
value = popI32();
|
|
|
|
index = popI32();
|
|
|
|
array = popRef();
|
|
|
|
checkArrayBounds(array, index);
|
|
|
|
array[index] = value;
|
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
case Bytecodes.SASTORE:
|
2015-05-08 03:31:22 +03:00
|
|
|
value = popI32();
|
|
|
|
index = popI32();
|
|
|
|
array = popRef();
|
2015-05-06 11:26:46 +03:00
|
|
|
checkArrayBounds(array, index);
|
|
|
|
array[index] = value;
|
|
|
|
break;
|
|
|
|
// case Bytecodes.LASTORE:
|
|
|
|
// case Bytecodes.DASTORE:
|
|
|
|
// value = stack.pop2();
|
|
|
|
// index = stack.pop();
|
|
|
|
// array = stack.pop();
|
|
|
|
// checkArrayBounds(array, index);
|
|
|
|
// array[index] = value;
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.AASTORE:
|
|
|
|
// value = stack.pop();
|
|
|
|
// index = stack.pop();
|
|
|
|
// array = stack.pop();
|
|
|
|
// checkArrayBounds(array, index);
|
|
|
|
// checkArrayStore(array, value);
|
|
|
|
// array[index] = value;
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.POP:
|
|
|
|
// stack.pop();
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.POP2:
|
|
|
|
// stack.pop2();
|
|
|
|
// break;
|
|
|
|
case Bytecodes.DUP:
|
2015-05-08 03:31:22 +03:00
|
|
|
ref[sp] = ref[sp - 1];
|
|
|
|
i32[sp] = i32[sp - 1];
|
2015-05-06 11:26:46 +03:00
|
|
|
sp++;
|
|
|
|
break;
|
|
|
|
// case Bytecodes.DUP_X1:
|
|
|
|
// a = stack.pop();
|
|
|
|
// b = stack.pop();
|
|
|
|
// stack.push(a);
|
|
|
|
// stack.push(b);
|
|
|
|
// stack.push(a);
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.DUP_X2:
|
|
|
|
// a = stack.pop();
|
|
|
|
// b = stack.pop();
|
|
|
|
// c = stack.pop();
|
|
|
|
// stack.push(a);
|
|
|
|
// stack.push(c);
|
|
|
|
// stack.push(b);
|
|
|
|
// stack.push(a);
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.DUP2:
|
|
|
|
// a = stack.pop();
|
|
|
|
// b = stack.pop();
|
|
|
|
// stack.push(b);
|
|
|
|
// stack.push(a);
|
|
|
|
// stack.push(b);
|
|
|
|
// stack.push(a);
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.DUP2_X1:
|
|
|
|
// a = stack.pop();
|
|
|
|
// b = stack.pop();
|
|
|
|
// c = stack.pop();
|
|
|
|
// stack.push(b);
|
|
|
|
// stack.push(a);
|
|
|
|
// stack.push(c);
|
|
|
|
// stack.push(b);
|
|
|
|
// stack.push(a);
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.DUP2_X2:
|
|
|
|
// a = stack.pop();
|
|
|
|
// b = stack.pop();
|
|
|
|
// 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;
|
|
|
|
// case Bytecodes.SWAP:
|
|
|
|
// a = stack.pop();
|
|
|
|
// b = stack.pop();
|
|
|
|
// stack.push(a);
|
|
|
|
// stack.push(b);
|
|
|
|
// break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Bytecodes.IINC:
|
|
|
|
index = code[pc++];
|
2015-05-08 03:31:22 +03:00
|
|
|
value = readI8();
|
|
|
|
i32[fp + localFramePointerOffset(index)] += value | 0;
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
// case Bytecodes.IINC_GOTO:
|
|
|
|
// index = frame.read8();
|
|
|
|
// value = frame.read8Signed();
|
|
|
|
// frame.local[index] += frame.local[index];
|
|
|
|
// frame.pc ++;
|
|
|
|
// frame.pc = frame.readTargetPC();
|
|
|
|
// break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Bytecodes.IADD:
|
2015-05-08 03:31:22 +03:00
|
|
|
pushI32((popI32() + popI32()) | 0);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.LADD:
|
|
|
|
ASM._lAdd((sp - 4) >> 2, (sp - 4) >> 2, (sp - 2) >> 2); sp -= 2;
|
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
// case Bytecodes.FADD:
|
|
|
|
// stack.push(Math.fround(stack.pop() + stack.pop()));
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.DADD:
|
|
|
|
// stack.push2(stack.pop2() + stack.pop2());
|
|
|
|
// break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Bytecodes.ISUB:
|
2015-05-08 03:31:22 +03:00
|
|
|
pushI32((-popI32() + popI32()) | 0);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.LSUB:
|
|
|
|
ASM._lSub((sp - 4) >> 2, (sp - 4) >> 2, (sp - 2) >> 2); sp -= 2;
|
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
// case Bytecodes.FSUB:
|
|
|
|
// stack.push(Math.fround(-stack.pop() + stack.pop()));
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.DSUB:
|
|
|
|
// stack.push2(-stack.pop2() + stack.pop2());
|
|
|
|
// break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Bytecodes.IMUL:
|
2015-05-08 03:31:22 +03:00
|
|
|
pushI32(Math.imul(popI32(), popI32()) | 0);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
// case Bytecodes.LMUL:
|
|
|
|
// stack.push2(stack.pop2().multiply(stack.pop2()));
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.FMUL:
|
|
|
|
// stack.push(Math.fround(stack.pop() * stack.pop()));
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.DMUL:
|
|
|
|
// stack.push2(stack.pop2() * stack.pop2());
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.IDIV:
|
|
|
|
// b = stack.pop();
|
|
|
|
// a = stack.pop();
|
|
|
|
// checkDivideByZero(b);
|
|
|
|
// stack.push((a === Constants.INT_MIN && b === -1) ? a : ((a / b) | 0));
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.LDIV:
|
|
|
|
// b = stack.pop2();
|
|
|
|
// a = stack.pop2();
|
|
|
|
// checkDivideByZeroLong(b);
|
|
|
|
// stack.push2(a.div(b));
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.FDIV:
|
|
|
|
// b = stack.pop();
|
|
|
|
// a = stack.pop();
|
|
|
|
// stack.push(Math.fround(a / b));
|
|
|
|
// break;
|
|
|
|
case Bytecodes.DDIV:
|
2015-05-08 03:31:22 +03:00
|
|
|
fb = popF64();
|
|
|
|
fa = popF64();
|
|
|
|
pushF64(fa / fb);
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
// case Bytecodes.IREM:
|
|
|
|
// b = stack.pop();
|
|
|
|
// a = stack.pop();
|
|
|
|
// checkDivideByZero(b);
|
|
|
|
// stack.push(a % b);
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.LREM:
|
|
|
|
// b = stack.pop2();
|
|
|
|
// a = stack.pop2();
|
|
|
|
// checkDivideByZeroLong(b);
|
|
|
|
// stack.push2(a.modulo(b));
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.FREM:
|
|
|
|
// b = stack.pop();
|
|
|
|
// a = stack.pop();
|
|
|
|
// stack.push(Math.fround(a % b));
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.DREM:
|
|
|
|
// b = stack.pop2();
|
|
|
|
// a = stack.pop2();
|
|
|
|
// stack.push2(a % b);
|
|
|
|
// break;
|
|
|
|
case Bytecodes.INEG:
|
2015-05-08 03:31:22 +03:00
|
|
|
i32[sp - 1] = -i32[sp - 1] | 0;
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
// case Bytecodes.LNEG:
|
|
|
|
// stack.push2(stack.pop2().negate());
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.FNEG:
|
|
|
|
// stack.push(-stack.pop());
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.DNEG:
|
|
|
|
// stack.push2(-stack.pop2());
|
|
|
|
// break;
|
|
|
|
case Bytecodes.ISHL:
|
2015-05-08 03:31:22 +03:00
|
|
|
ib = popI32();
|
|
|
|
ia = popI32();
|
|
|
|
pushI32(ia << ib);
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
// case Bytecodes.LSHL:
|
|
|
|
// b = stack.pop();
|
|
|
|
// a = stack.pop2();
|
|
|
|
// stack.push2(a.shiftLeft(b));
|
|
|
|
// break;
|
|
|
|
case Bytecodes.ISHR:
|
2015-05-08 03:31:22 +03:00
|
|
|
ib = popI32();
|
|
|
|
ia = popI32();
|
|
|
|
pushI32(ia >> ib);
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
// case Bytecodes.LSHR:
|
|
|
|
// b = stack.pop();
|
|
|
|
// a = stack.pop2();
|
|
|
|
// stack.push2(a.shiftRight(b));
|
|
|
|
// break;
|
|
|
|
case Bytecodes.IUSHR:
|
2015-05-08 03:31:22 +03:00
|
|
|
ib = popI32();
|
|
|
|
ia = popI32();
|
|
|
|
pushI32(ia >>> ib);
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
// case Bytecodes.LUSHR:
|
|
|
|
// b = stack.pop();
|
|
|
|
// a = stack.pop2();
|
|
|
|
// stack.push2(a.shiftRightUnsigned(b));
|
|
|
|
// break;
|
|
|
|
case Bytecodes.IAND:
|
2015-05-08 03:31:22 +03:00
|
|
|
i32[sp - 2] &= popI32();
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
// case Bytecodes.LAND:
|
|
|
|
// stack.push2(stack.pop2().and(stack.pop2()));
|
|
|
|
// break;
|
|
|
|
case Bytecodes.IOR:
|
2015-05-08 03:31:22 +03:00
|
|
|
i32[sp - 2] |= popI32();
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
// case Bytecodes.LOR:
|
|
|
|
// stack.push2(stack.pop2().or(stack.pop2()));
|
|
|
|
// break;
|
|
|
|
case Bytecodes.IXOR:
|
2015-05-08 03:31:22 +03:00
|
|
|
i32[sp - 2] ^= popI32();
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
// case Bytecodes.LXOR:
|
|
|
|
// stack.push2(stack.pop2().xor(stack.pop2()));
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.LCMP:
|
|
|
|
// b = stack.pop2();
|
|
|
|
// a = stack.pop2();
|
|
|
|
// if (a.greaterThan(b)) {
|
|
|
|
// stack.push(1);
|
|
|
|
// } else if (a.lessThan(b)) {
|
|
|
|
// stack.push(-1);
|
|
|
|
// } else {
|
|
|
|
// stack.push(0);
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.FCMPL:
|
|
|
|
// b = stack.pop();
|
|
|
|
// 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;
|
|
|
|
// case Bytecodes.FCMPG:
|
|
|
|
// b = stack.pop();
|
|
|
|
// 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;
|
|
|
|
// case Bytecodes.DCMPL:
|
|
|
|
// b = stack.pop2();
|
|
|
|
// 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;
|
|
|
|
// case Bytecodes.DCMPG:
|
|
|
|
// b = stack.pop2();
|
|
|
|
// 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;
|
|
|
|
case Bytecodes.IFEQ:
|
|
|
|
targetPC = readTargetPC();
|
2015-05-08 03:31:22 +03:00
|
|
|
if (popI32() === 0) {
|
2015-05-06 11:26:46 +03:00
|
|
|
pc = targetPC;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.IFNE:
|
|
|
|
targetPC = readTargetPC();
|
2015-05-08 03:31:22 +03:00
|
|
|
if (popI32() !== 0) {
|
2015-05-06 11:26:46 +03:00
|
|
|
pc = targetPC;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.IFLT:
|
|
|
|
targetPC = readTargetPC();
|
2015-05-08 03:31:22 +03:00
|
|
|
if (popI32() < 0) {
|
2015-05-06 11:26:46 +03:00
|
|
|
pc = targetPC;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.IFGE:
|
|
|
|
targetPC = readTargetPC();
|
2015-05-08 03:31:22 +03:00
|
|
|
if (popI32() >= 0) {
|
2015-05-06 11:26:46 +03:00
|
|
|
pc = targetPC;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.IFGT:
|
|
|
|
targetPC = readTargetPC();
|
2015-05-08 03:31:22 +03:00
|
|
|
if (popI32() > 0) {
|
2015-05-06 11:26:46 +03:00
|
|
|
pc = targetPC;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.IFLE:
|
|
|
|
targetPC = readTargetPC();
|
2015-05-08 03:31:22 +03:00
|
|
|
if (popI32() <= 0) {
|
2015-05-06 11:26:46 +03:00
|
|
|
pc = targetPC;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.IF_ICMPEQ:
|
|
|
|
targetPC = readTargetPC();
|
2015-05-08 03:31:22 +03:00
|
|
|
if (popI32() === popI32()) {
|
2015-05-06 11:26:46 +03:00
|
|
|
pc = targetPC;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.IF_ICMPNE:
|
|
|
|
targetPC = readTargetPC();
|
2015-05-08 03:31:22 +03:00
|
|
|
if (popI32() !== popI32()) {
|
2015-05-06 11:26:46 +03:00
|
|
|
pc = targetPC;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.IF_ICMPLT:
|
|
|
|
targetPC = readTargetPC();
|
2015-05-08 03:31:22 +03:00
|
|
|
if (popI32() > popI32()) {
|
2015-05-06 11:26:46 +03:00
|
|
|
pc = targetPC;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.IF_ICMPGE:
|
|
|
|
targetPC = readTargetPC();
|
2015-05-08 03:31:22 +03:00
|
|
|
if (popI32() <= popI32()) {
|
2015-05-06 11:26:46 +03:00
|
|
|
pc = targetPC;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.IF_ICMPGT:
|
|
|
|
targetPC = readTargetPC();
|
2015-05-08 03:31:22 +03:00
|
|
|
if (popI32() < popI32()) {
|
2015-05-06 11:26:46 +03:00
|
|
|
pc = targetPC;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.IF_ICMPLE:
|
|
|
|
targetPC = readTargetPC();
|
2015-05-08 03:31:22 +03:00
|
|
|
if (popI32() >= popI32()) {
|
2015-05-06 11:26:46 +03:00
|
|
|
pc = targetPC;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.IF_ACMPEQ:
|
|
|
|
targetPC = readTargetPC();
|
2015-05-08 03:31:22 +03:00
|
|
|
if (popRef() === popRef()) {
|
2015-05-06 11:26:46 +03:00
|
|
|
pc = targetPC;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.IF_ACMPNE:
|
|
|
|
targetPC = readTargetPC();
|
2015-05-08 03:31:22 +03:00
|
|
|
if (popRef() !== popRef()) {
|
2015-05-06 11:26:46 +03:00
|
|
|
pc = targetPC;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.IFNULL:
|
|
|
|
targetPC = readTargetPC();
|
2015-05-08 03:31:22 +03:00
|
|
|
if (!popRef()) {
|
2015-05-06 11:26:46 +03:00
|
|
|
pc = targetPC;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.IFNONNULL:
|
|
|
|
targetPC = readTargetPC();
|
2015-05-08 03:31:22 +03:00
|
|
|
if (popRef()) {
|
2015-05-06 11:26:46 +03:00
|
|
|
pc = targetPC;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.GOTO:
|
|
|
|
pc = readTargetPC();
|
|
|
|
break;
|
|
|
|
// case Bytecodes.GOTO_W:
|
|
|
|
// frame.pc = frame.read32Signed() - 1;
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.JSR:
|
|
|
|
// pc = frame.read16();
|
|
|
|
// stack.push(frame.pc);
|
|
|
|
// frame.pc = pc;
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.JSR_W:
|
|
|
|
// pc = frame.read32();
|
|
|
|
// stack.push(frame.pc);
|
|
|
|
// frame.pc = pc;
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.RET:
|
|
|
|
// frame.pc = frame.local[frame.read8()];
|
|
|
|
// break;
|
|
|
|
case Bytecodes.I2L:
|
2015-05-08 03:31:22 +03:00
|
|
|
i32[sp] = i32[sp - 1] < 0 ? -1 : 0; sp++;
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
|
|
|
// case Bytecodes.I2F:
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.I2D:
|
|
|
|
// stack.push2(stack.pop());
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.L2I:
|
|
|
|
// stack.push(stack.pop2().toInt());
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.L2F:
|
|
|
|
// stack.push(Math.fround(stack.pop2().toNumber()));
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.L2D:
|
|
|
|
// stack.push2(stack.pop2().toNumber());
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.F2I:
|
|
|
|
// stack.push(util.double2int(stack.pop()));
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.F2L:
|
|
|
|
// stack.push2(Long.fromNumber(stack.pop()));
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.F2D:
|
|
|
|
// stack.push2(stack.pop());
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.D2I:
|
|
|
|
// stack.push(util.double2int(stack.pop2()));
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.D2L:
|
|
|
|
// stack.push2(util.double2long(stack.pop2()));
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.D2F:
|
|
|
|
// stack.push(Math.fround(stack.pop2()));
|
|
|
|
// break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Bytecodes.I2B:
|
2015-05-08 03:31:22 +03:00
|
|
|
i32[sp - 1] = (i32[sp - 1] << 24) >> 24;
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.I2C:
|
2015-05-08 03:31:22 +03:00
|
|
|
i32[sp - 1] &= 0xffff;
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.I2S:
|
2015-05-08 03:31:22 +03:00
|
|
|
i32[sp - 1] = (i32[sp - 1] << 16) >> 16;;
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
// case Bytecodes.TABLESWITCH:
|
|
|
|
// frame.pc = frame.tableSwitch();
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.LOOKUPSWITCH:
|
|
|
|
// frame.pc = frame.lookupSwitch();
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.NEWARRAY:
|
|
|
|
// type = frame.read8();
|
|
|
|
// size = stack.pop();
|
|
|
|
// stack.push(newArray(PrimitiveClassInfo["????ZCFDBSIJ"[type]].klass, size));
|
|
|
|
// break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Bytecodes.ANEWARRAY:
|
2015-05-08 03:31:22 +03:00
|
|
|
index = readU16();
|
2015-05-08 01:17:05 +03:00
|
|
|
classInfo = resolveClass(index, ci);
|
|
|
|
classInitAndUnwindCheck(classInfo, opPC);
|
2015-05-08 03:31:22 +03:00
|
|
|
size = popI32();
|
|
|
|
pushRef(newArray(classInfo.klass, size));
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
// case Bytecodes.MULTIANEWARRAY:
|
|
|
|
// index = frame.read16();
|
|
|
|
// classInfo = resolveClass(index, mi.classInfo);
|
|
|
|
// var dimensions = frame.read8();
|
|
|
|
// var lengths = new Array(dimensions);
|
|
|
|
// for (var i = 0; i < dimensions; i++)
|
|
|
|
// lengths[i] = stack.pop();
|
|
|
|
// stack.push(J2ME.newMultiArray(classInfo.klass, lengths.reverse()));
|
|
|
|
// break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Bytecodes.ARRAYLENGTH:
|
2015-05-08 03:31:22 +03:00
|
|
|
array = popRef();
|
|
|
|
pushI32(array.length);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
// case Bytecodes.ARRAYLENGTH_IF_ICMPGE:
|
|
|
|
// array = stack.pop();
|
|
|
|
// stack.push(array.length);
|
|
|
|
// frame.pc ++;
|
|
|
|
// pc = frame.readTargetPC();
|
|
|
|
// if (stack.pop() <= stack.pop()) {
|
|
|
|
// frame.pc = pc;
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
case Bytecodes.GETFIELD:
|
2015-05-08 03:31:22 +03:00
|
|
|
index = readI16();
|
2015-05-06 11:26:46 +03:00
|
|
|
fieldInfo = cp.resolveField(index, false);
|
2015-05-08 03:31:22 +03:00
|
|
|
object = popRef();
|
2015-05-06 11:26:46 +03:00
|
|
|
pushKind(fieldInfo.kind, fieldInfo.get(object));
|
|
|
|
// frame.patch(3, Bytecodes.GETFIELD, Bytecodes.RESOLVED_GETFIELD);
|
|
|
|
break;
|
|
|
|
// case Bytecodes.RESOLVED_GETFIELD:
|
|
|
|
// fieldInfo = <FieldInfo><any>rp[frame.read16()];
|
|
|
|
// object = stack.pop();
|
|
|
|
// stack.pushKind(fieldInfo.kind, fieldInfo.get(object));
|
|
|
|
// break;
|
|
|
|
case Bytecodes.PUTFIELD:
|
2015-05-08 03:31:22 +03:00
|
|
|
index = readI16();
|
2015-05-06 11:26:46 +03:00
|
|
|
fieldInfo = cp.resolveField(index, false);
|
|
|
|
value = popKind(fieldInfo.kind);
|
2015-05-08 03:31:22 +03:00
|
|
|
object = popRef();
|
2015-05-06 11:26:46 +03:00
|
|
|
fieldInfo.set(object, value);
|
|
|
|
// frame.patch(3, Bytecodes.PUTFIELD, Bytecodes.RESOLVED_PUTFIELD);
|
|
|
|
break;
|
|
|
|
// case Bytecodes.RESOLVED_PUTFIELD:
|
|
|
|
// fieldInfo = <FieldInfo><any>rp[frame.read16()];
|
|
|
|
// value = stack.popKind(fieldInfo.kind);
|
|
|
|
// object = stack.pop();
|
|
|
|
// fieldInfo.set(object, value);
|
|
|
|
// break;
|
|
|
|
case Bytecodes.GETSTATIC:
|
2015-05-08 03:31:22 +03:00
|
|
|
index = readI16();
|
2015-05-06 11:26:46 +03:00
|
|
|
fieldInfo = cp.resolveField(index, true);
|
2015-05-08 01:17:05 +03:00
|
|
|
classInitAndUnwindCheck(fieldInfo.classInfo, opPC);
|
2015-05-06 11:26:46 +03:00
|
|
|
//if (U) {
|
|
|
|
// return;
|
|
|
|
//}
|
|
|
|
pushKind(fieldInfo.kind, fieldInfo.getStatic());
|
|
|
|
break;
|
|
|
|
case Bytecodes.PUTSTATIC:
|
2015-05-08 03:31:22 +03:00
|
|
|
index = readI16();
|
2015-05-06 11:26:46 +03:00
|
|
|
fieldInfo = cp.resolveField(index, true);
|
2015-05-08 01:17:05 +03:00
|
|
|
classInitAndUnwindCheck(fieldInfo.classInfo, opPC);
|
2015-05-06 11:26:46 +03:00
|
|
|
//if (U) {
|
|
|
|
// return;
|
|
|
|
//}
|
|
|
|
fieldInfo.setStatic(popKind(fieldInfo.kind));
|
|
|
|
break;
|
|
|
|
case Bytecodes.NEW:
|
2015-05-08 03:31:22 +03:00
|
|
|
index = readI16();
|
2015-05-08 01:17:05 +03:00
|
|
|
traceWriter && traceWriter.writeLn(mi.implKey + " " + index);
|
2015-05-06 11:26:46 +03:00
|
|
|
classInfo = resolveClass(index, ci);
|
2015-05-05 05:46:26 +03:00
|
|
|
saveThreadState();
|
2015-05-06 11:26:46 +03:00
|
|
|
classInitAndUnwindCheck(classInfo, pc - 3);
|
|
|
|
if (U) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
loadThreadState();
|
2015-05-08 03:31:22 +03:00
|
|
|
pushRef(newObject(classInfo.klass));
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Bytecodes.CHECKCAST:
|
2015-05-08 03:31:22 +03:00
|
|
|
index = readI16();
|
2015-05-08 01:17:05 +03:00
|
|
|
classInfo = resolveClass(index, mi.classInfo);
|
2015-05-08 03:31:22 +03:00
|
|
|
object = peekRef();
|
2015-05-08 01:17:05 +03:00
|
|
|
if (object && !isAssignableTo(object.klass, classInfo.klass)) {
|
|
|
|
throw $.newClassCastException (
|
|
|
|
object.klass.classInfo.getClassNameSlow() + " is not assignable to " +
|
|
|
|
classInfo.getClassNameSlow()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.INSTANCEOF:
|
2015-05-08 03:31:22 +03:00
|
|
|
index = readI16();
|
2015-05-08 01:17:05 +03:00
|
|
|
classInfo = resolveClass(index, ci);
|
2015-05-08 03:31:22 +03:00
|
|
|
object = popRef();
|
2015-05-08 01:17:05 +03:00
|
|
|
result = !object ? false : isAssignableTo(object.klass, classInfo.klass);
|
2015-05-08 03:31:22 +03:00
|
|
|
pushI32(result ? 1 : 0);
|
2015-05-08 01:17:05 +03:00
|
|
|
break;
|
|
|
|
case Bytecodes.ATHROW:
|
2015-05-08 03:31:22 +03:00
|
|
|
object = popRef();
|
2015-05-08 01:17:05 +03:00
|
|
|
if (!object) {
|
|
|
|
throw $.newNullPointerException();
|
|
|
|
}
|
|
|
|
throw object;
|
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
case Bytecodes.MONITORENTER:
|
2015-05-08 03:31:22 +03:00
|
|
|
object = popRef();
|
2015-05-06 11:26:46 +03:00
|
|
|
thread.ctx.monitorEnter(object);
|
|
|
|
if (U === VMState.Pausing || U === VMState.Stopping) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Bytecodes.MONITOREXIT:
|
2015-05-08 03:31:22 +03:00
|
|
|
object = popRef();
|
2015-05-06 11:26:46 +03:00
|
|
|
thread.ctx.monitorExit(object);
|
|
|
|
break;
|
|
|
|
// case Bytecodes.WIDE:
|
|
|
|
// frame.wide();
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.RESOLVED_INVOKEVIRTUAL:
|
|
|
|
// index = frame.read16();
|
|
|
|
// var calleeMethodInfo = <MethodInfo><any>rp[index];
|
|
|
|
// var object = frame.peekInvokeObject(calleeMethodInfo);
|
|
|
|
//
|
|
|
|
// calleeMethod = object[calleeMethodInfo.virtualName];
|
|
|
|
// var calleeTargetMethodInfo: MethodInfo = calleeMethod.methodInfo;
|
|
|
|
//
|
|
|
|
// if (calleeTargetMethodInfo &&
|
|
|
|
// !calleeTargetMethodInfo.isSynchronized &&
|
|
|
|
// !calleeTargetMethodInfo.isNative &&
|
|
|
|
// calleeTargetMethodInfo.state !== MethodState.Compiled) {
|
|
|
|
// var calleeFrame = Frame.create(calleeTargetMethodInfo, []);
|
|
|
|
// ArrayUtilities.popManyInto(stack, calleeTargetMethodInfo.consumeArgumentSlots, calleeFrame.local);
|
|
|
|
// ctx.pushFrame(calleeFrame);
|
|
|
|
// frame = calleeFrame;
|
|
|
|
// mi = frame.methodInfo;
|
|
|
|
// mi.stats.interpreterCallCount ++;
|
|
|
|
// ci = mi.classInfo;
|
|
|
|
// rp = ci.constantPool.resolved;
|
|
|
|
// stack = frame.stack;
|
|
|
|
// lastPC = -1;
|
|
|
|
// continue;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// // Call directy.
|
|
|
|
// var returnValue;
|
|
|
|
// var argumentSlots = calleeMethodInfo.argumentSlots;
|
|
|
|
// switch (argumentSlots) {
|
|
|
|
// case 0:
|
|
|
|
// returnValue = calleeMethod.call(object);
|
|
|
|
// break;
|
|
|
|
// case 1:
|
|
|
|
// a = stack.pop();
|
|
|
|
// returnValue = calleeMethod.call(object, a);
|
|
|
|
// break;
|
|
|
|
// case 2:
|
|
|
|
// b = stack.pop();
|
|
|
|
// a = stack.pop();
|
|
|
|
// returnValue = calleeMethod.call(object, a, b);
|
|
|
|
// break;
|
|
|
|
// case 3:
|
|
|
|
// c = stack.pop();
|
|
|
|
// b = stack.pop();
|
|
|
|
// a = stack.pop();
|
|
|
|
// returnValue = calleeMethod.call(object, a, b, c);
|
|
|
|
// break;
|
|
|
|
// default:
|
|
|
|
// Debug.assertUnreachable("Unexpected number of arguments");
|
|
|
|
// break;
|
|
|
|
// }
|
|
|
|
// stack.pop();
|
|
|
|
// if (!release) {
|
|
|
|
// checkReturnValue(calleeMethodInfo, returnValue);
|
|
|
|
// }
|
|
|
|
// if (U) {
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
// if (calleeMethodInfo.returnKind !== Kind.Void) {
|
|
|
|
// if (isTwoSlot(calleeMethodInfo.returnKind)) {
|
|
|
|
// stack.push2(returnValue);
|
|
|
|
// } else {
|
|
|
|
// stack.push(returnValue);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.INVOKEVIRTUAL:
|
|
|
|
// case Bytecodes.INVOKESPECIAL:
|
|
|
|
// case Bytecodes.INVOKESTATIC:
|
|
|
|
// case Bytecodes.INVOKEINTERFACE:
|
|
|
|
// index = frame.read16();
|
|
|
|
// if (op === Bytecodes.INVOKEINTERFACE) {
|
|
|
|
// frame.read16(); // Args Number & Zero
|
|
|
|
// }
|
|
|
|
// var isStatic = (op === Bytecodes.INVOKESTATIC);
|
|
|
|
//
|
|
|
|
// // Resolve method and do the class init check if necessary.
|
|
|
|
// var calleeMethodInfo = mi.classInfo.constantPool.resolveMethod(index, isStatic);
|
|
|
|
//
|
|
|
|
// // Fast path for some of the most common interpreter call targets.
|
|
|
|
// if (calleeMethodInfo.classInfo.getClassNameSlow() === "java/lang/Object" &&
|
|
|
|
// calleeMethodInfo.name === "<init>") {
|
|
|
|
// stack.pop();
|
|
|
|
// continue;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// if (isStatic) {
|
|
|
|
// classInitAndUnwindCheck(calleeMethodInfo.classInfo, lastPC);
|
|
|
|
// if (U) {
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// // Figure out the target method.
|
|
|
|
// var calleeTargetMethodInfo: MethodInfo = calleeMethodInfo;
|
|
|
|
// object = null;
|
|
|
|
// var calleeMethod: any;
|
|
|
|
// if (!isStatic) {
|
|
|
|
// object = frame.peekInvokeObject(calleeMethodInfo);
|
|
|
|
// switch (op) {
|
|
|
|
// case Bytecodes.INVOKEVIRTUAL:
|
|
|
|
// if (!calleeTargetMethodInfo.hasTwoSlotArguments &&
|
|
|
|
// calleeTargetMethodInfo.argumentSlots < 4) {
|
|
|
|
// frame.patch(3, Bytecodes.INVOKEVIRTUAL, Bytecodes.RESOLVED_INVOKEVIRTUAL);
|
|
|
|
// }
|
|
|
|
// case Bytecodes.INVOKEINTERFACE:
|
|
|
|
// var name = op === Bytecodes.INVOKEVIRTUAL ? calleeMethodInfo.virtualName : calleeMethodInfo.mangledName;
|
|
|
|
// calleeMethod = object[name];
|
|
|
|
// calleeTargetMethodInfo = calleeMethod.methodInfo;
|
|
|
|
// break;
|
|
|
|
// case Bytecodes.INVOKESPECIAL:
|
|
|
|
// checkNull(object);
|
|
|
|
// calleeMethod = getLinkedMethod(calleeMethodInfo);
|
|
|
|
// break;
|
|
|
|
// }
|
|
|
|
// } else {
|
|
|
|
// calleeMethod = getLinkedMethod(calleeMethodInfo);
|
|
|
|
// }
|
|
|
|
// // Call method directly in the interpreter if we can.
|
|
|
|
// if (calleeTargetMethodInfo && !calleeTargetMethodInfo.isNative && calleeTargetMethodInfo.state !== MethodState.Compiled) {
|
|
|
|
// var calleeFrame = Frame.create(calleeTargetMethodInfo, []);
|
|
|
|
// ArrayUtilities.popManyInto(stack, calleeTargetMethodInfo.consumeArgumentSlots, calleeFrame.local);
|
|
|
|
// ctx.pushFrame(calleeFrame);
|
|
|
|
// frame = calleeFrame;
|
|
|
|
// mi = frame.methodInfo;
|
|
|
|
// mi.stats.interpreterCallCount ++;
|
|
|
|
// ci = mi.classInfo;
|
|
|
|
// rp = ci.constantPool.resolved;
|
|
|
|
// stack = frame.stack;
|
|
|
|
// lastPC = -1;
|
|
|
|
// if (calleeTargetMethodInfo.isSynchronized) {
|
|
|
|
// if (!calleeFrame.lockObject) {
|
|
|
|
// frame.lockObject = calleeTargetMethodInfo.isStatic
|
|
|
|
// ? calleeTargetMethodInfo.classInfo.getClassObject()
|
|
|
|
// : frame.local[0];
|
|
|
|
// }
|
|
|
|
// ctx.monitorEnter(calleeFrame.lockObject);
|
|
|
|
// if (U === VMState.Pausing || U === VMState.Stopping) {
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// continue;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// // Call directy.
|
|
|
|
// var returnValue;
|
|
|
|
// var argumentSlots = calleeMethodInfo.hasTwoSlotArguments ? -1 : calleeMethodInfo.argumentSlots;
|
|
|
|
// switch (argumentSlots) {
|
|
|
|
// case 0:
|
|
|
|
// returnValue = calleeMethod.call(object);
|
|
|
|
// break;
|
|
|
|
// case 1:
|
|
|
|
// a = stack.pop();
|
|
|
|
// returnValue = calleeMethod.call(object, a);
|
|
|
|
// break;
|
|
|
|
// case 2:
|
|
|
|
// b = stack.pop();
|
|
|
|
// a = stack.pop();
|
|
|
|
// returnValue = calleeMethod.call(object, a, b);
|
|
|
|
// break;
|
|
|
|
// case 3:
|
|
|
|
// c = stack.pop();
|
|
|
|
// b = stack.pop();
|
|
|
|
// a = stack.pop();
|
|
|
|
// returnValue = calleeMethod.call(object, a, b, c);
|
|
|
|
// break;
|
|
|
|
// default:
|
|
|
|
// if (calleeMethodInfo.hasTwoSlotArguments) {
|
|
|
|
// frame.popArgumentsInto(calleeMethodInfo, argArray);
|
|
|
|
// } else {
|
|
|
|
// popManyInto(stack, calleeMethodInfo.argumentSlots, argArray);
|
|
|
|
// }
|
|
|
|
// var returnValue = calleeMethod.apply(object, argArray);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// if (!isStatic) {
|
|
|
|
// stack.pop();
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// if (!release) {
|
|
|
|
// checkReturnValue(calleeMethodInfo, returnValue);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// if (U) {
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// if (calleeMethodInfo.returnKind !== Kind.Void) {
|
|
|
|
// if (isTwoSlot(calleeMethodInfo.returnKind)) {
|
|
|
|
// stack.push2(returnValue);
|
|
|
|
// } else {
|
|
|
|
// stack.push(returnValue);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
//
|
|
|
|
// case Bytecodes.LRETURN:
|
|
|
|
// case Bytecodes.DRETURN:
|
|
|
|
// returnValue = stack.pop();
|
|
|
|
// case Bytecodes.IRETURN:
|
|
|
|
// case Bytecodes.FRETURN:
|
|
|
|
// case Bytecodes.ARETURN:
|
|
|
|
// returnValue = stack.pop();
|
|
|
|
// case Bytecodes.RETURN:
|
|
|
|
// var callee = ctx.popFrame();
|
|
|
|
// if (callee.lockObject) {
|
|
|
|
// ctx.monitorExit(callee.lockObject);
|
|
|
|
// }
|
|
|
|
// callee.free();
|
|
|
|
// frame = ctx.current();
|
|
|
|
// if (Frame.isMarker(frame)) { // Marker or Start Frame
|
|
|
|
// if (op === Bytecodes.RETURN) {
|
|
|
|
// return undefined;
|
|
|
|
// }
|
|
|
|
// return returnValue;
|
|
|
|
// }
|
|
|
|
// mi = frame.methodInfo;
|
|
|
|
// ci = mi.classInfo;
|
|
|
|
// rp = ci.constantPool.resolved;
|
|
|
|
// stack = frame.stack;
|
|
|
|
// lastPC = -1;
|
|
|
|
// if (op === Bytecodes.RETURN) {
|
|
|
|
// // Nop.
|
|
|
|
// } else if (op === Bytecodes.LRETURN || op === Bytecodes.DRETURN) {
|
|
|
|
// stack.push2(returnValue);
|
|
|
|
// } else {
|
|
|
|
// stack.push(returnValue);
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
// default:
|
|
|
|
// var opName = Bytecodes[op];
|
|
|
|
// throw new Error("Opcode " + opName + " [" + op + "] not supported.");
|
|
|
|
|
|
|
|
case Bytecodes.NEWARRAY:
|
|
|
|
type = code[pc++];
|
2015-05-08 03:31:22 +03:00
|
|
|
size = popI32();
|
|
|
|
ref[sp++] = newArray(PrimitiveClassInfo["????ZCFDBSIJ"[type]].klass, size);
|
2015-05-06 11:26:46 +03:00
|
|
|
break;
|
2015-05-08 01:17:05 +03:00
|
|
|
case Bytecodes.LRETURN:
|
|
|
|
case Bytecodes.DRETURN:
|
|
|
|
case Bytecodes.IRETURN:
|
|
|
|
case Bytecodes.FRETURN:
|
|
|
|
case Bytecodes.ARETURN:
|
2015-05-06 11:26:46 +03:00
|
|
|
case Bytecodes.RETURN:
|
2015-05-08 01:17:05 +03:00
|
|
|
kind = returnKind(op);
|
|
|
|
returnValue = popKind(kind);
|
2015-05-08 03:31:22 +03:00
|
|
|
pc = i32[fp + FrameLayout.CallerRAOffset];
|
2015-05-06 11:26:46 +03:00
|
|
|
sp = fp - mi.codeAttribute.max_locals;
|
2015-05-08 03:31:22 +03:00
|
|
|
fp = i32[fp + FrameLayout.CallerFPOffset];
|
|
|
|
mi = ref[fp + FrameLayout.CalleeMethodInfoOffset];
|
2015-05-06 11:26:46 +03:00
|
|
|
if (mi === null) {
|
|
|
|
saveThreadState();
|
|
|
|
thread.popFrame(null);
|
|
|
|
return;
|
|
|
|
}
|
2015-05-08 03:31:22 +03:00
|
|
|
maxLocals = mi.codeAttribute.max_locals;
|
2015-05-08 01:17:05 +03:00
|
|
|
traceWriter && traceWriter.outdent();
|
|
|
|
traceWriter && traceWriter.writeLn("<< Interpreter Return");
|
2015-05-06 11:26:46 +03:00
|
|
|
ci = mi.classInfo;
|
|
|
|
cp = ci.constantPool;
|
|
|
|
code = mi.codeAttribute.code;
|
2015-05-08 01:17:05 +03:00
|
|
|
pushKind(kind, returnValue);
|
|
|
|
break;
|
2015-05-06 11:26:46 +03:00
|
|
|
case Bytecodes.INVOKEVIRTUAL:
|
|
|
|
case Bytecodes.INVOKESPECIAL:
|
|
|
|
case Bytecodes.INVOKESTATIC:
|
|
|
|
case Bytecodes.INVOKEINTERFACE:
|
2015-05-08 03:31:22 +03:00
|
|
|
index = readI16();
|
2015-05-06 11:26:46 +03:00
|
|
|
if (op === Bytecodes.INVOKEINTERFACE) {
|
|
|
|
pc += 2; // Args Number & Zero
|
|
|
|
}
|
|
|
|
var isStatic = (op === Bytecodes.INVOKESTATIC);
|
2015-04-30 19:51:47 +03:00
|
|
|
|
2015-05-06 11:26:46 +03:00
|
|
|
// Resolve method and do the class init check if necessary.
|
|
|
|
var calleeMethodInfo = cp.resolveMethod(index, isStatic);
|
|
|
|
var calleeTargetMethodInfo = calleeMethodInfo;
|
2015-04-30 19:51:47 +03:00
|
|
|
|
2015-05-06 11:26:46 +03:00
|
|
|
var callee = null;
|
|
|
|
object = null;
|
|
|
|
if (!isStatic) {
|
2015-05-08 03:31:22 +03:00
|
|
|
object = ref[sp - calleeMethodInfo.argumentSlots];
|
2015-05-06 11:26:46 +03:00
|
|
|
}
|
|
|
|
switch (op) {
|
|
|
|
case Bytecodes.INVOKESPECIAL:
|
|
|
|
checkNull(object);
|
|
|
|
case Bytecodes.INVOKESTATIC:
|
|
|
|
callee = getLinkedMethod(calleeMethodInfo);
|
|
|
|
break;
|
|
|
|
case Bytecodes.INVOKEVIRTUAL:
|
|
|
|
calleeTargetMethodInfo = object.klass.classInfo.vTable[calleeMethodInfo.vTableIndex];
|
|
|
|
case Bytecodes.INVOKEINTERFACE:
|
|
|
|
var name = op === Bytecodes.INVOKEVIRTUAL ? calleeMethodInfo.virtualName : calleeMethodInfo.mangledName;
|
|
|
|
callee = object[name];
|
|
|
|
break;
|
|
|
|
default:
|
2015-05-08 01:17:05 +03:00
|
|
|
traceWriter && traceWriter.writeLn("Not Implemented: " + Bytecodes[op]);
|
2015-05-06 11:26:46 +03:00
|
|
|
assert(false, "Not Implemented: " + Bytecodes[op]);
|
|
|
|
}
|
2015-04-30 19:51:47 +03:00
|
|
|
|
2015-05-06 11:26:46 +03:00
|
|
|
// Call Native or Compiled Method.
|
|
|
|
if (calleeTargetMethodInfo.isNative || calleeTargetMethodInfo.state === MethodState.Compiled) {
|
2015-05-08 01:17:05 +03:00
|
|
|
var args = popArguments(calleeTargetMethodInfo);
|
2015-05-06 11:26:46 +03:00
|
|
|
if (!isStatic) {
|
|
|
|
--sp; // Pop Reference
|
|
|
|
}
|
|
|
|
saveThreadState();
|
|
|
|
result = callee.apply(object, args);
|
|
|
|
loadThreadState();
|
|
|
|
if (calleeMethodInfo.returnKind !== Kind.Void) {
|
2015-05-08 01:17:05 +03:00
|
|
|
traceWriter && traceWriter.writeLn(">> Return Value: " + result);
|
2015-05-06 11:26:46 +03:00
|
|
|
pushKind(calleeMethodInfo.returnKind, result);
|
|
|
|
}
|
|
|
|
continue;
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
|
2015-05-08 01:17:05 +03:00
|
|
|
traceWriter && traceWriter.writeLn(">> Interpreter Invoke: " + calleeMethodInfo.implKey);
|
2015-05-06 11:26:46 +03:00
|
|
|
mi = calleeTargetMethodInfo;
|
2015-05-08 03:31:22 +03:00
|
|
|
maxLocals = mi.codeAttribute.max_locals;
|
2015-05-06 11:26:46 +03:00
|
|
|
ci = mi.classInfo;
|
|
|
|
cp = ci.constantPool;
|
2015-04-30 19:51:47 +03:00
|
|
|
|
2015-05-06 11:26:46 +03:00
|
|
|
// Reserve space for non-parameter locals.
|
|
|
|
sp += mi.codeAttribute.max_locals - mi.argumentSlots;
|
2015-04-30 19:51:47 +03:00
|
|
|
|
2015-05-06 11:26:46 +03:00
|
|
|
// Caller saved values.
|
2015-05-08 03:31:22 +03:00
|
|
|
pushI32(pc);
|
|
|
|
pushI32(fp);
|
|
|
|
pushRef(mi);
|
2015-05-06 11:26:46 +03:00
|
|
|
fp = sp - FrameLayout.CallerSaveSize;
|
2015-04-30 19:51:47 +03:00
|
|
|
|
2015-05-06 11:26:46 +03:00
|
|
|
opPC = pc = 0;
|
|
|
|
code = mi.codeAttribute.code;
|
2015-04-30 19:51:47 +03:00
|
|
|
|
2015-05-08 01:17:05 +03:00
|
|
|
traceWriter && traceWriter.indent();
|
2015-05-06 11:26:46 +03:00
|
|
|
continue;
|
|
|
|
default:
|
2015-05-08 01:17:05 +03:00
|
|
|
traceWriter && traceWriter.writeLn("Not Implemented: " + Bytecodes[op] + ", PC: " + opPC + ", CODE: " + code.length);
|
2015-05-06 11:26:46 +03:00
|
|
|
assert(false, "Not Implemented: " + Bytecodes[op]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} catch (e) {
|
2015-05-08 01:17:05 +03:00
|
|
|
// traceWriter.writeLn(jsGlobal.getBacktrace());
|
|
|
|
e = translateException(e);
|
|
|
|
if (!e.klass) {
|
|
|
|
// A non-java exception was thrown. Rethrow so it is not handled by tryCatch.
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
saveThreadStateBefore();
|
|
|
|
thread.tryCatch(e);
|
|
|
|
loadThreadState();
|
|
|
|
|
|
|
|
mi = thread.frame.methodInfo;
|
2015-05-08 03:31:22 +03:00
|
|
|
maxLocals = mi.codeAttribute.max_locals;
|
2015-05-08 01:17:05 +03:00
|
|
|
ci = mi.classInfo;
|
|
|
|
cp = ci.constantPool;
|
|
|
|
code = mi.codeAttribute.code;
|
|
|
|
continue;
|
2015-05-06 11:26:46 +03:00
|
|
|
}
|
2015-05-08 01:17:05 +03:00
|
|
|
// frame.set(fp, sp, opPC);
|
2015-05-05 05:46:26 +03:00
|
|
|
// frameView.traceStack(traceWriter);
|
2015-05-08 01:17:05 +03:00
|
|
|
// frame.trace(traceWriter, fieldInfo);
|
2015-04-30 19:51:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|