summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/large-arraybuffers
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/large-arraybuffers')
-rw-r--r--js/src/jit-test/tests/large-arraybuffers/address-offset-overflow.js94
-rw-r--r--js/src/jit-test/tests/large-arraybuffers/arraybuffer-transfer.js64
-rw-r--r--js/src/jit-test/tests/large-arraybuffers/atomics.js57
-rw-r--r--js/src/jit-test/tests/large-arraybuffers/basic.js50
-rw-r--r--js/src/jit-test/tests/large-arraybuffers/directives.txt1
-rw-r--r--js/src/jit-test/tests/large-arraybuffers/jit-alloc-big.js23
-rw-r--r--js/src/jit-test/tests/large-arraybuffers/jit-bounds-checks.js117
-rw-r--r--js/src/jit-test/tests/large-arraybuffers/large-lengths-offsets.js73
-rw-r--r--js/src/jit-test/tests/large-arraybuffers/max-typed-array-size.js19
-rw-r--r--js/src/jit-test/tests/large-arraybuffers/shared-array-buffer.js40
-rw-r--r--js/src/jit-test/tests/large-arraybuffers/structured-clone.js74
-rw-r--r--js/src/jit-test/tests/large-arraybuffers/typed-array.js203
12 files changed, 815 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/large-arraybuffers/address-offset-overflow.js b/js/src/jit-test/tests/large-arraybuffers/address-offset-overflow.js
new file mode 100644
index 0000000000..02914237d9
--- /dev/null
+++ b/js/src/jit-test/tests/large-arraybuffers/address-offset-overflow.js
@@ -0,0 +1,94 @@
+// |jit-test| test-also=--spectre-mitigations=off
+
+// Ensure |index * ByteSize| overflowing int32_t is handled correctly in the
+// backend.
+
+const ab = new ArrayBuffer(7 * 1024 * 1024 * 1024);
+
+function testInt16() {
+ var ta = new Int16Array(ab);
+ for (var i = 0; i < 2000; i++) {
+ var idx = 1073741824; // 2147483648 / 2, offset doesn't fit in int32_t.
+ assertEq(ta[idx], i);
+ ++ta[idx];
+
+ idx = 1073741823; // Largest offset that fits in int32_t.
+ assertEq(ta[idx], i * 2);
+ ta[idx] += 2;
+ }
+ ta[1073741823] = 0;
+ ta[1073741824] = 0;
+}
+testInt16();
+
+function testInt32() {
+ var ta = new Int32Array(ab);
+ for (var i = 0; i < 2000; i++) {
+ var idx = 536870912; // 2147483648 / 4, offset doesn't fit in int32_t.
+ assertEq(ta[idx], i);
+ ++ta[idx];
+
+ idx = 536870911; // Largest offset that fits in int32_t.
+ assertEq(ta[idx], i * 2);
+ ta[idx] += 2;
+ }
+ ta[536870911] = 0;
+ ta[536870912] = 0;
+}
+testInt32();
+
+function testFloat64() {
+ var ta = new Float64Array(ab);
+ for (var i = 0; i < 2000; i++) {
+ var idx = 268435456; // 2147483648 / 8
+ assertEq(ta[idx], i);
+ ++ta[idx];
+
+ idx = 268435455; // Largest offset that fits in int32_t.
+ assertEq(ta[idx], i * 2);
+ ta[idx] += 2;
+ }
+ ta[268435455] = 0;
+ ta[268435456] = 0;
+}
+testFloat64();
+
+function testBigInt() {
+ var ta = new BigInt64Array(ab);
+ for (var i = 0; i < 2000; i++) {
+ var idx = 268435456; // 2147483648 / 8
+ assertEq(ta[idx], BigInt(i));
+ ++ta[idx];
+
+ idx = 268435455; // Largest offset that fits in int32_t.
+ assertEq(ta[idx], BigInt(i * 2));
+ ta[idx] += 2n;
+ }
+ ta[268435455] = 0n;
+ ta[268435456] = 0n;
+}
+testBigInt();
+
+function testInt16Atomics() {
+ var ta = new Int16Array(ab);
+ for (var i = 0; i < 2000; i++) {
+ var idx = 1073741824; // 2147483648 / 2, offset doesn't fit in int32_t.
+ assertEq(Atomics.load(ta, idx), i);
+ Atomics.add(ta, idx, 1);
+ Atomics.exchange(ta, idx, 2);
+ assertEq(ta[idx], 2);
+ assertEq(Atomics.compareExchange(ta, idx, 2, 3), 2);
+ Atomics.store(ta, idx, i + 1);
+
+ idx = 1073741823; // Largest offset that fits in int32_t.
+ assertEq(Atomics.load(ta, idx), i);
+ Atomics.add(ta, idx, 1);
+ Atomics.exchange(ta, idx, 2);
+ assertEq(ta[idx], 2);
+ assertEq(Atomics.compareExchange(ta, idx, 2, 3), 2);
+ Atomics.store(ta, idx, i + 1);
+ }
+ ta[1073741823] = 0;
+ ta[1073741824] = 0;
+}
+testInt16Atomics();
diff --git a/js/src/jit-test/tests/large-arraybuffers/arraybuffer-transfer.js b/js/src/jit-test/tests/large-arraybuffers/arraybuffer-transfer.js
new file mode 100644
index 0000000000..3f522e741c
--- /dev/null
+++ b/js/src/jit-test/tests/large-arraybuffers/arraybuffer-transfer.js
@@ -0,0 +1,64 @@
+const gb = 1 * 1024 * 1024 * 1024;
+
+const smallByteLength = 1024;
+const largeByteLength = 4 * gb;
+
+// Fast alternative to |assertEq| to avoid a slow VM-call.
+// Should only be used when looping over the TypedArray contents to avoid
+// unnecessary test slowdowns.
+function assertEqNum(e, a) {
+ if (e !== a) {
+ assertEq(e, a);
+ }
+}
+
+{
+ let smallBuffer = new ArrayBuffer(smallByteLength);
+
+ let i8 = new Uint8Array(smallBuffer);
+ for (let i = 0; i < smallByteLength; ++i) {
+ assertEqNum(i8[i], 0);
+ i8[i] = i;
+ }
+
+ assertEq(smallBuffer.byteLength, smallByteLength);
+ assertEq(smallBuffer.detached, false);
+
+ // Copy from a small into a large buffer.
+ let largeBuffer = smallBuffer.transfer(largeByteLength);
+
+ assertEq(smallBuffer.byteLength, 0);
+ assertEq(smallBuffer.detached, true);
+
+ assertEq(largeBuffer.byteLength, largeByteLength);
+ assertEq(largeBuffer.detached, false);
+
+ i8 = new Uint8Array(largeBuffer);
+ for (let i = 0; i < smallByteLength; ++i) {
+ assertEqNum(i8[i], i & 0xff);
+ }
+
+ // Test the first 100 new bytes.
+ for (let i = smallByteLength; i < smallByteLength + 100; ++i) {
+ assertEqNum(i8[i], 0);
+ }
+
+ // And the last 100 new bytes.
+ for (let i = largeByteLength - 100; i < largeByteLength; ++i) {
+ assertEqNum(i8[i], 0);
+ }
+
+ // Copy back from a large into a small buffer.
+ smallBuffer = largeBuffer.transfer(smallByteLength);
+
+ assertEq(largeBuffer.byteLength, 0);
+ assertEq(largeBuffer.detached, true);
+
+ assertEq(smallBuffer.byteLength, smallByteLength);
+ assertEq(smallBuffer.detached, false);
+
+ i8 = new Uint8Array(smallBuffer);
+ for (let i = 0; i < smallByteLength; ++i) {
+ assertEqNum(i8[i], i & 0xff);
+ }
+}
diff --git a/js/src/jit-test/tests/large-arraybuffers/atomics.js b/js/src/jit-test/tests/large-arraybuffers/atomics.js
new file mode 100644
index 0000000000..0e108db3b7
--- /dev/null
+++ b/js/src/jit-test/tests/large-arraybuffers/atomics.js
@@ -0,0 +1,57 @@
+// |jit-test| skip-if: !this.SharedArrayBuffer || !this.Atomics
+
+let gb = 1 * 1024 * 1024 * 1024;
+let buflen = 4 * gb + 64;
+let sab = new SharedArrayBuffer(buflen);
+assertEq(sab.byteLength, buflen);
+
+function testBasic(base) {
+ var uint8 = new Uint8Array(sab);
+ var uint8Part = new Uint8Array(sab, base, 64);
+
+ for (var i = 0; i < 50; i++) {
+ var index = base + i;
+ uint8Part[i] = 123;
+ assertEq(uint8[index], 123);
+
+ // Binary ops.
+ assertEq(Atomics.add(uint8, index, 1), 123);
+ assertEq(Atomics.and(uint8, index, 0xf), 124);
+ assertEq(Atomics.or(uint8, index, 0xf), 12);
+ assertEq(Atomics.xor(uint8, index, 0xee), 0xf);
+ assertEq(Atomics.sub(uint8, index, 100), 225);
+ assertEq(uint8Part[i], 125);
+
+ // compareExchange.
+ assertEq(Atomics.compareExchange(uint8, index, 125, 90), 125);
+ assertEq(Atomics.compareExchange(uint8, index, 125, 90), 90);
+ assertEq(uint8Part[i], 90);
+
+ // exchange.
+ assertEq(Atomics.exchange(uint8, index, 42), 90);
+ assertEq(uint8Part[i], 42);
+
+ // load/store.
+ assertEq(Atomics.load(uint8, index), 42);
+ assertEq(Atomics.store(uint8, index, 99), 99);
+ assertEq(uint8Part[i], 99);
+ }
+}
+for (let i = 0; i <= 4; i++) {
+ testBasic(i * gb);
+}
+
+function testWait() {
+ let int32 = new Int32Array(sab);
+ let index = int32.length - 1;
+ assertEq(int32[index], 0);
+ assertEq(Atomics.wait(int32, index, 1), "not-equal");
+ int32[index] = 12345;
+ assertEq(Atomics.wait(int32, index, 12345, 1), "timed-out");
+ assertEq(Atomics.notify(int32, index), 0);
+
+ let int32WithOffset = new Int32Array(sab, int32.byteLength - 4);
+ assertEq(int32WithOffset[0], 12345);
+ assertEq(Atomics.wait(int32WithOffset, 0, 12345, 1), "timed-out");
+}
+testWait();
diff --git a/js/src/jit-test/tests/large-arraybuffers/basic.js b/js/src/jit-test/tests/large-arraybuffers/basic.js
new file mode 100644
index 0000000000..58db1ee128
--- /dev/null
+++ b/js/src/jit-test/tests/large-arraybuffers/basic.js
@@ -0,0 +1,50 @@
+// Basic smoke tests for large ArrayBuffers.
+
+let gb = 1 * 1024 * 1024 * 1024;
+
+function test1() {
+ let ab = new ArrayBuffer(7 * gb);
+ assertEq(ab.byteLength, 7 * gb);
+
+ let taInt16 = new Int16Array(ab);
+ assertEq(taInt16.byteOffset, 0);
+ assertEq(taInt16.byteLength, 7 * gb);
+ assertEq(taInt16.length, 3.5 * gb);
+
+ let taInt16LastGb = new Int16Array(ab, 6 * gb);
+ assertEq(taInt16LastGb.byteOffset, 6 * gb);
+ assertEq(taInt16LastGb.byteLength, 1 * gb);
+ assertEq(taInt16LastGb.length, 0.5 * gb);
+
+ taInt16LastGb[0] = -99;
+ assertEq(taInt16[3 * gb], -99);
+
+ let taUint8 = new Uint8Array(ab);
+ assertEq(taUint8.length, 7 * gb);
+ assertEq(taUint8[7 * gb - 1], 0);
+
+ taUint8[7 * gb - 1] = 42;
+ taUint8[7 * gb - 1]++;
+ ++taUint8[7 * gb - 1];
+ assertEq(taUint8[7 * gb - 1], 44);
+
+ let dv = new DataView(ab);
+ assertEq(dv.getInt16(6 * gb, true), -99);
+ assertEq(dv.getUint8(7 * gb - 1, true), 44);
+
+ dv.setInt16(6 * gb + 2, 123, true);
+ assertEq(taInt16LastGb[1], 123);
+}
+test1();
+
+function test2() {
+ let taInt8 = new Int8Array(4 * gb);
+ assertEq(taInt8.length, 4 * gb);
+ taInt8[4 * gb - 4] = 42;
+ assertEq(taInt8[4 * gb - 4], 42);
+
+ let dv = new DataView(taInt8.buffer);
+ assertEq(dv.getInt32(4 * gb - 4, true), 42);
+ assertEq(dv.getBigInt64(4 * gb - 8, true), 180388626432n);
+}
+test2();
diff --git a/js/src/jit-test/tests/large-arraybuffers/directives.txt b/js/src/jit-test/tests/large-arraybuffers/directives.txt
new file mode 100644
index 0000000000..7f4cb67f4a
--- /dev/null
+++ b/js/src/jit-test/tests/large-arraybuffers/directives.txt
@@ -0,0 +1 @@
+|jit-test| allow-oom; skip-if: (!largeArrayBufferSupported() || getBuildConfiguration("tsan"))
diff --git a/js/src/jit-test/tests/large-arraybuffers/jit-alloc-big.js b/js/src/jit-test/tests/large-arraybuffers/jit-alloc-big.js
new file mode 100644
index 0000000000..2d2706f903
--- /dev/null
+++ b/js/src/jit-test/tests/large-arraybuffers/jit-alloc-big.js
@@ -0,0 +1,23 @@
+// |jit-test| slow
+
+// Ensure Warp JIT code handles |new Int32Array(INT32_MAX)| correctly.
+
+function test(len) {
+ var ta;
+ for (var i = 0; i < 2149; i++) {
+ if (i % 1024 === 100) {
+ // Constant length.
+ ta = new Int32Array(0x7fff_ffff);
+ assertEq(ta.length, 0x7fff_ffff);
+ ta[0x7fff_fffe] = i;
+ assertEq(ta[0x7fff_fffe], i);
+
+ // Variable length.
+ ta = new Int32Array(len - i);
+ assertEq(ta.length, len - i);
+ ta[ta.length - 1] = i;
+ assertEq(ta[ta.length - 1], i);
+ }
+ }
+}
+test(0x7fff_ffff);
diff --git a/js/src/jit-test/tests/large-arraybuffers/jit-bounds-checks.js b/js/src/jit-test/tests/large-arraybuffers/jit-bounds-checks.js
new file mode 100644
index 0000000000..29a4056873
--- /dev/null
+++ b/js/src/jit-test/tests/large-arraybuffers/jit-bounds-checks.js
@@ -0,0 +1,117 @@
+// |jit-test| test-also=--spectre-mitigations=off
+
+const gb = 1 * 1024 * 1024 * 1024;
+const ab = new ArrayBuffer(7 * gb);
+
+// Function called with Uint8Arrays of different sizes.
+function test(u8arr) {
+ var length = u8arr.length;
+ u8arr[0] = 87;
+
+ function testExpectedOOB() {
+ var base = length - 10;
+ u8arr[base]++;
+ for (var i = 0; i < 15; i++) {
+ var val = u8arr[base + i];
+ u8arr[base + i + 1] = (val|0) + 1;
+ }
+ }
+ for (var i = 0; i < 500; i++) {
+ testExpectedOOB();
+ }
+ assertEq(u8arr[length - 1], 253);
+
+ function testNegativeInt32Index() {
+ var val = 0;
+ for (var i = 0; i < 1500; i++) {
+ var idx = (i < 1450) - 1; // First 0, then -1.
+ val = u8arr[idx];
+ }
+ assertEq(val, undefined);
+ }
+ testNegativeInt32Index();
+
+ function testNegativeDoubleIndex() {
+ var val = 0;
+ for (var i = 0; i < 1500; i++) {
+ var idx = numberToDouble(+(i < 1450)) - 1; // First 0.0, then -1.0.
+ val = u8arr[idx];
+ assertEq(val, i < 1450 ? 87 : undefined);
+ }
+ }
+ testNegativeDoubleIndex();
+
+ function testConstantDoubleIndex() {
+ for (var i = 0; i < 1500; i++) {
+ var idxInBounds = 4294967100;
+ assertEq(u8arr[idxInBounds], 0);
+ u8arr[idxInBounds] = 1;
+ assertEq(u8arr[idxInBounds], 1);
+ u8arr[idxInBounds] = 0;
+ var idxOOB = 7516192768;
+ assertEq(u8arr[idxOOB], undefined);
+ var idxFractional = 7516192766 - 0.1;
+ assertEq(u8arr[idxFractional], undefined);
+ var idxNeg0 = -0;
+ assertEq(u8arr[idxNeg0], 87);
+ var idxNaN = NaN;
+ assertEq(u8arr[idxNaN], undefined);
+ }
+ }
+ testConstantDoubleIndex();
+
+ function testDoubleIndexWeird() {
+ var arr = [0.0, -0, 3.14, NaN, Infinity, -Infinity,
+ Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER];
+ for (var i = 0; i < 1500; i++) {
+ var which = i % arr.length;
+ var idx = arr[which];
+ assertEq(u8arr[idx], which < 2 ? 87 : undefined);
+ }
+ }
+ testDoubleIndexWeird();
+
+ // Uses LCompare.
+ function testHasElement1() {
+ for (var i = 0; i < 1500; i++) {
+ var idx = (length - 500) + i;
+ assertEq(idx in u8arr, idx < length);
+ assertEq(-1 in u8arr, false);
+ assertEq(10737418240 in u8arr, false);
+ assertEq(0x7fff_ffff in u8arr, true);
+ assertEq(0xffff_ffff in u8arr, true);
+ }
+ }
+ testHasElement1();
+
+ // Uses LCompareAndBranch.
+ function testHasElement2() {
+ for (var i = 0; i < 1500; i++) {
+ var idx = (length - 500) + i;
+ if (idx in u8arr) {
+ assertEq(idx < length, true);
+ } else {
+ assertEq(idx >= length, true);
+ }
+ var count = 0;
+ if (-1 in u8arr) {
+ count++;
+ }
+ if (10737418240 in u8arr) {
+ count++;
+ }
+ if (0x7fff_ffff in u8arr) {
+ } else {
+ count++;
+ }
+ if (0xffff_ffff in u8arr) {
+ } else {
+ count++;
+ }
+ assertEq(count, 0);
+ }
+ }
+ testHasElement2();
+}
+test(new Uint8Array(ab)); // 7 GB
+test(new Uint8Array(ab, 0, 4 * gb)); // 4 GB
diff --git a/js/src/jit-test/tests/large-arraybuffers/large-lengths-offsets.js b/js/src/jit-test/tests/large-arraybuffers/large-lengths-offsets.js
new file mode 100644
index 0000000000..4e2bff1d70
--- /dev/null
+++ b/js/src/jit-test/tests/large-arraybuffers/large-lengths-offsets.js
@@ -0,0 +1,73 @@
+const gb = 1 * 1024 * 1024 * 1024;
+
+const bufferSmall = new ArrayBuffer(8);
+const bufferLarge = new ArrayBuffer(6 * gb);
+
+const taSmall = new Uint8Array(bufferSmall);
+const taLargeOffset = new Uint8Array(bufferLarge, 5 * gb);
+const taLargeLength = new Uint8Array(bufferLarge);
+
+const dvSmall = new DataView(bufferSmall);
+const dvLargeOffset = new DataView(bufferLarge, 5 * gb);
+const dvLargeLength = new DataView(bufferLarge);
+
+const ArrayBufferByteLength = getSelfHostedValue("ArrayBufferByteLength");
+const TypedArrayByteOffset = getSelfHostedValue("TypedArrayByteOffset");
+const TypedArrayLength = getSelfHostedValue("TypedArrayLength");
+
+function testBufferByteLengthInt32() {
+ var arr = [bufferLarge, bufferSmall];
+ for (var i = 0; i < 2000; i++) {
+ var idx = +(i < 1900); // First 1 then 0.
+ assertEq(ArrayBufferByteLength(arr[idx]), idx === 0 ? 6 * gb : 8);
+ assertEq(arr[idx].byteLength, idx === 0 ? 6 * gb : 8);
+ }
+}
+testBufferByteLengthInt32();
+
+function testTypedArrayByteOffsetInt32() {
+ var arr = [taLargeOffset, taSmall];
+ for (var i = 0; i < 2000; i++) {
+ var idx = +(i < 1900); // First 1 then 0.
+ assertEq(TypedArrayByteOffset(arr[idx]), idx === 0 ? 5 * gb : 0);
+ assertEq(arr[idx].byteOffset, idx === 0 ? 5 * gb : 0);
+ }
+}
+testTypedArrayByteOffsetInt32();
+
+function testTypedArrayLengthInt32() {
+ var arr = [taLargeLength, taSmall];
+ for (var i = 0; i < 2000; i++) {
+ var idx = +(i < 1900); // First 1 then 0.
+ assertEq(TypedArrayLength(arr[idx]), idx === 0 ? 6 * gb : 8);
+ assertEq(arr[idx].length, idx === 0 ? 6 * gb : 8);
+ }
+}
+testTypedArrayLengthInt32();
+
+function testTypedArrayByteLengthInt32() {
+ var arr = [taLargeLength, taSmall];
+ for (var i = 0; i < 2000; i++) {
+ var idx = +(i < 1900); // First 1 then 0.
+ assertEq(arr[idx].byteLength, idx === 0 ? 6 * gb : 8);
+ }
+}
+testTypedArrayByteLengthInt32();
+
+function testDataViewByteOffsetInt32() {
+ var arr = [dvLargeOffset, dvSmall];
+ for (var i = 0; i < 2000; i++) {
+ var idx = +(i < 1900); // First 1 then 0.
+ assertEq(arr[idx].byteOffset, idx === 0 ? 5 * gb : 0);
+ }
+}
+testDataViewByteOffsetInt32();
+
+function testDataViewByteLengthInt32() {
+ var arr = [dvLargeLength, dvSmall];
+ for (var i = 0; i < 2000; i++) {
+ var idx = +(i < 1900); // First 1 then 0.
+ assertEq(arr[idx].byteLength, idx === 0 ? 6 * gb : 8);
+ }
+}
+testDataViewByteLengthInt32();
diff --git a/js/src/jit-test/tests/large-arraybuffers/max-typed-array-size.js b/js/src/jit-test/tests/large-arraybuffers/max-typed-array-size.js
new file mode 100644
index 0000000000..3cf01057b6
--- /dev/null
+++ b/js/src/jit-test/tests/large-arraybuffers/max-typed-array-size.js
@@ -0,0 +1,19 @@
+load(libdir + "asserts.js");
+
+const maxByteLength = 8 * 1024 * 1024 * 1024;
+
+// Test only the smallest and largest element type, because allocating a lot of
+// large buffers can be pretty slow.
+for (let ctor of [Int8Array, BigInt64Array]) {
+ const maxLength = maxByteLength / ctor.BYTES_PER_ELEMENT;
+ let ta1 = new ctor(maxLength);
+ assertEq(ta1.length, maxLength);
+ ta1[maxLength - 1]++;
+
+ let ta2 = new ctor(ta1.buffer, 0, maxLength);
+ assertEq(ta2.length, maxLength);
+ assertEq(ta1[maxLength - 1], ta2[maxLength - 1]);
+
+ assertThrowsInstanceOf(() => new ctor(maxLength + 1), RangeError);
+ assertThrowsInstanceOf(() => new ctor(ta1.buffer, 0, maxLength + 1), RangeError);
+}
diff --git a/js/src/jit-test/tests/large-arraybuffers/shared-array-buffer.js b/js/src/jit-test/tests/large-arraybuffers/shared-array-buffer.js
new file mode 100644
index 0000000000..608744b392
--- /dev/null
+++ b/js/src/jit-test/tests/large-arraybuffers/shared-array-buffer.js
@@ -0,0 +1,40 @@
+// |jit-test| skip-if: !this.SharedArrayBuffer
+
+var gb = 1 * 1024 * 1024 * 1024;
+var sab = new SharedArrayBuffer(4 * gb + 10);
+var ta = new Uint8Array(sab);
+
+function testSlice() {
+ // Large |start| and |end|.
+ ta[4 * gb + 0] = 11;
+ ta[4 * gb + 1] = 22;
+ ta[4 * gb + 2] = 33;
+ ta[4 * gb + 3] = 44;
+ var ta2 = new Uint8Array(sab.slice(4 * gb, 4 * gb + 4));
+ assertEq(ta2.toString(), "11,22,33,44");
+
+ // Large |start|.
+ ta[ta.length - 3] = 99;
+ ta[ta.length - 2] = 88;
+ ta[ta.length - 1] = 77;
+ ta2 = new Uint8Array(sab.slice(4 * gb + 8));
+ assertEq(ta2.toString(), "88,77");
+
+ // Relative values.
+ ta2 = new Uint8Array(sab.slice(-3, -1));
+ assertEq(ta2.toString(), "99,88");
+
+ // Large relative values.
+ ta[0] = 100;
+ ta[1] = 101;
+ ta[2] = 102;
+ ta2 = new Uint8Array(sab.slice(-ta.length, -ta.length + 3));
+ assertEq(ta2.toString(), "100,101,102");
+}
+testSlice();
+
+function testSharedMailbox() {
+ setSharedObject(sab);
+ assertEq(getSharedObject().byteLength, 4 * gb + 10);
+}
+testSharedMailbox();
diff --git a/js/src/jit-test/tests/large-arraybuffers/structured-clone.js b/js/src/jit-test/tests/large-arraybuffers/structured-clone.js
new file mode 100644
index 0000000000..b9d3c70cb5
--- /dev/null
+++ b/js/src/jit-test/tests/large-arraybuffers/structured-clone.js
@@ -0,0 +1,74 @@
+var gb = 1 * 1024 * 1024 * 1024;
+var ab = new ArrayBuffer(5 * gb);
+
+var ta1 = new Uint8Array(ab);
+
+for (var i = 0; i < 5; i++) {
+ ta1[i * gb + 0] = i + 1;
+ ta1[i * gb + 1] = i + 2;
+ ta1[i * gb + 2] = i + 3;
+ ta1[i * gb + 3] = i + 4;
+}
+
+function test(transferables, scope) {
+ var ta2 = new Int32Array(ab, ab.byteLength - 8, 2);
+ ta2[0] = 1234567;
+ var dv1 = new DataView(ab);
+ var dv2 = new DataView(ab, ab.byteLength - 8);
+ dv2.setInt32(4, -987654);
+ var objects = [ab, ta1, ta2, dv1, dv2];
+
+ var clonebuf = serialize(objects, transferables, {scope});
+ check(clonebuf);
+}
+
+function check(clonebuf) {
+ var objects = deserialize(clonebuf);
+ assertEq(objects.length, 5);
+
+ var ab = objects[0];
+ assertEq(ab instanceof ArrayBuffer, true);
+ assertEq(ab.byteLength, 5 * gb);
+
+ var ta1 = objects[1];
+ assertEq(ta1 instanceof Uint8Array, true);
+ assertEq(ta1.buffer, ab);
+ assertEq(ta1.byteOffset, 0);
+ assertEq(ta1.length, 5 * gb);
+
+ for (var i = 0; i < 5; i++) {
+ assertEq(ta1[i * gb + 0], i + 1);
+ assertEq(ta1[i * gb + 1], i + 2);
+ assertEq(ta1[i * gb + 2], i + 3);
+ assertEq(ta1[i * gb + 3], i + 4);
+ }
+
+ var ta2 = objects[2];
+ assertEq(ta2 instanceof Int32Array, true);
+ assertEq(ta2.buffer, ab);
+ assertEq(ta2.byteOffset, 5 * gb - 8);
+ assertEq(ta2.length, 2);
+ assertEq(ta2[0], 1234567);
+
+ var dv1 = objects[3];
+ assertEq(dv1 instanceof DataView, true);
+ assertEq(dv1.buffer, ab);
+ assertEq(dv1.byteOffset, 0);
+ assertEq(dv1.byteLength, 5 * gb);
+
+ var dv2 = objects[4];
+ assertEq(dv2 instanceof DataView, true);
+ assertEq(dv2.buffer, ab);
+ assertEq(dv2.byteOffset, 5 * gb - 8);
+ assertEq(dv2.byteLength, 8);
+ assertEq(dv2.getInt32(4), -987654);
+}
+
+// It would be nice to test serialization of the ArrayBuffer's contents, but it
+// causes OOMs and/or timeouts in automation so for now only test the more
+// efficient version that transfers the underlying buffer.
+//test([], "DifferentProcessForIndexedDB");
+//assertEq(ab.byteLength, 5 * gb);
+
+test([ab], "SameProcess");
+assertEq(ab.byteLength, 0);
diff --git a/js/src/jit-test/tests/large-arraybuffers/typed-array.js b/js/src/jit-test/tests/large-arraybuffers/typed-array.js
new file mode 100644
index 0000000000..c6eebc86cd
--- /dev/null
+++ b/js/src/jit-test/tests/large-arraybuffers/typed-array.js
@@ -0,0 +1,203 @@
+load(libdir + "asserts.js");
+
+var gb = 1 * 1024 * 1024 * 1024;
+var ta = new Uint8Array(4 * gb + 10);
+
+function testSetFromTyped() {
+ var ta2 = new Int8Array(10);
+ ta2[0] = 23;
+ ta2[9] = -10;
+ ta.set(ta2, 4 * gb);
+ assertEq(ta[4 * gb + 0], 23);
+ assertEq(ta[4 * gb + 9], 246);
+}
+testSetFromTyped();
+
+function testSetFromOther() {
+ ta.set([12, 34], 4 * gb + 4);
+ assertEq(ta[4 * gb + 4], 12);
+ assertEq(ta[4 * gb + 5], 34);
+}
+testSetFromOther();
+
+function testCopyWithin() {
+ // Large |start|.
+ ta[ta.length - 1] = 3;
+ ta.copyWithin(0, 4 * gb);
+ assertEq(ta[9], 3);
+
+ // Large relative |start|.
+ ta[ta.length - 1] = 4;
+ ta.copyWithin(0, -10);
+ assertEq(ta[9], 4);
+
+ // Large |start| and |end|.
+ ta[ta.length - 3] = 5;
+ ta[ta.length - 2] = 66;
+ ta[1] = 1;
+ ta.copyWithin(0, ta.length - 3, ta.length - 2);
+ assertEq(ta[0], 5);
+ assertEq(ta[1], 1);
+
+ // Large |target| and |start|.
+ ta.copyWithin(4 * gb + 5, 4 * gb + 7);
+ assertEq(ta[4 * gb + 6], 66);
+
+ // Large |target|.
+ ta[6] = 117;
+ ta.copyWithin(4 * gb);
+ assertEq(ta[4 * gb + 6], 117);
+}
+testCopyWithin();
+
+function testSlice() {
+ // Large |start| and |end|.
+ ta[4 * gb + 0] = 11;
+ ta[4 * gb + 1] = 22;
+ ta[4 * gb + 2] = 33;
+ ta[4 * gb + 3] = 44;
+ var ta2 = ta.slice(4 * gb, 4 * gb + 4);
+ assertEq(ta2.toString(), "11,22,33,44");
+
+ // Large |start|.
+ ta[ta.length - 3] = 99;
+ ta[ta.length - 2] = 88;
+ ta[ta.length - 1] = 77;
+ ta2 = ta.slice(4 * gb + 8);
+ assertEq(ta2.toString(), "88,77");
+
+ // Relative values.
+ ta2 = ta.slice(-3, -1);
+ assertEq(ta2.toString(), "99,88");
+
+ // Large relative values.
+ ta[0] = 100;
+ ta[1] = 101;
+ ta[2] = 102;
+ ta2 = ta.slice(-ta.length, -ta.length + 3);
+ assertEq(ta2.toString(), "100,101,102");
+}
+testSlice();
+
+function testSubarray() {
+ // Large |start| and |end|.
+ ta[4 * gb + 0] = 11;
+ ta[4 * gb + 1] = 22;
+ ta[4 * gb + 2] = 33;
+ ta[4 * gb + 3] = 44;
+ var ta2 = ta.subarray(4 * gb, 4 * gb + 4);
+ assertEq(ta2.toString(), "11,22,33,44");
+
+ // Large |start|.
+ ta[ta.length - 3] = 99;
+ ta[ta.length - 2] = 88;
+ ta[ta.length - 1] = 77;
+ ta2 = ta.subarray(4 * gb + 8);
+ assertEq(ta2.toString(), "88,77");
+
+ // Relative values.
+ ta2 = ta.subarray(-3, -1);
+ assertEq(ta2.toString(), "99,88");
+
+ // Large relative values.
+ ta[0] = 100;
+ ta[1] = 101;
+ ta[2] = 102;
+ ta2 = ta.subarray(-ta.length, -ta.length + 3);
+ assertEq(ta2.toString(), "100,101,102");
+}
+testSubarray();
+
+function testIterators() {
+ var ex;
+
+ ex = null;
+ try {
+ for (var p in ta) {}
+ } catch (e) {
+ ex = e;
+ }
+ assertEq(ex, "out of memory");
+
+ ex = null;
+ try {
+ Object.getOwnPropertyNames(ta);
+ } catch (e) {
+ ex = e;
+ }
+ const msg = ex + "";
+ assertEq(msg.includes("out of memory") || msg.includes("InternalError: allocation size overflow"), true);
+}
+testIterators();
+
+function testArraySliceSparse() {
+ // Length mustn't exceed UINT32_MAX.
+ var len = 4 * gb - 1;
+ var ta2 = new Int8Array(ta.buffer, 0, len);
+ ta2[len - 1] = 1;
+
+ // The SliceSparse optimisation is only used for native objects which have the
+ // "indexed" flag set.
+ var o = {
+ length: len,
+ 100000: 0, // sparse + indexed
+ __proto__: ta2,
+ };
+
+ // Collect sufficient elements to trigger the SliceSparse optimisation.
+ var r = Array.prototype.slice.call(o, -2000);
+ assertEq(r.length, 2000);
+ assertEq(r[r.length - 1], 1);
+}
+testArraySliceSparse();
+
+function testArrayIterator() {
+ for (var i = 0; i < 20; i++) {
+ ta[i] = i;
+ }
+ var sum = 0;
+ var i = 0;
+ for (var x of ta) {
+ if (i++ > 20) {
+ break;
+ }
+ sum += x;
+ }
+ assertEq(sum, 190);
+}
+testArrayIterator();
+
+function testArrayBufferSlice() {
+ // Large |start| and |end|.
+ ta[4 * gb + 0] = 11;
+ ta[4 * gb + 1] = 22;
+ ta[4 * gb + 2] = 33;
+ ta[4 * gb + 3] = 44;
+ var ta2 = new Uint8Array(ta.buffer.slice(4 * gb, 4 * gb + 4));
+ assertEq(ta2.toString(), "11,22,33,44");
+
+ // Large |start|.
+ ta[ta.length - 3] = 99;
+ ta[ta.length - 2] = 88;
+ ta[ta.length - 1] = 77;
+ ta2 = new Uint8Array(ta.buffer.slice(4 * gb + 8));
+ assertEq(ta2.toString(), "88,77");
+
+ // Relative values.
+ ta2 = new Uint8Array(ta.buffer.slice(-3, -1));
+ assertEq(ta2.toString(), "99,88");
+
+ // Large relative values.
+ ta[0] = 100;
+ ta[1] = 101;
+ ta[2] = 102;
+ ta2 = new Uint8Array(ta.buffer.slice(-ta.length, -ta.length + 3));
+ assertEq(ta2.toString(), "100,101,102");
+}
+testArrayBufferSlice();
+
+function testFromObjectTooLargeLength() {
+ assertThrowsInstanceOf(() => new Uint8Array({length: 9 * gb}), RangeError);
+ assertThrowsInstanceOf(() => ta.set({length: 9 * gb}), RangeError);
+}
+testFromObjectTooLargeLength();