diff options
-rw-r--r-- | src/interpreter.cc | 171 | ||||
-rw-r--r-- | src/interpreter.h | 42 | ||||
-rw-r--r-- | src/tools/spectest-interp.cc | 220 | ||||
-rw-r--r-- | src/tools/wasm-interp.cc | 146 | ||||
-rw-r--r-- | test/interp/binary.txt | 2 |
5 files changed, 217 insertions, 364 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(); diff --git a/src/interpreter.h b/src/interpreter.h index cccf5897..91deeedb 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -152,6 +152,8 @@ struct TypedValue { Value value; }; +typedef std::vector<TypedValue> TypedValues; + struct Global { Global() : mutable_(false), import_index(kInvalidIndex) {} Global(const TypedValue& typed_value, bool mutable_) @@ -467,11 +469,13 @@ class Thread { explicit Options(uint32_t value_stack_size = kDefaultValueStackSize, uint32_t call_stack_size = kDefaultCallStackSize, - IstreamOffset pc = kInvalidIstreamOffset); + IstreamOffset pc = kInvalidIstreamOffset, + Stream* trace_stream = nullptr); uint32_t value_stack_size; uint32_t call_stack_size; IstreamOffset pc; + Stream* trace_stream; }; explicit Thread(Environment*, const Options& = Options()); @@ -479,19 +483,22 @@ class Thread { 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); + const TypedValues& args, + TypedValues* out_results); + Result RunStartFunction(DefinedModule* module); + Result RunExport(const Export*, + const TypedValues& args, + TypedValues* out_results); + Result RunExportByName(Module* module, + string_view name, + const TypedValues& args, + TypedValues* out_results); private: const uint8_t* GetIstream() const { return env_->istream_->data.data(); } - Result PushArgs(const FuncSignature*, const std::vector<TypedValue>& args); - void CopyResults(const FuncSignature*, std::vector<TypedValue>* out_results); + Result PushArgs(const FuncSignature*, const TypedValues& args); + void CopyResults(const FuncSignature*, TypedValues* out_results); Result Run(int num_instructions, IstreamOffset* call_stack_return_top); void Trace(Stream*); @@ -559,7 +566,6 @@ class Thread { Result BinopTrap(BinopTrapFunc<R, T> func) WABT_WARN_UNUSED; Result RunDefinedFunction(IstreamOffset); - Result TraceDefinedFunction(IstreamOffset, Stream*); Result CallHost(HostFunc*); @@ -571,6 +577,7 @@ class Thread { IstreamOffset* call_stack_top_; IstreamOffset* call_stack_end_; IstreamOffset pc_; + Stream* trace_stream_; }; bool IsCanonicalNan(uint32_t f32_bits); @@ -578,6 +585,19 @@ bool IsCanonicalNan(uint64_t f64_bits); bool IsArithmeticNan(uint32_t f32_bits); bool IsArithmeticNan(uint64_t f64_bits); +std::string TypedValueToString(const TypedValue&); +const char* ResultToString(Result); + +void WriteTypedValue(Stream* stream, const TypedValue&); +void WriteTypedValues(Stream* stream, const TypedValues&); +void WriteResult(Stream* stream, const char* desc, Result); +void WriteCall(Stream* stream, + string_view module_name, + string_view func_name, + const TypedValues& args, + const TypedValues& results, + Result); + } // namespace interpreter } // namespace wabt diff --git a/src/tools/spectest-interp.cc b/src/tools/spectest-interp.cc index 24253c9d..e7a7c1ba 100644 --- a/src/tools/spectest-interp.cc +++ b/src/tools/spectest-interp.cc @@ -40,14 +40,9 @@ using namespace wabt; using namespace wabt::interpreter; -#define V(name, str) str, -static const char* s_trap_strings[] = {FOREACH_INTERPRETER_RESULT(V)}; -#undef V - static int s_verbose; static const char* s_infile; static Thread::Options s_thread_options; -static bool s_trace; static Features s_features; static std::unique_ptr<FileStream> s_log_stream; @@ -87,7 +82,9 @@ static void ParseOptions(int argc, char** argv) { // TODO(binji): validate. s_thread_options.call_stack_size = atoi(argument.c_str()); }); - parser.AddOption('t', "trace", "Trace execution", []() { s_trace = true; }); + parser.AddOption('t', "trace", "Trace execution", []() { + s_thread_options.trace_stream = s_stdout_stream.get(); + }); parser.AddArgument("filename", OptionParser::ArgumentCount::One, [](const char* argument) { s_infile = argument; }); @@ -116,134 +113,10 @@ static string_view GetDirname(string_view path) { return path.substr(0, std::max(last_slash, last_backslash)); } -/* Not sure, but 100 chars is probably safe */ -#define MAX_TYPED_VALUE_CHARS 100 - -static void SPrintTypedValue(char* buffer, size_t size, const TypedValue* tv) { - switch (tv->type) { - case Type::I32: - snprintf(buffer, size, "i32:%u", tv->value.i32); - break; - - case Type::I64: - snprintf(buffer, size, "i64:%" PRIu64, tv->value.i64); - break; - - case Type::F32: { - float value; - memcpy(&value, &tv->value.f32_bits, sizeof(float)); - snprintf(buffer, size, "f32:%f", value); - break; - } - - case Type::F64: { - double value; - memcpy(&value, &tv->value.f64_bits, sizeof(double)); - snprintf(buffer, size, "f64:%f", value); - break; - } - - default: - WABT_UNREACHABLE; - } -} - -static void PrintTypedValue(const TypedValue* tv) { - char buffer[MAX_TYPED_VALUE_CHARS]; - SPrintTypedValue(buffer, sizeof(buffer), tv); - printf("%s", buffer); -} - -static void PrintTypedValueVector(const std::vector<TypedValue>& values) { - for (size_t i = 0; i < values.size(); ++i) { - PrintTypedValue(&values[i]); - if (i != values.size() - 1) - printf(", "); - } -} - -static void PrintInterpreterResult(const char* desc, - interpreter::Result iresult) { - printf("%s: %s\n", desc, s_trap_strings[static_cast<size_t>(iresult)]); -} - -static void PrintCall(string_view module_name, - string_view func_name, - const std::vector<TypedValue>& args, - const std::vector<TypedValue>& results, - interpreter::Result iresult) { - if (!module_name.empty()) - printf(PRIstringview ".", WABT_PRINTF_STRING_VIEW_ARG(module_name)); - printf(PRIstringview "(", WABT_PRINTF_STRING_VIEW_ARG(func_name)); - PrintTypedValueVector(args); - printf(") =>"); - if (iresult == interpreter::Result::Ok) { - if (results.size() > 0) { - printf(" "); - PrintTypedValueVector(results); - } - printf("\n"); - } else { - PrintInterpreterResult(" error", iresult); - } -} - -static interpreter::Result RunFunction(Thread* thread, - Index func_index, - const std::vector<TypedValue>& args, - std::vector<TypedValue>* out_results) { - return s_trace ? thread->TraceFunction(func_index, s_stdout_stream.get(), - args, out_results) - : thread->RunFunction(func_index, args, out_results); -} - -static interpreter::Result RunStartFunction(Thread* thread, - DefinedModule* module) { - if (module->start_func_index == kInvalidIndex) - return interpreter::Result::Ok; - - if (s_trace) - printf(">>> running start function:\n"); - std::vector<TypedValue> args; - std::vector<TypedValue> results; - interpreter::Result iresult = - RunFunction(thread, module->start_func_index, args, &results); - assert(results.size() == 0); - return iresult; -} - -static interpreter::Result RunExport(Thread* thread, - const interpreter::Export* export_, - const std::vector<TypedValue>& args, - std::vector<TypedValue>* out_results) { - if (s_trace) { - printf(">>> running export \"" PRIstringview "\":\n", - WABT_PRINTF_STRING_VIEW_ARG(export_->name)); - } - - assert(export_->kind == ExternalKind::Func); - return RunFunction(thread, export_->index, args, out_results); -} - -static interpreter::Result RunExportByName(Thread* thread, - interpreter::Module* module, - string_view name, - const std::vector<TypedValue>& args, - std::vector<TypedValue>* out_results, - RunVerbosity verbose) { - interpreter::Export* export_ = module->GetExport(name); - if (!export_) - return interpreter::Result::UnknownExport; - if (export_->kind != ExternalKind::Func) - return interpreter::Result::ExportKindMismatch; - return RunExport(thread, export_, args, out_results); -} - -static interpreter::Result GetGlobalExportByName( - Thread* thread, - interpreter::Module* module, - string_view name, - std::vector<TypedValue>* out_results) { +static interpreter::Result GetGlobalExportByName(Thread* thread, + interpreter::Module* module, + string_view name, + TypedValues* out_results) { interpreter::Export* export_ = module->GetExport(name); if (!export_) return interpreter::Result::UnknownExport; @@ -294,12 +167,12 @@ static interpreter::Result DefaultHostCallback( for (Index i = 0; i < num_results; ++i) out_results[i].type = sig->result_types[i]; - std::vector<TypedValue> vec_args(args, args + num_args); - std::vector<TypedValue> vec_results(out_results, out_results + num_results); + TypedValues vec_args(args, args + num_args); + TypedValues vec_results(out_results, out_results + num_results); printf("called host "); - PrintCall(func->module_name, func->field_name, vec_args, vec_results, - interpreter::Result::Ok); + WriteCall(s_stdout_stream.get(), func->module_name, func->field_name, + vec_args, vec_results, interpreter::Result::Ok); return interpreter::Result::Ok; } @@ -415,7 +288,7 @@ struct Action { ::ActionType type = ::ActionType::Invoke; std::string module_name; std::string field_name; - std::vector<TypedValue> args; + TypedValues args; }; // An extremely simple JSON parser that only knows how to parse the expected @@ -448,7 +321,7 @@ class SpecJSONParser { wabt::Result ParseTypeObject(Type* out_type); wabt::Result ParseTypeVector(TypeVector* out_types); wabt::Result ParseConst(TypedValue* out_value); - wabt::Result ParseConstVector(std::vector<TypedValue>* out_values); + wabt::Result ParseConstVector(TypedValues* out_values); wabt::Result ParseAction(::Action* out_action); wabt::Result ParseModuleType(ModuleType* out_type); @@ -457,7 +330,7 @@ class SpecJSONParser { wabt::Result OnModuleCommand(string_view filename, string_view name); wabt::Result RunAction(::Action* action, interpreter::Result* out_iresult, - std::vector<TypedValue>* out_results, + TypedValues* out_results, RunVerbosity verbose); wabt::Result OnActionCommand(::Action* action); wabt::Result ReadInvalidTextModule(const char* module_filename, @@ -481,7 +354,7 @@ class SpecJSONParser { string_view text, ModuleType module_type); wabt::Result OnAssertReturnCommand(::Action* action, - const std::vector<TypedValue>& expected); + const TypedValues& expected); wabt::Result OnAssertReturnNanCommand(::Action* action, bool canonical); wabt::Result OnAssertTrapCommand(::Action* action, string_view text); wabt::Result OnAssertExhaustionCommand(::Action* action); @@ -788,8 +661,7 @@ wabt::Result SpecJSONParser::ParseConst(TypedValue* out_value) { } } -wabt::Result SpecJSONParser::ParseConstVector( - std::vector<TypedValue>* out_values) { +wabt::Result SpecJSONParser::ParseConstVector(TypedValues* out_values) { out_values->clear(); EXPECT("["); bool first = true; @@ -878,10 +750,10 @@ wabt::Result SpecJSONParser::OnModuleCommand(string_view filename, return wabt::Result::Error; } - interpreter::Result iresult = RunStartFunction(&thread_, last_module_); + interpreter::Result iresult = thread_.RunStartFunction(last_module_); if (iresult != interpreter::Result::Ok) { env_.ResetToMarkPoint(mark); - PrintInterpreterResult("error running start function", iresult); + WriteResult(s_stdout_stream.get(), "error running start function", iresult); return wabt::Result::Error; } @@ -895,7 +767,7 @@ wabt::Result SpecJSONParser::OnModuleCommand(string_view filename, wabt::Result SpecJSONParser::RunAction(::Action* action, interpreter::Result* out_iresult, - std::vector<TypedValue>* out_results, + TypedValues* out_results, RunVerbosity verbose) { out_results->clear(); @@ -909,11 +781,11 @@ wabt::Result SpecJSONParser::RunAction(::Action* action, switch (action->type) { case ::ActionType::Invoke: - *out_iresult = RunExportByName(&thread_, module, action->field_name, - action->args, out_results, verbose); + *out_iresult = thread_.RunExportByName(module, action->field_name, + action->args, out_results); if (verbose == RunVerbosity::Verbose) { - PrintCall(string_view(), action->field_name, action->args, *out_results, - *out_iresult); + WriteCall(s_stdout_stream.get(), string_view(), action->field_name, + action->args, *out_results, *out_iresult); } return wabt::Result::Ok; @@ -931,7 +803,7 @@ wabt::Result SpecJSONParser::RunAction(::Action* action, } wabt::Result SpecJSONParser::OnActionCommand(::Action* action) { - std::vector<TypedValue> results; + TypedValues results; interpreter::Result iresult; total_++; @@ -941,8 +813,7 @@ wabt::Result SpecJSONParser::OnActionCommand(::Action* action) { if (iresult == interpreter::Result::Ok) { passed_++; } else { - PrintCommandError("unexpected trap: %s", - s_trap_strings[static_cast<size_t>(iresult)]); + PrintCommandError("unexpected trap: %s", ResultToString(iresult)); result = wabt::Result::Error; } } @@ -1090,7 +961,7 @@ wabt::Result SpecJSONParser::OnAssertUninstantiableCommand( ReadModule(path.c_str(), &env_, &error_handler, &module); if (Succeeded(result)) { - interpreter::Result iresult = RunStartFunction(&thread_, module); + interpreter::Result iresult = thread_.RunStartFunction(module); if (iresult == interpreter::Result::Ok) { PrintCommandError("expected error running start function: \"%s\"", path.c_str()); @@ -1128,8 +999,8 @@ static bool TypedValuesAreEqual(const TypedValue* tv1, const TypedValue* tv2) { wabt::Result SpecJSONParser::OnAssertReturnCommand( ::Action* action, - const std::vector<TypedValue>& expected) { - std::vector<TypedValue> results; + const TypedValues& expected) { + TypedValues results; interpreter::Result iresult; total_++; @@ -1143,13 +1014,10 @@ wabt::Result SpecJSONParser::OnAssertReturnCommand( const TypedValue* expected_tv = &expected[i]; const TypedValue* actual_tv = &results[i]; if (!TypedValuesAreEqual(expected_tv, actual_tv)) { - char expected_str[MAX_TYPED_VALUE_CHARS]; - char actual_str[MAX_TYPED_VALUE_CHARS]; - SPrintTypedValue(expected_str, sizeof(expected_str), expected_tv); - SPrintTypedValue(actual_str, sizeof(actual_str), actual_tv); PrintCommandError("mismatch in result %" PRIzd " of assert_return: expected %s, got %s", - i, expected_str, actual_str); + i, TypedValueToString(*expected_tv).c_str(), + TypedValueToString(*actual_tv).c_str()); result = wabt::Result::Error; } } @@ -1161,8 +1029,7 @@ wabt::Result SpecJSONParser::OnAssertReturnCommand( result = wabt::Result::Error; } } else { - PrintCommandError("unexpected trap: %s", - s_trap_strings[static_cast<size_t>(iresult)]); + PrintCommandError("unexpected trap: %s", ResultToString(iresult)); result = wabt::Result::Error; } } @@ -1175,7 +1042,7 @@ wabt::Result SpecJSONParser::OnAssertReturnCommand( wabt::Result SpecJSONParser::OnAssertReturnNanCommand(::Action* action, bool canonical) { - std::vector<TypedValue> results; + TypedValues results; interpreter::Result iresult; total_++; @@ -1194,9 +1061,8 @@ wabt::Result SpecJSONParser::OnAssertReturnNanCommand(::Action* action, bool is_nan = canonical ? IsCanonicalNan(actual.value.f32_bits) : IsArithmeticNan(actual.value.f32_bits); if (!is_nan) { - char actual_str[MAX_TYPED_VALUE_CHARS]; - SPrintTypedValue(actual_str, sizeof(actual_str), &actual); - PrintCommandError("expected result to be nan, got %s", actual_str); + PrintCommandError("expected result to be nan, got %s", + TypedValueToString(actual).c_str()); result = wabt::Result::Error; } break; @@ -1206,9 +1072,8 @@ wabt::Result SpecJSONParser::OnAssertReturnNanCommand(::Action* action, bool is_nan = canonical ? IsCanonicalNan(actual.value.f64_bits) : IsArithmeticNan(actual.value.f64_bits); if (!is_nan) { - char actual_str[MAX_TYPED_VALUE_CHARS]; - SPrintTypedValue(actual_str, sizeof(actual_str), &actual); - PrintCommandError("expected result to be nan, got %s", actual_str); + PrintCommandError("expected result to be nan, got %s", + TypedValueToString(actual).c_str()); result = wabt::Result::Error; } break; @@ -1221,8 +1086,7 @@ wabt::Result SpecJSONParser::OnAssertReturnNanCommand(::Action* action, break; } } else { - PrintCommandError("unexpected trap: %s", - s_trap_strings[static_cast<int>(iresult)]); + PrintCommandError("unexpected trap: %s", ResultToString(iresult)); result = wabt::Result::Error; } } @@ -1235,7 +1099,7 @@ wabt::Result SpecJSONParser::OnAssertReturnNanCommand(::Action* action, wabt::Result SpecJSONParser::OnAssertTrapCommand(::Action* action, string_view text) { - std::vector<TypedValue> results; + TypedValues results; interpreter::Result iresult; total_++; @@ -1255,7 +1119,7 @@ wabt::Result SpecJSONParser::OnAssertTrapCommand(::Action* action, } wabt::Result SpecJSONParser::OnAssertExhaustionCommand(::Action* action) { - std::vector<TypedValue> results; + TypedValues results; interpreter::Result iresult; total_++; @@ -1363,7 +1227,7 @@ wabt::Result SpecJSONParser::ParseCommand() { OnAssertUninstantiableCommand(filename, text, module_type); } else if (Match("\"assert_return\"")) { ::Action action; - std::vector<TypedValue> expected; + TypedValues expected; EXPECT(","); CHECK_RESULT(ParseLine()); @@ -1454,10 +1318,10 @@ static wabt::Result ReadAndRunSpecJSON(const char* spec_json_filename) { int ProgramMain(int argc, char** argv) { InitStdio(); - ParseOptions(argc, argv); - s_stdout_stream = FileStream::CreateStdout(); + ParseOptions(argc, argv); + wabt::Result result; result = ReadAndRunSpecJSON(s_infile); return result != wabt::Result::Ok; diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index 00ec38ae..9bd2cc24 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -40,14 +40,9 @@ using namespace wabt; using namespace wabt::interpreter; -#define V(name, str) str, -static const char* s_trap_strings[] = {FOREACH_INTERPRETER_RESULT(V)}; -#undef V - static int s_verbose; static const char* s_infile; static Thread::Options s_thread_options; -static bool s_trace; static bool s_run_all_exports; static bool s_host_print; static Features s_features; @@ -100,7 +95,9 @@ static void ParseOptions(int argc, char** argv) { // TODO(binji): validate. s_thread_options.call_stack_size = atoi(argument.c_str()); }); - parser.AddOption('t', "trace", "Trace execution", []() { s_trace = true; }); + parser.AddOption('t', "trace", "Trace execution", []() { + s_thread_options.trace_stream = s_stdout_stream.get(); + }); parser.AddOption( "run-all-exports", "Run all the exported functions, in order. Useful for testing", @@ -115,126 +112,16 @@ static void ParseOptions(int argc, char** argv) { parser.Parse(argc, argv); } -// TODO(binji): Share these helper functions w/ spectest-interp as well. - -/* Not sure, but 100 chars is probably safe */ -#define MAX_TYPED_VALUE_CHARS 100 - -static void SPrintTypedValue(char* buffer, size_t size, const TypedValue* tv) { - switch (tv->type) { - case Type::I32: - snprintf(buffer, size, "i32:%u", tv->value.i32); - break; - - case Type::I64: - snprintf(buffer, size, "i64:%" PRIu64, tv->value.i64); - break; - - case Type::F32: { - float value; - memcpy(&value, &tv->value.f32_bits, sizeof(float)); - snprintf(buffer, size, "f32:%f", value); - break; - } - - case Type::F64: { - double value; - memcpy(&value, &tv->value.f64_bits, sizeof(double)); - snprintf(buffer, size, "f64:%f", value); - break; - } - - default: - WABT_UNREACHABLE; - } -} - -static void PrintTypedValue(const TypedValue* tv) { - char buffer[MAX_TYPED_VALUE_CHARS]; - SPrintTypedValue(buffer, sizeof(buffer), tv); - printf("%s", buffer); -} - -static void PrintTypedValueVector(const std::vector<TypedValue>& values) { - for (size_t i = 0; i < values.size(); ++i) { - PrintTypedValue(&values[i]); - if (i != values.size() - 1) - printf(", "); - } -} - -static void PrintInterpreterResult(const char* desc, - interpreter::Result iresult) { - printf("%s: %s\n", desc, s_trap_strings[static_cast<size_t>(iresult)]); -} - -static void PrintCall(string_view module_name, - string_view func_name, - const std::vector<TypedValue>& args, - const std::vector<TypedValue>& results, - interpreter::Result iresult) { - if (!module_name.empty()) - printf(PRIstringview ".", WABT_PRINTF_STRING_VIEW_ARG(module_name)); - printf(PRIstringview "(", WABT_PRINTF_STRING_VIEW_ARG(func_name)); - PrintTypedValueVector(args); - printf(") =>"); - if (iresult == interpreter::Result::Ok) { - if (results.size() > 0) { - printf(" "); - PrintTypedValueVector(results); - } - printf("\n"); - } else { - PrintInterpreterResult(" error", iresult); - } -} - -static interpreter::Result RunFunction(Thread* thread, - Index func_index, - const std::vector<TypedValue>& args, - std::vector<TypedValue>* out_results) { - return s_trace ? thread->TraceFunction(func_index, s_stdout_stream.get(), - args, out_results) - : thread->RunFunction(func_index, args, out_results); -} - -static interpreter::Result RunStartFunction(Thread* thread, - DefinedModule* module) { - if (module->start_func_index == kInvalidIndex) - return interpreter::Result::Ok; - - if (s_trace) - printf(">>> running start function:\n"); - std::vector<TypedValue> args; - std::vector<TypedValue> results; - interpreter::Result iresult = - RunFunction(thread, module->start_func_index, args, &results); - assert(results.size() == 0); - return iresult; -} - -static interpreter::Result RunExport(Thread* thread, - const interpreter::Export* export_, - const std::vector<TypedValue>& args, - std::vector<TypedValue>* out_results) { - if (s_trace) { - printf(">>> running export \"" PRIstringview "\":\n", - WABT_PRINTF_STRING_VIEW_ARG(export_->name)); - } - - assert(export_->kind == ExternalKind::Func); - return RunFunction(thread, export_->index, args, out_results); -} - static void RunAllExports(interpreter::Module* module, Thread* thread, RunVerbosity verbose) { - std::vector<TypedValue> args; - std::vector<TypedValue> results; + TypedValues args; + TypedValues results; for (const interpreter::Export& export_ : module->exports) { - interpreter::Result iresult = RunExport(thread, &export_, args, &results); + interpreter::Result iresult = thread->RunExport(&export_, args, &results); if (verbose == RunVerbosity::Verbose) { - PrintCall(string_view(), export_.name, args, results, iresult); + WriteCall(s_stdout_stream.get(), string_view(), export_.name, args, + results, iresult); } } } @@ -317,12 +204,12 @@ class WasmInterpHostImportDelegate : public HostImportDelegate { for (Index i = 0; i < num_results; ++i) out_results[i].type = sig->result_types[i]; - std::vector<TypedValue> vec_args(args, args + num_args); - std::vector<TypedValue> vec_results(out_results, out_results + num_results); + TypedValues vec_args(args, args + num_args); + TypedValues vec_results(out_results, out_results + num_results); printf("called host "); - PrintCall(func->module_name, func->field_name, vec_args, vec_results, - interpreter::Result::Ok); + WriteCall(s_stdout_stream.get(), func->module_name, func->field_name, + vec_args, vec_results, interpreter::Result::Ok); return interpreter::Result::Ok; } @@ -349,12 +236,13 @@ static wabt::Result ReadAndRunModule(const char* module_filename) { result = ReadModule(module_filename, &env, &error_handler, &module); if (Succeeded(result)) { Thread thread(&env, s_thread_options); - interpreter::Result iresult = RunStartFunction(&thread, module); + interpreter::Result iresult = thread.RunStartFunction(module); if (iresult == interpreter::Result::Ok) { if (s_run_all_exports) RunAllExports(module, &thread, RunVerbosity::Verbose); } else { - PrintInterpreterResult("error running start function", iresult); + WriteResult(s_stdout_stream.get(), "error running start function", + iresult); } } return result; @@ -362,10 +250,10 @@ static wabt::Result ReadAndRunModule(const char* module_filename) { int ProgramMain(int argc, char** argv) { InitStdio(); - ParseOptions(argc, argv); - s_stdout_stream = FileStream::CreateStdout(); + ParseOptions(argc, argv); + wabt::Result result = ReadAndRunModule(s_infile); return result != wabt::Result::Ok; } diff --git a/test/interp/binary.txt b/test/interp/binary.txt index 0cf8c37a..1e46ce04 100644 --- a/test/interp/binary.txt +++ b/test/interp/binary.txt @@ -225,7 +225,7 @@ f32_copysign() => f32:0.000000 f64_add() => f64:1111111110.000000 f64_sub() => f64:123400000000000007812762268812638756607430593436581896388608.000000 f64_mul() => f64:-15179717820000.000000 -f64_div() => f64:99999999999999998083559617243737459057312001403031879309116481015410011220367858297629826861622 +f64_div() => f64:999999999999999980835596172437374590573120014030318793091164810154100112203678582976298268616221151962702060266176005440567032331208403948233373515776.000000 f64_min() => f64:0.000000 f64_max() => f64:0.000000 f64_copysign() => f64:0.000000 |