diff --git a/CMakeLists.txt b/CMakeLists.txt index 0677862e70..8154b6945c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -641,6 +641,13 @@ if (BUILD_TOOLS) INSTALL ) + # component + wabt_executable( + NAME component + SOURCES src/tools/component.cc + INSTALL + ) + if(BUILD_FUZZ_TOOLS) # wasm2wat-fuzz wabt_executable( diff --git a/include/wabt/binary-reader-ir.h b/include/wabt/binary-reader-ir.h index 4de0ee7099..2828c2d86a 100644 --- a/include/wabt/binary-reader-ir.h +++ b/include/wabt/binary-reader-ir.h @@ -22,6 +22,7 @@ namespace wabt { +struct Component; struct Module; struct ReadBinaryOptions; @@ -32,6 +33,13 @@ Result ReadBinaryIr(const char* filename, Errors*, Module* out_module); +Result ReadBinaryComponentIr(const char* filename, + const void* data, + size_t size, + const ReadBinaryOptions& options, + Errors*, + Component* out_component); + } // namespace wabt #endif /* WABT_BINARY_READER_IR_H_ */ diff --git a/include/wabt/binary-reader-logging.h b/include/wabt/binary-reader-logging.h index ece3c469d0..1a69bac157 100644 --- a/include/wabt/binary-reader-logging.h +++ b/include/wabt/binary-reader-logging.h @@ -44,13 +44,20 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Result BeginTypeSection(Offset size) override; Result OnTypeCount(Index count) override; + Result OnRecursiveType(Index first_type_index, Index type_count) override; Result OnFuncType(Index index, Index param_count, Type* param_types, Index result_count, - Type* result_types) override; - Result OnStructType(Index index, Index field_count, TypeMut* fields) override; - Result OnArrayType(Index index, TypeMut field) override; + Type* result_types, + SupertypesInfo* supertypes) override; + Result OnStructType(Index index, + Index field_count, + TypeMut* fields, + SupertypesInfo* supertypes) override; + Result OnArrayType(Index index, + TypeMut field, + SupertypesInfo* supertypes) override; Result EndTypeSection() override; Result BeginImportSection(Offset size) override; @@ -158,6 +165,17 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Result OnOpcodeV128(v128 value) override; Result OnOpcodeBlockSig(Type sig_type) override; Result OnOpcodeType(Type type) override; + Result OnArrayCopyExpr(Index dst_type_index, Index src_type_index) override; + Result OnArrayFillExpr(Index type_index) override; + Result OnArrayGetExpr(Opcode opcode, Index type_index) override; + Result OnArrayInitDataExpr(Index type_index, Index data_index) override; + Result OnArrayInitElemExpr(Index type_index, Index elem_index) override; + Result OnArrayNewExpr(Index type_index) override; + Result OnArrayNewDataExpr(Index type_index, Index data_index) override; + Result OnArrayNewDefaultExpr(Index type_index) override; + Result OnArrayNewElemExpr(Index type_index, Index elem_index) override; + Result OnArrayNewFixedExpr(Index type_index, Index count) override; + Result OnArraySetExpr(Index type_index) override; Result OnAtomicLoadExpr(Opcode opcode, Index memidx, Address alignment_log2, @@ -178,6 +196,10 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Result OnBlockExpr(Type sig_type) override; Result OnBrExpr(Index depth) override; Result OnBrIfExpr(Index depth) override; + Result OnBrOnCastExpr(Opcode opcode, + Index depth, + Type type1, + Type type2) override; Result OnBrOnNonNullExpr(Index depth) override; Result OnBrOnNullExpr(Index depth) override; Result OnBrTableExpr(Index num_targets, @@ -197,6 +219,7 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Result OnF32ConstExpr(uint32_t value_bits) override; Result OnF64ConstExpr(uint64_t value_bits) override; Result OnV128ConstExpr(v128 value_bits) override; + Result OnGCUnaryExpr(Opcode opcode) override; Result OnGlobalGetExpr(Index global_index) override; Result OnGlobalSetExpr(Index global_index) override; Result OnI32ConstExpr(uint32_t value) override; @@ -225,9 +248,11 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Result OnTableSizeExpr(Index table) override; Result OnTableFillExpr(Index table) override; Result OnRefAsNonNullExpr() override; + Result OnRefCastExpr(Type type) override; Result OnRefFuncExpr(Index index) override; Result OnRefNullExpr(Type type) override; Result OnRefIsNullExpr() override; + Result OnRefTestExpr(Type type) override; Result OnNopExpr() override; Result OnRethrowExpr(Index depth) override; Result OnReturnCallExpr(Index func_index) override; @@ -239,6 +264,12 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Index memidx, Address alignment_log2, Address offset) override; + Result OnStructGetExpr(Opcode opcode, + Index type_index, + Index field_index) override; + Result OnStructNewExpr(Index type_index) override; + Result OnStructNewDefaultExpr(Index type_index) override; + Result OnStructSetExpr(Index type_index, Index field_index) override; Result OnThrowExpr(Index tag_index) override; Result OnThrowRefExpr() override; Result OnTryExpr(Type sig_type) override; @@ -432,6 +463,7 @@ class BinaryReaderLogging : public BinaryReaderDelegate { void LogType(Type type); void LogTypes(Index type_count, Type* types); void LogTypes(TypeVector& types); + void LogSupertypesInfo(SupertypesInfo* supertypes); void LogField(TypeMut field); Stream* stream_; diff --git a/include/wabt/binary-reader-nop.h b/include/wabt/binary-reader-nop.h index 359cf9cdf0..0e29009d12 100644 --- a/include/wabt/binary-reader-nop.h +++ b/include/wabt/binary-reader-nop.h @@ -45,20 +45,29 @@ class BinaryReaderNop : public BinaryReaderDelegate { /* Type section */ Result BeginTypeSection(Offset size) override { return Result::Ok; } + Result OnRecursiveType(Index first_type_index, Index type_count) override { + return Result::Ok; + } Result OnTypeCount(Index count) override { return Result::Ok; } Result OnFuncType(Index index, Index param_count, Type* param_types, Index result_count, - Type* result_types) override { + Type* result_types, + SupertypesInfo* supertypes) override { return Result::Ok; } Result OnStructType(Index index, Index field_count, - TypeMut* fields) override { + TypeMut* fields, + SupertypesInfo* supertypes) override { + return Result::Ok; + } + Result OnArrayType(Index index, + TypeMut field, + SupertypesInfo* supertypes) override { return Result::Ok; } - Result OnArrayType(Index index, TypeMut field) override { return Result::Ok; } Result EndTypeSection() override { return Result::Ok; } /* Import section */ @@ -210,6 +219,31 @@ class BinaryReaderNop : public BinaryReaderDelegate { Result OnOpcodeV128(v128 value) override { return Result::Ok; } Result OnOpcodeBlockSig(Type sig_type) override { return Result::Ok; } Result OnOpcodeType(Type type) override { return Result::Ok; } + Result OnArrayCopyExpr(Index dst_type_index, Index src_type_index) override { + return Result::Ok; + } + Result OnArrayFillExpr(Index type_index) override { return Result::Ok; } + Result OnArrayGetExpr(Opcode opcode, Index type_index) override { + return Result::Ok; + } + Result OnArrayInitDataExpr(Index type_index, Index data_index) override { + return Result::Ok; + } + Result OnArrayInitElemExpr(Index type_index, Index elem_index) override { + return Result::Ok; + } + Result OnArrayNewExpr(Index type_index) override { return Result::Ok; } + Result OnArrayNewDataExpr(Index type_index, Index data_index) override { + return Result::Ok; + } + Result OnArrayNewDefaultExpr(Index type_index) override { return Result::Ok; } + Result OnArrayNewElemExpr(Index type_index, Index elem_index) override { + return Result::Ok; + } + Result OnArrayNewFixedExpr(Index type_index, Index count) override { + return Result::Ok; + } + Result OnArraySetExpr(Index type_index) override { return Result::Ok; } Result OnAtomicLoadExpr(Opcode opcode, Index memidx, Address alignment_log2, @@ -245,6 +279,12 @@ 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 OnBrOnCastExpr(Opcode opcode, + Index depth, + Type type1, + Type type2) 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, @@ -268,6 +308,7 @@ class BinaryReaderNop : public BinaryReaderDelegate { Result OnF32ConstExpr(uint32_t value_bits) override { return Result::Ok; } Result OnF64ConstExpr(uint64_t value_bits) override { return Result::Ok; } Result OnV128ConstExpr(v128 value_bits) override { return Result::Ok; } + Result OnGCUnaryExpr(Opcode opcode) override { return Result::Ok; } Result OnGlobalGetExpr(Index global_index) override { return Result::Ok; } Result OnGlobalSetExpr(Index global_index) override { return Result::Ok; } Result OnI32ConstExpr(uint32_t value) override { return Result::Ok; } @@ -306,9 +347,11 @@ class BinaryReaderNop : public BinaryReaderDelegate { 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 OnRefCastExpr(Type type) 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; } + Result OnRefTestExpr(Type type) override { return Result::Ok; } Result OnNopExpr() override { return Result::Ok; } Result OnRethrowExpr(Index depth) override { return Result::Ok; } Result OnReturnCallExpr(Index sig_index) override { return Result::Ok; } @@ -326,6 +369,18 @@ class BinaryReaderNop : public BinaryReaderDelegate { Address offset) override { return Result::Ok; } + Result OnStructGetExpr(Opcode opcode, + Index type_index, + Index field_index) override { + return Result::Ok; + } + Result OnStructNewExpr(Index type_index) override { return Result::Ok; } + Result OnStructNewDefaultExpr(Index type_index) override { + return Result::Ok; + } + Result OnStructSetExpr(Index type_index, Index field_index) override { + return Result::Ok; + } Result OnThrowExpr(Index depth) override { return Result::Ok; } Result OnThrowRefExpr() override { return Result::Ok; } Result OnTryExpr(Type sig_type) override { return Result::Ok; } diff --git a/include/wabt/binary-reader.h b/include/wabt/binary-reader.h index fdec07a79b..b56b4eee14 100644 --- a/include/wabt/binary-reader.h +++ b/include/wabt/binary-reader.h @@ -52,13 +52,20 @@ struct ReadBinaryOptions { bool skip_function_bodies = false; }; -// TODO: Move somewhere else? +// TODO: Move both TypeMut and GCTypeInformation somewhere else? struct TypeMut { Type type; bool mutable_; }; using TypeMutVector = std::vector; +// Type extension introduced by the Garbage Collector proposal +struct SupertypesInfo { + bool is_final_sub_type; + Index sub_type_count; + Index* sub_types; +}; + struct CatchClause { CatchKind kind; Index tag; @@ -104,15 +111,20 @@ class BinaryReaderDelegate { /* Type section */ virtual Result BeginTypeSection(Offset size) = 0; virtual Result OnTypeCount(Index count) = 0; + virtual Result OnRecursiveType(Index first_type_index, Index type_count) = 0; virtual Result OnFuncType(Index index, Index param_count, Type* param_types, Index result_count, - Type* result_types) = 0; + Type* result_types, + SupertypesInfo* supertypes) = 0; virtual Result OnStructType(Index index, Index field_count, - TypeMut* fields) = 0; - virtual Result OnArrayType(Index index, TypeMut field) = 0; + TypeMut* fields, + SupertypesInfo* supertypes) = 0; + virtual Result OnArrayType(Index index, + TypeMut field, + SupertypesInfo* supertypes) = 0; virtual Result EndTypeSection() = 0; /* Import section */ @@ -230,6 +242,17 @@ class BinaryReaderDelegate { virtual Result OnOpcodeV128(v128 value) = 0; virtual Result OnOpcodeBlockSig(Type sig_type) = 0; virtual Result OnOpcodeType(Type type) = 0; + virtual Result OnArrayCopyExpr(Index dst_type_index, Index src_type_index) = 0; + virtual Result OnArrayFillExpr(Index type_index) = 0; + virtual Result OnArrayGetExpr(Opcode opcode, Index type_index) = 0; + virtual Result OnArrayInitDataExpr(Index type_index, Index data_index) = 0; + virtual Result OnArrayInitElemExpr(Index type_index, Index elem_index) = 0; + virtual Result OnArrayNewExpr(Index type_index) = 0; + virtual Result OnArrayNewDataExpr(Index type_index, Index data_index) = 0; + virtual Result OnArrayNewDefaultExpr(Index type_index) = 0; + virtual Result OnArrayNewElemExpr(Index type_index, Index elem_index) = 0; + virtual Result OnArrayNewFixedExpr(Index type_index, Index count) = 0; + virtual Result OnArraySetExpr(Index type_index) = 0; virtual Result OnAtomicLoadExpr(Opcode opcode, Index memidx, Address alignment_log2, @@ -259,6 +282,10 @@ class BinaryReaderDelegate { virtual Result OnBlockExpr(Type sig_type) = 0; virtual Result OnBrExpr(Index depth) = 0; virtual Result OnBrIfExpr(Index depth) = 0; + virtual Result OnBrOnCastExpr(Opcode opcode, + Index depth, + Type type1, + Type type2) = 0; virtual Result OnBrOnNonNullExpr(Index depth) = 0; virtual Result OnBrOnNullExpr(Index depth) = 0; virtual Result OnBrTableExpr(Index num_targets, @@ -278,6 +305,7 @@ class BinaryReaderDelegate { virtual Result OnF32ConstExpr(uint32_t value_bits) = 0; virtual Result OnF64ConstExpr(uint64_t value_bits) = 0; virtual Result OnV128ConstExpr(v128 value_bits) = 0; + virtual Result OnGCUnaryExpr(Opcode opcode) = 0; virtual Result OnGlobalGetExpr(Index global_index) = 0; virtual Result OnGlobalSetExpr(Index global_index) = 0; virtual Result OnI32ConstExpr(uint32_t value) = 0; @@ -306,9 +334,11 @@ class BinaryReaderDelegate { virtual Result OnTableSizeExpr(Index table_index) = 0; virtual Result OnTableFillExpr(Index table_index) = 0; virtual Result OnRefAsNonNullExpr() = 0; + virtual Result OnRefCastExpr(Type type) = 0; virtual Result OnRefFuncExpr(Index func_index) = 0; virtual Result OnRefNullExpr(Type type) = 0; virtual Result OnRefIsNullExpr() = 0; + virtual Result OnRefTestExpr(Type type) = 0; virtual Result OnNopExpr() = 0; virtual Result OnRethrowExpr(Index depth) = 0; virtual Result OnReturnExpr() = 0; @@ -321,6 +351,12 @@ class BinaryReaderDelegate { Index memidx, Address alignment_log2, Address offset) = 0; + virtual Result OnStructGetExpr(Opcode opcode, + Index type_index, + Index field_index) = 0; + virtual Result OnStructNewExpr(Index type_index) = 0; + virtual Result OnStructNewDefaultExpr(Index type_index) = 0; + virtual Result OnStructSetExpr(Index type_index, Index field_index) = 0; virtual Result OnThrowExpr(Index tag_index) = 0; virtual Result OnThrowRefExpr() = 0; virtual Result OnTryExpr(Type sig_type) = 0; @@ -519,11 +555,32 @@ class BinaryReaderDelegate { const State* state = nullptr; }; +class ComponentBinaryReaderDelegate { + public: + virtual ~ComponentBinaryReaderDelegate() {} + + virtual bool OnError(const Error&) = 0; + virtual void OnSetState(const BinaryReaderDelegate::State* s) { state = s; } + + virtual Result OnCoreModule(const void* data, + size_t size, + const ReadBinaryOptions& options) = 0; + virtual Result BeginComponent(uint32_t version, size_t depth) = 0; + virtual Result EndComponent() = 0; + + const BinaryReaderDelegate::State* state = nullptr; +}; + Result ReadBinary(const void* data, size_t size, BinaryReaderDelegate* reader, const ReadBinaryOptions& options); +Result ReadBinaryComponent(const void* data, + size_t size, + ComponentBinaryReaderDelegate* component_delegate, + const ReadBinaryOptions& options); + size_t ReadU32Leb128(const uint8_t* ptr, const uint8_t* end, uint32_t* out_value); diff --git a/include/wabt/binary-writer.h b/include/wabt/binary-writer.h index dedba1bdcf..40a058062b 100644 --- a/include/wabt/binary-writer.h +++ b/include/wabt/binary-writer.h @@ -24,6 +24,7 @@ namespace wabt { +struct Component; struct Module; struct Script; @@ -45,6 +46,7 @@ struct WriteBinaryOptions { }; Result WriteBinaryModule(Stream*, const Module*, const WriteBinaryOptions&); +Result WriteBinaryComponent(Stream*, const Component*, const WriteBinaryOptions&); void WriteType(Stream* stream, Type type, const char* desc = nullptr); diff --git a/include/wabt/binary.h b/include/wabt/binary.h index a8c768f332..18061371d8 100644 --- a/include/wabt/binary.h +++ b/include/wabt/binary.h @@ -21,6 +21,7 @@ #define WABT_BINARY_MAGIC 0x6d736100 #define WABT_BINARY_VERSION 1 +#define WABT_BINARY_COMPONENT_VERSION 0xd #define WABT_BINARY_LAYER_MODULE 0 #define WABT_BINARY_LAYER_COMPONENT 1 #define WABT_BINARY_LIMITS_HAS_MAX_FLAG 0x1 @@ -104,6 +105,15 @@ enum class NameSectionSubsection { }; const char* GetNameSectionSubsectionName(NameSectionSubsection subsec); +enum class ComponentBinarySection : uint8_t { + // Same as ComponentType in ir.h + CoreModule = 1, + CoreInstance = 2, + CoreType = 3, + Component = 4, + Instance = 5, +}; + } // namespace wabt #endif /* WABT_BINARY_H_ */ diff --git a/include/wabt/expr-visitor.h b/include/wabt/expr-visitor.h index cef8025baa..50a8155562 100644 --- a/include/wabt/expr-visitor.h +++ b/include/wabt/expr-visitor.h @@ -73,6 +73,7 @@ class ExprVisitor::Delegate { virtual Result EndBlockExpr(BlockExpr*) = 0; virtual Result OnBrExpr(BrExpr*) = 0; virtual Result OnBrIfExpr(BrIfExpr*) = 0; + virtual Result OnBrOnCastExpr(BrOnCastExpr*) = 0; virtual Result OnBrOnNonNullExpr(BrOnNonNullExpr*) = 0; virtual Result OnBrOnNullExpr(BrOnNullExpr*) = 0; virtual Result OnBrTableExpr(BrTableExpr*) = 0; @@ -145,6 +146,24 @@ class ExprVisitor::Delegate { virtual Result OnSimdShuffleOpExpr(SimdShuffleOpExpr*) = 0; virtual Result OnLoadSplatExpr(LoadSplatExpr*) = 0; virtual Result OnLoadZeroExpr(LoadZeroExpr*) = 0; + virtual Result OnArrayCopyExpr(ArrayCopyExpr*) = 0; + virtual Result OnArrayFillExpr(ArrayFillExpr*) = 0; + virtual Result OnArrayGetExpr(ArrayGetExpr*) = 0; + virtual Result OnArrayInitDataExpr(ArrayInitDataExpr*) = 0; + virtual Result OnArrayInitElemExpr(ArrayInitElemExpr*) = 0; + virtual Result OnArrayNewExpr(ArrayNewExpr*) = 0; + virtual Result OnArrayNewDataExpr(ArrayNewDataExpr*) = 0; + virtual Result OnArrayNewDefaultExpr(ArrayNewDefaultExpr*) = 0; + virtual Result OnArrayNewElemExpr(ArrayNewElemExpr*) = 0; + virtual Result OnArrayNewFixedExpr(ArrayNewFixedExpr*) = 0; + virtual Result OnArraySetExpr(ArraySetExpr*) = 0; + virtual Result OnGCUnaryExpr(GCUnaryExpr*) = 0; + virtual Result OnRefCastExpr(RefCastExpr*) = 0; + virtual Result OnRefTestExpr(RefTestExpr*) = 0; + virtual Result OnStructGetExpr(StructGetExpr*) = 0; + virtual Result OnStructNewExpr(StructNewExpr*) = 0; + virtual Result OnStructNewDefaultExpr(StructNewDefaultExpr*) = 0; + virtual Result OnStructSetExpr(StructSetExpr*) = 0; }; class ExprVisitor::DelegateNop : public ExprVisitor::Delegate { @@ -154,6 +173,7 @@ 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 OnBrOnCastExpr(BrOnCastExpr*) 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; } @@ -230,6 +250,28 @@ class ExprVisitor::DelegateNop : public ExprVisitor::Delegate { Result OnSimdShuffleOpExpr(SimdShuffleOpExpr*) override { return Result::Ok; } Result OnLoadSplatExpr(LoadSplatExpr*) override { return Result::Ok; } Result OnLoadZeroExpr(LoadZeroExpr*) override { return Result::Ok; } + Result OnArrayCopyExpr(ArrayCopyExpr*) override { return Result::Ok; } + Result OnArrayFillExpr(ArrayFillExpr*) override { return Result::Ok; } + Result OnArrayGetExpr(ArrayGetExpr*) override { return Result::Ok; } + Result OnArrayInitDataExpr(ArrayInitDataExpr*) override { return Result::Ok; } + Result OnArrayInitElemExpr(ArrayInitElemExpr*) override { return Result::Ok; } + Result OnArrayNewExpr(ArrayNewExpr*) override { return Result::Ok; } + Result OnArrayNewDataExpr(ArrayNewDataExpr*) override { return Result::Ok; } + Result OnArrayNewDefaultExpr(ArrayNewDefaultExpr*) override { + return Result::Ok; + } + Result OnArrayNewElemExpr(ArrayNewElemExpr*) override { return Result::Ok; } + Result OnArrayNewFixedExpr(ArrayNewFixedExpr*) override { return Result::Ok; } + Result OnArraySetExpr(ArraySetExpr*) override { return Result::Ok; } + Result OnGCUnaryExpr(GCUnaryExpr*) override { return Result::Ok; } + Result OnRefCastExpr(RefCastExpr*) override { return Result::Ok; } + Result OnRefTestExpr(RefTestExpr*) override { return Result::Ok; } + Result OnStructGetExpr(StructGetExpr*) override { return Result::Ok; } + Result OnStructNewExpr(StructNewExpr*) override { return Result::Ok; } + Result OnStructNewDefaultExpr(StructNewDefaultExpr*) override { + return Result::Ok; + } + Result OnStructSetExpr(StructSetExpr*) override { return Result::Ok; } }; } // namespace wabt diff --git a/include/wabt/interp/interp-inl.h b/include/wabt/interp/interp-inl.h index 6125999a9b..6ee6bc9dcd 100644 --- a/include/wabt/interp/interp-inl.h +++ b/include/wabt/interp/interp-inl.h @@ -32,6 +32,50 @@ inline bool operator!=(Ref lhs, Ref rhs) { return lhs.index != rhs.index; } +// static +inline Ref Ref::CreateI31Val(size_t value) { + assert((value & 0x7fffffff) < kI31Value); + return Ref((value & 0x7fffffff) | kI31Value); +} + +// static +inline Ref Ref::CreateHostVal(size_t value) { + assert(value < kHostValue); + return Ref(value | kHostValue); +} + +inline bool Ref::IsI31Val() const { + return (index & kI31Value) != 0; +} + +inline bool Ref::IsHostVal() const { + return (index & (kI31Value | kHostValue)) == kHostValue; +} + +inline bool Ref::IsI31OrHostVal() const { + return (index & (kI31Value | kHostValue)) != 0; +} + +inline u32 Ref::GetS32Val() const { + assert(IsI31Val()); + return static_cast(static_cast(index) << 1) >> 1; +} + +inline u32 Ref::GetU32Val() const { + assert(IsI31Val()); + return static_cast(index & 0x7fffffff); +} + +inline size_t Ref::GetHostVal() const { + assert(IsHostVal()); + return index ^ kHostValue; +} + +inline size_t Ref::IsAnyHostVal() const { + assert(IsHostVal()); + return index == (kHostValue | kAnyHostValue); +} + //// ExternType //// inline ExternType::ExternType(ExternKind kind) : kind(kind) {} @@ -42,7 +86,24 @@ inline bool FuncType::classof(const ExternType* type) { } inline FuncType::FuncType(ValueTypes params, ValueTypes results) - : ExternType(ExternKind::Func), params(params), results(results), func_types(nullptr) {} + : ExternType(ExternKind::Func), + params(params), + results(results), + func_types(nullptr) {} + +inline FuncType::FuncType(TypeKind kind, ValueTypes params, ValueTypes results) + : ExternType(ExternKind::Func), + kind(kind), + canonical_index(kInvalidIndex), + canonical_sub_index(kInvalidIndex), + is_final_sub_type(true), + recursive_start(0), + recursive_count(0), + params(params), + results(results), + func_types(nullptr) { + assert((kind == TypeKind::Struct || kind == TypeKind::Array) && params.size() == results.size()); +} //// TableType //// // static @@ -142,6 +203,7 @@ inline Frame::Frame(Ref func, //// FreeList //// template <> inline bool FreeList::IsUsed(Index index) const { + assert(index < list_.size()); return (list_[index].index & refFreeBit) == 0; } @@ -178,6 +240,7 @@ inline void FreeList::Delete(Index index) { template bool FreeList::IsUsed(Index index) const { + assert(index < list_.size()); return (reinterpret_cast(list_[index]) & ptrFreeBit) == 0; } @@ -474,12 +537,13 @@ template <> inline void WABT_VECTORCALL Value::Set(Ref val) { ref_ = val; S //// Store //// inline bool Store::IsValid(Ref ref) const { - return objects_.IsUsed(ref.index) && objects_.Get(ref.index); + return ref.index >= Ref::kHostValue || objects_.IsUsed(ref.index); } template bool Store::Is(Ref ref) const { - return objects_.IsUsed(ref.index) && isa(objects_.Get(ref.index)); + return ref.index < Ref::kHostValue && objects_.IsUsed(ref.index) && + isa(objects_.Get(ref.index)); } template @@ -879,6 +943,73 @@ inline const TagType& Tag::type() const { return type_; } +//// Array //// +// static +inline bool Array::classof(const Object* obj) { + return obj->kind() == skind; +} + +inline Array::Ptr Array::New(Store& store, + u32 size, + Index type_index, + Module* mod) { + return store.Alloc(store, size, type_index, mod); +} + +inline Index Array::Size() const { + return static_cast(items_.size()); +} + +inline Value Array::GetItem(Index idx) const { + return items_[idx]; +} + +inline void Array::SetItem(Index idx, Value value) { + items_[idx] = value; +} + +inline Values& Array::GetItems() { + return items_; +} + +inline Index Array::GetTypeIndex() const { + return type_index_; +} + +inline Ref Array::GetModule() const { + return module_; +} + +//// Struct //// +// static +inline bool Struct::classof(const Object* obj) { + return obj->kind() == skind; +} + +inline Struct::Ptr Struct::New(Store& store, Index type_index, Module* mod) { + return store.Alloc(store, type_index, mod); +} + +inline Index Struct::Size() const { + return static_cast(fields_.size()); +} + +inline Value Struct::GetField(Index idx) const { + return fields_[idx]; +} + +inline void Struct::SetField(Index idx, Value value) { + fields_[idx] = value; +} + +inline Index Struct::GetTypeIndex() const { + return type_index_; +} + +inline Ref Struct::GetModule() const { + return module_; +} + //// ElemSegment //// inline void ElemSegment::Drop() { elements_.clear(); diff --git a/include/wabt/interp/interp.h b/include/wabt/interp/interp.h index 42e6a6b8bb..7107dd760f 100644 --- a/include/wabt/interp/interp.h +++ b/include/wabt/interp/interp.h @@ -89,6 +89,8 @@ enum class ObjectKind { Memory, Global, Tag, + Array, + Struct, Module, Instance, @@ -105,10 +107,24 @@ const char* GetName(ObjectKind); struct Ref { static const Ref Null; + // The highest two bits represent special values. + static const size_t kI31Value = static_cast(1) << (sizeof(size_t) * 8 - 1); + static const size_t kHostValue = static_cast(1) << (sizeof(size_t) * 8 - 2); + static const size_t kAnyHostValue = ~static_cast(0) >> 2; Ref() = default; explicit Ref(size_t index); + static Ref CreateI31Val(size_t value); + static Ref CreateHostVal(size_t value); + bool IsI31Val() const; + bool IsHostVal() const; + bool IsI31OrHostVal() const; + u32 GetS32Val() const; + u32 GetU32Val() const; + size_t GetHostVal() const; + size_t IsAnyHostVal() const; + friend bool operator==(Ref, Ref); friend bool operator!=(Ref, Ref); @@ -178,7 +194,21 @@ struct FuncType : ExternType { static const ExternKind skind = ExternKind::Func; static bool classof(const ExternType* type); + enum class TypeKind { + Func, + Struct, + Array, + }; + + // To simplify the implementation, FuncType may also represent + // Struct and Array types. In the latter case, the mutability + // is stored in results array, which must have the same size + // as params. This implementation might change in the future. + static const Type::Enum Mutable = Type::I32; + static const Type::Enum Immutable = Type::I64; + explicit FuncType(ValueTypes params, ValueTypes results); + explicit FuncType(TypeKind kind, ValueTypes params, ValueTypes results); std::unique_ptr Clone() const override; @@ -186,6 +216,15 @@ struct FuncType : ExternType { const FuncType& actual, std::string* out_msg); + TypeKind kind = FuncType::TypeKind::Func; + // These two are needed for fast dynamic type comparison. + Index canonical_index = kInvalidIndex; + Index canonical_sub_index = kInvalidIndex; + // These three are needed for type equality comparisons + // across different modules (import/export validation). + bool is_final_sub_type = true; + Index recursive_start = 0; + Index recursive_count = 0; ValueTypes params; ValueTypes results; // When params or results contain references, the referenced @@ -976,6 +1015,59 @@ class Tag : public Extern { TagType type_; }; +class Array : public Object { + public: + static bool classof(const Object* obj); + static const ObjectKind skind = ObjectKind::Array; + static const char* GetTypeName() { return "Array"; } + using Ptr = RefPtr; + + static Array::Ptr New(Store&, u32 size, Index type_index, Module* mod); + + bool IsValidRange(u64 offset, u64 size) const; + + Index Size() const; + Value GetItem(Index idx) const; + void SetItem(Index idx, Value value); + Values& GetItems(); + Index GetTypeIndex() const; + Ref GetModule() const; + + private: + friend Store; + explicit Array(Store&, u32 size, Index type_index, Module* mod); + void Mark(Store&) override; + + Ref module_; + Index type_index_; + Values items_; +}; + +class Struct : public Object { + public: + static bool classof(const Object* obj); + static const ObjectKind skind = ObjectKind::Struct; + static const char* GetTypeName() { return "Struct"; } + using Ptr = RefPtr; + + static Struct::Ptr New(Store&, Index type_index, Module* mod); + + Index Size() const; + Value GetField(Index idx) const; + void SetField(Index idx, Value value); + Index GetTypeIndex() const; + Ref GetModule() const; + + private: + friend Store; + explicit Struct(Store&, Index type_index, Module* mod); + void Mark(Store&) override; + + Ref module_; + Index type_index_; + Values fields_; +}; + class ElemSegment { public: explicit ElemSegment(Store& store, const ElemDesc*, RefPtr&); @@ -1144,6 +1236,9 @@ class Thread { void Push(Value); void Push(Ref); + bool CheckRefCast(Ref ref, Type expected); + bool CheckRefFunc(Ref ref, Index expected_index, Func* new_func); + template using UnopFunc = R WABT_VECTORCALL(T); template @@ -1247,6 +1342,23 @@ class Thread { template RunResult DoAtomicRmwCmpxchg(Instr, Trap::Ptr* out_trap); + RunResult DoArrayCopy(Trap::Ptr* out_trap); + RunResult DoArrayFill(Trap::Ptr* out_trap); + RunResult DoArrayGet(Trap::Ptr* out_trap); + RunResult DoArrayInitElem(Instr, Trap::Ptr* out_trap); + RunResult DoArrayInitData(Instr, Trap::Ptr* out_trap); + RunResult DoArrayGetPacked(Instr, Trap::Ptr* out_trap); + RunResult DoArrayNew(Instr); + RunResult DoArrayNewData(Instr, Trap::Ptr* out_trap); + RunResult DoArrayNewElem(Instr, Trap::Ptr* out_trap); + RunResult DoArrayNewFixed(Instr); + RunResult DoArraySet(Trap::Ptr* out_trap); + RunResult DoBrOnCast(Instr); + RunResult DoRefCast(Instr, Trap::Ptr* out_trap); + RunResult DoRefTest(Instr); + RunResult DoStructGetPacked(Instr, Trap::Ptr* out_trap); + RunResult DoStructNew(Instr); + RunResult DoThrow(Exception::Ptr exn_ref); RunResult StepInternal(Trap::Ptr* out_trap); diff --git a/include/wabt/interp/istream.h b/include/wabt/interp/istream.h index f8eb6a2679..779a750685 100644 --- a/include/wabt/interp/istream.h +++ b/include/wabt/interp/istream.h @@ -47,14 +47,20 @@ enum class InstrKind { Imm_0_Op_1, // i32.eqz Imm_0_Op_2, // i32.add Imm_0_Op_3, // select + Imm_0_Op_4, // array.fill + Imm_0_Op_5, // array.copy Imm_Jump_Op_0, // br Imm_Jump_Op_1, // br_if Imm_Index_Op_0, // global.get Imm_Index_Op_1, // global.set Imm_Index_Op_2, // table.set Imm_Index_Op_3, // memory.fill + Imm_Index_Op_4, // array.init_elem Imm_Index_Op_N, // call + Imm_Index_Index_Op_1, // struct.get_s + Imm_Index_Index_Op_2, // array.new_data Imm_Index_Index_Op_3, // memory.init + Imm_Index_Index_Op_4, // array.init_data Imm_Index_Index_Op_N, // call_indirect Imm_Index_Offset_Op_1, // i32.load Imm_Index_Offset_Op_2, // i32.store diff --git a/include/wabt/ir.h b/include/wabt/ir.h index c5ca49dc8b..c0e526869d 100644 --- a/include/wabt/ir.h +++ b/include/wabt/ir.h @@ -110,6 +110,7 @@ using VarVector = std::vector; struct Const { static constexpr uintptr_t kRefNullBits = ~uintptr_t(0); + static constexpr uintptr_t kRefAnyValueBits = ~uintptr_t(1); Const() : Const(Type::I32, uint32_t(0)) {} @@ -180,9 +181,16 @@ struct Const { set_f64(0); set_expected_nan(0, nan); } - void set_funcref() { From(Type::FuncRef, 0); } + void set_arrayref() { From(Type(Type::ArrayRef, Type::ReferenceNonNull), 0); } + // AnyRef represents ref.host. + void set_anyref(uintptr_t x) { From(Type::AnyRef, x); } + void set_any(uintptr_t x) { From(Type(Type::AnyRef, Type::ReferenceNonNull), x); } + void set_eqref() { From(Type(Type::EqRef, Type::ReferenceNonNull), 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_funcref() { From(Type::FuncRef, 0); } + void set_i31ref() { From(Type(Type::I31Ref, Type::ReferenceNonNull), 0); } + void set_structref() { From(Type(Type::StructRef, Type::ReferenceNonNull), 0); } void set_null(Type type) { From(type, kRefNullBits); } bool is_expected_nan(int lane = 0) const { @@ -297,6 +305,19 @@ enum class TypeEntryKind { Array, }; +struct TypeEntrySupertypesInfo { + TypeEntrySupertypesInfo(bool is_final_sub_type) + : is_final_sub_type(is_final_sub_type) {} + + void InitSubTypes(Index* sub_type_list, Index sub_type_count); + + bool is_final_sub_type; + // The binary/text format allows any number of subtypes, + // so parsers must handle them. The validator rejects + // lists which size is greater than 1. + VarVector sub_types; +}; + class TypeEntry { public: WABT_DISALLOW_COPY_AND_ASSIGN(TypeEntry); @@ -307,12 +328,17 @@ class TypeEntry { Location loc; std::string name; + TypeEntrySupertypesInfo supertypes; protected: explicit TypeEntry(TypeEntryKind kind, + bool is_final_sub_type, std::string_view name = std::string_view(), const Location& loc = Location()) - : loc(loc), name(name), kind_(kind) {} + : loc(loc), + name(name), + supertypes(is_final_sub_type), + kind_(kind) {} TypeEntryKind kind_; }; @@ -323,8 +349,8 @@ class FuncType : public TypeEntry { return entry->kind() == TypeEntryKind::Func; } - explicit FuncType(std::string_view name = std::string_view()) - : TypeEntry(TypeEntryKind::Func, name) {} + explicit FuncType(bool is_final_sub_type, std::string_view name = std::string_view()) + : TypeEntry(TypeEntryKind::Func, is_final_sub_type, name) {} Index GetNumParams() const { return sig.GetNumParams(); } Index GetNumResults() const { return sig.GetNumResults(); } @@ -353,8 +379,8 @@ class StructType : public TypeEntry { return entry->kind() == TypeEntryKind::Struct; } - explicit StructType(std::string_view name = std::string_view()) - : TypeEntry(TypeEntryKind::Struct) {} + explicit StructType(bool is_final_sub_type, std::string_view name = std::string_view()) + : TypeEntry(TypeEntryKind::Struct, is_final_sub_type, name) {} std::vector fields; }; @@ -365,12 +391,19 @@ class ArrayType : public TypeEntry { return entry->kind() == TypeEntryKind::Array; } - explicit ArrayType(std::string_view name = std::string_view()) - : TypeEntry(TypeEntryKind::Array) {} + explicit ArrayType(bool is_final_sub_type, std::string_view name = std::string_view()) + : TypeEntry(TypeEntryKind::Array, is_final_sub_type, name) {} Field field; }; +struct RecGroupRange { + Index first_type_index; + Index type_count; + + Index EndTypeIndex() const { return first_type_index + type_count; } +}; + struct FuncDeclaration { Index GetNumParams() const { return sig.GetNumParams(); } Index GetNumResults() const { return sig.GetNumResults(); } @@ -383,6 +416,17 @@ struct FuncDeclaration { }; enum class ExprType { + ArrayCopy, + ArrayFill, + ArrayGet, + ArrayInitData, + ArrayInitElem, + ArrayNew, + ArrayNewData, + ArrayNewDefault, + ArrayNewElem, + ArrayNewFixed, + ArraySet, AtomicLoad, AtomicRmw, AtomicRmwCmpxchg, @@ -394,6 +438,7 @@ enum class ExprType { Block, Br, BrIf, + BrOnCast, BrOnNonNull, BrOnNull, BrTable, @@ -405,6 +450,7 @@ enum class ExprType { Const, Convert, Drop, + GCUnary, GlobalGet, GlobalSet, If, @@ -421,9 +467,11 @@ enum class ExprType { MemorySize, Nop, RefAsNonNull, + RefCast, RefIsNull, RefFunc, RefNull, + RefTest, Rethrow, Return, ReturnCall, @@ -434,6 +482,10 @@ enum class ExprType { SimdLoadLane, SimdStoreLane, SimdShuffleOp, + StructGet, + StructNew, + StructNewDefault, + StructSet, LoadSplat, LoadZero, Store, @@ -453,7 +505,7 @@ enum class ExprType { Unary, Unreachable, - First = AtomicLoad, + First = ArrayCopy, Last = Unreachable }; @@ -590,6 +642,7 @@ class OpcodeExpr : public ExprMixin { using BinaryExpr = OpcodeExpr; using CompareExpr = OpcodeExpr; using ConvertExpr = OpcodeExpr; +using GCUnaryExpr = OpcodeExpr; using UnaryExpr = OpcodeExpr; using TernaryExpr = OpcodeExpr; using RefAsNonNullExpr = OpcodeExpr; @@ -695,6 +748,15 @@ using TableFillExpr = VarExpr; using MemoryInitExpr = MemoryVarExpr; +using ArrayFillExpr = VarExpr; +using ArrayNewExpr = VarExpr; +using ArrayNewDefaultExpr = VarExpr; +using ArraySetExpr = VarExpr; +using RefCastExpr = VarExpr; +using RefTestExpr = VarExpr; +using StructNewExpr = VarExpr; +using StructNewDefaultExpr = VarExpr; + class SelectExpr : public ExprMixin { public: SelectExpr(const Location& loc = Location()) @@ -873,6 +935,62 @@ class AtomicFenceExpr : public ExprMixin { uint32_t consistency_model; }; +class ArrayGetExpr : public ExprMixin { + public: + ArrayGetExpr(Opcode opcode, const Var& type_var, const Location& loc = Location()) + : ExprMixin(loc), opcode(opcode), type_var(type_var) {} + + Opcode opcode; + Var type_var; +}; + +template +class TypeVarExpr : public ExprMixin { + public: + TypeVarExpr(const Var& type_var, const Var& var, const Location& loc = Location()) + : ExprMixin(loc), type_var(type_var), var(var) {} + + Var type_var; + Var var; +}; + +using ArrayCopyExpr = TypeVarExpr; +using ArrayInitDataExpr = TypeVarExpr; +using ArrayInitElemExpr = TypeVarExpr; +using ArrayNewDataExpr = TypeVarExpr; +using ArrayNewElemExpr = TypeVarExpr; +using StructSetExpr = TypeVarExpr; + +class ArrayNewFixedExpr : public ExprMixin { + public: + ArrayNewFixedExpr(const Var& type_var, Index count, const Location& loc = Location()) + : ExprMixin(loc), type_var(type_var), count(count) {} + + Var type_var; + Index count; +}; + +class StructGetExpr : public ExprMixin { + public: + StructGetExpr(Opcode opcode, const Var& type_var, const Var& var, const Location& loc = Location()) + : ExprMixin(loc), opcode(opcode), type_var(type_var), var(var) {} + + Opcode opcode; + Var type_var; + Var var; +}; + +class BrOnCastExpr : public ExprMixin { + public: + BrOnCastExpr(Opcode opcode, const Var& label_var, const Var& type1_var, const Var& type2_var, const Location& loc = Location()) + : ExprMixin(loc), opcode(opcode), label_var(label_var), type1_var(type1_var), type2_var(type2_var) {} + + Opcode opcode; + Var label_var; + Var type1_var; + Var type2_var; +}; + struct Tag { explicit Tag(std::string_view name) : name(name) {} @@ -1259,6 +1377,10 @@ struct Module { Index GetFuncTypeIndex(const FuncSignature&) const; const FuncType* GetFuncType(const Var&) const; FuncType* GetFuncType(const Var&); + const StructType* GetStructType(const Var&) const; + StructType* GetStructType(const Var&); + const ArrayType* GetArrayType(const Var&) const; + ArrayType* GetArrayType(const Var&); Index GetFuncIndex(const Var&) const; const Func* GetFunc(const Var&) const; Func* GetFunc(const Var&); @@ -1319,6 +1441,8 @@ struct Module { std::vector imports; std::vector exports; std::vector types; + // Ordered list of recursive group type ranges. + std::vector rec_group_ranges; std::vector tables; std::vector elem_segments; std::vector memories; @@ -1578,6 +1702,78 @@ struct Script { BindingHash module_bindings; }; +struct Component; +class ComponentCoreModule; +class ComponentComponent; + +class ComponentDefinition { + public: + enum class Type { + // Same as ComponentBinarySection in binary.h + CoreModule = 1, + CoreInstance = 2, + CoreType = 3, + Component = 4, + Instance = 5, + }; + + virtual ~ComponentDefinition() {} + + Type type() const { + return type_; + } + + ComponentCoreModule* AsCoreModule() { + assert(type() == Type::CoreModule); + return reinterpret_cast(this); + } + + ComponentComponent* AsComponent() { + assert(type() == Type::Component); + return reinterpret_cast(this); + } + + protected: + ComponentDefinition(Type type) + : type_(type) {} + + private: + Type type_; +}; + +class ComponentCoreModule : public ComponentDefinition { + public: + ComponentCoreModule() + : ComponentDefinition(Type::CoreModule) {} + + Module* module() { + return &module_; + } + + private: + Module module_; +}; + +struct Component { + Component* parent = nullptr; + std::vector> definitions; +}; + +class ComponentComponent : public ComponentDefinition { + public: + ComponentComponent(Component* parent) + : ComponentDefinition(Type::Component) { + component_.parent = parent; + } + + Component* component() { + return &component_; + } + + private: + Component component_; +}; + void MakeTypeBindingReverseMapping( size_t num_types, const BindingHash& bindings, diff --git a/include/wabt/opcode.def b/include/wabt/opcode.def index 901c0359a8..78201cfcbe 100644 --- a/include/wabt/opcode.def +++ b/include/wabt/opcode.def @@ -268,10 +268,44 @@ 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, 0xd3, RefEq, "ref.eq", "") 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", "") +/* Garbage collection opcodes */ +WABT_OPCODE(___, ___, ___, ___, 0, 0xfb, 0x00, StructNew, "struct.new", "") +WABT_OPCODE(___, ___, ___, ___, 0, 0xfb, 0x01, StructNewDefault, "struct.new_default", "") +WABT_OPCODE(___, ___, ___, ___, 0, 0xfb, 0x02, StructGet, "struct.get", "") +WABT_OPCODE(___, ___, ___, ___, 0, 0xfb, 0x03, StructGetS, "struct.get_s", "") +WABT_OPCODE(___, ___, ___, ___, 0, 0xfb, 0x04, StructGetU, "struct.get_u", "") +WABT_OPCODE(___, ___, ___, ___, 0, 0xfb, 0x05, StructSet, "struct.set", "") +WABT_OPCODE(___, ___, I32, ___, 0, 0xfb, 0x06, ArrayNew, "array.new", "") +WABT_OPCODE(___, I32, ___, ___, 0, 0xfb, 0x07, ArrayNewDefault, "array.new_default", "") +WABT_OPCODE(___, ___, ___, ___, 0, 0xfb, 0x08, ArrayNewFixed, "array.new_fixed", "") +WABT_OPCODE(___, I32, I32, ___, 0, 0xfb, 0x09, ArrayNewData, "array.new_data", "") +WABT_OPCODE(___, I32, I32, ___, 0, 0xfb, 0x0a, ArrayNewElem, "array.new_elem", "") +WABT_OPCODE(___, ___, I32, ___, 0, 0xfb, 0x0b, ArrayGet, "array.get", "") +WABT_OPCODE(___, ___, I32, ___, 0, 0xfb, 0x0c, ArrayGetS, "array.get_s", "") +WABT_OPCODE(___, ___, I32, ___, 0, 0xfb, 0x0d, ArrayGetU, "array.get_u", "") +WABT_OPCODE(___, ___, I32, ___, 0, 0xfb, 0x0e, ArraySet, "array.set", "") +WABT_OPCODE(I32, ___, ___, ___, 0, 0xfb, 0x0f, ArrayLen, "array.len", "") +WABT_OPCODE(___, ___, I32, ___, 0, 0xfb, 0x10, ArrayFill, "array.fill", "") +WABT_OPCODE(___, ___, I32, ___, 0, 0xfb, 0x11, ArrayCopy, "array.copy", "") +WABT_OPCODE(___, ___, I32, I32, 0, 0xfb, 0x12, ArrayInitData, "array.init_data", "") +WABT_OPCODE(___, ___, I32, I32, 0, 0xfb, 0x13, ArrayInitElem, "array.init_elem", "") +WABT_OPCODE(I32, ___, ___, ___, 0, 0xfb, 0x14, RefTest, "ref.test", "") +WABT_OPCODE(I32, ___, ___, ___, 0, 0xfb, 0x15, RefTestNull, "ref.test", "") +WABT_OPCODE(___, ___, ___, ___, 0, 0xfb, 0x16, RefCast, "ref.cast", "") +WABT_OPCODE(___, ___, ___, ___, 0, 0xfb, 0x17, RefCastNull, "ref.cast", "") +WABT_OPCODE(___, ___, ___, ___, 0, 0xfb, 0x18, BrOnCast, "br_on_cast", "") +WABT_OPCODE(___, ___, ___, ___, 0, 0xfb, 0x19, BrOnCastFail, "br_on_cast_fail", "") +WABT_OPCODE(___, ___, ___, ___, 0, 0xfb, 0x1a, AnyConvertExtern, "any.convert_extern", "") +WABT_OPCODE(___, ___, ___, ___, 0, 0xfb, 0x1b, ExternConvertAny, "extern.convert_any", "") +WABT_OPCODE(___, I32, ___, ___, 0, 0xfb, 0x1c, RefI31, "ref.i31", "") +WABT_OPCODE(I32, ___, ___, ___, 0, 0xfb, 0x1d, I31GetS, "i31.get_s", "") +WABT_OPCODE(I32, ___, ___, ___, 0, 0xfb, 0x1e, I31GetU, "i31.get_u", "") + /* Simd opcodes */ WABT_OPCODE(V128, I32, ___, ___, 16, 0xfd, 0x00, V128Load, "v128.load", "") WABT_OPCODE(V128, I32, ___, ___, 8, 0xfd, 0x01, V128Load8X8S, "v128.load8x8_s", "") diff --git a/include/wabt/opcode.h b/include/wabt/opcode.h index a7c7b2495a..e63658852a 100644 --- a/include/wabt/opcode.h +++ b/include/wabt/opcode.h @@ -84,7 +84,7 @@ struct Opcode { Address GetAlignment(Address alignment) const; static bool IsPrefixByte(uint8_t byte) { - return byte == kMathPrefix || byte == kThreadsPrefix || byte == kSimdPrefix; + return byte == kMathPrefix || byte == kThreadsPrefix || byte == kGarbageCollectionPrefix || byte == kSimdPrefix; } bool IsEnabled(const Features& features) const; @@ -93,6 +93,7 @@ struct Opcode { private: static constexpr uint32_t kMathPrefix = 0xfc; static constexpr uint32_t kThreadsPrefix = 0xfe; + static constexpr uint32_t kGarbageCollectionPrefix = 0xfb; static constexpr uint32_t kSimdPrefix = 0xfd; struct Info { diff --git a/include/wabt/shared-validator.h b/include/wabt/shared-validator.h index b333533bc8..c37d022531 100644 --- a/include/wabt/shared-validator.h +++ b/include/wabt/shared-validator.h @@ -29,8 +29,6 @@ #include "wabt/opcode.h" #include "wabt/type-checker.h" -#include "wabt/binary-reader.h" // For TypeMut. - namespace wabt { struct ValidateOptions { @@ -48,7 +46,11 @@ enum class TableImportStatus { class SharedValidator { public: WABT_DISALLOW_COPY_AND_ASSIGN(SharedValidator); + using TypeEntry = TypeChecker::TypeEntry; using FuncType = TypeChecker::FuncType; + using StructType = TypeChecker::StructType; + using ArrayType = TypeChecker::ArrayType; + using RecGroup = TypeChecker::RecGroup; SharedValidator(Errors*, const ValidateOptions& options); // TODO: Move into SharedValidator? @@ -68,22 +70,35 @@ class SharedValidator { Index GetLocalCount() const; + // The canonical index of a type is the index of the first type, + // which is equal to the original type. The canonical index is + // always less or equal than type_index. + Index GetCanonicalTypeIndex(Index type_index); + Result EndModule(); + Result OnRecursiveType(Index first_type_index, Index type_count); Result OnFuncType(const Location&, Index param_count, const Type* param_types, Index result_count, const Type* result_types, - Index type_index); - Result OnStructType(const Location&, Index field_count, TypeMut* fields); - Result OnArrayType(const Location&, TypeMut field); + Index type_index, + SupertypesInfo* supertypes); + Result OnStructType(const Location&, + Index field_count, + TypeMut* fields, + SupertypesInfo* supertypes); + Result OnArrayType(const Location&, + TypeMut field, + SupertypesInfo* supertypes); Result OnFunction(const Location&, Var sig_var); Result OnTable(const Location&, Type elem_type, const Limits&, TableImportStatus import_status, TableInitExprStatus init_provided); Result OnMemory(const Location&, const Limits&, uint32_t page_size); Result OnGlobalImport(const Location&, Type type, bool mutable_); - Result OnGlobal(const Location&, Type type, bool mutable_); + Result BeginGlobal(const Location&, Type type, bool mutable_); + Result EndGlobal(const Location&); Result OnTag(const Location&, Var sig_var); Result OnExport(const Location&, @@ -106,6 +121,17 @@ class SharedValidator { Result EndFunctionBody(const Location&); Result OnLocalDecl(const Location&, Index count, Type type); + Result OnArrayCopy(const Location&, Var dst_type, Var src_type); + Result OnArrayFill(const Location&, Var type); + Result OnArrayGet(const Location&, Opcode, Var type); + Result OnArrayInitData(const Location&, Var type, Var segment_var); + Result OnArrayInitElem(const Location&, Var type, Var segment_var); + Result OnArrayNew(const Location&, Var type); + Result OnArrayNewData(const Location&, Var type, Var segment_var); + Result OnArrayNewDefault(const Location&, Var type); + Result OnArrayNewElem(const Location&, Var type, Var segment_var); + Result OnArrayNewFixed(const Location&, Var type, Index count); + Result OnArraySet(const Location&, Var type); Result OnAtomicFence(const Location&, uint32_t consistency_model); Result OnAtomicLoad(const Location&, Opcode, @@ -141,6 +167,10 @@ class SharedValidator { Result OnBlock(const Location&, Type sig_type); Result OnBr(const Location&, Var depth); Result OnBrIf(const Location&, Var depth); + Result OnBrOnCast(const Location&, + Opcode, Var depth, + Var type1_var, + Var type2_var); Result OnBrOnNonNull(const Location&, Var depth); Result OnBrOnNull(const Location&, Var depth); Result BeginBrTable(const Location&); @@ -159,6 +189,7 @@ class SharedValidator { Result OnElemDrop(const Location&, Var segment_var); Result OnElse(const Location&); Result OnEnd(const Location&); + Result OnGCUnary(const Location&, Opcode); Result OnGlobalGet(const Location&, Var); Result OnGlobalSet(const Location&, Var); Result OnIf(const Location&, Type sig_type); @@ -184,9 +215,11 @@ class SharedValidator { Result OnMemorySize(const Location&, Var memidx); Result OnNop(const Location&); Result OnRefAsNonNull(const Location&); + Result OnRefCast(const Location&, Var type_var); Result OnRefFunc(const Location&, Var func_var); Result OnRefIsNull(const Location&); Result OnRefNull(const Location&, Var func_type_var); + Result OnRefTest(const Location&, Var 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); @@ -212,6 +245,10 @@ class SharedValidator { Var memidx, Address align, Address offset); + Result OnStructGet(const Location&, Opcode, Var type, Var field); + Result OnStructNew(const Location&, Var type); + Result OnStructNewDefault(const Location&, Var type); + Result OnStructSet(const Location&, Var type, Var field); Result OnTableCopy(const Location&, Var dst_var, Var src_var); Result OnTableFill(const Location&, Var table_var); Result OnTableGet(const Location&, Var table_var); @@ -230,20 +267,6 @@ class SharedValidator { Result OnUnreachable(const Location&); private: - struct StructType { - StructType() = default; - StructType(const TypeMutVector& fields) : fields(fields) {} - - TypeMutVector fields; - }; - - struct ArrayType { - ArrayType() = default; - ArrayType(TypeMut field) : field(field) {} - - TypeMut field; - }; - struct TableType { TableType() = default; TableType(Type element, Limits limits) : element(element), limits(limits) {} @@ -299,7 +322,11 @@ class SharedValidator { Type actual, Type expected, const char* desc); - Result CheckReferenceType(const Location&, Type type, const char* desc); + Result CheckReferenceType(const Location&, + Type type, + Index end_index, + const char* desc); + Result CheckSupertypes(const Location&, SupertypesInfo* supertypes); Result CheckLimits(const Location&, const Limits&, uint64_t absolute_max, @@ -315,7 +342,9 @@ class SharedValidator { const std::vector& values, T* out, const char* desc); - Result CheckFuncTypeIndex(Var sig_var, FuncType* out = nullptr); + Result CheckFuncTypeIndex(Var sig_var, FuncType* out); + Result CheckStructTypeIndex(Var type_var, Type* out_ref, StructType* out); + Result CheckArrayTypeIndex(Var type_var, Type* out_ref, TypeMut* out); Result CheckFuncIndex(Var func_var, FuncType* out = nullptr); Result CheckTableIndex(Var table_var, TableType* out = nullptr); Result CheckMemoryIndex(Var memory_var, MemoryType* out = nullptr); @@ -344,6 +373,8 @@ class SharedValidator { void RestoreLocalRefs(Result result); void IgnoreLocalRefs(); + Index GetEndIndex(); + ValidateOptions options_; Errors* errors_; TypeChecker typechecker_; // TODO: Move into SharedValidator. @@ -351,10 +382,7 @@ class SharedValidator { Location expr_loc_ = Location(kInvalidOffset); bool in_init_expr_ = false; - Index num_types_ = 0; - std::map func_types_; - std::map struct_types_; - std::map array_types_; + TypeChecker::TypeFields type_fields_; std::vector funcs_; // Includes imported and defined. std::vector tables_; // Includes imported and defined. @@ -363,8 +391,11 @@ class SharedValidator { std::vector tags_; // Includes imported and defined. std::vector elems_; Index starts_ = 0; - Index num_imported_globals_ = 0; + Index last_initialized_global_ = 0; Index data_segments_ = 0; + Index last_rec_type_end_ = 0; + // Recursive type checks may enter to infinite loop for invalid values. + Result type_validation_result_ = Result::Ok; // Includes parameters, since this is only used for validating // local.{get,set,tee} instructions. diff --git a/include/wabt/token.def b/include/wabt/token.def index 22b333cb73..ede54a8096 100644 --- a/include/wabt/token.def +++ b/include/wabt/token.def @@ -21,7 +21,6 @@ /* Tokens with no additional data (i.e. bare). */ WABT_TOKEN(Invalid, "Invalid") WABT_TOKEN(After, "after") -WABT_TOKEN(Array, "array") WABT_TOKEN(AssertException, "assert_exception") WABT_TOKEN(AssertExhaustion, "assert_exhaustion") WABT_TOKEN(AssertInvalid, "assert_invalid") @@ -32,6 +31,8 @@ WABT_TOKEN(AssertUnlinkable, "assert_unlinkable") WABT_TOKEN(Before, "before") WABT_TOKEN(Bin, "bin") WABT_TOKEN(Item, "item") +WABT_TOKEN(Component, "component") +WABT_TOKEN(Core, "core") WABT_TOKEN(Data, "data") WABT_TOKEN(Declare, "declare") WABT_TOKEN(Delegate, "delegate") @@ -42,12 +43,14 @@ WABT_TOKEN(Eof, "EOF") WABT_TOKEN(Tag, "tag") WABT_TOKEN(Export, "export") WABT_TOKEN(Field, "field") +WABT_TOKEN(Final, "final") WABT_TOKEN(Function, "function") WABT_TOKEN(Get, "get") WABT_TOKEN(Global, "global") WABT_TOKEN(Import, "import") WABT_TOKEN(Invoke, "invoke") WABT_TOKEN(Input, "input") +WABT_TOKEN(Instance, "instance") WABT_TOKEN(Local, "local") WABT_TOKEN(Lpar, "(") WABT_TOKEN(Memory, "memory") @@ -61,13 +64,17 @@ WABT_TOKEN(Output, "output") WABT_TOKEN(PageSize, "pagesize") WABT_TOKEN(Param, "param") WABT_TOKEN(Ref, "ref") +WABT_TOKEN(RefArray, "ref.array") +WABT_TOKEN(RefHost, "ref.host") +WABT_TOKEN(RefStruct, "ref.struct") WABT_TOKEN(Quote, "quote") +WABT_TOKEN(Rec, "rec") WABT_TOKEN(Register, "register") WABT_TOKEN(Result, "result") WABT_TOKEN(Rpar, ")") WABT_TOKEN(Shared, "shared") WABT_TOKEN(Start, "start") -WABT_TOKEN(Struct, "struct") +WABT_TOKEN(Sub, "sub") WABT_TOKEN(Table, "table") WABT_TOKEN(Then, "then") WABT_TOKEN(Type, "type") @@ -88,6 +95,19 @@ WABT_TOKEN_FIRST(Literal, Float) WABT_TOKEN_LAST(Literal, Nat) /* Tokens with Opcode data. */ +WABT_TOKEN(ArrayCopy, "array.copy") +WABT_TOKEN(ArrayFill, "array.fill") +WABT_TOKEN(ArrayGet, "array.get") +WABT_TOKEN(ArrayGetS, "array.get_s") +WABT_TOKEN(ArrayGetU, "array.get_u") +WABT_TOKEN(ArrayInitData, "array.init_data") +WABT_TOKEN(ArrayInitElem, "array.init_elem") +WABT_TOKEN(ArrayNew, "array.new") +WABT_TOKEN(ArrayNewData, "array.new_data") +WABT_TOKEN(ArrayNewDefault, "array.new_default") +WABT_TOKEN(ArrayNewFixed, "array.new_fixed") +WABT_TOKEN(ArrayNewElem, "array.new_elem") +WABT_TOKEN(ArraySet, "array.set") WABT_TOKEN(AtomicFence, "atomic.fence") WABT_TOKEN(AtomicLoad, "ATOMIC_LOAD") WABT_TOKEN(AtomicNotify, "ATOMIC_NOTIFY") @@ -99,6 +119,7 @@ WABT_TOKEN(Binary, "BINARY") WABT_TOKEN(Block, "block") WABT_TOKEN(Br, "br") WABT_TOKEN(BrIf, "br_if") +WABT_TOKEN(BrOnCast, "br_on_cast") WABT_TOKEN(BrOnNonNull, "br_on_non_null") WABT_TOKEN(BrOnNull, "br_on_null") WABT_TOKEN(BrTable, "br_table") @@ -119,6 +140,7 @@ WABT_TOKEN(Drop, "drop") WABT_TOKEN(ElemDrop, "elem.drop") WABT_TOKEN(Else, "else") WABT_TOKEN(End, "end") +WABT_TOKEN(GCUnary, "GC_UNARY") WABT_TOKEN(GlobalGet, "global.get") WABT_TOKEN(GlobalSet, "global.set") WABT_TOKEN(If, "if") @@ -134,10 +156,14 @@ WABT_TOKEN(MemoryInit, "memory.init") WABT_TOKEN(MemorySize, "memory.size") WABT_TOKEN(Nop, "nop") WABT_TOKEN(RefAsNonNull, "ref.as_non_null") +WABT_TOKEN(RefCast, "ref.cast") +WABT_TOKEN(RefEq, "ref.eq") WABT_TOKEN(RefExtern, "ref.extern") WABT_TOKEN(RefFunc, "ref.func") +WABT_TOKEN(RefI31, "ref.i31") WABT_TOKEN(RefIsNull, "ref.is_null") WABT_TOKEN(RefNull, "ref.null") +WABT_TOKEN(RefTest, "ref.test") WABT_TOKEN(Rethrow, "rethrow") WABT_TOKEN(ReturnCallIndirect, "return_call_indirect") WABT_TOKEN(ReturnCall, "return_call") @@ -149,6 +175,12 @@ WABT_TOKEN(SimdLoadLane, "SIMDLOADLANE") WABT_TOKEN(SimdStoreLane, "SIMDSTORELANE") WABT_TOKEN(SimdShuffleOp, "i8x16.shuffle") WABT_TOKEN(Store, "STORE") +WABT_TOKEN(StructGet, "struct.get") +WABT_TOKEN(StructGetS, "struct.get_s") +WABT_TOKEN(StructGetU, "struct.get_u") +WABT_TOKEN(StructNew, "struct.new") +WABT_TOKEN(StructNewDefault, "struct.new_default") +WABT_TOKEN(StructSet, "struct.set") WABT_TOKEN(TableCopy, "table.copy") WABT_TOKEN(TableFill, "table.fill") WABT_TOKEN(TableGet, "table.get") @@ -163,7 +195,7 @@ WABT_TOKEN(Try, "try") WABT_TOKEN(TryTable, "try_table") WABT_TOKEN(Unary, "UNARY") WABT_TOKEN(Unreachable, "unreachable") -WABT_TOKEN_FIRST(Opcode, AtomicFence) +WABT_TOKEN_FIRST(Opcode, ArrayCopy) WABT_TOKEN_LAST(Opcode, Unreachable) /* Tokens with string data. */ @@ -182,8 +214,16 @@ WABT_TOKEN_FIRST(Type, ValueType) WABT_TOKEN_LAST(Type, ValueType) /* Tokens with Type data, but are reference kinds. */ +WABT_TOKEN(Any, "any") +WABT_TOKEN(Array, "array") WABT_TOKEN(Func, "func") +WABT_TOKEN(Eq, "eq") WABT_TOKEN(Extern, "extern") WABT_TOKEN(Exn, "exn") -WABT_TOKEN_FIRST(RefKind, Func) -WABT_TOKEN_LAST(RefKind, Exn) +WABT_TOKEN(I31, "i31") +WABT_TOKEN(NoExtern, "noextern") +WABT_TOKEN(NoFunc, "nofunc") +WABT_TOKEN(None, "none") +WABT_TOKEN(Struct, "struct") +WABT_TOKEN_FIRST(RefKind, Any) +WABT_TOKEN_LAST(RefKind, Struct) diff --git a/include/wabt/type-checker.h b/include/wabt/type-checker.h index 6bff08b881..634db203c5 100644 --- a/include/wabt/type-checker.h +++ b/include/wabt/type-checker.h @@ -26,12 +26,33 @@ #include "wabt/feature.h" #include "wabt/opcode.h" +#include "wabt/binary-reader.h" // For TypeMut. + namespace wabt { class TypeChecker { public: using ErrorCallback = std::function; + struct TypeEntry { + explicit TypeEntry(Type::Enum kind, Index map_index, Index canonical_index) + : kind(kind), + map_index(map_index), + canonical_index(canonical_index), + is_final_sub_type(true), + first_sub_type(kInvalidIndex) { + assert(kind == Type::FuncRef || kind == Type::StructRef || + kind == Type::ArrayRef); + } + + Type::Enum kind; + Index map_index; + Index canonical_index; + bool is_final_sub_type; + // Currently the sub type list is limited to maximum 1 value. + Index first_sub_type; + }; + struct FuncType { FuncType() = default; FuncType(const TypeVector& params, @@ -44,6 +65,77 @@ class TypeChecker { Index type_index; }; + struct StructType { + StructType() = default; + StructType(const TypeMutVector& fields) : fields(fields) {} + + TypeMutVector fields; + }; + + struct ArrayType { + ArrayType() = default; + ArrayType(TypeMut field) : field(field) {} + + TypeMut field; + }; + + struct RecGroup { + RecGroup(Index start_index, Index type_count) + : start_index(start_index), type_count(type_count), hash(0) {} + + Index start_index; + Index type_count; + uint32_t hash; + }; + + struct TypeFields { + Index NumTypes() { + return static_cast(type_entries.size()); + } + + void PushFunc(FuncType&& func_type) { + Index map_index = static_cast(func_types.size()); + type_entries.emplace_back(TypeEntry(Type::FuncRef, map_index, + NumTypes())); + func_types.emplace_back(func_type); + } + + void PushStruct(StructType&& struct_type) { + Index map_index = static_cast(struct_types.size()); + type_entries.emplace_back(TypeEntry(Type::StructRef, map_index, + NumTypes())); + struct_types.emplace_back(struct_type); + } + + void PushArray(ArrayType&& array_type) { + Index map_index = static_cast(array_types.size()); + type_entries.emplace_back(TypeEntry(Type::ArrayRef, map_index, + NumTypes())); + array_types.emplace_back(array_type); + } + + bool IsValidType(Type type) { + return !type.IsReferenceWithIndex() || + type.GetReferenceIndex() < type_entries.size(); + } + + Type GetGenericType(Type type) { + if (type.IsReferenceWithIndex()) { + return Type(type_entries[type.GetReferenceIndex()].kind, + type == Type::RefNull); + } + return type; + } + + Type GetGroupType(Type type); + + std::vector type_entries; + std::vector func_types; + std::vector struct_types; + std::vector array_types; + std::vector rec_groups; + }; + struct Label { Label(LabelType, const TypeVector& param_types, @@ -62,8 +154,8 @@ class TypeChecker { std::vector local_ref_is_set_; }; - explicit TypeChecker(const Features& features, std::map& func_types) - : features_(features), func_types_(func_types) {} + explicit TypeChecker(const Features& features, TypeFields& type_fields) + : features_(features), type_fields_(type_fields) {} void set_error_callback(const ErrorCallback& error_callback) { error_callback_ = error_callback; @@ -77,6 +169,24 @@ class TypeChecker { Result GetCatchCount(Index depth, Index* out_depth); Result BeginFunction(const TypeVector& sig); + Result OnArrayCopy(Type dst_ref_type, + TypeMut& dst_array_type, + Type src_ref_type, + Type src_array_type); + Result OnArrayFill(Type ref_type, TypeMut& array_type); + Result OnArrayGet(Opcode, Type ref_type, Type array_type); + Result OnArrayInitData(Type ref_type, TypeMut& array_type); + Result OnArrayInitElem(Type ref_type, TypeMut& array_type, Type elem_type); + Result OnArrayNew(Type ref_type, Type array_type); + Result OnArrayNewData(Type ref_type, Type array_type); + Result OnArrayNewDefault(Type ref_type); + Result OnArrayNewElem(Type ref_type, + Type array_type, + Type elem_type); + Result OnArrayNewFixed(Type ref_type, + Type array_type, + Index count); + Result OnArraySet(Type ref_type, const TypeMut& field); Result OnAtomicFence(uint32_t consistency_model); Result OnAtomicLoad(Opcode, const Limits& limits); Result OnAtomicNotify(Opcode, const Limits& limits); @@ -88,6 +198,7 @@ class TypeChecker { Result OnBlock(const TypeVector& param_types, const TypeVector& result_types); Result OnBr(Index depth); Result OnBrIf(Index depth); + Result OnBrOnCast(Opcode opcode, Index depth, Type type1, Type type2); Result OnBrOnNonNull(Index depth); Result OnBrOnNull(Index depth); Result BeginBrTable(); @@ -115,6 +226,7 @@ class TypeChecker { Result OnDrop(); Result OnElse(); Result OnEnd(); + Result OnGCUnary(Opcode); Result OnGlobalGet(Type); Result OnGlobalSet(Type); Result OnIf(const TypeVector& param_types, const TypeVector& result_types); @@ -139,8 +251,10 @@ class TypeChecker { Result OnTableFill(Type elem_type, const Limits& limits); Result OnRefFuncExpr(Index func_type); Result OnRefAsNonNullExpr(); + Result OnRefCast(Type type); Result OnRefNullExpr(Type type); Result OnRefIsNullExpr(); + Result OnRefTest(Type type); Result OnRethrow(Index depth); Result OnReturn(); Result OnSelect(const TypeVector& result_types); @@ -149,6 +263,10 @@ class TypeChecker { Result OnSimdStoreLane(Opcode, const Limits& limits, uint64_t); Result OnSimdShuffleOp(Opcode, v128); Result OnStore(Opcode, const Limits& limits); + Result OnStructGet(Opcode, Type ref_type, const StructType&, Index field); + Result OnStructNew(Type ref_type, const StructType&); + Result OnStructNewDefault(Type ref_type); + Result OnStructSet(Type ref_type, const StructType&, Index field); Result OnTernary(Opcode); Result OnThrow(const TypeVector& sig); Result OnThrowRef(); @@ -164,6 +282,12 @@ class TypeChecker { Result BeginInitExpr(Type type); Result EndInitExpr(); + uint32_t UpdateHash(uint32_t hash, Index type_index, Index rec_start); + bool CheckTypeFields(Index actual, + Index actual_rec_start, + Index expected, + Index expected_rec_start, + bool is_equal); Result CheckType(Type actual, Type expected); private: @@ -203,6 +327,17 @@ class TypeChecker { Type expected2, Type expected3, const char* desc); + Result PopAndCheck4Types(Type expected1, + Type expected2, + Type expected3, + Type expected4, + const char* desc); + Result PopAndCheck5Types(Type expected1, + Type expected2, + Type expected3, + Type expected4, + Type expected5, + 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); @@ -212,6 +347,25 @@ class TypeChecker { const Limits* limits3 = nullptr); Result OnEnd(Label* label, const char* sig_desc, const char* end_desc); + static uint32_t ComputeHash(uint32_t hash, Index value) { + // Shift-Add-XOR hash + return hash ^ ((hash << 5) + (hash >> 2) + value); + } + + static Type ToUnpackedType(Type type) { + if (type.IsPackedType()) { + return Type::I32; + } + return type; + } + + uint32_t ComputeHash(uint32_t hash, Type& type, Index rec_start); + bool CompareType(Type actual, + Index actual_rec_start, + Type expected, + Index expected_rec_start, + bool is_equal); + template void PrintStackIfFailed(Result result, const char* desc, Args... args) { // Assert all args are Type or Type::Enum. If it's a TypeVector then @@ -236,7 +390,7 @@ class TypeChecker { // to represent "any". TypeVector* br_table_sig_ = nullptr; Features features_; - std::map& func_types_; + TypeFields& type_fields_; }; } // namespace wabt diff --git a/include/wabt/type.h b/include/wabt/type.h index 8ef73112db..72a57827b4 100644 --- a/include/wabt/type.h +++ b/include/wabt/type.h @@ -40,17 +40,27 @@ class Type { F32 = -0x03, // 0x7d F64 = -0x04, // 0x7c V128 = -0x05, // 0x7b - I8 = -0x06, // 0x7a : packed-type only, used in gc and as v128 lane - I16 = -0x07, // 0x79 : packed-type only, used in gc and as v128 lane - ExnRef = -0x17, // 0x69 + I8 = -0x08, // 0x78 : packed-type only, used in gc and as v128 lane + I16 = -0x09, // 0x77 : packed-type only, used in gc and as v128 lane + NullFuncRef = -0x0d, // 0x73 + NullExternRef = -0x0e, // 0x72 + NullRef = -0x0f, // 0x71 FuncRef = -0x10, // 0x70 ExternRef = -0x11, // 0x6f - Reference = -0x15, // 0x6b + AnyRef = -0x12, // 0x6e + EqRef = -0x13, // 0x6d + I31Ref = -0x14, // 0x6c + StructRef = -0x15, // 0x6b + ArrayRef = -0x16, // 0x6a + ExnRef = -0x17, // 0x69 Ref = -0x1c, // 0x64 RefNull = -0x1d, // 0x63 Func = -0x20, // 0x60 Struct = -0x21, // 0x5f Array = -0x22, // 0x5e + Sub = -0x30, // 0x50 + SubFinal = -0x31, // 0x4f + Rec = -0x32, // 0x4e Void = -0x40, // 0x40 ___ = Void, // Convenient for the opcode table in opcode.h @@ -78,6 +88,10 @@ class Type { assert(IsReferenceWithIndex() || (IsNonTypedRef() && (type_index_ == ReferenceOrNull || type_index_ == ReferenceNonNull))); } + Type(Enum e, bool is_nullable) + : enum_(e), type_index_(is_nullable ? ReferenceOrNull : ReferenceNonNull) { + assert(IsNonTypedRef()); + } constexpr operator Enum() const { return enum_; } @@ -99,20 +113,23 @@ class Type { } bool IsRef() const { - return enum_ == Type::ExternRef || enum_ == Type::FuncRef || - enum_ == Type::Reference || enum_ == Type::ExnRef || - enum_ == Type::RefNull || enum_ == Type::Ref; + return enum_ == Type::NullFuncRef || enum_ == Type::NullExternRef || + enum_ == Type::NullRef || enum_ == Type::FuncRef || + enum_ == Type::ExternRef || enum_ == Type::AnyRef || + enum_ == Type::EqRef || enum_ == Type::I31Ref || + enum_ == Type::StructRef || enum_ == Type::ArrayRef || + enum_ == Type::ExnRef || enum_ == Type::Ref || + enum_ == Type::RefNull; } bool IsNullableRef() const { - return enum_ == Type::Reference || enum_ == Type::ExnRef || - enum_ == Type::RefNull || - ((enum_ == Type::ExternRef || enum_ == Type::FuncRef) && type_index_ == ReferenceOrNull); + return enum_ == Type::ExnRef || enum_ == Type::RefNull || + (EnumIsNonTypedRef(enum_) && type_index_ == ReferenceOrNull); } bool IsNonNullableRef() const { return enum_ == Type::Ref || - ((enum_ == Type::ExternRef || enum_ == Type::FuncRef) && type_index_ != ReferenceOrNull); + (EnumIsNonTypedRef(enum_) && type_index_ != ReferenceOrNull); } bool IsReferenceWithIndex() const { return EnumIsReferenceWithIndex(enum_); } @@ -137,13 +154,33 @@ class Type { case Type::I16: return "i16"; case Type::ExnRef: return "exnref"; case Type::Func: return "func"; + case Type::Struct: return "struct"; + case Type::Array: return "array"; case Type::Void: return "void"; case Type::Any: return "any"; + case Type::NullFuncRef: + return type_index_ == ReferenceOrNull ? "nullfuncref" : "(ref nofunc)"; + case Type::NullExternRef: + return type_index_ == ReferenceOrNull ? "nullexternref" : "(ref noextern)"; + case Type::NullRef: + if (type_index_ == kBottomRef) { + return "(ref something)"; + } + return type_index_ == ReferenceOrNull ? "nullref" : "(ref none)"; 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::AnyRef: + return type_index_ == ReferenceOrNull ? "anyref" : "(ref any)"; + case Type::EqRef: + return type_index_ == ReferenceOrNull ? "eqref" : "(ref eq)"; + case Type::I31Ref: + return type_index_ == ReferenceOrNull ? "i31ref" : "(ref i31)"; + case Type::StructRef: + return type_index_ == ReferenceOrNull ? "structref" : "(ref struct)"; + case Type::ArrayRef: + return type_index_ == ReferenceOrNull ? "arrayref" : "(ref array)"; case Type::Ref: return StringPrintf("(ref %d)", type_index_); case Type::RefNull: @@ -155,12 +192,19 @@ class Type { const char* GetRefKindName() const { switch (enum_) { - case Type::FuncRef: return "func"; - case Type::ExternRef: return "extern"; - case Type::ExnRef: return "exn"; - case Type::Struct: return "struct"; - case Type::Array: return "array"; - default: return ""; + case Type::NullFuncRef: return "nofunc"; + case Type::NullExternRef: return "noextern"; + case Type::NullRef: + return (type_index_ == kBottomRef) ? "something" : "none"; + case Type::FuncRef: return "func"; + case Type::ExternRef: return "extern"; + case Type::ExnRef: return "exn"; + case Type::AnyRef: return "any"; + case Type::EqRef: return "eq"; + case Type::I31Ref: return "i31"; + case Type::Struct: return "struct"; + case Type::Array: return "array"; + default: return ""; } } @@ -188,6 +232,10 @@ class Type { return type_index_; } + bool IsPackedType() const { + return enum_ == Type::I8 || enum_ == Type::I16; + } + TypeVector GetInlineVector() const { assert(!IsIndex()); switch (enum_) { @@ -199,10 +247,17 @@ class Type { case Type::F32: case Type::F64: case Type::V128: + case Type::NullFuncRef: + case Type::NullExternRef: + case Type::NullRef: case Type::FuncRef: - case Type::ExnRef: case Type::ExternRef: - case Type::Reference: + case Type::AnyRef: + case Type::EqRef: + case Type::I31Ref: + case Type::StructRef: + case Type::ArrayRef: + case Type::ExnRef: case Type::Ref: case Type::RefNull: return TypeVector(this, this + 1); @@ -213,15 +268,47 @@ class Type { } static bool EnumIsReferenceWithIndex(Enum value) { - return value == Type::Reference || value == Type::Ref || - value == Type::RefNull; + return value == Type::Ref || value == Type::RefNull; + } + + static bool EnumIsNonTypedGCRef(Enum value) { + return value == Type::NullFuncRef || value == Type::NullExternRef || + value == Type::NullRef || value == Type::AnyRef || + value == Type::EqRef || value == Type::I31Ref || + value == Type::StructRef || value == Type::ArrayRef; } static bool EnumIsNonTypedRef(Enum value) { - return value == Type::ExternRef || value == Type::FuncRef; + return value == Type::ExternRef || value == Type::FuncRef || + value == Type::ExnRef || EnumIsNonTypedGCRef(value); + } + + // Bottom references are only used by the shared + // validator. It represents an unknown reference. + // Nullable property is not defined for this type. + static Type BottomRef() { + Type type(NullRef); + type.type_index_ = kBottomRef; + return type; + } + + bool IsBottomRef() const { + return enum_ == NullRef && type_index_ == kBottomRef; + } + + void ConvertRefNullToRef() { + if (IsReferenceWithIndex()) { + enum_ = Type::Ref; + } else { + assert(IsNonTypedRef()); + type_index_ |= ReferenceNonNull; + } } private: + // Special value representing an unknown reference. + static const uint32_t kBottomRef = 0x2 | ReferenceNonNull; + 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 ad1c935da3..d5bcfd8d56 100644 --- a/include/wabt/wast-parser.h +++ b/include/wabt/wast-parser.h @@ -47,6 +47,7 @@ class WastParser { void WABT_PRINTF_FORMAT(3, 4) Error(Location, const char* format, ...); Result ParseModule(std::unique_ptr* out_module); Result ParseScript(std::unique_ptr