blob: b72d6d5f0f5c8ff9be33dfc420726c670ca35707 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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
Ben Murdoch61f157c2016-09-16 13:49:30 +010010#include "src/interpreter/bytecode-label.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011#include "src/zone-containers.h"
12
13namespace v8 {
14namespace internal {
15namespace interpreter {
16
17class ControlFlowBuilder BASE_EMBEDDED {
18 public:
19 explicit ControlFlowBuilder(BytecodeArrayBuilder* builder)
20 : builder_(builder) {}
21 virtual ~ControlFlowBuilder() {}
22
23 protected:
24 BytecodeArrayBuilder* builder() const { return builder_; }
25
26 private:
27 BytecodeArrayBuilder* builder_;
28
29 DISALLOW_COPY_AND_ASSIGN(ControlFlowBuilder);
30};
31
32class BreakableControlFlowBuilder : public ControlFlowBuilder {
33 public:
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.
46 void Break() { EmitJump(&break_sites_); }
47 void BreakIfTrue() { EmitJumpIfTrue(&break_sites_); }
48 void BreakIfFalse() { EmitJumpIfFalse(&break_sites_); }
49 void BreakIfUndefined() { EmitJumpIfUndefined(&break_sites_); }
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).
70class BlockBuilder final : public BreakableControlFlowBuilder {
71 public:
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.
84class LoopBuilder final : public BreakableControlFlowBuilder {
85 public:
86 explicit LoopBuilder(BytecodeArrayBuilder* builder)
87 : BreakableControlFlowBuilder(builder),
88 continue_sites_(builder->zone()) {}
89 ~LoopBuilder();
90
Ben Murdochc5610432016-08-08 18:44:38 +010091 void LoopHeader(ZoneVector<BytecodeLabel>* additional_labels);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000092 void JumpToHeader() { builder()->Jump(&loop_header_); }
93 void JumpToHeaderIfTrue() { builder()->JumpIfTrue(&loop_header_); }
Ben Murdochc5610432016-08-08 18:44:38 +010094 void SetContinueTarget();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000095 void EndLoop();
96
97 // This method is called when visiting continue statements in the AST.
Ben Murdochc5610432016-08-08 18:44:38 +010098 // Inserts a jump to an unbound label that is patched when SetContinueTarget
99 // is called.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000100 void Continue() { EmitJump(&continue_sites_); }
101 void ContinueIfTrue() { EmitJumpIfTrue(&continue_sites_); }
102 void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_sites_); }
103 void ContinueIfNull() { EmitJumpIfNull(&continue_sites_); }
104
105 private:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000106 BytecodeLabel loop_header_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000107 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.
115class SwitchBuilder final : public BreakableControlFlowBuilder {
116 public:
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.
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.
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
Ben Murdoch097c5b22016-05-18 11:27:45 +0100143
144// A class to help with co-ordinating control flow in try-catch statements.
145class TryCatchBuilder final : public ControlFlowBuilder {
146 public:
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.
162class TryFinallyBuilder final : public ControlFlowBuilder {
163 public:
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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000190} // namespace interpreter
191} // namespace internal
192} // namespace v8
193
194#endif // V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_