Index: src/compiler/bytecode-analysis-liveness.h |
diff --git a/src/compiler/bytecode-analysis-liveness.h b/src/compiler/bytecode-analysis-liveness.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9419b572ec3b79a66016b3f9b5fbc417e3918c57 |
--- /dev/null |
+++ b/src/compiler/bytecode-analysis-liveness.h |
@@ -0,0 +1,152 @@ |
+// Copyright 2016 the V8 project authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef V8_COMPILER_BYTECODE_ANALYSIS_LIVENESS_H_ |
+#define V8_COMPILER_BYTECODE_ANALYSIS_LIVENESS_H_ |
+ |
+#include "src/bit-vector.h" |
+#include "src/compiler/bytecode-liveness-map.h" |
+#include "src/interpreter/bytecode-array-accessor.h" |
+#include "src/interpreter/bytecodes.h" |
+ |
+namespace v8 { |
+namespace internal { |
+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
|
+ |
+using namespace interpreter; |
+ |
+void UpdateInLiveness(Bytecode bytecode, BitVector& in_liveness, |
+ const BytecodeArrayAccessor& accessor) { |
+ if (bytecode == Bytecode::kDebugger) { |
+ // TODO(leszeks): Do we really need to keep everything alive for a debugger |
+ // bytecode? Other ways of breaking the debugger here (such as a debugger |
+ // 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
|
+ in_liveness.AddAll(); |
+ return; |
+ } |
+ |
+ int num_operands = Bytecodes::NumberOfOperands(bytecode); |
+ const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode); |
+ AccumulatorUse accumulator_use = Bytecodes::GetAccumulatorUse(bytecode); |
+ |
+ if (accumulator_use == AccumulatorUse::kWrite) { |
+ in_liveness.Remove(in_liveness.length() - 1); |
+ } |
+ 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
:(
|
+ switch (operand_types[i]) { |
+ case OperandType::kRegOut: { |
+ interpreter::Register r = accessor.GetRegisterOperand(i); |
+ if (!r.is_parameter()) { |
+ in_liveness.Remove(r.index()); |
+ } |
+ break; |
+ } |
+ case OperandType::kRegOutPair: { |
+ interpreter::Register r = accessor.GetRegisterOperand(i); |
+ 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
|
+ in_liveness.Remove(r.index()); |
+ in_liveness.Remove(r.index() + 1); |
+ } |
+ break; |
+ } |
+ case OperandType::kRegOutTriple: { |
+ interpreter::Register r = accessor.GetRegisterOperand(i); |
+ if (!r.is_parameter()) { |
+ in_liveness.Remove(r.index()); |
+ in_liveness.Remove(r.index() + 1); |
+ in_liveness.Remove(r.index() + 2); |
+ } |
+ break; |
+ } |
+ default: |
+ DCHECK(!Bytecodes::IsRegisterOutputOperandType(operand_types[i])); |
+ break; |
+ } |
+ } |
+ |
+ if (accumulator_use == AccumulatorUse::kRead) { |
+ in_liveness.Add(in_liveness.length() - 1); |
+ } |
+ for (int i = 0; i < num_operands; ++i) { |
+ switch (operand_types[i]) { |
+ case OperandType::kReg: { |
+ interpreter::Register r = accessor.GetRegisterOperand(i); |
+ if (!r.is_parameter()) { |
+ in_liveness.Add(r.index()); |
+ } |
+ break; |
+ } |
+ case OperandType::kRegPair: { |
+ interpreter::Register r = accessor.GetRegisterOperand(i); |
+ if (!r.is_parameter()) { |
+ in_liveness.Add(r.index()); |
+ in_liveness.Add(r.index() + 1); |
+ } |
+ break; |
+ } |
+ case OperandType::kRegList: { |
+ 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.
|
+ i++; |
+ 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.
|
+ uint32_t reg_count = accessor.GetRegisterCountOperand(i); |
+ |
+ for (uint32_t j = 0; j < reg_count; ++j) { |
+ in_liveness.Add(r.index() + j); |
+ } |
+ } |
+ } |
+ default: |
+ DCHECK(!Bytecodes::IsRegisterInputOperandType(operand_types[i])); |
+ break; |
+ } |
+ } |
+} |
+ |
+void UpdateOutLiveness(Bytecode bytecode, BitVector& out_liveness, |
+ const BytecodeArrayAccessor& accessor, |
+ const BytecodeLivenessMap& liveness_map) { |
+ if (bytecode == Bytecode::kDebugger) { |
+ // TODO(leszeks): Do we really need to keep everything alive for a debugger |
+ // bytecode? Other ways of breaking the debugger here (such as a debugger |
+ // statement in a called function) won't keep locals alive. |
+ out_liveness.AddAll(); |
+ return; |
+ } |
+ |
+ int current_offset = accessor.current_offset(); |
+ const Handle<BytecodeArray>& bytecode_array = accessor.bytecode_array(); |
+ |
+ // Update from jump target (if any). Skip loops, we update these manually in |
+ // the liveness iterations. |
+ if (Bytecodes::IsForwardJump(bytecode)) { |
+ int target_offset = accessor.GetJumpTargetOffset(); |
+ out_liveness.Union(*liveness_map.GetInLiveness(target_offset)); |
+ } |
+ |
+ // Update from next bytecode (unless this is an unconditional jump). |
+ 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
|
+ int next_offset = current_offset + accessor.current_bytecode_size(); |
+ if (next_offset < bytecode_array->length()) { |
+ out_liveness.Union(*liveness_map.GetInLiveness(next_offset)); |
+ } |
+ } |
+ |
+ // Update from exception handler (if any). |
+ 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(*liveness_map.GetInLiveness(handler_offset)); |
+ out_liveness.Add(handler_context); |
+ } |
+ } |
+} |
+ |
+} // namespace compiler |
+} // namespace internal |
+} // namespace v8 |
+ |
+#endif // V8_COMPILER_BYTECODE_ANALYSIS_LIVENESS_H_ |