diff options
Diffstat (limited to 'src/wasm-binary-writer-spec.c')
-rw-r--r-- | src/wasm-binary-writer-spec.c | 804 |
1 files changed, 331 insertions, 473 deletions
diff --git a/src/wasm-binary-writer-spec.c b/src/wasm-binary-writer-spec.c index cdf02ebb..2aa49e8a 100644 --- a/src/wasm-binary-writer-spec.c +++ b/src/wasm-binary-writer-spec.c @@ -17,561 +17,419 @@ #include "wasm-binary-writer-spec.h" #include <assert.h> +#include <inttypes.h> #include "wasm-ast.h" #include "wasm-binary.h" #include "wasm-binary-writer.h" #include "wasm-config.h" +#include "wasm-stream.h" #include "wasm-writer.h" -#define DUMP_OCTETS_PER_LINE 16 - -#define CALLBACK0(ctx, member) \ - do { \ - if (((ctx)->spec_options->member)) \ - (ctx)->spec_options->member((ctx)->spec_options->user_data); \ - } while (0) - -#define CALLBACK(ctx, member, ...) \ - do { \ - if (((ctx)->spec_options->member)) \ - (ctx) \ - ->spec_options->member(__VA_ARGS__, (ctx)->spec_options->user_data); \ - } while (0) - typedef struct Context { WasmAllocator* allocator; - WasmWriter* writer; - size_t writer_offset; - const WasmWriteBinaryOptions* options; + WasmMemoryWriter json_writer; + WasmStream json_stream; + const char* source_filename; + WasmStringSlice json_filename_noext; const WasmWriteBinarySpecOptions* spec_options; WasmResult result; + size_t num_modules; } Context; -typedef struct ExprList { - WasmExpr* first; - WasmExpr* last; -} ExprList; - -typedef struct ActionInfo { - const WasmAction* action; - int index; - size_t num_results; - union { - /* when action->type == INVOKE; memory is shared with the callee's sig */ - const WasmTypeVector* result_types; - /* when action->type == GET */ - WasmType result_type; - }; -} ActionInfo; - -static void append_expr(ExprList* expr_list, WasmExpr* expr) { - if (expr_list->last) - expr_list->last->next = expr; - else - expr_list->first = expr; - expr_list->last = expr; +static void convert_backslash_to_slash(char* s, size_t length) { + size_t i = 0; + for (; i < length; ++i) + if (s[i] == '\\') + s[i] = '/'; } -static void append_const_expr(WasmAllocator* allocator, - ExprList* expr_list, - const WasmConst* const_) { - WasmExpr* expr = wasm_new_const_expr(allocator); - expr->const_ = *const_; - append_expr(expr_list, expr); +static WasmStringSlice strip_extension(const char* s) { + /* strip .json or .wasm, but leave other extensions, e.g.: + * + * s = "foo", => "foo" + * s = "foo.json" => "foo" + * s = "foo.wasm" => "foo" + * s = "foo.bar" => "foo.bar" + */ + if (s == NULL) { + WasmStringSlice result; + result.start = NULL; + result.length = 0; + return result; + } + + size_t slen = strlen(s); + const char* ext_start = strrchr(s, '.'); + if (ext_start == NULL) + ext_start = s + slen; + + WasmStringSlice result; + result.start = s; + + if (strcmp(ext_start, ".json") == 0 || strcmp(ext_start, ".wasm") == 0) { + result.length = ext_start - s; + } else { + result.length = slen; + } + return result; } -static void append_i32_const_expr(WasmAllocator* allocator, - ExprList* expr_list, - uint32_t value) { - WasmConst const_; - const_.type = WASM_TYPE_I32; - const_.u32 = value; - append_const_expr(allocator, expr_list, &const_); +static WasmStringSlice get_basename(const char* s) { + /* strip everything up to and including the last slash, e.g.: + * + * s = "/foo/bar/baz", => "baz" + * s = "/usr/local/include/stdio.h", => "stdio.h" + * s = "foo.bar", => "foo.bar" + */ + size_t slen = strlen(s); + const char* start = s; + const char* last_slash = strrchr(s, '/'); + if (last_slash != NULL) + start = last_slash + 1; + + WasmStringSlice result; + result.start = start; + result.length = s + slen - start; + return result; } -static void append_invoke_expr(WasmAllocator* allocator, - ExprList* expr_list, - const WasmActionInvoke* invoke, - int func_index) { - size_t i; - for (i = 0; i < invoke->args.size; ++i) - append_const_expr(allocator, expr_list, &invoke->args.data[i]); +static char* get_module_filename(Context* ctx) { + size_t buflen = ctx->json_filename_noext.length + 20; + char* str = wasm_alloc(ctx->allocator, buflen, WASM_DEFAULT_ALIGN); + size_t length = wasm_snprintf( + str, buflen, PRIstringslice ".%" PRIzd ".wasm", + WASM_PRINTF_STRING_SLICE_ARG(ctx->json_filename_noext), ctx->num_modules); + convert_backslash_to_slash(str, length); + return str; +} - WasmExpr* expr = wasm_new_call_expr(allocator); - expr->call.var.type = WASM_VAR_TYPE_INDEX; - expr->call.var.index = func_index; - append_expr(expr_list, expr); +static void write_string(Context* ctx, const char* s) { + wasm_writef(&ctx->json_stream, "\"%s\"", s); } -static void append_get_global_expr(WasmAllocator* allocator, - ExprList* expr_list, - const WasmActionGet* get, - int global_index) { - WasmExpr* expr = wasm_new_get_global_expr(allocator); - expr->get_global.var.type = WASM_VAR_TYPE_INDEX; - expr->get_global.var.index = global_index; - append_expr(expr_list, expr); +static void write_key(Context* ctx, const char* key) { + wasm_writef(&ctx->json_stream, "\"%s\": ", key); } -static void append_eq_expr(WasmAllocator* allocator, - ExprList* expr_list, - WasmType type) { - WasmExpr* expr = wasm_new_compare_expr(allocator); - switch (type) { - case WASM_TYPE_I32: - expr->compare.opcode = WASM_OPCODE_I32_EQ; - break; - case WASM_TYPE_I64: - expr->compare.opcode = WASM_OPCODE_I64_EQ; - break; - case WASM_TYPE_F32: - expr->compare.opcode = WASM_OPCODE_F32_EQ; - break; - case WASM_TYPE_F64: - expr->compare.opcode = WASM_OPCODE_F64_EQ; - break; - default: - assert(0); - } - append_expr(expr_list, expr); +static void write_separator(Context* ctx) { + wasm_writef(&ctx->json_stream, ", "); } -static void append_ne_expr(WasmAllocator* allocator, - ExprList* expr_list, - WasmType type) { - WasmExpr* expr = wasm_new_compare_expr(allocator); - switch (type) { - case WASM_TYPE_I32: - expr->compare.opcode = WASM_OPCODE_I32_NE; - break; - case WASM_TYPE_I64: - expr->compare.opcode = WASM_OPCODE_I64_NE; - break; - case WASM_TYPE_F32: - expr->compare.opcode = WASM_OPCODE_F32_NE; - break; - case WASM_TYPE_F64: - expr->compare.opcode = WASM_OPCODE_F64_NE; - break; - default: - assert(0); +static void write_escaped_string_slice(Context* ctx, WasmStringSlice ss) { + size_t i; + wasm_write_char(&ctx->json_stream, '"'); + for (i = 0; i < ss.length; ++i) { + uint8_t c = ss.start[i]; + if (c < 0x20 || c == '\\' || c == '"') { + wasm_writef(&ctx->json_stream, "\\u%04x", c); + } else { + wasm_write_char(&ctx->json_stream, c); + } } - append_expr(expr_list, expr); + wasm_write_char(&ctx->json_stream, '"'); } -static void append_tee_local_expr(WasmAllocator* allocator, - ExprList* expr_list, - int index) { - WasmExpr* expr = wasm_new_tee_local_expr(allocator); - expr->tee_local.var.type = WASM_VAR_TYPE_INDEX; - expr->tee_local.var.index = index; - append_expr(expr_list, expr); -} +static void write_command_type(Context* ctx, const WasmCommand* command) { + static const char* s_command_names[] = { + "module", + "action", + "register", + "assert_malformed", + "assert_invalid", + "assert_unlinkable", + "assert_return", + "assert_return_nan", + "assert_trap", + }; + WASM_STATIC_ASSERT(WASM_ARRAY_SIZE(s_command_names) == + WASM_NUM_COMMAND_TYPES); -static void append_get_local_expr(WasmAllocator* allocator, - ExprList* expr_list, - int index) { - WasmExpr* expr = wasm_new_get_local_expr(allocator); - expr->get_local.var.type = WASM_VAR_TYPE_INDEX; - expr->get_local.var.index = index; - append_expr(expr_list, expr); + write_key(ctx, "type"); + write_string(ctx, s_command_names[command->type]); } -static void append_reinterpret_expr(WasmAllocator* allocator, - ExprList* expr_list, - WasmType type) { - WasmExpr* expr = wasm_new_convert_expr(allocator); - switch (type) { - case WASM_TYPE_F32: - expr->convert.opcode = WASM_OPCODE_I32_REINTERPRET_F32; - break; - case WASM_TYPE_F64: - expr->convert.opcode = WASM_OPCODE_I64_REINTERPRET_F64; - break; - default: - assert(0); - break; - } - append_expr(expr_list, expr); +static void write_location(Context* ctx, const WasmLocation* loc) { + write_key(ctx, "line"); + wasm_writef(&ctx->json_stream, "%d", loc->line); } -static void append_return_expr(WasmAllocator* allocator, ExprList* expr_list) { - WasmExpr* expr = wasm_new_return_expr(allocator); - append_expr(expr_list, expr); +static void write_var(Context* ctx, const WasmVar* var) { + if (var->type == WASM_VAR_TYPE_INDEX) + wasm_writef(&ctx->json_stream, "\"%" PRIu64 "\"", var->index); + else + write_escaped_string_slice(ctx, var->name); } -static WasmModuleField* append_module_field( - WasmAllocator* allocator, - WasmModule* module, - WasmModuleFieldType module_field_type) { - WasmModuleField* result = wasm_append_module_field(allocator, module); - result->type = module_field_type; - - switch (module_field_type) { - case WASM_MODULE_FIELD_TYPE_FUNC: { - WasmFuncPtr* func_ptr = wasm_append_func_ptr(allocator, &module->funcs); - *func_ptr = &result->func; +static void write_const(Context* ctx, const WasmConst* const_) { + wasm_writef(&ctx->json_stream, "{"); + write_key(ctx, "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 WASM_TYPE_I32: + write_string(ctx, "i32"); + write_separator(ctx); + write_key(ctx, "value"); + wasm_writef(&ctx->json_stream, "\"%u\"", const_->u32); break; - } - case WASM_MODULE_FIELD_TYPE_IMPORT: { - WasmImportPtr* import_ptr = - wasm_append_import_ptr(allocator, &module->imports); - *import_ptr = &result->import; + + case WASM_TYPE_I64: + write_string(ctx, "i64"); + write_separator(ctx); + write_key(ctx, "value"); + wasm_writef(&ctx->json_stream, "\"%" PRIu64 "\"", const_->u64); break; - } - case WASM_MODULE_FIELD_TYPE_EXPORT: { - WasmExportPtr* export_ptr = - wasm_append_export_ptr(allocator, &module->exports); - *export_ptr = &result->export_; + + case WASM_TYPE_F32: { + /* TODO(binji): write as hex float */ + write_string(ctx, "f32"); + write_separator(ctx); + write_key(ctx, "value"); + wasm_writef(&ctx->json_stream, "\"%u\"", const_->f32_bits); break; } - case WASM_MODULE_FIELD_TYPE_FUNC_TYPE: { - WasmFuncTypePtr* func_type_ptr = - wasm_append_func_type_ptr(allocator, &module->func_types); - *func_type_ptr = &result->func_type; + + case WASM_TYPE_F64: { + /* TODO(binji): write as hex float */ + write_string(ctx, "f64"); + write_separator(ctx); + write_key(ctx, "value"); + wasm_writef(&ctx->json_stream, "\"%" PRIu64 "\"", const_->f64_bits); break; } - case WASM_MODULE_FIELD_TYPE_GLOBAL: - case WASM_MODULE_FIELD_TYPE_TABLE: - case WASM_MODULE_FIELD_TYPE_MEMORY: - case WASM_MODULE_FIELD_TYPE_START: - case WASM_MODULE_FIELD_TYPE_ELEM_SEGMENT: - case WASM_MODULE_FIELD_TYPE_DATA_SEGMENT: - /* not supported */ + default: assert(0); - break; } - return result; + wasm_writef(&ctx->json_stream, "}"); } -static WasmStringSlice create_assert_func_name(WasmAllocator* allocator, - const char* format, - int format_index) { - WasmStringSlice name; - char buffer[256]; - int buffer_len = wasm_snprintf(buffer, 256, format, format_index); - name.start = wasm_strndup(allocator, buffer, buffer_len); - name.length = buffer_len; - return name; +static void write_const_vector(Context* ctx, const WasmConstVector* consts) { + wasm_writef(&ctx->json_stream, "["); + size_t i; + for (i = 0; i < consts->size; ++i) { + const WasmConst* const_ = &consts->data[i]; + write_const(ctx, const_); + if (i != consts->size - 1) + write_separator(ctx); + } + wasm_writef(&ctx->json_stream, "]"); } -static WasmFunc* append_nullary_func(WasmAllocator* allocator, - WasmModule* module, - const WasmTypeVector* result_types, - WasmStringSlice export_name) { - WasmFuncType* func_type; - WasmFuncSignature sig; - WASM_ZERO_MEMORY(sig); - /* OK to share memory w/ result_types, because we're just using it to see if - * this signature already exists */ - sig.result_types = *result_types; - int sig_index = wasm_get_func_type_index_by_sig(module, &sig); - if (sig_index == -1) { - WasmLocation loc; - WASM_ZERO_MEMORY(loc); - /* clone result_types so we don't share its memory */ - WASM_ZERO_MEMORY(sig.result_types); - wasm_extend_types(allocator, &sig.result_types, result_types); - func_type = wasm_append_implicit_func_type(allocator, &loc, module, &sig); - sig_index = module->func_types.size - 1; +static void write_action(Context* ctx, const WasmAction* action) { + write_key(ctx, "action"); + wasm_writef(&ctx->json_stream, "{"); + write_key(ctx, "type"); + if (action->type == WASM_ACTION_TYPE_INVOKE) { + write_string(ctx, "invoke"); } else { - func_type = module->func_types.data[sig_index]; + assert(action->type == WASM_ACTION_TYPE_GET); + write_string(ctx, "get"); } - - WasmModuleField* func_field = - append_module_field(allocator, module, WASM_MODULE_FIELD_TYPE_FUNC); - WasmFunc* func = &func_field->func; - func->decl.flags = WASM_FUNC_DECLARATION_FLAG_HAS_FUNC_TYPE | - WASM_FUNC_DECLARATION_FLAG_SHARED_SIGNATURE; - func->decl.type_var.type = WASM_VAR_TYPE_INDEX; - func->decl.type_var.index = sig_index; - func->decl.sig = func_type->sig; - int func_index = module->funcs.size - 1; - - WasmModuleField* export_field = - append_module_field(allocator, module, WASM_MODULE_FIELD_TYPE_EXPORT); - WasmExport* export_ = &export_field->export_; - export_->var.type = WASM_VAR_TYPE_INDEX; - export_->var.index = func_index; - export_->name = export_name; - return module->funcs.data[func_index]; -} - -static WasmFunc* append_nullary_func_0(WasmAllocator* allocator, - WasmModule* module, - WasmStringSlice export_name) { - WasmTypeVector types; - WASM_ZERO_MEMORY(types); - return append_nullary_func(allocator, module, &types, export_name); -} - -static WasmFunc* append_nullary_func_1(WasmAllocator* allocator, - WasmModule* module, - WasmType type, - WasmStringSlice export_name) { - WasmTypeVector types; - WASM_ZERO_MEMORY(types); - types.size = 1; - types.data = &type; - return append_nullary_func(allocator, module, &types, export_name); -} - -static ActionInfo get_action_info(const WasmModule* module, - const WasmAction* action) { - ActionInfo result; - WASM_ZERO_MEMORY(result); - - switch (action->type) { - case WASM_ACTION_TYPE_INVOKE: { - WasmExport* export_ = - wasm_get_export_by_name(module, &action->invoke.name); - assert(export_); - - int func_index = wasm_get_func_index_by_var(module, &export_->var); - assert(func_index >= 0 && (size_t)func_index < module->funcs.size); - WasmFunc* callee = module->funcs.data[func_index]; - result.action = action; - result.index = func_index; - result.num_results = callee->decl.sig.result_types.size; - result.result_types = &callee->decl.sig.result_types; - break; - } - - case WASM_ACTION_TYPE_GET: { - WasmExport* export_ = wasm_get_export_by_name(module, &action->get.name); - assert(export_); - - int global_index = wasm_get_global_index_by_var(module, &export_->var); - assert(global_index >= 0 && (size_t)global_index < module->globals.size); - WasmGlobal* global = module->globals.data[global_index]; - result.action = action; - result.index = global_index; - result.num_results = 1; - result.result_type = global->type; - break; - } + write_separator(ctx); + if (action->module_var.type != WASM_VAR_TYPE_INDEX) { + write_key(ctx, "module"); + write_var(ctx, &action->module_var); + write_separator(ctx); } - return result; -} - -static WasmType get_action_info_result_type(const ActionInfo* info) { - assert(info->num_results == 1); - - switch (info->action->type) { - case WASM_ACTION_TYPE_INVOKE: - return info->result_types->data[0]; - - case WASM_ACTION_TYPE_GET: - return info->result_type; + if (action->type == WASM_ACTION_TYPE_INVOKE) { + write_key(ctx, "field"); + write_escaped_string_slice(ctx, action->invoke.name); + write_separator(ctx); + write_key(ctx, "args"); + write_const_vector(ctx, &action->invoke.args); + } else { + write_key(ctx, "field"); + write_escaped_string_slice(ctx, action->get.name); } - WABT_UNREACHABLE; + wasm_writef(&ctx->json_stream, "}"); } -static void append_action_expr(WasmAllocator* allocator, - WasmModule* module, - ExprList* expr_list, - const ActionInfo* info) { - switch (info->action->type) { - case WASM_ACTION_TYPE_INVOKE: - append_invoke_expr(allocator, expr_list, &info->action->invoke, - info->index); - break; - - case WASM_ACTION_TYPE_GET: - append_get_global_expr(allocator, expr_list, &info->action->get, - info->index); - break; +static void write_module(Context* ctx, + char* filename, + const WasmModule* module) { + WasmMemoryWriter writer; + WasmResult result = wasm_init_mem_writer(ctx->allocator, &writer); + if (WASM_SUCCEEDED(result)) { + result = wasm_write_binary_module(ctx->allocator, &writer.base, module, + &ctx->spec_options->write_binary_options); + if (WASM_SUCCEEDED(result)) + result = wasm_write_output_buffer_to_file(&writer.buf, filename); + wasm_close_mem_writer(&writer); } + + ctx->result = result; } -static void write_module(Context* ctx, uint32_t index, WasmModule* module) { - WasmResult result; - WasmWriter* writer = NULL; - CALLBACK(ctx, on_module_before_write, index, &writer); - if (writer != NULL) { - result = - wasm_write_binary_module(ctx->allocator, writer, module, ctx->options); +static void write_raw_module(Context* ctx, + char* filename, + const WasmRawModule* raw_module) { + if (raw_module->type == WASM_RAW_MODULE_TYPE_TEXT) { + write_module(ctx, filename, raw_module->text); } else { - result = WASM_ERROR; - } - if (WASM_FAILED(result)) + WasmFileStream stream; + WasmResult result = wasm_init_file_writer(&stream.writer, filename); + if (WASM_SUCCEEDED(result)) { + wasm_init_stream(&stream.base, &stream.writer.base, NULL); + wasm_write_data(&stream.base, raw_module->binary.data, + raw_module->binary.size, ""); + wasm_close_file_writer(&stream.writer); + } ctx->result = result; - CALLBACK(ctx, on_module_end, index, result); + } +} + +static void write_invalid_module(Context* ctx, + const WasmRawModule* module, + WasmStringSlice text) { + char* filename = get_module_filename(ctx); + write_location(ctx, wasm_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); + wasm_free(ctx->allocator, filename); } static void write_commands(Context* ctx, WasmScript* script) { - uint32_t i; - uint32_t num_modules = 0; - WasmAllocator* allocator = script->allocator; - WasmModule* last_module = NULL; - uint32_t num_assert_funcs = 0; + wasm_writef(&ctx->json_stream, "{\"source_filename\": \"%s\",\n", + ctx->source_filename); + wasm_writef(&ctx->json_stream, " \"commands\": [\n"); + size_t i; for (i = 0; i < script->commands.size; ++i) { WasmCommand* command = &script->commands.data[i]; - if (command->type == WASM_COMMAND_TYPE_MODULE) { - if (last_module) - write_module(ctx, num_modules, last_module); - CALLBACK(ctx, on_module_begin, num_modules); - last_module = &command->module; - num_assert_funcs = 0; - ++num_modules; - } else { - if (!last_module) - continue; - - const char* format = NULL; - WasmAction* action = NULL; - switch (command->type) { - case WASM_COMMAND_TYPE_ACTION: - format = "$action_%d"; - action = &command->action; - break; - case WASM_COMMAND_TYPE_ASSERT_RETURN: - format = "$assert_return_%d"; - action = &command->assert_return.action; - break; - case WASM_COMMAND_TYPE_ASSERT_RETURN_NAN: - format = "$assert_return_nan_%d"; - action = &command->assert_return_nan.action; - break; - case WASM_COMMAND_TYPE_ASSERT_TRAP: - format = "$assert_trap_%d"; - action = &command->assert_trap.action; - break; - default: - continue; - } - WasmStringSlice name = - create_assert_func_name(allocator, format, num_assert_funcs); - CALLBACK(ctx, on_command, num_assert_funcs, command->type, &name, - &action->loc); - - ++num_assert_funcs; - - ActionInfo info = get_action_info(last_module, action); - - switch (command->type) { - case WASM_COMMAND_TYPE_ACTION: { - WasmFunc* caller = - append_nullary_func_0(allocator, last_module, name); - ExprList expr_list; - WASM_ZERO_MEMORY(expr_list); - append_action_expr(allocator, last_module, &expr_list, &info); - append_return_expr(allocator, &expr_list); - caller->first_expr = expr_list.first; - break; + wasm_writef(&ctx->json_stream, " {"); + write_command_type(ctx, command); + write_separator(ctx); + + switch (command->type) { + case WASM_COMMAND_TYPE_MODULE: { + WasmModule* module = &command->module; + char* filename = get_module_filename(ctx); + write_location(ctx, &module->loc); + write_separator(ctx); + if (module->name.start) { + write_key(ctx, "name"); + write_escaped_string_slice(ctx, module->name); + write_separator(ctx); } - - case WASM_COMMAND_TYPE_ASSERT_RETURN: { - WasmFunc* caller = append_nullary_func_1(allocator, last_module, - WASM_TYPE_I32, name); - ExprList expr_list; - WASM_ZERO_MEMORY(expr_list); - append_action_expr(allocator, last_module, &expr_list, &info); - - if (info.num_results == 1) { - WasmType result_type = get_action_info_result_type(&info); - const WasmConstVector* expected_consts = - &command->assert_return.expected; - if (expected_consts->size == 1) { - WasmConst expected = expected_consts->data[0]; - if (expected.type == WASM_TYPE_F32) { - append_reinterpret_expr(allocator, &expr_list, WASM_TYPE_F32); - append_const_expr(allocator, &expr_list, &expected); - append_reinterpret_expr(allocator, &expr_list, WASM_TYPE_F32); - append_eq_expr(allocator, &expr_list, WASM_TYPE_I32); - } else if (expected.type == WASM_TYPE_F64) { - append_reinterpret_expr(allocator, &expr_list, WASM_TYPE_F64); - append_const_expr(allocator, &expr_list, &expected); - append_reinterpret_expr(allocator, &expr_list, WASM_TYPE_F64); - append_eq_expr(allocator, &expr_list, WASM_TYPE_I64); - } else { - append_const_expr(allocator, &expr_list, &expected); - append_eq_expr(allocator, &expr_list, result_type); - } - } else { - /* function result count mismatch; just fail */ - append_i32_const_expr(allocator, &expr_list, 0); - append_return_expr(allocator, &expr_list); - } - } else { - /* 0 results or >1 results. If there are 0 results, we just assume - * that everything was OK. We don't currenty support multiple - * results, so consider that a failure. */ - append_i32_const_expr(allocator, &expr_list, - info.num_results == 0 ? 1 : 0); - append_return_expr(allocator, &expr_list); - } - - caller->first_expr = expr_list.first; - break; - } - - case WASM_COMMAND_TYPE_ASSERT_RETURN_NAN: { - WasmFunc* caller = append_nullary_func_1(allocator, last_module, - WASM_TYPE_I32, name); - ExprList expr_list; - WASM_ZERO_MEMORY(expr_list); - - append_action_expr(allocator, last_module, &expr_list, &info); - - if (info.num_results == 1) { - WasmType result_type = get_action_info_result_type(&info); - wasm_append_type_value(allocator, &caller->local_types, - &result_type); - append_tee_local_expr(allocator, &expr_list, 0); - append_get_local_expr(allocator, &expr_list, 0); - /* x != x is true iff x is NaN */ - append_ne_expr(allocator, &expr_list, result_type); - } else { - /* assert_return_nan doesn't make sense w/ 0 or >1 results; just - * fail */ - append_i32_const_expr(allocator, &expr_list, 0); - append_return_expr(allocator, &expr_list); - } - - caller->first_expr = expr_list.first; - break; - } - - case WASM_COMMAND_TYPE_ASSERT_TRAP: { - WasmFunc* caller = - append_nullary_func_0(allocator, last_module, name); - ExprList expr_list; - WASM_ZERO_MEMORY(expr_list); - append_action_expr(allocator, last_module, &expr_list, &info); - append_return_expr(allocator, &expr_list); - caller->first_expr = expr_list.first; - break; - } - - default: - assert(0); + write_key(ctx, "filename"); + write_escaped_string_slice(ctx, get_basename(filename)); + write_module(ctx, filename, module); + wasm_free(ctx->allocator, filename); + ctx->num_modules++; + break; } + + case WASM_COMMAND_TYPE_ACTION: + write_location(ctx, &command->action.loc); + write_separator(ctx); + write_action(ctx, &command->action); + break; + + case WASM_COMMAND_TYPE_REGISTER: + write_location(ctx, &command->register_.var.loc); + write_separator(ctx); + write_key(ctx, "name"); + write_var(ctx, &command->register_.var); + write_separator(ctx); + write_key(ctx, "as"); + write_escaped_string_slice(ctx, command->register_.module_name); + break; + + case WASM_COMMAND_TYPE_ASSERT_MALFORMED: + write_invalid_module(ctx, &command->assert_malformed.module, + command->assert_malformed.text); + ctx->num_modules++; + break; + + case WASM_COMMAND_TYPE_ASSERT_INVALID: + /* TODO(binji): this doesn't currently work because of various + * assertions in wasm-binary-writer.c */ +#if 0 + write_invalid_module(ctx, &command->assert_invalid.module, + command->assert_invalid.text); + ctx->num_modules++; +#else + write_location( + ctx, wasm_get_raw_module_location(&command->assert_invalid.module)); +#endif + break; + + case WASM_COMMAND_TYPE_ASSERT_UNLINKABLE: + write_invalid_module(ctx, &command->assert_unlinkable.module, + command->assert_unlinkable.text); + ctx->num_modules++; + break; + + case WASM_COMMAND_TYPE_ASSERT_RETURN: + 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); + break; + + case WASM_COMMAND_TYPE_ASSERT_RETURN_NAN: + write_location(ctx, &command->assert_return_nan.action.loc); + write_separator(ctx); + write_action(ctx, &command->assert_return_nan.action); + break; + + case WASM_COMMAND_TYPE_ASSERT_TRAP: + 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); + break; + + case WASM_NUM_COMMAND_TYPES: + assert(0); + break; } + + wasm_writef(&ctx->json_stream, "}"); + if (i != script->commands.size - 1) + write_separator(ctx); + wasm_writef(&ctx->json_stream, "\n"); } - if (last_module) - write_module(ctx, num_modules, last_module); + wasm_writef(&ctx->json_stream, "]}\n"); } WasmResult wasm_write_binary_spec_script( WasmAllocator* allocator, WasmScript* script, - const WasmWriteBinaryOptions* options, + const char* source_filename, const WasmWriteBinarySpecOptions* spec_options) { + assert(source_filename); Context ctx; WASM_ZERO_MEMORY(ctx); ctx.allocator = allocator; - ctx.options = options; ctx.spec_options = spec_options; ctx.result = WASM_OK; - - CALLBACK0(&ctx, on_script_begin); - write_commands(&ctx, script); - CALLBACK0(&ctx, on_script_end); + ctx.source_filename = source_filename; + ctx.json_filename_noext = strip_extension(ctx.spec_options->json_filename); + + WasmResult result = wasm_init_mem_writer(ctx.allocator, &ctx.json_writer); + if (WASM_SUCCEEDED(result)) { + wasm_init_stream(&ctx.json_stream, &ctx.json_writer.base, NULL); + write_commands(&ctx, script); + if (ctx.spec_options->json_filename) { + wasm_write_output_buffer_to_file(&ctx.json_writer.buf, + ctx.spec_options->json_filename); + } + wasm_close_mem_writer(&ctx.json_writer); + } return ctx.result; } |