| 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 |