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/. */
7 #include "frontend/ObjectEmitter.h"
9 #include "mozilla/Assertions.h" // MOZ_ASSERT
11 #include "frontend/BytecodeEmitter.h" // BytecodeEmitter
12 #include "frontend/IfEmitter.h" // IfEmitter
13 #include "frontend/ParseNode.h" // AccessorType
14 #include "frontend/SharedContext.h" // SharedContext
15 #include "vm/FunctionPrefixKind.h" // FunctionPrefixKind
16 #include "vm/Opcodes.h" // JSOp
19 using namespace js::frontend
;
23 PropertyEmitter::PropertyEmitter(BytecodeEmitter
* bce
) : bce_(bce
) {}
25 bool PropertyEmitter::prepareForProtoValue(uint32_t keyPos
) {
26 MOZ_ASSERT(propertyState_
== PropertyState::Start
||
27 propertyState_
== PropertyState::Init
);
29 // [stack] CTOR? OBJ CTOR?
31 if (!bce_
->updateSourceCoordNotes(keyPos
)) {
36 propertyState_
= PropertyState::ProtoValue
;
41 bool PropertyEmitter::emitMutateProto() {
42 MOZ_ASSERT(propertyState_
== PropertyState::ProtoValue
);
46 if (!bce_
->emit1(JSOp::MutateProto
)) {
52 propertyState_
= PropertyState::Init
;
57 bool PropertyEmitter::prepareForSpreadOperand(uint32_t spreadPos
) {
58 MOZ_ASSERT(propertyState_
== PropertyState::Start
||
59 propertyState_
== PropertyState::Init
);
63 if (!bce_
->updateSourceCoordNotes(spreadPos
)) {
66 if (!bce_
->emit1(JSOp::Dup
)) {
72 propertyState_
= PropertyState::SpreadOperand
;
77 bool PropertyEmitter::emitSpread() {
78 MOZ_ASSERT(propertyState_
== PropertyState::SpreadOperand
);
80 // [stack] OBJ OBJ VAL
82 if (!bce_
->emitCopyDataProperties(BytecodeEmitter::CopyOption::Unfiltered
)) {
88 propertyState_
= PropertyState::Init
;
93 MOZ_ALWAYS_INLINE
bool PropertyEmitter::prepareForProp(uint32_t keyPos
,
95 bool isIndexOrComputed
) {
97 isIndexOrComputed_
= isIndexOrComputed
;
101 if (!bce_
->updateSourceCoordNotes(keyPos
)) {
106 if (!bce_
->emit1(JSOp::Dup2
)) {
107 // [stack] CTOR HOMEOBJ CTOR HOMEOBJ
110 if (!bce_
->emit1(JSOp::Pop
)) {
111 // [stack] CTOR HOMEOBJ CTOR
119 bool PropertyEmitter::prepareForPrivateMethod() {
120 MOZ_ASSERT(propertyState_
== PropertyState::Start
||
121 propertyState_
== PropertyState::Init
);
122 MOZ_ASSERT(isClass_
);
125 isIndexOrComputed_
= false;
128 propertyState_
= PropertyState::PrivateMethodValue
;
133 bool PropertyEmitter::prepareForPrivateStaticMethod(uint32_t keyPos
) {
134 MOZ_ASSERT(propertyState_
== PropertyState::Start
||
135 propertyState_
== PropertyState::Init
);
136 MOZ_ASSERT(isClass_
);
140 if (!prepareForProp(keyPos
,
141 /* isStatic_ = */ true,
142 /* isIndexOrComputed = */ true)) {
143 // [stack] CTOR OBJ CTOR
148 propertyState_
= PropertyState::PrivateStaticMethod
;
153 bool PropertyEmitter::prepareForPropValue(uint32_t keyPos
, Kind kind
) {
154 MOZ_ASSERT(propertyState_
== PropertyState::Start
||
155 propertyState_
== PropertyState::Init
);
159 if (!prepareForProp(keyPos
,
160 /* isStatic_ = */ kind
== Kind::Static
,
161 /* isIndexOrComputed = */ false)) {
162 // [stack] CTOR? OBJ CTOR?
167 propertyState_
= PropertyState::PropValue
;
172 bool PropertyEmitter::prepareForIndexPropKey(uint32_t keyPos
, Kind kind
) {
173 MOZ_ASSERT(propertyState_
== PropertyState::Start
||
174 propertyState_
== PropertyState::Init
);
178 if (!prepareForProp(keyPos
,
179 /* isStatic_ = */ kind
== Kind::Static
,
180 /* isIndexOrComputed = */ true)) {
181 // [stack] CTOR? OBJ CTOR?
186 propertyState_
= PropertyState::IndexKey
;
191 bool PropertyEmitter::prepareForIndexPropValue() {
192 MOZ_ASSERT(propertyState_
== PropertyState::IndexKey
);
194 // [stack] CTOR? OBJ CTOR? KEY
197 propertyState_
= PropertyState::IndexValue
;
202 bool PropertyEmitter::prepareForComputedPropKey(uint32_t keyPos
, Kind kind
) {
203 MOZ_ASSERT(propertyState_
== PropertyState::Start
||
204 propertyState_
== PropertyState::Init
);
208 if (!prepareForProp(keyPos
,
209 /* isStatic_ = */ kind
== Kind::Static
,
210 /* isIndexOrComputed = */ true)) {
211 // [stack] CTOR? OBJ CTOR?
216 propertyState_
= PropertyState::ComputedKey
;
221 bool PropertyEmitter::prepareForComputedPropValue() {
222 MOZ_ASSERT(propertyState_
== PropertyState::ComputedKey
);
224 // [stack] CTOR? OBJ CTOR? KEY
226 if (!bce_
->emit1(JSOp::ToPropertyKey
)) {
227 // [stack] CTOR? OBJ CTOR? KEY
232 propertyState_
= PropertyState::ComputedValue
;
237 bool PropertyEmitter::emitInitHomeObject() {
238 MOZ_ASSERT(propertyState_
== PropertyState::PropValue
||
239 propertyState_
== PropertyState::PrivateMethodValue
||
240 propertyState_
== PropertyState::PrivateStaticMethod
||
241 propertyState_
== PropertyState::IndexValue
||
242 propertyState_
== PropertyState::ComputedValue
);
244 // [stack] CTOR? HOMEOBJ CTOR? KEY? FUN
246 // There are the following values on the stack conditionally, between
248 // * the 2nd CTOR if isStatic_
249 // * KEY if isIndexOrComputed_
251 // JSOp::InitHomeObject uses one of the following:
252 // * HOMEOBJ if !isStatic_
253 // (`super.foo` points the super prototype property)
254 // * the 2nd CTOR if isStatic_
255 // (`super.foo` points the super constructor property)
256 if (!bce_
->emitDupAt(1 + isIndexOrComputed_
)) {
257 // [stack] # non-static method
258 // [stack] CTOR? HOMEOBJ CTOR KEY? FUN CTOR
259 // [stack] # static method
260 // [stack] CTOR? HOMEOBJ KEY? FUN HOMEOBJ
263 if (!bce_
->emit1(JSOp::InitHomeObject
)) {
264 // [stack] CTOR? HOMEOBJ CTOR? KEY? FUN
269 if (propertyState_
== PropertyState::PropValue
) {
270 propertyState_
= PropertyState::InitHomeObj
;
271 } else if (propertyState_
== PropertyState::PrivateMethodValue
) {
272 propertyState_
= PropertyState::InitHomeObjForPrivateMethod
;
273 } else if (propertyState_
== PropertyState::PrivateStaticMethod
) {
274 propertyState_
= PropertyState::InitHomeObjForPrivateStaticMethod
;
275 } else if (propertyState_
== PropertyState::IndexValue
) {
276 propertyState_
= PropertyState::InitHomeObjForIndex
;
278 propertyState_
= PropertyState::InitHomeObjForComputed
;
284 bool PropertyEmitter::emitInit(AccessorType accessorType
,
285 TaggedParserAtomIndex key
) {
286 switch (accessorType
) {
287 case AccessorType::None
:
288 return emitInit(isClass_
? JSOp::InitHiddenProp
: JSOp::InitProp
, key
);
289 case AccessorType::Getter
:
291 isClass_
? JSOp::InitHiddenPropGetter
: JSOp::InitPropGetter
, key
);
292 case AccessorType::Setter
:
294 isClass_
? JSOp::InitHiddenPropSetter
: JSOp::InitPropSetter
, key
);
296 MOZ_CRASH("Invalid op");
299 bool PropertyEmitter::emitInitIndexOrComputed(AccessorType accessorType
) {
300 switch (accessorType
) {
301 case AccessorType::None
:
302 return emitInitIndexOrComputed(isClass_
? JSOp::InitHiddenElem
304 case AccessorType::Getter
:
305 return emitInitIndexOrComputed(isClass_
? JSOp::InitHiddenElemGetter
306 : JSOp::InitElemGetter
);
307 case AccessorType::Setter
:
308 return emitInitIndexOrComputed(isClass_
? JSOp::InitHiddenElemSetter
309 : JSOp::InitElemSetter
);
311 MOZ_CRASH("Invalid op");
314 bool PropertyEmitter::emitPrivateStaticMethod(AccessorType accessorType
) {
315 MOZ_ASSERT(isClass_
);
317 switch (accessorType
) {
318 case AccessorType::None
:
319 return emitInitIndexOrComputed(JSOp::InitLockedElem
);
320 case AccessorType::Getter
:
321 return emitInitIndexOrComputed(JSOp::InitHiddenElemGetter
);
322 case AccessorType::Setter
:
323 return emitInitIndexOrComputed(JSOp::InitHiddenElemSetter
);
325 MOZ_CRASH("Invalid op");
328 bool PropertyEmitter::emitInit(JSOp op
, TaggedParserAtomIndex key
) {
329 MOZ_ASSERT(propertyState_
== PropertyState::PropValue
||
330 propertyState_
== PropertyState::InitHomeObj
);
332 MOZ_ASSERT(op
== JSOp::InitProp
|| op
== JSOp::InitHiddenProp
||
333 op
== JSOp::InitPropGetter
|| op
== JSOp::InitHiddenPropGetter
||
334 op
== JSOp::InitPropSetter
|| op
== JSOp::InitHiddenPropSetter
);
336 // [stack] CTOR? OBJ CTOR? VAL
338 if (!bce_
->emitAtomOp(op
, key
)) {
339 // [stack] CTOR? OBJ CTOR?
343 if (!emitPopClassConstructor()) {
348 propertyState_
= PropertyState::Init
;
353 bool PropertyEmitter::skipInit() {
354 MOZ_ASSERT(propertyState_
== PropertyState::PrivateMethodValue
||
355 propertyState_
== PropertyState::InitHomeObjForPrivateMethod
);
357 propertyState_
= PropertyState::Init
;
362 bool PropertyEmitter::emitInitIndexOrComputed(JSOp op
) {
363 MOZ_ASSERT(propertyState_
== PropertyState::IndexValue
||
364 propertyState_
== PropertyState::InitHomeObjForIndex
||
365 propertyState_
== PropertyState::ComputedValue
||
366 propertyState_
== PropertyState::InitHomeObjForComputed
||
367 propertyState_
== PropertyState::PrivateStaticMethod
||
369 PropertyState::InitHomeObjForPrivateStaticMethod
);
371 MOZ_ASSERT(op
== JSOp::InitElem
|| op
== JSOp::InitHiddenElem
||
372 op
== JSOp::InitLockedElem
|| op
== JSOp::InitElemGetter
||
373 op
== JSOp::InitHiddenElemGetter
|| op
== JSOp::InitElemSetter
||
374 op
== JSOp::InitHiddenElemSetter
);
376 // [stack] CTOR? OBJ CTOR? KEY VAL
378 if (!bce_
->emit1(op
)) {
379 // [stack] CTOR? OBJ CTOR?
383 if (!emitPopClassConstructor()) {
388 propertyState_
= PropertyState::Init
;
393 bool PropertyEmitter::emitPopClassConstructor() {
395 // [stack] CTOR HOMEOBJ CTOR
397 if (!bce_
->emit1(JSOp::Pop
)) {
398 // [stack] CTOR HOMEOBJ
406 ObjectEmitter::ObjectEmitter(BytecodeEmitter
* bce
) : PropertyEmitter(bce
) {}
408 bool ObjectEmitter::emitObject(size_t propertyCount
) {
409 MOZ_ASSERT(propertyState_
== PropertyState::Start
);
410 MOZ_ASSERT(objectState_
== ObjectState::Start
);
414 // Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing
415 // a new object and defining (in source order) each property on the object
416 // (or mutating the object's [[Prototype]], in the case of __proto__).
417 if (!bce_
->emit1(JSOp::NewInit
)) {
423 objectState_
= ObjectState::Object
;
428 bool ObjectEmitter::emitObjectWithTemplateOnStack() {
429 MOZ_ASSERT(propertyState_
== PropertyState::Start
);
430 MOZ_ASSERT(objectState_
== ObjectState::Start
);
433 objectState_
= ObjectState::Object
;
438 bool ObjectEmitter::emitEnd() {
439 MOZ_ASSERT(propertyState_
== PropertyState::Start
||
440 propertyState_
== PropertyState::Init
);
441 MOZ_ASSERT(objectState_
== ObjectState::Object
);
446 objectState_
= ObjectState::End
;
451 AutoSaveLocalStrictMode::AutoSaveLocalStrictMode(SharedContext
* sc
) : sc_(sc
) {
452 savedStrictness_
= sc_
->setLocalStrictMode(true);
455 AutoSaveLocalStrictMode::~AutoSaveLocalStrictMode() {
461 void AutoSaveLocalStrictMode::restore() {
462 MOZ_ALWAYS_TRUE(sc_
->setLocalStrictMode(savedStrictness_
));
466 ClassEmitter::ClassEmitter(BytecodeEmitter
* bce
)
467 : PropertyEmitter(bce
), strictMode_(bce
->sc
) {
471 bool ClassEmitter::emitScope(LexicalScope::ParserData
* scopeBindings
) {
472 MOZ_ASSERT(propertyState_
== PropertyState::Start
);
473 MOZ_ASSERT(classState_
== ClassState::Start
);
475 tdzCache_
.emplace(bce_
);
477 innerScope_
.emplace(bce_
);
478 if (!innerScope_
->enterLexical(bce_
, ScopeKind::Lexical
, scopeBindings
)) {
483 classState_
= ClassState::Scope
;
489 bool ClassEmitter::emitBodyScope(ClassBodyScope::ParserData
* scopeBindings
) {
490 MOZ_ASSERT(propertyState_
== PropertyState::Start
);
491 MOZ_ASSERT(classState_
== ClassState::Start
||
492 classState_
== ClassState::Scope
);
494 bodyTdzCache_
.emplace(bce_
);
496 bodyScope_
.emplace(bce_
);
497 if (!bodyScope_
->enterClassBody(bce_
, ScopeKind::ClassBody
, scopeBindings
)) {
502 classState_
= ClassState::BodyScope
;
508 bool ClassEmitter::emitClass(TaggedParserAtomIndex name
,
509 TaggedParserAtomIndex nameForAnonymousClass
,
510 bool hasNameOnStack
) {
511 MOZ_ASSERT(propertyState_
== PropertyState::Start
);
512 MOZ_ASSERT(classState_
== ClassState::Start
||
513 classState_
== ClassState::Scope
||
514 classState_
== ClassState::BodyScope
);
515 MOZ_ASSERT_IF(nameForAnonymousClass
|| hasNameOnStack
, !name
);
516 MOZ_ASSERT(!(nameForAnonymousClass
&& hasNameOnStack
));
521 nameForAnonymousClass_
= nameForAnonymousClass
;
522 hasNameOnStack_
= hasNameOnStack
;
525 if (!bce_
->emit1(JSOp::NewInit
)) {
531 classState_
= ClassState::Class
;
536 bool ClassEmitter::emitDerivedClass(TaggedParserAtomIndex name
,
537 TaggedParserAtomIndex nameForAnonymousClass
,
538 bool hasNameOnStack
) {
539 MOZ_ASSERT(propertyState_
== PropertyState::Start
);
540 MOZ_ASSERT(classState_
== ClassState::Start
||
541 classState_
== ClassState::Scope
||
542 classState_
== ClassState::BodyScope
);
543 MOZ_ASSERT_IF(nameForAnonymousClass
|| hasNameOnStack
, !name
);
544 MOZ_ASSERT(!nameForAnonymousClass
|| !hasNameOnStack
);
549 nameForAnonymousClass_
= nameForAnonymousClass
;
550 hasNameOnStack_
= hasNameOnStack
;
553 InternalIfEmitter
ifThenElse(bce_
);
555 // Heritage must be null or a non-generator constructor
556 if (!bce_
->emit1(JSOp::CheckClassHeritage
)) {
561 // [IF] (heritage !== null)
562 if (!bce_
->emit1(JSOp::Dup
)) {
563 // [stack] HERITAGE HERITAGE
566 if (!bce_
->emit1(JSOp::Null
)) {
567 // [stack] HERITAGE HERITAGE NULL
570 if (!bce_
->emit1(JSOp::StrictNe
)) {
571 // [stack] HERITAGE NE
575 // [THEN] funProto = heritage, objProto = heritage.prototype
576 if (!ifThenElse
.emitThenElse()) {
579 if (!bce_
->emit1(JSOp::Dup
)) {
580 // [stack] HERITAGE HERITAGE
583 if (!bce_
->emitAtomOp(JSOp::GetProp
,
584 TaggedParserAtomIndex::WellKnown::prototype())) {
585 // [stack] HERITAGE PROTO
589 // [ELSE] funProto = %FunctionPrototype%, objProto = null
590 if (!ifThenElse
.emitElse()) {
593 if (!bce_
->emit1(JSOp::Pop
)) {
597 if (!bce_
->emitBuiltinObject(BuiltinObjectKind::FunctionPrototype
)) {
601 if (!bce_
->emit1(JSOp::Null
)) {
602 // [stack] PROTO NULL
607 if (!ifThenElse
.emitEnd()) {
611 if (!bce_
->emit1(JSOp::ObjWithProto
)) {
612 // [stack] HERITAGE HOMEOBJ
615 if (!bce_
->emit1(JSOp::Swap
)) {
616 // [stack] HOMEOBJ HERITAGE
621 classState_
= ClassState::Class
;
626 bool ClassEmitter::emitInitConstructor(bool needsHomeObject
) {
627 MOZ_ASSERT(classState_
== ClassState::Class
||
628 classState_
== ClassState::InstanceMemberInitializersEnd
);
630 // [stack] HOMEOBJ CTOR
632 if (needsHomeObject
) {
633 if (!bce_
->emitDupAt(1)) {
634 // [stack] HOMEOBJ CTOR HOMEOBJ
637 if (!bce_
->emit1(JSOp::InitHomeObject
)) {
638 // [stack] HOMEOBJ CTOR
643 if (!initProtoAndCtor()) {
644 // [stack] CTOR HOMEOBJ
649 classState_
= ClassState::InitConstructor
;
654 bool ClassEmitter::initProtoAndCtor() {
655 // [stack] NAME? HOMEOBJ CTOR
657 if (hasNameOnStack_
) {
658 if (!bce_
->emitDupAt(2)) {
659 // [stack] NAME HOMEOBJ CTOR NAME
662 if (!bce_
->emit2(JSOp::SetFunName
, uint8_t(FunctionPrefixKind::None
))) {
663 // [stack] NAME HOMEOBJ CTOR
668 if (!bce_
->emit1(JSOp::Swap
)) {
669 // [stack] NAME? CTOR HOMEOBJ
672 if (!bce_
->emit1(JSOp::Dup2
)) {
673 // [stack] NAME? CTOR HOMEOBJ CTOR HOMEOBJ
676 if (!bce_
->emitAtomOp(JSOp::InitLockedProp
,
677 TaggedParserAtomIndex::WellKnown::prototype())) {
678 // [stack] NAME? CTOR HOMEOBJ CTOR
681 if (!bce_
->emitAtomOp(JSOp::InitHiddenProp
,
682 TaggedParserAtomIndex::WellKnown::constructor())) {
683 // [stack] NAME? CTOR HOMEOBJ
690 bool ClassEmitter::prepareForMemberInitializers(size_t numInitializers
,
692 MOZ_ASSERT_IF(!isStatic
, classState_
== ClassState::Class
);
693 MOZ_ASSERT_IF(isStatic
, classState_
== ClassState::InitConstructor
);
694 MOZ_ASSERT(memberState_
== MemberState::Start
);
696 // .initializers is a variable that stores an array of lambdas containing
697 // code (the initializer) for each field. Upon an object's construction,
698 // these lambdas will be called, defining the values.
700 isStatic
? TaggedParserAtomIndex::WellKnown::dot_staticInitializers_()
701 : TaggedParserAtomIndex::WellKnown::dot_initializers_();
702 initializersAssignment_
.emplace(bce_
, initializers
,
703 NameOpEmitter::Kind::Initialize
);
704 if (!initializersAssignment_
->prepareForRhs()) {
708 if (!bce_
->emitUint32Operand(JSOp::NewArray
, numInitializers
)) {
713 initializerIndex_
= 0;
716 classState_
= ClassState::StaticMemberInitializers
;
718 classState_
= ClassState::InstanceMemberInitializers
;
720 numInitializers_
= numInitializers
;
725 bool ClassEmitter::prepareForMemberInitializer() {
726 MOZ_ASSERT(classState_
== ClassState::InstanceMemberInitializers
||
727 classState_
== ClassState::StaticMemberInitializers
);
728 MOZ_ASSERT(memberState_
== MemberState::Start
);
731 memberState_
= MemberState::Initializer
;
736 bool ClassEmitter::emitMemberInitializerHomeObject(bool isStatic
) {
737 MOZ_ASSERT(memberState_
== MemberState::Initializer
);
738 // [stack] OBJ HERITAGE? ARRAY METHOD
740 // [stack] CTOR HOMEOBJ ARRAY METHOD
743 if (!bce_
->emitDupAt(3)) {
744 // [stack] CTOR HOMEOBJ ARRAY METHOD CTOR
748 if (!bce_
->emitDupAt(isDerived_
? 3 : 2)) {
749 // [stack] OBJ HERITAGE? ARRAY METHOD OBJ
753 if (!bce_
->emit1(JSOp::InitHomeObject
)) {
754 // [stack] OBJ HERITAGE? ARRAY METHOD
756 // [stack] CTOR HOMEOBJ ARRAY METHOD
761 memberState_
= MemberState::InitializerWithHomeObject
;
766 bool ClassEmitter::emitStoreMemberInitializer() {
767 MOZ_ASSERT(memberState_
== MemberState::Initializer
||
768 memberState_
== MemberState::InitializerWithHomeObject
);
769 MOZ_ASSERT(initializerIndex_
< numInitializers_
);
770 // [stack] HOMEOBJ HERITAGE? ARRAY METHOD
772 if (!bce_
->emitUint32Operand(JSOp::InitElemArray
, initializerIndex_
)) {
773 // [stack] HOMEOBJ HERITAGE? ARRAY
779 memberState_
= MemberState::Start
;
784 bool ClassEmitter::emitMemberInitializersEnd() {
785 MOZ_ASSERT(propertyState_
== PropertyState::Start
||
786 propertyState_
== PropertyState::Init
);
787 MOZ_ASSERT(classState_
== ClassState::InstanceMemberInitializers
||
788 classState_
== ClassState::StaticMemberInitializers
);
789 MOZ_ASSERT(memberState_
== MemberState::Start
);
790 MOZ_ASSERT(initializerIndex_
== numInitializers_
);
792 if (!initializersAssignment_
->emitAssignment()) {
793 // [stack] HOMEOBJ HERITAGE? ARRAY
796 initializersAssignment_
.reset();
798 if (!bce_
->emit1(JSOp::Pop
)) {
799 // [stack] HOMEOBJ HERITAGE?
804 if (classState_
== ClassState::InstanceMemberInitializers
) {
805 classState_
= ClassState::InstanceMemberInitializersEnd
;
807 classState_
= ClassState::StaticMemberInitializersEnd
;
813 bool ClassEmitter::emitBinding() {
814 MOZ_ASSERT(propertyState_
== PropertyState::Start
||
815 propertyState_
== PropertyState::Init
);
816 MOZ_ASSERT(classState_
== ClassState::InitConstructor
||
817 classState_
== ClassState::InstanceMemberInitializersEnd
||
818 classState_
== ClassState::StaticMemberInitializersEnd
);
819 // [stack] CTOR HOMEOBJ
821 if (!bce_
->emit1(JSOp::Pop
)) {
827 MOZ_ASSERT(innerScope_
.isSome());
829 if (!bce_
->emitLexicalInitialization(name_
)) {
838 classState_
= ClassState::BoundName
;
843 #ifdef ENABLE_DECORATORS
844 bool ClassEmitter::prepareForDecorators() { return leaveBodyAndInnerScope(); }
847 bool ClassEmitter::leaveBodyAndInnerScope() {
848 if (bodyScope_
.isSome()) {
849 MOZ_ASSERT(bodyTdzCache_
.isSome());
851 if (!bodyScope_
->leave(bce_
)) {
855 bodyTdzCache_
.reset();
858 if (innerScope_
.isSome()) {
859 MOZ_ASSERT(tdzCache_
.isSome());
861 if (!innerScope_
->leave(bce_
)) {
867 MOZ_ASSERT(tdzCache_
.isNothing());
873 bool ClassEmitter::emitEnd(Kind kind
) {
874 MOZ_ASSERT(classState_
== ClassState::BoundName
);
877 #ifndef ENABLE_DECORATORS
878 if (!leaveBodyAndInnerScope()) {
883 if (kind
== Kind::Declaration
) {
886 if (!bce_
->emitLexicalInitialization(name_
)) {
890 // Only class statements make outer bindings, and they do not leave
891 // themselves on the stack.
892 if (!bce_
->emit1(JSOp::Pop
)) {
898 // [stack] # class declaration
900 // [stack] # class expression
903 strictMode_
.restore();
906 classState_
= ClassState::End
;