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
~BreakableControlFlowBuilder()13 BreakableControlFlowBuilder::~BreakableControlFlowBuilder() {
14 BindBreakTarget();
15 DCHECK(break_labels_.empty() || break_labels_.is_bound());
16 if (block_coverage_builder_ != nullptr && needs_continuation_counter()) {
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 }
51
LoopHeader()52 void LoopBuilder::LoopHeader() {
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
LoopBody()61 void LoopBuilder::LoopBody() {
62 if (block_coverage_builder_ != nullptr) {
63 block_coverage_builder_->IncrementBlockCounter(block_coverage_body_slot_);
64 }
65 }
66
JumpToHeader(int loop_depth)67 void LoopBuilder::JumpToHeader(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 DCHECK(loop_header_.is_bound());
74 builder()->JumpLoop(&loop_header_, level);
75 }
76
BindContinueTarget()77 void LoopBuilder::BindContinueTarget() { continue_labels_.Bind(builder()); }
78
~SwitchBuilder()79 SwitchBuilder::~SwitchBuilder() {
80 #ifdef DEBUG
81 for (auto site : case_sites_) {
82 DCHECK(site.is_bound());
83 }
84 #endif
85 }
86
SetCaseTarget(int index,CaseClause * clause)87 void SwitchBuilder::SetCaseTarget(int index, CaseClause* clause) {
88 BytecodeLabel& site = case_sites_.at(index);
89 builder()->Bind(&site);
90 if (block_coverage_builder_) {
91 block_coverage_builder_->IncrementBlockCounter(clause,
92 SourceRangeKind::kBody);
93 }
94 }
95
~TryCatchBuilder()96 TryCatchBuilder::~TryCatchBuilder() {
97 if (block_coverage_builder_ != nullptr) {
98 block_coverage_builder_->IncrementBlockCounter(
99 statement_, SourceRangeKind::kContinuation);
100 }
101 }
102
BeginTry(Register context)103 void TryCatchBuilder::BeginTry(Register context) {
104 builder()->MarkTryBegin(handler_id_, context);
105 }
106
107
EndTry()108 void TryCatchBuilder::EndTry() {
109 builder()->MarkTryEnd(handler_id_);
110 builder()->Jump(&exit_);
111 builder()->Bind(&handler_);
112 builder()->MarkHandler(handler_id_, catch_prediction_);
113
114 if (block_coverage_builder_ != nullptr) {
115 block_coverage_builder_->IncrementBlockCounter(statement_,
116 SourceRangeKind::kCatch);
117 }
118 }
119
EndCatch()120 void TryCatchBuilder::EndCatch() { builder()->Bind(&exit_); }
121
~TryFinallyBuilder()122 TryFinallyBuilder::~TryFinallyBuilder() {
123 if (block_coverage_builder_ != nullptr) {
124 block_coverage_builder_->IncrementBlockCounter(
125 statement_, SourceRangeKind::kContinuation);
126 }
127 }
128
BeginTry(Register context)129 void TryFinallyBuilder::BeginTry(Register context) {
130 builder()->MarkTryBegin(handler_id_, context);
131 }
132
133
LeaveTry()134 void TryFinallyBuilder::LeaveTry() {
135 builder()->Jump(finalization_sites_.New());
136 }
137
138
EndTry()139 void TryFinallyBuilder::EndTry() {
140 builder()->MarkTryEnd(handler_id_);
141 }
142
143
BeginHandler()144 void TryFinallyBuilder::BeginHandler() {
145 builder()->Bind(&handler_);
146 builder()->MarkHandler(handler_id_, catch_prediction_);
147 }
148
BeginFinally()149 void TryFinallyBuilder::BeginFinally() {
150 finalization_sites_.Bind(builder());
151
152 if (block_coverage_builder_ != nullptr) {
153 block_coverage_builder_->IncrementBlockCounter(statement_,
154 SourceRangeKind::kFinally);
155 }
156 }
157
EndFinally()158 void TryFinallyBuilder::EndFinally() {
159 // Nothing to be done here.
160 }
161
~ConditionalControlFlowBuilder()162 ConditionalControlFlowBuilder::~ConditionalControlFlowBuilder() {
163 if (!else_labels_.is_bound()) else_labels_.Bind(builder());
164 end_labels_.Bind(builder());
165
166 DCHECK(end_labels_.empty() || end_labels_.is_bound());
167 DCHECK(then_labels_.empty() || then_labels_.is_bound());
168 DCHECK(else_labels_.empty() || else_labels_.is_bound());
169
170 // IfStatement requires a continuation counter, Conditional does not (as it
171 // can only contain expressions).
172 if (block_coverage_builder_ != nullptr && node_->IsIfStatement()) {
173 block_coverage_builder_->IncrementBlockCounter(
174 node_, SourceRangeKind::kContinuation);
175 }
176 }
177
JumpToEnd()178 void ConditionalControlFlowBuilder::JumpToEnd() {
179 DCHECK(end_labels_.empty()); // May only be called once.
180 builder()->Jump(end_labels_.New());
181 }
182
Then()183 void ConditionalControlFlowBuilder::Then() {
184 then_labels()->Bind(builder());
185 if (block_coverage_builder_ != nullptr) {
186 block_coverage_builder_->IncrementBlockCounter(block_coverage_then_slot_);
187 }
188 }
189
Else()190 void ConditionalControlFlowBuilder::Else() {
191 else_labels()->Bind(builder());
192 if (block_coverage_builder_ != nullptr) {
193 block_coverage_builder_->IncrementBlockCounter(block_coverage_else_slot_);
194 }
195 }
196
197 } // namespace interpreter
198 } // namespace internal
199 } // namespace v8
200