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
8namespace v8 {
9namespace internal {
10namespace interpreter {
11
12
13BreakableControlFlowBuilder::~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
22void BreakableControlFlowBuilder::BindBreakTarget() {
23 break_labels_.Bind(builder());
24}
25
26void BreakableControlFlowBuilder::EmitJump(BytecodeLabels* sites) {
27 builder()->Jump(sites->New());
28}
29
30void BreakableControlFlowBuilder::EmitJumpIfTrue(
31 BytecodeArrayBuilder::ToBooleanMode mode, BytecodeLabels* sites) {
32 builder()->JumpIfTrue(mode, sites->New());
33}
34
35void BreakableControlFlowBuilder::EmitJumpIfFalse(
36 BytecodeArrayBuilder::ToBooleanMode mode, BytecodeLabels* sites) {
37 builder()->JumpIfFalse(mode, sites->New());
38}
39
40void BreakableControlFlowBuilder::EmitJumpIfUndefined(BytecodeLabels* sites) {
41 builder()->JumpIfUndefined(sites->New());
42}
43
44void BreakableControlFlowBuilder::EmitJumpIfNull(BytecodeLabels* sites) {
45 builder()->JumpIfNull(sites->New());
46}
47
48LoopBuilder::~LoopBuilder() {
49 DCHECK(continue_labels_.empty() || continue_labels_.is_bound());
50}
51
52void 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
61void LoopBuilder::LoopBody() {
62 if (block_coverage_builder_ != nullptr) {
63 block_coverage_builder_->IncrementBlockCounter(block_coverage_body_slot_);
64 }
65}
66
67void 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 builder()->JumpLoop(&loop_header_, level);
74}
75
76void LoopBuilder::BindContinueTarget() { continue_labels_.Bind(builder()); }
77
78SwitchBuilder::~SwitchBuilder() {
79#ifdef DEBUG
80 for (auto site : case_sites_) {
81 DCHECK(!site.has_referrer_jump() || site.is_bound());
82 }
83#endif
84}
85
86void 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
95TryCatchBuilder::~TryCatchBuilder() {
96 if (block_coverage_builder_ != nullptr) {
97 block_coverage_builder_->IncrementBlockCounter(
98 statement_, SourceRangeKind::kContinuation);
99 }
100}
101
102void TryCatchBuilder::BeginTry(Register context) {
103 builder()->MarkTryBegin(handler_id_, context);
104}
105
106
107void 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
118void TryCatchBuilder::EndCatch() { builder()->Bind(&exit_); }
119
120TryFinallyBuilder::~TryFinallyBuilder() {
121 if (block_coverage_builder_ != nullptr) {
122 block_coverage_builder_->IncrementBlockCounter(
123 statement_, SourceRangeKind::kContinuation);
124 }
125}
126
127void TryFinallyBuilder::BeginTry(Register context) {
128 builder()->MarkTryBegin(handler_id_, context);
129}
130
131
132void TryFinallyBuilder::LeaveTry() {
133 builder()->Jump(finalization_sites_.New());
134}
135
136
137void TryFinallyBuilder::EndTry() {
138 builder()->MarkTryEnd(handler_id_);
139}
140
141
142void TryFinallyBuilder::BeginHandler() {
143 builder()->Bind(&handler_);
144 builder()->MarkHandler(handler_id_, catch_prediction_);
145}
146
147void 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
156void TryFinallyBuilder::EndFinally() {
157 // Nothing to be done here.
158}
159
160ConditionalControlFlowBuilder::~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
176void ConditionalControlFlowBuilder::JumpToEnd() {
177 DCHECK(end_labels_.empty()); // May only be called once.
178 builder()->Jump(end_labels_.New());
179}
180
181void 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
188void 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