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 | |
43 | namespace wasm { |
44 | |
45 | // An index in a wasm module |
46 | using Index = uint32_t; |
47 | |
48 | // An address in linear memory. |
49 | struct 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 | |
66 | enum class IRProfile { Normal, Poppy }; |
67 | |
68 | // Operators |
69 | |
70 | enum 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 | |
233 | enum 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 | |
482 | enum AtomicRMWOp { RMWAdd, RMWSub, RMWAnd, RMWOr, RMWXor, RMWXchg }; |
483 | |
484 | enum { |
485 | , |
486 | , |
487 | , |
488 | , |
489 | , |
490 | , |
491 | , |
492 | |
493 | }; |
494 | |
495 | enum SIMDReplaceOp { |
496 | ReplaceLaneVecI8x16, |
497 | ReplaceLaneVecI16x8, |
498 | ReplaceLaneVecI32x4, |
499 | ReplaceLaneVecI64x2, |
500 | ReplaceLaneVecF32x4, |
501 | ReplaceLaneVecF64x2, |
502 | }; |
503 | |
504 | enum 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 | |
519 | enum 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 | |
534 | enum SIMDLoadStoreLaneOp { |
535 | Load8LaneVec128, |
536 | Load16LaneVec128, |
537 | Load32LaneVec128, |
538 | Load64LaneVec128, |
539 | Store8LaneVec128, |
540 | Store16LaneVec128, |
541 | Store32LaneVec128, |
542 | Store64LaneVec128, |
543 | }; |
544 | |
545 | enum 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 | |
560 | enum RefAsOp { |
561 | RefAsNonNull, |
562 | ExternInternalize, |
563 | ExternExternalize, |
564 | }; |
565 | |
566 | enum BrOnOp { |
567 | BrOnNull, |
568 | BrOnNonNull, |
569 | BrOnCast, |
570 | BrOnCastFail, |
571 | }; |
572 | |
573 | enum 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 | |
588 | enum StringMeasureOp { |
589 | StringMeasureUTF8, |
590 | StringMeasureWTF8, |
591 | StringMeasureWTF16, |
592 | StringMeasureIsUSV, |
593 | StringMeasureWTF16View, |
594 | StringMeasureHash, |
595 | }; |
596 | |
597 | enum StringEncodeOp { |
598 | StringEncodeUTF8, |
599 | StringEncodeLossyUTF8, |
600 | StringEncodeWTF8, |
601 | StringEncodeWTF16, |
602 | StringEncodeUTF8Array, |
603 | StringEncodeLossyUTF8Array, |
604 | StringEncodeWTF8Array, |
605 | StringEncodeWTF16Array, |
606 | }; |
607 | |
608 | enum StringEqOp { |
609 | StringEqEqual, |
610 | StringEqCompare, |
611 | }; |
612 | |
613 | enum StringAsOp { |
614 | StringAsWTF8, |
615 | StringAsWTF16, |
616 | StringAsIter, |
617 | }; |
618 | |
619 | enum StringIterMoveOp { |
620 | StringIterMoveAdvance, |
621 | StringIterMoveRewind, |
622 | }; |
623 | |
624 | enum 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 | |
649 | class Expression { |
650 | public: |
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 | , |
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 | , |
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 | |
749 | protected: |
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 | |
757 | public: |
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 | |
796 | const char* getExpressionName(Expression* curr); |
797 | |
798 | Literal getLiteralFromConstExpression(Expression* curr); |
799 | Literals getLiteralsFromConstExpression(Expression* curr); |
800 | |
801 | using ExpressionList = ArenaVector<Expression*>; |
802 | |
803 | template<Expression::Id SID> class SpecificExpression : public Expression { |
804 | public: |
805 | enum { |
806 | SpecificId = SID // compile-time access to the type for the class |
807 | }; |
808 | |
809 | SpecificExpression() : Expression(SID) {} |
810 | }; |
811 | |
812 | class Nop : public SpecificExpression<Expression::NopId> { |
813 | public: |
814 | Nop() = default; |
815 | Nop(MixedArena& allocator) {} |
816 | }; |
817 | |
818 | class Block : public SpecificExpression<Expression::BlockId> { |
819 | public: |
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 | |
844 | class If : public SpecificExpression<Expression::IfId> { |
845 | public: |
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 | |
863 | class Loop : public SpecificExpression<Expression::LoopId> { |
864 | public: |
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 | |
881 | class Break : public SpecificExpression<Expression::BreakId> { |
882 | public: |
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 | |
893 | class Switch : public SpecificExpression<Expression::SwitchId> { |
894 | public: |
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 | |
907 | class Call : public SpecificExpression<Expression::CallId> { |
908 | public: |
909 | Call(MixedArena& allocator) : operands(allocator) {} |
910 | |
911 | ExpressionList operands; |
912 | Name target; |
913 | bool isReturn = false; |
914 | |
915 | void finalize(); |
916 | }; |
917 | |
918 | class CallIndirect : public SpecificExpression<Expression::CallIndirectId> { |
919 | public: |
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 | |
930 | class LocalGet : public SpecificExpression<Expression::LocalGetId> { |
931 | public: |
932 | LocalGet() = default; |
933 | LocalGet(MixedArena& allocator) {} |
934 | |
935 | Index index; |
936 | }; |
937 | |
938 | class LocalSet : public SpecificExpression<Expression::LocalSetId> { |
939 | public: |
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 | |
953 | class GlobalGet : public SpecificExpression<Expression::GlobalGetId> { |
954 | public: |
955 | GlobalGet() = default; |
956 | GlobalGet(MixedArena& allocator) {} |
957 | |
958 | Name name; |
959 | }; |
960 | |
961 | class GlobalSet : public SpecificExpression<Expression::GlobalSetId> { |
962 | public: |
963 | GlobalSet() = default; |
964 | GlobalSet(MixedArena& allocator) {} |
965 | |
966 | Name name; |
967 | Expression* value; |
968 | |
969 | void finalize(); |
970 | }; |
971 | |
972 | class Load : public SpecificExpression<Expression::LoadId> { |
973 | public: |
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 | |
990 | class Store : public SpecificExpression<Expression::StoreId> { |
991 | public: |
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 | |
1007 | class AtomicRMW : public SpecificExpression<Expression::AtomicRMWId> { |
1008 | public: |
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 | |
1022 | class AtomicCmpxchg : public SpecificExpression<Expression::AtomicCmpxchgId> { |
1023 | public: |
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 | |
1037 | class AtomicWait : public SpecificExpression<Expression::AtomicWaitId> { |
1038 | public: |
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 | |
1052 | class AtomicNotify : public SpecificExpression<Expression::AtomicNotifyId> { |
1053 | public: |
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 | |
1065 | class AtomicFence : public SpecificExpression<Expression::AtomicFenceId> { |
1066 | public: |
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 | |
1078 | class : public SpecificExpression<Expression::SIMDExtractId> { |
1079 | public: |
1080 | () = default; |
1081 | (MixedArena& allocator) : SIMDExtract() {} |
1082 | |
1083 | SIMDExtractOp ; |
1084 | Expression* ; |
1085 | uint8_t ; |
1086 | |
1087 | void (); |
1088 | }; |
1089 | |
1090 | class SIMDReplace : public SpecificExpression<Expression::SIMDReplaceId> { |
1091 | public: |
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 | |
1103 | class SIMDShuffle : public SpecificExpression<Expression::SIMDShuffleId> { |
1104 | public: |
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 | |
1115 | class SIMDTernary : public SpecificExpression<Expression::SIMDTernaryId> { |
1116 | public: |
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 | |
1128 | class SIMDShift : public SpecificExpression<Expression::SIMDShiftId> { |
1129 | public: |
1130 | SIMDShift() = default; |
1131 | SIMDShift(MixedArena& allocator) : SIMDShift() {} |
1132 | |
1133 | SIMDShiftOp op; |
1134 | Expression* vec; |
1135 | Expression* shift; |
1136 | |
1137 | void finalize(); |
1138 | }; |
1139 | |
1140 | class SIMDLoad : public SpecificExpression<Expression::SIMDLoadId> { |
1141 | public: |
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 | |
1155 | class SIMDLoadStoreLane |
1156 | : public SpecificExpression<Expression::SIMDLoadStoreLaneId> { |
1157 | public: |
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 | |
1175 | class MemoryInit : public SpecificExpression<Expression::MemoryInitId> { |
1176 | public: |
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 | |
1189 | class DataDrop : public SpecificExpression<Expression::DataDropId> { |
1190 | public: |
1191 | DataDrop() = default; |
1192 | DataDrop(MixedArena& allocator) : DataDrop() {} |
1193 | |
1194 | Name segment; |
1195 | |
1196 | void finalize(); |
1197 | }; |
1198 | |
1199 | class MemoryCopy : public SpecificExpression<Expression::MemoryCopyId> { |
1200 | public: |
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 | |
1213 | class MemoryFill : public SpecificExpression<Expression::MemoryFillId> { |
1214 | public: |
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 | |
1226 | class Const : public SpecificExpression<Expression::ConstId> { |
1227 | public: |
1228 | Const() = default; |
1229 | Const(MixedArena& allocator) {} |
1230 | |
1231 | Literal value; |
1232 | |
1233 | Const* set(Literal value_); |
1234 | |
1235 | void finalize(); |
1236 | }; |
1237 | |
1238 | class Unary : public SpecificExpression<Expression::UnaryId> { |
1239 | public: |
1240 | Unary() = default; |
1241 | Unary(MixedArena& allocator) {} |
1242 | |
1243 | UnaryOp op; |
1244 | Expression* value; |
1245 | |
1246 | bool isRelational(); |
1247 | |
1248 | void finalize(); |
1249 | }; |
1250 | |
1251 | class Binary : public SpecificExpression<Expression::BinaryId> { |
1252 | public: |
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 | |
1268 | class Select : public SpecificExpression<Expression::SelectId> { |
1269 | public: |
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 | |
1281 | class Drop : public SpecificExpression<Expression::DropId> { |
1282 | public: |
1283 | Drop() = default; |
1284 | Drop(MixedArena& allocator) {} |
1285 | |
1286 | Expression* value; |
1287 | |
1288 | void finalize(); |
1289 | }; |
1290 | |
1291 | class Return : public SpecificExpression<Expression::ReturnId> { |
1292 | public: |
1293 | Return() { type = Type::unreachable; } |
1294 | Return(MixedArena& allocator) : Return() {} |
1295 | |
1296 | Expression* value = nullptr; |
1297 | }; |
1298 | |
1299 | class MemorySize : public SpecificExpression<Expression::MemorySizeId> { |
1300 | public: |
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 | |
1311 | class MemoryGrow : public SpecificExpression<Expression::MemoryGrowId> { |
1312 | public: |
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 | |
1324 | class Unreachable : public SpecificExpression<Expression::UnreachableId> { |
1325 | public: |
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. |
1332 | class Pop : public SpecificExpression<Expression::PopId> { |
1333 | public: |
1334 | Pop() = default; |
1335 | Pop(MixedArena& allocator) {} |
1336 | }; |
1337 | |
1338 | class RefNull : public SpecificExpression<Expression::RefNullId> { |
1339 | public: |
1340 | RefNull() = default; |
1341 | RefNull(MixedArena& allocator) {} |
1342 | |
1343 | void finalize(); |
1344 | void finalize(HeapType heapType); |
1345 | void finalize(Type type); |
1346 | }; |
1347 | |
1348 | class RefIsNull : public SpecificExpression<Expression::RefIsNullId> { |
1349 | public: |
1350 | RefIsNull(MixedArena& allocator) {} |
1351 | |
1352 | Expression* value; |
1353 | |
1354 | void finalize(); |
1355 | }; |
1356 | |
1357 | class RefFunc : public SpecificExpression<Expression::RefFuncId> { |
1358 | public: |
1359 | RefFunc(MixedArena& allocator) {} |
1360 | |
1361 | Name func; |
1362 | |
1363 | void finalize(); |
1364 | void finalize(Type type_); |
1365 | }; |
1366 | |
1367 | class RefEq : public SpecificExpression<Expression::RefEqId> { |
1368 | public: |
1369 | RefEq(MixedArena& allocator) {} |
1370 | |
1371 | Expression* left; |
1372 | Expression* right; |
1373 | |
1374 | void finalize(); |
1375 | }; |
1376 | |
1377 | class TableGet : public SpecificExpression<Expression::TableGetId> { |
1378 | public: |
1379 | TableGet(MixedArena& allocator) {} |
1380 | |
1381 | Name table; |
1382 | |
1383 | Expression* index; |
1384 | |
1385 | void finalize(); |
1386 | }; |
1387 | |
1388 | class TableSet : public SpecificExpression<Expression::TableSetId> { |
1389 | public: |
1390 | TableSet(MixedArena& allocator) {} |
1391 | |
1392 | Name table; |
1393 | |
1394 | Expression* index; |
1395 | Expression* value; |
1396 | |
1397 | void finalize(); |
1398 | }; |
1399 | |
1400 | class TableSize : public SpecificExpression<Expression::TableSizeId> { |
1401 | public: |
1402 | TableSize() { type = Type::i32; } |
1403 | TableSize(MixedArena& allocator) : TableSize() {} |
1404 | |
1405 | Name table; |
1406 | |
1407 | void finalize(); |
1408 | }; |
1409 | |
1410 | class TableGrow : public SpecificExpression<Expression::TableGrowId> { |
1411 | public: |
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 | |
1422 | class Try : public SpecificExpression<Expression::TryId> { |
1423 | public: |
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 | |
1441 | class Throw : public SpecificExpression<Expression::ThrowId> { |
1442 | public: |
1443 | Throw(MixedArena& allocator) : operands(allocator) {} |
1444 | |
1445 | Name tag; |
1446 | ExpressionList operands; |
1447 | |
1448 | void finalize(); |
1449 | }; |
1450 | |
1451 | class Rethrow : public SpecificExpression<Expression::RethrowId> { |
1452 | public: |
1453 | Rethrow(MixedArena& allocator) {} |
1454 | |
1455 | Name target; |
1456 | |
1457 | void finalize(); |
1458 | }; |
1459 | |
1460 | class TupleMake : public SpecificExpression<Expression::TupleMakeId> { |
1461 | public: |
1462 | TupleMake(MixedArena& allocator) : operands(allocator) {} |
1463 | |
1464 | ExpressionList operands; |
1465 | |
1466 | void finalize(); |
1467 | }; |
1468 | |
1469 | class : public SpecificExpression<Expression::TupleExtractId> { |
1470 | public: |
1471 | (MixedArena& allocator) {} |
1472 | |
1473 | Expression* ; |
1474 | Index ; |
1475 | |
1476 | void (); |
1477 | }; |
1478 | |
1479 | class I31New : public SpecificExpression<Expression::I31NewId> { |
1480 | public: |
1481 | I31New(MixedArena& allocator) {} |
1482 | |
1483 | Expression* value; |
1484 | |
1485 | void finalize(); |
1486 | }; |
1487 | |
1488 | class I31Get : public SpecificExpression<Expression::I31GetId> { |
1489 | public: |
1490 | I31Get(MixedArena& allocator) {} |
1491 | |
1492 | Expression* i31; |
1493 | bool signed_ = false; |
1494 | |
1495 | void finalize(); |
1496 | }; |
1497 | |
1498 | class CallRef : public SpecificExpression<Expression::CallRefId> { |
1499 | public: |
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 | |
1509 | class RefTest : public SpecificExpression<Expression::RefTestId> { |
1510 | public: |
1511 | RefTest(MixedArena& allocator) {} |
1512 | |
1513 | Expression* ref; |
1514 | |
1515 | Type castType; |
1516 | |
1517 | void finalize(); |
1518 | |
1519 | Type& getCastType() { return castType; } |
1520 | }; |
1521 | |
1522 | class RefCast : public SpecificExpression<Expression::RefCastId> { |
1523 | public: |
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 | |
1538 | class BrOn : public SpecificExpression<Expression::BrOnId> { |
1539 | public: |
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 | |
1555 | class StructNew : public SpecificExpression<Expression::StructNewId> { |
1556 | public: |
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 | |
1569 | class StructGet : public SpecificExpression<Expression::StructGetId> { |
1570 | public: |
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 | |
1581 | class StructSet : public SpecificExpression<Expression::StructSetId> { |
1582 | public: |
1583 | StructSet(MixedArena& allocator) {} |
1584 | |
1585 | Index index; |
1586 | Expression* ref; |
1587 | Expression* value; |
1588 | |
1589 | void finalize(); |
1590 | }; |
1591 | |
1592 | class ArrayNew : public SpecificExpression<Expression::ArrayNewId> { |
1593 | public: |
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 | |
1607 | class ArrayNewData : public SpecificExpression<Expression::ArrayNewDataId> { |
1608 | public: |
1609 | ArrayNewData(MixedArena& allocator) {} |
1610 | |
1611 | Name segment; |
1612 | Expression* offset; |
1613 | Expression* size; |
1614 | |
1615 | void finalize(); |
1616 | }; |
1617 | |
1618 | class ArrayNewElem : public SpecificExpression<Expression::ArrayNewElemId> { |
1619 | public: |
1620 | ArrayNewElem(MixedArena& allocator) {} |
1621 | |
1622 | Name segment; |
1623 | Expression* offset; |
1624 | Expression* size; |
1625 | |
1626 | void finalize(); |
1627 | }; |
1628 | |
1629 | class ArrayNewFixed : public SpecificExpression<Expression::ArrayNewFixedId> { |
1630 | public: |
1631 | ArrayNewFixed(MixedArena& allocator) : values(allocator) {} |
1632 | |
1633 | ExpressionList values; |
1634 | |
1635 | void finalize(); |
1636 | }; |
1637 | |
1638 | class ArrayGet : public SpecificExpression<Expression::ArrayGetId> { |
1639 | public: |
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 | |
1650 | class ArraySet : public SpecificExpression<Expression::ArraySetId> { |
1651 | public: |
1652 | ArraySet(MixedArena& allocator) {} |
1653 | |
1654 | Expression* ref; |
1655 | Expression* index; |
1656 | Expression* value; |
1657 | |
1658 | void finalize(); |
1659 | }; |
1660 | |
1661 | class ArrayLen : public SpecificExpression<Expression::ArrayLenId> { |
1662 | public: |
1663 | ArrayLen(MixedArena& allocator) {} |
1664 | |
1665 | Expression* ref; |
1666 | |
1667 | void finalize(); |
1668 | }; |
1669 | |
1670 | class ArrayCopy : public SpecificExpression<Expression::ArrayCopyId> { |
1671 | public: |
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 | |
1683 | class ArrayFill : public SpecificExpression<Expression::ArrayFillId> { |
1684 | public: |
1685 | ArrayFill(MixedArena& allocator) {} |
1686 | |
1687 | Expression* ref; |
1688 | Expression* index; |
1689 | Expression* value; |
1690 | Expression* size; |
1691 | |
1692 | void finalize(); |
1693 | }; |
1694 | |
1695 | class ArrayInitData : public SpecificExpression<Expression::ArrayInitDataId> { |
1696 | public: |
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 | |
1708 | class ArrayInitElem : public SpecificExpression<Expression::ArrayInitElemId> { |
1709 | public: |
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 | |
1721 | class RefAs : public SpecificExpression<Expression::RefAsId> { |
1722 | public: |
1723 | RefAs(MixedArena& allocator) {} |
1724 | |
1725 | RefAsOp op; |
1726 | |
1727 | Expression* value; |
1728 | |
1729 | void finalize(); |
1730 | }; |
1731 | |
1732 | class StringNew : public SpecificExpression<Expression::StringNewId> { |
1733 | public: |
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 | |
1756 | class StringConst : public SpecificExpression<Expression::StringConstId> { |
1757 | public: |
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 | |
1768 | class StringMeasure : public SpecificExpression<Expression::StringMeasureId> { |
1769 | public: |
1770 | StringMeasure(MixedArena& allocator) {} |
1771 | |
1772 | StringMeasureOp op; |
1773 | |
1774 | Expression* ref; |
1775 | |
1776 | void finalize(); |
1777 | }; |
1778 | |
1779 | class StringEncode : public SpecificExpression<Expression::StringEncodeId> { |
1780 | public: |
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 | |
1798 | class StringConcat : public SpecificExpression<Expression::StringConcatId> { |
1799 | public: |
1800 | StringConcat(MixedArena& allocator) {} |
1801 | |
1802 | Expression* left; |
1803 | Expression* right; |
1804 | |
1805 | void finalize(); |
1806 | }; |
1807 | |
1808 | class StringEq : public SpecificExpression<Expression::StringEqId> { |
1809 | public: |
1810 | StringEq(MixedArena& allocator) {} |
1811 | |
1812 | StringEqOp op; |
1813 | |
1814 | Expression* left; |
1815 | Expression* right; |
1816 | |
1817 | void finalize(); |
1818 | }; |
1819 | |
1820 | class StringAs : public SpecificExpression<Expression::StringAsId> { |
1821 | public: |
1822 | StringAs(MixedArena& allocator) {} |
1823 | |
1824 | StringAsOp op; |
1825 | |
1826 | Expression* ref; |
1827 | |
1828 | void finalize(); |
1829 | }; |
1830 | |
1831 | class StringWTF8Advance |
1832 | : public SpecificExpression<Expression::StringWTF8AdvanceId> { |
1833 | public: |
1834 | StringWTF8Advance(MixedArena& allocator) {} |
1835 | |
1836 | Expression* ref; |
1837 | Expression* pos; |
1838 | Expression* bytes; |
1839 | |
1840 | void finalize(); |
1841 | }; |
1842 | |
1843 | class StringWTF16Get : public SpecificExpression<Expression::StringWTF16GetId> { |
1844 | public: |
1845 | StringWTF16Get(MixedArena& allocator) {} |
1846 | |
1847 | Expression* ref; |
1848 | Expression* pos; |
1849 | |
1850 | void finalize(); |
1851 | }; |
1852 | |
1853 | class StringIterNext : public SpecificExpression<Expression::StringIterNextId> { |
1854 | public: |
1855 | StringIterNext(MixedArena& allocator) {} |
1856 | |
1857 | Expression* ref; |
1858 | |
1859 | void finalize(); |
1860 | }; |
1861 | |
1862 | class StringIterMove : public SpecificExpression<Expression::StringIterMoveId> { |
1863 | public: |
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 | |
1877 | class StringSliceWTF : public SpecificExpression<Expression::StringSliceWTFId> { |
1878 | public: |
1879 | StringSliceWTF(MixedArena& allocator) {} |
1880 | |
1881 | StringSliceWTFOp op; |
1882 | |
1883 | Expression* ref; |
1884 | Expression* start; |
1885 | Expression* end; |
1886 | |
1887 | void finalize(); |
1888 | }; |
1889 | |
1890 | class StringSliceIter |
1891 | : public SpecificExpression<Expression::StringSliceIterId> { |
1892 | public: |
1893 | StringSliceIter(MixedArena& allocator) {} |
1894 | |
1895 | Expression* ref; |
1896 | Expression* num; |
1897 | |
1898 | void finalize(); |
1899 | }; |
1900 | |
1901 | // Globals |
1902 | |
1903 | struct 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 | |
1920 | struct 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 | |
1927 | class 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. |
1932 | using 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. |
1937 | struct 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. |
1979 | class StackInst; |
1980 | |
1981 | using StackIR = std::vector<StackInst*>; |
1982 | |
1983 | class Function : public Importable { |
1984 | public: |
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. |
2064 | enum 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. |
2077 | enum 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 | |
2088 | class Export { |
2089 | public: |
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 | |
2097 | class ElementSegment : public Named { |
2098 | public: |
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 | |
2118 | class Table : public Importable { |
2119 | public: |
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 | |
2137 | class DataSegment : public Named { |
2138 | public: |
2139 | Name memory; |
2140 | bool isPassive = false; |
2141 | Expression* offset = nullptr; |
2142 | std::vector<char> data; // TODO: optimize |
2143 | }; |
2144 | |
2145 | class Memory : public Importable { |
2146 | public: |
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 | |
2172 | class Global : public Importable { |
2173 | public: |
2174 | Type type; |
2175 | Expression* init = nullptr; |
2176 | bool mutable_ = false; |
2177 | }; |
2178 | |
2179 | class Tag : public Importable { |
2180 | public: |
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 |
2186 | class CustomSection { |
2187 | public: |
2188 | std::string name; |
2189 | std::vector<char> data; |
2190 | }; |
2191 | |
2192 | // The optional "dylink" section is used in dynamic linking. |
2193 | class DylinkSection { |
2194 | public: |
2195 | bool isLegacy = false; |
2196 | Index memorySize, memoryAlignment, tableSize, tableAlignment; |
2197 | std::vector<Name> neededDynlibs; |
2198 | std::vector<char> tail; |
2199 | }; |
2200 | |
2201 | class Module { |
2202 | public: |
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 | |
2238 | private: |
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 | |
2251 | public: |
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. |
2314 | using 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. |
2318 | struct ShallowExpression { |
2319 | Expression* expr; |
2320 | Module* module = nullptr; |
2321 | }; |
2322 | |
2323 | } // namespace wasm |
2324 | |
2325 | namespace std { |
2326 | template<> 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 | |
2332 | std::ostream& operator<<(std::ostream& o, wasm::Module& module); |
2333 | std::ostream& operator<<(std::ostream& o, wasm::Expression& expression); |
2334 | std::ostream& operator<<(std::ostream& o, wasm::ModuleExpression pair); |
2335 | std::ostream& operator<<(std::ostream& o, wasm::ShallowExpression expression); |
2336 | std::ostream& operator<<(std::ostream& o, wasm::StackInst& inst); |
2337 | std::ostream& operator<<(std::ostream& o, wasm::StackIR& ir); |
2338 | |
2339 | } // namespace std |
2340 | |
2341 | #endif // wasm_wasm_h |
2342 | |