blob: 346f225778d03175d682f1f62d6145f0e42c4d31 [file] [log] [blame]
/*
* 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 <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
#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<Var> 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<Const> 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<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;
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<std::unique_ptr<Command>> 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<std::string>* 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<size_t>(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<size_t>(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<size_t>(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_ */