6168782925
Per https://github.com/WebAssembly/function-references/pull/76, call_ref and return_call_ref should consume type immediates specifying the signature of the funcref. This is a breaking change. To ease the migration, this patch introduces a temporary alternative binary encoding for call_ref: - 0x14 continues to *not* take a type immediate for now. - 0x17 (formerly "let") is the new call_ref *with* type immediate. Module producers are encouraged to emit this encoding ASAP. - After a few weeks of transitionary period, we'll update 0x14 to take a type immediate as well. At this point, module producers will be encouraged to switch back to 0x14. - After a few more weeks of transitionary period, we'll drop 0x17 again. We're not doing the same dance for return_call_ref because it currently has no uses that we know of. Bug: v8:7748,v8:9495 Change-Id: Id8d468be3949f84571efff713c937ffd1addff70 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3863280 Reviewed-by: Matthias Liedtke <mliedtke@chromium.org> Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Auto-Submit: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/main@{#82839}
232 lines
8.0 KiB
JavaScript
232 lines
8.0 KiB
JavaScript
// Copyright 2019 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: --experimental-wasm-typed-funcref --experimental-wasm-type-reflection
|
|
|
|
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
|
|
|
(function TestExternRefTableSetWithMultipleTypes() {
|
|
print(arguments.callee.name);
|
|
let table = new WebAssembly.Table({element: "externref", initial: 10});
|
|
|
|
// Table should be initialized with undefined.
|
|
assertEquals(undefined, table.get(1));
|
|
let obj = {'hello' : 'world'};
|
|
table.set(2, obj);
|
|
assertSame(obj, table.get(2));
|
|
table.set(3, 1234);
|
|
assertEquals(1234, table.get(3));
|
|
table.set(4, 123.5);
|
|
assertEquals(123.5, table.get(4));
|
|
table.set(5, undefined);
|
|
assertEquals(undefined, table.get(5));
|
|
// Overwrite entry 4, because null would otherwise be the default value.
|
|
table.set(4, null);
|
|
assertEquals(null, table.get(4));
|
|
table.set(7, print);
|
|
assertEquals(print, table.get(7));
|
|
|
|
assertThrows(() => table.set(12), RangeError);
|
|
})();
|
|
|
|
(function TestImportExternRefTable() {
|
|
print(arguments.callee.name);
|
|
|
|
const builder = new WasmModuleBuilder();
|
|
const table_index = builder.addImportedTable(
|
|
"imp", "table", 3, 10, kWasmExternRef);
|
|
builder.addFunction('get', kSig_r_v)
|
|
.addBody([kExprI32Const, 0, kExprTableGet, table_index]);
|
|
|
|
let table_ref = new WebAssembly.Table(
|
|
{ element: "externref", initial: 3, maximum: 10 });
|
|
builder.instantiate({imp:{table: table_ref}});
|
|
|
|
let table_func = new WebAssembly.Table(
|
|
{ element: "anyfunc", initial: 3, maximum: 10 });
|
|
assertThrows(() => builder.instantiate({ imp: { table: table_func } }),
|
|
WebAssembly.LinkError, /imported table does not match the expected type/);
|
|
})();
|
|
|
|
(function TestExternRefDropDeclarativeElementSegment() {
|
|
print(arguments.callee.name);
|
|
|
|
const builder = new WasmModuleBuilder();
|
|
builder.addDeclarativeElementSegment([[kExprRefNull, kFuncRefCode]],
|
|
kWasmFuncRef);
|
|
builder.addFunction('drop', kSig_v_v)
|
|
.addBody([kNumericPrefix, kExprElemDrop, 0])
|
|
.exportFunc();
|
|
const instance = builder.instantiate();
|
|
|
|
// Counts as double-drop because declarative segments are dropped on
|
|
// initialization and is therefore not expected to throw.
|
|
instance.exports.drop();
|
|
})();
|
|
|
|
(function TestExternRefTableInitFromDeclarativeElementSegment() {
|
|
print(arguments.callee.name);
|
|
|
|
const builder = new WasmModuleBuilder();
|
|
const table = builder.addTable(kWasmAnyFunc, 10);
|
|
builder.addDeclarativeElementSegment([[kExprRefNull, kFuncRefCode]],
|
|
kWasmFuncRef);
|
|
builder.addFunction('init', kSig_v_v)
|
|
.addBody([
|
|
kExprI32Const, 0, kExprI32Const, 0, kExprI32Const, 1, kNumericPrefix,
|
|
kExprTableInit, table.index, 0
|
|
])
|
|
.exportFunc();
|
|
const instance = builder.instantiate();
|
|
|
|
assertTraps(kTrapElementSegmentOutOfBounds, () => instance.exports.init());
|
|
})();
|
|
|
|
(function TestTableInitializer() {
|
|
print(arguments.callee.name);
|
|
|
|
let test = function(is_nullable) {
|
|
const builder = new WasmModuleBuilder();
|
|
const sig = builder.addType(kSig_i_i);
|
|
const func = builder.addFunction("func", kSig_i_i)
|
|
.addBody([kExprLocalGet, 0]);
|
|
builder.addTable(is_nullable ? wasmRefNullType(sig) : wasmRefType(sig),
|
|
10, 10, [kExprRefFunc, func.index]);
|
|
builder.addFunction("main", kSig_i_ii)
|
|
.addBody([kExprLocalGet, 1, kExprLocalGet, 0, kExprTableGet, 0,
|
|
kExprCallRef, sig])
|
|
.exportFunc();
|
|
|
|
const instance = builder.instantiate();
|
|
|
|
assertEquals(1, instance.exports.main(0, 1));
|
|
assertEquals(33, instance.exports.main(5, 33));
|
|
}
|
|
|
|
test(true);
|
|
test(false);
|
|
})();
|
|
|
|
(function TestExternRefTableConstructorWithDefaultValue() {
|
|
print(arguments.callee.name);
|
|
const testObject = {};
|
|
const argument = { "element": "externref", "initial": 3 };
|
|
const table = new WebAssembly.Table(argument, testObject);
|
|
assertEquals(table.length, 3);
|
|
assertEquals(table.get(0), testObject);
|
|
assertEquals(table.get(1), testObject);
|
|
assertEquals(table.get(2), testObject);
|
|
})();
|
|
|
|
function getDummy(val) {
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addFunction('dummy', kSig_i_v)
|
|
.addBody([kExprI32Const, val])
|
|
.exportAs('dummy');
|
|
return builder.instantiate().exports.dummy;
|
|
}
|
|
|
|
(function TestFuncRefTableConstructorWithDefaultValue() {
|
|
print(arguments.callee.name);
|
|
|
|
const expected = 6;
|
|
let dummy = getDummy(expected);
|
|
|
|
const argument = { "element": "anyfunc", "initial": 3 };
|
|
const table = new WebAssembly.Table(argument, dummy);
|
|
assertEquals(table.length, 3);
|
|
assertEquals(table.get(0)(), expected);
|
|
assertEquals(table.get(1)(), expected);
|
|
assertEquals(table.get(2)(), expected);
|
|
})();
|
|
|
|
(function TestExternFuncTableSetWithoutValue() {
|
|
print(arguments.callee.name);
|
|
|
|
const expected = 6;
|
|
const dummy = getDummy(expected);
|
|
const argument = { "element": "anyfunc", "initial": 3 };
|
|
const table = new WebAssembly.Table(argument, dummy);
|
|
assertEquals(table.get(1)(), expected);
|
|
table.set(1);
|
|
assertEquals(table.get(1), null);
|
|
})();
|
|
|
|
(function TestExternRefTableSetWithoutValue() {
|
|
print(arguments.callee.name);
|
|
|
|
const testObject = {};
|
|
const argument = { "element": "externref", "initial": 3 };
|
|
const table = new WebAssembly.Table(argument, testObject);
|
|
assertEquals(table.get(1), testObject);
|
|
table.set(1);
|
|
assertEquals(table.get(1), undefined);
|
|
})();
|
|
|
|
(function TestFunctionExternRefTableRoundtrip() {
|
|
// Test that
|
|
// - initialization, setting, and growing an externref table, and
|
|
// - (imported) externref globals
|
|
// preserve function references.
|
|
print(arguments.callee.name);
|
|
|
|
const js_function = function (i) { return i + 1; };
|
|
const wasm_js_function = new WebAssembly.Function(
|
|
{parameters:['i32', 'i32'], results: ['i32']},
|
|
function(a, b) { return a * b; })
|
|
|
|
let extern_type = wasmRefType(kWasmExternRef);
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
let imported_global = builder.addImportedGlobal('m', 'n', extern_type, false);
|
|
let global = builder.addGlobal(kWasmExternRef, true).exportAs('global');
|
|
let table = builder.addTable(extern_type, 2, 10,
|
|
[kExprGlobalGet, imported_global])
|
|
builder.addFunction(
|
|
'setup', makeSig([extern_type, extern_type], []))
|
|
.addBody([
|
|
kExprLocalGet, 0, kExprGlobalSet, global.index,
|
|
kExprI32Const, 1, kExprLocalGet, 0, kExprTableSet, table.index,
|
|
kExprLocalGet, 1, kExprI32Const, 1, kNumericPrefix,
|
|
kExprTableGrow, table.index, kExprDrop])
|
|
.exportFunc();
|
|
builder.addFunction('get', makeSig([kWasmI32], [kWasmExternRef]))
|
|
.addBody([kExprLocalGet, 0, kExprTableGet, table.index])
|
|
.exportFunc();
|
|
let instance = builder.instantiate({m : {n : js_function}});
|
|
|
|
instance.exports.setup(wasm_js_function, instance.exports.setup);
|
|
|
|
assertEquals(instance.exports.global.value, wasm_js_function);
|
|
assertEquals(instance.exports.get(0), js_function);
|
|
assertEquals(instance.exports.get(1), wasm_js_function);
|
|
assertEquals(instance.exports.get(2), instance.exports.setup);
|
|
})();
|
|
|
|
(function TestFunctionExternRefTableRoundtrip2() {
|
|
// Test that initialization, setting, and growing an externref table in the JS
|
|
// API preserves function references.
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addFunction('dummy', kSig_i_v)
|
|
.addBody([kExprI32Const, 0])
|
|
.exportAs('dummy');
|
|
let instance = builder.instantiate();
|
|
const js_function = function (i) { return i + 1; };
|
|
const wasm_js_function = new WebAssembly.Function(
|
|
{parameters:['i32', 'i32'], results: ['i32']},
|
|
function(a, b) { return a * b; })
|
|
|
|
const argument = { "element": "externref", "initial": 3 };
|
|
const table = new WebAssembly.Table(argument, js_function);
|
|
table.set(1, wasm_js_function);
|
|
table.set(2, instance.exports.dummy);
|
|
table.grow(1, wasm_js_function);
|
|
assertEquals(table.get(0), js_function);
|
|
assertEquals(table.get(1), wasm_js_function);
|
|
assertEquals(table.get(2), instance.exports.dummy);
|
|
assertEquals(table.get(3), wasm_js_function);
|
|
})();
|