blob: 8778b2656568080095728455d5e13bb9bda2db97 [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
Ben Murdochc5610432016-08-08 18:44:38 +010090 void LoopHeader(ZoneVector<BytecodeLabel>* additional_labels);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000091 void JumpToHeader() { builder()->Jump(&loop_header_); }
92 void JumpToHeaderIfTrue() { builder()->JumpIfTrue(&loop_header_); }
Ben Murdochc5610432016-08-08 18:44:38 +010093 void SetContinueTarget();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000094 void EndLoop();
95
96 // This method is called when visiting continue statements in the AST.
Ben Murdochc5610432016-08-08 18:44:38 +010097 // Inserts a jump to an unbound label that is patched when SetContinueTarget
98 // is called.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000099 void Continue() { EmitJump(&continue_sites_); }
100 void ContinueIfTrue() { EmitJumpIfTrue(&continue_sites_); }
101 void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_sites_); }
102 void ContinueIfNull() { EmitJumpIfNull(&continue_sites_); }
103
104 private:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000105 BytecodeLabel loop_header_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000106 BytecodeLabel loop_end_;
107
108 // Unbound labels that identify jumps for continue statements in the code.
109 ZoneVector<BytecodeLabel> continue_sites_;
110};
111
112
113// A class to help with co-ordinating break statements with their switch.
114class SwitchBuilder final : public BreakableControlFlowBuilder {
115 public:
116 explicit SwitchBuilder(BytecodeArrayBuilder* builder, int number_of_cases)
117 : BreakableControlFlowBuilder(builder),
118 case_sites_(builder->zone()) {
119 case_sites_.resize(number_of_cases);
120 }
121 ~SwitchBuilder();
122
123 // This method should be called by the SwitchBuilder owner when the case
124 // statement with |index| is emitted to update the case jump site.
125 void SetCaseTarget(int index);
126
127 // This method is called when visiting case comparison operation for |index|.
128 // Inserts a JumpIfTrue to a unbound label that is patched when the
129 // corresponding SetCaseTarget is called.
130 void Case(int index) { EmitJumpIfTrue(&case_sites_, index); }
131
132 // This method is called when all cases comparisons have been emitted if there
133 // is a default case statement. Inserts a Jump to a unbound label that is
134 // patched when the corresponding SetCaseTarget is called.
135 void DefaultAt(int index) { EmitJump(&case_sites_, index); }
136
137 private:
138 // Unbound labels that identify jumps for case statements in the code.
139 ZoneVector<BytecodeLabel> case_sites_;
140};
141
Ben Murdoch097c5b22016-05-18 11:27:45 +0100142
143// A class to help with co-ordinating control flow in try-catch statements.
144class TryCatchBuilder final : public ControlFlowBuilder {
145 public:
146 explicit TryCatchBuilder(BytecodeArrayBuilder* builder)
147 : ControlFlowBuilder(builder), handler_id_(builder->NewHandlerEntry()) {}
148
149 void BeginTry(Register context);
150 void EndTry();
151 void EndCatch();
152
153 private:
154 int handler_id_;
155 BytecodeLabel handler_;
156 BytecodeLabel exit_;
157};
158
159
160// A class to help with co-ordinating control flow in try-finally statements.
161class TryFinallyBuilder final : public ControlFlowBuilder {
162 public:
163 explicit TryFinallyBuilder(BytecodeArrayBuilder* builder, bool will_catch)
164 : ControlFlowBuilder(builder),
165 handler_id_(builder->NewHandlerEntry()),
166 finalization_sites_(builder->zone()),
167 will_catch_(will_catch) {}
168
169 void BeginTry(Register context);
170 void LeaveTry();
171 void EndTry();
172 void BeginHandler();
173 void BeginFinally();
174 void EndFinally();
175
176 private:
177 int handler_id_;
178 BytecodeLabel handler_;
179
180 // Unbound labels that identify jumps to the finally block in the code.
181 ZoneVector<BytecodeLabel> finalization_sites_;
182
183 // Conservative prediction of whether exceptions thrown into the handler for
184 // this finally block will be caught. Note that such a prediction depends on
185 // whether this try-finally is nested inside a surrounding try-catch.
186 bool will_catch_;
187};
188
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000189} // namespace interpreter
190} // namespace internal
191} // namespace v8
192
193#endif // V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_