// Copyright 2021 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Flags: --allow-natives-syntax --experimental-wasm-gc --wasm-gc-js-interop // Flags: --expose-gc d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); const kIterationsCountForICProgression = 20; function createSimpleStruct(field_type, value1, value2) { const builder = new WasmModuleBuilder(); const is_small_int = (field_type == kWasmI8) || (field_type == kWasmI16); const parameter_type = is_small_int ? kWasmI32 : field_type; const struct_get_opcode = is_small_int ? kExprStructGetS : kExprStructGet; const type_index = builder.addStruct([ {type: field_type, mutability: true}, ]); let sig_a_t = makeSig_r_x(kWasmDataRef, parameter_type); let sig_t_a = makeSig_r_x(parameter_type, kWasmDataRef); let sig_v_at = makeSig([kWasmDataRef, parameter_type], []); builder.addFunction("new_struct", sig_a_t) .addBody([ kExprLocalGet, 0, // -- kGCPrefix, kExprRttCanon, type_index, // -- kGCPrefix, kExprStructNewWithRtt, type_index]) // -- .exportAs("new_struct"); builder.addFunction("get_field", sig_t_a) .addBody([ kExprLocalGet, 0, // -- kGCPrefix, kExprRttCanon, type_index, // -- kGCPrefix, kExprRefCast, // -- kGCPrefix, struct_get_opcode, type_index, 0]) // -- .exportAs("get_field"); builder.addFunction("set_field", sig_v_at) .addBody([ kExprLocalGet, 0, // -- kGCPrefix, kExprRttCanon, type_index, // -- kGCPrefix, kExprRefCast, // -- kExprLocalGet, 1, // -- kGCPrefix, kExprStructSet, type_index, 0]) // -- .exportAs("set_field"); let instance = builder.instantiate(); let new_struct = instance.exports.new_struct; let get_field = instance.exports.get_field; let set_field = instance.exports.set_field; // Check that ctor, getter and setter work. let o = new_struct(value1); let res; res = get_field(o); assertEquals(value1, res); set_field(o, value2); res = get_field(o); assertEquals(value2, res); return {new_struct, get_field, set_field}; } function SimpleStructInterop(field_type, value_generator, value1 = 42, value2 = 111) { const { new_struct, get_field, set_field } = createSimpleStruct(field_type, value1, value2); function f(o, value) { for (let i = 0; i < kIterationsCountForICProgression; i++) { let store_IC_exception; try { o.$field0 = value; } catch (e) { store_IC_exception = e; } let set_field_exception; try { set_field(o, value); } catch (e) { set_field_exception = e; }; // set_field() and store IC should throw the same error at the same time. assertEquals(set_field_exception, store_IC_exception); if (set_field_exception != undefined) continue; let expected = get_field(o); let v = o.$field0; assertEquals(expected, v); // "Clear" the field value. set_field(o, value1); assertEquals(value1, get_field(o)); o.$field0 = value; assertEquals(expected, get_field(o)); v = o[i]; assertEquals(undefined, v); } } // Start collecting feedback from scratch. %ClearFunctionFeedback(f); let o = new_struct(value1); for (const value of value_generator()) { print("value: " + value); f(o, value); } gc(); } function MakeValueGenerator(max, ValueConstructor = Number) { return function*() { const max_safe_integer_float = 2**23 - 1; yield -max; yield -max - ValueConstructor(1); yield max; yield 0.0; yield -0.0; yield 0n; for (let i = 0; i < 10; i++) { yield ValueConstructor(Math.floor((Math.random() - 0.5) * Number(max))); } // Try some non-trivial values. yield 153; yield 77n; yield ValueConstructor(Number.MAX_SAFE_INTEGER); yield ValueConstructor(Number.MIN_SAFE_INTEGER); yield ValueConstructor(max_safe_integer_float); yield { foo:17 }; yield "boom"; yield { valueOf() { return 42; } }; yield { valueOf() { return 15142n; } }; yield { valueOf() { return BigInt(max); } }; yield { toString() { return "" + max; } }; yield { toString() { return "" + (-max); } }; yield { toString() { return "5421351n"; } }; }; } (function TestSimpleStructsInteropI8() { const max = 0x7f; SimpleStructInterop(kWasmI8, MakeValueGenerator(max)); })(); (function TestSimpleStructsInteropI16() { const max = 0x7fff; SimpleStructInterop(kWasmI16, MakeValueGenerator(max)); })(); (function TestSimpleStructsInteropI32() { const max = 0x7fffffff; SimpleStructInterop(kWasmI32, MakeValueGenerator(max)); })(); (function TestSimpleStructsInteropI64() { const max = 0x7fffffffffffffn; SimpleStructInterop(kWasmI64, MakeValueGenerator(max, BigInt), 42n, 153n); })(); (function TestSimpleStructsInteropF32() { const max = 3.402823466e+38; SimpleStructInterop(kWasmF32, MakeValueGenerator(max)); })(); (function TestSimpleStructsInteropF64() { const max = 1.7976931348623157e+308; SimpleStructInterop(kWasmF64, MakeValueGenerator(max)); })();