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 #ifndef frontend_ObjectEmitter_h
8 #define frontend_ObjectEmitter_h
10 #include "mozilla/Attributes.h" // MOZ_STACK_CLASS, MOZ_ALWAYS_INLINE, MOZ_RAII
11 #include "mozilla/Maybe.h" // Maybe
13 #include <stddef.h> // size_t
14 #include <stdint.h> // uint32_t
16 #include "frontend/EmitterScope.h" // EmitterScope
17 #include "frontend/NameOpEmitter.h" // NameOpEmitter
18 #include "frontend/ParseNode.h" // AccessorType
19 #include "frontend/ParserAtom.h" // TaggedParserAtomIndex
20 #include "frontend/TDZCheckCache.h" // TDZCheckCache
21 #include "vm/Opcodes.h" // JSOp
22 #include "vm/Scope.h" // LexicalScope
28 struct BytecodeEmitter
;
31 // Class for emitting bytecode for object and class properties.
32 // See ObjectEmitter and ClassEmitter for usage.
33 class MOZ_STACK_CLASS PropertyEmitter
{
36 // Prototype property.
39 // Class static property.
44 BytecodeEmitter
* bce_
;
46 // True if the object is class.
47 // Set by ClassEmitter.
48 bool isClass_
= false;
50 // True if the property is class static method.
51 bool isStatic_
= false;
53 // True if the property has computed or index key.
54 bool isIndexOrComputed_
= false;
57 // The state of this emitter.
65 // | +------------------------------------------------------------+
67 // | | [normal property/method/accessor] |
68 // | v prepareForPropValue +-----------+ +------+ |
69 // +->+----------------------->| PropValue |-+ +->| Init |-+
70 // | +-----------+ | | +------+
72 // | +-----------------------------------+ +-----------+
74 // | +-+---------------------------------------+ |
76 // | | [method with super] | |
77 // | | emitInitHomeObject +-------------+ v |
78 // | +--------------------->| InitHomeObj |->+ |
79 // | +-------------+ | |
81 // | +-------------------------------------- + |
84 // | +------------------------------------------------------>+
86 // | [optimized private non-static method] |
87 // | prepareForPrivateMethod +--------------------+ |
88 // +---------------------------->| PrivateMethodValue |-+ |
89 // | +--------------------+ | |
91 // | +-------------------------------------------------+ |
93 // | +-+---------------------------------------------+ |
95 // | | [method with super | |
96 // | | emitInitHomeObject +-----------------+ v |
97 // | +--------------------->| InitHomeObjFor- |----+ |
98 // | | PrivateMethod | | |
99 // | +-----------------+ | |
101 // | +---------------------------------------------+ |
104 // | +------------------------------------------------------>+
106 // | [private static method] |
107 // | prepareForPrivateStaticMethod +---------------------+ |
108 // +--------------------------------->| PrivateStaticMethod |-+ |
109 // | +---------------------+ | |
111 // | +-------------------------------------------------------+ |
113 // | +-+-------------------------------------------------+ |
115 // | | [method with super | |
116 // | | emitInitHomeObject +---------------------+ v |
117 // | +--------------------->| InitHomeObjFor- |----+ |
118 // | | PrivateStaticMethod | | |
119 // | +---------------------+ | |
121 // | +-----------------------------------------------+ |
123 // | | emitPrivateStaticMethod |
124 // | +---------------------------------------------------->+
126 // | [index property/method/accessor] |
127 // | prepareForIndexPropKey +----------+ |
128 // +-------------------------->| IndexKey |-+ |
129 // | +----------+ | |
131 // | +-------------------------------------+ |
133 // | | prepareForIndexPropValue +------------+ |
134 // | +------------------------->| IndexValue |-+ |
135 // | +------------+ | |
137 // | +---------------------------------------+ |
139 // | +-+--------------------------------------------------+ |
141 // | | [method with super] | |
142 // | | emitInitHomeObject +---------------------+ v |
143 // | +--------------------->| InitHomeObjForIndex |---->+ |
144 // | +---------------------+ | |
146 // | +--------------------------------------------------+ |
148 // | | emitInitIndexOrComputed |
149 // | +---------------------------------------------------->+
151 // | [computed property/method/accessor] |
152 // | prepareForComputedPropKey +-------------+ |
153 // +----------------------------->| ComputedKey |-+ |
154 // | +-------------+ | |
156 // | +-------------------------------------------+ |
158 // | | prepareForComputedPropValue +---------------+ |
159 // | +---------------------------->| ComputedValue |-+ |
160 // | +---------------+ | |
162 // | +---------------------------------------------+ |
164 // | +-+--------------------------------------------------+ |
166 // | | [method with super] | |
167 // | | emitInitHomeObject +------------------------+ v |
168 // | +--------------------->| InitHomeObjForComputed |->+ |
169 // | +------------------------+ | |
171 // | +--------------------------------------------------+ |
173 // | | emitInitIndexOrComputed |
174 // | +---------------------------------------------------->+
178 // | prepareForProtoValue +------------+ emitMutateProto |
179 // +------------------------>| ProtoValue |-------------------->+
180 // | +------------+ ^
183 // | prepareForSpreadOperand +---------------+ emitSpread |
184 // +-------------------------->| SpreadOperand |----------------+
186 enum class PropertyState
{
187 // The initial state.
190 // After calling prepareForPropValue.
193 // After calling emitInitHomeObject, from PropValue.
196 // After calling prepareForPrivateMethod.
199 // After calling emitInitHomeObject, from PrivateMethod.
200 InitHomeObjForPrivateMethod
,
202 // After calling prepareForPrivateStaticMethod.
205 // After calling emitInitHomeObject, from PrivateStaticMethod.
206 InitHomeObjForPrivateStaticMethod
,
208 // After calling prepareForIndexPropKey.
211 // prepareForIndexPropValue.
214 // After calling emitInitHomeObject, from IndexValue.
217 // After calling prepareForComputedPropKey.
220 // prepareForComputedPropValue.
223 // After calling emitInitHomeObject, from ComputedValue.
224 InitHomeObjForComputed
,
226 // After calling prepareForProtoValue.
229 // After calling prepareForSpreadOperand.
232 // After calling one of emitInit, emitInitIndexOrComputed, emitMutateProto,
236 PropertyState propertyState_
= PropertyState::Start
;
240 explicit PropertyEmitter(BytecodeEmitter
* bce
);
242 // Parameters are the offset in the source code for each character below:
244 // { __proto__: protoValue }
248 [[nodiscard
]] bool prepareForProtoValue(uint32_t keyPos
);
249 [[nodiscard
]] bool emitMutateProto();
255 [[nodiscard
]] bool prepareForSpreadOperand(uint32_t spreadPos
);
256 [[nodiscard
]] bool emitSpread();
262 [[nodiscard
]] bool prepareForPropValue(uint32_t keyPos
, Kind kind
);
264 [[nodiscard
]] bool prepareForPrivateMethod();
266 [[nodiscard
]] bool prepareForPrivateStaticMethod(uint32_t keyPos
);
272 [[nodiscard
]] bool prepareForIndexPropKey(uint32_t keyPos
, Kind kind
);
273 [[nodiscard
]] bool prepareForIndexPropValue();
275 // { [ key ]: value }
279 [[nodiscard
]] bool prepareForComputedPropKey(uint32_t keyPos
, Kind kind
);
280 [[nodiscard
]] bool prepareForComputedPropValue();
282 [[nodiscard
]] bool emitInitHomeObject();
286 [[nodiscard
]] bool emitInit(AccessorType accessorType
,
287 TaggedParserAtomIndex key
);
289 [[nodiscard
]] bool emitInitIndexOrComputed(AccessorType accessorType
);
291 [[nodiscard
]] bool emitPrivateStaticMethod(AccessorType accessorType
);
293 [[nodiscard
]] bool skipInit();
296 [[nodiscard
]] MOZ_ALWAYS_INLINE
bool prepareForProp(uint32_t keyPos
,
301 // Opcode for initializing property
303 // Atom of the property if the property key is not computed
304 [[nodiscard
]] bool emitInit(JSOp op
, TaggedParserAtomIndex key
);
305 [[nodiscard
]] bool emitInitIndexOrComputed(JSOp op
);
307 [[nodiscard
]] bool emitPopClassConstructor();
310 // Class for emitting bytecode for object literal.
312 // Usage: (check for the return value is omitted for simplicity)
315 // ObjectEmitter oe(this);
320 // ObjectEmitter oe(this);
323 // oe.prepareForPropValue(offset_of_prop);
325 // oe.emitInitProp(atom_of_prop);
329 // `{ prop: function() {} }`, when property value is anonymous function
330 // ObjectEmitter oe(this);
333 // oe.prepareForPropValue(offset_of_prop);
335 // oe.emitInitProp(atom_of_prop);
339 // `{ get prop() { ... }, set prop(v) { ... } }`
340 // ObjectEmitter oe(this);
343 // oe.prepareForPropValue(offset_of_prop);
344 // emit(function_for_getter);
345 // oe.emitInitGetter(atom_of_prop);
347 // oe.prepareForPropValue(offset_of_prop);
348 // emit(function_for_setter);
349 // oe.emitInitSetter(atom_of_prop);
353 // `{ 1: 10, get 2() { ... }, set 3(v) { ... } }`
354 // ObjectEmitter oe(this);
357 // oe.prepareForIndexPropKey(offset_of_prop);
359 // oe.prepareForIndexPropValue();
361 // oe.emitInitIndexedProp();
363 // oe.prepareForIndexPropKey(offset_of_opening_bracket);
365 // oe.prepareForIndexPropValue();
366 // emit(function_for_getter);
367 // oe.emitInitIndexGetter();
369 // oe.prepareForIndexPropKey(offset_of_opening_bracket);
371 // oe.prepareForIndexPropValue();
372 // emit(function_for_setter);
373 // oe.emitInitIndexSetter();
377 // `{ [prop1]: 10, get [prop2]() { ... }, set [prop3](v) { ... } }`
378 // ObjectEmitter oe(this);
381 // oe.prepareForComputedPropKey(offset_of_opening_bracket);
383 // oe.prepareForComputedPropValue();
385 // oe.emitInitComputedProp();
387 // oe.prepareForComputedPropKey(offset_of_opening_bracket);
389 // oe.prepareForComputedPropValue();
390 // emit(function_for_getter);
391 // oe.emitInitComputedGetter();
393 // oe.prepareForComputedPropKey(offset_of_opening_bracket);
395 // oe.prepareForComputedPropValue();
396 // emit(function_for_setter);
397 // oe.emitInitComputedSetter();
401 // `{ __proto__: obj }`
402 // ObjectEmitter oe(this);
404 // oe.prepareForProtoValue(offset_of___proto__);
406 // oe.emitMutateProto();
410 // ObjectEmitter oe(this);
412 // oe.prepareForSpreadOperand(offset_of_triple_dots);
417 class MOZ_STACK_CLASS ObjectEmitter
: public PropertyEmitter
{
420 // The state of this emitter.
422 // +-------+ emitObject +--------+
423 // | Start |----------->| Object |-+
424 // +-------+ +--------+ |
426 // +-----------------------------+
428 // | (do PropertyEmitter operation) emitEnd +-----+
429 // +-------------------------------+--------->| End |
431 enum class ObjectState
{
432 // The initial state.
435 // After calling emitObject.
438 // After calling emitEnd.
441 ObjectState objectState_
= ObjectState::Start
;
445 explicit ObjectEmitter(BytecodeEmitter
* bce
);
447 [[nodiscard
]] bool emitObject(size_t propertyCount
);
448 // Same as `emitObject()`, but start with an empty template object already on
450 [[nodiscard
]] bool emitObjectWithTemplateOnStack();
451 [[nodiscard
]] bool emitEnd();
454 // Save and restore the strictness.
455 // Used by class declaration/expression to temporarily enable strict mode.
456 class MOZ_RAII AutoSaveLocalStrictMode
{
458 bool savedStrictness_
;
461 explicit AutoSaveLocalStrictMode(SharedContext
* sc
);
462 ~AutoSaveLocalStrictMode();
464 // Force restore the strictness now.
468 // Class for emitting bytecode for JS class.
470 // Usage: (check for the return value is omitted for simplicity)
472 // `class { constructor() { ... } }`
473 // ClassEmitter ce(this);
474 // ce.emitScope(scopeBindings);
475 // ce.emitClass(nullptr, nullptr, false);
477 // emit(function_for_constructor);
478 // ce.emitInitConstructor(/* needsHomeObject = */ false);
480 // ce.emitEnd(ClassEmitter::Kind::Expression);
482 // `class X { constructor() { ... } }`
483 // ClassEmitter ce(this);
484 // ce.emitScope(scopeBindings);
485 // ce.emitClass(atom_of_X, nullptr, false);
487 // emit(function_for_constructor);
488 // ce.emitInitConstructor(/* needsHomeObject = */ false);
490 // ce.emitEnd(ClassEmitter::Kind::Expression);
492 // `class X extends Y { constructor() { ... } }`
493 // ClassEmitter ce(this);
494 // ce.emitScope(scopeBindings);
497 // ce.emitDerivedClass(atom_of_X, nullptr, false);
499 // emit(function_for_constructor);
500 // ce.emitInitConstructor(/* needsHomeObject = */ false);
502 // ce.emitEnd(ClassEmitter::Kind::Expression);
504 // `class X extends Y { constructor() { ... super.f(); ... } }`
505 // ClassEmitter ce(this);
506 // ce.emitScope(scopeBindings);
509 // ce.emitDerivedClass(atom_of_X, nullptr, false);
511 // emit(function_for_constructor);
512 // // pass true if constructor contains super.prop access
513 // ce.emitInitConstructor(/* needsHomeObject = */ true);
515 // ce.emitEnd(ClassEmitter::Kind::Expression);
517 // `class X extends Y { field0 = expr0; ... }`
518 // ClassEmitter ce(this);
519 // ce.emitScope(scopeBindings);
521 // ce.emitDerivedClass(atom_of_X, nullptr, false);
523 // ce.prepareForMemberInitializers(fields.length());
524 // for (auto field : fields) {
525 // emit(field.initializer_method());
526 // ce.emitStoreMemberInitializer();
528 // ce.emitMemberInitializersEnd();
530 // emit(function_for_constructor);
531 // ce.emitInitConstructor(/* needsHomeObject = */ false);
532 // ce.emitEnd(ClassEmitter::Kind::Expression);
534 // `class X { field0 = super.method(); ... }`
535 // // after emitClass/emitDerivedClass
536 // ce.prepareForMemberInitializers(1);
537 // for (auto field : fields) {
538 // emit(field.initializer_method());
539 // if (field.initializer_contains_super_or_eval()) {
540 // ce.emitMemberInitializerHomeObject();
542 // ce.emitStoreMemberInitializer();
544 // ce.emitMemberInitializersEnd();
547 // // after emitInitConstructor
548 // ce.prepareForPropValue(offset_of_m);
549 // emit(function_for_m);
550 // ce.emitInitProp(atom_of_m);
552 // `m() { super.f(); }` in class
553 // // after emitInitConstructor
554 // ce.prepareForPropValue(offset_of_m);
555 // emit(function_for_m);
556 // ce.emitInitHomeObject();
557 // ce.emitInitProp(atom_of_m);
559 // `async m() { super.f(); }` in class
560 // // after emitInitConstructor
561 // ce.prepareForPropValue(offset_of_m);
562 // emit(function_for_m);
563 // ce.emitInitHomeObject();
564 // ce.emitInitProp(atom_of_m);
566 // `get p() { super.f(); }` in class
567 // // after emitInitConstructor
568 // ce.prepareForPropValue(offset_of_p);
569 // emit(function_for_p);
570 // ce.emitInitHomeObject();
571 // ce.emitInitGetter(atom_of_m);
573 // `static m() {}` in class
574 // // after emitInitConstructor
575 // ce.prepareForPropValue(offset_of_m,
576 // PropertyEmitter::Kind::Static);
577 // emit(function_for_m);
578 // ce.emitInitProp(atom_of_m);
580 // `static get [p]() { super.f(); }` in class
581 // // after emitInitConstructor
582 // ce.prepareForComputedPropValue(offset_of_m,
583 // PropertyEmitter::Kind::Static);
585 // ce.prepareForComputedPropValue();
586 // emit(function_for_m);
587 // ce.emitInitHomeObject();
588 // ce.emitInitComputedGetter();
590 class MOZ_STACK_CLASS ClassEmitter
: public PropertyEmitter
{
596 // Class declaration.
601 // Pseudocode for class declarations:
603 // class extends BaseExpression {
604 // constructor() { ... }
609 // if defined <BaseExpression> {
610 // let heritage = BaseExpression;
612 // if (heritage !== null) {
613 // funProto = heritage;
614 // objProto = heritage.prototype;
616 // funProto = %FunctionPrototype%;
620 // objProto = %ObjectPrototype%;
623 // let homeObject = ObjectCreate(objProto);
625 // if defined <constructor> {
626 // if defined <BaseExpression> {
627 // cons = DefineMethod(<constructor>, proto=homeObject,
628 // funProto=funProto);
630 // cons = DefineMethod(<constructor>, proto=homeObject);
633 // if defined <BaseExpression> {
634 // cons = DefaultDerivedConstructor(proto=homeObject,
635 // funProto=funProto);
637 // cons = DefaultConstructor(proto=homeObject);
641 // cons.prototype = homeObject;
642 // homeObject.constructor = cons;
644 // EmitPropertyList(...)
646 bool isDerived_
= false;
648 mozilla::Maybe
<TDZCheckCache
> tdzCache_
;
649 mozilla::Maybe
<EmitterScope
> innerScope_
;
650 mozilla::Maybe
<TDZCheckCache
> bodyTdzCache_
;
651 mozilla::Maybe
<EmitterScope
> bodyScope_
;
652 AutoSaveLocalStrictMode strictMode_
;
655 // The state of this emitter.
659 // | Start |-+------------------------>+--+------------------------------>+--+
660 // +-------+ | ^ | ^ |
661 // | [has scope] | | [has body scope] | |
662 // | emitScope +-------+ | | emitBodyScope +-----------+ | |
663 // +-------------->| Scope |-+ +---------------->| BodyScope |-+ |
664 // +-------+ +-----------+ |
666 // +-----------------------------------------------------------------------+
668 // | emitClass +-------+
669 // +-+----------------->+->| Class |-+
671 // | emitDerivedClass | |
672 // +------------------+ |
674 // +-------------------------------+
677 // | prepareForMemberInitializers(isStatic = false)
680 // | +--------v-------------------+
681 // | | InstanceMemberInitializers |
682 // | +----------------------------+
684 // | emitMemberInitializersEnd
686 // | +--------v----------------------+
687 // | | InstanceMemberInitializersEnd |
688 // | +-------------------------------+
692 // | emitInitConstructor +-----------------+
693 // +-------------------------------->| InitConstructor |-+
694 // +-----------------+ |
698 // +-----------------------------------------------------+
700 // | prepareForMemberInitializers(isStatic = true)
703 // | +--------v-----------------+
704 // | | StaticMemberInitializers |
705 // | +--------------------------+
707 // | | emitMemberInitializersEnd
709 // | +--------v--------------------+
710 // | | StaticMemberInitializersEnd |
711 // | +-----------------------------+
715 // | (do PropertyEmitter operation)
716 // +--------------------------------+
718 // +-------------+ emitBinding |
719 // | BoundName |<-----------------+
729 enum class ClassState
{
730 // The initial state.
733 // After calling emitScope.
736 // After calling emitBodyScope.
739 // After calling emitClass or emitDerivedClass.
742 // After calling emitInitConstructor.
745 // After calling prepareForMemberInitializers(isStatic = false).
746 InstanceMemberInitializers
,
748 // After calling emitMemberInitializersEnd.
749 InstanceMemberInitializersEnd
,
751 // After calling prepareForMemberInitializers(isStatic = true).
752 StaticMemberInitializers
,
754 // After calling emitMemberInitializersEnd.
755 StaticMemberInitializersEnd
,
757 // After calling emitBinding.
760 // After calling emitEnd.
763 ClassState classState_
= ClassState::Start
;
765 // The state of the members emitter.
770 // | Start +<-----------------------------+
773 // | prepareForMemberInitializer | emitStoreMemberInitializer
776 // | Initializer +------------------------->+
779 // | emitMemberInitializerHomeObject |
781 // +---------------------------+ |
782 // | InitializerWithHomeObject +------------+
783 // +---------------------------+
786 enum class MemberState
{
787 // After calling prepareForMemberInitializers
788 // and 0 or more calls to emitStoreMemberInitializer.
791 // After calling prepareForMemberInitializer
794 // After calling emitMemberInitializerHomeObject
795 InitializerWithHomeObject
,
797 MemberState memberState_
= MemberState::Start
;
799 size_t numInitializers_
= 0;
802 TaggedParserAtomIndex name_
;
803 TaggedParserAtomIndex nameForAnonymousClass_
;
804 bool hasNameOnStack_
= false;
805 mozilla::Maybe
<NameOpEmitter
> initializersAssignment_
;
806 size_t initializerIndex_
= 0;
809 explicit ClassEmitter(BytecodeEmitter
* bce
);
811 bool emitScope(LexicalScope::ParserData
* scopeBindings
);
812 bool emitBodyScope(ClassBodyScope::ParserData
* scopeBindings
);
815 // Name of the class (nullptr if this is anonymous class)
816 // @param nameForAnonymousClass
817 // Statically inferred name of the class (only for anonymous classes)
818 // @param hasNameOnStack
819 // If true the name is on the stack (only for anonymous classes)
820 [[nodiscard
]] bool emitClass(TaggedParserAtomIndex name
,
821 TaggedParserAtomIndex nameForAnonymousClass
,
822 bool hasNameOnStack
);
823 [[nodiscard
]] bool emitDerivedClass(
824 TaggedParserAtomIndex name
, TaggedParserAtomIndex nameForAnonymousClass
,
825 bool hasNameOnStack
);
827 // @param needsHomeObject
828 // True if the constructor contains `super.foo`
829 [[nodiscard
]] bool emitInitConstructor(bool needsHomeObject
);
831 [[nodiscard
]] bool prepareForMemberInitializers(size_t numInitializers
,
833 [[nodiscard
]] bool prepareForMemberInitializer();
834 [[nodiscard
]] bool emitMemberInitializerHomeObject(bool isStatic
);
835 [[nodiscard
]] bool emitStoreMemberInitializer();
836 [[nodiscard
]] bool emitMemberInitializersEnd();
838 [[nodiscard
]] bool emitBinding();
840 #ifdef ENABLE_DECORATORS
841 // TODO!: When we've enabled decorators, update the states and transition
842 // diagram to reflect this new state.
843 [[nodiscard
]] bool prepareForDecorators();
846 [[nodiscard
]] bool emitEnd(Kind kind
);
849 [[nodiscard
]] bool initProtoAndCtor();
851 [[nodiscard
]] bool leaveBodyAndInnerScope();
854 } /* namespace frontend */
857 #endif /* frontend_ObjectEmitter_h */