summaryrefslogtreecommitdiffstats
path: root/js/src/frontend/ObjectEmitter.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /js/src/frontend/ObjectEmitter.h
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/frontend/ObjectEmitter.h')
-rw-r--r--js/src/frontend/ObjectEmitter.h864
1 files changed, 864 insertions, 0 deletions
diff --git a/js/src/frontend/ObjectEmitter.h b/js/src/frontend/ObjectEmitter.h
new file mode 100644
index 0000000000..833eb4a1a4
--- /dev/null
+++ b/js/src/frontend/ObjectEmitter.h
@@ -0,0 +1,864 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef frontend_ObjectEmitter_h
+#define frontend_ObjectEmitter_h
+
+#include "mozilla/Attributes.h" // MOZ_STACK_CLASS, MOZ_ALWAYS_INLINE, MOZ_RAII
+#include "mozilla/Maybe.h" // Maybe
+
+#include <stddef.h> // size_t
+#include <stdint.h> // uint32_t
+
+#include "frontend/EmitterScope.h" // EmitterScope
+#include "frontend/NameOpEmitter.h" // NameOpEmitter
+#include "frontend/ParseNode.h" // AccessorType
+#include "frontend/ParserAtom.h" // TaggedParserAtomIndex
+#include "frontend/TDZCheckCache.h" // TDZCheckCache
+#include "vm/Opcodes.h" // JSOp
+#include "vm/Scope.h" // LexicalScope
+
+namespace js {
+
+namespace frontend {
+
+struct BytecodeEmitter;
+class SharedContext;
+
+// Class for emitting bytecode for object and class properties.
+// See ObjectEmitter and ClassEmitter for usage.
+class MOZ_STACK_CLASS PropertyEmitter {
+ public:
+ enum class Kind {
+ // Prototype property.
+ Prototype,
+
+ // Class static property.
+ Static
+ };
+
+ protected:
+ BytecodeEmitter* bce_;
+
+ // True if the object is class.
+ // Set by ClassEmitter.
+ bool isClass_ = false;
+
+ // True if the property is class static method.
+ bool isStatic_ = false;
+
+ // True if the property has computed or index key.
+ bool isIndexOrComputed_ = false;
+
+#ifdef DEBUG
+ // The state of this emitter.
+ //
+ // +-------+
+ // | Start |-+
+ // +-------+ |
+ // |
+ // +---------+
+ // |
+ // | +------------------------------------------------------------+
+ // | | |
+ // | | [normal property/method/accessor] |
+ // | v prepareForPropValue +-----------+ +------+ |
+ // +->+----------------------->| PropValue |-+ +->| Init |-+
+ // | +-----------+ | | +------+
+ // | | |
+ // | +-----------------------------------+ +-----------+
+ // | | |
+ // | +-+---------------------------------------+ |
+ // | | | |
+ // | | [method with super] | |
+ // | | emitInitHomeObject +-------------+ v |
+ // | +--------------------->| InitHomeObj |->+ |
+ // | +-------------+ | |
+ // | | |
+ // | +-------------------------------------- + |
+ // | | |
+ // | | emitInit |
+ // | +------------------------------------------------------>+
+ // | ^
+ // | [optimized private non-static method] |
+ // | prepareForPrivateMethod +--------------------+ |
+ // +---------------------------->| PrivateMethodValue |-+ |
+ // | +--------------------+ | |
+ // | | |
+ // | +-------------------------------------------------+ |
+ // | | |
+ // | +-+---------------------------------------------+ |
+ // | | | |
+ // | | [method with super | |
+ // | | emitInitHomeObject +-----------------+ v |
+ // | +--------------------->| InitHomeObjFor- |----+ |
+ // | | PrivateMethod | | |
+ // | +-----------------+ | |
+ // | | |
+ // | +---------------------------------------------+ |
+ // | | |
+ // | | skipInit |
+ // | +------------------------------------------------------>+
+ // | ^
+ // | [private static method] |
+ // | prepareForPrivateStaticMethod +---------------------+ |
+ // +--------------------------------->| PrivateStaticMethod |-+ |
+ // | +---------------------+ | |
+ // | | |
+ // | +-------------------------------------------------------+ |
+ // | | |
+ // | +-+-------------------------------------------------+ |
+ // | | | |
+ // | | [method with super | |
+ // | | emitInitHomeObject +---------------------+ v |
+ // | +--------------------->| InitHomeObjFor- |----+ |
+ // | | PrivateStaticMethod | | |
+ // | +---------------------+ | |
+ // | | |
+ // | +-----------------------------------------------+ |
+ // | | |
+ // | | emitPrivateStaticMethod |
+ // | +---------------------------------------------------->+
+ // | ^
+ // | [index property/method/accessor] |
+ // | prepareForIndexPropKey +----------+ |
+ // +-------------------------->| IndexKey |-+ |
+ // | +----------+ | |
+ // | | |
+ // | +-------------------------------------+ |
+ // | | |
+ // | | prepareForIndexPropValue +------------+ |
+ // | +------------------------->| IndexValue |-+ |
+ // | +------------+ | |
+ // | | |
+ // | +---------------------------------------+ |
+ // | | |
+ // | +-+--------------------------------------------------+ |
+ // | | | |
+ // | | [method with super] | |
+ // | | emitInitHomeObject +---------------------+ v |
+ // | +--------------------->| InitHomeObjForIndex |---->+ |
+ // | +---------------------+ | |
+ // | | |
+ // | +--------------------------------------------------+ |
+ // | | |
+ // | | emitInitIndexOrComputed |
+ // | +---------------------------------------------------->+
+ // | ^
+ // | [computed property/method/accessor] |
+ // | prepareForComputedPropKey +-------------+ |
+ // +----------------------------->| ComputedKey |-+ |
+ // | +-------------+ | |
+ // | | |
+ // | +-------------------------------------------+ |
+ // | | |
+ // | | prepareForComputedPropValue +---------------+ |
+ // | +---------------------------->| ComputedValue |-+ |
+ // | +---------------+ | |
+ // | | |
+ // | +---------------------------------------------+ |
+ // | | |
+ // | +-+--------------------------------------------------+ |
+ // | | | |
+ // | | [method with super] | |
+ // | | emitInitHomeObject +------------------------+ v |
+ // | +--------------------->| InitHomeObjForComputed |->+ |
+ // | +------------------------+ | |
+ // | | |
+ // | +--------------------------------------------------+ |
+ // | | |
+ // | | emitInitIndexOrComputed |
+ // | +---------------------------------------------------->+
+ // | ^
+ // | |
+ // | [__proto__] |
+ // | prepareForProtoValue +------------+ emitMutateProto |
+ // +------------------------>| ProtoValue |-------------------->+
+ // | +------------+ ^
+ // | |
+ // | [...prop] |
+ // | prepareForSpreadOperand +---------------+ emitSpread |
+ // +-------------------------->| SpreadOperand |----------------+
+ // +---------------+
+ enum class PropertyState {
+ // The initial state.
+ Start,
+
+ // After calling prepareForPropValue.
+ PropValue,
+
+ // After calling emitInitHomeObject, from PropValue.
+ InitHomeObj,
+
+ // After calling prepareForPrivateMethod.
+ PrivateMethodValue,
+
+ // After calling emitInitHomeObject, from PrivateMethod.
+ InitHomeObjForPrivateMethod,
+
+ // After calling prepareForPrivateStaticMethod.
+ PrivateStaticMethod,
+
+ // After calling emitInitHomeObject, from PrivateStaticMethod.
+ InitHomeObjForPrivateStaticMethod,
+
+ // After calling prepareForIndexPropKey.
+ IndexKey,
+
+ // prepareForIndexPropValue.
+ IndexValue,
+
+ // After calling emitInitHomeObject, from IndexValue.
+ InitHomeObjForIndex,
+
+ // After calling prepareForComputedPropKey.
+ ComputedKey,
+
+ // prepareForComputedPropValue.
+ ComputedValue,
+
+ // After calling emitInitHomeObject, from ComputedValue.
+ InitHomeObjForComputed,
+
+ // After calling prepareForProtoValue.
+ ProtoValue,
+
+ // After calling prepareForSpreadOperand.
+ SpreadOperand,
+
+ // After calling one of emitInit, emitInitIndexOrComputed, emitMutateProto,
+ // or emitSpread.
+ Init,
+ };
+ PropertyState propertyState_ = PropertyState::Start;
+#endif
+
+ public:
+ explicit PropertyEmitter(BytecodeEmitter* bce);
+
+ // Parameters are the offset in the source code for each character below:
+ //
+ // { __proto__: protoValue }
+ // ^
+ // |
+ // keyPos
+ [[nodiscard]] bool prepareForProtoValue(uint32_t keyPos);
+ [[nodiscard]] bool emitMutateProto();
+
+ // { ...obj }
+ // ^
+ // |
+ // spreadPos
+ [[nodiscard]] bool prepareForSpreadOperand(uint32_t spreadPos);
+ [[nodiscard]] bool emitSpread();
+
+ // { key: value }
+ // ^
+ // |
+ // keyPos
+ [[nodiscard]] bool prepareForPropValue(uint32_t keyPos, Kind kind);
+
+ [[nodiscard]] bool prepareForPrivateMethod();
+
+ [[nodiscard]] bool prepareForPrivateStaticMethod(uint32_t keyPos);
+
+ // { 1: value }
+ // ^
+ // |
+ // keyPos
+ [[nodiscard]] bool prepareForIndexPropKey(uint32_t keyPos, Kind kind);
+ [[nodiscard]] bool prepareForIndexPropValue();
+
+ // { [ key ]: value }
+ // ^
+ // |
+ // keyPos
+ [[nodiscard]] bool prepareForComputedPropKey(uint32_t keyPos, Kind kind);
+ [[nodiscard]] bool prepareForComputedPropValue();
+
+ [[nodiscard]] bool emitInitHomeObject();
+
+ // @param key
+ // Property key
+ [[nodiscard]] bool emitInit(AccessorType accessorType,
+ TaggedParserAtomIndex key);
+
+ [[nodiscard]] bool emitInitIndexOrComputed(AccessorType accessorType);
+
+ [[nodiscard]] bool emitPrivateStaticMethod(AccessorType accessorType);
+
+ [[nodiscard]] bool skipInit();
+
+ private:
+ [[nodiscard]] MOZ_ALWAYS_INLINE bool prepareForProp(uint32_t keyPos,
+ bool isStatic,
+ bool isComputed);
+
+ // @param op
+ // Opcode for initializing property
+ // @param key
+ // Atom of the property if the property key is not computed
+ [[nodiscard]] bool emitInit(JSOp op, TaggedParserAtomIndex key);
+ [[nodiscard]] bool emitInitIndexOrComputed(JSOp op);
+
+ [[nodiscard]] bool emitPopClassConstructor();
+};
+
+// Class for emitting bytecode for object literal.
+//
+// Usage: (check for the return value is omitted for simplicity)
+//
+// `{}`
+// ObjectEmitter oe(this);
+// oe.emitObject(0);
+// oe.emitEnd();
+//
+// `{ prop: 10 }`
+// ObjectEmitter oe(this);
+// oe.emitObject(1);
+//
+// oe.prepareForPropValue(offset_of_prop);
+// emit(10);
+// oe.emitInitProp(atom_of_prop);
+//
+// oe.emitEnd();
+//
+// `{ prop: function() {} }`, when property value is anonymous function
+// ObjectEmitter oe(this);
+// oe.emitObject(1);
+//
+// oe.prepareForPropValue(offset_of_prop);
+// emit(function);
+// oe.emitInitProp(atom_of_prop);
+//
+// oe.emitEnd();
+//
+// `{ get prop() { ... }, set prop(v) { ... } }`
+// ObjectEmitter oe(this);
+// oe.emitObject(2);
+//
+// oe.prepareForPropValue(offset_of_prop);
+// emit(function_for_getter);
+// oe.emitInitGetter(atom_of_prop);
+//
+// oe.prepareForPropValue(offset_of_prop);
+// emit(function_for_setter);
+// oe.emitInitSetter(atom_of_prop);
+//
+// oe.emitEnd();
+//
+// `{ 1: 10, get 2() { ... }, set 3(v) { ... } }`
+// ObjectEmitter oe(this);
+// oe.emitObject(3);
+//
+// oe.prepareForIndexPropKey(offset_of_prop);
+// emit(1);
+// oe.prepareForIndexPropValue();
+// emit(10);
+// oe.emitInitIndexedProp();
+//
+// oe.prepareForIndexPropKey(offset_of_opening_bracket);
+// emit(2);
+// oe.prepareForIndexPropValue();
+// emit(function_for_getter);
+// oe.emitInitIndexGetter();
+//
+// oe.prepareForIndexPropKey(offset_of_opening_bracket);
+// emit(3);
+// oe.prepareForIndexPropValue();
+// emit(function_for_setter);
+// oe.emitInitIndexSetter();
+//
+// oe.emitEnd();
+//
+// `{ [prop1]: 10, get [prop2]() { ... }, set [prop3](v) { ... } }`
+// ObjectEmitter oe(this);
+// oe.emitObject(3);
+//
+// oe.prepareForComputedPropKey(offset_of_opening_bracket);
+// emit(prop1);
+// oe.prepareForComputedPropValue();
+// emit(10);
+// oe.emitInitComputedProp();
+//
+// oe.prepareForComputedPropKey(offset_of_opening_bracket);
+// emit(prop2);
+// oe.prepareForComputedPropValue();
+// emit(function_for_getter);
+// oe.emitInitComputedGetter();
+//
+// oe.prepareForComputedPropKey(offset_of_opening_bracket);
+// emit(prop3);
+// oe.prepareForComputedPropValue();
+// emit(function_for_setter);
+// oe.emitInitComputedSetter();
+//
+// oe.emitEnd();
+//
+// `{ __proto__: obj }`
+// ObjectEmitter oe(this);
+// oe.emitObject(1);
+// oe.prepareForProtoValue(offset_of___proto__);
+// emit(obj);
+// oe.emitMutateProto();
+// oe.emitEnd();
+//
+// `{ ...obj }`
+// ObjectEmitter oe(this);
+// oe.emitObject(1);
+// oe.prepareForSpreadOperand(offset_of_triple_dots);
+// emit(obj);
+// oe.emitSpread();
+// oe.emitEnd();
+//
+class MOZ_STACK_CLASS ObjectEmitter : public PropertyEmitter {
+ private:
+#ifdef DEBUG
+ // The state of this emitter.
+ //
+ // +-------+ emitObject +--------+
+ // | Start |----------->| Object |-+
+ // +-------+ +--------+ |
+ // |
+ // +-----------------------------+
+ // |
+ // | (do PropertyEmitter operation) emitEnd +-----+
+ // +-------------------------------+--------->| End |
+ // +-----+
+ enum class ObjectState {
+ // The initial state.
+ Start,
+
+ // After calling emitObject.
+ Object,
+
+ // After calling emitEnd.
+ End,
+ };
+ ObjectState objectState_ = ObjectState::Start;
+#endif
+
+ public:
+ explicit ObjectEmitter(BytecodeEmitter* bce);
+
+ [[nodiscard]] bool emitObject(size_t propertyCount);
+ // Same as `emitObject()`, but start with an empty template object already on
+ // the stack.
+ [[nodiscard]] bool emitObjectWithTemplateOnStack();
+ [[nodiscard]] bool emitEnd();
+};
+
+// Save and restore the strictness.
+// Used by class declaration/expression to temporarily enable strict mode.
+class MOZ_RAII AutoSaveLocalStrictMode {
+ SharedContext* sc_;
+ bool savedStrictness_;
+
+ public:
+ explicit AutoSaveLocalStrictMode(SharedContext* sc);
+ ~AutoSaveLocalStrictMode();
+
+ // Force restore the strictness now.
+ void restore();
+};
+
+// Class for emitting bytecode for JS class.
+//
+// Usage: (check for the return value is omitted for simplicity)
+//
+// `class { constructor() { ... } }`
+// ClassEmitter ce(this);
+// ce.emitScope(scopeBindings);
+// ce.emitClass(nullptr, nullptr, false);
+//
+// emit(function_for_constructor);
+// ce.emitInitConstructor(/* needsHomeObject = */ false);
+//
+// ce.emitEnd(ClassEmitter::Kind::Expression);
+//
+// `class X { constructor() { ... } }`
+// ClassEmitter ce(this);
+// ce.emitScope(scopeBindings);
+// ce.emitClass(atom_of_X, nullptr, false);
+//
+// emit(function_for_constructor);
+// ce.emitInitConstructor(/* needsHomeObject = */ false);
+//
+// ce.emitEnd(ClassEmitter::Kind::Expression);
+//
+// `class X extends Y { constructor() { ... } }`
+// ClassEmitter ce(this);
+// ce.emitScope(scopeBindings);
+//
+// emit(Y);
+// ce.emitDerivedClass(atom_of_X, nullptr, false);
+//
+// emit(function_for_constructor);
+// ce.emitInitConstructor(/* needsHomeObject = */ false);
+//
+// ce.emitEnd(ClassEmitter::Kind::Expression);
+//
+// `class X extends Y { constructor() { ... super.f(); ... } }`
+// ClassEmitter ce(this);
+// ce.emitScope(scopeBindings);
+//
+// emit(Y);
+// ce.emitDerivedClass(atom_of_X, nullptr, false);
+//
+// emit(function_for_constructor);
+// // pass true if constructor contains super.prop access
+// ce.emitInitConstructor(/* needsHomeObject = */ true);
+//
+// ce.emitEnd(ClassEmitter::Kind::Expression);
+//
+// `class X extends Y { field0 = expr0; ... }`
+// ClassEmitter ce(this);
+// ce.emitScope(scopeBindings);
+// emit(Y);
+// ce.emitDerivedClass(atom_of_X, nullptr, false);
+//
+// ce.prepareForMemberInitializers(fields.length());
+// for (auto field : fields) {
+// emit(field.initializer_method());
+// ce.emitStoreMemberInitializer();
+// }
+// ce.emitMemberInitializersEnd();
+//
+// emit(function_for_constructor);
+// ce.emitInitConstructor(/* needsHomeObject = */ false);
+// ce.emitEnd(ClassEmitter::Kind::Expression);
+//
+// `class X { field0 = super.method(); ... }`
+// // after emitClass/emitDerivedClass
+// ce.prepareForMemberInitializers(1);
+// for (auto field : fields) {
+// emit(field.initializer_method());
+// if (field.initializer_contains_super_or_eval()) {
+// ce.emitMemberInitializerHomeObject();
+// }
+// ce.emitStoreMemberInitializer();
+// }
+// ce.emitMemberInitializersEnd();
+//
+// `m() {}` in class
+// // after emitInitConstructor
+// ce.prepareForPropValue(offset_of_m);
+// emit(function_for_m);
+// ce.emitInitProp(atom_of_m);
+//
+// `m() { super.f(); }` in class
+// // after emitInitConstructor
+// ce.prepareForPropValue(offset_of_m);
+// emit(function_for_m);
+// ce.emitInitHomeObject();
+// ce.emitInitProp(atom_of_m);
+//
+// `async m() { super.f(); }` in class
+// // after emitInitConstructor
+// ce.prepareForPropValue(offset_of_m);
+// emit(function_for_m);
+// ce.emitInitHomeObject();
+// ce.emitInitProp(atom_of_m);
+//
+// `get p() { super.f(); }` in class
+// // after emitInitConstructor
+// ce.prepareForPropValue(offset_of_p);
+// emit(function_for_p);
+// ce.emitInitHomeObject();
+// ce.emitInitGetter(atom_of_m);
+//
+// `static m() {}` in class
+// // after emitInitConstructor
+// ce.prepareForPropValue(offset_of_m,
+// PropertyEmitter::Kind::Static);
+// emit(function_for_m);
+// ce.emitInitProp(atom_of_m);
+//
+// `static get [p]() { super.f(); }` in class
+// // after emitInitConstructor
+// ce.prepareForComputedPropValue(offset_of_m,
+// PropertyEmitter::Kind::Static);
+// emit(p);
+// ce.prepareForComputedPropValue();
+// emit(function_for_m);
+// ce.emitInitHomeObject();
+// ce.emitInitComputedGetter();
+//
+class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter {
+ public:
+ enum class Kind {
+ // Class expression.
+ Expression,
+
+ // Class declaration.
+ Declaration,
+ };
+
+ private:
+ // Pseudocode for class declarations:
+ //
+ // class extends BaseExpression {
+ // constructor() { ... }
+ // ...
+ // }
+ //
+ //
+ // if defined <BaseExpression> {
+ // let heritage = BaseExpression;
+ //
+ // if (heritage !== null) {
+ // funProto = heritage;
+ // objProto = heritage.prototype;
+ // } else {
+ // funProto = %FunctionPrototype%;
+ // objProto = null;
+ // }
+ // } else {
+ // objProto = %ObjectPrototype%;
+ // }
+ //
+ // let homeObject = ObjectCreate(objProto);
+ //
+ // if defined <constructor> {
+ // if defined <BaseExpression> {
+ // cons = DefineMethod(<constructor>, proto=homeObject,
+ // funProto=funProto);
+ // } else {
+ // cons = DefineMethod(<constructor>, proto=homeObject);
+ // }
+ // } else {
+ // if defined <BaseExpression> {
+ // cons = DefaultDerivedConstructor(proto=homeObject,
+ // funProto=funProto);
+ // } else {
+ // cons = DefaultConstructor(proto=homeObject);
+ // }
+ // }
+ //
+ // cons.prototype = homeObject;
+ // homeObject.constructor = cons;
+ //
+ // EmitPropertyList(...)
+
+ bool isDerived_ = false;
+
+ mozilla::Maybe<TDZCheckCache> tdzCache_;
+ mozilla::Maybe<EmitterScope> innerScope_;
+ mozilla::Maybe<TDZCheckCache> bodyTdzCache_;
+ mozilla::Maybe<EmitterScope> bodyScope_;
+ AutoSaveLocalStrictMode strictMode_;
+
+#ifdef DEBUG
+ // The state of this emitter.
+ //
+ // clang-format off
+ // +-------+
+ // | Start |-+------------------------>+--+------------------------------>+--+
+ // +-------+ | ^ | ^ |
+ // | [has scope] | | [has body scope] | |
+ // | emitScope +-------+ | | emitBodyScope +-----------+ | |
+ // +-------------->| Scope |-+ +---------------->| BodyScope |-+ |
+ // +-------+ +-----------+ |
+ // |
+ // +-----------------------------------------------------------------------+
+ // |
+ // | emitClass +-------+
+ // +-+----------------->+->| Class |-+
+ // | ^ +-------+ |
+ // | emitDerivedClass | |
+ // +------------------+ |
+ // |
+ // +-------------------------------+
+ // |
+ // |
+ // | prepareForMemberInitializers(isStatic = false)
+ // +---------------+
+ // | |
+ // | +--------v-------------------+
+ // | | InstanceMemberInitializers |
+ // | +----------------------------+
+ // | |
+ // | emitMemberInitializersEnd
+ // | |
+ // | +--------v----------------------+
+ // | | InstanceMemberInitializersEnd |
+ // | +-------------------------------+
+ // | |
+ // +<--------------+
+ // |
+ // | emitInitConstructor +-----------------+
+ // +-------------------------------->| InitConstructor |-+
+ // +-----------------+ |
+ // |
+ // |
+ // |
+ // +-----------------------------------------------------+
+ // |
+ // | prepareForMemberInitializers(isStatic = true)
+ // +---------------+
+ // | |
+ // | +--------v-----------------+
+ // | | StaticMemberInitializers |
+ // | +--------------------------+
+ // | |
+ // | | emitMemberInitializersEnd
+ // | |
+ // | +--------v--------------------+
+ // | | StaticMemberInitializersEnd |
+ // | +-----------------------------+
+ // | |
+ // +<--------------+
+ // |
+ // | (do PropertyEmitter operation)
+ // +--------------------------------+
+ // |
+ // +-------------+ emitBinding |
+ // | BoundName |<-----------------+
+ // +--+----------+
+ // |
+ // | emitEnd
+ // |
+ // +--v----+
+ // | End |
+ // +-------+
+ //
+ // clang-format on
+ enum class ClassState {
+ // The initial state.
+ Start,
+
+ // After calling emitScope.
+ Scope,
+
+ // After calling emitBodyScope.
+ BodyScope,
+
+ // After calling emitClass or emitDerivedClass.
+ Class,
+
+ // After calling emitInitConstructor.
+ InitConstructor,
+
+ // After calling prepareForMemberInitializers(isStatic = false).
+ InstanceMemberInitializers,
+
+ // After calling emitMemberInitializersEnd.
+ InstanceMemberInitializersEnd,
+
+ // After calling prepareForMemberInitializers(isStatic = true).
+ StaticMemberInitializers,
+
+ // After calling emitMemberInitializersEnd.
+ StaticMemberInitializersEnd,
+
+ // After calling emitBinding.
+ BoundName,
+
+ // After calling emitEnd.
+ End,
+ };
+ ClassState classState_ = ClassState::Start;
+
+ // The state of the members emitter.
+ //
+ // clang-format off
+ //
+ // +-------+
+ // | Start +<-----------------------------+
+ // +-------+ |
+ // | |
+ // | prepareForMemberInitializer | emitStoreMemberInitializer
+ // v |
+ // +-------------+ |
+ // | Initializer +------------------------->+
+ // +-------------+ |
+ // | |
+ // | emitMemberInitializerHomeObject |
+ // v |
+ // +---------------------------+ |
+ // | InitializerWithHomeObject +------------+
+ // +---------------------------+
+ //
+ // clang-format on
+ enum class MemberState {
+ // After calling prepareForMemberInitializers
+ // and 0 or more calls to emitStoreMemberInitializer.
+ Start,
+
+ // After calling prepareForMemberInitializer
+ Initializer,
+
+ // After calling emitMemberInitializerHomeObject
+ InitializerWithHomeObject,
+ };
+ MemberState memberState_ = MemberState::Start;
+
+ size_t numInitializers_ = 0;
+#endif
+
+ TaggedParserAtomIndex name_;
+ TaggedParserAtomIndex nameForAnonymousClass_;
+ bool hasNameOnStack_ = false;
+ mozilla::Maybe<NameOpEmitter> initializersAssignment_;
+ size_t initializerIndex_ = 0;
+
+ public:
+ explicit ClassEmitter(BytecodeEmitter* bce);
+
+ bool emitScope(LexicalScope::ParserData* scopeBindings);
+ bool emitBodyScope(ClassBodyScope::ParserData* scopeBindings);
+
+ // @param name
+ // Name of the class (nullptr if this is anonymous class)
+ // @param nameForAnonymousClass
+ // Statically inferred name of the class (only for anonymous classes)
+ // @param hasNameOnStack
+ // If true the name is on the stack (only for anonymous classes)
+ [[nodiscard]] bool emitClass(TaggedParserAtomIndex name,
+ TaggedParserAtomIndex nameForAnonymousClass,
+ bool hasNameOnStack);
+ [[nodiscard]] bool emitDerivedClass(
+ TaggedParserAtomIndex name, TaggedParserAtomIndex nameForAnonymousClass,
+ bool hasNameOnStack);
+
+ // @param needsHomeObject
+ // True if the constructor contains `super.foo`
+ [[nodiscard]] bool emitInitConstructor(bool needsHomeObject);
+
+ [[nodiscard]] bool prepareForMemberInitializers(size_t numInitializers,
+ bool isStatic);
+ [[nodiscard]] bool prepareForMemberInitializer();
+ [[nodiscard]] bool emitMemberInitializerHomeObject(bool isStatic);
+ [[nodiscard]] bool emitStoreMemberInitializer();
+ [[nodiscard]] bool emitMemberInitializersEnd();
+
+#ifdef ENABLE_DECORATORS
+ // TODO!: When we've enabled decorators, update the states and transition
+ // diagram to reflect this new state.
+ [[nodiscard]] bool prepareForExtraInitializers(
+ TaggedParserAtomIndex initializers);
+#endif
+
+ [[nodiscard]] bool emitBinding();
+
+#ifdef ENABLE_DECORATORS
+ // TODO!: When we've enabled decorators, update the states and transition
+ // diagram to reflect this new state.
+ [[nodiscard]] bool prepareForDecorators();
+#endif
+
+ [[nodiscard]] bool emitEnd(Kind kind);
+
+ private:
+ [[nodiscard]] bool initProtoAndCtor();
+
+ [[nodiscard]] bool leaveBodyAndInnerScope();
+};
+
+} /* namespace frontend */
+} /* namespace js */
+
+#endif /* frontend_ObjectEmitter_h */