/* * 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_AST_H_ #define WABT_AST_H_ #include #include #include #include #include #include #include "binding-hash.h" #include "common.h" namespace wabt { enum class VarType { Index, Name, }; struct Var { // Keep the default constructor trivial so it can be used as a union member. Var() = default; explicit Var(int64_t index); explicit Var(const StringSlice& name); Location loc; VarType type; union { int64_t index; StringSlice name; }; }; typedef std::vector VarVector; typedef StringSlice Label; struct Const { // Struct tags to differentiate constructors. struct I32 {}; struct I64 {}; struct F32 {}; struct F64 {}; // Keep the default constructor trivial so it can be used as a union member. Const() = default; Const(I32, uint32_t); Const(I64, uint64_t); Const(F32, uint32_t); Const(F64, uint64_t); Location loc; Type type; union { uint32_t u32; uint64_t u64; uint32_t f32_bits; uint64_t f64_bits; }; }; typedef std::vector ConstVector; enum class ExprType { Binary, Block, Br, BrIf, BrTable, Call, CallIndirect, Compare, Const, Convert, CurrentMemory, Drop, GetGlobal, GetLocal, GrowMemory, If, Load, Loop, Nop, Return, Select, SetGlobal, SetLocal, Store, TeeLocal, Unary, Unreachable, }; typedef TypeVector BlockSignature; struct Block { WABT_DISALLOW_COPY_AND_ASSIGN(Block); Block(); explicit Block(struct Expr* first); ~Block(); Label label; BlockSignature sig; struct Expr* first; }; struct Expr { WABT_DISALLOW_COPY_AND_ASSIGN(Expr); Expr(); explicit Expr(ExprType); ~Expr(); static Expr* CreateBinary(Opcode); static Expr* CreateBlock(Block*); static Expr* CreateBr(Var); static Expr* CreateBrIf(Var); static Expr* CreateBrTable(VarVector* targets, Var default_target); static Expr* CreateCall(Var); static Expr* CreateCallIndirect(Var); static Expr* CreateCompare(Opcode); static Expr* CreateConst(const Const&); static Expr* CreateConvert(Opcode); static Expr* CreateCurrentMemory(); static Expr* CreateDrop(); static Expr* CreateGetGlobal(Var); static Expr* CreateGetLocal(Var); static Expr* CreateGrowMemory(); static Expr* CreateIf(struct Block* true_, struct Expr* false_ = nullptr); static Expr* CreateLoad(Opcode, uint32_t align, uint64_t offset); static Expr* CreateLoop(struct Block*); static Expr* CreateNop(); static Expr* CreateReturn(); static Expr* CreateSelect(); static Expr* CreateSetGlobal(Var); static Expr* CreateSetLocal(Var); static Expr* CreateStore(Opcode, uint32_t align, uint64_t offset); static Expr* CreateTeeLocal(Var); static Expr* CreateUnary(Opcode); static Expr* CreateUnreachable(); Location loc; ExprType type; Expr* next; union { struct { Opcode opcode; } binary, compare, convert, unary; struct Block *block, *loop; struct { Var var; } br, br_if; struct { VarVector* targets; Var default_target; } br_table; struct { Var var; } call, call_indirect; struct Const const_; struct { Var var; } get_global, set_global; struct { Var var; } get_local, set_local, tee_local; struct { struct Block* true_; struct Expr* false_; } if_; struct { Opcode opcode; uint32_t align; uint64_t offset; } load, store; }; }; struct FuncSignature { TypeVector param_types; TypeVector result_types; }; struct FuncType { WABT_DISALLOW_COPY_AND_ASSIGN(FuncType); FuncType(); ~FuncType(); StringSlice name; FuncSignature sig; }; struct FuncDeclaration { WABT_DISALLOW_COPY_AND_ASSIGN(FuncDeclaration); FuncDeclaration(); ~FuncDeclaration(); bool has_func_type; Var type_var; FuncSignature sig; }; struct Func { WABT_DISALLOW_COPY_AND_ASSIGN(Func); Func(); ~Func(); StringSlice name; FuncDeclaration decl; TypeVector local_types; BindingHash param_bindings; BindingHash local_bindings; Expr* first_expr; }; struct Global { WABT_DISALLOW_COPY_AND_ASSIGN(Global); Global(); ~Global(); StringSlice name; Type type; bool mutable_; Expr* init_expr; }; struct Table { WABT_DISALLOW_COPY_AND_ASSIGN(Table); Table(); ~Table(); StringSlice name; Limits elem_limits; }; struct ElemSegment { WABT_DISALLOW_COPY_AND_ASSIGN(ElemSegment); ElemSegment(); ~ElemSegment(); Var table_var; Expr* offset; VarVector vars; }; struct Memory { WABT_DISALLOW_COPY_AND_ASSIGN(Memory); Memory(); ~Memory(); StringSlice name; Limits page_limits; }; struct DataSegment { WABT_DISALLOW_COPY_AND_ASSIGN(DataSegment); DataSegment(); ~DataSegment(); Var memory_var; Expr* offset; char* data; size_t size; }; struct Import { WABT_DISALLOW_COPY_AND_ASSIGN(Import); Import(); ~Import(); StringSlice module_name; StringSlice field_name; ExternalKind kind; union { /* an imported func is has the type Func so it can be more easily * included in the Module's vector of funcs; but only the * FuncDeclaration will have any useful information */ Func* func; Table* table; Memory* memory; Global* global; }; }; struct Export { WABT_DISALLOW_COPY_AND_ASSIGN(Export); Export(); ~Export(); StringSlice name; ExternalKind kind; Var var; }; enum class ModuleFieldType { Func, Global, Import, Export, FuncType, Table, ElemSegment, Memory, DataSegment, Start, }; struct ModuleField { WABT_DISALLOW_COPY_AND_ASSIGN(ModuleField); ModuleField(); ~ModuleField(); Location loc; ModuleFieldType type; struct ModuleField* next; union { Func* func; Global* global; Import* import; Export* export_; FuncType* func_type; Table* table; ElemSegment* elem_segment; Memory* memory; DataSegment* data_segment; Var start; }; }; struct Module { WABT_DISALLOW_COPY_AND_ASSIGN(Module); Module(); ~Module(); Location loc; StringSlice name; ModuleField* first_field; ModuleField* last_field; uint32_t num_func_imports; uint32_t num_table_imports; uint32_t num_memory_imports; uint32_t num_global_imports; /* cached for convenience; the pointers are shared with values that are * stored in either ModuleField or Import. */ std::vector funcs; std::vector globals; std::vector imports; std::vector exports; std::vector func_types; std::vector tables; std::vector elem_segments; std::vector memories; std::vector data_segments; Var* start; BindingHash func_bindings; BindingHash global_bindings; BindingHash export_bindings; BindingHash func_type_bindings; BindingHash table_bindings; BindingHash memory_bindings; }; enum class RawModuleType { Text, Binary, }; /* "raw" means that the binary module has not yet been decoded. This is only * necessary when embedded in assert_invalid. In that case we want to defer * decoding errors until wabt_check_assert_invalid is called. This isn't needed * when parsing text, as assert_invalid always assumes that text parsing * succeeds. */ struct RawModule { WABT_DISALLOW_COPY_AND_ASSIGN(RawModule); RawModule(); ~RawModule(); RawModuleType type; union { Module* text; struct { Location loc; StringSlice name; char* data; size_t size; } binary; }; }; enum class ActionType { Invoke, Get, }; struct ActionInvoke { WABT_DISALLOW_COPY_AND_ASSIGN(ActionInvoke); ActionInvoke(); ConstVector args; }; struct Action { WABT_DISALLOW_COPY_AND_ASSIGN(Action); Action(); ~Action(); Location loc; ActionType type; Var module_var; StringSlice name; union { ActionInvoke* invoke; struct {} get; }; }; enum class CommandType { Module, Action, Register, AssertMalformed, AssertInvalid, /* This is a module that is invalid, but cannot be written as a binary module * (e.g. it has unresolvable names.) */ AssertInvalidNonBinary, AssertUnlinkable, AssertUninstantiable, AssertReturn, AssertReturnCanonicalNan, AssertReturnArithmeticNan, AssertTrap, AssertExhaustion, First = Module, Last = AssertExhaustion, }; static const int kCommandTypeCount = WABT_ENUM_COUNT(CommandType); struct Command { WABT_DISALLOW_COPY_AND_ASSIGN(Command); Command(); ~Command(); CommandType type; union { Module* module; Action* action; struct { StringSlice module_name; Var var; } register_; struct { Action* action; ConstVector* expected; } assert_return; struct { Action* action; } assert_return_canonical_nan, assert_return_arithmetic_nan; struct { Action* action; StringSlice text; } assert_trap; struct { RawModule* module; StringSlice text; } assert_malformed, assert_invalid, assert_unlinkable, assert_uninstantiable; }; }; typedef std::vector> CommandPtrVector; struct Script { WABT_DISALLOW_COPY_AND_ASSIGN(Script); Script(); CommandPtrVector commands; BindingHash module_bindings; }; struct ExprVisitor { void* user_data; Result (*on_binary_expr)(Expr*, void* user_data); Result (*begin_block_expr)(Expr*, void* user_data); Result (*end_block_expr)(Expr*, void* user_data); Result (*on_br_expr)(Expr*, void* user_data); Result (*on_br_if_expr)(Expr*, void* user_data); Result (*on_br_table_expr)(Expr*, void* user_data); Result (*on_call_expr)(Expr*, void* user_data); Result (*on_call_indirect_expr)(Expr*, void* user_data); Result (*on_compare_expr)(Expr*, void* user_data); Result (*on_const_expr)(Expr*, void* user_data); Result (*on_convert_expr)(Expr*, void* user_data); Result (*on_current_memory_expr)(Expr*, void* user_data); Result (*on_drop_expr)(Expr*, void* user_data); Result (*on_get_global_expr)(Expr*, void* user_data); Result (*on_get_local_expr)(Expr*, void* user_data); Result (*on_grow_memory_expr)(Expr*, void* user_data); Result (*begin_if_expr)(Expr*, void* user_data); Result (*after_if_true_expr)(Expr*, void* user_data); Result (*end_if_expr)(Expr*, void* user_data); Result (*on_load_expr)(Expr*, void* user_data); Result (*begin_loop_expr)(Expr*, void* user_data); Result (*end_loop_expr)(Expr*, void* user_data); Result (*on_nop_expr)(Expr*, void* user_data); Result (*on_return_expr)(Expr*, void* user_data); Result (*on_select_expr)(Expr*, void* user_data); Result (*on_set_global_expr)(Expr*, void* user_data); Result (*on_set_local_expr)(Expr*, void* user_data); Result (*on_store_expr)(Expr*, void* user_data); Result (*on_tee_local_expr)(Expr*, void* user_data); Result (*on_unary_expr)(Expr*, void* user_data); Result (*on_unreachable_expr)(Expr*, void* user_data); }; ModuleField* append_module_field(Module*); /* ownership of the function signature is passed to the module */ FuncType* append_implicit_func_type(Location*, Module*, FuncSignature*); /* destruction functions. not needed unless you're creating your own AST elements */ void destroy_expr_list(Expr*); void destroy_var(Var*); /* traversal functions */ Result visit_func(Func* func, ExprVisitor*); Result visit_expr_list(Expr* expr, ExprVisitor*); /* convenience functions for looking through the AST */ int get_index_from_var(const BindingHash* bindings, const Var* var); int get_func_index_by_var(const Module* module, const Var* var); int get_global_index_by_var(const Module* func, const Var* var); int get_func_type_index_by_var(const Module* module, const Var* var); int get_func_type_index_by_sig(const Module* module, const FuncSignature* sig); int get_func_type_index_by_decl(const Module* module, const FuncDeclaration* decl); int get_table_index_by_var(const Module* module, const Var* var); int get_memory_index_by_var(const Module* module, const Var* var); int get_import_index_by_var(const Module* module, const Var* var); int get_local_index_by_var(const Func* func, const Var* var); int get_module_index_by_var(const Script* script, const Var* var); Func* get_func_by_var(const Module* module, const Var* var); Global* get_global_by_var(const Module* func, const Var* var); FuncType* get_func_type_by_var(const Module* module, const Var* var); Table* get_table_by_var(const Module* module, const Var* var); Memory* get_memory_by_var(const Module* module, const Var* var); Import* get_import_by_var(const Module* module, const Var* var); Export* get_export_by_name(const Module* module, const StringSlice* name); Module* get_first_module(const Script* script); Module* get_module_by_var(const Script* script, const Var* var); void make_type_binding_reverse_mapping( const TypeVector&, const BindingHash&, std::vector* out_reverse_mapping); static WABT_INLINE bool decl_has_func_type(const FuncDeclaration* decl) { return decl->has_func_type; } static WABT_INLINE bool signatures_are_equal(const FuncSignature* sig1, const FuncSignature* sig2) { return sig1->param_types == sig2->param_types && sig1->result_types == sig2->result_types; } static WABT_INLINE size_t get_num_params(const Func* func) { return func->decl.sig.param_types.size(); } static WABT_INLINE size_t get_num_results(const Func* func) { return func->decl.sig.result_types.size(); } static WABT_INLINE size_t get_num_locals(const Func* func) { return func->local_types.size(); } static WABT_INLINE size_t get_num_params_and_locals(const Func* func) { return get_num_params(func) + get_num_locals(func); } static WABT_INLINE Type get_param_type(const Func* func, int index) { assert(static_cast(index) < func->decl.sig.param_types.size()); return func->decl.sig.param_types[index]; } static WABT_INLINE Type get_local_type(const Func* func, int index) { assert(static_cast(index) < get_num_locals(func)); return func->local_types[index]; } static WABT_INLINE Type get_result_type(const Func* func, int index) { assert(static_cast(index) < func->decl.sig.result_types.size()); return func->decl.sig.result_types[index]; } static WABT_INLINE Type get_func_type_param_type(const FuncType* func_type, int index) { return func_type->sig.param_types[index]; } static WABT_INLINE size_t get_func_type_num_params(const FuncType* func_type) { return func_type->sig.param_types.size(); } static WABT_INLINE Type get_func_type_result_type(const FuncType* func_type, int index) { return func_type->sig.result_types[index]; } static WABT_INLINE size_t get_func_type_num_results(const FuncType* func_type) { return func_type->sig.result_types.size(); } static WABT_INLINE const Location* get_raw_module_location( const RawModule* raw) { switch (raw->type) { case RawModuleType::Binary: return &raw->binary.loc; case RawModuleType::Text: return &raw->text->loc; default: assert(0); return nullptr; } } } // namespace wabt #endif /* WABT_AST_H_ */