summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/TypedArray
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/tests/non262/TypedArray')
-rw-r--r--js/src/tests/non262/TypedArray/Tconstructor-fromTypedArray-byteLength.js17
-rw-r--r--js/src/tests/non262/TypedArray/at.js47
-rw-r--r--js/src/tests/non262/TypedArray/browser.js0
-rw-r--r--js/src/tests/non262/TypedArray/bug1526838.js8
-rw-r--r--js/src/tests/non262/TypedArray/constructor-ArrayBuffer-species-wrap.js55
-rw-r--r--js/src/tests/non262/TypedArray/constructor-ArrayBuffer-species.js19
-rw-r--r--js/src/tests/non262/TypedArray/constructor-buffer-sequence.js230
-rw-r--r--js/src/tests/non262/TypedArray/constructor-byteoffsets-bounds.js34
-rw-r--r--js/src/tests/non262/TypedArray/constructor-iterable-generator.js16
-rw-r--r--js/src/tests/non262/TypedArray/constructor-iterable-modified-array-iterator-next.js28
-rw-r--r--js/src/tests/non262/TypedArray/constructor-iterable-modified-array-iterator.js28
-rw-r--r--js/src/tests/non262/TypedArray/constructor-iterable-nonpacked-array.js17
-rw-r--r--js/src/tests/non262/TypedArray/constructor-iterable-not-callable.js15
-rw-r--r--js/src/tests/non262/TypedArray/constructor-iterable-packed-array-side-effect.js17
-rw-r--r--js/src/tests/non262/TypedArray/constructor-iterable-packed-array.js16
-rw-r--r--js/src/tests/non262/TypedArray/constructor-iterable-undefined-or-null.js22
-rw-r--r--js/src/tests/non262/TypedArray/constructor-iterator-primitive.js29
-rw-r--r--js/src/tests/non262/TypedArray/constructor-length-too-large.js40
-rw-r--r--js/src/tests/non262/TypedArray/constructor-non-detached.js13
-rw-r--r--js/src/tests/non262/TypedArray/constructor-not-callable.js10
-rw-r--r--js/src/tests/non262/TypedArray/constructor-typedarray-species-other-global.js33
-rw-r--r--js/src/tests/non262/TypedArray/constructor-undefined-args.js14
-rw-r--r--js/src/tests/non262/TypedArray/constructor_bad-args.js13
-rw-r--r--js/src/tests/non262/TypedArray/detached-array-buffer-checks.js107
-rw-r--r--js/src/tests/non262/TypedArray/element-setting-converts-using-ToNumber.js91
-rw-r--r--js/src/tests/non262/TypedArray/entries.js38
-rw-r--r--js/src/tests/non262/TypedArray/every-and-some.js249
-rw-r--r--js/src/tests/non262/TypedArray/fill-detached.js36
-rw-r--r--js/src/tests/non262/TypedArray/fill.js65
-rw-r--r--js/src/tests/non262/TypedArray/filter-species.js56
-rw-r--r--js/src/tests/non262/TypedArray/filter-validation.js185
-rw-r--r--js/src/tests/non262/TypedArray/find-and-findIndex.js52
-rw-r--r--js/src/tests/non262/TypedArray/findLast-and-findLastIndex.js52
-rw-r--r--js/src/tests/non262/TypedArray/forEach.js93
-rw-r--r--js/src/tests/non262/TypedArray/from-iterable-validation.js140
-rw-r--r--js/src/tests/non262/TypedArray/from-non-iterable-validation.js140
-rw-r--r--js/src/tests/non262/TypedArray/from_basics.js42
-rw-r--r--js/src/tests/non262/TypedArray/from_constructor.js36
-rw-r--r--js/src/tests/non262/TypedArray/from_errors.js76
-rw-r--r--js/src/tests/non262/TypedArray/from_iterable.js49
-rw-r--r--js/src/tests/non262/TypedArray/from_mapping.js45
-rw-r--r--js/src/tests/non262/TypedArray/from_realms.js32
-rw-r--r--js/src/tests/non262/TypedArray/from_string.js24
-rw-r--r--js/src/tests/non262/TypedArray/from_surfaces.js12
-rw-r--r--js/src/tests/non262/TypedArray/from_this.js59
-rw-r--r--js/src/tests/non262/TypedArray/from_typedarray_fastpath_detached.js10
-rw-r--r--js/src/tests/non262/TypedArray/getter-name.js16
-rw-r--r--js/src/tests/non262/TypedArray/has-property-op.js22
-rw-r--r--js/src/tests/non262/TypedArray/includes.js40
-rw-r--r--js/src/tests/non262/TypedArray/indexOf-and-lastIndexOf.js123
-rw-r--r--js/src/tests/non262/TypedArray/indexOf-never-returns-negative-zero.js7
-rw-r--r--js/src/tests/non262/TypedArray/iterator-next-with-detached.js73
-rw-r--r--js/src/tests/non262/TypedArray/iterator.js42
-rw-r--r--js/src/tests/non262/TypedArray/join.js48
-rw-r--r--js/src/tests/non262/TypedArray/keys.js36
-rw-r--r--js/src/tests/non262/TypedArray/large-arrays.js24
-rw-r--r--js/src/tests/non262/TypedArray/lastIndexOf-never-returns-negative-zero.js7
-rw-r--r--js/src/tests/non262/TypedArray/length.js14
-rw-r--r--js/src/tests/non262/TypedArray/map-and-filter.js274
-rw-r--r--js/src/tests/non262/TypedArray/map-species.js56
-rw-r--r--js/src/tests/non262/TypedArray/map-validation.js149
-rw-r--r--js/src/tests/non262/TypedArray/object-defineproperty.js68
-rw-r--r--js/src/tests/non262/TypedArray/of-validation.js140
-rw-r--r--js/src/tests/non262/TypedArray/of.js92
-rw-r--r--js/src/tests/non262/TypedArray/prototype-constructor-identity.js55
-rw-r--r--js/src/tests/non262/TypedArray/reduce-and-reduceRight.js188
-rw-r--r--js/src/tests/non262/TypedArray/reverse.js38
-rw-r--r--js/src/tests/non262/TypedArray/seal-and-freeze.js49
-rw-r--r--js/src/tests/non262/TypedArray/set-detached-bigint.js19
-rw-r--r--js/src/tests/non262/TypedArray/set-detached.js265
-rw-r--r--js/src/tests/non262/TypedArray/set-negative-offset.js35
-rw-r--r--js/src/tests/non262/TypedArray/set-same-buffer-different-source-target-types.js41
-rw-r--r--js/src/tests/non262/TypedArray/set-tointeger.js95
-rw-r--r--js/src/tests/non262/TypedArray/set-toobject.js53
-rw-r--r--js/src/tests/non262/TypedArray/set-with-receiver.js28
-rw-r--r--js/src/tests/non262/TypedArray/set-wrapped.js81
-rw-r--r--js/src/tests/non262/TypedArray/set.js21
-rw-r--r--js/src/tests/non262/TypedArray/shell.js114
-rw-r--r--js/src/tests/non262/TypedArray/slice-bitwise.js153
-rw-r--r--js/src/tests/non262/TypedArray/slice-conversion.js515
-rw-r--r--js/src/tests/non262/TypedArray/slice-detached.js103
-rw-r--r--js/src/tests/non262/TypedArray/slice-memcpy.js84
-rw-r--r--js/src/tests/non262/TypedArray/slice-species.js49
-rw-r--r--js/src/tests/non262/TypedArray/slice-validation.js194
-rw-r--r--js/src/tests/non262/TypedArray/slice.js45
-rw-r--r--js/src/tests/non262/TypedArray/sort-negative-nan.js106
-rw-r--r--js/src/tests/non262/TypedArray/sort-non-function.js22
-rw-r--r--js/src/tests/non262/TypedArray/sort_basics.js73
-rw-r--r--js/src/tests/non262/TypedArray/sort_byteoffset.js30
-rw-r--r--js/src/tests/non262/TypedArray/sort_comparators.js32
-rw-r--r--js/src/tests/non262/TypedArray/sort_compare_nan.js12
-rw-r--r--js/src/tests/non262/TypedArray/sort_errors.js87
-rw-r--r--js/src/tests/non262/TypedArray/sort_globals.js9
-rw-r--r--js/src/tests/non262/TypedArray/sort_modifications.js73
-rw-r--r--js/src/tests/non262/TypedArray/sort_modifications_concurrent.js145
-rw-r--r--js/src/tests/non262/TypedArray/sort_modifications_concurrent_radixsort.js116
-rw-r--r--js/src/tests/non262/TypedArray/sort_small.js38
-rw-r--r--js/src/tests/non262/TypedArray/sort_snans.js79
-rw-r--r--js/src/tests/non262/TypedArray/sort_sorted.js30
-rw-r--r--js/src/tests/non262/TypedArray/sort_stable.js23
-rw-r--r--js/src/tests/non262/TypedArray/sorting_buffer_access.js15
-rw-r--r--js/src/tests/non262/TypedArray/subarray-species.js63
-rw-r--r--js/src/tests/non262/TypedArray/subarray-validation.js117
-rw-r--r--js/src/tests/non262/TypedArray/subarray.js29
-rw-r--r--js/src/tests/non262/TypedArray/test-integrity-level-detached.js104
-rw-r--r--js/src/tests/non262/TypedArray/test-integrity-level.js67
-rw-r--r--js/src/tests/non262/TypedArray/toLocaleString-detached.js38
-rw-r--r--js/src/tests/non262/TypedArray/toLocaleString-nointl.js40
-rw-r--r--js/src/tests/non262/TypedArray/toLocaleString.js80
-rw-r--r--js/src/tests/non262/TypedArray/toReversed-detached.js10
-rw-r--r--js/src/tests/non262/TypedArray/toSorted-detached.js10
-rw-r--r--js/src/tests/non262/TypedArray/toString.js69
-rw-r--r--js/src/tests/non262/TypedArray/toStringTag-cross-compartment.js12
-rw-r--r--js/src/tests/non262/TypedArray/uint8clamped-constructor.js9
-rw-r--r--js/src/tests/non262/TypedArray/values.js37
-rw-r--r--js/src/tests/non262/TypedArray/with-detached.js10
-rw-r--r--js/src/tests/non262/TypedArray/with.js34
-rw-r--r--js/src/tests/non262/TypedArray/write-out-of-bounds-tonumber.js60
118 files changed, 7545 insertions, 0 deletions
diff --git a/js/src/tests/non262/TypedArray/Tconstructor-fromTypedArray-byteLength.js b/js/src/tests/non262/TypedArray/Tconstructor-fromTypedArray-byteLength.js
new file mode 100644
index 0000000000..6aadca5c81
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/Tconstructor-fromTypedArray-byteLength.js
@@ -0,0 +1,17 @@
+var g = newGlobal();
+
+var arr = [1, 2, 3];
+for (var constructor of anyTypedArrayConstructors) {
+ var tarr = new constructor(arr);
+ for (var constructor2 of anyTypedArrayConstructors) {
+ var copied = new constructor2(tarr);
+ assertEq(copied.buffer.byteLength, arr.length * constructor2.BYTES_PER_ELEMENT);
+
+ g.tarr = tarr;
+ copied = g.eval(`new ${constructor2.name}(tarr);`);
+ assertEq(copied.buffer.byteLength, arr.length * constructor2.BYTES_PER_ELEMENT);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/at.js b/js/src/tests/non262/TypedArray/at.js
new file mode 100644
index 0000000000..bab5dc8ff2
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/at.js
@@ -0,0 +1,47 @@
+for (var constructor of anyTypedArrayConstructors) {
+ assertEq(constructor.prototype.at.length, 1);
+
+ assertEq(new constructor([0]).at(0), 0);
+ assertEq(new constructor([0]).at(-1), 0);
+
+ assertEq(new constructor([]).at(0), undefined);
+ assertEq(new constructor([]).at(-1), undefined);
+ assertEq(new constructor([]).at(1), undefined);
+
+ assertEq(new constructor([0, 1]).at(0), 0);
+ assertEq(new constructor([0, 1]).at(1), 1);
+ assertEq(new constructor([0, 1]).at(-2), 0);
+ assertEq(new constructor([0, 1]).at(-1), 1);
+
+ assertEq(new constructor([0, 1]).at(2), undefined);
+ assertEq(new constructor([0, 1]).at(-3), undefined);
+ assertEq(new constructor([0, 1]).at(-4), undefined);
+ assertEq(new constructor([0, 1]).at(Infinity), undefined);
+ assertEq(new constructor([0, 1]).at(-Infinity), undefined);
+ assertEq(new constructor([0, 1]).at(NaN), 0); // ToInteger(NaN) = 0
+
+ // Called from other globals.
+ if (typeof newGlobal === "function") {
+ var at = newGlobal()[constructor.name].prototype.at;
+ assertEq(at.call(new constructor([1, 2, 3]), 2), 3);
+ }
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.at.call(invalidReceiver);
+ }, TypeError, "Assert that 'at' fails if this value is not a TypedArray");
+ });
+
+ // Test that the length getter is never called.
+ assertEq(Object.defineProperty(new constructor([1, 2, 3]), "length", {
+ get() {
+ throw new Error("length accessor called");
+ }
+ }).at(1), 2);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/browser.js b/js/src/tests/non262/TypedArray/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/browser.js
diff --git a/js/src/tests/non262/TypedArray/bug1526838.js b/js/src/tests/non262/TypedArray/bug1526838.js
new file mode 100644
index 0000000000..1d652f7783
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/bug1526838.js
@@ -0,0 +1,8 @@
+const testArray = [1n];
+for (const constructor of anyTypedArrayConstructors) {
+ assertThrowsInstanceOf(() => new constructor(testArray), TypeError);
+ assertThrowsInstanceOf(() => new constructor(testArray.values()), TypeError);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/constructor-ArrayBuffer-species-wrap.js b/js/src/tests/non262/TypedArray/constructor-ArrayBuffer-species-wrap.js
new file mode 100644
index 0000000000..d454804f94
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-ArrayBuffer-species-wrap.js
@@ -0,0 +1,55 @@
+// |reftest| skip-if(!xulRuntime.shell)
+
+let g = newGlobal();
+
+// Both TypedArray and ArrayBuffer from different global.
+for (let ctor of typedArrayConstructors) {
+ let a = g.eval(`new ${ctor.name}([1, 2, 3, 4, 5]);`);
+ for (let ctor2 of typedArrayConstructors) {
+ let b = new ctor2(a);
+ assertEq(Object.getPrototypeOf(b).constructor, ctor2);
+ assertEq(Object.getPrototypeOf(b.buffer).constructor, ArrayBuffer);
+ }
+}
+
+// Only ArrayBuffer from different global.
+let origSpecies = Object.getOwnPropertyDescriptor(ArrayBuffer, Symbol.species);
+let modSpecies = {
+ get() {
+ throw new Error("unexpected @@species access");
+ }
+};
+for (let ctor of typedArrayConstructors) {
+ let a = new ctor([1, 2, 3, 4, 5]);
+ for (let ctor2 of typedArrayConstructors) {
+ Object.defineProperty(ArrayBuffer, Symbol.species, modSpecies);
+ let b = new ctor2(a);
+ Object.defineProperty(ArrayBuffer, Symbol.species, origSpecies);
+ assertEq(Object.getPrototypeOf(b).constructor, ctor2);
+ assertEq(Object.getPrototypeOf(b.buffer).constructor, ArrayBuffer);
+ }
+}
+
+// Only TypedArray from different global.
+g.otherArrayBuffer = ArrayBuffer;
+g.eval(`
+var origSpecies = Object.getOwnPropertyDescriptor(ArrayBuffer, Symbol.species);
+var modSpecies = {
+ get() {
+ throw new Error("unexpected @@species access");
+ }
+};
+`);
+for (let ctor of typedArrayConstructors) {
+ let a = g.eval(`new ${ctor.name}([1, 2, 3, 4, 5]);`);
+ for (let ctor2 of typedArrayConstructors) {
+ g.eval(`Object.defineProperty(ArrayBuffer, Symbol.species, modSpecies);`);
+ let b = new ctor2(a);
+ g.eval(`Object.defineProperty(ArrayBuffer, Symbol.species, origSpecies);`);
+ assertEq(Object.getPrototypeOf(b).constructor, ctor2);
+ assertEq(Object.getPrototypeOf(b.buffer).constructor, ArrayBuffer);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/constructor-ArrayBuffer-species.js b/js/src/tests/non262/TypedArray/constructor-ArrayBuffer-species.js
new file mode 100644
index 0000000000..aa7830df67
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-ArrayBuffer-species.js
@@ -0,0 +1,19 @@
+for (let ctor of typedArrayConstructors) {
+ let arr = new ctor([1, 2, 3, 4, 5, 6, 7, 8]);
+
+ arr.buffer.constructor = {
+ get [Symbol.species]() {
+ throw new Error("unexpected @@species access");
+ }
+ };
+
+ for (let ctor2 of typedArrayConstructors) {
+ let arr2 = new ctor2(arr);
+
+ assertEq(Object.getPrototypeOf(arr2.buffer), ArrayBuffer.prototype);
+ assertEq(arr2.buffer.constructor, ArrayBuffer);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/constructor-buffer-sequence.js b/js/src/tests/non262/TypedArray/constructor-buffer-sequence.js
new file mode 100644
index 0000000000..d69478344d
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-buffer-sequence.js
@@ -0,0 +1,230 @@
+// 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] )
+
+// Ensure the various error conditions are tested in the correct order.
+
+const otherGlobal = newGlobal();
+
+function* createBuffers(lengths = [0, 8]) {
+ for (let length of lengths) {
+ let buffer = new ArrayBuffer(length);
+ yield {buffer, detach: () => detachArrayBuffer(buffer)};
+ }
+
+ for (let length of lengths) {
+ let buffer = new otherGlobal.ArrayBuffer(length);
+ yield {buffer, detach: () => otherGlobal.detachArrayBuffer(buffer)};
+ }
+}
+
+const poisonedValue = new Proxy({}, new Proxy({}, {
+ get() {
+ // Throws an exception when any proxy trap is invoked.
+ throw new Error("Poisoned Value");
+ }
+}));
+
+class ExpectedError extends Error { }
+
+function ConstructorWithThrowingPrototype(detach) {
+ return Object.defineProperty(function(){}.bind(null), "prototype", {
+ get() {
+ if (detach)
+ detach();
+ throw new ExpectedError();
+ }
+ });
+}
+
+function ValueThrowing(detach) {
+ return {
+ valueOf() {
+ if (detach)
+ detach();
+ throw new ExpectedError();
+ }
+ };
+}
+
+function ValueReturning(value, detach) {
+ return {
+ valueOf() {
+ if (detach)
+ detach();
+ return value;
+ }
+ };
+}
+
+// Ensure step 4 |AllocateTypedArray| is executed before step 6 |ToIndex(byteOffset)|.
+for (let {buffer} of createBuffers()) {
+ let constructor = ConstructorWithThrowingPrototype();
+
+ assertThrowsInstanceOf(() =>
+ Reflect.construct(Int32Array, [buffer, poisonedValue, 0], constructor), ExpectedError);
+}
+
+// Ensure step 4 |AllocateTypedArray| is executed before step 9 |IsDetachedBuffer(buffer)|.
+for (let {buffer, detach} of createBuffers()) {
+ let constructor = ConstructorWithThrowingPrototype();
+
+ detach();
+ assertThrowsInstanceOf(() =>
+ Reflect.construct(Int32Array, [buffer, 0, 0], constructor), ExpectedError);
+}
+
+// Ensure step 4 |AllocateTypedArray| is executed before step 9 |IsDetachedBuffer(buffer)|.
+// - Variant: Detach buffer dynamically.
+for (let {buffer, detach} of createBuffers()) {
+ let constructor = ConstructorWithThrowingPrototype(detach);
+
+ assertThrowsInstanceOf(() =>
+ Reflect.construct(Int32Array, [buffer, 0, 0], constructor), ExpectedError);
+}
+
+// Ensure step 4 |AllocateTypedArray| is executed before step 8.a |ToIndex(length)|.
+for (let {buffer} of createBuffers()) {
+ let constructor = ConstructorWithThrowingPrototype();
+
+ assertThrowsInstanceOf(() =>
+ Reflect.construct(Int32Array, [buffer, 0, poisonedValue], constructor), ExpectedError);
+}
+
+// Ensure step 6 |ToIndex(byteOffset)| is executed before step 9 |IsDetachedBuffer(buffer)|.
+for (let {buffer, detach} of createBuffers()) {
+ let byteOffset = ValueThrowing();
+
+ detach();
+ assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, 0), ExpectedError);
+}
+
+// Ensure step 6 |ToIndex(byteOffset)| is executed before step 9 |IsDetachedBuffer(buffer)|.
+// - Variant: Detach buffer dynamically.
+for (let {buffer, detach} of createBuffers()) {
+ let byteOffset = ValueThrowing(detach);
+
+ assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, 0), ExpectedError);
+}
+
+// Ensure step 6 |ToIndex(byteOffset)| is executed before step 8.a |ToIndex(length)|.
+for (let {buffer} of createBuffers()) {
+ let byteOffset = ValueThrowing();
+
+ assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, poisonedValue), ExpectedError);
+}
+
+// Ensure step 7 |offset modulo elementSize ≠ 0| is executed before step 9 |IsDetachedBuffer(buffer)|.
+for (let {buffer, detach} of createBuffers()) {
+ let byteOffset = 1;
+
+ detach();
+ assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, 0), RangeError);
+}
+
+// Ensure step 7 |offset modulo elementSize ≠ 0| is executed before step 9 |IsDetachedBuffer(buffer)|.
+// - Variant: Detach buffer dynamically.
+for (let {buffer, detach} of createBuffers()) {
+ let byteOffset = ValueReturning(1, detach);
+
+ assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, 0), RangeError);
+}
+
+// Ensure step 7 |offset modulo elementSize ≠ 0| is executed before step 8.a |ToIndex(length)|.
+for (let {buffer} of createBuffers()) {
+ assertThrowsInstanceOf(() => new Int32Array(buffer, 1, poisonedValue), RangeError);
+}
+
+// Ensure step 8.a |ToIndex(length)| is executed before step 9 |IsDetachedBuffer(buffer)|.
+for (let {buffer, detach} of createBuffers()) {
+ let byteOffset = 0;
+ let length = ValueThrowing();
+
+ detach();
+ assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, length), ExpectedError);
+}
+
+// Ensure step 8.a |ToIndex(length)| is executed before step 9 |IsDetachedBuffer(buffer)|.
+// - Variant: Detach buffer dynamically (1).
+for (let {buffer, detach} of createBuffers()) {
+ let byteOffset = ValueReturning(0, detach);
+ let length = ValueThrowing();
+
+ assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, length), ExpectedError);
+}
+
+// Ensure step 8.a |ToIndex(length)| is executed before step 9 |IsDetachedBuffer(buffer)|.
+// - Variant: Detach buffer dynamically (2).
+for (let {buffer, detach} of createBuffers()) {
+ let byteOffset = 0;
+ let length = ValueThrowing(detach);
+
+ assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, length), ExpectedError);
+}
+
+// Ensure step 9 |IsDetachedBuffer(buffer)| is executed before step 11.a |bufferByteLength modulo elementSize ≠ 0|.
+for (let {buffer, detach} of createBuffers([1, 9])) {
+ let byteOffset = 0;
+
+ detach();
+ assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset), TypeError);
+}
+
+// Ensure step 9 |IsDetachedBuffer(buffer)| is executed before step 11.a |bufferByteLength modulo elementSize ≠ 0|.
+// - Variant: Detach buffer dynamically.
+for (let {buffer, detach} of createBuffers([1, 9])) {
+ let byteOffset = ValueReturning(0, detach);
+
+ assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset), TypeError);
+}
+
+// Ensure step 9 |IsDetachedBuffer(buffer)| is executed before step 11.c |newByteLength < 0|.
+for (let {buffer, detach} of createBuffers()) {
+ let byteOffset = 64;
+
+ detach();
+ assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset), TypeError);
+}
+
+// Ensure step 9 |IsDetachedBuffer(buffer)| is executed before step 11.c |newByteLength < 0|.
+// - Variant: Detach buffer dynamically.
+for (let {buffer, detach} of createBuffers()) {
+ let byteOffset = ValueReturning(64, detach);
+
+ assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset), TypeError);
+}
+
+// Ensure step 9 |IsDetachedBuffer(buffer)| is executed before step 12.b |offset+newByteLength > bufferByteLength|.
+// - Case A: The given byteOffset is too large.
+for (let {buffer, detach} of createBuffers()) {
+ let byteOffset = 64;
+ let length = ValueReturning(0, detach);
+
+ assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, length), TypeError);
+}
+
+// Ensure step 9 |IsDetachedBuffer(buffer)| is executed before step 12.b |offset+newByteLength > bufferByteLength|.
+// - Case B: The given length is too large.
+for (let {buffer, detach} of createBuffers()) {
+ let byteOffset = 0;
+ let length = ValueReturning(64, detach);
+
+ assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, length), TypeError);
+}
+
+// Ensure we handle the case when ToIndex(byteOffset) detaches the array buffer.
+for (let {buffer, detach} of createBuffers()) {
+ let byteOffset = ValueReturning(0, detach);
+ let length = 0;
+
+ assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, length), TypeError);
+}
+
+// Ensure we handle the case when ToIndex(length) detaches the array buffer.
+for (let {buffer, detach} of createBuffers()) {
+ let byteOffset = 0;
+ let length = ValueReturning(0, detach);
+
+ assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, length), TypeError);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/constructor-byteoffsets-bounds.js b/js/src/tests/non262/TypedArray/constructor-byteoffsets-bounds.js
new file mode 100644
index 0000000000..ce213038d4
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-byteoffsets-bounds.js
@@ -0,0 +1,34 @@
+// 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] )
+
+// Test bound checks around for |byteOffset| and |length| arguments.
+
+const ab = new ArrayBuffer(0);
+
+for (let TA of typedArrayConstructors) {
+ // Test bound checks around INT32_MAX for |byteOffset| argument.
+ assertThrowsInstanceOf(() => new TA(ab, 2**31 - TA.BYTES_PER_ELEMENT), RangeError);
+ assertThrowsInstanceOf(() => new TA(ab, 2**31 - 1), RangeError);
+ assertThrowsInstanceOf(() => new TA(ab, 2**31), RangeError);
+ assertThrowsInstanceOf(() => new TA(ab, 2**31 + 1), RangeError);
+ assertThrowsInstanceOf(() => new TA(ab, 2**31 + TA.BYTES_PER_ELEMENT), RangeError);
+
+ // Test bound checks around UINT32_MAX for |byteOffset| argument.
+ assertThrowsInstanceOf(() => new TA(ab, 2**32 - TA.BYTES_PER_ELEMENT), RangeError);
+ assertThrowsInstanceOf(() => new TA(ab, 2**32 - 1), RangeError);
+ assertThrowsInstanceOf(() => new TA(ab, 2**32), RangeError);
+ assertThrowsInstanceOf(() => new TA(ab, 2**32 + 1), RangeError);
+ assertThrowsInstanceOf(() => new TA(ab, 2**32 + TA.BYTES_PER_ELEMENT), RangeError);
+
+ // Test bound checks around INT32_MAX for |length| argument.
+ assertThrowsInstanceOf(() => new TA(ab, 0, 2**31 - 1), RangeError);
+ assertThrowsInstanceOf(() => new TA(ab, 0, 2**31), RangeError);
+ assertThrowsInstanceOf(() => new TA(ab, 0, 2**31 + 1), RangeError);
+
+ // Test bound checks around UINT32_MAX for |length| argument.
+ assertThrowsInstanceOf(() => new TA(ab, 0, 2**32 - 1), RangeError);
+ assertThrowsInstanceOf(() => new TA(ab, 0, 2**32), RangeError);
+ assertThrowsInstanceOf(() => new TA(ab, 0, 2**32 + 1), RangeError);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/constructor-iterable-generator.js b/js/src/tests/non262/TypedArray/constructor-iterable-generator.js
new file mode 100644
index 0000000000..233eeb9d92
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-iterable-generator.js
@@ -0,0 +1,16 @@
+/* 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/. */
+
+// Construct typed array from generator.
+for (let constructor of anyTypedArrayConstructors) {
+ for (let array of [[], [1], [2, 3], [4, 5, 6], Array(1024).fill(0).map((v, i) => i % 128)]) {
+ let typedArray = new constructor(function*(){ yield* array; }());
+
+ assertEq(typedArray.length, array.length);
+ assertEqArray(typedArray, array);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/constructor-iterable-modified-array-iterator-next.js b/js/src/tests/non262/TypedArray/constructor-iterable-modified-array-iterator-next.js
new file mode 100644
index 0000000000..76eaaae46d
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-iterable-modified-array-iterator-next.js
@@ -0,0 +1,28 @@
+/* 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/. */
+
+// Construct typed array from array with modified array iterator next method.
+const ArrayIteratorPrototype = Object.getPrototypeOf([][Symbol.iterator]());
+const origNext = ArrayIteratorPrototype.next;
+const modifiedNext = function() {
+ let {value, done} = origNext.call(this);
+ return {value: value * 5, done};
+};
+for (let constructor of anyTypedArrayConstructors) {
+ for (let array of [[], [1], [2, 3], [4, 5, 6], Array(1024).fill(0).map((v, i) => i % 24)]) {
+ ArrayIteratorPrototype.next = modifiedNext;
+ let typedArray;
+ try {
+ typedArray = new constructor(array);
+ } finally {
+ ArrayIteratorPrototype.next = origNext;
+ }
+
+ assertEq(typedArray.length, array.length);
+ assertEqArray(typedArray, array.map(v => v * 5));
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/constructor-iterable-modified-array-iterator.js b/js/src/tests/non262/TypedArray/constructor-iterable-modified-array-iterator.js
new file mode 100644
index 0000000000..7c3192a6a3
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-iterable-modified-array-iterator.js
@@ -0,0 +1,28 @@
+/* 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/. */
+
+// Construct typed array from array with modified array iterator.
+const origIterator = Array.prototype[Symbol.iterator];
+const modifiedIterator = function*() {
+ for (let v of origIterator.call(this)) {
+ yield v * 5;
+ }
+};
+for (let constructor of anyTypedArrayConstructors) {
+ for (let array of [[], [1], [2, 3], [4, 5, 6], Array(1024).fill(0).map((v, i) => i % 24)]) {
+ Array.prototype[Symbol.iterator] = modifiedIterator;
+ let typedArray;
+ try {
+ typedArray = new constructor(array)
+ } finally {
+ Array.prototype[Symbol.iterator] = origIterator;
+ }
+
+ assertEq(typedArray.length, array.length);
+ assertEqArray(typedArray, array.map(v => v * 5));
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/constructor-iterable-nonpacked-array.js b/js/src/tests/non262/TypedArray/constructor-iterable-nonpacked-array.js
new file mode 100644
index 0000000000..b9586a57e5
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-iterable-nonpacked-array.js
@@ -0,0 +1,17 @@
+/* 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/. */
+
+// Construct typed array from iterable non-packed array.
+for (let constructor of anyTypedArrayConstructors) {
+ for (let array of [[,], [,,], Array(1024)]) {
+ let typedArray = new constructor(array);
+
+ assertEq(typedArray.length, array.length);
+ let expectedArray = Array(array.length).fill(isFloatConstructor(constructor) ? NaN : 0);
+ assertEqArray(typedArray, expectedArray);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/constructor-iterable-not-callable.js b/js/src/tests/non262/TypedArray/constructor-iterable-not-callable.js
new file mode 100644
index 0000000000..824760900a
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-iterable-not-callable.js
@@ -0,0 +1,15 @@
+/* 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/. */
+
+// Construct typed array from object with non-callable [Symbol.iterator] property.
+for (let constructor of anyTypedArrayConstructors) {
+ for (let iterator of [true, 0, Math.PI, "", "10", Symbol.iterator, {}, []]) {
+ assertThrowsInstanceOf(() => new constructor({
+ [Symbol.iterator]: iterator
+ }), TypeError);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/constructor-iterable-packed-array-side-effect.js b/js/src/tests/non262/TypedArray/constructor-iterable-packed-array-side-effect.js
new file mode 100644
index 0000000000..3c00af0de2
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-iterable-packed-array-side-effect.js
@@ -0,0 +1,17 @@
+/* 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/. */
+
+// Construct typed array from iterable packed array, array contains object with modifying
+// valueOf() method.
+for (let constructor of anyTypedArrayConstructors) {
+ let array = [
+ 0, 1, {valueOf() { array[3] = 30; return 2; }}, 3, 4
+ ];
+ let typedArray = new constructor(array);
+ assertEq(typedArray.length, array.length);
+ assertEqArray(typedArray, [0, 1, 2, 3, 4]);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/constructor-iterable-packed-array.js b/js/src/tests/non262/TypedArray/constructor-iterable-packed-array.js
new file mode 100644
index 0000000000..495c2da496
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-iterable-packed-array.js
@@ -0,0 +1,16 @@
+/* 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/. */
+
+// Construct typed array from iterable packed array.
+for (let constructor of anyTypedArrayConstructors) {
+ for (let array of [[], [1], [2, 3], [4, 5, 6], Array(1024).fill(0).map((v, i) => i % 128)]) {
+ let typedArray = new constructor(array);
+
+ assertEq(typedArray.length, array.length);
+ assertEqArray(typedArray, array);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/constructor-iterable-undefined-or-null.js b/js/src/tests/non262/TypedArray/constructor-iterable-undefined-or-null.js
new file mode 100644
index 0000000000..48e5aaa648
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-iterable-undefined-or-null.js
@@ -0,0 +1,22 @@
+/* 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/. */
+
+// Construct typed array from object with undefined or null [Symbol.iterator] property.
+for (let constructor of anyTypedArrayConstructors) {
+ for (let iterator of [undefined, null]) {
+ let arrayLike = {
+ [Symbol.iterator]: iterator,
+ length: 2,
+ 0: 10,
+ 1: 20,
+ };
+ let typedArray = new constructor(arrayLike);
+
+ assertEq(typedArray.length, arrayLike.length);
+ assertEqArray(typedArray, arrayLike);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/constructor-iterator-primitive.js b/js/src/tests/non262/TypedArray/constructor-iterator-primitive.js
new file mode 100644
index 0000000000..5a14d7d5a7
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-iterator-primitive.js
@@ -0,0 +1,29 @@
+var BUGNUMBER = 1021835;
+var summary = "Returning non-object from @@iterator should throw";
+
+print(BUGNUMBER + ": " + summary);
+
+let primitives = [
+ 1,
+ true,
+ undefined,
+ null,
+ "foo",
+ Symbol.iterator
+];
+
+for (let ctor of typedArrayConstructors) {
+ for (let primitive of primitives) {
+ let arg = {
+ [Symbol.iterator]() {
+ return primitive;
+ }
+ };
+ assertThrowsInstanceOf(() => {
+ new ctor(arg);
+ }, TypeError);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/TypedArray/constructor-length-too-large.js b/js/src/tests/non262/TypedArray/constructor-length-too-large.js
new file mode 100644
index 0000000000..7a7a785041
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-length-too-large.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!xulRuntime.shell)
+
+// Test that all TypedArray constructor variants throw a RangeError when
+// attempting to create a too large array.
+
+// The maximum typed array length is limited to `(INT32_MAX/BYTES_PER_ELEMENT)`
+// on all 32-bit systems; on 64-bit systems the limit is 8GB presently.
+
+const INT32_MAX = 2**31 - 1;
+const EIGHTGB = 8 * 1024 * 1024 * 1024;
+
+function tooLarge(elementSize) {
+ if (largeArrayBufferSupported()) {
+ return (EIGHTGB / elementSize) + 1;
+ }
+ return (INT32_MAX + 1) / elementSize;
+}
+
+// 22.2.4.2 TypedArray ( length )
+for (let TA of typedArrayConstructors) {
+ assertThrowsInstanceOf(() => new TA(tooLarge(1)), RangeError);
+ assertThrowsInstanceOf(() => new TA(tooLarge(TA.BYTES_PER_ELEMENT)), RangeError);
+}
+
+// Test disabled because allocating a 2**30 Int8Array easily leads to OOMs.
+//
+// 22.2.4.3 TypedArray ( typedArray )
+// const largeInt8Array = new Int8Array(2**30);
+// for (let TA of typedArrayConstructors.filter(c => c.BYTES_PER_ELEMENT > 1)) {
+// assertThrowsInstanceOf(() => new TA(largeInt8Array), RangeError);
+// }
+
+// 22.2.4.4 TypedArray ( object )
+for (let TA of typedArrayConstructors) {
+ assertThrowsInstanceOf(() => new TA({length: tooLarge(1)}), RangeError);
+ assertThrowsInstanceOf(() => new TA({length: tooLarge(TA.BYTES_PER_ELEMENT)}), RangeError);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/constructor-non-detached.js b/js/src/tests/non262/TypedArray/constructor-non-detached.js
new file mode 100644
index 0000000000..9ec9329be8
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-non-detached.js
@@ -0,0 +1,13 @@
+for (var constructor of typedArrayConstructors) {
+ var buf = new constructor();
+ detachArrayBuffer(buf.buffer);
+ assertThrowsInstanceOf(() => new constructor(buf), TypeError);
+
+ var buffer = new ArrayBuffer();
+ detachArrayBuffer(buffer);
+ assertThrowsInstanceOf(() => new constructor(buffer), TypeError);
+}
+
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/constructor-not-callable.js b/js/src/tests/non262/TypedArray/constructor-not-callable.js
new file mode 100644
index 0000000000..a3a2f8d1d5
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-not-callable.js
@@ -0,0 +1,10 @@
+for (var constructor of anyTypedArrayConstructors) {
+ assertThrowsInstanceOf(() => constructor(), TypeError);
+ assertThrowsInstanceOf(() => constructor(1), TypeError);
+ assertThrowsInstanceOf(() => constructor.call(null), TypeError);
+ assertThrowsInstanceOf(() => constructor.apply(null, []), TypeError);
+ assertThrowsInstanceOf(() => Reflect.apply(constructor, null, []), TypeError);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/constructor-typedarray-species-other-global.js b/js/src/tests/non262/TypedArray/constructor-typedarray-species-other-global.js
new file mode 100644
index 0000000000..872f46408a
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-typedarray-species-other-global.js
@@ -0,0 +1,33 @@
+// 22.2.4.3 TypedArray ( typedArray )
+
+// Test [[Prototype]] of newly created typed array and its array buffer, and
+// ensure they are both created in the correct global.
+
+const thisGlobal = this;
+const otherGlobal = newGlobal();
+
+const typedArrays = [otherGlobal.eval("new Int32Array(0)")];
+
+if (this.SharedArrayBuffer) {
+ typedArrays.push(otherGlobal.eval("new Int32Array(new SharedArrayBuffer(0))"));
+}
+
+for (let typedArray of typedArrays) {
+ // Ensure the "constructor" property isn't accessed.
+ Object.defineProperty(typedArray.buffer, "constructor", {
+ get() {
+ throw new Error("constructor property accessed");
+ }
+ });
+
+ for (let ctor of typedArrayConstructors) {
+ let newTypedArray = new ctor(typedArray);
+
+ assertEq(Object.getPrototypeOf(newTypedArray), ctor.prototype);
+ assertEq(Object.getPrototypeOf(newTypedArray.buffer), ArrayBuffer.prototype);
+ assertEq(newTypedArray.buffer.constructor, ArrayBuffer);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/TypedArray/constructor-undefined-args.js b/js/src/tests/non262/TypedArray/constructor-undefined-args.js
new file mode 100644
index 0000000000..91a557a2c1
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor-undefined-args.js
@@ -0,0 +1,14 @@
+// Bug 1040402
+
+var ab = new ArrayBuffer(16);
+
+assertEq(new Int32Array(ab).length, 4);
+assertEq(new Int32Array(ab, undefined).length, 4);
+assertEq(new Int32Array(ab, undefined, undefined).length, 4);
+assertEq(new Int32Array(ab, 0).length, 4);
+assertEq(new Int32Array(ab, 0, undefined).length, 4);
+assertEq(new Int32Array(ab, 4).length, 3);
+assertEq(new Int32Array(ab, 4, undefined).length, 3);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/constructor_bad-args.js b/js/src/tests/non262/TypedArray/constructor_bad-args.js
new file mode 100644
index 0000000000..00bbf884c6
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/constructor_bad-args.js
@@ -0,0 +1,13 @@
+// Bug 1227207
+
+var AB = new ArrayBuffer(12); // Length divides 4
+var BC = new ArrayBuffer(14); // Length does not divide 4
+
+assertThrowsInstanceOf(() => new Int32Array(AB, -1), RangeError); // 22.2.4.5 #8
+assertThrowsInstanceOf(() => new Int32Array(AB, 2), RangeError); // 22.2.4.5 #10
+assertThrowsInstanceOf(() => new Int32Array(BC), RangeError); // 22.2.4.5 #13.a
+assertThrowsInstanceOf(() => new Int32Array(AB, 16), RangeError); // 22.2.4.5 #13.c
+assertThrowsInstanceOf(() => new Int32Array(AB, 0, 4), RangeError); // 22.2.4.5 #14.c
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/detached-array-buffer-checks.js b/js/src/tests/non262/TypedArray/detached-array-buffer-checks.js
new file mode 100644
index 0000000000..55256fb29d
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/detached-array-buffer-checks.js
@@ -0,0 +1,107 @@
+// Nearly every %TypedArray%.prototype method should throw a TypeError when called
+// atop a detached array buffer. Here we check verify that this holds true for
+// all relevant functions.
+let buffer = new ArrayBuffer(32);
+let array = new Int32Array(buffer);
+detachArrayBuffer(buffer);
+
+// A nice poisoned callable to ensure that we fail on a detached buffer check
+// before a method attempts to do anything with its arguments.
+var POISON = (function() {
+ var internalTarget = {};
+ var throwForAllTraps =
+ new Proxy(internalTarget, { get(target, prop, receiver) {
+ assertEq(target, internalTarget);
+ assertEq(receiver, throwForAllTraps);
+ throw "FAIL: " + prop + " trap invoked";
+ }});
+ return new Proxy(throwForAllTraps, throwForAllTraps);
+});
+
+
+assertThrowsInstanceOf(() => {
+ array.copyWithin(POISON);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.entries();
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.fill(POISON);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.filter(POISON);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.find(POISON);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.findIndex(POISON);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.forEach(POISON);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.indexOf(POISON);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.includes(POISON);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.join(POISON);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.keys();
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.lastIndexOf(POISON);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.map(POISON);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.reduce(POISON);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.reduceRight(POISON);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.reverse();
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.slice(POISON, POISON);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.some(POISON);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.values();
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.every(POISON);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ array.sort(POISON);
+}, TypeError);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/element-setting-converts-using-ToNumber.js b/js/src/tests/non262/TypedArray/element-setting-converts-using-ToNumber.js
new file mode 100644
index 0000000000..ae465f0147
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/element-setting-converts-using-ToNumber.js
@@ -0,0 +1,91 @@
+// |reftest| slow
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+var gTestfile = 'element-setting-converts-using-ToNumber.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 985733;
+var summary =
+ "Typed array element-setting should convert to target type using ToNumber "
+ "followed by an element-type-specific truncation function";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+anyTypedArrayConstructors.forEach(function(TypedArray) {
+ var ta = new TypedArray(1);
+ assertEq(ta[0], 0);
+
+ var count = 0;
+ function setToObject()
+ {
+ for (var i = 0; i < 1e4; i++)
+ {
+ assertEq(count, i);
+ ta[0] = { valueOf: function() { count++; return 17; } };
+ }
+ }
+ setToObject();
+ assertEq(count, 1e4);
+ assertEq(ta[0], 17);
+
+ function setToString()
+ {
+ for (var i = 0; i < 2e4; i++)
+ ta[0] = "17.0000000000000000000000000000000000000000000000000000001";
+ }
+ setToString();
+ assertEq(ta[0], 17);
+
+ count = 0;
+ var arrayConstructed =
+ new TypedArray([{ valueOf: function() { count++; return 17; } },
+ "17.0000000000000000000000000000000000000000000000000001"]);
+ assertEq(count, 1);
+ assertEq(arrayConstructed[0], 17);
+ assertEq(arrayConstructed[1], 17);
+
+ count = 0;
+ var arraySet = new TypedArray(5);
+ arraySet.set({ 0: 17,
+ 1: "17.000000000000000000000000000000000000000000000000000",
+ get 2() {
+ return { valueOf: undefined,
+ toString: function() { count++; return 42; } };
+ },
+ get 3() { return true; },
+ set 3(v) { throw "FAIL"; },
+ 4: { valueOf: function() { count++; return 127; } },
+ length: 5 });
+ assertEq(count, 2);
+ assertEq(arraySet[0], 17);
+ assertEq(arraySet[1], 17);
+ assertEq(arraySet[2], 42);
+ assertEq(arraySet[3], 1);
+ assertEq(arraySet[4], 127);
+
+ var bigLen = 1e4;
+ var big = new TypedArray(bigLen);
+ function initBig()
+ {
+ for (var i = 0; i < bigLen; i++)
+ big[i] = (i % 2) ? 3 : { valueOf: function() { return 3; } };
+ }
+ initBig();
+ for (var i = 0; i < bigLen; i++)
+ {
+ assertEq(big[i], 3,
+ "(" + Object.prototype.toString.call(big) + ")");
+ }
+});
+
+/******************************************************************************/
+
+reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/TypedArray/entries.js b/js/src/tests/non262/TypedArray/entries.js
new file mode 100644
index 0000000000..c55a959e3a
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/entries.js
@@ -0,0 +1,38 @@
+for (var constructor of anyTypedArrayConstructors) {
+ assertEq(constructor.prototype.entries.length, 0);
+ assertEq(constructor.prototype.entries.name, "entries");
+
+ assertDeepEq([...new constructor(0).entries()], []);
+ assertDeepEq([...new constructor(1).entries()], [[0, 0]]);
+ assertDeepEq([...new constructor(2).entries()], [[0, 0], [1, 0]]);
+ assertDeepEq([...new constructor([15]).entries()], [[0, 15]]);
+
+ var arr = new constructor([1, 2, 3]);
+ var iterator = arr.entries();
+ assertDeepEq(iterator.next(), {value: [0, 1], done: false});
+ assertDeepEq(iterator.next(), {value: [1, 2], done: false});
+ assertDeepEq(iterator.next(), {value: [2, 3], done: false});
+ assertDeepEq(iterator.next(), {value: undefined, done: true});
+
+ // Called from other globals.
+ if (typeof newGlobal === "function") {
+ var otherGlobal = newGlobal();
+ var entries = otherGlobal[constructor.name].prototype.entries;
+ assertDeepEq([...entries.call(new constructor(2))],
+ [new otherGlobal.Array(0, 0), new otherGlobal.Array(1, 0)]);
+ arr = new (newGlobal()[constructor.name])(2);
+ assertEq([...constructor.prototype.entries.call(arr)].toString(), "0,0,1,0");
+ }
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.entries.call(invalidReceiver);
+ }, TypeError, "Assert that entries fails if this value is not a TypedArray");
+ });
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/every-and-some.js b/js/src/tests/non262/TypedArray/every-and-some.js
new file mode 100644
index 0000000000..940ac736f9
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/every-and-some.js
@@ -0,0 +1,249 @@
+// Tests for TypedArray#every.
+for (var constructor of anyTypedArrayConstructors) {
+ assertEq(constructor.prototype.every.length, 1);
+
+ // Basic tests.
+ assertEq(new constructor([1, 3, 5]).every(v => v % 2), true);
+ assertEq(new constructor([1, 3, 5]).every(v => v > 2), false);
+ assertEq(new constructor(10).every(v => v === 0), true);
+ assertEq(new constructor().every(v => v > 1), true);
+
+ var arr = new constructor([1, 2, 3, 4, 5]);
+ var sum = 0;
+ var count = 0;
+ assertEq(arr.every((v, k, o) => {
+ count++;
+ sum += v;
+ assertEq(k, v - 1);
+ assertEq(o, arr);
+ return v < 3;
+ }), false);
+ assertEq(sum, 6);
+ assertEq(count, 3);
+
+ // Tests for `thisArg` argument.
+ function assertThisArg(thisArg, thisValue) {
+ // In sloppy mode, `this` could be global object or a wrapper of `thisArg`.
+ assertEq(arr.every(function() {
+ assertDeepEq(this, thisValue);
+ return true;
+ }, thisArg), true);
+
+ // In strict mode, `this` strictly equals `thisArg`.
+ assertEq(arr.every(function() {
+ "use strict";
+ assertDeepEq(this, thisArg);
+ return true;
+ }, thisArg), true);
+
+ // Passing `thisArg` has no effect if callback is an arrow function.
+ var self = this;
+ assertEq(arr.every(() => {
+ assertEq(this, self);
+ return true;
+ }, thisArg), true);
+ }
+ assertThisArg([1, 2, 3], [1, 2, 3]);
+ assertThisArg(Object, Object);
+ assertThisArg(1, Object(1));
+ assertThisArg("1", Object("1"));
+ assertThisArg(false, Object(false));
+ assertThisArg(undefined, this);
+ assertThisArg(null, this);
+
+ // Throw an exception in the callback.
+ var sum = 0;
+ var count = 0;
+ var thrown = false;
+ try {
+ arr.every((v, k, o) => {
+ count++;
+ sum += v;
+ assertEq(k, v - 1);
+ assertEq(o, arr);
+ if (v === 3) {
+ throw "every";
+ }
+ return true
+ })
+ } catch(e) {
+ assertEq(e, "every");
+ thrown = true;
+ }
+ assertEq(thrown, true);
+ assertEq(sum, 6);
+ assertEq(count, 3);
+
+ // There is no callback or callback is not a function.
+ assertThrowsInstanceOf(() => {
+ arr.every();
+ }, TypeError);
+ var invalidCallbacks = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
+ invalidCallbacks.forEach(callback => {
+ assertThrowsInstanceOf(() => {
+ arr.every(callback);
+ }, TypeError);
+ })
+
+ // Callback is a generator.
+ arr.every(function*(){
+ throw "This line will not be executed";
+ });
+
+ // Called from other globals.
+ if (typeof newGlobal === "function") {
+ var every = newGlobal()[constructor.name].prototype.every;
+ var sum = 0;
+ assertEq(every.call(new constructor([1, 2, 3]), v => sum += v), true);
+ assertEq(sum, 6);
+ }
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.every.call(invalidReceiver, () => true);
+ }, TypeError, "Assert that every fails if this value is not a TypedArray");
+ });
+
+ // Test that the length getter is never called.
+ assertEq(Object.defineProperty(new constructor([1, 2, 3]), "length", {
+ get() {
+ throw new Error("length accessor called");
+ }
+ }).every(() => true), true);
+}
+
+for (let constructor of anyTypedArrayConstructors.filter(isFloatConstructor)) {
+ assertEq(new constructor([undefined, , NaN]).every(v => Object.is(v, NaN)), true);
+}
+
+// Tests for TypedArray#some.
+for (var constructor of anyTypedArrayConstructors) {
+ assertEq(constructor.prototype.some.length, 1);
+
+ // Basic tests.
+ assertEq(new constructor([1, 2, 3]).some(v => v % 2), true);
+ assertEq(new constructor([0, 2, 4]).some(v => v % 2), false);
+ assertEq(new constructor([1, 3, 5]).some(v => v > 2), true);
+ assertEq(new constructor([1, 3, 5]).some(v => v < 0), false);
+ assertEq(new constructor(10).some(v => v !== 0), false);
+ assertEq(new constructor().some(v => v > 1), false);
+
+ var arr = new constructor([1, 2, 3, 4, 5]);
+ var sum = 0;
+ var count = 0;
+ assertEq(arr.some((v, k, o) => {
+ count++;
+ sum += v;
+ assertEq(k, v - 1);
+ assertEq(o, arr);
+ return v > 2;
+ }), true);
+ assertEq(sum, 6);
+ assertEq(count, 3);
+
+ // Tests for `thisArg` argument.
+ function assertThisArg(thisArg, thisValue) {
+ // In sloppy mode, `this` could be global object or a wrapper of `thisArg`.
+ assertEq(arr.some(function() {
+ assertDeepEq(this, thisValue);
+ return false;
+ }, thisArg), false);
+
+ // In strict mode, `this` strictly equals `thisArg`.
+ assertEq(arr.some(function() {
+ "use strict";
+ assertDeepEq(this, thisArg);
+ return false;
+ }, thisArg), false);
+
+ // Passing `thisArg` has no effect if callback is an arrow function.
+ var self = this;
+ assertEq(arr.some(() => {
+ assertEq(this, self);
+ return false;
+ }, thisArg), false);
+ }
+ assertThisArg([1, 2, 3], [1, 2, 3]);
+ assertThisArg(Object, Object);
+ assertThisArg(1, Object(1));
+ assertThisArg("1", Object("1"));
+ assertThisArg(false, Object(false));
+ assertThisArg(undefined, this);
+ assertThisArg(null, this);
+
+ // Throw an exception in the callback.
+ var sum = 0;
+ var count = 0;
+ var thrown = false;
+ try {
+ arr.some((v, k, o) => {
+ count++;
+ sum += v;
+ assertEq(k, v - 1);
+ assertEq(o, arr);
+ if (v === 3) {
+ throw "some";
+ }
+ return false
+ })
+ } catch(e) {
+ assertEq(e, "some");
+ thrown = true;
+ }
+ assertEq(thrown, true);
+ assertEq(sum, 6);
+ assertEq(count, 3);
+
+ // There is no callback or callback is not a function.
+ assertThrowsInstanceOf(() => {
+ arr.some();
+ }, TypeError);
+ var invalidCallbacks = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
+ invalidCallbacks.forEach(callback => {
+ assertThrowsInstanceOf(() => {
+ arr.some(callback);
+ }, TypeError);
+ })
+
+ // Callback is a generator.
+ arr.some(function*(){
+ throw "This line will not be executed";
+ });
+
+ // Called from other globals.
+ if (typeof newGlobal === "function") {
+ var some = newGlobal()[constructor.name].prototype.some;
+ var sum = 0;
+ assertEq(some.call(new constructor([1, 2, 3]), v => {
+ sum += v;
+ return false;
+ }), false);
+ assertEq(sum, 6);
+ }
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.some.call(invalidReceiver, () => true);
+ }, TypeError, "Assert that some fails if this value is not a TypedArray");
+ });
+
+ // Test that the length getter is never called.
+ assertEq(Object.defineProperty(new constructor([1, 2, 3]), "length", {
+ get() {
+ throw new Error("length accessor called");
+ }
+ }).some(() => false), false);
+}
+
+for (let constructor of anyTypedArrayConstructors.filter(isFloatConstructor)) {
+ assertEq(new constructor([undefined, , NaN]).some(v => v === v), false);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/fill-detached.js b/js/src/tests/non262/TypedArray/fill-detached.js
new file mode 100644
index 0000000000..770067a81f
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/fill-detached.js
@@ -0,0 +1,36 @@
+// Ensure %TypedArray%.prototype.fill checks for detached buffers.
+
+function DetachArrayBufferValue(buffer, value) {
+ return {
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return value;
+ }
+ };
+}
+
+function DetachTypedArrayValue(ta, value) {
+ return {
+ valueOf() {
+ detachArrayBuffer(ta.buffer);
+ return value;
+ }
+ };
+}
+
+// Test when ArrayBuffer is already reified.
+for (let length of [0, 1, 10, 4096]) {
+ let ta = new Int32Array(length);
+ let value = DetachArrayBufferValue(ta.buffer, 123);
+ assertThrowsInstanceOf(() => ta.fill(value), TypeError);
+}
+
+// Test when ArrayBuffer is reified during the fill() call.
+for (let length of [0, 1, 10, 4096]) {
+ let ta = new Int32Array(length);
+ let value = DetachTypedArrayValue(ta, 123);
+ assertThrowsInstanceOf(() => ta.fill(value), TypeError);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/TypedArray/fill.js b/js/src/tests/non262/TypedArray/fill.js
new file mode 100644
index 0000000000..4349da06a9
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/fill.js
@@ -0,0 +1,65 @@
+for (var constructor of anyTypedArrayConstructors) {
+ assertDeepEq(constructor.prototype.fill.length, 1);
+
+ assertDeepEq(new constructor([]).fill(1), new constructor([]));
+ assertDeepEq(new constructor([1,1,1]).fill(2), new constructor([2,2,2]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, 1), new constructor([1,2,2]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, 1, 2), new constructor([1,2,1]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, -2), new constructor([1,2,2]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, -2, -1), new constructor([1,2,1]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, undefined), new constructor([2,2,2]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, undefined, undefined), new constructor([2,2,2]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, 1, undefined), new constructor([1,2,2]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, undefined, 1), new constructor([2,1,1]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, 2, 1), new constructor([1,1,1]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, -1, 1), new constructor([1,1,1]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, -2, 1), new constructor([1,1,1]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, 1, -2), new constructor([1,1,1]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, 0.1), new constructor([2,2,2]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, 0.9), new constructor([2,2,2]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, 1.1), new constructor([1,2,2]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, 0.1, 0.9), new constructor([1,1,1]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, 0.1, 1.9), new constructor([2,1,1]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, 0.1, 1.9), new constructor([2,1,1]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, -0), new constructor([2,2,2]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, 0, -0), new constructor([1,1,1]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, NaN), new constructor([2,2,2]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, 0, NaN), new constructor([1,1,1]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, false), new constructor([2,2,2]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, true), new constructor([1,2,2]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, "0"), new constructor([2,2,2]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, "1"), new constructor([1,2,2]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, "-2"), new constructor([1,2,2]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, "-2", "-1"), new constructor([1,2,1]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, {valueOf: ()=>1}), new constructor([1,2,2]));
+ assertDeepEq(new constructor([1,1,1]).fill(2, 0, {valueOf: ()=>1}), new constructor([2,1,1]));
+
+ // Called from other globals.
+ if (typeof newGlobal === "function") {
+ var fill = newGlobal()[constructor.name].prototype.fill;
+ assertDeepEq(fill.call(new constructor([3, 2, 1]), 2), new constructor([2, 2, 2]));
+ }
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.fill.call(invalidReceiver, 1);
+ }, TypeError);
+ });
+
+ // Test that the length getter is never called.
+ Object.defineProperty(new constructor([1, 2, 3]), "length", {
+ get() {
+ throw new Error("length accessor called");
+ }
+ }).fill(1);
+}
+
+for (let constructor of anyTypedArrayConstructors.filter(isFloatConstructor)) {
+ assertDeepEq(new constructor([0, 0]).fill(NaN), new constructor([NaN, NaN]));
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/filter-species.js b/js/src/tests/non262/TypedArray/filter-species.js
new file mode 100644
index 0000000000..2de4e254e8
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/filter-species.js
@@ -0,0 +1,56 @@
+function test(constructor, constructor2, from=[1, 2, 3, 4, 5], to=[2, 4]) {
+ var modifiedConstructor = new constructor(from);
+ modifiedConstructor.constructor = constructor2;
+ assertDeepEq(modifiedConstructor.filter(x => x % 2 == 0), new constructor2(to));
+ var modifiedSpecies = new constructor(from);
+ modifiedSpecies.constructor = { [Symbol.species]: constructor2 };
+ assertDeepEq(modifiedSpecies.filter(x => x % 2 == 0), new constructor2(to));
+}
+
+// same size, same sign
+
+test(Int8Array, Uint8Array);
+test(Int8Array, Uint8ClampedArray);
+
+test(Uint8Array, Int8Array);
+test(Uint8Array, Uint8ClampedArray);
+
+test(Uint8ClampedArray, Int8Array);
+test(Uint8ClampedArray, Uint8Array);
+
+test(Int16Array, Uint16Array);
+test(Uint16Array, Int16Array);
+
+test(Int32Array, Uint32Array);
+test(Uint32Array, Int32Array);
+
+// same size, different sign
+
+test(Int8Array, Uint8Array, [-1, -2, -3, -4, -5], [0xFE, 0xFC]);
+test(Int8Array, Uint8ClampedArray, [-1, -2, -3, -4, -5], [0, 0]);
+
+test(Uint8Array, Int8Array, [0xFF, 0xFE, 0xFD, 0xFC, 0xFB], [-2, -4]);
+test(Uint8ClampedArray, Int8Array, [0xFF, 0xFE, 0xFD, 0xFC, 0xFB], [-2, -4]);
+
+test(Int16Array, Uint16Array, [-1, -2, -3, -4, -5], [0xFFFE, 0xFFFC]);
+test(Uint16Array, Int16Array, [0xFFFF, 0xFFFE, 0xFFFD, 0xFFFC, 0xFFFB], [-2, -4]);
+
+test(Int32Array, Uint32Array, [-1, -2, -3, -4, -5], [0xFFFFFFFE, 0xFFFFFFFC]);
+test(Uint32Array, Int32Array, [0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFC, 0xFFFFFFFB], [-2, -4]);
+
+// different size
+
+test(Uint8Array, Uint16Array);
+test(Uint16Array, Uint8Array);
+
+test(Uint8Array, Uint32Array);
+test(Uint32Array, Uint8Array);
+
+test(Uint16Array, Uint32Array);
+test(Uint32Array, Uint16Array);
+
+test(Float32Array, Float64Array);
+test(Float64Array, Float32Array);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/filter-validation.js b/js/src/tests/non262/TypedArray/filter-validation.js
new file mode 100644
index 0000000000..450b4fa2cf
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/filter-validation.js
@@ -0,0 +1,185 @@
+/* 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/. */
+
+// Summary: Ensure typed array validation is called for TypedArray.prototype.filter.
+
+const otherGlobal = typeof newGlobal === "function" ? newGlobal() : undefined;
+const typedArrayLengths = [0, 1, 1024];
+
+function createTestCases(TAConstructor, constructor, constructorCrossRealm) {
+ let testCases = [];
+ testCases.push({
+ species: constructor,
+ method: TAConstructor.prototype.filter,
+ error: TypeError,
+ });
+ if (otherGlobal) {
+ testCases.push({
+ species: constructorCrossRealm,
+ method: TAConstructor.prototype.filter,
+ error: TypeError,
+ });
+ testCases.push({
+ species: constructor,
+ method: otherGlobal[TAConstructor.name].prototype.filter,
+ error: otherGlobal.TypeError,
+ });
+ }
+ return testCases;
+}
+
+// Throws TypeError when the returned value is not a typed array.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function NoTypedArrayConstructor(...args) {
+ let a = [];
+ callCount += 1;
+ return a;
+ }
+ function NoTypedArrayConstructorCrossRealm(...args) {
+ let a = new otherGlobal.Array();
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, NoTypedArrayConstructor, NoTypedArrayConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ assertThrowsInstanceOf(() => method.call(ta, () => true), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ assertThrowsInstanceOf(() => method.call(ta, () => false), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// Throws TypeError exception when returned array is too small.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function TooSmallConstructor(length) {
+ let a = new TAConstructor(Math.max(length - 1, 0));
+ callCount += 1;
+ return a;
+ }
+ function TooSmallConstructorCrossRealm(length) {
+ let a = new otherGlobal[TAConstructor.name](Math.max(length - 1, 0));
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, TooSmallConstructor, TooSmallConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+
+ // Passes when the length is zero.
+ if (length === 0) {
+ let result = method.call(ta, () => true);
+ assertEq(result.length, 0);
+ } else {
+ assertThrowsInstanceOf(() => method.call(ta, () => true), error);
+ }
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ let result = method.call(ta, () => false);
+ assertEq(result.length, 0);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// No exception when array is larger than requested.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ const extraLength = 1;
+
+ let callCount = 0, expectedCallCount = 0;
+ function TooLargeConstructor(length) {
+ let a = new TAConstructor(length + extraLength);
+ callCount += 1;
+ return a;
+ }
+ function TooLargeConstructorCrossRealm(length) {
+ let a = new otherGlobal[TAConstructor.name](length + extraLength);
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, TooLargeConstructor, TooLargeConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ let result = method.call(ta, () => true);
+ assertEq(result.length, length + extraLength);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ let result = method.call(ta, () => false);
+ assertEq(result.length, extraLength);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// Throws TypeError exception when returned array is detached.
+if (typeof detachArrayBuffer === "function") {
+ for (const TAConstructor of typedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function DetachConstructor(...args) {
+ let a = new TAConstructor(...args);
+ detachArrayBuffer(a.buffer);
+ callCount += 1;
+ return a;
+ }
+ function DetachConstructorCrossRealm(...args) {
+ let a = new otherGlobal[TAConstructor.name](...args);
+ otherGlobal.detachArrayBuffer(a.buffer);
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, DetachConstructor, DetachConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ assertThrowsInstanceOf(() => method.call(ta, () => true), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ assertThrowsInstanceOf(() => method.call(ta, () => false), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/TypedArray/find-and-findIndex.js b/js/src/tests/non262/TypedArray/find-and-findIndex.js
new file mode 100644
index 0000000000..125ababd0b
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/find-and-findIndex.js
@@ -0,0 +1,52 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * https://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var BUGNUMBER = 1078975;
+var summary = "Implement %TypedArray%.prototype.{find, findIndex}";
+print(BUGNUMBER + ": " + summary);
+
+const methods = ["find", "findIndex"];
+
+anyTypedArrayConstructors.forEach(constructor => {
+ methods.forEach(method => {
+ var arr = new constructor([0, 1, 2, 3, 4, 5]);
+ // test that this.length is never called
+ Object.defineProperty(arr, "length", {
+ get() {
+ throw new Error("length accessor called");
+ }
+ });
+ assertEq(arr[method].length, 1);
+ assertEq(arr[method](v => v === 3), 3);
+ assertEq(arr[method](v => v === 6), method === "find" ? undefined : -1);
+
+ var thisValues = [undefined, null, true, 1, "foo", [], {}];
+ if (typeof Symbol == "function")
+ thisValues.push(Symbol());
+
+ thisValues.forEach(thisArg =>
+ assertThrowsInstanceOf(() => arr[method].call(thisArg, () => true), TypeError)
+ );
+
+ assertThrowsInstanceOf(() => arr[method](), TypeError);
+ assertThrowsInstanceOf(() => arr[method](1), TypeError);
+ });
+});
+
+anyTypedArrayConstructors.filter(isFloatConstructor).forEach(constructor => {
+ var arr = new constructor([-0, 0, 1, 5, NaN, 6]);
+ assertEq(arr.find(v => Number.isNaN(v)), NaN);
+ assertEq(arr.findIndex(v => Number.isNaN(v)), 4);
+
+ assertEq(arr.find(v => Object.is(v, 0)), 0);
+ assertEq(arr.findIndex(v => Object.is(v, 0)), 1);
+
+ assertEq(arr.find(v => Object.is(v, -0)), -0);
+ assertEq(arr.findIndex(v => Object.is(v, -0)), 0);
+})
+
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/findLast-and-findLastIndex.js b/js/src/tests/non262/TypedArray/findLast-and-findLastIndex.js
new file mode 100644
index 0000000000..ed14b4a002
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/findLast-and-findLastIndex.js
@@ -0,0 +1,52 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * https://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var BUGNUMBER = 1704385;
+var summary = "Implement %TypedArray%.prototype.{findLast, findLastIndex}";
+print(BUGNUMBER + ": " + summary);
+
+const methods = ["findLast", "findLastIndex"];
+
+anyTypedArrayConstructors.forEach(constructor => {
+ methods.forEach(method => {
+ var arr = new constructor([0, 1, 2, 3, 4, 5]);
+ // test that this.length is never called
+ Object.defineProperty(arr, "length", {
+ get() {
+ throw new Error("length accessor called");
+ }
+ });
+ assertEq(arr[method].length, 1);
+ assertEq(arr[method](v => v === 3), 3);
+ assertEq(arr[method](v => v === 6), method === "findLast" ? undefined : -1);
+
+ var thisValues = [undefined, null, true, 1, "foo", [], {}];
+ if (typeof Symbol == "function")
+ thisValues.push(Symbol());
+
+ thisValues.forEach(thisArg =>
+ assertThrowsInstanceOf(() => arr[method].call(thisArg, () => true), TypeError)
+ );
+
+ assertThrowsInstanceOf(() => arr[method](), TypeError);
+ assertThrowsInstanceOf(() => arr[method](1), TypeError);
+ });
+});
+
+anyTypedArrayConstructors.filter(isFloatConstructor).forEach(constructor => {
+ var arr = new constructor([-0, 0, 1, 5, NaN, 6]);
+ assertEq(arr.findLast(v => Number.isNaN(v)), NaN);
+ assertEq(arr.findLastIndex(v => Number.isNaN(v)), 4);
+
+ assertEq(arr.findLast(v => Object.is(v, 0)), 0);
+ assertEq(arr.findLastIndex(v => Object.is(v, 0)), 1);
+
+ assertEq(arr.findLast(v => Object.is(v, -0)), -0);
+ assertEq(arr.findLastIndex(v => Object.is(v, -0)), 0);
+})
+
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/forEach.js b/js/src/tests/non262/TypedArray/forEach.js
new file mode 100644
index 0000000000..9daa690e2e
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/forEach.js
@@ -0,0 +1,93 @@
+// Tests for TypedArray#forEach
+for (var constructor of anyTypedArrayConstructors) {
+ assertEq(constructor.prototype.forEach.length, 1);
+
+ var arr = new constructor([1, 2, 3, 4, 5]);
+ // Tests for `thisArg` argument.
+ function assertThisArg(thisArg, thisValue) {
+ // In sloppy mode, `this` could be global object or a wrapper of `thisArg`.
+ arr.forEach(function() {
+ assertDeepEq(this, thisValue);
+ return false;
+ }, thisArg);
+
+ // In strict mode, `this` strictly equals `thisArg`.
+ arr.forEach(function() {
+ "use strict";
+ assertDeepEq(this, thisArg);
+ return false;
+ }, thisArg);
+
+ // Passing `thisArg` has no effect if callback is an arrow function.
+ var self = this;
+ arr.forEach(() => {
+ assertEq(this, self);
+ return false;
+ }, thisArg);
+ }
+ assertThisArg([1, 2, 3], [1, 2, 3]);
+ assertThisArg(Object, Object);
+ assertThisArg(1, Object(1));
+ assertThisArg("1", Object("1"));
+ assertThisArg(false, Object(false));
+ assertThisArg(undefined, this);
+ assertThisArg(null, this);
+
+ // Throw an exception in the callback.
+ var sum = 0;
+ var count = 0;
+ var thrown = false;
+ try {
+ assertEq(arr.forEach((v) => {
+ count++;
+ sum += v;
+ if (v === 3) {
+ throw "forEach";
+ }
+ }), undefined)
+ } catch(e) {
+ assertEq(e, "forEach");
+ thrown = true;
+ }
+ assertEq(thrown, true);
+ assertEq(sum, 6);
+ assertEq(count, 3);
+
+ // There is no callback or callback is not a function.
+ assertThrowsInstanceOf(() => {
+ arr.forEach();
+ }, TypeError);
+ var invalidCallbacks = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
+ invalidCallbacks.forEach(callback => {
+ assertThrowsInstanceOf(() => {
+ arr.forEach(callback);
+ }, TypeError);
+ })
+
+ // Callback is a generator.
+ arr.forEach(function*(){
+ throw "This line will not be executed";
+ });
+
+ // Called from other globals.
+ if (typeof newGlobal === "function") {
+ var forEach = newGlobal()[constructor.name].prototype.forEach;
+ var sum = 0;
+ forEach.call(new constructor([1, 2, 3]), v => {
+ sum += v;
+ });
+ assertEq(sum, 6);
+ }
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.forEach.call(invalidReceiver, () => true);
+ }, TypeError, "Assert that some fails if this value is not a TypedArray");
+ });
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/from-iterable-validation.js b/js/src/tests/non262/TypedArray/from-iterable-validation.js
new file mode 100644
index 0000000000..50d46bb81f
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/from-iterable-validation.js
@@ -0,0 +1,140 @@
+/* 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/. */
+
+// Summary: Ensure typed array validation is called for TypedArray.from.
+
+const otherGlobal = typeof newGlobal === "function" ? newGlobal() : undefined;
+const typedArrayArgs = [[], [123], [123, ...Array(1023).fill(0)]];
+
+function createTestCases(TAConstructor, constructor, constructorCrossRealm) {
+ let testCases = [];
+ testCases.push({
+ species: constructor,
+ method: TAConstructor.from,
+ error: TypeError,
+ });
+ if (otherGlobal) {
+ testCases.push({
+ species: constructorCrossRealm,
+ method: TAConstructor.from,
+ error: TypeError,
+ });
+ testCases.push({
+ species: constructor,
+ method: otherGlobal[TAConstructor.name].from,
+ error: otherGlobal.TypeError,
+ });
+ }
+ return testCases;
+}
+
+// Throws TypeError when the returned value is not a typed array.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function NoTypedArrayConstructor(...args) {
+ let a = [];
+ callCount += 1;
+ return a;
+ }
+ function NoTypedArrayConstructorCrossRealm(...args) {
+ let a = new otherGlobal.Array();
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, NoTypedArrayConstructor, NoTypedArrayConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let args of typedArrayArgs) {
+ assertThrowsInstanceOf(() => method.call(species, args), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// Throws TypeError exception when returned array is too small.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function TooSmallConstructor(length) {
+ let a = new TAConstructor(Math.max(length - 1, 0));
+ callCount += 1;
+ return a;
+ }
+ function TooSmallConstructorCrossRealm(length) {
+ let a = new otherGlobal[TAConstructor.name](Math.max(length - 1, 0));
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, TooSmallConstructor, TooSmallConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let args of typedArrayArgs) {
+ // Passes when the length is zero.
+ if (args.length === 0) {
+ let result = method.call(species, args);
+ assertEq(result.length, 0);
+ } else {
+ assertThrowsInstanceOf(() => method.call(species, args), error);
+ }
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// No exception when array is larger than requested.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ const extraLength = 1;
+
+ let callCount = 0, expectedCallCount = 0;
+ function TooLargeConstructor(length) {
+ let a = new TAConstructor(length + extraLength);
+ callCount += 1;
+ return a;
+ }
+ function TooLargeConstructorCrossRealm(length) {
+ let a = new otherGlobal[TAConstructor.name](length + extraLength);
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, TooLargeConstructor, TooLargeConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let args of typedArrayArgs) {
+ let result = method.call(species, args);
+ assertEq(result.length, args.length + extraLength);
+ assertEq(result[0], (args.length === 0 ? 0 : 123));
+ assertEq(result[args.length + extraLength - 1], 0);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// Throws TypeError exception when returned array is detached.
+if (typeof detachArrayBuffer === "function") {
+ for (const TAConstructor of typedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function DetachConstructor(...args) {
+ let a = new TAConstructor(...args);
+ detachArrayBuffer(a.buffer);
+ callCount += 1;
+ return a;
+ }
+ function DetachConstructorCrossRealm(...args) {
+ let a = new otherGlobal[TAConstructor.name](...args);
+ otherGlobal.detachArrayBuffer(a.buffer);
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, DetachConstructor, DetachConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let args of typedArrayArgs) {
+ assertThrowsInstanceOf(() => method.call(species, args), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/TypedArray/from-non-iterable-validation.js b/js/src/tests/non262/TypedArray/from-non-iterable-validation.js
new file mode 100644
index 0000000000..3276426b28
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/from-non-iterable-validation.js
@@ -0,0 +1,140 @@
+/* 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/. */
+
+// Summary: Ensure typed array validation is called for TypedArray.from.
+
+const otherGlobal = typeof newGlobal === "function" ? newGlobal() : undefined;
+const typedArrayArgs = [{length: 0}, {length: 1, 0: 123}, {length: 1024, 0: 123}];
+
+function createTestCases(TAConstructor, constructor, constructorCrossRealm) {
+ let testCases = [];
+ testCases.push({
+ species: constructor,
+ method: TAConstructor.from,
+ error: TypeError,
+ });
+ if (otherGlobal) {
+ testCases.push({
+ species: constructorCrossRealm,
+ method: TAConstructor.from,
+ error: TypeError,
+ });
+ testCases.push({
+ species: constructor,
+ method: otherGlobal[TAConstructor.name].from,
+ error: otherGlobal.TypeError,
+ });
+ }
+ return testCases;
+}
+
+// Throws TypeError when the returned value is not a typed array.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function NoTypedArrayConstructor(...args) {
+ let a = [];
+ callCount += 1;
+ return a;
+ }
+ function NoTypedArrayConstructorCrossRealm(...args) {
+ let a = new otherGlobal.Array();
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, NoTypedArrayConstructor, NoTypedArrayConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let args of typedArrayArgs) {
+ assertThrowsInstanceOf(() => method.call(species, args), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// Throws TypeError exception when returned array is too small.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function TooSmallConstructor(length) {
+ let a = new TAConstructor(Math.max(length - 1, 0));
+ callCount += 1;
+ return a;
+ }
+ function TooSmallConstructorCrossRealm(length) {
+ let a = new otherGlobal[TAConstructor.name](Math.max(length - 1, 0));
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, TooSmallConstructor, TooSmallConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let args of typedArrayArgs) {
+ // Passes when the length is zero.
+ if (args.length === 0) {
+ let result = method.call(species, args);
+ assertEq(result.length, 0);
+ } else {
+ assertThrowsInstanceOf(() => method.call(species, args), error);
+ }
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// No exception when array is larger than requested.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ const extraLength = 1;
+
+ let callCount = 0, expectedCallCount = 0;
+ function TooLargeConstructor(length) {
+ let a = new TAConstructor(length + extraLength);
+ callCount += 1;
+ return a;
+ }
+ function TooLargeConstructorCrossRealm(length) {
+ let a = new otherGlobal[TAConstructor.name](length + extraLength);
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, TooLargeConstructor, TooLargeConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let args of typedArrayArgs) {
+ let result = method.call(species, args);
+ assertEq(result.length, args.length + extraLength);
+ assertEq(result[0], (args.length === 0 ? 0 : 123));
+ assertEq(result[args.length + extraLength - 1], 0);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// Throws TypeError exception when returned array is detached.
+if (typeof detachArrayBuffer === "function") {
+ for (const TAConstructor of typedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function DetachConstructor(...args) {
+ let a = new TAConstructor(...args);
+ detachArrayBuffer(a.buffer);
+ callCount += 1;
+ return a;
+ }
+ function DetachConstructorCrossRealm(...args) {
+ let a = new otherGlobal[TAConstructor.name](...args);
+ otherGlobal.detachArrayBuffer(a.buffer);
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, DetachConstructor, DetachConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let args of typedArrayArgs) {
+ assertThrowsInstanceOf(() => method.call(species, args), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/TypedArray/from_basics.js b/js/src/tests/non262/TypedArray/from_basics.js
new file mode 100644
index 0000000000..9f53feb72d
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/from_basics.js
@@ -0,0 +1,42 @@
+for (var constructor of anyTypedArrayConstructors) {
+ // 'from' method is identical for all typed array constructors.
+ assertEq(anyTypedArrayConstructors[0].from === constructor.from, true);
+
+ // %TypedArray%.from copies arrays.
+ var src = new constructor([1, 2, 3]), copy = constructor.from(src);
+ assertEq(copy === src, false);
+ assertEq(copy instanceof constructor, true);
+ assertDeepEq(copy, src);
+
+ // Non-element properties are not copied.
+ var a = new constructor([0, 1]);
+ a.name = "lisa";
+ assertDeepEq(constructor.from(a), new constructor([0, 1]));
+
+ // %TypedArray%.from can copy non-iterable objects, if they're array-like.
+ src = {0: 0, 1: 1, length: 2};
+ copy = constructor.from(src);
+ assertEq(copy instanceof constructor, true);
+ assertDeepEq(copy, new constructor([0, 1]));
+
+ // Properties past the .length are not copied.
+ src = {0: "0", 1: "1", 2: "two", 9: "nine", name: "lisa", length: 2};
+ assertDeepEq(constructor.from(src), new constructor([0, 1]));
+
+ // If an object has neither an @@iterator method nor .length,
+ // then it's treated as zero-length.
+ assertDeepEq(constructor.from({}), new constructor());
+
+ // Primitives will be coerced to primitive wrapper first.
+ assertDeepEq(constructor.from(1), new constructor());
+ assertDeepEq(constructor.from("123"), new constructor([1, 2, 3]));
+ assertDeepEq(constructor.from(true), new constructor());
+ assertDeepEq(constructor.from(Symbol()), new constructor());
+
+ // Source object property order doesn't matter.
+ src = {length: 2, 1: "1", 0: "0"};
+ assertDeepEq(constructor.from(src), new constructor([0, 1]));
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/from_constructor.js b/js/src/tests/non262/TypedArray/from_constructor.js
new file mode 100644
index 0000000000..0b0773b85c
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/from_constructor.js
@@ -0,0 +1,36 @@
+for (var constructor of anyTypedArrayConstructors) {
+ // Note %TypedArray%.from(iterable) calls 'this' with an argument whose value is
+ // `[...iterable].length`, while Array.from(iterable) doesn't pass any argument.
+ constructor.from.call(function(len){
+ assertEq(len, 3);
+ return new constructor(len);
+ }, Array(3));
+
+ // If the 'this' value passed to %TypedArray.from is not a constructor,
+ // then an exception is thrown, while Array.from will use Array as it's constructor.
+ var arr = [3, 4, 5];
+ var nonconstructors = [
+ {}, Math, Object.getPrototypeOf, undefined, 17,
+ () => ({}) // arrow functions are not constructors
+ ];
+ for (var v of nonconstructors) {
+ assertThrowsInstanceOf(() => {
+ constructor.from.call(v, arr);
+ }, TypeError);
+ }
+
+ // %TypedArray%.from does not get confused if global constructors for typed arrays
+ // are replaced with another constructor.
+ function NotArray(...rest) {
+ return new constructor(...rest);
+ }
+ var RealArray = constructor;
+ NotArray.from = constructor.from;
+ this[constructor.name] = NotArray;
+ assertEq(RealArray.from([1]) instanceof RealArray, true);
+ assertEq(NotArray.from([1]) instanceof RealArray, true);
+ this[constructor.name] = RealArray;
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/from_errors.js b/js/src/tests/non262/TypedArray/from_errors.js
new file mode 100644
index 0000000000..281b1b5129
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/from_errors.js
@@ -0,0 +1,76 @@
+for (var constructor of anyTypedArrayConstructors) {
+ // %TypedArray%.from throws if the argument is undefined or null.
+ assertThrowsInstanceOf(() => constructor.from(), TypeError);
+ assertThrowsInstanceOf(() => constructor.from(undefined), TypeError);
+ assertThrowsInstanceOf(() => constructor.from(null), TypeError);
+
+ // Unlike Array.from, %TypedArray%.from doesn't get or set the length property.
+ function ObjectWithThrowingLengthGetterSetter(...rest) {
+ var ta = new constructor(...rest);
+ Object.defineProperty(ta, "length", {
+ configurable: true,
+ get() { throw new RangeError("getter!"); },
+ set() { throw new RangeError("setter!"); }
+ });
+ return ta;
+ }
+ ObjectWithThrowingLengthGetterSetter.from = constructor.from;
+ assertEq(ObjectWithThrowingLengthGetterSetter.from([123])[0], 123);
+
+ // %TypedArray%.from throws if mapfn is neither callable nor undefined.
+ assertThrowsInstanceOf(() => constructor.from([3, 4, 5], {}), TypeError);
+ assertThrowsInstanceOf(() => constructor.from([3, 4, 5], "also not a function"), TypeError);
+ assertThrowsInstanceOf(() => constructor.from([3, 4, 5], null), TypeError);
+
+ // Even if the function would not have been called.
+ assertThrowsInstanceOf(() => constructor.from([], JSON), TypeError);
+
+ // If mapfn is not undefined and not callable, the error happens before anything else.
+ // Before calling the constructor, before touching the arrayLike.
+ var log = "";
+ var obj;
+ function C(...rest) {
+ log += "C";
+ obj = new constructor(...rest);
+ return obj;
+ }
+ var p = new Proxy({}, {
+ has: function () { log += "1"; },
+ get: function () { log += "2"; },
+ getOwnPropertyDescriptor: function () { log += "3"; }
+ });
+ assertThrowsInstanceOf(() => constructor.from.call(C, p, {}), TypeError);
+ assertEq(log, "");
+
+ // If mapfn throws, the new object has already been created.
+ var arrayish = {
+ get length() { log += "l"; return 1; },
+ get 0() { log += "0"; return "q"; }
+ };
+ log = "";
+ var exc = {surprise: "ponies"};
+ assertThrowsValue(() => constructor.from.call(C, arrayish, () => { throw exc; }), exc);
+ assertEq(log, "lC0");
+ assertEq(obj instanceof constructor, true);
+
+ // It's a TypeError if the @@iterator property is a primitive (except null and undefined).
+ for (var primitive of ["foo", 17, Symbol(), true]) {
+ assertThrowsInstanceOf(() => constructor.from({[Symbol.iterator] : primitive}), TypeError);
+ }
+ assertDeepEq(constructor.from({[Symbol.iterator]: null}), new constructor());
+ assertDeepEq(constructor.from({[Symbol.iterator]: undefined}), new constructor());
+
+ // It's a TypeError if the iterator's .next() method returns a primitive.
+ for (var primitive of [undefined, null, "foo", 17, Symbol(), true]) {
+ assertThrowsInstanceOf(
+ () => constructor.from({
+ [Symbol.iterator]() {
+ return {next() { return primitive; }};
+ }
+ }),
+ TypeError);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/from_iterable.js b/js/src/tests/non262/TypedArray/from_iterable.js
new file mode 100644
index 0000000000..889c815898
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/from_iterable.js
@@ -0,0 +1,49 @@
+for (var constructor of anyTypedArrayConstructors) {
+ // %TypedArray%.from works on arguments objects.
+ (function () {
+ assertDeepEq(constructor.from(arguments), new constructor(["0", "1", undefined]));
+ })("0", "1", undefined);
+
+ // If an object has both .length and [@@iterator] properties, [@@iterator] is used.
+ var a = ['0', '1', '2', '3', '4'];
+ a[Symbol.iterator] = function* () {
+ for (var i = 5; i--; )
+ yield this[i];
+ };
+
+ var log = '';
+ function f(x) {
+ log += x;
+ return x + x;
+ }
+
+ var b = constructor.from(a, f);
+ assertDeepEq(b, new constructor(['44', '33', '22', '11', '00']));
+ assertEq(log, '43210');
+
+ // In fact, if [@@iterator] is present, .length isn't queried at all.
+ var pa = new Proxy(a, {
+ has: function (target, id) {
+ if (id === "length")
+ throw new Error(".length should not be queried (has)");
+ return id in target;
+ },
+ get: function (target, id) {
+ if (id === "length")
+ throw new Error(".length should not be queried (get)");
+ return target[id];
+ },
+ getOwnPropertyDescriptor: function (target, id) {
+ if (id === "length")
+ throw new Error(".length should not be queried (getOwnPropertyDescriptor)");
+ return Object.getOwnPropertyDescriptor(target, id)
+ }
+ });
+ log = "";
+ b = constructor.from(pa, f);
+ assertDeepEq(b, new constructor(['44', '33', '22', '11', '00']));
+ assertEq(log, '43210');
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/from_mapping.js b/js/src/tests/non262/TypedArray/from_mapping.js
new file mode 100644
index 0000000000..1c24815418
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/from_mapping.js
@@ -0,0 +1,45 @@
+for (var constructor of anyTypedArrayConstructors) {
+ // If the mapfn argument to %TypedArray%.from is undefined, don't map.
+ assertDeepEq(constructor.from([3, 4, 5], undefined), new constructor([3, 4, 5]));
+ assertDeepEq(constructor.from([4, 5, 6], undefined, Math), new constructor([4, 5, 6]));
+
+ // mapfn is called with two arguments: value and index.
+ var log = [];
+ function f(...args) {
+ log.push(args);
+ return log.length;
+ }
+ assertDeepEq(constructor.from(['a', 'e', 'i', 'o', 'u'], f), new constructor([1, 2, 3, 4, 5]));
+ assertDeepEq(log, [['a', 0], ['e', 1], ['i', 2], ['o', 3], ['u', 4]]);
+
+ // If the object to be copied is non-iterable, mapfn is still called with two
+ // arguments.
+ log = [];
+ assertDeepEq(constructor.from({0: "zero", 1: "one", length: 2}, f), new constructor([1, 2]));
+ assertDeepEq(log, [["zero", 0], ["one", 1]]);
+
+ // If the object to be copied is iterable and the constructor is not Array,
+ // mapfn is still called with two arguments.
+ log = [];
+ function C(...rest) {
+ return new constructor(...rest);
+ }
+ C.from = constructor.from;
+ var c = new C(2);
+ c[0] = 1;
+ c[1] = 2;
+ assertDeepEq(C.from(["zero", "one"], f), c);
+ assertDeepEq(log, [["zero", 0], ["one", 1]]);
+
+ // The mapfn is called even if the value to be mapped is undefined.
+ assertDeepEq(constructor.from([0, 1, , 3], String), new constructor(["0", "1", "undefined", "3"]));
+ var arraylike = {length: 4, "0": 0, "1": 1, "3": 3};
+ assertDeepEq(constructor.from(arraylike, String), new constructor(["0", "1", "undefined", "3"]));
+}
+
+// %TypedArray%.from(obj, map) is not exactly the same as %TypedArray%.from(obj).map(mapFn).
+assertDeepEq(Int8Array.from([150], v => v / 2), new Int8Array([75]));
+assertDeepEq(Int8Array.from([150]).map(v => v / 2), new Int8Array([-53]));
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/from_realms.js b/js/src/tests/non262/TypedArray/from_realms.js
new file mode 100644
index 0000000000..590589392f
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/from_realms.js
@@ -0,0 +1,32 @@
+for (var constructor of anyTypedArrayConstructors) {
+ if (typeof newGlobal !== 'function')
+ break;
+
+ // G[constructor.name].from, where G is any global, produces an array whose prototype
+ // is G[constructor.name].prototype.
+ var g = newGlobal();
+ var ga = g[constructor.name].from([1, 2, 3]);
+ assertEq(ga instanceof g[constructor.name], true);
+
+ // %TypedArray%.from can be applied to a constructor from another realm.
+ var p = constructor.from.call(g[constructor.name], [1, 2, 3]);
+ assertEq(p instanceof g[constructor.name], true);
+ var q = g[constructor.name].from.call(constructor, [3, 4, 5]);
+ assertEq(q instanceof constructor, true);
+
+ // The default 'this' value received by a non-strict mapping function is
+ // that function's global, not %TypedArray%.from's global or the caller's global.
+ var h = newGlobal(), result = undefined;
+ h.mainGlobal = this;
+ h.eval("function f() { mainGlobal.result = this; }");
+ g[constructor.name].from.call(constructor, [5, 6, 7], h.f);
+ // (Give each global in the test a name, for better error messages. But use
+ // globalName, because window.name is complicated.)
+ this.globalName = "main";
+ g.globalName = "g";
+ h.globalName = "h";
+ assertEq(result.globalName, "h");
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/from_string.js b/js/src/tests/non262/TypedArray/from_string.js
new file mode 100644
index 0000000000..09a2c36710
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/from_string.js
@@ -0,0 +1,24 @@
+// %TypedArray%.from called on Array should also handle strings correctly.
+var from = Int8Array.from.bind(Uint32Array);
+var toCodePoint = s => s.codePointAt(0);
+
+// %TypedArray%.from on a string iterates over the string.
+assertEqArray(from("test string", toCodePoint),
+ ['t', 'e', 's', 't', ' ', 's', 't', 'r', 'i', 'n', 'g'].map(toCodePoint));
+
+// %TypedArray%.from on a string handles surrogate pairs correctly.
+var gclef = "\uD834\uDD1E"; // U+1D11E MUSICAL SYMBOL G CLEF
+assertEqArray(from(gclef, toCodePoint), [gclef].map(toCodePoint));
+assertEqArray(from(gclef + " G", toCodePoint), [gclef, " ", "G"].map(toCodePoint));
+
+// %TypedArray%.from on a string calls the @@iterator method.
+String.prototype[Symbol.iterator] = function* () { yield 1; yield 2; };
+assertEqArray(from("anything"), [1, 2]);
+
+// If the iterator method is deleted, Strings are still arraylike.
+delete String.prototype[Symbol.iterator];
+assertEqArray(from("works", toCodePoint), ['w', 'o', 'r', 'k', 's'].map(toCodePoint));
+assertEqArray(from(gclef, toCodePoint), ['\uD834', '\uDD1E'].map(toCodePoint));
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/from_surfaces.js b/js/src/tests/non262/TypedArray/from_surfaces.js
new file mode 100644
index 0000000000..ef15536378
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/from_surfaces.js
@@ -0,0 +1,12 @@
+for (var constructor of anyTypedArrayConstructors) {
+ // Check superficial features of %TypeArray%.from.
+ var desc = Object.getOwnPropertyDescriptor(constructor.__proto__, "from");
+ assertEq(desc.configurable, true);
+ assertEq(desc.enumerable, false);
+ assertEq(desc.writable, true);
+ assertEq(constructor.from.length, 1);
+ assertThrowsInstanceOf(() => new constructor.from(), TypeError); // not a constructor
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/from_this.js b/js/src/tests/non262/TypedArray/from_this.js
new file mode 100644
index 0000000000..95af053b8d
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/from_this.js
@@ -0,0 +1,59 @@
+for (var constructor of anyTypedArrayConstructors) {
+ // The third argument to %TypedArray%.from is passed as the 'this' value to the
+ // mapping function.
+ var hits = 0, obj = {};
+ function f(x) {
+ assertEq(this, obj);
+ hits++;
+ }
+ constructor.from(["a", "b", "c"], f, obj);
+ assertEq(hits, 3);
+
+ // Without an argument, undefined is passed...
+ hits = 0;
+ function gs(x) {
+ "use strict";
+ assertEq(this, undefined);
+ hits++;
+ }
+ constructor.from("def", gs);
+ assertEq(hits, 3);
+
+ // ...and if the mapping function is non-strict, that means the global is
+ // passed.
+ var global = this;
+ hits = 0;
+ function g(x) {
+ assertEq(this, global);
+ hits++;
+ }
+ constructor.from("ghi", g);
+ assertEq(hits, 3);
+
+ // A primitive value can be passed.
+ for (var v of [0, "str", undefined]) {
+ hits = 0;
+ var mapfn = function h(x) {
+ "use strict";
+ assertEq(this, v);
+ hits++;
+ };
+ constructor.from("pq", mapfn, v);
+ assertEq(hits, 2);
+ }
+
+ // ...and if the mapping function is non-strict, primitive values will
+ // be wrapped to objects.
+ for (var v of [0, "str", true]) {
+ hits = 0;
+ var mapfn = function h(x) {
+ assertDeepEq(this, Object(v));
+ hits++;
+ };
+ constructor.from("pq", mapfn, v);
+ assertEq(hits, 2);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/from_typedarray_fastpath_detached.js b/js/src/tests/non262/TypedArray/from_typedarray_fastpath_detached.js
new file mode 100644
index 0000000000..d1f574cb10
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/from_typedarray_fastpath_detached.js
@@ -0,0 +1,10 @@
+// Ensure the fast-path when TypedArray.from is called with a TypedArray still
+// checks for detached buffers.
+
+var ta = new Int32Array(4);
+detachArrayBuffer(ta.buffer);
+
+assertThrowsInstanceOf(() => Int32Array.from(ta), TypeError);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/getter-name.js b/js/src/tests/non262/TypedArray/getter-name.js
new file mode 100644
index 0000000000..47050e3c1b
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/getter-name.js
@@ -0,0 +1,16 @@
+var BUGNUMBER = 1180290;
+var summary = 'TypedArray getters should have get prefix';
+
+print(BUGNUMBER + ": " + summary);
+
+let TypedArray = Object.getPrototypeOf(Float32Array.prototype).constructor;
+
+assertEq(Object.getOwnPropertyDescriptor(TypedArray, Symbol.species).get.name, "get [Symbol.species]");
+assertEq(Object.getOwnPropertyDescriptor(TypedArray.prototype, "buffer").get.name, "get buffer");
+assertEq(Object.getOwnPropertyDescriptor(TypedArray.prototype, "byteLength").get.name, "get byteLength");
+assertEq(Object.getOwnPropertyDescriptor(TypedArray.prototype, "byteOffset").get.name, "get byteOffset");
+assertEq(Object.getOwnPropertyDescriptor(TypedArray.prototype, "length").get.name, "get length");
+assertEq(Object.getOwnPropertyDescriptor(TypedArray.prototype, Symbol.toStringTag).get.name, "get [Symbol.toStringTag]");
+
+if (typeof reportCompare === 'function')
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/has-property-op.js b/js/src/tests/non262/TypedArray/has-property-op.js
new file mode 100644
index 0000000000..7ae70ef36d
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/has-property-op.js
@@ -0,0 +1,22 @@
+for (var constructor of anyTypedArrayConstructors) {
+ var obj = new constructor(5);
+
+ for (var i = 0; i < obj.length; i++)
+ assertEq(i in obj, true);
+
+ for (var v of [20, 300, -1, 5, -10, Math.pow(2, 32) - 1, -Math.pow(2, 32)])
+ assertEq(v in obj, false);
+
+ // Don't inherit elements
+ obj.__proto__[50] = "hello";
+ assertEq(obj.__proto__[50], "hello");
+ assertEq(50 in obj, false);
+
+ // Do inherit normal properties
+ obj.__proto__.a = "world";
+ assertEq(obj.__proto__.a, "world");
+ assertEq("a" in obj, true);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/includes.js b/js/src/tests/non262/TypedArray/includes.js
new file mode 100644
index 0000000000..bcc50a2572
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/includes.js
@@ -0,0 +1,40 @@
+for (var constructor of anyTypedArrayConstructors) {
+ assertEq(constructor.prototype.includes.length, 1);
+
+ assertEq(new constructor([1, 2, 3]).includes(1), true);
+ assertEq(new constructor([1, 2, 3]).includes(2), true);
+ assertEq(new constructor([1, 2, 3]).includes(3), true);
+ assertEq(new constructor([1, 2, 3]).includes(2, 1), true);
+ assertEq(new constructor([1, 2, 3]).includes(2, -2), true);
+ assertEq(new constructor([1, 2, 3]).includes(2, -100), true);
+
+ assertEq(new constructor([1, 2, 3]).includes("2"), false);
+ assertEq(new constructor([1, 2, 3]).includes(2, 2), false);
+ assertEq(new constructor([1, 2, 3]).includes(2, -1), false);
+ assertEq(new constructor([1, 2, 3]).includes(2, 100), false);
+
+ // Called from other globals.
+ if (typeof newGlobal === "function") {
+ var includes = newGlobal()[constructor.name].prototype.includes;
+ assertEq(includes.call(new constructor([1, 2, 3]), 2), true);
+ }
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.includes.call(invalidReceiver);
+ }, TypeError, "Assert that reverse fails if this value is not a TypedArray");
+ });
+
+ // Test that the length getter is never called.
+ assertEq(Object.defineProperty(new constructor([1, 2, 3]), "length", {
+ get() {
+ throw new Error("length accessor called");
+ }
+ }).includes(2), true);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/indexOf-and-lastIndexOf.js b/js/src/tests/non262/TypedArray/indexOf-and-lastIndexOf.js
new file mode 100644
index 0000000000..c179f78502
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/indexOf-and-lastIndexOf.js
@@ -0,0 +1,123 @@
+// Tests for TypedArray#indexOf.
+for (var constructor of anyTypedArrayConstructors) {
+ assertEq(constructor.prototype.indexOf.length, 1);
+
+ // Works with one argument.
+ assertEq(new constructor([1, 2, 3, 4, 5]).indexOf(0), -1);
+ assertEq(new constructor([1, 2, 3, 4, 5]).indexOf(1), 0);
+ assertEq(new constructor([1, 2, 3, 4, 5]).indexOf(5), 4);
+ assertEq(new constructor([1, 2, 3, 4, 5]).indexOf(6), -1);
+ assertEq(new constructor([1, 2, 1, 2, 1]).indexOf(1), 0);
+
+ if (isFloatConstructor(constructor)) {
+ assertEq(new constructor([NaN, 0, -0]).indexOf(NaN), -1);
+ assertEq(new constructor([NaN, 0, -0]).indexOf(0), 1);
+ assertEq(new constructor([NaN, 0, -0]).indexOf(-0), 1);
+ } else {
+ // [NaN, 0, -0] will be coerced to [0, 0, 0]
+ assertEq(new constructor([NaN, 0, -0]).indexOf(NaN), -1);
+ assertEq(new constructor([NaN, 0, -0]).indexOf(0), 0);
+ assertEq(new constructor([NaN, 0, -0]).indexOf(-0), 0);
+ }
+
+ // Works with two arguments.
+ assertEq(new constructor([1, 2, 3, 4, 5]).indexOf(1, 1), -1);
+ assertEq(new constructor([1, 2, 3, 4, 5]).indexOf(1, -100), 0);
+ assertEq(new constructor([1, 2, 3, 4, 5]).indexOf(3, 100), -1);
+ assertEq(new constructor([1, 2, 3, 4, 5]).indexOf(5, -1), 4);
+ assertEq(new constructor([1, 2, 1, 2, 1]).indexOf(1, 2), 2);
+ assertEq(new constructor([1, 2, 1, 2, 1]).indexOf(1, -2), 4);
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.indexOf.call(invalidReceiver);
+ }, TypeError, "Assert that indexOf fails if this value is not a TypedArray");
+ });
+
+ // test that this.length is never called
+ assertEq(Object.defineProperty(new constructor([0, 1, 2, 3, 5]), "length", {
+ get() {
+ throw new Error("length accessor called");
+ }
+ }).indexOf(1), 1);
+}
+
+for (let constructor of anyTypedArrayConstructors.filter(isFloatConstructor)) {
+ if (constructor.BYTES_PER_ELEMENT === 4) {
+ assertEq(new constructor([.1, .2, .3]).indexOf(.2), -1);
+ assertEq(new constructor([.1, .2, .3]).indexOf(Math.fround(.2)), 1);
+ } else {
+ assertEq(constructor.BYTES_PER_ELEMENT, 8);
+ assertEq(new constructor([.1, .2, .3]).indexOf(.2), 1);
+ }
+}
+
+// Tests for TypedArray#lastIndexOf.
+for (var constructor of anyTypedArrayConstructors) {
+
+ assertEq(constructor.prototype.lastIndexOf.length, 1);
+
+ // Works with one arguments.
+ assertEq(new constructor([1, 2, 3, 4, 5]).lastIndexOf(0), -1);
+ assertEq(new constructor([1, 2, 3, 4, 5]).lastIndexOf(1), 0);
+ assertEq(new constructor([1, 2, 3, 4, 5]).lastIndexOf(5), 4);
+ assertEq(new constructor([1, 2, 3, 4, 5]).lastIndexOf(6), -1);
+ assertEq(new constructor([1, 2, 1, 2, 1]).lastIndexOf(1), 4);
+
+ if (isFloatConstructor(constructor)) {
+ assertEq(new constructor([NaN, 0, -0]).lastIndexOf(NaN), -1);
+ assertEq(new constructor([NaN, 0, -0]).lastIndexOf(0), 2);
+ assertEq(new constructor([NaN, 0, -0]).lastIndexOf(-0), 2);
+ } else {
+ // [NaN, 0, -0] will be coerced to [0, 0, 0].
+ assertEq(new constructor([NaN, 0, -0]).lastIndexOf(NaN), -1);
+ assertEq(new constructor([NaN, 0, -0]).lastIndexOf(0), 2);
+ assertEq(new constructor([NaN, 0, -0]).lastIndexOf(-0), 2);
+ }
+
+ // Works with two arguments.
+ assertEq(new constructor([1, 2, 3, 4, 5]).lastIndexOf(1, 1), 0);
+ assertEq(new constructor([1, 2, 3, 4, 5]).lastIndexOf(1, -100), -1);
+ assertEq(new constructor([1, 2, 3, 4, 5]).lastIndexOf(3, 100), 2);
+ assertEq(new constructor([1, 2, 3, 4, 5]).lastIndexOf(5, -1), 4);
+ assertEq(new constructor([1, 2, 1, 2, 1]).lastIndexOf(1, 2), 2);
+ assertEq(new constructor([1, 2, 1, 2, 1]).lastIndexOf(1, -2), 2);
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.lastIndexOf.call(invalidReceiver);
+ }, TypeError, "Assert that lastIndexOf fails if this value is not a TypedArray");
+ });
+
+ // Test that the length getter is never called.
+ assertEq(Object.defineProperty(new constructor([0, 1, 2, 3, 5]), "length", {
+ get() {
+ throw new Error("length accessor called");
+ }
+ }).lastIndexOf(1), 1);
+
+ // Starts search at last index when fromIndex parameter is absent.
+ assertEq(new constructor([10, 20, 10]).lastIndexOf(10), 2);
+
+ // Starts search at first index when fromIndex parameter is undefined.
+ assertEq(new constructor([10, 20, 10]).lastIndexOf(10, undefined), 0);
+}
+
+for (let constructor of anyTypedArrayConstructors.filter(isFloatConstructor)) {
+ if (constructor.BYTES_PER_ELEMENT === 4) {
+ assertEq(new constructor([.1, .2, .3]).lastIndexOf(.2), -1);
+ assertEq(new constructor([.1, .2, .3]).lastIndexOf(Math.fround(.2)), 1);
+ } else {
+ assertEq(constructor.BYTES_PER_ELEMENT, 8);
+ assertEq(new constructor([.1, .2, .3]).lastIndexOf(.2), 1);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/indexOf-never-returns-negative-zero.js b/js/src/tests/non262/TypedArray/indexOf-never-returns-negative-zero.js
new file mode 100644
index 0000000000..72f8342156
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/indexOf-never-returns-negative-zero.js
@@ -0,0 +1,7 @@
+var ta = new Uint8Array(1);
+ta[0] = 17;
+
+assertEq(ta.indexOf(17, -0), +0);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/iterator-next-with-detached.js b/js/src/tests/non262/TypedArray/iterator-next-with-detached.js
new file mode 100644
index 0000000000..d6a31160a6
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/iterator-next-with-detached.js
@@ -0,0 +1,73 @@
+function checkResult(actual, expected)
+{
+ assertEq(actual.value, expected.value);
+ assertEq(actual.done, expected.done);
+}
+
+if (typeof detachArrayBuffer === "function" && typeof newGlobal === "function")
+{
+ var iteratorFunction = Uint8Array.prototype[Symbol.iterator];
+
+
+ var thisGlobal = this;
+ var otherGlobal = newGlobal();
+
+ var thisNext = new Uint8Array()[Symbol.iterator]().next
+
+ for (const constructor of typedArrayConstructors)
+ {
+ assertEq(new constructor()[Symbol.iterator]().next, thisNext);
+
+ var globals =
+ [
+ [thisGlobal, thisGlobal],
+ [thisGlobal, otherGlobal],
+ [otherGlobal, otherGlobal],
+ [otherGlobal, thisGlobal],
+ ];
+
+ for (const [arrayGlobal, bufferGlobal] of globals)
+ {
+ var arr, buffer, iterator;
+
+ function arrayBufferIterator()
+ {
+ var byteLength = 2 * constructor.BYTES_PER_ELEMENT;
+ var buf = new bufferGlobal.ArrayBuffer(byteLength);
+ var tarray = new arrayGlobal[constructor.name](buf);
+
+ tarray[0] = 1;
+ tarray[1] = 2;
+
+ return [tarray, buf, Reflect.apply(iteratorFunction, tarray, [])];
+ }
+
+ [arr, buffer, iterator] = arrayBufferIterator();
+ checkResult(thisNext.call(iterator), {value: 1, done: false});
+ checkResult(thisNext.call(iterator), {value: 2, done: false});
+ checkResult(thisNext.call(iterator), {value: undefined, done: true});
+
+ // Test an exhausted iterator.
+ bufferGlobal.detachArrayBuffer(buffer);
+ checkResult(thisNext.call(iterator), {value: undefined, done: true});
+
+ // Test an all-but-exhausted iterator.
+ [arr, buffer, iterator] = arrayBufferIterator();
+ checkResult(thisNext.call(iterator), {value: 1, done: false});
+ checkResult(thisNext.call(iterator), {value: 2, done: false});
+
+ bufferGlobal.detachArrayBuffer(buffer);
+ assertThrowsInstanceOf(() => thisNext.call(iterator), TypeError);
+
+ // Test an unexhausted iterator.
+ [arr, buffer, iterator] = arrayBufferIterator();
+ checkResult(thisNext.call(iterator), {value: 1, done: false});
+
+ bufferGlobal.detachArrayBuffer(buffer);
+ assertThrowsInstanceOf(() => thisNext.call(iterator), TypeError);
+ }
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/iterator.js b/js/src/tests/non262/TypedArray/iterator.js
new file mode 100644
index 0000000000..3f943aa70d
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/iterator.js
@@ -0,0 +1,42 @@
+// Ensure that we're using [[ArrayLength]] to determine the number of
+// values to produce instead of the length property.
+
+function testIterationCount(iterator, expectedLength) {
+ for (let i = 0; i < expectedLength; i++)
+ assertEq(iterator.next().done, false);
+ assertEq(iterator.next().done, true);
+}
+
+let i8Array = new Int8Array(4);
+Object.defineProperty(i8Array, "length", {value: 0});
+let i8Iterator = i8Array[Symbol.iterator]();
+testIterationCount(i8Iterator, 4);
+
+// Veryify that the length property isn't even touched
+i8Array = new Int8Array();
+Object.defineProperty(i8Array, "length", {
+ get() {
+ throw TypeError;
+ }
+});
+i8Iterator = i8Array[Symbol.iterator]();
+testIterationCount(i8Iterator, 0);
+
+// Verify that it works for set as well
+i8Array = new Uint8Array(1);
+// Try setting a high length which would trigger failure
+Object.defineProperty(i8Array, "length", {value: 15});
+// Works if the fake length is ignored
+(new Uint8Array(4)).set(i8Array, 3);
+
+// Ensure that it works across globals
+let g2 = newGlobal();
+
+i8Array = new Int8Array(8);
+Object.defineProperty(i8Array, "length", {value: 0});
+let iterator = i8Array[Symbol.iterator]();
+iterator.next = g2.Array.prototype[Symbol.iterator]().next;
+testIterationCount(iterator, 8);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/join.js b/js/src/tests/non262/TypedArray/join.js
new file mode 100644
index 0000000000..0e797320fd
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/join.js
@@ -0,0 +1,48 @@
+for (var constructor of anyTypedArrayConstructors) {
+ assertEq(constructor.prototype.join.length, 1);
+
+ assertEq(new constructor([1, 2, 3]).join(), "1,2,3");
+ assertEq(new constructor([1, 2, 3]).join(undefined), "1,2,3");
+ assertEq(new constructor([1, 2, 3]).join(null), "1null2null3");
+ assertEq(new constructor([1, 2, 3]).join(""), "123");
+ assertEq(new constructor([1, 2, 3]).join("+"), "1+2+3");
+ assertEq(new constructor([1, 2, 3]).join(.1), "10.120.13");
+ assertEq(new constructor([1, 2, 3]).join({toString(){return "foo"}}), "1foo2foo3");
+ assertEq(new constructor([1]).join("-"), "1");
+ assertEq(new constructor().join(), "");
+ assertEq(new constructor().join("*"), "");
+ assertEq(new constructor(1).join(), "0");
+ assertEq(new constructor(3).join(), "0,0,0");
+
+ assertThrowsInstanceOf(() => new constructor().join({toString(){throw new TypeError}}), TypeError);
+ assertThrowsInstanceOf(() => new constructor().join(Symbol()), TypeError);
+
+ // Called from other globals.
+ if (typeof newGlobal === "function") {
+ var join = newGlobal()[constructor.name].prototype.join;
+ assertEq(join.call(new constructor([1, 2, 3]), "\t"), "1\t2\t3");
+ }
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.join.call(invalidReceiver);
+ }, TypeError, "Assert that join fails if this value is not a TypedArray");
+ });
+
+ // Test that the length getter is never called.
+ assertEq(Object.defineProperty(new constructor([1, 2, 3]), "length", {
+ get() {
+ throw new Error("length accessor called");
+ }
+ }).join("\0"), "1\0002\0003");
+}
+
+for (let constructor of anyTypedArrayConstructors.filter(isFloatConstructor)) {
+ assertDeepEq(new constructor([null, , NaN]).join(), "0,NaN,NaN");
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/keys.js b/js/src/tests/non262/TypedArray/keys.js
new file mode 100644
index 0000000000..88477cd758
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/keys.js
@@ -0,0 +1,36 @@
+for (var constructor of anyTypedArrayConstructors) {
+ assertEq(constructor.prototype.keys.length, 0);
+ assertEq(constructor.prototype.keys.name, "keys");
+
+ assertDeepEq([...new constructor(0).keys()], []);
+ assertDeepEq([...new constructor(1).keys()], [0]);
+ assertDeepEq([...new constructor(2).keys()], [0, 1]);
+ assertDeepEq([...new constructor([15]).keys()], [0]);
+
+ var arr = new constructor([1, 2, 3]);
+ var iterator = arr.keys();
+ assertDeepEq(iterator.next(), {value: 0, done: false});
+ assertDeepEq(iterator.next(), {value: 1, done: false});
+ assertDeepEq(iterator.next(), {value: 2, done: false});
+ assertDeepEq(iterator.next(), {value: undefined, done: true});
+
+ // Called from other globals.
+ if (typeof newGlobal === "function") {
+ var keys = newGlobal()[constructor.name].prototype.keys;
+ assertDeepEq([...keys.call(new constructor(2))], [0, 1]);
+ arr = new (newGlobal()[constructor.name])(2);
+ assertEq([...constructor.prototype.keys.call(arr)].toString(), "0,1");
+ }
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.keys.call(invalidReceiver);
+ }, TypeError, "Assert that keys fails if this value is not a TypedArray");
+ });
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/large-arrays.js b/js/src/tests/non262/TypedArray/large-arrays.js
new file mode 100644
index 0000000000..feb0e05ac6
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/large-arrays.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!xulRuntime.shell)
+
+// Test that we can access TypedArrays beyond the 4GB mark, if large buffers are
+// supported.
+
+const gb = 1024 * 1024 * 1024;
+
+if (largeArrayBufferSupported()) {
+ for (let TA of typedArrayConstructors) {
+ let ta = new TA(6*gb / TA.BYTES_PER_ELEMENT);
+
+ // Set element at the 5GB mark
+ ta[5*gb / TA.BYTES_PER_ELEMENT] = 37;
+
+ // Check that it was set
+ assertEq(ta[5*gb / TA.BYTES_PER_ELEMENT], 37);
+
+ // Check that we're not operating mod 4GB
+ assertEq(ta[1*gb / TA.BYTES_PER_ELEMENT], 0);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/lastIndexOf-never-returns-negative-zero.js b/js/src/tests/non262/TypedArray/lastIndexOf-never-returns-negative-zero.js
new file mode 100644
index 0000000000..bffc05af73
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/lastIndexOf-never-returns-negative-zero.js
@@ -0,0 +1,7 @@
+var ta = new Uint8Array(1);
+ta[0] = 17;
+
+assertEq(ta.lastIndexOf(17, -0), +0);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/length.js b/js/src/tests/non262/TypedArray/length.js
new file mode 100644
index 0000000000..7ed79b4954
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/length.js
@@ -0,0 +1,14 @@
+/* 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/. */
+
+const TypedArray = Object.getPrototypeOf(Int32Array);
+
+assertEq(TypedArray.length, 0);
+
+assertDeepEq(Object.getOwnPropertyDescriptor(TypedArray, "length"), {
+ value: 0, writable: false, enumerable: false, configurable: true,
+});
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/TypedArray/map-and-filter.js b/js/src/tests/non262/TypedArray/map-and-filter.js
new file mode 100644
index 0000000000..0d86fc02b2
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/map-and-filter.js
@@ -0,0 +1,274 @@
+// Tests for TypedArray#map.
+for (var constructor of anyTypedArrayConstructors) {
+ assertEq(constructor.prototype.map.length, 1);
+
+ // Basic tests.
+ assertDeepEq(new constructor([1, 3, 5]).map(v => v * 2), new constructor([2,6,10]));
+ assertDeepEq(new constructor([-1, 13, 5]).map(v => v - 2), new constructor([-3, 11, 3]));
+ assertDeepEq(new constructor(10).map(v => v), new constructor(10));
+ assertDeepEq(new constructor().map(v => v + 1), new constructor);
+ assertDeepEq(new constructor([1,2,3]).map(v => v), new constructor([1,2,3]));
+
+ var arr = new constructor([1, 2, 3, 4, 5]);
+ var sum = 0;
+ var count = 0;
+ assertDeepEq(arr.map((v, k, o) => {
+ count++;
+ sum += v;
+ assertEq(k, v - 1);
+ assertEq(o, arr);
+ return v;
+ }), arr);
+ assertEq(sum, 15);
+ assertEq(count, 5);
+
+ // Test that changing elements that have been visited does not affect the result.
+ var changeArr = new constructor([1,2,3,4,5]);
+ assertDeepEq(arr.map((v,k) => {
+ changeArr[k] = v + 1;
+ return v;
+ }), new constructor([1,2,3,4,5]));
+
+ // Tests for `thisArg` argument.
+ function assertThisArg(thisArg, thisValue) {
+ // In sloppy mode, `this` could be global object or a wrapper of `thisArg`.
+ assertDeepEq(arr.map(function(v) {
+ assertDeepEq(this, thisValue);
+ return v;
+ }, thisArg), arr);
+
+ // In strict mode, `this` strictly equals `thisArg`.
+ assertDeepEq(arr.map(function(v) {
+ "use strict";
+ assertDeepEq(this, thisArg);
+ return v;
+ }, thisArg), arr);
+
+ // Passing `thisArg` has no effect if callback is an arrow function.
+ var self = this;
+ assertDeepEq(arr.map((v) => {
+ assertEq(this, self);
+ return v;
+ }, thisArg), arr);
+ }
+ assertThisArg([1, 2, 3], [1, 2, 3]);
+ assertThisArg(Object, Object);
+ assertThisArg(1, Object(1));
+ assertThisArg("1", Object("1"));
+ assertThisArg(false, Object(false));
+ assertThisArg(undefined, this);
+ assertThisArg(null, this);
+
+ // Throw an exception in the callback.
+ var sum = 0;
+ var count = 0;
+ var thrown = false;
+ try {
+ arr.map((v, k, o) => {
+ count++;
+ sum += v;
+ assertEq(k, v - 1);
+ assertEq(o, arr);
+ if (v === 3) {
+ throw "map";
+ }
+ return v;
+ })
+ } catch(e) {
+ assertEq(e, "map");
+ thrown = true;
+ }
+ assertEq(thrown, true);
+ assertEq(sum, 6);
+ assertEq(count, 3);
+
+ // There is no callback or callback is not a function.
+ assertThrowsInstanceOf(() => {
+ arr.map();
+ }, TypeError);
+ var invalidCallbacks = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
+ invalidCallbacks.forEach(callback => {
+ assertThrowsInstanceOf(() => {
+ arr.map(callback);
+ }, TypeError);
+ })
+
+ // Callback is a generator.
+ arr.map(function*(){
+ throw "This line will not be executed";
+ });
+
+ // Called from other globals.
+ if (typeof newGlobal === "function") {
+ var map = newGlobal()[constructor.name].prototype.map;
+ var sum = 0;
+ assertDeepEq(map.call(new constructor([1, 2, 3]), v => sum += v), new constructor([1,3,6]));
+ assertEq(sum, 6);
+ }
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.filter.call(invalidReceiver, () => true);
+ }, TypeError, "Assert that map fails if this value is not a TypedArray");
+ });
+
+ // Test that the length getter is never called.
+ assertDeepEq(Object.defineProperty(new constructor([1, 2, 3]), "length", {
+ get() {
+ throw new Error("length accessor called");
+ }
+ }).map((b) => b), new constructor([1,2,3]));
+}
+
+// Test For TypedArray#filter.
+for (var constructor of anyTypedArrayConstructors) {
+ assertEq(constructor.prototype.filter.length, 1)
+
+ // Basic tests.
+ assertDeepEq(new constructor([1,2,3]).filter(x => x == x), new constructor([1,2,3]));
+ assertDeepEq(new constructor([1,2,3,4]).filter(x => x % 2 == 0), new constructor([2,4]));
+ assertDeepEq(new constructor([1,2,3,4,5]).filter(x => x < 4), new constructor([1,2,3]));
+ assertDeepEq(new constructor().filter(x => x * 2 == 4), new constructor());
+
+ var arr = new constructor([1,2,3,4,5]);
+ var sum = 0;
+ var count = 0;
+ assertDeepEq(arr.filter((v, k, o) => {
+ count++;
+ sum += v;
+ assertEq(k, v - 1);
+ assertEq(o, arr);
+ return (v < 4);
+ }), new constructor([1,2,3]));
+ assertEq(sum, 15);
+ assertEq(count, 5);
+
+ // Test that changing elements that have been visited does not affect the result.
+ var changeArr = new constructor([1,2,3,4,5]);
+ assertDeepEq(arr.filter((v,k) => {
+ changeArr[k] = v + 1;
+ return true;
+ }), new constructor([1,2,3,4,5]));
+
+ // Tests for `thisArg` argument.
+ function assertThisArg(thisArg, thisValue) {
+ // In sloppy mode, `this` could be global object or a wrapper of `thisArg`.
+ assertDeepEq(arr.filter(function(v) {
+ assertDeepEq(this, thisValue);
+ return v;
+ }, thisArg), arr);
+
+ // In strict mode, `this` strictly equals `thisArg`.
+ assertDeepEq(arr.filter(function(v) {
+ "use strict";
+ assertDeepEq(this, thisArg);
+ return v;
+ }, thisArg), arr);
+
+ // Passing `thisArg` has no effect if callback is an arrow function.
+ var self = this;
+ assertDeepEq(arr.filter((v) => {
+ assertEq(this, self);
+ return v;
+ }, thisArg), arr);
+ }
+ assertThisArg([1, 2, 3], [1, 2, 3]);
+ assertThisArg(Object, Object);
+ assertThisArg(1, Object(1));
+ assertThisArg("1", Object("1"));
+ assertThisArg(false, Object(false));
+ assertThisArg(undefined, this);
+ assertThisArg(null, this);
+
+ // Throw an exception in the callback.
+ var sum = 0;
+ var count = 0;
+ var thrown = false;
+ try {
+ arr.filter((v, k, o) => {
+ count++;
+ sum += v;
+ assertEq(k, v - 1);
+ assertEq(o, arr);
+ if (v === 3) {
+ throw "filter";
+ }
+ return v;
+ })
+ } catch(e) {
+ assertEq(e, "filter");
+ thrown = true;
+ }
+ assertEq(thrown, true);
+ assertEq(sum, 6);
+ assertEq(count, 3);
+
+ // There is no callback or callback is not a function.
+ assertThrowsInstanceOf(() => {
+ arr.filter();
+ }, TypeError);
+ var invalidCallbacks = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
+ invalidCallbacks.forEach(callback => {
+ assertThrowsInstanceOf(() => {
+ arr.filter(callback);
+ }, TypeError);
+ })
+
+ // Callback is a generator.
+ arr.filter(function*(){
+ throw "This line will not be executed";
+ });
+
+ // Called from other globals.
+ if (typeof newGlobal === "function") {
+ var filter = newGlobal()[constructor.name].prototype.filter;
+ var sum = 0;
+ assertDeepEq(filter.call(new constructor([1, 2, 3]), v => {sum += v; return true}),
+ new constructor([1,2,3]));
+ assertEq(sum, 6);
+ }
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.filter.call(invalidReceiver, () => true);
+ }, TypeError, "Assert that filter fails if this value is not a TypedArray");
+ });
+
+ // Test that the length getter is never called.
+ assertDeepEq(Object.defineProperty(new constructor([1, 2, 3]), "length", {
+ get() {
+ throw new Error("length accessor called");
+ }
+ }).filter((b) => true), new constructor([1,2,3]));
+}
+
+// Test that changing Array.prototype[Symbol.iterator] does not affect the
+// behaviour of filter. See https://bugzilla.mozilla.org/show_bug.cgi?id=1121936#c18
+// for more details.
+
+var arr = new Uint16Array([1,2,3]);
+
+// save
+var old = Array.prototype[Symbol.iterator];
+
+Array.prototype[Symbol.iterator] = () => { throw new Error("unreachable"); };
+assertDeepEq(arr.filter(v => true), arr);
+
+// restore
+Array.prototype[Symbol.iterator] = old;
+
+// Test that defining accessors on Array.prototype doesn't affect the behaviour
+// of filter. See https://bugzilla.mozilla.org/show_bug.cgi?id=1121936#c18
+// for more details.
+Object.defineProperty(Array.prototype, 0, {configurable: true, get: function() { return 1; }, set: function() { this.b = 1; }});
+assertDeepEq(new Uint16Array([1,2,3]).filter(v => true), new Uint16Array([1,2,3]));
+delete Array.prototype[0];
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/map-species.js b/js/src/tests/non262/TypedArray/map-species.js
new file mode 100644
index 0000000000..8353d914bd
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/map-species.js
@@ -0,0 +1,56 @@
+function test(constructor, constructor2, from=[1, 2, 3, 4, 5], to=[2, 4, 6, 8, 10]) {
+ var modifiedConstructor = new constructor(from);
+ modifiedConstructor.constructor = constructor2;
+ assertDeepEq(modifiedConstructor.map(x => x * 2), new constructor2(to));
+ var modifiedSpecies = new constructor(from);
+ modifiedSpecies.constructor = { [Symbol.species]: constructor2 };
+ assertDeepEq(modifiedSpecies.map(x => x * 2), new constructor2(to));
+}
+
+// same size, same sign
+
+test(Int8Array, Uint8Array);
+test(Int8Array, Uint8ClampedArray);
+
+test(Uint8Array, Int8Array);
+test(Uint8Array, Uint8ClampedArray);
+
+test(Uint8ClampedArray, Int8Array);
+test(Uint8ClampedArray, Uint8Array);
+
+test(Int16Array, Uint16Array);
+test(Uint16Array, Int16Array);
+
+test(Int32Array, Uint32Array);
+test(Uint32Array, Int32Array);
+
+// same size, different sign
+
+test(Int8Array, Uint8Array, [-1, -2, -3, -4, -5], [0xFE, 0xFC, 0xFA, 0xF8, 0xF6]);
+test(Int8Array, Uint8ClampedArray, [-1, -2, -3, -4, -5], [0, 0, 0, 0, 0]);
+
+test(Uint8Array, Int8Array, [0xFF, 0xFE, 0xFD, 0xFC, 0xFB], [-2, -4, -6, -8, -10]);
+test(Uint8ClampedArray, Int8Array, [0xFF, 0xFE, 0xFD, 0xFC, 0xFB], [-2, -4, -6, -8, -10]);
+
+test(Int16Array, Uint16Array, [-1, -2, -3, -4, -5], [0xFFFE, 0xFFFC, 0xFFFA, 0xFFF8, 0xFFF6]);
+test(Uint16Array, Int16Array, [0xFFFF, 0xFFFE, 0xFFFD, 0xFFFC, 0xFFFB], [-2, -4, -6, -8, -10]);
+
+test(Int32Array, Uint32Array, [-1, -2, -3, -4, -5], [0xFFFFFFFE, 0xFFFFFFFC, 0xFFFFFFFA, 0xFFFFFFF8, 0xFFFFFFF6]);
+test(Uint32Array, Int32Array, [0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFC, 0xFFFFFFFB], [-2, -4, -6, -8, -10]);
+
+// different size
+
+test(Uint8Array, Uint16Array);
+test(Uint16Array, Uint8Array);
+
+test(Uint8Array, Uint32Array);
+test(Uint32Array, Uint8Array);
+
+test(Uint16Array, Uint32Array);
+test(Uint32Array, Uint16Array);
+
+test(Float32Array, Float64Array);
+test(Float64Array, Float32Array);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/map-validation.js b/js/src/tests/non262/TypedArray/map-validation.js
new file mode 100644
index 0000000000..1694ef50cb
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/map-validation.js
@@ -0,0 +1,149 @@
+/* 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/. */
+
+// Summary: Ensure typed array validation is called for TypedArray.prototype.map.
+
+const otherGlobal = typeof newGlobal === "function" ? newGlobal() : undefined;
+const typedArrayLengths = [0, 1, 1024];
+
+function createTestCases(TAConstructor, constructor, constructorCrossRealm) {
+ let testCases = [];
+ testCases.push({
+ species: constructor,
+ method: TAConstructor.prototype.map,
+ error: TypeError,
+ });
+ if (otherGlobal) {
+ testCases.push({
+ species: constructorCrossRealm,
+ method: TAConstructor.prototype.map,
+ error: TypeError,
+ });
+ testCases.push({
+ species: constructor,
+ method: otherGlobal[TAConstructor.name].prototype.map,
+ error: otherGlobal.TypeError,
+ });
+ }
+ return testCases;
+}
+
+// Throws TypeError when the returned value is not a typed array.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function NoTypedArrayConstructor(...args) {
+ let a = [];
+ callCount += 1;
+ return a;
+ }
+ function NoTypedArrayConstructorCrossRealm(...args) {
+ let a = new otherGlobal.Array();
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, NoTypedArrayConstructor, NoTypedArrayConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ assertThrowsInstanceOf(() => method.call(ta, () => 123), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// Throws TypeError exception when returned array is too small.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function TooSmallConstructor(length) {
+ let a = new TAConstructor(Math.max(length - 1, 0));
+ callCount += 1;
+ return a;
+ }
+ function TooSmallConstructorCrossRealm(length) {
+ let a = new otherGlobal[TAConstructor.name](Math.max(length - 1, 0));
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, TooSmallConstructor, TooSmallConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+
+ // Passes when the length is zero.
+ if (length === 0) {
+ let result = method.call(ta, () => 123);
+ assertEq(result.length, 0);
+ } else {
+ assertThrowsInstanceOf(() => method.call(ta, () => 123), error);
+ }
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// No exception when array is larger than requested.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ const extraLength = 1;
+
+ let callCount = 0, expectedCallCount = 0;
+ function TooLargeConstructor(length) {
+ let a = new TAConstructor(length + extraLength);
+ callCount += 1;
+ return a;
+ }
+ function TooLargeConstructorCrossRealm(length) {
+ let a = new otherGlobal[TAConstructor.name](length + extraLength);
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, TooLargeConstructor, TooLargeConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ let result = method.call(ta, () => 123);
+ assertEq(result.length, length + extraLength);
+ assertEq(result[0], (length === 0 ? 0 : 123));
+ assertEq(result[length + extraLength - 1], 0);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// Throws TypeError exception when returned array is detached.
+if (typeof detachArrayBuffer === "function") {
+ for (const TAConstructor of typedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function DetachConstructor(...args) {
+ let a = new TAConstructor(...args);
+ detachArrayBuffer(a.buffer);
+ callCount += 1;
+ return a;
+ }
+ function DetachConstructorCrossRealm(...args) {
+ let a = new otherGlobal[TAConstructor.name](...args);
+ otherGlobal.detachArrayBuffer(a.buffer);
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, DetachConstructor, DetachConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ assertThrowsInstanceOf(() => method.call(ta, () => 123), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/TypedArray/object-defineproperty.js b/js/src/tests/non262/TypedArray/object-defineproperty.js
new file mode 100644
index 0000000000..b19f76b845
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/object-defineproperty.js
@@ -0,0 +1,68 @@
+var obj = new Int32Array(2);
+obj[0] = 100;
+
+var throws = [
+ // Disallow accessors
+ {get: undefined},
+ {set: undefined},
+ {get: undefined, set: undefined},
+ {get: function() {}},
+ {set: function() {}},
+ {get: function() {}, set: function() {}},
+
+ {configurable: false},
+ {enumerable: false},
+ {writable: false},
+
+ {configurable: false, writable: true},
+ {enumerable: false, configurable: false},
+
+ {configurable: false, value: 15}
+];
+
+for (var desc of throws) {
+ assertThrowsInstanceOf(function() { Object.defineProperty(obj, 0, desc); }, TypeError);
+ assertThrowsInstanceOf(function() { Object.defineProperties(obj, {0: desc}); }, TypeError);
+}
+
+Object.defineProperty(obj, 0, {});
+Object.defineProperty(obj, 0, {configurable: true});
+Object.defineProperty(obj, 0, {enumerable: true});
+Object.defineProperty(obj, 0, {writable: true});
+
+assertEq(obj[0], 100);
+
+Object.defineProperty(obj, 0, {configurable: true, value: 15});
+assertEq(obj[0], 15);
+Object.defineProperty(obj, 0, {enumerable: true, value: 16});
+assertEq(obj[0], 16);
+Object.defineProperty(obj, 0, {writable: true, value: 17});
+assertEq(obj[0], 17);
+Object.defineProperty(obj, 0, {value: 18});
+assertEq(obj[0], 18);
+
+var desc = Object.getOwnPropertyDescriptor(obj, 0);
+assertEq(desc.configurable, true);
+assertEq(desc.enumerable, true);
+assertEq(desc.writable, true);
+assertEq(desc.value, 18);
+assertEq('get' in desc, false);
+assertEq('set' in desc, false);
+
+Object.defineProperties(obj, {0: {value: 20}, 1: {value: 42}});
+assertEq(obj[0], 20);
+assertEq(obj[1], 42);
+
+anyTypedArrayConstructors.forEach(constructor => {
+ var obj = new constructor(4);
+ obj[0] = 100;
+ obj[1] = 200;
+
+ for (var v of [20, 300, -10, Math.pow(2, 32), -Math.pow(2, 32), NaN]) {
+ Object.defineProperty(obj, 0, {value: v});
+ obj[1] = v;
+ assertEq(obj[0], obj[1]);
+ }
+});
+
+reportCompare(true, true, "test");
diff --git a/js/src/tests/non262/TypedArray/of-validation.js b/js/src/tests/non262/TypedArray/of-validation.js
new file mode 100644
index 0000000000..e7ab905195
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/of-validation.js
@@ -0,0 +1,140 @@
+/* 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/. */
+
+// Summary: Ensure typed array validation is called for TypedArray.of.
+
+const otherGlobal = typeof newGlobal === "function" ? newGlobal() : undefined;
+const typedArrayArgs = [[], [123], [123, ...Array(1023).fill(0)]];
+
+function createTestCases(TAConstructor, constructor, constructorCrossRealm) {
+ let testCases = [];
+ testCases.push({
+ species: constructor,
+ method: TAConstructor.of,
+ error: TypeError,
+ });
+ if (otherGlobal) {
+ testCases.push({
+ species: constructorCrossRealm,
+ method: TAConstructor.of,
+ error: TypeError,
+ });
+ testCases.push({
+ species: constructor,
+ method: otherGlobal[TAConstructor.name].of,
+ error: otherGlobal.TypeError,
+ });
+ }
+ return testCases;
+}
+
+// Throws TypeError when the returned value is not a typed array.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function NoTypedArrayConstructor(...args) {
+ let a = [];
+ callCount += 1;
+ return a;
+ }
+ function NoTypedArrayConstructorCrossRealm(...args) {
+ let a = new otherGlobal.Array();
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, NoTypedArrayConstructor, NoTypedArrayConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let args of typedArrayArgs) {
+ assertThrowsInstanceOf(() => method.call(species, ...args), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// Throws TypeError exception when returned array is too small.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function TooSmallConstructor(length) {
+ let a = new TAConstructor(Math.max(length - 1, 0));
+ callCount += 1;
+ return a;
+ }
+ function TooSmallConstructorCrossRealm(length) {
+ let a = new otherGlobal[TAConstructor.name](Math.max(length - 1, 0));
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, TooSmallConstructor, TooSmallConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let args of typedArrayArgs) {
+ // Passes when the length is zero.
+ if (args.length === 0) {
+ let result = method.call(species, ...args);
+ assertEq(result.length, 0);
+ } else {
+ assertThrowsInstanceOf(() => method.call(species, ...args), error);
+ }
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// No exception when array is larger than requested.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ const extraLength = 1;
+
+ let callCount = 0, expectedCallCount = 0;
+ function TooLargeConstructor(length) {
+ let a = new TAConstructor(length + extraLength);
+ callCount += 1;
+ return a;
+ }
+ function TooLargeConstructorCrossRealm(length) {
+ let a = new otherGlobal[TAConstructor.name](length + extraLength);
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, TooLargeConstructor, TooLargeConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let args of typedArrayArgs) {
+ let result = method.call(species, ...args);
+ assertEq(result.length, args.length + extraLength);
+ assertEq(result[0], (args.length === 0 ? 0 : 123));
+ assertEq(result[args.length + extraLength - 1], 0);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// Throws TypeError exception when returned array is detached.
+if (typeof detachArrayBuffer === "function") {
+ for (const TAConstructor of typedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function DetachConstructor(...args) {
+ let a = new TAConstructor(...args);
+ detachArrayBuffer(a.buffer);
+ callCount += 1;
+ return a;
+ }
+ function DetachConstructorCrossRealm(...args) {
+ let a = new otherGlobal[TAConstructor.name](...args);
+ otherGlobal.detachArrayBuffer(a.buffer);
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, DetachConstructor, DetachConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let args of typedArrayArgs) {
+ assertThrowsInstanceOf(() => method.call(species, ...args), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/TypedArray/of.js b/js/src/tests/non262/TypedArray/of.js
new file mode 100644
index 0000000000..af9c112023
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/of.js
@@ -0,0 +1,92 @@
+for (var constructor of anyTypedArrayConstructors) {
+ assertEq(constructor.of.length, 0);
+
+ assertDeepEq(Object.getOwnPropertyDescriptor(constructor.__proto__, "of"), {
+ value: constructor.of,
+ writable: true,
+ enumerable: false,
+ configurable: true
+ });
+
+ // Basic tests.
+ assertEq(constructor.of().constructor, constructor);
+ assertEq(constructor.of() instanceof constructor, true);
+ assertDeepEq(constructor.of(10), new constructor([10]));
+ assertDeepEq(constructor.of(1, 2, 3), new constructor([1, 2, 3]));
+ assertDeepEq(constructor.of("1", "2", "3"), new constructor([1, 2, 3]));
+
+ // This method can't be transplanted to other constructors.
+ assertThrowsInstanceOf(() => constructor.of.call(Array), TypeError);
+ assertThrowsInstanceOf(() => constructor.of.call(Array, 1, 2, 3), TypeError);
+
+ var hits = 0;
+ assertDeepEq(constructor.of.call(function(len) {
+ assertEq(arguments.length, 1);
+ assertEq(len, 3);
+ hits++;
+ return new constructor(len);
+ }, 10, 20, 30), new constructor([10, 20, 30]));
+ assertEq(hits, 1);
+
+ // Behavior across compartments.
+ if (typeof newGlobal === "function") {
+ var newC = newGlobal()[constructor.name];
+ assertEq(newC.of() instanceof newC, true);
+ assertEq(newC.of() instanceof constructor, false);
+ assertEq(newC.of.call(constructor) instanceof constructor, true);
+ }
+
+ // Throws if `this` isn't a constructor.
+ var invalidConstructors = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ constructor.of, () => {}];
+ invalidConstructors.forEach(C => {
+ assertThrowsInstanceOf(() => {
+ constructor.of.call(C);
+ }, TypeError);
+ });
+
+ // Throw if `this` is a method definition or a getter/setter function.
+ assertThrowsInstanceOf(() => {
+ constructor.of.call({method() {}}.method);
+ }, TypeError);
+ assertThrowsInstanceOf(() => {
+ constructor.of.call(Object.getOwnPropertyDescriptor({get getter() {}}, "getter").get);
+ }, TypeError);
+
+ // Generators are not legal constructors.
+ assertThrowsInstanceOf(() => {
+ constructor.of.call(function*(len) {
+ return len;
+ }, "a")
+ }, TypeError);
+
+ // An exception might be thrown in a strict assignment to the new object's indexed properties.
+ assertThrowsInstanceOf(() => {
+ constructor.of.call(function() {
+ return {get 0() {}};
+ }, "a");
+ }, TypeError);
+
+ assertThrowsInstanceOf(() => {
+ constructor.of.call(function() {
+ return Object("1");
+ }, "a");
+ }, TypeError);
+
+ assertThrowsInstanceOf(() => {
+ constructor.of.call(function() {
+ return Object.create({
+ set 0(v) {
+ throw new TypeError;
+ }
+ });
+ }, "a");
+ }, TypeError);
+}
+
+for (let constructor of anyTypedArrayConstructors.filter(isFloatConstructor)) {
+ assertDeepEq(constructor.of(0.1, null, undefined, NaN), new constructor([0.1, 0, NaN, NaN]));
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/prototype-constructor-identity.js b/js/src/tests/non262/TypedArray/prototype-constructor-identity.js
new file mode 100644
index 0000000000..10324f5720
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/prototype-constructor-identity.js
@@ -0,0 +1,55 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var gTestfile = 'prototype-constructor-identity.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 896116;
+var summary =
+ "Typed array prototypes/constructors should be largely empty, inheriting "
+ "most functionality from %TypedArray% and %TypedArray%.prototype";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var TypedArray = Object.getPrototypeOf(Int8Array);
+
+assertEq(TypedArray !== Function.prototype, true,
+ "%TypedArray% should be in constructors' [[Prototype]] chains");
+assertEq(Object.getPrototypeOf(TypedArray), Function.prototype,
+ "%TypedArray%.prototype should inherit from Function.prototype");
+
+assertEq(TypedArray.prototype.constructor, TypedArray,
+ "bad %TypedArray%.prototype.constructor");
+
+// Check a few different functions we implement are here, as a sanity check.
+var typedArrayProps = Object.getOwnPropertyNames(TypedArray.prototype);
+assertEq(typedArrayProps.indexOf("copyWithin") >= 0, true);
+assertEq(typedArrayProps.indexOf("subarray") >= 0, true);
+assertEq(typedArrayProps.indexOf("set") >= 0, true);
+
+anyTypedArrayConstructors.forEach(function(ctor) {
+ assertEq(Object.getPrototypeOf(ctor), TypedArray);
+
+ var proto = ctor.prototype;
+
+ // Inherited functions aren't present.
+ var props = Object.getOwnPropertyNames(proto).sort();
+ assertEq(props[0], "BYTES_PER_ELEMENT");
+ assertEq(props[1], "constructor");
+ assertEq(props.length, 2);
+
+ // The inheritance chain should be set up properly.
+ assertEq(Object.getPrototypeOf(proto), TypedArray.prototype,
+ "prototype should inherit from %TypedArray%.prototype");
+});
+
+/******************************************************************************/
+
+reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/TypedArray/reduce-and-reduceRight.js b/js/src/tests/non262/TypedArray/reduce-and-reduceRight.js
new file mode 100644
index 0000000000..21a7d99e90
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/reduce-and-reduceRight.js
@@ -0,0 +1,188 @@
+// Tests for TypedArray#reduce.
+for (var constructor of anyTypedArrayConstructors) {
+ assertEq(constructor.prototype.reduce.length, 1);
+
+ // Basic tests.
+ var arr = new constructor([1, 2, 3, 4, 5]);
+
+ assertEq(arr.reduce((previous, current) => previous + current), 15);
+ assertEq(arr.reduce((previous, current) => current - previous), 3);
+
+ var count = 0;
+ var sum = 0;
+ assertEq(arr.reduce((previous, current, index, array) => {
+ count++;
+ sum += current;
+ assertEq(current - 1, index);
+ assertEq(current, arr[index]);
+ assertEq(array, arr);
+ return previous * current;
+ }), 120);
+ assertEq(count, 4);
+ assertEq(sum, 14);
+
+ // Tests for `initialValue` argument.
+ assertEq(arr.reduce((previous, current) => previous + current, -15), 0);
+ assertEq(arr.reduce((previous, current) => previous + current, ""), "12345");
+ assertDeepEq(arr.reduce((previous, current) => previous.concat(current), []), [1, 2, 3, 4, 5]);
+
+ // Tests for `this` value.
+ var global = this;
+ arr.reduce(function(){
+ assertEq(this, global);
+ });
+ arr.reduce(function(){
+ "use strict";
+ assertEq(this, undefined);
+ });
+ arr.reduce(() => assertEq(this, global));
+
+ // Throw an exception in the callback.
+ var count = 0;
+ var sum = 0;
+ assertThrowsInstanceOf(() => {
+ arr.reduce((previous, current, index, array) => {
+ count++;
+ sum += current;
+ if (index === 3) {
+ throw TypeError("reduce");
+ }
+ })
+ }, TypeError);
+ assertEq(count, 3);
+ assertEq(sum, 9);
+
+ // There is no callback or callback is not a function.
+ assertThrowsInstanceOf(() => {
+ arr.reduce();
+ }, TypeError);
+ var invalidCallbacks = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
+ invalidCallbacks.forEach(callback => {
+ assertThrowsInstanceOf(() => {
+ arr.reduce(callback);
+ }, TypeError);
+ })
+
+ // Callback is a generator.
+ arr.reduce(function*(){
+ throw "This line will not be executed";
+ });
+
+ // Called from other globals.
+ if (typeof newGlobal === "function") {
+ var reduce = newGlobal()[constructor.name].prototype.reduce;
+ assertEq(reduce.call(arr, (previous, current) => Math.min(previous, current)), 1);
+ }
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(3), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.reduce.call(invalidReceiver, () => {});
+ }, TypeError, "Assert that reduce fails if this value is not a TypedArray");
+ });
+
+ // Test that the length getter is never called.
+ assertEq(Object.defineProperty(arr, "length", {
+ get() {
+ throw new Error("length accessor called");
+ }
+ }).reduce((previous, current) => Math.max(previous, current)), 5);
+}
+
+// Tests for TypedArray#reduceRight.
+for (var constructor of anyTypedArrayConstructors) {
+ assertEq(constructor.prototype.reduceRight.length, 1);
+
+ // Basic tests.
+ var arr = new constructor([1, 2, 3, 4, 5]);
+
+ assertEq(arr.reduceRight((previous, current) => previous + current), 15);
+ assertEq(arr.reduceRight((previous, current) => current - previous), 3);
+
+ var count = 0;
+ var sum = 0;
+ assertEq(arr.reduceRight((previous, current, index, array) => {
+ count++;
+ sum += current;
+ assertEq(current - 1, index);
+ assertEq(current, arr[index]);
+ assertEq(array, arr);
+ return previous * current;
+ }), 120);
+ assertEq(count, 4);
+ assertEq(sum, 10);
+
+ // Tests for `initialValue` argument.
+ assertEq(arr.reduceRight((previous, current) => previous + current, -15), 0);
+ assertEq(arr.reduceRight((previous, current) => previous + current, ""), "54321");
+ assertDeepEq(arr.reduceRight((previous, current) => previous.concat(current), []), [5, 4, 3, 2, 1]);
+
+ // Tests for `this` value.
+ var global = this;
+ arr.reduceRight(function(){
+ assertEq(this, global);
+ });
+ arr.reduceRight(function(){
+ "use strict";
+ assertEq(this, undefined);
+ });
+ arr.reduceRight(() => assertEq(this, global));
+
+ // Throw an exception in the callback.
+ var count = 0;
+ var sum = 0;
+ assertThrowsInstanceOf(() => {
+ arr.reduceRight((previous, current, index, array) => {
+ count++;
+ sum += current;
+ if (index === 1) {
+ throw TypeError("reduceRight");
+ }
+ })
+ }, TypeError);
+ assertEq(count, 3);
+ assertEq(sum, 9);
+
+ // There is no callback or callback is not a function.
+ assertThrowsInstanceOf(() => {
+ arr.reduceRight();
+ }, TypeError);
+ var invalidCallbacks = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
+ invalidCallbacks.forEach(callback => {
+ assertThrowsInstanceOf(() => {
+ arr.reduceRight(callback);
+ }, TypeError);
+ })
+
+ // Callback is a generator.
+ arr.reduceRight(function*(){
+ throw "This line will not be executed";
+ });
+
+ // Called from other globals.
+ if (typeof newGlobal === "function") {
+ var reduceRight = newGlobal()[constructor.name].prototype.reduceRight;
+ assertEq(reduceRight.call(arr, (previous, current) => Math.min(previous, current)), 1);
+ }
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(3), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.reduceRight.call(invalidReceiver, () => {});
+ }, TypeError, "Assert that reduceRight fails if this value is not a TypedArray");
+ });
+
+ // Test that the length getter is never called.
+ assertEq(Object.defineProperty(arr, "length", {
+ get() {
+ throw new Error("length accessor called");
+ }
+ }).reduceRight((previous, current) => Math.max(previous, current)), 5);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/reverse.js b/js/src/tests/non262/TypedArray/reverse.js
new file mode 100644
index 0000000000..f8146506c6
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/reverse.js
@@ -0,0 +1,38 @@
+for (var constructor of anyTypedArrayConstructors) {
+ assertDeepEq(constructor.prototype.reverse.length, 0);
+
+ assertDeepEq(new constructor().reverse(), new constructor());
+ assertDeepEq(new constructor(10).reverse(), new constructor(10));
+ assertDeepEq(new constructor([]).reverse(), new constructor([]));
+ assertDeepEq(new constructor([1]).reverse(), new constructor([1]));
+ assertDeepEq(new constructor([1, 2]).reverse(), new constructor([2, 1]));
+ assertDeepEq(new constructor([1, 2, 3]).reverse(), new constructor([3, 2, 1]));
+ assertDeepEq(new constructor([1, 2, 3, 4]).reverse(), new constructor([4, 3, 2, 1]));
+ assertDeepEq(new constructor([1, 2, 3, 4, 5]).reverse(), new constructor([5, 4, 3, 2, 1]));
+ assertDeepEq(new constructor([.1, .2, .3]).reverse(), new constructor([.3, .2, .1]));
+
+ // Called from other globals.
+ if (typeof newGlobal === "function") {
+ var reverse = newGlobal()[constructor.name].prototype.reverse;
+ assertDeepEq(reverse.call(new constructor([3, 2, 1])), new constructor([1, 2, 3]));
+ }
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.reverse.call(invalidReceiver);
+ }, TypeError, "Assert that reverse fails if this value is not a TypedArray");
+ });
+
+ // Test that the length getter is never called.
+ Object.defineProperty(new constructor([1, 2, 3]), "length", {
+ get() {
+ throw new Error("length accessor called");
+ }
+ }).reverse();
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/seal-and-freeze.js b/js/src/tests/non262/TypedArray/seal-and-freeze.js
new file mode 100644
index 0000000000..f90efb866f
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/seal-and-freeze.js
@@ -0,0 +1,49 @@
+"use strict";
+
+// Seal
+assertEq(Object.isSealed(new Int32Array(2)), false);
+assertEq(Object.isSealed(new Int32Array(0)), false);
+
+var array = new Int32Array(0);
+Object.preventExtensions(array);
+assertEq(Object.isSealed(array), true);
+
+// Non-empty typed arrays can never be sealed, because the elements stay configurable.
+array = new Int32Array(1);
+array.b = "test";
+Object.preventExtensions(array);
+assertEq(Object.isSealed(array), false);
+Object.defineProperty(array, "b", {configurable: false});
+assertEq(Object.isSealed(array), false);
+
+array = new Int32Array(2);
+array.b = "test";
+assertThrowsInstanceOf(() => Object.seal(array), TypeError);
+assertEq(Object.isSealed(array), false);
+assertThrowsInstanceOf(() => array.c = 15, TypeError);
+
+// Freeze
+assertEq(Object.isFrozen(new Int32Array(2)), false);
+assertEq(Object.isFrozen(new Int32Array(0)), false);
+
+// Empty non-extensible typed-array is trivially frozen
+var array = new Int32Array(0);
+Object.preventExtensions(array);
+assertEq(Object.isFrozen(array), true);
+
+array = new Int32Array(0);
+array.b = "test";
+assertEq(Object.isFrozen(array), false);
+Object.preventExtensions(array);
+assertEq(Object.isFrozen(array), false);
+Object.defineProperty(array, "b", {configurable: false, writable: false});
+assertEq(Object.isFrozen(array), true);
+
+// Non-empty typed arrays can never be frozen, because the elements stay writable
+array = new Int32Array(1);
+assertThrowsInstanceOf(() => Object.freeze(array), TypeError);
+assertEq(Object.isExtensible(array), false);
+assertEq(Object.isFrozen(array), false);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/set-detached-bigint.js b/js/src/tests/non262/TypedArray/set-detached-bigint.js
new file mode 100644
index 0000000000..c54f4b867f
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/set-detached-bigint.js
@@ -0,0 +1,19 @@
+let ta = new BigInt64Array(10);
+
+let obj = {
+ get length() {
+ detachArrayBuffer(ta.buffer);
+ return 1;
+ },
+ 0: {
+ valueOf() {
+ return "huzzah!";
+ }
+ },
+};
+
+// Throws a SyntaxError, because "huzzah!" can't be parsed as a BigInt.
+assertThrowsInstanceOf(() => ta.set(obj), SyntaxError);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/set-detached.js b/js/src/tests/non262/TypedArray/set-detached.js
new file mode 100644
index 0000000000..4f9226c608
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/set-detached.js
@@ -0,0 +1,265 @@
+// Tests for detached ArrayBuffer checks in %TypedArray%.prototype.set(array|typedArray, offset).
+
+function* createTypedArrays(lengths = [0, 1, 4, 4096]) {
+ for (let length of lengths) {
+ let buffer = new ArrayBuffer(length * Int32Array.BYTES_PER_ELEMENT);
+ let typedArray = new Int32Array(buffer);
+
+ yield {typedArray, buffer};
+ }
+}
+
+if (typeof detachArrayBuffer === "function") {
+ class ExpectedError extends Error {}
+
+ // No detached check on function entry.
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ detachArrayBuffer(buffer);
+
+ assertThrowsInstanceOf(() => typedArray.set(null, {
+ valueOf() {
+ throw new ExpectedError();
+ }
+ }), ExpectedError);
+ }
+
+ // Check for detached buffer after calling ToInteger(offset). Test with:
+ // - valid offset,
+ // - too large offset,
+ // - and negative offset.
+ for (let [offset, error] of [[0, TypeError], [1000000, TypeError], [-1, RangeError]]) {
+ for (let source of [[], [0], new Int32Array(0), new Int32Array(1)]) {
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ assertThrowsInstanceOf(() => typedArray.set(source, {
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return offset;
+ }
+ }), error);
+ }
+ }
+ }
+
+ // Tests when called with detached typed array as source.
+ for (let {typedArray} of createTypedArrays()) {
+ for (let {typedArray: source, buffer: sourceBuffer} of createTypedArrays()) {
+ detachArrayBuffer(sourceBuffer);
+
+ assertThrowsInstanceOf(() => typedArray.set(source, {
+ valueOf() {
+ throw new ExpectedError();
+ }
+ }), ExpectedError);
+ }
+ }
+
+ // Check when detaching source buffer in ToInteger(offset). Test with:
+ // - valid offset,
+ // - too large offset,
+ // - and negative offset.
+ for (let [offset, error] of [[0, TypeError], [1000000, TypeError], [-1, RangeError]]) {
+ for (let {typedArray} of createTypedArrays()) {
+ for (let {typedArray: source, buffer: sourceBuffer} of createTypedArrays()) {
+ assertThrowsInstanceOf(() => typedArray.set(source, {
+ valueOf() {
+ detachArrayBuffer(sourceBuffer);
+ return offset;
+ }
+ }), error);
+ }
+ }
+ }
+
+ // Test when target and source use the same underlying buffer and
+ // ToInteger(offset) detaches the buffer. Test with:
+ // - same typed array,
+ // - different typed array, but same element type,
+ // - and different element type.
+ for (let src of [ta => ta, ta => new Int32Array(ta.buffer), ta => new Float32Array(ta.buffer)]) {
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let source = src(typedArray);
+ assertThrowsInstanceOf(() => typedArray.set(source, {
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return 0;
+ }
+ }), TypeError);
+ }
+ }
+
+ // Test when Get(src, "length") detaches the buffer, but srcLength is 0.
+ // Also use different offsets to ensure bounds checks use the typed array's
+ // length value from before detaching the buffer.
+ for (let offset of [() => 0, ta => Math.min(1, ta.length), ta => Math.max(0, ta.length - 1)]) {
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let source = {
+ get length() {
+ detachArrayBuffer(buffer);
+ return 0;
+ }
+ };
+ typedArray.set(source, offset(typedArray));
+ }
+ }
+
+ // Test when ToLength(Get(src, "length")) detaches the buffer, but
+ // srcLength is 0. Also use different offsets to ensure bounds checks use
+ // the typed array's length value from before detaching the buffer.
+ for (let offset of [() => 0, ta => Math.min(1, ta.length), ta => Math.max(0, ta.length - 1)]) {
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let source = {
+ length: {
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return 0;
+ }
+ }
+ };
+ typedArray.set(source, offset(typedArray));
+ }
+ }
+
+ // Test no TypeError is thrown when the typed array is detached and
+ // srcLength > 0.
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let source = {
+ length: {
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return 1;
+ }
+ }
+ };
+ if (typedArray.length === 0) {
+ assertThrowsInstanceOf(() => typedArray.set(source), RangeError);
+ } else {
+ typedArray.set(source);
+ }
+ }
+
+ // Same as above, but with side-effect when executing Get(src, "0").
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let source = {
+ get 0() {
+ throw new ExpectedError();
+ },
+ length: {
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return 1;
+ }
+ }
+ };
+ let err = typedArray.length === 0 ? RangeError : ExpectedError;
+ assertThrowsInstanceOf(() => typedArray.set(source), err);
+ }
+
+ // Same as above, but with side-effect when executing ToNumber(Get(src, "0")).
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let source = {
+ get 0() {
+ return {
+ valueOf() {
+ throw new ExpectedError();
+ }
+ };
+ },
+ length: {
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return 1;
+ }
+ }
+ };
+ let err = typedArray.length === 0 ? RangeError : ExpectedError;
+ assertThrowsInstanceOf(() => typedArray.set(source), err);
+ }
+
+ // Side-effects when getting the source elements detach the buffer.
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let source = Object.defineProperties([], {
+ 0: {
+ get() {
+ detachArrayBuffer(buffer);
+ return 1;
+ }
+ }
+ });
+ if (typedArray.length === 0) {
+ assertThrowsInstanceOf(() => typedArray.set(source), RangeError);
+ } else {
+ typedArray.set(source);
+ }
+ }
+
+ // Side-effects when getting the source elements detach the buffer. Also
+ // ensure other elements are accessed.
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let accessed = false;
+ let source = Object.defineProperties([], {
+ 0: {
+ get() {
+ detachArrayBuffer(buffer);
+ return 1;
+ }
+ },
+ 1: {
+ get() {
+ assertEq(accessed, false);
+ accessed = true;
+ return 2;
+ }
+ }
+ });
+ if (typedArray.length <= 1) {
+ assertThrowsInstanceOf(() => typedArray.set(source), RangeError);
+ } else {
+ assertEq(accessed, false);
+ typedArray.set(source);
+ assertEq(accessed, true);
+ }
+ }
+
+ // Side-effects when converting the source elements detach the buffer.
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let source = [{
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return 1;
+ }
+ }];
+ if (typedArray.length === 0) {
+ assertThrowsInstanceOf(() => typedArray.set(source), RangeError);
+ } else {
+ typedArray.set(source);
+ }
+ }
+
+ // Side-effects when converting the source elements detach the buffer. Also
+ // ensure other elements are accessed.
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let accessed = false;
+ let source = [{
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return 1;
+ }
+ }, {
+ valueOf() {
+ assertEq(accessed, false);
+ accessed = true;
+ return 2;
+ }
+ }];
+ if (typedArray.length <= 1) {
+ assertThrowsInstanceOf(() => typedArray.set(source), RangeError);
+ } else {
+ assertEq(accessed, false);
+ typedArray.set(source);
+ assertEq(accessed, true);
+ }
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/set-negative-offset.js b/js/src/tests/non262/TypedArray/set-negative-offset.js
new file mode 100644
index 0000000000..6d9c45ffb2
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/set-negative-offset.js
@@ -0,0 +1,35 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var gTestfile = "set-negative-offset.js";
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 1140752;
+var summary =
+ "%TypedArray%.prototype.set must throw a RangeError when passed a negative " +
+ "offset";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+try
+{
+ new Uint8Array().set([], -1);
+ throw new Error("didn't throw at all");
+}
+catch (e)
+{
+ assertEq(e instanceof RangeError, true,
+ "expected RangeError, instead got: " + e);
+}
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/TypedArray/set-same-buffer-different-source-target-types.js b/js/src/tests/non262/TypedArray/set-same-buffer-different-source-target-types.js
new file mode 100644
index 0000000000..9084ce883a
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/set-same-buffer-different-source-target-types.js
@@ -0,0 +1,41 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var gTestfile = "set-same-buffer-different-source-target-types.js";
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 896116;
+var summary =
+ "When setting a typed array from an overlapping typed array of different " +
+ "element type, copy the source elements into properly-sized temporary " +
+ "memory, and properly copy them into the target without overflow (of " +
+ "either source *or* target) when finished";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+// smallest 2**n triggering segfaults in a pre-patch build locally, then
+// quadrupled in case the boundary ever changes, or is different in some other
+// memory-allocating implementation
+var srclen = 65536;
+
+var ta = new Uint8Array(srclen * Float64Array.BYTES_PER_ELEMENT);
+var ta2 = new Float64Array(ta.buffer, 0, srclen);
+ta.set(ta2);
+
+// This test mostly exists to check for no crash above, but it's worth testing
+// for no uninitialized memory (in case of buffer overflow) being copied into
+// the array, too.
+for (var i = 0, len = ta.length; i < len; i++)
+ assertEq(ta[i], 0, "zero-bits double should convert to zero");
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/TypedArray/set-tointeger.js b/js/src/tests/non262/TypedArray/set-tointeger.js
new file mode 100644
index 0000000000..8c1e9c2418
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/set-tointeger.js
@@ -0,0 +1,95 @@
+// Test ToInteger conversion in %TypedArray%.prototype.set(array|typedArray, offset).
+
+let ta = new Int32Array(4);
+
+// %TypedArray%.prototype.set has two different implementations for typed array
+// and non-typed array arguments. Test with both input types.
+let emptySources = [[], new Int32Array(0)];
+let nonEmptySource = [[0], new Int32Array(1)];
+let sources = [...emptySources, ...nonEmptySource];
+
+// Test when ToInteger(offset) is in (-1, 4).
+let validOffsets = [
+ // Values in [+0, 4).
+ 0,
+ 0.1,
+ 3,
+ 3.9,
+
+ // Values in (-1, -0].
+ -0,
+ -0.1,
+ -0.9,
+
+ NaN,
+
+ // Also include some non-number values.
+ undefined,
+ null,
+ true,
+ "",
+ "3",
+ " 1\t\n",
+ "some string",
+ {valueOf() { return 2; }},
+];
+
+for (let offset of validOffsets) {
+ for (let source of sources) {
+ ta.set(source, offset);
+ }
+}
+
+// Test when ToInteger(offset) isn't in (-1, 4).
+let invalidOffsets = [
+ // Values exceeding the typed array's length.
+ 5,
+ 2147483647,
+ 2147483648,
+ 2147483649,
+ 4294967295,
+ 4294967296,
+ 4294967297,
+ Infinity,
+
+ // Negative values.
+ -1,
+ -1.1,
+ -2147483647,
+ -2147483648,
+ -2147483649,
+ -4294967295,
+ -4294967296,
+ -4294967297,
+ -Infinity,
+
+ // Also include some non-number values.
+ "8",
+ "Infinity",
+ " Infinity ",
+ {valueOf() { return 10; }},
+];
+
+for (let offset of invalidOffsets) {
+ for (let source of sources) {
+ assertThrowsInstanceOf(() => ta.set(source, offset), RangeError);
+ }
+}
+
+// Test when ToInteger(offset) is in [4, 5).
+for (let source of emptySources) {
+ ta.set(source, 4);
+ ta.set(source, 4.9);
+}
+for (let source of nonEmptySource) {
+ assertThrowsInstanceOf(() => ta.set(source, 4), RangeError);
+ assertThrowsInstanceOf(() => ta.set(source, 4.9), RangeError);
+}
+
+// ToInteger(symbol value) throws a TypeError.
+for (let source of sources) {
+ assertThrowsInstanceOf(() => ta.set(source, Symbol()), TypeError);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/set-toobject.js b/js/src/tests/non262/TypedArray/set-toobject.js
new file mode 100644
index 0000000000..360c5dde7e
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/set-toobject.js
@@ -0,0 +1,53 @@
+// Test ToObject in %TypedArray%.prototype.set(array|typedArray, offset).
+
+let ta = new Int32Array(4);
+
+for (let nullOrUndefined of [null, undefined]) {
+ // ToObject(array) throws a TypeError when |array| is null or undefined.
+ assertThrowsInstanceOf(() => ta.set(nullOrUndefined), TypeError);
+
+ // ToInteger(offset) is called before ToObject(array).
+ class ExpectedError extends Error {}
+ assertThrowsInstanceOf(() => ta.set(nullOrUndefined, {
+ valueOf() {
+ throw new ExpectedError();
+ }
+ }), ExpectedError);
+}
+
+// Ensure ta is still initialized with zeros.
+assertEqArray(ta, [0, 0, 0, 0]);
+
+// %TypedArray%.prototype.set can be called with a string primitive values.
+ta.set("");
+assertEqArray(ta, [0, 0, 0, 0]);
+
+ta.set("123");
+assertEqArray(ta, [1, 2, 3, 0]);
+
+// Throws a RangeError if the length is too large.
+assertThrowsInstanceOf(() => ta.set("456789"), RangeError);
+assertEqArray(ta, [1, 2, 3, 0]);
+
+// When called with other primitive values the typed array contents don't
+// change since ToObject(<primitive>).length is zero, i.e. the source object is
+// treated the same as an empty array.
+for (let value of [true, false, 0, NaN, 123, Infinity, Symbol()]) {
+ ta.set(value);
+ assertEqArray(ta, [1, 2, 3, 0]);
+}
+
+// Repeat test from above when the primitive wrapper prototype has been changed
+// to include "length" and an indexed property.
+Number.prototype.length = 4;
+Number.prototype[3] = -1;
+try {
+ ta.set(456);
+ assertEqArray(ta, [0, 0, 0, -1]);
+} finally {
+ delete Number.prototype.length;
+ delete Number.prototype[3];
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/set-with-receiver.js b/js/src/tests/non262/TypedArray/set-with-receiver.js
new file mode 100644
index 0000000000..dc01c0766f
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/set-with-receiver.js
@@ -0,0 +1,28 @@
+for (var constructor of anyTypedArrayConstructors) {
+ var receiver = {};
+
+ var ta = new constructor(1);
+ assertEq(Reflect.set(ta, 0, 47, receiver), true);
+ assertEq(ta[0], 0);
+ assertEq(receiver[0], 47);
+
+ // Out-of-bounds
+ assertEq(Reflect.set(ta, 10, 47, receiver), true);
+ assertEq(ta[10], undefined);
+ assertEq(receiver[10], 47);
+
+ // Detached
+ if (typeof detachArrayBuffer === "function" &&
+ !isSharedConstructor(constructor))
+ {
+ detachArrayBuffer(ta.buffer)
+
+ assertEq(ta[0], undefined);
+ assertEq(Reflect.set(ta, 0, 42, receiver), true);
+ assertEq(ta[0], undefined);
+ assertEq(receiver[0], 42);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/set-wrapped.js b/js/src/tests/non262/TypedArray/set-wrapped.js
new file mode 100644
index 0000000000..30a242bf0b
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/set-wrapped.js
@@ -0,0 +1,81 @@
+// Test %TypedArray%.prototype.set(typedArray, offset) when called with wrapped
+// typed array.
+
+if (typeof newGlobal === "function") {
+ var otherGlobal = newGlobal();
+
+ function taintLengthProperty(obj) {
+ Object.defineProperty(obj, "length", {
+ get() {
+ assertEq(true, false);
+ }
+ });
+ }
+
+ for (var TA of anyTypedArrayConstructors) {
+ var target = new TA(4);
+ var source = new otherGlobal[TA.name]([10, 20]);
+
+ // Ensure "length" getter accessor isn't called.
+ taintLengthProperty(source);
+
+ assertEqArray(target, [0, 0, 0, 0]);
+ target.set(source, 1);
+ assertEqArray(target, [0, 10, 20, 0]);
+ }
+
+ // Detachment checks are also applied correctly for wrapped typed arrays.
+ if (typeof detachArrayBuffer === "function") {
+ // Create typed array from different global (explicit constructor call).
+ for (var TA of typedArrayConstructors) {
+ var target = new TA(4);
+ var source = new otherGlobal[TA.name](1);
+ taintLengthProperty(source);
+
+ // Called with wrapped typed array, array buffer already detached.
+ otherGlobal.detachArrayBuffer(source.buffer);
+ assertThrowsInstanceOf(() => target.set(source), TypeError);
+
+ var source = new otherGlobal[TA.name](1);
+ taintLengthProperty(source);
+
+ // Called with wrapped typed array, array buffer detached when
+ // processing offset parameter.
+ var offset = {
+ valueOf() {
+ otherGlobal.detachArrayBuffer(source.buffer);
+ return 0;
+ }
+ };
+ assertThrowsInstanceOf(() => target.set(source, offset), TypeError);
+ }
+
+ // Create typed array from different global (implictly created when
+ // ArrayBuffer is a CCW).
+ for (var TA of typedArrayConstructors) {
+ var target = new TA(4);
+ var source = new TA(new otherGlobal.ArrayBuffer(1 * TA.BYTES_PER_ELEMENT));
+ taintLengthProperty(source);
+
+ // Called with wrapped typed array, array buffer already detached.
+ otherGlobal.detachArrayBuffer(source.buffer);
+ assertThrowsInstanceOf(() => target.set(source), TypeError);
+
+ var source = new TA(new otherGlobal.ArrayBuffer(1 * TA.BYTES_PER_ELEMENT));
+ taintLengthProperty(source);
+
+ // Called with wrapped typed array, array buffer detached when
+ // processing offset parameter.
+ var offset = {
+ valueOf() {
+ otherGlobal.detachArrayBuffer(source.buffer);
+ return 0;
+ }
+ };
+ assertThrowsInstanceOf(() => target.set(source, offset), TypeError);
+ }
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/set.js b/js/src/tests/non262/TypedArray/set.js
new file mode 100644
index 0000000000..2af5a129a8
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/set.js
@@ -0,0 +1,21 @@
+const TypedArrayPrototype = Object.getPrototypeOf(Int8Array.prototype);
+
+// %TypedArrayPrototype% has an own "set" function property.
+assertEq(TypedArrayPrototype.hasOwnProperty("set"), true);
+assertEq(typeof TypedArrayPrototype.set, "function");
+
+// The concrete TypedArray prototypes do not have an own "set" property.
+assertEq(anyTypedArrayConstructors.every(c => !c.hasOwnProperty("set")), true);
+
+assertDeepEq(Object.getOwnPropertyDescriptor(TypedArrayPrototype, "set"), {
+ value: TypedArrayPrototype.set,
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+assertEq(TypedArrayPrototype.set.name, "set");
+assertEq(TypedArrayPrototype.set.length, 1);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/shell.js b/js/src/tests/non262/TypedArray/shell.js
new file mode 100644
index 0000000000..2fb0ab8f1d
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/shell.js
@@ -0,0 +1,114 @@
+(function(global) {
+ "use strict";
+
+ const {
+ Float32Array, Float64Array, Object, Reflect, SharedArrayBuffer, WeakMap,
+ assertEq
+ } = global;
+ const {
+ apply: Reflect_apply,
+ construct: Reflect_construct,
+ } = Reflect;
+ const {
+ get: WeakMap_prototype_get,
+ has: WeakMap_prototype_has,
+ } = WeakMap.prototype;
+
+ const sharedConstructors = new WeakMap();
+
+ // Synthesize a constructor for a shared memory array from the constructor
+ // for unshared memory. This has "good enough" fidelity for many uses. In
+ // cases where it's not good enough, call isSharedConstructor for local
+ // workarounds.
+ function sharedConstructor(baseConstructor) {
+ // Create SharedTypedArray as a subclass of %TypedArray%, following the
+ // built-in %TypedArray% subclasses.
+ class SharedTypedArray extends Object.getPrototypeOf(baseConstructor) {
+ constructor(...args) {
+ var array = Reflect_construct(baseConstructor, args);
+ var {buffer, byteOffset, length} = array;
+ var sharedBuffer = new SharedArrayBuffer(buffer.byteLength);
+ var sharedArray = Reflect_construct(baseConstructor,
+ [sharedBuffer, byteOffset, length],
+ new.target);
+ for (var i = 0; i < length; i++)
+ sharedArray[i] = array[i];
+ assertEq(sharedArray.buffer, sharedBuffer);
+ return sharedArray;
+ }
+ }
+
+ // 22.2.5.1 TypedArray.BYTES_PER_ELEMENT
+ Object.defineProperty(SharedTypedArray, "BYTES_PER_ELEMENT",
+ {__proto__: null, value: baseConstructor.BYTES_PER_ELEMENT});
+
+ // 22.2.6.1 TypedArray.prototype.BYTES_PER_ELEMENT
+ Object.defineProperty(SharedTypedArray.prototype, "BYTES_PER_ELEMENT",
+ {__proto__: null, value: baseConstructor.BYTES_PER_ELEMENT});
+
+ // Share the same name with the base constructor to avoid calling
+ // isSharedConstructor() in multiple places.
+ Object.defineProperty(SharedTypedArray, "name",
+ {__proto__: null, value: baseConstructor.name});
+
+ sharedConstructors.set(SharedTypedArray, baseConstructor);
+
+ return SharedTypedArray;
+ }
+
+ /**
+ * All TypedArray constructors for unshared memory.
+ */
+ const typedArrayConstructors = Object.freeze([
+ Int8Array,
+ Uint8Array,
+ Uint8ClampedArray,
+ Int16Array,
+ Uint16Array,
+ Int32Array,
+ Uint32Array,
+ Float32Array,
+ Float64Array,
+ ]);
+
+ /**
+ * All TypedArray constructors for shared memory.
+ */
+ const sharedTypedArrayConstructors = Object.freeze(
+ typeof SharedArrayBuffer === "function"
+ ? typedArrayConstructors.map(sharedConstructor)
+ : []
+ );
+
+ /**
+ * All TypedArray constructors for unshared and shared memory.
+ */
+ const anyTypedArrayConstructors = Object.freeze([
+ ...typedArrayConstructors, ...sharedTypedArrayConstructors,
+ ]);
+
+ /**
+ * Returns `true` if `constructor` is a TypedArray constructor for shared
+ * memory.
+ */
+ function isSharedConstructor(constructor) {
+ return Reflect_apply(WeakMap_prototype_has, sharedConstructors, [constructor]);
+ }
+
+ /**
+ * Returns `true` if `constructor` is a TypedArray constructor for shared
+ * or unshared memory, with an underlying element type of either Float32 or
+ * Float64.
+ */
+ function isFloatConstructor(constructor) {
+ if (isSharedConstructor(constructor))
+ constructor = Reflect_apply(WeakMap_prototype_get, sharedConstructors, [constructor]);
+ return constructor == Float32Array || constructor == Float64Array;
+ }
+
+ global.typedArrayConstructors = typedArrayConstructors;
+ global.sharedTypedArrayConstructors = sharedTypedArrayConstructors;
+ global.anyTypedArrayConstructors = anyTypedArrayConstructors;
+ global.isSharedConstructor = isSharedConstructor;
+ global.isFloatConstructor = isFloatConstructor;
+})(this);
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 0000000000..ea0a670b18
--- /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 0000000000..bc44d798c5
--- /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-detached.js b/js/src/tests/non262/TypedArray/slice-detached.js
new file mode 100644
index 0000000000..be16653154
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/slice-detached.js
@@ -0,0 +1,103 @@
+// Tests for detached ArrayBuffer checks in %TypedArray%.prototype.slice ( start, end ).
+
+function* createTypedArrays(lengths = [0, 1, 4, 4096]) {
+ // Test with eagerly created ArrayBuffer.
+ for (let length of lengths) {
+ let buffer = new ArrayBuffer(length * Int32Array.BYTES_PER_ELEMENT);
+ let typedArray = new Int32Array(buffer);
+
+ yield {typedArray, length, buffer() { return buffer; }};
+ }
+
+ // Test with lazily created ArrayBuffer.
+ for (let length of lengths) {
+ let typedArray = new Int32Array(length);
+
+ yield {typedArray, length, buffer() { return typedArray.buffer; }};
+ }
+}
+
+if (typeof detachArrayBuffer === "function") {
+ // ArrayBuffer is detached when entering slice().
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ detachArrayBuffer(buffer());
+ assertThrowsInstanceOf(() => {
+ typedArray.slice(0);
+ }, TypeError, "ArrayBuffer is detached on function entry");
+ }
+
+ // ArrayBuffer is detached when computing ToInteger(start).
+ for (let {typedArray, length, buffer} of createTypedArrays()) {
+ let detached = false;
+ let start = {
+ valueOf() {
+ assertEq(detached, false);
+ detachArrayBuffer(buffer());
+ assertEq(detached, false);
+ detached = true;
+ return 0;
+ }
+ };
+
+ // Doesn't throw an error when no bytes are copied.
+ if (length === 0) {
+ typedArray.slice(start);
+ } else {
+ assertThrowsInstanceOf(() => {
+ typedArray.slice(start);
+ }, TypeError, "ArrayBuffer is detached in ToInteger(start)");
+ }
+ assertEq(detached, true, "detachArrayBuffer was called");
+ }
+
+ // ArrayBuffer is detached when computing ToInteger(end).
+ for (let {typedArray, length, buffer} of createTypedArrays()) {
+ let detached = false;
+ let end = {
+ valueOf() {
+ assertEq(detached, false);
+ detachArrayBuffer(buffer());
+ assertEq(detached, false);
+ detached = true;
+ return length;
+ }
+ };
+
+ // Doesn't throw an error when no bytes are copied.
+ if (length === 0) {
+ typedArray.slice(0, end);
+ } else {
+ assertThrowsInstanceOf(() => {
+ typedArray.slice(0, end);
+ }, TypeError, "ArrayBuffer is detached in ToInteger(end)");
+ }
+ assertEq(detached, true, "detachArrayBuffer was called");
+ }
+
+ // ArrayBuffer is detached in species constructor.
+ for (let {typedArray, length, buffer} of createTypedArrays()) {
+ let detached = false;
+ typedArray.constructor = {
+ [Symbol.species]: function(...args) {
+ assertEq(detached, false);
+ detachArrayBuffer(buffer());
+ assertEq(detached, false);
+ detached = true;
+ return new Int32Array(...args);
+ }
+ };
+
+ // Doesn't throw an error when no bytes are copied.
+ if (length === 0) {
+ typedArray.slice(0);
+ } else {
+ assertThrowsInstanceOf(() => {
+ typedArray.slice(0);
+ }, TypeError, "ArrayBuffer is detached in TypedArraySpeciesCreate(...)");
+ }
+ assertEq(detached, true, "detachArrayBuffer was called");
+ }
+}
+
+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 0000000000..a20010ed16
--- /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 (this.setSharedObject && this.SharedArrayBuffer) {
+ 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) {
+ setSharedObject(ab);
+ try {
+ return otherGlobal.eval(`
+ new ${constructor.name}(getSharedObject(), ${2 * elementSize}, ${len});
+ `);
+ } finally {
+ setSharedObject(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/tests/non262/TypedArray/slice-species.js b/js/src/tests/non262/TypedArray/slice-species.js
new file mode 100644
index 0000000000..8a03f2f6ee
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/slice-species.js
@@ -0,0 +1,49 @@
+for (var constructor of typedArrayConstructors) {
+ // Basic tests for our SpeciesConstructor implementation.
+ var undefConstructor = new constructor(2);
+ undefConstructor.constructor = undefined;
+ assertDeepEq(undefConstructor.slice(1), new constructor(1));
+
+ assertThrowsInstanceOf(() => {
+ var strConstructor = new constructor;
+ strConstructor.constructor = "not a constructor";
+ strConstructor.slice(123);
+ }, TypeError, "Assert that we have an invalid constructor");
+
+ // If obj.constructor[@@species] is undefined or null then the default
+ // constructor is used.
+ var mathConstructor = new constructor(8);
+ mathConstructor.constructor = Math.sin;
+ assertDeepEq(mathConstructor.slice(4), new constructor(4));
+
+ var undefSpecies = new constructor(2);
+ undefSpecies.constructor = { [Symbol.species]: undefined };
+ assertDeepEq(undefSpecies.slice(1), new constructor(1));
+
+ var nullSpecies = new constructor(2);
+ nullSpecies.constructor = { [Symbol.species]: null };
+ assertDeepEq(nullSpecies.slice(1), new constructor(1));
+
+ // If obj.constructor[@@species] is different constructor, it should be
+ // used.
+ for (var constructor2 of typedArrayConstructors) {
+ var modifiedConstructor = new constructor(2);
+ modifiedConstructor.constructor = constructor2;
+ assertDeepEq(modifiedConstructor.slice(1), new constructor2(1));
+
+ var modifiedSpecies = new constructor(2);
+ modifiedSpecies.constructor = { [Symbol.species]: constructor2 };
+ assertDeepEq(modifiedSpecies.slice(1), new constructor2(1));
+ }
+
+ // If obj.constructor[@@species] is neither undefined nor null, and it's
+ // not a constructor, TypeError should be thrown.
+ assertThrowsInstanceOf(() => {
+ var strSpecies = new constructor;
+ strSpecies.constructor = { [Symbol.species]: "not a constructor" };
+ strSpecies.slice(123);
+ }, TypeError);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/slice-validation.js b/js/src/tests/non262/TypedArray/slice-validation.js
new file mode 100644
index 0000000000..28d50e36f4
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/slice-validation.js
@@ -0,0 +1,194 @@
+/* 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/. */
+
+// Summary: Ensure typed array validation is called for TypedArray.prototype.slice.
+
+const otherGlobal = newGlobal({newCompartment: true});
+const typedArrayLengths = [0, 1, 1024];
+
+// Note: slice uses CallTypedArrayMethodIfWrapped, which results in throwing
+// a TypeError from the wrong Realm if cross-compartment. The browser
+// runner doesn't support the "newCompartment" option, so it can't create
+// cross-compartment globals, which means it throws the error from the
+// correct Realm.
+const eitherGlobalTypeError = {
+ [Symbol.hasInstance](obj) {
+ return obj instanceof TypeError || obj instanceof otherGlobal.TypeError;
+ }
+};
+
+function createTestCases(TAConstructor, constructor, constructorCrossRealm) {
+ let testCases = [];
+ testCases.push({
+ species: constructor,
+ method: TAConstructor.prototype.slice,
+ error: TypeError,
+ });
+ testCases.push({
+ species: constructorCrossRealm,
+ method: TAConstructor.prototype.slice,
+ error: TypeError,
+ });
+ testCases.push({
+ species: constructor,
+ method: otherGlobal[TAConstructor.name].prototype.slice,
+ error: eitherGlobalTypeError,
+ });
+ return testCases;
+}
+
+// Throws TypeError when the returned value is not a typed array.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function NoTypedArrayConstructor(...args) {
+ let a = [];
+ callCount += 1;
+ return a;
+ }
+ function NoTypedArrayConstructorCrossRealm(...args) {
+ let a = new otherGlobal.Array();
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, NoTypedArrayConstructor, NoTypedArrayConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ assertThrowsInstanceOf(() => method.call(ta, 0), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ assertThrowsInstanceOf(() => method.call(ta, 0, 0), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// Throws TypeError exception when returned array is too small.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function TooSmallConstructor(length) {
+ let a = new TAConstructor(Math.max(length - 1, 0));
+ callCount += 1;
+ return a;
+ }
+ function TooSmallConstructorCrossRealm(length) {
+ let a = new otherGlobal[TAConstructor.name](Math.max(length - 1, 0));
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, TooSmallConstructor, TooSmallConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+
+ // Passes when the length is zero.
+ if (length === 0) {
+ let result = method.call(ta, 0);
+ assertEq(result.length, 0);
+ } else {
+ assertThrowsInstanceOf(() => method.call(ta, 0), error);
+ }
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ let result = method.call(ta, 0, 0);
+ assertEq(result.length, 0);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// No exception when array is larger than requested.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ const extraLength = 1;
+
+ let callCount = 0, expectedCallCount = 0;
+ function TooLargeConstructor(length) {
+ let a = new TAConstructor(length + extraLength);
+ callCount += 1;
+ return a;
+ }
+ function TooLargeConstructorCrossRealm(length) {
+ let a = new otherGlobal[TAConstructor.name](length + extraLength);
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, TooLargeConstructor, TooLargeConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ let result = method.call(ta, 0);
+ assertEq(result.length, length + extraLength);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ let result = method.call(ta, 0, 0);
+ assertEq(result.length, extraLength);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// Throws TypeError exception when returned array is detached.
+if (typeof detachArrayBuffer === "function") {
+ for (const TAConstructor of typedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function DetachConstructor(...args) {
+ let a = new TAConstructor(...args);
+ detachArrayBuffer(a.buffer);
+ callCount += 1;
+ return a;
+ }
+ function DetachConstructorCrossRealm(...args) {
+ let a = new otherGlobal[TAConstructor.name](...args);
+ otherGlobal.detachArrayBuffer(a.buffer);
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, DetachConstructor, DetachConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ assertThrowsInstanceOf(() => method.call(ta, 0), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ assertThrowsInstanceOf(() => method.call(ta, 0, 0), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/TypedArray/slice.js b/js/src/tests/non262/TypedArray/slice.js
new file mode 100644
index 0000000000..0a5ce4c50b
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/slice.js
@@ -0,0 +1,45 @@
+for (var constructor of anyTypedArrayConstructors) {
+ assertDeepEq(constructor.prototype.slice.length, 2);
+
+ assertDeepEq(new constructor().slice(0), new constructor());
+ assertDeepEq(new constructor().slice(0, 4), new constructor());
+ assertDeepEq(new constructor(10).slice(0, 2), new constructor(2));
+
+ assertDeepEq(new constructor([1, 2]).slice(1), new constructor([2]));
+ assertDeepEq(new constructor([1, 2]).slice(0), new constructor([1, 2]));
+ assertDeepEq(new constructor([1, 2, 3]).slice(-1), new constructor([3]));
+ assertDeepEq(new constructor([1, 2, 3, 4]).slice(-3, -1), new constructor([2, 3]));
+ assertDeepEq(new constructor([.1, .2]).slice(0), new constructor([.1, .2]));
+
+ assertDeepEq(new constructor([1, 2]).slice(-3), new constructor([1, 2]));
+ assertDeepEq(new constructor([1, 2]).slice(0, -3), new constructor());
+ assertDeepEq(new constructor([1, 2]).slice(4), new constructor());
+ assertDeepEq(new constructor([1, 2]).slice(1, 5), new constructor([2]));
+
+ // Called from other globals.
+ if (typeof newGlobal === "function") {
+ var slice = newGlobal()[constructor.name].prototype.slice;
+ assertDeepEq(slice.call(new constructor([3, 2, 1]), 1),
+ new constructor([2, 1]));
+ }
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.slice.call(invalidReceiver, 0);
+ }, TypeError, "Assert that slice fails if this value is not a TypedArray");
+ });
+
+ // Test that the length getter is never called.
+ Object.defineProperty(new constructor([1, 2, 3]), "length", {
+ get() {
+ throw new Error("length accessor called");
+ }
+ }).slice(2);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
diff --git a/js/src/tests/non262/TypedArray/sort-negative-nan.js b/js/src/tests/non262/TypedArray/sort-negative-nan.js
new file mode 100644
index 0000000000..cf9a67714b
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/sort-negative-nan.js
@@ -0,0 +1,106 @@
+// Test with all floating point typed arrays.
+const floatConstructors = anyTypedArrayConstructors.filter(isFloatConstructor);
+
+// Also test with cross-compartment wrapped typed arrays.
+if (typeof newGlobal === "function") {
+ const otherGlobal = newGlobal();
+ floatConstructors.push(otherGlobal.Float32Array);
+ floatConstructors.push(otherGlobal.Float64Array);
+}
+
+function* prod(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 seti32(i32, i, v) {
+ i32[i] = v;
+}
+
+function seti64(i32, i, [hi, lo]) {
+ i32[i * 2 + isLittleEndian] = hi;
+ i32[i * 2 + !isLittleEndian] = lo;
+}
+
+const setInt = {
+ Float32: seti32,
+ Float64: seti64,
+};
+
+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
+ ],
+};
+
+// %TypedArray%.prototype.sort
+const TypedArraySort = Int32Array.prototype.sort;
+
+// Test with small and large typed arrays.
+const typedArrayLengths = [16, 4096];
+
+for (const [TA, taLength] of prod(floatConstructors, typedArrayLengths)) {
+ let type = TA.name.slice(0, -"Array".length);
+ let nansLength = NaNs[type].length;
+ let fta = new TA(taLength);
+ let i32 = new Int32Array(fta.buffer);
+
+ // Add NaNs in various representations at the start of the typed array.
+ for (let i = 0; i < nansLength; ++i) {
+ setInt[type](i32, i, NaNs[type][i]);
+ }
+
+ // Also add two non-NaN values for testing.
+ fta[nansLength] = 123;
+ fta[nansLength + 1] = -456;
+
+ // Sort the array and validate sort() sorted all elements correctly.
+ TypedArraySort.call(fta);
+
+ // |-456| should be sorted to the start.
+ assertEq(fta[0], -456);
+
+ // Followed by a bunch of zeros,
+ const zeroOffset = 1;
+ const zeroCount = taLength - nansLength - 2;
+ for (let i = 0; i < zeroCount; ++i) {
+ assertEq(fta[zeroOffset + i], 0, `At offset: ${zeroOffset + i}`);
+ }
+
+ // and then |123|.
+ assertEq(fta[zeroOffset + zeroCount], 123);
+
+ // And finally the NaNs.
+ const nanOffset = zeroCount + 2;
+ for (let i = 0; i < nansLength; ++i) {
+ // We don't assert a specific NaN value is present, because this is
+ // not required by the spec and we don't provide any guarantees NaN
+ // values are either unchanged or canonicalized in sort().
+ assertEq(fta[nanOffset + i], NaN, `At offset: ${nanOffset + i}`);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/sort-non-function.js b/js/src/tests/non262/TypedArray/sort-non-function.js
new file mode 100644
index 0000000000..bea810457a
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/sort-non-function.js
@@ -0,0 +1,22 @@
+// %TypedArray%.prototype.sort throws if the comparator is neither undefined nor
+// a callable object.
+
+// Use a zero length typed array, so we can provide any kind of callable object
+// without worrying that the function is actually a valid comparator function.
+const typedArray = new Int32Array(0);
+
+// Throws if the comparator is neither undefined nor callable.
+for (let invalidComparator of [null, 0, true, Symbol(), {}, []]) {
+ assertThrowsInstanceOf(() => typedArray.sort(invalidComparator), TypeError);
+}
+
+// Doesn't throw if the comparator is undefined or a callable object.
+for (let validComparator of [undefined, () => {}, Math.max, class {}, new Proxy(function(){}, {})]) {
+ typedArray.sort(validComparator);
+}
+
+// Also doesn't throw if no comparator was provided at all.
+typedArray.sort();
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/TypedArray/sort_basics.js b/js/src/tests/non262/TypedArray/sort_basics.js
new file mode 100644
index 0000000000..3338861507
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/sort_basics.js
@@ -0,0 +1,73 @@
+// Note: failed runs should include their "SEED" value in error messages,
+// setting "const SEED" to that value will recreate the data from any such run.
+const SEED = (Math.random() * 10) + 1;
+
+// Fill up an array buffer with random values and return it in raw form.
+// 'size' is the desired length of the view we will place atop the buffer,
+// 'width' is the bit-width of the view we plan on placing atop the buffer,
+// and 'seed' is an initial value supplied to a pseudo-random number generator.
+function genRandomArrayBuffer(size, width, seed) {
+ let buf = new ArrayBuffer((width / 8) * size);
+ let arr = new Uint8Array(buf);
+ let len = 0;
+ // We generate a random number, n, where 0 <= n <= 255 for every space
+ // available in our buffer.
+ for (let n of XorShiftGenerator(seed, buf.byteLength))
+ arr[len++] = n;
+ return buf;
+}
+
+// Because we can generate any possible combination of bits, some floating point
+// entries will take on -Infinity, Infinity, and NaN values. This function ensures
+// that a is <= b, where, like the default comparator, -Infinity < Infinity and
+// every non-NaN < NaN.
+function lte(a, b) {
+ if (isNaN(b))
+ return true;
+ return a <= b;
+}
+
+// A a >= b counterpart to the helper function above.
+function gte(a, b) {
+ return lte(b, a);
+}
+
+// A custom comparator.
+function cmp(a, b) {
+ return lte(a, b) ? gte(a, b) ? 0 : -1 : 1;
+}
+
+function SortTest(dataType, dataSource) {
+ let typedArray = new dataType(dataSource);
+ let originalValues = Array.from(typedArray);
+
+ // Test the default comparator
+ typedArray.sort();
+
+ // Test against regular array sort
+ assertEqArray(Array.from(typedArray), Array.from(originalValues).sort(cmp),
+ `The array is not properly sorted! seed: ${SEED}`);
+
+ // Another sanity check
+ for (let i=0; i < typedArray.length - 1; i++)
+ assertEq(lte(typedArray[i], typedArray[i + 1]), true,
+ `The array is not properly sorted! ${typedArray[i]} > ${typedArray[i + 1]}, seed: ${SEED}`)
+
+ // Test custom comparators
+ typedArray.sort((x, y) => cmp(y, x));
+
+ // The array should be in reverse order
+ for (let i=typedArray.length - 2; i >= 0; i--)
+ assertEq(gte(typedArray[i], typedArray[i + 1]), true,
+ `The array is not properly sorted! ${typedArray[i]} < ${typedArray[i + 1]}, seed: ${SEED}`)
+}
+
+for (let constructor of anyTypedArrayConstructors) {
+ for (let arrayLength of [512, 256, 16, 0]) {
+ let source = genRandomArrayBuffer(arrayLength, constructor.BYTES_PER_ELEMENT * 8, SEED);
+ SortTest(constructor, source);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/sort_byteoffset.js b/js/src/tests/non262/TypedArray/sort_byteoffset.js
new file mode 100644
index 0000000000..b4e262c450
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/sort_byteoffset.js
@@ -0,0 +1,30 @@
+// Ensure that when sorting TypedArrays we don't
+// ignore byte offsets (bug 1290579).
+
+var sortFunctions = [Int32Array.prototype.sort];
+
+// Also test with cross-compartment wrapped typed arrays.
+if (typeof newGlobal === "function") {
+ var otherGlobal = newGlobal();
+ sortFunctions.push(newGlobal().Int32Array.prototype.sort);
+}
+
+// The bug manifests itself only with Float arrays,
+// but checking everything here just for sanity.
+
+for (var ctor of anyTypedArrayConstructors) {
+ var ab = new ArrayBuffer(1025 * ctor.BYTES_PER_ELEMENT);
+ var ta = new ctor(ab, ctor.BYTES_PER_ELEMENT, 1024);
+
+ // |testArray[0]| shouldn't be modified when sort() is called below.
+ var testArray = new ctor(ab, 0, 1);
+ testArray[0] = 1;
+
+ for (var sortFn of sortFunctions) {
+ sortFn.call(ta);
+ assertEq(testArray[0], 1);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/sort_comparators.js b/js/src/tests/non262/TypedArray/sort_comparators.js
new file mode 100644
index 0000000000..ca190948fc
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/sort_comparators.js
@@ -0,0 +1,32 @@
+// Ensure that sorts finish even if a comparator adds items
+// Note: the array is not expected to be properly sorted.
+let outsideArray = new Int32Array([1, 99, 2]);
+function addingComparator(x, y) {
+ if (x == 99 || y == 99) {
+ outsideArray[0] = 101;
+ outsideArray[outsideArray.length - 1] = 102;
+ }
+ return x - y;
+}
+outsideArray.sort(addingComparator);
+assertEq(outsideArray.every(x => [1, 2, 99, 101, 102].includes(x)), true);
+
+// Ensure that sorts finish even if a comparator calls sort again
+// Note: the array is not expected to be properly sorted.
+outsideArray = new Int32Array([1, 99, 2]);
+function recursiveComparator(x, y) {
+ outsideArray.sort();
+ return x - y;
+}
+outsideArray.sort(recursiveComparator);
+assertEq(outsideArray.every(x => outsideArray.includes(x)), true)
+
+// Ensure that NaN's returned from custom comparators behave as / are converted
+// to +0s.
+let nanComparatorData = [2112, 42, 1111, 34];
+let nanComparatorArray = new Int32Array(nanComparatorData);
+nanComparatorArray.sort((x, y) => NaN);
+assertEq(nanComparatorData.every(x => nanComparatorArray.includes(x)), true);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/sort_compare_nan.js b/js/src/tests/non262/TypedArray/sort_compare_nan.js
new file mode 100644
index 0000000000..c9af7dff77
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/sort_compare_nan.js
@@ -0,0 +1,12 @@
+// Returning zero from the sort comparator...
+let ta = new Int32Array([0, 1]).sort(() => 0);
+assertEq(ta[0], 0);
+assertEq(ta[1], 1);
+
+// ... should give the same result as returning NaN.
+let tb = new Int32Array([0, 1]).sort(() => NaN);
+assertEq(tb[0], 0);
+assertEq(tb[1], 1);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/sort_errors.js b/js/src/tests/non262/TypedArray/sort_errors.js
new file mode 100644
index 0000000000..f3bdc05b20
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/sort_errors.js
@@ -0,0 +1,87 @@
+// Ensure that TypedArrays throw when attempting to sort a detached ArrayBuffer
+if (typeof detachArrayBuffer === "function") {
+ assertThrowsInstanceOf(() => {
+ let buffer = new ArrayBuffer(32);
+ let array = new Int32Array(buffer);
+ detachArrayBuffer(buffer);
+ array.sort();
+ }, TypeError);
+}
+
+// Ensure detaching buffer in comparator doesn't throw an error.
+if (typeof detachArrayBuffer === "function") {
+ let detached = false;
+ let ta = new Int32Array(3);
+ ta.sort(function(a, b) {
+ if (!detached) {
+ detached = true;
+ detachArrayBuffer(ta.buffer);
+ }
+ return a - b;
+ });
+ assertEq(detached, true);
+}
+
+// Ensure detachment check doesn't choke on wrapped typed array.
+if (typeof newGlobal === "function") {
+ let ta = new Int32Array(3);
+ let otherGlobal = newGlobal();
+ otherGlobal.Int32Array.prototype.sort.call(ta, function(a, b) {
+ return a - b;
+ });
+}
+
+// Ensure detaching buffer in comparator doesn't throw an error when the typed array is wrapped.
+if (typeof newGlobal === "function" && typeof detachArrayBuffer === "function") {
+ let detached = false;
+ let ta = new Int32Array(3);
+ let otherGlobal = newGlobal();
+ otherGlobal.Int32Array.prototype.sort.call(ta, function(a,b) {
+ if (!detached) {
+ detached = true;
+ detachArrayBuffer(ta.buffer);
+ }
+ return a - b;
+ });
+ assertEq(detached, true);
+}
+
+// Ensure that TypedArray.prototype.sort will not sort non-TypedArrays
+assertThrowsInstanceOf(() => {
+ let array = [4, 3, 2, 1];
+ Int32Array.prototype.sort.call(array);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ Int32Array.prototype.sort.call({a: 1, b: 2});
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ Int32Array.prototype.sort.call(Int32Array.prototype);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ let buf = new ArrayBuffer(32);
+ Int32Array.prototype.sort.call(buf);
+}, TypeError);
+
+// Ensure that comparator errors are propagataed
+function badComparator(x, y) {
+ if (x == 99 && y == 99)
+ throw new TypeError;
+ return x - y;
+}
+
+assertThrowsInstanceOf(() => {
+ let array = new Uint8Array([99, 99, 99, 99]);
+ array.sort(badComparator);
+}, TypeError);
+
+assertThrowsInstanceOf(() => {
+ let array = new Uint8Array([1, 99, 2, 99]);
+ array.sort(badComparator);
+}, TypeError);
+
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/sort_globals.js b/js/src/tests/non262/TypedArray/sort_globals.js
new file mode 100644
index 0000000000..6bab6a3913
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/sort_globals.js
@@ -0,0 +1,9 @@
+// TypedArray.prototype.sort should work across globals
+let g2 = newGlobal();
+assertEqArray(
+ Int32Array.prototype.sort.call(new g2.Int32Array([3, 2, 1])),
+ new Int32Array([1, 2, 3])
+);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/sort_modifications.js b/js/src/tests/non262/TypedArray/sort_modifications.js
new file mode 100644
index 0000000000..2a6ed49eb7
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/sort_modifications.js
@@ -0,0 +1,73 @@
+const TAConstructors = [
+ Int8Array,
+ Uint8Array,
+ Int16Array,
+ Uint16Array,
+ Int32Array,
+ Uint32Array,
+ Uint8ClampedArray,
+ Float32Array,
+ Float64Array,
+ BigInt64Array,
+ BigUint64Array,
+];
+
+// Use different size classes to catch any implementation-specific
+// optimisations.
+const sizes = [
+ 4, 8, 64, 128, 1024
+];
+
+function ToNumeric(TA) {
+ if (TA === BigInt64Array || TA === BigUint64Array) {
+ return BigInt;
+ }
+ return Number;
+}
+
+function ascending(a, b) {
+ return a < b ? -1 : a > b ? 1 : 0;
+}
+
+function descending(a, b) {
+ return -ascending(a, b);
+}
+
+for (let TA of TAConstructors) {
+ let toNumeric = ToNumeric(TA);
+ for (let size of sizes) {
+ let sorted = new TA(size);
+
+ // Fill with |1..size| and then sort to account for wrap-arounds.
+ for (let i = 0; i < size; ++i) {
+ sorted[i] = toNumeric(i + 1);
+ }
+ sorted.sort();
+
+ // Create a copy in descending order.
+ let ta = new TA(sorted);
+ ta.sort(descending);
+
+ // Sort the copy in ascending order and on the first call reset all
+ // elements to zero.
+ let called = false;
+ ta.sort(function(a, b) {
+ if (!called) {
+ called = true;
+ ta.fill(toNumeric(0));
+ }
+ return ascending(a, b);
+ });
+
+ // Ensure the comparator function was called.
+ assertEq(called, true);
+
+ // All elements should be sorted correctly. No elements should be zero.
+ for (let i = 0; i < size; ++i) {
+ assertEq(ta[i], sorted[i], `${TA.name} at index ${i} for size ${size}`);
+ }
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/sort_modifications_concurrent.js b/js/src/tests/non262/TypedArray/sort_modifications_concurrent.js
new file mode 100644
index 0000000000..99493df800
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/sort_modifications_concurrent.js
@@ -0,0 +1,145 @@
+// |reftest| skip-if(!xulRuntime.shell)
+
+if (helperThreadCount() === 0) {
+ if (typeof reportCompare === "function")
+ reportCompare(true, true);
+ quit();
+}
+
+const TAConstructors = [
+ Int8Array,
+ Uint8Array,
+ Int16Array,
+ Uint16Array,
+ Int32Array,
+ Uint32Array,
+ Uint8ClampedArray,
+ Float32Array,
+ Float64Array,
+ BigInt64Array,
+ BigUint64Array,
+];
+
+// Use different size classes to catch any implementation-specific
+// optimisations.
+const sizes = [
+ 4, 8, 64, 128, 1024
+];
+
+function ToNumeric(TA) {
+ if (TA === BigInt64Array || TA === BigUint64Array) {
+ return BigInt;
+ }
+ return Number;
+}
+
+function ToAtomicTA(TA) {
+ switch (TA) {
+ case Int8Array:
+ case Int16Array:
+ case Int32Array:
+ case Uint8Array:
+ case Uint16Array:
+ case Uint32Array:
+ case BigInt64Array:
+ case BigUint64Array:
+ return TA;
+ case Uint8ClampedArray:
+ return Uint8Array;
+ case Float32Array:
+ return Uint32Array;
+ case Float64Array:
+ return BigUint64Array;
+ }
+ throw new Error("Invalid typed array kind");
+}
+
+function ascending(a, b) {
+ return a < b ? -1 : a > b ? 1 : 0;
+}
+
+function descending(a, b) {
+ return -ascending(a, b);
+}
+
+for (let TA of TAConstructors) {
+ let toNumeric = ToNumeric(TA);
+ for (let size of sizes) {
+ let sorted = new TA(size);
+
+ // Fill with |1..size| and then sort to account for wrap-arounds.
+ for (let i = 0; i < size; ++i) {
+ sorted[i] = toNumeric(i + 1);
+ }
+ sorted.sort();
+
+ let extra = Math.max(TA.BYTES_PER_ELEMENT, Int32Array.BYTES_PER_ELEMENT);
+ let buffer = new SharedArrayBuffer(size * TA.BYTES_PER_ELEMENT + extra);
+ let controller = new Int32Array(buffer, 0, 1);
+
+ // Create a copy in descending order.
+ let ta = new TA(buffer, extra, size);
+ ta.set(sorted)
+ ta.sort(descending);
+
+ // Worker code expects that the last element changes when sorted.
+ assertEq(ta[size - 1] === sorted[size - 1], false);
+
+ setSharedObject(buffer);
+
+ evalInWorker(`
+ const ToNumeric = ${ToNumeric};
+ const ToAtomicTA = ${ToAtomicTA};
+ const TA = ${TA.name};
+ const AtomicTA = ToAtomicTA(TA);
+
+ let size = ${size};
+ let extra = ${extra};
+
+ let toNumeric = ToNumeric(AtomicTA);
+ let buffer = getSharedObject();
+ let controller = new Int32Array(buffer, 0, 1);
+ let ta = new AtomicTA(buffer, extra, size);
+
+ let value = Atomics.load(ta, size - 1);
+
+ // Coordinate with main thread.
+ while (Atomics.notify(controller, 0, 1) < 1) ;
+
+ // Wait until modification of the last element.
+ //
+ // Sorting writes in ascending indexed ordered, so when the last element
+ // was modified, we know that the sort operation has finished.
+ while (Atomics.load(ta, size - 1) === value) ;
+
+ // Set all elements to zero.
+ ta.fill(toNumeric(0));
+
+ // Sleep for 50 ms.
+ const amount = 0.05;
+
+ // Coordinate with main thread.
+ while (Atomics.notify(controller, 0, 1) < 1) {
+ sleep(amount);
+ }
+ `);
+
+ // Wait until worker is set-up.
+ assertEq(Atomics.wait(controller, 0, 0), "ok");
+
+ // Sort the array in ascending order.
+ ta.sort();
+
+ // Wait until worker has finished.
+ assertEq(Atomics.wait(controller, 0, 0), "ok");
+
+ // All elements have been set to zero.
+ let zero = toNumeric(0);
+ for (let i = 0; i < size; ++i) {
+ assertEq(ta[i], zero, `${TA.name} at index ${i} for size ${size}`);
+ }
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/sort_modifications_concurrent_radixsort.js b/js/src/tests/non262/TypedArray/sort_modifications_concurrent_radixsort.js
new file mode 100644
index 0000000000..c6de0f1ece
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/sort_modifications_concurrent_radixsort.js
@@ -0,0 +1,116 @@
+// |reftest| skip-if(!xulRuntime.shell)
+
+if (helperThreadCount() === 0) {
+ if (typeof reportCompare === "function")
+ reportCompare(true, true);
+ quit();
+}
+
+// TypedArray constructors which can use radix sort.
+const TAConstructors = [
+ Int16Array,
+ Uint16Array,
+ Int32Array,
+ Uint32Array,
+ Float32Array,
+];
+
+// Use a large enough size to ensure concurrent accesses can be detected.
+const size = 0x4000;
+
+function ToAtomicTA(TA) {
+ switch (TA) {
+ case Int16Array:
+ case Int32Array:
+ case Uint16Array:
+ case Uint32Array:
+ return TA;
+ case Float32Array:
+ return Uint32Array;
+ }
+ throw new Error("Invalid typed array kind");
+}
+
+function ascending(a, b) {
+ return a < b ? -1 : a > b ? 1 : 0;
+}
+
+function descending(a, b) {
+ return -ascending(a, b);
+}
+
+for (let TA of TAConstructors) {
+ let sorted = new TA(size);
+
+ // Fill with |1..size| and then sort to account for wrap-arounds.
+ for (let i = 0; i < size; ++i) {
+ sorted[i] = i + 1;
+ }
+ sorted.sort();
+
+ let extra = Math.max(TA.BYTES_PER_ELEMENT, Int32Array.BYTES_PER_ELEMENT);
+ let buffer = new SharedArrayBuffer(size * TA.BYTES_PER_ELEMENT + extra);
+ let controller = new Int32Array(buffer, 0, 1);
+
+ // Create a copy in descending order.
+ let ta = new TA(buffer, extra, size);
+ ta.set(sorted)
+ ta.sort(descending);
+
+ // Worker code expects that the last element changes when sorted.
+ assertEq(ta[size - 1] === sorted[size - 1], false);
+
+ setSharedObject(buffer);
+
+ evalInWorker(`
+ const ToAtomicTA = ${ToAtomicTA};
+ const TA = ${TA.name};
+ const AtomicTA = ToAtomicTA(TA);
+
+ let size = ${size};
+ let extra = ${extra};
+
+ let buffer = getSharedObject();
+ let controller = new Int32Array(buffer, 0, 1);
+ let ta = new AtomicTA(buffer, extra, size);
+
+ let value = Atomics.load(ta, size - 1);
+
+ // Coordinate with main thread.
+ while (Atomics.notify(controller, 0, 1) < 1) ;
+
+ // Wait until modification of the last element.
+ //
+ // Sorting writes in ascending indexed ordered, so when the last element
+ // was modified, we know that the sort operation has finished.
+ while (Atomics.load(ta, size - 1) === value) ;
+
+ // Set all elements to zero.
+ ta.fill(0);
+
+ // Sleep for 50 ms.
+ const amount = 0.05;
+
+ // Coordinate with main thread.
+ while (Atomics.notify(controller, 0, 1) < 1) {
+ sleep(amount);
+ }
+ `);
+
+ // Wait until worker is set-up.
+ assertEq(Atomics.wait(controller, 0, 0), "ok");
+
+ // Sort the array in ascending order.
+ ta.sort();
+
+ // Wait until worker has finished.
+ assertEq(Atomics.wait(controller, 0, 0), "ok");
+
+ // All elements have been set to zero.
+ for (let i = 0; i < size; ++i) {
+ assertEq(ta[i], 0, `${TA.name} at index ${i} for size ${size}`);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/sort_small.js b/js/src/tests/non262/TypedArray/sort_small.js
new file mode 100644
index 0000000000..22f9dc69a6
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/sort_small.js
@@ -0,0 +1,38 @@
+const testCases = {
+ // Pre-sorted test data, it's important that these arrays remain in ascending order.
+ [Int8Array.name]: [[-128, 127]],
+ [Int16Array.name]: [[-32768, -999, 1942, 32767]],
+ [Int32Array.name]: [[-2147483648, -320000, -244000, 2147483647]],
+ [Uint8Array.name]: [[255]],
+ [Uint16Array.name]: [[0, 65535, 65535]],
+ [Uint32Array.name]: [[0, 987632, 4294967295]],
+ [Uint8ClampedArray.name]: [[255]],
+
+ // Test the behavior in the default comparator as described in 22.2.3.26.
+ // The spec boils down to, -0s come before +0s, and NaNs always come last.
+ // Float Arrays are used because all other types convert -0 and NaN to +0.
+ [Float32Array.name]: [
+ [-2147483647, -2147483646.99, -0, 0, 2147483646.99, NaN],
+ [1/undefined, NaN, Number.NaN]
+ ],
+ [Float64Array.name]: [
+ [-2147483646.99, -0, 0, 4147483646.99, NaN],
+ [1/undefined, NaN, Number.NaN]
+ ],
+};
+
+// Sort every possible permutation of an arrays
+function sortAllPermutations(dataType, testData) {
+ let reference = new dataType(testData);
+ for (let permutation of Permutations(testData))
+ assertDeepEq((new dataType(permutation)).sort(), reference);
+}
+
+for (let constructor of sharedTypedArrayConstructors) {
+ for (let data of testCases[constructor.name]) {
+ sortAllPermutations(constructor, data);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/sort_snans.js b/js/src/tests/non262/TypedArray/sort_snans.js
new file mode 100644
index 0000000000..50f99b2205
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/sort_snans.js
@@ -0,0 +1,79 @@
+// Ensure that signaling NaN's don't cause problems while sorting
+
+function getNaNArray(length) {
+ let a = [];
+ for (let i = 0; i < length; i++)
+ a.push(NaN);
+ return a;
+}
+
+// Test every skipNth value in some range n, where start <= n <= end
+// and start/stop should be 32-bit integers with bit patterns that
+// form Float32 NaNs.
+function testFloat32NaNRanges(start, end) {
+ let skipN = 10e3;
+
+ // sample the space of possible NaNs to save time
+ let sampleSize = Math.floor((end - start)/ skipN);
+
+ let NaNArray = new Float32Array(getNaNArray(sampleSize));
+ let buffer = new ArrayBuffer(4 * sampleSize);
+ let uintView = new Uint32Array(buffer);
+ let floatView = new Float32Array(buffer);
+
+ uintView[0] = start;
+ for (let i = 1; i < sampleSize; i++) {
+ uintView[i] = uintView[0] + (i * skipN);
+ }
+
+ floatView.sort();
+ assertDeepEq(floatView, NaNArray);
+}
+
+// Test every skipNth value in some range n, where start <= n <= end
+// and startHi, startLow and endHi, endLow should be 32-bit integers which,
+// when combined (Hi + Low), form Float64 NaNs.
+function testFloat64NaNRanges(startHi, startLow, endHi, endLow) {
+
+ // Swap on big endian platforms
+ if (new Uint32Array(new Uint8Array([1,2,3,4]).buffer)[0] === 0x01020304) {
+ [startHi, startLow] = [startLow, startHi];
+ [endHi, endLow] = [endLow, endHi];
+ }
+
+ let skipN = 10e6;
+
+ let sampleSizeHi = Math.floor((endHi - startHi)/skipN);
+ let sampleSizeLow = Math.floor((endLow - startLow)/skipN);
+
+ let NaNArray = new Float64Array(getNaNArray(sampleSizeHi + sampleSizeLow));
+ let buffer = new ArrayBuffer(8 * (sampleSizeHi + sampleSizeLow));
+ let uintView = new Uint32Array(buffer);
+ let floatView = new Float64Array(buffer);
+
+ // Fill in all of the low bits first.
+ for (let i = 0; i <= sampleSizeLow; i++) {
+ uintView[i * 2] = startLow + (i * skipN);
+ uintView[(i * 2) + 1] = startHi;
+ }
+
+ // Then the high bits.
+ for (let i = sampleSizeLow; i <= sampleSizeLow + sampleSizeHi; i++) {
+ uintView[i * 2] = endLow;
+ uintView[(i * 2) + 1] = startHi + ((i - sampleSizeLow) * skipN);
+ }
+
+ floatView.sort();
+ assertDeepEq(floatView, NaNArray);
+}
+
+// Float32 Signaling NaN ranges
+testFloat32NaNRanges(0x7F800001, 0x7FBFFFFF);
+testFloat32NaNRanges(0xFF800001, 0xFFBFFFFF);
+
+// Float64 Signaling NaN ranges
+testFloat64NaNRanges(0x7FF00000, 0x00000001, 0x7FF7FFFF, 0xFFFFFFFF);
+testFloat64NaNRanges(0xFFF00000, 0x00000001, 0xFFF7FFFF, 0xFFFFFFFF);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/sort_sorted.js b/js/src/tests/non262/TypedArray/sort_sorted.js
new file mode 100644
index 0000000000..cb55ec3399
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/sort_sorted.js
@@ -0,0 +1,30 @@
+function SortedAscending(length) {
+ var array = new Int32Array(length);
+ for (var i = 0; i < length; ++i)
+ array[i] = i + 1;
+
+ array.sort((x, y) => x - y);
+
+ for (var i = 0; i < length; ++i)
+ assertEq(i + 1, array[i], `Mismatch at index=${i}, length=${length}`);
+}
+
+for (var i = 0; i < 256; ++i)
+ SortedAscending(i);
+
+function SortedDescending(length) {
+ var array = new Int32Array(length);
+ for (var i = 0; i < length; ++i)
+ array[i] = length - i;
+
+ array.sort((x, y) => x - y);
+
+ for (var i = 0; i < length; ++i)
+ assertEq(i + 1, array[i], `Mismatch at index=${i}, length=${length}`);
+}
+
+for (var i = 0; i < 256; ++i)
+ SortedDescending(i);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/sort_stable.js b/js/src/tests/non262/TypedArray/sort_stable.js
new file mode 100644
index 0000000000..d945e774c1
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/sort_stable.js
@@ -0,0 +1,23 @@
+// Test with different lengths to cover the case when InsertionSort is resp.
+// is not called.
+for (let i = 2; i <= 10; ++i) {
+ let length = 2 ** i;
+ let ta = new Int8Array(length);
+
+ ta[0] = 2;
+ ta[1] = 1;
+ ta[2] = 0;
+
+ for (let i = 3; i < length; ++i) {
+ ta[i] = 4;
+ }
+
+ ta.sort((a, b) => (a/4|0) - (b/4|0));
+
+ assertEq(ta[0], 2);
+ assertEq(ta[1], 1);
+ assertEq(ta[2], 0);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/sorting_buffer_access.js b/js/src/tests/non262/TypedArray/sorting_buffer_access.js
new file mode 100644
index 0000000000..c31f4ca167
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/sorting_buffer_access.js
@@ -0,0 +1,15 @@
+// Ensure that when sorting arrays of size greater than 128, which
+// calls RadixSort under the hood, we don't access the 'buffer'
+// property of the typed array directly.
+
+
+// The buggy behavior in the RadixSort is only exposed when we use
+// float arrays, but checking everything just to be sure.
+for (var ctor of anyTypedArrayConstructors) {
+ var testArray = new ctor(1024);
+ Object.defineProperty(testArray, "buffer", { get() { throw new Error("FAIL: Buffer accessed directly"); } });
+ testArray.sort();
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/subarray-species.js b/js/src/tests/non262/TypedArray/subarray-species.js
new file mode 100644
index 0000000000..91c34e80cc
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/subarray-species.js
@@ -0,0 +1,63 @@
+function test(constructor, constructor2, from=[1, 2, 3, 4, 5], to=[3, 4], begin=2, end=4) {
+ var modifiedConstructor = new constructor(from);
+ modifiedConstructor.constructor = constructor2;
+ assertDeepEq(modifiedConstructor.subarray(begin, end), new constructor2(to));
+ var modifiedSpecies = new constructor(from);
+ modifiedSpecies.constructor = { [Symbol.species]: constructor2 };
+ assertDeepEq(modifiedSpecies.subarray(begin, end), new constructor2(to));
+}
+
+// same size, same sign
+
+test(Int8Array, Uint8Array);
+test(Int8Array, Uint8ClampedArray);
+
+test(Uint8Array, Int8Array);
+test(Uint8Array, Uint8ClampedArray);
+
+test(Uint8ClampedArray, Int8Array);
+test(Uint8ClampedArray, Uint8Array);
+
+test(Int16Array, Uint16Array);
+test(Uint16Array, Int16Array);
+
+test(Int32Array, Uint32Array);
+test(Uint32Array, Int32Array);
+
+// same size, different sign
+
+test(Int8Array, Uint8Array, [-1, -2, -3, -4, -5], [0xFD, 0xFC]);
+test(Int8Array, Uint8ClampedArray, [-1, -2, -3, -4, -5], [0xFD, 0xFC]);
+
+test(Uint8Array, Int8Array, [0xFF, 0xFE, 0xFD, 0xFC, 0xFB], [-3, -4]);
+test(Uint8ClampedArray, Int8Array, [0xFF, 0xFE, 0xFD, 0xFC, 0xFB], [-3, -4]);
+
+test(Int16Array, Uint16Array, [-1, -2, -3, -4, -5], [0xFFFD, 0xFFFC]);
+test(Uint16Array, Int16Array, [0xFFFF, 0xFFFE, 0xFFFD, 0xFFFC, 0xFFFB], [-3, -4]);
+
+test(Int32Array, Uint32Array, [-1, -2, -3, -4, -5], [0xFFFFFFFD, 0xFFFFFFFC]);
+test(Uint32Array, Int32Array, [0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFC, 0xFFFFFFFB], [-3, -4]);
+
+// different size
+
+// To avoid handling endian, use ArrayBuffer as an argument.
+var a = new Int8Array([0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
+ 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01,
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+ 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x0F]);
+
+test(Uint8Array, Uint16Array, a.buffer, a.slice(2, 6).buffer);
+test(Uint16Array, Uint8Array, a.buffer, a.slice(4, 6).buffer);
+
+test(Uint8Array, Uint32Array, a.buffer, a.slice(4, 12).buffer, 4, 6);
+test(Uint32Array, Uint8Array, a.buffer, a.slice(8, 10).buffer);
+
+test(Uint16Array, Uint32Array, a.buffer, a.slice(4, 12).buffer);
+test(Uint32Array, Uint16Array, a.buffer, a.slice(8, 12).buffer);
+
+test(Float32Array, Float64Array, a.buffer, a.slice(8, 24).buffer);
+test(Float64Array, Float32Array, a.buffer, a.slice(16, 24).buffer);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
diff --git a/js/src/tests/non262/TypedArray/subarray-validation.js b/js/src/tests/non262/TypedArray/subarray-validation.js
new file mode 100644
index 0000000000..4ad8c86095
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/subarray-validation.js
@@ -0,0 +1,117 @@
+/* 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/. */
+
+// Summary: Ensure typed array validation is called for TypedArray.prototype.subarray.
+
+const otherGlobal = newGlobal({newCompartment: true});
+const typedArrayLengths = [0, 1, 1024];
+
+// Note: subarray uses CallTypedArrayMethodIfWrapped, which results in throwing
+// a TypeError from the wrong Realm if cross-compartment. The browser
+// runner doesn't support the "newCompartment" option, so it can't create
+// cross-compartment globals, which means it throws the error from the
+// correct Realm.
+const eitherGlobalTypeError = {
+ [Symbol.hasInstance](obj) {
+ return obj instanceof TypeError || obj instanceof otherGlobal.TypeError;
+ }
+};
+
+function createTestCases(TAConstructor, constructor, constructorCrossRealm) {
+ let testCases = [];
+ testCases.push({
+ species: constructor,
+ method: TAConstructor.prototype.subarray,
+ error: TypeError,
+ });
+ testCases.push({
+ species: constructorCrossRealm,
+ method: TAConstructor.prototype.subarray,
+ error: TypeError,
+ });
+ testCases.push({
+ species: constructor,
+ method: otherGlobal[TAConstructor.name].prototype.subarray,
+ error: eitherGlobalTypeError,
+ });
+ return testCases;
+}
+
+// Throws TypeError when the returned value is not a typed array.
+for (const TAConstructor of anyTypedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function NoTypedArrayConstructor(...args) {
+ let a = [];
+ callCount += 1;
+ return a;
+ }
+ function NoTypedArrayConstructorCrossRealm(...args) {
+ let a = new otherGlobal.Array();
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, NoTypedArrayConstructor, NoTypedArrayConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ assertThrowsInstanceOf(() => method.call(ta, 0), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ assertThrowsInstanceOf(() => method.call(ta, 0, 0), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+}
+
+// Throws TypeError exception when returned array is detached.
+if (typeof detachArrayBuffer === "function") {
+ for (const TAConstructor of typedArrayConstructors) {
+ let callCount = 0, expectedCallCount = 0;
+ function DetachConstructor(...args) {
+ let a = new TAConstructor(...args);
+ detachArrayBuffer(a.buffer);
+ callCount += 1;
+ return a;
+ }
+ function DetachConstructorCrossRealm(...args) {
+ let a = new otherGlobal[TAConstructor.name](...args);
+ // Note: TypedArray |a| is (currently) created in this global, not
+ // |otherGlobal|, because a typed array and its buffer must
+ // use the same compartment.
+ detachArrayBuffer(a.buffer);
+ callCount += 1;
+ return a;
+ }
+ let testCases = createTestCases(TAConstructor, DetachConstructor, DetachConstructorCrossRealm);
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ assertThrowsInstanceOf(() => method.call(ta, 0), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+
+ for (let {species, method, error} of testCases) {
+ for (let length of typedArrayLengths) {
+ let ta = new TAConstructor(length);
+ ta.constructor = {[Symbol.species]: species};
+ assertThrowsInstanceOf(() => method.call(ta, 0, 0), error);
+ assertEq(callCount, ++expectedCallCount);
+ }
+ }
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/TypedArray/subarray.js b/js/src/tests/non262/TypedArray/subarray.js
new file mode 100644
index 0000000000..a7bfab0efd
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/subarray.js
@@ -0,0 +1,29 @@
+// Bug 1291003
+if (typeof detachArrayBuffer === "function") {
+ for (let constructor of typedArrayConstructors) {
+ const elementSize = constructor.BYTES_PER_ELEMENT;
+
+ let targetOffset;
+ let buffer = new ArrayBuffer(2 * elementSize);
+ let typedArray = new constructor(buffer, 1 * elementSize, 1);
+ typedArray.constructor = {
+ [Symbol.species]: function(ab, offset, length) {
+ targetOffset = offset;
+ return new constructor(1);
+ }
+ };
+
+ let beginIndex = {
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return 0;
+ }
+ };
+ typedArray.subarray(beginIndex);
+
+ assertEq(targetOffset, 1 * elementSize);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/test-integrity-level-detached.js b/js/src/tests/non262/TypedArray/test-integrity-level-detached.js
new file mode 100644
index 0000000000..68f772de61
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/test-integrity-level-detached.js
@@ -0,0 +1,104 @@
+const EMPTY = 0;
+const INLINE_STORAGE = 10;
+const NON_INLINE_STORAGE = 1024;
+
+class DetachedInt32Array extends Int32Array {
+ constructor(...args) {
+ super(...args);
+ detachArrayBuffer(this.buffer);
+ }
+}
+
+function throwsTypeError(fn) {
+ try {
+ fn();
+ } catch (e) {
+ assertEq(e instanceof TypeError, true);
+ return true;
+ }
+ return false;
+}
+
+// Non-standard: Accessing elements of detached array buffers should throw, but
+// this is currently not implemented.
+const ACCESS_ON_DETACHED_ARRAY_BUFFER_THROWS = (() => {
+ let ta = new DetachedInt32Array(10);
+ let throws = throwsTypeError(() => ta[0]);
+ // Ensure [[Get]] and [[GetOwnProperty]] return consistent results.
+ assertEq(throwsTypeError(() => Object.getOwnPropertyDescriptor(ta, 0)), throws);
+ return throws;
+})();
+
+function maybeThrowOnDetached(fn, returnValue) {
+ if (ACCESS_ON_DETACHED_ARRAY_BUFFER_THROWS) {
+ assertThrowsInstanceOf(fn, TypeError);
+ return returnValue;
+ }
+ return fn();
+}
+
+// Empty typed arrays can be sealed.
+{
+ let ta = new DetachedInt32Array(EMPTY);
+ Object.seal(ta);
+
+ assertEq(Object.isExtensible(ta), false);
+ assertEq(Object.isSealed(ta), true);
+ assertEq(Object.isFrozen(ta), true);
+}
+
+// Non-empty typed arrays can be sealed, but calling TestIntegrityLevel will
+// throw on detached typed arrays.
+for (let length of [INLINE_STORAGE, NON_INLINE_STORAGE]) {
+ let ta = new DetachedInt32Array(length);
+ Object.seal(ta);
+
+ assertEq(Object.isExtensible(ta), false);
+ assertEq(maybeThrowOnDetached(() => Object.isSealed(ta), true), true);
+ assertEq(maybeThrowOnDetached(() => Object.isFrozen(ta), true), true);
+}
+
+// Empty typed arrays can be frozen.
+{
+ let ta = new DetachedInt32Array(EMPTY);
+ Object.freeze(ta);
+
+ assertEq(Object.isExtensible(ta), false);
+ assertEq(Object.isSealed(ta), true);
+ assertEq(Object.isFrozen(ta), true);
+}
+
+// Non-empty typed arrays cannot be frozen.
+for (let length of [INLINE_STORAGE, NON_INLINE_STORAGE]) {
+ let ta = new DetachedInt32Array(length);
+ maybeThrowOnDetached(() => Object.freeze(ta));
+
+ assertEq(Object.isExtensible(ta), false);
+ assertEq(maybeThrowOnDetached(() => Object.isSealed(ta), true), true);
+ assertEq(maybeThrowOnDetached(() => Object.isFrozen(ta), true), true);
+}
+
+// Non-extensible empty typed arrays are sealed and frozen.
+{
+ let ta = new DetachedInt32Array(EMPTY);
+ Object.preventExtensions(ta);
+
+ assertEq(Object.isExtensible(ta), false);
+ assertEq(Object.isSealed(ta), true);
+ assertEq(Object.isFrozen(ta), true);
+}
+
+// Calling TestIntegrityLevel will throw on detached typed arrays with non-zero
+// length.
+for (let length of [INLINE_STORAGE, NON_INLINE_STORAGE]) {
+ let ta = new DetachedInt32Array(length);
+ Object.preventExtensions(ta);
+
+ assertEq(Object.isExtensible(ta), false);
+ assertEq(maybeThrowOnDetached(() => Object.isSealed(ta), true), true);
+ assertEq(maybeThrowOnDetached(() => Object.isFrozen(ta), true), true);
+}
+
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/test-integrity-level.js b/js/src/tests/non262/TypedArray/test-integrity-level.js
new file mode 100644
index 0000000000..c382b4967c
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/test-integrity-level.js
@@ -0,0 +1,67 @@
+const EMPTY = 0;
+const INLINE_STORAGE = 10;
+const NON_INLINE_STORAGE = 1024;
+
+// Empty typed arrays can be sealed.
+{
+ let ta = new Int32Array(EMPTY);
+ Object.seal(ta);
+
+ assertEq(Object.isExtensible(ta), false);
+ assertEq(Object.isSealed(ta), true);
+ assertEq(Object.isFrozen(ta), true);
+}
+
+// Non-empty typed arrays cannot be sealed.
+for (let length of [INLINE_STORAGE, NON_INLINE_STORAGE]) {
+ let ta = new Int32Array(length);
+ assertThrowsInstanceOf(() => Object.seal(ta), TypeError);
+
+ assertEq(Object.isExtensible(ta), false);
+ assertEq(Object.isSealed(ta), false);
+ assertEq(Object.isFrozen(ta), false);
+}
+
+// Empty typed arrays can be frozen.
+{
+ let ta = new Int32Array(EMPTY);
+ Object.freeze(ta);
+
+ assertEq(Object.isExtensible(ta), false);
+ assertEq(Object.isSealed(ta), true);
+ assertEq(Object.isFrozen(ta), true);
+}
+
+// Non-empty typed arrays cannot be frozen.
+for (let length of [INLINE_STORAGE, NON_INLINE_STORAGE]) {
+ let ta = new Int32Array(length);
+ assertThrowsInstanceOf(() => Object.freeze(ta), TypeError);
+
+ assertEq(Object.isExtensible(ta), false);
+ assertEq(Object.isSealed(ta), false);
+ assertEq(Object.isFrozen(ta), false);
+}
+
+// Non-extensible empty typed arrays are sealed and frozen.
+{
+ let ta = new Int32Array(EMPTY);
+ Object.preventExtensions(ta);
+
+ assertEq(Object.isExtensible(ta), false);
+ assertEq(Object.isSealed(ta), true);
+ assertEq(Object.isFrozen(ta), true);
+}
+
+// Non-extensible non-empty typed arrays are neither sealed nor frozen.
+for (let length of [INLINE_STORAGE, NON_INLINE_STORAGE]) {
+ let ta = new Int32Array(length);
+ Object.preventExtensions(ta);
+
+ assertEq(Object.isExtensible(ta), false);
+ assertEq(Object.isSealed(ta), false);
+ assertEq(Object.isFrozen(ta), false);
+}
+
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/toLocaleString-detached.js b/js/src/tests/non262/TypedArray/toLocaleString-detached.js
new file mode 100644
index 0000000000..fe95ae689c
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/toLocaleString-detached.js
@@ -0,0 +1,38 @@
+if (typeof detachArrayBuffer === "function") {
+ const originalNumberToLocaleString = Number.prototype.toLocaleString;
+
+ // Throws if array buffer is detached.
+ for (let constructor of typedArrayConstructors) {
+ let typedArray = new constructor(42);
+ detachArrayBuffer(typedArray.buffer);
+ assertThrowsInstanceOf(() => typedArray.toLocaleString(), TypeError);
+ }
+
+ // Throws a TypeError if detached in Number.prototype.toLocaleString.
+ for (let constructor of typedArrayConstructors) {
+ Number.prototype.toLocaleString = function() {
+ "use strict";
+ if (!detached) {
+ detachArrayBuffer(typedArray.buffer);
+ detached = true;
+ }
+ return this;
+ };
+
+ // No error for single element arrays.
+ let detached = false;
+ let typedArray = new constructor(1);
+ assertEq(typedArray.toLocaleString(), "0");
+ assertEq(detached, true);
+
+ // TypeError if more than one element is present.
+ detached = false;
+ typedArray = new constructor(2);
+ assertThrowsInstanceOf(() => typedArray.toLocaleString(), TypeError);
+ assertEq(detached, true);
+ }
+ Number.prototype.toLocaleString = originalNumberToLocaleString;
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/toLocaleString-nointl.js b/js/src/tests/non262/TypedArray/toLocaleString-nointl.js
new file mode 100644
index 0000000000..f2870efbe6
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/toLocaleString-nointl.js
@@ -0,0 +1,40 @@
+if (typeof Intl !== "object") {
+ const localeSep = [,,].toLocaleString();
+
+ const originalNumberToLocaleString = Number.prototype.toLocaleString;
+
+ // Ensure no arguments are passed to the array elements.
+ for (let constructor of anyTypedArrayConstructors) {
+ Number.prototype.toLocaleString = function() {
+ assertEq(arguments.length, 0);
+ return "pass";
+ };
+
+ // Single element case.
+ assertEq(new constructor(1).toLocaleString(), "pass");
+
+ // More than one element.
+ assertEq(new constructor(2).toLocaleString(), "pass" + localeSep + "pass");
+ }
+ Number.prototype.toLocaleString = originalNumberToLocaleString;
+
+ // Ensure no arguments are passed to the array elements even if supplied.
+ for (let constructor of anyTypedArrayConstructors) {
+ Number.prototype.toLocaleString = function() {
+ assertEq(arguments.length, 0);
+ return "pass";
+ };
+ let locales = {};
+ let options = {};
+
+ // Single element case.
+ assertEq(new constructor(1).toLocaleString(locales, options), "pass");
+
+ // More than one element.
+ assertEq(new constructor(2).toLocaleString(locales, options), "pass" + localeSep + "pass");
+ }
+ Number.prototype.toLocaleString = originalNumberToLocaleString;
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/toLocaleString.js b/js/src/tests/non262/TypedArray/toLocaleString.js
new file mode 100644
index 0000000000..78049ec225
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/toLocaleString.js
@@ -0,0 +1,80 @@
+const TypedArrayPrototype = Object.getPrototypeOf(Int8Array.prototype);
+
+// %TypedArrayPrototype% has an own "toLocaleString" function property.
+assertEq(TypedArrayPrototype.hasOwnProperty("toLocaleString"), true);
+assertEq(typeof TypedArrayPrototype.toLocaleString, "function");
+
+// The initial value of %TypedArrayPrototype%.toLocaleString is not Array.prototype.toLocaleString.
+assertEq(TypedArrayPrototype.toLocaleString === Array.prototype.toLocaleString, false);
+
+// The concrete TypedArray prototypes do not have an own "toLocaleString" property.
+assertEq(anyTypedArrayConstructors.every(c => !c.hasOwnProperty("toLocaleString")), true);
+
+assertDeepEq(Object.getOwnPropertyDescriptor(TypedArrayPrototype, "toLocaleString"), {
+ value: TypedArrayPrototype.toLocaleString,
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+assertEq(TypedArrayPrototype.toLocaleString.name, "toLocaleString");
+assertEq(TypedArrayPrototype.toLocaleString.length, 0);
+
+// It's not a generic method.
+assertThrowsInstanceOf(() => TypedArrayPrototype.toLocaleString.call(), TypeError);
+for (let invalid of [void 0, null, {}, [], function(){}, true, 0, "", Symbol()]) {
+ assertThrowsInstanceOf(() => TypedArrayPrototype.toLocaleString.call(invalid), TypeError);
+}
+
+const localeOne = 1..toLocaleString(),
+ localeTwo = 2..toLocaleString(),
+ localeSep = [,,].toLocaleString();
+
+for (let constructor of anyTypedArrayConstructors) {
+ assertEq(new constructor([]).toLocaleString(), "");
+ assertEq(new constructor([1]).toLocaleString(), localeOne);
+ assertEq(new constructor([1, 2]).toLocaleString(), localeOne + localeSep + localeTwo);
+}
+
+const originalNumberToLocaleString = Number.prototype.toLocaleString;
+
+// Calls Number.prototype.toLocaleString on each element.
+for (let constructor of anyTypedArrayConstructors) {
+ Number.prototype.toLocaleString = function() {
+ "use strict";
+
+ // Ensure this-value is not boxed.
+ assertEq(typeof this, "number");
+
+ // Test ToString is applied.
+ return {
+ valueOf: () => {
+ throw new Error("valueOf called");
+ },
+ toString: () => {
+ return this + 10;
+ }
+ };
+ };
+ let typedArray = new constructor([1, 2]);
+ assertEq(typedArray.toLocaleString(), "11" + localeSep + "12");
+}
+Number.prototype.toLocaleString = originalNumberToLocaleString;
+
+// Calls Number.prototype.toLocaleString from the current Realm.
+const otherGlobal = newGlobal();
+for (let constructor of anyTypedArrayConstructors) {
+ Number.prototype.toLocaleString = function() {
+ "use strict";
+ called = true;
+ return this;
+ };
+ let typedArray = new otherGlobal[constructor.name]([1]);
+ let called = false;
+ assertEq(TypedArrayPrototype.toLocaleString.call(typedArray), "1");
+ assertEq(called, true);
+}
+Number.prototype.toLocaleString = originalNumberToLocaleString;
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/toReversed-detached.js b/js/src/tests/non262/TypedArray/toReversed-detached.js
new file mode 100644
index 0000000000..ae2a784180
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/toReversed-detached.js
@@ -0,0 +1,10 @@
+// |reftest| shell-option(--enable-change-array-by-copy) skip-if(!Int32Array.prototype.toReversed)
+
+var ta = new Int32Array([3, 2, 1]);
+
+detachArrayBuffer(ta.buffer);
+
+assertThrowsInstanceOf(() => ta.toReversed(), TypeError);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/TypedArray/toSorted-detached.js b/js/src/tests/non262/TypedArray/toSorted-detached.js
new file mode 100644
index 0000000000..a4c5ba2252
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/toSorted-detached.js
@@ -0,0 +1,10 @@
+// |reftest| shell-option(--enable-change-array-by-copy) skip-if(!Int32Array.prototype.toSorted)
+
+var ta = new Int32Array([3, 2, 1]);
+
+detachArrayBuffer(ta.buffer);
+
+assertThrowsInstanceOf(() => ta.toSorted(), TypeError);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/TypedArray/toString.js b/js/src/tests/non262/TypedArray/toString.js
new file mode 100644
index 0000000000..0879b8b31d
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/toString.js
@@ -0,0 +1,69 @@
+const TypedArrayPrototype = Object.getPrototypeOf(Int8Array.prototype);
+
+// %TypedArrayPrototype% has an own "toString" property.
+assertEq(TypedArrayPrototype.hasOwnProperty("toString"), true);
+
+// The initial value of %TypedArrayPrototype%.toString is Array.prototype.toString.
+assertEq(TypedArrayPrototype.toString, Array.prototype.toString);
+
+// The concrete TypedArray prototypes do not have an own "toString" property.
+assertEq(anyTypedArrayConstructors.every(c => !c.hasOwnProperty("toString")), true);
+
+assertDeepEq(Object.getOwnPropertyDescriptor(TypedArrayPrototype, "toString"), {
+ value: TypedArrayPrototype.toString,
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+for (let constructor of anyTypedArrayConstructors) {
+ assertEq(new constructor([]).toString(), "");
+ assertEq(new constructor([1]).toString(), "1");
+ assertEq(new constructor([1, 2]).toString(), "1,2");
+}
+
+const testCases = {
+ [Int8Array.name]: {
+ array: [-1, 2, -3, 4, NaN],
+ expected: "-1,2,-3,4,0",
+ },
+ [Int16Array.name]: {
+ array: [-1, 2, -3, 4, NaN],
+ expected: "-1,2,-3,4,0",
+ },
+ [Int32Array.name]: {
+ array: [-1, 2, -3, 4, NaN],
+ expected: "-1,2,-3,4,0",
+ },
+ [Uint8Array.name]: {
+ array: [255, 2, 3, 4, NaN],
+ expected: "255,2,3,4,0",
+ },
+ [Uint16Array.name]: {
+ array: [-1, 2, 3, 4, NaN],
+ expected: "65535,2,3,4,0",
+ },
+ [Uint32Array.name]: {
+ array: [-1, 2, 3, 4, NaN],
+ expected: "4294967295,2,3,4,0",
+ },
+ [Uint8ClampedArray.name]: {
+ array: [255, 256, 2, 3, 4, NaN],
+ expected: "255,255,2,3,4,0",
+ },
+ [Float32Array.name]: {
+ array: [-0, 0, 0.5, -0.5, NaN, Infinity, -Infinity],
+ expected: "0,0,0.5,-0.5,NaN,Infinity,-Infinity",
+ },
+ [Float64Array.name]: {
+ array: [-0, 0, 0.5, -0.5, NaN, Infinity, -Infinity],
+ expected: "0,0,0.5,-0.5,NaN,Infinity,-Infinity",
+ },
+};
+for (let constructor of anyTypedArrayConstructors) {
+ let {array, expected} = testCases[constructor.name];
+ assertEq(new constructor(array).toString(), expected);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/toStringTag-cross-compartment.js b/js/src/tests/non262/TypedArray/toStringTag-cross-compartment.js
new file mode 100644
index 0000000000..8f0875721c
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/toStringTag-cross-compartment.js
@@ -0,0 +1,12 @@
+const TypedArrayPrototype = Object.getPrototypeOf(Int8Array.prototype);
+const {get: toStringTag} = Object.getOwnPropertyDescriptor(TypedArrayPrototype, Symbol.toStringTag);
+
+const otherGlobal = newGlobal();
+
+for (let constructor of anyTypedArrayConstructors) {
+ let ta = new otherGlobal[constructor.name](0);
+ assertEq(toStringTag.call(ta), constructor.name);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/uint8clamped-constructor.js b/js/src/tests/non262/TypedArray/uint8clamped-constructor.js
new file mode 100644
index 0000000000..3eefe70f1f
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/uint8clamped-constructor.js
@@ -0,0 +1,9 @@
+for (var v of [-300, 255.6, 300, 3.5, -3.9]) {
+ var a = new Uint8ClampedArray([v]);
+ var b = new Uint8ClampedArray(1);
+ b[0] = v;
+
+ assertEq(a[0], b[0]);
+}
+
+reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/values.js b/js/src/tests/non262/TypedArray/values.js
new file mode 100644
index 0000000000..bf486bfa0a
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/values.js
@@ -0,0 +1,37 @@
+for (var constructor of anyTypedArrayConstructors) {
+ assertEq(constructor.prototype.values.length, 0);
+ assertEq(constructor.prototype.values.name, "values");
+ assertEq(constructor.prototype.values, constructor.prototype[Symbol.iterator]);
+
+ assertDeepEq([...new constructor(0).values()], []);
+ assertDeepEq([...new constructor(1).values()], [0]);
+ assertDeepEq([...new constructor(2).values()], [0, 0]);
+ assertDeepEq([...new constructor([15]).values()], [15]);
+
+ var arr = new constructor([1, 2, 3]);
+ var iterator = arr.values();
+ assertDeepEq(iterator.next(), {value: 1, done: false});
+ assertDeepEq(iterator.next(), {value: 2, done: false});
+ assertDeepEq(iterator.next(), {value: 3, done: false});
+ assertDeepEq(iterator.next(), {value: undefined, done: true});
+
+ // Called from other globals.
+ if (typeof newGlobal === "function") {
+ var values = newGlobal()[constructor.name].prototype.values;
+ assertDeepEq([...values.call(new constructor([42, 36]))], [42, 36]);
+ arr = new (newGlobal()[constructor.name])([42, 36]);
+ assertEq([...constructor.prototype.values.call(arr)].toString(), "42,36");
+ }
+
+ // Throws if `this` isn't a TypedArray.
+ var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
+ new Proxy(new constructor(), {})];
+ invalidReceivers.forEach(invalidReceiver => {
+ assertThrowsInstanceOf(() => {
+ constructor.prototype.values.call(invalidReceiver);
+ }, TypeError, "Assert that values fails if this value is not a TypedArray");
+ });
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/TypedArray/with-detached.js b/js/src/tests/non262/TypedArray/with-detached.js
new file mode 100644
index 0000000000..76711a0ee5
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/with-detached.js
@@ -0,0 +1,10 @@
+// |reftest| shell-option(--enable-change-array-by-copy) skip-if(!Int32Array.prototype.with)
+
+var ta = new Int32Array([3, 2, 1]);
+
+detachArrayBuffer(ta.buffer);
+
+assertThrowsInstanceOf(() => ta.with(0, 0), TypeError);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/TypedArray/with.js b/js/src/tests/non262/TypedArray/with.js
new file mode 100644
index 0000000000..c240f7084e
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/with.js
@@ -0,0 +1,34 @@
+// |reftest| shell-option(--enable-change-array-by-copy) skip-if(!Int32Array.prototype.with)
+
+class Err {}
+
+const indices = [
+ -Infinity, -10, -0.5, -0, 0, 0.5, 10, Infinity, NaN
+];
+
+let value = {
+ valueOf() {
+ throw new Err;
+ }
+};
+
+let ta = new Int32Array(5);
+for (let index of indices) {
+ assertThrowsInstanceOf(() => ta.with(index, value), Err);
+}
+
+for (let index of indices) {
+ let ta = new Int32Array(5);
+
+ let value = {
+ valueOf() {
+ detachArrayBuffer(ta.buffer);
+ return 0;
+ }
+ };
+
+ assertThrowsInstanceOf(() => ta.with(index, value), RangeError);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/TypedArray/write-out-of-bounds-tonumber.js b/js/src/tests/non262/TypedArray/write-out-of-bounds-tonumber.js
new file mode 100644
index 0000000000..48a538eab7
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/write-out-of-bounds-tonumber.js
@@ -0,0 +1,60 @@
+// ToNumber(value) is executed for OOB writes when using a direct assignment.
+function plainSet() {
+ var callCount = 0;
+ var value = {
+ valueOf() {
+ callCount++;
+ return 1;
+ }
+ };
+
+ var N = 100;
+ var ta = new Int32Array(0);
+ for (var i = 0; i < N; ++i)
+ ta[0] = value
+
+ assertEq(callCount, N);
+}
+for (var i = 0; i < 2; ++i) plainSet();
+
+// ToNumber(value) is executed for OOB writes when using Reflect.set(...).
+function reflectSet() {
+ var callCount = 0;
+ var value = {
+ valueOf() {
+ callCount++;
+ return 1;
+ }
+ };
+
+ var N = 100;
+ var ta = new Int32Array(0);
+ for (var i = 0; i < N; ++i)
+ assertEq(Reflect.set(ta, 0, value), true);
+
+ assertEq(callCount, N);
+}
+for (var i = 0; i < 2; ++i) reflectSet();
+
+// ToNumber(value) is not executed for OOB writes when using Reflect.defineProperty(...).
+function defineProp() {
+ var callCount = 0;
+ var value = {
+ valueOf() {
+ callCount++;
+ return 1;
+ }
+ };
+ var desc = {value, writable: true, enumerable: true, configurable: true};
+
+ var N = 100;
+ var ta = new Int32Array(0);
+ for (var i = 0; i < N; ++i)
+ assertEq(Reflect.defineProperty(ta, 0, desc), false);
+
+ assertEq(callCount, 0);
+}
+for (var i = 0; i < 2; ++i) defineProp();
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);