Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / js / src / frontend / IfEmitter.h
blob80345fc21e8befd0b21587f1ca6fabd9bab17594
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_IfEmitter_h
8 #define frontend_IfEmitter_h
10 #include "mozilla/Attributes.h"
11 #include "mozilla/Maybe.h"
13 #include <stdint.h>
15 #include "frontend/JumpList.h"
16 #include "frontend/TDZCheckCache.h"
18 namespace js {
19 namespace frontend {
21 struct BytecodeEmitter;
23 class MOZ_STACK_CLASS BranchEmitterBase {
24 public:
25 // Whether the then-clause, the else-clause, or else-if condition may
26 // contain declaration or access to lexical variables, which means they
27 // should have their own TDZCheckCache. Basically TDZCheckCache should be
28 // created for each basic block, which then-clause, else-clause, and
29 // else-if condition are, but for internally used branches which are
30 // known not to touch lexical variables we can skip creating TDZCheckCache
31 // for them.
33 // See the comment for TDZCheckCache class for more details.
34 enum class LexicalKind {
35 // For syntactic branches (if, if-else, and conditional expression),
36 // which basically may contain declaration or accesses to lexical
37 // variables inside then-clause, else-clause, and else-if condition.
38 MayContainLexicalAccessInBranch,
40 // For internally used branches which don't touch lexical variables
41 // inside then-clause, else-clause, nor else-if condition.
42 NoLexicalAccessInBranch
45 protected:
46 BytecodeEmitter* bce_;
48 // Jump around the then clause, to the beginning of the else clause.
49 JumpList jumpAroundThen_;
51 // Jump around the else clause, to the end of the entire branch.
52 JumpList jumpsAroundElse_;
54 // The stack depth before emitting the then block.
55 // Used for restoring stack depth before emitting the else block.
56 // Also used for assertion to make sure then and else blocks pushed the
57 // same number of values.
58 int32_t thenDepth_ = 0;
60 enum class ConditionKind { Positive, Negative };
61 LexicalKind lexicalKind_;
63 mozilla::Maybe<TDZCheckCache> tdzCache_;
65 #ifdef DEBUG
66 // The number of values pushed in the then and else blocks.
67 int32_t pushed_ = 0;
68 bool calculatedPushed_ = false;
69 #endif
71 protected:
72 BranchEmitterBase(BytecodeEmitter* bce, LexicalKind lexicalKind);
74 [[nodiscard]] bool emitThenInternal(ConditionKind conditionKind);
75 void calculateOrCheckPushed();
76 [[nodiscard]] bool emitElseInternal();
77 [[nodiscard]] bool emitEndInternal();
79 public:
80 #ifdef DEBUG
81 // Returns the number of values pushed onto the value stack inside
82 // `then_block` and `else_block`.
83 // Can be used in assertion after emitting if-then-else.
84 int32_t pushed() const { return pushed_; }
86 // Returns the number of values popped onto the value stack inside
87 // `then_block` and `else_block`.
88 // Can be used in assertion after emitting if-then-else.
89 int32_t popped() const { return -pushed_; }
90 #endif
93 // Class for emitting bytecode for blocks like if-then-else.
95 // This class can be used to emit single if-then-else block, or cascading
96 // else-if blocks.
98 // Usage: (check for the return value is omitted for simplicity)
100 // `if (cond) then_block`
101 // IfEmitter ifThen(this);
102 // ifThen.emitIf(Some(offset_of_if));
103 // emit(cond);
104 // ifThen.emitThen();
105 // emit(then_block);
106 // ifThen.emitEnd();
108 // `if (!cond) then_block`
109 // IfEmitter ifThen(this);
110 // ifThen.emitIf(Some(offset_of_if));
111 // emit(cond);
112 // ifThen.emitThen(IfEmitter::ConditionKind::Negative);
113 // emit(then_block);
114 // ifThen.emitEnd();
116 // `if (cond) then_block else else_block`
117 // IfEmitter ifThenElse(this);
118 // ifThen.emitIf(Some(offset_of_if));
119 // emit(cond);
120 // ifThenElse.emitThenElse();
121 // emit(then_block);
122 // ifThenElse.emitElse();
123 // emit(else_block);
124 // ifThenElse.emitEnd();
126 // `if (c1) b1 else if (c2) b2 else if (c3) b3 else b4`
127 // IfEmitter ifThenElse(this);
128 // ifThen.emitIf(Some(offset_of_if));
129 // emit(c1);
130 // ifThenElse.emitThenElse();
131 // emit(b1);
132 // ifThenElse.emitElseIf(Some(offset_of_if));
133 // emit(c2);
134 // ifThenElse.emitThenElse();
135 // emit(b2);
136 // ifThenElse.emitElseIf(Some(offset_of_if));
137 // emit(c3);
138 // ifThenElse.emitThenElse();
139 // emit(b3);
140 // ifThenElse.emitElse();
141 // emit(b4);
142 // ifThenElse.emitEnd();
144 class MOZ_STACK_CLASS IfEmitter : public BranchEmitterBase {
145 public:
146 using ConditionKind = BranchEmitterBase::ConditionKind;
148 protected:
149 #ifdef DEBUG
150 // The state of this emitter.
152 // +-------+ emitIf +----+
153 // | Start |------->| If |-+
154 // +-------+ +----+ |
155 // |
156 // +--------------------+
157 // |
158 // v emitThen +------+ emitEnd +-----+
159 // +->+--------->| Then |---------------------------->+-------->| End |
160 // ^ | +------+ ^ +-----+
161 // | | |
162 // | | |
163 // | | |
164 // | | emitThenElse +----------+ emitElse +------+ |
165 // | +------------->| ThenElse |-+--------->| Else |-+
166 // | +----------+ | +------+
167 // | |
168 // | | emitElseIf +--------+
169 // | +----------->| ElseIf |-+
170 // | +--------+ |
171 // | |
172 // +------------------------------------------------------+
173 enum class State {
174 // The initial state.
175 Start,
177 // After calling emitIf.
180 // After calling emitThen.
181 Then,
183 // After calling emitThenElse.
184 ThenElse,
186 // After calling emitElse.
187 Else,
189 // After calling emitElseIf.
190 ElseIf,
192 // After calling emitEnd.
195 State state_ = State::Start;
196 #endif
198 protected:
199 // For InternalIfEmitter.
200 IfEmitter(BytecodeEmitter* bce, LexicalKind lexicalKind);
202 public:
203 explicit IfEmitter(BytecodeEmitter* bce);
205 // `ifPos` is the offset in the source code for the character below:
207 // if ( cond ) { ... } else if ( cond2 ) { ... }
208 // ^ ^
209 // | |
210 // | ifPos for emitElseIf
211 // |
212 // ifPos for emitIf
214 // Can be Nothing() if not available.
215 [[nodiscard]] bool emitIf(const mozilla::Maybe<uint32_t>& ifPos);
217 [[nodiscard]] bool emitThen(
218 ConditionKind conditionKind = ConditionKind::Positive);
219 [[nodiscard]] bool emitThenElse(
220 ConditionKind conditionKind = ConditionKind::Positive);
222 [[nodiscard]] bool emitElseIf(const mozilla::Maybe<uint32_t>& ifPos);
223 [[nodiscard]] bool emitElse();
225 [[nodiscard]] bool emitEnd();
228 // Class for emitting bytecode for blocks like if-then-else which doesn't touch
229 // lexical variables.
231 // See the comments above NoLexicalAccessInBranch for more details when to use
232 // this instead of IfEmitter.
233 // Compared to IfEmitter, this class doesn't have emitIf method, given that
234 // it doesn't have syntactic `if`, and also the `cond` value can be already
235 // on the stack.
237 // Usage: (check for the return value is omitted for simplicity)
239 // `if (cond) then_block else else_block` (effectively)
240 // emit(cond);
241 // InternalIfEmitter ifThenElse(this);
242 // ifThenElse.emitThenElse();
243 // emit(then_block);
244 // ifThenElse.emitElse();
245 // emit(else_block);
246 // ifThenElse.emitEnd();
248 class MOZ_STACK_CLASS InternalIfEmitter : public IfEmitter {
249 public:
250 explicit InternalIfEmitter(
251 BytecodeEmitter* bce,
252 LexicalKind lexicalKind =
253 BranchEmitterBase::LexicalKind::NoLexicalAccessInBranch);
256 // Class for emitting bytecode for conditional expression.
258 // Usage: (check for the return value is omitted for simplicity)
260 // `cond ? then_expr : else_expr`
261 // CondEmitter condElse(this);
262 // condElse.emitCond();
263 // emit(cond);
264 // condElse.emitThenElse();
265 // emit(then_expr);
266 // condElse.emitElse();
267 // emit(else_expr);
268 // condElse.emitEnd();
270 class MOZ_STACK_CLASS CondEmitter : public BranchEmitterBase {
271 #ifdef DEBUG
272 // The state of this emitter.
274 // +-------+ emitCond +------+ emitThenElse +----------+
275 // | Start |--------->| Cond |------------->| ThenElse |-+
276 // +-------+ +------+ +----------+ |
277 // |
278 // +-----------------+
279 // |
280 // | emitElse +------+ emitEnd +-----+
281 // +--------->| Else |-------->| End |
282 // +------+ +-----+
283 enum class State {
284 // The initial state.
285 Start,
287 // After calling emitCond.
288 Cond,
290 // After calling emitThenElse.
291 ThenElse,
293 // After calling emitElse.
294 Else,
296 // After calling emitEnd.
299 State state_ = State::Start;
300 #endif
302 public:
303 explicit CondEmitter(BytecodeEmitter* bce);
305 [[nodiscard]] bool emitCond();
306 [[nodiscard]] bool emitThenElse(
307 ConditionKind conditionKind = ConditionKind::Positive);
308 [[nodiscard]] bool emitElse();
309 [[nodiscard]] bool emitEnd();
312 } /* namespace frontend */
313 } /* namespace js */
315 #endif /* frontend_IfEmitter_h */