Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / frontend / CallOrNewEmitter.h
blob5abf644b70585d2ecded632106e8f01093a47e5b
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_CallOrNewEmitter_h
8 #define frontend_CallOrNewEmitter_h
10 #include "mozilla/Attributes.h"
11 #include "mozilla/Maybe.h"
13 #include <stdint.h>
15 #include "frontend/ElemOpEmitter.h"
16 #include "frontend/IfEmitter.h"
17 #include "frontend/PrivateOpEmitter.h"
18 #include "frontend/PropOpEmitter.h"
19 #include "frontend/ValueUsage.h"
20 #include "vm/BytecodeUtil.h"
21 #include "vm/Opcodes.h"
23 namespace js {
24 namespace frontend {
26 struct BytecodeEmitter;
27 class TaggedParserAtomIndex;
29 // Class for emitting bytecode for call or new expression.
31 // Usage: (check for the return value is omitted for simplicity)
33 // `print(arg);`
34 // CallOrNewEmitter cone(this, JSOp::Call,
35 // CallOrNewEmitter::ArgumentsKind::Other,
36 // ValueUsage::WantValue);
37 // cone.emitNameCallee(print);
38 // cone.emitThis();
39 // cone.prepareForNonSpreadArguments();
40 // emit(arg);
41 // cone.emitEnd(1, offset_of_callee);
43 // `callee.prop(arg1, arg2);`
44 // CallOrNewEmitter cone(this, JSOp::Call,
45 // CallOrNewEmitter::ArgumentsKind::Other,
46 // ValueUsage::WantValue);
47 // PropOpEmitter& poe = cone.prepareForPropCallee(false);
48 // ... emit `callee.prop` with `poe` here...
49 // cone.emitThis();
50 // cone.prepareForNonSpreadArguments();
51 // emit(arg1);
52 // emit(arg2);
53 // cone.emitEnd(2, offset_of_callee);
55 // `callee[key](arg);`
56 // CallOrNewEmitter cone(this, JSOp::Call,
57 // CallOrNewEmitter::ArgumentsKind::Other,
58 // ValueUsage::WantValue);
59 // ElemOpEmitter& eoe = cone.prepareForElemCallee(false);
60 // ... emit `callee[key]` with `eoe` here...
61 // cone.emitThis();
62 // cone.prepareForNonSpreadArguments();
63 // emit(arg);
64 // cone.emitEnd(1, offset_of_callee);
66 // `callee.#method(arg);`
67 // CallOrNewEmitter cone(this, JSOp::Call,
68 // CallOrNewEmitter::ArgumentsKind::Other,
69 // ValueUsage::WantValue);
70 // PrivateOpEmitter& xoe = cone.prepareForPrivateCallee();
71 // ... emit `callee.#method` with `xoe` here...
72 // cone.prepareForNonSpreadArguments();
73 // emit(arg);
74 // cone.emitEnd(1, offset_of_callee);
76 // `(function() { ... })(arg);`
77 // CallOrNewEmitter cone(this, JSOp::Call,
78 // CallOrNewEmitter::ArgumentsKind::Other,
79 // ValueUsage::WantValue);
80 // cone.prepareForFunctionCallee();
81 // emit(function);
82 // cone.emitThis();
83 // cone.prepareForNonSpreadArguments();
84 // emit(arg);
85 // cone.emitEnd(1, offset_of_callee);
87 // `super(arg);`
88 // CallOrNewEmitter cone(this, JSOp::Call,
89 // CallOrNewEmitter::ArgumentsKind::Other,
90 // ValueUsage::WantValue);
91 // cone.emitSuperCallee();
92 // cone.emitThis();
93 // cone.prepareForNonSpreadArguments();
94 // emit(arg);
95 // cone.emitEnd(1, offset_of_callee);
97 // `(some_other_expression)(arg);`
98 // CallOrNewEmitter cone(this, JSOp::Call,
99 // CallOrNewEmitter::ArgumentsKind::Other,
100 // ValueUsage::WantValue);
101 // cone.prepareForOtherCallee();
102 // emit(some_other_expression);
103 // cone.emitThis();
104 // cone.prepareForNonSpreadArguments();
105 // emit(arg);
106 // cone.emitEnd(1, offset_of_callee);
108 // `print(...arg);`
109 // CallOrNewEmitter cone(this, JSOp::SpreadCall,
110 // CallOrNewEmitter::ArgumentsKind::SingleSpread,
111 // ValueUsage::WantValue);
112 // cone.emitNameCallee(print);
113 // cone.emitThis();
114 // if (cone.wantSpreadOperand()) {
115 // emit(arg)
116 // }
117 // cone.emitSpreadArgumentsTest();
118 // emit([...arg]);
119 // cone.emitEnd(1, offset_of_callee);
121 // `new f(arg);`
122 // CallOrNewEmitter cone(this, JSOp::New,
123 // CallOrNewEmitter::ArgumentsKind::Other,
124 // ValueUsage::WantValue);
125 // cone.emitNameCallee(f);
126 // cone.emitThis();
127 // cone.prepareForNonSpreadArguments();
128 // emit(arg);
129 // cone.emitEnd(1, offset_of_callee);
131 class MOZ_STACK_CLASS CallOrNewEmitter {
132 public:
133 enum class ArgumentsKind {
134 Other,
136 // Specify this for the following case:
138 // g(...input);
140 // This enables optimization to avoid allocating an intermediate array
141 // for spread operation.
143 // wantSpreadOperand() returns true when this is specified.
144 SingleSpread,
146 // Used for default derived class constructors:
148 // constructor(...args) {
149 // super(...args);
150 // }
152 // The rest-parameter is directly passed through to the `super` call without
153 // using the iteration protocol.
154 PassthroughRest,
157 private:
158 BytecodeEmitter* bce_;
160 // The opcode for the call or new.
161 JSOp op_;
163 // Whether the call is a spread call with single parameter or not.
164 // See the comment in emitSpreadArgumentsTest for more details.
165 ArgumentsKind argumentsKind_;
167 // The branch for spread call optimization.
168 mozilla::Maybe<InternalIfEmitter> ifNotOptimizable_;
170 mozilla::Maybe<PropOpEmitter> poe_;
171 mozilla::Maybe<ElemOpEmitter> eoe_;
172 mozilla::Maybe<PrivateOpEmitter> xoe_;
174 // The state of this emitter.
176 // +-------+ emitNameCallee +------------+
177 // | Start |-+------------------------->| NameCallee |------+
178 // +-------+ | +------------+ |
179 // | |
180 // | prepareForPropCallee +------------+ v
181 // +------------------------->| PropCallee |----->+
182 // | +------------+ |
183 // | |
184 // | prepareForElemCallee +------------+ v
185 // +------------------------->| ElemCallee |----->+
186 // | +------------+ |
187 // | |
188 // | prepareForPrivateCallee +---------------+ v
189 // +------------------------->| PrivateCallee |-->+
190 // | +---------------+ |
191 // | |
192 // | prepareForFunctionCallee +----------------+ v
193 // +------------------------->| FunctionCallee |->+
194 // | +----------------+ |
195 // | |
196 // | emitSuperCallee +-------------+ v
197 // +------------------------->| SuperCallee |---->+
198 // | +-------------+ |
199 // | |
200 // | prepareForOtherCallee +-------------+ v
201 // +------------------------->| OtherCallee |---->+
202 // +-------------+ |
203 // |
204 // +--------------------------------------------------------+
205 // |
206 // | emitThis +------+
207 // +--------->| This |-+
208 // +------+ |
209 // |
210 // +-------------------+
211 // |
212 // | [!isSpread]
213 // | prepareForNonSpreadArguments +-----------+ emitEnd +-----+
214 // +------------------------------->+->| Arguments |-------->| End |
215 // | ^ +-----------+ +-----+
216 // | |
217 // | +<------------------------------------+
218 // | | |
219 // | | emitSpreadArgumentsTestEnd |
220 // | | |
221 // | | +-----------------+ |
222 // | +---------| SpreadIteration |------+ |
223 // | +-----------------+ | |
224 // | +----------------------------------+ |
225 // | | |
226 // | | wantSpreadIteration |
227 // | | |
228 // | | +---------------------+ |
229 // | +---------| SpreadArgumentsTest |--+ |
230 // | +---------------------+ | |
231 // | [isSpread] | |
232 // | wantSpreadOperand +-------------------+ emitSpreadArgumentsTest | |
233 // +-------------------->| WantSpreadOperand |-------------------------+ |
234 // | +-------------------+ |
235 // | |
236 // | |
237 // | |
238 // | [isSpread] |
239 // | prepareForSpreadArguments |
240 // +----------------------------------------------------------------------+
241 enum class State {
242 // The initial state.
243 Start,
245 // After calling emitNameCallee.
246 NameCallee,
248 // After calling prepareForPropCallee.
249 PropCallee,
251 // After calling prepareForElemCallee.
252 ElemCallee,
254 // After calling prepareForPrivateCallee.
255 PrivateCallee,
257 // After calling prepareForFunctionCallee.
258 FunctionCallee,
260 // After calling emitSuperCallee.
261 SuperCallee,
263 // After calling prepareForOtherCallee.
264 OtherCallee,
266 // After calling emitThis.
267 This,
269 // After calling wantSpreadOperand.
270 WantSpreadOperand,
272 // After calling emitSpreadArgumentsTest.
273 SpreadArgumentsTest,
275 // After calling wantSpreadIteration.
276 SpreadIteration,
278 // After calling prepareForNonSpreadArguments.
279 Arguments,
281 // After calling emitEnd.
284 State state_ = State::Start;
286 public:
287 CallOrNewEmitter(BytecodeEmitter* bce, JSOp op, ArgumentsKind argumentsKind,
288 ValueUsage valueUsage);
290 private:
291 [[nodiscard]] bool isCall() const {
292 return op_ == JSOp::Call || op_ == JSOp::CallIgnoresRv ||
293 op_ == JSOp::SpreadCall || isEval();
296 [[nodiscard]] bool isNew() const {
297 return op_ == JSOp::New || op_ == JSOp::SpreadNew;
300 [[nodiscard]] bool isSuperCall() const {
301 return op_ == JSOp::SuperCall || op_ == JSOp::SpreadSuperCall;
304 [[nodiscard]] bool isEval() const {
305 return op_ == JSOp::Eval || op_ == JSOp::StrictEval ||
306 op_ == JSOp::SpreadEval || op_ == JSOp::StrictSpreadEval;
309 [[nodiscard]] bool isSpread() const { return IsSpreadOp(op_); }
311 [[nodiscard]] bool isSingleSpread() const {
312 return argumentsKind_ == ArgumentsKind::SingleSpread;
315 [[nodiscard]] bool isPassthroughRest() const {
316 return argumentsKind_ == ArgumentsKind::PassthroughRest;
319 public:
320 [[nodiscard]] bool emitNameCallee(TaggedParserAtomIndex name);
321 [[nodiscard]] PropOpEmitter& prepareForPropCallee(bool isSuperProp);
322 [[nodiscard]] ElemOpEmitter& prepareForElemCallee(bool isSuperElem);
323 [[nodiscard]] PrivateOpEmitter& prepareForPrivateCallee(
324 TaggedParserAtomIndex privateName);
325 [[nodiscard]] bool prepareForFunctionCallee();
326 [[nodiscard]] bool emitSuperCallee();
327 [[nodiscard]] bool prepareForOtherCallee();
329 [[nodiscard]] bool emitThis();
331 [[nodiscard]] bool prepareForNonSpreadArguments();
332 [[nodiscard]] bool prepareForSpreadArguments();
334 // See the usage in the comment at the top of the class.
335 [[nodiscard]] bool wantSpreadOperand();
336 [[nodiscard]] bool emitSpreadArgumentsTest();
337 [[nodiscard]] bool emitSpreadArgumentsTestEnd();
338 [[nodiscard]] bool wantSpreadIteration();
340 // Parameters are the offset in the source code for each character below:
342 // callee(arg);
343 // ^
344 // |
345 // beginPos
346 [[nodiscard]] bool emitEnd(uint32_t argc, uint32_t beginPos);
349 } /* namespace frontend */
350 } /* namespace js */
352 #endif /* frontend_CallOrNewEmitter_h */