From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- js/src/jit-test/tests/wasm/gc/structs2.js | 243 ++++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 js/src/jit-test/tests/wasm/gc/structs2.js (limited to 'js/src/jit-test/tests/wasm/gc/structs2.js') diff --git a/js/src/jit-test/tests/wasm/gc/structs2.js b/js/src/jit-test/tests/wasm/gc/structs2.js new file mode 100644 index 0000000000..25651d7175 --- /dev/null +++ b/js/src/jit-test/tests/wasm/gc/structs2.js @@ -0,0 +1,243 @@ +// |jit-test| skip-if: !wasmGcEnabled(); test-also=--gc-zeal=2 + +// This tests 8- and 16-bit field accesses for structs. + +// Check that struct.new writes for 8-bit fields do not overwrite subsequent +// data. Because the writes happen forwards in the address space, the only +// way I could think to do this is to force an 8-bit field to occupy the last +// byte of the OOL malloc'd block, and then hope that ASan runs in automation +// will pick up any overrun. I think it's impossible to test this from inside +// the JS+wasm universe. Hence the test is pretty pointless from a purely +// JS+wasm interpretation. +{ + let txt = + `(module + (type $hasOOL (struct + ;; In-line storage; 16 fields that preserve 16-alignment + (field i64) (field i64) (field i64) (field i64) ;; 32 + (field i64) (field i64) (field i64) (field i64) ;; 64 + (field i64) (field i64) (field i64) (field i64) ;; 96 + (field i64) (field i64) (field i64) (field i64) ;; 128 + ;; Out-of-line storage (or maybe it starts earlier, but + ;; definitely not after this point). 16 bytes on the + ;; basis that StructLayout::close will round the requested + ;; block size up to at max the next 16 byte boundary. + ;; The goal is that the last (field i8) is right at the + ;; end of the resulting malloc'd block, so that, if the + ;; struct.new initialisation code mistakenly initialises + ;; that field with a write larger than 8 bits, then we'll + ;; have a write off the end of the malloc'd block, which + ;; ASan automation runs should detect. + (field i8) (field i8) (field i8) (field i8) + (field i8) (field i8) (field i8) (field i8) + (field i8) (field i8) (field i8) (field i8) + (field i8) (field i8) (field i8) (field i8)) + ) + (func (export "build8") + (param $filler i64) (param $interesting i32) (result eqref) + (struct.new $hasOOL + (local.get $filler) (local.get $filler) + (local.get $filler) (local.get $filler) + (local.get $filler) (local.get $filler) + (local.get $filler) (local.get $filler) + (local.get $filler) (local.get $filler) + (local.get $filler) (local.get $filler) + (local.get $filler) (local.get $filler) + (local.get $filler) (local.get $filler) + (local.get $interesting) (local.get $interesting) + (local.get $interesting) (local.get $interesting) + (local.get $interesting) (local.get $interesting) + (local.get $interesting) (local.get $interesting) + (local.get $interesting) (local.get $interesting) + (local.get $interesting) (local.get $interesting) + (local.get $interesting) (local.get $interesting) + (local.get $interesting) (local.get $interesting) + ) + ) + )`; + let exports = wasmEvalText(txt).exports; + let obj8 = exports.build8(0x1234n, 0x5678); + // The above call should trigger OOB writes if the struct.new field + // writes are too large, but those will only be visible if we're running + // on ASan or Valgrind. In any case, add a fake data dependency below, so + // that the construction of the object can't (so easily) be optimised away. + assertEq(wasmGcReadField(obj8, 0) + BigInt(wasmGcReadField(obj8, 31)), 0x12ACn); // == 0x1234 + 0x78 +} + +// And exactly the same, except for 16 bit fields. +{ + let txt = + `(module + (type $hasOOL (struct + ;; in-line storage + (field i64) (field i64) (field i64) (field i64) ;; 32 + (field i64) (field i64) (field i64) (field i64) ;; 64 + (field i64) (field i64) (field i64) (field i64) ;; 96 + (field i64) (field i64) (field i64) (field i64) ;; 128 + (field i16) (field i16) (field i16) (field i16) + (field i16) (field i16) (field i16) (field i16)) + ) + (func (export "build16") + (param $filler i64) (param $interesting i32) (result eqref) + (struct.new $hasOOL + (local.get $filler) (local.get $filler) + (local.get $filler) (local.get $filler) + (local.get $filler) (local.get $filler) + (local.get $filler) (local.get $filler) + (local.get $filler) (local.get $filler) + (local.get $filler) (local.get $filler) + (local.get $filler) (local.get $filler) + (local.get $filler) (local.get $filler) + (local.get $interesting) (local.get $interesting) + (local.get $interesting) (local.get $interesting) + (local.get $interesting) (local.get $interesting) + (local.get $interesting) (local.get $interesting) + ) + ) + )`; + let exports = wasmEvalText(txt).exports; + let obj16 = exports.build16(0x4321n, 0x7865); + assertEq(wasmGcReadField(obj16, 0) + BigInt(wasmGcReadField(obj16, 23)), 0xBB86n); // == 0x4321 + 0x7865 +} + +// Test that 8-bit field writes do not overwrite adjacent fields. +{ + let txt = + `(module + (type $struct8x8 + (struct (field i8) (field i8) (field i8) (field (mut i8)) + (field i8) (field i8) (field i8) (field i8) + )) + (func (export "create") (result eqref) + (struct.new $struct8x8 (i32.const 0x55) (i32.const 0x55) + (i32.const 0x55) (i32.const 0x55) + (i32.const 0x55) (i32.const 0x55) + (i32.const 0x55) (i32.const 0x55) + )) + (func (export "writeField8x8_3") (param $p eqref) (param $v i32) + (struct.set $struct8x8 3 (ref.cast (ref null $struct8x8) (local.get $p)) + (local.get $v)) + ) + )`; + let exports = wasmEvalText(txt).exports; + let theObject = exports.create(); + exports.writeField8x8_3(theObject, 0x77); + assertEq(wasmGcReadField(theObject, 0), 0x55); + assertEq(wasmGcReadField(theObject, 1), 0x55); + assertEq(wasmGcReadField(theObject, 2), 0x55); + assertEq(wasmGcReadField(theObject, 3), 0x77); + assertEq(wasmGcReadField(theObject, 4), 0x55); + assertEq(wasmGcReadField(theObject, 5), 0x55); + assertEq(wasmGcReadField(theObject, 6), 0x55); + assertEq(wasmGcReadField(theObject, 7), 0x55); +} + +// Test that 16-bit field writes do not overwrite adjacent fields. +{ + let txt = + `(module + (type $struct16x8 + (struct (field i16) (field i16) (field i16) (field (mut i16)) + (field i16) (field i16) (field i16) (field i16) + )) + (func (export "create") (result eqref) + (struct.new $struct16x8 (i32.const 0x5555) (i32.const 0x5555) + (i32.const 0x5555) (i32.const 0x5555) + (i32.const 0x5555) (i32.const 0x5555) + (i32.const 0x5555) (i32.const 0x5555) + )) + (func (export "writeField16x8_3") (param $p eqref) (param $v i32) + (struct.set $struct16x8 3 (ref.cast (ref null $struct16x8) (local.get $p)) + (local.get $v)) + ) + )`; + let exports = wasmEvalText(txt).exports; + let theObject = exports.create(); + exports.writeField16x8_3(theObject, 0x7766); + assertEq(wasmGcReadField(theObject, 0), 0x5555); + assertEq(wasmGcReadField(theObject, 1), 0x5555); + assertEq(wasmGcReadField(theObject, 2), 0x5555); + assertEq(wasmGcReadField(theObject, 3), 0x7766); + assertEq(wasmGcReadField(theObject, 4), 0x5555); + assertEq(wasmGcReadField(theObject, 5), 0x5555); + assertEq(wasmGcReadField(theObject, 6), 0x5555); + assertEq(wasmGcReadField(theObject, 7), 0x5555); +} + +// Test that 8-bit field reads sign/zero extend correctly. +{ + let txt = + `(module + (type $struct8x8 + (struct (field i8) (field i8) (field i8) (field i8) + (field i8) (field i8) (field i8) (field i8) + )) + (func (export "create") (result eqref) + (struct.new $struct8x8 (i32.const 0x11) (i32.const 0x82) + (i32.const 0x23) (i32.const 0x94) + (i32.const 0x35) (i32.const 0xA6) + (i32.const 0x47) (i32.const 0xB8) + )) + ;; read i8 from a field, unsigned extend, read value has top bit 0 + (func (export "readU8hi0") (param $p eqref) (result i32) + (struct.get_u $struct8x8 2 (ref.cast (ref null $struct8x8) (local.get $p))) + ) + ;; read i8 from a field, unsigned extend, read value has top bit 1 + (func (export "readU8hi1") (param $p eqref) (result i32) + (struct.get_u $struct8x8 3 (ref.cast (ref null $struct8x8) (local.get $p))) + ) + ;; read i8 from a field, signed extend, read value has top bit 0 + (func (export "readS8hi0") (param $p eqref) (result i32) + (struct.get_s $struct8x8 4 (ref.cast (ref null $struct8x8) (local.get $p))) + ) + ;; read i8 from a field, signed extend, read value has top bit 1 + (func (export "readS8hi1") (param $p eqref) (result i32) + (struct.get_s $struct8x8 5 (ref.cast (ref null $struct8x8) (local.get $p))) + ) + )`; + let exports = wasmEvalText(txt).exports; + let theObject = exports.create(); + assertEq(exports.readU8hi0(theObject), 0x23); // zx of 0x23 + assertEq(exports.readU8hi1(theObject), 0x94); // zx of 0x94 + assertEq(exports.readS8hi0(theObject), 0x35); // sx of 0x35 + assertEq(exports.readS8hi1(theObject), -0x5A); // sx of 0xA6 +} + +// Test that 16-bit field reads sign/zero extend correctly. +{ + let txt = + `(module + (type $struct16x8 + (struct (field i16) (field i16) (field i16) (field i16) + (field i16) (field i16) (field i16) (field i16) + )) + (func (export "create") (result eqref) + (struct.new $struct16x8 (i32.const 0x11FF) (i32.const 0x82FE) + (i32.const 0x23FD) (i32.const 0x94FC) + (i32.const 0x35FB) (i32.const 0xA6FA) + (i32.const 0x47F9) (i32.const 0xB8F8) + )) + ;; read i16 from a field, unsigned extend, read value has top bit 0 + (func (export "readU16hi0") (param $p eqref) (result i32) + (struct.get_u $struct16x8 2 (ref.cast (ref null $struct16x8) (local.get $p))) + ) + ;; read i16 from a field, unsigned extend, read value has top bit 1 + (func (export "readU16hi1") (param $p eqref) (result i32) + (struct.get_u $struct16x8 3 (ref.cast (ref null $struct16x8) (local.get $p))) + ) + ;; read i16 from a field, signed extend, read value has top bit 0 + (func (export "readS16hi0") (param $p eqref) (result i32) + (struct.get_s $struct16x8 4 (ref.cast (ref null $struct16x8) (local.get $p))) + ) + ;; read i16 from a field, signed extend, read value has top bit 1 + (func (export "readS16hi1") (param $p eqref) (result i32) + (struct.get_s $struct16x8 5 (ref.cast (ref null $struct16x8) (local.get $p))) + ) + )`; + let exports = wasmEvalText(txt).exports; + let theObject = exports.create(); + assertEq(exports.readU16hi0(theObject), 0x23FD); // zx of 0x23FD + assertEq(exports.readU16hi1(theObject), 0x94FC); // zx of 0x94FC + assertEq(exports.readS16hi0(theObject), 0x35FB); // sx of 0x35FB + assertEq(exports.readS16hi1(theObject), -0x5906); // sx of 0xA6FC +} -- cgit v1.2.3