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