diff options
-rw-r--r-- | src/ast-writer.cc | 706 | ||||
-rw-r--r-- | src/binary-writer-spec.cc | 456 | ||||
-rw-r--r-- | src/binary-writer.cc | 901 |
3 files changed, 1058 insertions, 1005 deletions
diff --git a/src/ast-writer.cc b/src/ast-writer.cc index d7ec12e4..306da811 100644 --- a/src/ast-writer.cc +++ b/src/ast-writer.cc @@ -58,302 +58,339 @@ enum class NextChar { ForceNewline, }; -struct Context { - explicit Context(Writer* writer) : stream(writer) {} - - Stream stream; - Result result = Result::Ok; - int indent = 0; - NextChar next_char = NextChar::None; - int depth = 0; - std::vector<std::string> index_to_name; - - int func_index = 0; - int global_index = 0; - int export_index = 0; - int table_index = 0; - int memory_index = 0; - int func_type_index = 0; +class ASTWriter { + public: + ASTWriter(Writer* writer) : stream_(writer) {} + + Result WriteModule(const Module* module); + + private: + void Indent(); + void Dedent(); + void WriteIndent(); + void WriteNextChar(); + void WriteDataWithNextChar(const void* src, size_t size); + void Writef(const char* format, ...); + void WritePutc(char c); + void WritePuts(const char* s, NextChar next_char); + void WritePutsSpace(const char* s); + void WritePutsNewline(const char* s); + void WriteNewline(bool force); + void WriteOpen(const char* name, NextChar next_char); + void WriteOpenNewline(const char* name); + void WriteOpenSpace(const char* name); + void WriteClose(NextChar next_char); + void WriteCloseNewline(); + void WriteCloseSpace(); + void WriteString(const std::string& str, NextChar next_char); + void WriteStringSlice(const StringSlice* str, NextChar next_char); + bool WriteStringSliceOpt(const StringSlice* str, NextChar next_char); + void WriteStringSliceOrIndex(const StringSlice* str, + uint32_t index, + NextChar next_char); + void WriteQuotedData(const void* data, size_t length); + void WriteQuotedStringSlice(const StringSlice* str, NextChar next_char); + void WriteVar(const Var* var, NextChar next_char); + void WriteBrVar(const Var* var, NextChar next_char); + void WriteType(Type type, NextChar next_char); + void WriteTypes(const TypeVector& types, const char* name); + void WriteFuncSigSpace(const FuncSignature* func_sig); + void WriteBeginBlock(const Block* block, const char* text); + void WriteEndBlock(); + void WriteBlock(const Block* block, const char* start_text); + void WriteConst(const Const* const_); + void WriteExpr(const Expr* expr); + void WriteExprList(const Expr* first); + void WriteInitExpr(const Expr* expr); + void WriteTypeBindings(const char* prefix, + const Func* func, + const TypeVector& types, + const BindingHash& bindings); + void WriteFunc(const Module* module, const Func* func); + void WriteBeginGlobal(const Global* global); + void WriteGlobal(const Global* global); + void WriteLimits(const Limits* limits); + void WriteTable(const Table* table); + void WriteElemSegment(const ElemSegment* segment); + void WriteMemory(const Memory* memory); + void WriteDataSegment(const DataSegment* segment); + void WriteImport(const Import* import); + void WriteExport(const Export* export_); + void WriteFuncType(const FuncType* func_type); + void WriteStartFunction(const Var* start); + + Stream stream_; + Result result_ = Result::Ok; + int indent_ = 0; + NextChar next_char_ = NextChar::None; + int depth_ = 0; + std::vector<std::string> index_to_name_; + + int func_index_ = 0; + int global_index_ = 0; + int table_index_ = 0; + int memory_index_ = 0; + int func_type_index_ = 0; }; } // namespace -static void indent(Context* ctx) { - ctx->indent += INDENT_SIZE; +void ASTWriter::Indent() { + indent_ += INDENT_SIZE; } -static void dedent(Context* ctx) { - ctx->indent -= INDENT_SIZE; - assert(ctx->indent >= 0); +void ASTWriter::Dedent() { + indent_ -= INDENT_SIZE; + assert(indent_ >= 0); } -static void write_indent(Context* ctx) { +void ASTWriter::WriteIndent() { static char s_indent[] = " " " "; static size_t s_indent_len = sizeof(s_indent) - 1; - size_t indent = ctx->indent; - while (indent > s_indent_len) { - ctx->stream.WriteData(s_indent, s_indent_len); + size_t indent = indent_; + while (static_cast<size_t>(indent_) > s_indent_len) { + stream_.WriteData(s_indent, s_indent_len); indent -= s_indent_len; } if (indent > 0) { - ctx->stream.WriteData(s_indent, indent); + stream_.WriteData(s_indent, indent); } } -static void write_next_char(Context* ctx) { - switch (ctx->next_char) { +void ASTWriter::WriteNextChar() { + switch (next_char_) { case NextChar::Space: - ctx->stream.WriteChar(' '); + stream_.WriteChar(' '); break; case NextChar::Newline: case NextChar::ForceNewline: - ctx->stream.WriteChar('\n'); - write_indent(ctx); + stream_.WriteChar('\n'); + WriteIndent(); break; default: case NextChar::None: break; } - ctx->next_char = NextChar::None; + next_char_ = NextChar::None; } -static void write_data_with_next_char(Context* ctx, - const void* src, - size_t size) { - write_next_char(ctx); - ctx->stream.WriteData(src, size); +void ASTWriter::WriteDataWithNextChar(const void* src, size_t size) { + WriteNextChar(); + stream_.WriteData(src, size); } -static void WABT_PRINTF_FORMAT(2, 3) - writef(Context* ctx, const char* format, ...) { +void WABT_PRINTF_FORMAT(2, 3) ASTWriter::Writef(const char* format, ...) { WABT_SNPRINTF_ALLOCA(buffer, length, format); /* default to following space */ - write_data_with_next_char(ctx, buffer, length); - ctx->next_char = NextChar::Space; + WriteDataWithNextChar(buffer, length); + next_char_ = NextChar::Space; } -static void write_putc(Context* ctx, char c) { - ctx->stream.WriteChar(c); +void ASTWriter::WritePutc(char c) { + stream_.WriteChar(c); } -static void write_puts(Context* ctx, const char* s, NextChar next_char) { +void ASTWriter::WritePuts(const char* s, NextChar next_char) { size_t len = strlen(s); - write_data_with_next_char(ctx, s, len); - ctx->next_char = next_char; + WriteDataWithNextChar(s, len); + next_char_ = next_char; } -static void write_puts_space(Context* ctx, const char* s) { - write_puts(ctx, s, NextChar::Space); +void ASTWriter::WritePutsSpace(const char* s) { + WritePuts(s, NextChar::Space); } -static void write_puts_newline(Context* ctx, const char* s) { - write_puts(ctx, s, NextChar::Newline); +void ASTWriter::WritePutsNewline(const char* s) { + WritePuts(s, NextChar::Newline); } -static void write_newline(Context* ctx, bool force) { - if (ctx->next_char == NextChar::ForceNewline) - write_next_char(ctx); - ctx->next_char = force ? NextChar::ForceNewline : NextChar::Newline; +void ASTWriter::WriteNewline(bool force) { + if (next_char_ == NextChar::ForceNewline) + WriteNextChar(); + next_char_ = force ? NextChar::ForceNewline : NextChar::Newline; } -static void write_open(Context* ctx, const char* name, NextChar next_char) { - write_puts(ctx, "(", NextChar::None); - write_puts(ctx, name, next_char); - indent(ctx); +void ASTWriter::WriteOpen(const char* name, NextChar next_char) { + WritePuts("(", NextChar::None); + WritePuts(name, next_char); + Indent(); } -static void write_open_newline(Context* ctx, const char* name) { - write_open(ctx, name, NextChar::Newline); +void ASTWriter::WriteOpenNewline(const char* name) { + WriteOpen(name, NextChar::Newline); } -static void write_open_space(Context* ctx, const char* name) { - write_open(ctx, name, NextChar::Space); +void ASTWriter::WriteOpenSpace(const char* name) { + WriteOpen(name, NextChar::Space); } -static void write_close(Context* ctx, NextChar next_char) { - if (ctx->next_char != NextChar::ForceNewline) - ctx->next_char = NextChar::None; - dedent(ctx); - write_puts(ctx, ")", next_char); +void ASTWriter::WriteClose(NextChar next_char) { + if (next_char_ != NextChar::ForceNewline) + next_char_ = NextChar::None; + Dedent(); + WritePuts(")", next_char); } -static void write_close_newline(Context* ctx) { - write_close(ctx, NextChar::Newline); +void ASTWriter::WriteCloseNewline() { + WriteClose(NextChar::Newline); } -static void write_close_space(Context* ctx) { - write_close(ctx, NextChar::Space); +void ASTWriter::WriteCloseSpace() { + WriteClose(NextChar::Space); } -static void write_string(Context* ctx, - const std::string& str, - NextChar next_char) { - write_puts(ctx, str.c_str(), next_char); +void ASTWriter::WriteString(const std::string& str, NextChar next_char) { + WritePuts(str.c_str(), next_char); } -static void write_string_slice(Context* ctx, - const StringSlice* str, - NextChar next_char) { - writef(ctx, PRIstringslice, WABT_PRINTF_STRING_SLICE_ARG(*str)); - ctx->next_char = next_char; +void ASTWriter::WriteStringSlice(const StringSlice* str, NextChar next_char) { + Writef(PRIstringslice, WABT_PRINTF_STRING_SLICE_ARG(*str)); + next_char_ = next_char; } -static bool write_string_slice_opt(Context* ctx, - const StringSlice* str, - NextChar next_char) { +bool ASTWriter::WriteStringSliceOpt(const StringSlice* str, + NextChar next_char) { if (str->start) - write_string_slice(ctx, str, next_char); + WriteStringSlice(str, next_char); return !!str->start; } -static void write_string_slice_or_index(Context* ctx, - const StringSlice* str, +void ASTWriter::WriteStringSliceOrIndex(const StringSlice* str, uint32_t index, NextChar next_char) { if (str->start) - write_string_slice(ctx, str, next_char); + WriteStringSlice(str, next_char); else - writef(ctx, "(;%u;)", index); + Writef("(;%u;)", index); } -static void write_quoted_data(Context* ctx, const void* data, size_t length) { +void ASTWriter::WriteQuotedData(const void* data, size_t length) { const uint8_t* u8_data = static_cast<const uint8_t*>(data); static const char s_hexdigits[] = "0123456789abcdef"; - write_next_char(ctx); - write_putc(ctx, '\"'); + WriteNextChar(); + WritePutc('\"'); for (size_t i = 0; i < length; ++i) { uint8_t c = u8_data[i]; if (s_is_char_escaped[c]) { - write_putc(ctx, '\\'); - write_putc(ctx, s_hexdigits[c >> 4]); - write_putc(ctx, s_hexdigits[c & 0xf]); + WritePutc('\\'); + WritePutc(s_hexdigits[c >> 4]); + WritePutc(s_hexdigits[c & 0xf]); } else { - write_putc(ctx, c); + WritePutc(c); } } - write_putc(ctx, '\"'); - ctx->next_char = NextChar::Space; + WritePutc('\"'); + next_char_ = NextChar::Space; } -static void write_quoted_string_slice(Context* ctx, - const StringSlice* str, - NextChar next_char) { - write_quoted_data(ctx, str->start, str->length); - ctx->next_char = next_char; +void ASTWriter::WriteQuotedStringSlice(const StringSlice* str, + NextChar next_char) { + WriteQuotedData(str->start, str->length); + next_char_ = next_char; } -static void write_var(Context* ctx, const Var* var, NextChar next_char) { +void ASTWriter::WriteVar(const Var* var, NextChar next_char) { if (var->type == VarType::Index) { - writef(ctx, "%" PRId64, var->index); - ctx->next_char = next_char; + Writef("%" PRId64, var->index); + next_char_ = next_char; } else { - write_string_slice(ctx, &var->name, next_char); + WriteStringSlice(&var->name, next_char); } } -static void write_br_var(Context* ctx, const Var* var, NextChar next_char) { +void ASTWriter::WriteBrVar(const Var* var, NextChar next_char) { if (var->type == VarType::Index) { - writef(ctx, "%" PRId64 " (;@%" PRId64 ";)", var->index, - ctx->depth - var->index - 1); - ctx->next_char = next_char; + Writef("%" PRId64 " (;@%" PRId64 ";)", var->index, + depth_ - var->index - 1); + next_char_ = next_char; } else { - write_string_slice(ctx, &var->name, next_char); + WriteStringSlice(&var->name, next_char); } } -static void write_type(Context* ctx, Type type, NextChar next_char) { +void ASTWriter::WriteType(Type type, NextChar next_char) { const char* type_name = get_type_name(type); assert(type_name); - write_puts(ctx, type_name, next_char); + WritePuts(type_name, next_char); } -static void write_types(Context* ctx, - const TypeVector& types, - const char* name) { +void ASTWriter::WriteTypes(const TypeVector& types, const char* name) { if (types.size()) { if (name) - write_open_space(ctx, name); + WriteOpenSpace(name); for (Type type: types) - write_type(ctx, type, NextChar::Space); + WriteType(type, NextChar::Space); if (name) - write_close_space(ctx); + WriteCloseSpace(); } } -static void write_func_sig_space(Context* ctx, const FuncSignature* func_sig) { - write_types(ctx, func_sig->param_types, "param"); - write_types(ctx, func_sig->result_types, "result"); +void ASTWriter::WriteFuncSigSpace(const FuncSignature* func_sig) { + WriteTypes(func_sig->param_types, "param"); + WriteTypes(func_sig->result_types, "result"); } -static void write_expr_list(Context* ctx, const Expr* first); - -static void write_expr(Context* ctx, const Expr* expr); - -static void write_begin_block(Context* ctx, - const Block* block, - const char* text) { - write_puts_space(ctx, text); - bool has_label = write_string_slice_opt(ctx, &block->label, NextChar::Space); - write_types(ctx, block->sig, nullptr); +void ASTWriter::WriteBeginBlock(const Block* block, const char* text) { + WritePutsSpace(text); + bool has_label = WriteStringSliceOpt(&block->label, NextChar::Space); + WriteTypes(block->sig, nullptr); if (!has_label) - writef(ctx, " ;; label = @%d", ctx->depth); - write_newline(ctx, FORCE_NEWLINE); - ctx->depth++; - indent(ctx); + Writef(" ;; label = @%d", depth_); + WriteNewline(FORCE_NEWLINE); + depth_++; + Indent(); } -static void write_end_block(Context* ctx) { - dedent(ctx); - ctx->depth--; - write_puts_newline(ctx, get_opcode_name(Opcode::End)); +void ASTWriter::WriteEndBlock() { + Dedent(); + depth_--; + WritePutsNewline(get_opcode_name(Opcode::End)); } -static void write_block(Context* ctx, - const Block* block, - const char* start_text) { - write_begin_block(ctx, block, start_text); - write_expr_list(ctx, block->first); - write_end_block(ctx); +void ASTWriter::WriteBlock(const Block* block, const char* start_text) { + WriteBeginBlock(block, start_text); + WriteExprList(block->first); + WriteEndBlock(); } -static void write_const(Context* ctx, const Const* const_) { +void ASTWriter::WriteConst(const Const* const_) { switch (const_->type) { case Type::I32: - write_puts_space(ctx, get_opcode_name(Opcode::I32Const)); - writef(ctx, "%d", static_cast<int32_t>(const_->u32)); - write_newline(ctx, NO_FORCE_NEWLINE); + WritePutsSpace(get_opcode_name(Opcode::I32Const)); + Writef("%d", static_cast<int32_t>(const_->u32)); + WriteNewline(NO_FORCE_NEWLINE); break; case Type::I64: - write_puts_space(ctx, get_opcode_name(Opcode::I64Const)); - writef(ctx, "%" PRId64, static_cast<int64_t>(const_->u64)); - write_newline(ctx, NO_FORCE_NEWLINE); + WritePutsSpace(get_opcode_name(Opcode::I64Const)); + Writef("%" PRId64, static_cast<int64_t>(const_->u64)); + WriteNewline(NO_FORCE_NEWLINE); break; case Type::F32: { - write_puts_space(ctx, get_opcode_name(Opcode::F32Const)); + WritePutsSpace(get_opcode_name(Opcode::F32Const)); char buffer[128]; write_float_hex(buffer, 128, const_->f32_bits); - write_puts_space(ctx, buffer); + WritePutsSpace(buffer); float f32; memcpy(&f32, &const_->f32_bits, sizeof(f32)); - writef(ctx, "(;=%g;)", f32); - write_newline(ctx, NO_FORCE_NEWLINE); + Writef("(;=%g;)", f32); + WriteNewline(NO_FORCE_NEWLINE); break; } case Type::F64: { - write_puts_space(ctx, get_opcode_name(Opcode::F64Const)); + WritePutsSpace(get_opcode_name(Opcode::F64Const)); char buffer[128]; write_double_hex(buffer, 128, const_->f64_bits); - write_puts_space(ctx, buffer); + WritePutsSpace(buffer); double f64; memcpy(&f64, &const_->f64_bits, sizeof(f64)); - writef(ctx, "(;=%g;)", f64); - write_newline(ctx, NO_FORCE_NEWLINE); + Writef("(;=%g;)", f64); + WriteNewline(NO_FORCE_NEWLINE); break; } @@ -363,146 +400,146 @@ static void write_const(Context* ctx, const Const* const_) { } } -static void write_expr(Context* ctx, const Expr* expr) { +void ASTWriter::WriteExpr(const Expr* expr) { switch (expr->type) { case ExprType::Binary: - write_puts_newline(ctx, get_opcode_name(expr->binary.opcode)); + WritePutsNewline(get_opcode_name(expr->binary.opcode)); break; case ExprType::Block: - write_block(ctx, expr->block, get_opcode_name(Opcode::Block)); + WriteBlock(expr->block, get_opcode_name(Opcode::Block)); break; case ExprType::Br: - write_puts_space(ctx, get_opcode_name(Opcode::Br)); - write_br_var(ctx, &expr->br.var, NextChar::Newline); + WritePutsSpace(get_opcode_name(Opcode::Br)); + WriteBrVar(&expr->br.var, NextChar::Newline); break; case ExprType::BrIf: - write_puts_space(ctx, get_opcode_name(Opcode::BrIf)); - write_br_var(ctx, &expr->br_if.var, NextChar::Newline); + WritePutsSpace(get_opcode_name(Opcode::BrIf)); + WriteBrVar(&expr->br_if.var, NextChar::Newline); break; case ExprType::BrTable: { - write_puts_space(ctx, get_opcode_name(Opcode::BrTable)); + WritePutsSpace(get_opcode_name(Opcode::BrTable)); for (const Var& var : *expr->br_table.targets) - write_br_var(ctx, &var, NextChar::Space); - write_br_var(ctx, &expr->br_table.default_target, NextChar::Newline); + WriteBrVar(&var, NextChar::Space); + WriteBrVar(&expr->br_table.default_target, NextChar::Newline); break; } case ExprType::Call: - write_puts_space(ctx, get_opcode_name(Opcode::Call)); - write_var(ctx, &expr->call.var, NextChar::Newline); + WritePutsSpace(get_opcode_name(Opcode::Call)); + WriteVar(&expr->call.var, NextChar::Newline); break; case ExprType::CallIndirect: - write_puts_space(ctx, get_opcode_name(Opcode::CallIndirect)); - write_var(ctx, &expr->call_indirect.var, NextChar::Newline); + WritePutsSpace(get_opcode_name(Opcode::CallIndirect)); + WriteVar(&expr->call_indirect.var, NextChar::Newline); break; case ExprType::Compare: - write_puts_newline(ctx, get_opcode_name(expr->compare.opcode)); + WritePutsNewline(get_opcode_name(expr->compare.opcode)); break; case ExprType::Const: - write_const(ctx, &expr->const_); + WriteConst(&expr->const_); break; case ExprType::Convert: - write_puts_newline(ctx, get_opcode_name(expr->convert.opcode)); + WritePutsNewline(get_opcode_name(expr->convert.opcode)); break; case ExprType::Drop: - write_puts_newline(ctx, get_opcode_name(Opcode::Drop)); + WritePutsNewline(get_opcode_name(Opcode::Drop)); break; case ExprType::GetGlobal: - write_puts_space(ctx, get_opcode_name(Opcode::GetGlobal)); - write_var(ctx, &expr->get_global.var, NextChar::Newline); + WritePutsSpace(get_opcode_name(Opcode::GetGlobal)); + WriteVar(&expr->get_global.var, NextChar::Newline); break; case ExprType::GetLocal: - write_puts_space(ctx, get_opcode_name(Opcode::GetLocal)); - write_var(ctx, &expr->get_local.var, NextChar::Newline); + WritePutsSpace(get_opcode_name(Opcode::GetLocal)); + WriteVar(&expr->get_local.var, NextChar::Newline); break; case ExprType::GrowMemory: - write_puts_newline(ctx, get_opcode_name(Opcode::GrowMemory)); + WritePutsNewline(get_opcode_name(Opcode::GrowMemory)); break; case ExprType::If: - write_begin_block(ctx, expr->if_.true_, get_opcode_name(Opcode::If)); - write_expr_list(ctx, expr->if_.true_->first); + WriteBeginBlock(expr->if_.true_, get_opcode_name(Opcode::If)); + WriteExprList(expr->if_.true_->first); if (expr->if_.false_) { - dedent(ctx); - write_puts_space(ctx, get_opcode_name(Opcode::Else)); - indent(ctx); - write_newline(ctx, FORCE_NEWLINE); - write_expr_list(ctx, expr->if_.false_); + Dedent(); + WritePutsSpace(get_opcode_name(Opcode::Else)); + Indent(); + WriteNewline(FORCE_NEWLINE); + WriteExprList(expr->if_.false_); } - write_end_block(ctx); + WriteEndBlock(); break; case ExprType::Load: - write_puts_space(ctx, get_opcode_name(expr->load.opcode)); + WritePutsSpace(get_opcode_name(expr->load.opcode)); if (expr->load.offset) - writef(ctx, "offset=%" PRIu64, expr->load.offset); + Writef("offset=%" PRIu64, expr->load.offset); if (!is_naturally_aligned(expr->load.opcode, expr->load.align)) - writef(ctx, "align=%u", expr->load.align); - write_newline(ctx, NO_FORCE_NEWLINE); + Writef("align=%u", expr->load.align); + WriteNewline(NO_FORCE_NEWLINE); break; case ExprType::Loop: - write_block(ctx, expr->loop, get_opcode_name(Opcode::Loop)); + WriteBlock(expr->loop, get_opcode_name(Opcode::Loop)); break; case ExprType::CurrentMemory: - write_puts_newline(ctx, get_opcode_name(Opcode::CurrentMemory)); + WritePutsNewline(get_opcode_name(Opcode::CurrentMemory)); break; case ExprType::Nop: - write_puts_newline(ctx, get_opcode_name(Opcode::Nop)); + WritePutsNewline(get_opcode_name(Opcode::Nop)); break; case ExprType::Return: - write_puts_newline(ctx, get_opcode_name(Opcode::Return)); + WritePutsNewline(get_opcode_name(Opcode::Return)); break; case ExprType::Select: - write_puts_newline(ctx, get_opcode_name(Opcode::Select)); + WritePutsNewline(get_opcode_name(Opcode::Select)); break; case ExprType::SetGlobal: - write_puts_space(ctx, get_opcode_name(Opcode::SetGlobal)); - write_var(ctx, &expr->set_global.var, NextChar::Newline); + WritePutsSpace(get_opcode_name(Opcode::SetGlobal)); + WriteVar(&expr->set_global.var, NextChar::Newline); break; case ExprType::SetLocal: - write_puts_space(ctx, get_opcode_name(Opcode::SetLocal)); - write_var(ctx, &expr->set_local.var, NextChar::Newline); + WritePutsSpace(get_opcode_name(Opcode::SetLocal)); + WriteVar(&expr->set_local.var, NextChar::Newline); break; case ExprType::Store: - write_puts_space(ctx, get_opcode_name(expr->store.opcode)); + WritePutsSpace(get_opcode_name(expr->store.opcode)); if (expr->store.offset) - writef(ctx, "offset=%" PRIu64, expr->store.offset); + Writef("offset=%" PRIu64, expr->store.offset); if (!is_naturally_aligned(expr->store.opcode, expr->store.align)) - writef(ctx, "align=%u", expr->store.align); - write_newline(ctx, NO_FORCE_NEWLINE); + Writef("align=%u", expr->store.align); + WriteNewline(NO_FORCE_NEWLINE); break; case ExprType::TeeLocal: - write_puts_space(ctx, get_opcode_name(Opcode::TeeLocal)); - write_var(ctx, &expr->tee_local.var, NextChar::Newline); + WritePutsSpace(get_opcode_name(Opcode::TeeLocal)); + WriteVar(&expr->tee_local.var, NextChar::Newline); break; case ExprType::Unary: - write_puts_newline(ctx, get_opcode_name(expr->unary.opcode)); + WritePutsNewline(get_opcode_name(expr->unary.opcode)); break; case ExprType::Unreachable: - write_puts_newline(ctx, get_opcode_name(Opcode::Unreachable)); + WritePutsNewline(get_opcode_name(Opcode::Unreachable)); break; default: @@ -512,27 +549,26 @@ static void write_expr(Context* ctx, const Expr* expr) { } } -static void write_expr_list(Context* ctx, const Expr* first) { +void ASTWriter::WriteExprList(const Expr* first) { for (const Expr* expr = first; expr; expr = expr->next) - write_expr(ctx, expr); + WriteExpr(expr); } -static void write_init_expr(Context* ctx, const Expr* expr) { +void ASTWriter::WriteInitExpr(const Expr* expr) { if (expr) { - write_puts(ctx, "(", NextChar::None); - write_expr(ctx, expr); + WritePuts("(", NextChar::None); + WriteExpr(expr); /* clear the next char, so we don't write a newline after the expr */ - ctx->next_char = NextChar::None; - write_puts(ctx, ")", NextChar::Space); + next_char_ = NextChar::None; + WritePuts(")", NextChar::Space); } } -static void write_type_bindings(Context* ctx, - const char* prefix, - const Func* func, - const TypeVector& types, - const BindingHash& bindings) { - make_type_binding_reverse_mapping(types, bindings, &ctx->index_to_name); +void ASTWriter::WriteTypeBindings(const char* prefix, + const Func* func, + const TypeVector& types, + const BindingHash& bindings) { + make_type_binding_reverse_mapping(types, bindings, &index_to_name_); /* named params/locals must be specified by themselves, but nameless * params/locals can be compressed, e.g.: @@ -542,212 +578,210 @@ static void write_type_bindings(Context* ctx, bool is_open = false; for (size_t i = 0; i < types.size(); ++i) { if (!is_open) { - write_open_space(ctx, prefix); + WriteOpenSpace(prefix); is_open = true; } - const std::string& name = ctx->index_to_name[i]; + const std::string& name = index_to_name_[i]; if (!name.empty()) - write_string(ctx, name, NextChar::Space); - write_type(ctx, types[i], NextChar::Space); + WriteString(name, NextChar::Space); + WriteType(types[i], NextChar::Space); if (!name.empty()) { - write_close_space(ctx); + WriteCloseSpace(); is_open = false; } } if (is_open) - write_close_space(ctx); + WriteCloseSpace(); } -static void write_func(Context* ctx, const Module* module, const Func* func) { - write_open_space(ctx, "func"); - write_string_slice_or_index(ctx, &func->name, ctx->func_index++, - NextChar::Space); +void ASTWriter::WriteFunc(const Module* module, const Func* func) { + WriteOpenSpace("func"); + WriteStringSliceOrIndex(&func->name, func_index_++, NextChar::Space); if (decl_has_func_type(&func->decl)) { - write_open_space(ctx, "type"); - write_var(ctx, &func->decl.type_var, NextChar::None); - write_close_space(ctx); + WriteOpenSpace("type"); + WriteVar(&func->decl.type_var, NextChar::None); + WriteCloseSpace(); } - write_type_bindings(ctx, "param", func, func->decl.sig.param_types, - func->param_bindings); - write_types(ctx, func->decl.sig.result_types, "result"); - write_newline(ctx, NO_FORCE_NEWLINE); + WriteTypeBindings("param", func, func->decl.sig.param_types, + func->param_bindings); + WriteTypes(func->decl.sig.result_types, "result"); + WriteNewline(NO_FORCE_NEWLINE); if (func->local_types.size()) { - write_type_bindings(ctx, "local", func, func->local_types, - func->local_bindings); + WriteTypeBindings("local", func, func->local_types, func->local_bindings); } - write_newline(ctx, NO_FORCE_NEWLINE); - ctx->depth = 1; /* for the implicit "return" label */ - write_expr_list(ctx, func->first_expr); - write_close_newline(ctx); + WriteNewline(NO_FORCE_NEWLINE); + depth_ = 1; /* for the implicit "return" label */ + WriteExprList(func->first_expr); + WriteCloseNewline(); } -static void write_begin_global(Context* ctx, const Global* global) { - write_open_space(ctx, "global"); - write_string_slice_or_index(ctx, &global->name, ctx->global_index++, +void ASTWriter::WriteBeginGlobal(const Global* global) { + WriteOpenSpace("global"); + WriteStringSliceOrIndex(&global->name, global_index_++, NextChar::Space); if (global->mutable_) { - write_open_space(ctx, "mut"); - write_type(ctx, global->type, NextChar::Space); - write_close_space(ctx); + WriteOpenSpace("mut"); + WriteType(global->type, NextChar::Space); + WriteCloseSpace(); } else { - write_type(ctx, global->type, NextChar::Space); + WriteType(global->type, NextChar::Space); } } -static void write_global(Context* ctx, const Global* global) { - write_begin_global(ctx, global); - write_init_expr(ctx, global->init_expr); - write_close_newline(ctx); +void ASTWriter::WriteGlobal(const Global* global) { + WriteBeginGlobal(global); + WriteInitExpr(global->init_expr); + WriteCloseNewline(); } -static void write_limits(Context* ctx, const Limits* limits) { - writef(ctx, "%" PRIu64, limits->initial); +void ASTWriter::WriteLimits(const Limits* limits) { + Writef("%" PRIu64, limits->initial); if (limits->has_max) - writef(ctx, "%" PRIu64, limits->max); + Writef("%" PRIu64, limits->max); } -static void write_table(Context* ctx, const Table* table) { - write_open_space(ctx, "table"); - write_string_slice_or_index(ctx, &table->name, ctx->table_index++, +void ASTWriter::WriteTable(const Table* table) { + WriteOpenSpace("table"); + WriteStringSliceOrIndex(&table->name, table_index_++, NextChar::Space); - write_limits(ctx, &table->elem_limits); - write_puts_space(ctx, "anyfunc"); - write_close_newline(ctx); + WriteLimits(&table->elem_limits); + WritePutsSpace("anyfunc"); + WriteCloseNewline(); } -static void write_elem_segment(Context* ctx, const ElemSegment* segment) { - write_open_space(ctx, "elem"); - write_init_expr(ctx, segment->offset); +void ASTWriter::WriteElemSegment(const ElemSegment* segment) { + WriteOpenSpace("elem"); + WriteInitExpr(segment->offset); for (const Var& var : segment->vars) - write_var(ctx, &var, NextChar::Space); - write_close_newline(ctx); + WriteVar(&var, NextChar::Space); + WriteCloseNewline(); } -static void write_memory(Context* ctx, const Memory* memory) { - write_open_space(ctx, "memory"); - write_string_slice_or_index(ctx, &memory->name, ctx->memory_index++, +void ASTWriter::WriteMemory(const Memory* memory) { + WriteOpenSpace("memory"); + WriteStringSliceOrIndex(&memory->name, memory_index_++, NextChar::Space); - write_limits(ctx, &memory->page_limits); - write_close_newline(ctx); + WriteLimits(&memory->page_limits); + WriteCloseNewline(); } -static void write_data_segment(Context* ctx, const DataSegment* segment) { - write_open_space(ctx, "data"); - write_init_expr(ctx, segment->offset); - write_quoted_data(ctx, segment->data, segment->size); - write_close_newline(ctx); +void ASTWriter::WriteDataSegment(const DataSegment* segment) { + WriteOpenSpace("data"); + WriteInitExpr(segment->offset); + WriteQuotedData(segment->data, segment->size); + WriteCloseNewline(); } -static void write_import(Context* ctx, const Import* import) { - write_open_space(ctx, "import"); - write_quoted_string_slice(ctx, &import->module_name, NextChar::Space); - write_quoted_string_slice(ctx, &import->field_name, NextChar::Space); +void ASTWriter::WriteImport(const Import* import) { + WriteOpenSpace("import"); + WriteQuotedStringSlice(&import->module_name, NextChar::Space); + WriteQuotedStringSlice(&import->field_name, NextChar::Space); switch (import->kind) { case ExternalKind::Func: - write_open_space(ctx, "func"); - write_string_slice_or_index(ctx, &import->func->name, ctx->func_index++, + WriteOpenSpace("func"); + WriteStringSliceOrIndex(&import->func->name, func_index_++, NextChar::Space); if (decl_has_func_type(&import->func->decl)) { - write_open_space(ctx, "type"); - write_var(ctx, &import->func->decl.type_var, NextChar::None); - write_close_space(ctx); + WriteOpenSpace("type"); + WriteVar(&import->func->decl.type_var, NextChar::None); + WriteCloseSpace(); } else { - write_func_sig_space(ctx, &import->func->decl.sig); + WriteFuncSigSpace(&import->func->decl.sig); } - write_close_space(ctx); + WriteCloseSpace(); break; case ExternalKind::Table: - write_table(ctx, import->table); + WriteTable(import->table); break; case ExternalKind::Memory: - write_memory(ctx, import->memory); + WriteMemory(import->memory); break; case ExternalKind::Global: - write_begin_global(ctx, import->global); - write_close_space(ctx); + WriteBeginGlobal(import->global); + WriteCloseSpace(); break; } - write_close_newline(ctx); + WriteCloseNewline(); } -static void write_export(Context* ctx, const Export* export_) { +void ASTWriter::WriteExport(const Export* export_) { static const char* s_kind_names[] = {"func", "table", "memory", "global"}; WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(s_kind_names) == kExternalKindCount); - write_open_space(ctx, "export"); - write_quoted_string_slice(ctx, &export_->name, NextChar::Space); + WriteOpenSpace("export"); + WriteQuotedStringSlice(&export_->name, NextChar::Space); assert(static_cast<size_t>(export_->kind) < WABT_ARRAY_SIZE(s_kind_names)); - write_open_space(ctx, s_kind_names[static_cast<size_t>(export_->kind)]); - write_var(ctx, &export_->var, NextChar::Space); - write_close_space(ctx); - write_close_newline(ctx); + WriteOpenSpace(s_kind_names[static_cast<size_t>(export_->kind)]); + WriteVar(&export_->var, NextChar::Space); + WriteCloseSpace(); + WriteCloseNewline(); } -static void write_func_type(Context* ctx, const FuncType* func_type) { - write_open_space(ctx, "type"); - write_string_slice_or_index(ctx, &func_type->name, ctx->func_type_index++, - NextChar::Space); - write_open_space(ctx, "func"); - write_func_sig_space(ctx, &func_type->sig); - write_close_space(ctx); - write_close_newline(ctx); +void ASTWriter::WriteFuncType(const FuncType* func_type) { + WriteOpenSpace("type"); + WriteStringSliceOrIndex(&func_type->name, func_type_index_++, + NextChar::Space); + WriteOpenSpace("func"); + WriteFuncSigSpace(&func_type->sig); + WriteCloseSpace(); + WriteCloseNewline(); } -static void write_start_function(Context* ctx, const Var* start) { - write_open_space(ctx, "start"); - write_var(ctx, start, NextChar::None); - write_close_newline(ctx); +void ASTWriter::WriteStartFunction(const Var* start) { + WriteOpenSpace("start"); + WriteVar(start, NextChar::None); + WriteCloseNewline(); } -static void write_module(Context* ctx, const Module* module) { - write_open_newline(ctx, "module"); +Result ASTWriter::WriteModule(const Module* module) { + WriteOpenNewline("module"); for (const ModuleField* field = module->first_field; field; field = field->next) { switch (field->type) { case ModuleFieldType::Func: - write_func(ctx, module, field->func); + WriteFunc(module, field->func); break; case ModuleFieldType::Global: - write_global(ctx, field->global); + WriteGlobal(field->global); break; case ModuleFieldType::Import: - write_import(ctx, field->import); + WriteImport(field->import); break; case ModuleFieldType::Export: - write_export(ctx, field->export_); + WriteExport(field->export_); break; case ModuleFieldType::Table: - write_table(ctx, field->table); + WriteTable(field->table); break; case ModuleFieldType::ElemSegment: - write_elem_segment(ctx, field->elem_segment); + WriteElemSegment(field->elem_segment); break; case ModuleFieldType::Memory: - write_memory(ctx, field->memory); + WriteMemory(field->memory); break; case ModuleFieldType::DataSegment: - write_data_segment(ctx, field->data_segment); + WriteDataSegment(field->data_segment); break; case ModuleFieldType::FuncType: - write_func_type(ctx, field->func_type); + WriteFuncType(field->func_type); break; case ModuleFieldType::Start: - write_start_function(ctx, &field->start); + WriteStartFunction(&field->start); break; } } - write_close_newline(ctx); + WriteCloseNewline(); /* force the newline to be written */ - write_next_char(ctx); + WriteNextChar(); + return result_; } Result write_ast(Writer* writer, const Module* module) { - Context ctx(writer); - write_module(&ctx, module); - return ctx.result; + ASTWriter ast_writer(writer); + return ast_writer.WriteModule(module); } } // namespace wabt diff --git a/src/binary-writer-spec.cc b/src/binary-writer-spec.cc index d4b7f20d..171b40e3 100644 --- a/src/binary-writer-spec.cc +++ b/src/binary-writer-spec.cc @@ -28,27 +28,6 @@ namespace wabt { -namespace { - -struct Context { - Context(); - - MemoryStream json_stream; - StringSlice source_filename; - StringSlice module_filename_noext; - bool write_modules = false; /* Whether to write the modules files. */ - const WriteBinarySpecOptions* spec_options; - Result result = Result::Ok; - size_t num_modules = 0; -}; - -Context::Context() { - WABT_ZERO_MEMORY(source_filename); - WABT_ZERO_MEMORY(module_filename_noext); -} - -} // namespace - static void convert_backslash_to_slash(char* s, size_t length) { for (size_t i = 0; i < length; ++i) if (s[i] == '\\') @@ -105,43 +84,90 @@ static StringSlice get_basename(const char* s) { return result; } -static char* get_module_filename(Context* ctx) { - size_t buflen = ctx->module_filename_noext.length + 20; +namespace { + +class BinaryWriterSpec { + public: + BinaryWriterSpec(const char* source_filename, + const WriteBinarySpecOptions* spec_options); + + Result WriteScript(Script* script); + + private: + char* GetModuleFilename(); + void WriteString(const char* s); + void WriteKey(const char* key); + void WriteSeparator(); + void WriteEscapedStringSlice(StringSlice ss); + void WriteCommandType(const Command& command); + void WriteLocation(const Location* loc); + void WriteVar(const Var* var); + void WriteTypeObject(Type type); + void WriteConst(const Const* const_); + void WriteConstVector(const ConstVector& consts); + void WriteAction(const Action* action); + void WriteActionResultType(Script* script, const Action* action); + void WriteModule(char* filename, const Module* module); + void WriteRawModule(char* filename, const RawModule* raw_module); + void WriteInvalidModule(const RawModule* module, StringSlice text); + void WriteCommands(Script* script); + + MemoryStream json_stream_; + StringSlice source_filename_; + StringSlice module_filename_noext_; + bool write_modules_ = false; /* Whether to write the modules files. */ + const WriteBinarySpecOptions* spec_options_ = nullptr; + Result result_ = Result::Ok; + size_t num_modules_ = 0; +}; + +BinaryWriterSpec::BinaryWriterSpec(const char* source_filename, + const WriteBinarySpecOptions* spec_options) + : spec_options_(spec_options) { + source_filename_.start = source_filename; + source_filename_.length = strlen(source_filename); + module_filename_noext_ = strip_extension(spec_options_->json_filename + ? spec_options_->json_filename + : source_filename); + write_modules_ = !!spec_options_->json_filename; +} + +char* BinaryWriterSpec::GetModuleFilename() { + size_t buflen = module_filename_noext_.length + 20; char* str = new char[buflen]; - size_t length = - wabt_snprintf(str, buflen, PRIstringslice ".%" PRIzd ".wasm", - WABT_PRINTF_STRING_SLICE_ARG(ctx->module_filename_noext), - ctx->num_modules); + size_t length = wabt_snprintf( + str, buflen, PRIstringslice ".%" PRIzd ".wasm", + WABT_PRINTF_STRING_SLICE_ARG(module_filename_noext_), num_modules_); convert_backslash_to_slash(str, length); return str; } -static void write_string(Context* ctx, const char* s) { - ctx->json_stream.Writef("\"%s\"", s); +void BinaryWriterSpec::WriteString(const char* s) { + json_stream_.Writef("\"%s\"", s); } -static void write_key(Context* ctx, const char* key) { - ctx->json_stream.Writef("\"%s\": ", key); +void BinaryWriterSpec::WriteKey(const char* key) { + json_stream_.Writef("\"%s\": ", key); } -static void write_separator(Context* ctx) { - ctx->json_stream.Writef(", "); +void BinaryWriterSpec::WriteSeparator() { + json_stream_.Writef(", "); } -static void write_escaped_string_slice(Context* ctx, StringSlice ss) { - ctx->json_stream.WriteChar('"'); +void BinaryWriterSpec::WriteEscapedStringSlice(StringSlice ss) { + json_stream_.WriteChar('"'); for (size_t i = 0; i < ss.length; ++i) { uint8_t c = ss.start[i]; if (c < 0x20 || c == '\\' || c == '"') { - ctx->json_stream.Writef("\\u%04x", c); + json_stream_.Writef("\\u%04x", c); } else { - ctx->json_stream.WriteChar(c); + json_stream_.WriteChar(c); } } - ctx->json_stream.WriteChar('"'); + json_stream_.WriteChar('"'); } -static void write_command_type(Context* ctx, const Command& command) { +void BinaryWriterSpec::WriteCommandType(const Command& command) { static const char* s_command_names[] = { "module", "action", @@ -160,66 +186,66 @@ static void write_command_type(Context* ctx, const Command& command) { }; WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(s_command_names) == kCommandTypeCount); - write_key(ctx, "type"); + WriteKey("type"); assert(s_command_names[static_cast<size_t>(command.type)]); - write_string(ctx, s_command_names[static_cast<size_t>(command.type)]); + WriteString(s_command_names[static_cast<size_t>(command.type)]); } -static void write_location(Context* ctx, const Location* loc) { - write_key(ctx, "line"); - ctx->json_stream.Writef("%d", loc->line); +void BinaryWriterSpec::WriteLocation(const Location* loc) { + WriteKey("line"); + json_stream_.Writef("%d", loc->line); } -static void write_var(Context* ctx, const Var* var) { +void BinaryWriterSpec::WriteVar(const Var* var) { if (var->type == VarType::Index) - ctx->json_stream.Writef("\"%" PRIu64 "\"", var->index); + json_stream_.Writef("\"%" PRIu64 "\"", var->index); else - write_escaped_string_slice(ctx, var->name); + WriteEscapedStringSlice(var->name); } -static void write_type_object(Context* ctx, Type type) { - ctx->json_stream.Writef("{"); - write_key(ctx, "type"); - write_string(ctx, get_type_name(type)); - ctx->json_stream.Writef("}"); +void BinaryWriterSpec::WriteTypeObject(Type type) { + json_stream_.Writef("{"); + WriteKey("type"); + WriteString(get_type_name(type)); + json_stream_.Writef("}"); } -static void write_const(Context* ctx, const Const* const_) { - ctx->json_stream.Writef("{"); - write_key(ctx, "type"); +void BinaryWriterSpec::WriteConst(const Const* const_) { + json_stream_.Writef("{"); + WriteKey("type"); /* Always write the values as strings, even though they may be representable * as JSON numbers. This way the formatting is consistent. */ switch (const_->type) { case Type::I32: - write_string(ctx, "i32"); - write_separator(ctx); - write_key(ctx, "value"); - ctx->json_stream.Writef("\"%u\"", const_->u32); + WriteString("i32"); + WriteSeparator(); + WriteKey("value"); + json_stream_.Writef("\"%u\"", const_->u32); break; case Type::I64: - write_string(ctx, "i64"); - write_separator(ctx); - write_key(ctx, "value"); - ctx->json_stream.Writef("\"%" PRIu64 "\"", const_->u64); + WriteString("i64"); + WriteSeparator(); + WriteKey("value"); + json_stream_.Writef("\"%" PRIu64 "\"", const_->u64); break; case Type::F32: { /* TODO(binji): write as hex float */ - write_string(ctx, "f32"); - write_separator(ctx); - write_key(ctx, "value"); - ctx->json_stream.Writef("\"%u\"", const_->f32_bits); + WriteString("f32"); + WriteSeparator(); + WriteKey("value"); + json_stream_.Writef("\"%u\"", const_->f32_bits); break; } case Type::F64: { /* TODO(binji): write as hex float */ - write_string(ctx, "f64"); - write_separator(ctx); - write_key(ctx, "value"); - ctx->json_stream.Writef("\"%" PRIu64 "\"", const_->f64_bits); + WriteString("f64"); + WriteSeparator(); + WriteKey("value"); + json_stream_.Writef("\"%" PRIu64 "\"", const_->f64_bits); break; } @@ -227,55 +253,54 @@ static void write_const(Context* ctx, const Const* const_) { assert(0); } - ctx->json_stream.Writef("}"); + json_stream_.Writef("}"); } -static void write_const_vector(Context* ctx, const ConstVector& consts) { - ctx->json_stream.Writef("["); +void BinaryWriterSpec::WriteConstVector(const ConstVector& consts) { + json_stream_.Writef("["); for (size_t i = 0; i < consts.size(); ++i) { const Const* const_ = &consts[i]; - write_const(ctx, const_); + WriteConst(const_); if (i != consts.size() - 1) - write_separator(ctx); + WriteSeparator(); } - ctx->json_stream.Writef("]"); + json_stream_.Writef("]"); } -static void write_action(Context* ctx, const Action* action) { - write_key(ctx, "action"); - ctx->json_stream.Writef("{"); - write_key(ctx, "type"); +void BinaryWriterSpec::WriteAction(const Action* action) { + WriteKey("action"); + json_stream_.Writef("{"); + WriteKey("type"); if (action->type == ActionType::Invoke) { - write_string(ctx, "invoke"); + WriteString("invoke"); } else { assert(action->type == ActionType::Get); - write_string(ctx, "get"); + WriteString("get"); } - write_separator(ctx); + WriteSeparator(); if (action->module_var.type != VarType::Index) { - write_key(ctx, "module"); - write_var(ctx, &action->module_var); - write_separator(ctx); + WriteKey("module"); + WriteVar(&action->module_var); + WriteSeparator(); } if (action->type == ActionType::Invoke) { - write_key(ctx, "field"); - write_escaped_string_slice(ctx, action->name); - write_separator(ctx); - write_key(ctx, "args"); - write_const_vector(ctx, action->invoke->args); + WriteKey("field"); + WriteEscapedStringSlice(action->name); + WriteSeparator(); + WriteKey("args"); + WriteConstVector(action->invoke->args); } else { - write_key(ctx, "field"); - write_escaped_string_slice(ctx, action->name); + WriteKey("field"); + WriteEscapedStringSlice(action->name); } - ctx->json_stream.Writef("}"); + json_stream_.Writef("}"); } -static void write_action_result_type(Context* ctx, - Script* script, - const Action* action) { +void BinaryWriterSpec::WriteActionResultType(Script* script, + const Action* action) { const Module* module = get_module_by_var(script, &action->module_var); const Export* export_; - ctx->json_stream.Writef("["); + json_stream_.Writef("["); switch (action->type) { case ActionType::Invoke: { export_ = get_export_by_name(module, &action->name); @@ -283,7 +308,7 @@ static void write_action_result_type(Context* ctx, Func* func = get_func_by_var(module, &export_->var); size_t num_results = get_num_results(func); for (size_t i = 0; i < num_results; ++i) - write_type_object(ctx, get_result_type(func, i)); + WriteTypeObject(get_result_type(func, i)); break; } @@ -291,58 +316,55 @@ static void write_action_result_type(Context* ctx, export_ = get_export_by_name(module, &action->name); assert(export_->kind == ExternalKind::Global); Global* global = get_global_by_var(module, &export_->var); - write_type_object(ctx, global->type); + WriteTypeObject(global->type); break; } } - ctx->json_stream.Writef("]"); + json_stream_.Writef("]"); } -static void write_module(Context* ctx, char* filename, const Module* module) { - MemoryWriter writer; - WriteBinaryOptions options = ctx->spec_options->write_binary_options; - Result result = write_binary_module(&writer, module, &options); - if (WABT_SUCCEEDED(result) && ctx->write_modules) - result = writer.output_buffer().WriteToFile(filename); - - ctx->result = result; +void BinaryWriterSpec::WriteModule(char* filename, const Module* module) { + MemoryStream memory_stream; + result_ = write_binary_module(&memory_stream.writer(), module, + &spec_options_->write_binary_options); + if (WABT_SUCCEEDED(result_) && write_modules_) + result_ = memory_stream.WriteToFile(filename); } -static void write_raw_module(Context* ctx, - char* filename, - const RawModule* raw_module) { +void BinaryWriterSpec::WriteRawModule(char* filename, + const RawModule* raw_module) { if (raw_module->type == RawModuleType::Text) { - write_module(ctx, filename, raw_module->text); - } else if (ctx->write_modules) { - FileStream stream(filename); - if (stream.is_open()) { - stream.WriteData(raw_module->binary.data, raw_module->binary.size); - ctx->result = stream.result(); + WriteModule(filename, raw_module->text); + } else if (write_modules_) { + FileStream file_stream(filename); + if (file_stream.is_open()) { + file_stream.WriteData(raw_module->binary.data, raw_module->binary.size, + ""); + result_ = file_stream.result(); } else { - ctx->result = Result::Error; + result_ = Result::Error; } } } -static void write_invalid_module(Context* ctx, - const RawModule* module, - StringSlice text) { - char* filename = get_module_filename(ctx); - write_location(ctx, get_raw_module_location(module)); - write_separator(ctx); - write_key(ctx, "filename"); - write_escaped_string_slice(ctx, get_basename(filename)); - write_separator(ctx); - write_key(ctx, "text"); - write_escaped_string_slice(ctx, text); - write_raw_module(ctx, filename, module); +void BinaryWriterSpec::WriteInvalidModule(const RawModule* module, + StringSlice text) { + char* filename = GetModuleFilename(); + WriteLocation(get_raw_module_location(module)); + WriteSeparator(); + WriteKey("filename"); + WriteEscapedStringSlice(get_basename(filename)); + WriteSeparator(); + WriteKey("text"); + WriteEscapedStringSlice(text); + WriteRawModule(filename, module); delete [] filename; } -static void write_commands(Context* ctx, Script* script) { - ctx->json_stream.Writef("{\"source_filename\": "); - write_escaped_string_slice(ctx, ctx->source_filename); - ctx->json_stream.Writef(",\n \"commands\": [\n"); +void BinaryWriterSpec::WriteCommands(Script* script) { + json_stream_.Writef("{\"source_filename\": "); + WriteEscapedStringSlice(source_filename_); + json_stream_.Writef(",\n \"commands\": [\n"); int last_module_index = -1; for (size_t i = 0; i < script->commands.size(); ++i) { const Command& command = *script->commands[i].get(); @@ -351,122 +373,122 @@ static void write_commands(Context* ctx, Script* script) { continue; if (i != 0) - write_separator(ctx); - ctx->json_stream.Writef("\n"); + WriteSeparator(); + json_stream_.Writef("\n"); - ctx->json_stream.Writef(" {"); - write_command_type(ctx, command); - write_separator(ctx); + json_stream_.Writef(" {"); + WriteCommandType(command); + WriteSeparator(); switch (command.type) { case CommandType::Module: { Module* module = command.module; - char* filename = get_module_filename(ctx); - write_location(ctx, &module->loc); - write_separator(ctx); + char* filename = GetModuleFilename(); + WriteLocation(&module->loc); + WriteSeparator(); if (module->name.start) { - write_key(ctx, "name"); - write_escaped_string_slice(ctx, module->name); - write_separator(ctx); + WriteKey("name"); + WriteEscapedStringSlice(module->name); + WriteSeparator(); } - write_key(ctx, "filename"); - write_escaped_string_slice(ctx, get_basename(filename)); - write_module(ctx, filename, module); + WriteKey("filename"); + WriteEscapedStringSlice(get_basename(filename)); + WriteModule(filename, module); delete [] filename; - ctx->num_modules++; + num_modules_++; last_module_index = static_cast<int>(i); break; } case CommandType::Action: - write_location(ctx, &command.action->loc); - write_separator(ctx); - write_action(ctx, command.action); + WriteLocation(&command.action->loc); + WriteSeparator(); + WriteAction(command.action); break; case CommandType::Register: - write_location(ctx, &command.register_.var.loc); - write_separator(ctx); + WriteLocation(&command.register_.var.loc); + WriteSeparator(); if (command.register_.var.type == VarType::Name) { - write_key(ctx, "name"); - write_var(ctx, &command.register_.var); - write_separator(ctx); + WriteKey("name"); + WriteVar(&command.register_.var); + WriteSeparator(); } else { /* If we're not registering by name, then we should only be * registering the last module. */ WABT_USE(last_module_index); assert(command.register_.var.index == last_module_index); } - write_key(ctx, "as"); - write_escaped_string_slice(ctx, command.register_.module_name); + WriteKey("as"); + WriteEscapedStringSlice(command.register_.module_name); break; case CommandType::AssertMalformed: - write_invalid_module(ctx, command.assert_malformed.module, - command.assert_malformed.text); - ctx->num_modules++; + WriteInvalidModule(command.assert_malformed.module, + command.assert_malformed.text); + num_modules_++; break; case CommandType::AssertInvalid: - write_invalid_module(ctx, command.assert_invalid.module, + WriteInvalidModule(command.assert_invalid.module, command.assert_invalid.text); - ctx->num_modules++; + num_modules_++; break; case CommandType::AssertUnlinkable: - write_invalid_module(ctx, command.assert_unlinkable.module, - command.assert_unlinkable.text); - ctx->num_modules++; + WriteInvalidModule(command.assert_unlinkable.module, + command.assert_unlinkable.text); + num_modules_++; break; case CommandType::AssertUninstantiable: - write_invalid_module(ctx, command.assert_uninstantiable.module, - command.assert_uninstantiable.text); - ctx->num_modules++; + WriteInvalidModule(command.assert_uninstantiable.module, + command.assert_uninstantiable.text); + num_modules_++; break; case CommandType::AssertReturn: - write_location(ctx, &command.assert_return.action->loc); - write_separator(ctx); - write_action(ctx, command.assert_return.action); - write_separator(ctx); - write_key(ctx, "expected"); - write_const_vector(ctx, *command.assert_return.expected); + WriteLocation(&command.assert_return.action->loc); + WriteSeparator(); + WriteAction(command.assert_return.action); + WriteSeparator(); + WriteKey("expected"); + WriteConstVector(*command.assert_return.expected); break; case CommandType::AssertReturnCanonicalNan: - write_location(ctx, &command.assert_return_canonical_nan.action->loc); - write_separator(ctx); - write_action(ctx, command.assert_return_canonical_nan.action); - write_separator(ctx); - write_key(ctx, "expected"); - write_action_result_type(ctx, script, - command.assert_return_canonical_nan.action); + WriteLocation(&command.assert_return_canonical_nan.action->loc); + WriteSeparator(); + WriteAction(command.assert_return_canonical_nan.action); + WriteSeparator(); + WriteKey("expected"); + WriteActionResultType(script, + command.assert_return_canonical_nan.action); break; case CommandType::AssertReturnArithmeticNan: - write_location(ctx, &command.assert_return_arithmetic_nan.action->loc); - write_separator(ctx); - write_action(ctx, command.assert_return_arithmetic_nan.action); - write_separator(ctx); - write_key(ctx, "expected"); - write_action_result_type(ctx, script, - command.assert_return_arithmetic_nan.action); + WriteLocation(&command.assert_return_arithmetic_nan.action->loc); + WriteSeparator(); + WriteAction(command.assert_return_arithmetic_nan.action); + WriteSeparator(); + WriteKey("expected"); + WriteActionResultType(script, + command.assert_return_arithmetic_nan.action); break; case CommandType::AssertTrap: - write_location(ctx, &command.assert_trap.action->loc); - write_separator(ctx); - write_action(ctx, command.assert_trap.action); - write_separator(ctx); - write_key(ctx, "text"); - write_escaped_string_slice(ctx, command.assert_trap.text); + WriteLocation(&command.assert_trap.action->loc); + WriteSeparator(); + WriteAction(command.assert_trap.action); + WriteSeparator(); + WriteKey("text"); + WriteEscapedStringSlice(command.assert_trap.text); break; case CommandType::AssertExhaustion: - write_location(ctx, &command.assert_trap.action->loc); - write_separator(ctx); - write_action(ctx, command.assert_trap.action); + WriteLocation(&command.assert_trap.action->loc); + WriteSeparator(); + WriteAction(command.assert_trap.action); break; case CommandType::AssertInvalidNonBinary: @@ -474,31 +496,27 @@ static void write_commands(Context* ctx, Script* script) { break; } - ctx->json_stream.Writef("}"); + json_stream_.Writef("}"); } - ctx->json_stream.Writef("]}\n"); + json_stream_.Writef("]}\n"); } +Result BinaryWriterSpec::WriteScript(Script* script) { + WriteCommands(script); + if (spec_options_->json_filename) { + json_stream_.WriteToFile(spec_options_->json_filename); + } + return result_; +} + +} // namespace + Result write_binary_spec_script(Script* script, const char* source_filename, const WriteBinarySpecOptions* spec_options) { assert(source_filename); - Context ctx; - ctx.spec_options = spec_options; - ctx.result = Result::Ok; - ctx.source_filename.start = source_filename; - ctx.source_filename.length = strlen(source_filename); - ctx.module_filename_noext = strip_extension( - ctx.spec_options->json_filename ? ctx.spec_options->json_filename - : source_filename); - ctx.write_modules = !!ctx.spec_options->json_filename; - - write_commands(&ctx, script); - if (ctx.spec_options->json_filename) { - ctx.json_stream.WriteToFile(ctx.spec_options->json_filename); - } - - return ctx.result; + BinaryWriterSpec binary_writer_spec(source_filename, spec_options); + return binary_writer_spec.WriteScript(script); } } // namespace wabt diff --git a/src/binary-writer.cc b/src/binary-writer.cc index 8e4b383f..3d76eec2 100644 --- a/src/binary-writer.cc +++ b/src/binary-writer.cc @@ -37,68 +37,15 @@ namespace wabt { -namespace { - -/* TODO(binji): better leb size guess. Some sections we know will only be 1 - byte, but others we can be fairly certain will be larger. */ -static const size_t LEB_SECTION_SIZE_GUESS = 1; - -#define ALLOC_FAILURE \ - fprintf(stderr, "%s:%d: allocation failed\n", __FILE__, __LINE__) - -struct RelocSection { - RelocSection(const char* name, BinarySection code); - - const char* name; - BinarySection section_code; - std::vector<Reloc> relocations; -}; - -RelocSection::RelocSection(const char* name, BinarySection code) - : name(name), section_code(code) {} - -struct Context { - WABT_DISALLOW_COPY_AND_ASSIGN(Context); - Context(Writer* writer, const WriteBinaryOptions* options); - - Stream stream; - const WriteBinaryOptions* options = nullptr; +// TODO(binji): move the LEB128 functions somewhere else. - std::vector<RelocSection> reloc_sections; - RelocSection* current_reloc_section = nullptr; - - size_t last_section_offset = 0; - size_t last_section_leb_size_guess = 0; - BinarySection last_section_type = BinarySection::Invalid; - size_t last_section_payload_offset = 0; - - size_t last_subsection_offset = 0; - size_t last_subsection_leb_size_guess = 0; - size_t last_subsection_payload_offset = 0; -}; - -Context::Context(Writer* writer, const WriteBinaryOptions* options) - : stream(writer, options->log_stream), options(options) {} - -} // namespace - -static uint8_t log2_u32(uint32_t x) { - uint8_t result = 0; - while (x > 1) { - x >>= 1; - result++; - } - return result; -} - -static void write_header(Context* ctx, const char* name, int index) { - if (ctx->stream.has_log_stream()) { - if (index == PRINT_HEADER_NO_INDEX) { - ctx->stream.log_stream().Writef("; %s\n", name); - } else { - ctx->stream.log_stream().Writef("; %s %d\n", name, index); - } - } +uint32_t u32_leb128_length(uint32_t value) { + uint32_t size = 0; + do { + value >>= 7; + size++; + } while (value != 0); + return size; } #define LEB128_LOOP_UNTIL(end_cond) \ @@ -106,18 +53,36 @@ static void write_header(Context* ctx, const char* name, int index) { uint8_t byte = value & 0x7f; \ value >>= 7; \ if (end_cond) { \ - data[i++] = byte; \ + data[length++] = byte; \ break; \ } else { \ - data[i++] = byte | 0x80; \ + data[length++] = byte | 0x80; \ } \ } while (1) -uint32_t u32_leb128_length(uint32_t value) { - uint8_t data[MAX_U32_LEB128_BYTES] WABT_UNUSED; - uint32_t i = 0; +uint32_t write_fixed_u32_leb128_at(Stream* stream, + uint32_t offset, + uint32_t value, + const char* desc) { + uint8_t data[MAX_U32_LEB128_BYTES]; + uint32_t length = + write_fixed_u32_leb128_raw(data, data + MAX_U32_LEB128_BYTES, value); + stream->WriteDataAt(offset, data, length, desc); + return length; +} + +void write_u32_leb128(Stream* stream, uint32_t value, const char* desc) { + uint8_t data[MAX_U32_LEB128_BYTES]; + uint32_t length = 0; LEB128_LOOP_UNTIL(value == 0); - return i; + stream->WriteData(data, length, desc); +} + +void write_fixed_u32_leb128(Stream* stream, uint32_t value, const char* desc) { + uint8_t data[MAX_U32_LEB128_BYTES]; + uint32_t length = + write_fixed_u32_leb128_raw(data, data + MAX_U32_LEB128_BYTES, value); + stream->WriteData(data, length, desc); } /* returns the length of the leb128 */ @@ -126,10 +91,9 @@ uint32_t write_u32_leb128_at(Stream* stream, uint32_t value, const char* desc) { uint8_t data[MAX_U32_LEB128_BYTES]; - uint32_t i = 0; + uint32_t length = 0; LEB128_LOOP_UNTIL(value == 0); - uint32_t length = i; - stream->WriteDataAt(offset, data, length, desc, PrintChars::No); + stream->WriteDataAt(offset, data, length, desc); return length; } @@ -146,95 +110,30 @@ uint32_t write_fixed_u32_leb128_raw(uint8_t* data, return MAX_U32_LEB128_BYTES; } -uint32_t write_fixed_u32_leb128_at(Stream* stream, - uint32_t offset, - uint32_t value, - const char* desc) { - uint8_t data[MAX_U32_LEB128_BYTES]; - uint32_t length = - write_fixed_u32_leb128_raw(data, data + MAX_U32_LEB128_BYTES, value); - 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->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->AddOffset(length); -} - void write_i32_leb128(Stream* stream, int32_t value, const char* desc) { uint8_t data[MAX_U32_LEB128_BYTES]; - uint32_t i = 0; + uint32_t length = 0; if (value < 0) LEB128_LOOP_UNTIL(value == -1 && (byte & 0x40)); else LEB128_LOOP_UNTIL(value == 0 && !(byte & 0x40)); - uint32_t length = i; stream->WriteData(data, length, desc); } static void write_i64_leb128(Stream* stream, int64_t value, const char* desc) { uint8_t data[MAX_U64_LEB128_BYTES]; - uint32_t i = 0; + uint32_t length = 0; if (value < 0) LEB128_LOOP_UNTIL(value == -1 && (byte & 0x40)); else LEB128_LOOP_UNTIL(value == 0 && !(byte & 0x40)); - int length = i; stream->WriteData(data, length, desc); } -#undef LEB128_LOOP_UNTIL - -static uint32_t size_u32_leb128(uint32_t value) { - uint32_t size = 0; - do { - value >>= 7; - size++; - } while (value != 0); - return size; -} - -/* returns offset of leb128 */ -static uint32_t write_u32_leb128_space(Context* ctx, - uint32_t leb_size_guess, - const char* desc) { - assert(leb_size_guess <= MAX_U32_LEB128_BYTES); - uint8_t data[MAX_U32_LEB128_BYTES] = {0}; - uint32_t result = ctx->stream.offset(); - uint32_t bytes_to_write = - ctx->options->canonicalize_lebs ? leb_size_guess : MAX_U32_LEB128_BYTES; - ctx->stream.WriteData(data, bytes_to_write, desc); - return result; -} -static void write_fixup_u32_leb128_size(Context* ctx, - uint32_t offset, - 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 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; - ctx->stream.MoveData(dst_offset, src_offset, size); - } - write_u32_leb128_at(&ctx->stream, offset, size, desc); - ctx->stream.AddOffset(leb_size - leb_size_guess); - } else { - uint32_t size = ctx->stream.offset() - offset - MAX_U32_LEB128_BYTES; - write_fixed_u32_leb128_at(&ctx->stream, offset, size, desc); - } -} +#undef LEB128_LOOP_UNTIL void write_str(Stream* stream, const char* s, @@ -253,6 +152,139 @@ void write_type(Stream* stream, Type type) { write_i32_leb128_enum(stream, type, get_type_name(type)); } +void write_limits(Stream* stream, const Limits* limits) { + uint32_t flags = limits->has_max ? WABT_BINARY_LIMITS_HAS_MAX_FLAG : 0; + write_u32_leb128(stream, flags, "limits: flags"); + write_u32_leb128(stream, limits->initial, "limits: initial"); + if (limits->has_max) + write_u32_leb128(stream, limits->max, "limits: max"); +} + +namespace { + +/* TODO(binji): better leb size guess. Some sections we know will only be 1 + byte, but others we can be fairly certain will be larger. */ +static const size_t LEB_SECTION_SIZE_GUESS = 1; + +#define ALLOC_FAILURE \ + fprintf(stderr, "%s:%d: allocation failed\n", __FILE__, __LINE__) + +struct RelocSection { + RelocSection(const char* name, BinarySection code); + + const char* name; + BinarySection section_code; + std::vector<Reloc> relocations; +}; + +RelocSection::RelocSection(const char* name, BinarySection code) + : name(name), section_code(code) {} + +class BinaryWriter { + WABT_DISALLOW_COPY_AND_ASSIGN(BinaryWriter); + + public: + BinaryWriter(Writer*, const WriteBinaryOptions* options); + + Result WriteModule(const Module* module); + + private: + void WriteHeader(const char* name, int index); + uint32_t WriteU32Leb128Space(uint32_t leb_size_guess, const char* desc); + void WriteFixupU32Leb128Size(uint32_t offset, + uint32_t leb_size_guess, + const char* desc); + void BeginKnownSection(BinarySection section_code, size_t leb_size_guess); + void BeginCustomSection(const char* name, size_t leb_size_guess); + void EndSection(); + void BeginSubsection(const char* name, size_t leb_size_guess); + void EndSubsection(); + uint32_t GetLabelVarDepth(const Var* var); + void AddReloc(RelocType reloc_type, uint32_t index); + void WriteU32Leb128WithReloc(uint32_t index, + const char* desc, + RelocType reloc_type); + void WriteExpr(const Module* module, const Func* func, const Expr* expr); + void WriteExprList(const Module* module, const Func* func, const Expr* first); + void WriteInitExpr(const Module* module, const Expr* expr); + void WriteFuncLocals(const Module* module, + const Func* func, + const TypeVector& local_types); + void WriteFunc(const Module* module, const Func* func); + void WriteTable(const Table* table); + void WriteMemory(const Memory* memory); + void WriteGlobalHeader(const Global* global); + void WriteRelocSection(const RelocSection* reloc_section); + + Stream stream_; + const WriteBinaryOptions* options_ = nullptr; + + std::vector<RelocSection> reloc_sections_; + RelocSection* current_reloc_section_ = nullptr; + + size_t last_section_offset_ = 0; + size_t last_section_leb_size_guess_ = 0; + BinarySection last_section_type_ = BinarySection::Invalid; + size_t last_section_payload_offset_ = 0; + + size_t last_subsection_offset_ = 0; + size_t last_subsection_leb_size_guess_ = 0; + size_t last_subsection_payload_offset_ = 0; +}; + +static uint8_t log2_u32(uint32_t x) { + uint8_t result = 0; + while (x > 1) { + x >>= 1; + result++; + } + return result; +} + +BinaryWriter::BinaryWriter(Writer* writer, const WriteBinaryOptions* options) + : stream_(writer, options->log_stream), options_(options) {} + +void BinaryWriter::WriteHeader(const char* name, int index) { + if (stream_.has_log_stream()) { + if (index == PRINT_HEADER_NO_INDEX) { + stream_.log_stream().Writef("; %s\n", name); + } else { + stream_.log_stream().Writef("; %s %d\n", name, index); + } + } +} + +/* returns offset of leb128 */ +uint32_t BinaryWriter::WriteU32Leb128Space(uint32_t leb_size_guess, + const char* desc) { + assert(leb_size_guess <= MAX_U32_LEB128_BYTES); + uint8_t data[MAX_U32_LEB128_BYTES] = {0}; + uint32_t result = stream_.offset(); + uint32_t bytes_to_write = + options_->canonicalize_lebs ? leb_size_guess : MAX_U32_LEB128_BYTES; + stream_.WriteData(data, bytes_to_write, desc); + return result; +} + +void BinaryWriter::WriteFixupU32Leb128Size(uint32_t offset, + uint32_t leb_size_guess, + const char* desc) { + if (options_->canonicalize_lebs) { + uint32_t size = stream_.offset() - offset - leb_size_guess; + uint32_t leb_size = u32_leb128_length(size); + if (leb_size != leb_size_guess) { + uint32_t src_offset = offset + leb_size_guess; + uint32_t dst_offset = offset + leb_size; + stream_.MoveData(dst_offset, src_offset, size); + } + write_u32_leb128_at(&stream_, offset, size, desc); + stream_.AddOffset(leb_size - leb_size_guess); + } else { + uint32_t size = stream_.offset() - offset - MAX_U32_LEB128_BYTES; + write_fixed_u32_leb128_at(&stream_, offset, size, desc); + } +} + static void write_inline_signature_type(Stream* stream, const BlockSignature& sig) { if (sig.size() == 0) { @@ -265,297 +297,276 @@ static void write_inline_signature_type(Stream* stream, } } -static void begin_known_section(Context* ctx, - BinarySection section_code, - size_t leb_size_guess) { - assert(ctx->last_section_leb_size_guess == 0); +void BinaryWriter::BeginKnownSection(BinarySection section_code, + size_t leb_size_guess) { + assert(last_section_leb_size_guess_ == 0); char desc[100]; 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); - 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(); -} - -static void begin_custom_section(Context* ctx, - const char* name, - size_t leb_size_guess) { - assert(ctx->last_section_leb_size_guess == 0); + get_section_name(section_code), + static_cast<unsigned>(section_code)); + WriteHeader(desc, PRINT_HEADER_NO_INDEX); + stream_.WriteU8Enum(section_code, "section code"); + last_section_type_ = section_code; + last_section_leb_size_guess_ = leb_size_guess; + last_section_offset_ = + WriteU32Leb128Space(leb_size_guess, "section size (guess)"); + last_section_payload_offset_ = stream_.offset(); +} + +void BinaryWriter::BeginCustomSection(const char* name, size_t leb_size_guess) { + assert(last_section_leb_size_guess_ == 0); char desc[100]; wabt_snprintf(desc, sizeof(desc), "section \"%s\"", name); - write_header(ctx, desc, PRINT_HEADER_NO_INDEX); - 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), "custom section name", + WriteHeader(desc, PRINT_HEADER_NO_INDEX); + stream_.WriteU8Enum(BinarySection::Custom, "custom section code"); + last_section_type_ = BinarySection::Custom; + last_section_leb_size_guess_ = leb_size_guess; + last_section_offset_ = + WriteU32Leb128Space(leb_size_guess, "section size (guess)"); + last_section_payload_offset_ = stream_.offset(); + write_str(&stream_, name, strlen(name), "custom section name", PrintChars::Yes); } -static void end_section(Context* ctx) { - assert(ctx->last_section_leb_size_guess != 0); - write_fixup_u32_leb128_size(ctx, ctx->last_section_offset, - ctx->last_section_leb_size_guess, - "FIXUP section size"); - ctx->last_section_leb_size_guess = 0; +void BinaryWriter::EndSection() { + assert(last_section_leb_size_guess_ != 0); + WriteFixupU32Leb128Size(last_section_offset_, last_section_leb_size_guess_, + "FIXUP section size"); + last_section_leb_size_guess_ = 0; } -static void begin_subsection(Context* ctx, - const char* name, - size_t leb_size_guess) { - assert(ctx->last_subsection_leb_size_guess == 0); - 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(); +void BinaryWriter::BeginSubsection(const char* name, size_t leb_size_guess) { + assert(last_subsection_leb_size_guess_ == 0); + last_subsection_leb_size_guess_ = leb_size_guess; + last_subsection_offset_ = + WriteU32Leb128Space(leb_size_guess, "subsection size (guess)"); + last_subsection_payload_offset_ = stream_.offset(); } -static void end_subsection(Context* ctx) { - assert(ctx->last_subsection_leb_size_guess != 0); - write_fixup_u32_leb128_size(ctx, ctx->last_subsection_offset, - ctx->last_subsection_leb_size_guess, - "FIXUP subsection size"); - ctx->last_subsection_leb_size_guess = 0; +void BinaryWriter::EndSubsection() { + assert(last_subsection_leb_size_guess_ != 0); + WriteFixupU32Leb128Size(last_subsection_offset_, + last_subsection_leb_size_guess_, + "FIXUP subsection size"); + last_subsection_leb_size_guess_ = 0; } -static uint32_t get_label_var_depth(Context* ctx, const Var* var) { +uint32_t BinaryWriter::GetLabelVarDepth(const Var* var) { assert(var->type == VarType::Index); return var->index; } -static void write_expr_list(Context* ctx, - const Module* module, - const Func* func, - const Expr* first_expr); - -static void add_reloc(Context* ctx, RelocType reloc_type, uint32_t index) { +void BinaryWriter::AddReloc(RelocType reloc_type, uint32_t index) { // Add a new reloc section if needed - if (!ctx->current_reloc_section || - ctx->current_reloc_section->section_code != ctx->last_section_type) { - ctx->reloc_sections.emplace_back(get_section_name(ctx->last_section_type), - ctx->last_section_type); - ctx->current_reloc_section = &ctx->reloc_sections.back(); + if (!current_reloc_section_ || + current_reloc_section_->section_code != last_section_type_) { + reloc_sections_.emplace_back(get_section_name(last_section_type_), + last_section_type_); + current_reloc_section_ = &reloc_sections_.back(); } // Add a new relocation to the curent reloc section - size_t offset = ctx->stream.offset() - ctx->last_section_payload_offset; - ctx->current_reloc_section->relocations.emplace_back(reloc_type, offset, - index); -} - -static void write_u32_leb128_with_reloc(Context* ctx, - uint32_t index, - const char* desc, - RelocType reloc_type) { - if (ctx->options->relocatable) { - add_reloc(ctx, reloc_type, index); - write_fixed_u32_leb128(&ctx->stream, index, desc); + size_t offset = stream_.offset() - last_section_payload_offset_; + current_reloc_section_->relocations.emplace_back(reloc_type, offset, index); +} + +void BinaryWriter::WriteU32Leb128WithReloc(uint32_t index, + const char* desc, + RelocType reloc_type) { + if (options_->relocatable) { + AddReloc(reloc_type, index); + write_fixed_u32_leb128(&stream_, index, desc); } else { - write_u32_leb128(&ctx->stream, index, desc); + write_u32_leb128(&stream_, index, desc); } } -static void write_expr(Context* ctx, - const Module* module, - const Func* func, - const Expr* expr) { +void BinaryWriter::WriteExpr(const Module* module, + const Func* func, + const Expr* expr) { switch (expr->type) { case ExprType::Binary: - write_opcode(&ctx->stream, expr->binary.opcode); + write_opcode(&stream_, expr->binary.opcode); break; case ExprType::Block: - write_opcode(&ctx->stream, Opcode::Block); - write_inline_signature_type(&ctx->stream, expr->block->sig); - write_expr_list(ctx, module, func, expr->block->first); - write_opcode(&ctx->stream, Opcode::End); + write_opcode(&stream_, Opcode::Block); + write_inline_signature_type(&stream_, expr->block->sig); + WriteExprList(module, func, expr->block->first); + write_opcode(&stream_, Opcode::End); break; case ExprType::Br: - write_opcode(&ctx->stream, Opcode::Br); - write_u32_leb128(&ctx->stream, get_label_var_depth(ctx, &expr->br.var), + write_opcode(&stream_, Opcode::Br); + write_u32_leb128(&stream_, GetLabelVarDepth(&expr->br.var), "break depth"); break; case ExprType::BrIf: - write_opcode(&ctx->stream, Opcode::BrIf); - write_u32_leb128(&ctx->stream, get_label_var_depth(ctx, &expr->br_if.var), + write_opcode(&stream_, Opcode::BrIf); + write_u32_leb128(&stream_, GetLabelVarDepth(&expr->br_if.var), "break depth"); break; case ExprType::BrTable: { - write_opcode(&ctx->stream, Opcode::BrTable); - write_u32_leb128(&ctx->stream, expr->br_table.targets->size(), - "num targets"); + write_opcode(&stream_, Opcode::BrTable); + write_u32_leb128(&stream_, expr->br_table.targets->size(), "num targets"); uint32_t depth; - for (const Var& var: *expr->br_table.targets) { - depth = get_label_var_depth(ctx, &var); - write_u32_leb128(&ctx->stream, depth, "break depth"); + for (const Var& var : *expr->br_table.targets) { + depth = GetLabelVarDepth(&var); + write_u32_leb128(&stream_, depth, "break depth"); } - depth = get_label_var_depth(ctx, &expr->br_table.default_target); - write_u32_leb128(&ctx->stream, depth, "break depth for default"); + depth = GetLabelVarDepth(&expr->br_table.default_target); + write_u32_leb128(&stream_, depth, "break depth for default"); break; } case ExprType::Call: { int index = get_func_index_by_var(module, &expr->call.var); - write_opcode(&ctx->stream, Opcode::Call); - write_u32_leb128_with_reloc(ctx, index, "function index", - RelocType::FuncIndexLEB); + write_opcode(&stream_, Opcode::Call); + WriteU32Leb128WithReloc(index, "function index", RelocType::FuncIndexLEB); break; } case ExprType::CallIndirect: { int index = get_func_type_index_by_var(module, &expr->call_indirect.var); - write_opcode(&ctx->stream, Opcode::CallIndirect); - write_u32_leb128(&ctx->stream, index, "signature index"); - write_u32_leb128(&ctx->stream, 0, "call_indirect reserved"); + write_opcode(&stream_, Opcode::CallIndirect); + write_u32_leb128(&stream_, index, "signature index"); + write_u32_leb128(&stream_, 0, "call_indirect reserved"); break; } case ExprType::Compare: - write_opcode(&ctx->stream, expr->compare.opcode); + write_opcode(&stream_, expr->compare.opcode); break; case ExprType::Const: switch (expr->const_.type) { case Type::I32: { - write_opcode(&ctx->stream, Opcode::I32Const); - write_i32_leb128(&ctx->stream, expr->const_.u32, "i32 literal"); + write_opcode(&stream_, Opcode::I32Const); + write_i32_leb128(&stream_, expr->const_.u32, "i32 literal"); break; } case Type::I64: - write_opcode(&ctx->stream, Opcode::I64Const); - write_i64_leb128(&ctx->stream, expr->const_.u64, "i64 literal"); + write_opcode(&stream_, Opcode::I64Const); + write_i64_leb128(&stream_, expr->const_.u64, "i64 literal"); break; case Type::F32: - write_opcode(&ctx->stream, Opcode::F32Const); - ctx->stream.WriteU32(expr->const_.f32_bits, "f32 literal"); + write_opcode(&stream_, Opcode::F32Const); + stream_.WriteU32(expr->const_.f32_bits, "f32 literal"); break; case Type::F64: - write_opcode(&ctx->stream, Opcode::F64Const); - ctx->stream.WriteU64(expr->const_.f64_bits, "f64 literal"); + write_opcode(&stream_, Opcode::F64Const); + stream_.WriteU64(expr->const_.f64_bits, "f64 literal"); break; default: assert(0); } break; case ExprType::Convert: - write_opcode(&ctx->stream, expr->convert.opcode); + write_opcode(&stream_, expr->convert.opcode); break; case ExprType::CurrentMemory: - write_opcode(&ctx->stream, Opcode::CurrentMemory); - write_u32_leb128(&ctx->stream, 0, "current_memory reserved"); + write_opcode(&stream_, Opcode::CurrentMemory); + write_u32_leb128(&stream_, 0, "current_memory reserved"); break; case ExprType::Drop: - write_opcode(&ctx->stream, Opcode::Drop); + write_opcode(&stream_, Opcode::Drop); break; case ExprType::GetGlobal: { int index = get_global_index_by_var(module, &expr->get_global.var); - write_opcode(&ctx->stream, Opcode::GetGlobal); - write_u32_leb128_with_reloc(ctx, index, "global index", - RelocType::GlobalIndexLEB); + write_opcode(&stream_, Opcode::GetGlobal); + WriteU32Leb128WithReloc(index, "global index", RelocType::GlobalIndexLEB); break; } case ExprType::GetLocal: { int index = get_local_index_by_var(func, &expr->get_local.var); - write_opcode(&ctx->stream, Opcode::GetLocal); - write_u32_leb128(&ctx->stream, index, "local index"); + write_opcode(&stream_, Opcode::GetLocal); + write_u32_leb128(&stream_, index, "local index"); break; } case ExprType::GrowMemory: - write_opcode(&ctx->stream, Opcode::GrowMemory); - write_u32_leb128(&ctx->stream, 0, "grow_memory reserved"); + write_opcode(&stream_, Opcode::GrowMemory); + write_u32_leb128(&stream_, 0, "grow_memory reserved"); break; case ExprType::If: - write_opcode(&ctx->stream, Opcode::If); - write_inline_signature_type(&ctx->stream, expr->if_.true_->sig); - write_expr_list(ctx, module, func, expr->if_.true_->first); + write_opcode(&stream_, Opcode::If); + write_inline_signature_type(&stream_, expr->if_.true_->sig); + WriteExprList(module, func, expr->if_.true_->first); if (expr->if_.false_) { - write_opcode(&ctx->stream, Opcode::Else); - write_expr_list(ctx, module, func, expr->if_.false_); + write_opcode(&stream_, Opcode::Else); + WriteExprList(module, func, expr->if_.false_); } - write_opcode(&ctx->stream, Opcode::End); + write_opcode(&stream_, Opcode::End); break; case ExprType::Load: { - write_opcode(&ctx->stream, expr->load.opcode); + write_opcode(&stream_, expr->load.opcode); uint32_t align = get_opcode_alignment(expr->load.opcode, expr->load.align); - ctx->stream.WriteU8(log2_u32(align), "alignment"); - write_u32_leb128(&ctx->stream, expr->load.offset, "load offset"); + stream_.WriteU8(log2_u32(align), "alignment"); + write_u32_leb128(&stream_, expr->load.offset, "load offset"); break; } case ExprType::Loop: - write_opcode(&ctx->stream, Opcode::Loop); - write_inline_signature_type(&ctx->stream, expr->loop->sig); - write_expr_list(ctx, module, func, expr->loop->first); - write_opcode(&ctx->stream, Opcode::End); + write_opcode(&stream_, Opcode::Loop); + write_inline_signature_type(&stream_, expr->loop->sig); + WriteExprList(module, func, expr->loop->first); + write_opcode(&stream_, Opcode::End); break; case ExprType::Nop: - write_opcode(&ctx->stream, Opcode::Nop); + write_opcode(&stream_, Opcode::Nop); break; case ExprType::Return: - write_opcode(&ctx->stream, Opcode::Return); + write_opcode(&stream_, Opcode::Return); break; case ExprType::Select: - write_opcode(&ctx->stream, Opcode::Select); + write_opcode(&stream_, Opcode::Select); break; case ExprType::SetGlobal: { int index = get_global_index_by_var(module, &expr->get_global.var); - write_opcode(&ctx->stream, Opcode::SetGlobal); - write_u32_leb128_with_reloc(ctx, index, "global index", - RelocType::GlobalIndexLEB); + write_opcode(&stream_, Opcode::SetGlobal); + WriteU32Leb128WithReloc(index, "global index", RelocType::GlobalIndexLEB); break; } case ExprType::SetLocal: { int index = get_local_index_by_var(func, &expr->get_local.var); - write_opcode(&ctx->stream, Opcode::SetLocal); - write_u32_leb128(&ctx->stream, index, "local index"); + write_opcode(&stream_, Opcode::SetLocal); + write_u32_leb128(&stream_, index, "local index"); break; } case ExprType::Store: { - write_opcode(&ctx->stream, expr->store.opcode); + write_opcode(&stream_, expr->store.opcode); uint32_t align = get_opcode_alignment(expr->store.opcode, expr->store.align); - ctx->stream.WriteU8(log2_u32(align), "alignment"); - write_u32_leb128(&ctx->stream, expr->store.offset, "store offset"); + stream_.WriteU8(log2_u32(align), "alignment"); + write_u32_leb128(&stream_, expr->store.offset, "store offset"); break; } case ExprType::TeeLocal: { int index = get_local_index_by_var(func, &expr->get_local.var); - write_opcode(&ctx->stream, Opcode::TeeLocal); - write_u32_leb128(&ctx->stream, index, "local index"); + write_opcode(&stream_, Opcode::TeeLocal); + write_u32_leb128(&stream_, index, "local index"); break; } case ExprType::Unary: - write_opcode(&ctx->stream, expr->unary.opcode); + write_opcode(&stream_, expr->unary.opcode); break; case ExprType::Unreachable: - write_opcode(&ctx->stream, Opcode::Unreachable); + write_opcode(&stream_, Opcode::Unreachable); break; } } -static void write_expr_list(Context* ctx, - const Module* module, - const Func* func, - const Expr* first) { +void BinaryWriter::WriteExprList(const Module* module, + const Func* func, + const Expr* first) { for (const Expr* expr = first; expr; expr = expr->next) - write_expr(ctx, module, func, expr); + WriteExpr(module, func, expr); } -static void write_init_expr(Context* ctx, - const Module* module, - const Expr* expr) { +void BinaryWriter::WriteInitExpr(const Module* module, const Expr* expr) { if (expr) - write_expr_list(ctx, module, nullptr, expr); - write_opcode(&ctx->stream, Opcode::End); + WriteExprList(module, nullptr, expr); + write_opcode(&stream_, Opcode::End); } -static void write_func_locals(Context* ctx, - const Module* module, - const Func* func, - const TypeVector& local_types) { +void BinaryWriter::WriteFuncLocals(const Module* module, + const Func* func, + const TypeVector& local_types) { if (local_types.size() == 0) { - write_u32_leb128(&ctx->stream, 0, "local decl count"); + write_u32_leb128(&stream_, 0, "local decl count"); return; } @@ -577,7 +588,7 @@ static void write_func_locals(Context* ctx, } /* loop through again to write everything out */ - write_u32_leb128(&ctx->stream, local_decl_count, "local decl count"); + write_u32_leb128(&stream_, local_decl_count, "local decl count"); current_type = GET_LOCAL_TYPE(FIRST_LOCAL_INDEX); uint32_t local_type_count = 1; for (uint32_t i = FIRST_LOCAL_INDEX + 1; i <= LAST_LOCAL_INDEX; ++i) { @@ -586,337 +597,326 @@ static void write_func_locals(Context* ctx, if (current_type == type) { local_type_count++; } else { - write_u32_leb128(&ctx->stream, local_type_count, "local type count"); - write_type(&ctx->stream, current_type); + write_u32_leb128(&stream_, local_type_count, "local type count"); + write_type(&stream_, current_type); local_type_count = 1; current_type = type; } } } -static void write_func(Context* ctx, const Module* module, const Func* func) { - write_func_locals(ctx, module, func, func->local_types); - write_expr_list(ctx, module, func, func->first_expr); - write_opcode(&ctx->stream, Opcode::End); +void BinaryWriter::WriteFunc(const Module* module, const Func* func) { + WriteFuncLocals(module, func, func->local_types); + WriteExprList(module, func, func->first_expr); + write_opcode(&stream_, Opcode::End); } -void write_limits(Stream* stream, const Limits* limits) { - uint32_t flags = limits->has_max ? WABT_BINARY_LIMITS_HAS_MAX_FLAG : 0; - write_u32_leb128(stream, flags, "limits: flags"); - write_u32_leb128(stream, limits->initial, "limits: initial"); - if (limits->has_max) - write_u32_leb128(stream, limits->max, "limits: max"); +void BinaryWriter::WriteTable(const Table* table) { + write_type(&stream_, Type::Anyfunc); + write_limits(&stream_, &table->elem_limits); } -static void write_table(Context* ctx, const Table* table) { - write_type(&ctx->stream, Type::Anyfunc); - write_limits(&ctx->stream, &table->elem_limits); +void BinaryWriter::WriteMemory(const Memory* memory) { + write_limits(&stream_, &memory->page_limits); } -static void write_memory(Context* ctx, const Memory* memory) { - write_limits(&ctx->stream, &memory->page_limits); +void BinaryWriter::WriteGlobalHeader(const Global* global) { + write_type(&stream_, global->type); + stream_.WriteU8(global->mutable_, "global mutability"); } -static void write_global_header(Context* ctx, const Global* global) { - write_type(&ctx->stream, global->type); - ctx->stream.WriteU8(global->mutable_, "global mutability"); -} - -static void write_reloc_section(Context* ctx, RelocSection* reloc_section) { +void BinaryWriter::WriteRelocSection(const RelocSection* reloc_section) { char section_name[128]; wabt_snprintf(section_name, sizeof(section_name), "%s.%s", - WABT_BINARY_SECTION_RELOC, reloc_section->name); - begin_custom_section(ctx, section_name, LEB_SECTION_SIZE_GUESS); - write_u32_leb128_enum(&ctx->stream, reloc_section->section_code, + WABT_BINARY_SECTION_RELOC, reloc_section->name); + BeginCustomSection(section_name, LEB_SECTION_SIZE_GUESS); + write_u32_leb128_enum(&stream_, reloc_section->section_code, "reloc section type"); - std::vector<Reloc>& relocs = reloc_section->relocations; - write_u32_leb128(&ctx->stream, relocs.size(), "num relocs"); + const std::vector<Reloc>& relocs = reloc_section->relocations; + write_u32_leb128(&stream_, relocs.size(), "num relocs"); - for (const Reloc& reloc: relocs) { - write_u32_leb128_enum(&ctx->stream, reloc.type, "reloc type"); - write_u32_leb128(&ctx->stream, reloc.offset, "reloc offset"); - write_u32_leb128(&ctx->stream, reloc.index, "reloc index"); + for (const Reloc& reloc : relocs) { + write_u32_leb128_enum(&stream_, reloc.type, "reloc type"); + write_u32_leb128(&stream_, reloc.offset, "reloc offset"); + write_u32_leb128(&stream_, reloc.index, "reloc index"); switch (reloc.type) { case RelocType::MemoryAddressLEB: case RelocType::MemoryAddressSLEB: case RelocType::MemoryAddressI32: - write_u32_leb128(&ctx->stream, reloc.addend, "reloc addend"); + write_u32_leb128(&stream_, reloc.addend, "reloc addend"); break; default: break; } } - end_section(ctx); + EndSection(); } -static Result write_module(Context* ctx, const Module* module) { - ctx->stream.WriteU32(WABT_BINARY_MAGIC, "WASM_BINARY_MAGIC"); - ctx->stream.WriteU32(WABT_BINARY_VERSION, "WASM_BINARY_VERSION"); +Result BinaryWriter::WriteModule(const Module* module) { + stream_.WriteU32(WABT_BINARY_MAGIC, "WASM_BINARY_MAGIC"); + stream_.WriteU32(WABT_BINARY_VERSION, "WASM_BINARY_VERSION"); if (module->func_types.size()) { - begin_known_section(ctx, BinarySection::Type, LEB_SECTION_SIZE_GUESS); - write_u32_leb128(&ctx->stream, module->func_types.size(), "num types"); + BeginKnownSection(BinarySection::Type, LEB_SECTION_SIZE_GUESS); + write_u32_leb128(&stream_, module->func_types.size(), "num types"); for (size_t i = 0; i < module->func_types.size(); ++i) { const FuncType* func_type = module->func_types[i]; const FuncSignature* sig = &func_type->sig; - write_header(ctx, "type", i); - write_type(&ctx->stream, Type::Func); + WriteHeader("type", i); + write_type(&stream_, Type::Func); uint32_t num_params = sig->param_types.size(); uint32_t num_results = sig->result_types.size(); - write_u32_leb128(&ctx->stream, num_params, "num params"); + write_u32_leb128(&stream_, num_params, "num params"); for (size_t j = 0; j < num_params; ++j) - write_type(&ctx->stream, sig->param_types[j]); + write_type(&stream_, sig->param_types[j]); - write_u32_leb128(&ctx->stream, num_results, "num results"); + write_u32_leb128(&stream_, num_results, "num results"); for (size_t j = 0; j < num_results; ++j) - write_type(&ctx->stream, sig->result_types[j]); + write_type(&stream_, sig->result_types[j]); } - end_section(ctx); + EndSection(); } if (module->imports.size()) { - begin_known_section(ctx, BinarySection::Import, LEB_SECTION_SIZE_GUESS); - write_u32_leb128(&ctx->stream, module->imports.size(), "num imports"); + BeginKnownSection(BinarySection::Import, LEB_SECTION_SIZE_GUESS); + write_u32_leb128(&stream_, module->imports.size(), "num imports"); for (size_t i = 0; i < module->imports.size(); ++i) { const Import* import = module->imports[i]; - write_header(ctx, "import header", i); - write_str(&ctx->stream, import->module_name.start, - import->module_name.length, "import module name", - PrintChars::Yes); - write_str(&ctx->stream, import->field_name.start, - import->field_name.length, "import field name", - PrintChars::Yes); - ctx->stream.WriteU8Enum(import->kind, "import kind"); + WriteHeader("import header", i); + write_str(&stream_, import->module_name.start, import->module_name.length, + "import module name", PrintChars::Yes); + write_str(&stream_, import->field_name.start, import->field_name.length, + "import field name", PrintChars::Yes); + stream_.WriteU8Enum(import->kind, "import kind"); switch (import->kind) { case ExternalKind::Func: - write_u32_leb128(&ctx->stream, get_func_type_index_by_decl( - module, &import->func->decl), - "import signature index"); + write_u32_leb128( + &stream_, + get_func_type_index_by_decl(module, &import->func->decl), + "import signature index"); break; case ExternalKind::Table: - write_table(ctx, import->table); + WriteTable(import->table); break; case ExternalKind::Memory: - write_memory(ctx, import->memory); + WriteMemory(import->memory); break; case ExternalKind::Global: - write_global_header(ctx, import->global); + WriteGlobalHeader(import->global); break; } } - end_section(ctx); + EndSection(); } assert(module->funcs.size() >= module->num_func_imports); uint32_t num_funcs = module->funcs.size() - module->num_func_imports; if (num_funcs) { - begin_known_section(ctx, BinarySection::Function, LEB_SECTION_SIZE_GUESS); - write_u32_leb128(&ctx->stream, num_funcs, "num functions"); + BeginKnownSection(BinarySection::Function, LEB_SECTION_SIZE_GUESS); + write_u32_leb128(&stream_, num_funcs, "num functions"); for (size_t i = 0; i < num_funcs; ++i) { const Func* func = module->funcs[i + module->num_func_imports]; char desc[100]; wabt_snprintf(desc, sizeof(desc), "function %" PRIzd " signature index", i); - write_u32_leb128(&ctx->stream, + write_u32_leb128(&stream_, get_func_type_index_by_decl(module, &func->decl), desc); } - end_section(ctx); + EndSection(); } assert(module->tables.size() >= module->num_table_imports); uint32_t num_tables = module->tables.size() - module->num_table_imports; if (num_tables) { - begin_known_section(ctx, BinarySection::Table, LEB_SECTION_SIZE_GUESS); - write_u32_leb128(&ctx->stream, num_tables, "num tables"); + BeginKnownSection(BinarySection::Table, LEB_SECTION_SIZE_GUESS); + write_u32_leb128(&stream_, num_tables, "num tables"); for (size_t i = 0; i < num_tables; ++i) { const Table* table = module->tables[i + module->num_table_imports]; - write_header(ctx, "table", i); - write_table(ctx, table); + WriteHeader("table", i); + WriteTable(table); } - end_section(ctx); + EndSection(); } assert(module->memories.size() >= module->num_memory_imports); uint32_t num_memories = module->memories.size() - module->num_memory_imports; if (num_memories) { - begin_known_section(ctx, BinarySection::Memory, LEB_SECTION_SIZE_GUESS); - write_u32_leb128(&ctx->stream, num_memories, "num memories"); + BeginKnownSection(BinarySection::Memory, LEB_SECTION_SIZE_GUESS); + write_u32_leb128(&stream_, num_memories, "num memories"); for (size_t i = 0; i < num_memories; ++i) { const Memory* memory = module->memories[i + module->num_memory_imports]; - write_header(ctx, "memory", i); - write_memory(ctx, memory); + WriteHeader("memory", i); + WriteMemory(memory); } - end_section(ctx); + EndSection(); } assert(module->globals.size() >= module->num_global_imports); uint32_t num_globals = module->globals.size() - module->num_global_imports; if (num_globals) { - begin_known_section(ctx, BinarySection::Global, LEB_SECTION_SIZE_GUESS); - write_u32_leb128(&ctx->stream, num_globals, "num globals"); + BeginKnownSection(BinarySection::Global, LEB_SECTION_SIZE_GUESS); + write_u32_leb128(&stream_, num_globals, "num globals"); for (size_t i = 0; i < num_globals; ++i) { const Global* global = module->globals[i + module->num_global_imports]; - write_global_header(ctx, global); - write_init_expr(ctx, module, global->init_expr); + WriteGlobalHeader(global); + WriteInitExpr(module, global->init_expr); } - end_section(ctx); + EndSection(); } if (module->exports.size()) { - begin_known_section(ctx, BinarySection::Export, LEB_SECTION_SIZE_GUESS); - write_u32_leb128(&ctx->stream, module->exports.size(), "num exports"); + BeginKnownSection(BinarySection::Export, LEB_SECTION_SIZE_GUESS); + write_u32_leb128(&stream_, module->exports.size(), "num exports"); for (const Export* export_ : module->exports) { - write_str(&ctx->stream, export_->name.start, export_->name.length, + write_str(&stream_, export_->name.start, export_->name.length, "export name", PrintChars::Yes); - ctx->stream.WriteU8Enum(export_->kind, "export kind"); + stream_.WriteU8Enum(export_->kind, "export kind"); switch (export_->kind) { case ExternalKind::Func: { int index = get_func_index_by_var(module, &export_->var); - write_u32_leb128(&ctx->stream, index, "export func index"); + write_u32_leb128(&stream_, index, "export func index"); break; } case ExternalKind::Table: { int index = get_table_index_by_var(module, &export_->var); - write_u32_leb128(&ctx->stream, index, "export table index"); + write_u32_leb128(&stream_, index, "export table index"); break; } case ExternalKind::Memory: { int index = get_memory_index_by_var(module, &export_->var); - write_u32_leb128(&ctx->stream, index, "export memory index"); + write_u32_leb128(&stream_, index, "export memory index"); break; } case ExternalKind::Global: { int index = get_global_index_by_var(module, &export_->var); - write_u32_leb128(&ctx->stream, index, "export global index"); + write_u32_leb128(&stream_, index, "export global index"); break; } } } - end_section(ctx); + EndSection(); } if (module->start) { int start_func_index = get_func_index_by_var(module, module->start); if (start_func_index != -1) { - begin_known_section(ctx, BinarySection::Start, LEB_SECTION_SIZE_GUESS); - write_u32_leb128(&ctx->stream, start_func_index, "start func index"); - end_section(ctx); + BeginKnownSection(BinarySection::Start, LEB_SECTION_SIZE_GUESS); + write_u32_leb128(&stream_, start_func_index, "start func index"); + EndSection(); } } if (module->elem_segments.size()) { - begin_known_section(ctx, BinarySection::Elem, LEB_SECTION_SIZE_GUESS); - write_u32_leb128(&ctx->stream, module->elem_segments.size(), + BeginKnownSection(BinarySection::Elem, LEB_SECTION_SIZE_GUESS); + write_u32_leb128(&stream_, module->elem_segments.size(), "num elem segments"); for (size_t i = 0; i < module->elem_segments.size(); ++i) { ElemSegment* segment = module->elem_segments[i]; int table_index = get_table_index_by_var(module, &segment->table_var); - write_header(ctx, "elem segment header", i); - write_u32_leb128(&ctx->stream, table_index, "table index"); - write_init_expr(ctx, module, segment->offset); - write_u32_leb128(&ctx->stream, segment->vars.size(), - "num function indices"); - for (const Var& var: segment->vars) { + WriteHeader("elem segment header", i); + write_u32_leb128(&stream_, table_index, "table index"); + WriteInitExpr(module, segment->offset); + write_u32_leb128(&stream_, segment->vars.size(), "num function indices"); + for (const Var& var : segment->vars) { int index = get_func_index_by_var(module, &var); - write_u32_leb128_with_reloc(ctx, index, "function index", - RelocType::FuncIndexLEB); + WriteU32Leb128WithReloc(index, "function index", + RelocType::FuncIndexLEB); } } - end_section(ctx); + EndSection(); } if (num_funcs) { - begin_known_section(ctx, BinarySection::Code, LEB_SECTION_SIZE_GUESS); - write_u32_leb128(&ctx->stream, num_funcs, "num functions"); + BeginKnownSection(BinarySection::Code, LEB_SECTION_SIZE_GUESS); + write_u32_leb128(&stream_, num_funcs, "num functions"); for (size_t i = 0; i < num_funcs; ++i) { - write_header(ctx, "function body", i); + WriteHeader("function body", i); const Func* func = module->funcs[i + module->num_func_imports]; /* TODO(binji): better guess of the size of the function body section */ const uint32_t leb_size_guess = 1; uint32_t body_size_offset = - write_u32_leb128_space(ctx, leb_size_guess, "func body size (guess)"); - write_func(ctx, module, func); - write_fixup_u32_leb128_size(ctx, body_size_offset, leb_size_guess, - "FIXUP func body size"); + WriteU32Leb128Space(leb_size_guess, "func body size (guess)"); + WriteFunc(module, func); + WriteFixupU32Leb128Size(body_size_offset, leb_size_guess, + "FIXUP func body size"); } - end_section(ctx); + EndSection(); } if (module->data_segments.size()) { - begin_known_section(ctx, BinarySection::Data, LEB_SECTION_SIZE_GUESS); - write_u32_leb128(&ctx->stream, module->data_segments.size(), + BeginKnownSection(BinarySection::Data, LEB_SECTION_SIZE_GUESS); + write_u32_leb128(&stream_, module->data_segments.size(), "num data segments"); for (size_t i = 0; i < module->data_segments.size(); ++i) { const DataSegment* segment = module->data_segments[i]; - write_header(ctx, "data segment header", i); + WriteHeader("data segment header", i); int memory_index = get_memory_index_by_var(module, &segment->memory_var); - write_u32_leb128(&ctx->stream, memory_index, "memory index"); - write_init_expr(ctx, module, segment->offset); - write_u32_leb128(&ctx->stream, segment->size, "data segment size"); - write_header(ctx, "data segment data", i); - ctx->stream.WriteData(segment->data, segment->size, "data segment data"); + write_u32_leb128(&stream_, memory_index, "memory index"); + WriteInitExpr(module, segment->offset); + write_u32_leb128(&stream_, segment->size, "data segment size"); + WriteHeader("data segment data", i); + stream_.WriteData(segment->data, segment->size, "data segment data"); } - end_section(ctx); + EndSection(); } - if (ctx->options->write_debug_names) { + if (options_->write_debug_names) { std::vector<std::string> index_to_name; char desc[100]; - begin_custom_section(ctx, WABT_BINARY_SECTION_NAME, LEB_SECTION_SIZE_GUESS); + BeginCustomSection(WABT_BINARY_SECTION_NAME, LEB_SECTION_SIZE_GUESS); size_t named_functions = 0; - for (const Func* func: module->funcs) { + for (const Func* func : module->funcs) { if (func->name.length > 0) named_functions++; } if (named_functions > 0) { - write_u32_leb128(&ctx->stream, 1, "function name type"); - begin_subsection(ctx, "function name subsection", LEB_SECTION_SIZE_GUESS); + write_u32_leb128(&stream_, 1, "function name type"); + BeginSubsection("function name subsection", LEB_SECTION_SIZE_GUESS); - write_u32_leb128(&ctx->stream, named_functions, "num functions"); + write_u32_leb128(&stream_, named_functions, "num functions"); for (size_t i = 0; i < module->funcs.size(); ++i) { const Func* func = module->funcs[i]; if (func->name.length == 0) continue; - write_u32_leb128(&ctx->stream, i, "function index"); + write_u32_leb128(&stream_, i, "function index"); wabt_snprintf(desc, sizeof(desc), "func name %" PRIzd, i); - write_str(&ctx->stream, func->name.start, func->name.length, desc, + write_str(&stream_, func->name.start, func->name.length, desc, PrintChars::Yes); } - end_subsection(ctx); + EndSubsection(); } - write_u32_leb128(&ctx->stream, 2, "local name type"); + write_u32_leb128(&stream_, 2, "local name type"); - begin_subsection(ctx, "local name subsection", LEB_SECTION_SIZE_GUESS); - write_u32_leb128(&ctx->stream, module->funcs.size(), "num functions"); + BeginSubsection("local name subsection", LEB_SECTION_SIZE_GUESS); + write_u32_leb128(&stream_, module->funcs.size(), "num functions"); for (size_t i = 0; i < module->funcs.size(); ++i) { const Func* func = module->funcs[i]; uint32_t num_params = get_num_params(func); uint32_t num_locals = func->local_types.size(); uint32_t num_params_and_locals = get_num_params_and_locals(func); - write_u32_leb128(&ctx->stream, i, "function index"); - write_u32_leb128(&ctx->stream, num_params_and_locals, "num locals"); + write_u32_leb128(&stream_, i, "function index"); + write_u32_leb128(&stream_, num_params_and_locals, "num locals"); make_type_binding_reverse_mapping(func->decl.sig.param_types, func->param_bindings, &index_to_name); for (size_t j = 0; j < num_params; ++j) { 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(), desc, - PrintChars::Yes); + write_u32_leb128(&stream_, j, "local index"); + write_str(&stream_, name.data(), name.length(), desc, PrintChars::Yes); } make_type_binding_reverse_mapping(func->local_types, func->local_bindings, @@ -924,29 +924,30 @@ static Result write_module(Context* ctx, const Module* module) { for (size_t j = 0; j < num_locals; ++j) { 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(), desc, - PrintChars::Yes); + write_u32_leb128(&stream_, num_params + j, "local index"); + write_str(&stream_, name.data(), name.length(), desc, PrintChars::Yes); } } - end_subsection(ctx); - end_section(ctx); + EndSubsection(); + EndSection(); } - if (ctx->options->relocatable) { - for (size_t i = 0; i < ctx->reloc_sections.size(); i++) { - write_reloc_section(ctx, &ctx->reloc_sections[i]); + if (options_->relocatable) { + for (RelocSection& section : reloc_sections_) { + WriteRelocSection(§ion); } } - return ctx->stream.result(); + return stream_.result(); } +} // namespace + Result write_binary_module(Writer* writer, const Module* module, const WriteBinaryOptions* options) { - Context ctx(writer, options); - return write_module(&ctx, module); + BinaryWriter binary_writer(writer, options); + return binary_writer.WriteModule(module); } } // namespace wabt |