DecoratorEmitter.cpp (45884B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "frontend/DecoratorEmitter.h" 6 7 #include "mozilla/Assertions.h" 8 9 #include "frontend/BytecodeEmitter.h" 10 #include "frontend/CallOrNewEmitter.h" 11 #include "frontend/FunctionEmitter.h" 12 #include "frontend/IfEmitter.h" 13 #include "frontend/LexicalScopeEmitter.h" 14 #include "frontend/NameAnalysisTypes.h" 15 #include "frontend/ObjectEmitter.h" 16 #include "frontend/ParseNode.h" 17 #include "frontend/ParserAtom.h" 18 #include "frontend/WhileEmitter.h" 19 #include "vm/ThrowMsgKind.h" 20 21 using namespace js; 22 using namespace js::frontend; 23 24 DecoratorEmitter::DecoratorEmitter(BytecodeEmitter* bce) : bce_(bce) {} 25 26 // A helper function to read the decorators in reverse order to how they were 27 // parsed. 28 bool DecoratorEmitter::reverseDecoratorsToApplicationOrder( 29 const ListNode* decorators, DecoratorsVector& vec) const { 30 MOZ_ASSERT(!decorators->empty()); 31 if (!vec.resize(decorators->count())) { 32 ReportOutOfMemory(bce_->fc); 33 return false; 34 } 35 int end = decorators->count() - 1; 36 for (ParseNode* decorator : decorators->contents()) { 37 vec[end--] = decorator; 38 } 39 return true; 40 } 41 42 bool DecoratorEmitter::emitApplyDecoratorsToElementDefinition( 43 DecoratorEmitter::Kind kind, ParseNode* key, ListNode* decorators, 44 bool isStatic) { 45 MOZ_ASSERT(kind != Kind::Field && kind != Kind::Accessor); 46 47 // The DecoratorEmitter expects the value to be decorated to be at the top 48 // of the stack prior to this call. It will apply the decorators to this 49 // value, possibly replacing the value with a value returned by a decorator. 50 // [stack] ADDINIT VAL 51 52 // Decorators Proposal 53 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-applydecoratorstoelementdefinition. 54 // Step 1. Let decorators be elementRecord.[[Decorators]]. 55 // Step 2. If decorators is empty, return unused. 56 // This is checked by the caller. 57 MOZ_ASSERT(!decorators->empty()); 58 59 DecoratorsVector dec_vecs; 60 if (!reverseDecoratorsToApplicationOrder(decorators, dec_vecs)) { 61 return false; 62 } 63 64 // Step 3. Let key be elementRecord.[[Key]]. 65 // Step 4. Let kind be elementRecord.[[Kind]]. 66 // Step 5. For each element decorator of decorators, do 67 for (auto decorator : dec_vecs) { 68 // Step 5.a. Let decorationState be the Record { [[Finished]]: false }. 69 if (!emitDecorationState()) { 70 return false; 71 } 72 73 // TODO: See Bug 1869000 to support addInitializer for methods. 74 if (!bce_->emitDupAt(1)) { 75 // [stack] ADDINIT VAL ADDINIT 76 return false; 77 } 78 79 if (!emitCallDecoratorForElement(kind, key, isStatic, decorator)) { 80 // [stack] ADDINIT RETVAL 81 return false; 82 } 83 84 // Step 5.i. Set decorationState.[[Finished]] to true. 85 if (!emitUpdateDecorationState()) { 86 return false; 87 } 88 89 // We need to check if the decorator returned undefined, a callable value, 90 // or any other value. 91 if (!emitCheckIsUndefined()) { 92 // [stack] ADDINIT VAL RETVAL ISUNDEFINED 93 return false; 94 } 95 96 InternalIfEmitter ie(bce_); 97 if (!ie.emitThenElse()) { 98 // [stack] ADDINIT VAL RETVAL 99 return false; 100 } 101 102 // Pop the undefined RETVAL from the stack, leaving the original value in 103 // place. 104 if (!bce_->emitPopN(1)) { 105 // [stack] ADDINIT VAL 106 return false; 107 } 108 109 if (!ie.emitElseIf(mozilla::Nothing())) { 110 return false; 111 } 112 113 // Step 5.l.i. If IsCallable(newValue) is true, then 114 if (!bce_->emitCheckIsCallable()) { 115 // [stack] ADDINIT VAL RETVAL ISCALLABLE_RESULT 116 return false; 117 } 118 119 if (!ie.emitThenElse()) { 120 // [stack] ADDINIT VAL RETVAL 121 return false; 122 } 123 // Step 5.l. Else, 124 // Step 5.l.i.1. Perform MakeMethod(newValue, homeObject). 125 // MakeMethod occurs in the caller, here we just drop the original method 126 // which was an argument to the decorator, and leave the new method 127 // returned by the decorator on the stack. 128 if (!bce_->emit1(JSOp::Swap)) { 129 // [stack] ADDINIT RETVAL VAL 130 return false; 131 } 132 if (!bce_->emitPopN(1)) { 133 // [stack] ADDINIT RETVAL 134 return false; 135 } 136 // Step 5.j.ii. Else if initializer is not undefined, throw a TypeError 137 // exception. 138 // Step 5.l.ii. Else if newValue is not undefined, throw a 139 // TypeError exception. 140 if (!ie.emitElse()) { 141 return false; 142 } 143 144 if (!bce_->emitPopN(1)) { 145 // [stack] ADDINIT RETVAL 146 return false; 147 } 148 149 if (!bce_->emit2(JSOp::ThrowMsg, 150 uint8_t(ThrowMsgKind::DecoratorInvalidReturnType))) { 151 return false; 152 } 153 154 if (!ie.emitEnd()) { 155 return false; 156 } 157 } 158 159 return true; 160 // [stack] ADDINIT RETVAL 161 } 162 163 bool DecoratorEmitter::emitApplyDecoratorsToFieldDefinition( 164 ParseNode* key, ListNode* decorators, bool isStatic) { 165 // This method creates a new array to contain initializers added by decorators 166 // to the stack. start: 167 // [stack] ADDINIT 168 // end: 169 // [stack] ADDINIT ARRAY 170 171 // Decorators Proposal 172 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-applydecoratorstoelementdefinition. 173 // Step 1. Let decorators be elementRecord.[[Decorators]]. 174 // Step 2. If decorators is empty, return unused. 175 // This is checked by the caller. 176 MOZ_ASSERT(!decorators->empty()); 177 178 // If we're apply decorators to a field, we'll push a new array to the stack 179 // to hold newly created initializers. 180 if (!bce_->emitUint32Operand(JSOp::NewArray, 1)) { 181 // [stack] ADDINIT ARRAY 182 return false; 183 } 184 185 if (!emitPropertyKey(key)) { 186 // [stack] ADDINIT ARRAY NAME 187 return false; 188 } 189 190 if (!bce_->emitUint32Operand(JSOp::InitElemArray, 0)) { 191 // [stack] ADDINIT ARRAY 192 return false; 193 } 194 195 if (!bce_->emit1(JSOp::One)) { 196 // [stack] ADDINIT ARRAY INDEX 197 return false; 198 } 199 200 DecoratorsVector dec_vecs; 201 if (!reverseDecoratorsToApplicationOrder(decorators, dec_vecs)) { 202 return false; 203 } 204 205 // Step 3. Let key be elementRecord.[[Key]]. 206 // Step 4. Let kind be elementRecord.[[Kind]]. 207 // Step 5. For each element decorator of decorators, do 208 for (auto it = dec_vecs.begin(); it != dec_vecs.end(); it++) { 209 ParseNode* decorator = *it; 210 // Step 5.a. Let decorationState be the Record { [[Finished]]: false }. 211 if (!emitDecorationState()) { 212 return false; 213 } 214 215 if (!bce_->emitDupAt(2)) { 216 // [stack] ADDINIT ARRAY INDEX ADDINIT 217 return false; 218 } 219 220 if (!emitCallDecoratorForElement(Kind::Field, key, isStatic, decorator)) { 221 // [stack] ADDINIT ARRAY INDEX RETVAL 222 return false; 223 } 224 225 // Step 5.i. Set decorationState.[[Finished]] to true. 226 if (!emitUpdateDecorationState()) { 227 // [stack] ADDINIT ARRAY INDEX RETVAL 228 return false; 229 } 230 231 // We need to check if the decorator returned undefined, a callable value, 232 // or any other value. 233 if (!emitCheckIsUndefined()) { 234 // [stack] ADDINIT ARRAY INDEX RETVAL ISUNDEFINED 235 return false; 236 } 237 238 InternalIfEmitter ie(bce_); 239 if (!ie.emitThenElse()) { 240 // [stack] ADDINIT ARRAY INDEX RETVAL 241 return false; 242 } 243 244 // Pop the undefined RETVAL from the stack, leaving the original value in 245 // place. 246 if (!bce_->emitPopN(1)) { 247 // [stack] ADDINIT ARRAY INDEX 248 return false; 249 } 250 251 if (!ie.emitElseIf(mozilla::Nothing())) { 252 return false; 253 } 254 255 // Step 5.l.i. If IsCallable(newValue) is true, then 256 257 if (!bce_->emitCheckIsCallable()) { 258 // [stack] ARRAY INDEX RETVAL ISCALLABLE_RESULT 259 return false; 260 } 261 262 if (!ie.emitThenElse()) { 263 // [stack] ADDINIT ARRAY INDEX RETVAL 264 return false; 265 } 266 267 // Step 5.j. If kind is field, then 268 // Step 5.j.i. If IsCallable(initializer) is true, append initializer to 269 // elementRecord.[[Initializers]]. 270 if (!bce_->emit1(JSOp::InitElemInc)) { 271 // [stack] ADDINIT ARRAY INDEX 272 return false; 273 } 274 275 // Step 5.j.ii. Else if initializer is not undefined, throw a TypeError 276 // exception. 277 // Step 5.l.ii. Else if newValue is not undefined, throw a 278 // TypeError exception. 279 if (!ie.emitElse()) { 280 return false; 281 } 282 283 if (!bce_->emitPopN(1)) { 284 // [stack] ADDINIT ARRAY INDEX 285 return false; 286 } 287 288 if (!bce_->emit2(JSOp::ThrowMsg, 289 uint8_t(ThrowMsgKind::DecoratorInvalidReturnType))) { 290 return false; 291 } 292 293 if (!ie.emitEnd()) { 294 return false; 295 } 296 } 297 298 // Pop INDEX 299 return bce_->emitPopN(1); 300 // [stack] ADDINIT ARRAY 301 } 302 303 bool DecoratorEmitter::emitApplyDecoratorsToAccessorDefinition( 304 ParseNode* key, ListNode* decorators, bool isStatic) { 305 // This method creates a new array to contain initializers added by decorators 306 // to the stack. start: 307 // [stack] ADDINIT GETTER SETTER 308 // end: 309 // [stack] ADDINIT GETTER SETTER ARRAY 310 MOZ_ASSERT(key->is<NameNode>()); 311 312 // Decorators Proposal 313 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-applydecoratorstoelementdefinition. 314 // Step 1. Let decorators be elementRecord.[[Decorators]]. 315 // Step 2. If decorators is empty, return unused. 316 // This is checked by the caller. 317 MOZ_ASSERT(!decorators->empty()); 318 319 // If we're applying decorators to a field, we'll push a new array to the 320 // stack to hold newly created initializers. 321 if (!bce_->emitUint32Operand(JSOp::NewArray, 1)) { 322 // [stack] ADDINIT GETTER SETTER ARRAY 323 return false; 324 } 325 326 if (!bce_->emitGetPrivateName(&key->as<NameNode>())) { 327 // [stack] ADDINIT GETTER SETTER ARRAY NAME 328 return false; 329 } 330 331 if (!bce_->emitUint32Operand(JSOp::InitElemArray, 0)) { 332 // [stack] ADDINIT GETTER SETTER ARRAY 333 return false; 334 } 335 336 if (!bce_->emit1(JSOp::One)) { 337 // [stack] ADDINIT GETTER SETTER ARRAY INDEX 338 return false; 339 } 340 341 DecoratorsVector dec_vecs; 342 if (!reverseDecoratorsToApplicationOrder(decorators, dec_vecs)) { 343 return false; 344 } 345 346 // Step 3. Let key be elementRecord.[[Key]]. 347 // Step 4. Let kind be elementRecord.[[Kind]]. 348 // Step 5. For each element decorator of decorators, do 349 for (auto it = dec_vecs.begin(); it != dec_vecs.end(); it++) { 350 ParseNode* decorator = *it; 351 // 5.a. Let decorationState be the Record { [[Finished]]: false }. 352 if (!emitDecorationState()) { 353 return false; 354 } 355 356 // Step 5.g.i. Set value to OrdinaryObjectCreate(%Object.prototype%). 357 ObjectEmitter oe(bce_); 358 if (!oe.emitObject(2)) { 359 // [stack] ADDINIT GETTER SETTER ARRAY INDEX VALUE 360 return false; 361 } 362 363 // Step 5.g.ii. Perform ! CreateDataPropertyOrThrow(value, "get", 364 // elementRecord.[[Get]]). 365 if (!oe.prepareForPropValue(decorator->pn_pos.begin, 366 PropertyEmitter::Kind::Prototype)) { 367 return false; 368 } 369 if (!bce_->emitDupAt(4)) { 370 // [stack] ADDINIT GETTER SETTER ARRAY INDEX VALUE GETTER 371 return false; 372 } 373 if (!oe.emitInit(frontend::AccessorType::None, 374 frontend::TaggedParserAtomIndex::WellKnown::get())) { 375 // [stack] ADDINIT GETTER SETTER ARRAY INDEX VALUE 376 return false; 377 } 378 379 // Step 5.g.iii. Perform ! CreateDataPropertyOrThrow(value, "set", 380 // elementRecord.[[Set]]). 381 if (!oe.prepareForPropValue(decorator->pn_pos.begin, 382 PropertyEmitter::Kind::Prototype)) { 383 return false; 384 } 385 if (!bce_->emitDupAt(3)) { 386 // [stack] ADDINIT GETTER SETTER ARRAY INDEX VALUE SETTER 387 return false; 388 } 389 if (!oe.emitInit(frontend::AccessorType::None, 390 frontend::TaggedParserAtomIndex::WellKnown::set())) { 391 // [stack] ADDINIT GETTER SETTER ARRAY INDEX VALUE 392 return false; 393 } 394 395 if (!oe.emitEnd()) { 396 // [stack] ADDINIT GETTER SETTER ARRAY INDEX VALUE 397 return false; 398 } 399 400 if (!bce_->emitDupAt(5)) { 401 // [stack] ADDINIT GETTER SETTER ARRAY INDEX VALUE ADDINIT 402 return false; 403 } 404 405 // Step 5.j. Let newValue be ? Call(decorator, decoratorReceiver, 406 // « value, context »). 407 if (!emitCallDecoratorForElement(Kind::Accessor, key, isStatic, 408 decorator)) { 409 // [stack] ADDINIT GETTER SETTER ARRAY INDEX RETVAL 410 return false; 411 } 412 413 // Step 5.k. Set decorationState.[[Finished]] to true. 414 if (!emitUpdateDecorationState()) { 415 // [stack] ADDINIT GETTER SETTER ARRAY INDEX RETVAL 416 return false; 417 } 418 419 // We need to check if the decorator returned undefined, a callable value, 420 // or any other value. 421 if (!emitCheckIsUndefined()) { 422 // [stack] ADDINIT GETTER SETTER ARRAY INDEX RETVAL ISUNDEFINED 423 return false; 424 } 425 426 InternalIfEmitter ie(bce_); 427 if (!ie.emitThenElse()) { 428 // [stack] ADDINIT GETTER SETTER ARRAY INDEX RETVAL 429 return false; 430 } 431 432 // Pop the undefined RETVAL from the stack, leaving the original values in 433 // place. 434 if (!bce_->emitPopN(1)) { 435 // [stack] ADDINIT GETTER SETTER ARRAY INDEX 436 return false; 437 } 438 439 if (!ie.emitElse()) { 440 return false; 441 } 442 443 // Step 5.k. Else if kind is accessor, then 444 // Step 5.k.ii. Else if newValue is not undefined, throw a TypeError 445 // exception. (Reordered) 446 if (!bce_->emit2(JSOp::CheckIsObj, 447 uint8_t(CheckIsObjectKind::DecoratorReturn))) { 448 // [stack] ADDINIT GETTER SETTER ARRAY INDEX RETVAL 449 return false; 450 } 451 452 // Step 5.k.i. If newValue is an Object, then 453 // Step 5.k.i.1. Let newGetter be ? Get(newValue, "get"). 454 // Step 5.k.i.2. If IsCallable(newGetter) is true, set 455 // elementRecord.[[Get]] to newGetter. 456 // Step 5.k.i.3. Else if newGetter is not undefined, throw a 457 // TypeError exception. 458 if (!emitHandleNewValueField( 459 frontend::TaggedParserAtomIndex::WellKnown::get(), 5)) { 460 return false; 461 } 462 463 // Step 5.k.i.4. Let newSetter be ? Get(newValue, "set"). 464 // Step 5.k.i.5. If IsCallable(newSetter) is true, set 465 // elementRecord.[[Set]] to newSetter. 466 // Step 5.k.i.6. Else if newSetter is not undefined, throw a 467 // TypeError exception. 468 if (!emitHandleNewValueField( 469 frontend::TaggedParserAtomIndex::WellKnown::set(), 4)) { 470 return false; 471 } 472 473 // Step 5.k.i.7. Let initializer be ? Get(newValue, "init"). 474 // Step 5.k.i.8. If IsCallable(initializer) is true, append 475 // initializer to elementRecord.[[Initializers]]. 476 // Step 5.k.i.9. Else if initializer is not undefined, throw a 477 // TypeError exception. 478 if (!emitHandleNewValueField( 479 frontend::TaggedParserAtomIndex::WellKnown::init(), 0)) { 480 return false; 481 } 482 483 // Pop RETVAL from stack 484 if (!bce_->emitPopN(1)) { 485 // [stack] ADDINIT GETTER SETTER ARRAY INDEX 486 return false; 487 } 488 489 if (!ie.emitEnd()) { 490 return false; 491 } 492 } 493 494 // Pop INDEX 495 return bce_->emitPopN(1); 496 // [stack] ADDINIT GETTER SETTER ARRAY 497 } 498 499 bool DecoratorEmitter::emitApplyDecoratorsToClassDefinition( 500 ParseNode* key, ListNode* decorators) { 501 // This function expects a class constructor to already be on the stack. It 502 // applies each decorator to the class constructor, possibly replacing it with 503 // the return value of the decorator. 504 // [stack] CTOR 505 506 DecoratorsVector dec_vecs; 507 if (!reverseDecoratorsToApplicationOrder(decorators, dec_vecs)) { 508 return false; 509 } 510 511 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-applydecoratorstoclassdefinition 512 // Step 1. For each element decoratorRecord of decorators, do 513 for (auto it = dec_vecs.begin(); it != dec_vecs.end(); it++) { 514 ParseNode* decorator = *it; 515 // Step 1.a. Let decorator be decoratorRecord.[[Decorator]]. 516 // Step 1.b. Let decoratorReceiver be decoratorRecord.[[Receiver]]. 517 // Step 1.c. Let decorationState be the Record { [[Finished]]: false }. 518 if (!emitDecorationState()) { 519 return false; 520 } 521 522 CallOrNewEmitter cone(bce_, JSOp::Call, 523 CallOrNewEmitter::ArgumentsKind::Other, 524 ValueUsage::WantValue); 525 526 if (!bce_->emitCalleeAndThis(decorator, nullptr, cone)) { 527 // [stack] VAL? CALLEE THIS 528 return false; 529 } 530 531 if (!cone.prepareForNonSpreadArguments()) { 532 return false; 533 } 534 535 // Duplicate the class definition to pass it as an argument 536 // to the decorator. 537 if (!bce_->emitDupAt(2)) { 538 // [stack] CTOR CALLEE THIS CTOR 539 return false; 540 } 541 542 // Step 1.d. Let context be CreateDecoratorContextObject(class, className, 543 // extraInitializers, decorationState). 544 // TODO: See Bug 1868221 for support for addInitializer for class 545 // decorators. 546 if (!bce_->emit1(JSOp::Undefined)) { 547 // [stack] CTOR CALLEE THIS CTOR ADDINIT 548 return false; 549 } 550 if (!emitCreateDecoratorContextObject(Kind::Class, key, false, 551 decorator->pn_pos)) { 552 // [stack] CTOR CALLEE THIS CTOR context 553 return false; 554 } 555 556 // Step 1.e. Let newDef be ? Call(decorator, decoratorReceiver, « classDef, 557 // context »). 558 if (!cone.emitEnd(2, decorator->pn_pos.begin)) { 559 // [stack] CTOR NEWCTOR 560 return false; 561 } 562 563 // Step 1.f. Set decorationState.[[Finished]] to true. 564 if (!emitUpdateDecorationState()) { 565 return false; 566 } 567 568 if (!emitCheckIsUndefined()) { 569 // [stack] CTOR NEWCTOR ISUNDEFINED 570 return false; 571 } 572 573 InternalIfEmitter ie(bce_); 574 if (!ie.emitThenElse()) { 575 // [stack] CTOR NEWCTOR 576 return false; 577 } 578 579 // Pop the undefined NEWDEF from the stack, leaving the original value in 580 // place. 581 if (!bce_->emitPopN(1)) { 582 // [stack] CTOR 583 return false; 584 } 585 586 if (!ie.emitElseIf(mozilla::Nothing())) { 587 return false; 588 } 589 590 // Step 1.g. If IsCallable(newDef) is true, then 591 // Step 1.g.i. Set classDef to newDef. 592 if (!bce_->emitCheckIsCallable()) { 593 // [stack] CTOR NEWCTOR ISCALLABLE_RESULT 594 return false; 595 } 596 597 if (!ie.emitThenElse()) { 598 // [stack] CTOR NEWCTOR 599 return false; 600 } 601 602 if (!bce_->emit1(JSOp::Swap)) { 603 // [stack] NEWCTOR CTOR 604 return false; 605 } 606 if (!bce_->emitPopN(1)) { 607 // [stack] NEWCTOR 608 return false; 609 } 610 611 // Step 1.h. Else if newDef is not undefined, then 612 // Step 1.h.i. Throw a TypeError exception. 613 if (!ie.emitElse()) { 614 return false; 615 } 616 617 if (!bce_->emitPopN(1)) { 618 // [stack] CTOR 619 return false; 620 } 621 if (!bce_->emit2(JSOp::ThrowMsg, 622 uint8_t(ThrowMsgKind::DecoratorInvalidReturnType))) { 623 return false; 624 } 625 626 if (!ie.emitEnd()) { 627 return false; 628 } 629 } 630 631 // Step 2. Return classDef. 632 return true; 633 } 634 635 bool DecoratorEmitter::emitInitializeFieldOrAccessor() { 636 // [stack] THIS INITIALIZERS 637 638 // Decorators Proposal 639 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-applydecoratorstoelementdefinition. 640 // 641 // Step 1. Assert: elementRecord.[[Kind]] is field or accessor. 642 // Step 2. If elementRecord.[[BackingStorageKey]] is present, let fieldName be 643 // elementRecord.[[BackingStorageKey]]. 644 // Step 3. Else, let fieldName be elementRecord.[[Key]]. 645 // We've stored the fieldname in the first element of the initializers array. 646 if (!bce_->emit1(JSOp::Dup)) { 647 // [stack] THIS INITIALIZERS INITIALIZERS 648 return false; 649 } 650 651 if (!bce_->emit1(JSOp::Zero)) { 652 // [stack] THIS INITIALIZERS INITIALIZERS INDEX 653 return false; 654 } 655 656 if (!bce_->emit1(JSOp::GetElem)) { 657 // [stack] THIS INITIALIZERS FIELDNAME 658 return false; 659 } 660 661 // Retrieve initial value of the field 662 if (!bce_->emit1(JSOp::Dup)) { 663 // [stack] THIS INITIALIZERS FIELDNAME FIELDNAME 664 return false; 665 } 666 667 if (!bce_->emitDupAt(3)) { 668 // [stack] THIS INITIALIZERS FIELDNAME FIELDNAME THIS 669 return false; 670 } 671 672 if (!bce_->emit1(JSOp::Swap)) { 673 // [stack] THIS INITIALIZERS FIELDNAME THIS FIELDNAME 674 return false; 675 } 676 677 // Step 4. Let initValue be undefined. 678 // TODO: (See Bug 1817993) At the moment, we're applying the initialization 679 // logic in two steps. The pre-decorator initialization code runs, stores 680 // the initial value, and then we retrieve it here and apply the initializers 681 // added by decorators. We should unify these two steps. 682 if (!bce_->emit1(JSOp::GetElem)) { 683 // [stack] THIS INITIALIZERS FIELDNAME VALUE 684 return false; 685 } 686 687 if (!bce_->emit2(JSOp::Pick, 2)) { 688 // [stack] THIS FIELDNAME VALUE INITIALIZERS 689 return false; 690 } 691 692 // Retrieve the length of the initializers array. 693 if (!bce_->emit1(JSOp::Dup)) { 694 // [stack] THIS FIELDNAME VALUE INITIALIZERS INITIALIZERS 695 return false; 696 } 697 698 if (!bce_->emitAtomOp(JSOp::GetProp, 699 TaggedParserAtomIndex::WellKnown::length())) { 700 // [stack] THIS FIELDNAME VALUE INITIALIZERS LENGTH 701 return false; 702 } 703 704 if (!bce_->emit1(JSOp::One)) { 705 // [stack] THIS FIELDNAME VALUE INITIALIZERS LENGTH INDEX 706 return false; 707 } 708 709 // Step 5. For each element initializer of elementRecord.[[Initializers]], do 710 InternalWhileEmitter wh(bce_); 711 // At this point, we have no context to determine offsets in the 712 // code for this while statement. Ideally, it would correspond to 713 // the field we're initializing. 714 if (!wh.emitCond()) { 715 // [stack] THIS FIELDNAME VALUE INITIALIZERS LENGTH INDEX 716 return false; 717 } 718 719 if (!bce_->emit1(JSOp::Dup)) { 720 // [stack] THIS FIELDNAME VALUE INITIALIZERS LENGTH INDEX INDEX 721 return false; 722 } 723 724 if (!bce_->emitDupAt(2)) { 725 // [stack] THIS FIELDNAME VALUE INITIALIZERS LENGTH INDEX INDEX 726 // LENGTH 727 return false; 728 } 729 730 if (!bce_->emit1(JSOp::Lt)) { 731 // [stack] THIS FIELDNAME VALUE INITIALIZERS LENGTH INDEX BOOL 732 return false; 733 } 734 735 // Step 5.a. Set initValue to ? Call(initializer, receiver, « initValue»). 736 if (!wh.emitBody()) { 737 // [stack] THIS FIELDNAME VALUE INITIALIZERS LENGTH INDEX 738 return false; 739 } 740 741 if (!bce_->emitDupAt(2)) { 742 // [stack] THIS FIELDNAME VALUE INITIALIZERS LENGTH INDEX 743 // INITIALIZERS 744 return false; 745 } 746 747 if (!bce_->emitDupAt(1)) { 748 // [stack] THIS FIELDNAME VALUE INITIALIZERS LENGTH INDEX 749 // INITIALIZERS INDEX 750 return false; 751 } 752 753 if (!bce_->emit1(JSOp::GetElem)) { 754 // [stack] THIS FIELDNAME VALUE INITIALIZERS LENGTH INDEX FUNC 755 return false; 756 } 757 758 if (!bce_->emitDupAt(6)) { 759 // [stack] THIS FIELDNAME VALUE INITIALIZERS LENGTH INDEX FUNC THIS 760 return false; 761 } 762 763 // Pass value in as argument to the initializer 764 if (!bce_->emit2(JSOp::Pick, 5)) { 765 // [stack] THIS FIELDNAME INITIALIZERS LENGTH INDEX FUNC THIS VALUE 766 return false; 767 } 768 769 // Callee is always internal function. 770 if (!bce_->emitCall(JSOp::Call, 1)) { 771 // [stack] THIS FIELDNAME INITIALIZERS LENGTH INDEX RVAL 772 return false; 773 } 774 775 // Store returned value for next iteration 776 if (!bce_->emit2(JSOp::Unpick, 3)) { 777 // [stack] THIS FIELDNAME VALUE INITIALIZERS LENGTH INDEX 778 return false; 779 } 780 781 if (!bce_->emit1(JSOp::Inc)) { 782 // [stack] THIS FIELDNAME VALUE INITIALIZERS LENGTH INDEX 783 return false; 784 } 785 786 if (!wh.emitEnd()) { 787 // [stack] THIS FIELDNAME VALUE INITIALIZERS LENGTH INDEX 788 return false; 789 } 790 791 // Step 6. If fieldName is a Private Name, then 792 // Step 6.a. Perform ? PrivateFieldAdd(receiver, fieldName, initValue). 793 // Step 7. Else, 794 // Step 7.a. Assert: IsPropertyKey(fieldName) is true. 795 // Step 7.b. Perform ? CreateDataPropertyOrThrow(receiver, fieldName, 796 // initValue). 797 // TODO: (See Bug 1817993) Because the field already exists, we just store the 798 // updated value here. 799 if (!bce_->emitPopN(3)) { 800 // [stack] THIS FIELDNAME VALUE 801 return false; 802 } 803 804 if (!bce_->emit1(JSOp::InitElem)) { 805 // [stack] THIS 806 return false; 807 } 808 809 // Step 8. Return unused. 810 return bce_->emitPopN(1); 811 // [stack] 812 } 813 814 bool DecoratorEmitter::emitCallExtraInitializers( 815 TaggedParserAtomIndex extraInitializers) { 816 // Support for static and class extra initializers will be added in 817 // bug 1868220 and bug 1868221. 818 MOZ_ASSERT( 819 extraInitializers == 820 TaggedParserAtomIndex::WellKnown::dot_instanceExtraInitializers_()); 821 822 if (!bce_->emitGetName(extraInitializers)) { 823 // [stack] ARRAY 824 return false; 825 } 826 827 if (!bce_->emit1(JSOp::Dup)) { 828 // [stack] ARRAY ARRAY 829 return false; 830 } 831 832 if (!bce_->emitAtomOp(JSOp::GetProp, 833 TaggedParserAtomIndex::WellKnown::length())) { 834 // [stack] ARRAY LENGTH 835 return false; 836 } 837 838 if (!bce_->emit1(JSOp::Zero)) { 839 // [stack] ARRAY LENGTH INDEX 840 return false; 841 } 842 843 InternalWhileEmitter wh(bce_); 844 if (!wh.emitCond()) { 845 // [stack] ARRAY LENGTH INDEX 846 return false; 847 } 848 849 if (!bce_->emit1(JSOp::Dup)) { 850 // [stack] ARRAY LENGTH INDEX INDEX 851 return false; 852 } 853 854 if (!bce_->emitDupAt(2)) { 855 // [stack] ARRAY LENGTH INDEX INDEX LENGTH 856 return false; 857 } 858 859 if (!bce_->emit1(JSOp::Lt)) { 860 // [stack] ARRAY LENGTH INDEX BOOL 861 return false; 862 } 863 864 if (!wh.emitBody()) { 865 // [stack] ARRAY LENGTH INDEX 866 return false; 867 } 868 869 if (!bce_->emitDupAt(2)) { 870 // [stack] ARRAY LENGTH INDEX ARRAY 871 return false; 872 } 873 874 if (!bce_->emitDupAt(1)) { 875 // [stack] ARRAY LENGTH INDEX ARRAY INDEX 876 return false; 877 } 878 879 // Retrieve initializer 880 if (!bce_->emit1(JSOp::GetElem)) { 881 // [stack] ARRAY LENGTH INDEX INITIALIZER 882 return false; 883 } 884 885 // This is guaranteed to run after super(), so we don't need TDZ checks. 886 if (!bce_->emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) { 887 // [stack] ARRAY LENGTH INDEX INITIALIZER THIS 888 return false; 889 } 890 891 // Callee is always internal function. 892 if (!bce_->emitCall(JSOp::CallIgnoresRv, 0)) { 893 // [stack] ARRAY LENGTH INDEX RVAL 894 return false; 895 } 896 897 if (!bce_->emit1(JSOp::Pop)) { 898 // [stack] ARRAY LENGTH INDEX 899 return false; 900 } 901 902 if (!bce_->emit1(JSOp::Inc)) { 903 // [stack] ARRAY LENGTH INDEX 904 return false; 905 } 906 907 if (!wh.emitEnd()) { 908 // [stack] ARRAY LENGTH INDEX 909 return false; 910 } 911 912 return bce_->emitPopN(3); 913 // [stack] 914 } 915 916 bool DecoratorEmitter::emitPropertyKey(ParseNode* key) { 917 if (key->is<NameNode>()) { 918 NameNode* keyAsNameNode = &key->as<NameNode>(); 919 if (keyAsNameNode->privateNameKind() == PrivateNameKind::None) { 920 if (!bce_->emitStringOp(JSOp::String, keyAsNameNode->atom())) { 921 // [stack] NAME 922 return false; 923 } 924 } else { 925 MOZ_ASSERT(keyAsNameNode->privateNameKind() == PrivateNameKind::Field); 926 if (!bce_->emitGetPrivateName(keyAsNameNode)) { 927 // [stack] NAME 928 return false; 929 } 930 } 931 } else if (key->isKind(ParseNodeKind::NumberExpr)) { 932 if (!bce_->emitNumberOp(key->as<NumericLiteral>().value())) { 933 // [stack] NAME 934 return false; 935 } 936 } else { 937 // Otherwise this is a computed property name. BigInt keys are parsed 938 // as (synthetic) computed property names, too. 939 MOZ_ASSERT(key->isKind(ParseNodeKind::ComputedName)); 940 941 if (!bce_->emitComputedPropertyName(&key->as<UnaryNode>())) { 942 // [stack] NAME 943 return false; 944 } 945 } 946 947 return true; 948 } 949 950 bool DecoratorEmitter::emitDecorationState() { 951 // TODO: See https://bugzilla.mozilla.org/show_bug.cgi?id=1868841 952 return true; 953 } 954 955 bool DecoratorEmitter::emitUpdateDecorationState() { 956 // TODO: See https://bugzilla.mozilla.org/show_bug.cgi?id=1868841. 957 return true; 958 } 959 960 bool DecoratorEmitter::emitCallDecoratorForElement(Kind kind, ParseNode* key, 961 bool isStatic, 962 ParseNode* decorator) { 963 MOZ_ASSERT(kind != Kind::Class); 964 // Except for fields, this method expects the value to be passed 965 // to the decorator to be on top of the stack. For methods, getters and 966 // setters this is the method itself. For accessors it is an object 967 // containing the getter and setter associated with the accessor. 968 // This method also expects the addInitializerFunction to be present on 969 // the top of the stack. 970 // [stack] VAL? ADDINIT 971 // Prepare to call decorator 972 CallOrNewEmitter cone(bce_, JSOp::Call, 973 CallOrNewEmitter::ArgumentsKind::Other, 974 ValueUsage::WantValue); 975 976 if (!bce_->emitCalleeAndThis(decorator, nullptr, cone)) { 977 // [stack] VAL? ADDINIT CALLEE THIS 978 return false; 979 } 980 981 if (!cone.prepareForNonSpreadArguments()) { 982 return false; 983 } 984 985 if (kind == Kind::Field) { 986 // Step 5.c. Let value be undefined. 987 if (!bce_->emit1(JSOp::Undefined)) { 988 // [stack] ADDINIT CALLEE THIS undefined 989 return false; 990 } 991 } else if (kind == Kind::Getter || kind == Kind::Method || 992 kind == Kind::Setter) { 993 // Step 5.d. If kind is method, set value to elementRecord.[[Value]]. 994 // Step 5.e. Else if kind is getter, set value to elementRecord.[[Get]]. 995 // Step 5.f. Else if kind is setter, set value to elementRecord.[[Set]]. 996 // The DecoratorEmitter expects the method to already be on the stack. 997 // We dup the value here so we can use it as an argument to the decorator. 998 if (!bce_->emitDupAt(3)) { 999 // [stack] VAL ADDINIT CALLEE THIS VAL 1000 return false; 1001 } 1002 } else { 1003 // Step 5.g. Else if kind is accessor, then 1004 // Step 5.g.i. Set value to OrdinaryObjectCreate(%Object.prototype%). 1005 // For accessor decorators, we've already created the value object prior 1006 // to calling this method. 1007 MOZ_ASSERT(kind == Kind::Accessor); 1008 if (!bce_->emitPickN(3)) { 1009 // [stack] ADDINIT CALLEE THIS VAL 1010 return false; 1011 } 1012 } 1013 // Step 5.b. Let context be CreateDecoratorContextObject(kind, key, 1014 // extraInitializers, decorationState, isStatic). 1015 if (!bce_->emitPickN(3)) { 1016 // [stack] VAL? CALLEE THIS VAL ADDINIT 1017 return false; 1018 } 1019 if (!emitCreateDecoratorContextObject(kind, key, isStatic, 1020 decorator->pn_pos)) { 1021 // [stack] VAL? CALLEE THIS VAL context 1022 return false; 1023 } 1024 1025 // Step 5.h. Let newValue be ? Call(decorator, undefined, « value, context»). 1026 return cone.emitEnd(2, decorator->pn_pos.begin); 1027 // [stack] VAL? RETVAL 1028 } 1029 1030 bool DecoratorEmitter::emitCreateDecoratorAccessObject() { 1031 // TODO: See https://bugzilla.mozilla.org/show_bug.cgi?id=1800725. 1032 ObjectEmitter oe(bce_); 1033 if (!oe.emitObject(0)) { 1034 return false; 1035 } 1036 return oe.emitEnd(); 1037 } 1038 1039 bool DecoratorEmitter::emitCheckIsUndefined() { 1040 // This emits code to check if the value at the top of the stack is 1041 // undefined. The value is left on the stack. 1042 // [stack] VAL 1043 if (!bce_->emit1(JSOp::Dup)) { 1044 // [stack] VAL VAL 1045 return false; 1046 } 1047 if (!bce_->emit1(JSOp::Undefined)) { 1048 // [stack] VAL VAL undefined 1049 return false; 1050 } 1051 return bce_->emit1(JSOp::Eq); 1052 // [stack] VAL ISUNDEFINED 1053 } 1054 1055 bool DecoratorEmitter::emitCreateAddInitializerFunction( 1056 FunctionNode* addInitializerFunction, TaggedParserAtomIndex initializers) { 1057 // This synthesizes a function corresponding to this JavaScript code: 1058 // function(initializer) { 1059 // if (IsCallable(initializer)) { 1060 // initializers[initializers.length++] = initializer; 1061 // } else { 1062 // throw DecoratorInvalidReturnType; 1063 // } 1064 // } 1065 MOZ_ASSERT(addInitializerFunction); 1066 // TODO: Add support for static and class extra initializers, see bug 1868220 1067 // and bug 1868221. 1068 MOZ_ASSERT( 1069 initializers == 1070 TaggedParserAtomIndex::WellKnown::dot_instanceExtraInitializers_()); 1071 1072 FunctionEmitter fe(bce_, addInitializerFunction->funbox(), 1073 FunctionSyntaxKind::Statement, 1074 FunctionEmitter::IsHoisted::No); 1075 if (!fe.prepareForNonLazy()) { 1076 return false; 1077 } 1078 1079 BytecodeEmitter bce2(bce_, addInitializerFunction->funbox()); 1080 if (!bce2.init()) { 1081 return false; 1082 } 1083 1084 FunctionScriptEmitter fse(&bce2, addInitializerFunction->funbox(), 1085 mozilla::Nothing(), mozilla::Nothing()); 1086 if (!fse.prepareForParameters()) { 1087 return false; 1088 } 1089 1090 if (!bce2.emitFunctionFormalParameters(addInitializerFunction->body())) { 1091 return false; 1092 } 1093 1094 if (!fse.prepareForBody()) { 1095 return false; 1096 } 1097 1098 LexicalScopeNode* lexicalScope = addInitializerFunction->body()->body(); 1099 LexicalScopeEmitter lse(&bce2); 1100 if (lexicalScope->isEmptyScope()) { 1101 if (!lse.emitEmptyScope()) { 1102 return false; 1103 } 1104 } else { 1105 if (!lse.emitScope(lexicalScope->kind(), lexicalScope->scopeBindings())) { 1106 return false; 1107 } 1108 } 1109 1110 NameLocation loc = 1111 bce2.lookupName(TaggedParserAtomIndex::WellKnown::initializer()); 1112 MOZ_ASSERT(loc.kind() == NameLocation::Kind::ArgumentSlot); 1113 1114 if (!bce2.emitArgOp(JSOp::GetArg, loc.argumentSlot())) { 1115 // [stack] INITIALIZER 1116 return false; 1117 } 1118 1119 if (!bce2.emitCheckIsCallable()) { 1120 // [stack] INITIALIZER ISCALLABLE 1121 return false; 1122 } 1123 1124 InternalIfEmitter ifCallable(&bce2); 1125 if (!ifCallable.emitThenElse()) { 1126 // [stack] INITIALIZER 1127 return false; 1128 } 1129 1130 loc = bce2.lookupName(initializers); 1131 MOZ_ASSERT(loc.kind() == NameLocation::Kind::EnvironmentCoordinate); 1132 if (!bce2.emitEnvCoordOp(JSOp::GetAliasedVar, loc.environmentCoordinate())) { 1133 // [stack] INITIALIZER ARRAY 1134 return false; 1135 } 1136 if (!bce2.emitEnvCoordOp(JSOp::CheckAliasedLexical, 1137 loc.environmentCoordinate())) { 1138 // [stack] INITIALIZER ARRAY 1139 return false; 1140 } 1141 if (!bce2.emit1(JSOp::Dup)) { 1142 // [stack] INITIALIZER ARRAY ARRAY 1143 return false; 1144 } 1145 if (!bce2.emitAtomOp(JSOp::GetProp, 1146 TaggedParserAtomIndex::WellKnown::length())) { 1147 // [stack] INITIALIZER ARRAY LENGTH 1148 return false; 1149 } 1150 if (!bce2.emitPickN(2)) { 1151 // [stack] ARRAY LENGTH INITIALIZER 1152 return false; 1153 } 1154 if (!bce2.emit1(JSOp::InitElemInc)) { 1155 // [stack] ARRAY LENGTH 1156 return false; 1157 } 1158 if (!bce2.emitPopN(2)) { 1159 // [stack] 1160 return false; 1161 } 1162 1163 if (!ifCallable.emitElse()) { 1164 // [stack] INITIALIZER 1165 return false; 1166 } 1167 1168 if (!bce2.emitPopN(1)) { 1169 // [stack] 1170 return false; 1171 } 1172 if (!bce2.emit2(JSOp::ThrowMsg, 1173 uint8_t(ThrowMsgKind::DecoratorInvalidReturnType))) { 1174 return false; 1175 } 1176 1177 if (!ifCallable.emitEnd()) { 1178 return false; 1179 } 1180 1181 if (!lse.emitEnd()) { 1182 return false; 1183 } 1184 1185 if (!fse.emitEndBody()) { 1186 return false; 1187 } 1188 1189 if (!fse.intoStencil()) { 1190 return false; 1191 } 1192 1193 return fe.emitNonLazyEnd(); 1194 // [stack] ADDINIT 1195 } 1196 1197 bool DecoratorEmitter::emitCreateDecoratorContextObject(Kind kind, 1198 ParseNode* key, 1199 bool isStatic, 1200 TokenPos pos) { 1201 // We expect the addInitializerFunction to already be on the stack. 1202 // [stack] ADDINIT 1203 1204 // Step 1. Let contextObj be OrdinaryObjectCreate(%Object.prototype%). 1205 ObjectEmitter oe(bce_); 1206 size_t propertyCount = kind == Kind::Class ? 3 : 6; 1207 if (!oe.emitObject(propertyCount)) { 1208 // [stack] ADDINIT context 1209 return false; 1210 } 1211 if (!oe.prepareForPropValue(pos.begin, PropertyEmitter::Kind::Prototype)) { 1212 return false; 1213 } 1214 1215 TaggedParserAtomIndex kindStr; 1216 switch (kind) { 1217 case Kind::Method: 1218 // Step 2. If kind is method, let kindStr be "method". 1219 kindStr = frontend::TaggedParserAtomIndex::WellKnown::method(); 1220 break; 1221 case Kind::Getter: 1222 // Step 3. Else if kind is getter, let kindStr be "getter". 1223 kindStr = frontend::TaggedParserAtomIndex::WellKnown::getter(); 1224 break; 1225 case Kind::Setter: 1226 // Step 4. Else if kind is setter, let kindStr be "setter". 1227 kindStr = frontend::TaggedParserAtomIndex::WellKnown::setter(); 1228 break; 1229 case Kind::Accessor: 1230 // Step 5. Else if kind is accessor, let kindStr be "accessor". 1231 kindStr = frontend::TaggedParserAtomIndex::WellKnown::accessor(); 1232 break; 1233 case Kind::Field: 1234 // Step 6. Else if kind is field, let kindStr be "field". 1235 kindStr = frontend::TaggedParserAtomIndex::WellKnown::field(); 1236 break; 1237 case Kind::Class: 1238 // Step 7. Else, 1239 // Step 7.a. Assert: kind is class. 1240 // Step 7.b. Let kindStr be "class". 1241 kindStr = frontend::TaggedParserAtomIndex::WellKnown::class_(); 1242 break; 1243 default: 1244 MOZ_ASSERT_UNREACHABLE("Unknown kind"); 1245 break; 1246 } 1247 if (!bce_->emitStringOp(JSOp::String, kindStr)) { 1248 // [stack] ADDINIT context kindStr 1249 return false; 1250 } 1251 1252 // Step 8. Perform ! CreateDataPropertyOrThrow(contextObj, "kind", kindStr). 1253 if (!oe.emitInit(frontend::AccessorType::None, 1254 frontend::TaggedParserAtomIndex::WellKnown::kind())) { 1255 // [stack] ADDINIT context 1256 return false; 1257 } 1258 // Step 9. If kind is not class, then 1259 if (kind != Kind::Class) { 1260 MOZ_ASSERT(key != nullptr, "Expect key to be present except for classes"); 1261 1262 // Step 9.a. Perform ! CreateDataPropertyOrThrow(contextObj, "access", 1263 // CreateDecoratorAccessObject(kind, name)). 1264 if (!oe.prepareForPropValue(pos.begin, PropertyEmitter::Kind::Prototype)) { 1265 return false; 1266 } 1267 if (!emitCreateDecoratorAccessObject()) { 1268 return false; 1269 } 1270 if (!oe.emitInit(frontend::AccessorType::None, 1271 frontend::TaggedParserAtomIndex::WellKnown::access())) { 1272 // [stack] ADDINIT context 1273 return false; 1274 } 1275 // Step 9.b. If isStatic is present, perform 1276 // ! CreateDataPropertyOrThrow(contextObj, "static", isStatic). 1277 if (!oe.prepareForPropValue(pos.begin, PropertyEmitter::Kind::Prototype)) { 1278 return false; 1279 } 1280 if (!bce_->emit1(isStatic ? JSOp::True : JSOp::False)) { 1281 // [stack] ADDINIT context isStatic 1282 return false; 1283 } 1284 if (!oe.emitInit(frontend::AccessorType::None, 1285 frontend::TaggedParserAtomIndex::WellKnown::static_())) { 1286 // [stack] ADDINIT context 1287 return false; 1288 } 1289 // Step 9.c. If name is a Private Name, then 1290 // Step 9.c.i. Perform ! CreateDataPropertyOrThrow(contextObj, "private", 1291 // true). 1292 // Step 9.d. Else, Step 9.d.i. Perform 1293 // ! CreateDataPropertyOrThrow(contextObj, "private", false). 1294 if (!oe.prepareForPropValue(pos.begin, PropertyEmitter::Kind::Prototype)) { 1295 return false; 1296 } 1297 if (!bce_->emit1(key->isKind(ParseNodeKind::PrivateName) ? JSOp::True 1298 : JSOp::False)) { 1299 // [stack] ADDINIT context private 1300 return false; 1301 } 1302 if (!oe.emitInit(frontend::AccessorType::None, 1303 frontend::TaggedParserAtomIndex::WellKnown::private_())) { 1304 // [stack] ADDINIT context 1305 return false; 1306 } 1307 // Step 9.c.ii. Perform ! CreateDataPropertyOrThrow(contextObj, 1308 // "name", name.[[Description]]). 1309 // 1310 // Step 9.d.ii. Perform ! CreateDataPropertyOrThrow(contextObj, 1311 // "name", name.[[Description]]).) 1312 if (!oe.prepareForPropValue(pos.begin, PropertyEmitter::Kind::Prototype)) { 1313 return false; 1314 } 1315 if (key->is<NameNode>()) { 1316 if (!bce_->emitStringOp(JSOp::String, key->as<NameNode>().atom())) { 1317 return false; 1318 } 1319 } else { 1320 if (!emitPropertyKey(key)) { 1321 return false; 1322 } 1323 } 1324 if (!oe.emitInit(frontend::AccessorType::None, 1325 frontend::TaggedParserAtomIndex::WellKnown::name())) { 1326 // [stack] ADDINIT context 1327 return false; 1328 } 1329 } else { 1330 // Step 10. Else, 1331 // Step 10.a. Perform ! CreateDataPropertyOrThrow(contextObj, "name", name). 1332 if (!oe.prepareForPropValue(pos.begin, PropertyEmitter::Kind::Prototype)) { 1333 return false; 1334 } 1335 if (key != nullptr) { 1336 if (!bce_->emitStringOp(JSOp::String, key->as<NameNode>().atom())) { 1337 return false; 1338 } 1339 } else { 1340 if (!bce_->emit1(JSOp::Undefined)) { 1341 return false; 1342 } 1343 } 1344 if (!oe.emitInit(frontend::AccessorType::None, 1345 frontend::TaggedParserAtomIndex::WellKnown::name())) { 1346 // [stack] ADDINIT context 1347 return false; 1348 } 1349 } 1350 // Step 11. Let addInitializer be CreateAddInitializerFunction(initializers, 1351 // decorationState). 1352 if (!oe.prepareForPropValue(pos.begin, PropertyEmitter::Kind::Prototype)) { 1353 return false; 1354 } 1355 1356 if (!bce_->emitPickN(1)) { 1357 // [stack] context ADDINIT 1358 return false; 1359 } 1360 // Step 12. Perform ! CreateDataPropertyOrThrow(contextObj, "addInitializer", 1361 // addInitializer). 1362 if (!oe.emitInit( 1363 frontend::AccessorType::None, 1364 frontend::TaggedParserAtomIndex::WellKnown::addInitializer())) { 1365 // [stack] context 1366 return false; 1367 } 1368 // Step 13. Return contextObj. 1369 return oe.emitEnd(); 1370 } 1371 1372 bool DecoratorEmitter::emitHandleNewValueField(TaggedParserAtomIndex atom, 1373 int8_t offset) { 1374 // This function handles retrieving the new value from a field in the RETVAL 1375 // object returned by the decorator. The `atom` is the atom of the field to be 1376 // examined. The offset is the offset of the existing value on the stack, 1377 // which will be replaced by the new value. If the offset is zero, we're 1378 // handling the initializer which will be added to the array of initializers 1379 // already on the stack. 1380 // [stack] GETTER SETTER ARRAY INDEX RETVAL 1381 1382 if (!bce_->emit1(JSOp::Dup)) { 1383 // [stack] GETTER SETTER ARRAY INDEX RETVAL RETVAL 1384 return false; 1385 } 1386 if (!bce_->emitStringOp(JSOp::String, atom)) { 1387 // [stack] GETTER SETTER ARRAY INDEX RETVAL RETVAL ATOM 1388 return false; 1389 } 1390 if (!bce_->emit1(JSOp::GetElem)) { 1391 // [stack] GETTER SETTER ARRAY INDEX RETVAL 1392 // NEW_VALUE 1393 return false; 1394 } 1395 1396 if (!emitCheckIsUndefined()) { 1397 // [stack] GETTER SETTER ARRAY INDEX RETVAL 1398 // NEW_VALUE ISUNDEFINED 1399 return false; 1400 } 1401 1402 InternalIfEmitter ifCallable(bce_); 1403 if (!ifCallable.emitThenElse()) { 1404 // [stack] GETTER SETTER ARRAY INDEX RETVAL 1405 // NEW_VALUE 1406 return false; 1407 } 1408 1409 // Pop the undefined getter or setter from the stack, leaving the original 1410 // values in place. 1411 if (!bce_->emitPopN(1)) { 1412 // [stack] GETTER SETTER ARRAY INDEX RETVAL 1413 return false; 1414 } 1415 1416 if (!ifCallable.emitElseIf(mozilla::Nothing())) { 1417 return false; 1418 } 1419 if (!bce_->emitCheckIsCallable()) { 1420 // [stack] GETTER SETTER ARRAY INDEX RETVAL 1421 // NEW_VALUE ISCALLABLE_RESULT 1422 return false; 1423 } 1424 if (!ifCallable.emitThenElse()) { 1425 // [stack] GETTER SETTER ARRAY INDEX RETVAL 1426 // NEW_VALUE 1427 return false; 1428 } 1429 if (offset != 0) { 1430 if (!bce_->emitPickN(offset)) { 1431 // [stack] GETTER? SETTER? ARRAY INDEX RETVAL 1432 // NEW_VALUE GETTER_OR_SETTER 1433 return false; 1434 } 1435 if (!bce_->emitPopN(1)) { 1436 // [stack] GETTER? SETTER? ARRAY INDEX RETVAL 1437 // NEW_VALUE 1438 return false; 1439 } 1440 if (!bce_->emitUnpickN(offset - 1)) { 1441 // [stack] GETTER SETTER ARRAY INDEX RETVAL 1442 return false; 1443 } 1444 } else { 1445 // Offset == 0 means we're retrieving the initializer, this is 1446 // stored in the initializer array on the stack. 1447 if (!bce_->emit1(JSOp::Swap)) { 1448 // [stack] GETTER SETTER ARRAY INDEX NEW_VALUE RETVAL 1449 return false; 1450 } 1451 1452 if (!bce_->emitUnpickN(3)) { 1453 // [stack] GETTER SETTER RETVAL ARRAY INDEX NEW_VALUE 1454 return false; 1455 } 1456 1457 if (!bce_->emit1(JSOp::InitElemInc)) { 1458 // [stack] GETTER SETTER RETVAL ARRAY INDEX 1459 return false; 1460 } 1461 1462 if (!bce_->emitPickN(2)) { 1463 // [stack] GETTER SETTER ARRAY INDEX RETVAL 1464 return false; 1465 } 1466 } 1467 1468 if (!ifCallable.emitElse()) { 1469 return false; 1470 } 1471 1472 if (!bce_->emitPopN(1)) { 1473 // [stack] GETTER SETTER ARRAY INDEX 1474 return false; 1475 } 1476 1477 if (!bce_->emit2(JSOp::ThrowMsg, 1478 uint8_t(ThrowMsgKind::DecoratorInvalidReturnType))) { 1479 return false; 1480 } 1481 1482 return ifCallable.emitEnd(); 1483 }