• 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/interpreter/bytecode-label.h"
11 #include "src/zone/zone-containers.h"
12 
13 namespace v8 {
14 namespace internal {
15 namespace interpreter {
16 
17 class V8_EXPORT_PRIVATE ControlFlowBuilder BASE_EMBEDDED {
18  public:
ControlFlowBuilder(BytecodeArrayBuilder * builder)19   explicit ControlFlowBuilder(BytecodeArrayBuilder* builder)
20       : builder_(builder) {}
~ControlFlowBuilder()21   virtual ~ControlFlowBuilder() {}
22 
23  protected:
builder()24   BytecodeArrayBuilder* builder() const { return builder_; }
25 
26  private:
27   BytecodeArrayBuilder* builder_;
28 
29   DISALLOW_COPY_AND_ASSIGN(ControlFlowBuilder);
30 };
31 
32 class V8_EXPORT_PRIVATE BreakableControlFlowBuilder
33     : public ControlFlowBuilder {
34  public:
BreakableControlFlowBuilder(BytecodeArrayBuilder * builder)35   explicit BreakableControlFlowBuilder(BytecodeArrayBuilder* builder)
36       : ControlFlowBuilder(builder), break_labels_(builder->zone()) {}
37   virtual ~BreakableControlFlowBuilder();
38 
39   // This method should be called by the control flow owner before
40   // destruction to update sites that emit jumps for break.
41   void BindBreakTarget();
42 
43   // This method is called when visiting break statements in the AST.
44   // Inserts a jump to an unbound label that is patched when the corresponding
45   // BindBreakTarget is called.
Break()46   void Break() { EmitJump(&break_labels_); }
BreakIfTrue()47   void BreakIfTrue() { EmitJumpIfTrue(&break_labels_); }
BreakIfFalse()48   void BreakIfFalse() { EmitJumpIfFalse(&break_labels_); }
BreakIfUndefined()49   void BreakIfUndefined() { EmitJumpIfUndefined(&break_labels_); }
BreakIfNull()50   void BreakIfNull() { EmitJumpIfNull(&break_labels_); }
51 
break_labels()52   BytecodeLabels* break_labels() { return &break_labels_; }
53 
54  protected:
55   void EmitJump(BytecodeLabels* labels);
56   void EmitJumpIfTrue(BytecodeLabels* labels);
57   void EmitJumpIfFalse(BytecodeLabels* labels);
58   void EmitJumpIfUndefined(BytecodeLabels* labels);
59   void EmitJumpIfNull(BytecodeLabels* labels);
60 
61   // Unbound labels that identify jumps for break statements in the code.
62   BytecodeLabels break_labels_;
63 };
64 
65 
66 // Class to track control flow for block statements (which can break in JS).
67 class V8_EXPORT_PRIVATE BlockBuilder final
68     : public BreakableControlFlowBuilder {
69  public:
BlockBuilder(BytecodeArrayBuilder * builder)70   explicit BlockBuilder(BytecodeArrayBuilder* builder)
71       : BreakableControlFlowBuilder(builder) {}
72 
73   void EndBlock();
74 
75  private:
76   BytecodeLabel block_end_;
77 };
78 
79 
80 // A class to help with co-ordinating break and continue statements with
81 // their loop.
82 class V8_EXPORT_PRIVATE LoopBuilder final : public BreakableControlFlowBuilder {
83  public:
LoopBuilder(BytecodeArrayBuilder * builder)84   explicit LoopBuilder(BytecodeArrayBuilder* builder)
85       : BreakableControlFlowBuilder(builder),
86         continue_labels_(builder->zone()),
87         header_labels_(builder->zone()) {}
88   ~LoopBuilder();
89 
90   void LoopHeader(ZoneVector<BytecodeLabel>* additional_labels = nullptr);
91   void JumpToHeader(int loop_depth);
92   void BindContinueTarget();
93   void EndLoop();
94 
95   // This method is called when visiting continue statements in the AST.
96   // Inserts a jump to an unbound label that is patched when BindContinueTarget
97   // is called.
Continue()98   void Continue() { EmitJump(&continue_labels_); }
ContinueIfTrue()99   void ContinueIfTrue() { EmitJumpIfTrue(&continue_labels_); }
ContinueIfUndefined()100   void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_labels_); }
ContinueIfNull()101   void ContinueIfNull() { EmitJumpIfNull(&continue_labels_); }
102 
103  private:
104   BytecodeLabel loop_header_;
105 
106   // Unbound labels that identify jumps for continue statements in the code and
107   // jumps from checking the loop condition to the header for do-while loops.
108   BytecodeLabels continue_labels_;
109   BytecodeLabels header_labels_;
110 };
111 
112 
113 // A class to help with co-ordinating break statements with their switch.
114 class V8_EXPORT_PRIVATE SwitchBuilder final
115     : public BreakableControlFlowBuilder {
116  public:
SwitchBuilder(BytecodeArrayBuilder * builder,int number_of_cases)117   explicit SwitchBuilder(BytecodeArrayBuilder* builder, int number_of_cases)
118       : BreakableControlFlowBuilder(builder),
119         case_sites_(builder->zone()) {
120     case_sites_.resize(number_of_cases);
121   }
122   ~SwitchBuilder();
123 
124   // This method should be called by the SwitchBuilder owner when the case
125   // statement with |index| is emitted to update the case jump site.
126   void SetCaseTarget(int index);
127 
128   // This method is called when visiting case comparison operation for |index|.
129   // Inserts a JumpIfTrue to a unbound label that is patched when the
130   // corresponding SetCaseTarget is called.
Case(int index)131   void Case(int index) { builder()->JumpIfTrue(&case_sites_.at(index)); }
132 
133   // This method is called when all cases comparisons have been emitted if there
134   // is a default case statement. Inserts a Jump to a unbound label that is
135   // patched when the corresponding SetCaseTarget is called.
DefaultAt(int index)136   void DefaultAt(int index) { builder()->Jump(&case_sites_.at(index)); }
137 
138  private:
139   // Unbound labels that identify jumps for case statements in the code.
140   ZoneVector<BytecodeLabel> case_sites_;
141 };
142 
143 
144 // A class to help with co-ordinating control flow in try-catch statements.
145 class V8_EXPORT_PRIVATE TryCatchBuilder final : public ControlFlowBuilder {
146  public:
TryCatchBuilder(BytecodeArrayBuilder * builder,HandlerTable::CatchPrediction catch_prediction)147   explicit TryCatchBuilder(BytecodeArrayBuilder* builder,
148                            HandlerTable::CatchPrediction catch_prediction)
149       : ControlFlowBuilder(builder),
150         handler_id_(builder->NewHandlerEntry()),
151         catch_prediction_(catch_prediction) {}
152 
153   void BeginTry(Register context);
154   void EndTry();
155   void EndCatch();
156 
157  private:
158   int handler_id_;
159   HandlerTable::CatchPrediction catch_prediction_;
160   BytecodeLabel handler_;
161   BytecodeLabel exit_;
162 };
163 
164 
165 // A class to help with co-ordinating control flow in try-finally statements.
166 class V8_EXPORT_PRIVATE TryFinallyBuilder final : public ControlFlowBuilder {
167  public:
TryFinallyBuilder(BytecodeArrayBuilder * builder,HandlerTable::CatchPrediction catch_prediction)168   explicit TryFinallyBuilder(BytecodeArrayBuilder* builder,
169                              HandlerTable::CatchPrediction catch_prediction)
170       : ControlFlowBuilder(builder),
171         handler_id_(builder->NewHandlerEntry()),
172         catch_prediction_(catch_prediction),
173         finalization_sites_(builder->zone()) {}
174 
175   void BeginTry(Register context);
176   void LeaveTry();
177   void EndTry();
178   void BeginHandler();
179   void BeginFinally();
180   void EndFinally();
181 
182  private:
183   int handler_id_;
184   HandlerTable::CatchPrediction catch_prediction_;
185   BytecodeLabel handler_;
186 
187   // Unbound labels that identify jumps to the finally block in the code.
188   BytecodeLabels finalization_sites_;
189 };
190 
191 }  // namespace interpreter
192 }  // namespace internal
193 }  // namespace v8
194 
195 #endif  // V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_
196