| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/bytecode-analysis.h" | 5 #include "src/compiler/bytecode-analysis.h" |
| 6 | 6 |
| 7 #include "src/interpreter/bytecode-array-iterator.h" | 7 #include "src/interpreter/bytecode-array-iterator.h" |
| 8 #include "src/interpreter/bytecode-array-random-iterator.h" | 8 #include "src/interpreter/bytecode-array-random-iterator.h" |
| 9 #include "src/objects-inl.h" | 9 #include "src/objects-inl.h" |
| 10 | 10 |
| 11 namespace v8 { | 11 namespace v8 { |
| 12 namespace internal { | 12 namespace internal { |
| 13 namespace compiler { | 13 namespace compiler { |
| 14 | 14 |
| 15 using namespace interpreter; | 15 using namespace interpreter; |
| 16 | 16 |
| 17 BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array, | 17 BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array, |
| 18 Zone* zone, bool do_liveness_analysis) | 18 Zone* zone, bool do_liveness_analysis) |
| 19 : bytecode_array_(bytecode_array), | 19 : bytecode_array_(bytecode_array), |
| 20 do_liveness_analysis_(do_liveness_analysis), | 20 do_liveness_analysis_(do_liveness_analysis), |
| 21 zone_(zone), | 21 zone_(zone), |
| 22 loop_stack_(zone), | 22 loop_stack_(zone), |
| 23 loop_end_index_queue_(zone), | 23 loop_end_index_queue_(zone), |
| 24 end_to_header_(zone), | 24 end_to_header_(zone), |
| 25 header_to_parent_(zone), | 25 header_to_parent_(zone), |
| 26 liveness_map_(bytecode_array->length(), zone) {} | 26 liveness_map_(bytecode_array->length(), zone) {} |
| 27 | 27 |
| 28 namespace { | 28 namespace { |
| 29 | 29 |
| 30 void UpdateInLiveness(Bytecode bytecode, BitVector& in_liveness, | 30 void UpdateInLiveness(Bytecode bytecode, BytecodeLivenessState& in_liveness, |
| 31 const BytecodeArrayAccessor& accessor) { | 31 const BytecodeArrayAccessor& accessor) { |
| 32 int num_operands = Bytecodes::NumberOfOperands(bytecode); | 32 int num_operands = Bytecodes::NumberOfOperands(bytecode); |
| 33 const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode); | 33 const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode); |
| 34 AccumulatorUse accumulator_use = Bytecodes::GetAccumulatorUse(bytecode); | 34 AccumulatorUse accumulator_use = Bytecodes::GetAccumulatorUse(bytecode); |
| 35 | 35 |
| 36 if (accumulator_use == AccumulatorUse::kWrite) { | 36 if (accumulator_use == AccumulatorUse::kWrite) { |
| 37 in_liveness.Remove(in_liveness.length() - 1); | 37 in_liveness.MarkAccumulatorDead(); |
| 38 } | 38 } |
| 39 for (int i = 0; i < num_operands; ++i) { | 39 for (int i = 0; i < num_operands; ++i) { |
| 40 switch (operand_types[i]) { | 40 switch (operand_types[i]) { |
| 41 case OperandType::kRegOut: { | 41 case OperandType::kRegOut: { |
| 42 interpreter::Register r = accessor.GetRegisterOperand(i); | 42 interpreter::Register r = accessor.GetRegisterOperand(i); |
| 43 if (!r.is_parameter()) { | 43 if (!r.is_parameter()) { |
| 44 in_liveness.Remove(r.index()); | 44 in_liveness.MarkRegisterDead(r.index()); |
| 45 } | 45 } |
| 46 break; | 46 break; |
| 47 } | 47 } |
| 48 case OperandType::kRegOutPair: { | 48 case OperandType::kRegOutPair: { |
| 49 interpreter::Register r = accessor.GetRegisterOperand(i); | 49 interpreter::Register r = accessor.GetRegisterOperand(i); |
| 50 if (!r.is_parameter()) { | 50 if (!r.is_parameter()) { |
| 51 DCHECK(!interpreter::Register(r.index() + 1).is_parameter()); | 51 DCHECK(!interpreter::Register(r.index() + 1).is_parameter()); |
| 52 in_liveness.Remove(r.index()); | 52 in_liveness.MarkRegisterDead(r.index()); |
| 53 in_liveness.Remove(r.index() + 1); | 53 in_liveness.MarkRegisterDead(r.index() + 1); |
| 54 } | 54 } |
| 55 break; | 55 break; |
| 56 } | 56 } |
| 57 case OperandType::kRegOutTriple: { | 57 case OperandType::kRegOutTriple: { |
| 58 interpreter::Register r = accessor.GetRegisterOperand(i); | 58 interpreter::Register r = accessor.GetRegisterOperand(i); |
| 59 if (!r.is_parameter()) { | 59 if (!r.is_parameter()) { |
| 60 DCHECK(!interpreter::Register(r.index() + 1).is_parameter()); | 60 DCHECK(!interpreter::Register(r.index() + 1).is_parameter()); |
| 61 DCHECK(!interpreter::Register(r.index() + 2).is_parameter()); | 61 DCHECK(!interpreter::Register(r.index() + 2).is_parameter()); |
| 62 in_liveness.Remove(r.index()); | 62 in_liveness.MarkRegisterDead(r.index()); |
| 63 in_liveness.Remove(r.index() + 1); | 63 in_liveness.MarkRegisterDead(r.index() + 1); |
| 64 in_liveness.Remove(r.index() + 2); | 64 in_liveness.MarkRegisterDead(r.index() + 2); |
| 65 } | 65 } |
| 66 break; | 66 break; |
| 67 } | 67 } |
| 68 default: | 68 default: |
| 69 DCHECK(!Bytecodes::IsRegisterOutputOperandType(operand_types[i])); | 69 DCHECK(!Bytecodes::IsRegisterOutputOperandType(operand_types[i])); |
| 70 break; | 70 break; |
| 71 } | 71 } |
| 72 } | 72 } |
| 73 | 73 |
| 74 if (accumulator_use == AccumulatorUse::kRead) { | 74 if (accumulator_use == AccumulatorUse::kRead) { |
| 75 in_liveness.Add(in_liveness.length() - 1); | 75 in_liveness.MarkAccumulatorLive(); |
| 76 } | 76 } |
| 77 for (int i = 0; i < num_operands; ++i) { | 77 for (int i = 0; i < num_operands; ++i) { |
| 78 switch (operand_types[i]) { | 78 switch (operand_types[i]) { |
| 79 case OperandType::kReg: { | 79 case OperandType::kReg: { |
| 80 interpreter::Register r = accessor.GetRegisterOperand(i); | 80 interpreter::Register r = accessor.GetRegisterOperand(i); |
| 81 if (!r.is_parameter()) { | 81 if (!r.is_parameter()) { |
| 82 in_liveness.Add(r.index()); | 82 in_liveness.MarkRegisterLive(r.index()); |
| 83 } | 83 } |
| 84 break; | 84 break; |
| 85 } | 85 } |
| 86 case OperandType::kRegPair: { | 86 case OperandType::kRegPair: { |
| 87 interpreter::Register r = accessor.GetRegisterOperand(i); | 87 interpreter::Register r = accessor.GetRegisterOperand(i); |
| 88 if (!r.is_parameter()) { | 88 if (!r.is_parameter()) { |
| 89 DCHECK(!interpreter::Register(r.index() + 1).is_parameter()); | 89 DCHECK(!interpreter::Register(r.index() + 1).is_parameter()); |
| 90 in_liveness.Add(r.index()); | 90 in_liveness.MarkRegisterLive(r.index()); |
| 91 in_liveness.Add(r.index() + 1); | 91 in_liveness.MarkRegisterLive(r.index() + 1); |
| 92 } | 92 } |
| 93 break; | 93 break; |
| 94 } | 94 } |
| 95 case OperandType::kRegList: { | 95 case OperandType::kRegList: { |
| 96 interpreter::Register r = accessor.GetRegisterOperand(i++); | 96 interpreter::Register r = accessor.GetRegisterOperand(i++); |
| 97 uint32_t reg_count = accessor.GetRegisterCountOperand(i); | 97 uint32_t reg_count = accessor.GetRegisterCountOperand(i); |
| 98 if (!r.is_parameter()) { | 98 if (!r.is_parameter()) { |
| 99 for (uint32_t j = 0; j < reg_count; ++j) { | 99 for (uint32_t j = 0; j < reg_count; ++j) { |
| 100 DCHECK(!interpreter::Register(r.index() + j).is_parameter()); | 100 DCHECK(!interpreter::Register(r.index() + j).is_parameter()); |
| 101 in_liveness.Add(r.index() + j); | 101 in_liveness.MarkRegisterLive(r.index() + j); |
| 102 } | 102 } |
| 103 } | 103 } |
| 104 } | 104 } |
| 105 default: | 105 default: |
| 106 DCHECK(!Bytecodes::IsRegisterInputOperandType(operand_types[i])); | 106 DCHECK(!Bytecodes::IsRegisterInputOperandType(operand_types[i])); |
| 107 break; | 107 break; |
| 108 } | 108 } |
| 109 } | 109 } |
| 110 } | 110 } |
| 111 | 111 |
| 112 void UpdateOutLiveness(Bytecode bytecode, BitVector& out_liveness, | 112 void UpdateOutLiveness(Bytecode bytecode, BytecodeLivenessState& out_liveness, |
| 113 BitVector* next_bytecode_in_liveness, | 113 BytecodeLivenessState* next_bytecode_in_liveness, |
| 114 const BytecodeArrayAccessor& accessor, | 114 const BytecodeArrayAccessor& accessor, |
| 115 const BytecodeLivenessMap& liveness_map) { | 115 const BytecodeLivenessMap& liveness_map) { |
| 116 int current_offset = accessor.current_offset(); | 116 int current_offset = accessor.current_offset(); |
| 117 const Handle<BytecodeArray>& bytecode_array = accessor.bytecode_array(); | 117 const Handle<BytecodeArray>& bytecode_array = accessor.bytecode_array(); |
| 118 | 118 |
| 119 // Update from jump target (if any). Skip loops, we update these manually in | 119 // Update from jump target (if any). Skip loops, we update these manually in |
| 120 // the liveness iterations. | 120 // the liveness iterations. |
| 121 if (Bytecodes::IsForwardJump(bytecode)) { | 121 if (Bytecodes::IsForwardJump(bytecode)) { |
| 122 int target_offset = accessor.GetJumpTargetOffset(); | 122 int target_offset = accessor.GetJumpTargetOffset(); |
| 123 out_liveness.Union(*liveness_map.GetInLiveness(target_offset)); | 123 out_liveness.Union(*liveness_map.GetInLiveness(target_offset)); |
| 124 } | 124 } |
| 125 | 125 |
| 126 // Update from next bytecode (unless there isn't one or this is an | 126 // Update from next bytecode (unless there isn't one or this is an |
| 127 // unconditional jump). | 127 // unconditional jump). |
| 128 if (next_bytecode_in_liveness != nullptr && | 128 if (next_bytecode_in_liveness != nullptr && |
| 129 !Bytecodes::IsUnconditionalJump(bytecode)) { | 129 !Bytecodes::IsUnconditionalJump(bytecode)) { |
| 130 out_liveness.Union(*next_bytecode_in_liveness); | 130 out_liveness.Union(*next_bytecode_in_liveness); |
| 131 } | 131 } |
| 132 | 132 |
| 133 // Update from exception handler (if any). | 133 // Update from exception handler (if any). |
| 134 if (!interpreter::Bytecodes::IsWithoutExternalSideEffects(bytecode)) { | 134 if (!interpreter::Bytecodes::IsWithoutExternalSideEffects(bytecode)) { |
| 135 int handler_context; | 135 int handler_context; |
| 136 // TODO(leszeks): We should look up this range only once per entry. | 136 // TODO(leszeks): We should look up this range only once per entry. |
| 137 HandlerTable* table = HandlerTable::cast(bytecode_array->handler_table()); | 137 HandlerTable* table = HandlerTable::cast(bytecode_array->handler_table()); |
| 138 int handler_offset = | 138 int handler_offset = |
| 139 table->LookupRange(current_offset, &handler_context, nullptr); | 139 table->LookupRange(current_offset, &handler_context, nullptr); |
| 140 | 140 |
| 141 if (handler_offset != -1) { | 141 if (handler_offset != -1) { |
| 142 out_liveness.Union(*liveness_map.GetInLiveness(handler_offset)); | 142 out_liveness.Union(*liveness_map.GetInLiveness(handler_offset)); |
| 143 out_liveness.Add(handler_context); | 143 out_liveness.MarkRegisterLive(handler_context); |
| 144 } | 144 } |
| 145 } | 145 } |
| 146 } | 146 } |
| 147 | 147 |
| 148 } // namespace | 148 } // namespace |
| 149 | 149 |
| 150 void BytecodeAnalysis::Analyze() { | 150 void BytecodeAnalysis::Analyze() { |
| 151 loop_stack_.push(-1); | 151 loop_stack_.push(-1); |
| 152 | 152 |
| 153 BitVector* next_bytecode_in_liveness = nullptr; | 153 BytecodeLivenessState* next_bytecode_in_liveness = nullptr; |
| 154 | 154 |
| 155 BytecodeArrayRandomIterator iterator(bytecode_array(), zone()); | 155 BytecodeArrayRandomIterator iterator(bytecode_array(), zone()); |
| 156 for (iterator.GoToEnd(); iterator.IsValid(); --iterator) { | 156 for (iterator.GoToEnd(); iterator.IsValid(); --iterator) { |
| 157 Bytecode bytecode = iterator.current_bytecode(); | 157 Bytecode bytecode = iterator.current_bytecode(); |
| 158 int current_offset = iterator.current_offset(); | 158 int current_offset = iterator.current_offset(); |
| 159 | 159 |
| 160 if (bytecode == Bytecode::kJumpLoop) { | 160 if (bytecode == Bytecode::kJumpLoop) { |
| 161 // Every byte up to and including the last byte within the backwards jump | 161 // Every byte up to and including the last byte within the backwards jump |
| 162 // instruction is considered part of the loop, set loop end accordingly. | 162 // instruction is considered part of the loop, set loop end accordingly. |
| 163 int loop_end = current_offset + iterator.current_bytecode_size(); | 163 int loop_end = current_offset + iterator.current_bytecode_size(); |
| 164 PushLoop(iterator.GetJumpTargetOffset(), loop_end); | 164 PushLoop(iterator.GetJumpTargetOffset(), loop_end); |
| 165 | 165 |
| 166 // Save the index so that we can do another pass later. | 166 // Save the index so that we can do another pass later. |
| 167 if (do_liveness_analysis_) { | 167 if (do_liveness_analysis_) { |
| 168 loop_end_index_queue_.push_back(iterator.current_index()); | 168 loop_end_index_queue_.push_back(iterator.current_index()); |
| 169 } | 169 } |
| 170 } else if (current_offset == loop_stack_.top()) { | 170 } else if (current_offset == loop_stack_.top()) { |
| 171 loop_stack_.pop(); | 171 loop_stack_.pop(); |
| 172 } | 172 } |
| 173 | 173 |
| 174 if (do_liveness_analysis_) { | 174 if (do_liveness_analysis_) { |
| 175 // The liveness vector had bits for the liveness of the registers, and one | 175 BytecodeLiveness& liveness = liveness_map_.InitializeLiveness( |
| 176 // more bit for the liveness of the accumulator. | 176 current_offset, bytecode_array()->register_count(), zone()); |
| 177 Liveness& liveness = liveness_map_.InitializeLiveness( | |
| 178 current_offset, bytecode_array()->register_count() + 1, zone()); | |
| 179 | 177 |
| 180 UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness, | 178 UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness, |
| 181 iterator, liveness_map_); | 179 iterator, liveness_map_); |
| 182 liveness.in->CopyFrom(*liveness.out); | 180 liveness.in->CopyFrom(*liveness.out); |
| 183 UpdateInLiveness(bytecode, *liveness.in, iterator); | 181 UpdateInLiveness(bytecode, *liveness.in, iterator); |
| 184 | 182 |
| 185 next_bytecode_in_liveness = liveness.in; | 183 next_bytecode_in_liveness = liveness.in; |
| 186 } | 184 } |
| 187 } | 185 } |
| 188 | 186 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 217 // outer-to-inner requirements. | 215 // outer-to-inner requirements. |
| 218 | 216 |
| 219 for (int loop_end_index : loop_end_index_queue_) { | 217 for (int loop_end_index : loop_end_index_queue_) { |
| 220 iterator.GoToIndex(loop_end_index); | 218 iterator.GoToIndex(loop_end_index); |
| 221 | 219 |
| 222 DCHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpLoop); | 220 DCHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpLoop); |
| 223 | 221 |
| 224 int header_offset = iterator.GetJumpTargetOffset(); | 222 int header_offset = iterator.GetJumpTargetOffset(); |
| 225 int end_offset = iterator.current_offset(); | 223 int end_offset = iterator.current_offset(); |
| 226 | 224 |
| 227 Liveness& header_liveness = liveness_map_.GetLiveness(header_offset); | 225 BytecodeLiveness& header_liveness = |
| 228 Liveness& end_liveness = liveness_map_.GetLiveness(end_offset); | 226 liveness_map_.GetLiveness(header_offset); |
| 227 BytecodeLiveness& end_liveness = liveness_map_.GetLiveness(end_offset); |
| 229 | 228 |
| 230 if (!end_liveness.out->UnionIsChanged(*header_liveness.in)) { | 229 if (!end_liveness.out->UnionIsChanged(*header_liveness.in)) { |
| 231 // Only update the loop body if the loop end liveness changed. | 230 // Only update the loop body if the loop end liveness changed. |
| 232 continue; | 231 continue; |
| 233 } | 232 } |
| 234 end_liveness.in->CopyFrom(*end_liveness.out); | 233 end_liveness.in->CopyFrom(*end_liveness.out); |
| 235 next_bytecode_in_liveness = end_liveness.in; | 234 next_bytecode_in_liveness = end_liveness.in; |
| 236 | 235 |
| 237 // Advance into the loop body. | 236 // Advance into the loop body. |
| 238 --iterator; | 237 --iterator; |
| 239 for (; iterator.current_offset() > header_offset; --iterator) { | 238 for (; iterator.current_offset() > header_offset; --iterator) { |
| 240 Bytecode bytecode = iterator.current_bytecode(); | 239 Bytecode bytecode = iterator.current_bytecode(); |
| 241 | 240 |
| 242 int current_offset = iterator.current_offset(); | 241 int current_offset = iterator.current_offset(); |
| 243 Liveness& liveness = liveness_map_.GetLiveness(current_offset); | 242 BytecodeLiveness& liveness = liveness_map_.GetLiveness(current_offset); |
| 244 | 243 |
| 245 UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness, | 244 UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness, |
| 246 iterator, liveness_map_); | 245 iterator, liveness_map_); |
| 247 liveness.in->CopyFrom(*liveness.out); | 246 liveness.in->CopyFrom(*liveness.out); |
| 248 UpdateInLiveness(bytecode, *liveness.in, iterator); | 247 UpdateInLiveness(bytecode, *liveness.in, iterator); |
| 249 | 248 |
| 250 next_bytecode_in_liveness = liveness.in; | 249 next_bytecode_in_liveness = liveness.in; |
| 251 } | 250 } |
| 252 // Now we are at the loop header. Since the in-liveness of the header | 251 // Now we are at the loop header. Since the in-liveness of the header |
| 253 // can't change, we need only to update the out-liveness. | 252 // can't change, we need only to update the out-liveness. |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 306 | 305 |
| 307 return header_to_parent_.upper_bound(offset)->second; | 306 return header_to_parent_.upper_bound(offset)->second; |
| 308 } | 307 } |
| 309 | 308 |
| 310 int BytecodeAnalysis::GetParentLoopFor(int header_offset) const { | 309 int BytecodeAnalysis::GetParentLoopFor(int header_offset) const { |
| 311 DCHECK(IsLoopHeader(header_offset)); | 310 DCHECK(IsLoopHeader(header_offset)); |
| 312 | 311 |
| 313 return header_to_parent_.find(header_offset)->second; | 312 return header_to_parent_.find(header_offset)->second; |
| 314 } | 313 } |
| 315 | 314 |
| 316 const BitVector* BytecodeAnalysis::GetInLivenessFor(int offset) const { | 315 const BytecodeLivenessState* BytecodeAnalysis::GetInLivenessFor( |
| 316 int offset) const { |
| 317 if (!do_liveness_analysis_) return nullptr; | 317 if (!do_liveness_analysis_) return nullptr; |
| 318 | 318 |
| 319 return liveness_map_.GetInLiveness(offset); | 319 return liveness_map_.GetInLiveness(offset); |
| 320 } | 320 } |
| 321 | 321 |
| 322 const BitVector* BytecodeAnalysis::GetOutLivenessFor(int offset) const { | 322 const BytecodeLivenessState* BytecodeAnalysis::GetOutLivenessFor( |
| 323 int offset) const { |
| 323 if (!do_liveness_analysis_) return nullptr; | 324 if (!do_liveness_analysis_) return nullptr; |
| 324 | 325 |
| 325 return liveness_map_.GetOutLiveness(offset); | 326 return liveness_map_.GetOutLiveness(offset); |
| 326 } | 327 } |
| 327 | 328 |
| 328 std::ostream& BytecodeAnalysis::PrintLivenessTo(std::ostream& os) const { | 329 std::ostream& BytecodeAnalysis::PrintLivenessTo(std::ostream& os) const { |
| 329 interpreter::BytecodeArrayIterator iterator(bytecode_array()); | 330 interpreter::BytecodeArrayIterator iterator(bytecode_array()); |
| 330 | 331 |
| 331 for (; !iterator.done(); iterator.Advance()) { | 332 for (; !iterator.done(); iterator.Advance()) { |
| 332 int current_offset = iterator.current_offset(); | 333 int current_offset = iterator.current_offset(); |
| 333 | 334 |
| 334 const BitVector* in_liveness = GetInLivenessFor(current_offset); | 335 const BitVector& in_liveness = |
| 335 const BitVector* out_liveness = GetOutLivenessFor(current_offset); | 336 GetInLivenessFor(current_offset)->bit_vector(); |
| 337 const BitVector& out_liveness = |
| 338 GetOutLivenessFor(current_offset)->bit_vector(); |
| 336 | 339 |
| 337 for (int i = 0; i < in_liveness->length(); ++i) { | 340 for (int i = 0; i < in_liveness.length(); ++i) { |
| 338 os << (in_liveness->Contains(i) ? "L" : "."); | 341 os << (in_liveness.Contains(i) ? "L" : "."); |
| 339 } | 342 } |
| 340 os << " -> "; | 343 os << " -> "; |
| 341 | 344 |
| 342 for (int i = 0; i < out_liveness->length(); ++i) { | 345 for (int i = 0; i < out_liveness.length(); ++i) { |
| 343 os << (out_liveness->Contains(i) ? "L" : "."); | 346 os << (out_liveness.Contains(i) ? "L" : "."); |
| 344 } | 347 } |
| 345 | 348 |
| 346 os << " | " << current_offset << ": "; | 349 os << " | " << current_offset << ": "; |
| 347 iterator.PrintTo(os) << std::endl; | 350 iterator.PrintTo(os) << std::endl; |
| 348 } | 351 } |
| 349 | 352 |
| 350 return os; | 353 return os; |
| 351 } | 354 } |
| 352 | 355 |
| 353 #if DEBUG | 356 #if DEBUG |
| 354 bool BytecodeAnalysis::LivenessIsValid() { | 357 bool BytecodeAnalysis::LivenessIsValid() { |
| 355 BytecodeArrayRandomIterator iterator(bytecode_array(), zone()); | 358 BytecodeArrayRandomIterator iterator(bytecode_array(), zone()); |
| 356 | 359 |
| 357 BitVector previous_liveness(bytecode_array()->register_count() + 1, zone()); | 360 BytecodeLivenessState previous_liveness(bytecode_array()->register_count(), |
| 361 zone()); |
| 358 | 362 |
| 359 int invalid_offset = -1; | 363 int invalid_offset = -1; |
| 360 int which_invalid = -1; | 364 int which_invalid = -1; |
| 361 | 365 |
| 362 BitVector* next_bytecode_in_liveness = nullptr; | 366 BytecodeLivenessState* next_bytecode_in_liveness = nullptr; |
| 363 | 367 |
| 364 // Ensure that there are no liveness changes if we iterate one more time. | 368 // Ensure that there are no liveness changes if we iterate one more time. |
| 365 for (iterator.GoToEnd(); iterator.IsValid(); --iterator) { | 369 for (iterator.GoToEnd(); iterator.IsValid(); --iterator) { |
| 366 Bytecode bytecode = iterator.current_bytecode(); | 370 Bytecode bytecode = iterator.current_bytecode(); |
| 367 | 371 |
| 368 int current_offset = iterator.current_offset(); | 372 int current_offset = iterator.current_offset(); |
| 369 | 373 |
| 370 Liveness& liveness = liveness_map_.GetLiveness(current_offset); | 374 BytecodeLiveness& liveness = liveness_map_.GetLiveness(current_offset); |
| 371 | 375 |
| 372 previous_liveness.CopyFrom(*liveness.out); | 376 previous_liveness.CopyFrom(*liveness.out); |
| 373 | 377 |
| 374 UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness, | 378 UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness, |
| 375 iterator, liveness_map_); | 379 iterator, liveness_map_); |
| 376 // UpdateOutLiveness skips kJumpLoop, so we update it manually. | 380 // UpdateOutLiveness skips kJumpLoop, so we update it manually. |
| 377 if (bytecode == Bytecode::kJumpLoop) { | 381 if (bytecode == Bytecode::kJumpLoop) { |
| 378 int target_offset = iterator.GetJumpTargetOffset(); | 382 int target_offset = iterator.GetJumpTargetOffset(); |
| 379 liveness.out->Union(*liveness_map_.GetInLiveness(target_offset)); | 383 liveness.out->Union(*liveness_map_.GetInLiveness(target_offset)); |
| 380 } | 384 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 407 OFStream of(stderr); | 411 OFStream of(stderr); |
| 408 of << "Invalid liveness:" << std::endl; | 412 of << "Invalid liveness:" << std::endl; |
| 409 | 413 |
| 410 // Dump the bytecode, annotated with the liveness and marking loops. | 414 // Dump the bytecode, annotated with the liveness and marking loops. |
| 411 | 415 |
| 412 int loop_indent = 0; | 416 int loop_indent = 0; |
| 413 | 417 |
| 414 BytecodeArrayIterator forward_iterator(bytecode_array()); | 418 BytecodeArrayIterator forward_iterator(bytecode_array()); |
| 415 for (; !forward_iterator.done(); forward_iterator.Advance()) { | 419 for (; !forward_iterator.done(); forward_iterator.Advance()) { |
| 416 int current_offset = forward_iterator.current_offset(); | 420 int current_offset = forward_iterator.current_offset(); |
| 417 BitVector* in_liveness = liveness_map_.GetInLiveness(current_offset); | 421 const BitVector& in_liveness = |
| 418 BitVector* out_liveness = liveness_map_.GetOutLiveness(current_offset); | 422 GetInLivenessFor(current_offset)->bit_vector(); |
| 423 const BitVector& out_liveness = |
| 424 GetOutLivenessFor(current_offset)->bit_vector(); |
| 419 | 425 |
| 420 for (int i = 0; i < in_liveness->length(); ++i) { | 426 for (int i = 0; i < in_liveness.length(); ++i) { |
| 421 of << (in_liveness->Contains(i) ? 'L' : '.'); | 427 of << (in_liveness.Contains(i) ? 'L' : '.'); |
| 422 } | 428 } |
| 423 | 429 |
| 424 of << " | "; | 430 of << " | "; |
| 425 | 431 |
| 426 for (int i = 0; i < out_liveness->length(); ++i) { | 432 for (int i = 0; i < out_liveness.length(); ++i) { |
| 427 of << (out_liveness->Contains(i) ? 'L' : '.'); | 433 of << (out_liveness.Contains(i) ? 'L' : '.'); |
| 428 } | 434 } |
| 429 | 435 |
| 430 of << " : " << current_offset << " : "; | 436 of << " : " << current_offset << " : "; |
| 431 | 437 |
| 432 // Draw loop back edges by indentin everything between loop headers and | 438 // Draw loop back edges by indentin everything between loop headers and |
| 433 // jump loop instructions. | 439 // jump loop instructions. |
| 434 if (forward_iterator.current_bytecode() == Bytecode::kJumpLoop) { | 440 if (forward_iterator.current_bytecode() == Bytecode::kJumpLoop) { |
| 435 loop_indent--; | 441 loop_indent--; |
| 436 } | 442 } |
| 437 for (int i = 0; i < loop_indent; ++i) { | 443 for (int i = 0; i < loop_indent; ++i) { |
| 438 of << " | "; | 444 of << " | "; |
| 439 } | 445 } |
| 440 if (forward_iterator.current_bytecode() == Bytecode::kJumpLoop) { | 446 if (forward_iterator.current_bytecode() == Bytecode::kJumpLoop) { |
| 441 of << " `-" << current_offset; | 447 of << " `-" << current_offset; |
| 442 } else if (IsLoopHeader(current_offset)) { | 448 } else if (IsLoopHeader(current_offset)) { |
| 443 of << " .>" << current_offset; | 449 of << " .>" << current_offset; |
| 444 loop_indent++; | 450 loop_indent++; |
| 445 } | 451 } |
| 446 forward_iterator.PrintTo(of) << std::endl; | 452 forward_iterator.PrintTo(of) << std::endl; |
| 447 | 453 |
| 448 if (current_offset == invalid_offset) { | 454 if (current_offset == invalid_offset) { |
| 449 // Underline the invalid liveness. | 455 // Underline the invalid liveness. |
| 450 if (which_invalid == 0) { | 456 if (which_invalid == 0) { |
| 451 for (int i = 0; i < in_liveness->length(); ++i) { | 457 for (int i = 0; i < in_liveness.length(); ++i) { |
| 452 of << '^'; | 458 of << '^'; |
| 453 } | 459 } |
| 454 } else { | 460 } else { |
| 455 for (int i = 0; i < in_liveness->length() + 3; ++i) { | 461 for (int i = 0; i < in_liveness.length() + 3; ++i) { |
| 456 of << ' '; | 462 of << ' '; |
| 457 } | 463 } |
| 458 for (int i = 0; i < out_liveness->length(); ++i) { | 464 for (int i = 0; i < out_liveness.length(); ++i) { |
| 459 of << '^'; | 465 of << '^'; |
| 460 } | 466 } |
| 461 } | 467 } |
| 462 | 468 |
| 463 // Make sure to draw the loop indentation marks on this additional line. | 469 // Make sure to draw the loop indentation marks on this additional line. |
| 464 of << " : " << current_offset << " : "; | 470 of << " : " << current_offset << " : "; |
| 465 for (int i = 0; i < loop_indent; ++i) { | 471 for (int i = 0; i < loop_indent; ++i) { |
| 466 of << " | "; | 472 of << " | "; |
| 467 } | 473 } |
| 468 | 474 |
| 469 of << std::endl; | 475 of << std::endl; |
| 470 } | 476 } |
| 471 } | 477 } |
| 472 } | 478 } |
| 473 | 479 |
| 474 return invalid_offset == -1; | 480 return invalid_offset == -1; |
| 475 } | 481 } |
| 476 #endif | 482 #endif |
| 477 | 483 |
| 478 } // namespace compiler | 484 } // namespace compiler |
| 479 } // namespace internal | 485 } // namespace internal |
| 480 } // namespace v8 | 486 } // namespace v8 |
| OLD | NEW |