diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/tools/wasm-interp.cc | 680 |
1 files changed, 357 insertions, 323 deletions
diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index 8fb92353..4a06925d 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -314,13 +314,13 @@ static wabt::Result ReadModule(const char* module_filename, return result; } -static interpreter::Result default_host_callback(const HostFunc* func, - const FuncSignature* sig, - Index num_args, - TypedValue* args, - Index num_results, - TypedValue* out_results, - void* user_data) { +static interpreter::Result DefaultHostCallback(const HostFunc* func, + const FuncSignature* sig, + Index num_args, + TypedValue* args, + Index num_results, + TypedValue* out_results, + void* user_data) { memset(out_results, 0, sizeof(TypedValue) * num_results); for (Index i = 0; i < num_results; ++i) out_results[i].type = sig->result_types[i]; @@ -346,7 +346,7 @@ class SpectestHostImportDelegate : public HostImportDelegate { FuncSignature* func_sig, const ErrorCallback& callback) override { if (import->field_name == "print") { - func->as_host()->callback = default_host_callback; + func->as_host()->callback = DefaultHostCallback; return wabt::Result::Ok; } else { PrintError(callback, "unknown host function import " PRIimport, @@ -458,36 +458,6 @@ static wabt::Result ReadAndRunModule(const char* module_filename) { return result; } -/* An extremely simple JSON parser that only knows how to parse the expected - * format from wast2wasm. */ -struct Context { - Context() - : thread(&env, s_thread_options), - last_module(nullptr), - json_offset(0), - has_prev_loc(0), - command_line_number(0), - passed(0), - total(0) {} - - Environment env; - Thread thread; - DefinedModule* last_module; - - /* Parsing info */ - std::vector<uint8_t> json_data; - std::string source_filename; - size_t json_offset; - Location loc; - Location prev_loc; - bool has_prev_loc; - uint32_t command_line_number; - - /* Test info */ - int passed; - int total; -}; - enum class ActionType { Invoke, Get, @@ -500,57 +470,151 @@ struct Action { std::vector<TypedValue> args; }; +// An extremely simple JSON parser that only knows how to parse the expected +// format from wast2wasm. +class SpecJSONParser { + public: + SpecJSONParser() : thread_(&env_, s_thread_options) {} + + wabt::Result ReadFile(const char* spec_json_filename); + wabt::Result ParseCommands(); + + int passed() const { return passed_; } + int total() const { return total_; } + + private: + void WABT_PRINTF_FORMAT(2, 3) PrintParseError(const char* format, ...); + void WABT_PRINTF_FORMAT(2, 3) PrintCommandError(const char* format, ...); + + void PutbackChar(); + int ReadChar(); + void SkipWhitespace(); + bool Match(const char* s); + wabt::Result Expect(const char* s); + wabt::Result ExpectKey(const char* key); + wabt::Result ParseUint32(uint32_t* out_int); + wabt::Result ParseString(std::string* out_string); + wabt::Result ParseKeyStringValue(const char* key, std::string* out_string); + wabt::Result ParseOptNameStringValue(std::string* out_string); + wabt::Result ParseLine(); + 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 ParseAction(Action* out_action); + wabt::Result ParseModuleType(ModuleType* out_type); + + std::string CreateModulePath(string_view filename); + + wabt::Result OnModuleCommand(string_view filename, string_view name); + wabt::Result RunAction(Action* action, + interpreter::Result* out_iresult, + std::vector<TypedValue>* out_results, + RunVerbosity verbose); + wabt::Result OnActionCommand(Action* action); + wabt::Result ReadInvalidTextModule(const char* module_filename, + Environment* env, + ErrorHandler* error_handler); + wabt::Result ReadInvalidModule(const char* module_filename, + Environment* env, + ModuleType module_type, + const char* desc); + wabt::Result OnAssertMalformedCommand(string_view filename, + string_view text, + ModuleType module_type); + wabt::Result OnRegisterCommand(string_view name, string_view as); + wabt::Result OnAssertUnlinkableCommand(string_view filename, + string_view text, + ModuleType module_type); + wabt::Result OnAssertInvalidCommand(string_view filename, + string_view text, + ModuleType module_type); + wabt::Result OnAssertUninstantiableCommand(string_view filename, + string_view text, + ModuleType module_type); + wabt::Result OnAssertReturnCommand(Action* action, + const std::vector<TypedValue>& expected); + wabt::Result OnAssertReturnNanCommand(Action* action, bool canonical); + wabt::Result OnAssertTrapCommand(Action* action, string_view text); + wabt::Result OnAssertExhaustionCommand(Action* action); + wabt::Result ParseCommand(); + + Environment env_; + Thread thread_; + DefinedModule* last_module_ = nullptr; + + // Parsing info. + std::vector<uint8_t> json_data_; + std::string source_filename_; + size_t json_offset_ = 0; + Location loc_; + Location prev_loc_; + bool has_prev_loc_ = false; + uint32_t command_line_number_ = 0; + + // Test info. + int passed_ = 0; + int total_ = 0; +}; + #define CHECK_RESULT(x) \ do { \ if (Failed(x)) \ return wabt::Result::Error; \ } while (0) -#define EXPECT(x) CHECK_RESULT(Expect(ctx, x)) -#define EXPECT_KEY(x) CHECK_RESULT(ExpectKey(ctx, x)) +#define EXPECT(x) CHECK_RESULT(Expect(x)) +#define EXPECT_KEY(x) CHECK_RESULT(ExpectKey(x)) #define PARSE_KEY_STRING_VALUE(key, value) \ - CHECK_RESULT(ParseKeyStringValue(ctx, key, value)) + CHECK_RESULT(ParseKeyStringValue(key, value)) + +wabt::Result SpecJSONParser::ReadFile(const char* spec_json_filename) { + loc_.filename = spec_json_filename; + loc_.line = 1; + loc_.first_column = 1; + InitEnvironment(&env_); + + return wabt::ReadFile(spec_json_filename, &json_data_); +} -static void WABT_PRINTF_FORMAT(2, 3) - PrintParseError(Context* ctx, const char* format, ...) { +void SpecJSONParser::PrintParseError(const char* format, ...) { WABT_SNPRINTF_ALLOCA(buffer, length, format); - fprintf(stderr, "%s:%d:%d: %s\n", ctx->loc.filename, ctx->loc.line, - ctx->loc.first_column, buffer); + fprintf(stderr, "%s:%d:%d: %s\n", loc_.filename, loc_.line, loc_.first_column, + buffer); } -static void WABT_PRINTF_FORMAT(2, 3) - PrintCommandError(Context* ctx, const char* format, ...) { +void SpecJSONParser::PrintCommandError(const char* format, ...) { WABT_SNPRINTF_ALLOCA(buffer, length, format); printf(PRIstringview ":%u: %s\n", - WABT_PRINTF_STRING_VIEW_ARG(ctx->source_filename), - ctx->command_line_number, buffer); + WABT_PRINTF_STRING_VIEW_ARG(source_filename_), command_line_number_, + buffer); } -static void PutbackChar(Context* ctx) { - assert(ctx->has_prev_loc); - ctx->json_offset--; - ctx->loc = ctx->prev_loc; - ctx->has_prev_loc = false; +void SpecJSONParser::PutbackChar() { + assert(has_prev_loc_); + json_offset_--; + loc_ = prev_loc_; + has_prev_loc_ = false; } -static int ReadChar(Context* ctx) { - if (ctx->json_offset >= ctx->json_data.size()) +int SpecJSONParser::ReadChar() { + if (json_offset_ >= json_data_.size()) return -1; - ctx->prev_loc = ctx->loc; - char c = ctx->json_data[ctx->json_offset++]; + prev_loc_ = loc_; + char c = json_data_[json_offset_++]; if (c == '\n') { - ctx->loc.line++; - ctx->loc.first_column = 1; + loc_.line++; + loc_.first_column = 1; } else { - ctx->loc.first_column++; + loc_.first_column++; } - ctx->has_prev_loc = true; + has_prev_loc_ = true; return c; } -static void SkipWhitespace(Context* ctx) { +void SpecJSONParser::SkipWhitespace() { while (1) { - switch (ReadChar(ctx)) { + switch (ReadChar()) { case -1: return; @@ -561,38 +625,38 @@ static void SkipWhitespace(Context* ctx) { break; default: - PutbackChar(ctx); + PutbackChar(); return; } } } -static bool Match(Context* ctx, const char* s) { - SkipWhitespace(ctx); - Location start_loc = ctx->loc; - size_t start_offset = ctx->json_offset; - while (*s && *s == ReadChar(ctx)) +bool SpecJSONParser::Match(const char* s) { + SkipWhitespace(); + Location start_loc = loc_; + size_t start_offset = json_offset_; + while (*s && *s == ReadChar()) s++; if (*s == 0) { return true; } else { - ctx->json_offset = start_offset; - ctx->loc = start_loc; + json_offset_ = start_offset; + loc_ = start_loc; return false; } } -static wabt::Result Expect(Context* ctx, const char* s) { - if (Match(ctx, s)) { +wabt::Result SpecJSONParser::Expect(const char* s) { + if (Match(s)) { return wabt::Result::Ok; } else { - PrintParseError(ctx, "expected %s", s); + PrintParseError("expected %s", s); return wabt::Result::Error; } } -static wabt::Result ExpectKey(Context* ctx, const char* key) { +wabt::Result SpecJSONParser::ExpectKey(const char* key) { size_t keylen = strlen(key); size_t quoted_len = keylen + 2 + 1; char* quoted = static_cast<char*>(alloca(quoted_len)); @@ -602,20 +666,20 @@ static wabt::Result ExpectKey(Context* ctx, const char* key) { return wabt::Result::Ok; } -static wabt::Result ParseUint32(Context* ctx, uint32_t* out_int) { +wabt::Result SpecJSONParser::ParseUint32(uint32_t* out_int) { uint32_t result = 0; - SkipWhitespace(ctx); + SkipWhitespace(); while (1) { - int c = ReadChar(ctx); + int c = ReadChar(); if (c >= '0' && c <= '9') { uint32_t last_result = result; result = result * 10 + static_cast<uint32_t>(c - '0'); if (result < last_result) { - PrintParseError(ctx, "uint32 overflow"); + PrintParseError("uint32 overflow"); return wabt::Result::Error; } } else { - PutbackChar(ctx); + PutbackChar(); break; } } @@ -623,29 +687,29 @@ static wabt::Result ParseUint32(Context* ctx, uint32_t* out_int) { return wabt::Result::Ok; } -static wabt::Result ParseString(Context* ctx, std::string* out_string) { +wabt::Result SpecJSONParser::ParseString(std::string* out_string) { out_string->clear(); - SkipWhitespace(ctx); - if (ReadChar(ctx) != '"') { - PrintParseError(ctx, "expected string"); + SkipWhitespace(); + if (ReadChar() != '"') { + PrintParseError("expected string"); return wabt::Result::Error; } while (1) { - int c = ReadChar(ctx); + int c = ReadChar(); if (c == '"') { break; } else if (c == '\\') { /* The only escape supported is \uxxxx. */ - c = ReadChar(ctx); + c = ReadChar(); if (c != 'u') { - PrintParseError(ctx, "expected escape: \\uxxxx"); + PrintParseError("expected escape: \\uxxxx"); return wabt::Result::Error; } uint16_t code = 0; for (int i = 0; i < 4; ++i) { - c = ReadChar(ctx); + c = ReadChar(); int cval; if (c >= '0' && c <= '9') { cval = c - '0'; @@ -654,7 +718,7 @@ static wabt::Result ParseString(Context* ctx, std::string* out_string) { } else if (c >= 'A' && c <= 'F') { cval = c - 'A' + 10; } else { - PrintParseError(ctx, "expected hex char"); + PrintParseError("expected hex char"); return wabt::Result::Error; } code = (code << 4) + cval; @@ -663,7 +727,7 @@ static wabt::Result ParseString(Context* ctx, std::string* out_string) { if (code < 256) { *out_string += code; } else { - PrintParseError(ctx, "only escape codes < 256 allowed, got %u\n", code); + PrintParseError("only escape codes < 256 allowed, got %u\n", code); } } else { *out_string += c; @@ -672,32 +736,30 @@ static wabt::Result ParseString(Context* ctx, std::string* out_string) { return wabt::Result::Ok; } -static wabt::Result ParseKeyStringValue(Context* ctx, - const char* key, - std::string* out_string) { +wabt::Result SpecJSONParser::ParseKeyStringValue(const char* key, + std::string* out_string) { out_string->clear(); EXPECT_KEY(key); - return ParseString(ctx, out_string); + return ParseString(out_string); } -static wabt::Result ParseOptNameStringValue(Context* ctx, - std::string* out_string) { +wabt::Result SpecJSONParser::ParseOptNameStringValue(std::string* out_string) { out_string->clear(); - if (Match(ctx, "\"name\"")) { + if (Match("\"name\"")) { EXPECT(":"); - CHECK_RESULT(ParseString(ctx, out_string)); + CHECK_RESULT(ParseString(out_string)); EXPECT(","); } return wabt::Result::Ok; } -static wabt::Result ParseLine(Context* ctx) { +wabt::Result SpecJSONParser::ParseLine() { EXPECT_KEY("line"); - CHECK_RESULT(ParseUint32(ctx, &ctx->command_line_number)); + CHECK_RESULT(ParseUint32(&command_line_number_)); return wabt::Result::Ok; } -static wabt::Result ParseTypeObject(Context* ctx, Type* out_type) { +wabt::Result SpecJSONParser::ParseTypeObject(Type* out_type) { std::string type_str; EXPECT("{"); PARSE_KEY_STRING_VALUE("type", &type_str); @@ -716,28 +778,28 @@ static wabt::Result ParseTypeObject(Context* ctx, Type* out_type) { *out_type = Type::F64; return wabt::Result::Ok; } else { - PrintParseError(ctx, "unknown type: \"" PRIstringview "\"", + PrintParseError("unknown type: \"" PRIstringview "\"", WABT_PRINTF_STRING_VIEW_ARG(type_str)); return wabt::Result::Error; } } -static wabt::Result ParseTypeVector(Context* ctx, TypeVector* out_types) { +wabt::Result SpecJSONParser::ParseTypeVector(TypeVector* out_types) { out_types->clear(); EXPECT("["); bool first = true; - while (!Match(ctx, "]")) { + while (!Match("]")) { if (!first) EXPECT(","); Type type; - CHECK_RESULT(ParseTypeObject(ctx, &type)); + CHECK_RESULT(ParseTypeObject(&type)); first = false; out_types->push_back(type); } return wabt::Result::Ok; } -static wabt::Result ParseConst(Context* ctx, TypedValue* out_value) { +wabt::Result SpecJSONParser::ParseConst(TypedValue* out_value) { std::string type_str; std::string value_str; EXPECT("{"); @@ -778,55 +840,55 @@ static wabt::Result ParseConst(Context* ctx, TypedValue* out_value) { out_value->value.f64_bits = value_bits; return wabt::Result::Ok; } else { - PrintParseError(ctx, "unknown type: \"" PRIstringview "\"", + PrintParseError("unknown type: \"" PRIstringview "\"", WABT_PRINTF_STRING_VIEW_ARG(type_str)); return wabt::Result::Error; } } -static wabt::Result ParseConstVector(Context* ctx, - std::vector<TypedValue>* out_values) { +wabt::Result SpecJSONParser::ParseConstVector( + std::vector<TypedValue>* out_values) { out_values->clear(); EXPECT("["); bool first = true; - while (!Match(ctx, "]")) { + while (!Match("]")) { if (!first) EXPECT(","); TypedValue value; - CHECK_RESULT(ParseConst(ctx, &value)); + CHECK_RESULT(ParseConst(&value)); out_values->push_back(value); first = false; } return wabt::Result::Ok; } -static wabt::Result ParseAction(Context* ctx, Action* out_action) { +wabt::Result SpecJSONParser::ParseAction(Action* out_action) { EXPECT_KEY("action"); EXPECT("{"); EXPECT_KEY("type"); - if (Match(ctx, "\"invoke\"")) { + if (Match("\"invoke\"")) { out_action->type = ActionType::Invoke; } else { EXPECT("\"get\""); out_action->type = ActionType::Get; } EXPECT(","); - if (Match(ctx, "\"module\"")) { + if (Match("\"module\"")) { EXPECT(":"); - CHECK_RESULT(ParseString(ctx, &out_action->module_name)); + CHECK_RESULT(ParseString(&out_action->module_name)); EXPECT(","); } PARSE_KEY_STRING_VALUE("field", &out_action->field_name); if (out_action->type == ActionType::Invoke) { EXPECT(","); EXPECT_KEY("args"); - CHECK_RESULT(ParseConstVector(ctx, &out_action->args)); + CHECK_RESULT(ParseConstVector(&out_action->args)); } EXPECT("}"); return wabt::Result::Ok; } -static wabt::Result ParseModuleType(Context* ctx, ModuleType* out_type) { +wabt::Result SpecJSONParser::ParseModuleType(ModuleType* out_type) { std::string module_type_str; PARSE_KEY_STRING_VALUE("module_type", &module_type_str); @@ -837,14 +899,14 @@ static wabt::Result ParseModuleType(Context* ctx, ModuleType* out_type) { *out_type = ModuleType::Binary; return wabt::Result::Ok; } else { - PrintParseError(ctx, "unknown module type: \"" PRIstringview "\"", + PrintParseError("unknown module type: \"" PRIstringview "\"", WABT_PRINTF_STRING_VIEW_ARG(module_type_str)); return wabt::Result::Error; } } -static std::string CreateModulePath(Context* ctx, string_view filename) { - const char* spec_json_filename = ctx->loc.filename; +std::string SpecJSONParser::CreateModulePath(string_view filename) { + const char* spec_json_filename = loc_.filename; string_view dirname = GetDirname(spec_json_filename); std::string path; @@ -860,55 +922,52 @@ static std::string CreateModulePath(Context* ctx, string_view filename) { return path; } -static wabt::Result OnModuleCommand(Context* ctx, - string_view filename, - string_view name) { - std::string path = CreateModulePath(ctx, filename); - Environment::MarkPoint mark = ctx->env.Mark(); +wabt::Result SpecJSONParser::OnModuleCommand(string_view filename, + string_view name) { + std::string path = CreateModulePath(filename); + Environment::MarkPoint mark = env_.Mark(); ErrorHandlerFile error_handler(Location::Type::Binary); wabt::Result result = - ReadModule(path.c_str(), &ctx->env, &error_handler, &ctx->last_module); + ReadModule(path.c_str(), &env_, &error_handler, &last_module_); if (Failed(result)) { - ctx->env.ResetToMarkPoint(mark); - PrintCommandError(ctx, "error reading module: \"%s\"", path.c_str()); + env_.ResetToMarkPoint(mark); + PrintCommandError("error reading module: \"%s\"", path.c_str()); return wabt::Result::Error; } - interpreter::Result iresult = - RunStartFunction(&ctx->thread, ctx->last_module); + interpreter::Result iresult = RunStartFunction(&thread_, last_module_); if (iresult != interpreter::Result::Ok) { - ctx->env.ResetToMarkPoint(mark); + env_.ResetToMarkPoint(mark); PrintInterpreterResult("error running start function", iresult); return wabt::Result::Error; } if (!name.empty()) { - ctx->last_module->name = name.to_string(); - ctx->env.EmplaceModuleBinding(name.to_string(), - Binding(ctx->env.GetModuleCount() - 1)); + last_module_->name = name.to_string(); + env_.EmplaceModuleBinding(name.to_string(), + Binding(env_.GetModuleCount() - 1)); } return wabt::Result::Ok; } -static wabt::Result RunAction(Context* ctx, - Action* action, - interpreter::Result* out_iresult, - std::vector<TypedValue>* out_results, - RunVerbosity verbose) { +wabt::Result SpecJSONParser::RunAction(Action* action, + interpreter::Result* out_iresult, + std::vector<TypedValue>* out_results, + RunVerbosity verbose) { out_results->clear(); Module* module; if (!action->module_name.empty()) { - module = ctx->env.FindModule(action->module_name); + module = env_.FindModule(action->module_name); } else { - module = ctx->env.GetLastModule(); + module = env_.GetLastModule(); } assert(module); switch (action->type) { case ActionType::Invoke: - *out_iresult = RunExportByName(&ctx->thread, module, action->field_name, + *out_iresult = RunExportByName(&thread_, module, action->field_name, action->args, out_results, verbose); if (verbose == RunVerbosity::Verbose) { PrintCall(string_view(), action->field_name, action->args, *out_results, @@ -917,30 +976,30 @@ static wabt::Result RunAction(Context* ctx, return wabt::Result::Ok; case ActionType::Get: { - *out_iresult = GetGlobalExportByName(&ctx->thread, module, - action->field_name, out_results); + *out_iresult = GetGlobalExportByName(&thread_, module, action->field_name, + out_results); return wabt::Result::Ok; } default: - PrintCommandError(ctx, "invalid action type %d", + PrintCommandError("invalid action type %d", static_cast<int>(action->type)); return wabt::Result::Error; } } -static wabt::Result OnActionCommand(Context* ctx, Action* action) { +wabt::Result SpecJSONParser::OnActionCommand(Action* action) { std::vector<TypedValue> results; interpreter::Result iresult; - ctx->total++; + total_++; wabt::Result result = - RunAction(ctx, action, &iresult, &results, RunVerbosity::Verbose); + RunAction(action, &iresult, &results, RunVerbosity::Verbose); if (Succeeded(result)) { if (iresult == interpreter::Result::Ok) { - ctx->passed++; + passed_++; } else { - PrintCommandError(ctx, "unexpected trap: %s", + PrintCommandError("unexpected trap: %s", s_trap_strings[static_cast<size_t>(iresult)]); result = wabt::Result::Error; } @@ -949,24 +1008,24 @@ static wabt::Result OnActionCommand(Context* ctx, Action* action) { return result; } -static wabt::Result ReadInvalidTextModule(const char* module_filename, - Environment* env, - ErrorHandler* error_handler) { +wabt::Result SpecJSONParser::ReadInvalidTextModule( + const char* module_filename, + Environment* env, + ErrorHandler* error_handler) { std::unique_ptr<WastLexer> lexer = WastLexer::CreateFileLexer(module_filename); wabt::Result result = ParseWast(lexer.get(), nullptr, error_handler); return result; } -static wabt::Result ReadInvalidModule(Context* ctx, - const char* module_filename, - Environment* env, - ModuleType module_type, - const char* desc) { +wabt::Result SpecJSONParser::ReadInvalidModule(const char* module_filename, + Environment* env, + ModuleType module_type, + const char* desc) { std::string header = StringPrintf(PRIstringview ":%d: %s passed", - WABT_PRINTF_STRING_VIEW_ARG(ctx->source_filename), - ctx->command_line_number, desc); + WABT_PRINTF_STRING_VIEW_ARG(source_filename_), + command_line_number_, desc); switch (module_type) { case ModuleType::Text: { @@ -987,123 +1046,115 @@ static wabt::Result ReadInvalidModule(Context* ctx, } } -static wabt::Result OnAssertMalformedCommand(Context* ctx, - string_view filename, - string_view text, - ModuleType module_type) { +wabt::Result SpecJSONParser::OnAssertMalformedCommand(string_view filename, + string_view text, + ModuleType module_type) { Environment env; InitEnvironment(&env); - ctx->total++; - std::string path = CreateModulePath(ctx, filename); - wabt::Result result = ReadInvalidModule(ctx, path.c_str(), &env, module_type, - "assert_malformed"); + total_++; + std::string path = CreateModulePath(filename); + wabt::Result result = + ReadInvalidModule(path.c_str(), &env, module_type, "assert_malformed"); if (Failed(result)) { - ctx->passed++; + passed_++; result = wabt::Result::Ok; } else { - PrintCommandError(ctx, "expected module to be malformed: \"%s\"", - path.c_str()); + PrintCommandError("expected module to be malformed: \"%s\"", path.c_str()); result = wabt::Result::Error; } return result; } -static wabt::Result OnRegisterCommand(Context* ctx, - string_view name, - string_view as) { +wabt::Result SpecJSONParser::OnRegisterCommand(string_view name, + string_view as) { Index module_index; if (!name.empty()) { - module_index = ctx->env.FindModuleIndex(name); + module_index = env_.FindModuleIndex(name); } else { - module_index = ctx->env.GetLastModuleIndex(); + module_index = env_.GetLastModuleIndex(); } if (module_index == kInvalidIndex) { - PrintCommandError(ctx, "unknown module in register"); + PrintCommandError("unknown module in register"); return wabt::Result::Error; } - ctx->env.EmplaceRegisteredModuleBinding(as.to_string(), - Binding(module_index)); + env_.EmplaceRegisteredModuleBinding(as.to_string(), Binding(module_index)); return wabt::Result::Ok; } -static wabt::Result OnAssertUnlinkableCommand(Context* ctx, - string_view filename, - string_view text, - ModuleType module_type) { - ctx->total++; - std::string path = CreateModulePath(ctx, filename); - Environment::MarkPoint mark = ctx->env.Mark(); - wabt::Result result = ReadInvalidModule(ctx, path.c_str(), &ctx->env, - module_type, "assert_unlinkable"); - ctx->env.ResetToMarkPoint(mark); +wabt::Result SpecJSONParser::OnAssertUnlinkableCommand(string_view filename, + string_view text, + ModuleType module_type) { + total_++; + std::string path = CreateModulePath(filename); + Environment::MarkPoint mark = env_.Mark(); + wabt::Result result = + ReadInvalidModule(path.c_str(), &env_, module_type, "assert_unlinkable"); + env_.ResetToMarkPoint(mark); if (Failed(result)) { - ctx->passed++; + passed_++; result = wabt::Result::Ok; } else { - PrintCommandError(ctx, "expected module to be unlinkable: \"%s\"", - path.c_str()); + PrintCommandError("expected module to be unlinkable: \"%s\"", path.c_str()); result = wabt::Result::Error; } return result; } -static wabt::Result OnAssertInvalidCommand(Context* ctx, - string_view filename, - string_view text, - ModuleType module_type) { +wabt::Result SpecJSONParser::OnAssertInvalidCommand(string_view filename, + string_view text, + ModuleType module_type) { Environment env; InitEnvironment(&env); - ctx->total++; - std::string path = CreateModulePath(ctx, filename); + total_++; + std::string path = CreateModulePath(filename); wabt::Result result = - ReadInvalidModule(ctx, path.c_str(), &env, module_type, "assert_invalid"); + ReadInvalidModule(path.c_str(), &env, module_type, "assert_invalid"); if (Failed(result)) { - ctx->passed++; + passed_++; result = wabt::Result::Ok; } else { - PrintCommandError(ctx, "expected module to be invalid: \"%s\"", - path.c_str()); + PrintCommandError("expected module to be invalid: \"%s\"", path.c_str()); result = wabt::Result::Error; } return result; } -static wabt::Result OnAssertUninstantiableCommand(Context* ctx, - string_view filename, - string_view text, - ModuleType module_type) { +wabt::Result SpecJSONParser::OnAssertUninstantiableCommand( + string_view filename, + string_view text, + ModuleType module_type) { ErrorHandlerFile error_handler(Location::Type::Binary); - ctx->total++; - std::string path = CreateModulePath(ctx, filename); + total_++; + std::string path = CreateModulePath(filename); DefinedModule* module; - Environment::MarkPoint mark = ctx->env.Mark(); + Environment::MarkPoint mark = env_.Mark(); wabt::Result result = - ReadModule(path.c_str(), &ctx->env, &error_handler, &module); + ReadModule(path.c_str(), &env_, &error_handler, &module); if (Succeeded(result)) { - interpreter::Result iresult = RunStartFunction(&ctx->thread, module); + interpreter::Result iresult = RunStartFunction(&thread_, module); if (iresult == interpreter::Result::Ok) { - PrintCommandError(ctx, "expected error running start function: \"%s\"", + PrintCommandError("expected error running start function: \"%s\"", path.c_str()); result = wabt::Result::Error; } else { - ctx->passed++; + passed_++; result = wabt::Result::Ok; } } else { - PrintCommandError(ctx, "error reading module: \"%s\"", path.c_str()); + PrintCommandError("error reading module: \"%s\"", path.c_str()); result = wabt::Result::Error; } - ctx->env.ResetToMarkPoint(mark); + env_.ResetToMarkPoint(mark); return result; } @@ -1126,16 +1177,15 @@ static bool TypedValuesAreEqual(const TypedValue* tv1, const TypedValue* tv2) { } } -static wabt::Result OnAssertReturnCommand( - Context* ctx, +wabt::Result SpecJSONParser::OnAssertReturnCommand( Action* action, const std::vector<TypedValue>& expected) { std::vector<TypedValue> results; interpreter::Result iresult; - ctx->total++; + total_++; wabt::Result result = - RunAction(ctx, action, &iresult, &results, RunVerbosity::Quiet); + RunAction(action, &iresult, &results, RunVerbosity::Quiet); if (Succeeded(result)) { if (iresult == interpreter::Result::Ok) { @@ -1148,8 +1198,7 @@ static wabt::Result OnAssertReturnCommand( char actual_str[MAX_TYPED_VALUE_CHARS]; SPrintTypedValue(expected_str, sizeof(expected_str), expected_tv); SPrintTypedValue(actual_str, sizeof(actual_str), actual_tv); - PrintCommandError(ctx, - "mismatch in result %" PRIzd + PrintCommandError("mismatch in result %" PRIzd " of assert_return: expected %s, got %s", i, expected_str, actual_str); result = wabt::Result::Error; @@ -1157,39 +1206,36 @@ static wabt::Result OnAssertReturnCommand( } } else { PrintCommandError( - ctx, "result length mismatch in assert_return: expected %" PRIzd ", got %" PRIzd, expected.size(), results.size()); result = wabt::Result::Error; } } else { - PrintCommandError(ctx, "unexpected trap: %s", + PrintCommandError("unexpected trap: %s", s_trap_strings[static_cast<size_t>(iresult)]); result = wabt::Result::Error; } } if (Succeeded(result)) - ctx->passed++; + passed_++; return result; } -static wabt::Result OnAssertReturnNanCommand(Context* ctx, - Action* action, - bool canonical) { +wabt::Result SpecJSONParser::OnAssertReturnNanCommand(Action* action, + bool canonical) { std::vector<TypedValue> results; interpreter::Result iresult; - ctx->total++; + total_++; wabt::Result result = - RunAction(ctx, action, &iresult, &results, RunVerbosity::Quiet); + RunAction(action, &iresult, &results, RunVerbosity::Quiet); if (Succeeded(result)) { if (iresult == interpreter::Result::Ok) { if (results.size() != 1) { - PrintCommandError(ctx, "expected one result, got %" PRIzd, - results.size()); + PrintCommandError("expected one result, got %" PRIzd, results.size()); result = wabt::Result::Error; } @@ -1201,8 +1247,7 @@ static wabt::Result OnAssertReturnNanCommand(Context* ctx, if (!is_nan) { char actual_str[MAX_TYPED_VALUE_CHARS]; SPrintTypedValue(actual_str, sizeof(actual_str), &actual); - PrintCommandError(ctx, "expected result to be nan, got %s", - actual_str); + PrintCommandError("expected result to be nan, got %s", actual_str); result = wabt::Result::Error; } break; @@ -1214,47 +1259,44 @@ static wabt::Result OnAssertReturnNanCommand(Context* ctx, if (!is_nan) { char actual_str[MAX_TYPED_VALUE_CHARS]; SPrintTypedValue(actual_str, sizeof(actual_str), &actual); - PrintCommandError(ctx, "expected result to be nan, got %s", - actual_str); + PrintCommandError("expected result to be nan, got %s", actual_str); result = wabt::Result::Error; } break; } default: - PrintCommandError(ctx, - "expected result type to be f32 or f64, got %s", + PrintCommandError("expected result type to be f32 or f64, got %s", GetTypeName(actual.type)); result = wabt::Result::Error; break; } } else { - PrintCommandError(ctx, "unexpected trap: %s", + PrintCommandError("unexpected trap: %s", s_trap_strings[static_cast<int>(iresult)]); result = wabt::Result::Error; } } if (Succeeded(result)) - ctx->passed++; + passed_++; return wabt::Result::Ok; } -static wabt::Result OnAssertTrapCommand(Context* ctx, - Action* action, - string_view text) { +wabt::Result SpecJSONParser::OnAssertTrapCommand(Action* action, + string_view text) { std::vector<TypedValue> results; interpreter::Result iresult; - ctx->total++; + total_++; wabt::Result result = - RunAction(ctx, action, &iresult, &results, RunVerbosity::Quiet); + RunAction(action, &iresult, &results, RunVerbosity::Quiet); if (Succeeded(result)) { if (iresult != interpreter::Result::Ok) { - ctx->passed++; + passed_++; } else { - PrintCommandError(ctx, "expected trap: \"" PRIstringview "\"", + PrintCommandError("expected trap: \"" PRIstringview "\"", WABT_PRINTF_STRING_VIEW_ARG(text)); result = wabt::Result::Error; } @@ -1263,19 +1305,19 @@ static wabt::Result OnAssertTrapCommand(Context* ctx, return result; } -static wabt::Result OnAssertExhaustionCommand(Context* ctx, Action* action) { +wabt::Result SpecJSONParser::OnAssertExhaustionCommand(Action* action) { std::vector<TypedValue> results; interpreter::Result iresult; - ctx->total++; + total_++; wabt::Result result = - RunAction(ctx, action, &iresult, &results, RunVerbosity::Quiet); + RunAction(action, &iresult, &results, RunVerbosity::Quiet); if (Succeeded(result)) { if (iresult == interpreter::Result::TrapCallStackExhausted || iresult == interpreter::Result::TrapValueStackExhausted) { - ctx->passed++; + passed_++; } else { - PrintCommandError(ctx, "expected call stack exhaustion"); + PrintCommandError("expected call stack exhaustion"); result = wabt::Result::Error; } } @@ -1283,189 +1325,181 @@ static wabt::Result OnAssertExhaustionCommand(Context* ctx, Action* action) { return result; } -static wabt::Result ParseCommand(Context* ctx) { +wabt::Result SpecJSONParser::ParseCommand() { EXPECT("{"); EXPECT_KEY("type"); - if (Match(ctx, "\"module\"")) { + if (Match("\"module\"")) { std::string name; std::string filename; EXPECT(","); - CHECK_RESULT(ParseLine(ctx)); + CHECK_RESULT(ParseLine()); EXPECT(","); - CHECK_RESULT(ParseOptNameStringValue(ctx, &name)); + CHECK_RESULT(ParseOptNameStringValue(&name)); PARSE_KEY_STRING_VALUE("filename", &filename); - OnModuleCommand(ctx, filename, name); - } else if (Match(ctx, "\"action\"")) { + OnModuleCommand(filename, name); + } else if (Match("\"action\"")) { Action action; EXPECT(","); - CHECK_RESULT(ParseLine(ctx)); + CHECK_RESULT(ParseLine()); EXPECT(","); - CHECK_RESULT(ParseAction(ctx, &action)); - OnActionCommand(ctx, &action); - } else if (Match(ctx, "\"register\"")) { + CHECK_RESULT(ParseAction(&action)); + OnActionCommand(&action); + } else if (Match("\"register\"")) { std::string as; std::string name; EXPECT(","); - CHECK_RESULT(ParseLine(ctx)); + CHECK_RESULT(ParseLine()); EXPECT(","); - CHECK_RESULT(ParseOptNameStringValue(ctx, &name)); + CHECK_RESULT(ParseOptNameStringValue(&name)); PARSE_KEY_STRING_VALUE("as", &as); - OnRegisterCommand(ctx, name, as); - } else if (Match(ctx, "\"assert_malformed\"")) { + OnRegisterCommand(name, as); + } else if (Match("\"assert_malformed\"")) { std::string filename; std::string text; ModuleType module_type; EXPECT(","); - CHECK_RESULT(ParseLine(ctx)); + CHECK_RESULT(ParseLine()); EXPECT(","); PARSE_KEY_STRING_VALUE("filename", &filename); EXPECT(","); PARSE_KEY_STRING_VALUE("text", &text); EXPECT(","); - CHECK_RESULT(ParseModuleType(ctx, &module_type)); - OnAssertMalformedCommand(ctx, filename, text, module_type); - } else if (Match(ctx, "\"assert_invalid\"")) { + CHECK_RESULT(ParseModuleType(&module_type)); + OnAssertMalformedCommand(filename, text, module_type); + } else if (Match("\"assert_invalid\"")) { std::string filename; std::string text; ModuleType module_type; EXPECT(","); - CHECK_RESULT(ParseLine(ctx)); + CHECK_RESULT(ParseLine()); EXPECT(","); PARSE_KEY_STRING_VALUE("filename", &filename); EXPECT(","); PARSE_KEY_STRING_VALUE("text", &text); EXPECT(","); - CHECK_RESULT(ParseModuleType(ctx, &module_type)); - OnAssertInvalidCommand(ctx, filename, text, module_type); - } else if (Match(ctx, "\"assert_unlinkable\"")) { + CHECK_RESULT(ParseModuleType(&module_type)); + OnAssertInvalidCommand(filename, text, module_type); + } else if (Match("\"assert_unlinkable\"")) { std::string filename; std::string text; ModuleType module_type; EXPECT(","); - CHECK_RESULT(ParseLine(ctx)); + CHECK_RESULT(ParseLine()); EXPECT(","); PARSE_KEY_STRING_VALUE("filename", &filename); EXPECT(","); PARSE_KEY_STRING_VALUE("text", &text); EXPECT(","); - CHECK_RESULT(ParseModuleType(ctx, &module_type)); - OnAssertUnlinkableCommand(ctx, filename, text, module_type); - } else if (Match(ctx, "\"assert_uninstantiable\"")) { + CHECK_RESULT(ParseModuleType(&module_type)); + OnAssertUnlinkableCommand(filename, text, module_type); + } else if (Match("\"assert_uninstantiable\"")) { std::string filename; std::string text; ModuleType module_type; EXPECT(","); - CHECK_RESULT(ParseLine(ctx)); + CHECK_RESULT(ParseLine()); EXPECT(","); PARSE_KEY_STRING_VALUE("filename", &filename); EXPECT(","); PARSE_KEY_STRING_VALUE("text", &text); EXPECT(","); - CHECK_RESULT(ParseModuleType(ctx, &module_type)); - OnAssertUninstantiableCommand(ctx, filename, text, module_type); - } else if (Match(ctx, "\"assert_return\"")) { + CHECK_RESULT(ParseModuleType(&module_type)); + OnAssertUninstantiableCommand(filename, text, module_type); + } else if (Match("\"assert_return\"")) { Action action; std::vector<TypedValue> expected; EXPECT(","); - CHECK_RESULT(ParseLine(ctx)); + CHECK_RESULT(ParseLine()); EXPECT(","); - CHECK_RESULT(ParseAction(ctx, &action)); + CHECK_RESULT(ParseAction(&action)); EXPECT(","); EXPECT_KEY("expected"); - CHECK_RESULT(ParseConstVector(ctx, &expected)); - OnAssertReturnCommand(ctx, &action, expected); - } else if (Match(ctx, "\"assert_return_canonical_nan\"")) { + CHECK_RESULT(ParseConstVector(&expected)); + OnAssertReturnCommand(&action, expected); + } else if (Match("\"assert_return_canonical_nan\"")) { Action action; TypeVector expected; EXPECT(","); - CHECK_RESULT(ParseLine(ctx)); + CHECK_RESULT(ParseLine()); EXPECT(","); - CHECK_RESULT(ParseAction(ctx, &action)); + CHECK_RESULT(ParseAction(&action)); EXPECT(","); /* Not needed for wabt-interp, but useful for other parsers. */ EXPECT_KEY("expected"); - CHECK_RESULT(ParseTypeVector(ctx, &expected)); - OnAssertReturnNanCommand(ctx, &action, true); - } else if (Match(ctx, "\"assert_return_arithmetic_nan\"")) { + CHECK_RESULT(ParseTypeVector(&expected)); + OnAssertReturnNanCommand(&action, true); + } else if (Match("\"assert_return_arithmetic_nan\"")) { Action action; TypeVector expected; EXPECT(","); - CHECK_RESULT(ParseLine(ctx)); + CHECK_RESULT(ParseLine()); EXPECT(","); - CHECK_RESULT(ParseAction(ctx, &action)); + CHECK_RESULT(ParseAction(&action)); EXPECT(","); /* Not needed for wabt-interp, but useful for other parsers. */ EXPECT_KEY("expected"); - CHECK_RESULT(ParseTypeVector(ctx, &expected)); - OnAssertReturnNanCommand(ctx, &action, false); - } else if (Match(ctx, "\"assert_trap\"")) { + CHECK_RESULT(ParseTypeVector(&expected)); + OnAssertReturnNanCommand(&action, false); + } else if (Match("\"assert_trap\"")) { Action action; std::string text; EXPECT(","); - CHECK_RESULT(ParseLine(ctx)); + CHECK_RESULT(ParseLine()); EXPECT(","); - CHECK_RESULT(ParseAction(ctx, &action)); + CHECK_RESULT(ParseAction(&action)); EXPECT(","); PARSE_KEY_STRING_VALUE("text", &text); - OnAssertTrapCommand(ctx, &action, text); - } else if (Match(ctx, "\"assert_exhaustion\"")) { + OnAssertTrapCommand(&action, text); + } else if (Match("\"assert_exhaustion\"")) { Action action; std::string text; EXPECT(","); - CHECK_RESULT(ParseLine(ctx)); + CHECK_RESULT(ParseLine()); EXPECT(","); - CHECK_RESULT(ParseAction(ctx, &action)); - OnAssertExhaustionCommand(ctx, &action); + CHECK_RESULT(ParseAction(&action)); + OnAssertExhaustionCommand(&action); } else { - PrintCommandError(ctx, "unknown command type"); + PrintCommandError("unknown command type"); return wabt::Result::Error; } EXPECT("}"); return wabt::Result::Ok; } -static wabt::Result ParseCommands(Context* ctx) { +wabt::Result SpecJSONParser::ParseCommands() { EXPECT("{"); - PARSE_KEY_STRING_VALUE("source_filename", &ctx->source_filename); + PARSE_KEY_STRING_VALUE("source_filename", &source_filename_); EXPECT(","); EXPECT_KEY("commands"); EXPECT("["); bool first = true; - while (!Match(ctx, "]")) { + while (!Match("]")) { if (!first) EXPECT(","); - CHECK_RESULT(ParseCommand(ctx)); + CHECK_RESULT(ParseCommand()); first = false; } EXPECT("}"); return wabt::Result::Ok; } -static wabt::Result ReadAndRunSpecJson(const char* spec_json_filename) { - Context ctx; - ctx.loc.filename = spec_json_filename; - ctx.loc.line = 1; - ctx.loc.first_column = 1; - InitEnvironment(&ctx.env); - - wabt::Result result = ReadFile(spec_json_filename, &ctx.json_data); - if (Failed(result)) - return wabt::Result::Error; - - result = ParseCommands(&ctx); - printf("%d/%d tests passed.\n", ctx.passed, ctx.total); +static wabt::Result ReadAndRunSpecJSON(const char* spec_json_filename) { + SpecJSONParser parser; + CHECK_RESULT(parser.ReadFile(spec_json_filename)); + wabt::Result result = parser.ParseCommands(); + printf("%d/%d tests passed.\n", parser.passed(), parser.total()); return result; } @@ -1477,7 +1511,7 @@ int ProgramMain(int argc, char** argv) { wabt::Result result; if (s_spec) { - result = ReadAndRunSpecJson(s_infile); + result = ReadAndRunSpecJSON(s_infile); } else { result = ReadAndRunModule(s_infile); } |