diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /js/src/jit-test/tests/large-arraybuffers | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit-test/tests/large-arraybuffers')
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(); |