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