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"
15 #include "frontend/JumpList.h"
16 #include "frontend/TDZCheckCache.h"
21 struct BytecodeEmitter
;
23 class MOZ_STACK_CLASS BranchEmitterBase
{
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
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
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_
;
66 // The number of values pushed in the then and else blocks.
68 bool calculatedPushed_
= false;
72 BranchEmitterBase(BytecodeEmitter
* bce
, LexicalKind lexicalKind
);
74 [[nodiscard
]] bool emitThenInternal(ConditionKind conditionKind
);
75 void calculateOrCheckPushed();
76 [[nodiscard
]] bool emitElseInternal();
77 [[nodiscard
]] bool emitEndInternal();
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_
; }
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
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));
104 // ifThen.emitThen();
108 // `if (!cond) then_block`
109 // IfEmitter ifThen(this);
110 // ifThen.emitIf(Some(offset_of_if));
112 // ifThen.emitThen(IfEmitter::ConditionKind::Negative);
116 // `if (cond) then_block else else_block`
117 // IfEmitter ifThenElse(this);
118 // ifThen.emitIf(Some(offset_of_if));
120 // ifThenElse.emitThenElse();
122 // ifThenElse.emitElse();
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));
130 // ifThenElse.emitThenElse();
132 // ifThenElse.emitElseIf(Some(offset_of_if));
134 // ifThenElse.emitThenElse();
136 // ifThenElse.emitElseIf(Some(offset_of_if));
138 // ifThenElse.emitThenElse();
140 // ifThenElse.emitElse();
142 // ifThenElse.emitEnd();
144 class MOZ_STACK_CLASS IfEmitter
: public BranchEmitterBase
{
146 using ConditionKind
= BranchEmitterBase::ConditionKind
;
150 // The state of this emitter.
152 // +-------+ emitIf +----+
153 // | Start |------->| If |-+
154 // +-------+ +----+ |
156 // +--------------------+
158 // v emitThen +------+ emitEnd +-----+
159 // +->+--------->| Then |---------------------------->+-------->| End |
160 // ^ | +------+ ^ +-----+
164 // | | emitThenElse +----------+ emitElse +------+ |
165 // | +------------->| ThenElse |-+--------->| Else |-+
166 // | +----------+ | +------+
168 // | | emitElseIf +--------+
169 // | +----------->| ElseIf |-+
172 // +------------------------------------------------------+
174 // The initial state.
177 // After calling emitIf.
180 // After calling emitThen.
183 // After calling emitThenElse.
186 // After calling emitElse.
189 // After calling emitElseIf.
192 // After calling emitEnd.
195 State state_
= State::Start
;
199 // For InternalIfEmitter.
200 IfEmitter(BytecodeEmitter
* bce
, LexicalKind lexicalKind
);
203 explicit IfEmitter(BytecodeEmitter
* bce
);
205 // `ifPos` is the offset in the source code for the character below:
207 // if ( cond ) { ... } else if ( cond2 ) { ... }
210 // | ifPos for emitElseIf
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
237 // Usage: (check for the return value is omitted for simplicity)
239 // `if (cond) then_block else else_block` (effectively)
241 // InternalIfEmitter ifThenElse(this);
242 // ifThenElse.emitThenElse();
244 // ifThenElse.emitElse();
246 // ifThenElse.emitEnd();
248 class MOZ_STACK_CLASS InternalIfEmitter
: public IfEmitter
{
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();
264 // condElse.emitThenElse();
266 // condElse.emitElse();
268 // condElse.emitEnd();
270 class MOZ_STACK_CLASS CondEmitter
: public BranchEmitterBase
{
272 // The state of this emitter.
274 // +-------+ emitCond +------+ emitThenElse +----------+
275 // | Start |--------->| Cond |------------->| ThenElse |-+
276 // +-------+ +------+ +----------+ |
278 // +-----------------+
280 // | emitElse +------+ emitEnd +-----+
281 // +--------->| Else |-------->| End |
284 // The initial state.
287 // After calling emitCond.
290 // After calling emitThenElse.
293 // After calling emitElse.
296 // After calling emitEnd.
299 State state_
= State::Start
;
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 */
315 #endif /* frontend_IfEmitter_h */