summaryrefslogtreecommitdiff
path: root/src/binary-writer-spec.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/binary-writer-spec.cc')
-rw-r--r--src/binary-writer-spec.cc456
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