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 |