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