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-iterator.h" | 7 #include "src/interpreter/bytecode-array-iterator.h" |
8 #include "src/interpreter/bytecode-array-reverse-iterator.h" | 8 #include "src/interpreter/bytecode-array-random-iterator.h" |
9 #include "src/objects-inl.h" | 9 #include "src/objects-inl.h" |
10 | 10 |
11 namespace v8 { | 11 namespace v8 { |
12 namespace internal { | 12 namespace internal { |
13 namespace compiler { | 13 namespace compiler { |
14 | 14 |
15 using namespace interpreter; | 15 using namespace interpreter; |
16 | 16 |
17 BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array, | 17 BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array, |
18 Zone* zone, bool do_liveness_analysis) | 18 Zone* zone, bool do_liveness_analysis) |
19 : bytecode_array_(bytecode_array), | 19 : bytecode_array_(bytecode_array), |
20 do_liveness_analysis_(do_liveness_analysis), | 20 do_liveness_analysis_(do_liveness_analysis), |
21 zone_(zone), | 21 zone_(zone), |
22 loop_stack_(zone), | 22 loop_stack_(zone), |
| 23 loop_end_index_queue_(zone), |
23 end_to_header_(zone), | 24 end_to_header_(zone), |
24 header_to_parent_(zone), | 25 header_to_parent_(zone), |
25 liveness_map_(bytecode_array->length(), zone) {} | 26 liveness_map_(bytecode_array->length(), zone) {} |
26 | 27 |
27 namespace { | 28 namespace { |
28 | 29 |
29 void UpdateInLiveness(Bytecode bytecode, BitVector& in_liveness, | 30 void UpdateInLiveness(Bytecode bytecode, BitVector& in_liveness, |
30 const BytecodeArrayAccessor& accessor) { | 31 const BytecodeArrayAccessor& accessor) { |
31 int num_operands = Bytecodes::NumberOfOperands(bytecode); | 32 int num_operands = Bytecodes::NumberOfOperands(bytecode); |
32 const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode); | 33 const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
144 } | 145 } |
145 } | 146 } |
146 | 147 |
147 } // namespace | 148 } // namespace |
148 | 149 |
149 void BytecodeAnalysis::Analyze() { | 150 void BytecodeAnalysis::Analyze() { |
150 loop_stack_.push(-1); | 151 loop_stack_.push(-1); |
151 | 152 |
152 BitVector* next_bytecode_in_liveness = nullptr; | 153 BitVector* next_bytecode_in_liveness = nullptr; |
153 | 154 |
154 // The last JumpLoop that we haven't done a guaranteed valid liveness pass | 155 BytecodeArrayRandomIterator iterator(bytecode_array(), zone()); |
155 // over. See the below wall of text for a more thorough explanation. | 156 for (iterator.GoToEnd(); iterator.IsValid(); --iterator) { |
156 int last_invalid_jumploop_offset = -1; | |
157 | |
158 BytecodeArrayReverseIterator iterator(bytecode_array(), zone()); | |
159 for (; !iterator.done(); iterator.Advance()) { | |
160 Bytecode bytecode = iterator.current_bytecode(); | 157 Bytecode bytecode = iterator.current_bytecode(); |
161 int current_offset = iterator.current_offset(); | 158 int current_offset = iterator.current_offset(); |
162 | 159 |
163 if (bytecode == Bytecode::kJumpLoop) { | 160 if (bytecode == Bytecode::kJumpLoop) { |
164 // Every byte up to and including the last byte within the backwards jump | 161 // Every byte up to and including the last byte within the backwards jump |
165 // instruction is considered part of the loop, set loop end accordingly. | 162 // instruction is considered part of the loop, set loop end accordingly. |
166 int loop_end = current_offset + iterator.current_bytecode_size(); | 163 int loop_end = current_offset + iterator.current_bytecode_size(); |
167 PushLoop(iterator.GetJumpTargetOffset(), loop_end); | 164 PushLoop(iterator.GetJumpTargetOffset(), loop_end); |
168 | 165 |
169 // Save the last offset so that we can do another pass later. | 166 // Save the index so that we can do another pass later. |
170 if (last_invalid_jumploop_offset == -1) { | 167 if (do_liveness_analysis_) { |
171 last_invalid_jumploop_offset = current_offset; | 168 loop_end_index_queue_.push_back(iterator.current_index()); |
172 } | 169 } |
173 } else if (current_offset == loop_stack_.top()) { | 170 } else if (current_offset == loop_stack_.top()) { |
174 loop_stack_.pop(); | 171 loop_stack_.pop(); |
175 } | 172 } |
176 | 173 |
177 if (do_liveness_analysis_) { | 174 if (do_liveness_analysis_) { |
178 // The liveness vector had bits for the liveness of the registers, and one | 175 // The liveness vector had bits for the liveness of the registers, and one |
179 // more bit for the liveness of the accumulator. | 176 // more bit for the liveness of the accumulator. |
180 Liveness& liveness = liveness_map_.InitializeLiveness( | 177 Liveness& liveness = liveness_map_.InitializeLiveness( |
181 current_offset, bytecode_array()->register_count() + 1, zone()); | 178 current_offset, bytecode_array()->register_count() + 1, zone()); |
(...skipping 25 matching lines...) Expand all Loading... |
207 // So, if we know that the liveness of bytecodes after a loop header won't | 204 // So, if we know that the liveness of bytecodes after a loop header won't |
208 // change (e.g. because there are no loops in them, or we have already ensured | 205 // change (e.g. because there are no loops in them, or we have already ensured |
209 // those loops are valid), we can safely update the loop end and pass over the | 206 // those loops are valid), we can safely update the loop end and pass over the |
210 // loop body, and then never have to pass over that loop end again, because we | 207 // loop body, and then never have to pass over that loop end again, because we |
211 // have shown that its target, the loop header, can't change from the entries | 208 // have shown that its target, the loop header, can't change from the entries |
212 // after the loop, and can't change from any loop body pass. | 209 // after the loop, and can't change from any loop body pass. |
213 // | 210 // |
214 // This means that in a pass, we can iterate backwards over the bytecode | 211 // This means that in a pass, we can iterate backwards over the bytecode |
215 // array, process any loops that we encounter, and on subsequent passes we can | 212 // array, process any loops that we encounter, and on subsequent passes we can |
216 // skip processing those loops (though we still have to process inner loops). | 213 // skip processing those loops (though we still have to process inner loops). |
| 214 // |
| 215 // Equivalently, we can queue up loop ends from back to front, and pass over |
| 216 // the loops in that order, as this preserves both the bottom-to-top and |
| 217 // outer-to-inner requirements. |
217 | 218 |
218 while (last_invalid_jumploop_offset != -1) { | 219 for (int loop_end_index : loop_end_index_queue_) { |
219 // TODO(leszeks): We shouldn't need to iterate here, we should just have a | 220 iterator.GoToIndex(loop_end_index); |
220 // random access iterator. | |
221 iterator.Reset(); | |
222 while (last_invalid_jumploop_offset < iterator.current_offset()) { | |
223 iterator.Advance(); | |
224 } | |
225 last_invalid_jumploop_offset = -1; | |
226 | 221 |
227 DCHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpLoop); | 222 DCHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpLoop); |
228 | 223 |
229 for (; !iterator.done(); iterator.Advance()) { | 224 int header_offset = iterator.GetJumpTargetOffset(); |
| 225 int end_offset = iterator.current_offset(); |
| 226 |
| 227 Liveness& header_liveness = liveness_map_.GetLiveness(header_offset); |
| 228 Liveness& end_liveness = liveness_map_.GetLiveness(end_offset); |
| 229 |
| 230 if (!end_liveness.out->UnionIsChanged(*header_liveness.in)) { |
| 231 // Only update the loop body if the loop end liveness changed. |
| 232 continue; |
| 233 } |
| 234 end_liveness.in->CopyFrom(*end_liveness.out); |
| 235 next_bytecode_in_liveness = end_liveness.in; |
| 236 |
| 237 // Advance into the loop body. |
| 238 --iterator; |
| 239 for (; iterator.current_offset() > header_offset; --iterator) { |
230 Bytecode bytecode = iterator.current_bytecode(); | 240 Bytecode bytecode = iterator.current_bytecode(); |
231 if (bytecode != Bytecode::kJumpLoop) { | |
232 // Skip bytecodes until we hit a JumpLoop. This check isn't needed for | |
233 // the first loop we see (thanks to saving its offset), but it is for | |
234 // subsequent ones we want to process on this pass. | |
235 continue; | |
236 } | |
237 | 241 |
238 int header_offset = iterator.GetJumpTargetOffset(); | 242 int current_offset = iterator.current_offset(); |
239 int end_offset = iterator.current_offset(); | 243 Liveness& liveness = liveness_map_.GetLiveness(current_offset); |
240 | 244 |
241 Liveness& header_liveness = liveness_map_.GetLiveness(header_offset); | 245 UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness, |
242 Liveness& end_liveness = liveness_map_.GetLiveness(end_offset); | 246 iterator, liveness_map_); |
| 247 liveness.in->CopyFrom(*liveness.out); |
| 248 UpdateInLiveness(bytecode, *liveness.in, iterator); |
243 | 249 |
244 if (end_liveness.out->UnionIsChanged(*header_liveness.in)) { | 250 next_bytecode_in_liveness = liveness.in; |
245 // Only update the loop body if the loop end liveness changed. | |
246 end_liveness.in->CopyFrom(*end_liveness.out); | |
247 next_bytecode_in_liveness = end_liveness.in; | |
248 | |
249 // Advance into the loop body. | |
250 iterator.Advance(); | |
251 for (; iterator.current_offset() > header_offset; iterator.Advance()) { | |
252 bytecode = iterator.current_bytecode(); | |
253 if (bytecode == Bytecode::kJumpLoop) { | |
254 // We can't validate this loop at the moment because we can't | |
255 // guarantee that its header is valid yet. Save it for later. | |
256 if (last_invalid_jumploop_offset == -1) { | |
257 last_invalid_jumploop_offset = iterator.current_offset(); | |
258 } | |
259 } | |
260 | |
261 int current_offset = iterator.current_offset(); | |
262 Liveness& liveness = liveness_map_.GetLiveness(current_offset); | |
263 | |
264 UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness, | |
265 iterator, liveness_map_); | |
266 liveness.in->CopyFrom(*liveness.out); | |
267 UpdateInLiveness(bytecode, *liveness.in, iterator); | |
268 | |
269 next_bytecode_in_liveness = liveness.in; | |
270 } | |
271 // Now we are at the loop header. Since the in-liveness of the header | |
272 // can't change, we need only to update the out-liveness. | |
273 bytecode = iterator.current_bytecode(); | |
274 UpdateOutLiveness(bytecode, *header_liveness.out, | |
275 next_bytecode_in_liveness, iterator, liveness_map_); | |
276 } | |
277 | |
278 // Keep the iterator going so that we can find other loops. | |
279 } | 251 } |
| 252 // Now we are at the loop header. Since the in-liveness of the header |
| 253 // can't change, we need only to update the out-liveness. |
| 254 UpdateOutLiveness(iterator.current_bytecode(), *header_liveness.out, |
| 255 next_bytecode_in_liveness, iterator, liveness_map_); |
280 } | 256 } |
281 | 257 |
282 DCHECK(LivenessIsValid()); | 258 DCHECK(LivenessIsValid()); |
283 } | 259 } |
284 | 260 |
285 void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) { | 261 void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) { |
286 DCHECK(loop_header < loop_end); | 262 DCHECK(loop_header < loop_end); |
287 DCHECK(loop_stack_.top() < loop_header); | 263 DCHECK(loop_stack_.top() < loop_header); |
288 DCHECK(end_to_header_.find(loop_end) == end_to_header_.end()); | 264 DCHECK(end_to_header_.find(loop_end) == end_to_header_.end()); |
289 DCHECK(header_to_parent_.find(loop_header) == header_to_parent_.end()); | 265 DCHECK(header_to_parent_.find(loop_header) == header_to_parent_.end()); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
369 | 345 |
370 os << " | " << current_offset << ": "; | 346 os << " | " << current_offset << ": "; |
371 iterator.PrintTo(os) << std::endl; | 347 iterator.PrintTo(os) << std::endl; |
372 } | 348 } |
373 | 349 |
374 return os; | 350 return os; |
375 } | 351 } |
376 | 352 |
377 #if DEBUG | 353 #if DEBUG |
378 bool BytecodeAnalysis::LivenessIsValid() { | 354 bool BytecodeAnalysis::LivenessIsValid() { |
379 BytecodeArrayReverseIterator iterator(bytecode_array(), zone()); | 355 BytecodeArrayRandomIterator iterator(bytecode_array(), zone()); |
380 | 356 |
381 BitVector previous_liveness(bytecode_array()->register_count() + 1, zone()); | 357 BitVector previous_liveness(bytecode_array()->register_count() + 1, zone()); |
382 | 358 |
383 int invalid_offset = -1; | 359 int invalid_offset = -1; |
384 int which_invalid = -1; | 360 int which_invalid = -1; |
385 | 361 |
386 BitVector* next_bytecode_in_liveness = nullptr; | 362 BitVector* next_bytecode_in_liveness = nullptr; |
387 | 363 |
388 // Ensure that there are no liveness changes if we iterate one more time. | 364 // Ensure that there are no liveness changes if we iterate one more time. |
389 for (iterator.Reset(); !iterator.done(); iterator.Advance()) { | 365 for (iterator.GoToEnd(); iterator.IsValid(); --iterator) { |
390 Bytecode bytecode = iterator.current_bytecode(); | 366 Bytecode bytecode = iterator.current_bytecode(); |
391 | 367 |
392 int current_offset = iterator.current_offset(); | 368 int current_offset = iterator.current_offset(); |
393 | 369 |
394 Liveness& liveness = liveness_map_.GetLiveness(current_offset); | 370 Liveness& liveness = liveness_map_.GetLiveness(current_offset); |
395 | 371 |
396 previous_liveness.CopyFrom(*liveness.out); | 372 previous_liveness.CopyFrom(*liveness.out); |
397 | 373 |
398 UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness, | 374 UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness, |
399 iterator, liveness_map_); | 375 iterator, liveness_map_); |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
495 } | 471 } |
496 } | 472 } |
497 | 473 |
498 return invalid_offset == -1; | 474 return invalid_offset == -1; |
499 } | 475 } |
500 #endif | 476 #endif |
501 | 477 |
502 } // namespace compiler | 478 } // namespace compiler |
503 } // namespace internal | 479 } // namespace internal |
504 } // namespace v8 | 480 } // namespace v8 |
OLD | NEW |