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

Generated by: LCOV version 1.13