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_OptionalEmitter_h
8 #define frontend_OptionalEmitter_h
10 #include "mozilla/Attributes.h"
12 #include "frontend/JumpList.h"
13 #include "frontend/TDZCheckCache.h"
18 struct BytecodeEmitter
;
20 // Class for emitting bytecode for optional expressions.
22 // Usage: (check for the return value is omitted for simplicity)
25 // OptionalEmitter oe(this);
26 // PropOpEmitter poe(this,
27 // PropOpEmitter::Kind::Get,
28 // PropOpEmitter::ObjKind::Other);
29 // poe.prepareForObj();
31 // oe.emitJumpShortCircuit();
32 // poe.emitGet(atom_of_prop);
33 // oe.emitOptionalJumpTarget(JSOp::Undefined);
35 // `delete obj?.prop;`
36 // OptionalEmitter oe(this);
37 // OptionalPropOpEmitter poe(this,
38 // PropOpEmitter::Kind::Delete,
39 // PropOpEmitter::ObjKind::Other);
40 // poe.prepareForObj();
42 // oe.emitJumpShortCircuit();
43 // poe.emitDelete(atom_of_prop);
44 // oe.emitOptionalJumpTarget(JSOp:True);
47 // OptionalEmitter oe(this);
48 // ElemOpEmitter eoe(this,
49 // ElemOpEmitter::Kind::Get,
50 // ElemOpEmitter::ObjKind::Other);
51 // eoe.prepareForObj();
53 // oe.emitJumpShortCircuit();
54 // eoe.prepareForKey();
57 // oe.emitOptionalJumpTarget(JSOp::Undefined);
59 // `delete obj?.[key];`
60 // OptionalEmitter oe(this);
61 // ElemOpEmitter eoe(this,
62 // ElemOpEmitter::Kind::Delete,
63 // ElemOpEmitter::ObjKind::Other);
64 // eoe.prepareForObj();
66 // oe.emitJumpShortCircuit();
67 // eoe.prepareForKey();
70 // oe.emitOptionalJumpTarget(JSOp::True);
73 // OptionalEmitter oe(this);
74 // CallOrNewEmitter cone(this, JSOp::Call,
75 // CallOrNewEmitter::ArgumentsKind::Other,
76 // ValueUsage::WantValue);
77 // cone.emitNameCallee(print);
79 // oe.emitShortCircuitForCall();
80 // cone.prepareForNonSpreadArguments();
82 // cone.emitEnd(1, offset_of_callee);
83 // oe.emitOptionalJumpTarget(JSOp::Undefined);
85 // `callee.prop?.(arg1, arg2);`
86 // OptionalEmitter oe(this);
87 // CallOrNewEmitter cone(this, JSOp::Call,
88 // CallOrNewEmitter::ArgumentsKind::Other,
89 // ValueUsage::WantValue);
90 // PropOpEmitter& poe = cone.prepareForPropCallee(false);
91 // ... emit `callee.prop` with `poe` here...
93 // oe.emitShortCircuitForCall();
94 // cone.prepareForNonSpreadArguments();
97 // cone.emitEnd(2, offset_of_callee);
98 // oe.emitOptionalJumpTarget(JSOp::Undefined);
100 // `callee[key]?.(arg);`
101 // OptionalEmitter oe(this);
102 // CallOrNewEmitter cone(this, JSOp::Call,
103 // CallOrNewEmitter::ArgumentsKind::Other,
104 // ValueUsage::WantValue);
105 // ElemOpEmitter& eoe = cone.prepareForElemCallee(false);
106 // ... emit `callee[key]` with `eoe` here...
108 // oe.emitShortCircuitForCall();
109 // cone.prepareForNonSpreadArguments();
111 // cone.emitEnd(1, offset_of_callee);
112 // oe.emitOptionalJumpTarget(JSOp::Undefined);
114 // `(function() { ... })?.(arg);`
115 // OptionalEmitter oe(this);
116 // CallOrNewEmitter cone(this, JSOp::Call,
117 // CallOrNewEmitter::ArgumentsKind::Other,
118 // ValueUsage::WantValue);
119 // cone.prepareForFunctionCallee();
122 // oe.emitShortCircuitForCall();
123 // cone.prepareForNonSpreadArguments();
125 // cone.emitEnd(1, offset_of_callee);
126 // oe.emitOptionalJumpTarget(JSOp::Undefined);
129 // OptionalEmitter oe(this);
130 // CallOrNewEmitter cone(this, JSOp::Call,
131 // CallOrNewEmitter::ArgumentsKind::Other,
132 // ValueUsage::WantValue);
133 // cone.prepareForFunctionCallee();
134 // emit(optionalChain);
136 // oe.emitOptionalJumpTarget(JSOp::Undefined,
137 // OptionalEmitter::Kind::Reference);
138 // oe.emitShortCircuitForCall();
139 // cone.prepareForNonSpreadArguments();
141 // cone.emitEnd(1, offset_of_callee);
142 // oe.emitOptionalJumpTarget(JSOp::Undefined);
144 class MOZ_RAII OptionalEmitter
{
146 OptionalEmitter(BytecodeEmitter
* bce
, int32_t initialDepth
);
149 BytecodeEmitter
* bce_
;
151 TDZCheckCache tdzCache_
;
153 // jumptarget for ShortCircuiting code, which has null or undefined values
154 JumpList jumpShortCircuit_
;
156 // jumpTarget for code that does not shortCircuit
157 JumpList jumpFinish_
;
159 // jumpTarget for code that does not shortCircuit
160 int32_t initialDepth_
;
162 // The state of this emitter.
164 // +-------+ emitJumpShortCircuit +--------------+
165 // | Start |-+---------------------------->| ShortCircuit |-----------+
166 // +-------+ | +--------------+ |
168 // | | emitJumpShortCircuitForCall +---------------------+ v
169 // | +---------------------------->| ShortCircuitForCall |--->+
170 // | +---------------------+ |
172 // ---------------------------------------------------------------+
175 // +------------------------------------------------------------------+
177 // | emitOptionalJumpTarget +---------+
178 // +----------------------->| JumpEnd |
183 // The initial state.
186 // for shortcircuiting in most cases.
189 // for shortcircuiting from references, which have two items on
190 // the stack. For example function calls.
193 // internally used, end of the jump code
197 State state_
= State::Start
;
202 // Requires two values on the stack
204 // Requires one value on the stack
208 [[nodiscard
]] bool emitJumpShortCircuit();
209 [[nodiscard
]] bool emitJumpShortCircuitForCall();
211 // JSOp is the op code to be emitted, Kind is if we are dealing with a
212 // reference (in which case we need two elements on the stack) or other value
213 // (which needs one element on the stack)
214 [[nodiscard
]] bool emitOptionalJumpTarget(JSOp op
, Kind kind
= Kind::Other
);
217 } /* namespace frontend */
220 #endif /* frontend_OptionalEmitter_h */