OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
11 // with the distribution. | 11 // with the distribution. |
(...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 Counters::number_of_symbols.Set(symbol_table()->NumberOfElements()); | 416 Counters::number_of_symbols.Set(symbol_table()->NumberOfElements()); |
417 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) | 417 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
418 ReportStatisticsAfterGC(); | 418 ReportStatisticsAfterGC(); |
419 #endif | 419 #endif |
420 #ifdef ENABLE_DEBUGGER_SUPPORT | 420 #ifdef ENABLE_DEBUGGER_SUPPORT |
421 Debug::AfterGarbageCollection(); | 421 Debug::AfterGarbageCollection(); |
422 #endif | 422 #endif |
423 } | 423 } |
424 | 424 |
425 | 425 |
426 void Heap::CollectAllGarbage(bool force_compaction) { | 426 void Heap::CollectAllGarbage(int flags) { |
427 // Since we are ignoring the return value, the exact choice of space does | 427 // Since we are ignoring the return value, the exact choice of space does |
428 // not matter, so long as we do not specify NEW_SPACE, which would not | 428 // not matter, so long as we do not specify NEW_SPACE, which would not |
429 // cause a full GC. | 429 // cause a full GC. |
430 MarkCompactCollector::SetForceCompaction(force_compaction); | 430 MarkCompactCollector::SetFlags(flags); |
431 CollectGarbage(OLD_POINTER_SPACE); | 431 CollectGarbage(OLD_POINTER_SPACE); |
432 MarkCompactCollector::SetForceCompaction(false); | 432 MarkCompactCollector::SetFlags(kNoGCFlags); |
433 } | 433 } |
434 | 434 |
435 | 435 |
436 void Heap::CollectAllAvailableGarbage() { | 436 void Heap::CollectAllAvailableGarbage() { |
437 // Since we are ignoring the return value, the exact choice of space does | 437 // Since we are ignoring the return value, the exact choice of space does |
438 // not matter, so long as we do not specify NEW_SPACE, which would not | 438 // not matter, so long as we do not specify NEW_SPACE, which would not |
439 // cause a full GC. | 439 // cause a full GC. |
440 MarkCompactCollector::SetForceCompaction(true); | 440 MarkCompactCollector::SetFlags(kMakeHeapIterableMask | kForceCompactionMask); |
441 | 441 |
442 // Major GC would invoke weak handle callbacks on weakly reachable | 442 // Major GC would invoke weak handle callbacks on weakly reachable |
443 // handles, but won't collect weakly reachable objects until next | 443 // handles, but won't collect weakly reachable objects until next |
444 // major GC. Therefore if we collect aggressively and weak handle callback | 444 // major GC. Therefore if we collect aggressively and weak handle callback |
445 // has been invoked, we rerun major GC to release objects which become | 445 // has been invoked, we rerun major GC to release objects which become |
446 // garbage. | 446 // garbage. |
447 // Note: as weak callbacks can execute arbitrary code, we cannot | 447 // Note: as weak callbacks can execute arbitrary code, we cannot |
448 // hope that eventually there will be no weak callbacks invocations. | 448 // hope that eventually there will be no weak callbacks invocations. |
449 // Therefore stop recollecting after several attempts. | 449 // Therefore stop recollecting after several attempts. |
450 const int kMaxNumberOfAttempts = 7; | 450 const int kMaxNumberOfAttempts = 7; |
451 for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) { | 451 for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) { |
452 if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR)) { | 452 if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR)) { |
453 break; | 453 break; |
454 } | 454 } |
455 } | 455 } |
456 MarkCompactCollector::SetForceCompaction(false); | 456 MarkCompactCollector::SetFlags(kNoGCFlags); |
457 } | 457 } |
458 | 458 |
459 | 459 |
460 bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) { | 460 bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) { |
461 // The VM is in the GC state until exiting this function. | 461 // The VM is in the GC state until exiting this function. |
462 VMState state(GC); | 462 VMState state(GC); |
463 | 463 |
464 #ifdef DEBUG | 464 #ifdef DEBUG |
465 // Reset the allocation timeout to the GC interval, but make sure to | 465 // Reset the allocation timeout to the GC interval, but make sure to |
466 // allow at least a few allocations after a collection. The reason | 466 // allow at least a few allocations after a collection. The reason |
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
905 } | 905 } |
906 } | 906 } |
907 }; | 907 }; |
908 | 908 |
909 | 909 |
910 static void VerifyNonPointerSpacePointers() { | 910 static void VerifyNonPointerSpacePointers() { |
911 // Verify that there are no pointers to new space in spaces where we | 911 // Verify that there are no pointers to new space in spaces where we |
912 // do not expect them. | 912 // do not expect them. |
913 VerifyNonPointerSpacePointersVisitor v; | 913 VerifyNonPointerSpacePointersVisitor v; |
914 HeapObjectIterator code_it(Heap::code_space()); | 914 HeapObjectIterator code_it(Heap::code_space()); |
915 for (HeapObject* object = code_it.next(); | 915 for (HeapObject* object = code_it.Next(); |
916 object != NULL; object = code_it.next()) | 916 object != NULL; object = code_it.Next()) |
917 object->Iterate(&v); | 917 object->Iterate(&v); |
918 | 918 |
919 HeapObjectIterator data_it(Heap::old_data_space()); | 919 // The old data space was normally swept conservatively so that the iterator |
920 for (HeapObject* object = data_it.next(); | 920 // doesn't work, so we normally skip the next bit. |
921 object != NULL; object = data_it.next()) | 921 if (!Heap::old_data_space()->was_swept_conservatively()) { |
922 object->Iterate(&v); | 922 HeapObjectIterator data_it(Heap::old_data_space()); |
| 923 for (HeapObject* object = data_it.Next(); |
| 924 object != NULL; object = data_it.Next()) |
| 925 object->Iterate(&v); |
| 926 } |
923 } | 927 } |
924 #endif | 928 #endif |
925 | 929 |
926 | 930 |
927 void Heap::CheckNewSpaceExpansionCriteria() { | 931 void Heap::CheckNewSpaceExpansionCriteria() { |
928 if (new_space_.Capacity() < new_space_.MaximumCapacity() && | 932 if (new_space_.Capacity() < new_space_.MaximumCapacity() && |
929 survived_since_last_expansion_ > new_space_.Capacity()) { | 933 survived_since_last_expansion_ > new_space_.Capacity()) { |
930 // Grow the size of new space if there is room to grow and enough | 934 // Grow the size of new space if there is room to grow and enough |
931 // data has survived scavenge since the last expansion. | 935 // data has survived scavenge since the last expansion. |
932 new_space_.Grow(); | 936 new_space_.Grow(); |
933 survived_since_last_expansion_ = 0; | 937 survived_since_last_expansion_ = 0; |
934 } | 938 } |
935 } | 939 } |
936 | 940 |
937 | 941 |
938 void Heap::Scavenge() { | 942 void Heap::Scavenge() { |
939 #ifdef DEBUG | 943 #ifdef DEBUG |
940 if (FLAG_enable_slow_asserts) VerifyNonPointerSpacePointers(); | 944 if (FLAG_enable_slow_asserts) VerifyNonPointerSpacePointers(); |
941 #endif | 945 #endif |
942 | 946 |
943 gc_state_ = SCAVENGE; | 947 gc_state_ = SCAVENGE; |
944 | 948 |
945 Page::FlipMeaningOfInvalidatedWatermarkFlag(); | |
946 | |
947 // We do not update an allocation watermark of the top page during linear | |
948 // allocation to avoid overhead. So to maintain the watermark invariant | |
949 // we have to manually cache the watermark and mark the top page as having an | |
950 // invalid watermark. This guarantees that old space pointer iteration will | |
951 // use a correct watermark even if a linear allocation happens. | |
952 old_pointer_space_->FlushTopPageWatermark(); | |
953 map_space_->FlushTopPageWatermark(); | |
954 | |
955 // Implements Cheney's copying algorithm | 949 // Implements Cheney's copying algorithm |
956 LOG(ResourceEvent("scavenge", "begin")); | 950 LOG(ResourceEvent("scavenge", "begin")); |
957 | 951 |
958 // Clear descriptor cache. | 952 // Clear descriptor cache. |
959 DescriptorLookupCache::Clear(); | 953 DescriptorLookupCache::Clear(); |
960 | 954 |
961 // Used for updating survived_since_last_expansion_ at function end. | 955 // Used for updating survived_since_last_expansion_ at function end. |
962 intptr_t survived_watermark = PromotedSpaceSize(); | 956 intptr_t survived_watermark = PromotedSpaceSize(); |
963 | 957 |
964 CheckNewSpaceExpansionCriteria(); | 958 CheckNewSpaceExpansionCriteria(); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
997 IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE); | 991 IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE); |
998 | 992 |
999 // Copy objects reachable from the old generation. | 993 // Copy objects reachable from the old generation. |
1000 { | 994 { |
1001 StoreBufferRebuildScope scope; | 995 StoreBufferRebuildScope scope; |
1002 StoreBuffer::IteratePointersToNewSpace(&ScavengeObject); | 996 StoreBuffer::IteratePointersToNewSpace(&ScavengeObject); |
1003 } | 997 } |
1004 | 998 |
1005 // Copy objects reachable from cells by scavenging cell values directly. | 999 // Copy objects reachable from cells by scavenging cell values directly. |
1006 HeapObjectIterator cell_iterator(cell_space_); | 1000 HeapObjectIterator cell_iterator(cell_space_); |
1007 for (HeapObject* cell = cell_iterator.next(); | 1001 for (HeapObject* cell = cell_iterator.Next(); |
1008 cell != NULL; cell = cell_iterator.next()) { | 1002 cell != NULL; cell = cell_iterator.Next()) { |
1009 if (cell->IsJSGlobalPropertyCell()) { | 1003 if (cell->IsJSGlobalPropertyCell()) { |
1010 Address value_address = | 1004 Address value_address = |
1011 reinterpret_cast<Address>(cell) + | 1005 reinterpret_cast<Address>(cell) + |
1012 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag); | 1006 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag); |
1013 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address)); | 1007 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address)); |
1014 } | 1008 } |
1015 } | 1009 } |
1016 | 1010 |
1017 // Scavenge object reachable from the global contexts list directly. | 1011 // Scavenge object reachable from the global contexts list directly. |
1018 scavenge_visitor.VisitPointer(BitCast<Object**>(&global_contexts_list_)); | 1012 scavenge_visitor.VisitPointer(BitCast<Object**>(&global_contexts_list_)); |
(...skipping 646 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1665 } | 1659 } |
1666 set_undetectable_ascii_string_map(Map::cast(obj)); | 1660 set_undetectable_ascii_string_map(Map::cast(obj)); |
1667 Map::cast(obj)->set_is_undetectable(); | 1661 Map::cast(obj)->set_is_undetectable(); |
1668 | 1662 |
1669 { MaybeObject* maybe_obj = | 1663 { MaybeObject* maybe_obj = |
1670 AllocateMap(BYTE_ARRAY_TYPE, kVariableSizeSentinel); | 1664 AllocateMap(BYTE_ARRAY_TYPE, kVariableSizeSentinel); |
1671 if (!maybe_obj->ToObject(&obj)) return false; | 1665 if (!maybe_obj->ToObject(&obj)) return false; |
1672 } | 1666 } |
1673 set_byte_array_map(Map::cast(obj)); | 1667 set_byte_array_map(Map::cast(obj)); |
1674 | 1668 |
| 1669 { MaybeObject* maybe_obj = |
| 1670 AllocateMap(FREE_SPACE_TYPE, kVariableSizeSentinel); |
| 1671 if (!maybe_obj->ToObject(&obj)) return false; |
| 1672 } |
| 1673 set_free_space_map(Map::cast(obj)); |
| 1674 |
1675 { MaybeObject* maybe_obj = AllocateByteArray(0, TENURED); | 1675 { MaybeObject* maybe_obj = AllocateByteArray(0, TENURED); |
1676 if (!maybe_obj->ToObject(&obj)) return false; | 1676 if (!maybe_obj->ToObject(&obj)) return false; |
1677 } | 1677 } |
1678 set_empty_byte_array(ByteArray::cast(obj)); | 1678 set_empty_byte_array(ByteArray::cast(obj)); |
1679 | 1679 |
1680 { MaybeObject* maybe_obj = | 1680 { MaybeObject* maybe_obj = |
1681 AllocateMap(EXTERNAL_PIXEL_ARRAY_TYPE, ExternalArray::kAlignedSize); | 1681 AllocateMap(EXTERNAL_PIXEL_ARRAY_TYPE, ExternalArray::kAlignedSize); |
1682 if (!maybe_obj->ToObject(&obj)) return false; | 1682 if (!maybe_obj->ToObject(&obj)) return false; |
1683 } | 1683 } |
1684 set_external_pixel_array_map(Map::cast(obj)); | 1684 set_external_pixel_array_map(Map::cast(obj)); |
(...skipping 937 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2622 | 2622 |
2623 | 2623 |
2624 void Heap::CreateFillerObjectAt(Address addr, int size) { | 2624 void Heap::CreateFillerObjectAt(Address addr, int size) { |
2625 if (size == 0) return; | 2625 if (size == 0) return; |
2626 HeapObject* filler = HeapObject::FromAddress(addr); | 2626 HeapObject* filler = HeapObject::FromAddress(addr); |
2627 if (size == kPointerSize) { | 2627 if (size == kPointerSize) { |
2628 filler->set_map(one_pointer_filler_map()); | 2628 filler->set_map(one_pointer_filler_map()); |
2629 } else if (size == 2 * kPointerSize) { | 2629 } else if (size == 2 * kPointerSize) { |
2630 filler->set_map(two_pointer_filler_map()); | 2630 filler->set_map(two_pointer_filler_map()); |
2631 } else { | 2631 } else { |
2632 filler->set_map(byte_array_map()); | 2632 filler->set_map(free_space_map()); |
2633 ByteArray::cast(filler)->set_length(ByteArray::LengthFor(size)); | 2633 FreeSpace::cast(filler)->set_size(size); |
2634 } | 2634 } |
2635 } | 2635 } |
2636 | 2636 |
2637 | 2637 |
2638 MaybeObject* Heap::AllocateExternalArray(int length, | 2638 MaybeObject* Heap::AllocateExternalArray(int length, |
2639 ExternalArrayType array_type, | 2639 ExternalArrayType array_type, |
2640 void* external_pointer, | 2640 void* external_pointer, |
2641 PretenureFlag pretenure) { | 2641 PretenureFlag pretenure) { |
2642 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; | 2642 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; |
2643 Object* result; | 2643 Object* result; |
(...skipping 1058 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3702 (size > MaxObjectSizeInPagedSpace()) ? LO_SPACE : OLD_POINTER_SPACE; | 3702 (size > MaxObjectSizeInPagedSpace()) ? LO_SPACE : OLD_POINTER_SPACE; |
3703 Object* result; | 3703 Object* result; |
3704 { MaybeObject* maybe_result = Heap::Allocate(map, space); | 3704 { MaybeObject* maybe_result = Heap::Allocate(map, space); |
3705 if (!maybe_result->ToObject(&result)) return maybe_result; | 3705 if (!maybe_result->ToObject(&result)) return maybe_result; |
3706 } | 3706 } |
3707 Struct::cast(result)->InitializeBody(size); | 3707 Struct::cast(result)->InitializeBody(size); |
3708 return result; | 3708 return result; |
3709 } | 3709 } |
3710 | 3710 |
3711 | 3711 |
| 3712 void Heap::EnsureHeapIsIterable() { |
| 3713 ASSERT(IsAllocationAllowed()); |
| 3714 if (IncrementalMarking::state() != IncrementalMarking::STOPPED || |
| 3715 old_pointer_space()->was_swept_conservatively() || |
| 3716 old_data_space()->was_swept_conservatively()) { |
| 3717 CollectAllGarbage(kMakeHeapIterableMask); |
| 3718 } |
| 3719 ASSERT(!old_pointer_space()->was_swept_conservatively()); |
| 3720 ASSERT(!old_data_space()->was_swept_conservatively()); |
| 3721 } |
| 3722 |
| 3723 |
3712 bool Heap::IdleNotification() { | 3724 bool Heap::IdleNotification() { |
3713 static const int kIdlesBeforeScavenge = 4; | 3725 static const int kIdlesBeforeScavenge = 4; |
3714 static const int kIdlesBeforeMarkSweep = 7; | 3726 static const int kIdlesBeforeMarkSweep = 7; |
3715 static const int kIdlesBeforeMarkCompact = 8; | 3727 static const int kIdlesBeforeMarkCompact = 8; |
3716 static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1; | 3728 static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1; |
3717 static const unsigned int kGCsBetweenCleanup = 4; | 3729 static const unsigned int kGCsBetweenCleanup = 4; |
3718 static int number_idle_notifications = 0; | 3730 static int number_idle_notifications = 0; |
3719 static unsigned int last_gc_count = gc_count_; | 3731 static unsigned int last_gc_count = gc_count_; |
3720 | 3732 |
3721 bool uncommit = true; | 3733 bool uncommit = true; |
3722 bool finished = false; | 3734 bool finished = false; |
3723 | 3735 |
3724 // Reset the number of idle notifications received when a number of | 3736 // Reset the number of idle notifications received when a number of |
3725 // GCs have taken place. This allows another round of cleanup based | 3737 // GCs have taken place. This allows another round of cleanup based |
3726 // on idle notifications if enough work has been carried out to | 3738 // on idle notifications if enough work has been carried out to |
3727 // provoke a number of garbage collections. | 3739 // provoke a number of garbage collections. |
3728 if (gc_count_ - last_gc_count < kGCsBetweenCleanup) { | 3740 if (gc_count_ - last_gc_count < kGCsBetweenCleanup) { |
3729 number_idle_notifications = | 3741 number_idle_notifications = |
3730 Min(number_idle_notifications + 1, kMaxIdleCount); | 3742 Min(number_idle_notifications + 1, kMaxIdleCount); |
3731 } else { | 3743 } else { |
3732 number_idle_notifications = 0; | 3744 number_idle_notifications = 0; |
3733 last_gc_count = gc_count_; | 3745 last_gc_count = gc_count_; |
3734 } | 3746 } |
3735 | 3747 |
3736 if (number_idle_notifications == kIdlesBeforeScavenge) { | 3748 if (number_idle_notifications == kIdlesBeforeScavenge) { |
3737 if (contexts_disposed_ > 0) { | 3749 if (contexts_disposed_ > 0) { |
3738 HistogramTimerScope scope(&Counters::gc_context); | 3750 HistogramTimerScope scope(&Counters::gc_context); |
3739 CollectAllGarbage(false); | 3751 CollectAllGarbage(kNoGCFlags); |
3740 } else { | 3752 } else { |
3741 CollectGarbage(NEW_SPACE); | 3753 CollectGarbage(NEW_SPACE); |
3742 } | 3754 } |
3743 new_space_.Shrink(); | 3755 new_space_.Shrink(); |
3744 last_gc_count = gc_count_; | 3756 last_gc_count = gc_count_; |
3745 } else if (number_idle_notifications == kIdlesBeforeMarkSweep) { | 3757 } else if (number_idle_notifications == kIdlesBeforeMarkSweep) { |
3746 // Before doing the mark-sweep collections we clear the | 3758 // Before doing the mark-sweep collections we clear the |
3747 // compilation cache to avoid hanging on to source code and | 3759 // compilation cache to avoid hanging on to source code and |
3748 // generated code for cached functions. | 3760 // generated code for cached functions. |
3749 CompilationCache::Clear(); | 3761 CompilationCache::Clear(); |
3750 | 3762 |
3751 CollectAllGarbage(false); | 3763 CollectAllGarbage(kNoGCFlags); |
3752 new_space_.Shrink(); | 3764 new_space_.Shrink(); |
3753 last_gc_count = gc_count_; | 3765 last_gc_count = gc_count_; |
3754 | 3766 |
3755 } else if (number_idle_notifications == kIdlesBeforeMarkCompact) { | 3767 } else if (number_idle_notifications == kIdlesBeforeMarkCompact) { |
3756 CollectAllGarbage(true); | 3768 CollectAllGarbage(kForceCompactionMask); |
3757 new_space_.Shrink(); | 3769 new_space_.Shrink(); |
3758 last_gc_count = gc_count_; | 3770 last_gc_count = gc_count_; |
3759 finished = true; | 3771 finished = true; |
3760 | 3772 |
3761 } else if (contexts_disposed_ > 0) { | 3773 } else if (contexts_disposed_ > 0) { |
3762 if (FLAG_expose_gc) { | 3774 if (FLAG_expose_gc) { |
3763 contexts_disposed_ = 0; | 3775 contexts_disposed_ = 0; |
3764 } else { | 3776 } else { |
3765 HistogramTimerScope scope(&Counters::gc_context); | 3777 HistogramTimerScope scope(&Counters::gc_context); |
3766 CollectAllGarbage(false); | 3778 CollectAllGarbage(kNoGCFlags); |
3767 last_gc_count = gc_count_; | 3779 last_gc_count = gc_count_; |
3768 } | 3780 } |
3769 // If this is the first idle notification, we reset the | 3781 // If this is the first idle notification, we reset the |
3770 // notification count to avoid letting idle notifications for | 3782 // notification count to avoid letting idle notifications for |
3771 // context disposal garbage collections start a potentially too | 3783 // context disposal garbage collections start a potentially too |
3772 // aggressive idle GC cycle. | 3784 // aggressive idle GC cycle. |
3773 if (number_idle_notifications <= 1) { | 3785 if (number_idle_notifications <= 1) { |
3774 number_idle_notifications = 0; | 3786 number_idle_notifications = 0; |
3775 uncommit = false; | 3787 uncommit = false; |
3776 } | 3788 } |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3900 | 3912 |
3901 #ifdef DEBUG | 3913 #ifdef DEBUG |
3902 static void DummyScavengePointer(HeapObject** p, HeapObject* o) { | 3914 static void DummyScavengePointer(HeapObject** p, HeapObject* o) { |
3903 // When we are not in GC the Heap::InNewSpace() predicate | 3915 // When we are not in GC the Heap::InNewSpace() predicate |
3904 // checks that pointers which satisfy predicate point into | 3916 // checks that pointers which satisfy predicate point into |
3905 // the active semispace. | 3917 // the active semispace. |
3906 Heap::InNewSpace(*p); | 3918 Heap::InNewSpace(*p); |
3907 } | 3919 } |
3908 | 3920 |
3909 | 3921 |
3910 static void VerifyPointersUnderWatermark( | 3922 static void VerifyPointers( |
3911 PagedSpace* space, | 3923 PagedSpace* space, |
3912 PointerRegionCallback visit_pointer_region) { | 3924 PointerRegionCallback visit_pointer_region) { |
3913 PageIterator it(space, PageIterator::PAGES_IN_USE); | 3925 PageIterator it(space); |
3914 | 3926 |
3915 while (it.has_next()) { | 3927 while (it.has_next()) { |
3916 Page* page = it.next(); | 3928 Page* page = it.next(); |
3917 Address start = page->ObjectAreaStart(); | 3929 Address start = page->ObjectAreaStart(); |
3918 Address end = page->AllocationWatermark(); | 3930 Address end = page->ObjectAreaEnd(); |
3919 | 3931 |
3920 Heap::IteratePointersToNewSpace(start, | 3932 Heap::IteratePointersToNewSpace(start, |
3921 end, | 3933 end, |
3922 &DummyScavengePointer); | 3934 &DummyScavengePointer); |
3923 } | 3935 } |
3924 } | 3936 } |
3925 | 3937 |
3926 | 3938 |
3927 static void VerifyPointersUnderWatermark(LargeObjectSpace* space) { | 3939 static void VerifyPointers(LargeObjectSpace* space) { |
3928 LargeObjectIterator it(space); | 3940 LargeObjectIterator it(space); |
3929 for (HeapObject* object = it.next(); object != NULL; object = it.next()) { | 3941 for (HeapObject* object = it.next(); object != NULL; object = it.next()) { |
3930 if (object->IsFixedArray()) { | 3942 if (object->IsFixedArray()) { |
3931 Address slot_address = object->address(); | 3943 Address slot_address = object->address(); |
3932 Address end = object->address() + object->Size(); | 3944 Address end = object->address() + object->Size(); |
3933 | 3945 |
3934 while (slot_address < end) { | 3946 while (slot_address < end) { |
3935 HeapObject** slot = reinterpret_cast<HeapObject**>(slot_address); | 3947 HeapObject** slot = reinterpret_cast<HeapObject**>(slot_address); |
3936 // When we are not in GC the Heap::InNewSpace() predicate | 3948 // When we are not in GC the Heap::InNewSpace() predicate |
3937 // checks that pointers which satisfy predicate point into | 3949 // checks that pointers which satisfy predicate point into |
(...skipping 12 matching lines...) Expand all Loading... |
3950 StoreBuffer::Verify(); | 3962 StoreBuffer::Verify(); |
3951 | 3963 |
3952 VerifyPointersVisitor visitor; | 3964 VerifyPointersVisitor visitor; |
3953 IterateRoots(&visitor, VISIT_ONLY_STRONG); | 3965 IterateRoots(&visitor, VISIT_ONLY_STRONG); |
3954 | 3966 |
3955 new_space_.Verify(); | 3967 new_space_.Verify(); |
3956 | 3968 |
3957 old_pointer_space_->Verify(&visitor); | 3969 old_pointer_space_->Verify(&visitor); |
3958 map_space_->Verify(&visitor); | 3970 map_space_->Verify(&visitor); |
3959 | 3971 |
3960 VerifyPointersUnderWatermark(old_pointer_space_, | 3972 VerifyPointers(old_pointer_space_, &IteratePointersToNewSpace); |
3961 &IteratePointersToNewSpace); | 3973 VerifyPointers(map_space_, &IteratePointersFromMapsToNewSpace); |
3962 VerifyPointersUnderWatermark(map_space_, | 3974 VerifyPointers(lo_space_); |
3963 &IteratePointersFromMapsToNewSpace); | |
3964 VerifyPointersUnderWatermark(lo_space_); | |
3965 | 3975 |
3966 VerifyPointersVisitor no_dirty_regions_visitor; | 3976 VerifyPointersVisitor no_dirty_regions_visitor; |
3967 old_data_space_->Verify(&no_dirty_regions_visitor); | 3977 old_data_space_->Verify(&no_dirty_regions_visitor); |
3968 code_space_->Verify(&no_dirty_regions_visitor); | 3978 code_space_->Verify(&no_dirty_regions_visitor); |
3969 cell_space_->Verify(&no_dirty_regions_visitor); | 3979 cell_space_->Verify(&no_dirty_regions_visitor); |
3970 | 3980 |
3971 lo_space_->Verify(); | 3981 lo_space_->Verify(); |
3972 } | 3982 } |
3973 #endif // DEBUG | 3983 #endif // DEBUG |
3974 | 3984 |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4150 ASSERT(StoreBuffer::CellIsInStoreBuffer( | 4160 ASSERT(StoreBuffer::CellIsInStoreBuffer( |
4151 reinterpret_cast<Address>(slot))); | 4161 reinterpret_cast<Address>(slot))); |
4152 } | 4162 } |
4153 } | 4163 } |
4154 slot_address += kPointerSize; | 4164 slot_address += kPointerSize; |
4155 } | 4165 } |
4156 } | 4166 } |
4157 | 4167 |
4158 | 4168 |
4159 #ifdef DEBUG | 4169 #ifdef DEBUG |
| 4170 typedef bool (*CheckStoreBufferFilter)(Object** addr); |
| 4171 |
| 4172 |
| 4173 bool IsAMapPointerAddress(Object** addr) { |
| 4174 uintptr_t a = reinterpret_cast<uintptr_t>(addr); |
| 4175 int mod = a % Map::kSize; |
| 4176 return mod >= Map::kPointerFieldsBeginOffset && |
| 4177 mod < Map::kPointerFieldsEndOffset; |
| 4178 } |
| 4179 |
| 4180 |
| 4181 bool EverythingsAPointer(Object** addr) { |
| 4182 return true; |
| 4183 } |
| 4184 |
| 4185 |
4160 static void CheckStoreBuffer(Object** current, | 4186 static void CheckStoreBuffer(Object** current, |
4161 Object** limit, | 4187 Object** limit, |
4162 Object**** store_buffer_position, | 4188 Object**** store_buffer_position, |
4163 Object*** store_buffer_top) { | 4189 Object*** store_buffer_top, |
| 4190 CheckStoreBufferFilter filter, |
| 4191 Address special_garbage_start, |
| 4192 Address special_garbage_end) { |
4164 for ( ; current < limit; current++) { | 4193 for ( ; current < limit; current++) { |
4165 Object* o = *current; | 4194 Object* o = *current; |
4166 if (reinterpret_cast<uintptr_t>(o) == kFreeListZapValue) { | 4195 Address current_address = reinterpret_cast<Address>(current); |
4167 Object*** zap_checker = *store_buffer_position; | 4196 // Skip free space. |
4168 while (*zap_checker < current) { | 4197 if (o == Heap::free_space_map()) { |
4169 zap_checker++; | 4198 Address current_address = reinterpret_cast<Address>(current); |
4170 if (zap_checker >= store_buffer_top) break; | 4199 FreeSpace* free_space = |
4171 } | 4200 FreeSpace::cast(HeapObject::FromAddress(current_address)); |
4172 if (zap_checker < store_buffer_top) { | 4201 int skip = free_space->Size(); |
4173 // Objects in the free list shouldn't be in the store buffer. | 4202 ASSERT(current_address + skip <= reinterpret_cast<Address>(limit)); |
4174 ASSERT(*zap_checker != current); | 4203 ASSERT(skip > 0); |
4175 } | 4204 current_address += skip - kPointerSize; |
| 4205 current = reinterpret_cast<Object**>(current_address); |
4176 continue; | 4206 continue; |
4177 } | 4207 } |
| 4208 // Skip the current linear allocation space between top and limit which is |
| 4209 // unmarked with the free space map, but can contain junk. |
| 4210 if (current_address == special_garbage_start && |
| 4211 special_garbage_end != special_garbage_start) { |
| 4212 current_address = special_garbage_end - kPointerSize; |
| 4213 current = reinterpret_cast<Object**>(current_address); |
| 4214 continue; |
| 4215 } |
| 4216 if (!(*filter)(current)) continue; |
| 4217 ASSERT(current_address < special_garbage_start || |
| 4218 current_address >= special_garbage_end); |
| 4219 ASSERT(reinterpret_cast<uintptr_t>(o) != kFreeListZapValue); |
4178 // We have to check that the pointer does not point into new space | 4220 // We have to check that the pointer does not point into new space |
4179 // without trying to cast it to a heap object since the hash field of | 4221 // without trying to cast it to a heap object since the hash field of |
4180 // a string can contain values like 1 and 3 which are tagged null | 4222 // a string can contain values like 1 and 3 which are tagged null |
4181 // pointers. | 4223 // pointers. |
4182 if (!Heap::InNewSpace(o)) continue; | 4224 if (!Heap::InNewSpace(o)) continue; |
4183 while (**store_buffer_position < current && | 4225 while (**store_buffer_position < current && |
4184 *store_buffer_position < store_buffer_top) { | 4226 *store_buffer_position < store_buffer_top) { |
4185 (*store_buffer_position)++; | 4227 (*store_buffer_position)++; |
4186 } | 4228 } |
4187 if (**store_buffer_position != current || | 4229 if (**store_buffer_position != current || |
4188 *store_buffer_position == store_buffer_top) { | 4230 *store_buffer_position == store_buffer_top) { |
4189 Object** obj_start = current; | 4231 Object** obj_start = current; |
4190 while (!(*obj_start)->IsMap()) obj_start--; | 4232 while (!(*obj_start)->IsMap()) obj_start--; |
4191 UNREACHABLE(); | 4233 UNREACHABLE(); |
4192 } | 4234 } |
4193 } | 4235 } |
4194 } | 4236 } |
4195 | 4237 |
4196 | 4238 |
4197 // Check that the store buffer contains all intergenerational pointers by | 4239 // Check that the store buffer contains all intergenerational pointers by |
4198 // scanning a page and ensuring that all pointers to young space are in the | 4240 // scanning a page and ensuring that all pointers to young space are in the |
4199 // store buffer. | 4241 // store buffer. |
4200 void Heap::OldPointerSpaceCheckStoreBuffer( | 4242 void Heap::OldPointerSpaceCheckStoreBuffer( |
4201 ExpectedPageWatermarkState watermark_state) { | 4243 ExpectedPageWatermarkState watermark_state) { |
4202 OldSpace* space = old_pointer_space(); | 4244 OldSpace* space = old_pointer_space(); |
4203 PageIterator pages(space, PageIterator::PAGES_IN_USE); | 4245 PageIterator pages(space); |
4204 | |
4205 space->free_list()->Zap(); | |
4206 | 4246 |
4207 StoreBuffer::SortUniq(); | 4247 StoreBuffer::SortUniq(); |
4208 | 4248 |
4209 while (pages.has_next()) { | 4249 while (pages.has_next()) { |
4210 Page* page = pages.next(); | 4250 Page* page = pages.next(); |
4211 Object** current = reinterpret_cast<Object**>(page->ObjectAreaStart()); | 4251 Object** current = reinterpret_cast<Object**>(page->ObjectAreaStart()); |
4212 | 4252 |
4213 // Do not try to visit pointers beyond page allocation watermark. | 4253 Address end = page->ObjectAreaEnd(); |
4214 // Page can contain garbage pointers there. | |
4215 Address end; | |
4216 | |
4217 if (watermark_state == WATERMARK_SHOULD_BE_VALID || | |
4218 page->IsWatermarkValid()) { | |
4219 end = page->AllocationWatermark(); | |
4220 } else { | |
4221 end = page->CachedAllocationWatermark(); | |
4222 } | |
4223 | 4254 |
4224 Object*** store_buffer_position = StoreBuffer::Start(); | 4255 Object*** store_buffer_position = StoreBuffer::Start(); |
4225 Object*** store_buffer_top = StoreBuffer::Top(); | 4256 Object*** store_buffer_top = StoreBuffer::Top(); |
4226 | 4257 |
4227 Object** limit = reinterpret_cast<Object**>(end); | 4258 Object** limit = reinterpret_cast<Object**>(end); |
4228 CheckStoreBuffer(current, limit, &store_buffer_position, store_buffer_top); | 4259 CheckStoreBuffer(current, |
| 4260 limit, |
| 4261 &store_buffer_position, |
| 4262 store_buffer_top, |
| 4263 &EverythingsAPointer, |
| 4264 space->top(), |
| 4265 space->limit()); |
4229 } | 4266 } |
4230 } | 4267 } |
4231 | 4268 |
4232 | 4269 |
4233 void Heap::MapSpaceCheckStoreBuffer( | 4270 void Heap::MapSpaceCheckStoreBuffer( |
4234 ExpectedPageWatermarkState watermark_state) { | 4271 ExpectedPageWatermarkState watermark_state) { |
4235 MapSpace* space = map_space(); | 4272 MapSpace* space = map_space(); |
4236 PageIterator pages(space, PageIterator::PAGES_IN_USE); | 4273 PageIterator pages(space); |
4237 | |
4238 space->free_list()->Zap(); | |
4239 | 4274 |
4240 StoreBuffer::SortUniq(); | 4275 StoreBuffer::SortUniq(); |
4241 | 4276 |
4242 while (pages.has_next()) { | 4277 while (pages.has_next()) { |
4243 Page* page = pages.next(); | 4278 Page* page = pages.next(); |
| 4279 Object** current = reinterpret_cast<Object**>(page->ObjectAreaStart()); |
4244 | 4280 |
4245 // Do not try to visit pointers beyond page allocation watermark. | 4281 Address end = page->ObjectAreaEnd(); |
4246 // Page can contain garbage pointers there. | |
4247 Address end; | |
4248 | |
4249 if (watermark_state == WATERMARK_SHOULD_BE_VALID || | |
4250 page->IsWatermarkValid()) { | |
4251 end = page->AllocationWatermark(); | |
4252 } else { | |
4253 end = page->CachedAllocationWatermark(); | |
4254 } | |
4255 | |
4256 Address map_aligned_current = page->ObjectAreaStart(); | |
4257 | |
4258 ASSERT(map_aligned_current == MapStartAlign(map_aligned_current)); | |
4259 ASSERT(end == MapEndAlign(end)); | |
4260 | 4282 |
4261 Object*** store_buffer_position = StoreBuffer::Start(); | 4283 Object*** store_buffer_position = StoreBuffer::Start(); |
4262 Object*** store_buffer_top = StoreBuffer::Top(); | 4284 Object*** store_buffer_top = StoreBuffer::Top(); |
4263 | 4285 |
4264 for ( ; map_aligned_current < end; map_aligned_current += Map::kSize) { | 4286 Object** limit = reinterpret_cast<Object**>(end); |
4265 ASSERT(!Heap::InNewSpace(Memory::Object_at(map_aligned_current))); | 4287 CheckStoreBuffer(current, |
4266 ASSERT(Memory::Object_at(map_aligned_current)->IsMap()); | 4288 limit, |
4267 | 4289 &store_buffer_position, |
4268 Object** current = reinterpret_cast<Object**>( | 4290 store_buffer_top, |
4269 map_aligned_current + Map::kPointerFieldsBeginOffset); | 4291 &IsAMapPointerAddress, |
4270 Object** limit = reinterpret_cast<Object**>( | 4292 space->top(), |
4271 map_aligned_current + Map::kPointerFieldsEndOffset); | 4293 space->limit()); |
4272 | |
4273 CheckStoreBuffer(current, | |
4274 limit, | |
4275 &store_buffer_position, | |
4276 store_buffer_top); | |
4277 } | |
4278 } | 4294 } |
4279 } | 4295 } |
4280 | 4296 |
4281 | 4297 |
4282 void Heap::LargeObjectSpaceCheckStoreBuffer() { | 4298 void Heap::LargeObjectSpaceCheckStoreBuffer() { |
4283 LargeObjectIterator it(lo_space()); | 4299 LargeObjectIterator it(lo_space()); |
4284 for (HeapObject* object = it.next(); object != NULL; object = it.next()) { | 4300 for (HeapObject* object = it.next(); object != NULL; object = it.next()) { |
4285 // We only have code, sequential strings, or fixed arrays in large | 4301 // We only have code, sequential strings, or fixed arrays in large |
4286 // object space, and only fixed arrays can possibly contain pointers to | 4302 // object space, and only fixed arrays can possibly contain pointers to |
4287 // the young generation. | 4303 // the young generation. |
4288 if (object->IsFixedArray()) { | 4304 if (object->IsFixedArray()) { |
4289 Object*** store_buffer_position = StoreBuffer::Start(); | 4305 Object*** store_buffer_position = StoreBuffer::Start(); |
4290 Object*** store_buffer_top = StoreBuffer::Top(); | 4306 Object*** store_buffer_top = StoreBuffer::Top(); |
4291 Object** current = reinterpret_cast<Object**>(object->address()); | 4307 Object** current = reinterpret_cast<Object**>(object->address()); |
4292 Object** limit = | 4308 Object** limit = |
4293 reinterpret_cast<Object**>(object->address() + object->Size()); | 4309 reinterpret_cast<Object**>(object->address() + object->Size()); |
4294 CheckStoreBuffer(current, | 4310 CheckStoreBuffer(current, |
4295 limit, | 4311 limit, |
4296 &store_buffer_position, | 4312 &store_buffer_position, |
4297 store_buffer_top); | 4313 store_buffer_top, |
| 4314 &EverythingsAPointer, |
| 4315 NULL, |
| 4316 NULL); |
4298 } | 4317 } |
4299 } | 4318 } |
4300 } | 4319 } |
4301 | 4320 |
4302 | 4321 |
4303 #endif | 4322 #endif |
4304 | 4323 |
4305 | 4324 |
| 4325 // This function iterates over all the pointers in a paged space in the heap, |
| 4326 // looking for pointers into new space. Within the pages there may be dead |
| 4327 // objects that have not been overwritten by free spaces or fillers because of |
| 4328 // lazy sweeping. These dead objects may not contain pointers to new space. |
| 4329 // The garbage areas that have been swept properly (these will normally be the |
| 4330 // large ones) will be marked with free space and filler map words. In |
| 4331 // addition any area that has never been used at all for object allocation must |
| 4332 // be marked with a free space or filler. Because the free space and filler |
| 4333 // maps do not move we can always recognize these even after a compaction. |
| 4334 // Normal objects like FixedArrays and JSObjects should not contain references |
| 4335 // to these maps. The special garbage section (see comment in spaces.h) is |
| 4336 // skipped since it can contain absolutely anything. Any objects that are |
| 4337 // allocated during iteration may or may not be visited by the iteration, but |
| 4338 // they will not be partially visited. |
4306 void Heap::IteratePointers( | 4339 void Heap::IteratePointers( |
4307 PagedSpace* space, | 4340 PagedSpace* space, |
4308 PointerRegionCallback visit_pointer_region, | 4341 PointerRegionCallback visit_pointer_region, |
4309 ObjectSlotCallback copy_object_func, | 4342 ObjectSlotCallback copy_object_func, |
4310 ExpectedPageWatermarkState expected_page_watermark_state) { | 4343 ExpectedPageWatermarkState expected_page_watermark_state) { |
4311 | 4344 |
4312 PageIterator pages(space, PageIterator::PAGES_IN_USE); | 4345 PageIterator pages(space); |
4313 | 4346 |
4314 while (pages.has_next()) { | 4347 while (pages.has_next()) { |
4315 Page* page = pages.next(); | 4348 Page* page = pages.next(); |
4316 Address start = page->ObjectAreaStart(); | 4349 Address start = page->ObjectAreaStart(); |
| 4350 Address limit = page->ObjectAreaEnd(); |
4317 | 4351 |
4318 // Do not try to visit pointers beyond page allocation watermark. | 4352 Address end = start; |
4319 // Page can contain garbage pointers there. | |
4320 Address end; | |
4321 | 4353 |
4322 if ((expected_page_watermark_state == WATERMARK_SHOULD_BE_VALID) || | 4354 Object* free_space_map = Heap::free_space_map(); |
4323 page->IsWatermarkValid()) { | 4355 Object* two_pointer_filler_map = Heap::two_pointer_filler_map(); |
4324 end = page->AllocationWatermark(); | 4356 |
4325 } else { | 4357 while (end < limit) { |
4326 end = page->CachedAllocationWatermark(); | 4358 Object* o = *reinterpret_cast<Object**>(end); |
| 4359 // Skip fillers but not things that look like fillers in the special |
| 4360 // garbage section which can contain anything. |
| 4361 if (o == free_space_map || |
| 4362 o == two_pointer_filler_map || |
| 4363 end == space->top()) { |
| 4364 if (start != end) { |
| 4365 // After calling this the special garbage section may have moved. |
| 4366 visit_pointer_region(start, end, copy_object_func); |
| 4367 if (end >= space->top() && end < space->limit()) { |
| 4368 end = space->limit(); |
| 4369 start = end; |
| 4370 continue; |
| 4371 } |
| 4372 } |
| 4373 if (end == space->top()) { |
| 4374 start = end = space->limit(); |
| 4375 } else { |
| 4376 // At this point we are either at the start of a filler or we are at |
| 4377 // the point where the space->top() used to be before the |
| 4378 // visit_pointer_region call above. Either way we can skip the |
| 4379 // object at the current spot: We don't promise to visit objects |
| 4380 // allocated during heap traversal, and if space->top() moved then it |
| 4381 // must be because an object was allocated at this point. |
| 4382 start = end + HeapObject::FromAddress(end)->Size(); |
| 4383 end = start; |
| 4384 } |
| 4385 } else { |
| 4386 ASSERT(o != free_space_map); |
| 4387 ASSERT(o != two_pointer_filler_map); |
| 4388 ASSERT(end < space->top() || end >= space->limit()); |
| 4389 end += kPointerSize; |
| 4390 } |
4327 } | 4391 } |
4328 | 4392 ASSERT(end == limit); |
4329 ASSERT(space == old_pointer_space_ || | 4393 if (start != end) { |
4330 (space == map_space_ && | 4394 visit_pointer_region(start, end, copy_object_func); |
4331 ((page->ObjectAreaStart() - end) % Map::kSize == 0))); | 4395 } |
4332 | |
4333 visit_pointer_region(start, end, copy_object_func); | |
4334 | |
4335 // Mark page watermark as invalid to maintain watermark validity invariant. | |
4336 // See Page::FlipMeaningOfInvalidatedWatermarkFlag() for details. | |
4337 page->InvalidateWatermark(true); | |
4338 } | 4396 } |
4339 } | 4397 } |
4340 | 4398 |
4341 | 4399 |
4342 void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) { | 4400 void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) { |
4343 IterateStrongRoots(v, mode); | 4401 IterateStrongRoots(v, mode); |
4344 IterateWeakRoots(v, mode); | 4402 IterateWeakRoots(v, mode); |
4345 } | 4403 } |
4346 | 4404 |
4347 | 4405 |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4494 *stats->map_space_capacity = map_space_->Capacity(); | 4552 *stats->map_space_capacity = map_space_->Capacity(); |
4495 *stats->cell_space_size = cell_space_->Size(); | 4553 *stats->cell_space_size = cell_space_->Size(); |
4496 *stats->cell_space_capacity = cell_space_->Capacity(); | 4554 *stats->cell_space_capacity = cell_space_->Capacity(); |
4497 *stats->lo_space_size = lo_space_->Size(); | 4555 *stats->lo_space_size = lo_space_->Size(); |
4498 GlobalHandles::RecordStats(stats); | 4556 GlobalHandles::RecordStats(stats); |
4499 *stats->memory_allocator_size = MemoryAllocator::Size(); | 4557 *stats->memory_allocator_size = MemoryAllocator::Size(); |
4500 *stats->memory_allocator_capacity = | 4558 *stats->memory_allocator_capacity = |
4501 MemoryAllocator::Size() + MemoryAllocator::Available(); | 4559 MemoryAllocator::Size() + MemoryAllocator::Available(); |
4502 *stats->os_error = OS::GetLastError(); | 4560 *stats->os_error = OS::GetLastError(); |
4503 if (take_snapshot) { | 4561 if (take_snapshot) { |
4504 HeapIterator iterator(HeapIterator::kFilterFreeListNodes); | 4562 HeapIterator iterator; |
4505 for (HeapObject* obj = iterator.next(); | 4563 for (HeapObject* obj = iterator.Next(); |
4506 obj != NULL; | 4564 obj != NULL; |
4507 obj = iterator.next()) { | 4565 obj = iterator.Next()) { |
4508 InstanceType type = obj->map()->instance_type(); | 4566 InstanceType type = obj->map()->instance_type(); |
4509 ASSERT(0 <= type && type <= LAST_TYPE); | 4567 ASSERT(0 <= type && type <= LAST_TYPE); |
4510 stats->objects_per_type[type]++; | 4568 stats->objects_per_type[type]++; |
4511 stats->size_per_type[type] += obj->Size(); | 4569 stats->size_per_type[type] += obj->Size(); |
4512 } | 4570 } |
4513 } | 4571 } |
4514 } | 4572 } |
4515 | 4573 |
4516 | 4574 |
4517 intptr_t Heap::PromotedSpaceSize() { | 4575 intptr_t Heap::PromotedSpaceSize() { |
(...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4928 } | 4986 } |
4929 | 4987 |
4930 | 4988 |
4931 class HeapObjectsFilter { | 4989 class HeapObjectsFilter { |
4932 public: | 4990 public: |
4933 virtual ~HeapObjectsFilter() {} | 4991 virtual ~HeapObjectsFilter() {} |
4934 virtual bool SkipObject(HeapObject* object) = 0; | 4992 virtual bool SkipObject(HeapObject* object) = 0; |
4935 }; | 4993 }; |
4936 | 4994 |
4937 | 4995 |
4938 class FreeListNodesFilter : public HeapObjectsFilter { | |
4939 public: | |
4940 FreeListNodesFilter() { | |
4941 MarkFreeListNodes(); | |
4942 } | |
4943 | |
4944 bool SkipObject(HeapObject* object) { | |
4945 if (IntrusiveMarking::IsMarked(object)) { | |
4946 IntrusiveMarking::ClearMark(object); | |
4947 return true; | |
4948 } else { | |
4949 return false; | |
4950 } | |
4951 } | |
4952 | |
4953 private: | |
4954 void MarkFreeListNodes() { | |
4955 Heap::old_pointer_space()->MarkFreeListNodes(); | |
4956 Heap::old_data_space()->MarkFreeListNodes(); | |
4957 MarkCodeSpaceFreeListNodes(); | |
4958 Heap::map_space()->MarkFreeListNodes(); | |
4959 Heap::cell_space()->MarkFreeListNodes(); | |
4960 } | |
4961 | |
4962 void MarkCodeSpaceFreeListNodes() { | |
4963 // For code space, using FreeListNode::IsFreeListNode is OK. | |
4964 HeapObjectIterator iter(Heap::code_space()); | |
4965 for (HeapObject* obj = iter.next_object(); | |
4966 obj != NULL; | |
4967 obj = iter.next_object()) { | |
4968 if (FreeListNode::IsFreeListNode(obj)) { | |
4969 IntrusiveMarking::SetMark(obj); | |
4970 } | |
4971 } | |
4972 } | |
4973 | |
4974 AssertNoAllocation no_alloc; | |
4975 }; | |
4976 | |
4977 | |
4978 class UnreachableObjectsFilter : public HeapObjectsFilter { | 4996 class UnreachableObjectsFilter : public HeapObjectsFilter { |
4979 public: | 4997 public: |
4980 UnreachableObjectsFilter() { | 4998 UnreachableObjectsFilter() { |
4981 MarkUnreachableObjects(); | 4999 MarkUnreachableObjects(); |
4982 } | 5000 } |
4983 | 5001 |
4984 bool SkipObject(HeapObject* object) { | 5002 bool SkipObject(HeapObject* object) { |
4985 if (IntrusiveMarking::IsMarked(object)) { | 5003 if (IntrusiveMarking::IsMarked(object)) { |
4986 IntrusiveMarking::ClearMark(object); | 5004 IntrusiveMarking::ClearMark(object); |
4987 return true; | 5005 return true; |
(...skipping 24 matching lines...) Expand all Loading... |
5012 HeapObject* obj = list_.RemoveLast(); | 5030 HeapObject* obj = list_.RemoveLast(); |
5013 obj->Iterate(this); | 5031 obj->Iterate(this); |
5014 } | 5032 } |
5015 | 5033 |
5016 private: | 5034 private: |
5017 List<HeapObject*> list_; | 5035 List<HeapObject*> list_; |
5018 }; | 5036 }; |
5019 | 5037 |
5020 void MarkUnreachableObjects() { | 5038 void MarkUnreachableObjects() { |
5021 HeapIterator iterator; | 5039 HeapIterator iterator; |
5022 for (HeapObject* obj = iterator.next(); | 5040 for (HeapObject* obj = iterator.Next(); |
5023 obj != NULL; | 5041 obj != NULL; |
5024 obj = iterator.next()) { | 5042 obj = iterator.Next()) { |
5025 IntrusiveMarking::SetMark(obj); | 5043 IntrusiveMarking::SetMark(obj); |
5026 } | 5044 } |
5027 UnmarkingVisitor visitor; | 5045 UnmarkingVisitor visitor; |
5028 Heap::IterateRoots(&visitor, VISIT_ALL); | 5046 Heap::IterateRoots(&visitor, VISIT_ALL); |
5029 while (visitor.can_process()) | 5047 while (visitor.can_process()) |
5030 visitor.ProcessNext(); | 5048 visitor.ProcessNext(); |
5031 } | 5049 } |
5032 | 5050 |
5033 AssertNoAllocation no_alloc; | 5051 AssertNoAllocation no_alloc; |
5034 }; | 5052 }; |
5035 | 5053 |
5036 | 5054 |
5037 HeapIterator::HeapIterator() | 5055 HeapIterator::HeapIterator() { |
5038 : filtering_(HeapIterator::kNoFiltering), | |
5039 filter_(NULL) { | |
5040 Init(); | |
5041 } | |
5042 | |
5043 | |
5044 HeapIterator::HeapIterator(HeapIterator::HeapObjectsFiltering filtering) | |
5045 : filtering_(filtering), | |
5046 filter_(NULL) { | |
5047 Init(); | 5056 Init(); |
5048 } | 5057 } |
5049 | 5058 |
5050 | 5059 |
5051 HeapIterator::~HeapIterator() { | 5060 HeapIterator::~HeapIterator() { |
5052 Shutdown(); | 5061 Shutdown(); |
5053 } | 5062 } |
5054 | 5063 |
5055 | 5064 |
5056 void HeapIterator::Init() { | 5065 void HeapIterator::Init() { |
5057 // Start the iteration. | 5066 // Start the iteration. |
5058 space_iterator_ = filtering_ == kNoFiltering ? new SpaceIterator : | 5067 Heap::EnsureHeapIsIterable(); |
5059 new SpaceIterator(IntrusiveMarking::SizeOfMarkedObject); | 5068 space_iterator_ = new SpaceIterator(); |
5060 switch (filtering_) { | |
5061 case kFilterFreeListNodes: | |
5062 filter_ = new FreeListNodesFilter; | |
5063 break; | |
5064 case kFilterUnreachable: | |
5065 filter_ = new UnreachableObjectsFilter; | |
5066 break; | |
5067 default: | |
5068 break; | |
5069 } | |
5070 object_iterator_ = space_iterator_->next(); | 5069 object_iterator_ = space_iterator_->next(); |
5071 } | 5070 } |
5072 | 5071 |
5073 | 5072 |
5074 void HeapIterator::Shutdown() { | 5073 void HeapIterator::Shutdown() { |
5075 #ifdef DEBUG | |
5076 // Assert that in filtering mode we have iterated through all | |
5077 // objects. Otherwise, heap will be left in an inconsistent state. | |
5078 if (filtering_ != kNoFiltering) { | |
5079 ASSERT(object_iterator_ == NULL); | |
5080 } | |
5081 #endif | |
5082 // Make sure the last iterator is deallocated. | 5074 // Make sure the last iterator is deallocated. |
5083 delete space_iterator_; | 5075 delete space_iterator_; |
5084 space_iterator_ = NULL; | 5076 space_iterator_ = NULL; |
5085 object_iterator_ = NULL; | 5077 object_iterator_ = NULL; |
5086 delete filter_; | |
5087 filter_ = NULL; | |
5088 } | 5078 } |
5089 | 5079 |
5090 | 5080 |
5091 HeapObject* HeapIterator::next() { | 5081 HeapObject* HeapIterator::Next() { |
5092 if (filter_ == NULL) return NextObject(); | |
5093 | |
5094 HeapObject* obj = NextObject(); | |
5095 while (obj != NULL && filter_->SkipObject(obj)) obj = NextObject(); | |
5096 return obj; | |
5097 } | |
5098 | |
5099 | |
5100 HeapObject* HeapIterator::NextObject() { | |
5101 // No iterator means we are done. | 5082 // No iterator means we are done. |
5102 if (object_iterator_ == NULL) return NULL; | 5083 if (object_iterator_ == NULL) return NULL; |
5103 | 5084 |
5104 if (HeapObject* obj = object_iterator_->next_object()) { | 5085 if (HeapObject* obj = object_iterator_->next_object()) { |
5105 // If the current iterator has more objects we are fine. | 5086 // If the current iterator has more objects we are fine. |
5106 return obj; | 5087 return obj; |
5107 } else { | 5088 } else { |
5108 // Go though the spaces looking for one that has objects. | 5089 // Go though the spaces looking for one that has objects. |
5109 while (space_iterator_->has_next()) { | 5090 while (space_iterator_->has_next()) { |
5110 object_iterator_ = space_iterator_->next(); | 5091 object_iterator_ = space_iterator_->next(); |
5111 if (HeapObject* obj = object_iterator_->next_object()) { | 5092 if (HeapObject* obj = object_iterator_->next_object()) { |
5112 return obj; | 5093 return obj; |
5113 } | 5094 } |
5114 } | 5095 } |
5115 } | 5096 } |
5116 // Done with the last space. | 5097 // Done with the last space. |
5117 object_iterator_ = NULL; | 5098 object_iterator_ = NULL; |
5118 return NULL; | 5099 return NULL; |
5119 } | 5100 } |
5120 | 5101 |
5121 | 5102 |
5122 void HeapIterator::reset() { | 5103 void HeapIterator::Reset() { |
5123 // Restart the iterator. | 5104 // Restart the iterator. |
5124 Shutdown(); | 5105 Shutdown(); |
5125 Init(); | 5106 Init(); |
5126 } | 5107 } |
5127 | 5108 |
5128 | 5109 |
5129 #if defined(DEBUG) || defined(LIVE_OBJECT_LIST) | 5110 #if defined(DEBUG) || defined(LIVE_OBJECT_LIST) |
5130 | 5111 |
5131 Object* const PathTracer::kAnyGlobalObject = reinterpret_cast<Object*>(NULL); | 5112 Object* const PathTracer::kAnyGlobalObject = reinterpret_cast<Object*>(NULL); |
5132 | 5113 |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5315 } | 5296 } |
5316 #endif | 5297 #endif |
5317 | 5298 |
5318 | 5299 |
5319 static intptr_t CountTotalHolesSize() { | 5300 static intptr_t CountTotalHolesSize() { |
5320 intptr_t holes_size = 0; | 5301 intptr_t holes_size = 0; |
5321 OldSpaces spaces; | 5302 OldSpaces spaces; |
5322 for (OldSpace* space = spaces.next(); | 5303 for (OldSpace* space = spaces.next(); |
5323 space != NULL; | 5304 space != NULL; |
5324 space = spaces.next()) { | 5305 space = spaces.next()) { |
5325 holes_size += space->Waste() + space->AvailableFree(); | 5306 holes_size += space->Waste() + space->Available(); |
5326 } | 5307 } |
5327 return holes_size; | 5308 return holes_size; |
5328 } | 5309 } |
5329 | 5310 |
5330 | 5311 |
5331 GCTracer::GCTracer() | 5312 GCTracer::GCTracer() |
5332 : start_time_(0.0), | 5313 : start_time_(0.0), |
5333 start_size_(0), | 5314 start_size_(0), |
5334 gc_count_(0), | 5315 gc_count_(0), |
5335 full_gc_count_(0), | 5316 full_gc_count_(0), |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5556 void ExternalStringTable::TearDown() { | 5537 void ExternalStringTable::TearDown() { |
5557 new_space_strings_.Free(); | 5538 new_space_strings_.Free(); |
5558 old_space_strings_.Free(); | 5539 old_space_strings_.Free(); |
5559 } | 5540 } |
5560 | 5541 |
5561 | 5542 |
5562 List<Object*> ExternalStringTable::new_space_strings_; | 5543 List<Object*> ExternalStringTable::new_space_strings_; |
5563 List<Object*> ExternalStringTable::old_space_strings_; | 5544 List<Object*> ExternalStringTable::old_space_strings_; |
5564 | 5545 |
5565 } } // namespace v8::internal | 5546 } } // namespace v8::internal |
OLD | NEW |