Line data Source code
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/ast/ast-source-ranges.h"
11 : #include "src/interpreter/block-coverage-builder.h"
12 : #include "src/interpreter/bytecode-label.h"
13 : #include "src/zone/zone-containers.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 : namespace interpreter {
18 :
19 : class V8_EXPORT_PRIVATE ControlFlowBuilder BASE_EMBEDDED {
20 : public:
21 : explicit ControlFlowBuilder(BytecodeArrayBuilder* builder)
22 6556280 : : builder_(builder) {}
23 6417846 : virtual ~ControlFlowBuilder() {}
24 :
25 : protected:
26 : BytecodeArrayBuilder* builder() const { return builder_; }
27 :
28 : private:
29 : BytecodeArrayBuilder* builder_;
30 :
31 : DISALLOW_COPY_AND_ASSIGN(ControlFlowBuilder);
32 : };
33 :
34 : class V8_EXPORT_PRIVATE BreakableControlFlowBuilder
35 : : public ControlFlowBuilder {
36 : public:
37 5402251 : BreakableControlFlowBuilder(BytecodeArrayBuilder* builder,
38 : BlockCoverageBuilder* block_coverage_builder,
39 : AstNode* node)
40 : : ControlFlowBuilder(builder),
41 : break_labels_(builder->zone()),
42 : node_(node),
43 10804502 : block_coverage_builder_(block_coverage_builder) {}
44 : virtual ~BreakableControlFlowBuilder();
45 :
46 : // This method is called when visiting break statements in the AST.
47 : // Inserts a jump to an unbound label that is patched when the corresponding
48 : // BindBreakTarget is called.
49 77323 : void Break() { EmitJump(&break_labels_); }
50 : void BreakIfTrue(BytecodeArrayBuilder::ToBooleanMode mode) {
51 24663 : EmitJumpIfTrue(mode, &break_labels_);
52 : }
53 : void BreakIfFalse(BytecodeArrayBuilder::ToBooleanMode mode) {
54 6072 : EmitJumpIfFalse(mode, &break_labels_);
55 : }
56 : void BreakIfUndefined() { EmitJumpIfUndefined(&break_labels_); }
57 : void BreakIfNull() { EmitJumpIfNull(&break_labels_); }
58 :
59 : BytecodeLabels* break_labels() { return &break_labels_; }
60 :
61 594551 : void set_needs_continuation_counter() { needs_continuation_counter_ = true; }
62 : bool needs_continuation_counter() const {
63 : return needs_continuation_counter_;
64 : }
65 :
66 : protected:
67 : void EmitJump(BytecodeLabels* labels);
68 : void EmitJumpIfTrue(BytecodeArrayBuilder::ToBooleanMode mode,
69 : BytecodeLabels* labels);
70 : void EmitJumpIfFalse(BytecodeArrayBuilder::ToBooleanMode mode,
71 : BytecodeLabels* labels);
72 : void EmitJumpIfUndefined(BytecodeLabels* labels);
73 : void EmitJumpIfNull(BytecodeLabels* labels);
74 :
75 : // Called from the destructor to update sites that emit jumps for break.
76 : void BindBreakTarget();
77 :
78 : // Unbound labels that identify jumps for break statements in the code.
79 : BytecodeLabels break_labels_;
80 :
81 : // A continuation counter (for block coverage) is needed e.g. when
82 : // encountering a break statement.
83 : AstNode* node_;
84 : bool needs_continuation_counter_ = false;
85 : BlockCoverageBuilder* block_coverage_builder_;
86 : };
87 :
88 :
89 : // Class to track control flow for block statements (which can break in JS).
90 5146767 : class V8_EXPORT_PRIVATE BlockBuilder final
91 : : public BreakableControlFlowBuilder {
92 : public:
93 : BlockBuilder(BytecodeArrayBuilder* builder,
94 : BlockCoverageBuilder* block_coverage_builder,
95 : BreakableStatement* statement)
96 : : BreakableControlFlowBuilder(builder, block_coverage_builder,
97 5146767 : statement) {}
98 : };
99 :
100 :
101 : // A class to help with co-ordinating break and continue statements with
102 : // their loop.
103 : class V8_EXPORT_PRIVATE LoopBuilder final : public BreakableControlFlowBuilder {
104 : public:
105 477626 : LoopBuilder(BytecodeArrayBuilder* builder,
106 : BlockCoverageBuilder* block_coverage_builder, AstNode* node)
107 : : BreakableControlFlowBuilder(builder, block_coverage_builder, node),
108 : continue_labels_(builder->zone()),
109 : generator_jump_table_location_(nullptr),
110 477626 : parent_generator_jump_table_(nullptr) {
111 238813 : if (block_coverage_builder_ != nullptr) {
112 : set_needs_continuation_counter();
113 : block_coverage_body_slot_ =
114 : block_coverage_builder_->AllocateBlockCoverageSlot(
115 330 : node, SourceRangeKind::kBody);
116 : }
117 238813 : }
118 : ~LoopBuilder();
119 :
120 : void LoopHeader();
121 : void LoopHeaderInGenerator(BytecodeJumpTable** parent_generator_jump_table,
122 : int first_resume_id, int resume_count);
123 : void LoopBody();
124 : void JumpToHeader(int loop_depth);
125 : void BindContinueTarget();
126 :
127 : // This method is called when visiting continue statements in the AST.
128 : // Inserts a jump to an unbound label that is patched when BindContinueTarget
129 : // is called.
130 8726 : void Continue() { EmitJump(&continue_labels_); }
131 6072 : void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_labels_); }
132 : void ContinueIfNull() { EmitJumpIfNull(&continue_labels_); }
133 :
134 : private:
135 : BytecodeLabel loop_header_;
136 :
137 : // Unbound labels that identify jumps for continue statements in the code and
138 : // jumps from checking the loop condition to the header for do-while loops.
139 : BytecodeLabels continue_labels_;
140 :
141 : // While we're in the loop, we want to have a different jump table for
142 : // generator switch statements. We restore it at the end of the loop.
143 : // TODO(leszeks): Storing a pointer to the BytecodeGenerator's jump table
144 : // field is ugly, figure out a better way to do this.
145 : BytecodeJumpTable** generator_jump_table_location_;
146 : BytecodeJumpTable* parent_generator_jump_table_;
147 :
148 : int block_coverage_body_slot_;
149 : };
150 :
151 :
152 : // A class to help with co-ordinating break statements with their switch.
153 : class V8_EXPORT_PRIVATE SwitchBuilder final
154 : : public BreakableControlFlowBuilder {
155 : public:
156 33342 : SwitchBuilder(BytecodeArrayBuilder* builder,
157 : BlockCoverageBuilder* block_coverage_builder,
158 : SwitchStatement* statement, int number_of_cases)
159 : : BreakableControlFlowBuilder(builder, block_coverage_builder, statement),
160 16671 : case_sites_(builder->zone()) {
161 16671 : case_sites_.resize(number_of_cases);
162 16671 : }
163 : ~SwitchBuilder();
164 :
165 : // This method should be called by the SwitchBuilder owner when the case
166 : // statement with |index| is emitted to update the case jump site.
167 : void SetCaseTarget(int index, CaseClause* clause);
168 :
169 : // This method is called when visiting case comparison operation for |index|.
170 : // Inserts a JumpIfTrue with ToBooleanMode |mode| to a unbound label that is
171 : // patched when the corresponding SetCaseTarget is called.
172 93269 : void Case(BytecodeArrayBuilder::ToBooleanMode mode, int index) {
173 186538 : builder()->JumpIfTrue(mode, &case_sites_.at(index));
174 93269 : }
175 :
176 : // This method is called when all cases comparisons have been emitted if there
177 : // is a default case statement. Inserts a Jump to a unbound label that is
178 : // patched when the corresponding SetCaseTarget is called.
179 14678 : void DefaultAt(int index) { builder()->Jump(&case_sites_.at(index)); }
180 :
181 : private:
182 : // Unbound labels that identify jumps for case statements in the code.
183 : ZoneVector<BytecodeLabel> case_sites_;
184 : };
185 :
186 :
187 : // A class to help with co-ordinating control flow in try-catch statements.
188 1 : class V8_EXPORT_PRIVATE TryCatchBuilder final : public ControlFlowBuilder {
189 : public:
190 : TryCatchBuilder(BytecodeArrayBuilder* builder,
191 : HandlerTable::CatchPrediction catch_prediction)
192 : : ControlFlowBuilder(builder),
193 : handler_id_(builder->NewHandlerEntry()),
194 204246 : catch_prediction_(catch_prediction) {}
195 :
196 : void BeginTry(Register context);
197 : void EndTry();
198 : void EndCatch();
199 :
200 : private:
201 : int handler_id_;
202 : HandlerTable::CatchPrediction catch_prediction_;
203 : BytecodeLabel handler_;
204 : BytecodeLabel exit_;
205 : };
206 :
207 :
208 : // A class to help with co-ordinating control flow in try-finally statements.
209 36312 : class V8_EXPORT_PRIVATE TryFinallyBuilder final : public ControlFlowBuilder {
210 : public:
211 72624 : TryFinallyBuilder(BytecodeArrayBuilder* builder,
212 : HandlerTable::CatchPrediction catch_prediction)
213 : : ControlFlowBuilder(builder),
214 : handler_id_(builder->NewHandlerEntry()),
215 : catch_prediction_(catch_prediction),
216 108936 : finalization_sites_(builder->zone()) {}
217 :
218 : void BeginTry(Register context);
219 : void LeaveTry();
220 : void EndTry();
221 : void BeginHandler();
222 : void BeginFinally();
223 : void EndFinally();
224 :
225 : private:
226 : int handler_id_;
227 : HandlerTable::CatchPrediction catch_prediction_;
228 : BytecodeLabel handler_;
229 :
230 : // Unbound labels that identify jumps to the finally block in the code.
231 : BytecodeLabels finalization_sites_;
232 : };
233 :
234 : class V8_EXPORT_PRIVATE ConditionalControlFlowBuilder final
235 : : public ControlFlowBuilder {
236 : public:
237 4062376 : ConditionalControlFlowBuilder(BytecodeArrayBuilder* builder,
238 : BlockCoverageBuilder* block_coverage_builder,
239 : AstNode* node)
240 : : ControlFlowBuilder(builder),
241 : end_labels_(builder->zone()),
242 : then_labels_(builder->zone()),
243 : else_labels_(builder->zone()),
244 : node_(node),
245 2031188 : block_coverage_builder_(block_coverage_builder) {
246 : DCHECK(node->IsIfStatement() || node->IsConditional());
247 1015594 : if (block_coverage_builder != nullptr) {
248 : block_coverage_then_slot_ =
249 : block_coverage_builder->AllocateBlockCoverageSlot(
250 773 : node, SourceRangeKind::kThen);
251 : block_coverage_else_slot_ =
252 : block_coverage_builder->AllocateBlockCoverageSlot(
253 773 : node, SourceRangeKind::kElse);
254 : }
255 1015594 : }
256 : ~ConditionalControlFlowBuilder();
257 :
258 : BytecodeLabels* then_labels() { return &then_labels_; }
259 : BytecodeLabels* else_labels() { return &else_labels_; }
260 :
261 : void Then();
262 : void Else();
263 :
264 : void JumpToEnd();
265 :
266 : private:
267 : BytecodeLabels end_labels_;
268 : BytecodeLabels then_labels_;
269 : BytecodeLabels else_labels_;
270 :
271 : AstNode* node_;
272 : int block_coverage_then_slot_;
273 : int block_coverage_else_slot_;
274 : BlockCoverageBuilder* block_coverage_builder_;
275 : };
276 :
277 : } // namespace interpreter
278 : } // namespace internal
279 : } // namespace v8
280 :
281 : #endif // V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_
|