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