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) {
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