Index: src/compiler/bytecode-analysis.cc |
diff --git a/src/compiler/bytecode-analysis.cc b/src/compiler/bytecode-analysis.cc |
index ea5d71a7da1c0cefdcb2d4c5ad4296353d82901b..86b12017057ff5570d622c6ef4bbcd91d2000829 100644 |
--- a/src/compiler/bytecode-analysis.cc |
+++ b/src/compiler/bytecode-analysis.cc |
@@ -11,30 +11,286 @@ namespace v8 { |
namespace internal { |
namespace compiler { |
+using namespace interpreter; |
+ |
BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array, |
Zone* zone) |
: bytecode_array_(bytecode_array), |
zone_(zone), |
loop_stack_(zone), |
end_to_header_(zone), |
- header_to_parent_(zone) {} |
+ header_to_parent_(zone), |
+ liveness_( |
+ base::bits::RoundUpToPowerOfTwo32(bytecode_array->length() / 4 + 1), |
+ base::KeyEqualityMatcher<int>(), ZoneAllocationPolicy(zone)) {} |
+ |
+namespace { |
+ |
+uint32_t OffsetHash(int offset) { return offset; } |
+ |
+const BitVector* GetInLiveness( |
+ int offset, const BytecodeAnalysis::LivenessMap& liveness_map) { |
+ return liveness_map.Lookup(offset, OffsetHash(offset))->value.in; |
+} |
+ |
+const BitVector* GetOutLiveness( |
+ int offset, const BytecodeAnalysis::LivenessMap& liveness_map) { |
+ return liveness_map.Lookup(offset, OffsetHash(offset))->value.out; |
+} |
+ |
+template <int index, OperandType... operandTypes> |
+struct LivenessHelper; |
+ |
+template <int index, OperandType otherOperandType, OperandType... operandTypes> |
+struct LivenessHelper<index, otherOperandType, operandTypes...> { |
+ static void AddReads(BitVector& liveness, |
+ const BytecodeArrayAccessor& accessor) { |
+ LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); |
+ } |
+ static void KillWrites(BitVector& liveness, |
+ const BytecodeArrayAccessor& accessor) { |
+ LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); |
+ } |
+}; |
+ |
+template <int index> |
+struct LivenessHelper<index> { |
+ static void AddReads(BitVector& liveness, |
+ const BytecodeArrayAccessor& accessor) {} |
+ static void KillWrites(BitVector& liveness, |
+ const BytecodeArrayAccessor& accessor) {} |
+}; |
+ |
+template <int index, OperandType... operandTypes> |
+struct LivenessHelper<index, OperandType::kReg, operandTypes...> { |
+ static void AddReads(BitVector& liveness, |
+ const BytecodeArrayAccessor& accessor) { |
+ interpreter::Register r = accessor.GetRegisterOperand(index); |
+ if (!r.is_parameter()) { |
+ liveness.Add(r.index()); |
+ } |
+ |
+ LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); |
+ } |
+ static void KillWrites(BitVector& liveness, |
+ const BytecodeArrayAccessor& accessor) { |
+ LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); |
+ } |
+}; |
+ |
+template <int index, OperandType... operandTypes> |
+struct LivenessHelper<index, OperandType::kRegList, OperandType::kRegCount, |
+ operandTypes...> { |
+ static void AddReads(BitVector& liveness, |
+ const BytecodeArrayAccessor& accessor) { |
+ interpreter::Register r = accessor.GetRegisterOperand(index); |
+ if (!r.is_parameter()) { |
+ int count = accessor.GetRegisterCountOperand(index + 1); |
+ for (int i = 0; i < count; ++i) { |
+ liveness.Add(r.index() + i); |
+ } |
+ } |
+ |
+ LivenessHelper<index + 2, operandTypes...>::AddReads(liveness, accessor); |
+ } |
+ static void KillWrites(BitVector& liveness, |
+ const BytecodeArrayAccessor& accessor) { |
+ LivenessHelper<index + 2, operandTypes...>::KillWrites(liveness, accessor); |
+ } |
+}; |
+ |
+template <int index, OperandType otherOperandType, OperandType... operandTypes> |
+struct LivenessHelper<index, OperandType::kRegList, otherOperandType, |
+ operandTypes...> {}; |
+ |
+template <int index, OperandType... operandTypes> |
+struct LivenessHelper<index, OperandType::kRegPair, operandTypes...> { |
+ static void AddReads(BitVector& liveness, |
+ const BytecodeArrayAccessor& accessor) { |
+ interpreter::Register r = accessor.GetRegisterOperand(index); |
+ if (!r.is_parameter()) { |
+ liveness.Add(r.index()); |
+ liveness.Add(r.index() + 1); |
+ } |
+ |
+ LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); |
+ } |
+ static void KillWrites(BitVector& liveness, |
+ const BytecodeArrayAccessor& accessor) { |
+ LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); |
+ } |
+}; |
+ |
+template <int index, OperandType... operandTypes> |
+struct LivenessHelper<index, OperandType::kRegOut, operandTypes...> { |
+ static void AddReads(BitVector& liveness, |
+ const BytecodeArrayAccessor& accessor) { |
+ LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); |
+ } |
+ static void KillWrites(BitVector& liveness, |
+ const BytecodeArrayAccessor& accessor) { |
+ interpreter::Register r = accessor.GetRegisterOperand(index); |
+ if (!r.is_parameter()) { |
+ liveness.Remove(r.index()); |
+ } |
+ |
+ LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); |
+ } |
+}; |
+ |
+template <int index, OperandType... operandTypes> |
+struct LivenessHelper<index, OperandType::kRegOutPair, operandTypes...> { |
+ static void AddReads(BitVector& liveness, |
+ const BytecodeArrayAccessor& accessor) { |
+ LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); |
+ } |
+ static void KillWrites(BitVector& liveness, |
+ const BytecodeArrayAccessor& accessor) { |
+ interpreter::Register r = accessor.GetRegisterOperand(index); |
+ if (!r.is_parameter()) { |
+ liveness.Remove(r.index()); |
+ liveness.Remove(r.index() + 1); |
+ } |
+ |
+ LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); |
+ } |
+}; |
+ |
+template <int index, OperandType... operandTypes> |
+struct LivenessHelper<index, OperandType::kRegOutTriple, operandTypes...> { |
+ static void AddReads(BitVector& liveness, |
+ const BytecodeArrayAccessor& accessor) { |
+ LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); |
+ } |
+ static void KillWrites(BitVector& liveness, |
+ const BytecodeArrayAccessor& accessor) { |
+ interpreter::Register r = accessor.GetRegisterOperand(index); |
+ if (!r.is_parameter()) { |
+ liveness.Remove(r.index()); |
+ liveness.Remove(r.index() + 1); |
+ liveness.Remove(r.index() + 2); |
+ } |
+ |
+ LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); |
+ } |
+}; |
+ |
+template <Bytecode bytecode, AccumulatorUse accumulatorUse, |
+ 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
|
+void UpdateLiveness(BytecodeAnalysis::Liveness liveness, |
+ const BytecodeArrayAccessor& accessor, |
+ const BytecodeAnalysis::LivenessMap& liveness_map) { |
+ int current_offset = accessor.current_offset(); |
+ const Handle<BytecodeArray>& bytecode_array = accessor.bytecode_array(); |
+ |
+ BitVector& in_liveness = *liveness.in; |
+ BitVector& out_liveness = *liveness.out; |
+ |
+ if (Bytecodes::IsJump(bytecode)) { |
+ int target_offset = accessor.GetJumpTargetOffset(); |
+ out_liveness.Union(*GetInLiveness(target_offset, liveness_map)); |
+ } |
+ |
+ if (!Bytecodes::IsJump(bytecode) || Bytecodes::IsConditionalJump(bytecode)) { |
+ int next_offset = current_offset + accessor.current_bytecode_size(); |
+ if (next_offset < bytecode_array->length()) { |
+ out_liveness.Union(*GetInLiveness(next_offset, liveness_map)); |
+ } |
+ } |
+ |
+ if (!interpreter::Bytecodes::IsWithoutExternalSideEffects(bytecode)) { |
+ int handler_context; |
+ int handler_offset = bytecode_array->LookupRangeInHandlerTable( |
+ current_offset, &handler_context, nullptr); |
+ |
+ if (handler_offset != -1) { |
+ out_liveness.Union(*GetInLiveness(handler_offset, liveness_map)); |
+ out_liveness.Add(handler_context); |
+ } |
+ } |
+ |
+ in_liveness.CopyFrom(out_liveness); |
+ |
+ if (accumulatorUse == AccumulatorUse::kWrite) { |
+ in_liveness.Remove(in_liveness.length() - 1); |
+ } |
+ LivenessHelper<0, operandsTypes...>::KillWrites(in_liveness, accessor); |
+ |
+ if (accumulatorUse == AccumulatorUse::kRead) { |
+ in_liveness.Add(in_liveness.length() - 1); |
+ } |
+ LivenessHelper<0, operandsTypes...>::AddReads(in_liveness, accessor); |
+} |
+} // namespace |
+ |
+BytecodeAnalysis::Liveness::Liveness(int size, Zone* zone) |
+ : in(new (zone) BitVector(size, zone)), |
+ out(new (zone) BitVector(size, zone)) {} |
void BytecodeAnalysis::Analyze() { |
loop_stack_.push(-1); |
- interpreter::BytecodeArrayReverseIterator iterator(bytecode_array(), zone()); |
+ BytecodeArrayReverseIterator iterator(bytecode_array(), zone()); |
while (!iterator.done()) { |
- interpreter::Bytecode bytecode = iterator.current_bytecode(); |
- if (bytecode == interpreter::Bytecode::kJumpLoop) { |
- PushLoop(iterator.GetJumpTargetOffset(), iterator.current_offset()); |
- } else if (iterator.current_offset() == loop_stack_.top()) { |
+ Bytecode bytecode = iterator.current_bytecode(); |
+ int current_offset = iterator.current_offset(); |
+ |
+ if (bytecode == Bytecode::kJumpLoop) { |
+ PushLoop(iterator.GetJumpTargetOffset(), current_offset); |
+ } else if (current_offset == loop_stack_.top()) { |
loop_stack_.pop(); |
} |
+ |
+ liveness_.LookupOrInsert( |
+ current_offset, OffsetHash(current_offset), |
+ [&]() { |
+ return Liveness(bytecode_array()->register_count() + 1, zone()); |
+ }, |
+ ZoneAllocationPolicy(zone())); |
+ |
iterator.Advance(); |
} |
DCHECK_EQ(loop_stack_.size(), 1u); |
DCHECK_EQ(loop_stack_.top(), -1); |
+ |
+ // Hoist previous_in_liveness out of the loop so that we don't trash the zone |
+ // with allocations. |
+ BitVector previous_in_liveness(bytecode_array()->register_count() + 1, |
+ zone()); |
+ |
+ bool liveness_changed = true; |
+ while (liveness_changed) { |
+ liveness_changed = false; |
+ iterator.Reset(); |
+ while (!iterator.done()) { |
+ Liveness current_liveness = |
+ liveness_ |
+ .Lookup(iterator.current_offset(), |
+ OffsetHash(iterator.current_offset())) |
+ ->value; |
+ previous_in_liveness.CopyFrom(*current_liveness.in); |
+ |
+ switch (iterator.current_bytecode()) { |
+#define CASE(NAME, ...) \ |
+ case Bytecode::k##NAME: { \ |
+ UpdateLiveness<Bytecode::k##NAME, __VA_ARGS__>(current_liveness, iterator, \ |
+ liveness_); \ |
+ break; \ |
+ } |
+ |
+ BYTECODE_LIST(CASE) |
+#undef CASE |
+ } |
+ |
+ if (!liveness_changed && |
+ !current_liveness.in->Equals(previous_in_liveness)) { |
+ liveness_changed = true; |
+ } |
+ |
+ iterator.Advance(); |
+ } |
+ } |
} |
void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) { |
@@ -92,6 +348,14 @@ int BytecodeAnalysis::GetParentLoopFor(int header_offset) const { |
return header_to_parent_.find(header_offset)->second; |
} |
+const BitVector* BytecodeAnalysis::GetInLivenessFor(int offset) const { |
+ return GetInLiveness(offset, liveness_); |
+} |
+ |
+const BitVector* BytecodeAnalysis::GetOutLivenessFor(int offset) const { |
+ return GetOutLiveness(offset, liveness_); |
+} |
+ |
} // namespace compiler |
} // namespace internal |
} // namespace v8 |