V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
control-flow-builders.h
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 "src/interpreter/bytecode-array-builder.h"
9 
10 #include "src/ast/ast-source-ranges.h"
11 #include "src/interpreter/block-coverage-builder.h"
12 #include "src/interpreter/bytecode-label.h"
13 #include "src/zone/zone-containers.h"
14 
15 namespace v8 {
16 namespace internal {
17 namespace interpreter {
18 
19 class V8_EXPORT_PRIVATE ControlFlowBuilder {
20  public:
21  explicit ControlFlowBuilder(BytecodeArrayBuilder* builder)
22  : builder_(builder) {}
23  virtual ~ControlFlowBuilder() = default;
24 
25  protected:
26  BytecodeArrayBuilder* builder() const { return builder_; }
27 
28  private:
29  BytecodeArrayBuilder* builder_;
30 
31  DISALLOW_COPY_AND_ASSIGN(ControlFlowBuilder);
32 };
33 
34 class V8_EXPORT_PRIVATE BreakableControlFlowBuilder
35  : public ControlFlowBuilder {
36  public:
38  BlockCoverageBuilder* block_coverage_builder,
39  AstNode* node)
40  : ControlFlowBuilder(builder),
41  break_labels_(builder->zone()),
42  node_(node),
43  block_coverage_builder_(block_coverage_builder) {}
44  ~BreakableControlFlowBuilder() override;
45 
46  // This method is called when visiting break statements in the AST.
47  // Inserts a jump to an unbound label that is patched when the corresponding
48  // BindBreakTarget is called.
49  void Break() { EmitJump(&break_labels_); }
50  void BreakIfTrue(BytecodeArrayBuilder::ToBooleanMode mode) {
51  EmitJumpIfTrue(mode, &break_labels_);
52  }
53  void BreakIfFalse(BytecodeArrayBuilder::ToBooleanMode mode) {
54  EmitJumpIfFalse(mode, &break_labels_);
55  }
56  void BreakIfUndefined() { EmitJumpIfUndefined(&break_labels_); }
57  void BreakIfNull() { EmitJumpIfNull(&break_labels_); }
58 
59  BytecodeLabels* break_labels() { return &break_labels_; }
60 
61  void set_needs_continuation_counter() { needs_continuation_counter_ = true; }
62  bool needs_continuation_counter() const {
63  return needs_continuation_counter_;
64  }
65 
66  protected:
67  void EmitJump(BytecodeLabels* labels);
68  void EmitJumpIfTrue(BytecodeArrayBuilder::ToBooleanMode mode,
69  BytecodeLabels* labels);
70  void EmitJumpIfFalse(BytecodeArrayBuilder::ToBooleanMode mode,
71  BytecodeLabels* labels);
72  void EmitJumpIfUndefined(BytecodeLabels* labels);
73  void EmitJumpIfNull(BytecodeLabels* labels);
74 
75  // Called from the destructor to update sites that emit jumps for break.
76  void BindBreakTarget();
77 
78  // Unbound labels that identify jumps for break statements in the code.
79  BytecodeLabels break_labels_;
80 
81  // A continuation counter (for block coverage) is needed e.g. when
82  // encountering a break statement.
83  AstNode* node_;
84  bool needs_continuation_counter_ = false;
85  BlockCoverageBuilder* block_coverage_builder_;
86 };
87 
88 
89 // Class to track control flow for block statements (which can break in JS).
90 class V8_EXPORT_PRIVATE BlockBuilder final
92  public:
94  BlockCoverageBuilder* block_coverage_builder,
95  BreakableStatement* statement)
96  : BreakableControlFlowBuilder(builder, block_coverage_builder,
97  statement) {}
98 };
99 
100 
101 // A class to help with co-ordinating break and continue statements with
102 // their loop.
103 class V8_EXPORT_PRIVATE LoopBuilder final : public BreakableControlFlowBuilder {
104  public:
106  BlockCoverageBuilder* block_coverage_builder, AstNode* node)
107  : BreakableControlFlowBuilder(builder, block_coverage_builder, node),
108  continue_labels_(builder->zone()) {
109  if (block_coverage_builder_ != nullptr) {
110  set_needs_continuation_counter();
111  block_coverage_body_slot_ =
112  block_coverage_builder_->AllocateBlockCoverageSlot(
113  node, SourceRangeKind::kBody);
114  }
115  }
116  ~LoopBuilder() override;
117 
118  void LoopHeader();
119  void LoopBody();
120  void JumpToHeader(int loop_depth);
121  void BindContinueTarget();
122 
123  // This method is called when visiting continue statements in the AST.
124  // Inserts a jump to an unbound label that is patched when BindContinueTarget
125  // is called.
126  void Continue() { EmitJump(&continue_labels_); }
127  void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_labels_); }
128  void ContinueIfNull() { EmitJumpIfNull(&continue_labels_); }
129 
130  private:
131  BytecodeLabel loop_header_;
132 
133  // Unbound labels that identify jumps for continue statements in the code and
134  // jumps from checking the loop condition to the header for do-while loops.
135  BytecodeLabels continue_labels_;
136 
137  int block_coverage_body_slot_;
138 };
139 
140 
141 // A class to help with co-ordinating break statements with their switch.
142 class V8_EXPORT_PRIVATE SwitchBuilder final
143  : public BreakableControlFlowBuilder {
144  public:
146  BlockCoverageBuilder* block_coverage_builder,
147  SwitchStatement* statement, int number_of_cases)
148  : BreakableControlFlowBuilder(builder, block_coverage_builder, statement),
149  case_sites_(builder->zone()) {
150  case_sites_.resize(number_of_cases);
151  }
152  ~SwitchBuilder() override; // NOLINT (modernize-use-equals-default)
153 
154  // This method should be called by the SwitchBuilder owner when the case
155  // statement with |index| is emitted to update the case jump site.
156  void SetCaseTarget(int index, CaseClause* clause);
157 
158  // This method is called when visiting case comparison operation for |index|.
159  // Inserts a JumpIfTrue with ToBooleanMode |mode| to a unbound label that is
160  // patched when the corresponding SetCaseTarget is called.
161  void Case(BytecodeArrayBuilder::ToBooleanMode mode, int index) {
162  builder()->JumpIfTrue(mode, &case_sites_.at(index));
163  }
164 
165  // This method is called when all cases comparisons have been emitted if there
166  // is a default case statement. Inserts a Jump to a unbound label that is
167  // patched when the corresponding SetCaseTarget is called.
168  void DefaultAt(int index) { builder()->Jump(&case_sites_.at(index)); }
169 
170  private:
171  // Unbound labels that identify jumps for case statements in the code.
172  ZoneVector<BytecodeLabel> case_sites_;
173 };
174 
175 
176 // A class to help with co-ordinating control flow in try-catch statements.
177 class V8_EXPORT_PRIVATE TryCatchBuilder final : public ControlFlowBuilder {
178  public:
180  BlockCoverageBuilder* block_coverage_builder,
181  TryCatchStatement* statement,
182  HandlerTable::CatchPrediction catch_prediction)
183  : ControlFlowBuilder(builder),
184  handler_id_(builder->NewHandlerEntry()),
185  catch_prediction_(catch_prediction),
186  block_coverage_builder_(block_coverage_builder),
187  statement_(statement) {}
188 
189  ~TryCatchBuilder() override;
190 
191  void BeginTry(Register context);
192  void EndTry();
193  void EndCatch();
194 
195  private:
196  int handler_id_;
197  HandlerTable::CatchPrediction catch_prediction_;
198  BytecodeLabel handler_;
199  BytecodeLabel exit_;
200 
201  BlockCoverageBuilder* block_coverage_builder_;
202  TryCatchStatement* statement_;
203 };
204 
205 
206 // A class to help with co-ordinating control flow in try-finally statements.
207 class V8_EXPORT_PRIVATE TryFinallyBuilder final : public ControlFlowBuilder {
208  public:
210  BlockCoverageBuilder* block_coverage_builder,
211  TryFinallyStatement* statement,
212  HandlerTable::CatchPrediction catch_prediction)
213  : ControlFlowBuilder(builder),
214  handler_id_(builder->NewHandlerEntry()),
215  catch_prediction_(catch_prediction),
216  finalization_sites_(builder->zone()),
217  block_coverage_builder_(block_coverage_builder),
218  statement_(statement) {}
219 
220  ~TryFinallyBuilder() override;
221 
222  void BeginTry(Register context);
223  void LeaveTry();
224  void EndTry();
225  void BeginHandler();
226  void BeginFinally();
227  void EndFinally();
228 
229  private:
230  int handler_id_;
231  HandlerTable::CatchPrediction catch_prediction_;
232  BytecodeLabel handler_;
233 
234  // Unbound labels that identify jumps to the finally block in the code.
235  BytecodeLabels finalization_sites_;
236 
237  BlockCoverageBuilder* block_coverage_builder_;
238  TryFinallyStatement* statement_;
239 };
240 
241 class V8_EXPORT_PRIVATE ConditionalControlFlowBuilder final
242  : public ControlFlowBuilder {
243  public:
245  BlockCoverageBuilder* block_coverage_builder,
246  AstNode* node)
247  : ControlFlowBuilder(builder),
248  end_labels_(builder->zone()),
249  then_labels_(builder->zone()),
250  else_labels_(builder->zone()),
251  node_(node),
252  block_coverage_builder_(block_coverage_builder) {
253  DCHECK(node->IsIfStatement() || node->IsConditional());
254  if (block_coverage_builder != nullptr) {
255  block_coverage_then_slot_ =
256  block_coverage_builder->AllocateBlockCoverageSlot(
257  node, SourceRangeKind::kThen);
258  block_coverage_else_slot_ =
259  block_coverage_builder->AllocateBlockCoverageSlot(
260  node, SourceRangeKind::kElse);
261  }
262  }
263  ~ConditionalControlFlowBuilder() override;
264 
265  BytecodeLabels* then_labels() { return &then_labels_; }
266  BytecodeLabels* else_labels() { return &else_labels_; }
267 
268  void Then();
269  void Else();
270 
271  void JumpToEnd();
272 
273  private:
274  BytecodeLabels end_labels_;
275  BytecodeLabels then_labels_;
276  BytecodeLabels else_labels_;
277 
278  AstNode* node_;
279  int block_coverage_then_slot_;
280  int block_coverage_else_slot_;
281  BlockCoverageBuilder* block_coverage_builder_;
282 };
283 
284 } // namespace interpreter
285 } // namespace internal
286 } // namespace v8
287 
288 #endif // V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_
Definition: libplatform.h:13