diff options
Diffstat (limited to 'src/binary-writer-spec.cc')
-rw-r--r-- | src/binary-writer-spec.cc | 456 |
1 files changed, 237 insertions, 219 deletions
diff --git a/src/binary-writer-spec.cc b/src/binary-writer-spec.cc index d4b7f20d..171b40e3 100644 --- a/src/binary-writer-spec.cc +++ b/src/binary-writer-spec.cc @@ -28,27 +28,6 @@ namespace wabt { -namespace { - -struct Context { - Context(); - - MemoryStream json_stream; - StringSlice source_filename; - StringSlice module_filename_noext; - bool write_modules = false; /* Whether to write the modules files. */ - const WriteBinarySpecOptions* spec_options; - Result result = Result::Ok; - size_t num_modules = 0; -}; - -Context::Context() { - WABT_ZERO_MEMORY(source_filename); - WABT_ZERO_MEMORY(module_filename_noext); -} - -} // namespace - static void convert_backslash_to_slash(char* s, size_t length) { for (size_t i = 0; i < length; ++i) if (s[i] == '\\') @@ -105,43 +84,90 @@ static StringSlice get_basename(const char* s) { return result; } -static char* get_module_filename(Context* ctx) { - size_t buflen = ctx->module_filename_noext.length + 20; +namespace { + +class BinaryWriterSpec { + public: + BinaryWriterSpec(const char* source_filename, + const WriteBinarySpecOptions* spec_options); + + Result WriteScript(Script* script); + + private: + char* GetModuleFilename(); + void WriteString(const char* s); + void WriteKey(const char* key); + void WriteSeparator(); + void WriteEscapedStringSlice(StringSlice ss); + void WriteCommandType(const Command& command); + void WriteLocation(const Location* loc); + void WriteVar(const Var* var); + void WriteTypeObject(Type type); + void WriteConst(const Const* const_); + void WriteConstVector(const ConstVector& consts); + void WriteAction(const Action* action); + void WriteActionResultType(Script* script, const Action* action); + void WriteModule(char* filename, const Module* module); + void WriteRawModule(char* filename, const RawModule* raw_module); + void WriteInvalidModule(const RawModule* module, StringSlice text); + void WriteCommands(Script* script); + + MemoryStream json_stream_; + StringSlice source_filename_; + StringSlice module_filename_noext_; + bool write_modules_ = false; /* Whether to write the modules files. */ + const WriteBinarySpecOptions* spec_options_ = nullptr; + Result result_ = Result::Ok; + size_t num_modules_ = 0; +}; + +BinaryWriterSpec::BinaryWriterSpec(const char* source_filename, + const WriteBinarySpecOptions* spec_options) + : spec_options_(spec_options) { + source_filename_.start = source_filename; + source_filename_.length = strlen(source_filename); + module_filename_noext_ = strip_extension(spec_options_->json_filename + ? spec_options_->json_filename + : source_filename); + write_modules_ = !!spec_options_->json_filename; +} + +char* BinaryWriterSpec::GetModuleFilename() { + size_t buflen = module_filename_noext_.length + 20; char* str = new char[buflen]; - size_t length = - wabt_snprintf(str, buflen, PRIstringslice ".%" PRIzd ".wasm", - WABT_PRINTF_STRING_SLICE_ARG(ctx->module_filename_noext), - ctx->num_modules); + size_t length = wabt_snprintf( + str, buflen, PRIstringslice ".%" PRIzd ".wasm", + WABT_PRINTF_STRING_SLICE_ARG(module_filename_noext_), num_modules_); convert_backslash_to_slash(str, length); return str; } -static void write_string(Context* ctx, const char* s) { - ctx->json_stream.Writef("\"%s\"", s); +void BinaryWriterSpec::WriteString(const char* s) { + json_stream_.Writef("\"%s\"", s); } -static void write_key(Context* ctx, const char* key) { - ctx->json_stream.Writef("\"%s\": ", key); +void BinaryWriterSpec::WriteKey(const char* key) { + json_stream_.Writef("\"%s\": ", key); } -static void write_separator(Context* ctx) { - ctx->json_stream.Writef(", "); +void BinaryWriterSpec::WriteSeparator() { + json_stream_.Writef(", "); } -static void write_escaped_string_slice(Context* ctx, StringSlice ss) { - ctx->json_stream.WriteChar('"'); +void BinaryWriterSpec::WriteEscapedStringSlice(StringSlice ss) { + json_stream_.WriteChar('"'); for (size_t i = 0; i < ss.length; ++i) { uint8_t c = ss.start[i]; if (c < 0x20 || c == '\\' || c == '"') { - ctx->json_stream.Writef("\\u%04x", c); + json_stream_.Writef("\\u%04x", c); } else { - ctx->json_stream.WriteChar(c); + json_stream_.WriteChar(c); } } - ctx->json_stream.WriteChar('"'); + json_stream_.WriteChar('"'); } -static void write_command_type(Context* ctx, const Command& command) { +void BinaryWriterSpec::WriteCommandType(const Command& command) { static const char* s_command_names[] = { "module", "action", @@ -160,66 +186,66 @@ static void write_command_type(Context* ctx, const Command& command) { }; WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(s_command_names) == kCommandTypeCount); - write_key(ctx, "type"); + WriteKey("type"); assert(s_command_names[static_cast<size_t>(command.type)]); - write_string(ctx, s_command_names[static_cast<size_t>(command.type)]); + WriteString(s_command_names[static_cast<size_t>(command.type)]); } -static void write_location(Context* ctx, const Location* loc) { - write_key(ctx, "line"); - ctx->json_stream.Writef("%d", loc->line); +void BinaryWriterSpec::WriteLocation(const Location* loc) { + WriteKey("line"); + json_stream_.Writef("%d", loc->line); } -static void write_var(Context* ctx, const Var* var) { +void BinaryWriterSpec::WriteVar(const Var* var) { if (var->type == VarType::Index) - ctx->json_stream.Writef("\"%" PRIu64 "\"", var->index); + json_stream_.Writef("\"%" PRIu64 "\"", var->index); else - write_escaped_string_slice(ctx, var->name); + WriteEscapedStringSlice(var->name); } -static void write_type_object(Context* ctx, Type type) { - ctx->json_stream.Writef("{"); - write_key(ctx, "type"); - write_string(ctx, get_type_name(type)); - ctx->json_stream.Writef("}"); +void BinaryWriterSpec::WriteTypeObject(Type type) { + json_stream_.Writef("{"); + WriteKey("type"); + WriteString(get_type_name(type)); + json_stream_.Writef("}"); } -static void write_const(Context* ctx, const Const* const_) { - ctx->json_stream.Writef("{"); - write_key(ctx, "type"); +void BinaryWriterSpec::WriteConst(const Const* const_) { + json_stream_.Writef("{"); + WriteKey("type"); /* Always write the values as strings, even though they may be representable * as JSON numbers. This way the formatting is consistent. */ switch (const_->type) { case Type::I32: - write_string(ctx, "i32"); - write_separator(ctx); - write_key(ctx, "value"); - ctx->json_stream.Writef("\"%u\"", const_->u32); + WriteString("i32"); + WriteSeparator(); + WriteKey("value"); + json_stream_.Writef("\"%u\"", const_->u32); break; case Type::I64: - write_string(ctx, "i64"); - write_separator(ctx); - write_key(ctx, "value"); - ctx->json_stream.Writef("\"%" PRIu64 "\"", const_->u64); + WriteString("i64"); + WriteSeparator(); + WriteKey("value"); + json_stream_.Writef("\"%" PRIu64 "\"", const_->u64); break; case Type::F32: { /* TODO(binji): write as hex float */ - write_string(ctx, "f32"); - write_separator(ctx); - write_key(ctx, "value"); - ctx->json_stream.Writef("\"%u\"", const_->f32_bits); + WriteString("f32"); + WriteSeparator(); + WriteKey("value"); + json_stream_.Writef("\"%u\"", const_->f32_bits); break; } case Type::F64: { /* TODO(binji): write as hex float */ - write_string(ctx, "f64"); - write_separator(ctx); - write_key(ctx, "value"); - ctx->json_stream.Writef("\"%" PRIu64 "\"", const_->f64_bits); + WriteString("f64"); + WriteSeparator(); + WriteKey("value"); + json_stream_.Writef("\"%" PRIu64 "\"", const_->f64_bits); break; } @@ -227,55 +253,54 @@ static void write_const(Context* ctx, const Const* const_) { assert(0); } - ctx->json_stream.Writef("}"); + json_stream_.Writef("}"); } -static void write_const_vector(Context* ctx, const ConstVector& consts) { - ctx->json_stream.Writef("["); +void BinaryWriterSpec::WriteConstVector(const ConstVector& consts) { + json_stream_.Writef("["); for (size_t i = 0; i < consts.size(); ++i) { const Const* const_ = &consts[i]; - write_const(ctx, const_); + WriteConst(const_); if (i != consts.size() - 1) - write_separator(ctx); + WriteSeparator(); } - ctx->json_stream.Writef("]"); + json_stream_.Writef("]"); } -static void write_action(Context* ctx, const Action* action) { - write_key(ctx, "action"); - ctx->json_stream.Writef("{"); - write_key(ctx, "type"); +void BinaryWriterSpec::WriteAction(const Action* action) { + WriteKey("action"); + json_stream_.Writef("{"); + WriteKey("type"); if (action->type == ActionType::Invoke) { - write_string(ctx, "invoke"); + WriteString("invoke"); } else { assert(action->type == ActionType::Get); - write_string(ctx, "get"); + WriteString("get"); } - write_separator(ctx); + WriteSeparator(); if (action->module_var.type != VarType::Index) { - write_key(ctx, "module"); - write_var(ctx, &action->module_var); - write_separator(ctx); + WriteKey("module"); + WriteVar(&action->module_var); + WriteSeparator(); } if (action->type == ActionType::Invoke) { - write_key(ctx, "field"); - write_escaped_string_slice(ctx, action->name); - write_separator(ctx); - write_key(ctx, "args"); - write_const_vector(ctx, action->invoke->args); + WriteKey("field"); + WriteEscapedStringSlice(action->name); + WriteSeparator(); + WriteKey("args"); + WriteConstVector(action->invoke->args); } else { - write_key(ctx, "field"); - write_escaped_string_slice(ctx, action->name); + WriteKey("field"); + WriteEscapedStringSlice(action->name); } - ctx->json_stream.Writef("}"); + json_stream_.Writef("}"); } -static void write_action_result_type(Context* ctx, - Script* script, - const Action* action) { +void BinaryWriterSpec::WriteActionResultType(Script* script, + const Action* action) { const Module* module = get_module_by_var(script, &action->module_var); const Export* export_; - ctx->json_stream.Writef("["); + json_stream_.Writef("["); switch (action->type) { case ActionType::Invoke: { export_ = get_export_by_name(module, &action->name); @@ -283,7 +308,7 @@ static void write_action_result_type(Context* ctx, Func* func = get_func_by_var(module, &export_->var); size_t num_results = get_num_results(func); for (size_t i = 0; i < num_results; ++i) - write_type_object(ctx, get_result_type(func, i)); + WriteTypeObject(get_result_type(func, i)); break; } @@ -291,58 +316,55 @@ static void write_action_result_type(Context* ctx, export_ = get_export_by_name(module, &action->name); assert(export_->kind == ExternalKind::Global); Global* global = get_global_by_var(module, &export_->var); - write_type_object(ctx, global->type); + WriteTypeObject(global->type); break; } } - ctx->json_stream.Writef("]"); + json_stream_.Writef("]"); } -static void write_module(Context* ctx, char* filename, const Module* module) { - MemoryWriter writer; - WriteBinaryOptions options = ctx->spec_options->write_binary_options; - Result result = write_binary_module(&writer, module, &options); - if (WABT_SUCCEEDED(result) && ctx->write_modules) - result = writer.output_buffer().WriteToFile(filename); - - ctx->result = result; +void BinaryWriterSpec::WriteModule(char* filename, const Module* module) { + MemoryStream memory_stream; + result_ = write_binary_module(&memory_stream.writer(), module, + &spec_options_->write_binary_options); + if (WABT_SUCCEEDED(result_) && write_modules_) + result_ = memory_stream.WriteToFile(filename); } -static void write_raw_module(Context* ctx, - char* filename, - const RawModule* raw_module) { +void BinaryWriterSpec::WriteRawModule(char* filename, + const RawModule* raw_module) { if (raw_module->type == RawModuleType::Text) { - write_module(ctx, filename, raw_module->text); - } else if (ctx->write_modules) { - FileStream stream(filename); - if (stream.is_open()) { - stream.WriteData(raw_module->binary.data, raw_module->binary.size); - ctx->result = stream.result(); + WriteModule(filename, raw_module->text); + } else if (write_modules_) { + FileStream file_stream(filename); + if (file_stream.is_open()) { + file_stream.WriteData(raw_module->binary.data, raw_module->binary.size, + ""); + result_ = file_stream.result(); } else { - ctx->result = Result::Error; + result_ = Result::Error; } } } -static void write_invalid_module(Context* ctx, - const RawModule* module, - StringSlice text) { - char* filename = get_module_filename(ctx); - write_location(ctx, get_raw_module_location(module)); - write_separator(ctx); - write_key(ctx, "filename"); - write_escaped_string_slice(ctx, get_basename(filename)); - write_separator(ctx); - write_key(ctx, "text"); - write_escaped_string_slice(ctx, text); - write_raw_module(ctx, filename, module); +void BinaryWriterSpec::WriteInvalidModule(const RawModule* module, + StringSlice text) { + char* filename = GetModuleFilename(); + WriteLocation(get_raw_module_location(module)); + WriteSeparator(); + WriteKey("filename"); + WriteEscapedStringSlice(get_basename(filename)); + WriteSeparator(); + WriteKey("text"); + WriteEscapedStringSlice(text); + WriteRawModule(filename, module); delete [] filename; } -static void write_commands(Context* ctx, Script* script) { - ctx->json_stream.Writef("{\"source_filename\": "); - write_escaped_string_slice(ctx, ctx->source_filename); - ctx->json_stream.Writef(",\n \"commands\": [\n"); +void BinaryWriterSpec::WriteCommands(Script* script) { + json_stream_.Writef("{\"source_filename\": "); + WriteEscapedStringSlice(source_filename_); + json_stream_.Writef(",\n \"commands\": [\n"); int last_module_index = -1; for (size_t i = 0; i < script->commands.size(); ++i) { const Command& command = *script->commands[i].get(); @@ -351,122 +373,122 @@ static void write_commands(Context* ctx, Script* script) { continue; if (i != 0) - write_separator(ctx); - ctx->json_stream.Writef("\n"); + WriteSeparator(); + json_stream_.Writef("\n"); - ctx->json_stream.Writef(" {"); - write_command_type(ctx, command); - write_separator(ctx); + json_stream_.Writef(" {"); + WriteCommandType(command); + WriteSeparator(); switch (command.type) { case CommandType::Module: { Module* module = command.module; - char* filename = get_module_filename(ctx); - write_location(ctx, &module->loc); - write_separator(ctx); + char* filename = GetModuleFilename(); + WriteLocation(&module->loc); + WriteSeparator(); if (module->name.start) { - write_key(ctx, "name"); - write_escaped_string_slice(ctx, module->name); - write_separator(ctx); + WriteKey("name"); + WriteEscapedStringSlice(module->name); + WriteSeparator(); } - write_key(ctx, "filename"); - write_escaped_string_slice(ctx, get_basename(filename)); - write_module(ctx, filename, module); + WriteKey("filename"); + WriteEscapedStringSlice(get_basename(filename)); + WriteModule(filename, module); delete [] filename; - ctx->num_modules++; + num_modules_++; last_module_index = static_cast<int>(i); break; } case CommandType::Action: - write_location(ctx, &command.action->loc); - write_separator(ctx); - write_action(ctx, command.action); + WriteLocation(&command.action->loc); + WriteSeparator(); + WriteAction(command.action); break; case CommandType::Register: - write_location(ctx, &command.register_.var.loc); - write_separator(ctx); + WriteLocation(&command.register_.var.loc); + WriteSeparator(); if (command.register_.var.type == VarType::Name) { - write_key(ctx, "name"); - write_var(ctx, &command.register_.var); - write_separator(ctx); + WriteKey("name"); + WriteVar(&command.register_.var); + WriteSeparator(); } else { /* If we're not registering by name, then we should only be * registering the last module. */ WABT_USE(last_module_index); assert(command.register_.var.index == last_module_index); } - write_key(ctx, "as"); - write_escaped_string_slice(ctx, command.register_.module_name); + WriteKey("as"); + WriteEscapedStringSlice(command.register_.module_name); break; case CommandType::AssertMalformed: - write_invalid_module(ctx, command.assert_malformed.module, - command.assert_malformed.text); - ctx->num_modules++; + WriteInvalidModule(command.assert_malformed.module, + command.assert_malformed.text); + num_modules_++; break; case CommandType::AssertInvalid: - write_invalid_module(ctx, command.assert_invalid.module, + WriteInvalidModule(command.assert_invalid.module, command.assert_invalid.text); - ctx->num_modules++; + num_modules_++; break; case CommandType::AssertUnlinkable: - write_invalid_module(ctx, command.assert_unlinkable.module, - command.assert_unlinkable.text); - ctx->num_modules++; + WriteInvalidModule(command.assert_unlinkable.module, + command.assert_unlinkable.text); + num_modules_++; break; case CommandType::AssertUninstantiable: - write_invalid_module(ctx, command.assert_uninstantiable.module, - command.assert_uninstantiable.text); - ctx->num_modules++; + WriteInvalidModule(command.assert_uninstantiable.module, + command.assert_uninstantiable.text); + num_modules_++; break; case CommandType::AssertReturn: - write_location(ctx, &command.assert_return.action->loc); - write_separator(ctx); - write_action(ctx, command.assert_return.action); - write_separator(ctx); - write_key(ctx, "expected"); - write_const_vector(ctx, *command.assert_return.expected); + WriteLocation(&command.assert_return.action->loc); + WriteSeparator(); + WriteAction(command.assert_return.action); + WriteSeparator(); + WriteKey("expected"); + WriteConstVector(*command.assert_return.expected); break; case CommandType::AssertReturnCanonicalNan: - write_location(ctx, &command.assert_return_canonical_nan.action->loc); - write_separator(ctx); - write_action(ctx, command.assert_return_canonical_nan.action); - write_separator(ctx); - write_key(ctx, "expected"); - write_action_result_type(ctx, script, - command.assert_return_canonical_nan.action); + WriteLocation(&command.assert_return_canonical_nan.action->loc); + WriteSeparator(); + WriteAction(command.assert_return_canonical_nan.action); + WriteSeparator(); + WriteKey("expected"); + WriteActionResultType(script, + command.assert_return_canonical_nan.action); break; case CommandType::AssertReturnArithmeticNan: - write_location(ctx, &command.assert_return_arithmetic_nan.action->loc); - write_separator(ctx); - write_action(ctx, command.assert_return_arithmetic_nan.action); - write_separator(ctx); - write_key(ctx, "expected"); - write_action_result_type(ctx, script, - command.assert_return_arithmetic_nan.action); + WriteLocation(&command.assert_return_arithmetic_nan.action->loc); + WriteSeparator(); + WriteAction(command.assert_return_arithmetic_nan.action); + WriteSeparator(); + WriteKey("expected"); + WriteActionResultType(script, + command.assert_return_arithmetic_nan.action); break; case CommandType::AssertTrap: - write_location(ctx, &command.assert_trap.action->loc); - write_separator(ctx); - write_action(ctx, command.assert_trap.action); - write_separator(ctx); - write_key(ctx, "text"); - write_escaped_string_slice(ctx, command.assert_trap.text); + WriteLocation(&command.assert_trap.action->loc); + WriteSeparator(); + WriteAction(command.assert_trap.action); + WriteSeparator(); + WriteKey("text"); + WriteEscapedStringSlice(command.assert_trap.text); break; case CommandType::AssertExhaustion: - write_location(ctx, &command.assert_trap.action->loc); - write_separator(ctx); - write_action(ctx, command.assert_trap.action); + WriteLocation(&command.assert_trap.action->loc); + WriteSeparator(); + WriteAction(command.assert_trap.action); break; case CommandType::AssertInvalidNonBinary: @@ -474,31 +496,27 @@ static void write_commands(Context* ctx, Script* script) { break; } - ctx->json_stream.Writef("}"); + json_stream_.Writef("}"); } - ctx->json_stream.Writef("]}\n"); + json_stream_.Writef("]}\n"); } +Result BinaryWriterSpec::WriteScript(Script* script) { + WriteCommands(script); + if (spec_options_->json_filename) { + json_stream_.WriteToFile(spec_options_->json_filename); + } + return result_; +} + +} // namespace + Result write_binary_spec_script(Script* script, const char* source_filename, const WriteBinarySpecOptions* spec_options) { assert(source_filename); - Context ctx; - ctx.spec_options = spec_options; - ctx.result = Result::Ok; - ctx.source_filename.start = source_filename; - ctx.source_filename.length = strlen(source_filename); - ctx.module_filename_noext = strip_extension( - ctx.spec_options->json_filename ? ctx.spec_options->json_filename - : source_filename); - ctx.write_modules = !!ctx.spec_options->json_filename; - - write_commands(&ctx, script); - if (ctx.spec_options->json_filename) { - ctx.json_stream.WriteToFile(ctx.spec_options->json_filename); - } - - return ctx.result; + BinaryWriterSpec binary_writer_spec(source_filename, spec_options); + return binary_writer_spec.WriteScript(script); } } // namespace wabt |