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 <string>
32 #include <vector>
33 
34 #include "literal.h"
35 #include "mixed_arena.h"
36 #include "support/name.h"
37 #include "wasm-features.h"
38 #include "wasm-type.h"
39 
40 namespace wasm {
41 
42 // An index in a wasm module
43 typedef uint32_t Index;
44 
45 // An address in linear memory.
46 struct Address {
47   typedef uint32_t address32_t;
48   typedef uint64_t address64_t;
49   address64_t addr;
AddressAddress50   Address() : addr(0) {}
AddressAddress51   Address(uint64_t a) : addr(a) {}
52   Address& operator=(uint64_t a) {
53     addr = a;
54     return *this;
55   }
address64_tAddress56   operator address64_t() const { return addr; }
57   Address& operator++() {
58     ++addr;
59     return *this;
60   }
61 };
62 
63 enum class IRProfile { Normal, Poppy };
64 
65 // Operators
66 
67 enum UnaryOp {
68   // int
69   ClzInt32,
70   ClzInt64,
71   CtzInt32,
72   CtzInt64,
73   PopcntInt32,
74   PopcntInt64,
75 
76   // float
77   NegFloat32,
78   NegFloat64,
79   AbsFloat32,
80   AbsFloat64,
81   CeilFloat32,
82   CeilFloat64,
83   FloorFloat32,
84   FloorFloat64,
85   TruncFloat32,
86   TruncFloat64,
87   NearestFloat32,
88   NearestFloat64,
89   SqrtFloat32,
90   SqrtFloat64,
91 
92   // relational
93   EqZInt32,
94   EqZInt64,
95 
96   // conversions
97   // extend i32 to i64
98   ExtendSInt32,
99   ExtendUInt32,
100   // i64 to i32
101   WrapInt64,
102   // float to int
103   TruncSFloat32ToInt32,
104   TruncSFloat32ToInt64,
105   TruncUFloat32ToInt32,
106   TruncUFloat32ToInt64,
107   TruncSFloat64ToInt32,
108   TruncSFloat64ToInt64,
109   TruncUFloat64ToInt32,
110   TruncUFloat64ToInt64,
111   // reintepret bits to int
112   ReinterpretFloat32,
113   ReinterpretFloat64,
114   // int to float
115   ConvertSInt32ToFloat32,
116   ConvertSInt32ToFloat64,
117   ConvertUInt32ToFloat32,
118   ConvertUInt32ToFloat64,
119   ConvertSInt64ToFloat32,
120   ConvertSInt64ToFloat64,
121   ConvertUInt64ToFloat32,
122   ConvertUInt64ToFloat64,
123   // f32 to f64
124   PromoteFloat32,
125   // f64 to f32
126   DemoteFloat64,
127   // reinterpret bits to float
128   ReinterpretInt32,
129   ReinterpretInt64,
130 
131   // Extend signed subword-sized integer. This differs from e.g. ExtendSInt32
132   // because the input integer is in an i64 value insetad of an i32 value.
133   ExtendS8Int32,
134   ExtendS16Int32,
135   ExtendS8Int64,
136   ExtendS16Int64,
137   ExtendS32Int64,
138 
139   // Saturating float-to-int
140   TruncSatSFloat32ToInt32,
141   TruncSatUFloat32ToInt32,
142   TruncSatSFloat64ToInt32,
143   TruncSatUFloat64ToInt32,
144   TruncSatSFloat32ToInt64,
145   TruncSatUFloat32ToInt64,
146   TruncSatSFloat64ToInt64,
147   TruncSatUFloat64ToInt64,
148 
149   // SIMD splats
150   SplatVecI8x16,
151   SplatVecI16x8,
152   SplatVecI32x4,
153   SplatVecI64x2,
154   SplatVecF32x4,
155   SplatVecF64x2,
156 
157   // SIMD arithmetic
158   NotVec128,
159   AbsVecI8x16,
160   NegVecI8x16,
161   AnyTrueVecI8x16,
162   AllTrueVecI8x16,
163   BitmaskVecI8x16,
164   AbsVecI16x8,
165   NegVecI16x8,
166   AnyTrueVecI16x8,
167   AllTrueVecI16x8,
168   BitmaskVecI16x8,
169   AbsVecI32x4,
170   NegVecI32x4,
171   AnyTrueVecI32x4,
172   AllTrueVecI32x4,
173   BitmaskVecI32x4,
174   NegVecI64x2,
175   AnyTrueVecI64x2,
176   AllTrueVecI64x2,
177   AbsVecF32x4,
178   NegVecF32x4,
179   SqrtVecF32x4,
180   CeilVecF32x4,
181   FloorVecF32x4,
182   TruncVecF32x4,
183   NearestVecF32x4,
184   AbsVecF64x2,
185   NegVecF64x2,
186   SqrtVecF64x2,
187   CeilVecF64x2,
188   FloorVecF64x2,
189   TruncVecF64x2,
190   NearestVecF64x2,
191 
192   // SIMD conversions
193   TruncSatSVecF32x4ToVecI32x4,
194   TruncSatUVecF32x4ToVecI32x4,
195   TruncSatSVecF64x2ToVecI64x2,
196   TruncSatUVecF64x2ToVecI64x2,
197   ConvertSVecI32x4ToVecF32x4,
198   ConvertUVecI32x4ToVecF32x4,
199   ConvertSVecI64x2ToVecF64x2,
200   ConvertUVecI64x2ToVecF64x2,
201   WidenLowSVecI8x16ToVecI16x8,
202   WidenHighSVecI8x16ToVecI16x8,
203   WidenLowUVecI8x16ToVecI16x8,
204   WidenHighUVecI8x16ToVecI16x8,
205   WidenLowSVecI16x8ToVecI32x4,
206   WidenHighSVecI16x8ToVecI32x4,
207   WidenLowUVecI16x8ToVecI32x4,
208   WidenHighUVecI16x8ToVecI32x4,
209 
210   InvalidUnary
211 };
212 
213 enum BinaryOp {
214   // int or float
215   AddInt32,
216   SubInt32,
217   MulInt32,
218 
219   // int
220   DivSInt32,
221   DivUInt32,
222   RemSInt32,
223   RemUInt32,
224   AndInt32,
225   OrInt32,
226   XorInt32,
227   ShlInt32,
228   ShrSInt32,
229   ShrUInt32,
230   RotLInt32,
231   RotRInt32,
232 
233   // relational ops
234   // int or float
235   EqInt32,
236   NeInt32,
237   // int
238   LtSInt32,
239   LtUInt32,
240   LeSInt32,
241   LeUInt32,
242   GtSInt32,
243   GtUInt32,
244   GeSInt32,
245   GeUInt32,
246 
247   // int or float
248   AddInt64,
249   SubInt64,
250   MulInt64,
251 
252   // int
253   DivSInt64,
254   DivUInt64,
255   RemSInt64,
256   RemUInt64,
257   AndInt64,
258   OrInt64,
259   XorInt64,
260   ShlInt64,
261   ShrSInt64,
262   ShrUInt64,
263   RotLInt64,
264   RotRInt64,
265 
266   // relational ops
267   // int or float
268   EqInt64,
269   NeInt64,
270   // int
271   LtSInt64,
272   LtUInt64,
273   LeSInt64,
274   LeUInt64,
275   GtSInt64,
276   GtUInt64,
277   GeSInt64,
278   GeUInt64,
279 
280   // int or float
281   AddFloat32,
282   SubFloat32,
283   MulFloat32,
284 
285   // float
286   DivFloat32,
287   CopySignFloat32,
288   MinFloat32,
289   MaxFloat32,
290 
291   // relational ops
292   // int or float
293   EqFloat32,
294   NeFloat32,
295   // float
296   LtFloat32,
297   LeFloat32,
298   GtFloat32,
299   GeFloat32,
300 
301   // int or float
302   AddFloat64,
303   SubFloat64,
304   MulFloat64,
305 
306   // float
307   DivFloat64,
308   CopySignFloat64,
309   MinFloat64,
310   MaxFloat64,
311 
312   // relational ops
313   // int or float
314   EqFloat64,
315   NeFloat64,
316   // float
317   LtFloat64,
318   LeFloat64,
319   GtFloat64,
320   GeFloat64,
321 
322   // SIMD relational ops (return vectors)
323   EqVecI8x16,
324   NeVecI8x16,
325   LtSVecI8x16,
326   LtUVecI8x16,
327   GtSVecI8x16,
328   GtUVecI8x16,
329   LeSVecI8x16,
330   LeUVecI8x16,
331   GeSVecI8x16,
332   GeUVecI8x16,
333   EqVecI16x8,
334   NeVecI16x8,
335   LtSVecI16x8,
336   LtUVecI16x8,
337   GtSVecI16x8,
338   GtUVecI16x8,
339   LeSVecI16x8,
340   LeUVecI16x8,
341   GeSVecI16x8,
342   GeUVecI16x8,
343   EqVecI32x4,
344   NeVecI32x4,
345   LtSVecI32x4,
346   LtUVecI32x4,
347   GtSVecI32x4,
348   GtUVecI32x4,
349   LeSVecI32x4,
350   LeUVecI32x4,
351   GeSVecI32x4,
352   GeUVecI32x4,
353   EqVecF32x4,
354   NeVecF32x4,
355   LtVecF32x4,
356   GtVecF32x4,
357   LeVecF32x4,
358   GeVecF32x4,
359   EqVecF64x2,
360   NeVecF64x2,
361   LtVecF64x2,
362   GtVecF64x2,
363   LeVecF64x2,
364   GeVecF64x2,
365 
366   // SIMD arithmetic
367   AndVec128,
368   OrVec128,
369   XorVec128,
370   AndNotVec128,
371   AddVecI8x16,
372   AddSatSVecI8x16,
373   AddSatUVecI8x16,
374   SubVecI8x16,
375   SubSatSVecI8x16,
376   SubSatUVecI8x16,
377   MulVecI8x16,
378   MinSVecI8x16,
379   MinUVecI8x16,
380   MaxSVecI8x16,
381   MaxUVecI8x16,
382   AvgrUVecI8x16,
383   AddVecI16x8,
384   AddSatSVecI16x8,
385   AddSatUVecI16x8,
386   SubVecI16x8,
387   SubSatSVecI16x8,
388   SubSatUVecI16x8,
389   MulVecI16x8,
390   MinSVecI16x8,
391   MinUVecI16x8,
392   MaxSVecI16x8,
393   MaxUVecI16x8,
394   AvgrUVecI16x8,
395   AddVecI32x4,
396   SubVecI32x4,
397   MulVecI32x4,
398   MinSVecI32x4,
399   MinUVecI32x4,
400   MaxSVecI32x4,
401   MaxUVecI32x4,
402   DotSVecI16x8ToVecI32x4,
403   AddVecI64x2,
404   SubVecI64x2,
405   MulVecI64x2,
406   AddVecF32x4,
407   SubVecF32x4,
408   MulVecF32x4,
409   DivVecF32x4,
410   MinVecF32x4,
411   MaxVecF32x4,
412   PMinVecF32x4,
413   PMaxVecF32x4,
414   AddVecF64x2,
415   SubVecF64x2,
416   MulVecF64x2,
417   DivVecF64x2,
418   MinVecF64x2,
419   MaxVecF64x2,
420   PMinVecF64x2,
421   PMaxVecF64x2,
422 
423   // SIMD Conversion
424   NarrowSVecI16x8ToVecI8x16,
425   NarrowUVecI16x8ToVecI8x16,
426   NarrowSVecI32x4ToVecI16x8,
427   NarrowUVecI32x4ToVecI16x8,
428 
429   // SIMD Swizzle
430   SwizzleVec8x16,
431 
432   InvalidBinary
433 };
434 
435 enum AtomicRMWOp { Add, Sub, And, Or, Xor, Xchg };
436 
437 enum SIMDExtractOp {
438   ExtractLaneSVecI8x16,
439   ExtractLaneUVecI8x16,
440   ExtractLaneSVecI16x8,
441   ExtractLaneUVecI16x8,
442   ExtractLaneVecI32x4,
443   ExtractLaneVecI64x2,
444   ExtractLaneVecF32x4,
445   ExtractLaneVecF64x2
446 };
447 
448 enum SIMDReplaceOp {
449   ReplaceLaneVecI8x16,
450   ReplaceLaneVecI16x8,
451   ReplaceLaneVecI32x4,
452   ReplaceLaneVecI64x2,
453   ReplaceLaneVecF32x4,
454   ReplaceLaneVecF64x2
455 };
456 
457 enum SIMDShiftOp {
458   ShlVecI8x16,
459   ShrSVecI8x16,
460   ShrUVecI8x16,
461   ShlVecI16x8,
462   ShrSVecI16x8,
463   ShrUVecI16x8,
464   ShlVecI32x4,
465   ShrSVecI32x4,
466   ShrUVecI32x4,
467   ShlVecI64x2,
468   ShrSVecI64x2,
469   ShrUVecI64x2
470 };
471 
472 enum SIMDLoadOp {
473   LoadSplatVec8x16,
474   LoadSplatVec16x8,
475   LoadSplatVec32x4,
476   LoadSplatVec64x2,
477   LoadExtSVec8x8ToVecI16x8,
478   LoadExtUVec8x8ToVecI16x8,
479   LoadExtSVec16x4ToVecI32x4,
480   LoadExtUVec16x4ToVecI32x4,
481   LoadExtSVec32x2ToVecI64x2,
482   LoadExtUVec32x2ToVecI64x2,
483   Load32Zero,
484   Load64Zero
485 };
486 
487 enum SIMDTernaryOp { Bitselect, QFMAF32x4, QFMSF32x4, QFMAF64x2, QFMSF64x2 };
488 
489 //
490 // Expressions
491 //
492 // Note that little is provided in terms of constructors for these. The
493 // rationale is that writing  new Something(a, b, c, d, e)  is not the clearest,
494 // and it would be better to write   new Something(name=a, leftOperand=b...
495 // etc., but C++ lacks named operands, so in asm2wasm etc. you will see things
496 // like
497 //   auto x = new Something();
498 //   x->name = a;
499 //   x->leftOperand = b;
500 //   ..
501 // which is less compact but less ambiguous. See wasm-builder.h for a more
502 // friendly API for building nodes.
503 //
504 // Most nodes have no need of internal allocation, and when arena-allocated
505 // they drop the provided arena on the floor. You can create random instances
506 // of those that are not in an arena without issue. However, the nodes that
507 // have internal allocation will need an allocator provided to them in order
508 // to be constructed.
509 
510 class Expression {
511 public:
512   enum Id {
513     InvalidId = 0,
514     BlockId,
515     IfId,
516     LoopId,
517     BreakId,
518     SwitchId,
519     CallId,
520     CallIndirectId,
521     LocalGetId,
522     LocalSetId,
523     GlobalGetId,
524     GlobalSetId,
525     LoadId,
526     StoreId,
527     ConstId,
528     UnaryId,
529     BinaryId,
530     SelectId,
531     DropId,
532     ReturnId,
533     MemorySizeId,
534     MemoryGrowId,
535     NopId,
536     UnreachableId,
537     AtomicRMWId,
538     AtomicCmpxchgId,
539     AtomicWaitId,
540     AtomicNotifyId,
541     AtomicFenceId,
542     SIMDExtractId,
543     SIMDReplaceId,
544     SIMDShuffleId,
545     SIMDTernaryId,
546     SIMDShiftId,
547     SIMDLoadId,
548     MemoryInitId,
549     DataDropId,
550     MemoryCopyId,
551     MemoryFillId,
552     PopId,
553     RefNullId,
554     RefIsNullId,
555     RefFuncId,
556     RefEqId,
557     TryId,
558     ThrowId,
559     RethrowId,
560     BrOnExnId,
561     TupleMakeId,
562     TupleExtractId,
563     I31NewId,
564     I31GetId,
565     RefTestId,
566     RefCastId,
567     BrOnCastId,
568     RttCanonId,
569     RttSubId,
570     StructNewId,
571     StructGetId,
572     StructSetId,
573     ArrayNewId,
574     ArrayGetId,
575     ArraySetId,
576     ArrayLenId,
577     NumExpressionIds
578   };
579   Id _id;
580 
581   // the type of the expression: its *output*, not necessarily its input(s)
582   Type type = Type::none;
583 
Expression(Id id)584   Expression(Id id) : _id(id) {}
585 
finalize()586   void finalize() {}
587 
is()588   template<class T> bool is() const {
589     static_assert(std::is_base_of<Expression, T>::value,
590                   "Expression is not a base of destination type T");
591     return int(_id) == int(T::SpecificId);
592   }
593 
dynCast()594   template<class T> T* dynCast() {
595     static_assert(std::is_base_of<Expression, T>::value,
596                   "Expression is not a base of destination type T");
597     return int(_id) == int(T::SpecificId) ? (T*)this : nullptr;
598   }
599 
dynCast()600   template<class T> const T* dynCast() const {
601     static_assert(std::is_base_of<Expression, T>::value,
602                   "Expression is not a base of destination type T");
603     return int(_id) == int(T::SpecificId) ? (const T*)this : nullptr;
604   }
605 
cast()606   template<class T> T* cast() {
607     static_assert(std::is_base_of<Expression, T>::value,
608                   "Expression is not a base of destination type T");
609     assert(int(_id) == int(T::SpecificId));
610     return (T*)this;
611   }
612 
cast()613   template<class T> const T* cast() const {
614     static_assert(std::is_base_of<Expression, T>::value,
615                   "Expression is not a base of destination type T");
616     assert(int(_id) == int(T::SpecificId));
617     return (const T*)this;
618   }
619 
620   // Print the expression to stderr. Meant for use while debugging.
621   void dump();
622 };
623 
624 const char* getExpressionName(Expression* curr);
625 
626 Literal getLiteralFromConstExpression(Expression* curr);
627 Literals getLiteralsFromConstExpression(Expression* curr);
628 
629 typedef ArenaVector<Expression*> ExpressionList;
630 
631 template<Expression::Id SID> class SpecificExpression : public Expression {
632 public:
633   enum {
634     SpecificId = SID // compile-time access to the type for the class
635   };
636 
SpecificExpression()637   SpecificExpression() : Expression(SID) {}
638 };
639 
640 class Nop : public SpecificExpression<Expression::NopId> {
641 public:
642   Nop() = default;
Nop(MixedArena & allocator)643   Nop(MixedArena& allocator) {}
644 };
645 
646 class Block : public SpecificExpression<Expression::BlockId> {
647 public:
Block(MixedArena & allocator)648   Block(MixedArena& allocator) : list(allocator) {}
649 
650   Name name;
651   ExpressionList list;
652 
653   // set the type purely based on its contents. this scans the block, so it is
654   // not fast.
655   void finalize();
656 
657   // set the type given you know its type, which is the case when parsing
658   // s-expression or binary, as explicit types are given. the only additional
659   // work this does is to set the type to unreachable in the cases that is
660   // needed (which may require scanning the block)
661   void finalize(Type type_);
662 
663   // set the type given you know its type, and you know if there is a break to
664   // this block. this avoids the need to scan the contents of the block in the
665   // case that it might be unreachable, so it is recommended if you already know
666   // the type and breakability anyhow.
667   void finalize(Type type_, bool hasBreak);
668 };
669 
670 class If : public SpecificExpression<Expression::IfId> {
671 public:
If()672   If() : ifFalse(nullptr) {}
If(MixedArena & allocator)673   If(MixedArena& allocator) : If() {}
674 
675   Expression* condition;
676   Expression* ifTrue;
677   Expression* ifFalse;
678 
679   // set the type given you know its type, which is the case when parsing
680   // s-expression or binary, as explicit types are given. the only additional
681   // work this does is to set the type to unreachable in the cases that is
682   // needed.
683   void finalize(Type type_);
684 
685   // set the type purely based on its contents.
686   void finalize();
687 };
688 
689 class Loop : public SpecificExpression<Expression::LoopId> {
690 public:
691   Loop() = default;
Loop(MixedArena & allocator)692   Loop(MixedArena& allocator) {}
693 
694   Name name;
695   Expression* body;
696 
697   // set the type given you know its type, which is the case when parsing
698   // s-expression or binary, as explicit types are given. the only additional
699   // work this does is to set the type to unreachable in the cases that is
700   // needed.
701   void finalize(Type type_);
702 
703   // set the type purely based on its contents.
704   void finalize();
705 };
706 
707 class Break : public SpecificExpression<Expression::BreakId> {
708 public:
Break()709   Break() : value(nullptr), condition(nullptr) {}
Break(MixedArena & allocator)710   Break(MixedArena& allocator) : Break() { type = Type::unreachable; }
711 
712   Name name;
713   Expression* value;
714   Expression* condition;
715 
716   void finalize();
717 };
718 
719 class Switch : public SpecificExpression<Expression::SwitchId> {
720 public:
Switch(MixedArena & allocator)721   Switch(MixedArena& allocator) : targets(allocator) {
722     type = Type::unreachable;
723   }
724 
725   ArenaVector<Name> targets;
726   Name default_;
727   Expression* condition = nullptr;
728   Expression* value = nullptr;
729 
730   void finalize();
731 };
732 
733 class Call : public SpecificExpression<Expression::CallId> {
734 public:
Call(MixedArena & allocator)735   Call(MixedArena& allocator) : operands(allocator) {}
736 
737   ExpressionList operands;
738   Name target;
739   bool isReturn = false;
740 
741   void finalize();
742 };
743 
744 class CallIndirect : public SpecificExpression<Expression::CallIndirectId> {
745 public:
CallIndirect(MixedArena & allocator)746   CallIndirect(MixedArena& allocator) : operands(allocator) {}
747   Signature sig;
748   ExpressionList operands;
749   Expression* target;
750   bool isReturn = false;
751 
752   void finalize();
753 };
754 
755 class LocalGet : public SpecificExpression<Expression::LocalGetId> {
756 public:
757   LocalGet() = default;
LocalGet(MixedArena & allocator)758   LocalGet(MixedArena& allocator) {}
759 
760   Index index;
761 };
762 
763 class LocalSet : public SpecificExpression<Expression::LocalSetId> {
764 public:
765   LocalSet() = default;
LocalSet(MixedArena & allocator)766   LocalSet(MixedArena& allocator) {}
767 
768   void finalize();
769 
770   Index index;
771   Expression* value;
772 
773   bool isTee() const;
774   void makeTee(Type type);
775   void makeSet();
776 };
777 
778 class GlobalGet : public SpecificExpression<Expression::GlobalGetId> {
779 public:
780   GlobalGet() = default;
GlobalGet(MixedArena & allocator)781   GlobalGet(MixedArena& allocator) {}
782 
783   Name name;
784 };
785 
786 class GlobalSet : public SpecificExpression<Expression::GlobalSetId> {
787 public:
788   GlobalSet() = default;
GlobalSet(MixedArena & allocator)789   GlobalSet(MixedArena& allocator) {}
790 
791   Name name;
792   Expression* value;
793 
794   void finalize();
795 };
796 
797 class Load : public SpecificExpression<Expression::LoadId> {
798 public:
799   Load() = default;
Load(MixedArena & allocator)800   Load(MixedArena& allocator) {}
801 
802   uint8_t bytes;
803   bool signed_;
804   Address offset;
805   Address align;
806   bool isAtomic;
807   Expression* ptr;
808 
809   // type must be set during creation, cannot be inferred
810 
811   void finalize();
812 };
813 
814 class Store : public SpecificExpression<Expression::StoreId> {
815 public:
816   Store() = default;
Store(MixedArena & allocator)817   Store(MixedArena& allocator) : Store() {}
818 
819   uint8_t bytes;
820   Address offset;
821   Address align;
822   bool isAtomic;
823   Expression* ptr;
824   Expression* value;
825   Type valueType;
826 
827   void finalize();
828 };
829 
830 class AtomicRMW : public SpecificExpression<Expression::AtomicRMWId> {
831 public:
832   AtomicRMW() = default;
AtomicRMW(MixedArena & allocator)833   AtomicRMW(MixedArena& allocator) : AtomicRMW() {}
834 
835   AtomicRMWOp op;
836   uint8_t bytes;
837   Address offset;
838   Expression* ptr;
839   Expression* value;
840 
841   void finalize();
842 };
843 
844 class AtomicCmpxchg : public SpecificExpression<Expression::AtomicCmpxchgId> {
845 public:
846   AtomicCmpxchg() = default;
AtomicCmpxchg(MixedArena & allocator)847   AtomicCmpxchg(MixedArena& allocator) : AtomicCmpxchg() {}
848 
849   uint8_t bytes;
850   Address offset;
851   Expression* ptr;
852   Expression* expected;
853   Expression* replacement;
854 
855   void finalize();
856 };
857 
858 class AtomicWait : public SpecificExpression<Expression::AtomicWaitId> {
859 public:
860   AtomicWait() = default;
AtomicWait(MixedArena & allocator)861   AtomicWait(MixedArena& allocator) : AtomicWait() {}
862 
863   Address offset;
864   Expression* ptr;
865   Expression* expected;
866   Expression* timeout;
867   Type expectedType;
868 
869   void finalize();
870 };
871 
872 class AtomicNotify : public SpecificExpression<Expression::AtomicNotifyId> {
873 public:
874   AtomicNotify() = default;
AtomicNotify(MixedArena & allocator)875   AtomicNotify(MixedArena& allocator) : AtomicNotify() {}
876 
877   Address offset;
878   Expression* ptr;
879   Expression* notifyCount;
880 
881   void finalize();
882 };
883 
884 class AtomicFence : public SpecificExpression<Expression::AtomicFenceId> {
885 public:
886   AtomicFence() = default;
AtomicFence(MixedArena & allocator)887   AtomicFence(MixedArena& allocator) : AtomicFence() {}
888 
889   // Current wasm threads only supports sequentialy consistent atomics, but
890   // other orderings may be added in the future. This field is reserved for
891   // that, and currently set to 0.
892   uint8_t order = 0;
893 
894   void finalize();
895 };
896 
897 class SIMDExtract : public SpecificExpression<Expression::SIMDExtractId> {
898 public:
899   SIMDExtract() = default;
SIMDExtract(MixedArena & allocator)900   SIMDExtract(MixedArena& allocator) : SIMDExtract() {}
901 
902   SIMDExtractOp op;
903   Expression* vec;
904   uint8_t index;
905 
906   void finalize();
907 };
908 
909 class SIMDReplace : public SpecificExpression<Expression::SIMDReplaceId> {
910 public:
911   SIMDReplace() = default;
SIMDReplace(MixedArena & allocator)912   SIMDReplace(MixedArena& allocator) : SIMDReplace() {}
913 
914   SIMDReplaceOp op;
915   Expression* vec;
916   uint8_t index;
917   Expression* value;
918 
919   void finalize();
920 };
921 
922 class SIMDShuffle : public SpecificExpression<Expression::SIMDShuffleId> {
923 public:
924   SIMDShuffle() = default;
SIMDShuffle(MixedArena & allocator)925   SIMDShuffle(MixedArena& allocator) : SIMDShuffle() {}
926 
927   Expression* left;
928   Expression* right;
929   std::array<uint8_t, 16> mask;
930 
931   void finalize();
932 };
933 
934 class SIMDTernary : public SpecificExpression<Expression::SIMDTernaryId> {
935 public:
936   SIMDTernary() = default;
SIMDTernary(MixedArena & allocator)937   SIMDTernary(MixedArena& allocator) : SIMDTernary() {}
938 
939   SIMDTernaryOp op;
940   Expression* a;
941   Expression* b;
942   Expression* c;
943 
944   void finalize();
945 };
946 
947 class SIMDShift : public SpecificExpression<Expression::SIMDShiftId> {
948 public:
949   SIMDShift() = default;
SIMDShift(MixedArena & allocator)950   SIMDShift(MixedArena& allocator) : SIMDShift() {}
951 
952   SIMDShiftOp op;
953   Expression* vec;
954   Expression* shift;
955 
956   void finalize();
957 };
958 
959 class SIMDLoad : public SpecificExpression<Expression::SIMDLoadId> {
960 public:
961   SIMDLoad() = default;
SIMDLoad(MixedArena & allocator)962   SIMDLoad(MixedArena& allocator) {}
963 
964   SIMDLoadOp op;
965   Address offset;
966   Address align;
967   Expression* ptr;
968 
969   Index getMemBytes();
970   void finalize();
971 };
972 
973 class MemoryInit : public SpecificExpression<Expression::MemoryInitId> {
974 public:
975   MemoryInit() = default;
MemoryInit(MixedArena & allocator)976   MemoryInit(MixedArena& allocator) : MemoryInit() {}
977 
978   Index segment;
979   Expression* dest;
980   Expression* offset;
981   Expression* size;
982 
983   void finalize();
984 };
985 
986 class DataDrop : public SpecificExpression<Expression::DataDropId> {
987 public:
988   DataDrop() = default;
DataDrop(MixedArena & allocator)989   DataDrop(MixedArena& allocator) : DataDrop() {}
990 
991   Index segment;
992 
993   void finalize();
994 };
995 
996 class MemoryCopy : public SpecificExpression<Expression::MemoryCopyId> {
997 public:
998   MemoryCopy() = default;
MemoryCopy(MixedArena & allocator)999   MemoryCopy(MixedArena& allocator) : MemoryCopy() {}
1000 
1001   Expression* dest;
1002   Expression* source;
1003   Expression* size;
1004 
1005   void finalize();
1006 };
1007 
1008 class MemoryFill : public SpecificExpression<Expression::MemoryFillId> {
1009 public:
1010   MemoryFill() = default;
MemoryFill(MixedArena & allocator)1011   MemoryFill(MixedArena& allocator) : MemoryFill() {}
1012 
1013   Expression* dest;
1014   Expression* value;
1015   Expression* size;
1016 
1017   void finalize();
1018 };
1019 
1020 class Const : public SpecificExpression<Expression::ConstId> {
1021 public:
1022   Const() = default;
Const(MixedArena & allocator)1023   Const(MixedArena& allocator) {}
1024 
1025   Literal value;
1026 
1027   Const* set(Literal value_);
1028 
1029   void finalize();
1030 };
1031 
1032 class Unary : public SpecificExpression<Expression::UnaryId> {
1033 public:
1034   Unary() = default;
Unary(MixedArena & allocator)1035   Unary(MixedArena& allocator) {}
1036 
1037   UnaryOp op;
1038   Expression* value;
1039 
1040   bool isRelational();
1041 
1042   void finalize();
1043 };
1044 
1045 class Binary : public SpecificExpression<Expression::BinaryId> {
1046 public:
1047   Binary() = default;
Binary(MixedArena & allocator)1048   Binary(MixedArena& allocator) {}
1049 
1050   BinaryOp op;
1051   Expression* left;
1052   Expression* right;
1053 
1054   // the type is always the type of the operands,
1055   // except for relationals
1056 
1057   bool isRelational();
1058 
1059   void finalize();
1060 };
1061 
1062 class Select : public SpecificExpression<Expression::SelectId> {
1063 public:
1064   Select() = default;
Select(MixedArena & allocator)1065   Select(MixedArena& allocator) {}
1066 
1067   Expression* ifTrue;
1068   Expression* ifFalse;
1069   Expression* condition;
1070 
1071   void finalize();
1072   void finalize(Type type_);
1073 };
1074 
1075 class Drop : public SpecificExpression<Expression::DropId> {
1076 public:
1077   Drop() = default;
Drop(MixedArena & allocator)1078   Drop(MixedArena& allocator) {}
1079 
1080   Expression* value;
1081 
1082   void finalize();
1083 };
1084 
1085 class Return : public SpecificExpression<Expression::ReturnId> {
1086 public:
Return()1087   Return() { type = Type::unreachable; }
Return(MixedArena & allocator)1088   Return(MixedArena& allocator) : Return() {}
1089 
1090   Expression* value = nullptr;
1091 };
1092 
1093 class MemorySize : public SpecificExpression<Expression::MemorySizeId> {
1094 public:
MemorySize()1095   MemorySize() { type = Type::i32; }
MemorySize(MixedArena & allocator)1096   MemorySize(MixedArena& allocator) : MemorySize() {}
1097 
1098   Type ptrType = Type::i32;
1099 
1100   void make64();
1101   void finalize();
1102 };
1103 
1104 class MemoryGrow : public SpecificExpression<Expression::MemoryGrowId> {
1105 public:
MemoryGrow()1106   MemoryGrow() { type = Type::i32; }
MemoryGrow(MixedArena & allocator)1107   MemoryGrow(MixedArena& allocator) : MemoryGrow() {}
1108 
1109   Expression* delta = nullptr;
1110   Type ptrType = Type::i32;
1111 
1112   void make64();
1113   void finalize();
1114 };
1115 
1116 class Unreachable : public SpecificExpression<Expression::UnreachableId> {
1117 public:
Unreachable()1118   Unreachable() { type = Type::unreachable; }
Unreachable(MixedArena & allocator)1119   Unreachable(MixedArena& allocator) : Unreachable() {}
1120 };
1121 
1122 // Represents a pop of a value that arrives as an implicit argument to the
1123 // current block. Currently used in exception handling.
1124 class Pop : public SpecificExpression<Expression::PopId> {
1125 public:
1126   Pop() = default;
Pop(MixedArena & allocator)1127   Pop(MixedArena& allocator) {}
1128 };
1129 
1130 class RefNull : public SpecificExpression<Expression::RefNullId> {
1131 public:
1132   RefNull() = default;
RefNull(MixedArena & allocator)1133   RefNull(MixedArena& allocator) {}
1134 
1135   void finalize();
1136   void finalize(HeapType heapType);
1137   void finalize(Type type);
1138 };
1139 
1140 class RefIsNull : public SpecificExpression<Expression::RefIsNullId> {
1141 public:
RefIsNull(MixedArena & allocator)1142   RefIsNull(MixedArena& allocator) {}
1143 
1144   Expression* value;
1145 
1146   void finalize();
1147 };
1148 
1149 class RefFunc : public SpecificExpression<Expression::RefFuncId> {
1150 public:
RefFunc(MixedArena & allocator)1151   RefFunc(MixedArena& allocator) {}
1152 
1153   Name func;
1154 
1155   void finalize();
1156 };
1157 
1158 class RefEq : public SpecificExpression<Expression::RefEqId> {
1159 public:
RefEq(MixedArena & allocator)1160   RefEq(MixedArena& allocator) {}
1161 
1162   Expression* left;
1163   Expression* right;
1164 
1165   void finalize();
1166 };
1167 
1168 class Try : public SpecificExpression<Expression::TryId> {
1169 public:
Try(MixedArena & allocator)1170   Try(MixedArena& allocator) {}
1171 
1172   Expression* body;
1173   Expression* catchBody;
1174 
1175   void finalize();
1176   void finalize(Type type_);
1177 };
1178 
1179 class Throw : public SpecificExpression<Expression::ThrowId> {
1180 public:
Throw(MixedArena & allocator)1181   Throw(MixedArena& allocator) : operands(allocator) {}
1182 
1183   Name event;
1184   ExpressionList operands;
1185 
1186   void finalize();
1187 };
1188 
1189 class Rethrow : public SpecificExpression<Expression::RethrowId> {
1190 public:
Rethrow(MixedArena & allocator)1191   Rethrow(MixedArena& allocator) {}
1192 
1193   Expression* exnref;
1194 
1195   void finalize();
1196 };
1197 
1198 class BrOnExn : public SpecificExpression<Expression::BrOnExnId> {
1199 public:
BrOnExn()1200   BrOnExn() { type = Type::unreachable; }
BrOnExn(MixedArena & allocator)1201   BrOnExn(MixedArena& allocator) : BrOnExn() {}
1202 
1203   Name name;
1204   Name event;
1205   Expression* exnref;
1206   // This is duplicate info of param types stored in Event, but this is required
1207   // for us to know the type of the value sent to the target block.
1208   Type sent;
1209 
1210   void finalize();
1211 };
1212 
1213 class TupleMake : public SpecificExpression<Expression::TupleMakeId> {
1214 public:
TupleMake(MixedArena & allocator)1215   TupleMake(MixedArena& allocator) : operands(allocator) {}
1216 
1217   ExpressionList operands;
1218 
1219   void finalize();
1220 };
1221 
1222 class TupleExtract : public SpecificExpression<Expression::TupleExtractId> {
1223 public:
TupleExtract(MixedArena & allocator)1224   TupleExtract(MixedArena& allocator) {}
1225 
1226   Expression* tuple;
1227   Index index;
1228 
1229   void finalize();
1230 };
1231 
1232 class I31New : public SpecificExpression<Expression::I31NewId> {
1233 public:
I31New(MixedArena & allocator)1234   I31New(MixedArena& allocator) {}
1235 
1236   Expression* value;
1237 
1238   void finalize();
1239 };
1240 
1241 class I31Get : public SpecificExpression<Expression::I31GetId> {
1242 public:
I31Get(MixedArena & allocator)1243   I31Get(MixedArena& allocator) {}
1244 
1245   Expression* i31;
1246   bool signed_;
1247 
1248   void finalize();
1249 };
1250 
1251 class RefTest : public SpecificExpression<Expression::RefTestId> {
1252 public:
RefTest(MixedArena & allocator)1253   RefTest(MixedArena& allocator) {}
1254 
finalize()1255   void finalize() { WASM_UNREACHABLE("TODO (gc): ref.test"); }
1256 };
1257 
1258 class RefCast : public SpecificExpression<Expression::RefCastId> {
1259 public:
RefCast(MixedArena & allocator)1260   RefCast(MixedArena& allocator) {}
1261 
finalize()1262   void finalize() { WASM_UNREACHABLE("TODO (gc): ref.cast"); }
1263 };
1264 
1265 class BrOnCast : public SpecificExpression<Expression::BrOnCastId> {
1266 public:
BrOnCast(MixedArena & allocator)1267   BrOnCast(MixedArena& allocator) {}
1268 
finalize()1269   void finalize() { WASM_UNREACHABLE("TODO (gc): br_on_cast"); }
1270 };
1271 
1272 class RttCanon : public SpecificExpression<Expression::RttCanonId> {
1273 public:
RttCanon(MixedArena & allocator)1274   RttCanon(MixedArena& allocator) {}
1275 
finalize()1276   void finalize() { WASM_UNREACHABLE("TODO (gc): rtt.canon"); }
1277 };
1278 
1279 class RttSub : public SpecificExpression<Expression::RttSubId> {
1280 public:
RttSub(MixedArena & allocator)1281   RttSub(MixedArena& allocator) {}
1282 
finalize()1283   void finalize() { WASM_UNREACHABLE("TODO (gc): rtt.sub"); }
1284 };
1285 
1286 class StructNew : public SpecificExpression<Expression::StructNewId> {
1287 public:
StructNew(MixedArena & allocator)1288   StructNew(MixedArena& allocator) {}
1289 
finalize()1290   void finalize() { WASM_UNREACHABLE("TODO (gc): struct.new"); }
1291 };
1292 
1293 class StructGet : public SpecificExpression<Expression::StructGetId> {
1294 public:
StructGet(MixedArena & allocator)1295   StructGet(MixedArena& allocator) {}
1296 
finalize()1297   void finalize() { WASM_UNREACHABLE("TODO (gc): struct.get"); }
1298 };
1299 
1300 class StructSet : public SpecificExpression<Expression::StructSetId> {
1301 public:
StructSet(MixedArena & allocator)1302   StructSet(MixedArena& allocator) {}
1303 
finalize()1304   void finalize() { WASM_UNREACHABLE("TODO (gc): struct.set"); }
1305 };
1306 
1307 class ArrayNew : public SpecificExpression<Expression::ArrayNewId> {
1308 public:
ArrayNew(MixedArena & allocator)1309   ArrayNew(MixedArena& allocator) {}
1310 
finalize()1311   void finalize() { WASM_UNREACHABLE("TODO (gc): array.new"); }
1312 };
1313 
1314 class ArrayGet : public SpecificExpression<Expression::ArrayGetId> {
1315 public:
ArrayGet(MixedArena & allocator)1316   ArrayGet(MixedArena& allocator) {}
1317 
finalize()1318   void finalize() { WASM_UNREACHABLE("TODO (gc): array.get"); }
1319 };
1320 
1321 class ArraySet : public SpecificExpression<Expression::ArraySetId> {
1322 public:
ArraySet(MixedArena & allocator)1323   ArraySet(MixedArena& allocator) {}
1324 
finalize()1325   void finalize() { WASM_UNREACHABLE("TODO (gc): array.set"); }
1326 };
1327 
1328 class ArrayLen : public SpecificExpression<Expression::ArrayLenId> {
1329 public:
ArrayLen(MixedArena & allocator)1330   ArrayLen(MixedArena& allocator) {}
1331 
finalize()1332   void finalize() { WASM_UNREACHABLE("TODO (gc): array.len"); }
1333 };
1334 
1335 // Globals
1336 
1337 struct Importable {
1338   // If these are set, then this is an import, as module.base
1339   Name module, base;
1340 
importedImportable1341   bool imported() { return module.is(); }
1342 };
1343 
1344 class Function;
1345 
1346 // Represents an offset into a wasm binary file. This is used for debug info.
1347 // For now, assume this is 32 bits as that's the size limit of wasm files
1348 // anyhow.
1349 using BinaryLocation = uint32_t;
1350 
1351 // Represents a mapping of wasm module elements to their location in the
1352 // binary representation. This is used for general debugging info support.
1353 // Offsets are relative to the beginning of the code section, as in DWARF.
1354 struct BinaryLocations {
1355   struct Span {
1356     BinaryLocation start = 0, end = 0;
1357   };
1358 
1359   // Track the range of addresses an expressions appears at. This is the
1360   // contiguous range that all instructions have - control flow instructions
1361   // have additional opcodes later (like an end for a block or loop), see
1362   // just after this.
1363   std::unordered_map<Expression*, Span> expressions;
1364 
1365   // Track the extra delimiter positions that some instructions, in particular
1366   // control flow, have, like 'end' for loop and block. We keep these in a
1367   // separate map because they are rare and we optimize for the storage space
1368   // for the common type of instruction which just needs a Span. We implement
1369   // this as a simple struct with two elements (as two extra elements is the
1370   // maximum currently needed; due to 'catch' and 'end' for try-catch). The
1371   // second value may be 0, indicating it is not used.
1372   struct DelimiterLocations : public std::array<BinaryLocation, 2> {
DelimiterLocationsBinaryLocations::DelimiterLocations1373     DelimiterLocations() {
1374       // Ensure zero-initialization.
1375       for (auto& item : *this) {
1376         item = 0;
1377       }
1378     }
1379   };
1380 
1381   enum DelimiterId {
1382     // All control flow structures have an end, so use index 0 for that.
1383     End = 0,
1384     // Use index 1 for all other current things.
1385     Else = 1,
1386     Catch = 1,
1387     Invalid = -1
1388   };
1389   std::unordered_map<Expression*, DelimiterLocations> delimiters;
1390 
1391   // DWARF debug info can refer to multiple interesting positions in a function.
1392   struct FunctionLocations {
1393     // The very start of the function, where the binary has a size LEB.
1394     BinaryLocation start = 0;
1395     // The area where we declare locals, which is right after the size LEB.
1396     BinaryLocation declarations = 0;
1397     // The end, which is one past the final "end" instruction byte.
1398     BinaryLocation end = 0;
1399   };
1400 
1401   std::unordered_map<Function*, FunctionLocations> functions;
1402 };
1403 
1404 // Forward declarations of Stack IR, as functions can contain it, see
1405 // the stackIR property.
1406 // Stack IR is a secondary IR to the main IR defined in this file (Binaryen
1407 // IR). See wasm-stack.h.
1408 class StackInst;
1409 
1410 using StackIR = std::vector<StackInst*>;
1411 
1412 class Function : public Importable {
1413 public:
1414   Name name;
1415   Signature sig; // parameters and return value
1416   IRProfile profile = IRProfile::Normal;
1417   std::vector<Type> vars; // non-param locals
1418 
1419   // The body of the function
1420   Expression* body = nullptr;
1421 
1422   // If present, this stack IR was generated from the main Binaryen IR body,
1423   // and possibly optimized. If it is present when writing to wasm binary,
1424   // it will be emitted instead of the main Binaryen IR.
1425   //
1426   // Note that no special care is taken to synchronize the two IRs - if you
1427   // emit stack IR and then optimize the main IR, you need to recompute the
1428   // stack IR. The Pass system will throw away Stack IR if a pass is run
1429   // that declares it may modify Binaryen IR.
1430   std::unique_ptr<StackIR> stackIR;
1431 
1432   // local names. these are optional.
1433   std::map<Index, Name> localNames;
1434   std::map<Name, Index> localIndices;
1435 
1436   // Source maps debugging info: map expression nodes to their file, line, col.
1437   struct DebugLocation {
1438     BinaryLocation fileIndex, lineNumber, columnNumber;
1439     bool operator==(const DebugLocation& other) const {
1440       return fileIndex == other.fileIndex && lineNumber == other.lineNumber &&
1441              columnNumber == other.columnNumber;
1442     }
1443     bool operator!=(const DebugLocation& other) const {
1444       return !(*this == other);
1445     }
1446     bool operator<(const DebugLocation& other) const {
1447       return fileIndex != other.fileIndex
1448                ? fileIndex < other.fileIndex
1449                : lineNumber != other.lineNumber
1450                    ? lineNumber < other.lineNumber
1451                    : columnNumber < other.columnNumber;
1452     }
1453   };
1454   std::unordered_map<Expression*, DebugLocation> debugLocations;
1455   std::set<DebugLocation> prologLocation;
1456   std::set<DebugLocation> epilogLocation;
1457 
1458   // General debugging info support: track instructions and the function itself.
1459   std::unordered_map<Expression*, BinaryLocations::Span> expressionLocations;
1460   std::unordered_map<Expression*, BinaryLocations::DelimiterLocations>
1461     delimiterLocations;
1462   BinaryLocations::FunctionLocations funcLocation;
1463 
1464   size_t getNumParams();
1465   size_t getNumVars();
1466   size_t getNumLocals();
1467 
1468   bool isParam(Index index);
1469   bool isVar(Index index);
1470 
1471   Name getLocalName(Index index);
1472   Index getLocalIndex(Name name);
1473   Index getVarIndexBase();
1474   Type getLocalType(Index index);
1475 
1476   Name getLocalNameOrDefault(Index index);
1477   Name getLocalNameOrGeneric(Index index);
1478 
1479   bool hasLocalName(Index index) const;
1480   void setLocalName(Index index, Name name);
1481 
1482   void clearNames();
1483   void clearDebugInfo();
1484 };
1485 
1486 // The kind of an import or export.
1487 enum class ExternalKind {
1488   Function = 0,
1489   Table = 1,
1490   Memory = 2,
1491   Global = 3,
1492   Event = 4,
1493   Invalid = -1
1494 };
1495 
1496 class Export {
1497 public:
1498   // exported name - note that this is the key, as the internal name is
1499   // non-unique (can have multiple exports for an internal, also over kinds)
1500   Name name;
1501   Name value; // internal name
1502   ExternalKind kind;
1503 };
1504 
1505 class Table : public Importable {
1506 public:
1507   static const Address::address32_t kPageSize = 1;
1508   static const Index kUnlimitedSize = Index(-1);
1509   // In wasm32/64, the maximum table size is limited by a 32-bit pointer: 4GB
1510   static const Index kMaxSize = Index(-1);
1511 
1512   struct Segment {
1513     Expression* offset;
1514     std::vector<Name> data;
1515     Segment() = default;
SegmentSegment1516     Segment(Expression* offset) : offset(offset) {}
SegmentSegment1517     Segment(Expression* offset, std::vector<Name>& init) : offset(offset) {
1518       data.swap(init);
1519     }
1520   };
1521 
1522   // Currently the wasm object always 'has' one Table. It 'exists' if it has
1523   // been defined or imported. The table can exist but be empty and have no
1524   // defined initial or max size.
1525   bool exists = false;
1526   Name name;
1527   Address initial = 0;
1528   Address max = kMaxSize;
1529   std::vector<Segment> segments;
1530 
Table()1531   Table() { name = Name::fromInt(0); }
hasMax()1532   bool hasMax() { return max != kUnlimitedSize; }
clear()1533   void clear() {
1534     exists = false;
1535     name = "";
1536     initial = 0;
1537     max = kMaxSize;
1538     segments.clear();
1539   }
1540 };
1541 
1542 class Memory : public Importable {
1543 public:
1544   static const Address::address32_t kPageSize = 64 * 1024;
1545   static const Address::address64_t kUnlimitedSize = Address::address64_t(-1);
1546   // In wasm32, the maximum memory size is limited by a 32-bit pointer: 4GB
1547   static const Address::address32_t kMaxSize32 =
1548     (uint64_t(4) * 1024 * 1024 * 1024) / kPageSize;
1549 
1550   struct Segment {
1551     bool isPassive = false;
1552     Expression* offset = nullptr;
1553     std::vector<char> data; // TODO: optimize
1554     Segment() = default;
SegmentSegment1555     Segment(Expression* offset) : offset(offset) {}
SegmentSegment1556     Segment(Expression* offset, const char* init, Address size)
1557       : offset(offset) {
1558       data.resize(size);
1559       std::copy_n(init, size, data.begin());
1560     }
SegmentSegment1561     Segment(Expression* offset, std::vector<char>& init) : offset(offset) {
1562       data.swap(init);
1563     }
SegmentSegment1564     Segment(bool isPassive, Expression* offset, const char* init, Address size)
1565       : isPassive(isPassive), offset(offset) {
1566       data.resize(size);
1567       std::copy_n(init, size, data.begin());
1568     }
1569   };
1570 
1571   bool exists = false;
1572   Name name;
1573   Address initial = 0; // sizes are in pages
1574   Address max = kMaxSize32;
1575   std::vector<Segment> segments;
1576 
1577   // See comment in Table.
1578   bool shared = false;
1579   Type indexType = Type::i32;
1580 
Memory()1581   Memory() { name = Name::fromInt(0); }
hasMax()1582   bool hasMax() { return max != kUnlimitedSize; }
is64()1583   bool is64() { return indexType == Type::i64; }
clear()1584   void clear() {
1585     exists = false;
1586     name = "";
1587     initial = 0;
1588     max = kMaxSize32;
1589     segments.clear();
1590     shared = false;
1591     indexType = Type::i32;
1592   }
1593 };
1594 
1595 class Global : public Importable {
1596 public:
1597   Name name;
1598   Type type;
1599   Expression* init = nullptr;
1600   bool mutable_ = false;
1601 };
1602 
1603 // Kinds of event attributes.
1604 enum WasmEventAttribute : unsigned { WASM_EVENT_ATTRIBUTE_EXCEPTION = 0x0 };
1605 
1606 class Event : public Importable {
1607 public:
1608   Name name;
1609   // Kind of event. Currently only WASM_EVENT_ATTRIBUTE_EXCEPTION is possible.
1610   uint32_t attribute = WASM_EVENT_ATTRIBUTE_EXCEPTION;
1611   Signature sig;
1612 };
1613 
1614 // "Opaque" data, not part of the core wasm spec, that is held in binaries.
1615 // May be parsed/handled by utility code elsewhere, but not in wasm.h
1616 class UserSection {
1617 public:
1618   std::string name;
1619   std::vector<char> data;
1620 };
1621 
1622 // The optional "dylink" section is used in dynamic linking.
1623 class DylinkSection {
1624 public:
1625   Index memorySize, memoryAlignment, tableSize, tableAlignment;
1626   std::vector<Name> neededDynlibs;
1627 };
1628 
1629 class Module {
1630 public:
1631   // wasm contents (generally you shouldn't access these from outside, except
1632   // maybe for iterating; use add*() and the get() functions)
1633   std::vector<std::unique_ptr<Export>> exports;
1634   std::vector<std::unique_ptr<Function>> functions;
1635   std::vector<std::unique_ptr<Global>> globals;
1636   std::vector<std::unique_ptr<Event>> events;
1637 
1638   Table table;
1639   Memory memory;
1640   Name start;
1641 
1642   std::vector<UserSection> userSections;
1643 
1644   // Optional user section IR representation.
1645   std::unique_ptr<DylinkSection> dylinkSection;
1646 
1647   // Source maps debug info.
1648   std::vector<std::string> debugInfoFileNames;
1649 
1650   // `features` are the features allowed to be used in this module and should be
1651   // respected regardless of the value of`hasFeaturesSection`.
1652   // `hasFeaturesSection` means we read a features section and will emit one
1653   // too.
1654   FeatureSet features = FeatureSet::MVP;
1655   bool hasFeaturesSection = false;
1656 
1657   // Module name, if specified. Serves a documentary role only.
1658   Name name;
1659 
1660   MixedArena allocator;
1661 
1662 private:
1663   // TODO: add a build option where Names are just indices, and then these
1664   // methods are not needed
1665   // exports map is by the *exported* name, which is unique
1666   std::map<Name, Export*> exportsMap;
1667   std::map<Name, Function*> functionsMap;
1668   std::map<Name, Global*> globalsMap;
1669   std::map<Name, Event*> eventsMap;
1670 
1671 public:
1672   Module() = default;
1673 
1674   Export* getExport(Name name);
1675   Function* getFunction(Name name);
1676   Global* getGlobal(Name name);
1677   Event* getEvent(Name name);
1678 
1679   Export* getExportOrNull(Name name);
1680   Function* getFunctionOrNull(Name name);
1681   Global* getGlobalOrNull(Name name);
1682   Event* getEventOrNull(Name name);
1683 
1684   Export* addExport(Export* curr);
1685   Function* addFunction(Function* curr);
1686   Global* addGlobal(Global* curr);
1687   Event* addEvent(Event* curr);
1688 
1689   Export* addExport(std::unique_ptr<Export> curr);
1690   Function* addFunction(std::unique_ptr<Function> curr);
1691   Global* addGlobal(std::unique_ptr<Global> curr);
1692   Event* addEvent(std::unique_ptr<Event> curr);
1693 
1694   void addStart(const Name& s);
1695 
1696   void removeExport(Name name);
1697   void removeFunction(Name name);
1698   void removeGlobal(Name name);
1699   void removeEvent(Name name);
1700 
1701   void removeExports(std::function<bool(Export*)> pred);
1702   void removeFunctions(std::function<bool(Function*)> pred);
1703   void removeGlobals(std::function<bool(Global*)> pred);
1704   void removeEvents(std::function<bool(Event*)> pred);
1705 
1706   void updateMaps();
1707 
1708   void clearDebugInfo();
1709 };
1710 
1711 } // namespace wasm
1712 
1713 namespace std {
1714 template<> struct hash<wasm::Address> {
1715   size_t operator()(const wasm::Address a) const {
1716     return std::hash<wasm::Address::address64_t>()(a.addr);
1717   }
1718 };
1719 } // namespace std
1720 
1721 #endif // wasm_wasm_h
1722