| /* |
| * 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_IR_H_ |
| #define WABT_IR_H_ |
| |
| #include <cassert> |
| #include <cstddef> |
| #include <cstdint> |
| #include <memory> |
| #include <string> |
| #include <type_traits> |
| #include <vector> |
| |
| #include "src/binding-hash.h" |
| #include "src/common.h" |
| #include "src/intrusive-list.h" |
| #include "src/opcode.h" |
| #include "src/string-view.h" |
| |
| namespace wabt { |
| |
| enum class VarType { |
| Index, |
| Name, |
| }; |
| |
| struct Var { |
| explicit Var(Index index = kInvalidIndex, const Location& loc = Location()); |
| explicit Var(string_view name, const Location& loc = Location()); |
| Var(Var&&); |
| Var(const Var&); |
| Var& operator=(const Var&); |
| Var& operator=(Var&&); |
| ~Var(); |
| |
| VarType type() const { return type_; } |
| bool is_index() const { return type_ == VarType::Index; } |
| bool is_name() const { return type_ == VarType::Name; } |
| |
| Index index() const { assert(is_index()); return index_; } |
| const std::string& name() const { assert(is_name()); return name_; } |
| |
| void set_index(Index); |
| void set_name(std::string&&); |
| void set_name(string_view); |
| |
| Location loc; |
| |
| private: |
| void Destroy(); |
| |
| VarType type_; |
| union { |
| Index index_; |
| std::string name_; |
| }; |
| }; |
| typedef std::vector<Var> VarVector; |
| |
| struct Const { |
| Const() : Const(I32Tag(), 0, Location()) {} |
| |
| static Const I32(uint32_t val = 0, const Location& loc = Location()) { |
| return Const(I32Tag(), val, loc); |
| } |
| |
| static Const I64(uint64_t val = 0, const Location& loc = Location()) { |
| return Const(I64Tag(), val, loc); |
| } |
| |
| static Const F32(uint32_t val = 0, const Location& loc = Location()) { |
| return Const(F32Tag(), val, loc); |
| } |
| |
| static Const F64(uint64_t val = 0, const Location& loc = Location()) { |
| return Const(F64Tag(), val, loc); |
| } |
| |
| static Const V128(v128 val, const Location& loc = Location()) { |
| return Const(V128Tag(), val, loc); |
| } |
| |
| Location loc; |
| Type type; |
| union { |
| uint32_t u32; |
| uint64_t u64; |
| uint32_t f32_bits; |
| uint64_t f64_bits; |
| uintptr_t ref_bits; |
| v128 vec128; |
| }; |
| |
| private: |
| // Struct tags to differentiate constructors. |
| struct I32Tag {}; |
| struct I64Tag {}; |
| struct F32Tag {}; |
| struct F64Tag {}; |
| struct RefTag {}; |
| struct V128Tag {}; |
| |
| Const(I32Tag, uint32_t val = 0, const Location& loc = Location()); |
| Const(I64Tag, uint64_t val = 0, const Location& loc = Location()); |
| Const(F32Tag, uint32_t val = 0, const Location& loc = Location()); |
| Const(F64Tag, uint64_t val = 0, const Location& loc = Location()); |
| Const(RefTag, uintptr_t val = 0, const Location& loc = Location()); |
| Const(V128Tag, v128 val = {{0, 0, 0, 0}}, const Location& loc = Location()); |
| }; |
| typedef std::vector<Const> ConstVector; |
| |
| struct FuncSignature { |
| TypeVector param_types; |
| TypeVector result_types; |
| |
| Index GetNumParams() const { return param_types.size(); } |
| Index GetNumResults() const { return result_types.size(); } |
| Type GetParamType(Index index) const { return param_types[index]; } |
| Type GetResultType(Index index) const { return result_types[index]; } |
| |
| bool operator==(const FuncSignature&) const; |
| }; |
| |
| struct FuncType { |
| explicit FuncType(string_view name) : name(name.to_string()) {} |
| |
| Index GetNumParams() const { return sig.GetNumParams(); } |
| Index GetNumResults() const { return sig.GetNumResults(); } |
| Type GetParamType(Index index) const { return sig.GetParamType(index); } |
| Type GetResultType(Index index) const { return sig.GetResultType(index); } |
| |
| std::string name; |
| FuncSignature sig; |
| }; |
| |
| struct FuncDeclaration { |
| Index GetNumParams() const { return sig.GetNumParams(); } |
| Index GetNumResults() const { return sig.GetNumResults(); } |
| Type GetParamType(Index index) const { return sig.GetParamType(index); } |
| Type GetResultType(Index index) const { return sig.GetResultType(index); } |
| |
| bool has_func_type = false; |
| Var type_var; |
| FuncSignature sig; |
| }; |
| |
| enum class ExprType { |
| AtomicLoad, |
| AtomicRmw, |
| AtomicRmwCmpxchg, |
| AtomicStore, |
| AtomicNotify, |
| AtomicWait, |
| Binary, |
| Block, |
| Br, |
| BrIf, |
| BrOnExn, |
| BrTable, |
| Call, |
| CallIndirect, |
| Compare, |
| Const, |
| Convert, |
| Drop, |
| GlobalGet, |
| GlobalSet, |
| If, |
| Load, |
| LocalGet, |
| LocalSet, |
| LocalTee, |
| Loop, |
| MemoryCopy, |
| DataDrop, |
| MemoryFill, |
| MemoryGrow, |
| MemoryInit, |
| MemorySize, |
| Nop, |
| RefIsNull, |
| RefFunc, |
| RefNull, |
| Rethrow, |
| Return, |
| ReturnCall, |
| ReturnCallIndirect, |
| Select, |
| SimdLaneOp, |
| SimdShuffleOp, |
| LoadSplat, |
| Store, |
| TableCopy, |
| ElemDrop, |
| TableInit, |
| TableGet, |
| TableGrow, |
| TableSize, |
| TableSet, |
| TableFill, |
| Ternary, |
| Throw, |
| Try, |
| Unary, |
| Unreachable, |
| |
| First = AtomicLoad, |
| Last = Unreachable |
| }; |
| |
| const char* GetExprTypeName(ExprType type); |
| |
| class Expr; |
| typedef intrusive_list<Expr> ExprList; |
| |
| typedef FuncDeclaration BlockDeclaration; |
| |
| struct Block { |
| Block() = default; |
| explicit Block(ExprList exprs) : exprs(std::move(exprs)) {} |
| |
| std::string label; |
| BlockDeclaration decl; |
| ExprList exprs; |
| Location end_loc; |
| }; |
| |
| class Expr : public intrusive_list_base<Expr> { |
| public: |
| WABT_DISALLOW_COPY_AND_ASSIGN(Expr); |
| Expr() = delete; |
| virtual ~Expr() = default; |
| |
| ExprType type() const { return type_; } |
| |
| Location loc; |
| |
| protected: |
| explicit Expr(ExprType type, const Location& loc = Location()) |
| : loc(loc), type_(type) {} |
| |
| ExprType type_; |
| }; |
| |
| const char* GetExprTypeName(const Expr& expr); |
| |
| template <ExprType TypeEnum> |
| class ExprMixin : public Expr { |
| public: |
| static bool classof(const Expr* expr) { return expr->type() == TypeEnum; } |
| |
| explicit ExprMixin(const Location& loc = Location()) : Expr(TypeEnum, loc) {} |
| }; |
| |
| typedef ExprMixin<ExprType::Drop> DropExpr; |
| typedef ExprMixin<ExprType::MemoryGrow> MemoryGrowExpr; |
| typedef ExprMixin<ExprType::MemorySize> MemorySizeExpr; |
| typedef ExprMixin<ExprType::MemoryCopy> MemoryCopyExpr; |
| typedef ExprMixin<ExprType::MemoryFill> MemoryFillExpr; |
| typedef ExprMixin<ExprType::Nop> NopExpr; |
| typedef ExprMixin<ExprType::Rethrow> RethrowExpr; |
| typedef ExprMixin<ExprType::Return> ReturnExpr; |
| typedef ExprMixin<ExprType::Unreachable> UnreachableExpr; |
| typedef ExprMixin<ExprType::RefNull> RefNullExpr; |
| typedef ExprMixin<ExprType::RefIsNull> RefIsNullExpr; |
| |
| template <ExprType TypeEnum> |
| class OpcodeExpr : public ExprMixin<TypeEnum> { |
| public: |
| OpcodeExpr(Opcode opcode, const Location& loc = Location()) |
| : ExprMixin<TypeEnum>(loc), opcode(opcode) {} |
| |
| Opcode opcode; |
| }; |
| |
| typedef OpcodeExpr<ExprType::Binary> BinaryExpr; |
| typedef OpcodeExpr<ExprType::Compare> CompareExpr; |
| typedef OpcodeExpr<ExprType::Convert> ConvertExpr; |
| typedef OpcodeExpr<ExprType::Unary> UnaryExpr; |
| typedef OpcodeExpr<ExprType::Ternary> TernaryExpr; |
| |
| class SimdLaneOpExpr : public ExprMixin<ExprType::SimdLaneOp> { |
| public: |
| SimdLaneOpExpr(Opcode opcode, uint64_t val, const Location& loc = Location()) |
| : ExprMixin<ExprType::SimdLaneOp>(loc), opcode(opcode), val(val) {} |
| |
| Opcode opcode; |
| uint64_t val; |
| }; |
| |
| class SimdShuffleOpExpr : public ExprMixin<ExprType::SimdShuffleOp> { |
| public: |
| SimdShuffleOpExpr(Opcode opcode, v128 val, const Location& loc = Location()) |
| : ExprMixin<ExprType::SimdShuffleOp>(loc), opcode(opcode), val(val) {} |
| |
| Opcode opcode; |
| v128 val; |
| }; |
| |
| template <ExprType TypeEnum> |
| class VarExpr : public ExprMixin<TypeEnum> { |
| public: |
| VarExpr(const Var& var, const Location& loc = Location()) |
| : ExprMixin<TypeEnum>(loc), var(var) {} |
| |
| Var var; |
| }; |
| |
| typedef VarExpr<ExprType::Br> BrExpr; |
| typedef VarExpr<ExprType::BrIf> BrIfExpr; |
| typedef VarExpr<ExprType::Call> CallExpr; |
| typedef VarExpr<ExprType::RefFunc> RefFuncExpr; |
| typedef VarExpr<ExprType::GlobalGet> GlobalGetExpr; |
| typedef VarExpr<ExprType::GlobalSet> GlobalSetExpr; |
| typedef VarExpr<ExprType::LocalGet> LocalGetExpr; |
| typedef VarExpr<ExprType::LocalSet> LocalSetExpr; |
| typedef VarExpr<ExprType::LocalTee> LocalTeeExpr; |
| typedef VarExpr<ExprType::ReturnCall> ReturnCallExpr; |
| typedef VarExpr<ExprType::Throw> ThrowExpr; |
| |
| typedef VarExpr<ExprType::MemoryInit> MemoryInitExpr; |
| typedef VarExpr<ExprType::DataDrop> DataDropExpr; |
| typedef VarExpr<ExprType::ElemDrop> ElemDropExpr; |
| typedef VarExpr<ExprType::TableGet> TableGetExpr; |
| typedef VarExpr<ExprType::TableSet> TableSetExpr; |
| typedef VarExpr<ExprType::TableGrow> TableGrowExpr; |
| typedef VarExpr<ExprType::TableSize> TableSizeExpr; |
| typedef VarExpr<ExprType::TableFill> TableFillExpr; |
| |
| class SelectExpr : public ExprMixin<ExprType::Select> { |
| public: |
| SelectExpr(TypeVector type, const Location& loc = Location()) |
| : ExprMixin<ExprType::Select>(loc), result_type(type) {} |
| TypeVector result_type; |
| }; |
| |
| class TableInitExpr : public ExprMixin<ExprType::TableInit> { |
| public: |
| TableInitExpr(const Var& segment_index, |
| const Var& table_index, |
| const Location& loc = Location()) |
| : ExprMixin<ExprType::TableInit>(loc), |
| segment_index(segment_index), |
| table_index(table_index) {} |
| |
| Var segment_index; |
| Var table_index; |
| }; |
| |
| class TableCopyExpr : public ExprMixin<ExprType::TableCopy> { |
| public: |
| TableCopyExpr(const Var& dst, |
| const Var& src, |
| const Location& loc = Location()) |
| : ExprMixin<ExprType::TableCopy>(loc), dst_table(dst), src_table(src) {} |
| |
| Var dst_table; |
| Var src_table; |
| }; |
| |
| class CallIndirectExpr : public ExprMixin<ExprType::CallIndirect> { |
| public: |
| explicit CallIndirectExpr(const Location& loc = Location()) |
| : ExprMixin<ExprType::CallIndirect>(loc) {} |
| |
| FuncDeclaration decl; |
| Var table; |
| }; |
| |
| class ReturnCallIndirectExpr : public ExprMixin<ExprType::ReturnCallIndirect> { |
| public: |
| explicit ReturnCallIndirectExpr(const Location &loc = Location()) |
| : ExprMixin<ExprType::ReturnCallIndirect>(loc) {} |
| |
| FuncDeclaration decl; |
| Var table; |
| }; |
| |
| template <ExprType TypeEnum> |
| class BlockExprBase : public ExprMixin<TypeEnum> { |
| public: |
| explicit BlockExprBase(const Location& loc = Location()) |
| : ExprMixin<TypeEnum>(loc) {} |
| |
| Block block; |
| }; |
| |
| typedef BlockExprBase<ExprType::Block> BlockExpr; |
| typedef BlockExprBase<ExprType::Loop> LoopExpr; |
| |
| class IfExpr : public ExprMixin<ExprType::If> { |
| public: |
| explicit IfExpr(const Location& loc = Location()) |
| : ExprMixin<ExprType::If>(loc) {} |
| |
| Block true_; |
| ExprList false_; |
| Location false_end_loc; |
| }; |
| |
| class TryExpr : public ExprMixin<ExprType::Try> { |
| public: |
| explicit TryExpr(const Location& loc = Location()) |
| : ExprMixin<ExprType::Try>(loc) {} |
| |
| Block block; |
| ExprList catch_; |
| }; |
| |
| class BrOnExnExpr : public ExprMixin<ExprType::BrOnExn> { |
| public: |
| BrOnExnExpr(const Location& loc = Location()) |
| : ExprMixin<ExprType::BrOnExn>(loc) {} |
| |
| Var label_var; |
| Var event_var; |
| }; |
| |
| class BrTableExpr : public ExprMixin<ExprType::BrTable> { |
| public: |
| BrTableExpr(const Location& loc = Location()) |
| : ExprMixin<ExprType::BrTable>(loc) {} |
| |
| VarVector targets; |
| Var default_target; |
| }; |
| |
| class ConstExpr : public ExprMixin<ExprType::Const> { |
| public: |
| ConstExpr(const Const& c, const Location& loc = Location()) |
| : ExprMixin<ExprType::Const>(loc), const_(c) {} |
| |
| Const const_; |
| }; |
| |
| // TODO(binji): Rename this, it is used for more than loads/stores now. |
| template <ExprType TypeEnum> |
| class LoadStoreExpr : public ExprMixin<TypeEnum> { |
| public: |
| LoadStoreExpr(Opcode opcode, |
| Address align, |
| uint32_t offset, |
| const Location& loc = Location()) |
| : ExprMixin<TypeEnum>(loc), |
| opcode(opcode), |
| align(align), |
| offset(offset) {} |
| |
| Opcode opcode; |
| Address align; |
| uint32_t offset; |
| }; |
| |
| typedef LoadStoreExpr<ExprType::Load> LoadExpr; |
| typedef LoadStoreExpr<ExprType::Store> StoreExpr; |
| typedef LoadStoreExpr<ExprType::AtomicLoad> AtomicLoadExpr; |
| typedef LoadStoreExpr<ExprType::AtomicStore> AtomicStoreExpr; |
| typedef LoadStoreExpr<ExprType::AtomicRmw> AtomicRmwExpr; |
| typedef LoadStoreExpr<ExprType::AtomicRmwCmpxchg> AtomicRmwCmpxchgExpr; |
| typedef LoadStoreExpr<ExprType::AtomicWait> AtomicWaitExpr; |
| typedef LoadStoreExpr<ExprType::AtomicNotify> AtomicNotifyExpr; |
| typedef LoadStoreExpr<ExprType::LoadSplat> LoadSplatExpr; |
| |
| struct Event { |
| explicit Event(string_view name) : name(name.to_string()) {} |
| |
| std::string name; |
| FuncDeclaration decl; |
| }; |
| |
| class LocalTypes { |
| public: |
| typedef std::pair<Type, Index> Decl; |
| typedef std::vector<Decl> Decls; |
| |
| struct const_iterator { |
| const_iterator(Decls::const_iterator decl, Index index) |
| : decl(decl), index(index) {} |
| Type operator*() const { return decl->first; } |
| const_iterator& operator++(); |
| const_iterator operator++(int); |
| |
| Decls::const_iterator decl; |
| Index index; |
| }; |
| |
| void Set(const TypeVector&); |
| |
| const Decls& decls() const { return decls_; } |
| |
| void AppendDecl(Type type, Index count) { |
| if (count != 0) { |
| decls_.emplace_back(type, count); |
| } |
| } |
| |
| Index size() const; |
| Type operator[](Index) const; |
| |
| const_iterator begin() const { return {decls_.begin(), 0}; } |
| const_iterator end() const { return {decls_.end(), 0}; } |
| |
| private: |
| Decls decls_; |
| }; |
| |
| inline LocalTypes::const_iterator& LocalTypes::const_iterator::operator++() { |
| ++index; |
| if (index >= decl->second) { |
| ++decl; |
| index = 0; |
| } |
| return *this; |
| } |
| |
| inline LocalTypes::const_iterator LocalTypes::const_iterator::operator++(int) { |
| const_iterator result = *this; |
| operator++(); |
| return result; |
| } |
| |
| inline bool operator==(const LocalTypes::const_iterator& lhs, |
| const LocalTypes::const_iterator& rhs) { |
| return lhs.decl == rhs.decl && lhs.index == rhs.index; |
| } |
| |
| inline bool operator!=(const LocalTypes::const_iterator& lhs, |
| const LocalTypes::const_iterator& rhs) { |
| return !operator==(lhs, rhs); |
| } |
| |
| struct Func { |
| explicit Func(string_view name) : name(name.to_string()) {} |
| |
| Type GetParamType(Index index) const { return decl.GetParamType(index); } |
| Type GetResultType(Index index) const { return decl.GetResultType(index); } |
| Type GetLocalType(Index index) const; |
| Type GetLocalType(const Var& var) const; |
| Index GetNumParams() const { return decl.GetNumParams(); } |
| Index GetNumLocals() const { return local_types.size(); } |
| Index GetNumParamsAndLocals() const { |
| return GetNumParams() + GetNumLocals(); |
| } |
| Index GetNumResults() const { return decl.GetNumResults(); } |
| Index GetLocalIndex(const Var&) const; |
| |
| std::string name; |
| FuncDeclaration decl; |
| LocalTypes local_types; |
| BindingHash bindings; |
| ExprList exprs; |
| }; |
| |
| struct Global { |
| explicit Global(string_view name) : name(name.to_string()) {} |
| |
| std::string name; |
| Type type = Type::Void; |
| bool mutable_ = false; |
| ExprList init_expr; |
| }; |
| |
| struct Table { |
| explicit Table(string_view name) |
| : name(name.to_string()), elem_type(Type::Funcref) {} |
| |
| std::string name; |
| Limits elem_limits; |
| Type elem_type; |
| }; |
| |
| enum class ElemExprKind { |
| RefNull, |
| RefFunc, |
| }; |
| |
| struct ElemExpr { |
| ElemExpr() : kind(ElemExprKind::RefNull) {} |
| explicit ElemExpr(Var var) : kind(ElemExprKind::RefFunc), var(var) {} |
| |
| ElemExprKind kind; |
| Var var; // Only used when kind == RefFunc. |
| }; |
| |
| typedef std::vector<ElemExpr> ElemExprVector; |
| |
| struct ElemSegment { |
| explicit ElemSegment(string_view name) : name(name.to_string()) {} |
| bool is_passive() const { return flags & SegPassive; } |
| |
| std::string name; |
| Var table_var; |
| uint8_t flags = 0; |
| Type elem_type; |
| ExprList offset; |
| ElemExprVector elem_exprs; |
| }; |
| |
| struct Memory { |
| explicit Memory(string_view name) : name(name.to_string()) {} |
| |
| std::string name; |
| Limits page_limits; |
| }; |
| |
| struct DataSegment { |
| explicit DataSegment(string_view name) : name(name.to_string()) {} |
| bool is_passive() const { return flags & SegPassive; } |
| |
| std::string name; |
| Var memory_var; |
| uint8_t flags = 0; |
| ExprList offset; |
| std::vector<uint8_t> data; |
| }; |
| |
| class Import { |
| public: |
| WABT_DISALLOW_COPY_AND_ASSIGN(Import); |
| Import() = delete; |
| virtual ~Import() = default; |
| |
| ExternalKind kind() const { return kind_; } |
| |
| std::string module_name; |
| std::string field_name; |
| |
| protected: |
| Import(ExternalKind kind) : kind_(kind) {} |
| |
| ExternalKind kind_; |
| }; |
| |
| template <ExternalKind TypeEnum> |
| class ImportMixin : public Import { |
| public: |
| static bool classof(const Import* import) { |
| return import->kind() == TypeEnum; |
| } |
| |
| ImportMixin() : Import(TypeEnum) {} |
| }; |
| |
| class FuncImport : public ImportMixin<ExternalKind::Func> { |
| public: |
| explicit FuncImport(string_view name = string_view()) |
| : ImportMixin<ExternalKind::Func>(), func(name) {} |
| |
| Func func; |
| }; |
| |
| class TableImport : public ImportMixin<ExternalKind::Table> { |
| public: |
| explicit TableImport(string_view name = string_view()) |
| : ImportMixin<ExternalKind::Table>(), table(name) {} |
| |
| Table table; |
| }; |
| |
| class MemoryImport : public ImportMixin<ExternalKind::Memory> { |
| public: |
| explicit MemoryImport(string_view name = string_view()) |
| : ImportMixin<ExternalKind::Memory>(), memory(name) {} |
| |
| Memory memory; |
| }; |
| |
| class GlobalImport : public ImportMixin<ExternalKind::Global> { |
| public: |
| explicit GlobalImport(string_view name = string_view()) |
| : ImportMixin<ExternalKind::Global>(), global(name) {} |
| |
| Global global; |
| }; |
| |
| class EventImport : public ImportMixin<ExternalKind::Event> { |
| public: |
| explicit EventImport(string_view name = string_view()) |
| : ImportMixin<ExternalKind::Event>(), event(name) {} |
| |
| Event event; |
| }; |
| |
| struct Export { |
| std::string name; |
| ExternalKind kind; |
| Var var; |
| }; |
| |
| enum class ModuleFieldType { |
| Func, |
| Global, |
| Import, |
| Export, |
| FuncType, |
| Table, |
| ElemSegment, |
| Memory, |
| DataSegment, |
| Start, |
| Event |
| }; |
| |
| class ModuleField : public intrusive_list_base<ModuleField> { |
| public: |
| WABT_DISALLOW_COPY_AND_ASSIGN(ModuleField); |
| ModuleField() = delete; |
| virtual ~ModuleField() = default; |
| |
| ModuleFieldType type() const { return type_; } |
| |
| Location loc; |
| |
| protected: |
| ModuleField(ModuleFieldType type, const Location& loc) |
| : loc(loc), type_(type) {} |
| |
| ModuleFieldType type_; |
| }; |
| |
| typedef intrusive_list<ModuleField> ModuleFieldList; |
| |
| template <ModuleFieldType TypeEnum> |
| class ModuleFieldMixin : public ModuleField { |
| public: |
| static bool classof(const ModuleField* field) { |
| return field->type() == TypeEnum; |
| } |
| |
| explicit ModuleFieldMixin(const Location& loc) : ModuleField(TypeEnum, loc) {} |
| }; |
| |
| class FuncModuleField : public ModuleFieldMixin<ModuleFieldType::Func> { |
| public: |
| explicit FuncModuleField(const Location& loc = Location(), |
| string_view name = string_view()) |
| : ModuleFieldMixin<ModuleFieldType::Func>(loc), func(name) {} |
| |
| Func func; |
| }; |
| |
| class GlobalModuleField : public ModuleFieldMixin<ModuleFieldType::Global> { |
| public: |
| explicit GlobalModuleField(const Location& loc = Location(), |
| string_view name = string_view()) |
| : ModuleFieldMixin<ModuleFieldType::Global>(loc), global(name) {} |
| |
| Global global; |
| }; |
| |
| class ImportModuleField : public ModuleFieldMixin<ModuleFieldType::Import> { |
| public: |
| explicit ImportModuleField(const Location& loc = Location()) |
| : ModuleFieldMixin<ModuleFieldType::Import>(loc) {} |
| explicit ImportModuleField(std::unique_ptr<Import> import, |
| const Location& loc = Location()) |
| : ModuleFieldMixin<ModuleFieldType::Import>(loc), |
| import(std::move(import)) {} |
| |
| std::unique_ptr<Import> import; |
| }; |
| |
| class ExportModuleField : public ModuleFieldMixin<ModuleFieldType::Export> { |
| public: |
| explicit ExportModuleField(const Location& loc = Location()) |
| : ModuleFieldMixin<ModuleFieldType::Export>(loc) {} |
| |
| Export export_; |
| }; |
| |
| class FuncTypeModuleField : public ModuleFieldMixin<ModuleFieldType::FuncType> { |
| public: |
| explicit FuncTypeModuleField(const Location& loc = Location(), |
| string_view name = string_view()) |
| : ModuleFieldMixin<ModuleFieldType::FuncType>(loc), func_type(name) {} |
| |
| FuncType func_type; |
| }; |
| |
| class TableModuleField : public ModuleFieldMixin<ModuleFieldType::Table> { |
| public: |
| explicit TableModuleField(const Location& loc = Location(), |
| string_view name = string_view()) |
| : ModuleFieldMixin<ModuleFieldType::Table>(loc), table(name) {} |
| |
| Table table; |
| }; |
| |
| class ElemSegmentModuleField |
| : public ModuleFieldMixin<ModuleFieldType::ElemSegment> { |
| public: |
| explicit ElemSegmentModuleField(const Location& loc = Location(), |
| string_view name = string_view()) |
| : ModuleFieldMixin<ModuleFieldType::ElemSegment>(loc), |
| elem_segment(name) {} |
| |
| ElemSegment elem_segment; |
| }; |
| |
| class MemoryModuleField : public ModuleFieldMixin<ModuleFieldType::Memory> { |
| public: |
| explicit MemoryModuleField(const Location& loc = Location(), |
| string_view name = string_view()) |
| : ModuleFieldMixin<ModuleFieldType::Memory>(loc), memory(name) {} |
| |
| Memory memory; |
| }; |
| |
| class DataSegmentModuleField |
| : public ModuleFieldMixin<ModuleFieldType::DataSegment> { |
| public: |
| explicit DataSegmentModuleField(const Location& loc = Location(), |
| string_view name = string_view()) |
| : ModuleFieldMixin<ModuleFieldType::DataSegment>(loc), |
| data_segment(name) {} |
| |
| DataSegment data_segment; |
| }; |
| |
| class EventModuleField : public ModuleFieldMixin<ModuleFieldType::Event> { |
| public: |
| explicit EventModuleField(const Location& loc = Location(), |
| string_view name = string_view()) |
| : ModuleFieldMixin<ModuleFieldType::Event>(loc), event(name) {} |
| |
| Event event; |
| }; |
| |
| class StartModuleField : public ModuleFieldMixin<ModuleFieldType::Start> { |
| public: |
| explicit StartModuleField(Var start = Var(), const Location& loc = Location()) |
| : ModuleFieldMixin<ModuleFieldType::Start>(loc), start(start) {} |
| |
| Var start; |
| }; |
| |
| struct Module { |
| Index GetFuncTypeIndex(const Var&) const; |
| Index GetFuncTypeIndex(const FuncDeclaration&) const; |
| Index GetFuncTypeIndex(const FuncSignature&) const; |
| const FuncType* GetFuncType(const Var&) const; |
| FuncType* GetFuncType(const Var&); |
| Index GetFuncIndex(const Var&) const; |
| const Func* GetFunc(const Var&) const; |
| Func* GetFunc(const Var&); |
| Index GetTableIndex(const Var&) const; |
| const Table* GetTable(const Var&) const; |
| Table* GetTable(const Var&); |
| Index GetMemoryIndex(const Var&) const; |
| const Memory* GetMemory(const Var&) const; |
| Memory* GetMemory(const Var&); |
| Index GetGlobalIndex(const Var&) const; |
| const Global* GetGlobal(const Var&) const; |
| Global* GetGlobal(const Var&); |
| const Export* GetExport(string_view) const; |
| Event* GetEvent(const Var&) const; |
| Index GetEventIndex(const Var&) const; |
| const DataSegment* GetDataSegment(const Var&) const; |
| DataSegment* GetDataSegment(const Var&); |
| Index GetDataSegmentIndex(const Var&) const; |
| const ElemSegment* GetElemSegment(const Var&) const; |
| ElemSegment* GetElemSegment(const Var&); |
| Index GetElemSegmentIndex(const Var&) const; |
| |
| bool IsImport(ExternalKind kind, const Var&) const; |
| bool IsImport(const Export& export_) const { |
| return IsImport(export_.kind, export_.var); |
| } |
| |
| // TODO(binji): move this into a builder class? |
| void AppendField(std::unique_ptr<DataSegmentModuleField>); |
| void AppendField(std::unique_ptr<ElemSegmentModuleField>); |
| void AppendField(std::unique_ptr<EventModuleField>); |
| void AppendField(std::unique_ptr<ExportModuleField>); |
| void AppendField(std::unique_ptr<FuncModuleField>); |
| void AppendField(std::unique_ptr<FuncTypeModuleField>); |
| void AppendField(std::unique_ptr<GlobalModuleField>); |
| void AppendField(std::unique_ptr<ImportModuleField>); |
| void AppendField(std::unique_ptr<MemoryModuleField>); |
| void AppendField(std::unique_ptr<StartModuleField>); |
| void AppendField(std::unique_ptr<TableModuleField>); |
| void AppendField(std::unique_ptr<ModuleField>); |
| void AppendFields(ModuleFieldList*); |
| |
| Location loc; |
| std::string name; |
| ModuleFieldList fields; |
| |
| Index num_event_imports = 0; |
| Index num_func_imports = 0; |
| Index num_table_imports = 0; |
| Index num_memory_imports = 0; |
| Index num_global_imports = 0; |
| |
| // Cached for convenience; the pointers are shared with values that are |
| // stored in either ModuleField or Import. |
| std::vector<Event*> events; |
| std::vector<Func*> funcs; |
| std::vector<Global*> globals; |
| std::vector<Import*> imports; |
| std::vector<Export*> exports; |
| std::vector<FuncType*> func_types; |
| std::vector<Table*> tables; |
| std::vector<ElemSegment*> elem_segments; |
| std::vector<Memory*> memories; |
| std::vector<DataSegment*> data_segments; |
| std::vector<Var*> starts; |
| |
| BindingHash event_bindings; |
| BindingHash func_bindings; |
| BindingHash global_bindings; |
| BindingHash export_bindings; |
| BindingHash func_type_bindings; |
| BindingHash table_bindings; |
| BindingHash memory_bindings; |
| BindingHash data_segment_bindings; |
| BindingHash elem_segment_bindings; |
| }; |
| |
| enum class ScriptModuleType { |
| Text, |
| Binary, |
| Quoted, |
| }; |
| |
| // A ScriptModule is a module that may not yet be decoded. This allows for text |
| // and binary parsing errors to be deferred until validation time. |
| class ScriptModule { |
| public: |
| WABT_DISALLOW_COPY_AND_ASSIGN(ScriptModule); |
| ScriptModule() = delete; |
| virtual ~ScriptModule() = default; |
| |
| ScriptModuleType type() const { return type_; } |
| virtual const Location& location() const = 0; |
| |
| protected: |
| explicit ScriptModule(ScriptModuleType type) : type_(type) {} |
| |
| ScriptModuleType type_; |
| }; |
| |
| template <ScriptModuleType TypeEnum> |
| class ScriptModuleMixin : public ScriptModule { |
| public: |
| static bool classof(const ScriptModule* script_module) { |
| return script_module->type() == TypeEnum; |
| } |
| |
| ScriptModuleMixin() : ScriptModule(TypeEnum) {} |
| }; |
| |
| class TextScriptModule : public ScriptModuleMixin<ScriptModuleType::Text> { |
| public: |
| const Location& location() const override { return module.loc; } |
| |
| Module module; |
| }; |
| |
| template <ScriptModuleType TypeEnum> |
| class DataScriptModule : public ScriptModuleMixin<TypeEnum> { |
| public: |
| const Location& location() const override { return loc; } |
| |
| Location loc; |
| std::string name; |
| std::vector<uint8_t> data; |
| }; |
| |
| typedef DataScriptModule<ScriptModuleType::Binary> BinaryScriptModule; |
| typedef DataScriptModule<ScriptModuleType::Quoted> QuotedScriptModule; |
| |
| enum class ActionType { |
| Invoke, |
| Get, |
| }; |
| |
| class Action { |
| public: |
| WABT_DISALLOW_COPY_AND_ASSIGN(Action); |
| Action() = delete; |
| virtual ~Action() = default; |
| |
| ActionType type() const { return type_; } |
| |
| Location loc; |
| Var module_var; |
| std::string name; |
| |
| protected: |
| explicit Action(ActionType type, const Location& loc = Location()) |
| : loc(loc), type_(type) {} |
| |
| ActionType type_; |
| }; |
| |
| typedef std::unique_ptr<Action> ActionPtr; |
| |
| template <ActionType TypeEnum> |
| class ActionMixin : public Action { |
| public: |
| static bool classof(const Action* action) { |
| return action->type() == TypeEnum; |
| } |
| |
| explicit ActionMixin(const Location& loc = Location()) |
| : Action(TypeEnum, loc) {} |
| }; |
| |
| class GetAction : public ActionMixin<ActionType::Get> { |
| public: |
| explicit GetAction(const Location& loc = Location()) |
| : ActionMixin<ActionType::Get>(loc) {} |
| }; |
| |
| class InvokeAction : public ActionMixin<ActionType::Invoke> { |
| public: |
| explicit InvokeAction(const Location& loc = Location()) |
| : ActionMixin<ActionType::Invoke>(loc) {} |
| |
| ConstVector args; |
| }; |
| |
| enum class CommandType { |
| Module, |
| Action, |
| Register, |
| AssertMalformed, |
| AssertInvalid, |
| AssertUnlinkable, |
| AssertUninstantiable, |
| AssertReturn, |
| AssertReturnFunc, |
| AssertReturnCanonicalNan, |
| AssertReturnArithmeticNan, |
| AssertTrap, |
| AssertExhaustion, |
| |
| First = Module, |
| Last = AssertExhaustion, |
| }; |
| static const int kCommandTypeCount = WABT_ENUM_COUNT(CommandType); |
| |
| class Command { |
| public: |
| WABT_DISALLOW_COPY_AND_ASSIGN(Command); |
| Command() = delete; |
| virtual ~Command() = default; |
| |
| CommandType type; |
| |
| protected: |
| explicit Command(CommandType type) : type(type) {} |
| }; |
| |
| template <CommandType TypeEnum> |
| class CommandMixin : public Command { |
| public: |
| static bool classof(const Command* cmd) { return cmd->type == TypeEnum; } |
| CommandMixin() : Command(TypeEnum) {} |
| }; |
| |
| class ModuleCommand : public CommandMixin<CommandType::Module> { |
| public: |
| Module module; |
| }; |
| |
| template <CommandType TypeEnum> |
| class ActionCommandBase : public CommandMixin<TypeEnum> { |
| public: |
| ActionPtr action; |
| }; |
| |
| typedef ActionCommandBase<CommandType::Action> ActionCommand; |
| typedef ActionCommandBase<CommandType::AssertReturnCanonicalNan> |
| AssertReturnCanonicalNanCommand; |
| typedef ActionCommandBase<CommandType::AssertReturnArithmeticNan> |
| AssertReturnArithmeticNanCommand; |
| |
| class RegisterCommand : public CommandMixin<CommandType::Register> { |
| public: |
| RegisterCommand(string_view module_name, const Var& var) |
| : module_name(module_name), var(var) {} |
| |
| std::string module_name; |
| Var var; |
| }; |
| |
| class AssertReturnCommand : public CommandMixin<CommandType::AssertReturn> { |
| public: |
| ActionPtr action; |
| ConstVector expected; |
| }; |
| |
| class AssertReturnFuncCommand |
| : public CommandMixin<CommandType::AssertReturnFunc> { |
| public: |
| ActionPtr action; |
| }; |
| |
| template <CommandType TypeEnum> |
| class AssertTrapCommandBase : public CommandMixin<TypeEnum> { |
| public: |
| ActionPtr action; |
| std::string text; |
| }; |
| |
| typedef AssertTrapCommandBase<CommandType::AssertTrap> AssertTrapCommand; |
| typedef AssertTrapCommandBase<CommandType::AssertExhaustion> |
| AssertExhaustionCommand; |
| |
| template <CommandType TypeEnum> |
| class AssertModuleCommand : public CommandMixin<TypeEnum> { |
| public: |
| std::unique_ptr<ScriptModule> module; |
| std::string text; |
| }; |
| |
| typedef AssertModuleCommand<CommandType::AssertMalformed> |
| AssertMalformedCommand; |
| typedef AssertModuleCommand<CommandType::AssertInvalid> AssertInvalidCommand; |
| typedef AssertModuleCommand<CommandType::AssertUnlinkable> |
| AssertUnlinkableCommand; |
| typedef AssertModuleCommand<CommandType::AssertUninstantiable> |
| AssertUninstantiableCommand; |
| |
| typedef std::unique_ptr<Command> CommandPtr; |
| typedef std::vector<CommandPtr> CommandPtrVector; |
| |
| struct Script { |
| WABT_DISALLOW_COPY_AND_ASSIGN(Script); |
| Script() = default; |
| |
| const Module* GetFirstModule() const; |
| Module* GetFirstModule(); |
| const Module* GetModule(const Var&) const; |
| |
| CommandPtrVector commands; |
| BindingHash module_bindings; |
| }; |
| |
| void MakeTypeBindingReverseMapping( |
| size_t num_types, |
| const BindingHash& bindings, |
| std::vector<std::string>* out_reverse_mapping); |
| |
| } // namespace wabt |
| |
| #endif /* WABT_IR_H_ */ |