tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test262-host.js (9261B)


      1 // This Source Code Form is subject to the terms of the Mozilla Public
      2 // License, v. 2.0. If a copy of the MPL was not distributed with this
      3 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
      4 
      5 // https://github.com/tc39/test262/blob/main/INTERPRETING.md#host-defined-functions
      6 ;(function createHostObject(global) {
      7    "use strict";
      8 
      9    // Save built-in functions and constructors.
     10    var FunctionToString = global.Function.prototype.toString;
     11    var ReflectApply = global.Reflect.apply;
     12    var Atomics = global.Atomics;
     13    var Error = global.Error;
     14    var SharedArrayBuffer = global.SharedArrayBuffer;
     15    var Int32Array = global.Int32Array;
     16 
     17    // Save built-in shell functions.
     18    var NewGlobal = global.newGlobal;
     19    var setSharedArrayBuffer = global.setSharedArrayBuffer;
     20    var getSharedArrayBuffer = global.getSharedArrayBuffer;
     21    var evalInWorker = global.evalInWorker;
     22    var monotonicNow = global.monotonicNow;
     23    var gc = global.gc;
     24    var clearKeptObjects = global.clearKeptObjects;
     25 
     26    var hasCreateIsHTMLDDA = "createIsHTMLDDA" in global;
     27    var hasThreads = ("helperThreadCount" in global ? global.helperThreadCount() > 0 : true);
     28    var hasMailbox = typeof setSharedArrayBuffer === "function" && typeof getSharedArrayBuffer === "function";
     29    var hasEvalInWorker = typeof evalInWorker === "function";
     30 
     31    if (!hasCreateIsHTMLDDA && !("document" in global && "all" in global.document))
     32        throw new Error("no [[IsHTMLDDA]] object available for testing");
     33 
     34    var IsHTMLDDA = hasCreateIsHTMLDDA
     35                    ? global.createIsHTMLDDA()
     36                    : global.document.all;
     37 
     38    // The $262.agent framework is not appropriate for browsers yet, and some
     39    // test cases can't work in browsers (they block the main thread).
     40 
     41    var shellCode = hasMailbox && hasEvalInWorker;
     42    var sabTestable = Atomics && SharedArrayBuffer && hasThreads && shellCode;
     43 
     44    global.$262 = {
     45        __proto__: null,
     46        createRealm() {
     47            var newGlobalObject = NewGlobal();
     48            var createHostObjectFn = ReflectApply(FunctionToString, createHostObject, []);
     49            newGlobalObject.Function(`${createHostObjectFn} createHostObject(this);`)();
     50            return newGlobalObject.$262;
     51        },
     52        detachArrayBuffer: global.detachArrayBuffer,
     53        evalScript: global.evaluateScript || global.evaluate,
     54        global,
     55        IsHTMLDDA,
     56        gc() {
     57            gc();
     58        },
     59        clearKeptObjects() {
     60            clearKeptObjects();
     61        },
     62        agent: (function () {
     63 
     64            // SpiderMonkey complication: With run-time argument --no-threads
     65            // our test runner will not properly filter test cases that can't be
     66            // run because agents can't be started, and so we do a little
     67            // filtering here: We will quietly succeed and exit if an agent test
     68            // should not have been run because threads cannot be started.
     69            //
     70            // Firefox complication: The test cases that use $262.agent can't
     71            // currently work in the browser, so for now we rely on them not
     72            // being run at all.
     73 
     74            if (!sabTestable) {
     75                let {reportCompare, quit} = global;
     76 
     77                function notAvailable() {
     78                    // See comment above.
     79                    if (!hasThreads && shellCode) {
     80                        reportCompare(0, 0);
     81                        quit(0);
     82                    }
     83                    throw new Error("Agents not available");
     84                }
     85 
     86                return {
     87                    start(script) { notAvailable() },
     88                    broadcast(sab, id) { notAvailable() },
     89                    getReport() { notAvailable() },
     90                    sleep(s) { notAvailable() },
     91                    monotonicNow,
     92                }
     93            }
     94 
     95            // The SpiderMonkey implementation uses a designated shared buffer _ia
     96            // for coordination, and spinlocks for everything except sleeping.
     97 
     98            var _MSG_LOC = 0;           // Low bit set: broadcast available; High bits: seq #
     99            var _ID_LOC = 1;            // ID sent with broadcast
    100            var _ACK_LOC = 2;           // Worker increments this to ack that broadcast was received
    101            var _RDY_LOC = 3;           // Worker increments this to ack that worker is up and running
    102            var _LOCKTXT_LOC = 4;       // Writer lock for the text buffer: 0=open, 1=closed
    103            var _NUMTXT_LOC = 5;        // Count of messages in text buffer
    104            var _NEXT_LOC = 6;          // First free location in the buffer
    105            var _SLEEP_LOC = 7;         // Used for sleeping
    106 
    107            var _FIRST = 10;            // First location of first message
    108 
    109            var _ia = new Int32Array(new SharedArrayBuffer(65536));
    110            _ia[_NEXT_LOC] = _FIRST;
    111 
    112            var _worker_prefix =
    113 // BEGIN WORKER PREFIX
    114 `if (typeof $262 === 'undefined')
    115    $262 = {};
    116 $262.agent = (function (global) {
    117    var ReflectApply = global.Reflect.apply;
    118    var StringCharCodeAt = global.String.prototype.charCodeAt;
    119    var {
    120        add: Atomics_add,
    121        compareExchange: Atomics_compareExchange,
    122        load: Atomics_load,
    123        store: Atomics_store,
    124        wait: Atomics_wait,
    125    } = global.Atomics;
    126 
    127    var {getSharedArrayBuffer} = global;
    128 
    129    var _finished = { done: false };
    130 
    131    var _ia = new Int32Array(getSharedArrayBuffer());
    132    var agent = {
    133        receiveBroadcast(receiver) {
    134            var k;
    135            while (((k = Atomics_load(_ia, ${_MSG_LOC})) & 1) === 0)
    136                ;
    137            var received_sab = getSharedArrayBuffer();
    138            var received_id = Atomics_load(_ia, ${_ID_LOC});
    139            Atomics_add(_ia, ${_ACK_LOC}, 1);
    140            while (Atomics_load(_ia, ${_MSG_LOC}) === k)
    141                ;
    142            receiver(received_sab, received_id);
    143            waitForDone(_finished);
    144        },
    145 
    146        report(msg) {
    147            while (Atomics_compareExchange(_ia, ${_LOCKTXT_LOC}, 0, 1) === 1)
    148                ;
    149            msg = "" + msg;
    150            var i = _ia[${_NEXT_LOC}];
    151            _ia[i++] = msg.length;
    152            for ( let j=0 ; j < msg.length ; j++ )
    153                _ia[i++] = ReflectApply(StringCharCodeAt, msg, [j]);
    154            _ia[${_NEXT_LOC}] = i;
    155            Atomics_add(_ia, ${_NUMTXT_LOC}, 1);
    156            Atomics_store(_ia, ${_LOCKTXT_LOC}, 0);
    157        },
    158 
    159        sleep(s) {
    160            Atomics_wait(_ia, ${_SLEEP_LOC}, 0, s);
    161        },
    162 
    163        leaving() {
    164            _finished.done = true;
    165        },
    166 
    167        monotonicNow: global.monotonicNow,
    168    };
    169    Atomics_add(_ia, ${_RDY_LOC}, 1);
    170    return agent;
    171 })(this);`;
    172 // END WORKER PREFIX
    173 
    174            var _numWorkers = 0;
    175            var _numReports = 0;
    176            var _reportPtr = _FIRST;
    177            var {
    178                add: Atomics_add,
    179                load: Atomics_load,
    180                store: Atomics_store,
    181                wait: Atomics_wait,
    182            } = Atomics;
    183            var StringFromCharCode = global.String.fromCharCode;
    184 
    185            return {
    186                start(script) {
    187                    setSharedArrayBuffer(_ia.buffer);
    188                    var oldrdy = Atomics_load(_ia, _RDY_LOC);
    189                    evalInWorker(_worker_prefix + script);
    190                    while (Atomics_load(_ia, _RDY_LOC) === oldrdy)
    191                        ;
    192                    _numWorkers++;
    193                },
    194 
    195                broadcast(sab, id) {
    196                    setSharedArrayBuffer(sab);
    197                    Atomics_store(_ia, _ID_LOC, id);
    198                    Atomics_store(_ia, _ACK_LOC, 0);
    199                    Atomics_add(_ia, _MSG_LOC, 1);
    200                    while (Atomics_load(_ia, _ACK_LOC) < _numWorkers)
    201                        ;
    202                    Atomics_add(_ia, _MSG_LOC, 1);
    203                },
    204 
    205                getReport() {
    206                    if (_numReports === Atomics_load(_ia, _NUMTXT_LOC))
    207                        return null;
    208                    var s = "";
    209                    var i = _reportPtr;
    210                    var len = _ia[i++];
    211                    for ( let j=0 ; j < len ; j++ )
    212                        s += StringFromCharCode(_ia[i++]);
    213                    _reportPtr = i;
    214                    _numReports++;
    215                    return s;
    216                },
    217 
    218                sleep(s) {
    219                    Atomics_wait(_ia, _SLEEP_LOC, 0, s);
    220                },
    221 
    222                monotonicNow,
    223            };
    224        })()
    225    };
    226 })(this);
    227 
    228 var $mozAsyncTestDone = false;
    229 function $DONE(failure) {
    230    // This function is generally called from within a Promise handler, so any
    231    // exception thrown by this method will be swallowed and most likely
    232    // ignored by the Promise machinery.
    233    if ($mozAsyncTestDone) {
    234        reportFailure("$DONE() already called");
    235        return;
    236    }
    237    $mozAsyncTestDone = true;
    238 
    239    if (failure)
    240        reportFailure(failure);
    241    else
    242        reportCompare(0, 0);
    243 
    244    if (typeof jsTestDriverEnd === "function") {
    245        gDelayTestDriverEnd = false;
    246        jsTestDriverEnd();
    247    }
    248 }
    249 
    250 // Some tests in test262 leave promise rejections unhandled.
    251 if ("ignoreUnhandledRejections" in this) {
    252  ignoreUnhandledRejections();
    253 }