From efedb002260b402a189dfec5a7a4c9cb74ed1c30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bargull?= Date: Wed, 2 May 2018 09:52:05 -0700 Subject: [PATCH] Bug 1140152 - Copy elements' underlying bit patterns in TypedArray.prototype.slice. r=till --- js/src/builtin/TypedArray.js | 24 +- js/src/tests/jstests.list | 3 - .../tests/non262/TypedArray/slice-bitwise.js | 153 ++++++ .../non262/TypedArray/slice-conversion.js | 515 ++++++++++++++++++ .../tests/non262/TypedArray/slice-memcpy.js | 84 +++ js/src/vm/SelfHosting.cpp | 116 +++- 6 files changed, 880 insertions(+), 15 deletions(-) create mode 100644 js/src/tests/non262/TypedArray/slice-bitwise.js create mode 100644 js/src/tests/non262/TypedArray/slice-conversion.js create mode 100644 js/src/tests/non262/TypedArray/slice-memcpy.js diff --git a/js/src/builtin/TypedArray.js b/js/src/builtin/TypedArray.js index c831f4a1109d..d774a14aff35 100644 --- a/js/src/builtin/TypedArray.js +++ b/js/src/builtin/TypedArray.js @@ -1025,13 +1025,8 @@ function TypedArraySlice(start, end) { // Step 9. var A = TypedArraySpeciesCreateWithLength(O, count); - // Steps 10-13 (Not implemented, bug 1140152). - // Steps 14-15. if (count > 0) { - // Step 14.a. - var n = 0; - // Steps 14.b.ii, 15.b. if (buffer === null) { // A typed array previously using inline storage may acquire a @@ -1042,13 +1037,20 @@ function TypedArraySlice(start, end) { if (IsDetachedBuffer(buffer)) ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED); - // Step 14.b. - while (k < final) { - // Steps 14.b.i-v. - A[n++] = O[k++]; - } + // Steps 10-13, 15. + var sliced = TypedArrayBitwiseSlice(O, A, k | 0, count | 0); - // FIXME: Implement step 15 (bug 1140152). + // Step 14. + if (!sliced) { + // Step 14.a. + var n = 0; + + // Step 14.b. + while (k < final) { + // Steps 14.b.i-v. + A[n++] = O[k++]; + } + } } // Step 16. diff --git a/js/src/tests/jstests.list b/js/src/tests/jstests.list index fa2f0ff87060..c2876411238d 100644 --- a/js/src/tests/jstests.list +++ b/js/src/tests/jstests.list @@ -145,9 +145,6 @@ skip script test262/built-ins/TypedArrayConstructors/internals/Set/key-is-not-in skip script test262/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds.js skip script test262/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-throws.js -# https://bugzilla.mozilla.org/show_bug.cgi?id=1140152 -skip script test262/built-ins/TypedArray/prototype/slice/bit-precision.js - # https://bugzilla.mozilla.org/show_bug.cgi?id=1317405 skip script test262/language/computed-property-names/class/static/method-number.js skip script test262/language/computed-property-names/class/static/method-string.js diff --git a/js/src/tests/non262/TypedArray/slice-bitwise.js b/js/src/tests/non262/TypedArray/slice-bitwise.js new file mode 100644 index 000000000000..ea0a670b1873 --- /dev/null +++ b/js/src/tests/non262/TypedArray/slice-bitwise.js @@ -0,0 +1,153 @@ +// Copies bytes bit-wise if source and target type are the same. +// Only detectable when using floating point typed arrays. +const float32Constructors = anyTypedArrayConstructors.filter(isFloatConstructor) + .filter(c => c.BYTES_PER_ELEMENT === 4); +const float64Constructors = anyTypedArrayConstructors.filter(isFloatConstructor) + .filter(c => c.BYTES_PER_ELEMENT === 8); + +// Also test with cross-compartment typed arrays. +const otherGlobal = newGlobal(); +float32Constructors.push(otherGlobal.Float32Array); +float64Constructors.push(otherGlobal.Float64Array); + +function* p(xs, ys) { + for (let x of xs) { + for (let y of ys) { + yield [x, y]; + } + } +} + +const isLittleEndian = new Uint8Array(new Uint16Array([1]).buffer)[0] !== 0; + +function geti64(i32, i) { + return [i32[2 * i + isLittleEndian], i32[2 * i + !isLittleEndian]]; +} + +function seti64(i32, i, [hi, lo]) { + i32[i * 2 + isLittleEndian] = hi; + i32[i * 2 + !isLittleEndian] = lo; +} + +const NaNs = { + Float32: [ + 0x7F800001|0, // smallest SNaN + 0x7FBFFFFF|0, // largest SNaN + 0x7FC00000|0, // smallest QNaN + 0x7FFFFFFF|0, // largest QNaN + 0xFF800001|0, // smallest SNaN, sign-bit set + 0xFFBFFFFF|0, // largest SNaN, sign-bit set + 0xFFC00000|0, // smallest QNaN, sign-bit set + 0xFFFFFFFF|0, // largest QNaN, sign-bit set + ], + Float64: [ + [0x7FF00000|0, 0x00000001|0], // smallest SNaN + [0x7FF7FFFF|0, 0xFFFFFFFF|0], // largest SNaN + [0x7FF80000|0, 0x00000000|0], // smallest QNaN + [0x7FFFFFFF|0, 0xFFFFFFFF|0], // largest QNaN + [0xFFF00000|0, 0x00000001|0], // smallest SNaN, sign-bit set + [0xFFF7FFFF|0, 0xFFFFFFFF|0], // largest SNaN, sign-bit set + [0xFFF80000|0, 0x00000000|0], // smallest QNaN, sign-bit set + [0xFFFFFFFF|0, 0xFFFFFFFF|0], // largest QNaN, sign-bit set + ], +}; + +const cNaN = { + Float32: new Int32Array(new Float32Array([NaN]).buffer)[0], + Float64: geti64(new Int32Array(new Float64Array([NaN]).buffer), 0), +}; + +// Float32 -> Float32 +for (let [sourceConstructor, targetConstructor] of p(float32Constructors, float32Constructors)) { + let len = NaNs.Float32.length; + let f32 = new sourceConstructor(len); + let i32 = new Int32Array(f32.buffer); + f32.constructor = targetConstructor; + + for (let i = 0; i < len; ++i) { + i32[i] = NaNs.Float32[i]; + } + + let rf32 = f32.slice(0); + let ri32 = new Int32Array(rf32.buffer); + + assertEq(rf32.length, len); + assertEq(ri32.length, len); + + // Same bits. + for (let i = 0; i < len; ++i) { + assertEq(ri32[i], NaNs.Float32[i]); + } +} + +// Float32 -> Float64 +for (let [sourceConstructor, targetConstructor] of p(float32Constructors, float64Constructors)) { + let len = NaNs.Float32.length; + let f32 = new sourceConstructor(len); + let i32 = new Int32Array(f32.buffer); + f32.constructor = targetConstructor; + + for (let i = 0; i < len; ++i) { + i32[i] = NaNs.Float32[i]; + } + + let rf64 = f32.slice(0); + let ri32 = new Int32Array(rf64.buffer); + + assertEq(rf64.length, len); + assertEq(ri32.length, 2 * len); + + // NaN bits canonicalized. + for (let i = 0; i < len; ++i) { + assertEqArray(geti64(ri32, i), cNaN.Float64); + } +} + +// Float64 -> Float64 +for (let [sourceConstructor, targetConstructor] of p(float64Constructors, float64Constructors)) { + let len = NaNs.Float64.length; + let f64 = new sourceConstructor(len); + let i32 = new Int32Array(f64.buffer); + f64.constructor = targetConstructor; + + for (let i = 0; i < len; ++i) { + seti64(i32, i, NaNs.Float64[i]); + } + + let rf64 = f64.slice(0); + let ri32 = new Int32Array(rf64.buffer); + + assertEq(rf64.length, len); + assertEq(ri32.length, 2 * len); + + // Same bits. + for (let i = 0; i < len; ++i) { + assertEqArray(geti64(ri32, i), NaNs.Float64[i]); + } +} + +// Float64 -> Float32 +for (let [sourceConstructor, targetConstructor] of p(float64Constructors, float32Constructors)) { + let len = NaNs.Float64.length; + let f64 = new sourceConstructor(len); + let i32 = new Int32Array(f64.buffer); + f64.constructor = targetConstructor; + + for (let i = 0; i < len; ++i) { + seti64(i32, i, NaNs.Float64[i]); + } + + let rf32 = f64.slice(0); + let ri32 = new Int32Array(rf32.buffer); + + assertEq(rf32.length, len); + assertEq(ri32.length, len); + + // NaN bits canonicalized. + for (let i = 0; i < len; ++i) { + assertEqArray(ri32[i], cNaN.Float32); + } +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/non262/TypedArray/slice-conversion.js b/js/src/tests/non262/TypedArray/slice-conversion.js new file mode 100644 index 000000000000..bc44d798c570 --- /dev/null +++ b/js/src/tests/non262/TypedArray/slice-conversion.js @@ -0,0 +1,515 @@ +// Test conversions to different element types. +let tests = [ + /* Int8Array */ + { + from: Int8Array, + to: Int8Array, + values: [-129, -128, -127, -1, 0, 1, 127, 128, 129], + expected: [127, -128, -127, -1, 0, 1, 127, -128, -127], + }, + { + from: Int8Array, + to: Uint8Array, + values: [-129, -128, -127, -1, 0, 1, 127, 128, 129], + expected: [127, 128, 129, 255, 0, 1, 127, 128, 129], + }, + { + from: Int8Array, + to: Uint8ClampedArray, + values: [-129, -128, -127, -1, 0, 1, 127, 128, 129], + expected: [127, 0, 0, 0, 0, 1, 127, 0, 0], + }, + { + from: Int8Array, + to: Int16Array, + values: [-129, -128, -127, -1, 0, 1, 127, 128, 129], + expected: [127, -128, -127, -1, 0, 1, 127, -128, -127], + }, + { + from: Int8Array, + to: Uint16Array, + values: [-129, -128, -127, -1, 0, 1, 127, 128, 129], + expected: [127, 65408, 65409, 65535, 0, 1, 127, 65408, 65409], + }, + { + from: Int8Array, + to: Int32Array, + values: [-129, -128, -127, -1, 0, 1, 127, 128, 129], + expected: [127, -128, -127, -1, 0, 1, 127, -128, -127], + }, + { + from: Int8Array, + to: Uint32Array, + values: [-129, -128, -127, -1, 0, 1, 127, 128, 129], + expected: [127, 4294967168, 4294967169, 4294967295, 0, 1, 127, 4294967168, 4294967169], + }, + { + from: Int8Array, + to: Float32Array, + values: [-129, -128, -127, -1, 0, 1, 127, 128, 129], + expected: [127, -128, -127, -1, 0, 1, 127, -128, -127], + }, + { + from: Int8Array, + to: Float64Array, + values: [-129, -128, -127, -1, 0, 1, 127, 128, 129], + expected: [127, -128, -127, -1, 0, 1, 127, -128, -127], + }, + + /* Uint8Array */ + { + from: Uint8Array, + to: Int8Array, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, -128, -127, -2, -1, 0], + }, + { + from: Uint8Array, + to: Uint8Array, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, 128, 129, 254, 255, 0], + }, + { + from: Uint8Array, + to: Uint8ClampedArray, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, 128, 129, 254, 255, 0], + }, + { + from: Uint8Array, + to: Int16Array, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, 128, 129, 254, 255, 0], + }, + { + from: Uint8Array, + to: Uint16Array, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, 128, 129, 254, 255, 0], + }, + { + from: Uint8Array, + to: Int32Array, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, 128, 129, 254, 255, 0], + }, + { + from: Uint8Array, + to: Uint32Array, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, 128, 129, 254, 255, 0], + }, + { + from: Uint8Array, + to: Float32Array, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, 128, 129, 254, 255, 0], + }, + { + from: Uint8Array, + to: Float64Array, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, 128, 129, 254, 255, 0], + }, + + /* Uint8ClampedArray */ + { + from: Uint8ClampedArray, + to: Int8Array, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, -128, -127, -2, -1, -1], + }, + { + from: Uint8ClampedArray, + to: Uint8Array, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, 128, 129, 254, 255, 255], + }, + { + from: Uint8ClampedArray, + to: Uint8ClampedArray, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, 128, 129, 254, 255, 255], + }, + { + from: Uint8ClampedArray, + to: Int16Array, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, 128, 129, 254, 255, 255], + }, + { + from: Uint8ClampedArray, + to: Uint16Array, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, 128, 129, 254, 255, 255], + }, + { + from: Uint8ClampedArray, + to: Int32Array, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, 128, 129, 254, 255, 255], + }, + { + from: Uint8ClampedArray, + to: Uint32Array, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, 128, 129, 254, 255, 255], + }, + { + from: Uint8ClampedArray, + to: Float32Array, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, 128, 129, 254, 255, 255], + }, + { + from: Uint8ClampedArray, + to: Float64Array, + values: [0, 1, 127, 128, 129, 254, 255, 256], + expected: [0, 1, 127, 128, 129, 254, 255, 255], + }, + + /* Int16Array */ + { + from: Int16Array, + to: Int8Array, + values: [-32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769], + expected: [-1, 0, 1, 127, -128, -127, -1, 0, 1, 127, -128, -127, -1, 0, 1], + }, + { + from: Int16Array, + to: Uint8Array, + values: [-32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769], + expected: [255, 0, 1, 127, 128, 129, 255, 0, 1, 127, 128, 129, 255, 0, 1], + }, + { + from: Int16Array, + to: Uint8ClampedArray, + values: [-32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769], + expected: [255, 0, 0, 0, 0, 0, 0, 0, 1, 127, 128, 129, 255, 0, 0], + }, + { + from: Int16Array, + to: Int16Array, + values: [-32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769], + expected: [32767, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, -32768, -32767], + }, + { + from: Int16Array, + to: Uint16Array, + values: [-32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769], + expected: [32767, 32768, 32769, 65407, 65408, 65409, 65535, 0, 1, 127, 128, 129, 32767, 32768, 32769], + }, + { + from: Int16Array, + to: Int32Array, + values: [-32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769], + expected: [32767, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, -32768, -32767], + }, + { + from: Int16Array, + to: Uint32Array, + values: [-32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769], + expected: [32767, 4294934528, 4294934529, 4294967167, 4294967168, 4294967169, 4294967295, 0, 1, 127, 128, 129, 32767, 4294934528, 4294934529], + }, + { + from: Int16Array, + to: Float32Array, + values: [-32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769], + expected: [32767, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, -32768, -32767], + }, + { + from: Int16Array, + to: Float64Array, + values: [-32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769], + expected: [32767, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, -32768, -32767], + }, + + /* Uint16Array */ + { + from: Uint16Array, + to: Int8Array, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536], + expected: [0, 1, 127, -128, -127, -2, -1, 0, -1, 0, 1, -2, -1, 0], + }, + { + from: Uint16Array, + to: Uint8Array, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536], + expected: [0, 1, 127, 128, 129, 254, 255, 0, 255, 0, 1, 254, 255, 0], + }, + { + from: Uint16Array, + to: Uint8ClampedArray, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536], + expected: [0, 1, 127, 128, 129, 254, 255, 255, 255, 255, 255, 255, 255, 0], + }, + { + from: Uint16Array, + to: Int16Array, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536], + expected: [0, 1, 127, 128, 129, 254, 255, 256, 32767, -32768, -32767, -2, -1, 0], + }, + { + from: Uint16Array, + to: Uint16Array, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536], + expected: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 0], + }, + { + from: Uint16Array, + to: Int32Array, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536], + expected: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 0], + }, + { + from: Uint16Array, + to: Uint32Array, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536], + expected: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 0], + }, + { + from: Uint16Array, + to: Float32Array, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536], + expected: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 0], + }, + { + from: Uint16Array, + to: Float64Array, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536], + expected: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 0], + }, + + /* Int32Array */ + { + from: Int32Array, + to: Int8Array, + values: [-2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649], + expected: [-1, 0, 1, -1, 0, 1, 127, -128, -127, -1, 0, 1, 127, -128, -127, -1, 0, 1, -1, 0, 1], + }, + { + from: Int32Array, + to: Uint8Array, + values: [-2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649], + expected: [255, 0, 1, 255, 0, 1, 127, 128, 129, 255, 0, 1, 127, 128, 129, 255, 0, 1, 255, 0, 1], + }, + { + from: Int32Array, + to: Uint8ClampedArray, + values: [-2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649], + expected: [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 127, 128, 129, 255, 255, 255, 255, 0, 0], + }, + { + from: Int32Array, + to: Int16Array, + values: [-2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649], + expected: [-1, 0, 1, 32767, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, -32768, -32767, -1, 0, 1], + }, + { + from: Int32Array, + to: Uint16Array, + values: [-2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649], + expected: [65535, 0, 1, 32767, 32768, 32769, 65407, 65408, 65409, 65535, 0, 1, 127, 128, 129, 32767, 32768, 32769, 65535, 0, 1], + }, + { + from: Int32Array, + to: Int32Array, + values: [-2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649], + expected: [2147483647, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769, 2147483647, -2147483648, -2147483647], + }, + { + from: Int32Array, + to: Uint32Array, + values: [-2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649], + expected: [2147483647, 2147483648, 2147483649, 4294934527, 4294934528, 4294934529, 4294967167, 4294967168, 4294967169, 4294967295, 0, 1, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649], + }, + { + from: Int32Array, + to: Float32Array, + values: [-2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649], + expected: [2147483648, -2147483648, -2147483648, -32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769, 2147483648, -2147483648, -2147483648], + }, + { + from: Int32Array, + to: Float64Array, + values: [-2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649], + expected: [2147483647, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1, 0, 1, 127, 128, 129, 32767, 32768, 32769, 2147483647, -2147483648, -2147483647], + }, + + /* Uint32Array */ + { + from: Uint32Array, + to: Int8Array, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536, 2147483647, 2147483648, 2147483649, 4294967294, 4294967295, 4294967296], + expected: [0, 1, 127, -128, -127, -2, -1, 0, -1, 0, 1, -2, -1, 0, -1, 0, 1, -2, -1, 0], + }, + { + from: Uint32Array, + to: Uint8Array, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536, 2147483647, 2147483648, 2147483649, 4294967294, 4294967295, 4294967296], + expected: [0, 1, 127, 128, 129, 254, 255, 0, 255, 0, 1, 254, 255, 0, 255, 0, 1, 254, 255, 0], + }, + { + from: Uint32Array, + to: Uint8ClampedArray, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536, 2147483647, 2147483648, 2147483649, 4294967294, 4294967295, 4294967296], + expected: [0, 1, 127, 128, 129, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0], + }, + { + from: Uint32Array, + to: Int16Array, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536, 2147483647, 2147483648, 2147483649, 4294967294, 4294967295, 4294967296], + expected: [0, 1, 127, 128, 129, 254, 255, 256, 32767, -32768, -32767, -2, -1, 0, -1, 0, 1, -2, -1, 0], + }, + { + from: Uint32Array, + to: Uint16Array, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536, 2147483647, 2147483648, 2147483649, 4294967294, 4294967295, 4294967296], + expected: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 0, 65535, 0, 1, 65534, 65535, 0], + }, + { + from: Uint32Array, + to: Int32Array, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536, 2147483647, 2147483648, 2147483649, 4294967294, 4294967295, 4294967296], + expected: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536, 2147483647, -2147483648, -2147483647, -2, -1, 0], + }, + { + from: Uint32Array, + to: Uint32Array, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536, 2147483647, 2147483648, 2147483649, 4294967294, 4294967295, 4294967296], + expected: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536, 2147483647, 2147483648, 2147483649, 4294967294, 4294967295, 0], + }, + { + from: Uint32Array, + to: Float32Array, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536, 2147483647, 2147483648, 2147483649, 4294967294, 4294967295, 4294967296], + expected: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536, 2147483648, 2147483648, 2147483648, 4294967296, 4294967296, 0], + }, + { + from: Uint32Array, + to: Float64Array, + values: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536, 2147483647, 2147483648, 2147483649, 4294967294, 4294967295, 4294967296], + expected: [0, 1, 127, 128, 129, 254, 255, 256, 32767, 32768, 32769, 65534, 65535, 65536, 2147483647, 2147483648, 2147483649, 4294967294, 4294967295, 0], + }, + + /* Float32Array */ + { + from: Float32Array, + to: Int8Array, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [0, 0, 0, 0, -1, 0, 1, 127, -128, -127, -1, -1, -1, -1, 0, 0, 1, 1, 1, 1, 127, -128, -127, -1, 0, 1, 0, 0, 0, 0, 0], + }, + { + from: Float32Array, + to: Uint8Array, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [0, 0, 0, 0, 255, 0, 1, 127, 128, 129, 255, 255, 255, 255, 0, 0, 1, 1, 1, 1, 127, 128, 129, 255, 0, 1, 0, 0, 0, 0, 0], + }, + { + from: Float32Array, + to: Uint8ClampedArray, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 127, 128, 129, 255, 255, 255, 255, 255, 255, 255, 0], + }, + { + from: Float32Array, + to: Int16Array, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [0, 0, 0, 0, 32767, -32768, -32767, -129, -128, -127, -1, -1, -1, -1, 0, 0, 1, 1, 1, 1, 127, 128, 129, 32767, -32768, -32767, 0, 0, 0, 0, 0], + }, + { + from: Float32Array, + to: Uint16Array, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [0, 0, 0, 0, 32767, 32768, 32769, 65407, 65408, 65409, 65535, 65535, 65535, 65535, 0, 0, 1, 1, 1, 1, 127, 128, 129, 32767, 32768, 32769, 0, 0, 0, 0, 0], + }, + { + from: Float32Array, + to: Int32Array, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [0, -2147483648, -2147483648, -2147483648, -32769, -32768, -32767, -129, -128, -127, -1, -1, -1, -1, 0, 0, 1, 1, 1, 1, 127, 128, 129, 32767, 32768, 32769, -2147483648, -2147483648, -2147483648, 0, 0], + }, + { + from: Float32Array, + to: Uint32Array, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [0, 2147483648, 2147483648, 2147483648, 4294934527, 4294934528, 4294934529, 4294967167, 4294967168, 4294967169, 4294967295, 4294967295, 4294967295, 4294967295, 0, 0, 1, 1, 1, 1, 127, 128, 129, 32767, 32768, 32769, 2147483648, 2147483648, 2147483648, 0, 0], + }, + { + from: Float32Array, + to: Float32Array, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [-Infinity, -2147483648, -2147483648, -2147483648, -32769, -32768, -32767, -129, -128, -127, -1.600000023841858, -1.5, -1.399999976158142, -1, -0, 0, 1, 1.399999976158142, 1.5, 1.600000023841858, 127, 128, 129, 32767, 32768, 32769, 2147483648, 2147483648, 2147483648, Infinity, NaN], + }, + { + from: Float32Array, + to: Float64Array, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [-Infinity, -2147483648, -2147483648, -2147483648, -32769, -32768, -32767, -129, -128, -127, -1.600000023841858, -1.5, -1.399999976158142, -1, -0, 0, 1, 1.399999976158142, 1.5, 1.600000023841858, 127, 128, 129, 32767, 32768, 32769, 2147483648, 2147483648, 2147483648, Infinity, NaN], + }, + + /* Float64Array */ + { + from: Float64Array, + to: Int8Array, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [0, -1, 0, 1, -1, 0, 1, 127, -128, -127, -1, -1, -1, -1, 0, 0, 1, 1, 1, 1, 127, -128, -127, -1, 0, 1, -1, 0, 1, 0, 0], + }, + { + from: Float64Array, + to: Uint8Array, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [0, 255, 0, 1, 255, 0, 1, 127, 128, 129, 255, 255, 255, 255, 0, 0, 1, 1, 1, 1, 127, 128, 129, 255, 0, 1, 255, 0, 1, 0, 0], + }, + { + from: Float64Array, + to: Uint8ClampedArray, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 127, 128, 129, 255, 255, 255, 255, 255, 255, 255, 0], + }, + { + from: Float64Array, + to: Int16Array, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [0, -1, 0, 1, 32767, -32768, -32767, -129, -128, -127, -1, -1, -1, -1, 0, 0, 1, 1, 1, 1, 127, 128, 129, 32767, -32768, -32767, -1, 0, 1, 0, 0], + }, + { + from: Float64Array, + to: Uint16Array, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [0, 65535, 0, 1, 32767, 32768, 32769, 65407, 65408, 65409, 65535, 65535, 65535, 65535, 0, 0, 1, 1, 1, 1, 127, 128, 129, 32767, 32768, 32769, 65535, 0, 1, 0, 0], + }, + { + from: Float64Array, + to: Int32Array, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [0, 2147483647, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1, -1, -1, -1, 0, 0, 1, 1, 1, 1, 127, 128, 129, 32767, 32768, 32769, 2147483647, -2147483648, -2147483647, 0, 0], + }, + { + from: Float64Array, + to: Uint32Array, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [0, 2147483647, 2147483648, 2147483649, 4294934527, 4294934528, 4294934529, 4294967167, 4294967168, 4294967169, 4294967295, 4294967295, 4294967295, 4294967295, 0, 0, 1, 1, 1, 1, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, 0, 0], + }, + { + from: Float64Array, + to: Float32Array, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [-Infinity, -2147483648, -2147483648, -2147483648, -32769, -32768, -32767, -129, -128, -127, -1.600000023841858, -1.5, -1.399999976158142, -1, -0, 0, 1, 1.399999976158142, 1.5, 1.600000023841858, 127, 128, 129, 32767, 32768, 32769, 2147483648, 2147483648, 2147483648, Infinity, NaN], + }, + { + from: Float64Array, + to: Float64Array, + values: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + expected: [-Infinity, -2147483649, -2147483648, -2147483647, -32769, -32768, -32767, -129, -128, -127, -1.6, -1.5, -1.4, -1, -0, 0, 1, 1.4, 1.5, 1.6, 127, 128, 129, 32767, 32768, 32769, 2147483647, 2147483648, 2147483649, Infinity, NaN], + }, +]; + +for (let {from, to, values, expected} of tests) { + let ta = new from(values); + ta.constructor = to; + assertEqArray(ta.slice(0), expected, `${from.name} -> ${to.name}`); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/non262/TypedArray/slice-memcpy.js b/js/src/tests/non262/TypedArray/slice-memcpy.js new file mode 100644 index 000000000000..8659246e2909 --- /dev/null +++ b/js/src/tests/non262/TypedArray/slice-memcpy.js @@ -0,0 +1,84 @@ +const otherGlobal = newGlobal(); + +// Create with new ArrayBuffer and offset. +for (var constructor of typedArrayConstructors) { + const elementSize = constructor.BYTES_PER_ELEMENT; + let ab = new constructor(10).map((v, i) => i).buffer; + let ta = new constructor(ab, 2 * elementSize, 6); + ta.constructor = { + [Symbol.species]: function(len) { + return new constructor(new ArrayBuffer((len + 4) * elementSize), 4 * elementSize); + } + }; + let tb = ta.slice(0); + + assertEqArray(ta, [2, 3, 4, 5, 6, 7]); + assertEqArray(tb, [2, 3, 4, 5, 6, 7]); +} + +// Source and target arrays use the same ArrayBuffer, target range before source range. +for (var constructor of typedArrayConstructors) { + const elementSize = constructor.BYTES_PER_ELEMENT; + let ab = new constructor(10).map((v, i) => i).buffer; + let ta = new constructor(ab, 2 * elementSize, 6); + ta.constructor = { + [Symbol.species]: function(len) { + return new constructor(ab, 0, len); + } + }; + let tb = ta.slice(0); + + assertEqArray(ta, [4, 5, 6, 7, 6, 7]); + assertEqArray(tb, [2, 3, 4, 5, 6, 7]); + assertEqArray(new constructor(ab), [2, 3, 4, 5, 6, 7, 6, 7, 8, 9]); +} + +// Source and target arrays use the same ArrayBuffer, target range after source range. +for (var constructor of typedArrayConstructors) { + const elementSize = constructor.BYTES_PER_ELEMENT; + let ab = new constructor(10).map((v, i) => i + 1).buffer; + let ta = new constructor(ab, 0, 6); + ta.constructor = { + [Symbol.species]: function(len) { + return new constructor(ab, 2 * elementSize, len); + } + }; + let tb = ta.slice(0); + + assertEqArray(ta, [1, 2, 1, 2, 1, 2]); + assertEqArray(tb, [1, 2, 1, 2, 1, 2]); + assertEqArray(new constructor(ab), [1, 2, 1, 2, 1, 2, 1, 2, 9, 10]); +} + +// Tricky: Same as above, but with SharedArrayBuffer and different compartments. +if (typeof setSharedArrayBuffer === "function") { + for (var constructor of typedArrayConstructors) { + const elementSize = constructor.BYTES_PER_ELEMENT; + let ts = new constructor(new SharedArrayBuffer(10 * elementSize)); + for (let i = 0; i < ts.length; i++) { + ts[i] = i + 1; + } + let ab = ts.buffer; + let ta = new constructor(ab, 0, 6); + ta.constructor = { + [Symbol.species]: function(len) { + setSharedArrayBuffer(ab); + try { + return otherGlobal.eval(` + new ${constructor.name}(getSharedArrayBuffer(), ${2 * elementSize}, ${len}); + `); + } finally { + setSharedArrayBuffer(null); + } + } + }; + let tb = ta.slice(0); + + assertEqArray(ta, [1, 2, 1, 2, 1, 2]); + assertEqArray(tb, [1, 2, 1, 2, 1, 2]); + assertEqArray(new constructor(ab), [1, 2, 1, 2, 1, 2, 1, 2, 9, 10]); + } +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index b2bee8eb2947..93dcd8b575d5 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -1252,8 +1252,13 @@ DangerouslyUnwrapTypedArray(JSContext* cx, JSObject* obj) // An unwrapped pointer to an object potentially on the other side of a // compartment boundary! Isn't this such fun? JSObject* unwrapped = CheckedUnwrap(obj); + if (!unwrapped) { + ReportAccessDenied(cx); + return nullptr; + } + if (!unwrapped->is()) { - // By *appearances* this can't happen, as self-hosted TypedArraySet + // By *appearances* this can't happen, as self-hosted code // checked this. But. Who's to say a GC couldn't happen between // the check that this value was a typed array, and this extraction // occurring? A GC might turn a cross-compartment wrapper |obj| into @@ -1588,6 +1593,113 @@ intrinsic_SetOverlappingTypedElements(JSContext* cx, unsigned argc, Value* vp) return true; } +// The specification requires us to perform bitwise copying when |sourceType| +// and |targetType| are the same (ES2017, ยง22.2.3.24, step 15). Additionally, +// as an optimization, we can also perform bitwise copying when |sourceType| +// and |targetType| have compatible bit-level representations. +static bool +IsTypedArrayBitwiseSlice(Scalar::Type sourceType, Scalar::Type targetType) +{ + switch (sourceType) { + case Scalar::Int8: + return targetType == Scalar::Int8 || targetType == Scalar::Uint8; + + case Scalar::Uint8: + case Scalar::Uint8Clamped: + return targetType == Scalar::Int8 || targetType == Scalar::Uint8 || + targetType == Scalar::Uint8Clamped; + + case Scalar::Int16: + case Scalar::Uint16: + return targetType == Scalar::Int16 || targetType == Scalar::Uint16; + + case Scalar::Int32: + case Scalar::Uint32: + return targetType == Scalar::Int32 || targetType == Scalar::Uint32; + + case Scalar::Float32: + return targetType == Scalar::Float32; + + case Scalar::Float64: + return targetType == Scalar::Float64; + + default: + MOZ_CRASH("IsTypedArrayBitwiseSlice with a bogus typed array type"); + } +} + +static bool +intrinsic_TypedArrayBitwiseSlice(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 4); + MOZ_ASSERT(args[0].isObject()); + MOZ_ASSERT(args[1].isObject()); + MOZ_ASSERT(args[2].isInt32()); + MOZ_ASSERT(args[3].isInt32()); + + Rooted source(cx, &args[0].toObject().as()); + MOZ_ASSERT(!source->hasDetachedBuffer()); + + // As directed by |DangerouslyUnwrapTypedArray|, sigil this pointer and all + // variables derived from it to counsel extreme caution here. + Rooted unsafeTypedArrayCrossCompartment(cx); + unsafeTypedArrayCrossCompartment = DangerouslyUnwrapTypedArray(cx, &args[1].toObject()); + if (!unsafeTypedArrayCrossCompartment) + return false; + MOZ_ASSERT(!unsafeTypedArrayCrossCompartment->hasDetachedBuffer()); + + Scalar::Type sourceType = source->type(); + if (!IsTypedArrayBitwiseSlice(sourceType, unsafeTypedArrayCrossCompartment->type())) { + args.rval().setBoolean(false); + return true; + } + + MOZ_ASSERT(args[2].toInt32() >= 0); + uint32_t sourceOffset = uint32_t(args[2].toInt32()); + + MOZ_ASSERT(args[3].toInt32() >= 0); + uint32_t count = uint32_t(args[3].toInt32()); + + MOZ_ASSERT(count > 0 && count <= source->length()); + MOZ_ASSERT(sourceOffset <= source->length() - count); + MOZ_ASSERT(count <= unsafeTypedArrayCrossCompartment->length()); + + size_t elementSize = TypedArrayElemSize(sourceType); + MOZ_ASSERT(elementSize == TypedArrayElemSize(unsafeTypedArrayCrossCompartment->type())); + + SharedMem sourceData = + source->viewDataEither().cast() + sourceOffset * elementSize; + + SharedMem unsafeTargetDataCrossCompartment = + unsafeTypedArrayCrossCompartment->viewDataEither().cast(); + + uint32_t byteLength = count * elementSize; + + // The same-type case requires exact copying preserving the bit-level + // encoding of the source data, so use memcpy if possible. If source and + // target are the same buffer, we can't use memcpy (or memmove), because + // the specification requires sequential copying of the values. This case + // is only possible if a @@species constructor created a specifically + // crafted typed array. It won't happen in normal code and hence doesn't + // need to be optimized. + if (!TypedArrayObject::sameBuffer(source, unsafeTypedArrayCrossCompartment)) { + jit::AtomicOperations::memcpySafeWhenRacy(unsafeTargetDataCrossCompartment, + sourceData, + byteLength); + } else { + using namespace jit; + + for (; byteLength > 0; byteLength--) { + AtomicOperations::storeSafeWhenRacy(unsafeTargetDataCrossCompartment++, + AtomicOperations::loadSafeWhenRacy(sourceData++)); + } + } + + args.rval().setBoolean(true); + return true; +} + static bool intrinsic_RegExpCreate(JSContext* cx, unsigned argc, Value* vp) { @@ -2473,6 +2585,8 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_INLINABLE_FN("SetDisjointTypedElements",intrinsic_SetDisjointTypedElements,3,0, IntrinsicSetDisjointTypedElements), + JS_FN("TypedArrayBitwiseSlice", intrinsic_TypedArrayBitwiseSlice, 4, 0), + JS_FN("CallArrayBufferMethodIfWrapped", CallNonGenericSelfhostedMethod>, 2, 0), JS_FN("CallSharedArrayBufferMethodIfWrapped",