Commit d964a1b1 authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[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/+/1627348Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61823}
parent 50ec11f1
...@@ -808,7 +808,8 @@ class ModuleDecoderImpl : public Decoder { ...@@ -808,7 +808,8 @@ class ModuleDecoderImpl : public Decoder {
errorf(pos, "out of bounds table index %u", table_index); errorf(pos, "out of bounds table index %u", table_index);
break; break;
} }
if (module_->tables[table_index].type != kWasmAnyFunc) { if (!ValueTypes::IsSubType(module_->tables[table_index].type,
kWasmAnyFunc)) {
errorf(pos, errorf(pos,
"Invalid element segment. Table %u is not of type AnyFunc", "Invalid element segment. Table %u is not of type AnyFunc",
table_index); table_index);
...@@ -816,7 +817,7 @@ class ModuleDecoderImpl : public Decoder { ...@@ -816,7 +817,7 @@ class ModuleDecoderImpl : public Decoder {
} }
} else { } else {
ValueType type = consume_reference_type(); ValueType type = consume_reference_type();
if (type != kWasmAnyFunc) { if (!ValueTypes::IsSubType(type, kWasmAnyFunc)) {
error(pc_ - 1, "invalid element segment type"); error(pc_ - 1, "invalid element segment type");
break; break;
} }
......
...@@ -1518,7 +1518,9 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance, ...@@ -1518,7 +1518,9 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
int entry_index = static_cast<int>(dst + i); int entry_index = static_cast<int>(dst + i);
if (func_index == WasmElemSegment::kNullIndex) { if (func_index == WasmElemSegment::kNullIndex) {
if (table_object->type() == kWasmAnyFunc) {
IndirectFunctionTableEntry(instance, entry_index).clear(); IndirectFunctionTableEntry(instance, entry_index).clear();
}
WasmTableObject::Set(isolate, table_object, entry_index, WasmTableObject::Set(isolate, table_object, entry_index,
isolate->factory()->null_value()); isolate->factory()->null_value());
continue; continue;
...@@ -1530,12 +1532,21 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance, ...@@ -1530,12 +1532,21 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
// update the dispatch table if the first table of the instance is changed. // 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 // For all other tables, function calls do not use a dispatch table at
// the moment. // 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]; uint32_t sig_id = module->signature_ids[function->sig_index];
IndirectFunctionTableEntry(instance, entry_index) IndirectFunctionTableEntry(instance, entry_index)
.Set(sig_id, instance, func_index); .Set(sig_id, 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 {
// Update the table object's other dispatch tables. // Update the table object's other dispatch tables.
MaybeHandle<WasmExportedFunction> wasm_exported_function = MaybeHandle<WasmExportedFunction> wasm_exported_function =
WasmInstanceObject::GetWasmExportedFunction(isolate, instance, WasmInstanceObject::GetWasmExportedFunction(isolate, instance,
...@@ -1552,7 +1563,9 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance, ...@@ -1552,7 +1563,9 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
// UpdateDispatchTables() updates all other dispatch tables, since // UpdateDispatchTables() updates all other dispatch tables, since
// we have not yet added the dispatch table we are currently building. // we have not yet added the dispatch table we are currently building.
WasmTableObject::UpdateDispatchTables(isolate, table_object, entry_index, WasmTableObject::UpdateDispatchTables(isolate, table_object, entry_index,
function->sig, instance, func_index); function->sig, instance,
func_index);
}
} }
return ok; return ok;
} }
......
...@@ -6,21 +6,24 @@ ...@@ -6,21 +6,24 @@
load("test/mjsunit/wasm/wasm-module-builder.js"); load("test/mjsunit/wasm/wasm-module-builder.js");
const value1 = 11; (function TestInitMultipleTables() {
const value2 = 22; print(arguments.callee.name);
const value3 = 46;
const value4 = 57; const value1 = 11;
const value5 = 13; const value2 = 22;
const value3 = 46;
// The offsets for the initialization of tables. The segement for table2 should const value4 = 57;
// overlap with the segment of table1, because table2 is actually the imported const value5 = 13;
// table1.
const offset1 = 2; // The offsets for the initialization of tables. The segement for table2 should
const offset2 = offset1 + 1; // overlap with the segment of table1, because table2 is actually the imported
const offset3 = 4; // table1.
const offset4 = 1; const offset1 = 2;
const offset2 = offset1 + 1;
const instance_for_import = (function() { const offset3 = 4;
const offset4 = 1;
const instance_for_import = (function () {
const builder_for_import = new WasmModuleBuilder(); const builder_for_import = new WasmModuleBuilder();
const t1 = builder_for_import.addTable(kWasmAnyFunc, 15, 15) const t1 = builder_for_import.addTable(kWasmAnyFunc, 15, 15)
.exportAs("table").index; .exportAs("table").index;
...@@ -35,42 +38,61 @@ const instance_for_import = (function() { ...@@ -35,42 +38,61 @@ const instance_for_import = (function() {
assertEquals(value1, table1.get(offset1)()); assertEquals(value1, table1.get(offset1)());
assertEquals(value2, table1.get(offset1 + 1)()); assertEquals(value2, table1.get(offset1 + 1)());
return instance_for_import; return instance_for_import;
})(); })();
const builder = new WasmModuleBuilder(); const builder = new WasmModuleBuilder();
const t2 = builder.addImportedTable("exports", "table", 15, 15); const t2 = builder.addImportedTable("exports", "table", 15, 15);
builder.addExportOfKind("table2", kExternalTable, t2); builder.addExportOfKind("table2", kExternalTable, t2);
const t3 = builder.addTable(kWasmAnyFunc, 10).exportAs("table3").index; const t3 = builder.addTable(kWasmAnyFunc, 10).exportAs("table3").index;
const t4 = builder.addTable(kWasmAnyFunc, 12).exportAs("table4").index; const t4 = builder.addTable(kWasmAnyFunc, 12).exportAs("table4").index;
const f3 = builder.addFunction('f3', kSig_i_v) const f3 = builder.addFunction('f3', kSig_i_v)
.addBody([kExprI32Const, value3]).index; .addBody([kExprI32Const, value3]).index;
const f4 = builder.addFunction('f4', kSig_i_v) const f4 = builder.addFunction('f4', kSig_i_v)
.addBody([kExprI32Const, value4]).index; .addBody([kExprI32Const, value4]).index;
const f5 = builder.addFunction('f5', kSig_i_v) const f5 = builder.addFunction('f5', kSig_i_v)
.addBody([kExprI32Const, value5]).index; .addBody([kExprI32Const, value5]).index;
builder.addElementSegment(t2, offset2, false, [f3, f4]); builder.addElementSegment(t2, offset2, false, [f3, f4]);
builder.addElementSegment(t3, offset3, false, [f5, f4]); builder.addElementSegment(t3, offset3, false, [f5, f4]);
builder.addElementSegment(t4, offset4, false, [f3, f5]); builder.addElementSegment(t4, offset4, false, [f3, f5]);
// Add one more overlapping offset // Add one more overlapping offset
builder.addElementSegment(t4, offset4 + 1, false, [f4, f3]); builder.addElementSegment(t4, offset4 + 1, false, [f4, f3]);
const instance = builder.instantiate(instance_for_import); const instance = builder.instantiate(instance_for_import);
// table2 == table1 // table2 == table1
const table2 = instance.exports.table2; const table2 = instance.exports.table2;
const table3 = instance.exports.table3; const table3 = instance.exports.table3;
const table4 = instance.exports.table4; const table4 = instance.exports.table4;
// table1 == table2 // table1 == table2
assertEquals(value1, table2.get(offset1)()); assertEquals(value1, table2.get(offset1)());
assertEquals(value3, table2.get(offset2)()); assertEquals(value3, table2.get(offset2)());
assertEquals(value4, table2.get(offset2 + 1)()); assertEquals(value4, table2.get(offset2 + 1)());
assertEquals(value5, table3.get(offset3)()); assertEquals(value5, table3.get(offset3)());
assertEquals(value4, table3.get(offset3 + 1)()); assertEquals(value4, table3.get(offset3 + 1)());
assertEquals(value3, table4.get(offset4)()); assertEquals(value3, table4.get(offset4)());
assertEquals(value4, table4.get(offset4 + 1)()); assertEquals(value4, table4.get(offset4 + 1)());
assertEquals(value3, table4.get(offset4 + 2)()); assertEquals(value3, table4.get(offset4 + 2)());
})();
(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;
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) { ...@@ -1225,7 +1225,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMixedTablesArbitraryOrder) {
EXPECT_VERIFIES(data); EXPECT_VERIFIES(data);
} }
TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefTable) { TEST_F(WasmModuleVerifyTest, ElementSectionInitAnyRefTableWithAnyFunc) {
// Test that tables of type 'AnyRef' cannot be initialized by the element // Test that tables of type 'AnyRef' cannot be initialized by the element
// section. // section.
WASM_FEATURE_SCOPE(anyref); WASM_FEATURE_SCOPE(anyref);
...@@ -1251,9 +1251,11 @@ TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefTable) { ...@@ -1251,9 +1251,11 @@ TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefTable) {
2, // elements count 2, // elements count
FUNC_INDEX(0), // entry 0 FUNC_INDEX(0), // entry 0
FUNC_INDEX(0)), // entry 1 FUNC_INDEX(0)), // entry 1
// code ----------------------------------------------------------------
ONE_EMPTY_BODY,
}; };
EXPECT_FAILURE(data); EXPECT_VERIFIES(data);
} }
TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefImportedTable) { TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefImportedTable) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment