summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binary-reader-interpreter.cc148
-rw-r--r--src/binary-reader-interpreter.h2
-rw-r--r--src/interpreter.cc388
-rw-r--r--src/interpreter.h263
-rw-r--r--src/tools/wasm-interp.cc150
-rw-r--r--src/writer.h2
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;
};