summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/interpreter.cc171
-rw-r--r--src/interpreter.h42
-rw-r--r--src/tools/spectest-interp.cc220
-rw-r--r--src/tools/wasm-interp.cc146
-rw-r--r--test/interp/binary.txt2
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