LibWasm: Parse wasm-gc types

No more unsupported heap refs.
This commit is contained in:
Ali Mohammad Pur 2026-06-11 06:14:58 +02:00 committed by Ali Mohammad Pur
parent 5ec468bfdd
commit 3ca552b37b
10 changed files with 447 additions and 97 deletions

View file

@ -91,22 +91,31 @@ public:
case ValueType::F32:
case ValueType::F64:
case ValueType::V128:
case ValueType::I8:
case ValueType::I16:
break;
case ValueType::FunctionReference:
// ref.null funcref
case ValueType::NoFunctionReference:
// ref.null func | ref.null nofunc
m_value = u128(0, 2);
break;
case ValueType::ExternReference:
// ref.null externref
case ValueType::NoExternReference:
// ref.null extern | ref.null noextern
m_value = u128(0, 3);
break;
case ValueType::ExceptionReference:
// ref.null exnref
case ValueType::NoExceptionReference:
// ref.null exn | ref.null noexn
m_value = u128(0, 4);
break;
case ValueType::AnyReference:
case ValueType::EqReference:
case ValueType::I31Reference:
case ValueType::StructReference:
case ValueType::ArrayReference:
case ValueType::NoneReference:
case ValueType::TypeUseReference:
case ValueType::UnsupportedHeapReference:
// ref.null (todo)
m_value = u128(0, 5);
break;
}

View file

@ -425,11 +425,11 @@ ErrorOr<void, ValidationError> Validator::validate(TagSection const& section)
return {};
}
// https://webassembly.github.io/spec/core/valid/types.html#recursive-types
ErrorOr<void, ValidationError> Validator::validate(TypeSection const& section)
{
for (auto& type : section.types()) {
TRY(validate(type));
}
for (size_t type_index = 0; type_index < section.types().size(); ++type_index)
TRY(validate(section.types()[type_index], type_index));
return {};
}
@ -472,8 +472,30 @@ ErrorOr<void, ValidationError> Validator::validate(ValueType const& type)
return {};
}
ErrorOr<void, ValidationError> Validator::validate(TypeSection::Type const& type)
// https://webassembly.github.io/spec/core/valid/types.html#recursive-types
ErrorOr<void, ValidationError> Validator::validate(TypeSection::Type const& type, size_t this_type_index)
{
// - The length of x* is less than or equal to 1.
if (type.supertypes().size() > 1)
return Errors::invalid("supertype count, only a single supertype is allowed"sv);
// - For all x in x*:
for (auto supertype_index : type.supertypes()) {
// - The index x is less than x0.
if (supertype_index.value() >= this_type_index)
return Errors::invalid("supertype index, must precede the subtype"sv);
// - The type C.types[x] exists.
TRY(validate(supertype_index));
// - The sub type unroll(C.types[x]) is of the form (sub y* comptype').
auto const& supertype = m_context.types[supertype_index.value()];
if (supertype.is_final())
return Errors::invalid("supertype, must not be final"sv);
// FIXME: - The composite type comptype matches the composite type comptype'.
}
return type.description().visit(
[&](FunctionType const& function) { return validate(function); },
[&](StructType const& struct_) { return validate(struct_); },

View file

@ -328,7 +328,7 @@ public:
ErrorOr<void, ValidationError> validate(GlobalType const&);
ErrorOr<void, ValidationError> validate(TagType const&);
ErrorOr<void, ValidationError> validate(ValueType const&);
ErrorOr<void, ValidationError> validate(TypeSection::Type const&);
ErrorOr<void, ValidationError> validate(TypeSection::Type const&, size_t this_type_index);
// Proposal 'memory64'
ErrorOr<void, ValidationError> take_memory_address(Stack& stack, MemoryType const& memory, Instruction::MemoryArgument const& arg)

View file

@ -10,35 +10,44 @@
namespace Wasm::Constants {
// Value
// Number types
static constexpr auto i32_tag = 0x7f;
static constexpr auto i64_tag = 0x7e;
static constexpr auto f32_tag = 0x7d;
static constexpr auto f64_tag = 0x7c;
static constexpr auto v128_tag = 0x7b;
static constexpr auto function_reference_tag = 0x70;
static constexpr auto extern_reference_tag = 0x6f;
// wasm-gc references
// Vector types
static constexpr auto v128_tag = 0x7b;
// Heap types
static constexpr auto exn_reference_tag = 0x69;
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 extern_reference_tag = 0x6f;
static constexpr auto function_reference_tag = 0x70;
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 noexn_reference_tag = 0x74;
// Reference types
static constexpr auto nullable_reference_tag_tag = 0x63;
static constexpr auto non_nullable_reference_tag_tag = 0x64;
// Composite
static constexpr auto struct_tag = 0x5f;
// Composite types
static constexpr auto array_tag = 0x5e;
// Function
static constexpr auto struct_tag = 0x5f;
static constexpr auto function_signature_tag = 0x60;
static constexpr auto i16_tag = 0x77;
static constexpr auto i8_tag = 0x78;
// Recursive types
static constexpr auto rec_group_tag = 0x4e;
static constexpr auto sub_final_type_tag = 0x4f;
static constexpr auto sub_type_tag = 0x50;
// Global
static constexpr auto const_tag = 0x00;

View file

@ -99,48 +99,104 @@ static ParseResult<ByteString> parse_name(ConstrainedStream& stream)
return string;
}
static ParseResult<ValueType> parse_reference_type(Stream& stream, u8 tag)
// https://webassembly.github.io/spec/core/binary/values.html#integers
template<size_t N>
static ParseResult<i64> parse_signed_integer_of_size(Stream& stream)
{
static_assert(N <= 64);
constexpr size_t max_bytes = (N + 6) / 7;
i64 result = 0;
size_t shift = 0;
for (size_t i = 0; i < max_bytes; ++i) {
auto n = TRY_READ(stream, u8, ParseError::ExpectedSignedImmediate);
if (0 == (n & 0x80)) {
auto const remaining_bits = min(N - 7 * i, 7uz);
u8 const sign_bit = 1u << (remaining_bits - 1);
u8 const unused_mask = static_cast<u8>(0x7f & ~(static_cast<u8>(sign_bit << 1) - 1));
if ((n & sign_bit) ? ((n & unused_mask) != unused_mask) : ((n & unused_mask) != 0))
return with_eof_check(stream, ParseError::InvalidImmediate);
result |= static_cast<i64>(n & 0x7f) << shift;
shift += 7;
if (shift < 64 && (n & 0x40))
result |= ~static_cast<i64>(0) << shift;
return result;
}
result |= static_cast<i64>(n & 0x7f) << shift;
shift += 7;
}
return with_eof_check(stream, ParseError::InvalidImmediate);
}
// https://webassembly.github.io/spec/core/binary/types.html#heap-types
static Optional<ValueType::Kind> abstract_heap_type_from_tag(u8 tag)
{
switch (tag) {
case Constants::function_reference_tag:
return ValueType(ValueType::FunctionReference);
case Constants::extern_reference_tag:
return ValueType(ValueType::ExternReference);
case Constants::exn_reference_tag:
return ValueType::ExceptionReference;
case Constants::array_reference_tag:
return ValueType::ArrayReference;
case Constants::struct_reference_tag:
return ValueType::StructReference;
case Constants::i31_reference_tag:
return ValueType::I31Reference;
case Constants::eq_reference_tag:
return ValueType::EqReference;
case Constants::any_reference_tag:
return ValueType::AnyReference;
case Constants::extern_reference_tag:
return ValueType::ExternReference;
case Constants::function_reference_tag:
return ValueType::FunctionReference;
case Constants::none_reference_tag:
return ValueType::NoneReference;
case Constants::noextern_reference_tag:
return ValueType::NoExternReference;
case Constants::nofunc_reference_tag:
case Constants::noexn_heap_reference_tag:
// FIXME: Implement these when we support wasm-gc properly.
return ValueType(ValueType::UnsupportedHeapReference);
case Constants::nullable_reference_tag_tag:
case Constants::non_nullable_reference_tag_tag: {
bool nullable = tag == Constants::nullable_reference_tag_tag;
tag = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
auto type = TRY(parse_reference_type(stream, tag));
type.set_nullable(nullable);
return type;
}
default: {
ReconsumableStream new_stream { stream };
new_stream.unread({ &tag, 1 });
// FIXME: should be an i33. Right now, we're missing a potential last bit at
// the end. See https://webassembly.github.io/spec/core/bikeshed/#heap-types%E2%91%A6
i32 type_index = TRY_READ(new_stream, LEB128<i32>, ParseError::ExpectedIndex);
if (type_index < 0) {
return with_eof_check(stream, ParseError::InvalidIndex);
}
return ValueType(ValueType::TypeUseReference, TypeIndex(type_index));
}
return ValueType::NoFunctionReference;
case Constants::noexn_reference_tag:
return ValueType::NoExceptionReference;
default:
return {};
}
}
// https://webassembly.github.io/spec/core/binary/types.html#heap-types
// NOTE: Nullable by default, caller must explicitly set nullability if needed.
static ParseResult<ValueType> parse_heap_type(Stream& stream)
{
auto tag = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
if (auto kind = abstract_heap_type_from_tag(tag); kind.has_value())
return ValueType(*kind);
ReconsumableStream new_stream { stream };
new_stream.unread({ &tag, 1 });
auto type_index = TRY(parse_signed_integer_of_size<33>(new_stream));
if (type_index < 0)
return with_eof_check(stream, ParseError::InvalidIndex);
if (type_index > NumericLimits<u32>::max())
return with_eof_check(stream, ParseError::InvalidIndex);
return ValueType(ValueType::TypeUseReference, TypeIndex(static_cast<u32>(type_index)));
}
// https://webassembly.github.io/spec/core/binary/types.html#reference-types
static ParseResult<ValueType> parse_reference_type(Stream& stream, u8 tag)
{
switch (tag) {
case Constants::nullable_reference_tag_tag:
case Constants::non_nullable_reference_tag_tag: {
bool nullable = tag == Constants::nullable_reference_tag_tag;
auto type = TRY(parse_heap_type(stream));
type.set_nullable(nullable);
return type;
}
default:
if (auto kind = abstract_heap_type_from_tag(tag); kind.has_value())
return ValueType(*kind);
return with_eof_check(stream, ParseError::InvalidType);
}
}
// https://webassembly.github.io/spec/core/binary/types.html#value-types
ParseResult<ValueType> ValueType::parse(Stream& stream)
{
ScopeLogger<WASM_BINPARSER_DEBUG> logger("ValueType"sv);
@ -162,6 +218,23 @@ ParseResult<ValueType> ValueType::parse(Stream& stream)
}
}
// https://webassembly.github.io/spec/core/binary/types.html#composite-types
static ParseResult<ValueType> parse_storage_type(Stream& stream)
{
auto tag = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
switch (tag) {
case Constants::i16_tag:
return ValueType(ValueType::I16);
case Constants::i8_tag:
return ValueType(ValueType::I8);
default: {
ReconsumableStream new_stream { stream };
new_stream.unread({ &tag, 1 });
return ValueType::parse(new_stream);
}
}
}
ParseResult<ResultType> ResultType::parse(ConstrainedStream& stream)
{
ScopeLogger<WASM_BINPARSER_DEBUG> logger("ResultType"sv);
@ -179,11 +252,12 @@ ParseResult<FunctionType> FunctionType::parse(ConstrainedStream& stream)
return FunctionType { parameters_result, results_result };
}
// https://webassembly.github.io/spec/core/binary/types.html#composite-types
ParseResult<FieldType> FieldType::parse(ConstrainedStream& stream)
{
ScopeLogger<WASM_BINPARSER_DEBUG> logger("FieldType"sv);
auto type_ = TRY(ValueType::parse(stream));
auto type_ = TRY(parse_storage_type(stream));
auto mutable_ = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
if (mutable_ > 1)
@ -276,6 +350,7 @@ ParseResult<TagType> TagType::parse(ConstrainedStream& stream)
return TagType { index, static_cast<TagType::Flags>(flags) };
}
// https://webassembly.github.io/spec/core/binary/instructions.html#control-instructions
ParseResult<BlockType> BlockType::parse(ConstrainedStream& stream)
{
ScopeLogger<WASM_BINPARSER_DEBUG> logger("BlockType"sv);
@ -284,14 +359,31 @@ ParseResult<BlockType> BlockType::parse(ConstrainedStream& stream)
if (kind == Constants::empty_block_tag)
return BlockType {};
ReconsumableStream value_stream { stream };
value_stream.unread({ &kind, 1 });
auto value_type = TRY(ValueType::parse(value_stream));
if (value_type.is_typeuse()) {
return BlockType { value_type.unsafe_typeindex() };
switch (kind) {
case Constants::i32_tag:
case Constants::i64_tag:
case Constants::f32_tag:
case Constants::f64_tag:
case Constants::v128_tag:
case Constants::nullable_reference_tag_tag:
case Constants::non_nullable_reference_tag_tag: {
ReconsumableStream value_stream { stream };
value_stream.unread({ &kind, 1 });
return BlockType { TRY(ValueType::parse(value_stream)) };
}
default:
break;
}
return BlockType { value_type };
if (auto abstract_kind = abstract_heap_type_from_tag(kind); abstract_kind.has_value())
return BlockType { ValueType(*abstract_kind) };
ReconsumableStream index_stream { stream };
index_stream.unread({ &kind, 1 });
auto type_index = TRY(parse_signed_integer_of_size<33>(index_stream));
if (type_index < 0 || type_index > NumericLimits<u32>::max())
return with_eof_check(stream, ParseError::InvalidIndex);
return BlockType { TypeIndex(static_cast<u32>(type_index)) };
}
ParseResult<Catch> Catch::parse(ConstrainedStream& stream)
@ -486,10 +578,8 @@ ParseResult<Instruction> Instruction::parse(ConstrainedStream& stream)
return Instruction { opcode, types };
}
case Instructions::ref_null.value(): {
auto type = TRY(ValueType::parse(stream));
if (!type.is_reference())
return ParseError::InvalidType;
// https://webassembly.github.io/spec/core/binary/instructions.html#reference-instructions
auto type = TRY(parse_heap_type(stream));
return Instruction { opcode, type };
}
case Instructions::ref_func.value(): {
@ -1035,27 +1125,72 @@ ParseResult<CustomSection> CustomSection::parse(ConstrainedStream& stream)
return CustomSection(name, move(data_buffer));
}
ParseResult<TypeSection::Type> TypeSection::Type::parse(ConstrainedStream& stream)
// https://webassembly.github.io/spec/core/binary/types.html#recursive-types
ParseResult<TypeSection::Type> TypeSection::Type::parse(ConstrainedStream& stream, Optional<u8> leading_tag)
{
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Type"sv);
auto tag = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
u8 tag;
if (leading_tag.has_value())
tag = *leading_tag;
else
tag = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
bool is_final = true;
Vector<TypeIndex> supertypes;
if (tag == Constants::sub_type_tag || tag == Constants::sub_final_type_tag) {
is_final = tag == Constants::sub_final_type_tag;
supertypes = TRY(parse_vector<GenericIndexParser<TypeIndex>>(stream));
tag = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
}
switch (tag) {
case Constants::function_signature_tag:
return Type { TRY(FunctionType::parse(stream)) };
return Type { TRY(FunctionType::parse(stream)), move(supertypes), is_final };
case Constants::struct_tag:
return Type { TRY(StructType::parse(stream)) };
return Type { TRY(StructType::parse(stream)), move(supertypes), is_final };
case Constants::array_tag:
return Type { TRY(ArrayType::parse(stream)) };
return Type { TRY(ArrayType::parse(stream)), move(supertypes), is_final };
default:
return ParseError::InvalidTag;
}
}
// https://webassembly.github.io/spec/core/binary/modules.html#type-section
// https://webassembly.github.io/spec/core/binary/types.html#recursive-types
ParseResult<TypeSection> TypeSection::parse(ConstrainedStream& stream)
{
ScopeLogger<WASM_BINPARSER_DEBUG> logger("TypeSection"sv);
auto types = TRY(parse_vector<Type>(stream));
auto rec_type_count_or_error = stream.read_value<LEB128<u32>>();
if (rec_type_count_or_error.is_error())
return with_eof_check(stream, ParseError::ExpectedSize);
size_t rec_type_count = rec_type_count_or_error.release_value();
Vector<Type> types;
types.ensure_capacity(rec_type_count);
for (size_t rec_type_index = 0; rec_type_index < rec_type_count; ++rec_type_index) {
auto tag = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
auto first_type_index = types.size();
if (tag == Constants::rec_group_tag) {
auto sub_type_count_or_error = stream.read_value<LEB128<u32>>();
if (sub_type_count_or_error.is_error())
return with_eof_check(stream, ParseError::ExpectedSize);
size_t sub_type_count = sub_type_count_or_error.release_value();
for (size_t i = 0; i < sub_type_count; ++i)
types.append(TRY(Type::parse(stream)));
} else {
types.append(TRY(Type::parse(stream, tag)));
}
Type::RecGroupSpan const span {
static_cast<u32>(first_type_index),
static_cast<u32>(types.size() - first_type_index),
};
for (size_t i = first_type_index; i < types.size(); ++i)
types[i].set_rec_group(span);
}
return TypeSection { types };
}

View file

@ -806,9 +806,24 @@ void Printer::print(Wasm::Value const& value, Wasm::ValueType const& type)
case ValueType::V128:
print("v128({:x})", value.value());
break;
case ValueType::I8:
print("{}", value.to<i8>());
break;
case ValueType::I16:
print("{}", value.to<i16>());
break;
case ValueType::FunctionReference:
case ValueType::NoFunctionReference:
case ValueType::ExternReference:
case ValueType::NoExternReference:
case ValueType::ExceptionReference:
case ValueType::NoExceptionReference:
case ValueType::AnyReference:
case ValueType::EqReference:
case ValueType::I31Reference:
case ValueType::StructReference:
case ValueType::ArrayReference:
case ValueType::NoneReference:
print("addr({})",
value.to<Reference>().ref().visit(
[](Wasm::Reference::Null const&) { return ByteString("null"); },
@ -816,10 +831,7 @@ void Printer::print(Wasm::Value const& value, Wasm::ValueType const& type)
[](auto const& ref) { return ByteString::number(ref.address.value()); }));
break;
case ValueType::TypeUseReference:
print("unsupported-type-use-ref({})", type.unsafe_typeindex());
break;
case ValueType::UnsupportedHeapReference:
print("unsupported-heap-ref");
print("typed-ref({})", type.unsafe_typeindex());
break;
}
TemporaryChange<size_t> change { m_indent, 0 };

View file

@ -190,7 +190,15 @@ private:
Vector<u8, 8> m_buffer;
};
// https://webassembly.github.io/spec/core/bikeshed/#value-types%E2%91%A2
// https://webassembly.github.io/spec/core/syntax/types.html#value-types
// valtype ::= numtype | vectype | reftype
// https://webassembly.github.io/spec/core/syntax/types.html#reference-types
// reftype ::= ref null? heaptype
// https://webassembly.github.io/spec/core/syntax/types.html#heap-types
// heaptype ::= absheaptype | typeidx
// absheaptype ::= func | nofunc | extern | noextern | any | eq | i31 | struct | array | none | exn | noexn
// https://webassembly.github.io/spec/core/syntax/types.html#composite-types
// packtype ::= i8 | i16
class ValueType {
public:
enum Kind : u8 {
@ -199,11 +207,21 @@ public:
F32,
F64,
V128,
I8, // as packtype
I16, // as packtype
FunctionReference,
NoFunctionReference,
ExternReference,
NoExternReference,
AnyReference,
EqReference,
I31Reference,
StructReference,
ArrayReference,
NoneReference,
ExceptionReference,
NoExceptionReference,
TypeUseReference,
UnsupportedHeapReference, // Stub for wasm-gc proposal's reference types.
};
explicit ValueType(Kind kind)
@ -211,8 +229,15 @@ public:
{
}
explicit ValueType(Kind kind, TypeIndex type_index)
explicit ValueType(Kind kind, bool nullable)
: m_kind(kind)
, m_nullable(nullable)
{
}
explicit ValueType(Kind kind, TypeIndex type_index, bool nullable = true)
: m_kind(kind)
, m_nullable(nullable)
, m_type_index(type_index)
{
VERIFY(kind == TypeUseReference);
@ -223,12 +248,31 @@ public:
bool is_nullable() const { return m_nullable; }
void set_nullable(bool nullable) { m_nullable = nullable; }
auto is_reference() const { return m_kind == ExternReference || m_kind == FunctionReference || m_kind == TypeUseReference || m_kind == UnsupportedHeapReference; }
auto is_reference() const { return m_kind >= FunctionReference; }
auto is_vector() const { return m_kind == V128; }
auto is_numeric() const { return !is_reference() && !is_vector(); }
auto is_packed() const { return m_kind == I8 || m_kind == I16; }
auto is_numeric() const { return !is_reference() && !is_vector() && !is_packed(); }
auto is_typeuse() const { return m_kind == TypeUseReference; }
auto kind() const { return m_kind; }
// https://webassembly.github.io/spec/core/syntax/types.html#aux-unpack
// unpack(valtype) = valtype
// unpack(packtype) = i32
ValueType unpacked() const
{
if (is_packed())
return ValueType(I32);
return *this;
}
// https://webassembly.github.io/spec/core/valid/types.html#defaultable-types
bool is_defaultable() const
{
if (is_reference())
return m_nullable;
return true;
}
auto unsafe_typeindex() const
{
VERIFY(m_kind == TypeUseReference);
@ -250,16 +294,36 @@ public:
return "f64";
case V128:
return "v128";
case I8:
return "i8";
case I16:
return "i16";
case FunctionReference:
return m_nullable ? "funcref" : "ref func";
return m_nullable ? "funcref" : "(ref func)";
case NoFunctionReference:
return m_nullable ? "nullfuncref" : "(ref nofunc)";
case ExternReference:
return m_nullable ? "externref" : "ref extern";
return m_nullable ? "externref" : "(ref extern)";
case NoExternReference:
return m_nullable ? "nullexternref" : "(ref noextern)";
case AnyReference:
return m_nullable ? "anyref" : "(ref any)";
case EqReference:
return m_nullable ? "eqref" : "(ref eq)";
case I31Reference:
return m_nullable ? "i31ref" : "(ref i31)";
case StructReference:
return m_nullable ? "structref" : "(ref struct)";
case ArrayReference:
return m_nullable ? "arrayref" : "(ref array)";
case NoneReference:
return m_nullable ? "nullref" : "(ref none)";
case ExceptionReference:
return "exnref";
return m_nullable ? "exnref" : "(ref exn)";
case NoExceptionReference:
return m_nullable ? "nullexnref" : "(ref noexn)";
case TypeUseReference:
return ByteString::formatted("ref {} {}", m_nullable ? "null" : "", unsafe_typeindex().value());
case UnsupportedHeapReference:
return "todo.heapref";
return ByteString::formatted("(ref {}{})", m_nullable ? "null " : "", unsafe_typeindex().value());
}
VERIFY_NOT_REACHED();
}
@ -1014,13 +1078,22 @@ private:
class TypeSection {
public:
// https://webassembly.github.io/spec/core/syntax/types.html#recursive-types
// https://webassembly.github.io/spec/core/syntax/types.html#composite-types
class Type {
private:
using TypeDesc = Variant<FunctionType, StructType, ArrayType>;
using CompositeType = Variant<FunctionType, StructType, ArrayType>;
public:
Type(TypeDesc type)
: m_description(type)
struct RecGroupSpan {
u32 first_type_index { 0 };
u32 size { 1 };
};
Type(CompositeType type, Vector<TypeIndex> supertypes = {}, bool is_final = true)
: m_description(move(type))
, m_supertypes(move(supertypes))
, m_is_final(is_final)
{
}
@ -1033,6 +1106,16 @@ public:
auto& struct_() const { return m_description.get<StructType>(); }
bool is_struct() const { return m_description.has<StructType>(); }
auto& array() const { return m_description.get<ArrayType>(); }
bool is_array() const { return m_description.has<ArrayType>(); }
// sub final? x* ct
auto& supertypes() const { return m_supertypes; }
bool is_final() const { return m_is_final; }
auto& rec_group() const { return m_rec_group; }
void set_rec_group(RecGroupSpan span) { m_rec_group = span; }
ByteString name() const
{
return m_description.visit(
@ -1041,10 +1124,13 @@ public:
[](ArrayType const&) -> ByteString { return "array type"; });
}
static ParseResult<Type> parse(ConstrainedStream& stream);
static ParseResult<Type> parse(ConstrainedStream& stream, Optional<u8> leading_tag = {});
private:
TypeDesc m_description;
CompositeType m_description;
Vector<TypeIndex> m_supertypes;
bool m_is_final { true };
RecGroupSpan m_rec_group;
};
TypeSection() = default;

View file

@ -788,8 +788,21 @@ JS::ThrowCompletionOr<Wasm::Value> to_webassembly_value(JS::VM& vm, JS::Value va
return Wasm::Value(Wasm::ValueType { Wasm::ValueType::Kind::ExceptionReference });
case Wasm::ValueType::V128:
return vm.throw_completion<JS::TypeError>("Cannot convert a vector value to a javascript value"sv);
case Wasm::ValueType::I8:
case Wasm::ValueType::I16:
return vm.throw_completion<JS::TypeError>("Cannot convert a packed value to a javascript value"sv);
case Wasm::ValueType::NoFunctionReference:
case Wasm::ValueType::NoExternReference:
case Wasm::ValueType::AnyReference:
case Wasm::ValueType::EqReference:
case Wasm::ValueType::I31Reference:
case Wasm::ValueType::StructReference:
case Wasm::ValueType::ArrayReference:
case Wasm::ValueType::NoneReference:
case Wasm::ValueType::NoExceptionReference:
case Wasm::ValueType::TypeUseReference:
case Wasm::ValueType::UnsupportedHeapReference:
// FIXME: Implement the conversions for the wasm-gc reference hierarchy
// (https://webassembly.github.io/spec/js-api/#tojsvalue).
return vm.throw_completion<JS::TypeError>("Unsupported heap reference"sv);
}
@ -810,10 +823,19 @@ Wasm::Value default_webassembly_value(JS::VM& vm, Wasm::ValueType type)
return MUST(to_webassembly_value(vm, JS::js_undefined(), type));
case Wasm::ValueType::ExceptionReference:
return Wasm::Value(type);
case Wasm::ValueType::I8:
case Wasm::ValueType::I16:
case Wasm::ValueType::NoFunctionReference:
case Wasm::ValueType::NoExternReference:
case Wasm::ValueType::AnyReference:
case Wasm::ValueType::EqReference:
case Wasm::ValueType::I31Reference:
case Wasm::ValueType::StructReference:
case Wasm::ValueType::ArrayReference:
case Wasm::ValueType::NoneReference:
case Wasm::ValueType::NoExceptionReference:
case Wasm::ValueType::TypeUseReference:
return Wasm::Value(type);
case Wasm::ValueType::UnsupportedHeapReference:
return Wasm::Value(type);
}
VERIFY_NOT_REACHED();
}
@ -858,9 +880,19 @@ JS::Value to_js_value(JS::VM& vm, Wasm::Value& wasm_value, Wasm::ValueType type)
return value.release_value();
}
case Wasm::ValueType::V128:
case Wasm::ValueType::I8:
case Wasm::ValueType::I16:
case Wasm::ValueType::ExceptionReference:
case Wasm::ValueType::NoFunctionReference:
case Wasm::ValueType::NoExternReference:
case Wasm::ValueType::AnyReference:
case Wasm::ValueType::EqReference:
case Wasm::ValueType::I31Reference:
case Wasm::ValueType::StructReference:
case Wasm::ValueType::ArrayReference:
case Wasm::ValueType::NoneReference:
case Wasm::ValueType::NoExceptionReference:
case Wasm::ValueType::TypeUseReference:
case Wasm::ValueType::UnsupportedHeapReference:
VERIFY_NOT_REACHED();
}
VERIFY_NOT_REACHED();

View file

@ -346,16 +346,26 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::get_export)
return JS::BigInt::create(vm, Crypto::SignedBigInteger::import_data(value.bytes()));
}
case Wasm::ValueType::FunctionReference:
case Wasm::ValueType::NoFunctionReference:
case Wasm::ValueType::ExternReference:
case Wasm::ValueType::ExceptionReference: {
case Wasm::ValueType::NoExternReference:
case Wasm::ValueType::ExceptionReference:
case Wasm::ValueType::NoExceptionReference:
case Wasm::ValueType::AnyReference:
case Wasm::ValueType::EqReference:
case Wasm::ValueType::I31Reference:
case Wasm::ValueType::StructReference:
case Wasm::ValueType::ArrayReference:
case Wasm::ValueType::NoneReference: {
auto ref = global->value().to<Wasm::Reference>();
return ref.ref().visit(
[&](Wasm::Reference::Null const&) -> JS::Value { return JS::js_null(); },
[](Wasm::Reference::Exception const&) -> JS::Value { return JS::js_undefined(); },
[&](auto const& ref) -> JS::Value { return JS::Value(static_cast<double>(ref.address.value())); });
}
case Wasm::ValueType::I8:
case Wasm::ValueType::I16:
case Wasm::ValueType::TypeUseReference:
case Wasm::ValueType::UnsupportedHeapReference:
return vm.throw_completion<JS::TypeError>("Unsupported heap reference"sv);
}
}
@ -449,8 +459,23 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke)
else
return vm.throw_completion<JS::TypeError>("GC Heap references are not supported"sv);
break;
case Wasm::ValueType::Kind::UnsupportedHeapReference:
return vm.throw_completion<JS::TypeError>("GC Heap references are not supported"sv);
case Wasm::ValueType::Kind::NoFunctionReference:
case Wasm::ValueType::Kind::NoExternReference:
case Wasm::ValueType::Kind::AnyReference:
case Wasm::ValueType::Kind::EqReference:
case Wasm::ValueType::Kind::I31Reference:
case Wasm::ValueType::Kind::StructReference:
case Wasm::ValueType::Kind::ArrayReference:
case Wasm::ValueType::Kind::NoneReference:
case Wasm::ValueType::Kind::NoExceptionReference:
if (argument.is_null())
arguments.append(Wasm::Value(Wasm::Reference { Wasm::Reference::Null { Wasm::ValueType(param.kind()) } }));
else
return vm.throw_completion<JS::TypeError>("GC Heap references are not supported"sv);
break;
case Wasm::ValueType::Kind::I8:
case Wasm::ValueType::Kind::I16:
return vm.throw_completion<JS::TypeError>("Packed types are not valid parameter types"sv);
}
}
@ -483,14 +508,24 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke)
return JS::Value(buf);
}
case Wasm::ValueType::FunctionReference:
case Wasm::ValueType::NoFunctionReference:
case Wasm::ValueType::ExternReference:
case Wasm::ValueType::NoExternReference:
case Wasm::ValueType::AnyReference:
case Wasm::ValueType::EqReference:
case Wasm::ValueType::I31Reference:
case Wasm::ValueType::StructReference:
case Wasm::ValueType::ArrayReference:
case Wasm::ValueType::NoneReference:
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::NoExceptionReference:
return JS::js_null();
case Wasm::ValueType::TypeUseReference:
return JS::js_null();
case Wasm::ValueType::UnsupportedHeapReference:
return vm.throw_completion<JS::TypeError>("Unsupported heap reference"sv);
case Wasm::ValueType::I8:
case Wasm::ValueType::I16:
return vm.throw_completion<JS::TypeError>("Unsupported packed type"sv);
}
VERIFY_NOT_REACHED();
};

View file

@ -233,11 +233,21 @@ static ErrorOr<ParsedValue> parse_value(StringView spec)
width = sizeof(u64);
break;
case Wasm::ValueType::V128:
case Wasm::ValueType::I8:
case Wasm::ValueType::I16:
case Wasm::ValueType::FunctionReference:
case Wasm::ValueType::NoFunctionReference:
case Wasm::ValueType::ExternReference:
case Wasm::ValueType::NoExternReference:
case Wasm::ValueType::ExceptionReference:
case Wasm::ValueType::NoExceptionReference:
case Wasm::ValueType::AnyReference:
case Wasm::ValueType::EqReference:
case Wasm::ValueType::I31Reference:
case Wasm::ValueType::StructReference:
case Wasm::ValueType::ArrayReference:
case Wasm::ValueType::NoneReference:
case Wasm::ValueType::TypeUseReference:
case Wasm::ValueType::UnsupportedHeapReference:
VERIFY_NOT_REACHED();
}
last_value = parsed.value.value();