Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / frontend / PrivateOpEmitter.h
blob558541b05c36b3c0d2e179733a54332f166c5263
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"
13 #include <stddef.h>
15 #include "frontend/NameAnalysisTypes.h" // NameLocation
16 #include "frontend/ParserAtom.h" // TaggedParserAtomIndex
18 namespace js {
19 namespace frontend {
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
29 // SyntaxErrors.
31 // Usage: (error checking is omitted for simplicity)
33 // `obj.#member;`
34 // PrivateOpEmitter xoe(this,
35 // privateName,
36 // PrivateOpEmitter::Kind::Get);
37 // emit(obj);
38 // xoe.emitReference();
39 // xoe.emitGet();
41 // `obj.#member();`
42 // PrivateOpEmitter xoe(this,
43 // privateName,
44 // PrivateOpEmitter::Kind::Call);
45 // emit(obj);
46 // xoe.emitReference();
47 // xoe.emitGet();
48 // emit_call_here();
50 // `new obj.#member();`
51 // The same, but use PrivateOpEmitter::Kind::Get.
53 // `obj.#field++;`
54 // PrivateOpEmitter xoe(this,
55 // privateName,
56 // PrivateOpEmitter::Kind::PostIncrement);
57 // emit(obj);
58 // xoe.emitReference();
59 // xoe.emitIncDec();
61 // `obj.#field = value;`
62 // PrivateOpEmitter xoe(this,
63 // privateName,
64 // PrivateOpEmitter::Kind::SimpleAssignment);
65 // emit(obj);
66 // xoe.emitReference();
67 // emit(value);
68 // xoe.emitAssignment();
70 // `obj.#field += value;`
71 // PrivateOpEmitter xoe(this,
72 // privateName,
73 // PrivateOpEmitter::Kind::CompoundAssignment);
74 // emit(obj);
75 // xoe.emitReference();
76 // emit(JSOp::Dup2);
77 // xoe.emitGet();
78 // emit(value);
79 // emit_add_op_here();
80 // xoe.emitAssignment();
82 class MOZ_STACK_CLASS PrivateOpEmitter {
83 public:
84 enum class Kind {
85 Get,
86 Call,
87 Delete,
88 PostIncrement,
89 PreIncrement,
90 PostDecrement,
91 PreDecrement,
92 SimpleAssignment,
93 PropInit,
94 CompoundAssignment,
95 ErgonomicBrandCheck,
98 private:
99 BytecodeEmitter* bce_;
101 Kind kind_;
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_{};
114 #ifdef DEBUG
115 // The state of this emitter.
117 // emitReference
118 // +-------+ skipReference +-----------+
119 // | Start |---------------->| Reference |
120 // +-------+ +-----+-----+
121 // |
122 // +---------------------------+
123 // |
124 // |
125 // | [Get]
126 // | emitGet
127 // | [Call] [Get] [CompoundAssignment]
128 // | emitGetForCallOrNew +-----+ emitAssignment
129 // +---------------------->| Get |-------------------+
130 // | +-----+ |
131 // | [PostIncrement] |
132 // | [PreIncrement] |
133 // | [PostDecrement] |
134 // | [PreDecrement] |
135 // | emitIncDec |
136 // +------------------------------------------------>+
137 // | |
138 // | [SimpleAssignment] |
139 // | [PropInit] V
140 // | emitAssignment +------------+
141 // +------------------------------------------>| Assignment |
142 // +------------+
143 enum class State {
144 // The initial state.
145 Start,
147 // After calling emitReference or skipReference.
148 Reference,
150 // After calling emitGet.
151 Get,
153 // After calling emitAssignment or emitIncDec.
154 Assignment,
156 State state_ = State::Start;
157 #endif
159 public:
160 PrivateOpEmitter(BytecodeEmitter* bce, Kind kind, TaggedParserAtomIndex name);
162 private:
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();
203 public:
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 */
229 } /* namespace js */
231 #endif /* frontend_PrivateOpEmitter_h */