From 530c95fde52d173ea11d5b148adcaf19f42e7124 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Thu, 11 Jun 2026 09:06:47 +0200 Subject: [PATCH] LibWasm: Remove all gc, function-refs and EH test exceptions --- .../LibWasm/AbstractMachine/Validator.cpp | 41 ++-- Libraries/LibWasm/Parser/Parser.cpp | 8 +- Meta/Generators/wasm_unimplemented_tests.txt | 206 ------------------ Tests/LibWasm/test-wasm.cpp | 4 + 4 files changed, 38 insertions(+), 221 deletions(-) diff --git a/Libraries/LibWasm/AbstractMachine/Validator.cpp b/Libraries/LibWasm/AbstractMachine/Validator.cpp index c55d5bda38..72fc62e3aa 100644 --- a/Libraries/LibWasm/AbstractMachine/Validator.cpp +++ b/Libraries/LibWasm/AbstractMachine/Validator.cpp @@ -147,6 +147,8 @@ ErrorOr Validator::validate(Module& module) } for (auto& segment : module.global_section().entries()) scan_expression_for_function_indices(segment.expression()); + for (auto& table : module.table_section().tables()) + scan_expression_for_function_indices(table.initializer()); TRY(validate(module.import_section())); TRY(validate(module.export_section())); @@ -328,6 +330,9 @@ ErrorOr Validator::validate(DataSection const& section) ErrorOr Validator::validate(ElementSection const& section) { for (auto& segment : section.segments()) { + // https://webassembly.github.io/spec/core/valid/modules.html#element-segments + // - The reference type elemtype is valid. + TRY(validate(segment.type)); TRY(segment.mode.visit( [](ElementSection::Declarative const&) -> ErrorOr { return {}; }, [](ElementSection::Passive const&) -> ErrorOr { return {}; }, @@ -419,6 +424,9 @@ ErrorOr Validator::validate(CodeSection const& section) function_validator.m_context.locals.extend(function_type.parameters()); function_validator.m_context.current_function_parameter_count = function_type.parameters().size(); for (auto& local : function.locals()) { + // https://webassembly.github.io/spec/core/valid/modules.html#functions + // The locals' value types must be valid (in particular, type uses must exist). + TRY(function_validator.validate(local.type())); for (size_t i = 0; i < local.n(); ++i) function_validator.m_context.locals.append(local.type()); } @@ -1629,14 +1637,15 @@ VALIDATE_INSTRUCTION(select_typed) if (required_types.size() != 1) return Errors::invalid("select types"sv, "exactly one type"sv, required_types); + // https://webassembly.github.io/spec/core/valid/instructions.html#parametric-instructions + // select t: valid with [t t i32] -> [t] if the value type t is valid; both operands must + // match the annotated type. + TRY(validate(required_types.first())); TRY(stack.take()); - auto arg0_type = TRY(stack.take_last()); - auto arg1_type = TRY(stack.take_last()); + TRY(stack.take(required_types.first())); + TRY(stack.take(required_types.first())); - if (arg0_type != arg1_type || arg0_type != required_types.first()) - return Errors::invalid("select argument types"sv, Vector { required_types.first(), required_types.first() }, Vector { arg0_type, arg1_type }); - - stack.append(arg0_type.is_known ? arg0_type : arg1_type); + stack.append(required_types.first()); return {}; } @@ -1772,12 +1781,11 @@ VALIDATE_INSTRUCTION(table_copy) auto lhs_table = TRY(validate(args.lhs)); auto rhs_table = TRY(validate(args.rhs)); - if (lhs_table.element_type() != rhs_table.element_type()) + // https://webassembly.github.io/spec/core/valid/instructions.html#table-instructions + // table.copy x y: the source table's reference type rt2 must match the destination's rt1. + if (!matches_reference_type(rhs_table.element_type(), lhs_table.element_type(), m_context.type_context())) return Errors::non_conforming_types("table.copy"sv, lhs_table.element_type(), rhs_table.element_type()); - if (!lhs_table.element_type().is_reference()) - return Errors::invalid("table.copy element type"sv, "a reference type"sv, lhs_table.element_type()); - auto const lhs_at = lhs_table.limits().address_value_type(); auto const rhs_at = rhs_table.limits().address_value_type(); auto const size_type = ValueType(lhs_at.kind() == ValueType::I32 || rhs_at.kind() == ValueType::I32 ? ValueType::I32 : ValueType::I64); @@ -1798,7 +1806,10 @@ VALIDATE_INSTRUCTION(table_init) auto& element_type = m_context.elements[args.element_index.value()]; - if (table.element_type() != element_type) + // https://webassembly.github.io/spec/core/valid/instructions.html#table-instructions + // table.init x y: "The element segment C.elems[y] must match the reference type rt" of the + // table C.tables[x]. + if (!matches_reference_type(element_type, table.element_type(), m_context.type_context())) return Errors::non_conforming_types("table.init"sv, table.element_type(), element_type); TRY((stack.take())); @@ -2662,7 +2673,10 @@ VALIDATE_INSTRUCTION(call_indirect) auto table = TRY(validate(args.table)); TRY(validate(args.type)); - if (table.element_type().kind() != ValueType::FunctionReference) + // https://webassembly.github.io/spec/core/valid/instructions.html#control-instructions + // call_indirect x y: "The table C.tables[x] must be of the form (at lim rt), and rt must + // match (ref null func)." + if (!matches_reference_type(table.element_type(), ValueType(ValueType::FunctionReference), m_context.type_context())) return Errors::invalid("table element type for call.indirect"sv, "a function reference"sv, table.element_type()); auto& type = m_context.types[args.type.value()]; @@ -2708,7 +2722,8 @@ VALIDATE_INSTRUCTION(return_call_indirect) TRY(validate(args.type)); auto& table = m_context.tables[args.table.value()]; - if (table.element_type().kind() != ValueType::FunctionReference) + // See call_indirect: rt must match (ref null func). + if (!matches_reference_type(table.element_type(), ValueType(ValueType::FunctionReference), m_context.type_context())) return Errors::invalid("table element type for call.indirect"sv, "a function reference"sv, table.element_type()); auto& type = m_context.types[args.type.value()]; diff --git a/Libraries/LibWasm/Parser/Parser.cpp b/Libraries/LibWasm/Parser/Parser.cpp index dc481b4744..d5aa96956c 100644 --- a/Libraries/LibWasm/Parser/Parser.cpp +++ b/Libraries/LibWasm/Parser/Parser.cpp @@ -1571,7 +1571,11 @@ ParseResult ElementSection::Element::parse(ConstrainedS mode = Active { table_index, move(expression) }; } - auto type = ValueType(ValueType::FunctionReference); + // https://webassembly.github.io/spec/core/binary/modules.html#element-section + // elemkind ::= 0x00 => (ref func) + // Segments listing function indices have the non-nullable type (ref func) (flags 0-3); + // the flag-4 expression shorthand has type funcref, i.e. (ref null func). + auto type = has_exprs ? ValueType(ValueType::FunctionReference) : ValueType(ValueType::FunctionReference, false); if (has_passive || has_explicit_index) { if (has_exprs) { type = TRY(ValueType::parse(stream)); @@ -1582,7 +1586,7 @@ ParseResult ElementSection::Element::parse(ConstrainedS if (extern_ != 0x00) { return ParseError::InvalidType; } - type = ValueType(ValueType::FunctionReference); + type = ValueType(ValueType::FunctionReference, false); } } diff --git a/Meta/Generators/wasm_unimplemented_tests.txt b/Meta/Generators/wasm_unimplemented_tests.txt index b9e800c507..67a5ef2700 100644 --- a/Meta/Generators/wasm_unimplemented_tests.txt +++ b/Meta/Generators/wasm_unimplemented_tests.txt @@ -1,208 +1,2 @@ -module array.0 -module array.12 -module array.2 -module array.5 -module array.6 -module array.7 -module array.8 -module array_copy.4 -module array_fill.3 -module array_init_data.2 -module array_init_data.3 -module array_init_elem.3 -module array_new_data.0 -module array_new_data.1 -module array_new_data.2 -module array_new_data.3 -module array_new_data.4 -module array_new_elem.0 -module array_new_elem.1 -module array_new_elem.2 -module array_new_elem.3 -module br_on_cast.0 -module br_on_cast.1 -module br_on_cast.2 -module br_on_cast_fail.0 -module br_on_cast_fail.1 -module br_on_cast_fail.2 -module br_on_non_null.0 -module br_on_non_null.1 -module br_on_non_null.2 -module br_on_null.0 -module br_on_null.1 -module br_on_null.2 -module br_table.0 -module call_ref.0 -module call_ref.1 -module call_ref.2 -module call_ref.3 -module elem.2 -module elem.31 -module elem.47 -module elem.48 -module elem.49 -module elem.50 -module elem.51 -module elem.52 -module elem.53 -module elem.54 -module elem.57 -module elem.58 -module elem.59 -module elem.60 -module elem.61 -module elem.62 -module extern.0 -module func.21 -module global.50 -module i31.0 -module i31.1 -module i31.3 -module i31.4 -module i31.5 -module i31.6 -module instance.0 -module instance.1 -module instance.2 -module instance.3 -module instance.4 -module linking.10 -module linking.9 -module local_init.0 -module local_init.1 -module local_init.2 -module local_init.4 -module local_init.5 -module ref.1 -module ref.12 -module ref.2 -module ref.4 -module ref.5 -module ref.6 -module ref.8 -module ref_as_non_null.0 -module ref_as_non_null.2 -module ref_cast.0 -module ref_cast.1 -module ref_eq.0 -module ref_is_null.0 -module ref_null.0 -module ref_null.1 -module ref_test.0 -module ref_test.1 module relaxed_dot_product.0 module relaxed_madd_nmadd.0 -module return_call_ref.0 -module return_call_ref.1 -module return_call_ref.10 -module return_call_ref.8 -module return_call_ref.9 -module select.0 -module struct.0 -module struct.10 -module struct.2 -module struct.5 -module struct.7 -module struct.9 -module table-sub.0 -module table.13 -module table.14 -module table.15 -module table.29 -module table.30 -module table.31 -module table.32 -module table.33 -module table.34 -module table.35 -module table.36 -module table64.11 -module tag.2 -module tag.4 -module tag.5 -module throw.0 -module throw_ref.0 -module try_table.1 -module try_table.13 -module try_table.2 -module try_table.5 -module type-canon.0 -module type-canon.1 -module type-equivalence.0 -module type-equivalence.1 -module type-equivalence.13 -module type-equivalence.14 -module type-equivalence.15 -module type-equivalence.16 -module type-equivalence.17 -module type-equivalence.18 -module type-equivalence.19 -module type-equivalence.2 -module type-equivalence.20 -module type-equivalence.21 -module type-equivalence.3 -module type-equivalence.4 -module type-equivalence.5 -module type-equivalence.7 -module type-equivalence.8 -module type-equivalence.9 -module type-rec.0 -module type-rec.1 -module type-rec.13 -module type-rec.14 -module type-rec.17 -module type-rec.18 -module type-rec.19 -module type-rec.20 -module type-rec.3 -module type-rec.4 -module type-rec.7 -module type-rec.8 -module type-subtyping.0 -module type-subtyping.1 -module type-subtyping.11 -module type-subtyping.12 -module type-subtyping.13 -module type-subtyping.14 -module type-subtyping.17 -module type-subtyping.18 -module type-subtyping.19 -module type-subtyping.2 -module type-subtyping.20 -module type-subtyping.21 -module type-subtyping.22 -module type-subtyping.23 -module type-subtyping.24 -module type-subtyping.25 -module type-subtyping.26 -module type-subtyping.27 -module type-subtyping.28 -module type-subtyping.29 -module type-subtyping.3 -module type-subtyping.30 -module type-subtyping.34 -module type-subtyping.37 -module type-subtyping.38 -module type-subtyping.39 -module type-subtyping.4 -module type-subtyping.40 -module type-subtyping.41 -module type-subtyping.43 -module type-subtyping.44 -module type-subtyping.45 -module type-subtyping.46 -module type-subtyping.47 -module type-subtyping.48 -module type-subtyping.49 -module type-subtyping.5 -module type-subtyping.50 -module type-subtyping.51 -module type-subtyping.53 -module type-subtyping.6 -module type-subtyping.7 -module type-subtyping.76 -module type-subtyping.8 -module type-subtyping.9 -module unreached-valid.0 -module unreached-valid.2 -test local_init.5 diff --git a/Tests/LibWasm/test-wasm.cpp b/Tests/LibWasm/test-wasm.cpp index f973b78196..4f9d380e5b 100644 --- a/Tests/LibWasm/test-wasm.cpp +++ b/Tests/LibWasm/test-wasm.cpp @@ -115,6 +115,10 @@ private: auto table_address = m_machine.store().allocate(table_type); s_spec_test_namespace.set({ "spectest", "table", table_type }, Wasm::ExternValue { *table_address }); + Wasm::TableType table64_type { Wasm::ValueType(Wasm::ValueType::FunctionReference), Wasm::Limits(Wasm::AddressType::I64, 10, 20) }; + auto table64_address = m_machine.store().allocate(table64_type); + s_spec_test_namespace.set({ "spectest", "table64", table64_type }, Wasm::ExternValue { *table64_address }); + Wasm::MemoryType memory_type { Wasm::Limits(Wasm::AddressType::I32, 1, 2) }; auto memory_address = m_machine.store().allocate(memory_type); s_spec_test_namespace.set({ "spectest", "memory", memory_type }, Wasm::ExternValue { *memory_address });