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