diff options
-rw-r--r-- | src/ast-writer.cc | 17 | ||||
-rw-r--r-- | src/ast-writer.h | 4 | ||||
-rw-r--r-- | src/binary-reader-interpreter.cc | 34 | ||||
-rw-r--r-- | src/binary-reader-linker.h | 4 | ||||
-rw-r--r-- | src/binary-reader-logging.cc | 8 | ||||
-rw-r--r-- | src/binary-reader-logging.h | 2 | ||||
-rw-r--r-- | src/binary-reader-objdump.cc | 12 | ||||
-rw-r--r-- | src/binary-reader.h | 4 | ||||
-rw-r--r-- | src/binary-writer-spec.cc | 100 | ||||
-rw-r--r-- | src/binary-writer-spec.h | 2 | ||||
-rw-r--r-- | src/binary-writer.cc | 121 | ||||
-rw-r--r-- | src/binary-writer.h | 35 | ||||
-rw-r--r-- | src/interpreter.cc | 296 | ||||
-rw-r--r-- | src/interpreter.h | 10 | ||||
-rw-r--r-- | src/stream.cc | 164 | ||||
-rw-r--r-- | src/stream.h | 178 | ||||
-rw-r--r-- | src/tools/wasm-interp.cc | 23 | ||||
-rw-r--r-- | src/tools/wasm-link.cc | 136 | ||||
-rw-r--r-- | src/tools/wasm2wast.cc | 24 | ||||
-rw-r--r-- | src/tools/wasmdump.cc | 9 | ||||
-rw-r--r-- | src/tools/wasmopcodecnt.cc | 8 | ||||
-rw-r--r-- | src/tools/wast-desugar.cc | 13 | ||||
-rw-r--r-- | src/tools/wast2wasm.cc | 27 | ||||
-rw-r--r-- | src/writer.cc | 209 | ||||
-rw-r--r-- | src/writer.h | 85 |
25 files changed, 715 insertions, 810 deletions
diff --git a/src/ast-writer.cc b/src/ast-writer.cc index a688d004..d7ec12e4 100644 --- a/src/ast-writer.cc +++ b/src/ast-writer.cc @@ -59,7 +59,7 @@ enum class NextChar { }; struct Context { - Context() { WABT_ZERO_MEMORY(stream); } + explicit Context(Writer* writer) : stream(writer) {} Stream stream; Result result = Result::Ok; @@ -94,22 +94,22 @@ static void write_indent(Context* ctx) { static size_t s_indent_len = sizeof(s_indent) - 1; size_t indent = ctx->indent; while (indent > s_indent_len) { - write_data(&ctx->stream, s_indent, s_indent_len, nullptr); + ctx->stream.WriteData(s_indent, s_indent_len); indent -= s_indent_len; } if (indent > 0) { - write_data(&ctx->stream, s_indent, indent, nullptr); + ctx->stream.WriteData(s_indent, indent); } } static void write_next_char(Context* ctx) { switch (ctx->next_char) { case NextChar::Space: - write_data(&ctx->stream, " ", 1, nullptr); + ctx->stream.WriteChar(' '); break; case NextChar::Newline: case NextChar::ForceNewline: - write_data(&ctx->stream, "\n", 1, nullptr); + ctx->stream.WriteChar('\n'); write_indent(ctx); break; @@ -124,7 +124,7 @@ static void write_data_with_next_char(Context* ctx, const void* src, size_t size) { write_next_char(ctx); - write_data(&ctx->stream, src, size, nullptr); + ctx->stream.WriteData(src, size); } static void WABT_PRINTF_FORMAT(2, 3) @@ -136,7 +136,7 @@ static void WABT_PRINTF_FORMAT(2, 3) } static void write_putc(Context* ctx, char c) { - write_data(&ctx->stream, &c, 1, nullptr); + ctx->stream.WriteChar(c); } static void write_puts(Context* ctx, const char* s, NextChar next_char) { @@ -745,8 +745,7 @@ static void write_module(Context* ctx, const Module* module) { } Result write_ast(Writer* writer, const Module* module) { - Context ctx; - init_stream(&ctx.stream, writer, nullptr); + Context ctx(writer); write_module(&ctx, module); return ctx.result; } diff --git a/src/ast-writer.h b/src/ast-writer.h index 950e640e..79bf2c76 100644 --- a/src/ast-writer.h +++ b/src/ast-writer.h @@ -22,9 +22,9 @@ namespace wabt { struct Module; -struct Writer; +class Writer; -Result write_ast(struct Writer*, const struct Module*); +Result write_ast(Writer*, const Module*); } // namespace wabt diff --git a/src/binary-reader-interpreter.cc b/src/binary-reader-interpreter.cc index b22a4472..db5f9719 100644 --- a/src/binary-reader-interpreter.cc +++ b/src/binary-reader-interpreter.cc @@ -75,8 +75,7 @@ class BinaryReaderInterpreter : public BinaryReaderNop { size_t istream_offset, BinaryErrorHandler* error_handler); - Result Init(); - void StealOutputBuffer(OutputBuffer*); + std::unique_ptr<OutputBuffer> ReleaseOutputBuffer(); size_t get_istream_offset() { return istream_offset; } // Implement BinaryReader. @@ -301,20 +300,15 @@ BinaryReaderInterpreter::BinaryReaderInterpreter( : error_handler(error_handler), env(env), module(module), + istream_writer(std::move(env->istream)), istream_offset(istream_offset) { - WABT_ZERO_MEMORY(istream_writer); - tc_error_handler.on_error = OnTypecheckerError; tc_error_handler.user_data = this; typechecker.error_handler = &tc_error_handler; } -Result BinaryReaderInterpreter::Init() { - return init_mem_writer_existing(&istream_writer, &env->istream); -} - -void BinaryReaderInterpreter::StealOutputBuffer(OutputBuffer* output_buffer) { - steal_mem_writer_output_buffer(&istream_writer, output_buffer); +std::unique_ptr<OutputBuffer> BinaryReaderInterpreter::ReleaseOutputBuffer() { + return istream_writer.ReleaseOutputBuffer(); } Label* BinaryReaderInterpreter::GetLabel(uint32_t depth) { @@ -415,8 +409,7 @@ uint32_t BinaryReaderInterpreter::GetIstreamOffset() { Result BinaryReaderInterpreter::EmitDataAt(size_t offset, const void* data, size_t size) { - return istream_writer.base.write_data(offset, data, size, - istream_writer.base.user_data); + return istream_writer.WriteData(offset, data, size); } Result BinaryReaderInterpreter::EmitData(const void* data, size_t size) { @@ -1492,24 +1485,21 @@ Result read_binary_interpreter(InterpreterEnvironment* env, const ReadBinaryOptions* options, BinaryErrorHandler* error_handler, DefinedInterpreterModule** out_module) { - size_t istream_offset = env->istream.size; + size_t istream_offset = env->istream->data.size(); DefinedInterpreterModule* module = new DefinedInterpreterModule(istream_offset); - BinaryReaderInterpreter reader(env, module, istream_offset, error_handler); - if (WABT_FAILED(reader.Init())) { - delete module; - return Result::Error; - } - + // Need to mark before constructing the reader since it takes ownership of + // env->istream, which makes env->istream == nullptr. InterpreterEnvironmentMark mark = mark_interpreter_environment(env); + BinaryReaderInterpreter reader(env, module, istream_offset, error_handler); env->modules.emplace_back(module); Result result = read_binary(data, size, &reader, options); - reader.StealOutputBuffer(&env->istream); + env->istream = reader.ReleaseOutputBuffer(); if (WABT_SUCCEEDED(result)) { - env->istream.size = reader.get_istream_offset(); - module->istream_end = env->istream.size; + env->istream->data.resize(reader.get_istream_offset()); + module->istream_end = env->istream->data.size(); *out_module = module; } else { reset_interpreter_environment_to_mark(env, mark); diff --git a/src/binary-reader-linker.h b/src/binary-reader-linker.h index 5a543bb3..0ffb7e42 100644 --- a/src/binary-reader-linker.h +++ b/src/binary-reader-linker.h @@ -22,14 +22,14 @@ namespace wabt { -struct Stream; +class Stream; namespace link { struct LinkerInputBinary; struct LinkOptions { - struct Stream* log_stream; + Stream* log_stream; }; Result read_binary_linker(struct LinkerInputBinary* input_info, diff --git a/src/binary-reader-logging.cc b/src/binary-reader-logging.cc index 6657a3e5..093c9c07 100644 --- a/src/binary-reader-logging.cc +++ b/src/binary-reader-logging.cc @@ -24,7 +24,7 @@ namespace wabt { #define INDENT_SIZE 2 -#define LOGF_NOINDENT(...) writef(stream, __VA_ARGS__) +#define LOGF_NOINDENT(...) stream->Writef(__VA_ARGS__) #define LOGF(...) \ do { \ @@ -64,14 +64,14 @@ void BinaryReaderLogging::WriteIndent() { static char s_indent[] = " " " "; - static size_t s_indent_len = sizeof(s_indent) - 1; + static const size_t s_indent_len = sizeof(s_indent) - 1; size_t i = indent; while (i > s_indent_len) { - write_data(stream, s_indent, s_indent_len, nullptr); + stream->WriteData(s_indent, s_indent_len); i -= s_indent_len; } if (i > 0) { - write_data(stream, s_indent, indent, nullptr); + stream->WriteData(s_indent, indent); } } diff --git a/src/binary-reader-logging.h b/src/binary-reader-logging.h index 021420cb..374095f8 100644 --- a/src/binary-reader-logging.h +++ b/src/binary-reader-logging.h @@ -21,7 +21,7 @@ namespace wabt { -struct Stream; +class Stream; class BinaryReaderLogging : public BinaryReader { public: diff --git a/src/binary-reader-objdump.cc b/src/binary-reader-objdump.cc index b086c55b..a57ec1bb 100644 --- a/src/binary-reader-objdump.cc +++ b/src/binary-reader-objdump.cc @@ -485,14 +485,14 @@ class BinaryReaderObjdump : public BinaryReaderObjdumpBase { void PrintDetails(const char* fmt, ...); Result OnCount(uint32_t count); - Stream* out_stream; + std::unique_ptr<FileStream> out_stream; }; BinaryReaderObjdump::BinaryReaderObjdump(const uint8_t* data, size_t size, ObjdumpOptions* options) : BinaryReaderObjdumpBase(data, size, options), - out_stream(init_stdout_stream()) {} + out_stream(FileStream::CreateStdout()) {} Result BinaryReaderObjdump::BeginCustomSection(uint32_t size, StringSlice section_name) { @@ -533,8 +533,8 @@ Result BinaryReaderObjdump::BeginSection(BinarySection section_code, case ObjdumpMode::RawData: if (section_match) { printf("\nContents of section %s:\n", name); - write_memory_dump(out_stream, data + state->offset, size, state->offset, - PrintChars::Yes, nullptr, nullptr); + out_stream->WriteMemoryDump(data + state->offset, size, state->offset, + nullptr, nullptr, PrintChars::Yes); } break; case ObjdumpMode::Prepass: @@ -807,8 +807,8 @@ Result BinaryReaderObjdump::OnDataSegmentData(uint32_t index, const void* src_data, uint32_t size) { if (ShouldPrintDetails()) { - write_memory_dump(out_stream, src_data, size, 0, PrintChars::Yes, " - ", - nullptr); + out_stream->WriteMemoryDump(src_data, size, 0, " - ", nullptr, + PrintChars::Yes); } return Result::Ok; } diff --git a/src/binary-reader.h b/src/binary-reader.h index 55ac8dd2..1c2f2780 100644 --- a/src/binary-reader.h +++ b/src/binary-reader.h @@ -28,8 +28,10 @@ namespace wabt { +class Stream; + struct ReadBinaryOptions { - struct Stream* log_stream; + Stream* log_stream; bool read_debug_names; }; diff --git a/src/binary-writer-spec.cc b/src/binary-writer-spec.cc index d87fe820..ed726475 100644 --- a/src/binary-writer-spec.cc +++ b/src/binary-writer-spec.cc @@ -31,8 +31,7 @@ namespace wabt { namespace { struct Context { - MemoryWriter json_writer; - Stream json_stream; + MemoryStream json_stream; StringSlice source_filename; StringSlice module_filename_noext; bool write_modules; /* Whether to write the modules files. */ @@ -111,28 +110,28 @@ static char* get_module_filename(Context* ctx) { } static void write_string(Context* ctx, const char* s) { - writef(&ctx->json_stream, "\"%s\"", s); + ctx->json_stream.Writef("\"%s\"", s); } static void write_key(Context* ctx, const char* key) { - writef(&ctx->json_stream, "\"%s\": ", key); + ctx->json_stream.Writef("\"%s\": ", key); } static void write_separator(Context* ctx) { - writef(&ctx->json_stream, ", "); + ctx->json_stream.Writef(", "); } static void write_escaped_string_slice(Context* ctx, StringSlice ss) { - write_char(&ctx->json_stream, '"'); + ctx->json_stream.WriteChar('"'); for (size_t i = 0; i < ss.length; ++i) { uint8_t c = ss.start[i]; if (c < 0x20 || c == '\\' || c == '"') { - writef(&ctx->json_stream, "\\u%04x", c); + ctx->json_stream.Writef("\\u%04x", c); } else { - write_char(&ctx->json_stream, c); + ctx->json_stream.WriteChar(c); } } - write_char(&ctx->json_stream, '"'); + ctx->json_stream.WriteChar('"'); } static void write_command_type(Context* ctx, const Command& command) { @@ -161,25 +160,25 @@ static void write_command_type(Context* ctx, const Command& command) { static void write_location(Context* ctx, const Location* loc) { write_key(ctx, "line"); - writef(&ctx->json_stream, "%d", loc->line); + ctx->json_stream.Writef("%d", loc->line); } static void write_var(Context* ctx, const Var* var) { if (var->type == VarType::Index) - writef(&ctx->json_stream, "\"%" PRIu64 "\"", var->index); + ctx->json_stream.Writef("\"%" PRIu64 "\"", var->index); else write_escaped_string_slice(ctx, var->name); } static void write_type_object(Context* ctx, Type type) { - writef(&ctx->json_stream, "{"); + ctx->json_stream.Writef("{"); write_key(ctx, "type"); write_string(ctx, get_type_name(type)); - writef(&ctx->json_stream, "}"); + ctx->json_stream.Writef("}"); } static void write_const(Context* ctx, const Const* const_) { - writef(&ctx->json_stream, "{"); + ctx->json_stream.Writef("{"); write_key(ctx, "type"); /* Always write the values as strings, even though they may be representable @@ -189,14 +188,14 @@ static void write_const(Context* ctx, const Const* const_) { write_string(ctx, "i32"); write_separator(ctx); write_key(ctx, "value"); - writef(&ctx->json_stream, "\"%u\"", const_->u32); + ctx->json_stream.Writef("\"%u\"", const_->u32); break; case Type::I64: write_string(ctx, "i64"); write_separator(ctx); write_key(ctx, "value"); - writef(&ctx->json_stream, "\"%" PRIu64 "\"", const_->u64); + ctx->json_stream.Writef("\"%" PRIu64 "\"", const_->u64); break; case Type::F32: { @@ -204,7 +203,7 @@ static void write_const(Context* ctx, const Const* const_) { write_string(ctx, "f32"); write_separator(ctx); write_key(ctx, "value"); - writef(&ctx->json_stream, "\"%u\"", const_->f32_bits); + ctx->json_stream.Writef("\"%u\"", const_->f32_bits); break; } @@ -213,7 +212,7 @@ static void write_const(Context* ctx, const Const* const_) { write_string(ctx, "f64"); write_separator(ctx); write_key(ctx, "value"); - writef(&ctx->json_stream, "\"%" PRIu64 "\"", const_->f64_bits); + ctx->json_stream.Writef("\"%" PRIu64 "\"", const_->f64_bits); break; } @@ -221,23 +220,23 @@ static void write_const(Context* ctx, const Const* const_) { assert(0); } - writef(&ctx->json_stream, "}"); + ctx->json_stream.Writef("}"); } static void write_const_vector(Context* ctx, const ConstVector& consts) { - writef(&ctx->json_stream, "["); + ctx->json_stream.Writef("["); for (size_t i = 0; i < consts.size(); ++i) { const Const* const_ = &consts[i]; write_const(ctx, const_); if (i != consts.size() - 1) write_separator(ctx); } - writef(&ctx->json_stream, "]"); + ctx->json_stream.Writef("]"); } static void write_action(Context* ctx, const Action* action) { write_key(ctx, "action"); - writef(&ctx->json_stream, "{"); + ctx->json_stream.Writef("{"); write_key(ctx, "type"); if (action->type == ActionType::Invoke) { write_string(ctx, "invoke"); @@ -261,7 +260,7 @@ static void write_action(Context* ctx, const Action* action) { write_key(ctx, "field"); write_escaped_string_slice(ctx, action->name); } - writef(&ctx->json_stream, "}"); + ctx->json_stream.Writef("}"); } static void write_action_result_type(Context* ctx, @@ -269,7 +268,7 @@ static void write_action_result_type(Context* ctx, const Action* action) { const Module* module = get_module_by_var(script, &action->module_var); const Export* export_; - writef(&ctx->json_stream, "["); + ctx->json_stream.Writef("["); switch (action->type) { case ActionType::Invoke: { export_ = get_export_by_name(module, &action->name); @@ -289,19 +288,15 @@ static void write_action_result_type(Context* ctx, break; } } - writef(&ctx->json_stream, "]"); + ctx->json_stream.Writef("]"); } static void write_module(Context* ctx, char* filename, const Module* module) { MemoryWriter writer; - Result result = init_mem_writer(&writer); - if (WABT_SUCCEEDED(result)) { - WriteBinaryOptions options = ctx->spec_options->write_binary_options; - result = write_binary_module(&writer.base, module, &options); - if (WABT_SUCCEEDED(result) && ctx->write_modules) - result = write_output_buffer_to_file(&writer.buf, filename); - close_mem_writer(&writer); - } + WriteBinaryOptions options = ctx->spec_options->write_binary_options; + Result result = write_binary_module(&writer, module, &options); + if (WABT_SUCCEEDED(result) && ctx->write_modules) + result = writer.output_buffer().WriteToFile(filename); ctx->result = result; } @@ -312,15 +307,13 @@ static void write_raw_module(Context* ctx, if (raw_module->type == RawModuleType::Text) { write_module(ctx, filename, raw_module->text); } else if (ctx->write_modules) { - FileStream stream; - Result result = init_file_writer(&stream.writer, filename); - if (WABT_SUCCEEDED(result)) { - init_stream(&stream.base, &stream.writer.base, nullptr); - write_data(&stream.base, raw_module->binary.data, raw_module->binary.size, - ""); - close_file_writer(&stream.writer); + FileStream stream(filename); + if (stream.is_open()) { + stream.WriteData(raw_module->binary.data, raw_module->binary.size); + ctx->result = stream.result(); + } else { + ctx->result = Result::Error; } - ctx->result = result; } } @@ -340,9 +333,9 @@ static void write_invalid_module(Context* ctx, } static void write_commands(Context* ctx, Script* script) { - writef(&ctx->json_stream, "{\"source_filename\": "); + ctx->json_stream.Writef("{\"source_filename\": "); write_escaped_string_slice(ctx, ctx->source_filename); - writef(&ctx->json_stream, ",\n \"commands\": [\n"); + ctx->json_stream.Writef(",\n \"commands\": [\n"); int last_module_index = -1; for (size_t i = 0; i < script->commands.size(); ++i) { const Command& command = *script->commands[i].get(); @@ -352,9 +345,9 @@ static void write_commands(Context* ctx, Script* script) { if (i != 0) write_separator(ctx); - writef(&ctx->json_stream, "\n"); + ctx->json_stream.Writef("\n"); - writef(&ctx->json_stream, " {"); + ctx->json_stream.Writef(" {"); write_command_type(ctx, command); write_separator(ctx); @@ -474,9 +467,9 @@ static void write_commands(Context* ctx, Script* script) { break; } - writef(&ctx->json_stream, "}"); + ctx->json_stream.Writef("}"); } - writef(&ctx->json_stream, "]}\n"); + ctx->json_stream.Writef("]}\n"); } Result write_binary_spec_script(Script* script, @@ -484,7 +477,6 @@ Result write_binary_spec_script(Script* script, const WriteBinarySpecOptions* spec_options) { assert(source_filename); Context ctx; - WABT_ZERO_MEMORY(ctx); ctx.spec_options = spec_options; ctx.result = Result::Ok; ctx.source_filename.start = source_filename; @@ -494,15 +486,9 @@ Result write_binary_spec_script(Script* script, : source_filename); ctx.write_modules = !!ctx.spec_options->json_filename; - Result result = init_mem_writer(&ctx.json_writer); - if (WABT_SUCCEEDED(result)) { - init_stream(&ctx.json_stream, &ctx.json_writer.base, nullptr); - write_commands(&ctx, script); - if (ctx.spec_options->json_filename) { - write_output_buffer_to_file(&ctx.json_writer.buf, - ctx.spec_options->json_filename); - } - close_mem_writer(&ctx.json_writer); + write_commands(&ctx, script); + if (ctx.spec_options->json_filename) { + ctx.json_stream.WriteToFile(ctx.spec_options->json_filename); } return ctx.result; diff --git a/src/binary-writer-spec.h b/src/binary-writer-spec.h index 974af5fd..9cc6b2ea 100644 --- a/src/binary-writer-spec.h +++ b/src/binary-writer-spec.h @@ -23,8 +23,6 @@ namespace wabt { -struct Writer; - #define WABT_WRITE_BINARY_SPEC_OPTIONS_DEFAULT \ { nullptr, WABT_WRITE_BINARY_OPTIONS_DEFAULT } diff --git a/src/binary-writer.cc b/src/binary-writer.cc index 8c7d9be4..8e4b383f 100644 --- a/src/binary-writer.cc +++ b/src/binary-writer.cc @@ -59,10 +59,9 @@ RelocSection::RelocSection(const char* name, BinarySection code) struct Context { WABT_DISALLOW_COPY_AND_ASSIGN(Context); - Context(); + Context(Writer* writer, const WriteBinaryOptions* options); Stream stream; - Stream* log_stream = nullptr; const WriteBinaryOptions* options = nullptr; std::vector<RelocSection> reloc_sections; @@ -78,9 +77,8 @@ struct Context { size_t last_subsection_payload_offset = 0; }; -Context::Context() { - WABT_ZERO_MEMORY(stream); -} +Context::Context(Writer* writer, const WriteBinaryOptions* options) + : stream(writer, options->log_stream), options(options) {} } // namespace @@ -94,11 +92,11 @@ static uint8_t log2_u32(uint32_t x) { } static void write_header(Context* ctx, const char* name, int index) { - if (ctx->log_stream) { + if (ctx->stream.has_log_stream()) { if (index == PRINT_HEADER_NO_INDEX) { - writef(ctx->log_stream, "; %s\n", name); + ctx->stream.log_stream().Writef("; %s\n", name); } else { - writef(ctx->log_stream, "; %s %d\n", name, index); + ctx->stream.log_stream().Writef("; %s %d\n", name, index); } } } @@ -131,7 +129,7 @@ uint32_t write_u32_leb128_at(Stream* stream, uint32_t i = 0; LEB128_LOOP_UNTIL(value == 0); uint32_t length = i; - write_data_at(stream, offset, data, length, PrintChars::No, desc); + stream->WriteDataAt(offset, data, length, desc, PrintChars::No); return length; } @@ -155,19 +153,19 @@ uint32_t write_fixed_u32_leb128_at(Stream* stream, uint8_t data[MAX_U32_LEB128_BYTES]; uint32_t length = write_fixed_u32_leb128_raw(data, data + MAX_U32_LEB128_BYTES, value); - write_data_at(stream, offset, data, length, PrintChars::No, desc); + stream->WriteDataAt(offset, data, length, desc, PrintChars::No); return length; } void write_u32_leb128(Stream* stream, uint32_t value, const char* desc) { - uint32_t length = write_u32_leb128_at(stream, stream->offset, value, desc); - stream->offset += length; + uint32_t length = write_u32_leb128_at(stream, stream->offset(), value, desc); + stream->AddOffset(length); } void write_fixed_u32_leb128(Stream* stream, uint32_t value, const char* desc) { uint32_t length = - write_fixed_u32_leb128_at(stream, stream->offset, value, desc); - stream->offset += length; + write_fixed_u32_leb128_at(stream, stream->offset(), value, desc); + stream->AddOffset(length); } void write_i32_leb128(Stream* stream, int32_t value, const char* desc) { @@ -179,8 +177,7 @@ void write_i32_leb128(Stream* stream, int32_t value, const char* desc) { LEB128_LOOP_UNTIL(value == 0 && !(byte & 0x40)); uint32_t length = i; - write_data_at(stream, stream->offset, data, length, PrintChars::No, desc); - stream->offset += length; + stream->WriteData(data, length, desc); } static void write_i64_leb128(Stream* stream, int64_t value, const char* desc) { @@ -192,8 +189,7 @@ static void write_i64_leb128(Stream* stream, int64_t value, const char* desc) { LEB128_LOOP_UNTIL(value == 0 && !(byte & 0x40)); int length = i; - write_data_at(stream, stream->offset, data, length, PrintChars::No, desc); - stream->offset += length; + stream->WriteData(data, length, desc); } #undef LEB128_LOOP_UNTIL @@ -213,10 +209,10 @@ static uint32_t write_u32_leb128_space(Context* ctx, const char* desc) { assert(leb_size_guess <= MAX_U32_LEB128_BYTES); uint8_t data[MAX_U32_LEB128_BYTES] = {0}; - uint32_t result = ctx->stream.offset; + uint32_t result = ctx->stream.offset(); uint32_t bytes_to_write = ctx->options->canonicalize_lebs ? leb_size_guess : MAX_U32_LEB128_BYTES; - write_data(&ctx->stream, data, bytes_to_write, desc); + ctx->stream.WriteData(data, bytes_to_write, desc); return result; } @@ -225,17 +221,17 @@ static void write_fixup_u32_leb128_size(Context* ctx, uint32_t leb_size_guess, const char* desc) { if (ctx->options->canonicalize_lebs) { - uint32_t size = ctx->stream.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->stream, dst_offset, src_offset, size); + ctx->stream.MoveData(dst_offset, src_offset, size); } write_u32_leb128_at(&ctx->stream, offset, size, desc); - ctx->stream.offset += leb_size - leb_size_guess; + ctx->stream.AddOffset(leb_size - leb_size_guess); } else { - uint32_t size = ctx->stream.offset - offset - MAX_U32_LEB128_BYTES; + uint32_t size = ctx->stream.offset() - offset - MAX_U32_LEB128_BYTES; write_fixed_u32_leb128_at(&ctx->stream, offset, size, desc); } } @@ -243,15 +239,14 @@ static void write_fixup_u32_leb128_size(Context* ctx, void write_str(Stream* stream, const char* s, size_t length, - PrintChars print_chars, - const char* desc) { + const char* desc, + PrintChars print_chars) { write_u32_leb128(stream, length, "string length"); - write_data_at(stream, stream->offset, s, length, print_chars, desc); - stream->offset += length; + stream->WriteData(s, length, desc, print_chars); } void write_opcode(Stream* stream, Opcode opcode) { - write_u8_enum(stream, opcode, get_opcode_name(opcode)); + stream->WriteU8Enum(opcode, get_opcode_name(opcode)); } void write_type(Stream* stream, Type type) { @@ -266,7 +261,7 @@ static void write_inline_signature_type(Stream* stream, write_type(stream, sig[0]); } else { /* this is currently unrepresentable */ - write_u8(stream, 0xff, "INVALID INLINE SIGNATURE"); + stream->WriteU8(0xff, "INVALID INLINE SIGNATURE"); } } @@ -278,12 +273,12 @@ static void begin_known_section(Context* ctx, wabt_snprintf(desc, sizeof(desc), "section \"%s\" (%u)", get_section_name(section_code), static_cast<unsigned>(section_code)); write_header(ctx, desc, PRINT_HEADER_NO_INDEX); - write_u8_enum(&ctx->stream, section_code, "section code"); + ctx->stream.WriteU8Enum(section_code, "section code"); ctx->last_section_type = section_code; ctx->last_section_leb_size_guess = leb_size_guess; ctx->last_section_offset = write_u32_leb128_space(ctx, leb_size_guess, "section size (guess)"); - ctx->last_section_payload_offset = ctx->stream.offset; + ctx->last_section_payload_offset = ctx->stream.offset(); } static void begin_custom_section(Context* ctx, @@ -293,14 +288,14 @@ static void begin_custom_section(Context* ctx, char desc[100]; wabt_snprintf(desc, sizeof(desc), "section \"%s\"", name); write_header(ctx, desc, PRINT_HEADER_NO_INDEX); - write_u8_enum(&ctx->stream, BinarySection::Custom, "custom section code"); + ctx->stream.WriteU8Enum(BinarySection::Custom, "custom section code"); ctx->last_section_type = BinarySection::Custom; ctx->last_section_leb_size_guess = leb_size_guess; ctx->last_section_offset = write_u32_leb128_space(ctx, leb_size_guess, "section size (guess)"); - ctx->last_section_payload_offset = ctx->stream.offset; - write_str(&ctx->stream, name, strlen(name), PrintChars::Yes, - "custom section name"); + ctx->last_section_payload_offset = ctx->stream.offset(); + write_str(&ctx->stream, name, strlen(name), "custom section name", + PrintChars::Yes); } static void end_section(Context* ctx) { @@ -318,7 +313,7 @@ static void begin_subsection(Context* ctx, ctx->last_subsection_leb_size_guess = leb_size_guess; ctx->last_subsection_offset = write_u32_leb128_space(ctx, leb_size_guess, "subsection size (guess)"); - ctx->last_subsection_payload_offset = ctx->stream.offset; + ctx->last_subsection_payload_offset = ctx->stream.offset(); } static void end_subsection(Context* ctx) { @@ -349,7 +344,7 @@ static void add_reloc(Context* ctx, RelocType reloc_type, uint32_t index) { } // Add a new relocation to the curent reloc section - size_t offset = ctx->stream.offset - ctx->last_section_payload_offset; + size_t offset = ctx->stream.offset() - ctx->last_section_payload_offset; ctx->current_reloc_section->relocations.emplace_back(reloc_type, offset, index); } @@ -433,11 +428,11 @@ static void write_expr(Context* ctx, break; case Type::F32: write_opcode(&ctx->stream, Opcode::F32Const); - write_u32(&ctx->stream, expr->const_.f32_bits, "f32 literal"); + ctx->stream.WriteU32(expr->const_.f32_bits, "f32 literal"); break; case Type::F64: write_opcode(&ctx->stream, Opcode::F64Const); - write_u64(&ctx->stream, expr->const_.f64_bits, "f64 literal"); + ctx->stream.WriteU64(expr->const_.f64_bits, "f64 literal"); break; default: assert(0); @@ -484,7 +479,7 @@ static void write_expr(Context* ctx, write_opcode(&ctx->stream, expr->load.opcode); uint32_t align = get_opcode_alignment(expr->load.opcode, expr->load.align); - write_u8(&ctx->stream, log2_u32(align), "alignment"); + ctx->stream.WriteU8(log2_u32(align), "alignment"); write_u32_leb128(&ctx->stream, expr->load.offset, "load offset"); break; } @@ -520,7 +515,7 @@ static void write_expr(Context* ctx, write_opcode(&ctx->stream, expr->store.opcode); uint32_t align = get_opcode_alignment(expr->store.opcode, expr->store.align); - write_u8(&ctx->stream, log2_u32(align), "alignment"); + ctx->stream.WriteU8(log2_u32(align), "alignment"); write_u32_leb128(&ctx->stream, expr->store.offset, "store offset"); break; } @@ -624,7 +619,7 @@ static void write_memory(Context* ctx, const Memory* memory) { static void write_global_header(Context* ctx, const Global* global) { write_type(&ctx->stream, global->type); - write_u8(&ctx->stream, global->mutable_, "global mutability"); + ctx->stream.WriteU8(global->mutable_, "global mutability"); } static void write_reloc_section(Context* ctx, RelocSection* reloc_section) { @@ -656,8 +651,8 @@ static void write_reloc_section(Context* ctx, RelocSection* reloc_section) { } static Result write_module(Context* ctx, const Module* module) { - write_u32(&ctx->stream, WABT_BINARY_MAGIC, "WASM_BINARY_MAGIC"); - write_u32(&ctx->stream, WABT_BINARY_VERSION, "WASM_BINARY_VERSION"); + ctx->stream.WriteU32(WABT_BINARY_MAGIC, "WASM_BINARY_MAGIC"); + ctx->stream.WriteU32(WABT_BINARY_VERSION, "WASM_BINARY_VERSION"); if (module->func_types.size()) { begin_known_section(ctx, BinarySection::Type, LEB_SECTION_SIZE_GUESS); @@ -689,12 +684,12 @@ static Result write_module(Context* ctx, const Module* module) { const Import* import = module->imports[i]; write_header(ctx, "import header", i); write_str(&ctx->stream, import->module_name.start, - import->module_name.length, PrintChars::Yes, - "import module name"); + import->module_name.length, "import module name", + PrintChars::Yes); write_str(&ctx->stream, import->field_name.start, - import->field_name.length, PrintChars::Yes, - "import field name"); - write_u8_enum(&ctx->stream, import->kind, "import kind"); + import->field_name.length, "import field name", + PrintChars::Yes); + ctx->stream.WriteU8Enum(import->kind, "import kind"); switch (import->kind) { case ExternalKind::Func: write_u32_leb128(&ctx->stream, get_func_type_index_by_decl( @@ -778,8 +773,8 @@ static Result write_module(Context* ctx, const Module* module) { for (const Export* export_ : module->exports) { write_str(&ctx->stream, export_->name.start, export_->name.length, - PrintChars::Yes, "export name"); - write_u8_enum(&ctx->stream, export_->kind, "export kind"); + "export name", PrintChars::Yes); + ctx->stream.WriteU8Enum(export_->kind, "export kind"); switch (export_->kind) { case ExternalKind::Func: { int index = get_func_index_by_var(module, &export_->var); @@ -867,8 +862,7 @@ static Result write_module(Context* ctx, const Module* module) { write_init_expr(ctx, module, segment->offset); write_u32_leb128(&ctx->stream, segment->size, "data segment size"); write_header(ctx, "data segment data", i); - write_data(&ctx->stream, segment->data, segment->size, - "data segment data"); + ctx->stream.WriteData(segment->data, segment->size, "data segment data"); } end_section(ctx); } @@ -896,8 +890,8 @@ static Result write_module(Context* ctx, const Module* module) { continue; write_u32_leb128(&ctx->stream, i, "function index"); wabt_snprintf(desc, sizeof(desc), "func name %" PRIzd, i); - write_str(&ctx->stream, func->name.start, func->name.length, - PrintChars::Yes, desc); + write_str(&ctx->stream, func->name.start, func->name.length, desc, + PrintChars::Yes); } end_subsection(ctx); } @@ -921,8 +915,8 @@ static Result write_module(Context* ctx, const Module* module) { const std::string& name = index_to_name[j]; wabt_snprintf(desc, sizeof(desc), "local name %" PRIzd, j); write_u32_leb128(&ctx->stream, j, "local index"); - write_str(&ctx->stream, name.data(), name.length(), PrintChars::Yes, - desc); + write_str(&ctx->stream, name.data(), name.length(), desc, + PrintChars::Yes); } make_type_binding_reverse_mapping(func->local_types, func->local_bindings, @@ -931,8 +925,8 @@ static Result write_module(Context* ctx, const Module* module) { const std::string& name = index_to_name[j]; wabt_snprintf(desc, sizeof(desc), "local name %" PRIzd, num_params + j); write_u32_leb128(&ctx->stream, num_params + j, "local index"); - write_str(&ctx->stream, name.data(), name.length(), PrintChars::Yes, - desc); + write_str(&ctx->stream, name.data(), name.length(), desc, + PrintChars::Yes); } } end_subsection(ctx); @@ -945,16 +939,13 @@ static Result write_module(Context* ctx, const Module* module) { } } - return ctx->stream.result; + return ctx->stream.result(); } Result write_binary_module(Writer* writer, const Module* module, const WriteBinaryOptions* options) { - Context ctx; - ctx.options = options; - ctx.log_stream = options->log_stream; - init_stream(&ctx.stream, writer, ctx.log_stream); + Context ctx(writer, options); return write_module(&ctx, module); } diff --git a/src/binary-writer.h b/src/binary-writer.h index 830f0d9b..0b131b7f 100644 --- a/src/binary-writer.h +++ b/src/binary-writer.h @@ -22,37 +22,32 @@ namespace wabt { +class Writer; struct Module; struct Script; -struct Writer; -struct Stream; #define WABT_WRITE_BINARY_OPTIONS_DEFAULT \ { nullptr, true, false, false } struct WriteBinaryOptions { - struct Stream* log_stream; + Stream* log_stream; bool canonicalize_lebs; bool relocatable; bool write_debug_names; }; -Result write_binary_module(struct Writer*, - const struct Module*, - const WriteBinaryOptions*); +Result write_binary_module(Writer*, const Module*, const WriteBinaryOptions*); /* returns the length of the leb128 */ uint32_t u32_leb128_length(uint32_t value); -void write_u32_leb128(struct Stream* stream, uint32_t value, const char* desc); +void write_u32_leb128(Stream* stream, uint32_t value, const char* desc); -void write_i32_leb128(struct Stream* stream, int32_t value, const char* desc); +void write_i32_leb128(Stream* stream, int32_t value, const char* desc); -void write_fixed_u32_leb128(struct Stream* stream, - uint32_t value, - const char* desc); +void write_fixed_u32_leb128(Stream* stream, uint32_t value, const char* desc); -uint32_t write_fixed_u32_leb128_at(struct Stream* stream, +uint32_t write_fixed_u32_leb128_at(Stream* stream, uint32_t offset, uint32_t value, const char* desc); @@ -61,26 +56,26 @@ uint32_t write_fixed_u32_leb128_raw(uint8_t* data, uint8_t* end, uint32_t value); -void write_type(struct Stream* stream, Type type); +void write_type(Stream* stream, Type type); -void write_str(struct Stream* stream, +void write_str(Stream* stream, const char* s, size_t length, - PrintChars print_chars, - const char* desc); + const char* desc, + PrintChars print_chars = PrintChars::No); -void write_opcode(struct Stream* stream, Opcode opcode); +void write_opcode(Stream* stream, Opcode opcode); -void write_limits(struct Stream* stream, const Limits* limits); +void write_limits(Stream* stream, const Limits* limits); /* Convenience functions for writing enums as LEB128s. */ template <typename T> -void write_u32_leb128_enum(struct Stream* stream, T value, const char* desc) { +void write_u32_leb128_enum(Stream* stream, T value, const char* desc) { write_u32_leb128(stream, static_cast<uint32_t>(value), desc); } template <typename T> -void write_i32_leb128_enum(struct Stream* stream, T value, const char* desc) { +void write_i32_leb128_enum(Stream* stream, T value, const char* desc) { write_i32_leb128(stream, static_cast<int32_t>(value), desc); } diff --git a/src/interpreter.cc b/src/interpreter.cc index 98e58b30..ba56db94 100644 --- a/src/interpreter.cc +++ b/src/interpreter.cc @@ -25,8 +25,6 @@ #include "stream.h" -#define INITIAL_ISTREAM_CAPACITY (64 * 1024) - namespace wabt { static const char* s_interpreter_opcode_name[256]; @@ -57,10 +55,8 @@ static const char* get_interpreter_opcode_name(InterpreterOpcode opcode) { return s_interpreter_opcode_name[static_cast<int>(opcode)]; } -InterpreterEnvironment::InterpreterEnvironment() { - WABT_ZERO_MEMORY(istream); - init_output_buffer(&istream, INITIAL_ISTREAM_CAPACITY); -} +InterpreterEnvironment::InterpreterEnvironment() + : istream(new OutputBuffer()) {} InterpreterThread::InterpreterThread() : env(nullptr), @@ -156,10 +152,6 @@ DefinedInterpreterModule::DefinedInterpreterModule(size_t istream_start) HostInterpreterModule::HostInterpreterModule(const StringSlice& name) : InterpreterModule(name, true) {} -void destroy_interpreter_environment(InterpreterEnvironment* env) { - destroy_output_buffer(&env->istream); -} - InterpreterEnvironmentMark mark_interpreter_environment( InterpreterEnvironment* env) { InterpreterEnvironmentMark mark; @@ -170,7 +162,7 @@ InterpreterEnvironmentMark mark_interpreter_environment( mark.memories_size = env->memories.size(); mark.tables_size = env->tables.size(); mark.globals_size = env->globals.size(); - mark.istream_size = env->istream.size; + mark.istream_size = env->istream->data.size(); return mark; } @@ -203,7 +195,7 @@ void reset_interpreter_environment_to_mark(InterpreterEnvironment* env, env->tables.erase(env->tables.begin() + mark.tables_size, env->tables.end()); env->globals.erase(env->globals.begin() + mark.globals_size, env->globals.end()); - env->istream.size = mark.istream_size; + env->istream->data.resize(mark.istream_size); } HostInterpreterModule* append_host_module(InterpreterEnvironment* env, @@ -567,8 +559,7 @@ DEFINE_BITCAST(bitcast_u64_to_f64, uint64_t, double) MEM_TYPE_##mem_type value; \ TRAP_IF(offset + sizeof(value) > memory->data.size(), \ MemoryAccessOutOfBounds); \ - void* src = static_cast<void*>(memory->data.data() + \ - static_cast<uint32_t>(offset)); \ + void* src = memory->data.data() + static_cast<uint32_t>(offset); \ memcpy(&value, src, sizeof(MEM_TYPE_##mem_type)); \ PUSH_##type(static_cast<MEM_TYPE_EXTEND_##type##_##mem_type>(value)); \ } while (0) @@ -581,8 +572,7 @@ DEFINE_BITCAST(bitcast_u64_to_f64, uint64_t, double) MEM_TYPE_##mem_type src = static_cast<MEM_TYPE_##mem_type>(value); \ TRAP_IF(offset + sizeof(src) > memory->data.size(), \ MemoryAccessOutOfBounds); \ - void* dst = static_cast<void*>(memory->data.data() + \ - static_cast<uint32_t>(offset)); \ + void* dst = memory->data.data() + static_cast<uint32_t>(offset); \ memcpy(dst, &src, sizeof(MEM_TYPE_##mem_type)); \ } while (0) @@ -820,7 +810,7 @@ InterpreterResult run_interpreter(InterpreterThread* thread, InterpreterEnvironment* env = thread->env; - const uint8_t* istream = reinterpret_cast<const uint8_t*>(env->istream.start); + const uint8_t* istream = env->istream->data.data(); const uint8_t* pc = &istream[thread->pc]; for (uint32_t i = 0; i < num_instructions; ++i) { InterpreterOpcode opcode = static_cast<InterpreterOpcode>(*pc++); @@ -1712,42 +1702,40 @@ exit_loop: } void trace_pc(InterpreterThread* thread, Stream* stream) { - const uint8_t* istream = - reinterpret_cast<const uint8_t*>(thread->env->istream.start); + const uint8_t* istream = thread->env->istream->data.data(); const uint8_t* pc = &istream[thread->pc]; size_t value_stack_depth = thread->value_stack_top - thread->value_stack.data(); size_t call_stack_depth = thread->call_stack_top - thread->call_stack.data(); - writef(stream, "#%" PRIzd ". %4" PRIzd ": V:%-3" PRIzd "| ", call_stack_depth, - pc - reinterpret_cast<uint8_t*>(thread->env->istream.start), - value_stack_depth); + stream->Writef("#%" PRIzd ". %4" PRIzd ": V:%-3" PRIzd "| ", call_stack_depth, + pc - thread->env->istream->data.data(), value_stack_depth); InterpreterOpcode opcode = static_cast<InterpreterOpcode>(*pc++); switch (opcode) { case InterpreterOpcode::Select: - writef(stream, "%s %u, %" PRIu64 ", %" PRIu64 "\n", - get_interpreter_opcode_name(opcode), PICK(3).i32, PICK(2).i64, - PICK(1).i64); + stream->Writef("%s %u, %" PRIu64 ", %" PRIu64 "\n", + get_interpreter_opcode_name(opcode), PICK(3).i32, + PICK(2).i64, PICK(1).i64); break; case InterpreterOpcode::Br: - writef(stream, "%s @%u\n", get_interpreter_opcode_name(opcode), - read_u32_at(pc)); + stream->Writef("%s @%u\n", get_interpreter_opcode_name(opcode), + read_u32_at(pc)); break; case InterpreterOpcode::BrIf: - writef(stream, "%s @%u, %u\n", get_interpreter_opcode_name(opcode), - read_u32_at(pc), TOP().i32); + stream->Writef("%s @%u, %u\n", get_interpreter_opcode_name(opcode), + read_u32_at(pc), TOP().i32); break; case InterpreterOpcode::BrTable: { uint32_t num_targets = read_u32_at(pc); uint32_t table_offset = read_u32_at(pc + 4); VALUE_TYPE_I32 key = TOP().i32; - writef(stream, "%s %u, $#%u, table:$%u\n", - get_interpreter_opcode_name(opcode), key, num_targets, - table_offset); + stream->Writef("%s %u, $#%u, table:$%u\n", + get_interpreter_opcode_name(opcode), key, num_targets, + table_offset); break; } @@ -1755,62 +1743,62 @@ void trace_pc(InterpreterThread* thread, Stream* stream) { case InterpreterOpcode::Return: case InterpreterOpcode::Unreachable: case InterpreterOpcode::Drop: - writef(stream, "%s\n", get_interpreter_opcode_name(opcode)); + stream->Writef("%s\n", get_interpreter_opcode_name(opcode)); break; case InterpreterOpcode::CurrentMemory: { uint32_t memory_index = read_u32(&pc); - writef(stream, "%s $%u\n", get_interpreter_opcode_name(opcode), - memory_index); + stream->Writef("%s $%u\n", get_interpreter_opcode_name(opcode), + memory_index); break; } case InterpreterOpcode::I32Const: - writef(stream, "%s $%u\n", get_interpreter_opcode_name(opcode), - read_u32_at(pc)); + stream->Writef("%s $%u\n", get_interpreter_opcode_name(opcode), + read_u32_at(pc)); break; case InterpreterOpcode::I64Const: - writef(stream, "%s $%" PRIu64 "\n", get_interpreter_opcode_name(opcode), - read_u64_at(pc)); + stream->Writef("%s $%" PRIu64 "\n", get_interpreter_opcode_name(opcode), + read_u64_at(pc)); break; case InterpreterOpcode::F32Const: - writef(stream, "%s $%g\n", get_interpreter_opcode_name(opcode), - bitcast_u32_to_f32(read_u32_at(pc))); + stream->Writef("%s $%g\n", get_interpreter_opcode_name(opcode), + bitcast_u32_to_f32(read_u32_at(pc))); break; case InterpreterOpcode::F64Const: - writef(stream, "%s $%g\n", get_interpreter_opcode_name(opcode), - bitcast_u64_to_f64(read_u64_at(pc))); + stream->Writef("%s $%g\n", get_interpreter_opcode_name(opcode), + bitcast_u64_to_f64(read_u64_at(pc))); break; case InterpreterOpcode::GetLocal: case InterpreterOpcode::GetGlobal: - writef(stream, "%s $%u\n", get_interpreter_opcode_name(opcode), - read_u32_at(pc)); + stream->Writef("%s $%u\n", get_interpreter_opcode_name(opcode), + read_u32_at(pc)); break; case InterpreterOpcode::SetLocal: case InterpreterOpcode::SetGlobal: case InterpreterOpcode::TeeLocal: - writef(stream, "%s $%u, %u\n", get_interpreter_opcode_name(opcode), - read_u32_at(pc), TOP().i32); + stream->Writef("%s $%u, %u\n", get_interpreter_opcode_name(opcode), + read_u32_at(pc), TOP().i32); break; case InterpreterOpcode::Call: - writef(stream, "%s @%u\n", get_interpreter_opcode_name(opcode), - read_u32_at(pc)); + stream->Writef("%s @%u\n", get_interpreter_opcode_name(opcode), + read_u32_at(pc)); break; case InterpreterOpcode::CallIndirect: - writef(stream, "%s $%u, %u\n", get_interpreter_opcode_name(opcode), - read_u32_at(pc), TOP().i32); + stream->Writef("%s $%u, %u\n", get_interpreter_opcode_name(opcode), + read_u32_at(pc), TOP().i32); break; case InterpreterOpcode::CallHost: - writef(stream, "%s $%u\n", get_interpreter_opcode_name(opcode), - read_u32_at(pc)); + stream->Writef("%s $%u\n", get_interpreter_opcode_name(opcode), + read_u32_at(pc)); break; case InterpreterOpcode::I32Load8S: @@ -1828,8 +1816,8 @@ void trace_pc(InterpreterThread* thread, Stream* stream) { case InterpreterOpcode::F32Load: case InterpreterOpcode::F64Load: { uint32_t memory_index = read_u32(&pc); - writef(stream, "%s $%u:%u+$%u\n", get_interpreter_opcode_name(opcode), - memory_index, TOP().i32, read_u32_at(pc)); + stream->Writef("%s $%u:%u+$%u\n", get_interpreter_opcode_name(opcode), + memory_index, TOP().i32, read_u32_at(pc)); break; } @@ -1837,8 +1825,8 @@ void trace_pc(InterpreterThread* thread, Stream* stream) { case InterpreterOpcode::I32Store16: case InterpreterOpcode::I32Store: { uint32_t memory_index = read_u32(&pc); - writef(stream, "%s $%u:%u+$%u, %u\n", get_interpreter_opcode_name(opcode), - memory_index, PICK(2).i32, read_u32_at(pc), PICK(1).i32); + stream->Writef("%s $%u:%u+$%u, %u\n", get_interpreter_opcode_name(opcode), + memory_index, PICK(2).i32, read_u32_at(pc), PICK(1).i32); break; } @@ -1847,32 +1835,32 @@ void trace_pc(InterpreterThread* thread, Stream* stream) { case InterpreterOpcode::I64Store32: case InterpreterOpcode::I64Store: { uint32_t memory_index = read_u32(&pc); - writef(stream, "%s $%u:%u+$%u, %" PRIu64 "\n", - get_interpreter_opcode_name(opcode), memory_index, PICK(2).i32, - read_u32_at(pc), PICK(1).i64); + stream->Writef("%s $%u:%u+$%u, %" PRIu64 "\n", + get_interpreter_opcode_name(opcode), memory_index, + PICK(2).i32, read_u32_at(pc), PICK(1).i64); break; } case InterpreterOpcode::F32Store: { uint32_t memory_index = read_u32(&pc); - writef(stream, "%s $%u:%u+$%u, %g\n", get_interpreter_opcode_name(opcode), - memory_index, PICK(2).i32, read_u32_at(pc), - bitcast_u32_to_f32(PICK(1).f32_bits)); + stream->Writef("%s $%u:%u+$%u, %g\n", get_interpreter_opcode_name(opcode), + memory_index, PICK(2).i32, read_u32_at(pc), + bitcast_u32_to_f32(PICK(1).f32_bits)); break; } case InterpreterOpcode::F64Store: { uint32_t memory_index = read_u32(&pc); - writef(stream, "%s $%u:%u+$%u, %g\n", get_interpreter_opcode_name(opcode), - memory_index, PICK(2).i32, read_u32_at(pc), - bitcast_u64_to_f64(PICK(1).f64_bits)); + stream->Writef("%s $%u:%u+$%u, %g\n", get_interpreter_opcode_name(opcode), + memory_index, PICK(2).i32, read_u32_at(pc), + bitcast_u64_to_f64(PICK(1).f64_bits)); break; } case InterpreterOpcode::GrowMemory: { uint32_t memory_index = read_u32(&pc); - writef(stream, "%s $%u:%u\n", get_interpreter_opcode_name(opcode), - memory_index, TOP().i32); + stream->Writef("%s $%u:%u\n", get_interpreter_opcode_name(opcode), + memory_index, TOP().i32); break; } @@ -1901,15 +1889,15 @@ void trace_pc(InterpreterThread* thread, Stream* stream) { case InterpreterOpcode::I32GeU: case InterpreterOpcode::I32Rotr: case InterpreterOpcode::I32Rotl: - writef(stream, "%s %u, %u\n", get_interpreter_opcode_name(opcode), - PICK(2).i32, PICK(1).i32); + stream->Writef("%s %u, %u\n", get_interpreter_opcode_name(opcode), + PICK(2).i32, PICK(1).i32); break; case InterpreterOpcode::I32Clz: case InterpreterOpcode::I32Ctz: case InterpreterOpcode::I32Popcnt: case InterpreterOpcode::I32Eqz: - writef(stream, "%s %u\n", get_interpreter_opcode_name(opcode), TOP().i32); + stream->Writef("%s %u\n", get_interpreter_opcode_name(opcode), TOP().i32); break; case InterpreterOpcode::I64Add: @@ -1937,16 +1925,17 @@ void trace_pc(InterpreterThread* thread, Stream* stream) { case InterpreterOpcode::I64GeU: case InterpreterOpcode::I64Rotr: case InterpreterOpcode::I64Rotl: - writef(stream, "%s %" PRIu64 ", %" PRIu64 "\n", - get_interpreter_opcode_name(opcode), PICK(2).i64, PICK(1).i64); + stream->Writef("%s %" PRIu64 ", %" PRIu64 "\n", + get_interpreter_opcode_name(opcode), PICK(2).i64, + PICK(1).i64); break; case InterpreterOpcode::I64Clz: case InterpreterOpcode::I64Ctz: case InterpreterOpcode::I64Popcnt: case InterpreterOpcode::I64Eqz: - writef(stream, "%s %" PRIu64 "\n", get_interpreter_opcode_name(opcode), - TOP().i64); + stream->Writef("%s %" PRIu64 "\n", get_interpreter_opcode_name(opcode), + TOP().i64); break; case InterpreterOpcode::F32Add: @@ -1962,8 +1951,9 @@ void trace_pc(InterpreterThread* thread, Stream* stream) { case InterpreterOpcode::F32Le: case InterpreterOpcode::F32Gt: case InterpreterOpcode::F32Ge: - writef(stream, "%s %g, %g\n", get_interpreter_opcode_name(opcode), - bitcast_u32_to_f32(PICK(2).i32), bitcast_u32_to_f32(PICK(1).i32)); + stream->Writef("%s %g, %g\n", get_interpreter_opcode_name(opcode), + bitcast_u32_to_f32(PICK(2).i32), + bitcast_u32_to_f32(PICK(1).i32)); break; case InterpreterOpcode::F32Abs: @@ -1973,8 +1963,8 @@ void trace_pc(InterpreterThread* thread, Stream* stream) { case InterpreterOpcode::F32Trunc: case InterpreterOpcode::F32Nearest: case InterpreterOpcode::F32Sqrt: - writef(stream, "%s %g\n", get_interpreter_opcode_name(opcode), - bitcast_u32_to_f32(TOP().i32)); + stream->Writef("%s %g\n", get_interpreter_opcode_name(opcode), + bitcast_u32_to_f32(TOP().i32)); break; case InterpreterOpcode::F64Add: @@ -1990,8 +1980,9 @@ void trace_pc(InterpreterThread* thread, Stream* stream) { case InterpreterOpcode::F64Le: case InterpreterOpcode::F64Gt: case InterpreterOpcode::F64Ge: - writef(stream, "%s %g, %g\n", get_interpreter_opcode_name(opcode), - bitcast_u64_to_f64(PICK(2).i64), bitcast_u64_to_f64(PICK(1).i64)); + stream->Writef("%s %g, %g\n", get_interpreter_opcode_name(opcode), + bitcast_u64_to_f64(PICK(2).i64), + bitcast_u64_to_f64(PICK(1).i64)); break; case InterpreterOpcode::F64Abs: @@ -2001,8 +1992,8 @@ void trace_pc(InterpreterThread* thread, Stream* stream) { case InterpreterOpcode::F64Trunc: case InterpreterOpcode::F64Nearest: case InterpreterOpcode::F64Sqrt: - writef(stream, "%s %g\n", get_interpreter_opcode_name(opcode), - bitcast_u64_to_f64(TOP().i64)); + stream->Writef("%s %g\n", get_interpreter_opcode_name(opcode), + bitcast_u64_to_f64(TOP().i64)); break; case InterpreterOpcode::I32TruncSF32: @@ -2011,8 +2002,8 @@ void trace_pc(InterpreterThread* thread, Stream* stream) { case InterpreterOpcode::I64TruncUF32: case InterpreterOpcode::F64PromoteF32: case InterpreterOpcode::I32ReinterpretF32: - writef(stream, "%s %g\n", get_interpreter_opcode_name(opcode), - bitcast_u32_to_f32(TOP().i32)); + stream->Writef("%s %g\n", get_interpreter_opcode_name(opcode), + bitcast_u32_to_f32(TOP().i32)); break; case InterpreterOpcode::I32TruncSF64: @@ -2021,8 +2012,8 @@ void trace_pc(InterpreterThread* thread, Stream* stream) { case InterpreterOpcode::I64TruncUF64: case InterpreterOpcode::F32DemoteF64: case InterpreterOpcode::I64ReinterpretF64: - writef(stream, "%s %g\n", get_interpreter_opcode_name(opcode), - bitcast_u64_to_f64(TOP().i64)); + stream->Writef("%s %g\n", get_interpreter_opcode_name(opcode), + bitcast_u64_to_f64(TOP().i64)); break; case InterpreterOpcode::I32WrapI64: @@ -2031,8 +2022,8 @@ void trace_pc(InterpreterThread* thread, Stream* stream) { case InterpreterOpcode::F64ConvertSI64: case InterpreterOpcode::F64ConvertUI64: case InterpreterOpcode::F64ReinterpretI64: - writef(stream, "%s %" PRIu64 "\n", get_interpreter_opcode_name(opcode), - TOP().i64); + stream->Writef("%s %" PRIu64 "\n", get_interpreter_opcode_name(opcode), + TOP().i64); break; case InterpreterOpcode::I64ExtendSI32: @@ -2042,22 +2033,22 @@ void trace_pc(InterpreterThread* thread, Stream* stream) { case InterpreterOpcode::F32ReinterpretI32: case InterpreterOpcode::F64ConvertSI32: case InterpreterOpcode::F64ConvertUI32: - writef(stream, "%s %u\n", get_interpreter_opcode_name(opcode), TOP().i32); + stream->Writef("%s %u\n", get_interpreter_opcode_name(opcode), TOP().i32); break; case InterpreterOpcode::Alloca: - writef(stream, "%s $%u\n", get_interpreter_opcode_name(opcode), - read_u32_at(pc)); + stream->Writef("%s $%u\n", get_interpreter_opcode_name(opcode), + read_u32_at(pc)); break; case InterpreterOpcode::BrUnless: - writef(stream, "%s @%u, %u\n", get_interpreter_opcode_name(opcode), - read_u32_at(pc), TOP().i32); + stream->Writef("%s @%u, %u\n", get_interpreter_opcode_name(opcode), + read_u32_at(pc), TOP().i32); break; case InterpreterOpcode::DropKeep: - writef(stream, "%s $%u $%u\n", get_interpreter_opcode_name(opcode), - read_u32_at(pc), *(pc + 4)); + stream->Writef("%s $%u $%u\n", get_interpreter_opcode_name(opcode), + read_u32_at(pc), *(pc + 4)); break; case InterpreterOpcode::Data: @@ -2077,38 +2068,38 @@ void disassemble(InterpreterEnvironment* env, uint32_t to) { /* TODO(binji): mark function entries */ /* TODO(binji): track value stack size */ - if (from >= env->istream.size) + if (from >= env->istream->data.size()) return; - if (to > env->istream.size) - to = env->istream.size; - const uint8_t* istream = reinterpret_cast<const uint8_t*>(env->istream.start); + to = std::min<uint32_t>(to, env->istream->data.size()); + const uint8_t* istream = env->istream->data.data(); const uint8_t* pc = &istream[from]; while (static_cast<uint32_t>(pc - istream) < to) { - writef(stream, "%4" PRIzd "| ", pc - istream); + stream->Writef("%4" PRIzd "| ", pc - istream); InterpreterOpcode opcode = static_cast<InterpreterOpcode>(*pc++); switch (opcode) { case InterpreterOpcode::Select: - writef(stream, "%s %%[-3], %%[-2], %%[-1]\n", - get_interpreter_opcode_name(opcode)); + stream->Writef("%s %%[-3], %%[-2], %%[-1]\n", + get_interpreter_opcode_name(opcode)); break; case InterpreterOpcode::Br: - writef(stream, "%s @%u\n", get_interpreter_opcode_name(opcode), - read_u32(&pc)); + stream->Writef("%s @%u\n", get_interpreter_opcode_name(opcode), + read_u32(&pc)); break; case InterpreterOpcode::BrIf: - writef(stream, "%s @%u, %%[-1]\n", get_interpreter_opcode_name(opcode), - read_u32(&pc)); + stream->Writef("%s @%u, %%[-1]\n", get_interpreter_opcode_name(opcode), + read_u32(&pc)); break; case InterpreterOpcode::BrTable: { uint32_t num_targets = read_u32(&pc); uint32_t table_offset = read_u32(&pc); - writef(stream, "%s %%[-1], $#%u, table:$%u\n", - get_interpreter_opcode_name(opcode), num_targets, table_offset); + stream->Writef("%s %%[-1], $#%u, table:$%u\n", + get_interpreter_opcode_name(opcode), num_targets, + table_offset); break; } @@ -2116,64 +2107,65 @@ void disassemble(InterpreterEnvironment* env, case InterpreterOpcode::Return: case InterpreterOpcode::Unreachable: case InterpreterOpcode::Drop: - writef(stream, "%s\n", get_interpreter_opcode_name(opcode)); + stream->Writef("%s\n", get_interpreter_opcode_name(opcode)); break; case InterpreterOpcode::CurrentMemory: { uint32_t memory_index = read_u32(&pc); - writef(stream, "%s $%u\n", get_interpreter_opcode_name(opcode), - memory_index); + stream->Writef("%s $%u\n", get_interpreter_opcode_name(opcode), + memory_index); break; } case InterpreterOpcode::I32Const: - writef(stream, "%s $%u\n", get_interpreter_opcode_name(opcode), - read_u32(&pc)); + stream->Writef("%s $%u\n", get_interpreter_opcode_name(opcode), + read_u32(&pc)); break; case InterpreterOpcode::I64Const: - writef(stream, "%s $%" PRIu64 "\n", get_interpreter_opcode_name(opcode), - read_u64(&pc)); + stream->Writef("%s $%" PRIu64 "\n", get_interpreter_opcode_name(opcode), + read_u64(&pc)); break; case InterpreterOpcode::F32Const: - writef(stream, "%s $%g\n", get_interpreter_opcode_name(opcode), - bitcast_u32_to_f32(read_u32(&pc))); + stream->Writef("%s $%g\n", get_interpreter_opcode_name(opcode), + bitcast_u32_to_f32(read_u32(&pc))); break; case InterpreterOpcode::F64Const: - writef(stream, "%s $%g\n", get_interpreter_opcode_name(opcode), - bitcast_u64_to_f64(read_u64(&pc))); + stream->Writef("%s $%g\n", get_interpreter_opcode_name(opcode), + bitcast_u64_to_f64(read_u64(&pc))); break; case InterpreterOpcode::GetLocal: case InterpreterOpcode::GetGlobal: - writef(stream, "%s $%u\n", get_interpreter_opcode_name(opcode), - read_u32(&pc)); + stream->Writef("%s $%u\n", get_interpreter_opcode_name(opcode), + read_u32(&pc)); break; case InterpreterOpcode::SetLocal: case InterpreterOpcode::SetGlobal: case InterpreterOpcode::TeeLocal: - writef(stream, "%s $%u, %%[-1]\n", get_interpreter_opcode_name(opcode), - read_u32(&pc)); + stream->Writef("%s $%u, %%[-1]\n", get_interpreter_opcode_name(opcode), + read_u32(&pc)); break; case InterpreterOpcode::Call: - writef(stream, "%s @%u\n", get_interpreter_opcode_name(opcode), - read_u32(&pc)); + stream->Writef("%s @%u\n", get_interpreter_opcode_name(opcode), + read_u32(&pc)); break; case InterpreterOpcode::CallIndirect: { uint32_t table_index = read_u32(&pc); - writef(stream, "%s $%u:%u, %%[-1]\n", - get_interpreter_opcode_name(opcode), table_index, read_u32(&pc)); + stream->Writef("%s $%u:%u, %%[-1]\n", + get_interpreter_opcode_name(opcode), table_index, + read_u32(&pc)); break; } case InterpreterOpcode::CallHost: - writef(stream, "%s $%u\n", get_interpreter_opcode_name(opcode), - read_u32(&pc)); + stream->Writef("%s $%u\n", get_interpreter_opcode_name(opcode), + read_u32(&pc)); break; case InterpreterOpcode::I32Load8S: @@ -2191,9 +2183,9 @@ void disassemble(InterpreterEnvironment* env, case InterpreterOpcode::F32Load: case InterpreterOpcode::F64Load: { uint32_t memory_index = read_u32(&pc); - writef(stream, "%s $%u:%%[-1]+$%u\n", - get_interpreter_opcode_name(opcode), memory_index, - read_u32(&pc)); + stream->Writef("%s $%u:%%[-1]+$%u\n", + get_interpreter_opcode_name(opcode), memory_index, + read_u32(&pc)); break; } @@ -2207,9 +2199,9 @@ void disassemble(InterpreterEnvironment* env, case InterpreterOpcode::F32Store: case InterpreterOpcode::F64Store: { uint32_t memory_index = read_u32(&pc); - writef(stream, "%s %%[-2]+$%u, $%u:%%[-1]\n", - get_interpreter_opcode_name(opcode), memory_index, - read_u32(&pc)); + stream->Writef("%s %%[-2]+$%u, $%u:%%[-1]\n", + get_interpreter_opcode_name(opcode), memory_index, + read_u32(&pc)); break; } @@ -2289,8 +2281,8 @@ void disassemble(InterpreterEnvironment* env, case InterpreterOpcode::F64Le: case InterpreterOpcode::F64Gt: case InterpreterOpcode::F64Ge: - writef(stream, "%s %%[-2], %%[-1]\n", - get_interpreter_opcode_name(opcode)); + stream->Writef("%s %%[-2], %%[-1]\n", + get_interpreter_opcode_name(opcode)); break; case InterpreterOpcode::I32Clz: @@ -2340,50 +2332,50 @@ void disassemble(InterpreterEnvironment* env, case InterpreterOpcode::F32ReinterpretI32: case InterpreterOpcode::F64ConvertSI32: case InterpreterOpcode::F64ConvertUI32: - writef(stream, "%s %%[-1]\n", get_interpreter_opcode_name(opcode)); + stream->Writef("%s %%[-1]\n", get_interpreter_opcode_name(opcode)); break; case InterpreterOpcode::GrowMemory: { uint32_t memory_index = read_u32(&pc); - writef(stream, "%s $%u:%%[-1]\n", get_interpreter_opcode_name(opcode), - memory_index); + stream->Writef("%s $%u:%%[-1]\n", get_interpreter_opcode_name(opcode), + memory_index); break; } case InterpreterOpcode::Alloca: - writef(stream, "%s $%u\n", get_interpreter_opcode_name(opcode), - read_u32(&pc)); + stream->Writef("%s $%u\n", get_interpreter_opcode_name(opcode), + read_u32(&pc)); break; case InterpreterOpcode::BrUnless: - writef(stream, "%s @%u, %%[-1]\n", get_interpreter_opcode_name(opcode), - read_u32(&pc)); + stream->Writef("%s @%u, %%[-1]\n", get_interpreter_opcode_name(opcode), + read_u32(&pc)); break; case InterpreterOpcode::DropKeep: { uint32_t drop = read_u32(&pc); uint32_t keep = *pc++; - writef(stream, "%s $%u $%u\n", get_interpreter_opcode_name(opcode), - drop, keep); + stream->Writef("%s $%u $%u\n", get_interpreter_opcode_name(opcode), + drop, keep); break; } case InterpreterOpcode::Data: { uint32_t num_bytes = read_u32(&pc); - writef(stream, "%s $%u\n", get_interpreter_opcode_name(opcode), - num_bytes); + stream->Writef("%s $%u\n", get_interpreter_opcode_name(opcode), + num_bytes); /* for now, the only reason this is emitted is for br_table, so display * it as a list of table entries */ if (num_bytes % WABT_TABLE_ENTRY_SIZE == 0) { uint32_t num_entries = num_bytes / WABT_TABLE_ENTRY_SIZE; for (uint32_t i = 0; i < num_entries; ++i) { - writef(stream, "%4" PRIzd "| ", pc - istream); + stream->Writef("%4" PRIzd "| ", pc - istream); uint32_t offset; uint32_t drop; uint8_t keep; read_table_entry_at(pc, &offset, &drop, &keep); - writef(stream, " entry %d: offset: %u drop: %u keep: %u\n", i, - offset, drop, keep); + stream->Writef(" entry %d: offset: %u drop: %u keep: %u\n", i, + offset, drop, keep); pc += WABT_TABLE_ENTRY_SIZE; } } else { diff --git a/src/interpreter.h b/src/interpreter.h index 28b15b33..8f4143fe 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -28,7 +28,7 @@ namespace wabt { -struct Stream; +class Stream; #define FOREACH_INTERPRETER_RESULT(V) \ V(Ok, "ok") \ @@ -334,7 +334,7 @@ struct InterpreterEnvironment { std::vector<InterpreterMemory> memories; std::vector<InterpreterTable> tables; std::vector<InterpreterGlobal> globals; - OutputBuffer istream; + std::unique_ptr<OutputBuffer> istream; BindingHash module_bindings; BindingHash registered_module_bindings; }; @@ -387,13 +387,13 @@ InterpreterResult call_host(InterpreterThread* thread, InterpreterResult run_interpreter(InterpreterThread* thread, uint32_t num_instructions, uint32_t* call_stack_return_top); -void trace_pc(InterpreterThread* thread, struct Stream* stream); +void trace_pc(InterpreterThread* thread, Stream* stream); void disassemble(InterpreterEnvironment* env, - struct Stream* stream, + Stream* stream, uint32_t from, uint32_t to); void disassemble_module(InterpreterEnvironment* env, - struct Stream* stream, + Stream* stream, InterpreterModule* module); InterpreterExport* get_interpreter_export_by_name(InterpreterModule* module, diff --git a/src/stream.cc b/src/stream.cc index 12510e93..0e1b5c43 100644 --- a/src/stream.cc +++ b/src/stream.cc @@ -24,140 +24,110 @@ namespace wabt { -static FileStream s_stdout_stream; -static FileStream s_stderr_stream; - -void init_stream(Stream* stream, Writer* writer, Stream* log_stream) { - stream->writer = writer; - stream->offset = 0; - stream->result = Result::Ok; - stream->log_stream = log_stream; +Stream::Stream(Writer* writer, Stream* log_stream) + : writer_(writer), + offset_(0), + result_(Result::Ok), + log_stream_(log_stream) {} + +void Stream::AddOffset(ssize_t delta) { + offset_ += delta; } -void init_file_stream_from_existing(FileStream* stream, FILE* file) { - init_file_writer_existing(&stream->writer, file); - init_stream(&stream->base, &stream->writer.base, nullptr); -} - -Stream* init_stdout_stream(void) { - init_file_stream_from_existing(&s_stdout_stream, stdout); - return &s_stdout_stream.base; -} - -Stream* init_stderr_stream(void) { - init_file_stream_from_existing(&s_stderr_stream, stderr); - return &s_stderr_stream.base; -} - -void write_data_at(Stream* stream, - size_t offset, - const void* src, - size_t size, - PrintChars print_chars, - const char* desc) { - if (WABT_FAILED(stream->result)) +void Stream::WriteDataAt(size_t at, + const void* src, + size_t size, + const char* desc, + PrintChars print_chars) { + if (WABT_FAILED(result_)) return; - if (stream->log_stream) { - write_memory_dump(stream->log_stream, src, size, offset, print_chars, - nullptr, desc); - } - if (stream->writer->write_data) { - stream->result = stream->writer->write_data(offset, src, size, - stream->writer->user_data); + if (log_stream_) { + log_stream_->WriteMemoryDump(src, size, at, nullptr, desc, print_chars); } + result_ = writer_->WriteData(at, src, size); } -void write_data(Stream* stream, - const void* src, - size_t size, - const char* desc) { - write_data_at(stream, stream->offset, src, size, PrintChars::No, desc); - stream->offset += size; +void Stream::WriteData(const void* src, + size_t size, + const char* desc, + PrintChars print_chars) { + WriteDataAt(offset_, src, size, desc, print_chars); + offset_ += size; } -void move_data(Stream* stream, - size_t dst_offset, - size_t src_offset, - size_t size) { - if (WABT_FAILED(stream->result)) +void Stream::MoveData(size_t dst_offset, size_t src_offset, size_t size) { + if (WABT_FAILED(result_)) return; - if (stream->log_stream) { - 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); + if (log_stream_) { + log_stream_->Writef( + "; move data: [%" PRIzx ", %" PRIzx ") -> [%" PRIzx ", %" PRIzx ")\n", + src_offset, src_offset + size, dst_offset, dst_offset + size); } + result_ = writer_->MoveData(dst_offset, src_offset, size); } -void writef(Stream* stream, const char* format, ...) { +void Stream::Writef(const char* format, ...) { WABT_SNPRINTF_ALLOCA(buffer, length, format); - write_data(stream, buffer, length, nullptr); -} - -void write_u8(Stream* stream, uint32_t value, const char* desc) { - assert(value <= UINT8_MAX); - uint8_t value8 = value; - write_data_at(stream, stream->offset, &value8, sizeof(value8), PrintChars::No, - desc); - stream->offset += sizeof(value8); -} - -void write_u32(Stream* stream, uint32_t value, const char* desc) { - write_data_at(stream, stream->offset, &value, sizeof(value), PrintChars::No, - desc); - stream->offset += sizeof(value); -} - -void write_u64(Stream* stream, uint64_t value, const char* desc) { - write_data_at(stream, stream->offset, &value, sizeof(value), PrintChars::No, - desc); - stream->offset += sizeof(value); + WriteData(buffer, length); } -void write_memory_dump(Stream* stream, - const void* start, - size_t size, - size_t offset, - PrintChars print_chars, - const char* prefix, - const char* desc) { +void Stream::WriteMemoryDump(const void* start, + size_t size, + size_t offset, + const char* prefix, + const char* desc, + PrintChars print_chars) { const uint8_t* p = static_cast<const uint8_t*>(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; if (prefix) - writef(stream, "%s", prefix); - writef(stream, "%07" PRIzx ": ", reinterpret_cast<intptr_t>(p) - - reinterpret_cast<intptr_t>(start) + - offset); + Writef("%s", prefix); + Writef("%07" PRIzx ": ", reinterpret_cast<intptr_t>(p) - + reinterpret_cast<intptr_t>(start) + offset); while (p < line_end) { for (int i = 0; i < DUMP_OCTETS_PER_GROUP; ++i, ++p) { if (p < end) { - writef(stream, "%02x", *p); + Writef("%02x", *p); } else { - write_char(stream, ' '); - write_char(stream, ' '); + WriteChar(' '); + WriteChar(' '); } } - write_char(stream, ' '); + WriteChar(' '); } if (print_chars == PrintChars::Yes) { - write_char(stream, ' '); + WriteChar(' '); p = line; for (int i = 0; i < DUMP_OCTETS_PER_LINE && p < end; ++i, ++p) - write_char(stream, isprint(*p) ? *p : '.'); + WriteChar(isprint(*p) ? *p : '.'); } /* if there are multiple lines, only print the desc on the last one */ if (p >= end && desc) - writef(stream, " ; %s", desc); - write_char(stream, '\n'); + Writef(" ; %s", desc); + WriteChar('\n'); } } +MemoryStream::MemoryStream() : Stream(&writer_) {} + +FileStream::FileStream(const char* filename) + : Stream(&writer_), writer_(filename) {} + +FileStream::FileStream(FILE* file) : Stream(&writer_), writer_(file) {} + +// static +std::unique_ptr<FileStream> FileStream::CreateStdout() { + return std::unique_ptr<FileStream>(new FileStream(stdout)); +} + +// static +std::unique_ptr<FileStream> FileStream::CreateStderr() { + return std::unique_ptr<FileStream>(new FileStream(stderr)); +} + + } // namespace wabt diff --git a/src/stream.h b/src/stream.h index 8e027333..a43c5c12 100644 --- a/src/stream.h +++ b/src/stream.h @@ -17,26 +17,14 @@ #ifndef WABT_STREAM_H_ #define WABT_STREAM_H_ -#include <stdio.h> +#include <cassert> +#include <memory> #include "common.h" #include "writer.h" namespace wabt { -struct Stream { - Writer* writer; - size_t offset; - Result result; - /* if non-null, log all writes to this stream */ - struct Stream* log_stream; -}; - -struct FileStream { - Stream base; - FileWriter writer; -}; - /* whether to display the ASCII characters in the debug output for * write_memory */ enum class PrintChars { @@ -44,55 +32,127 @@ enum class PrintChars { Yes = 1, }; -void init_stream(Stream* stream, Writer* writer, Stream* log_stream); -void init_file_stream_from_existing(FileStream* stream, FILE* file); -Stream* init_stdout_stream(void); -Stream* init_stderr_stream(void); +class Stream { + public: + Stream(Writer* writer, Stream* log_stream = nullptr); + + size_t offset() { return offset_; } + Result result() { return result_; } + + void set_log_stream(Stream* stream) { + assert(stream); + log_stream_ = stream; + } -/* helper functions for writing to a Stream. the |desc| parameter is - * optional, and will be appended to the log stream if |stream.log_stream| is - * non-null. */ -void write_data_at(Stream*, - size_t offset, + Stream& log_stream() { + assert(log_stream_); + return *log_stream_; + } + + bool has_log_stream() const { return log_stream_ != nullptr; } + + void AddOffset(ssize_t delta); + + void WriteData(const void* src, + size_t size, + const char* desc = nullptr, + PrintChars = PrintChars::No); + void MoveData(size_t dst_offset, size_t src_offset, size_t size); + + void WriteDataAt(size_t offset, const void* src, size_t size, - PrintChars print_chars, - const char* desc); -void write_data(Stream*, const void* src, size_t size, const char* desc); -void move_data(Stream*, size_t dst_offset, size_t src_offset, size_t size); - -void WABT_PRINTF_FORMAT(2, 3) writef(Stream*, 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 write_u8(Stream*, uint32_t value, const char* desc); -void write_u32(Stream*, uint32_t value, const char* desc); -void write_u64(Stream*, uint64_t value, const char* desc); - -static WABT_INLINE void write_char(Stream* stream, char c) { - write_u8(stream, c, nullptr); -} - -/* dump memory as text, similar to the xxd format */ -void write_memory_dump(Stream*, - const void* start, + const char* desc = nullptr, + PrintChars = PrintChars::No); + + void WABT_PRINTF_FORMAT(2, 3) Writef(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 WriteU8(uint32_t value, + const char* desc = nullptr, + PrintChars print_chars = PrintChars::No) { + assert(value <= UINT8_MAX); + Write(static_cast<uint8_t>(value), desc, print_chars); + } + void WriteU32(uint32_t value, + const char* desc = nullptr, + PrintChars print_chars = PrintChars::No) { + Write(value, desc, print_chars); + } + void WriteU64(uint64_t value, + const char* desc = nullptr, + PrintChars print_chars = PrintChars::No) { + Write(value, desc, print_chars); + } + void WriteChar(char c, + const char* desc = nullptr, + PrintChars print_chars = PrintChars::No) { + WriteU8(c, desc, print_chars); + } + + // Dump memory as text, similar to the xxd format. + void WriteMemoryDump(const void* start, size_t size, - size_t offset, - PrintChars print_chars, - const char* prefix, - const char* desc); - -static WABT_INLINE void write_output_buffer_memory_dump( - Stream* stream, - struct OutputBuffer* buf) { - write_memory_dump(stream, buf->start, buf->size, 0, PrintChars::No, nullptr, - nullptr); -} - -/* Helper function for writing enums as u8. */ -template <typename T> -void write_u8_enum(Stream* stream, T value, const char* desc) { - write_u8(stream, static_cast<uint32_t>(value), desc); -} + size_t offset = 0, + const char* prefix = nullptr, + const char* desc = nullptr, + PrintChars print_chars = PrintChars::No); + + // Convenience functions for writing enums. + template <typename T> + void WriteU8Enum(T value, + const char* desc = nullptr, + PrintChars print_chars = PrintChars::No) { + WriteU8(static_cast<uint32_t>(value), desc, print_chars); + } + + private: + template <typename T> + void Write(const T& data, const char* desc, PrintChars print_chars) { + WriteData(&data, sizeof(data), desc, print_chars); + } + + Writer* writer_; // Not owned. + size_t offset_; + Result result_; + // Not owned. If non-null, log all writes to this stream. + Stream* log_stream_; +}; + +class MemoryStream : public Stream { + public: + MemoryStream(); + + MemoryWriter& writer() { return writer_; } + + std::unique_ptr<OutputBuffer> ReleaseOutputBuffer() { + return writer_.ReleaseOutputBuffer(); + } + + Result WriteToFile(const char* filename) { + return writer_.output_buffer().WriteToFile(filename); + } + + private: + MemoryWriter writer_; +}; + +class FileStream : public Stream { + public: + explicit FileStream(const char* filename); + explicit FileStream(FILE*); + + FileWriter& writer() { return writer_; } + + static std::unique_ptr<FileStream> CreateStdout(); + static std::unique_ptr<FileStream> CreateStderr(); + + bool is_open() const { return writer_.is_open(); } + + private: + FileWriter writer_; +}; } // namespace wabt diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index 643fc3fa..a90ba77a 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -20,6 +20,7 @@ #include <stdlib.h> #include <algorithm> +#include <memory> #include <vector> #include "binary-reader.h" @@ -47,12 +48,11 @@ static InterpreterThreadOptions s_thread_options = static bool s_trace; static bool s_spec; static bool s_run_all_exports; -static Stream* s_stdout_stream; static BinaryErrorHandler s_error_handler = WABT_BINARY_ERROR_HANDLER_DEFAULT; -static FileWriter s_log_stream_writer; -static Stream s_log_stream; +static std::unique_ptr<FileStream> s_log_stream; +static std::unique_ptr<FileStream> s_stdout_stream; #define NOPE HasArgument::No #define YEP HasArgument::Yes @@ -117,9 +117,8 @@ static void on_option(struct OptionParser* parser, switch (option->id) { case FLAG_VERBOSE: s_verbose++; - init_file_writer_existing(&s_log_stream_writer, stdout); - init_stream(&s_log_stream, &s_log_stream_writer.base, nullptr); - s_read_binary_options.log_stream = &s_log_stream; + s_log_stream = FileStream::CreateStdout(); + s_read_binary_options.log_stream = s_log_stream.get(); break; case FLAG_HELP: @@ -284,7 +283,7 @@ static InterpreterResult run_defined_function(InterpreterThread* thread, uint32_t* call_stack_return_top = thread->call_stack_top; while (iresult == InterpreterResult::Ok) { if (s_trace) - trace_pc(thread, s_stdout_stream); + trace_pc(thread, s_stdout_stream.get()); iresult = run_interpreter(thread, quantum, call_stack_return_top); } if (iresult != InterpreterResult::Returned) @@ -444,7 +443,7 @@ static Result read_module(const char* module_filename, if (WABT_SUCCEEDED(result)) { if (s_verbose) - disassemble_module(env, s_stdout_stream, *out_module); + disassemble_module(env, s_stdout_stream.get(), *out_module); } delete[] data; } @@ -598,12 +597,11 @@ static Result read_and_run_module(const char* module_filename) { print_interpreter_result("error running start function", iresult); } } - destroy_interpreter_environment(&env); return result; } /* An extremely simple JSON parser that only knows how to parse the expected - * format from wast2wabt. */ + * format from wast2wasm. */ struct Context { Context() : last_module(nullptr), @@ -1150,7 +1148,6 @@ static Result on_assert_malformed_command(Context* ctx, } delete[] path; - destroy_interpreter_environment(&env); destroy_custom_error_handler(error_handler); return result; } @@ -1234,7 +1231,6 @@ static Result on_assert_invalid_command(Context* ctx, } delete[] path; - destroy_interpreter_environment(&env); destroy_custom_error_handler(error_handler); return result; } @@ -1615,7 +1611,6 @@ static Result parse_commands(Context* ctx) { } static void destroy_context(Context* ctx) { - destroy_interpreter_environment(&ctx->env); delete[] ctx->json_data; } @@ -1646,7 +1641,7 @@ int main(int argc, char** argv) { init_stdio(); parse_options(argc, argv); - s_stdout_stream = init_stdout_stream(); + s_stdout_stream = FileStream::CreateStdout(); Result result; if (s_spec) { diff --git a/src/tools/wasm-link.cc b/src/tools/wasm-link.cc index 3e61a3a7..7ecfb71d 100644 --- a/src/tools/wasm-link.cc +++ b/src/tools/wasm-link.cc @@ -56,16 +56,13 @@ static bool s_debug; static bool s_relocatable; static const char* s_outfile = "a.wasm"; static std::vector<std::string> s_infiles; -static FileWriter s_log_stream_writer; -static Stream s_log_stream; +static std::unique_ptr<FileStream> s_log_stream; struct Context { WABT_DISALLOW_COPY_AND_ASSIGN(Context); - Context() { - WABT_ZERO_MEMORY(stream); - } + Context() {} - Stream stream; + MemoryStream stream; std::vector<std::unique_ptr<LinkerInputBinary>> inputs; ssize_t current_section_payload_offset = 0; }; @@ -76,8 +73,7 @@ static void on_option(struct OptionParser* parser, switch (option->id) { case FLAG_DEBUG: s_debug = true; - init_file_writer_existing(&s_log_stream_writer, stdout); - init_stream(&s_log_stream, &s_log_stream_writer.base, nullptr); + s_log_stream = FileStream::CreateStdout(); break; case FLAG_OUTPUT: @@ -165,7 +161,7 @@ static uint32_t relocate_func_index(LinkerInputBinary* binary, /* locally declared function call */ offset = binary->function_index_offset; if (s_debug) - writef(&s_log_stream, "func reloc %d + %d\n", function_index, offset); + s_log_stream->Writef("func reloc %d + %d\n", function_index, offset); } else { /* imported function call */ FunctionImport* import = &binary->function_imports[function_index]; @@ -173,15 +169,14 @@ static uint32_t relocate_func_index(LinkerInputBinary* binary, function_index = import->foreign_index; offset = import->foreign_binary->function_index_offset; if (s_debug) - writef(&s_log_stream, - "reloc for disabled import. new index = %d + %d\n", - function_index, offset); + s_log_stream->Writef("reloc for disabled import. new index = %d + %d\n", + function_index, offset); } else { uint32_t new_index = import->relocated_function_index; if (s_debug) - writef(&s_log_stream, - "reloc for active import. old index = %d, new index = %d\n", - function_index, new_index); + s_log_stream->Writef( + "reloc for active import. old index = %d, new index = %d\n", + function_index, new_index); return new_index; } } @@ -236,9 +231,10 @@ static void apply_relocations(Section* section) { if (!section->relocations.size()) return; - if (s_debug) - writef(&s_log_stream, "apply_relocations: %s\n", - get_section_name(section->section_code)); + if (s_debug) { + s_log_stream->Writef("apply_relocations: %s\n", + get_section_name(section->section_code)); + } /* Perform relocations in-place */ for (Reloc& reloc: section->relocations) { @@ -250,36 +246,36 @@ static void write_section_payload(Context* ctx, Section* sec) { assert(ctx->current_section_payload_offset != -1); sec->output_payload_offset = - ctx->stream.offset - ctx->current_section_payload_offset; + ctx->stream.offset() - ctx->current_section_payload_offset; uint8_t* payload = &sec->binary->data[sec->payload_offset]; - write_data(&ctx->stream, payload, sec->payload_size, "section content"); + ctx->stream.WriteData(payload, sec->payload_size, "section content"); } static void write_c_str(Stream* stream, const char* str, const char* desc) { - write_str(stream, str, strlen(str), PrintChars::Yes, desc); + write_str(stream, str, strlen(str), desc, PrintChars::Yes); } static void write_slice(Stream* stream, StringSlice str, const char* desc) { - write_str(stream, str.start, str.length, PrintChars::Yes, desc); + write_str(stream, str.start, str.length, desc, PrintChars::Yes); } static void write_string(Stream* stream, const std::string& str, const char* desc) { - write_str(stream, str.data(), str.length(), PrintChars::Yes, desc); + write_str(stream, str.data(), str.length(), desc, PrintChars::Yes); } -#define WRITE_UNKNOWN_SIZE(STREAM) \ - { \ - uint32_t fixup_offset = (STREAM)->offset; \ - write_fixed_u32_leb128(STREAM, 0, "unknown size"); \ - ctx->current_section_payload_offset = (STREAM)->offset; \ - uint32_t start = (STREAM)->offset; +#define WRITE_UNKNOWN_SIZE(STREAM) \ + { \ + uint32_t fixup_offset = (STREAM)->offset(); \ + write_fixed_u32_leb128(STREAM, 0, "unknown size"); \ + ctx->current_section_payload_offset = (STREAM)->offset(); \ + uint32_t start = (STREAM)->offset(); -#define FIXUP_SIZE(STREAM) \ - write_fixed_u32_leb128_at(STREAM, fixup_offset, (STREAM)->offset - start, \ - "fixup size"); \ +#define FIXUP_SIZE(STREAM) \ + write_fixed_u32_leb128_at(STREAM, fixup_offset, (STREAM)->offset() - start, \ + "fixup size"); \ } static void write_table_section(Context* ctx, @@ -317,7 +313,7 @@ static void write_export_section(Context* ctx) { for (const std::unique_ptr<LinkerInputBinary>& binary : ctx->inputs) { for (const Export& export_ : binary->exports) { write_slice(stream, export_.name, "export name"); - write_u8_enum(stream, export_.kind, "export kind"); + stream->WriteU8Enum(export_.kind, "export kind"); uint32_t index = export_.index; switch (export_.kind) { case ExternalKind::Func: @@ -351,7 +347,7 @@ static void write_elem_section(Context* ctx, write_opcode(&ctx->stream, Opcode::End); write_u32_leb128(stream, total_elem_count, "num elements"); - ctx->current_section_payload_offset = stream->offset; + ctx->current_section_payload_offset = stream->offset(); for (Section* section : sections) { apply_relocations(section); @@ -386,7 +382,7 @@ static void write_function_import(Context* ctx, uint32_t offset) { write_c_str(&ctx->stream, WABT_LINK_MODULE_NAME, "import module name"); write_slice(&ctx->stream, import->name, "import field name"); - write_u8_enum(&ctx->stream, ExternalKind::Func, "import kind"); + ctx->stream.WriteU8Enum(ExternalKind::Func, "import kind"); write_u32_leb128(&ctx->stream, import->sig_index + offset, "import signature index"); } @@ -394,9 +390,9 @@ static void write_function_import(Context* ctx, static void write_global_import(Context* ctx, GlobalImport* import) { write_c_str(&ctx->stream, WABT_LINK_MODULE_NAME, "import module name"); write_slice(&ctx->stream, import->name, "import field name"); - write_u8_enum(&ctx->stream, ExternalKind::Global, "import kind"); + ctx->stream.WriteU8Enum(ExternalKind::Global, "import kind"); write_type(&ctx->stream, import->type); - write_u8(&ctx->stream, import->mutable_, "global mutability"); + ctx->stream.WriteU8(import->mutable_, "global mutability"); } static void write_import_section(Context* ctx) { @@ -468,7 +464,7 @@ static void write_data_segment(Stream* stream, write_u32_leb128(stream, segment.offset + offset, "offset"); write_opcode(stream, Opcode::End); write_u32_leb128(stream, segment.size, "segment size"); - write_data(stream, segment.data, segment.size, "segment data"); + stream->WriteData(segment.data, segment.size, "segment data"); } static void write_data_section(Context* ctx, @@ -508,11 +504,11 @@ static void write_names_section(Context* ctx) { return; Stream* stream = &ctx->stream; - write_u8_enum(stream, BinarySection::Custom, "section code"); + stream->WriteU8Enum(BinarySection::Custom, "section code"); WRITE_UNKNOWN_SIZE(stream); write_c_str(stream, "name", "custom section name"); - write_u8_enum(stream, NameSectionSubsection::Function, "subsection code"); + stream->WriteU8Enum(NameSectionSubsection::Function, "subsection code"); WRITE_UNKNOWN_SIZE(stream); write_u32_leb128(stream, total_count, "element count"); for (const std::unique_ptr<LinkerInputBinary>& binary: ctx->inputs) { @@ -553,7 +549,7 @@ static void write_reloc_section(Context* ctx, WABT_BINARY_SECTION_RELOC, get_section_name(section_code)); Stream* stream = &ctx->stream; - write_u8_enum(stream, BinarySection::Custom, "section code"); + stream->WriteU8Enum(BinarySection::Custom, "section code"); WRITE_UNKNOWN_SIZE(stream); write_c_str(stream, section_name, "reloc section name"); write_u32_leb128_enum(&ctx->stream, section_code, "reloc section"); @@ -604,7 +600,7 @@ static bool write_combined_section(Context* ctx, total_count += sec->count; } - write_u8_enum(&ctx->stream, section_code, "section code"); + ctx->stream.WriteU8Enum(section_code, "section code"); ctx->current_section_payload_offset = -1; switch (section_code) { @@ -637,7 +633,7 @@ static bool write_combined_section(Context* ctx, Stream* stream = &ctx->stream; write_u32_leb128(stream, total_size, "section size"); write_u32_leb128(stream, total_count, "element count"); - ctx->current_section_payload_offset = ctx->stream.offset; + ctx->current_section_payload_offset = ctx->stream.offset(); for (Section* sec: sections) { apply_relocations(sec); write_section_payload(ctx, sec); @@ -777,8 +773,8 @@ static void write_binary(Context* ctx) { } /* Write the final binary */ - write_u32(&ctx->stream, WABT_BINARY_MAGIC, "WABT_BINARY_MAGIC"); - write_u32(&ctx->stream, WABT_BINARY_VERSION, "WABT_BINARY_VERSION"); + ctx->stream.WriteU32(WABT_BINARY_MAGIC, "WABT_BINARY_MAGIC"); + ctx->stream.WriteU32(WABT_BINARY_VERSION, "WABT_BINARY_VERSION"); /* Write known sections first */ for (size_t i = FIRST_KNOWN_SECTION; i < kBinarySectionCount; i++) { @@ -797,47 +793,39 @@ static void dump_reloc_offsets(Context* ctx) { if (s_debug) { for (uint32_t i = 0; i < ctx->inputs.size(); i++) { LinkerInputBinary* binary = ctx->inputs[i].get(); - writef(&s_log_stream, "Relocation info for: %s\n", binary->filename); - writef(&s_log_stream, " - type index offset : %d\n", - binary->type_index_offset); - writef(&s_log_stream, " - mem page offset : %d\n", - binary->memory_page_offset); - writef(&s_log_stream, " - function index offset : %d\n", - binary->function_index_offset); - writef(&s_log_stream, " - global index offset : %d\n", - binary->global_index_offset); - writef(&s_log_stream, " - imported function offset: %d\n", - binary->imported_function_index_offset); - writef(&s_log_stream, " - imported global offset : %d\n", - binary->imported_global_index_offset); + s_log_stream->Writef("Relocation info for: %s\n", binary->filename); + s_log_stream->Writef(" - type index offset : %d\n", + binary->type_index_offset); + s_log_stream->Writef(" - mem page offset : %d\n", + binary->memory_page_offset); + s_log_stream->Writef(" - function index offset : %d\n", + binary->function_index_offset); + s_log_stream->Writef(" - global index offset : %d\n", + binary->global_index_offset); + s_log_stream->Writef(" - imported function offset: %d\n", + binary->imported_function_index_offset); + s_log_stream->Writef(" - imported global offset : %d\n", + binary->imported_global_index_offset); } } } static Result perform_link(Context* ctx) { - MemoryWriter writer; - WABT_ZERO_MEMORY(writer); - if (WABT_FAILED(init_mem_writer(&writer))) - WABT_FATAL("unable to open memory writer for writing\n"); - - Stream* log_stream = nullptr; - if (s_debug) - log_stream = &s_log_stream; - - if (s_debug) - writef(&s_log_stream, "writing file: %s\n", s_outfile); + if (s_debug) { + ctx->stream.set_log_stream(s_log_stream.get()); + s_log_stream->Writef("writing file: %s\n", s_outfile); + } calculate_reloc_offsets(ctx); resolve_symbols(ctx); calculate_reloc_offsets(ctx); dump_reloc_offsets(ctx); - init_stream(&ctx->stream, &writer.base, log_stream); write_binary(ctx); - if (WABT_FAILED(write_output_buffer_to_file(&writer.buf, s_outfile))) + if (WABT_FAILED(ctx->stream.WriteToFile(s_outfile))) { WABT_FATAL("error writing linked output to file\n"); + } - close_mem_writer(&writer); return Result::Ok; } @@ -852,7 +840,7 @@ int main(int argc, char** argv) { for (size_t i = 0; i < s_infiles.size(); i++) { const std::string& input_filename = s_infiles[i]; if (s_debug) - writef(&s_log_stream, "reading file: %s\n", input_filename.c_str()); + s_log_stream->Writef("reading file: %s\n", input_filename.c_str()); char* data; size_t size; result = read_file(input_filename.c_str(), &data, &size); @@ -863,7 +851,7 @@ int main(int argc, char** argv) { context.inputs.emplace_back(b); LinkOptions options = { NULL }; if (s_debug) - options.log_stream = &s_log_stream; + options.log_stream = s_log_stream.get(); result = read_binary_linker(b, &options); if (WABT_FAILED(result)) WABT_FATAL("error parsing file: %s\n", input_filename.c_str()); diff --git a/src/tools/wasm2wast.cc b/src/tools/wasm2wast.cc index d885f740..e826c3b8 100644 --- a/src/tools/wasm2wast.cc +++ b/src/tools/wasm2wast.cc @@ -38,11 +38,8 @@ static const char* s_infile; static const char* s_outfile; static ReadBinaryOptions s_read_binary_options = {nullptr, true}; static bool s_generate_names; - static BinaryErrorHandler s_error_handler = WABT_BINARY_ERROR_HANDLER_DEFAULT; - -static FileWriter s_log_stream_writer; -static Stream s_log_stream; +static std::unique_ptr<FileStream> s_log_stream; #define NOPE HasArgument::No #define YEP HasArgument::Yes @@ -86,9 +83,8 @@ static void on_option(struct OptionParser* parser, switch (option->id) { case FLAG_VERBOSE: s_verbose++; - init_file_writer_existing(&s_log_stream_writer, stdout); - init_stream(&s_log_stream, &s_log_stream_writer.base, nullptr); - s_read_binary_options.log_stream = &s_log_stream; + s_log_stream = FileStream::CreateStdout(); + s_read_binary_options.log_stream = s_log_stream.get(); break; case FLAG_HELP: @@ -160,17 +156,9 @@ int main(int argc, char** argv) { } if (WABT_SUCCEEDED(result)) { - FileWriter file_writer; - if (s_outfile) { - result = init_file_writer(&file_writer, s_outfile); - } else { - init_file_writer_existing(&file_writer, stdout); - } - - if (WABT_SUCCEEDED(result)) { - result = write_ast(&file_writer.base, &module); - close_file_writer(&file_writer); - } + FileWriter writer(s_outfile ? FileWriter(s_outfile) + : FileWriter(stdout)); + result = write_ast(&writer, &module); } } delete[] data; diff --git a/src/tools/wasmdump.cc b/src/tools/wasmdump.cc index 25d227fb..8ed207ce 100644 --- a/src/tools/wasmdump.cc +++ b/src/tools/wasmdump.cc @@ -67,8 +67,8 @@ static Option s_options[] = { WABT_STATIC_ASSERT(NUM_FLAGS == WABT_ARRAY_SIZE(s_options)); static ObjdumpOptions s_objdump_options; -static FileWriter s_log_stream_writer; -static Stream s_log_stream; + +static std::unique_ptr<FileStream> s_log_stream; static void on_argument(struct OptionParser* parser, const char* argument) { s_objdump_options.infile = argument; @@ -88,9 +88,8 @@ static void on_option(struct OptionParser* parser, case FLAG_DEBUG: s_objdump_options.debug = true; - init_file_writer_existing(&s_log_stream_writer, stdout); - init_stream(&s_log_stream, &s_log_stream_writer.base, nullptr); - s_objdump_options.log_stream = &s_log_stream; + s_log_stream = FileStream::CreateStdout(); + s_objdump_options.log_stream = s_log_stream.get(); break; case FLAG_DISASSEMBLE: diff --git a/src/tools/wasmopcodecnt.cc b/src/tools/wasmopcodecnt.cc index 89009aca..332bb442 100644 --- a/src/tools/wasmopcodecnt.cc +++ b/src/tools/wasmopcodecnt.cc @@ -43,8 +43,7 @@ static const char* s_separator = ": "; static ReadBinaryOptions s_read_binary_options = WABT_READ_BINARY_OPTIONS_DEFAULT; -static FileWriter s_log_stream_writer; -static Stream s_log_stream; +static std::unique_ptr<FileStream> s_log_stream; #define NOPE HasArgument::No #define YEP HasArgument::Yes @@ -85,9 +84,8 @@ static void on_option(struct OptionParser* parser, switch (option->id) { case FLAG_VERBOSE: s_verbose++; - init_file_writer_existing(&s_log_stream_writer, stdout); - init_stream(&s_log_stream, &s_log_stream_writer.base, nullptr); - s_read_binary_options.log_stream = &s_log_stream; + s_log_stream = FileStream::CreateStdout(); + s_read_binary_options.log_stream = s_log_stream.get(); break; case FLAG_HELP: diff --git a/src/tools/wast-desugar.cc b/src/tools/wast-desugar.cc index 74fbf0b2..51e12cb1 100644 --- a/src/tools/wast-desugar.cc +++ b/src/tools/wast-desugar.cc @@ -149,17 +149,8 @@ int main(int argc, char** argv) { result = apply_names(module); if (WABT_SUCCEEDED(result)) { - FileWriter file_writer; - if (s_outfile) { - result = init_file_writer(&file_writer, s_outfile); - } else { - init_file_writer_existing(&file_writer, stdout); - } - - if (WABT_SUCCEEDED(result)) { - result = write_ast(&file_writer.base, module); - close_file_writer(&file_writer); - } + FileWriter writer(s_outfile ? FileWriter(s_outfile) : FileWriter(stdout)); + result = write_ast(&writer, module); } } diff --git a/src/tools/wast2wasm.cc b/src/tools/wast2wasm.cc index 26248c6e..a9f0e9dc 100644 --- a/src/tools/wast2wasm.cc +++ b/src/tools/wast2wasm.cc @@ -50,7 +50,7 @@ static bool s_validate = true; static SourceErrorHandler s_error_handler = WABT_SOURCE_ERROR_HANDLER_DEFAULT; -static FileStream s_log_stream; +static std::unique_ptr<FileStream> s_log_stream; #define NOPE HasArgument::No #define YEP HasArgument::Yes @@ -114,7 +114,8 @@ static void on_option(struct OptionParser* parser, switch (option->id) { case FLAG_VERBOSE: s_verbose++; - s_write_binary_options.log_stream = &s_log_stream.base; + s_log_stream = FileStream::CreateStdout(); + s_write_binary_options.log_stream = s_log_stream.get(); break; case FLAG_HELP: @@ -179,22 +180,23 @@ static void parse_options(int argc, char** argv) { } static void write_buffer_to_file(const char* filename, - OutputBuffer* buffer) { + const OutputBuffer& buffer) { if (s_dump_module) { if (s_verbose) - writef(&s_log_stream.base, ";; dump\n"); - write_output_buffer_memory_dump(&s_log_stream.base, buffer); + s_log_stream->Writef(";; dump\n"); + if (!buffer.data.empty()) { + s_log_stream->WriteMemoryDump(buffer.data.data(), buffer.data.size()); + } } if (filename) { - write_output_buffer_to_file(buffer, filename); + buffer.WriteToFile(filename); } } int main(int argc, char** argv) { init_stdio(); - init_file_stream_from_existing(&s_log_stream, stdout); parse_options(argc, argv); AstLexer* lexer = new_ast_file_lexer(s_infile); @@ -219,21 +221,16 @@ int main(int argc, char** argv) { &s_write_binary_spec_options); } else { MemoryWriter writer; - WABT_ZERO_MEMORY(writer); - if (WABT_FAILED(init_mem_writer(&writer))) - WABT_FATAL("unable to open memory writer for writing\n"); - Module* module = get_first_module(script); if (module) { - result = write_binary_module(&writer.base, module, - &s_write_binary_options); + result = + write_binary_module(&writer, module, &s_write_binary_options); } else { WABT_FATAL("no module found\n"); } if (WABT_SUCCEEDED(result)) - write_buffer_to_file(s_outfile, &writer.buf); - close_mem_writer(&writer); + write_buffer_to_file(s_outfile, writer.output_buffer()); } } } diff --git a/src/writer.cc b/src/writer.cc index 8e24abc0..a408ff32 100644 --- a/src/writer.cc +++ b/src/writer.cc @@ -22,177 +22,136 @@ #include <stdio.h> #include <stdlib.h> +#include <utility> + #define ERROR0(msg) fprintf(stderr, "%s:%d: " msg, __FILE__, __LINE__) #define ERROR(fmt, ...) \ fprintf(stderr, "%s:%d: " fmt, __FILE__, __LINE__, __VA_ARGS__) -#define INITIAL_OUTPUT_BUFFER_CAPACITY (64 * 1024) - namespace wabt { -static Result write_data_to_file(size_t offset, - const void* data, - size_t size, - void* user_data) { - if (size == 0) - return Result::Ok; - FileWriter* writer = static_cast<FileWriter*>(user_data); - if (offset != writer->offset) { - if (fseek(writer->file, offset, SEEK_SET) != 0) { - ERROR("fseek offset=%" PRIzd " failed, errno=%d\n", size, errno); - return Result::Error; - } - writer->offset = offset; - } - if (fwrite(data, size, 1, writer->file) != 1) { - ERROR("fwrite size=%" PRIzd " failed, errno=%d\n", size, errno); +Result OutputBuffer::WriteToFile(const char* filename) const { + FILE* file = fopen(filename, "wb"); + if (!file) { + ERROR("unable to open %s for writing\n", filename); return Result::Error; } - writer->offset += size; - return Result::Ok; -} -static Result move_data_in_file(size_t dst_offset, - size_t src_offset, - size_t size, - void* user_data) { - if (size == 0) + if (data.empty()) { return Result::Ok; - /* TODO(binji): implement if needed. */ - ERROR0("move_data_in_file not implemented!\n"); - return Result::Error; -} - -void init_file_writer_existing(FileWriter* writer, FILE* file) { - WABT_ZERO_MEMORY(*writer); - writer->file = file; - writer->offset = 0; - writer->base.user_data = writer; - writer->base.write_data = write_data_to_file; - writer->base.move_data = move_data_in_file; -} + } -Result init_file_writer(FileWriter* writer, const char* filename) { - FILE* file = fopen(filename, "wb"); - if (!file) { - ERROR("fopen name=\"%s\" failed, errno=%d\n", filename, errno); + ssize_t bytes = fwrite(data.data(), 1, data.size(), file); + if (bytes < 0 || static_cast<size_t>(bytes) != data.size()) { + ERROR("failed to write %" PRIzd " bytes to %s\n", data.size(), filename); return Result::Error; } - init_file_writer_existing(writer, file); + fclose(file); return Result::Ok; } -void close_file_writer(FileWriter* writer) { - fclose(writer->file); -} +MemoryWriter::MemoryWriter() : buf_(new OutputBuffer()) {} -void init_output_buffer(OutputBuffer* buf, size_t initial_capacity) { - assert(initial_capacity != 0); - buf->start = new char[initial_capacity](); - buf->size = 0; - buf->capacity = initial_capacity; -} +MemoryWriter::MemoryWriter(std::unique_ptr<OutputBuffer> buf) + : buf_(std::move(buf)) {} -static void ensure_output_buffer_capacity(OutputBuffer* buf, - size_t ensure_capacity) { - if (ensure_capacity > buf->capacity) { - assert(buf->capacity != 0); - size_t new_capacity = buf->capacity * 2; - while (new_capacity < ensure_capacity) - new_capacity *= 2; - char* new_data = new char [new_capacity]; - memcpy(new_data, buf->start, buf->capacity); - memset(new_data + buf->capacity, 0, new_capacity - buf->capacity); - delete [] buf->start; - buf->start = new_data; - buf->capacity = new_capacity; - } +std::unique_ptr<OutputBuffer> MemoryWriter::ReleaseOutputBuffer() { + return std::move(buf_); } -static Result write_data_to_output_buffer(size_t offset, - const void* data, - size_t size, - void* user_data) { - MemoryWriter* writer = static_cast<MemoryWriter*>(user_data); - size_t end = offset + size; - ensure_output_buffer_capacity(&writer->buf, end); - memcpy(writer->buf.start + offset, data, size); - if (end > writer->buf.size) - writer->buf.size = end; +Result MemoryWriter::WriteData(size_t dst_offset, + const void* src, + size_t size) { + size_t end = dst_offset + size; + if (end > buf_->data.size()) { + buf_->data.resize(end); + } + uint8_t* dst = &buf_->data[dst_offset]; + memcpy(dst, src, size); return Result::Ok; } -static Result move_data_in_output_buffer(size_t dst_offset, - size_t src_offset, - size_t size, - void* user_data) { - MemoryWriter* writer = static_cast<MemoryWriter*>(user_data); +Result MemoryWriter::MoveData(size_t dst_offset, + size_t src_offset, + size_t size) { size_t src_end = src_offset + size; size_t dst_end = dst_offset + size; size_t end = src_end > dst_end ? src_end : dst_end; - ensure_output_buffer_capacity(&writer->buf, end); - void* dst = reinterpret_cast<void*>( - reinterpret_cast<size_t>(writer->buf.start) + dst_offset); - void* src = reinterpret_cast<void*>( - reinterpret_cast<size_t>(writer->buf.start) + src_offset); + if (end > buf_->data.size()) { + buf_->data.resize(end); + } + + uint8_t* dst = &buf_->data[dst_offset]; + uint8_t* src = &buf_->data[src_offset]; memmove(dst, src, size); - if (end > writer->buf.size) - writer->buf.size = end; return Result::Ok; } -Result init_mem_writer(MemoryWriter* writer) { - WABT_ZERO_MEMORY(*writer); - writer->base.user_data = writer; - writer->base.write_data = write_data_to_output_buffer; - writer->base.move_data = move_data_in_output_buffer; - init_output_buffer(&writer->buf, INITIAL_OUTPUT_BUFFER_CAPACITY); - return Result::Ok; +FileWriter::FileWriter(FILE* file) + : file_(file), offset_(0), should_close_(false) {} + +FileWriter::FileWriter(const char* filename) + : file_(nullptr), offset_(0), should_close_(false) { + file_ = fopen(filename, "wb"); + + // TODO(binji): this is pretty cheesy, should come up with a better API. + if (file_) { + should_close_ = true; + } else { + ERROR("fopen name=\"%s\" failed, errno=%d\n", filename, errno); + } } -Result init_mem_writer_existing(MemoryWriter* writer, OutputBuffer* buf) { - WABT_ZERO_MEMORY(*writer); - writer->base.user_data = writer; - writer->base.write_data = write_data_to_output_buffer; - writer->base.move_data = move_data_in_output_buffer; - writer->buf = *buf; - /* Clear buffer, since ownership has passed to the writer. */ - WABT_ZERO_MEMORY(*buf); - return Result::Ok; +FileWriter::FileWriter(FileWriter&& other) { + *this = std::move(other); } -void steal_mem_writer_output_buffer(MemoryWriter* writer, - OutputBuffer* out_buf) { - *out_buf = writer->buf; - writer->buf.start = nullptr; - writer->buf.size = 0; - writer->buf.capacity = 0; +FileWriter& FileWriter::operator=(FileWriter&& other) { + file_ = other.file_; + offset_ = other.offset_; + should_close_ = other.should_close_; + other.file_ = nullptr; + other.offset_ = 0; + other.should_close_ = false; + return *this; } -void close_mem_writer(MemoryWriter* writer) { - destroy_output_buffer(&writer->buf); +FileWriter::~FileWriter() { + // We don't want to close existing files (stdout/sterr, for example). + if (should_close_) { + fclose(file_); + } } -Result write_output_buffer_to_file(OutputBuffer* buf, const char* filename) { - FILE* file = fopen(filename, "wb"); - if (!file) { - ERROR("unable to open %s for writing\n", filename); +Result FileWriter::WriteData(size_t at, const void* data, size_t size) { + if (!file_) return Result::Error; + if (size == 0) + return Result::Ok; + if (at != offset_) { + if (fseek(file_, at, SEEK_SET) != 0) { + ERROR("fseek offset=%" PRIzd " failed, errno=%d\n", size, errno); + return Result::Error; + } + offset_ = at; } - - ssize_t bytes = fwrite(buf->start, 1, buf->size, file); - if (bytes < 0 || static_cast<size_t>(bytes) != buf->size) { - ERROR("failed to write %" PRIzd " bytes to %s\n", buf->size, filename); + if (fwrite(data, size, 1, file_) != 1) { + ERROR("fwrite size=%" PRIzd " failed, errno=%d\n", size, errno); return Result::Error; } - - fclose(file); + offset_ += size; return Result::Ok; } -void destroy_output_buffer(OutputBuffer* buf) { - delete[] buf->start; +Result FileWriter::MoveData(size_t dst_offset, size_t src_offset, size_t size) { + if (!file_) + return Result::Error; + if (size == 0) + return Result::Ok; + // TODO(binji): implement if needed. + ERROR0("FileWriter::MoveData not implemented!\n"); + return Result::Error; } } // namespace wabt diff --git a/src/writer.h b/src/writer.h index 19d70948..ecb4aeb7 100644 --- a/src/writer.h +++ b/src/writer.h @@ -21,54 +21,61 @@ #include "common.h" -namespace wabt { +#include <memory> +#include <vector> -struct Writer { - void* user_data; - Result (*write_data)(size_t offset, - const void* data, - size_t size, - void* user_data); - Result (*move_data)(size_t dst_offset, - size_t src_offset, - size_t size, - void* user_data); -}; +namespace wabt { struct OutputBuffer { - char* start; - size_t size; - size_t capacity; + Result WriteToFile(const char* filename) const; + + std::vector<uint8_t> data; }; -struct MemoryWriter { - Writer base; - OutputBuffer buf; +class Writer { + public: + virtual ~Writer() {} + virtual Result WriteData(size_t offset, const void* data, size_t size) = 0; + virtual Result MoveData(size_t dst_offset, + size_t src_offset, + size_t size) = 0; }; -struct FileWriter { - Writer base; - FILE* file; - size_t offset; +class MemoryWriter : public Writer { + public: + MemoryWriter(); + explicit MemoryWriter(std::unique_ptr<OutputBuffer>); + + OutputBuffer& output_buffer() { return *buf_; } + std::unique_ptr<OutputBuffer> ReleaseOutputBuffer(); + + virtual Result WriteData(size_t offset, const void* data, size_t size); + virtual Result MoveData(size_t dst_offset, size_t src_offset, size_t size); + + private: + std::unique_ptr<OutputBuffer> buf_; }; -/* FileWriter */ -Result init_file_writer(FileWriter* writer, const char* filename); -void init_file_writer_existing(FileWriter* writer, FILE* file); -void close_file_writer(FileWriter* writer); - -/* MemoryWriter */ -Result init_mem_writer(MemoryWriter* writer); -/* Passes ownership of the buffer to writer */ -Result init_mem_writer_existing(MemoryWriter* writer, OutputBuffer* buf); -void steal_mem_writer_output_buffer(MemoryWriter* writer, - OutputBuffer* out_buf); -void close_mem_writer(MemoryWriter* writer); - -/* OutputBuffer */ -void init_output_buffer(OutputBuffer* buf, size_t initial_capacity); -Result write_output_buffer_to_file(OutputBuffer* buf, const char* filename); -void destroy_output_buffer(OutputBuffer* buf); +class FileWriter : public Writer { + WABT_DISALLOW_COPY_AND_ASSIGN(FileWriter); + + public: + explicit FileWriter(const char* filename); + explicit FileWriter(FILE* file); + FileWriter(FileWriter&&); + FileWriter& operator=(FileWriter&&); + ~FileWriter(); + + bool is_open() const { return file_ != nullptr; } + + virtual Result WriteData(size_t offset, const void* data, size_t size); + virtual Result MoveData(size_t dst_offset, size_t src_offset, size_t size); + + private: + FILE* file_; + size_t offset_; + bool should_close_; +}; } // namespace wabt |