• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/objects-inl.h"
7 
8 namespace v8 {
9 namespace internal {
10 namespace interpreter {
11 
12 
~BreakableControlFlowBuilder()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 
BindBreakTarget()22 void BreakableControlFlowBuilder::BindBreakTarget() {
23   break_labels_.Bind(builder());
24 }
25 
EmitJump(BytecodeLabels * sites)26 void BreakableControlFlowBuilder::EmitJump(BytecodeLabels* sites) {
27   builder()->Jump(sites->New());
28 }
29 
EmitJumpIfTrue(BytecodeArrayBuilder::ToBooleanMode mode,BytecodeLabels * sites)30 void BreakableControlFlowBuilder::EmitJumpIfTrue(
31     BytecodeArrayBuilder::ToBooleanMode mode, BytecodeLabels* sites) {
32   builder()->JumpIfTrue(mode, sites->New());
33 }
34 
EmitJumpIfFalse(BytecodeArrayBuilder::ToBooleanMode mode,BytecodeLabels * sites)35 void BreakableControlFlowBuilder::EmitJumpIfFalse(
36     BytecodeArrayBuilder::ToBooleanMode mode, BytecodeLabels* sites) {
37   builder()->JumpIfFalse(mode, sites->New());
38 }
39 
EmitJumpIfUndefined(BytecodeLabels * sites)40 void BreakableControlFlowBuilder::EmitJumpIfUndefined(BytecodeLabels* sites) {
41   builder()->JumpIfUndefined(sites->New());
42 }
43 
EmitJumpIfNull(BytecodeLabels * sites)44 void BreakableControlFlowBuilder::EmitJumpIfNull(BytecodeLabels* sites) {
45   builder()->JumpIfNull(sites->New());
46 }
47 
~LoopBuilder()48 LoopBuilder::~LoopBuilder() {
49   DCHECK(continue_labels_.empty() || continue_labels_.is_bound());
50   DCHECK(end_labels_.empty() || end_labels_.is_bound());
51 }
52 
LoopHeader()53 void LoopBuilder::LoopHeader() {
54   // Jumps from before the loop header into the loop violate ordering
55   // requirements of bytecode basic blocks. The only entry into a loop
56   // must be the loop header. Surely breaks is okay? Not if nested
57   // and misplaced between the headers.
58   DCHECK(break_labels_.empty() && continue_labels_.empty() &&
59          end_labels_.empty());
60   builder()->Bind(&loop_header_);
61 }
62 
LoopBody()63 void LoopBuilder::LoopBody() {
64   if (block_coverage_builder_ != nullptr) {
65     block_coverage_builder_->IncrementBlockCounter(block_coverage_body_slot_);
66   }
67 }
68 
JumpToHeader(int loop_depth,LoopBuilder * const parent_loop)69 void LoopBuilder::JumpToHeader(int loop_depth, LoopBuilder* const parent_loop) {
70   BindLoopEnd();
71   if (parent_loop &&
72       loop_header_.offset() == parent_loop->loop_header_.offset()) {
73     // TurboFan can't cope with multiple loops that have the same loop header
74     // bytecode offset. If we have an inner loop with the same header offset
75     // than its parent loop, we do not create a JumpLoop bytecode. Instead, we
76     // Jump to our parent's JumpToHeader which in turn can be a JumpLoop or, iff
77     // they are a nested inner loop too, a Jump to its parent's JumpToHeader.
78     parent_loop->JumpToLoopEnd();
79   } else {
80     // Pass the proper loop depth to the backwards branch for triggering OSR.
81     // For purposes of OSR, the loop depth is capped at `kMaxOsrUrgency - 1`.
82     // Once that urgency is reached, all loops become OSR candidates.
83     //
84     // The loop must have closed form, i.e. all loop elements are within the
85     // loop, the loop header precedes the body and next elements in the loop.
86     builder()->JumpLoop(&loop_header_,
87                         std::min(loop_depth, BytecodeArray::kMaxOsrUrgency - 1),
88                         source_position_);
89   }
90 }
91 
BindContinueTarget()92 void LoopBuilder::BindContinueTarget() { continue_labels_.Bind(builder()); }
93 
BindLoopEnd()94 void LoopBuilder::BindLoopEnd() { end_labels_.Bind(builder()); }
95 
~SwitchBuilder()96 SwitchBuilder::~SwitchBuilder() {
97 #ifdef DEBUG
98   for (auto site : case_sites_) {
99     DCHECK(!site.has_referrer_jump() || site.is_bound());
100   }
101 #endif
102 }
103 
BindCaseTargetForJumpTable(int case_value,CaseClause * clause)104 void SwitchBuilder::BindCaseTargetForJumpTable(int case_value,
105                                                CaseClause* clause) {
106   builder()->Bind(jump_table_, case_value);
107   BuildBlockCoverage(clause);
108 }
109 
BindCaseTargetForCompareJump(int index,CaseClause * clause)110 void SwitchBuilder::BindCaseTargetForCompareJump(int index,
111                                                  CaseClause* clause) {
112   builder()->Bind(&case_sites_.at(index));
113   BuildBlockCoverage(clause);
114 }
115 
JumpToCaseIfTrue(BytecodeArrayBuilder::ToBooleanMode mode,int index)116 void SwitchBuilder::JumpToCaseIfTrue(BytecodeArrayBuilder::ToBooleanMode mode,
117                                      int index) {
118   builder()->JumpIfTrue(mode, &case_sites_.at(index));
119 }
120 
121 // Precondition: tag is in the accumulator
EmitJumpTableIfExists(int min_case,int max_case,std::map<int,CaseClause * > & covered_cases)122 void SwitchBuilder::EmitJumpTableIfExists(
123     int min_case, int max_case, std::map<int, CaseClause*>& covered_cases) {
124   builder()->SwitchOnSmiNoFeedback(jump_table_);
125   fall_through_.Bind(builder());
126   for (int j = min_case; j <= max_case; ++j) {
127     if (covered_cases.find(j) == covered_cases.end()) {
128       this->BindCaseTargetForJumpTable(j, nullptr);
129     }
130   }
131 }
132 
BindDefault(CaseClause * clause)133 void SwitchBuilder::BindDefault(CaseClause* clause) {
134   default_.Bind(builder());
135   BuildBlockCoverage(clause);
136 }
137 
JumpToDefault()138 void SwitchBuilder::JumpToDefault() { this->EmitJump(&default_); }
139 
JumpToFallThroughIfFalse()140 void SwitchBuilder::JumpToFallThroughIfFalse() {
141   this->EmitJumpIfFalse(BytecodeArrayBuilder::ToBooleanMode::kAlreadyBoolean,
142                         &fall_through_);
143 }
144 
~TryCatchBuilder()145 TryCatchBuilder::~TryCatchBuilder() {
146   if (block_coverage_builder_ != nullptr) {
147     block_coverage_builder_->IncrementBlockCounter(
148         statement_, SourceRangeKind::kContinuation);
149   }
150 }
151 
BeginTry(Register context)152 void TryCatchBuilder::BeginTry(Register context) {
153   builder()->MarkTryBegin(handler_id_, context);
154 }
155 
156 
EndTry()157 void TryCatchBuilder::EndTry() {
158   builder()->MarkTryEnd(handler_id_);
159   builder()->Jump(&exit_);
160   builder()->MarkHandler(handler_id_, catch_prediction_);
161 
162   if (block_coverage_builder_ != nullptr) {
163     block_coverage_builder_->IncrementBlockCounter(statement_,
164                                                    SourceRangeKind::kCatch);
165   }
166 }
167 
EndCatch()168 void TryCatchBuilder::EndCatch() { builder()->Bind(&exit_); }
169 
~TryFinallyBuilder()170 TryFinallyBuilder::~TryFinallyBuilder() {
171   if (block_coverage_builder_ != nullptr) {
172     block_coverage_builder_->IncrementBlockCounter(
173         statement_, SourceRangeKind::kContinuation);
174   }
175 }
176 
BeginTry(Register context)177 void TryFinallyBuilder::BeginTry(Register context) {
178   builder()->MarkTryBegin(handler_id_, context);
179 }
180 
181 
LeaveTry()182 void TryFinallyBuilder::LeaveTry() {
183   builder()->Jump(finalization_sites_.New());
184 }
185 
186 
EndTry()187 void TryFinallyBuilder::EndTry() {
188   builder()->MarkTryEnd(handler_id_);
189 }
190 
191 
BeginHandler()192 void TryFinallyBuilder::BeginHandler() {
193   builder()->Bind(&handler_);
194   builder()->MarkHandler(handler_id_, catch_prediction_);
195 }
196 
BeginFinally()197 void TryFinallyBuilder::BeginFinally() {
198   finalization_sites_.Bind(builder());
199 
200   if (block_coverage_builder_ != nullptr) {
201     block_coverage_builder_->IncrementBlockCounter(statement_,
202                                                    SourceRangeKind::kFinally);
203   }
204 }
205 
EndFinally()206 void TryFinallyBuilder::EndFinally() {
207   // Nothing to be done here.
208 }
209 
~ConditionalControlFlowBuilder()210 ConditionalControlFlowBuilder::~ConditionalControlFlowBuilder() {
211   if (!else_labels_.is_bound()) else_labels_.Bind(builder());
212   end_labels_.Bind(builder());
213 
214   DCHECK(end_labels_.empty() || end_labels_.is_bound());
215   DCHECK(then_labels_.empty() || then_labels_.is_bound());
216   DCHECK(else_labels_.empty() || else_labels_.is_bound());
217 
218   // IfStatement requires a continuation counter, Conditional does not (as it
219   // can only contain expressions).
220   if (block_coverage_builder_ != nullptr && node_->IsIfStatement()) {
221     block_coverage_builder_->IncrementBlockCounter(
222         node_, SourceRangeKind::kContinuation);
223   }
224 }
225 
JumpToEnd()226 void ConditionalControlFlowBuilder::JumpToEnd() {
227   DCHECK(end_labels_.empty());  // May only be called once.
228   builder()->Jump(end_labels_.New());
229 }
230 
Then()231 void ConditionalControlFlowBuilder::Then() {
232   then_labels()->Bind(builder());
233   if (block_coverage_builder_ != nullptr) {
234     block_coverage_builder_->IncrementBlockCounter(block_coverage_then_slot_);
235   }
236 }
237 
Else()238 void ConditionalControlFlowBuilder::Else() {
239   else_labels()->Bind(builder());
240   if (block_coverage_builder_ != nullptr) {
241     block_coverage_builder_->IncrementBlockCounter(block_coverage_else_slot_);
242   }
243 }
244 
245 }  // namespace interpreter
246 }  // namespace internal
247 }  // namespace v8
248