blob: e4d376b9b21e90bdd1121589bcc28d6cc8de4924 [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
10#include "src/zone-containers.h"
11
12namespace v8 {
13namespace internal {
14namespace interpreter {
15
16class ControlFlowBuilder BASE_EMBEDDED {
17 public:
18 explicit ControlFlowBuilder(BytecodeArrayBuilder* builder)
19 : builder_(builder) {}
20 virtual ~ControlFlowBuilder() {}
21
22 protected:
23 BytecodeArrayBuilder* builder() const { return builder_; }
24
25 private:
26 BytecodeArrayBuilder* builder_;
27
28 DISALLOW_COPY_AND_ASSIGN(ControlFlowBuilder);
29};
30
31class BreakableControlFlowBuilder : public ControlFlowBuilder {
32 public:
33 explicit BreakableControlFlowBuilder(BytecodeArrayBuilder* builder)
34 : ControlFlowBuilder(builder),
35 break_sites_(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 SetBreakTarget(const BytecodeLabel& break_target);
41
42 // This method is called when visiting break statements in the AST.
43 // Inserts a jump to a unbound label that is patched when the corresponding
44 // SetBreakTarget is called.
45 void Break() { EmitJump(&break_sites_); }
46 void BreakIfTrue() { EmitJumpIfTrue(&break_sites_); }
47 void BreakIfFalse() { EmitJumpIfFalse(&break_sites_); }
48 void BreakIfUndefined() { EmitJumpIfUndefined(&break_sites_); }
49 void BreakIfNull() { EmitJumpIfNull(&break_sites_); }
50
51 protected:
52 void EmitJump(ZoneVector<BytecodeLabel>* labels);
53 void EmitJump(ZoneVector<BytecodeLabel>* labels, int index);
54 void EmitJumpIfTrue(ZoneVector<BytecodeLabel>* labels);
55 void EmitJumpIfTrue(ZoneVector<BytecodeLabel>* labels, int index);
56 void EmitJumpIfFalse(ZoneVector<BytecodeLabel>* labels);
57 void EmitJumpIfFalse(ZoneVector<BytecodeLabel>* labels, int index);
58 void EmitJumpIfUndefined(ZoneVector<BytecodeLabel>* labels);
59 void EmitJumpIfNull(ZoneVector<BytecodeLabel>* labels);
60
61 void BindLabels(const BytecodeLabel& target, ZoneVector<BytecodeLabel>* site);
62
63 // Unbound labels that identify jumps for break statements in the code.
64 ZoneVector<BytecodeLabel> break_sites_;
65};
66
67
68// Class to track control flow for block statements (which can break in JS).
69class BlockBuilder final : public BreakableControlFlowBuilder {
70 public:
71 explicit BlockBuilder(BytecodeArrayBuilder* builder)
72 : BreakableControlFlowBuilder(builder) {}
73
74 void EndBlock();
75
76 private:
77 BytecodeLabel block_end_;
78};
79
80
81// A class to help with co-ordinating break and continue statements with
82// their loop.
83class LoopBuilder final : public BreakableControlFlowBuilder {
84 public:
85 explicit LoopBuilder(BytecodeArrayBuilder* builder)
86 : BreakableControlFlowBuilder(builder),
87 continue_sites_(builder->zone()) {}
88 ~LoopBuilder();
89
90 void LoopHeader();
91 void Condition() { builder()->Bind(&condition_); }
92 void Next() { builder()->Bind(&next_); }
93 void JumpToHeader() { builder()->Jump(&loop_header_); }
94 void JumpToHeaderIfTrue() { builder()->JumpIfTrue(&loop_header_); }
95 void EndLoop();
96
97 // This method is called when visiting continue statements in the AST.
98 // Inserts a jump to a unbound label that is patched when the corresponding
99 // SetContinueTarget is called.
100 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:
106 void SetContinueTarget(const BytecodeLabel& continue_target);
107
108 BytecodeLabel loop_header_;
109 BytecodeLabel condition_;
110 BytecodeLabel next_;
111 BytecodeLabel loop_end_;
112
113 // Unbound labels that identify jumps for continue statements in the code.
114 ZoneVector<BytecodeLabel> continue_sites_;
115};
116
117
118// A class to help with co-ordinating break statements with their switch.
119class SwitchBuilder final : public BreakableControlFlowBuilder {
120 public:
121 explicit SwitchBuilder(BytecodeArrayBuilder* builder, int number_of_cases)
122 : BreakableControlFlowBuilder(builder),
123 case_sites_(builder->zone()) {
124 case_sites_.resize(number_of_cases);
125 }
126 ~SwitchBuilder();
127
128 // This method should be called by the SwitchBuilder owner when the case
129 // statement with |index| is emitted to update the case jump site.
130 void SetCaseTarget(int index);
131
132 // This method is called when visiting case comparison operation for |index|.
133 // Inserts a JumpIfTrue to a unbound label that is patched when the
134 // corresponding SetCaseTarget is called.
135 void Case(int index) { EmitJumpIfTrue(&case_sites_, index); }
136
137 // This method is called when all cases comparisons have been emitted if there
138 // is a default case statement. Inserts a Jump to a unbound label that is
139 // patched when the corresponding SetCaseTarget is called.
140 void DefaultAt(int index) { EmitJump(&case_sites_, index); }
141
142 private:
143 // Unbound labels that identify jumps for case statements in the code.
144 ZoneVector<BytecodeLabel> case_sites_;
145};
146
Ben Murdoch097c5b22016-05-18 11:27:45 +0100147
148// A class to help with co-ordinating control flow in try-catch statements.
149class TryCatchBuilder final : public ControlFlowBuilder {
150 public:
151 explicit TryCatchBuilder(BytecodeArrayBuilder* builder)
152 : ControlFlowBuilder(builder), handler_id_(builder->NewHandlerEntry()) {}
153
154 void BeginTry(Register context);
155 void EndTry();
156 void EndCatch();
157
158 private:
159 int handler_id_;
160 BytecodeLabel handler_;
161 BytecodeLabel exit_;
162};
163
164
165// A class to help with co-ordinating control flow in try-finally statements.
166class TryFinallyBuilder final : public ControlFlowBuilder {
167 public:
168 explicit TryFinallyBuilder(BytecodeArrayBuilder* builder, bool will_catch)
169 : ControlFlowBuilder(builder),
170 handler_id_(builder->NewHandlerEntry()),
171 finalization_sites_(builder->zone()),
172 will_catch_(will_catch) {}
173
174 void BeginTry(Register context);
175 void LeaveTry();
176 void EndTry();
177 void BeginHandler();
178 void BeginFinally();
179 void EndFinally();
180
181 private:
182 int handler_id_;
183 BytecodeLabel handler_;
184
185 // Unbound labels that identify jumps to the finally block in the code.
186 ZoneVector<BytecodeLabel> finalization_sites_;
187
188 // Conservative prediction of whether exceptions thrown into the handler for
189 // this finally block will be caught. Note that such a prediction depends on
190 // whether this try-finally is nested inside a surrounding try-catch.
191 bool will_catch_;
192};
193
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000194} // namespace interpreter
195} // namespace internal
196} // namespace v8
197
198#endif // V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_