• 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 nesting level to the backwards branch, to trigger
81     // on-stack replacement when armed for the given loop nesting depth.
82     int level = Min(loop_depth, AbstractCode::kMaxLoopNestingMarker - 1);
83     // Loop must have closed form, i.e. all loop elements are within the loop,
84     // the loop header precedes the body and next elements in the loop.
85     builder()->JumpLoop(&loop_header_, level, source_position_);
86   }
87 }
88 
BindContinueTarget()89 void LoopBuilder::BindContinueTarget() { continue_labels_.Bind(builder()); }
90 
BindLoopEnd()91 void LoopBuilder::BindLoopEnd() { end_labels_.Bind(builder()); }
92 
~SwitchBuilder()93 SwitchBuilder::~SwitchBuilder() {
94 #ifdef DEBUG
95   for (auto site : case_sites_) {
96     DCHECK(!site.has_referrer_jump() || site.is_bound());
97   }
98 #endif
99 }
100 
SetCaseTarget(int index,CaseClause * clause)101 void SwitchBuilder::SetCaseTarget(int index, CaseClause* clause) {
102   BytecodeLabel& site = case_sites_.at(index);
103   builder()->Bind(&site);
104   if (block_coverage_builder_) {
105     block_coverage_builder_->IncrementBlockCounter(clause,
106                                                    SourceRangeKind::kBody);
107   }
108 }
109 
~TryCatchBuilder()110 TryCatchBuilder::~TryCatchBuilder() {
111   if (block_coverage_builder_ != nullptr) {
112     block_coverage_builder_->IncrementBlockCounter(
113         statement_, SourceRangeKind::kContinuation);
114   }
115 }
116 
BeginTry(Register context)117 void TryCatchBuilder::BeginTry(Register context) {
118   builder()->MarkTryBegin(handler_id_, context);
119 }
120 
121 
EndTry()122 void TryCatchBuilder::EndTry() {
123   builder()->MarkTryEnd(handler_id_);
124   builder()->Jump(&exit_);
125   builder()->MarkHandler(handler_id_, catch_prediction_);
126 
127   if (block_coverage_builder_ != nullptr) {
128     block_coverage_builder_->IncrementBlockCounter(statement_,
129                                                    SourceRangeKind::kCatch);
130   }
131 }
132 
EndCatch()133 void TryCatchBuilder::EndCatch() { builder()->Bind(&exit_); }
134 
~TryFinallyBuilder()135 TryFinallyBuilder::~TryFinallyBuilder() {
136   if (block_coverage_builder_ != nullptr) {
137     block_coverage_builder_->IncrementBlockCounter(
138         statement_, SourceRangeKind::kContinuation);
139   }
140 }
141 
BeginTry(Register context)142 void TryFinallyBuilder::BeginTry(Register context) {
143   builder()->MarkTryBegin(handler_id_, context);
144 }
145 
146 
LeaveTry()147 void TryFinallyBuilder::LeaveTry() {
148   builder()->Jump(finalization_sites_.New());
149 }
150 
151 
EndTry()152 void TryFinallyBuilder::EndTry() {
153   builder()->MarkTryEnd(handler_id_);
154 }
155 
156 
BeginHandler()157 void TryFinallyBuilder::BeginHandler() {
158   builder()->Bind(&handler_);
159   builder()->MarkHandler(handler_id_, catch_prediction_);
160 }
161 
BeginFinally()162 void TryFinallyBuilder::BeginFinally() {
163   finalization_sites_.Bind(builder());
164 
165   if (block_coverage_builder_ != nullptr) {
166     block_coverage_builder_->IncrementBlockCounter(statement_,
167                                                    SourceRangeKind::kFinally);
168   }
169 }
170 
EndFinally()171 void TryFinallyBuilder::EndFinally() {
172   // Nothing to be done here.
173 }
174 
~ConditionalControlFlowBuilder()175 ConditionalControlFlowBuilder::~ConditionalControlFlowBuilder() {
176   if (!else_labels_.is_bound()) else_labels_.Bind(builder());
177   end_labels_.Bind(builder());
178 
179   DCHECK(end_labels_.empty() || end_labels_.is_bound());
180   DCHECK(then_labels_.empty() || then_labels_.is_bound());
181   DCHECK(else_labels_.empty() || else_labels_.is_bound());
182 
183   // IfStatement requires a continuation counter, Conditional does not (as it
184   // can only contain expressions).
185   if (block_coverage_builder_ != nullptr && node_->IsIfStatement()) {
186     block_coverage_builder_->IncrementBlockCounter(
187         node_, SourceRangeKind::kContinuation);
188   }
189 }
190 
JumpToEnd()191 void ConditionalControlFlowBuilder::JumpToEnd() {
192   DCHECK(end_labels_.empty());  // May only be called once.
193   builder()->Jump(end_labels_.New());
194 }
195 
Then()196 void ConditionalControlFlowBuilder::Then() {
197   then_labels()->Bind(builder());
198   if (block_coverage_builder_ != nullptr) {
199     block_coverage_builder_->IncrementBlockCounter(block_coverage_then_slot_);
200   }
201 }
202 
Else()203 void ConditionalControlFlowBuilder::Else() {
204   else_labels()->Bind(builder());
205   if (block_coverage_builder_ != nullptr) {
206     block_coverage_builder_->IncrementBlockCounter(block_coverage_else_slot_);
207   }
208 }
209 
210 }  // namespace interpreter
211 }  // namespace internal
212 }  // namespace v8
213