Bug 1346068 - Implement $262.agent. r=shu

--HG--
extra : rebase_source : 73cb86ed09a22a393cdfed0eb6a2be8e13ee0b76
extra : histedit_source : e6cd352554c3c1c8cfe84a4e2f3f692e191279cb
This commit is contained in:
Lars T Hansen 2017-03-24 09:03:32 +01:00
Родитель c055a4757e
Коммит 5669ef5c81
3 изменённых файлов: 339 добавлений и 15 удалений

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

@ -826,21 +826,23 @@ skip script test262/language/expressions/class/gen-method-yield-spread-obj.js
skip script test262/language/expressions/class/dstr-meth-static-dflt-obj-ptrn-rest-val-obj.js
skip script test262/language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-rest-getter.js
# https://bugzilla.mozilla.org/show_bug.cgi?id=1346068
skip script test262/built-ins/Atomics/wait/negative-timeout.js
skip script test262/built-ins/Atomics/wait/was-woken.js
skip script test262/built-ins/Atomics/wait/did-timeout.js
skip script test262/built-ins/Atomics/wait/good-views.js
skip script test262/built-ins/Atomics/wait/no-spurious-wakeup.js
skip script test262/built-ins/Atomics/wait/nan-timeout.js
skip script test262/built-ins/Atomics/wake/wake-all.js
skip script test262/built-ins/Atomics/wake/wake-zero.js
skip script test262/built-ins/Atomics/wake/wake-negative.js
skip script test262/built-ins/Atomics/wake/wake-nan.js
skip script test262/built-ins/Atomics/wake/wake-two.js
skip script test262/built-ins/Atomics/wake/wake-in-order.js
skip script test262/built-ins/Atomics/wake/wake-one.js
skip script test262/built-ins/Atomics/wake/wake-all-on-loc.js
# Dependent on evalInWorker, setSharedArrayBuffer, and
# getSharedArrayBuffer, plus the test cases can't actually run in the
# browser even if that were fixed, https://bugzil.la/1349863
skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wait/negative-timeout.js
skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wait/was-woken.js
skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wait/did-timeout.js
skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wait/good-views.js
skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wait/no-spurious-wakeup.js
skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wait/nan-timeout.js
skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wake/wake-all.js
skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wake/wake-zero.js
skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wake/wake-negative.js
skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wake/wake-nan.js
skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wake/wake-two.js
skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wake/wake-in-order.js
skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wake/wake-one.js
skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wake/wake-all-on-loc.js
# SharedArrayBuffer API pedantry
# https://bugzilla.mozilla.org/show_bug.cgi?id=1346071

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

@ -7,6 +7,21 @@
var FunctionToString = global.Function.prototype.toString;
var ReflectApply = global.Reflect.apply;
var NewGlobal = global.newGlobal;
var Atomics = global.Atomics;
var SharedArrayBuffer = global.SharedArrayBuffer;
var Int32Array = global.Int32Array;
var setSharedArrayBuffer = global.setSharedArrayBuffer;
var getSharedArrayBuffer = global.getSharedArrayBuffer;
var evalInWorker = global.evalInWorker;
var hasThreads = ("helperThreadCount" in global ? global.helperThreadCount() > 0 : true);
var hasMailbox = typeof setSharedArrayBuffer == "function" && typeof getSharedArrayBuffer == "function";
var hasEvalInWorker = typeof evalInWorker == "function";
// The $262.agent framework is not appropriate for browsers yet, and some
// test cases can't work in browsers (they block the main thread).
var shellCode = hasMailbox && hasEvalInWorker;
var sabTestable = Atomics && SharedArrayBuffer && hasThreads && shellCode;
global.$262 = {
__proto__: null,
@ -19,6 +34,152 @@
detachArrayBuffer: global.detachArrayBuffer,
evalScript: global.evaluateScript || global.evaluate,
global,
agent: (function () {
// SpiderMonkey complication: With run-time argument --no-threads
// our test runner will not properly filter test cases that can't be
// run because agents can't be started, and so we do a little
// filtering here: We will quietly succeed and exit if an agent test
// should not have been run because threads cannot be started.
//
// Firefox complication: The test cases that use $262.agent can't
// currently work in the browser, so for now we rely on them not
// being run at all.
if (!sabTestable) {
return {
_notAvailable() {
// See comment above.
if (!hasThreads && shellCode) {
global.reportCompare(0,0);
global.quit(0);
}
throw new Error("Agents not available");
},
start(script) { this._notAvailable() },
broadcast(sab, id) { this._notAvailable() },
getReport() { this._notAvailable() },
sleep(s) { this._notAvailable() }
}
}
// The SpiderMonkey implementation uses a designated shared buffer _ia
// for coordination, and spinlocks for everything except sleeping.
var _MSG_LOC = 0; // Low bit set: broadcast available; High bits: seq #
var _ID_LOC = 1; // ID sent with broadcast
var _ACK_LOC = 2; // Worker increments this to ack that broadcast was received
var _RDY_LOC = 3; // Worker increments this to ack that worker is up and running
var _LOCKTXT_LOC = 4; // Writer lock for the text buffer: 0=open, 1=closed
var _NUMTXT_LOC = 5; // Count of messages in text buffer
var _NEXT_LOC = 6; // First free location in the buffer
var _SLEEP_LOC = 7; // Used for sleeping
var _FIRST = 10; // First location of first message
var _ia = new Int32Array(new SharedArrayBuffer(65536));
_ia[_NEXT_LOC] = _FIRST;
var _worker_prefix =
// BEGIN WORKER PREFIX
`if (typeof $262 == 'undefined')
$262 = {};
$262.agent = (function () {
var _ia = new Int32Array(getSharedArrayBuffer());
var agent = {
receiveBroadcast(receiver) {
var k;
while (((k = Atomics.load(_ia, ${_MSG_LOC})) & 1) == 0)
;
var received_sab = getSharedArrayBuffer();
var received_id = Atomics.load(_ia, ${_ID_LOC});
Atomics.add(_ia, ${_ACK_LOC}, 1);
while (Atomics.load(_ia, ${_MSG_LOC}) == k)
;
receiver(received_sab, received_id);
},
report(msg) {
while (Atomics.compareExchange(_ia, ${_LOCKTXT_LOC}, 0, 1) == 1)
;
msg = "" + msg;
var i = _ia[${_NEXT_LOC}];
_ia[i++] = msg.length;
for ( let j=0 ; j < msg.length ; j++ )
_ia[i++] = msg.charCodeAt(j);
_ia[${_NEXT_LOC}] = i;
Atomics.add(_ia, ${_NUMTXT_LOC}, 1);
Atomics.store(_ia, ${_LOCKTXT_LOC}, 0);
},
sleep(s) {
Atomics.wait(_ia, ${_SLEEP_LOC}, 0, s);
},
leaving() {}
};
Atomics.add(_ia, ${_RDY_LOC}, 1);
return agent;
})();`;
// END WORKER PREFIX
return {
_numWorkers: 0,
_numReports: 0,
_reportPtr: _FIRST,
_bailIfNotAvailable() {
if (!sabTestable) {
// See comment above.
if (!hasThreads && shellCode) {
global.reportCompare(0,0);
global.quit(0);
}
throw new Error("Agents not available");
}
},
start(script) {
this._bailIfNotAvailable();
setSharedArrayBuffer(_ia.buffer);
var oldrdy = Atomics.load(_ia, _RDY_LOC);
evalInWorker(_worker_prefix + script);
while (Atomics.load(_ia, _RDY_LOC) == oldrdy)
;
this._numWorkers++;
},
broadcast(sab, id) {
this._bailIfNotAvailable();
setSharedArrayBuffer(sab);
Atomics.store(_ia, _ID_LOC, id);
Atomics.store(_ia, _ACK_LOC, 0);
Atomics.add(_ia, _MSG_LOC, 1);
while (Atomics.load(_ia, _ACK_LOC) < this._numWorkers)
;
Atomics.add(_ia, _MSG_LOC, 1);
},
getReport() {
this._bailIfNotAvailable();
if (this._numReports == Atomics.load(_ia, _NUMTXT_LOC))
return null;
var s = "";
var i = this._reportPtr;
var len = _ia[i++];
for ( let j=0 ; j < len ; j++ )
s += String.fromCharCode(_ia[i++]);
this._reportPtr = i;
this._numReports++;
return s;
},
sleep(s) {
this._bailIfNotAvailable();
Atomics.wait(_ia, _SLEEP_LOC, 0, s);
},
};
})()
};
})(this);

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

@ -243,6 +243,21 @@ function testFailed(message) {
var FunctionToString = global.Function.prototype.toString;
var ReflectApply = global.Reflect.apply;
var NewGlobal = global.newGlobal;
var Atomics = global.Atomics;
var SharedArrayBuffer = global.SharedArrayBuffer;
var Int32Array = global.Int32Array;
var setSharedArrayBuffer = global.setSharedArrayBuffer;
var getSharedArrayBuffer = global.getSharedArrayBuffer;
var evalInWorker = global.evalInWorker;
var hasThreads = ("helperThreadCount" in global ? global.helperThreadCount() > 0 : true);
var hasMailbox = typeof setSharedArrayBuffer == "function" && typeof getSharedArrayBuffer == "function";
var hasEvalInWorker = typeof evalInWorker == "function";
// The $262.agent framework is not appropriate for browsers yet, and some
// test cases can't work in browsers (they block the main thread).
var shellCode = hasMailbox && hasEvalInWorker;
var sabTestable = Atomics && SharedArrayBuffer && hasThreads && shellCode;
global.$262 = {
__proto__: null,
@ -255,6 +270,152 @@ function testFailed(message) {
detachArrayBuffer: global.detachArrayBuffer,
evalScript: global.evaluateScript || global.evaluate,
global,
agent: (function () {
// SpiderMonkey complication: With run-time argument --no-threads
// our test runner will not properly filter test cases that can't be
// run because agents can't be started, and so we do a little
// filtering here: We will quietly succeed and exit if an agent test
// should not have been run because threads cannot be started.
//
// Firefox complication: The test cases that use $262.agent can't
// currently work in the browser, so for now we rely on them not
// being run at all.
if (!sabTestable) {
return {
_notAvailable() {
// See comment above.
if (!hasThreads && shellCode) {
global.reportCompare(0,0);
global.quit(0);
}
throw new Error("Agents not available");
},
start(script) { this._notAvailable() },
broadcast(sab, id) { this._notAvailable() },
getReport() { this._notAvailable() },
sleep(s) { this._notAvailable() }
}
}
// The SpiderMonkey implementation uses a designated shared buffer _ia
// for coordination, and spinlocks for everything except sleeping.
var _MSG_LOC = 0; // Low bit set: broadcast available; High bits: seq #
var _ID_LOC = 1; // ID sent with broadcast
var _ACK_LOC = 2; // Worker increments this to ack that broadcast was received
var _RDY_LOC = 3; // Worker increments this to ack that worker is up and running
var _LOCKTXT_LOC = 4; // Writer lock for the text buffer: 0=open, 1=closed
var _NUMTXT_LOC = 5; // Count of messages in text buffer
var _NEXT_LOC = 6; // First free location in the buffer
var _SLEEP_LOC = 7; // Used for sleeping
var _FIRST = 10; // First location of first message
var _ia = new Int32Array(new SharedArrayBuffer(65536));
_ia[_NEXT_LOC] = _FIRST;
var _worker_prefix =
// BEGIN WORKER PREFIX
`if (typeof $262 == 'undefined')
$262 = {};
$262.agent = (function () {
var _ia = new Int32Array(getSharedArrayBuffer());
var agent = {
receiveBroadcast(receiver) {
var k;
while (((k = Atomics.load(_ia, ${_MSG_LOC})) & 1) == 0)
;
var received_sab = getSharedArrayBuffer();
var received_id = Atomics.load(_ia, ${_ID_LOC});
Atomics.add(_ia, ${_ACK_LOC}, 1);
while (Atomics.load(_ia, ${_MSG_LOC}) == k)
;
receiver(received_sab, received_id);
},
report(msg) {
while (Atomics.compareExchange(_ia, ${_LOCKTXT_LOC}, 0, 1) == 1)
;
msg = "" + msg;
var i = _ia[${_NEXT_LOC}];
_ia[i++] = msg.length;
for ( let j=0 ; j < msg.length ; j++ )
_ia[i++] = msg.charCodeAt(j);
_ia[${_NEXT_LOC}] = i;
Atomics.add(_ia, ${_NUMTXT_LOC}, 1);
Atomics.store(_ia, ${_LOCKTXT_LOC}, 0);
},
sleep(s) {
Atomics.wait(_ia, ${_SLEEP_LOC}, 0, s);
},
leaving() {}
};
Atomics.add(_ia, ${_RDY_LOC}, 1);
return agent;
})();`;
// END WORKER PREFIX
return {
_numWorkers: 0,
_numReports: 0,
_reportPtr: _FIRST,
_bailIfNotAvailable() {
if (!sabTestable) {
// See comment above.
if (!hasThreads && shellCode) {
global.reportCompare(0,0);
global.quit(0);
}
throw new Error("Agents not available");
}
},
start(script) {
this._bailIfNotAvailable();
setSharedArrayBuffer(_ia.buffer);
var oldrdy = Atomics.load(_ia, _RDY_LOC);
evalInWorker(_worker_prefix + script);
while (Atomics.load(_ia, _RDY_LOC) == oldrdy)
;
this._numWorkers++;
},
broadcast(sab, id) {
this._bailIfNotAvailable();
setSharedArrayBuffer(sab);
Atomics.store(_ia, _ID_LOC, id);
Atomics.store(_ia, _ACK_LOC, 0);
Atomics.add(_ia, _MSG_LOC, 1);
while (Atomics.load(_ia, _ACK_LOC) < this._numWorkers)
;
Atomics.add(_ia, _MSG_LOC, 1);
},
getReport() {
this._bailIfNotAvailable();
if (this._numReports == Atomics.load(_ia, _NUMTXT_LOC))
return null;
var s = "";
var i = this._reportPtr;
var len = _ia[i++];
for ( let j=0 ; j < len ; j++ )
s += String.fromCharCode(_ia[i++]);
this._reportPtr = i;
this._numReports++;
return s;
},
sleep(s) {
this._bailIfNotAvailable();
Atomics.wait(_ia, _SLEEP_LOC, 0, s);
},
};
})()
};
})(this);