diff --git a/include/wabt/binary-reader-logging.h b/include/wabt/binary-reader-logging.h index 4a031f74bb..bd7ff33fe1 100644 --- a/include/wabt/binary-reader-logging.h +++ b/include/wabt/binary-reader-logging.h @@ -174,6 +174,8 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Result OnBlockExpr(Type sig_type) override; Result OnBrExpr(Index depth) override; Result OnBrIfExpr(Index depth) override; + Result OnBrOnNonNullExpr(Index depth) override; + Result OnBrOnNullExpr(Index depth) override; Result OnBrTableExpr(Index num_targets, Index* target_depths, Index default_target_depth) override; @@ -181,7 +183,7 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Result OnCatchExpr(Index tag_index) override; Result OnCatchAllExpr() override; Result OnCallIndirectExpr(Index sig_index, Index table_index) override; - Result OnCallRefExpr() override; + Result OnCallRefExpr(Type sig_type) override; Result OnCompareExpr(Opcode opcode) override; Result OnConvertExpr(Opcode opcode) override; Result OnDelegateExpr(Index depth) override; @@ -218,12 +220,14 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Result OnTableGrowExpr(Index table) override; Result OnTableSizeExpr(Index table) override; Result OnTableFillExpr(Index table) override; + Result OnRefAsNonNullExpr() override; Result OnRefFuncExpr(Index index) override; Result OnRefNullExpr(Type type) override; Result OnRefIsNullExpr() override; Result OnNopExpr() override; Result OnRethrowExpr(Index depth) override; Result OnReturnCallExpr(Index func_index) override; + Result OnReturnCallRefExpr(Type sig_type) override; Result OnReturnCallIndirectExpr(Index sig_index, Index table_index) override; Result OnReturnExpr() override; Result OnSelectExpr(Index result_count, Type* result_types) override; diff --git a/include/wabt/binary-reader-nop.h b/include/wabt/binary-reader-nop.h index fdb7d14a41..545db127b2 100644 --- a/include/wabt/binary-reader-nop.h +++ b/include/wabt/binary-reader-nop.h @@ -241,6 +241,8 @@ class BinaryReaderNop : public BinaryReaderDelegate { Result OnBlockExpr(Type sig_type) override { return Result::Ok; } Result OnBrExpr(Index depth) override { return Result::Ok; } Result OnBrIfExpr(Index depth) override { return Result::Ok; } + Result OnBrOnNonNullExpr(Index depth) override { return Result::Ok; } + Result OnBrOnNullExpr(Index depth) override { return Result::Ok; } Result OnBrTableExpr(Index num_targets, Index* target_depths, Index default_target_depth) override { @@ -250,7 +252,7 @@ class BinaryReaderNop : public BinaryReaderDelegate { Result OnCallIndirectExpr(Index sig_index, Index table_index) override { return Result::Ok; } - Result OnCallRefExpr() override { return Result::Ok; } + Result OnCallRefExpr(Type sig_type) override { return Result::Ok; } Result OnCatchExpr(Index tag_index) override { return Result::Ok; } Result OnCatchAllExpr() override { return Result::Ok; } Result OnCompareExpr(Opcode opcode) override { return Result::Ok; } @@ -299,6 +301,7 @@ class BinaryReaderNop : public BinaryReaderDelegate { Result OnTableGrowExpr(Index table_index) override { return Result::Ok; } Result OnTableSizeExpr(Index table_index) override { return Result::Ok; } Result OnTableFillExpr(Index table_index) override { return Result::Ok; } + Result OnRefAsNonNullExpr() override { return Result::Ok; } Result OnRefFuncExpr(Index func_index) override { return Result::Ok; } Result OnRefNullExpr(Type type) override { return Result::Ok; } Result OnRefIsNullExpr() override { return Result::Ok; } @@ -308,6 +311,7 @@ class BinaryReaderNop : public BinaryReaderDelegate { Result OnReturnCallIndirectExpr(Index sig_index, Index table_index) override { return Result::Ok; } + Result OnReturnCallRefExpr(Type sig_type) override { return Result::Ok; } Result OnReturnExpr() override { return Result::Ok; } Result OnSelectExpr(Index result_count, Type* result_types) override { return Result::Ok; diff --git a/include/wabt/binary-reader.h b/include/wabt/binary-reader.h index 94b19c1100..96455f2251 100644 --- a/include/wabt/binary-reader.h +++ b/include/wabt/binary-reader.h @@ -250,12 +250,14 @@ class BinaryReaderDelegate { virtual Result OnBlockExpr(Type sig_type) = 0; virtual Result OnBrExpr(Index depth) = 0; virtual Result OnBrIfExpr(Index depth) = 0; + virtual Result OnBrOnNonNullExpr(Index depth) = 0; + virtual Result OnBrOnNullExpr(Index depth) = 0; virtual Result OnBrTableExpr(Index num_targets, Index* target_depths, Index default_target_depth) = 0; virtual Result OnCallExpr(Index func_index) = 0; virtual Result OnCallIndirectExpr(Index sig_index, Index table_index) = 0; - virtual Result OnCallRefExpr() = 0; + virtual Result OnCallRefExpr(Type sig_type) = 0; virtual Result OnCatchExpr(Index tag_index) = 0; virtual Result OnCatchAllExpr() = 0; virtual Result OnCompareExpr(Opcode opcode) = 0; @@ -294,6 +296,7 @@ class BinaryReaderDelegate { virtual Result OnTableGrowExpr(Index table_index) = 0; virtual Result OnTableSizeExpr(Index table_index) = 0; virtual Result OnTableFillExpr(Index table_index) = 0; + virtual Result OnRefAsNonNullExpr() = 0; virtual Result OnRefFuncExpr(Index func_index) = 0; virtual Result OnRefNullExpr(Type type) = 0; virtual Result OnRefIsNullExpr() = 0; @@ -303,6 +306,7 @@ class BinaryReaderDelegate { virtual Result OnReturnCallExpr(Index func_index) = 0; virtual Result OnReturnCallIndirectExpr(Index sig_index, Index table_index) = 0; + virtual Result OnReturnCallRefExpr(Type sig_type) = 0; virtual Result OnSelectExpr(Index result_count, Type* result_types) = 0; virtual Result OnStoreExpr(Opcode opcode, Index memidx, diff --git a/include/wabt/expr-visitor.h b/include/wabt/expr-visitor.h index 5be7879391..cef8025baa 100644 --- a/include/wabt/expr-visitor.h +++ b/include/wabt/expr-visitor.h @@ -73,6 +73,8 @@ class ExprVisitor::Delegate { virtual Result EndBlockExpr(BlockExpr*) = 0; virtual Result OnBrExpr(BrExpr*) = 0; virtual Result OnBrIfExpr(BrIfExpr*) = 0; + virtual Result OnBrOnNonNullExpr(BrOnNonNullExpr*) = 0; + virtual Result OnBrOnNullExpr(BrOnNullExpr*) = 0; virtual Result OnBrTableExpr(BrTableExpr*) = 0; virtual Result BeginTryTableExpr(TryTableExpr*) = 0; virtual Result EndTryTableExpr(TryTableExpr*) = 0; @@ -109,6 +111,7 @@ class ExprVisitor::Delegate { virtual Result OnTableGrowExpr(TableGrowExpr*) = 0; virtual Result OnTableSizeExpr(TableSizeExpr*) = 0; virtual Result OnTableFillExpr(TableFillExpr*) = 0; + virtual Result OnRefAsNonNullExpr(RefAsNonNullExpr*) = 0; virtual Result OnRefFuncExpr(RefFuncExpr*) = 0; virtual Result OnRefNullExpr(RefNullExpr*) = 0; virtual Result OnRefIsNullExpr(RefIsNullExpr*) = 0; @@ -116,6 +119,7 @@ class ExprVisitor::Delegate { virtual Result OnReturnExpr(ReturnExpr*) = 0; virtual Result OnReturnCallExpr(ReturnCallExpr*) = 0; virtual Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr*) = 0; + virtual Result OnReturnCallRefExpr(ReturnCallRefExpr*) = 0; virtual Result OnSelectExpr(SelectExpr*) = 0; virtual Result OnStoreExpr(StoreExpr*) = 0; virtual Result OnUnaryExpr(UnaryExpr*) = 0; @@ -150,6 +154,8 @@ class ExprVisitor::DelegateNop : public ExprVisitor::Delegate { Result EndBlockExpr(BlockExpr*) override { return Result::Ok; } Result OnBrExpr(BrExpr*) override { return Result::Ok; } Result OnBrIfExpr(BrIfExpr*) override { return Result::Ok; } + Result OnBrOnNonNullExpr(BrOnNonNullExpr*) override { return Result::Ok; }; + Result OnBrOnNullExpr(BrOnNullExpr*) override { return Result::Ok; }; Result OnBrTableExpr(BrTableExpr*) override { return Result::Ok; } Result BeginTryTableExpr(TryTableExpr*) override { return Result::Ok; } Result EndTryTableExpr(TryTableExpr*) override { return Result::Ok; } @@ -186,6 +192,7 @@ class ExprVisitor::DelegateNop : public ExprVisitor::Delegate { Result OnTableGrowExpr(TableGrowExpr*) override { return Result::Ok; } Result OnTableSizeExpr(TableSizeExpr*) override { return Result::Ok; } Result OnTableFillExpr(TableFillExpr*) override { return Result::Ok; } + Result OnRefAsNonNullExpr(RefAsNonNullExpr*) override { return Result::Ok; } Result OnRefFuncExpr(RefFuncExpr*) override { return Result::Ok; } Result OnRefNullExpr(RefNullExpr*) override { return Result::Ok; } Result OnRefIsNullExpr(RefIsNullExpr*) override { return Result::Ok; } @@ -195,6 +202,7 @@ class ExprVisitor::DelegateNop : public ExprVisitor::Delegate { Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr*) override { return Result::Ok; } + Result OnReturnCallRefExpr(ReturnCallRefExpr*) override { return Result::Ok; } Result OnSelectExpr(SelectExpr*) override { return Result::Ok; } Result OnStoreExpr(StoreExpr*) override { return Result::Ok; } Result OnUnaryExpr(UnaryExpr*) override { return Result::Ok; } diff --git a/include/wabt/interp/interp-inl.h b/include/wabt/interp/interp-inl.h index a9ac4a3488..074fc9fc9f 100644 --- a/include/wabt/interp/interp-inl.h +++ b/include/wabt/interp/interp-inl.h @@ -42,7 +42,7 @@ inline bool FuncType::classof(const ExternType* type) { } inline FuncType::FuncType(ValueTypes params, ValueTypes results) - : ExternType(ExternKind::Func), params(params), results(results) {} + : ExternType(ExternKind::Func), params(params), results(results), func_types(nullptr) {} //// TableType //// // static diff --git a/include/wabt/interp/interp.h b/include/wabt/interp/interp.h index 9ce7b1815e..4e376eb327 100644 --- a/include/wabt/interp/interp.h +++ b/include/wabt/interp/interp.h @@ -184,6 +184,10 @@ struct FuncType : ExternType { ValueTypes params; ValueTypes results; + // When params or results contain references, the referenced + // types are also needed for type equality comparisons. + // An example for these comparisons is import validation. + std::vector* func_types; }; struct TableType : ExternType { diff --git a/include/wabt/ir.h b/include/wabt/ir.h index 5fa4439a0c..9102297dc8 100644 --- a/include/wabt/ir.h +++ b/include/wabt/ir.h @@ -36,24 +36,43 @@ namespace wabt { struct Module; -enum class VarType { +// VarType (16 bit) and the opt_type_ (16 bit) +// fields of Var forms a 32 bit field. +enum class VarType : uint16_t { Index, Name, }; struct Var { + // Var can represent variables or types. + + // Represent a variable: + // has_opt_type() is false + // Only used by wast-parser + + // Represent a type: + // has_opt_type() is true, is_index() is true + // type can be get by to_type() + // Binary reader only constructs this variant + + // Represent both a variable and a type: + // has_opt_type() is true, is_name() is true + // A reference, which index is unknown + // Only used by wast-parser + explicit Var(); explicit Var(Index index, const Location& loc); explicit Var(std::string_view name, const Location& loc); + explicit Var(Type type, const Location& loc); Var(Var&&); Var(const Var&); Var& operator=(const Var&); Var& operator=(Var&&); ~Var(); - VarType type() const { return type_; } bool is_index() const { return type_ == VarType::Index; } bool is_name() const { return type_ == VarType::Name; } + bool has_opt_type() const { return opt_type_ < 0; } Index index() const { assert(is_index()); @@ -63,10 +82,16 @@ struct Var { assert(is_name()); return name_; } + Type::Enum opt_type() const { + assert(has_opt_type()); + return static_cast(opt_type_); + } void set_index(Index); void set_name(std::string&&); void set_name(std::string_view); + void set_opt_type(Type::Enum); + Type to_type() const; Location loc; @@ -74,6 +99,8 @@ struct Var { void Destroy(); VarType type_; + // Can be set to Type::Enum types, Type::Any represent no optional type. + int16_t opt_type_; union { Index index_; std::string name_; @@ -155,6 +182,7 @@ struct Const { } void set_funcref() { From(Type::FuncRef, 0); } void set_externref(uintptr_t x) { From(Type::ExternRef, x); } + void set_extern(uintptr_t x) { From(Type(Type::ExternRef, Type::ReferenceNonNull), x); } void set_null(Type type) { From(type, kRefNullBits); } bool is_expected_nan(int lane = 0) const { @@ -366,6 +394,8 @@ enum class ExprType { Block, Br, BrIf, + BrOnNonNull, + BrOnNull, BrTable, Call, CallIndirect, @@ -390,6 +420,7 @@ enum class ExprType { MemoryInit, MemorySize, Nop, + RefAsNonNull, RefIsNull, RefFunc, RefNull, @@ -397,6 +428,7 @@ enum class ExprType { Return, ReturnCall, ReturnCallIndirect, + ReturnCallRef, Select, SimdLaneOp, SimdLoadLane, @@ -537,10 +569,10 @@ using MemoryCopyExpr = MemoryBinaryExpr; template class RefTypeExpr : public ExprMixin { public: - RefTypeExpr(Type type, const Location& loc = Location()) + RefTypeExpr(Var type, const Location& loc = Location()) : ExprMixin(loc), type(type) {} - Type type; + Var type; }; using RefNullExpr = RefTypeExpr; @@ -560,6 +592,7 @@ using CompareExpr = OpcodeExpr; using ConvertExpr = OpcodeExpr; using UnaryExpr = OpcodeExpr; using TernaryExpr = OpcodeExpr; +using RefAsNonNullExpr = OpcodeExpr; class SimdLaneOpExpr : public ExprMixin { public: @@ -639,6 +672,8 @@ class MemoryVarExpr : public MemoryExpr { using BrExpr = VarExpr; using BrIfExpr = VarExpr; +using BrOnNonNullExpr = VarExpr; +using BrOnNullExpr = VarExpr; using CallExpr = VarExpr; using RefFuncExpr = VarExpr; using GlobalGetExpr = VarExpr; @@ -662,8 +697,8 @@ using MemoryInitExpr = MemoryVarExpr; class SelectExpr : public ExprMixin { public: - SelectExpr(TypeVector type, const Location& loc = Location()) - : ExprMixin(loc), result_type(type) {} + SelectExpr(const Location& loc = Location()) + : ExprMixin(loc) {} TypeVector result_type; }; @@ -727,9 +762,15 @@ class CallRefExpr : public ExprMixin { explicit CallRefExpr(const Location& loc = Location()) : ExprMixin(loc) {} - // This field is setup only during Validate phase, - // so keep that in mind when you use it. - Var function_type_index; + Var sig_type; +}; + +class ReturnCallRefExpr : public ExprMixin { + public: + explicit ReturnCallRefExpr(const Location& loc = Location()) + : ExprMixin(loc) {} + + Var sig_type; }; template diff --git a/include/wabt/opcode.def b/include/wabt/opcode.def index 4218a30b80..901c0359a8 100644 --- a/include/wabt/opcode.def +++ b/include/wabt/opcode.def @@ -56,6 +56,7 @@ WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x11, CallIndirect, "call_indirect WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x12, ReturnCall, "return_call", "") WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x13, ReturnCallIndirect, "return_call_indirect", "") WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x14, CallRef, "call_ref", "") +WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x15, ReturnCallRef, "return_call_ref", "") WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x18, Delegate, "delegate", "") WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x19, CatchAll, "catch_all", "") WABT_OPCODE(___, ___, ___, ___, 0, 0, 0x1a, Drop, "drop", "") @@ -267,6 +268,9 @@ WABT_OPCODE(___, I32, ___, I32, 0, 0xfc, 0x11, TableFill, "table.fill", "") WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xd0, RefNull, "ref.null", "") WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xd1, RefIsNull, "ref.is_null", "") WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xd2, RefFunc, "ref.func", "") +WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xd4, RefAsNonNull, "ref.as_non_null", "") +WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xd5, BrOnNull, "br_on_null", "") +WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xd6, BrOnNonNull, "br_on_non_null", "") /* Simd opcodes */ WABT_OPCODE(V128, I32, ___, ___, 16, 0xfd, 0x00, V128Load, "v128.load", "") diff --git a/include/wabt/shared-validator.h b/include/wabt/shared-validator.h index 267a77b276..d568aac805 100644 --- a/include/wabt/shared-validator.h +++ b/include/wabt/shared-validator.h @@ -43,6 +43,7 @@ struct ValidateOptions { class SharedValidator { public: WABT_DISALLOW_COPY_AND_ASSIGN(SharedValidator); + using FuncType = TypeChecker::FuncType; SharedValidator(Errors*, const ValidateOptions& options); // TODO: Move into SharedValidator? @@ -72,7 +73,6 @@ class SharedValidator { Index type_index); Result OnStructType(const Location&, Index field_count, TypeMut* fields); Result OnArrayType(const Location&, TypeMut field); - Result EndTypeSection(); Result OnFunction(const Location&, Var sig_var); Result OnTable(const Location&, Type elem_type, const Limits&); @@ -136,12 +136,14 @@ class SharedValidator { Result OnBlock(const Location&, Type sig_type); Result OnBr(const Location&, Var depth); Result OnBrIf(const Location&, Var depth); + Result OnBrOnNonNull(const Location&, Var depth); + Result OnBrOnNull(const Location&, Var depth); Result BeginBrTable(const Location&); Result OnBrTableTarget(const Location&, Var depth); Result EndBrTable(const Location&); Result OnCall(const Location&, Var func_var); Result OnCallIndirect(const Location&, Var sig_var, Var table_var); - Result OnCallRef(const Location&, Index* function_type_index); + Result OnCallRef(const Location&, Var function_type_var); Result OnCatch(const Location&, Var tag_var, bool is_catch_all); Result OnCompare(const Location&, Opcode); Result OnConst(const Location&, Type); @@ -176,12 +178,14 @@ class SharedValidator { Result OnMemoryInit(const Location&, Var segment_var, Var memidx); Result OnMemorySize(const Location&, Var memidx); Result OnNop(const Location&); + Result OnRefAsNonNull(const Location&); Result OnRefFunc(const Location&, Var func_var); Result OnRefIsNull(const Location&); - Result OnRefNull(const Location&, Type type); + Result OnRefNull(const Location&, Var func_type_var); Result OnRethrow(const Location&, Var depth); Result OnReturnCall(const Location&, Var func_var); Result OnReturnCallIndirect(const Location&, Var sig_var, Var table_var); + Result OnReturnCallRef(const Location&, Var function_type_var); Result OnReturn(const Location&); Result OnSelect(const Location&, Index result_count, Type* result_types); Result OnSimdLaneOp(const Location&, Opcode, uint64_t lane_idx); @@ -221,18 +225,6 @@ class SharedValidator { Result OnUnreachable(const Location&); private: - struct FuncType { - FuncType() = default; - FuncType(const TypeVector& params, - const TypeVector& results, - Index type_index) - : params(params), results(results), type_index(type_index) {} - - TypeVector params; - TypeVector results; - Index type_index; - }; - struct StructType { StructType() = default; StructType(const TypeMutVector& fields) : fields(fields) {} @@ -289,6 +281,11 @@ class SharedValidator { Index end; }; + struct LocalReferenceMap { + Type type; + Index bit_index; + }; + bool ValidInitOpcode(Opcode opcode) const; Result CheckInstr(Opcode opcode, const Location& loc); Result CheckType(const Location&, @@ -336,6 +333,10 @@ class SharedValidator { TypeVector ToTypeVector(Index count, const Type* types); + void SaveLocalRefs(); + void RestoreLocalRefs(Result result); + void IgnoreLocalRefs(); + ValidateOptions options_; Errors* errors_; TypeChecker typechecker_; // TODO: Move into SharedValidator. @@ -361,6 +362,8 @@ class SharedValidator { // Includes parameters, since this is only used for validating // local.{get,set,tee} instructions. std::vector locals_; + std::map local_refs_map_; + std::vector local_ref_is_set_; std::set export_names_; // Used to check for duplicates. std::set declared_funcs_; // TODO: optimize? diff --git a/include/wabt/token.def b/include/wabt/token.def index f2f05aec34..22b333cb73 100644 --- a/include/wabt/token.def +++ b/include/wabt/token.def @@ -55,6 +55,7 @@ WABT_TOKEN(Module, "module") WABT_TOKEN(Mut, "mut") WABT_TOKEN(NanArithmetic, "nan:arithmetic") WABT_TOKEN(NanCanonical, "nan:canonical") +WABT_TOKEN(Null, "null") WABT_TOKEN(Offset, "offset") WABT_TOKEN(Output, "output") WABT_TOKEN(PageSize, "pagesize") @@ -98,11 +99,14 @@ WABT_TOKEN(Binary, "BINARY") WABT_TOKEN(Block, "block") WABT_TOKEN(Br, "br") WABT_TOKEN(BrIf, "br_if") +WABT_TOKEN(BrOnNonNull, "br_on_non_null") +WABT_TOKEN(BrOnNull, "br_on_null") WABT_TOKEN(BrTable, "br_table") WABT_TOKEN(Code, "code") WABT_TOKEN(Call, "call") WABT_TOKEN(CallIndirect, "call_indirect") WABT_TOKEN(CallRef, "call_ref") +WABT_TOKEN(ReturnCallRef, "return_call_ref") WABT_TOKEN(Catch, "catch") WABT_TOKEN(CatchAll, "catch_all") WABT_TOKEN(CatchRef, "catch_ref") @@ -129,6 +133,7 @@ WABT_TOKEN(MemoryGrow, "memory.grow") WABT_TOKEN(MemoryInit, "memory.init") WABT_TOKEN(MemorySize, "memory.size") WABT_TOKEN(Nop, "nop") +WABT_TOKEN(RefAsNonNull, "ref.as_non_null") WABT_TOKEN(RefExtern, "ref.extern") WABT_TOKEN(RefFunc, "ref.func") WABT_TOKEN(RefIsNull, "ref.is_null") diff --git a/include/wabt/type-checker.h b/include/wabt/type-checker.h index 85575c3c8b..3600212a83 100644 --- a/include/wabt/type-checker.h +++ b/include/wabt/type-checker.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "wabt/common.h" #include "wabt/feature.h" @@ -31,6 +32,18 @@ class TypeChecker { public: using ErrorCallback = std::function; + struct FuncType { + FuncType() = default; + FuncType(const TypeVector& params, + const TypeVector& results, + Index type_index) + : params(params), results(results), type_index(type_index) {} + + TypeVector params; + TypeVector results; + Index type_index; + }; + struct Label { Label(LabelType, const TypeVector& param_types, @@ -46,9 +59,11 @@ class TypeChecker { TypeVector result_types; size_t type_stack_limit; bool unreachable; + std::vector local_ref_is_set_; }; - explicit TypeChecker(const Features& features) : features_(features) {} + explicit TypeChecker(const Features& features, std::map& func_types) + : features_(features), func_types_(func_types) {} void set_error_callback(const ErrorCallback& error_callback) { error_callback_ = error_callback; @@ -73,6 +88,8 @@ class TypeChecker { Result OnBlock(const TypeVector& param_types, const TypeVector& result_types); Result OnBr(Index depth); Result OnBrIf(Index depth); + Result OnBrOnNonNull(Index depth); + Result OnBrOnNull(Index depth); Result BeginBrTable(); Result OnBrTableTarget(Index depth); Result EndBrTable(); @@ -80,11 +97,12 @@ class TypeChecker { Result OnCallIndirect(const TypeVector& param_types, const TypeVector& result_types, const Limits& table_limits); - Result OnIndexedFuncRef(Index* out_index); + Result OnCallRef(Type); Result OnReturnCall(const TypeVector& param_types, const TypeVector& result_types); Result OnReturnCallIndirect(const TypeVector& param_types, const TypeVector& result_types); + Result OnReturnCallRef(Type); Result OnCatch(const TypeVector& sig); Result OnCompare(Opcode); Result OnConst(Type); @@ -115,7 +133,8 @@ class TypeChecker { Result OnTableGrow(Type elem_type, const Limits& limits); Result OnTableSize(const Limits& limits); Result OnTableFill(Type elem_type, const Limits& limits); - Result OnRefFuncExpr(Index func_type, bool force_generic_funcref); + Result OnRefFuncExpr(Index func_type); + Result OnRefAsNonNullExpr(); Result OnRefNullExpr(Type type); Result OnRefIsNullExpr(); Result OnRethrow(Index depth); @@ -141,7 +160,7 @@ class TypeChecker { Result BeginInitExpr(Type type); Result EndInitExpr(); - static Result CheckType(Type actual, Type expected); + Result CheckType(Type actual, Type expected); private: void WABT_PRINTF_FORMAT(2, 3) PrintError(const char* fmt, ...); @@ -178,6 +197,7 @@ class TypeChecker { Type expected2, Type expected3, const char* desc); + Result PopAndCheckReference(Type* actual, const char* desc); Result CheckOpcode1(Opcode opcode, const Limits* limits = nullptr); Result CheckOpcode2(Opcode opcode, const Limits* limits = nullptr); Result CheckOpcode3(Opcode opcode, @@ -210,6 +230,7 @@ class TypeChecker { // to represent "any". TypeVector* br_table_sig_ = nullptr; Features features_; + std::map& func_types_; }; } // namespace wabt diff --git a/include/wabt/type.h b/include/wabt/type.h index 30234166b3..8ef73112db 100644 --- a/include/wabt/type.h +++ b/include/wabt/type.h @@ -46,6 +46,8 @@ class Type { FuncRef = -0x10, // 0x70 ExternRef = -0x11, // 0x6f Reference = -0x15, // 0x6b + Ref = -0x1c, // 0x64 + RefNull = -0x1d, // 0x63 Func = -0x20, // 0x60 Struct = -0x21, // 0x5f Array = -0x22, // 0x5e @@ -58,17 +60,25 @@ class Type { I32U = 7, // Not actually specified, but used internally with load/store }; + // Used by FuncRef / ExternRef + enum GenericReferenceType : uint32_t { + ReferenceOrNull = 0, + ReferenceNonNull = 1, + }; + Type() = default; // Provided so Type can be member of a union. Type(int32_t code) : enum_(static_cast(code)), type_index_(0) { - assert(!EnumIsReferenceWithIndex(enum_)); + assert(!IsReferenceWithIndex()); } Type(Enum e) : enum_(e), type_index_(0) { - assert(!EnumIsReferenceWithIndex(enum_)); + assert(!IsReferenceWithIndex()); } Type(Enum e, Index type_index) : enum_(e), type_index_(type_index) { - assert(EnumIsReferenceWithIndex(e)); + assert(IsReferenceWithIndex() || + (IsNonTypedRef() && (type_index_ == ReferenceOrNull || type_index_ == ReferenceNonNull))); } + constexpr operator Enum() const { return enum_; } friend constexpr bool operator==(const Type a, const Type b) { @@ -90,14 +100,30 @@ class Type { bool IsRef() const { return enum_ == Type::ExternRef || enum_ == Type::FuncRef || - enum_ == Type::Reference || enum_ == Type::ExnRef; + enum_ == Type::Reference || enum_ == Type::ExnRef || + enum_ == Type::RefNull || enum_ == Type::Ref; + } + + bool IsNullableRef() const { + return enum_ == Type::Reference || enum_ == Type::ExnRef || + enum_ == Type::RefNull || + ((enum_ == Type::ExternRef || enum_ == Type::FuncRef) && type_index_ == ReferenceOrNull); + } + + bool IsNonNullableRef() const { + return enum_ == Type::Ref || + ((enum_ == Type::ExternRef || enum_ == Type::FuncRef) && type_index_ != ReferenceOrNull); } bool IsReferenceWithIndex() const { return EnumIsReferenceWithIndex(enum_); } - bool IsNullableRef() const { - // Currently all reftypes are nullable - return IsRef(); + bool IsNonTypedRef() const { + return EnumIsNonTypedRef(enum_); + } + + bool IsNullableNonTypedRef() const { + assert(EnumIsNonTypedRef(enum_)); + return type_index_ == ReferenceOrNull; } std::string GetName() const { @@ -110,13 +136,18 @@ class Type { case Type::I8: return "i8"; case Type::I16: return "i16"; case Type::ExnRef: return "exnref"; - case Type::FuncRef: return "funcref"; case Type::Func: return "func"; case Type::Void: return "void"; case Type::Any: return "any"; - case Type::ExternRef: return "externref"; + case Type::FuncRef: + return type_index_ == ReferenceOrNull ? "funcref" : "(ref func)"; + case Type::ExternRef: + return type_index_ == ReferenceOrNull ? "externref" : "(ref extern)"; case Type::Reference: + case Type::Ref: return StringPrintf("(ref %d)", type_index_); + case Type::RefNull: + return StringPrintf("(ref null %d)", type_index_); default: return StringPrintf("", enum_); } @@ -153,7 +184,7 @@ class Type { } Index GetReferenceIndex() const { - assert(enum_ == Enum::Reference); + assert(IsReferenceWithIndex()); return type_index_; } @@ -172,6 +203,8 @@ class Type { case Type::ExnRef: case Type::ExternRef: case Type::Reference: + case Type::Ref: + case Type::RefNull: return TypeVector(this, this + 1); default: @@ -179,11 +212,16 @@ class Type { } } - private: static bool EnumIsReferenceWithIndex(Enum value) { - return value == Type::Reference; + return value == Type::Reference || value == Type::Ref || + value == Type::RefNull; + } + + static bool EnumIsNonTypedRef(Enum value) { + return value == Type::ExternRef || value == Type::FuncRef; } + private: Enum enum_; // This index is 0 for non-references, so a zeroed // memory area represents a valid Type::Any type. diff --git a/include/wabt/wast-parser.h b/include/wabt/wast-parser.h index 7a60af23b5..ad1c935da3 100644 --- a/include/wabt/wast-parser.h +++ b/include/wabt/wast-parser.h @@ -56,6 +56,14 @@ class WastParser { Expectation, }; + struct ResolveRefType { + ResolveRefType(Type* target_type, Var var) + : target_type(target_type), var(var) {} + + Type* target_type; + Var var; + }; + struct ReferenceVar { ReferenceVar(uint32_t index, Var var) : index(index), var(var) {} @@ -66,16 +74,16 @@ class WastParser { typedef std::vector ReferenceVars; - struct ResolveTypes { - ResolveTypes(TypeVector* target_types) - : target_types(target_types) {} + struct ResolveTypeVector { + ResolveTypeVector(TypeVector* target_vector) + : target_vector(target_vector) {} - TypeVector* target_types; + TypeVector* target_vector; ReferenceVars vars; }; - struct ResolveFuncs { - ResolveFuncs(Func* target_func) + struct ResolveFunc { + ResolveFunc(Func* target_func) : target_func(target_func) {} Func* target_func; @@ -162,13 +170,14 @@ class WastParser { bool ParseElemExprOpt(ExprList* out_elem_expr); bool ParseElemExprListOpt(ExprListVector* out_list); bool ParseElemExprVarListOpt(ExprListVector* out_list); + Result ParseRefDeclaration(Var* out_type); Result ParseValueType(Var* out_type); Result ParseValueTypeList( TypeVector* out_type_list, ReferenceVars* type_vars); - Result ParseRefKind(Type* out_type); - Result ParseRefType(Type* out_type); - bool ParseRefTypeOpt(Type* out_type); + Result ParseRefKind(Var* out_type); + Result ParseRefType(Var* out_type); + bool ParseRefTypeOpt(Var* out_type, Result& result); Result ParseQuotedText(std::string* text, bool check_utf8 = true); bool ParseOffsetOpt(Address* offset); bool ParseAlignOpt(Address* align); @@ -178,8 +187,9 @@ class WastParser { Result ParsePageSize(uint32_t*); Result ParseNat(uint64_t*, bool is_64); - static Result ResolveRefTypes(const Module&, TypeVector*, - ReferenceVars*, Errors* errors); + static Result ResolveTargetRefType(const Module&, Type*, const Var&, Errors*); + static Result ResolveTargetTypeVector(const Module&, TypeVector*, + ReferenceVars*, Errors*); Result ParseModuleFieldList(Module*); Result ParseModuleField(Module*); Result ParseDataModuleField(Module*); @@ -288,25 +298,29 @@ class WastParser { void CheckImportOrdering(Module*); bool HasError() const; + bool CheckRefType(Type::Enum type); + void VarToType(const Var& var, Type* type); WastLexer* lexer_; Index last_module_index_ = kInvalidIndex; Errors* errors_; WastParseOptions* options_; - // Reference types can have names, for example (ref $foo) represents - // a type which name is $foo. These types are translated to their - // corresponding index after the parsing is completed. The position - // and names of these reference types are stored in a ReferenceVars - // vector. The names are stored as variables, because the error - // message construction requires a location when a name is not found. - std::vector resolve_types_; - - // When some locals are named references, the parser keeps the - // non-compressed local vector until the module parsing is - // completed. After the locals are resolved, local_types are - // constructed from this vector, and then this vector is freed. - std::vector resolve_funcs_; + // Reference types can have names or indicies. For example (ref $foo) + // represents a type which name is $foo, and (ref 5) represents + // the fifth type declaration. Both of these variants needs to + // be validated after the parsing is completed. + + // Single type references are stored in the following vector. + std::vector resolve_ref_types_; + + // Type vectors and their corresponding references are stored in the + // following vector. At least one reference must be present for each vector. + std::vector resolve_type_vectors_; + + // Local vectors and their corresponding references are stored in the + // following vector. At least one reference must be present for each vector. + std::vector resolve_funcs_; // two-element queue of upcoming tokens class TokenQueue { diff --git a/src/apply-names.cc b/src/apply-names.cc index c8516c8cd9..3d25749ccd 100644 --- a/src/apply-names.cc +++ b/src/apply-names.cc @@ -40,6 +40,8 @@ class NameApplier : public ExprVisitor::DelegateNop { Result EndBlockExpr(BlockExpr*) override; Result OnBrExpr(BrExpr*) override; Result OnBrIfExpr(BrIfExpr*) override; + Result OnBrOnNonNullExpr(BrOnNonNullExpr*) override; + Result OnBrOnNullExpr(BrOnNullExpr*) override; Result OnBrTableExpr(BrTableExpr*) override; Result OnCallExpr(CallExpr*) override; Result OnRefFuncExpr(RefFuncExpr*) override; @@ -350,6 +352,18 @@ Result NameApplier::OnBrIfExpr(BrIfExpr* expr) { return Result::Ok; } +Result NameApplier::OnBrOnNonNullExpr(BrOnNonNullExpr* expr) { + std::string_view label = FindLabelByVar(&expr->var); + UseNameForVar(label, &expr->var); + return Result::Ok; +} + +Result NameApplier::OnBrOnNullExpr(BrOnNullExpr* expr) { + std::string_view label = FindLabelByVar(&expr->var); + UseNameForVar(label, &expr->var); + return Result::Ok; +} + Result NameApplier::OnBrTableExpr(BrTableExpr* expr) { for (Var& target : expr->targets) { std::string_view label = FindLabelByVar(&target); diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index 2029b0f7c4..855c8a8c16 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -200,6 +200,8 @@ class BinaryReaderIR : public BinaryReaderNop { Result OnBlockExpr(Type sig_type) override; Result OnBrExpr(Index depth) override; Result OnBrIfExpr(Index depth) override; + Result OnBrOnNonNullExpr(Index depth) override; + Result OnBrOnNullExpr(Index depth) override; Result OnBrTableExpr(Index num_targets, Index* target_depths, Index default_target_depth) override; @@ -207,9 +209,10 @@ class BinaryReaderIR : public BinaryReaderNop { Result OnCatchExpr(Index tag_index) override; Result OnCatchAllExpr() override; Result OnCallIndirectExpr(Index sig_index, Index table_index) override; - Result OnCallRefExpr() override; + Result OnCallRefExpr(Type sig_type) override; Result OnReturnCallExpr(Index func_index) override; Result OnReturnCallIndirectExpr(Index sig_index, Index table_index) override; + Result OnReturnCallRefExpr(Type sig_type) override; Result OnCompareExpr(Opcode opcode) override; Result OnConvertExpr(Opcode opcode) override; Result OnDelegateExpr(Index depth) override; @@ -246,6 +249,7 @@ class BinaryReaderIR : public BinaryReaderNop { Result OnTableGrowExpr(Index table_index) override; Result OnTableSizeExpr(Index table_index) override; Result OnTableFillExpr(Index table_index) override; + Result OnRefAsNonNullExpr() override; Result OnRefFuncExpr(Index func_index) override; Result OnRefNullExpr(Type type) override; Result OnRefIsNullExpr() override; @@ -897,6 +901,15 @@ Result BinaryReaderIR::OnBrIfExpr(Index depth) { return AppendExpr(std::make_unique(Var(depth, GetLocation()))); } +Result BinaryReaderIR::OnBrOnNonNullExpr(Index depth) { + return AppendExpr( + std::make_unique(Var(depth, GetLocation()))); +} + +Result BinaryReaderIR::OnBrOnNullExpr(Index depth) { + return AppendExpr(std::make_unique(Var(depth, GetLocation()))); +} + Result BinaryReaderIR::OnBrTableExpr(Index num_targets, Index* target_depths, Index default_target_depth) { @@ -920,8 +933,10 @@ Result BinaryReaderIR::OnCallIndirectExpr(Index sig_index, Index table_index) { return AppendExpr(std::move(expr)); } -Result BinaryReaderIR::OnCallRefExpr() { - return AppendExpr(std::make_unique()); +Result BinaryReaderIR::OnCallRefExpr(Type sig_type) { + auto expr = std::make_unique(); + expr->sig_type = Var(sig_type, GetLocation()); + return AppendExpr(std::move(expr)); } Result BinaryReaderIR::OnReturnCallExpr(Index func_index) { @@ -951,6 +966,12 @@ Result BinaryReaderIR::OnReturnCallIndirectExpr(Index sig_index, return AppendExpr(std::move(expr)); } +Result BinaryReaderIR::OnReturnCallRefExpr(Type sig_type) { + auto expr = std::make_unique(); + expr->sig_type = Var(sig_type, GetLocation()); + return AppendExpr(std::move(expr)); +} + Result BinaryReaderIR::OnCompareExpr(Opcode opcode) { return AppendExpr(std::make_unique(opcode)); } @@ -1145,6 +1166,11 @@ Result BinaryReaderIR::OnTableFillExpr(Index table_index) { std::make_unique(Var(table_index, GetLocation()))); } +Result BinaryReaderIR::OnRefAsNonNullExpr() { + return AppendExpr( + std::make_unique(Opcode::RefAsNonNull, GetLocation())); +} + Result BinaryReaderIR::OnRefFuncExpr(Index func_index) { module_->used_func_refs.insert(func_index); return AppendExpr( @@ -1153,7 +1179,7 @@ Result BinaryReaderIR::OnRefFuncExpr(Index func_index) { Result BinaryReaderIR::OnRefNullExpr(Type type) { module_->features_used.exceptions |= (type == Type::ExnRef); - return AppendExpr(std::make_unique(type)); + return AppendExpr(std::make_unique(Var(type, GetLocation()))); } Result BinaryReaderIR::OnRefIsNullExpr() { @@ -1173,9 +1199,9 @@ Result BinaryReaderIR::OnReturnExpr() { } Result BinaryReaderIR::OnSelectExpr(Index result_count, Type* result_types) { - TypeVector results; - results.assign(result_types, result_types + result_count); - return AppendExpr(std::make_unique(results)); + auto expr_ptr = std::make_unique(); + expr_ptr->result_type.assign(result_types, result_types + result_count); + return AppendExpr(std::move(expr_ptr)); } Result BinaryReaderIR::OnGlobalSetExpr(Index global_index) { diff --git a/src/binary-reader-logging.cc b/src/binary-reader-logging.cc index 0c13622576..89690ca533 100644 --- a/src/binary-reader-logging.cc +++ b/src/binary-reader-logging.cc @@ -320,6 +320,16 @@ Result BinaryReaderLogging::OnBrIfExpr(Index depth) { return reader_->OnBrIfExpr(depth); } +Result BinaryReaderLogging::OnBrOnNonNullExpr(Index depth) { + LOGF("OnBrOnNonNullExpr(depth: %" PRIindex ")\n", depth); + return reader_->OnBrOnNonNullExpr(depth); +} + +Result BinaryReaderLogging::OnBrOnNullExpr(Index depth) { + LOGF("OnBrOnNullExpr(depth: %" PRIindex ")\n", depth); + return reader_->OnBrOnNullExpr(depth); +} + Result BinaryReaderLogging::OnBrTableExpr(Index num_targets, Index* target_depths, Index default_target_depth) { @@ -842,7 +852,7 @@ DEFINE_LOAD_STORE_OPCODE(OnAtomicNotifyExpr); DEFINE_OPCODE(OnBinaryExpr) DEFINE_INDEX_DESC(OnCallExpr, "func_index") DEFINE_INDEX_INDEX(OnCallIndirectExpr, "sig_index", "table_index") -DEFINE0(OnCallRefExpr) +DEFINE_TYPE(OnCallRefExpr) DEFINE_INDEX_DESC(OnCatchExpr, "tag_index"); DEFINE0(OnCatchAllExpr); DEFINE_OPCODE(OnCompareExpr) @@ -871,6 +881,7 @@ DEFINE_INDEX(OnTableGetExpr) DEFINE_INDEX(OnTableGrowExpr) DEFINE_INDEX(OnTableSizeExpr) DEFINE_INDEX_DESC(OnTableFillExpr, "table index") +DEFINE0(OnRefAsNonNullExpr) DEFINE_INDEX(OnRefFuncExpr) DEFINE_TYPE(OnRefNullExpr) DEFINE0(OnRefIsNullExpr) @@ -879,6 +890,7 @@ DEFINE_INDEX_DESC(OnRethrowExpr, "depth"); DEFINE_INDEX_DESC(OnReturnCallExpr, "func_index") DEFINE_INDEX_INDEX(OnReturnCallIndirectExpr, "sig_index", "table_index") +DEFINE_TYPE(OnReturnCallRefExpr) DEFINE0(OnReturnExpr) DEFINE_LOAD_STORE_OPCODE(OnLoadSplatExpr); DEFINE_LOAD_STORE_OPCODE(OnLoadZeroExpr); diff --git a/src/binary-reader-objdump.cc b/src/binary-reader-objdump.cc index 34ba068708..e35d1fe5b8 100644 --- a/src/binary-reader-objdump.cc +++ b/src/binary-reader-objdump.cc @@ -901,7 +901,7 @@ Result BinaryReaderObjdumpDisassemble::OnOpcodeType(Type type) { if (!in_function_body) { return Result::Ok; } - if (current_opcode == Opcode::SelectT) { + if (current_opcode == Opcode::SelectT || current_opcode == Opcode::CallRef) { LogOpcode(type.GetName().c_str()); } else { LogOpcode(type.GetRefKindName()); diff --git a/src/binary-reader.cc b/src/binary-reader.cc index 6828435385..fdb271c290 100644 --- a/src/binary-reader.cc +++ b/src/binary-reader.cc @@ -145,6 +145,7 @@ class BinaryReader { [[nodiscard]] Result ReadCount(Index* index, const char* desc); [[nodiscard]] Result ReadField(TypeMut* out_value); + bool IsConcreteReferenceType(Type::Enum); bool IsConcreteType(Type); bool IsBlockType(Type); @@ -365,10 +366,25 @@ Result BinaryReader::ReadS64Leb128(uint64_t* out_value, const char* desc) { Result BinaryReader::ReadType(Type* out_value, const char* desc) { uint32_t type = 0; CHECK_RESULT(ReadS32Leb128(&type, desc)); - if (static_cast(type) == Type::Reference) { - uint32_t heap_type = 0; - CHECK_RESULT(ReadS32Leb128(&heap_type, desc)); - *out_value = Type(Type::Reference, heap_type); + if (options_.features.reference_types_enabled() && + Type::EnumIsReferenceWithIndex(static_cast(type))) { + uint64_t heap_type = 0; + CHECK_RESULT(ReadS64Leb128(&heap_type, desc)); + + if (static_cast(heap_type) < 0 || + static_cast(heap_type) >= kInvalidIndex) { + Type::Enum heap_type_code = static_cast(heap_type); + ERROR_UNLESS( + heap_type_code == Type::FuncRef || heap_type_code == Type::ExternRef, + "Reference type is limited to func and extern: %s", desc); + type = (static_cast(type) == Type::Ref) + ? Type::ReferenceNonNull + : Type::ReferenceOrNull; + *out_value = Type(heap_type_code, type); + } else { + *out_value = + Type(static_cast(type), static_cast(heap_type)); + } } else { *out_value = static_cast(type); } @@ -552,6 +568,20 @@ Result BinaryReader::ReadField(TypeMut* out_value) { return Result::Ok; } +bool BinaryReader::IsConcreteReferenceType(Type::Enum type) { + switch (type) { + case Type::FuncRef: + case Type::ExternRef: + return options_.features.reference_types_enabled(); + + case Type::ExnRef: + return options_.features.exceptions_enabled(); + + default: + return false; + } +} + bool BinaryReader::IsConcreteType(Type type) { switch (type) { case Type::I32: @@ -563,18 +593,13 @@ bool BinaryReader::IsConcreteType(Type type) { case Type::V128: return options_.features.simd_enabled(); - case Type::FuncRef: - case Type::ExternRef: - return options_.features.reference_types_enabled(); - - case Type::ExnRef: - return options_.features.exceptions_enabled(); - case Type::Reference: + case Type::Ref: + case Type::RefNull: return options_.features.function_references_enabled(); default: - return false; + return IsConcreteReferenceType(type); } } @@ -815,6 +840,22 @@ Result BinaryReader::ReadInstructions(Offset end_offset, const char* context) { break; } + case Opcode::BrOnNonNull: { + Index depth; + CHECK_RESULT(ReadIndex(&depth, "br_on_non_null depth")); + CALLBACK(OnBrOnNonNullExpr, depth); + CALLBACK(OnOpcodeIndex, depth); + break; + } + + case Opcode::BrOnNull: { + Index depth; + CHECK_RESULT(ReadIndex(&depth, "br_on_null depth")); + CALLBACK(OnBrOnNullExpr, depth); + CALLBACK(OnOpcodeIndex, depth); + break; + } + case Opcode::BrTable: { Index num_targets; CHECK_RESULT(ReadCount(&num_targets, "br_table target count")); @@ -1902,6 +1943,11 @@ Result BinaryReader::ReadInstructions(Offset end_offset, const char* context) { break; } + case Opcode::RefAsNonNull: + CALLBACK(OnRefAsNonNullExpr); + CALLBACK(OnOpcodeBare); + break; + case Opcode::RefFunc: { Index func; CHECK_RESULT(ReadIndex(&func, "func index")); @@ -1911,8 +1957,23 @@ Result BinaryReader::ReadInstructions(Offset end_offset, const char* context) { } case Opcode::RefNull: { + uint64_t heap_type; Type type; - CHECK_RESULT(ReadRefType(&type, "ref.null type")); + CHECK_RESULT(ReadS64Leb128(&heap_type, "ref.null type")); + + if (static_cast(heap_type) < 0 || + static_cast(heap_type) >= kInvalidIndex) { + Type::Enum type_code = static_cast(heap_type); + ERROR_UNLESS(IsConcreteReferenceType(type_code), + "expected valid ref.null type (got " PRItypecode ")", + WABT_PRINTF_TYPE_CODE(type_code)); + type = Type(type_code); + } else { + ERROR_UNLESS(options_.features.function_references_enabled(), + "function references are not enabled for ref.null"); + type = Type(Type::RefNull, static_cast(heap_type)); + } + CALLBACK(OnRefNullExpr, type); CALLBACK(OnOpcodeType, type); break; @@ -1923,10 +1984,25 @@ Result BinaryReader::ReadInstructions(Offset end_offset, const char* context) { CALLBACK(OnOpcodeBare); break; - case Opcode::CallRef: - CALLBACK(OnCallRefExpr); - CALLBACK(OnOpcodeBare); + case Opcode::CallRef: { + uint32_t type; + CHECK_RESULT(ReadU32Leb128(&type, "call_ref type")); + + Type sig_type(Type::RefNull, type); + CALLBACK(OnCallRefExpr, sig_type); + CALLBACK(OnOpcodeType, sig_type); break; + } + + case Opcode::ReturnCallRef: { + uint32_t type; + CHECK_RESULT(ReadU32Leb128(&type, "return_call_ref type")); + + Type sig_type(Type::RefNull, type); + CALLBACK(OnReturnCallRefExpr, sig_type); + CALLBACK(OnOpcodeType, sig_type); + break; + } default: return ReportUnexpectedOpcode(opcode); diff --git a/src/binary-writer.cc b/src/binary-writer.cc index 600154b941..68b1ba9d31 100644 --- a/src/binary-writer.cc +++ b/src/binary-writer.cc @@ -57,9 +57,12 @@ void WriteOpcode(Stream* stream, Opcode opcode) { } void WriteType(Stream* stream, Type type, const char* desc) { + if (type.IsNonTypedRef() && !type.IsNullableNonTypedRef()) { + WriteS32Leb128(stream, Type::Ref, "type prefix"); + } WriteS32Leb128(stream, type, desc ? desc : type.GetName().c_str()); if (type.IsReferenceWithIndex()) { - WriteS32Leb128(stream, type.GetReferenceIndex(), + WriteU32Leb128(stream, type.GetReferenceIndex(), desc ? desc : type.GetName().c_str()); } } @@ -759,6 +762,17 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { WriteU32Leb128(stream_, GetLabelVarDepth(&cast(expr)->var), "break depth"); break; + case ExprType::BrOnNonNull: + WriteOpcode(stream_, Opcode::BrOnNonNull); + WriteU32Leb128(stream_, + GetLabelVarDepth(&cast(expr)->var), + "break depth"); + break; + case ExprType::BrOnNull: + WriteOpcode(stream_, Opcode::BrOnNull); + WriteU32Leb128(stream_, GetLabelVarDepth(&cast(expr)->var), + "break depth"); + break; case ExprType::BrTable: { auto* br_table_expr = cast(expr); WriteOpcode(stream_, Opcode::BrTable); @@ -795,10 +809,6 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { WriteTableNumberWithReloc(table_index, "table index"); break; } - case ExprType::CallRef: { - WriteOpcode(stream_, Opcode::CallRef); - break; - } case ExprType::ReturnCallIndirect: { Index sig_index = module_->GetFuncTypeIndex(cast(expr)->decl); @@ -810,6 +820,23 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { WriteTableNumberWithReloc(table_index, "table index"); break; } + case ExprType::CallRef: { + WriteOpcode(stream_, Opcode::CallRef); + assert(cast(expr)->sig_type.opt_type() == Type::RefNull); + Index sig_index = cast(expr)->sig_type.index(); + WriteU32Leb128WithReloc(sig_index, "signature index", + RelocType::TypeIndexLEB); + break; + } + case ExprType::ReturnCallRef: { + WriteOpcode(stream_, Opcode::ReturnCallRef); + assert(cast(expr)->sig_type.opt_type() == + Type::RefNull); + Index sig_index = cast(expr)->sig_type.index(); + WriteU32Leb128WithReloc(sig_index, "signature index", + RelocType::TypeIndexLEB); + break; + } case ExprType::Compare: WriteOpcode(stream_, cast(expr)->opcode); break; @@ -1003,6 +1030,10 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { WriteTableNumberWithReloc(index, "table.fill table index"); break; } + case ExprType::RefAsNonNull: { + WriteOpcode(stream_, Opcode::RefAsNonNull); + break; + } case ExprType::RefFunc: { WriteOpcode(stream_, Opcode::RefFunc); Index index = module_->GetFuncIndex(cast(expr)->var); @@ -1011,7 +1042,17 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { } case ExprType::RefNull: { WriteOpcode(stream_, Opcode::RefNull); - WriteType(stream_, cast(expr)->type, "ref.null type"); + const RefNullExpr* ref_null_expr = cast(expr); + Type::Enum type = ref_null_expr->type.opt_type(); + + if (type != Type::RefNull) { + WriteType(stream_, type, "ref.null type"); + break; + } + + Index index = module_->GetFuncTypeIndex(ref_null_expr->type); + WriteU32Leb128WithReloc(index, "heap type index", + RelocType::FuncIndexLEB); break; } case ExprType::RefIsNull: diff --git a/src/c-writer.cc b/src/c-writer.cc index da58d1c951..8fc565ae7e 100644 --- a/src/c-writer.cc +++ b/src/c-writer.cc @@ -1517,7 +1517,7 @@ void CWriter::WriteInitExprTerminal(const Expr* expr) { } break; case ExprType::RefNull: - Write(GetReferenceNullValue(cast(expr)->type)); + Write(GetReferenceNullValue(cast(expr)->type.opt_type())); break; default: @@ -2506,16 +2506,17 @@ void CWriter::WriteElemInitializers() { void CWriter::WriteElemTableInit(bool active_initialization, const ElemSegment* src_segment, const Table* dst_table) { - assert(dst_table->elem_type.IsRef() && - dst_table->elem_type != Type::Reference); - assert(dst_table->elem_type == src_segment->elem_type); + Type elem_type = dst_table->elem_type; - Write(GetReferenceTypeName(dst_table->elem_type), "_table_init(", + assert(elem_type.IsRef() && !elem_type.IsReferenceWithIndex()); + assert(elem_type == src_segment->elem_type); + + Write(GetReferenceTypeName(elem_type), "_table_init(", ExternalInstancePtr(ModuleFieldType::Table, dst_table->name), ", "); // elem segment exprs needed only for funcref tables // because externref and exnref tables can only be initialized with ref.null - if (dst_table->elem_type == Type::FuncRef) { + if (elem_type == Type::FuncRef) { if (src_segment->elem_exprs.empty()) { Write("NULL, "); } else { @@ -2540,7 +2541,7 @@ void CWriter::WriteElemTableInit(bool active_initialization, Write(StackVar(2), ", ", StackVar(1), ", ", StackVar(0)); } - if (dst_table->elem_type == Type::FuncRef) { + if (elem_type == Type::FuncRef) { Write(", instance"); } @@ -3610,6 +3611,21 @@ void CWriter::Write(const ExprList& exprs) { Write(GotoLabel(cast(&expr)->var), "}", Newline()); break; + case ExprType::BrOnNonNull: + Write("if (", StackVar(0), ".func != NULL) {"); + Write(GotoLabel(cast(&expr)->var), "}", Newline()); + DropTypes(1); + break; + + case ExprType::BrOnNull: { + Write("if (", StackVar(0), ".func == NULL) {"); + Type type = StackType(0); + DropTypes(1); + Write(GotoLabel(cast(&expr)->var), "}", Newline()); + PushType(type); + break; + } + case ExprType::BrTable: { const auto* bt_expr = cast(&expr); Write("switch (", StackVar(0), ") ", OpenBrace()); @@ -3944,6 +3960,10 @@ void CWriter::Write(const ExprList& exprs) { DropTypes(3); } break; + case ExprType::RefAsNonNull: + Write("if (", StackVar(0), ".func == NULL) { TRAP(NULL_REF); }"); + break; + case ExprType::RefFunc: { const Func* func = module_->GetFunc(cast(&expr)->var); PushType(Type::FuncRef); @@ -3973,10 +3993,10 @@ void CWriter::Write(const ExprList& exprs) { } break; case ExprType::RefNull: - PushType(cast(&expr)->type); + PushType(cast(&expr)->type.opt_type()); Write(StackVar(0), " = ", - GetReferenceNullValue(cast(&expr)->type), ";", - Newline()); + GetReferenceNullValue(cast(&expr)->type.opt_type()), + ";", Newline()); break; case ExprType::RefIsNull: @@ -4282,6 +4302,7 @@ void CWriter::Write(const ExprList& exprs) { case ExprType::AtomicWait: case ExprType::AtomicNotify: case ExprType::CallRef: + case ExprType::ReturnCallRef: UNIMPLEMENTED("..."); break; } diff --git a/src/expr-visitor.cc b/src/expr-visitor.cc index 217d45cc01..b1e8b8c37d 100644 --- a/src/expr-visitor.cc +++ b/src/expr-visitor.cc @@ -215,6 +215,14 @@ Result ExprVisitor::HandleDefaultState(Expr* expr) { CHECK_RESULT(delegate_->OnBrIfExpr(cast(expr))); break; + case ExprType::BrOnNonNull: + CHECK_RESULT(delegate_->OnBrOnNonNullExpr(cast(expr))); + break; + + case ExprType::BrOnNull: + CHECK_RESULT(delegate_->OnBrOnNullExpr(cast(expr))); + break; + case ExprType::BrTable: CHECK_RESULT(delegate_->OnBrTableExpr(cast(expr))); break; @@ -353,6 +361,10 @@ Result ExprVisitor::HandleDefaultState(Expr* expr) { CHECK_RESULT(delegate_->OnTableFillExpr(cast(expr))); break; + case ExprType::RefAsNonNull: + CHECK_RESULT(delegate_->OnRefAsNonNullExpr(cast(expr))); + break; + case ExprType::RefFunc: CHECK_RESULT(delegate_->OnRefFuncExpr(cast(expr))); break; @@ -386,6 +398,11 @@ Result ExprVisitor::HandleDefaultState(Expr* expr) { cast(expr))); break; + case ExprType::ReturnCallRef: + CHECK_RESULT( + delegate_->OnReturnCallRefExpr(cast(expr))); + break; + case ExprType::Select: CHECK_RESULT(delegate_->OnSelectExpr(cast(expr))); break; diff --git a/src/interp/binary-reader-interp.cc b/src/interp/binary-reader-interp.cc index 9eb54d45da..d0dd7863c7 100644 --- a/src/interp/binary-reader-interp.cc +++ b/src/interp/binary-reader-interp.cc @@ -182,16 +182,20 @@ class BinaryReaderInterp : public BinaryReaderNop { Result OnBlockExpr(Type sig_type) override; Result OnBrExpr(Index depth) override; Result OnBrIfExpr(Index depth) override; + Result OnBrOnNonNullExpr(Index depth) override; + Result OnBrOnNullExpr(Index depth) override; Result OnBrTableExpr(Index num_targets, Index* target_depths, Index default_target_depth) override; Result OnCallExpr(Index func_index) override; Result OnCallIndirectExpr(Index sig_index, Index table_index) override; + Result OnCallRefExpr(Type sig_type) override; Result OnCatchExpr(Index tag_index) override; Result OnCatchAllExpr() override; Result OnDelegateExpr(Index depth) override; Result OnReturnCallExpr(Index func_index) override; Result OnReturnCallIndirectExpr(Index sig_index, Index table_index) override; + Result OnReturnCallRefExpr(Type sig_type) override; Result OnCompareExpr(Opcode opcode) override; Result OnConvertExpr(Opcode opcode) override; Result OnDropExpr() override; @@ -219,6 +223,7 @@ class BinaryReaderInterp : public BinaryReaderNop { Result OnMemoryFillExpr(Index memidx) override; Result OnMemoryInitExpr(Index segment_index, Index memidx) override; Result OnMemorySizeExpr(Index memidx) override; + Result OnRefAsNonNullExpr() override; Result OnRefFuncExpr(Index func_index) override; Result OnRefNullExpr(Type type) override; Result OnRefIsNullExpr() override; @@ -320,6 +325,9 @@ class BinaryReaderInterp : public BinaryReaderNop { Index drop_count, Index keep_count, Index catch_drop_count); + + Result EmitBrCond(Opcode opcode, Index depth); + void FixupTopLabel(); u32 GetFuncOffset(Index func_index); @@ -471,6 +479,25 @@ void BinaryReaderInterp::EmitBr(Index depth, istream_.Emit(offset); } +Result BinaryReaderInterp::EmitBrCond(Opcode opcode, Index depth) { + Index drop_count, keep_count, catch_drop_count; + CHECK_RESULT(GetBrDropKeepCount(depth, &drop_count, &keep_count)); + CHECK_RESULT(validator_.GetCatchCount(depth, &catch_drop_count)); + // The opcode is flipped so if is + // true it can drop values from the stack. + istream_.Emit(opcode); + auto fixup = istream_.EmitFixupU32(); + // The validator for br_on_null keeps the (non-null) reference on + // the stack. This reference needs to be ignored when the branch + // is executed. Note: opcode contains the flipped value. + if (opcode == Opcode::BrOnNonNull && drop_count > 0) { + drop_count--; + } + EmitBr(depth, drop_count, keep_count, catch_drop_count); + istream_.ResolveFixupU32(fixup); + return Result::Ok; +} + void BinaryReaderInterp::FixupTopLabel() { depth_fixups_.Resolve(istream_, label_stack_.size() - 1); } @@ -504,11 +531,11 @@ Result BinaryReaderInterp::OnFuncType(Index index, Type* param_types, Index result_count, Type* result_types) { - CHECK_RESULT(validator_.OnFuncType(GetLocation(), param_count, param_types, - result_count, result_types, index)); + Result result = validator_.OnFuncType(GetLocation(), param_count, param_types, + result_count, result_types, index); module_.func_types.push_back(FuncType(ToInterp(param_count, param_types), ToInterp(result_count, result_types))); - return Result::Ok; + return result; } Result BinaryReaderInterp::OnImportFunc(Index import_index, @@ -1106,16 +1133,22 @@ Result BinaryReaderInterp::OnBrExpr(Index depth) { } Result BinaryReaderInterp::OnBrIfExpr(Index depth) { - Index drop_count, keep_count, catch_drop_count; CHECK_RESULT(validator_.OnBrIf(GetLocation(), Var(depth, GetLocation()))); - CHECK_RESULT(GetBrDropKeepCount(depth, &drop_count, &keep_count)); - CHECK_RESULT(validator_.GetCatchCount(depth, &catch_drop_count)); - // Flip the br_if so if is true it can drop values from the stack. - istream_.Emit(Opcode::InterpBrUnless); - auto fixup = istream_.EmitFixupU32(); - EmitBr(depth, drop_count, keep_count, catch_drop_count); - istream_.ResolveFixupU32(fixup); - return Result::Ok; + // Opcode is flipped. + return EmitBrCond(Opcode::InterpBrUnless, depth); +} + +Result BinaryReaderInterp::OnBrOnNonNullExpr(Index depth) { + CHECK_RESULT( + validator_.OnBrOnNonNull(GetLocation(), Var(depth, GetLocation()))); + // Opcode is flipped. + return EmitBrCond(Opcode::BrOnNull, depth); +} + +Result BinaryReaderInterp::OnBrOnNullExpr(Index depth) { + CHECK_RESULT(validator_.OnBrOnNull(GetLocation(), Var(depth, GetLocation()))); + // Opcode is flipped. + return EmitBrCond(Opcode::BrOnNonNull, depth); } Result BinaryReaderInterp::OnBrTableExpr(Index num_targets, @@ -1174,6 +1207,14 @@ Result BinaryReaderInterp::OnCallIndirectExpr(Index sig_index, return Result::Ok; } +Result BinaryReaderInterp::OnCallRefExpr(Type sig_type) { + CHECK_RESULT( + validator_.OnCallRef(GetLocation(), Var(sig_type, GetLocation()))); + assert(sig_type == Type::RefNull); + istream_.Emit(Opcode::CallRef); + return Result::Ok; +} + Result BinaryReaderInterp::OnReturnCallExpr(Index func_index) { CHECK_RESULT( validator_.OnReturnCall(GetLocation(), Var(func_index, GetLocation()))); @@ -1231,6 +1272,14 @@ Result BinaryReaderInterp::OnReturnCallIndirectExpr(Index sig_index, return Result::Ok; } +Result BinaryReaderInterp::OnReturnCallRefExpr(Type sig_type) { + CHECK_RESULT( + validator_.OnReturnCallRef(GetLocation(), Var(sig_type, GetLocation()))); + assert(sig_type == Type::RefNull); + istream_.Emit(Opcode::ReturnCallRef); + return Result::Ok; +} + Result BinaryReaderInterp::OnCompareExpr(Opcode opcode) { CHECK_RESULT(validator_.OnCompare(GetLocation(), opcode)); istream_.Emit(opcode); @@ -1396,6 +1445,12 @@ Result BinaryReaderInterp::OnTableFillExpr(Index table_index) { return Result::Ok; } +Result BinaryReaderInterp::OnRefAsNonNullExpr() { + CHECK_RESULT(validator_.OnRefAsNonNull(Location())); + istream_.Emit(Opcode::RefAsNonNull); + return Result::Ok; +} + Result BinaryReaderInterp::OnRefFuncExpr(Index func_index) { CHECK_RESULT( validator_.OnRefFunc(GetLocation(), Var(func_index, GetLocation()))); @@ -1404,7 +1459,7 @@ Result BinaryReaderInterp::OnRefFuncExpr(Index func_index) { } Result BinaryReaderInterp::OnRefNullExpr(Type type) { - CHECK_RESULT(validator_.OnRefNull(GetLocation(), type)); + CHECK_RESULT(validator_.OnRefNull(GetLocation(), Var(type, GetLocation()))); istream_.Emit(Opcode::RefNull); return Result::Ok; } diff --git a/src/interp/interp-util.cc b/src/interp/interp-util.cc index fcba2c7f1a..3d21d6d099 100644 --- a/src/interp/interp-util.cc +++ b/src/interp/interp-util.cc @@ -59,6 +59,8 @@ std::string TypedValueToString(const TypedValue& tv) { return StringPrintf("exnref:%" PRIzd, tv.value.Get().index); case Type::Reference: + case Type::Ref: + case Type::RefNull: case Type::Func: case Type::Struct: case Type::Array: diff --git a/src/interp/interp.cc b/src/interp/interp.cc index cc4415fb9f..f18b4d5ed7 100644 --- a/src/interp/interp.cc +++ b/src/interp/interp.cc @@ -94,16 +94,91 @@ std::unique_ptr FuncType::Clone() const { return std::make_unique(*this); } +static bool RecursiveMatch(const ValueTypes& expected, + std::vector* expected_func_types, + const ValueTypes& actual, + std::vector* actual_func_types) { + if (expected_func_types == nullptr || actual_func_types == nullptr) { + return false; + } + + size_t size = expected.size(); + if (size != actual.size()) { + return false; + } + + for (size_t i = 0; i < size; i++) { + if (!expected[i].IsReferenceWithIndex()) { + if (expected[i] != actual[i]) { + return false; + } + continue; + } + + if (static_cast(expected[i]) != + static_cast(actual[i])) { + return false; + } + + const FuncType& expected_type = + (*expected_func_types)[expected[i].GetReferenceIndex()]; + const FuncType& actual_type = + (*actual_func_types)[actual[i].GetReferenceIndex()]; + + assert(expected_type.func_types == expected_func_types); + assert(actual_type.func_types == actual_func_types); + + if (!RecursiveMatch(expected_type.params, expected_func_types, + actual_type.params, actual_func_types) || + !RecursiveMatch(expected_type.results, expected_func_types, + actual_type.results, actual_func_types)) { + return false; + } + } + + return true; +} + Result Match(const FuncType& expected, const FuncType& actual, std::string* out_msg) { - if (expected.params != actual.params || expected.results != actual.results) { - if (out_msg) { - *out_msg = "import signature mismatch"; + bool has_reference = false; + + for (auto it : expected.params) { + if (it.IsReferenceWithIndex()) { + has_reference = true; + break; } - return Result::Error; } - return Result::Ok; + + if (!has_reference) { + for (auto it : expected.results) { + if (it.IsReferenceWithIndex()) { + has_reference = true; + break; + } + } + } + + if (!has_reference) { + // Simple function, can be a callback without module. + if (expected.params == actual.params && + expected.results == actual.results) { + return Result::Ok; + } + } else { + if (RecursiveMatch(expected.params, expected.func_types, actual.params, + actual.func_types) && + RecursiveMatch(expected.results, expected.func_types, actual.results, + actual.func_types)) { + return Result::Ok; + } + } + + if (out_msg) { + *out_msg = "import signature mismatch"; + } + return Result::Error; } //// TableType //// @@ -756,10 +831,26 @@ Module::Module(Store&, ModuleDesc desc) : Object(skind), desc_(std::move(desc)) { for (auto&& import : desc_.imports) { import_types_.emplace_back(import.type); + + if (import.type.type->kind == ExternKind::Func) { + cast(import.type.type.get())->func_types = &desc_.func_types; + } } for (auto&& export_ : desc_.exports) { export_types_.emplace_back(export_.type); + + if (export_.type.type->kind == ExternKind::Func) { + cast(export_.type.type.get())->func_types = &desc_.func_types; + } + } + + for (auto& func_type : desc_.func_types) { + func_type.func_types = &desc_.func_types; + } + + for (auto& func : desc_.funcs) { + func.type.func_types = &desc_.func_types; } } @@ -1208,6 +1299,25 @@ RunResult Thread::StepInternal(Trap::Ptr* out_trap) { } break; + case O::BrOnNonNull: { + Ref ref = Pop(); + if (ref != Ref::Null) { + Push(ref); + pc = instr.imm_u32; + } + break; + } + + case O::BrOnNull: { + Ref ref = Pop(); + if (ref == Ref::Null) { + pc = instr.imm_u32; + } else { + Push(ref); + } + break; + } + case O::BrTable: { auto key = Pop(); if (key >= instr.imm_u32) { @@ -1249,6 +1359,19 @@ RunResult Thread::StepInternal(Trap::Ptr* out_trap) { } } + case O::CallRef: + case O::ReturnCallRef: { + Ref new_func_ref = Pop(); + TRAP_IF(new_func_ref == Ref::Null, "null function reference"); + Func::Ptr new_func{store_, new_func_ref}; + + if (instr.op == O::ReturnCallRef) { + return DoReturnCall(new_func, out_trap); + } else { + return DoCall(new_func, out_trap); + } + } + case O::Drop: Pop(); break; @@ -1583,6 +1706,10 @@ RunResult Thread::StepInternal(Trap::Ptr* out_trap) { Push(Pop() == Ref::Null); break; + case O::RefAsNonNull: + TRAP_IF(Pick(1).Get() == Ref::Null, "null reference"); + break; + case O::RefFunc: Push(inst_->funcs()[instr.imm_u32]); break; @@ -2001,7 +2128,6 @@ RunResult Thread::StepInternal(Trap::Ptr* out_trap) { case O::ReturnCall: case O::SelectT: - case O::CallRef: case O::Try: case O::TryTable: case O::Catch: diff --git a/src/interp/istream.cc b/src/interp/istream.cc index aecc03dbf3..827d1b7c30 100644 --- a/src/interp/istream.cc +++ b/src/interp/istream.cc @@ -246,6 +246,7 @@ Instr Istream::Read(Offset* offset) const { case Opcode::F64X2ConvertLowI32X4U: case Opcode::I8X16Splat: case Opcode::RefIsNull: + case Opcode::RefAsNonNull: case Opcode::V128Not: case Opcode::V128AnyTrue: case Opcode::I8X16Abs: @@ -506,6 +507,8 @@ Instr Istream::Read(Offset* offset) const { break; case Opcode::BrIf: + case Opcode::BrOnNonNull: + case Opcode::BrOnNull: case Opcode::BrTable: case Opcode::InterpBrUnless: // Jump target immediate, 1 operand. @@ -785,8 +788,8 @@ Instr Istream::Read(Offset* offset) const { instr.imm_v128 = ReadAt(offset); break; - case Opcode::CallRef: case Opcode::Block: + case Opcode::CallRef: case Opcode::Catch: case Opcode::CatchAll: case Opcode::Delegate: @@ -799,6 +802,7 @@ Instr Istream::Read(Offset* offset) const { case Opcode::Try: case Opcode::TryTable: case Opcode::ReturnCall: + case Opcode::ReturnCallRef: // Not used. break; } diff --git a/src/ir-util.cc b/src/ir-util.cc index 5266a26457..16a85cd220 100644 --- a/src/ir-util.cc +++ b/src/ir-util.cc @@ -120,6 +120,16 @@ ModuleContext::Arities ModuleContext::GetExprArity(const Expr& expr) const { return {arity + 1, arity}; } + case ExprType::BrOnNonNull: { + Index arity = GetLabelArity(cast(&expr)->var); + return {arity + 1, arity}; + } + + case ExprType::BrOnNull: { + Index arity = GetLabelArity(cast(&expr)->var); + return {arity + 1, arity}; + } + case ExprType::BrTable: return {GetLabelArity(cast(&expr)->default_target) + 1, 1, true}; @@ -140,7 +150,7 @@ ModuleContext::Arities ModuleContext::GetExprArity(const Expr& expr) const { } case ExprType::CallRef: { - const Var& var = cast(&expr)->function_type_index; + const Var& var = cast(&expr)->sig_type; return {GetFuncParamCount(var) + 1, GetFuncResultCount(var)}; } @@ -150,6 +160,11 @@ ModuleContext::Arities ModuleContext::GetExprArity(const Expr& expr) const { true}; } + case ExprType::ReturnCallRef: { + const Var& var = cast(&expr)->sig_type; + return {GetFuncParamCount(var) + 1, GetFuncResultCount(var), true}; + } + case ExprType::Const: case ExprType::GlobalGet: case ExprType::LocalGet: @@ -186,6 +201,7 @@ ModuleContext::Arities ModuleContext::GetExprArity(const Expr& expr) const { case ExprType::RefIsNull: case ExprType::LoadSplat: case ExprType::LoadZero: + case ExprType::RefAsNonNull: return {1, 1}; case ExprType::Drop: diff --git a/src/ir.cc b/src/ir.cc index a2f9c48e0c..46713db04c 100644 --- a/src/ir.cc +++ b/src/ir.cc @@ -36,6 +36,8 @@ const char* ExprTypeName[] = { "Block", "Br", "BrIf", + "BrOnNonNull", + "BrOnNull", "BrTable", "Call", "CallIndirect", @@ -60,6 +62,7 @@ const char* ExprTypeName[] = { "MemoryInit", "MemorySize", "Nop", + "RefAsNonNull", "RefIsNull", "RefFunc", "RefNull", @@ -67,6 +70,7 @@ const char* ExprTypeName[] = { "Return", "ReturnCall", "ReturnCallIndirect", + "ReturnCallRef", "Select", "SimdLaneOp", "SimdLoadLane", @@ -107,7 +111,24 @@ const char* GetExprTypeName(const Expr& expr) { } bool FuncSignature::operator==(const FuncSignature& rhs) const { - return param_types == rhs.param_types && result_types == rhs.result_types; + if (param_types.size() != rhs.param_types.size() || + result_types.size() != rhs.result_types.size()) { + return false; + } + + if (param_types.size() > 0 && + memcmp(param_types.data(), rhs.param_types.data(), + param_types.size() * sizeof(Type)) != 0) { + return false; + } + + if (result_types.size() > 0 && + memcmp(result_types.data(), rhs.result_types.data(), + result_types.size() * sizeof(Type)) != 0) { + return false; + } + + return true; } const Export* Module::GetExport(std::string_view name) const { @@ -591,10 +612,24 @@ void MakeTypeBindingReverseMapping( Var::Var() : Var(kInvalidIndex, Location()) {} Var::Var(Index index, const Location& loc) - : loc(loc), type_(VarType::Index), index_(index) {} + : loc(loc), type_(VarType::Index), opt_type_(0), index_(index) {} Var::Var(std::string_view name, const Location& loc) - : loc(loc), type_(VarType::Name), name_(name) {} + : loc(loc), type_(VarType::Name), opt_type_(0), name_(name) {} + +Var::Var(Type type, const Location& loc) + : loc(loc), type_(VarType::Index), index_(0) { + assert(static_cast(type) < 0 && + static_cast(type) >= INT16_MIN); + opt_type_ = static_cast(type); + + if (type.IsReferenceWithIndex()) { + index_ = type.GetReferenceIndex(); + } else if (type.IsNonTypedRef()) { + index_ = type.IsNullableNonTypedRef() ? Type::ReferenceOrNull + : Type::ReferenceNonNull; + } +} Var::Var(Var&& rhs) : Var() { *this = std::move(rhs); @@ -606,6 +641,7 @@ Var::Var(const Var& rhs) : Var() { Var& Var::operator=(Var&& rhs) { loc = rhs.loc; + opt_type_ = rhs.opt_type_; if (rhs.is_index()) { set_index(rhs.index_); } else { @@ -616,6 +652,7 @@ Var& Var::operator=(Var&& rhs) { Var& Var::operator=(const Var& rhs) { loc = rhs.loc; + opt_type_ = rhs.opt_type_; if (rhs.is_index()) { set_index(rhs.index_); } else { @@ -644,6 +681,22 @@ void Var::set_name(std::string_view name) { set_name(std::string(name)); } +void Var::set_opt_type(Type::Enum type) { + assert(static_cast(type) < 0 && + static_cast(type) >= INT16_MIN); + opt_type_ = static_cast(type); +} + +Type Var::to_type() const { + Type::Enum type = static_cast(opt_type_); + + if (Type::EnumIsReferenceWithIndex(type) || Type::EnumIsNonTypedRef(type)) { + return Type(type, index()); + } + + return Type(type); +} + void Var::Destroy() { if (is_name()) { Destruct(name_); diff --git a/src/leb128.cc b/src/leb128.cc index 6c5a650fa9..c4b1dab37c 100644 --- a/src/leb128.cc +++ b/src/leb128.cc @@ -273,10 +273,8 @@ size_t ReadS32Leb128(const uint8_t* p, return 4; } else if (p + 4 < end && (p[4] & 0x80) == 0) { // The top bits should be a sign-extension of the sign bit. - bool sign_bit_set = (p[4] & 0x8); - int top_bits = p[4] & 0xf0; - if ((sign_bit_set && top_bits != 0x70) || - (!sign_bit_set && top_bits != 0)) { + int top_bits = p[4] & 0xf8; + if (top_bits != 0x78 && top_bits != 0) { return 0; } uint32_t result = LEB128_5(uint32_t); @@ -329,10 +327,8 @@ size_t ReadS64Leb128(const uint8_t* p, return 9; } else if (p + 9 < end && (p[9] & 0x80) == 0) { // The top bits should be a sign-extension of the sign bit. - bool sign_bit_set = (p[9] & 0x1); - int top_bits = p[9] & 0xfe; - if ((sign_bit_set && top_bits != 0x7e) || - (!sign_bit_set && top_bits != 0)) { + int top_bits = p[9]; + if (top_bits != 0x7f && top_bits != 0) { return 0; } uint64_t result = LEB128_10(uint64_t); diff --git a/src/lexer-keywords.txt b/src/lexer-keywords.txt index 5923c7109c..eda61a3b7e 100644 --- a/src/lexer-keywords.txt +++ b/src/lexer-keywords.txt @@ -31,6 +31,8 @@ before, TokenType::Before binary, TokenType::Bin block, TokenType::Block, Opcode::Block br_if, TokenType::BrIf, Opcode::BrIf +br_on_non_null, TokenType::BrOnNonNull, Opcode::BrOnNonNull +br_on_null, TokenType::BrOnNull, Opcode::BrOnNull br_table, TokenType::BrTable, Opcode::BrTable br, TokenType::Br, Opcode::Br call_indirect, TokenType::CallIndirect, Opcode::CallIndirect @@ -183,8 +185,8 @@ f64x2.convert_low_i32x4_u, TokenType::Unary, Opcode::F64X2ConvertLowI32X4U f64x2.promote_low_f32x4, TokenType::Unary, Opcode::F64X2PromoteLowF32X4 f64x2, TokenType::F64X2 field, TokenType::Field -funcref, Type::FuncRef func, Type::FuncRef, TokenType::Func +funcref, Type::FuncRef function, TokenType::Function get, TokenType::Get global.get, TokenType::GlobalGet, Opcode::GlobalGet @@ -556,12 +558,14 @@ mut, TokenType::Mut nan:arithmetic, TokenType::NanArithmetic nan:canonical, TokenType::NanCanonical nop, TokenType::Nop, Opcode::Nop +null, TokenType::Null offset, TokenType::Offset output, TokenType::Output pagesize, TokenType::PageSize param, TokenType::Param ref, TokenType::Ref quote, TokenType::Quote +ref.as_non_null, TokenType::RefAsNonNull, Opcode::RefAsNonNull ref.extern, TokenType::RefExtern ref.func, TokenType::RefFunc, Opcode::RefFunc ref.is_null, TokenType::RefIsNull, Opcode::RefIsNull @@ -570,6 +574,7 @@ register, TokenType::Register result, TokenType::Result rethrow, TokenType::Rethrow, Opcode::Rethrow return_call_indirect, TokenType::ReturnCallIndirect, Opcode::ReturnCallIndirect +return_call_ref, TokenType::ReturnCallRef, Opcode::ReturnCallRef return_call, TokenType::ReturnCall, Opcode::ReturnCall return, TokenType::Return, Opcode::Return select, TokenType::Select, Opcode::Select diff --git a/src/opcode.cc b/src/opcode.cc index 023ae0b2a4..b01e615de5 100644 --- a/src/opcode.cc +++ b/src/opcode.cc @@ -360,6 +360,10 @@ bool Opcode::IsEnabled(const Features& features) const { return features.reference_types_enabled(); case Opcode::CallRef: + case Opcode::ReturnCallRef: + case Opcode::BrOnNonNull: + case Opcode::BrOnNull: + case Opcode::RefAsNonNull: return features.function_references_enabled(); // Interpreter opcodes are never "enabled". diff --git a/src/prebuilt/lexer-keywords.cc b/src/prebuilt/lexer-keywords.cc index 89f14dbaca..8dd541f499 100644 --- a/src/prebuilt/lexer-keywords.cc +++ b/src/prebuilt/lexer-keywords.cc @@ -158,7 +158,7 @@ Perfect_Hash::InWordSet (const char *str, size_t len) { enum { - TOTAL_KEYWORDS = 601, + TOTAL_KEYWORDS = 606, MIN_WORD_LENGTH = 2, MAX_WORD_LENGTH = 35, MIN_HASH_VALUE = 37, @@ -172,1417 +172,1427 @@ Perfect_Hash::InWordSet (const char *str, size_t len) {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 35 "src/lexer-keywords.txt" +#line 37 "src/lexer-keywords.txt" {"br", TokenType::Br, Opcode::Br}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 152 "src/lexer-keywords.txt" +#line 154 "src/lexer-keywords.txt" {"f64", Type::F64}, {""}, {""}, -#line 45 "src/lexer-keywords.txt" +#line 47 "src/lexer-keywords.txt" {"data", TokenType::Data}, {""}, {""}, {""}, -#line 464 "src/lexer-keywords.txt" +#line 466 "src/lexer-keywords.txt" {"i64", Type::I64}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 122 "src/lexer-keywords.txt" +#line 124 "src/lexer-keywords.txt" {"f32x4", TokenType::F32X4}, {""}, {""}, {""}, {""}, -#line 586 "src/lexer-keywords.txt" +#line 591 "src/lexer-keywords.txt" {"table", TokenType::Table}, -#line 48 "src/lexer-keywords.txt" +#line 50 "src/lexer-keywords.txt" {"do", TokenType::Do}, -#line 364 "src/lexer-keywords.txt" +#line 366 "src/lexer-keywords.txt" {"i32x4", TokenType::I32X4}, {""}, {""}, {""}, -#line 135 "src/lexer-keywords.txt" +#line 137 "src/lexer-keywords.txt" {"f64.ge", TokenType::Compare, Opcode::F64Ge}, -#line 74 "src/lexer-keywords.txt" +#line 76 "src/lexer-keywords.txt" {"f32.ge", TokenType::Compare, Opcode::F32Ge}, -#line 137 "src/lexer-keywords.txt" +#line 139 "src/lexer-keywords.txt" {"f64.le", TokenType::Compare, Opcode::F64Le}, -#line 76 "src/lexer-keywords.txt" +#line 78 "src/lexer-keywords.txt" {"f32.le", TokenType::Compare, Opcode::F32Le}, {""}, {""}, {""}, {""}, {""}, #line 30 "src/lexer-keywords.txt" {"before", TokenType::Before}, {""}, {""}, {""}, {""}, {""}, -#line 187 "src/lexer-keywords.txt" +#line 188 "src/lexer-keywords.txt" {"func", Type::FuncRef, TokenType::Func}, -#line 136 "src/lexer-keywords.txt" +#line 138 "src/lexer-keywords.txt" {"f64.gt", TokenType::Compare, Opcode::F64Gt}, -#line 75 "src/lexer-keywords.txt" +#line 77 "src/lexer-keywords.txt" {"f32.gt", TokenType::Compare, Opcode::F32Gt}, -#line 139 "src/lexer-keywords.txt" +#line 141 "src/lexer-keywords.txt" {"f64.lt", TokenType::Compare, Opcode::F64Lt}, -#line 78 "src/lexer-keywords.txt" +#line 80 "src/lexer-keywords.txt" {"f32.lt", TokenType::Compare, Opcode::F32Lt}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 43 "src/lexer-keywords.txt" +#line 45 "src/lexer-keywords.txt" {"code", TokenType::Code}, {""}, {""}, {""}, -#line 570 "src/lexer-keywords.txt" +#line 574 "src/lexer-keywords.txt" {"result", TokenType::Result}, {""}, -#line 100 "src/lexer-keywords.txt" +#line 102 "src/lexer-keywords.txt" {"f32x4.ge", TokenType::Compare, Opcode::F32X4Ge}, {""}, -#line 102 "src/lexer-keywords.txt" +#line 104 "src/lexer-keywords.txt" {"f32x4.le", TokenType::Compare, Opcode::F32X4Le}, {""}, -#line 578 "src/lexer-keywords.txt" +#line 583 "src/lexer-keywords.txt" {"struct", Type::Struct, TokenType::Struct}, {""}, {""}, {""}, {""}, {""}, -#line 555 "src/lexer-keywords.txt" +#line 557 "src/lexer-keywords.txt" {"mut", TokenType::Mut}, -#line 441 "src/lexer-keywords.txt" +#line 443 "src/lexer-keywords.txt" {"i64.or", TokenType::Binary, Opcode::I64Or}, -#line 298 "src/lexer-keywords.txt" +#line 300 "src/lexer-keywords.txt" {"i32.or", TokenType::Binary, Opcode::I32Or}, {""}, {""}, -#line 581 "src/lexer-keywords.txt" +#line 586 "src/lexer-keywords.txt" {"table.get", TokenType::TableGet, Opcode::TableGet}, -#line 101 "src/lexer-keywords.txt" +#line 103 "src/lexer-keywords.txt" {"f32x4.gt", TokenType::Compare, Opcode::F32X4Gt}, -#line 584 "src/lexer-keywords.txt" +#line 589 "src/lexer-keywords.txt" {"table.set", TokenType::TableSet, Opcode::TableSet}, -#line 103 "src/lexer-keywords.txt" +#line 105 "src/lexer-keywords.txt" {"f32x4.lt", TokenType::Compare, Opcode::F32X4Lt}, -#line 330 "src/lexer-keywords.txt" +#line 332 "src/lexer-keywords.txt" {"i32x4.ge_u", TokenType::Compare, Opcode::I32X4GeU}, {""}, -#line 334 "src/lexer-keywords.txt" +#line 336 "src/lexer-keywords.txt" {"i32x4.le_u", TokenType::Compare, Opcode::I32X4LeU}, {""}, -#line 329 "src/lexer-keywords.txt" +#line 331 "src/lexer-keywords.txt" {"i32x4.ge_s", TokenType::Compare, Opcode::I32X4GeS}, -#line 93 "src/lexer-keywords.txt" +#line 95 "src/lexer-keywords.txt" {"f32x4.ceil", TokenType::Unary, Opcode::F32X4Ceil}, -#line 333 "src/lexer-keywords.txt" +#line 335 "src/lexer-keywords.txt" {"i32x4.le_s", TokenType::Compare, Opcode::I32X4LeS}, {""}, -#line 332 "src/lexer-keywords.txt" +#line 334 "src/lexer-keywords.txt" {"i32x4.gt_u", TokenType::Compare, Opcode::I32X4GtU}, {""}, -#line 342 "src/lexer-keywords.txt" +#line 344 "src/lexer-keywords.txt" {"i32x4.lt_u", TokenType::Compare, Opcode::I32X4LtU}, {""}, -#line 331 "src/lexer-keywords.txt" +#line 333 "src/lexer-keywords.txt" {"i32x4.gt_s", TokenType::Compare, Opcode::I32X4GtS}, {""}, -#line 341 "src/lexer-keywords.txt" +#line 343 "src/lexer-keywords.txt" {"i32x4.lt_s", TokenType::Compare, Opcode::I32X4LtS}, -#line 145 "src/lexer-keywords.txt" +#line 147 "src/lexer-keywords.txt" {"f64.ne", TokenType::Compare, Opcode::F64Ne}, -#line 84 "src/lexer-keywords.txt" +#line 86 "src/lexer-keywords.txt" {"f32.ne", TokenType::Compare, Opcode::F32Ne}, {""}, {""}, {""}, -#line 554 "src/lexer-keywords.txt" +#line 556 "src/lexer-keywords.txt" {"module", TokenType::Module}, {""}, -#line 440 "src/lexer-keywords.txt" +#line 442 "src/lexer-keywords.txt" {"i64.ne", TokenType::Compare, Opcode::I64Ne}, -#line 297 "src/lexer-keywords.txt" +#line 299 "src/lexer-keywords.txt" {"i32.ne", TokenType::Compare, Opcode::I32Ne}, -#line 46 "src/lexer-keywords.txt" +#line 48 "src/lexer-keywords.txt" {"declare", TokenType::Declare}, {""}, -#line 144 "src/lexer-keywords.txt" +#line 146 "src/lexer-keywords.txt" {"f64.neg", TokenType::Unary, Opcode::F64Neg}, -#line 83 "src/lexer-keywords.txt" +#line 85 "src/lexer-keywords.txt" {"f32.neg", TokenType::Unary, Opcode::F32Neg}, {""}, -#line 149 "src/lexer-keywords.txt" +#line 151 "src/lexer-keywords.txt" {"f64.store", TokenType::Store, Opcode::F64Store}, -#line 87 "src/lexer-keywords.txt" +#line 89 "src/lexer-keywords.txt" {"f32.store", TokenType::Store, Opcode::F32Store}, {""}, -#line 447 "src/lexer-keywords.txt" +#line 449 "src/lexer-keywords.txt" {"i64.rotr", TokenType::Binary, Opcode::I64Rotr}, -#line 304 "src/lexer-keywords.txt" +#line 306 "src/lexer-keywords.txt" {"i32.rotr", TokenType::Binary, Opcode::I32Rotr}, -#line 446 "src/lexer-keywords.txt" +#line 448 "src/lexer-keywords.txt" {"i64.rotl", TokenType::Binary, Opcode::I64Rotl}, -#line 303 "src/lexer-keywords.txt" +#line 305 "src/lexer-keywords.txt" {"i32.rotl", TokenType::Binary, Opcode::I32Rotl}, -#line 454 "src/lexer-keywords.txt" +#line 456 "src/lexer-keywords.txt" {"i64.store", TokenType::Store, Opcode::I64Store}, -#line 310 "src/lexer-keywords.txt" +#line 312 "src/lexer-keywords.txt" {"i32.store", TokenType::Store, Opcode::I32Store}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 568 "src/lexer-keywords.txt" +#line 572 "src/lexer-keywords.txt" {"ref.null", TokenType::RefNull, Opcode::RefNull}, -#line 108 "src/lexer-keywords.txt" +#line 110 "src/lexer-keywords.txt" {"f32x4.neg", TokenType::Unary, Opcode::F32X4Neg}, {""}, -#line 109 "src/lexer-keywords.txt" +#line 111 "src/lexer-keywords.txt" {"f32x4.ne", TokenType::Compare, Opcode::F32X4Ne}, {""}, {""}, {""}, {""}, -#line 349 "src/lexer-keywords.txt" +#line 351 "src/lexer-keywords.txt" {"i32x4.neg", TokenType::Unary, Opcode::I32X4Neg}, {""}, -#line 350 "src/lexer-keywords.txt" +#line 352 "src/lexer-keywords.txt" {"i32x4.ne", TokenType::Compare, Opcode::I32X4Ne}, {""}, {""}, -#line 151 "src/lexer-keywords.txt" +#line 153 "src/lexer-keywords.txt" {"f64.trunc", TokenType::Unary, Opcode::F64Trunc}, -#line 89 "src/lexer-keywords.txt" +#line 91 "src/lexer-keywords.txt" {"f32.trunc", TokenType::Unary, Opcode::F32Trunc}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 143 "src/lexer-keywords.txt" +#line 145 "src/lexer-keywords.txt" {"f64.nearest", TokenType::Unary, Opcode::F64Nearest}, -#line 82 "src/lexer-keywords.txt" +#line 84 "src/lexer-keywords.txt" {"f32.nearest", TokenType::Unary, Opcode::F32Nearest}, {""}, {""}, {""}, -#line 120 "src/lexer-keywords.txt" +#line 122 "src/lexer-keywords.txt" {"f32x4.trunc", TokenType::Unary, Opcode::F32X4Trunc}, -#line 574 "src/lexer-keywords.txt" +#line 579 "src/lexer-keywords.txt" {"return", TokenType::Return, Opcode::Return}, - {""}, {""}, {""}, {""}, {""}, -#line 453 "src/lexer-keywords.txt" + {""}, {""}, {""}, {""}, +#line 561 "src/lexer-keywords.txt" + {"null", TokenType::Null}, +#line 455 "src/lexer-keywords.txt" {"i64.store8", TokenType::Store, Opcode::I64Store8}, -#line 309 "src/lexer-keywords.txt" +#line 311 "src/lexer-keywords.txt" {"i32.store8", TokenType::Store, Opcode::I32Store8}, -#line 142 "src/lexer-keywords.txt" +#line 144 "src/lexer-keywords.txt" {"f64.mul", TokenType::Binary, Opcode::F64Mul}, -#line 81 "src/lexer-keywords.txt" +#line 83 "src/lexer-keywords.txt" {"f32.mul", TokenType::Binary, Opcode::F32Mul}, -#line 92 "src/lexer-keywords.txt" +#line 94 "src/lexer-keywords.txt" {"f32x4.add", TokenType::Binary, Opcode::F32X4Add}, -#line 107 "src/lexer-keywords.txt" +#line 109 "src/lexer-keywords.txt" {"f32x4.nearest", TokenType::Unary, Opcode::F32X4Nearest}, {""}, {""}, {""}, -#line 439 "src/lexer-keywords.txt" +#line 441 "src/lexer-keywords.txt" {"i64.mul", TokenType::Binary, Opcode::I64Mul}, -#line 296 "src/lexer-keywords.txt" +#line 298 "src/lexer-keywords.txt" {"i32.mul", TokenType::Binary, Opcode::I32Mul}, -#line 323 "src/lexer-keywords.txt" +#line 325 "src/lexer-keywords.txt" {"i32x4.add", TokenType::Binary, Opcode::I32X4Add}, {""}, -#line 38 "src/lexer-keywords.txt" +#line 40 "src/lexer-keywords.txt" {"call", TokenType::Call, Opcode::Call}, {""}, -#line 126 "src/lexer-keywords.txt" +#line 128 "src/lexer-keywords.txt" {"f64.const", TokenType::Const, Opcode::F64Const}, -#line 64 "src/lexer-keywords.txt" +#line 66 "src/lexer-keywords.txt" {"f32.const", TokenType::Const, Opcode::F32Const}, {""}, {""}, {""}, -#line 106 "src/lexer-keywords.txt" +#line 108 "src/lexer-keywords.txt" {"f32x4.mul", TokenType::Binary, Opcode::F32X4Mul}, {""}, -#line 413 "src/lexer-keywords.txt" +#line 415 "src/lexer-keywords.txt" {"i64.const", TokenType::Const, Opcode::I64Const}, -#line 275 "src/lexer-keywords.txt" +#line 277 "src/lexer-keywords.txt" {"i32.const", TokenType::Const, Opcode::I32Const}, {""}, -#line 575 "src/lexer-keywords.txt" +#line 580 "src/lexer-keywords.txt" {"select", TokenType::Select, Opcode::Select}, {""}, -#line 348 "src/lexer-keywords.txt" +#line 350 "src/lexer-keywords.txt" {"i32x4.mul", TokenType::Binary, Opcode::I32X4Mul}, {""}, -#line 543 "src/lexer-keywords.txt" +#line 545 "src/lexer-keywords.txt" {"local", TokenType::Local}, {""}, {""}, {""}, -#line 496 "src/lexer-keywords.txt" +#line 498 "src/lexer-keywords.txt" {"i64.xor", TokenType::Binary, Opcode::I64Xor}, -#line 373 "src/lexer-keywords.txt" +#line 375 "src/lexer-keywords.txt" {"i32.xor", TokenType::Binary, Opcode::I32Xor}, -#line 47 "src/lexer-keywords.txt" +#line 49 "src/lexer-keywords.txt" {"delegate", TokenType::Delegate}, {""}, {""}, {""}, -#line 124 "src/lexer-keywords.txt" +#line 126 "src/lexer-keywords.txt" {"f64.add", TokenType::Binary, Opcode::F64Add}, -#line 62 "src/lexer-keywords.txt" +#line 64 "src/lexer-keywords.txt" {"f32.add", TokenType::Binary, Opcode::F32Add}, -#line 138 "src/lexer-keywords.txt" +#line 140 "src/lexer-keywords.txt" {"f64.load", TokenType::Load, Opcode::F64Load}, -#line 77 "src/lexer-keywords.txt" +#line 79 "src/lexer-keywords.txt" {"f32.load", TokenType::Load, Opcode::F32Load}, {""}, {""}, {""}, -#line 374 "src/lexer-keywords.txt" +#line 376 "src/lexer-keywords.txt" {"i64.add", TokenType::Binary, Opcode::I64Add}, -#line 245 "src/lexer-keywords.txt" +#line 247 "src/lexer-keywords.txt" {"i32.add", TokenType::Binary, Opcode::I32Add}, -#line 436 "src/lexer-keywords.txt" +#line 438 "src/lexer-keywords.txt" {"i64.load", TokenType::Load, Opcode::I64Load}, -#line 293 "src/lexer-keywords.txt" +#line 295 "src/lexer-keywords.txt" {"i32.load", TokenType::Load, Opcode::I32Load}, {""}, {""}, {""}, {""}, -#line 116 "src/lexer-keywords.txt" +#line 118 "src/lexer-keywords.txt" {"f32x4.replace_lane", TokenType::SimdLaneOp, Opcode::F32X4ReplaceLane}, {""}, {""}, {""}, -#line 375 "src/lexer-keywords.txt" +#line 377 "src/lexer-keywords.txt" {"i64.and", TokenType::Binary, Opcode::I64And}, -#line 246 "src/lexer-keywords.txt" +#line 248 "src/lexer-keywords.txt" {"i32.and", TokenType::Binary, Opcode::I32And}, {""}, -#line 352 "src/lexer-keywords.txt" +#line 354 "src/lexer-keywords.txt" {"i32x4.replace_lane", TokenType::SimdLaneOp, Opcode::I32X4ReplaceLane}, {""}, {""}, {""}, -#line 425 "src/lexer-keywords.txt" +#line 427 "src/lexer-keywords.txt" {"i64.ge_u", TokenType::Compare, Opcode::I64GeU}, -#line 284 "src/lexer-keywords.txt" +#line 286 "src/lexer-keywords.txt" {"i32.ge_u", TokenType::Compare, Opcode::I32GeU}, -#line 429 "src/lexer-keywords.txt" +#line 431 "src/lexer-keywords.txt" {"i64.le_u", TokenType::Compare, Opcode::I64LeU}, -#line 288 "src/lexer-keywords.txt" +#line 290 "src/lexer-keywords.txt" {"i32.le_u", TokenType::Compare, Opcode::I32LeU}, -#line 424 "src/lexer-keywords.txt" +#line 426 "src/lexer-keywords.txt" {"i64.ge_s", TokenType::Compare, Opcode::I64GeS}, -#line 283 "src/lexer-keywords.txt" +#line 285 "src/lexer-keywords.txt" {"i32.ge_s", TokenType::Compare, Opcode::I32GeS}, -#line 428 "src/lexer-keywords.txt" +#line 430 "src/lexer-keywords.txt" {"i64.le_s", TokenType::Compare, Opcode::I64LeS}, -#line 287 "src/lexer-keywords.txt" +#line 289 "src/lexer-keywords.txt" {"i32.le_s", TokenType::Compare, Opcode::I32LeS}, -#line 427 "src/lexer-keywords.txt" +#line 429 "src/lexer-keywords.txt" {"i64.gt_u", TokenType::Compare, Opcode::I64GtU}, -#line 286 "src/lexer-keywords.txt" +#line 288 "src/lexer-keywords.txt" {"i32.gt_u", TokenType::Compare, Opcode::I32GtU}, -#line 438 "src/lexer-keywords.txt" +#line 440 "src/lexer-keywords.txt" {"i64.lt_u", TokenType::Compare, Opcode::I64LtU}, -#line 295 "src/lexer-keywords.txt" +#line 297 "src/lexer-keywords.txt" {"i32.lt_u", TokenType::Compare, Opcode::I32LtU}, -#line 426 "src/lexer-keywords.txt" +#line 428 "src/lexer-keywords.txt" {"i64.gt_s", TokenType::Compare, Opcode::I64GtS}, -#line 285 "src/lexer-keywords.txt" +#line 287 "src/lexer-keywords.txt" {"i32.gt_s", TokenType::Compare, Opcode::I32GtS}, -#line 437 "src/lexer-keywords.txt" +#line 439 "src/lexer-keywords.txt" {"i64.lt_s", TokenType::Compare, Opcode::I64LtS}, -#line 294 "src/lexer-keywords.txt" +#line 296 "src/lexer-keywords.txt" {"i32.lt_s", TokenType::Compare, Opcode::I32LtS}, {""}, {""}, {""}, -#line 540 "src/lexer-keywords.txt" +#line 542 "src/lexer-keywords.txt" {"local.get", TokenType::LocalGet, Opcode::LocalGet}, {""}, -#line 541 "src/lexer-keywords.txt" +#line 543 "src/lexer-keywords.txt" {"local.set", TokenType::LocalSet, Opcode::LocalSet}, -#line 542 "src/lexer-keywords.txt" +#line 544 "src/lexer-keywords.txt" {"local.tee", TokenType::LocalTee, Opcode::LocalTee}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 351 "src/lexer-keywords.txt" +#line 353 "src/lexer-keywords.txt" {"i32x4.relaxed_laneselect", TokenType::Ternary, Opcode::I32X4RelaxedLaneSelect}, -#line 324 "src/lexer-keywords.txt" +#line 326 "src/lexer-keywords.txt" {"i32x4.all_true", TokenType::Unary, Opcode::I32X4AllTrue}, {""}, -#line 125 "src/lexer-keywords.txt" +#line 127 "src/lexer-keywords.txt" {"f64.ceil", TokenType::Unary, Opcode::F64Ceil}, -#line 63 "src/lexer-keywords.txt" +#line 65 "src/lexer-keywords.txt" {"f32.ceil", TokenType::Unary, Opcode::F32Ceil}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 585 "src/lexer-keywords.txt" +#line 590 "src/lexer-keywords.txt" {"table.size", TokenType::TableSize, Opcode::TableSize}, {""}, {""}, {""}, -#line 104 "src/lexer-keywords.txt" +#line 106 "src/lexer-keywords.txt" {"f32x4.max", TokenType::Binary, Opcode::F32X4Max}, -#line 535 "src/lexer-keywords.txt" +#line 537 "src/lexer-keywords.txt" {"if", TokenType::If, Opcode::If}, -#line 411 "src/lexer-keywords.txt" +#line 413 "src/lexer-keywords.txt" {"i64.atomic.store", TokenType::AtomicStore, Opcode::I64AtomicStore}, -#line 273 "src/lexer-keywords.txt" +#line 275 "src/lexer-keywords.txt" {"i32.atomic.store", TokenType::AtomicStore, Opcode::I32AtomicStore}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 563 "src/lexer-keywords.txt" +#line 566 "src/lexer-keywords.txt" {"ref", TokenType::Ref}, {""}, {""}, -#line 404 "src/lexer-keywords.txt" +#line 406 "src/lexer-keywords.txt" {"i64.atomic.rmw.or", TokenType::AtomicRmw, Opcode::I64AtomicRmwOr}, -#line 267 "src/lexer-keywords.txt" +#line 269 "src/lexer-keywords.txt" {"i32.atomic.rmw.or", TokenType::AtomicRmw, Opcode::I32AtomicRmwOr}, {""}, {""}, {""}, {""}, {""}, -#line 573 "src/lexer-keywords.txt" +#line 578 "src/lexer-keywords.txt" {"return_call", TokenType::ReturnCall, Opcode::ReturnCall}, {""}, {""}, -#line 53 "src/lexer-keywords.txt" +#line 55 "src/lexer-keywords.txt" {"else", TokenType::Else, Opcode::Else}, {""}, {""}, {""}, {""}, {""}, -#line 55 "src/lexer-keywords.txt" +#line 57 "src/lexer-keywords.txt" {"tag", TokenType::Tag}, {""}, -#line 98 "src/lexer-keywords.txt" +#line 100 "src/lexer-keywords.txt" {"f32x4.extract_lane", TokenType::SimdLaneOp, Opcode::F32X4ExtractLane}, -#line 565 "src/lexer-keywords.txt" +#line 569 "src/lexer-keywords.txt" {"ref.extern", TokenType::RefExtern}, -#line 338 "src/lexer-keywords.txt" +#line 340 "src/lexer-keywords.txt" {"i32x4.relaxed_trunc_f64x2_u_zero", TokenType::Unary, Opcode::I32X4RelaxedTruncF64X2UZero}, -#line 90 "src/lexer-keywords.txt" +#line 92 "src/lexer-keywords.txt" {"f32", Type::F32}, -#line 337 "src/lexer-keywords.txt" +#line 339 "src/lexer-keywords.txt" {"i32x4.relaxed_trunc_f64x2_s_zero", TokenType::Unary, Opcode::I32X4RelaxedTruncF64X2SZero}, {""}, {""}, -#line 328 "src/lexer-keywords.txt" +#line 330 "src/lexer-keywords.txt" {"i32x4.extract_lane", TokenType::SimdLaneOp, Opcode::I32X4ExtractLane}, {""}, -#line 189 "src/lexer-keywords.txt" +#line 191 "src/lexer-keywords.txt" {"get", TokenType::Get}, -#line 320 "src/lexer-keywords.txt" +#line 322 "src/lexer-keywords.txt" {"i32", Type::I32}, -#line 50 "src/lexer-keywords.txt" +#line 52 "src/lexer-keywords.txt" {"either", TokenType::Either}, {""}, {""}, -#line 391 "src/lexer-keywords.txt" +#line 393 "src/lexer-keywords.txt" {"i64.atomic.rmw32.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32SubU}, -#line 435 "src/lexer-keywords.txt" +#line 437 "src/lexer-keywords.txt" {"i64.load8_u", TokenType::Load, Opcode::I64Load8U}, -#line 292 "src/lexer-keywords.txt" +#line 294 "src/lexer-keywords.txt" {"i32.load8_u", TokenType::Load, Opcode::I32Load8U}, -#line 434 "src/lexer-keywords.txt" +#line 436 "src/lexer-keywords.txt" {"i64.load8_s", TokenType::Load, Opcode::I64Load8S}, -#line 291 "src/lexer-keywords.txt" +#line 293 "src/lexer-keywords.txt" {"i32.load8_s", TokenType::Load, Opcode::I32Load8S}, {""}, -#line 410 "src/lexer-keywords.txt" +#line 412 "src/lexer-keywords.txt" {"i64.atomic.store8", TokenType::AtomicStore, Opcode::I64AtomicStore8}, -#line 272 "src/lexer-keywords.txt" +#line 274 "src/lexer-keywords.txt" {"i32.atomic.store8", TokenType::AtomicStore, Opcode::I32AtomicStore8}, -#line 431 "src/lexer-keywords.txt" +#line 433 "src/lexer-keywords.txt" {"i64.load16_u", TokenType::Load, Opcode::I64Load16U}, -#line 290 "src/lexer-keywords.txt" +#line 292 "src/lexer-keywords.txt" {"i32.load16_u", TokenType::Load, Opcode::I32Load16U}, -#line 457 "src/lexer-keywords.txt" +#line 459 "src/lexer-keywords.txt" {"i64.trunc_f32_u", TokenType::Convert, Opcode::I64TruncF32U}, -#line 313 "src/lexer-keywords.txt" +#line 315 "src/lexer-keywords.txt" {"i32.trunc_f32_u", TokenType::Convert, Opcode::I32TruncF32U}, -#line 430 "src/lexer-keywords.txt" +#line 432 "src/lexer-keywords.txt" {"i64.load16_s", TokenType::Load, Opcode::I64Load16S}, -#line 289 "src/lexer-keywords.txt" +#line 291 "src/lexer-keywords.txt" {"i32.load16_s", TokenType::Load, Opcode::I32Load16S}, -#line 456 "src/lexer-keywords.txt" +#line 458 "src/lexer-keywords.txt" {"i64.trunc_f32_s", TokenType::Convert, Opcode::I64TruncF32S}, -#line 312 "src/lexer-keywords.txt" +#line 314 "src/lexer-keywords.txt" {"i32.trunc_f32_s", TokenType::Convert, Opcode::I32TruncF32S}, -#line 445 "src/lexer-keywords.txt" +#line 447 "src/lexer-keywords.txt" {"i64.rem_u", TokenType::Binary, Opcode::I64RemU}, -#line 302 "src/lexer-keywords.txt" +#line 304 "src/lexer-keywords.txt" {"i32.rem_u", TokenType::Binary, Opcode::I32RemU}, -#line 444 "src/lexer-keywords.txt" +#line 446 "src/lexer-keywords.txt" {"i64.rem_s", TokenType::Binary, Opcode::I64RemS}, -#line 301 "src/lexer-keywords.txt" +#line 303 "src/lexer-keywords.txt" {"i32.rem_s", TokenType::Binary, Opcode::I32RemS}, {""}, -#line 54 "src/lexer-keywords.txt" +#line 56 "src/lexer-keywords.txt" {"end", TokenType::End, Opcode::End}, {""}, -#line 407 "src/lexer-keywords.txt" +#line 409 "src/lexer-keywords.txt" {"i64.atomic.rmw.xor", TokenType::AtomicRmw, Opcode::I64AtomicRmwXor}, -#line 270 "src/lexer-keywords.txt" +#line 272 "src/lexer-keywords.txt" {"i32.atomic.rmw.xor", TokenType::AtomicRmw, Opcode::I32AtomicRmwXor}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 587 "src/lexer-keywords.txt" +#line 592 "src/lexer-keywords.txt" {"then", TokenType::Then}, -#line 583 "src/lexer-keywords.txt" +#line 588 "src/lexer-keywords.txt" {"table.init", TokenType::TableInit, Opcode::TableInit}, {""}, {""}, -#line 344 "src/lexer-keywords.txt" +#line 346 "src/lexer-keywords.txt" {"i32x4.max_u", TokenType::Binary, Opcode::I32X4MaxU}, {""}, -#line 343 "src/lexer-keywords.txt" +#line 345 "src/lexer-keywords.txt" {"i32x4.max_s", TokenType::Binary, Opcode::I32X4MaxS}, - {""}, -#line 390 "src/lexer-keywords.txt" +#line 35 "src/lexer-keywords.txt" + {"br_on_null", TokenType::BrOnNull, Opcode::BrOnNull}, +#line 392 "src/lexer-keywords.txt" {"i64.atomic.rmw32.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32OrU}, -#line 448 "src/lexer-keywords.txt" +#line 450 "src/lexer-keywords.txt" {"i64.shl", TokenType::Binary, Opcode::I64Shl}, -#line 305 "src/lexer-keywords.txt" +#line 307 "src/lexer-keywords.txt" {"i32.shl", TokenType::Binary, Opcode::I32Shl}, {""}, {""}, -#line 114 "src/lexer-keywords.txt" +#line 116 "src/lexer-keywords.txt" {"f32x4.relaxed_min", TokenType::Binary, Opcode::F32X4RelaxedMin}, {""}, -#line 115 "src/lexer-keywords.txt" +#line 117 "src/lexer-keywords.txt" {"f32x4.relaxed_nmadd", TokenType::Ternary, Opcode::F32X4RelaxedNmadd}, -#line 140 "src/lexer-keywords.txt" +#line 142 "src/lexer-keywords.txt" {"f64.max", TokenType::Binary, Opcode::F64Max}, -#line 79 "src/lexer-keywords.txt" +#line 81 "src/lexer-keywords.txt" {"f32.max", TokenType::Binary, Opcode::F32Max}, {""}, {""}, -#line 160 "src/lexer-keywords.txt" +#line 162 "src/lexer-keywords.txt" {"f64x2.ge", TokenType::Compare, Opcode::F64X2Ge}, {""}, -#line 162 "src/lexer-keywords.txt" +#line 164 "src/lexer-keywords.txt" {"f64x2.le", TokenType::Compare, Opcode::F64X2Le}, {""}, {""}, -#line 387 "src/lexer-keywords.txt" +#line 389 "src/lexer-keywords.txt" {"i64.atomic.rmw32.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32AddU}, {""}, -#line 353 "src/lexer-keywords.txt" +#line 355 "src/lexer-keywords.txt" {"i32x4.shl", TokenType::Binary, Opcode::I32X4Shl}, {""}, {""}, -#line 569 "src/lexer-keywords.txt" +#line 573 "src/lexer-keywords.txt" {"register", TokenType::Register}, -#line 379 "src/lexer-keywords.txt" +#line 381 "src/lexer-keywords.txt" {"i64.atomic.load", TokenType::AtomicLoad, Opcode::I64AtomicLoad}, -#line 249 "src/lexer-keywords.txt" +#line 251 "src/lexer-keywords.txt" {"i32.atomic.load", TokenType::AtomicLoad, Opcode::I32AtomicLoad}, {""}, {""}, {""}, -#line 161 "src/lexer-keywords.txt" +#line 163 "src/lexer-keywords.txt" {"f64x2.gt", TokenType::Compare, Opcode::F64X2Gt}, -#line 388 "src/lexer-keywords.txt" +#line 390 "src/lexer-keywords.txt" {"i64.atomic.rmw32.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32AndU}, -#line 163 "src/lexer-keywords.txt" +#line 165 "src/lexer-keywords.txt" {"f64x2.lt", TokenType::Compare, Opcode::F64X2Lt}, {""}, -#line 58 "src/lexer-keywords.txt" +#line 60 "src/lexer-keywords.txt" {"exn", Type::ExnRef, TokenType::Exn}, {""}, {""}, -#line 475 "src/lexer-keywords.txt" +#line 477 "src/lexer-keywords.txt" {"i64x2.ge_s", TokenType::Binary, Opcode::I64X2GeS}, -#line 155 "src/lexer-keywords.txt" +#line 157 "src/lexer-keywords.txt" {"f64x2.ceil", TokenType::Unary, Opcode::F64X2Ceil}, -#line 474 "src/lexer-keywords.txt" +#line 476 "src/lexer-keywords.txt" {"i64x2.le_s", TokenType::Binary, Opcode::I64X2LeS}, {""}, {""}, {""}, {""}, {""}, -#line 473 "src/lexer-keywords.txt" +#line 475 "src/lexer-keywords.txt" {"i64x2.gt_s", TokenType::Binary, Opcode::I64X2GtS}, {""}, -#line 472 "src/lexer-keywords.txt" +#line 474 "src/lexer-keywords.txt" {"i64x2.lt_s", TokenType::Binary, Opcode::I64X2LtS}, -#line 99 "src/lexer-keywords.txt" +#line 101 "src/lexer-keywords.txt" {"f32x4.floor", TokenType::Unary, Opcode::F32X4Floor}, {""}, {""}, -#line 185 "src/lexer-keywords.txt" +#line 187 "src/lexer-keywords.txt" {"field", TokenType::Field}, -#line 112 "src/lexer-keywords.txt" +#line 114 "src/lexer-keywords.txt" {"f32x4.relaxed_madd", TokenType::Ternary, Opcode::F32X4RelaxedMadd}, {""}, {""}, {""}, {""}, {""}, -#line 419 "src/lexer-keywords.txt" +#line 421 "src/lexer-keywords.txt" {"i64.extend16_s", TokenType::Unary, Opcode::I64Extend16S}, -#line 281 "src/lexer-keywords.txt" +#line 283 "src/lexer-keywords.txt" {"i32.extend16_s", TokenType::Unary, Opcode::I32Extend16S}, {""}, -#line 539 "src/lexer-keywords.txt" +#line 541 "src/lexer-keywords.txt" {"item", TokenType::Item}, {""}, {""}, -#line 421 "src/lexer-keywords.txt" +#line 423 "src/lexer-keywords.txt" {"i64.extend8_s", TokenType::Unary, Opcode::I64Extend8S}, -#line 282 "src/lexer-keywords.txt" +#line 284 "src/lexer-keywords.txt" {"i32.extend8_s", TokenType::Unary, Opcode::I32Extend8S}, {""}, {""}, -#line 566 "src/lexer-keywords.txt" +#line 570 "src/lexer-keywords.txt" {"ref.func", TokenType::RefFunc, Opcode::RefFunc}, -#line 134 "src/lexer-keywords.txt" +#line 136 "src/lexer-keywords.txt" {"f64.floor", TokenType::Unary, Opcode::F64Floor}, -#line 73 "src/lexer-keywords.txt" +#line 75 "src/lexer-keywords.txt" {"f32.floor", TokenType::Unary, Opcode::F32Floor}, {""}, {""}, -#line 412 "src/lexer-keywords.txt" +#line 414 "src/lexer-keywords.txt" {"i64.clz", TokenType::Unary, Opcode::I64Clz}, -#line 274 "src/lexer-keywords.txt" +#line 276 "src/lexer-keywords.txt" {"i32.clz", TokenType::Unary, Opcode::I32Clz}, {""}, {""}, {""}, {""}, -#line 168 "src/lexer-keywords.txt" +#line 170 "src/lexer-keywords.txt" {"f64x2.neg", TokenType::Unary, Opcode::F64X2Neg}, -#line 105 "src/lexer-keywords.txt" +#line 107 "src/lexer-keywords.txt" {"f32x4.min", TokenType::Binary, Opcode::F32X4Min}, -#line 169 "src/lexer-keywords.txt" +#line 171 "src/lexer-keywords.txt" {"f64x2.ne", TokenType::Compare, Opcode::F64X2Ne}, -#line 414 "src/lexer-keywords.txt" +#line 416 "src/lexer-keywords.txt" {"i64.ctz", TokenType::Unary, Opcode::I64Ctz}, -#line 276 "src/lexer-keywords.txt" +#line 278 "src/lexer-keywords.txt" {"i32.ctz", TokenType::Unary, Opcode::I32Ctz}, {""}, {""}, -#line 477 "src/lexer-keywords.txt" +#line 479 "src/lexer-keywords.txt" {"i64x2.neg", TokenType::Unary, Opcode::I64X2Neg}, -#line 452 "src/lexer-keywords.txt" +#line 454 "src/lexer-keywords.txt" {"i64.store32", TokenType::Store, Opcode::I64Store32}, -#line 471 "src/lexer-keywords.txt" +#line 473 "src/lexer-keywords.txt" {"i64x2.ne", TokenType::Binary, Opcode::I64X2Ne}, {""}, -#line 56 "src/lexer-keywords.txt" +#line 58 "src/lexer-keywords.txt" {"extern", Type::ExternRef, TokenType::Extern}, -#line 394 "src/lexer-keywords.txt" +#line 396 "src/lexer-keywords.txt" {"i64.atomic.rmw8.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8AddU}, -#line 257 "src/lexer-keywords.txt" +#line 259 "src/lexer-keywords.txt" {"i32.atomic.rmw8.add_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8AddU}, {""}, {""}, -#line 392 "src/lexer-keywords.txt" +#line 394 "src/lexer-keywords.txt" {"i64.atomic.rmw32.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32XchgU}, {""}, -#line 113 "src/lexer-keywords.txt" +#line 115 "src/lexer-keywords.txt" {"f32x4.relaxed_max", TokenType::Binary, Opcode::F32X4RelaxedMax}, - {""}, {""}, {""}, {""}, {""}, -#line 395 "src/lexer-keywords.txt" +#line 568 "src/lexer-keywords.txt" + {"ref.as_non_null", TokenType::RefAsNonNull, Opcode::RefAsNonNull}, + {""}, {""}, {""}, {""}, +#line 397 "src/lexer-keywords.txt" {"i64.atomic.rmw8.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8AndU}, -#line 258 "src/lexer-keywords.txt" +#line 260 "src/lexer-keywords.txt" {"i32.atomic.rmw8.and_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8AndU}, {""}, {""}, -#line 188 "src/lexer-keywords.txt" +#line 190 "src/lexer-keywords.txt" {"function", TokenType::Function}, -#line 401 "src/lexer-keywords.txt" +#line 403 "src/lexer-keywords.txt" {"i64.atomic.rmw.add", TokenType::AtomicRmw, Opcode::I64AtomicRmwAdd}, -#line 264 "src/lexer-keywords.txt" +#line 266 "src/lexer-keywords.txt" {"i32.atomic.rmw.add", TokenType::AtomicRmw, Opcode::I32AtomicRmwAdd}, {""}, -#line 180 "src/lexer-keywords.txt" +#line 182 "src/lexer-keywords.txt" {"f64x2.trunc", TokenType::Unary, Opcode::F64X2Trunc}, {""}, {""}, -#line 393 "src/lexer-keywords.txt" +#line 395 "src/lexer-keywords.txt" {"i64.atomic.rmw32.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32XorU}, {""}, {""}, -#line 557 "src/lexer-keywords.txt" +#line 559 "src/lexer-keywords.txt" {"nan:canonical", TokenType::NanCanonical}, {""}, {""}, -#line 402 "src/lexer-keywords.txt" +#line 404 "src/lexer-keywords.txt" {"i64.atomic.rmw.and", TokenType::AtomicRmw, Opcode::I64AtomicRmwAnd}, -#line 265 "src/lexer-keywords.txt" +#line 267 "src/lexer-keywords.txt" {"i32.atomic.rmw.and", TokenType::AtomicRmw, Opcode::I32AtomicRmwAnd}, -#line 154 "src/lexer-keywords.txt" +#line 156 "src/lexer-keywords.txt" {"f64x2.add", TokenType::Binary, Opcode::F64X2Add}, -#line 167 "src/lexer-keywords.txt" +#line 169 "src/lexer-keywords.txt" {"f64x2.nearest", TokenType::Unary, Opcode::F64X2Nearest}, {""}, {""}, {""}, -#line 141 "src/lexer-keywords.txt" +#line 143 "src/lexer-keywords.txt" {"f64.min", TokenType::Binary, Opcode::F64Min}, -#line 80 "src/lexer-keywords.txt" +#line 82 "src/lexer-keywords.txt" {"f32.min", TokenType::Binary, Opcode::F32Min}, -#line 465 "src/lexer-keywords.txt" +#line 467 "src/lexer-keywords.txt" {"i64x2.add", TokenType::Binary, Opcode::I64X2Add}, {""}, {""}, -#line 400 "src/lexer-keywords.txt" +#line 402 "src/lexer-keywords.txt" {"i64.atomic.rmw8.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8XorU}, -#line 263 "src/lexer-keywords.txt" +#line 265 "src/lexer-keywords.txt" {"i32.atomic.rmw8.xor_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8XorU}, {""}, -#line 459 "src/lexer-keywords.txt" +#line 461 "src/lexer-keywords.txt" {"i64.trunc_f64_u", TokenType::Convert, Opcode::I64TruncF64U}, -#line 315 "src/lexer-keywords.txt" +#line 317 "src/lexer-keywords.txt" {"i32.trunc_f64_u", TokenType::Convert, Opcode::I32TruncF64U}, {""}, -#line 166 "src/lexer-keywords.txt" +#line 168 "src/lexer-keywords.txt" {"f64x2.mul", TokenType::Binary, Opcode::F64X2Mul}, -#line 458 "src/lexer-keywords.txt" +#line 460 "src/lexer-keywords.txt" {"i64.trunc_f64_s", TokenType::Convert, Opcode::I64TruncF64S}, -#line 314 "src/lexer-keywords.txt" +#line 316 "src/lexer-keywords.txt" {"i32.trunc_f64_s", TokenType::Convert, Opcode::I32TruncF64S}, -#line 567 "src/lexer-keywords.txt" +#line 571 "src/lexer-keywords.txt" {"ref.is_null", TokenType::RefIsNull, Opcode::RefIsNull}, -#line 605 "src/lexer-keywords.txt" +#line 610 "src/lexer-keywords.txt" {"v128", Type::V128}, {""}, {""}, -#line 469 "src/lexer-keywords.txt" +#line 471 "src/lexer-keywords.txt" {"i64x2.mul", TokenType::Binary, Opcode::I64X2Mul}, -#line 433 "src/lexer-keywords.txt" +#line 435 "src/lexer-keywords.txt" {"i64.load32_u", TokenType::Load, Opcode::I64Load32U}, {""}, {""}, {""}, -#line 432 "src/lexer-keywords.txt" +#line 434 "src/lexer-keywords.txt" {"i64.load32_s", TokenType::Load, Opcode::I64Load32S}, {""}, {""}, {""}, {""}, -#line 556 "src/lexer-keywords.txt" +#line 558 "src/lexer-keywords.txt" {"nan:arithmetic", TokenType::NanArithmetic}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 538 "src/lexer-keywords.txt" +#line 540 "src/lexer-keywords.txt" {"invoke", TokenType::Invoke}, {""}, {""}, {""}, {""}, {""}, -#line 378 "src/lexer-keywords.txt" +#line 380 "src/lexer-keywords.txt" {"i64.atomic.load8_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad8U}, -#line 248 "src/lexer-keywords.txt" +#line 250 "src/lexer-keywords.txt" {"i32.atomic.load8_u", TokenType::AtomicLoad, Opcode::I32AtomicLoad8U}, {""}, -#line 176 "src/lexer-keywords.txt" +#line 178 "src/lexer-keywords.txt" {"f64x2.replace_lane", TokenType::SimdLaneOp, Opcode::F64X2ReplaceLane}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 485 "src/lexer-keywords.txt" +#line 487 "src/lexer-keywords.txt" {"i64x2.replace_lane", TokenType::SimdLaneOp, Opcode::I64X2ReplaceLane}, {""}, -#line 564 "src/lexer-keywords.txt" +#line 567 "src/lexer-keywords.txt" {"quote", TokenType::Quote}, #line 32 "src/lexer-keywords.txt" {"block", TokenType::Block, Opcode::Block}, {""}, {""}, -#line 450 "src/lexer-keywords.txt" +#line 452 "src/lexer-keywords.txt" {"i64.shr_u", TokenType::Binary, Opcode::I64ShrU}, -#line 307 "src/lexer-keywords.txt" +#line 309 "src/lexer-keywords.txt" {"i32.shr_u", TokenType::Binary, Opcode::I32ShrU}, -#line 449 "src/lexer-keywords.txt" +#line 451 "src/lexer-keywords.txt" {"i64.shr_s", TokenType::Binary, Opcode::I64ShrS}, -#line 306 "src/lexer-keywords.txt" +#line 308 "src/lexer-keywords.txt" {"i32.shr_s", TokenType::Binary, Opcode::I32ShrS}, -#line 397 "src/lexer-keywords.txt" +#line 399 "src/lexer-keywords.txt" {"i64.atomic.rmw8.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8OrU}, -#line 260 "src/lexer-keywords.txt" +#line 262 "src/lexer-keywords.txt" {"i32.atomic.rmw8.or_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8OrU}, -#line 240 "src/lexer-keywords.txt" +#line 242 "src/lexer-keywords.txt" {"i16x8", TokenType::I16X8}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 355 "src/lexer-keywords.txt" +#line 357 "src/lexer-keywords.txt" {"i32x4.shr_u", TokenType::Binary, Opcode::I32X4ShrU}, -#line 346 "src/lexer-keywords.txt" +#line 348 "src/lexer-keywords.txt" {"i32x4.min_u", TokenType::Binary, Opcode::I32X4MinU}, -#line 354 "src/lexer-keywords.txt" +#line 356 "src/lexer-keywords.txt" {"i32x4.shr_s", TokenType::Binary, Opcode::I32X4ShrS}, -#line 345 "src/lexer-keywords.txt" +#line 347 "src/lexer-keywords.txt" {"i32x4.min_s", TokenType::Binary, Opcode::I32X4MinS}, -#line 600 "src/lexer-keywords.txt" +#line 605 "src/lexer-keywords.txt" {"v128.or", TokenType::Binary, Opcode::V128Or}, {""}, -#line 560 "src/lexer-keywords.txt" +#line 563 "src/lexer-keywords.txt" {"output", TokenType::Output}, {""}, {""}, -#line 559 "src/lexer-keywords.txt" +#line 562 "src/lexer-keywords.txt" {"offset", TokenType::Offset}, {""}, -#line 592 "src/lexer-keywords.txt" +#line 597 "src/lexer-keywords.txt" {"type", TokenType::Type}, -#line 590 "src/lexer-keywords.txt" +#line 595 "src/lexer-keywords.txt" {"try", TokenType::Try, Opcode::Try}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 580 "src/lexer-keywords.txt" +#line 585 "src/lexer-keywords.txt" {"table.fill", TokenType::TableFill, Opcode::TableFill}, {""}, -#line 484 "src/lexer-keywords.txt" +#line 486 "src/lexer-keywords.txt" {"i64x2.relaxed_laneselect", TokenType::Ternary, Opcode::I64X2RelaxedLaneSelect}, -#line 478 "src/lexer-keywords.txt" +#line 480 "src/lexer-keywords.txt" {"i64x2.all_true", TokenType::Unary, Opcode::I64X2AllTrue}, - {""}, {""}, {""}, {""}, {""}, -#line 205 "src/lexer-keywords.txt" +#line 34 "src/lexer-keywords.txt" + {"br_on_non_null", TokenType::BrOnNonNull, Opcode::BrOnNonNull}, + {""}, {""}, {""}, {""}, +#line 207 "src/lexer-keywords.txt" {"i16x8.ge_u", TokenType::Compare, Opcode::I16X8GeU}, -#line 420 "src/lexer-keywords.txt" +#line 422 "src/lexer-keywords.txt" {"i64.extend32_s", TokenType::Unary, Opcode::I64Extend32S}, -#line 209 "src/lexer-keywords.txt" +#line 211 "src/lexer-keywords.txt" {"i16x8.le_u", TokenType::Compare, Opcode::I16X8LeU}, {""}, -#line 204 "src/lexer-keywords.txt" +#line 206 "src/lexer-keywords.txt" {"i16x8.ge_s", TokenType::Compare, Opcode::I16X8GeS}, -#line 40 "src/lexer-keywords.txt" +#line 42 "src/lexer-keywords.txt" {"catch_all", TokenType::CatchAll, Opcode::CatchAll}, -#line 208 "src/lexer-keywords.txt" +#line 210 "src/lexer-keywords.txt" {"i16x8.le_s", TokenType::Compare, Opcode::I16X8LeS}, -#line 336 "src/lexer-keywords.txt" +#line 338 "src/lexer-keywords.txt" {"i32x4.relaxed_trunc_f32x4_u", TokenType::Unary, Opcode::I32X4RelaxedTruncF32X4U}, -#line 207 "src/lexer-keywords.txt" +#line 209 "src/lexer-keywords.txt" {"i16x8.gt_u", TokenType::Compare, Opcode::I16X8GtU}, {""}, -#line 213 "src/lexer-keywords.txt" +#line 215 "src/lexer-keywords.txt" {"i16x8.lt_u", TokenType::Compare, Opcode::I16X8LtU}, -#line 335 "src/lexer-keywords.txt" +#line 337 "src/lexer-keywords.txt" {"i32x4.relaxed_trunc_f32x4_s", TokenType::Unary, Opcode::I32X4RelaxedTruncF32X4S}, -#line 206 "src/lexer-keywords.txt" +#line 208 "src/lexer-keywords.txt" {"i16x8.gt_s", TokenType::Compare, Opcode::I16X8GtS}, {""}, -#line 212 "src/lexer-keywords.txt" +#line 214 "src/lexer-keywords.txt" {"i16x8.lt_s", TokenType::Compare, Opcode::I16X8LtS}, {""}, {""}, -#line 70 "src/lexer-keywords.txt" +#line 72 "src/lexer-keywords.txt" {"f32.demote_f64", TokenType::Convert, Opcode::F32DemoteF64}, {""}, -#line 164 "src/lexer-keywords.txt" +#line 166 "src/lexer-keywords.txt" {"f64x2.max", TokenType::Binary, Opcode::F64X2Max}, {""}, -#line 117 "src/lexer-keywords.txt" +#line 119 "src/lexer-keywords.txt" {"f32x4.splat", TokenType::Unary, Opcode::F32X4Splat}, -#line 604 "src/lexer-keywords.txt" +#line 609 "src/lexer-keywords.txt" {"v128.store", TokenType::Store, Opcode::V128Store}, -#line 537 "src/lexer-keywords.txt" +#line 539 "src/lexer-keywords.txt" {"input", TokenType::Input}, {""}, {""}, -#line 572 "src/lexer-keywords.txt" +#line 576 "src/lexer-keywords.txt" {"return_call_indirect", TokenType::ReturnCallIndirect, Opcode::ReturnCallIndirect}, {""}, -#line 356 "src/lexer-keywords.txt" +#line 358 "src/lexer-keywords.txt" {"i32x4.splat", TokenType::Unary, Opcode::I32X4Splat}, -#line 508 "src/lexer-keywords.txt" +#line 510 "src/lexer-keywords.txt" {"i8x16.ge_u", TokenType::Compare, Opcode::I8X16GeU}, #line 33 "src/lexer-keywords.txt" {"br_if", TokenType::BrIf, Opcode::BrIf}, -#line 512 "src/lexer-keywords.txt" +#line 514 "src/lexer-keywords.txt" {"i8x16.le_u", TokenType::Compare, Opcode::I8X16LeU}, {""}, -#line 507 "src/lexer-keywords.txt" +#line 509 "src/lexer-keywords.txt" {"i8x16.ge_s", TokenType::Compare, Opcode::I8X16GeS}, {""}, -#line 511 "src/lexer-keywords.txt" +#line 513 "src/lexer-keywords.txt" {"i8x16.le_s", TokenType::Compare, Opcode::I8X16LeS}, {""}, -#line 510 "src/lexer-keywords.txt" +#line 512 "src/lexer-keywords.txt" {"i8x16.gt_u", TokenType::Compare, Opcode::I8X16GtU}, -#line 536 "src/lexer-keywords.txt" +#line 538 "src/lexer-keywords.txt" {"import", TokenType::Import}, -#line 514 "src/lexer-keywords.txt" +#line 516 "src/lexer-keywords.txt" {"i8x16.lt_u", TokenType::Compare, Opcode::I8X16LtU}, {""}, -#line 509 "src/lexer-keywords.txt" +#line 511 "src/lexer-keywords.txt" {"i8x16.gt_s", TokenType::Compare, Opcode::I8X16GtS}, {""}, -#line 513 "src/lexer-keywords.txt" +#line 515 "src/lexer-keywords.txt" {"i8x16.lt_s", TokenType::Compare, Opcode::I8X16LtS}, {""}, {""}, {""}, {""}, {""}, -#line 598 "src/lexer-keywords.txt" +#line 603 "src/lexer-keywords.txt" {"v128.load", TokenType::Load, Opcode::V128Load}, -#line 158 "src/lexer-keywords.txt" +#line 160 "src/lexer-keywords.txt" {"f64x2.extract_lane", TokenType::SimdLaneOp, Opcode::F64X2ExtractLane}, {""}, {""}, -#line 221 "src/lexer-keywords.txt" +#line 223 "src/lexer-keywords.txt" {"i16x8.neg", TokenType::Unary, Opcode::I16X8Neg}, {""}, -#line 223 "src/lexer-keywords.txt" +#line 225 "src/lexer-keywords.txt" {"i16x8.ne", TokenType::Compare, Opcode::I16X8Ne}, -#line 423 "src/lexer-keywords.txt" +#line 425 "src/lexer-keywords.txt" {"i64.extend_i32_u", TokenType::Convert, Opcode::I64ExtendI32U}, -#line 466 "src/lexer-keywords.txt" +#line 468 "src/lexer-keywords.txt" {"i64x2.extract_lane", TokenType::SimdLaneOp, Opcode::I64X2ExtractLane}, -#line 422 "src/lexer-keywords.txt" +#line 424 "src/lexer-keywords.txt" {"i64.extend_i32_s", TokenType::Convert, Opcode::I64ExtendI32S}, {""}, {""}, -#line 148 "src/lexer-keywords.txt" +#line 150 "src/lexer-keywords.txt" {"f64.sqrt", TokenType::Unary, Opcode::F64Sqrt}, -#line 86 "src/lexer-keywords.txt" +#line 88 "src/lexer-keywords.txt" {"f32.sqrt", TokenType::Unary, Opcode::F32Sqrt}, -#line 211 "src/lexer-keywords.txt" +#line 213 "src/lexer-keywords.txt" {"v128.load8x8_u", TokenType::Load, Opcode::V128Load8X8U}, {""}, -#line 210 "src/lexer-keywords.txt" +#line 212 "src/lexer-keywords.txt" {"v128.load8x8_s", TokenType::Load, Opcode::V128Load8X8S}, -#line 611 "src/lexer-keywords.txt" +#line 616 "src/lexer-keywords.txt" {"v128.load8_lane", TokenType::SimdLoadLane, Opcode::V128Load8Lane}, -#line 406 "src/lexer-keywords.txt" +#line 408 "src/lexer-keywords.txt" {"i64.atomic.rmw.xchg", TokenType::AtomicRmw, Opcode::I64AtomicRmwXchg}, -#line 269 "src/lexer-keywords.txt" +#line 271 "src/lexer-keywords.txt" {"i32.atomic.rmw.xchg", TokenType::AtomicRmw, Opcode::I32AtomicRmwXchg}, {""}, {""}, {""}, -#line 184 "src/lexer-keywords.txt" +#line 186 "src/lexer-keywords.txt" {"f64x2", TokenType::F64X2}, {""}, {""}, -#line 610 "src/lexer-keywords.txt" +#line 615 "src/lexer-keywords.txt" {"v128.load8_splat", TokenType::Load, Opcode::V128Load8Splat}, {""}, -#line 599 "src/lexer-keywords.txt" +#line 604 "src/lexer-keywords.txt" {"v128.not", TokenType::Unary, Opcode::V128Not}, -#line 618 "src/lexer-keywords.txt" +#line 623 "src/lexer-keywords.txt" {"v128.store64_lane", TokenType::SimdStoreLane, Opcode::V128Store64Lane}, -#line 495 "src/lexer-keywords.txt" +#line 497 "src/lexer-keywords.txt" {"i64x2", TokenType::I64X2}, -#line 118 "src/lexer-keywords.txt" +#line 120 "src/lexer-keywords.txt" {"f32x4.sqrt", TokenType::Unary, Opcode::F32X4Sqrt}, {""}, -#line 521 "src/lexer-keywords.txt" +#line 523 "src/lexer-keywords.txt" {"i8x16.neg", TokenType::Unary, Opcode::I8X16Neg}, {""}, -#line 523 "src/lexer-keywords.txt" +#line 525 "src/lexer-keywords.txt" {"i8x16.ne", TokenType::Compare, Opcode::I8X16Ne}, -#line 44 "src/lexer-keywords.txt" +#line 46 "src/lexer-keywords.txt" {"data.drop", TokenType::DataDrop, Opcode::DataDrop}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 451 "src/lexer-keywords.txt" +#line 453 "src/lexer-keywords.txt" {"i64.store16", TokenType::Store, Opcode::I64Store16}, -#line 308 "src/lexer-keywords.txt" +#line 310 "src/lexer-keywords.txt" {"i32.store16", TokenType::Store, Opcode::I32Store16}, {""}, -#line 186 "src/lexer-keywords.txt" +#line 189 "src/lexer-keywords.txt" {"funcref", Type::FuncRef}, -#line 196 "src/lexer-keywords.txt" +#line 198 "src/lexer-keywords.txt" {"i16x8.add", TokenType::Binary, Opcode::I16X8Add}, {""}, {""}, {""}, -#line 597 "src/lexer-keywords.txt" +#line 602 "src/lexer-keywords.txt" {"v128.const", TokenType::Const, Opcode::V128Const}, {""}, -#line 606 "src/lexer-keywords.txt" +#line 611 "src/lexer-keywords.txt" {"v128.xor", TokenType::Binary, Opcode::V128Xor}, {""}, {""}, {""}, {""}, {""}, -#line 174 "src/lexer-keywords.txt" +#line 176 "src/lexer-keywords.txt" {"f64x2.relaxed_min", TokenType::Binary, Opcode::F64X2RelaxedMin}, {""}, -#line 175 "src/lexer-keywords.txt" +#line 177 "src/lexer-keywords.txt" {"f64x2.relaxed_nmadd", TokenType::Ternary, Opcode::F64X2RelaxedNmadd}, {""}, -#line 218 "src/lexer-keywords.txt" +#line 220 "src/lexer-keywords.txt" {"i16x8.mul", TokenType::Binary, Opcode::I16X8Mul}, {""}, -#line 376 "src/lexer-keywords.txt" +#line 378 "src/lexer-keywords.txt" {"i64.atomic.load16_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad16U}, -#line 247 "src/lexer-keywords.txt" +#line 249 "src/lexer-keywords.txt" {"i32.atomic.load16_u", TokenType::AtomicLoad, Opcode::I32AtomicLoad16U}, {""}, {""}, {""}, -#line 39 "src/lexer-keywords.txt" +#line 41 "src/lexer-keywords.txt" {"catch", TokenType::Catch, Opcode::Catch}, {""}, {""}, -#line 486 "src/lexer-keywords.txt" +#line 488 "src/lexer-keywords.txt" {"i64x2.shl", TokenType::Binary, Opcode::I64X2Shl}, {""}, {""}, -#line 500 "src/lexer-keywords.txt" +#line 502 "src/lexer-keywords.txt" {"i8x16.add", TokenType::Binary, Opcode::I8X16Add}, {""}, -#line 595 "src/lexer-keywords.txt" +#line 600 "src/lexer-keywords.txt" {"v128.and", TokenType::Binary, Opcode::V128And}, {""}, {""}, {""}, {""}, -#line 534 "src/lexer-keywords.txt" +#line 536 "src/lexer-keywords.txt" {"i8x16", TokenType::I8X16}, {""}, {""}, -#line 52 "src/lexer-keywords.txt" +#line 54 "src/lexer-keywords.txt" {"elem", TokenType::Elem}, {""}, -#line 57 "src/lexer-keywords.txt" +#line 59 "src/lexer-keywords.txt" {"externref", Type::ExternRef}, {""}, {""}, -#line 594 "src/lexer-keywords.txt" +#line 599 "src/lexer-keywords.txt" {"v128.andnot", TokenType::Binary, Opcode::V128Andnot}, {""}, {""}, -#line 384 "src/lexer-keywords.txt" +#line 386 "src/lexer-keywords.txt" {"i64.atomic.rmw16.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16SubU}, -#line 254 "src/lexer-keywords.txt" +#line 256 "src/lexer-keywords.txt" {"i32.atomic.rmw16.sub_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16SubU}, {""}, -#line 226 "src/lexer-keywords.txt" +#line 228 "src/lexer-keywords.txt" {"i16x8.replace_lane", TokenType::SimdLaneOp, Opcode::I16X8ReplaceLane}, {""}, {""}, -#line 159 "src/lexer-keywords.txt" +#line 161 "src/lexer-keywords.txt" {"f64x2.floor", TokenType::Unary, Opcode::F64X2Floor}, {""}, {""}, -#line 468 "src/lexer-keywords.txt" +#line 470 "src/lexer-keywords.txt" {"v128.load32x2_u", TokenType::Load, Opcode::V128Load32X2U}, -#line 172 "src/lexer-keywords.txt" +#line 174 "src/lexer-keywords.txt" {"f64x2.relaxed_madd", TokenType::Ternary, Opcode::F64X2RelaxedMadd}, {""}, {""}, -#line 467 "src/lexer-keywords.txt" +#line 469 "src/lexer-keywords.txt" {"v128.load32x2_s", TokenType::Load, Opcode::V128Load32X2S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 36 "src/lexer-keywords.txt" +#line 38 "src/lexer-keywords.txt" {"call_indirect", TokenType::CallIndirect, Opcode::CallIndirect}, {""}, -#line 526 "src/lexer-keywords.txt" +#line 528 "src/lexer-keywords.txt" {"i8x16.replace_lane", TokenType::SimdLaneOp, Opcode::I8X16ReplaceLane}, {""}, {""}, {""}, {""}, {""}, -#line 165 "src/lexer-keywords.txt" +#line 167 "src/lexer-keywords.txt" {"f64x2.min", TokenType::Binary, Opcode::F64X2Min}, -#line 383 "src/lexer-keywords.txt" +#line 385 "src/lexer-keywords.txt" {"i64.atomic.rmw16.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16OrU}, -#line 253 "src/lexer-keywords.txt" +#line 255 "src/lexer-keywords.txt" {"i32.atomic.rmw16.or_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16OrU}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 224 "src/lexer-keywords.txt" +#line 226 "src/lexer-keywords.txt" {"i16x8.relaxed_laneselect", TokenType::Ternary, Opcode::I16X8RelaxedLaneSelect}, -#line 197 "src/lexer-keywords.txt" +#line 199 "src/lexer-keywords.txt" {"i16x8.all_true", TokenType::Unary, Opcode::I16X8AllTrue}, {""}, {""}, #line 21 "src/lexer-keywords.txt" {"after", TokenType::After}, -#line 552 "src/lexer-keywords.txt" +#line 554 "src/lexer-keywords.txt" {"memory.size", TokenType::MemorySize, Opcode::MemorySize}, -#line 173 "src/lexer-keywords.txt" +#line 175 "src/lexer-keywords.txt" {"f64x2.relaxed_max", TokenType::Binary, Opcode::F64X2RelaxedMax}, -#line 380 "src/lexer-keywords.txt" +#line 382 "src/lexer-keywords.txt" {"i64.atomic.rmw16.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16AddU}, -#line 250 "src/lexer-keywords.txt" +#line 252 "src/lexer-keywords.txt" {"i32.atomic.rmw16.add_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16AddU}, -#line 399 "src/lexer-keywords.txt" +#line 401 "src/lexer-keywords.txt" {"i64.atomic.rmw8.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8XchgU}, -#line 262 "src/lexer-keywords.txt" +#line 264 "src/lexer-keywords.txt" {"i32.atomic.rmw8.xchg_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8XchgU}, -#line 232 "src/lexer-keywords.txt" +#line 234 "src/lexer-keywords.txt" {"i16x8.sub_sat_u", TokenType::Binary, Opcode::I16X8SubSatU}, {""}, {""}, {""}, -#line 231 "src/lexer-keywords.txt" +#line 233 "src/lexer-keywords.txt" {"i16x8.sub_sat_s", TokenType::Binary, Opcode::I16X8SubSatS}, {""}, {""}, {""}, -#line 381 "src/lexer-keywords.txt" +#line 383 "src/lexer-keywords.txt" {"i64.atomic.rmw16.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16AndU}, -#line 251 "src/lexer-keywords.txt" +#line 253 "src/lexer-keywords.txt" {"i32.atomic.rmw16.and_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16AndU}, -#line 347 "src/lexer-keywords.txt" +#line 349 "src/lexer-keywords.txt" {"i32x4.dot_i16x8_s", TokenType::Binary, Opcode::I32X4DotI16X8S}, {""}, -#line 389 "src/lexer-keywords.txt" +#line 391 "src/lexer-keywords.txt" {"i64.atomic.rmw32.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw32CmpxchgU}, {""}, {""}, {""}, {""}, {""}, -#line 525 "src/lexer-keywords.txt" +#line 527 "src/lexer-keywords.txt" {"i8x16.relaxed_laneselect", TokenType::Ternary, Opcode::I8X16RelaxedLaneSelect}, -#line 501 "src/lexer-keywords.txt" +#line 503 "src/lexer-keywords.txt" {"i8x16.all_true", TokenType::Unary, Opcode::I8X16AllTrue}, {""}, {""}, {""}, {""}, -#line 577 "src/lexer-keywords.txt" +#line 582 "src/lexer-keywords.txt" {"start", TokenType::Start}, {""}, -#line 123 "src/lexer-keywords.txt" +#line 125 "src/lexer-keywords.txt" {"f64.abs", TokenType::Unary, Opcode::F64Abs}, -#line 61 "src/lexer-keywords.txt" +#line 63 "src/lexer-keywords.txt" {"f32.abs", TokenType::Unary, Opcode::F32Abs}, {""}, -#line 532 "src/lexer-keywords.txt" +#line 534 "src/lexer-keywords.txt" {"i8x16.sub_sat_u", TokenType::Binary, Opcode::I8X16SubSatU}, {""}, {""}, {""}, -#line 531 "src/lexer-keywords.txt" +#line 533 "src/lexer-keywords.txt" {"i8x16.sub_sat_s", TokenType::Binary, Opcode::I8X16SubSatS}, -#line 616 "src/lexer-keywords.txt" +#line 621 "src/lexer-keywords.txt" {"v128.store16_lane", TokenType::SimdStoreLane, Opcode::V128Store16Lane}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 119 "src/lexer-keywords.txt" +#line 121 "src/lexer-keywords.txt" {"f32x4.sub", TokenType::Binary, Opcode::F32X4Sub}, {""}, {""}, -#line 91 "src/lexer-keywords.txt" +#line 93 "src/lexer-keywords.txt" {"f32x4.abs", TokenType::Unary, Opcode::F32X4Abs}, {""}, -#line 608 "src/lexer-keywords.txt" +#line 613 "src/lexer-keywords.txt" {"v128.load32_splat", TokenType::Load, Opcode::V128Load32Splat}, -#line 562 "src/lexer-keywords.txt" +#line 565 "src/lexer-keywords.txt" {"param", TokenType::Param}, -#line 357 "src/lexer-keywords.txt" +#line 359 "src/lexer-keywords.txt" {"i32x4.sub", TokenType::Binary, Opcode::I32X4Sub}, -#line 96 "src/lexer-keywords.txt" +#line 98 "src/lexer-keywords.txt" {"f32x4.div", TokenType::Binary, Opcode::F32X4Div}, -#line 602 "src/lexer-keywords.txt" +#line 607 "src/lexer-keywords.txt" {"v128.load32_zero", TokenType::Load, Opcode::V128Load32Zero}, -#line 322 "src/lexer-keywords.txt" +#line 324 "src/lexer-keywords.txt" {"i32x4.abs", TokenType::Unary, Opcode::I32X4Abs}, -#line 34 "src/lexer-keywords.txt" +#line 36 "src/lexer-keywords.txt" {"br_table", TokenType::BrTable, Opcode::BrTable}, {""}, {""}, {""}, -#line 195 "src/lexer-keywords.txt" +#line 197 "src/lexer-keywords.txt" {"i16x8.add_sat_u", TokenType::Binary, Opcode::I16X8AddSatU}, {""}, {""}, {""}, -#line 194 "src/lexer-keywords.txt" +#line 196 "src/lexer-keywords.txt" {"i16x8.add_sat_s", TokenType::Binary, Opcode::I16X8AddSatS}, {""}, -#line 111 "src/lexer-keywords.txt" +#line 113 "src/lexer-keywords.txt" {"f32x4.pmin", TokenType::Binary, Opcode::F32X4PMin}, #line 31 "src/lexer-keywords.txt" {"binary", TokenType::Bin}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 463 "src/lexer-keywords.txt" +#line 465 "src/lexer-keywords.txt" {"i64.trunc_sat_f64_u", TokenType::Convert, Opcode::I64TruncSatF64U}, -#line 319 "src/lexer-keywords.txt" +#line 321 "src/lexer-keywords.txt" {"i32.trunc_sat_f64_u", TokenType::Convert, Opcode::I32TruncSatF64U}, -#line 385 "src/lexer-keywords.txt" +#line 387 "src/lexer-keywords.txt" {"i64.atomic.rmw16.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16XchgU}, -#line 255 "src/lexer-keywords.txt" +#line 257 "src/lexer-keywords.txt" {"i32.atomic.rmw16.xchg_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16XchgU}, -#line 462 "src/lexer-keywords.txt" +#line 464 "src/lexer-keywords.txt" {"i64.trunc_sat_f64_s", TokenType::Convert, Opcode::I64TruncSatF64S}, -#line 318 "src/lexer-keywords.txt" +#line 320 "src/lexer-keywords.txt" {"i32.trunc_sat_f64_s", TokenType::Convert, Opcode::I32TruncSatF64S}, {""}, {""}, -#line 613 "src/lexer-keywords.txt" +#line 618 "src/lexer-keywords.txt" {"v128.load32_lane", TokenType::SimdLoadLane, Opcode::V128Load32Lane}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 499 "src/lexer-keywords.txt" +#line 501 "src/lexer-keywords.txt" {"i8x16.add_sat_u", TokenType::Binary, Opcode::I8X16AddSatU}, -#line 377 "src/lexer-keywords.txt" +#line 379 "src/lexer-keywords.txt" {"i64.atomic.load32_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad32U}, {""}, -#line 615 "src/lexer-keywords.txt" +#line 620 "src/lexer-keywords.txt" {"v128.store8_lane", TokenType::SimdStoreLane, Opcode::V128Store8Lane}, -#line 498 "src/lexer-keywords.txt" +#line 500 "src/lexer-keywords.txt" {"i8x16.add_sat_s", TokenType::Binary, Opcode::I8X16AddSatS}, {""}, -#line 386 "src/lexer-keywords.txt" +#line 388 "src/lexer-keywords.txt" {"i64.atomic.rmw16.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16XorU}, -#line 256 "src/lexer-keywords.txt" +#line 258 "src/lexer-keywords.txt" {"i32.atomic.rmw16.xor_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16XorU}, {""}, -#line 192 "src/lexer-keywords.txt" +#line 194 "src/lexer-keywords.txt" {"global", TokenType::Global}, -#line 215 "src/lexer-keywords.txt" +#line 217 "src/lexer-keywords.txt" {"i16x8.max_u", TokenType::Binary, Opcode::I16X8MaxU}, {""}, -#line 214 "src/lexer-keywords.txt" +#line 216 "src/lexer-keywords.txt" {"i16x8.max_s", TokenType::Binary, Opcode::I16X8MaxS}, {""}, {""}, {""}, {""}, -#line 488 "src/lexer-keywords.txt" +#line 490 "src/lexer-keywords.txt" {"i64x2.shr_u", TokenType::Binary, Opcode::I64X2ShrU}, {""}, -#line 487 "src/lexer-keywords.txt" +#line 489 "src/lexer-keywords.txt" {"i64x2.shr_s", TokenType::Binary, Opcode::I64X2ShrS}, {""}, -#line 549 "src/lexer-keywords.txt" +#line 551 "src/lexer-keywords.txt" {"memory.fill", TokenType::MemoryFill, Opcode::MemoryFill}, {""}, {""}, {""}, {""}, -#line 326 "src/lexer-keywords.txt" +#line 328 "src/lexer-keywords.txt" {"i32x4.relaxed_dot_i8x16_i7x16_add_s", TokenType::Ternary, Opcode::I32X4DotI8X16I7X16AddS}, -#line 41 "src/lexer-keywords.txt" +#line 43 "src/lexer-keywords.txt" {"catch_ref", TokenType::CatchRef}, {""}, {""}, {""}, -#line 579 "src/lexer-keywords.txt" +#line 584 "src/lexer-keywords.txt" {"table.copy", TokenType::TableCopy, Opcode::TableCopy}, {""}, -#line 227 "src/lexer-keywords.txt" +#line 229 "src/lexer-keywords.txt" {"i16x8.shl", TokenType::Binary, Opcode::I16X8Shl}, {""}, {""}, {""}, {""}, {""}, -#line 516 "src/lexer-keywords.txt" +#line 518 "src/lexer-keywords.txt" {"i8x16.max_u", TokenType::Binary, Opcode::I8X16MaxU}, {""}, -#line 515 "src/lexer-keywords.txt" +#line 517 "src/lexer-keywords.txt" {"i8x16.max_s", TokenType::Binary, Opcode::I8X16MaxS}, {""}, {""}, -#line 576 "src/lexer-keywords.txt" +#line 581 "src/lexer-keywords.txt" {"shared", TokenType::Shared}, -#line 130 "src/lexer-keywords.txt" +#line 132 "src/lexer-keywords.txt" {"f64.convert_i64_u", TokenType::Convert, Opcode::F64ConvertI64U}, -#line 68 "src/lexer-keywords.txt" +#line 70 "src/lexer-keywords.txt" {"f32.convert_i64_u", TokenType::Convert, Opcode::F32ConvertI64U}, {""}, {""}, -#line 129 "src/lexer-keywords.txt" +#line 131 "src/lexer-keywords.txt" {"f64.convert_i64_s", TokenType::Convert, Opcode::F64ConvertI64S}, -#line 67 "src/lexer-keywords.txt" +#line 69 "src/lexer-keywords.txt" {"f32.convert_i64_s", TokenType::Convert, Opcode::F32ConvertI64S}, {""}, {""}, {""}, {""}, {""}, -#line 60 "src/lexer-keywords.txt" +#line 62 "src/lexer-keywords.txt" {"export", TokenType::Export}, {""}, {""}, {""}, {""}, {""}, -#line 527 "src/lexer-keywords.txt" +#line 529 "src/lexer-keywords.txt" {"i8x16.shl", TokenType::Binary, Opcode::I8X16Shl}, -#line 553 "src/lexer-keywords.txt" +#line 555 "src/lexer-keywords.txt" {"memory", TokenType::Memory}, -#line 593 "src/lexer-keywords.txt" +#line 598 "src/lexer-keywords.txt" {"unreachable", TokenType::Unreachable, Opcode::Unreachable}, {""}, -#line 177 "src/lexer-keywords.txt" +#line 179 "src/lexer-keywords.txt" {"f64x2.splat", TokenType::Unary, Opcode::F64X2Splat}, -#line 110 "src/lexer-keywords.txt" +#line 112 "src/lexer-keywords.txt" {"f32x4.pmax", TokenType::Binary, Opcode::F32X4PMax}, -#line 372 "src/lexer-keywords.txt" +#line 374 "src/lexer-keywords.txt" {"i32x4.trunc_sat_f64x2_u_zero", TokenType::Unary, Opcode::I32X4TruncSatF64X2UZero}, {""}, -#line 371 "src/lexer-keywords.txt" +#line 373 "src/lexer-keywords.txt" {"i32x4.trunc_sat_f64x2_s_zero", TokenType::Unary, Opcode::I32X4TruncSatF64X2SZero}, {""}, -#line 190 "src/lexer-keywords.txt" +#line 192 "src/lexer-keywords.txt" {"global.get", TokenType::GlobalGet, Opcode::GlobalGet}, -#line 489 "src/lexer-keywords.txt" +#line 491 "src/lexer-keywords.txt" {"i64x2.splat", TokenType::Unary, Opcode::I64X2Splat}, -#line 191 "src/lexer-keywords.txt" +#line 193 "src/lexer-keywords.txt" {"global.set", TokenType::GlobalSet, Opcode::GlobalSet}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 409 "src/lexer-keywords.txt" +#line 411 "src/lexer-keywords.txt" {"i64.atomic.store32", TokenType::AtomicStore, Opcode::I64AtomicStore32}, {""}, {""}, -#line 59 "src/lexer-keywords.txt" +#line 61 "src/lexer-keywords.txt" {"exnref", Type::ExnRef}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 609 "src/lexer-keywords.txt" +#line 614 "src/lexer-keywords.txt" {"v128.load64_splat", TokenType::Load, Opcode::V128Load64Splat}, -#line 617 "src/lexer-keywords.txt" +#line 622 "src/lexer-keywords.txt" {"v128.store32_lane", TokenType::SimdStoreLane, Opcode::V128Store32Lane}, -#line 178 "src/lexer-keywords.txt" +#line 180 "src/lexer-keywords.txt" {"f64x2.sqrt", TokenType::Unary, Opcode::F64X2Sqrt}, -#line 588 "src/lexer-keywords.txt" +#line 593 "src/lexer-keywords.txt" {"throw", TokenType::Throw, Opcode::Throw}, -#line 603 "src/lexer-keywords.txt" +#line 608 "src/lexer-keywords.txt" {"v128.load64_zero", TokenType::Load, Opcode::V128Load64Zero}, {""}, {""}, {""}, {""}, -#line 37 "src/lexer-keywords.txt" +#line 39 "src/lexer-keywords.txt" {"call_ref", TokenType::CallRef, Opcode::CallRef}, {""}, {""}, -#line 551 "src/lexer-keywords.txt" +#line 553 "src/lexer-keywords.txt" {"memory.init", TokenType::MemoryInit, Opcode::MemoryInit}, -#line 416 "src/lexer-keywords.txt" +#line 418 "src/lexer-keywords.txt" {"i64.div_u", TokenType::Binary, Opcode::I64DivU}, -#line 278 "src/lexer-keywords.txt" +#line 280 "src/lexer-keywords.txt" {"i32.div_u", TokenType::Binary, Opcode::I32DivU}, -#line 415 "src/lexer-keywords.txt" +#line 417 "src/lexer-keywords.txt" {"i64.div_s", TokenType::Binary, Opcode::I64DivS}, -#line 277 "src/lexer-keywords.txt" +#line 279 "src/lexer-keywords.txt" {"i32.div_s", TokenType::Binary, Opcode::I32DivS}, {""}, {""}, {""}, {""}, -#line 418 "src/lexer-keywords.txt" +#line 420 "src/lexer-keywords.txt" {"i64.eqz", TokenType::Convert, Opcode::I64Eqz}, -#line 280 "src/lexer-keywords.txt" +#line 282 "src/lexer-keywords.txt" {"i32.eqz", TokenType::Convert, Opcode::I32Eqz}, {""}, {""}, -#line 589 "src/lexer-keywords.txt" +#line 594 "src/lexer-keywords.txt" {"throw_ref", TokenType::ThrowRef, Opcode::ThrowRef}, {""}, -#line 203 "src/lexer-keywords.txt" +#line 205 "src/lexer-keywords.txt" {"i16x8.extract_lane_u", TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneU}, {""}, -#line 202 "src/lexer-keywords.txt" +#line 204 "src/lexer-keywords.txt" {"i16x8.extract_lane_s", TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneS}, {""}, {""}, -#line 614 "src/lexer-keywords.txt" +#line 619 "src/lexer-keywords.txt" {"v128.load64_lane", TokenType::SimdLoadLane, Opcode::V128Load64Lane}, -#line 396 "src/lexer-keywords.txt" +#line 398 "src/lexer-keywords.txt" {"i64.atomic.rmw8.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw8CmpxchgU}, -#line 259 "src/lexer-keywords.txt" +#line 261 "src/lexer-keywords.txt" {"i32.atomic.rmw8.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw8CmpxchgU}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 408 "src/lexer-keywords.txt" +#line 410 "src/lexer-keywords.txt" {"i64.atomic.store16", TokenType::AtomicStore, Opcode::I64AtomicStore16}, -#line 271 "src/lexer-keywords.txt" +#line 273 "src/lexer-keywords.txt" {"i32.atomic.store16", TokenType::AtomicStore, Opcode::I32AtomicStore16}, {""}, {""}, -#line 591 "src/lexer-keywords.txt" +#line 596 "src/lexer-keywords.txt" {"try_table", TokenType::TryTable, Opcode::TryTable}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 601 "src/lexer-keywords.txt" +#line 606 "src/lexer-keywords.txt" {"v128.any_true", TokenType::Unary, Opcode::V128AnyTrue}, {""}, -#line 506 "src/lexer-keywords.txt" +#line 508 "src/lexer-keywords.txt" {"i8x16.extract_lane_u", TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneU}, -#line 366 "src/lexer-keywords.txt" +#line 368 "src/lexer-keywords.txt" {"i32x4.trunc_sat_f32x4_u", TokenType::Unary, Opcode::I32X4TruncSatF32X4U}, -#line 505 "src/lexer-keywords.txt" +#line 507 "src/lexer-keywords.txt" {"i8x16.extract_lane_s", TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneS}, {""}, {""}, -#line 365 "src/lexer-keywords.txt" +#line 367 "src/lexer-keywords.txt" {"i32x4.trunc_sat_f32x4_s", TokenType::Unary, Opcode::I32X4TruncSatF32X4S}, {""}, {""}, {""}, {""}, -#line 49 "src/lexer-keywords.txt" +#line 51 "src/lexer-keywords.txt" {"drop", TokenType::Drop, Opcode::Drop}, {""}, {""}, {""}, -#line 582 "src/lexer-keywords.txt" +#line 587 "src/lexer-keywords.txt" {"table.grow", TokenType::TableGrow, Opcode::TableGrow}, {""}, {""}, -#line 571 "src/lexer-keywords.txt" +#line 575 "src/lexer-keywords.txt" {"rethrow", TokenType::Rethrow, Opcode::Rethrow}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 229 "src/lexer-keywords.txt" +#line 231 "src/lexer-keywords.txt" {"i16x8.shr_u", TokenType::Binary, Opcode::I16X8ShrU}, -#line 217 "src/lexer-keywords.txt" +#line 219 "src/lexer-keywords.txt" {"i16x8.min_u", TokenType::Binary, Opcode::I16X8MinU}, -#line 228 "src/lexer-keywords.txt" +#line 230 "src/lexer-keywords.txt" {"i16x8.shr_s", TokenType::Binary, Opcode::I16X8ShrS}, -#line 216 "src/lexer-keywords.txt" +#line 218 "src/lexer-keywords.txt" {"i16x8.min_s", TokenType::Binary, Opcode::I16X8MinS}, {""}, {""}, {""}, {""}, {""}, -#line 403 "src/lexer-keywords.txt" +#line 405 "src/lexer-keywords.txt" {"i64.atomic.rmw.cmpxchg", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmwCmpxchg}, -#line 266 "src/lexer-keywords.txt" +#line 268 "src/lexer-keywords.txt" {"i32.atomic.rmw.cmpxchg", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmwCmpxchg}, {""}, -#line 121 "src/lexer-keywords.txt" +#line 123 "src/lexer-keywords.txt" {"f32x4.demote_f64x2_zero", TokenType::Unary, Opcode::F32X4DemoteF64X2Zero}, {""}, {""}, -#line 42 "src/lexer-keywords.txt" +#line 44 "src/lexer-keywords.txt" {"catch_all_ref", TokenType::CatchAllRef}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, -#line 529 "src/lexer-keywords.txt" + {""}, +#line 577 "src/lexer-keywords.txt" + {"return_call_ref", TokenType::ReturnCallRef, Opcode::ReturnCallRef}, + {""}, {""}, +#line 531 "src/lexer-keywords.txt" {"i8x16.shr_u", TokenType::Binary, Opcode::I8X16ShrU}, -#line 518 "src/lexer-keywords.txt" +#line 520 "src/lexer-keywords.txt" {"i8x16.min_u", TokenType::Binary, Opcode::I8X16MinU}, -#line 528 "src/lexer-keywords.txt" +#line 530 "src/lexer-keywords.txt" {"i8x16.shr_s", TokenType::Binary, Opcode::I8X16ShrS}, -#line 517 "src/lexer-keywords.txt" +#line 519 "src/lexer-keywords.txt" {"i8x16.min_s", TokenType::Binary, Opcode::I8X16MinS}, {""}, {""}, {""}, #line 26 "src/lexer-keywords.txt" {"assert_return", TokenType::AssertReturn}, -#line 550 "src/lexer-keywords.txt" +#line 552 "src/lexer-keywords.txt" {"memory.grow", TokenType::MemoryGrow, Opcode::MemoryGrow}, {""}, {""}, {""}, {""}, -#line 398 "src/lexer-keywords.txt" +#line 400 "src/lexer-keywords.txt" {"i64.atomic.rmw8.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8SubU}, -#line 261 "src/lexer-keywords.txt" +#line 263 "src/lexer-keywords.txt" {"i32.atomic.rmw8.sub_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8SubU}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 198 "src/lexer-keywords.txt" +#line 200 "src/lexer-keywords.txt" {"i16x8.avgr_u", TokenType::Binary, Opcode::I16X8AvgrU}, -#line 230 "src/lexer-keywords.txt" +#line 232 "src/lexer-keywords.txt" {"i16x8.splat", TokenType::Unary, Opcode::I16X8Splat}, {""}, {""}, {""}, -#line 340 "src/lexer-keywords.txt" +#line 342 "src/lexer-keywords.txt" {"v128.load16x4_u", TokenType::Load, Opcode::V128Load16X4U}, {""}, -#line 558 "src/lexer-keywords.txt" +#line 560 "src/lexer-keywords.txt" {"nop", TokenType::Nop, Opcode::Nop}, {""}, -#line 339 "src/lexer-keywords.txt" +#line 341 "src/lexer-keywords.txt" {"v128.load16x4_s", TokenType::Load, Opcode::V128Load16X4S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 179 "src/lexer-keywords.txt" +#line 181 "src/lexer-keywords.txt" {"f64x2.sub", TokenType::Binary, Opcode::F64X2Sub}, {""}, {""}, -#line 153 "src/lexer-keywords.txt" +#line 155 "src/lexer-keywords.txt" {"f64x2.abs", TokenType::Unary, Opcode::F64X2Abs}, {""}, {""}, {""}, -#line 490 "src/lexer-keywords.txt" +#line 492 "src/lexer-keywords.txt" {"i64x2.sub", TokenType::Binary, Opcode::I64X2Sub}, -#line 156 "src/lexer-keywords.txt" +#line 158 "src/lexer-keywords.txt" {"f64x2.div", TokenType::Binary, Opcode::F64X2Div}, {""}, -#line 476 "src/lexer-keywords.txt" +#line 478 "src/lexer-keywords.txt" {"i64x2.abs", TokenType::Unary, Opcode::I64X2Abs}, -#line 502 "src/lexer-keywords.txt" +#line 504 "src/lexer-keywords.txt" {"i8x16.avgr_u", TokenType::Binary, Opcode::I8X16AvgrU}, -#line 530 "src/lexer-keywords.txt" +#line 532 "src/lexer-keywords.txt" {"i8x16.splat", TokenType::Unary, Opcode::I8X16Splat}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 171 "src/lexer-keywords.txt" +#line 173 "src/lexer-keywords.txt" {"f64x2.pmin", TokenType::Binary, Opcode::F64X2PMin}, {""}, {""}, -#line 544 "src/lexer-keywords.txt" +#line 546 "src/lexer-keywords.txt" {"loop", TokenType::Loop, Opcode::Loop}, {""}, {""}, {""}, {""}, {""}, -#line 461 "src/lexer-keywords.txt" +#line 463 "src/lexer-keywords.txt" {"i64.trunc_sat_f32_u", TokenType::Convert, Opcode::I64TruncSatF32U}, -#line 317 "src/lexer-keywords.txt" +#line 319 "src/lexer-keywords.txt" {"i32.trunc_sat_f32_u", TokenType::Convert, Opcode::I32TruncSatF32U}, -#line 133 "src/lexer-keywords.txt" +#line 135 "src/lexer-keywords.txt" {"f64.eq", TokenType::Compare, Opcode::F64Eq}, -#line 72 "src/lexer-keywords.txt" +#line 74 "src/lexer-keywords.txt" {"f32.eq", TokenType::Compare, Opcode::F32Eq}, -#line 460 "src/lexer-keywords.txt" +#line 462 "src/lexer-keywords.txt" {"i64.trunc_sat_f32_s", TokenType::Convert, Opcode::I64TruncSatF32S}, -#line 316 "src/lexer-keywords.txt" +#line 318 "src/lexer-keywords.txt" {"i32.trunc_sat_f32_s", TokenType::Convert, Opcode::I32TruncSatF32S}, {""}, {""}, {""}, -#line 417 "src/lexer-keywords.txt" +#line 419 "src/lexer-keywords.txt" {"i64.eq", TokenType::Compare, Opcode::I64Eq}, -#line 279 "src/lexer-keywords.txt" +#line 281 "src/lexer-keywords.txt" {"i32.eq", TokenType::Compare, Opcode::I32Eq}, -#line 325 "src/lexer-keywords.txt" +#line 327 "src/lexer-keywords.txt" {"i32x4.bitmask", TokenType::Unary, Opcode::I32X4Bitmask}, {""}, {""}, {""}, {""}, -#line 442 "src/lexer-keywords.txt" +#line 444 "src/lexer-keywords.txt" {"i64.popcnt", TokenType::Unary, Opcode::I64Popcnt}, -#line 299 "src/lexer-keywords.txt" +#line 301 "src/lexer-keywords.txt" {"i32.popcnt", TokenType::Unary, Opcode::I32Popcnt}, {""}, {""}, -#line 382 "src/lexer-keywords.txt" +#line 384 "src/lexer-keywords.txt" {"i64.atomic.rmw16.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw16CmpxchgU}, -#line 252 "src/lexer-keywords.txt" +#line 254 "src/lexer-keywords.txt" {"i32.atomic.rmw16.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw16CmpxchgU}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 97 "src/lexer-keywords.txt" +#line 99 "src/lexer-keywords.txt" {"f32x4.eq", TokenType::Compare, Opcode::F32X4Eq}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 327 "src/lexer-keywords.txt" +#line 329 "src/lexer-keywords.txt" {"i32x4.eq", TokenType::Compare, Opcode::I32X4Eq}, {""}, {""}, {""}, {""}, {""}, -#line 482 "src/lexer-keywords.txt" +#line 484 "src/lexer-keywords.txt" {"i64x2.extend_low_i32x4_u", TokenType::Unary, Opcode::I64X2ExtendLowI32X4U}, {""}, -#line 480 "src/lexer-keywords.txt" +#line 482 "src/lexer-keywords.txt" {"i64x2.extend_low_i32x4_s", TokenType::Unary, Opcode::I64X2ExtendLowI32X4S}, -#line 522 "src/lexer-keywords.txt" +#line 524 "src/lexer-keywords.txt" {"i8x16.popcnt", TokenType::Unary, Opcode::I8X16Popcnt}, {""}, {""}, -#line 607 "src/lexer-keywords.txt" +#line 612 "src/lexer-keywords.txt" {"v128.load16_splat", TokenType::Load, Opcode::V128Load16Splat}, {""}, {""}, {""}, {""}, {""}, -#line 128 "src/lexer-keywords.txt" +#line 130 "src/lexer-keywords.txt" {"f64.convert_i32_u", TokenType::Convert, Opcode::F64ConvertI32U}, -#line 66 "src/lexer-keywords.txt" +#line 68 "src/lexer-keywords.txt" {"f32.convert_i32_u", TokenType::Convert, Opcode::F32ConvertI32U}, {""}, {""}, -#line 127 "src/lexer-keywords.txt" +#line 129 "src/lexer-keywords.txt" {"f64.convert_i32_s", TokenType::Convert, Opcode::F64ConvertI32S}, -#line 65 "src/lexer-keywords.txt" +#line 67 "src/lexer-keywords.txt" {"f32.convert_i32_s", TokenType::Convert, Opcode::F32ConvertI32S}, {""}, -#line 368 "src/lexer-keywords.txt" +#line 370 "src/lexer-keywords.txt" {"i32x4.extend_high_i16x8_u", TokenType::Unary, Opcode::I32X4ExtendHighI16X8U}, {""}, -#line 367 "src/lexer-keywords.txt" +#line 369 "src/lexer-keywords.txt" {"i32x4.extend_high_i16x8_s", TokenType::Unary, Opcode::I32X4ExtendHighI16X8S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 170 "src/lexer-keywords.txt" +#line 172 "src/lexer-keywords.txt" {"f64x2.pmax", TokenType::Binary, Opcode::F64X2PMax}, {""}, {""}, {""}, {""}, -#line 612 "src/lexer-keywords.txt" +#line 617 "src/lexer-keywords.txt" {"v128.load16_lane", TokenType::SimdLoadLane, Opcode::V128Load16Lane}, {""}, {""}, -#line 619 "src/lexer-keywords.txt" +#line 624 "src/lexer-keywords.txt" {"i8x16.shuffle", TokenType::SimdShuffleOp, Opcode::I8X16Shuffle}, {""}, {""}, -#line 359 "src/lexer-keywords.txt" +#line 361 "src/lexer-keywords.txt" {"i32x4.extadd_pairwise_i16x8_u", TokenType::Unary, Opcode::I32X4ExtaddPairwiseI16X8U}, {""}, -#line 358 "src/lexer-keywords.txt" +#line 360 "src/lexer-keywords.txt" {"i32x4.extadd_pairwise_i16x8_s", TokenType::Unary, Opcode::I32X4ExtaddPairwiseI16X8S}, {""}, {""}, #line 25 "src/lexer-keywords.txt" {"assert_malformed", TokenType::AssertMalformed}, {""}, {""}, {""}, -#line 51 "src/lexer-keywords.txt" +#line 53 "src/lexer-keywords.txt" {"elem.drop", TokenType::ElemDrop, Opcode::ElemDrop}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 493 "src/lexer-keywords.txt" +#line 495 "src/lexer-keywords.txt" {"i64x2.extmul_low_i32x4_u", TokenType::Binary, Opcode::I64X2ExtmulLowI32X4U}, -#line 524 "src/lexer-keywords.txt" +#line 526 "src/lexer-keywords.txt" {"i8x16.relaxed_swizzle", TokenType::Binary, Opcode::I8X16RelaxedSwizzle}, -#line 491 "src/lexer-keywords.txt" +#line 493 "src/lexer-keywords.txt" {"i64x2.extmul_low_i32x4_s", TokenType::Binary, Opcode::I64X2ExtmulLowI32X4S}, {""}, {""}, {""}, {""}, {""}, -#line 370 "src/lexer-keywords.txt" +#line 372 "src/lexer-keywords.txt" {"i32x4.extend_low_i16x8_u", TokenType::Unary, Opcode::I32X4ExtendLowI16X8U}, {""}, -#line 369 "src/lexer-keywords.txt" +#line 371 "src/lexer-keywords.txt" {"i32x4.extend_low_i16x8_s", TokenType::Unary, Opcode::I32X4ExtendLowI16X8S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 363 "src/lexer-keywords.txt" +#line 365 "src/lexer-keywords.txt" {"i32x4.extmul_high_i16x8_u", TokenType::Binary, Opcode::I32X4ExtmulHighI16X8U}, {""}, -#line 361 "src/lexer-keywords.txt" +#line 363 "src/lexer-keywords.txt" {"i32x4.extmul_high_i16x8_s", TokenType::Binary, Opcode::I32X4ExtmulHighI16X8S}, {""}, -#line 147 "src/lexer-keywords.txt" +#line 149 "src/lexer-keywords.txt" {"f64.reinterpret_i64", TokenType::Convert, Opcode::F64ReinterpretI64}, {""}, {""}, -#line 321 "src/lexer-keywords.txt" +#line 323 "src/lexer-keywords.txt" {"i32.wrap_i64", TokenType::Convert, Opcode::I32WrapI64}, {""}, {""}, {""}, {""}, -#line 620 "src/lexer-keywords.txt" +#line 625 "src/lexer-keywords.txt" {"i8x16.swizzle", TokenType::Binary, Opcode::I8X16Swizzle}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 132 "src/lexer-keywords.txt" +#line 134 "src/lexer-keywords.txt" {"f64.div", TokenType::Binary, Opcode::F64Div}, -#line 71 "src/lexer-keywords.txt" +#line 73 "src/lexer-keywords.txt" {"f32.div", TokenType::Binary, Opcode::F32Div}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 233 "src/lexer-keywords.txt" +#line 235 "src/lexer-keywords.txt" {"i16x8.sub", TokenType::Binary, Opcode::I16X8Sub}, {""}, {""}, -#line 193 "src/lexer-keywords.txt" +#line 195 "src/lexer-keywords.txt" {"i16x8.abs", TokenType::Unary, Opcode::I16X8Abs}, {""}, -#line 561 "src/lexer-keywords.txt" +#line 564 "src/lexer-keywords.txt" {"pagesize", TokenType::PageSize}, {""}, {""}, -#line 95 "src/lexer-keywords.txt" +#line 97 "src/lexer-keywords.txt" {"f32x4.convert_i32x4_u", TokenType::Unary, Opcode::F32X4ConvertI32X4U}, {""}, -#line 94 "src/lexer-keywords.txt" +#line 96 "src/lexer-keywords.txt" {"f32x4.convert_i32x4_s", TokenType::Unary, Opcode::F32X4ConvertI32X4S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 362 "src/lexer-keywords.txt" +#line 364 "src/lexer-keywords.txt" {"i32x4.extmul_low_i16x8_u", TokenType::Binary, Opcode::I32X4ExtmulLowI16X8U}, {""}, -#line 360 "src/lexer-keywords.txt" +#line 362 "src/lexer-keywords.txt" {"i32x4.extmul_low_i16x8_s", TokenType::Binary, Opcode::I32X4ExtmulLowI16X8S}, {""}, {""}, -#line 131 "src/lexer-keywords.txt" +#line 133 "src/lexer-keywords.txt" {"f64.copysign", TokenType::Binary, Opcode::F64Copysign}, -#line 69 "src/lexer-keywords.txt" +#line 71 "src/lexer-keywords.txt" {"f32.copysign", TokenType::Binary, Opcode::F32Copysign}, -#line 533 "src/lexer-keywords.txt" +#line 535 "src/lexer-keywords.txt" {"i8x16.sub", TokenType::Binary, Opcode::I8X16Sub}, {""}, {""}, -#line 497 "src/lexer-keywords.txt" +#line 499 "src/lexer-keywords.txt" {"i8x16.abs", TokenType::Unary, Opcode::I8X16Abs}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 225 "src/lexer-keywords.txt" +#line 227 "src/lexer-keywords.txt" {"i16x8.relaxed_q15mulr_s", TokenType::Binary, Opcode::I16X8RelaxedQ15mulrS}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 200 "src/lexer-keywords.txt" +#line 202 "src/lexer-keywords.txt" {"i16x8.relaxed_dot_i8x16_i7x16_s", TokenType::Binary, Opcode::I16X8DotI8X16I7X16S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 443 "src/lexer-keywords.txt" +#line 445 "src/lexer-keywords.txt" {"i64.reinterpret_f64", TokenType::Convert, Opcode::I64ReinterpretF64}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 244 "src/lexer-keywords.txt" +#line 246 "src/lexer-keywords.txt" {"i16x8.extend_low_i8x16_u", TokenType::Unary, Opcode::I16X8ExtendLowI8X16U}, {""}, -#line 243 "src/lexer-keywords.txt" +#line 245 "src/lexer-keywords.txt" {"i16x8.extend_low_i8x16_s", TokenType::Unary, Opcode::I16X8ExtendLowI8X16S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, @@ -1591,36 +1601,36 @@ Perfect_Hash::InWordSet (const char *str, size_t len) {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 220 "src/lexer-keywords.txt" +#line 222 "src/lexer-keywords.txt" {"i16x8.narrow_i32x4_u", TokenType::Binary, Opcode::I16X8NarrowI32X4U}, {""}, -#line 219 "src/lexer-keywords.txt" +#line 221 "src/lexer-keywords.txt" {"i16x8.narrow_i32x4_s", TokenType::Binary, Opcode::I16X8NarrowI32X4S}, {""}, {""}, -#line 238 "src/lexer-keywords.txt" +#line 240 "src/lexer-keywords.txt" {"i16x8.extmul_low_i8x16_u", TokenType::Binary, Opcode::I16X8ExtmulLowI8X16U}, {""}, -#line 236 "src/lexer-keywords.txt" +#line 238 "src/lexer-keywords.txt" {"i16x8.extmul_low_i8x16_s", TokenType::Binary, Opcode::I16X8ExtmulLowI8X16S}, {""}, {""}, {""}, -#line 548 "src/lexer-keywords.txt" +#line 550 "src/lexer-keywords.txt" {"memory.copy", TokenType::MemoryCopy, Opcode::MemoryCopy}, {""}, -#line 479 "src/lexer-keywords.txt" +#line 481 "src/lexer-keywords.txt" {"i64x2.bitmask", TokenType::Unary, Opcode::I64X2Bitmask}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 157 "src/lexer-keywords.txt" +#line 159 "src/lexer-keywords.txt" {"f64x2.eq", TokenType::Compare, Opcode::F64X2Eq}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 470 "src/lexer-keywords.txt" +#line 472 "src/lexer-keywords.txt" {"i64x2.eq", TokenType::Binary, Opcode::I64X2Eq}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 483 "src/lexer-keywords.txt" +#line 485 "src/lexer-keywords.txt" {"i64x2.extend_high_i32x4_u", TokenType::Unary, Opcode::I64X2ExtendHighI32X4U}, {""}, -#line 481 "src/lexer-keywords.txt" +#line 483 "src/lexer-keywords.txt" {"i64x2.extend_high_i32x4_s", TokenType::Unary, Opcode::I64X2ExtendHighI32X4S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, #line 20 "src/lexer-keywords.txt" @@ -1629,28 +1639,28 @@ Perfect_Hash::InWordSet (const char *str, size_t len) #line 27 "src/lexer-keywords.txt" {"assert_trap", TokenType::AssertTrap}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 596 "src/lexer-keywords.txt" +#line 601 "src/lexer-keywords.txt" {"v128.bitselect", TokenType::Ternary, Opcode::V128BitSelect}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 150 "src/lexer-keywords.txt" +#line 152 "src/lexer-keywords.txt" {"f64.sub", TokenType::Binary, Opcode::F64Sub}, -#line 88 "src/lexer-keywords.txt" +#line 90 "src/lexer-keywords.txt" {"f32.sub", TokenType::Binary, Opcode::F32Sub}, {""}, {""}, {""}, {""}, {""}, -#line 455 "src/lexer-keywords.txt" +#line 457 "src/lexer-keywords.txt" {"i64.sub", TokenType::Binary, Opcode::I64Sub}, -#line 311 "src/lexer-keywords.txt" +#line 313 "src/lexer-keywords.txt" {"i32.sub", TokenType::Binary, Opcode::I32Sub}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 146 "src/lexer-keywords.txt" +#line 148 "src/lexer-keywords.txt" {"f64.promote_f32", TokenType::Convert, Opcode::F64PromoteF32}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 494 "src/lexer-keywords.txt" +#line 496 "src/lexer-keywords.txt" {"i64x2.extmul_high_i32x4_u", TokenType::Binary, Opcode::I64X2ExtmulHighI32X4U}, {""}, -#line 492 "src/lexer-keywords.txt" +#line 494 "src/lexer-keywords.txt" {"i64x2.extmul_high_i32x4_s", TokenType::Binary, Opcode::I64X2ExtmulHighI32X4S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, @@ -1664,7 +1674,7 @@ Perfect_Hash::InWordSet (const char *str, size_t len) #line 22 "src/lexer-keywords.txt" {"assert_exception", TokenType::AssertException}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 199 "src/lexer-keywords.txt" +#line 201 "src/lexer-keywords.txt" {"i16x8.bitmask", TokenType::Unary, Opcode::I16X8Bitmask}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, @@ -1672,26 +1682,26 @@ Perfect_Hash::InWordSet (const char *str, size_t len) #line 23 "src/lexer-keywords.txt" {"assert_exhaustion", TokenType::AssertExhaustion}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 503 "src/lexer-keywords.txt" +#line 505 "src/lexer-keywords.txt" {"i8x16.bitmask", TokenType::Unary, Opcode::I8X16Bitmask}, {""}, -#line 201 "src/lexer-keywords.txt" +#line 203 "src/lexer-keywords.txt" {"i16x8.eq", TokenType::Compare, Opcode::I16X8Eq}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 504 "src/lexer-keywords.txt" +#line 506 "src/lexer-keywords.txt" {"i8x16.eq", TokenType::Compare, Opcode::I8X16Eq}, {""}, {""}, {""}, {""}, {""}, -#line 547 "src/lexer-keywords.txt" +#line 549 "src/lexer-keywords.txt" {"memory.atomic.wait64", TokenType::AtomicWait, Opcode::MemoryAtomicWait64}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 85 "src/lexer-keywords.txt" +#line 87 "src/lexer-keywords.txt" {"f32.reinterpret_i32", TokenType::Convert, Opcode::F32ReinterpretI32}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, @@ -1701,63 +1711,63 @@ Perfect_Hash::InWordSet (const char *str, size_t len) {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 405 "src/lexer-keywords.txt" +#line 407 "src/lexer-keywords.txt" {"i64.atomic.rmw.sub", TokenType::AtomicRmw, Opcode::I64AtomicRmwSub}, -#line 268 "src/lexer-keywords.txt" +#line 270 "src/lexer-keywords.txt" {"i32.atomic.rmw.sub", TokenType::AtomicRmw, Opcode::I32AtomicRmwSub}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 545 "src/lexer-keywords.txt" +#line 547 "src/lexer-keywords.txt" {"memory.atomic.notify", TokenType::AtomicNotify, Opcode::MemoryAtomicNotify}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 242 "src/lexer-keywords.txt" +#line 244 "src/lexer-keywords.txt" {"i16x8.extend_high_i8x16_u", TokenType::Unary, Opcode::I16X8ExtendHighI8X16U}, {""}, -#line 241 "src/lexer-keywords.txt" +#line 243 "src/lexer-keywords.txt" {"i16x8.extend_high_i8x16_s", TokenType::Unary, Opcode::I16X8ExtendHighI8X16S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, #line 28 "src/lexer-keywords.txt" {"assert_unlinkable", TokenType::AssertUnlinkable}, {""}, {""}, -#line 300 "src/lexer-keywords.txt" +#line 302 "src/lexer-keywords.txt" {"i32.reinterpret_f32", TokenType::Convert, Opcode::I32ReinterpretF32}, {""}, {""}, {""}, {""}, -#line 182 "src/lexer-keywords.txt" +#line 184 "src/lexer-keywords.txt" {"f64x2.convert_low_i32x4_u", TokenType::Unary, Opcode::F64X2ConvertLowI32X4U}, {""}, -#line 181 "src/lexer-keywords.txt" +#line 183 "src/lexer-keywords.txt" {"f64x2.convert_low_i32x4_s", TokenType::Unary, Opcode::F64X2ConvertLowI32X4S}, {""}, -#line 235 "src/lexer-keywords.txt" +#line 237 "src/lexer-keywords.txt" {"i16x8.extadd_pairwise_i8x16_u", TokenType::Unary, Opcode::I16X8ExtaddPairwiseI8X16U}, {""}, -#line 234 "src/lexer-keywords.txt" +#line 236 "src/lexer-keywords.txt" {"i16x8.extadd_pairwise_i8x16_s", TokenType::Unary, Opcode::I16X8ExtaddPairwiseI8X16S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 546 "src/lexer-keywords.txt" +#line 548 "src/lexer-keywords.txt" {"memory.atomic.wait32", TokenType::AtomicWait, Opcode::MemoryAtomicWait32}, {""}, {""}, {""}, {""}, {""}, -#line 520 "src/lexer-keywords.txt" +#line 522 "src/lexer-keywords.txt" {"i8x16.narrow_i16x8_u", TokenType::Binary, Opcode::I8X16NarrowI16X8U}, {""}, -#line 519 "src/lexer-keywords.txt" +#line 521 "src/lexer-keywords.txt" {"i8x16.narrow_i16x8_s", TokenType::Binary, Opcode::I8X16NarrowI16X8S}, {""}, -#line 222 "src/lexer-keywords.txt" +#line 224 "src/lexer-keywords.txt" {"i16x8.q15mulr_sat_s", TokenType::Binary, Opcode::I16X8Q15mulrSatS}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, #line 29 "src/lexer-keywords.txt" {"atomic.fence", TokenType::AtomicFence, Opcode::AtomicFence}, {""}, {""}, {""}, {""}, -#line 239 "src/lexer-keywords.txt" +#line 241 "src/lexer-keywords.txt" {"i16x8.extmul_high_i8x16_u", TokenType::Binary, Opcode::I16X8ExtmulHighI8X16U}, {""}, -#line 237 "src/lexer-keywords.txt" +#line 239 "src/lexer-keywords.txt" {"i16x8.extmul_high_i8x16_s", TokenType::Binary, Opcode::I16X8ExtmulHighI8X16S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, @@ -1775,7 +1785,7 @@ Perfect_Hash::InWordSet (const char *str, size_t len) {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 183 "src/lexer-keywords.txt" +#line 185 "src/lexer-keywords.txt" {"f64x2.promote_low_f32x4", TokenType::Unary, Opcode::F64X2PromoteLowF32X4} }; diff --git a/src/resolve-names.cc b/src/resolve-names.cc index 67fc44e923..d24f2f5c37 100644 --- a/src/resolve-names.cc +++ b/src/resolve-names.cc @@ -40,13 +40,17 @@ class NameResolver : public ExprVisitor::DelegateNop { Result EndBlockExpr(BlockExpr*) override; Result OnBrExpr(BrExpr*) override; Result OnBrIfExpr(BrIfExpr*) override; + Result OnBrOnNonNullExpr(BrOnNonNullExpr*) override; + Result OnBrOnNullExpr(BrOnNullExpr*) override; Result OnBrTableExpr(BrTableExpr*) override; Result OnCallExpr(CallExpr*) override; Result OnCallIndirectExpr(CallIndirectExpr*) override; + Result OnCallRefExpr(CallRefExpr*) override; Result OnCatchExpr(TryExpr*, Catch*) override; Result OnDelegateExpr(TryExpr*) override; Result OnReturnCallExpr(ReturnCallExpr*) override; Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr*) override; + Result OnReturnCallRefExpr(ReturnCallRefExpr*) override; Result OnGlobalGetExpr(GlobalGetExpr*) override; Result OnGlobalSetExpr(GlobalSetExpr*) override; Result BeginIfExpr(IfExpr*) override; @@ -72,6 +76,7 @@ class NameResolver : public ExprVisitor::DelegateNop { Result OnTableSizeExpr(TableSizeExpr*) override; Result OnTableFillExpr(TableFillExpr*) override; Result OnRefFuncExpr(RefFuncExpr*) override; + Result OnRefNullExpr(RefNullExpr*) override; Result OnStoreExpr(StoreExpr*) override; Result BeginTryExpr(TryExpr*) override; Result EndTryExpr(TryExpr*) override; @@ -275,6 +280,16 @@ Result NameResolver::OnBrIfExpr(BrIfExpr* expr) { return Result::Ok; } +Result NameResolver::OnBrOnNonNullExpr(BrOnNonNullExpr* expr) { + ResolveLabelVar(&expr->var); + return Result::Ok; +} + +Result NameResolver::OnBrOnNullExpr(BrOnNullExpr* expr) { + ResolveLabelVar(&expr->var); + return Result::Ok; +} + Result NameResolver::OnBrTableExpr(BrTableExpr* expr) { for (Var& target : expr->targets) ResolveLabelVar(&target); @@ -295,6 +310,11 @@ Result NameResolver::OnCallIndirectExpr(CallIndirectExpr* expr) { return Result::Ok; } +Result NameResolver::OnCallRefExpr(CallRefExpr* expr) { + ResolveFuncTypeVar(&expr->sig_type); + return Result::Ok; +} + Result NameResolver::OnReturnCallExpr(ReturnCallExpr* expr) { ResolveFuncVar(&expr->var); return Result::Ok; @@ -308,6 +328,11 @@ Result NameResolver::OnReturnCallIndirectExpr(ReturnCallIndirectExpr* expr) { return Result::Ok; } +Result NameResolver::OnReturnCallRefExpr(ReturnCallRefExpr* expr) { + ResolveFuncTypeVar(&expr->sig_type); + return Result::Ok; +} + Result NameResolver::OnGlobalGetExpr(GlobalGetExpr* expr) { ResolveGlobalVar(&expr->var); return Result::Ok; @@ -428,6 +453,11 @@ Result NameResolver::OnRefFuncExpr(RefFuncExpr* expr) { return Result::Ok; } +Result NameResolver::OnRefNullExpr(RefNullExpr* expr) { + ResolveFuncTypeVar(&expr->type); + return Result::Ok; +} + Result NameResolver::OnStoreExpr(StoreExpr* expr) { ResolveMemoryVar(&expr->memidx); return Result::Ok; diff --git a/src/shared-validator.cc b/src/shared-validator.cc index ad3a85393b..5fac43aa72 100644 --- a/src/shared-validator.cc +++ b/src/shared-validator.cc @@ -27,7 +27,9 @@ TypeVector SharedValidator::ToTypeVector(Index count, const Type* types) { } SharedValidator::SharedValidator(Errors* errors, const ValidateOptions& options) - : options_(options), errors_(errors), typechecker_(options.features) { + : options_(options), + errors_(errors), + typechecker_(options.features, func_types_) { typechecker_.set_error_callback( [this](const char* msg) { OnTypecheckerError(msg); }); } @@ -56,6 +58,14 @@ Result SharedValidator::OnFuncType(const Location& loc, "multiple result values are not supported without " "multi-value enabled."); } + if (options_.features.reference_types_enabled()) { + for (Index i = 0; i < param_count; i++) { + result |= CheckReferenceType(loc, param_types[i], "params"); + } + for (Index i = 0; i < result_count; i++) { + result |= CheckReferenceType(loc, result_types[i], "results"); + } + } func_types_.emplace( num_types_++, FuncType{ToTypeVector(param_count, param_types), @@ -76,21 +86,6 @@ Result SharedValidator::OnArrayType(const Location&, TypeMut field) { return Result::Ok; } -Result SharedValidator::EndTypeSection() { - Result result = Result::Ok; - - for (auto func_type : func_types_) { - for (auto type : func_type.second.params) { - result |= CheckReferenceType(Location(), type, "params"); - } - - for (auto type : func_type.second.results) { - result |= CheckReferenceType(Location(), type, "results"); - } - } - return result; -} - Result SharedValidator::OnFunction(const Location& loc, Var sig_var) { Result result = Result::Ok; FuncType type; @@ -129,6 +124,8 @@ Result SharedValidator::OnTable(const Location& loc, Type elem_type, const Limits& limits) { Result result = Result::Ok; + // Must be checked by parser or binary reader. + assert(elem_type.IsRef()); if (tables_.size() > 0 && !options_.features.reference_types_enabled()) { result |= PrintError(loc, "only one table allowed"); } @@ -141,8 +138,13 @@ Result SharedValidator::OnTable(const Location& loc, !options_.features.reference_types_enabled()) { result |= PrintError(loc, "tables must have funcref type"); } - if (!elem_type.IsRef()) { - result |= PrintError(loc, "tables must have reference types"); + + result |= CheckReferenceType(loc, elem_type, "tables"); + + // TODO: support table initializers + if (elem_type.IsRef() && !elem_type.IsNullableRef()) { + result |= + PrintError(loc, "currently non-nullable references are not supported"); } tables_.push_back(TableType{elem_type, limits}); @@ -196,6 +198,7 @@ Result SharedValidator::OnGlobalImport(const Location& loc, Result SharedValidator::OnGlobal(const Location& loc, Type type, bool mutable_) { + CHECK_RESULT(CheckReferenceType(loc, type, "globals")); globals_.push_back(GlobalType{type, mutable_}); return Result::Ok; } @@ -204,7 +207,7 @@ Result SharedValidator::CheckType(const Location& loc, Type actual, Type expected, const char* desc) { - if (Failed(TypeChecker::CheckType(actual, expected))) { + if (Failed(typechecker_.CheckType(actual, expected))) { PrintError(loc, "type mismatch at %s. got %s, expected %s", desc, actual.GetName().c_str(), expected.GetName().c_str()); return Result::Error; @@ -315,6 +318,17 @@ Result SharedValidator::OnElemSegmentElemType(const Location& loc, // it is active. result |= CheckType(loc, elem_type, elem.table_type, "elem segment"); } + + if (elem_type.IsReferenceWithIndex()) { + Index index = elem_type.GetReferenceIndex(); + auto iter = func_types_.find(index); + + if (iter == func_types_.end()) { + result |= + PrintError(loc, "reference %" PRIindex " is out of range", index); + } + } + elem.element = elem_type; return result; } @@ -458,6 +472,16 @@ Result SharedValidator::CheckBlockSignature(const Location& loc, *out_param_types = func_type.params; *out_result_types = func_type.results; } else { + if (sig_type.IsReferenceWithIndex()) { + Index index = sig_type.GetReferenceIndex(); + auto iter = func_types_.find(index); + + if (iter == func_types_.end()) { + result |= + PrintError(loc, "reference %" PRIindex " is out of range", index); + } + } + out_param_types->clear(); *out_result_types = sig_type.GetInlineVector(); } @@ -470,6 +494,33 @@ Index SharedValidator::GetFunctionTypeIndex(Index func_index) const { return funcs_[func_index].type_index; } +void SharedValidator::SaveLocalRefs() { + if (!local_ref_is_set_.empty()) { + Label* label; + typechecker_.GetLabel(0, &label); + label->local_ref_is_set_ = local_ref_is_set_; + } +} + +void SharedValidator::RestoreLocalRefs(Result result) { + if (!local_ref_is_set_.empty()) { + if (Succeeded(result)) { + Label* label; + typechecker_.GetLabel(0, &label); + assert(local_ref_is_set_.size() == label->local_ref_is_set_.size()); + local_ref_is_set_ = label->local_ref_is_set_; + } else { + IgnoreLocalRefs(); + } + } +} + +void SharedValidator::IgnoreLocalRefs() { + if (!local_ref_is_set_.empty()) { + std::fill(local_ref_is_set_.begin(), local_ref_is_set_.end(), true); + } +} + Result SharedValidator::BeginInitExpr(const Location& loc, Type type) { expr_loc_ = loc; in_init_expr_ = true; @@ -513,7 +564,17 @@ Result SharedValidator::OnLocalDecl(const Location& loc, CHECK_RESULT(CheckReferenceType(loc, type, "locals")); - locals_.push_back(LocalDecl{type, GetLocalCount() + count}); + Index local_count = GetLocalCount(); + + if (type.IsNonNullableRef()) { + for (Index i = 0; i < count; i++) { + local_refs_map_[local_count + i] = + LocalReferenceMap{type, static_cast(local_ref_is_set_.size())}; + local_ref_is_set_.push_back(false); + } + } + + locals_.push_back(LocalDecl{type, local_count + count}); return Result::Ok; } @@ -708,12 +769,14 @@ Result SharedValidator::OnBlock(const Location& loc, Type sig_type) { result |= CheckBlockSignature(loc, Opcode::Block, sig_type, ¶m_types, &result_types); result |= typechecker_.OnBlock(param_types, result_types); + SaveLocalRefs(); return result; } Result SharedValidator::OnBr(const Location& loc, Var depth) { Result result = CheckInstr(Opcode::Br, loc); result |= typechecker_.OnBr(depth.index()); + IgnoreLocalRefs(); return result; } @@ -723,6 +786,18 @@ Result SharedValidator::OnBrIf(const Location& loc, Var depth) { return result; } +Result SharedValidator::OnBrOnNonNull(const Location& loc, Var depth) { + Result result = CheckInstr(Opcode::BrOnNonNull, loc); + result |= typechecker_.OnBrOnNonNull(depth.index()); + return result; +} + +Result SharedValidator::OnBrOnNull(const Location& loc, Var depth) { + Result result = CheckInstr(Opcode::BrOnNull, loc); + result |= typechecker_.OnBrOnNull(depth.index()); + return result; +} + Result SharedValidator::BeginBrTable(const Location& loc) { Result result = CheckInstr(Opcode::BrTable, loc); result |= typechecker_.BeginBrTable(); @@ -739,6 +814,7 @@ Result SharedValidator::OnBrTableTarget(const Location& loc, Var depth) { Result SharedValidator::EndBrTable(const Location& loc) { Result result = CheckInstr(Opcode::BrTable, loc); result |= typechecker_.EndBrTable(); + IgnoreLocalRefs(); return result; } @@ -768,20 +844,12 @@ Result SharedValidator::OnCallIndirect(const Location& loc, return result; } -Result SharedValidator::OnCallRef(const Location& loc, - Index* function_type_index) { +Result SharedValidator::OnCallRef(const Location& loc, Var function_type_var) { Result result = CheckInstr(Opcode::CallRef, loc); - Index func_index; - result |= typechecker_.OnIndexedFuncRef(&func_index); - if (Failed(result)) { - return result; - } FuncType func_type; - result |= CheckFuncTypeIndex(Var(func_index, loc), &func_type); + result |= typechecker_.OnCallRef(function_type_var.to_type()); + result |= CheckFuncTypeIndex(function_type_var, &func_type); result |= typechecker_.OnCall(func_type.params, func_type.results); - if (Succeeded(result)) { - *function_type_index = func_index; - } return result; } @@ -797,6 +865,7 @@ Result SharedValidator::OnCatch(const Location& loc, result |= CheckTagIndex(tag_var, &tag_type); result |= typechecker_.OnCatch(tag_type.params); } + RestoreLocalRefs(result); return result; } @@ -851,11 +920,13 @@ Result SharedValidator::OnElse(const Location& loc) { // not the else itself. Result result = Result::Ok; result |= typechecker_.OnElse(); + RestoreLocalRefs(result); return result; } Result SharedValidator::OnEnd(const Location& loc) { Result result = CheckInstr(Opcode::End, loc); + RestoreLocalRefs(result); result |= typechecker_.OnEnd(); return result; } @@ -899,6 +970,7 @@ Result SharedValidator::OnIf(const Location& loc, Type sig_type) { result |= CheckBlockSignature(loc, Opcode::If, sig_type, ¶m_types, &result_types); result |= typechecker_.OnIf(param_types, result_types); + SaveLocalRefs(); return result; } @@ -950,6 +1022,13 @@ Result SharedValidator::OnLocalGet(const Location& loc, Var local_var) { Type type = Type::Any; result |= CheckLocalIndex(local_var, &type); result |= typechecker_.OnLocalGet(type); + if (Succeeded(result) && type.IsNonNullableRef()) { + auto it = local_refs_map_.find(local_var.index()); + if (it != local_refs_map_.end() && + !local_ref_is_set_[it->second.bit_index]) { + return PrintError(local_var.loc, "uninitialized local reference"); + } + } return result; } @@ -959,6 +1038,12 @@ Result SharedValidator::OnLocalSet(const Location& loc, Var local_var) { Type type = Type::Any; result |= CheckLocalIndex(local_var, &type); result |= typechecker_.OnLocalSet(type); + if (Succeeded(result) && type.IsNonNullableRef()) { + auto it = local_refs_map_.find(local_var.index()); + if (it != local_refs_map_.end()) { + local_ref_is_set_[it->second.bit_index] = true; + } + } return result; } @@ -968,6 +1053,12 @@ Result SharedValidator::OnLocalTee(const Location& loc, Var local_var) { Type type = Type::Any; result |= CheckLocalIndex(local_var, &type); result |= typechecker_.OnLocalTee(type); + if (Succeeded(result) && type.IsNonNullableRef()) { + auto it = local_refs_map_.find(local_var.index()); + if (it != local_refs_map_.end()) { + local_ref_is_set_[it->second.bit_index] = true; + } + } return result; } @@ -977,6 +1068,7 @@ Result SharedValidator::OnLoop(const Location& loc, Type sig_type) { result |= CheckBlockSignature(loc, Opcode::Loop, sig_type, ¶m_types, &result_types); result |= typechecker_.OnLoop(param_types, result_types); + SaveLocalRefs(); return result; } @@ -1032,6 +1124,12 @@ Result SharedValidator::OnNop(const Location& loc) { return result; } +Result SharedValidator::OnRefAsNonNull(const Location& loc) { + Result result = CheckInstr(Opcode::Nop, loc); + result |= typechecker_.OnRefAsNonNullExpr(); + return result; +} + Result SharedValidator::OnRefFunc(const Location& loc, Var func_var) { Result result = CheckInstr(Opcode::RefFunc, loc); result |= CheckFuncIndex(func_var); @@ -1044,7 +1142,7 @@ Result SharedValidator::OnRefFunc(const Location& loc, Var func_var) { check_declared_funcs_.push_back(func_var); } Index func_type = GetFunctionTypeIndex(func_var.index()); - result |= typechecker_.OnRefFuncExpr(func_type, in_init_expr_); + result |= typechecker_.OnRefFuncExpr(func_type); } return result; } @@ -1055,8 +1153,25 @@ Result SharedValidator::OnRefIsNull(const Location& loc) { return result; } -Result SharedValidator::OnRefNull(const Location& loc, Type type) { +Result SharedValidator::OnRefNull(const Location& loc, Var func_type_var) { Result result = CheckInstr(Opcode::RefNull, loc); + + Type type = func_type_var.to_type(); + + switch (type) { + case Type::RefNull: + result |= CheckIndex(func_type_var, num_types_, "function type"); + break; + case Type::FuncRef: + case Type::ExnRef: + case Type::ExternRef: + break; + default: + result |= PrintError( + loc, "Only ref, externref, exnref, funcref are allowed for ref.null"); + break; + } + result |= typechecker_.OnRefNullExpr(type); return result; } @@ -1072,6 +1187,7 @@ Result SharedValidator::OnReturnCall(const Location& loc, Var func_var) { FuncType func_type; result |= CheckFuncIndex(func_var, &func_type); result |= typechecker_.OnReturnCall(func_type.params, func_type.results); + IgnoreLocalRefs(); return result; } @@ -1090,12 +1206,24 @@ Result SharedValidator::OnReturnCallIndirect(const Location& loc, } result |= typechecker_.OnReturnCallIndirect(func_type.params, func_type.results); + IgnoreLocalRefs(); + return result; +} + +Result SharedValidator::OnReturnCallRef(const Location& loc, + Var function_type_var) { + Result result = CheckInstr(Opcode::ReturnCallRef, loc); + FuncType func_type; + result |= typechecker_.OnReturnCallRef(function_type_var.to_type()); + result |= CheckFuncTypeIndex(function_type_var, &func_type); + result |= typechecker_.OnReturnCall(func_type.params, func_type.results); return result; } Result SharedValidator::OnReturn(const Location& loc) { Result result = CheckInstr(Opcode::Return, loc); result |= typechecker_.OnReturn(); + IgnoreLocalRefs(); return result; } @@ -1103,6 +1231,19 @@ Result SharedValidator::OnSelect(const Location& loc, Index result_count, Type* result_types) { Result result = CheckInstr(Opcode::Select, loc); + + for (Index i = 0; i < result_count; i++) { + if (result_types[i].IsReferenceWithIndex()) { + Index index = result_types[i].GetReferenceIndex(); + auto iter = func_types_.find(index); + + if (iter == func_types_.end()) { + result |= + PrintError(loc, "reference %" PRIindex " is out of range", index); + } + } + } + if (result_count > 1) { result |= PrintError(loc, "invalid arity in select instruction: %" PRIindex ".", @@ -1265,6 +1406,7 @@ Result SharedValidator::OnTry(const Location& loc, Type sig_type) { result |= CheckBlockSignature(loc, Opcode::Try, sig_type, ¶m_types, &result_types); result |= typechecker_.OnTry(param_types, result_types); + SaveLocalRefs(); return result; } @@ -1311,6 +1453,7 @@ Result SharedValidator::OnUnary(const Location& loc, Opcode opcode) { Result SharedValidator::OnUnreachable(const Location& loc) { Result result = CheckInstr(Opcode::Unreachable, loc); result |= typechecker_.OnUnreachable(); + IgnoreLocalRefs(); return result; } diff --git a/src/type-checker.cc b/src/type-checker.cc index 90dda71e42..c13e3ad4de 100644 --- a/src/type-checker.cc +++ b/src/type-checker.cc @@ -33,7 +33,7 @@ std::string TypesToString(const TypeVector& types, Type ty = types[i]; // NOTE: Reference (and GetName) is also used by (e.g.) objdump, which does // not apply validation. do this here so as to not break that. - if (ty == Type::Reference && ty.GetReferenceIndex() == kInvalidIndex) { + if (ty.IsReferenceWithIndex() && ty.GetReferenceIndex() == kInvalidIndex) { result += "reference"; } else { result += types[i].GetName(); @@ -228,15 +228,100 @@ Result TypeChecker::CheckTypeStackEnd(const char* desc) { return result; } +static bool CompareTypeVector( + const std::map& func_types, + const TypeVector& left, + const TypeVector& right) { + size_t size = left.size(); + + if (size != right.size()) { + return false; + } + + for (size_t i = 0; i < size; i++) { + const Type& left_type = left[i]; + const Type& right_type = right[i]; + + if (left_type != right_type) { + if (!left_type.IsReferenceWithIndex() || + left_type != static_cast(right_type)) { + return false; + } + + const TypeChecker::FuncType& left_func_type = + func_types.at(left_type.GetReferenceIndex()); + const TypeChecker::FuncType& right_func_type = + func_types.at(right_type.GetReferenceIndex()); + + // Circular references were checked during validation. + if (!CompareTypeVector(func_types, left_func_type.params, + right_func_type.params) || + !CompareTypeVector(func_types, left_func_type.results, + right_func_type.results)) { + return false; + } + } + } + + return true; +} + Result TypeChecker::CheckType(Type actual, Type expected) { if (expected == Type::Any || actual == Type::Any) { return Result::Ok; } - if (actual != expected) { + Type::Enum actual_type = actual; + Type::Enum expected_type = expected; + + if (actual_type == expected_type) { + switch (actual_type) { + case Type::ExternRef: + case Type::FuncRef: + return (expected.IsNullableNonTypedRef() || + !actual.IsNullableNonTypedRef()) + ? Result::Ok + : Result::Error; + + case Type::Reference: + case Type::Ref: + case Type::RefNull: + break; + + default: + return Result::Ok; + } + } + + if (!actual.IsReferenceWithIndex()) { return Result::Error; } - return Result::Ok; + + if (expected_type == Type::FuncRef) { + return (actual == Type::Ref || expected.IsNullableNonTypedRef()) + ? Result::Ok + : Result::Error; + } + + if (!expected.IsReferenceWithIndex()) { + return Result::Error; + } + + if (expected_type == Type::Ref && actual_type == Type::RefNull) { + return Result::Error; + } + + FuncType& actual_func_type = func_types_[actual.GetReferenceIndex()]; + FuncType& expected_func_type = func_types_[expected.GetReferenceIndex()]; + + if (CompareTypeVector(func_types_, actual_func_type.params, + expected_func_type.params) && + CompareTypeVector(func_types_, actual_func_type.results, + expected_func_type.results)) { + return Result::Ok; + } + + return Result::Error; } Result TypeChecker::CheckTypes(const TypeVector& actual, @@ -319,6 +404,21 @@ Result TypeChecker::PopAndCheck3Types(Type expected1, return result; } +Result TypeChecker::PopAndCheckReference(Type* actual, const char* desc) { + *actual = Type::Any; + Result result = PeekType(0, actual); + + // Type::Any is a valid value for dead code, and replacing + // it with anything might break the syntax checker. + if (*actual != Type::Any && !actual->IsRef()) { + result = Result::Error; + } + + PrintStackIfFailed(result, desc, Type::FuncRef); + result |= DropTypes(1); + return result; +} + // Some paramater types depend on the memory being used. // For example load/store operands, or memory.fill operands. static Type GetMemoryParam(Type param, const Limits* limits) { @@ -469,6 +569,49 @@ Result TypeChecker::OnBrIf(Index depth) { return result; } +static Type convertRefNullToRef(Type type) { + if (type == Type::ExternRef || type == Type::FuncRef) { + return Type(type, Type::ReferenceNonNull); + } + + assert(type.IsReferenceWithIndex()); + return Type(Type::Ref, type.GetReferenceIndex()); +} + +Result TypeChecker::OnBrOnNonNull(Index depth) { + Type actual; + CHECK_RESULT(PopAndCheckReference(&actual, "br_on_non_null")); + if (actual != Type::Any) { + PushType(convertRefNullToRef(actual)); + } + + Label* label; + CHECK_RESULT(GetLabel(depth, &label)); + Result result = PopAndCheckSignature(label->br_types(), "br_on_non_null"); + PushTypes(label->br_types()); + + if (actual != Type::Any) { + result |= DropTypes(1); + } + return result; +} + +Result TypeChecker::OnBrOnNull(Index depth) { + Type actual; + CHECK_RESULT(PopAndCheckReference(&actual, "br_on_null")); + + Label* label; + CHECK_RESULT(GetLabel(depth, &label)); + Result result = PopAndCheckSignature(label->br_types(), "br_on_null"); + PushTypes(label->br_types()); + + if (actual != Type::Any) { + actual = convertRefNullToRef(actual); + } + PushType(actual); + return result; +} + Result TypeChecker::BeginBrTable() { br_table_sig_ = nullptr; return PopAndCheck1Type(Type::I32, "br_table"); @@ -515,17 +658,8 @@ Result TypeChecker::OnCallIndirect(const TypeVector& param_types, return result; } -Result TypeChecker::OnIndexedFuncRef(Index* out_index) { - Type type; - Result result = PeekType(0, &type); - if (!type.IsReferenceWithIndex()) { - type = Type(Type::Reference, kInvalidIndex); - } - result |= PopAndCheck1Type(type, "call_ref"); - if (Succeeded(result)) { - *out_index = type.GetReferenceIndex(); - } - return result; +Result TypeChecker::OnCallRef(Type type) { + return PopAndCheck1Type(type, "call_ref"); } Result TypeChecker::OnReturnCall(const TypeVector& param_types, @@ -554,6 +688,10 @@ Result TypeChecker::OnReturnCallIndirect(const TypeVector& param_types, return result; } +Result TypeChecker::OnReturnCallRef(Type type) { + return PopAndCheck1Type(type, "return_call_ref"); +} + Result TypeChecker::OnCompare(Opcode opcode) { return CheckOpcode2(opcode); } @@ -785,18 +923,18 @@ Result TypeChecker::OnTableFill(Type elem_type, const Limits& limits) { "table.fill"); } -Result TypeChecker::OnRefFuncExpr(Index func_type, bool force_generic_funcref) { - /* - * In a const expression, treat ref.func as producing a generic funcref. - * This avoids having to implement funcref subtyping (for now) and matches - * the previous behavior where SharedValidator::OnElemSegmentElemExpr_RefFunc - * examined only the validity of the function index. - */ - if (features_.function_references_enabled() && !force_generic_funcref) { - PushType(Type(Type::Reference, func_type)); - } else { - PushType(Type::FuncRef); +Result TypeChecker::OnRefAsNonNullExpr() { + Type actual; + CHECK_RESULT(PopAndCheckReference(&actual, "ref.as_non_null")); + if (actual != Type::Any) { + actual = convertRefNullToRef(actual); } + PushType(actual); + return Result::Ok; +} + +Result TypeChecker::OnRefFuncExpr(Index func_type) { + PushType(Type(Type::Ref, func_type)); return Result::Ok; } diff --git a/src/validator.cc b/src/validator.cc index fcb4e69be1..76b8f31c40 100644 --- a/src/validator.cc +++ b/src/validator.cc @@ -98,6 +98,8 @@ class Validator : public ExprVisitor::Delegate { Result EndBlockExpr(BlockExpr*) override; Result OnBrExpr(BrExpr*) override; Result OnBrIfExpr(BrIfExpr*) override; + Result OnBrOnNonNullExpr(BrOnNonNullExpr*) override; + Result OnBrOnNullExpr(BrOnNullExpr*) override; Result OnBrTableExpr(BrTableExpr*) override; Result OnCallExpr(CallExpr*) override; Result OnCallIndirectExpr(CallIndirectExpr*) override; @@ -132,6 +134,7 @@ class Validator : public ExprVisitor::Delegate { Result OnTableGrowExpr(TableGrowExpr*) override; Result OnTableSizeExpr(TableSizeExpr*) override; Result OnTableFillExpr(TableFillExpr*) override; + Result OnRefAsNonNullExpr(RefAsNonNullExpr*) override; Result OnRefFuncExpr(RefFuncExpr*) override; Result OnRefNullExpr(RefNullExpr*) override; Result OnRefIsNullExpr(RefIsNullExpr*) override; @@ -139,6 +142,7 @@ class Validator : public ExprVisitor::Delegate { Result OnReturnExpr(ReturnExpr*) override; Result OnReturnCallExpr(ReturnCallExpr*) override; Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr*) override; + Result OnReturnCallRefExpr(ReturnCallRefExpr*) override; Result OnSelectExpr(SelectExpr*) override; Result OnStoreExpr(StoreExpr*) override; Result OnUnaryExpr(UnaryExpr*) override; @@ -189,13 +193,47 @@ void ScriptValidator::PrintError(const Location* loc, const char* format, ...) { errors_->emplace_back(ErrorLevel::Error, *loc, buffer); } +static Result CheckType(Type actual, Type expected) { + // Script validator (strict) type compare + if (expected == Type::Any || actual == Type::Any) { + return Result::Ok; + } + + Type::Enum actual_type = actual; + Type::Enum expected_type = expected; + + if (actual_type == expected_type) { + switch (actual_type) { + case Type::ExternRef: + case Type::FuncRef: + return (expected.IsNullableNonTypedRef() || + !actual.IsNullableNonTypedRef()) + ? Result::Ok + : Result::Error; + + case Type::Reference: + case Type::Ref: + case Type::RefNull: + if (actual == expected) { + return Result::Ok; + } + break; + + default: + return Result::Ok; + } + } + + return Result::Error; +} + void ScriptValidator::CheckTypeIndex(const Location* loc, Type actual, Type expected, const char* desc, Index index, const char* index_kind) { - if (Failed(TypeChecker::CheckType(actual, expected))) { + if (Failed(CheckType(actual, expected))) { PrintError(loc, "type mismatch for %s %" PRIindex " of %s. got %s, expected %s", index_kind, index, desc, actual.GetName().c_str(), @@ -299,6 +337,16 @@ Result Validator::OnBrIfExpr(BrIfExpr* expr) { return Result::Ok; } +Result Validator::OnBrOnNonNullExpr(BrOnNonNullExpr* expr) { + result_ |= validator_.OnBrOnNonNull(expr->loc, expr->var); + return Result::Ok; +} + +Result Validator::OnBrOnNullExpr(BrOnNullExpr* expr) { + result_ |= validator_.OnBrOnNull(expr->loc, expr->var); + return Result::Ok; +} + Result Validator::OnBrTableExpr(BrTableExpr* expr) { result_ |= validator_.BeginBrTable(expr->loc); for (const Var& var : expr->targets) { @@ -321,14 +369,8 @@ Result Validator::OnCallIndirectExpr(CallIndirectExpr* expr) { } Result Validator::OnCallRefExpr(CallRefExpr* expr) { - Index function_type_index; - result_ |= validator_.OnCallRef(expr->loc, &function_type_index); - if (Succeeded(result_)) { - expr->function_type_index = Var{function_type_index, expr->loc}; - return Result::Ok; - } - - return Result::Error; + result_ |= validator_.OnCallRef(expr->loc, expr->sig_type); + return Result::Ok; } Result Validator::OnCodeMetadataExpr(CodeMetadataExpr* expr) { @@ -488,6 +530,11 @@ Result Validator::OnTableFillExpr(TableFillExpr* expr) { return Result::Ok; } +Result Validator::OnRefAsNonNullExpr(RefAsNonNullExpr* expr) { + result_ |= validator_.OnRefAsNonNull(expr->loc); + return Result::Ok; +} + Result Validator::OnRefFuncExpr(RefFuncExpr* expr) { result_ |= validator_.OnRefFunc(expr->loc, expr->var); return Result::Ok; @@ -524,6 +571,11 @@ Result Validator::OnReturnCallIndirectExpr(ReturnCallIndirectExpr* expr) { return Result::Ok; } +Result Validator::OnReturnCallRefExpr(ReturnCallRefExpr* expr) { + result_ |= validator_.OnReturnCallRef(expr->loc, expr->sig_type); + return Result::Ok; +} + Result Validator::OnSelectExpr(SelectExpr* expr) { result_ |= validator_.OnSelect(expr->loc, expr->result_type.size(), expr->result_type.data()); @@ -736,8 +788,6 @@ Result Validator::CheckModule() { } } - result_ |= validator_.EndTypeSection(); - // Import section. for (const ModuleField& field : module->fields) { if (auto* f = dyn_cast(&field)) { diff --git a/src/wast-parser.cc b/src/wast-parser.cc index b452697bfa..ed0b155125 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -157,10 +157,13 @@ bool IsPlainInstr(TokenType token_type) { case TokenType::Select: case TokenType::Br: case TokenType::BrIf: + case TokenType::BrOnNonNull: + case TokenType::BrOnNull: case TokenType::BrTable: case TokenType::Return: case TokenType::ReturnCall: case TokenType::ReturnCallIndirect: + case TokenType::ReturnCallRef: case TokenType::Call: case TokenType::CallIndirect: case TokenType::CallRef: @@ -193,6 +196,7 @@ bool IsPlainInstr(TokenType token_type) { case TokenType::Throw: case TokenType::ThrowRef: case TokenType::Rethrow: + case TokenType::RefAsNonNull: case TokenType::RefFunc: case TokenType::RefNull: case TokenType::RefIsNull: @@ -542,11 +546,6 @@ void AppendInlineExportFields(Module* module, module->AppendFields(fields); } -bool IsIndexLikelyType(Index index) { - // TODO: Incorrect values can be misinterpreted by the parser. - return index >= static_cast(Type::Void); -} - } // End of anonymous namespace WastParser::WastParser(WastLexer* lexer, @@ -883,25 +882,47 @@ bool WastParser::ParseElemExprVarListOpt(ExprListVector* out_list) { return !out_list->empty(); } +Result WastParser::ParseRefDeclaration(Var* out_type) { + EXPECT(Lpar); + EXPECT(Ref); + + Type::Enum opt_type = Type::Reference; + + if (options_->features.function_references_enabled()) { + opt_type = Type::Ref; + + if (Match(TokenType::Null)) { + opt_type = Type::RefNull; + } + } + + if (PeekMatch(TokenType::Func) || PeekMatch(TokenType::Extern)) { + TokenType token = Consume().token_type(); + out_type->set_opt_type(token == TokenType::Func ? Type::FuncRef + : Type::ExternRef); + out_type->set_index(opt_type == Type::Ref ? Type::ReferenceNonNull + : Type::ReferenceOrNull); + } else { + CHECK_RESULT(ParseVar(out_type)); + out_type->set_opt_type(opt_type); + } + + EXPECT(Rpar); + return Result::Ok; +} + Result WastParser::ParseValueType(Var* out_type) { WABT_TRACE(ParseValueType); - const bool is_ref_type = PeekMatchRefType(); - const bool is_value_type = PeekMatch(TokenType::ValueType); + if (PeekMatchRefType()) { + return ParseRefDeclaration(out_type); + } - if (!is_value_type && !is_ref_type) { + if (!PeekMatch(TokenType::ValueType)) { return ErrorExpected( {"i32", "i64", "f32", "f64", "v128", "externref", "exnref", "funcref"}); } - if (is_ref_type) { - EXPECT(Lpar); - EXPECT(Ref); - CHECK_RESULT(ParseVar(out_type)); - EXPECT(Rpar); - return Result::Ok; - } - Token token = Consume(); Type type = token.type(); bool is_enabled; @@ -926,7 +947,8 @@ Result WastParser::ParseValueType(Var* out_type) { return Result::Error; } - *out_type = Var(type, GetLocation()); + *out_type = Var(0, GetLocation()); + out_type->set_opt_type(type); return Result::Ok; } @@ -942,25 +964,29 @@ Result WastParser::ParseValueTypeList(TypeVector* out_type_list, CHECK_RESULT(ParseValueType(&type)); if (type.is_index()) { - if (IsIndexLikelyType(type.index())) { - out_type_list->push_back(Type(type.index())); - } else { - type_vars->push_back(ReferenceVar(out_type_list->size(), type)); - out_type_list->push_back(Type(Type::Reference, type.index())); - } + out_type_list->push_back(type.to_type()); } else { assert(type.is_name()); assert(options_->features.function_references_enabled()); type_vars->push_back(ReferenceVar(out_type_list->size(), type)); - out_type_list->push_back(Type(Type::Reference, kInvalidIndex)); + out_type_list->push_back(Type(type.opt_type(), kInvalidIndex)); } } return Result::Ok; } -Result WastParser::ParseRefKind(Type* out_type) { +Result WastParser::ParseRefKind(Var* out_type) { WABT_TRACE(ParseRefKind); + + if (options_->features.function_references_enabled() && + (PeekMatch(TokenType::Nat) || PeekMatch(TokenType::Var))) { + CHECK_RESULT(ParseVar(out_type)); + + out_type->set_opt_type(Type::RefNull); + return Result::Ok; + } + if (!IsTokenTypeRefKind(Peek())) { return ErrorExpected({"func", "extern", "exn"}); } @@ -976,42 +1002,55 @@ Result WastParser::ParseRefKind(Type* out_type) { return Result::Error; } - *out_type = type; + *out_type = Var(0, GetLocation()); + out_type->set_opt_type(type); return Result::Ok; } -Result WastParser::ParseRefType(Type* out_type) { +Result WastParser::ParseRefType(Var* out_type) { WABT_TRACE(ParseRefType); + if (PeekMatchRefType()) { + return ParseRefDeclaration(out_type); + } + if (!PeekMatch(TokenType::ValueType)) { return ErrorExpected({"funcref", "externref", "exnref"}); } Token token = Consume(); Type type = token.type(); - if (type == Type::ExternRef && - !options_->features.reference_types_enabled()) { + if (!CheckRefType(type)) { Error(token.loc, "value type not allowed: %s", type.GetName().c_str()); return Result::Error; } - *out_type = type; + *out_type = Var(0, GetLocation()); + out_type->set_opt_type(type); return Result::Ok; } -bool WastParser::ParseRefTypeOpt(Type* out_type) { +bool WastParser::ParseRefTypeOpt(Var* out_type, Result& result) { WABT_TRACE(ParseRefTypeOpt); + + if (PeekMatchRefType()) { + result |= ParseRefDeclaration(out_type); + return true; + } + if (!PeekMatch(TokenType::ValueType)) { return false; } Token token = Consume(); Type type = token.type(); - if (type == Type::ExternRef && - !options_->features.reference_types_enabled()) { - return false; + if (!CheckRefType(type)) { + Error(token.loc, "value type not allowed: %s", type.GetName().c_str()); + result = Result::Error; + return true; } - *out_type = type; + *out_type = Var(0, GetLocation()); + out_type->set_opt_type(type); return true; } @@ -1298,10 +1337,34 @@ bool WastParser::PeekIsCustom() { tokens_.front().text() == "custom"; } -Result WastParser::ResolveRefTypes(const Module& module, - TypeVector* types, - ReferenceVars* ref_vars, - Errors* errors) { +Result WastParser::ResolveTargetRefType(const Module& module, + Type* type, + const Var& var, + Errors* errors) { + assert(type->IsReferenceWithIndex() && !var.is_index()); + + if (type->GetReferenceIndex() != kInvalidIndex) { + // Resolved earlier. + return Result::Ok; + } + + Index type_index = module.type_bindings.FindIndex(var.name()); + + if (type_index != kInvalidIndex) { + *type = Type(static_cast(*type), type_index); + return Result::Ok; + } + + errors->emplace_back( + ErrorLevel::Error, var.loc, + StringPrintf("undefined reference type name %s", var.name().c_str())); + return Result::Ok; +} + +Result WastParser::ResolveTargetTypeVector(const Module& module, + TypeVector* types, + ReferenceVars* ref_vars, + Errors* errors) { Result result = Result::Ok; for (auto& ref_var : *ref_vars) { @@ -1312,40 +1375,11 @@ Result WastParser::ResolveRefTypes(const Module& module, continue; } - assert(index < types->size()); - Type type = (*types)[index]; ref_var.index = kInvalidIndex; - assert(type.IsReferenceWithIndex()); - - if (ref_var.var.is_index()) { - if (type.GetReferenceIndex() >= module.types.size()) { - errors->emplace_back( - ErrorLevel::Error, ref_var.var.loc, - StringPrintf("reference type out of range: %d (max: %d)", - static_cast(type.GetReferenceIndex()), - static_cast(module.types.size()))); - result = Result::Error; - } - continue; - } - - if (type.GetReferenceIndex() != kInvalidIndex) { - // Resolved earlier. - continue; - } - - Index type_index = module.type_bindings.FindIndex(ref_var.var.name()); - - if (type_index == kInvalidIndex) { - errors->emplace_back(ErrorLevel::Error, ref_var.var.loc, - StringPrintf("undefined reference type name %s", - ref_var.var.name().c_str())); - result = Result::Error; - continue; - } - - (*types)[index] = Type(static_cast(type), type_index); + assert(index < types->size()); + result |= ResolveTargetRefType(module, types->data() + index, ref_var.var, + errors); } return Result::Ok; @@ -1355,7 +1389,8 @@ Result WastParser::ParseModuleFieldList(Module* module) { WABT_TRACE(ParseModuleFieldList); // Reset module-specific state. - resolve_types_.clear(); + resolve_ref_types_.clear(); + resolve_type_vectors_.clear(); resolve_funcs_.clear(); while (IsModuleField(PeekPair()) || PeekIsCustom()) { @@ -1371,12 +1406,17 @@ Result WastParser::ParseModuleFieldList(Module* module) { // Module parsing is completed, type names can be resolved now. Result result = Result::Ok; - for (auto it : resolve_types_) { - result |= ResolveRefTypes(*module, it.target_types, &it.vars, errors_); + for (auto it : resolve_ref_types_) { + result |= ResolveTargetRefType(*module, it.target_type, it.var, errors_); + } + + for (auto it : resolve_type_vectors_) { + result |= + ResolveTargetTypeVector(*module, it.target_vector, &it.vars, errors_); } for (auto it : resolve_funcs_) { - result |= ResolveRefTypes(*module, &it.types, &it.vars, errors_); + result |= ResolveTargetTypeVector(*module, &it.types, &it.vars, errors_); it.target_func->local_types.Set(it.types); } @@ -1491,7 +1531,11 @@ Result WastParser::ParseElemModuleField(Module* module) { CHECK_RESULT(ParseOffsetExpr(&field->elem_segment.offset)); } - if (ParseRefTypeOpt(&field->elem_segment.elem_type)) { + Result result; + Var elem_type; + if (ParseRefTypeOpt(&elem_type, result)) { + CHECK_RESULT(result); + VarToType(elem_type, &field->elem_segment.elem_type); ParseElemExprListOpt(&field->elem_segment.elem_exprs); } else { field->elem_segment.elem_type = Type::FuncRef; @@ -1586,7 +1630,7 @@ Result WastParser::ParseFuncModuleField(Module* module) { CHECK_RESULT(ParseTypeUseOpt(&func.decl)); CHECK_RESULT(ParseFuncSignature(&func.decl.sig, &func.bindings)); - ResolveFuncs references(&func); + ResolveFunc references(&func); CHECK_RESULT(ParseBoundValueTypeList(TokenType::Local, &references.types, &func.bindings, &references.vars, @@ -1659,13 +1703,13 @@ Result WastParser::ParseField(Field* field) { field->mutable_ = true; Var type; CHECK_RESULT(ParseValueType(&type)); - field->type = Type(type.index()); + field->type = Type(type.opt_type()); EXPECT(Rpar); } else { field->mutable_ = false; Var type; CHECK_RESULT(ParseValueType(&type)); - field->type = Type(type.index()); + field->type = Type(type.opt_type()); } return Result::Ok; }; @@ -1758,7 +1802,9 @@ Result WastParser::ParseImportModuleField(Module* module) { auto import = std::make_unique(name); CHECK_RESULT(ParseLimitsIndex(&import->table.elem_limits)); CHECK_RESULT(ParseLimits(&import->table.elem_limits)); - CHECK_RESULT(ParseRefType(&import->table.elem_type)); + Var elem_type; + CHECK_RESULT(ParseRefType(&elem_type)); + VarToType(elem_type, &import->table.elem_type); EXPECT(Rpar); field = std::make_unique(std::move(import), loc); break; @@ -1908,7 +1954,9 @@ Result WastParser::ParseTableModuleField(Module* module) { CHECK_RESULT(ParseInlineImport(import.get())); CHECK_RESULT(ParseLimitsIndex(&import->table.elem_limits)); CHECK_RESULT(ParseLimits(&import->table.elem_limits)); - CHECK_RESULT(ParseRefType(&import->table.elem_type)); + Var elem_type; + CHECK_RESULT(ParseRefType(&elem_type)); + VarToType(elem_type, &import->table.elem_type); auto field = std::make_unique(std::move(import), GetLocation()); module->AppendField(std::move(field)); @@ -1916,8 +1964,8 @@ Result WastParser::ParseTableModuleField(Module* module) { auto field = std::make_unique(loc, name); auto& table = field->table; CHECK_RESULT(ParseLimitsIndex(&table.elem_limits)); - if (PeekMatch(TokenType::ValueType)) { - Type elem_type; + if (PeekMatch(TokenType::ValueType) || PeekMatchRefType()) { + Var elem_type; CHECK_RESULT(ParseRefType(&elem_type)); EXPECT(Lpar); @@ -1929,7 +1977,7 @@ Result WastParser::ParseTableModuleField(Module* module) { auto offset = table.elem_limits.is_64 ? Const::I64(0) : Const::I32(0); elem_segment.offset.push_back(std::make_unique(offset)); elem_segment.offset.back().loc = loc; - elem_segment.elem_type = elem_type; + VarToType(elem_type, &elem_segment.elem_type); // Syntax is either an optional list of var (legacy), or a non-empty list // of elem expr. ExprList elem_expr; @@ -1945,12 +1993,14 @@ Result WastParser::ParseTableModuleField(Module* module) { table.elem_limits.initial = elem_segment.elem_exprs.size(); table.elem_limits.max = elem_segment.elem_exprs.size(); table.elem_limits.has_max = true; - table.elem_type = elem_type; + VarToType(elem_type, &table.elem_type); module->AppendField(std::move(field)); module->AppendField(std::move(elem_segment_field)); } else { CHECK_RESULT(ParseLimits(&table.elem_limits)); - CHECK_RESULT(ParseRefType(&table.elem_type)); + Var elem_type; + CHECK_RESULT(ParseRefType(&elem_type)); + VarToType(elem_type, &table.elem_type); module->AppendField(std::move(field)); } } @@ -2020,19 +2070,19 @@ Result WastParser::ParseFuncSignature(FuncSignature* sig, BindingHash* param_bindings) { WABT_TRACE(ParseFuncSignature); - ResolveTypes param_references(&sig->param_types); - ResolveTypes result_references(&sig->result_types); + ResolveTypeVector param_references(&sig->param_types); + ResolveTypeVector result_references(&sig->result_types); CHECK_RESULT(ParseBoundValueTypeList(TokenType::Param, &sig->param_types, param_bindings, ¶m_references.vars)); CHECK_RESULT(ParseResultList(&sig->result_types, &result_references.vars)); if (!param_references.vars.empty()) { - resolve_types_.push_back(param_references); + resolve_type_vectors_.push_back(param_references); } if (!result_references.vars.empty()) { - resolve_types_.push_back(result_references); + resolve_type_vectors_.push_back(result_references); } return Result::Ok; @@ -2041,19 +2091,19 @@ Result WastParser::ParseFuncSignature(FuncSignature* sig, Result WastParser::ParseUnboundFuncSignature(FuncSignature* sig) { WABT_TRACE(ParseUnboundFuncSignature); - ResolveTypes param_references(&sig->param_types); - ResolveTypes result_references(&sig->result_types); + ResolveTypeVector param_references(&sig->param_types); + ResolveTypeVector result_references(&sig->result_types); CHECK_RESULT(ParseUnboundValueTypeList(TokenType::Param, &sig->param_types, ¶m_references.vars)); CHECK_RESULT(ParseResultList(&sig->result_types, &result_references.vars)); if (!param_references.vars.empty()) { - resolve_types_.push_back(param_references); + resolve_type_vectors_.push_back(param_references); } if (!result_references.vars.empty()) { - resolve_types_.push_back(result_references); + resolve_type_vectors_.push_back(result_references); } return Result::Ok; @@ -2075,17 +2125,12 @@ Result WastParser::ParseBoundValueTypeList(TokenType token, bindings->emplace(name, Binding(loc, binding_index_offset + types->size())); if (type.is_index()) { - if (IsIndexLikelyType(type.index())) { - types->push_back(Type(type.index())); - } else { - type_vars->push_back(ReferenceVar(types->size(), type)); - types->push_back(Type(Type::Reference, type.index())); - } + types->push_back(type.to_type()); } else { assert(type.is_name()); assert(options_->features.function_references_enabled()); type_vars->push_back(ReferenceVar(types->size(), type)); - types->push_back(Type(Type::Reference, kInvalidIndex)); + types->push_back(Type(type.opt_type(), kInvalidIndex)); } } else { CHECK_RESULT(ParseValueTypeList(types, type_vars)); @@ -2341,12 +2386,13 @@ Result WastParser::ParsePlainInstr(std::unique_ptr* out_expr) { case TokenType::Select: { Consume(); - TypeVector result; + auto expr = std::make_unique(loc); + ResolveTypeVector result_type(&expr->result_type); if (options_->features.reference_types_enabled() && PeekMatchLpar(TokenType::Result)) { - CHECK_RESULT(ParseResultList(&result, nullptr)); + CHECK_RESULT(ParseResultList(&expr->result_type, &result_type.vars)); } - out_expr->reset(new SelectExpr(result, loc)); + *out_expr = std::move(expr); break; } @@ -2360,6 +2406,16 @@ Result WastParser::ParsePlainInstr(std::unique_ptr* out_expr) { CHECK_RESULT(ParsePlainInstrVar(loc, out_expr)); break; + case TokenType::BrOnNonNull: + Consume(); + CHECK_RESULT(ParsePlainInstrVar(loc, out_expr)); + break; + + case TokenType::BrOnNull: + Consume(); + CHECK_RESULT(ParsePlainInstrVar(loc, out_expr)); + break; + case TokenType::BrTable: { Consume(); auto expr = std::make_unique(loc); @@ -2392,7 +2448,10 @@ Result WastParser::ParsePlainInstr(std::unique_ptr* out_expr) { case TokenType::CallRef: { ErrorUnlessOpcodeEnabled(Consume()); - out_expr->reset(new CallRefExpr(loc)); + auto expr = std::make_unique(loc); + CHECK_RESULT(ParseVar(&expr->sig_type)); + expr->sig_type.set_opt_type(Type::RefNull); + *out_expr = std::move(expr); break; } @@ -2411,6 +2470,15 @@ Result WastParser::ParsePlainInstr(std::unique_ptr* out_expr) { break; } + case TokenType::ReturnCallRef: { + ErrorUnlessOpcodeEnabled(Consume()); + auto expr = std::make_unique(loc); + CHECK_RESULT(ParseVar(&expr->sig_type)); + expr->sig_type.set_opt_type(Type::RefNull); + *out_expr = std::move(expr); + break; + } + case TokenType::LocalGet: Consume(); CHECK_RESULT(ParsePlainInstrVar(loc, out_expr)); @@ -2581,6 +2649,11 @@ Result WastParser::ParsePlainInstr(std::unique_ptr* out_expr) { break; } + case TokenType::RefAsNonNull: + ErrorUnlessOpcodeEnabled(Consume()); + out_expr->reset(new RefAsNonNullExpr(Opcode::RefAsNonNull, loc)); + break; + case TokenType::RefFunc: ErrorUnlessOpcodeEnabled(Consume()); CHECK_RESULT(ParsePlainInstrVar(loc, out_expr)); @@ -2588,7 +2661,7 @@ Result WastParser::ParsePlainInstr(std::unique_ptr* out_expr) { case TokenType::RefNull: { ErrorUnlessOpcodeEnabled(Consume()); - Type type; + Var type; CHECK_RESULT(ParseRefKind(&type)); out_expr->reset(new RefNullExpr(type, loc)); break; @@ -3009,7 +3082,11 @@ Result WastParser::ParseExternref(Const* const_) { uint64_t ref_bits; Result result = ParseInt64(sv, &ref_bits, ParseIntType::UnsignedOnly); - const_->set_externref(static_cast(ref_bits)); + if (ref_bits != 0 && options_->features.function_references_enabled()) { + const_->set_extern(static_cast(ref_bits)); + } else { + const_->set_externref(static_cast(ref_bits)); + } if (Failed(result)) { Error(const_->loc, "invalid literal \"" PRIstringview "\"", @@ -3034,11 +3111,11 @@ Result WastParser::ParseConstList(ConstVector* consts, ConstType type) { break; case TokenType::RefNull: { auto token = Consume(); - Type type; + Var type; CHECK_RESULT(ParseRefKind(&type)); ErrorUnlessOpcodeEnabled(token); const_.loc = GetLocation(); - const_.set_null(type); + const_.set_null(type.opt_type()); break; } case TokenType::RefFunc: { @@ -3437,13 +3514,13 @@ Result WastParser::ParseGlobalType(Global* global) { global->mutable_ = true; Var type; CHECK_RESULT(ParseValueType(&type)); - global->type = Type(type.index()); + VarToType(type, &global->type); CHECK_RESULT(ErrorIfLpar({"i32", "i64", "f32", "f64"})); EXPECT(Rpar); } else { Var type; CHECK_RESULT(ParseValueType(&type)); - global->type = Type(type.index()); + VarToType(type, &global->type); } return Result::Ok; @@ -3886,6 +3963,30 @@ bool WastParser::HasError() const { }); } +bool WastParser::CheckRefType(Type::Enum type) { + switch (type) { + case Type::FuncRef: + return true; + case Type::ExternRef: + return options_->features.reference_types_enabled(); + case Type::ExnRef: + return options_->features.exceptions_enabled(); + default: + assert(!Type::EnumIsNonTypedRef(type)); + return false; + } +} + +void WastParser::VarToType(const Var& var, Type* type) { + if (!Type::EnumIsReferenceWithIndex(var.opt_type()) || var.is_index()) { + *type = var.to_type(); + return; + } + + *type = Type(var.opt_type(), kInvalidIndex); + resolve_ref_types_.push_back(ResolveRefType(type, var)); +} + void WastParser::TokenQueue::push_back(Token t) { assert(!tokens[!i]); tokens[!i] = t; diff --git a/src/wat-writer.cc b/src/wat-writer.cc index f19e3c3c86..5da55e8535 100644 --- a/src/wat-writer.cc +++ b/src/wat-writer.cc @@ -554,6 +554,8 @@ class WatWriter::ExprVisitorDelegate : public ExprVisitor::Delegate { Result EndBlockExpr(BlockExpr*) override; Result OnBrExpr(BrExpr*) override; Result OnBrIfExpr(BrIfExpr*) override; + Result OnBrOnNonNullExpr(BrOnNonNullExpr*) override; + Result OnBrOnNullExpr(BrOnNullExpr*) override; Result OnBrTableExpr(BrTableExpr*) override; Result OnCallExpr(CallExpr*) override; Result OnCallIndirectExpr(CallIndirectExpr*) override; @@ -588,6 +590,7 @@ class WatWriter::ExprVisitorDelegate : public ExprVisitor::Delegate { Result OnTableGrowExpr(TableGrowExpr*) override; Result OnTableSizeExpr(TableSizeExpr*) override; Result OnTableFillExpr(TableFillExpr*) override; + Result OnRefAsNonNullExpr(RefAsNonNullExpr*) override; Result OnRefFuncExpr(RefFuncExpr*) override; Result OnRefNullExpr(RefNullExpr*) override; Result OnRefIsNullExpr(RefIsNullExpr*) override; @@ -595,6 +598,7 @@ class WatWriter::ExprVisitorDelegate : public ExprVisitor::Delegate { Result OnReturnExpr(ReturnExpr*) override; Result OnReturnCallExpr(ReturnCallExpr*) override; Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr*) override; + Result OnReturnCallRefExpr(ReturnCallRefExpr*) override; Result OnSelectExpr(SelectExpr*) override; Result OnStoreExpr(StoreExpr*) override; Result OnUnaryExpr(UnaryExpr*) override; @@ -655,6 +659,19 @@ Result WatWriter::ExprVisitorDelegate::OnBrIfExpr(BrIfExpr* expr) { return Result::Ok; } +Result WatWriter::ExprVisitorDelegate::OnBrOnNonNullExpr( + BrOnNonNullExpr* expr) { + writer_->WritePutsSpace(Opcode::BrOnNonNull_Opcode.GetName()); + writer_->WriteBrVar(expr->var, NextChar::Newline); + return Result::Ok; +} + +Result WatWriter::ExprVisitorDelegate::OnBrOnNullExpr(BrOnNullExpr* expr) { + writer_->WritePutsSpace(Opcode::BrOnNull_Opcode.GetName()); + writer_->WriteBrVar(expr->var, NextChar::Newline); + return Result::Ok; +} + Result WatWriter::ExprVisitorDelegate::OnBrTableExpr(BrTableExpr* expr) { writer_->WritePutsSpace(Opcode::BrTable_Opcode.GetName()); for (const Var& var : expr->targets) { @@ -686,6 +703,7 @@ Result WatWriter::ExprVisitorDelegate::OnCallIndirectExpr( Result WatWriter::ExprVisitorDelegate::OnCallRefExpr(CallRefExpr* expr) { writer_->WritePutsSpace(Opcode::CallRef_Opcode.GetName()); + writer_->WriteVar(expr->sig_type, NextChar::Newline); return Result::Ok; } @@ -882,6 +900,12 @@ Result WatWriter::ExprVisitorDelegate::OnTableFillExpr(TableFillExpr* expr) { return Result::Ok; } +Result WatWriter::ExprVisitorDelegate::OnRefAsNonNullExpr( + RefAsNonNullExpr* expr) { + writer_->WritePutsNewline(Opcode::RefAsNonNull_Opcode.GetName()); + return Result::Ok; +} + Result WatWriter::ExprVisitorDelegate::OnRefFuncExpr(RefFuncExpr* expr) { writer_->WritePutsSpace(Opcode::RefFunc_Opcode.GetName()); writer_->WriteVar(expr->var, NextChar::Newline); @@ -890,7 +914,12 @@ Result WatWriter::ExprVisitorDelegate::OnRefFuncExpr(RefFuncExpr* expr) { Result WatWriter::ExprVisitorDelegate::OnRefNullExpr(RefNullExpr* expr) { writer_->WritePutsSpace(Opcode::RefNull_Opcode.GetName()); - writer_->WriteRefKind(expr->type, NextChar::Newline); + if (expr->type.opt_type() != Type::RefNull) { + assert(!Type(expr->type.opt_type()).IsReferenceWithIndex()); + writer_->WriteRefKind(expr->type.opt_type(), NextChar::Newline); + } else { + writer_->WriteVar(expr->type, NextChar::Newline); + } return Result::Ok; } @@ -928,6 +957,13 @@ Result WatWriter::ExprVisitorDelegate::OnReturnCallIndirectExpr( return Result::Ok; } +Result WatWriter::ExprVisitorDelegate::OnReturnCallRefExpr( + ReturnCallRefExpr* expr) { + writer_->WritePutsSpace(Opcode::ReturnCallRef_Opcode.GetName()); + writer_->WriteVar(expr->sig_type, NextChar::Newline); + return Result::Ok; +} + Result WatWriter::ExprVisitorDelegate::OnSelectExpr(SelectExpr* expr) { writer_->WritePutsSpace(Opcode::Select_Opcode.GetName()); if (!expr->result_type.empty()) { diff --git a/test/binary/bad-reference-indicies.txt b/test/binary/bad-reference-indicies.txt index 06d21a7c8d..fea35b8dfe 100644 --- a/test/binary/bad-reference-indicies.txt +++ b/test/binary/bad-reference-indicies.txt @@ -17,10 +17,10 @@ section(CODE) { } } (;; STDERR ;;; -0000000: error: reference 10 is out of range in params -0000000: error: reference 20 is out of range in results +out/test/binary/bad-reference-indicies/bad-reference-indicies.wasm:0000012: error: reference 10 is out of range in params +out/test/binary/bad-reference-indicies/bad-reference-indicies.wasm:0000012: error: reference 20 is out of range in results out/test/binary/bad-reference-indicies/bad-reference-indicies.wasm:000001d: error: reference 30 is out of range in locals -0000000: error: reference 10 is out of range in params -0000000: error: reference 20 is out of range in results +out/test/binary/bad-reference-indicies/bad-reference-indicies.wasm:0000012: error: reference 10 is out of range in params +out/test/binary/bad-reference-indicies/bad-reference-indicies.wasm:0000012: error: reference 20 is out of range in results out/test/binary/bad-reference-indicies/bad-reference-indicies.wasm:000001d: error: reference 30 is out of range in locals ;;; STDERR ;;) diff --git a/test/dump/call_ref.txt b/test/dump/call_ref.txt index 5c24aff479..997440c108 100644 --- a/test/dump/call_ref.txt +++ b/test/dump/call_ref.txt @@ -5,13 +5,14 @@ (func (export "main") (result i32) i32.const 10 ref.func $foo - call_ref + call_ref 0 ) (func $foo (param $x i32) (result i32) (i32.add (local.get $x) (i32.const 19)) ) (elem declare funcref (ref.func $foo)) + (type (func (param i32) (result i32))) ) (;; STDERR ;;; @@ -23,13 +24,13 @@ 000000a: 02 ; num types ; func type 0 000000b: 60 ; func -000000c: 00 ; num params -000000d: 01 ; num results -000000e: 7f ; i32 +000000c: 01 ; num params +000000d: 7f ; i32 +000000e: 01 ; num results +000000f: 7f ; i32 ; func type 1 -000000f: 60 ; func -0000010: 01 ; num params -0000011: 7f ; i32 +0000010: 60 ; func +0000011: 00 ; num params 0000012: 01 ; num results 0000013: 7f ; i32 0000009: 0a ; FIXUP section size @@ -37,8 +38,8 @@ 0000014: 03 ; section code 0000015: 00 ; section size (guess) 0000016: 02 ; num functions -0000017: 00 ; function 0 signature index -0000018: 01 ; function 1 signature index +0000017: 01 ; function 0 signature index +0000018: 00 ; function 1 signature index 0000015: 03 ; FIXUP section size ; section "Export" (7) 0000019: 07 ; section code @@ -71,19 +72,20 @@ 0000031: d2 ; ref.func 0000032: 01 ; function index 0000033: 14 ; call_ref -0000034: 0b ; end -000002d: 07 ; FIXUP func body size +0000034: 00 ; signature index +0000035: 0b ; end +000002d: 08 ; FIXUP func body size ; function body 1 -0000035: 00 ; func body size (guess) -0000036: 00 ; local decl count -0000037: 20 ; local.get -0000038: 00 ; local index -0000039: 41 ; i32.const -000003a: 13 ; i32 literal -000003b: 6a ; i32.add -000003c: 0b ; end -0000035: 07 ; FIXUP func body size -000002b: 11 ; FIXUP section size +0000036: 00 ; func body size (guess) +0000037: 00 ; local decl count +0000038: 20 ; local.get +0000039: 00 ; local index +000003a: 41 ; i32.const +000003b: 13 ; i32 literal +000003c: 6a ; i32.add +000003d: 0b ; end +0000036: 07 ; FIXUP func body size +000002b: 12 ; FIXUP section size ;;; STDERR ;;) (;; STDOUT ;;; @@ -94,11 +96,11 @@ Code Disassembly: 00002e func[0]
: 00002f: 41 0a | i32.const 10 000031: d2 01 | ref.func 1 - 000033: 14 | call_ref - 000034: 0b | end -000036 func[1]: - 000037: 20 00 | local.get 0 - 000039: 41 13 | i32.const 19 - 00003b: 6a | i32.add - 00003c: 0b | end + 000033: 14 00 | call_ref (ref null 0) + 000035: 0b | end +000037 func[1]: + 000038: 20 00 | local.get 0 + 00003a: 41 13 | i32.const 19 + 00003c: 6a | i32.add + 00003d: 0b | end ;;; STDOUT ;;) diff --git a/test/dump/typed-func-ref-signature.txt b/test/dump/typed-func-ref-signature.txt index 506affe055..5598f6e02e 100644 --- a/test/dump/typed-func-ref-signature.txt +++ b/test/dump/typed-func-ref-signature.txt @@ -34,19 +34,19 @@ ; func type 3 0000014: 60 ; func 0000015: 01 ; num params -0000016: 6b ; (ref 0) +0000016: 64 ; (ref 0) 0000017: 00 ; (ref 0) 0000018: 00 ; num results ; func type 4 0000019: 60 ; func 000001a: 01 ; num params -000001b: 6b ; (ref 1) +000001b: 64 ; (ref 1) 000001c: 01 ; (ref 1) 000001d: 00 ; num results ; func type 5 000001e: 60 ; func 000001f: 01 ; num params -0000020: 6b ; (ref 2) +0000020: 64 ; (ref 2) 0000021: 02 ; (ref 2) 0000022: 00 ; num results 0000009: 19 ; FIXUP section size diff --git a/test/dump/typed-func-refs-locals.txt b/test/dump/typed-func-refs-locals.txt index cd6363d52b..9a67cec86a 100644 --- a/test/dump/typed-func-refs-locals.txt +++ b/test/dump/typed-func-refs-locals.txt @@ -3,9 +3,9 @@ (module (type $t0 (func)) + (type $t1 (func)) - ;; Self reference - (type $t1 (func (param (ref $t0) (ref $t1) (ref 1)))) + (type $t2 (func (param (ref $t0) (ref $t1) (ref 1)))) (func $f1 (param (ref $t0) (ref 0)) (local (ref $t0) (ref 0) @@ -19,52 +19,56 @@ ; section "Type" (1) 0000008: 01 ; section code 0000009: 00 ; section size (guess) -000000a: 03 ; num types +000000a: 04 ; num types ; func type 0 000000b: 60 ; func 000000c: 00 ; num params 000000d: 00 ; num results ; func type 1 000000e: 60 ; func -000000f: 03 ; num params -0000010: 6b ; (ref 0) -0000011: 00 ; (ref 0) -0000012: 6b ; (ref 1) -0000013: 01 ; (ref 1) -0000014: 6b ; (ref 1) -0000015: 01 ; (ref 1) -0000016: 00 ; num results +000000f: 00 ; num params +0000010: 00 ; num results ; func type 2 -0000017: 60 ; func -0000018: 02 ; num params -0000019: 6b ; (ref 0) -000001a: 00 ; (ref 0) -000001b: 6b ; (ref 0) -000001c: 00 ; (ref 0) -000001d: 00 ; num results -0000009: 14 ; FIXUP section size +0000011: 60 ; func +0000012: 03 ; num params +0000013: 64 ; (ref 0) +0000014: 00 ; (ref 0) +0000015: 64 ; (ref 1) +0000016: 01 ; (ref 1) +0000017: 64 ; (ref 1) +0000018: 01 ; (ref 1) +0000019: 00 ; num results +; func type 3 +000001a: 60 ; func +000001b: 02 ; num params +000001c: 64 ; (ref 0) +000001d: 00 ; (ref 0) +000001e: 64 ; (ref 0) +000001f: 00 ; (ref 0) +0000020: 00 ; num results +0000009: 17 ; FIXUP section size ; section "Function" (3) -000001e: 03 ; section code -000001f: 00 ; section size (guess) -0000020: 01 ; num functions -0000021: 02 ; function 0 signature index -000001f: 02 ; FIXUP section size +0000021: 03 ; section code +0000022: 00 ; section size (guess) +0000023: 01 ; num functions +0000024: 03 ; function 0 signature index +0000022: 02 ; FIXUP section size ; section "Code" (10) -0000022: 0a ; section code -0000023: 00 ; section size (guess) -0000024: 01 ; num functions +0000025: 0a ; section code +0000026: 00 ; section size (guess) +0000027: 01 ; num functions ; function body 0 -0000025: 00 ; func body size (guess) -0000026: 02 ; local decl count -0000027: 02 ; local type count -0000028: 6b ; (ref 0) -0000029: 00 ; (ref 0) +0000028: 00 ; func body size (guess) +0000029: 02 ; local decl count 000002a: 02 ; local type count -000002b: 6b ; (ref 1) -000002c: 01 ; (ref 1) -000002d: 0b ; end -0000025: 08 ; FIXUP func body size -0000023: 0a ; FIXUP section size +000002b: 64 ; (ref 0) +000002c: 00 ; (ref 0) +000002d: 02 ; local type count +000002e: 64 ; (ref 1) +000002f: 01 ; (ref 1) +0000030: 0b ; end +0000028: 08 ; FIXUP func body size +0000026: 0a ; FIXUP section size ;;; STDERR ;;) (;; STDOUT ;;; @@ -72,8 +76,8 @@ typed-func-refs-locals.wasm: file format wasm 0x1 Code Disassembly: -000026 func[0]: - 000027: 02 6b 00 | local[2..3] type=(ref 0) - 00002a: 02 6b 01 | local[4..5] type=(ref 1) - 00002d: 0b | end +000029 func[0]: + 00002a: 02 64 00 | local[2..3] type=(ref 0) + 00002d: 02 64 01 | local[4..5] type=(ref 1) + 000030: 0b | end ;;; STDOUT ;;) diff --git a/test/dump/typed_func_refs_params.txt b/test/dump/typed_func_refs_params.txt index 6bda5d10af..7bbd41f722 100644 --- a/test/dump/typed_func_refs_params.txt +++ b/test/dump/typed_func_refs_params.txt @@ -6,8 +6,8 @@ (func $deriv (param $f (ref $f32-f32)) (param $x f32) (param $delta f32) (result f32) (f32.div - (f32.sub (call_ref (f32.add (local.get $delta) (local.get $x)) (local.get $f)) - (call_ref (local.get $x) (local.get $f)) + (f32.sub (call_ref $f32-f32 (f32.add (local.get $delta) (local.get $x)) (local.get $f)) + (call_ref $f32-f32 (local.get $x) (local.get $f)) ) (local.get $delta) ) @@ -44,7 +44,7 @@ ; func type 1 0000010: 60 ; func 0000011: 03 ; num params -0000012: 6b ; (ref 0) +0000012: 64 ; (ref 0) 0000013: 00 ; (ref 0) 0000014: 7d ; f32 0000015: 7d ; f32 @@ -98,41 +98,43 @@ 000003d: 20 ; local.get 000003e: 00 ; local index 000003f: 14 ; call_ref -0000040: 20 ; local.get -0000041: 01 ; local index -0000042: 20 ; local.get -0000043: 00 ; local index -0000044: 14 ; call_ref -0000045: 93 ; f32.sub -0000046: 20 ; local.get -0000047: 02 ; local index -0000048: 95 ; f32.div -0000049: 0b ; end -0000036: 13 ; FIXUP func body size +0000040: 00 ; signature index +0000041: 20 ; local.get +0000042: 01 ; local index +0000043: 20 ; local.get +0000044: 00 ; local index +0000045: 14 ; call_ref +0000046: 00 ; signature index +0000047: 93 ; f32.sub +0000048: 20 ; local.get +0000049: 02 ; local index +000004a: 95 ; f32.div +000004b: 0b ; end +0000036: 15 ; FIXUP func body size ; function body 1 -000004a: 00 ; func body size (guess) -000004b: 00 ; local decl count -000004c: 20 ; local.get -000004d: 00 ; local index +000004c: 00 ; func body size (guess) +000004d: 00 ; local decl count 000004e: 20 ; local.get 000004f: 00 ; local index -0000050: 94 ; f32.mul -0000051: 0b ; end -000004a: 07 ; FIXUP func body size +0000050: 20 ; local.get +0000051: 00 ; local index +0000052: 94 ; f32.mul +0000053: 0b ; end +000004c: 07 ; FIXUP func body size ; function body 2 -0000052: 00 ; func body size (guess) -0000053: 00 ; local decl count -0000054: d2 ; ref.func -0000055: 01 ; function index -0000056: 43 ; f32.const -0000057: 0000 803f ; f32 literal -000005b: 43 ; f32.const -000005c: 0ad7 233c ; f32 literal -0000060: 10 ; call -0000061: 00 ; function index -0000062: 0b ; end -0000052: 10 ; FIXUP func body size -0000034: 2e ; FIXUP section size +0000054: 00 ; func body size (guess) +0000055: 00 ; local decl count +0000056: d2 ; ref.func +0000057: 01 ; function index +0000058: 43 ; f32.const +0000059: 0000 803f ; f32 literal +000005d: 43 ; f32.const +000005e: 0ad7 233c ; f32 literal +0000062: 10 ; call +0000063: 00 ; function index +0000064: 0b ; end +0000054: 10 ; FIXUP func body size +0000034: 30 ; FIXUP section size ;;; STDERR ;;) (;; STDOUT ;;; @@ -145,23 +147,23 @@ Code Disassembly: 00003a: 20 01 | local.get 1 00003c: 92 | f32.add 00003d: 20 00 | local.get 0 - 00003f: 14 | call_ref - 000040: 20 01 | local.get 1 - 000042: 20 00 | local.get 0 - 000044: 14 | call_ref - 000045: 93 | f32.sub - 000046: 20 02 | local.get 2 - 000048: 95 | f32.div - 000049: 0b | end -00004b func[1]: - 00004c: 20 00 | local.get 0 + 00003f: 14 00 | call_ref (ref null 0) + 000041: 20 01 | local.get 1 + 000043: 20 00 | local.get 0 + 000045: 14 00 | call_ref (ref null 0) + 000047: 93 | f32.sub + 000048: 20 02 | local.get 2 + 00004a: 95 | f32.div + 00004b: 0b | end +00004d func[1]: 00004e: 20 00 | local.get 0 - 000050: 94 | f32.mul - 000051: 0b | end -000053 func[2]
: - 000054: d2 01 | ref.func 1 - 000056: 43 00 00 80 3f | f32.const 0x1p+0 - 00005b: 43 0a d7 23 3c | f32.const 0x1.47ae14p-7 - 000060: 10 00 | call 0 - 000062: 0b | end + 000050: 20 00 | local.get 0 + 000052: 94 | f32.mul + 000053: 0b | end +000055 func[2]
: + 000056: d2 01 | ref.func 1 + 000058: 43 00 00 80 3f | f32.const 0x1p+0 + 00005d: 43 0a d7 23 3c | f32.const 0x1.47ae14p-7 + 000062: 10 00 | call 0 + 000064: 0b | end ;;; STDOUT ;;) diff --git a/test/dump/typed_func_refs_results.txt b/test/dump/typed_func_refs_results.txt index 5acffc39ae..81ff524039 100644 --- a/test/dump/typed_func_refs_results.txt +++ b/test/dump/typed_func_refs_results.txt @@ -33,7 +33,7 @@ ) (func (export "main") (result f32) - (call_ref + (call_ref $f32-f32 (f32.const 2.0) (call $choice (ref.func $square) (ref.func $double) (i32.const 1)) ) @@ -58,13 +58,13 @@ ; func type 1 0000010: 60 ; func 0000011: 03 ; num params -0000012: 6b ; (ref 0) +0000012: 64 ; (ref 0) 0000013: 00 ; (ref 0) -0000014: 6b ; (ref 0) +0000014: 64 ; (ref 0) 0000015: 00 ; (ref 0) 0000016: 7f ; i32 0000017: 01 ; num results -0000018: 6b ; (ref 0) +0000018: 64 ; (ref 0) 0000019: 00 ; (ref 0) ; func type 2 000001a: 60 ; func @@ -114,7 +114,7 @@ 000003f: 01 ; i32 literal 0000040: 46 ; i32.eq 0000041: 04 ; if -0000042: 6b ; (ref 0) +0000042: 64 ; (ref 0) 0000043: 00 ; (ref 0) 0000044: 20 ; local.get 0000045: 00 ; local index @@ -158,9 +158,10 @@ 0000068: 10 ; call 0000069: 00 ; function index 000006a: 14 ; call_ref -000006b: 0b ; end -000005b: 10 ; FIXUP func body size -0000038: 33 ; FIXUP section size +000006b: 00 ; signature index +000006c: 0b ; end +000005b: 11 ; FIXUP func body size +0000038: 34 ; FIXUP section size ;;; STDERR ;;) (;; STDOUT ;;; @@ -172,7 +173,7 @@ Code Disassembly: 00003c: 20 02 | local.get 2 00003e: 41 01 | i32.const 1 000040: 46 | i32.eq - 000041: 04 6b 00 | if (ref 0) + 000041: 04 64 00 | if (ref 0) 000044: 20 00 | local.get 0 000046: 05 | else 000047: 20 01 | local.get 1 @@ -194,6 +195,6 @@ Code Disassembly: 000064: d2 02 | ref.func 2 000066: 41 01 | i32.const 1 000068: 10 00 | call 0 - 00006a: 14 | call_ref - 00006b: 0b | end + 00006a: 14 00 | call_ref (ref null 0) + 00006c: 0b | end ;;; STDOUT ;;) diff --git a/test/parse/bad-references.txt b/test/parse/bad-references.txt index b31e4ce0d6..6ca809ab29 100644 --- a/test/parse/bad-references.txt +++ b/test/parse/bad-references.txt @@ -11,19 +11,19 @@ ) ) (;; STDERR ;;; -out/test/parse/bad-references.txt:6:31: error: reference type out of range: 2 (max: 2) +out/test/parse/bad-references.txt:6:4: error: reference 2 is out of range in params (type $t0 (func (param (ref 2)))) - ^ -out/test/parse/bad-references.txt:7:31: error: reference type out of range: 33 (max: 2) + ^^^^ +out/test/parse/bad-references.txt:7:4: error: reference 33 is out of range in params (type $t1 (func (param (ref 33)) (result (ref 444)))) - ^^ -out/test/parse/bad-references.txt:7:49: error: reference type out of range: 444 (max: 2) + ^^^^ +out/test/parse/bad-references.txt:7:4: error: reference 444 is out of range in results (type $t1 (func (param (ref 33)) (result (ref 444)))) - ^^^ -out/test/parse/bad-references.txt:9:28: error: reference type out of range: 5555 (max: 2) + ^^^^ +out/test/parse/bad-references.txt:9:4: error: reference 5555 is out of range in params (func $f (param $p1 (ref 5555)) - ^^^^ -out/test/parse/bad-references.txt:10:21: error: reference type out of range: 66666 (max: 2) - (local $p2 (ref 66666)) - ^^^^^ + ^^^^ +out/test/parse/bad-references.txt:9:12: error: reference 66666 is out of range in locals + (func $f (param $p1 (ref 5555)) + ^ ;;; STDERR ;;) diff --git a/test/parse/expr/callref-imported-function.txt b/test/parse/expr/callref-imported-function.txt index 255f7c19e9..edabe4354f 100644 --- a/test/parse/expr/callref-imported-function.txt +++ b/test/parse/expr/callref-imported-function.txt @@ -3,9 +3,10 @@ (module (import "" "foo" (func $foo (param i32) (result i32))) (func (export "main") (result i32) - (call_ref (i32.const 10) - (ref.func $foo) + (call_ref $t (i32.const 10) + (ref.func $foo) ) ) (elem declare funcref (ref.func $foo)) + (type $t (func (param i32) (result i32))) ) diff --git a/test/parse/expr/callref-internal-function.txt b/test/parse/expr/callref-internal-function.txt index 5cc27cc682..fc85558345 100644 --- a/test/parse/expr/callref-internal-function.txt +++ b/test/parse/expr/callref-internal-function.txt @@ -2,13 +2,15 @@ ;;; ARGS: --enable-function-references (module (func (export "main") (result i32) - (call_ref (i32.const 10) - (ref.func $foo) + (call_ref 0 (i32.const 10) + (ref.func $foo) ) ) (func $foo (param $x i32) (result i32) (i32.add (local.get $x) (i32.const 19)) ) + (elem declare funcref (ref.func $foo)) + (type (func (param i32) (result i32))) ) diff --git a/test/parse/module/bad-element-followed-by-illegal-expression.txt b/test/parse/module/bad-element-followed-by-illegal-expression.txt index 5243aedc8e..34e3389fe6 100644 --- a/test/parse/module/bad-element-followed-by-illegal-expression.txt +++ b/test/parse/module/bad-element-followed-by-illegal-expression.txt @@ -3,7 +3,7 @@ ;;; ERROR: 1 ( elem f64 ( ) ) (;; STDERR ;;; -out/test/parse/module/bad-element-followed-by-illegal-expression.txt:4:12: error: unexpected token (, expected ). +out/test/parse/module/bad-element-followed-by-illegal-expression.txt:4:8: error: value type not allowed: f64 ( elem f64 ( ) ) - ^ + ^^^ ;;; STDERR ;;) diff --git a/test/roundtrip/fold-callref.txt b/test/roundtrip/fold-callref.txt index fdfbcae052..dbd885b88b 100644 --- a/test/roundtrip/fold-callref.txt +++ b/test/roundtrip/fold-callref.txt @@ -1,26 +1,24 @@ ;;; TOOL: run-roundtrip ;;; ARGS: --stdout --fold-exprs --enable-function-references (module - (type $i_i (func (param i32) (result i32))) - (func $i32_r_i32 (type $i_i) i32.const 1) - (func $i32_f32_r_f32 (param i32 f32) (result f32) + (func $i32_f32_r_f32 (type $if_f) f32.const 0) - (func $f32_f32_f32_f32_r_v (param f32 f32 f32 f32)) + (func $f32_f32_f32_f32_r_v (type $ffff)) (elem declare funcref (ref.func $i32_r_i32) (ref.func $i32_f32_r_f32) (ref.func $f32_f32_f32_f32_r_v)) (func $fold-callref (result i32) i32.const 1 ref.func $i32_r_i32 - call_ref + call_ref $i_i drop i32.const 2 ref.func $i32_r_i32 - call_ref) + call_ref $i_i) (func $fold-call-2 f32.const 0 @@ -29,9 +27,13 @@ i32.const 3 f32.const 4 ref.func $i32_f32_r_f32 - call_ref + call_ref $if_f ref.func $f32_f32_f32_f32_r_v - call_ref) + call_ref $ffff) + + (type $i_i (func (param i32) (result i32))) + (type $if_f (func (param i32 f32) (result f32))) + (type $ffff (func (param f32 f32 f32 f32))) ) (;; STDOUT ;;; @@ -48,15 +50,19 @@ (func (;2;) (type 2) (param f32 f32 f32 f32)) (func (;3;) (type 3) (result i32) (drop - (call_ref (i32.const 1) + (call_ref 0 + (i32.const 1) (ref.func 0))) - (call_ref (i32.const 2) + (call_ref 0 + (i32.const 2) (ref.func 0))) (func (;4;) (type 4) - (call_ref (f32.const 0x0p+0 (;=0;)) + (call_ref 2 + (f32.const 0x0p+0 (;=0;)) (f32.const 0x1p+0 (;=1;)) (f32.const 0x1p+1 (;=2;)) - (call_ref (i32.const 3) + (call_ref 1 + (i32.const 3) (f32.const 0x1p+2 (;=4;)) (ref.func 1)) (ref.func 2))) diff --git a/test/roundtrip/ref-types.txt b/test/roundtrip/ref-types.txt new file mode 100644 index 0000000000..2b010c5e69 --- /dev/null +++ b/test/roundtrip/ref-types.txt @@ -0,0 +1,37 @@ +;;; TOOL: run-roundtrip +;;; ARGS: --stdout --enable-function-references +(module + (type $ii (func)) + (func $dummy) + + (global (ref func) ref.func $dummy) + (global (ref $ii) ref.func $dummy) + (global (ref null func) ref.null $ii) + (global (ref null $ii) ref.null $ii) + + (func $f1 (param (ref func) (ref extern) (ref $ii)) + (local (ref func) (ref func) + (ref extern) (ref extern) + (ref $ii) (ref $ii)) + ) + (func $f2 (param (ref null func) (ref null extern) (ref null $ii)) + (local (ref null func) (ref null func) + (ref null extern) (ref null extern) + (ref null $ii) (ref null $ii)) + ) +) +(;; STDOUT ;;; +(module + (type (;0;) (func)) + (type (;1;) (func (param (ref func) (ref extern) (ref 0)))) + (type (;2;) (func (param funcref externref (ref null 0)))) + (func (;0;) (type 0)) + (func (;1;) (type 1) (param (ref func) (ref extern) (ref 0)) + (local (ref func) (ref func) (ref extern) (ref extern) (ref 0) (ref 0))) + (func (;2;) (type 2) (param funcref externref (ref null 0)) + (local funcref funcref externref externref (ref null 0) (ref null 0))) + (global (;0;) (ref func) (ref.func 0)) + (global (;1;) (ref 0) (ref.func 0)) + (global (;2;) funcref (ref.null 0)) + (global (;3;) (ref null 0) (ref.null 0))) +;;; STDOUT ;;) diff --git a/test/roundtrip/typed-func-refs.txt b/test/roundtrip/typed-func-refs.txt index 25fdfebf1c..c1961de3c5 100644 --- a/test/roundtrip/typed-func-refs.txt +++ b/test/roundtrip/typed-func-refs.txt @@ -2,9 +2,9 @@ ;;; ARGS: --stdout --enable-function-references --debug-names (module (type $t0 (func)) + (type $t1 (func)) - ;; Self reference - (type $t1 (func (param (ref $t0) (ref $t1) (ref 1)))) + (type $t2 (func (param (ref $t0) (ref $t1) (ref 1)))) (func $f1 (param (ref $t0) (ref 0)) (local (ref $t0) (ref 0) @@ -14,8 +14,9 @@ (;; STDOUT ;;; (module (type $t0 (func)) - (type $t1 (func (param (ref 0) (ref 1) (ref 1)))) - (type (;2;) (func (param (ref 0) (ref 0)))) - (func $f1 (type 2) (param (ref 0) (ref 0)) + (type $t1 (func)) + (type $t2 (func (param (ref 0) (ref 1) (ref 1)))) + (type (;3;) (func (param (ref 0) (ref 0)))) + (func $f1 (type 3) (param (ref 0) (ref 0)) (local (ref 0) (ref 0) (ref 1) (ref 1)))) ;;; STDOUT ;;) diff --git a/test/spec/function-references/br_on_non_null.txt b/test/spec/function-references/br_on_non_null.txt new file mode 100644 index 0000000000..83dbbe22f4 --- /dev/null +++ b/test/spec/function-references/br_on_non_null.txt @@ -0,0 +1,7 @@ +;;; TOOL: run-interp-spec +;;; STDIN_FILE: third_party/testsuite/proposals/function-references/br_on_non_null.wast +;;; ARGS*: --enable-function-references +(;; STDOUT ;;; +out/test/spec/function-references/br_on_non_null.wast:37: assert_trap passed: unreachable executed +9/9 tests passed. +;;; STDOUT ;;) diff --git a/test/spec/function-references/br_on_null.txt b/test/spec/function-references/br_on_null.txt new file mode 100644 index 0000000000..a81579f1dc --- /dev/null +++ b/test/spec/function-references/br_on_null.txt @@ -0,0 +1,7 @@ +;;; TOOL: run-interp-spec +;;; STDIN_FILE: third_party/testsuite/proposals/function-references/br_on_null.wast +;;; ARGS*: --enable-function-references +(;; STDOUT ;;; +out/test/spec/function-references/br_on_null.wast:32: assert_trap passed: unreachable executed +9/9 tests passed. +;;; STDOUT ;;) diff --git a/test/spec/function-references/br_table.txt b/test/spec/function-references/br_table.txt new file mode 100644 index 0000000000..efbc319cfb --- /dev/null +++ b/test/spec/function-references/br_table.txt @@ -0,0 +1,78 @@ +;;; TOOL: run-interp-spec +;;; STDIN_FILE: third_party/testsuite/proposals/function-references/br_table.wast +;;; ARGS*: --enable-function-references +(;; STDOUT ;;; +out/test/spec/function-references/br_table.wast:1267: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.1.wasm:0000022: error: type mismatch at end of block, expected [] but got [i32] + 0000022: error: OnEndExpr callback failed +out/test/spec/function-references/br_table.wast:1274: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.2.wasm:000001d: error: type mismatch in br_table, expected [i32] but got [] + 000001d: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1281: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.3.wasm:0000020: error: type mismatch in br_table, expected [i32] but got [] + 0000020: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1287: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.4.wasm:0000023: error: type mismatch in br_table, expected [i32] but got [i64] + 0000023: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1295: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.5.wasm:0000026: error: br_table labels have inconsistent types: expected [f32], got [] + 0000026: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1306: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.6.wasm:0000023: error: type mismatch in br_table, expected [i64] but got [i32] + 0000023: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1317: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.7.wasm:000001f: error: type mismatch in br_table, expected [i32] but got [] + 000001f: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1323: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.8.wasm:000001e: error: type mismatch in br_table, expected [i32] but got [i64] + 000001e: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1329: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.9.wasm:0000021: error: type mismatch in br_table, expected [i32] but got [] + 0000021: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1335: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.10.wasm:0000023: error: type mismatch in br_table, expected [i32] but got [] + 0000023: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1341: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.11.wasm:0000022: error: type mismatch in br_table, expected [i32] but got [... i64] + 0000022: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1350: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.12.wasm:0000022: error: type mismatch at end of block, expected [] but got [i32] + 0000022: error: OnEndExpr callback failed +out/test/spec/function-references/br_table.wast:1357: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.13.wasm:0000022: error: type mismatch in br_table, expected [i32] but got [] + 0000022: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1369: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.14.wasm:0000024: error: type mismatch in br_table, expected [i32] but got [] + 0000024: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1381: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.15.wasm:000001c: error: type mismatch in br_table, expected [i32] but got [] + 000001c: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1392: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.16.wasm:000001e: error: type mismatch in br_table, expected [i32] but got [] + 000001e: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1404: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.17.wasm:0000025: error: br_table labels have inconsistent types: expected [i32], got [] + 0000025: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1416: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.18.wasm:0000025: error: br_table labels have inconsistent types: expected [], got [i32] + 0000025: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1430: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.19.wasm:000001f: error: invalid depth: 2 (max 1) + 000001f: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1436: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.20.wasm:0000021: error: invalid depth: 5 (max 2) + 0000021: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1442: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.21.wasm:0000024: error: invalid depth: 268435457 (max 1) + 0000024: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1449: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.22.wasm:000001f: error: invalid depth: 2 (max 1) + 000001f: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1455: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.23.wasm:0000021: error: invalid depth: 5 (max 2) + 0000021: error: OnBrTableExpr callback failed +out/test/spec/function-references/br_table.wast:1461: assert_invalid passed: + out/test/spec/function-references/br_table/br_table.24.wasm:0000024: error: invalid depth: 268435457 (max 1) + 0000024: error: OnBrTableExpr callback failed +186/186 tests passed. +;;; STDOUT ;;) diff --git a/test/spec/function-references/call_ref.txt b/test/spec/function-references/call_ref.txt new file mode 100644 index 0000000000..b664ef249c --- /dev/null +++ b/test/spec/function-references/call_ref.txt @@ -0,0 +1,19 @@ +;;; TOOL: run-interp-spec +;;; STDIN_FILE: third_party/testsuite/proposals/function-references/call_ref.wast +;;; ARGS*: --enable-function-references +(;; STDOUT ;;; +out/test/spec/function-references/call_ref.wast:97: assert_trap passed: null function reference +out/test/spec/function-references/call_ref.wast:136: assert_trap passed: unreachable executed +out/test/spec/function-references/call_ref.wast:149: assert_trap passed: unreachable executed +out/test/spec/function-references/call_ref.wast:165: assert_trap passed: unreachable executed +out/test/spec/function-references/call_ref.wast:168: assert_invalid passed: + out/test/spec/function-references/call_ref/call_ref.4.wasm:0000042: error: type mismatch in call, expected [i32] but got [i64] + 0000042: error: OnCallRefExpr callback failed +out/test/spec/function-references/call_ref.wast:184: assert_invalid passed: + out/test/spec/function-references/call_ref/call_ref.5.wasm:0000044: error: type mismatch in implicit return, expected [i32] but got [i64] + 0000044: error: EndFunctionBody callback failed +out/test/spec/function-references/call_ref.wast:201: assert_invalid passed: + out/test/spec/function-references/call_ref/call_ref.6.wasm:000001f: error: type mismatch in call_ref, expected [(ref null 0)] but got [externref] + 000001f: error: OnCallRefExpr callback failed +34/34 tests passed. +;;; STDOUT ;;) diff --git a/test/spec/function-references/func.txt b/test/spec/function-references/func.txt new file mode 100644 index 0000000000..0bdff35ff0 --- /dev/null +++ b/test/spec/function-references/func.txt @@ -0,0 +1,257 @@ +;;; TOOL: run-interp-spec +;;; STDIN_FILE: third_party/testsuite/proposals/function-references/func.wast +;;; ARGS*: --enable-function-references +(;; STDOUT ;;; +out/test/spec/function-references/func.wast:436: assert_invalid passed: + out/test/spec/function-references/func/func.2.wasm:000001a: error: function type variable out of range: 2 (max 2) + 000001a: error: OnFunction callback failed +out/test/spec/function-references/func.wast:448: assert_malformed passed: + out/test/spec/function-references/func/func.3.wat:1:123: error: invalid func type index 2 + ...lt f64) (f64.const 1))(type $t (func (param i32)))(func (type 2) (param i32)) + ^^^^ +out/test/spec/function-references/func.wast:560: assert_malformed passed: + out/test/spec/function-references/func/func.6.wat:1:76: error: unexpected token "param", expected an instr. + ... i32) (result i32)))(func (type $sig) (result i32) (param i32) (i32.const 0)) + ^^^^^ +out/test/spec/function-references/func.wast:567: assert_malformed passed: + out/test/spec/function-references/func/func.7.wat:1:63: error: unexpected token "type", expected an instr. + ... i32) (result i32)))(func (param i32) (type $sig) (result i32) (i32.const 0)) + ^^^^ +out/test/spec/function-references/func.wast:574: assert_malformed passed: + out/test/spec/function-references/func/func.8.wat:1:76: error: unexpected token "type", expected an instr. + ... i32) (result i32)))(func (param i32) (result i32) (type $sig) (i32.const 0)) + ^^^^ +out/test/spec/function-references/func.wast:581: assert_malformed passed: + out/test/spec/function-references/func/func.9.wat:1:64: error: unexpected token "type", expected an instr. + ... i32) (result i32)))(func (result i32) (type $sig) (param i32) (i32.const 0)) + ^^^^ +out/test/spec/function-references/func.wast:588: assert_malformed passed: + out/test/spec/function-references/func/func.10.wat:1:64: error: unexpected token "param", expected an instr. + ... i32) (result i32)))(func (result i32) (param i32) (type $sig) (i32.const 0)) + ^^^^^ + out/test/spec/function-references/func/func.10.wat:1:85: error: unexpected token ), expected (. + ... i32) (result i32)))(func (result i32) (param i32) (type $sig) (i32.const 0)) + ^ +out/test/spec/function-references/func.wast:595: assert_malformed passed: + out/test/spec/function-references/func/func.11.wat:1:21: error: unexpected token "param", expected an instr. + (func (result i32) (param i32) (i32.const 0)) + ^^^^^ +out/test/spec/function-references/func.wast:602: assert_malformed passed: + out/test/spec/function-references/func/func.12.wat:1:20: error: expected 0 results, got 1 + (type $sig (func))(func (type $sig) (result i32) (i32.const 0)) + ^^^^ +out/test/spec/function-references/func.wast:609: assert_malformed passed: + out/test/spec/function-references/func/func.13.wat:1:45: error: expected 1 arguments, got 0 + ...g (func (param i32) (result i32)))(func (type $sig) (result i32) (i32.cons... + ^^^^ +out/test/spec/function-references/func.wast:616: assert_malformed passed: + out/test/spec/function-references/func/func.14.wat:1:45: error: expected 1 results, got 0 + ...g (func (param i32) (result i32)))(func (type $sig) (param i32) (i32.const... + ^^^^ +out/test/spec/function-references/func.wast:623: assert_malformed passed: + out/test/spec/function-references/func/func.15.wat:1:49: error: expected 2 arguments, got 1 + ...unc (param i32 i32) (result i32)))(func (type $sig) (param i32) (result i3... + ^^^^ +out/test/spec/function-references/func.wast:631: assert_invalid passed: + out/test/spec/function-references/func/func.16.wasm:000000c: error: function type variable out of range: 4 (max 0) + 000000c: error: OnFunction callback failed +out/test/spec/function-references/func.wast:635: assert_invalid passed: + out/test/spec/function-references/func/func.17.wasm:0000013: error: function type variable out of range: 4 (max 1) + 0000013: error: OnFunction callback failed +out/test/spec/function-references/func.wast:647: assert_invalid passed: + out/test/spec/function-references/func/func.18.wasm:000001d: error: type mismatch in implicit return, expected [i64] but got [i32] + 000001d: error: EndFunctionBody callback failed +out/test/spec/function-references/func.wast:651: assert_invalid passed: + out/test/spec/function-references/func/func.19.wasm:000001c: error: type mismatch in i32.eqz, expected [i32] but got [f32] + 000001c: error: OnConvertExpr callback failed +out/test/spec/function-references/func.wast:655: assert_invalid passed: + out/test/spec/function-references/func/func.20.wasm:000001e: error: type mismatch in f64.neg, expected [f64] but got [i64] + 000001e: error: OnUnaryExpr callback failed +out/test/spec/function-references/func.wast:660: assert_invalid passed: + out/test/spec/function-references/func/func.21.wasm:000001c: error: uninitialized local reference + 000001c: error: OnLocalGetExpr callback failed +out/test/spec/function-references/func.wast:671: assert_invalid passed: + out/test/spec/function-references/func/func.22.wasm:000001c: error: type mismatch in implicit return, expected [i64] but got [i32] + 000001c: error: EndFunctionBody callback failed +out/test/spec/function-references/func.wast:675: assert_invalid passed: + out/test/spec/function-references/func/func.23.wasm:000001b: error: type mismatch in i32.eqz, expected [i32] but got [f32] + 000001b: error: OnConvertExpr callback failed +out/test/spec/function-references/func.wast:679: assert_invalid passed: + out/test/spec/function-references/func/func.24.wasm:000001c: error: type mismatch in f64.neg, expected [f64] but got [i64] + 000001c: error: OnUnaryExpr callback failed +out/test/spec/function-references/func.wast:687: assert_invalid passed: + out/test/spec/function-references/func/func.25.wasm:0000019: error: type mismatch in implicit return, expected [i32] but got [] + 0000019: error: EndFunctionBody callback failed +out/test/spec/function-references/func.wast:691: assert_invalid passed: + out/test/spec/function-references/func/func.26.wasm:0000019: error: type mismatch in implicit return, expected [i64] but got [] + 0000019: error: EndFunctionBody callback failed +out/test/spec/function-references/func.wast:695: assert_invalid passed: + out/test/spec/function-references/func/func.27.wasm:0000019: error: type mismatch in implicit return, expected [f32] but got [] + 0000019: error: EndFunctionBody callback failed +out/test/spec/function-references/func.wast:699: assert_invalid passed: + out/test/spec/function-references/func/func.28.wasm:0000019: error: type mismatch in implicit return, expected [f64] but got [] + 0000019: error: EndFunctionBody callback failed +out/test/spec/function-references/func.wast:703: assert_invalid passed: + out/test/spec/function-references/func/func.29.wasm:000001a: error: type mismatch in implicit return, expected [f64, i32] but got [] + 000001a: error: EndFunctionBody callback failed +out/test/spec/function-references/func.wast:708: assert_invalid passed: + out/test/spec/function-references/func/func.30.wasm:000001a: error: type mismatch in implicit return, expected [i32] but got [] + 000001a: error: EndFunctionBody callback failed +out/test/spec/function-references/func.wast:714: assert_invalid passed: + out/test/spec/function-references/func/func.31.wasm:000001b: error: type mismatch in implicit return, expected [i32, i32] but got [] + 000001b: error: EndFunctionBody callback failed +out/test/spec/function-references/func.wast:720: assert_invalid passed: + out/test/spec/function-references/func/func.32.wasm:000001a: error: type mismatch at end of function, expected [] but got [i32] + 000001a: error: EndFunctionBody callback failed +out/test/spec/function-references/func.wast:726: assert_invalid passed: + out/test/spec/function-references/func/func.33.wasm:000001c: error: type mismatch at end of function, expected [] but got [i32, i64] + 000001c: error: EndFunctionBody callback failed +out/test/spec/function-references/func.wast:732: assert_invalid passed: + out/test/spec/function-references/func/func.34.wasm:000001e: error: type mismatch in implicit return, expected [i32] but got [f32] + 000001e: error: EndFunctionBody callback failed +out/test/spec/function-references/func.wast:738: assert_invalid passed: + out/test/spec/function-references/func/func.35.wasm:000001f: error: type mismatch in implicit return, expected [f32, f32] but got [f32] + 000001f: error: EndFunctionBody callback failed +out/test/spec/function-references/func.wast:744: assert_invalid passed: + out/test/spec/function-references/func/func.36.wasm:0000023: error: type mismatch at end of function, expected [] but got [f32] + 0000023: error: EndFunctionBody callback failed +out/test/spec/function-references/func.wast:751: assert_invalid passed: + out/test/spec/function-references/func/func.37.wasm:0000019: error: type mismatch in return, expected [i32] but got [] + 0000019: error: OnReturnExpr callback failed +out/test/spec/function-references/func.wast:757: assert_invalid passed: + out/test/spec/function-references/func/func.38.wasm:000001a: error: type mismatch in return, expected [i32, i32] but got [] + 000001a: error: OnReturnExpr callback failed +out/test/spec/function-references/func.wast:763: assert_invalid passed: + out/test/spec/function-references/func/func.39.wasm:000001a: error: type mismatch in return, expected [i32] but got [] + 000001a: error: OnReturnExpr callback failed +out/test/spec/function-references/func.wast:769: assert_invalid passed: + out/test/spec/function-references/func/func.40.wasm:000001b: error: type mismatch in return, expected [i32, i64] but got [] + 000001b: error: OnReturnExpr callback failed +out/test/spec/function-references/func.wast:775: assert_invalid passed: + out/test/spec/function-references/func/func.41.wasm:000001b: error: type mismatch in return, expected [i32] but got [i64] + 000001b: error: OnReturnExpr callback failed +out/test/spec/function-references/func.wast:781: assert_invalid passed: + out/test/spec/function-references/func/func.42.wasm:000001c: error: type mismatch in return, expected [i64, i64] but got [i64] + 000001c: error: OnReturnExpr callback failed +out/test/spec/function-references/func.wast:788: assert_invalid passed: + out/test/spec/function-references/func/func.43.wasm:0000019: error: type mismatch in return, expected [i32] but got [] + 0000019: error: OnReturnExpr callback failed +out/test/spec/function-references/func.wast:794: assert_invalid passed: + out/test/spec/function-references/func/func.44.wasm:000001a: error: type mismatch in return, expected [i32, i32] but got [] + 000001a: error: OnReturnExpr callback failed +out/test/spec/function-references/func.wast:800: assert_invalid passed: + out/test/spec/function-references/func/func.45.wasm:000001c: error: type mismatch in return, expected [i32, i32] but got [i32] + 000001c: error: OnReturnExpr callback failed +out/test/spec/function-references/func.wast:806: assert_invalid passed: + out/test/spec/function-references/func/func.46.wasm:000001a: error: type mismatch in return, expected [i32] but got [] + 000001a: error: OnReturnExpr callback failed +out/test/spec/function-references/func.wast:812: assert_invalid passed: + out/test/spec/function-references/func/func.47.wasm:000001b: error: type mismatch in return, expected [i32, i32] but got [] + 000001b: error: OnReturnExpr callback failed +out/test/spec/function-references/func.wast:818: assert_invalid passed: + out/test/spec/function-references/func/func.48.wasm:000001b: error: type mismatch in return, expected [i32] but got [i64] + 000001b: error: OnReturnExpr callback failed +out/test/spec/function-references/func.wast:824: assert_invalid passed: + out/test/spec/function-references/func/func.49.wasm:000001c: error: type mismatch in return, expected [i32, i32] but got [i64] + 000001c: error: OnReturnExpr callback failed +out/test/spec/function-references/func.wast:830: assert_invalid passed: + out/test/spec/function-references/func/func.50.wasm:000001b: error: type mismatch in return, expected [i32] but got [i64] + 000001b: error: OnReturnExpr callback failed +out/test/spec/function-references/func.wast:836: assert_invalid passed: + out/test/spec/function-references/func/func.51.wasm:000001c: error: type mismatch in return, expected [i32, i32] but got [i32] + 000001c: error: OnReturnExpr callback failed +out/test/spec/function-references/func.wast:843: assert_invalid passed: + out/test/spec/function-references/func/func.52.wasm:000001a: error: type mismatch in br, expected [i32] but got [] + 000001a: error: OnBrExpr callback failed +out/test/spec/function-references/func.wast:849: assert_invalid passed: + out/test/spec/function-references/func/func.53.wasm:000001b: error: type mismatch in br, expected [i32, i32] but got [] + 000001b: error: OnBrExpr callback failed +out/test/spec/function-references/func.wast:855: assert_invalid passed: + out/test/spec/function-references/func/func.54.wasm:000001f: error: type mismatch in br, expected [i32] but got [f32] + 000001f: error: OnBrExpr callback failed +out/test/spec/function-references/func.wast:861: assert_invalid passed: + out/test/spec/function-references/func/func.55.wasm:000001d: error: type mismatch in br, expected [i32, i32] but got [i32] + 000001d: error: OnBrExpr callback failed +out/test/spec/function-references/func.wast:867: assert_invalid passed: + out/test/spec/function-references/func/func.56.wasm:000001a: error: type mismatch in br, expected [i32] but got [] + 000001a: error: OnBrExpr callback failed +out/test/spec/function-references/func.wast:873: assert_invalid passed: + out/test/spec/function-references/func/func.57.wasm:000001b: error: type mismatch in br, expected [i32, i32] but got [] + 000001b: error: OnBrExpr callback failed +out/test/spec/function-references/func.wast:879: assert_invalid passed: + out/test/spec/function-references/func/func.58.wasm:000001c: error: type mismatch in br, expected [i32] but got [i64] + 000001c: error: OnBrExpr callback failed +out/test/spec/function-references/func.wast:885: assert_invalid passed: + out/test/spec/function-references/func/func.59.wasm:000001d: error: type mismatch in br, expected [i32, i32] but got [i32] + 000001d: error: OnBrExpr callback failed +out/test/spec/function-references/func.wast:891: assert_invalid passed: + out/test/spec/function-references/func/func.60.wasm:000001c: error: type mismatch in br, expected [i32] but got [i64] + 000001c: error: OnBrExpr callback failed +out/test/spec/function-references/func.wast:898: assert_invalid passed: + out/test/spec/function-references/func/func.61.wasm:000001c: error: type mismatch in br, expected [i32] but got [] + 000001c: error: OnBrExpr callback failed +out/test/spec/function-references/func.wast:904: assert_invalid passed: + out/test/spec/function-references/func/func.62.wasm:000001d: error: type mismatch in br, expected [i32, i32] but got [] + 000001d: error: OnBrExpr callback failed +out/test/spec/function-references/func.wast:910: assert_invalid passed: + out/test/spec/function-references/func/func.63.wasm:000001d: error: type mismatch in br, expected [i32] but got [] + 000001d: error: OnBrExpr callback failed +out/test/spec/function-references/func.wast:916: assert_invalid passed: + out/test/spec/function-references/func/func.64.wasm:000001e: error: type mismatch in br, expected [i32, i32] but got [] + 000001e: error: OnBrExpr callback failed +out/test/spec/function-references/func.wast:922: assert_invalid passed: + out/test/spec/function-references/func/func.65.wasm:000001e: error: type mismatch in br, expected [i32] but got [i64] + 000001e: error: OnBrExpr callback failed +out/test/spec/function-references/func.wast:928: assert_invalid passed: + out/test/spec/function-references/func/func.66.wasm:000001f: error: type mismatch in br, expected [i32, i32] but got [i32] + 000001f: error: OnBrExpr callback failed +out/test/spec/function-references/func.wast:938: assert_malformed passed: + out/test/spec/function-references/func/func.67.wat:1:14: error: unexpected token "local", expected an instr. + (func (nop) (local i32)) + ^^^^^ +out/test/spec/function-references/func.wast:942: assert_malformed passed: + out/test/spec/function-references/func/func.68.wat:1:14: error: unexpected token "param", expected an instr. + (func (nop) (param i32)) + ^^^^^ +out/test/spec/function-references/func.wast:946: assert_malformed passed: + out/test/spec/function-references/func/func.69.wat:1:14: error: unexpected token "result", expected an instr. + (func (nop) (result i32)) + ^^^^^^ +out/test/spec/function-references/func.wast:950: assert_malformed passed: + out/test/spec/function-references/func/func.70.wat:1:20: error: unexpected token "param", expected an instr. + (func (local i32) (param i32)) + ^^^^^ +out/test/spec/function-references/func.wast:954: assert_malformed passed: + out/test/spec/function-references/func/func.71.wat:1:20: error: unexpected token "result", expected an instr. + (func (local i32) (result i32) (local.get 0)) + ^^^^^^ +out/test/spec/function-references/func.wast:958: assert_malformed passed: + out/test/spec/function-references/func/func.72.wat:1:21: error: unexpected token "param", expected an instr. + (func (result i32) (param i32) (local.get 0)) + ^^^^^ +out/test/spec/function-references/func.wast:965: assert_malformed passed: + out/test/spec/function-references/func/func.73.wat:1:13: error: redefinition of function "$foo" + (func $foo)(func $foo) + ^^^^ +out/test/spec/function-references/func.wast:969: assert_malformed passed: + out/test/spec/function-references/func/func.74.wat:1:28: error: redefinition of function "$foo" + (import "" "" (func $foo))(func $foo) + ^^^^ +out/test/spec/function-references/func.wast:973: assert_malformed passed: + out/test/spec/function-references/func/func.75.wat:1:28: error: redefinition of function "$foo" + (import "" "" (func $foo))(import "" "" (func $foo)) + ^^^^^^ +out/test/spec/function-references/func.wast:978: assert_malformed passed: + out/test/spec/function-references/func/func.76.wat:1:31: error: redefinition of parameter "$foo" + (func (param $foo i32) (param $foo i32)) + ^^^^ +out/test/spec/function-references/func.wast:982: assert_malformed passed: + out/test/spec/function-references/func/func.77.wat:1:31: error: redefinition of parameter "$foo" + (func (param $foo i32) (local $foo i32)) + ^^^^ +out/test/spec/function-references/func.wast:986: assert_malformed passed: + out/test/spec/function-references/func/func.78.wat:1:31: error: redefinition of local "$foo" + (func (local $foo i32) (local $foo i32)) + ^^^^ +175/175 tests passed. +;;; STDOUT ;;) diff --git a/test/spec/function-references/global.txt b/test/spec/function-references/global.txt new file mode 100644 index 0000000000..2810e9015b --- /dev/null +++ b/test/spec/function-references/global.txt @@ -0,0 +1,141 @@ +;;; TOOL: run-interp-spec +;;; STDIN_FILE: third_party/testsuite/proposals/function-references/global.wast +;;; ARGS*: --enable-function-references +(;; STDOUT ;;; +out/test/spec/function-references/global.wast:251: assert_trap passed: undefined table index +out/test/spec/function-references/global.wast:273: assert_invalid passed: + out/test/spec/function-references/global/global.1.wasm:0000029: error: can't global.set on immutable global at index 0. + 0000029: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:278: assert_invalid passed: + out/test/spec/function-references/global/global.2.wasm:0000035: error: can't global.set on immutable global at index 0. + 0000035: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:287: assert_invalid passed: + out/test/spec/function-references/global/global.5.wasm:0000013: error: invalid initializer: instruction not valid in initializer expression: f32.neg + 0000013: error: OnUnaryExpr callback failed +out/test/spec/function-references/global.wast:292: assert_invalid passed: + out/test/spec/function-references/global/global.6.wasm:000000f: error: invalid initializer: instruction not valid in initializer expression: local.get + 000000f: error: OnLocalGetExpr callback failed +out/test/spec/function-references/global.wast:297: assert_invalid passed: + out/test/spec/function-references/global/global.7.wasm:0000013: error: invalid initializer: instruction not valid in initializer expression: f32.neg + 0000013: error: OnUnaryExpr callback failed +out/test/spec/function-references/global.wast:302: assert_invalid passed: + out/test/spec/function-references/global/global.8.wasm:0000010: error: invalid initializer: instruction not valid in initializer expression: nop + 0000010: error: OnNopExpr callback failed +out/test/spec/function-references/global.wast:307: assert_invalid passed: + out/test/spec/function-references/global/global.9.wasm:0000010: error: invalid initializer: instruction not valid in initializer expression: i32.ctz + 0000010: error: OnUnaryExpr callback failed +out/test/spec/function-references/global.wast:312: assert_invalid passed: + out/test/spec/function-references/global/global.10.wasm:000000e: error: invalid initializer: instruction not valid in initializer expression: nop + 000000e: error: OnNopExpr callback failed +out/test/spec/function-references/global.wast:317: assert_invalid passed: + out/test/spec/function-references/global/global.11.wasm:0000012: error: type mismatch in initializer expression, expected [i32] but got [f32] + 0000013: error: EndGlobalInitExpr callback failed +out/test/spec/function-references/global.wast:322: assert_invalid passed: + out/test/spec/function-references/global/global.12.wasm:0000011: error: type mismatch at end of initializer expression, expected [] but got [i32] + 0000012: error: EndGlobalInitExpr callback failed +out/test/spec/function-references/global.wast:327: assert_invalid passed: + out/test/spec/function-references/global/global.13.wasm:000000d: error: type mismatch in initializer expression, expected [i32] but got [] + 000000e: error: EndGlobalInitExpr callback failed +out/test/spec/function-references/global.wast:332: assert_invalid passed: + out/test/spec/function-references/global/global.14.wasm:0000017: error: type mismatch in initializer expression, expected [funcref] but got [externref] + 0000018: error: EndGlobalInitExpr callback failed +out/test/spec/function-references/global.wast:337: assert_invalid passed: + out/test/spec/function-references/global/global.15.wasm:0000027: error: type mismatch at end of initializer expression, expected [] but got [i32] + 0000028: error: EndGlobalInitExpr callback failed +out/test/spec/function-references/global.wast:342: assert_invalid passed: + out/test/spec/function-references/global/global.16.wasm:0000027: error: type mismatch at end of initializer expression, expected [] but got [i32] + 0000028: error: EndGlobalInitExpr callback failed +out/test/spec/function-references/global.wast:347: assert_invalid passed: + out/test/spec/function-references/global/global.17.wasm:000000f: error: initializer expression can only reference an imported global + 000000f: error: OnGlobalGetExpr callback failed +out/test/spec/function-references/global.wast:352: assert_invalid passed: + out/test/spec/function-references/global/global.18.wasm:000000f: error: global variable out of range: 1 (max 1) + 000000f: error: OnGlobalGetExpr callback failed +out/test/spec/function-references/global.wast:357: assert_invalid passed: + out/test/spec/function-references/global/global.19.wasm:0000025: error: global variable out of range: 2 (max 2) + 0000025: error: OnGlobalGetExpr callback failed +out/test/spec/function-references/global.wast:362: assert_invalid passed: + out/test/spec/function-references/global/global.20.wasm:0000029: error: initializer expression cannot reference a mutable global + 0000029: error: OnGlobalGetExpr callback failed +out/test/spec/function-references/global.wast:370: assert_malformed passed: + 0000026: error: global mutability must be 0 or 1 +out/test/spec/function-references/global.wast:383: assert_malformed passed: + 0000026: error: global mutability must be 0 or 1 +out/test/spec/function-references/global.wast:400: assert_malformed passed: + 0000011: error: global mutability must be 0 or 1 +out/test/spec/function-references/global.wast:412: assert_malformed passed: + 0000011: error: global mutability must be 0 or 1 +out/test/spec/function-references/global.wast:426: assert_invalid passed: + out/test/spec/function-references/global/global.27.wasm:000001a: error: global variable out of range: 0 (max 0) + 000001a: error: OnGlobalGetExpr callback failed +out/test/spec/function-references/global.wast:431: assert_invalid passed: + out/test/spec/function-references/global/global.28.wasm:0000022: error: global variable out of range: 1 (max 1) + 0000022: error: OnGlobalGetExpr callback failed +out/test/spec/function-references/global.wast:439: assert_invalid passed: + out/test/spec/function-references/global/global.29.wasm:0000034: error: global variable out of range: 1 (max 1) + 0000034: error: OnGlobalGetExpr callback failed +out/test/spec/function-references/global.wast:447: assert_invalid passed: + out/test/spec/function-references/global/global.30.wasm:000003c: error: global variable out of range: 2 (max 2) + 000003c: error: OnGlobalGetExpr callback failed +out/test/spec/function-references/global.wast:457: assert_invalid passed: + out/test/spec/function-references/global/global.31.wasm:000001b: error: global variable out of range: 0 (max 0) + 000001b: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:462: assert_invalid passed: + out/test/spec/function-references/global/global.32.wasm:0000023: error: global variable out of range: 1 (max 1) + 0000023: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:470: assert_invalid passed: + out/test/spec/function-references/global/global.33.wasm:0000035: error: global variable out of range: 1 (max 1) + 0000035: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:478: assert_invalid passed: + out/test/spec/function-references/global/global.34.wasm:000003d: error: global variable out of range: 2 (max 2) + 000003d: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:488: assert_invalid passed: + out/test/spec/function-references/global/global.35.wasm:0000021: error: type mismatch in global.set, expected [i32] but got [] + 0000021: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:497: assert_invalid passed: + out/test/spec/function-references/global/global.36.wasm:0000025: error: type mismatch in global.set, expected [i32] but got [] + 0000025: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:507: assert_invalid passed: + out/test/spec/function-references/global/global.37.wasm:0000025: error: type mismatch in global.set, expected [i32] but got [] + 0000025: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:517: assert_invalid passed: + out/test/spec/function-references/global/global.38.wasm:0000027: error: type mismatch in global.set, expected [i32] but got [] + 0000027: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:527: assert_invalid passed: + out/test/spec/function-references/global/global.39.wasm:000002a: error: type mismatch in global.set, expected [i32] but got [] + 000002a: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:537: assert_invalid passed: + out/test/spec/function-references/global/global.40.wasm:0000025: error: type mismatch in global.set, expected [i32] but got [] + 0000025: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:547: assert_invalid passed: + out/test/spec/function-references/global/global.41.wasm:0000025: error: type mismatch in global.set, expected [i32] but got [] + 0000025: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:557: assert_invalid passed: + out/test/spec/function-references/global/global.42.wasm:0000025: error: type mismatch in global.set, expected [i32] but got [] + 0000025: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:567: assert_invalid passed: + out/test/spec/function-references/global/global.43.wasm:0000021: error: type mismatch in global.set, expected [i32] but got [] + 0000021: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:576: assert_invalid passed: + out/test/spec/function-references/global/global.44.wasm:0000021: error: type mismatch in global.set, expected [i32] but got [] + 0000021: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:585: assert_invalid passed: + out/test/spec/function-references/global/global.45.wasm:0000027: error: type mismatch in global.set, expected [i32] but got [] + 0000027: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:595: assert_invalid passed: + out/test/spec/function-references/global/global.46.wasm:000003e: error: type mismatch in global.set, expected [i32] but got [] + 000003e: error: OnGlobalSetExpr callback failed +out/test/spec/function-references/global.wast:613: assert_malformed passed: + out/test/spec/function-references/global/global.47.wat:1:33: error: redefinition of global "$foo" + (global $foo i32 (i32.const 0))(global $foo i32 (i32.const 0)) + ^^^^^^ +out/test/spec/function-references/global.wast:617: assert_malformed passed: + out/test/spec/function-references/global/global.48.wat:1:34: error: redefinition of global "$foo" + (import "" "" (global $foo i32))(global $foo i32 (i32.const 0)) + ^^^^^^ +out/test/spec/function-references/global.wast:621: assert_malformed passed: + out/test/spec/function-references/global/global.49.wat:1:34: error: redefinition of global "$foo" + (import "" "" (global $foo i32))(import "" "" (global $foo i32)) + ^^^^^^ +108/108 tests passed. +;;; STDOUT ;;) diff --git a/test/spec/function-references/local_init.txt b/test/spec/function-references/local_init.txt new file mode 100644 index 0000000000..3c9cdc720d --- /dev/null +++ b/test/spec/function-references/local_init.txt @@ -0,0 +1,18 @@ +;;; TOOL: run-interp-spec +;;; STDIN_FILE: third_party/testsuite/proposals/function-references/local_init.wast +;;; ARGS*: --enable-function-references +(;; STDOUT ;;; +out/test/spec/function-references/local_init.wast:26: assert_invalid passed: + out/test/spec/function-references/local_init/local_init.1.wasm:000001c: error: uninitialized local reference + 000001c: error: OnLocalGetExpr callback failed +out/test/spec/function-references/local_init.wast:30: assert_invalid passed: + out/test/spec/function-references/local_init/local_init.2.wasm:000002a: error: uninitialized local reference + 000002a: error: OnLocalGetExpr callback failed +out/test/spec/function-references/local_init.wast:40: assert_invalid passed: + out/test/spec/function-references/local_init/local_init.3.wasm:0000027: error: uninitialized local reference + 0000027: error: OnLocalGetExpr callback failed +out/test/spec/function-references/local_init.wast:53: assert_invalid passed: + out/test/spec/function-references/local_init/local_init.4.wasm:000002c: error: uninitialized local reference + 000002c: error: OnLocalGetExpr callback failed +10/10 tests passed. +;;; STDOUT ;;) diff --git a/test/spec/function-references/ref.txt b/test/spec/function-references/ref.txt new file mode 100644 index 0000000000..e178a7799a --- /dev/null +++ b/test/spec/function-references/ref.txt @@ -0,0 +1,43 @@ +;;; TOOL: run-interp-spec +;;; STDIN_FILE: third_party/testsuite/proposals/function-references/ref.wast +;;; ARGS*: --enable-function-references +(;; STDOUT ;;; +out/test/spec/function-references/ref.wast:28: assert_invalid passed: + out/test/spec/function-references/ref/ref.1.wasm:0000010: error: reference 1 is out of range in params + 0000010: error: OnFuncType callback failed +out/test/spec/function-references/ref.wast:32: assert_invalid passed: + out/test/spec/function-references/ref/ref.2.wasm:0000010: error: reference 1 is out of range in results + 0000010: error: OnFuncType callback failed +out/test/spec/function-references/ref.wast:37: assert_invalid passed: + out/test/spec/function-references/ref/ref.3.wasm:000000e: error: reference 1 is out of range in globals + 000000e: error: BeginGlobal callback failed +out/test/spec/function-references/ref.wast:42: assert_invalid passed: + out/test/spec/function-references/ref/ref.4.wasm:000000f: error: reference 1 is out of range in tables + 000000f: error: OnTable callback failed +out/test/spec/function-references/ref.wast:47: assert_invalid passed: + out/test/spec/function-references/ref/ref.5.wasm:000000e: error: reference 1 is out of range + 000000e: error: OnElemSegmentElemType callback failed +out/test/spec/function-references/ref.wast:52: assert_invalid passed: + out/test/spec/function-references/ref/ref.6.wasm:0000010: error: reference 1 is out of range in params + 0000010: error: OnFuncType callback failed +out/test/spec/function-references/ref.wast:56: assert_invalid passed: + out/test/spec/function-references/ref/ref.7.wasm:0000010: error: reference 1 is out of range in results + 0000010: error: OnFuncType callback failed +out/test/spec/function-references/ref.wast:60: assert_invalid passed: + out/test/spec/function-references/ref/ref.8.wasm:000001a: error: reference 1 is out of range in locals + 000001a: error: OnLocalDecl callback failed +out/test/spec/function-references/ref.wast:65: assert_invalid passed: + out/test/spec/function-references/ref/ref.9.wasm:000001a: error: reference 1 is out of range + 000001a: error: OnBlockExpr callback failed +out/test/spec/function-references/ref.wast:69: assert_invalid passed: + out/test/spec/function-references/ref/ref.10.wasm:000001a: error: reference 1 is out of range + 000001a: error: OnLoopExpr callback failed +out/test/spec/function-references/ref.wast:73: assert_invalid passed: + out/test/spec/function-references/ref/ref.11.wasm:000001a: error: reference 1 is out of range + out/test/spec/function-references/ref/ref.11.wasm:000001a: error: type mismatch in if, expected [i32] but got [] + 000001a: error: OnIfExpr callback failed +out/test/spec/function-references/ref.wast:78: assert_invalid passed: + out/test/spec/function-references/ref/ref.12.wasm:000001c: error: reference 1 is out of range + 000001c: error: OnSelectExpr callback failed +13/13 tests passed. +;;; STDOUT ;;) diff --git a/test/spec/function-references/ref_as_non_null.txt b/test/spec/function-references/ref_as_non_null.txt new file mode 100644 index 0000000000..99b9e552ae --- /dev/null +++ b/test/spec/function-references/ref_as_non_null.txt @@ -0,0 +1,11 @@ +;;; TOOL: run-interp-spec +;;; STDIN_FILE: third_party/testsuite/proposals/function-references/ref_as_non_null.wast +;;; ARGS*: --enable-function-references +(;; STDOUT ;;; +out/test/spec/function-references/ref_as_non_null.wast:25: assert_trap passed: unreachable executed +out/test/spec/function-references/ref_as_non_null.wast:27: assert_trap passed: null reference +out/test/spec/function-references/ref_as_non_null.wast:32: assert_invalid passed: + out/test/spec/function-references/ref_as_non_null/ref_as_non_null.1.wasm:000002c: error: type mismatch in call, expected [(ref 0)] but got [(ref null 0)] + 000002c: error: OnCallExpr callback failed +7/7 tests passed. +;;; STDOUT ;;) diff --git a/test/spec/function-references/return_call_ref.txt b/test/spec/function-references/return_call_ref.txt new file mode 100644 index 0000000000..7d32cd582a --- /dev/null +++ b/test/spec/function-references/return_call_ref.txt @@ -0,0 +1,42 @@ +;;; SLOW: +;;; TOOL: run-interp-spec +;;; STDIN_FILE: third_party/testsuite/proposals/function-references/return_call_ref.wast +;;; ARGS*: --enable-function-references +(;; STDOUT ;;; +out/test/spec/function-references/return_call_ref.wast:183: assert_trap passed: null function reference +out/test/spec/function-references/return_call_ref.wast:232: assert_invalid passed: + out/test/spec/function-references/return_call_ref/return_call_ref.2.wasm:000002d: error: return signatures have inconsistent types: expected [(ref 0)], got [(ref null 0)] + 000002d: error: OnReturnCallRefExpr callback failed +out/test/spec/function-references/return_call_ref.wast:243: assert_invalid passed: + out/test/spec/function-references/return_call_ref/return_call_ref.3.wasm:000002d: error: return signatures have inconsistent types: expected [(ref 0)], got [(ref func)] + 000002d: error: OnReturnCallRefExpr callback failed +out/test/spec/function-references/return_call_ref.wast:254: assert_invalid passed: + out/test/spec/function-references/return_call_ref/return_call_ref.4.wasm:000002c: error: return signatures have inconsistent types: expected [(ref 0)], got [funcref] + 000002c: error: OnReturnCallRefExpr callback failed +out/test/spec/function-references/return_call_ref.wast:265: assert_invalid passed: + out/test/spec/function-references/return_call_ref/return_call_ref.5.wasm:000002d: error: return signatures have inconsistent types: expected [(ref null 0)], got [(ref func)] + 000002d: error: OnReturnCallRefExpr callback failed +out/test/spec/function-references/return_call_ref.wast:276: assert_invalid passed: + out/test/spec/function-references/return_call_ref/return_call_ref.6.wasm:000002c: error: return signatures have inconsistent types: expected [(ref null 0)], got [funcref] + 000002c: error: OnReturnCallRefExpr callback failed +out/test/spec/function-references/return_call_ref.wast:287: assert_invalid passed: + out/test/spec/function-references/return_call_ref/return_call_ref.7.wasm:0000029: error: return signatures have inconsistent types: expected [(ref func)], got [funcref] + 0000029: error: OnReturnCallRefExpr callback failed +out/test/spec/function-references/return_call_ref.wast:306: assert_trap passed: unreachable executed +out/test/spec/function-references/return_call_ref.wast:319: assert_trap passed: unreachable executed +out/test/spec/function-references/return_call_ref.wast:334: assert_trap passed: unreachable executed +out/test/spec/function-references/return_call_ref.wast:337: assert_invalid passed: + out/test/spec/function-references/return_call_ref/return_call_ref.11.wasm:0000042: error: type mismatch in return_call, expected [i32] but got [i64] + 0000042: error: OnReturnCallRefExpr callback failed +out/test/spec/function-references/return_call_ref.wast:353: assert_invalid passed: + out/test/spec/function-references/return_call_ref/return_call_ref.12.wasm:0000043: error: type mismatch in implicit return, expected [i32] but got [i64] + 0000043: error: EndFunctionBody callback failed +out/test/spec/function-references/return_call_ref.wast:369: assert_invalid passed: + out/test/spec/function-references/return_call_ref/return_call_ref.13.wasm:000001f: error: type mismatch in return_call_ref, expected [(ref null 0)] but got [externref] + 000001f: error: OnReturnCallRefExpr callback failed +out/test/spec/function-references/return_call_ref.wast:379: assert_invalid passed: + out/test/spec/function-references/return_call_ref/return_call_ref.14.wasm:0000022: error: type mismatch in return_call_ref, expected [(ref null 0)] but got [funcref] + out/test/spec/function-references/return_call_ref/return_call_ref.14.wasm:0000022: error: return signatures have inconsistent types: expected [i32], got [i32, i32] + 0000022: error: OnReturnCallRefExpr callback failed +50/50 tests passed. +;;; STDOUT ;;) diff --git a/test/spec/function-references/type-equivalence.txt b/test/spec/function-references/type-equivalence.txt new file mode 100644 index 0000000000..2a704cabdc --- /dev/null +++ b/test/spec/function-references/type-equivalence.txt @@ -0,0 +1,12 @@ +;;; TOOL: run-interp-spec +;;; STDIN_FILE: third_party/testsuite/proposals/function-references/type-equivalence.wast +;;; ARGS*: --enable-function-references +(;; STDOUT ;;; +out/test/spec/function-references/type-equivalence.wast:31: assert_invalid passed: + out/test/spec/function-references/type-equivalence/type-equivalence.2.wasm:0000010: error: reference 0 is out of range in results + 0000010: error: OnFuncType callback failed +out/test/spec/function-references/type-equivalence.wast:38: assert_invalid passed: + out/test/spec/function-references/type-equivalence/type-equivalence.3.wasm:0000010: error: reference 1 is out of range in params + 0000010: error: OnFuncType callback failed +12/12 tests passed. +;;; STDOUT ;;) diff --git a/test/typecheck/bad-callref-empty.txt b/test/typecheck/bad-callref-empty.txt index cee3885352..e97e08783b 100644 --- a/test/typecheck/bad-callref-empty.txt +++ b/test/typecheck/bad-callref-empty.txt @@ -2,13 +2,15 @@ ;;; ARGS: --enable-function-references ;;; ERROR: 1 (module + (type (func)) + (func (export "main") - (call_ref + (call_ref 0 ) ) ) (;; STDERR ;;; -out/test/typecheck/bad-callref-empty.txt:6:6: error: type mismatch in call_ref, expected [reference] but got [] - (call_ref +out/test/typecheck/bad-callref-empty.txt:8:6: error: type mismatch in call_ref, expected [(ref null 0)] but got [] + (call_ref 0 ^^^^^^^^ ;;; STDERR ;;) diff --git a/test/typecheck/bad-callref-int32.txt b/test/typecheck/bad-callref-int32.txt index 95401b9504..f598dbd8f0 100644 --- a/test/typecheck/bad-callref-int32.txt +++ b/test/typecheck/bad-callref-int32.txt @@ -2,14 +2,16 @@ ;;; ARGS: --enable-function-references ;;; ERROR: 1 (module + (type $t (func)) + (func (export "main") (result i32) - (call_ref (i32.const 10) - (i32.const 13) + (call_ref $t (i32.const 10) + (i32.const 13) ) ) ) (;; STDERR ;;; -out/test/typecheck/bad-callref-int32.txt:6:6: error: type mismatch in call_ref, expected [reference] but got [... i32] - (call_ref (i32.const 10) +out/test/typecheck/bad-callref-int32.txt:8:6: error: type mismatch in call_ref, expected [(ref null 0)] but got [... i32] + (call_ref $t (i32.const 10) ^^^^^^^^ ;;; STDERR ;;) diff --git a/test/typecheck/bad-callref-nosubtype.txt b/test/typecheck/bad-callref-nosubtype.txt new file mode 100644 index 0000000000..3d6ec7325e --- /dev/null +++ b/test/typecheck/bad-callref-nosubtype.txt @@ -0,0 +1,18 @@ +;;; TOOL: wat2wasm +;;; ARGS: --enable-function-references +;;; ERROR: 1 +(module + (func (export "main") (param (ref $t1)) + (call_ref $t2 (i64.const 10) + (local.get 0) + ) + ) + + (type $t1 (func (param i32))) + (type $t2 (func (param i64))) +) +(;; STDERR ;;; +out/test/typecheck/bad-callref-nosubtype.txt:6:6: error: type mismatch in call_ref, expected [(ref null 1)] but got [... (ref 0)] + (call_ref $t2 (i64.const 10) + ^^^^^^^^ +;;; STDERR ;;) diff --git a/test/typecheck/bad-callref-null.txt b/test/typecheck/bad-callref-null.txt index 6771a89367..314dff8b6d 100644 --- a/test/typecheck/bad-callref-null.txt +++ b/test/typecheck/bad-callref-null.txt @@ -3,13 +3,15 @@ ;;; ERROR: 1 (module (func (export "main") (result i32) - (call_ref (i32.const 10) - (ref.null func) + (call_ref $t (i32.const 10) + (ref.null func) ) ) + + (type $t (func)) ) (;; STDERR ;;; -out/test/typecheck/bad-callref-null.txt:6:6: error: type mismatch in call_ref, expected [reference] but got [... funcref] - (call_ref (i32.const 10) +out/test/typecheck/bad-callref-null.txt:6:6: error: type mismatch in call_ref, expected [(ref null 0)] but got [... funcref] + (call_ref $t (i32.const 10) ^^^^^^^^ ;;; STDERR ;;)