Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(49)

Unified Diff: src/compiler/bytecode-analysis-liveness.h

Issue 2523893003: Reland of [ignition/turbo] Perform liveness analysis on the bytecodes (Closed)
Patch Set: Fix debugger special casing and liveness disabling Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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_

Powered by Google App Engine
This is Rietveld 408576698