v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
control-flow-builders.h
Go to the documentation of this file.
1// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_
6#define V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_
7
8#include <map>
9
17
18namespace v8 {
19namespace internal {
20namespace interpreter {
21
23 public:
25 : builder_(builder) {}
28 virtual ~ControlFlowBuilder() = default;
29
30 protected:
32
33 private:
35};
36
38 : public ControlFlowBuilder {
39 public:
41 BlockCoverageBuilder* block_coverage_builder,
42 AstNode* node)
43 : ControlFlowBuilder(builder),
44 break_labels_(builder->zone()),
45 node_(node),
46 block_coverage_builder_(block_coverage_builder) {}
48
49 // This method is called when visiting break statements in the AST.
50 // Inserts a jump to an unbound label that is patched when the corresponding
51 // BindBreakTarget is called.
52 void Break() { EmitJump(&break_labels_); }
54 EmitJumpIfTrue(mode, &break_labels_);
55 }
56 void BreakIfForInDone(Register index, Register cache_length) {
57 EmitJumpIfForInDone(&break_labels_, index, cache_length);
58 }
59
60 BytecodeLabels* break_labels() { return &break_labels_; }
61
62 protected:
63 void EmitJump(BytecodeLabels* labels);
64 void EmitJumpIfTrue(BytecodeArrayBuilder::ToBooleanMode mode,
65 BytecodeLabels* labels);
66 void EmitJumpIfFalse(BytecodeArrayBuilder::ToBooleanMode mode,
67 BytecodeLabels* labels);
68 void EmitJumpIfUndefined(BytecodeLabels* labels);
69 void EmitJumpIfForInDone(BytecodeLabels* labels, Register index,
70 Register cache_length);
71
72 // Called from the destructor to update sites that emit jumps for break.
73 void BindBreakTarget();
74
75 // Unbound labels that identify jumps for break statements in the code.
77
78 // A continuation counter (for block coverage) is needed e.g. when
79 // encountering a break statement.
82};
83
84// Class to track control flow for block statements (which can break in JS).
87 public:
89 BlockCoverageBuilder* block_coverage_builder,
91 : BreakableControlFlowBuilder(builder, block_coverage_builder,
92 statement) {}
93};
94
95// A class to help with co-ordinating break and continue statements with
96// their loop.
98 public:
100 BlockCoverageBuilder* block_coverage_builder, AstNode* node,
101 FeedbackVectorSpec* feedback_vector_spec)
102 : BreakableControlFlowBuilder(builder, block_coverage_builder, node),
103 continue_labels_(builder->zone()),
104 end_labels_(builder->zone()),
105 feedback_vector_spec_(feedback_vector_spec) {
106 if (block_coverage_builder_ != nullptr) {
107 block_coverage_body_slot_ =
108 block_coverage_builder_->AllocateBlockCoverageSlot(
109 node, SourceRangeKind::kBody);
110 }
111 source_position_ = node ? node->position() : kNoSourcePosition;
112 }
113 ~LoopBuilder() override;
114
115 void LoopHeader();
116 void LoopBody();
117 void JumpToHeader(int loop_depth, LoopBuilder* const parent_loop);
118 void BindContinueTarget();
119
120 // This method is called when visiting continue statements in the AST.
121 // Inserts a jump to an unbound label that is patched when BindContinueTarget
122 // is called.
123 void Continue() { EmitJump(&continue_labels_); }
124 void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_labels_); }
125
126 private:
127 // Emit a Jump to our parent_loop_'s end label which could be a JumpLoop or,
128 // iff they are a nested inner loop with the same loop header bytecode offset
129 // as their parent's, a Jump to its parent's end label.
130 void JumpToLoopEnd() { EmitJump(&end_labels_); }
131 void BindLoopEnd();
132
134
135 // Unbound labels that identify jumps for continue statements in the code and
136 // jumps from checking the loop condition to the header for do-while loops.
138
139 // Unbound labels that identify jumps for nested inner loops which share the
140 // same header offset as this loop. Said inner loops will Jump to our end
141 // label, which could be a JumpLoop or, iff we are a nested inner loop too, a
142 // Jump to our parent's end label.
144
148};
149
150// A class to help with co-ordinating break statements with their switch.
153 public:
155 BlockCoverageBuilder* block_coverage_builder,
156 SwitchStatement* statement, int number_of_cases,
157 BytecodeJumpTable* jump_table)
158 : BreakableControlFlowBuilder(builder, block_coverage_builder, statement),
159 case_sites_(builder->zone()),
160 default_(builder->zone()),
161 fall_through_(builder->zone()),
162 jump_table_(jump_table) {
163 case_sites_.resize(number_of_cases);
164 }
165
166 ~SwitchBuilder() override;
167
168 void BindCaseTargetForJumpTable(int case_value, CaseClause* clause);
169
170 void BindCaseTargetForCompareJump(int index, CaseClause* clause);
171
172 // This method is called when visiting case comparison operation for |index|.
173 // Inserts a JumpIfTrue with ToBooleanMode |mode| to a unbound label that is
174 // patched when the corresponding SetCaseTarget is called.
175 void JumpToCaseIfTrue(BytecodeArrayBuilder::ToBooleanMode mode, int index);
176
177 void EmitJumpTableIfExists(int min_case, int max_case,
178 std::map<int, CaseClause*>& covered_cases);
179
180 void BindDefault(CaseClause* clause);
181
182 void JumpToDefault();
183
184 void JumpToFallThroughIfFalse();
185
186 private:
187 // Unbound labels that identify jumps for case statements in the code.
192
194 if (block_coverage_builder_ && clause != nullptr) {
195 block_coverage_builder_->IncrementBlockCounter(clause,
196 SourceRangeKind::kBody);
197 }
198 }
199};
200
201// A class to help with co-ordinating control flow in try-catch statements.
203 public:
205 BlockCoverageBuilder* block_coverage_builder,
207 HandlerTable::CatchPrediction catch_prediction)
208 : ControlFlowBuilder(builder),
209 handler_id_(builder->NewHandlerEntry()),
210 catch_prediction_(catch_prediction),
211 block_coverage_builder_(block_coverage_builder),
212 statement_(statement) {}
213
214 ~TryCatchBuilder() override;
215
216 void BeginTry(Register context);
217 void EndTry();
218 void EndCatch();
219
220 private:
224
227};
228
229// A class to help with co-ordinating control flow in try-finally statements.
231 public:
233 BlockCoverageBuilder* block_coverage_builder,
235 HandlerTable::CatchPrediction catch_prediction)
236 : ControlFlowBuilder(builder),
237 handler_id_(builder->NewHandlerEntry()),
238 catch_prediction_(catch_prediction),
239 finalization_sites_(builder->zone()),
240 block_coverage_builder_(block_coverage_builder),
241 statement_(statement) {}
242
243 ~TryFinallyBuilder() override;
244
245 void BeginTry(Register context);
246 void LeaveTry();
247 void EndTry();
248 void BeginHandler();
249 void BeginFinally();
250 void EndFinally();
251
252 private:
256
257 // Unbound labels that identify jumps to the finally block in the code.
259
262};
263
265 : public ControlFlowBuilder {
266 public:
268 BytecodeArrayBuilder* builder,
269 BlockCoverageBuilder* block_coverage_builder, AstNode* node,
270 size_t then_count)
271 : ControlFlowBuilder(builder),
272 end_labels_(builder->zone()),
273 then_count_(then_count),
274 then_labels_list_(static_cast<int>(then_count_), builder->zone()),
275 else_labels_list_(static_cast<int>(then_count_), builder->zone()),
276 block_coverage_then_slots_(then_count_, builder->zone()),
277 block_coverage_else_slots_(then_count_, builder->zone()),
278 block_coverage_builder_(block_coverage_builder) {
279 DCHECK(node->IsConditionalChain());
280
281 Zone* zone = builder->zone();
282 for (size_t i = 0; i < then_count_; ++i) {
283 then_labels_list_.Add(zone->New<BytecodeLabels>(zone), zone);
284 else_labels_list_.Add(zone->New<BytecodeLabels>(zone), zone);
285 }
286
287 if (block_coverage_builder != nullptr) {
288 ConditionalChain* conditional_chain = node->AsConditionalChain();
289 block_coverage_then_slots_.resize(then_count_);
290 block_coverage_else_slots_.resize(then_count_);
291 for (size_t i = 0; i < then_count_; ++i) {
292 block_coverage_then_slots_[i] =
293 block_coverage_builder->AllocateConditionalChainBlockCoverageSlot(
294 conditional_chain, SourceRangeKind::kThen, i);
295 block_coverage_else_slots_[i] =
296 block_coverage_builder->AllocateConditionalChainBlockCoverageSlot(
297 conditional_chain, SourceRangeKind::kElse, i);
298 }
299 }
300 }
302
304 DCHECK_LT(index, then_count_);
305 return then_labels_list_[static_cast<int>(index)];
306 }
307
309 DCHECK_LT(index, then_count_);
310 return else_labels_list_[static_cast<int>(index)];
311 }
312
313 int block_coverage_then_slot_at(size_t index) const {
314 DCHECK_LT(index, then_count_);
315 return block_coverage_then_slots_[index];
316 }
317
318 int block_coverage_else_slot_at(size_t index) const {
319 DCHECK_LT(index, then_count_);
320 return block_coverage_else_slots_[index];
321 }
322
323 void ThenAt(size_t index);
324 void ElseAt(size_t index);
325
326 void JumpToEnd();
327
328 private:
333
337};
338
340 : public ControlFlowBuilder {
341 public:
343 BlockCoverageBuilder* block_coverage_builder,
344 AstNode* node)
345 : ControlFlowBuilder(builder),
346 end_labels_(builder->zone()),
347 then_labels_(builder->zone()),
348 else_labels_(builder->zone()),
349 node_(node),
350 block_coverage_builder_(block_coverage_builder) {
351 DCHECK(node->IsIfStatement() || node->IsConditional());
352 if (block_coverage_builder != nullptr) {
353 block_coverage_then_slot_ =
354 block_coverage_builder->AllocateBlockCoverageSlot(
355 node, SourceRangeKind::kThen);
356 block_coverage_else_slot_ =
357 block_coverage_builder->AllocateBlockCoverageSlot(
358 node, SourceRangeKind::kElse);
359 }
360 }
362
363 BytecodeLabels* then_labels() { return &then_labels_; }
364 BytecodeLabels* else_labels() { return &else_labels_; }
365
366 void Then();
367 void Else();
368
369 void JumpToEnd();
370
371 private:
375
380};
381
382} // namespace interpreter
383} // namespace internal
384} // namespace v8
385
386#endif // V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_
std::map< int, CaseClause * > covered_cases
T * New(Args &&... args)
Definition zone.h:114
BlockBuilder(BytecodeArrayBuilder *builder, BlockCoverageBuilder *block_coverage_builder, BreakableStatement *statement)
int AllocateConditionalChainBlockCoverageSlot(ConditionalChain *node, SourceRangeKind kind, size_t index)
int AllocateBlockCoverageSlot(ZoneObject *node, SourceRangeKind kind)
BreakableControlFlowBuilder(BytecodeArrayBuilder *builder, BlockCoverageBuilder *block_coverage_builder, AstNode *node)
void BreakIfTrue(BytecodeArrayBuilder::ToBooleanMode mode)
void BreakIfForInDone(Register index, Register cache_length)
ConditionalChainControlFlowBuilder(BytecodeArrayBuilder *builder, BlockCoverageBuilder *block_coverage_builder, AstNode *node, size_t then_count)
ConditionalControlFlowBuilder(BytecodeArrayBuilder *builder, BlockCoverageBuilder *block_coverage_builder, AstNode *node)
ControlFlowBuilder & operator=(const ControlFlowBuilder &)=delete
ControlFlowBuilder(const ControlFlowBuilder &)=delete
LoopBuilder(BytecodeArrayBuilder *builder, BlockCoverageBuilder *block_coverage_builder, AstNode *node, FeedbackVectorSpec *feedback_vector_spec)
SwitchBuilder(BytecodeArrayBuilder *builder, BlockCoverageBuilder *block_coverage_builder, SwitchStatement *statement, int number_of_cases, BytecodeJumpTable *jump_table)
TryCatchBuilder(BytecodeArrayBuilder *builder, BlockCoverageBuilder *block_coverage_builder, TryCatchStatement *statement, HandlerTable::CatchPrediction catch_prediction)
TryFinallyBuilder(BytecodeArrayBuilder *builder, BlockCoverageBuilder *block_coverage_builder, TryFinallyStatement *statement, HandlerTable::CatchPrediction catch_prediction)
OptionalOpIndex index
constexpr int kNoSourcePosition
Definition globals.h:850
RegExpBuilder builder_
Node * node_
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define V8_EXPORT_PRIVATE
Definition macros.h:460
Symbol statement