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 UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(); | |
291 for (int i = 0; i < entry->maps_->size(); ++i) { | |
292 Unique<Map> map = entry->maps_->at(i); | |
293 if (!string_maps()->Contains(map)) maps->Add(map, zone); | |
294 } | |
Igor Sheludko
2014/05/30 10:00:41
Suggestion: What about adding Subtract() method to
Benedikt Meurer
2014/05/31 11:15:46
Done.
| |
295 entry->maps_ = maps; | |
296 ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, entry->state_); | |
297 } | |
298 } | |
264 } | 299 } |
265 // Learning on false branches requires storing negative facts. | 300 // Learning on false branches requires storing negative facts. |
266 } | 301 } |
267 | 302 |
268 if (FLAG_trace_check_elimination) { | 303 if (FLAG_trace_check_elimination) { |
269 PrintF("B%d checkmaps-table %s from B%d:\n", | 304 PrintF("B%d checkmaps-table %s from B%d:\n", |
270 succ->block_id(), | 305 succ->block_id(), |
271 learned ? "learned" : "copied", | 306 learned ? "learned" : "copied", |
272 from_block->block_id()); | 307 from_block->block_id()); |
273 Print(copy); | 308 Print(copy); |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
408 } else { | 443 } else { |
409 // No entry; insert a new one. | 444 // No entry; insert a new one. |
410 HCheckTableEntry::State state = instr->maps_are_stable() | 445 HCheckTableEntry::State state = instr->maps_are_stable() |
411 ? HCheckTableEntry::CHECKED_STABLE | 446 ? HCheckTableEntry::CHECKED_STABLE |
412 : HCheckTableEntry::CHECKED; | 447 : HCheckTableEntry::CHECKED; |
413 HCheckMaps* check = instr->IsStabilityCheck() ? NULL : instr; | 448 HCheckMaps* check = instr->IsStabilityCheck() ? NULL : instr; |
414 Insert(object, check, instr->maps(), state); | 449 Insert(object, check, instr->maps(), state); |
415 } | 450 } |
416 } | 451 } |
417 | 452 |
453 void ReduceCheckInstanceType(HCheckInstanceType* instr) { | |
454 HValue* value = instr->value()->ActualValue(); | |
455 HCheckTableEntry* entry = Find(value); | |
456 if (entry == NULL) return; | |
457 for (int i = 0; i < entry->maps_->size(); ++i) { | |
458 InstanceType type; | |
459 Handle<Map> map = entry->maps_->at(i).handle(); | |
460 { | |
461 // This is safe, because maps don't move and their instance type does | |
462 // not change. | |
463 AllowHandleDereference allow_deref; | |
464 type = map->instance_type(); | |
465 } | |
466 if (instr->is_interval_check()) { | |
467 InstanceType first_type, last_type; | |
468 instr->GetCheckInterval(&first_type, &last_type); | |
469 if (type < first_type || last_type < type) return; | |
470 } else { | |
471 uint8_t mask, tag; | |
472 instr->GetCheckMaskAndTag(&mask, &tag); | |
473 if ((type & mask) != tag) return; | |
474 } | |
475 } | |
Igor Sheludko
2014/05/30 10:00:41
Does it make sense to update set of entry maps if
Benedikt Meurer
2014/05/31 11:15:46
Done.
| |
476 TRACE(("Removing redundant CheckInstanceType #%d at B%d\n", | |
477 instr->id(), instr->block()->block_id())); | |
478 EnsureChecked(entry, value, instr); | |
479 instr->DeleteAndReplaceWith(value); | |
480 INC_STAT(removed_cit_); | |
481 return; | |
482 } | |
483 | |
418 void ReduceLoadNamedField(HLoadNamedField* instr) { | 484 void ReduceLoadNamedField(HLoadNamedField* instr) { |
419 // Reduce a load of the map field when it is known to be a constant. | 485 // Reduce a load of the map field when it is known to be a constant. |
420 if (!instr->access().IsMap()) { | 486 if (!instr->access().IsMap()) { |
421 // Check if we introduce field maps here. | 487 // Check if we introduce field maps here. |
422 MapSet maps = instr->maps(); | 488 MapSet maps = instr->maps(); |
423 if (maps != NULL) { | 489 if (maps != NULL) { |
424 ASSERT_NE(0, maps->size()); | 490 ASSERT_NE(0, maps->size()); |
425 Insert(instr, NULL, maps, HCheckTableEntry::UNCHECKED_STABLE); | 491 Insert(instr, NULL, maps, HCheckTableEntry::UNCHECKED_STABLE); |
426 } | 492 } |
427 return; | 493 return; |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
521 | 587 |
522 TRACE(("Marking redundant CompareObjectEqAndBranch #%d at B%d as false\n", | 588 TRACE(("Marking redundant CompareObjectEqAndBranch #%d at B%d as false\n", |
523 instr->id(), instr->block()->block_id())); | 589 instr->id(), instr->block()->block_id())); |
524 int succ = 1; | 590 int succ = 1; |
525 instr->set_known_successor_index(succ); | 591 instr->set_known_successor_index(succ); |
526 | 592 |
527 int unreachable_succ = 1 - succ; | 593 int unreachable_succ = 1 - succ; |
528 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ); | 594 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ); |
529 } | 595 } |
530 | 596 |
597 void ReduceIsStringAndBranch(HIsStringAndBranch* instr) { | |
598 HValue* value = instr->value()->ActualValue(); | |
599 HCheckTableEntry* entry = Find(value); | |
600 if (entry == NULL) return; | |
601 EnsureChecked(entry, value, instr); | |
602 if (entry->maps_->IsSubset(string_maps())) { | |
603 TRACE(("Marking redundant IsStringAndBranch #%d at B%d as true\n", | |
604 instr->id(), instr->block()->block_id())); | |
605 int succ = 0; | |
606 instr->set_known_successor_index(succ); | |
607 | |
608 int unreachable_succ = 1 - succ; | |
609 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ); | |
610 return; | |
611 } | |
612 | |
613 // TODO(bmeurer): Add a predicate here instead of computing the intersection | |
614 MapSet intersection = entry->maps_->Intersect(string_maps(), zone()); | |
615 if (intersection->size() > 0) return; | |
616 | |
617 TRACE(("Marking redundant IsStringAndBranch #%d at B%d as false\n", | |
618 instr->id(), instr->block()->block_id())); | |
619 int succ = 1; | |
620 instr->set_known_successor_index(succ); | |
621 | |
622 int unreachable_succ = 1 - succ; | |
623 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ); | |
Igor Sheludko
2014/05/30 10:00:41
I would suggest to avoid duplication of the three
Benedikt Meurer
2014/05/31 11:15:46
Done.
| |
624 } | |
625 | |
531 void ReduceTransitionElementsKind(HTransitionElementsKind* instr) { | 626 void ReduceTransitionElementsKind(HTransitionElementsKind* instr) { |
532 HValue* object = instr->object()->ActualValue(); | 627 HValue* object = instr->object()->ActualValue(); |
533 HCheckTableEntry* entry = Find(object); | 628 HCheckTableEntry* entry = Find(object); |
534 // Can only learn more about an object that already has a known set of maps. | 629 // Can only learn more about an object that already has a known set of maps. |
535 if (entry == NULL) return; | 630 if (entry == NULL) return; |
536 EnsureChecked(entry, object, instr); | 631 EnsureChecked(entry, object, instr); |
537 if (entry->maps_->Contains(instr->original_map())) { | 632 if (entry->maps_->Contains(instr->original_map())) { |
538 // If the object has the original map, it will be transitioned. | 633 // If the object has the original map, it will be transitioned. |
539 UniqueSet<Map>* maps = entry->maps_->Copy(zone()); | 634 UniqueSet<Map>* maps = entry->maps_->Copy(zone()); |
540 maps->Remove(instr->original_map()); | 635 maps->Remove(instr->original_map()); |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
681 entry->object_ = object; | 776 entry->object_ = object; |
682 entry->check_ = check; | 777 entry->check_ = check; |
683 entry->maps_ = maps; | 778 entry->maps_ = maps; |
684 entry->state_ = state; | 779 entry->state_ = state; |
685 // If the table becomes full, wrap around and overwrite older entries. | 780 // If the table becomes full, wrap around and overwrite older entries. |
686 if (cursor_ == kMaxTrackedObjects) cursor_ = 0; | 781 if (cursor_ == kMaxTrackedObjects) cursor_ = 0; |
687 if (size_ < kMaxTrackedObjects) size_++; | 782 if (size_ < kMaxTrackedObjects) size_++; |
688 } | 783 } |
689 | 784 |
690 Zone* zone() const { return phase_->zone(); } | 785 Zone* zone() const { return phase_->zone(); } |
786 MapSet string_maps() const { return phase_->string_maps(); } | |
691 | 787 |
692 friend class HCheckMapsEffects; | 788 friend class HCheckMapsEffects; |
693 friend class HCheckEliminationPhase; | 789 friend class HCheckEliminationPhase; |
694 | 790 |
695 HCheckEliminationPhase* phase_; | 791 HCheckEliminationPhase* phase_; |
696 HCheckTableEntry entries_[kMaxTrackedObjects]; | 792 HCheckTableEntry entries_[kMaxTrackedObjects]; |
697 int16_t cursor_; // Must be <= kMaxTrackedObjects | 793 int16_t cursor_; // Must be <= kMaxTrackedObjects |
698 int16_t size_; // Must be <= kMaxTrackedObjects | 794 int16_t size_; // Must be <= kMaxTrackedObjects |
699 STATIC_ASSERT(kMaxTrackedObjects < (1 << 15)); | 795 STATIC_ASSERT(kMaxTrackedObjects < (1 << 15)); |
700 }; | 796 }; |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
787 // Are we eliminated yet? | 883 // Are we eliminated yet? |
788 void HCheckEliminationPhase::PrintStats() { | 884 void HCheckEliminationPhase::PrintStats() { |
789 #if DEBUG | 885 #if DEBUG |
790 #define PRINT_STAT(x) if (x##_ > 0) PrintF(" %-16s = %2d\n", #x, x##_) | 886 #define PRINT_STAT(x) if (x##_ > 0) PrintF(" %-16s = %2d\n", #x, x##_) |
791 #else | 887 #else |
792 #define PRINT_STAT(x) | 888 #define PRINT_STAT(x) |
793 #endif | 889 #endif |
794 PRINT_STAT(redundant); | 890 PRINT_STAT(redundant); |
795 PRINT_STAT(removed); | 891 PRINT_STAT(removed); |
796 PRINT_STAT(removed_cho); | 892 PRINT_STAT(removed_cho); |
893 PRINT_STAT(removed_cit); | |
797 PRINT_STAT(narrowed); | 894 PRINT_STAT(narrowed); |
798 PRINT_STAT(loads); | 895 PRINT_STAT(loads); |
799 PRINT_STAT(empty); | 896 PRINT_STAT(empty); |
800 PRINT_STAT(compares_true); | 897 PRINT_STAT(compares_true); |
801 PRINT_STAT(compares_false); | 898 PRINT_STAT(compares_false); |
802 PRINT_STAT(transitions); | 899 PRINT_STAT(transitions); |
803 } | 900 } |
804 | 901 |
805 } } // namespace v8::internal | 902 } } // namespace v8::internal |
OLD | NEW |