Chromium Code Reviews| 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-reverse-iterator.h" | 7 #include "src/interpreter/bytecode-array-reverse-iterator.h" |
| 8 #include "src/objects-inl.h" | 8 #include "src/objects-inl.h" |
| 9 | 9 |
| 10 namespace v8 { | 10 namespace v8 { |
| 11 namespace internal { | 11 namespace internal { |
| 12 namespace compiler { | 12 namespace compiler { |
| 13 | 13 |
| 14 using namespace interpreter; | |
| 15 | |
| 14 BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array, | 16 BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array, |
| 15 Zone* zone) | 17 Zone* zone) |
| 16 : bytecode_array_(bytecode_array), | 18 : bytecode_array_(bytecode_array), |
| 17 zone_(zone), | 19 zone_(zone), |
| 18 loop_stack_(zone), | 20 loop_stack_(zone), |
| 19 end_to_header_(zone), | 21 end_to_header_(zone), |
| 20 header_to_parent_(zone) {} | 22 header_to_parent_(zone), |
| 23 liveness_( | |
| 24 base::bits::RoundUpToPowerOfTwo32(bytecode_array->length() / 4 + 1), | |
| 25 base::KeyEqualityMatcher<int>(), ZoneAllocationPolicy(zone)) {} | |
| 26 | |
| 27 namespace { | |
| 28 | |
| 29 uint32_t OffsetHash(int offset) { return offset; } | |
| 30 | |
| 31 const BitVector* GetInLiveness( | |
| 32 int offset, const BytecodeAnalysis::LivenessMap& liveness_map) { | |
| 33 return liveness_map.Lookup(offset, OffsetHash(offset))->value.in; | |
| 34 } | |
| 35 | |
| 36 const BitVector* GetOutLiveness( | |
| 37 int offset, const BytecodeAnalysis::LivenessMap& liveness_map) { | |
| 38 return liveness_map.Lookup(offset, OffsetHash(offset))->value.out; | |
| 39 } | |
| 40 | |
| 41 template <int index, OperandType... operandTypes> | |
| 42 struct LivenessHelper; | |
| 43 | |
| 44 template <int index, OperandType otherOperandType, OperandType... operandTypes> | |
| 45 struct LivenessHelper<index, otherOperandType, operandTypes...> { | |
| 46 static void AddReads(BitVector& liveness, | |
| 47 const BytecodeArrayAccessor& accessor) { | |
| 48 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); | |
| 49 } | |
| 50 static void KillWrites(BitVector& liveness, | |
| 51 const BytecodeArrayAccessor& accessor) { | |
| 52 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); | |
| 53 } | |
| 54 }; | |
| 55 | |
| 56 template <int index> | |
| 57 struct LivenessHelper<index> { | |
| 58 static void AddReads(BitVector& liveness, | |
| 59 const BytecodeArrayAccessor& accessor) {} | |
| 60 static void KillWrites(BitVector& liveness, | |
| 61 const BytecodeArrayAccessor& accessor) {} | |
| 62 }; | |
| 63 | |
| 64 template <int index, OperandType... operandTypes> | |
| 65 struct LivenessHelper<index, OperandType::kReg, operandTypes...> { | |
| 66 static void AddReads(BitVector& liveness, | |
| 67 const BytecodeArrayAccessor& accessor) { | |
| 68 interpreter::Register r = accessor.GetRegisterOperand(index); | |
| 69 if (!r.is_parameter()) { | |
| 70 liveness.Add(r.index()); | |
| 71 } | |
| 72 | |
| 73 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); | |
| 74 } | |
| 75 static void KillWrites(BitVector& liveness, | |
| 76 const BytecodeArrayAccessor& accessor) { | |
| 77 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); | |
| 78 } | |
| 79 }; | |
| 80 | |
| 81 template <int index, OperandType... operandTypes> | |
| 82 struct LivenessHelper<index, OperandType::kRegList, OperandType::kRegCount, | |
| 83 operandTypes...> { | |
| 84 static void AddReads(BitVector& liveness, | |
| 85 const BytecodeArrayAccessor& accessor) { | |
| 86 interpreter::Register r = accessor.GetRegisterOperand(index); | |
| 87 if (!r.is_parameter()) { | |
| 88 int count = accessor.GetRegisterCountOperand(index + 1); | |
| 89 for (int i = 0; i < count; ++i) { | |
| 90 liveness.Add(r.index() + i); | |
| 91 } | |
| 92 } | |
| 93 | |
| 94 LivenessHelper<index + 2, operandTypes...>::AddReads(liveness, accessor); | |
| 95 } | |
| 96 static void KillWrites(BitVector& liveness, | |
| 97 const BytecodeArrayAccessor& accessor) { | |
| 98 LivenessHelper<index + 2, operandTypes...>::KillWrites(liveness, accessor); | |
| 99 } | |
| 100 }; | |
| 101 | |
| 102 template <int index, OperandType otherOperandType, OperandType... operandTypes> | |
| 103 struct LivenessHelper<index, OperandType::kRegList, otherOperandType, | |
| 104 operandTypes...> {}; | |
| 105 | |
| 106 template <int index, OperandType... operandTypes> | |
| 107 struct LivenessHelper<index, OperandType::kRegPair, operandTypes...> { | |
| 108 static void AddReads(BitVector& liveness, | |
| 109 const BytecodeArrayAccessor& accessor) { | |
| 110 interpreter::Register r = accessor.GetRegisterOperand(index); | |
| 111 if (!r.is_parameter()) { | |
| 112 liveness.Add(r.index()); | |
| 113 liveness.Add(r.index() + 1); | |
| 114 } | |
| 115 | |
| 116 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); | |
| 117 } | |
| 118 static void KillWrites(BitVector& liveness, | |
| 119 const BytecodeArrayAccessor& accessor) { | |
| 120 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); | |
| 121 } | |
| 122 }; | |
| 123 | |
| 124 template <int index, OperandType... operandTypes> | |
| 125 struct LivenessHelper<index, OperandType::kRegOut, operandTypes...> { | |
| 126 static void AddReads(BitVector& liveness, | |
| 127 const BytecodeArrayAccessor& accessor) { | |
| 128 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); | |
| 129 } | |
| 130 static void KillWrites(BitVector& liveness, | |
| 131 const BytecodeArrayAccessor& accessor) { | |
| 132 interpreter::Register r = accessor.GetRegisterOperand(index); | |
| 133 if (!r.is_parameter()) { | |
| 134 liveness.Remove(r.index()); | |
| 135 } | |
| 136 | |
| 137 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); | |
| 138 } | |
| 139 }; | |
| 140 | |
| 141 template <int index, OperandType... operandTypes> | |
| 142 struct LivenessHelper<index, OperandType::kRegOutPair, operandTypes...> { | |
| 143 static void AddReads(BitVector& liveness, | |
| 144 const BytecodeArrayAccessor& accessor) { | |
| 145 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); | |
| 146 } | |
| 147 static void KillWrites(BitVector& liveness, | |
| 148 const BytecodeArrayAccessor& accessor) { | |
| 149 interpreter::Register r = accessor.GetRegisterOperand(index); | |
| 150 if (!r.is_parameter()) { | |
| 151 liveness.Remove(r.index()); | |
| 152 liveness.Remove(r.index() + 1); | |
| 153 } | |
| 154 | |
| 155 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); | |
| 156 } | |
| 157 }; | |
| 158 | |
| 159 template <int index, OperandType... operandTypes> | |
| 160 struct LivenessHelper<index, OperandType::kRegOutTriple, operandTypes...> { | |
| 161 static void AddReads(BitVector& liveness, | |
| 162 const BytecodeArrayAccessor& accessor) { | |
| 163 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); | |
| 164 } | |
| 165 static void KillWrites(BitVector& liveness, | |
| 166 const BytecodeArrayAccessor& accessor) { | |
| 167 interpreter::Register r = accessor.GetRegisterOperand(index); | |
| 168 if (!r.is_parameter()) { | |
| 169 liveness.Remove(r.index()); | |
| 170 liveness.Remove(r.index() + 1); | |
| 171 liveness.Remove(r.index() + 2); | |
| 172 } | |
| 173 | |
| 174 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); | |
| 175 } | |
| 176 }; | |
| 177 | |
| 178 template <Bytecode bytecode, AccumulatorUse accumulatorUse, | |
| 179 OperandType... operandsTypes> | |
|
Jarin
2016/11/24 12:47:17
Oh, my eyes, my eyes!
Does the heavy use of templ
Leszek Swirski
2016/11/25 17:31:27
Beauty is in the eye of the beholder ;)
Unfortuna
| |
| 180 void UpdateLiveness(BytecodeAnalysis::Liveness liveness, | |
| 181 const BytecodeArrayAccessor& accessor, | |
| 182 const BytecodeAnalysis::LivenessMap& liveness_map) { | |
| 183 int current_offset = accessor.current_offset(); | |
| 184 const Handle<BytecodeArray>& bytecode_array = accessor.bytecode_array(); | |
| 185 | |
| 186 BitVector& in_liveness = *liveness.in; | |
| 187 BitVector& out_liveness = *liveness.out; | |
| 188 | |
| 189 if (Bytecodes::IsJump(bytecode)) { | |
| 190 int target_offset = accessor.GetJumpTargetOffset(); | |
| 191 out_liveness.Union(*GetInLiveness(target_offset, liveness_map)); | |
| 192 } | |
| 193 | |
| 194 if (!Bytecodes::IsJump(bytecode) || Bytecodes::IsConditionalJump(bytecode)) { | |
| 195 int next_offset = current_offset + accessor.current_bytecode_size(); | |
| 196 if (next_offset < bytecode_array->length()) { | |
| 197 out_liveness.Union(*GetInLiveness(next_offset, liveness_map)); | |
| 198 } | |
| 199 } | |
| 200 | |
| 201 if (!interpreter::Bytecodes::IsWithoutExternalSideEffects(bytecode)) { | |
| 202 int handler_context; | |
| 203 int handler_offset = bytecode_array->LookupRangeInHandlerTable( | |
| 204 current_offset, &handler_context, nullptr); | |
| 205 | |
| 206 if (handler_offset != -1) { | |
| 207 out_liveness.Union(*GetInLiveness(handler_offset, liveness_map)); | |
| 208 out_liveness.Add(handler_context); | |
| 209 } | |
| 210 } | |
| 211 | |
| 212 in_liveness.CopyFrom(out_liveness); | |
| 213 | |
| 214 if (accumulatorUse == AccumulatorUse::kWrite) { | |
| 215 in_liveness.Remove(in_liveness.length() - 1); | |
| 216 } | |
| 217 LivenessHelper<0, operandsTypes...>::KillWrites(in_liveness, accessor); | |
| 218 | |
| 219 if (accumulatorUse == AccumulatorUse::kRead) { | |
| 220 in_liveness.Add(in_liveness.length() - 1); | |
| 221 } | |
| 222 LivenessHelper<0, operandsTypes...>::AddReads(in_liveness, accessor); | |
| 223 } | |
| 224 } // namespace | |
| 225 | |
| 226 BytecodeAnalysis::Liveness::Liveness(int size, Zone* zone) | |
| 227 : in(new (zone) BitVector(size, zone)), | |
| 228 out(new (zone) BitVector(size, zone)) {} | |
| 21 | 229 |
| 22 void BytecodeAnalysis::Analyze() { | 230 void BytecodeAnalysis::Analyze() { |
| 23 loop_stack_.push(-1); | 231 loop_stack_.push(-1); |
| 24 | 232 |
| 25 interpreter::BytecodeArrayReverseIterator iterator(bytecode_array(), zone()); | 233 BytecodeArrayReverseIterator iterator(bytecode_array(), zone()); |
| 26 while (!iterator.done()) { | 234 while (!iterator.done()) { |
| 27 interpreter::Bytecode bytecode = iterator.current_bytecode(); | 235 Bytecode bytecode = iterator.current_bytecode(); |
| 28 if (bytecode == interpreter::Bytecode::kJumpLoop) { | 236 int current_offset = iterator.current_offset(); |
| 29 PushLoop(iterator.GetJumpTargetOffset(), iterator.current_offset()); | 237 |
| 30 } else if (iterator.current_offset() == loop_stack_.top()) { | 238 if (bytecode == Bytecode::kJumpLoop) { |
| 239 PushLoop(iterator.GetJumpTargetOffset(), current_offset); | |
| 240 } else if (current_offset == loop_stack_.top()) { | |
| 31 loop_stack_.pop(); | 241 loop_stack_.pop(); |
| 32 } | 242 } |
| 243 | |
| 244 liveness_.LookupOrInsert( | |
| 245 current_offset, OffsetHash(current_offset), | |
| 246 [&]() { | |
| 247 return Liveness(bytecode_array()->register_count() + 1, zone()); | |
| 248 }, | |
| 249 ZoneAllocationPolicy(zone())); | |
| 250 | |
| 33 iterator.Advance(); | 251 iterator.Advance(); |
| 34 } | 252 } |
| 35 | 253 |
| 36 DCHECK_EQ(loop_stack_.size(), 1u); | 254 DCHECK_EQ(loop_stack_.size(), 1u); |
| 37 DCHECK_EQ(loop_stack_.top(), -1); | 255 DCHECK_EQ(loop_stack_.top(), -1); |
| 256 | |
| 257 // Hoist previous_in_liveness out of the loop so that we don't trash the zone | |
| 258 // with allocations. | |
| 259 BitVector previous_in_liveness(bytecode_array()->register_count() + 1, | |
| 260 zone()); | |
| 261 | |
| 262 bool liveness_changed = true; | |
| 263 while (liveness_changed) { | |
| 264 liveness_changed = false; | |
| 265 iterator.Reset(); | |
| 266 while (!iterator.done()) { | |
| 267 Liveness current_liveness = | |
| 268 liveness_ | |
| 269 .Lookup(iterator.current_offset(), | |
| 270 OffsetHash(iterator.current_offset())) | |
| 271 ->value; | |
| 272 previous_in_liveness.CopyFrom(*current_liveness.in); | |
| 273 | |
| 274 switch (iterator.current_bytecode()) { | |
| 275 #define CASE(NAME, ...) \ | |
| 276 case Bytecode::k##NAME: { \ | |
| 277 UpdateLiveness<Bytecode::k##NAME, __VA_ARGS__>(current_liveness, iterator, \ | |
| 278 liveness_); \ | |
| 279 break; \ | |
| 280 } | |
| 281 | |
| 282 BYTECODE_LIST(CASE) | |
| 283 #undef CASE | |
| 284 } | |
| 285 | |
| 286 if (!liveness_changed && | |
| 287 !current_liveness.in->Equals(previous_in_liveness)) { | |
| 288 liveness_changed = true; | |
| 289 } | |
| 290 | |
| 291 iterator.Advance(); | |
| 292 } | |
| 293 } | |
| 38 } | 294 } |
| 39 | 295 |
| 40 void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) { | 296 void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) { |
| 41 DCHECK(loop_header < loop_end); | 297 DCHECK(loop_header < loop_end); |
| 42 DCHECK(loop_stack_.top() < loop_header); | 298 DCHECK(loop_stack_.top() < loop_header); |
| 43 DCHECK(end_to_header_.find(loop_end) == end_to_header_.end()); | 299 DCHECK(end_to_header_.find(loop_end) == end_to_header_.end()); |
| 44 DCHECK(header_to_parent_.find(loop_header) == header_to_parent_.end()); | 300 DCHECK(header_to_parent_.find(loop_header) == header_to_parent_.end()); |
| 45 | 301 |
| 46 end_to_header_.insert(ZoneMap<int, int>::value_type(loop_end, loop_header)); | 302 end_to_header_.insert(ZoneMap<int, int>::value_type(loop_end, loop_header)); |
| 47 header_to_parent_.insert( | 303 header_to_parent_.insert( |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 85 | 341 |
| 86 return header_to_parent_.upper_bound(offset)->second; | 342 return header_to_parent_.upper_bound(offset)->second; |
| 87 } | 343 } |
| 88 | 344 |
| 89 int BytecodeAnalysis::GetParentLoopFor(int header_offset) const { | 345 int BytecodeAnalysis::GetParentLoopFor(int header_offset) const { |
| 90 DCHECK(IsLoopHeader(header_offset)); | 346 DCHECK(IsLoopHeader(header_offset)); |
| 91 | 347 |
| 92 return header_to_parent_.find(header_offset)->second; | 348 return header_to_parent_.find(header_offset)->second; |
| 93 } | 349 } |
| 94 | 350 |
| 351 const BitVector* BytecodeAnalysis::GetInLivenessFor(int offset) const { | |
| 352 return GetInLiveness(offset, liveness_); | |
| 353 } | |
| 354 | |
| 355 const BitVector* BytecodeAnalysis::GetOutLivenessFor(int offset) const { | |
| 356 return GetOutLiveness(offset, liveness_); | |
| 357 } | |
| 358 | |
| 95 } // namespace compiler | 359 } // namespace compiler |
| 96 } // namespace internal | 360 } // namespace internal |
| 97 } // namespace v8 | 361 } // namespace v8 |
| OLD | NEW |