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