diff options
Diffstat (limited to 'src/interpreter.cc')
-rw-r--r-- | src/interpreter.cc | 171 |
1 files changed, 126 insertions, 45 deletions
diff --git a/src/interpreter.cc b/src/interpreter.cc index 80e4ec18..83cb69fb 100644 --- a/src/interpreter.cc +++ b/src/interpreter.cc @@ -50,6 +50,78 @@ namespace interpreter { } \ } while (0) +std::string TypedValueToString(const TypedValue& tv) { + switch (tv.type) { + case Type::I32: + return StringPrintf("i32:%u", tv.value.i32); + + case Type::I64: + return StringPrintf("i64:%" PRIu64, tv.value.i64); + + case Type::F32: { + float value; + memcpy(&value, &tv.value.f32_bits, sizeof(float)); + return StringPrintf("f32:%f", value); + } + + case Type::F64: { + double value; + memcpy(&value, &tv.value.f64_bits, sizeof(double)); + return StringPrintf("f64:%f", value); + } + + default: + WABT_UNREACHABLE; + } +} + +void WriteTypedValue(Stream* stream, const TypedValue& tv) { + std::string s = TypedValueToString(tv); + stream->WriteData(s.data(), s.size()); +} + +void WriteTypedValues(Stream* stream, const TypedValues& values) { + for (size_t i = 0; i < values.size(); ++i) { + WriteTypedValue(stream, values[i]); + if (i != values.size() - 1) + stream->Writef(", "); + } +} + +#define V(name, str) str, + static const char* s_trap_strings[] = {FOREACH_INTERPRETER_RESULT(V)}; +#undef V + +const char* ResultToString(Result result) { + return s_trap_strings[static_cast<size_t>(result)]; +} + +void WriteResult(Stream* stream, const char* desc, Result result) { + stream->Writef("%s: %s\n", desc, ResultToString(result)); +} + +void WriteCall(Stream* stream, + string_view module_name, + string_view func_name, + const TypedValues& args, + const TypedValues& results, + Result result) { + if (!module_name.empty()) + stream->Writef(PRIstringview ".", WABT_PRINTF_STRING_VIEW_ARG(module_name)); + stream->Writef(PRIstringview "(", WABT_PRINTF_STRING_VIEW_ARG(func_name)); + WriteTypedValues(stream, args); + stream->Writef(") =>"); + if (result == Result::Ok) { + if (results.size() > 0) { + stream->Writef(" "); + WriteTypedValues(stream, results); + } + stream->Writef("\n"); + } else { + WriteResult(stream, " error", result); + } +} + Environment::Environment() : istream_(new OutputBuffer()) {} Index Environment::FindModuleIndex(string_view name) const { @@ -73,10 +145,12 @@ Module* Environment::FindRegisteredModule(string_view name) { Thread::Options::Options(uint32_t value_stack_size, uint32_t call_stack_size, - IstreamOffset pc) + IstreamOffset pc, + Stream* trace_stream) : value_stack_size(value_stack_size), call_stack_size(call_stack_size), - pc(pc) {} + pc(pc), + trace_stream(trace_stream) {} Thread::Thread(Environment* env, const Options& options) : env_(env), @@ -86,7 +160,8 @@ Thread::Thread(Environment* env, const Options& options) 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) {} + pc_(options.pc), + trace_stream_(options.trace_stream) {} FuncSignature::FuncSignature(Index param_count, Type* param_types, @@ -168,8 +243,7 @@ HostModule* Environment::AppendHostModule(string_view name) { return module; } -Result Thread::PushArgs(const FuncSignature* sig, - const std::vector<TypedValue>& args) { +Result Thread::PushArgs(const FuncSignature* sig, const TypedValues& args) { if (sig->param_types.size() != args.size()) return interpreter::Result::ArgumentTypeMismatch; @@ -186,8 +260,7 @@ Result Thread::PushArgs(const FuncSignature* sig, return interpreter::Result::Ok; } -void Thread::CopyResults(const FuncSignature* sig, - std::vector<TypedValue>* out_results) { +void Thread::CopyResults(const FuncSignature* sig, TypedValues* 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); @@ -1149,8 +1222,8 @@ bool Environment::FuncSignaturesAreEqual(Index sig_index_0, } Result Thread::RunFunction(Index func_index, - const std::vector<TypedValue>& args, - std::vector<TypedValue>* out_results) { + const TypedValues& args, + TypedValues* out_results) { Func* func = env_->GetFunc(func_index); FuncSignature* sig = env_->GetFuncSignature(func->sig_index); @@ -1169,51 +1242,59 @@ Result Thread::RunFunction(Index func_index, 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 Thread::RunStartFunction(DefinedModule* module) { + if (module->start_func_index == kInvalidIndex) + return Result::Ok; - Result result = PushArgs(sig, args); - if (result == Result::Ok) { - result = func->is_host ? CallHost(cast<HostFunc>(func)) - : TraceDefinedFunction( - cast<DefinedFunc>(func)->offset, stream); - if (result == Result::Ok) - CopyResults(sig, out_results); + if (trace_stream_) { + trace_stream_->Writef(">>> running start function:\n"); } - - // Always reset the value and call stacks. - value_stack_top_ = value_stack_.data(); - call_stack_top_ = call_stack_.data(); + TypedValues args; + TypedValues results; + Result result = RunFunction(module->start_func_index, args, &results); + assert(results.size() == 0); 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); +Result Thread::RunExport(const Export* export_, + const TypedValues& args, + TypedValues* out_results) { + if (trace_stream_) { + trace_stream_->Writef(">>> running export \"" PRIstringview "\":\n", + WABT_PRINTF_STRING_VIEW_ARG(export_->name)); } - if (result != Result::Returned) - return result; - // Use OK instead of RETURNED for consistency. - return Result::Ok; + + assert(export_->kind == ExternalKind::Func); + return RunFunction(export_->index, args, out_results); } -Result Thread::TraceDefinedFunction(IstreamOffset function_offset, - Stream* stream) { - const int kNumInstructions = 1; +Result Thread::RunExportByName(interpreter::Module* module, + string_view name, + const TypedValues& args, + TypedValues* out_results) { + interpreter::Export* export_ = module->GetExport(name); + if (!export_) + return interpreter::Result::UnknownExport; + if (export_->kind != ExternalKind::Func) + return interpreter::Result::ExportKindMismatch; + return RunExport(export_, args, out_results); +} + +Result Thread::RunDefinedFunction(IstreamOffset function_offset) { 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 (trace_stream_) { + const int kNumInstructions = 1; + while (result == Result::Ok) { + Trace(trace_stream_); + result = Run(kNumInstructions, call_stack_return_top); + } + } else { + const int kNumInstructions = 1000; + while (result == Result::Ok) { + result = Run(kNumInstructions, call_stack_return_top); + } } if (result != Result::Returned) return result; @@ -1228,8 +1309,8 @@ Result Thread::CallHost(HostFunc* func) { size_t num_results = sig->result_types.size(); // + 1 is a workaround for using data() below; UBSAN doesn't like calling // data() with an empty vector. - std::vector<TypedValue> params(num_params + 1); - std::vector<TypedValue> results(num_results + 1); + TypedValues params(num_params + 1); + TypedValues results(num_results + 1); for (size_t i = num_params; i > 0; --i) { params[i - 1].value = Pop(); |