LibWasm+LibWeb: Stub wasm-gc's heap reference types

WPT inserts these into all modules regardless of whether they're used,
so let's just parse and ignore them.
This commit is contained in:
Ali Mohammad Pur 2025-10-14 17:21:33 +02:00 committed by Ali Mohammad Pur
parent 33d2959a4c
commit 92c0cbc453
Notes: github-actions[bot] 2025-10-14 23:28:44 +00:00
8 changed files with 57 additions and 4 deletions

View file

@ -99,6 +99,10 @@ public:
// ref.null exnref // ref.null exnref
m_value = u128(0, 4); m_value = u128(0, 4);
break; break;
case ValueType::UnsupportedHeapReference:
// ref.null (todo)
m_value = u128(0, 5);
break;
} }
} }

View file

@ -19,6 +19,20 @@ static constexpr auto v128_tag = 0x7b;
static constexpr auto function_reference_tag = 0x70; static constexpr auto function_reference_tag = 0x70;
static constexpr auto extern_reference_tag = 0x6f; static constexpr auto extern_reference_tag = 0x6f;
// wasm-gc references
static constexpr auto array_reference_tag = 0x6a;
static constexpr auto struct_reference_tag = 0x6b;
static constexpr auto i31_reference_tag = 0x6c;
static constexpr auto eq_reference_tag = 0x6d;
static constexpr auto any_reference_tag = 0x6e;
static constexpr auto none_reference_tag = 0x71;
static constexpr auto noextern_reference_tag = 0x72;
static constexpr auto nofunc_reference_tag = 0x73;
static constexpr auto noexn_heap_reference_tag = 0x74;
static constexpr auto nullable_reference_tag_tag = 0x63;
static constexpr auto non_nullable_reference_tag_tag = 0x64;
// Function // Function
static constexpr auto function_signature_tag = 0x60; static constexpr auto function_signature_tag = 0x60;

View file

@ -118,6 +118,22 @@ ParseResult<ValueType> ValueType::parse(Stream& stream)
return ValueType(FunctionReference); return ValueType(FunctionReference);
case Constants::extern_reference_tag: case Constants::extern_reference_tag:
return ValueType(ExternReference); return ValueType(ExternReference);
case Constants::array_reference_tag:
case Constants::struct_reference_tag:
case Constants::i31_reference_tag:
case Constants::eq_reference_tag:
case Constants::any_reference_tag:
case Constants::none_reference_tag:
case Constants::noextern_reference_tag:
case Constants::nofunc_reference_tag:
case Constants::noexn_heap_reference_tag:
// FIXME: Implement these when we support wasm-gc properly.
return ValueType(UnsupportedHeapReference);
case Constants::nullable_reference_tag_tag:
case Constants::non_nullable_reference_tag_tag:
tag = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
(void)tag;
return ValueType(UnsupportedHeapReference);
default: default:
return ParseError::InvalidTag; return ParseError::InvalidTag;
} }

View file

@ -760,6 +760,9 @@ void Printer::print(Wasm::Value const& value, Wasm::ValueType const& type)
[](Wasm::Reference::Exception const&) { return ByteString("exception"); }, [](Wasm::Reference::Exception const&) { return ByteString("exception"); },
[](auto const& ref) { return ByteString::number(ref.address.value()); })); [](auto const& ref) { return ByteString::number(ref.address.value()); }));
break; break;
case ValueType::UnsupportedHeapReference:
print("unsupported-heap-ref");
break;
} }
TemporaryChange<size_t> change { m_indent, 0 }; TemporaryChange<size_t> change { m_indent, 0 };
} }

View file

@ -169,6 +169,7 @@ public:
FunctionReference, FunctionReference,
ExternReference, ExternReference,
ExceptionReference, ExceptionReference,
UnsupportedHeapReference, // Stub for wasm-gc proposal's reference types.
}; };
explicit ValueType(Kind kind) explicit ValueType(Kind kind)
@ -178,7 +179,7 @@ public:
bool operator==(ValueType const&) const = default; bool operator==(ValueType const&) const = default;
auto is_reference() const { return m_kind == ExternReference || m_kind == FunctionReference; } auto is_reference() const { return m_kind == ExternReference || m_kind == FunctionReference || m_kind == UnsupportedHeapReference; }
auto is_vector() const { return m_kind == V128; } auto is_vector() const { return m_kind == V128; }
auto is_numeric() const { return !is_reference() && !is_vector(); } auto is_numeric() const { return !is_reference() && !is_vector(); }
auto kind() const { return m_kind; } auto kind() const { return m_kind; }
@ -204,6 +205,8 @@ public:
return "externref"; return "externref";
case ExceptionReference: case ExceptionReference:
return "exnref"; return "exnref";
case UnsupportedHeapReference:
return "todo.heapref";
} }
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }

View file

@ -621,6 +621,8 @@ JS::ThrowCompletionOr<Wasm::Value> to_webassembly_value(JS::VM& vm, JS::Value va
return Wasm::Value(Wasm::ValueType { Wasm::ValueType::Kind::ExceptionReference }); return Wasm::Value(Wasm::ValueType { Wasm::ValueType::Kind::ExceptionReference });
case Wasm::ValueType::V128: case Wasm::ValueType::V128:
return vm.throw_completion<JS::TypeError>("Cannot convert a vector value to a javascript value"sv); return vm.throw_completion<JS::TypeError>("Cannot convert a vector value to a javascript value"sv);
case Wasm::ValueType::UnsupportedHeapReference:
return vm.throw_completion<JS::TypeError>("Unsupported heap reference"sv);
} }
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
@ -640,6 +642,8 @@ Wasm::Value default_webassembly_value(JS::VM& vm, Wasm::ValueType type)
return MUST(to_webassembly_value(vm, JS::js_undefined(), type)); return MUST(to_webassembly_value(vm, JS::js_undefined(), type));
case Wasm::ValueType::ExceptionReference: case Wasm::ValueType::ExceptionReference:
return Wasm::Value(type); return Wasm::Value(type);
case Wasm::ValueType::UnsupportedHeapReference:
return Wasm::Value(type);
} }
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
@ -685,6 +689,7 @@ JS::Value to_js_value(JS::VM& vm, Wasm::Value& wasm_value, Wasm::ValueType type)
} }
case Wasm::ValueType::V128: case Wasm::ValueType::V128:
case Wasm::ValueType::ExceptionReference: case Wasm::ValueType::ExceptionReference:
case Wasm::ValueType::UnsupportedHeapReference:
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();

View file

@ -314,13 +314,16 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::get_export)
} }
case Wasm::ValueType::FunctionReference: case Wasm::ValueType::FunctionReference:
case Wasm::ValueType::ExternReference: case Wasm::ValueType::ExternReference:
case Wasm::ValueType::ExceptionReference: case Wasm::ValueType::ExceptionReference: {
auto ref = global->value().to<Wasm::Reference>(); auto ref = global->value().to<Wasm::Reference>();
return ref.ref().visit( return ref.ref().visit(
[&](Wasm::Reference::Null const&) -> JS::Value { return JS::js_null(); }, [&](Wasm::Reference::Null const&) -> JS::Value { return JS::js_null(); },
[](Wasm::Reference::Exception const&) -> JS::Value { return JS::js_undefined(); }, [](Wasm::Reference::Exception const&) -> JS::Value { return JS::js_undefined(); },
[&](auto const& ref) -> JS::Value { return JS::Value(static_cast<double>(ref.address.value())); }); [&](auto const& ref) -> JS::Value { return JS::Value(static_cast<double>(ref.address.value())); });
} }
case Wasm::ValueType::UnsupportedHeapReference:
return vm.throw_completion<JS::TypeError>("Unsupported heap reference"sv);
}
} }
return vm.throw_completion<JS::TypeError>(TRY_OR_THROW_OOM(vm, String::formatted("'{}' does not refer to a function or a global", name))); return vm.throw_completion<JS::TypeError>(TRY_OR_THROW_OOM(vm, String::formatted("'{}' does not refer to a function or a global", name)));
} }
@ -406,6 +409,8 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke)
else else
return vm.throw_completion<JS::TypeError>("Exception references are not supported"sv); return vm.throw_completion<JS::TypeError>("Exception references are not supported"sv);
break; break;
case Wasm::ValueType::Kind::UnsupportedHeapReference:
return vm.throw_completion<JS::TypeError>("GC Heap references are not supported"sv);
} }
} }
@ -420,7 +425,7 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke)
if (result.values().is_empty()) if (result.values().is_empty())
return JS::js_null(); return JS::js_null();
auto to_js_value = [&](Wasm::Value const& value, Wasm::ValueType type) { auto to_js_value = [&](Wasm::Value const& value, Wasm::ValueType type) -> JS::ThrowCompletionOr<JS::Value> {
switch (type.kind()) { switch (type.kind()) {
case Wasm::ValueType::I32: case Wasm::ValueType::I32:
return JS::Value(static_cast<double>(value.to<i32>())); return JS::Value(static_cast<double>(value.to<i32>()));
@ -442,6 +447,8 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke)
return (value.to<Wasm::Reference>()).ref().visit([&](Wasm::Reference::Null) { return JS::js_null(); }, [&](Wasm::Reference::Exception) { return JS::Value(); }, [&](auto const& ref) { return JS::Value(static_cast<double>(ref.address.value())); }); return (value.to<Wasm::Reference>()).ref().visit([&](Wasm::Reference::Null) { return JS::js_null(); }, [&](Wasm::Reference::Exception) { return JS::Value(); }, [&](auto const& ref) { return JS::Value(static_cast<double>(ref.address.value())); });
case Wasm::ValueType::ExceptionReference: case Wasm::ValueType::ExceptionReference:
return JS::js_null(); return JS::js_null();
case Wasm::ValueType::UnsupportedHeapReference:
return vm.throw_completion<JS::TypeError>("Unsupported heap reference"sv);
} }
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
}; };
@ -452,6 +459,6 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke)
size_t i = 0; size_t i = 0;
return JS::Array::create_from<Wasm::Value>(*vm.current_realm(), result.values(), [&](Wasm::Value value) { return JS::Array::create_from<Wasm::Value>(*vm.current_realm(), result.values(), [&](Wasm::Value value) {
auto value_type = type->results()[i++]; auto value_type = type->results()[i++];
return to_js_value(value, value_type); return MUST(to_js_value(value, value_type));
}); });
} }

View file

@ -234,6 +234,7 @@ static ErrorOr<ParsedValue> parse_value(StringView spec)
case Wasm::ValueType::FunctionReference: case Wasm::ValueType::FunctionReference:
case Wasm::ValueType::ExternReference: case Wasm::ValueType::ExternReference:
case Wasm::ValueType::ExceptionReference: case Wasm::ValueType::ExceptionReference:
case Wasm::ValueType::UnsupportedHeapReference:
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
last_value = parsed.value.value(); last_value = parsed.value.value();