tor-browser

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

basic.js (11619B)


      1 let testModule = `(module
      2  (type $arrayMutI16 (array (mut i16)))
      3 
      4  (func $testImp
      5    (import "wasm:js-string" "test")
      6    (param externref)
      7    (result i32)
      8  )
      9  (func $castImp
     10    (import "wasm:js-string" "cast")
     11    (param externref)
     12    (result (ref extern))
     13  )
     14  (func $fromCharCodeArrayImp
     15    (import "wasm:js-string" "fromCharCodeArray")
     16    (param (ref null $arrayMutI16) i32 i32)
     17    (result (ref extern))
     18  )
     19  (func $intoCharCodeArrayImp
     20    (import "wasm:js-string" "intoCharCodeArray")
     21    (param externref (ref null $arrayMutI16) i32)
     22    (result i32)
     23  )
     24  (func $fromCharCodeImp
     25    (import "wasm:js-string" "fromCharCode")
     26    (param i32)
     27    (result (ref extern))
     28  )
     29  (func $fromCodePointImp
     30    (import "wasm:js-string" "fromCodePoint")
     31    (param i32)
     32    (result (ref extern))
     33  )
     34  (func $charCodeAtImp
     35    (import "wasm:js-string" "charCodeAt")
     36    (param externref i32)
     37    (result i32)
     38  )
     39  (func $codePointAtImp
     40    (import "wasm:js-string" "codePointAt")
     41    (param externref i32)
     42    (result i32)
     43  )
     44  (func $lengthImp
     45    (import "wasm:js-string" "length")
     46    (param externref)
     47    (result i32)
     48  )
     49  (func $concatImp
     50    (import "wasm:js-string" "concat")
     51    (param externref externref)
     52    (result (ref extern))
     53  )
     54  (func $substringImp
     55    (import "wasm:js-string" "substring")
     56    (param externref i32 i32)
     57    (result (ref extern))
     58  )
     59  (func $equalsImp
     60    (import "wasm:js-string" "equals")
     61    (param externref externref)
     62    (result i32)
     63  )
     64  (func $compareImp
     65    (import "wasm:js-string" "compare")
     66    (param externref externref)
     67    (result i32)
     68  )
     69 
     70  (func $test (export "test")
     71    (param externref)
     72    (result i32)
     73    local.get 0
     74    call $testImp
     75  )
     76  (func $cast (export "cast")
     77    (param externref)
     78    (result (ref extern))
     79    local.get 0
     80    call $castImp
     81  )
     82  (func $fromCharCodeArray (export "fromCharCodeArray")
     83    (param (ref null $arrayMutI16) i32 i32)
     84    (result (ref extern))
     85    local.get 0
     86    local.get 1
     87    local.get 2
     88    call $fromCharCodeArrayImp
     89  )
     90  (func $intoCharCodeArray (export "intoCharCodeArray")
     91    (param externref (ref null $arrayMutI16) i32)
     92    (result i32)
     93    local.get 0
     94    local.get 1
     95    local.get 2
     96    call $intoCharCodeArrayImp
     97  )
     98  (func $fromCharCode (export "fromCharCode")
     99    (param i32)
    100    (result externref)
    101    local.get 0
    102    call $fromCharCodeImp
    103  )
    104  (func $fromCodePoint (export "fromCodePoint")
    105    (param i32)
    106    (result externref)
    107    local.get 0
    108    call $fromCodePointImp
    109  )
    110  (func $charCodeAt (export "charCodeAt")
    111    (param externref i32)
    112    (result i32)
    113    local.get 0
    114    local.get 1
    115    call $charCodeAtImp
    116  )
    117  (func $codePointAt (export "codePointAt")
    118    (param externref i32)
    119    (result i32)
    120    local.get 0
    121    local.get 1
    122    call $codePointAtImp
    123  )
    124  (func $length (export "length")
    125    (param externref)
    126    (result i32)
    127    local.get 0
    128    call $lengthImp
    129  )
    130  (func $concat (export "concat")
    131    (param externref externref)
    132    (result externref)
    133    local.get 0
    134    local.get 1
    135    call $concatImp
    136  )
    137  (func $substring (export "substring")
    138    (param externref i32 i32)
    139    (result externref)
    140    local.get 0
    141    local.get 1
    142    local.get 2
    143    call $substringImp
    144  )
    145  (func $equals (export "equals")
    146    (param externref externref)
    147    (result i32)
    148    local.get 0
    149    local.get 1
    150    call $equalsImp
    151  )
    152  (func $compare (export "compare")
    153    (param externref externref)
    154    (result i32)
    155    local.get 0
    156    local.get 1
    157    call $compareImp
    158  )
    159 )`;
    160 
    161 let {
    162  createArrayMutI16,
    163  arrayLength,
    164  arraySet,
    165  arrayGet
    166 } = wasmEvalText(`(module
    167  (type $arrayMutI16 (array (mut i16)))
    168  (func (export "createArrayMutI16") (param i32) (result anyref)
    169    i32.const 0
    170    local.get 0
    171    array.new $arrayMutI16
    172  )
    173  (func (export "arrayLength") (param arrayref) (result i32)
    174    local.get 0
    175    array.len
    176  )
    177  (func (export "arraySet") (param (ref $arrayMutI16) i32 i32)
    178    local.get 0
    179    local.get 1
    180    local.get 2
    181    array.set $arrayMutI16
    182  )
    183  (func (export "arrayGet") (param (ref $arrayMutI16) i32) (result i32)
    184    local.get 0
    185    local.get 1
    186    array.get_u $arrayMutI16
    187  )
    188 )`).exports;
    189 
    190 function throwIfNotString(a) {
    191  if (typeof a !== "string") {
    192    throw new WebAssembly.RuntimeError();
    193  }
    194 }
    195 function throwIfNotStringOrNull(a) {
    196  if (a !== null && typeof a !== "string") {
    197    throw new WebAssembly.RuntimeError();
    198  }
    199 }
    200 let polyFillImports = {
    201  test: (string) => {
    202    if (string === null ||
    203        typeof string !== "string") {
    204      return 0;
    205    }
    206    return 1;
    207  },
    208  cast: (string) => {
    209    if (string === null ||
    210        typeof string !== "string") {
    211      throw new WebAssembly.RuntimeError();
    212    }
    213    return string;
    214  },
    215  fromCharCodeArray: (array, arrayStart, arrayEnd) => {
    216    arrayStart >>>= 0;
    217    arrayEnd >>>= 0;
    218    if (array == null ||
    219        arrayStart > arrayEnd ||
    220        arrayEnd > arrayLength(array)) {
    221      throw new WebAssembly.RuntimeError();
    222    }
    223    let result = '';
    224    for (let i = arrayStart; i < arrayEnd; i++) {
    225      result += String.fromCharCode(arrayGet(array, i));
    226    }
    227    return result;
    228  },
    229  intoCharCodeArray: (string, arr, arrayStart) => {
    230    arrayStart >>>= 0;
    231    throwIfNotString(string);
    232    if (arr == null) {
    233      throw new WebAssembly.RuntimeError();
    234    }
    235    let arrLength = arrayLength(arr);
    236    let stringLength = string.length;
    237    if (BigInt(arrayStart) + BigInt(stringLength) > BigInt(arrLength)) {
    238      throw new WebAssembly.RuntimeError();
    239    }
    240    for (let i = 0; i < stringLength; i++) {
    241      arraySet(arr, arrayStart + i, string[i].charCodeAt(0));
    242    }
    243    return stringLength;
    244  },
    245  fromCharCode: (charCode) => {
    246    charCode >>>= 0;
    247    return String.fromCharCode(charCode);
    248  },
    249  fromCodePoint: (codePoint) => {
    250    codePoint >>>= 0;
    251    return String.fromCodePoint(codePoint);
    252  },
    253  charCodeAt: (string, stringIndex) => {
    254    stringIndex >>>= 0;
    255    throwIfNotString(string);
    256    if (stringIndex >= string.length)
    257      throw new WebAssembly.RuntimeError();
    258    return string.charCodeAt(stringIndex);
    259  },
    260  codePointAt: (string, stringIndex) => {
    261    stringIndex >>>= 0;
    262    throwIfNotString(string);
    263    if (stringIndex >= string.length)
    264      throw new WebAssembly.RuntimeError();
    265    return string.codePointAt(stringIndex);
    266  },
    267  length: (string) => {
    268    throwIfNotString(string);
    269    return string.length;
    270  },
    271  concat: (stringA, stringB) => {
    272    throwIfNotString(stringA);
    273    throwIfNotString(stringB);
    274    return stringA + stringB;
    275  },
    276  substring: (string, startIndex, endIndex) => {
    277    startIndex >>>= 0;
    278    endIndex >>>= 0;
    279    throwIfNotString(string);
    280    if (startIndex > string.length ||
    281        endIndex < startIndex) {
    282      return "";
    283    }
    284    if (endIndex > string.length) {
    285      endIndex = string.length;
    286    }
    287    return string.substring(startIndex, endIndex);
    288  },
    289  equals: (stringA, stringB) => {
    290    throwIfNotStringOrNull(stringA);
    291    throwIfNotStringOrNull(stringB);
    292    return stringA === stringB;
    293  },
    294  compare: (stringA, stringB) => {
    295    throwIfNotString(stringA);
    296    throwIfNotString(stringB);
    297    if (stringA < stringB) {
    298      return -1;
    299    }
    300    return stringA === stringB ? 0 : 1;
    301  },
    302 };
    303 
    304 function assertSameBehavior(funcA, funcB, ...params) {
    305  let resultA;
    306  let errA = null;
    307  try {
    308    resultA = funcA(...params);
    309  } catch (err) {
    310    errA = err;
    311  }
    312 
    313  let resultB;
    314  let errB = null;
    315  try {
    316    resultB = funcB(...params);
    317  } catch (err) {
    318    errB = err;
    319  }
    320 
    321  if (errA || errB) {
    322    assertEq(errA === null, errB === null, errA ? errA.message : errB.message);
    323    assertEq(Object.getPrototypeOf(errA), Object.getPrototypeOf(errB));
    324  }
    325  assertEq(resultA, resultB);
    326 
    327  if (errA) {
    328    throw errA;
    329  }
    330  return resultA;
    331 }
    332 
    333 let builtinExports = wasmEvalText(testModule, {}, {builtins: ["js-string"]}).exports;
    334 let polyfillExports = wasmEvalText(testModule, { 'wasm:js-string': polyFillImports }).exports;
    335 
    336 let testStrings = ["", "a", "1", "ab", "hello, world", "\n", "☺", "☺smiley", String.fromCodePoint(0x10000, 0x10001)];
    337 let testStringsAndNull = [...testStrings, null];
    338 let testCharCodes = [1, 2, 3, 10, 0x7f, 0xff, 0xfffe, 0xffff];
    339 let testCodePoints = [1, 2, 3, 10, 0x7f, 0xff, 0xfffe, 0xffff, 0x10000, 0x10001];
    340 
    341 for (let a of WasmExternrefValues) {
    342  assertSameBehavior(
    343    builtinExports['test'],
    344    polyfillExports['test'],
    345    a
    346  );
    347  try {
    348    assertSameBehavior(
    349      builtinExports['cast'],
    350      polyfillExports['cast'],
    351      a
    352    );
    353  } catch (err) {
    354    assertEq(err instanceof WebAssembly.RuntimeError, true);
    355  }
    356 }
    357 
    358 for (let a of testCharCodes) {
    359  assertSameBehavior(
    360    builtinExports['fromCharCode'],
    361    polyfillExports['fromCharCode'],
    362    a
    363  );
    364 }
    365 
    366 for (let a of testCodePoints) {
    367  assertSameBehavior(
    368    builtinExports['fromCodePoint'],
    369    polyfillExports['fromCodePoint'],
    370    a
    371  );
    372 }
    373 
    374 for (let a of testStrings) {
    375  let length = assertSameBehavior(
    376    builtinExports['length'],
    377    polyfillExports['length'],
    378    a
    379  );
    380 
    381  for (let i = 0; i < length; i++) {
    382    let charCode = assertSameBehavior(
    383      builtinExports['charCodeAt'],
    384      polyfillExports['charCodeAt'],
    385      a, i
    386    );
    387  }
    388  for (let i = 0; i < length; i++) {
    389    let charCode = assertSameBehavior(
    390      builtinExports['codePointAt'],
    391      polyfillExports['codePointAt'],
    392      a, i
    393    );
    394  }
    395 
    396  let arrayMutI16 = createArrayMutI16(length);
    397  assertSameBehavior(
    398    builtinExports['intoCharCodeArray'],
    399    polyfillExports['intoCharCodeArray'],
    400    a, arrayMutI16, 0
    401  );
    402  assertSameBehavior(
    403    builtinExports['fromCharCodeArray'],
    404    polyfillExports['fromCharCodeArray'],
    405    arrayMutI16, 0, length
    406  );
    407 
    408  for (let i = 0; i < length; i++) {
    409    // The end parameter is interpreted as unsigned and is always clamped to
    410    // the string length. This means that -1, and string.length + 1 are valid
    411    // end indices.
    412    for (let j = -1; j <= length + 1; j++) {
    413      assertSameBehavior(
    414        builtinExports['substring'],
    415        polyfillExports['substring'],
    416        a, i, j
    417      );
    418    }
    419  }
    420 }
    421 
    422 for (let a of testStrings) {
    423  for (let b of testStrings) {
    424    assertSameBehavior(
    425      builtinExports['concat'],
    426      polyfillExports['concat'],
    427      a, b
    428    );
    429    assertSameBehavior(
    430      builtinExports['compare'],
    431      polyfillExports['compare'],
    432      a, b
    433    );
    434  }
    435 }
    436 
    437 for (let a of testStringsAndNull) {
    438  for (let b of testStringsAndNull) {
    439    assertSameBehavior(
    440      builtinExports['equals'],
    441      polyfillExports['equals'],
    442      a, b
    443    );
    444  }
    445 }
    446 
    447 // fromCharCodeArray endIndex is an unsigned integer
    448 {
    449  let arrayMutI16 = createArrayMutI16(1);
    450  assertErrorMessage(() => assertSameBehavior(
    451    builtinExports['fromCharCodeArray'],
    452    polyfillExports['fromCharCodeArray'],
    453    arrayMutI16, 1, -1
    454  ), WebAssembly.RuntimeError, /./);
    455 }
    456 
    457 // fromCharCodeArray is startIndex and endIndex, not a count
    458 {
    459  let arrayMutI16 = createArrayMutI16(1);
    460  // Ask for [1, 1) to get an empty string. If misinterpreted as a count, this
    461  // will result in a trap.
    462  assertEq(assertSameBehavior(
    463    builtinExports['fromCharCodeArray'],
    464    polyfillExports['fromCharCodeArray'],
    465    arrayMutI16, 1, 1
    466  ), "");
    467 }
    468 
    469 // fromCharCodeArray array is null
    470 {
    471  assertErrorMessage(() => assertSameBehavior(
    472    builtinExports['fromCharCodeArray'],
    473    polyfillExports['fromCharCodeArray'],
    474    null, 0, 0
    475  ), WebAssembly.RuntimeError, /./);
    476 }
    477 
    478 // intoCharCodeArray array is null
    479 {
    480  assertErrorMessage(() => assertSameBehavior(
    481    builtinExports['intoCharCodeArray'],
    482    polyfillExports['intoCharCodeArray'],
    483    "test", null, 0,
    484  ), WebAssembly.RuntimeError, /./);
    485 }