1/*
2 * Copyright 2015 WebAssembly Community Group participants
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//
18// wasm.h: Define Binaryen IR, a representation for WebAssembly, with
19// all core parts in one simple header file.
20//
21// For more overview, see README.md
22//
23
24#ifndef wasm_wasm_h
25#define wasm_wasm_h
26
27#include <algorithm>
28#include <array>
29#include <cassert>
30#include <map>
31#include <ostream>
32#include <string>
33#include <unordered_map>
34#include <vector>
35
36#include "literal.h"
37#include "mixed_arena.h"
38#include "support/index.h"
39#include "support/name.h"
40#include "wasm-features.h"
41#include "wasm-type.h"
42
43namespace wasm {
44
45// An index in a wasm module
46using Index = uint32_t;
47
48// An address in linear memory.
49struct Address {
50 using address32_t = uint32_t;
51 using address64_t = uint64_t;
52 address64_t addr;
53 constexpr Address() : addr(0) {}
54 constexpr Address(uint64_t a) : addr(a) {}
55 Address& operator=(uint64_t a) {
56 addr = a;
57 return *this;
58 }
59 operator address64_t() const { return addr; }
60 Address& operator++(int) {
61 ++addr;
62 return *this;
63 }
64};
65
66enum class IRProfile { Normal, Poppy };
67
68// Operators
69
70enum UnaryOp {
71 // int
72 ClzInt32,
73 ClzInt64,
74 CtzInt32,
75 CtzInt64,
76 PopcntInt32,
77 PopcntInt64,
78
79 // float
80 NegFloat32,
81 NegFloat64,
82 AbsFloat32,
83 AbsFloat64,
84 CeilFloat32,
85 CeilFloat64,
86 FloorFloat32,
87 FloorFloat64,
88 TruncFloat32,
89 TruncFloat64,
90 NearestFloat32,
91 NearestFloat64,
92 SqrtFloat32,
93 SqrtFloat64,
94
95 // relational
96 EqZInt32,
97 EqZInt64,
98
99 // conversions
100 // extend i32 to i64
101 ExtendSInt32,
102 ExtendUInt32,
103 // i64 to i32
104 WrapInt64,
105 // float to int
106 TruncSFloat32ToInt32,
107 TruncSFloat32ToInt64,
108 TruncUFloat32ToInt32,
109 TruncUFloat32ToInt64,
110 TruncSFloat64ToInt32,
111 TruncSFloat64ToInt64,
112 TruncUFloat64ToInt32,
113 TruncUFloat64ToInt64,
114 // reintepret bits to int
115 ReinterpretFloat32,
116 ReinterpretFloat64,
117 // int to float
118 ConvertSInt32ToFloat32,
119 ConvertSInt32ToFloat64,
120 ConvertUInt32ToFloat32,
121 ConvertUInt32ToFloat64,
122 ConvertSInt64ToFloat32,
123 ConvertSInt64ToFloat64,
124 ConvertUInt64ToFloat32,
125 ConvertUInt64ToFloat64,
126 // f32 to f64
127 PromoteFloat32,
128 // f64 to f32
129 DemoteFloat64,
130 // reinterpret bits to float
131 ReinterpretInt32,
132 ReinterpretInt64,
133
134 // Extend signed subword-sized integer. This differs from e.g. ExtendSInt32
135 // because the input integer is in an i64 value insetad of an i32 value.
136 ExtendS8Int32,
137 ExtendS16Int32,
138 ExtendS8Int64,
139 ExtendS16Int64,
140 ExtendS32Int64,
141
142 // Saturating float-to-int
143 TruncSatSFloat32ToInt32,
144 TruncSatUFloat32ToInt32,
145 TruncSatSFloat64ToInt32,
146 TruncSatUFloat64ToInt32,
147 TruncSatSFloat32ToInt64,
148 TruncSatUFloat32ToInt64,
149 TruncSatSFloat64ToInt64,
150 TruncSatUFloat64ToInt64,
151
152 // SIMD splats
153 SplatVecI8x16,
154 SplatVecI16x8,
155 SplatVecI32x4,
156 SplatVecI64x2,
157 SplatVecF32x4,
158 SplatVecF64x2,
159
160 // SIMD arithmetic
161 NotVec128,
162 AnyTrueVec128,
163 AbsVecI8x16,
164 NegVecI8x16,
165 AllTrueVecI8x16,
166 BitmaskVecI8x16,
167 PopcntVecI8x16,
168 AbsVecI16x8,
169 NegVecI16x8,
170 AllTrueVecI16x8,
171 BitmaskVecI16x8,
172 AbsVecI32x4,
173 NegVecI32x4,
174 AllTrueVecI32x4,
175 BitmaskVecI32x4,
176 AbsVecI64x2,
177 NegVecI64x2,
178 AllTrueVecI64x2,
179 BitmaskVecI64x2,
180 AbsVecF32x4,
181 NegVecF32x4,
182 SqrtVecF32x4,
183 CeilVecF32x4,
184 FloorVecF32x4,
185 TruncVecF32x4,
186 NearestVecF32x4,
187 AbsVecF64x2,
188 NegVecF64x2,
189 SqrtVecF64x2,
190 CeilVecF64x2,
191 FloorVecF64x2,
192 TruncVecF64x2,
193 NearestVecF64x2,
194 ExtAddPairwiseSVecI8x16ToI16x8,
195 ExtAddPairwiseUVecI8x16ToI16x8,
196 ExtAddPairwiseSVecI16x8ToI32x4,
197 ExtAddPairwiseUVecI16x8ToI32x4,
198
199 // SIMD conversions
200 TruncSatSVecF32x4ToVecI32x4,
201 TruncSatUVecF32x4ToVecI32x4,
202 ConvertSVecI32x4ToVecF32x4,
203 ConvertUVecI32x4ToVecF32x4,
204 ExtendLowSVecI8x16ToVecI16x8,
205 ExtendHighSVecI8x16ToVecI16x8,
206 ExtendLowUVecI8x16ToVecI16x8,
207 ExtendHighUVecI8x16ToVecI16x8,
208 ExtendLowSVecI16x8ToVecI32x4,
209 ExtendHighSVecI16x8ToVecI32x4,
210 ExtendLowUVecI16x8ToVecI32x4,
211 ExtendHighUVecI16x8ToVecI32x4,
212 ExtendLowSVecI32x4ToVecI64x2,
213 ExtendHighSVecI32x4ToVecI64x2,
214 ExtendLowUVecI32x4ToVecI64x2,
215 ExtendHighUVecI32x4ToVecI64x2,
216
217 ConvertLowSVecI32x4ToVecF64x2,
218 ConvertLowUVecI32x4ToVecF64x2,
219 TruncSatZeroSVecF64x2ToVecI32x4,
220 TruncSatZeroUVecF64x2ToVecI32x4,
221 DemoteZeroVecF64x2ToVecF32x4,
222 PromoteLowVecF32x4ToVecF64x2,
223
224 // Relaxed SIMD
225 RelaxedTruncSVecF32x4ToVecI32x4,
226 RelaxedTruncUVecF32x4ToVecI32x4,
227 RelaxedTruncZeroSVecF64x2ToVecI32x4,
228 RelaxedTruncZeroUVecF64x2ToVecI32x4,
229
230 InvalidUnary
231};
232
233enum BinaryOp {
234 // int or float
235 AddInt32,
236 SubInt32,
237 MulInt32,
238
239 // int
240 DivSInt32,
241 DivUInt32,
242 RemSInt32,
243 RemUInt32,
244 AndInt32,
245 OrInt32,
246 XorInt32,
247 ShlInt32,
248 ShrSInt32,
249 ShrUInt32,
250 RotLInt32,
251 RotRInt32,
252
253 // relational ops
254 // int or float
255 EqInt32,
256 NeInt32,
257 // int
258 LtSInt32,
259 LtUInt32,
260 LeSInt32,
261 LeUInt32,
262 GtSInt32,
263 GtUInt32,
264 GeSInt32,
265 GeUInt32,
266
267 // int or float
268 AddInt64,
269 SubInt64,
270 MulInt64,
271
272 // int
273 DivSInt64,
274 DivUInt64,
275 RemSInt64,
276 RemUInt64,
277 AndInt64,
278 OrInt64,
279 XorInt64,
280 ShlInt64,
281 ShrSInt64,
282 ShrUInt64,
283 RotLInt64,
284 RotRInt64,
285
286 // relational ops
287 // int or float
288 EqInt64,
289 NeInt64,
290 // int
291 LtSInt64,
292 LtUInt64,
293 LeSInt64,
294 LeUInt64,
295 GtSInt64,
296 GtUInt64,
297 GeSInt64,
298 GeUInt64,
299
300 // int or float
301 AddFloat32,
302 SubFloat32,
303 MulFloat32,
304
305 // float
306 DivFloat32,
307 CopySignFloat32,
308 MinFloat32,
309 MaxFloat32,
310
311 // relational ops
312 // int or float
313 EqFloat32,
314 NeFloat32,
315 // float
316 LtFloat32,
317 LeFloat32,
318 GtFloat32,
319 GeFloat32,
320
321 // int or float
322 AddFloat64,
323 SubFloat64,
324 MulFloat64,
325
326 // float
327 DivFloat64,
328 CopySignFloat64,
329 MinFloat64,
330 MaxFloat64,
331
332 // relational ops
333 // int or float
334 EqFloat64,
335 NeFloat64,
336 // float
337 LtFloat64,
338 LeFloat64,
339 GtFloat64,
340 GeFloat64,
341
342 // SIMD relational ops (return vectors)
343 EqVecI8x16,
344 NeVecI8x16,
345 LtSVecI8x16,
346 LtUVecI8x16,
347 GtSVecI8x16,
348 GtUVecI8x16,
349 LeSVecI8x16,
350 LeUVecI8x16,
351 GeSVecI8x16,
352 GeUVecI8x16,
353 EqVecI16x8,
354 NeVecI16x8,
355 LtSVecI16x8,
356 LtUVecI16x8,
357 GtSVecI16x8,
358 GtUVecI16x8,
359 LeSVecI16x8,
360 LeUVecI16x8,
361 GeSVecI16x8,
362 GeUVecI16x8,
363 EqVecI32x4,
364 NeVecI32x4,
365 LtSVecI32x4,
366 LtUVecI32x4,
367 GtSVecI32x4,
368 GtUVecI32x4,
369 LeSVecI32x4,
370 LeUVecI32x4,
371 GeSVecI32x4,
372 GeUVecI32x4,
373 EqVecI64x2,
374 NeVecI64x2,
375 LtSVecI64x2,
376 GtSVecI64x2,
377 LeSVecI64x2,
378 GeSVecI64x2,
379 EqVecF32x4,
380 NeVecF32x4,
381 LtVecF32x4,
382 GtVecF32x4,
383 LeVecF32x4,
384 GeVecF32x4,
385 EqVecF64x2,
386 NeVecF64x2,
387 LtVecF64x2,
388 GtVecF64x2,
389 LeVecF64x2,
390 GeVecF64x2,
391
392 // SIMD arithmetic
393 AndVec128,
394 OrVec128,
395 XorVec128,
396 AndNotVec128,
397 AddVecI8x16,
398 AddSatSVecI8x16,
399 AddSatUVecI8x16,
400 SubVecI8x16,
401 SubSatSVecI8x16,
402 SubSatUVecI8x16,
403 MinSVecI8x16,
404 MinUVecI8x16,
405 MaxSVecI8x16,
406 MaxUVecI8x16,
407 AvgrUVecI8x16,
408 AddVecI16x8,
409 AddSatSVecI16x8,
410 AddSatUVecI16x8,
411 SubVecI16x8,
412 SubSatSVecI16x8,
413 SubSatUVecI16x8,
414 MulVecI16x8,
415 MinSVecI16x8,
416 MinUVecI16x8,
417 MaxSVecI16x8,
418 MaxUVecI16x8,
419 AvgrUVecI16x8,
420 Q15MulrSatSVecI16x8,
421 ExtMulLowSVecI16x8,
422 ExtMulHighSVecI16x8,
423 ExtMulLowUVecI16x8,
424 ExtMulHighUVecI16x8,
425 AddVecI32x4,
426 SubVecI32x4,
427 MulVecI32x4,
428 MinSVecI32x4,
429 MinUVecI32x4,
430 MaxSVecI32x4,
431 MaxUVecI32x4,
432 DotSVecI16x8ToVecI32x4,
433 ExtMulLowSVecI32x4,
434 ExtMulHighSVecI32x4,
435 ExtMulLowUVecI32x4,
436 ExtMulHighUVecI32x4,
437 AddVecI64x2,
438 SubVecI64x2,
439 MulVecI64x2,
440 ExtMulLowSVecI64x2,
441 ExtMulHighSVecI64x2,
442 ExtMulLowUVecI64x2,
443 ExtMulHighUVecI64x2,
444 AddVecF32x4,
445 SubVecF32x4,
446 MulVecF32x4,
447 DivVecF32x4,
448 MinVecF32x4,
449 MaxVecF32x4,
450 PMinVecF32x4,
451 PMaxVecF32x4,
452 AddVecF64x2,
453 SubVecF64x2,
454 MulVecF64x2,
455 DivVecF64x2,
456 MinVecF64x2,
457 MaxVecF64x2,
458 PMinVecF64x2,
459 PMaxVecF64x2,
460
461 // SIMD Conversion
462 NarrowSVecI16x8ToVecI8x16,
463 NarrowUVecI16x8ToVecI8x16,
464 NarrowSVecI32x4ToVecI16x8,
465 NarrowUVecI32x4ToVecI16x8,
466
467 // SIMD Swizzle
468 SwizzleVecI8x16,
469
470 // Relaxed SIMD
471 RelaxedSwizzleVecI8x16,
472 RelaxedMinVecF32x4,
473 RelaxedMaxVecF32x4,
474 RelaxedMinVecF64x2,
475 RelaxedMaxVecF64x2,
476 RelaxedQ15MulrSVecI16x8,
477 DotI8x16I7x16SToVecI16x8,
478
479 InvalidBinary
480};
481
482enum AtomicRMWOp { RMWAdd, RMWSub, RMWAnd, RMWOr, RMWXor, RMWXchg };
483
484enum SIMDExtractOp {
485 ExtractLaneSVecI8x16,
486 ExtractLaneUVecI8x16,
487 ExtractLaneSVecI16x8,
488 ExtractLaneUVecI16x8,
489 ExtractLaneVecI32x4,
490 ExtractLaneVecI64x2,
491 ExtractLaneVecF32x4,
492 ExtractLaneVecF64x2
493};
494
495enum SIMDReplaceOp {
496 ReplaceLaneVecI8x16,
497 ReplaceLaneVecI16x8,
498 ReplaceLaneVecI32x4,
499 ReplaceLaneVecI64x2,
500 ReplaceLaneVecF32x4,
501 ReplaceLaneVecF64x2,
502};
503
504enum SIMDShiftOp {
505 ShlVecI8x16,
506 ShrSVecI8x16,
507 ShrUVecI8x16,
508 ShlVecI16x8,
509 ShrSVecI16x8,
510 ShrUVecI16x8,
511 ShlVecI32x4,
512 ShrSVecI32x4,
513 ShrUVecI32x4,
514 ShlVecI64x2,
515 ShrSVecI64x2,
516 ShrUVecI64x2
517};
518
519enum SIMDLoadOp {
520 Load8SplatVec128,
521 Load16SplatVec128,
522 Load32SplatVec128,
523 Load64SplatVec128,
524 Load8x8SVec128,
525 Load8x8UVec128,
526 Load16x4SVec128,
527 Load16x4UVec128,
528 Load32x2SVec128,
529 Load32x2UVec128,
530 Load32ZeroVec128,
531 Load64ZeroVec128,
532};
533
534enum SIMDLoadStoreLaneOp {
535 Load8LaneVec128,
536 Load16LaneVec128,
537 Load32LaneVec128,
538 Load64LaneVec128,
539 Store8LaneVec128,
540 Store16LaneVec128,
541 Store32LaneVec128,
542 Store64LaneVec128,
543};
544
545enum SIMDTernaryOp {
546 Bitselect,
547
548 // Relaxed SIMD
549 RelaxedFmaVecF32x4,
550 RelaxedFmsVecF32x4,
551 RelaxedFmaVecF64x2,
552 RelaxedFmsVecF64x2,
553 LaneselectI8x16,
554 LaneselectI16x8,
555 LaneselectI32x4,
556 LaneselectI64x2,
557 DotI8x16I7x16AddSToVecI32x4,
558};
559
560enum RefAsOp {
561 RefAsNonNull,
562 ExternInternalize,
563 ExternExternalize,
564};
565
566enum BrOnOp {
567 BrOnNull,
568 BrOnNonNull,
569 BrOnCast,
570 BrOnCastFail,
571};
572
573enum StringNewOp {
574 // Linear memory
575 StringNewUTF8,
576 StringNewWTF8,
577 StringNewLossyUTF8,
578 StringNewWTF16,
579 // GC
580 StringNewUTF8Array,
581 StringNewWTF8Array,
582 StringNewLossyUTF8Array,
583 StringNewWTF16Array,
584 // Other
585 StringNewFromCodePoint,
586};
587
588enum StringMeasureOp {
589 StringMeasureUTF8,
590 StringMeasureWTF8,
591 StringMeasureWTF16,
592 StringMeasureIsUSV,
593 StringMeasureWTF16View,
594 StringMeasureHash,
595};
596
597enum StringEncodeOp {
598 StringEncodeUTF8,
599 StringEncodeLossyUTF8,
600 StringEncodeWTF8,
601 StringEncodeWTF16,
602 StringEncodeUTF8Array,
603 StringEncodeLossyUTF8Array,
604 StringEncodeWTF8Array,
605 StringEncodeWTF16Array,
606};
607
608enum StringEqOp {
609 StringEqEqual,
610 StringEqCompare,
611};
612
613enum StringAsOp {
614 StringAsWTF8,
615 StringAsWTF16,
616 StringAsIter,
617};
618
619enum StringIterMoveOp {
620 StringIterMoveAdvance,
621 StringIterMoveRewind,
622};
623
624enum StringSliceWTFOp {
625 StringSliceWTF8,
626 StringSliceWTF16,
627};
628
629//
630// Expressions
631//
632// Note that little is provided in terms of constructors for these. The
633// rationale is that writing `new Something(a, b, c, d, e)` is not the clearest,
634// and it would be better to write new `Something(name=a, leftOperand=b...`
635// etc., but C++ lacks named operands so you will see things like
636// auto x = new Something();
637// x->name = a;
638// x->leftOperand = b;
639// ..
640// which is less compact but less ambiguous. See wasm-builder.h for a more
641// friendly API for building nodes.
642//
643// Most nodes have no need of internal allocation, and when arena-allocated
644// they drop the provided arena on the floor. You can create random instances
645// of those that are not in an arena without issue. However, the nodes that
646// have internal allocation will need an allocator provided to them in order
647// to be constructed.
648
649class Expression {
650public:
651 enum Id {
652 InvalidId = 0,
653 BlockId,
654 IfId,
655 LoopId,
656 BreakId,
657 SwitchId,
658 CallId,
659 CallIndirectId,
660 LocalGetId,
661 LocalSetId,
662 GlobalGetId,
663 GlobalSetId,
664 LoadId,
665 StoreId,
666 ConstId,
667 UnaryId,
668 BinaryId,
669 SelectId,
670 DropId,
671 ReturnId,
672 MemorySizeId,
673 MemoryGrowId,
674 NopId,
675 UnreachableId,
676 AtomicRMWId,
677 AtomicCmpxchgId,
678 AtomicWaitId,
679 AtomicNotifyId,
680 AtomicFenceId,
681 SIMDExtractId,
682 SIMDReplaceId,
683 SIMDShuffleId,
684 SIMDTernaryId,
685 SIMDShiftId,
686 SIMDLoadId,
687 SIMDLoadStoreLaneId,
688 MemoryInitId,
689 DataDropId,
690 MemoryCopyId,
691 MemoryFillId,
692 PopId,
693 RefNullId,
694 RefIsNullId,
695 RefFuncId,
696 RefEqId,
697 TableGetId,
698 TableSetId,
699 TableSizeId,
700 TableGrowId,
701 TryId,
702 ThrowId,
703 RethrowId,
704 TupleMakeId,
705 TupleExtractId,
706 I31NewId,
707 I31GetId,
708 CallRefId,
709 RefTestId,
710 RefCastId,
711 BrOnId,
712 StructNewId,
713 StructGetId,
714 StructSetId,
715 ArrayNewId,
716 ArrayNewDataId,
717 ArrayNewElemId,
718 ArrayNewFixedId,
719 ArrayGetId,
720 ArraySetId,
721 ArrayLenId,
722 ArrayCopyId,
723 ArrayFillId,
724 ArrayInitDataId,
725 ArrayInitElemId,
726 RefAsId,
727 StringNewId,
728 StringConstId,
729 StringMeasureId,
730 StringEncodeId,
731 StringConcatId,
732 StringEqId,
733 StringAsId,
734 StringWTF8AdvanceId,
735 StringWTF16GetId,
736 StringIterNextId,
737 StringIterMoveId,
738 StringSliceWTFId,
739 StringSliceIterId,
740 NumExpressionIds
741 };
742 Id _id;
743
744 // the type of the expression: its *output*, not necessarily its input(s)
745 Type type = Type::none;
746
747 Expression(Id id) : _id(id) {}
748
749protected:
750 // An expression cannot be constructed without knowing what kind of expression
751 // it should be.
752 Expression(const Expression& other) = default;
753 Expression(Expression&& other) = default;
754 Expression& operator=(Expression& other) = default;
755 Expression& operator=(Expression&& other) = default;
756
757public:
758 void finalize() {}
759
760 template<class T> bool is() const {
761 static_assert(std::is_base_of<Expression, T>::value,
762 "Expression is not a base of destination type T");
763 return int(_id) == int(T::SpecificId);
764 }
765
766 template<class T> T* dynCast() {
767 static_assert(std::is_base_of<Expression, T>::value,
768 "Expression is not a base of destination type T");
769 return int(_id) == int(T::SpecificId) ? (T*)this : nullptr;
770 }
771
772 template<class T> const T* dynCast() const {
773 static_assert(std::is_base_of<Expression, T>::value,
774 "Expression is not a base of destination type T");
775 return int(_id) == int(T::SpecificId) ? (const T*)this : nullptr;
776 }
777
778 template<class T> T* cast() {
779 static_assert(std::is_base_of<Expression, T>::value,
780 "Expression is not a base of destination type T");
781 assert(int(_id) == int(T::SpecificId));
782 return (T*)this;
783 }
784
785 template<class T> const T* cast() const {
786 static_assert(std::is_base_of<Expression, T>::value,
787 "Expression is not a base of destination type T");
788 assert(int(_id) == int(T::SpecificId));
789 return (const T*)this;
790 }
791
792 // Print the expression to stderr. Meant for use while debugging.
793 void dump();
794};
795
796const char* getExpressionName(Expression* curr);
797
798Literal getLiteralFromConstExpression(Expression* curr);
799Literals getLiteralsFromConstExpression(Expression* curr);
800
801using ExpressionList = ArenaVector<Expression*>;
802
803template<Expression::Id SID> class SpecificExpression : public Expression {
804public:
805 enum {
806 SpecificId = SID // compile-time access to the type for the class
807 };
808
809 SpecificExpression() : Expression(SID) {}
810};
811
812class Nop : public SpecificExpression<Expression::NopId> {
813public:
814 Nop() = default;
815 Nop(MixedArena& allocator) {}
816};
817
818class Block : public SpecificExpression<Expression::BlockId> {
819public:
820 Block(MixedArena& allocator) : list(allocator) {}
821
822 Name name;
823 ExpressionList list;
824
825 // set the type purely based on its contents. this scans the block, so it is
826 // not fast.
827 void finalize();
828
829 // set the type given you know its type, which is the case when parsing
830 // s-expression or binary, as explicit types are given. the only additional
831 // work this does is to set the type to unreachable in the cases that is
832 // needed (which may require scanning the block)
833 void finalize(Type type_);
834
835 enum Breakability { Unknown, HasBreak, NoBreak };
836
837 // set the type given you know its type, and you know if there is a break to
838 // this block. this avoids the need to scan the contents of the block in the
839 // case that it might be unreachable, so it is recommended if you already know
840 // the type and breakability anyhow.
841 void finalize(Type type_, Breakability breakability);
842};
843
844class If : public SpecificExpression<Expression::IfId> {
845public:
846 If() : ifFalse(nullptr) {}
847 If(MixedArena& allocator) : If() {}
848
849 Expression* condition;
850 Expression* ifTrue;
851 Expression* ifFalse;
852
853 // set the type given you know its type, which is the case when parsing
854 // s-expression or binary, as explicit types are given. the only additional
855 // work this does is to set the type to unreachable in the cases that is
856 // needed.
857 void finalize(Type type_);
858
859 // set the type purely based on its contents.
860 void finalize();
861};
862
863class Loop : public SpecificExpression<Expression::LoopId> {
864public:
865 Loop() = default;
866 Loop(MixedArena& allocator) {}
867
868 Name name;
869 Expression* body;
870
871 // set the type given you know its type, which is the case when parsing
872 // s-expression or binary, as explicit types are given. the only additional
873 // work this does is to set the type to unreachable in the cases that is
874 // needed.
875 void finalize(Type type_);
876
877 // set the type purely based on its contents.
878 void finalize();
879};
880
881class Break : public SpecificExpression<Expression::BreakId> {
882public:
883 Break() : value(nullptr), condition(nullptr) {}
884 Break(MixedArena& allocator) : Break() { type = Type::unreachable; }
885
886 Name name;
887 Expression* value;
888 Expression* condition;
889
890 void finalize();
891};
892
893class Switch : public SpecificExpression<Expression::SwitchId> {
894public:
895 Switch(MixedArena& allocator) : targets(allocator) {
896 type = Type::unreachable;
897 }
898
899 ArenaVector<Name> targets;
900 Name default_;
901 Expression* value = nullptr;
902 Expression* condition = nullptr;
903
904 void finalize();
905};
906
907class Call : public SpecificExpression<Expression::CallId> {
908public:
909 Call(MixedArena& allocator) : operands(allocator) {}
910
911 ExpressionList operands;
912 Name target;
913 bool isReturn = false;
914
915 void finalize();
916};
917
918class CallIndirect : public SpecificExpression<Expression::CallIndirectId> {
919public:
920 CallIndirect(MixedArena& allocator) : operands(allocator) {}
921 HeapType heapType;
922 ExpressionList operands;
923 Expression* target;
924 Name table;
925 bool isReturn = false;
926
927 void finalize();
928};
929
930class LocalGet : public SpecificExpression<Expression::LocalGetId> {
931public:
932 LocalGet() = default;
933 LocalGet(MixedArena& allocator) {}
934
935 Index index;
936};
937
938class LocalSet : public SpecificExpression<Expression::LocalSetId> {
939public:
940 LocalSet() = default;
941 LocalSet(MixedArena& allocator) {}
942
943 void finalize();
944
945 Index index;
946 Expression* value;
947
948 bool isTee() const;
949 void makeTee(Type type);
950 void makeSet();
951};
952
953class GlobalGet : public SpecificExpression<Expression::GlobalGetId> {
954public:
955 GlobalGet() = default;
956 GlobalGet(MixedArena& allocator) {}
957
958 Name name;
959};
960
961class GlobalSet : public SpecificExpression<Expression::GlobalSetId> {
962public:
963 GlobalSet() = default;
964 GlobalSet(MixedArena& allocator) {}
965
966 Name name;
967 Expression* value;
968
969 void finalize();
970};
971
972class Load : public SpecificExpression<Expression::LoadId> {
973public:
974 Load() = default;
975 Load(MixedArena& allocator) {}
976
977 uint8_t bytes;
978 bool signed_ = false;
979 Address offset;
980 Address align;
981 bool isAtomic;
982 Expression* ptr;
983 Name memory;
984
985 // type must be set during creation, cannot be inferred
986
987 void finalize();
988};
989
990class Store : public SpecificExpression<Expression::StoreId> {
991public:
992 Store() = default;
993 Store(MixedArena& allocator) : Store() {}
994
995 uint8_t bytes;
996 Address offset;
997 Address align;
998 bool isAtomic;
999 Expression* ptr;
1000 Expression* value;
1001 Type valueType;
1002 Name memory;
1003
1004 void finalize();
1005};
1006
1007class AtomicRMW : public SpecificExpression<Expression::AtomicRMWId> {
1008public:
1009 AtomicRMW() = default;
1010 AtomicRMW(MixedArena& allocator) : AtomicRMW() {}
1011
1012 AtomicRMWOp op;
1013 uint8_t bytes;
1014 Address offset;
1015 Expression* ptr;
1016 Expression* value;
1017 Name memory;
1018
1019 void finalize();
1020};
1021
1022class AtomicCmpxchg : public SpecificExpression<Expression::AtomicCmpxchgId> {
1023public:
1024 AtomicCmpxchg() = default;
1025 AtomicCmpxchg(MixedArena& allocator) : AtomicCmpxchg() {}
1026
1027 uint8_t bytes;
1028 Address offset;
1029 Expression* ptr;
1030 Expression* expected;
1031 Expression* replacement;
1032 Name memory;
1033
1034 void finalize();
1035};
1036
1037class AtomicWait : public SpecificExpression<Expression::AtomicWaitId> {
1038public:
1039 AtomicWait() = default;
1040 AtomicWait(MixedArena& allocator) : AtomicWait() {}
1041
1042 Address offset;
1043 Expression* ptr;
1044 Expression* expected;
1045 Expression* timeout;
1046 Type expectedType;
1047 Name memory;
1048
1049 void finalize();
1050};
1051
1052class AtomicNotify : public SpecificExpression<Expression::AtomicNotifyId> {
1053public:
1054 AtomicNotify() = default;
1055 AtomicNotify(MixedArena& allocator) : AtomicNotify() {}
1056
1057 Address offset;
1058 Expression* ptr;
1059 Expression* notifyCount;
1060 Name memory;
1061
1062 void finalize();
1063};
1064
1065class AtomicFence : public SpecificExpression<Expression::AtomicFenceId> {
1066public:
1067 AtomicFence() = default;
1068 AtomicFence(MixedArena& allocator) : AtomicFence() {}
1069
1070 // Current wasm threads only supports sequentialy consistent atomics, but
1071 // other orderings may be added in the future. This field is reserved for
1072 // that, and currently set to 0.
1073 uint8_t order = 0;
1074
1075 void finalize();
1076};
1077
1078class SIMDExtract : public SpecificExpression<Expression::SIMDExtractId> {
1079public:
1080 SIMDExtract() = default;
1081 SIMDExtract(MixedArena& allocator) : SIMDExtract() {}
1082
1083 SIMDExtractOp op;
1084 Expression* vec;
1085 uint8_t index;
1086
1087 void finalize();
1088};
1089
1090class SIMDReplace : public SpecificExpression<Expression::SIMDReplaceId> {
1091public:
1092 SIMDReplace() = default;
1093 SIMDReplace(MixedArena& allocator) : SIMDReplace() {}
1094
1095 SIMDReplaceOp op;
1096 Expression* vec;
1097 uint8_t index;
1098 Expression* value;
1099
1100 void finalize();
1101};
1102
1103class SIMDShuffle : public SpecificExpression<Expression::SIMDShuffleId> {
1104public:
1105 SIMDShuffle() = default;
1106 SIMDShuffle(MixedArena& allocator) : SIMDShuffle() {}
1107
1108 Expression* left;
1109 Expression* right;
1110 std::array<uint8_t, 16> mask;
1111
1112 void finalize();
1113};
1114
1115class SIMDTernary : public SpecificExpression<Expression::SIMDTernaryId> {
1116public:
1117 SIMDTernary() = default;
1118 SIMDTernary(MixedArena& allocator) : SIMDTernary() {}
1119
1120 SIMDTernaryOp op;
1121 Expression* a;
1122 Expression* b;
1123 Expression* c;
1124
1125 void finalize();
1126};
1127
1128class SIMDShift : public SpecificExpression<Expression::SIMDShiftId> {
1129public:
1130 SIMDShift() = default;
1131 SIMDShift(MixedArena& allocator) : SIMDShift() {}
1132
1133 SIMDShiftOp op;
1134 Expression* vec;
1135 Expression* shift;
1136
1137 void finalize();
1138};
1139
1140class SIMDLoad : public SpecificExpression<Expression::SIMDLoadId> {
1141public:
1142 SIMDLoad() = default;
1143 SIMDLoad(MixedArena& allocator) {}
1144
1145 SIMDLoadOp op;
1146 Address offset;
1147 Address align;
1148 Expression* ptr;
1149 Name memory;
1150
1151 Index getMemBytes();
1152 void finalize();
1153};
1154
1155class SIMDLoadStoreLane
1156 : public SpecificExpression<Expression::SIMDLoadStoreLaneId> {
1157public:
1158 SIMDLoadStoreLane() = default;
1159 SIMDLoadStoreLane(MixedArena& allocator) {}
1160
1161 SIMDLoadStoreLaneOp op;
1162 Address offset;
1163 Address align;
1164 uint8_t index;
1165 Expression* ptr;
1166 Expression* vec;
1167 Name memory;
1168
1169 bool isStore();
1170 bool isLoad() { return !isStore(); }
1171 Index getMemBytes();
1172 void finalize();
1173};
1174
1175class MemoryInit : public SpecificExpression<Expression::MemoryInitId> {
1176public:
1177 MemoryInit() = default;
1178 MemoryInit(MixedArena& allocator) : MemoryInit() {}
1179
1180 Name segment;
1181 Expression* dest;
1182 Expression* offset;
1183 Expression* size;
1184 Name memory;
1185
1186 void finalize();
1187};
1188
1189class DataDrop : public SpecificExpression<Expression::DataDropId> {
1190public:
1191 DataDrop() = default;
1192 DataDrop(MixedArena& allocator) : DataDrop() {}
1193
1194 Name segment;
1195
1196 void finalize();
1197};
1198
1199class MemoryCopy : public SpecificExpression<Expression::MemoryCopyId> {
1200public:
1201 MemoryCopy() = default;
1202 MemoryCopy(MixedArena& allocator) : MemoryCopy() {}
1203
1204 Expression* dest;
1205 Expression* source;
1206 Expression* size;
1207 Name destMemory;
1208 Name sourceMemory;
1209
1210 void finalize();
1211};
1212
1213class MemoryFill : public SpecificExpression<Expression::MemoryFillId> {
1214public:
1215 MemoryFill() = default;
1216 MemoryFill(MixedArena& allocator) : MemoryFill() {}
1217
1218 Expression* dest;
1219 Expression* value;
1220 Expression* size;
1221 Name memory;
1222
1223 void finalize();
1224};
1225
1226class Const : public SpecificExpression<Expression::ConstId> {
1227public:
1228 Const() = default;
1229 Const(MixedArena& allocator) {}
1230
1231 Literal value;
1232
1233 Const* set(Literal value_);
1234
1235 void finalize();
1236};
1237
1238class Unary : public SpecificExpression<Expression::UnaryId> {
1239public:
1240 Unary() = default;
1241 Unary(MixedArena& allocator) {}
1242
1243 UnaryOp op;
1244 Expression* value;
1245
1246 bool isRelational();
1247
1248 void finalize();
1249};
1250
1251class Binary : public SpecificExpression<Expression::BinaryId> {
1252public:
1253 Binary() = default;
1254 Binary(MixedArena& allocator) {}
1255
1256 BinaryOp op;
1257 Expression* left;
1258 Expression* right;
1259
1260 // the type is always the type of the operands,
1261 // except for relationals
1262
1263 bool isRelational();
1264
1265 void finalize();
1266};
1267
1268class Select : public SpecificExpression<Expression::SelectId> {
1269public:
1270 Select() = default;
1271 Select(MixedArena& allocator) {}
1272
1273 Expression* ifTrue;
1274 Expression* ifFalse;
1275 Expression* condition;
1276
1277 void finalize();
1278 void finalize(Type type_);
1279};
1280
1281class Drop : public SpecificExpression<Expression::DropId> {
1282public:
1283 Drop() = default;
1284 Drop(MixedArena& allocator) {}
1285
1286 Expression* value;
1287
1288 void finalize();
1289};
1290
1291class Return : public SpecificExpression<Expression::ReturnId> {
1292public:
1293 Return() { type = Type::unreachable; }
1294 Return(MixedArena& allocator) : Return() {}
1295
1296 Expression* value = nullptr;
1297};
1298
1299class MemorySize : public SpecificExpression<Expression::MemorySizeId> {
1300public:
1301 MemorySize() { type = Type::i32; }
1302 MemorySize(MixedArena& allocator) : MemorySize() {}
1303
1304 Type ptrType = Type::i32;
1305 Name memory;
1306
1307 void make64();
1308 void finalize();
1309};
1310
1311class MemoryGrow : public SpecificExpression<Expression::MemoryGrowId> {
1312public:
1313 MemoryGrow() { type = Type::i32; }
1314 MemoryGrow(MixedArena& allocator) : MemoryGrow() {}
1315
1316 Expression* delta = nullptr;
1317 Type ptrType = Type::i32;
1318 Name memory;
1319
1320 void make64();
1321 void finalize();
1322};
1323
1324class Unreachable : public SpecificExpression<Expression::UnreachableId> {
1325public:
1326 Unreachable() { type = Type::unreachable; }
1327 Unreachable(MixedArena& allocator) : Unreachable() {}
1328};
1329
1330// Represents a pop of a value that arrives as an implicit argument to the
1331// current block. Currently used in exception handling.
1332class Pop : public SpecificExpression<Expression::PopId> {
1333public:
1334 Pop() = default;
1335 Pop(MixedArena& allocator) {}
1336};
1337
1338class RefNull : public SpecificExpression<Expression::RefNullId> {
1339public:
1340 RefNull() = default;
1341 RefNull(MixedArena& allocator) {}
1342
1343 void finalize();
1344 void finalize(HeapType heapType);
1345 void finalize(Type type);
1346};
1347
1348class RefIsNull : public SpecificExpression<Expression::RefIsNullId> {
1349public:
1350 RefIsNull(MixedArena& allocator) {}
1351
1352 Expression* value;
1353
1354 void finalize();
1355};
1356
1357class RefFunc : public SpecificExpression<Expression::RefFuncId> {
1358public:
1359 RefFunc(MixedArena& allocator) {}
1360
1361 Name func;
1362
1363 void finalize();
1364 void finalize(Type type_);
1365};
1366
1367class RefEq : public SpecificExpression<Expression::RefEqId> {
1368public:
1369 RefEq(MixedArena& allocator) {}
1370
1371 Expression* left;
1372 Expression* right;
1373
1374 void finalize();
1375};
1376
1377class TableGet : public SpecificExpression<Expression::TableGetId> {
1378public:
1379 TableGet(MixedArena& allocator) {}
1380
1381 Name table;
1382
1383 Expression* index;
1384
1385 void finalize();
1386};
1387
1388class TableSet : public SpecificExpression<Expression::TableSetId> {
1389public:
1390 TableSet(MixedArena& allocator) {}
1391
1392 Name table;
1393
1394 Expression* index;
1395 Expression* value;
1396
1397 void finalize();
1398};
1399
1400class TableSize : public SpecificExpression<Expression::TableSizeId> {
1401public:
1402 TableSize() { type = Type::i32; }
1403 TableSize(MixedArena& allocator) : TableSize() {}
1404
1405 Name table;
1406
1407 void finalize();
1408};
1409
1410class TableGrow : public SpecificExpression<Expression::TableGrowId> {
1411public:
1412 TableGrow() { type = Type::i32; }
1413 TableGrow(MixedArena& allocator) : TableGrow() {}
1414
1415 Name table;
1416 Expression* value;
1417 Expression* delta;
1418
1419 void finalize();
1420};
1421
1422class Try : public SpecificExpression<Expression::TryId> {
1423public:
1424 Try(MixedArena& allocator) : catchTags(allocator), catchBodies(allocator) {}
1425
1426 Name name; // label that can only be targeted by 'delegate's
1427 Expression* body;
1428 ArenaVector<Name> catchTags;
1429 ExpressionList catchBodies;
1430 Name delegateTarget; // target try's label
1431
1432 bool hasCatchAll() const {
1433 return catchBodies.size() - catchTags.size() == 1;
1434 }
1435 bool isCatch() const { return !catchBodies.empty(); }
1436 bool isDelegate() const { return delegateTarget.is(); }
1437 void finalize();
1438 void finalize(Type type_);
1439};
1440
1441class Throw : public SpecificExpression<Expression::ThrowId> {
1442public:
1443 Throw(MixedArena& allocator) : operands(allocator) {}
1444
1445 Name tag;
1446 ExpressionList operands;
1447
1448 void finalize();
1449};
1450
1451class Rethrow : public SpecificExpression<Expression::RethrowId> {
1452public:
1453 Rethrow(MixedArena& allocator) {}
1454
1455 Name target;
1456
1457 void finalize();
1458};
1459
1460class TupleMake : public SpecificExpression<Expression::TupleMakeId> {
1461public:
1462 TupleMake(MixedArena& allocator) : operands(allocator) {}
1463
1464 ExpressionList operands;
1465
1466 void finalize();
1467};
1468
1469class TupleExtract : public SpecificExpression<Expression::TupleExtractId> {
1470public:
1471 TupleExtract(MixedArena& allocator) {}
1472
1473 Expression* tuple;
1474 Index index;
1475
1476 void finalize();
1477};
1478
1479class I31New : public SpecificExpression<Expression::I31NewId> {
1480public:
1481 I31New(MixedArena& allocator) {}
1482
1483 Expression* value;
1484
1485 void finalize();
1486};
1487
1488class I31Get : public SpecificExpression<Expression::I31GetId> {
1489public:
1490 I31Get(MixedArena& allocator) {}
1491
1492 Expression* i31;
1493 bool signed_ = false;
1494
1495 void finalize();
1496};
1497
1498class CallRef : public SpecificExpression<Expression::CallRefId> {
1499public:
1500 CallRef(MixedArena& allocator) : operands(allocator) {}
1501 ExpressionList operands;
1502 Expression* target;
1503 bool isReturn = false;
1504
1505 void finalize();
1506 void finalize(Type type_);
1507};
1508
1509class RefTest : public SpecificExpression<Expression::RefTestId> {
1510public:
1511 RefTest(MixedArena& allocator) {}
1512
1513 Expression* ref;
1514
1515 Type castType;
1516
1517 void finalize();
1518
1519 Type& getCastType() { return castType; }
1520};
1521
1522class RefCast : public SpecificExpression<Expression::RefCastId> {
1523public:
1524 RefCast(MixedArena& allocator) {}
1525
1526 Expression* ref;
1527
1528 // Support the unsafe `ref.cast_nop_static` to enable precise cast overhead
1529 // measurements.
1530 enum Safety { Safe, Unsafe };
1531 Safety safety = Safe;
1532
1533 void finalize();
1534
1535 Type& getCastType() { return type; }
1536};
1537
1538class BrOn : public SpecificExpression<Expression::BrOnId> {
1539public:
1540 BrOn(MixedArena& allocator) {}
1541
1542 BrOnOp op;
1543 Name name;
1544 Expression* ref;
1545 Type castType;
1546
1547 void finalize();
1548
1549 Type& getCastType() { return castType; }
1550
1551 // Returns the type sent on the branch, if it is taken.
1552 Type getSentType();
1553};
1554
1555class StructNew : public SpecificExpression<Expression::StructNewId> {
1556public:
1557 StructNew(MixedArena& allocator) : operands(allocator) {}
1558
1559 // A struct.new_with_default has empty operands. This does leave the case of a
1560 // struct with no fields ambiguous, but it doesn't make a difference in that
1561 // case, and binaryen doesn't guarantee roundtripping binaries anyhow.
1562 ExpressionList operands;
1563
1564 bool isWithDefault() { return operands.empty(); }
1565
1566 void finalize();
1567};
1568
1569class StructGet : public SpecificExpression<Expression::StructGetId> {
1570public:
1571 StructGet(MixedArena& allocator) {}
1572
1573 Index index;
1574 Expression* ref;
1575 // Packed fields have a sign.
1576 bool signed_ = false;
1577
1578 void finalize();
1579};
1580
1581class StructSet : public SpecificExpression<Expression::StructSetId> {
1582public:
1583 StructSet(MixedArena& allocator) {}
1584
1585 Index index;
1586 Expression* ref;
1587 Expression* value;
1588
1589 void finalize();
1590};
1591
1592class ArrayNew : public SpecificExpression<Expression::ArrayNewId> {
1593public:
1594 ArrayNew(MixedArena& allocator) {}
1595
1596 // If set, then the initial value is assigned to all entries in the array. If
1597 // not set, this is array.new_with_default and the default of the type is
1598 // used.
1599 Expression* init = nullptr;
1600 Expression* size;
1601
1602 bool isWithDefault() { return !init; }
1603
1604 void finalize();
1605};
1606
1607class ArrayNewData : public SpecificExpression<Expression::ArrayNewDataId> {
1608public:
1609 ArrayNewData(MixedArena& allocator) {}
1610
1611 Name segment;
1612 Expression* offset;
1613 Expression* size;
1614
1615 void finalize();
1616};
1617
1618class ArrayNewElem : public SpecificExpression<Expression::ArrayNewElemId> {
1619public:
1620 ArrayNewElem(MixedArena& allocator) {}
1621
1622 Name segment;
1623 Expression* offset;
1624 Expression* size;
1625
1626 void finalize();
1627};
1628
1629class ArrayNewFixed : public SpecificExpression<Expression::ArrayNewFixedId> {
1630public:
1631 ArrayNewFixed(MixedArena& allocator) : values(allocator) {}
1632
1633 ExpressionList values;
1634
1635 void finalize();
1636};
1637
1638class ArrayGet : public SpecificExpression<Expression::ArrayGetId> {
1639public:
1640 ArrayGet(MixedArena& allocator) {}
1641
1642 Expression* ref;
1643 Expression* index;
1644 // Packed fields have a sign.
1645 bool signed_ = false;
1646
1647 void finalize();
1648};
1649
1650class ArraySet : public SpecificExpression<Expression::ArraySetId> {
1651public:
1652 ArraySet(MixedArena& allocator) {}
1653
1654 Expression* ref;
1655 Expression* index;
1656 Expression* value;
1657
1658 void finalize();
1659};
1660
1661class ArrayLen : public SpecificExpression<Expression::ArrayLenId> {
1662public:
1663 ArrayLen(MixedArena& allocator) {}
1664
1665 Expression* ref;
1666
1667 void finalize();
1668};
1669
1670class ArrayCopy : public SpecificExpression<Expression::ArrayCopyId> {
1671public:
1672 ArrayCopy(MixedArena& allocator) {}
1673
1674 Expression* destRef;
1675 Expression* destIndex;
1676 Expression* srcRef;
1677 Expression* srcIndex;
1678 Expression* length;
1679
1680 void finalize();
1681};
1682
1683class ArrayFill : public SpecificExpression<Expression::ArrayFillId> {
1684public:
1685 ArrayFill(MixedArena& allocator) {}
1686
1687 Expression* ref;
1688 Expression* index;
1689 Expression* value;
1690 Expression* size;
1691
1692 void finalize();
1693};
1694
1695class ArrayInitData : public SpecificExpression<Expression::ArrayInitDataId> {
1696public:
1697 ArrayInitData(MixedArena& allocator) {}
1698
1699 Name segment;
1700 Expression* ref;
1701 Expression* index;
1702 Expression* offset;
1703 Expression* size;
1704
1705 void finalize();
1706};
1707
1708class ArrayInitElem : public SpecificExpression<Expression::ArrayInitElemId> {
1709public:
1710 ArrayInitElem(MixedArena& allocator) {}
1711
1712 Name segment;
1713 Expression* ref;
1714 Expression* index;
1715 Expression* offset;
1716 Expression* size;
1717
1718 void finalize();
1719};
1720
1721class RefAs : public SpecificExpression<Expression::RefAsId> {
1722public:
1723 RefAs(MixedArena& allocator) {}
1724
1725 RefAsOp op;
1726
1727 Expression* value;
1728
1729 void finalize();
1730};
1731
1732class StringNew : public SpecificExpression<Expression::StringNewId> {
1733public:
1734 StringNew(MixedArena& allocator) {}
1735
1736 StringNewOp op;
1737
1738 // In linear memory variations this is the pointer in linear memory. In the
1739 // GC variations this is an Array. In from_codepoint this is the code point.
1740 Expression* ptr;
1741
1742 // Used only in linear memory variations.
1743 Expression* length = nullptr;
1744
1745 // Used only in GC variations.
1746 Expression* start = nullptr;
1747 Expression* end = nullptr;
1748
1749 // The "try" variants will return null if an encoding error happens, rather
1750 // than trap.
1751 bool try_ = false;
1752
1753 void finalize();
1754};
1755
1756class StringConst : public SpecificExpression<Expression::StringConstId> {
1757public:
1758 StringConst(MixedArena& allocator) {}
1759
1760 // TODO: Use a different type to allow null bytes in the middle -
1761 // ArenaVector<char> perhaps? However, Name has the benefit of being
1762 // interned and immutable (which is appropriate here).
1763 Name string;
1764
1765 void finalize();
1766};
1767
1768class StringMeasure : public SpecificExpression<Expression::StringMeasureId> {
1769public:
1770 StringMeasure(MixedArena& allocator) {}
1771
1772 StringMeasureOp op;
1773
1774 Expression* ref;
1775
1776 void finalize();
1777};
1778
1779class StringEncode : public SpecificExpression<Expression::StringEncodeId> {
1780public:
1781 StringEncode(MixedArena& allocator) {}
1782
1783 StringEncodeOp op;
1784
1785 Expression* ref;
1786
1787 // In linear memory variations this is the pointer in linear memory. In the
1788 // GC variations this is an Array.
1789 Expression* ptr;
1790
1791 // Used only in GC variations, where it is the index in |ptr| to start
1792 // encoding from.
1793 Expression* start = nullptr;
1794
1795 void finalize();
1796};
1797
1798class StringConcat : public SpecificExpression<Expression::StringConcatId> {
1799public:
1800 StringConcat(MixedArena& allocator) {}
1801
1802 Expression* left;
1803 Expression* right;
1804
1805 void finalize();
1806};
1807
1808class StringEq : public SpecificExpression<Expression::StringEqId> {
1809public:
1810 StringEq(MixedArena& allocator) {}
1811
1812 StringEqOp op;
1813
1814 Expression* left;
1815 Expression* right;
1816
1817 void finalize();
1818};
1819
1820class StringAs : public SpecificExpression<Expression::StringAsId> {
1821public:
1822 StringAs(MixedArena& allocator) {}
1823
1824 StringAsOp op;
1825
1826 Expression* ref;
1827
1828 void finalize();
1829};
1830
1831class StringWTF8Advance
1832 : public SpecificExpression<Expression::StringWTF8AdvanceId> {
1833public:
1834 StringWTF8Advance(MixedArena& allocator) {}
1835
1836 Expression* ref;
1837 Expression* pos;
1838 Expression* bytes;
1839
1840 void finalize();
1841};
1842
1843class StringWTF16Get : public SpecificExpression<Expression::StringWTF16GetId> {
1844public:
1845 StringWTF16Get(MixedArena& allocator) {}
1846
1847 Expression* ref;
1848 Expression* pos;
1849
1850 void finalize();
1851};
1852
1853class StringIterNext : public SpecificExpression<Expression::StringIterNextId> {
1854public:
1855 StringIterNext(MixedArena& allocator) {}
1856
1857 Expression* ref;
1858
1859 void finalize();
1860};
1861
1862class StringIterMove : public SpecificExpression<Expression::StringIterMoveId> {
1863public:
1864 StringIterMove(MixedArena& allocator) {}
1865
1866 // Whether the movement is to advance or reverse.
1867 StringIterMoveOp op;
1868
1869 Expression* ref;
1870
1871 // How many codepoints to advance or reverse.
1872 Expression* num;
1873
1874 void finalize();
1875};
1876
1877class StringSliceWTF : public SpecificExpression<Expression::StringSliceWTFId> {
1878public:
1879 StringSliceWTF(MixedArena& allocator) {}
1880
1881 StringSliceWTFOp op;
1882
1883 Expression* ref;
1884 Expression* start;
1885 Expression* end;
1886
1887 void finalize();
1888};
1889
1890class StringSliceIter
1891 : public SpecificExpression<Expression::StringSliceIterId> {
1892public:
1893 StringSliceIter(MixedArena& allocator) {}
1894
1895 Expression* ref;
1896 Expression* num;
1897
1898 void finalize();
1899};
1900
1901// Globals
1902
1903struct Named {
1904 Name name;
1905
1906 // Explicit names are ones that we read from the input file and
1907 // will be written the name section in the output file.
1908 // Implicit names are names that binaryen generated for internal
1909 // use only and will not be written the name section.
1910 bool hasExplicitName = false;
1911
1912 void setName(Name name_, bool hasExplicitName_) {
1913 name = name_;
1914 hasExplicitName = hasExplicitName_;
1915 }
1916
1917 void setExplicitName(Name name_) { setName(name_, hasExplicitName_: true); }
1918};
1919
1920struct Importable : Named {
1921 // If these are set, then this is an import, as module.base
1922 Name module, base;
1923
1924 bool imported() const { return module.is(); }
1925};
1926
1927class Function;
1928
1929// Represents an offset into a wasm binary file. This is used for debug info.
1930// For now, assume this is 32 bits as that's the size limit of wasm files
1931// anyhow.
1932using BinaryLocation = uint32_t;
1933
1934// Represents a mapping of wasm module elements to their location in the
1935// binary representation. This is used for general debugging info support.
1936// Offsets are relative to the beginning of the code section, as in DWARF.
1937struct BinaryLocations {
1938 struct Span {
1939 BinaryLocation start = 0, end = 0;
1940 };
1941
1942 // Track the range of addresses an expressions appears at. This is the
1943 // contiguous range that all instructions have - control flow instructions
1944 // have additional opcodes later (like an end for a block or loop), see
1945 // just after this.
1946 std::unordered_map<Expression*, Span> expressions;
1947
1948 // Track the extra delimiter positions that some instructions, in particular
1949 // control flow, have, like 'end' for loop and block. We keep these in a
1950 // separate map because they are rare and we optimize for the storage space
1951 // for the common type of instruction which just needs a Span.
1952 // For "else" (from an if) we use index 0, and for catch (from a try) we use
1953 // indexes 0 and above.
1954 // We use automatic zero-initialization here because that indicates a "null"
1955 // debug value, indicating the information is not present.
1956 using DelimiterLocations = ZeroInitSmallVector<BinaryLocation, 1>;
1957
1958 enum DelimiterId : size_t { Else = 0, Invalid = size_t(-1) };
1959
1960 std::unordered_map<Expression*, DelimiterLocations> delimiters;
1961
1962 // DWARF debug info can refer to multiple interesting positions in a function.
1963 struct FunctionLocations {
1964 // The very start of the function, where the binary has a size LEB.
1965 BinaryLocation start = 0;
1966 // The area where we declare locals, which is right after the size LEB.
1967 BinaryLocation declarations = 0;
1968 // The end, which is one past the final "end" instruction byte.
1969 BinaryLocation end = 0;
1970 };
1971
1972 std::unordered_map<Function*, FunctionLocations> functions;
1973};
1974
1975// Forward declarations of Stack IR, as functions can contain it, see
1976// the stackIR property.
1977// Stack IR is a secondary IR to the main IR defined in this file (Binaryen
1978// IR). See wasm-stack.h.
1979class StackInst;
1980
1981using StackIR = std::vector<StackInst*>;
1982
1983class Function : public Importable {
1984public:
1985 HeapType type = HeapType(Signature()); // parameters and return value
1986 IRProfile profile = IRProfile::Normal;
1987 std::vector<Type> vars; // non-param locals
1988
1989 // The body of the function
1990 Expression* body = nullptr;
1991
1992 // If present, this stack IR was generated from the main Binaryen IR body,
1993 // and possibly optimized. If it is present when writing to wasm binary,
1994 // it will be emitted instead of the main Binaryen IR.
1995 //
1996 // Note that no special care is taken to synchronize the two IRs - if you
1997 // emit stack IR and then optimize the main IR, you need to recompute the
1998 // stack IR. The Pass system will throw away Stack IR if a pass is run
1999 // that declares it may modify Binaryen IR.
2000 std::unique_ptr<StackIR> stackIR;
2001
2002 // local names. these are optional.
2003 std::unordered_map<Index, Name> localNames;
2004 std::unordered_map<Name, Index> localIndices;
2005
2006 // Source maps debugging info: map expression nodes to their file, line, col.
2007 struct DebugLocation {
2008 BinaryLocation fileIndex, lineNumber, columnNumber;
2009 bool operator==(const DebugLocation& other) const {
2010 return fileIndex == other.fileIndex && lineNumber == other.lineNumber &&
2011 columnNumber == other.columnNumber;
2012 }
2013 bool operator!=(const DebugLocation& other) const {
2014 return !(*this == other);
2015 }
2016 bool operator<(const DebugLocation& other) const {
2017 return fileIndex != other.fileIndex
2018 ? fileIndex < other.fileIndex
2019 : lineNumber != other.lineNumber
2020 ? lineNumber < other.lineNumber
2021 : columnNumber < other.columnNumber;
2022 }
2023 };
2024 std::unordered_map<Expression*, DebugLocation> debugLocations;
2025 std::set<DebugLocation> prologLocation;
2026 std::set<DebugLocation> epilogLocation;
2027
2028 // General debugging info support: track instructions and the function itself.
2029 std::unordered_map<Expression*, BinaryLocations::Span> expressionLocations;
2030 std::unordered_map<Expression*, BinaryLocations::DelimiterLocations>
2031 delimiterLocations;
2032 BinaryLocations::FunctionLocations funcLocation;
2033
2034 Signature getSig() { return type.getSignature(); }
2035 Type getParams() { return getSig().params; }
2036 Type getResults() { return getSig().results; }
2037 void setParams(Type params) { type = Signature(params, getResults()); }
2038 void setResults(Type results) { type = Signature(getParams(), results); }
2039
2040 size_t getNumParams();
2041 size_t getNumVars();
2042 size_t getNumLocals();
2043
2044 bool isParam(Index index);
2045 bool isVar(Index index);
2046
2047 Name getLocalName(Index index);
2048 Index getLocalIndex(Name name);
2049 bool hasLocalIndex(Name name) const;
2050 Index getVarIndexBase();
2051 Type getLocalType(Index index);
2052
2053 Name getLocalNameOrDefault(Index index);
2054 Name getLocalNameOrGeneric(Index index);
2055
2056 bool hasLocalName(Index index) const;
2057 void setLocalName(Index index, Name name);
2058
2059 void clearNames();
2060 void clearDebugInfo();
2061};
2062
2063// The kind of an import or export.
2064enum class ExternalKind {
2065 Function = 0,
2066 Table = 1,
2067 Memory = 2,
2068 Global = 3,
2069 Tag = 4,
2070 Invalid = -1
2071};
2072
2073// The kind of a top-level module item. (This overlaps with ExternalKind, but
2074// C++ has no good way to extend an enum.) All such items are referred to by
2075// name in the IR (that is, the IR is relocatable), and so they are subclasses
2076// of the Named class.
2077enum class ModuleItemKind {
2078 Function = 0,
2079 Table = 1,
2080 Memory = 2,
2081 Global = 3,
2082 Tag = 4,
2083 DataSegment = 5,
2084 ElementSegment = 6,
2085 Invalid = -1
2086};
2087
2088class Export {
2089public:
2090 // exported name - note that this is the key, as the internal name is
2091 // non-unique (can have multiple exports for an internal, also over kinds)
2092 Name name;
2093 Name value; // internal name
2094 ExternalKind kind;
2095};
2096
2097class ElementSegment : public Named {
2098public:
2099 Name table;
2100 Expression* offset = nullptr;
2101 Type type = Type(HeapType::func, Nullable);
2102 std::vector<Expression*> data;
2103
2104 ElementSegment() = default;
2105 ElementSegment(Name table,
2106 Expression* offset,
2107 Type type = Type(HeapType::func, Nullable))
2108 : table(table), offset(offset), type(type) {}
2109 ElementSegment(Name table,
2110 Expression* offset,
2111 Type type,
2112 std::vector<Expression*>& init)
2113 : table(table), offset(offset), type(type) {
2114 data.swap(init);
2115 }
2116};
2117
2118class Table : public Importable {
2119public:
2120 static const Address::address32_t kPageSize = 1;
2121 static const Index kUnlimitedSize = Index(-1);
2122 // In wasm32/64, the maximum table size is limited by a 32-bit pointer: 4GB
2123 static const Index kMaxSize = Index(-1);
2124
2125 Address initial = 0;
2126 Address max = kMaxSize;
2127 Type type = Type(HeapType::func, Nullable);
2128
2129 bool hasMax() { return max != kUnlimitedSize; }
2130 void clear() {
2131 name = "";
2132 initial = 0;
2133 max = kMaxSize;
2134 }
2135};
2136
2137class DataSegment : public Named {
2138public:
2139 Name memory;
2140 bool isPassive = false;
2141 Expression* offset = nullptr;
2142 std::vector<char> data; // TODO: optimize
2143};
2144
2145class Memory : public Importable {
2146public:
2147 static const Address::address32_t kPageSize = 64 * 1024;
2148 static const Address::address64_t kUnlimitedSize = Address::address64_t(-1);
2149 // In wasm32, the maximum memory size is limited by a 32-bit pointer: 4GB
2150 static const Address::address32_t kMaxSize32 =
2151 (uint64_t(4) * 1024 * 1024 * 1024) / kPageSize;
2152 // in wasm64, the maximum number of pages
2153 static const Address::address64_t kMaxSize64 = 1ull << (64 - 16);
2154
2155 Address initial = 0; // sizes are in pages
2156 Address max = kMaxSize32;
2157
2158 bool shared = false;
2159 Type indexType = Type::i32;
2160
2161 bool hasMax() { return max != kUnlimitedSize; }
2162 bool is64() { return indexType == Type::i64; }
2163 void clear() {
2164 name = "";
2165 initial = 0;
2166 max = kMaxSize32;
2167 shared = false;
2168 indexType = Type::i32;
2169 }
2170};
2171
2172class Global : public Importable {
2173public:
2174 Type type;
2175 Expression* init = nullptr;
2176 bool mutable_ = false;
2177};
2178
2179class Tag : public Importable {
2180public:
2181 Signature sig;
2182};
2183
2184// "Opaque" data, not part of the core wasm spec, that is held in binaries.
2185// May be parsed/handled by utility code elsewhere, but not in wasm.h
2186class CustomSection {
2187public:
2188 std::string name;
2189 std::vector<char> data;
2190};
2191
2192// The optional "dylink" section is used in dynamic linking.
2193class DylinkSection {
2194public:
2195 bool isLegacy = false;
2196 Index memorySize, memoryAlignment, tableSize, tableAlignment;
2197 std::vector<Name> neededDynlibs;
2198 std::vector<char> tail;
2199};
2200
2201class Module {
2202public:
2203 // wasm contents (generally you shouldn't access these from outside, except
2204 // maybe for iterating; use add*() and the get() functions)
2205 std::vector<std::unique_ptr<Export>> exports;
2206 std::vector<std::unique_ptr<Function>> functions;
2207 std::vector<std::unique_ptr<Global>> globals;
2208 std::vector<std::unique_ptr<Tag>> tags;
2209 std::vector<std::unique_ptr<ElementSegment>> elementSegments;
2210 std::vector<std::unique_ptr<Memory>> memories;
2211 std::vector<std::unique_ptr<DataSegment>> dataSegments;
2212 std::vector<std::unique_ptr<Table>> tables;
2213
2214 Name start;
2215
2216 std::vector<CustomSection> customSections;
2217
2218 // Optional user section IR representation.
2219 std::unique_ptr<DylinkSection> dylinkSection;
2220
2221 // Source maps debug info.
2222 std::vector<std::string> debugInfoFileNames;
2223
2224 // `features` are the features allowed to be used in this module and should be
2225 // respected regardless of the value of`hasFeaturesSection`.
2226 // `hasFeaturesSection` means we read a features section and will emit one
2227 // too.
2228 FeatureSet features = FeatureSet::MVP;
2229 bool hasFeaturesSection = false;
2230
2231 // Module name, if specified. Serves a documentary role only.
2232 Name name;
2233
2234 std::unordered_map<HeapType, TypeNames> typeNames;
2235
2236 MixedArena allocator;
2237
2238private:
2239 // TODO: add a build option where Names are just indices, and then these
2240 // methods are not needed
2241 // exports map is by the *exported* name, which is unique
2242 std::unordered_map<Name, Export*> exportsMap;
2243 std::unordered_map<Name, Function*> functionsMap;
2244 std::unordered_map<Name, Table*> tablesMap;
2245 std::unordered_map<Name, Memory*> memoriesMap;
2246 std::unordered_map<Name, ElementSegment*> elementSegmentsMap;
2247 std::unordered_map<Name, DataSegment*> dataSegmentsMap;
2248 std::unordered_map<Name, Global*> globalsMap;
2249 std::unordered_map<Name, Tag*> tagsMap;
2250
2251public:
2252 Module() = default;
2253
2254 Export* getExport(Name name);
2255 Function* getFunction(Name name);
2256 Table* getTable(Name name);
2257 ElementSegment* getElementSegment(Name name);
2258 Memory* getMemory(Name name);
2259 DataSegment* getDataSegment(Name name);
2260 Global* getGlobal(Name name);
2261 Tag* getTag(Name name);
2262
2263 Export* getExportOrNull(Name name);
2264 Table* getTableOrNull(Name name);
2265 Memory* getMemoryOrNull(Name name);
2266 ElementSegment* getElementSegmentOrNull(Name name);
2267 DataSegment* getDataSegmentOrNull(Name name);
2268 Function* getFunctionOrNull(Name name);
2269 Global* getGlobalOrNull(Name name);
2270 Tag* getTagOrNull(Name name);
2271
2272 Export* addExport(Export* curr);
2273 Function* addFunction(Function* curr);
2274 Global* addGlobal(Global* curr);
2275 Tag* addTag(Tag* curr);
2276
2277 Export* addExport(std::unique_ptr<Export>&& curr);
2278 Function* addFunction(std::unique_ptr<Function>&& curr);
2279 Table* addTable(std::unique_ptr<Table>&& curr);
2280 ElementSegment* addElementSegment(std::unique_ptr<ElementSegment>&& curr);
2281 Memory* addMemory(std::unique_ptr<Memory>&& curr);
2282 DataSegment* addDataSegment(std::unique_ptr<DataSegment>&& curr);
2283 Global* addGlobal(std::unique_ptr<Global>&& curr);
2284 Tag* addTag(std::unique_ptr<Tag>&& curr);
2285
2286 void addStart(const Name& s);
2287
2288 void removeExport(Name name);
2289 void removeFunction(Name name);
2290 void removeTable(Name name);
2291 void removeElementSegment(Name name);
2292 void removeMemory(Name name);
2293 void removeDataSegment(Name name);
2294 void removeGlobal(Name name);
2295 void removeTag(Name name);
2296
2297 void removeExports(std::function<bool(Export*)> pred);
2298 void removeFunctions(std::function<bool(Function*)> pred);
2299 void removeTables(std::function<bool(Table*)> pred);
2300 void removeElementSegments(std::function<bool(ElementSegment*)> pred);
2301 void removeMemories(std::function<bool(Memory*)> pred);
2302 void removeDataSegments(std::function<bool(DataSegment*)> pred);
2303 void removeGlobals(std::function<bool(Global*)> pred);
2304 void removeTags(std::function<bool(Tag*)> pred);
2305
2306 void updateFunctionsMap();
2307 void updateDataSegmentsMap();
2308 void updateMaps();
2309
2310 void clearDebugInfo();
2311};
2312
2313// Utility for printing an expression with named types.
2314using ModuleExpression = std::pair<Module&, Expression*>;
2315
2316// Utility for printing only the top level of an expression. Named types will be
2317// used if `module` is non-null.
2318struct ShallowExpression {
2319 Expression* expr;
2320 Module* module = nullptr;
2321};
2322
2323} // namespace wasm
2324
2325namespace std {
2326template<> struct hash<wasm::Address> {
2327 size_t operator()(const wasm::Address a) const {
2328 return std::hash<wasm::Address::address64_t>()(a.addr);
2329 }
2330};
2331
2332std::ostream& operator<<(std::ostream& o, wasm::Module& module);
2333std::ostream& operator<<(std::ostream& o, wasm::Expression& expression);
2334std::ostream& operator<<(std::ostream& o, wasm::ModuleExpression pair);
2335std::ostream& operator<<(std::ostream& o, wasm::ShallowExpression expression);
2336std::ostream& operator<<(std::ostream& o, wasm::StackInst& inst);
2337std::ostream& operator<<(std::ostream& o, wasm::StackIR& ir);
2338
2339} // namespace std
2340
2341#endif // wasm_wasm_h
2342

source code of dart_sdk/third_party/binaryen/src/src/wasm.h