diff --git a/test/js/bun/jsc-stress/fixtures/dataview-get-cse.js b/test/js/bun/jsc-stress/fixtures/dataview-get-cse.js new file mode 100644 index 000000000000..03dcec8a7b6e --- /dev/null +++ b/test/js/bun/jsc-stress/fixtures/dataview-get-cse.js @@ -0,0 +1,158 @@ +// @bun +"use strict"; + +function assert(b) { + if (!b) + throw new Error; +} + +function getIsLittleEndian() { + let ab = new ArrayBuffer(2); + let ta = new Int16Array(ab); + ta[0] = 0x0102; + let dv = new DataView(ab); + return dv.getInt16(0, true) === 0x0102; +} + +let isLittleEndian = getIsLittleEndian(); + +function adjustForEndianess(value) { + if (isLittleEndian) + return value; + + let ab = new ArrayBuffer(8); + let ta = new Float64Array(ab); + ta[0] = value; + let dv = new DataView(ab); + return dv.getFloat64(0, true); +} + +function test1() { + function foo(dv) { + return [dv.getFloat32(0), dv.getFloat64(0)]; + } + noInline(foo); + + let ab = new ArrayBuffer(8); + let dv = new DataView(ab); + dv.setFloat64(0, 128431.42342189432, false); + for (let i = 0; i < testLoopCount; ++i) { + let result = foo(dv); + assert(result[0] !== result[1]); + } +} +test1(); + +function test2() { + function foo(dv) { + return [dv.getFloat32(0), dv.getFloat32(0)]; + } + noInline(foo); + + let ab = new ArrayBuffer(8); + let dv = new DataView(ab); + dv.setFloat64(0, 128431.42342189432, false); + for (let i = 0; i < testLoopCount; ++i) { + let result = foo(dv); + assert(result[0] === result[1]); + } +} +test2(); + +function test3() { + function foo(dv, ta) { + let a = dv.getFloat64(0, true); + ta[0] = adjustForEndianess(Math.PI); + let b = dv.getFloat64(0, true); + return [a, b]; + } + noInline(foo); + + let ab = new ArrayBuffer(8); + let dv = new DataView(ab); + let ta = new Float64Array(ab); + for (let i = 0; i < 40000; ++i) { + dv.setFloat64(0, 0.0, true); + let result = foo(dv, ta); + assert(result[0] === 0.0); + assert(result[1] === Math.PI); + } +} +test3(); + +function test4() { + function foo(dv) { + let a = dv.getInt32(0, true); + let b = dv.getInt32(0, false); + return [a, b]; + } + noInline(foo); + + let ab = new ArrayBuffer(8); + let dv = new DataView(ab); + dv.setInt32(0, 0x11223344, true); + for (let i = 0; i < 40000; ++i) { + let result = foo(dv); + assert(result[0] === 0x11223344); + assert(result[1] === 0x44332211) + } +} +test4(); + +function test5() { + function foo(dv, littleEndian) { + let a = dv.getInt32(0, littleEndian); + let b = dv.getInt32(0, !littleEndian); + return [a, b]; + } + noInline(foo); + + let ab = new ArrayBuffer(8); + let dv = new DataView(ab); + dv.setInt32(0, 0x11223344, true); + for (let i = 0; i < 40000; ++i) { + let result = foo(dv, true); + assert(result[0] === 0x11223344); + assert(result[1] === 0x44332211) + } +} +test5(); + +function test6() { + function foo(dv, littleEndian) { + let a = dv.getInt32(0, littleEndian); + let b = dv.getInt32(0, littleEndian); + return [a, b]; + } + noInline(foo); + + let ab = new ArrayBuffer(8); + let dv = new DataView(ab); + dv.setInt32(0, 0x11223344, true); + for (let i = 0; i < 40000; ++i) { + let result = foo(dv, true); + assert(result[0] === 0x11223344); + assert(result[1] === 0x11223344) + } +} +test6(); + +function test7() { + function foo(dv) { + let a = dv.getInt32(0, true); + let b = dv.getInt32(4, true); + return [a, b]; + } + noInline(foo); + + let ab = new ArrayBuffer(8); + let dv = new DataView(ab); + dv.setInt32(0, 0x11223344, true); + dv.setInt32(4, 0x12121212, true); + for (let i = 0; i < 40000; ++i) { + let result = foo(dv, true); + assert(result[0] === 0x11223344); + assert(result[1] === 0x12121212); + } +} +test7(); diff --git a/test/js/bun/jsc-stress/fixtures/dataview-jit-bigint64-byte-offset.js b/test/js/bun/jsc-stress/fixtures/dataview-jit-bigint64-byte-offset.js new file mode 100644 index 000000000000..38df611f23fa --- /dev/null +++ b/test/js/bun/jsc-stress/fixtures/dataview-jit-bigint64-byte-offset.js @@ -0,0 +1,41 @@ +// @bun +function shouldBe(actual, expected) { + if (actual !== expected) + throw new Error("bad value: " + actual + " expected: " + expected); +} + +function shouldThrow(func, errorType) { + let error = null; + try { + func(); + } catch (e) { + error = e; + } + if (!(error instanceof errorType)) + throw new Error("bad error: " + error); +} + +function get(dv, offset) { return dv.getBigUint64(offset, true); } +function set(dv, offset, value) { dv.setBigUint64(offset, value, true); } +noInline(get); +noInline(set); + +const buffer = new ArrayBuffer(32); +const bytes = new Uint8Array(buffer); +const dv = new DataView(buffer, 8, 16); + +for (let i = 0; i < testLoopCount; i++) { + set(dv, 0, 0x0807060504030201n); + for (let j = 0; j < 8; j++) + shouldBe(bytes[8 + j], j + 1); + shouldBe(get(dv, 0), 0x0807060504030201n); + + set(dv, 8, BigInt(i)); + shouldBe(get(dv, 8), BigInt(i)); + for (let j = 0; j < 8; j++) + shouldBe(bytes[16 + j], Number((BigInt(i) >> BigInt(8 * j)) & 0xffn)); +} + +shouldThrow(() => get(dv, 9), RangeError); +shouldThrow(() => set(dv, 16, 1n), RangeError); +shouldThrow(() => get(dv, -1), RangeError); diff --git a/test/js/bun/jsc-stress/fixtures/dataview-jit-bigint64-cse-and-aliasing.js b/test/js/bun/jsc-stress/fixtures/dataview-jit-bigint64-cse-and-aliasing.js new file mode 100644 index 000000000000..db7ddfa449e5 --- /dev/null +++ b/test/js/bun/jsc-stress/fixtures/dataview-jit-bigint64-cse-and-aliasing.js @@ -0,0 +1,51 @@ +// @bun +function shouldBe(actual, expected) { + if (actual !== expected) + throw new Error("bad value: " + actual + " expected: " + expected); +} + +function getSetGet(dv, offset, value) { + let before = dv.getBigInt64(offset, true); + dv.setBigInt64(offset, value, true); + let after = dv.getBigInt64(offset, true); + return [before, after]; +} +noInline(getSetGet); + +function getTwice(dv, offset) { + let a = dv.getBigUint64(offset, false); + let b = dv.getBigUint64(offset, false); + return [a, b]; +} +noInline(getTwice); + +function getArrayStoreGet(dv, array, index, value) { + let before = dv.getBigUint64(index * 8, true); + array[index] = value; + let after = dv.getBigUint64(index * 8, true); + return [before, after]; +} +noInline(getArrayStoreGet); + +const dv = new DataView(new ArrayBuffer(64)); +for (let i = 0; i < testLoopCount; i++) { + dv.setBigInt64(8, BigInt(i), true); + let [before, after] = getSetGet(dv, 8, BigInt(-i) - 1n); + shouldBe(before, BigInt(i)); + shouldBe(after, BigInt(-i) - 1n); + + dv.setBigUint64(16, BigInt(i) * 3n, false); + let [a, b] = getTwice(dv, 16); + shouldBe(a, BigInt(i) * 3n); + shouldBe(b, BigInt(i) * 3n); +} + +const buffer = new ArrayBuffer(64); +const aliasedView = new DataView(buffer); +const array = new BigUint64Array(buffer); +for (let i = 0; i < testLoopCount; i++) { + array[2] = BigInt(i); + let [before, after] = getArrayStoreGet(aliasedView, array, 2, BigInt(i) + (1n << 40n)); + shouldBe(before, BigInt(i)); + shouldBe(after, BigInt(i) + (1n << 40n)); +} diff --git a/test/js/bun/jsc-stress/fixtures/dataview-jit-bigint64-type-check-failures.js b/test/js/bun/jsc-stress/fixtures/dataview-jit-bigint64-type-check-failures.js new file mode 100644 index 000000000000..180d91d31b1b --- /dev/null +++ b/test/js/bun/jsc-stress/fixtures/dataview-jit-bigint64-type-check-failures.js @@ -0,0 +1,51 @@ +// @bun +function shouldBe(actual, expected) { + if (actual !== expected) + throw new Error("bad value: " + actual + " expected: " + expected); +} + +function shouldThrow(func, errorType) { + let error = null; + try { + func(); + } catch (e) { + error = e; + } + if (!(error instanceof errorType)) + throw new Error("bad error: " + error); +} + +function get(dv, offset, littleEndian) { return dv.getBigUint64(offset, littleEndian); } +function set(dv, offset, value, littleEndian) { dv.setBigUint64(offset, value, littleEndian); } +noInline(get); +noInline(set); + +const dv = new DataView(new ArrayBuffer(64)); +for (let i = 0; i < testLoopCount; i++) { + set(dv, 8, 0x0102030405060708n, true); + shouldBe(get(dv, 8, true), 0x0102030405060708n); +} + +shouldBe(get(dv, 8.9, true), 0x0102030405060708n); +shouldBe(get(dv, "8", true), 0x0102030405060708n); +shouldBe(get(dv, [8], true), 0x0102030405060708n); +shouldThrow(() => get(dv, 8n, true), TypeError); +shouldThrow(() => get(dv, Symbol("8"), true), TypeError); +shouldBe(get(dv, NaN, true), 0n); + +set(dv, 16.7, 0xa1a2a3a4a5a6a7a8n, true); +shouldBe(get(dv, 16, true), 0xa1a2a3a4a5a6a7a8n); +shouldThrow(() => set(dv, 8n, 1n, true), TypeError); + +shouldBe(get(dv, 8, 1), 0x0102030405060708n); +shouldBe(get(dv, 8, "yes"), 0x0102030405060708n); +shouldBe(get(dv, 8, undefined), 0x0807060504030201n); +shouldBe(get(dv, 8, null), 0x0807060504030201n); +shouldBe(get(dv, 8, {}), 0x0102030405060708n); +set(dv, 24, 0x1112131415161718n, 0); +shouldBe(get(dv, 24, false), 0x1112131415161718n); + +shouldThrow(() => get({}, 0, true), TypeError); +shouldThrow(() => get(new Uint8Array(64), 0, true), TypeError); +shouldThrow(() => set(null, 0, 1n, true), TypeError); +shouldThrow(() => get.call(undefined, DataView.prototype, 0, true), TypeError); diff --git a/test/js/bun/jsc-stress/fixtures/dataview-jit-bigint64.js b/test/js/bun/jsc-stress/fixtures/dataview-jit-bigint64.js new file mode 100644 index 000000000000..3af1369c9c46 --- /dev/null +++ b/test/js/bun/jsc-stress/fixtures/dataview-jit-bigint64.js @@ -0,0 +1,172 @@ +// @bun +function shouldBe(actual, expected) { + if (actual !== expected) + throw new Error("bad value: " + actual + " expected: " + expected); +} + +function shouldThrow(func, errorType) { + let error = null; + try { + func(); + } catch (e) { + error = e; + } + if (!(error instanceof errorType)) + throw new Error("bad error: " + error); +} + +function toUint64(v) { + return BigInt.asUintN(64, v); +} + +function toInt64(v) { + return BigInt.asIntN(64, v); +} + +function refSetBigUint64(bytes, offset, value, littleEndian) { + let v = toUint64(value); + for (let i = 0; i < 8; i++) + bytes[offset + i] = Number((v >> BigInt(8 * (littleEndian ? i : 7 - i))) & 0xffn); +} + +function getLE(view, offset) { return [view.getBigInt64(offset, true), view.getBigUint64(offset, true)]; } +function getBE(view, offset) { return [view.getBigInt64(offset, false), view.getBigUint64(offset, false)]; } +function getDefault(view, offset) { return [view.getBigInt64(offset), view.getBigUint64(offset)]; } +function getVar(view, offset, le) { return [view.getBigInt64(offset, le), view.getBigUint64(offset, le)]; } +noInline(getLE); +noInline(getBE); +noInline(getDefault); +noInline(getVar); + +function setLE(view, offset, v) { view.setBigInt64(offset, v, true); view.setBigUint64(offset + 8, v, true); } +function setBE(view, offset, v) { view.setBigInt64(offset, v, false); view.setBigUint64(offset + 8, v, false); } +function setDefault(view, offset, v) { view.setBigInt64(offset, v); view.setBigUint64(offset + 8, v); } +function setVar(view, offset, v, le) { view.setBigInt64(offset, v, le); view.setBigUint64(offset + 8, v, le); } +noInline(setLE); +noInline(setBE); +noInline(setDefault); +noInline(setVar); + +const size = 64; +const bytes = new Uint8Array(size); +const view = new DataView(bytes.buffer); + +const values = [ + 0n, 1n, -1n, 255n, 256n, 0x7fffffffn, 0x80000000n, 0xffffffffn, 0x100000000n, + (1n << 63n) - 1n, 1n << 63n, (1n << 64n) - 1n, -(1n << 63n), -(1n << 63n) + 1n, + 0x0102030405060708n, 0xf1f2f3f4f5f6f7f8n, + (1n << 64n) + 5n, (1n << 128n) + 7n, -((1n << 64n) + 5n), -((1n << 100n) + 123n), 1n << 64n, -(1n << 64n), +]; + +for (let i = 0; i < testLoopCount; i++) { + const value = values[i % values.length]; + const offset = (i * 3) % (size - 16); + + for (const le of [true, false]) { + setVar(view, offset, value, le); + const expected = new Uint8Array(16); + refSetBigUint64(expected, 0, value, le); + refSetBigUint64(expected, 8, value, le); + for (let j = 0; j < 16; j++) + shouldBe(bytes[offset + j], expected[j]); + + const [i64, u64] = getVar(view, offset, le); + shouldBe(i64, toInt64(value)); + shouldBe(u64, toUint64(value)); + } + + setLE(view, offset, value); + let [a, b] = getLE(view, offset); + shouldBe(a, toInt64(value)); + shouldBe(b, toUint64(value)); + + setBE(view, offset, value); + [a, b] = getBE(view, offset); + shouldBe(a, toInt64(value)); + shouldBe(b, toUint64(value)); + + setDefault(view, offset, value); + [a, b] = getDefault(view, offset); + shouldBe(a, toInt64(value)); + shouldBe(b, toUint64(value)); + shouldBe(view.getBigUint64(offset, false), toUint64(value)); +} + +function oobGet(view, offset) { return view.getBigUint64(offset, true); } +function oobSet(view, offset) { view.setBigUint64(offset, 1n, true); } +noInline(oobGet); +noInline(oobSet); +for (let i = 0; i < testLoopCount; i++) { + oobGet(view, 0); + oobSet(view, 0); +} +for (const badOffset of [size - 7, size, -1, 0x7fffffff]) { + shouldThrow(() => oobGet(view, badOffset), RangeError); + shouldThrow(() => oobSet(view, badOffset), RangeError); +} + +function setAny(view, offset, v) { view.setBigUint64(offset, v, true); } +noInline(setAny); +for (let i = 0; i < testLoopCount; i++) + setAny(view, 0, 42n); +for (const bad of [42, 1.5, null, undefined, Symbol("x")]) + shouldThrow(() => setAny(view, 0, bad), TypeError); +shouldThrow(() => setAny(view, 0, {}), SyntaxError); +setAny(view, 0, "42"); +shouldBe(view.getBigUint64(0, true), 42n); +setAny(view, 0, true); +shouldBe(view.getBigUint64(0, true), 1n); +setAny(view, 0, 7n); +shouldBe(view.getBigUint64(0, true), 7n); + +{ + const buffer = new ArrayBuffer(16); + const detachedView = new DataView(buffer); + detachedView.setBigUint64(0, 0x1122334455667788n, true); + transferArrayBuffer(buffer); + shouldThrow(() => oobGet(detachedView, 0), TypeError); + shouldThrow(() => oobSet(detachedView, 0), TypeError); +} + +{ + const rab = new ArrayBuffer(32, { maxByteLength: 64 }); + const resizableView = new DataView(rab); + function rget(view, offset) { return view.getBigUint64(offset, true); } + function rset(view, offset, value) { view.setBigUint64(offset, value, true); } + noInline(rget); + noInline(rset); + for (let i = 0; i < testLoopCount; i++) { + rset(resizableView, 16, BigInt(i)); + shouldBe(rget(resizableView, 16), BigInt(i)); + } + rab.resize(16); + shouldThrow(() => rget(resizableView, 16), RangeError); + rab.resize(64); + rset(resizableView, 48, 99n); + shouldBe(rget(resizableView, 48), 99n); +} + +function gcGet(view, offset) { return view.getBigUint64(offset, true); } +noInline(gcGet); +view.setBigUint64(0, 0xdeadbeefcafebaben, true); +{ + const keep = []; + for (let i = 0; i < 5 * testLoopCount; i++) { + keep.push(gcGet(view, 0)); + if (keep.length > 64) + keep.shift(); + } + fullGC(); + for (const k of keep) + shouldBe(k, 0xdeadbeefcafebaben); +} + +function setZero(view) { view.setBigUint64(0, 0n, true); view.setBigInt64(8, 0n, true); } +noInline(setZero); +for (let i = 0; i < testLoopCount; i++) { + view.setBigUint64(0, 0xffffffffffffffffn, true); + view.setBigInt64(8, -1n, true); + setZero(view); + shouldBe(view.getBigUint64(0, true), 0n); + shouldBe(view.getBigInt64(8, true), 0n); +} diff --git a/test/js/bun/jsc-stress/fixtures/dataview-jit-bounds-checks.js b/test/js/bun/jsc-stress/fixtures/dataview-jit-bounds-checks.js new file mode 100644 index 000000000000..db0b86bdf6fe --- /dev/null +++ b/test/js/bun/jsc-stress/fixtures/dataview-jit-bounds-checks.js @@ -0,0 +1,123 @@ +// @bun +"use strict"; + +function assert(b, m = "") { + if (!b) + throw new Error("Bad: " + m); +} + +let getOps = { + getUint8: 1, + getUint16: 2, + getUint32: 4, + getInt8: 1, + getInt16: 2, + getInt32: 4, + getFloat32: 4, + getFloat64: 8, + getBigInt64: 8, + getBigUint64: 8, +}; + +let setOps = { + setUint8: 1, + setUint16: 2, + setUint32: 4, + setInt8: 1, + setInt16: 2, + setInt32: 4, + setFloat32: 4, + setFloat64: 8, + setBigInt64: 8, + setBigUint64: 8, +}; + +let getFuncs = []; +for (let p of Object.keys(getOps)) { + let endOfCall = getOps[p] === 1 ? ");" : ", true);"; + let str = ` + (function ${p}(dv, index) { + return dv.${p}(index${endOfCall} + }) + `; + + let func = eval(str); + noInline(func); + getFuncs.push(func); +} + +let setFuncs = []; +for (let p of Object.keys(setOps)) { + let endOfCall = setOps[p] === 1 ? ");" : ", true);"; + let str = ` + (function ${p}(dv, index, value) { + return dv.${p}(index, value${endOfCall} + }) + `; + + let func = eval(str); + noInline(func); + setFuncs.push(func); +} + +function valueFor(name) { + return name.indexOf("Big") !== -1 ? 10n : 10; +} + +function assertThrowsRangeError(f) { + let e = null; + try { + f(); + } catch(err) { + e = err; + } + assert(e instanceof RangeError, e); +} + +function test(warmup) { + const size = 16*1024; + let ab = new ArrayBuffer(size); + let dv = new DataView(ab); + for (let i = 0; i < warmup; ++i) { + for (let f of getFuncs) { + f(dv, 0); + } + + for (let f of setFuncs) { + f(dv, 0, valueFor(f.name)); + } + } + + for (let f of getFuncs) { + assertThrowsRangeError(() => { + let index = size - getOps[f.name] + 1; + f(dv, index); + }); + assertThrowsRangeError(() => { + let index = -1; + f(dv, index); + }); + assertThrowsRangeError(() => { + let index = -2147483648; + f(dv, index); + }); + } + + for (let f of setFuncs) { + assertThrowsRangeError(() => { + let index = size - setOps[f.name] + 1; + f(dv, index, valueFor(f.name)); + }); + assertThrowsRangeError(() => { + let index = -1; + f(dv, index, valueFor(f.name)); + }); + assertThrowsRangeError(() => { + let index = -2147483648; + f(dv, index, valueFor(f.name)); + }); + } +} + +test(2000); +test(10000); diff --git a/test/js/bun/jsc-stress/fixtures/dataview-jit-get.js b/test/js/bun/jsc-stress/fixtures/dataview-jit-get.js new file mode 100644 index 000000000000..76c0afabe822 --- /dev/null +++ b/test/js/bun/jsc-stress/fixtures/dataview-jit-get.js @@ -0,0 +1,357 @@ +// @bun +"use strict"; + +function assert(b) { + if (!b) + throw new Error("Bad!"); +} + +function getIsLittleEndian() { + let ab = new ArrayBuffer(2); + let ta = new Int16Array(ab); + ta[0] = 0x0102; + let dv = new DataView(ab); + return dv.getInt16(0, true) === 0x0102; +} + +let isLittleEndian = getIsLittleEndian(); + +function test1() { + function bigEndian(o, i) { + return o.getInt32(i, false); + } + noInline(bigEndian); + function littleEndian(o, i) { + return o.getInt32(i, true); + } + noInline(littleEndian); + function biEndian(o, i, b) { + return o.getInt32(i, b); + } + noInline(biEndian); + function adjustForEndianess(value) { + if (isLittleEndian) + return value; + + let ab = new ArrayBuffer(4); + let ta = new Int32Array(ab); + ta[0] = value; + let dv = new DataView(ab); + return dv.getInt32(0, true); + } + + let ab = new ArrayBuffer(4); + let ta = new Int32Array(ab); + ta[0] = adjustForEndianess(0x01020304); + let dv = new DataView(ab); + + for (let i = 0; i < testLoopCount; ++i) { + assert(bigEndian(dv, 0) === 0x04030201); + assert(littleEndian(dv, 0) === 0x01020304); + if (i % 2) + assert(biEndian(dv, 0, true) === 0x01020304); + else + assert(biEndian(dv, 0, false) === 0x04030201); + } + + for (let i = 0; i < testLoopCount; ++i) { + assert(bigEndian(dv, 0) === 0x04030201); + assert(littleEndian(dv, 0) === 0x01020304); + if (i % 2) + assert(biEndian(dv, 0, true) === 0x01020304); + else + assert(biEndian(dv, 0, false) === 0x04030201); + } + + // Make sure we get the right sign. + ta[0] = adjustForEndianess(-32361386); // 0xfe123456 + for (let i = 0; i < testLoopCount; ++i) { + assert(bigEndian(dv, 0) === 0x563412fe); + assert(littleEndian(dv, 0) === -32361386); + if (i % 2) + assert(biEndian(dv, 0, true) === -32361386); + else + assert(biEndian(dv, 0, false) === 0x563412fe); + } + + // -2146290602 == (int)0x80123456 + ta[0] = adjustForEndianess(0x56341280); + for (let i = 0; i < testLoopCount; ++i) { + assert(bigEndian(dv, 0) === -2146290602); + assert(littleEndian(dv, 0) === 0x56341280); + if (i % 2) + assert(biEndian(dv, 0, true) === 0x56341280); + else + assert(biEndian(dv, 0, false) === -2146290602); + } +} +test1(); + +function test2() { + function bigEndian(o, i) { + return o.getInt16(i, false); + } + noInline(bigEndian); + function littleEndian(o, i) { + return o.getInt16(i, true); + } + noInline(littleEndian); + function biEndian(o, i, b) { + return o.getInt16(i, b); + } + noInline(biEndian); + function adjustForEndianess(value) { + if (isLittleEndian) + return value; + + let ab = new ArrayBuffer(2); + let ta = new Int16Array(ab); + ta[0] = value; + let dv = new DataView(ab); + return dv.getInt16(0, true); + } + + let ab = new ArrayBuffer(2); + let ta = new Int16Array(ab); + ta[0] = adjustForEndianess(0x0102); + let dv = new DataView(ab); + + for (let i = 0; i < testLoopCount; ++i) { + assert(bigEndian(dv, 0) === 0x0201); + assert(littleEndian(dv, 0) === 0x0102); + if (i % 2) + assert(biEndian(dv, 0, true) === 0x0102); + else + assert(biEndian(dv, 0, false) === 0x0201); + } + + // Check sign. + ta[0] = adjustForEndianess(-512); // 0xfe00 + for (let i = 0; i < testLoopCount; ++i) { + assert(bigEndian(dv, 0) === 0x00fe); + assert(littleEndian(dv, 0) === -512); + if (i % 2) + assert(biEndian(dv, 0, true) === -512); + else + assert(biEndian(dv, 0, false) === 0x00fe); + } + + // Check sign extension. + ta[0] = adjustForEndianess(0x00fe); + for (let i = 0; i < testLoopCount; ++i) { + assert(bigEndian(dv, 0) === -512); + assert(littleEndian(dv, 0) === 0x00fe); + if (i % 2) + assert(biEndian(dv, 0, true) === 0x00fe); + else + assert(biEndian(dv, 0, false) === -512); + } +} +test2(); + +function test3() { + function bigEndian(o, i) { + return o.getFloat32(i, false); + } + noInline(bigEndian); + function littleEndian(o, i) { + return o.getFloat32(i, true); + } + noInline(littleEndian); + function biEndian(o, i, b) { + return o.getFloat32(i, b); + } + noInline(biEndian); + function adjustForEndianess(value) { + if (isLittleEndian) + return value; + + let ab = new ArrayBuffer(4); + let ta = new Float32Array(ab); + ta[0] = value; + let dv = new DataView(ab); + return dv.getFloat32(0, true); + } + + let ab = new ArrayBuffer(4); + let ta = new Float32Array(ab); + const normal = 12912.403; // 0x4649c19d + const normalAsDouble = 12912.403320312500; + + const flipped = -5.1162437589918884e-21; + ta[0] = adjustForEndianess(normal); + + let dv = new DataView(ab); + for (let i = 0; i < testLoopCount; ++i) { + assert(bigEndian(dv, 0) === flipped); + assert(littleEndian(dv, 0) === 12912.403320312500); + if (i % 2) + assert(biEndian(dv, 0, true) === normalAsDouble); + else + assert(biEndian(dv, 0, false) === flipped); + } +} +test3(); + +function adjustForEndianessUint32(value) { + if (isLittleEndian) + return value; + + let ab = new ArrayBuffer(4); + let ta = new Uint32Array(ab); + ta[0] = value; + let dv = new DataView(ab); + return dv.getUint32(0, true); +} + +function test4() { + function bigEndian(o, i) { + return o.getUint32(i, false); + } + noInline(bigEndian); + function littleEndian(o, i) { + return o.getUint32(i, true); + } + noInline(littleEndian); + function biEndian(o, i, b) { + return o.getUint32(i, b); + } + noInline(biEndian); + + let ab = new ArrayBuffer(4); + let ta = new Uint32Array(ab); + ta[0] = adjustForEndianessUint32(0xa0b0d0f0); + + let dv = new DataView(ab); + for (let i = 0; i < testLoopCount; ++i) { + assert(bigEndian(dv, 0) === 0xf0d0b0a0); + assert(littleEndian(dv, 0) === 0xa0b0d0f0); + if (i % 2) + assert(biEndian(dv, 0, true) === 0xa0b0d0f0); + else + assert(biEndian(dv, 0, false) === 0xf0d0b0a0); + } +} +test4(); + +function test5() { + function bigEndian(o, i) { + return o.getUint16(i, false); + } + noInline(bigEndian); + function littleEndian(o, i) { + return o.getUint16(i, true); + } + noInline(littleEndian); + function biEndian(o, i, b) { + return o.getUint16(i, b); + } + noInline(biEndian); + + let ab = new ArrayBuffer(4); + let ta = new Uint32Array(ab); + ta[0] = adjustForEndianessUint32(0xa0b0d0f0); + + let dv = new DataView(ab); + for (let i = 0; i < testLoopCount; ++i) { + assert(littleEndian(dv, 0) == 0xd0f0); + assert(bigEndian(dv, 0) == 0xf0d0); + + assert(littleEndian(dv, 1) == 0xb0d0); + assert(bigEndian(dv, 1) == 0xd0b0); + + assert(littleEndian(dv, 2) == 0xa0b0); + assert(bigEndian(dv, 2) == 0xb0a0); + + assert(biEndian(dv, 0, true) == 0xd0f0); + assert(biEndian(dv, 0, false) == 0xf0d0); + + assert(biEndian(dv, 1, true) == 0xb0d0); + assert(biEndian(dv, 1, false) == 0xd0b0); + + assert(biEndian(dv, 2, true) == 0xa0b0); + assert(biEndian(dv, 2, false) == 0xb0a0); + } +} +test5(); + +function test6() { + function bigEndian(o, i) { + return o.getInt16(i, false); + } + noInline(bigEndian); + function littleEndian(o, i) { + return o.getInt16(i, true); + } + noInline(littleEndian); + function biEndian(o, i, b) { + return o.getInt16(i, b); + } + noInline(biEndian); + + let ab = new ArrayBuffer(4); + let ta = new Uint32Array(ab); + ta[0] = adjustForEndianessUint32(0xa070fa01); + + let dv = new DataView(ab); + for (let i = 0; i < testLoopCount; ++i) { + assert(littleEndian(dv, 0) == -1535); + assert(bigEndian(dv, 0) == 0x01fa); + + assert(littleEndian(dv, 1) == 0x70fa); + assert(bigEndian(dv, 1) == -1424); + + assert(littleEndian(dv, 2) == -24464); + assert(bigEndian(dv, 2) == 0x70a0); + + assert(biEndian(dv, 0, true) == -1535); + assert(biEndian(dv, 0, false) == 0x01fa); + + assert(biEndian(dv, 1, true) == 0x70fa); + assert(biEndian(dv, 1, false) == -1424); + + assert(biEndian(dv, 2, true) == -24464); + assert(biEndian(dv, 2, false) == 0x70a0); + } +} +test6(); + +function test7() { + function load(o, i) { + return o.getInt8(i); + } + noInline(load); + + let ab = new ArrayBuffer(4); + let ta = new Uint32Array(ab); + ta[0] = adjustForEndianessUint32(0xa070fa01); + + let dv = new DataView(ab); + for (let i = 0; i < testLoopCount; ++i) { + assert(load(dv, 0) === 0x01); + assert(load(dv, 1) === -6); + assert(load(dv, 2) === 0x70); + assert(load(dv, 3) === -96); + } +} +test7(); + +function test8() { + function load(o, i) { + return o.getUint8(i); + } + noInline(load); + + let ab = new ArrayBuffer(4); + let ta = new Uint32Array(ab); + ta[0] = adjustForEndianessUint32(0xa070fa01); + + let dv = new DataView(ab); + for (let i = 0; i < testLoopCount; ++i) { + assert(load(dv, 0) === 0x01); + assert(load(dv, 1) === 0xfa); + assert(load(dv, 2) === 0x70); + assert(load(dv, 3) === 0xa0) + } +} +test8(); diff --git a/test/js/bun/jsc-stress/fixtures/dataview-jit-neuter.js b/test/js/bun/jsc-stress/fixtures/dataview-jit-neuter.js new file mode 100644 index 000000000000..770496a962bb --- /dev/null +++ b/test/js/bun/jsc-stress/fixtures/dataview-jit-neuter.js @@ -0,0 +1,81 @@ +// @bun +"use strict"; + +function assert(b) { + if (!b) + throw new Error("Bad!"); +} + +function getIsLittleEndian() { + let ab = new ArrayBuffer(2); + let ta = new Int16Array(ab); + ta[0] = 0x0102; + let dv = new DataView(ab); + return dv.getInt16(0, true) === 0x0102; +} + +let isLittleEndian = getIsLittleEndian(); + +function adjustForEndianess(value) { + if (isLittleEndian) + return value; + + let ab = new ArrayBuffer(4); + let ta = new Uint32Array(ab); + ta[0] = value; + let dv = new DataView(ab); + return dv.getUint32(0, true); +} + +function test() { + function load(o, i) { + return o.getUint8(i); + } + noInline(load); + + let ab = new ArrayBuffer(4); + let ta = new Uint32Array(ab); + ta[0] = adjustForEndianess(0xa070fa01); + let dv = new DataView(ab); + + for (let i = 0; i < 1000; ++i) { + assert(load(dv, 0) === 0x01); + } + + transferArrayBuffer(ab); + let e = null; + try { + load(dv, 0); + } catch(err) { + e = err; + } + assert(e instanceof TypeError); +} +test(); + + +function test2() { + function load(o, i) { + return o.getUint8(i); + } + noInline(load); + + let ab = new ArrayBuffer(4); + let ta = new Uint32Array(ab); + ta[0] = adjustForEndianess(0xa070fa01); + let dv = new DataView(ab); + + for (let i = 0; i < testLoopCount; ++i) { + assert(load(dv, 0) === 0x01); + } + + transferArrayBuffer(ab); + let e = null; + try { + load(dv, 0); + } catch(err) { + e = err; + } + assert(e instanceof TypeError); +} +test2(); diff --git a/test/js/bun/jsc-stress/fixtures/dataview-jit-set.js b/test/js/bun/jsc-stress/fixtures/dataview-jit-set.js new file mode 100644 index 000000000000..98b844f620ee --- /dev/null +++ b/test/js/bun/jsc-stress/fixtures/dataview-jit-set.js @@ -0,0 +1,503 @@ +// @bun +"use strict"; + +function assert(b) { + if (!b) + throw new Error; +} + +function getIsLittleEndian() { + let ab = new ArrayBuffer(2); + let ta = new Int16Array(ab); + ta[0] = 0x0102; + let dv = new DataView(ab); + return dv.getInt16(0, true) === 0x0102; +} + +let isLittleEndian = getIsLittleEndian(); + +function readHex(dv, bytes) { + let str = ""; + function readByte(i) { + let b = dv.getUint8(i).toString(16); + if (b.length === 1) + b = "0" + b; + else + assert(b.length === 2) + return b; + } + if (isLittleEndian) { + for (let i = bytes; i--;) + str = str + readByte(i); + } else { + for (let i = 0; i < bytes; ++i) + str = str + readByte(i); + } + + return "0x" + str; +} + +{ + let b = new ArrayBuffer(4); + let dv = new DataView(b); + dv.setInt32(0, 0x00112233, isLittleEndian); + assert(readHex(dv, 4) === "0x00112233"); +} + +function adjustForEndianessUint16(value) { + if (isLittleEndian) + return value; + + let ab = new ArrayBuffer(4); + let ta = new Uint16Array(ab); + ta[0] = value; + let dv = new DataView(ab); + return dv.getUint16(0, true); +} + +function test() { + function storeLittleEndian(dv, index, value) { + dv.setInt16(index, value, true); + } + noInline(storeLittleEndian); + + function storeBigEndian(dv, index, value) { + dv.setInt16(index, value, false); + } + noInline(storeBigEndian); + + function store(dv, index, value, littleEndian) { + dv.setInt16(index, value, littleEndian); + } + noInline(store); + + let buffer = new ArrayBuffer(2); + let arr = new Uint16Array(buffer); + let dv = new DataView(buffer); + + for (let i = 0; i < testLoopCount; ++i) { + storeLittleEndian(dv, 0, adjustForEndianessUint16(0xfaba)); + assert(arr[0] === 0xfaba); + + store(dv, 0, adjustForEndianessUint16(0xabcd), true); + assert(arr[0] === 0xabcd); + + store(dv, 0, adjustForEndianessUint16(0xbadbeef), true); + assert(arr[0] === 0xbeef); + + storeLittleEndian(dv, 0, adjustForEndianessUint16(0xbb4db33f), true); + assert(arr[0] === 0xb33f); + + storeBigEndian(dv, 0, adjustForEndianessUint16(0xfada)); + assert(arr[0] === 0xdafa); + + storeBigEndian(dv, 0, adjustForEndianessUint16(0x12ab)); + assert(arr[0] === 0xab12); + + store(dv, 0, adjustForEndianessUint16(0x1234), false); + assert(arr[0] === 0x3412); + + store(dv, 0, adjustForEndianessUint16(0x0102), false); + assert(arr[0] === 0x0201); + + store(dv, 0, adjustForEndianessUint16(-1), false); + assert(arr[0] === 0xffff); + + store(dv, 0, adjustForEndianessUint16(-2), false); + assert(arr[0] === 0xfeff); + + storeBigEndian(dv, 0, adjustForEndianessUint16(-1)); + assert(arr[0] === 0xffff); + + storeBigEndian(dv, 0, adjustForEndianessUint16(-2)); + assert(arr[0] === 0xfeff); + + storeBigEndian(dv, 0, adjustForEndianessUint16(-2147483648)); + assert(arr[0] === 0x0000); + + storeLittleEndian(dv, 0, adjustForEndianessUint16(-2147483648)); + assert(arr[0] === 0x0000); + + storeLittleEndian(dv, 0, adjustForEndianessUint16(-2147478988)); + assert(arr[0] === 0x1234); + + storeBigEndian(dv, 0, adjustForEndianessUint16(-2147478988)); + assert(arr[0] === 0x3412); + } +} +test(); + +function test2() { + function storeLittleEndian(dv, index, value) { + dv.setUint16(index, value, true); + } + noInline(storeLittleEndian); + + function storeBigEndian(dv, index, value) { + dv.setUint16(index, value, false); + } + noInline(storeBigEndian); + + function store(dv, index, value, littleEndian) { + dv.setUint16(index, value, littleEndian); + } + noInline(store); + + let buffer = new ArrayBuffer(2); + let arr = new Uint16Array(buffer); + let dv = new DataView(buffer); + + for (let i = 0; i < testLoopCount; ++i) { + storeLittleEndian(dv, 0, adjustForEndianessUint16(0xfaba)); + assert(arr[0] === 0xfaba); + + store(dv, 0, adjustForEndianessUint16(0xabcd), true); + assert(arr[0] === 0xabcd); + + store(dv, 0, adjustForEndianessUint16(0xbadbeef), true); + assert(arr[0] === 0xbeef); + + storeLittleEndian(dv, 0, adjustForEndianessUint16(0xbb4db33f), true); + assert(arr[0] === 0xb33f); + + storeBigEndian(dv, 0, adjustForEndianessUint16(0xfada)); + assert(arr[0] === 0xdafa); + + storeBigEndian(dv, 0, adjustForEndianessUint16(0x12ab)); + assert(arr[0] === 0xab12); + + store(dv, 0, adjustForEndianessUint16(0x1234), false); + assert(arr[0] === 0x3412); + + store(dv, 0, adjustForEndianessUint16(0x0102), false); + assert(arr[0] === 0x0201); + + store(dv, 0, adjustForEndianessUint16(-1), false); + assert(arr[0] === 0xffff); + + store(dv, 0, adjustForEndianessUint16(-2), false); + assert(arr[0] === 0xfeff); + + storeBigEndian(dv, 0, adjustForEndianessUint16(-1)); + assert(arr[0] === 0xffff); + + storeBigEndian(dv, 0, adjustForEndianessUint16(-2)); + assert(arr[0] === 0xfeff); + + storeBigEndian(dv, 0, adjustForEndianessUint16(-2147483648)); + assert(arr[0] === 0x0000); + + storeLittleEndian(dv, 0, adjustForEndianessUint16(-2147483648)); + assert(arr[0] === 0x0000); + + storeLittleEndian(dv, 0, adjustForEndianessUint16(-2147478988)); + assert(arr[0] === 0x1234); + + storeBigEndian(dv, 0, adjustForEndianessUint16(-2147478988)); + assert(arr[0] === 0x3412); + } +} +test2(); + +function adjustForEndianessUint32(value) { + if (isLittleEndian) + return value; + + let ab = new ArrayBuffer(4); + let ta = new Uint32Array(ab); + ta[0] = value; + let dv = new DataView(ab); + return dv.getUint32(0, true); +} + +function test3() { + function storeLittleEndian(dv, index, value) { + dv.setUint32(index, value, true); + } + noInline(storeLittleEndian); + + function storeBigEndian(dv, index, value) { + dv.setUint32(index, value, false); + } + noInline(storeBigEndian); + + function store(dv, index, value, littleEndian) { + dv.setUint32(index, value, littleEndian); + } + noInline(store); + + let buffer = new ArrayBuffer(4); + let arr = new Uint32Array(buffer); + let arr2 = new Int32Array(buffer); + let dv = new DataView(buffer); + + for (let i = 0; i < testLoopCount; ++i) { + storeLittleEndian(dv, 0, adjustForEndianessUint32(0xffffffff)); + assert(arr[0] === 0xffffffff); + assert(arr2[0] === -1); + + storeLittleEndian(dv, 0, adjustForEndianessUint32(0xffaabbcc)); + assert(arr[0] === 0xffaabbcc); + + storeBigEndian(dv, 0, adjustForEndianessUint32(0x12345678)); + assert(arr[0] === 0x78563412); + + storeBigEndian(dv, 0, adjustForEndianessUint32(0xffaabbcc)); + assert(arr[0] === 0xccbbaaff); + + store(dv, 0, adjustForEndianessUint32(0xfaeadaca), false); + assert(arr[0] === 0xcadaeafa); + + store(dv, 0, adjustForEndianessUint32(0xcadaeafa), false); + assert(arr2[0] === -85271862); + + store(dv, 0, adjustForEndianessUint32(0x12345678), false); + assert(arr[0] === 0x78563412); + + storeBigEndian(dv, 0, adjustForEndianessUint32(0xbeeffeeb)); + assert(arr2[0] === -335614018); + } +} +test3(); + +function test4() { + function storeLittleEndian(dv, index, value) { + dv.setInt32(index, value, true); + } + noInline(storeLittleEndian); + + function storeBigEndian(dv, index, value) { + dv.setInt32(index, value, false); + } + noInline(storeBigEndian); + + function store(dv, index, value, littleEndian) { + dv.setInt32(index, value, littleEndian); + } + noInline(store); + + let buffer = new ArrayBuffer(4); + let arr = new Uint32Array(buffer); + let arr2 = new Int32Array(buffer); + let dv = new DataView(buffer); + + for (let i = 0; i < testLoopCount; ++i) { + storeLittleEndian(dv, 0, adjustForEndianessUint32(0xffffffff)); + assert(arr[0] === 0xffffffff); + assert(arr2[0] === -1); + + storeLittleEndian(dv, 0, adjustForEndianessUint32(0xffaabbcc)); + assert(arr[0] === 0xffaabbcc); + + storeBigEndian(dv, 0, adjustForEndianessUint32(0x12345678)); + assert(arr[0] === 0x78563412); + + storeBigEndian(dv, 0, adjustForEndianessUint32(0xffaabbcc)); + assert(arr[0] === 0xccbbaaff); + + store(dv, 0, adjustForEndianessUint32(0xfaeadaca), false); + assert(arr[0] === 0xcadaeafa); + + store(dv, 0, adjustForEndianessUint32(0xcadaeafa), false); + assert(arr2[0] === -85271862); + + store(dv, 0, adjustForEndianessUint32(0x12345678), false); + assert(arr[0] === 0x78563412); + + storeBigEndian(dv, 0, adjustForEndianessUint32(0xbeeffeeb)); + assert(arr2[0] === -335614018); + } +} +test4(); + +function adjustForEndianessFloat32(value) { + if (isLittleEndian) + return value; + + let ab = new ArrayBuffer(4); + let ta = new Float32Array(ab); + ta[0] = value; + let dv = new DataView(ab); + return dv.getFloat32(0, true); +} + +function test5() { + function storeLittleEndian(dv, index, value) { + dv.setFloat32(index, value, true); + } + noInline(storeLittleEndian); + + function storeBigEndian(dv, index, value) { + dv.setFloat32(index, value, false); + } + noInline(storeBigEndian); + + function store(dv, index, value, littleEndian) { + dv.setFloat32(index, value, littleEndian); + } + noInline(store); + + let buffer = new ArrayBuffer(4); + let arr = new Float32Array(buffer); + let bits = new Uint32Array(buffer); + let dv = new DataView(buffer); + let f32_exponent_bits = 0x7F800000; + let f32_fraction_bits = 0x007FFFFF; + + for (let i = 0; i < testLoopCount; ++i) { + storeLittleEndian(dv, 0, adjustForEndianessFloat32(1.5)); + assert(arr[0] === 1.5); + + // The right way how to process this test is to uncomment the line below + // and comment out the line below it. But strangely it doesn't work. I + // opened https://bugs.webkit.org/show_bug.cgi?id=209289 for it. + //storeLittleEndian(dv, 0, adjustForEndianessFloat32(12912.124123215122)); + store(dv, 0, 12912.124123215122, isLittleEndian); + assert(bits[0] === 0x4649c07f); + assert(arr[0] === 12912.1240234375); + + storeLittleEndian(dv, 0, adjustForEndianessFloat32(NaN)); + assert(isNaN(arr[0])); + // The conversion of our initial 64-bit pure NaN (0x7ff8000000000000) + // should yield a Float32 NaN, but we can't check for a specific binary + // value since different CPUs might convert to different 32-bit NaNs, + // so we just check that the bits represent a NaN. + // The binary representation of a NaN has all its exponent bits set to + // 1 and at least one fraction bit set to 1. + assert(((bits[0] & f32_exponent_bits) === f32_exponent_bits) && !!(bits[0] & f32_fraction_bits)) + + storeLittleEndian(dv, 0, adjustForEndianessFloat32(2.3879393e-38)); + assert(arr[0] === 2.387939260590663e-38); + assert(bits[0] === 0x01020304); + + storeBigEndian(dv, 0, adjustForEndianessFloat32(2.3879393e-38)); + assert(arr[0] === 1.539989614439558e-36); + assert(bits[0] === 0x04030201); + } +} +test5(); + +function adjustForEndianessFloat64(value) { + if (isLittleEndian) + return value; + + let ab = new ArrayBuffer(8); + let ta = new Float64Array(ab); + ta[0] = value; + let dv = new DataView(ab); + return dv.getFloat64(0, true); +} + +function test6() { + function storeLittleEndian(dv, index, value) { + dv.setFloat64(index, value, true); + } + noInline(storeLittleEndian); + + function storeBigEndian(dv, index, value) { + dv.setFloat64(index, value, false); + } + noInline(storeBigEndian); + + function store(dv, index, value, littleEndian) { + dv.setFloat64(index, value, littleEndian); + } + noInline(store); + + let buffer = new ArrayBuffer(8); + let arr = new Float64Array(buffer); + let dv = new DataView(buffer); + + for (let i = 0; i < testLoopCount; ++i) { + storeLittleEndian(dv, 0, adjustForEndianessFloat64(NaN)); + assert(isNaN(arr[0])); + // The NaN we stored should be a pure NaN, so that's what we should get + assert(readHex(dv, 8) == "0x7ff8000000000000"); + + storeLittleEndian(dv, 0, adjustForEndianessFloat64(-2.5075187084135162e+284)); + assert(arr[0] === -2.5075187084135162e+284); + assert(readHex(dv, 8) === "0xfafafafafafafafa"); + + store(dv, 0, adjustForEndianessFloat64(124.553), true); + assert(readHex(dv, 8) === "0x405f23645a1cac08"); + + store(dv, 0, adjustForEndianessFloat64(Infinity), true); + assert(readHex(dv, 8) === "0x7ff0000000000000"); + + store(dv, 0, adjustForEndianessFloat64(Infinity), false); + assert(readHex(dv, 8) === "0x000000000000f07f"); + + store(dv, 0, adjustForEndianessFloat64(-Infinity), true); + assert(readHex(dv, 8) === "0xfff0000000000000"); + + storeBigEndian(dv, 0, adjustForEndianessFloat64(-2.5075187084135162e+284)); + assert(arr[0] === -2.5075187084135162e+284); + assert(readHex(dv, 8) === "0xfafafafafafafafa"); + + storeBigEndian(dv, 0, adjustForEndianessFloat64(124.553)); + assert(readHex(dv, 8) === "0x08ac1c5a64235f40"); + } +} +test6(); + +function test7() { + function store(dv, index, value) { + dv.setInt8(index, value); + } + noInline(store); + + let buffer = new ArrayBuffer(1); + let arr = new Uint8Array(buffer); + let arr2 = new Int8Array(buffer); + let dv = new DataView(buffer); + + for (let i = 0; i < testLoopCount; ++i) { + store(dv, 0, 0xff); + assert(arr[0] === 0xff); + assert(arr2[0] === -1); + + store(dv, 0, 0xff00); + assert(arr[0] === 0); + assert(arr2[0] === 0); + + store(dv, 0, -1); + assert(arr[0] === 0xff); + assert(arr2[0] === -1); + + store(dv, 0, 0x0badbeef); + assert(arr[0] === 0xef); + assert(arr2[0] === -17); + } +} +test7(); + +function test8() { + function store(dv, index, value) { + dv.setInt8(index, value); + } + noInline(store); + + let buffer = new ArrayBuffer(1); + let arr = new Uint8Array(buffer); + let arr2 = new Int8Array(buffer); + let dv = new DataView(buffer); + + for (let i = 0; i < testLoopCount; ++i) { + store(dv, 0, 0xff); + assert(arr[0] === 0xff); + assert(arr2[0] === -1); + + store(dv, 0, 0xff00); + assert(arr[0] === 0); + assert(arr2[0] === 0); + + store(dv, 0, -1); + assert(arr[0] === 0xff); + assert(arr2[0] === -1); + + store(dv, 0, 0x0badbeef); + assert(arr[0] === 0xef); + assert(arr2[0] === -17); + } +} +test8(); diff --git a/test/js/bun/jsc-stress/fixtures/dataview-jit-unaligned-accesses.js b/test/js/bun/jsc-stress/fixtures/dataview-jit-unaligned-accesses.js new file mode 100644 index 000000000000..7f9eaf21031d --- /dev/null +++ b/test/js/bun/jsc-stress/fixtures/dataview-jit-unaligned-accesses.js @@ -0,0 +1,80 @@ +// @bun +"use strict"; + +function assert(b, m = "") { + if (!b) + throw new Error("Bad: " + m); +} + +let getOps = { + getUint8: 1, + getUint16: 2, + getUint32: 4, + getInt8: 1, + getInt16: 2, + getInt32: 4, + getFloat32: 4, + getFloat64: 8, + getBigInt64: 8, + getBigUint64: 8, +}; + +let setOps = { + setUint8: 1, + setUint16: 2, + setUint32: 4, + setInt8: 1, + setInt16: 2, + setInt32: 4, + setFloat32: 4, + setFloat64: 8, + setBigInt64: 8, + setBigUint64: 8, +}; + +let getFuncs = []; +for (let p of Object.keys(getOps)) { + let endOfCall = getOps[p] === 1 ? ");" : ", true);"; + let str = ` + (function ${p}(dv, index) { + return dv.${p}(index${endOfCall} + }) + `; + + let func = eval(str); + noInline(func); + getFuncs.push(func); +} + +let setFuncs = []; +for (let p of Object.keys(setOps)) { + let endOfCall = setOps[p] === 1 ? ");" : ", true);"; + let str = ` + (function ${p}(dv, index, value) { + dv.${p}(index, value${endOfCall} + }) + `; + + let func = eval(str); + noInline(func); + setFuncs.push(func); +} + +function test() { + const size = 16*1024; + let ab = new ArrayBuffer(size); + let dv = new DataView(ab); + for (let i = 0; i < testLoopCount; ++i) { + let index = (Math.random() * size) >>> 0; + index = Math.max(index - 8, 0); + for (let f of getFuncs) { + f(dv, index); + } + + for (let f of setFuncs) { + f(dv, index, f.name.indexOf("Big") !== -1 ? 10n : 10); + } + } + +} +test(); diff --git a/test/js/bun/jsc-stress/jsc-stress.test.ts b/test/js/bun/jsc-stress/jsc-stress.test.ts index 9ee07adfdf61..393bf706e007 100644 --- a/test/js/bun/jsc-stress/jsc-stress.test.ts +++ b/test/js/bun/jsc-stress/jsc-stress.test.ts @@ -121,6 +121,19 @@ const jsFixtures = [ "varargs-inlined-simple-exit.js", "loop-unrolling.js", "licm-no-pre-header.js", + // DFG/FTL - DataView intrinsics (DataViewGetInt / DataViewGetFloat / + // DataViewSet, including the byteSize == 8 BigInt64 / BigUint64 case added + // in WebKit 317392@main) + "dataview-jit-get.js", + "dataview-jit-set.js", + "dataview-jit-neuter.js", + "dataview-get-cse.js", + "dataview-jit-bounds-checks.js", + "dataview-jit-unaligned-accesses.js", + "dataview-jit-bigint64.js", + "dataview-jit-bigint64-byte-offset.js", + "dataview-jit-bigint64-cse-and-aliasing.js", + "dataview-jit-bigint64-type-check-failures.js", ]; const wasmFixtures = [ diff --git a/test/js/bun/jsc-stress/preload.js b/test/js/bun/jsc-stress/preload.js index b0b991f5d067..67cb0d306afe 100644 --- a/test/js/bun/jsc-stress/preload.js +++ b/test/js/bun/jsc-stress/preload.js @@ -32,3 +32,8 @@ globalThis.fullGC = jsc.fullGC; globalThis.edenGC = jsc.edenGC; globalThis.numberOfDFGCompiles = jsc.numberOfDFGCompiles; globalThis.noDFG = jsc.noFTL; + +// transferArrayBuffer: jsc shell helper that detaches an ArrayBuffer. +globalThis.transferArrayBuffer = buffer => { + buffer.transfer(); +};