LCOV - code coverage report
Current view: top level - js/src/wasm - WasmTextToBinary.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 2769 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 224 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/WasmTextToBinary.h"
      20             : 
      21             : #include "mozilla/CheckedInt.h"
      22             : #include "mozilla/MathAlgorithms.h"
      23             : #include "mozilla/Maybe.h"
      24             : 
      25             : #include "jsdtoa.h"
      26             : #include "jsnum.h"
      27             : #include "jsprf.h"
      28             : #include "jsstr.h"
      29             : 
      30             : #include "ds/LifoAlloc.h"
      31             : #include "js/CharacterEncoding.h"
      32             : #include "js/HashTable.h"
      33             : #include "wasm/WasmAST.h"
      34             : #include "wasm/WasmTypes.h"
      35             : #include "wasm/WasmValidate.h"
      36             : 
      37             : using namespace js;
      38             : using namespace js::wasm;
      39             : 
      40             : using mozilla::BitwiseCast;
      41             : using mozilla::CeilingLog2;
      42             : using mozilla::CountLeadingZeroes32;
      43             : using mozilla::CheckedInt;
      44             : using mozilla::FloatingPoint;
      45             : using mozilla::IsPowerOfTwo;
      46             : using mozilla::Maybe;
      47             : using mozilla::PositiveInfinity;
      48             : using mozilla::SpecificNaN;
      49             : 
      50             : /*****************************************************************************/
      51             : // wasm text token stream
      52             : 
      53             : namespace {
      54             : 
      55             : class WasmToken
      56             : {
      57             :   public:
      58             :     enum FloatLiteralKind
      59             :     {
      60             :         HexNumber,
      61             :         DecNumber,
      62             :         Infinity,
      63             :         NaN
      64             :     };
      65             : 
      66             :     enum Kind
      67             :     {
      68             :         Align,
      69             :         AnyFunc,
      70             :         BinaryOpcode,
      71             :         Block,
      72             :         Br,
      73             :         BrIf,
      74             :         BrTable,
      75             :         Call,
      76             :         CallIndirect,
      77             :         CloseParen,
      78             :         ComparisonOpcode,
      79             :         Const,
      80             :         ConversionOpcode,
      81             :         CurrentMemory,
      82             :         Data,
      83             :         Drop,
      84             :         Elem,
      85             :         Else,
      86             :         End,
      87             :         EndOfFile,
      88             :         Equal,
      89             :         Error,
      90             :         Export,
      91             :         Float,
      92             :         Func,
      93             :         GetGlobal,
      94             :         GetLocal,
      95             :         Global,
      96             :         GrowMemory,
      97             :         If,
      98             :         Import,
      99             :         Index,
     100             :         Memory,
     101             :         NegativeZero,
     102             :         Load,
     103             :         Local,
     104             :         Loop,
     105             :         Module,
     106             :         Mutable,
     107             :         Name,
     108             :         Nop,
     109             :         Offset,
     110             :         OpenParen,
     111             :         Param,
     112             :         Result,
     113             :         Return,
     114             :         SetGlobal,
     115             :         SetLocal,
     116             :         SignedInteger,
     117             :         Start,
     118             :         Store,
     119             :         Table,
     120             :         TeeLocal,
     121             :         TernaryOpcode,
     122             :         Text,
     123             :         Then,
     124             :         Type,
     125             :         UnaryOpcode,
     126             :         Unreachable,
     127             :         UnsignedInteger,
     128             :         ValueType
     129             :     };
     130             :   private:
     131             :     Kind kind_;
     132             :     const char16_t* begin_;
     133             :     const char16_t* end_;
     134             :     union {
     135             :         uint32_t index_;
     136             :         uint64_t uint_;
     137             :         int64_t sint_;
     138             :         FloatLiteralKind floatLiteralKind_;
     139             :         ValType valueType_;
     140             :         Op op_;
     141             :     } u;
     142             :   public:
     143           0 :     WasmToken()
     144           0 :       : kind_(Kind(-1)),
     145             :         begin_(nullptr),
     146             :         end_(nullptr),
     147           0 :         u()
     148           0 :     { }
     149           0 :     WasmToken(Kind kind, const char16_t* begin, const char16_t* end)
     150           0 :       : kind_(kind),
     151             :         begin_(begin),
     152           0 :         end_(end)
     153             :     {
     154           0 :         MOZ_ASSERT(kind_ != Error);
     155           0 :         MOZ_ASSERT((kind == EndOfFile) == (begin == end));
     156           0 :     }
     157           0 :     explicit WasmToken(uint32_t index, const char16_t* begin, const char16_t* end)
     158           0 :       : kind_(Index),
     159             :         begin_(begin),
     160           0 :         end_(end)
     161             :     {
     162           0 :         MOZ_ASSERT(begin != end);
     163           0 :         u.index_ = index;
     164           0 :     }
     165           0 :     explicit WasmToken(uint64_t uint, const char16_t* begin, const char16_t* end)
     166           0 :       : kind_(UnsignedInteger),
     167             :         begin_(begin),
     168           0 :         end_(end)
     169             :     {
     170           0 :         MOZ_ASSERT(begin != end);
     171           0 :         u.uint_ = uint;
     172           0 :     }
     173           0 :     explicit WasmToken(int64_t sint, const char16_t* begin, const char16_t* end)
     174           0 :       : kind_(SignedInteger),
     175             :         begin_(begin),
     176           0 :         end_(end)
     177             :     {
     178           0 :         MOZ_ASSERT(begin != end);
     179           0 :         u.sint_ = sint;
     180           0 :     }
     181           0 :     explicit WasmToken(FloatLiteralKind floatLiteralKind,
     182             :                        const char16_t* begin, const char16_t* end)
     183           0 :       : kind_(Float),
     184             :         begin_(begin),
     185           0 :         end_(end)
     186             :     {
     187           0 :         MOZ_ASSERT(begin != end);
     188           0 :         u.floatLiteralKind_ = floatLiteralKind;
     189           0 :     }
     190           0 :     explicit WasmToken(Kind kind, ValType valueType, const char16_t* begin, const char16_t* end)
     191           0 :       : kind_(kind),
     192             :         begin_(begin),
     193           0 :         end_(end)
     194             :     {
     195           0 :         MOZ_ASSERT(begin != end);
     196           0 :         MOZ_ASSERT(kind_ == ValueType || kind_ == Const);
     197           0 :         u.valueType_ = valueType;
     198           0 :     }
     199           0 :     explicit WasmToken(Kind kind, Op op, const char16_t* begin, const char16_t* end)
     200           0 :       : kind_(kind),
     201             :         begin_(begin),
     202           0 :         end_(end)
     203             :     {
     204           0 :         MOZ_ASSERT(begin != end);
     205           0 :         MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode || kind_ == TernaryOpcode ||
     206             :                    kind_ == ComparisonOpcode || kind_ == ConversionOpcode ||
     207             :                    kind_ == Load || kind_ == Store);
     208           0 :         u.op_ = op;
     209           0 :     }
     210           0 :     explicit WasmToken(const char16_t* begin)
     211           0 :       : kind_(Error),
     212             :         begin_(begin),
     213           0 :         end_(begin)
     214           0 :     {}
     215           0 :     Kind kind() const {
     216           0 :         MOZ_ASSERT(kind_ != Kind(-1));
     217           0 :         return kind_;
     218             :     }
     219           0 :     const char16_t* begin() const {
     220           0 :         return begin_;
     221             :     }
     222           0 :     const char16_t* end() const {
     223           0 :         return end_;
     224             :     }
     225           0 :     AstName text() const {
     226           0 :         MOZ_ASSERT(kind_ == Text);
     227           0 :         MOZ_ASSERT(begin_[0] == '"');
     228           0 :         MOZ_ASSERT(end_[-1] == '"');
     229           0 :         MOZ_ASSERT(end_ - begin_ >= 2);
     230           0 :         return AstName(begin_ + 1, end_ - begin_ - 2);
     231             :     }
     232           0 :     AstName name() const {
     233           0 :         return AstName(begin_, end_ - begin_);
     234             :     }
     235           0 :     uint32_t index() const {
     236           0 :         MOZ_ASSERT(kind_ == Index);
     237           0 :         return u.index_;
     238             :     }
     239           0 :     uint64_t uint() const {
     240           0 :         MOZ_ASSERT(kind_ == UnsignedInteger);
     241           0 :         return u.uint_;
     242             :     }
     243           0 :     int64_t sint() const {
     244           0 :         MOZ_ASSERT(kind_ == SignedInteger);
     245           0 :         return u.sint_;
     246             :     }
     247           0 :     FloatLiteralKind floatLiteralKind() const {
     248           0 :         MOZ_ASSERT(kind_ == Float);
     249           0 :         return u.floatLiteralKind_;
     250             :     }
     251           0 :     ValType valueType() const {
     252           0 :         MOZ_ASSERT(kind_ == ValueType || kind_ == Const);
     253           0 :         return u.valueType_;
     254             :     }
     255           0 :     Op op() const {
     256           0 :         MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode || kind_ == TernaryOpcode ||
     257             :                    kind_ == ComparisonOpcode || kind_ == ConversionOpcode ||
     258             :                    kind_ == Load || kind_ == Store);
     259           0 :         return u.op_;
     260             :     }
     261           0 :     bool isOpcode() const {
     262           0 :         switch (kind_) {
     263             :           case BinaryOpcode:
     264             :           case Block:
     265             :           case Br:
     266             :           case BrIf:
     267             :           case BrTable:
     268             :           case Call:
     269             :           case CallIndirect:
     270             :           case ComparisonOpcode:
     271             :           case Const:
     272             :           case ConversionOpcode:
     273             :           case CurrentMemory:
     274             :           case Drop:
     275             :           case GetGlobal:
     276             :           case GetLocal:
     277             :           case GrowMemory:
     278             :           case If:
     279             :           case Load:
     280             :           case Loop:
     281             :           case Nop:
     282             :           case Return:
     283             :           case SetGlobal:
     284             :           case SetLocal:
     285             :           case Store:
     286             :           case TeeLocal:
     287             :           case TernaryOpcode:
     288             :           case UnaryOpcode:
     289             :           case Unreachable:
     290           0 :             return true;
     291             :           case Align:
     292             :           case AnyFunc:
     293             :           case CloseParen:
     294             :           case Data:
     295             :           case Elem:
     296             :           case Else:
     297             :           case EndOfFile:
     298             :           case Equal:
     299             :           case End:
     300             :           case Error:
     301             :           case Export:
     302             :           case Float:
     303             :           case Func:
     304             :           case Global:
     305             :           case Mutable:
     306             :           case Import:
     307             :           case Index:
     308             :           case Memory:
     309             :           case NegativeZero:
     310             :           case Local:
     311             :           case Module:
     312             :           case Name:
     313             :           case Offset:
     314             :           case OpenParen:
     315             :           case Param:
     316             :           case Result:
     317             :           case SignedInteger:
     318             :           case Start:
     319             :           case Table:
     320             :           case Text:
     321             :           case Then:
     322             :           case Type:
     323             :           case UnsignedInteger:
     324             :           case ValueType:
     325           0 :             return false;
     326             :         }
     327           0 :         MOZ_CRASH("unexpected token kind");
     328             :     }
     329             : };
     330             : 
     331           0 : struct InlineImport
     332             : {
     333             :     WasmToken module;
     334             :     WasmToken field;
     335             : };
     336             : 
     337             : } // end anonymous namespace
     338             : 
     339             : static bool
     340           0 : IsWasmNewLine(char16_t c)
     341             : {
     342           0 :     return c == '\n';
     343             : }
     344             : 
     345             : static bool
     346           0 : IsWasmSpace(char16_t c)
     347             : {
     348           0 :     switch (c) {
     349             :       case ' ':
     350             :       case '\n':
     351             :       case '\r':
     352             :       case '\t':
     353             :       case '\v':
     354             :       case '\f':
     355           0 :         return true;
     356             :       default:
     357           0 :         return false;
     358             :     }
     359             : }
     360             : 
     361             : static bool
     362           0 : IsWasmDigit(char16_t c)
     363             : {
     364           0 :     return c >= '0' && c <= '9';
     365             : }
     366             : 
     367             : static bool
     368           0 : IsWasmLetter(char16_t c)
     369             : {
     370           0 :     return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
     371             : }
     372             : 
     373             : static bool
     374           0 : IsNameAfterDollar(char16_t c)
     375             : {
     376           0 :     return IsWasmLetter(c) ||
     377           0 :            IsWasmDigit(c) ||
     378           0 :            c == '_' || c == '$' || c == '-' || c == '.' || c == '>';
     379             : }
     380             : 
     381             : static bool
     382           0 : IsHexDigit(char c, uint8_t* value)
     383             : {
     384           0 :     if (c >= '0' && c <= '9') {
     385           0 :         *value = c - '0';
     386           0 :         return true;
     387             :     }
     388             : 
     389           0 :     if (c >= 'a' && c <= 'f') {
     390           0 :         *value = 10 + (c - 'a');
     391           0 :         return true;
     392             :     }
     393             : 
     394           0 :     if (c >= 'A' && c <= 'F') {
     395           0 :         *value = 10 + (c - 'A');
     396           0 :         return true;
     397             :     }
     398             : 
     399           0 :     return false;
     400             : }
     401             : 
     402             : static WasmToken
     403           0 : LexHexFloatLiteral(const char16_t* begin, const char16_t* end, const char16_t** curp)
     404             : {
     405           0 :     const char16_t* cur = begin;
     406             : 
     407           0 :     if (cur != end && (*cur == '-' || *cur == '+'))
     408           0 :         cur++;
     409             : 
     410           0 :     MOZ_ASSERT(cur != end && *cur == '0');
     411           0 :     cur++;
     412           0 :     MOZ_ASSERT(cur != end && *cur == 'x');
     413           0 :     cur++;
     414             : 
     415             :     uint8_t digit;
     416           0 :     while (cur != end && IsHexDigit(*cur, &digit))
     417           0 :         cur++;
     418             : 
     419           0 :     if (cur != end && *cur == '.')
     420           0 :         cur++;
     421             : 
     422           0 :     while (cur != end && IsHexDigit(*cur, &digit))
     423           0 :         cur++;
     424             : 
     425           0 :     if (cur != end && *cur == 'p') {
     426           0 :         cur++;
     427             : 
     428           0 :         if (cur != end && (*cur == '-' || *cur == '+'))
     429           0 :             cur++;
     430             : 
     431           0 :         while (cur != end && IsWasmDigit(*cur))
     432           0 :             cur++;
     433             :     }
     434             : 
     435           0 :     *curp = cur;
     436           0 :     return WasmToken(WasmToken::HexNumber, begin, cur);
     437             : }
     438             : 
     439             : static WasmToken
     440           0 : LexDecFloatLiteral(const char16_t* begin, const char16_t* end, const char16_t** curp)
     441             : {
     442           0 :     const char16_t* cur = begin;
     443             : 
     444           0 :     if (cur != end && (*cur == '-' || *cur == '+'))
     445           0 :         cur++;
     446             : 
     447           0 :     while (cur != end && IsWasmDigit(*cur))
     448           0 :         cur++;
     449             : 
     450           0 :     if (cur != end && *cur == '.')
     451           0 :         cur++;
     452             : 
     453           0 :     while (cur != end && IsWasmDigit(*cur))
     454           0 :         cur++;
     455             : 
     456           0 :     if (cur != end && *cur == 'e') {
     457           0 :         cur++;
     458             : 
     459           0 :         if (cur != end && (*cur == '-' || *cur == '+'))
     460           0 :             cur++;
     461             : 
     462           0 :         while (cur != end && IsWasmDigit(*cur))
     463           0 :             cur++;
     464             :     }
     465             : 
     466           0 :     *curp = cur;
     467           0 :     return WasmToken(WasmToken::DecNumber, begin, cur);
     468             : }
     469             : 
     470             : static bool
     471           0 : ConsumeTextByte(const char16_t** curp, const char16_t* end, uint8_t* byte = nullptr)
     472             : {
     473           0 :     const char16_t*& cur = *curp;
     474           0 :     MOZ_ASSERT(cur != end);
     475             : 
     476           0 :     if (*cur != '\\') {
     477           0 :         if (byte)
     478           0 :             *byte = *cur;
     479           0 :         cur++;
     480           0 :         return true;
     481             :     }
     482             : 
     483           0 :     if (++cur == end)
     484           0 :         return false;
     485             : 
     486             :     uint8_t u8;
     487           0 :     switch (*cur) {
     488           0 :       case 'n': u8 = '\n'; break;
     489           0 :       case 't': u8 = '\t'; break;
     490           0 :       case '\\': u8 = '\\'; break;
     491           0 :       case '\"': u8 = '\"'; break;
     492           0 :       case '\'': u8 = '\''; break;
     493             :       default: {
     494             :         uint8_t highNibble;
     495           0 :         if (!IsHexDigit(*cur, &highNibble))
     496           0 :             return false;
     497             : 
     498           0 :         if (++cur == end)
     499           0 :             return false;
     500             : 
     501             :         uint8_t lowNibble;
     502           0 :         if (!IsHexDigit(*cur, &lowNibble))
     503           0 :             return false;
     504             : 
     505           0 :         u8 = lowNibble | (highNibble << 4);
     506           0 :         break;
     507             :       }
     508             :     }
     509             : 
     510           0 :     if (byte)
     511           0 :         *byte = u8;
     512           0 :     cur++;
     513           0 :     return true;
     514             : }
     515             : 
     516             : namespace {
     517             : 
     518             : class WasmTokenStream
     519             : {
     520             :     static const uint32_t LookaheadSize = 2;
     521             : 
     522             :     const char16_t* cur_;
     523             :     const char16_t* const end_;
     524             :     const char16_t* lineStart_;
     525             :     unsigned line_;
     526             :     uint32_t lookaheadIndex_;
     527             :     uint32_t lookaheadDepth_;
     528             :     WasmToken lookahead_[LookaheadSize];
     529             : 
     530           0 :     bool consume(const char16_t* match) {
     531           0 :         const char16_t* p = cur_;
     532           0 :         for (; *match; p++, match++) {
     533           0 :             if (p == end_ || *p != *match)
     534           0 :                 return false;
     535             :         }
     536           0 :         cur_ = p;
     537           0 :         return true;
     538             :     }
     539           0 :     WasmToken fail(const char16_t* begin) const {
     540           0 :         return WasmToken(begin);
     541             :     }
     542             : 
     543             :     WasmToken nan(const char16_t* begin);
     544             :     WasmToken literal(const char16_t* begin);
     545             :     WasmToken next();
     546             :     void skipSpaces();
     547             : 
     548             :   public:
     549           0 :     WasmTokenStream(const char16_t* text, UniqueChars* error)
     550           0 :       : cur_(text),
     551           0 :         end_(text + js_strlen(text)),
     552             :         lineStart_(text),
     553             :         line_(1),
     554             :         lookaheadIndex_(0),
     555           0 :         lookaheadDepth_(0)
     556           0 :     {}
     557           0 :     void generateError(WasmToken token, UniqueChars* error) {
     558           0 :         unsigned column = token.begin() - lineStart_ + 1;
     559           0 :         *error = JS_smprintf("parsing wasm text at %u:%u", line_, column);
     560           0 :     }
     561           0 :     void generateError(WasmToken token, const char* msg, UniqueChars* error) {
     562           0 :         unsigned column = token.begin() - lineStart_ + 1;
     563           0 :         *error = JS_smprintf("parsing wasm text at %u:%u: %s", line_, column, msg);
     564           0 :     }
     565           0 :     WasmToken peek() {
     566           0 :         if (!lookaheadDepth_) {
     567           0 :             lookahead_[lookaheadIndex_] = next();
     568           0 :             lookaheadDepth_ = 1;
     569             :         }
     570           0 :         return lookahead_[lookaheadIndex_];
     571             :     }
     572           0 :     WasmToken get() {
     573             :         static_assert(LookaheadSize == 2, "can just flip");
     574           0 :         if (lookaheadDepth_) {
     575           0 :             lookaheadDepth_--;
     576           0 :             WasmToken ret = lookahead_[lookaheadIndex_];
     577           0 :             lookaheadIndex_ ^= 1;
     578           0 :             return ret;
     579             :         }
     580           0 :         return next();
     581             :     }
     582           0 :     void unget(WasmToken token) {
     583             :         static_assert(LookaheadSize == 2, "can just flip");
     584           0 :         lookaheadDepth_++;
     585           0 :         lookaheadIndex_ ^= 1;
     586           0 :         lookahead_[lookaheadIndex_] = token;
     587           0 :     }
     588             : 
     589             :     // Helpers:
     590           0 :     bool getIf(WasmToken::Kind kind, WasmToken* token) {
     591           0 :         if (peek().kind() == kind) {
     592           0 :             *token = get();
     593           0 :             return true;
     594             :         }
     595           0 :         return false;
     596             :     }
     597           0 :     bool getIf(WasmToken::Kind kind) {
     598           0 :         WasmToken token;
     599           0 :         if (getIf(kind, &token))
     600           0 :             return true;
     601           0 :         return false;
     602             :     }
     603           0 :     AstName getIfName() {
     604           0 :         WasmToken token;
     605           0 :         if (getIf(WasmToken::Name, &token))
     606           0 :             return token.name();
     607           0 :         return AstName();
     608             :     }
     609           0 :     bool getIfRef(AstRef* ref) {
     610           0 :         WasmToken token = peek();
     611           0 :         if (token.kind() == WasmToken::Name || token.kind() == WasmToken::Index)
     612           0 :             return matchRef(ref, nullptr);
     613           0 :         return false;
     614             :     }
     615           0 :     bool getIfOpcode(WasmToken* token) {
     616           0 :         *token = peek();
     617           0 :         if (token->isOpcode()) {
     618           0 :             (void)get();
     619           0 :             return true;
     620             :         }
     621           0 :         return false;
     622             :     }
     623           0 :     bool match(WasmToken::Kind expect, WasmToken* token, UniqueChars* error) {
     624           0 :         *token = get();
     625           0 :         if (token->kind() == expect)
     626           0 :             return true;
     627           0 :         generateError(*token, error);
     628           0 :         return false;
     629             :     }
     630           0 :     bool match(WasmToken::Kind expect, UniqueChars* error) {
     631           0 :         WasmToken token;
     632           0 :         return match(expect, &token, error);
     633             :     }
     634           0 :     bool matchRef(AstRef* ref, UniqueChars* error) {
     635           0 :         WasmToken token = get();
     636           0 :         switch (token.kind()) {
     637             :           case WasmToken::Name:
     638           0 :             *ref = AstRef(token.name());
     639           0 :             break;
     640             :           case WasmToken::Index:
     641           0 :             *ref = AstRef(token.index());
     642           0 :             break;
     643             :           default:
     644           0 :             generateError(token, error);
     645           0 :             return false;
     646             :         }
     647           0 :         return true;
     648             :     }
     649             : };
     650             : 
     651             : } // end anonymous namespace
     652             : 
     653             : WasmToken
     654           0 : WasmTokenStream::nan(const char16_t* begin)
     655             : {
     656           0 :     if (consume(u":")) {
     657           0 :         if (!consume(u"0x"))
     658           0 :             return fail(begin);
     659             : 
     660             :         uint8_t digit;
     661           0 :         while (cur_ != end_ && IsHexDigit(*cur_, &digit))
     662           0 :             cur_++;
     663             :     }
     664             : 
     665           0 :     return WasmToken(WasmToken::NaN, begin, cur_);
     666             : }
     667             : 
     668             : WasmToken
     669           0 : WasmTokenStream::literal(const char16_t* begin)
     670             : {
     671           0 :     CheckedInt<uint64_t> u = 0;
     672           0 :     if (consume(u"0x")) {
     673           0 :         if (cur_ == end_)
     674           0 :             return fail(begin);
     675             : 
     676           0 :         do {
     677           0 :             if (*cur_ == '.' || *cur_ == 'p')
     678           0 :                 return LexHexFloatLiteral(begin, end_, &cur_);
     679             : 
     680             :             uint8_t digit;
     681           0 :             if (!IsHexDigit(*cur_, &digit))
     682           0 :                 break;
     683             : 
     684           0 :             u *= 16;
     685           0 :             u += digit;
     686           0 :             if (!u.isValid())
     687           0 :                 return LexHexFloatLiteral(begin, end_, &cur_);
     688             : 
     689           0 :             cur_++;
     690           0 :         } while (cur_ != end_);
     691             : 
     692           0 :         if (*begin == '-') {
     693           0 :             uint64_t value = u.value();
     694           0 :             if (value == 0)
     695           0 :                 return WasmToken(WasmToken::NegativeZero, begin, cur_);
     696           0 :             if (value > uint64_t(INT64_MIN))
     697           0 :                 return LexHexFloatLiteral(begin, end_, &cur_);
     698             : 
     699           0 :             value = -value;
     700           0 :             return WasmToken(int64_t(value), begin, cur_);
     701             :         }
     702             :     } else {
     703           0 :         while (cur_ != end_) {
     704           0 :             if (*cur_ == '.' || *cur_ == 'e')
     705           0 :                 return LexDecFloatLiteral(begin, end_, &cur_);
     706             : 
     707           0 :             if (!IsWasmDigit(*cur_))
     708           0 :                 break;
     709             : 
     710           0 :             u *= 10;
     711           0 :             u += *cur_ - '0';
     712           0 :             if (!u.isValid())
     713           0 :                 return LexDecFloatLiteral(begin, end_, &cur_);
     714             : 
     715           0 :             cur_++;
     716             :         }
     717             : 
     718           0 :         if (*begin == '-') {
     719           0 :             uint64_t value = u.value();
     720           0 :             if (value == 0)
     721           0 :                 return WasmToken(WasmToken::NegativeZero, begin, cur_);
     722           0 :             if (value > uint64_t(INT64_MIN))
     723           0 :                 return LexDecFloatLiteral(begin, end_, &cur_);
     724             : 
     725           0 :             value = -value;
     726           0 :             return WasmToken(int64_t(value), begin, cur_);
     727             :         }
     728             :     }
     729             : 
     730           0 :     CheckedInt<uint32_t> index = u.value();
     731           0 :     if (index.isValid())
     732           0 :         return WasmToken(index.value(), begin, cur_);
     733             : 
     734           0 :     return WasmToken(u.value(), begin, cur_);
     735             : }
     736             : 
     737             : void
     738           0 : WasmTokenStream::skipSpaces()
     739             : {
     740           0 :     while (cur_ != end_) {
     741           0 :         char16_t ch = *cur_;
     742           0 :         if (ch == ';' && consume(u";;")) {
     743             :             // Skipping single line comment.
     744           0 :             while (cur_ != end_ && !IsWasmNewLine(*cur_))
     745           0 :                 cur_++;
     746           0 :         } else if (ch == '(' && consume(u"(;")) {
     747             :             // Skipping multi-line and possibly nested comments.
     748           0 :             size_t level = 1;
     749           0 :             while (cur_ != end_) {
     750           0 :                 char16_t ch = *cur_;
     751           0 :                 if (ch == '(' && consume(u"(;")) {
     752           0 :                     level++;
     753           0 :                 } else if (ch == ';' && consume(u";)")) {
     754           0 :                     if (--level == 0)
     755           0 :                         break;
     756             :                 } else {
     757           0 :                     cur_++;
     758           0 :                     if (IsWasmNewLine(ch)) {
     759           0 :                         lineStart_ = cur_;
     760           0 :                         line_++;
     761             :                     }
     762             :                 }
     763             :             }
     764           0 :         } else if (IsWasmSpace(ch)) {
     765           0 :             cur_++;
     766           0 :             if (IsWasmNewLine(ch)) {
     767           0 :                 lineStart_ = cur_;
     768           0 :                 line_++;
     769             :             }
     770             :         } else
     771           0 :             break; // non-whitespace found
     772             :     }
     773           0 : }
     774             : 
     775             : WasmToken
     776           0 : WasmTokenStream::next()
     777             : {
     778           0 :     skipSpaces();
     779             : 
     780           0 :     if (cur_ == end_)
     781           0 :         return WasmToken(WasmToken::EndOfFile, cur_, cur_);
     782             : 
     783           0 :     const char16_t* begin = cur_;
     784           0 :     switch (*begin) {
     785             :       case '"':
     786           0 :         cur_++;
     787             :         while (true) {
     788           0 :             if (cur_ == end_)
     789           0 :                 return fail(begin);
     790           0 :             if (*cur_ == '"')
     791           0 :                 break;
     792           0 :             if (!ConsumeTextByte(&cur_, end_))
     793           0 :                 return fail(begin);
     794             :         }
     795           0 :         cur_++;
     796           0 :         return WasmToken(WasmToken::Text, begin, cur_);
     797             : 
     798             :       case '$':
     799           0 :         cur_++;
     800           0 :         while (cur_ != end_ && IsNameAfterDollar(*cur_))
     801           0 :             cur_++;
     802           0 :         return WasmToken(WasmToken::Name, begin, cur_);
     803             : 
     804             :       case '(':
     805           0 :         cur_++;
     806           0 :         return WasmToken(WasmToken::OpenParen, begin, cur_);
     807             : 
     808             :       case ')':
     809           0 :         cur_++;
     810           0 :         return WasmToken(WasmToken::CloseParen, begin, cur_);
     811             : 
     812             :       case '=':
     813           0 :         cur_++;
     814           0 :         return WasmToken(WasmToken::Equal, begin, cur_);
     815             : 
     816             :       case '+': case '-':
     817           0 :         cur_++;
     818           0 :         if (consume(u"infinity"))
     819           0 :             return WasmToken(WasmToken::Infinity, begin, cur_);
     820           0 :         if (consume(u"nan"))
     821           0 :             return nan(begin);
     822           0 :         if (!IsWasmDigit(*cur_))
     823           0 :             break;
     824             :         MOZ_FALLTHROUGH;
     825             :       case '0': case '1': case '2': case '3': case '4':
     826             :       case '5': case '6': case '7': case '8': case '9':
     827           0 :         return literal(begin);
     828             : 
     829             :       case 'a':
     830           0 :         if (consume(u"align"))
     831           0 :             return WasmToken(WasmToken::Align, begin, cur_);
     832           0 :         if (consume(u"anyfunc"))
     833           0 :             return WasmToken(WasmToken::AnyFunc, begin, cur_);
     834           0 :         break;
     835             : 
     836             :       case 'b':
     837           0 :         if (consume(u"block"))
     838           0 :             return WasmToken(WasmToken::Block, begin, cur_);
     839           0 :         if (consume(u"br")) {
     840           0 :             if (consume(u"_table"))
     841           0 :                 return WasmToken(WasmToken::BrTable, begin, cur_);
     842           0 :             if (consume(u"_if"))
     843           0 :                 return WasmToken(WasmToken::BrIf, begin, cur_);
     844           0 :             return WasmToken(WasmToken::Br, begin, cur_);
     845             :         }
     846           0 :         break;
     847             : 
     848             :       case 'c':
     849           0 :         if (consume(u"call")) {
     850           0 :             if (consume(u"_indirect"))
     851           0 :                 return WasmToken(WasmToken::CallIndirect, begin, cur_);
     852           0 :             return WasmToken(WasmToken::Call, begin, cur_);
     853             :         }
     854           0 :         if (consume(u"current_memory"))
     855           0 :             return WasmToken(WasmToken::CurrentMemory, begin, cur_);
     856           0 :         break;
     857             : 
     858             :       case 'd':
     859           0 :         if (consume(u"data"))
     860           0 :             return WasmToken(WasmToken::Data, begin, cur_);
     861           0 :         if (consume(u"drop"))
     862           0 :             return WasmToken(WasmToken::Drop, begin, cur_);
     863           0 :         break;
     864             : 
     865             :       case 'e':
     866           0 :         if (consume(u"elem"))
     867           0 :             return WasmToken(WasmToken::Elem, begin, cur_);
     868           0 :         if (consume(u"else"))
     869           0 :             return WasmToken(WasmToken::Else, begin, cur_);
     870           0 :         if (consume(u"end"))
     871           0 :             return WasmToken(WasmToken::End, begin, cur_);
     872           0 :         if (consume(u"export"))
     873           0 :             return WasmToken(WasmToken::Export, begin, cur_);
     874           0 :         break;
     875             : 
     876             :       case 'f':
     877           0 :         if (consume(u"func"))
     878           0 :             return WasmToken(WasmToken::Func, begin, cur_);
     879             : 
     880           0 :         if (consume(u"f32")) {
     881           0 :             if (!consume(u"."))
     882           0 :                 return WasmToken(WasmToken::ValueType, ValType::F32, begin, cur_);
     883             : 
     884           0 :             switch (*cur_) {
     885             :               case 'a':
     886           0 :                 if (consume(u"abs"))
     887           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::F32Abs, begin, cur_);
     888           0 :                 if (consume(u"add"))
     889           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::F32Add, begin, cur_);
     890           0 :                 break;
     891             :               case 'c':
     892           0 :                 if (consume(u"ceil"))
     893           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::F32Ceil, begin, cur_);
     894           0 :                 if (consume(u"const"))
     895           0 :                     return WasmToken(WasmToken::Const, ValType::F32, begin, cur_);
     896           0 :                 if (consume(u"convert_s/i32")) {
     897             :                     return WasmToken(WasmToken::ConversionOpcode, Op::F32ConvertSI32,
     898           0 :                                      begin, cur_);
     899             :                 }
     900           0 :                 if (consume(u"convert_u/i32")) {
     901             :                     return WasmToken(WasmToken::ConversionOpcode, Op::F32ConvertUI32,
     902           0 :                                      begin, cur_);
     903             :                 }
     904           0 :                 if (consume(u"convert_s/i64")) {
     905             :                     return WasmToken(WasmToken::ConversionOpcode, Op::F32ConvertSI64,
     906           0 :                                      begin, cur_);
     907             :                 }
     908           0 :                 if (consume(u"convert_u/i64")) {
     909             :                     return WasmToken(WasmToken::ConversionOpcode, Op::F32ConvertUI64,
     910           0 :                                      begin, cur_);
     911             :                 }
     912           0 :                 if (consume(u"copysign"))
     913           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::F32CopySign, begin, cur_);
     914           0 :                 break;
     915             :               case 'd':
     916           0 :                 if (consume(u"demote/f64"))
     917             :                     return WasmToken(WasmToken::ConversionOpcode, Op::F32DemoteF64,
     918           0 :                                      begin, cur_);
     919           0 :                 if (consume(u"div"))
     920           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::F32Div, begin, cur_);
     921           0 :                 break;
     922             :               case 'e':
     923           0 :                 if (consume(u"eq"))
     924           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::F32Eq, begin, cur_);
     925           0 :                 break;
     926             :               case 'f':
     927           0 :                 if (consume(u"floor"))
     928           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::F32Floor, begin, cur_);
     929           0 :                 break;
     930             :               case 'g':
     931           0 :                 if (consume(u"ge"))
     932           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::F32Ge, begin, cur_);
     933           0 :                 if (consume(u"gt"))
     934           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::F32Gt, begin, cur_);
     935           0 :                 break;
     936             :               case 'l':
     937           0 :                 if (consume(u"le"))
     938           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::F32Le, begin, cur_);
     939           0 :                 if (consume(u"lt"))
     940           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::F32Lt, begin, cur_);
     941           0 :                 if (consume(u"load"))
     942           0 :                     return WasmToken(WasmToken::Load, Op::F32Load, begin, cur_);
     943           0 :                 break;
     944             :               case 'm':
     945           0 :                 if (consume(u"max"))
     946           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::F32Max, begin, cur_);
     947           0 :                 if (consume(u"min"))
     948           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::F32Min, begin, cur_);
     949           0 :                 if (consume(u"mul"))
     950           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::F32Mul, begin, cur_);
     951           0 :                 break;
     952             :               case 'n':
     953           0 :                 if (consume(u"nearest"))
     954           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::F32Nearest, begin, cur_);
     955           0 :                 if (consume(u"neg"))
     956           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::F32Neg, begin, cur_);
     957           0 :                 if (consume(u"ne"))
     958           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::F32Ne, begin, cur_);
     959           0 :                 break;
     960             :               case 'r':
     961           0 :                 if (consume(u"reinterpret/i32"))
     962             :                     return WasmToken(WasmToken::ConversionOpcode, Op::F32ReinterpretI32,
     963           0 :                                      begin, cur_);
     964           0 :                 break;
     965             :               case 's':
     966           0 :                 if (consume(u"sqrt"))
     967           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::F32Sqrt, begin, cur_);
     968           0 :                 if (consume(u"sub"))
     969           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::F32Sub, begin, cur_);
     970           0 :                 if (consume(u"store"))
     971           0 :                     return WasmToken(WasmToken::Store, Op::F32Store, begin, cur_);
     972           0 :                 break;
     973             :               case 't':
     974           0 :                 if (consume(u"trunc"))
     975           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::F32Trunc, begin, cur_);
     976           0 :                 break;
     977             :             }
     978           0 :             break;
     979             :         }
     980           0 :         if (consume(u"f64")) {
     981           0 :             if (!consume(u"."))
     982           0 :                 return WasmToken(WasmToken::ValueType, ValType::F64, begin, cur_);
     983             : 
     984           0 :             switch (*cur_) {
     985             :               case 'a':
     986           0 :                 if (consume(u"abs"))
     987           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::F64Abs, begin, cur_);
     988           0 :                 if (consume(u"add"))
     989           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::F64Add, begin, cur_);
     990           0 :                 break;
     991             :               case 'c':
     992           0 :                 if (consume(u"ceil"))
     993           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::F64Ceil, begin, cur_);
     994           0 :                 if (consume(u"const"))
     995           0 :                     return WasmToken(WasmToken::Const, ValType::F64, begin, cur_);
     996           0 :                 if (consume(u"convert_s/i32")) {
     997             :                     return WasmToken(WasmToken::ConversionOpcode, Op::F64ConvertSI32,
     998           0 :                                      begin, cur_);
     999             :                 }
    1000           0 :                 if (consume(u"convert_u/i32")) {
    1001             :                     return WasmToken(WasmToken::ConversionOpcode, Op::F64ConvertUI32,
    1002           0 :                                      begin, cur_);
    1003             :                 }
    1004           0 :                 if (consume(u"convert_s/i64")) {
    1005             :                     return WasmToken(WasmToken::ConversionOpcode, Op::F64ConvertSI64,
    1006           0 :                                      begin, cur_);
    1007             :                 }
    1008           0 :                 if (consume(u"convert_u/i64")) {
    1009             :                     return WasmToken(WasmToken::ConversionOpcode, Op::F64ConvertUI64,
    1010           0 :                                      begin, cur_);
    1011             :                 }
    1012           0 :                 if (consume(u"copysign"))
    1013           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::F64CopySign, begin, cur_);
    1014           0 :                 break;
    1015             :               case 'd':
    1016           0 :                 if (consume(u"div"))
    1017           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::F64Div, begin, cur_);
    1018           0 :                 break;
    1019             :               case 'e':
    1020           0 :                 if (consume(u"eq"))
    1021           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::F64Eq, begin, cur_);
    1022           0 :                 break;
    1023             :               case 'f':
    1024           0 :                 if (consume(u"floor"))
    1025           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::F64Floor, begin, cur_);
    1026           0 :                 break;
    1027             :               case 'g':
    1028           0 :                 if (consume(u"ge"))
    1029           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::F64Ge, begin, cur_);
    1030           0 :                 if (consume(u"gt"))
    1031           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::F64Gt, begin, cur_);
    1032           0 :                 break;
    1033             :               case 'l':
    1034           0 :                 if (consume(u"le"))
    1035           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::F64Le, begin, cur_);
    1036           0 :                 if (consume(u"lt"))
    1037           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::F64Lt, begin, cur_);
    1038           0 :                 if (consume(u"load"))
    1039           0 :                     return WasmToken(WasmToken::Load, Op::F64Load, begin, cur_);
    1040           0 :                 break;
    1041             :               case 'm':
    1042           0 :                 if (consume(u"max"))
    1043           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::F64Max, begin, cur_);
    1044           0 :                 if (consume(u"min"))
    1045           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::F64Min, begin, cur_);
    1046           0 :                 if (consume(u"mul"))
    1047           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::F64Mul, begin, cur_);
    1048           0 :                 break;
    1049             :               case 'n':
    1050           0 :                 if (consume(u"nearest"))
    1051           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::F64Nearest, begin, cur_);
    1052           0 :                 if (consume(u"neg"))
    1053           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::F64Neg, begin, cur_);
    1054           0 :                 if (consume(u"ne"))
    1055           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::F64Ne, begin, cur_);
    1056           0 :                 break;
    1057             :               case 'p':
    1058           0 :                 if (consume(u"promote/f32"))
    1059             :                     return WasmToken(WasmToken::ConversionOpcode, Op::F64PromoteF32,
    1060           0 :                                      begin, cur_);
    1061           0 :                 break;
    1062             :               case 'r':
    1063           0 :                 if (consume(u"reinterpret/i64"))
    1064             :                     return WasmToken(WasmToken::UnaryOpcode, Op::F64ReinterpretI64,
    1065           0 :                                      begin, cur_);
    1066           0 :                 break;
    1067             :               case 's':
    1068           0 :                 if (consume(u"sqrt"))
    1069           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::F64Sqrt, begin, cur_);
    1070           0 :                 if (consume(u"sub"))
    1071           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::F64Sub, begin, cur_);
    1072           0 :                 if (consume(u"store"))
    1073           0 :                     return WasmToken(WasmToken::Store, Op::F64Store, begin, cur_);
    1074           0 :                 break;
    1075             :               case 't':
    1076           0 :                 if (consume(u"trunc"))
    1077           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::F64Trunc, begin, cur_);
    1078           0 :                 break;
    1079             :             }
    1080           0 :             break;
    1081             :         }
    1082           0 :         break;
    1083             : 
    1084             :       case 'g':
    1085           0 :         if (consume(u"get_global"))
    1086           0 :             return WasmToken(WasmToken::GetGlobal, begin, cur_);
    1087           0 :         if (consume(u"get_local"))
    1088           0 :             return WasmToken(WasmToken::GetLocal, begin, cur_);
    1089           0 :         if (consume(u"global"))
    1090           0 :             return WasmToken(WasmToken::Global, begin, cur_);
    1091           0 :         if (consume(u"grow_memory"))
    1092           0 :             return WasmToken(WasmToken::GrowMemory, begin, cur_);
    1093           0 :         break;
    1094             : 
    1095             :       case 'i':
    1096           0 :         if (consume(u"i32")) {
    1097           0 :             if (!consume(u"."))
    1098           0 :                 return WasmToken(WasmToken::ValueType, ValType::I32, begin, cur_);
    1099             : 
    1100           0 :             switch (*cur_) {
    1101             :               case 'a':
    1102           0 :                 if (consume(u"add"))
    1103           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I32Add, begin, cur_);
    1104           0 :                 if (consume(u"and"))
    1105           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I32And, begin, cur_);
    1106           0 :                 break;
    1107             :               case 'c':
    1108           0 :                 if (consume(u"const"))
    1109           0 :                     return WasmToken(WasmToken::Const, ValType::I32, begin, cur_);
    1110           0 :                 if (consume(u"clz"))
    1111           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::I32Clz, begin, cur_);
    1112           0 :                 if (consume(u"ctz"))
    1113           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::I32Ctz, begin, cur_);
    1114           0 :                 break;
    1115             :               case 'd':
    1116           0 :                 if (consume(u"div_s"))
    1117           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I32DivS, begin, cur_);
    1118           0 :                 if (consume(u"div_u"))
    1119           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I32DivU, begin, cur_);
    1120           0 :                 break;
    1121             :               case 'e':
    1122           0 :                 if (consume(u"eqz"))
    1123           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::I32Eqz, begin, cur_);
    1124           0 :                 if (consume(u"eq"))
    1125           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I32Eq, begin, cur_);
    1126           0 :                 break;
    1127             :               case 'g':
    1128           0 :                 if (consume(u"ge_s"))
    1129           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I32GeS, begin, cur_);
    1130           0 :                 if (consume(u"ge_u"))
    1131           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I32GeU, begin, cur_);
    1132           0 :                 if (consume(u"gt_s"))
    1133           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I32GtS, begin, cur_);
    1134           0 :                 if (consume(u"gt_u"))
    1135           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I32GtU, begin, cur_);
    1136           0 :                 break;
    1137             :               case 'l':
    1138           0 :                 if (consume(u"le_s"))
    1139           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I32LeS, begin, cur_);
    1140           0 :                 if (consume(u"le_u"))
    1141           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I32LeU, begin, cur_);
    1142           0 :                 if (consume(u"lt_s"))
    1143           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I32LtS, begin, cur_);
    1144           0 :                 if (consume(u"lt_u"))
    1145           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I32LtU, begin, cur_);
    1146           0 :                 if (consume(u"load")) {
    1147           0 :                     if (IsWasmSpace(*cur_))
    1148           0 :                         return WasmToken(WasmToken::Load, Op::I32Load, begin, cur_);
    1149           0 :                     if (consume(u"8_s"))
    1150           0 :                         return WasmToken(WasmToken::Load, Op::I32Load8S, begin, cur_);
    1151           0 :                     if (consume(u"8_u"))
    1152           0 :                         return WasmToken(WasmToken::Load, Op::I32Load8U, begin, cur_);
    1153           0 :                     if (consume(u"16_s"))
    1154           0 :                         return WasmToken(WasmToken::Load, Op::I32Load16S, begin, cur_);
    1155           0 :                     if (consume(u"16_u"))
    1156           0 :                         return WasmToken(WasmToken::Load, Op::I32Load16U, begin, cur_);
    1157           0 :                     break;
    1158             :                 }
    1159           0 :                 break;
    1160             :               case 'm':
    1161           0 :                 if (consume(u"mul"))
    1162           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I32Mul, begin, cur_);
    1163           0 :                 break;
    1164             :               case 'n':
    1165           0 :                 if (consume(u"ne"))
    1166           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I32Ne, begin, cur_);
    1167           0 :                 break;
    1168             :               case 'o':
    1169           0 :                 if (consume(u"or"))
    1170           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I32Or, begin, cur_);
    1171           0 :                 break;
    1172             :               case 'p':
    1173           0 :                 if (consume(u"popcnt"))
    1174           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::I32Popcnt, begin, cur_);
    1175           0 :                 break;
    1176             :               case 'r':
    1177           0 :                 if (consume(u"reinterpret/f32"))
    1178             :                     return WasmToken(WasmToken::UnaryOpcode, Op::I32ReinterpretF32,
    1179           0 :                                      begin, cur_);
    1180           0 :                 if (consume(u"rem_s"))
    1181           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I32RemS, begin, cur_);
    1182           0 :                 if (consume(u"rem_u"))
    1183           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I32RemU, begin, cur_);
    1184           0 :                 if (consume(u"rotr"))
    1185           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I32Rotr, begin, cur_);
    1186           0 :                 if (consume(u"rotl"))
    1187           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I32Rotl, begin, cur_);
    1188           0 :                 break;
    1189             :               case 's':
    1190           0 :                 if (consume(u"sub"))
    1191           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I32Sub, begin, cur_);
    1192           0 :                 if (consume(u"shl"))
    1193           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I32Shl, begin, cur_);
    1194           0 :                 if (consume(u"shr_s"))
    1195           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I32ShrS, begin, cur_);
    1196           0 :                 if (consume(u"shr_u"))
    1197           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I32ShrU, begin, cur_);
    1198           0 :                 if (consume(u"store")) {
    1199           0 :                     if (IsWasmSpace(*cur_))
    1200           0 :                         return WasmToken(WasmToken::Store, Op::I32Store, begin, cur_);
    1201           0 :                     if (consume(u"8"))
    1202           0 :                         return WasmToken(WasmToken::Store, Op::I32Store8, begin, cur_);
    1203           0 :                     if (consume(u"16"))
    1204           0 :                         return WasmToken(WasmToken::Store, Op::I32Store16, begin, cur_);
    1205           0 :                     break;
    1206             :                 }
    1207           0 :                 break;
    1208             :               case 't':
    1209           0 :                 if (consume(u"trunc_s/f32"))
    1210             :                     return WasmToken(WasmToken::ConversionOpcode, Op::I32TruncSF32,
    1211           0 :                                      begin, cur_);
    1212           0 :                 if (consume(u"trunc_s/f64"))
    1213             :                     return WasmToken(WasmToken::ConversionOpcode, Op::I32TruncSF64,
    1214           0 :                                      begin, cur_);
    1215           0 :                 if (consume(u"trunc_u/f32"))
    1216             :                     return WasmToken(WasmToken::ConversionOpcode, Op::I32TruncUF32,
    1217           0 :                                      begin, cur_);
    1218           0 :                 if (consume(u"trunc_u/f64"))
    1219             :                     return WasmToken(WasmToken::ConversionOpcode, Op::I32TruncUF64,
    1220           0 :                                      begin, cur_);
    1221           0 :                 break;
    1222             :               case 'w':
    1223           0 :                 if (consume(u"wrap/i64"))
    1224             :                     return WasmToken(WasmToken::ConversionOpcode, Op::I32WrapI64,
    1225           0 :                                      begin, cur_);
    1226           0 :                 break;
    1227             :               case 'x':
    1228           0 :                 if (consume(u"xor"))
    1229           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I32Xor, begin, cur_);
    1230           0 :                 break;
    1231             :             }
    1232           0 :             break;
    1233             :         }
    1234           0 :         if (consume(u"i64")) {
    1235           0 :             if (!consume(u"."))
    1236           0 :                 return WasmToken(WasmToken::ValueType, ValType::I64, begin, cur_);
    1237             : 
    1238           0 :             switch (*cur_) {
    1239             :               case 'a':
    1240           0 :                 if (consume(u"add"))
    1241           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I64Add, begin, cur_);
    1242           0 :                 if (consume(u"and"))
    1243           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I64And, begin, cur_);
    1244           0 :                 break;
    1245             :               case 'c':
    1246           0 :                 if (consume(u"const"))
    1247           0 :                     return WasmToken(WasmToken::Const, ValType::I64, begin, cur_);
    1248           0 :                 if (consume(u"clz"))
    1249           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::I64Clz, begin, cur_);
    1250           0 :                 if (consume(u"ctz"))
    1251           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::I64Ctz, begin, cur_);
    1252           0 :                 break;
    1253             :               case 'd':
    1254           0 :                 if (consume(u"div_s"))
    1255           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I64DivS, begin, cur_);
    1256           0 :                 if (consume(u"div_u"))
    1257           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I64DivU, begin, cur_);
    1258           0 :                 break;
    1259             :               case 'e':
    1260           0 :                 if (consume(u"eqz"))
    1261           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::I64Eqz, begin, cur_);
    1262           0 :                 if (consume(u"eq"))
    1263           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I64Eq, begin, cur_);
    1264           0 :                 if (consume(u"extend_s/i32"))
    1265             :                     return WasmToken(WasmToken::ConversionOpcode, Op::I64ExtendSI32,
    1266           0 :                                      begin, cur_);
    1267           0 :                 if (consume(u"extend_u/i32"))
    1268             :                     return WasmToken(WasmToken::ConversionOpcode, Op::I64ExtendUI32,
    1269           0 :                                      begin, cur_);
    1270           0 :                 break;
    1271             :               case 'g':
    1272           0 :                 if (consume(u"ge_s"))
    1273           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I64GeS, begin, cur_);
    1274           0 :                 if (consume(u"ge_u"))
    1275           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I64GeU, begin, cur_);
    1276           0 :                 if (consume(u"gt_s"))
    1277           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I64GtS, begin, cur_);
    1278           0 :                 if (consume(u"gt_u"))
    1279           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I64GtU, begin, cur_);
    1280           0 :                 break;
    1281             :               case 'l':
    1282           0 :                 if (consume(u"le_s"))
    1283           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I64LeS, begin, cur_);
    1284           0 :                 if (consume(u"le_u"))
    1285           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I64LeU, begin, cur_);
    1286           0 :                 if (consume(u"lt_s"))
    1287           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I64LtS, begin, cur_);
    1288           0 :                 if (consume(u"lt_u"))
    1289           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I64LtU, begin, cur_);
    1290           0 :                 if (consume(u"load")) {
    1291           0 :                     if (IsWasmSpace(*cur_))
    1292           0 :                         return WasmToken(WasmToken::Load, Op::I64Load, begin, cur_);
    1293           0 :                     if (consume(u"8_s"))
    1294           0 :                         return WasmToken(WasmToken::Load, Op::I64Load8S, begin, cur_);
    1295           0 :                     if (consume(u"8_u"))
    1296           0 :                         return WasmToken(WasmToken::Load, Op::I64Load8U, begin, cur_);
    1297           0 :                     if (consume(u"16_s"))
    1298           0 :                         return WasmToken(WasmToken::Load, Op::I64Load16S, begin, cur_);
    1299           0 :                     if (consume(u"16_u"))
    1300           0 :                         return WasmToken(WasmToken::Load, Op::I64Load16U, begin, cur_);
    1301           0 :                     if (consume(u"32_s"))
    1302           0 :                         return WasmToken(WasmToken::Load, Op::I64Load32S, begin, cur_);
    1303           0 :                     if (consume(u"32_u"))
    1304           0 :                         return WasmToken(WasmToken::Load, Op::I64Load32U, begin, cur_);
    1305           0 :                     break;
    1306             :                 }
    1307           0 :                 break;
    1308             :               case 'm':
    1309           0 :                 if (consume(u"mul"))
    1310           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I64Mul, begin, cur_);
    1311           0 :                 break;
    1312             :               case 'n':
    1313           0 :                 if (consume(u"ne"))
    1314           0 :                     return WasmToken(WasmToken::ComparisonOpcode, Op::I64Ne, begin, cur_);
    1315           0 :                 break;
    1316             :               case 'o':
    1317           0 :                 if (consume(u"or"))
    1318           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I64Or, begin, cur_);
    1319           0 :                 break;
    1320             :               case 'p':
    1321           0 :                 if (consume(u"popcnt"))
    1322           0 :                     return WasmToken(WasmToken::UnaryOpcode, Op::I64Popcnt, begin, cur_);
    1323           0 :                 break;
    1324             :               case 'r':
    1325           0 :                 if (consume(u"reinterpret/f64"))
    1326             :                     return WasmToken(WasmToken::UnaryOpcode, Op::I64ReinterpretF64,
    1327           0 :                                      begin, cur_);
    1328           0 :                 if (consume(u"rem_s"))
    1329           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I64RemS, begin, cur_);
    1330           0 :                 if (consume(u"rem_u"))
    1331           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I64RemU, begin, cur_);
    1332           0 :                 if (consume(u"rotr"))
    1333           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I64Rotr, begin, cur_);
    1334           0 :                 if (consume(u"rotl"))
    1335           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I64Rotl, begin, cur_);
    1336           0 :                 break;
    1337             :               case 's':
    1338           0 :                 if (consume(u"sub"))
    1339           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I64Sub, begin, cur_);
    1340           0 :                 if (consume(u"shl"))
    1341           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I64Shl, begin, cur_);
    1342           0 :                 if (consume(u"shr_s"))
    1343           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I64ShrS, begin, cur_);
    1344           0 :                 if (consume(u"shr_u"))
    1345           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I64ShrU, begin, cur_);
    1346           0 :                 if (consume(u"store")) {
    1347           0 :                     if (IsWasmSpace(*cur_))
    1348           0 :                         return WasmToken(WasmToken::Store, Op::I64Store, begin, cur_);
    1349           0 :                     if (consume(u"8"))
    1350           0 :                         return WasmToken(WasmToken::Store, Op::I64Store8, begin, cur_);
    1351           0 :                     if (consume(u"16"))
    1352           0 :                         return WasmToken(WasmToken::Store, Op::I64Store16, begin, cur_);
    1353           0 :                     if (consume(u"32"))
    1354           0 :                         return WasmToken(WasmToken::Store, Op::I64Store32, begin, cur_);
    1355           0 :                     break;
    1356             :                 }
    1357           0 :                 break;
    1358             :               case 't':
    1359           0 :                 if (consume(u"trunc_s/f32"))
    1360             :                     return WasmToken(WasmToken::ConversionOpcode, Op::I64TruncSF32,
    1361           0 :                                      begin, cur_);
    1362           0 :                 if (consume(u"trunc_s/f64"))
    1363             :                     return WasmToken(WasmToken::ConversionOpcode, Op::I64TruncSF64,
    1364           0 :                                      begin, cur_);
    1365           0 :                 if (consume(u"trunc_u/f32"))
    1366             :                     return WasmToken(WasmToken::ConversionOpcode, Op::I64TruncUF32,
    1367           0 :                                      begin, cur_);
    1368           0 :                 if (consume(u"trunc_u/f64"))
    1369             :                     return WasmToken(WasmToken::ConversionOpcode, Op::I64TruncUF64,
    1370           0 :                                      begin, cur_);
    1371           0 :                 break;
    1372             :               case 'x':
    1373           0 :                 if (consume(u"xor"))
    1374           0 :                     return WasmToken(WasmToken::BinaryOpcode, Op::I64Xor, begin, cur_);
    1375           0 :                 break;
    1376             :             }
    1377           0 :             break;
    1378             :         }
    1379           0 :         if (consume(u"import"))
    1380           0 :             return WasmToken(WasmToken::Import, begin, cur_);
    1381           0 :         if (consume(u"infinity"))
    1382           0 :             return WasmToken(WasmToken::Infinity, begin, cur_);
    1383           0 :         if (consume(u"if"))
    1384           0 :             return WasmToken(WasmToken::If, begin, cur_);
    1385           0 :         break;
    1386             : 
    1387             :       case 'l':
    1388           0 :         if (consume(u"local"))
    1389           0 :             return WasmToken(WasmToken::Local, begin, cur_);
    1390           0 :         if (consume(u"loop"))
    1391           0 :             return WasmToken(WasmToken::Loop, begin, cur_);
    1392           0 :         break;
    1393             : 
    1394             :       case 'm':
    1395           0 :         if (consume(u"module"))
    1396           0 :             return WasmToken(WasmToken::Module, begin, cur_);
    1397           0 :         if (consume(u"memory"))
    1398           0 :             return WasmToken(WasmToken::Memory, begin, cur_);
    1399           0 :         if (consume(u"mut"))
    1400           0 :             return WasmToken(WasmToken::Mutable, begin, cur_);
    1401           0 :         break;
    1402             : 
    1403             :       case 'n':
    1404           0 :         if (consume(u"nan"))
    1405           0 :             return nan(begin);
    1406           0 :         if (consume(u"nop"))
    1407           0 :             return WasmToken(WasmToken::Nop, begin, cur_);
    1408           0 :         break;
    1409             : 
    1410             :       case 'o':
    1411           0 :         if (consume(u"offset"))
    1412           0 :             return WasmToken(WasmToken::Offset, begin, cur_);
    1413           0 :         break;
    1414             : 
    1415             :       case 'p':
    1416           0 :         if (consume(u"param"))
    1417           0 :             return WasmToken(WasmToken::Param, begin, cur_);
    1418           0 :         break;
    1419             : 
    1420             :       case 'r':
    1421           0 :         if (consume(u"result"))
    1422           0 :             return WasmToken(WasmToken::Result, begin, cur_);
    1423           0 :         if (consume(u"return"))
    1424           0 :             return WasmToken(WasmToken::Return, begin, cur_);
    1425           0 :         break;
    1426             : 
    1427             :       case 's':
    1428           0 :         if (consume(u"select"))
    1429           0 :             return WasmToken(WasmToken::TernaryOpcode, Op::Select, begin, cur_);
    1430           0 :         if (consume(u"set_global"))
    1431           0 :             return WasmToken(WasmToken::SetGlobal, begin, cur_);
    1432           0 :         if (consume(u"set_local"))
    1433           0 :             return WasmToken(WasmToken::SetLocal, begin, cur_);
    1434           0 :         if (consume(u"start"))
    1435           0 :             return WasmToken(WasmToken::Start, begin, cur_);
    1436           0 :         break;
    1437             : 
    1438             :       case 't':
    1439           0 :         if (consume(u"table"))
    1440           0 :             return WasmToken(WasmToken::Table, begin, cur_);
    1441           0 :         if (consume(u"tee_local"))
    1442           0 :             return WasmToken(WasmToken::TeeLocal, begin, cur_);
    1443           0 :         if (consume(u"then"))
    1444           0 :             return WasmToken(WasmToken::Then, begin, cur_);
    1445           0 :         if (consume(u"type"))
    1446           0 :             return WasmToken(WasmToken::Type, begin, cur_);
    1447           0 :         break;
    1448             : 
    1449             :       case 'u':
    1450           0 :         if (consume(u"unreachable"))
    1451           0 :             return WasmToken(WasmToken::Unreachable, begin, cur_);
    1452           0 :         break;
    1453             : 
    1454             :       default:
    1455           0 :         break;
    1456             :     }
    1457             : 
    1458           0 :     return fail(begin);
    1459             : }
    1460             : 
    1461             : /*****************************************************************************/
    1462             : // wasm text format parser
    1463             : 
    1464             : namespace {
    1465             : 
    1466             : struct WasmParseContext
    1467             : {
    1468             :     WasmTokenStream ts;
    1469             :     LifoAlloc& lifo;
    1470             :     UniqueChars* error;
    1471             :     DtoaState* dtoaState;
    1472             : 
    1473           0 :     WasmParseContext(const char16_t* text, LifoAlloc& lifo, UniqueChars* error)
    1474           0 :       : ts(text, error),
    1475             :         lifo(lifo),
    1476             :         error(error),
    1477           0 :         dtoaState(NewDtoaState())
    1478           0 :     {}
    1479             : 
    1480           0 :     ~WasmParseContext() {
    1481           0 :         DestroyDtoaState(dtoaState);
    1482           0 :     }
    1483             : };
    1484             : 
    1485             : } // end anonymous namespace
    1486             : 
    1487             : static AstExpr*
    1488             : ParseExprInsideParens(WasmParseContext& c);
    1489             : 
    1490             : static AstExpr*
    1491             : ParseExprBody(WasmParseContext& c, WasmToken token, bool inParens);
    1492             : 
    1493             : static AstExpr*
    1494           0 : ParseExpr(WasmParseContext& c, bool inParens)
    1495             : {
    1496           0 :     WasmToken openParen;
    1497           0 :     if (!inParens || !c.ts.getIf(WasmToken::OpenParen, &openParen))
    1498           0 :         return new(c.lifo) AstPop();
    1499             : 
    1500             :     // Special case: If we have an open paren, but it's a "(then ...", then
    1501             :     // we don't have an expresion following us, so we pop here too. This
    1502             :     // handles "(if (then ...))" which pops the condition.
    1503           0 :     if (c.ts.peek().kind() == WasmToken::Then) {
    1504           0 :         c.ts.unget(openParen);
    1505           0 :         return new(c.lifo) AstPop();
    1506             :     }
    1507             : 
    1508           0 :     AstExpr* expr = ParseExprInsideParens(c);
    1509           0 :     if (!expr)
    1510           0 :         return nullptr;
    1511             : 
    1512           0 :     if (!c.ts.match(WasmToken::CloseParen, c.error))
    1513           0 :         return nullptr;
    1514             : 
    1515           0 :     return expr;
    1516             : }
    1517             : 
    1518             : static bool
    1519           0 : ParseExprList(WasmParseContext& c, AstExprVector* exprs, bool inParens)
    1520             : {
    1521             :     for (;;) {
    1522           0 :         if (c.ts.getIf(WasmToken::OpenParen)) {
    1523           0 :             AstExpr* expr = ParseExprInsideParens(c);
    1524           0 :             if (!expr || !exprs->append(expr))
    1525           0 :                 return false;
    1526           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    1527           0 :                 return false;
    1528           0 :             continue;
    1529             :         }
    1530             : 
    1531           0 :         WasmToken token;
    1532           0 :         if (c.ts.getIfOpcode(&token)) {
    1533           0 :             AstExpr* expr = ParseExprBody(c, token, false);
    1534           0 :             if (!expr || !exprs->append(expr))
    1535           0 :                 return false;
    1536           0 :             continue;
    1537             :         }
    1538             : 
    1539           0 :         break;
    1540           0 :     }
    1541             : 
    1542           0 :     return true;
    1543             : }
    1544             : 
    1545             : static bool
    1546           0 : ParseBlockSignature(WasmParseContext& c, ExprType* type)
    1547             : {
    1548           0 :     WasmToken token;
    1549           0 :     if (c.ts.getIf(WasmToken::ValueType, &token))
    1550           0 :         *type = ToExprType(token.valueType());
    1551             :     else
    1552           0 :         *type = ExprType::Void;
    1553             : 
    1554           0 :     return true;
    1555             : }
    1556             : 
    1557             : static bool
    1558           0 : MaybeMatchName(WasmParseContext& c, const AstName& name)
    1559             : {
    1560           0 :     WasmToken tok;
    1561           0 :     if (c.ts.getIf(WasmToken::Name, &tok)) {
    1562           0 :         AstName otherName = tok.name();
    1563           0 :         if (otherName.empty())
    1564           0 :             return true;
    1565             : 
    1566           0 :         if (name.empty()) {
    1567           0 :             c.ts.generateError(tok, "end name without a start name", c.error);
    1568           0 :             return false;
    1569             :         }
    1570             : 
    1571           0 :         if (otherName != name) {
    1572           0 :             c.ts.generateError(tok, "start/end names don't match", c.error);
    1573           0 :             return false;
    1574             :         }
    1575             :     }
    1576           0 :     return true;
    1577             : }
    1578             : 
    1579             : static AstBlock*
    1580           0 : ParseBlock(WasmParseContext& c, Op op, bool inParens)
    1581             : {
    1582           0 :     AstExprVector exprs(c.lifo);
    1583             : 
    1584           0 :     AstName name = c.ts.getIfName();
    1585             : 
    1586             :     // Compatibility syntax sugar: If a second label is present, we'll wrap
    1587             :     // this loop in a block.
    1588           0 :     AstName otherName;
    1589           0 :     if (op == Op::Loop) {
    1590           0 :         AstName maybeName = c.ts.getIfName();
    1591           0 :         if (!maybeName.empty()) {
    1592           0 :             otherName = name;
    1593           0 :             name = maybeName;
    1594             :         }
    1595             :     }
    1596             : 
    1597             :     ExprType type;
    1598           0 :     if (!ParseBlockSignature(c, &type))
    1599           0 :         return nullptr;
    1600             : 
    1601           0 :     if (!ParseExprList(c, &exprs, inParens))
    1602           0 :         return nullptr;
    1603             : 
    1604           0 :     if (!inParens) {
    1605           0 :         if (!c.ts.match(WasmToken::End, c.error))
    1606           0 :             return nullptr;
    1607           0 :         if (!MaybeMatchName(c, name))
    1608           0 :             return nullptr;
    1609             :     }
    1610             : 
    1611           0 :     AstBlock* result = new(c.lifo) AstBlock(op, type, name, Move(exprs));
    1612           0 :     if (!result)
    1613           0 :         return nullptr;
    1614             : 
    1615           0 :     if (op == Op::Loop && !otherName.empty()) {
    1616           0 :         if (!exprs.append(result))
    1617           0 :             return nullptr;
    1618           0 :         result = new(c.lifo) AstBlock(Op::Block, type, otherName, Move(exprs));
    1619             :     }
    1620             : 
    1621           0 :     return result;
    1622             : }
    1623             : 
    1624             : static AstBranch*
    1625           0 : ParseBranch(WasmParseContext& c, Op op, bool inParens)
    1626             : {
    1627           0 :     MOZ_ASSERT(op == Op::Br || op == Op::BrIf);
    1628             : 
    1629           0 :     AstRef target;
    1630           0 :     if (!c.ts.matchRef(&target, c.error))
    1631           0 :         return nullptr;
    1632             : 
    1633           0 :     AstExpr* value = nullptr;
    1634           0 :     if (inParens) {
    1635           0 :         if (c.ts.getIf(WasmToken::OpenParen)) {
    1636           0 :             value = ParseExprInsideParens(c);
    1637           0 :             if (!value)
    1638           0 :                 return nullptr;
    1639           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    1640           0 :                 return nullptr;
    1641             :         }
    1642             :     }
    1643             : 
    1644           0 :     AstExpr* cond = nullptr;
    1645           0 :     if (op == Op::BrIf) {
    1646           0 :         if (inParens && c.ts.getIf(WasmToken::OpenParen)) {
    1647           0 :             cond = ParseExprInsideParens(c);
    1648           0 :             if (!cond)
    1649           0 :                 return nullptr;
    1650           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    1651           0 :                 return nullptr;
    1652             :         } else {
    1653           0 :             cond = new(c.lifo) AstPop();
    1654           0 :             if (!cond)
    1655           0 :                 return nullptr;
    1656             :         }
    1657             :     }
    1658             : 
    1659           0 :     return new(c.lifo) AstBranch(op, ExprType::Void, cond, target, value);
    1660             : }
    1661             : 
    1662             : static bool
    1663           0 : ParseArgs(WasmParseContext& c, AstExprVector* args)
    1664             : {
    1665           0 :     while (c.ts.getIf(WasmToken::OpenParen)) {
    1666           0 :         AstExpr* arg = ParseExprInsideParens(c);
    1667           0 :         if (!arg || !args->append(arg))
    1668           0 :             return false;
    1669           0 :         if (!c.ts.match(WasmToken::CloseParen, c.error))
    1670           0 :             return false;
    1671             :     }
    1672             : 
    1673           0 :     return true;
    1674             : }
    1675             : 
    1676             : static AstCall*
    1677           0 : ParseCall(WasmParseContext& c, bool inParens)
    1678             : {
    1679           0 :     AstRef func;
    1680           0 :     if (!c.ts.matchRef(&func, c.error))
    1681           0 :         return nullptr;
    1682             : 
    1683           0 :     AstExprVector args(c.lifo);
    1684           0 :     if (inParens) {
    1685           0 :         if (!ParseArgs(c, &args))
    1686           0 :             return nullptr;
    1687             :     }
    1688             : 
    1689           0 :     return new(c.lifo) AstCall(Op::Call, ExprType::Void, func, Move(args));
    1690             : }
    1691             : 
    1692             : static AstCallIndirect*
    1693           0 : ParseCallIndirect(WasmParseContext& c, bool inParens)
    1694             : {
    1695           0 :     AstRef sig;
    1696           0 :     if (!c.ts.matchRef(&sig, c.error))
    1697           0 :         return nullptr;
    1698             : 
    1699           0 :     AstExprVector args(c.lifo);
    1700             :     AstExpr* index;
    1701           0 :     if (inParens) {
    1702           0 :         if (!ParseArgs(c, &args))
    1703           0 :             return nullptr;
    1704             : 
    1705           0 :         if (args.empty())
    1706           0 :             index = new(c.lifo) AstPop();
    1707             :         else
    1708           0 :             index = args.popCopy();
    1709             :     } else {
    1710           0 :         index = new(c.lifo) AstPop();
    1711             :     }
    1712             : 
    1713           0 :     return new(c.lifo) AstCallIndirect(sig, ExprType::Void, Move(args), index);
    1714             : }
    1715             : 
    1716             : static uint_fast8_t
    1717           0 : CountLeadingZeroes4(uint8_t x)
    1718             : {
    1719           0 :     MOZ_ASSERT((x & -0x10) == 0);
    1720           0 :     return CountLeadingZeroes32(x) - 28;
    1721             : }
    1722             : 
    1723             : template <typename T>
    1724             : static T
    1725           0 : ushl(T lhs, unsigned rhs)
    1726             : {
    1727           0 :     return rhs < sizeof(T) * CHAR_BIT ? (lhs << rhs) : 0;
    1728             : }
    1729             : 
    1730             : template <typename T>
    1731             : static T
    1732           0 : ushr(T lhs, unsigned rhs)
    1733             : {
    1734           0 :     return rhs < sizeof(T) * CHAR_BIT ? (lhs >> rhs) : 0;
    1735             : }
    1736             : 
    1737             : template<typename Float>
    1738             : static AstConst*
    1739           0 : ParseNaNLiteral(WasmParseContext& c, WasmToken token, const char16_t* cur, bool isNegated)
    1740             : {
    1741           0 :     const char16_t* end = token.end();
    1742             : 
    1743           0 :     MOZ_ALWAYS_TRUE(*cur++ == 'n' && *cur++ == 'a' && *cur++ == 'n');
    1744             : 
    1745             :     typedef FloatingPoint<Float> Traits;
    1746             :     typedef typename Traits::Bits Bits;
    1747             : 
    1748             :     Bits value;
    1749           0 :     if (cur != end) {
    1750           0 :         MOZ_ALWAYS_TRUE(*cur++ == ':' && *cur++ == '0' && *cur++ == 'x');
    1751           0 :         if (cur == end)
    1752           0 :             goto error;
    1753           0 :         CheckedInt<Bits> u = 0;
    1754           0 :         do {
    1755           0 :             uint8_t digit = 0;
    1756           0 :             MOZ_ALWAYS_TRUE(IsHexDigit(*cur, &digit));
    1757           0 :             u *= 16;
    1758           0 :             u += digit;
    1759           0 :             cur++;
    1760           0 :         } while (cur != end);
    1761           0 :         if (!u.isValid())
    1762           0 :             goto error;
    1763           0 :         value = u.value();
    1764           0 :         if ((value & ~Traits::kSignificandBits) != 0)
    1765           0 :             goto error;
    1766             :         // NaN payloads must contain at least one set bit.
    1767           0 :         if (value == 0)
    1768           0 :             goto error;
    1769             :     } else {
    1770             :         // Produce the spec's default NaN.
    1771           0 :         value = (Traits::kSignificandBits + 1) >> 1;
    1772             :     }
    1773             : 
    1774           0 :     value = (isNegated ? Traits::kSignBit : 0) | Traits::kExponentBits | value;
    1775             : 
    1776             :     Float flt;
    1777           0 :     BitwiseCast(value, &flt);
    1778           0 :     return new (c.lifo) AstConst(Val(flt));
    1779             : 
    1780             :   error:
    1781           0 :     c.ts.generateError(token, c.error);
    1782           0 :     return nullptr;
    1783             : }
    1784             : 
    1785             : template <typename Float>
    1786             : static bool
    1787           0 : ParseHexFloatLiteral(const char16_t* cur, const char16_t* end, Float* result)
    1788             : {
    1789           0 :     MOZ_ALWAYS_TRUE(*cur++ == '0' && *cur++ == 'x');
    1790             :     typedef FloatingPoint<Float> Traits;
    1791             :     typedef typename Traits::Bits Bits;
    1792             :     static const unsigned numBits = sizeof(Float) * CHAR_BIT;
    1793             :     static const Bits allOnes = ~Bits(0);
    1794             :     static const Bits mostSignificantBit = ~(allOnes >> 1);
    1795             : 
    1796             :     // Significand part.
    1797           0 :     Bits significand = 0;
    1798           0 :     CheckedInt<int32_t> exponent = 0;
    1799           0 :     bool sawFirstNonZero = false;
    1800           0 :     bool discardedExtraNonZero = false;
    1801           0 :     const char16_t* dot = nullptr;
    1802             :     int significandPos;
    1803           0 :     for (; cur != end; cur++) {
    1804           0 :         if (*cur == '.') {
    1805           0 :             MOZ_ASSERT(!dot);
    1806           0 :             dot = cur;
    1807           0 :             continue;
    1808             :         }
    1809             : 
    1810             :         uint8_t digit;
    1811           0 :         if (!IsHexDigit(*cur, &digit))
    1812           0 :             break;
    1813           0 :         if (!sawFirstNonZero) {
    1814           0 :             if (digit == 0)
    1815           0 :                 continue;
    1816             :             // We've located the first non-zero digit; we can now determine the
    1817             :             // initial exponent. If we're after the dot, count the number of
    1818             :             // zeros from the dot to here, and adjust for the number of leading
    1819             :             // zero bits in the digit. Set up significandPos to put the first
    1820             :             // nonzero at the most significant bit.
    1821           0 :             int_fast8_t lz = CountLeadingZeroes4(digit);
    1822           0 :             ptrdiff_t zeroAdjustValue = !dot ? 1 : dot + 1 - cur;
    1823           0 :             CheckedInt<ptrdiff_t> zeroAdjust = zeroAdjustValue;
    1824           0 :             zeroAdjust *= 4;
    1825           0 :             zeroAdjust -= lz + 1;
    1826           0 :             if (!zeroAdjust.isValid())
    1827           0 :                 return false;
    1828           0 :             exponent = zeroAdjust.value();
    1829           0 :             significandPos = numBits - (4 - lz);
    1830           0 :             sawFirstNonZero = true;
    1831             :         } else {
    1832             :             // We've already seen a non-zero; just take 4 more bits.
    1833           0 :             if (!dot)
    1834           0 :                 exponent += 4;
    1835           0 :             if (significandPos > -4)
    1836           0 :                 significandPos -= 4;
    1837             :         }
    1838             : 
    1839             :         // Or the newly parsed digit into significand at signicandPos.
    1840           0 :         if (significandPos >= 0) {
    1841           0 :             significand |= ushl(Bits(digit), significandPos);
    1842           0 :         } else if (significandPos > -4) {
    1843           0 :             significand |= ushr(digit, 4 - significandPos);
    1844           0 :             discardedExtraNonZero = (digit & ~ushl(allOnes, 4 - significandPos)) != 0;
    1845           0 :         } else if (digit != 0) {
    1846           0 :             discardedExtraNonZero = true;
    1847             :         }
    1848             :     }
    1849             : 
    1850             :     // Exponent part.
    1851           0 :     if (cur != end) {
    1852           0 :         MOZ_ALWAYS_TRUE(*cur++ == 'p');
    1853           0 :         bool isNegated = false;
    1854           0 :         if (cur != end && (*cur == '-' || *cur == '+'))
    1855           0 :             isNegated = *cur++ == '-';
    1856           0 :         CheckedInt<int32_t> parsedExponent = 0;
    1857           0 :         while (cur != end && IsWasmDigit(*cur))
    1858           0 :             parsedExponent = parsedExponent * 10 + (*cur++ - '0');
    1859           0 :         if (isNegated)
    1860           0 :             parsedExponent = -parsedExponent;
    1861           0 :         exponent += parsedExponent;
    1862             :     }
    1863             : 
    1864           0 :     MOZ_ASSERT(cur == end);
    1865           0 :     if (!exponent.isValid())
    1866           0 :         return false;
    1867             : 
    1868             :     // Create preliminary exponent and significand encodings of the results.
    1869             :     Bits encodedExponent, encodedSignificand, discardedSignificandBits;
    1870           0 :     if (significand == 0) {
    1871             :         // Zero. The exponent is encoded non-biased.
    1872           0 :         encodedExponent = 0;
    1873           0 :         encodedSignificand = 0;
    1874           0 :         discardedSignificandBits = 0;
    1875           0 :     } else if (MOZ_UNLIKELY(exponent.value() <= int32_t(-Traits::kExponentBias))) {
    1876             :         // Underflow to subnormal or zero.
    1877           0 :         encodedExponent = 0;
    1878           0 :         encodedSignificand = ushr(significand,
    1879             :                                   numBits - Traits::kExponentShift -
    1880           0 :                                   exponent.value() - Traits::kExponentBias);
    1881           0 :         discardedSignificandBits =
    1882           0 :             ushl(significand,
    1883           0 :                  Traits::kExponentShift + exponent.value() + Traits::kExponentBias);
    1884           0 :     } else if (MOZ_LIKELY(exponent.value() <= int32_t(Traits::kExponentBias))) {
    1885             :         // Normal (non-zero). The significand's leading 1 is encoded implicitly.
    1886           0 :         encodedExponent = (Bits(exponent.value()) + Traits::kExponentBias) <<
    1887             :                           Traits::kExponentShift;
    1888           0 :         MOZ_ASSERT(significand & mostSignificantBit);
    1889           0 :         encodedSignificand = ushr(significand, numBits - Traits::kExponentShift - 1) &
    1890             :                              Traits::kSignificandBits;
    1891           0 :         discardedSignificandBits = ushl(significand, Traits::kExponentShift + 1);
    1892             :     } else {
    1893             :         // Overflow to infinity.
    1894           0 :         encodedExponent = Traits::kExponentBits;
    1895           0 :         encodedSignificand = 0;
    1896           0 :         discardedSignificandBits = 0;
    1897             :     }
    1898           0 :     MOZ_ASSERT((encodedExponent & ~Traits::kExponentBits) == 0);
    1899           0 :     MOZ_ASSERT((encodedSignificand & ~Traits::kSignificandBits) == 0);
    1900           0 :     MOZ_ASSERT(encodedExponent != Traits::kExponentBits || encodedSignificand == 0);
    1901           0 :     Bits bits = encodedExponent | encodedSignificand;
    1902             : 
    1903             :     // Apply rounding. If this overflows the significand, it carries into the
    1904             :     // exponent bit according to the magic of the IEEE 754 encoding.
    1905           0 :     bits += (discardedSignificandBits & mostSignificantBit) &&
    1906           0 :             ((discardedSignificandBits & ~mostSignificantBit) ||
    1907           0 :              discardedExtraNonZero ||
    1908             :              // ties to even
    1909           0 :              (encodedSignificand & 1));
    1910             : 
    1911           0 :     *result = BitwiseCast<Float>(bits);
    1912           0 :     return true;
    1913             : }
    1914             : 
    1915             : template <typename Float>
    1916             : static AstConst*
    1917           0 : ParseFloatLiteral(WasmParseContext& c, WasmToken token)
    1918             : {
    1919             :     Float result;
    1920           0 :     switch (token.kind()) {
    1921           0 :       case WasmToken::Index:           result = token.index(); break;
    1922           0 :       case WasmToken::UnsignedInteger: result = token.uint(); break;
    1923           0 :       case WasmToken::SignedInteger:   result = token.sint(); break;
    1924           0 :       case WasmToken::NegativeZero:    result = -0.; break;
    1925           0 :       case WasmToken::Float:           break;
    1926           0 :       default:                         c.ts.generateError(token, c.error); return nullptr;
    1927             :     }
    1928             : 
    1929           0 :     if (token.kind() != WasmToken::Float)
    1930           0 :         return new (c.lifo) AstConst(Val(Float(result)));
    1931             : 
    1932           0 :     const char16_t* begin = token.begin();
    1933           0 :     const char16_t* end = token.end();
    1934           0 :     const char16_t* cur = begin;
    1935             : 
    1936           0 :     bool isNegated = false;
    1937           0 :     if (*cur == '-' || *cur == '+')
    1938           0 :         isNegated = *cur++ == '-';
    1939             : 
    1940           0 :     switch (token.floatLiteralKind()) {
    1941             :       case WasmToken::Infinity: {
    1942           0 :         result = PositiveInfinity<Float>();
    1943           0 :         break;
    1944             :       }
    1945             :       case WasmToken::NaN: {
    1946           0 :         return ParseNaNLiteral<Float>(c, token, cur, isNegated);
    1947             :       }
    1948             :       case WasmToken::HexNumber: {
    1949           0 :         if (!ParseHexFloatLiteral(cur, end, &result)) {
    1950           0 :             c.ts.generateError(token, c.error);
    1951           0 :             return nullptr;
    1952             :         }
    1953           0 :         break;
    1954             :       }
    1955             :       case WasmToken::DecNumber: {
    1956             :         // Call into JS' strtod. Tokenization has already required that the
    1957             :         // string is well-behaved.
    1958           0 :         LifoAlloc::Mark mark = c.lifo.mark();
    1959           0 :         char* buffer = c.lifo.newArray<char>(end - cur + 1);
    1960           0 :         if (!buffer)
    1961           0 :             return nullptr;
    1962           0 :         for (ptrdiff_t i = 0; i < end - cur; ++i)
    1963           0 :             buffer[i] = char(cur[i]);
    1964           0 :         buffer[end - cur] = '\0';
    1965             :         char* strtod_end;
    1966             :         int err;
    1967           0 :         result = (Float)js_strtod_harder(c.dtoaState, buffer, &strtod_end, &err);
    1968           0 :         if (err != 0 || strtod_end == buffer) {
    1969           0 :             c.lifo.release(mark);
    1970           0 :             c.ts.generateError(token, c.error);
    1971           0 :             return nullptr;
    1972             :         }
    1973           0 :         c.lifo.release(mark);
    1974           0 :         break;
    1975             :       }
    1976             :     }
    1977             : 
    1978           0 :     if (isNegated)
    1979           0 :         result = -result;
    1980             : 
    1981           0 :     return new (c.lifo) AstConst(Val(Float(result)));
    1982             : }
    1983             : 
    1984             : static AstConst*
    1985           0 : ParseConst(WasmParseContext& c, WasmToken constToken)
    1986             : {
    1987           0 :     WasmToken val = c.ts.get();
    1988           0 :     switch (constToken.valueType()) {
    1989             :       case ValType::I32: {
    1990           0 :         switch (val.kind()) {
    1991             :           case WasmToken::Index:
    1992           0 :             return new(c.lifo) AstConst(Val(val.index()));
    1993             :           case WasmToken::SignedInteger: {
    1994           0 :             CheckedInt<int32_t> sint = val.sint();
    1995           0 :             if (!sint.isValid())
    1996           0 :                 break;
    1997           0 :             return new(c.lifo) AstConst(Val(uint32_t(sint.value())));
    1998             :           }
    1999             :           case WasmToken::NegativeZero:
    2000           0 :             return new(c.lifo) AstConst(Val(uint32_t(0)));
    2001             :           default:
    2002           0 :             break;
    2003             :         }
    2004           0 :         break;
    2005             :       }
    2006             :       case ValType::I64: {
    2007           0 :         switch (val.kind()) {
    2008             :           case WasmToken::Index:
    2009           0 :             return new(c.lifo) AstConst(Val(uint64_t(val.index())));
    2010             :           case WasmToken::UnsignedInteger:
    2011           0 :             return new(c.lifo) AstConst(Val(val.uint()));
    2012             :           case WasmToken::SignedInteger:
    2013           0 :             return new(c.lifo) AstConst(Val(uint64_t(val.sint())));
    2014             :           case WasmToken::NegativeZero:
    2015           0 :             return new(c.lifo) AstConst(Val(uint64_t(0)));
    2016             :           default:
    2017           0 :             break;
    2018             :         }
    2019           0 :         break;
    2020             :       }
    2021             :       case ValType::F32: {
    2022           0 :         return ParseFloatLiteral<float>(c, val);
    2023             :       }
    2024             :       case ValType::F64: {
    2025           0 :         return ParseFloatLiteral<double>(c, val);
    2026             :       }
    2027             :       default:
    2028           0 :         break;
    2029             :     }
    2030           0 :     c.ts.generateError(constToken, c.error);
    2031           0 :     return nullptr;
    2032             : }
    2033             : 
    2034             : static AstGetLocal*
    2035           0 : ParseGetLocal(WasmParseContext& c)
    2036             : {
    2037           0 :     AstRef local;
    2038           0 :     if (!c.ts.matchRef(&local, c.error))
    2039           0 :         return nullptr;
    2040             : 
    2041           0 :     return new(c.lifo) AstGetLocal(local);
    2042             : }
    2043             : 
    2044             : static AstGetGlobal*
    2045           0 : ParseGetGlobal(WasmParseContext& c)
    2046             : {
    2047           0 :     AstRef local;
    2048           0 :     if (!c.ts.matchRef(&local, c.error))
    2049           0 :         return nullptr;
    2050           0 :     return new(c.lifo) AstGetGlobal(local);
    2051             : }
    2052             : 
    2053             : static AstSetGlobal*
    2054           0 : ParseSetGlobal(WasmParseContext& c, bool inParens)
    2055             : {
    2056           0 :     AstRef global;
    2057           0 :     if (!c.ts.matchRef(&global, c.error))
    2058           0 :         return nullptr;
    2059             : 
    2060           0 :     AstExpr* value = ParseExpr(c, inParens);
    2061           0 :     if (!value)
    2062           0 :         return nullptr;
    2063             : 
    2064           0 :     return new(c.lifo) AstSetGlobal(global, *value);
    2065             : }
    2066             : 
    2067             : static AstSetLocal*
    2068           0 : ParseSetLocal(WasmParseContext& c, bool inParens)
    2069             : {
    2070           0 :     AstRef local;
    2071           0 :     if (!c.ts.matchRef(&local, c.error))
    2072           0 :         return nullptr;
    2073             : 
    2074           0 :     AstExpr* value = ParseExpr(c, inParens);
    2075           0 :     if (!value)
    2076           0 :         return nullptr;
    2077             : 
    2078           0 :     return new(c.lifo) AstSetLocal(local, *value);
    2079             : }
    2080             : 
    2081             : static AstTeeLocal*
    2082           0 : ParseTeeLocal(WasmParseContext& c, bool inParens)
    2083             : {
    2084           0 :     AstRef local;
    2085           0 :     if (!c.ts.matchRef(&local, c.error))
    2086           0 :         return nullptr;
    2087             : 
    2088           0 :     AstExpr* value = ParseExpr(c, inParens);
    2089           0 :     if (!value)
    2090           0 :         return nullptr;
    2091             : 
    2092           0 :     return new(c.lifo) AstTeeLocal(local, *value);
    2093             : }
    2094             : 
    2095             : static AstReturn*
    2096           0 : ParseReturn(WasmParseContext& c, bool inParens)
    2097             : {
    2098           0 :     AstExpr* maybeExpr = nullptr;
    2099             : 
    2100           0 :     if (c.ts.peek().kind() != WasmToken::CloseParen) {
    2101           0 :         maybeExpr = ParseExpr(c, inParens);
    2102           0 :         if (!maybeExpr)
    2103           0 :             return nullptr;
    2104             :     }
    2105             : 
    2106           0 :     return new(c.lifo) AstReturn(maybeExpr);
    2107             : }
    2108             : 
    2109             : static AstUnaryOperator*
    2110           0 : ParseUnaryOperator(WasmParseContext& c, Op op, bool inParens)
    2111             : {
    2112           0 :     AstExpr* operand = ParseExpr(c, inParens);
    2113           0 :     if (!operand)
    2114           0 :         return nullptr;
    2115             : 
    2116           0 :     return new(c.lifo) AstUnaryOperator(op, operand);
    2117             : }
    2118             : 
    2119             : static AstBinaryOperator*
    2120           0 : ParseBinaryOperator(WasmParseContext& c, Op op, bool inParens)
    2121             : {
    2122           0 :     AstExpr* lhs = ParseExpr(c, inParens);
    2123           0 :     if (!lhs)
    2124           0 :         return nullptr;
    2125             : 
    2126           0 :     AstExpr* rhs = ParseExpr(c, inParens);
    2127           0 :     if (!rhs)
    2128           0 :         return nullptr;
    2129             : 
    2130           0 :     return new(c.lifo) AstBinaryOperator(op, lhs, rhs);
    2131             : }
    2132             : 
    2133             : static AstComparisonOperator*
    2134           0 : ParseComparisonOperator(WasmParseContext& c, Op op, bool inParens)
    2135             : {
    2136           0 :     AstExpr* lhs = ParseExpr(c, inParens);
    2137           0 :     if (!lhs)
    2138           0 :         return nullptr;
    2139             : 
    2140           0 :     AstExpr* rhs = ParseExpr(c, inParens);
    2141           0 :     if (!rhs)
    2142           0 :         return nullptr;
    2143             : 
    2144           0 :     return new(c.lifo) AstComparisonOperator(op, lhs, rhs);
    2145             : }
    2146             : 
    2147             : static AstTernaryOperator*
    2148           0 : ParseTernaryOperator(WasmParseContext& c, Op op, bool inParens)
    2149             : {
    2150           0 :     AstExpr* op0 = ParseExpr(c, inParens);
    2151           0 :     if (!op0)
    2152           0 :         return nullptr;
    2153             : 
    2154           0 :     AstExpr* op1 = ParseExpr(c, inParens);
    2155           0 :     if (!op1)
    2156           0 :         return nullptr;
    2157             : 
    2158           0 :     AstExpr* op2 = ParseExpr(c, inParens);
    2159           0 :     if (!op2)
    2160           0 :         return nullptr;
    2161             : 
    2162           0 :     return new(c.lifo) AstTernaryOperator(op, op0, op1, op2);
    2163             : }
    2164             : 
    2165             : static AstConversionOperator*
    2166           0 : ParseConversionOperator(WasmParseContext& c, Op op, bool inParens)
    2167             : {
    2168           0 :     AstExpr* operand = ParseExpr(c, inParens);
    2169           0 :     if (!operand)
    2170           0 :         return nullptr;
    2171             : 
    2172           0 :     return new(c.lifo) AstConversionOperator(op, operand);
    2173             : }
    2174             : 
    2175             : static AstDrop*
    2176           0 : ParseDrop(WasmParseContext& c, bool inParens)
    2177             : {
    2178           0 :     AstExpr* value = ParseExpr(c, inParens);
    2179           0 :     if (!value)
    2180           0 :         return nullptr;
    2181             : 
    2182           0 :     return new(c.lifo) AstDrop(*value);
    2183             : }
    2184             : 
    2185             : static AstIf*
    2186           0 : ParseIf(WasmParseContext& c, bool inParens)
    2187             : {
    2188           0 :     AstName name = c.ts.getIfName();
    2189             : 
    2190             :     ExprType type;
    2191           0 :     if (!ParseBlockSignature(c, &type))
    2192           0 :         return nullptr;
    2193             : 
    2194           0 :     AstExpr* cond = ParseExpr(c, inParens);
    2195           0 :     if (!cond)
    2196           0 :         return nullptr;
    2197             : 
    2198           0 :     if (inParens) {
    2199           0 :         if (!c.ts.match(WasmToken::OpenParen, c.error))
    2200           0 :             return nullptr;
    2201             :     }
    2202             : 
    2203           0 :     AstExprVector thenExprs(c.lifo);
    2204           0 :     if (!inParens || c.ts.getIf(WasmToken::Then)) {
    2205           0 :         if (!ParseExprList(c, &thenExprs, inParens))
    2206           0 :             return nullptr;
    2207             :     } else {
    2208           0 :         AstExpr* thenBranch = ParseExprInsideParens(c);
    2209           0 :         if (!thenBranch || !thenExprs.append(thenBranch))
    2210           0 :             return nullptr;
    2211             :     }
    2212           0 :     if (inParens) {
    2213           0 :         if (!c.ts.match(WasmToken::CloseParen, c.error))
    2214           0 :             return nullptr;
    2215             :     }
    2216             : 
    2217           0 :     AstExprVector elseExprs(c.lifo);
    2218           0 :     if (!inParens || c.ts.getIf(WasmToken::OpenParen)) {
    2219           0 :         if (c.ts.getIf(WasmToken::Else)) {
    2220           0 :             if (!MaybeMatchName(c, name))
    2221           0 :                 return nullptr;
    2222           0 :             if (!ParseExprList(c, &elseExprs, inParens))
    2223           0 :                 return nullptr;
    2224           0 :         } else if (inParens) {
    2225           0 :             AstExpr* elseBranch = ParseExprInsideParens(c);
    2226           0 :             if (!elseBranch || !elseExprs.append(elseBranch))
    2227           0 :                 return nullptr;
    2228             :         }
    2229           0 :         if (inParens) {
    2230           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    2231           0 :                 return nullptr;
    2232             :         } else {
    2233           0 :             if (!c.ts.match(WasmToken::End, c.error))
    2234           0 :                 return nullptr;
    2235           0 :             if (!MaybeMatchName(c, name))
    2236           0 :                 return nullptr;
    2237             :         }
    2238             :     }
    2239             : 
    2240           0 :     return new(c.lifo) AstIf(type, cond, name, Move(thenExprs), Move(elseExprs));
    2241             : }
    2242             : 
    2243             : static bool
    2244           0 : ParseLoadStoreAddress(WasmParseContext& c, int32_t* offset, uint32_t* alignLog2, AstExpr** base,
    2245             :                       bool inParens)
    2246             : {
    2247           0 :     *offset = 0;
    2248           0 :     if (c.ts.getIf(WasmToken::Offset)) {
    2249           0 :         if (!c.ts.match(WasmToken::Equal, c.error))
    2250           0 :             return false;
    2251           0 :         WasmToken val = c.ts.get();
    2252           0 :         switch (val.kind()) {
    2253             :           case WasmToken::Index:
    2254           0 :             *offset = val.index();
    2255           0 :             break;
    2256             :           default:
    2257           0 :             c.ts.generateError(val, c.error);
    2258           0 :             return false;
    2259             :         }
    2260             :     }
    2261             : 
    2262           0 :     *alignLog2 = UINT32_MAX;
    2263           0 :     if (c.ts.getIf(WasmToken::Align)) {
    2264           0 :         if (!c.ts.match(WasmToken::Equal, c.error))
    2265           0 :             return false;
    2266           0 :         WasmToken val = c.ts.get();
    2267           0 :         switch (val.kind()) {
    2268             :           case WasmToken::Index:
    2269           0 :             if (!IsPowerOfTwo(val.index())) {
    2270           0 :                 c.ts.generateError(val, "non-power-of-two alignment", c.error);
    2271           0 :                 return false;
    2272             :             }
    2273           0 :             *alignLog2 = CeilingLog2(val.index());
    2274           0 :             break;
    2275             :           default:
    2276           0 :             c.ts.generateError(val, c.error);
    2277           0 :             return false;
    2278             :         }
    2279             :     }
    2280             : 
    2281           0 :     *base = ParseExpr(c, inParens);
    2282           0 :     if (!*base)
    2283           0 :         return false;
    2284             : 
    2285           0 :     return true;
    2286             : }
    2287             : 
    2288             : static AstLoad*
    2289           0 : ParseLoad(WasmParseContext& c, Op op, bool inParens)
    2290             : {
    2291             :     int32_t offset;
    2292             :     uint32_t alignLog2;
    2293             :     AstExpr* base;
    2294           0 :     if (!ParseLoadStoreAddress(c, &offset, &alignLog2, &base, inParens))
    2295           0 :         return nullptr;
    2296             : 
    2297           0 :     if (alignLog2 == UINT32_MAX) {
    2298           0 :         switch (op) {
    2299             :           case Op::I32Load8S:
    2300             :           case Op::I32Load8U:
    2301             :           case Op::I64Load8S:
    2302             :           case Op::I64Load8U:
    2303           0 :             alignLog2 = 0;
    2304           0 :             break;
    2305             :           case Op::I32Load16S:
    2306             :           case Op::I32Load16U:
    2307             :           case Op::I64Load16S:
    2308             :           case Op::I64Load16U:
    2309           0 :             alignLog2 = 1;
    2310           0 :             break;
    2311             :           case Op::I32Load:
    2312             :           case Op::F32Load:
    2313             :           case Op::I64Load32S:
    2314             :           case Op::I64Load32U:
    2315           0 :             alignLog2 = 2;
    2316           0 :             break;
    2317             :           case Op::I64Load:
    2318             :           case Op::F64Load:
    2319           0 :             alignLog2 = 3;
    2320           0 :             break;
    2321             :           default:
    2322           0 :             MOZ_CRASH("Bad load op");
    2323             :         }
    2324             :     }
    2325             : 
    2326           0 :     uint32_t flags = alignLog2;
    2327             : 
    2328           0 :     return new(c.lifo) AstLoad(op, AstLoadStoreAddress(base, flags, offset));
    2329             : }
    2330             : 
    2331             : static AstStore*
    2332           0 : ParseStore(WasmParseContext& c, Op op, bool inParens)
    2333             : {
    2334             :     int32_t offset;
    2335             :     uint32_t alignLog2;
    2336             :     AstExpr* base;
    2337           0 :     if (!ParseLoadStoreAddress(c, &offset, &alignLog2, &base, inParens))
    2338           0 :         return nullptr;
    2339             : 
    2340           0 :     if (alignLog2 == UINT32_MAX) {
    2341           0 :         switch (op) {
    2342             :           case Op::I32Store8:
    2343             :           case Op::I64Store8:
    2344           0 :             alignLog2 = 0;
    2345           0 :             break;
    2346             :           case Op::I32Store16:
    2347             :           case Op::I64Store16:
    2348           0 :             alignLog2 = 1;
    2349           0 :             break;
    2350             :           case Op::I32Store:
    2351             :           case Op::F32Store:
    2352             :           case Op::I64Store32:
    2353           0 :             alignLog2 = 2;
    2354           0 :             break;
    2355             :           case Op::I64Store:
    2356             :           case Op::F64Store:
    2357           0 :             alignLog2 = 3;
    2358           0 :             break;
    2359             :           default:
    2360           0 :             MOZ_CRASH("Bad load op");
    2361             :         }
    2362             :     }
    2363             : 
    2364           0 :     AstExpr* value = ParseExpr(c, inParens);
    2365           0 :     if (!value)
    2366           0 :         return nullptr;
    2367             : 
    2368           0 :     uint32_t flags = alignLog2;
    2369             : 
    2370           0 :     return new(c.lifo) AstStore(op, AstLoadStoreAddress(base, flags, offset), value);
    2371             : }
    2372             : 
    2373             : static AstBranchTable*
    2374           0 : ParseBranchTable(WasmParseContext& c, WasmToken brTable, bool inParens)
    2375             : {
    2376           0 :     AstRefVector table(c.lifo);
    2377             : 
    2378           0 :     AstRef target;
    2379           0 :     while (c.ts.getIfRef(&target)) {
    2380           0 :         if (!table.append(target))
    2381           0 :             return nullptr;
    2382             :     }
    2383             : 
    2384           0 :     if (table.empty()) {
    2385           0 :         c.ts.generateError(c.ts.get(), c.error);
    2386           0 :         return nullptr;
    2387             :     }
    2388             : 
    2389           0 :     AstRef def = table.popCopy();
    2390             : 
    2391           0 :     AstExpr* index = ParseExpr(c, inParens);
    2392           0 :     if (!index)
    2393           0 :         return nullptr;
    2394             : 
    2395           0 :     AstExpr* value = nullptr;
    2396           0 :     if (inParens) {
    2397           0 :         if (c.ts.getIf(WasmToken::OpenParen)) {
    2398           0 :             value = index;
    2399           0 :             index = ParseExprInsideParens(c);
    2400           0 :             if (!index)
    2401           0 :                 return nullptr;
    2402           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    2403           0 :                 return nullptr;
    2404             :         }
    2405             :     }
    2406             : 
    2407           0 :     return new(c.lifo) AstBranchTable(*index, def, Move(table), value);
    2408             : }
    2409             : 
    2410             : static AstGrowMemory*
    2411           0 : ParseGrowMemory(WasmParseContext& c, bool inParens)
    2412             : {
    2413           0 :     AstExpr* operand = ParseExpr(c, inParens);
    2414           0 :     if (!operand)
    2415           0 :         return nullptr;
    2416             : 
    2417           0 :     return new(c.lifo) AstGrowMemory(operand);
    2418             : }
    2419             : 
    2420             : static AstExpr*
    2421           0 : ParseExprBody(WasmParseContext& c, WasmToken token, bool inParens)
    2422             : {
    2423           0 :     switch (token.kind()) {
    2424             :       case WasmToken::Unreachable:
    2425           0 :         return new(c.lifo) AstUnreachable;
    2426             :       case WasmToken::BinaryOpcode:
    2427           0 :         return ParseBinaryOperator(c, token.op(), inParens);
    2428             :       case WasmToken::Block:
    2429           0 :         return ParseBlock(c, Op::Block, inParens);
    2430             :       case WasmToken::Br:
    2431           0 :         return ParseBranch(c, Op::Br, inParens);
    2432             :       case WasmToken::BrIf:
    2433           0 :         return ParseBranch(c, Op::BrIf, inParens);
    2434             :       case WasmToken::BrTable:
    2435           0 :         return ParseBranchTable(c, token, inParens);
    2436             :       case WasmToken::Call:
    2437           0 :         return ParseCall(c, inParens);
    2438             :       case WasmToken::CallIndirect:
    2439           0 :         return ParseCallIndirect(c, inParens);
    2440             :       case WasmToken::ComparisonOpcode:
    2441           0 :         return ParseComparisonOperator(c, token.op(), inParens);
    2442             :       case WasmToken::Const:
    2443           0 :         return ParseConst(c, token);
    2444             :       case WasmToken::ConversionOpcode:
    2445           0 :         return ParseConversionOperator(c, token.op(), inParens);
    2446             :       case WasmToken::Drop:
    2447           0 :         return ParseDrop(c, inParens);
    2448             :       case WasmToken::If:
    2449           0 :         return ParseIf(c, inParens);
    2450             :       case WasmToken::GetGlobal:
    2451           0 :         return ParseGetGlobal(c);
    2452             :       case WasmToken::GetLocal:
    2453           0 :         return ParseGetLocal(c);
    2454             :       case WasmToken::Load:
    2455           0 :         return ParseLoad(c, token.op(), inParens);
    2456             :       case WasmToken::Loop:
    2457           0 :         return ParseBlock(c, Op::Loop, inParens);
    2458             :       case WasmToken::Return:
    2459           0 :         return ParseReturn(c, inParens);
    2460             :       case WasmToken::SetGlobal:
    2461           0 :         return ParseSetGlobal(c, inParens);
    2462             :       case WasmToken::SetLocal:
    2463           0 :         return ParseSetLocal(c, inParens);
    2464             :       case WasmToken::Store:
    2465           0 :         return ParseStore(c, token.op(), inParens);
    2466             :       case WasmToken::TeeLocal:
    2467           0 :         return ParseTeeLocal(c, inParens);
    2468             :       case WasmToken::TernaryOpcode:
    2469           0 :         return ParseTernaryOperator(c, token.op(), inParens);
    2470             :       case WasmToken::UnaryOpcode:
    2471           0 :         return ParseUnaryOperator(c, token.op(), inParens);
    2472             :       case WasmToken::Nop:
    2473           0 :         return new(c.lifo) AstNop();
    2474             :       case WasmToken::CurrentMemory:
    2475           0 :         return new(c.lifo) AstCurrentMemory();
    2476             :       case WasmToken::GrowMemory:
    2477           0 :         return ParseGrowMemory(c, inParens);
    2478             :       default:
    2479           0 :         c.ts.generateError(token, c.error);
    2480           0 :         return nullptr;
    2481             :     }
    2482             : }
    2483             : 
    2484             : static AstExpr*
    2485           0 : ParseExprInsideParens(WasmParseContext& c)
    2486             : {
    2487           0 :     WasmToken token = c.ts.get();
    2488             : 
    2489           0 :     return ParseExprBody(c, token, true);
    2490             : }
    2491             : 
    2492             : static bool
    2493           0 : ParseValueTypeList(WasmParseContext& c, AstValTypeVector* vec)
    2494             : {
    2495           0 :     WasmToken token;
    2496           0 :     while (c.ts.getIf(WasmToken::ValueType, &token)) {
    2497           0 :         if (!vec->append(token.valueType()))
    2498           0 :             return false;
    2499             :     }
    2500             : 
    2501           0 :     return true;
    2502             : }
    2503             : 
    2504             : static bool
    2505           0 : ParseResult(WasmParseContext& c, ExprType* result)
    2506             : {
    2507           0 :     if (*result != ExprType::Void) {
    2508           0 :         c.ts.generateError(c.ts.peek(), c.error);
    2509           0 :         return false;
    2510             :     }
    2511             : 
    2512           0 :     WasmToken token;
    2513           0 :     if (!c.ts.match(WasmToken::ValueType, &token, c.error))
    2514           0 :         return false;
    2515             : 
    2516           0 :     *result = ToExprType(token.valueType());
    2517           0 :     return true;
    2518             : }
    2519             : 
    2520             : static bool
    2521           0 : ParseLocalOrParam(WasmParseContext& c, AstNameVector* locals, AstValTypeVector* localTypes)
    2522             : {
    2523           0 :     if (c.ts.peek().kind() != WasmToken::Name)
    2524           0 :         return locals->append(AstName()) && ParseValueTypeList(c, localTypes);
    2525             : 
    2526           0 :     WasmToken token;
    2527           0 :     return locals->append(c.ts.get().name()) &&
    2528           0 :            c.ts.match(WasmToken::ValueType, &token, c.error) &&
    2529           0 :            localTypes->append(token.valueType());
    2530             : }
    2531             : 
    2532             : static bool
    2533           0 : ParseInlineImport(WasmParseContext& c, InlineImport* import)
    2534             : {
    2535           0 :     return c.ts.match(WasmToken::Text, &import->module, c.error) &&
    2536           0 :            c.ts.match(WasmToken::Text, &import->field, c.error);
    2537             : }
    2538             : 
    2539             : static bool
    2540           0 : ParseInlineExport(WasmParseContext& c, DefinitionKind kind, AstModule* module, AstRef ref)
    2541             : {
    2542           0 :     WasmToken name;
    2543           0 :     if (!c.ts.match(WasmToken::Text, &name, c.error))
    2544           0 :         return false;
    2545             : 
    2546           0 :     AstExport* exp = new(c.lifo) AstExport(name.text(), kind, ref);
    2547           0 :     return exp && module->append(exp);
    2548             : }
    2549             : 
    2550             : static bool
    2551           0 : MaybeParseTypeUse(WasmParseContext& c, AstRef* sig)
    2552             : {
    2553           0 :     WasmToken openParen;
    2554           0 :     if (c.ts.getIf(WasmToken::OpenParen, &openParen)) {
    2555           0 :         if (c.ts.getIf(WasmToken::Type)) {
    2556           0 :             if (!c.ts.matchRef(sig, c.error))
    2557           0 :                 return false;
    2558           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    2559           0 :                 return false;
    2560             :         } else {
    2561           0 :             c.ts.unget(openParen);
    2562             :         }
    2563             :     }
    2564           0 :     return true;
    2565             : }
    2566             : 
    2567             : static bool
    2568           0 : ParseFuncSig(WasmParseContext& c, AstSig* sig)
    2569             : {
    2570           0 :     AstValTypeVector args(c.lifo);
    2571           0 :     ExprType result = ExprType::Void;
    2572             : 
    2573           0 :     while (c.ts.getIf(WasmToken::OpenParen)) {
    2574           0 :         WasmToken token = c.ts.get();
    2575           0 :         switch (token.kind()) {
    2576             :           case WasmToken::Param:
    2577           0 :             if (!ParseValueTypeList(c, &args))
    2578           0 :                 return false;
    2579           0 :             break;
    2580             :           case WasmToken::Result:
    2581           0 :             if (!ParseResult(c, &result))
    2582           0 :                 return false;
    2583           0 :             break;
    2584             :           default:
    2585           0 :             c.ts.generateError(token, c.error);
    2586           0 :             return false;
    2587             :         }
    2588           0 :         if (!c.ts.match(WasmToken::CloseParen, c.error))
    2589           0 :             return false;
    2590             :     }
    2591             : 
    2592           0 :     *sig = AstSig(Move(args), result);
    2593           0 :     return true;
    2594             : }
    2595             : 
    2596             : static bool
    2597           0 : ParseFuncType(WasmParseContext& c, AstRef* ref, AstModule* module)
    2598             : {
    2599           0 :     if (!MaybeParseTypeUse(c, ref))
    2600           0 :         return false;
    2601             : 
    2602           0 :     if (ref->isInvalid()) {
    2603           0 :         AstSig sig(c.lifo);
    2604           0 :         if (!ParseFuncSig(c, &sig))
    2605           0 :             return false;
    2606             :         uint32_t sigIndex;
    2607           0 :         if (!module->declare(Move(sig), &sigIndex))
    2608           0 :             return false;
    2609           0 :         ref->setIndex(sigIndex);
    2610             :     }
    2611             : 
    2612           0 :     return true;
    2613             : }
    2614             : 
    2615             : static bool
    2616           0 : ParseFunc(WasmParseContext& c, AstModule* module)
    2617             : {
    2618           0 :     AstValTypeVector vars(c.lifo);
    2619           0 :     AstValTypeVector args(c.lifo);
    2620           0 :     AstNameVector locals(c.lifo);
    2621             : 
    2622           0 :     AstName funcName = c.ts.getIfName();
    2623             : 
    2624             :     // Inline imports and exports.
    2625           0 :     WasmToken openParen;
    2626           0 :     if (c.ts.getIf(WasmToken::OpenParen, &openParen)) {
    2627           0 :         if (c.ts.getIf(WasmToken::Import)) {
    2628           0 :             if (module->funcs().length()) {
    2629           0 :                 c.ts.generateError(openParen, "import after function definition", c.error);
    2630           0 :                 return false;
    2631             :             }
    2632             : 
    2633           0 :             InlineImport names;
    2634           0 :             if (!ParseInlineImport(c, &names))
    2635           0 :                 return false;
    2636           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    2637           0 :                 return false;
    2638             : 
    2639           0 :             AstRef sig;
    2640           0 :             if (!ParseFuncType(c, &sig, module))
    2641           0 :                 return false;
    2642             : 
    2643           0 :             auto* imp = new(c.lifo) AstImport(funcName, names.module.text(), names.field.text(), sig);
    2644           0 :             return imp && module->append(imp);
    2645             :         }
    2646             : 
    2647           0 :         if (c.ts.getIf(WasmToken::Export)) {
    2648           0 :             AstRef ref = funcName.empty()
    2649           0 :                          ? AstRef(module->funcImportNames().length() + module->funcs().length())
    2650           0 :                          : AstRef(funcName);
    2651           0 :             if (!ParseInlineExport(c, DefinitionKind::Function, module, ref))
    2652           0 :                 return false;
    2653           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    2654           0 :                 return false;
    2655             :         } else {
    2656           0 :             c.ts.unget(openParen);
    2657             :         }
    2658             :     }
    2659             : 
    2660           0 :     AstRef sigRef;
    2661           0 :     if (!MaybeParseTypeUse(c, &sigRef))
    2662           0 :         return false;
    2663             : 
    2664           0 :     AstExprVector body(c.lifo);
    2665             : 
    2666           0 :     ExprType result = ExprType::Void;
    2667           0 :     while (c.ts.getIf(WasmToken::OpenParen)) {
    2668           0 :         WasmToken token = c.ts.get();
    2669           0 :         switch (token.kind()) {
    2670             :           case WasmToken::Local:
    2671           0 :             if (!ParseLocalOrParam(c, &locals, &vars))
    2672           0 :                 return false;
    2673           0 :             break;
    2674             :           case WasmToken::Param:
    2675           0 :             if (!vars.empty()) {
    2676           0 :                 c.ts.generateError(token, c.error);
    2677           0 :                 return false;
    2678             :             }
    2679           0 :             if (!ParseLocalOrParam(c, &locals, &args))
    2680           0 :                 return false;
    2681           0 :             break;
    2682             :           case WasmToken::Result:
    2683           0 :             if (!ParseResult(c, &result))
    2684           0 :                 return false;
    2685           0 :             break;
    2686             :           default:
    2687           0 :             c.ts.unget(token);
    2688           0 :             AstExpr* expr = ParseExprInsideParens(c);
    2689           0 :             if (!expr || !body.append(expr))
    2690           0 :                 return false;
    2691           0 :             break;
    2692             :         }
    2693           0 :         if (!c.ts.match(WasmToken::CloseParen, c.error))
    2694           0 :             return false;
    2695             :     }
    2696             : 
    2697           0 :     if (!ParseExprList(c, &body, true))
    2698           0 :         return false;
    2699             : 
    2700           0 :     if (sigRef.isInvalid()) {
    2701             :         uint32_t sigIndex;
    2702           0 :         if (!module->declare(AstSig(Move(args), result), &sigIndex))
    2703           0 :             return false;
    2704           0 :         sigRef.setIndex(sigIndex);
    2705             :     }
    2706             : 
    2707           0 :     auto* func = new(c.lifo) AstFunc(funcName, sigRef, Move(vars), Move(locals), Move(body));
    2708           0 :     return func && module->append(func);
    2709             : }
    2710             : 
    2711             : static AstSig*
    2712           0 : ParseTypeDef(WasmParseContext& c)
    2713             : {
    2714           0 :     AstName name = c.ts.getIfName();
    2715             : 
    2716           0 :     if (!c.ts.match(WasmToken::OpenParen, c.error))
    2717           0 :         return nullptr;
    2718           0 :     if (!c.ts.match(WasmToken::Func, c.error))
    2719           0 :         return nullptr;
    2720             : 
    2721           0 :     AstSig sig(c.lifo);
    2722           0 :     if (!ParseFuncSig(c, &sig))
    2723           0 :         return nullptr;
    2724             : 
    2725           0 :     if (!c.ts.match(WasmToken::CloseParen, c.error))
    2726           0 :         return nullptr;
    2727             : 
    2728           0 :     return new(c.lifo) AstSig(name, Move(sig));
    2729             : }
    2730             : 
    2731             : static bool
    2732           0 : MaybeParseOwnerIndex(WasmParseContext& c)
    2733             : {
    2734           0 :     if (c.ts.peek().kind() == WasmToken::Index) {
    2735           0 :         WasmToken elemIndex = c.ts.get();
    2736           0 :         if (elemIndex.index()) {
    2737           0 :             c.ts.generateError(elemIndex, "can't handle non-default memory/table yet", c.error);
    2738           0 :             return false;
    2739             :         }
    2740             :     }
    2741           0 :     return true;
    2742             : }
    2743             : 
    2744             : static AstExpr*
    2745           0 : ParseInitializerExpression(WasmParseContext& c)
    2746             : {
    2747           0 :     if (!c.ts.match(WasmToken::OpenParen, c.error))
    2748           0 :         return nullptr;
    2749             : 
    2750           0 :     AstExpr* initExpr = ParseExprInsideParens(c);
    2751           0 :     if (!initExpr)
    2752           0 :         return nullptr;
    2753             : 
    2754           0 :     if (!c.ts.match(WasmToken::CloseParen, c.error))
    2755           0 :         return nullptr;
    2756             : 
    2757           0 :     return initExpr;
    2758             : }
    2759             : 
    2760             : static AstDataSegment*
    2761           0 : ParseDataSegment(WasmParseContext& c)
    2762             : {
    2763           0 :     if (!MaybeParseOwnerIndex(c))
    2764           0 :         return nullptr;
    2765             : 
    2766           0 :     AstExpr* offset = ParseInitializerExpression(c);
    2767           0 :     if (!offset)
    2768           0 :         return nullptr;
    2769             : 
    2770           0 :     AstNameVector fragments(c.lifo);
    2771             : 
    2772           0 :     WasmToken text;
    2773           0 :     while (c.ts.getIf(WasmToken::Text, &text)) {
    2774           0 :         if (!fragments.append(text.text()))
    2775           0 :             return nullptr;
    2776             :     }
    2777             : 
    2778           0 :     return new(c.lifo) AstDataSegment(offset, Move(fragments));
    2779             : }
    2780             : 
    2781             : static bool
    2782           0 : ParseLimits(WasmParseContext& c, Limits* limits)
    2783             : {
    2784           0 :     WasmToken initial;
    2785           0 :     if (!c.ts.match(WasmToken::Index, &initial, c.error))
    2786           0 :         return false;
    2787             : 
    2788           0 :     Maybe<uint32_t> maximum;
    2789           0 :     WasmToken token;
    2790           0 :     if (c.ts.getIf(WasmToken::Index, &token))
    2791           0 :         maximum.emplace(token.index());
    2792             : 
    2793           0 :     Limits r = { initial.index(), maximum };
    2794           0 :     *limits = r;
    2795           0 :     return true;
    2796             : }
    2797             : 
    2798             : static bool
    2799           0 : ParseMemory(WasmParseContext& c, WasmToken token, AstModule* module)
    2800             : {
    2801           0 :     AstName name = c.ts.getIfName();
    2802             : 
    2803           0 :     WasmToken openParen;
    2804           0 :     if (c.ts.getIf(WasmToken::OpenParen, &openParen)) {
    2805           0 :         if (c.ts.getIf(WasmToken::Import)) {
    2806           0 :             InlineImport names;
    2807           0 :             if (!ParseInlineImport(c, &names))
    2808           0 :                 return false;
    2809           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    2810           0 :                 return false;
    2811             : 
    2812           0 :             Limits memory;
    2813           0 :             if (!ParseLimits(c, &memory))
    2814           0 :                 return false;
    2815             : 
    2816           0 :             auto* imp = new(c.lifo) AstImport(name, names.module.text(), names.field.text(),
    2817           0 :                                               DefinitionKind::Memory, memory);
    2818           0 :             return imp && module->append(imp);
    2819             :         }
    2820             : 
    2821           0 :         if (c.ts.getIf(WasmToken::Export)) {
    2822           0 :             AstRef ref = name.empty() ? AstRef(module->memories().length()) : AstRef(name);
    2823           0 :             if (!ParseInlineExport(c, DefinitionKind::Memory, module, ref))
    2824           0 :                 return false;
    2825           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    2826           0 :                 return false;
    2827             :         } else {
    2828           0 :             c.ts.unget(openParen);
    2829             :         }
    2830             :     }
    2831             : 
    2832           0 :     if (c.ts.getIf(WasmToken::OpenParen)) {
    2833           0 :         if (!c.ts.match(WasmToken::Data, c.error))
    2834           0 :             return false;
    2835             : 
    2836           0 :         AstNameVector fragments(c.lifo);
    2837             : 
    2838           0 :         WasmToken data;
    2839           0 :         size_t pages = 0;
    2840           0 :         size_t totalLength = 0;
    2841           0 :         while (c.ts.getIf(WasmToken::Text, &data)) {
    2842           0 :             if (!fragments.append(data.text()))
    2843           0 :                 return false;
    2844           0 :             totalLength += data.text().length();
    2845             :         }
    2846             : 
    2847           0 :         if (fragments.length()) {
    2848           0 :             AstExpr* offset = new(c.lifo) AstConst(Val(uint32_t(0)));
    2849           0 :             if (!offset)
    2850           0 :                 return false;
    2851             : 
    2852           0 :             AstDataSegment* segment = new(c.lifo) AstDataSegment(offset, Move(fragments));
    2853           0 :             if (!segment || !module->append(segment))
    2854           0 :                 return false;
    2855             : 
    2856           0 :             pages = AlignBytes<size_t>(totalLength, PageSize) / PageSize;
    2857           0 :             if (pages != uint32_t(pages))
    2858           0 :                 return false;
    2859             :         }
    2860             : 
    2861           0 :         Limits memory = { uint32_t(pages), Some(uint32_t(pages)) };
    2862           0 :         if (!module->addMemory(name, memory))
    2863           0 :             return false;
    2864             : 
    2865           0 :         if (!c.ts.match(WasmToken::CloseParen, c.error))
    2866           0 :             return false;
    2867             : 
    2868           0 :         return true;
    2869             :     }
    2870             : 
    2871           0 :     Limits memory;
    2872           0 :     if (!ParseLimits(c, &memory))
    2873           0 :         return false;
    2874             : 
    2875           0 :     return module->addMemory(name, memory);
    2876             : }
    2877             : 
    2878             : static bool
    2879           0 : ParseStartFunc(WasmParseContext& c, WasmToken token, AstModule* module)
    2880             : {
    2881           0 :     AstRef func;
    2882           0 :     if (!c.ts.matchRef(&func, c.error))
    2883           0 :         return false;
    2884             : 
    2885           0 :     if (!module->setStartFunc(AstStartFunc(func))) {
    2886           0 :         c.ts.generateError(token, c.error);
    2887           0 :         return false;
    2888             :     }
    2889             : 
    2890           0 :     return true;
    2891             : }
    2892             : 
    2893             : static bool
    2894           0 : ParseGlobalType(WasmParseContext& c, WasmToken* typeToken, bool* isMutable)
    2895             : {
    2896           0 :     *isMutable = false;
    2897             : 
    2898             :     // Either (mut i32) or i32.
    2899           0 :     if (c.ts.getIf(WasmToken::OpenParen)) {
    2900             :         // Immutable by default.
    2901           0 :         *isMutable = c.ts.getIf(WasmToken::Mutable);
    2902           0 :         if (!c.ts.match(WasmToken::ValueType, typeToken, c.error))
    2903           0 :             return false;
    2904           0 :         if (!c.ts.match(WasmToken::CloseParen, c.error))
    2905           0 :             return false;
    2906           0 :         return true;
    2907             :     }
    2908             : 
    2909           0 :     return c.ts.match(WasmToken::ValueType, typeToken, c.error);
    2910             : }
    2911             : 
    2912             : static bool
    2913           0 : ParseElemType(WasmParseContext& c)
    2914             : {
    2915             :     // Only AnyFunc is allowed at the moment.
    2916           0 :     return c.ts.match(WasmToken::AnyFunc, c.error);
    2917             : }
    2918             : 
    2919             : static bool
    2920           0 : ParseTableSig(WasmParseContext& c, Limits* table)
    2921             : {
    2922           0 :     return ParseLimits(c, table) &&
    2923           0 :            ParseElemType(c);
    2924             : }
    2925             : 
    2926             : static AstImport*
    2927           0 : ParseImport(WasmParseContext& c, AstModule* module)
    2928             : {
    2929           0 :     AstName name = c.ts.getIfName();
    2930             : 
    2931           0 :     WasmToken moduleName;
    2932           0 :     if (!c.ts.match(WasmToken::Text, &moduleName, c.error))
    2933           0 :         return nullptr;
    2934             : 
    2935           0 :     WasmToken fieldName;
    2936           0 :     if (!c.ts.match(WasmToken::Text, &fieldName, c.error))
    2937           0 :         return nullptr;
    2938             : 
    2939           0 :     AstRef sigRef;
    2940           0 :     WasmToken openParen;
    2941           0 :     if (c.ts.getIf(WasmToken::OpenParen, &openParen)) {
    2942           0 :         if (c.ts.getIf(WasmToken::Memory)) {
    2943           0 :             if (name.empty())
    2944           0 :                 name = c.ts.getIfName();
    2945             : 
    2946           0 :             Limits memory;
    2947           0 :             if (!ParseLimits(c, &memory))
    2948           0 :                 return nullptr;
    2949           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    2950           0 :                 return nullptr;
    2951           0 :             return new(c.lifo) AstImport(name, moduleName.text(), fieldName.text(),
    2952           0 :                                          DefinitionKind::Memory, memory);
    2953             :         }
    2954           0 :         if (c.ts.getIf(WasmToken::Table)) {
    2955           0 :             if (name.empty())
    2956           0 :                 name = c.ts.getIfName();
    2957             : 
    2958           0 :             Limits table;
    2959           0 :             if (!ParseTableSig(c, &table))
    2960           0 :                 return nullptr;
    2961           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    2962           0 :                 return nullptr;
    2963           0 :             return new(c.lifo) AstImport(name, moduleName.text(), fieldName.text(),
    2964           0 :                                          DefinitionKind::Table, table);
    2965             :         }
    2966           0 :         if (c.ts.getIf(WasmToken::Global)) {
    2967           0 :             if (name.empty())
    2968           0 :                 name = c.ts.getIfName();
    2969             : 
    2970           0 :             WasmToken typeToken;
    2971             :             bool isMutable;
    2972           0 :             if (!ParseGlobalType(c, &typeToken, &isMutable))
    2973           0 :                 return nullptr;
    2974           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    2975           0 :                 return nullptr;
    2976             : 
    2977           0 :             return new(c.lifo) AstImport(name, moduleName.text(), fieldName.text(),
    2978           0 :                                          AstGlobal(AstName(), typeToken.valueType(), isMutable));
    2979             :         }
    2980           0 :         if (c.ts.getIf(WasmToken::Func)) {
    2981           0 :             if (name.empty())
    2982           0 :                 name = c.ts.getIfName();
    2983             : 
    2984           0 :             AstRef sigRef;
    2985           0 :             if (!ParseFuncType(c, &sigRef, module))
    2986           0 :                 return nullptr;
    2987           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    2988           0 :                 return nullptr;
    2989             : 
    2990           0 :             return new(c.lifo) AstImport(name, moduleName.text(), fieldName.text(), sigRef);
    2991             :         }
    2992             : 
    2993           0 :         if (c.ts.getIf(WasmToken::Type)) {
    2994           0 :             if (!c.ts.matchRef(&sigRef, c.error))
    2995           0 :                 return nullptr;
    2996           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    2997           0 :                 return nullptr;
    2998             :         } else {
    2999           0 :             c.ts.unget(openParen);
    3000             :         }
    3001             :     }
    3002             : 
    3003           0 :     if (sigRef.isInvalid()) {
    3004           0 :         AstSig sig(c.lifo);
    3005           0 :         if (!ParseFuncSig(c, &sig))
    3006           0 :             return nullptr;
    3007             : 
    3008             :         uint32_t sigIndex;
    3009           0 :         if (!module->declare(Move(sig), &sigIndex))
    3010           0 :             return nullptr;
    3011           0 :         sigRef.setIndex(sigIndex);
    3012             :     }
    3013             : 
    3014           0 :     return new(c.lifo) AstImport(name, moduleName.text(), fieldName.text(), sigRef);
    3015             : }
    3016             : 
    3017             : static AstExport*
    3018           0 : ParseExport(WasmParseContext& c)
    3019             : {
    3020           0 :     WasmToken name;
    3021           0 :     if (!c.ts.match(WasmToken::Text, &name, c.error))
    3022           0 :         return nullptr;
    3023             : 
    3024           0 :     WasmToken exportee = c.ts.get();
    3025           0 :     switch (exportee.kind()) {
    3026             :       case WasmToken::Index:
    3027           0 :         return new(c.lifo) AstExport(name.text(), DefinitionKind::Function, AstRef(exportee.index()));
    3028             :       case WasmToken::Name:
    3029           0 :         return new(c.lifo) AstExport(name.text(), DefinitionKind::Function, AstRef(exportee.name()));
    3030             :       case WasmToken::Table: {
    3031           0 :         AstRef ref;
    3032           0 :         if (!c.ts.getIfRef(&ref))
    3033           0 :             ref = AstRef(0);
    3034           0 :         return new(c.lifo) AstExport(name.text(), DefinitionKind::Table, ref);
    3035             :       }
    3036             :       case WasmToken::Memory: {
    3037           0 :         AstRef ref;
    3038           0 :         if (!c.ts.getIfRef(&ref))
    3039           0 :             ref = AstRef(0);
    3040           0 :         return new(c.lifo) AstExport(name.text(), DefinitionKind::Memory, ref);
    3041             :       }
    3042             :       case WasmToken::Global: {
    3043           0 :         AstRef ref;
    3044           0 :         if (!c.ts.matchRef(&ref, c.error))
    3045           0 :             return nullptr;
    3046           0 :         return new(c.lifo) AstExport(name.text(), DefinitionKind::Global, ref);
    3047             :       }
    3048             :       case WasmToken::OpenParen: {
    3049           0 :         exportee = c.ts.get();
    3050             : 
    3051             :         DefinitionKind kind;
    3052           0 :         switch (exportee.kind()) {
    3053             :           case WasmToken::Func:
    3054           0 :             kind = DefinitionKind::Function;
    3055           0 :             break;
    3056             :           case WasmToken::Table:
    3057           0 :             kind = DefinitionKind::Table;
    3058           0 :             break;
    3059             :           case WasmToken::Memory:
    3060           0 :             kind = DefinitionKind::Memory;
    3061           0 :             break;
    3062             :           case WasmToken::Global:
    3063           0 :             kind = DefinitionKind::Global;
    3064           0 :             break;
    3065             :           default:
    3066           0 :             c.ts.generateError(exportee, c.error);
    3067           0 :             return nullptr;
    3068             :         }
    3069             : 
    3070           0 :         AstRef ref;
    3071           0 :         if (!c.ts.matchRef(&ref, c.error))
    3072           0 :             return nullptr;
    3073           0 :         if (!c.ts.match(WasmToken::CloseParen, c.error))
    3074           0 :             return nullptr;
    3075             : 
    3076           0 :         return new(c.lifo) AstExport(name.text(), kind, ref);
    3077             :       }
    3078             :       default:
    3079           0 :         break;
    3080             :     }
    3081             : 
    3082           0 :     c.ts.generateError(exportee, c.error);
    3083           0 :     return nullptr;
    3084             : }
    3085             : 
    3086             : static bool
    3087           0 : ParseTable(WasmParseContext& c, WasmToken token, AstModule* module)
    3088             : {
    3089           0 :     AstName name = c.ts.getIfName();
    3090             : 
    3091           0 :     if (c.ts.getIf(WasmToken::OpenParen)) {
    3092             :         // Either an import and we're done, or an export and continue.
    3093           0 :         if (c.ts.getIf(WasmToken::Import)) {
    3094           0 :             InlineImport names;
    3095           0 :             if (!ParseInlineImport(c, &names))
    3096           0 :                 return false;
    3097           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    3098           0 :                 return false;
    3099             : 
    3100           0 :             Limits table;
    3101           0 :             if (!ParseTableSig(c, &table))
    3102           0 :                 return false;
    3103             : 
    3104           0 :             auto* import = new(c.lifo) AstImport(name, names.module.text(), names.field.text(),
    3105           0 :                                                  DefinitionKind::Table, table);
    3106             : 
    3107           0 :             return import && module->append(import);
    3108             :         }
    3109             : 
    3110           0 :         if (!c.ts.match(WasmToken::Export, c.error)) {
    3111           0 :             c.ts.generateError(token, c.error);
    3112           0 :             return false;
    3113             :         }
    3114             : 
    3115           0 :         AstRef ref = name.empty() ? AstRef(module->tables().length()) : AstRef(name);
    3116           0 :         if (!ParseInlineExport(c, DefinitionKind::Table, module, ref))
    3117           0 :             return false;
    3118           0 :         if (!c.ts.match(WasmToken::CloseParen, c.error))
    3119           0 :             return false;
    3120             :     }
    3121             : 
    3122             :     // Either: min max? anyfunc
    3123           0 :     if (c.ts.peek().kind() == WasmToken::Index) {
    3124           0 :         Limits table;
    3125           0 :         if (!ParseTableSig(c, &table))
    3126           0 :             return false;
    3127           0 :         return module->addTable(name, table);
    3128             :     }
    3129             : 
    3130             :     // Or: anyfunc (elem 1 2 ...)
    3131           0 :     if (!ParseElemType(c))
    3132           0 :         return false;
    3133             : 
    3134           0 :     if (!c.ts.match(WasmToken::OpenParen, c.error))
    3135           0 :         return false;
    3136           0 :     if (!c.ts.match(WasmToken::Elem, c.error))
    3137           0 :         return false;
    3138             : 
    3139           0 :     AstRefVector elems(c.lifo);
    3140             : 
    3141           0 :     AstRef elem;
    3142           0 :     while (c.ts.getIfRef(&elem)) {
    3143           0 :         if (!elems.append(elem))
    3144           0 :             return false;
    3145             :     }
    3146             : 
    3147           0 :     if (!c.ts.match(WasmToken::CloseParen, c.error))
    3148           0 :         return false;
    3149             : 
    3150           0 :     uint32_t numElements = uint32_t(elems.length());
    3151           0 :     if (numElements != elems.length())
    3152           0 :         return false;
    3153             : 
    3154           0 :     Limits r = { numElements, Some(numElements) };
    3155           0 :     if (!module->addTable(name, r))
    3156           0 :         return false;
    3157             : 
    3158           0 :     auto* zero = new(c.lifo) AstConst(Val(uint32_t(0)));
    3159           0 :     if (!zero)
    3160           0 :         return false;
    3161             : 
    3162           0 :     AstElemSegment* segment = new(c.lifo) AstElemSegment(zero, Move(elems));
    3163           0 :     return segment && module->append(segment);
    3164             : }
    3165             : 
    3166             : static AstElemSegment*
    3167           0 : ParseElemSegment(WasmParseContext& c)
    3168             : {
    3169           0 :     if (!MaybeParseOwnerIndex(c))
    3170           0 :         return nullptr;
    3171             : 
    3172           0 :     AstExpr* offset = ParseInitializerExpression(c);
    3173           0 :     if (!offset)
    3174           0 :         return nullptr;
    3175             : 
    3176           0 :     AstRefVector elems(c.lifo);
    3177             : 
    3178           0 :     AstRef elem;
    3179           0 :     while (c.ts.getIfRef(&elem)) {
    3180           0 :         if (!elems.append(elem))
    3181           0 :             return nullptr;
    3182             :     }
    3183             : 
    3184           0 :     return new(c.lifo) AstElemSegment(offset, Move(elems));
    3185             : }
    3186             : 
    3187             : static bool
    3188           0 : ParseGlobal(WasmParseContext& c, AstModule* module)
    3189             : {
    3190           0 :     AstName name = c.ts.getIfName();
    3191             : 
    3192           0 :     WasmToken typeToken;
    3193             :     bool isMutable;
    3194             : 
    3195           0 :     WasmToken openParen;
    3196           0 :     if (c.ts.getIf(WasmToken::OpenParen, &openParen)) {
    3197           0 :         if (c.ts.getIf(WasmToken::Import)) {
    3198           0 :             if (module->globals().length()) {
    3199           0 :                 c.ts.generateError(openParen, "import after global definition", c.error);
    3200           0 :                 return false;
    3201             :             }
    3202             : 
    3203           0 :             InlineImport names;
    3204           0 :             if (!ParseInlineImport(c, &names))
    3205           0 :                 return false;
    3206           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    3207           0 :                 return false;
    3208             : 
    3209           0 :             if (!ParseGlobalType(c, &typeToken, &isMutable))
    3210           0 :                 return false;
    3211             : 
    3212           0 :             auto* imp = new(c.lifo) AstImport(name, names.module.text(), names.field.text(),
    3213           0 :                                               AstGlobal(AstName(), typeToken.valueType(),
    3214           0 :                                                         isMutable));
    3215           0 :             return imp && module->append(imp);
    3216             :         }
    3217             : 
    3218           0 :         if (c.ts.getIf(WasmToken::Export)) {
    3219           0 :             AstRef ref = name.empty() ? AstRef(module->globals().length()) : AstRef(name);
    3220           0 :             if (!ParseInlineExport(c, DefinitionKind::Global, module, ref))
    3221           0 :                 return false;
    3222           0 :             if (!c.ts.match(WasmToken::CloseParen, c.error))
    3223           0 :                 return false;
    3224             :         } else {
    3225           0 :             c.ts.unget(openParen);
    3226             :         }
    3227             :     }
    3228             : 
    3229           0 :     if (!ParseGlobalType(c, &typeToken, &isMutable))
    3230           0 :         return false;
    3231             : 
    3232           0 :     AstExpr* init = ParseInitializerExpression(c);
    3233           0 :     if (!init)
    3234           0 :         return false;
    3235             : 
    3236           0 :     auto* glob = new(c.lifo) AstGlobal(name, typeToken.valueType(), isMutable, Some(init));
    3237           0 :     return glob && module->append(glob);
    3238             : }
    3239             : 
    3240             : static AstModule*
    3241           0 : ParseBinaryModule(WasmParseContext& c, AstModule* module)
    3242             : {
    3243             :     // By convention with EncodeBinaryModule, a binary module only contains a
    3244             :     // data section containing the raw bytes contained in the module.
    3245           0 :     AstNameVector fragments(c.lifo);
    3246             : 
    3247           0 :     WasmToken text;
    3248           0 :     while (c.ts.getIf(WasmToken::Text, &text)) {
    3249           0 :         if (!fragments.append(text.text()))
    3250           0 :             return nullptr;
    3251             :     }
    3252             : 
    3253           0 :     auto* data = new(c.lifo) AstDataSegment(nullptr, Move(fragments));
    3254           0 :     if (!data || !module->append(data))
    3255           0 :         return nullptr;
    3256             : 
    3257           0 :     return module;
    3258             : }
    3259             : 
    3260             : static AstModule*
    3261           0 : ParseModule(const char16_t* text, LifoAlloc& lifo, UniqueChars* error, bool* binary)
    3262             : {
    3263           0 :     WasmParseContext c(text, lifo, error);
    3264             : 
    3265           0 :     *binary = false;
    3266             : 
    3267           0 :     if (!c.ts.match(WasmToken::OpenParen, c.error))
    3268           0 :         return nullptr;
    3269           0 :     if (!c.ts.match(WasmToken::Module, c.error))
    3270           0 :         return nullptr;
    3271             : 
    3272           0 :     auto* module = new(c.lifo) AstModule(c.lifo);
    3273           0 :     if (!module || !module->init())
    3274           0 :         return nullptr;
    3275             : 
    3276           0 :     if (c.ts.peek().kind() == WasmToken::Text) {
    3277           0 :         *binary = true;
    3278           0 :         return ParseBinaryModule(c, module);
    3279             :     }
    3280             : 
    3281           0 :     while (c.ts.getIf(WasmToken::OpenParen)) {
    3282           0 :         WasmToken section = c.ts.get();
    3283             : 
    3284           0 :         switch (section.kind()) {
    3285             :           case WasmToken::Type: {
    3286           0 :             AstSig* sig = ParseTypeDef(c);
    3287           0 :             if (!sig || !module->append(sig))
    3288           0 :                 return nullptr;
    3289           0 :             break;
    3290             :           }
    3291             :           case WasmToken::Start: {
    3292           0 :             if (!ParseStartFunc(c, section, module))
    3293           0 :                 return nullptr;
    3294           0 :             break;
    3295             :           }
    3296             :           case WasmToken::Memory: {
    3297           0 :             if (!ParseMemory(c, section, module))
    3298           0 :                 return nullptr;
    3299           0 :             break;
    3300             :           }
    3301             :           case WasmToken::Global: {
    3302           0 :             if (!ParseGlobal(c, module))
    3303           0 :                 return nullptr;
    3304           0 :             break;
    3305             :           }
    3306             :           case WasmToken::Data: {
    3307           0 :             AstDataSegment* segment = ParseDataSegment(c);
    3308           0 :             if (!segment || !module->append(segment))
    3309           0 :                 return nullptr;
    3310           0 :             break;
    3311             :           }
    3312             :           case WasmToken::Import: {
    3313           0 :             AstImport* imp = ParseImport(c, module);
    3314           0 :             if (!imp || !module->append(imp))
    3315           0 :                 return nullptr;
    3316           0 :             break;
    3317             :           }
    3318             :           case WasmToken::Export: {
    3319           0 :             AstExport* exp = ParseExport(c);
    3320           0 :             if (!exp || !module->append(exp))
    3321           0 :                 return nullptr;
    3322           0 :             break;
    3323             :           }
    3324             :           case WasmToken::Table: {
    3325           0 :             if (!ParseTable(c, section, module))
    3326           0 :                 return nullptr;
    3327           0 :             break;
    3328             :           }
    3329             :           case WasmToken::Elem: {
    3330           0 :             AstElemSegment* segment = ParseElemSegment(c);
    3331           0 :             if (!segment || !module->append(segment))
    3332           0 :                 return nullptr;
    3333           0 :             break;
    3334             :           }
    3335             :           case WasmToken::Func: {
    3336           0 :             if (!ParseFunc(c, module))
    3337           0 :                 return nullptr;
    3338           0 :             break;
    3339             :           }
    3340             :           default:
    3341           0 :             c.ts.generateError(section, c.error);
    3342           0 :             return nullptr;
    3343             :         }
    3344             : 
    3345           0 :         if (!c.ts.match(WasmToken::CloseParen, c.error))
    3346           0 :             return nullptr;
    3347             :     }
    3348             : 
    3349           0 :     if (!c.ts.match(WasmToken::CloseParen, c.error))
    3350           0 :         return nullptr;
    3351           0 :     if (!c.ts.match(WasmToken::EndOfFile, c.error))
    3352           0 :         return nullptr;
    3353             : 
    3354           0 :     return module;
    3355             : }
    3356             : 
    3357             : /*****************************************************************************/
    3358             : // wasm name resolution
    3359             : 
    3360             : namespace {
    3361             : 
    3362           0 : class Resolver
    3363             : {
    3364             :     UniqueChars* error_;
    3365             :     AstNameMap varMap_;
    3366             :     AstNameMap globalMap_;
    3367             :     AstNameMap sigMap_;
    3368             :     AstNameMap funcMap_;
    3369             :     AstNameMap importMap_;
    3370             :     AstNameMap tableMap_;
    3371             :     AstNameMap memoryMap_;
    3372             :     AstNameVector targetStack_;
    3373             : 
    3374           0 :     bool registerName(AstNameMap& map, AstName name, size_t index) {
    3375           0 :         AstNameMap::AddPtr p = map.lookupForAdd(name);
    3376           0 :         if (!p) {
    3377           0 :             if (!map.add(p, name, index))
    3378           0 :                 return false;
    3379             :         } else {
    3380           0 :             return false;
    3381             :         }
    3382           0 :         return true;
    3383             :     }
    3384           0 :     bool resolveRef(AstNameMap& map, AstRef& ref) {
    3385           0 :         AstNameMap::Ptr p = map.lookup(ref.name());
    3386           0 :         if (p) {
    3387           0 :             ref.setIndex(p->value());
    3388           0 :             return true;
    3389             :         }
    3390           0 :         return false;
    3391             :     }
    3392           0 :     bool failResolveLabel(const char* kind, AstName name) {
    3393           0 :         TwoByteChars chars(name.begin(), name.length());
    3394           0 :         UniqueChars utf8Chars(CharsToNewUTF8CharsZ(nullptr, chars).c_str());
    3395           0 :         *error_ = JS_smprintf("%s label '%s' not found", kind, utf8Chars.get());
    3396           0 :         return false;
    3397             :     }
    3398             : 
    3399             :   public:
    3400           0 :     explicit Resolver(LifoAlloc& lifo, UniqueChars* error)
    3401           0 :       : error_(error),
    3402             :         varMap_(lifo),
    3403             :         globalMap_(lifo),
    3404             :         sigMap_(lifo),
    3405             :         funcMap_(lifo),
    3406             :         importMap_(lifo),
    3407             :         tableMap_(lifo),
    3408             :         memoryMap_(lifo),
    3409           0 :         targetStack_(lifo)
    3410           0 :     {}
    3411           0 :     bool init() {
    3412           0 :         return sigMap_.init() &&
    3413           0 :                funcMap_.init() &&
    3414           0 :                importMap_.init() &&
    3415           0 :                tableMap_.init() &&
    3416           0 :                memoryMap_.init() &&
    3417           0 :                varMap_.init() &&
    3418           0 :                globalMap_.init();
    3419             :     }
    3420           0 :     void beginFunc() {
    3421           0 :         varMap_.clear();
    3422           0 :         MOZ_ASSERT(targetStack_.empty());
    3423           0 :     }
    3424             : 
    3425             : #define REGISTER(what, map)                                    \
    3426             :     bool register##what##Name(AstName name, size_t index) {    \
    3427             :         return name.empty() || registerName(map, name, index); \
    3428             :     }
    3429             : 
    3430           0 :     REGISTER(Sig, sigMap_)
    3431           0 :     REGISTER(Func, funcMap_)
    3432           0 :     REGISTER(Var, varMap_)
    3433           0 :     REGISTER(Global, globalMap_)
    3434           0 :     REGISTER(Table, tableMap_)
    3435           0 :     REGISTER(Memory, memoryMap_)
    3436             : 
    3437             : #undef REGISTER
    3438             : 
    3439           0 :     bool pushTarget(AstName name) {
    3440           0 :         return targetStack_.append(name);
    3441             :     }
    3442           0 :     void popTarget(AstName name) {
    3443           0 :         MOZ_ASSERT(targetStack_.back() == name);
    3444           0 :         targetStack_.popBack();
    3445           0 :     }
    3446             : 
    3447             : #define RESOLVE(map, label)                               \
    3448             :     bool resolve##label(AstRef& ref) {                    \
    3449             :         MOZ_ASSERT(!ref.isInvalid());                     \
    3450             :         if (!ref.name().empty() && !resolveRef(map, ref)) \
    3451             :             return failResolveLabel(#label, ref.name());  \
    3452             :         return true;                                      \
    3453             :     }
    3454             : 
    3455           0 :     RESOLVE(sigMap_, Signature)
    3456           0 :     RESOLVE(funcMap_, Function)
    3457           0 :     RESOLVE(varMap_, Local)
    3458           0 :     RESOLVE(globalMap_, Global)
    3459           0 :     RESOLVE(tableMap_, Table)
    3460           0 :     RESOLVE(memoryMap_, Memory)
    3461             : 
    3462             : #undef RESOLVE
    3463             : 
    3464           0 :     bool resolveBranchTarget(AstRef& ref) {
    3465           0 :         if (ref.name().empty())
    3466           0 :             return true;
    3467           0 :         for (size_t i = 0, e = targetStack_.length(); i < e; i++) {
    3468           0 :             if (targetStack_[e - i - 1] == ref.name()) {
    3469           0 :                 ref.setIndex(i);
    3470           0 :                 return true;
    3471             :             }
    3472             :         }
    3473           0 :         return failResolveLabel("branch target", ref.name());
    3474             :     }
    3475             : 
    3476           0 :     bool fail(const char* message) {
    3477           0 :         *error_ = JS_smprintf("%s", message);
    3478           0 :         return false;
    3479             :     }
    3480             : };
    3481             : 
    3482             : } // end anonymous namespace
    3483             : 
    3484             : static bool
    3485             : ResolveExpr(Resolver& r, AstExpr& expr);
    3486             : 
    3487             : static bool
    3488           0 : ResolveExprList(Resolver& r, const AstExprVector& v)
    3489             : {
    3490           0 :     for (size_t i = 0; i < v.length(); i++) {
    3491           0 :         if (!ResolveExpr(r, *v[i]))
    3492           0 :             return false;
    3493             :     }
    3494           0 :     return true;
    3495             : }
    3496             : 
    3497             : static bool
    3498           0 : ResolveBlock(Resolver& r, AstBlock& b)
    3499             : {
    3500           0 :     if (!r.pushTarget(b.name()))
    3501           0 :         return false;
    3502             : 
    3503           0 :     if (!ResolveExprList(r, b.exprs()))
    3504           0 :         return false;
    3505             : 
    3506           0 :     r.popTarget(b.name());
    3507           0 :     return true;
    3508             : }
    3509             : 
    3510             : static bool
    3511           0 : ResolveDropOperator(Resolver& r, AstDrop& drop)
    3512             : {
    3513           0 :     return ResolveExpr(r, drop.value());
    3514             : }
    3515             : 
    3516             : static bool
    3517           0 : ResolveBranch(Resolver& r, AstBranch& br)
    3518             : {
    3519           0 :     if (!r.resolveBranchTarget(br.target()))
    3520           0 :         return false;
    3521             : 
    3522           0 :     if (br.maybeValue() && !ResolveExpr(r, *br.maybeValue()))
    3523           0 :         return false;
    3524             : 
    3525           0 :     if (br.op() == Op::BrIf) {
    3526           0 :         if (!ResolveExpr(r, br.cond()))
    3527           0 :             return false;
    3528             :     }
    3529             : 
    3530           0 :     return true;
    3531             : }
    3532             : 
    3533             : static bool
    3534           0 : ResolveArgs(Resolver& r, const AstExprVector& args)
    3535             : {
    3536           0 :     for (AstExpr* arg : args) {
    3537           0 :         if (!ResolveExpr(r, *arg))
    3538           0 :             return false;
    3539             :     }
    3540             : 
    3541           0 :     return true;
    3542             : }
    3543             : 
    3544             : static bool
    3545           0 : ResolveCall(Resolver& r, AstCall& c)
    3546             : {
    3547           0 :     MOZ_ASSERT(c.op() == Op::Call);
    3548             : 
    3549           0 :     if (!ResolveArgs(r, c.args()))
    3550           0 :         return false;
    3551             : 
    3552           0 :     if (!r.resolveFunction(c.func()))
    3553           0 :         return false;
    3554             : 
    3555           0 :     return true;
    3556             : }
    3557             : 
    3558             : static bool
    3559           0 : ResolveCallIndirect(Resolver& r, AstCallIndirect& c)
    3560             : {
    3561           0 :     if (!ResolveArgs(r, c.args()))
    3562           0 :         return false;
    3563             : 
    3564           0 :     if (!ResolveExpr(r, *c.index()))
    3565           0 :         return false;
    3566             : 
    3567           0 :     if (!r.resolveSignature(c.sig()))
    3568           0 :         return false;
    3569             : 
    3570           0 :     return true;
    3571             : }
    3572             : 
    3573             : static bool
    3574           0 : ResolveFirst(Resolver& r, AstFirst& f)
    3575             : {
    3576           0 :     return ResolveExprList(r, f.exprs());
    3577             : }
    3578             : 
    3579             : static bool
    3580           0 : ResolveGetLocal(Resolver& r, AstGetLocal& gl)
    3581             : {
    3582           0 :     return r.resolveLocal(gl.local());
    3583             : }
    3584             : 
    3585             : static bool
    3586           0 : ResolveSetLocal(Resolver& r, AstSetLocal& sl)
    3587             : {
    3588           0 :     if (!ResolveExpr(r, sl.value()))
    3589           0 :         return false;
    3590             : 
    3591           0 :     if (!r.resolveLocal(sl.local()))
    3592           0 :         return false;
    3593             : 
    3594           0 :     return true;
    3595             : }
    3596             : 
    3597             : static bool
    3598           0 : ResolveGetGlobal(Resolver& r, AstGetGlobal& gl)
    3599             : {
    3600           0 :     return r.resolveGlobal(gl.global());
    3601             : }
    3602             : 
    3603             : static bool
    3604           0 : ResolveSetGlobal(Resolver& r, AstSetGlobal& sl)
    3605             : {
    3606           0 :     if (!ResolveExpr(r, sl.value()))
    3607           0 :         return false;
    3608             : 
    3609           0 :     if (!r.resolveGlobal(sl.global()))
    3610           0 :         return false;
    3611             : 
    3612           0 :     return true;
    3613             : }
    3614             : 
    3615             : static bool
    3616           0 : ResolveTeeLocal(Resolver& r, AstTeeLocal& sl)
    3617             : {
    3618           0 :     if (!ResolveExpr(r, sl.value()))
    3619           0 :         return false;
    3620             : 
    3621           0 :     if (!r.resolveLocal(sl.local()))
    3622           0 :         return false;
    3623             : 
    3624           0 :     return true;
    3625             : }
    3626             : 
    3627             : static bool
    3628           0 : ResolveUnaryOperator(Resolver& r, AstUnaryOperator& b)
    3629             : {
    3630           0 :     return ResolveExpr(r, *b.operand());
    3631             : }
    3632             : 
    3633             : static bool
    3634           0 : ResolveGrowMemory(Resolver& r, AstGrowMemory& gm)
    3635             : {
    3636           0 :     return ResolveExpr(r, *gm.operand());
    3637             : }
    3638             : 
    3639             : static bool
    3640           0 : ResolveBinaryOperator(Resolver& r, AstBinaryOperator& b)
    3641             : {
    3642           0 :     return ResolveExpr(r, *b.lhs()) &&
    3643           0 :            ResolveExpr(r, *b.rhs());
    3644             : }
    3645             : 
    3646             : static bool
    3647           0 : ResolveTernaryOperator(Resolver& r, AstTernaryOperator& b)
    3648             : {
    3649           0 :     return ResolveExpr(r, *b.op0()) &&
    3650           0 :            ResolveExpr(r, *b.op1()) &&
    3651           0 :            ResolveExpr(r, *b.op2());
    3652             : }
    3653             : 
    3654             : static bool
    3655           0 : ResolveComparisonOperator(Resolver& r, AstComparisonOperator& b)
    3656             : {
    3657           0 :     return ResolveExpr(r, *b.lhs()) &&
    3658           0 :            ResolveExpr(r, *b.rhs());
    3659             : }
    3660             : 
    3661             : static bool
    3662           0 : ResolveConversionOperator(Resolver& r, AstConversionOperator& b)
    3663             : {
    3664           0 :     return ResolveExpr(r, *b.operand());
    3665             : }
    3666             : 
    3667             : static bool
    3668           0 : ResolveIfElse(Resolver& r, AstIf& i)
    3669             : {
    3670           0 :     if (!ResolveExpr(r, i.cond()))
    3671           0 :         return false;
    3672           0 :     if (!r.pushTarget(i.name()))
    3673           0 :         return false;
    3674           0 :     if (!ResolveExprList(r, i.thenExprs()))
    3675           0 :         return false;
    3676           0 :     if (i.hasElse()) {
    3677           0 :         if (!ResolveExprList(r, i.elseExprs()))
    3678           0 :             return false;
    3679             :     }
    3680           0 :     r.popTarget(i.name());
    3681           0 :     return true;
    3682             : }
    3683             : 
    3684             : static bool
    3685           0 : ResolveLoadStoreAddress(Resolver& r, const AstLoadStoreAddress &address)
    3686             : {
    3687           0 :     return ResolveExpr(r, address.base());
    3688             : }
    3689             : 
    3690             : static bool
    3691           0 : ResolveLoad(Resolver& r, AstLoad& l)
    3692             : {
    3693           0 :     return ResolveLoadStoreAddress(r, l.address());
    3694             : }
    3695             : 
    3696             : static bool
    3697           0 : ResolveStore(Resolver& r, AstStore& s)
    3698             : {
    3699           0 :     return ResolveLoadStoreAddress(r, s.address()) &&
    3700           0 :            ResolveExpr(r, s.value());
    3701             : }
    3702             : 
    3703             : static bool
    3704           0 : ResolveReturn(Resolver& r, AstReturn& ret)
    3705             : {
    3706           0 :     return !ret.maybeExpr() || ResolveExpr(r, *ret.maybeExpr());
    3707             : }
    3708             : 
    3709             : static bool
    3710           0 : ResolveBranchTable(Resolver& r, AstBranchTable& bt)
    3711             : {
    3712           0 :     if (!r.resolveBranchTarget(bt.def()))
    3713           0 :         return false;
    3714             : 
    3715           0 :     for (AstRef& elem : bt.table()) {
    3716           0 :         if (!r.resolveBranchTarget(elem))
    3717           0 :             return false;
    3718             :     }
    3719             : 
    3720           0 :     if (bt.maybeValue() && !ResolveExpr(r, *bt.maybeValue()))
    3721           0 :         return false;
    3722             : 
    3723           0 :     return ResolveExpr(r, bt.index());
    3724             : }
    3725             : 
    3726             : static bool
    3727           0 : ResolveExpr(Resolver& r, AstExpr& expr)
    3728             : {
    3729           0 :     switch (expr.kind()) {
    3730             :       case AstExprKind::Nop:
    3731             :       case AstExprKind::Pop:
    3732             :       case AstExprKind::Unreachable:
    3733             :       case AstExprKind::CurrentMemory:
    3734           0 :         return true;
    3735             :       case AstExprKind::Drop:
    3736           0 :         return ResolveDropOperator(r, expr.as<AstDrop>());
    3737             :       case AstExprKind::BinaryOperator:
    3738           0 :         return ResolveBinaryOperator(r, expr.as<AstBinaryOperator>());
    3739             :       case AstExprKind::Block:
    3740           0 :         return ResolveBlock(r, expr.as<AstBlock>());
    3741             :       case AstExprKind::Branch:
    3742           0 :         return ResolveBranch(r, expr.as<AstBranch>());
    3743             :       case AstExprKind::Call:
    3744           0 :         return ResolveCall(r, expr.as<AstCall>());
    3745             :       case AstExprKind::CallIndirect:
    3746           0 :         return ResolveCallIndirect(r, expr.as<AstCallIndirect>());
    3747             :       case AstExprKind::ComparisonOperator:
    3748           0 :         return ResolveComparisonOperator(r, expr.as<AstComparisonOperator>());
    3749             :       case AstExprKind::Const:
    3750           0 :         return true;
    3751             :       case AstExprKind::ConversionOperator:
    3752           0 :         return ResolveConversionOperator(r, expr.as<AstConversionOperator>());
    3753             :       case AstExprKind::First:
    3754           0 :         return ResolveFirst(r, expr.as<AstFirst>());
    3755             :       case AstExprKind::GetGlobal:
    3756           0 :         return ResolveGetGlobal(r, expr.as<AstGetGlobal>());
    3757             :       case AstExprKind::GetLocal:
    3758           0 :         return ResolveGetLocal(r, expr.as<AstGetLocal>());
    3759             :       case AstExprKind::If:
    3760           0 :         return ResolveIfElse(r, expr.as<AstIf>());
    3761             :       case AstExprKind::Load:
    3762           0 :         return ResolveLoad(r, expr.as<AstLoad>());
    3763             :       case AstExprKind::Return:
    3764           0 :         return ResolveReturn(r, expr.as<AstReturn>());
    3765             :       case AstExprKind::SetGlobal:
    3766           0 :         return ResolveSetGlobal(r, expr.as<AstSetGlobal>());
    3767             :       case AstExprKind::SetLocal:
    3768           0 :         return ResolveSetLocal(r, expr.as<AstSetLocal>());
    3769             :       case AstExprKind::Store:
    3770           0 :         return ResolveStore(r, expr.as<AstStore>());
    3771             :       case AstExprKind::BranchTable:
    3772           0 :         return ResolveBranchTable(r, expr.as<AstBranchTable>());
    3773             :       case AstExprKind::TeeLocal:
    3774           0 :         return ResolveTeeLocal(r, expr.as<AstTeeLocal>());
    3775             :       case AstExprKind::TernaryOperator:
    3776           0 :         return ResolveTernaryOperator(r, expr.as<AstTernaryOperator>());
    3777             :       case AstExprKind::UnaryOperator:
    3778           0 :         return ResolveUnaryOperator(r, expr.as<AstUnaryOperator>());
    3779             :       case AstExprKind::GrowMemory:
    3780           0 :         return ResolveGrowMemory(r, expr.as<AstGrowMemory>());
    3781             :     }
    3782           0 :     MOZ_CRASH("Bad expr kind");
    3783             : }
    3784             : 
    3785             : static bool
    3786           0 : ResolveFunc(Resolver& r, AstFunc& func)
    3787             : {
    3788           0 :     r.beginFunc();
    3789             : 
    3790           0 :     for (size_t i = 0; i < func.locals().length(); i++) {
    3791           0 :         if (!r.registerVarName(func.locals()[i], i))
    3792           0 :             return r.fail("duplicate var");
    3793             :     }
    3794             : 
    3795           0 :     for (AstExpr* expr : func.body()) {
    3796           0 :         if (!ResolveExpr(r, *expr))
    3797           0 :             return false;
    3798             :     }
    3799           0 :     return true;
    3800             : }
    3801             : 
    3802             : static bool
    3803           0 : ResolveModule(LifoAlloc& lifo, AstModule* module, UniqueChars* error)
    3804             : {
    3805           0 :     Resolver r(lifo, error);
    3806             : 
    3807           0 :     if (!r.init())
    3808           0 :         return false;
    3809             : 
    3810           0 :     size_t numSigs = module->sigs().length();
    3811           0 :     for (size_t i = 0; i < numSigs; i++) {
    3812           0 :         AstSig* sig = module->sigs()[i];
    3813           0 :         if (!r.registerSigName(sig->name(), i))
    3814           0 :             return r.fail("duplicate signature");
    3815             :     }
    3816             : 
    3817           0 :     size_t lastFuncIndex = 0;
    3818           0 :     size_t lastGlobalIndex = 0;
    3819           0 :     size_t lastMemoryIndex = 0;
    3820           0 :     size_t lastTableIndex = 0;
    3821           0 :     for (AstImport* imp : module->imports()) {
    3822           0 :         switch (imp->kind()) {
    3823             :           case DefinitionKind::Function:
    3824           0 :             if (!r.registerFuncName(imp->name(), lastFuncIndex++))
    3825           0 :                 return r.fail("duplicate import");
    3826           0 :             if (!r.resolveSignature(imp->funcSig()))
    3827           0 :                 return false;
    3828           0 :             break;
    3829             :           case DefinitionKind::Global:
    3830           0 :             if (!r.registerGlobalName(imp->name(), lastGlobalIndex++))
    3831           0 :                 return r.fail("duplicate import");
    3832           0 :             break;
    3833             :           case DefinitionKind::Memory:
    3834           0 :             if (!r.registerMemoryName(imp->name(), lastMemoryIndex++))
    3835           0 :                 return r.fail("duplicate import");
    3836           0 :             break;
    3837             :           case DefinitionKind::Table:
    3838           0 :             if (!r.registerTableName(imp->name(), lastTableIndex++))
    3839           0 :                 return r.fail("duplicate import");
    3840           0 :             break;
    3841             :         }
    3842             :     }
    3843             : 
    3844           0 :     for (AstFunc* func : module->funcs()) {
    3845           0 :         if (!r.resolveSignature(func->sig()))
    3846           0 :             return false;
    3847           0 :         if (!r.registerFuncName(func->name(), lastFuncIndex++))
    3848           0 :             return r.fail("duplicate function");
    3849             :     }
    3850             : 
    3851           0 :     for (const AstGlobal* global : module->globals()) {
    3852           0 :         if (!r.registerGlobalName(global->name(), lastGlobalIndex++))
    3853           0 :             return r.fail("duplicate import");
    3854           0 :         if (global->hasInit() && !ResolveExpr(r, global->init()))
    3855           0 :             return false;
    3856             :     }
    3857             : 
    3858           0 :     for (const AstResizable& table : module->tables()) {
    3859           0 :         if (table.imported)
    3860           0 :             continue;
    3861           0 :         if (!r.registerTableName(table.name, lastTableIndex++))
    3862           0 :             return r.fail("duplicate import");
    3863             :     }
    3864             : 
    3865           0 :     for (const AstResizable& memory : module->memories()) {
    3866           0 :         if (memory.imported)
    3867           0 :             continue;
    3868           0 :         if (!r.registerMemoryName(memory.name, lastMemoryIndex++))
    3869           0 :             return r.fail("duplicate import");
    3870             :     }
    3871             : 
    3872           0 :     for (AstExport* export_ : module->exports()) {
    3873           0 :         switch (export_->kind()) {
    3874             :           case DefinitionKind::Function:
    3875           0 :             if (!r.resolveFunction(export_->ref()))
    3876           0 :                 return false;
    3877           0 :             break;
    3878             :           case DefinitionKind::Global:
    3879           0 :             if (!r.resolveGlobal(export_->ref()))
    3880           0 :                 return false;
    3881           0 :             break;
    3882             :           case DefinitionKind::Table:
    3883           0 :             if (!r.resolveTable(export_->ref()))
    3884           0 :                 return false;
    3885           0 :             break;
    3886             :           case DefinitionKind::Memory:
    3887           0 :             if (!r.resolveMemory(export_->ref()))
    3888           0 :                 return false;
    3889           0 :             break;
    3890             :         }
    3891             :     }
    3892             : 
    3893           0 :     for (AstFunc* func : module->funcs()) {
    3894           0 :         if (!ResolveFunc(r, *func))
    3895           0 :             return false;
    3896             :     }
    3897             : 
    3898           0 :     if (module->hasStartFunc()) {
    3899           0 :         if (!r.resolveFunction(module->startFunc().func()))
    3900           0 :             return false;
    3901             :     }
    3902             : 
    3903           0 :     for (AstDataSegment* segment : module->dataSegments()) {
    3904           0 :         if (!ResolveExpr(r, *segment->offset()))
    3905           0 :             return false;
    3906             :     }
    3907             : 
    3908           0 :     for (AstElemSegment* segment : module->elemSegments()) {
    3909           0 :         if (!ResolveExpr(r, *segment->offset()))
    3910           0 :             return false;
    3911           0 :         for (AstRef& ref : segment->elems()) {
    3912           0 :             if (!r.resolveFunction(ref))
    3913           0 :                 return false;
    3914             :         }
    3915             :     }
    3916             : 
    3917           0 :     return true;
    3918             : }
    3919             : 
    3920             : /*****************************************************************************/
    3921             : // wasm function body serialization
    3922             : 
    3923             : static bool
    3924             : EncodeExpr(Encoder& e, AstExpr& expr);
    3925             : 
    3926             : static bool
    3927           0 : EncodeExprList(Encoder& e, const AstExprVector& v)
    3928             : {
    3929           0 :     for (size_t i = 0; i < v.length(); i++) {
    3930           0 :         if (!EncodeExpr(e, *v[i]))
    3931           0 :             return false;
    3932             :     }
    3933           0 :     return true;
    3934             : }
    3935             : 
    3936             : static bool
    3937           0 : EncodeBlock(Encoder& e, AstBlock& b)
    3938             : {
    3939           0 :     if (!e.writeOp(b.op()))
    3940           0 :         return false;
    3941             : 
    3942           0 :     if (!e.writeBlockType(b.type()))
    3943           0 :         return false;
    3944             : 
    3945           0 :     if (!EncodeExprList(e, b.exprs()))
    3946           0 :         return false;
    3947             : 
    3948           0 :     if (!e.writeOp(Op::End))
    3949           0 :         return false;
    3950             : 
    3951           0 :     return true;
    3952             : }
    3953             : 
    3954             : static bool
    3955           0 : EncodeBranch(Encoder& e, AstBranch& br)
    3956             : {
    3957           0 :     MOZ_ASSERT(br.op() == Op::Br || br.op() == Op::BrIf);
    3958             : 
    3959           0 :     if (br.maybeValue()) {
    3960           0 :         if (!EncodeExpr(e, *br.maybeValue()))
    3961           0 :             return false;
    3962             :     }
    3963             : 
    3964           0 :     if (br.op() == Op::BrIf) {
    3965           0 :         if (!EncodeExpr(e, br.cond()))
    3966           0 :             return false;
    3967             :     }
    3968             : 
    3969           0 :     if (!e.writeOp(br.op()))
    3970           0 :         return false;
    3971             : 
    3972           0 :     if (!e.writeVarU32(br.target().index()))
    3973           0 :         return false;
    3974             : 
    3975           0 :     return true;
    3976             : }
    3977             : 
    3978             : static bool
    3979           0 : EncodeFirst(Encoder& e, AstFirst& f)
    3980             : {
    3981           0 :     return EncodeExprList(e, f.exprs());
    3982             : }
    3983             : 
    3984             : static bool
    3985           0 : EncodeArgs(Encoder& e, const AstExprVector& args)
    3986             : {
    3987           0 :     for (AstExpr* arg : args) {
    3988           0 :         if (!EncodeExpr(e, *arg))
    3989           0 :             return false;
    3990             :     }
    3991             : 
    3992           0 :     return true;
    3993             : }
    3994             : 
    3995             : static bool
    3996           0 : EncodeCall(Encoder& e, AstCall& c)
    3997             : {
    3998           0 :     if (!EncodeArgs(e, c.args()))
    3999           0 :         return false;
    4000             : 
    4001           0 :     if (!e.writeOp(c.op()))
    4002           0 :         return false;
    4003             : 
    4004           0 :     if (!e.writeVarU32(c.func().index()))
    4005           0 :         return false;
    4006             : 
    4007           0 :     return true;
    4008             : }
    4009             : 
    4010             : static bool
    4011           0 : EncodeCallIndirect(Encoder& e, AstCallIndirect& c)
    4012             : {
    4013           0 :     if (!EncodeArgs(e, c.args()))
    4014           0 :         return false;
    4015             : 
    4016           0 :     if (!EncodeExpr(e, *c.index()))
    4017           0 :         return false;
    4018             : 
    4019           0 :     if (!e.writeOp(Op::CallIndirect))
    4020           0 :         return false;
    4021             : 
    4022           0 :     if (!e.writeVarU32(c.sig().index()))
    4023           0 :         return false;
    4024             : 
    4025           0 :     if (!e.writeVarU32(uint32_t(MemoryTableFlags::Default)))
    4026           0 :         return false;
    4027             : 
    4028           0 :     return true;
    4029             : }
    4030             : 
    4031             : static bool
    4032           0 : EncodeConst(Encoder& e, AstConst& c)
    4033             : {
    4034           0 :     switch (c.val().type()) {
    4035             :       case ValType::I32:
    4036           0 :         return e.writeOp(Op::I32Const) &&
    4037           0 :                e.writeVarS32(c.val().i32());
    4038             :       case ValType::I64:
    4039           0 :         return e.writeOp(Op::I64Const) &&
    4040           0 :                e.writeVarS64(c.val().i64());
    4041             :       case ValType::F32:
    4042           0 :         return e.writeOp(Op::F32Const) &&
    4043           0 :                e.writeFixedF32(c.val().f32());
    4044             :       case ValType::F64:
    4045           0 :         return e.writeOp(Op::F64Const) &&
    4046           0 :                e.writeFixedF64(c.val().f64());
    4047             :       default:
    4048           0 :         break;
    4049             :     }
    4050           0 :     MOZ_CRASH("Bad value type");
    4051             : }
    4052             : 
    4053             : static bool
    4054           0 : EncodeDrop(Encoder& e, AstDrop &drop)
    4055             : {
    4056           0 :     return EncodeExpr(e, drop.value()) &&
    4057           0 :            e.writeOp(Op::Drop);
    4058             : }
    4059             : 
    4060             : static bool
    4061           0 : EncodeGetLocal(Encoder& e, AstGetLocal& gl)
    4062             : {
    4063           0 :     return e.writeOp(Op::GetLocal) &&
    4064           0 :            e.writeVarU32(gl.local().index());
    4065             : }
    4066             : 
    4067             : static bool
    4068           0 : EncodeSetLocal(Encoder& e, AstSetLocal& sl)
    4069             : {
    4070           0 :     return EncodeExpr(e, sl.value()) &&
    4071           0 :            e.writeOp(Op::SetLocal) &&
    4072           0 :            e.writeVarU32(sl.local().index());
    4073             : }
    4074             : 
    4075             : static bool
    4076           0 : EncodeTeeLocal(Encoder& e, AstTeeLocal& sl)
    4077             : {
    4078           0 :     return EncodeExpr(e, sl.value()) &&
    4079           0 :            e.writeOp(Op::TeeLocal) &&
    4080           0 :            e.writeVarU32(sl.local().index());
    4081             : }
    4082             : 
    4083             : static bool
    4084           0 : EncodeGetGlobal(Encoder& e, AstGetGlobal& gg)
    4085             : {
    4086           0 :     return e.writeOp(Op::GetGlobal) &&
    4087           0 :            e.writeVarU32(gg.global().index());
    4088             : }
    4089             : 
    4090             : static bool
    4091           0 : EncodeSetGlobal(Encoder& e, AstSetGlobal& sg)
    4092             : {
    4093           0 :     return EncodeExpr(e, sg.value()) &&
    4094           0 :            e.writeOp(Op::SetGlobal) &&
    4095           0 :            e.writeVarU32(sg.global().index());
    4096             : }
    4097             : 
    4098             : static bool
    4099           0 : EncodeUnaryOperator(Encoder& e, AstUnaryOperator& b)
    4100             : {
    4101           0 :     return EncodeExpr(e, *b.operand()) &&
    4102           0 :            e.writeOp(b.op());
    4103             : }
    4104             : 
    4105             : static bool
    4106           0 : EncodeBinaryOperator(Encoder& e, AstBinaryOperator& b)
    4107             : {
    4108           0 :     return EncodeExpr(e, *b.lhs()) &&
    4109           0 :            EncodeExpr(e, *b.rhs()) &&
    4110           0 :            e.writeOp(b.op());
    4111             : }
    4112             : 
    4113             : static bool
    4114           0 : EncodeTernaryOperator(Encoder& e, AstTernaryOperator& b)
    4115             : {
    4116           0 :     return EncodeExpr(e, *b.op0()) &&
    4117           0 :            EncodeExpr(e, *b.op1()) &&
    4118           0 :            EncodeExpr(e, *b.op2()) &&
    4119           0 :            e.writeOp(b.op());
    4120             : }
    4121             : 
    4122             : static bool
    4123           0 : EncodeComparisonOperator(Encoder& e, AstComparisonOperator& b)
    4124             : {
    4125           0 :     return EncodeExpr(e, *b.lhs()) &&
    4126           0 :            EncodeExpr(e, *b.rhs()) &&
    4127           0 :            e.writeOp(b.op());
    4128             : }
    4129             : 
    4130             : static bool
    4131           0 : EncodeConversionOperator(Encoder& e, AstConversionOperator& b)
    4132             : {
    4133           0 :     return EncodeExpr(e, *b.operand()) &&
    4134           0 :            e.writeOp(b.op());
    4135             : }
    4136             : 
    4137             : static bool
    4138           0 : EncodeIf(Encoder& e, AstIf& i)
    4139             : {
    4140           0 :     if (!EncodeExpr(e, i.cond()) || !e.writeOp(Op::If))
    4141           0 :         return false;
    4142             : 
    4143           0 :     if (!e.writeBlockType(i.type()))
    4144           0 :         return false;
    4145             : 
    4146           0 :     if (!EncodeExprList(e, i.thenExprs()))
    4147           0 :         return false;
    4148             : 
    4149           0 :     if (i.hasElse()) {
    4150           0 :         if (!e.writeOp(Op::Else))
    4151           0 :             return false;
    4152           0 :         if (!EncodeExprList(e, i.elseExprs()))
    4153           0 :             return false;
    4154             :     }
    4155             : 
    4156           0 :     return e.writeOp(Op::End);
    4157             : }
    4158             : 
    4159             : static bool
    4160           0 : EncodeLoadStoreAddress(Encoder &e, const AstLoadStoreAddress &address)
    4161             : {
    4162           0 :     return EncodeExpr(e, address.base());
    4163             : }
    4164             : 
    4165             : static bool
    4166           0 : EncodeLoadStoreFlags(Encoder &e, const AstLoadStoreAddress &address)
    4167             : {
    4168           0 :     return e.writeVarU32(address.flags()) &&
    4169           0 :            e.writeVarU32(address.offset());
    4170             : }
    4171             : 
    4172             : static bool
    4173           0 : EncodeLoad(Encoder& e, AstLoad& l)
    4174             : {
    4175           0 :     return EncodeLoadStoreAddress(e, l.address()) &&
    4176           0 :            e.writeOp(l.op()) &&
    4177           0 :            EncodeLoadStoreFlags(e, l.address());
    4178             : }
    4179             : 
    4180             : static bool
    4181           0 : EncodeStore(Encoder& e, AstStore& s)
    4182             : {
    4183           0 :     return EncodeLoadStoreAddress(e, s.address()) &&
    4184           0 :            EncodeExpr(e, s.value()) &&
    4185           0 :            e.writeOp(s.op()) &&
    4186           0 :            EncodeLoadStoreFlags(e, s.address());
    4187             : }
    4188             : 
    4189             : static bool
    4190           0 : EncodeReturn(Encoder& e, AstReturn& r)
    4191             : {
    4192           0 :     if (r.maybeExpr()) {
    4193           0 :         if (!EncodeExpr(e, *r.maybeExpr()))
    4194           0 :            return false;
    4195             :     }
    4196             : 
    4197           0 :     if (!e.writeOp(Op::Return))
    4198           0 :         return false;
    4199             : 
    4200           0 :     return true;
    4201             : }
    4202             : 
    4203             : static bool
    4204           0 : EncodeBranchTable(Encoder& e, AstBranchTable& bt)
    4205             : {
    4206           0 :     if (bt.maybeValue()) {
    4207           0 :         if (!EncodeExpr(e, *bt.maybeValue()))
    4208           0 :             return false;
    4209             :     }
    4210             : 
    4211           0 :     if (!EncodeExpr(e, bt.index()))
    4212           0 :         return false;
    4213             : 
    4214           0 :     if (!e.writeOp(Op::BrTable))
    4215           0 :         return false;
    4216             : 
    4217           0 :     if (!e.writeVarU32(bt.table().length()))
    4218           0 :         return false;
    4219             : 
    4220           0 :     for (const AstRef& elem : bt.table()) {
    4221           0 :         if (!e.writeVarU32(elem.index()))
    4222           0 :             return false;
    4223             :     }
    4224             : 
    4225           0 :     if (!e.writeVarU32(bt.def().index()))
    4226           0 :         return false;
    4227             : 
    4228           0 :     return true;
    4229             : }
    4230             : 
    4231             : static bool
    4232           0 : EncodeCurrentMemory(Encoder& e, AstCurrentMemory& cm)
    4233             : {
    4234           0 :     if (!e.writeOp(Op::CurrentMemory))
    4235           0 :         return false;
    4236             : 
    4237           0 :     if (!e.writeVarU32(uint32_t(MemoryTableFlags::Default)))
    4238           0 :         return false;
    4239             : 
    4240           0 :     return true;
    4241             : }
    4242             : 
    4243             : static bool
    4244           0 : EncodeGrowMemory(Encoder& e, AstGrowMemory& gm)
    4245             : {
    4246           0 :     if (!EncodeExpr(e, *gm.operand()))
    4247           0 :         return false;
    4248             : 
    4249           0 :     if (!e.writeOp(Op::GrowMemory))
    4250           0 :         return false;
    4251             : 
    4252           0 :     if (!e.writeVarU32(uint32_t(MemoryTableFlags::Default)))
    4253           0 :         return false;
    4254             : 
    4255           0 :     return true;
    4256             : }
    4257             : 
    4258             : static bool
    4259           0 : EncodeExpr(Encoder& e, AstExpr& expr)
    4260             : {
    4261           0 :     switch (expr.kind()) {
    4262             :       case AstExprKind::Pop:
    4263           0 :         return true;
    4264             :       case AstExprKind::Nop:
    4265           0 :         return e.writeOp(Op::Nop);
    4266             :       case AstExprKind::Unreachable:
    4267           0 :         return e.writeOp(Op::Unreachable);
    4268             :       case AstExprKind::BinaryOperator:
    4269           0 :         return EncodeBinaryOperator(e, expr.as<AstBinaryOperator>());
    4270             :       case AstExprKind::Block:
    4271           0 :         return EncodeBlock(e, expr.as<AstBlock>());
    4272             :       case AstExprKind::Branch:
    4273           0 :         return EncodeBranch(e, expr.as<AstBranch>());
    4274             :       case AstExprKind::Call:
    4275           0 :         return EncodeCall(e, expr.as<AstCall>());
    4276             :       case AstExprKind::CallIndirect:
    4277           0 :         return EncodeCallIndirect(e, expr.as<AstCallIndirect>());
    4278             :       case AstExprKind::ComparisonOperator:
    4279           0 :         return EncodeComparisonOperator(e, expr.as<AstComparisonOperator>());
    4280             :       case AstExprKind::Const:
    4281           0 :         return EncodeConst(e, expr.as<AstConst>());
    4282             :       case AstExprKind::ConversionOperator:
    4283           0 :         return EncodeConversionOperator(e, expr.as<AstConversionOperator>());
    4284             :       case AstExprKind::Drop:
    4285           0 :         return EncodeDrop(e, expr.as<AstDrop>());
    4286             :       case AstExprKind::First:
    4287           0 :         return EncodeFirst(e, expr.as<AstFirst>());
    4288             :       case AstExprKind::GetLocal:
    4289           0 :         return EncodeGetLocal(e, expr.as<AstGetLocal>());
    4290             :       case AstExprKind::GetGlobal:
    4291           0 :         return EncodeGetGlobal(e, expr.as<AstGetGlobal>());
    4292             :       case AstExprKind::If:
    4293           0 :         return EncodeIf(e, expr.as<AstIf>());
    4294             :       case AstExprKind::Load:
    4295           0 :         return EncodeLoad(e, expr.as<AstLoad>());
    4296             :       case AstExprKind::Return:
    4297           0 :         return EncodeReturn(e, expr.as<AstReturn>());
    4298             :       case AstExprKind::SetLocal:
    4299           0 :         return EncodeSetLocal(e, expr.as<AstSetLocal>());
    4300             :       case AstExprKind::TeeLocal:
    4301           0 :         return EncodeTeeLocal(e, expr.as<AstTeeLocal>());
    4302             :       case AstExprKind::SetGlobal:
    4303           0 :         return EncodeSetGlobal(e, expr.as<AstSetGlobal>());
    4304             :       case AstExprKind::Store:
    4305           0 :         return EncodeStore(e, expr.as<AstStore>());
    4306             :       case AstExprKind::BranchTable:
    4307           0 :         return EncodeBranchTable(e, expr.as<AstBranchTable>());
    4308             :       case AstExprKind::TernaryOperator:
    4309           0 :         return EncodeTernaryOperator(e, expr.as<AstTernaryOperator>());
    4310             :       case AstExprKind::UnaryOperator:
    4311           0 :         return EncodeUnaryOperator(e, expr.as<AstUnaryOperator>());
    4312             :       case AstExprKind::CurrentMemory:
    4313           0 :         return EncodeCurrentMemory(e, expr.as<AstCurrentMemory>());
    4314             :       case AstExprKind::GrowMemory:
    4315           0 :         return EncodeGrowMemory(e, expr.as<AstGrowMemory>());
    4316             :     }
    4317           0 :     MOZ_CRASH("Bad expr kind");
    4318             : }
    4319             : 
    4320             : /*****************************************************************************/
    4321             : // wasm AST binary serialization
    4322             : 
    4323             : static bool
    4324           0 : EncodeTypeSection(Encoder& e, AstModule& module)
    4325             : {
    4326           0 :     if (module.sigs().empty())
    4327           0 :         return true;
    4328             : 
    4329             :     size_t offset;
    4330           0 :     if (!e.startSection(SectionId::Type, &offset))
    4331           0 :         return false;
    4332             : 
    4333           0 :     if (!e.writeVarU32(module.sigs().length()))
    4334           0 :         return false;
    4335             : 
    4336           0 :     for (AstSig* sig : module.sigs()) {
    4337           0 :         if (!e.writeVarU32(uint32_t(TypeCode::Func)))
    4338           0 :             return false;
    4339             : 
    4340           0 :         if (!e.writeVarU32(sig->args().length()))
    4341           0 :             return false;
    4342             : 
    4343           0 :         for (ValType t : sig->args()) {
    4344           0 :             if (!e.writeValType(t))
    4345           0 :                 return false;
    4346             :         }
    4347             : 
    4348           0 :         if (!e.writeVarU32(!IsVoid(sig->ret())))
    4349           0 :             return false;
    4350             : 
    4351           0 :         if (!IsVoid(sig->ret())) {
    4352           0 :             if (!e.writeValType(NonVoidToValType(sig->ret())))
    4353           0 :                 return false;
    4354             :         }
    4355             :     }
    4356             : 
    4357           0 :     e.finishSection(offset);
    4358           0 :     return true;
    4359             : }
    4360             : 
    4361             : static bool
    4362           0 : EncodeFunctionSection(Encoder& e, AstModule& module)
    4363             : {
    4364           0 :     if (module.funcs().empty())
    4365           0 :         return true;
    4366             : 
    4367             :     size_t offset;
    4368           0 :     if (!e.startSection(SectionId::Function, &offset))
    4369           0 :         return false;
    4370             : 
    4371           0 :     if (!e.writeVarU32(module.funcs().length()))
    4372           0 :         return false;
    4373             : 
    4374           0 :     for (AstFunc* func : module.funcs()) {
    4375           0 :         if (!e.writeVarU32(func->sig().index()))
    4376           0 :             return false;
    4377             :     }
    4378             : 
    4379           0 :     e.finishSection(offset);
    4380           0 :     return true;
    4381             : }
    4382             : 
    4383             : static bool
    4384           0 : EncodeBytes(Encoder& e, AstName wasmName)
    4385             : {
    4386           0 :     TwoByteChars range(wasmName.begin(), wasmName.length());
    4387           0 :     UniqueChars utf8(JS::CharsToNewUTF8CharsZ(nullptr, range).c_str());
    4388           0 :     return utf8 && e.writeBytes(utf8.get(), strlen(utf8.get()));
    4389             : }
    4390             : 
    4391             : static bool
    4392           0 : EncodeLimits(Encoder& e, const Limits& limits)
    4393             : {
    4394           0 :     uint32_t flags = limits.maximum ? 1 : 0;
    4395           0 :     if (!e.writeVarU32(flags))
    4396           0 :         return false;
    4397             : 
    4398           0 :     if (!e.writeVarU32(limits.initial))
    4399           0 :         return false;
    4400             : 
    4401           0 :     if (limits.maximum) {
    4402           0 :         if (!e.writeVarU32(*limits.maximum))
    4403           0 :             return false;
    4404             :     }
    4405             : 
    4406           0 :     return true;
    4407             : }
    4408             : 
    4409             : static bool
    4410           0 : EncodeTableLimits(Encoder& e, const Limits& limits)
    4411             : {
    4412           0 :     if (!e.writeVarU32(uint32_t(TypeCode::AnyFunc)))
    4413           0 :         return false;
    4414             : 
    4415           0 :     return EncodeLimits(e, limits);
    4416             : }
    4417             : 
    4418             : static bool
    4419           0 : EncodeGlobalType(Encoder& e, const AstGlobal* global)
    4420             : {
    4421           0 :     return e.writeValType(global->type()) &&
    4422           0 :            e.writeVarU32(global->isMutable() ? uint32_t(GlobalTypeImmediate::IsMutable) : 0);
    4423             : }
    4424             : 
    4425             : static bool
    4426           0 : EncodeImport(Encoder& e, AstImport& imp)
    4427             : {
    4428           0 :     if (!EncodeBytes(e, imp.module()))
    4429           0 :         return false;
    4430             : 
    4431           0 :     if (!EncodeBytes(e, imp.field()))
    4432           0 :         return false;
    4433             : 
    4434           0 :     if (!e.writeVarU32(uint32_t(imp.kind())))
    4435           0 :         return false;
    4436             : 
    4437           0 :     switch (imp.kind()) {
    4438             :       case DefinitionKind::Function:
    4439           0 :         if (!e.writeVarU32(imp.funcSig().index()))
    4440           0 :             return false;
    4441           0 :         break;
    4442             :       case DefinitionKind::Global:
    4443           0 :         MOZ_ASSERT(!imp.global().hasInit());
    4444           0 :         if (!EncodeGlobalType(e, &imp.global()))
    4445           0 :             return false;
    4446           0 :         break;
    4447             :       case DefinitionKind::Table:
    4448           0 :         if (!EncodeTableLimits(e, imp.limits()))
    4449           0 :             return false;
    4450           0 :         break;
    4451             :       case DefinitionKind::Memory:
    4452           0 :         if (!EncodeLimits(e, imp.limits()))
    4453           0 :             return false;
    4454           0 :         break;
    4455             :     }
    4456             : 
    4457           0 :     return true;
    4458             : }
    4459             : 
    4460             : static bool
    4461           0 : EncodeImportSection(Encoder& e, AstModule& module)
    4462             : {
    4463           0 :     if (module.imports().empty())
    4464           0 :         return true;
    4465             : 
    4466             :     size_t offset;
    4467           0 :     if (!e.startSection(SectionId::Import, &offset))
    4468           0 :         return false;
    4469             : 
    4470           0 :     if (!e.writeVarU32(module.imports().length()))
    4471           0 :         return false;
    4472             : 
    4473           0 :     for (AstImport* imp : module.imports()) {
    4474           0 :         if (!EncodeImport(e, *imp))
    4475           0 :             return false;
    4476             :     }
    4477             : 
    4478           0 :     e.finishSection(offset);
    4479           0 :     return true;
    4480             : }
    4481             : 
    4482             : static bool
    4483           0 : EncodeMemorySection(Encoder& e, AstModule& module)
    4484             : {
    4485           0 :     size_t numOwnMemories = 0;
    4486           0 :     for (const AstResizable& memory : module.memories()) {
    4487           0 :         if (!memory.imported)
    4488           0 :             numOwnMemories++;
    4489             :     }
    4490             : 
    4491           0 :     if (!numOwnMemories)
    4492           0 :         return true;
    4493             : 
    4494             :     size_t offset;
    4495           0 :     if (!e.startSection(SectionId::Memory, &offset))
    4496           0 :         return false;
    4497             : 
    4498           0 :     if (!e.writeVarU32(numOwnMemories))
    4499           0 :         return false;
    4500             : 
    4501           0 :     for (const AstResizable& memory : module.memories()) {
    4502           0 :         if (memory.imported)
    4503           0 :             continue;
    4504           0 :         if (!EncodeLimits(e, memory.limits))
    4505           0 :             return false;
    4506             :     }
    4507             : 
    4508           0 :     e.finishSection(offset);
    4509           0 :     return true;
    4510             : }
    4511             : 
    4512             : static bool
    4513           0 : EncodeGlobalSection(Encoder& e, AstModule& module)
    4514             : {
    4515             :     size_t offset;
    4516           0 :     if (!e.startSection(SectionId::Global, &offset))
    4517           0 :         return false;
    4518             : 
    4519           0 :     const AstGlobalVector& globals = module.globals();
    4520             : 
    4521           0 :     if (!e.writeVarU32(globals.length()))
    4522           0 :         return false;
    4523             : 
    4524           0 :     for (const AstGlobal* global : globals) {
    4525           0 :         MOZ_ASSERT(global->hasInit());
    4526           0 :         if (!EncodeGlobalType(e, global))
    4527           0 :             return false;
    4528           0 :         if (!EncodeExpr(e, global->init()))
    4529           0 :             return false;
    4530           0 :         if (!e.writeOp(Op::End))
    4531           0 :             return false;
    4532             :     }
    4533             : 
    4534           0 :     e.finishSection(offset);
    4535           0 :     return true;
    4536             : }
    4537             : 
    4538             : static bool
    4539           0 : EncodeExport(Encoder& e, AstExport& exp)
    4540             : {
    4541           0 :     if (!EncodeBytes(e, exp.name()))
    4542           0 :         return false;
    4543             : 
    4544           0 :     if (!e.writeVarU32(uint32_t(exp.kind())))
    4545           0 :         return false;
    4546             : 
    4547           0 :     if (!e.writeVarU32(exp.ref().index()))
    4548           0 :         return false;
    4549             : 
    4550           0 :     return true;
    4551             : }
    4552             : 
    4553             : static bool
    4554           0 : EncodeExportSection(Encoder& e, AstModule& module)
    4555             : {
    4556           0 :     uint32_t numExports = module.exports().length();
    4557           0 :     if (!numExports)
    4558           0 :         return true;
    4559             : 
    4560             :     size_t offset;
    4561           0 :     if (!e.startSection(SectionId::Export, &offset))
    4562           0 :         return false;
    4563             : 
    4564           0 :     if (!e.writeVarU32(numExports))
    4565           0 :         return false;
    4566             : 
    4567           0 :     for (AstExport* exp : module.exports()) {
    4568           0 :         if (!EncodeExport(e, *exp))
    4569           0 :             return false;
    4570             :     }
    4571             : 
    4572           0 :     e.finishSection(offset);
    4573           0 :     return true;
    4574             : }
    4575             : 
    4576             : static bool
    4577           0 : EncodeTableSection(Encoder& e, AstModule& module)
    4578             : {
    4579           0 :     size_t numOwnTables = 0;
    4580           0 :     for (const AstResizable& table : module.tables()) {
    4581           0 :         if (!table.imported)
    4582           0 :             numOwnTables++;
    4583             :     }
    4584             : 
    4585           0 :     if (!numOwnTables)
    4586           0 :         return true;
    4587             : 
    4588             :     size_t offset;
    4589           0 :     if (!e.startSection(SectionId::Table, &offset))
    4590           0 :         return false;
    4591             : 
    4592           0 :     if (!e.writeVarU32(numOwnTables))
    4593           0 :         return false;
    4594             : 
    4595           0 :     for (const AstResizable& table : module.tables()) {
    4596           0 :         if (table.imported)
    4597           0 :             continue;
    4598           0 :         if (!EncodeTableLimits(e, table.limits))
    4599           0 :             return false;
    4600             :     }
    4601             : 
    4602           0 :     e.finishSection(offset);
    4603           0 :     return true;
    4604             : }
    4605             : 
    4606             : static bool
    4607           0 : EncodeFunctionBody(Encoder& e, AstFunc& func)
    4608             : {
    4609             :     size_t bodySizeAt;
    4610           0 :     if (!e.writePatchableVarU32(&bodySizeAt))
    4611           0 :         return false;
    4612             : 
    4613           0 :     size_t beforeBody = e.currentOffset();
    4614             : 
    4615           0 :     ValTypeVector varTypes;
    4616           0 :     if (!varTypes.appendAll(func.vars()))
    4617           0 :         return false;
    4618           0 :     if (!EncodeLocalEntries(e, varTypes))
    4619           0 :         return false;
    4620             : 
    4621           0 :     for (AstExpr* expr : func.body()) {
    4622           0 :         if (!EncodeExpr(e, *expr))
    4623           0 :             return false;
    4624             :     }
    4625             : 
    4626           0 :     if (!e.writeOp(Op::End))
    4627           0 :         return false;
    4628             : 
    4629           0 :     e.patchVarU32(bodySizeAt, e.currentOffset() - beforeBody);
    4630           0 :     return true;
    4631             : }
    4632             : 
    4633             : static bool
    4634           0 : EncodeStartSection(Encoder& e, AstModule& module)
    4635             : {
    4636           0 :     if (!module.hasStartFunc())
    4637           0 :         return true;
    4638             : 
    4639             :     size_t offset;
    4640           0 :     if (!e.startSection(SectionId::Start, &offset))
    4641           0 :         return false;
    4642             : 
    4643           0 :     if (!e.writeVarU32(module.startFunc().func().index()))
    4644           0 :         return false;
    4645             : 
    4646           0 :     e.finishSection(offset);
    4647           0 :     return true;
    4648             : }
    4649             : 
    4650             : static bool
    4651           0 : EncodeCodeSection(Encoder& e, AstModule& module)
    4652             : {
    4653           0 :     if (module.funcs().empty())
    4654           0 :         return true;
    4655             : 
    4656             :     size_t offset;
    4657           0 :     if (!e.startSection(SectionId::Code, &offset))
    4658           0 :         return false;
    4659             : 
    4660           0 :     if (!e.writeVarU32(module.funcs().length()))
    4661           0 :         return false;
    4662             : 
    4663           0 :     for (AstFunc* func : module.funcs()) {
    4664           0 :         if (!EncodeFunctionBody(e, *func))
    4665           0 :             return false;
    4666             :     }
    4667             : 
    4668           0 :     e.finishSection(offset);
    4669           0 :     return true;
    4670             : }
    4671             : 
    4672             : static bool
    4673           0 : EncodeDataSegment(Encoder& e, const AstDataSegment& segment)
    4674             : {
    4675           0 :     if (!e.writeVarU32(0))  // linear memory index
    4676           0 :         return false;
    4677             : 
    4678           0 :     if (!EncodeExpr(e, *segment.offset()))
    4679           0 :         return false;
    4680           0 :     if (!e.writeOp(Op::End))
    4681           0 :         return false;
    4682             : 
    4683           0 :     size_t totalLength = 0;
    4684           0 :     for (const AstName& fragment : segment.fragments())
    4685           0 :         totalLength += fragment.length();
    4686             : 
    4687           0 :     Vector<uint8_t, 0, SystemAllocPolicy> bytes;
    4688           0 :     if (!bytes.reserve(totalLength))
    4689           0 :         return false;
    4690             : 
    4691           0 :     for (const AstName& fragment : segment.fragments()) {
    4692           0 :         const char16_t* cur = fragment.begin();
    4693           0 :         const char16_t* end = fragment.end();
    4694           0 :         while (cur != end) {
    4695             :             uint8_t byte;
    4696           0 :             MOZ_ALWAYS_TRUE(ConsumeTextByte(&cur, end, &byte));
    4697           0 :             bytes.infallibleAppend(byte);
    4698             :         }
    4699             :     }
    4700             : 
    4701           0 :     return e.writeBytes(bytes.begin(), bytes.length());
    4702             : }
    4703             : 
    4704             : static bool
    4705           0 : EncodeDataSection(Encoder& e, AstModule& module)
    4706             : {
    4707           0 :     if (module.dataSegments().empty())
    4708           0 :         return true;
    4709             : 
    4710             :     size_t offset;
    4711           0 :     if (!e.startSection(SectionId::Data, &offset))
    4712           0 :         return false;
    4713             : 
    4714           0 :     if (!e.writeVarU32(module.dataSegments().length()))
    4715           0 :         return false;
    4716             : 
    4717           0 :     for (AstDataSegment* segment : module.dataSegments()) {
    4718           0 :         if (!EncodeDataSegment(e, *segment))
    4719           0 :             return false;
    4720             :     }
    4721             : 
    4722           0 :     e.finishSection(offset);
    4723           0 :     return true;
    4724             : }
    4725             : 
    4726             : static bool
    4727           0 : EncodeElemSegment(Encoder& e, AstElemSegment& segment)
    4728             : {
    4729           0 :     if (!e.writeVarU32(0)) // table index
    4730           0 :         return false;
    4731             : 
    4732           0 :     if (!EncodeExpr(e, *segment.offset()))
    4733           0 :         return false;
    4734           0 :     if (!e.writeOp(Op::End))
    4735           0 :         return false;
    4736             : 
    4737           0 :     if (!e.writeVarU32(segment.elems().length()))
    4738           0 :         return false;
    4739             : 
    4740           0 :     for (const AstRef& elem : segment.elems()) {
    4741           0 :         if (!e.writeVarU32(elem.index()))
    4742           0 :             return false;
    4743             :     }
    4744             : 
    4745           0 :     return true;
    4746             : }
    4747             : 
    4748             : static bool
    4749           0 : EncodeElemSection(Encoder& e, AstModule& module)
    4750             : {
    4751           0 :     if (module.elemSegments().empty())
    4752           0 :         return true;
    4753             : 
    4754             :     size_t offset;
    4755           0 :     if (!e.startSection(SectionId::Elem, &offset))
    4756           0 :         return false;
    4757             : 
    4758           0 :     if (!e.writeVarU32(module.elemSegments().length()))
    4759           0 :         return false;
    4760             : 
    4761           0 :     for (AstElemSegment* segment : module.elemSegments()) {
    4762           0 :         if (!EncodeElemSegment(e, *segment))
    4763           0 :             return false;
    4764             :     }
    4765             : 
    4766           0 :     e.finishSection(offset);
    4767           0 :     return true;
    4768             : }
    4769             : 
    4770             : static bool
    4771           0 : EncodeModule(AstModule& module, Bytes* bytes)
    4772             : {
    4773           0 :     Encoder e(*bytes);
    4774             : 
    4775           0 :     if (!e.writeFixedU32(MagicNumber))
    4776           0 :         return false;
    4777             : 
    4778           0 :     if (!e.writeFixedU32(EncodingVersion))
    4779           0 :         return false;
    4780             : 
    4781           0 :     if (!EncodeTypeSection(e, module))
    4782           0 :         return false;
    4783             : 
    4784           0 :     if (!EncodeImportSection(e, module))
    4785           0 :         return false;
    4786             : 
    4787           0 :     if (!EncodeFunctionSection(e, module))
    4788           0 :         return false;
    4789             : 
    4790           0 :     if (!EncodeTableSection(e, module))
    4791           0 :         return false;
    4792             : 
    4793           0 :     if (!EncodeMemorySection(e, module))
    4794           0 :         return false;
    4795             : 
    4796           0 :     if (!EncodeGlobalSection(e, module))
    4797           0 :         return false;
    4798             : 
    4799           0 :     if (!EncodeExportSection(e, module))
    4800           0 :         return false;
    4801             : 
    4802           0 :     if (!EncodeStartSection(e, module))
    4803           0 :         return false;
    4804             : 
    4805           0 :     if (!EncodeElemSection(e, module))
    4806           0 :         return false;
    4807             : 
    4808           0 :     if (!EncodeCodeSection(e, module))
    4809           0 :         return false;
    4810             : 
    4811           0 :     if (!EncodeDataSection(e, module))
    4812           0 :         return false;
    4813             : 
    4814           0 :     return true;
    4815             : }
    4816             : 
    4817             : static bool
    4818           0 : EncodeBinaryModule(const AstModule& module, Bytes* bytes)
    4819             : {
    4820           0 :     Encoder e(*bytes);
    4821             : 
    4822           0 :     const AstDataSegmentVector& dataSegments = module.dataSegments();
    4823           0 :     MOZ_ASSERT(dataSegments.length() == 1);
    4824             : 
    4825           0 :     for (const AstName& fragment : dataSegments[0]->fragments()) {
    4826           0 :         const char16_t* cur = fragment.begin();
    4827           0 :         const char16_t* end = fragment.end();
    4828           0 :         while (cur != end) {
    4829             :             uint8_t byte;
    4830           0 :             MOZ_ALWAYS_TRUE(ConsumeTextByte(&cur, end, &byte));
    4831           0 :             if (!e.writeFixedU8(byte))
    4832           0 :                 return false;
    4833             :         }
    4834             :     }
    4835             : 
    4836           0 :     return true;
    4837             : }
    4838             : 
    4839             : /*****************************************************************************/
    4840             : 
    4841             : bool
    4842           0 : wasm::TextToBinary(const char16_t* text, Bytes* bytes, UniqueChars* error)
    4843             : {
    4844           0 :     LifoAlloc lifo(AST_LIFO_DEFAULT_CHUNK_SIZE);
    4845             : 
    4846           0 :     bool binary = false;
    4847           0 :     AstModule* module = ParseModule(text, lifo, error, &binary);
    4848           0 :     if (!module)
    4849           0 :         return false;
    4850             : 
    4851           0 :     if (binary)
    4852           0 :         return EncodeBinaryModule(*module, bytes);
    4853             : 
    4854           0 :     if (!ResolveModule(lifo, module, error))
    4855           0 :         return false;
    4856             : 
    4857           0 :     return EncodeModule(*module, bytes);
    4858             : }

Generated by: LCOV version 1.13