1 /*
2 * Copyright 2016 WebAssembly Community Group participants
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/wat-writer.h"
18
19 #include <algorithm>
20 #include <array>
21 #include <cassert>
22 #include <cinttypes>
23 #include <cstdarg>
24 #include <cstdio>
25 #include <iterator>
26 #include <map>
27 #include <string>
28 #include <vector>
29
30 #include "src/cast.h"
31 #include "src/common.h"
32 #include "src/expr-visitor.h"
33 #include "src/ir.h"
34 #include "src/literal.h"
35 #include "src/stream.h"
36
37 #define WABT_TRACING 0
38 #include "src/tracing.h"
39
40 #define INDENT_SIZE 2
41 #define NO_FORCE_NEWLINE 0
42 #define FORCE_NEWLINE 1
43
44 namespace wabt {
45
46 namespace {
47
48 static const uint8_t s_is_char_escaped[] = {
49 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
50 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
53 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
54 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
57 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
58 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
59 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
60
61 // This table matches the characters allowed by wast-lexer.cc for `symbol`.
62 // The disallowed printable characters are: "(),;[]{} and <space>.
63 static const uint8_t s_valid_name_chars[256] = {
64 // 0 1 2 3 4 5 6 7 8 9 a b c d e f
65 /* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
66 /* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
67 /* 0x20 */ 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1,
68 /* 0x30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
69 /* 0x40 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
70 /* 0x50 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1,
71 /* 0x60 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
72 /* 0x70 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
73 };
74
75 enum class NextChar {
76 None,
77 Space,
78 Newline,
79 ForceNewline,
80 };
81
82 struct ExprTree {
ExprTreewabt::__anonf2fd58e90111::ExprTree83 explicit ExprTree(const Expr* expr, Index result_count)
84 : expr(expr), result_count(result_count) {}
85
86 const Expr* expr;
87 std::vector<ExprTree> children;
88 Index result_count;
89 };
90
91 struct Label {
Labelwabt::__anonf2fd58e90111::Label92 Label(LabelType label_type,
93 const std::string& name,
94 const TypeVector& param_types,
95 const TypeVector& result_types)
96 : name(name),
97 label_type(label_type),
98 param_types(param_types),
99 result_types(result_types) {}
100
101 std::string name;
102 LabelType label_type;
103 TypeVector param_types;
104 TypeVector result_types;
105 };
106
107 class WatWriter {
108 public:
WatWriter(Stream * stream,const WriteWatOptions & options)109 WatWriter(Stream* stream, const WriteWatOptions& options)
110 : options_(options), stream_(stream) {}
111
112 Result WriteModule(const Module& module);
113
114 private:
115 void Indent();
116 void Dedent();
117 void WriteIndent();
118 void WriteNextChar();
119 void WriteDataWithNextChar(const void* src, size_t size);
120 void Writef(const char* format, ...);
121 void WritePutc(char c);
122 void WritePuts(const char* s, NextChar next_char);
123 void WritePutsSpace(const char* s);
124 void WritePutsNewline(const char* s);
125 void WriteNewline(bool force);
126 void WriteOpen(const char* name, NextChar next_char);
127 void WriteOpenNewline(const char* name);
128 void WriteOpenSpace(const char* name);
129 void WriteClose(NextChar next_char);
130 void WriteCloseNewline();
131 void WriteCloseSpace();
132 void WriteString(const std::string& str, NextChar next_char);
133 void WriteName(string_view str, NextChar next_char);
134 void WriteNameOrIndex(string_view str, Index index, NextChar next_char);
135 void WriteQuotedData(const void* data, size_t length);
136 void WriteQuotedString(string_view str, NextChar next_char);
137 void WriteVar(const Var& var, NextChar next_char);
138 void WriteBrVar(const Var& var, NextChar next_char);
139 void WriteType(Type type, NextChar next_char);
140 void WriteTypes(const TypeVector& types, const char* name);
141 void WriteFuncSigSpace(const FuncSignature& func_sig);
142 void WriteBeginBlock(LabelType label_type,
143 const Block& block,
144 const char* text);
145 void WriteEndBlock();
146 void WriteConst(const Const& const_);
147 void WriteExpr(const Expr* expr);
148 template <typename T>
149 void WriteLoadStoreExpr(const Expr* expr);
150 void WriteExprList(const ExprList& exprs);
151 void WriteInitExpr(const ExprList& expr);
152 template <typename T>
153 void WriteTypeBindings(const char* prefix,
154 const T& types,
155 const std::vector<std::string>& index_to_name,
156 Index binding_index_offset = 0);
157 void WriteBeginFunc(const Func& func);
158 void WriteFunc(const Func& func);
159 void WriteBeginGlobal(const Global& global);
160 void WriteGlobal(const Global& global);
161 void WriteEvent(const Event& event);
162 void WriteLimits(const Limits& limits);
163 void WriteTable(const Table& table);
164 void WriteElemSegment(const ElemSegment& segment);
165 void WriteMemory(const Memory& memory);
166 void WriteDataSegment(const DataSegment& segment);
167 void WriteImport(const Import& import);
168 void WriteExport(const Export& export_);
169 void WriteFuncType(const FuncType& func_type);
170 void WriteStartFunction(const Var& start);
171
172 class ExprVisitorDelegate;
173
GetLabelStackSize()174 Index GetLabelStackSize() { return label_stack_.size(); }
175 Label* GetLabel(const Var& var);
176 Index GetLabelArity(const Var& var);
177 Index GetFuncParamCount(const Var& var);
178 Index GetFuncResultCount(const Var& var);
179 void PushExpr(const Expr* expr, Index operand_count, Index result_count);
180 void FlushExprTree(const ExprTree& expr_tree);
181 void FlushExprTreeVector(const std::vector<ExprTree>&);
182 void FlushExprTreeStack();
183 void WriteFoldedExpr(const Expr*);
184 void WriteFoldedExprList(const ExprList&);
185
186 void BuildInlineExportMap();
187 void WriteInlineExports(ExternalKind, Index);
188 bool IsInlineExport(const Export& export_);
189 void BuildInlineImportMap();
190 void WriteInlineImport(ExternalKind, Index);
191
192 const WriteWatOptions& options_;
193 const Module* module_ = nullptr;
194 const Func* current_func_ = nullptr;
195 Stream* stream_ = nullptr;
196 Result result_ = Result::Ok;
197 int indent_ = 0;
198 NextChar next_char_ = NextChar::None;
199 std::vector<Label> label_stack_;
200 std::vector<ExprTree> expr_tree_stack_;
201 std::multimap<std::pair<ExternalKind, Index>, const Export*>
202 inline_export_map_;
203 std::vector<const Import*> inline_import_map_[kExternalKindCount];
204
205 Index func_index_ = 0;
206 Index global_index_ = 0;
207 Index table_index_ = 0;
208 Index memory_index_ = 0;
209 Index func_type_index_ = 0;
210 Index event_index_ = 0;
211 Index data_segment_index_ = 0;
212 Index elem_segment_index_ = 0;
213 };
214
Indent()215 void WatWriter::Indent() {
216 indent_ += INDENT_SIZE;
217 }
218
Dedent()219 void WatWriter::Dedent() {
220 indent_ -= INDENT_SIZE;
221 assert(indent_ >= 0);
222 }
223
WriteIndent()224 void WatWriter::WriteIndent() {
225 static char s_indent[] =
226 " "
227 " ";
228 static size_t s_indent_len = sizeof(s_indent) - 1;
229 size_t to_write = indent_;
230 while (to_write >= s_indent_len) {
231 stream_->WriteData(s_indent, s_indent_len);
232 to_write -= s_indent_len;
233 }
234 if (to_write > 0) {
235 stream_->WriteData(s_indent, to_write);
236 }
237 }
238
WriteNextChar()239 void WatWriter::WriteNextChar() {
240 switch (next_char_) {
241 case NextChar::Space:
242 stream_->WriteChar(' ');
243 break;
244 case NextChar::Newline:
245 case NextChar::ForceNewline:
246 stream_->WriteChar('\n');
247 WriteIndent();
248 break;
249 case NextChar::None:
250 break;
251 }
252 next_char_ = NextChar::None;
253 }
254
WriteDataWithNextChar(const void * src,size_t size)255 void WatWriter::WriteDataWithNextChar(const void* src, size_t size) {
256 WriteNextChar();
257 stream_->WriteData(src, size);
258 }
259
Writef(const char * format,...)260 void WABT_PRINTF_FORMAT(2, 3) WatWriter::Writef(const char* format, ...) {
261 WABT_SNPRINTF_ALLOCA(buffer, length, format);
262 /* default to following space */
263 WriteDataWithNextChar(buffer, length);
264 next_char_ = NextChar::Space;
265 }
266
WritePutc(char c)267 void WatWriter::WritePutc(char c) {
268 stream_->WriteChar(c);
269 }
270
WritePuts(const char * s,NextChar next_char)271 void WatWriter::WritePuts(const char* s, NextChar next_char) {
272 size_t len = strlen(s);
273 WriteDataWithNextChar(s, len);
274 next_char_ = next_char;
275 }
276
WritePutsSpace(const char * s)277 void WatWriter::WritePutsSpace(const char* s) {
278 WritePuts(s, NextChar::Space);
279 }
280
WritePutsNewline(const char * s)281 void WatWriter::WritePutsNewline(const char* s) {
282 WritePuts(s, NextChar::Newline);
283 }
284
WriteNewline(bool force)285 void WatWriter::WriteNewline(bool force) {
286 if (next_char_ == NextChar::ForceNewline) {
287 WriteNextChar();
288 }
289 next_char_ = force ? NextChar::ForceNewline : NextChar::Newline;
290 }
291
WriteOpen(const char * name,NextChar next_char)292 void WatWriter::WriteOpen(const char* name, NextChar next_char) {
293 WritePuts("(", NextChar::None);
294 WritePuts(name, next_char);
295 Indent();
296 }
297
WriteOpenNewline(const char * name)298 void WatWriter::WriteOpenNewline(const char* name) {
299 WriteOpen(name, NextChar::Newline);
300 }
301
WriteOpenSpace(const char * name)302 void WatWriter::WriteOpenSpace(const char* name) {
303 WriteOpen(name, NextChar::Space);
304 }
305
WriteClose(NextChar next_char)306 void WatWriter::WriteClose(NextChar next_char) {
307 if (next_char_ != NextChar::ForceNewline) {
308 next_char_ = NextChar::None;
309 }
310 Dedent();
311 WritePuts(")", next_char);
312 }
313
WriteCloseNewline()314 void WatWriter::WriteCloseNewline() {
315 WriteClose(NextChar::Newline);
316 }
317
WriteCloseSpace()318 void WatWriter::WriteCloseSpace() {
319 WriteClose(NextChar::Space);
320 }
321
WriteString(const std::string & str,NextChar next_char)322 void WatWriter::WriteString(const std::string& str, NextChar next_char) {
323 WritePuts(str.c_str(), next_char);
324 }
325
WriteName(string_view str,NextChar next_char)326 void WatWriter::WriteName(string_view str, NextChar next_char) {
327 // Debug names must begin with a $ for for wast file to be valid
328 assert(!str.empty() && str.front() == '$');
329 bool has_invalid_chars = std::any_of(
330 str.begin(), str.end(), [](uint8_t c) { return !s_valid_name_chars[c]; });
331
332 if (has_invalid_chars) {
333 std::string valid_str;
334 std::transform(str.begin(), str.end(), std::back_inserter(valid_str),
335 [](uint8_t c) { return s_valid_name_chars[c] ? c : '_'; });
336 WriteDataWithNextChar(valid_str.data(), valid_str.length());
337 } else {
338 WriteDataWithNextChar(str.data(), str.length());
339 }
340
341 next_char_ = next_char;
342 }
343
WriteNameOrIndex(string_view str,Index index,NextChar next_char)344 void WatWriter::WriteNameOrIndex(string_view str,
345 Index index,
346 NextChar next_char) {
347 if (!str.empty()) {
348 WriteName(str, next_char);
349 } else {
350 Writef("(;%u;)", index);
351 }
352 }
353
WriteQuotedData(const void * data,size_t length)354 void WatWriter::WriteQuotedData(const void* data, size_t length) {
355 const uint8_t* u8_data = static_cast<const uint8_t*>(data);
356 static const char s_hexdigits[] = "0123456789abcdef";
357 WriteNextChar();
358 WritePutc('\"');
359 for (size_t i = 0; i < length; ++i) {
360 uint8_t c = u8_data[i];
361 if (s_is_char_escaped[c]) {
362 WritePutc('\\');
363 WritePutc(s_hexdigits[c >> 4]);
364 WritePutc(s_hexdigits[c & 0xf]);
365 } else {
366 WritePutc(c);
367 }
368 }
369 WritePutc('\"');
370 next_char_ = NextChar::Space;
371 }
372
WriteQuotedString(string_view str,NextChar next_char)373 void WatWriter::WriteQuotedString(string_view str, NextChar next_char) {
374 WriteQuotedData(str.data(), str.length());
375 next_char_ = next_char;
376 }
377
WriteVar(const Var & var,NextChar next_char)378 void WatWriter::WriteVar(const Var& var, NextChar next_char) {
379 if (var.is_index()) {
380 Writef("%" PRIindex, var.index());
381 next_char_ = next_char;
382 } else {
383 WriteName(var.name(), next_char);
384 }
385 }
386
WriteBrVar(const Var & var,NextChar next_char)387 void WatWriter::WriteBrVar(const Var& var, NextChar next_char) {
388 if (var.is_index()) {
389 if (var.index() < GetLabelStackSize()) {
390 Writef("%" PRIindex " (;@%" PRIindex ";)", var.index(),
391 GetLabelStackSize() - var.index() - 1);
392 } else {
393 Writef("%" PRIindex " (; INVALID ;)", var.index());
394 }
395 next_char_ = next_char;
396 } else {
397 WriteString(var.name(), next_char);
398 }
399 }
400
WriteType(Type type,NextChar next_char)401 void WatWriter::WriteType(Type type, NextChar next_char) {
402 const char* type_name = GetTypeName(type);
403 assert(type_name);
404 WritePuts(type_name, next_char);
405 }
406
WriteTypes(const TypeVector & types,const char * name)407 void WatWriter::WriteTypes(const TypeVector& types, const char* name) {
408 if (types.size()) {
409 if (name) {
410 WriteOpenSpace(name);
411 }
412 for (Type type : types) {
413 WriteType(type, NextChar::Space);
414 }
415 if (name) {
416 WriteCloseSpace();
417 }
418 }
419 }
420
WriteFuncSigSpace(const FuncSignature & func_sig)421 void WatWriter::WriteFuncSigSpace(const FuncSignature& func_sig) {
422 WriteTypes(func_sig.param_types, "param");
423 WriteTypes(func_sig.result_types, "result");
424 }
425
WriteBeginBlock(LabelType label_type,const Block & block,const char * text)426 void WatWriter::WriteBeginBlock(LabelType label_type,
427 const Block& block,
428 const char* text) {
429 WritePutsSpace(text);
430 bool has_label = !block.label.empty();
431 if (has_label) {
432 WriteString(block.label, NextChar::Space);
433 }
434 WriteTypes(block.decl.sig.param_types, "param");
435 WriteTypes(block.decl.sig.result_types, "result");
436 if (!has_label) {
437 Writef(" ;; label = @%" PRIindex, GetLabelStackSize());
438 }
439 WriteNewline(FORCE_NEWLINE);
440 label_stack_.emplace_back(label_type, block.label, block.decl.sig.param_types,
441 block.decl.sig.result_types);
442 Indent();
443 }
444
WriteEndBlock()445 void WatWriter::WriteEndBlock() {
446 Dedent();
447 label_stack_.pop_back();
448 WritePutsNewline(Opcode::End_Opcode.GetName());
449 }
450
WriteConst(const Const & const_)451 void WatWriter::WriteConst(const Const& const_) {
452 switch (const_.type) {
453 case Type::I32:
454 WritePutsSpace(Opcode::I32Const_Opcode.GetName());
455 Writef("%d", static_cast<int32_t>(const_.u32));
456 WriteNewline(NO_FORCE_NEWLINE);
457 break;
458
459 case Type::I64:
460 WritePutsSpace(Opcode::I64Const_Opcode.GetName());
461 Writef("%" PRId64, static_cast<int64_t>(const_.u64));
462 WriteNewline(NO_FORCE_NEWLINE);
463 break;
464
465 case Type::F32: {
466 WritePutsSpace(Opcode::F32Const_Opcode.GetName());
467 char buffer[128];
468 WriteFloatHex(buffer, 128, const_.f32_bits);
469 WritePutsSpace(buffer);
470 float f32;
471 memcpy(&f32, &const_.f32_bits, sizeof(f32));
472 Writef("(;=%g;)", f32);
473 WriteNewline(NO_FORCE_NEWLINE);
474 break;
475 }
476
477 case Type::F64: {
478 WritePutsSpace(Opcode::F64Const_Opcode.GetName());
479 char buffer[128];
480 WriteDoubleHex(buffer, 128, const_.f64_bits);
481 WritePutsSpace(buffer);
482 double f64;
483 memcpy(&f64, &const_.f64_bits, sizeof(f64));
484 Writef("(;=%g;)", f64);
485 WriteNewline(NO_FORCE_NEWLINE);
486 break;
487 }
488
489 case Type::V128: {
490 WritePutsSpace(Opcode::V128Const_Opcode.GetName());
491 Writef("i32x4 0x%08x 0x%08x 0x%08x 0x%08x", const_.v128_bits.v[0],
492 const_.v128_bits.v[1], const_.v128_bits.v[2],
493 const_.v128_bits.v[3]);
494 WriteNewline(NO_FORCE_NEWLINE);
495 break;
496 }
497
498 default:
499 assert(0);
500 break;
501 }
502 }
503
504 template <typename T>
WriteLoadStoreExpr(const Expr * expr)505 void WatWriter::WriteLoadStoreExpr(const Expr* expr) {
506 auto typed_expr = cast<T>(expr);
507 WritePutsSpace(typed_expr->opcode.GetName());
508 if (typed_expr->offset) {
509 Writef("offset=%u", typed_expr->offset);
510 }
511 if (!typed_expr->opcode.IsNaturallyAligned(typed_expr->align)) {
512 Writef("align=%u", typed_expr->align);
513 }
514 WriteNewline(NO_FORCE_NEWLINE);
515 }
516
517 class WatWriter::ExprVisitorDelegate : public ExprVisitor::Delegate {
518 public:
ExprVisitorDelegate(WatWriter * writer)519 explicit ExprVisitorDelegate(WatWriter* writer) : writer_(writer) {}
520
521 Result OnBinaryExpr(BinaryExpr*) override;
522 Result BeginBlockExpr(BlockExpr*) override;
523 Result EndBlockExpr(BlockExpr*) override;
524 Result OnBrExpr(BrExpr*) override;
525 Result OnBrIfExpr(BrIfExpr*) override;
526 Result OnBrOnExnExpr(BrOnExnExpr*) override;
527 Result OnBrTableExpr(BrTableExpr*) override;
528 Result OnCallExpr(CallExpr*) override;
529 Result OnCallIndirectExpr(CallIndirectExpr*) override;
530 Result OnCompareExpr(CompareExpr*) override;
531 Result OnConstExpr(ConstExpr*) override;
532 Result OnConvertExpr(ConvertExpr*) override;
533 Result OnDropExpr(DropExpr*) override;
534 Result OnGlobalGetExpr(GlobalGetExpr*) override;
535 Result OnGlobalSetExpr(GlobalSetExpr*) override;
536 Result BeginIfExpr(IfExpr*) override;
537 Result AfterIfTrueExpr(IfExpr*) override;
538 Result EndIfExpr(IfExpr*) override;
539 Result OnLoadExpr(LoadExpr*) override;
540 Result OnLocalGetExpr(LocalGetExpr*) override;
541 Result OnLocalSetExpr(LocalSetExpr*) override;
542 Result OnLocalTeeExpr(LocalTeeExpr*) override;
543 Result BeginLoopExpr(LoopExpr*) override;
544 Result EndLoopExpr(LoopExpr*) override;
545 Result OnMemoryCopyExpr(MemoryCopyExpr*) override;
546 Result OnDataDropExpr(DataDropExpr*) override;
547 Result OnMemoryFillExpr(MemoryFillExpr*) override;
548 Result OnMemoryGrowExpr(MemoryGrowExpr*) override;
549 Result OnMemoryInitExpr(MemoryInitExpr*) override;
550 Result OnMemorySizeExpr(MemorySizeExpr*) override;
551 Result OnTableCopyExpr(TableCopyExpr*) override;
552 Result OnElemDropExpr(ElemDropExpr*) override;
553 Result OnTableInitExpr(TableInitExpr*) override;
554 Result OnTableGetExpr(TableGetExpr*) override;
555 Result OnTableSetExpr(TableSetExpr*) override;
556 Result OnTableGrowExpr(TableGrowExpr*) override;
557 Result OnTableSizeExpr(TableSizeExpr*) override;
558 Result OnRefNullExpr(RefNullExpr*) override;
559 Result OnRefIsNullExpr(RefIsNullExpr*) override;
560 Result OnNopExpr(NopExpr*) override;
561 Result OnReturnExpr(ReturnExpr*) override;
562 Result OnReturnCallExpr(ReturnCallExpr*) override;
563 Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr*) override;
564 Result OnSelectExpr(SelectExpr*) override;
565 Result OnStoreExpr(StoreExpr*) override;
566 Result OnUnaryExpr(UnaryExpr*) override;
567 Result OnUnreachableExpr(UnreachableExpr*) override;
568 Result BeginTryExpr(TryExpr*) override;
569 Result OnCatchExpr(TryExpr*) override;
570 Result EndTryExpr(TryExpr*) override;
571 Result OnThrowExpr(ThrowExpr*) override;
572 Result OnRethrowExpr(RethrowExpr*) override;
573 Result OnAtomicWaitExpr(AtomicWaitExpr*) override;
574 Result OnAtomicNotifyExpr(AtomicNotifyExpr*) override;
575 Result OnAtomicLoadExpr(AtomicLoadExpr*) override;
576 Result OnAtomicStoreExpr(AtomicStoreExpr*) override;
577 Result OnAtomicRmwExpr(AtomicRmwExpr*) override;
578 Result OnAtomicRmwCmpxchgExpr(AtomicRmwCmpxchgExpr*) override;
579 Result OnTernaryExpr(TernaryExpr*) override;
580 Result OnSimdLaneOpExpr(SimdLaneOpExpr*) override;
581 Result OnSimdShuffleOpExpr(SimdShuffleOpExpr*) override;
582 Result OnLoadSplatExpr(LoadSplatExpr*) override;
583
584 private:
585 WatWriter* writer_;
586 };
587
OnBinaryExpr(BinaryExpr * expr)588 Result WatWriter::ExprVisitorDelegate::OnBinaryExpr(BinaryExpr* expr) {
589 writer_->WritePutsNewline(expr->opcode.GetName());
590 return Result::Ok;
591 }
592
BeginBlockExpr(BlockExpr * expr)593 Result WatWriter::ExprVisitorDelegate::BeginBlockExpr(BlockExpr* expr) {
594 writer_->WriteBeginBlock(LabelType::Block, expr->block,
595 Opcode::Block_Opcode.GetName());
596 return Result::Ok;
597 }
598
EndBlockExpr(BlockExpr * expr)599 Result WatWriter::ExprVisitorDelegate::EndBlockExpr(BlockExpr* expr) {
600 writer_->WriteEndBlock();
601 return Result::Ok;
602 }
603
OnBrExpr(BrExpr * expr)604 Result WatWriter::ExprVisitorDelegate::OnBrExpr(BrExpr* expr) {
605 writer_->WritePutsSpace(Opcode::Br_Opcode.GetName());
606 writer_->WriteBrVar(expr->var, NextChar::Newline);
607 return Result::Ok;
608 }
609
OnBrIfExpr(BrIfExpr * expr)610 Result WatWriter::ExprVisitorDelegate::OnBrIfExpr(BrIfExpr* expr) {
611 writer_->WritePutsSpace(Opcode::BrIf_Opcode.GetName());
612 writer_->WriteBrVar(expr->var, NextChar::Newline);
613 return Result::Ok;
614 }
615
OnBrOnExnExpr(BrOnExnExpr * expr)616 Result WatWriter::ExprVisitorDelegate::OnBrOnExnExpr(BrOnExnExpr* expr) {
617 writer_->WritePutsSpace(Opcode::BrOnExn_Opcode.GetName());
618 writer_->WriteBrVar(expr->label_var, NextChar::Space);
619 writer_->WriteVar(expr->event_var, NextChar::Newline);
620 return Result::Ok;
621 }
622
OnBrTableExpr(BrTableExpr * expr)623 Result WatWriter::ExprVisitorDelegate::OnBrTableExpr(BrTableExpr* expr) {
624 writer_->WritePutsSpace(Opcode::BrTable_Opcode.GetName());
625 for (const Var& var : expr->targets) {
626 writer_->WriteBrVar(var, NextChar::Space);
627 }
628 writer_->WriteBrVar(expr->default_target, NextChar::Newline);
629 return Result::Ok;
630 }
631
OnCallExpr(CallExpr * expr)632 Result WatWriter::ExprVisitorDelegate::OnCallExpr(CallExpr* expr) {
633 writer_->WritePutsSpace(Opcode::Call_Opcode.GetName());
634 writer_->WriteVar(expr->var, NextChar::Newline);
635 return Result::Ok;
636 }
637
OnCallIndirectExpr(CallIndirectExpr * expr)638 Result WatWriter::ExprVisitorDelegate::OnCallIndirectExpr(
639 CallIndirectExpr* expr) {
640 writer_->WritePutsSpace(Opcode::CallIndirect_Opcode.GetName());
641 writer_->WriteOpenSpace("type");
642 writer_->WriteVar(expr->decl.type_var, NextChar::Space);
643
644 if (expr->table.is_index() && expr->table.index() == 0) {
645 writer_->WriteCloseNewline();
646 } else {
647 writer_->WriteCloseSpace();
648 writer_->WriteVar(expr->table, NextChar::Newline);
649 }
650 return Result::Ok;
651 }
652
OnCompareExpr(CompareExpr * expr)653 Result WatWriter::ExprVisitorDelegate::OnCompareExpr(CompareExpr* expr) {
654 writer_->WritePutsNewline(expr->opcode.GetName());
655 return Result::Ok;
656 }
657
OnConstExpr(ConstExpr * expr)658 Result WatWriter::ExprVisitorDelegate::OnConstExpr(ConstExpr* expr) {
659 writer_->WriteConst(expr->const_);
660 return Result::Ok;
661 }
662
OnConvertExpr(ConvertExpr * expr)663 Result WatWriter::ExprVisitorDelegate::OnConvertExpr(ConvertExpr* expr) {
664 writer_->WritePutsNewline(expr->opcode.GetName());
665 return Result::Ok;
666 }
667
OnDropExpr(DropExpr * expr)668 Result WatWriter::ExprVisitorDelegate::OnDropExpr(DropExpr* expr) {
669 writer_->WritePutsNewline(Opcode::Drop_Opcode.GetName());
670 return Result::Ok;
671 }
672
OnGlobalGetExpr(GlobalGetExpr * expr)673 Result WatWriter::ExprVisitorDelegate::OnGlobalGetExpr(GlobalGetExpr* expr) {
674 writer_->WritePutsSpace(Opcode::GlobalGet_Opcode.GetName());
675 writer_->WriteVar(expr->var, NextChar::Newline);
676 return Result::Ok;
677 }
678
OnGlobalSetExpr(GlobalSetExpr * expr)679 Result WatWriter::ExprVisitorDelegate::OnGlobalSetExpr(GlobalSetExpr* expr) {
680 writer_->WritePutsSpace(Opcode::GlobalSet_Opcode.GetName());
681 writer_->WriteVar(expr->var, NextChar::Newline);
682 return Result::Ok;
683 }
684
BeginIfExpr(IfExpr * expr)685 Result WatWriter::ExprVisitorDelegate::BeginIfExpr(IfExpr* expr) {
686 writer_->WriteBeginBlock(LabelType::If, expr->true_,
687 Opcode::If_Opcode.GetName());
688 return Result::Ok;
689 }
690
AfterIfTrueExpr(IfExpr * expr)691 Result WatWriter::ExprVisitorDelegate::AfterIfTrueExpr(IfExpr* expr) {
692 if (!expr->false_.empty()) {
693 writer_->Dedent();
694 writer_->WritePutsSpace(Opcode::Else_Opcode.GetName());
695 writer_->Indent();
696 writer_->WriteNewline(FORCE_NEWLINE);
697 }
698 return Result::Ok;
699 }
700
EndIfExpr(IfExpr * expr)701 Result WatWriter::ExprVisitorDelegate::EndIfExpr(IfExpr* expr) {
702 writer_->WriteEndBlock();
703 return Result::Ok;
704 }
705
OnLoadExpr(LoadExpr * expr)706 Result WatWriter::ExprVisitorDelegate::OnLoadExpr(LoadExpr* expr) {
707 writer_->WriteLoadStoreExpr<LoadExpr>(expr);
708 return Result::Ok;
709 }
710
OnLocalGetExpr(LocalGetExpr * expr)711 Result WatWriter::ExprVisitorDelegate::OnLocalGetExpr(LocalGetExpr* expr) {
712 writer_->WritePutsSpace(Opcode::LocalGet_Opcode.GetName());
713 writer_->WriteVar(expr->var, NextChar::Newline);
714 return Result::Ok;
715 }
716
OnLocalSetExpr(LocalSetExpr * expr)717 Result WatWriter::ExprVisitorDelegate::OnLocalSetExpr(LocalSetExpr* expr) {
718 writer_->WritePutsSpace(Opcode::LocalSet_Opcode.GetName());
719 writer_->WriteVar(expr->var, NextChar::Newline);
720 return Result::Ok;
721 }
722
OnLocalTeeExpr(LocalTeeExpr * expr)723 Result WatWriter::ExprVisitorDelegate::OnLocalTeeExpr(LocalTeeExpr* expr) {
724 writer_->WritePutsSpace(Opcode::LocalTee_Opcode.GetName());
725 writer_->WriteVar(expr->var, NextChar::Newline);
726 return Result::Ok;
727 }
728
BeginLoopExpr(LoopExpr * expr)729 Result WatWriter::ExprVisitorDelegate::BeginLoopExpr(LoopExpr* expr) {
730 writer_->WriteBeginBlock(LabelType::Loop, expr->block,
731 Opcode::Loop_Opcode.GetName());
732 return Result::Ok;
733 }
734
EndLoopExpr(LoopExpr * expr)735 Result WatWriter::ExprVisitorDelegate::EndLoopExpr(LoopExpr* expr) {
736 writer_->WriteEndBlock();
737 return Result::Ok;
738 }
739
OnMemoryCopyExpr(MemoryCopyExpr * expr)740 Result WatWriter::ExprVisitorDelegate::OnMemoryCopyExpr(MemoryCopyExpr* expr) {
741 writer_->WritePutsNewline(Opcode::MemoryCopy_Opcode.GetName());
742 return Result::Ok;
743 }
744
OnDataDropExpr(DataDropExpr * expr)745 Result WatWriter::ExprVisitorDelegate::OnDataDropExpr(DataDropExpr* expr) {
746 writer_->WritePutsSpace(Opcode::DataDrop_Opcode.GetName());
747 writer_->WriteVar(expr->var, NextChar::Newline);
748 return Result::Ok;
749 }
750
OnMemoryFillExpr(MemoryFillExpr * expr)751 Result WatWriter::ExprVisitorDelegate::OnMemoryFillExpr(MemoryFillExpr* expr) {
752 writer_->WritePutsNewline(Opcode::MemoryFill_Opcode.GetName());
753 return Result::Ok;
754 }
755
OnMemoryGrowExpr(MemoryGrowExpr * expr)756 Result WatWriter::ExprVisitorDelegate::OnMemoryGrowExpr(MemoryGrowExpr* expr) {
757 writer_->WritePutsNewline(Opcode::MemoryGrow_Opcode.GetName());
758 return Result::Ok;
759 }
760
OnMemorySizeExpr(MemorySizeExpr * expr)761 Result WatWriter::ExprVisitorDelegate::OnMemorySizeExpr(MemorySizeExpr* expr) {
762 writer_->WritePutsNewline(Opcode::MemorySize_Opcode.GetName());
763 return Result::Ok;
764 }
765
OnMemoryInitExpr(MemoryInitExpr * expr)766 Result WatWriter::ExprVisitorDelegate::OnMemoryInitExpr(MemoryInitExpr* expr) {
767 writer_->WritePutsSpace(Opcode::MemoryInit_Opcode.GetName());
768 writer_->WriteVar(expr->var, NextChar::Newline);
769 return Result::Ok;
770 }
771
OnTableCopyExpr(TableCopyExpr * expr)772 Result WatWriter::ExprVisitorDelegate::OnTableCopyExpr(TableCopyExpr* expr) {
773 writer_->WritePutsNewline(Opcode::TableCopy_Opcode.GetName());
774 return Result::Ok;
775 }
776
OnElemDropExpr(ElemDropExpr * expr)777 Result WatWriter::ExprVisitorDelegate::OnElemDropExpr(ElemDropExpr* expr) {
778 writer_->WritePutsSpace(Opcode::ElemDrop_Opcode.GetName());
779 writer_->WriteVar(expr->var, NextChar::Newline);
780 return Result::Ok;
781 }
782
OnTableInitExpr(TableInitExpr * expr)783 Result WatWriter::ExprVisitorDelegate::OnTableInitExpr(TableInitExpr* expr) {
784 writer_->WritePutsSpace(Opcode::TableInit_Opcode.GetName());
785 writer_->WriteVar(expr->var, NextChar::Newline);
786 return Result::Ok;
787 }
788
OnTableGetExpr(TableGetExpr * expr)789 Result WatWriter::ExprVisitorDelegate::OnTableGetExpr(TableGetExpr* expr) {
790 writer_->WritePutsSpace(Opcode::TableGet_Opcode.GetName());
791 writer_->WriteVar(expr->var, NextChar::Newline);
792 return Result::Ok;
793 }
794
OnTableSetExpr(TableSetExpr * expr)795 Result WatWriter::ExprVisitorDelegate::OnTableSetExpr(TableSetExpr* expr) {
796 writer_->WritePutsSpace(Opcode::TableSet_Opcode.GetName());
797 writer_->WriteVar(expr->var, NextChar::Newline);
798 return Result::Ok;
799 }
800
OnTableGrowExpr(TableGrowExpr * expr)801 Result WatWriter::ExprVisitorDelegate::OnTableGrowExpr(TableGrowExpr* expr) {
802 writer_->WritePutsSpace(Opcode::TableGrow_Opcode.GetName());
803 writer_->WriteVar(expr->var, NextChar::Newline);
804 return Result::Ok;
805 }
806
OnTableSizeExpr(TableSizeExpr * expr)807 Result WatWriter::ExprVisitorDelegate::OnTableSizeExpr(TableSizeExpr* expr) {
808 writer_->WritePutsSpace(Opcode::TableSize_Opcode.GetName());
809 writer_->WriteVar(expr->var, NextChar::Newline);
810 return Result::Ok;
811 }
812
OnRefNullExpr(RefNullExpr * expr)813 Result WatWriter::ExprVisitorDelegate::OnRefNullExpr(RefNullExpr* expr) {
814 writer_->WritePutsNewline(Opcode::RefNull_Opcode.GetName());
815 return Result::Ok;
816 }
817
OnRefIsNullExpr(RefIsNullExpr * expr)818 Result WatWriter::ExprVisitorDelegate::OnRefIsNullExpr(RefIsNullExpr* expr) {
819 writer_->WritePutsNewline(Opcode::RefIsNull_Opcode.GetName());
820 return Result::Ok;
821 }
822
OnNopExpr(NopExpr * expr)823 Result WatWriter::ExprVisitorDelegate::OnNopExpr(NopExpr* expr) {
824 writer_->WritePutsNewline(Opcode::Nop_Opcode.GetName());
825 return Result::Ok;
826 }
827
OnReturnExpr(ReturnExpr * expr)828 Result WatWriter::ExprVisitorDelegate::OnReturnExpr(ReturnExpr* expr) {
829 writer_->WritePutsNewline(Opcode::Return_Opcode.GetName());
830 return Result::Ok;
831 }
832
OnReturnCallExpr(ReturnCallExpr * expr)833 Result WatWriter::ExprVisitorDelegate::OnReturnCallExpr(ReturnCallExpr* expr) {
834 writer_->WritePutsSpace(Opcode::ReturnCall_Opcode.GetName());
835 writer_->WriteVar(expr->var, NextChar::Newline);
836 return Result::Ok;
837 }
838
OnReturnCallIndirectExpr(ReturnCallIndirectExpr * expr)839 Result WatWriter::ExprVisitorDelegate::OnReturnCallIndirectExpr(
840 ReturnCallIndirectExpr* expr) {
841 writer_->WritePutsSpace(Opcode::ReturnCallIndirect_Opcode.GetName());
842 writer_->WriteOpenSpace("type");
843 writer_->WriteVar(expr->decl.type_var, NextChar::Space);
844 writer_->WriteCloseNewline();
845 return Result::Ok;
846 }
847
OnSelectExpr(SelectExpr * expr)848 Result WatWriter::ExprVisitorDelegate::OnSelectExpr(SelectExpr* expr) {
849 writer_->WritePutsNewline(Opcode::Select_Opcode.GetName());
850 return Result::Ok;
851 }
852
OnStoreExpr(StoreExpr * expr)853 Result WatWriter::ExprVisitorDelegate::OnStoreExpr(StoreExpr* expr) {
854 writer_->WriteLoadStoreExpr<StoreExpr>(expr);
855 return Result::Ok;
856 }
857
OnUnaryExpr(UnaryExpr * expr)858 Result WatWriter::ExprVisitorDelegate::OnUnaryExpr(UnaryExpr* expr) {
859 writer_->WritePutsNewline(expr->opcode.GetName());
860 return Result::Ok;
861 }
862
OnUnreachableExpr(UnreachableExpr * expr)863 Result WatWriter::ExprVisitorDelegate::OnUnreachableExpr(
864 UnreachableExpr* expr) {
865 writer_->WritePutsNewline(Opcode::Unreachable_Opcode.GetName());
866 return Result::Ok;
867 }
868
BeginTryExpr(TryExpr * expr)869 Result WatWriter::ExprVisitorDelegate::BeginTryExpr(TryExpr* expr) {
870 writer_->WriteBeginBlock(LabelType::Try, expr->block,
871 Opcode::Try_Opcode.GetName());
872 return Result::Ok;
873 }
874
OnCatchExpr(TryExpr * expr)875 Result WatWriter::ExprVisitorDelegate::OnCatchExpr(TryExpr* expr) {
876 writer_->Dedent();
877 writer_->WritePutsSpace(Opcode::Catch_Opcode.GetName());
878 writer_->Indent();
879 writer_->label_stack_.back().label_type = LabelType::Catch;
880 writer_->WriteNewline(FORCE_NEWLINE);
881 return Result::Ok;
882 }
883
EndTryExpr(TryExpr * expr)884 Result WatWriter::ExprVisitorDelegate::EndTryExpr(TryExpr* expr) {
885 writer_->WriteEndBlock();
886 return Result::Ok;
887 }
888
OnThrowExpr(ThrowExpr * expr)889 Result WatWriter::ExprVisitorDelegate::OnThrowExpr(ThrowExpr* expr) {
890 writer_->WritePutsSpace(Opcode::Throw_Opcode.GetName());
891 writer_->WriteVar(expr->var, NextChar::Newline);
892 return Result::Ok;
893 }
894
OnRethrowExpr(RethrowExpr * expr)895 Result WatWriter::ExprVisitorDelegate::OnRethrowExpr(RethrowExpr* expr) {
896 writer_->WritePutsSpace(Opcode::Rethrow_Opcode.GetName());
897 return Result::Ok;
898 }
899
OnAtomicWaitExpr(AtomicWaitExpr * expr)900 Result WatWriter::ExprVisitorDelegate::OnAtomicWaitExpr(AtomicWaitExpr* expr) {
901 writer_->WriteLoadStoreExpr<AtomicWaitExpr>(expr);
902 return Result::Ok;
903 }
904
OnAtomicNotifyExpr(AtomicNotifyExpr * expr)905 Result WatWriter::ExprVisitorDelegate::OnAtomicNotifyExpr(
906 AtomicNotifyExpr* expr) {
907 writer_->WriteLoadStoreExpr<AtomicNotifyExpr>(expr);
908 return Result::Ok;
909 }
910
OnAtomicLoadExpr(AtomicLoadExpr * expr)911 Result WatWriter::ExprVisitorDelegate::OnAtomicLoadExpr(AtomicLoadExpr* expr) {
912 writer_->WriteLoadStoreExpr<AtomicLoadExpr>(expr);
913 return Result::Ok;
914 }
915
OnAtomicStoreExpr(AtomicStoreExpr * expr)916 Result WatWriter::ExprVisitorDelegate::OnAtomicStoreExpr(
917 AtomicStoreExpr* expr) {
918 writer_->WriteLoadStoreExpr<AtomicStoreExpr>(expr);
919 return Result::Ok;
920 }
921
OnAtomicRmwExpr(AtomicRmwExpr * expr)922 Result WatWriter::ExprVisitorDelegate::OnAtomicRmwExpr(AtomicRmwExpr* expr) {
923 writer_->WriteLoadStoreExpr<AtomicRmwExpr>(expr);
924 return Result::Ok;
925 }
926
OnAtomicRmwCmpxchgExpr(AtomicRmwCmpxchgExpr * expr)927 Result WatWriter::ExprVisitorDelegate::OnAtomicRmwCmpxchgExpr(
928 AtomicRmwCmpxchgExpr* expr) {
929 writer_->WriteLoadStoreExpr<AtomicRmwCmpxchgExpr>(expr);
930 return Result::Ok;
931 }
932
OnTernaryExpr(TernaryExpr * expr)933 Result WatWriter::ExprVisitorDelegate::OnTernaryExpr(TernaryExpr* expr) {
934 writer_->WritePutsNewline(expr->opcode.GetName());
935 return Result::Ok;
936 }
937
OnSimdLaneOpExpr(SimdLaneOpExpr * expr)938 Result WatWriter::ExprVisitorDelegate::OnSimdLaneOpExpr(SimdLaneOpExpr* expr) {
939 writer_->WritePutsSpace(expr->opcode.GetName());
940 writer_->Writef("%" PRIu64, (expr->val));
941 writer_->WritePutsNewline("");
942 return Result::Ok;
943 }
944
OnSimdShuffleOpExpr(SimdShuffleOpExpr * expr)945 Result WatWriter::ExprVisitorDelegate::OnSimdShuffleOpExpr(
946 SimdShuffleOpExpr* expr) {
947 writer_->WritePutsSpace(expr->opcode.GetName());
948 std::array<uint8_t, 16> values = Bitcast<std::array<uint8_t, 16>>(expr->val);
949 for (int32_t lane = 0; lane < 16; ++lane) {
950 writer_->Writef(" %u", values[lane]);
951 }
952 writer_->WritePutsNewline("");
953 return Result::Ok;
954 }
955
OnLoadSplatExpr(LoadSplatExpr * expr)956 Result WatWriter::ExprVisitorDelegate::OnLoadSplatExpr(LoadSplatExpr* expr) {
957 writer_->WriteLoadStoreExpr<LoadSplatExpr>(expr);
958 return Result::Ok;
959 }
960
WriteExpr(const Expr * expr)961 void WatWriter::WriteExpr(const Expr* expr) {
962 WABT_TRACE(WriteExprList);
963 ExprVisitorDelegate delegate(this);
964 ExprVisitor visitor(&delegate);
965 visitor.VisitExpr(const_cast<Expr*>(expr));
966 }
967
WriteExprList(const ExprList & exprs)968 void WatWriter::WriteExprList(const ExprList& exprs) {
969 WABT_TRACE(WriteExprList);
970 ExprVisitorDelegate delegate(this);
971 ExprVisitor visitor(&delegate);
972 visitor.VisitExprList(const_cast<ExprList&>(exprs));
973 }
974
GetLabel(const Var & var)975 Label* WatWriter::GetLabel(const Var& var) {
976 if (var.is_name()) {
977 for (Index i = GetLabelStackSize(); i > 0; --i) {
978 Label* label = &label_stack_[i - 1];
979 if (label->name == var.name()) {
980 return label;
981 }
982 }
983 } else if (var.index() < GetLabelStackSize()) {
984 Label* label = &label_stack_[GetLabelStackSize() - var.index() - 1];
985 return label;
986 }
987 return nullptr;
988 }
989
GetLabelArity(const Var & var)990 Index WatWriter::GetLabelArity(const Var& var) {
991 Label* label = GetLabel(var);
992 if (!label) {
993 return 0;
994 }
995
996 return label->label_type == LabelType::Loop ? label->param_types.size()
997 : label->result_types.size();
998 }
999
GetFuncParamCount(const Var & var)1000 Index WatWriter::GetFuncParamCount(const Var& var) {
1001 const Func* func = module_->GetFunc(var);
1002 return func ? func->GetNumParams() : 0;
1003 }
1004
GetFuncResultCount(const Var & var)1005 Index WatWriter::GetFuncResultCount(const Var& var) {
1006 const Func* func = module_->GetFunc(var);
1007 return func ? func->GetNumResults() : 0;
1008 }
1009
WriteFoldedExpr(const Expr * expr)1010 void WatWriter::WriteFoldedExpr(const Expr* expr) {
1011 WABT_TRACE_ARGS(WriteFoldedExpr, "%s", GetExprTypeName(*expr));
1012 switch (expr->type()) {
1013 case ExprType::AtomicNotify:
1014 case ExprType::AtomicRmw:
1015 case ExprType::Binary:
1016 case ExprType::Compare:
1017 case ExprType::TableGrow:
1018 PushExpr(expr, 2, 1);
1019 break;
1020
1021 case ExprType::AtomicStore:
1022 case ExprType::Store:
1023 case ExprType::TableSet:
1024 PushExpr(expr, 2, 0);
1025 break;
1026
1027 case ExprType::Block:
1028 PushExpr(expr, 0, cast<BlockExpr>(expr)->block.decl.sig.GetNumResults());
1029 break;
1030
1031 case ExprType::Br:
1032 PushExpr(expr, GetLabelArity(cast<BrExpr>(expr)->var), 1);
1033 break;
1034
1035 case ExprType::BrIf: {
1036 Index arity = GetLabelArity(cast<BrIfExpr>(expr)->var);
1037 PushExpr(expr, arity + 1, arity);
1038 break;
1039 }
1040
1041 case ExprType::BrOnExn:
1042 PushExpr(expr, 1, 1);
1043 break;
1044
1045 case ExprType::BrTable:
1046 PushExpr(expr, GetLabelArity(cast<BrTableExpr>(expr)->default_target) + 1,
1047 1);
1048 break;
1049
1050 case ExprType::Call: {
1051 const Var& var = cast<CallExpr>(expr)->var;
1052 PushExpr(expr, GetFuncParamCount(var), GetFuncResultCount(var));
1053 break;
1054 }
1055
1056 case ExprType::ReturnCall: {
1057 const Var& var = cast<ReturnCallExpr>(expr)->var;
1058 PushExpr(expr, GetFuncParamCount(var), GetFuncResultCount(var));
1059 break;
1060 }
1061
1062 case ExprType::CallIndirect: {
1063 const auto* ci_expr = cast<CallIndirectExpr>(expr);
1064 PushExpr(expr, ci_expr->decl.GetNumParams() + 1,
1065 ci_expr->decl.GetNumResults());
1066 break;
1067 }
1068
1069 case ExprType::ReturnCallIndirect: {
1070 const auto* rci_expr = cast<ReturnCallIndirectExpr>(expr);
1071 PushExpr(expr, rci_expr->decl.GetNumParams() + 1,
1072 rci_expr->decl.GetNumResults());
1073 break;
1074 }
1075
1076 case ExprType::Const:
1077 case ExprType::GlobalGet:
1078 case ExprType::LocalGet:
1079 case ExprType::MemorySize:
1080 case ExprType::TableSize:
1081 case ExprType::Unreachable:
1082 case ExprType::RefNull:
1083 PushExpr(expr, 0, 1);
1084 break;
1085
1086 case ExprType::DataDrop:
1087 case ExprType::ElemDrop:
1088 PushExpr(expr, 0, 0);
1089 break;
1090
1091 case ExprType::MemoryInit:
1092 case ExprType::TableInit:
1093 case ExprType::MemoryFill:
1094 case ExprType::MemoryCopy:
1095 case ExprType::TableCopy:
1096 PushExpr(expr, 3, 0);
1097 break;
1098
1099 case ExprType::AtomicLoad:
1100 case ExprType::Convert:
1101 case ExprType::Load:
1102 case ExprType::LocalTee:
1103 case ExprType::MemoryGrow:
1104 case ExprType::Unary:
1105 case ExprType::TableGet:
1106 case ExprType::RefIsNull:
1107 PushExpr(expr, 1, 1);
1108 break;
1109
1110 case ExprType::Drop:
1111 case ExprType::GlobalSet:
1112 case ExprType::LocalSet:
1113 PushExpr(expr, 1, 0);
1114 break;
1115
1116 case ExprType::If:
1117 PushExpr(expr, 1, cast<IfExpr>(expr)->true_.decl.sig.GetNumResults());
1118 break;
1119
1120 case ExprType::Loop:
1121 PushExpr(expr, 0, cast<LoopExpr>(expr)->block.decl.sig.GetNumResults());
1122 break;
1123
1124 case ExprType::Nop:
1125 PushExpr(expr, 0, 0);
1126 break;
1127
1128 case ExprType::Return:
1129 PushExpr(expr, current_func_->decl.sig.result_types.size(), 1);
1130 break;
1131
1132 case ExprType::Rethrow:
1133 PushExpr(expr, 0, 0);
1134 break;
1135
1136 case ExprType::AtomicRmwCmpxchg:
1137 case ExprType::AtomicWait:
1138 case ExprType::Select:
1139 PushExpr(expr, 3, 1);
1140 break;
1141
1142 case ExprType::Throw: {
1143 auto throw_ = cast<ThrowExpr>(expr);
1144 Index operand_count = 0;
1145 if (Event* event = module_->GetEvent(throw_->var)) {
1146 operand_count = event->decl.sig.param_types.size();
1147 }
1148 PushExpr(expr, operand_count, 0);
1149 break;
1150 }
1151
1152 case ExprType::Try:
1153 PushExpr(expr, 0, cast<TryExpr>(expr)->block.decl.sig.GetNumResults());
1154 break;
1155
1156 case ExprType::Ternary:
1157 PushExpr(expr, 3, 1);
1158 break;
1159
1160 case ExprType::SimdLaneOp: {
1161 const Opcode opcode = cast<SimdLaneOpExpr>(expr)->opcode;
1162 switch (opcode) {
1163 case Opcode::I8X16ExtractLaneS:
1164 case Opcode::I8X16ExtractLaneU:
1165 case Opcode::I16X8ExtractLaneS:
1166 case Opcode::I16X8ExtractLaneU:
1167 case Opcode::I32X4ExtractLane:
1168 case Opcode::I64X2ExtractLane:
1169 case Opcode::F32X4ExtractLane:
1170 case Opcode::F64X2ExtractLane:
1171 PushExpr(expr, 1, 1);
1172 break;
1173
1174 case Opcode::I8X16ReplaceLane:
1175 case Opcode::I16X8ReplaceLane:
1176 case Opcode::I32X4ReplaceLane:
1177 case Opcode::I64X2ReplaceLane:
1178 case Opcode::F32X4ReplaceLane:
1179 case Opcode::F64X2ReplaceLane:
1180 PushExpr(expr, 2, 1);
1181 break;
1182
1183 default:
1184 fprintf(stderr, "Invalid Opcode for expr type: %s\n",
1185 GetExprTypeName(*expr));
1186 assert(0);
1187 }
1188 break;
1189 }
1190
1191 case ExprType::SimdShuffleOp:
1192 PushExpr(expr, 2, 1);
1193 break;
1194
1195 default:
1196 fprintf(stderr, "bad expr type: %s\n", GetExprTypeName(*expr));
1197 assert(0);
1198 break;
1199 }
1200 }
1201
WriteFoldedExprList(const ExprList & exprs)1202 void WatWriter::WriteFoldedExprList(const ExprList& exprs) {
1203 WABT_TRACE(WriteFoldedExprList);
1204 for (const Expr& expr : exprs) {
1205 WriteFoldedExpr(&expr);
1206 }
1207 }
1208
PushExpr(const Expr * expr,Index operand_count,Index result_count)1209 void WatWriter::PushExpr(const Expr* expr,
1210 Index operand_count,
1211 Index result_count) {
1212 WABT_TRACE_ARGS(PushExpr, "%s, %" PRIindex ", %" PRIindex "",
1213 GetExprTypeName(*expr), operand_count, result_count);
1214
1215 // Try to pop operand off the expr stack to use as this expr's children. One
1216 // expr can have multiple return values (with the multi-value extension), so
1217 // we have to iterate over each in reverse.
1218
1219 auto first_operand = expr_tree_stack_.end();
1220
1221 Index current_count = 0;
1222 if (operand_count > 0) {
1223 for (auto iter = expr_tree_stack_.rbegin(); iter != expr_tree_stack_.rend();
1224 ++iter) {
1225 assert(iter->result_count > 0);
1226 current_count += iter->result_count;
1227
1228 if (current_count == operand_count) {
1229 first_operand = iter.base() - 1;
1230 break;
1231 } else if (current_count > operand_count) {
1232 // We went over the number of operands this instruction wants; this can
1233 // only happen when there are expressions on the stack with a
1234 // result_count > 1. When this happens we can't fold, since any result
1235 // we produce will not make sense.
1236 break;
1237 }
1238 }
1239 }
1240
1241 ExprTree tree(expr, result_count);
1242
1243 if (current_count == operand_count && operand_count > 0) {
1244 auto last_operand = expr_tree_stack_.end();
1245 std::move(first_operand, last_operand, std::back_inserter(tree.children));
1246 expr_tree_stack_.erase(first_operand, last_operand);
1247 }
1248
1249 expr_tree_stack_.emplace_back(std::move(tree));
1250 if (current_count > operand_count || result_count == 0) {
1251 FlushExprTreeStack();
1252 }
1253 }
1254
FlushExprTree(const ExprTree & expr_tree)1255 void WatWriter::FlushExprTree(const ExprTree& expr_tree) {
1256 WABT_TRACE_ARGS(FlushExprTree, "%s", GetExprTypeName(*expr_tree.expr));
1257 switch (expr_tree.expr->type()) {
1258 case ExprType::Block:
1259 WritePuts("(", NextChar::None);
1260 WriteBeginBlock(LabelType::Block, cast<BlockExpr>(expr_tree.expr)->block,
1261 Opcode::Block_Opcode.GetName());
1262 WriteFoldedExprList(cast<BlockExpr>(expr_tree.expr)->block.exprs);
1263 FlushExprTreeStack();
1264 WriteCloseNewline();
1265 break;
1266
1267 case ExprType::Loop:
1268 WritePuts("(", NextChar::None);
1269 WriteBeginBlock(LabelType::Loop, cast<LoopExpr>(expr_tree.expr)->block,
1270 Opcode::Loop_Opcode.GetName());
1271 WriteFoldedExprList(cast<LoopExpr>(expr_tree.expr)->block.exprs);
1272 FlushExprTreeStack();
1273 WriteCloseNewline();
1274 break;
1275
1276 case ExprType::If: {
1277 auto if_expr = cast<IfExpr>(expr_tree.expr);
1278 WritePuts("(", NextChar::None);
1279 WriteBeginBlock(LabelType::If, if_expr->true_,
1280 Opcode::If_Opcode.GetName());
1281 FlushExprTreeVector(expr_tree.children);
1282 WriteOpenNewline("then");
1283 WriteFoldedExprList(if_expr->true_.exprs);
1284 FlushExprTreeStack();
1285 WriteCloseNewline();
1286 if (!if_expr->false_.empty()) {
1287 WriteOpenNewline("else");
1288 WriteFoldedExprList(if_expr->false_);
1289 FlushExprTreeStack();
1290 WriteCloseNewline();
1291 }
1292 WriteCloseNewline();
1293 break;
1294 }
1295
1296 case ExprType::Try: {
1297 auto try_expr = cast<TryExpr>(expr_tree.expr);
1298 WritePuts("(", NextChar::None);
1299 WriteBeginBlock(LabelType::Try, try_expr->block,
1300 Opcode::Try_Opcode.GetName());
1301 FlushExprTreeVector(expr_tree.children);
1302 WriteFoldedExprList(try_expr->block.exprs);
1303 FlushExprTreeStack();
1304 WriteOpenNewline("catch");
1305 WriteFoldedExprList(try_expr->catch_);
1306 FlushExprTreeStack();
1307 WriteCloseNewline();
1308 WriteCloseNewline();
1309 break;
1310 }
1311
1312 default: {
1313 WritePuts("(", NextChar::None);
1314 WriteExpr(expr_tree.expr);
1315 Indent();
1316 FlushExprTreeVector(expr_tree.children);
1317 WriteCloseNewline();
1318 break;
1319 }
1320 }
1321 }
1322
FlushExprTreeVector(const std::vector<ExprTree> & expr_trees)1323 void WatWriter::FlushExprTreeVector(const std::vector<ExprTree>& expr_trees) {
1324 WABT_TRACE_ARGS(FlushExprTreeVector, "%zu", expr_trees.size());
1325 for (auto expr_tree : expr_trees) {
1326 FlushExprTree(expr_tree);
1327 }
1328 }
1329
FlushExprTreeStack()1330 void WatWriter::FlushExprTreeStack() {
1331 std::vector<ExprTree> stack_copy(std::move(expr_tree_stack_));
1332 expr_tree_stack_.clear();
1333 FlushExprTreeVector(stack_copy);
1334 }
1335
WriteInitExpr(const ExprList & expr)1336 void WatWriter::WriteInitExpr(const ExprList& expr) {
1337 if (!expr.empty()) {
1338 WritePuts("(", NextChar::None);
1339 WriteExprList(expr);
1340 /* clear the next char, so we don't write a newline after the expr */
1341 next_char_ = NextChar::None;
1342 WritePuts(")", NextChar::Space);
1343 }
1344 }
1345
1346 template <typename T>
WriteTypeBindings(const char * prefix,const T & types,const std::vector<std::string> & index_to_name,Index binding_index_offset)1347 void WatWriter::WriteTypeBindings(const char* prefix,
1348 const T& types,
1349 const std::vector<std::string>& index_to_name,
1350 Index binding_index_offset) {
1351 /* named params/locals must be specified by themselves, but nameless
1352 * params/locals can be compressed, e.g.:
1353 * (param $foo i32)
1354 * (param i32 i64 f32)
1355 */
1356 bool is_open = false;
1357 size_t index = 0;
1358 for (Type type : types) {
1359 if (!is_open) {
1360 WriteOpenSpace(prefix);
1361 is_open = true;
1362 }
1363
1364 const std::string& name = index_to_name[binding_index_offset + index];
1365 if (!name.empty()) {
1366 WriteString(name, NextChar::Space);
1367 }
1368 WriteType(type, NextChar::Space);
1369 if (!name.empty()) {
1370 WriteCloseSpace();
1371 is_open = false;
1372 }
1373 ++index;
1374 }
1375 if (is_open) {
1376 WriteCloseSpace();
1377 }
1378 }
1379
WriteBeginFunc(const Func & func)1380 void WatWriter::WriteBeginFunc(const Func& func) {
1381 WriteOpenSpace("func");
1382 WriteNameOrIndex(func.name, func_index_, NextChar::Space);
1383 WriteInlineExports(ExternalKind::Func, func_index_);
1384 WriteInlineImport(ExternalKind::Func, func_index_);
1385 if (func.decl.has_func_type) {
1386 WriteOpenSpace("type");
1387 WriteVar(func.decl.type_var, NextChar::None);
1388 WriteCloseSpace();
1389 }
1390
1391 if (module_->IsImport(ExternalKind::Func, Var(func_index_))) {
1392 // Imported functions can be written a few ways:
1393 //
1394 // 1. (import "module" "field" (func (type 0)))
1395 // 2. (import "module" "field" (func (param i32) (result i32)))
1396 // 3. (func (import "module" "field") (type 0))
1397 // 4. (func (import "module" "field") (param i32) (result i32))
1398 // 5. (func (import "module" "field") (type 0) (param i32) (result i32))
1399 //
1400 // Note that the text format does not allow including the param/result
1401 // explicitly when using the "(import..." syntax (#1 and #2).
1402 if (options_.inline_import || !func.decl.has_func_type) {
1403 WriteFuncSigSpace(func.decl.sig);
1404 }
1405 }
1406 func_index_++;
1407 }
1408
WriteFunc(const Func & func)1409 void WatWriter::WriteFunc(const Func& func) {
1410 WriteBeginFunc(func);
1411 std::vector<std::string> index_to_name;
1412 MakeTypeBindingReverseMapping(func.GetNumParamsAndLocals(), func.bindings,
1413 &index_to_name);
1414 WriteTypeBindings("param", func.decl.sig.param_types, index_to_name);
1415 WriteTypes(func.decl.sig.result_types, "result");
1416 WriteNewline(NO_FORCE_NEWLINE);
1417 if (func.local_types.size()) {
1418 WriteTypeBindings("local", func.local_types, index_to_name,
1419 func.GetNumParams());
1420 }
1421 WriteNewline(NO_FORCE_NEWLINE);
1422 label_stack_.clear();
1423 label_stack_.emplace_back(LabelType::Func, std::string(), TypeVector(),
1424 func.decl.sig.result_types);
1425 current_func_ = &func;
1426 if (options_.fold_exprs) {
1427 WriteFoldedExprList(func.exprs);
1428 FlushExprTreeStack();
1429 } else {
1430 WriteExprList(func.exprs);
1431 }
1432 current_func_ = nullptr;
1433 WriteCloseNewline();
1434 }
1435
WriteBeginGlobal(const Global & global)1436 void WatWriter::WriteBeginGlobal(const Global& global) {
1437 WriteOpenSpace("global");
1438 WriteNameOrIndex(global.name, global_index_, NextChar::Space);
1439 WriteInlineExports(ExternalKind::Global, global_index_);
1440 WriteInlineImport(ExternalKind::Global, global_index_);
1441 if (global.mutable_) {
1442 WriteOpenSpace("mut");
1443 WriteType(global.type, NextChar::Space);
1444 WriteCloseSpace();
1445 } else {
1446 WriteType(global.type, NextChar::Space);
1447 }
1448 global_index_++;
1449 }
1450
WriteGlobal(const Global & global)1451 void WatWriter::WriteGlobal(const Global& global) {
1452 WriteBeginGlobal(global);
1453 WriteInitExpr(global.init_expr);
1454 WriteCloseNewline();
1455 }
1456
WriteEvent(const Event & event)1457 void WatWriter::WriteEvent(const Event& event) {
1458 WriteOpenSpace("event");
1459 WriteNameOrIndex(event.name, event_index_, NextChar::Space);
1460 WriteInlineExports(ExternalKind::Event, event_index_);
1461 WriteInlineImport(ExternalKind::Event, event_index_);
1462 if (event.decl.has_func_type) {
1463 WriteOpenSpace("type");
1464 WriteVar(event.decl.type_var, NextChar::None);
1465 WriteCloseSpace();
1466 }
1467 WriteTypes(event.decl.sig.param_types, "param");
1468 ++event_index_;
1469 WriteCloseNewline();
1470 }
1471
WriteLimits(const Limits & limits)1472 void WatWriter::WriteLimits(const Limits& limits) {
1473 Writef("%" PRIu64, limits.initial);
1474 if (limits.has_max) {
1475 Writef("%" PRIu64, limits.max);
1476 }
1477 if (limits.is_shared) {
1478 Writef("shared");
1479 }
1480 }
1481
WriteTable(const Table & table)1482 void WatWriter::WriteTable(const Table& table) {
1483 WriteOpenSpace("table");
1484 WriteNameOrIndex(table.name, table_index_, NextChar::Space);
1485 WriteInlineExports(ExternalKind::Table, table_index_);
1486 WriteInlineImport(ExternalKind::Table, table_index_);
1487 WriteLimits(table.elem_limits);
1488 WriteType(table.elem_type, NextChar::None);
1489 WriteCloseNewline();
1490 table_index_++;
1491 }
1492
WriteElemSegment(const ElemSegment & segment)1493 void WatWriter::WriteElemSegment(const ElemSegment& segment) {
1494 WriteOpenSpace("elem");
1495 WriteNameOrIndex(segment.name, elem_segment_index_, NextChar::Space);
1496 if (segment.passive) {
1497 WriteType(segment.elem_type, NextChar::Space);
1498 } else {
1499 WriteInitExpr(segment.offset);
1500 }
1501 for (const ElemExpr& expr : segment.elem_exprs) {
1502 if (segment.passive) {
1503 if (expr.kind == ElemExprKind::RefNull) {
1504 WriteOpenSpace("ref.null");
1505 WriteCloseSpace();
1506 } else {
1507 WriteOpenSpace("ref.func");
1508 WriteVar(expr.var, NextChar::Space);
1509 WriteCloseSpace();
1510 }
1511 } else {
1512 assert(expr.kind == ElemExprKind::RefFunc);
1513 WriteVar(expr.var, NextChar::Space);
1514 }
1515 }
1516 WriteCloseNewline();
1517 elem_segment_index_++;
1518 }
1519
WriteMemory(const Memory & memory)1520 void WatWriter::WriteMemory(const Memory& memory) {
1521 WriteOpenSpace("memory");
1522 WriteNameOrIndex(memory.name, memory_index_, NextChar::Space);
1523 WriteInlineExports(ExternalKind::Memory, memory_index_);
1524 WriteInlineImport(ExternalKind::Memory, memory_index_);
1525 WriteLimits(memory.page_limits);
1526 WriteCloseNewline();
1527 memory_index_++;
1528 }
1529
WriteDataSegment(const DataSegment & segment)1530 void WatWriter::WriteDataSegment(const DataSegment& segment) {
1531 WriteOpenSpace("data");
1532 WriteNameOrIndex(segment.name, data_segment_index_, NextChar::Space);
1533 if (!segment.passive) {
1534 WriteInitExpr(segment.offset);
1535 }
1536 WriteQuotedData(segment.data.data(), segment.data.size());
1537 WriteCloseNewline();
1538 data_segment_index_++;
1539 }
1540
WriteImport(const Import & import)1541 void WatWriter::WriteImport(const Import& import) {
1542 if (!options_.inline_import) {
1543 WriteOpenSpace("import");
1544 WriteQuotedString(import.module_name, NextChar::Space);
1545 WriteQuotedString(import.field_name, NextChar::Space);
1546 }
1547
1548 switch (import.kind()) {
1549 case ExternalKind::Func:
1550 WriteBeginFunc(cast<FuncImport>(&import)->func);
1551 WriteCloseSpace();
1552 break;
1553
1554 case ExternalKind::Table:
1555 WriteTable(cast<TableImport>(&import)->table);
1556 break;
1557
1558 case ExternalKind::Memory:
1559 WriteMemory(cast<MemoryImport>(&import)->memory);
1560 break;
1561
1562 case ExternalKind::Global:
1563 WriteBeginGlobal(cast<GlobalImport>(&import)->global);
1564 WriteCloseSpace();
1565 break;
1566
1567 case ExternalKind::Event:
1568 WriteEvent(cast<EventImport>(&import)->event);
1569 break;
1570 }
1571
1572 if (options_.inline_import) {
1573 WriteNewline(NO_FORCE_NEWLINE);
1574 } else {
1575 WriteCloseNewline();
1576 }
1577 }
1578
WriteExport(const Export & export_)1579 void WatWriter::WriteExport(const Export& export_) {
1580 if (options_.inline_export && IsInlineExport(export_)) {
1581 return;
1582 }
1583 WriteOpenSpace("export");
1584 WriteQuotedString(export_.name, NextChar::Space);
1585 WriteOpenSpace(GetKindName(export_.kind));
1586 WriteVar(export_.var, NextChar::Space);
1587 WriteCloseSpace();
1588 WriteCloseNewline();
1589 }
1590
WriteFuncType(const FuncType & func_type)1591 void WatWriter::WriteFuncType(const FuncType& func_type) {
1592 WriteOpenSpace("type");
1593 WriteNameOrIndex(func_type.name, func_type_index_++, NextChar::Space);
1594 WriteOpenSpace("func");
1595 WriteFuncSigSpace(func_type.sig);
1596 WriteCloseSpace();
1597 WriteCloseNewline();
1598 }
1599
WriteStartFunction(const Var & start)1600 void WatWriter::WriteStartFunction(const Var& start) {
1601 WriteOpenSpace("start");
1602 WriteVar(start, NextChar::None);
1603 WriteCloseNewline();
1604 }
1605
WriteModule(const Module & module)1606 Result WatWriter::WriteModule(const Module& module) {
1607 module_ = &module;
1608 BuildInlineExportMap();
1609 BuildInlineImportMap();
1610 WriteOpenSpace("module");
1611 if (module.name.empty()) {
1612 WriteNewline(NO_FORCE_NEWLINE);
1613 } else {
1614 WriteName(module.name, NextChar::Newline);
1615 }
1616 for (const ModuleField& field : module.fields) {
1617 switch (field.type()) {
1618 case ModuleFieldType::Func:
1619 WriteFunc(cast<FuncModuleField>(&field)->func);
1620 break;
1621 case ModuleFieldType::Global:
1622 WriteGlobal(cast<GlobalModuleField>(&field)->global);
1623 break;
1624 case ModuleFieldType::Import:
1625 WriteImport(*cast<ImportModuleField>(&field)->import);
1626 break;
1627 case ModuleFieldType::Event:
1628 WriteEvent(cast<EventModuleField>(&field)->event);
1629 break;
1630 case ModuleFieldType::Export:
1631 WriteExport(cast<ExportModuleField>(&field)->export_);
1632 break;
1633 case ModuleFieldType::Table:
1634 WriteTable(cast<TableModuleField>(&field)->table);
1635 break;
1636 case ModuleFieldType::ElemSegment:
1637 WriteElemSegment(cast<ElemSegmentModuleField>(&field)->elem_segment);
1638 break;
1639 case ModuleFieldType::Memory:
1640 WriteMemory(cast<MemoryModuleField>(&field)->memory);
1641 break;
1642 case ModuleFieldType::DataSegment:
1643 WriteDataSegment(cast<DataSegmentModuleField>(&field)->data_segment);
1644 break;
1645 case ModuleFieldType::FuncType:
1646 WriteFuncType(cast<FuncTypeModuleField>(&field)->func_type);
1647 break;
1648 case ModuleFieldType::Start:
1649 WriteStartFunction(cast<StartModuleField>(&field)->start);
1650 break;
1651 }
1652 }
1653 WriteCloseNewline();
1654 /* force the newline to be written */
1655 WriteNextChar();
1656 return result_;
1657 }
1658
BuildInlineExportMap()1659 void WatWriter::BuildInlineExportMap() {
1660 if (!options_.inline_export) {
1661 return;
1662 }
1663
1664 assert(module_);
1665 for (Export* export_ : module_->exports) {
1666 Index index = kInvalidIndex;
1667
1668 // Exported imports can't be written with inline exports, unless the
1669 // imports are also inline. For example, the following is invalid:
1670 //
1671 // (import "module" "field" (func (export "e")))
1672 //
1673 // But this is valid:
1674 //
1675 // (func (export "e") (import "module" "field"))
1676 //
1677 if (!options_.inline_import && module_->IsImport(*export_)) {
1678 continue;
1679 }
1680
1681 switch (export_->kind) {
1682 case ExternalKind::Func:
1683 index = module_->GetFuncIndex(export_->var);
1684 break;
1685
1686 case ExternalKind::Table:
1687 index = module_->GetTableIndex(export_->var);
1688 break;
1689
1690 case ExternalKind::Memory:
1691 index = module_->GetMemoryIndex(export_->var);
1692 break;
1693
1694 case ExternalKind::Global:
1695 index = module_->GetGlobalIndex(export_->var);
1696 break;
1697
1698 case ExternalKind::Event:
1699 index = module_->GetEventIndex(export_->var);
1700 break;
1701 }
1702
1703 if (index != kInvalidIndex) {
1704 auto key = std::make_pair(export_->kind, index);
1705 inline_export_map_.insert(std::make_pair(key, export_));
1706 }
1707 }
1708 }
1709
WriteInlineExports(ExternalKind kind,Index index)1710 void WatWriter::WriteInlineExports(ExternalKind kind, Index index) {
1711 if (!options_.inline_export) {
1712 return;
1713 }
1714
1715 auto iter_pair = inline_export_map_.equal_range(std::make_pair(kind, index));
1716 for (auto iter = iter_pair.first; iter != iter_pair.second; ++iter) {
1717 const Export* export_ = iter->second;
1718 WriteOpenSpace("export");
1719 WriteQuotedString(export_->name, NextChar::None);
1720 WriteCloseSpace();
1721 }
1722 }
1723
IsInlineExport(const Export & export_)1724 bool WatWriter::IsInlineExport(const Export& export_) {
1725 Index index;
1726 switch (export_.kind) {
1727 case ExternalKind::Func:
1728 index = module_->GetFuncIndex(export_.var);
1729 break;
1730
1731 case ExternalKind::Table:
1732 index = module_->GetTableIndex(export_.var);
1733 break;
1734
1735 case ExternalKind::Memory:
1736 index = module_->GetMemoryIndex(export_.var);
1737 break;
1738
1739 case ExternalKind::Global:
1740 index = module_->GetGlobalIndex(export_.var);
1741 break;
1742
1743 case ExternalKind::Event:
1744 index = module_->GetEventIndex(export_.var);
1745 break;
1746 }
1747
1748 return inline_export_map_.find(std::make_pair(export_.kind, index)) !=
1749 inline_export_map_.end();
1750 }
1751
BuildInlineImportMap()1752 void WatWriter::BuildInlineImportMap() {
1753 if (!options_.inline_import) {
1754 return;
1755 }
1756
1757 assert(module_);
1758 for (const Import* import : module_->imports) {
1759 inline_import_map_[static_cast<size_t>(import->kind())].push_back(import);
1760 }
1761 }
1762
WriteInlineImport(ExternalKind kind,Index index)1763 void WatWriter::WriteInlineImport(ExternalKind kind, Index index) {
1764 if (!options_.inline_import) {
1765 return;
1766 }
1767
1768 size_t kind_index = static_cast<size_t>(kind);
1769
1770 if (index >= inline_import_map_[kind_index].size()) {
1771 return;
1772 }
1773
1774 const Import* import = inline_import_map_[kind_index][index];
1775 WriteOpenSpace("import");
1776 WriteQuotedString(import->module_name, NextChar::Space);
1777 WriteQuotedString(import->field_name, NextChar::Space);
1778 WriteCloseSpace();
1779 }
1780
1781 } // end anonymous namespace
1782
WriteWat(Stream * stream,const Module * module,const WriteWatOptions & options)1783 Result WriteWat(Stream* stream,
1784 const Module* module,
1785 const WriteWatOptions& options) {
1786 WatWriter wat_writer(stream, options);
1787 return wat_writer.WriteModule(*module);
1788 }
1789
1790 } // namespace wabt
1791