[wasm] Allow initialization of anyref tables
New spec changes allow anyref tables to be initialized with function references. R=mstarzinger@chromium.org Bug: v8:7581 Change-Id: I59596e1e383408114b974fa10529ae15b8cf7a15 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1627348 Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Commit-Queue: Andreas Haas <ahaas@chromium.org> Cr-Commit-Position: refs/heads/master@{#61823}
This commit is contained in:
parent
50ec11f157
commit
d964a1b10e
@ -808,7 +808,8 @@ class ModuleDecoderImpl : public Decoder {
|
||||
errorf(pos, "out of bounds table index %u", table_index);
|
||||
break;
|
||||
}
|
||||
if (module_->tables[table_index].type != kWasmAnyFunc) {
|
||||
if (!ValueTypes::IsSubType(module_->tables[table_index].type,
|
||||
kWasmAnyFunc)) {
|
||||
errorf(pos,
|
||||
"Invalid element segment. Table %u is not of type AnyFunc",
|
||||
table_index);
|
||||
@ -816,7 +817,7 @@ class ModuleDecoderImpl : public Decoder {
|
||||
}
|
||||
} else {
|
||||
ValueType type = consume_reference_type();
|
||||
if (type != kWasmAnyFunc) {
|
||||
if (!ValueTypes::IsSubType(type, kWasmAnyFunc)) {
|
||||
error(pc_ - 1, "invalid element segment type");
|
||||
break;
|
||||
}
|
||||
|
@ -1518,7 +1518,9 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
|
||||
int entry_index = static_cast<int>(dst + i);
|
||||
|
||||
if (func_index == WasmElemSegment::kNullIndex) {
|
||||
IndirectFunctionTableEntry(instance, entry_index).clear();
|
||||
if (table_object->type() == kWasmAnyFunc) {
|
||||
IndirectFunctionTableEntry(instance, entry_index).clear();
|
||||
}
|
||||
WasmTableObject::Set(isolate, table_object, entry_index,
|
||||
isolate->factory()->null_value());
|
||||
continue;
|
||||
@ -1530,29 +1532,40 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
|
||||
// update the dispatch table if the first table of the instance is changed.
|
||||
// For all other tables, function calls do not use a dispatch table at
|
||||
// the moment.
|
||||
if (elem_segment.table_index == 0) {
|
||||
if (elem_segment.table_index == 0 && table_object->type() == kWasmAnyFunc) {
|
||||
uint32_t sig_id = module->signature_ids[function->sig_index];
|
||||
IndirectFunctionTableEntry(instance, entry_index)
|
||||
.Set(sig_id, instance, func_index);
|
||||
}
|
||||
|
||||
// Update the table object's other dispatch tables.
|
||||
MaybeHandle<WasmExportedFunction> wasm_exported_function =
|
||||
WasmInstanceObject::GetWasmExportedFunction(isolate, instance,
|
||||
func_index);
|
||||
if (wasm_exported_function.is_null()) {
|
||||
// No JSFunction entry yet exists for this function. Create a {Tuple2}
|
||||
// holding the information to lazily allocate one.
|
||||
WasmTableObject::SetFunctionTablePlaceholder(
|
||||
isolate, table_object, entry_index, instance, func_index);
|
||||
// For AnyRef tables, we have to generate the WasmExportedFunction eagerly.
|
||||
// Later we cannot know if an entry is a placeholder or not.
|
||||
if (table_object->type() == kWasmAnyRef) {
|
||||
Handle<WasmExportedFunction> wasm_exported_function =
|
||||
WasmInstanceObject::GetOrCreateWasmExportedFunction(isolate, instance,
|
||||
func_index);
|
||||
WasmTableObject::Set(isolate, table_object, entry_index,
|
||||
wasm_exported_function);
|
||||
} else {
|
||||
table_object->entries().set(entry_index,
|
||||
*wasm_exported_function.ToHandleChecked());
|
||||
// Update the table object's other dispatch tables.
|
||||
MaybeHandle<WasmExportedFunction> wasm_exported_function =
|
||||
WasmInstanceObject::GetWasmExportedFunction(isolate, instance,
|
||||
func_index);
|
||||
if (wasm_exported_function.is_null()) {
|
||||
// No JSFunction entry yet exists for this function. Create a {Tuple2}
|
||||
// holding the information to lazily allocate one.
|
||||
WasmTableObject::SetFunctionTablePlaceholder(
|
||||
isolate, table_object, entry_index, instance, func_index);
|
||||
} else {
|
||||
table_object->entries().set(entry_index,
|
||||
*wasm_exported_function.ToHandleChecked());
|
||||
}
|
||||
// UpdateDispatchTables() updates all other dispatch tables, since
|
||||
// we have not yet added the dispatch table we are currently building.
|
||||
WasmTableObject::UpdateDispatchTables(isolate, table_object, entry_index,
|
||||
function->sig, instance,
|
||||
func_index);
|
||||
}
|
||||
// UpdateDispatchTables() updates all other dispatch tables, since
|
||||
// we have not yet added the dispatch table we are currently building.
|
||||
WasmTableObject::UpdateDispatchTables(isolate, table_object, entry_index,
|
||||
function->sig, instance, func_index);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
@ -6,28 +6,31 @@
|
||||
|
||||
load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
const value1 = 11;
|
||||
const value2 = 22;
|
||||
const value3 = 46;
|
||||
const value4 = 57;
|
||||
const value5 = 13;
|
||||
(function TestInitMultipleTables() {
|
||||
print(arguments.callee.name);
|
||||
|
||||
// The offsets for the initialization of tables. The segement for table2 should
|
||||
// overlap with the segment of table1, because table2 is actually the imported
|
||||
// table1.
|
||||
const offset1 = 2;
|
||||
const offset2 = offset1 + 1;
|
||||
const offset3 = 4;
|
||||
const offset4 = 1;
|
||||
const value1 = 11;
|
||||
const value2 = 22;
|
||||
const value3 = 46;
|
||||
const value4 = 57;
|
||||
const value5 = 13;
|
||||
|
||||
const instance_for_import = (function() {
|
||||
// The offsets for the initialization of tables. The segement for table2 should
|
||||
// overlap with the segment of table1, because table2 is actually the imported
|
||||
// table1.
|
||||
const offset1 = 2;
|
||||
const offset2 = offset1 + 1;
|
||||
const offset3 = 4;
|
||||
const offset4 = 1;
|
||||
|
||||
const instance_for_import = (function () {
|
||||
const builder_for_import = new WasmModuleBuilder();
|
||||
const t1 = builder_for_import.addTable(kWasmAnyFunc, 15, 15)
|
||||
.exportAs("table").index;
|
||||
.exportAs("table").index;
|
||||
const f1 = builder_for_import.addFunction('f1', kSig_i_v)
|
||||
.addBody([kExprI32Const, value1]).index;
|
||||
.addBody([kExprI32Const, value1]).index;
|
||||
const f2 = builder_for_import.addFunction('f2', kSig_i_v)
|
||||
.addBody([kExprI32Const, value2]).index;
|
||||
.addBody([kExprI32Const, value2]).index;
|
||||
|
||||
builder_for_import.addElementSegment(t1, offset1, false, [f1, f2]);
|
||||
const instance_for_import = builder_for_import.instantiate();
|
||||
@ -35,42 +38,61 @@ const instance_for_import = (function() {
|
||||
assertEquals(value1, table1.get(offset1)());
|
||||
assertEquals(value2, table1.get(offset1 + 1)());
|
||||
return instance_for_import;
|
||||
})();
|
||||
|
||||
const builder = new WasmModuleBuilder();
|
||||
|
||||
const t2 = builder.addImportedTable("exports", "table", 15, 15);
|
||||
builder.addExportOfKind("table2", kExternalTable, t2);
|
||||
const t3 = builder.addTable(kWasmAnyFunc, 10).exportAs("table3").index;
|
||||
const t4 = builder.addTable(kWasmAnyFunc, 12).exportAs("table4").index;
|
||||
|
||||
const f3 = builder.addFunction('f3', kSig_i_v)
|
||||
.addBody([kExprI32Const, value3]).index;
|
||||
const f4 = builder.addFunction('f4', kSig_i_v)
|
||||
.addBody([kExprI32Const, value4]).index;
|
||||
const f5 = builder.addFunction('f5', kSig_i_v)
|
||||
.addBody([kExprI32Const, value5]).index;
|
||||
|
||||
|
||||
builder.addElementSegment(t2, offset2, false, [f3, f4]);
|
||||
builder.addElementSegment(t3, offset3, false, [f5, f4]);
|
||||
builder.addElementSegment(t4, offset4, false, [f3, f5]);
|
||||
// Add one more overlapping offset
|
||||
builder.addElementSegment(t4, offset4 + 1, false, [f4, f3]);
|
||||
|
||||
const instance = builder.instantiate(instance_for_import);
|
||||
// table2 == table1
|
||||
const table2 = instance.exports.table2;
|
||||
const table3 = instance.exports.table3;
|
||||
const table4 = instance.exports.table4;
|
||||
// table1 == table2
|
||||
assertEquals(value1, table2.get(offset1)());
|
||||
assertEquals(value3, table2.get(offset2)());
|
||||
assertEquals(value4, table2.get(offset2 + 1)());
|
||||
|
||||
assertEquals(value5, table3.get(offset3)());
|
||||
assertEquals(value4, table3.get(offset3 + 1)());
|
||||
|
||||
assertEquals(value3, table4.get(offset4)());
|
||||
assertEquals(value4, table4.get(offset4 + 1)());
|
||||
assertEquals(value3, table4.get(offset4 + 2)());
|
||||
})();
|
||||
|
||||
const builder = new WasmModuleBuilder();
|
||||
(function TestAnyRefTableWithAnyFuncInit() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
const table = builder.addTable(kWasmAnyRef, 5).index;
|
||||
builder.addExportOfKind("table", kExternalTable, table);
|
||||
const f1 = builder.addFunction('f1', kSig_i_v)
|
||||
.addBody([kExprI32Const, 11])
|
||||
.exportFunc().index;
|
||||
const f2 = builder.addFunction('f2', kSig_i_v)
|
||||
.addBody([kExprI32Const, 22])
|
||||
.exportFunc().index;
|
||||
|
||||
const t2 = builder.addImportedTable("exports", "table", 15, 15);
|
||||
builder.addExportOfKind("table2", kExternalTable, t2);
|
||||
const t3 = builder.addTable(kWasmAnyFunc, 10).exportAs("table3").index;
|
||||
const t4 = builder.addTable(kWasmAnyFunc, 12).exportAs("table4").index;
|
||||
|
||||
const f3 = builder.addFunction('f3', kSig_i_v)
|
||||
.addBody([kExprI32Const, value3]).index;
|
||||
const f4 = builder.addFunction('f4', kSig_i_v)
|
||||
.addBody([kExprI32Const, value4]).index;
|
||||
const f5 = builder.addFunction('f5', kSig_i_v)
|
||||
.addBody([kExprI32Const, value5]).index;
|
||||
|
||||
|
||||
builder.addElementSegment(t2, offset2, false, [f3, f4]);
|
||||
builder.addElementSegment(t3, offset3, false, [f5, f4]);
|
||||
builder.addElementSegment(t4, offset4, false, [f3, f5]);
|
||||
// Add one more overlapping offset
|
||||
builder.addElementSegment(t4, offset4 + 1, false, [f4, f3]);
|
||||
|
||||
const instance = builder.instantiate(instance_for_import);
|
||||
// table2 == table1
|
||||
const table2 = instance.exports.table2;
|
||||
const table3 = instance.exports.table3;
|
||||
const table4 = instance.exports.table4;
|
||||
// table1 == table2
|
||||
assertEquals(value1, table2.get(offset1)());
|
||||
assertEquals(value3, table2.get(offset2)());
|
||||
assertEquals(value4, table2.get(offset2 + 1)());
|
||||
|
||||
assertEquals(value5, table3.get(offset3)());
|
||||
assertEquals(value4, table3.get(offset3 + 1)());
|
||||
|
||||
assertEquals(value3, table4.get(offset4)());
|
||||
assertEquals(value4, table4.get(offset4 + 1)());
|
||||
assertEquals(value3, table4.get(offset4 + 2)());
|
||||
builder.addElementSegment(table, 1, false, [f1, f2]);
|
||||
const instance = builder.instantiate();
|
||||
assertEquals(instance.exports.table.get(1)(), 11);
|
||||
assertEquals(instance.exports.table.get(2)(), 22);
|
||||
})();
|
||||
|
@ -1225,7 +1225,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMixedTablesArbitraryOrder) {
|
||||
EXPECT_VERIFIES(data);
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefTable) {
|
||||
TEST_F(WasmModuleVerifyTest, ElementSectionInitAnyRefTableWithAnyFunc) {
|
||||
// Test that tables of type 'AnyRef' cannot be initialized by the element
|
||||
// section.
|
||||
WASM_FEATURE_SCOPE(anyref);
|
||||
@ -1251,9 +1251,11 @@ TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefTable) {
|
||||
2, // elements count
|
||||
FUNC_INDEX(0), // entry 0
|
||||
FUNC_INDEX(0)), // entry 1
|
||||
// code ----------------------------------------------------------------
|
||||
ONE_EMPTY_BODY,
|
||||
};
|
||||
|
||||
EXPECT_FAILURE(data);
|
||||
EXPECT_VERIFIES(data);
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefImportedTable) {
|
||||
|
Loading…
Reference in New Issue
Block a user