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 | #include "src/interpreter/control-flow-builders.h" |
6 | #include "src/objects-inl.h" |
7 | |
8 | namespace v8 { |
9 | namespace internal { |
10 | namespace interpreter { |
11 | |
12 | |
13 | BreakableControlFlowBuilder::~BreakableControlFlowBuilder() { |
14 | BindBreakTarget(); |
15 | DCHECK(break_labels_.empty() || break_labels_.is_bound()); |
16 | if (block_coverage_builder_ != nullptr) { |
17 | block_coverage_builder_->IncrementBlockCounter( |
18 | node_, SourceRangeKind::kContinuation); |
19 | } |
20 | } |
21 | |
22 | void BreakableControlFlowBuilder::BindBreakTarget() { |
23 | break_labels_.Bind(builder()); |
24 | } |
25 | |
26 | void BreakableControlFlowBuilder::EmitJump(BytecodeLabels* sites) { |
27 | builder()->Jump(sites->New()); |
28 | } |
29 | |
30 | void BreakableControlFlowBuilder::EmitJumpIfTrue( |
31 | BytecodeArrayBuilder::ToBooleanMode mode, BytecodeLabels* sites) { |
32 | builder()->JumpIfTrue(mode, sites->New()); |
33 | } |
34 | |
35 | void BreakableControlFlowBuilder::EmitJumpIfFalse( |
36 | BytecodeArrayBuilder::ToBooleanMode mode, BytecodeLabels* sites) { |
37 | builder()->JumpIfFalse(mode, sites->New()); |
38 | } |
39 | |
40 | void BreakableControlFlowBuilder::EmitJumpIfUndefined(BytecodeLabels* sites) { |
41 | builder()->JumpIfUndefined(sites->New()); |
42 | } |
43 | |
44 | void BreakableControlFlowBuilder::EmitJumpIfNull(BytecodeLabels* sites) { |
45 | builder()->JumpIfNull(sites->New()); |
46 | } |
47 | |
48 | LoopBuilder::~LoopBuilder() { |
49 | DCHECK(continue_labels_.empty() || continue_labels_.is_bound()); |
50 | } |
51 | |
52 | void LoopBuilder::() { |
53 | // Jumps from before the loop header into the loop violate ordering |
54 | // requirements of bytecode basic blocks. The only entry into a loop |
55 | // must be the loop header. Surely breaks is okay? Not if nested |
56 | // and misplaced between the headers. |
57 | DCHECK(break_labels_.empty() && continue_labels_.empty()); |
58 | builder()->Bind(&loop_header_); |
59 | } |
60 | |
61 | void LoopBuilder::LoopBody() { |
62 | if (block_coverage_builder_ != nullptr) { |
63 | block_coverage_builder_->IncrementBlockCounter(block_coverage_body_slot_); |
64 | } |
65 | } |
66 | |
67 | void LoopBuilder::(int loop_depth) { |
68 | // Pass the proper loop nesting level to the backwards branch, to trigger |
69 | // on-stack replacement when armed for the given loop nesting depth. |
70 | int level = Min(loop_depth, AbstractCode::kMaxLoopNestingMarker - 1); |
71 | // Loop must have closed form, i.e. all loop elements are within the loop, |
72 | // the loop header precedes the body and next elements in the loop. |
73 | builder()->JumpLoop(&loop_header_, level); |
74 | } |
75 | |
76 | void LoopBuilder::BindContinueTarget() { continue_labels_.Bind(builder()); } |
77 | |
78 | SwitchBuilder::~SwitchBuilder() { |
79 | #ifdef DEBUG |
80 | for (auto site : case_sites_) { |
81 | DCHECK(!site.has_referrer_jump() || site.is_bound()); |
82 | } |
83 | #endif |
84 | } |
85 | |
86 | void SwitchBuilder::SetCaseTarget(int index, CaseClause* clause) { |
87 | BytecodeLabel& site = case_sites_.at(index); |
88 | builder()->Bind(&site); |
89 | if (block_coverage_builder_) { |
90 | block_coverage_builder_->IncrementBlockCounter(clause, |
91 | SourceRangeKind::kBody); |
92 | } |
93 | } |
94 | |
95 | TryCatchBuilder::~TryCatchBuilder() { |
96 | if (block_coverage_builder_ != nullptr) { |
97 | block_coverage_builder_->IncrementBlockCounter( |
98 | statement_, SourceRangeKind::kContinuation); |
99 | } |
100 | } |
101 | |
102 | void TryCatchBuilder::BeginTry(Register context) { |
103 | builder()->MarkTryBegin(handler_id_, context); |
104 | } |
105 | |
106 | |
107 | void TryCatchBuilder::EndTry() { |
108 | builder()->MarkTryEnd(handler_id_); |
109 | builder()->Jump(&exit_); |
110 | builder()->MarkHandler(handler_id_, catch_prediction_); |
111 | |
112 | if (block_coverage_builder_ != nullptr) { |
113 | block_coverage_builder_->IncrementBlockCounter(statement_, |
114 | SourceRangeKind::kCatch); |
115 | } |
116 | } |
117 | |
118 | void TryCatchBuilder::EndCatch() { builder()->Bind(&exit_); } |
119 | |
120 | TryFinallyBuilder::~TryFinallyBuilder() { |
121 | if (block_coverage_builder_ != nullptr) { |
122 | block_coverage_builder_->IncrementBlockCounter( |
123 | statement_, SourceRangeKind::kContinuation); |
124 | } |
125 | } |
126 | |
127 | void TryFinallyBuilder::BeginTry(Register context) { |
128 | builder()->MarkTryBegin(handler_id_, context); |
129 | } |
130 | |
131 | |
132 | void TryFinallyBuilder::LeaveTry() { |
133 | builder()->Jump(finalization_sites_.New()); |
134 | } |
135 | |
136 | |
137 | void TryFinallyBuilder::EndTry() { |
138 | builder()->MarkTryEnd(handler_id_); |
139 | } |
140 | |
141 | |
142 | void TryFinallyBuilder::BeginHandler() { |
143 | builder()->Bind(&handler_); |
144 | builder()->MarkHandler(handler_id_, catch_prediction_); |
145 | } |
146 | |
147 | void TryFinallyBuilder::BeginFinally() { |
148 | finalization_sites_.Bind(builder()); |
149 | |
150 | if (block_coverage_builder_ != nullptr) { |
151 | block_coverage_builder_->IncrementBlockCounter(statement_, |
152 | SourceRangeKind::kFinally); |
153 | } |
154 | } |
155 | |
156 | void TryFinallyBuilder::EndFinally() { |
157 | // Nothing to be done here. |
158 | } |
159 | |
160 | ConditionalControlFlowBuilder::~ConditionalControlFlowBuilder() { |
161 | if (!else_labels_.is_bound()) else_labels_.Bind(builder()); |
162 | end_labels_.Bind(builder()); |
163 | |
164 | DCHECK(end_labels_.empty() || end_labels_.is_bound()); |
165 | DCHECK(then_labels_.empty() || then_labels_.is_bound()); |
166 | DCHECK(else_labels_.empty() || else_labels_.is_bound()); |
167 | |
168 | // IfStatement requires a continuation counter, Conditional does not (as it |
169 | // can only contain expressions). |
170 | if (block_coverage_builder_ != nullptr && node_->IsIfStatement()) { |
171 | block_coverage_builder_->IncrementBlockCounter( |
172 | node_, SourceRangeKind::kContinuation); |
173 | } |
174 | } |
175 | |
176 | void ConditionalControlFlowBuilder::JumpToEnd() { |
177 | DCHECK(end_labels_.empty()); // May only be called once. |
178 | builder()->Jump(end_labels_.New()); |
179 | } |
180 | |
181 | void ConditionalControlFlowBuilder::Then() { |
182 | then_labels()->Bind(builder()); |
183 | if (block_coverage_builder_ != nullptr) { |
184 | block_coverage_builder_->IncrementBlockCounter(block_coverage_then_slot_); |
185 | } |
186 | } |
187 | |
188 | void ConditionalControlFlowBuilder::Else() { |
189 | else_labels()->Bind(builder()); |
190 | if (block_coverage_builder_ != nullptr) { |
191 | block_coverage_builder_->IncrementBlockCounter(block_coverage_else_slot_); |
192 | } |
193 | } |
194 | |
195 | } // namespace interpreter |
196 | } // namespace internal |
197 | } // namespace v8 |
198 | |