зеркало из https://github.com/mozilla/pluotsorbet.git
Merge branch 'intex-jit' of https://github.com/brendandahl/j2me.js into intex-jit
This commit is contained in:
Коммит
93d8ed25e7
|
@ -0,0 +1,73 @@
|
|||
package benchmark;
|
||||
import com.sun.cldchi.jvm.JVM;
|
||||
|
||||
class Arithmetic {
|
||||
public static void f(int a) {}
|
||||
public static void f(int a, int b) {}
|
||||
public static void f(int a, int b, int c) {}
|
||||
|
||||
public static void f(long a) {}
|
||||
public static void f(long a, long b) {}
|
||||
public static void f(long a, long b, long c) {}
|
||||
|
||||
public static void f(float a) {}
|
||||
public static void f(float a, float b) {}
|
||||
public static void f(float a, float b, float c) {}
|
||||
|
||||
public static void f(double a) {}
|
||||
public static void f(double a, double b) {}
|
||||
public static void f(double a, double b, double c) {}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int i = 0;
|
||||
long l = 0;
|
||||
float f = 123;
|
||||
double d = 0;
|
||||
|
||||
long start = JVM.monotonicTimeMillis();
|
||||
|
||||
for (int k = 0; k < 1000000; k++) {
|
||||
i += 1;
|
||||
i >>= 2;
|
||||
i <<= 3;
|
||||
i &= 4;
|
||||
i |= 5;
|
||||
}
|
||||
|
||||
System.out.println("int: " + (JVM.monotonicTimeMillis() - start)); start = JVM.monotonicTimeMillis();
|
||||
|
||||
for (int k = 0; k < 1000000; k++) {
|
||||
l += 1;
|
||||
l >>= 2;
|
||||
l <<= 3;
|
||||
l &= 4;
|
||||
l |= 5;
|
||||
}
|
||||
|
||||
System.out.println("long: " + (JVM.monotonicTimeMillis() - start)); start = JVM.monotonicTimeMillis();
|
||||
|
||||
for (int k = 0; k < 1000000; k++) {
|
||||
f += 1;
|
||||
f -= 1;
|
||||
f *= 1;
|
||||
f /= 1;
|
||||
f %= 1;
|
||||
f = -f;
|
||||
f = f < f ? f : f;
|
||||
}
|
||||
|
||||
System.out.println("float: " + (JVM.monotonicTimeMillis() - start)); start = JVM.monotonicTimeMillis();
|
||||
|
||||
for (int k = 0; k < 1000000; k++) {
|
||||
d += 1;
|
||||
d -= 1;
|
||||
d *= 1;
|
||||
d /= 1;
|
||||
d %= 1;
|
||||
d = -d;
|
||||
d = d < d ? d : d;
|
||||
}
|
||||
|
||||
System.out.println("double: " + (JVM.monotonicTimeMillis() - start)); start = JVM.monotonicTimeMillis();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package benchmark;
|
||||
import com.sun.cldchi.jvm.JVM;
|
||||
|
||||
class Fields {
|
||||
public static int i;
|
||||
public static long l;
|
||||
public static float f;
|
||||
public static double d;
|
||||
|
||||
public int I;
|
||||
public long L;
|
||||
public float F;
|
||||
public double D;
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
long start = JVM.monotonicTimeMillis();
|
||||
|
||||
// Static Fields
|
||||
|
||||
for (int k = 0; k < 1000000; k++) {
|
||||
i = i; i = i; i = i; i = i; i = i;
|
||||
}
|
||||
System.out.println("static int: " + (JVM.monotonicTimeMillis() - start)); start = JVM.monotonicTimeMillis();
|
||||
|
||||
for (int k = 0; k < 1000000; k++) {
|
||||
l = l; l = l; l = l; l = l; l = l;
|
||||
}
|
||||
System.out.println("static long: " + (JVM.monotonicTimeMillis() - start)); start = JVM.monotonicTimeMillis();
|
||||
|
||||
for (int k = 0; k < 1000000; k++) {
|
||||
f = f; f = f; f = f; f = f; f = f;
|
||||
}
|
||||
System.out.println("static float: " + (JVM.monotonicTimeMillis() - start)); start = JVM.monotonicTimeMillis();
|
||||
|
||||
for (int k = 0; k < 1000000; k++) {
|
||||
d = d; d = d; d = d; d = d; d = d;
|
||||
}
|
||||
System.out.println("static double: " + (JVM.monotonicTimeMillis() - start)); start = JVM.monotonicTimeMillis();
|
||||
|
||||
// Instance Fields
|
||||
|
||||
Fields x = new Fields();
|
||||
|
||||
for (int k = 0; k < 1000000; k++) {
|
||||
x.I = x.I; x.I = x.I; x.I = x.I; x.I = x.I; x.I = x.I;
|
||||
}
|
||||
System.out.println("int: " + (JVM.monotonicTimeMillis() - start)); start = JVM.monotonicTimeMillis();
|
||||
|
||||
for (int k = 0; k < 1000000; k++) {
|
||||
x.L = x.L; x.L = x.L; x.L = x.L; x.L = x.L; x.L = x.L;
|
||||
}
|
||||
System.out.println("long: " + (JVM.monotonicTimeMillis() - start)); start = JVM.monotonicTimeMillis();
|
||||
|
||||
for (int k = 0; k < 1000000; k++) {
|
||||
x.F = x.F; x.F = x.F; x.F = x.F; x.F = x.F; x.F = x.F;
|
||||
}
|
||||
System.out.println("float: " + (JVM.monotonicTimeMillis() - start)); start = JVM.monotonicTimeMillis();
|
||||
|
||||
for (int k = 0; k < 1000000; k++) {
|
||||
x.D = x.D; x.D = x.D; x.D = x.D; x.D = x.D; x.D = x.D;
|
||||
}
|
||||
System.out.println("double: " + (JVM.monotonicTimeMillis() - start)); start = JVM.monotonicTimeMillis();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
package benchmark;
|
||||
import com.sun.cldchi.jvm.JVM;
|
||||
|
||||
class Invoke {
|
||||
public static void f(int a) {}
|
||||
public static void f(int a, int b) {}
|
||||
public static void f(int a, int b, int c) {}
|
||||
public static void f(int a, int b, int c, int d) {}
|
||||
public static void f(int a, int b, int c, int d, int e) {}
|
||||
public static void f(int a, int b, int c, int d, int e, int f) {}
|
||||
public static void f(int a, int b, int c, int d, int e, int f, int g) {}
|
||||
public static void f(int a, int b, int c, int d, int e, int f, int g, int h) {}
|
||||
|
||||
public static void f(long a) {}
|
||||
public static void f(long a, long b) {}
|
||||
public static void f(long a, long b, long c) {}
|
||||
public static void f(long a, long b, long c, long d) {}
|
||||
public static void f(long a, long b, long c, long d, long e) {}
|
||||
public static void f(long a, long b, long c, long d, long e, long f) {}
|
||||
public static void f(long a, long b, long c, long d, long e, long f, long g) {}
|
||||
public static void f(long a, long b, long c, long d, long e, long f, long g, long h) {}
|
||||
|
||||
public static void f(float a) {}
|
||||
public static void f(float a, float b) {}
|
||||
public static void f(float a, float b, float c) {}
|
||||
public static void f(float a, float b, float c, float d) {}
|
||||
public static void f(float a, float b, float c, float d, float e) {}
|
||||
public static void f(float a, float b, float c, float d, float e, float f) {}
|
||||
public static void f(float a, float b, float c, float d, float e, float f, float g) {}
|
||||
public static void f(float a, float b, float c, float d, float e, float f, float g, float h) {}
|
||||
|
||||
public static void f(double a) {}
|
||||
public static void f(double a, double b) {}
|
||||
public static void f(double a, double b, double c) {}
|
||||
public static void f(double a, double b, double c, double d) {}
|
||||
public static void f(double a, double b, double c, double d, double e) {}
|
||||
public static void f(double a, double b, double c, double d, double e, double f) {}
|
||||
public static void f(double a, double b, double c, double d, double e, double f, double g) {}
|
||||
public static void f(double a, double b, double c, double d, double e, double f, double g, double h) {}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
int i = 0;
|
||||
long l = 0;
|
||||
float f = 0;
|
||||
double d = 0;
|
||||
|
||||
long start = JVM.monotonicTimeMillis();
|
||||
|
||||
for (int k = 0; k < 1000000; k++) {
|
||||
f(i);
|
||||
f(i, i);
|
||||
f(i, i, i);
|
||||
f(i, i, i, i);
|
||||
f(i, i, i, i, i);
|
||||
f(i, i, i, i, i, i);
|
||||
f(i, i, i, i, i, i, i);
|
||||
f(i, i, i, i, i, i, i, i);
|
||||
}
|
||||
|
||||
System.out.println("int: " + (JVM.monotonicTimeMillis() - start)); start = JVM.monotonicTimeMillis();
|
||||
|
||||
for (int k = 0; k < 1000000; k++) {
|
||||
f(l);
|
||||
f(l, l);
|
||||
f(l, l, l);
|
||||
f(l, l, l, l);
|
||||
f(l, l, l, l, l);
|
||||
f(l, l, l, l, l, l);
|
||||
f(l, l, l, l, l, l, l);
|
||||
f(l, l, l, l, l, l, l, l);
|
||||
}
|
||||
|
||||
System.out.println("long: " + (JVM.monotonicTimeMillis() - start)); start = JVM.monotonicTimeMillis();
|
||||
|
||||
for (int k = 0; k < 1000000; k++) {
|
||||
f(f);
|
||||
f(f, f);
|
||||
f(f, f, f);
|
||||
f(f, f, f, f);
|
||||
f(f, f, f, f, f);
|
||||
f(f, f, f, f, f, f);
|
||||
f(f, f, f, f, f, f, f);
|
||||
f(f, f, f, f, f, f, f, f);
|
||||
}
|
||||
|
||||
System.out.println("float: " + (JVM.monotonicTimeMillis() - start)); start = JVM.monotonicTimeMillis();
|
||||
|
||||
for (int k = 0; k < 1000000; k++) {
|
||||
f(d);
|
||||
f(d, d);
|
||||
f(d, d, d);
|
||||
f(d, d, d, d);
|
||||
f(d, d, d, d, d);
|
||||
f(d, d, d, d, d, d);
|
||||
f(d, d, d, d, d, d, d);
|
||||
f(d, d, d, d, d, d, d, d);
|
||||
}
|
||||
|
||||
System.out.println("double: " + (JVM.monotonicTimeMillis() - start)); start = JVM.monotonicTimeMillis();
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ class IFaceImpl implements IFace {
|
|||
class InvokeInterface {
|
||||
public static void main(String[] args) {
|
||||
IFace foo = new IFaceImpl();
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
for (int i = 0; i < 10000000; i++) {
|
||||
foo.method();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ class InvokeStatic {
|
|||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
for (int i = 0; i < 10000000; i++) {
|
||||
staticus();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ class NextClass extends BaseClass {
|
|||
class InvokeVirtual {
|
||||
public static void main(String[] args) {
|
||||
NextClass foo = new NextClass();
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
for (int i = 0; i < 10000000; i++) {
|
||||
foo.method();
|
||||
}
|
||||
}
|
||||
|
|
90
int.ts
90
int.ts
|
@ -325,6 +325,8 @@ module J2ME {
|
|||
*/
|
||||
pc: number
|
||||
|
||||
nativeFrameCount: number;
|
||||
|
||||
/**
|
||||
* Context associated with this thread.
|
||||
*/
|
||||
|
@ -353,6 +355,7 @@ module J2ME {
|
|||
this.ctx = ctx;
|
||||
this.unwoundNativeFrames = [];
|
||||
this.pendingNativeFrames = [];
|
||||
this.nativeFrameCount = 0;
|
||||
release || threadWriter && threadWriter.writeLn("creatingThread: tp: " + toHEX(this.tp) + " " + toHEX(this.tp + Constants.MAX_STACK_SIZE));
|
||||
}
|
||||
|
||||
|
@ -374,6 +377,9 @@ module J2ME {
|
|||
}
|
||||
|
||||
pushMarkerFrame(frameType: FrameType) {
|
||||
if (frameType === FrameType.Native) {
|
||||
this.nativeFrameCount++;
|
||||
}
|
||||
this.pushFrame(null, 0, 0, null, frameType);
|
||||
}
|
||||
|
||||
|
@ -394,6 +400,9 @@ module J2ME {
|
|||
}
|
||||
|
||||
popMarkerFrame(frameType: FrameType): MethodInfo {
|
||||
if (frameType === FrameType.Native) {
|
||||
this.nativeFrameCount--;
|
||||
}
|
||||
return this.popFrame(undefined, frameType);
|
||||
}
|
||||
|
||||
|
@ -504,7 +513,7 @@ module J2ME {
|
|||
tracePendingFrames(writer: IndentingWriter) {
|
||||
for (var i = 0; i < this.pendingNativeFrames.length; i++) {
|
||||
var pendingFrame = this.pendingNativeFrames[i];
|
||||
writer.writeLn(pendingFrame ? pendingFrame.methodInfo.implKey : "-marker-");
|
||||
writer.writeLn(pendingFrame ? methodIdToMethodInfoMap[i32[pendingFrame + BailoutFrameLayout.MethodInfoIdOffset >> 2]].implKey : "-marker-");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -525,26 +534,29 @@ module J2ME {
|
|||
// We should have a |PushPendingFrames| marker frame on the stack at this point.
|
||||
this.popMarkerFrame(FrameType.PushPendingFrames);
|
||||
|
||||
var pendingNativeFrame = null;
|
||||
var pendingNativeFrameAddress = null;
|
||||
var frames = [];
|
||||
while (pendingNativeFrame = this.pendingNativeFrames.pop()) {
|
||||
frames.push(pendingNativeFrame);
|
||||
while (pendingNativeFrameAddress = this.pendingNativeFrames.pop()) {
|
||||
frames.push(pendingNativeFrameAddress);
|
||||
}
|
||||
while (pendingNativeFrame = frames.pop()) {
|
||||
traceWriter && traceWriter.writeLn("Pushing frame: " + pendingNativeFrame.methodInfo.implKey);
|
||||
this.pushFrame(pendingNativeFrame.methodInfo, pendingNativeFrame.stack.length, pendingNativeFrame.pc, pendingNativeFrame.lockObject);
|
||||
// TODO: Figure out how to copy floats and doubles.
|
||||
while (pendingNativeFrameAddress = frames.pop()) {
|
||||
var methodInfo = methodIdToMethodInfoMap[i32[pendingNativeFrameAddress + BailoutFrameLayout.MethodInfoIdOffset >> 2]];
|
||||
var stackCount = i32[pendingNativeFrameAddress + BailoutFrameLayout.StackCountOffset >> 2];
|
||||
var localCount = i32[pendingNativeFrameAddress + BailoutFrameLayout.LocalCountOffset >> 2];
|
||||
var pc = i32[pendingNativeFrameAddress + BailoutFrameLayout.PCOffset >> 2];
|
||||
var lockObjectAddress = i32[pendingNativeFrameAddress + BailoutFrameLayout.LockOffset >> 2];
|
||||
traceWriter && traceWriter.writeLn("Pushing frame: " + methodInfo.implKey);
|
||||
this.pushFrame(methodInfo, stackCount, pc, lockObjectAddress);
|
||||
var frame = this.frame;
|
||||
for (var j = 0; j < pendingNativeFrame.local.length; j++) {
|
||||
var value = pendingNativeFrame.local[j];
|
||||
var kind = typeof value === "object" ? Kind.Reference : Kind.Int;
|
||||
frame.setParameter(kind, j, value);
|
||||
for (var j = 0; j < localCount; j++) {
|
||||
var value = i32[(pendingNativeFrameAddress + BailoutFrameLayout.HeaderSize >> 2) + j];
|
||||
frame.setParameter(Kind.Int, j, value);
|
||||
}
|
||||
for (var j = 0; j < pendingNativeFrame.stack.length; j++) {
|
||||
var value = pendingNativeFrame.stack[j];
|
||||
var kind = typeof value === "object" ? Kind.Reference : Kind.Int;
|
||||
frame.setStackSlot(kind, j, value);
|
||||
for (var j = 0; j < stackCount; j++) {
|
||||
var value = i32[(pendingNativeFrameAddress + BailoutFrameLayout.HeaderSize >> 2) + j + localCount];
|
||||
frame.setStackSlot(Kind.Int, j, value);
|
||||
}
|
||||
ASM._gcFree(pendingNativeFrameAddress);
|
||||
}
|
||||
var frameType = i32[this.fp + FrameLayout.FrameTypeOffset] & FrameLayout.FrameTypeMask;
|
||||
|
||||
|
@ -618,7 +630,7 @@ module J2ME {
|
|||
var method = function fastInterpreterFrameAdapter() {
|
||||
var calleeStats = methodInfo.stats;
|
||||
calleeStats.interpreterCallCount++;
|
||||
if (calleeStats.interpreterCallCount + calleeStats.backwardsBranchCount > ConfigConstants.InvokeThreshold) {
|
||||
if (calleeStats.interpreterCallCount + calleeStats.backwardsBranchCount > ConfigThresholds.InvokeThreshold) {
|
||||
compileAndLinkMethod(methodInfo);
|
||||
if(methodInfo.state === MethodState.Compiled) {
|
||||
return methodInfo.fn.apply(null, arguments);
|
||||
|
@ -731,7 +743,7 @@ module J2ME {
|
|||
var mi = frame.methodInfo;
|
||||
release || assert(mi, "Must have method info.");
|
||||
mi.stats.interpreterCallCount++;
|
||||
if (mi.state === MethodState.Cold && mi.stats.interpreterCallCount + mi.stats.backwardsBranchCount > ConfigConstants.InvokeThreshold) {
|
||||
if (mi.state === MethodState.Cold && mi.stats.interpreterCallCount + mi.stats.backwardsBranchCount > ConfigThresholds.InvokeThreshold) {
|
||||
compileAndLinkMethod(mi);
|
||||
// TODO call the compiled method.
|
||||
}
|
||||
|
@ -1332,7 +1344,7 @@ module J2ME {
|
|||
case Bytecodes.FCMPG:
|
||||
var FCMP_fb = f32[--sp];
|
||||
var FCMP_fa = f32[--sp];
|
||||
if (isNaN(FCMP_fa) || isNaN(FCMP_fb)) {
|
||||
if (FCMP_fa !== FCMP_fa || FCMP_fb !== FCMP_fb) {
|
||||
i32[sp++] = op === Bytecodes.FCMPL ? -1 : 1;
|
||||
} else if (FCMP_fa > FCMP_fb) {
|
||||
i32[sp++] = 1;
|
||||
|
@ -1351,7 +1363,7 @@ module J2ME {
|
|||
aliasedI32[1] = i32[sp - 3];
|
||||
var DCMP_fa = aliasedF64[0];
|
||||
sp -= 4;
|
||||
if (isNaN(DCMP_fa) || isNaN(DCMP_fb)) {
|
||||
if (DCMP_fa !== DCMP_fa || DCMP_fb !== DCMP_fb) {
|
||||
i32[sp++] = op === Bytecodes.DCMPL ? -1 : 1;
|
||||
} else if (DCMP_fa > DCMP_fb) {
|
||||
i32[sp++] = 1;
|
||||
|
@ -1541,7 +1553,7 @@ module J2ME {
|
|||
jumpOffset = ((code[pc++] << 8 | code[pc++]) << 16 >> 16);
|
||||
if (jumpOffset < 0) {
|
||||
mi.stats.backwardsBranchCount++;
|
||||
if (mi.state === MethodState.Cold && mi.stats.interpreterCallCount + mi.stats.backwardsBranchCount > ConfigConstants.BackwardBranchThreshold) {
|
||||
if (mi.state === MethodState.Cold && mi.stats.interpreterCallCount + mi.stats.backwardsBranchCount > ConfigThresholds.BackwardBranchThreshold) {
|
||||
compileAndLinkMethod(mi);
|
||||
}
|
||||
if (enableOnStackReplacement && mi.state === MethodState.Compiled) {
|
||||
|
@ -1550,7 +1562,7 @@ module J2ME {
|
|||
// on stack replacement.
|
||||
var previousFrameType = i32[i32[fp + FrameLayout.CallerFPOffset] + FrameLayout.FrameTypeOffset] & FrameLayout.FrameTypeMask;
|
||||
|
||||
if ((previousFrameType === FrameType.Interpreter || previousFrameType === FrameType.ExitInterpreter) && mi.onStackReplacementEntryPoints.indexOf(opPC + jumpOffset) > -1) {
|
||||
if ((previousFrameType === FrameType.Interpreter) && mi.onStackReplacementEntryPoints.indexOf(opPC + jumpOffset) > -1) {
|
||||
traceWriter && traceWriter.writeLn("OSR: " + mi.implKey);
|
||||
onStackReplacementCount++;
|
||||
|
||||
|
@ -1577,6 +1589,7 @@ module J2ME {
|
|||
if (U) {
|
||||
traceWriter && traceWriter.writeLn("<< I Unwind: " + VMState[U]);
|
||||
release || assert(thread.unwoundNativeFrames.length, "Must have unwound frames.");
|
||||
thread.nativeFrameCount--;
|
||||
i32[frameTypeOffset] = FrameType.PushPendingFrames;
|
||||
thread.unwoundNativeFrames.push(null);
|
||||
return;
|
||||
|
@ -1588,27 +1601,6 @@ module J2ME {
|
|||
|
||||
kind = signatureKinds[0];
|
||||
|
||||
if (previousFrameType === FrameType.ExitInterpreter) {
|
||||
thread.set(fp, sp, opPC);
|
||||
switch (kind) {
|
||||
case Kind.Long:
|
||||
case Kind.Double:
|
||||
return returnLong(returnValue, tempReturn0);
|
||||
case Kind.Int:
|
||||
case Kind.Byte:
|
||||
case Kind.Char:
|
||||
case Kind.Float:
|
||||
case Kind.Short:
|
||||
case Kind.Boolean:
|
||||
case Kind.Reference:
|
||||
return returnValue;
|
||||
case Kind.Void:
|
||||
return;
|
||||
default:
|
||||
release || assert(false, "Invalid Kind: " + Kind[kind]);
|
||||
}
|
||||
}
|
||||
|
||||
mi = methodIdToMethodInfoMap[i32[fp + FrameLayout.CalleeMethodInfoOffset] & FrameLayout.CalleeMethodInfoMask];
|
||||
type = i32[fp + FrameLayout.FrameTypeOffset] & FrameLayout.FrameTypeMask;
|
||||
|
||||
|
@ -2083,7 +2075,7 @@ module J2ME {
|
|||
maxLocals = mi.codeAttribute.max_locals;
|
||||
lp = fp - maxLocals;
|
||||
release || traceWriter && traceWriter.outdent();
|
||||
release || traceWriter && traceWriter.writeLn(">> I " + lastMI.implKey);
|
||||
release || traceWriter && traceWriter.writeLn("<< I " + lastMI.implKey);
|
||||
ci = mi.classInfo;
|
||||
cp = ci.constantPool;
|
||||
code = mi.codeAttribute.code;
|
||||
|
@ -2163,7 +2155,7 @@ module J2ME {
|
|||
var calleeStats = calleeTargetMethodInfo.stats;
|
||||
calleeStats.interpreterCallCount++;
|
||||
if (callMethod === false && calleeTargetMethodInfo.state === MethodState.Cold) {
|
||||
if (calleeStats.interpreterCallCount + calleeStats.backwardsBranchCount > ConfigConstants.InvokeThreshold) {
|
||||
if (calleeStats.interpreterCallCount + calleeStats.backwardsBranchCount > ConfigThresholds.InvokeThreshold) {
|
||||
compileAndLinkMethod(calleeTargetMethodInfo);
|
||||
callMethod = calleeTargetMethodInfo.state === MethodState.Compiled;
|
||||
}
|
||||
|
@ -2234,6 +2226,7 @@ module J2ME {
|
|||
if (U) {
|
||||
traceWriter && traceWriter.writeLn("<< I Unwind: " + VMState[U]);
|
||||
release || assert(thread.unwoundNativeFrames.length, "Must have unwound frames.");
|
||||
thread.nativeFrameCount--;
|
||||
i32[frameTypeOffset] = FrameType.PushPendingFrames;
|
||||
thread.unwoundNativeFrames.push(null);
|
||||
return;
|
||||
|
@ -2319,6 +2312,13 @@ module J2ME {
|
|||
release || traceWriter && traceWriter.writeLn(e.stack);
|
||||
// release || traceWriter && traceWriter.writeLn(jsGlobal.getBacktrace());
|
||||
|
||||
// If an exception is thrown from a native there will be a native marker frame at the top of the stack
|
||||
// which will be cut off when the the fp is set on the thread below. To keep the nativeFrameCount in
|
||||
// sync the native marker must be popped.
|
||||
if (thread.fp > fp && thread.frame.type === FrameType.Native) {
|
||||
release || assert(i32[thread.fp + FrameLayout.CallerFPOffset] === fp, "Only one extra frame is on the stack. " + (thread.fp - fp));
|
||||
thread.popMarkerFrame(FrameType.Native);
|
||||
}
|
||||
thread.set(fp, sp, opPC);
|
||||
e = translateException(e);
|
||||
if (!e.classInfo) {
|
||||
|
|
|
@ -67,6 +67,7 @@ module J2ME {
|
|||
"java/lang/Thread.start0.()V": YieldReason.Root,
|
||||
"java/lang/Class.forName0.(Ljava/lang/String;)V": YieldReason.Root,
|
||||
"java/lang/Class.newInstance1.(Ljava/lang/Object;)V": YieldReason.Root,
|
||||
"java/lang/Runtime.gc.()V": YieldReason.Root,
|
||||
// Test Files:
|
||||
"gnu/testlet/vm/NativeTest.throwExceptionAfterPause.()V": YieldReason.Root,
|
||||
"gnu/testlet/vm/NativeTest.returnAfterPause.()I": YieldReason.Root,
|
||||
|
|
|
@ -390,9 +390,7 @@ module J2ME {
|
|||
if (needsTry) {
|
||||
this.bodyEmitter.leaveAndEnter("}catch(ex){");
|
||||
if (this.hasUnwindThrow) {
|
||||
var local = this.local.join(",");
|
||||
var stack = this.stack.join(",");
|
||||
this.bodyEmitter.writeLn("if(U){$.T(" + this.methodInfo.id + ",ex,[" + local + "],[" + stack + "]," + this.lockObject + ");return;}");
|
||||
this.emitBailout(this.bodyEmitter, "ex.getPC()", "ex.getSP()", this.stack);
|
||||
}
|
||||
this.bodyEmitter.writeLn(this.getStackName(0) + "=TE(ex)._address;");
|
||||
this.sp = 1;
|
||||
|
@ -1139,13 +1137,25 @@ module J2ME {
|
|||
emitter.writeLn("U&&B" + this.sp + "(" + pc + ");");
|
||||
this.hasUnwindThrow = true;
|
||||
} else {
|
||||
var local = this.local.join(",");
|
||||
var stack = BaselineCompiler.stackNames.slice(0, this.sp).join(",");
|
||||
emitter.writeLn("if(U){$.B(" + this.methodInfo.id + "," + pc + ",[" + local + "],[" + stack + "]," + this.lockObject + ");return;}");
|
||||
this.emitBailout(emitter, pc, String(this.sp), BaselineCompiler.stackNames.slice(0, this.sp));
|
||||
}
|
||||
baselineCounter && baselineCounter.count("emitUnwind");
|
||||
}
|
||||
|
||||
private emitBailout(emitter: Emitter, pc: string, sp: string, stack: string[]) {
|
||||
var localCount = this.local.length;
|
||||
var args = [this.methodInfo.id, pc, localCount, sp, this.lockObject];
|
||||
for (var i = 0; i < localCount; i++) {
|
||||
args.push(this.local[i]);
|
||||
}
|
||||
for (var i = 0; i < stack.length; i++) {
|
||||
args.push(stack[i]);
|
||||
}
|
||||
emitter.writeLn("if(U){" +
|
||||
"$.B(" + args.join(",") + ");" +
|
||||
"return;}");
|
||||
}
|
||||
|
||||
emitNoUnwindAssertion() {
|
||||
this.blockEmitter.writeLn("if(U){J2ME.Debug.assert(false,'Unexpected unwind.');}");
|
||||
}
|
||||
|
|
30
jsshell.js
30
jsshell.js
|
@ -55,6 +55,9 @@ function parseArguments(options, tokens) {
|
|||
case "string":
|
||||
options[name].value = value;
|
||||
break;
|
||||
case "boolean":
|
||||
options[name].value = value == "true" || value == "yes";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
print("Illegal option: " + name);
|
||||
|
@ -77,6 +80,21 @@ var options = {
|
|||
short: "m",
|
||||
value: -1,
|
||||
type: "number"
|
||||
},
|
||||
"backwardBranchThreshold": {
|
||||
short: "bbt",
|
||||
value: 1,
|
||||
type: "number"
|
||||
},
|
||||
"invokeThreshold": {
|
||||
short: "it",
|
||||
value: 1,
|
||||
type: "number"
|
||||
},
|
||||
"enableOnStackReplacement": {
|
||||
short: "osr",
|
||||
value: true,
|
||||
type: "boolean"
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -244,6 +262,10 @@ try {
|
|||
J2ME.enableRuntimeCompilation = false;
|
||||
J2ME.maxCompiledMethodCount = options.maxCompiledMethodCount.value;
|
||||
|
||||
J2ME.ConfigThresholds.InvokeThreshold = options.invokeThreshold.value;
|
||||
J2ME.ConfigThresholds.BackwardBranchThreshold = options.backwardBranchThreshold.value;
|
||||
J2ME.enableOnStackReplacement = options.enableOnStackReplacement.value;
|
||||
|
||||
start = dateNow();
|
||||
var runtime = jvm.startIsolate0(files[0], config.args);
|
||||
|
||||
|
@ -252,8 +274,12 @@ try {
|
|||
return true;
|
||||
});
|
||||
|
||||
print("Time: " + (dateNow() - start).toFixed(4) + " ms");
|
||||
J2ME.bytecodeCount && print("Bytecodes: " + J2ME.bytecodeCount);
|
||||
print("-------------------------------------------------------");
|
||||
print("Total Time: " + (dateNow() - start).toFixed(4) + " ms");
|
||||
print("bytecodeCount: " + J2ME.bytecodeCount);
|
||||
print("compiledMethodCount: " + J2ME.compiledMethodCount);
|
||||
print("onStackReplacementCount: " + J2ME.onStackReplacementCount);
|
||||
print("-------------------------------------------------------");
|
||||
J2ME.interpreterCounter.traceSorted(new J2ME.IndentingWriter(false, function (x) {
|
||||
print(x);
|
||||
}));
|
||||
|
|
|
@ -505,7 +505,14 @@ Native["java/lang/Runtime.totalMemory.()J"] = function(addr) {
|
|||
};
|
||||
|
||||
Native["java/lang/Runtime.gc.()V"] = function(addr) {
|
||||
ASM._forceCollection();
|
||||
// Force a bailout so that there are no native frames on the stack
|
||||
// so GC can be safely run.
|
||||
asyncImpl("V", new Promise(function(resolve, reject) {
|
||||
setTimeout(function() {
|
||||
ASM._forceCollection();
|
||||
resolve();
|
||||
});
|
||||
}));
|
||||
};
|
||||
|
||||
Native["java/lang/Math.floor.(D)D"] = function(addr, valLow, valHigh) {
|
||||
|
|
|
@ -148,6 +148,12 @@ module J2ME {
|
|||
|
||||
}
|
||||
|
||||
enum ThreadDataLayout {
|
||||
AddressOffset = 0,
|
||||
StackTopOffset = 1,
|
||||
Size = 2
|
||||
}
|
||||
|
||||
export class Context {
|
||||
private static _nextId: number = 0;
|
||||
private static _colors = [
|
||||
|
@ -191,17 +197,17 @@ module J2ME {
|
|||
}
|
||||
|
||||
setUncollectable(this.nativeThread.tp);
|
||||
this.threadData = new Int32Array(ASM.buffer, ASM._gcMallocUncollectable(8), 2);
|
||||
this.threadData[1] = this.nativeThread.tp;
|
||||
this.threadData = new Int32Array(ASM.buffer, ASM._gcMallocUncollectable(ThreadDataLayout.Size << 2), ThreadDataLayout.Size);
|
||||
this.threadData[ThreadDataLayout.StackTopOffset] = this.nativeThread.tp;
|
||||
unsetUncollectable(this.nativeThread.tp);
|
||||
}
|
||||
|
||||
public set threadAddress(addr: number) {
|
||||
this.threadData[0] = addr;
|
||||
this.threadData[ThreadDataLayout.AddressOffset] = addr;
|
||||
}
|
||||
|
||||
public get threadAddress() {
|
||||
return this.threadData[0];
|
||||
return this.threadData[ThreadDataLayout.AddressOffset];
|
||||
}
|
||||
|
||||
public static color(id) {
|
||||
|
@ -311,6 +317,7 @@ module J2ME {
|
|||
// Rethrow so the exception is not silent.
|
||||
throw "classInfo" in e ? e.classInfo : e;
|
||||
}
|
||||
release || assert(this.nativeThread.nativeFrameCount === 0, "All native frames should be gone.")
|
||||
if (U) {
|
||||
this.nativeThread.endUnwind();
|
||||
switch (U) {
|
||||
|
@ -447,9 +454,9 @@ module J2ME {
|
|||
this.unblock(monitor, "waiting", notifyAll);
|
||||
}
|
||||
|
||||
bailout(methodInfo: MethodInfo, pc: number, local: any [], stack: any [], lockObject: java.lang.Object) {
|
||||
traceWriter && traceWriter.writeLn("Bailout: " + methodInfo.implKey);
|
||||
this.nativeThread.unwoundNativeFrames.push({frameType: FrameType.Interpreter, methodInfo: methodInfo, pc: pc, local: local, stack: stack, lockObject: lockObject});
|
||||
bailout(bailoutFrameAddress: number) {
|
||||
traceWriter && traceWriter.writeLn("Bailout: " + methodIdToMethodInfoMap[i32[bailoutFrameAddress + BailoutFrameLayout.MethodInfoIdOffset >> 2]].implKey);
|
||||
this.nativeThread.unwoundNativeFrames.push(bailoutFrameAddress);
|
||||
}
|
||||
|
||||
pauseMethodTimeline() {
|
||||
|
|
|
@ -9,6 +9,11 @@
|
|||
#include <inttypes.h>
|
||||
#include <emscripten.h>
|
||||
|
||||
// #define GC_NONE 1
|
||||
// #define GC_NONE_HEAP_SIZE (128 * 1024 * 1024)
|
||||
|
||||
uint32_t * heap, * head;
|
||||
|
||||
// Formatting: Printing longs.
|
||||
// printf("L: %" PRId64 ", R: %" PRId64, *l, *r);
|
||||
|
||||
|
@ -56,6 +61,15 @@ extern "C" {
|
|||
}, (int)obj);
|
||||
}
|
||||
|
||||
int stop() {
|
||||
return EM_ASM_INT_V({
|
||||
if (!$) {
|
||||
return 0;
|
||||
}
|
||||
return $.ctx.nativeThread.nativeFrameCount;
|
||||
});
|
||||
}
|
||||
|
||||
uintptr_t gcMallocUncollectable(int32_t size) {
|
||||
return (uintptr_t)GC_MALLOC_UNCOLLECTABLE(size);
|
||||
}
|
||||
|
@ -65,11 +79,28 @@ extern "C" {
|
|||
}
|
||||
|
||||
uintptr_t gcMalloc(int32_t size) {
|
||||
return (uintptr_t)GC_MALLOC_UNCOLLECTABLE(size);
|
||||
#ifdef GC_NONE
|
||||
size = (size + 3) & ~0x03;
|
||||
uint32_t * curr = head;
|
||||
uint32_t * p = head;
|
||||
head += size;
|
||||
if (head > heap + GC_NONE_HEAP_SIZE) {
|
||||
printf("Out of memory, max: %d", GC_NONE_HEAP_SIZE);
|
||||
return 0;
|
||||
}
|
||||
while (curr < head) *curr++ = 0;
|
||||
return (uintptr_t)p;
|
||||
#else
|
||||
return (uintptr_t)GC_MALLOC(size);
|
||||
#endif
|
||||
}
|
||||
|
||||
uintptr_t gcMallocAtomic(int32_t size) {
|
||||
return (uintptr_t)GC_MALLOC_UNCOLLECTABLE(size);
|
||||
#ifdef GC_NONE
|
||||
return gcMalloc(size);
|
||||
#else
|
||||
return (uintptr_t)GC_MALLOC_ATOMIC(size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void gcRegisterDisappearingLink(uintptr_t p, uintptr_t objAddr) {
|
||||
|
@ -98,5 +129,9 @@ extern "C" {
|
|||
|
||||
int main() {
|
||||
GC_set_all_interior_pointers(0);
|
||||
GC_set_stop_func(stop);
|
||||
#ifdef GC_NONE
|
||||
heap = head = (uint32_t *)malloc(GC_NONE_HEAP_SIZE);
|
||||
#endif
|
||||
GC_INIT();
|
||||
}
|
||||
|
|
|
@ -633,20 +633,17 @@ module J2ME {
|
|||
/**
|
||||
* Bailout callback whenever a JIT frame is unwound.
|
||||
*/
|
||||
B(methodInfoId: number, pc: number, local: any [], stack: any [], lockObject: java.lang.Object) {
|
||||
var methodInfo = methodIdToMethodInfoMap[methodInfoId];
|
||||
release || assert(methodInfo !== undefined, "methodInfo undefined in B");
|
||||
this.ctx.bailout(methodInfo, pc, local, stack, lockObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bailout callback whenever a JIT frame is unwound that uses a slightly different calling
|
||||
* convetion that makes it more convenient to emit in some cases.
|
||||
*/
|
||||
T(methodInfoId: number, location: UnwindThrowLocation, local: any [], stack: any [], lockObject: java.lang.Object) {
|
||||
var methodInfo = methodIdToMethodInfoMap[methodInfoId];
|
||||
release || assert(methodInfo !== undefined, "methodInfo undefined in T");
|
||||
this.ctx.bailout(methodInfo, location.getPC(), local, stack.slice(0, location.getSP()), lockObject);
|
||||
B(methodInfoId: number, pc: number, localCount: number, stackCount: number, lockObjectAddress: number) {
|
||||
// TODO: use specialized $.B functions based on the local and stack size so we don't have to use the arguments variable.
|
||||
var bailoutFrameAddress = createBailoutFrame(methodInfoId, pc, localCount, stackCount, lockObjectAddress);
|
||||
var argumentOffset = 5;
|
||||
for (var j = 0; j < localCount; j++) {
|
||||
i32[(bailoutFrameAddress + BailoutFrameLayout.HeaderSize >> 2) + j] = arguments[argumentOffset + j];
|
||||
}
|
||||
for (var j = 0; j < stackCount; j++) {
|
||||
i32[(bailoutFrameAddress + BailoutFrameLayout.HeaderSize >> 2) + j + localCount] = arguments[argumentOffset + localCount + j];
|
||||
}
|
||||
this.ctx.bailout(bailoutFrameAddress);
|
||||
}
|
||||
|
||||
SA(classId: number) {
|
||||
|
@ -669,7 +666,8 @@ module J2ME {
|
|||
nativeBailout(returnKind: Kind, opCode?: Bytecode.Bytecodes) {
|
||||
var pc = returnKind === Kind.Void ? 0 : 1;
|
||||
var methodInfo = CLASSES.getUnwindMethodInfo(returnKind, opCode);
|
||||
$.ctx.bailout(methodInfo, pc, [], [], null);
|
||||
var bailoutFrameAddress = createBailoutFrame(methodInfo.id, pc, 0, 0, Constants.NULL);
|
||||
this.ctx.bailout(bailoutFrameAddress);
|
||||
}
|
||||
|
||||
pause(reason: string) {
|
||||
|
@ -1052,7 +1050,7 @@ module J2ME {
|
|||
}
|
||||
|
||||
// Don't compile if we've compiled too many methods.
|
||||
if (maxCompiledMethodCount > 0 && compiledMethodCount >= maxCompiledMethodCount) {
|
||||
if (maxCompiledMethodCount >= 0 && compiledMethodCount >= maxCompiledMethodCount) {
|
||||
return;
|
||||
}
|
||||
// Don't compile methods that are too large.
|
||||
|
@ -1197,6 +1195,26 @@ module J2ME {
|
|||
NativeMap.delete(addr);
|
||||
}
|
||||
|
||||
export enum BailoutFrameLayout {
|
||||
MethodInfoIdOffset = 0,
|
||||
PCOffset = 4,
|
||||
LocalCountOffset = 8,
|
||||
StackCountOffset = 12,
|
||||
LockOffset = 16,
|
||||
HeaderSize = 20
|
||||
}
|
||||
|
||||
export function createBailoutFrame(methodInfoId: number, pc: number, localCount: number, stackCount: number, lockObjectAddress: number): number {
|
||||
var address = ASM._gcMallocUncollectable(BailoutFrameLayout.HeaderSize + ((localCount + stackCount) << 2));
|
||||
release || assert(typeof methodInfoId === "number" && methodInfoId in methodIdToMethodInfoMap, "Must be valid method info.");
|
||||
i32[address + BailoutFrameLayout.MethodInfoIdOffset >> 2] = methodInfoId;
|
||||
i32[address + BailoutFrameLayout.PCOffset >> 2] = pc;
|
||||
i32[address + BailoutFrameLayout.LocalCountOffset >> 2] = localCount;
|
||||
i32[address + BailoutFrameLayout.StackCountOffset >> 2] = stackCount;
|
||||
i32[address + BailoutFrameLayout.LockOffset >> 2] = lockObjectAddress;
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* A map from Java object addresses to native objects.
|
||||
*
|
||||
|
@ -1484,9 +1502,9 @@ module J2ME {
|
|||
}
|
||||
}
|
||||
|
||||
export enum ConfigConstants {
|
||||
InvokeThreshold = 1,
|
||||
BackwardBranchThreshold = 1
|
||||
export class ConfigThresholds {
|
||||
static InvokeThreshold = 10;
|
||||
static BackwardBranchThreshold = 10;
|
||||
}
|
||||
|
||||
export enum Constants {
|
||||
|
@ -1557,6 +1575,7 @@ module J2ME {
|
|||
getLinkedMethod(CLASSES.java_lang_Class.getMethodByNameString("initialize", "()V"))($.getClassObjectAddress(classInfo));
|
||||
if (U) {
|
||||
i32[frameTypeOffset] = FrameType.PushPendingFrames;
|
||||
thread.nativeFrameCount--;
|
||||
thread.unwoundNativeFrames.push(null);
|
||||
return;
|
||||
}
|
||||
|
@ -1679,7 +1698,7 @@ module J2ME {
|
|||
export function fcmp(a: number, b: number, isLessThan: boolean): number {
|
||||
var x = (aliasedI32[0] = a, aliasedF32[0]);
|
||||
var y = (aliasedI32[0] = b, aliasedF32[0]);
|
||||
if (isNaN(x) || isNaN(y)) {
|
||||
if (x !== x || y !== y) {
|
||||
return isLessThan ? -1 : 1;
|
||||
} else if (x > y) {
|
||||
return 1;
|
||||
|
@ -1698,7 +1717,7 @@ module J2ME {
|
|||
export function dcmp(al: number, ah: number, bl: number, bh: number, isLessThan: boolean) {
|
||||
var x = (aliasedI32[0] = al, aliasedI32[1] = ah, aliasedF64[0]);
|
||||
var y = (aliasedI32[0] = bl, aliasedI32[1] = bh, aliasedF64[0]);
|
||||
if (isNaN(x) || isNaN(y)) {
|
||||
if (x !== x || y !== y) {
|
||||
return isLessThan ? -1 : 1;
|
||||
} else if (x > y) {
|
||||
return 1;
|
||||
|
|
Загрузка…
Ссылка в новой задаче