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