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_PrivateOpEmitter_h
8 #define frontend_PrivateOpEmitter_h
10 #include "mozilla/Attributes.h"
11 #include "mozilla/Maybe.h"
15 #include "frontend/NameAnalysisTypes.h" // NameLocation
16 #include "frontend/ParserAtom.h" // TaggedParserAtomIndex
21 struct BytecodeEmitter
;
22 enum class ValueUsage
;
24 // Class for emitting bytecode for operations on private members of objects.
26 // Usage is similar to PropOpEmitter, but the name of the private member must
27 // be passed to the constructor; prepare*() methods aren't necessary; and
28 // `delete obj.#member` and `super.#member` aren't supported because both are
31 // Usage: (error checking is omitted for simplicity)
34 // PrivateOpEmitter xoe(this,
36 // PrivateOpEmitter::Kind::Get);
38 // xoe.emitReference();
42 // PrivateOpEmitter xoe(this,
44 // PrivateOpEmitter::Kind::Call);
46 // xoe.emitReference();
50 // `new obj.#member();`
51 // The same, but use PrivateOpEmitter::Kind::Get.
54 // PrivateOpEmitter xoe(this,
56 // PrivateOpEmitter::Kind::PostIncrement);
58 // xoe.emitReference();
61 // `obj.#field = value;`
62 // PrivateOpEmitter xoe(this,
64 // PrivateOpEmitter::Kind::SimpleAssignment);
66 // xoe.emitReference();
68 // xoe.emitAssignment();
70 // `obj.#field += value;`
71 // PrivateOpEmitter xoe(this,
73 // PrivateOpEmitter::Kind::CompoundAssignment);
75 // xoe.emitReference();
79 // emit_add_op_here();
80 // xoe.emitAssignment();
82 class MOZ_STACK_CLASS PrivateOpEmitter
{
99 BytecodeEmitter
* bce_
;
103 // Name of the private member, e.g. "#field".
104 TaggedParserAtomIndex name_
;
106 // Location of the slot containing the private name symbol; or, for a
107 // non-static private method, the slot containing the method.
108 mozilla::Maybe
<NameLocation
> loc_
;
110 // For non-static private method accesses, the location of the relevant
111 // `.privateBrand` binding. Otherwise, `Nothing`.
112 mozilla::Maybe
<NameLocation
> brandLoc_
{};
115 // The state of this emitter.
118 // +-------+ skipReference +-----------+
119 // | Start |---------------->| Reference |
120 // +-------+ +-----+-----+
122 // +---------------------------+
127 // | [Call] [Get] [CompoundAssignment]
128 // | emitGetForCallOrNew +-----+ emitAssignment
129 // +---------------------->| Get |-------------------+
131 // | [PostIncrement] |
132 // | [PreIncrement] |
133 // | [PostDecrement] |
134 // | [PreDecrement] |
136 // +------------------------------------------------>+
138 // | [SimpleAssignment] |
140 // | emitAssignment +------------+
141 // +------------------------------------------>| Assignment |
144 // The initial state.
147 // After calling emitReference or skipReference.
150 // After calling emitGet.
153 // After calling emitAssignment or emitIncDec.
156 State state_
= State::Start
;
160 PrivateOpEmitter(BytecodeEmitter
* bce
, Kind kind
, TaggedParserAtomIndex name
);
163 [[nodiscard
]] bool isCall() const { return kind_
== Kind::Call
; }
165 [[nodiscard
]] bool isSimpleAssignment() const {
166 return kind_
== Kind::SimpleAssignment
;
169 [[nodiscard
]] bool isFieldInit() const { return kind_
== Kind::PropInit
; }
171 [[nodiscard
]] bool isBrandCheck() const {
172 return kind_
== Kind::ErgonomicBrandCheck
;
175 [[nodiscard
]] bool isCompoundAssignment() const {
176 return kind_
== Kind::CompoundAssignment
;
179 [[nodiscard
]] bool isIncDec() const {
180 return isPostIncDec() || isPreIncDec();
183 [[nodiscard
]] bool isPostIncDec() const {
184 return kind_
== Kind::PostIncrement
|| kind_
== Kind::PostDecrement
;
187 [[nodiscard
]] bool isPreIncDec() const {
188 return kind_
== Kind::PreIncrement
|| kind_
== Kind::PreDecrement
;
191 [[nodiscard
]] bool isInc() const {
192 return kind_
== Kind::PostIncrement
|| kind_
== Kind::PreIncrement
;
195 [[nodiscard
]] bool init();
197 // Emit a GetAliasedLexical or similar instruction.
198 [[nodiscard
]] bool emitLoad(TaggedParserAtomIndex name
,
199 const NameLocation
& loc
);
201 [[nodiscard
]] bool emitLoadPrivateBrand();
204 // Emit bytecode to check for the presence/absence of a private field/brand.
206 // Given OBJ KEY on the stack, where KEY is a private name symbol, the
207 // emitted code will throw if OBJ does not have the given KEY.
209 // If `isFieldInit()`, the check is reversed: the code will throw if OBJ
210 // already has the KEY.
212 // If `isBrandCheck()`, the check verifies RHS is an object (throwing if not).
214 // The bytecode leaves OBJ KEY BOOL on the stack. Caller is responsible for
215 // consuming or popping it.
216 [[nodiscard
]] bool emitBrandCheck();
218 [[nodiscard
]] bool emitReference();
219 [[nodiscard
]] bool skipReference();
220 [[nodiscard
]] bool emitGet();
221 [[nodiscard
]] bool emitGetForCallOrNew();
222 [[nodiscard
]] bool emitAssignment();
223 [[nodiscard
]] bool emitIncDec(ValueUsage valueUsage
);
225 [[nodiscard
]] size_t numReferenceSlots() { return 2; }
228 } /* namespace frontend */
231 #endif /* frontend_PrivateOpEmitter_h */