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