Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / frontend / ObjectEmitter.cpp
blob6758a4954c15e00a79a822e994b0a31b87a42b80
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
18 using namespace js;
19 using namespace js::frontend;
21 using mozilla::Maybe;
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)) {
32 return false;
35 #ifdef DEBUG
36 propertyState_ = PropertyState::ProtoValue;
37 #endif
38 return true;
41 bool PropertyEmitter::emitMutateProto() {
42 MOZ_ASSERT(propertyState_ == PropertyState::ProtoValue);
44 // [stack] OBJ PROTO
46 if (!bce_->emit1(JSOp::MutateProto)) {
47 // [stack] OBJ
48 return false;
51 #ifdef DEBUG
52 propertyState_ = PropertyState::Init;
53 #endif
54 return true;
57 bool PropertyEmitter::prepareForSpreadOperand(uint32_t spreadPos) {
58 MOZ_ASSERT(propertyState_ == PropertyState::Start ||
59 propertyState_ == PropertyState::Init);
61 // [stack] OBJ
63 if (!bce_->updateSourceCoordNotes(spreadPos)) {
64 return false;
66 if (!bce_->emit1(JSOp::Dup)) {
67 // [stack] OBJ OBJ
68 return false;
71 #ifdef DEBUG
72 propertyState_ = PropertyState::SpreadOperand;
73 #endif
74 return true;
77 bool PropertyEmitter::emitSpread() {
78 MOZ_ASSERT(propertyState_ == PropertyState::SpreadOperand);
80 // [stack] OBJ OBJ VAL
82 if (!bce_->emitCopyDataProperties(BytecodeEmitter::CopyOption::Unfiltered)) {
83 // [stack] OBJ
84 return false;
87 #ifdef DEBUG
88 propertyState_ = PropertyState::Init;
89 #endif
90 return true;
93 MOZ_ALWAYS_INLINE bool PropertyEmitter::prepareForProp(uint32_t keyPos,
94 bool isStatic,
95 bool isIndexOrComputed) {
96 isStatic_ = isStatic;
97 isIndexOrComputed_ = isIndexOrComputed;
99 // [stack] CTOR? OBJ
101 if (!bce_->updateSourceCoordNotes(keyPos)) {
102 return false;
105 if (isStatic_) {
106 if (!bce_->emit1(JSOp::Dup2)) {
107 // [stack] CTOR HOMEOBJ CTOR HOMEOBJ
108 return false;
110 if (!bce_->emit1(JSOp::Pop)) {
111 // [stack] CTOR HOMEOBJ CTOR
112 return false;
116 return true;
119 bool PropertyEmitter::prepareForPrivateMethod() {
120 MOZ_ASSERT(propertyState_ == PropertyState::Start ||
121 propertyState_ == PropertyState::Init);
122 MOZ_ASSERT(isClass_);
124 isStatic_ = false;
125 isIndexOrComputed_ = false;
127 #ifdef DEBUG
128 propertyState_ = PropertyState::PrivateMethodValue;
129 #endif
130 return true;
133 bool PropertyEmitter::prepareForPrivateStaticMethod(uint32_t keyPos) {
134 MOZ_ASSERT(propertyState_ == PropertyState::Start ||
135 propertyState_ == PropertyState::Init);
136 MOZ_ASSERT(isClass_);
138 // [stack] CTOR OBJ
140 if (!prepareForProp(keyPos,
141 /* isStatic_ = */ true,
142 /* isIndexOrComputed = */ true)) {
143 // [stack] CTOR OBJ CTOR
144 return false;
147 #ifdef DEBUG
148 propertyState_ = PropertyState::PrivateStaticMethod;
149 #endif
150 return true;
153 bool PropertyEmitter::prepareForPropValue(uint32_t keyPos, Kind kind) {
154 MOZ_ASSERT(propertyState_ == PropertyState::Start ||
155 propertyState_ == PropertyState::Init);
157 // [stack] CTOR? OBJ
159 if (!prepareForProp(keyPos,
160 /* isStatic_ = */ kind == Kind::Static,
161 /* isIndexOrComputed = */ false)) {
162 // [stack] CTOR? OBJ CTOR?
163 return false;
166 #ifdef DEBUG
167 propertyState_ = PropertyState::PropValue;
168 #endif
169 return true;
172 bool PropertyEmitter::prepareForIndexPropKey(uint32_t keyPos, Kind kind) {
173 MOZ_ASSERT(propertyState_ == PropertyState::Start ||
174 propertyState_ == PropertyState::Init);
176 // [stack] CTOR? OBJ
178 if (!prepareForProp(keyPos,
179 /* isStatic_ = */ kind == Kind::Static,
180 /* isIndexOrComputed = */ true)) {
181 // [stack] CTOR? OBJ CTOR?
182 return false;
185 #ifdef DEBUG
186 propertyState_ = PropertyState::IndexKey;
187 #endif
188 return true;
191 bool PropertyEmitter::prepareForIndexPropValue() {
192 MOZ_ASSERT(propertyState_ == PropertyState::IndexKey);
194 // [stack] CTOR? OBJ CTOR? KEY
196 #ifdef DEBUG
197 propertyState_ = PropertyState::IndexValue;
198 #endif
199 return true;
202 bool PropertyEmitter::prepareForComputedPropKey(uint32_t keyPos, Kind kind) {
203 MOZ_ASSERT(propertyState_ == PropertyState::Start ||
204 propertyState_ == PropertyState::Init);
206 // [stack] CTOR? OBJ
208 if (!prepareForProp(keyPos,
209 /* isStatic_ = */ kind == Kind::Static,
210 /* isIndexOrComputed = */ true)) {
211 // [stack] CTOR? OBJ CTOR?
212 return false;
215 #ifdef DEBUG
216 propertyState_ = PropertyState::ComputedKey;
217 #endif
218 return true;
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
228 return false;
231 #ifdef DEBUG
232 propertyState_ = PropertyState::ComputedValue;
233 #endif
234 return true;
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
247 // HOMEOBJ and FUN:
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
261 return false;
263 if (!bce_->emit1(JSOp::InitHomeObject)) {
264 // [stack] CTOR? HOMEOBJ CTOR? KEY? FUN
265 return false;
268 #ifdef DEBUG
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;
277 } else {
278 propertyState_ = PropertyState::InitHomeObjForComputed;
280 #endif
281 return true;
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:
290 return emitInit(
291 isClass_ ? JSOp::InitHiddenPropGetter : JSOp::InitPropGetter, key);
292 case AccessorType::Setter:
293 return emitInit(
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
303 : JSOp::InitElem);
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?
340 return false;
343 if (!emitPopClassConstructor()) {
344 return false;
347 #ifdef DEBUG
348 propertyState_ = PropertyState::Init;
349 #endif
350 return true;
353 bool PropertyEmitter::skipInit() {
354 MOZ_ASSERT(propertyState_ == PropertyState::PrivateMethodValue ||
355 propertyState_ == PropertyState::InitHomeObjForPrivateMethod);
356 #ifdef DEBUG
357 propertyState_ = PropertyState::Init;
358 #endif
359 return true;
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 ||
368 propertyState_ ==
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?
380 return false;
383 if (!emitPopClassConstructor()) {
384 return false;
387 #ifdef DEBUG
388 propertyState_ = PropertyState::Init;
389 #endif
390 return true;
393 bool PropertyEmitter::emitPopClassConstructor() {
394 if (isStatic_) {
395 // [stack] CTOR HOMEOBJ CTOR
397 if (!bce_->emit1(JSOp::Pop)) {
398 // [stack] CTOR HOMEOBJ
399 return false;
403 return true;
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);
412 // [stack]
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)) {
418 // [stack] OBJ
419 return false;
422 #ifdef DEBUG
423 objectState_ = ObjectState::Object;
424 #endif
425 return true;
428 bool ObjectEmitter::emitObjectWithTemplateOnStack() {
429 MOZ_ASSERT(propertyState_ == PropertyState::Start);
430 MOZ_ASSERT(objectState_ == ObjectState::Start);
432 #ifdef DEBUG
433 objectState_ = ObjectState::Object;
434 #endif
435 return true;
438 bool ObjectEmitter::emitEnd() {
439 MOZ_ASSERT(propertyState_ == PropertyState::Start ||
440 propertyState_ == PropertyState::Init);
441 MOZ_ASSERT(objectState_ == ObjectState::Object);
443 // [stack] OBJ
445 #ifdef DEBUG
446 objectState_ = ObjectState::End;
447 #endif
448 return true;
451 AutoSaveLocalStrictMode::AutoSaveLocalStrictMode(SharedContext* sc) : sc_(sc) {
452 savedStrictness_ = sc_->setLocalStrictMode(true);
455 AutoSaveLocalStrictMode::~AutoSaveLocalStrictMode() {
456 if (sc_) {
457 restore();
461 void AutoSaveLocalStrictMode::restore() {
462 MOZ_ALWAYS_TRUE(sc_->setLocalStrictMode(savedStrictness_));
463 sc_ = nullptr;
466 ClassEmitter::ClassEmitter(BytecodeEmitter* bce)
467 : PropertyEmitter(bce), strictMode_(bce->sc) {
468 isClass_ = true;
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)) {
479 return false;
482 #ifdef DEBUG
483 classState_ = ClassState::Scope;
484 #endif
486 return true;
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)) {
498 return false;
501 #ifdef DEBUG
502 classState_ = ClassState::BodyScope;
503 #endif
505 return true;
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));
518 // [stack]
520 name_ = name;
521 nameForAnonymousClass_ = nameForAnonymousClass;
522 hasNameOnStack_ = hasNameOnStack;
523 isDerived_ = false;
525 if (!bce_->emit1(JSOp::NewInit)) {
526 // [stack] HOMEOBJ
527 return false;
530 #ifdef DEBUG
531 classState_ = ClassState::Class;
532 #endif
533 return true;
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);
546 // [stack] HERITAGE
548 name_ = name;
549 nameForAnonymousClass_ = nameForAnonymousClass;
550 hasNameOnStack_ = hasNameOnStack;
551 isDerived_ = true;
553 InternalIfEmitter ifThenElse(bce_);
555 // Heritage must be null or a non-generator constructor
556 if (!bce_->emit1(JSOp::CheckClassHeritage)) {
557 // [stack] HERITAGE
558 return false;
561 // [IF] (heritage !== null)
562 if (!bce_->emit1(JSOp::Dup)) {
563 // [stack] HERITAGE HERITAGE
564 return false;
566 if (!bce_->emit1(JSOp::Null)) {
567 // [stack] HERITAGE HERITAGE NULL
568 return false;
570 if (!bce_->emit1(JSOp::StrictNe)) {
571 // [stack] HERITAGE NE
572 return false;
575 // [THEN] funProto = heritage, objProto = heritage.prototype
576 if (!ifThenElse.emitThenElse()) {
577 return false;
579 if (!bce_->emit1(JSOp::Dup)) {
580 // [stack] HERITAGE HERITAGE
581 return false;
583 if (!bce_->emitAtomOp(JSOp::GetProp,
584 TaggedParserAtomIndex::WellKnown::prototype())) {
585 // [stack] HERITAGE PROTO
586 return false;
589 // [ELSE] funProto = %FunctionPrototype%, objProto = null
590 if (!ifThenElse.emitElse()) {
591 return false;
593 if (!bce_->emit1(JSOp::Pop)) {
594 // [stack]
595 return false;
597 if (!bce_->emitBuiltinObject(BuiltinObjectKind::FunctionPrototype)) {
598 // [stack] PROTO
599 return false;
601 if (!bce_->emit1(JSOp::Null)) {
602 // [stack] PROTO NULL
603 return false;
606 // [ENDIF]
607 if (!ifThenElse.emitEnd()) {
608 return false;
611 if (!bce_->emit1(JSOp::ObjWithProto)) {
612 // [stack] HERITAGE HOMEOBJ
613 return false;
615 if (!bce_->emit1(JSOp::Swap)) {
616 // [stack] HOMEOBJ HERITAGE
617 return false;
620 #ifdef DEBUG
621 classState_ = ClassState::Class;
622 #endif
623 return true;
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
635 return false;
637 if (!bce_->emit1(JSOp::InitHomeObject)) {
638 // [stack] HOMEOBJ CTOR
639 return false;
643 if (!initProtoAndCtor()) {
644 // [stack] CTOR HOMEOBJ
645 return false;
648 #ifdef DEBUG
649 classState_ = ClassState::InitConstructor;
650 #endif
651 return true;
654 bool ClassEmitter::initProtoAndCtor() {
655 // [stack] NAME? HOMEOBJ CTOR
657 if (hasNameOnStack_) {
658 if (!bce_->emitDupAt(2)) {
659 // [stack] NAME HOMEOBJ CTOR NAME
660 return false;
662 if (!bce_->emit2(JSOp::SetFunName, uint8_t(FunctionPrefixKind::None))) {
663 // [stack] NAME HOMEOBJ CTOR
664 return false;
668 if (!bce_->emit1(JSOp::Swap)) {
669 // [stack] NAME? CTOR HOMEOBJ
670 return false;
672 if (!bce_->emit1(JSOp::Dup2)) {
673 // [stack] NAME? CTOR HOMEOBJ CTOR HOMEOBJ
674 return false;
676 if (!bce_->emitAtomOp(JSOp::InitLockedProp,
677 TaggedParserAtomIndex::WellKnown::prototype())) {
678 // [stack] NAME? CTOR HOMEOBJ CTOR
679 return false;
681 if (!bce_->emitAtomOp(JSOp::InitHiddenProp,
682 TaggedParserAtomIndex::WellKnown::constructor())) {
683 // [stack] NAME? CTOR HOMEOBJ
684 return false;
687 return true;
690 bool ClassEmitter::prepareForMemberInitializers(size_t numInitializers,
691 bool isStatic) {
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.
699 auto initializers =
700 isStatic ? TaggedParserAtomIndex::WellKnown::dot_staticInitializers_()
701 : TaggedParserAtomIndex::WellKnown::dot_initializers_();
702 initializersAssignment_.emplace(bce_, initializers,
703 NameOpEmitter::Kind::Initialize);
704 if (!initializersAssignment_->prepareForRhs()) {
705 return false;
708 if (!bce_->emitUint32Operand(JSOp::NewArray, numInitializers)) {
709 // [stack] ARRAY
710 return false;
713 initializerIndex_ = 0;
714 #ifdef DEBUG
715 if (isStatic) {
716 classState_ = ClassState::StaticMemberInitializers;
717 } else {
718 classState_ = ClassState::InstanceMemberInitializers;
720 numInitializers_ = numInitializers;
721 #endif
722 return true;
725 bool ClassEmitter::prepareForMemberInitializer() {
726 MOZ_ASSERT(classState_ == ClassState::InstanceMemberInitializers ||
727 classState_ == ClassState::StaticMemberInitializers);
728 MOZ_ASSERT(memberState_ == MemberState::Start);
730 #ifdef DEBUG
731 memberState_ = MemberState::Initializer;
732 #endif
733 return true;
736 bool ClassEmitter::emitMemberInitializerHomeObject(bool isStatic) {
737 MOZ_ASSERT(memberState_ == MemberState::Initializer);
738 // [stack] OBJ HERITAGE? ARRAY METHOD
739 // or:
740 // [stack] CTOR HOMEOBJ ARRAY METHOD
742 if (isStatic) {
743 if (!bce_->emitDupAt(3)) {
744 // [stack] CTOR HOMEOBJ ARRAY METHOD CTOR
745 return false;
747 } else {
748 if (!bce_->emitDupAt(isDerived_ ? 3 : 2)) {
749 // [stack] OBJ HERITAGE? ARRAY METHOD OBJ
750 return false;
753 if (!bce_->emit1(JSOp::InitHomeObject)) {
754 // [stack] OBJ HERITAGE? ARRAY METHOD
755 // or:
756 // [stack] CTOR HOMEOBJ ARRAY METHOD
757 return false;
760 #ifdef DEBUG
761 memberState_ = MemberState::InitializerWithHomeObject;
762 #endif
763 return true;
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
774 return false;
777 initializerIndex_++;
778 #ifdef DEBUG
779 memberState_ = MemberState::Start;
780 #endif
781 return true;
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
794 return false;
796 initializersAssignment_.reset();
798 if (!bce_->emit1(JSOp::Pop)) {
799 // [stack] HOMEOBJ HERITAGE?
800 return false;
803 #ifdef DEBUG
804 if (classState_ == ClassState::InstanceMemberInitializers) {
805 classState_ = ClassState::InstanceMemberInitializersEnd;
806 } else {
807 classState_ = ClassState::StaticMemberInitializersEnd;
809 #endif
810 return true;
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)) {
822 // [stack] CTOR
823 return false;
826 if (name_) {
827 MOZ_ASSERT(innerScope_.isSome());
829 if (!bce_->emitLexicalInitialization(name_)) {
830 // [stack] CTOR
831 return false;
835 // [stack] CTOR
837 #ifdef DEBUG
838 classState_ = ClassState::BoundName;
839 #endif
840 return true;
843 #ifdef ENABLE_DECORATORS
844 bool ClassEmitter::prepareForDecorators() { return leaveBodyAndInnerScope(); }
845 #endif
847 bool ClassEmitter::leaveBodyAndInnerScope() {
848 if (bodyScope_.isSome()) {
849 MOZ_ASSERT(bodyTdzCache_.isSome());
851 if (!bodyScope_->leave(bce_)) {
852 return false;
854 bodyScope_.reset();
855 bodyTdzCache_.reset();
858 if (innerScope_.isSome()) {
859 MOZ_ASSERT(tdzCache_.isSome());
861 if (!innerScope_->leave(bce_)) {
862 return false;
864 innerScope_.reset();
865 tdzCache_.reset();
866 } else {
867 MOZ_ASSERT(tdzCache_.isNothing());
870 return true;
873 bool ClassEmitter::emitEnd(Kind kind) {
874 MOZ_ASSERT(classState_ == ClassState::BoundName);
875 // [stack] CTOR
877 #ifndef ENABLE_DECORATORS
878 if (!leaveBodyAndInnerScope()) {
879 return false;
881 #endif
883 if (kind == Kind::Declaration) {
884 MOZ_ASSERT(name_);
886 if (!bce_->emitLexicalInitialization(name_)) {
887 // [stack] CTOR
888 return false;
890 // Only class statements make outer bindings, and they do not leave
891 // themselves on the stack.
892 if (!bce_->emit1(JSOp::Pop)) {
893 // [stack]
894 return false;
898 // [stack] # class declaration
899 // [stack]
900 // [stack] # class expression
901 // [stack] CTOR
903 strictMode_.restore();
905 #ifdef DEBUG
906 classState_ = ClassState::End;
907 #endif
908 return true;