Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / js / src / frontend / CForEmitter.h
blob231dd318be53a1cb1b386a4a163840aedfcc7e68
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
18 namespace js {
19 namespace frontend {
21 struct BytecodeEmitter;
22 class EmitterScope;
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));
33 // emit(cond);
34 // cfor.emitBody(CForEmitter::Cond::Present);
35 // emit(body);
36 // cfor.emitUpdate(CForEmitter::Update::Present, Some(offset_of_update)));
37 // emit(update);
38 // cfor.emitEnd(offset_of_for);
40 // `for (;;) body`
41 // CForEmitter cfor(this, nullptr);
42 // cfor.emitInit(Nothing());
43 // cfor.emitCond(Nothing());
44 // cfor.emitBody(CForEmitter::Cond::Missing);
45 // emit(body);
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:
53 // {init}
54 // loop:
55 // JSOp::LoopHead
56 // {cond}
57 // JSOp::JumpIfFalse break
58 // {body}
59 // continue:
60 // {update}
61 // JSOp::Goto loop
62 // break:
64 // If `cond` is empty:
65 // {init}
66 // loop:
67 // JSOp::LoopHead
68 // {body}
69 // continue:
70 // {update}
71 // JSOp::Goto loop
72 // break:
74 public:
75 enum class Cond { Missing, Present };
76 enum class Update { Missing, Present };
78 private:
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:
95 // var funcs = [];
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_;
112 #ifdef DEBUG
113 // The state of this emitter.
115 // +-------+ emitInit +------+ emitCond +------+ emitBody +------+
116 // | Start |--------->| Init |--------->| Cond |--------->| Body |-+
117 // +-------+ +------+ +------+ +------+ |
118 // |
119 // +-------------------------------------+
120 // |
121 // | emitUpdate +--------+ emitEnd +-----+
122 // +----------->| Update |-------->| End |
123 // +--------+ +-----+
124 enum class State {
125 // The initial state.
126 Start,
128 // After calling emitInit.
129 Init,
131 // After calling emitCond.
132 Cond,
134 // After calling emitBody.
135 Body,
137 // After calling emitUpdate.
138 Update,
140 // After calling emitEnd.
143 State state_ = State::Start;
144 #endif
146 public:
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); }
153 // ^ ^ ^ ^
154 // | | | |
155 // | | | updatePos
156 // | | |
157 // | | condPos
158 // | |
159 // | initPos
160 // |
161 // forPos
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 */
173 } /* namespace js */
175 #endif /* frontend_CForEmitter_h */