diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/sexpr-wasm.c | 77 | ||||
-rw-r--r-- | src/wasm-ast-writer.c | 495 | ||||
-rw-r--r-- | src/wasm-binary-writer.c | 425 | ||||
-rw-r--r-- | src/wasm-binary-writer.h | 5 | ||||
-rw-r--r-- | src/wasm-common.c | 44 | ||||
-rw-r--r-- | src/wasm-common.h | 12 | ||||
-rw-r--r-- | src/wasm-stream.c | 138 | ||||
-rw-r--r-- | src/wasm-stream.h | 90 | ||||
-rw-r--r-- | src/wasm-writer.c | 18 | ||||
-rw-r--r-- | src/wasm-writer.h | 9 |
10 files changed, 719 insertions, 594 deletions
diff --git a/src/sexpr-wasm.c b/src/sexpr-wasm.c index 4e2147ff..68836430 100644 --- a/src/sexpr-wasm.c +++ b/src/sexpr-wasm.c @@ -30,6 +30,7 @@ #include "wasm-option-parser.h" #include "wasm-parser.h" #include "wasm-stack-allocator.h" +#include "wasm-stream.h" #include "wasm-writer.h" #define ALLOC_FAILURE \ @@ -57,6 +58,9 @@ static WasmSourceErrorHandler s_error_handler = static WasmSourceErrorHandler s_assert_invalid_error_handler = WASM_ASSERT_INVALID_SOURCE_ERROR_HANDLER_DEFAULT; +static WasmFileWriter s_log_stream_writer; +static WasmStream s_log_stream; + #define NOPE WASM_OPTION_NO_ARGUMENT #define YEP WASM_OPTION_HAS_ARGUMENT @@ -122,7 +126,9 @@ static void on_option(struct WasmOptionParser* parser, switch (option->id) { case FLAG_VERBOSE: s_verbose++; - s_write_binary_options.log_writes = WASM_TRUE; + wasm_init_file_writer_existing(&s_log_stream_writer, stdout); + wasm_init_stream(&s_log_stream, &s_log_stream_writer.base, NULL); + s_write_binary_options.log_stream = &s_log_stream; break; case FLAG_HELP: @@ -186,26 +192,16 @@ static void parse_options(int argc, char** argv) { } } -static void write_buffer_to_file(const char* out_filename, +static void write_buffer_to_file(const char* filename, WasmOutputBuffer* buffer) { if (s_dump_module) { if (s_verbose) - printf(";; dump\n"); - wasm_print_memory(buffer->start, buffer->size, 0, WASM_DONT_PRINT_CHARS, - NULL); + wasm_writef(&s_log_stream, ";; dump\n"); + wasm_write_output_buffer_memory_dump(&s_log_stream, buffer); } - if (out_filename) { - FILE* file = fopen(out_filename, "wb"); - if (!file) - WASM_FATAL("unable to open %s for writing\n", s_outfile); - - ssize_t bytes = fwrite(buffer->start, 1, buffer->size, file); - if (bytes < 0 || (size_t)bytes != buffer->size) { - WASM_FATAL("failed to write %" PRIzd " bytes to %s\n", buffer->size, - out_filename); - } - fclose(file); + if (filename) { + wasm_write_output_buffer_to_file(buffer, filename); } } @@ -273,40 +269,13 @@ static char* get_module_filename(WasmAllocator* allocator, typedef struct WasmContext { WasmAllocator* allocator; WasmMemoryWriter json_writer; - uint32_t json_writer_offset; WasmMemoryWriter module_writer; + WasmStream json_stream; WasmStringSlice output_filename_noext; char* module_filename; WasmResult result; } WasmContext; -static void out_data(WasmContext* ctx, const void* src, size_t size) { - if (WASM_FAILED(ctx->result)) - return; - WasmWriter* writer = &ctx->json_writer.base; - if (writer->write_data) { - ctx->result = writer->write_data(ctx->json_writer_offset, src, size, - writer->user_data); - ctx->json_writer_offset += size; - } -} - -static void out_printf(WasmContext* ctx, const char* format, ...) { - va_list args; - va_list args_copy; - va_start(args, format); - va_copy(args_copy, args); - /* + 1 to account for the \0 that will be added automatically by - wasm_vsnprintf */ - int len = wasm_vsnprintf(NULL, 0, format, args) + 1; - va_end(args); - char* buffer = alloca(len); - wasm_vsnprintf(buffer, len, format, args_copy); - va_end(args_copy); - /* - 1 to remove the trailing \0 that was added by wasm_vsnprintf */ - out_data(ctx, buffer, len - 1); -} - static void on_script_begin(void* user_data) { WasmContext* ctx = user_data; @@ -315,8 +284,9 @@ static void on_script_begin(void* user_data) { if (WASM_FAILED(wasm_init_mem_writer(ctx->allocator, &ctx->json_writer))) WASM_FATAL("unable to open memory writer for writing\n"); + wasm_init_stream(&ctx->json_stream, &ctx->json_writer.base, NULL); - out_printf(ctx, "{\"modules\": [\n"); + wasm_writef(&ctx->json_stream, "{\"modules\": [\n"); } static void on_module_begin(uint32_t index, void* user_data) { @@ -325,10 +295,11 @@ static void on_module_begin(uint32_t index, void* user_data) { ctx->module_filename = get_module_filename(ctx->allocator, &ctx->output_filename_noext, index); if (index != 0) - out_printf(ctx, ",\n"); + wasm_writef(&ctx->json_stream, ",\n"); WasmStringSlice module_basename = get_basename(ctx->module_filename); - out_printf(ctx, " {\"filename\": \"" PRIstringslice "\", \"commands\": [\n", - WASM_PRINTF_STRING_SLICE_ARG(module_basename)); + wasm_writef(&ctx->json_stream, + " {\"filename\": \"" PRIstringslice "\", \"commands\": [\n", + WASM_PRINTF_STRING_SLICE_ARG(module_basename)); } static void on_command(uint32_t index, @@ -357,9 +328,9 @@ static void on_command(uint32_t index, WasmContext* ctx = user_data; if (index != 0) - out_printf(ctx, ",\n"); - out_printf(ctx, s_command_format, s_command_names[type], - WASM_PRINTF_STRING_SLICE_ARG(*name), loc->filename, loc->line); + wasm_writef(&ctx->json_stream, ",\n"); + wasm_writef(&ctx->json_stream, s_command_format, s_command_names[type], + WASM_PRINTF_STRING_SLICE_ARG(*name), loc->filename, loc->line); } static void on_module_before_write(uint32_t index, @@ -372,14 +343,14 @@ static void on_module_before_write(uint32_t index, static void on_module_end(uint32_t index, WasmResult result, void* user_data) { WasmContext* ctx = user_data; - out_printf(ctx, "\n ]}"); + wasm_writef(&ctx->json_stream, "\n ]}"); if (WASM_SUCCEEDED(result)) write_buffer_to_file(ctx->module_filename, &ctx->module_writer.buf); } static void on_script_end(void* user_data) { WasmContext* ctx = user_data; - out_printf(ctx, "\n]}\n"); + wasm_writef(&ctx->json_stream, "\n]}\n"); if (WASM_SUCCEEDED(ctx->result)) write_buffer_to_file(s_outfile, &ctx->json_writer.buf); diff --git a/src/wasm-ast-writer.c b/src/wasm-ast-writer.c index 495c0377..49deee33 100644 --- a/src/wasm-ast-writer.c +++ b/src/wasm-ast-writer.c @@ -24,6 +24,7 @@ #include "wasm-ast.h" #include "wasm-common.h" #include "wasm-literal.h" +#include "wasm-stream.h" #include "wasm-writer.h" #define INDENT_SIZE 2 @@ -70,8 +71,7 @@ typedef enum WasmNextChar { typedef struct WasmContext { WasmAllocator* allocator; - WasmWriter* writer; - size_t offset; + WasmStream stream; WasmResult result; int indent; WasmNextChar next_char; @@ -88,47 +88,30 @@ static void dedent(WasmContext* ctx) { assert(ctx->indent >= 0); } -static void out_data_at(WasmContext* ctx, - size_t offset, - const void* src, - size_t size) { - if (WASM_FAILED(ctx->result)) - return; - if (ctx->writer->write_data) { - ctx->result = - ctx->writer->write_data(offset, src, size, ctx->writer->user_data); - } -} - -static void out_data(WasmContext* ctx, const void* src, size_t size) { - out_data_at(ctx, ctx->offset, src, size); - ctx->offset += size; -} - -static void out_indent(WasmContext* ctx) { +static void write_indent(WasmContext* ctx) { static char s_indent[] = " " " "; static size_t s_indent_len = sizeof(s_indent) - 1; size_t indent = ctx->indent; while (indent > s_indent_len) { - out_data(ctx, s_indent, s_indent_len); + wasm_write_data(&ctx->stream, s_indent, s_indent_len, NULL); indent -= s_indent_len; } if (indent > 0) { - out_data(ctx, s_indent, indent); + wasm_write_data(&ctx->stream, s_indent, indent, NULL); } } -static void out_next_char(WasmContext* ctx) { +static void write_next_char(WasmContext* ctx) { switch (ctx->next_char) { case WASM_NEXT_CHAR_SPACE: - out_data(ctx, " ", 1); + wasm_write_data(&ctx->stream, " ", 1, NULL); break; case WASM_NEXT_CHAR_NEWLINE: case WASM_NEXT_CHAR_FORCE_NEWLINE: - out_data(ctx, "\n", 1); - out_indent(ctx); + wasm_write_data(&ctx->stream, "\n", 1, NULL); + write_indent(ctx); break; default: @@ -138,166 +121,172 @@ static void out_next_char(WasmContext* ctx) { ctx->next_char = WASM_NEXT_CHAR_NONE; } -static void out_data_with_next_char(WasmContext* ctx, - const void* src, - size_t size) { - out_next_char(ctx); - out_data(ctx, src, size); +static void write_data_with_next_char(WasmContext* ctx, + const void* src, + size_t size) { + write_next_char(ctx); + wasm_write_data(&ctx->stream, src, size, NULL); } -static void out_printf(WasmContext* ctx, const char* format, ...) { +static void writef(WasmContext* ctx, const char* format, ...) { WASM_SNPRINTF_ALLOCA(buffer, length, format); /* default to following space */ - out_data_with_next_char(ctx, buffer, length); + write_data_with_next_char(ctx, buffer, length); ctx->next_char = WASM_NEXT_CHAR_SPACE; } -static void out_putc(WasmContext* ctx, char c) { - out_data(ctx, &c, 1); +static void write_putc(WasmContext* ctx, char c) { + wasm_write_data(&ctx->stream, &c, 1, NULL); } -static void out_puts(WasmContext* ctx, const char* s, WasmNextChar next_char) { +static void write_puts(WasmContext* ctx, + const char* s, + WasmNextChar next_char) { size_t len = strlen(s); - out_data_with_next_char(ctx, s, len); + write_data_with_next_char(ctx, s, len); ctx->next_char = next_char; } -static void out_puts_space(WasmContext* ctx, const char* s) { - out_puts(ctx, s, WASM_NEXT_CHAR_SPACE); +static void write_puts_space(WasmContext* ctx, const char* s) { + write_puts(ctx, s, WASM_NEXT_CHAR_SPACE); } -static void out_newline(WasmContext* ctx, WasmBool force) { +static void write_newline(WasmContext* ctx, WasmBool force) { if (ctx->next_char == WASM_NEXT_CHAR_FORCE_NEWLINE) - out_next_char(ctx); + write_next_char(ctx); ctx->next_char = force ? WASM_NEXT_CHAR_FORCE_NEWLINE : WASM_NEXT_CHAR_NEWLINE; } -static void out_open(WasmContext* ctx, - const char* name, - WasmNextChar next_char) { - out_puts(ctx, "(", WASM_NEXT_CHAR_NONE); - out_puts(ctx, name, next_char); +static void write_open(WasmContext* ctx, + const char* name, + WasmNextChar next_char) { + write_puts(ctx, "(", WASM_NEXT_CHAR_NONE); + write_puts(ctx, name, next_char); indent(ctx); } -static void out_open_newline(WasmContext* ctx, const char* name) { - out_open(ctx, name, WASM_NEXT_CHAR_NEWLINE); +static void write_open_newline(WasmContext* ctx, const char* name) { + write_open(ctx, name, WASM_NEXT_CHAR_NEWLINE); } -static void out_open_space(WasmContext* ctx, const char* name) { - out_open(ctx, name, WASM_NEXT_CHAR_SPACE); +static void write_open_space(WasmContext* ctx, const char* name) { + write_open(ctx, name, WASM_NEXT_CHAR_SPACE); } -static void out_close(WasmContext* ctx, WasmNextChar next_char) { +static void write_close(WasmContext* ctx, WasmNextChar next_char) { if (ctx->next_char != WASM_NEXT_CHAR_FORCE_NEWLINE) ctx->next_char = WASM_NEXT_CHAR_NONE; dedent(ctx); - out_puts(ctx, ")", next_char); + write_puts(ctx, ")", next_char); } -static void out_close_newline(WasmContext* ctx) { - out_close(ctx, WASM_NEXT_CHAR_NEWLINE); +static void write_close_newline(WasmContext* ctx) { + write_close(ctx, WASM_NEXT_CHAR_NEWLINE); } -static void out_close_space(WasmContext* ctx) { - out_close(ctx, WASM_NEXT_CHAR_SPACE); +static void write_close_space(WasmContext* ctx) { + write_close(ctx, WASM_NEXT_CHAR_SPACE); } -static void out_string_slice(WasmContext* ctx, - const WasmStringSlice* str, - WasmNextChar next_char) { - out_printf(ctx, PRIstringslice, WASM_PRINTF_STRING_SLICE_ARG(*str)); +static void write_string_slice(WasmContext* ctx, + const WasmStringSlice* str, + WasmNextChar next_char) { + writef(ctx, PRIstringslice, WASM_PRINTF_STRING_SLICE_ARG(*str)); ctx->next_char = next_char; } -static WasmBool out_string_slice_opt(WasmContext* ctx, - const WasmStringSlice* str, - WasmNextChar next_char) { +static WasmBool write_string_slice_opt(WasmContext* ctx, + const WasmStringSlice* str, + WasmNextChar next_char) { if (str->start) - out_string_slice(ctx, str, next_char); + write_string_slice(ctx, str, next_char); return str->start ? WASM_TRUE : WASM_FALSE; } -static void out_string_slice_or_index(WasmContext* ctx, - const WasmStringSlice* str, - uint32_t index, - WasmNextChar next_char) { +static void write_string_slice_or_index(WasmContext* ctx, + const WasmStringSlice* str, + uint32_t index, + WasmNextChar next_char) { if (str->start) - out_string_slice(ctx, str, next_char); + write_string_slice(ctx, str, next_char); else - out_printf(ctx, "(;%u;)", index); + writef(ctx, "(;%u;)", index); } -static void out_quoted_data(WasmContext* ctx, const void* data, size_t length) { +static void write_quoted_data(WasmContext* ctx, + const void* data, + size_t length) { const uint8_t* u8_data = data; static const char s_hexdigits[] = "0123456789abcdef"; - out_next_char(ctx); - out_putc(ctx, '\"'); + write_next_char(ctx); + write_putc(ctx, '\"'); size_t i; for (i = 0; i < length; ++i) { uint8_t c = u8_data[i]; if (s_is_char_escaped[c]) { - out_putc(ctx, '\\'); - out_putc(ctx, s_hexdigits[c >> 4]); - out_putc(ctx, s_hexdigits[c & 0xf]); + write_putc(ctx, '\\'); + write_putc(ctx, s_hexdigits[c >> 4]); + write_putc(ctx, s_hexdigits[c & 0xf]); } else { - out_putc(ctx, c); + write_putc(ctx, c); } } - out_putc(ctx, '\"'); + write_putc(ctx, '\"'); ctx->next_char = WASM_NEXT_CHAR_SPACE; } -static void out_quoted_string_slice(WasmContext* ctx, - const WasmStringSlice* str, - WasmNextChar next_char) { - out_quoted_data(ctx, str->start, str->length); +static void write_quoted_string_slice(WasmContext* ctx, + const WasmStringSlice* str, + WasmNextChar next_char) { + write_quoted_data(ctx, str->start, str->length); ctx->next_char = next_char; } -static void out_var(WasmContext* ctx, - const WasmVar* var, - WasmNextChar next_char) { +static void write_var(WasmContext* ctx, + const WasmVar* var, + WasmNextChar next_char) { if (var->type == WASM_VAR_TYPE_INDEX) { - out_printf(ctx, "%d", var->index); + writef(ctx, "%d", var->index); ctx->next_char = next_char; } else { - out_string_slice(ctx, &var->name, next_char); + write_string_slice(ctx, &var->name, next_char); } } -static void out_br_var(WasmContext* ctx, - const WasmVar* var, - WasmNextChar next_char) { +static void write_br_var(WasmContext* ctx, + const WasmVar* var, + WasmNextChar next_char) { if (var->type == WASM_VAR_TYPE_INDEX) { - out_printf(ctx, "%d (;@%d;)", var->index, ctx->depth - var->index - 1); + writef(ctx, "%d (;@%d;)", var->index, ctx->depth - var->index - 1); ctx->next_char = next_char; } else { - out_string_slice(ctx, &var->name, next_char); + write_string_slice(ctx, &var->name, next_char); } } -static void out_type(WasmContext* ctx, WasmType type, WasmNextChar next_char) { +static void write_type(WasmContext* ctx, + WasmType type, + WasmNextChar next_char) { static const char* s_types[] = {NULL, "i32", "i64", "f32", "f64"}; - out_puts(ctx, s_types[type], next_char); + write_puts(ctx, s_types[type], next_char); } -static void out_func_sig_space(WasmContext* ctx, - const WasmFuncSignature* func_sig) { +static void write_func_sig_space(WasmContext* ctx, + const WasmFuncSignature* func_sig) { if (func_sig->param_types.size) { size_t i; - out_open_space(ctx, "param"); + write_open_space(ctx, "param"); for (i = 0; i < func_sig->param_types.size; ++i) { - out_type(ctx, func_sig->param_types.data[i], WASM_NEXT_CHAR_SPACE); + write_type(ctx, func_sig->param_types.data[i], WASM_NEXT_CHAR_SPACE); } - out_close_space(ctx); + write_close_space(ctx); } if (func_sig->result_type != WASM_TYPE_VOID) { - out_open_space(ctx, "result"); - out_type(ctx, func_sig->result_type, WASM_NEXT_CHAR_NONE); - out_close_space(ctx); + write_open_space(ctx, "result"); + write_type(ctx, func_sig->result_type, WASM_NEXT_CHAR_NONE); + write_close_space(ctx); } } @@ -308,14 +297,14 @@ static void write_expr(WasmContext* ctx, const WasmExpr* expr); static void write_block(WasmContext* ctx, const WasmBlock* block, const char* text) { - out_open_space(ctx, text); - if (!out_string_slice_opt(ctx, &block->label, WASM_NEXT_CHAR_SPACE)) - out_printf(ctx, " ;; exit = @%d", ctx->depth); - out_newline(ctx, FORCE_NEWLINE); + write_open_space(ctx, text); + if (!write_string_slice_opt(ctx, &block->label, WASM_NEXT_CHAR_SPACE)) + writef(ctx, " ;; exit = @%d", ctx->depth); + write_newline(ctx, FORCE_NEWLINE); ctx->depth++; write_exprs(ctx, &block->exprs); ctx->depth--; - out_close_newline(ctx); + write_close_newline(ctx); } /* TODO(binji): remove all this if-block stuff when we switch to postorder */ @@ -336,8 +325,8 @@ static void write_if_branch(WasmContext* ctx, const char* text) { switch (type) { case WASM_IF_BRANCH_TYPE_ONE_EXPRESSION: - out_printf(ctx, ";; exit = @%d", ctx->depth); - out_newline(ctx, FORCE_NEWLINE); + writef(ctx, ";; exit = @%d", ctx->depth); + write_newline(ctx, FORCE_NEWLINE); ctx->depth++; write_expr(ctx, expr); ctx->depth--; @@ -346,13 +335,13 @@ static void write_if_branch(WasmContext* ctx, if (expr->type == WASM_EXPR_TYPE_BLOCK) { write_block(ctx, &expr->block, text); } else { - out_open_space(ctx, text); - out_printf(ctx, " ;; exit = @%d", ctx->depth); - out_newline(ctx, FORCE_NEWLINE); + write_open_space(ctx, text); + writef(ctx, " ;; exit = @%d", ctx->depth); + write_newline(ctx, FORCE_NEWLINE); ctx->depth++; write_expr(ctx, expr); ctx->depth--; - out_close_newline(ctx); + write_close_newline(ctx); } break; default: @@ -364,32 +353,32 @@ static void write_if_branch(WasmContext* ctx, static void write_const(WasmContext* ctx, const WasmConst* const_) { switch (const_->type) { case WASM_TYPE_I32: - out_open_space(ctx, s_opcode_name[WASM_OPCODE_I32_CONST]); - out_printf(ctx, "%d", (int32_t)const_->u32); - out_close_newline(ctx); + write_open_space(ctx, s_opcode_name[WASM_OPCODE_I32_CONST]); + writef(ctx, "%d", (int32_t)const_->u32); + write_close_newline(ctx); break; case WASM_TYPE_I64: - out_open_space(ctx, s_opcode_name[WASM_OPCODE_I64_CONST]); - out_printf(ctx, "%" PRId64, (int64_t)const_->u64); - out_close_newline(ctx); + write_open_space(ctx, s_opcode_name[WASM_OPCODE_I64_CONST]); + writef(ctx, "%" PRId64, (int64_t)const_->u64); + write_close_newline(ctx); break; case WASM_TYPE_F32: { - out_open_space(ctx, s_opcode_name[WASM_OPCODE_F32_CONST]); + write_open_space(ctx, s_opcode_name[WASM_OPCODE_F32_CONST]); char buffer[128]; wasm_write_float_hex(buffer, 128, const_->f32_bits); - out_puts_space(ctx, buffer); - out_close_newline(ctx); + write_puts_space(ctx, buffer); + write_close_newline(ctx); break; } case WASM_TYPE_F64: { - out_open_space(ctx, s_opcode_name[WASM_OPCODE_F64_CONST]); + write_open_space(ctx, s_opcode_name[WASM_OPCODE_F64_CONST]); char buffer[128]; wasm_write_double_hex(buffer, 128, const_->f64_bits); - out_puts_space(ctx, buffer); - out_close_newline(ctx); + write_puts_space(ctx, buffer); + write_close_newline(ctx); break; } @@ -402,10 +391,10 @@ static void write_const(WasmContext* ctx, const WasmConst* const_) { static void write_expr(WasmContext* ctx, const WasmExpr* expr) { switch (expr->type) { case WASM_EXPR_TYPE_BINARY: - out_open_newline(ctx, s_opcode_name[expr->binary.opcode]); + write_open_newline(ctx, s_opcode_name[expr->binary.opcode]); write_expr(ctx, expr->binary.left); write_expr(ctx, expr->binary.right); - out_close_newline(ctx); + write_close_newline(ctx); break; case WASM_EXPR_TYPE_BLOCK: @@ -413,69 +402,70 @@ static void write_expr(WasmContext* ctx, const WasmExpr* expr) { break; case WASM_EXPR_TYPE_BR: - out_open_space(ctx, s_opcode_name[WASM_OPCODE_BR]); - out_br_var(ctx, &expr->br.var, WASM_NEXT_CHAR_NEWLINE); + write_open_space(ctx, s_opcode_name[WASM_OPCODE_BR]); + write_br_var(ctx, &expr->br.var, WASM_NEXT_CHAR_NEWLINE); if (expr->br.expr && expr->br.expr->type != WASM_EXPR_TYPE_NOP) write_expr(ctx, expr->br.expr); - out_close_newline(ctx); + write_close_newline(ctx); break; case WASM_EXPR_TYPE_BR_IF: - out_open_space(ctx, s_opcode_name[WASM_OPCODE_BR_IF]); - out_br_var(ctx, &expr->br_if.var, WASM_NEXT_CHAR_NEWLINE); + write_open_space(ctx, s_opcode_name[WASM_OPCODE_BR_IF]); + write_br_var(ctx, &expr->br_if.var, WASM_NEXT_CHAR_NEWLINE); if (expr->br_if.expr && expr->br_if.expr->type != WASM_EXPR_TYPE_NOP) write_expr(ctx, expr->br_if.expr); write_expr(ctx, expr->br_if.cond); - out_close_newline(ctx); + write_close_newline(ctx); break; case WASM_EXPR_TYPE_BR_TABLE: { - out_open_newline(ctx, s_opcode_name[WASM_OPCODE_BR_TABLE]); + write_open_newline(ctx, s_opcode_name[WASM_OPCODE_BR_TABLE]); size_t i; for (i = 0; i < expr->br_table.targets.size; ++i) - out_br_var(ctx, &expr->br_table.targets.data[i], WASM_NEXT_CHAR_SPACE); - out_br_var(ctx, &expr->br_table.default_target, WASM_NEXT_CHAR_NEWLINE); + write_br_var(ctx, &expr->br_table.targets.data[i], + WASM_NEXT_CHAR_SPACE); + write_br_var(ctx, &expr->br_table.default_target, WASM_NEXT_CHAR_NEWLINE); write_expr(ctx, expr->br_table.expr); - out_close_newline(ctx); + write_close_newline(ctx); break; } case WASM_EXPR_TYPE_CALL: { - out_open_space(ctx, s_opcode_name[WASM_OPCODE_CALL_FUNCTION]); - out_var(ctx, &expr->call.var, WASM_NEXT_CHAR_NEWLINE); + write_open_space(ctx, s_opcode_name[WASM_OPCODE_CALL_FUNCTION]); + write_var(ctx, &expr->call.var, WASM_NEXT_CHAR_NEWLINE); size_t i; for (i = 0; i < expr->call.args.size; ++i) write_expr(ctx, expr->call.args.data[i]); - out_close_newline(ctx); + write_close_newline(ctx); break; } case WASM_EXPR_TYPE_CALL_IMPORT: { - out_open_space(ctx, s_opcode_name[WASM_OPCODE_CALL_IMPORT]); - out_var(ctx, &expr->call.var, WASM_NEXT_CHAR_NEWLINE); + write_open_space(ctx, s_opcode_name[WASM_OPCODE_CALL_IMPORT]); + write_var(ctx, &expr->call.var, WASM_NEXT_CHAR_NEWLINE); size_t i; for (i = 0; i < expr->call.args.size; ++i) write_expr(ctx, expr->call.args.data[i]); - out_close_newline(ctx); + write_close_newline(ctx); break; } case WASM_EXPR_TYPE_CALL_INDIRECT: { - out_open_space(ctx, s_opcode_name[WASM_OPCODE_CALL_INDIRECT]); - out_var(ctx, &expr->call_indirect.var, WASM_NEXT_CHAR_NEWLINE); + write_open_space(ctx, s_opcode_name[WASM_OPCODE_CALL_INDIRECT]); + write_var(ctx, &expr->call_indirect.var, WASM_NEXT_CHAR_NEWLINE); write_expr(ctx, expr->call_indirect.expr); size_t i; for (i = 0; i < expr->call_indirect.args.size; ++i) write_expr(ctx, expr->call_indirect.args.data[i]); - out_close_newline(ctx); + write_close_newline(ctx); break; } case WASM_EXPR_TYPE_COMPARE: - out_open_newline(ctx, s_opcode_name[expr->compare.opcode]); + write_open_newline(ctx, s_opcode_name[expr->compare.opcode]); write_expr(ctx, expr->compare.left); write_expr(ctx, expr->compare.right); - out_close_newline(ctx); + write_close_newline(ctx); break; case WASM_EXPR_TYPE_CONST: @@ -483,34 +473,34 @@ static void write_expr(WasmContext* ctx, const WasmExpr* expr) { break; case WASM_EXPR_TYPE_CONVERT: - out_open_newline(ctx, s_opcode_name[expr->convert.opcode]); + write_open_newline(ctx, s_opcode_name[expr->convert.opcode]); write_expr(ctx, expr->convert.expr); - out_close_newline(ctx); + write_close_newline(ctx); break; case WASM_EXPR_TYPE_GET_LOCAL: - out_open_space(ctx, s_opcode_name[WASM_OPCODE_GET_LOCAL]); - out_var(ctx, &expr->get_local.var, WASM_NEXT_CHAR_NONE); - out_close_newline(ctx); + write_open_space(ctx, s_opcode_name[WASM_OPCODE_GET_LOCAL]); + write_var(ctx, &expr->get_local.var, WASM_NEXT_CHAR_NONE); + write_close_newline(ctx); break; case WASM_EXPR_TYPE_GROW_MEMORY: - out_open_newline(ctx, s_opcode_name[WASM_OPCODE_GROW_MEMORY]); + write_open_newline(ctx, s_opcode_name[WASM_OPCODE_GROW_MEMORY]); write_expr(ctx, expr->grow_memory.expr); - out_close_newline(ctx); + write_close_newline(ctx); break; case WASM_EXPR_TYPE_IF: { - out_open_newline(ctx, s_opcode_name[WASM_OPCODE_IF]); + write_open_newline(ctx, s_opcode_name[WASM_OPCODE_IF]); write_expr(ctx, expr->if_.cond); WriteIfBranchType true_type = get_if_branch_type(expr->if_.true_); write_if_branch(ctx, true_type, expr->if_.true_, "then"); - out_close_newline(ctx); + write_close_newline(ctx); break; } case WASM_EXPR_TYPE_IF_ELSE: { - out_open_newline(ctx, s_opcode_name[WASM_OPCODE_IF]); + write_open_newline(ctx, s_opcode_name[WASM_OPCODE_IF]); write_expr(ctx, expr->if_else.cond); /* silly dance to make sure that we don't use mismatching format for @@ -527,96 +517,96 @@ static void write_expr(WasmContext* ctx, const WasmExpr* expr) { write_if_branch(ctx, true_type, expr->if_else.true_, "then"); write_if_branch(ctx, false_type, expr->if_else.false_, "else"); - out_close_newline(ctx); + write_close_newline(ctx); break; } case WASM_EXPR_TYPE_LOAD: - out_open_space(ctx, s_opcode_name[expr->load.opcode]); + write_open_space(ctx, s_opcode_name[expr->load.opcode]); if (expr->load.offset) - out_printf(ctx, "offset=%" PRIu64, expr->load.offset); + writef(ctx, "offset=%" PRIu64, expr->load.offset); if (!wasm_is_naturally_aligned(expr->load.opcode, expr->load.align)) - out_printf(ctx, "align=%u", expr->load.align); - out_newline(ctx, NO_FORCE_NEWLINE); + writef(ctx, "align=%u", expr->load.align); + write_newline(ctx, NO_FORCE_NEWLINE); write_expr(ctx, expr->load.addr); - out_close_newline(ctx); + write_close_newline(ctx); break; case WASM_EXPR_TYPE_LOOP: { - out_open_space(ctx, s_opcode_name[WASM_OPCODE_LOOP]); + write_open_space(ctx, s_opcode_name[WASM_OPCODE_LOOP]); WasmBool has_outer_name = - out_string_slice_opt(ctx, &expr->loop.outer, WASM_NEXT_CHAR_SPACE); + write_string_slice_opt(ctx, &expr->loop.outer, WASM_NEXT_CHAR_SPACE); WasmBool has_inner_name = - out_string_slice_opt(ctx, &expr->loop.inner, WASM_NEXT_CHAR_SPACE); + write_string_slice_opt(ctx, &expr->loop.inner, WASM_NEXT_CHAR_SPACE); if (!has_outer_name || !has_inner_name) { - out_printf(ctx, " ;;"); + writef(ctx, " ;;"); if (!has_outer_name) - out_printf(ctx, "exit = @%d", ctx->depth); + writef(ctx, "exit = @%d", ctx->depth); if (!has_inner_name) { - out_printf(ctx, "cont = @%d", ctx->depth + 1); + writef(ctx, "cont = @%d", ctx->depth + 1); } } - out_newline(ctx, FORCE_NEWLINE); + write_newline(ctx, FORCE_NEWLINE); ctx->depth += 2; write_exprs(ctx, &expr->loop.exprs); ctx->depth -= 2; - out_close_newline(ctx); + write_close_newline(ctx); break; } case WASM_EXPR_TYPE_MEMORY_SIZE: - out_open_space(ctx, s_opcode_name[WASM_OPCODE_MEMORY_SIZE]); - out_close_newline(ctx); + write_open_space(ctx, s_opcode_name[WASM_OPCODE_MEMORY_SIZE]); + write_close_newline(ctx); break; case WASM_EXPR_TYPE_NOP: - out_open_space(ctx, s_opcode_name[WASM_OPCODE_NOP]); - out_close_newline(ctx); + write_open_space(ctx, s_opcode_name[WASM_OPCODE_NOP]); + write_close_newline(ctx); break; case WASM_EXPR_TYPE_RETURN: - out_open_newline(ctx, s_opcode_name[WASM_OPCODE_RETURN]); + write_open_newline(ctx, s_opcode_name[WASM_OPCODE_RETURN]); if (expr->return_.expr) write_expr(ctx, expr->return_.expr); - out_close_newline(ctx); + write_close_newline(ctx); break; case WASM_EXPR_TYPE_SELECT: - out_open_newline(ctx, s_opcode_name[WASM_OPCODE_SELECT]); + write_open_newline(ctx, s_opcode_name[WASM_OPCODE_SELECT]); write_expr(ctx, expr->select.true_); write_expr(ctx, expr->select.false_); write_expr(ctx, expr->select.cond); - out_close_newline(ctx); + write_close_newline(ctx); break; case WASM_EXPR_TYPE_SET_LOCAL: - out_open_space(ctx, s_opcode_name[WASM_OPCODE_SET_LOCAL]); - out_var(ctx, &expr->set_local.var, WASM_NEXT_CHAR_NEWLINE); + write_open_space(ctx, s_opcode_name[WASM_OPCODE_SET_LOCAL]); + write_var(ctx, &expr->set_local.var, WASM_NEXT_CHAR_NEWLINE); write_expr(ctx, expr->set_local.expr); - out_close_newline(ctx); + write_close_newline(ctx); break; case WASM_EXPR_TYPE_STORE: - out_open_space(ctx, s_opcode_name[expr->store.opcode]); + write_open_space(ctx, s_opcode_name[expr->store.opcode]); if (expr->store.offset) - out_printf(ctx, "offset=%" PRIu64, expr->store.offset); + writef(ctx, "offset=%" PRIu64, expr->store.offset); if (!wasm_is_naturally_aligned(expr->store.opcode, expr->store.align)) - out_printf(ctx, "align=%u", expr->store.align); - out_newline(ctx, NO_FORCE_NEWLINE); + writef(ctx, "align=%u", expr->store.align); + write_newline(ctx, NO_FORCE_NEWLINE); write_expr(ctx, expr->store.addr); write_expr(ctx, expr->store.value); - out_close_newline(ctx); + write_close_newline(ctx); break; case WASM_EXPR_TYPE_UNARY: - out_open_newline(ctx, s_opcode_name[expr->unary.opcode]); + write_open_newline(ctx, s_opcode_name[expr->unary.opcode]); write_expr(ctx, expr->unary.expr); - out_close_newline(ctx); + write_close_newline(ctx); break; case WASM_EXPR_TYPE_UNREACHABLE: - out_open_space(ctx, s_opcode_name[WASM_OPCODE_UNREACHABLE]); - out_close_newline(ctx); + write_open_space(ctx, s_opcode_name[WASM_OPCODE_UNREACHABLE]); + write_close_newline(ctx); break; default: @@ -649,138 +639,139 @@ static void write_type_bindings(WasmContext* ctx, size_t i; for (i = 0; i < types->size; ++i) { if (!is_open) { - out_open_space(ctx, prefix); + write_open_space(ctx, prefix); is_open = WASM_TRUE; } const WasmStringSlice* name = &ctx->index_to_name.data[i]; WasmBool has_name = name->start != NULL; if (has_name) - out_string_slice(ctx, name, WASM_NEXT_CHAR_SPACE); - out_type(ctx, types->data[i], WASM_NEXT_CHAR_SPACE); + write_string_slice(ctx, name, WASM_NEXT_CHAR_SPACE); + write_type(ctx, types->data[i], WASM_NEXT_CHAR_SPACE); if (has_name) { - out_close_space(ctx); + write_close_space(ctx); is_open = WASM_FALSE; } } if (is_open) - out_close_space(ctx); + write_close_space(ctx); } static void write_func(WasmContext* ctx, const WasmModule* module, int func_index, const WasmFunc* func) { - out_open_space(ctx, "func"); - out_string_slice_or_index(ctx, &func->name, func_index, WASM_NEXT_CHAR_SPACE); + write_open_space(ctx, "func"); + write_string_slice_or_index(ctx, &func->name, func_index, + WASM_NEXT_CHAR_SPACE); if (wasm_decl_has_func_type(&func->decl)) { - out_open_space(ctx, "type"); - out_var(ctx, &func->decl.type_var, WASM_NEXT_CHAR_NONE); - out_close_space(ctx); + write_open_space(ctx, "type"); + write_var(ctx, &func->decl.type_var, WASM_NEXT_CHAR_NONE); + write_close_space(ctx); } if (wasm_decl_has_signature(&func->decl)) { write_type_bindings(ctx, "param", func, &func->decl.sig.param_types, &func->param_bindings); if (wasm_get_result_type(func) != WASM_TYPE_VOID) { - out_open_space(ctx, "result"); - out_type(ctx, wasm_get_result_type(func), WASM_NEXT_CHAR_NONE); - out_close_space(ctx); + write_open_space(ctx, "result"); + write_type(ctx, wasm_get_result_type(func), WASM_NEXT_CHAR_NONE); + write_close_space(ctx); } } - out_newline(ctx, NO_FORCE_NEWLINE); + write_newline(ctx, NO_FORCE_NEWLINE); if (func->local_types.size) { write_type_bindings(ctx, "local", func, &func->local_types, &func->local_bindings); } - out_newline(ctx, NO_FORCE_NEWLINE); + write_newline(ctx, NO_FORCE_NEWLINE); write_exprs(ctx, &func->exprs); - out_close_newline(ctx); + write_close_newline(ctx); } static void write_import(WasmContext* ctx, int import_index, const WasmImport* import) { - out_open_space(ctx, "import"); - out_string_slice_or_index(ctx, &import->name, import_index, - WASM_NEXT_CHAR_SPACE); - out_quoted_string_slice(ctx, &import->module_name, WASM_NEXT_CHAR_SPACE); - out_quoted_string_slice(ctx, &import->func_name, WASM_NEXT_CHAR_SPACE); + write_open_space(ctx, "import"); + write_string_slice_or_index(ctx, &import->name, import_index, + WASM_NEXT_CHAR_SPACE); + write_quoted_string_slice(ctx, &import->module_name, WASM_NEXT_CHAR_SPACE); + write_quoted_string_slice(ctx, &import->func_name, WASM_NEXT_CHAR_SPACE); if (wasm_decl_has_func_type(&import->decl)) { - out_open_space(ctx, "type"); - out_var(ctx, &import->decl.type_var, WASM_NEXT_CHAR_NONE); - out_close_space(ctx); + write_open_space(ctx, "type"); + write_var(ctx, &import->decl.type_var, WASM_NEXT_CHAR_NONE); + write_close_space(ctx); } else { - out_func_sig_space(ctx, &import->decl.sig); + write_func_sig_space(ctx, &import->decl.sig); } - out_close_newline(ctx); + write_close_newline(ctx); } static void write_export(WasmContext* ctx, int export_index, const WasmExport* export) { - out_open_space(ctx, "export"); - out_quoted_string_slice(ctx, &export->name, WASM_NEXT_CHAR_SPACE); - out_var(ctx, &export->var, WASM_NEXT_CHAR_SPACE); - out_close_newline(ctx); + write_open_space(ctx, "export"); + write_quoted_string_slice(ctx, &export->name, WASM_NEXT_CHAR_SPACE); + write_var(ctx, &export->var, WASM_NEXT_CHAR_SPACE); + write_close_newline(ctx); } static void write_export_memory(WasmContext* ctx, const WasmExportMemory* export) { - out_open_space(ctx, "export"); - out_quoted_string_slice(ctx, &export->name, WASM_NEXT_CHAR_SPACE); - out_puts_space(ctx, "memory"); - out_close_newline(ctx); + write_open_space(ctx, "export"); + write_quoted_string_slice(ctx, &export->name, WASM_NEXT_CHAR_SPACE); + write_puts_space(ctx, "memory"); + write_close_newline(ctx); } static void write_table(WasmContext* ctx, const WasmVarVector* table) { - out_open_space(ctx, "table"); + write_open_space(ctx, "table"); size_t i; for (i = 0; i < table->size; ++i) - out_var(ctx, &table->data[i], WASM_NEXT_CHAR_SPACE); - out_close_newline(ctx); + write_var(ctx, &table->data[i], WASM_NEXT_CHAR_SPACE); + write_close_newline(ctx); } static void write_segment(WasmContext* ctx, const WasmSegment* segment) { - out_open_space(ctx, "segment"); - out_printf(ctx, "%u", segment->addr); - out_quoted_data(ctx, segment->data, segment->size); - out_close_newline(ctx); + write_open_space(ctx, "segment"); + writef(ctx, "%u", segment->addr); + write_quoted_data(ctx, segment->data, segment->size); + write_close_newline(ctx); } static void write_memory(WasmContext* ctx, const WasmMemory* memory) { - out_open_space(ctx, "memory"); - out_printf(ctx, "%u", memory->initial_pages); + write_open_space(ctx, "memory"); + writef(ctx, "%u", memory->initial_pages); if (memory->initial_pages != memory->max_pages) - out_printf(ctx, "%u", memory->max_pages); - out_newline(ctx, NO_FORCE_NEWLINE); + writef(ctx, "%u", memory->max_pages); + write_newline(ctx, NO_FORCE_NEWLINE); size_t i; for (i = 0; i < memory->segments.size; ++i) { const WasmSegment* segment = &memory->segments.data[i]; write_segment(ctx, segment); } - out_close_newline(ctx); + write_close_newline(ctx); } static void write_func_type(WasmContext* ctx, int func_type_index, const WasmFuncType* func_type) { - out_open_space(ctx, "type"); - out_string_slice_or_index(ctx, &func_type->name, func_type_index, - WASM_NEXT_CHAR_SPACE); - out_open_space(ctx, "func"); - out_func_sig_space(ctx, &func_type->sig); - out_close_space(ctx); - out_close_newline(ctx); + write_open_space(ctx, "type"); + write_string_slice_or_index(ctx, &func_type->name, func_type_index, + WASM_NEXT_CHAR_SPACE); + write_open_space(ctx, "func"); + write_func_sig_space(ctx, &func_type->sig); + write_close_space(ctx); + write_close_newline(ctx); } static void write_start_function(WasmContext* ctx, const WasmVar* start) { - out_open_space(ctx, "start"); - out_var(ctx, start, WASM_NEXT_CHAR_NONE); - out_close_newline(ctx); + write_open_space(ctx, "start"); + write_var(ctx, start, WASM_NEXT_CHAR_NONE); + write_close_newline(ctx); } static void write_module(WasmContext* ctx, const WasmModule* module) { - out_open_newline(ctx, "module"); + write_open_newline(ctx, "module"); const WasmModuleField* field; int func_index = 0; int import_index = 0; @@ -814,9 +805,9 @@ static void write_module(WasmContext* ctx, const WasmModule* module) { break; } } - out_close_newline(ctx); + write_close_newline(ctx); /* force the newline to be written */ - out_next_char(ctx); + write_next_char(ctx); } WasmResult wasm_write_ast(WasmAllocator* allocator, @@ -826,7 +817,7 @@ WasmResult wasm_write_ast(WasmAllocator* allocator, WASM_ZERO_MEMORY(ctx); ctx.allocator = allocator; ctx.result = WASM_OK; - ctx.writer = writer; + wasm_init_stream(&ctx.stream, writer, NULL); write_module(&ctx, module); /* the memory for the actual string slice is shared with the module, so we * only need to free the vector */ diff --git a/src/wasm-binary-writer.c b/src/wasm-binary-writer.c index e3b3fc15..e713e92d 100644 --- a/src/wasm-binary-writer.c +++ b/src/wasm-binary-writer.c @@ -26,6 +26,7 @@ #include "wasm-ast.h" #include "wasm-binary.h" +#include "wasm-stream.h" #include "wasm-writer.h" #define PRINT_HEADER_NO_INDEX -1 @@ -35,13 +36,13 @@ #define ALLOC_FAILURE \ fprintf(stderr, "%s:%d: allocation failed\n", __FILE__, __LINE__) -#define CHECK_ALLOC_(cond) \ - do { \ - if (!(cond)) { \ - ALLOC_FAILURE; \ - ctx->result = WASM_ERROR; \ - return; \ - } \ +#define CHECK_ALLOC_(cond) \ + do { \ + if (!(cond)) { \ + ALLOC_FAILURE; \ + ctx->stream.result = WASM_ERROR; \ + return; \ + } \ } while (0) #define CHECK_ALLOC(e) CHECK_ALLOC_(WASM_SUCCEEDED(e)) @@ -72,12 +73,11 @@ typedef struct WasmLabelNode { typedef struct WasmContext { WasmAllocator* allocator; - WasmWriter* writer; - size_t writer_offset; + WasmStream stream; + WasmStream* log_stream; const WasmWriteBinaryOptions* options; WasmLabelNode* top_label; int max_depth; - WasmResult result; size_t last_section_offset; size_t last_section_leb_size_guess; @@ -96,79 +96,16 @@ static void destroy_func_signature_vector_and_elements( WASM_DESTROY_VECTOR_AND_ELEMENTS(allocator, *sigs, func_signature); } -static void print_header(WasmContext* ctx, const char* name, int index) { - if (ctx->options->log_writes) { +static void write_header(WasmContext* ctx, const char* name, int index) { + if (ctx->log_stream) { if (index == PRINT_HEADER_NO_INDEX) { - printf("; %s\n", name); + wasm_writef(ctx->log_stream, "; %s\n", name); } else { - printf("; %s %d\n", name, index); + wasm_writef(ctx->log_stream, "; %s %d\n", name, index); } } } -static void out_data_at(WasmContext* ctx, - size_t offset, - const void* src, - size_t size, - WasmPrintChars print_chars, - const char* desc) { - if (WASM_FAILED(ctx->result)) - return; - if (ctx->options->log_writes) - wasm_print_memory(src, size, offset, print_chars, desc); - if (ctx->writer->write_data) { - ctx->result = - ctx->writer->write_data(offset, src, size, ctx->writer->user_data); - } -} - -static void out_data(WasmContext* ctx, - const void* src, - size_t length, - const char* desc) { - out_data_at(ctx, ctx->writer_offset, src, length, 0, desc); - ctx->writer_offset += length; -} - -static void move_data(WasmContext* ctx, - size_t dst_offset, - size_t src_offset, - size_t size) { - if (WASM_FAILED(ctx->result)) - return; - if (ctx->options->log_writes) - printf("; move data: [%" PRIzx ", %" PRIzx ") -> [%" PRIzx ", %" PRIzx - ")\n", - src_offset, src_offset + size, dst_offset, dst_offset + size); - if (ctx->writer->write_data) { - ctx->result = ctx->writer->move_data(dst_offset, src_offset, size, - ctx->writer->user_data); - } -} - -static void out_u8(WasmContext* ctx, uint32_t value, const char* desc) { - assert(value <= UINT8_MAX); - uint8_t value8 = value; - out_data_at(ctx, ctx->writer_offset, &value8, sizeof(value8), - WASM_DONT_PRINT_CHARS, desc); - ctx->writer_offset += sizeof(value8); -} - -/* TODO(binji): endianness */ -static void out_u32(WasmContext* ctx, uint32_t value, const char* desc) { - out_data_at(ctx, ctx->writer_offset, &value, sizeof(value), - WASM_DONT_PRINT_CHARS, desc); - ctx->writer_offset += sizeof(value); -} - -static void out_u64(WasmContext* ctx, uint64_t value, const char* desc) { - out_data_at(ctx, ctx->writer_offset, &value, sizeof(value), - WASM_DONT_PRINT_CHARS, desc); - ctx->writer_offset += sizeof(value); -} - -#undef OUT_AT_TYPE - #define LEB128_LOOP_UNTIL(end_cond) \ do { \ uint8_t byte = value & 0x7f; \ @@ -182,39 +119,43 @@ static void out_u64(WasmContext* ctx, uint64_t value, const char* desc) { } while (1) /* returns the length of the leb128 */ -static uint32_t out_u32_leb128_at(WasmContext* ctx, - uint32_t offset, - uint32_t value, - const char* desc) { +static uint32_t write_u32_leb128_at(WasmStream* stream, + uint32_t offset, + uint32_t value, + const char* desc) { uint8_t data[MAX_U32_LEB128_BYTES]; uint32_t i = 0; LEB128_LOOP_UNTIL(value == 0); uint32_t length = i; - out_data_at(ctx, offset, data, length, WASM_DONT_PRINT_CHARS, desc); + wasm_write_data_at(stream, offset, data, length, WASM_DONT_PRINT_CHARS, desc); return length; } -static uint32_t out_fixed_u32_leb128_at(WasmContext* ctx, - uint32_t offset, - uint32_t value, - const char* desc) { +static uint32_t write_fixed_u32_leb128_at(WasmStream* stream, + uint32_t offset, + uint32_t value, + const char* desc) { uint8_t data[MAX_U32_LEB128_BYTES]; data[0] = (value & 0x7f) | 0x80; data[1] = ((value >> 7) & 0x7f) | 0x80; data[2] = ((value >> 14) & 0x7f) | 0x80; data[3] = ((value >> 21) & 0x7f) | 0x80; data[4] = ((value >> 28) & 0x0f); - out_data_at(ctx, offset, data, MAX_U32_LEB128_BYTES, WASM_DONT_PRINT_CHARS, - desc); + wasm_write_data_at(stream, offset, data, MAX_U32_LEB128_BYTES, + WASM_DONT_PRINT_CHARS, desc); return MAX_U32_LEB128_BYTES; } -static void out_u32_leb128(WasmContext* ctx, uint32_t value, const char* desc) { - uint32_t length = out_u32_leb128_at(ctx, ctx->writer_offset, value, desc); - ctx->writer_offset += length; +static void write_u32_leb128(WasmStream* stream, + uint32_t value, + const char* desc) { + uint32_t length = write_u32_leb128_at(stream, stream->offset, value, desc); + stream->offset += length; } -static void out_i32_leb128(WasmContext* ctx, int32_t value, const char* desc) { +static void write_i32_leb128(WasmStream* stream, + int32_t value, + const char* desc) { uint8_t data[MAX_U32_LEB128_BYTES]; uint32_t i = 0; if (value < 0) @@ -223,12 +164,14 @@ static void out_i32_leb128(WasmContext* ctx, int32_t value, const char* desc) { LEB128_LOOP_UNTIL(value == 0 && !(byte & 0x40)); uint32_t length = i; - out_data_at(ctx, ctx->writer_offset, data, length, WASM_DONT_PRINT_CHARS, - desc); - ctx->writer_offset += length; + wasm_write_data_at(stream, stream->offset, data, length, + WASM_DONT_PRINT_CHARS, desc); + stream->offset += length; } -static void out_i64_leb128(WasmContext* ctx, int64_t value, const char* desc) { +static void write_i64_leb128(WasmStream* stream, + int64_t value, + const char* desc) { uint8_t data[MAX_U64_LEB128_BYTES]; uint32_t i = 0; if (value < 0) @@ -237,9 +180,9 @@ static void out_i64_leb128(WasmContext* ctx, int64_t value, const char* desc) { LEB128_LOOP_UNTIL(value == 0 && !(byte & 0x40)); int length = i; - out_data_at(ctx, ctx->writer_offset, data, length, WASM_DONT_PRINT_CHARS, - desc); - ctx->writer_offset += length; + wasm_write_data_at(stream, stream->offset, data, length, + WASM_DONT_PRINT_CHARS, desc); + stream->offset += length; } #undef LEB128_LOOP_UNTIL @@ -254,50 +197,50 @@ static uint32_t size_u32_leb128(uint32_t value) { } /* returns offset of leb128 */ -static uint32_t out_u32_leb128_space(WasmContext* ctx, - uint32_t leb_size_guess, - const char* desc) { +static uint32_t write_u32_leb128_space(WasmContext* ctx, + uint32_t leb_size_guess, + const char* desc) { assert(leb_size_guess <= MAX_U32_LEB128_BYTES); uint8_t data[MAX_U32_LEB128_BYTES] = {0}; - uint32_t result = ctx->writer_offset; + uint32_t result = ctx->stream.offset; uint32_t bytes_to_write = ctx->options->canonicalize_lebs ? leb_size_guess : MAX_U32_LEB128_BYTES; - out_data(ctx, data, bytes_to_write, desc); + wasm_write_data(&ctx->stream, data, bytes_to_write, desc); return result; } -static void out_fixup_u32_leb128_size(WasmContext* ctx, - uint32_t offset, - uint32_t leb_size_guess, - const char* desc) { +static void write_fixup_u32_leb128_size(WasmContext* ctx, + uint32_t offset, + uint32_t leb_size_guess, + const char* desc) { if (ctx->options->canonicalize_lebs) { - uint32_t size = ctx->writer_offset - offset - leb_size_guess; + uint32_t size = ctx->stream.offset - offset - leb_size_guess; uint32_t leb_size = size_u32_leb128(size); if (leb_size != leb_size_guess) { uint32_t src_offset = offset + leb_size_guess; uint32_t dst_offset = offset + leb_size; - move_data(ctx, dst_offset, src_offset, size); + wasm_move_data(&ctx->stream, dst_offset, src_offset, size); } - out_u32_leb128_at(ctx, offset, size, desc); - ctx->writer_offset += leb_size - leb_size_guess; + write_u32_leb128_at(&ctx->stream, offset, size, desc); + ctx->stream.offset += leb_size - leb_size_guess; } else { - uint32_t size = ctx->writer_offset - offset - MAX_U32_LEB128_BYTES; - out_fixed_u32_leb128_at(ctx, offset, size, desc); + uint32_t size = ctx->stream.offset - offset - MAX_U32_LEB128_BYTES; + write_fixed_u32_leb128_at(&ctx->stream, offset, size, desc); } } -static void out_str(WasmContext* ctx, - const char* s, - size_t length, - WasmPrintChars print_chars, - const char* desc) { - out_u32_leb128(ctx, length, "string length"); - out_data_at(ctx, ctx->writer_offset, s, length, print_chars, desc); - ctx->writer_offset += length; +static void write_str(WasmStream* stream, + const char* s, + size_t length, + WasmPrintChars print_chars, + const char* desc) { + write_u32_leb128(stream, length, "string length"); + wasm_write_data_at(stream, stream->offset, s, length, print_chars, desc); + stream->offset += length; } -static void out_opcode(WasmContext* ctx, uint8_t opcode) { - out_u8(ctx, opcode, s_opcode_name[opcode]); +static void write_opcode(WasmStream* stream, uint8_t opcode) { + wasm_write_u8(stream, opcode, s_opcode_name[opcode]); } static void begin_section(WasmContext* ctx, @@ -306,19 +249,19 @@ static void begin_section(WasmContext* ctx, assert(ctx->last_section_leb_size_guess == 0); char desc[100]; wasm_snprintf(desc, sizeof(desc), "section \"%s\"", name); - print_header(ctx, desc, PRINT_HEADER_NO_INDEX); + write_header(ctx, desc, PRINT_HEADER_NO_INDEX); ctx->last_section_offset = - out_u32_leb128_space(ctx, leb_size_guess, "section size (guess)"); + write_u32_leb128_space(ctx, leb_size_guess, "section size (guess)"); ctx->last_section_leb_size_guess = leb_size_guess; wasm_snprintf(desc, sizeof(desc), "section id: \"%s\"", name); - out_str(ctx, name, strlen(name), WASM_DONT_PRINT_CHARS, desc); + write_str(&ctx->stream, name, strlen(name), WASM_DONT_PRINT_CHARS, desc); } static void end_section(WasmContext* ctx) { assert(ctx->last_section_leb_size_guess != 0); - out_fixup_u32_leb128_size(ctx, ctx->last_section_offset, - ctx->last_section_leb_size_guess, - "FIXUP section size"); + write_fixup_u32_leb128_size(ctx, ctx->last_section_offset, + ctx->last_section_leb_size_guess, + "FIXUP section size"); ctx->last_section_leb_size_guess = 0; } @@ -545,7 +488,7 @@ static void write_expr(WasmContext* ctx, const WasmExpr* expr) { switch (expr->type) { case WASM_EXPR_TYPE_BINARY: - out_opcode(ctx, expr->binary.opcode); + write_opcode(&ctx->stream, expr->binary.opcode); write_expr(ctx, module, func, expr->binary.left); write_expr(ctx, module, func, expr->binary.right); break; @@ -555,39 +498,41 @@ static void write_expr(WasmContext* ctx, case WASM_EXPR_TYPE_BR: { WasmLabelNode* node = find_label_by_var(ctx->top_label, &expr->br.var); assert(node); - out_opcode(ctx, WASM_OPCODE_BR); - out_u32_leb128(ctx, ctx->max_depth - node->depth - 1, "break depth"); + write_opcode(&ctx->stream, WASM_OPCODE_BR); + write_u32_leb128(&ctx->stream, ctx->max_depth - node->depth - 1, + "break depth"); if (expr->br.expr) write_expr(ctx, module, func, expr->br.expr); else - out_opcode(ctx, WASM_OPCODE_NOP); + write_opcode(&ctx->stream, WASM_OPCODE_NOP); break; } case WASM_EXPR_TYPE_BR_IF: { WasmLabelNode* node = find_label_by_var(ctx->top_label, &expr->br_if.var); assert(node); - out_opcode(ctx, WASM_OPCODE_BR_IF); - out_u32_leb128(ctx, ctx->max_depth - node->depth - 1, "break depth"); + write_opcode(&ctx->stream, WASM_OPCODE_BR_IF); + write_u32_leb128(&ctx->stream, ctx->max_depth - node->depth - 1, + "break depth"); if (expr->br_if.expr) write_expr(ctx, module, func, expr->br_if.expr); else - out_opcode(ctx, WASM_OPCODE_NOP); + write_opcode(&ctx->stream, WASM_OPCODE_NOP); write_expr(ctx, module, func, expr->br_if.cond); break; } case WASM_EXPR_TYPE_CALL: { int index = wasm_get_func_index_by_var(module, &expr->call.var); assert(index >= 0 && (size_t)index < module->funcs.size); - out_opcode(ctx, WASM_OPCODE_CALL_FUNCTION); - out_u32_leb128(ctx, index, "func index"); + write_opcode(&ctx->stream, WASM_OPCODE_CALL_FUNCTION); + write_u32_leb128(&ctx->stream, index, "func index"); write_expr_list(ctx, module, func, &expr->call.args); break; } case WASM_EXPR_TYPE_CALL_IMPORT: { int index = wasm_get_import_index_by_var(module, &expr->call.var); assert(index >= 0 && (size_t)index < module->imports.size); - out_opcode(ctx, WASM_OPCODE_CALL_IMPORT); - out_u32_leb128(ctx, index, "import index"); + write_opcode(&ctx->stream, WASM_OPCODE_CALL_IMPORT); + write_u32_leb128(&ctx->stream, index, "import index"); write_expr_list(ctx, module, func, &expr->call.args); break; } @@ -595,67 +540,70 @@ static void write_expr(WasmContext* ctx, int index = wasm_get_func_type_index_by_var(module, &expr->call_indirect.var); assert(index >= 0 && (size_t)index < module->func_types.size); - out_opcode(ctx, WASM_OPCODE_CALL_INDIRECT); - out_u32_leb128(ctx, index, "signature index"); + write_opcode(&ctx->stream, WASM_OPCODE_CALL_INDIRECT); + write_u32_leb128(&ctx->stream, index, "signature index"); write_expr(ctx, module, func, expr->call_indirect.expr); write_expr_list(ctx, module, func, &expr->call_indirect.args); break; } case WASM_EXPR_TYPE_COMPARE: - out_opcode(ctx, expr->compare.opcode); + write_opcode(&ctx->stream, expr->compare.opcode); write_expr(ctx, module, func, expr->compare.left); write_expr(ctx, module, func, expr->compare.right); break; case WASM_EXPR_TYPE_CONST: switch (expr->const_.type) { case WASM_TYPE_I32: { - out_opcode(ctx, WASM_OPCODE_I32_CONST); - out_i32_leb128(ctx, (int32_t)expr->const_.u32, "i32 literal"); + write_opcode(&ctx->stream, WASM_OPCODE_I32_CONST); + write_i32_leb128(&ctx->stream, (int32_t)expr->const_.u32, + "i32 literal"); break; } case WASM_TYPE_I64: - out_opcode(ctx, WASM_OPCODE_I64_CONST); - out_i64_leb128(ctx, (int64_t)expr->const_.u64, "i64 literal"); + write_opcode(&ctx->stream, WASM_OPCODE_I64_CONST); + write_i64_leb128(&ctx->stream, (int64_t)expr->const_.u64, + "i64 literal"); break; case WASM_TYPE_F32: - out_opcode(ctx, WASM_OPCODE_F32_CONST); - out_u32(ctx, expr->const_.f32_bits, "f32 literal"); + write_opcode(&ctx->stream, WASM_OPCODE_F32_CONST); + wasm_write_u32(&ctx->stream, expr->const_.f32_bits, "f32 literal"); break; case WASM_TYPE_F64: - out_opcode(ctx, WASM_OPCODE_F64_CONST); - out_u64(ctx, expr->const_.f64_bits, "f64 literal"); + write_opcode(&ctx->stream, WASM_OPCODE_F64_CONST); + wasm_write_u64(&ctx->stream, expr->const_.f64_bits, "f64 literal"); break; default: assert(0); } break; case WASM_EXPR_TYPE_CONVERT: - out_opcode(ctx, expr->convert.opcode); + write_opcode(&ctx->stream, expr->convert.opcode); write_expr(ctx, module, func, expr->convert.expr); break; case WASM_EXPR_TYPE_GET_LOCAL: { int index = wasm_get_local_index_by_var(func, &expr->get_local.var); - out_opcode(ctx, WASM_OPCODE_GET_LOCAL); - out_u32_leb128(ctx, ctx->remapped_locals[index], "remapped local index"); + write_opcode(&ctx->stream, WASM_OPCODE_GET_LOCAL); + write_u32_leb128(&ctx->stream, ctx->remapped_locals[index], + "remapped local index"); break; } case WASM_EXPR_TYPE_GROW_MEMORY: - out_opcode(ctx, WASM_OPCODE_GROW_MEMORY); + write_opcode(&ctx->stream, WASM_OPCODE_GROW_MEMORY); write_expr(ctx, module, func, expr->grow_memory.expr); break; case WASM_EXPR_TYPE_IF: - out_opcode(ctx, WASM_OPCODE_IF); + write_opcode(&ctx->stream, WASM_OPCODE_IF); write_expr(ctx, module, func, expr->if_.cond); write_expr(ctx, module, func, expr->if_.true_); break; case WASM_EXPR_TYPE_IF_ELSE: - out_opcode(ctx, WASM_OPCODE_IF_ELSE); + write_opcode(&ctx->stream, WASM_OPCODE_IF_ELSE); write_expr(ctx, module, func, expr->if_else.cond); write_expr(ctx, module, func, expr->if_else.true_); write_expr(ctx, module, func, expr->if_else.false_); break; case WASM_EXPR_TYPE_LOAD: { - out_opcode(ctx, expr->load.opcode); + write_opcode(&ctx->stream, expr->load.opcode); uint32_t align = wasm_get_opcode_alignment(expr->load.opcode, expr->load.align); uint8_t align_log = 0; @@ -663,8 +611,9 @@ static void write_expr(WasmContext* ctx, align >>= 1; align_log++; } - out_u8(ctx, align_log, "alignment"); - out_u32_leb128(ctx, (uint32_t)expr->load.offset, "load offset"); + wasm_write_u8(&ctx->stream, align_log, "alignment"); + write_u32_leb128(&ctx->stream, (uint32_t)expr->load.offset, + "load offset"); write_expr(ctx, module, func, expr->load.addr); break; } @@ -673,38 +622,39 @@ static void write_expr(WasmContext* ctx, WasmLabelNode inner; push_label(ctx, &outer, &expr->loop.outer); push_label(ctx, &inner, &expr->loop.inner); - out_opcode(ctx, WASM_OPCODE_LOOP); + write_opcode(&ctx->stream, WASM_OPCODE_LOOP); write_expr_list_with_count(ctx, module, func, &expr->loop.exprs); pop_label(ctx, &expr->loop.inner); pop_label(ctx, &expr->loop.outer); break; } case WASM_EXPR_TYPE_MEMORY_SIZE: - out_opcode(ctx, WASM_OPCODE_MEMORY_SIZE); + write_opcode(&ctx->stream, WASM_OPCODE_MEMORY_SIZE); break; case WASM_EXPR_TYPE_NOP: - out_opcode(ctx, WASM_OPCODE_NOP); + write_opcode(&ctx->stream, WASM_OPCODE_NOP); break; case WASM_EXPR_TYPE_RETURN: - out_opcode(ctx, WASM_OPCODE_RETURN); + write_opcode(&ctx->stream, WASM_OPCODE_RETURN); if (expr->return_.expr) write_expr(ctx, module, func, expr->return_.expr); break; case WASM_EXPR_TYPE_SELECT: - out_opcode(ctx, WASM_OPCODE_SELECT); + write_opcode(&ctx->stream, WASM_OPCODE_SELECT); write_expr(ctx, module, func, expr->select.true_); write_expr(ctx, module, func, expr->select.false_); write_expr(ctx, module, func, expr->select.cond); break; case WASM_EXPR_TYPE_SET_LOCAL: { int index = wasm_get_local_index_by_var(func, &expr->get_local.var); - out_opcode(ctx, WASM_OPCODE_SET_LOCAL); - out_u32_leb128(ctx, ctx->remapped_locals[index], "remapped local index"); + write_opcode(&ctx->stream, WASM_OPCODE_SET_LOCAL); + write_u32_leb128(&ctx->stream, ctx->remapped_locals[index], + "remapped local index"); write_expr(ctx, module, func, expr->set_local.expr); break; } case WASM_EXPR_TYPE_STORE: { - out_opcode(ctx, expr->store.opcode); + write_opcode(&ctx->stream, expr->store.opcode); uint32_t align = wasm_get_opcode_alignment(expr->store.opcode, expr->store.align); uint8_t align_log = 0; @@ -712,33 +662,37 @@ static void write_expr(WasmContext* ctx, align >>= 1; align_log++; } - out_u8(ctx, align_log, "alignment"); - out_u32_leb128(ctx, (uint32_t)expr->store.offset, "store offset"); + wasm_write_u8(&ctx->stream, align_log, "alignment"); + write_u32_leb128(&ctx->stream, (uint32_t)expr->store.offset, + "store offset"); write_expr(ctx, module, func, expr->store.addr); write_expr(ctx, module, func, expr->store.value); break; } case WASM_EXPR_TYPE_BR_TABLE: { - out_opcode(ctx, WASM_OPCODE_BR_TABLE); - out_u32_leb128(ctx, expr->br_table.targets.size, "num targets"); + write_opcode(&ctx->stream, WASM_OPCODE_BR_TABLE); + write_u32_leb128(&ctx->stream, expr->br_table.targets.size, + "num targets"); size_t i; WasmLabelNode* node; for (i = 0; i < expr->br_table.targets.size; ++i) { const WasmVar* var = &expr->br_table.targets.data[i]; node = find_label_by_var(ctx->top_label, var); - out_u32(ctx, ctx->max_depth - node->depth - 1, "break depth"); + wasm_write_u32(&ctx->stream, ctx->max_depth - node->depth - 1, + "break depth"); } node = find_label_by_var(ctx->top_label, &expr->br_table.default_target); - out_u32(ctx, ctx->max_depth - node->depth - 1, "break depth for default"); + wasm_write_u32(&ctx->stream, ctx->max_depth - node->depth - 1, + "break depth for default"); write_expr(ctx, module, func, expr->br_table.expr); break; } case WASM_EXPR_TYPE_UNARY: - out_opcode(ctx, expr->unary.opcode); + write_opcode(&ctx->stream, expr->unary.opcode); write_expr(ctx, module, func, expr->unary.expr); break; case WASM_EXPR_TYPE_UNREACHABLE: - out_opcode(ctx, WASM_OPCODE_UNREACHABLE); + write_opcode(&ctx->stream, WASM_OPCODE_UNREACHABLE); break; } } @@ -756,7 +710,7 @@ static void write_expr_list_with_count(WasmContext* ctx, const WasmModule* module, const WasmFunc* func, const WasmExprPtrVector* exprs) { - out_u32_leb128(ctx, exprs->size, "num expressions"); + write_u32_leb128(&ctx->stream, exprs->size, "num expressions"); write_expr_list(ctx, module, func, exprs); } @@ -771,7 +725,7 @@ static void write_block(WasmContext* ctx, pop_unused_label(ctx, &block->label); } else { push_label(ctx, &node, &block->label); - out_opcode(ctx, WASM_OPCODE_BLOCK); + write_opcode(&ctx->stream, WASM_OPCODE_BLOCK); write_expr_list_with_count(ctx, module, func, &block->exprs); pop_label(ctx, &block->label); } @@ -784,7 +738,7 @@ static void write_func_locals(WasmContext* ctx, remap_locals(ctx, func); if (local_types->size == 0) { - out_u32_leb128(ctx, 0, "local decl count"); + write_u32_leb128(&ctx->stream, 0, "local decl count"); return; } @@ -808,7 +762,7 @@ static void write_func_locals(WasmContext* ctx, } /* loop through again to write everything out */ - out_u32_leb128(ctx, local_decl_count, "local decl count"); + write_u32_leb128(&ctx->stream, local_decl_count, "local decl count"); current_type = GET_LOCAL_TYPE(FIRST_LOCAL_INDEX); uint32_t local_type_count = 1; for (i = FIRST_LOCAL_INDEX + 1; i <= LAST_LOCAL_INDEX; ++i) { @@ -817,8 +771,8 @@ static void write_func_locals(WasmContext* ctx, if (current_type == type) { local_type_count++; } else { - out_u32_leb128(ctx, local_type_count, "local type count"); - out_u8(ctx, current_type, s_type_names[current_type]); + write_u32_leb128(&ctx->stream, local_type_count, "local type count"); + wasm_write_u8(&ctx->stream, current_type, s_type_names[current_type]); local_type_count = 1; current_type = type; } @@ -838,63 +792,66 @@ static void write_module(WasmContext* ctx, const WasmModule* module) { const size_t leb_size_guess = 1; size_t i; - out_u32(ctx, WASM_BINARY_MAGIC, "WASM_BINARY_MAGIC"); - out_u32(ctx, WASM_BINARY_VERSION, "WASM_BINARY_VERSION"); + wasm_write_u32(&ctx->stream, WASM_BINARY_MAGIC, "WASM_BINARY_MAGIC"); + wasm_write_u32(&ctx->stream, WASM_BINARY_VERSION, "WASM_BINARY_VERSION"); WasmFuncSignatureVector sigs; WASM_ZERO_MEMORY(sigs); get_func_signatures(ctx, module, &sigs); if (sigs.size) { begin_section(ctx, WASM_SECTION_NAME_SIGNATURES, leb_size_guess); - out_u32_leb128(ctx, sigs.size, "num signatures"); + write_u32_leb128(&ctx->stream, sigs.size, "num signatures"); for (i = 0; i < sigs.size; ++i) { const WasmFuncSignature* sig = &sigs.data[i]; - print_header(ctx, "signature", i); - out_u8(ctx, sig->param_types.size, "num params"); - out_u8(ctx, sig->result_type, "result_type"); + write_header(ctx, "signature", i); + wasm_write_u8(&ctx->stream, sig->param_types.size, "num params"); + wasm_write_u8(&ctx->stream, sig->result_type, "result_type"); size_t j; for (j = 0; j < sig->param_types.size; ++j) - out_u8(ctx, sig->param_types.data[j], "param type"); + wasm_write_u8(&ctx->stream, sig->param_types.data[j], "param type"); } end_section(ctx); } if (module->imports.size) { begin_section(ctx, WASM_SECTION_NAME_IMPORT_TABLE, leb_size_guess); - out_u32_leb128(ctx, module->imports.size, "num imports"); + write_u32_leb128(&ctx->stream, module->imports.size, "num imports"); for (i = 0; i < module->imports.size; ++i) { const WasmImport* import = module->imports.data[i]; - print_header(ctx, "import header", i); - out_u32_leb128(ctx, ctx->import_sig_indexes[i], "import signature index"); - out_str(ctx, import->module_name.start, import->module_name.length, - WASM_PRINT_CHARS, "import module name"); - out_str(ctx, import->func_name.start, import->func_name.length, - WASM_PRINT_CHARS, "import function name"); + write_header(ctx, "import header", i); + write_u32_leb128(&ctx->stream, ctx->import_sig_indexes[i], + "import signature index"); + write_str(&ctx->stream, import->module_name.start, + import->module_name.length, WASM_PRINT_CHARS, + "import module name"); + write_str(&ctx->stream, import->func_name.start, import->func_name.length, + WASM_PRINT_CHARS, "import function name"); } end_section(ctx); } if (module->funcs.size) { begin_section(ctx, WASM_SECTION_NAME_FUNCTION_SIGNATURES, leb_size_guess); - out_u32_leb128(ctx, module->funcs.size, "num functions"); + write_u32_leb128(&ctx->stream, module->funcs.size, "num functions"); for (i = 0; i < module->funcs.size; ++i) { char desc[100]; wasm_snprintf(desc, sizeof(desc), "function %" PRIzd " signature index", i); - out_u32_leb128(ctx, ctx->func_sig_indexes[i], desc); + write_u32_leb128(&ctx->stream, ctx->func_sig_indexes[i], desc); } end_section(ctx); } if (module->table && module->table->size) { begin_section(ctx, WASM_SECTION_NAME_FUNCTION_TABLE, leb_size_guess); - out_u32_leb128(ctx, module->table->size, "num function table entries"); + write_u32_leb128(&ctx->stream, module->table->size, + "num function table entries"); for (i = 0; i < module->table->size; ++i) { int index = wasm_get_func_index_by_var(module, &module->table->data[i]); assert(index >= 0 && (size_t)index < module->funcs.size); - out_u32_leb128(ctx, index, "function table entry"); + write_u32_leb128(&ctx->stream, index, "function table entry"); } end_section(ctx); } @@ -902,23 +859,24 @@ static void write_module(WasmContext* ctx, const WasmModule* module) { if (module->memory) { WasmBool export_memory = module->export_memory != NULL; begin_section(ctx, WASM_SECTION_NAME_MEMORY, leb_size_guess); - out_u32_leb128(ctx, module->memory->initial_pages, "min mem pages"); - out_u32_leb128(ctx, module->memory->max_pages, "max mem pages"); - out_u8(ctx, export_memory, "export mem"); + write_u32_leb128(&ctx->stream, module->memory->initial_pages, + "min mem pages"); + write_u32_leb128(&ctx->stream, module->memory->max_pages, "max mem pages"); + wasm_write_u8(&ctx->stream, export_memory, "export mem"); end_section(ctx); } if (module->exports.size) { begin_section(ctx, WASM_SECTION_NAME_EXPORT_TABLE, leb_size_guess); - out_u32_leb128(ctx, module->exports.size, "num exports"); + write_u32_leb128(&ctx->stream, module->exports.size, "num exports"); for (i = 0; i < module->exports.size; ++i) { const WasmExport* export = module->exports.data[i]; int func_index = wasm_get_func_index_by_var(module, &export->var); assert(func_index >= 0 && (size_t)func_index < module->funcs.size); - out_u32_leb128(ctx, func_index, "export func index"); - out_str(ctx, export->name.start, export->name.length, WASM_PRINT_CHARS, - "export name"); + write_u32_leb128(&ctx->stream, func_index, "export func index"); + write_str(&ctx->stream, export->name.start, export->name.length, + WASM_PRINT_CHARS, "export name"); } end_section(ctx); } @@ -927,40 +885,42 @@ static void write_module(WasmContext* ctx, const WasmModule* module) { int start_func_index = wasm_get_func_index_by_var(module, module->start); if (start_func_index != -1) { begin_section(ctx, WASM_SECTION_NAME_START_FUNCTION, leb_size_guess); - out_u32_leb128(ctx, start_func_index, "start func index"); + write_u32_leb128(&ctx->stream, start_func_index, "start func index"); end_section(ctx); } } if (module->funcs.size) { begin_section(ctx, WASM_SECTION_NAME_FUNCTION_BODIES, leb_size_guess); - out_u32_leb128(ctx, module->funcs.size, "num functions"); + write_u32_leb128(&ctx->stream, module->funcs.size, "num functions"); for (i = 0; i < module->funcs.size; ++i) { - print_header(ctx, "function body", i); + write_header(ctx, "function body", i); const WasmFunc* func = module->funcs.data[i]; /* TODO(binji): better guess of the size of the function body section */ const uint32_t leb_size_guess = 1; uint32_t body_size_offset = - out_u32_leb128_space(ctx, leb_size_guess, "func body size (guess)"); + write_u32_leb128_space(ctx, leb_size_guess, "func body size (guess)"); write_func(ctx, module, func); - out_fixup_u32_leb128_size(ctx, body_size_offset, leb_size_guess, - "FIXUP func body size"); + write_fixup_u32_leb128_size(ctx, body_size_offset, leb_size_guess, + "FIXUP func body size"); } end_section(ctx); } if (module->memory && module->memory->segments.size) { begin_section(ctx, WASM_SECTION_NAME_DATA_SEGMENTS, leb_size_guess); - out_u32_leb128(ctx, module->memory->segments.size, "num data segments"); + write_u32_leb128(&ctx->stream, module->memory->segments.size, + "num data segments"); for (i = 0; i < module->memory->segments.size; ++i) { const WasmSegment* segment = &module->memory->segments.data[i]; - print_header(ctx, "segment header", i); - out_u32_leb128(ctx, segment->addr, "segment address"); - out_u32_leb128(ctx, segment->size, "segment size"); - print_header(ctx, "segment data", i); - out_data(ctx, segment->data, segment->size, "segment data"); + write_header(ctx, "segment header", i); + write_u32_leb128(&ctx->stream, segment->addr, "segment address"); + write_u32_leb128(&ctx->stream, segment->size, "segment size"); + write_header(ctx, "segment data", i); + wasm_write_data(&ctx->stream, segment->data, segment->size, + "segment data"); } end_section(ctx); } @@ -971,7 +931,7 @@ static void write_module(WasmContext* ctx, const WasmModule* module) { char desc[100]; begin_section(ctx, WASM_SECTION_NAME_NAMES, leb_size_guess); - out_u32_leb128(ctx, module->funcs.size, "num functions"); + write_u32_leb128(&ctx->stream, module->funcs.size, "num functions"); for (i = 0; i < module->funcs.size; ++i) { const WasmFunc* func = module->funcs.data[i]; uint32_t num_params = wasm_get_num_params(func); @@ -979,8 +939,9 @@ static void write_module(WasmContext* ctx, const WasmModule* module) { uint32_t num_params_and_locals = wasm_get_num_params_and_locals(func); wasm_snprintf(desc, sizeof(desc), "func name %" PRIzd, i); - out_str(ctx, func->name.start, func->name.length, WASM_PRINT_CHARS, desc); - out_u32_leb128(ctx, num_params_and_locals, "num locals"); + write_str(&ctx->stream, func->name.start, func->name.length, + WASM_PRINT_CHARS, desc); + write_u32_leb128(&ctx->stream, num_params_and_locals, "num locals"); if (num_params_and_locals) { remap_locals(ctx, func); @@ -992,7 +953,8 @@ static void write_module(WasmContext* ctx, const WasmModule* module) { for (j = 0; j < num_params; ++j) { WasmStringSlice name = index_to_name.data[j]; wasm_snprintf(desc, sizeof(desc), "remapped local name %" PRIzd, j); - out_str(ctx, name.start, name.length, WASM_PRINT_CHARS, desc); + write_str(&ctx->stream, name.start, name.length, WASM_PRINT_CHARS, + desc); } CHECK_ALLOC(wasm_make_type_binding_reverse_mapping( @@ -1004,7 +966,8 @@ static void write_module(WasmContext* ctx, const WasmModule* module) { num_params]; wasm_snprintf(desc, sizeof(desc), "remapped local name %" PRIzd, num_params + j); - out_str(ctx, name.start, name.length, WASM_PRINT_CHARS, desc); + write_str(&ctx->stream, name.start, name.length, WASM_PRINT_CHARS, + desc); } } } @@ -1050,13 +1013,13 @@ WasmResult wasm_write_binary_module(WasmAllocator* allocator, WASM_ZERO_MEMORY(ctx); ctx.allocator = allocator; ctx.options = options; - ctx.result = WASM_OK; - ctx.writer = writer; + ctx.log_stream = options->log_stream; + wasm_init_stream(&ctx.stream, writer, ctx.log_stream); write_module(&ctx, module); cleanup_context(&ctx); - return ctx.result; + return ctx.stream.result; } WasmResult wasm_write_binary_script(WasmAllocator* allocator, @@ -1067,11 +1030,11 @@ WasmResult wasm_write_binary_script(WasmAllocator* allocator, WASM_ZERO_MEMORY(ctx); ctx.allocator = allocator; ctx.options = options; - ctx.result = WASM_OK; - ctx.writer = writer; + ctx.log_stream = options->log_stream; + wasm_init_stream(&ctx.stream, writer, ctx.log_stream); write_commands(&ctx, script); cleanup_context(&ctx); - return ctx.result; + return ctx.stream.result; } diff --git a/src/wasm-binary-writer.h b/src/wasm-binary-writer.h index e4435845..b799d20e 100644 --- a/src/wasm-binary-writer.h +++ b/src/wasm-binary-writer.h @@ -23,12 +23,13 @@ struct WasmAllocator; struct WasmModule; struct WasmScript; struct WasmWriter; +struct WasmStream; #define WASM_WRITE_BINARY_OPTIONS_DEFAULT \ - { WASM_FALSE, WASM_TRUE, WASM_TRUE, WASM_FALSE } + { NULL, WASM_TRUE, WASM_TRUE, WASM_FALSE } typedef struct WasmWriteBinaryOptions { - WasmBool log_writes; + struct WasmStream* log_stream; WasmBool canonicalize_lebs; WasmBool remap_locals; WasmBool write_debug_names; diff --git a/src/wasm-common.c b/src/wasm-common.c index 834ce59d..9b13ba8c 100644 --- a/src/wasm-common.c +++ b/src/wasm-common.c @@ -17,18 +17,12 @@ #include "wasm-common.h" #include <assert.h> -#include <ctype.h> -#include <stdio.h> -#include <stdarg.h> #include <stdio.h> #include <stdint.h> #include <string.h> #include "wasm-allocator.h" -#define DUMP_OCTETS_PER_LINE 16 -#define DUMP_OCTETS_PER_GROUP 2 - #define V(rtype, type1, type2, mem_size, code, NAME, text) [code] = mem_size, static uint8_t s_opcode_mem_size[] = {WASM_FOREACH_OPCODE(V)}; #undef V @@ -57,44 +51,6 @@ void wasm_destroy_string_slice(WasmAllocator* allocator, WasmStringSlice* str) { wasm_free(allocator, (void*)str->start); } -void wasm_print_memory(const void* start, - size_t size, - size_t offset, - WasmPrintChars print_chars, - const char* desc) { - /* mimic xxd output */ - const uint8_t* p = start; - const uint8_t* end = p + size; - while (p < end) { - const uint8_t* line = p; - const uint8_t* line_end = p + DUMP_OCTETS_PER_LINE; - printf("%07" PRIzx ": ", (size_t)p - (size_t)start + offset); - while (p < line_end) { - int i; - for (i = 0; i < DUMP_OCTETS_PER_GROUP; ++i, ++p) { - if (p < end) { - printf("%02x", *p); - } else { - putchar(' '); - putchar(' '); - } - } - putchar(' '); - } - - putchar(' '); - p = line; - int i; - for (i = 0; i < DUMP_OCTETS_PER_LINE && p < end; ++i, ++p) - if (print_chars) - printf("%c", isprint(*p) ? *p : '.'); - /* if there are multiple lines, only print the desc on the last one */ - if (p >= end && desc) - printf(" ; %s", desc); - putchar('\n'); - } -} - WasmResult wasm_read_file(WasmAllocator* allocator, const char* filename, void** out_data, diff --git a/src/wasm-common.h b/src/wasm-common.h index 7af2ea4e..051203b1 100644 --- a/src/wasm-common.h +++ b/src/wasm-common.h @@ -67,12 +67,6 @@ typedef enum WasmBool { WASM_TRUE, } WasmBool; -/* whether to display the ASCII characters in the debug output */ -typedef enum WasmPrintChars { - WASM_DONT_PRINT_CHARS, - WASM_PRINT_CHARS, -} WasmPrintChars; - typedef enum WasmResult { WASM_OK, WASM_ERROR, @@ -354,12 +348,6 @@ uint32_t wasm_get_opcode_alignment(WasmOpcode opcode, uint32_t alignment); WasmBool wasm_string_slices_are_equal(const WasmStringSlice*, const WasmStringSlice*); void wasm_destroy_string_slice(struct WasmAllocator*, WasmStringSlice*); -/* dump memory to stdout similar to the xxd format */ -void wasm_print_memory(const void* start, - size_t size, - size_t offset, - WasmPrintChars print_chars, - const char* desc); WasmResult wasm_read_file(struct WasmAllocator* allocator, const char* filename, void** out_data, diff --git a/src/wasm-stream.c b/src/wasm-stream.c new file mode 100644 index 00000000..0023cfb5 --- /dev/null +++ b/src/wasm-stream.c @@ -0,0 +1,138 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wasm-stream.h" + +#include <assert.h> +#include <ctype.h> + +#define DUMP_OCTETS_PER_LINE 16 +#define DUMP_OCTETS_PER_GROUP 2 + +void wasm_init_stream(WasmStream* stream, + WasmWriter* writer, + WasmStream* log_stream) { + stream->writer = writer; + stream->offset = 0; + stream->result = WASM_OK; + stream->log_stream = log_stream; +} + +void wasm_write_data_at(WasmStream* stream, + size_t offset, + const void* src, + size_t size, + WasmPrintChars print_chars, + const char* desc) { + if (WASM_FAILED(stream->result)) + return; + if (stream->log_stream) { + wasm_write_memory_dump(stream->log_stream, src, size, offset, print_chars, + desc); + } + if (stream->writer->write_data) { + stream->result = stream->writer->write_data(offset, src, size, + stream->writer->user_data); + } +} + +void wasm_write_data(WasmStream* stream, + const void* src, + size_t size, + const char* desc) { + wasm_write_data_at(stream, stream->offset, src, size, WASM_DONT_PRINT_CHARS, + desc); + stream->offset += size; +} +void wasm_move_data(WasmStream* stream, + size_t dst_offset, + size_t src_offset, + size_t size) { + if (WASM_FAILED(stream->result)) + return; + if (stream->log_stream) { + wasm_writef(stream->log_stream, "; move data: [%" PRIzx ", %" PRIzx + ") -> [%" PRIzx ", %" PRIzx ")\n", + src_offset, src_offset + size, dst_offset, dst_offset + size); + } + if (stream->writer->write_data) { + stream->result = stream->writer->move_data(dst_offset, src_offset, size, + stream->writer->user_data); + } +} + +void wasm_writef(WasmStream* stream, const char* format, ...) { + WASM_SNPRINTF_ALLOCA(buffer, length, format); + wasm_write_data(stream, buffer, length, NULL); +} + +void wasm_write_u8(WasmStream* stream, uint32_t value, const char* desc) { + assert(value <= UINT8_MAX); + uint8_t value8 = value; + wasm_write_data_at(stream, stream->offset, &value8, sizeof(value8), + WASM_DONT_PRINT_CHARS, desc); + stream->offset += sizeof(value8); +} + +void wasm_write_u32(WasmStream* stream, uint32_t value, const char* desc) { + wasm_write_data_at(stream, stream->offset, &value, sizeof(value), + WASM_DONT_PRINT_CHARS, desc); + stream->offset += sizeof(value); +} + +void wasm_write_u64(WasmStream* stream, uint64_t value, const char* desc) { + wasm_write_data_at(stream, stream->offset, &value, sizeof(value), + WASM_DONT_PRINT_CHARS, desc); + stream->offset += sizeof(value); +} + +void wasm_write_memory_dump(WasmStream* stream, + const void* start, + size_t size, + size_t offset, + WasmPrintChars print_chars, + const char* desc) { + const uint8_t* p = start; + const uint8_t* end = p + size; + while (p < end) { + const uint8_t* line = p; + const uint8_t* line_end = p + DUMP_OCTETS_PER_LINE; + wasm_writef(stream, "%07" PRIzx ": ", (size_t)p - (size_t)start + offset); + while (p < line_end) { + int i; + for (i = 0; i < DUMP_OCTETS_PER_GROUP; ++i, ++p) { + if (p < end) { + wasm_writef(stream, "%02x", *p); + } else { + wasm_write_char(stream, ' '); + wasm_write_char(stream, ' '); + } + } + wasm_write_char(stream, ' '); + } + + wasm_write_char(stream, ' '); + p = line; + int i; + for (i = 0; i < DUMP_OCTETS_PER_LINE && p < end; ++i, ++p) + if (print_chars) + wasm_write_char(stream, isprint(*p) ? *p : '.'); + /* if there are multiple lines, only print the desc on the last one */ + if (p >= end && desc) + wasm_writef(stream, " ; %s", desc); + wasm_write_char(stream, '\n'); + } +} diff --git a/src/wasm-stream.h b/src/wasm-stream.h new file mode 100644 index 00000000..d0d152ef --- /dev/null +++ b/src/wasm-stream.h @@ -0,0 +1,90 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WASM_STREAM_H_ +#define WASM_STREAM_H_ + +#include "wasm-common.h" +#include "wasm-writer.h" + +typedef struct WasmStream { + WasmWriter* writer; + size_t offset; + WasmResult result; + /* if non-NULL, log all writes to this stream */ + struct WasmStream* log_stream; +} WasmStream; + +/* whether to display the ASCII characters in the debug output for + * wasm_write_memory */ +typedef enum WasmPrintChars { + WASM_DONT_PRINT_CHARS, + WASM_PRINT_CHARS, +} WasmPrintChars; + +WASM_EXTERN_C_BEGIN + +void wasm_init_stream(WasmStream* stream, + WasmWriter* writer, + WasmStream* log_stream); + +/* helper functions for writing to a WasmStream. the |desc| parameter is + * optional, and will be appended to the log stream if |stream.log_stream| is + * non-NULL. */ +void wasm_write_data_at(WasmStream*, + size_t offset, + const void* src, + size_t size, + WasmPrintChars print_chars, + const char* desc); +void wasm_write_data(WasmStream*, + const void* src, + size_t size, + const char* desc); +void wasm_move_data(WasmStream*, + size_t dst_offset, + size_t src_offset, + size_t size); + +void wasm_writef(WasmStream*, const char* format, ...); +/* specified as uint32_t instead of uint8_t so we can check if the value given + * is in range before wrapping */ +void wasm_write_u8(WasmStream*, uint32_t value, const char* desc); +void wasm_write_u32(WasmStream*, uint32_t value, const char* desc); +void wasm_write_u64(WasmStream*, uint64_t value, const char* desc); + +static WASM_INLINE void wasm_write_char(WasmStream* stream, char c) { + wasm_write_u8(stream, c, NULL); +} + +/* dump memory as text, similar to the xxd format */ +void wasm_write_memory_dump(WasmStream*, + const void* start, + size_t size, + size_t offset, + WasmPrintChars print_chars, + const char* desc); + +static WASM_INLINE void wasm_write_output_buffer_memory_dump( + WasmStream* stream, + struct WasmOutputBuffer* buf) { + wasm_write_memory_dump(stream, buf->start, buf->size, 0, + WASM_DONT_PRINT_CHARS, NULL); +} + +WASM_EXTERN_C_END + +#endif /* WASM_STREAM_H_ */ diff --git a/src/wasm-writer.c b/src/wasm-writer.c index 9990a36d..502678b5 100644 --- a/src/wasm-writer.c +++ b/src/wasm-writer.c @@ -170,6 +170,24 @@ void wasm_close_mem_writer(WasmMemoryWriter* writer) { wasm_destroy_output_buffer(&writer->buf); } +WasmResult wasm_write_output_buffer_to_file(WasmOutputBuffer* buf, + const char* filename) { + FILE* file = fopen(filename, "wb"); + if (!file) { + ERROR("unable to open %s for writing\n", filename); + return WASM_ERROR; + } + + ssize_t bytes = fwrite(buf->start, 1, buf->size, file); + if (bytes < 0 || (size_t)bytes != buf->size) { + ERROR("failed to write %" PRIzd " bytes to %s\n", buf->size, filename); + return WASM_ERROR; + } + + fclose(file); + return WASM_OK; +} + void wasm_destroy_output_buffer(WasmOutputBuffer* buf) { if (buf->allocator) wasm_free(buf->allocator, buf->start); diff --git a/src/wasm-writer.h b/src/wasm-writer.h index 325e15d7..fe114848 100644 --- a/src/wasm-writer.h +++ b/src/wasm-writer.h @@ -53,15 +53,24 @@ typedef struct WasmFileWriter { } WasmFileWriter; WASM_EXTERN_C_BEGIN + +/* WasmFileWriter */ WasmResult wasm_init_file_writer(WasmFileWriter* writer, const char* filename); WasmResult wasm_init_file_writer_existing(WasmFileWriter* writer, FILE* file); void wasm_close_file_writer(WasmFileWriter* writer); + +/* WasmMemoryWriter */ WasmResult wasm_init_mem_writer(WasmAllocator* allocator, WasmMemoryWriter* writer); void wasm_steal_mem_writer_output_buffer(WasmMemoryWriter* writer, WasmOutputBuffer* out_buf); void wasm_close_mem_writer(WasmMemoryWriter* writer); + +/* WasmOutputBuffer */ +WasmResult wasm_write_output_buffer_to_file(WasmOutputBuffer* buf, + const char* filename); void wasm_destroy_output_buffer(WasmOutputBuffer* buf); + WASM_EXTERN_C_END #endif /* WASM_WRITER_H_ */ |