Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / frontend / OptionalEmitter.h
blob6507d68fa0721ec791f1d2dc68605427284364f6
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"
15 namespace js {
16 namespace frontend {
18 struct BytecodeEmitter;
20 // Class for emitting bytecode for optional expressions.
22 // Usage: (check for the return value is omitted for simplicity)
24 // `obj?.prop;`
25 // OptionalEmitter oe(this);
26 // PropOpEmitter poe(this,
27 // PropOpEmitter::Kind::Get,
28 // PropOpEmitter::ObjKind::Other);
29 // poe.prepareForObj();
30 // emit(obj);
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();
41 // emit(obj);
42 // oe.emitJumpShortCircuit();
43 // poe.emitDelete(atom_of_prop);
44 // oe.emitOptionalJumpTarget(JSOp:True);
46 // `obj?.[key];`
47 // OptionalEmitter oe(this);
48 // ElemOpEmitter eoe(this,
49 // ElemOpEmitter::Kind::Get,
50 // ElemOpEmitter::ObjKind::Other);
51 // eoe.prepareForObj();
52 // emit(obj);
53 // oe.emitJumpShortCircuit();
54 // eoe.prepareForKey();
55 // emit(key);
56 // eoe.emitGet();
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();
65 // emit(obj);
66 // oe.emitJumpShortCircuit();
67 // eoe.prepareForKey();
68 // emit(key);
69 // eoe.emitDelete();
70 // oe.emitOptionalJumpTarget(JSOp::True);
72 // `print?.(arg);`
73 // OptionalEmitter oe(this);
74 // CallOrNewEmitter cone(this, JSOp::Call,
75 // CallOrNewEmitter::ArgumentsKind::Other,
76 // ValueUsage::WantValue);
77 // cone.emitNameCallee(print);
78 // cone.emitThis();
79 // oe.emitShortCircuitForCall();
80 // cone.prepareForNonSpreadArguments();
81 // emit(arg);
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...
92 // cone.emitThis();
93 // oe.emitShortCircuitForCall();
94 // cone.prepareForNonSpreadArguments();
95 // emit(arg1);
96 // emit(arg2);
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...
107 // cone.emitThis();
108 // oe.emitShortCircuitForCall();
109 // cone.prepareForNonSpreadArguments();
110 // emit(arg);
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();
120 // emit(function);
121 // cone.emitThis();
122 // oe.emitShortCircuitForCall();
123 // cone.prepareForNonSpreadArguments();
124 // emit(arg);
125 // cone.emitEnd(1, offset_of_callee);
126 // oe.emitOptionalJumpTarget(JSOp::Undefined);
128 // `(a?b)();`
129 // OptionalEmitter oe(this);
130 // CallOrNewEmitter cone(this, JSOp::Call,
131 // CallOrNewEmitter::ArgumentsKind::Other,
132 // ValueUsage::WantValue);
133 // cone.prepareForFunctionCallee();
134 // emit(optionalChain);
135 // cone.emitThis();
136 // oe.emitOptionalJumpTarget(JSOp::Undefined,
137 // OptionalEmitter::Kind::Reference);
138 // oe.emitShortCircuitForCall();
139 // cone.prepareForNonSpreadArguments();
140 // emit(arg);
141 // cone.emitEnd(1, offset_of_callee);
142 // oe.emitOptionalJumpTarget(JSOp::Undefined);
144 class MOZ_RAII OptionalEmitter {
145 public:
146 OptionalEmitter(BytecodeEmitter* bce, int32_t initialDepth);
148 private:
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 // +-------+ | +--------------+ |
167 // +----->| |
168 // | | emitJumpShortCircuitForCall +---------------------+ v
169 // | +---------------------------->| ShortCircuitForCall |--->+
170 // | +---------------------+ |
171 // | |
172 // ---------------------------------------------------------------+
173 // |
174 // |
175 // +------------------------------------------------------------------+
176 // |
177 // | emitOptionalJumpTarget +---------+
178 // +----------------------->| JumpEnd |
179 // +---------+
181 #ifdef DEBUG
182 enum class State {
183 // The initial state.
184 Start,
186 // for shortcircuiting in most cases.
187 ShortCircuit,
189 // for shortcircuiting from references, which have two items on
190 // the stack. For example function calls.
191 ShortCircuitForCall,
193 // internally used, end of the jump code
194 JumpEnd
197 State state_ = State::Start;
198 #endif
200 public:
201 enum class Kind {
202 // Requires two values on the stack
203 Reference,
204 // Requires one value on the stack
205 Other
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 */
218 } /* namespace js */
220 #endif /* frontend_OptionalEmitter_h */