LCOV - code coverage report
Current view: top level - js/src/wasm - WasmBinaryToText.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1112 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 66 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  *
       4             :  * Copyright 2015 Mozilla Foundation
       5             :  *
       6             :  * Licensed under the Apache License, Version 2.0 (the "License");
       7             :  * you may not use this file except in compliance with the License.
       8             :  * You may obtain a copy of the License at
       9             :  *
      10             :  *     http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  * Unless required by applicable law or agreed to in writing, software
      13             :  * distributed under the License is distributed on an "AS IS" BASIS,
      14             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  * See the License for the specific language governing permissions and
      16             :  * limitations under the License.
      17             :  */
      18             : 
      19             : #include "wasm/WasmBinaryToText.h"
      20             : 
      21             : #include "jsnum.h"
      22             : #include "jsprf.h"
      23             : 
      24             : #include "vm/ArrayBufferObject.h"
      25             : #include "vm/StringBuffer.h"
      26             : #include "wasm/WasmAST.h"
      27             : #include "wasm/WasmBinaryToAST.h"
      28             : #include "wasm/WasmDebug.h"
      29             : #include "wasm/WasmTextUtils.h"
      30             : #include "wasm/WasmTypes.h"
      31             : 
      32             : using namespace js;
      33             : using namespace js::wasm;
      34             : 
      35             : using mozilla::IsInfinite;
      36             : using mozilla::IsNaN;
      37             : using mozilla::IsNegativeZero;
      38             : 
      39             : struct WasmRenderContext
      40             : {
      41             :     JSContext* cx;
      42             :     AstModule* module;
      43             :     WasmPrintBuffer& buffer;
      44             :     GeneratedSourceMap* maybeSourceMap;
      45             :     uint32_t indent;
      46             :     uint32_t currentFuncIndex;
      47             : 
      48           0 :     WasmRenderContext(JSContext* cx, AstModule* module, WasmPrintBuffer& buffer,
      49             :                       GeneratedSourceMap* sourceMap)
      50           0 :       : cx(cx),
      51             :         module(module),
      52             :         buffer(buffer),
      53             :         maybeSourceMap(sourceMap),
      54             :         indent(0),
      55           0 :         currentFuncIndex(0)
      56           0 :     {}
      57             : 
      58           0 :     StringBuffer& sb() { return buffer.stringBuffer(); }
      59             : };
      60             : 
      61             : /*****************************************************************************/
      62             : // utilities
      63             : 
      64             : // Return true on purpose, so that we have a useful error message to provide to
      65             : // the user.
      66             : static bool
      67           0 : Fail(WasmRenderContext& c, const char* msg)
      68             : {
      69           0 :     c.buffer.stringBuffer().clear();
      70             : 
      71           0 :     return c.buffer.append("There was a problem when rendering the wasm text format: ") &&
      72           0 :            c.buffer.append(msg, strlen(msg)) &&
      73           0 :            c.buffer.append("\nYou should consider file a bug on Bugzilla in the "
      74             :                            "Core:::JavaScript Engine::JIT component at "
      75           0 :                            "https://bugzilla.mozilla.org/enter_bug.cgi.");
      76             : }
      77             : 
      78             : static bool
      79           0 : RenderIndent(WasmRenderContext& c)
      80             : {
      81           0 :     for (uint32_t i = 0; i < c.indent; i++) {
      82           0 :         if (!c.buffer.append("  "))
      83           0 :             return false;
      84             :     }
      85           0 :     return true;
      86             : }
      87             : 
      88             : static bool
      89           0 : RenderInt32(WasmRenderContext& c, int32_t num)
      90             : {
      91           0 :     return NumberValueToStringBuffer(c.cx, Int32Value(num), c.sb());
      92             : }
      93             : 
      94             : static bool
      95           0 : RenderInt64(WasmRenderContext& c, int64_t num)
      96             : {
      97           0 :     if (num < 0 && !c.buffer.append("-"))
      98           0 :         return false;
      99           0 :     if (!num)
     100           0 :         return c.buffer.append("0");
     101           0 :     return RenderInBase<10>(c.sb(), mozilla::Abs(num));
     102             : }
     103             : 
     104             : static bool
     105           0 : RenderDouble(WasmRenderContext& c, double d)
     106             : {
     107           0 :     if (IsNaN(d))
     108           0 :         return RenderNaN(c.sb(), d);
     109           0 :     if (IsNegativeZero(d))
     110           0 :         return c.buffer.append("-0");
     111           0 :     if (IsInfinite(d)) {
     112           0 :         if (d > 0)
     113           0 :             return c.buffer.append("infinity");
     114           0 :         return c.buffer.append("-infinity");
     115             :     }
     116           0 :     return NumberValueToStringBuffer(c.cx, DoubleValue(d), c.sb());
     117             : }
     118             : 
     119             : static bool
     120           0 : RenderFloat32(WasmRenderContext& c, float f)
     121             : {
     122           0 :     if (IsNaN(f))
     123           0 :         return RenderNaN(c.sb(), f);
     124           0 :     return RenderDouble(c, double(f));
     125             : }
     126             : 
     127             : static bool
     128           0 : RenderEscapedString(WasmRenderContext& c, const AstName& s)
     129             : {
     130           0 :     size_t length = s.length();
     131           0 :     const char16_t* p = s.begin();
     132           0 :     for (size_t i = 0; i < length; i++) {
     133           0 :         char16_t byte = p[i];
     134           0 :         switch (byte) {
     135             :           case '\n':
     136           0 :             if (!c.buffer.append("\\n"))
     137           0 :                 return false;
     138           0 :             break;
     139             :           case '\r':
     140           0 :             if (!c.buffer.append("\\0d"))
     141           0 :                 return false;
     142           0 :             break;
     143             :           case '\t':
     144           0 :             if (!c.buffer.append("\\t"))
     145           0 :                 return false;
     146           0 :             break;
     147             :           case '\f':
     148           0 :             if (!c.buffer.append("\\0c"))
     149           0 :                 return false;
     150           0 :             break;
     151             :           case '\b':
     152           0 :             if (!c.buffer.append("\\08"))
     153           0 :                 return false;
     154           0 :             break;
     155             :           case '\\':
     156           0 :             if (!c.buffer.append("\\\\"))
     157           0 :                 return false;
     158           0 :             break;
     159             :           case '"' :
     160           0 :             if (!c.buffer.append("\\\""))
     161           0 :                 return false;
     162           0 :             break;
     163             :           case '\'':
     164           0 :             if (!c.buffer.append("\\'"))
     165           0 :                 return false;
     166           0 :             break;
     167             :           default:
     168           0 :             if (byte >= 32 && byte < 127) {
     169           0 :                 if (!c.buffer.append((char)byte))
     170           0 :                     return false;
     171             :             } else {
     172           0 :                 char digit1 = byte / 16, digit2 = byte % 16;
     173           0 :                 if (!c.buffer.append("\\"))
     174           0 :                     return false;
     175           0 :                 if (!c.buffer.append((char)(digit1 < 10 ? digit1 + '0' : digit1 + 'a' - 10)))
     176           0 :                     return false;
     177           0 :                 if (!c.buffer.append((char)(digit2 < 10 ? digit2 + '0' : digit2 + 'a' - 10)))
     178           0 :                     return false;
     179             :             }
     180           0 :             break;
     181             :         }
     182             :     }
     183           0 :     return true;
     184             : }
     185             : 
     186             : static bool
     187           0 : RenderExprType(WasmRenderContext& c, ExprType type)
     188             : {
     189           0 :     switch (type) {
     190           0 :       case ExprType::Void: return true; // ignoring void
     191           0 :       case ExprType::I32: return c.buffer.append("i32");
     192           0 :       case ExprType::I64: return c.buffer.append("i64");
     193           0 :       case ExprType::F32: return c.buffer.append("f32");
     194           0 :       case ExprType::F64: return c.buffer.append("f64");
     195             :       default:;
     196             :     }
     197             : 
     198           0 :     MOZ_CRASH("bad type");
     199             : }
     200             : 
     201             : static bool
     202           0 : RenderValType(WasmRenderContext& c, ValType type)
     203             : {
     204           0 :     return RenderExprType(c, ToExprType(type));
     205             : }
     206             : 
     207             : static bool
     208           0 : RenderName(WasmRenderContext& c, const AstName& name)
     209             : {
     210           0 :     return c.buffer.append(name.begin(), name.end());
     211             : }
     212             : 
     213             : static bool
     214           0 : RenderRef(WasmRenderContext& c, const AstRef& ref)
     215             : {
     216           0 :     if (ref.name().empty())
     217           0 :         return RenderInt32(c, ref.index());
     218             : 
     219           0 :     return RenderName(c, ref.name());
     220             : }
     221             : 
     222             : static bool
     223           0 : RenderBlockNameAndSignature(WasmRenderContext& c, const AstName& name, ExprType type)
     224             : {
     225           0 :     if (!name.empty()) {
     226           0 :         if (!c.buffer.append(' '))
     227           0 :             return false;
     228             : 
     229           0 :         if (!RenderName(c, name))
     230           0 :             return false;
     231             :     }
     232             : 
     233           0 :     if (!IsVoid(type)) {
     234           0 :         if (!c.buffer.append(' '))
     235           0 :             return false;
     236             : 
     237           0 :         if (!RenderExprType(c, type))
     238           0 :             return false;
     239             :     }
     240             : 
     241           0 :     return true;
     242             : }
     243             : 
     244             : static bool
     245             : RenderExpr(WasmRenderContext& c, AstExpr& expr, bool newLine = true);
     246             : 
     247             : #define MAP_AST_EXPR(c, expr)                                                         \
     248             :     if (c.maybeSourceMap) {                                                           \
     249             :         uint32_t lineno = c.buffer.lineno();                                          \
     250             :         uint32_t column = c.buffer.column();                                          \
     251             :         if (!c.maybeSourceMap->exprlocs().emplaceBack(lineno, column, expr.offset())) \
     252             :             return false;                                                             \
     253             :     }
     254             : 
     255             : /*****************************************************************************/
     256             : // binary format parsing and rendering
     257             : 
     258             : static bool
     259           0 : RenderNop(WasmRenderContext& c, AstNop& nop)
     260             : {
     261           0 :     if (!RenderIndent(c))
     262           0 :         return false;
     263           0 :     MAP_AST_EXPR(c, nop);
     264           0 :     return c.buffer.append("nop");
     265             : }
     266             : 
     267             : static bool
     268           0 : RenderDrop(WasmRenderContext& c, AstDrop& drop)
     269             : {
     270           0 :     if (!RenderExpr(c, drop.value()))
     271           0 :         return false;
     272             : 
     273           0 :     if (!RenderIndent(c))
     274           0 :         return false;
     275           0 :     MAP_AST_EXPR(c, drop);
     276           0 :     return c.buffer.append("drop");
     277             : }
     278             : 
     279             : static bool
     280           0 : RenderUnreachable(WasmRenderContext& c, AstUnreachable& unreachable)
     281             : {
     282           0 :     if (!RenderIndent(c))
     283           0 :         return false;
     284           0 :     MAP_AST_EXPR(c, unreachable);
     285           0 :     return c.buffer.append("unreachable");
     286             : }
     287             : 
     288             : static bool
     289           0 : RenderCallArgs(WasmRenderContext& c, const AstExprVector& args)
     290             : {
     291           0 :     for (uint32_t i = 0; i < args.length(); i++) {
     292           0 :         if (!RenderExpr(c, *args[i]))
     293           0 :             return false;
     294             :     }
     295             : 
     296           0 :     return true;
     297             : }
     298             : 
     299             : static bool
     300           0 : RenderCall(WasmRenderContext& c, AstCall& call)
     301             : {
     302           0 :     if (!RenderCallArgs(c, call.args()))
     303           0 :         return false;
     304             : 
     305           0 :     if (!RenderIndent(c))
     306           0 :         return false;
     307             : 
     308           0 :     MAP_AST_EXPR(c, call);
     309           0 :     if (call.op() == Op::Call) {
     310           0 :         if (!c.buffer.append("call "))
     311           0 :             return false;
     312             :     } else {
     313           0 :         return Fail(c, "unexpected operator");
     314             :     }
     315             : 
     316           0 :     return RenderRef(c, call.func());
     317             : }
     318             : 
     319             : static bool
     320           0 : RenderCallIndirect(WasmRenderContext& c, AstCallIndirect& call)
     321             : {
     322           0 :     if (!RenderCallArgs(c, call.args()))
     323           0 :         return false;
     324             : 
     325           0 :     if (!RenderExpr(c, *call.index()))
     326           0 :         return false;
     327             : 
     328           0 :     if (!RenderIndent(c))
     329           0 :         return false;
     330             : 
     331           0 :     MAP_AST_EXPR(c, call);
     332           0 :     if (!c.buffer.append("call_indirect "))
     333           0 :         return false;
     334           0 :     return RenderRef(c, call.sig());
     335             : }
     336             : 
     337             : static bool
     338           0 : RenderConst(WasmRenderContext& c, AstConst& cst)
     339             : {
     340           0 :     if (!RenderIndent(c))
     341           0 :         return false;
     342             : 
     343           0 :     MAP_AST_EXPR(c, cst);
     344           0 :     if (!RenderValType(c, cst.val().type()))
     345           0 :         return false;
     346           0 :     if (!c.buffer.append(".const "))
     347           0 :         return false;
     348             : 
     349           0 :     switch (ToExprType(cst.val().type())) {
     350             :       case ExprType::I32:
     351           0 :         return RenderInt32(c, (int32_t)cst.val().i32());
     352             :       case ExprType::I64:
     353           0 :         return RenderInt64(c, (int64_t)cst.val().i64());
     354             :       case ExprType::F32:
     355           0 :         return RenderFloat32(c, cst.val().f32());
     356             :       case ExprType::F64:
     357           0 :         return RenderDouble(c, cst.val().f64());
     358             :       default:
     359           0 :         break;
     360             :     }
     361             : 
     362           0 :     return false;
     363             : }
     364             : 
     365             : static bool
     366           0 : RenderGetLocal(WasmRenderContext& c, AstGetLocal& gl)
     367             : {
     368           0 :     if (!RenderIndent(c))
     369           0 :         return false;
     370             : 
     371           0 :     MAP_AST_EXPR(c, gl);
     372           0 :     if (!c.buffer.append("get_local "))
     373           0 :         return false;
     374           0 :     return RenderRef(c, gl.local());
     375             : }
     376             : 
     377             : static bool
     378           0 : RenderSetLocal(WasmRenderContext& c, AstSetLocal& sl)
     379             : {
     380           0 :     if (!RenderExpr(c, sl.value()))
     381           0 :         return false;
     382             : 
     383           0 :     if (!RenderIndent(c))
     384           0 :         return false;
     385             : 
     386           0 :     MAP_AST_EXPR(c, sl);
     387           0 :     if (!c.buffer.append("set_local "))
     388           0 :         return false;
     389           0 :     return RenderRef(c, sl.local());
     390             : }
     391             : 
     392             : static bool
     393           0 : RenderTeeLocal(WasmRenderContext& c, AstTeeLocal& tl)
     394             : {
     395           0 :     if (!RenderExpr(c, tl.value()))
     396           0 :         return false;
     397             : 
     398           0 :     if (!RenderIndent(c))
     399           0 :         return false;
     400             : 
     401           0 :     MAP_AST_EXPR(c, tl);
     402           0 :     if (!c.buffer.append("tee_local "))
     403           0 :         return false;
     404           0 :     return RenderRef(c, tl.local());
     405             : }
     406             : 
     407             : static bool
     408           0 : RenderGetGlobal(WasmRenderContext& c, AstGetGlobal& gg)
     409             : {
     410           0 :     if (!RenderIndent(c))
     411           0 :         return false;
     412             : 
     413           0 :     MAP_AST_EXPR(c, gg);
     414           0 :     if (!c.buffer.append("get_global "))
     415           0 :         return false;
     416           0 :     return RenderRef(c, gg.global());
     417             : }
     418             : 
     419             : static bool
     420           0 : RenderSetGlobal(WasmRenderContext& c, AstSetGlobal& sg)
     421             : {
     422           0 :     if (!RenderExpr(c, sg.value()))
     423           0 :         return false;
     424             : 
     425           0 :     if (!RenderIndent(c))
     426           0 :         return false;
     427             : 
     428           0 :     MAP_AST_EXPR(c, sg);
     429           0 :     if (!c.buffer.append("set_global "))
     430           0 :         return false;
     431           0 :     return RenderRef(c, sg.global());
     432             : }
     433             : 
     434             : static bool
     435           0 : RenderExprList(WasmRenderContext& c, const AstExprVector& exprs, uint32_t startAt = 0)
     436             : {
     437           0 :     for (uint32_t i = startAt; i < exprs.length(); i++) {
     438           0 :         if (!RenderExpr(c, *exprs[i]))
     439           0 :             return false;
     440             :     }
     441           0 :     return true;
     442             : }
     443             : 
     444             : static bool
     445           0 : RenderBlock(WasmRenderContext& c, AstBlock& block, bool isInline = false)
     446             : {
     447           0 :     if (!isInline && !RenderIndent(c))
     448           0 :         return false;
     449             : 
     450           0 :     MAP_AST_EXPR(c, block);
     451           0 :     if (block.op() == Op::Block) {
     452           0 :         if (!c.buffer.append("block"))
     453           0 :             return false;
     454           0 :     } else if (block.op() == Op::Loop) {
     455           0 :         if (!c.buffer.append("loop"))
     456           0 :             return false;
     457             :     } else {
     458           0 :         return Fail(c, "unexpected block kind");
     459             :     }
     460             : 
     461           0 :     if (!RenderBlockNameAndSignature(c, block.name(), block.type()))
     462           0 :         return false;
     463             : 
     464           0 :     uint32_t startAtSubExpr = 0;
     465             : 
     466             :     // If there is a stack of blocks, print them all inline.
     467           0 :     if (block.op() == Op::Block &&
     468           0 :         block.exprs().length() &&
     469           0 :         block.exprs()[0]->kind() == AstExprKind::Block &&
     470           0 :         block.exprs()[0]->as<AstBlock>().op() == Op::Block)
     471             :     {
     472           0 :         if (!c.buffer.append(' '))
     473           0 :             return false;
     474             : 
     475             :         // Render the first inner expr (block) at the same indent level, but
     476             :         // next instructions one level further.
     477           0 :         if (!RenderBlock(c, block.exprs()[0]->as<AstBlock>(), /* isInline */ true))
     478           0 :             return false;
     479             : 
     480           0 :         startAtSubExpr = 1;
     481             :     }
     482             : 
     483           0 :     if (!c.buffer.append('\n'))
     484           0 :         return false;
     485             : 
     486           0 :     c.indent++;
     487           0 :     if (!RenderExprList(c, block.exprs(), startAtSubExpr))
     488           0 :         return false;
     489           0 :     c.indent--;
     490             : 
     491           0 :     return RenderIndent(c) &&
     492           0 :            c.buffer.append("end ") &&
     493           0 :            RenderName(c, block.name());
     494             : }
     495             : 
     496             : static bool
     497           0 : RenderFirst(WasmRenderContext& c, AstFirst& first)
     498             : {
     499           0 :     return RenderExprList(c, first.exprs());
     500             : }
     501             : 
     502             : static bool
     503           0 : RenderCurrentMemory(WasmRenderContext& c, AstCurrentMemory& cm)
     504             : {
     505           0 :     if (!RenderIndent(c))
     506           0 :         return false;
     507             : 
     508           0 :     return c.buffer.append("current_memory\n");
     509             : }
     510             : 
     511             : static bool
     512           0 : RenderGrowMemory(WasmRenderContext& c, AstGrowMemory& gm)
     513             : {
     514           0 :     if (!RenderExpr(c, *gm.operand()))
     515           0 :         return false;
     516             : 
     517           0 :     if (!RenderIndent(c))
     518           0 :         return false;
     519             : 
     520           0 :     MAP_AST_EXPR(c, gm);
     521           0 :     return c.buffer.append("grow_memory\n");
     522             : }
     523             : 
     524             : static bool
     525           0 : RenderUnaryOperator(WasmRenderContext& c, AstUnaryOperator& unary)
     526             : {
     527           0 :     if (!RenderExpr(c, *unary.operand()))
     528           0 :         return false;
     529             : 
     530           0 :     if (!RenderIndent(c))
     531           0 :         return false;
     532             : 
     533           0 :     MAP_AST_EXPR(c, unary);
     534             :     const char* opStr;
     535           0 :     switch (unary.op()) {
     536           0 :       case Op::I32Eqz:     opStr = "i32.eqz"; break;
     537           0 :       case Op::I32Clz:     opStr = "i32.clz"; break;
     538           0 :       case Op::I32Ctz:     opStr = "i32.ctz"; break;
     539           0 :       case Op::I32Popcnt:  opStr = "i32.popcnt"; break;
     540           0 :       case Op::I64Clz:     opStr = "i64.clz"; break;
     541           0 :       case Op::I64Ctz:     opStr = "i64.ctz"; break;
     542           0 :       case Op::I64Popcnt:  opStr = "i64.popcnt"; break;
     543           0 :       case Op::F32Abs:     opStr = "f32.abs"; break;
     544           0 :       case Op::F32Neg:     opStr = "f32.neg"; break;
     545           0 :       case Op::F32Ceil:    opStr = "f32.ceil"; break;
     546           0 :       case Op::F32Floor:   opStr = "f32.floor"; break;
     547           0 :       case Op::F32Sqrt:    opStr = "f32.sqrt"; break;
     548           0 :       case Op::F32Trunc:   opStr = "f32.trunc"; break;
     549           0 :       case Op::F32Nearest: opStr = "f32.nearest"; break;
     550           0 :       case Op::F64Abs:     opStr = "f64.abs"; break;
     551           0 :       case Op::F64Neg:     opStr = "f64.neg"; break;
     552           0 :       case Op::F64Ceil:    opStr = "f64.ceil"; break;
     553           0 :       case Op::F64Floor:   opStr = "f64.floor"; break;
     554           0 :       case Op::F64Nearest: opStr = "f64.nearest"; break;
     555           0 :       case Op::F64Sqrt:    opStr = "f64.sqrt"; break;
     556           0 :       case Op::F64Trunc:   opStr = "f64.trunc"; break;
     557           0 :       default:               return Fail(c, "unexpected unary operator");
     558             :     }
     559             : 
     560           0 :     return c.buffer.append(opStr, strlen(opStr));
     561             : }
     562             : 
     563             : static bool
     564           0 : RenderBinaryOperator(WasmRenderContext& c, AstBinaryOperator& binary)
     565             : {
     566           0 :     if (!RenderExpr(c, *binary.lhs()))
     567           0 :         return false;
     568           0 :     if (!RenderExpr(c, *binary.rhs()))
     569           0 :         return false;
     570             : 
     571           0 :     if (!RenderIndent(c))
     572           0 :         return false;
     573             : 
     574           0 :     MAP_AST_EXPR(c, binary);
     575             :     const char* opStr;
     576           0 :     switch (binary.op()) {
     577           0 :       case Op::I32Add:      opStr = "i32.add"; break;
     578           0 :       case Op::I32Sub:      opStr = "i32.sub"; break;
     579           0 :       case Op::I32Mul:      opStr = "i32.mul"; break;
     580           0 :       case Op::I32DivS:     opStr = "i32.div_s"; break;
     581           0 :       case Op::I32DivU:     opStr = "i32.div_u"; break;
     582           0 :       case Op::I32RemS:     opStr = "i32.rem_s"; break;
     583           0 :       case Op::I32RemU:     opStr = "i32.rem_u"; break;
     584           0 :       case Op::I32And:      opStr = "i32.and"; break;
     585           0 :       case Op::I32Or:       opStr = "i32.or"; break;
     586           0 :       case Op::I32Xor:      opStr = "i32.xor"; break;
     587           0 :       case Op::I32Shl:      opStr = "i32.shl"; break;
     588           0 :       case Op::I32ShrS:     opStr = "i32.shr_s"; break;
     589           0 :       case Op::I32ShrU:     opStr = "i32.shr_u"; break;
     590           0 :       case Op::I32Rotl:     opStr = "i32.rotl"; break;
     591           0 :       case Op::I32Rotr:     opStr = "i32.rotr"; break;
     592           0 :       case Op::I64Add:      opStr = "i64.add"; break;
     593           0 :       case Op::I64Sub:      opStr = "i64.sub"; break;
     594           0 :       case Op::I64Mul:      opStr = "i64.mul"; break;
     595           0 :       case Op::I64DivS:     opStr = "i64.div_s"; break;
     596           0 :       case Op::I64DivU:     opStr = "i64.div_u"; break;
     597           0 :       case Op::I64RemS:     opStr = "i64.rem_s"; break;
     598           0 :       case Op::I64RemU:     opStr = "i64.rem_u"; break;
     599           0 :       case Op::I64And:      opStr = "i64.and"; break;
     600           0 :       case Op::I64Or:       opStr = "i64.or"; break;
     601           0 :       case Op::I64Xor:      opStr = "i64.xor"; break;
     602           0 :       case Op::I64Shl:      opStr = "i64.shl"; break;
     603           0 :       case Op::I64ShrS:     opStr = "i64.shr_s"; break;
     604           0 :       case Op::I64ShrU:     opStr = "i64.shr_u"; break;
     605           0 :       case Op::I64Rotl:     opStr = "i64.rotl"; break;
     606           0 :       case Op::I64Rotr:     opStr = "i64.rotr"; break;
     607           0 :       case Op::F32Add:      opStr = "f32.add"; break;
     608           0 :       case Op::F32Sub:      opStr = "f32.sub"; break;
     609           0 :       case Op::F32Mul:      opStr = "f32.mul"; break;
     610           0 :       case Op::F32Div:      opStr = "f32.div"; break;
     611           0 :       case Op::F32Min:      opStr = "f32.min"; break;
     612           0 :       case Op::F32Max:      opStr = "f32.max"; break;
     613           0 :       case Op::F32CopySign: opStr = "f32.copysign"; break;
     614           0 :       case Op::F64Add:      opStr = "f64.add"; break;
     615           0 :       case Op::F64Sub:      opStr = "f64.sub"; break;
     616           0 :       case Op::F64Mul:      opStr = "f64.mul"; break;
     617           0 :       case Op::F64Div:      opStr = "f64.div"; break;
     618           0 :       case Op::F64Min:      opStr = "f64.min"; break;
     619           0 :       case Op::F64Max:      opStr = "f64.max"; break;
     620           0 :       case Op::F64CopySign: opStr = "f64.copysign"; break;
     621           0 :       default:                return Fail(c, "unexpected binary operator");
     622             :     }
     623             : 
     624           0 :     return c.buffer.append(opStr, strlen(opStr));
     625             : }
     626             : 
     627             : static bool
     628           0 : RenderTernaryOperator(WasmRenderContext& c, AstTernaryOperator& ternary)
     629             : {
     630           0 :     if (!RenderExpr(c, *ternary.op0()))
     631           0 :         return false;
     632           0 :     if (!RenderExpr(c, *ternary.op1()))
     633           0 :         return false;
     634           0 :     if (!RenderExpr(c, *ternary.op2()))
     635           0 :         return false;
     636             : 
     637           0 :     if (!RenderIndent(c))
     638           0 :         return false;
     639             : 
     640           0 :     MAP_AST_EXPR(c, ternary);
     641             :     const char* opStr;
     642           0 :     switch (ternary.op()) {
     643           0 :       case Op::Select: opStr = "select"; break;
     644           0 :       default:           return Fail(c, "unexpected ternary operator");
     645             :     }
     646             : 
     647           0 :     return c.buffer.append(opStr, strlen(opStr));
     648             : }
     649             : 
     650             : static bool
     651           0 : RenderComparisonOperator(WasmRenderContext& c, AstComparisonOperator& comp)
     652             : {
     653           0 :     if (!RenderExpr(c, *comp.lhs()))
     654           0 :         return false;
     655           0 :     if (!RenderExpr(c, *comp.rhs()))
     656           0 :         return false;
     657             : 
     658           0 :     if (!RenderIndent(c))
     659           0 :         return false;
     660             : 
     661           0 :     MAP_AST_EXPR(c, comp);
     662             :     const char* opStr;
     663           0 :     switch (comp.op()) {
     664           0 :       case Op::I32Eq:  opStr = "i32.eq"; break;
     665           0 :       case Op::I32Ne:  opStr = "i32.ne"; break;
     666           0 :       case Op::I32LtS: opStr = "i32.lt_s"; break;
     667           0 :       case Op::I32LtU: opStr = "i32.lt_u"; break;
     668           0 :       case Op::I32LeS: opStr = "i32.le_s"; break;
     669           0 :       case Op::I32LeU: opStr = "i32.le_u"; break;
     670           0 :       case Op::I32GtS: opStr = "i32.gt_s"; break;
     671           0 :       case Op::I32GtU: opStr = "i32.gt_u"; break;
     672           0 :       case Op::I32GeS: opStr = "i32.ge_s"; break;
     673           0 :       case Op::I32GeU: opStr = "i32.ge_u"; break;
     674           0 :       case Op::I64Eq:  opStr = "i64.eq"; break;
     675           0 :       case Op::I64Ne:  opStr = "i64.ne"; break;
     676           0 :       case Op::I64LtS: opStr = "i64.lt_s"; break;
     677           0 :       case Op::I64LtU: opStr = "i64.lt_u"; break;
     678           0 :       case Op::I64LeS: opStr = "i64.le_s"; break;
     679           0 :       case Op::I64LeU: opStr = "i64.le_u"; break;
     680           0 :       case Op::I64GtS: opStr = "i64.gt_s"; break;
     681           0 :       case Op::I64GtU: opStr = "i64.gt_u"; break;
     682           0 :       case Op::I64GeS: opStr = "i64.ge_s"; break;
     683           0 :       case Op::I64GeU: opStr = "i64.ge_u"; break;
     684           0 :       case Op::F32Eq:  opStr = "f32.eq"; break;
     685           0 :       case Op::F32Ne:  opStr = "f32.ne"; break;
     686           0 :       case Op::F32Lt:  opStr = "f32.lt"; break;
     687           0 :       case Op::F32Le:  opStr = "f32.le"; break;
     688           0 :       case Op::F32Gt:  opStr = "f32.gt"; break;
     689           0 :       case Op::F32Ge:  opStr = "f32.ge"; break;
     690           0 :       case Op::F64Eq:  opStr = "f64.eq"; break;
     691           0 :       case Op::F64Ne:  opStr = "f64.ne"; break;
     692           0 :       case Op::F64Lt:  opStr = "f64.lt"; break;
     693           0 :       case Op::F64Le:  opStr = "f64.le"; break;
     694           0 :       case Op::F64Gt:  opStr = "f64.gt"; break;
     695           0 :       case Op::F64Ge:  opStr = "f64.ge"; break;
     696           0 :       default:           return Fail(c, "unexpected comparison operator");
     697             :     }
     698             : 
     699           0 :     return c.buffer.append(opStr, strlen(opStr));
     700             : }
     701             : 
     702             : static bool
     703           0 : RenderConversionOperator(WasmRenderContext& c, AstConversionOperator& conv)
     704             : {
     705           0 :     if (!RenderExpr(c, *conv.operand()))
     706           0 :         return false;
     707             : 
     708           0 :     if (!RenderIndent(c))
     709           0 :         return false;
     710             : 
     711           0 :     MAP_AST_EXPR(c, conv);
     712             :     const char* opStr;
     713           0 :     switch (conv.op()) {
     714           0 :       case Op::I32WrapI64:        opStr = "i32.wrap/i64"; break;
     715           0 :       case Op::I32TruncSF32:      opStr = "i32.trunc_s/f32"; break;
     716           0 :       case Op::I32TruncUF32:      opStr = "i32.trunc_u/f32"; break;
     717           0 :       case Op::I32ReinterpretF32: opStr = "i32.reinterpret/f32"; break;
     718           0 :       case Op::I32TruncSF64:      opStr = "i32.trunc_s/f64"; break;
     719           0 :       case Op::I32TruncUF64:      opStr = "i32.trunc_u/f64"; break;
     720           0 :       case Op::I64ExtendSI32:     opStr = "i64.extend_s/i32"; break;
     721           0 :       case Op::I64ExtendUI32:     opStr = "i64.extend_u/i32"; break;
     722           0 :       case Op::I64TruncSF32:      opStr = "i64.trunc_s/f32"; break;
     723           0 :       case Op::I64TruncUF32:      opStr = "i64.trunc_u/f32"; break;
     724           0 :       case Op::I64TruncSF64:      opStr = "i64.trunc_s/f64"; break;
     725           0 :       case Op::I64TruncUF64:      opStr = "i64.trunc_u/f64"; break;
     726           0 :       case Op::I64ReinterpretF64: opStr = "i64.reinterpret/f64"; break;
     727           0 :       case Op::F32ConvertSI32:    opStr = "f32.convert_s/i32"; break;
     728           0 :       case Op::F32ConvertUI32:    opStr = "f32.convert_u/i32"; break;
     729           0 :       case Op::F32ReinterpretI32: opStr = "f32.reinterpret/i32"; break;
     730           0 :       case Op::F32ConvertSI64:    opStr = "f32.convert_s/i64"; break;
     731           0 :       case Op::F32ConvertUI64:    opStr = "f32.convert_u/i64"; break;
     732           0 :       case Op::F32DemoteF64:      opStr = "f32.demote/f64"; break;
     733           0 :       case Op::F64ConvertSI32:    opStr = "f64.convert_s/i32"; break;
     734           0 :       case Op::F64ConvertUI32:    opStr = "f64.convert_u/i32"; break;
     735           0 :       case Op::F64ConvertSI64:    opStr = "f64.convert_s/i64"; break;
     736           0 :       case Op::F64ConvertUI64:    opStr = "f64.convert_u/i64"; break;
     737           0 :       case Op::F64ReinterpretI64: opStr = "f64.reinterpret/i64"; break;
     738           0 :       case Op::F64PromoteF32:     opStr = "f64.promote/f32"; break;
     739           0 :       case Op::I32Eqz:            opStr = "i32.eqz"; break;
     740           0 :       case Op::I64Eqz:            opStr = "i64.eqz"; break;
     741           0 :       default:                      return Fail(c, "unexpected conversion operator");
     742             :     }
     743           0 :     return c.buffer.append(opStr, strlen(opStr));
     744             : }
     745             : 
     746             : static bool
     747           0 : RenderIf(WasmRenderContext& c, AstIf& if_)
     748             : {
     749           0 :     if (!RenderExpr(c, if_.cond()))
     750           0 :         return false;
     751             : 
     752           0 :     if (!RenderIndent(c))
     753           0 :         return false;
     754             : 
     755           0 :     MAP_AST_EXPR(c, if_);
     756           0 :     if (!c.buffer.append("if"))
     757           0 :         return false;
     758           0 :     if (!RenderBlockNameAndSignature(c, if_.name(), if_.type()))
     759           0 :         return false;
     760           0 :     if (!c.buffer.append('\n'))
     761           0 :         return false;
     762             : 
     763           0 :     c.indent++;
     764           0 :     if (!RenderExprList(c, if_.thenExprs()))
     765           0 :         return false;
     766           0 :     c.indent--;
     767             : 
     768           0 :     if (if_.hasElse()) {
     769           0 :         if (!RenderIndent(c))
     770           0 :             return false;
     771             : 
     772           0 :         if (!c.buffer.append("else\n"))
     773           0 :             return false;
     774             : 
     775           0 :         c.indent++;
     776           0 :         if (!RenderExprList(c, if_.elseExprs()))
     777           0 :             return false;
     778           0 :         c.indent--;
     779             :     }
     780             : 
     781           0 :     if (!RenderIndent(c))
     782           0 :         return false;
     783             : 
     784           0 :     return c.buffer.append("end");
     785             : }
     786             : 
     787             : static bool
     788           0 : RenderLoadStoreBase(WasmRenderContext& c, const AstLoadStoreAddress& lsa)
     789             : {
     790           0 :     return RenderExpr(c, lsa.base());
     791             : }
     792             : 
     793             : static bool
     794           0 : RenderLoadStoreAddress(WasmRenderContext& c, const AstLoadStoreAddress& lsa, uint32_t defaultAlignLog2)
     795             : {
     796           0 :     if (lsa.offset() != 0) {
     797           0 :         if (!c.buffer.append(" offset="))
     798           0 :             return false;
     799           0 :         if (!RenderInt32(c, lsa.offset()))
     800           0 :             return false;
     801             :     }
     802             : 
     803           0 :     uint32_t alignLog2 = lsa.flags();
     804           0 :     if (defaultAlignLog2 != alignLog2) {
     805           0 :         if (!c.buffer.append(" align="))
     806           0 :             return false;
     807           0 :         if (!RenderInt32(c, 1 << alignLog2))
     808           0 :             return false;
     809             :     }
     810             : 
     811           0 :     return true;
     812             : }
     813             : 
     814             : static bool
     815           0 : RenderLoad(WasmRenderContext& c, AstLoad& load)
     816             : {
     817           0 :     if (!RenderLoadStoreBase(c, load.address()))
     818           0 :         return false;
     819             : 
     820           0 :     if (!RenderIndent(c))
     821           0 :         return false;
     822             : 
     823           0 :     MAP_AST_EXPR(c, load);
     824             :     uint32_t defaultAlignLog2;
     825           0 :     switch (load.op()) {
     826             :       case Op::I32Load8S:
     827           0 :         if (!c.buffer.append("i32.load8_s"))
     828           0 :             return false;
     829           0 :         defaultAlignLog2 = 0;
     830           0 :         break;
     831             :       case Op::I64Load8S:
     832           0 :         if (!c.buffer.append("i64.load8_s"))
     833           0 :             return false;
     834           0 :         defaultAlignLog2 = 0;
     835           0 :         break;
     836             :       case Op::I32Load8U:
     837           0 :         if (!c.buffer.append("i32.load8_u"))
     838           0 :             return false;
     839           0 :         defaultAlignLog2 = 0;
     840           0 :         break;
     841             :       case Op::I64Load8U:
     842           0 :         if (!c.buffer.append("i64.load8_u"))
     843           0 :             return false;
     844           0 :         defaultAlignLog2 = 0;
     845           0 :         break;
     846             :       case Op::I32Load16S:
     847           0 :         if (!c.buffer.append("i32.load16_s"))
     848           0 :             return false;
     849           0 :         defaultAlignLog2 = 1;
     850           0 :         break;
     851             :       case Op::I64Load16S:
     852           0 :         if (!c.buffer.append("i64.load16_s"))
     853           0 :             return false;
     854           0 :         defaultAlignLog2 = 1;
     855           0 :         break;
     856             :       case Op::I32Load16U:
     857           0 :         if (!c.buffer.append("i32.load16_u"))
     858           0 :             return false;
     859           0 :         defaultAlignLog2 = 1;
     860           0 :         break;
     861             :       case Op::I64Load16U:
     862           0 :         if (!c.buffer.append("i64.load16_u"))
     863           0 :             return false;
     864           0 :         defaultAlignLog2 = 1;
     865           0 :         break;
     866             :       case Op::I64Load32S:
     867           0 :         if (!c.buffer.append("i64.load32_s"))
     868           0 :             return false;
     869           0 :         defaultAlignLog2 = 2;
     870           0 :         break;
     871             :       case Op::I64Load32U:
     872           0 :         if (!c.buffer.append("i64.load32_u"))
     873           0 :             return false;
     874           0 :         defaultAlignLog2 = 2;
     875           0 :         break;
     876             :       case Op::I32Load:
     877           0 :         if (!c.buffer.append("i32.load"))
     878           0 :             return false;
     879           0 :         defaultAlignLog2 = 2;
     880           0 :         break;
     881             :       case Op::I64Load:
     882           0 :         if (!c.buffer.append("i64.load"))
     883           0 :             return false;
     884           0 :         defaultAlignLog2 = 3;
     885           0 :         break;
     886             :       case Op::F32Load:
     887           0 :         if (!c.buffer.append("f32.load"))
     888           0 :             return false;
     889           0 :         defaultAlignLog2 = 2;
     890           0 :         break;
     891             :       case Op::F64Load:
     892           0 :         if (!c.buffer.append("f64.load"))
     893           0 :             return false;
     894           0 :         defaultAlignLog2 = 3;
     895           0 :         break;
     896             :       default:
     897           0 :         return Fail(c, "unexpected load operator");
     898             :     }
     899             : 
     900           0 :     return RenderLoadStoreAddress(c, load.address(), defaultAlignLog2);
     901             : }
     902             : 
     903             : static bool
     904           0 : RenderStore(WasmRenderContext& c, AstStore& store)
     905             : {
     906           0 :     if (!RenderLoadStoreBase(c, store.address()))
     907           0 :         return false;
     908             : 
     909           0 :     if (!RenderExpr(c, store.value()))
     910           0 :         return false;
     911             : 
     912           0 :     if (!RenderIndent(c))
     913           0 :         return false;
     914             : 
     915           0 :     MAP_AST_EXPR(c, store);
     916             :     uint32_t defaultAlignLog2;
     917           0 :     switch (store.op()) {
     918             :       case Op::I32Store8:
     919           0 :         if (!c.buffer.append("i32.store8"))
     920           0 :             return false;
     921           0 :         defaultAlignLog2 = 0;
     922           0 :         break;
     923             :       case Op::I64Store8:
     924           0 :         if (!c.buffer.append("i64.store8"))
     925           0 :             return false;
     926           0 :         defaultAlignLog2 = 0;
     927           0 :         break;
     928             :       case Op::I32Store16:
     929           0 :         if (!c.buffer.append("i32.store16"))
     930           0 :             return false;
     931           0 :         defaultAlignLog2 = 1;
     932           0 :         break;
     933             :       case Op::I64Store16:
     934           0 :         if (!c.buffer.append("i64.store16"))
     935           0 :             return false;
     936           0 :         defaultAlignLog2 = 1;
     937           0 :         break;
     938             :       case Op::I64Store32:
     939           0 :         if (!c.buffer.append("i64.store32"))
     940           0 :             return false;
     941           0 :         defaultAlignLog2 = 2;
     942           0 :         break;
     943             :       case Op::I32Store:
     944           0 :         if (!c.buffer.append("i32.store"))
     945           0 :             return false;
     946           0 :         defaultAlignLog2 = 2;
     947           0 :         break;
     948             :       case Op::I64Store:
     949           0 :         if (!c.buffer.append("i64.store"))
     950           0 :             return false;
     951           0 :         defaultAlignLog2 = 3;
     952           0 :         break;
     953             :       case Op::F32Store:
     954           0 :         if (!c.buffer.append("f32.store"))
     955           0 :             return false;
     956           0 :         defaultAlignLog2 = 2;
     957           0 :         break;
     958             :       case Op::F64Store:
     959           0 :         if (!c.buffer.append("f64.store"))
     960           0 :             return false;
     961           0 :         defaultAlignLog2 = 3;
     962           0 :         break;
     963             :       default:
     964           0 :         return Fail(c, "unexpected store operator");
     965             :     }
     966             : 
     967           0 :     return RenderLoadStoreAddress(c, store.address(), defaultAlignLog2);
     968             : }
     969             : 
     970             : static bool
     971           0 : RenderBranch(WasmRenderContext& c, AstBranch& branch)
     972             : {
     973           0 :     Op op = branch.op();
     974           0 :     MOZ_ASSERT(op == Op::BrIf || op == Op::Br);
     975             : 
     976           0 :     if (op == Op::BrIf) {
     977           0 :         if (!RenderExpr(c, branch.cond()))
     978           0 :             return false;
     979             :     }
     980             : 
     981           0 :     if (branch.maybeValue()) {
     982           0 :         if (!RenderExpr(c, *(branch.maybeValue())))
     983           0 :             return false;
     984             :     }
     985             : 
     986           0 :     if (!RenderIndent(c))
     987           0 :         return false;
     988             : 
     989           0 :     MAP_AST_EXPR(c, branch);
     990           0 :     if (op == Op::BrIf ? !c.buffer.append("br_if ") : !c.buffer.append("br "))
     991           0 :         return false;
     992             : 
     993           0 :     return RenderRef(c, branch.target());
     994             : }
     995             : 
     996             : static bool
     997           0 : RenderBrTable(WasmRenderContext& c, AstBranchTable& table)
     998             : {
     999           0 :     if (table.maybeValue()) {
    1000           0 :         if (!RenderExpr(c, *(table.maybeValue())))
    1001           0 :             return false;
    1002             :     }
    1003             : 
    1004             :     // Index
    1005           0 :     if (!RenderExpr(c, table.index()))
    1006           0 :         return false;
    1007             : 
    1008           0 :     if (!RenderIndent(c))
    1009           0 :         return false;
    1010             : 
    1011           0 :     MAP_AST_EXPR(c, table);
    1012           0 :     if (!c.buffer.append("br_table "))
    1013           0 :         return false;
    1014             : 
    1015           0 :     uint32_t tableLength = table.table().length();
    1016           0 :     for (uint32_t i = 0; i < tableLength; i++) {
    1017           0 :         if (!RenderRef(c, table.table()[i]))
    1018           0 :             return false;
    1019             : 
    1020           0 :         if (!c.buffer.append(" "))
    1021           0 :             return false;
    1022             :     }
    1023             : 
    1024           0 :     return RenderRef(c, table.def());
    1025             : }
    1026             : 
    1027             : static bool
    1028           0 : RenderReturn(WasmRenderContext& c, AstReturn& ret)
    1029             : {
    1030           0 :     if (ret.maybeExpr()) {
    1031           0 :         if (!RenderExpr(c, *(ret.maybeExpr())))
    1032           0 :             return false;
    1033             :     }
    1034             : 
    1035           0 :     if (!RenderIndent(c))
    1036           0 :         return false;
    1037             : 
    1038           0 :     MAP_AST_EXPR(c, ret);
    1039           0 :     return c.buffer.append("return");
    1040             : }
    1041             : 
    1042             : static bool
    1043           0 : RenderExpr(WasmRenderContext& c, AstExpr& expr, bool newLine /* = true */)
    1044             : {
    1045           0 :     switch (expr.kind()) {
    1046             :       case AstExprKind::Drop:
    1047           0 :         if (!RenderDrop(c, expr.as<AstDrop>()))
    1048           0 :             return false;
    1049           0 :         break;
    1050             :       case AstExprKind::Nop:
    1051           0 :         if (!RenderNop(c, expr.as<AstNop>()))
    1052           0 :             return false;
    1053           0 :         break;
    1054             :       case AstExprKind::Unreachable:
    1055           0 :         if (!RenderUnreachable(c, expr.as<AstUnreachable>()))
    1056           0 :             return false;
    1057           0 :         break;
    1058             :       case AstExprKind::Call:
    1059           0 :         if (!RenderCall(c, expr.as<AstCall>()))
    1060           0 :             return false;
    1061           0 :         break;
    1062             :       case AstExprKind::CallIndirect:
    1063           0 :         if (!RenderCallIndirect(c, expr.as<AstCallIndirect>()))
    1064           0 :             return false;
    1065           0 :         break;
    1066             :       case AstExprKind::Const:
    1067           0 :         if (!RenderConst(c, expr.as<AstConst>()))
    1068           0 :             return false;
    1069           0 :         break;
    1070             :       case AstExprKind::GetLocal:
    1071           0 :         if (!RenderGetLocal(c, expr.as<AstGetLocal>()))
    1072           0 :             return false;
    1073           0 :         break;
    1074             :       case AstExprKind::SetLocal:
    1075           0 :         if (!RenderSetLocal(c, expr.as<AstSetLocal>()))
    1076           0 :             return false;
    1077           0 :         break;
    1078             :       case AstExprKind::GetGlobal:
    1079           0 :         if (!RenderGetGlobal(c, expr.as<AstGetGlobal>()))
    1080           0 :             return false;
    1081           0 :         break;
    1082             :       case AstExprKind::SetGlobal:
    1083           0 :         if (!RenderSetGlobal(c, expr.as<AstSetGlobal>()))
    1084           0 :             return false;
    1085           0 :         break;
    1086             :       case AstExprKind::TeeLocal:
    1087           0 :         if (!RenderTeeLocal(c, expr.as<AstTeeLocal>()))
    1088           0 :             return false;
    1089           0 :         break;
    1090             :       case AstExprKind::Block:
    1091           0 :         if (!RenderBlock(c, expr.as<AstBlock>()))
    1092           0 :             return false;
    1093           0 :         break;
    1094             :       case AstExprKind::If:
    1095           0 :         if (!RenderIf(c, expr.as<AstIf>()))
    1096           0 :             return false;
    1097           0 :         break;
    1098             :       case AstExprKind::UnaryOperator:
    1099           0 :         if (!RenderUnaryOperator(c, expr.as<AstUnaryOperator>()))
    1100           0 :             return false;
    1101           0 :         break;
    1102             :       case AstExprKind::BinaryOperator:
    1103           0 :         if (!RenderBinaryOperator(c, expr.as<AstBinaryOperator>()))
    1104           0 :             return false;
    1105           0 :         break;
    1106             :       case AstExprKind::TernaryOperator:
    1107           0 :         if (!RenderTernaryOperator(c, expr.as<AstTernaryOperator>()))
    1108           0 :             return false;
    1109           0 :         break;
    1110             :       case AstExprKind::ComparisonOperator:
    1111           0 :         if (!RenderComparisonOperator(c, expr.as<AstComparisonOperator>()))
    1112           0 :             return false;
    1113           0 :         break;
    1114             :       case AstExprKind::ConversionOperator:
    1115           0 :         if (!RenderConversionOperator(c, expr.as<AstConversionOperator>()))
    1116           0 :             return false;
    1117           0 :         break;
    1118             :       case AstExprKind::Load:
    1119           0 :         if (!RenderLoad(c, expr.as<AstLoad>()))
    1120           0 :             return false;
    1121           0 :         break;
    1122             :       case AstExprKind::Store:
    1123           0 :         if (!RenderStore(c, expr.as<AstStore>()))
    1124           0 :             return false;
    1125           0 :         break;
    1126             :       case AstExprKind::Branch:
    1127           0 :         if (!RenderBranch(c, expr.as<AstBranch>()))
    1128           0 :             return false;
    1129           0 :         break;
    1130             :       case AstExprKind::BranchTable:
    1131           0 :         if (!RenderBrTable(c, expr.as<AstBranchTable>()))
    1132           0 :             return false;
    1133           0 :         break;
    1134             :       case AstExprKind::Return:
    1135           0 :         if (!RenderReturn(c, expr.as<AstReturn>()))
    1136           0 :             return false;
    1137           0 :         break;
    1138             :       case AstExprKind::First:
    1139           0 :         newLine = false;
    1140           0 :         if (!RenderFirst(c, expr.as<AstFirst>()))
    1141           0 :             return false;
    1142           0 :         break;
    1143             :       case AstExprKind::CurrentMemory:
    1144           0 :         if (!RenderCurrentMemory(c, expr.as<AstCurrentMemory>()))
    1145           0 :             return false;
    1146           0 :         break;
    1147             :       case AstExprKind::GrowMemory:
    1148           0 :         if (!RenderGrowMemory(c, expr.as<AstGrowMemory>()))
    1149           0 :             return false;
    1150           0 :         break;
    1151             :       default:
    1152           0 :         MOZ_CRASH("Bad AstExprKind");
    1153             :     }
    1154             : 
    1155           0 :     return !newLine || c.buffer.append("\n");
    1156             : }
    1157             : 
    1158             : static bool
    1159           0 : RenderSignature(WasmRenderContext& c, const AstSig& sig, const AstNameVector* maybeLocals = nullptr)
    1160             : {
    1161           0 :     uint32_t paramsNum = sig.args().length();
    1162             : 
    1163           0 :     if (maybeLocals) {
    1164           0 :         for (uint32_t i = 0; i < paramsNum; i++) {
    1165           0 :             if (!c.buffer.append(" (param "))
    1166           0 :                 return false;
    1167           0 :             const AstName& name = (*maybeLocals)[i];
    1168           0 :             if (!name.empty()) {
    1169           0 :                 if (!RenderName(c, name))
    1170           0 :                     return false;
    1171           0 :                 if (!c.buffer.append(" "))
    1172           0 :                     return false;
    1173             :             }
    1174           0 :             ValType arg = sig.args()[i];
    1175           0 :             if (!RenderValType(c, arg))
    1176           0 :                 return false;
    1177           0 :             if (!c.buffer.append(")"))
    1178           0 :                 return false;
    1179             :         }
    1180           0 :     } else if (paramsNum > 0) {
    1181           0 :         if (!c.buffer.append(" (param"))
    1182           0 :             return false;
    1183           0 :         for (uint32_t i = 0; i < paramsNum; i++) {
    1184           0 :             if (!c.buffer.append(" "))
    1185           0 :                 return false;
    1186           0 :             ValType arg = sig.args()[i];
    1187           0 :             if (!RenderValType(c, arg))
    1188           0 :                 return false;
    1189             :         }
    1190           0 :         if (!c.buffer.append(")"))
    1191           0 :             return false;
    1192             :     }
    1193           0 :     if (sig.ret() != ExprType::Void) {
    1194           0 :         if (!c.buffer.append(" (result "))
    1195           0 :             return false;
    1196           0 :         if (!RenderExprType(c, sig.ret()))
    1197           0 :             return false;
    1198           0 :         if (!c.buffer.append(")"))
    1199           0 :             return false;
    1200             :     }
    1201           0 :     return true;
    1202             : }
    1203             : 
    1204             : static bool
    1205           0 : RenderTypeSection(WasmRenderContext& c, const AstModule::SigVector& sigs)
    1206             : {
    1207           0 :     uint32_t numSigs = sigs.length();
    1208           0 :     if (!numSigs)
    1209           0 :         return true;
    1210             : 
    1211           0 :     for (uint32_t sigIndex = 0; sigIndex < numSigs; sigIndex++) {
    1212           0 :         const AstSig* sig = sigs[sigIndex];
    1213           0 :         if (!RenderIndent(c))
    1214           0 :             return false;
    1215           0 :         if (!c.buffer.append("(type"))
    1216           0 :             return false;
    1217           0 :         if (!sig->name().empty()) {
    1218           0 :             if (!c.buffer.append(" "))
    1219           0 :                 return false;
    1220           0 :             if (!RenderName(c, sig->name()))
    1221           0 :                 return false;
    1222             :         }
    1223           0 :         if (!c.buffer.append(" (func"))
    1224           0 :             return false;
    1225           0 :         if (!RenderSignature(c, *sig))
    1226           0 :             return false;
    1227           0 :         if (!c.buffer.append("))\n"))
    1228           0 :             return false;
    1229             :     }
    1230           0 :     return true;
    1231             : }
    1232             : 
    1233             : static bool
    1234           0 : RenderLimits(WasmRenderContext& c, const Limits& limits)
    1235             : {
    1236           0 :     if (!RenderInt32(c, limits.initial))
    1237           0 :         return false;
    1238           0 :     if (limits.maximum) {
    1239           0 :         if (!c.buffer.append(" "))
    1240           0 :             return false;
    1241           0 :         if (!RenderInt32(c, *limits.maximum))
    1242           0 :             return false;
    1243             :     }
    1244           0 :     return true;
    1245             : }
    1246             : 
    1247             : static bool
    1248           0 : RenderResizableTable(WasmRenderContext& c, const Limits& table)
    1249             : {
    1250           0 :     if (!c.buffer.append("(table "))
    1251           0 :         return false;
    1252           0 :     if (!RenderLimits(c, table))
    1253           0 :         return false;
    1254           0 :     return c.buffer.append(" anyfunc)");
    1255             : }
    1256             : 
    1257             : static bool
    1258           0 : RenderTableSection(WasmRenderContext& c, const AstModule& module)
    1259             : {
    1260           0 :     if (!module.hasTable())
    1261           0 :         return true;
    1262           0 :     for (const AstResizable& table : module.tables()) {
    1263           0 :         if (table.imported)
    1264           0 :             continue;
    1265           0 :         if (!RenderIndent(c))
    1266           0 :             return false;
    1267           0 :         if (!RenderResizableTable(c, table.limits))
    1268           0 :             return false;
    1269           0 :         if (!c.buffer.append("\n"))
    1270           0 :             return false;
    1271             :     }
    1272           0 :     return true;
    1273             : }
    1274             : 
    1275             : static bool
    1276           0 : RenderInlineExpr(WasmRenderContext& c, AstExpr& expr)
    1277             : {
    1278           0 :     if (!c.buffer.append("("))
    1279           0 :         return false;
    1280             : 
    1281           0 :     uint32_t prevIndent = c.indent;
    1282           0 :     c.indent = 0;
    1283           0 :     if (!RenderExpr(c, expr, /* newLine */ false))
    1284           0 :         return false;
    1285           0 :     c.indent = prevIndent;
    1286             : 
    1287           0 :     return c.buffer.append(")");
    1288             : }
    1289             : 
    1290             : static bool
    1291           0 : RenderElemSection(WasmRenderContext& c, const AstModule& module)
    1292             : {
    1293           0 :     for (const AstElemSegment* segment : module.elemSegments()) {
    1294           0 :         if (!RenderIndent(c))
    1295           0 :             return false;
    1296           0 :         if (!c.buffer.append("(elem "))
    1297           0 :             return false;
    1298           0 :         if (!RenderInlineExpr(c, *segment->offset()))
    1299           0 :             return false;
    1300             : 
    1301           0 :         for (const AstRef& elem : segment->elems()) {
    1302           0 :             if (!c.buffer.append(" "))
    1303           0 :                 return false;
    1304             : 
    1305           0 :             uint32_t index = elem.index();
    1306           0 :             AstName name = index < module.funcImportNames().length()
    1307           0 :                            ? module.funcImportNames()[index]
    1308           0 :                            : module.funcs()[index - module.funcImportNames().length()]->name();
    1309             : 
    1310           0 :             if (name.empty()) {
    1311           0 :                 if (!RenderInt32(c, index))
    1312           0 :                     return false;
    1313             :             } else {
    1314           0 :                 if (!RenderName(c, name))
    1315           0 :                     return false;
    1316             :             }
    1317             :         }
    1318             : 
    1319           0 :         if (!c.buffer.append(")\n"))
    1320           0 :             return false;
    1321             :     }
    1322             : 
    1323           0 :     return true;
    1324             : }
    1325             : 
    1326             : static bool
    1327           0 : RenderGlobal(WasmRenderContext& c, const AstGlobal& glob, bool inImport = false)
    1328             : {
    1329           0 :     if (!c.buffer.append("(global "))
    1330           0 :         return false;
    1331             : 
    1332           0 :     if (!inImport) {
    1333           0 :         if (!RenderName(c, glob.name()))
    1334           0 :             return false;
    1335           0 :         if (!c.buffer.append(" "))
    1336           0 :             return false;
    1337             :     }
    1338             : 
    1339           0 :     if (glob.isMutable()) {
    1340           0 :         if (!c.buffer.append("(mut "))
    1341           0 :             return false;
    1342           0 :         if (!RenderValType(c, glob.type()))
    1343           0 :             return false;
    1344           0 :         if (!c.buffer.append(")"))
    1345           0 :             return false;
    1346             :     } else {
    1347           0 :         if (!RenderValType(c, glob.type()))
    1348           0 :             return false;
    1349             :     }
    1350             : 
    1351           0 :     if (glob.hasInit()) {
    1352           0 :         if (!c.buffer.append(" "))
    1353           0 :             return false;
    1354           0 :         if (!RenderInlineExpr(c, glob.init()))
    1355           0 :             return false;
    1356             :     }
    1357             : 
    1358           0 :     if (!c.buffer.append(")"))
    1359           0 :         return false;
    1360             : 
    1361           0 :     return inImport || c.buffer.append("\n");
    1362             : }
    1363             : 
    1364             : static bool
    1365           0 : RenderGlobalSection(WasmRenderContext& c, const AstModule& module)
    1366             : {
    1367           0 :     if (module.globals().empty())
    1368           0 :         return true;
    1369             : 
    1370           0 :     for (const AstGlobal* global : module.globals()) {
    1371           0 :         if (!RenderIndent(c))
    1372           0 :             return false;
    1373           0 :         if (!RenderGlobal(c, *global))
    1374           0 :             return false;
    1375             :     }
    1376             : 
    1377           0 :     return true;
    1378             : }
    1379             : 
    1380             : static bool
    1381           0 : RenderResizableMemory(WasmRenderContext& c, const Limits& memory)
    1382             : {
    1383           0 :     if (!c.buffer.append("(memory "))
    1384           0 :         return false;
    1385             : 
    1386           0 :     Limits resizedMemory = memory;
    1387             : 
    1388           0 :     MOZ_ASSERT(resizedMemory.initial % PageSize == 0);
    1389           0 :     resizedMemory.initial /= PageSize;
    1390             : 
    1391           0 :     if (resizedMemory.maximum) {
    1392           0 :         MOZ_ASSERT(*resizedMemory.maximum % PageSize == 0);
    1393           0 :         *resizedMemory.maximum /= PageSize;
    1394             :     }
    1395             : 
    1396           0 :     if (!RenderLimits(c, resizedMemory))
    1397           0 :         return false;
    1398             : 
    1399           0 :     return c.buffer.append(")");
    1400             : }
    1401             : 
    1402             : static bool
    1403           0 : RenderImport(WasmRenderContext& c, AstImport& import, const AstModule& module)
    1404             : {
    1405           0 :     if (!RenderIndent(c))
    1406           0 :         return false;
    1407           0 :     if (!c.buffer.append("(import "))
    1408           0 :         return false;
    1409           0 :     if (!RenderName(c, import.name()))
    1410           0 :         return false;
    1411           0 :     if (!c.buffer.append(" \""))
    1412           0 :         return false;
    1413             : 
    1414           0 :     const AstName& moduleName = import.module();
    1415           0 :     if (!RenderEscapedString(c, moduleName))
    1416           0 :         return false;
    1417             : 
    1418           0 :     if (!c.buffer.append("\" \""))
    1419           0 :         return false;
    1420             : 
    1421           0 :     const AstName& fieldName = import.field();
    1422           0 :     if (!RenderEscapedString(c, fieldName))
    1423           0 :         return false;
    1424             : 
    1425           0 :     if (!c.buffer.append("\" "))
    1426           0 :         return false;
    1427             : 
    1428           0 :     switch (import.kind()) {
    1429             :       case DefinitionKind::Function: {
    1430           0 :         if (!c.buffer.append("(func"))
    1431           0 :             return false;
    1432           0 :         const AstSig* sig = module.sigs()[import.funcSig().index()];
    1433           0 :         if (!RenderSignature(c, *sig))
    1434           0 :             return false;
    1435           0 :         if (!c.buffer.append(")"))
    1436           0 :             return false;
    1437           0 :         break;
    1438             :       }
    1439             :       case DefinitionKind::Table: {
    1440           0 :         if (!RenderResizableTable(c, import.limits()))
    1441           0 :             return false;
    1442           0 :         break;
    1443             :       }
    1444             :       case DefinitionKind::Memory: {
    1445           0 :         if (!RenderResizableMemory(c, import.limits()))
    1446           0 :             return false;
    1447           0 :         break;
    1448             :       }
    1449             :       case DefinitionKind::Global: {
    1450           0 :         const AstGlobal& glob = import.global();
    1451           0 :         if (!RenderGlobal(c, glob, /* inImport */ true))
    1452           0 :             return false;
    1453           0 :         break;
    1454             :       }
    1455             :     }
    1456             : 
    1457           0 :     return c.buffer.append(")\n");
    1458             : }
    1459             : 
    1460             : static bool
    1461           0 : RenderImportSection(WasmRenderContext& c, const AstModule& module)
    1462             : {
    1463           0 :     for (AstImport* import : module.imports()) {
    1464           0 :         if (!RenderImport(c, *import, module))
    1465           0 :             return false;
    1466             :     }
    1467           0 :     return true;
    1468             : }
    1469             : 
    1470             : static bool
    1471           0 : RenderExport(WasmRenderContext& c, AstExport& export_,
    1472             :              const AstModule::NameVector& funcImportNames,
    1473             :              const AstModule::FuncVector& funcs)
    1474             : {
    1475           0 :     if (!RenderIndent(c))
    1476           0 :         return false;
    1477           0 :     if (!c.buffer.append("(export \""))
    1478           0 :         return false;
    1479           0 :     if (!RenderEscapedString(c, export_.name()))
    1480           0 :         return false;
    1481           0 :     if (!c.buffer.append("\" "))
    1482           0 :         return false;
    1483             : 
    1484           0 :     switch (export_.kind()) {
    1485             :       case DefinitionKind::Function: {
    1486           0 :         uint32_t index = export_.ref().index();
    1487           0 :         AstName name = index < funcImportNames.length()
    1488           0 :                        ? funcImportNames[index]
    1489           0 :                        : funcs[index - funcImportNames.length()]->name();
    1490           0 :         if (name.empty()) {
    1491           0 :             if (!RenderInt32(c, index))
    1492           0 :                 return false;
    1493             :         } else {
    1494           0 :             if (!RenderName(c, name))
    1495           0 :                 return false;
    1496             :         }
    1497           0 :         break;
    1498             :       }
    1499             :       case DefinitionKind::Table: {
    1500           0 :         if (!c.buffer.append("table"))
    1501           0 :             return false;
    1502           0 :         break;
    1503             :       }
    1504             :       case DefinitionKind::Memory: {
    1505           0 :         if (!c.buffer.append("memory"))
    1506           0 :             return false;
    1507           0 :         break;
    1508             :       }
    1509             :       case DefinitionKind::Global: {
    1510           0 :         if (!c.buffer.append("global"))
    1511           0 :             return false;
    1512           0 :         if (!RenderRef(c, export_.ref()))
    1513           0 :             return false;
    1514           0 :         break;
    1515             :       }
    1516             :     }
    1517             : 
    1518           0 :     return c.buffer.append(")\n");
    1519             : }
    1520             : 
    1521             : static bool
    1522           0 : RenderExportSection(WasmRenderContext& c, const AstModule::ExportVector& exports,
    1523             :                     const AstModule::NameVector& funcImportNames,
    1524             :                     const AstModule::FuncVector& funcs)
    1525             : {
    1526           0 :     uint32_t numExports = exports.length();
    1527           0 :     for (uint32_t i = 0; i < numExports; i++) {
    1528           0 :         if (!RenderExport(c, *exports[i], funcImportNames, funcs))
    1529           0 :             return false;
    1530             :     }
    1531           0 :     return true;
    1532             : }
    1533             : 
    1534             : static bool
    1535           0 : RenderFunctionBody(WasmRenderContext& c, AstFunc& func, const AstModule::SigVector& sigs)
    1536             : {
    1537           0 :     const AstSig* sig = sigs[func.sig().index()];
    1538             : 
    1539           0 :     uint32_t argsNum = sig->args().length();
    1540           0 :     uint32_t localsNum = func.vars().length();
    1541           0 :     if (localsNum > 0) {
    1542           0 :         if (!RenderIndent(c))
    1543           0 :             return false;
    1544           0 :         for (uint32_t i = 0; i < localsNum; i++) {
    1545           0 :             if (!c.buffer.append("(local "))
    1546           0 :                 return false;
    1547           0 :             const AstName& name = func.locals()[argsNum + i];
    1548           0 :             if (!name.empty()) {
    1549           0 :                 if (!RenderName(c, name))
    1550           0 :                     return false;
    1551           0 :                 if (!c.buffer.append(" "))
    1552           0 :                     return false;
    1553             :             }
    1554           0 :             ValType local = func.vars()[i];
    1555           0 :             if (!RenderValType(c, local))
    1556           0 :                 return false;
    1557           0 :             if (!c.buffer.append(") "))
    1558           0 :                 return false;
    1559             :         }
    1560           0 :         if (!c.buffer.append("\n"))
    1561           0 :             return false;
    1562             :     }
    1563             : 
    1564             : 
    1565           0 :     uint32_t exprsNum = func.body().length();
    1566           0 :     for (uint32_t i = 0; i < exprsNum; i++) {
    1567           0 :         if (!RenderExpr(c, *func.body()[i]))
    1568           0 :             return false;
    1569             :     }
    1570             : 
    1571           0 :     if (c.maybeSourceMap) {
    1572           0 :         if (!c.maybeSourceMap->exprlocs().emplaceBack(c.buffer.lineno(), c.buffer.column(), func.endOffset()))
    1573           0 :             return false;
    1574             :     }
    1575             : 
    1576           0 :     return true;
    1577             : }
    1578             : 
    1579             : static bool
    1580           0 : RenderCodeSection(WasmRenderContext& c, const AstModule::FuncVector& funcs,
    1581             :                   const AstModule::SigVector& sigs)
    1582             : {
    1583           0 :     uint32_t numFuncBodies = funcs.length();
    1584           0 :     for (uint32_t funcIndex = 0; funcIndex < numFuncBodies; funcIndex++) {
    1585           0 :         AstFunc* func = funcs[funcIndex];
    1586           0 :         uint32_t sigIndex = func->sig().index();
    1587           0 :         AstSig* sig = sigs[sigIndex];
    1588             : 
    1589           0 :         if (!RenderIndent(c))
    1590           0 :             return false;
    1591           0 :         if (!c.buffer.append("(func "))
    1592           0 :             return false;
    1593           0 :         if (!func->name().empty()) {
    1594           0 :             if (!RenderName(c, func->name()))
    1595           0 :                 return false;
    1596             :         }
    1597             : 
    1598           0 :         if (!RenderSignature(c, *sig, &(func->locals())))
    1599           0 :             return false;
    1600           0 :         if (!c.buffer.append("\n"))
    1601           0 :             return false;
    1602             : 
    1603           0 :         c.currentFuncIndex = funcIndex;
    1604             : 
    1605           0 :         c.indent++;
    1606           0 :         if (!RenderFunctionBody(c, *func, sigs))
    1607           0 :             return false;
    1608           0 :         c.indent--;
    1609           0 :         if (!RenderIndent(c))
    1610           0 :             return false;
    1611           0 :         if (!c.buffer.append(")\n"))
    1612           0 :             return false;
    1613             :     }
    1614             : 
    1615           0 :     return true;
    1616             : }
    1617             : 
    1618             : static bool
    1619           0 : RenderMemorySection(WasmRenderContext& c, const AstModule& module)
    1620             : {
    1621           0 :     if (!module.hasMemory())
    1622           0 :         return true;
    1623             : 
    1624           0 :     for (const AstResizable& memory : module.memories()) {
    1625           0 :         if (memory.imported)
    1626           0 :             continue;
    1627           0 :         if (!RenderIndent(c))
    1628           0 :             return false;
    1629           0 :         if (!RenderResizableMemory(c, memory.limits))
    1630           0 :             return false;
    1631           0 :         if (!c.buffer.append("\n"))
    1632           0 :             return false;
    1633             :     }
    1634             : 
    1635           0 :     return true;
    1636             : }
    1637             : 
    1638             : static bool
    1639           0 : RenderDataSection(WasmRenderContext& c, const AstModule& module)
    1640             : {
    1641           0 :     uint32_t numSegments = module.dataSegments().length();
    1642           0 :     if (!numSegments)
    1643           0 :         return true;
    1644             : 
    1645           0 :     for (const AstDataSegment* seg : module.dataSegments()) {
    1646           0 :         if (!RenderIndent(c))
    1647           0 :             return false;
    1648           0 :         if (!c.buffer.append("(data "))
    1649           0 :             return false;
    1650           0 :         if (!RenderInlineExpr(c, *seg->offset()))
    1651           0 :             return false;
    1652           0 :         if (!c.buffer.append("\n"))
    1653           0 :             return false;
    1654             : 
    1655           0 :         c.indent++;
    1656           0 :         for (const AstName& fragment : seg->fragments()) {
    1657           0 :             if (!RenderIndent(c))
    1658           0 :                 return false;
    1659           0 :             if (!c.buffer.append("\""))
    1660           0 :                 return false;
    1661           0 :             if (!RenderEscapedString(c, fragment))
    1662           0 :                 return false;
    1663           0 :             if (!c.buffer.append("\"\n"))
    1664           0 :                 return false;
    1665             :         }
    1666           0 :         c.indent--;
    1667             : 
    1668           0 :         if (!RenderIndent(c))
    1669           0 :             return false;
    1670           0 :         if (!c.buffer.append(")\n"))
    1671           0 :             return false;
    1672             :     }
    1673             : 
    1674           0 :     return true;
    1675             : }
    1676             : 
    1677             : static bool
    1678           0 : RenderStartSection(WasmRenderContext& c, AstModule& module)
    1679             : {
    1680           0 :     if (!module.hasStartFunc())
    1681           0 :         return true;
    1682             : 
    1683           0 :     if (!RenderIndent(c))
    1684           0 :         return false;
    1685           0 :     if (!c.buffer.append("(start "))
    1686           0 :         return false;
    1687           0 :     if (!RenderRef(c, module.startFunc().func()))
    1688           0 :         return false;
    1689           0 :     if (!c.buffer.append(")\n"))
    1690           0 :         return false;
    1691             : 
    1692           0 :     return true;
    1693             : }
    1694             : 
    1695             : static bool
    1696           0 : RenderModule(WasmRenderContext& c, AstModule& module)
    1697             : {
    1698           0 :     if (!c.buffer.append("(module\n"))
    1699           0 :         return false;
    1700             : 
    1701           0 :     c.indent++;
    1702             : 
    1703           0 :     if (!RenderTypeSection(c, module.sigs()))
    1704           0 :         return false;
    1705             : 
    1706           0 :     if (!RenderImportSection(c, module))
    1707           0 :         return false;
    1708             : 
    1709           0 :     if (!RenderTableSection(c, module))
    1710           0 :         return false;
    1711             : 
    1712           0 :     if (!RenderMemorySection(c, module))
    1713           0 :         return false;
    1714             : 
    1715           0 :     if (!RenderGlobalSection(c, module))
    1716           0 :         return false;
    1717             : 
    1718           0 :     if (!RenderExportSection(c, module.exports(), module.funcImportNames(), module.funcs()))
    1719           0 :         return false;
    1720             : 
    1721           0 :     if (!RenderStartSection(c, module))
    1722           0 :         return false;
    1723             : 
    1724           0 :     if (!RenderElemSection(c, module))
    1725           0 :         return false;
    1726             : 
    1727           0 :     if (!RenderCodeSection(c, module.funcs(), module.sigs()))
    1728           0 :         return false;
    1729             : 
    1730           0 :     if (!RenderDataSection(c, module))
    1731           0 :         return false;
    1732             : 
    1733           0 :     c.indent--;
    1734             : 
    1735           0 :     if (!c.buffer.append(")"))
    1736           0 :         return false;
    1737             : 
    1738           0 :     return true;
    1739             : }
    1740             : 
    1741             : #undef MAP_AST_EXPR
    1742             : 
    1743             : /*****************************************************************************/
    1744             : // Top-level functions
    1745             : 
    1746             : bool
    1747           0 : wasm::BinaryToText(JSContext* cx, const uint8_t* bytes, size_t length, StringBuffer& buffer,
    1748             :                    GeneratedSourceMap* sourceMap /* = nullptr */)
    1749             : {
    1750           0 :     LifoAlloc lifo(AST_LIFO_DEFAULT_CHUNK_SIZE);
    1751             : 
    1752             :     AstModule* module;
    1753           0 :     if (!BinaryToAst(cx, bytes, length, lifo, &module))
    1754           0 :         return false;
    1755             : 
    1756           0 :     WasmPrintBuffer buf(buffer);
    1757           0 :     WasmRenderContext c(cx, module, buf, sourceMap);
    1758             : 
    1759           0 :     if (!RenderModule(c, *module)) {
    1760           0 :         if (!cx->isExceptionPending())
    1761           0 :             ReportOutOfMemory(cx);
    1762           0 :         return false;
    1763             :     }
    1764             : 
    1765           0 :     return true;
    1766             : }

Generated by: LCOV version 1.13