зеркало из https://github.com/mozilla/pluotsorbet.git
reland thread preemption
This commit is contained in:
Родитель
9c8bdcd97a
Коммит
1e4ed78581
15
context.ts
15
context.ts
|
@ -22,8 +22,9 @@ module J2ME {
|
||||||
Load = 0x10,
|
Load = 0x10,
|
||||||
JIT = 0x20,
|
JIT = 0x20,
|
||||||
Code = 0x40,
|
Code = 0x40,
|
||||||
|
Thread = 0x80,
|
||||||
|
|
||||||
All = Trace | Link | Init | Perf | Load | JIT | Code
|
All = Trace | Link | Init | Perf | Load | JIT | Code | Thread
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -382,6 +383,7 @@ module J2ME {
|
||||||
jitWriter = writers & WriterFlags.JIT ? writer : null;
|
jitWriter = writers & WriterFlags.JIT ? writer : null;
|
||||||
codeWriter = writers & WriterFlags.Code ? writer : null;
|
codeWriter = writers & WriterFlags.Code ? writer : null;
|
||||||
initWriter = writers & WriterFlags.Init ? writer : null;
|
initWriter = writers & WriterFlags.Init ? writer : null;
|
||||||
|
threadWriter = writers & WriterFlags.Thread ? writer : null;
|
||||||
loadWriter = writers & WriterFlags.Load ? writer : null;
|
loadWriter = writers & WriterFlags.Load ? writer : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,17 +564,6 @@ module J2ME {
|
||||||
this.bailoutFrames = [];
|
this.bailoutFrames = [];
|
||||||
}
|
}
|
||||||
var frames = this.frames;
|
var frames = this.frames;
|
||||||
if (windingWriter) {
|
|
||||||
windingWriter.enter("Unwound");
|
|
||||||
frames.map(function (f) {
|
|
||||||
if (Frame.isMarker(f)) {
|
|
||||||
windingWriter.writeLn("- marker -");
|
|
||||||
} else {
|
|
||||||
windingWriter.writeLn((f.methodInfo.state === MethodState.Compiled ? "C" : "I") + " " + f.toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
windingWriter.leave("");
|
|
||||||
}
|
|
||||||
switch (U) {
|
switch (U) {
|
||||||
case VMState.Yielding:
|
case VMState.Yielding:
|
||||||
this.resume();
|
this.resume();
|
||||||
|
|
|
@ -440,6 +440,12 @@ module J2ME {
|
||||||
this.methodInfo.isStatic ? this.runtimeClassObject(this.methodInfo.classInfo) : this.getLocal(0)
|
this.methodInfo.isStatic ? this.runtimeClassObject(this.methodInfo.classInfo) : this.getLocal(0)
|
||||||
: "null";
|
: "null";
|
||||||
|
|
||||||
|
// Insert a preemption check at the top of the method. We can only
|
||||||
|
// do this if the method has the necessary unwinding code.
|
||||||
|
if (canYield(this.methodInfo)) {
|
||||||
|
this.emitPreemptionCheck(this.bodyEmitter, 0);
|
||||||
|
}
|
||||||
|
|
||||||
this.emitEntryPoints();
|
this.emitEntryPoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -852,6 +858,11 @@ module J2ME {
|
||||||
this.emitUnwind(emitter, this.pc, nextPC);
|
this.emitUnwind(emitter, this.pc, nextPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private emitPreemptionCheck(emitter: Emitter, nextPC: number) {
|
||||||
|
emitter.writeLn("CP();");
|
||||||
|
this.emitUnwind(emitter, nextPC, nextPC);
|
||||||
|
}
|
||||||
|
|
||||||
private emitMonitorExit(emitter: Emitter, object: string) {
|
private emitMonitorExit(emitter: Emitter, object: string) {
|
||||||
emitter.writeLn("MX(" + object + ");");
|
emitter.writeLn("MX(" + object + ");");
|
||||||
}
|
}
|
||||||
|
|
4
main.js
4
main.js
|
@ -254,6 +254,10 @@ window.onload = function() {
|
||||||
|
|
||||||
var el = document.getElementById("unwindCount");
|
var el = document.getElementById("unwindCount");
|
||||||
el.textContent = numberWithCommas(J2ME.unwindCount);
|
el.textContent = numberWithCommas(J2ME.unwindCount);
|
||||||
|
|
||||||
|
var el = document.getElementById("preemptionCount");
|
||||||
|
el.textContent = numberWithCommas(J2ME.preemptionCount);
|
||||||
|
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
function dumpCounters() {
|
function dumpCounters() {
|
||||||
|
|
|
@ -611,7 +611,7 @@ Native["java/lang/Thread.sleep.(J)V"] = function(delay) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Native["java/lang/Thread.yield.()V"] = function() {
|
Native["java/lang/Thread.yield.()V"] = function() {
|
||||||
$.yield();
|
$.yield("Thread.yield");
|
||||||
};
|
};
|
||||||
|
|
||||||
Native["java/lang/Thread.activeCount.()I"] = function() {
|
Native["java/lang/Thread.activeCount.()I"] = function() {
|
||||||
|
|
67
runtime.ts
67
runtime.ts
|
@ -88,6 +88,11 @@ module J2ME {
|
||||||
*/
|
*/
|
||||||
export var initWriter = null;
|
export var initWriter = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traces thread execution.
|
||||||
|
*/
|
||||||
|
export var threadWriter = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Traces generated code.
|
* Traces generated code.
|
||||||
*/
|
*/
|
||||||
|
@ -724,16 +729,16 @@ module J2ME {
|
||||||
$.ctx.bailout(methodInfo, bci, nextBCI, local, stack, lockObject);
|
$.ctx.bailout(methodInfo, bci, nextBCI, local, stack, lockObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
yield() {
|
yield(reason: string) {
|
||||||
windingWriter && windingWriter.writeLn("yielding");
|
|
||||||
unwindCount ++;
|
unwindCount ++;
|
||||||
runtimeCounter && runtimeCounter.count("yielding");
|
threadWriter && threadWriter.writeLn("yielding " + reason);
|
||||||
|
runtimeCounter && runtimeCounter.count("yielding " + reason);
|
||||||
U = VMState.Yielding;
|
U = VMState.Yielding;
|
||||||
}
|
}
|
||||||
|
|
||||||
pause(reason: string) {
|
pause(reason: string) {
|
||||||
windingWriter && windingWriter.writeLn("pausing");
|
|
||||||
unwindCount ++;
|
unwindCount ++;
|
||||||
|
threadWriter && threadWriter.writeLn("pausing " + reason);
|
||||||
runtimeCounter && runtimeCounter.count("pausing " + reason);
|
runtimeCounter && runtimeCounter.count("pausing " + reason);
|
||||||
U = VMState.Pausing;
|
U = VMState.Pausing;
|
||||||
}
|
}
|
||||||
|
@ -1787,6 +1792,58 @@ module J2ME {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last time we preempted a thread.
|
||||||
|
*/
|
||||||
|
var lastPreemption = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The preemption check should be quick. We don't always want to measure
|
||||||
|
* time so we use a quick counter and mask to determine when to do the
|
||||||
|
* more expensive preemption check.
|
||||||
|
*/
|
||||||
|
var preemptionSamples = 0;
|
||||||
|
var preemptionSampleMask = 0xFF;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of ms between preemptions, chosen arbitrarily.
|
||||||
|
*/
|
||||||
|
var preemptionInterval = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of preemptions thus far.
|
||||||
|
*/
|
||||||
|
export var preemptionCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Periodically preempts the current thread. Calls to this method are inserted in
|
||||||
|
* methods that can yield.
|
||||||
|
*/
|
||||||
|
export function checkPreemption() {
|
||||||
|
preemptionSamples ++;
|
||||||
|
if ((preemptionSamples & preemptionSampleMask) === 0) {
|
||||||
|
preempt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: We will almost always preempt the next time we call this if the application
|
||||||
|
* has been idle. Figure out a better heurisitc here, maybe measure the frequency at
|
||||||
|
* at which |checkPreemption| is invoked and ony preempt if the frequency is sustained
|
||||||
|
* for a longer period of time *and* the time since we last preempted is above the
|
||||||
|
* |preemptionInterval|.
|
||||||
|
*/
|
||||||
|
function preempt() {
|
||||||
|
var now = performance.now();
|
||||||
|
var elapsed = now - lastPreemption;
|
||||||
|
if (elapsed > preemptionInterval) {
|
||||||
|
lastPreemption = now;
|
||||||
|
preemptionCount ++;
|
||||||
|
threadWriter && threadWriter.writeLn("Preemption timeout: " + elapsed.toFixed(2) + " ms, samples: " + preemptionSamples + ", count: " + preemptionCount);
|
||||||
|
$.yield("preemption");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Runtime = J2ME.Runtime;
|
var Runtime = J2ME.Runtime;
|
||||||
|
@ -1827,3 +1884,5 @@ var CAS = J2ME.checkArrayStore;
|
||||||
var ME = J2ME.monitorEnter;
|
var ME = J2ME.monitorEnter;
|
||||||
var MX = J2ME.monitorExit;
|
var MX = J2ME.monitorExit;
|
||||||
var TE = J2ME.translateException;
|
var TE = J2ME.translateException;
|
||||||
|
|
||||||
|
var CP = J2ME.checkPreemption;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче