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_CForEmitter_h
8 #define frontend_CForEmitter_h
10 #include "mozilla/Attributes.h" // MOZ_STACK_CLASS
11 #include "mozilla/Maybe.h" // mozilla::Maybe
13 #include <stdint.h> // uint32_t
15 #include "frontend/BytecodeControlStructures.h" // LoopControl
16 #include "frontend/TDZCheckCache.h" // TDZCheckCache
21 struct BytecodeEmitter
;
24 // Class for emitting bytecode for c-style for block.
26 // Usage: (check for the return value is omitted for simplicity)
28 // `for (init; cond; update) body`
29 // CForEmitter cfor(this, headLexicalEmitterScopeForLet or nullptr);
30 // cfor.emitInit(Some(offset_of_init));
31 // emit(init); // without pushing value
32 // cfor.emitCond(Some(offset_of_cond));
34 // cfor.emitBody(CForEmitter::Cond::Present);
36 // cfor.emitUpdate(CForEmitter::Update::Present, Some(offset_of_update)));
38 // cfor.emitEnd(offset_of_for);
41 // CForEmitter cfor(this, nullptr);
42 // cfor.emitInit(Nothing());
43 // cfor.emitCond(Nothing());
44 // cfor.emitBody(CForEmitter::Cond::Missing);
46 // cfor.emitUpdate(CForEmitter::Update::Missing, Nothing());
47 // cfor.emitEnd(offset_of_for);
49 class MOZ_STACK_CLASS CForEmitter
{
50 // Basic structure of the bytecode (not complete).
52 // If `cond` is not empty:
57 // JSOp::JumpIfFalse break
64 // If `cond` is empty:
75 enum class Cond
{ Missing
, Present
};
76 enum class Update
{ Missing
, Present
};
79 BytecodeEmitter
* bce_
;
81 // Whether the c-style for loop has `cond` and `update`.
82 Cond cond_
= Cond::Missing
;
83 Update update_
= Update::Missing
;
85 mozilla::Maybe
<LoopControl
> loopInfo_
;
87 // The lexical scope to be freshened for each iteration.
88 // See the comment in `emitCond` for more details.
90 // ### Scope freshening
92 // Each iteration of a `for (let V...)` loop creates a fresh loop variable
93 // binding for V, even if the loop is a C-style `for(;;)` loop:
96 // for (let i = 0; i < 2; i++)
97 // funcs.push(function() { return i; });
98 // assertEq(funcs[0](), 0); // the two closures capture...
99 // assertEq(funcs[1](), 1); // ...two different `i` bindings
101 // This is implemented by "freshening" the implicit block -- changing the
102 // scope chain to a fresh clone of the instantaneous block object -- each
103 // iteration, just before evaluating the "update" in for(;;) loops.
105 // ECMAScript doesn't freshen in `for (const ...;;)`. Lack of freshening
106 // isn't directly observable in-language because `const`s can't be mutated,
107 // but it *can* be observed in the Debugger API.
108 const EmitterScope
* headLexicalEmitterScopeForLet_
;
110 mozilla::Maybe
<TDZCheckCache
> tdzCache_
;
113 // The state of this emitter.
115 // +-------+ emitInit +------+ emitCond +------+ emitBody +------+
116 // | Start |--------->| Init |--------->| Cond |--------->| Body |-+
117 // +-------+ +------+ +------+ +------+ |
119 // +-------------------------------------+
121 // | emitUpdate +--------+ emitEnd +-----+
122 // +----------->| Update |-------->| End |
123 // +--------+ +-----+
125 // The initial state.
128 // After calling emitInit.
131 // After calling emitCond.
134 // After calling emitBody.
137 // After calling emitUpdate.
140 // After calling emitEnd.
143 State state_
= State::Start
;
147 CForEmitter(BytecodeEmitter
* bce
,
148 const EmitterScope
* headLexicalEmitterScopeForLet
);
150 // Parameters are the offset in the source code for each character below:
152 // for ( x = 10 ; x < 20 ; x ++ ) { f(x); }
163 // Can be Nothing() if not available.
164 [[nodiscard
]] bool emitInit(const mozilla::Maybe
<uint32_t>& initPos
);
165 [[nodiscard
]] bool emitCond(const mozilla::Maybe
<uint32_t>& condPos
);
166 [[nodiscard
]] bool emitBody(Cond cond
);
167 [[nodiscard
]] bool emitUpdate(Update update
,
168 const mozilla::Maybe
<uint32_t>& updatePos
);
169 [[nodiscard
]] bool emitEnd(uint32_t forPos
);
172 } /* namespace frontend */
175 #endif /* frontend_CForEmitter_h */