summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast-writer.cc706
-rw-r--r--src/binary-writer-spec.cc456
-rw-r--r--src/binary-writer.cc901
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(&section);
}
}
- 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