/* * 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. */ #include "ast.h" #include #include namespace wabt { int get_index_from_var(const BindingHash* hash, const Var* var) { if (var->type == VarType::Name) return hash->find_index(var->name); return static_cast(var->index); } Export* get_export_by_name(const Module* module, const StringSlice* name) { int index = module->export_bindings.find_index(*name); if (index == -1) return nullptr; return module->exports[index]; } int get_func_index_by_var(const Module* module, const Var* var) { return get_index_from_var(&module->func_bindings, var); } int get_global_index_by_var(const Module* module, const Var* var) { return get_index_from_var(&module->global_bindings, var); } int get_table_index_by_var(const Module* module, const Var* var) { return get_index_from_var(&module->table_bindings, var); } int get_memory_index_by_var(const Module* module, const Var* var) { return get_index_from_var(&module->memory_bindings, var); } int get_func_type_index_by_var(const Module* module, const Var* var) { return get_index_from_var(&module->func_type_bindings, var); } int get_local_index_by_var(const Func* func, const Var* var) { if (var->type == VarType::Index) return static_cast(var->index); int result = func->param_bindings.find_index(var->name); if (result != -1) return result; result = func->local_bindings.find_index(var->name); if (result == -1) return result; /* the locals start after all the params */ return func->decl.sig.param_types.size() + result; } int get_module_index_by_var(const Script* script, const Var* var) { return get_index_from_var(&script->module_bindings, var); } Func* get_func_by_var(const Module* module, const Var* var) { int index = get_index_from_var(&module->func_bindings, var); if (index < 0 || static_cast(index) >= module->funcs.size()) return nullptr; return module->funcs[index]; } Global* get_global_by_var(const Module* module, const Var* var) { int index = get_index_from_var(&module->global_bindings, var); if (index < 0 || static_cast(index) >= module->globals.size()) return nullptr; return module->globals[index]; } Table* get_table_by_var(const Module* module, const Var* var) { int index = get_index_from_var(&module->table_bindings, var); if (index < 0 || static_cast(index) >= module->tables.size()) return nullptr; return module->tables[index]; } Memory* get_memory_by_var(const Module* module, const Var* var) { int index = get_index_from_var(&module->memory_bindings, var); if (index < 0 || static_cast(index) >= module->memories.size()) return nullptr; return module->memories[index]; } FuncType* get_func_type_by_var(const Module* module, const Var* var) { int index = get_index_from_var(&module->func_type_bindings, var); if (index < 0 || static_cast(index) >= module->func_types.size()) return nullptr; return module->func_types[index]; } int get_func_type_index_by_sig(const Module* module, const FuncSignature* sig) { for (size_t i = 0; i < module->func_types.size(); ++i) if (signatures_are_equal(&module->func_types[i]->sig, sig)) return i; return -1; } int get_func_type_index_by_decl(const Module* module, const FuncDeclaration* decl) { if (decl_has_func_type(decl)) { return get_func_type_index_by_var(module, &decl->type_var); } else { return get_func_type_index_by_sig(module, &decl->sig); } } Module* get_first_module(const Script* script) { for (const std::unique_ptr& command : script->commands) { if (command->type == CommandType::Module) return command->module; } return nullptr; } Module* get_module_by_var(const Script* script, const Var* var) { int index = get_index_from_var(&script->module_bindings, var); if (index < 0 || static_cast(index) >= script->commands.size()) return nullptr; const Command& command = *script->commands[index].get(); assert(command.type == CommandType::Module); return command.module; } void make_type_binding_reverse_mapping( const TypeVector& types, const BindingHash& bindings, std::vector* out_reverse_mapping) { out_reverse_mapping->clear(); out_reverse_mapping->resize(types.size()); for (const auto& pair : bindings) { assert(static_cast(pair.second.index) < out_reverse_mapping->size()); (*out_reverse_mapping)[pair.second.index] = pair.first; } } ModuleField* append_module_field(Module* module) { ModuleField* result = new ModuleField(); if (!module->first_field) module->first_field = result; else if (module->last_field) module->last_field->next = result; module->last_field = result; return result; } FuncType* append_implicit_func_type(Location* loc, Module* module, FuncSignature* sig) { ModuleField* field = append_module_field(module); field->loc = *loc; field->type = ModuleFieldType::FuncType; field->func_type = new FuncType(); field->func_type->sig = *sig; module->func_types.push_back(field->func_type); return field->func_type; } void destroy_var(Var* var) { if (var->type == VarType::Name) destroy_string_slice(&var->name); } void destroy_expr_list(Expr* first) { Expr* expr = first; while (expr) { Expr* next = expr->next; delete expr; expr = next; } } Var::Var(int64_t index) : type(VarType::Index), index(index) { WABT_ZERO_MEMORY(loc); } Var::Var(const StringSlice& name) : type(VarType::Name), name(name) { WABT_ZERO_MEMORY(loc); } Const::Const(I32, uint32_t value) : type(Type::I32), u32(value) { WABT_ZERO_MEMORY(loc); } Const::Const(I64, uint64_t value) : type(Type::I64), u64(value) { WABT_ZERO_MEMORY(loc); } Const::Const(F32, uint32_t value) : type(Type::F32), f32_bits(value) { WABT_ZERO_MEMORY(loc); } Const::Const(F64, uint64_t value) : type(Type::F64), f64_bits(value) { WABT_ZERO_MEMORY(loc); } Block::Block(): first(nullptr) { WABT_ZERO_MEMORY(label); } Block::Block(Expr* first) : first(first) { WABT_ZERO_MEMORY(label); } Block::~Block() { destroy_string_slice(&label); destroy_expr_list(first); } Expr::Expr() : type(ExprType::Binary), next(nullptr) { WABT_ZERO_MEMORY(loc); binary.opcode = Opcode::Nop; } Expr::Expr(ExprType type) : type(type), next(nullptr) { WABT_ZERO_MEMORY(loc); } Expr::~Expr() { switch (type) { case ExprType::Block: delete block; break; case ExprType::Br: destroy_var(&br.var); break; case ExprType::BrIf: destroy_var(&br_if.var); break; case ExprType::BrTable: for (Var& var : *br_table.targets) destroy_var(&var); delete br_table.targets; destroy_var(&br_table.default_target); break; case ExprType::Call: destroy_var(&call.var); break; case ExprType::CallIndirect: destroy_var(&call_indirect.var); break; case ExprType::GetGlobal: destroy_var(&get_global.var); break; case ExprType::GetLocal: destroy_var(&get_local.var); break; case ExprType::If: delete if_.true_; destroy_expr_list(if_.false_); break; case ExprType::Loop: delete loop; break; case ExprType::SetGlobal: destroy_var(&set_global.var); break; case ExprType::SetLocal: destroy_var(&set_local.var); break; case ExprType::TeeLocal: destroy_var(&tee_local.var); break; case ExprType::Binary: case ExprType::Compare: case ExprType::Const: case ExprType::Convert: case ExprType::Drop: case ExprType::CurrentMemory: case ExprType::GrowMemory: case ExprType::Load: case ExprType::Nop: case ExprType::Return: case ExprType::Select: case ExprType::Store: case ExprType::Unary: case ExprType::Unreachable: break; } } // static Expr* Expr::CreateBinary(Opcode opcode) { Expr* expr = new Expr(ExprType::Binary); expr->binary.opcode = opcode; return expr; } // static Expr* Expr::CreateBlock(Block* block) { Expr* expr = new Expr(ExprType::Block); expr->block = block; return expr; } // static Expr* Expr::CreateBr(Var var) { Expr* expr = new Expr(ExprType::Br); expr->br.var = var; return expr; } // static Expr* Expr::CreateBrIf(Var var) { Expr* expr = new Expr(ExprType::BrIf); expr->br_if.var = var; return expr; } // static Expr* Expr::CreateBrTable(VarVector* targets, Var default_target) { Expr* expr = new Expr(ExprType::BrTable); expr->br_table.targets = targets; expr->br_table.default_target = default_target; return expr; } // static Expr* Expr::CreateCall(Var var) { Expr* expr = new Expr(ExprType::Call); expr->call.var = var; return expr; } // static Expr* Expr::CreateCallIndirect(Var var) { Expr* expr = new Expr(ExprType::CallIndirect); expr->call_indirect.var = var; return expr; } // static Expr* Expr::CreateCompare(Opcode opcode) { Expr* expr = new Expr(ExprType::Compare); expr->compare.opcode = opcode; return expr; } // static Expr* Expr::CreateConst(const Const& const_) { Expr* expr = new Expr(ExprType::Const); expr->const_ = const_; return expr; } // static Expr* Expr::CreateConvert(Opcode opcode) { Expr* expr = new Expr(ExprType::Convert); expr->convert.opcode = opcode; return expr; } // static Expr* Expr::CreateCurrentMemory() { return new Expr(ExprType::CurrentMemory); } // static Expr* Expr::CreateDrop() { return new Expr(ExprType::Drop); } // static Expr* Expr::CreateGetGlobal(Var var) { Expr* expr = new Expr(ExprType::GetGlobal); expr->get_global.var = var; return expr; } // static Expr* Expr::CreateGetLocal(Var var) { Expr* expr = new Expr(ExprType::GetLocal); expr->get_local.var = var; return expr; } // static Expr* Expr::CreateGrowMemory() { return new Expr(ExprType::GrowMemory); } // static Expr* Expr::CreateIf(Block* true_, Expr* false_) { Expr* expr = new Expr(ExprType::If); expr->if_.true_ = true_; expr->if_.false_ = false_; return expr; } // static Expr* Expr::CreateLoad(Opcode opcode, uint32_t align, uint64_t offset) { Expr* expr = new Expr(ExprType::Load); expr->load.opcode = opcode; expr->load.align = align; expr->load.offset = offset; return expr; } // static Expr* Expr::CreateLoop(Block* block) { Expr* expr = new Expr(ExprType::Loop); expr->loop = block; return expr; } // static Expr* Expr::CreateNop() { return new Expr(ExprType::Nop); } // static Expr* Expr::CreateReturn() { return new Expr(ExprType::Return); } // static Expr* Expr::CreateSelect() { return new Expr(ExprType::Select); } // static Expr* Expr::CreateSetGlobal(Var var) { Expr* expr = new Expr(ExprType::SetGlobal); expr->set_global.var = var; return expr; } // static Expr* Expr::CreateSetLocal(Var var) { Expr* expr = new Expr(ExprType::SetLocal); expr->set_local.var = var; return expr; } // static Expr* Expr::CreateStore(Opcode opcode, uint32_t align, uint64_t offset) { Expr* expr = new Expr(ExprType::Store); expr->store.opcode = opcode; expr->store.align = align; expr->store.offset = offset; return expr; } // static Expr* Expr::CreateTeeLocal(Var var) { Expr* expr = new Expr(ExprType::TeeLocal); expr->tee_local.var = var; return expr; } // static Expr* Expr::CreateUnary(Opcode opcode) { Expr* expr = new Expr(ExprType::Unary); expr->unary.opcode = opcode; return expr; } // static Expr* Expr::CreateUnreachable() { return new Expr(ExprType::Unreachable); } FuncType::FuncType() { WABT_ZERO_MEMORY(name); } FuncType::~FuncType() { destroy_string_slice(&name); } FuncDeclaration::FuncDeclaration() : has_func_type(false) { WABT_ZERO_MEMORY(type_var); } FuncDeclaration::~FuncDeclaration() { destroy_var(&type_var); } Func::Func() : first_expr(nullptr) { WABT_ZERO_MEMORY(name); } Func::~Func() { destroy_string_slice(&name); destroy_expr_list(first_expr); } Global::Global() : type(Type::Void), mutable_(false), init_expr(nullptr) { WABT_ZERO_MEMORY(name); } Global::~Global() { destroy_string_slice(&name); destroy_expr_list(init_expr); } Table::Table() { WABT_ZERO_MEMORY(name); WABT_ZERO_MEMORY(elem_limits); } Table::~Table() { destroy_string_slice(&name); } ElemSegment::ElemSegment() : offset(nullptr) { WABT_ZERO_MEMORY(table_var); } ElemSegment::~ElemSegment() { destroy_var(&table_var); destroy_expr_list(offset); for (Var& var : vars) destroy_var(&var); } DataSegment::DataSegment() : offset(nullptr), data(nullptr), size(0) { WABT_ZERO_MEMORY(memory_var); } DataSegment::~DataSegment() { destroy_var(&memory_var); destroy_expr_list(offset); delete [] data; } Memory::Memory() { WABT_ZERO_MEMORY(name); WABT_ZERO_MEMORY(page_limits); } Memory::~Memory() { destroy_string_slice(&name); } Import::Import() : kind(ExternalKind::Func), func(nullptr) { WABT_ZERO_MEMORY(module_name); WABT_ZERO_MEMORY(field_name); } Import::~Import() { destroy_string_slice(&module_name); destroy_string_slice(&field_name); switch (kind) { case ExternalKind::Func: delete func; break; case ExternalKind::Table: delete table; break; case ExternalKind::Memory: delete memory; break; case ExternalKind::Global: delete global; break; } } Export::Export() { WABT_ZERO_MEMORY(name); WABT_ZERO_MEMORY(var); } Export::~Export() { destroy_string_slice(&name); destroy_var(&var); } void destroy_memory(Memory* memory) { destroy_string_slice(&memory->name); } void destroy_table(Table* table) { destroy_string_slice(&table->name); } ModuleField::ModuleField() : type(ModuleFieldType::Start), next(nullptr) { WABT_ZERO_MEMORY(loc); WABT_ZERO_MEMORY(start); } ModuleField::~ModuleField() { switch (type) { case ModuleFieldType::Func: delete func; break; case ModuleFieldType::Global: delete global; break; case ModuleFieldType::Import: delete import; break; case ModuleFieldType::Export: delete export_; break; case ModuleFieldType::FuncType: delete func_type; break; case ModuleFieldType::Table: delete table; break; case ModuleFieldType::ElemSegment: delete elem_segment; break; case ModuleFieldType::Memory: delete memory; break; case ModuleFieldType::DataSegment: delete data_segment; break; case ModuleFieldType::Start: destroy_var(&start); break; } } Module::Module() : first_field(nullptr), last_field(nullptr), num_func_imports(0), num_table_imports(0), num_memory_imports(0), num_global_imports(0), start(0) { WABT_ZERO_MEMORY(loc); WABT_ZERO_MEMORY(name); } Module::~Module() { destroy_string_slice(&name); ModuleField* field = first_field; while (field) { ModuleField* next_field = field->next; delete field; field = next_field; } } RawModule::RawModule() : type(RawModuleType::Text), text(nullptr) {} RawModule::~RawModule() { if (type == RawModuleType::Text) { delete text; } else { destroy_string_slice(&binary.name); delete [] binary.data; } } ActionInvoke::ActionInvoke() {} Action::Action() : type(ActionType::Get) { WABT_ZERO_MEMORY(loc); WABT_ZERO_MEMORY(module_var); WABT_ZERO_MEMORY(name); } Action::~Action() { destroy_var(&module_var); destroy_string_slice(&name); switch (type) { case ActionType::Invoke: delete invoke; break; case ActionType::Get: break; } } Command::Command() : type(CommandType::Module), module(nullptr) {} Command::~Command() { switch (type) { case CommandType::Module: delete module; break; case CommandType::Action: delete action; break; case CommandType::Register: destroy_string_slice(®ister_.module_name); destroy_var(®ister_.var); break; case CommandType::AssertMalformed: delete assert_malformed.module; destroy_string_slice(&assert_malformed.text); break; case CommandType::AssertInvalid: case CommandType::AssertInvalidNonBinary: delete assert_invalid.module; destroy_string_slice(&assert_invalid.text); break; case CommandType::AssertUnlinkable: delete assert_unlinkable.module; destroy_string_slice(&assert_unlinkable.text); break; case CommandType::AssertUninstantiable: delete assert_uninstantiable.module; destroy_string_slice(&assert_uninstantiable.text); break; case CommandType::AssertReturn: delete assert_return.action; delete assert_return.expected; break; case CommandType::AssertReturnCanonicalNan: delete assert_return_arithmetic_nan.action; break; case CommandType::AssertReturnArithmeticNan: delete assert_return_canonical_nan.action; break; case CommandType::AssertTrap: case CommandType::AssertExhaustion: delete assert_trap.action; destroy_string_slice(&assert_trap.text); break; } } Script::Script() {} #define CHECK_RESULT(expr) \ do { \ if (WABT_FAILED((expr))) \ return Result::Error; \ } while (0) #define CALLBACK(member) \ CHECK_RESULT((visitor)->member \ ? (visitor)->member(expr, (visitor)->user_data) \ : Result::Ok) static Result visit_expr(Expr* expr, ExprVisitor* visitor); Result visit_expr_list(Expr* first, ExprVisitor* visitor) { for (Expr* expr = first; expr; expr = expr->next) CHECK_RESULT(visit_expr(expr, visitor)); return Result::Ok; } static Result visit_expr(Expr* expr, ExprVisitor* visitor) { switch (expr->type) { case ExprType::Binary: CALLBACK(on_binary_expr); break; case ExprType::Block: CALLBACK(begin_block_expr); CHECK_RESULT(visit_expr_list(expr->block->first, visitor)); CALLBACK(end_block_expr); break; case ExprType::Br: CALLBACK(on_br_expr); break; case ExprType::BrIf: CALLBACK(on_br_if_expr); break; case ExprType::BrTable: CALLBACK(on_br_table_expr); break; case ExprType::Call: CALLBACK(on_call_expr); break; case ExprType::CallIndirect: CALLBACK(on_call_indirect_expr); break; case ExprType::Compare: CALLBACK(on_compare_expr); break; case ExprType::Const: CALLBACK(on_const_expr); break; case ExprType::Convert: CALLBACK(on_convert_expr); break; case ExprType::CurrentMemory: CALLBACK(on_current_memory_expr); break; case ExprType::Drop: CALLBACK(on_drop_expr); break; case ExprType::GetGlobal: CALLBACK(on_get_global_expr); break; case ExprType::GetLocal: CALLBACK(on_get_local_expr); break; case ExprType::GrowMemory: CALLBACK(on_grow_memory_expr); break; case ExprType::If: CALLBACK(begin_if_expr); CHECK_RESULT(visit_expr_list(expr->if_.true_->first, visitor)); CALLBACK(after_if_true_expr); CHECK_RESULT(visit_expr_list(expr->if_.false_, visitor)); CALLBACK(end_if_expr); break; case ExprType::Load: CALLBACK(on_load_expr); break; case ExprType::Loop: CALLBACK(begin_loop_expr); CHECK_RESULT(visit_expr_list(expr->loop->first, visitor)); CALLBACK(end_loop_expr); break; case ExprType::Nop: CALLBACK(on_nop_expr); break; case ExprType::Return: CALLBACK(on_return_expr); break; case ExprType::Select: CALLBACK(on_select_expr); break; case ExprType::SetGlobal: CALLBACK(on_set_global_expr); break; case ExprType::SetLocal: CALLBACK(on_set_local_expr); break; case ExprType::Store: CALLBACK(on_store_expr); break; case ExprType::TeeLocal: CALLBACK(on_tee_local_expr); break; case ExprType::Unary: CALLBACK(on_unary_expr); break; case ExprType::Unreachable: CALLBACK(on_unreachable_expr); break; } return Result::Ok; } /* TODO(binji): make the visitor non-recursive */ Result visit_func(Func* func, ExprVisitor* visitor) { return visit_expr_list(func->first_expr, visitor); } } // namespace wabt