Commit cb5c1b8a authored by Manos Koukoutos's avatar Manos Koukoutos Committed by V8 LUCI CQ

[wasm-gc] Implement table-with-initializer encoding

See https://github.com/WebAssembly/function-references/pull/65.

Drive-by: Lower gc nodes also if typed-funcref is enabled.

Bug: v8:9495
Change-Id: I19cb67cdbdedae24b9460bc7d5b280a21a946b21
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3784590Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81956}
parent dc0be4e3
...@@ -3327,6 +3327,11 @@ void Pipeline::GenerateCodeForWasmFunction( ...@@ -3327,6 +3327,11 @@ void Pipeline::GenerateCodeForWasmFunction(
pipeline.Run<WasmGCOptimizationPhase>(module); pipeline.Run<WasmGCOptimizationPhase>(module);
pipeline.RunPrintAndVerify(WasmGCOptimizationPhase::phase_name(), true); pipeline.RunPrintAndVerify(WasmGCOptimizationPhase::phase_name(), true);
} }
}
// These proposals use gc nodes.
if (FLAG_experimental_wasm_gc || FLAG_experimental_wasm_typed_funcref ||
FLAG_experimental_wasm_stringref) {
pipeline.Run<WasmGCLoweringPhase>(); pipeline.Run<WasmGCLoweringPhase>();
pipeline.RunPrintAndVerify(WasmGCLoweringPhase::phase_name(), true); pipeline.RunPrintAndVerify(WasmGCLoweringPhase::phase_name(), true);
} }
......
...@@ -905,6 +905,15 @@ class ModuleDecoderTemplate : public Decoder { ...@@ -905,6 +905,15 @@ class ModuleDecoderTemplate : public Decoder {
module_->tables.emplace_back(); module_->tables.emplace_back();
WasmTable* table = &module_->tables.back(); WasmTable* table = &module_->tables.back();
const byte* type_position = pc(); const byte* type_position = pc();
bool has_initializer = false;
if (enabled_features_.has_typed_funcref() &&
read_u8<Decoder::kFullValidation>(
pc(), "table-with-initializer byte") == 0x40) {
consume_bytes(1, "table-with-initializer byte");
has_initializer = true;
}
ValueType table_type = consume_reference_type(); ValueType table_type = consume_reference_type();
if (!WasmTable::IsValidTableType(table_type, module_.get())) { if (!WasmTable::IsValidTableType(table_type, module_.get())) {
error(type_position, error(type_position,
...@@ -912,13 +921,21 @@ class ModuleDecoderTemplate : public Decoder { ...@@ -912,13 +921,21 @@ class ModuleDecoderTemplate : public Decoder {
"as table types"); "as table types");
continue; continue;
} }
if (!has_initializer && !table_type.is_defaultable()) {
errorf(type_position,
"Table of non-defaultable table %s needs initial value",
table_type.name().c_str());
continue;
}
table->type = table_type; table->type = table_type;
uint8_t flags = validate_table_flags("table elements"); uint8_t flags = validate_table_flags("table elements");
consume_resizable_limits( consume_resizable_limits(
"table elements", "elements", std::numeric_limits<uint32_t>::max(), "table elements", "elements", std::numeric_limits<uint32_t>::max(),
&table->initial_size, &table->has_maximum_size, &table->initial_size, &table->has_maximum_size,
std::numeric_limits<uint32_t>::max(), &table->maximum_size, flags); std::numeric_limits<uint32_t>::max(), &table->maximum_size, flags);
if (!table_type.is_defaultable()) {
if (has_initializer) {
table->initial_value = consume_init_expr(module_.get(), table_type); table->initial_value = consume_init_expr(module_.get(), table_type);
} }
} }
......
...@@ -405,7 +405,7 @@ class InstanceBuilder { ...@@ -405,7 +405,7 @@ class InstanceBuilder {
// and globals. // and globals.
void ProcessExports(Handle<WasmInstanceObject> instance); void ProcessExports(Handle<WasmInstanceObject> instance);
void InitializeNonDefaultableTables(Handle<WasmInstanceObject> instance); void SetTableInitialValues(Handle<WasmInstanceObject> instance);
void LoadTableSegments(Handle<WasmInstanceObject> instance); void LoadTableSegments(Handle<WasmInstanceObject> instance);
...@@ -618,7 +618,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() { ...@@ -618,7 +618,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
for (int i = module_->num_imported_tables; i < table_count; i++) { for (int i = module_->num_imported_tables; i < table_count; i++) {
const WasmTable& table = module_->tables[i]; const WasmTable& table = module_->tables[i];
// Initialize tables with null for now. We will initialize non-defaultable // Initialize tables with null for now. We will initialize non-defaultable
// tables later, in {InitializeNonDefaultableTables}. // tables later, in {SetTableInitialValues}.
Handle<WasmTableObject> table_obj = WasmTableObject::New( Handle<WasmTableObject> table_obj = WasmTableObject::New(
isolate_, instance, table.type, table.initial_size, isolate_, instance, table.type, table.initial_size,
table.has_maximum_size, table.maximum_size, nullptr, table.has_maximum_size, table.maximum_size, nullptr,
...@@ -730,7 +730,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() { ...@@ -730,7 +730,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
// Initialize non-defaultable tables. // Initialize non-defaultable tables.
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
if (FLAG_experimental_wasm_typed_funcref) { if (FLAG_experimental_wasm_typed_funcref) {
InitializeNonDefaultableTables(instance); SetTableInitialValues(instance);
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
...@@ -1907,12 +1907,12 @@ V8_INLINE void SetFunctionTableNullEntry(Isolate* isolate, ...@@ -1907,12 +1907,12 @@ V8_INLINE void SetFunctionTableNullEntry(Isolate* isolate,
} }
} // namespace } // namespace
void InstanceBuilder::InitializeNonDefaultableTables( void InstanceBuilder::SetTableInitialValues(
Handle<WasmInstanceObject> instance) { Handle<WasmInstanceObject> instance) {
for (int table_index = 0; for (int table_index = 0;
table_index < static_cast<int>(module_->tables.size()); ++table_index) { table_index < static_cast<int>(module_->tables.size()); ++table_index) {
const WasmTable& table = module_->tables[table_index]; const WasmTable& table = module_->tables[table_index];
if (!table.type.is_defaultable()) { if (table.initial_value.is_set()) {
auto table_object = handle( auto table_object = handle(
WasmTableObject::cast(instance->tables().get(table_index)), isolate_); WasmTableObject::cast(instance->tables().get(table_index)), isolate_);
bool is_function_table = IsSubtypeOf(table.type, kWasmFuncRef, module_); bool is_function_table = IsSubtypeOf(table.type, kWasmFuncRef, module_);
...@@ -1940,9 +1940,9 @@ void InstanceBuilder::InitializeNonDefaultableTables( ...@@ -1940,9 +1940,9 @@ void InstanceBuilder::InitializeNonDefaultableTables(
to_value(result).to_ref()); to_value(result).to_ref());
} }
} }
}
} }
} }
}
namespace { namespace {
// If the operation succeeds, returns an empty {Optional}. Otherwise, returns an // If the operation succeeds, returns an empty {Optional}. Otherwise, returns an
......
...@@ -83,6 +83,30 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -83,6 +83,30 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
assertTraps(kTrapElementSegmentOutOfBounds, () => instance.exports.init()); 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])
.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() { (function TestExternRefTableConstructorWithDefaultValue() {
print(arguments.callee.name); print(arguments.callee.name);
......
...@@ -1715,13 +1715,12 @@ class WasmModuleBuilder { ...@@ -1715,13 +1715,12 @@ class WasmModuleBuilder {
binary.emit_section(kTableSectionCode, section => { binary.emit_section(kTableSectionCode, section => {
section.emit_u32v(wasm.tables.length); section.emit_u32v(wasm.tables.length);
for (let table of wasm.tables) { for (let table of wasm.tables) {
if (table.has_init) section.emit_u8(0x40);
section.emit_type(table.type); section.emit_type(table.type);
section.emit_u8(table.has_max); section.emit_u8(table.has_max);
section.emit_u32v(table.initial_size); section.emit_u32v(table.initial_size);
if (table.has_max) section.emit_u32v(table.max_size); if (table.has_max) section.emit_u32v(table.max_size);
if (table.has_init) { if (table.has_init) section.emit_init_expr(table.init_expr);
section.emit_init_expr(table.init_expr);
}
} }
}); });
} }
......
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
#include "src/wasm/module-decoder.h" #include "src/wasm/module-decoder.h"
#include "src/handles/handles.h"
#include "src/objects/objects-inl.h"
#include "src/wasm/branch-hint-map.h" #include "src/wasm/branch-hint-map.h"
#include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-engine.h"
#include "src/wasm/wasm-features.h" #include "src/wasm/wasm-features.h"
...@@ -2101,6 +2099,24 @@ TEST_F(WasmModuleVerifyTest, IllegalTableTypes) { ...@@ -2101,6 +2099,24 @@ TEST_F(WasmModuleVerifyTest, IllegalTableTypes) {
} }
} }
TEST_F(WasmModuleVerifyTest, TableWithInitializer) {
WASM_FEATURE_SCOPE(typed_funcref);
static const byte data[] = {
SECTION(Type, ENTRY_COUNT(1), SIG_ENTRY_v_v), // type section
ONE_EMPTY_FUNCTION(0), // function section
SECTION(Table, // table section
ENTRY_COUNT(1), // 1 table
0x40, // table 0: has initializer
kRefNullCode, 0, // table 0: type
0, 10, // table 0: limits
kExprRefFunc, 0, kExprEnd), // table 0: initial value
SECTION(Code, ENTRY_COUNT(1), NOP_BODY)};
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(ValueType::RefNull(0), result.value()->tables[0].type);
}
TEST_F(WasmModuleVerifyTest, NonNullableTable) { TEST_F(WasmModuleVerifyTest, NonNullableTable) {
WASM_FEATURE_SCOPE(typed_funcref); WASM_FEATURE_SCOPE(typed_funcref);
...@@ -2109,6 +2125,7 @@ TEST_F(WasmModuleVerifyTest, NonNullableTable) { ...@@ -2109,6 +2125,7 @@ TEST_F(WasmModuleVerifyTest, NonNullableTable) {
ONE_EMPTY_FUNCTION(0), // function section ONE_EMPTY_FUNCTION(0), // function section
SECTION(Table, // table section SECTION(Table, // table section
ENTRY_COUNT(1), // 1 table ENTRY_COUNT(1), // 1 table
0x40, // table 0: has initializer
kRefCode, 0, // table 0: type kRefCode, 0, // table 0: type
0, 10, // table 0: limits 0, 10, // table 0: limits
kExprRefFunc, 0, kExprEnd), // table 0: initial value kExprRefFunc, 0, kExprEnd), // table 0: initial value
...@@ -2130,7 +2147,8 @@ TEST_F(WasmModuleVerifyTest, NonNullableTableNoInitializer) { ...@@ -2130,7 +2147,8 @@ TEST_F(WasmModuleVerifyTest, NonNullableTableNoInitializer) {
kRefCode, 0, // table 1: type kRefCode, 0, // table 1: type
5, 6)}; // table 1: limits 5, 6)}; // table 1: limits
EXPECT_FAILURE(data); EXPECT_FAILURE_WITH_MSG(
data, "Table of non-defaultable table (ref 0) needs initial value");
} }
TEST_F(WasmModuleVerifyTest, TieringCompilationHints) { TEST_F(WasmModuleVerifyTest, TieringCompilationHints) {
......
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