summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/sexpr-wasm.c77
-rw-r--r--src/wasm-ast-writer.c495
-rw-r--r--src/wasm-binary-writer.c425
-rw-r--r--src/wasm-binary-writer.h5
-rw-r--r--src/wasm-common.c44
-rw-r--r--src/wasm-common.h12
-rw-r--r--src/wasm-stream.c138
-rw-r--r--src/wasm-stream.h90
-rw-r--r--src/wasm-writer.c18
-rw-r--r--src/wasm-writer.h9
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_ */