[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/+/3784590 Reviewed-by: Nico Hartmann <nicohartmann@chromium.org> Commit-Queue: Manos Koukoutos <manoskouk@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/main@{#81956}
This commit is contained in:
parent
dc0be4e376
commit
cb5c1b8a1f
@ -3327,6 +3327,11 @@ void Pipeline::GenerateCodeForWasmFunction(
|
||||
pipeline.Run<WasmGCOptimizationPhase>(module);
|
||||
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.RunPrintAndVerify(WasmGCLoweringPhase::phase_name(), true);
|
||||
}
|
||||
|
@ -905,6 +905,15 @@ class ModuleDecoderTemplate : public Decoder {
|
||||
module_->tables.emplace_back();
|
||||
WasmTable* table = &module_->tables.back();
|
||||
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();
|
||||
if (!WasmTable::IsValidTableType(table_type, module_.get())) {
|
||||
error(type_position,
|
||||
@ -912,13 +921,21 @@ class ModuleDecoderTemplate : public Decoder {
|
||||
"as table types");
|
||||
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;
|
||||
|
||||
uint8_t flags = validate_table_flags("table elements");
|
||||
consume_resizable_limits(
|
||||
"table elements", "elements", std::numeric_limits<uint32_t>::max(),
|
||||
&table->initial_size, &table->has_maximum_size,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -405,7 +405,7 @@ class InstanceBuilder {
|
||||
// and globals.
|
||||
void ProcessExports(Handle<WasmInstanceObject> instance);
|
||||
|
||||
void InitializeNonDefaultableTables(Handle<WasmInstanceObject> instance);
|
||||
void SetTableInitialValues(Handle<WasmInstanceObject> instance);
|
||||
|
||||
void LoadTableSegments(Handle<WasmInstanceObject> instance);
|
||||
|
||||
@ -618,7 +618,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
|
||||
for (int i = module_->num_imported_tables; i < table_count; i++) {
|
||||
const WasmTable& table = module_->tables[i];
|
||||
// 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(
|
||||
isolate_, instance, table.type, table.initial_size,
|
||||
table.has_maximum_size, table.maximum_size, nullptr,
|
||||
@ -730,7 +730,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
|
||||
// Initialize non-defaultable tables.
|
||||
//--------------------------------------------------------------------------
|
||||
if (FLAG_experimental_wasm_typed_funcref) {
|
||||
InitializeNonDefaultableTables(instance);
|
||||
SetTableInitialValues(instance);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@ -1907,12 +1907,12 @@ V8_INLINE void SetFunctionTableNullEntry(Isolate* isolate,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void InstanceBuilder::InitializeNonDefaultableTables(
|
||||
void InstanceBuilder::SetTableInitialValues(
|
||||
Handle<WasmInstanceObject> instance) {
|
||||
for (int table_index = 0;
|
||||
table_index < static_cast<int>(module_->tables.size()); ++table_index) {
|
||||
const WasmTable& table = module_->tables[table_index];
|
||||
if (!table.type.is_defaultable()) {
|
||||
if (table.initial_value.is_set()) {
|
||||
auto table_object = handle(
|
||||
WasmTableObject::cast(instance->tables().get(table_index)), isolate_);
|
||||
bool is_function_table = IsSubtypeOf(table.type, kWasmFuncRef, module_);
|
||||
@ -1940,9 +1940,9 @@ void InstanceBuilder::InitializeNonDefaultableTables(
|
||||
to_value(result).to_ref());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
// 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");
|
||||
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() {
|
||||
print(arguments.callee.name);
|
||||
|
@ -1715,13 +1715,12 @@ class WasmModuleBuilder {
|
||||
binary.emit_section(kTableSectionCode, section => {
|
||||
section.emit_u32v(wasm.tables.length);
|
||||
for (let table of wasm.tables) {
|
||||
if (table.has_init) section.emit_u8(0x40);
|
||||
section.emit_type(table.type);
|
||||
section.emit_u8(table.has_max);
|
||||
section.emit_u32v(table.initial_size);
|
||||
if (table.has_max) section.emit_u32v(table.max_size);
|
||||
if (table.has_init) {
|
||||
section.emit_init_expr(table.init_expr);
|
||||
}
|
||||
if (table.has_init) section.emit_init_expr(table.init_expr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -4,8 +4,6 @@
|
||||
|
||||
#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/wasm-engine.h"
|
||||
#include "src/wasm/wasm-features.h"
|
||||
@ -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) {
|
||||
WASM_FEATURE_SCOPE(typed_funcref);
|
||||
|
||||
@ -2109,6 +2125,7 @@ TEST_F(WasmModuleVerifyTest, NonNullableTable) {
|
||||
ONE_EMPTY_FUNCTION(0), // function section
|
||||
SECTION(Table, // table section
|
||||
ENTRY_COUNT(1), // 1 table
|
||||
0x40, // table 0: has initializer
|
||||
kRefCode, 0, // table 0: type
|
||||
0, 10, // table 0: limits
|
||||
kExprRefFunc, 0, kExprEnd), // table 0: initial value
|
||||
@ -2130,7 +2147,8 @@ TEST_F(WasmModuleVerifyTest, NonNullableTableNoInitializer) {
|
||||
kRefCode, 0, // table 1: type
|
||||
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user