ObjectEmitter.cpp (26207B)
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 #include "frontend/ObjectEmitter.h" 8 9 #include "mozilla/Assertions.h" // MOZ_ASSERT 10 11 #include "frontend/BytecodeEmitter.h" // BytecodeEmitter 12 #include "frontend/IfEmitter.h" // IfEmitter 13 #include "frontend/ParseNode.h" // AccessorType 14 #include "frontend/SharedContext.h" // SharedContext 15 #include "vm/FunctionPrefixKind.h" // FunctionPrefixKind 16 #include "vm/Opcodes.h" // JSOp 17 18 using namespace js; 19 using namespace js::frontend; 20 21 PropertyEmitter::PropertyEmitter(BytecodeEmitter* bce) : bce_(bce) {} 22 23 bool PropertyEmitter::prepareForProtoValue(uint32_t keyPos) { 24 MOZ_ASSERT(propertyState_ == PropertyState::Start || 25 propertyState_ == PropertyState::Init); 26 27 // [stack] CTOR? OBJ CTOR? 28 29 if (!bce_->updateSourceCoordNotes(keyPos)) { 30 return false; 31 } 32 33 #ifdef DEBUG 34 propertyState_ = PropertyState::ProtoValue; 35 #endif 36 return true; 37 } 38 39 bool PropertyEmitter::emitMutateProto() { 40 MOZ_ASSERT(propertyState_ == PropertyState::ProtoValue); 41 42 // [stack] OBJ PROTO 43 44 if (!bce_->emit1(JSOp::MutateProto)) { 45 // [stack] OBJ 46 return false; 47 } 48 49 #ifdef DEBUG 50 propertyState_ = PropertyState::Init; 51 #endif 52 return true; 53 } 54 55 bool PropertyEmitter::prepareForSpreadOperand(uint32_t spreadPos) { 56 MOZ_ASSERT(propertyState_ == PropertyState::Start || 57 propertyState_ == PropertyState::Init); 58 59 // [stack] OBJ 60 61 if (!bce_->updateSourceCoordNotes(spreadPos)) { 62 return false; 63 } 64 if (!bce_->emit1(JSOp::Dup)) { 65 // [stack] OBJ OBJ 66 return false; 67 } 68 69 #ifdef DEBUG 70 propertyState_ = PropertyState::SpreadOperand; 71 #endif 72 return true; 73 } 74 75 bool PropertyEmitter::emitSpread() { 76 MOZ_ASSERT(propertyState_ == PropertyState::SpreadOperand); 77 78 // [stack] OBJ OBJ VAL 79 80 if (!bce_->emitCopyDataProperties(BytecodeEmitter::CopyOption::Unfiltered)) { 81 // [stack] OBJ 82 return false; 83 } 84 85 #ifdef DEBUG 86 propertyState_ = PropertyState::Init; 87 #endif 88 return true; 89 } 90 91 MOZ_ALWAYS_INLINE bool PropertyEmitter::prepareForProp(uint32_t keyPos, 92 bool isStatic, 93 bool isIndexOrComputed) { 94 isStatic_ = isStatic; 95 isIndexOrComputed_ = isIndexOrComputed; 96 97 // [stack] CTOR? OBJ 98 99 if (!bce_->updateSourceCoordNotes(keyPos)) { 100 return false; 101 } 102 103 if (isStatic_) { 104 if (!bce_->emit1(JSOp::Dup2)) { 105 // [stack] CTOR HOMEOBJ CTOR HOMEOBJ 106 return false; 107 } 108 if (!bce_->emit1(JSOp::Pop)) { 109 // [stack] CTOR HOMEOBJ CTOR 110 return false; 111 } 112 } 113 114 return true; 115 } 116 117 bool PropertyEmitter::prepareForPrivateMethod() { 118 MOZ_ASSERT(propertyState_ == PropertyState::Start || 119 propertyState_ == PropertyState::Init); 120 MOZ_ASSERT(isClass_); 121 122 isStatic_ = false; 123 isIndexOrComputed_ = false; 124 125 #ifdef DEBUG 126 propertyState_ = PropertyState::PrivateMethodValue; 127 #endif 128 return true; 129 } 130 131 bool PropertyEmitter::prepareForPrivateStaticMethod(uint32_t keyPos) { 132 MOZ_ASSERT(propertyState_ == PropertyState::Start || 133 propertyState_ == PropertyState::Init); 134 MOZ_ASSERT(isClass_); 135 136 // [stack] CTOR OBJ 137 138 if (!prepareForProp(keyPos, 139 /* isStatic_ = */ true, 140 /* isIndexOrComputed = */ true)) { 141 // [stack] CTOR OBJ CTOR 142 return false; 143 } 144 145 #ifdef DEBUG 146 propertyState_ = PropertyState::PrivateStaticMethod; 147 #endif 148 return true; 149 } 150 151 bool PropertyEmitter::prepareForPropValue(uint32_t keyPos, Kind kind) { 152 MOZ_ASSERT(propertyState_ == PropertyState::Start || 153 propertyState_ == PropertyState::Init); 154 155 // [stack] CTOR? OBJ 156 157 if (!prepareForProp(keyPos, 158 /* isStatic_ = */ kind == Kind::Static, 159 /* isIndexOrComputed = */ false)) { 160 // [stack] CTOR? OBJ CTOR? 161 return false; 162 } 163 164 #ifdef DEBUG 165 propertyState_ = PropertyState::PropValue; 166 #endif 167 return true; 168 } 169 170 bool PropertyEmitter::prepareForIndexPropKey(uint32_t keyPos, Kind kind) { 171 MOZ_ASSERT(propertyState_ == PropertyState::Start || 172 propertyState_ == PropertyState::Init); 173 174 // [stack] CTOR? OBJ 175 176 if (!prepareForProp(keyPos, 177 /* isStatic_ = */ kind == Kind::Static, 178 /* isIndexOrComputed = */ true)) { 179 // [stack] CTOR? OBJ CTOR? 180 return false; 181 } 182 183 #ifdef DEBUG 184 propertyState_ = PropertyState::IndexKey; 185 #endif 186 return true; 187 } 188 189 bool PropertyEmitter::prepareForIndexPropValue() { 190 MOZ_ASSERT(propertyState_ == PropertyState::IndexKey); 191 192 // [stack] CTOR? OBJ CTOR? KEY 193 194 #ifdef DEBUG 195 propertyState_ = PropertyState::IndexValue; 196 #endif 197 return true; 198 } 199 200 bool PropertyEmitter::prepareForComputedPropKey(uint32_t keyPos, Kind kind) { 201 MOZ_ASSERT(propertyState_ == PropertyState::Start || 202 propertyState_ == PropertyState::Init); 203 204 // [stack] CTOR? OBJ 205 206 if (!prepareForProp(keyPos, 207 /* isStatic_ = */ kind == Kind::Static, 208 /* isIndexOrComputed = */ true)) { 209 // [stack] CTOR? OBJ CTOR? 210 return false; 211 } 212 213 #ifdef DEBUG 214 propertyState_ = PropertyState::ComputedKey; 215 #endif 216 return true; 217 } 218 219 bool PropertyEmitter::prepareForComputedPropValue() { 220 MOZ_ASSERT(propertyState_ == PropertyState::ComputedKey); 221 222 // [stack] CTOR? OBJ CTOR? KEY 223 224 if (!bce_->emit1(JSOp::ToPropertyKey)) { 225 // [stack] CTOR? OBJ CTOR? KEY 226 return false; 227 } 228 229 #ifdef DEBUG 230 propertyState_ = PropertyState::ComputedValue; 231 #endif 232 return true; 233 } 234 235 bool PropertyEmitter::emitInitHomeObject() { 236 MOZ_ASSERT(propertyState_ == PropertyState::PropValue || 237 propertyState_ == PropertyState::PrivateMethodValue || 238 propertyState_ == PropertyState::PrivateStaticMethod || 239 propertyState_ == PropertyState::IndexValue || 240 propertyState_ == PropertyState::ComputedValue); 241 242 // [stack] CTOR? HOMEOBJ CTOR? KEY? FUN 243 244 // There are the following values on the stack conditionally, between 245 // HOMEOBJ and FUN: 246 // * the 2nd CTOR if isStatic_ 247 // * KEY if isIndexOrComputed_ 248 // 249 // JSOp::InitHomeObject uses one of the following: 250 // * HOMEOBJ if !isStatic_ 251 // (`super.foo` points the super prototype property) 252 // * the 2nd CTOR if isStatic_ 253 // (`super.foo` points the super constructor property) 254 if (!bce_->emitDupAt(1 + isIndexOrComputed_)) { 255 // [stack] # non-static method 256 // [stack] CTOR? HOMEOBJ CTOR KEY? FUN CTOR 257 // [stack] # static method 258 // [stack] CTOR? HOMEOBJ KEY? FUN HOMEOBJ 259 return false; 260 } 261 if (!bce_->emit1(JSOp::InitHomeObject)) { 262 // [stack] CTOR? HOMEOBJ CTOR? KEY? FUN 263 return false; 264 } 265 266 #ifdef DEBUG 267 if (propertyState_ == PropertyState::PropValue) { 268 propertyState_ = PropertyState::InitHomeObj; 269 } else if (propertyState_ == PropertyState::PrivateMethodValue) { 270 propertyState_ = PropertyState::InitHomeObjForPrivateMethod; 271 } else if (propertyState_ == PropertyState::PrivateStaticMethod) { 272 propertyState_ = PropertyState::InitHomeObjForPrivateStaticMethod; 273 } else if (propertyState_ == PropertyState::IndexValue) { 274 propertyState_ = PropertyState::InitHomeObjForIndex; 275 } else { 276 propertyState_ = PropertyState::InitHomeObjForComputed; 277 } 278 #endif 279 return true; 280 } 281 282 bool PropertyEmitter::emitInit(AccessorType accessorType, 283 TaggedParserAtomIndex key) { 284 switch (accessorType) { 285 case AccessorType::None: 286 return emitInit(isClass_ ? JSOp::InitHiddenProp : JSOp::InitProp, key); 287 case AccessorType::Getter: 288 return emitInit( 289 isClass_ ? JSOp::InitHiddenPropGetter : JSOp::InitPropGetter, key); 290 case AccessorType::Setter: 291 return emitInit( 292 isClass_ ? JSOp::InitHiddenPropSetter : JSOp::InitPropSetter, key); 293 } 294 MOZ_CRASH("Invalid op"); 295 } 296 297 bool PropertyEmitter::emitInitIndexOrComputed(AccessorType accessorType) { 298 switch (accessorType) { 299 case AccessorType::None: 300 return emitInitIndexOrComputed(isClass_ ? JSOp::InitHiddenElem 301 : JSOp::InitElem); 302 case AccessorType::Getter: 303 return emitInitIndexOrComputed(isClass_ ? JSOp::InitHiddenElemGetter 304 : JSOp::InitElemGetter); 305 case AccessorType::Setter: 306 return emitInitIndexOrComputed(isClass_ ? JSOp::InitHiddenElemSetter 307 : JSOp::InitElemSetter); 308 } 309 MOZ_CRASH("Invalid op"); 310 } 311 312 bool PropertyEmitter::emitPrivateStaticMethod(AccessorType accessorType) { 313 MOZ_ASSERT(isClass_); 314 315 switch (accessorType) { 316 case AccessorType::None: 317 return emitInitIndexOrComputed(JSOp::InitLockedElem); 318 case AccessorType::Getter: 319 return emitInitIndexOrComputed(JSOp::InitHiddenElemGetter); 320 case AccessorType::Setter: 321 return emitInitIndexOrComputed(JSOp::InitHiddenElemSetter); 322 } 323 MOZ_CRASH("Invalid op"); 324 } 325 326 bool PropertyEmitter::emitInit(JSOp op, TaggedParserAtomIndex key) { 327 MOZ_ASSERT(propertyState_ == PropertyState::PropValue || 328 propertyState_ == PropertyState::InitHomeObj); 329 330 MOZ_ASSERT(op == JSOp::InitProp || op == JSOp::InitHiddenProp || 331 op == JSOp::InitPropGetter || op == JSOp::InitHiddenPropGetter || 332 op == JSOp::InitPropSetter || op == JSOp::InitHiddenPropSetter); 333 334 // [stack] CTOR? OBJ CTOR? VAL 335 336 if (!bce_->emitAtomOp(op, key)) { 337 // [stack] CTOR? OBJ CTOR? 338 return false; 339 } 340 341 if (!emitPopClassConstructor()) { 342 return false; 343 } 344 345 #ifdef DEBUG 346 propertyState_ = PropertyState::Init; 347 #endif 348 return true; 349 } 350 351 bool PropertyEmitter::skipInit() { 352 MOZ_ASSERT(propertyState_ == PropertyState::PrivateMethodValue || 353 propertyState_ == PropertyState::InitHomeObjForPrivateMethod); 354 #ifdef DEBUG 355 propertyState_ = PropertyState::Init; 356 #endif 357 return true; 358 } 359 360 bool PropertyEmitter::emitInitIndexOrComputed(JSOp op) { 361 MOZ_ASSERT(propertyState_ == PropertyState::IndexValue || 362 propertyState_ == PropertyState::InitHomeObjForIndex || 363 propertyState_ == PropertyState::ComputedValue || 364 propertyState_ == PropertyState::InitHomeObjForComputed || 365 propertyState_ == PropertyState::PrivateStaticMethod || 366 propertyState_ == 367 PropertyState::InitHomeObjForPrivateStaticMethod); 368 369 MOZ_ASSERT(op == JSOp::InitElem || op == JSOp::InitHiddenElem || 370 op == JSOp::InitLockedElem || op == JSOp::InitElemGetter || 371 op == JSOp::InitHiddenElemGetter || op == JSOp::InitElemSetter || 372 op == JSOp::InitHiddenElemSetter); 373 374 // [stack] CTOR? OBJ CTOR? KEY VAL 375 376 if (!bce_->emit1(op)) { 377 // [stack] CTOR? OBJ CTOR? 378 return false; 379 } 380 381 if (!emitPopClassConstructor()) { 382 return false; 383 } 384 385 #ifdef DEBUG 386 propertyState_ = PropertyState::Init; 387 #endif 388 return true; 389 } 390 391 bool PropertyEmitter::emitPopClassConstructor() { 392 if (isStatic_) { 393 // [stack] CTOR HOMEOBJ CTOR 394 395 if (!bce_->emit1(JSOp::Pop)) { 396 // [stack] CTOR HOMEOBJ 397 return false; 398 } 399 } 400 401 return true; 402 } 403 404 ObjectEmitter::ObjectEmitter(BytecodeEmitter* bce) : PropertyEmitter(bce) {} 405 406 bool ObjectEmitter::emitObject(size_t propertyCount) { 407 MOZ_ASSERT(propertyState_ == PropertyState::Start); 408 MOZ_ASSERT(objectState_ == ObjectState::Start); 409 410 // [stack] 411 412 // Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing 413 // a new object and defining (in source order) each property on the object 414 // (or mutating the object's [[Prototype]], in the case of __proto__). 415 uint8_t propCount = (propertyCount > 255) ? 255 : uint8_t(propertyCount); 416 if (!bce_->emit2(JSOp::NewInit, propCount)) { 417 // [stack] OBJ 418 return false; 419 } 420 421 #ifdef DEBUG 422 objectState_ = ObjectState::Object; 423 #endif 424 return true; 425 } 426 427 bool ObjectEmitter::emitObjectWithTemplateOnStack() { 428 MOZ_ASSERT(propertyState_ == PropertyState::Start); 429 MOZ_ASSERT(objectState_ == ObjectState::Start); 430 431 #ifdef DEBUG 432 objectState_ = ObjectState::Object; 433 #endif 434 return true; 435 } 436 437 bool ObjectEmitter::emitEnd() { 438 MOZ_ASSERT(propertyState_ == PropertyState::Start || 439 propertyState_ == PropertyState::Init); 440 MOZ_ASSERT(objectState_ == ObjectState::Object); 441 442 // [stack] OBJ 443 444 #ifdef DEBUG 445 objectState_ = ObjectState::End; 446 #endif 447 return true; 448 } 449 450 AutoSaveLocalStrictMode::AutoSaveLocalStrictMode(SharedContext* sc) : sc_(sc) { 451 savedStrictness_ = sc_->setLocalStrictMode(true); 452 } 453 454 AutoSaveLocalStrictMode::~AutoSaveLocalStrictMode() { 455 if (sc_) { 456 restore(); 457 } 458 } 459 460 void AutoSaveLocalStrictMode::restore() { 461 MOZ_ALWAYS_TRUE(sc_->setLocalStrictMode(savedStrictness_)); 462 sc_ = nullptr; 463 } 464 465 ClassEmitter::ClassEmitter(BytecodeEmitter* bce) 466 : PropertyEmitter(bce), strictMode_(bce->sc) { 467 isClass_ = true; 468 } 469 470 bool ClassEmitter::emitScope(LexicalScope::ParserData* scopeBindings) { 471 MOZ_ASSERT(propertyState_ == PropertyState::Start); 472 MOZ_ASSERT(classState_ == ClassState::Start); 473 474 tdzCache_.emplace(bce_); 475 476 innerScope_.emplace(bce_); 477 if (!innerScope_->enterLexical(bce_, ScopeKind::Lexical, scopeBindings)) { 478 return false; 479 } 480 481 #ifdef DEBUG 482 classState_ = ClassState::Scope; 483 #endif 484 485 return true; 486 } 487 488 bool ClassEmitter::emitBodyScope(ClassBodyScope::ParserData* scopeBindings) { 489 MOZ_ASSERT(propertyState_ == PropertyState::Start); 490 MOZ_ASSERT(classState_ == ClassState::Start || 491 classState_ == ClassState::Scope); 492 493 bodyTdzCache_.emplace(bce_); 494 495 bodyScope_.emplace(bce_); 496 if (!bodyScope_->enterClassBody(bce_, ScopeKind::ClassBody, scopeBindings)) { 497 return false; 498 } 499 500 #ifdef DEBUG 501 classState_ = ClassState::BodyScope; 502 #endif 503 504 return true; 505 } 506 507 bool ClassEmitter::emitClass(TaggedParserAtomIndex name, 508 TaggedParserAtomIndex nameForAnonymousClass, 509 bool hasNameOnStack, uint8_t membersCount) { 510 MOZ_ASSERT(propertyState_ == PropertyState::Start); 511 MOZ_ASSERT(classState_ == ClassState::Start || 512 classState_ == ClassState::Scope || 513 classState_ == ClassState::BodyScope); 514 MOZ_ASSERT_IF(nameForAnonymousClass || hasNameOnStack, !name); 515 MOZ_ASSERT(!(nameForAnonymousClass && hasNameOnStack)); 516 517 // [stack] 518 519 name_ = name; 520 nameForAnonymousClass_ = nameForAnonymousClass; 521 hasNameOnStack_ = hasNameOnStack; 522 isDerived_ = false; 523 524 if (!bce_->emit2(JSOp::NewInit, membersCount)) { 525 // [stack] HOMEOBJ 526 return false; 527 } 528 529 #ifdef DEBUG 530 classState_ = ClassState::Class; 531 #endif 532 return true; 533 } 534 535 bool ClassEmitter::emitDerivedClass(TaggedParserAtomIndex name, 536 TaggedParserAtomIndex nameForAnonymousClass, 537 bool hasNameOnStack) { 538 MOZ_ASSERT(propertyState_ == PropertyState::Start); 539 MOZ_ASSERT(classState_ == ClassState::Start || 540 classState_ == ClassState::Scope || 541 classState_ == ClassState::BodyScope); 542 MOZ_ASSERT_IF(nameForAnonymousClass || hasNameOnStack, !name); 543 MOZ_ASSERT(!nameForAnonymousClass || !hasNameOnStack); 544 545 // [stack] HERITAGE 546 547 name_ = name; 548 nameForAnonymousClass_ = nameForAnonymousClass; 549 hasNameOnStack_ = hasNameOnStack; 550 isDerived_ = true; 551 552 InternalIfEmitter ifThenElse(bce_); 553 554 // Heritage must be null or a non-generator constructor 555 if (!bce_->emit1(JSOp::CheckClassHeritage)) { 556 // [stack] HERITAGE 557 return false; 558 } 559 560 // [IF] (heritage !== null) 561 if (!bce_->emit1(JSOp::Dup)) { 562 // [stack] HERITAGE HERITAGE 563 return false; 564 } 565 if (!bce_->emit1(JSOp::Null)) { 566 // [stack] HERITAGE HERITAGE NULL 567 return false; 568 } 569 if (!bce_->emit1(JSOp::StrictNe)) { 570 // [stack] HERITAGE NE 571 return false; 572 } 573 574 // [THEN] funProto = heritage, objProto = heritage.prototype 575 if (!ifThenElse.emitThenElse()) { 576 return false; 577 } 578 if (!bce_->emit1(JSOp::Dup)) { 579 // [stack] HERITAGE HERITAGE 580 return false; 581 } 582 if (!bce_->emitAtomOp(JSOp::GetProp, 583 TaggedParserAtomIndex::WellKnown::prototype())) { 584 // [stack] HERITAGE PROTO 585 return false; 586 } 587 588 // [ELSE] funProto = %FunctionPrototype%, objProto = null 589 if (!ifThenElse.emitElse()) { 590 return false; 591 } 592 if (!bce_->emit1(JSOp::Pop)) { 593 // [stack] 594 return false; 595 } 596 if (!bce_->emitBuiltinObject(BuiltinObjectKind::FunctionPrototype)) { 597 // [stack] PROTO 598 return false; 599 } 600 if (!bce_->emit1(JSOp::Null)) { 601 // [stack] PROTO NULL 602 return false; 603 } 604 605 // [ENDIF] 606 if (!ifThenElse.emitEnd()) { 607 return false; 608 } 609 610 if (!bce_->emit1(JSOp::ObjWithProto)) { 611 // [stack] HERITAGE HOMEOBJ 612 return false; 613 } 614 if (!bce_->emit1(JSOp::Swap)) { 615 // [stack] HOMEOBJ HERITAGE 616 return false; 617 } 618 619 #ifdef DEBUG 620 classState_ = ClassState::Class; 621 #endif 622 return true; 623 } 624 625 bool ClassEmitter::emitInitConstructor(bool needsHomeObject) { 626 MOZ_ASSERT(classState_ == ClassState::Class || 627 classState_ == ClassState::InstanceMemberInitializersEnd); 628 629 // [stack] HOMEOBJ CTOR 630 631 if (needsHomeObject) { 632 if (!bce_->emitDupAt(1)) { 633 // [stack] HOMEOBJ CTOR HOMEOBJ 634 return false; 635 } 636 if (!bce_->emit1(JSOp::InitHomeObject)) { 637 // [stack] HOMEOBJ CTOR 638 return false; 639 } 640 } 641 642 if (!initProtoAndCtor()) { 643 // [stack] CTOR HOMEOBJ 644 return false; 645 } 646 647 #ifdef DEBUG 648 classState_ = ClassState::InitConstructor; 649 #endif 650 return true; 651 } 652 653 bool ClassEmitter::initProtoAndCtor() { 654 // [stack] NAME? HOMEOBJ CTOR 655 656 if (hasNameOnStack_) { 657 if (!bce_->emitDupAt(2)) { 658 // [stack] NAME HOMEOBJ CTOR NAME 659 return false; 660 } 661 if (!bce_->emit2(JSOp::SetFunName, uint8_t(FunctionPrefixKind::None))) { 662 // [stack] NAME HOMEOBJ CTOR 663 return false; 664 } 665 } 666 667 if (!bce_->emit1(JSOp::Swap)) { 668 // [stack] NAME? CTOR HOMEOBJ 669 return false; 670 } 671 if (!bce_->emit1(JSOp::Dup2)) { 672 // [stack] NAME? CTOR HOMEOBJ CTOR HOMEOBJ 673 return false; 674 } 675 if (!bce_->emitAtomOp(JSOp::InitLockedProp, 676 TaggedParserAtomIndex::WellKnown::prototype())) { 677 // [stack] NAME? CTOR HOMEOBJ CTOR 678 return false; 679 } 680 if (!bce_->emitAtomOp(JSOp::InitHiddenProp, 681 TaggedParserAtomIndex::WellKnown::constructor())) { 682 // [stack] NAME? CTOR HOMEOBJ 683 return false; 684 } 685 686 return true; 687 } 688 689 bool ClassEmitter::prepareForMemberInitializers(size_t numInitializers, 690 bool isStatic) { 691 MOZ_ASSERT_IF(!isStatic, classState_ == ClassState::Class); 692 MOZ_ASSERT_IF(isStatic, classState_ == ClassState::InitConstructor); 693 MOZ_ASSERT(memberState_ == MemberState::Start); 694 695 // .initializers is a variable that stores an array of lambdas containing 696 // code (the initializer) for each field. Upon an object's construction, 697 // these lambdas will be called, defining the values. 698 auto initializers = 699 isStatic ? TaggedParserAtomIndex::WellKnown::dot_staticInitializers_() 700 : TaggedParserAtomIndex::WellKnown::dot_initializers_(); 701 initializersAssignment_.emplace(bce_, initializers, 702 NameOpEmitter::Kind::Initialize); 703 if (!initializersAssignment_->prepareForRhs()) { 704 return false; 705 } 706 707 if (!bce_->emitUint32Operand(JSOp::NewArray, numInitializers)) { 708 // [stack] ARRAY 709 return false; 710 } 711 712 initializerIndex_ = 0; 713 #ifdef DEBUG 714 if (isStatic) { 715 classState_ = ClassState::StaticMemberInitializers; 716 } else { 717 classState_ = ClassState::InstanceMemberInitializers; 718 } 719 numInitializers_ = numInitializers; 720 #endif 721 return true; 722 } 723 724 bool ClassEmitter::prepareForMemberInitializer() { 725 MOZ_ASSERT(classState_ == ClassState::InstanceMemberInitializers || 726 classState_ == ClassState::StaticMemberInitializers); 727 MOZ_ASSERT(memberState_ == MemberState::Start); 728 729 #ifdef DEBUG 730 memberState_ = MemberState::Initializer; 731 #endif 732 return true; 733 } 734 735 bool ClassEmitter::emitMemberInitializerHomeObject(bool isStatic) { 736 MOZ_ASSERT(memberState_ == MemberState::Initializer); 737 // [stack] OBJ HERITAGE? ARRAY METHOD 738 // or: 739 // [stack] CTOR HOMEOBJ ARRAY METHOD 740 741 if (isStatic) { 742 if (!bce_->emitDupAt(3)) { 743 // [stack] CTOR HOMEOBJ ARRAY METHOD CTOR 744 return false; 745 } 746 } else { 747 if (!bce_->emitDupAt(isDerived_ ? 3 : 2)) { 748 // [stack] OBJ HERITAGE? ARRAY METHOD OBJ 749 return false; 750 } 751 } 752 if (!bce_->emit1(JSOp::InitHomeObject)) { 753 // [stack] OBJ HERITAGE? ARRAY METHOD 754 // or: 755 // [stack] CTOR HOMEOBJ ARRAY METHOD 756 return false; 757 } 758 759 #ifdef DEBUG 760 memberState_ = MemberState::InitializerWithHomeObject; 761 #endif 762 return true; 763 } 764 765 bool ClassEmitter::emitStoreMemberInitializer() { 766 MOZ_ASSERT(memberState_ == MemberState::Initializer || 767 memberState_ == MemberState::InitializerWithHomeObject); 768 MOZ_ASSERT(initializerIndex_ < numInitializers_); 769 // [stack] HOMEOBJ HERITAGE? ARRAY METHOD 770 771 if (!bce_->emitUint32Operand(JSOp::InitElemArray, initializerIndex_)) { 772 // [stack] HOMEOBJ HERITAGE? ARRAY 773 return false; 774 } 775 776 initializerIndex_++; 777 #ifdef DEBUG 778 memberState_ = MemberState::Start; 779 #endif 780 return true; 781 } 782 783 bool ClassEmitter::emitMemberInitializersEnd() { 784 MOZ_ASSERT(propertyState_ == PropertyState::Start || 785 propertyState_ == PropertyState::Init); 786 MOZ_ASSERT(classState_ == ClassState::InstanceMemberInitializers || 787 classState_ == ClassState::StaticMemberInitializers); 788 MOZ_ASSERT(memberState_ == MemberState::Start); 789 MOZ_ASSERT(initializerIndex_ == numInitializers_); 790 791 if (!initializersAssignment_->emitAssignment()) { 792 // [stack] HOMEOBJ HERITAGE? ARRAY 793 return false; 794 } 795 initializersAssignment_.reset(); 796 797 if (!bce_->emit1(JSOp::Pop)) { 798 // [stack] HOMEOBJ HERITAGE? 799 return false; 800 } 801 802 #ifdef DEBUG 803 if (classState_ == ClassState::InstanceMemberInitializers) { 804 classState_ = ClassState::InstanceMemberInitializersEnd; 805 } else { 806 classState_ = ClassState::StaticMemberInitializersEnd; 807 } 808 #endif 809 return true; 810 } 811 812 #ifdef ENABLE_DECORATORS 813 bool ClassEmitter::prepareForExtraInitializers( 814 TaggedParserAtomIndex initializers) { 815 // TODO: Add support for static and class extra initializers, see bug 1868220 816 // and bug 1868221. 817 MOZ_ASSERT( 818 initializers == 819 TaggedParserAtomIndex::WellKnown::dot_instanceExtraInitializers_()); 820 821 NameOpEmitter noe(bce_, initializers, NameOpEmitter::Kind::Initialize); 822 if (!noe.prepareForRhs()) { 823 return false; 824 } 825 826 // Because the initializers are created while executing decorators, we don't 827 // know beforehand how many there will be. 828 if (!bce_->emitUint32Operand(JSOp::NewArray, 0)) { 829 // [stack] ARRAY 830 return false; 831 } 832 833 if (!noe.emitAssignment()) { 834 // [stack] ARRAY 835 return false; 836 } 837 838 return bce_->emit1(JSOp::Pop); 839 // [stack] 840 } 841 #endif 842 843 bool ClassEmitter::emitBinding() { 844 MOZ_ASSERT(propertyState_ == PropertyState::Start || 845 propertyState_ == PropertyState::Init); 846 MOZ_ASSERT(classState_ == ClassState::InitConstructor || 847 classState_ == ClassState::InstanceMemberInitializersEnd || 848 classState_ == ClassState::StaticMemberInitializersEnd); 849 // [stack] CTOR HOMEOBJ 850 851 if (!bce_->emit1(JSOp::Pop)) { 852 // [stack] CTOR 853 return false; 854 } 855 856 if (name_) { 857 MOZ_ASSERT(innerScope_.isSome()); 858 859 if (!bce_->emitLexicalInitialization(name_)) { 860 // [stack] CTOR 861 return false; 862 } 863 } 864 865 // [stack] CTOR 866 867 #ifdef DEBUG 868 classState_ = ClassState::BoundName; 869 #endif 870 return true; 871 } 872 873 #ifdef ENABLE_DECORATORS 874 bool ClassEmitter::prepareForDecorators() { return leaveBodyAndInnerScope(); } 875 #endif 876 877 bool ClassEmitter::leaveBodyAndInnerScope() { 878 if (bodyScope_.isSome()) { 879 MOZ_ASSERT(bodyTdzCache_.isSome()); 880 881 if (!bodyScope_->leave(bce_)) { 882 return false; 883 } 884 bodyScope_.reset(); 885 bodyTdzCache_.reset(); 886 } 887 888 if (innerScope_.isSome()) { 889 MOZ_ASSERT(tdzCache_.isSome()); 890 891 if (!innerScope_->leave(bce_)) { 892 return false; 893 } 894 innerScope_.reset(); 895 tdzCache_.reset(); 896 } else { 897 MOZ_ASSERT(tdzCache_.isNothing()); 898 } 899 900 return true; 901 } 902 903 bool ClassEmitter::emitEnd(Kind kind) { 904 MOZ_ASSERT(classState_ == ClassState::BoundName); 905 // [stack] CTOR 906 907 #ifndef ENABLE_DECORATORS 908 if (!leaveBodyAndInnerScope()) { 909 return false; 910 } 911 #endif 912 913 if (kind == Kind::Declaration) { 914 MOZ_ASSERT(name_); 915 916 if (!bce_->emitLexicalInitialization(name_)) { 917 // [stack] CTOR 918 return false; 919 } 920 // Only class statements make outer bindings, and they do not leave 921 // themselves on the stack. 922 if (!bce_->emit1(JSOp::Pop)) { 923 // [stack] 924 return false; 925 } 926 } 927 928 // [stack] # class declaration 929 // [stack] 930 // [stack] # class expression 931 // [stack] CTOR 932 933 strictMode_.restore(); 934 935 #ifdef DEBUG 936 classState_ = ClassState::End; 937 #endif 938 return true; 939 }