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 |