| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 "hydrogen-check-elimination.h" | 5 #include "hydrogen-check-elimination.h" |
| 6 | 6 |
| 7 #include "hydrogen-alias-analysis.h" | 7 #include "hydrogen-alias-analysis.h" |
| 8 #include "hydrogen-flow-engine.h" | 8 #include "hydrogen-flow-engine.h" |
| 9 | 9 |
| 10 #define GLOBAL 1 | 10 #define GLOBAL 1 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 break; | 97 break; |
| 98 } | 98 } |
| 99 case HValue::kCompareMap: { | 99 case HValue::kCompareMap: { |
| 100 ReduceCompareMap(HCompareMap::cast(instr)); | 100 ReduceCompareMap(HCompareMap::cast(instr)); |
| 101 break; | 101 break; |
| 102 } | 102 } |
| 103 case HValue::kCompareObjectEqAndBranch: { | 103 case HValue::kCompareObjectEqAndBranch: { |
| 104 ReduceCompareObjectEqAndBranch(HCompareObjectEqAndBranch::cast(instr)); | 104 ReduceCompareObjectEqAndBranch(HCompareObjectEqAndBranch::cast(instr)); |
| 105 break; | 105 break; |
| 106 } | 106 } |
| 107 case HValue::kIsStringAndBranch: { |
| 108 ReduceIsStringAndBranch(HIsStringAndBranch::cast(instr)); |
| 109 break; |
| 110 } |
| 107 case HValue::kTransitionElementsKind: { | 111 case HValue::kTransitionElementsKind: { |
| 108 ReduceTransitionElementsKind( | 112 ReduceTransitionElementsKind( |
| 109 HTransitionElementsKind::cast(instr)); | 113 HTransitionElementsKind::cast(instr)); |
| 110 break; | 114 break; |
| 111 } | 115 } |
| 112 case HValue::kCheckHeapObject: { | 116 case HValue::kCheckHeapObject: { |
| 113 ReduceCheckHeapObject(HCheckHeapObject::cast(instr)); | 117 ReduceCheckHeapObject(HCheckHeapObject::cast(instr)); |
| 114 break; | 118 break; |
| 115 } | 119 } |
| 120 case HValue::kCheckInstanceType: { |
| 121 ReduceCheckInstanceType(HCheckInstanceType::cast(instr)); |
| 122 break; |
| 123 } |
| 116 default: { | 124 default: { |
| 117 // If the instruction changes maps uncontrollably, drop everything. | 125 // If the instruction changes maps uncontrollably, drop everything. |
| 118 if (instr->CheckChangesFlag(kOsrEntries)) { | 126 if (instr->CheckChangesFlag(kOsrEntries)) { |
| 119 Kill(); | 127 Kill(); |
| 120 break; | 128 break; |
| 121 } | 129 } |
| 122 if (instr->CheckChangesFlag(kElementsKind) || | 130 if (instr->CheckChangesFlag(kElementsKind) || |
| 123 instr->CheckChangesFlag(kMaps)) { | 131 instr->CheckChangesFlag(kMaps)) { |
| 124 KillUnstableEntries(); | 132 KillUnstableEntries(); |
| 125 } | 133 } |
| 126 } | 134 } |
| 127 // Improvements possible: | 135 // Improvements possible: |
| 128 // - eliminate redundant HCheckSmi, HCheckInstanceType instructions | 136 // - eliminate redundant HCheckSmi instructions |
| 129 // - track which values have been HCheckHeapObject'd | 137 // - track which values have been HCheckHeapObject'd |
| 130 } | 138 } |
| 131 | 139 |
| 132 return this; | 140 return this; |
| 133 } | 141 } |
| 134 | 142 |
| 135 // Support for global analysis with HFlowEngine: Merge given state with | 143 // Support for global analysis with HFlowEngine: Merge given state with |
| 136 // the other incoming state. | 144 // the other incoming state. |
| 137 static HCheckTable* Merge(HCheckTable* succ_state, HBasicBlock* succ_block, | 145 static HCheckTable* Merge(HCheckTable* succ_state, HBasicBlock* succ_block, |
| 138 HCheckTable* pred_state, HBasicBlock* pred_block, | 146 HCheckTable* pred_state, HBasicBlock* pred_block, |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 254 } else { | 262 } else { |
| 255 EnsureChecked(le, cmp->left(), cmp); | 263 EnsureChecked(le, cmp->left(), cmp); |
| 256 EnsureChecked(re, cmp->right(), cmp); | 264 EnsureChecked(re, cmp->right(), cmp); |
| 257 le->maps_ = re->maps_ = le->maps_->Intersect(re->maps_, zone); | 265 le->maps_ = re->maps_ = le->maps_->Intersect(re->maps_, zone); |
| 258 le->state_ = re->state_ = HCheckTableEntry::StateMerge( | 266 le->state_ = re->state_ = HCheckTableEntry::StateMerge( |
| 259 le->state_, re->state_); | 267 le->state_, re->state_); |
| 260 ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, le->state_); | 268 ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, le->state_); |
| 261 ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, re->state_); | 269 ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, re->state_); |
| 262 } | 270 } |
| 263 learned = true; | 271 learned = true; |
| 272 } else if (end->IsIsStringAndBranch()) { |
| 273 HIsStringAndBranch* cmp = HIsStringAndBranch::cast(end); |
| 274 HValue* object = cmp->value()->ActualValue(); |
| 275 HCheckTableEntry* entry = copy->Find(object); |
| 276 if (is_true_branch) { |
| 277 // Learn on the true branch of if(IsString(x)). |
| 278 if (entry == NULL) { |
| 279 copy->Insert(object, NULL, string_maps(), |
| 280 HCheckTableEntry::CHECKED); |
| 281 } else { |
| 282 EnsureChecked(entry, object, cmp); |
| 283 entry->maps_ = entry->maps_->Intersect(string_maps(), zone); |
| 284 ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, entry->state_); |
| 285 } |
| 286 } else { |
| 287 // Learn on the false branch of if(IsString(x)). |
| 288 if (entry != NULL) { |
| 289 EnsureChecked(entry, object, cmp); |
| 290 entry->maps_ = entry->maps_->Subtract(string_maps(), zone); |
| 291 ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, entry->state_); |
| 292 } |
| 293 } |
| 264 } | 294 } |
| 265 // Learning on false branches requires storing negative facts. | 295 // Learning on false branches requires storing negative facts. |
| 266 } | 296 } |
| 267 | 297 |
| 268 if (FLAG_trace_check_elimination) { | 298 if (FLAG_trace_check_elimination) { |
| 269 PrintF("B%d checkmaps-table %s from B%d:\n", | 299 PrintF("B%d checkmaps-table %s from B%d:\n", |
| 270 succ->block_id(), | 300 succ->block_id(), |
| 271 learned ? "learned" : "copied", | 301 learned ? "learned" : "copied", |
| 272 from_block->block_id()); | 302 from_block->block_id()); |
| 273 Print(copy); | 303 Print(copy); |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 408 } else { | 438 } else { |
| 409 // No entry; insert a new one. | 439 // No entry; insert a new one. |
| 410 HCheckTableEntry::State state = instr->maps_are_stable() | 440 HCheckTableEntry::State state = instr->maps_are_stable() |
| 411 ? HCheckTableEntry::CHECKED_STABLE | 441 ? HCheckTableEntry::CHECKED_STABLE |
| 412 : HCheckTableEntry::CHECKED; | 442 : HCheckTableEntry::CHECKED; |
| 413 HCheckMaps* check = instr->IsStabilityCheck() ? NULL : instr; | 443 HCheckMaps* check = instr->IsStabilityCheck() ? NULL : instr; |
| 414 Insert(object, check, instr->maps(), state); | 444 Insert(object, check, instr->maps(), state); |
| 415 } | 445 } |
| 416 } | 446 } |
| 417 | 447 |
| 448 void ReduceCheckInstanceType(HCheckInstanceType* instr) { |
| 449 HValue* value = instr->value()->ActualValue(); |
| 450 HCheckTableEntry* entry = Find(value); |
| 451 if (entry == NULL) { |
| 452 if (instr->check() == HCheckInstanceType::IS_STRING) { |
| 453 Insert(value, NULL, string_maps(), HCheckTableEntry::CHECKED); |
| 454 } |
| 455 return; |
| 456 } |
| 457 UniqueSet<Map>* maps = new(zone()) UniqueSet<Map>( |
| 458 entry->maps_->size(), zone()); |
| 459 for (int i = 0; i < entry->maps_->size(); ++i) { |
| 460 InstanceType type; |
| 461 Unique<Map> map = entry->maps_->at(i); |
| 462 { |
| 463 // This is safe, because maps don't move and their instance type does |
| 464 // not change. |
| 465 AllowHandleDereference allow_deref; |
| 466 type = map.handle()->instance_type(); |
| 467 } |
| 468 if (instr->is_interval_check()) { |
| 469 InstanceType first_type, last_type; |
| 470 instr->GetCheckInterval(&first_type, &last_type); |
| 471 if (first_type <= type && type <= last_type) maps->Add(map, zone()); |
| 472 } else { |
| 473 uint8_t mask, tag; |
| 474 instr->GetCheckMaskAndTag(&mask, &tag); |
| 475 if ((type & mask) == tag) maps->Add(map, zone()); |
| 476 } |
| 477 } |
| 478 if (maps->size() == entry->maps_->size()) { |
| 479 TRACE(("Removing redundant CheckInstanceType #%d at B%d\n", |
| 480 instr->id(), instr->block()->block_id())); |
| 481 EnsureChecked(entry, value, instr); |
| 482 instr->DeleteAndReplaceWith(value); |
| 483 INC_STAT(removed_cit_); |
| 484 } else if (maps->size() != 0) { |
| 485 entry->maps_ = maps; |
| 486 if (entry->state_ == HCheckTableEntry::UNCHECKED_STABLE) { |
| 487 entry->state_ = HCheckTableEntry::CHECKED_STABLE; |
| 488 } |
| 489 } |
| 490 } |
| 491 |
| 418 void ReduceLoadNamedField(HLoadNamedField* instr) { | 492 void ReduceLoadNamedField(HLoadNamedField* instr) { |
| 419 // Reduce a load of the map field when it is known to be a constant. | 493 // Reduce a load of the map field when it is known to be a constant. |
| 420 if (!instr->access().IsMap()) { | 494 if (!instr->access().IsMap()) { |
| 421 // Check if we introduce field maps here. | 495 // Check if we introduce field maps here. |
| 422 MapSet maps = instr->maps(); | 496 MapSet maps = instr->maps(); |
| 423 if (maps != NULL) { | 497 if (maps != NULL) { |
| 424 ASSERT_NE(0, maps->size()); | 498 ASSERT_NE(0, maps->size()); |
| 425 Insert(instr, NULL, maps, HCheckTableEntry::UNCHECKED_STABLE); | 499 Insert(instr, NULL, maps, HCheckTableEntry::UNCHECKED_STABLE); |
| 426 } | 500 } |
| 427 return; | 501 return; |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 521 | 595 |
| 522 TRACE(("Marking redundant CompareObjectEqAndBranch #%d at B%d as false\n", | 596 TRACE(("Marking redundant CompareObjectEqAndBranch #%d at B%d as false\n", |
| 523 instr->id(), instr->block()->block_id())); | 597 instr->id(), instr->block()->block_id())); |
| 524 int succ = 1; | 598 int succ = 1; |
| 525 instr->set_known_successor_index(succ); | 599 instr->set_known_successor_index(succ); |
| 526 | 600 |
| 527 int unreachable_succ = 1 - succ; | 601 int unreachable_succ = 1 - succ; |
| 528 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ); | 602 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ); |
| 529 } | 603 } |
| 530 | 604 |
| 605 void ReduceIsStringAndBranch(HIsStringAndBranch* instr) { |
| 606 HValue* value = instr->value()->ActualValue(); |
| 607 HCheckTableEntry* entry = Find(value); |
| 608 if (entry == NULL) return; |
| 609 EnsureChecked(entry, value, instr); |
| 610 int succ; |
| 611 if (entry->maps_->IsSubset(string_maps())) { |
| 612 TRACE(("Marking redundant IsStringAndBranch #%d at B%d as true\n", |
| 613 instr->id(), instr->block()->block_id())); |
| 614 succ = 0; |
| 615 } else { |
| 616 MapSet intersection = entry->maps_->Intersect(string_maps(), zone()); |
| 617 if (intersection->size() > 0) return; |
| 618 TRACE(("Marking redundant IsStringAndBranch #%d at B%d as false\n", |
| 619 instr->id(), instr->block()->block_id())); |
| 620 succ = 1; |
| 621 } |
| 622 instr->set_known_successor_index(succ); |
| 623 int unreachable_succ = 1 - succ; |
| 624 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ); |
| 625 } |
| 626 |
| 531 void ReduceTransitionElementsKind(HTransitionElementsKind* instr) { | 627 void ReduceTransitionElementsKind(HTransitionElementsKind* instr) { |
| 532 HValue* object = instr->object()->ActualValue(); | 628 HValue* object = instr->object()->ActualValue(); |
| 533 HCheckTableEntry* entry = Find(object); | 629 HCheckTableEntry* entry = Find(object); |
| 534 // Can only learn more about an object that already has a known set of maps. | 630 // Can only learn more about an object that already has a known set of maps. |
| 535 if (entry == NULL) return; | 631 if (entry == NULL) return; |
| 536 EnsureChecked(entry, object, instr); | 632 EnsureChecked(entry, object, instr); |
| 537 if (entry->maps_->Contains(instr->original_map())) { | 633 if (entry->maps_->Contains(instr->original_map())) { |
| 538 // If the object has the original map, it will be transitioned. | 634 // If the object has the original map, it will be transitioned. |
| 539 UniqueSet<Map>* maps = entry->maps_->Copy(zone()); | 635 UniqueSet<Map>* maps = entry->maps_->Copy(zone()); |
| 540 maps->Remove(instr->original_map()); | 636 maps->Remove(instr->original_map()); |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 681 entry->object_ = object; | 777 entry->object_ = object; |
| 682 entry->check_ = check; | 778 entry->check_ = check; |
| 683 entry->maps_ = maps; | 779 entry->maps_ = maps; |
| 684 entry->state_ = state; | 780 entry->state_ = state; |
| 685 // If the table becomes full, wrap around and overwrite older entries. | 781 // If the table becomes full, wrap around and overwrite older entries. |
| 686 if (cursor_ == kMaxTrackedObjects) cursor_ = 0; | 782 if (cursor_ == kMaxTrackedObjects) cursor_ = 0; |
| 687 if (size_ < kMaxTrackedObjects) size_++; | 783 if (size_ < kMaxTrackedObjects) size_++; |
| 688 } | 784 } |
| 689 | 785 |
| 690 Zone* zone() const { return phase_->zone(); } | 786 Zone* zone() const { return phase_->zone(); } |
| 787 MapSet string_maps() const { return phase_->string_maps(); } |
| 691 | 788 |
| 692 friend class HCheckMapsEffects; | 789 friend class HCheckMapsEffects; |
| 693 friend class HCheckEliminationPhase; | 790 friend class HCheckEliminationPhase; |
| 694 | 791 |
| 695 HCheckEliminationPhase* phase_; | 792 HCheckEliminationPhase* phase_; |
| 696 HCheckTableEntry entries_[kMaxTrackedObjects]; | 793 HCheckTableEntry entries_[kMaxTrackedObjects]; |
| 697 int16_t cursor_; // Must be <= kMaxTrackedObjects | 794 int16_t cursor_; // Must be <= kMaxTrackedObjects |
| 698 int16_t size_; // Must be <= kMaxTrackedObjects | 795 int16_t size_; // Must be <= kMaxTrackedObjects |
| 699 STATIC_ASSERT(kMaxTrackedObjects < (1 << 15)); | 796 STATIC_ASSERT(kMaxTrackedObjects < (1 << 15)); |
| 700 }; | 797 }; |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 787 // Are we eliminated yet? | 884 // Are we eliminated yet? |
| 788 void HCheckEliminationPhase::PrintStats() { | 885 void HCheckEliminationPhase::PrintStats() { |
| 789 #if DEBUG | 886 #if DEBUG |
| 790 #define PRINT_STAT(x) if (x##_ > 0) PrintF(" %-16s = %2d\n", #x, x##_) | 887 #define PRINT_STAT(x) if (x##_ > 0) PrintF(" %-16s = %2d\n", #x, x##_) |
| 791 #else | 888 #else |
| 792 #define PRINT_STAT(x) | 889 #define PRINT_STAT(x) |
| 793 #endif | 890 #endif |
| 794 PRINT_STAT(redundant); | 891 PRINT_STAT(redundant); |
| 795 PRINT_STAT(removed); | 892 PRINT_STAT(removed); |
| 796 PRINT_STAT(removed_cho); | 893 PRINT_STAT(removed_cho); |
| 894 PRINT_STAT(removed_cit); |
| 797 PRINT_STAT(narrowed); | 895 PRINT_STAT(narrowed); |
| 798 PRINT_STAT(loads); | 896 PRINT_STAT(loads); |
| 799 PRINT_STAT(empty); | 897 PRINT_STAT(empty); |
| 800 PRINT_STAT(compares_true); | 898 PRINT_STAT(compares_true); |
| 801 PRINT_STAT(compares_false); | 899 PRINT_STAT(compares_false); |
| 802 PRINT_STAT(transitions); | 900 PRINT_STAT(transitions); |
| 803 } | 901 } |
| 804 | 902 |
| 805 } } // namespace v8::internal | 903 } } // namespace v8::internal |
| OLD | NEW |