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-reverse-iterator.h" |
9 #include "src/objects-inl.h" | 9 #include "src/objects-inl.h" |
10 | 10 |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 } | 102 } |
103 } | 103 } |
104 default: | 104 default: |
105 DCHECK(!Bytecodes::IsRegisterInputOperandType(operand_types[i])); | 105 DCHECK(!Bytecodes::IsRegisterInputOperandType(operand_types[i])); |
106 break; | 106 break; |
107 } | 107 } |
108 } | 108 } |
109 } | 109 } |
110 | 110 |
111 void UpdateOutLiveness(Bytecode bytecode, BitVector& out_liveness, | 111 void UpdateOutLiveness(Bytecode bytecode, BitVector& out_liveness, |
| 112 BitVector* next_bytecode_in_liveness, |
112 const BytecodeArrayAccessor& accessor, | 113 const BytecodeArrayAccessor& accessor, |
113 const BytecodeLivenessMap& liveness_map) { | 114 const BytecodeLivenessMap& liveness_map) { |
114 int current_offset = accessor.current_offset(); | 115 int current_offset = accessor.current_offset(); |
115 const Handle<BytecodeArray>& bytecode_array = accessor.bytecode_array(); | 116 const Handle<BytecodeArray>& bytecode_array = accessor.bytecode_array(); |
116 | 117 |
117 // Update from jump target (if any). Skip loops, we update these manually in | 118 // Update from jump target (if any). Skip loops, we update these manually in |
118 // the liveness iterations. | 119 // the liveness iterations. |
119 if (Bytecodes::IsForwardJump(bytecode)) { | 120 if (Bytecodes::IsForwardJump(bytecode)) { |
120 int target_offset = accessor.GetJumpTargetOffset(); | 121 int target_offset = accessor.GetJumpTargetOffset(); |
121 out_liveness.Union(*liveness_map.GetInLiveness(target_offset)); | 122 out_liveness.Union(*liveness_map.GetInLiveness(target_offset)); |
122 } | 123 } |
123 | 124 |
124 // Update from next bytecode (unless this is an unconditional jump). | 125 // Update from next bytecode (unless there isn't one or this is an |
125 if (!Bytecodes::IsUnconditionalJump(bytecode)) { | 126 // unconditional jump). |
126 int next_offset = current_offset + accessor.current_bytecode_size(); | 127 if (next_bytecode_in_liveness != nullptr && |
127 if (next_offset < bytecode_array->length()) { | 128 !Bytecodes::IsUnconditionalJump(bytecode)) { |
128 out_liveness.Union(*liveness_map.GetInLiveness(next_offset)); | 129 out_liveness.Union(*next_bytecode_in_liveness); |
129 } | |
130 } | 130 } |
131 | 131 |
132 // Update from exception handler (if any). | 132 // Update from exception handler (if any). |
133 if (!interpreter::Bytecodes::IsWithoutExternalSideEffects(bytecode)) { | 133 if (!interpreter::Bytecodes::IsWithoutExternalSideEffects(bytecode)) { |
134 int handler_context; | 134 int handler_context; |
135 // TODO(leszeks): We should look up this range only once per entry. | 135 // TODO(leszeks): We should look up this range only once per entry. |
136 HandlerTable* table = HandlerTable::cast(bytecode_array->handler_table()); | 136 HandlerTable* table = HandlerTable::cast(bytecode_array->handler_table()); |
137 int handler_offset = | 137 int handler_offset = |
138 table->LookupRange(current_offset, &handler_context, nullptr); | 138 table->LookupRange(current_offset, &handler_context, nullptr); |
139 | 139 |
140 if (handler_offset != -1) { | 140 if (handler_offset != -1) { |
141 out_liveness.Union(*liveness_map.GetInLiveness(handler_offset)); | 141 out_liveness.Union(*liveness_map.GetInLiveness(handler_offset)); |
142 out_liveness.Add(handler_context); | 142 out_liveness.Add(handler_context); |
143 } | 143 } |
144 } | 144 } |
145 } | 145 } |
146 | 146 |
147 } // namespace | 147 } // namespace |
148 | 148 |
149 void BytecodeAnalysis::Analyze() { | 149 void BytecodeAnalysis::Analyze() { |
150 loop_stack_.push(-1); | 150 loop_stack_.push(-1); |
151 | 151 |
| 152 BitVector* next_bytecode_in_liveness = nullptr; |
| 153 |
152 // The last JumpLoop that we haven't done a guaranteed valid liveness pass | 154 // The last JumpLoop that we haven't done a guaranteed valid liveness pass |
153 // over. See the below wall of text for a more thorough explanation. | 155 // over. See the below wall of text for a more thorough explanation. |
154 int last_invalid_jumploop_offset = -1; | 156 int last_invalid_jumploop_offset = -1; |
155 | 157 |
156 BytecodeArrayReverseIterator iterator(bytecode_array(), zone()); | 158 BytecodeArrayReverseIterator iterator(bytecode_array(), zone()); |
157 for (; !iterator.done(); iterator.Advance()) { | 159 for (; !iterator.done(); iterator.Advance()) { |
158 Bytecode bytecode = iterator.current_bytecode(); | 160 Bytecode bytecode = iterator.current_bytecode(); |
159 int current_offset = iterator.current_offset(); | 161 int current_offset = iterator.current_offset(); |
160 | 162 |
161 if (bytecode == Bytecode::kJumpLoop) { | 163 if (bytecode == Bytecode::kJumpLoop) { |
162 PushLoop(iterator.GetJumpTargetOffset(), current_offset); | 164 PushLoop(iterator.GetJumpTargetOffset(), current_offset); |
163 | 165 |
164 // Save the last offset so that we can do another pass later. | 166 // Save the last offset so that we can do another pass later. |
165 if (last_invalid_jumploop_offset == -1) { | 167 if (last_invalid_jumploop_offset == -1) { |
166 last_invalid_jumploop_offset = current_offset; | 168 last_invalid_jumploop_offset = current_offset; |
167 } | 169 } |
168 } else if (current_offset == loop_stack_.top()) { | 170 } else if (current_offset == loop_stack_.top()) { |
169 loop_stack_.pop(); | 171 loop_stack_.pop(); |
170 } | 172 } |
171 | 173 |
172 if (do_liveness_analysis_) { | 174 if (do_liveness_analysis_) { |
173 // 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 |
174 // more bit for the liveness of the accumulator. | 176 // more bit for the liveness of the accumulator. |
175 Liveness& liveness = liveness_map_.InitializeLiveness( | 177 Liveness& liveness = liveness_map_.InitializeLiveness( |
176 current_offset, bytecode_array()->register_count() + 1, zone()); | 178 current_offset, bytecode_array()->register_count() + 1, zone()); |
177 | 179 |
178 UpdateOutLiveness(bytecode, *liveness.out, iterator, liveness_map_); | 180 UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness, |
| 181 iterator, liveness_map_); |
179 liveness.in->CopyFrom(*liveness.out); | 182 liveness.in->CopyFrom(*liveness.out); |
180 UpdateInLiveness(bytecode, *liveness.in, iterator); | 183 UpdateInLiveness(bytecode, *liveness.in, iterator); |
| 184 |
| 185 next_bytecode_in_liveness = liveness.in; |
181 } | 186 } |
182 } | 187 } |
183 | 188 |
184 DCHECK_EQ(loop_stack_.size(), 1u); | 189 DCHECK_EQ(loop_stack_.size(), 1u); |
185 DCHECK_EQ(loop_stack_.top(), -1); | 190 DCHECK_EQ(loop_stack_.top(), -1); |
186 | 191 |
187 if (!do_liveness_analysis_) return; | 192 if (!do_liveness_analysis_) return; |
188 | 193 |
189 // At this point, every bytecode has a valid in and out liveness, except for | 194 // At this point, every bytecode has a valid in and out liveness, except for |
190 // propagating liveness across back edges (i.e. JumpLoop). Subsequent liveness | 195 // propagating liveness across back edges (i.e. JumpLoop). Subsequent liveness |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 | 234 |
230 int header_offset = iterator.GetJumpTargetOffset(); | 235 int header_offset = iterator.GetJumpTargetOffset(); |
231 int end_offset = iterator.current_offset(); | 236 int end_offset = iterator.current_offset(); |
232 | 237 |
233 Liveness& header_liveness = liveness_map_.GetLiveness(header_offset); | 238 Liveness& header_liveness = liveness_map_.GetLiveness(header_offset); |
234 Liveness& end_liveness = liveness_map_.GetLiveness(end_offset); | 239 Liveness& end_liveness = liveness_map_.GetLiveness(end_offset); |
235 | 240 |
236 if (end_liveness.out->UnionIsChanged(*header_liveness.in)) { | 241 if (end_liveness.out->UnionIsChanged(*header_liveness.in)) { |
237 // Only update the loop body if the loop end liveness changed. | 242 // Only update the loop body if the loop end liveness changed. |
238 end_liveness.in->CopyFrom(*end_liveness.out); | 243 end_liveness.in->CopyFrom(*end_liveness.out); |
| 244 next_bytecode_in_liveness = end_liveness.in; |
239 | 245 |
240 // Advance into the loop body. | 246 // Advance into the loop body. |
241 iterator.Advance(); | 247 iterator.Advance(); |
242 for (; iterator.current_offset() > header_offset; iterator.Advance()) { | 248 for (; iterator.current_offset() > header_offset; iterator.Advance()) { |
243 bytecode = iterator.current_bytecode(); | 249 bytecode = iterator.current_bytecode(); |
244 if (bytecode == Bytecode::kJumpLoop) { | 250 if (bytecode == Bytecode::kJumpLoop) { |
245 // We can't validate this loop at the moment because we can't | 251 // We can't validate this loop at the moment because we can't |
246 // guarantee that its header is valid yet. Save it for later. | 252 // guarantee that its header is valid yet. Save it for later. |
247 if (last_invalid_jumploop_offset == -1) { | 253 if (last_invalid_jumploop_offset == -1) { |
248 last_invalid_jumploop_offset = iterator.current_offset(); | 254 last_invalid_jumploop_offset = iterator.current_offset(); |
249 } | 255 } |
250 } | 256 } |
251 | 257 |
252 int current_offset = iterator.current_offset(); | 258 int current_offset = iterator.current_offset(); |
253 Liveness& liveness = liveness_map_.GetLiveness(current_offset); | 259 Liveness& liveness = liveness_map_.GetLiveness(current_offset); |
254 | 260 |
255 UpdateOutLiveness(bytecode, *liveness.out, iterator, liveness_map_); | 261 UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness, |
| 262 iterator, liveness_map_); |
256 liveness.in->CopyFrom(*liveness.out); | 263 liveness.in->CopyFrom(*liveness.out); |
257 UpdateInLiveness(bytecode, *liveness.in, iterator); | 264 UpdateInLiveness(bytecode, *liveness.in, iterator); |
| 265 |
| 266 next_bytecode_in_liveness = liveness.in; |
258 } | 267 } |
259 // Now we are at the loop header. Since the in-liveness of the header | 268 // Now we are at the loop header. Since the in-liveness of the header |
260 // can't change, we need only to update the out-liveness. | 269 // can't change, we need only to update the out-liveness. |
261 bytecode = iterator.current_bytecode(); | 270 bytecode = iterator.current_bytecode(); |
262 UpdateOutLiveness(bytecode, *header_liveness.out, iterator, | 271 UpdateOutLiveness(bytecode, *header_liveness.out, |
263 liveness_map_); | 272 next_bytecode_in_liveness, iterator, liveness_map_); |
264 } | 273 } |
265 | 274 |
266 // Keep the iterator going so that we can find other loops. | 275 // Keep the iterator going so that we can find other loops. |
267 } | 276 } |
268 } | 277 } |
269 | 278 |
270 DCHECK(LivenessIsValid()); | 279 DCHECK(LivenessIsValid()); |
271 } | 280 } |
272 | 281 |
273 void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) { | 282 void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) { |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
364 | 373 |
365 #if DEBUG | 374 #if DEBUG |
366 bool BytecodeAnalysis::LivenessIsValid() { | 375 bool BytecodeAnalysis::LivenessIsValid() { |
367 BytecodeArrayReverseIterator iterator(bytecode_array(), zone()); | 376 BytecodeArrayReverseIterator iterator(bytecode_array(), zone()); |
368 | 377 |
369 BitVector previous_liveness(bytecode_array()->register_count() + 1, zone()); | 378 BitVector previous_liveness(bytecode_array()->register_count() + 1, zone()); |
370 | 379 |
371 int invalid_offset = -1; | 380 int invalid_offset = -1; |
372 int which_invalid = -1; | 381 int which_invalid = -1; |
373 | 382 |
| 383 BitVector* next_bytecode_in_liveness = nullptr; |
| 384 |
374 // Ensure that there are no liveness changes if we iterate one more time. | 385 // Ensure that there are no liveness changes if we iterate one more time. |
375 for (iterator.Reset(); !iterator.done(); iterator.Advance()) { | 386 for (iterator.Reset(); !iterator.done(); iterator.Advance()) { |
376 Bytecode bytecode = iterator.current_bytecode(); | 387 Bytecode bytecode = iterator.current_bytecode(); |
377 | 388 |
378 int current_offset = iterator.current_offset(); | 389 int current_offset = iterator.current_offset(); |
379 | 390 |
380 Liveness& liveness = liveness_map_.GetLiveness(current_offset); | 391 Liveness& liveness = liveness_map_.GetLiveness(current_offset); |
381 | 392 |
382 previous_liveness.CopyFrom(*liveness.out); | 393 previous_liveness.CopyFrom(*liveness.out); |
383 | 394 |
384 UpdateOutLiveness(bytecode, *liveness.out, iterator, liveness_map_); | 395 UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness, |
| 396 iterator, liveness_map_); |
385 // UpdateOutLiveness skips kJumpLoop, so we update it manually. | 397 // UpdateOutLiveness skips kJumpLoop, so we update it manually. |
386 if (bytecode == Bytecode::kJumpLoop) { | 398 if (bytecode == Bytecode::kJumpLoop) { |
387 int target_offset = iterator.GetJumpTargetOffset(); | 399 int target_offset = iterator.GetJumpTargetOffset(); |
388 liveness.out->Union(*liveness_map_.GetInLiveness(target_offset)); | 400 liveness.out->Union(*liveness_map_.GetInLiveness(target_offset)); |
389 } | 401 } |
390 | 402 |
391 if (!liveness.out->Equals(previous_liveness)) { | 403 if (!liveness.out->Equals(previous_liveness)) { |
392 // Reset the invalid liveness. | 404 // Reset the invalid liveness. |
393 liveness.out->CopyFrom(previous_liveness); | 405 liveness.out->CopyFrom(previous_liveness); |
394 invalid_offset = current_offset; | 406 invalid_offset = current_offset; |
395 which_invalid = 1; | 407 which_invalid = 1; |
396 break; | 408 break; |
397 } | 409 } |
398 | 410 |
399 previous_liveness.CopyFrom(*liveness.in); | 411 previous_liveness.CopyFrom(*liveness.in); |
400 | 412 |
401 liveness.in->CopyFrom(*liveness.out); | 413 liveness.in->CopyFrom(*liveness.out); |
402 UpdateInLiveness(bytecode, *liveness.in, iterator); | 414 UpdateInLiveness(bytecode, *liveness.in, iterator); |
403 | 415 |
404 if (!liveness.in->Equals(previous_liveness)) { | 416 if (!liveness.in->Equals(previous_liveness)) { |
405 // Reset the invalid liveness. | 417 // Reset the invalid liveness. |
406 liveness.in->CopyFrom(previous_liveness); | 418 liveness.in->CopyFrom(previous_liveness); |
407 invalid_offset = current_offset; | 419 invalid_offset = current_offset; |
408 which_invalid = 0; | 420 which_invalid = 0; |
409 break; | 421 break; |
410 } | 422 } |
| 423 |
| 424 next_bytecode_in_liveness = liveness.in; |
411 } | 425 } |
412 | 426 |
413 if (invalid_offset != -1) { | 427 if (invalid_offset != -1) { |
414 OFStream of(stderr); | 428 OFStream of(stderr); |
415 of << "Invalid liveness:" << std::endl; | 429 of << "Invalid liveness:" << std::endl; |
416 | 430 |
417 // Dump the bytecode, annotated with the liveness and marking loops. | 431 // Dump the bytecode, annotated with the liveness and marking loops. |
418 | 432 |
419 int loop_indent = 0; | 433 int loop_indent = 0; |
420 | 434 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
478 } | 492 } |
479 } | 493 } |
480 | 494 |
481 return invalid_offset == -1; | 495 return invalid_offset == -1; |
482 } | 496 } |
483 #endif | 497 #endif |
484 | 498 |
485 } // namespace compiler | 499 } // namespace compiler |
486 } // namespace internal | 500 } // namespace internal |
487 } // namespace v8 | 501 } // namespace v8 |
OLD | NEW |