Source code

Revision control

Copy as Markdown

Other Tools

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
;(function createHostObject(global) {
"use strict";
// Save built-in functions and constructors.
var FunctionToString = global.Function.prototype.toString;
var ReflectApply = global.Reflect.apply;
var Atomics = global.Atomics;
var Error = global.Error;
var SharedArrayBuffer = global.SharedArrayBuffer;
var Int32Array = global.Int32Array;
// Save built-in shell functions.
var NewGlobal = global.newGlobal;
var setSharedArrayBuffer = global.setSharedArrayBuffer;
var getSharedArrayBuffer = global.getSharedArrayBuffer;
var evalInWorker = global.evalInWorker;
var monotonicNow = global.monotonicNow;
var gc = global.gc;
var clearKeptObjects = global.clearKeptObjects;
var hasCreateIsHTMLDDA = "createIsHTMLDDA" in global;
var hasThreads = ("helperThreadCount" in global ? global.helperThreadCount() > 0 : true);
var hasMailbox = typeof setSharedArrayBuffer === "function" && typeof getSharedArrayBuffer === "function";
var hasEvalInWorker = typeof evalInWorker === "function";
if (!hasCreateIsHTMLDDA && !("document" in global && "all" in global.document))
throw new Error("no [[IsHTMLDDA]] object available for testing");
var IsHTMLDDA = hasCreateIsHTMLDDA
? global.createIsHTMLDDA()
: global.document.all;
// 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,
createRealm() {
var newGlobalObject = NewGlobal();
var createHostObjectFn = ReflectApply(FunctionToString, createHostObject, []);
newGlobalObject.Function(`${createHostObjectFn} createHostObject(this);`)();
return newGlobalObject.$262;
},
detachArrayBuffer: global.detachArrayBuffer,
evalScript: global.evaluateScript || global.evaluate,
global,
IsHTMLDDA,
gc() {
gc();
},
clearKeptObjects() {
clearKeptObjects();
},
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) {
let {reportCompare, quit} = global;
function notAvailable() {
// See comment above.
if (!hasThreads && shellCode) {
reportCompare(0, 0);
quit(0);
}
throw new Error("Agents not available");
}
return {
start(script) { notAvailable() },
broadcast(sab, id) { notAvailable() },
getReport() { notAvailable() },
sleep(s) { notAvailable() },
monotonicNow,
}
}
// 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 (global) {
var ReflectApply = global.Reflect.apply;
var StringCharCodeAt = global.String.prototype.charCodeAt;
var {
add: Atomics_add,
compareExchange: Atomics_compareExchange,
load: Atomics_load,
store: Atomics_store,
wait: Atomics_wait,
} = global.Atomics;
var {getSharedArrayBuffer} = global;
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++] = ReflectApply(StringCharCodeAt, msg, [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() {},
monotonicNow: global.monotonicNow,
};
Atomics_add(_ia, ${_RDY_LOC}, 1);
return agent;
})(this);`;
// END WORKER PREFIX
var _numWorkers = 0;
var _numReports = 0;
var _reportPtr = _FIRST;
var {
add: Atomics_add,
load: Atomics_load,
store: Atomics_store,
wait: Atomics_wait,
} = Atomics;
var StringFromCharCode = global.String.fromCharCode;
return {
start(script) {
setSharedArrayBuffer(_ia.buffer);
var oldrdy = Atomics_load(_ia, _RDY_LOC);
evalInWorker(_worker_prefix + script);
while (Atomics_load(_ia, _RDY_LOC) === oldrdy)
;
_numWorkers++;
},
broadcast(sab, id) {
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) < _numWorkers)
;
Atomics_add(_ia, _MSG_LOC, 1);
},
getReport() {
if (_numReports === Atomics_load(_ia, _NUMTXT_LOC))
return null;
var s = "";
var i = _reportPtr;
var len = _ia[i++];
for ( let j=0 ; j < len ; j++ )
s += StringFromCharCode(_ia[i++]);
_reportPtr = i;
_numReports++;
return s;
},
sleep(s) {
Atomics_wait(_ia, _SLEEP_LOC, 0, s);
},
monotonicNow,
};
})()
};
})(this);
var $mozAsyncTestDone = false;
function $DONE(failure) {
// This function is generally called from within a Promise handler, so any
// exception thrown by this method will be swallowed and most likely
// ignored by the Promise machinery.
if ($mozAsyncTestDone) {
reportFailure("$DONE() already called");
return;
}
$mozAsyncTestDone = true;
if (failure)
reportFailure(failure);
else
reportCompare(0, 0);
if (typeof jsTestDriverEnd === "function") {
gDelayTestDriverEnd = false;
jsTestDriverEnd();
}
}
// Some tests in test262 leave promise rejections unhandled.
if ("ignoreUnhandledRejections" in this) {
ignoreUnhandledRejections();
}