Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef V8_COMPILER_BYTECODE_ANALYSIS_LIVENESS_H_ | |
| 6 #define V8_COMPILER_BYTECODE_ANALYSIS_LIVENESS_H_ | |
| 7 | |
| 8 #include "src/bit-vector.h" | |
| 9 #include "src/compiler/bytecode-liveness-map.h" | |
| 10 #include "src/interpreter/bytecode-array-accessor.h" | |
| 11 #include "src/interpreter/bytecodes.h" | |
| 12 | |
| 13 namespace v8 { | |
| 14 namespace internal { | |
| 15 namespace compiler { | |
|
Jarin
2016/11/28 08:34:43
Why does this stuff have to live in a header?
rmcilroy
2016/11/28 10:00:30
+1. Could this not all just live in bytecode analy
Leszek Swirski
2016/11/28 10:11:01
I suppose it needn't, I moved it here while it was
| |
| 16 | |
| 17 using namespace interpreter; | |
| 18 | |
| 19 void UpdateInLiveness(Bytecode bytecode, BitVector& in_liveness, | |
| 20 const BytecodeArrayAccessor& accessor) { | |
| 21 if (bytecode == Bytecode::kDebugger) { | |
| 22 // TODO(leszeks): Do we really need to keep everything alive for a debugger | |
| 23 // bytecode? Other ways of breaking the debugger here (such as a debugger | |
| 24 // statement in a called function) won't keep locals alive. | |
|
Jarin
2016/11/28 08:34:43
I am not sure what you are arguing for. We do want
Leszek Swirski
2016/11/28 10:11:01
I guess what I'm arguing is that this is a leaky a
Jarin
2016/11/28 12:05:42
I talked to Yang and he is happy not to keep varia
Leszek Swirski
2016/11/28 14:18:51
Ok, I'll update the relevant tests to disable live
| |
| 25 in_liveness.AddAll(); | |
| 26 return; | |
| 27 } | |
| 28 | |
| 29 int num_operands = Bytecodes::NumberOfOperands(bytecode); | |
| 30 const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode); | |
| 31 AccumulatorUse accumulator_use = Bytecodes::GetAccumulatorUse(bytecode); | |
| 32 | |
| 33 if (accumulator_use == AccumulatorUse::kWrite) { | |
| 34 in_liveness.Remove(in_liveness.length() - 1); | |
| 35 } | |
| 36 for (int i = 0; i < num_operands; ++i) { | |
|
Jarin
2016/11/28 08:34:43
Aaaaah, no templates, beauuuuuuutiful.
Leszek Swirski
2016/11/28 10:11:01
:(
| |
| 37 switch (operand_types[i]) { | |
| 38 case OperandType::kRegOut: { | |
| 39 interpreter::Register r = accessor.GetRegisterOperand(i); | |
| 40 if (!r.is_parameter()) { | |
| 41 in_liveness.Remove(r.index()); | |
| 42 } | |
| 43 break; | |
| 44 } | |
| 45 case OperandType::kRegOutPair: { | |
| 46 interpreter::Register r = accessor.GetRegisterOperand(i); | |
| 47 if (!r.is_parameter()) { | |
|
Jarin
2016/11/28 08:34:43
Out of curiousity, do we ever have output register
Leszek Swirski
2016/11/28 10:11:01
Good point, I do make the assumption that lists of
| |
| 48 in_liveness.Remove(r.index()); | |
| 49 in_liveness.Remove(r.index() + 1); | |
| 50 } | |
| 51 break; | |
| 52 } | |
| 53 case OperandType::kRegOutTriple: { | |
| 54 interpreter::Register r = accessor.GetRegisterOperand(i); | |
| 55 if (!r.is_parameter()) { | |
| 56 in_liveness.Remove(r.index()); | |
| 57 in_liveness.Remove(r.index() + 1); | |
| 58 in_liveness.Remove(r.index() + 2); | |
| 59 } | |
| 60 break; | |
| 61 } | |
| 62 default: | |
| 63 DCHECK(!Bytecodes::IsRegisterOutputOperandType(operand_types[i])); | |
| 64 break; | |
| 65 } | |
| 66 } | |
| 67 | |
| 68 if (accumulator_use == AccumulatorUse::kRead) { | |
| 69 in_liveness.Add(in_liveness.length() - 1); | |
| 70 } | |
| 71 for (int i = 0; i < num_operands; ++i) { | |
| 72 switch (operand_types[i]) { | |
| 73 case OperandType::kReg: { | |
| 74 interpreter::Register r = accessor.GetRegisterOperand(i); | |
| 75 if (!r.is_parameter()) { | |
| 76 in_liveness.Add(r.index()); | |
| 77 } | |
| 78 break; | |
| 79 } | |
| 80 case OperandType::kRegPair: { | |
| 81 interpreter::Register r = accessor.GetRegisterOperand(i); | |
| 82 if (!r.is_parameter()) { | |
| 83 in_liveness.Add(r.index()); | |
| 84 in_liveness.Add(r.index() + 1); | |
| 85 } | |
| 86 break; | |
| 87 } | |
| 88 case OperandType::kRegList: { | |
| 89 interpreter::Register r = accessor.GetRegisterOperand(i); | |
|
rmcilroy
2016/11/28 10:00:30
nit - maybe you could add a GetRegisterListOperand
Leszek Swirski
2016/11/28 11:07:22
I'm not sure, liveness here is a raw BitVector so
rmcilroy
2016/11/28 15:16:37
I guess we are fine without it. Please add some co
Leszek Swirski
2016/11/28 16:31:11
Done.
| |
| 90 i++; | |
| 91 if (!r.is_parameter()) { | |
|
rmcilroy
2016/11/28 10:00:30
Same comment as Jaro above regarding parameters. M
Leszek Swirski
2016/11/28 11:07:22
Done.
| |
| 92 uint32_t reg_count = accessor.GetRegisterCountOperand(i); | |
| 93 | |
| 94 for (uint32_t j = 0; j < reg_count; ++j) { | |
| 95 in_liveness.Add(r.index() + j); | |
| 96 } | |
| 97 } | |
| 98 } | |
| 99 default: | |
| 100 DCHECK(!Bytecodes::IsRegisterInputOperandType(operand_types[i])); | |
| 101 break; | |
| 102 } | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 void UpdateOutLiveness(Bytecode bytecode, BitVector& out_liveness, | |
| 107 const BytecodeArrayAccessor& accessor, | |
| 108 const BytecodeLivenessMap& liveness_map) { | |
| 109 if (bytecode == Bytecode::kDebugger) { | |
| 110 // TODO(leszeks): Do we really need to keep everything alive for a debugger | |
| 111 // bytecode? Other ways of breaking the debugger here (such as a debugger | |
| 112 // statement in a called function) won't keep locals alive. | |
| 113 out_liveness.AddAll(); | |
| 114 return; | |
| 115 } | |
| 116 | |
| 117 int current_offset = accessor.current_offset(); | |
| 118 const Handle<BytecodeArray>& bytecode_array = accessor.bytecode_array(); | |
| 119 | |
| 120 // Update from jump target (if any). Skip loops, we update these manually in | |
| 121 // the liveness iterations. | |
| 122 if (Bytecodes::IsForwardJump(bytecode)) { | |
| 123 int target_offset = accessor.GetJumpTargetOffset(); | |
| 124 out_liveness.Union(*liveness_map.GetInLiveness(target_offset)); | |
| 125 } | |
| 126 | |
| 127 // Update from next bytecode (unless this is an unconditional jump). | |
| 128 if (!Bytecodes::IsJump(bytecode) || Bytecodes::IsConditionalJump(bytecode)) { | |
|
rmcilroy
2016/11/28 10:00:30
Nit - just add IsUnconditionalJump in bytecodes.h
Leszek Swirski
2016/11/28 11:07:22
Done, also gave me the chance to simplify it a bit
| |
| 129 int next_offset = current_offset + accessor.current_bytecode_size(); | |
| 130 if (next_offset < bytecode_array->length()) { | |
| 131 out_liveness.Union(*liveness_map.GetInLiveness(next_offset)); | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 // Update from exception handler (if any). | |
| 136 if (!interpreter::Bytecodes::IsWithoutExternalSideEffects(bytecode)) { | |
| 137 int handler_context; | |
| 138 int handler_offset = bytecode_array->LookupRangeInHandlerTable( | |
| 139 current_offset, &handler_context, nullptr); | |
| 140 | |
| 141 if (handler_offset != -1) { | |
| 142 out_liveness.Union(*liveness_map.GetInLiveness(handler_offset)); | |
| 143 out_liveness.Add(handler_context); | |
| 144 } | |
| 145 } | |
| 146 } | |
| 147 | |
| 148 } // namespace compiler | |
| 149 } // namespace internal | |
| 150 } // namespace v8 | |
| 151 | |
| 152 #endif // V8_COMPILER_BYTECODE_ANALYSIS_LIVENESS_H_ | |
| OLD | NEW |