зеркало из https://github.com/mozilla/pluotsorbet.git
Primitive bump allocator, more ops.
This commit is contained in:
Родитель
b1c576b982
Коммит
fa3fe83ca3
403
int.ts
403
int.ts
|
@ -1,29 +1,33 @@
|
|||
module J2ME {
|
||||
declare var ASM;
|
||||
|
||||
declare var ASM;
|
||||
var buffer = ASM.buffer;
|
||||
var bufferView: DataView = new DataView(buffer);
|
||||
|
||||
var i32: Int32Array = ASM.HEAP32;
|
||||
var u32: Uint32Array = ASM.HEAPU32;
|
||||
var f32: Float32Array = ASM.HEAPF32;
|
||||
var ref = J2ME.ArrayUtilities.makeDenseArray(buffer.byteLength >> 2, null);
|
||||
|
||||
module J2ME {
|
||||
|
||||
import assert = Debug.assert;
|
||||
import Bytecodes = Bytecode.Bytecodes;
|
||||
import toHEX = IntegerUtilities.toHEX;
|
||||
|
||||
var buffer = ASM.buffer;
|
||||
|
||||
var i32: Int32Array = ASM.HEAP32;
|
||||
var u32: Uint32Array = ASM.HEAPU32;
|
||||
var f32: Float32Array = ASM.HEAPF32;
|
||||
var ref = ArrayUtilities.makeDenseArray(buffer.byteLength >> 2, null);
|
||||
|
||||
function toName(o) {
|
||||
if (o instanceof MethodInfo) {
|
||||
return o.implKey;
|
||||
}
|
||||
function getObjectInfo(o) {
|
||||
return fromUTF8(o.klass.classInfo.utf8Name) + " " + (o._address ? toHEX(o._address) : "");
|
||||
}
|
||||
if (o && o.klass === Klasses.java.lang.Class) {
|
||||
return "[" + fromUTF8(o.klass.classInfo.utf8Name) + "] " + o.runtimeKlass.templateKlass.classInfo.getClassNameSlow();
|
||||
return "[" + getObjectInfo(o) + "] " + o.runtimeKlass.templateKlass.classInfo.getClassNameSlow();
|
||||
}
|
||||
if (o && o.klass === Klasses.java.lang.String) {
|
||||
return "[" + fromUTF8(o.klass.classInfo.utf8Name) + "] \"" + fromJavaString(o) + "\"";
|
||||
return "[" + getObjectInfo(o) + "] \"" + fromJavaString(o) + "\"";
|
||||
}
|
||||
return o ? ("[" + fromUTF8(o.klass.classInfo.utf8Name) + "]") : "null";
|
||||
return o ? ("[" + getObjectInfo(o) + "]") : "null";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -217,7 +221,7 @@ module J2ME {
|
|||
view: FrameView;
|
||||
|
||||
constructor(ctx: Context) {
|
||||
this.tp = ASM._malloc(1024 * 128);
|
||||
this.tp = ASM._gcMalloc(1024 * 128);
|
||||
this.bp = this.tp;
|
||||
this.fp = this.bp;
|
||||
this.sp = this.fp;
|
||||
|
@ -349,8 +353,8 @@ module J2ME {
|
|||
var tag: TAGS;
|
||||
var type, size;
|
||||
var value, index, array, object, result, constant, targetPC, returnValue, kind;
|
||||
|
||||
var ia = 0, ib = 0; // Integer Operands
|
||||
var ll = 0, lh = 0; // Long Low / High
|
||||
var fa = 0, fb = 0; // Float / Double Operands
|
||||
|
||||
var classInfo: ClassInfo;
|
||||
|
@ -512,6 +516,50 @@ module J2ME {
|
|||
}
|
||||
}
|
||||
|
||||
function pushKindFromAddress(kind: Kind, address: number) {
|
||||
switch (kind) {
|
||||
case Kind.Reference:
|
||||
ref[sp++] = ref[address >> 2];
|
||||
return;
|
||||
case Kind.Int:
|
||||
case Kind.Char:
|
||||
case Kind.Short:
|
||||
case Kind.Boolean:
|
||||
case Kind.Float:
|
||||
i32[sp++] = i32[address >> 2];
|
||||
return;
|
||||
case Kind.Long:
|
||||
case Kind.Double:
|
||||
i32[sp++] = i32[address >> 2];
|
||||
i32[sp++] = i32[address + 4 >> 2];
|
||||
return;
|
||||
default:
|
||||
Debug.assert(false, "Cannot Push Kind: " + Kind[kind]);
|
||||
}
|
||||
}
|
||||
|
||||
function popKindIntoAddress(kind: Kind, address: number) {
|
||||
switch (kind) {
|
||||
case Kind.Reference:
|
||||
ref[address >> 2] = ref[--sp];
|
||||
return;
|
||||
case Kind.Int:
|
||||
case Kind.Char:
|
||||
case Kind.Short:
|
||||
case Kind.Boolean:
|
||||
case Kind.Float:
|
||||
i32[address >> 2] = i32[--sp];
|
||||
break;
|
||||
case Kind.Long:
|
||||
case Kind.Double:
|
||||
i32[address + 4 >> 2] = i32[--sp];
|
||||
i32[address >> 2] = i32[--sp];
|
||||
break;
|
||||
default:
|
||||
Debug.assert(false, "Cannot Pop Kind: " + Kind[kind]);
|
||||
}
|
||||
}
|
||||
|
||||
function classInitAndUnwindCheck(classInfo: ClassInfo, pc: number) {
|
||||
saveThreadState();
|
||||
classInitCheck(classInfo);
|
||||
|
@ -522,6 +570,8 @@ module J2ME {
|
|||
//}
|
||||
}
|
||||
|
||||
// HEAD
|
||||
|
||||
while (true) {
|
||||
|
||||
// saveThreadState();
|
||||
|
@ -536,7 +586,12 @@ module J2ME {
|
|||
var opPC = pc;
|
||||
var op = code[pc++];
|
||||
|
||||
// traceWriter.writeLn(bytecodeCount++ + " " + mi.implKey + ": PC: " + opPC + ", FP: " + fp + ", " + Bytecodes[op]);
|
||||
if (traceWriter) {
|
||||
//traceWriter.writeLn(bytecodeCount++ + " " + mi.implKey + ": PC: " + opPC + ", FP: " + fp + ", " + Bytecodes[op]);
|
||||
frame.set(fp, sp, opPC);
|
||||
// frameView.traceStack(traceWriter);
|
||||
// frame.trace(traceWriter, fieldInfo);
|
||||
}
|
||||
|
||||
try {
|
||||
switch (op) {
|
||||
|
@ -559,10 +614,14 @@ module J2ME {
|
|||
case Bytecodes.FCONST_2:
|
||||
i32[sp++] = op - Bytecodes.FCONST_0;
|
||||
continue;
|
||||
// case Bytecodes.DCONST_0:
|
||||
// case Bytecodes.DCONST_1:
|
||||
// stack.push2(op - Bytecodes.DCONST_0);
|
||||
// break;
|
||||
case Bytecodes.DCONST_0:
|
||||
i32[sp++] = 0;
|
||||
i32[sp++] = 0;
|
||||
continue;
|
||||
case Bytecodes.DCONST_1:
|
||||
i32[sp++] = 0;
|
||||
i32[sp++] = 1072693248;
|
||||
continue;
|
||||
case Bytecodes.LCONST_0:
|
||||
case Bytecodes.LCONST_1:
|
||||
i32[sp++] = op - Bytecodes.LCONST_0;
|
||||
|
@ -674,16 +733,37 @@ module J2ME {
|
|||
}
|
||||
i32[sp++] = array[index];
|
||||
continue;
|
||||
// case Bytecodes.FALOAD:
|
||||
// case Bytecodes.AALOAD:
|
||||
// break;
|
||||
// case Bytecodes.LALOAD:
|
||||
case Bytecodes.FALOAD:
|
||||
index = i32[--sp];
|
||||
array = ref[--sp];
|
||||
if ((index >>> 0) >= (array.length >>> 0)) {
|
||||
throw $.newArrayIndexOutOfBoundsException(String(index));
|
||||
}
|
||||
f32[sp++] = array[index];
|
||||
continue;
|
||||
case Bytecodes.AALOAD:
|
||||
index = i32[--sp];
|
||||
array = ref[--sp];
|
||||
if ((index >>> 0) >= (array.length >>> 0)) {
|
||||
throw $.newArrayIndexOutOfBoundsException(String(index));
|
||||
}
|
||||
ref[sp++] = array[index];
|
||||
continue;
|
||||
// case Bytecodes.DALOAD:
|
||||
// index = stack.pop();
|
||||
// array = stack.pop();
|
||||
// checkArrayBounds(array, index);
|
||||
// stack.push2(array[index]);
|
||||
// break;
|
||||
case Bytecodes.DALOAD:
|
||||
index = i32[--sp];
|
||||
array = ref[--sp];
|
||||
if ((index >>> 0) >= (array.length >>> 0)) {
|
||||
throw $.newArrayIndexOutOfBoundsException(String(index));
|
||||
}
|
||||
bufferView.setFloat64(sp << 2, array[index]);
|
||||
sp += 2;
|
||||
continue;
|
||||
case Bytecodes.ISTORE:
|
||||
case Bytecodes.FSTORE:
|
||||
i32[lp + code[pc++]] = i32[--sp];
|
||||
|
@ -739,7 +819,7 @@ module J2ME {
|
|||
array[index] = value;
|
||||
continue;
|
||||
case Bytecodes.FASTORE:
|
||||
value = i32[--sp];
|
||||
value = f32[--sp];
|
||||
index = i32[--sp];
|
||||
array = ref[--sp];
|
||||
if ((index >>> 0) >= (array.length >>> 0)) {
|
||||
|
@ -774,22 +854,46 @@ module J2ME {
|
|||
}
|
||||
array[index] = value;
|
||||
continue;
|
||||
// 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.LASTORE:
|
||||
lh = i32[--sp];
|
||||
ll = i32[--sp];
|
||||
index = i32[--sp];
|
||||
array = ref[--sp];
|
||||
if ((index >>> 0) >= (array.length >>> 0)) {
|
||||
throw $.newArrayIndexOutOfBoundsException(String(index));
|
||||
}
|
||||
array.value[index << 2 ] = ll;
|
||||
array.value[index << 2 + 1] = lh;
|
||||
continue;
|
||||
case Bytecodes.LALOAD:
|
||||
index = i32[--sp];
|
||||
array = ref[--sp];
|
||||
if ((index >>> 0) >= (array.length >>> 0)) {
|
||||
throw $.newArrayIndexOutOfBoundsException(String(index));
|
||||
}
|
||||
i32[sp++] = array.value[index << 2 ];
|
||||
i32[sp++] = array.value[index << 2 + 1];
|
||||
continue;
|
||||
case Bytecodes.DASTORE:
|
||||
sp -= 2;
|
||||
value = bufferView.getFloat64(sp << 2);
|
||||
index = i32[--sp];
|
||||
array = ref[--sp];
|
||||
if ((index >>> 0) >= (array.length >>> 0)) {
|
||||
throw $.newArrayIndexOutOfBoundsException(String(index));
|
||||
}
|
||||
array[index] = value;
|
||||
continue;
|
||||
case Bytecodes.AASTORE:
|
||||
value = ref[--sp];
|
||||
index = i32[--sp];
|
||||
array = ref[--sp];
|
||||
if ((index >>> 0) >= (array.length >>> 0)) {
|
||||
throw $.newArrayIndexOutOfBoundsException(String(index));
|
||||
}
|
||||
checkArrayStore(array, value);
|
||||
array[index] = value;
|
||||
break;
|
||||
case Bytecodes.POP:
|
||||
--sp;
|
||||
continue;
|
||||
|
@ -914,11 +1018,11 @@ module J2ME {
|
|||
}
|
||||
ASM._lDiv((sp - 4) >> 2, (sp - 4) >> 2, (sp - 2) >> 2); sp -= 2;
|
||||
continue;
|
||||
// case Bytecodes.FDIV:
|
||||
// b = stack.pop();
|
||||
// a = stack.pop();
|
||||
// stack.push(Math.fround(a / b));
|
||||
// break;
|
||||
case Bytecodes.FDIV:
|
||||
fb = f32[--sp];
|
||||
fa = f32[--sp];
|
||||
f32[sp++] = Math.fround(fa / fb);
|
||||
break;
|
||||
case Bytecodes.DDIV:
|
||||
fb = popF64();
|
||||
fa = popF64();
|
||||
|
@ -936,11 +1040,11 @@ module J2ME {
|
|||
}
|
||||
ASM._lRem((sp - 4) >> 2, (sp - 4) >> 2, (sp - 2) >> 2); sp -= 2;
|
||||
continue;
|
||||
// case Bytecodes.FREM:
|
||||
// b = stack.pop();
|
||||
// a = stack.pop();
|
||||
// stack.push(Math.fround(a % b));
|
||||
// break;
|
||||
case Bytecodes.FREM:
|
||||
fb = f32[--sp];
|
||||
fa = f32[--sp];
|
||||
f32[sp++] = Math.fround(fa % fb);
|
||||
break;
|
||||
// case Bytecodes.DREM:
|
||||
// b = stack.pop2();
|
||||
// a = stack.pop2();
|
||||
|
@ -1000,69 +1104,38 @@ module J2ME {
|
|||
// 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.LCMP:
|
||||
ASM._lCmp((sp - 4) >> 2, (sp - 4) >> 2, (sp - 2) >> 2); sp -= 3;
|
||||
break;
|
||||
case Bytecodes.FCMPL:
|
||||
case Bytecodes.FCMPG:
|
||||
fb = f32[--sp];
|
||||
fa = f32[--sp];
|
||||
if (isNaN(fa) || isNaN(fb)) {
|
||||
i32[sp++] = op === Bytecodes.FCMPL ? -1 : 1;
|
||||
} else if (fa > fb) {
|
||||
i32[sp++] = 1;
|
||||
} else if (fa < fb) {
|
||||
i32[sp++] = -1;
|
||||
} else {
|
||||
i32[sp++] = 0;
|
||||
}
|
||||
break;
|
||||
case Bytecodes.DCMPL:
|
||||
case Bytecodes.DCMPG:
|
||||
fb = bufferView.getFloat64(sp - 2 << 2);
|
||||
fa = bufferView.getFloat64(sp - 4 << 2);
|
||||
sp -= 4;
|
||||
if (isNaN(fa) || isNaN(fb)) {
|
||||
i32[sp++] = op === Bytecodes.DCMPL ? -1 : 1;
|
||||
} else if (fa > fb) {
|
||||
i32[sp++] = 1;
|
||||
} else if (fa < fb) {
|
||||
i32[sp++] = -1;
|
||||
} else {
|
||||
i32[sp++] = 0;
|
||||
}
|
||||
break;
|
||||
case Bytecodes.IFEQ:
|
||||
targetPC = opPC + (code[pc++] << 8 | code[pc ++]) << 16 >> 16;
|
||||
if (i32[--sp] === 0) {
|
||||
|
@ -1240,70 +1313,50 @@ module J2ME {
|
|||
size = i32[--sp];
|
||||
ref[sp++] = newArray(classInfo.klass, size);
|
||||
continue;
|
||||
// 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;
|
||||
case Bytecodes.MULTIANEWARRAY:
|
||||
index = readU16();
|
||||
classInfo = resolveClass(index, ci);
|
||||
var dimensions = code[pc++];
|
||||
var lengths = new Array(dimensions);
|
||||
for (var i = 0; i < dimensions; i++) {
|
||||
lengths[i] = i32[--sp];
|
||||
}
|
||||
ref[sp++] = J2ME.newMultiArray(classInfo.klass, lengths.reverse());
|
||||
break;
|
||||
case Bytecodes.ARRAYLENGTH:
|
||||
array = ref[--sp];
|
||||
i32[sp++] = array.length;
|
||||
continue;
|
||||
// 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:
|
||||
index = readI16();
|
||||
fieldInfo = cp.resolveField(index, false);
|
||||
object = ref[--sp];
|
||||
pushKind(fieldInfo.kind, fieldInfo.get(object), 0);
|
||||
continue;
|
||||
// case Bytecodes.RESOLVED_GETFIELD:
|
||||
// fieldInfo = <FieldInfo><any>rp[frame.read16()];
|
||||
// object = stack.pop();
|
||||
// stack.pushKind(fieldInfo.kind, fieldInfo.get(object));
|
||||
// break;
|
||||
case Bytecodes.PUTFIELD:
|
||||
index = readI16();
|
||||
fieldInfo = cp.resolveField(index, false);
|
||||
value = popKind(fieldInfo.kind);
|
||||
object = ref[--sp];
|
||||
fieldInfo.set(object, value);
|
||||
// frame.patch(3, Bytecodes.PUTFIELD, Bytecodes.RESOLVED_PUTFIELD);
|
||||
continue;
|
||||
// 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:
|
||||
index = readI16();
|
||||
fieldInfo = cp.resolveField(index, true);
|
||||
classInitAndUnwindCheck(fieldInfo.classInfo, opPC);
|
||||
//if (U) {
|
||||
// return;
|
||||
//}
|
||||
pushKind(fieldInfo.kind, fieldInfo.getStatic(), 0);
|
||||
fieldInfo = cp.resolveField(index, false);
|
||||
if (op === Bytecodes.GETSTATIC) {
|
||||
classInitAndUnwindCheck(fieldInfo.classInfo, opPC);
|
||||
//if (U) {
|
||||
// return;
|
||||
//}
|
||||
object = fieldInfo.classInfo.getStaticObject($.ctx);
|
||||
} else {
|
||||
object = ref[--sp];
|
||||
}
|
||||
pushKindFromAddress(fieldInfo.kind, object._address + fieldInfo.byteOffset);
|
||||
continue;
|
||||
case Bytecodes.PUTFIELD:
|
||||
case Bytecodes.PUTSTATIC:
|
||||
index = readI16();
|
||||
fieldInfo = cp.resolveField(index, true);
|
||||
classInitAndUnwindCheck(fieldInfo.classInfo, opPC);
|
||||
//if (U) {
|
||||
// return;
|
||||
//}
|
||||
fieldInfo.setStatic(popKind(fieldInfo.kind));
|
||||
fieldInfo = cp.resolveField(index, false);
|
||||
if (op === Bytecodes.PUTSTATIC) {
|
||||
classInitAndUnwindCheck(fieldInfo.classInfo, opPC);
|
||||
//if (U) {
|
||||
// return;
|
||||
//}
|
||||
object = fieldInfo.classInfo.getStaticObject($.ctx);
|
||||
popKindIntoAddress(fieldInfo.kind, object._address + fieldInfo.byteOffset);
|
||||
} else {
|
||||
popKindIntoAddress(fieldInfo.kind, ref[sp - (isTwoSlot(fieldInfo.kind) ? 3 : 2)]._address + fieldInfo.byteOffset);
|
||||
sp--;
|
||||
}
|
||||
continue;
|
||||
case Bytecodes.NEW:
|
||||
index = readI16();
|
||||
|
@ -1396,7 +1449,7 @@ module J2ME {
|
|||
|
||||
// Resolve method and do the class init check if necessary.
|
||||
var calleeMethodInfo = cp.resolved[index] || cp.resolveMethod(index, isStatic);
|
||||
var calleeTargetMethodInfo = calleeMethodInfo;
|
||||
var calleeTargetMethodInfo = null;
|
||||
|
||||
var callee = null;
|
||||
object = null;
|
||||
|
@ -1407,13 +1460,13 @@ module J2ME {
|
|||
case Bytecodes.INVOKESPECIAL:
|
||||
checkNull(object);
|
||||
case Bytecodes.INVOKESTATIC:
|
||||
callee = calleeMethodInfo.fn || getLinkedMethod(calleeMethodInfo);
|
||||
calleeTargetMethodInfo = calleeMethodInfo;
|
||||
break;
|
||||
case Bytecodes.INVOKEVIRTUAL:
|
||||
calleeTargetMethodInfo = object.klass.classInfo.vTable[calleeMethodInfo.vTableIndex];
|
||||
break;
|
||||
case Bytecodes.INVOKEINTERFACE:
|
||||
var name = op === Bytecodes.INVOKEVIRTUAL ? calleeMethodInfo.virtualName : calleeMethodInfo.mangledName;
|
||||
callee = object[name];
|
||||
calleeTargetMethodInfo = object.klass.classInfo.iTable[calleeMethodInfo.mangledName];
|
||||
break;
|
||||
default:
|
||||
traceWriter && traceWriter.writeLn("Not Implemented: " + Bytecodes[op]);
|
||||
|
@ -1427,6 +1480,7 @@ module J2ME {
|
|||
--sp; // Pop Reference
|
||||
}
|
||||
saveThreadState();
|
||||
callee = calleeTargetMethodInfo.fn || getLinkedMethod(calleeTargetMethodInfo);
|
||||
result = callee.apply(object, args);
|
||||
loadThreadState();
|
||||
if (calleeMethodInfo.returnKind !== Kind.Void) {
|
||||
|
@ -1463,7 +1517,9 @@ module J2ME {
|
|||
continue;
|
||||
}
|
||||
} catch (e) {
|
||||
// traceWriter.writeLn(jsGlobal.getBacktrace());
|
||||
traceWriter && traceWriter.writeLn("XXXXXX " + e);
|
||||
traceWriter && traceWriter.writeLn(e.stack);
|
||||
// traceWriter && traceWriter.writeLn(jsGlobal.getBacktrace());
|
||||
e = translateException(e);
|
||||
if (!e.klass) {
|
||||
// A non-java exception was thrown. Rethrow so it is not handled by tryCatch.
|
||||
|
@ -1481,9 +1537,6 @@ module J2ME {
|
|||
code = mi.codeAttribute.code;
|
||||
continue;
|
||||
}
|
||||
//frame.set(fp, sp, opPC);
|
||||
// frameView.traceStack(traceWriter);
|
||||
// frame.trace(traceWriter, fieldInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,15 +63,15 @@ module J2ME {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Emit class initializer.
|
||||
writer.enter("function " + mangledClassName + "() {");
|
||||
writer.writeLn("this._address = ASM._gcMalloc(" + classInfo.sizeOfFields + ");");
|
||||
//
|
||||
// Should we or should we not generate hash codes at this point? Eager or lazy, we should at least
|
||||
// initialize it zero to keep object shapes fixed.
|
||||
// writer.writeLn("this._hashCode = $.nextHashCode(this);");
|
||||
writer.writeLn("this._hashCode = 0;");
|
||||
emitFields(classInfo.fTable, false);
|
||||
//writer.writeLn("this._hashCode = 0;");
|
||||
//emitFields(classInfo.fTable, false);
|
||||
writer.leave("}");
|
||||
|
||||
if (emitter.klassHeaderOnly) {
|
||||
|
|
23
native.js
23
native.js
|
@ -429,17 +429,18 @@ Native["java/lang/Double.longBitsToDouble.(J)D"] = (function() {
|
|||
|
||||
Native["java/lang/Throwable.fillInStackTrace.()V"] = function() {
|
||||
this.stackTrace = [];
|
||||
$.ctx.frames.forEach(function(frame) {
|
||||
if (!frame.methodInfo)
|
||||
return;
|
||||
var methodInfo = frame.methodInfo;
|
||||
var methodName = methodInfo.name;
|
||||
if (!methodName)
|
||||
return;
|
||||
var classInfo = methodInfo.classInfo;
|
||||
var className = classInfo.getClassNameSlow();
|
||||
this.stackTrace.unshift({ className: className, methodName: methodName, methodSignature: methodInfo.signature, offset: frame.bci });
|
||||
}.bind(this));
|
||||
J2ME.traceWriter && J2ME.traceWriter.writeLn("REDUX");
|
||||
//$.ctx.frames.forEach(function(frame) {
|
||||
// if (!frame.methodInfo)
|
||||
// return;
|
||||
// var methodInfo = frame.methodInfo;
|
||||
// var methodName = methodInfo.name;
|
||||
// if (!methodName)
|
||||
// return;
|
||||
// var classInfo = methodInfo.classInfo;
|
||||
// var className = classInfo.getClassNameSlow();
|
||||
// this.stackTrace.unshift({ className: className, methodName: methodName, methodSignature: methodInfo.signature, offset: frame.bci });
|
||||
//}.bind(this));
|
||||
};
|
||||
|
||||
Native["java/lang/Throwable.obtainBackTrace.()Ljava/lang/Object;"] = function() {
|
||||
|
|
7
types.ts
7
types.ts
|
@ -80,6 +80,13 @@ module J2ME {
|
|||
}
|
||||
}
|
||||
|
||||
export function kindSize(kind: Kind): number {
|
||||
if (isTwoSlot(kind)) {
|
||||
return 8;
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
||||
export function kindCharacter(kind: Kind): string {
|
||||
switch (kind) {
|
||||
case Kind.Boolean:
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
all: native.cpp
|
||||
# Make sure emcc in your path.
|
||||
emcc -Oz native.cpp -DNDEBUG -o native.raw.js --memory-init-file 0 -s TOTAL_STACK=16384 -s TOTAL_MEMORY=33554432 -s NO_FILESYSTEM=1 -s NO_BROWSER=1 -O3 \
|
||||
-s 'EXPORTED_FUNCTIONS=["_main", "_lAdd", "_lSub", "_lShl", "_lShr", "_lUshr", "_lMul", "_lDiv", "_lRem"]' \
|
||||
-s 'EXPORTED_FUNCTIONS=["_main", "_lAdd", "_lSub", "_lShl", "_lShr", "_lUshr", "_lMul", "_lDiv", "_lRem", "_lCmp", "_gcMalloc"]' \
|
||||
-s 'DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=["memcpy", "memset", "malloc", "free", "puts"]'
|
||||
echo "var ASM = (function(Module) {" >> native.js
|
||||
cat native.raw.js >> native.js
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {}
|
||||
uintptr_t heap = 0, bump = 0;
|
||||
|
||||
extern "C" {
|
||||
void lAdd(int64_t *result, int64_t *l, int64_t *r) {
|
||||
|
@ -27,6 +28,21 @@ extern "C" {
|
|||
void lUshr(int64_t *result, int64_t *l, int32_t v) {
|
||||
*result = (uint64_t)*l >> v;
|
||||
}
|
||||
void lCmp(int32_t *result, int64_t *l, int64_t *r) {
|
||||
if (l > r) {
|
||||
*result = 1;
|
||||
} else if (l < r) {
|
||||
*result = -1;
|
||||
} else {
|
||||
*result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t gcMalloc(int32_t size) {
|
||||
return bump += (size + 3) & ~0x03;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
bump = heap = (uintptr_t)malloc(1024 * 1024 * 16);
|
||||
}
|
67
vm/parser.ts
67
vm/parser.ts
|
@ -584,6 +584,7 @@ module J2ME {
|
|||
public classInfo: ClassInfo;
|
||||
public kind: Kind;
|
||||
public name: string;
|
||||
public byteOffset: number = 0;
|
||||
public utf8Name: Uint8Array;
|
||||
public utf8Signature: Uint8Array;
|
||||
public mangledName: string = null;
|
||||
|
@ -607,21 +608,31 @@ module J2ME {
|
|||
return !!(this.accessFlags & ACCESS_FLAGS.ACC_STATIC);
|
||||
}
|
||||
|
||||
public get(object: java.lang.Object) {
|
||||
return object[this.mangledName];
|
||||
}
|
||||
|
||||
//public get(object: java.lang.Object) {
|
||||
// return object[this.mangledName];
|
||||
//}
|
||||
//
|
||||
public set(object: java.lang.Object, value: any) {
|
||||
object[this.mangledName] = value
|
||||
}
|
||||
|
||||
public getStatic() {
|
||||
return this.get(this.classInfo.getStaticObject($.ctx));
|
||||
}
|
||||
|
||||
public setStatic(value: any) {
|
||||
return this.set(this.classInfo.getStaticObject($.ctx), value);
|
||||
switch (this.kind) {
|
||||
case Kind.Int:
|
||||
i32[object._address + this.byteOffset >> 2] = value;
|
||||
break;
|
||||
case Kind.Reference:
|
||||
ref[object._address + this.byteOffset >> 2] = value;
|
||||
break;
|
||||
default:
|
||||
Debug.assert(false, Kind[this.kind]);
|
||||
}
|
||||
// object[this.mangledName] = value
|
||||
}
|
||||
//
|
||||
//public getStatic() {
|
||||
// return this.get(this.classInfo.getStaticObject($.ctx));
|
||||
//}
|
||||
//
|
||||
//public setStatic(value: any) {
|
||||
// return this.set(this.classInfo.getStaticObject($.ctx), value);
|
||||
//}
|
||||
|
||||
private scanFieldInfoAttributes() {
|
||||
var s = this;
|
||||
|
@ -980,6 +991,8 @@ module J2ME {
|
|||
|
||||
accessFlags: number = 0;
|
||||
vTable: MethodInfo [] = null;
|
||||
// This is not really a table per se, but rather a map.
|
||||
iTable: { [name: string]: MethodInfo; } = Object.create(null);
|
||||
|
||||
// Custom hash map to make vTable name lookups quicker. It maps utf8 method names to indices in
|
||||
// the vTable. A zero value indicate no method by that name exists, while a value > 0 indicates
|
||||
|
@ -990,6 +1003,9 @@ module J2ME {
|
|||
|
||||
fTable: FieldInfo [] = null;
|
||||
|
||||
sizeOfFields: number = 0;
|
||||
sizeOfStaticFields: number = 0;
|
||||
|
||||
klass: Klass = null;
|
||||
private resolvedFlags: ResolvedFlags = ResolvedFlags.None;
|
||||
private fields: (number | FieldInfo) [] = null;
|
||||
|
@ -1119,6 +1135,7 @@ module J2ME {
|
|||
public complete() {
|
||||
if (!this.isInterface) {
|
||||
this.buildVTable();
|
||||
this.buildITable();
|
||||
this.buildFTable();
|
||||
}
|
||||
loadWriter && this.trace(loadWriter);
|
||||
|
@ -1176,7 +1193,27 @@ module J2ME {
|
|||
}
|
||||
}
|
||||
|
||||
private buildITable() {
|
||||
var vTable = this.vTable;
|
||||
var iTable = this.iTable;
|
||||
for (var i = 0; i < vTable.length; i++) {
|
||||
var methodInfo = vTable[i];
|
||||
if (methodInfo.implementsInterface) {
|
||||
release || assert(methodInfo.mangledName);
|
||||
release || assert(!iTable[methodInfo.mangledName]);
|
||||
iTable[methodInfo.mangledName] = methodInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private buildFTable() {
|
||||
if (this.superClass === null) {
|
||||
this.sizeOfFields = 0;
|
||||
this.sizeOfStaticFields = 0;
|
||||
} else {
|
||||
this.sizeOfFields = this.superClass.sizeOfFields;
|
||||
this.sizeOfStaticFields = this.superClass.sizeOfStaticFields;
|
||||
}
|
||||
var superClassFTable = this.superClass ? this.superClass.fTable : null;
|
||||
var fTable = this.fTable = superClassFTable ? superClassFTable.slice() : [];
|
||||
var fields = this.fields;
|
||||
|
@ -1189,8 +1226,12 @@ module J2ME {
|
|||
fieldInfo.fTableIndex = fTable.length;
|
||||
fTable.push(fieldInfo); // Append
|
||||
fieldInfo.mangledName = "f" + fieldInfo.fTableIndex;
|
||||
fieldInfo.byteOffset = this.sizeOfFields;
|
||||
this.sizeOfFields += kindSize(fieldInfo.kind);
|
||||
} else {
|
||||
fieldInfo.mangledName = "s" + i;
|
||||
fieldInfo.byteOffset = this.sizeOfStaticFields;
|
||||
this.sizeOfStaticFields += kindSize(fieldInfo.kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -212,14 +212,9 @@ module J2ME {
|
|||
long: null
|
||||
};
|
||||
|
||||
function Int64Array(size: number) {
|
||||
var array = Array(size);
|
||||
for (var i = 0; i < size; i++) {
|
||||
array[i] = Long.ZERO;
|
||||
}
|
||||
// We can't put the klass on the prototype.
|
||||
(<any>array).klass = Klasses.long;
|
||||
return array;
|
||||
function Int64Array(length: number) {
|
||||
this.value = new Int32Array(length * 2);
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
var arrays = {
|
||||
|
@ -857,6 +852,9 @@ module J2ME {
|
|||
}
|
||||
|
||||
export class RuntimeKlass {
|
||||
|
||||
_address: number;
|
||||
|
||||
templateKlass: Klass;
|
||||
|
||||
/**
|
||||
|
@ -871,6 +869,7 @@ module J2ME {
|
|||
// isRuntimeKlass: boolean;
|
||||
|
||||
constructor(templateKlass: Klass) {
|
||||
this._address = ASM._gcMalloc(templateKlass.classInfo.sizeOfStaticFields);
|
||||
this.templateKlass = templateKlass;
|
||||
}
|
||||
}
|
||||
|
@ -899,26 +898,27 @@ module J2ME {
|
|||
$.setClassInitialized(runtimeKlass);
|
||||
return;
|
||||
}
|
||||
var fields = runtimeKlass.templateKlass.classInfo.getFields();
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
var field = fields[i];
|
||||
if (field.isStatic) {
|
||||
var kind = getSignatureKind(field.utf8Signature);
|
||||
var defaultValue;
|
||||
switch (kind) {
|
||||
case Kind.Reference:
|
||||
defaultValue = null;
|
||||
break;
|
||||
case Kind.Long:
|
||||
defaultValue = Long.ZERO;
|
||||
break;
|
||||
default:
|
||||
defaultValue = 0;
|
||||
break;
|
||||
}
|
||||
field.set(<java.lang.Object><any>runtimeKlass, defaultValue);
|
||||
}
|
||||
}
|
||||
//REDUX: No need.
|
||||
//var fields = runtimeKlass.templateKlass.classInfo.getFields();
|
||||
//for (var i = 0; i < fields.length; i++) {
|
||||
// var field = fields[i];
|
||||
// if (field.isStatic) {
|
||||
// var kind = getSignatureKind(field.utf8Signature);
|
||||
// var defaultValue;
|
||||
// switch (kind) {
|
||||
// case Kind.Reference:
|
||||
// defaultValue = null;
|
||||
// break;
|
||||
// case Kind.Long:
|
||||
// defaultValue = Long.ZERO;
|
||||
// break;
|
||||
// default:
|
||||
// defaultValue = 0;
|
||||
// break;
|
||||
// }
|
||||
// field.set(<java.lang.Object><any>runtimeKlass, defaultValue);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1296,10 +1296,22 @@ module J2ME {
|
|||
release || assert(!field.isStatic, "Static field was defined as instance in BindingsMap");
|
||||
var object = field.isStatic ? klass : klass.prototype;
|
||||
release || assert (!object.hasOwnProperty(fieldName), "Should not overwrite existing properties.");
|
||||
var getter = FunctionUtilities.makeForwardingGetter(field.mangledName);
|
||||
var getter;
|
||||
var setter;
|
||||
if (release) {
|
||||
setter = FunctionUtilities.makeForwardingSetter(field.mangledName);
|
||||
if (true || release) {
|
||||
switch (field.kind) {
|
||||
case Kind.Reference:
|
||||
setter = new Function("value", "ref[this._address + " + field.byteOffset + " >> 2] = value;");
|
||||
getter = new Function("return ref[this._address + " + field.byteOffset + " >> 2];");
|
||||
break;
|
||||
case Kind.Int:
|
||||
setter = new Function("value", "i32[this._address + " + field.byteOffset + " >> 2] = value;");
|
||||
getter = new Function("return i32[this._address + " + field.byteOffset + " >> 2];");
|
||||
break;
|
||||
default:
|
||||
Debug.assert(false, Kind[field.kind]);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
setter = FunctionUtilities.makeDebugForwardingSetter(field.mangledName, getKindCheck(field.kind));
|
||||
}
|
||||
|
@ -1405,7 +1417,7 @@ module J2ME {
|
|||
}
|
||||
linkKlass(methodInfo.classInfo);
|
||||
linkKlassMethod(methodInfo.classInfo.klass, methodInfo);
|
||||
assert (methodInfo.fn);
|
||||
release || assert (methodInfo.fn);
|
||||
return methodInfo.fn;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче