• 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-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),
36         break_sites_(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 SetBreakTarget(const BytecodeLabel& break_target);
42 
43   // This method is called when visiting break statements in the AST.
44   // Inserts a jump to a unbound label that is patched when the corresponding
45   // SetBreakTarget is called.
Break()46   void Break() { EmitJump(&break_sites_); }
BreakIfTrue()47   void BreakIfTrue() { EmitJumpIfTrue(&break_sites_); }
BreakIfFalse()48   void BreakIfFalse() { EmitJumpIfFalse(&break_sites_); }
BreakIfUndefined()49   void BreakIfUndefined() { EmitJumpIfUndefined(&break_sites_); }
BreakIfNull()50   void BreakIfNull() { EmitJumpIfNull(&break_sites_); }
51 
52  protected:
53   void EmitJump(ZoneVector<BytecodeLabel>* labels);
54   void EmitJump(ZoneVector<BytecodeLabel>* labels, int index);
55   void EmitJumpIfTrue(ZoneVector<BytecodeLabel>* labels);
56   void EmitJumpIfTrue(ZoneVector<BytecodeLabel>* labels, int index);
57   void EmitJumpIfFalse(ZoneVector<BytecodeLabel>* labels);
58   void EmitJumpIfFalse(ZoneVector<BytecodeLabel>* labels, int index);
59   void EmitJumpIfUndefined(ZoneVector<BytecodeLabel>* labels);
60   void EmitJumpIfNull(ZoneVector<BytecodeLabel>* labels);
61 
62   void BindLabels(const BytecodeLabel& target, ZoneVector<BytecodeLabel>* site);
63 
64   // Unbound labels that identify jumps for break statements in the code.
65   ZoneVector<BytecodeLabel> break_sites_;
66 };
67 
68 
69 // Class to track control flow for block statements (which can break in JS).
70 class BlockBuilder final : public BreakableControlFlowBuilder {
71  public:
BlockBuilder(BytecodeArrayBuilder * builder)72   explicit BlockBuilder(BytecodeArrayBuilder* builder)
73       : BreakableControlFlowBuilder(builder) {}
74 
75   void EndBlock();
76 
77  private:
78   BytecodeLabel block_end_;
79 };
80 
81 
82 // A class to help with co-ordinating break and continue statements with
83 // their loop.
84 class LoopBuilder final : public BreakableControlFlowBuilder {
85  public:
LoopBuilder(BytecodeArrayBuilder * builder)86   explicit LoopBuilder(BytecodeArrayBuilder* builder)
87       : BreakableControlFlowBuilder(builder),
88         continue_sites_(builder->zone()) {}
89   ~LoopBuilder();
90 
91   void LoopHeader(ZoneVector<BytecodeLabel>* additional_labels);
JumpToHeader()92   void JumpToHeader() { builder()->Jump(&loop_header_); }
JumpToHeaderIfTrue()93   void JumpToHeaderIfTrue() { builder()->JumpIfTrue(&loop_header_); }
94   void SetContinueTarget();
95   void EndLoop();
96 
97   // This method is called when visiting continue statements in the AST.
98   // Inserts a jump to an unbound label that is patched when SetContinueTarget
99   // is called.
Continue()100   void Continue() { EmitJump(&continue_sites_); }
ContinueIfTrue()101   void ContinueIfTrue() { EmitJumpIfTrue(&continue_sites_); }
ContinueIfUndefined()102   void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_sites_); }
ContinueIfNull()103   void ContinueIfNull() { EmitJumpIfNull(&continue_sites_); }
104 
105  private:
106   BytecodeLabel loop_header_;
107   BytecodeLabel loop_end_;
108 
109   // Unbound labels that identify jumps for continue statements in the code.
110   ZoneVector<BytecodeLabel> continue_sites_;
111 };
112 
113 
114 // A class to help with co-ordinating break statements with their switch.
115 class SwitchBuilder final : 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) { EmitJumpIfTrue(&case_sites_, 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) { EmitJump(&case_sites_, 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 TryCatchBuilder final : public ControlFlowBuilder {
146  public:
TryCatchBuilder(BytecodeArrayBuilder * builder)147   explicit TryCatchBuilder(BytecodeArrayBuilder* builder)
148       : ControlFlowBuilder(builder), handler_id_(builder->NewHandlerEntry()) {}
149 
150   void BeginTry(Register context);
151   void EndTry();
152   void EndCatch();
153 
154  private:
155   int handler_id_;
156   BytecodeLabel handler_;
157   BytecodeLabel exit_;
158 };
159 
160 
161 // A class to help with co-ordinating control flow in try-finally statements.
162 class TryFinallyBuilder final : public ControlFlowBuilder {
163  public:
TryFinallyBuilder(BytecodeArrayBuilder * builder,bool will_catch)164   explicit TryFinallyBuilder(BytecodeArrayBuilder* builder, bool will_catch)
165       : ControlFlowBuilder(builder),
166         handler_id_(builder->NewHandlerEntry()),
167         finalization_sites_(builder->zone()),
168         will_catch_(will_catch) {}
169 
170   void BeginTry(Register context);
171   void LeaveTry();
172   void EndTry();
173   void BeginHandler();
174   void BeginFinally();
175   void EndFinally();
176 
177  private:
178   int handler_id_;
179   BytecodeLabel handler_;
180 
181   // Unbound labels that identify jumps to the finally block in the code.
182   ZoneVector<BytecodeLabel> finalization_sites_;
183 
184   // Conservative prediction of whether exceptions thrown into the handler for
185   // this finally block will be caught. Note that such a prediction depends on
186   // whether this try-finally is nested inside a surrounding try-catch.
187   bool will_catch_;
188 };
189 
190 }  // namespace interpreter
191 }  // namespace internal
192 }  // namespace v8
193 
194 #endif  // V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_
195