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 {
20 : public:
21 : explicit ControlFlowBuilder(BytecodeArrayBuilder* builder)
22 6311256 : : builder_(builder) {}
23 6311350 : virtual ~ControlFlowBuilder() = default;
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 : BreakableControlFlowBuilder(BytecodeArrayBuilder* builder,
38 : BlockCoverageBuilder* block_coverage_builder,
39 : AstNode* node)
40 : : ControlFlowBuilder(builder),
41 : break_labels_(builder->zone()),
42 : node_(node),
43 11089136 : block_coverage_builder_(block_coverage_builder) {}
44 : ~BreakableControlFlowBuilder() override;
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 49268 : void Break() { EmitJump(&break_labels_); }
50 : void BreakIfTrue(BytecodeArrayBuilder::ToBooleanMode mode) {
51 37805 : EmitJumpIfTrue(mode, &break_labels_);
52 : }
53 : void BreakIfFalse(BytecodeArrayBuilder::ToBooleanMode mode) {
54 4752 : 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 : protected:
62 : void EmitJump(BytecodeLabels* labels);
63 : void EmitJumpIfTrue(BytecodeArrayBuilder::ToBooleanMode mode,
64 : BytecodeLabels* labels);
65 : void EmitJumpIfFalse(BytecodeArrayBuilder::ToBooleanMode mode,
66 : BytecodeLabels* labels);
67 : void EmitJumpIfUndefined(BytecodeLabels* labels);
68 : void EmitJumpIfNull(BytecodeLabels* labels);
69 :
70 : // Called from the destructor to update sites that emit jumps for break.
71 : void BindBreakTarget();
72 :
73 : // Unbound labels that identify jumps for break statements in the code.
74 : BytecodeLabels break_labels_;
75 :
76 : // A continuation counter (for block coverage) is needed e.g. when
77 : // encountering a break statement.
78 : AstNode* node_;
79 : BlockCoverageBuilder* block_coverage_builder_;
80 : };
81 :
82 :
83 : // Class to track control flow for block statements (which can break in JS).
84 5255585 : class V8_EXPORT_PRIVATE BlockBuilder final
85 : : public BreakableControlFlowBuilder {
86 : public:
87 : BlockBuilder(BytecodeArrayBuilder* builder,
88 : BlockCoverageBuilder* block_coverage_builder,
89 : BreakableStatement* statement)
90 : : BreakableControlFlowBuilder(builder, block_coverage_builder,
91 5255524 : statement) {}
92 : };
93 :
94 :
95 : // A class to help with co-ordinating break and continue statements with
96 : // their loop.
97 : class V8_EXPORT_PRIVATE LoopBuilder final : public BreakableControlFlowBuilder {
98 : public:
99 276121 : LoopBuilder(BytecodeArrayBuilder* builder,
100 : BlockCoverageBuilder* block_coverage_builder, AstNode* node)
101 : : BreakableControlFlowBuilder(builder, block_coverage_builder, node),
102 278389 : continue_labels_(builder->zone()) {
103 276121 : if (block_coverage_builder_ != nullptr) {
104 : block_coverage_body_slot_ =
105 244 : block_coverage_builder_->AllocateBlockCoverageSlot(
106 244 : node, SourceRangeKind::kBody);
107 : }
108 276121 : }
109 : ~LoopBuilder() override;
110 :
111 : void LoopHeader();
112 : void LoopBody();
113 : void JumpToHeader(int loop_depth);
114 : void BindContinueTarget();
115 :
116 : // This method is called when visiting continue statements in the AST.
117 : // Inserts a jump to an unbound label that is patched when BindContinueTarget
118 : // is called.
119 3642 : void Continue() { EmitJump(&continue_labels_); }
120 4752 : void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_labels_); }
121 : void ContinueIfNull() { EmitJumpIfNull(&continue_labels_); }
122 :
123 : private:
124 : BytecodeLoopHeader loop_header_;
125 :
126 : // Unbound labels that identify jumps for continue statements in the code and
127 : // jumps from checking the loop condition to the header for do-while loops.
128 : BytecodeLabels continue_labels_;
129 :
130 : int block_coverage_body_slot_;
131 : };
132 :
133 :
134 : // A class to help with co-ordinating break statements with their switch.
135 : class V8_EXPORT_PRIVATE SwitchBuilder final
136 : : public BreakableControlFlowBuilder {
137 : public:
138 : SwitchBuilder(BytecodeArrayBuilder* builder,
139 : BlockCoverageBuilder* block_coverage_builder,
140 : SwitchStatement* statement, int number_of_cases)
141 : : BreakableControlFlowBuilder(builder, block_coverage_builder, statement),
142 10655 : case_sites_(builder->zone()) {
143 10655 : case_sites_.resize(number_of_cases);
144 : }
145 : ~SwitchBuilder() override; // NOLINT (modernize-use-equals-default)
146 :
147 : // This method should be called by the SwitchBuilder owner when the case
148 : // statement with |index| is emitted to update the case jump site.
149 : void SetCaseTarget(int index, CaseClause* clause);
150 :
151 : // This method is called when visiting case comparison operation for |index|.
152 : // Inserts a JumpIfTrue with ToBooleanMode |mode| to a unbound label that is
153 : // patched when the corresponding SetCaseTarget is called.
154 73058 : void Case(BytecodeArrayBuilder::ToBooleanMode mode, int index) {
155 146116 : builder()->JumpIfTrue(mode, &case_sites_.at(index));
156 73058 : }
157 :
158 : // This method is called when all cases comparisons have been emitted if there
159 : // is a default case statement. Inserts a Jump to a unbound label that is
160 : // patched when the corresponding SetCaseTarget is called.
161 14958 : void DefaultAt(int index) { builder()->Jump(&case_sites_.at(index)); }
162 :
163 : private:
164 : // Unbound labels that identify jumps for case statements in the code.
165 : ZoneVector<BytecodeLabel> case_sites_;
166 : };
167 :
168 :
169 : // A class to help with co-ordinating control flow in try-catch statements.
170 : class V8_EXPORT_PRIVATE TryCatchBuilder final : public ControlFlowBuilder {
171 : public:
172 : TryCatchBuilder(BytecodeArrayBuilder* builder,
173 : BlockCoverageBuilder* block_coverage_builder,
174 : TryCatchStatement* statement,
175 : HandlerTable::CatchPrediction catch_prediction)
176 : : ControlFlowBuilder(builder),
177 : handler_id_(builder->NewHandlerEntry()),
178 : catch_prediction_(catch_prediction),
179 : block_coverage_builder_(block_coverage_builder),
180 339391 : statement_(statement) {}
181 :
182 : ~TryCatchBuilder() override;
183 :
184 : void BeginTry(Register context);
185 : void EndTry();
186 : void EndCatch();
187 :
188 : private:
189 : int handler_id_;
190 : HandlerTable::CatchPrediction catch_prediction_;
191 : BytecodeLabel exit_;
192 :
193 : BlockCoverageBuilder* block_coverage_builder_;
194 : TryCatchStatement* statement_;
195 : };
196 :
197 :
198 : // A class to help with co-ordinating control flow in try-finally statements.
199 : class V8_EXPORT_PRIVATE TryFinallyBuilder final : public ControlFlowBuilder {
200 : public:
201 : TryFinallyBuilder(BytecodeArrayBuilder* builder,
202 : BlockCoverageBuilder* block_coverage_builder,
203 : TryFinallyStatement* statement,
204 : HandlerTable::CatchPrediction catch_prediction)
205 : : ControlFlowBuilder(builder),
206 : handler_id_(builder->NewHandlerEntry()),
207 : catch_prediction_(catch_prediction),
208 : finalization_sites_(builder->zone()),
209 : block_coverage_builder_(block_coverage_builder),
210 124917 : statement_(statement) {}
211 :
212 : ~TryFinallyBuilder() override;
213 :
214 : void BeginTry(Register context);
215 : void LeaveTry();
216 : void EndTry();
217 : void BeginHandler();
218 : void BeginFinally();
219 : void EndFinally();
220 :
221 : private:
222 : int handler_id_;
223 : HandlerTable::CatchPrediction catch_prediction_;
224 : BytecodeLabel handler_;
225 :
226 : // Unbound labels that identify jumps to the finally block in the code.
227 : BytecodeLabels finalization_sites_;
228 :
229 : BlockCoverageBuilder* block_coverage_builder_;
230 : TryFinallyStatement* statement_;
231 : };
232 :
233 : class V8_EXPORT_PRIVATE ConditionalControlFlowBuilder final
234 : : public ControlFlowBuilder {
235 : public:
236 611922 : ConditionalControlFlowBuilder(BytecodeArrayBuilder* builder,
237 : BlockCoverageBuilder* block_coverage_builder,
238 : AstNode* node)
239 : : ControlFlowBuilder(builder),
240 : end_labels_(builder->zone()),
241 : then_labels_(builder->zone()),
242 : else_labels_(builder->zone()),
243 : node_(node),
244 1223844 : block_coverage_builder_(block_coverage_builder) {
245 : DCHECK(node->IsIfStatement() || node->IsConditional());
246 611922 : if (block_coverage_builder != nullptr) {
247 : block_coverage_then_slot_ =
248 524 : block_coverage_builder->AllocateBlockCoverageSlot(
249 524 : node, SourceRangeKind::kThen);
250 : block_coverage_else_slot_ =
251 524 : block_coverage_builder->AllocateBlockCoverageSlot(
252 524 : node, SourceRangeKind::kElse);
253 : }
254 611922 : }
255 : ~ConditionalControlFlowBuilder() override;
256 :
257 603501 : BytecodeLabels* then_labels() { return &then_labels_; }
258 79408 : BytecodeLabels* else_labels() { return &else_labels_; }
259 :
260 : void Then();
261 : void Else();
262 :
263 : void JumpToEnd();
264 :
265 : private:
266 : BytecodeLabels end_labels_;
267 : BytecodeLabels then_labels_;
268 : BytecodeLabels else_labels_;
269 :
270 : AstNode* node_;
271 : int block_coverage_then_slot_;
272 : int block_coverage_else_slot_;
273 : BlockCoverageBuilder* block_coverage_builder_;
274 : };
275 :
276 : } // namespace interpreter
277 : } // namespace internal
278 : } // namespace v8
279 :
280 : #endif // V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_
|