2021-05-26 12:53:40 +00:00
|
|
|
// 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
|
|
|
|
|
2021-06-01 12:46:36 +00:00
|
|
|
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
2021-05-26 12:53:40 +00:00
|
|
|
|
2021-05-26 17:01:19 +00:00
|
|
|
const kIterationsCountForICProgression = 20;
|
|
|
|
|
2021-06-16 15:30:35 +00:00
|
|
|
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;
|
2021-05-26 12:53:40 +00:00
|
|
|
|
|
|
|
const type_index = builder.addStruct([
|
2021-06-16 15:30:35 +00:00
|
|
|
{type: field_type, mutability: true},
|
2021-05-26 12:53:40 +00:00
|
|
|
]);
|
|
|
|
|
2021-06-16 15:30:35 +00:00
|
|
|
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], []);
|
2021-05-26 12:53:40 +00:00
|
|
|
|
2021-06-16 15:30:35 +00:00
|
|
|
builder.addFunction("new_struct", sig_a_t)
|
2021-05-26 12:53:40 +00:00
|
|
|
.addBody([
|
|
|
|
kExprLocalGet, 0, // --
|
|
|
|
kGCPrefix, kExprRttCanon, type_index, // --
|
|
|
|
kGCPrefix, kExprStructNewWithRtt, type_index]) // --
|
|
|
|
.exportAs("new_struct");
|
|
|
|
|
2021-06-16 15:30:35 +00:00
|
|
|
builder.addFunction("get_field", sig_t_a)
|
2021-05-26 12:53:40 +00:00
|
|
|
.addBody([
|
2021-06-16 15:30:35 +00:00
|
|
|
kExprLocalGet, 0, // --
|
|
|
|
kGCPrefix, kExprRttCanon, type_index, // --
|
|
|
|
kGCPrefix, kExprRefCast, // --
|
|
|
|
kGCPrefix, struct_get_opcode, type_index, 0]) // --
|
2021-05-26 12:53:40 +00:00
|
|
|
.exportAs("get_field");
|
|
|
|
|
2021-06-16 15:30:35 +00:00
|
|
|
builder.addFunction("set_field", sig_v_at)
|
2021-05-26 12:53:40 +00:00
|
|
|
.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;
|
|
|
|
|
2021-06-16 15:30:35 +00:00
|
|
|
// Check that ctor, getter and setter work.
|
|
|
|
let o = new_struct(value1);
|
2021-05-26 12:53:40 +00:00
|
|
|
|
|
|
|
let res;
|
|
|
|
res = get_field(o);
|
2021-06-16 15:30:35 +00:00
|
|
|
assertEquals(value1, res);
|
2021-05-26 12:53:40 +00:00
|
|
|
|
2021-06-16 15:30:35 +00:00
|
|
|
set_field(o, value2);
|
2021-05-26 12:53:40 +00:00
|
|
|
res = get_field(o);
|
2021-06-16 15:30:35 +00:00
|
|
|
assertEquals(value2, res);
|
2021-05-26 12:53:40 +00:00
|
|
|
|
2021-06-16 15:30:35 +00:00
|
|
|
return {new_struct, get_field, set_field};
|
2021-05-26 12:53:40 +00:00
|
|
|
}
|
|
|
|
|
2021-06-16 15:30:35 +00:00
|
|
|
function SimpleStructInterop(field_type, value_generator,
|
|
|
|
value1 = 42, value2 = 111) {
|
|
|
|
const { new_struct, get_field, set_field } =
|
|
|
|
createSimpleStruct(field_type, value1, value2);
|
|
|
|
|
2021-06-24 18:20:22 +00:00
|
|
|
function f(o, value) {
|
2021-05-26 17:01:19 +00:00
|
|
|
for (let i = 0; i < kIterationsCountForICProgression; i++) {
|
2021-06-24 18:20:22 +00:00
|
|
|
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;
|
|
|
|
|
2021-06-16 15:30:35 +00:00
|
|
|
let expected = get_field(o);
|
2021-06-24 18:20:22 +00:00
|
|
|
|
|
|
|
let v = o.$field0;
|
2021-06-16 15:30:35 +00:00
|
|
|
assertEquals(expected, v);
|
|
|
|
|
2021-06-24 18:20:22 +00:00
|
|
|
// "Clear" the field value.
|
|
|
|
set_field(o, value1);
|
|
|
|
assertEquals(value1, get_field(o));
|
|
|
|
|
|
|
|
o.$field0 = value;
|
|
|
|
assertEquals(expected, get_field(o));
|
|
|
|
|
2021-06-11 21:03:30 +00:00
|
|
|
v = o[i];
|
|
|
|
assertEquals(undefined, v);
|
2021-05-26 12:53:40 +00:00
|
|
|
}
|
|
|
|
}
|
2021-06-16 15:30:35 +00:00
|
|
|
// Start collecting feedback from scratch.
|
|
|
|
%ClearFunctionFeedback(f);
|
2021-05-26 12:53:40 +00:00
|
|
|
|
2021-06-16 15:30:35 +00:00
|
|
|
let o = new_struct(value1);
|
2021-05-26 12:53:40 +00:00
|
|
|
|
2021-06-16 15:30:35 +00:00
|
|
|
for (const value of value_generator()) {
|
|
|
|
print("value: " + value);
|
2021-06-24 18:20:22 +00:00
|
|
|
f(o, value);
|
2021-06-16 15:30:35 +00:00
|
|
|
}
|
2021-05-26 12:53:40 +00:00
|
|
|
gc();
|
2021-06-16 15:30:35 +00:00
|
|
|
}
|
|
|
|
|
2021-06-24 18:20:22 +00:00
|
|
|
function MakeValueGenerator(max, ValueConstructor = Number) {
|
|
|
|
return function*() {
|
|
|
|
const max_safe_integer_float = 2**23 - 1;
|
|
|
|
|
|
|
|
yield -max;
|
|
|
|
yield -max - ValueConstructor(1);
|
2021-06-16 15:30:35 +00:00
|
|
|
yield max;
|
2021-06-24 18:20:22 +00:00
|
|
|
yield 0.0;
|
|
|
|
yield -0.0;
|
|
|
|
yield 0n;
|
2021-06-16 15:30:35 +00:00
|
|
|
|
|
|
|
for (let i = 0; i < 10; i++) {
|
2021-06-24 18:20:22 +00:00
|
|
|
yield ValueConstructor(Math.floor((Math.random() - 0.5) * Number(max)));
|
2021-06-16 15:30:35 +00:00
|
|
|
}
|
2021-06-24 18:20:22 +00:00
|
|
|
|
|
|
|
// 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));
|
2021-06-16 15:30:35 +00:00
|
|
|
})();
|
|
|
|
|
|
|
|
(function TestSimpleStructsInteropI16() {
|
2021-06-24 18:20:22 +00:00
|
|
|
const max = 0x7fff;
|
|
|
|
SimpleStructInterop(kWasmI16, MakeValueGenerator(max));
|
2021-06-16 15:30:35 +00:00
|
|
|
})();
|
|
|
|
|
|
|
|
(function TestSimpleStructsInteropI32() {
|
2021-06-24 18:20:22 +00:00
|
|
|
const max = 0x7fffffff;
|
|
|
|
SimpleStructInterop(kWasmI32, MakeValueGenerator(max));
|
2021-06-16 15:30:35 +00:00
|
|
|
})();
|
|
|
|
|
|
|
|
(function TestSimpleStructsInteropI64() {
|
2021-06-24 18:20:22 +00:00
|
|
|
const max = 0x7fffffffffffffn;
|
|
|
|
SimpleStructInterop(kWasmI64, MakeValueGenerator(max, BigInt), 42n, 153n);
|
2021-06-16 15:30:35 +00:00
|
|
|
})();
|
|
|
|
|
|
|
|
(function TestSimpleStructsInteropF32() {
|
2021-06-24 18:20:22 +00:00
|
|
|
const max = 3.402823466e+38;
|
|
|
|
SimpleStructInterop(kWasmF32, MakeValueGenerator(max));
|
2021-06-16 15:30:35 +00:00
|
|
|
})();
|
|
|
|
|
|
|
|
(function TestSimpleStructsInteropF64() {
|
2021-06-24 18:20:22 +00:00
|
|
|
const max = 1.7976931348623157e+308;
|
|
|
|
SimpleStructInterop(kWasmF64, MakeValueGenerator(max));
|
2021-05-26 12:53:40 +00:00
|
|
|
})();
|