diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binary-reader-interpreter.cc | 148 | ||||
-rw-r--r-- | src/binary-reader-interpreter.h | 2 | ||||
-rw-r--r-- | src/interpreter.cc | 388 | ||||
-rw-r--r-- | src/interpreter.h | 263 | ||||
-rw-r--r-- | src/tools/wasm-interp.cc | 150 | ||||
-rw-r--r-- | src/writer.h | 2 |
6 files changed, 536 insertions, 417 deletions
diff --git a/src/binary-reader-interpreter.cc b/src/binary-reader-interpreter.cc index cbac7668..23f5d745 100644 --- a/src/binary-reader-interpreter.cc +++ b/src/binary-reader-interpreter.cc @@ -75,11 +75,12 @@ class BinaryReaderInterpreter : public BinaryReaderNop { public: BinaryReaderInterpreter(Environment* env, DefinedModule* module, - IstreamOffset istream_offset, + std::unique_ptr<OutputBuffer> istream, BinaryErrorHandler* error_handler); + wabt::Result ReadBinary(DefinedModule* out_module); + std::unique_ptr<OutputBuffer> ReleaseOutputBuffer(); - IstreamOffset get_istream_offset() { return istream_offset; } // Implement BinaryReader. bool OnError(const char* message) override; @@ -210,14 +211,11 @@ class BinaryReaderInterpreter : public BinaryReaderNop { static void OnTypecheckerError(const char* msg, void* user_data); Index TranslateSigIndexToEnv(Index sig_index); - FuncSignature* GetSignatureByEnvIndex(Index sig_index); FuncSignature* GetSignatureByModuleIndex(Index sig_index); Index TranslateFuncIndexToEnv(Index func_index); Index TranslateModuleFuncIndexToDefined(Index func_index); - Func* GetFuncByEnvIndex(Index func_index); Func* GetFuncByModuleIndex(Index func_index); Index TranslateGlobalIndexToEnv(Index global_index); - Global* GetGlobalByEnvIndex(Index global_index); Global* GetGlobalByModuleIndex(Index global_index); Type GetGlobalTypeByModuleIndex(Index global_index); Index TranslateLocalIndex(Index local_index); @@ -302,13 +300,13 @@ class BinaryReaderInterpreter : public BinaryReaderNop { BinaryReaderInterpreter::BinaryReaderInterpreter( Environment* env, DefinedModule* module, - IstreamOffset istream_offset, + std::unique_ptr<OutputBuffer> istream, BinaryErrorHandler* error_handler) : error_handler(error_handler), env(env), module(module), - istream_writer(std::move(env->istream)), - istream_offset(istream_offset) { + istream_writer(std::move(istream)), + istream_offset(istream_writer.output_buffer().size()) { tc_error_handler.on_error = OnTypecheckerError; tc_error_handler.user_data = this; typechecker.error_handler = &tc_error_handler; @@ -348,14 +346,9 @@ Index BinaryReaderInterpreter::TranslateSigIndexToEnv(Index sig_index) { return sig_index_mapping[sig_index]; } -FuncSignature* BinaryReaderInterpreter::GetSignatureByEnvIndex( - Index sig_index) { - return &env->sigs[sig_index]; -} - FuncSignature* BinaryReaderInterpreter::GetSignatureByModuleIndex( Index sig_index) { - return GetSignatureByEnvIndex(TranslateSigIndexToEnv(sig_index)); + return env->GetFuncSignature(TranslateSigIndexToEnv(sig_index)); } Index BinaryReaderInterpreter::TranslateFuncIndexToEnv(Index func_index) { @@ -369,24 +362,16 @@ Index BinaryReaderInterpreter::TranslateModuleFuncIndexToDefined( return func_index - num_func_imports; } -Func* BinaryReaderInterpreter::GetFuncByEnvIndex(Index func_index) { - return env->funcs[func_index].get(); -} - Func* BinaryReaderInterpreter::GetFuncByModuleIndex(Index func_index) { - return GetFuncByEnvIndex(TranslateFuncIndexToEnv(func_index)); + return env->GetFunc(TranslateFuncIndexToEnv(func_index)); } Index BinaryReaderInterpreter::TranslateGlobalIndexToEnv(Index global_index) { return global_index_mapping[global_index]; } -Global* BinaryReaderInterpreter::GetGlobalByEnvIndex(Index global_index) { - return &env->globals[global_index]; -} - Global* BinaryReaderInterpreter::GetGlobalByModuleIndex(Index global_index) { - return GetGlobalByEnvIndex(TranslateGlobalIndexToEnv(global_index)); + return env->GetGlobal(TranslateGlobalIndexToEnv(global_index)); } Type BinaryReaderInterpreter::GetGlobalTypeByModuleIndex(Index global_index) { @@ -556,10 +541,10 @@ bool BinaryReaderInterpreter::OnError(const char* message) { } wabt::Result BinaryReaderInterpreter::OnTypeCount(Index count) { + Index sig_count = env->GetFuncSignatureCount(); sig_index_mapping.resize(count); for (Index i = 0; i < count; ++i) - sig_index_mapping[i] = env->sigs.size() + i; - env->sigs.resize(env->sigs.size() + count); + sig_index_mapping[i] = sig_count + i; return wabt::Result::Ok; } @@ -568,11 +553,9 @@ wabt::Result BinaryReaderInterpreter::OnType(Index index, Type* param_types, Index result_count, Type* result_types) { - FuncSignature* sig = GetSignatureByModuleIndex(index); - sig->param_types.insert(sig->param_types.end(), param_types, - param_types + param_count); - sig->result_types.insert(sig->result_types.end(), result_types, - result_types + result_count); + assert(TranslateSigIndexToEnv(index) == env->GetFuncSignatureCount()); + env->EmplaceBackFuncSignature(param_count, param_types, result_count, + result_types); return wabt::Result::Ok; } @@ -587,15 +570,12 @@ wabt::Result BinaryReaderInterpreter::OnImport(Index index, Import* import = &module->imports[index]; import->module_name = dup_string_slice(module_name); import->field_name = dup_string_slice(field_name); - int module_index = - env->registered_module_bindings.find_index(import->module_name); - if (module_index < 0) { + Module* module = env->FindRegisteredModule(import->module_name); + if (!module) { PrintError("unknown import module \"" PRIstringslice "\"", WABT_PRINTF_STRING_SLICE_ARG(import->module_name)); return wabt::Result::Error; } - - Module* module = env->modules[module_index].get(); if (module->is_host) { /* We don't yet know the kind of a host import module, so just assume it * exists for now. We'll fail later (in on_import_* below) if it doesn't @@ -603,7 +583,7 @@ wabt::Result BinaryReaderInterpreter::OnImport(Index index, is_host_import = true; host_import_module = module->as_host(); } else { - Export* export_ = get_export_by_name(module, &import->field_name); + Export* export_ = module->GetExport(import->field_name); if (!export_) { PrintError("unknown module field \"" PRIstringslice "\"", WABT_PRINTF_STRING_SLICE_ARG(import->field_name)); @@ -718,23 +698,21 @@ wabt::Result BinaryReaderInterpreter::OnImportFunc(Index import_index, if (is_host_import) { HostFunc* func = new HostFunc(import->module_name, import->field_name, import->func.sig_index); - - env->funcs.emplace_back(func); + env->EmplaceBackFunc(func); HostImportDelegate* host_delegate = &host_import_module->import_delegate; - FuncSignature* sig = &env->sigs[func->sig_index]; + FuncSignature* sig = env->GetFuncSignature(func->sig_index); CHECK_RESULT(host_delegate->import_func( import, func, sig, MakePrintErrorCallback(), host_delegate->user_data)); assert(func->callback); - func_env_index = env->funcs.size() - 1; + func_env_index = env->GetFuncCount() - 1; AppendExport(host_import_module, ExternalKind::Func, func_env_index, import->field_name); } else { CHECK_RESULT(CheckImportKind(import, ExternalKind::Func)); - Func* func = env->funcs[import_env_index].get(); - if (!func_signatures_are_equal(env, import->func.sig_index, - func->sig_index)) { + Func* func = env->GetFunc(import_env_index); + if (!env->FuncSignaturesAreEqual(import->func.sig_index, func->sig_index)) { PrintError("import signature mismatch"); return wabt::Result::Error; } @@ -760,8 +738,7 @@ wabt::Result BinaryReaderInterpreter::OnImportTable(Index import_index, Import* import = &module->imports[import_index]; if (is_host_import) { - env->tables.emplace_back(*elem_limits); - Table* table = &env->tables.back(); + Table* table = env->EmplaceBackTable(*elem_limits); HostImportDelegate* host_delegate = &host_import_module->import_delegate; CHECK_RESULT(host_delegate->import_table( @@ -769,12 +746,12 @@ wabt::Result BinaryReaderInterpreter::OnImportTable(Index import_index, CHECK_RESULT(CheckImportLimits(elem_limits, &table->limits)); - module->table_index = env->tables.size() - 1; + module->table_index = env->GetTableCount() - 1; AppendExport(host_import_module, ExternalKind::Table, module->table_index, import->field_name); } else { CHECK_RESULT(CheckImportKind(import, ExternalKind::Table)); - Table* table = &env->tables[import_env_index]; + Table* table = env->GetTable(import_env_index); CHECK_RESULT(CheckImportLimits(elem_limits, &table->limits)); import->table.limits = *elem_limits; @@ -797,8 +774,7 @@ wabt::Result BinaryReaderInterpreter::OnImportMemory( Import* import = &module->imports[import_index]; if (is_host_import) { - env->memories.emplace_back(); - Memory* memory = &env->memories.back(); + Memory* memory = env->EmplaceBackMemory(); HostImportDelegate* host_delegate = &host_import_module->import_delegate; CHECK_RESULT(host_delegate->import_memory( @@ -806,12 +782,12 @@ wabt::Result BinaryReaderInterpreter::OnImportMemory( CHECK_RESULT(CheckImportLimits(page_limits, &memory->page_limits)); - module->memory_index = env->memories.size() - 1; + module->memory_index = env->GetMemoryCount() - 1; AppendExport(host_import_module, ExternalKind::Memory, module->memory_index, import->field_name); } else { CHECK_RESULT(CheckImportKind(import, ExternalKind::Memory)); - Memory* memory = &env->memories[import_env_index]; + Memory* memory = env->GetMemory(import_env_index); CHECK_RESULT(CheckImportLimits(page_limits, &memory->page_limits)); import->memory.limits = *page_limits; @@ -828,16 +804,15 @@ wabt::Result BinaryReaderInterpreter::OnImportGlobal(Index import_index, bool mutable_) { Import* import = &module->imports[import_index]; - Index global_env_index = env->globals.size() - 1; + Index global_env_index = env->GetGlobalCount() - 1; if (is_host_import) { - env->globals.emplace_back(TypedValue(type), mutable_); - Global* global = &env->globals.back(); + Global* global = env->EmplaceBackGlobal(TypedValue(type), mutable_); HostImportDelegate* host_delegate = &host_import_module->import_delegate; CHECK_RESULT(host_delegate->import_global( import, global, MakePrintErrorCallback(), host_delegate->user_data)); - global_env_index = env->globals.size() - 1; + global_env_index = env->GetGlobalCount() - 1; AppendExport(host_import_module, ExternalKind::Global, global_env_index, import->field_name); } else { @@ -854,15 +829,13 @@ wabt::Result BinaryReaderInterpreter::OnImportGlobal(Index import_index, wabt::Result BinaryReaderInterpreter::OnFunctionCount(Index count) { for (Index i = 0; i < count; ++i) - func_index_mapping.push_back(env->funcs.size() + i); - env->funcs.reserve(env->funcs.size() + count); + func_index_mapping.push_back(env->GetFuncCount() + i); func_fixups.resize(count); return wabt::Result::Ok; } wabt::Result BinaryReaderInterpreter::OnFunction(Index index, Index sig_index) { - DefinedFunc* func = new DefinedFunc(TranslateSigIndexToEnv(sig_index)); - env->funcs.emplace_back(func); + env->EmplaceBackFunc(new DefinedFunc(TranslateSigIndexToEnv(sig_index))); return wabt::Result::Ok; } @@ -873,8 +846,8 @@ wabt::Result BinaryReaderInterpreter::OnTable(Index index, PrintError("only one table allowed"); return wabt::Result::Error; } - env->tables.emplace_back(*elem_limits); - module->table_index = env->tables.size() - 1; + env->EmplaceBackTable(*elem_limits); + module->table_index = env->GetTableCount() - 1; return wabt::Result::Ok; } @@ -884,24 +857,22 @@ wabt::Result BinaryReaderInterpreter::OnMemory(Index index, PrintError("only one memory allowed"); return wabt::Result::Error; } - env->memories.emplace_back(*page_limits); - module->memory_index = env->memories.size() - 1; + env->EmplaceBackMemory(*page_limits); + module->memory_index = env->GetMemoryCount() - 1; return wabt::Result::Ok; } wabt::Result BinaryReaderInterpreter::OnGlobalCount(Index count) { for (Index i = 0; i < count; ++i) - global_index_mapping.push_back(env->globals.size() + i); - env->globals.resize(env->globals.size() + count); + global_index_mapping.push_back(env->GetGlobalCount() + i); return wabt::Result::Ok; } wabt::Result BinaryReaderInterpreter::BeginGlobal(Index index, Type type, bool mutable_) { - Global* global = GetGlobalByModuleIndex(index); - global->typed_value.type = type; - global->mutable_ = mutable_; + assert(TranslateGlobalIndexToEnv(index) == env->GetGlobalCount()); + env->EmplaceBackGlobal(TypedValue(type), mutable_); init_expr_value.type = Type::Void; return wabt::Result::Ok; } @@ -983,7 +954,7 @@ wabt::Result BinaryReaderInterpreter::OnExport(Index index, case ExternalKind::Global: { item_index = TranslateGlobalIndexToEnv(item_index); - Global* global = &env->globals[item_index]; + Global* global = env->GetGlobal(item_index); if (global->mutable_) { PrintError("mutable globals cannot be exported"); return wabt::Result::Error; @@ -996,8 +967,8 @@ wabt::Result BinaryReaderInterpreter::OnExport(Index index, wabt::Result BinaryReaderInterpreter::OnStartFunction(Index func_index) { Index start_func_index = TranslateFuncIndexToEnv(func_index); - Func* start_func = GetFuncByEnvIndex(start_func_index); - FuncSignature* sig = GetSignatureByEnvIndex(start_func->sig_index); + Func* start_func = env->GetFunc(start_func_index); + FuncSignature* sig = env->GetFuncSignature(start_func->sig_index); if (sig->param_types.size() != 0) { PrintError("start function must be nullary"); return wabt::Result::Error; @@ -1024,7 +995,7 @@ wabt::Result BinaryReaderInterpreter::OnElemSegmentFunctionIndex( Index index, Index func_index) { assert(module->table_index != kInvalidIndex); - Table* table = &env->tables[module->table_index]; + Table* table = env->GetTable(module->table_index); if (table_offset >= table->func_indexes.size()) { PrintError("elem segment offset is out of bounds: %u >= max value %" PRIzd, table_offset, table->func_indexes.size()); @@ -1047,7 +1018,7 @@ wabt::Result BinaryReaderInterpreter::OnDataSegmentData(Index index, const void* src_data, Address size) { assert(module->memory_index != kInvalidIndex); - Memory* memory = &env->memories[module->memory_index]; + Memory* memory = env->GetMemory(module->memory_index); if (init_expr_value.type != Type::I32) { PrintError("type mismatch in data segment, expected i32 but got %s", get_type_name(init_expr_value.type)); @@ -1086,7 +1057,7 @@ void BinaryReaderInterpreter::PopLabel() { wabt::Result BinaryReaderInterpreter::BeginFunctionBody(Index index) { DefinedFunc* func = GetFuncByModuleIndex(index)->as_defined(); - FuncSignature* sig = GetSignatureByEnvIndex(func->sig_index); + FuncSignature* sig = env->GetFuncSignature(func->sig_index); func->offset = GetIstreamOffset(); func->local_decl_count = 0; @@ -1276,7 +1247,7 @@ wabt::Result BinaryReaderInterpreter::OnBrTableExpr( wabt::Result BinaryReaderInterpreter::OnCallExpr(Index func_index) { Func* func = GetFuncByModuleIndex(func_index); - FuncSignature* sig = GetSignatureByEnvIndex(func->sig_index); + FuncSignature* sig = env->GetFuncSignature(func->sig_index); CHECK_RESULT( typechecker_on_call(&typechecker, &sig->param_types, &sig->result_types)); @@ -1491,23 +1462,26 @@ wabt::Result read_binary_interpreter(Environment* env, const ReadBinaryOptions* options, BinaryErrorHandler* error_handler, DefinedModule** out_module) { - IstreamOffset istream_offset = env->istream->data.size(); - DefinedModule* module = new DefinedModule(istream_offset); + // Need to mark before taking ownership of env->istream. + Environment::MarkPoint mark = env->Mark(); + + std::unique_ptr<OutputBuffer> istream = env->ReleaseIstream(); + IstreamOffset istream_offset = istream->size(); + DefinedModule* module = new DefinedModule(); - // Need to mark before constructing the reader since it takes ownership of - // env->istream, which makes env->istream == nullptr. - EnvironmentMark mark = mark_environment(env); - BinaryReaderInterpreter reader(env, module, istream_offset, error_handler); - env->modules.emplace_back(module); + BinaryReaderInterpreter reader(env, module, std::move(istream), + error_handler); + env->EmplaceBackModule(module); wabt::Result result = read_binary(data, size, &reader, options); - env->istream = reader.ReleaseOutputBuffer(); + env->SetIstream(reader.ReleaseOutputBuffer()); + if (WABT_SUCCEEDED(result)) { - env->istream->data.resize(reader.get_istream_offset()); - module->istream_end = env->istream->data.size(); + module->istream_start = istream_offset; + module->istream_end = env->istream().size(); *out_module = module; } else { - reset_environment_to_mark(env, mark); + env->ResetToMarkPoint(mark); *out_module = nullptr; } return result; diff --git a/src/binary-reader-interpreter.h b/src/binary-reader-interpreter.h index a075e631..1c70d3bf 100644 --- a/src/binary-reader-interpreter.h +++ b/src/binary-reader-interpreter.h @@ -24,7 +24,7 @@ namespace wabt { namespace interpreter { struct DefinedModule; -struct Environment; +class Environment; } // namespace interpreter diff --git a/src/interpreter.cc b/src/interpreter.cc index f116eb25..11921f7a 100644 --- a/src/interpreter.cc +++ b/src/interpreter.cc @@ -45,15 +45,50 @@ static const char* get_opcode_name(Opcode opcode) { return s_opcode_name[static_cast<int>(opcode)]; } -Environment::Environment() : istream(new OutputBuffer()) {} +Environment::Environment() : istream_(new OutputBuffer()) {} -Thread::Thread() - : env(nullptr), - value_stack_top(nullptr), - value_stack_end(nullptr), - call_stack_top(nullptr), - call_stack_end(nullptr), - pc(0) {} +Index Environment::FindModuleIndex(StringSlice name) const { + auto iter = module_bindings_.find(string_slice_to_string(name)); + if (iter == module_bindings_.end()) + return kInvalidIndex; + return iter->second.index; +} + +Module* Environment::FindModule(StringSlice name) { + Index index = FindModuleIndex(name); + return index == kInvalidIndex ? nullptr : modules_[index].get(); +} + +Module* Environment::FindRegisteredModule(StringSlice name) { + auto iter = registered_module_bindings_.find(string_slice_to_string(name)); + if (iter == registered_module_bindings_.end()) + return nullptr; + return modules_[iter->second.index].get(); +} + +Thread::Options::Options(uint32_t value_stack_size, + uint32_t call_stack_size, + IstreamOffset pc) + : value_stack_size(value_stack_size), + call_stack_size(call_stack_size), + pc(pc) {} + +Thread::Thread(Environment* env, const Options& options) + : env_(env), + value_stack_(options.value_stack_size), + call_stack_(options.call_stack_size), + value_stack_top_(value_stack_.data()), + value_stack_end_(value_stack_.data() + value_stack_.size()), + call_stack_top_(call_stack_.data()), + call_stack_end_(call_stack_.data() + call_stack_.size()), + pc_(options.pc) {} + +FuncSignature::FuncSignature(Index param_count, + Type* param_types, + Index result_count, + Type* result_types) + : param_types(param_types, param_types + param_count), + result_types(result_types, result_types + result_count) {} Import::Import() : kind(ExternalKind::Func) { WABT_ZERO_MEMORY(module_name); @@ -128,91 +163,103 @@ Module::~Module() { destroy_string_slice(&name); } -DefinedModule::DefinedModule(size_t istream_start) +Export* Module::GetExport(StringSlice name) { + int field_index = export_bindings.find_index(name); + if (field_index < 0) + return nullptr; + return &exports[field_index]; +} + +DefinedModule::DefinedModule() : Module(false), start_func_index(kInvalidIndex), - istream_start(istream_start), - istream_end(istream_start) {} + istream_start(kInvalidIstreamOffset), + istream_end(kInvalidIstreamOffset) {} HostModule::HostModule(const StringSlice& name) : Module(name, true) {} -EnvironmentMark mark_environment(Environment* env) { - EnvironmentMark mark; - WABT_ZERO_MEMORY(mark); - mark.modules_size = env->modules.size(); - mark.sigs_size = env->sigs.size(); - mark.funcs_size = env->funcs.size(); - mark.memories_size = env->memories.size(); - mark.tables_size = env->tables.size(); - mark.globals_size = env->globals.size(); - mark.istream_size = env->istream->data.size(); +Environment::MarkPoint Environment::Mark() { + MarkPoint mark; + mark.modules_size = modules_.size(); + mark.sigs_size = sigs_.size(); + mark.funcs_size = funcs_.size(); + mark.memories_size = memories_.size(); + mark.tables_size = tables_.size(); + mark.globals_size = globals_.size(); + mark.istream_size = istream_->data.size(); return mark; } -void reset_environment_to_mark(Environment* env, EnvironmentMark mark) { - /* Destroy entries in the binding hash. */ - for (size_t i = mark.modules_size; i < env->modules.size(); ++i) { - const StringSlice* name = &env->modules[i]->name; +void Environment::ResetToMarkPoint(const MarkPoint& mark) { + // Destroy entries in the binding hash. + for (size_t i = mark.modules_size; i < modules_.size(); ++i) { + const StringSlice* name = &modules_[i]->name; if (!string_slice_is_empty(name)) - env->module_bindings.erase(string_slice_to_string(*name)); + module_bindings_.erase(string_slice_to_string(*name)); } - /* registered_module_bindings maps from an arbitrary name to a module index, - * so we have to iterate through the entire table to find entries to remove. - */ - auto iter = env->registered_module_bindings.begin(); - while (iter != env->registered_module_bindings.end()) { + // registered_module_bindings_ maps from an arbitrary name to a module index, + // so we have to iterate through the entire table to find entries to remove. + auto iter = registered_module_bindings_.begin(); + while (iter != registered_module_bindings_.end()) { if (iter->second.index >= static_cast<int>(mark.modules_size)) - iter = env->registered_module_bindings.erase(iter); + iter = registered_module_bindings_.erase(iter); else ++iter; } - env->modules.erase(env->modules.begin() + mark.modules_size, - env->modules.end()); - env->sigs.erase(env->sigs.begin() + mark.sigs_size, env->sigs.end()); - env->funcs.erase(env->funcs.begin() + mark.funcs_size, env->funcs.end()); - env->memories.erase(env->memories.begin() + mark.memories_size, - env->memories.end()); - env->tables.erase(env->tables.begin() + mark.tables_size, env->tables.end()); - env->globals.erase(env->globals.begin() + mark.globals_size, - env->globals.end()); - env->istream->data.resize(mark.istream_size); + modules_.erase(modules_.begin() + mark.modules_size, modules_.end()); + sigs_.erase(sigs_.begin() + mark.sigs_size, sigs_.end()); + funcs_.erase(funcs_.begin() + mark.funcs_size, funcs_.end()); + memories_.erase(memories_.begin() + mark.memories_size, memories_.end()); + tables_.erase(tables_.begin() + mark.tables_size, tables_.end()); + globals_.erase(globals_.begin() + mark.globals_size, globals_.end()); + istream_->data.resize(mark.istream_size); } -HostModule* append_host_module(Environment* env, StringSlice name) { +HostModule* Environment::AppendHostModule(StringSlice name) { HostModule* module = new HostModule(dup_string_slice(name)); - env->modules.emplace_back(module); - env->registered_module_bindings.emplace(string_slice_to_string(name), - Binding(env->modules.size() - 1)); + modules_.emplace_back(module); + registered_module_bindings_.emplace(string_slice_to_string(name), + Binding(modules_.size() - 1)); return module; } -void init_thread(Environment* env, Thread* thread, ThreadOptions* options) { - thread->value_stack.resize(options->value_stack_size); - thread->call_stack.resize(options->call_stack_size); - thread->env = env; - thread->value_stack_top = thread->value_stack.data(); - thread->value_stack_end = - thread->value_stack.data() + thread->value_stack.size(); - thread->call_stack_top = thread->call_stack.data(); - thread->call_stack_end = - thread->call_stack.data() + thread->call_stack.size(); - thread->pc = options->pc; -} - -Result push_thread_value(Thread* thread, Value value) { - if (thread->value_stack_top >= thread->value_stack_end) +Result Thread::PushValue(Value value) { + if (value_stack_top_ >= value_stack_end_) return Result::TrapValueStackExhausted; - *thread->value_stack_top++ = value; + *value_stack_top_++ = value; return Result::Ok; } -Export* get_export_by_name(Module* module, const StringSlice* name) { - int field_index = module->export_bindings.find_index(*name); - if (field_index < 0) - return nullptr; - return &module->exports[field_index]; +Result Thread::PushArgs(const FuncSignature* sig, + const std::vector<TypedValue>& args) { + if (sig->param_types.size() != args.size()) + return interpreter::Result::ArgumentTypeMismatch; + + for (size_t i = 0; i < sig->param_types.size(); ++i) { + if (sig->param_types[i] != args[i].type) + return interpreter::Result::ArgumentTypeMismatch; + + interpreter::Result iresult = PushValue(args[i].value); + if (iresult != interpreter::Result::Ok) { + value_stack_top_ = value_stack_.data(); + return iresult; + } + } + return interpreter::Result::Ok; +} + +void Thread::CopyResults(const FuncSignature* sig, + std::vector<TypedValue>* out_results) { + size_t expected_results = sig->result_types.size(); + size_t value_stack_depth = value_stack_top_ - value_stack_.data(); + WABT_USE(value_stack_depth); + assert(expected_results == value_stack_depth); + + out_results->clear(); + for (size_t i = 0; i < expected_results; ++i) + out_results->emplace_back(sig->result_types[i], value_stack_[i]); } /* 3 32222222 222...00 @@ -470,9 +517,8 @@ DEFINE_BITCAST(bitcast_u64_to_f64, uint64_t, double) TRAP(type); \ } while (0) -#define CHECK_STACK() \ - TRAP_IF(thread->value_stack_top >= thread->value_stack_end, \ - ValueStackExhausted) +#define CHECK_STACK() \ + TRAP_IF(value_stack_top_ >= value_stack_end_, ValueStackExhausted) #define PUSH_NEG_1_AND_BREAK_IF(cond) \ if (WABT_UNLIKELY(cond)) { \ @@ -480,17 +526,17 @@ DEFINE_BITCAST(bitcast_u64_to_f64, uint64_t, double) break; \ } -#define PUSH(v) \ - do { \ - CHECK_STACK(); \ - (*thread->value_stack_top++) = (v); \ +#define PUSH(v) \ + do { \ + CHECK_STACK(); \ + (*value_stack_top_++) = (v); \ } while (0) -#define PUSH_TYPE(type, v) \ - do { \ - CHECK_STACK(); \ - (*thread->value_stack_top++).TYPE_FIELD_NAME_##type = \ - static_cast<VALUE_TYPE_##type>(v); \ +#define PUSH_TYPE(type, v) \ + do { \ + CHECK_STACK(); \ + (*value_stack_top_++).TYPE_FIELD_NAME_##type = \ + static_cast<VALUE_TYPE_##type>(v); \ } while (0) #define PUSH_I32(v) PUSH_TYPE(I32, (v)) @@ -498,35 +544,34 @@ DEFINE_BITCAST(bitcast_u64_to_f64, uint64_t, double) #define PUSH_F32(v) PUSH_TYPE(F32, (v)) #define PUSH_F64(v) PUSH_TYPE(F64, (v)) -#define PICK(depth) (*(thread->value_stack_top - (depth))) +#define PICK(depth) (*(value_stack_top_ - (depth))) #define TOP() (PICK(1)) -#define POP() (*--thread->value_stack_top) +#define POP() (*--value_stack_top_) #define POP_I32() (POP().i32) #define POP_I64() (POP().i64) #define POP_F32() (POP().f32_bits) #define POP_F64() (POP().f64_bits) -#define DROP_KEEP(drop, keep) \ - do { \ - assert((keep) <= 1); \ - if ((keep) == 1) \ - PICK((drop) + 1) = TOP(); \ - thread->value_stack_top -= (drop); \ +#define DROP_KEEP(drop, keep) \ + do { \ + assert((keep) <= 1); \ + if ((keep) == 1) \ + PICK((drop) + 1) = TOP(); \ + value_stack_top_ -= (drop); \ } while (0) #define GOTO(offset) pc = &istream[offset] -#define PUSH_CALL() \ - do { \ - TRAP_IF(thread->call_stack_top >= thread->call_stack_end, \ - CallStackExhausted); \ - (*thread->call_stack_top++) = (pc - istream); \ +#define PUSH_CALL() \ + do { \ + TRAP_IF(call_stack_top_ >= call_stack_end_, CallStackExhausted); \ + (*call_stack_top_++) = (pc - istream); \ } while (0) -#define POP_CALL() (*--thread->call_stack_top) +#define POP_CALL() (*--call_stack_top_) #define GET_MEMORY(var) \ Index memory_index = read_u32(&pc); \ - Memory* var = &env->memories[memory_index] + Memory* var = &env_->memories_[memory_index] #define LOAD(type, mem_type) \ do { \ @@ -738,19 +783,90 @@ static WABT_INLINE void read_table_entry_at(const uint8_t* pc, *out_keep = *(pc + WABT_TABLE_ENTRY_KEEP_OFFSET); } -bool func_signatures_are_equal(Environment* env, - Index sig_index_0, - Index sig_index_1) { +bool Environment::FuncSignaturesAreEqual(Index sig_index_0, + Index sig_index_1) const { if (sig_index_0 == sig_index_1) return true; - FuncSignature* sig_0 = &env->sigs[sig_index_0]; - FuncSignature* sig_1 = &env->sigs[sig_index_1]; + const FuncSignature* sig_0 = &sigs_[sig_index_0]; + const FuncSignature* sig_1 = &sigs_[sig_index_1]; return sig_0->param_types == sig_1->param_types && sig_0->result_types == sig_1->result_types; } -Result call_host(Thread* thread, HostFunc* func) { - FuncSignature* sig = &thread->env->sigs[func->sig_index]; +Result Thread::RunFunction(Index func_index, + const std::vector<TypedValue>& args, + std::vector<TypedValue>* out_results) { + Func* func = env_->GetFunc(func_index); + FuncSignature* sig = env_->GetFuncSignature(func->sig_index); + + Result result = PushArgs(sig, args); + if (result == Result::Ok) { + result = func->is_host ? CallHost(func->as_host()) + : RunDefinedFunction(func->as_defined()->offset); + if (result == Result::Ok) + CopyResults(sig, out_results); + } + + // Always reset the value and call stacks. + value_stack_top_ = value_stack_.data(); + call_stack_top_ = call_stack_.data(); + return result; +} + +Result Thread::TraceFunction(Index func_index, + Stream* stream, + const std::vector<TypedValue>& args, + std::vector<TypedValue>* out_results) { + Func* func = env_->GetFunc(func_index); + FuncSignature* sig = env_->GetFuncSignature(func->sig_index); + + Result result = PushArgs(sig, args); + if (result == Result::Ok) { + result = func->is_host + ? CallHost(func->as_host()) + : TraceDefinedFunction(func->as_defined()->offset, stream); + if (result == Result::Ok) + CopyResults(sig, out_results); + } + + // Always reset the value and call stacks. + value_stack_top_ = value_stack_.data(); + call_stack_top_ = call_stack_.data(); + return result; +} + +Result Thread::RunDefinedFunction(IstreamOffset function_offset) { + const int kNumInstructions = 1000; + Result result = Result::Ok; + pc_ = function_offset; + IstreamOffset* call_stack_return_top = call_stack_top_; + while (result == Result::Ok) { + result = Run(kNumInstructions, call_stack_return_top); + } + if (result != Result::Returned) + return result; + // Use OK instead of RETURNED for consistency. + return Result::Ok; +} + +Result Thread::TraceDefinedFunction(IstreamOffset function_offset, + Stream* stream) { + const int kNumInstructions = 1; + Result result = Result::Ok; + pc_ = function_offset; + IstreamOffset* call_stack_return_top = call_stack_top_; + while (result == Result::Ok) { + Trace(stream); + result = Run(kNumInstructions, call_stack_return_top); + } + if (result != Result::Returned) + return result; + // Use OK instead of RETURNED for consistency. + return Result::Ok; +} + +Result Thread::CallHost(HostFunc* func) { + FuncSignature* sig = &env_->sigs_[func->sig_index]; size_t num_params = sig->param_types.size(); size_t num_results = sig->result_types.size(); @@ -777,16 +893,12 @@ Result call_host(Thread* thread, HostFunc* func) { return Result::Ok; } -Result run_interpreter(Thread* thread, - int num_instructions, - IstreamOffset* call_stack_return_top) { +Result Thread::Run(int num_instructions, IstreamOffset* call_stack_return_top) { Result result = Result::Ok; - assert(call_stack_return_top < thread->call_stack_end); - - Environment* env = thread->env; + assert(call_stack_return_top < call_stack_end_); - const uint8_t* istream = env->istream->data.data(); - const uint8_t* pc = &istream[thread->pc]; + const uint8_t* istream = env_->istream_->data.data(); + const uint8_t* pc = &istream[pc_]; for (int i = 0; i < num_instructions; ++i) { Opcode opcode = static_cast<Opcode>(*pc++); switch (opcode) { @@ -826,7 +938,7 @@ Result run_interpreter(Thread* thread, } case Opcode::Return: - if (thread->call_stack_top == call_stack_return_top) { + if (call_stack_top_ == call_stack_return_top) { result = Result::Returned; goto exit_loop; } @@ -855,15 +967,15 @@ Result run_interpreter(Thread* thread, case Opcode::GetGlobal: { Index index = read_u32(&pc); - assert(index < env->globals.size()); - PUSH(env->globals[index].typed_value.value); + assert(index < env_->globals_.size()); + PUSH(env_->globals_[index].typed_value.value); break; } case Opcode::SetGlobal: { Index index = read_u32(&pc); - assert(index < env->globals.size()); - env->globals[index].typed_value.value = POP(); + assert(index < env_->globals_.size()); + env_->globals_[index].typed_value.value = POP(); break; } @@ -892,17 +1004,17 @@ Result run_interpreter(Thread* thread, case Opcode::CallIndirect: { Index table_index = read_u32(&pc); - Table* table = &env->tables[table_index]; + Table* table = &env_->tables_[table_index]; Index sig_index = read_u32(&pc); VALUE_TYPE_I32 entry_index = POP_I32(); TRAP_IF(entry_index >= table->func_indexes.size(), UndefinedTableIndex); Index func_index = table->func_indexes[entry_index]; TRAP_IF(func_index == kInvalidIndex, UninitializedTableElement); - Func* func = env->funcs[func_index].get(); - TRAP_UNLESS(func_signatures_are_equal(env, func->sig_index, sig_index), + Func* func = env_->funcs_[func_index].get(); + TRAP_UNLESS(env_->FuncSignaturesAreEqual(func->sig_index, sig_index), IndirectCallSignatureMismatch); if (func->is_host) { - call_host(thread, func->as_host()); + CallHost(func->as_host()); } else { PUSH_CALL(); GOTO(func->as_defined()->offset); @@ -912,7 +1024,7 @@ Result run_interpreter(Thread* thread, case Opcode::CallHost: { Index func_index = read_u32(&pc); - call_host(thread, env->funcs[func_index]->as_host()); + CallHost(env_->funcs_[func_index]->as_host()); break; } @@ -1630,11 +1742,11 @@ Result run_interpreter(Thread* thread, } case Opcode::Alloca: { - Value* old_value_stack_top = thread->value_stack_top; - thread->value_stack_top += read_u32(&pc); + Value* old_value_stack_top = value_stack_top_; + value_stack_top_ += read_u32(&pc); CHECK_STACK(); memset(old_value_stack_top, 0, - (thread->value_stack_top - old_value_stack_top) * sizeof(Value)); + (value_stack_top_ - old_value_stack_top) * sizeof(Value)); break; } @@ -1671,19 +1783,18 @@ Result run_interpreter(Thread* thread, } exit_loop: - thread->pc = pc - istream; + pc_ = pc - istream; return result; } -void trace_pc(Thread* thread, Stream* stream) { - const uint8_t* istream = thread->env->istream->data.data(); - const uint8_t* pc = &istream[thread->pc]; - size_t value_stack_depth = - thread->value_stack_top - thread->value_stack.data(); - size_t call_stack_depth = thread->call_stack_top - thread->call_stack.data(); +void Thread::Trace(Stream* stream) { + const uint8_t* istream = env_->istream_->data.data(); + const uint8_t* pc = &istream[pc_]; + size_t value_stack_depth = value_stack_top_ - value_stack_.data(); + size_t call_stack_depth = call_stack_top_ - call_stack_.data(); stream->Writef("#%" PRIzd ". %4" PRIzd ": V:%-3" PRIzd "| ", call_stack_depth, - pc - thread->env->istream->data.data(), value_stack_depth); + pc - env_->istream_->data.data(), value_stack_depth); Opcode opcode = static_cast<Opcode>(*pc++); switch (opcode) { @@ -2026,16 +2137,15 @@ void trace_pc(Thread* thread, Stream* stream) { } } -void disassemble(Environment* env, - Stream* stream, - IstreamOffset from, - IstreamOffset to) { +void Environment::Disassemble(Stream* stream, + IstreamOffset from, + IstreamOffset to) { /* TODO(binji): mark function entries */ /* TODO(binji): track value stack size */ - if (from >= env->istream->data.size()) + if (from >= istream_->data.size()) return; - to = std::min<IstreamOffset>(to, env->istream->data.size()); - const uint8_t* istream = env->istream->data.data(); + to = std::min<IstreamOffset>(to, istream_->data.size()); + const uint8_t* istream = istream_->data.data(); const uint8_t* pc = &istream[from]; while (static_cast<IstreamOffset>(pc - istream) < to) { @@ -2344,9 +2454,9 @@ void disassemble(Environment* env, } } -void disassemble_module(Environment* env, Stream* stream, Module* module) { +void Environment::DisassembleModule(Stream* stream, Module* module) { assert(!module->is_host); - disassemble(env, stream, module->as_defined()->istream_start, + Disassemble(stream, module->as_defined()->istream_start, module->as_defined()->istream_end); } diff --git a/src/interpreter.h b/src/interpreter.h index d37473d5..3f60bdbb 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -22,8 +22,8 @@ #include <memory> #include <vector> -#include "common.h" #include "binding-hash.h" +#include "common.h" #include "opcode.h" #include "writer.h" @@ -105,6 +105,12 @@ enum class Opcode { static const int kOpcodeCount = WABT_ENUM_COUNT(Opcode); struct FuncSignature { + FuncSignature() = default; + FuncSignature(Index param_count, + Type* param_types, + Index result_count, + Type* result_types); + std::vector<Type> param_types; std::vector<Type> result_types; }; @@ -255,10 +261,10 @@ struct PrintErrorCallback { struct HostImportDelegate { void* user_data; ::wabt::Result (*import_func)(Import*, - Func*, - FuncSignature*, - PrintErrorCallback, - void* user_data); + Func*, + FuncSignature*, + PrintErrorCallback, + void* user_data); ::wabt::Result (*import_table)(Import*, Table*, PrintErrorCallback, @@ -282,6 +288,8 @@ struct Module { inline struct DefinedModule* as_defined(); inline struct HostModule* as_host(); + Export* GetExport(StringSlice name); + StringSlice name; std::vector<Export> exports; BindingHash export_bindings; @@ -291,12 +299,12 @@ struct Module { }; struct DefinedModule : Module { - explicit DefinedModule(size_t istream_start); + DefinedModule(); std::vector<Import> imports; Index start_func_index; /* kInvalidIndex if not defined */ - size_t istream_start; - size_t istream_end; + IstreamOffset istream_start; + IstreamOffset istream_end; }; struct HostModule : Module { @@ -315,85 +323,192 @@ HostModule* Module::as_host() { return static_cast<HostModule*>(this); } -/* Used to track and reset the state of the environment. */ -struct EnvironmentMark { - size_t modules_size; - size_t sigs_size; - size_t funcs_size; - size_t memories_size; - size_t tables_size; - size_t globals_size; - size_t istream_size; -}; +class Environment { + public: + // Used to track and reset the state of the environment. + struct MarkPoint { + size_t modules_size = 0; + size_t sigs_size = 0; + size_t funcs_size = 0; + size_t memories_size = 0; + size_t tables_size = 0; + size_t globals_size = 0; + size_t istream_size = 0; + }; -struct Environment { Environment(); - std::vector<std::unique_ptr<Module>> modules; - std::vector<FuncSignature> sigs; - std::vector<std::unique_ptr<Func>> funcs; - std::vector<Memory> memories; - std::vector<Table> tables; - std::vector<Global> globals; - std::unique_ptr<OutputBuffer> istream; - BindingHash module_bindings; - BindingHash registered_module_bindings; -}; + OutputBuffer& istream() { return *istream_; } + void SetIstream(std::unique_ptr<OutputBuffer> istream) { + istream_ = std::move(istream); + } + std::unique_ptr<OutputBuffer> ReleaseIstream() { return std::move(istream_); } -struct Thread { - Thread(); - - Environment* env; - std::vector<Value> value_stack; - std::vector<IstreamOffset> call_stack; - Value* value_stack_top; - Value* value_stack_end; - IstreamOffset* call_stack_top; - IstreamOffset* call_stack_end; - IstreamOffset pc; -}; + Index GetFuncSignatureCount() const { return sigs_.size(); } + Index GetFuncCount() const { return funcs_.size(); } + Index GetGlobalCount() const { return globals_.size(); } + Index GetMemoryCount() const { return memories_.size(); } + Index GetTableCount() const { return tables_.size(); } + Index GetModuleCount() const { return modules_.size(); } + + Index GetLastModuleIndex() const { + return modules_.empty() ? kInvalidIndex : modules_.size() - 1; + } + Index FindModuleIndex(StringSlice name) const; + + FuncSignature* GetFuncSignature(Index index) { return &sigs_[index]; } + Func* GetFunc(Index index) { + assert(index < funcs_.size()); + return funcs_[index].get(); + } + Global* GetGlobal(Index index) { + assert(index < globals_.size()); + return &globals_[index]; + } + Memory* GetMemory(Index index) { + assert(index < memories_.size()); + return &memories_[index]; + } + Table* GetTable(Index index) { + assert(index < tables_.size()); + return &tables_[index]; + } + Module* GetModule(Index index) { + assert(index < modules_.size()); + return modules_[index].get(); + } + + Module* GetLastModule() { + return modules_.empty() ? nullptr : modules_.back().get(); + } + Module* FindModule(StringSlice name); + Module* FindRegisteredModule(StringSlice name); + + template <typename... Args> + FuncSignature* EmplaceBackFuncSignature(Args&&... args) { + sigs_.emplace_back(args...); + return &sigs_.back(); + } + + template <typename... Args> + Func* EmplaceBackFunc(Args&&... args) { + funcs_.emplace_back(args...); + return funcs_.back().get(); + } + + template <typename... Args> + Global* EmplaceBackGlobal(Args&&... args) { + globals_.emplace_back(args...); + return &globals_.back(); + } + + template <typename... Args> + Table* EmplaceBackTable(Args&&... args) { + tables_.emplace_back(args...); + return &tables_.back(); + } + + template <typename... Args> + Memory* EmplaceBackMemory(Args&&... args) { + memories_.emplace_back(args...); + return &memories_.back(); + } + + template <typename... Args> + Module* EmplaceBackModule(Args&&... args) { + modules_.emplace_back(args...); + return modules_.back().get(); + } + + template <typename... Args> + void EmplaceModuleBinding(Args&&... args) { + module_bindings_.emplace(args...); + } -// TODO(binji): Remove and use default constructor. -#define WABT_INTERPRETER_THREAD_OPTIONS_DEFAULT \ - { \ - 512 * 1024 / sizeof(::wabt::interpreter::Value), 64 * 1024, \ - ::wabt::interpreter::kInvalidIstreamOffset \ + template <typename... Args> + void EmplaceRegisteredModuleBinding(Args&&... args) { + registered_module_bindings_.emplace(args...); } -struct ThreadOptions { - uint32_t value_stack_size; - uint32_t call_stack_size; - IstreamOffset pc; + HostModule* AppendHostModule(StringSlice name); + + bool FuncSignaturesAreEqual(Index sig_index_0, Index sig_index_1) const; + + MarkPoint Mark(); + void ResetToMarkPoint(const MarkPoint&); + + void Disassemble(Stream* stream, IstreamOffset from, IstreamOffset to); + void DisassembleModule(Stream* stream, Module*); + + private: + friend class Thread; + + std::vector<std::unique_ptr<Module>> modules_; + std::vector<FuncSignature> sigs_; + std::vector<std::unique_ptr<Func>> funcs_; + std::vector<Memory> memories_; + std::vector<Table> tables_; + std::vector<Global> globals_; + std::unique_ptr<OutputBuffer> istream_; + BindingHash module_bindings_; + BindingHash registered_module_bindings_; +}; + +class Thread { + public: + struct Options { + static const uint32_t kDefaultValueStackSize = 512 * 1024 / sizeof(Value); + static const uint32_t kDefaultCallStackSize = 64 * 1024; + + explicit Options(uint32_t value_stack_size = kDefaultValueStackSize, + uint32_t call_stack_size = kDefaultCallStackSize, + IstreamOffset pc = kInvalidIstreamOffset); + + uint32_t value_stack_size; + uint32_t call_stack_size; + IstreamOffset pc; + }; + + explicit Thread(Environment*, const Options& = Options()); + + Environment* env() { return env_; } + + Result RunFunction(Index func_index, + const std::vector<TypedValue>& args, + std::vector<TypedValue>* out_results); + + Result TraceFunction(Index func_index, + Stream*, + const std::vector<TypedValue>& args, + std::vector<TypedValue>* out_results); + + private: + Result PushValue(Value); + Result PushArgs(const FuncSignature*, const std::vector<TypedValue>& args); + void CopyResults(const FuncSignature*, std::vector<TypedValue>* out_results); + + Result Run(int num_instructions, IstreamOffset* call_stack_return_top); + void Trace(Stream*); + + Result RunDefinedFunction(IstreamOffset); + Result TraceDefinedFunction(IstreamOffset, Stream*); + + Result CallHost(HostFunc*); + + Environment* env_; + std::vector<Value> value_stack_; + std::vector<IstreamOffset> call_stack_; + Value* value_stack_top_; + Value* value_stack_end_; + IstreamOffset* call_stack_top_; + IstreamOffset* call_stack_end_; + IstreamOffset pc_; }; bool is_canonical_nan_f32(uint32_t f32_bits); bool is_canonical_nan_f64(uint64_t f64_bits); bool is_arithmetic_nan_f32(uint32_t f32_bits); bool is_arithmetic_nan_f64(uint64_t f64_bits); -bool func_signatures_are_equal(Environment* env, - Index sig_index_0, - Index sig_index_1); - -// TODO(binji): Use methods on Environment and Thread instead. -void destroy_environment(Environment* env); -EnvironmentMark mark_environment(Environment* env); -void reset_environment_to_mark(Environment* env, EnvironmentMark mark); -HostModule* append_host_module(Environment* env, StringSlice name); -void init_thread(Environment* env, Thread* thread, ThreadOptions* options); -Result push_thread_value(Thread* thread, Value value); -void destroy_thread(Thread* thread); -Result call_host(Thread* thread, HostFunc* func); -Result run_interpreter(Thread* thread, - int num_instructions, - IstreamOffset* call_stack_return_top); -void trace_pc(Thread* thread, Stream* stream); -void disassemble(Environment* env, - Stream* stream, - IstreamOffset from, - IstreamOffset to); -void disassemble_module(Environment* env, Stream* stream, Module* module); - -Export* get_export_by_name(Module* module, const StringSlice* name); } // namespace interpreter } // namespace wabt diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index cbc1da4d..f24f4030 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -30,7 +30,6 @@ #include "option-parser.h" #include "stream.h" -#define INSTRUCTION_QUANTUM 1000 #define PROGRAM_NAME "wasm-interp" using namespace wabt; @@ -44,7 +43,7 @@ static int s_verbose; static const char* s_infile; static ReadBinaryOptions s_read_binary_options = WABT_READ_BINARY_OPTIONS_DEFAULT; -static ThreadOptions s_thread_options = WABT_INTERPRETER_THREAD_OPTIONS_DEFAULT; +static Thread::Options s_thread_options; static bool s_trace; static bool s_spec; static bool s_run_all_exports; @@ -271,79 +270,13 @@ static void print_call(StringSlice module_name, } } -static interpreter::Result run_defined_function(Thread* thread, - IstreamOffset offset) { - thread->pc = offset; - interpreter::Result iresult = interpreter::Result::Ok; - int quantum = s_trace ? 1 : INSTRUCTION_QUANTUM; - IstreamOffset* call_stack_return_top = thread->call_stack_top; - while (iresult == interpreter::Result::Ok) { - if (s_trace) - trace_pc(thread, s_stdout_stream.get()); - iresult = run_interpreter(thread, quantum, call_stack_return_top); - } - if (iresult != interpreter::Result::Returned) - return iresult; - /* use OK instead of RETURNED for consistency */ - return interpreter::Result::Ok; -} - -static interpreter::Result push_args(Thread* thread, - const FuncSignature* sig, - const std::vector<TypedValue>& args) { - if (sig->param_types.size() != args.size()) - return interpreter::Result::ArgumentTypeMismatch; - - for (size_t i = 0; i < sig->param_types.size(); ++i) { - if (sig->param_types[i] != args[i].type) - return interpreter::Result::ArgumentTypeMismatch; - - interpreter::Result iresult = push_thread_value(thread, args[i].value); - if (iresult != interpreter::Result::Ok) { - thread->value_stack_top = thread->value_stack.data(); - return iresult; - } - } - return interpreter::Result::Ok; -} - -static void copy_results(Thread* thread, - const FuncSignature* sig, - std::vector<TypedValue>* out_results) { - size_t expected_results = sig->result_types.size(); - size_t value_stack_depth = - thread->value_stack_top - thread->value_stack.data(); - WABT_USE(value_stack_depth); - assert(expected_results == value_stack_depth); - - out_results->clear(); - for (size_t i = 0; i < expected_results; ++i) - out_results->emplace_back(sig->result_types[i], thread->value_stack[i]); -} - static interpreter::Result run_function(Thread* thread, Index func_index, const std::vector<TypedValue>& args, std::vector<TypedValue>* out_results) { - assert(func_index < thread->env->funcs.size()); - Func* func = thread->env->funcs[func_index].get(); - Index sig_index = func->sig_index; - assert(sig_index < thread->env->sigs.size()); - FuncSignature* sig = &thread->env->sigs[sig_index]; - - interpreter::Result iresult = push_args(thread, sig, args); - if (iresult == interpreter::Result::Ok) { - iresult = func->is_host - ? call_host(thread, func->as_host()) - : run_defined_function(thread, func->as_defined()->offset); - if (iresult == interpreter::Result::Ok) - copy_results(thread, sig, out_results); - } - - /* Always reset the value and call stacks */ - thread->value_stack_top = thread->value_stack.data(); - thread->call_stack_top = thread->call_stack.data(); - return iresult; + return s_trace ? thread->TraceFunction(func_index, s_stdout_stream.get(), + args, out_results) + : thread->RunFunction(func_index, args, out_results); } static interpreter::Result run_start_function(Thread* thread, @@ -381,7 +314,7 @@ static interpreter::Result run_export_by_name( const std::vector<TypedValue>& args, std::vector<TypedValue>* out_results, RunVerbosity verbose) { - Export* export_ = get_export_by_name(module, name); + Export* export_ = module->GetExport(*name); if (!export_) return interpreter::Result::UnknownExport; if (export_->kind != ExternalKind::Func) @@ -394,13 +327,13 @@ static interpreter::Result get_global_export_by_name( Module* module, const StringSlice* name, std::vector<TypedValue>* out_results) { - Export* export_ = get_export_by_name(module, name); + Export* export_ = module->GetExport(*name); if (!export_) return interpreter::Result::UnknownExport; if (export_->kind != ExternalKind::Global) return interpreter::Result::ExportKindMismatch; - Global* global = &thread->env->globals[export_->index]; + Global* global = thread->env()->GetGlobal(export_->index); out_results->clear(); out_results->push_back(global->typed_value); return interpreter::Result::Ok; @@ -436,7 +369,7 @@ static wabt::Result read_module(const char* module_filename, if (WABT_SUCCEEDED(result)) { if (s_verbose) - disassemble_module(env, s_stdout_stream.get(), *out_module); + env->DisassembleModule(s_stdout_stream.get(), *out_module); } delete[] data; } @@ -564,7 +497,7 @@ static wabt::Result spectest_import_global(Import* import, static void init_environment(Environment* env) { HostModule* host_module = - append_host_module(env, string_slice_from_cstr("spectest")); + env->AppendHostModule(string_slice_from_cstr("spectest")); host_module->import_delegate.import_func = spectest_import_func; host_module->import_delegate.import_table = spectest_import_table; host_module->import_delegate.import_memory = spectest_import_memory; @@ -574,14 +507,13 @@ static void init_environment(Environment* env) { static wabt::Result read_and_run_module(const char* module_filename) { wabt::Result result; Environment env; - DefinedModule* module = nullptr; - Thread thread; - BinaryErrorHandlerFile error_handler; - init_environment(&env); - init_thread(&env, &thread, &s_thread_options); + + BinaryErrorHandlerFile error_handler; + DefinedModule* module = nullptr; result = read_module(module_filename, &env, &error_handler, &module); if (WABT_SUCCEEDED(result)) { + Thread thread(&env, s_thread_options); interpreter::Result iresult = run_start_function(&thread, module); if (iresult == interpreter::Result::Ok) { if (s_run_all_exports) @@ -597,7 +529,8 @@ static wabt::Result read_and_run_module(const char* module_filename) { * format from wast2wasm. */ struct Context { Context() - : last_module(nullptr), + : thread(&env, s_thread_options), + last_module(nullptr), json_data(nullptr), json_data_size(0), json_offset(0), @@ -1002,13 +935,13 @@ static wabt::Result on_module_command(Context* ctx, StringSlice filename, StringSlice name) { char* path = create_module_path(ctx, filename); - EnvironmentMark mark = mark_environment(&ctx->env); + Environment::MarkPoint mark = ctx->env.Mark(); BinaryErrorHandlerFile error_handler; wabt::Result result = read_module(path, &ctx->env, &error_handler, &ctx->last_module); if (WABT_FAILED(result)) { - reset_environment_to_mark(&ctx->env, mark); + ctx->env.ResetToMarkPoint(mark); print_command_error(ctx, "error reading module: \"%s\"", path); delete[] path; return wabt::Result::Error; @@ -1019,15 +952,15 @@ static wabt::Result on_module_command(Context* ctx, interpreter::Result iresult = run_start_function(&ctx->thread, ctx->last_module); if (iresult != interpreter::Result::Ok) { - reset_environment_to_mark(&ctx->env, mark); + ctx->env.ResetToMarkPoint(mark); print_interpreter_result("error running start function", iresult); return wabt::Result::Error; } if (!string_slice_is_empty(&name)) { ctx->last_module->name = dup_string_slice(name); - ctx->env.module_bindings.emplace(string_slice_to_string(name), - Binding(ctx->env.modules.size() - 1)); + ctx->env.EmplaceModuleBinding(string_slice_to_string(name), + Binding(ctx->env.GetModuleCount() - 1)); } return wabt::Result::Ok; } @@ -1039,15 +972,13 @@ static wabt::Result run_action(Context* ctx, RunVerbosity verbose) { out_results->clear(); - int module_index; + Module* module; if (!string_slice_is_empty(&action->module_name)) { - module_index = ctx->env.module_bindings.find_index(action->module_name); + module = ctx->env.FindModule(action->module_name); } else { - module_index = static_cast<int>(ctx->env.modules.size()) - 1; + module = ctx->env.GetLastModule(); } - - assert(module_index < static_cast<int>(ctx->env.modules.size())); - Module* module = ctx->env.modules[module_index].get(); + assert(module); switch (action->type) { case ActionType::Invoke: @@ -1132,32 +1063,20 @@ static wabt::Result on_assert_malformed_command(Context* ctx, static wabt::Result on_register_command(Context* ctx, StringSlice name, StringSlice as) { - int module_index; + Index module_index; if (!string_slice_is_empty(&name)) { - /* The module names can be different than their registered names. We don't - * keep a hash for the module names (just the registered names), so we'll - * just iterate over all the modules to find it. */ - module_index = -1; - for (size_t i = 0; i < ctx->env.modules.size(); ++i) { - const StringSlice* module_name = &ctx->env.modules[i]->name; - if (!string_slice_is_empty(module_name) && - string_slices_are_equal(&name, module_name)) { - module_index = static_cast<int>(i); - break; - } - } + module_index = ctx->env.FindModuleIndex(name); } else { - module_index = static_cast<int>(ctx->env.modules.size()) - 1; + module_index = ctx->env.GetLastModuleIndex(); } - if (module_index < 0 || - module_index >= static_cast<int>(ctx->env.modules.size())) { + if (module_index == kInvalidIndex) { print_command_error(ctx, "unknown module in register"); return wabt::Result::Error; } - ctx->env.registered_module_bindings.emplace(string_slice_to_string(as), - Binding(module_index)); + ctx->env.EmplaceRegisteredModuleBinding(string_slice_to_string(as), + Binding(module_index)); return wabt::Result::Ok; } @@ -1169,9 +1088,9 @@ static wabt::Result on_assert_unlinkable_command(Context* ctx, ctx->total++; char* path = create_module_path(ctx, filename); DefinedModule* module; - EnvironmentMark mark = mark_environment(&ctx->env); + Environment::MarkPoint mark = ctx->env.Mark(); wabt::Result result = read_module(path, &ctx->env, &error_handler, &module); - reset_environment_to_mark(&ctx->env, mark); + ctx->env.ResetToMarkPoint(mark); if (WABT_FAILED(result)) { ctx->passed++; @@ -1215,7 +1134,7 @@ static wabt::Result on_assert_uninstantiable_command(Context* ctx, ctx->total++; char* path = create_module_path(ctx, filename); DefinedModule* module; - EnvironmentMark mark = mark_environment(&ctx->env); + Environment::MarkPoint mark = ctx->env.Mark(); wabt::Result result = read_module(path, &ctx->env, &error_handler, &module); if (WABT_SUCCEEDED(result)) { @@ -1233,7 +1152,7 @@ static wabt::Result on_assert_uninstantiable_command(Context* ctx, result = wabt::Result::Error; } - reset_environment_to_mark(&ctx->env, mark); + ctx->env.ResetToMarkPoint(mark); delete[] path; return result; } @@ -1596,7 +1515,6 @@ static wabt::Result read_and_run_spec_json(const char* spec_json_filename) { ctx.loc.line = 1; ctx.loc.first_column = 1; init_environment(&ctx.env); - init_thread(&ctx.env, &ctx.thread, &s_thread_options); char* data; size_t size; diff --git a/src/writer.h b/src/writer.h index ecb4aeb7..555820b6 100644 --- a/src/writer.h +++ b/src/writer.h @@ -29,6 +29,8 @@ namespace wabt { struct OutputBuffer { Result WriteToFile(const char* filename) const; + size_t size() const { return data.size(); } + std::vector<uint8_t> data; }; |