LibWasm: Parse wasm-gc types
No more unsupported heap refs.
This commit is contained in:
parent
5ec468bfdd
commit
3ca552b37b
10 changed files with 447 additions and 97 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_); },
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in a new issue