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 } | |
111 case HValue::kTransitionElementsKind: { | 107 case HValue::kTransitionElementsKind: { |
112 ReduceTransitionElementsKind( | 108 ReduceTransitionElementsKind( |
113 HTransitionElementsKind::cast(instr)); | 109 HTransitionElementsKind::cast(instr)); |
114 break; | 110 break; |
115 } | 111 } |
116 case HValue::kCheckHeapObject: { | 112 case HValue::kCheckHeapObject: { |
117 ReduceCheckHeapObject(HCheckHeapObject::cast(instr)); | 113 ReduceCheckHeapObject(HCheckHeapObject::cast(instr)); |
118 break; | 114 break; |
119 } | 115 } |
120 case HValue::kCheckInstanceType: { | |
121 ReduceCheckInstanceType(HCheckInstanceType::cast(instr)); | |
122 break; | |
123 } | |
124 default: { | 116 default: { |
125 // If the instruction changes maps uncontrollably, drop everything. | 117 // If the instruction changes maps uncontrollably, drop everything. |
126 if (instr->CheckChangesFlag(kOsrEntries)) { | 118 if (instr->CheckChangesFlag(kOsrEntries)) { |
127 Kill(); | 119 Kill(); |
128 break; | 120 break; |
129 } | 121 } |
130 if (instr->CheckChangesFlag(kElementsKind) || | 122 if (instr->CheckChangesFlag(kElementsKind) || |
131 instr->CheckChangesFlag(kMaps)) { | 123 instr->CheckChangesFlag(kMaps)) { |
132 KillUnstableEntries(); | 124 KillUnstableEntries(); |
133 } | 125 } |
134 } | 126 } |
135 // Improvements possible: | 127 // Improvements possible: |
136 // - eliminate redundant HCheckSmi instructions | 128 // - eliminate redundant HCheckSmi, HCheckInstanceType instructions |
137 // - track which values have been HCheckHeapObject'd | 129 // - track which values have been HCheckHeapObject'd |
138 } | 130 } |
139 | 131 |
140 return this; | 132 return this; |
141 } | 133 } |
142 | 134 |
143 // Support for global analysis with HFlowEngine: Merge given state with | 135 // Support for global analysis with HFlowEngine: Merge given state with |
144 // the other incoming state. | 136 // the other incoming state. |
145 static HCheckTable* Merge(HCheckTable* succ_state, HBasicBlock* succ_block, | 137 static HCheckTable* Merge(HCheckTable* succ_state, HBasicBlock* succ_block, |
146 HCheckTable* pred_state, HBasicBlock* pred_block, | 138 HCheckTable* pred_state, HBasicBlock* pred_block, |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
262 } else { | 254 } else { |
263 EnsureChecked(le, cmp->left(), cmp); | 255 EnsureChecked(le, cmp->left(), cmp); |
264 EnsureChecked(re, cmp->right(), cmp); | 256 EnsureChecked(re, cmp->right(), cmp); |
265 le->maps_ = re->maps_ = le->maps_->Intersect(re->maps_, zone); | 257 le->maps_ = re->maps_ = le->maps_->Intersect(re->maps_, zone); |
266 le->state_ = re->state_ = HCheckTableEntry::StateMerge( | 258 le->state_ = re->state_ = HCheckTableEntry::StateMerge( |
267 le->state_, re->state_); | 259 le->state_, re->state_); |
268 ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, le->state_); | 260 ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, le->state_); |
269 ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, re->state_); | 261 ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, re->state_); |
270 } | 262 } |
271 learned = true; | 263 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 } | |
294 } | 264 } |
295 // Learning on false branches requires storing negative facts. | 265 // Learning on false branches requires storing negative facts. |
296 } | 266 } |
297 | 267 |
298 if (FLAG_trace_check_elimination) { | 268 if (FLAG_trace_check_elimination) { |
299 PrintF("B%d checkmaps-table %s from B%d:\n", | 269 PrintF("B%d checkmaps-table %s from B%d:\n", |
300 succ->block_id(), | 270 succ->block_id(), |
301 learned ? "learned" : "copied", | 271 learned ? "learned" : "copied", |
302 from_block->block_id()); | 272 from_block->block_id()); |
303 Print(copy); | 273 Print(copy); |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
438 } else { | 408 } else { |
439 // No entry; insert a new one. | 409 // No entry; insert a new one. |
440 HCheckTableEntry::State state = instr->maps_are_stable() | 410 HCheckTableEntry::State state = instr->maps_are_stable() |
441 ? HCheckTableEntry::CHECKED_STABLE | 411 ? HCheckTableEntry::CHECKED_STABLE |
442 : HCheckTableEntry::CHECKED; | 412 : HCheckTableEntry::CHECKED; |
443 HCheckMaps* check = instr->IsStabilityCheck() ? NULL : instr; | 413 HCheckMaps* check = instr->IsStabilityCheck() ? NULL : instr; |
444 Insert(object, check, instr->maps(), state); | 414 Insert(object, check, instr->maps(), state); |
445 } | 415 } |
446 } | 416 } |
447 | 417 |
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 | |
492 void ReduceLoadNamedField(HLoadNamedField* instr) { | 418 void ReduceLoadNamedField(HLoadNamedField* instr) { |
493 // Reduce a load of the map field when it is known to be a constant. | 419 // Reduce a load of the map field when it is known to be a constant. |
494 if (!instr->access().IsMap()) { | 420 if (!instr->access().IsMap()) { |
495 // Check if we introduce field maps here. | 421 // Check if we introduce field maps here. |
496 MapSet maps = instr->maps(); | 422 MapSet maps = instr->maps(); |
497 if (maps != NULL) { | 423 if (maps != NULL) { |
498 ASSERT_NE(0, maps->size()); | 424 ASSERT_NE(0, maps->size()); |
499 Insert(instr, NULL, maps, HCheckTableEntry::UNCHECKED_STABLE); | 425 Insert(instr, NULL, maps, HCheckTableEntry::UNCHECKED_STABLE); |
500 } | 426 } |
501 return; | 427 return; |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
595 | 521 |
596 TRACE(("Marking redundant CompareObjectEqAndBranch #%d at B%d as false\n", | 522 TRACE(("Marking redundant CompareObjectEqAndBranch #%d at B%d as false\n", |
597 instr->id(), instr->block()->block_id())); | 523 instr->id(), instr->block()->block_id())); |
598 int succ = 1; | 524 int succ = 1; |
599 instr->set_known_successor_index(succ); | 525 instr->set_known_successor_index(succ); |
600 | 526 |
601 int unreachable_succ = 1 - succ; | 527 int unreachable_succ = 1 - succ; |
602 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ); | 528 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ); |
603 } | 529 } |
604 | 530 |
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 | |
627 void ReduceTransitionElementsKind(HTransitionElementsKind* instr) { | 531 void ReduceTransitionElementsKind(HTransitionElementsKind* instr) { |
628 HValue* object = instr->object()->ActualValue(); | 532 HValue* object = instr->object()->ActualValue(); |
629 HCheckTableEntry* entry = Find(object); | 533 HCheckTableEntry* entry = Find(object); |
630 // Can only learn more about an object that already has a known set of maps. | 534 // Can only learn more about an object that already has a known set of maps. |
631 if (entry == NULL) return; | 535 if (entry == NULL) return; |
632 EnsureChecked(entry, object, instr); | 536 EnsureChecked(entry, object, instr); |
633 if (entry->maps_->Contains(instr->original_map())) { | 537 if (entry->maps_->Contains(instr->original_map())) { |
634 // If the object has the original map, it will be transitioned. | 538 // If the object has the original map, it will be transitioned. |
635 UniqueSet<Map>* maps = entry->maps_->Copy(zone()); | 539 UniqueSet<Map>* maps = entry->maps_->Copy(zone()); |
636 maps->Remove(instr->original_map()); | 540 maps->Remove(instr->original_map()); |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
777 entry->object_ = object; | 681 entry->object_ = object; |
778 entry->check_ = check; | 682 entry->check_ = check; |
779 entry->maps_ = maps; | 683 entry->maps_ = maps; |
780 entry->state_ = state; | 684 entry->state_ = state; |
781 // If the table becomes full, wrap around and overwrite older entries. | 685 // If the table becomes full, wrap around and overwrite older entries. |
782 if (cursor_ == kMaxTrackedObjects) cursor_ = 0; | 686 if (cursor_ == kMaxTrackedObjects) cursor_ = 0; |
783 if (size_ < kMaxTrackedObjects) size_++; | 687 if (size_ < kMaxTrackedObjects) size_++; |
784 } | 688 } |
785 | 689 |
786 Zone* zone() const { return phase_->zone(); } | 690 Zone* zone() const { return phase_->zone(); } |
787 MapSet string_maps() const { return phase_->string_maps(); } | |
788 | 691 |
789 friend class HCheckMapsEffects; | 692 friend class HCheckMapsEffects; |
790 friend class HCheckEliminationPhase; | 693 friend class HCheckEliminationPhase; |
791 | 694 |
792 HCheckEliminationPhase* phase_; | 695 HCheckEliminationPhase* phase_; |
793 HCheckTableEntry entries_[kMaxTrackedObjects]; | 696 HCheckTableEntry entries_[kMaxTrackedObjects]; |
794 int16_t cursor_; // Must be <= kMaxTrackedObjects | 697 int16_t cursor_; // Must be <= kMaxTrackedObjects |
795 int16_t size_; // Must be <= kMaxTrackedObjects | 698 int16_t size_; // Must be <= kMaxTrackedObjects |
796 STATIC_ASSERT(kMaxTrackedObjects < (1 << 15)); | 699 STATIC_ASSERT(kMaxTrackedObjects < (1 << 15)); |
797 }; | 700 }; |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
884 // Are we eliminated yet? | 787 // Are we eliminated yet? |
885 void HCheckEliminationPhase::PrintStats() { | 788 void HCheckEliminationPhase::PrintStats() { |
886 #if DEBUG | 789 #if DEBUG |
887 #define PRINT_STAT(x) if (x##_ > 0) PrintF(" %-16s = %2d\n", #x, x##_) | 790 #define PRINT_STAT(x) if (x##_ > 0) PrintF(" %-16s = %2d\n", #x, x##_) |
888 #else | 791 #else |
889 #define PRINT_STAT(x) | 792 #define PRINT_STAT(x) |
890 #endif | 793 #endif |
891 PRINT_STAT(redundant); | 794 PRINT_STAT(redundant); |
892 PRINT_STAT(removed); | 795 PRINT_STAT(removed); |
893 PRINT_STAT(removed_cho); | 796 PRINT_STAT(removed_cho); |
894 PRINT_STAT(removed_cit); | |
895 PRINT_STAT(narrowed); | 797 PRINT_STAT(narrowed); |
896 PRINT_STAT(loads); | 798 PRINT_STAT(loads); |
897 PRINT_STAT(empty); | 799 PRINT_STAT(empty); |
898 PRINT_STAT(compares_true); | 800 PRINT_STAT(compares_true); |
899 PRINT_STAT(compares_false); | 801 PRINT_STAT(compares_false); |
900 PRINT_STAT(transitions); | 802 PRINT_STAT(transitions); |
901 } | 803 } |
902 | 804 |
903 } } // namespace v8::internal | 805 } } // namespace v8::internal |
OLD | NEW |