OLD | NEW |
---|---|
1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/bytecode-analysis.h" | 5 #include "src/compiler/bytecode-analysis.h" |
6 | 6 |
7 #include "src/interpreter/bytecode-array-reverse-iterator.h" | 7 #include "src/interpreter/bytecode-array-reverse-iterator.h" |
8 #include "src/objects-inl.h" | 8 #include "src/objects-inl.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
11 namespace internal { | 11 namespace internal { |
12 namespace compiler { | 12 namespace compiler { |
13 | 13 |
14 using namespace interpreter; | |
15 | |
14 BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array, | 16 BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array, |
15 Zone* zone) | 17 Zone* zone) |
16 : bytecode_array_(bytecode_array), | 18 : bytecode_array_(bytecode_array), |
17 zone_(zone), | 19 zone_(zone), |
18 loop_stack_(zone), | 20 loop_stack_(zone), |
19 end_to_header_(zone), | 21 end_to_header_(zone), |
20 header_to_parent_(zone) {} | 22 header_to_parent_(zone), |
23 liveness_( | |
24 base::bits::RoundUpToPowerOfTwo32(bytecode_array->length() / 4 + 1), | |
25 base::KeyEqualityMatcher<int>(), ZoneAllocationPolicy(zone)) {} | |
26 | |
27 namespace { | |
28 | |
29 uint32_t OffsetHash(int offset) { return offset; } | |
30 | |
31 const BitVector* GetInLiveness( | |
32 int offset, const BytecodeAnalysis::LivenessMap& liveness_map) { | |
33 return liveness_map.Lookup(offset, OffsetHash(offset))->value.in; | |
34 } | |
35 | |
36 const BitVector* GetOutLiveness( | |
37 int offset, const BytecodeAnalysis::LivenessMap& liveness_map) { | |
38 return liveness_map.Lookup(offset, OffsetHash(offset))->value.out; | |
39 } | |
40 | |
41 template <int index, OperandType... operandTypes> | |
42 struct LivenessHelper; | |
43 | |
44 template <int index, OperandType otherOperandType, OperandType... operandTypes> | |
45 struct LivenessHelper<index, otherOperandType, operandTypes...> { | |
46 static void AddReads(BitVector& liveness, | |
47 const BytecodeArrayAccessor& accessor) { | |
48 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); | |
49 } | |
50 static void KillWrites(BitVector& liveness, | |
51 const BytecodeArrayAccessor& accessor) { | |
52 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); | |
53 } | |
54 }; | |
55 | |
56 template <int index> | |
57 struct LivenessHelper<index> { | |
58 static void AddReads(BitVector& liveness, | |
59 const BytecodeArrayAccessor& accessor) {} | |
60 static void KillWrites(BitVector& liveness, | |
61 const BytecodeArrayAccessor& accessor) {} | |
62 }; | |
63 | |
64 template <int index, OperandType... operandTypes> | |
65 struct LivenessHelper<index, OperandType::kReg, operandTypes...> { | |
66 static void AddReads(BitVector& liveness, | |
67 const BytecodeArrayAccessor& accessor) { | |
68 interpreter::Register r = accessor.GetRegisterOperand(index); | |
69 if (!r.is_parameter()) { | |
70 liveness.Add(r.index()); | |
71 } | |
72 | |
73 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); | |
74 } | |
75 static void KillWrites(BitVector& liveness, | |
76 const BytecodeArrayAccessor& accessor) { | |
77 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); | |
78 } | |
79 }; | |
80 | |
81 template <int index, OperandType... operandTypes> | |
82 struct LivenessHelper<index, OperandType::kRegList, OperandType::kRegCount, | |
83 operandTypes...> { | |
84 static void AddReads(BitVector& liveness, | |
85 const BytecodeArrayAccessor& accessor) { | |
86 interpreter::Register r = accessor.GetRegisterOperand(index); | |
87 if (!r.is_parameter()) { | |
88 int count = accessor.GetRegisterCountOperand(index + 1); | |
89 for (int i = 0; i < count; ++i) { | |
90 liveness.Add(r.index() + i); | |
91 } | |
92 } | |
93 | |
94 LivenessHelper<index + 2, operandTypes...>::AddReads(liveness, accessor); | |
95 } | |
96 static void KillWrites(BitVector& liveness, | |
97 const BytecodeArrayAccessor& accessor) { | |
98 LivenessHelper<index + 2, operandTypes...>::KillWrites(liveness, accessor); | |
99 } | |
100 }; | |
101 | |
102 template <int index, OperandType otherOperandType, OperandType... operandTypes> | |
103 struct LivenessHelper<index, OperandType::kRegList, otherOperandType, | |
104 operandTypes...> {}; | |
105 | |
106 template <int index, OperandType... operandTypes> | |
107 struct LivenessHelper<index, OperandType::kRegPair, operandTypes...> { | |
108 static void AddReads(BitVector& liveness, | |
109 const BytecodeArrayAccessor& accessor) { | |
110 interpreter::Register r = accessor.GetRegisterOperand(index); | |
111 if (!r.is_parameter()) { | |
112 liveness.Add(r.index()); | |
113 liveness.Add(r.index() + 1); | |
114 } | |
115 | |
116 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); | |
117 } | |
118 static void KillWrites(BitVector& liveness, | |
119 const BytecodeArrayAccessor& accessor) { | |
120 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); | |
121 } | |
122 }; | |
123 | |
124 template <int index, OperandType... operandTypes> | |
125 struct LivenessHelper<index, OperandType::kRegOut, operandTypes...> { | |
126 static void AddReads(BitVector& liveness, | |
127 const BytecodeArrayAccessor& accessor) { | |
128 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); | |
129 } | |
130 static void KillWrites(BitVector& liveness, | |
131 const BytecodeArrayAccessor& accessor) { | |
132 interpreter::Register r = accessor.GetRegisterOperand(index); | |
133 if (!r.is_parameter()) { | |
134 liveness.Remove(r.index()); | |
135 } | |
136 | |
137 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); | |
138 } | |
139 }; | |
140 | |
141 template <int index, OperandType... operandTypes> | |
142 struct LivenessHelper<index, OperandType::kRegOutPair, operandTypes...> { | |
143 static void AddReads(BitVector& liveness, | |
144 const BytecodeArrayAccessor& accessor) { | |
145 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); | |
146 } | |
147 static void KillWrites(BitVector& liveness, | |
148 const BytecodeArrayAccessor& accessor) { | |
149 interpreter::Register r = accessor.GetRegisterOperand(index); | |
150 if (!r.is_parameter()) { | |
151 liveness.Remove(r.index()); | |
152 liveness.Remove(r.index() + 1); | |
153 } | |
154 | |
155 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); | |
156 } | |
157 }; | |
158 | |
159 template <int index, OperandType... operandTypes> | |
160 struct LivenessHelper<index, OperandType::kRegOutTriple, operandTypes...> { | |
161 static void AddReads(BitVector& liveness, | |
162 const BytecodeArrayAccessor& accessor) { | |
163 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor); | |
164 } | |
165 static void KillWrites(BitVector& liveness, | |
166 const BytecodeArrayAccessor& accessor) { | |
167 interpreter::Register r = accessor.GetRegisterOperand(index); | |
168 if (!r.is_parameter()) { | |
169 liveness.Remove(r.index()); | |
170 liveness.Remove(r.index() + 1); | |
171 liveness.Remove(r.index() + 2); | |
172 } | |
173 | |
174 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor); | |
175 } | |
176 }; | |
177 | |
178 template <Bytecode bytecode, AccumulatorUse accumulatorUse, | |
179 OperandType... operandsTypes> | |
Jarin
2016/11/24 12:47:17
Oh, my eyes, my eyes!
Does the heavy use of templ
Leszek Swirski
2016/11/25 17:31:27
Beauty is in the eye of the beholder ;)
Unfortuna
| |
180 void UpdateLiveness(BytecodeAnalysis::Liveness liveness, | |
181 const BytecodeArrayAccessor& accessor, | |
182 const BytecodeAnalysis::LivenessMap& liveness_map) { | |
183 int current_offset = accessor.current_offset(); | |
184 const Handle<BytecodeArray>& bytecode_array = accessor.bytecode_array(); | |
185 | |
186 BitVector& in_liveness = *liveness.in; | |
187 BitVector& out_liveness = *liveness.out; | |
188 | |
189 if (Bytecodes::IsJump(bytecode)) { | |
190 int target_offset = accessor.GetJumpTargetOffset(); | |
191 out_liveness.Union(*GetInLiveness(target_offset, liveness_map)); | |
192 } | |
193 | |
194 if (!Bytecodes::IsJump(bytecode) || Bytecodes::IsConditionalJump(bytecode)) { | |
195 int next_offset = current_offset + accessor.current_bytecode_size(); | |
196 if (next_offset < bytecode_array->length()) { | |
197 out_liveness.Union(*GetInLiveness(next_offset, liveness_map)); | |
198 } | |
199 } | |
200 | |
201 if (!interpreter::Bytecodes::IsWithoutExternalSideEffects(bytecode)) { | |
202 int handler_context; | |
203 int handler_offset = bytecode_array->LookupRangeInHandlerTable( | |
204 current_offset, &handler_context, nullptr); | |
205 | |
206 if (handler_offset != -1) { | |
207 out_liveness.Union(*GetInLiveness(handler_offset, liveness_map)); | |
208 out_liveness.Add(handler_context); | |
209 } | |
210 } | |
211 | |
212 in_liveness.CopyFrom(out_liveness); | |
213 | |
214 if (accumulatorUse == AccumulatorUse::kWrite) { | |
215 in_liveness.Remove(in_liveness.length() - 1); | |
216 } | |
217 LivenessHelper<0, operandsTypes...>::KillWrites(in_liveness, accessor); | |
218 | |
219 if (accumulatorUse == AccumulatorUse::kRead) { | |
220 in_liveness.Add(in_liveness.length() - 1); | |
221 } | |
222 LivenessHelper<0, operandsTypes...>::AddReads(in_liveness, accessor); | |
223 } | |
224 } // namespace | |
225 | |
226 BytecodeAnalysis::Liveness::Liveness(int size, Zone* zone) | |
227 : in(new (zone) BitVector(size, zone)), | |
228 out(new (zone) BitVector(size, zone)) {} | |
21 | 229 |
22 void BytecodeAnalysis::Analyze() { | 230 void BytecodeAnalysis::Analyze() { |
23 loop_stack_.push(-1); | 231 loop_stack_.push(-1); |
24 | 232 |
25 interpreter::BytecodeArrayReverseIterator iterator(bytecode_array(), zone()); | 233 BytecodeArrayReverseIterator iterator(bytecode_array(), zone()); |
26 while (!iterator.done()) { | 234 while (!iterator.done()) { |
27 interpreter::Bytecode bytecode = iterator.current_bytecode(); | 235 Bytecode bytecode = iterator.current_bytecode(); |
28 if (bytecode == interpreter::Bytecode::kJumpLoop) { | 236 int current_offset = iterator.current_offset(); |
29 PushLoop(iterator.GetJumpTargetOffset(), iterator.current_offset()); | 237 |
30 } else if (iterator.current_offset() == loop_stack_.top()) { | 238 if (bytecode == Bytecode::kJumpLoop) { |
239 PushLoop(iterator.GetJumpTargetOffset(), current_offset); | |
240 } else if (current_offset == loop_stack_.top()) { | |
31 loop_stack_.pop(); | 241 loop_stack_.pop(); |
32 } | 242 } |
243 | |
244 liveness_.LookupOrInsert( | |
245 current_offset, OffsetHash(current_offset), | |
246 [&]() { | |
247 return Liveness(bytecode_array()->register_count() + 1, zone()); | |
248 }, | |
249 ZoneAllocationPolicy(zone())); | |
250 | |
33 iterator.Advance(); | 251 iterator.Advance(); |
34 } | 252 } |
35 | 253 |
36 DCHECK_EQ(loop_stack_.size(), 1u); | 254 DCHECK_EQ(loop_stack_.size(), 1u); |
37 DCHECK_EQ(loop_stack_.top(), -1); | 255 DCHECK_EQ(loop_stack_.top(), -1); |
256 | |
257 // Hoist previous_in_liveness out of the loop so that we don't trash the zone | |
258 // with allocations. | |
259 BitVector previous_in_liveness(bytecode_array()->register_count() + 1, | |
260 zone()); | |
261 | |
262 bool liveness_changed = true; | |
263 while (liveness_changed) { | |
264 liveness_changed = false; | |
265 iterator.Reset(); | |
266 while (!iterator.done()) { | |
267 Liveness current_liveness = | |
268 liveness_ | |
269 .Lookup(iterator.current_offset(), | |
270 OffsetHash(iterator.current_offset())) | |
271 ->value; | |
272 previous_in_liveness.CopyFrom(*current_liveness.in); | |
273 | |
274 switch (iterator.current_bytecode()) { | |
275 #define CASE(NAME, ...) \ | |
276 case Bytecode::k##NAME: { \ | |
277 UpdateLiveness<Bytecode::k##NAME, __VA_ARGS__>(current_liveness, iterator, \ | |
278 liveness_); \ | |
279 break; \ | |
280 } | |
281 | |
282 BYTECODE_LIST(CASE) | |
283 #undef CASE | |
284 } | |
285 | |
286 if (!liveness_changed && | |
287 !current_liveness.in->Equals(previous_in_liveness)) { | |
288 liveness_changed = true; | |
289 } | |
290 | |
291 iterator.Advance(); | |
292 } | |
293 } | |
38 } | 294 } |
39 | 295 |
40 void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) { | 296 void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) { |
41 DCHECK(loop_header < loop_end); | 297 DCHECK(loop_header < loop_end); |
42 DCHECK(loop_stack_.top() < loop_header); | 298 DCHECK(loop_stack_.top() < loop_header); |
43 DCHECK(end_to_header_.find(loop_end) == end_to_header_.end()); | 299 DCHECK(end_to_header_.find(loop_end) == end_to_header_.end()); |
44 DCHECK(header_to_parent_.find(loop_header) == header_to_parent_.end()); | 300 DCHECK(header_to_parent_.find(loop_header) == header_to_parent_.end()); |
45 | 301 |
46 end_to_header_.insert(ZoneMap<int, int>::value_type(loop_end, loop_header)); | 302 end_to_header_.insert(ZoneMap<int, int>::value_type(loop_end, loop_header)); |
47 header_to_parent_.insert( | 303 header_to_parent_.insert( |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
85 | 341 |
86 return header_to_parent_.upper_bound(offset)->second; | 342 return header_to_parent_.upper_bound(offset)->second; |
87 } | 343 } |
88 | 344 |
89 int BytecodeAnalysis::GetParentLoopFor(int header_offset) const { | 345 int BytecodeAnalysis::GetParentLoopFor(int header_offset) const { |
90 DCHECK(IsLoopHeader(header_offset)); | 346 DCHECK(IsLoopHeader(header_offset)); |
91 | 347 |
92 return header_to_parent_.find(header_offset)->second; | 348 return header_to_parent_.find(header_offset)->second; |
93 } | 349 } |
94 | 350 |
351 const BitVector* BytecodeAnalysis::GetInLivenessFor(int offset) const { | |
352 return GetInLiveness(offset, liveness_); | |
353 } | |
354 | |
355 const BitVector* BytecodeAnalysis::GetOutLivenessFor(int offset) const { | |
356 return GetOutLiveness(offset, liveness_); | |
357 } | |
358 | |
95 } // namespace compiler | 359 } // namespace compiler |
96 } // namespace internal | 360 } // namespace internal |
97 } // namespace v8 | 361 } // namespace v8 |
OLD | NEW |