FunctionEmitter.cpp (25544B)
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/FunctionEmitter.h" 8 9 #include "mozilla/Assertions.h" // MOZ_ASSERT 10 11 #include "frontend/AsyncEmitter.h" // AsyncEmitter 12 #include "frontend/BytecodeEmitter.h" // BytecodeEmitter 13 #include "frontend/FunctionSyntaxKind.h" // FunctionSyntaxKind 14 #include "frontend/ModuleSharedContext.h" // ModuleSharedContext 15 #include "frontend/NameAnalysisTypes.h" // NameLocation 16 #include "frontend/NameOpEmitter.h" // NameOpEmitter 17 #include "frontend/SharedContext.h" // SharedContext 18 #include "vm/ModuleBuilder.h" // ModuleBuilder 19 #include "vm/Opcodes.h" // JSOp 20 #include "vm/Scope.h" // BindingKind 21 22 using namespace js; 23 using namespace js::frontend; 24 25 using mozilla::Maybe; 26 using mozilla::Some; 27 28 FunctionEmitter::FunctionEmitter(BytecodeEmitter* bce, FunctionBox* funbox, 29 FunctionSyntaxKind syntaxKind, 30 IsHoisted isHoisted) 31 : bce_(bce), 32 funbox_(funbox), 33 name_(funbox_->explicitName()), 34 syntaxKind_(syntaxKind), 35 isHoisted_(isHoisted) {} 36 37 bool FunctionEmitter::prepareForNonLazy() { 38 MOZ_ASSERT(state_ == State::Start); 39 40 MOZ_ASSERT(funbox_->isInterpreted()); 41 MOZ_ASSERT(funbox_->emitBytecode); 42 MOZ_ASSERT(!funbox_->wasEmittedByEnclosingScript()); 43 44 // [stack] 45 46 funbox_->setWasEmittedByEnclosingScript(true); 47 48 #ifdef DEBUG 49 state_ = State::NonLazy; 50 #endif 51 return true; 52 } 53 54 bool FunctionEmitter::emitNonLazyEnd() { 55 MOZ_ASSERT(state_ == State::NonLazy); 56 57 // [stack] 58 59 if (!emitFunction()) { 60 // [stack] FUN? 61 return false; 62 } 63 64 #ifdef DEBUG 65 state_ = State::End; 66 #endif 67 return true; 68 } 69 70 bool FunctionEmitter::emitLazy() { 71 MOZ_ASSERT(state_ == State::Start); 72 73 MOZ_ASSERT(funbox_->isInterpreted()); 74 MOZ_ASSERT(!funbox_->emitBytecode); 75 MOZ_ASSERT(!funbox_->wasEmittedByEnclosingScript()); 76 77 // [stack] 78 79 funbox_->setWasEmittedByEnclosingScript(true); 80 81 // Prepare to update the inner lazy script now that it's parent is fully 82 // compiled. These updates will be applied in UpdateEmittedInnerFunctions(). 83 funbox_->setEnclosingScopeForInnerLazyFunction(bce_->innermostScopeIndex()); 84 85 if (!emitFunction()) { 86 // [stack] FUN? 87 return false; 88 } 89 90 #ifdef DEBUG 91 state_ = State::End; 92 #endif 93 return true; 94 } 95 96 bool FunctionEmitter::emitAgain() { 97 MOZ_ASSERT(state_ == State::Start); 98 MOZ_ASSERT(funbox_->wasEmittedByEnclosingScript()); 99 100 // [stack] 101 102 // Annex B block-scoped functions are hoisted like any other assignment 103 // that assigns the function to the outer 'var' binding. 104 if (!funbox_->isAnnexB) { 105 #ifdef DEBUG 106 state_ = State::End; 107 #endif 108 return true; 109 } 110 111 // Get the location of the 'var' binding in the body scope. The 112 // name must be found, else there is a bug in the Annex B handling 113 // in Parser. 114 // 115 // In sloppy eval contexts, this location is dynamic. 116 Maybe<NameLocation> lhsLoc = 117 bce_->locationOfNameBoundInScope(name_, bce_->varEmitterScope); 118 119 // If there are parameter expressions, the var name could be a 120 // parameter. 121 if (!lhsLoc && bce_->sc->isFunctionBox() && 122 bce_->sc->asFunctionBox()->functionHasExtraBodyVarScope()) { 123 lhsLoc = bce_->locationOfNameBoundInScope( 124 name_, bce_->varEmitterScope->enclosingInFrame()); 125 } 126 127 if (!lhsLoc) { 128 lhsLoc = Some(NameLocation::DynamicAnnexBVar()); 129 } else { 130 MOZ_ASSERT(lhsLoc->bindingKind() == BindingKind::Var || 131 lhsLoc->bindingKind() == BindingKind::FormalParameter || 132 (lhsLoc->bindingKind() == BindingKind::Let && 133 bce_->sc->asFunctionBox()->hasParameterExprs)); 134 } 135 136 NameOpEmitter noe(bce_, name_, *lhsLoc, 137 NameOpEmitter::Kind::SimpleAssignment); 138 if (!noe.prepareForRhs()) { 139 // [stack] 140 return false; 141 } 142 143 if (!bce_->emitGetName(name_)) { 144 // [stack] FUN 145 return false; 146 } 147 148 if (!noe.emitAssignment()) { 149 // [stack] FUN 150 return false; 151 } 152 153 if (!bce_->emit1(JSOp::Pop)) { 154 // [stack] 155 return false; 156 } 157 158 #ifdef DEBUG 159 state_ = State::End; 160 #endif 161 return true; 162 } 163 164 bool FunctionEmitter::emitAsmJSModule() { 165 MOZ_ASSERT(state_ == State::Start); 166 167 MOZ_ASSERT(!funbox_->wasEmittedByEnclosingScript()); 168 MOZ_ASSERT(funbox_->isAsmJSModule()); 169 170 // [stack] 171 172 funbox_->setWasEmittedByEnclosingScript(true); 173 174 if (!emitFunction()) { 175 // [stack] 176 return false; 177 } 178 179 #ifdef DEBUG 180 state_ = State::End; 181 #endif 182 return true; 183 } 184 185 bool FunctionEmitter::emitFunction() { 186 // Make the function object a literal in the outer script's pool. 187 GCThingIndex index; 188 if (!bce_->perScriptData().gcThingList().append(funbox_, &index)) { 189 return false; 190 } 191 192 // [stack] 193 194 if (isHoisted_ == IsHoisted::No) { 195 return emitNonHoisted(index); 196 // [stack] FUN? 197 } 198 199 bool topLevelFunction; 200 if (bce_->sc->isFunctionBox() || 201 (bce_->sc->isEvalContext() && bce_->sc->strict())) { 202 // No nested functions inside other functions are top-level. 203 topLevelFunction = false; 204 } else { 205 // In sloppy eval scripts, top-level functions are accessed dynamically. 206 // In global and module scripts, top-level functions are those bound in 207 // the var scope. 208 NameLocation loc = bce_->lookupName(name_); 209 topLevelFunction = loc.kind() == NameLocation::Kind::Dynamic || 210 loc.bindingKind() == BindingKind::Var; 211 } 212 213 if (topLevelFunction) { 214 return emitTopLevelFunction(index); 215 // [stack] 216 } 217 218 return emitHoisted(index); 219 // [stack] 220 } 221 222 bool FunctionEmitter::emitNonHoisted(GCThingIndex index) { 223 // Non-hoisted functions simply emit their respective op. 224 225 // [stack] 226 227 if (syntaxKind_ == FunctionSyntaxKind::DerivedClassConstructor) { 228 // [stack] PROTO 229 if (!bce_->emitGCIndexOp(JSOp::FunWithProto, index)) { 230 // [stack] FUN 231 return false; 232 } 233 return true; 234 } 235 236 // This is a FunctionExpression, ArrowFunctionExpression, or class 237 // constructor. Emit the single instruction (without location info). 238 if (!bce_->emitGCIndexOp(JSOp::Lambda, index)) { 239 // [stack] FUN 240 return false; 241 } 242 243 return true; 244 } 245 246 bool FunctionEmitter::emitHoisted(GCThingIndex index) { 247 MOZ_ASSERT(syntaxKind_ == FunctionSyntaxKind::Statement); 248 249 // [stack] 250 251 // For functions nested within functions and blocks, make a lambda and 252 // initialize the binding name of the function in the current scope. 253 254 NameOpEmitter noe(bce_, name_, NameOpEmitter::Kind::Initialize); 255 if (!noe.prepareForRhs()) { 256 // [stack] 257 return false; 258 } 259 260 if (!bce_->emitGCIndexOp(JSOp::Lambda, index)) { 261 // [stack] FUN 262 return false; 263 } 264 265 if (!noe.emitAssignment()) { 266 // [stack] FUN 267 return false; 268 } 269 270 if (!bce_->emit1(JSOp::Pop)) { 271 // [stack] 272 return false; 273 } 274 275 return true; 276 } 277 278 bool FunctionEmitter::emitTopLevelFunction(GCThingIndex index) { 279 // [stack] 280 281 if (bce_->sc->isModuleContext()) { 282 // For modules, we record the function and instantiate the binding 283 // during ModuleInstantiate(), before the script is run. 284 return bce_->sc->asModuleContext()->builder.noteFunctionDeclaration( 285 bce_->fc, index); 286 } 287 288 MOZ_ASSERT(bce_->sc->isGlobalContext() || bce_->sc->isEvalContext()); 289 MOZ_ASSERT(syntaxKind_ == FunctionSyntaxKind::Statement); 290 MOZ_ASSERT(bce_->inPrologue()); 291 292 // NOTE: The `index` is not directly stored as an opcode, but we collect the 293 // range of indices in `BytecodeEmitter::emitDeclarationInstantiation` instead 294 // of discrete indices. 295 (void)index; 296 297 return true; 298 } 299 300 bool FunctionScriptEmitter::prepareForParameters() { 301 MOZ_ASSERT(state_ == State::Start); 302 MOZ_ASSERT(bce_->inPrologue()); 303 304 // [stack] 305 306 if (paramStart_) { 307 bce_->setScriptStartOffsetIfUnset(*paramStart_); 308 } 309 310 // The ordering of these EmitterScopes is important. The named lambda 311 // scope needs to enclose the function scope needs to enclose the extra 312 // var scope. 313 314 if (funbox_->namedLambdaBindings()) { 315 namedLambdaEmitterScope_.emplace(bce_); 316 if (!namedLambdaEmitterScope_->enterNamedLambda(bce_, funbox_)) { 317 return false; 318 } 319 } 320 321 if (funbox_->needsPromiseResult()) { 322 asyncEmitter_.emplace(bce_); 323 } 324 325 if (bodyEnd_) { 326 bce_->setFunctionBodyEndPos(*bodyEnd_); 327 } 328 329 if (paramStart_) { 330 if (!bce_->updateLineNumberNotes(*paramStart_)) { 331 return false; 332 } 333 } 334 335 tdzCache_.emplace(bce_); 336 functionEmitterScope_.emplace(bce_); 337 338 if (!functionEmitterScope_->enterFunction(bce_, funbox_)) { 339 return false; 340 } 341 342 if (!emitInitializeClosedOverArgumentBindings()) { 343 // [stack] 344 return false; 345 } 346 347 if (funbox_->hasParameterExprs) { 348 // There's parameter exprs, emit them in the main section. 349 // 350 // One caveat is that Debugger considers ops in the prologue to be 351 // unreachable (i.e. cannot set a breakpoint on it). If there are no 352 // parameter exprs, any unobservable environment ops (like pushing the 353 // call object, setting '.this', etc) need to go in the prologue, else it 354 // messes up breakpoint tests. 355 bce_->switchToMain(); 356 } 357 358 if (!bce_->emitInitializeFunctionSpecialNames()) { 359 // [stack] 360 return false; 361 } 362 363 if (!funbox_->hasParameterExprs) { 364 bce_->switchToMain(); 365 } 366 367 if (funbox_->needsPromiseResult()) { 368 if (funbox_->hasParameterExprs || funbox_->hasDestructuringArgs) { 369 if (!asyncEmitter_->prepareForParamsWithExpressionOrDestructuring()) { 370 return false; 371 } 372 } else { 373 if (!asyncEmitter_->prepareForParamsWithoutExpressionOrDestructuring()) { 374 return false; 375 } 376 } 377 } 378 379 if (funbox_->isClassConstructor()) { 380 if (!funbox_->isDerivedClassConstructor()) { 381 if (!bce_->emitInitializeInstanceMembers(false)) { 382 // [stack] 383 return false; 384 } 385 } 386 } 387 388 #ifdef DEBUG 389 state_ = State::Parameters; 390 #endif 391 return true; 392 } 393 394 bool FunctionScriptEmitter::emitInitializeClosedOverArgumentBindings() { 395 // Initialize CallObject slots for closed-over arguments. If the function has 396 // parameter expressions, these are lexical bindings and we initialize the 397 // slots to the magic TDZ value. If the function doesn't have parameter 398 // expressions, we copy the frame's arguments. 399 400 MOZ_ASSERT(bce_->inPrologue()); 401 402 auto* bindings = funbox_->functionScopeBindings(); 403 if (!bindings) { 404 return true; 405 } 406 407 const bool hasParameterExprs = funbox_->hasParameterExprs; 408 409 bool pushedUninitialized = false; 410 for (ParserPositionalFormalParameterIter fi(*bindings, hasParameterExprs); fi; 411 fi++) { 412 if (!fi.closedOver()) { 413 continue; 414 } 415 416 if (hasParameterExprs) { 417 NameLocation nameLoc = bce_->lookupName(fi.name()); 418 if (!pushedUninitialized) { 419 if (!bce_->emit1(JSOp::Uninitialized)) { 420 // [stack] UNINITIALIZED 421 return false; 422 } 423 pushedUninitialized = true; 424 } 425 if (!bce_->emitEnvCoordOp(JSOp::InitAliasedLexical, 426 nameLoc.environmentCoordinate())) { 427 // [stack] UNINITIALIZED 428 return false; 429 } 430 } else { 431 NameOpEmitter noe(bce_, fi.name(), NameOpEmitter::Kind::Initialize); 432 if (!noe.prepareForRhs()) { 433 // [stack] 434 return false; 435 } 436 437 if (!bce_->emitArgOp(JSOp::GetFrameArg, fi.argumentSlot())) { 438 // [stack] VAL 439 return false; 440 } 441 442 if (!noe.emitAssignment()) { 443 // [stack] VAL 444 return false; 445 } 446 447 if (!bce_->emit1(JSOp::Pop)) { 448 // [stack] 449 return false; 450 } 451 } 452 } 453 454 if (pushedUninitialized) { 455 MOZ_ASSERT(hasParameterExprs); 456 if (!bce_->emit1(JSOp::Pop)) { 457 // [stack] 458 return false; 459 } 460 } 461 462 return true; 463 } 464 465 bool FunctionScriptEmitter::prepareForBody() { 466 MOZ_ASSERT(state_ == State::Parameters); 467 468 // [stack] 469 470 if (funbox_->needsPromiseResult()) { 471 if (!asyncEmitter_->emitParamsEpilogue()) { 472 return false; 473 } 474 } 475 476 if (!emitExtraBodyVarScope()) { 477 // [stack] 478 return false; 479 } 480 481 if (funbox_->needsPromiseResult()) { 482 if (!asyncEmitter_->prepareForBody()) { 483 return false; 484 } 485 } 486 487 #ifdef DEBUG 488 state_ = State::Body; 489 #endif 490 return true; 491 } 492 493 bool FunctionScriptEmitter::emitExtraBodyVarScope() { 494 // [stack] 495 496 if (!funbox_->functionHasExtraBodyVarScope()) { 497 return true; 498 } 499 500 extraBodyVarEmitterScope_.emplace(bce_); 501 if (!extraBodyVarEmitterScope_->enterFunctionExtraBodyVar(bce_, funbox_)) { 502 return false; 503 } 504 505 if (!funbox_->extraVarScopeBindings() || !funbox_->functionScopeBindings()) { 506 return true; 507 } 508 509 // After emitting expressions for all parameters, copy over any formal 510 // parameters which have been redeclared as vars. For example, in the 511 // following, the var y in the body scope is 42: 512 // 513 // function f(x, y = 42) { var y; } 514 // 515 for (ParserBindingIter bi(*funbox_->functionScopeBindings(), true); bi; 516 bi++) { 517 auto name = bi.name(); 518 519 // There may not be a var binding of the same name. 520 if (!bce_->locationOfNameBoundInScope(name, 521 extraBodyVarEmitterScope_.ptr())) { 522 continue; 523 } 524 525 // The '.this', '.newTarget', and '.generator' function special binding 526 // should never appear in the extra var scope. 'arguments', however, may. 527 MOZ_ASSERT(name != TaggedParserAtomIndex::WellKnown::dot_this_() && 528 name != TaggedParserAtomIndex::WellKnown::dot_newTarget_() && 529 name != TaggedParserAtomIndex::WellKnown::dot_generator_()); 530 531 NameOpEmitter noe(bce_, name, NameOpEmitter::Kind::Initialize); 532 if (!noe.prepareForRhs()) { 533 // [stack] 534 return false; 535 } 536 537 NameLocation paramLoc = 538 *bce_->locationOfNameBoundInScope(name, functionEmitterScope_.ptr()); 539 if (!bce_->emitGetNameAtLocation(name, paramLoc)) { 540 // [stack] VAL 541 return false; 542 } 543 544 if (!noe.emitAssignment()) { 545 // [stack] VAL 546 return false; 547 } 548 549 if (!bce_->emit1(JSOp::Pop)) { 550 // [stack] 551 return false; 552 } 553 } 554 555 return true; 556 } 557 558 bool FunctionScriptEmitter::emitEndBody() { 559 MOZ_ASSERT(state_ == State::Body); 560 // [stack] 561 562 if (bodyEnd_) { 563 if (!bce_->updateSourceCoordNotes(*bodyEnd_)) { 564 return false; 565 } 566 } 567 568 if (funbox_->needsFinalYield()) { 569 // If we fall off the end of a generator or async function, we 570 // do a final yield with an |undefined| payload. We put all 571 // the code to do this in one place, both to reduce bytecode 572 // size and to prevent any OOM or debugger exception that occurs 573 // at this point from being caught inside the function. 574 if (!bce_->emit1(JSOp::Undefined)) { 575 // [stack] UNDEF 576 return false; 577 } 578 if (!bce_->emit1(JSOp::SetRval)) { 579 // [stack] 580 return false; 581 } 582 583 // Return statements in the body of the function will jump here 584 // with the return payload in rval. 585 if (!bce_->emitJumpTargetAndPatch(bce_->finalYields)) { 586 // [stack] 587 return false; 588 } 589 590 if (funbox_->needsIteratorResult()) { 591 MOZ_ASSERT(!funbox_->needsPromiseResult()); 592 // Emit final yield bytecode for generators, for example: 593 // function gen * () { ... } 594 if (!bce_->emitPrepareIteratorResult()) { 595 // [stack] RESULT 596 return false; 597 } 598 599 if (!bce_->emit1(JSOp::GetRval)) { 600 // [stack] RESULT RVAL 601 return false; 602 } 603 604 if (!bce_->emitFinishIteratorResult(true)) { 605 // [stack] RESULT 606 return false; 607 } 608 609 if (!bce_->emit1(JSOp::SetRval)) { 610 // [stack] 611 return false; 612 } 613 614 } else if (funbox_->needsPromiseResult()) { 615 // Emit final yield bytecode for async functions, for example: 616 // async function deferred() { ... } 617 if (!bce_->emit1(JSOp::GetRval)) { 618 // [stack] RVAL 619 return false; 620 } 621 622 if (!bce_->emitGetDotGeneratorInInnermostScope()) { 623 // [stack] RVAL GEN 624 return false; 625 } 626 627 if (!bce_->emit1(JSOp::AsyncResolve)) { 628 // [stack] PROMISE 629 return false; 630 } 631 632 if (!bce_->emit1(JSOp::SetRval)) { 633 // [stack] 634 return false; 635 } 636 } 637 638 // Emit the final yield. 639 if (!bce_->emitGetDotGeneratorInInnermostScope()) { 640 // [stack] GEN 641 return false; 642 } 643 644 if (!bce_->emitYieldOp(JSOp::FinalYieldRval)) { 645 return false; 646 } 647 648 if (funbox_->needsPromiseResult()) { 649 // Emit the reject catch block. 650 if (!asyncEmitter_->emitEndFunction()) { 651 return false; 652 } 653 } 654 655 } else { 656 // Non-generator functions just return |undefined|. The 657 // JSOp::RetRval emitted below will do that, except if the 658 // script has a finally block: there can be a non-undefined 659 // value in the return value slot. Make sure the return value 660 // is |undefined|. 661 if (bce_->hasTryFinally) { 662 if (!bce_->emit1(JSOp::Undefined)) { 663 // [stack] UNDEF 664 return false; 665 } 666 if (!bce_->emit1(JSOp::SetRval)) { 667 // [stack] 668 return false; 669 } 670 } 671 } 672 673 // Execute |CheckReturn| right before exiting the class constructor. 674 if (funbox_->isDerivedClassConstructor()) { 675 if (!bce_->emitJumpTargetAndPatch(bce_->endOfDerivedClassConstructorBody)) { 676 return false; 677 } 678 679 if (!bce_->emitCheckDerivedClassConstructorReturn()) { 680 // [stack] 681 return false; 682 } 683 } 684 685 if (extraBodyVarEmitterScope_) { 686 if (!extraBodyVarEmitterScope_->leave(bce_)) { 687 return false; 688 } 689 690 extraBodyVarEmitterScope_.reset(); 691 } 692 693 if (!functionEmitterScope_->leave(bce_)) { 694 return false; 695 } 696 functionEmitterScope_.reset(); 697 tdzCache_.reset(); 698 699 // We only want to mark the end of a function as a breakable position if 700 // there is token there that the user can easily associate with the function 701 // as a whole. Since arrow function single-expression bodies have no closing 702 // curly bracket, we do not place a breakpoint at their end position. 703 if (!funbox_->hasExprBody()) { 704 if (!bce_->markSimpleBreakpoint()) { 705 return false; 706 } 707 } 708 709 // Emit JSOp::RetRval except for sync arrow function with expression body 710 // which always ends with JSOp::Return. Other parts of the codebase depend 711 // on these opcodes being the last opcode. 712 // See JSScript::lastPC and BaselineCompiler::emitBody. 713 if (!funbox_->hasExprBody() || funbox_->isAsync()) { 714 if (!bce_->emitReturnRval()) { 715 // [stack] 716 return false; 717 } 718 } 719 720 if (namedLambdaEmitterScope_) { 721 if (!namedLambdaEmitterScope_->leave(bce_)) { 722 return false; 723 } 724 namedLambdaEmitterScope_.reset(); 725 } 726 727 #ifdef DEBUG 728 state_ = State::EndBody; 729 #endif 730 return true; 731 } 732 733 bool FunctionScriptEmitter::intoStencil() { 734 MOZ_ASSERT(state_ == State::EndBody); 735 736 if (!bce_->intoScriptStencil(funbox_->index())) { 737 return false; 738 } 739 740 #ifdef DEBUG 741 state_ = State::End; 742 #endif 743 744 return true; 745 } 746 747 FunctionParamsEmitter::FunctionParamsEmitter(BytecodeEmitter* bce, 748 FunctionBox* funbox) 749 : bce_(bce), 750 funbox_(funbox), 751 functionEmitterScope_(bce_->innermostEmitterScope()) {} 752 753 bool FunctionParamsEmitter::emitSimple(TaggedParserAtomIndex paramName) { 754 MOZ_ASSERT(state_ == State::Start); 755 756 // [stack] 757 758 if (funbox_->hasParameterExprs) { 759 if (!bce_->emitArgOp(JSOp::GetArg, argSlot_)) { 760 // [stack] ARG 761 return false; 762 } 763 764 if (!emitAssignment(paramName)) { 765 // [stack] 766 return false; 767 } 768 } 769 770 argSlot_++; 771 return true; 772 } 773 774 bool FunctionParamsEmitter::prepareForDefault() { 775 MOZ_ASSERT(state_ == State::Start); 776 777 // [stack] 778 779 if (!prepareForInitializer()) { 780 // [stack] 781 return false; 782 } 783 784 #ifdef DEBUG 785 state_ = State::Default; 786 #endif 787 return true; 788 } 789 790 bool FunctionParamsEmitter::emitDefaultEnd(TaggedParserAtomIndex paramName) { 791 MOZ_ASSERT(state_ == State::Default); 792 793 // [stack] DEFAULT 794 795 if (!emitInitializerEnd()) { 796 // [stack] ARG/DEFAULT 797 return false; 798 } 799 if (!emitAssignment(paramName)) { 800 // [stack] 801 return false; 802 } 803 804 argSlot_++; 805 806 #ifdef DEBUG 807 state_ = State::Start; 808 #endif 809 return true; 810 } 811 812 bool FunctionParamsEmitter::prepareForDestructuring() { 813 MOZ_ASSERT(state_ == State::Start); 814 815 // [stack] 816 817 if (!bce_->emitArgOp(JSOp::GetArg, argSlot_)) { 818 // [stack] ARG 819 return false; 820 } 821 822 #ifdef DEBUG 823 state_ = State::Destructuring; 824 #endif 825 return true; 826 } 827 828 bool FunctionParamsEmitter::emitDestructuringEnd() { 829 MOZ_ASSERT(state_ == State::Destructuring); 830 831 // [stack] ARG 832 833 if (!bce_->emit1(JSOp::Pop)) { 834 // [stack] 835 return false; 836 } 837 838 argSlot_++; 839 840 #ifdef DEBUG 841 state_ = State::Start; 842 #endif 843 return true; 844 } 845 846 bool FunctionParamsEmitter::prepareForDestructuringDefaultInitializer() { 847 MOZ_ASSERT(state_ == State::Start); 848 849 // [stack] 850 851 if (!prepareForInitializer()) { 852 // [stack] 853 return false; 854 } 855 856 #ifdef DEBUG 857 state_ = State::DestructuringDefaultInitializer; 858 #endif 859 return true; 860 } 861 862 bool FunctionParamsEmitter::prepareForDestructuringDefault() { 863 MOZ_ASSERT(state_ == State::DestructuringDefaultInitializer); 864 865 // [stack] DEFAULT 866 867 if (!emitInitializerEnd()) { 868 // [stack] ARG/DEFAULT 869 return false; 870 } 871 872 #ifdef DEBUG 873 state_ = State::DestructuringDefault; 874 #endif 875 return true; 876 } 877 878 bool FunctionParamsEmitter::emitDestructuringDefaultEnd() { 879 MOZ_ASSERT(state_ == State::DestructuringDefault); 880 881 // [stack] ARG/DEFAULT 882 883 if (!bce_->emit1(JSOp::Pop)) { 884 // [stack] 885 return false; 886 } 887 888 argSlot_++; 889 890 #ifdef DEBUG 891 state_ = State::Start; 892 #endif 893 return true; 894 } 895 896 bool FunctionParamsEmitter::emitRest(TaggedParserAtomIndex paramName) { 897 MOZ_ASSERT(state_ == State::Start); 898 899 // [stack] 900 901 if (!emitRestArray()) { 902 // [stack] REST 903 return false; 904 } 905 if (!emitAssignment(paramName)) { 906 // [stack] 907 return false; 908 } 909 910 #ifdef DEBUG 911 state_ = State::End; 912 #endif 913 return true; 914 } 915 916 bool FunctionParamsEmitter::prepareForDestructuringRest() { 917 MOZ_ASSERT(state_ == State::Start); 918 919 // [stack] 920 921 if (!emitRestArray()) { 922 // [stack] REST 923 return false; 924 } 925 926 #ifdef DEBUG 927 state_ = State::DestructuringRest; 928 #endif 929 return true; 930 } 931 932 bool FunctionParamsEmitter::emitDestructuringRestEnd() { 933 MOZ_ASSERT(state_ == State::DestructuringRest); 934 935 // [stack] REST 936 937 if (!bce_->emit1(JSOp::Pop)) { 938 // [stack] 939 return false; 940 } 941 942 #ifdef DEBUG 943 state_ = State::End; 944 #endif 945 return true; 946 } 947 948 bool FunctionParamsEmitter::prepareForInitializer() { 949 // [stack] 950 951 // If we have an initializer, emit the initializer and assign it 952 // to the argument slot. TDZ is taken care of afterwards. 953 MOZ_ASSERT(funbox_->hasParameterExprs); 954 if (!bce_->emitArgOp(JSOp::GetArg, argSlot_)) { 955 // [stack] ARG 956 return false; 957 } 958 default_.emplace(bce_); 959 if (!default_->prepareForDefault()) { 960 // [stack] 961 return false; 962 } 963 return true; 964 } 965 966 bool FunctionParamsEmitter::emitInitializerEnd() { 967 // [stack] DEFAULT 968 969 if (!default_->emitEnd()) { 970 // [stack] ARG/DEFAULT 971 return false; 972 } 973 default_.reset(); 974 return true; 975 } 976 977 bool FunctionParamsEmitter::emitRestArray() { 978 // [stack] 979 980 if (!bce_->emit1(JSOp::Rest)) { 981 // [stack] REST 982 return false; 983 } 984 return true; 985 } 986 987 bool FunctionParamsEmitter::emitAssignment(TaggedParserAtomIndex paramName) { 988 // [stack] ARG 989 990 NameLocation paramLoc = 991 *bce_->locationOfNameBoundInScope(paramName, functionEmitterScope_); 992 993 // RHS is already pushed in the caller side. 994 // Make sure prepareForRhs doesn't touch stack. 995 MOZ_ASSERT(paramLoc.kind() == NameLocation::Kind::ArgumentSlot || 996 paramLoc.kind() == NameLocation::Kind::FrameSlot || 997 paramLoc.kind() == NameLocation::Kind::EnvironmentCoordinate); 998 999 NameOpEmitter noe(bce_, paramName, paramLoc, NameOpEmitter::Kind::Initialize); 1000 if (!noe.prepareForRhs()) { 1001 // [stack] ARG 1002 return false; 1003 } 1004 1005 if (!noe.emitAssignment()) { 1006 // [stack] ARG 1007 return false; 1008 } 1009 1010 if (!bce_->emit1(JSOp::Pop)) { 1011 // [stack] 1012 return false; 1013 } 1014 1015 return true; 1016 }