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"
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"
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)
34 // CallOrNewEmitter cone(this, JSOp::Call,
35 // CallOrNewEmitter::ArgumentsKind::Other,
36 // ValueUsage::WantValue);
37 // cone.emitNameCallee(print);
39 // cone.prepareForNonSpreadArguments();
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...
50 // cone.prepareForNonSpreadArguments();
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...
62 // cone.prepareForNonSpreadArguments();
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();
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();
83 // cone.prepareForNonSpreadArguments();
85 // cone.emitEnd(1, offset_of_callee);
88 // CallOrNewEmitter cone(this, JSOp::Call,
89 // CallOrNewEmitter::ArgumentsKind::Other,
90 // ValueUsage::WantValue);
91 // cone.emitSuperCallee();
93 // cone.prepareForNonSpreadArguments();
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);
104 // cone.prepareForNonSpreadArguments();
106 // cone.emitEnd(1, offset_of_callee);
109 // CallOrNewEmitter cone(this, JSOp::SpreadCall,
110 // CallOrNewEmitter::ArgumentsKind::SingleSpread,
111 // ValueUsage::WantValue);
112 // cone.emitNameCallee(print);
114 // if (cone.wantSpreadOperand()) {
117 // cone.emitSpreadArgumentsTest();
119 // cone.emitEnd(1, offset_of_callee);
122 // CallOrNewEmitter cone(this, JSOp::New,
123 // CallOrNewEmitter::ArgumentsKind::Other,
124 // ValueUsage::WantValue);
125 // cone.emitNameCallee(f);
127 // cone.prepareForNonSpreadArguments();
129 // cone.emitEnd(1, offset_of_callee);
131 class MOZ_STACK_CLASS CallOrNewEmitter
{
133 enum class ArgumentsKind
{
136 // Specify this for the following case:
140 // This enables optimization to avoid allocating an intermediate array
141 // for spread operation.
143 // wantSpreadOperand() returns true when this is specified.
146 // Used for default derived class constructors:
148 // constructor(...args) {
152 // The rest-parameter is directly passed through to the `super` call without
153 // using the iteration protocol.
158 BytecodeEmitter
* bce_
;
160 // The opcode for the call or new.
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 // +-------+ | +------------+ |
180 // | prepareForPropCallee +------------+ v
181 // +------------------------->| PropCallee |----->+
182 // | +------------+ |
184 // | prepareForElemCallee +------------+ v
185 // +------------------------->| ElemCallee |----->+
186 // | +------------+ |
188 // | prepareForPrivateCallee +---------------+ v
189 // +------------------------->| PrivateCallee |-->+
190 // | +---------------+ |
192 // | prepareForFunctionCallee +----------------+ v
193 // +------------------------->| FunctionCallee |->+
194 // | +----------------+ |
196 // | emitSuperCallee +-------------+ v
197 // +------------------------->| SuperCallee |---->+
198 // | +-------------+ |
200 // | prepareForOtherCallee +-------------+ v
201 // +------------------------->| OtherCallee |---->+
204 // +--------------------------------------------------------+
206 // | emitThis +------+
207 // +--------->| This |-+
210 // +-------------------+
213 // | prepareForNonSpreadArguments +-----------+ emitEnd +-----+
214 // +------------------------------->+->| Arguments |-------->| End |
215 // | ^ +-----------+ +-----+
217 // | +<------------------------------------+
219 // | | emitSpreadArgumentsTestEnd |
221 // | | +-----------------+ |
222 // | +---------| SpreadIteration |------+ |
223 // | +-----------------+ | |
224 // | +----------------------------------+ |
226 // | | wantSpreadIteration |
228 // | | +---------------------+ |
229 // | +---------| SpreadArgumentsTest |--+ |
230 // | +---------------------+ | |
232 // | wantSpreadOperand +-------------------+ emitSpreadArgumentsTest | |
233 // +-------------------->| WantSpreadOperand |-------------------------+ |
234 // | +-------------------+ |
239 // | prepareForSpreadArguments |
240 // +----------------------------------------------------------------------+
242 // The initial state.
245 // After calling emitNameCallee.
248 // After calling prepareForPropCallee.
251 // After calling prepareForElemCallee.
254 // After calling prepareForPrivateCallee.
257 // After calling prepareForFunctionCallee.
260 // After calling emitSuperCallee.
263 // After calling prepareForOtherCallee.
266 // After calling emitThis.
269 // After calling wantSpreadOperand.
272 // After calling emitSpreadArgumentsTest.
275 // After calling wantSpreadIteration.
278 // After calling prepareForNonSpreadArguments.
281 // After calling emitEnd.
284 State state_
= State::Start
;
287 CallOrNewEmitter(BytecodeEmitter
* bce
, JSOp op
, ArgumentsKind argumentsKind
,
288 ValueUsage valueUsage
);
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
;
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:
346 [[nodiscard
]] bool emitEnd(uint32_t argc
, uint32_t beginPos
);
349 } /* namespace frontend */
352 #endif /* frontend_CallOrNewEmitter_h */