diff --git a/CMakeLists.txt b/CMakeLists.txt index d98e8fcf13..fcbfd56dc4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -300,6 +300,7 @@ set(WABT_LIBRARY_CC src/binding-hash.cc src/color.cc src/common.cc + src/component.cc src/config.cc src/config.h.in src/decompiler.cc diff --git a/include/wabt/binary-reader-ir.h b/include/wabt/binary-reader-ir.h index 4de0ee7099..0cc7c18597 100644 --- a/include/wabt/binary-reader-ir.h +++ b/include/wabt/binary-reader-ir.h @@ -22,6 +22,7 @@ namespace wabt { +class 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 a69c36a34c..91bf51a623 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 OnRecursiveGroup(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; @@ -164,6 +171,17 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Result OnTernaryExpr(Opcode opcode) override; Result OnQuaternaryExpr(Opcode opcode) 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, @@ -183,6 +201,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, @@ -202,6 +224,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; @@ -230,9 +253,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; @@ -244,6 +269,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; @@ -435,6 +466,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 86a853626a..33a1f3e16f 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 OnRecursiveGroup(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 */ @@ -216,6 +225,31 @@ class BinaryReaderNop : public BinaryReaderDelegate { Result OnTernaryExpr(Opcode opcode) override { return Result::Ok; } Result OnQuaternaryExpr(Opcode opcode) 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, @@ -250,6 +284,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, @@ -273,6 +313,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; } @@ -311,9 +352,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; } @@ -331,6 +374,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 1dd5c8b0fa..b113301902 100644 --- a/include/wabt/binary-reader.h +++ b/include/wabt/binary-reader.h @@ -23,6 +23,7 @@ #include "wabt/binary.h" #include "wabt/common.h" +#include "wabt/component.h" #include "wabt/error.h" #include "wabt/feature.h" #include "wabt/opcode.h" @@ -52,13 +53,20 @@ struct ReadBinaryOptions { bool skip_function_bodies = false; }; -// TODO: Move somewhere else? +// TODO: Move both TypeMut and SupertypesInfo 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 +112,20 @@ class BinaryReaderDelegate { /* Type section */ virtual Result BeginTypeSection(Offset size) = 0; virtual Result OnTypeCount(Index count) = 0; + virtual Result OnRecursiveGroup(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 */ @@ -236,6 +249,17 @@ class BinaryReaderDelegate { virtual Result OnTernaryExpr(Opcode opcode) = 0; virtual Result OnQuaternaryExpr(Opcode opcode) = 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, @@ -264,6 +288,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, @@ -283,6 +311,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; @@ -311,9 +340,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; @@ -326,6 +357,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; @@ -522,11 +559,121 @@ 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; + + virtual Result BeginCoreInstanceSection(uint32_t count) = 0; + virtual Result EndCoreInstanceSection() = 0; + virtual Result OnCoreInstance(const ComponentIndexLoc& module_index, + uint32_t argument_count, + ComponentNamedSort* arguments) = 0; + virtual Result OnInlineCoreInstance(uint32_t argument_count, + ComponentNamedSort* arguments) = 0; + + virtual Result BeginInstanceSection(uint32_t count) = 0; + virtual Result EndInstanceSection() = 0; + virtual Result OnInstance(const ComponentIndexLoc& module_index, + uint32_t argument_count, + ComponentNamedSort* arguments) = 0; + virtual Result OnInlineInstance(uint32_t argument_count, + ComponentNamedExportInfo* arguments) = 0; + + virtual Result BeginAliasSection(uint32_t count) = 0; + virtual Result EndAliasSection() = 0; + virtual Result OnAliasExport(ComponentSort sort, + const ComponentIndexLoc& instance_index, + const ComponentStringLoc& name) = 0; + virtual Result OnAliasCoreExport(ComponentSort sort, + const ComponentIndexLoc& core_instance_index, + const ComponentStringLoc& name) = 0; + virtual Result OnAliasOuter(ComponentSort sort, + uint32_t counter, + uint32_t index) = 0; + + virtual Result BeginTypeSection(uint32_t count) = 0; + virtual Result EndTypeSection() = 0; + virtual Result OnPrimitiveType(const ComponentTypeLoc type) = 0; + virtual Result OnRecordType(uint32_t field_count, + ComponentNamedType* fields) = 0; + virtual Result OnVariantType(uint32_t case_count, + ComponentNamedType* cases) = 0; + virtual Result OnListType(const ComponentTypeLoc& type) = 0; + virtual Result OnListFixedType(const ComponentTypeLoc& type, + uint32_t size) = 0; + virtual Result OnTupleType(uint32_t type_count, + const ComponentTypeLoc* types) = 0; + virtual Result OnFlagsType(uint32_t flag_count, + const ComponentStringLoc* flags) = 0; + virtual Result OnEnumType(uint32_t enum_count, + const ComponentStringLoc* enums) = 0; + virtual Result OnOptionType(const ComponentTypeLoc& type) = 0; + virtual Result OnResultType(const ComponentTypeLoc& result, + const ComponentTypeLoc& error) = 0; + virtual Result OnOwnType(const ComponentIndexLoc& index) = 0; + virtual Result OnBorrowType(const ComponentIndexLoc& index) = 0; + virtual Result OnStreamType(const ComponentTypeLoc& type) = 0; + virtual Result OnFutureType(const ComponentTypeLoc& type) = 0; + virtual Result OnFuncType(ComponentTypeDef type, + uint32_t param_count, + const ComponentNamedType* params, + const ComponentTypeLoc& result) = 0; + virtual Result OnResourceType(const ComponentIndexLoc& dtor) = 0; + virtual Result OnResourceAsyncType(const ComponentIndexLoc& dtor, + const ComponentIndexLoc& callback) = 0; + virtual Result BeginInstanceType(uint32_t count) = 0; + virtual Result EndInstanceType() = 0; + virtual Result BeginComponentType(uint32_t count) = 0; + virtual Result EndComponentType() = 0; + + virtual Result BeginCanonSection(uint32_t count) = 0; + virtual Result EndCanonSection() = 0; + virtual Result OnCanonLift(const ComponentIndexLoc& core_func_index, + uint32_t option_count, + ComponentCanonOption* options, + const ComponentIndexLoc& type_index) = 0; + virtual Result OnCanonLower(const ComponentIndexLoc& func_index, + uint32_t option_count, + ComponentCanonOption* options) = 0; + virtual Result OnCanonType(ComponentBinaryCanon canon, + const ComponentIndexLoc& type_index) = 0; + + virtual Result BeginImportSection(uint32_t count) = 0; + virtual Result EndImportSection() = 0; + virtual Result OnImport(const ComponentStringLoc& external_name, + std::string_view* version_suffix, + ComponentExternalInfo* external_info) = 0; + + virtual Result BeginExportSection(uint32_t count) = 0; + virtual Result EndExportSection() = 0; + virtual Result OnExport(const ComponentStringLoc& external_name, + std::string_view* version_suffix, + ComponentExternalInfo* external_info, + ComponentExportInfo* export_info) = 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); + +bool ReadBinaryIsComponent(const void* data, size_t size); + 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..7c6c270848 100644 --- a/include/wabt/binary-writer.h +++ b/include/wabt/binary-writer.h @@ -24,6 +24,7 @@ namespace wabt { +class 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..1f68d1e2f0 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,59 @@ enum class NameSectionSubsection { }; const char* GetNameSectionSubsectionName(NameSectionSubsection subsec); +enum class ComponentBinarySort : uint8_t { + Core = 0x00, + Func = 0x01, + Value = 0x02, + Type = 0x03, + Component = 0x04, + Instance = 0x05, +}; + +enum class ComponentBinaryCoreSort : uint8_t { + Func = 0x00, + Table = 0x01, + Memory = 0x02, + Global = 0x03, + Type = 0x10, + Module = 0x11, + Instance = 0x12, + NonCore = 0xff, +}; + +enum class ComponentBinaryInstance : uint8_t { + Reference = 0x00, + Inline = 0x01, +}; + +enum class ComponentBinaryAlias : uint8_t { + Export = 0x00, + CoreExport = 0x01, + Outer = 0x02, +}; + +enum class ComponentBinaryType : uint8_t { + None = 0, + Some = 1, + + ResultSome = 0, + ResultNone = 1, +}; + +enum class ComponentBinaryInterface : uint8_t { + CoreType = 0, + Type = 1, + Alias = 2, + Import = 3, + Export = 4, +}; + +enum class ComponentBinaryCanon : uint8_t { + Lift = 0x00, + Lower = 0x01, + ResourceDrop = 0x03, +}; + } // namespace wabt #endif /* WABT_BINARY_H_ */ diff --git a/include/wabt/component.h b/include/wabt/component.h new file mode 100644 index 0000000000..eb2e7644d5 --- /dev/null +++ b/include/wabt/component.h @@ -0,0 +1,184 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WABT_COMPONENT_H_ +#define WABT_COMPONENT_H_ + +#include "wabt/common.h" + +namespace wabt { + +// Contains data structures used by the component model. + +enum class ComponentSection : uint8_t { + Custom = 0, + CoreModule = 1, + CoreInstance = 2, + CoreType = 3, + Component = 4, + Instance = 5, + Alias = 6, + Type = 7, + Canon = 8, + Import = 10, + Export = 11, +}; + +class ComponentSort { + public: + enum Enum : uint8_t { + CoreFunc, + CoreTable, + CoreMemory, + CoreGlobal, + CoreType, + CoreModule, + CoreInstance, + Func, + Value, + Type, + Component, + Instance, + Invalid, + }; + + ComponentSort(Enum sort) + : sort_(sort) {} + + ComponentSort() + : sort_(Invalid) {} + + constexpr operator Enum() const { return sort_; } + + const char* GetName() const; + const char* GetCoreName() const; + + private: + Enum sort_; +}; + +// Composite type definitions. +enum class ComponentTypeDef : uint8_t { + ValueType = 0, + + // Types + Record = 0x72, + Variant = 0x71, + List = 0x70, + Tuple = 0x6f, + Flags = 0x6e, + Enum = 0x6d, + Option = 0x6b, + Result = 0x6a, + Own = 0x69, + Borrow = 0x68, + Stream = 0x66, + Future = 0x65, + ListFixed = 0x67, + AsyncFunc = 0x43, + Instance = 0x42, + Component = 0x41, + Func = 0x40, + Resource = 0x3f, + ResourceAsync = 0x3e, +}; + +enum class ComponentExternalDesc : uint8_t { + ValueEq = 0x00, + ValueType = 0x01, + TypeEq = 0x00, + TypeSubRes = 0x01, + Unused = 0xff, +}; + +struct ComponentStringLoc { + ComponentStringLoc() {} + ComponentStringLoc(std::string_view str, Location loc) + : str(str), loc(loc) {} + + std::string_view str; + Location loc; +}; + +struct ComponentTypeLoc { + ComponentTypeLoc() {} + ComponentTypeLoc(ComponentType type, Location loc) + : type(type), loc(loc) {} + + ComponentType type; + Location loc; +}; + +struct ComponentIndexLoc { + ComponentIndexLoc() + : index(kInvalidIndex) {} + ComponentIndexLoc(Index index, Location loc) + : index(index), loc(loc) {} + + Index index; + Location loc; +}; + +struct ComponentNamedType { + ComponentStringLoc name; + ComponentTypeLoc type; +}; + +struct ComponentNamedSort { + ComponentStringLoc name; + ComponentSort sort; + ComponentIndexLoc index; +}; + +struct ComponentCanonOption { + enum Option : uint8_t { + StrEncUtf8 = 0x00, + StrEncUtf16 = 0x01, + StrEncLatin1Utf16 = 0x02, + Memory = 0x03, + Realloc = 0x04, + PostReturn = 0x05, + Async = 0x06, + Callback = 0x07, + }; + + Option option; + Index index; + Location loc; +}; + +struct ComponentExternalInfo { + ComponentSort sort; + ComponentExternalDesc external; + ComponentIndexLoc index; +}; + +struct ComponentExportInfo { + ComponentSort sort; + ComponentIndexLoc index; +}; + +struct ComponentNamedExportInfo { + ComponentStringLoc name; + std::string_view version_suffix; + ComponentSort sort; + bool has_version_suffix; + ComponentIndexLoc index; +}; + +} // namespace wabt + +#endif // WABT_DECOMPILER_AST_H_ diff --git a/include/wabt/expr-visitor.h b/include/wabt/expr-visitor.h index c0a3c72cc7..db60c533ae 100644 --- a/include/wabt/expr-visitor.h +++ b/include/wabt/expr-visitor.h @@ -77,6 +77,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; @@ -147,6 +148,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 { @@ -160,6 +179,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; } @@ -234,6 +254,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 9ebeb3bdc3..9d7be5affe 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) {} @@ -44,6 +88,20 @@ inline bool FuncType::classof(const ExternType* type) { inline FuncType::FuncType(ValueTypes params, ValueTypes results) : 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 inline bool TableType::classof(const ExternType* type) { @@ -142,6 +200,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 +237,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; } @@ -482,12 +542,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 @@ -887,6 +948,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..8efee8c048 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, + }; + + // Currently FuncType also represents Struct and Array types. + // In the latter case, the mutability is stored in results array, + // which must have the same size as params. + // TODO: support separate types for Structs and Arrays or rename FuncType. + 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 dc04577c3f..5da51b7870 100644 --- a/include/wabt/ir.h +++ b/include/wabt/ir.h @@ -29,6 +29,7 @@ #include "wabt/binding-hash.h" #include "wabt/common.h" +#include "wabt/component.h" #include "wabt/intrusive-list.h" #include "wabt/opcode.h" @@ -110,6 +111,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 +182,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 +306,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. + // Currently, validator rejects lists which size is greater + // than 1, but this might be changed in the future. + VarVector sub_types; +}; + class TypeEntry { public: WABT_DISALLOW_COPY_AND_ASSIGN(TypeEntry); @@ -307,12 +329,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 +350,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 +380,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 +392,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 +417,17 @@ struct FuncDeclaration { }; enum class ExprType { + ArrayCopy, + ArrayFill, + ArrayGet, + ArrayInitData, + ArrayInitElem, + ArrayNew, + ArrayNewData, + ArrayNewDefault, + ArrayNewElem, + ArrayNewFixed, + ArraySet, AtomicLoad, AtomicRmw, AtomicRmwCmpxchg, @@ -395,6 +440,7 @@ enum class ExprType { Block, Br, BrIf, + BrOnCast, BrOnNonNull, BrOnNull, BrTable, @@ -406,6 +452,7 @@ enum class ExprType { Const, Convert, Drop, + GCUnary, GlobalGet, GlobalSet, If, @@ -422,9 +469,11 @@ enum class ExprType { MemorySize, Nop, RefAsNonNull, + RefCast, RefIsNull, RefFunc, RefNull, + RefTest, Rethrow, Return, ReturnCall, @@ -435,6 +484,10 @@ enum class ExprType { SimdLoadLane, SimdStoreLane, SimdShuffleOp, + StructGet, + StructNew, + StructNewDefault, + StructSet, LoadSplat, LoadZero, Store, @@ -454,7 +507,7 @@ enum class ExprType { Unary, Unreachable, - First = AtomicLoad, + First = ArrayCopy, Last = Unreachable }; @@ -592,6 +645,7 @@ using BinaryExpr = OpcodeExpr; using QuaternaryExpr = OpcodeExpr; using CompareExpr = OpcodeExpr; using ConvertExpr = OpcodeExpr; +using GCUnaryExpr = OpcodeExpr; using UnaryExpr = OpcodeExpr; using TernaryExpr = OpcodeExpr; using RefAsNonNullExpr = OpcodeExpr; @@ -697,6 +751,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()) @@ -875,6 +938,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) {} @@ -1261,6 +1380,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&); @@ -1322,6 +1445,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; @@ -1582,6 +1707,783 @@ struct Script { std::string_view filename; }; +class ComponentData; +class ComponentTypeData; +class ComponentAliasExport; +class ComponentAliasOuter; +class ComponentValueType; +class ComponentTypeIndex; +class ComponentTypeItems; +class ComponentTypeListFixed; +class ComponentTypeTuple; +class ComponentTypeNames; +class ComponentTypeResult; +class ComponentTypeFunc; +class ComponentTypeResourceAsync; +class ComponentCanonLift; +class ComponentCanonLower; +class ComponentCanonType; +class ComponentExternal; +class ComponentCoreModule; +class ComponentInstance; +class ComponentInlineInstance; + +// Base class of all component definitions. +class ComponentDef { + public: + using Section = ComponentSection; + using Type = ComponentTypeDef; + + // Subtype for Section::CoreInstance and Section::Instance + enum class Instance : uint8_t { + Reference, + Inline, + }; + + // Subtype for Section::Alias + enum class Alias : uint8_t { + Export, + CoreExport, + Outer, + }; + + // Subtype for Section::Alias + enum class Canon : uint8_t { + Lift = 0x00, + Lower = 0x01, + ResourceDrop = 0x03, + }; + + // Subtype for Section::Import and Section::Export + enum class External : uint8_t { + CoreModule, + Func, + ValueEq, + ValueType, + TypeEq, + TypeSubResource, + Component, + Instance, + // Only allowed for Component Exports, + // where the descriptor is optional. + Unused, + }; + + struct StringLoc { + StringLoc() + : str(nullptr) {} + StringLoc(const std::string* str, Location loc) + : str(str), loc(loc) {} + + const std::string* str; + Location loc; + }; + + virtual ~ComponentDef() {} + + Section section() const { + return section_; + } + + ComponentSort sort() const { + return sort_; + } + + Instance instance() const { + assert(section() == Section::CoreInstance || + section() == Section::Instance); + return static_cast(sub_type_); + } + + Alias alias() const { + assert(section() == Section::Alias); + return static_cast(sub_type_); + } + + Type type() const { + assert(section() == Section::Type); + return static_cast(sub_type_); + } + + Canon canon() const { + assert(section() == Section::Canon); + return static_cast(sub_type_); + } + + External external() const { + assert(section() == Section::Import || section() == Section::Export); + return static_cast(sub_type_); + } + + const std::string* Name() const { return name_; } + + void SetName(const std::string* name) { + name_ = name; + } + + const ComponentData* AsComponent() const { + assert(section() == Section::Component); + return reinterpret_cast(this); + } + + const ComponentTypeData* AsComponentType() const { + assert(type() == Type::Instance || type() == Type::Component); + return reinterpret_cast(this); + } + + const ComponentAliasExport* AsAliasExport() const { + assert(alias() == Alias::Export || alias() == Alias::CoreExport); + return reinterpret_cast(this); + } + + const ComponentAliasOuter* AsAliasOuter() const { + assert(alias() == Alias::Outer); + return reinterpret_cast(this); + } + + const ComponentValueType* AsValueType() const { + assert(type() == Type::ValueType || type() == Type::List || + type() == Type::Option || type() == Type::Stream || + type() == Type::Future); + return reinterpret_cast(this); + } + + const ComponentTypeIndex* AsTypeIndex() const { + assert(type() == Type::Own || type() == Type::Borrow || + type() == Type::Resource); + return reinterpret_cast(this); + } + + const ComponentTypeItems* AsTypeItems() const { + assert(type() == Type::Record || type() == Type::Variant); + return reinterpret_cast(this); + } + + const ComponentTypeListFixed* AsTypeListFixed() const { + assert(type() == Type::ListFixed); + return reinterpret_cast(this); + } + + const ComponentTypeTuple* AsTypeTuple() const { + assert(type() == Type::Tuple); + return reinterpret_cast(this); + } + + const ComponentTypeNames* AsTypeNames() const { + assert(type() == Type::Flags || type() == Type::Enum); + return reinterpret_cast(this); + } + + const ComponentTypeResult* AsTypeResult() const { + assert(type() == Type::Result); + return reinterpret_cast(this); + } + + const ComponentTypeFunc* AsTypeFunc() const { + assert(type() == Type::Func); + return reinterpret_cast(this); + } + + const ComponentTypeResourceAsync* AsTypeResourceAsync() const { + assert(type() == Type::ResourceAsync); + return reinterpret_cast(this); + } + + const ComponentCanonLift* AsCanonLift() const { + assert(canon() == Canon::Lift); + return reinterpret_cast(this); + } + + const ComponentCanonLower* AsCanonLower() const { + assert(canon() == Canon::Lower); + return reinterpret_cast(this); + } + + const ComponentCanonType* AsCanonType() const { + assert(canon() == Canon::ResourceDrop); + return reinterpret_cast(this); + } + + const ComponentExternal* AsExternal() const { + assert(section() == Section::Import || section() == Section::Export); + return reinterpret_cast(this); + } + + const ComponentCoreModule* AsCoreModule() const { + assert(section() == Section::CoreModule); + return reinterpret_cast(this); + } + + const ComponentInstance* AsInstance() const { + assert(section() == Section::CoreInstance || + instance() == Instance::Reference); + return reinterpret_cast(this); + } + + const ComponentInlineInstance* AsInlineInstance() const { + assert(section() == Section::Instance && instance() == Instance::Inline); + return reinterpret_cast(this); + } + + protected: + ComponentDef(Section section, ComponentSort sort) + : section_(section), sort_(sort), sub_type_(0) { + assert(section != Section::Type); + } + + ComponentDef(Section section, Instance instance) + : section_(section), + sort_(section == Section::Instance ? ComponentSort::Instance + : ComponentSort::CoreInstance), + sub_type_(static_cast(instance)) { + assert(section == Section::CoreInstance || section == Section::Instance); + } + + ComponentDef(Alias alias, ComponentSort sort) + : section_(Section::Alias), sort_(sort), + sub_type_(static_cast(alias)) {} + + ComponentDef(Type type) + : section_(Section::Type), sort_(ComponentSort::Type), + sub_type_(static_cast(type)) {} + + ComponentDef(Canon canon) + : section_(Section::Canon), + sort_(canon == Canon::Lift ? ComponentSort::Func + : ComponentSort::CoreFunc), + sub_type_(static_cast(canon)) {} + + ComponentDef(Section section, + External external, + ComponentSort sort) + : section_(section), sort_(sort), + sub_type_(static_cast(external)) { + assert(section == Section::Import || section == Section::Export); + } + + private: + Section section_; + ComponentSort sort_; + // Secondary, optional type field. + uint8_t sub_type_; + const std::string* name_ = nullptr; +}; + +class ComponentSharedData : public ComponentDef { + public: + const ComponentSharedData* GetParent() const { return parent_; } + + bool IsComponent() const { + return section() == Section::Component; + } + + bool IsInstanceType() const { + return section() == Section::Type && type() == Type::Instance; + } + + bool IsComponentType() const { + return section() == Section::Type && type() == Type::Component; + } + + uint32_t Size() const { + return static_cast(list_.size()); + } + + const ComponentDef* Get(size_t idx) const { + return list_[idx].get(); + } + + void Append(std::unique_ptr type) { + assert(type->sort() != ComponentSort::Type); + list_.push_back(std::move(type)); + } + + void AppendType(std::unique_ptr type) { + assert(type->sort() == ComponentSort::Type); + type_list_.push_back(type.get()); + list_.push_back(std::move(type)); + } + + void AppendAny(std::unique_ptr type) { + if (type->sort() == ComponentSort::Type) { + type_list_.push_back(type.get()); + } + list_.push_back(std::move(type)); + } + + void SetLastTypeName(const std::string* name) { + assert(type_list_.size() > 0 && list_.back().get() == type_list_.back()); + list_.back().get()->SetName(name); + } + + Index TypeSize() const { + return static_cast(type_list_.size()); + } + + const ComponentDef* Find(ComponentSort sort, + const std::string* name, + Index* out_index = nullptr) const; + const ComponentDef* Find(ComponentSort sort, Index index) const; + Index SortSize(ComponentSort sort) const; + + protected: + ComponentSharedData(const ComponentSharedData* parent) + : ComponentDef(Section::Component, ComponentSort::Component), + parent_(parent) {} + + ComponentSharedData(const ComponentSharedData* parent, Type type) + : ComponentDef(type), parent_(parent) { + assert(IsInstanceType() || IsComponentType()); + } + + private: + const ComponentSharedData* parent_; + std::vector> list_; + // Types and core types are frequently used. + std::vector type_list_; +}; + +class ComponentTypeData : public ComponentSharedData { + public: + ComponentTypeData(const ComponentSharedData* parent, + bool is_component) + : ComponentSharedData(parent, + is_component ? Type::Component : Type::Instance) {} +}; + +class ComponentAliasExport : public ComponentDef { + public: + ComponentAliasExport(bool is_core, + const ComponentIndexLoc& instance_index, + const StringLoc& export_name, + ComponentSort sort) + : ComponentDef(is_core ? Alias::CoreExport : Alias::Export, sort), + instance_index_(instance_index), export_name_(export_name) {} + + Index InstanceIndex() const { return instance_index_.index; } + const std::string* ExportName() const { return export_name_.str; } + + private: + ComponentIndexLoc instance_index_; + StringLoc export_name_; +}; + +class ComponentAliasOuter : public ComponentDef { + public: + ComponentAliasOuter(Index counter, + Index index, + ComponentSort sort, + Location loc) + : ComponentDef(Alias::Outer, sort), counter_(counter), + index_(index), loc_(loc) { + assert(sort == ComponentSort::CoreModule || + sort == ComponentSort::Component || + sort == ComponentSort::Type); + } + + Index GetCounter() const { return counter_; } + Index GetIndex() const { return index_; } + const Location& GetLocation() { return loc_; } + + private: + Index counter_; + Index index_; + Location loc_; +}; + +class ComponentValueType : public ComponentDef { + public: + ComponentValueType(Type type, const ComponentTypeLoc& value_type) + : ComponentDef(type), value_type_(value_type) { + assert(type == Type::Stream || type == Type::Future || + ((type == Type::ValueType || type == Type::List || + type == Type::Option) && + !value_type.type.IsNone())); + } + + const ComponentType& ValueType() const { return value_type_.type; } + const ComponentTypeLoc& ValueTypeLoc() const { return value_type_; } + + private: + ComponentTypeLoc value_type_; +}; + +class ComponentTypeIndex : public ComponentDef { + public: + ComponentTypeIndex(Type type, const ComponentIndexLoc& index) + : ComponentDef(type), index_(index) { + assert(type == Type::Resource || + ((type == Type::Own || type == Type::Borrow) && + index.index != kInvalidIndex)); + } + + Index GetIndex() const { return index_.index; } + const ComponentIndexLoc& GetIndexLoc() const { return index_; } + + private: + ComponentIndexLoc index_; +}; + +class ComponentTypeItems : public ComponentDef { + public: + struct Item { + StringLoc name; + ComponentTypeLoc type; + }; + + using ItemVector = std::vector; + + ComponentTypeItems(Type type, ItemVector* items, Location loc) + : ComponentDef(type), loc_(loc) { + assert(type == Type::Record || type == Type::Variant); + items_ = std::move(*items); + } + + const ItemVector& Items() const { return items_; } + const Location& GetLocation() { return loc_; } + + private: + ItemVector items_; + Location loc_; +}; + +class ComponentTypeListFixed : public ComponentDef { + public: + ComponentTypeListFixed(const ComponentTypeLoc& value_type, + uint32_t size, + Location list_loc) + : ComponentDef(Type::ListFixed), value_type_(value_type), size_(size), + list_loc_(list_loc) { + assert(!value_type.type.IsNone()); + } + + const ComponentType& ValueType() const { return value_type_.type; } + const ComponentTypeLoc& ValueTypeLoc() { return value_type_; } + uint32_t Size() const { return size_; } + const Location& ListLocation() { return list_loc_; } + + private: + ComponentTypeLoc value_type_; + uint32_t size_; + Location list_loc_; +}; + +class ComponentTypeTuple : public ComponentDef { + public: + using ItemVector = std::vector; + + ComponentTypeTuple(ItemVector* items, Location tuple_loc) + : ComponentDef(Type::Tuple), tuple_loc_(tuple_loc) { + items_ = std::move(*items); + } + + const ItemVector& Items() const { return items_; } + const Location& TupleLocation() { return tuple_loc_; } + + private: + ItemVector items_; + Location tuple_loc_; +}; + +class ComponentTypeNames : public ComponentDef { + public: + using ItemVector = std::vector; + + ComponentTypeNames(Type type, ItemVector* items, Location names_loc) + : ComponentDef(type), names_loc_(names_loc) { + assert(type == Type::Flags || type == Type::Enum); + items_ = std::move(*items); + } + + const ItemVector& Items() const { return items_; } + const Location& NamesLocation() { return names_loc_; } + + private: + ItemVector items_; + Location names_loc_; +}; + +class ComponentTypeResult : public ComponentDef { + public: + ComponentTypeResult(const ComponentTypeLoc& result, + const ComponentTypeLoc& error) + : ComponentDef(Type::Result), result_(result), error_(error) {} + + const ComponentType& Result() const { return result_.type; } + const ComponentTypeLoc& ResultLoc() { return result_; } + const ComponentType& Error() const { return error_.type; } + const ComponentTypeLoc& ErrorLoc() { return error_; } + + private: + ComponentTypeLoc result_; + ComponentTypeLoc error_; +}; + +class ComponentTypeFunc : public ComponentDef { + public: + struct Param { + StringLoc name; + ComponentTypeLoc type; + }; + + using ParamVector = std::vector; + + ComponentTypeFunc(bool is_async, + ParamVector* params, + const ComponentTypeLoc& result) + : ComponentDef(is_async ? Type::AsyncFunc : Type::Func), + result_(result) { + params_ = std::move(*params); + } + + const ParamVector& Params() const { return params_; } + const ComponentType& Result() const { return result_.type; } + const ComponentTypeLoc& ResultLoc() { return result_; } + + private: + ParamVector params_; + ComponentTypeLoc result_; +}; + +class ComponentTypeResourceAsync : public ComponentDef { + public: + ComponentTypeResourceAsync(const ComponentIndexLoc& dtor, + const ComponentIndexLoc& callback) + : ComponentDef(Type::ResourceAsync), dtor_(dtor), callback_(callback) { + assert(dtor_.index != kInvalidIndex); + } + + Index Dtor() const { return dtor_.index; } + const ComponentIndexLoc& DtorLoc() { return dtor_; } + Index Callback() const { return callback_.index; } + const ComponentIndexLoc& CallbackLoc() { return callback_; } + + private: + ComponentIndexLoc dtor_; + ComponentIndexLoc callback_; +}; + + +class ComponentCanonOpts : public ComponentDef { + public: + using OptionVector = std::vector; + + const OptionVector& Options() const { return options_; } + + protected: + ComponentCanonOpts(Canon canon, OptionVector* options) + : ComponentDef(canon) { + options_ = std::move(*options); + } + + private: + OptionVector options_; +}; + +class ComponentCanonLift : public ComponentCanonOpts { + public: + ComponentCanonLift(const ComponentIndexLoc& core_func_index, + OptionVector* options, + const ComponentIndexLoc& type_index) + : ComponentCanonOpts(Canon::Lift, options), + core_func_index_(core_func_index), type_index_(type_index) {} + + Index CoreFuncIndex() const { return core_func_index_.index; } + const ComponentIndexLoc& CoreFuncIndexLoc() { return core_func_index_; } + Index TypeIndex() const { return type_index_.index; } + const ComponentIndexLoc& TypeIndexLoc() { return type_index_; } + + private: + ComponentIndexLoc core_func_index_; + ComponentIndexLoc type_index_; +}; + +class ComponentCanonLower : public ComponentCanonOpts { + public: + ComponentCanonLower(const ComponentIndexLoc& func_index, + OptionVector* options) + : ComponentCanonOpts(Canon::Lower, options), + func_index_(func_index) {} + + Index FuncIndex() const { return func_index_.index; } + const ComponentIndexLoc& FuncIndexLoc() { return func_index_; } + + private: + ComponentIndexLoc func_index_; +}; + +class ComponentCanonType : public ComponentDef { + public: + ComponentCanonType(Canon canon, const ComponentIndexLoc& type_index) + : ComponentDef(canon), type_index_(type_index) { + assert(AsCanonType() != nullptr); + } + + Index TypeIndex() const { return type_index_.index; } + const ComponentIndexLoc& TypeIndexLoc() { return type_index_; } + + private: + ComponentIndexLoc type_index_; +}; + +class ComponentExternal : public ComponentDef { + public: + ComponentExternal(bool is_import, + StringLoc& external_name, + const std::string* version_suffix, + External external, + ComponentSort sort, + const ComponentIndexLoc& type_index, + const ComponentIndexLoc& export_index) + : ComponentDef(is_import ? Section::Import : Section::Export, external, + sort), + external_name_(external_name), + version_suffix_(version_suffix), type_index_(type_index), + export_index_(export_index) { + assert(external_name.str != nullptr && + (export_index.index == kInvalidIndex || !is_import)); + } + + const std::string* ExternalName() const { return external_name_.str; } + const StringLoc& ExternalNameLoc() const { return external_name_; } + // Optional suffix (can be nullptr) + const std::string* VersionSuffix() const { return version_suffix_; } + // Optional for component exports + Index TypeIndex() const { return type_index_.index; } + const ComponentIndexLoc& TypeIndexLoc() { return type_index_; } + // Only used by component exports + Index ExportIndex() const { return export_index_.index; } + const ComponentIndexLoc& ExportIndexLoc() { return export_index_; } + + private: + StringLoc external_name_; + const std::string* version_suffix_; + ComponentIndexLoc type_index_; + ComponentIndexLoc export_index_; +}; + +class ComponentCoreModule : public ComponentDef { + public: + ComponentCoreModule() + : ComponentDef(Section::CoreModule, ComponentSort::CoreModule) {} + + const Module* module() const { + return &module_; + } + + Module* module() { + return &module_; + } + + private: + Module module_; +}; + +class ComponentInstance : public ComponentDef { + public: + struct Argument { + StringLoc name; + ComponentSort sort; + ComponentIndexLoc index; + }; + + using ArgumentVector = std::vector; + + ComponentInstance(bool is_core, + const ComponentIndexLoc& from_index, + ArgumentVector* arguments) + : ComponentDef(is_core ? Section::CoreInstance : Section::Instance, + Instance::Reference), + from_index_(from_index) { + arguments_ = std::move(*arguments); + } + + ComponentInstance(ArgumentVector* arguments) + : ComponentDef(Section::CoreInstance, Instance::Inline), + from_index_(ComponentIndexLoc()) { + arguments_ = std::move(*arguments); + } + + Index FromIndex() const { return from_index_.index; } + const Location& FromLocation() { return from_index_.loc; } + const ArgumentVector& Arguments() const { return arguments_; } + + private: + ArgumentVector arguments_; + ComponentIndexLoc from_index_; +}; + +class ComponentInlineInstance : public ComponentDef { + public: + struct Argument { + StringLoc name; + // Optional suffix (can be nullptr) + const std::string* version_suffix; + ComponentSort sort; + ComponentIndexLoc index; + }; + + using ArgumentVector = std::vector; + + ComponentInlineInstance(ArgumentVector* arguments) + : ComponentDef(Section::Instance, Instance::Inline) { + arguments_ = std::move(*arguments); + } + + const ArgumentVector& Arguments() const { return arguments_; } + + private: + ArgumentVector arguments_; +}; + +class ComponentData : public ComponentSharedData { + public: + ComponentData(const ComponentData* parent) + : ComponentSharedData(parent) {} + + const ComponentData* GetParentComponent() const { + return GetParent()->AsComponent(); + } +}; + +class Component : public ComponentData { + public: + // Helper class used by parsers. + class StringTable { + public: + StringTable(Component* owner) + : string_map_(Less), owner_(owner) { + assert(owner_->string_table_.empty()); + } + + const std::string* Find(const std::string_view& name) const; + const std::string* Append(const std::string_view& name); + + StringLoc Append(const ComponentStringLoc& name) { + return StringLoc{Append(name.str), name.loc}; + } + + private: + static bool Less(std::string* first, std::string* second) { + assert(first != nullptr && second != nullptr); + return *first < *second; + } + + std::set string_map_; + Component* owner_; + }; + + Component(std::string_view filename) + : ComponentData(nullptr), filename(filename) {} + + std::string_view Filename() { return filename; } + + private: + std::string_view filename; + // Only these strings are used by the component + std::vector> string_table_; +}; + void MakeTypeBindingReverseMapping( size_t num_types, const BindingHash& bindings, diff --git a/include/wabt/opcode.def b/include/wabt/opcode.def index b3237351e3..19c3c179eb 100644 --- a/include/wabt/opcode.def +++ b/include/wabt/opcode.def @@ -275,10 +275,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 8de3049998..d97fed3bc5 100644 --- a/include/wabt/opcode.h +++ b/include/wabt/opcode.h @@ -85,7 +85,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; @@ -94,6 +94,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 172d2a6939..e0f2a5f62a 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*, std::string_view filename, const ValidateOptions& options); @@ -70,22 +72,35 @@ class SharedValidator { Index GetLocalCount() const; + // The canonical index is the lowest index, which represents + // the same type as the type_index. The canonical index is + // always less or equal than type_index. + Index GetCanonicalTypeIndex(Index type_index); + Result EndModule(); + Result OnRecursiveGroup(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&, @@ -108,6 +123,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, @@ -145,6 +171,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&); @@ -163,6 +193,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); @@ -188,9 +219,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); @@ -216,6 +249,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); @@ -233,20 +270,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) {} @@ -302,7 +325,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, @@ -318,7 +345,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); @@ -347,6 +376,8 @@ class SharedValidator { void RestoreLocalRefs(Result result); void IgnoreLocalRefs(); + Index GetRecGroupEnd(); + ValidateOptions options_; Errors* errors_; std::string_view filename_; @@ -355,10 +386,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. @@ -367,8 +395,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. @@ -381,6 +412,16 @@ class SharedValidator { std::vector check_declared_funcs_; }; +class SharedComponentValidator { + public: + WABT_DISALLOW_COPY_AND_ASSIGN(SharedComponentValidator); + SharedComponentValidator(Errors*, const ValidateOptions& options); + + private: + ValidateOptions options_; + Errors* errors_; +}; + } // namespace wabt #endif // WABT_SHARED_VALIDATOR_H_ diff --git a/include/wabt/token.def b/include/wabt/token.def index 70c5481d5e..ceb1bbe9a2 100644 --- a/include/wabt/token.def +++ b/include/wabt/token.def @@ -21,7 +21,7 @@ /* Tokens with no additional data (i.e. bare). */ WABT_TOKEN(Invalid, "Invalid") WABT_TOKEN(After, "after") -WABT_TOKEN(Array, "array") +WABT_TOKEN(Alias, "alias") WABT_TOKEN(AssertException, "assert_exception") WABT_TOKEN(AssertExhaustion, "assert_exhaustion") WABT_TOKEN(AssertInvalid, "assert_invalid") @@ -29,26 +29,47 @@ WABT_TOKEN(AssertMalformed, "assert_malformed") WABT_TOKEN(AssertReturn, "assert_return") WABT_TOKEN(AssertTrap, "assert_trap") WABT_TOKEN(AssertUnlinkable, "assert_unlinkable") +WABT_TOKEN(Async, "async") WABT_TOKEN(Before, "before") WABT_TOKEN(Bin, "bin") +WABT_TOKEN(Bool, "bool") +WABT_TOKEN(Borrow, "borrow") WABT_TOKEN(Item, "item") +WABT_TOKEN(Callback, "callback") +WABT_TOKEN(Canon, "canon") +WABT_TOKEN(Case, "case") +WABT_TOKEN(Char, "char") +WABT_TOKEN(Component, "component") +WABT_TOKEN(Core, "core") WABT_TOKEN(Data, "data") WABT_TOKEN(Declare, "declare") WABT_TOKEN(Delegate, "delegate") WABT_TOKEN(Do, "do") +WABT_TOKEN(Dtor, "dtor") WABT_TOKEN(Either, "either") WABT_TOKEN(Elem, "elem") +WABT_TOKEN(Enum, "enum") WABT_TOKEN(Eof, "EOF") +WABT_TOKEN(Error, "error") +WABT_TOKEN(ErrorContext, "error-context") WABT_TOKEN(Tag, "tag") WABT_TOKEN(Export, "export") WABT_TOKEN(Field, "field") +WABT_TOKEN(Final, "final") +WABT_TOKEN(Flags, "flags") WABT_TOKEN(Function, "function") +WABT_TOKEN(Future, "future") 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(Instantiate, "instantiate") +WABT_TOKEN(Lift, "lift") +WABT_TOKEN(List, "list") WABT_TOKEN(Local, "local") +WABT_TOKEN(Lower, "lower") WABT_TOKEN(Lpar, "(") WABT_TOKEN(Memory, "memory") WABT_TOKEN(Module, "module") @@ -57,20 +78,51 @@ WABT_TOKEN(NanArithmetic, "nan:arithmetic") WABT_TOKEN(NanCanonical, "nan:canonical") WABT_TOKEN(Null, "null") WABT_TOKEN(Offset, "offset") +WABT_TOKEN(Option, "option") +WABT_TOKEN(Outer, "outer") WABT_TOKEN(Output, "output") +WABT_TOKEN(Own, "own") WABT_TOKEN(PageSize, "pagesize") WABT_TOKEN(Param, "param") +WABT_TOKEN(PostReturn, "post-return") 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(Realloc, "realloc") +WABT_TOKEN(Rec, "rec") +WABT_TOKEN(Rep, "rep") +WABT_TOKEN(Record, "record") WABT_TOKEN(Register, "register") +WABT_TOKEN(Resource, "resource") +WABT_TOKEN(ResourceDrop, "resource.drop") WABT_TOKEN(Result, "result") WABT_TOKEN(Rpar, ")") +WABT_TOKEN(S8, "s8") +WABT_TOKEN(S16, "s16") +WABT_TOKEN(S32, "s32") +WABT_TOKEN(S64, "s64") WABT_TOKEN(Shared, "shared") WABT_TOKEN(Start, "start") -WABT_TOKEN(Struct, "struct") +WABT_TOKEN(Stream, "stream") +WABT_TOKEN(String, "string") +WABT_TOKEN(StringEncodingLatin1Utf16, "string-encoding=latin1+utf16") +WABT_TOKEN(StringEncodingUtf16, "string-encoding=utf16") +WABT_TOKEN(StringEncodingUtf8, "string-encoding=utf8") +WABT_TOKEN(Sub, "sub") WABT_TOKEN(Table, "table") WABT_TOKEN(Then, "then") +WABT_TOKEN(Tuple, "tuple") WABT_TOKEN(Type, "type") +WABT_TOKEN(U8, "u8") +WABT_TOKEN(U16, "u16") +WABT_TOKEN(U32, "u32") +WABT_TOKEN(U64, "u64") +WABT_TOKEN(Value, "value") +WABT_TOKEN(Variant, "variant") +WABT_TOKEN(VersionSuffix, "versionsuffix") +WABT_TOKEN(With, "with") WABT_TOKEN(I8X16, "i8x16") WABT_TOKEN(I16X8, "i16x8") WABT_TOKEN(I32X4, "i32x4") @@ -88,6 +140,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") @@ -100,6 +165,7 @@ WABT_TOKEN(Quaternary, "QUATERNARY") 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") @@ -120,6 +186,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") @@ -135,10 +202,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") @@ -150,6 +221,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") @@ -164,7 +241,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. */ @@ -183,8 +260,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 25b2a421fd..25e9aed374 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_code(0) {} + + Index start_index; + Index type_count; + uint32_t hash_code; + }; + + 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; @@ -81,6 +173,24 @@ class TypeChecker { Result OnBinary(Opcode); Result OnQuaternary(Opcode); Result OnTernary(Opcode); + 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); @@ -91,6 +201,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(); @@ -118,6 +229,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); @@ -142,8 +254,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); @@ -152,6 +266,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 OnThrow(const TypeVector& sig); Result OnThrowRef(); Result OnTry(const TypeVector& param_types, const TypeVector& result_types); @@ -165,6 +283,14 @@ class TypeChecker { Result BeginInitExpr(Type type); Result EndInitExpr(); + uint32_t UpdateHashCode(uint32_t hash_code, + 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: @@ -209,6 +335,12 @@ class TypeChecker { 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); @@ -223,6 +355,25 @@ class TypeChecker { const Limits* limits4 = nullptr); Result OnEnd(Label* label, const char* sig_desc, const char* end_desc); + static uint32_t ComputeHashCode(uint32_t hash_code, Index value) { + // Shift-Add-XOR hash + return hash_code ^ ((hash_code << 5) + (hash_code >> 2) + value); + } + + static Type ToUnpackedType(Type type) { + if (type.IsPackedType()) { + return Type::I32; + } + return type; + } + + uint32_t ComputeHashCode(uint32_t hash_code, 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 @@ -247,7 +398,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..c77e383979 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 any)"; + } + 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) ? "any" : "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 which represents an any 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. @@ -229,6 +316,78 @@ class Type { Index type_index_; }; +class ComponentType { + public: + // Matches binary format, do not change. + enum Enum : uint8_t { + Bool = 0x7f, + S8 = 0x7e, + U8 = 0x7d, + S16 = 0x7c, + U16 = 0x7b, + S32 = 0x7a, + U32 = 0x79, + S64 = 0x78, + U64 = 0x77, + F32 = 0x76, + F64 = 0x75, + Char = 0x74, + String = 0x73, + ErrorContext = 0x64, + + TypeIndex = 0, + TypeNone = 1, + }; + + ComponentType() + : type_(Enum::TypeNone), type_index_(0) {} + + ComponentType(Enum type) + : type_(type), type_index_(0) { + assert(type != Enum::TypeIndex && type != Enum::TypeNone); + } + + ComponentType(Index index) + : type_(Enum::TypeIndex), type_index_(index) {} + + bool IsNone() const { + return type_ == Enum::TypeNone; + } + + bool IsIndex() const { + return type_ == Enum::TypeIndex; + } + + Enum GetType() const { + return type_; + } + + Index GetIndex() const { + assert(IsIndex()); + return type_index_; + } + + const char* GetName() const; + + static bool IsPrimitiveType(uint8_t code) { + Enum type = static_cast(code); + return type == Bool || type == S8 || type == U8 || type == S16 || + type == U16 || type == S32 || type == U32 || type == S64 || + type == U64 || type == F32 || type == F64 || type == Char || + type == String || type == ErrorContext; + } + + static bool IsPrimitiveTypeS64(int64_t code) { + int8_t mask = 0x7f; + return (code | mask) == ~static_cast(0) && + IsPrimitiveType(static_cast(code & mask)); + } + + private: + Enum type_; + Index type_index_; +}; + } // namespace wabt #endif // WABT_TYPE_H_ diff --git a/include/wabt/validator.h b/include/wabt/validator.h index f5b945884e..a58428bbf8 100644 --- a/include/wabt/validator.h +++ b/include/wabt/validator.h @@ -25,11 +25,13 @@ namespace wabt { struct Module; struct Script; +class Component; // Perform all checks on the script. It is valid if and only if this function // succeeds. Result ValidateScript(const Script*, Errors*, const ValidateOptions&); Result ValidateModule(const Module*, Errors*, const ValidateOptions&); +Result ValidateComponent(const Component*, Errors*, const ValidateOptions&); } // namespace wabt diff --git a/include/wabt/wast-parser.h b/include/wabt/wast-parser.h index 68e5af86ba..6a871e5a26 100644 --- a/include/wabt/wast-parser.h +++ b/include/wabt/wast-parser.h @@ -47,6 +47,8 @@ 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