This commit is contained in:
Marco Castelluccio 2015-08-12 15:32:05 +02:00
Родитель 9ed910afbd 54a4f0ab84
Коммит 93d8ed25e7
14 изменённых файлов: 432 добавлений и 87 удалений

73
bench/Arithmetic.java Normal file
Просмотреть файл

@ -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();
}
}

65
bench/Fields.java Normal file
Просмотреть файл

@ -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();
}
}

102
bench/Invoke.java Normal file
Просмотреть файл

@ -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
Просмотреть файл

@ -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.');}");
}

Просмотреть файл

@ -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;