зеркало из https://github.com/mozilla/pluotsorbet.git
improve locking of class initialization
This commit is contained in:
Родитель
11394b361b
Коммит
eb7b9eec14
60
context.js
60
context.js
|
@ -32,7 +32,6 @@ Context.prototype.popFrame = function() {
|
||||||
Context.prototype.pushClassInitFrame = function(classInfo) {
|
Context.prototype.pushClassInitFrame = function(classInfo) {
|
||||||
if (classInfo.initialized)
|
if (classInfo.initialized)
|
||||||
return;
|
return;
|
||||||
// console.log("starting initialization of", classInfo.className, this.thread.toString());
|
|
||||||
classInfo.thread = this.thread;
|
classInfo.thread = this.thread;
|
||||||
var syntheticMethod = {
|
var syntheticMethod = {
|
||||||
classInfo: {
|
classInfo: {
|
||||||
|
@ -53,8 +52,12 @@ Context.prototype.pushClassInitFrame = function(classInfo) {
|
||||||
code: [
|
code: [
|
||||||
0x2a, // aload_0
|
0x2a, // aload_0
|
||||||
0x59, // dup
|
0x59, // dup
|
||||||
|
0x59, // dup
|
||||||
|
0x59, // dup
|
||||||
|
0xc2, // monitorenter
|
||||||
0xb7, 0x00, 0x01, // invokespecial <idx=1>
|
0xb7, 0x00, 0x01, // invokespecial <idx=1>
|
||||||
0xb7, 0x00, 0x07, // invokespecial <idx=7>
|
0xb7, 0x00, 0x07, // invokespecial <idx=7>
|
||||||
|
0xc3, // monitorexit
|
||||||
0xb1, // return
|
0xb1, // return
|
||||||
],
|
],
|
||||||
exception_table: [],
|
exception_table: [],
|
||||||
|
@ -185,30 +188,6 @@ Context.prototype.resume = function() {
|
||||||
this.start(this.stopFrame);
|
this.start(this.stopFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
Context.prototype.wait = function(obj) {
|
|
||||||
if (!obj.waiters)
|
|
||||||
obj.waiters = [];
|
|
||||||
obj.waiters.push(this);
|
|
||||||
throw VM.Pause;
|
|
||||||
}
|
|
||||||
|
|
||||||
Context.prototype.notify = function(obj) {
|
|
||||||
if (obj.waiters && obj.waiters.length) {
|
|
||||||
if (!obj.ready)
|
|
||||||
obj.ready = [];
|
|
||||||
obj.ready.push(obj.waiters.pop());
|
|
||||||
}
|
|
||||||
if (!obj.ready || !obj.ready.length)
|
|
||||||
return;
|
|
||||||
var ctx = obj.ready.pop();
|
|
||||||
window.setZeroTimeout(VM.execute.bind(null, ctx));
|
|
||||||
}
|
|
||||||
|
|
||||||
Context.prototype.notifyAll = function(obj) {
|
|
||||||
while ((obj.waiters && obj.waiters.length) || (obj.ready && obj.ready.length))
|
|
||||||
this.notify(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
Context.prototype.monitorEnter = function(obj) {
|
Context.prototype.monitorEnter = function(obj) {
|
||||||
var lock = obj.lock;
|
var lock = obj.lock;
|
||||||
if (!lock) {
|
if (!lock) {
|
||||||
|
@ -219,7 +198,10 @@ Context.prototype.monitorEnter = function(obj) {
|
||||||
++lock.count;
|
++lock.count;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.wait(obj);
|
if (!obj.ready)
|
||||||
|
obj.ready = [];
|
||||||
|
obj.ready.push(this);
|
||||||
|
throw VM.Pause;
|
||||||
}
|
}
|
||||||
|
|
||||||
Context.prototype.monitorExit = function(obj) {
|
Context.prototype.monitorExit = function(obj) {
|
||||||
|
@ -232,5 +214,29 @@ Context.prototype.monitorExit = function(obj) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
obj.lock = null;
|
obj.lock = null;
|
||||||
this.notifyAll(obj);
|
if (obj.ready && obj.ready.length) {
|
||||||
|
var ctx = obj.ready.pop();
|
||||||
|
ctx.monitorEnter(obj);
|
||||||
|
ctx.resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Context.prototype.wait = function(obj, timeout) {
|
||||||
|
if (!obj.lock || obj.lock.thread !== this.thread || obj.lock.count !== 1)
|
||||||
|
this.raiseException("java/lang/IllegalMonitorStateException");
|
||||||
|
this.monitorExit(obj);
|
||||||
|
if (!obj.waiting)
|
||||||
|
obj.waiting = [];
|
||||||
|
obj.waiting.push(obj);
|
||||||
|
throw VM.Pause;
|
||||||
|
}
|
||||||
|
|
||||||
|
Context.prototype.notify = function(obj, notifyAll) {
|
||||||
|
if (!obj.lock || obj.lock.thread !== this.thread)
|
||||||
|
this.raiseException("java/lang/IllegalMonitorStateException");
|
||||||
|
while (obj.waiting && obj.waiting.length) {
|
||||||
|
obj.ready.push(obj.waiting.pop());
|
||||||
|
if (!notifyAll)
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
12
native.js
12
native.js
|
@ -103,7 +103,6 @@ Native["java/lang/Object.hashCode.()I"] = function(ctx, stack) {
|
||||||
var hashCode = obj.hashCode;
|
var hashCode = obj.hashCode;
|
||||||
while (!hashCode)
|
while (!hashCode)
|
||||||
hashCode = obj.hashCode = util.id();
|
hashCode = obj.hashCode = util.id();
|
||||||
console.log(hashCode);
|
|
||||||
stack.push(hashCode);
|
stack.push(hashCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +112,11 @@ Native["java/lang/Object.wait.(J)V"] = function(ctx, stack) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Native["java/lang/Class.invoke_clinit.()V"] = function(ctx, stack) {
|
Native["java/lang/Class.invoke_clinit.()V"] = function(ctx, stack) {
|
||||||
var classInfo = stack.pop().vmClass;
|
var classObject = stack.pop();
|
||||||
|
var classInfo = classObject.vmClass;
|
||||||
|
if (classInfo.initialized || classInfo.pending)
|
||||||
|
return;
|
||||||
|
classInfo.pending = true;
|
||||||
var clinit = CLASSES.getMethod(classInfo, "<clinit>", "()V", true);
|
var clinit = CLASSES.getMethod(classInfo, "<clinit>", "()V", true);
|
||||||
if (clinit)
|
if (clinit)
|
||||||
ctx.pushFrame(clinit, 0);
|
ctx.pushFrame(clinit, 0);
|
||||||
|
@ -125,9 +128,10 @@ Native["java/lang/Class.invoke_clinit.()V"] = function(ctx, stack) {
|
||||||
Native["java/lang/Class.init9.()V"] = function(ctx, stack) {
|
Native["java/lang/Class.init9.()V"] = function(ctx, stack) {
|
||||||
var classObject = stack.pop();
|
var classObject = stack.pop();
|
||||||
var classInfo = classObject.vmClass;
|
var classInfo = classObject.vmClass;
|
||||||
|
if (classInfo.initialized)
|
||||||
|
return;
|
||||||
|
classInfo.pending = false;
|
||||||
classInfo.initialized = true;
|
classInfo.initialized = true;
|
||||||
classInfo.thread = null;
|
|
||||||
ctx.notifyAll(classObject);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Native["java/lang/Class.getName.()Ljava/lang/String;"] = function(ctx, stack) {
|
Native["java/lang/Class.getName.()Ljava/lang/String;"] = function(ctx, stack) {
|
||||||
|
|
7
vm.js
7
vm.js
|
@ -95,13 +95,6 @@ VM.execute = function(ctx) {
|
||||||
function classInitCheck(classInfo, ip) {
|
function classInitCheck(classInfo, ip) {
|
||||||
if (classInfo.initialized)
|
if (classInfo.initialized)
|
||||||
return;
|
return;
|
||||||
if (classInfo.thread) {
|
|
||||||
// Nothing to do if class initialization is currently in progress on this thread.
|
|
||||||
if (classInfo.thread === ctx.thread)
|
|
||||||
return;
|
|
||||||
ctx.wait(classInfo.getClassObject());
|
|
||||||
// not reached
|
|
||||||
}
|
|
||||||
frame.ip = ip;
|
frame.ip = ip;
|
||||||
ctx.pushClassInitFrame(classInfo);
|
ctx.pushClassInitFrame(classInfo);
|
||||||
throw VM.Yield;
|
throw VM.Yield;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче