 Chromium Code Reviews
 Chromium Code Reviews Issue 2523893003:
  Reland of [ignition/turbo] Perform liveness analysis on the bytecodes  (Closed)
    
  
    Issue 2523893003:
  Reland of [ignition/turbo] Perform liveness analysis on the bytecodes  (Closed) 
  | 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_ |