• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 BASE_EMBEDDED {
20  public:
ControlFlowBuilder(BytecodeArrayBuilder * builder)21   explicit ControlFlowBuilder(BytecodeArrayBuilder* builder)
22       : builder_(builder) {}
~ControlFlowBuilder()23   virtual ~ControlFlowBuilder() {}
24 
25  protected:
builder()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:
BreakableControlFlowBuilder(BytecodeArrayBuilder * builder,BlockCoverageBuilder * block_coverage_builder,AstNode * node)37   BreakableControlFlowBuilder(BytecodeArrayBuilder* builder,
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   virtual ~BreakableControlFlowBuilder();
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.
Break()49   void Break() { EmitJump(&break_labels_); }
BreakIfTrue(BytecodeArrayBuilder::ToBooleanMode mode)50   void BreakIfTrue(BytecodeArrayBuilder::ToBooleanMode mode) {
51     EmitJumpIfTrue(mode, &break_labels_);
52   }
BreakIfFalse(BytecodeArrayBuilder::ToBooleanMode mode)53   void BreakIfFalse(BytecodeArrayBuilder::ToBooleanMode mode) {
54     EmitJumpIfFalse(mode, &break_labels_);
55   }
BreakIfUndefined()56   void BreakIfUndefined() { EmitJumpIfUndefined(&break_labels_); }
BreakIfNull()57   void BreakIfNull() { EmitJumpIfNull(&break_labels_); }
58 
break_labels()59   BytecodeLabels* break_labels() { return &break_labels_; }
60 
set_needs_continuation_counter()61   void set_needs_continuation_counter() { needs_continuation_counter_ = true; }
needs_continuation_counter()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
91     : public BreakableControlFlowBuilder {
92  public:
BlockBuilder(BytecodeArrayBuilder * builder,BlockCoverageBuilder * block_coverage_builder,BreakableStatement * statement)93   BlockBuilder(BytecodeArrayBuilder* builder,
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:
LoopBuilder(BytecodeArrayBuilder * builder,BlockCoverageBuilder * block_coverage_builder,AstNode * node)105   LoopBuilder(BytecodeArrayBuilder* builder,
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();
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.
Continue()126   void Continue() { EmitJump(&continue_labels_); }
ContinueIfUndefined()127   void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_labels_); }
ContinueIfNull()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:
SwitchBuilder(BytecodeArrayBuilder * builder,BlockCoverageBuilder * block_coverage_builder,SwitchStatement * statement,int number_of_cases)145   SwitchBuilder(BytecodeArrayBuilder* builder,
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();
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.
Case(BytecodeArrayBuilder::ToBooleanMode mode,int index)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.
DefaultAt(int index)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:
TryCatchBuilder(BytecodeArrayBuilder * builder,BlockCoverageBuilder * block_coverage_builder,TryCatchStatement * statement,HandlerTable::CatchPrediction catch_prediction)179   TryCatchBuilder(BytecodeArrayBuilder* builder,
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();
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:
TryFinallyBuilder(BytecodeArrayBuilder * builder,BlockCoverageBuilder * block_coverage_builder,TryFinallyStatement * statement,HandlerTable::CatchPrediction catch_prediction)209   TryFinallyBuilder(BytecodeArrayBuilder* builder,
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();
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:
ConditionalControlFlowBuilder(BytecodeArrayBuilder * builder,BlockCoverageBuilder * block_coverage_builder,AstNode * node)244   ConditionalControlFlowBuilder(BytecodeArrayBuilder* builder,
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();
264 
then_labels()265   BytecodeLabels* then_labels() { return &then_labels_; }
else_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_
289