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