ObjectEmitter.h (30644B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef frontend_ObjectEmitter_h 8 #define frontend_ObjectEmitter_h 9 10 #include "mozilla/Attributes.h" // MOZ_STACK_CLASS, MOZ_ALWAYS_INLINE, MOZ_RAII 11 #include "mozilla/Maybe.h" // Maybe 12 13 #include <stddef.h> // size_t 14 #include <stdint.h> // uint32_t 15 16 #include "frontend/EmitterScope.h" // EmitterScope 17 #include "frontend/NameOpEmitter.h" // NameOpEmitter 18 #include "frontend/ParseNode.h" // AccessorType 19 #include "frontend/ParserAtom.h" // TaggedParserAtomIndex 20 #include "frontend/TDZCheckCache.h" // TDZCheckCache 21 #include "vm/Opcodes.h" // JSOp 22 #include "vm/Scope.h" // LexicalScope 23 24 namespace js { 25 26 namespace frontend { 27 28 struct BytecodeEmitter; 29 class SharedContext; 30 31 // Class for emitting bytecode for object and class properties. 32 // See ObjectEmitter and ClassEmitter for usage. 33 class MOZ_STACK_CLASS PropertyEmitter { 34 public: 35 enum class Kind { 36 // Prototype property. 37 Prototype, 38 39 // Class static property. 40 Static 41 }; 42 43 protected: 44 BytecodeEmitter* bce_; 45 46 // True if the object is class. 47 // Set by ClassEmitter. 48 bool isClass_ = false; 49 50 // True if the property is class static method. 51 bool isStatic_ = false; 52 53 // True if the property has computed or index key. 54 bool isIndexOrComputed_ = false; 55 56 #ifdef DEBUG 57 // The state of this emitter. 58 // 59 // +-------+ 60 // | Start |-+ 61 // +-------+ | 62 // | 63 // +---------+ 64 // | 65 // | +------------------------------------------------------------+ 66 // | | | 67 // | | [normal property/method/accessor] | 68 // | v prepareForPropValue +-----------+ +------+ | 69 // +->+----------------------->| PropValue |-+ +->| Init |-+ 70 // | +-----------+ | | +------+ 71 // | | | 72 // | +-----------------------------------+ +-----------+ 73 // | | | 74 // | +-+---------------------------------------+ | 75 // | | | | 76 // | | [method with super] | | 77 // | | emitInitHomeObject +-------------+ v | 78 // | +--------------------->| InitHomeObj |->+ | 79 // | +-------------+ | | 80 // | | | 81 // | +-------------------------------------- + | 82 // | | | 83 // | | emitInit | 84 // | +------------------------------------------------------>+ 85 // | ^ 86 // | [optimized private non-static method] | 87 // | prepareForPrivateMethod +--------------------+ | 88 // +---------------------------->| PrivateMethodValue |-+ | 89 // | +--------------------+ | | 90 // | | | 91 // | +-------------------------------------------------+ | 92 // | | | 93 // | +-+---------------------------------------------+ | 94 // | | | | 95 // | | [method with super | | 96 // | | emitInitHomeObject +-----------------+ v | 97 // | +--------------------->| InitHomeObjFor- |----+ | 98 // | | PrivateMethod | | | 99 // | +-----------------+ | | 100 // | | | 101 // | +---------------------------------------------+ | 102 // | | | 103 // | | skipInit | 104 // | +------------------------------------------------------>+ 105 // | ^ 106 // | [private static method] | 107 // | prepareForPrivateStaticMethod +---------------------+ | 108 // +--------------------------------->| PrivateStaticMethod |-+ | 109 // | +---------------------+ | | 110 // | | | 111 // | +-------------------------------------------------------+ | 112 // | | | 113 // | +-+-------------------------------------------------+ | 114 // | | | | 115 // | | [method with super | | 116 // | | emitInitHomeObject +---------------------+ v | 117 // | +--------------------->| InitHomeObjFor- |----+ | 118 // | | PrivateStaticMethod | | | 119 // | +---------------------+ | | 120 // | | | 121 // | +-----------------------------------------------+ | 122 // | | | 123 // | | emitPrivateStaticMethod | 124 // | +---------------------------------------------------->+ 125 // | ^ 126 // | [index property/method/accessor] | 127 // | prepareForIndexPropKey +----------+ | 128 // +-------------------------->| IndexKey |-+ | 129 // | +----------+ | | 130 // | | | 131 // | +-------------------------------------+ | 132 // | | | 133 // | | prepareForIndexPropValue +------------+ | 134 // | +------------------------->| IndexValue |-+ | 135 // | +------------+ | | 136 // | | | 137 // | +---------------------------------------+ | 138 // | | | 139 // | +-+--------------------------------------------------+ | 140 // | | | | 141 // | | [method with super] | | 142 // | | emitInitHomeObject +---------------------+ v | 143 // | +--------------------->| InitHomeObjForIndex |---->+ | 144 // | +---------------------+ | | 145 // | | | 146 // | +--------------------------------------------------+ | 147 // | | | 148 // | | emitInitIndexOrComputed | 149 // | +---------------------------------------------------->+ 150 // | ^ 151 // | [computed property/method/accessor] | 152 // | prepareForComputedPropKey +-------------+ | 153 // +----------------------------->| ComputedKey |-+ | 154 // | +-------------+ | | 155 // | | | 156 // | +-------------------------------------------+ | 157 // | | | 158 // | | prepareForComputedPropValue +---------------+ | 159 // | +---------------------------->| ComputedValue |-+ | 160 // | +---------------+ | | 161 // | | | 162 // | +---------------------------------------------+ | 163 // | | | 164 // | +-+--------------------------------------------------+ | 165 // | | | | 166 // | | [method with super] | | 167 // | | emitInitHomeObject +------------------------+ v | 168 // | +--------------------->| InitHomeObjForComputed |->+ | 169 // | +------------------------+ | | 170 // | | | 171 // | +--------------------------------------------------+ | 172 // | | | 173 // | | emitInitIndexOrComputed | 174 // | +---------------------------------------------------->+ 175 // | ^ 176 // | | 177 // | [__proto__] | 178 // | prepareForProtoValue +------------+ emitMutateProto | 179 // +------------------------>| ProtoValue |-------------------->+ 180 // | +------------+ ^ 181 // | | 182 // | [...prop] | 183 // | prepareForSpreadOperand +---------------+ emitSpread | 184 // +-------------------------->| SpreadOperand |----------------+ 185 // +---------------+ 186 enum class PropertyState { 187 // The initial state. 188 Start, 189 190 // After calling prepareForPropValue. 191 PropValue, 192 193 // After calling emitInitHomeObject, from PropValue. 194 InitHomeObj, 195 196 // After calling prepareForPrivateMethod. 197 PrivateMethodValue, 198 199 // After calling emitInitHomeObject, from PrivateMethod. 200 InitHomeObjForPrivateMethod, 201 202 // After calling prepareForPrivateStaticMethod. 203 PrivateStaticMethod, 204 205 // After calling emitInitHomeObject, from PrivateStaticMethod. 206 InitHomeObjForPrivateStaticMethod, 207 208 // After calling prepareForIndexPropKey. 209 IndexKey, 210 211 // prepareForIndexPropValue. 212 IndexValue, 213 214 // After calling emitInitHomeObject, from IndexValue. 215 InitHomeObjForIndex, 216 217 // After calling prepareForComputedPropKey. 218 ComputedKey, 219 220 // prepareForComputedPropValue. 221 ComputedValue, 222 223 // After calling emitInitHomeObject, from ComputedValue. 224 InitHomeObjForComputed, 225 226 // After calling prepareForProtoValue. 227 ProtoValue, 228 229 // After calling prepareForSpreadOperand. 230 SpreadOperand, 231 232 // After calling one of emitInit, emitInitIndexOrComputed, emitMutateProto, 233 // or emitSpread. 234 Init, 235 }; 236 PropertyState propertyState_ = PropertyState::Start; 237 #endif 238 239 public: 240 explicit PropertyEmitter(BytecodeEmitter* bce); 241 242 // Parameters are the offset in the source code for each character below: 243 // 244 // { __proto__: protoValue } 245 // ^ 246 // | 247 // keyPos 248 [[nodiscard]] bool prepareForProtoValue(uint32_t keyPos); 249 [[nodiscard]] bool emitMutateProto(); 250 251 // { ...obj } 252 // ^ 253 // | 254 // spreadPos 255 [[nodiscard]] bool prepareForSpreadOperand(uint32_t spreadPos); 256 [[nodiscard]] bool emitSpread(); 257 258 // { key: value } 259 // ^ 260 // | 261 // keyPos 262 [[nodiscard]] bool prepareForPropValue(uint32_t keyPos, Kind kind); 263 264 [[nodiscard]] bool prepareForPrivateMethod(); 265 266 [[nodiscard]] bool prepareForPrivateStaticMethod(uint32_t keyPos); 267 268 // { 1: value } 269 // ^ 270 // | 271 // keyPos 272 [[nodiscard]] bool prepareForIndexPropKey(uint32_t keyPos, Kind kind); 273 [[nodiscard]] bool prepareForIndexPropValue(); 274 275 // { [ key ]: value } 276 // ^ 277 // | 278 // keyPos 279 [[nodiscard]] bool prepareForComputedPropKey(uint32_t keyPos, Kind kind); 280 [[nodiscard]] bool prepareForComputedPropValue(); 281 282 [[nodiscard]] bool emitInitHomeObject(); 283 284 // @param key 285 // Property key 286 [[nodiscard]] bool emitInit(AccessorType accessorType, 287 TaggedParserAtomIndex key); 288 289 [[nodiscard]] bool emitInitIndexOrComputed(AccessorType accessorType); 290 291 [[nodiscard]] bool emitPrivateStaticMethod(AccessorType accessorType); 292 293 [[nodiscard]] bool skipInit(); 294 295 private: 296 [[nodiscard]] MOZ_ALWAYS_INLINE bool prepareForProp(uint32_t keyPos, 297 bool isStatic, 298 bool isComputed); 299 300 // @param op 301 // Opcode for initializing property 302 // @param key 303 // Atom of the property if the property key is not computed 304 [[nodiscard]] bool emitInit(JSOp op, TaggedParserAtomIndex key); 305 [[nodiscard]] bool emitInitIndexOrComputed(JSOp op); 306 307 [[nodiscard]] bool emitPopClassConstructor(); 308 }; 309 310 // Class for emitting bytecode for object literal. 311 // 312 // Usage: (check for the return value is omitted for simplicity) 313 // 314 // `{}` 315 // ObjectEmitter oe(this); 316 // oe.emitObject(0); 317 // oe.emitEnd(); 318 // 319 // `{ prop: 10 }` 320 // ObjectEmitter oe(this); 321 // oe.emitObject(1); 322 // 323 // oe.prepareForPropValue(offset_of_prop); 324 // emit(10); 325 // oe.emitInitProp(atom_of_prop); 326 // 327 // oe.emitEnd(); 328 // 329 // `{ prop: function() {} }`, when property value is anonymous function 330 // ObjectEmitter oe(this); 331 // oe.emitObject(1); 332 // 333 // oe.prepareForPropValue(offset_of_prop); 334 // emit(function); 335 // oe.emitInitProp(atom_of_prop); 336 // 337 // oe.emitEnd(); 338 // 339 // `{ get prop() { ... }, set prop(v) { ... } }` 340 // ObjectEmitter oe(this); 341 // oe.emitObject(2); 342 // 343 // oe.prepareForPropValue(offset_of_prop); 344 // emit(function_for_getter); 345 // oe.emitInitGetter(atom_of_prop); 346 // 347 // oe.prepareForPropValue(offset_of_prop); 348 // emit(function_for_setter); 349 // oe.emitInitSetter(atom_of_prop); 350 // 351 // oe.emitEnd(); 352 // 353 // `{ 1: 10, get 2() { ... }, set 3(v) { ... } }` 354 // ObjectEmitter oe(this); 355 // oe.emitObject(3); 356 // 357 // oe.prepareForIndexPropKey(offset_of_prop); 358 // emit(1); 359 // oe.prepareForIndexPropValue(); 360 // emit(10); 361 // oe.emitInitIndexedProp(); 362 // 363 // oe.prepareForIndexPropKey(offset_of_opening_bracket); 364 // emit(2); 365 // oe.prepareForIndexPropValue(); 366 // emit(function_for_getter); 367 // oe.emitInitIndexGetter(); 368 // 369 // oe.prepareForIndexPropKey(offset_of_opening_bracket); 370 // emit(3); 371 // oe.prepareForIndexPropValue(); 372 // emit(function_for_setter); 373 // oe.emitInitIndexSetter(); 374 // 375 // oe.emitEnd(); 376 // 377 // `{ [prop1]: 10, get [prop2]() { ... }, set [prop3](v) { ... } }` 378 // ObjectEmitter oe(this); 379 // oe.emitObject(3); 380 // 381 // oe.prepareForComputedPropKey(offset_of_opening_bracket); 382 // emit(prop1); 383 // oe.prepareForComputedPropValue(); 384 // emit(10); 385 // oe.emitInitComputedProp(); 386 // 387 // oe.prepareForComputedPropKey(offset_of_opening_bracket); 388 // emit(prop2); 389 // oe.prepareForComputedPropValue(); 390 // emit(function_for_getter); 391 // oe.emitInitComputedGetter(); 392 // 393 // oe.prepareForComputedPropKey(offset_of_opening_bracket); 394 // emit(prop3); 395 // oe.prepareForComputedPropValue(); 396 // emit(function_for_setter); 397 // oe.emitInitComputedSetter(); 398 // 399 // oe.emitEnd(); 400 // 401 // `{ __proto__: obj }` 402 // ObjectEmitter oe(this); 403 // oe.emitObject(1); 404 // oe.prepareForProtoValue(offset_of___proto__); 405 // emit(obj); 406 // oe.emitMutateProto(); 407 // oe.emitEnd(); 408 // 409 // `{ ...obj }` 410 // ObjectEmitter oe(this); 411 // oe.emitObject(1); 412 // oe.prepareForSpreadOperand(offset_of_triple_dots); 413 // emit(obj); 414 // oe.emitSpread(); 415 // oe.emitEnd(); 416 // 417 class MOZ_STACK_CLASS ObjectEmitter : public PropertyEmitter { 418 private: 419 #ifdef DEBUG 420 // The state of this emitter. 421 // 422 // +-------+ emitObject +--------+ 423 // | Start |----------->| Object |-+ 424 // +-------+ +--------+ | 425 // | 426 // +-----------------------------+ 427 // | 428 // | (do PropertyEmitter operation) emitEnd +-----+ 429 // +-------------------------------+--------->| End | 430 // +-----+ 431 enum class ObjectState { 432 // The initial state. 433 Start, 434 435 // After calling emitObject. 436 Object, 437 438 // After calling emitEnd. 439 End, 440 }; 441 ObjectState objectState_ = ObjectState::Start; 442 #endif 443 444 public: 445 explicit ObjectEmitter(BytecodeEmitter* bce); 446 447 [[nodiscard]] bool emitObject(size_t propertyCount); 448 // Same as `emitObject()`, but start with an empty template object already on 449 // the stack. 450 [[nodiscard]] bool emitObjectWithTemplateOnStack(); 451 [[nodiscard]] bool emitEnd(); 452 }; 453 454 // Save and restore the strictness. 455 // Used by class declaration/expression to temporarily enable strict mode. 456 class MOZ_RAII AutoSaveLocalStrictMode { 457 SharedContext* sc_; 458 bool savedStrictness_; 459 460 public: 461 explicit AutoSaveLocalStrictMode(SharedContext* sc); 462 ~AutoSaveLocalStrictMode(); 463 464 // Force restore the strictness now. 465 void restore(); 466 }; 467 468 // Class for emitting bytecode for JS class. 469 // 470 // Usage: (check for the return value is omitted for simplicity) 471 // 472 // `class { constructor() { ... } }` 473 // ClassEmitter ce(this); 474 // ce.emitScope(scopeBindings); 475 // ce.emitClass(nullptr, nullptr, false); 476 // 477 // emit(function_for_constructor); 478 // ce.emitInitConstructor(/* needsHomeObject = */ false); 479 // 480 // ce.emitEnd(ClassEmitter::Kind::Expression); 481 // 482 // `class X { constructor() { ... } }` 483 // ClassEmitter ce(this); 484 // ce.emitScope(scopeBindings); 485 // ce.emitClass(atom_of_X, nullptr, false); 486 // 487 // emit(function_for_constructor); 488 // ce.emitInitConstructor(/* needsHomeObject = */ false); 489 // 490 // ce.emitEnd(ClassEmitter::Kind::Expression); 491 // 492 // `class X extends Y { constructor() { ... } }` 493 // ClassEmitter ce(this); 494 // ce.emitScope(scopeBindings); 495 // 496 // emit(Y); 497 // ce.emitDerivedClass(atom_of_X, nullptr, false); 498 // 499 // emit(function_for_constructor); 500 // ce.emitInitConstructor(/* needsHomeObject = */ false); 501 // 502 // ce.emitEnd(ClassEmitter::Kind::Expression); 503 // 504 // `class X extends Y { constructor() { ... super.f(); ... } }` 505 // ClassEmitter ce(this); 506 // ce.emitScope(scopeBindings); 507 // 508 // emit(Y); 509 // ce.emitDerivedClass(atom_of_X, nullptr, false); 510 // 511 // emit(function_for_constructor); 512 // // pass true if constructor contains super.prop access 513 // ce.emitInitConstructor(/* needsHomeObject = */ true); 514 // 515 // ce.emitEnd(ClassEmitter::Kind::Expression); 516 // 517 // `class X extends Y { field0 = expr0; ... }` 518 // ClassEmitter ce(this); 519 // ce.emitScope(scopeBindings); 520 // emit(Y); 521 // ce.emitDerivedClass(atom_of_X, nullptr, false); 522 // 523 // ce.prepareForMemberInitializers(fields.length()); 524 // for (auto field : fields) { 525 // emit(field.initializer_method()); 526 // ce.emitStoreMemberInitializer(); 527 // } 528 // ce.emitMemberInitializersEnd(); 529 // 530 // emit(function_for_constructor); 531 // ce.emitInitConstructor(/* needsHomeObject = */ false); 532 // ce.emitEnd(ClassEmitter::Kind::Expression); 533 // 534 // `class X { field0 = super.method(); ... }` 535 // // after emitClass/emitDerivedClass 536 // ce.prepareForMemberInitializers(1); 537 // for (auto field : fields) { 538 // emit(field.initializer_method()); 539 // if (field.initializer_contains_super_or_eval()) { 540 // ce.emitMemberInitializerHomeObject(); 541 // } 542 // ce.emitStoreMemberInitializer(); 543 // } 544 // ce.emitMemberInitializersEnd(); 545 // 546 // `m() {}` in class 547 // // after emitInitConstructor 548 // ce.prepareForPropValue(offset_of_m); 549 // emit(function_for_m); 550 // ce.emitInitProp(atom_of_m); 551 // 552 // `m() { super.f(); }` in class 553 // // after emitInitConstructor 554 // ce.prepareForPropValue(offset_of_m); 555 // emit(function_for_m); 556 // ce.emitInitHomeObject(); 557 // ce.emitInitProp(atom_of_m); 558 // 559 // `async m() { super.f(); }` in class 560 // // after emitInitConstructor 561 // ce.prepareForPropValue(offset_of_m); 562 // emit(function_for_m); 563 // ce.emitInitHomeObject(); 564 // ce.emitInitProp(atom_of_m); 565 // 566 // `get p() { super.f(); }` in class 567 // // after emitInitConstructor 568 // ce.prepareForPropValue(offset_of_p); 569 // emit(function_for_p); 570 // ce.emitInitHomeObject(); 571 // ce.emitInitGetter(atom_of_m); 572 // 573 // `static m() {}` in class 574 // // after emitInitConstructor 575 // ce.prepareForPropValue(offset_of_m, 576 // PropertyEmitter::Kind::Static); 577 // emit(function_for_m); 578 // ce.emitInitProp(atom_of_m); 579 // 580 // `static get [p]() { super.f(); }` in class 581 // // after emitInitConstructor 582 // ce.prepareForComputedPropValue(offset_of_m, 583 // PropertyEmitter::Kind::Static); 584 // emit(p); 585 // ce.prepareForComputedPropValue(); 586 // emit(function_for_m); 587 // ce.emitInitHomeObject(); 588 // ce.emitInitComputedGetter(); 589 // 590 class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter { 591 public: 592 enum class Kind { 593 // Class expression. 594 Expression, 595 596 // Class declaration. 597 Declaration, 598 }; 599 600 private: 601 // Pseudocode for class declarations: 602 // 603 // class extends BaseExpression { 604 // constructor() { ... } 605 // ... 606 // } 607 // 608 // 609 // if defined <BaseExpression> { 610 // let heritage = BaseExpression; 611 // 612 // if (heritage !== null) { 613 // funProto = heritage; 614 // objProto = heritage.prototype; 615 // } else { 616 // funProto = %FunctionPrototype%; 617 // objProto = null; 618 // } 619 // } else { 620 // objProto = %ObjectPrototype%; 621 // } 622 // 623 // let homeObject = ObjectCreate(objProto); 624 // 625 // if defined <constructor> { 626 // if defined <BaseExpression> { 627 // cons = DefineMethod(<constructor>, proto=homeObject, 628 // funProto=funProto); 629 // } else { 630 // cons = DefineMethod(<constructor>, proto=homeObject); 631 // } 632 // } else { 633 // if defined <BaseExpression> { 634 // cons = DefaultDerivedConstructor(proto=homeObject, 635 // funProto=funProto); 636 // } else { 637 // cons = DefaultConstructor(proto=homeObject); 638 // } 639 // } 640 // 641 // cons.prototype = homeObject; 642 // homeObject.constructor = cons; 643 // 644 // EmitPropertyList(...) 645 646 bool isDerived_ = false; 647 648 mozilla::Maybe<TDZCheckCache> tdzCache_; 649 mozilla::Maybe<EmitterScope> innerScope_; 650 mozilla::Maybe<TDZCheckCache> bodyTdzCache_; 651 mozilla::Maybe<EmitterScope> bodyScope_; 652 AutoSaveLocalStrictMode strictMode_; 653 654 #ifdef DEBUG 655 // The state of this emitter. 656 // 657 // clang-format off 658 // +-------+ 659 // | Start |-+------------------------>+--+------------------------------>+--+ 660 // +-------+ | ^ | ^ | 661 // | [has scope] | | [has body scope] | | 662 // | emitScope +-------+ | | emitBodyScope +-----------+ | | 663 // +-------------->| Scope |-+ +---------------->| BodyScope |-+ | 664 // +-------+ +-----------+ | 665 // | 666 // +-----------------------------------------------------------------------+ 667 // | 668 // | emitClass +-------+ 669 // +-+----------------->+->| Class |-+ 670 // | ^ +-------+ | 671 // | emitDerivedClass | | 672 // +------------------+ | 673 // | 674 // +-------------------------------+ 675 // | 676 // | 677 // | prepareForMemberInitializers(isStatic = false) 678 // +---------------+ 679 // | | 680 // | +--------v-------------------+ 681 // | | InstanceMemberInitializers | 682 // | +----------------------------+ 683 // | | 684 // | emitMemberInitializersEnd 685 // | | 686 // | +--------v----------------------+ 687 // | | InstanceMemberInitializersEnd | 688 // | +-------------------------------+ 689 // | | 690 // +<--------------+ 691 // | 692 // | emitInitConstructor +-----------------+ 693 // +-------------------------------->| InitConstructor |-+ 694 // +-----------------+ | 695 // | 696 // | 697 // | 698 // +-----------------------------------------------------+ 699 // | 700 // | prepareForMemberInitializers(isStatic = true) 701 // +---------------+ 702 // | | 703 // | +--------v-----------------+ 704 // | | StaticMemberInitializers | 705 // | +--------------------------+ 706 // | | 707 // | | emitMemberInitializersEnd 708 // | | 709 // | +--------v--------------------+ 710 // | | StaticMemberInitializersEnd | 711 // | +-----------------------------+ 712 // | | 713 // +<--------------+ 714 // | 715 // | (do PropertyEmitter operation) 716 // +--------------------------------+ 717 // | 718 // +-------------+ emitBinding | 719 // | BoundName |<-----------------+ 720 // +--+----------+ 721 // | 722 // | emitEnd 723 // | 724 // +--v----+ 725 // | End | 726 // +-------+ 727 // 728 // clang-format on 729 enum class ClassState { 730 // The initial state. 731 Start, 732 733 // After calling emitScope. 734 Scope, 735 736 // After calling emitBodyScope. 737 BodyScope, 738 739 // After calling emitClass or emitDerivedClass. 740 Class, 741 742 // After calling emitInitConstructor. 743 InitConstructor, 744 745 // After calling prepareForMemberInitializers(isStatic = false). 746 InstanceMemberInitializers, 747 748 // After calling emitMemberInitializersEnd. 749 InstanceMemberInitializersEnd, 750 751 // After calling prepareForMemberInitializers(isStatic = true). 752 StaticMemberInitializers, 753 754 // After calling emitMemberInitializersEnd. 755 StaticMemberInitializersEnd, 756 757 // After calling emitBinding. 758 BoundName, 759 760 // After calling emitEnd. 761 End, 762 }; 763 ClassState classState_ = ClassState::Start; 764 765 // The state of the members emitter. 766 // 767 // clang-format off 768 // 769 // +-------+ 770 // | Start +<-----------------------------+ 771 // +-------+ | 772 // | | 773 // | prepareForMemberInitializer | emitStoreMemberInitializer 774 // v | 775 // +-------------+ | 776 // | Initializer +------------------------->+ 777 // +-------------+ | 778 // | | 779 // | emitMemberInitializerHomeObject | 780 // v | 781 // +---------------------------+ | 782 // | InitializerWithHomeObject +------------+ 783 // +---------------------------+ 784 // 785 // clang-format on 786 enum class MemberState { 787 // After calling prepareForMemberInitializers 788 // and 0 or more calls to emitStoreMemberInitializer. 789 Start, 790 791 // After calling prepareForMemberInitializer 792 Initializer, 793 794 // After calling emitMemberInitializerHomeObject 795 InitializerWithHomeObject, 796 }; 797 MemberState memberState_ = MemberState::Start; 798 799 size_t numInitializers_ = 0; 800 #endif 801 802 TaggedParserAtomIndex name_; 803 TaggedParserAtomIndex nameForAnonymousClass_; 804 bool hasNameOnStack_ = false; 805 mozilla::Maybe<NameOpEmitter> initializersAssignment_; 806 size_t initializerIndex_ = 0; 807 808 public: 809 explicit ClassEmitter(BytecodeEmitter* bce); 810 811 bool emitScope(LexicalScope::ParserData* scopeBindings); 812 bool emitBodyScope(ClassBodyScope::ParserData* scopeBindings); 813 814 // @param name 815 // Name of the class (nullptr if this is anonymous class) 816 // @param nameForAnonymousClass 817 // Statically inferred name of the class (only for anonymous classes) 818 // @param hasNameOnStack 819 // If true the name is on the stack (only for anonymous classes) 820 [[nodiscard]] bool emitClass(TaggedParserAtomIndex name, 821 TaggedParserAtomIndex nameForAnonymousClass, 822 bool hasNameOnStack, uint8_t membersCount); 823 [[nodiscard]] bool emitDerivedClass( 824 TaggedParserAtomIndex name, TaggedParserAtomIndex nameForAnonymousClass, 825 bool hasNameOnStack); 826 827 // @param needsHomeObject 828 // True if the constructor contains `super.foo` 829 [[nodiscard]] bool emitInitConstructor(bool needsHomeObject); 830 831 [[nodiscard]] bool prepareForMemberInitializers(size_t numInitializers, 832 bool isStatic); 833 [[nodiscard]] bool prepareForMemberInitializer(); 834 [[nodiscard]] bool emitMemberInitializerHomeObject(bool isStatic); 835 [[nodiscard]] bool emitStoreMemberInitializer(); 836 [[nodiscard]] bool emitMemberInitializersEnd(); 837 838 #ifdef ENABLE_DECORATORS 839 // TODO!: When we've enabled decorators, update the states and transition 840 // diagram to reflect this new state. 841 [[nodiscard]] bool prepareForExtraInitializers( 842 TaggedParserAtomIndex initializers); 843 #endif 844 845 [[nodiscard]] bool emitBinding(); 846 847 #ifdef ENABLE_DECORATORS 848 // TODO!: When we've enabled decorators, update the states and transition 849 // diagram to reflect this new state. 850 [[nodiscard]] bool prepareForDecorators(); 851 #endif 852 853 [[nodiscard]] bool emitEnd(Kind kind); 854 855 private: 856 [[nodiscard]] bool initProtoAndCtor(); 857 858 [[nodiscard]] bool leaveBodyAndInnerScope(); 859 }; 860 861 } /* namespace frontend */ 862 } /* namespace js */ 863 864 #endif /* frontend_ObjectEmitter_h */