OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 "src/heap/mark-compact.h" | 5 #include "src/heap/mark-compact.h" |
6 | 6 |
7 #include "src/base/atomicops.h" | 7 #include "src/base/atomicops.h" |
8 #include "src/base/bits.h" | 8 #include "src/base/bits.h" |
9 #include "src/base/sys-info.h" | 9 #include "src/base/sys-info.h" |
10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
342 | 342 |
343 void MarkCompactCollector::CollectGarbage() { | 343 void MarkCompactCollector::CollectGarbage() { |
344 // Make sure that Prepare() has been called. The individual steps below will | 344 // Make sure that Prepare() has been called. The individual steps below will |
345 // update the state as they proceed. | 345 // update the state as they proceed. |
346 DCHECK(state_ == PREPARE_GC); | 346 DCHECK(state_ == PREPARE_GC); |
347 | 347 |
348 MarkLiveObjects(); | 348 MarkLiveObjects(); |
349 | 349 |
350 DCHECK(heap_->incremental_marking()->IsStopped()); | 350 DCHECK(heap_->incremental_marking()->IsStopped()); |
351 | 351 |
352 // ClearNonLiveReferences can deoptimize code in dependent code arrays. | 352 DependentCode* dependent_code_list = DependentCodeListFromNonLiveMaps(); |
353 // Process weak cells before so that weak cells in dependent code | 353 |
354 // arrays are cleared or contain only live code objects. | 354 // Process weak cells before MarkCodeForDeoptimization and |
355 // ClearNonLiveReferences so that weak cells in dependent code arrays are | |
356 // cleared or contain only live code objects. | |
355 ProcessAndClearWeakCells(); | 357 ProcessAndClearWeakCells(); |
356 | 358 |
359 MarkDependentCodeListForDeoptimization(dependent_code_list); | |
360 | |
357 ClearNonLiveReferences(); | 361 ClearNonLiveReferences(); |
358 | 362 |
359 ClearWeakCollections(); | 363 ClearWeakCollections(); |
360 | 364 |
361 heap_->set_encountered_weak_cells(Smi::FromInt(0)); | 365 heap_->set_encountered_weak_cells(Smi::FromInt(0)); |
362 | 366 |
363 #ifdef VERIFY_HEAP | 367 #ifdef VERIFY_HEAP |
364 if (FLAG_verify_heap) { | 368 if (FLAG_verify_heap) { |
365 VerifyMarking(heap_); | 369 VerifyMarking(heap_); |
366 } | 370 } |
(...skipping 1447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1814 if (!code->CanDeoptAt(it.frame()->pc())) { | 1818 if (!code->CanDeoptAt(it.frame()->pc())) { |
1815 Code::BodyDescriptor::IterateBody(code, visitor); | 1819 Code::BodyDescriptor::IterateBody(code, visitor); |
1816 } | 1820 } |
1817 ProcessMarkingDeque(); | 1821 ProcessMarkingDeque(); |
1818 return; | 1822 return; |
1819 } | 1823 } |
1820 } | 1824 } |
1821 } | 1825 } |
1822 | 1826 |
1823 | 1827 |
1828 bool ShouldRetainMap(Map* map, int age) { | |
1829 if (age == 0) { | |
1830 // The map has aged. Do not retain this map. | |
1831 return false; | |
1832 } | |
1833 Object* constructor = map->GetConstructor(); | |
1834 if (!constructor->IsHeapObject() || | |
1835 Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(constructor)))) { | |
1836 // The constructor is dead, no new objects with this map can | |
1837 // be created. Do not retain this map. | |
1838 return false; | |
1839 } | |
1840 return true; | |
1841 } | |
1842 | |
1843 | |
1824 void MarkCompactCollector::RetainMaps() { | 1844 void MarkCompactCollector::RetainMaps() { |
1825 if (heap()->ShouldReduceMemory() || heap()->ShouldAbortIncrementalMarking() || | 1845 // Do not retain dead maps if flag disables it or there is |
ulan
2015/11/23 12:16:13
Early return was a bug. We still need to compact t
| |
1826 FLAG_retain_maps_for_n_gc == 0) { | 1846 // - memory pressure (reduce_memory_footprint_), |
1827 // Do not retain dead maps if flag disables it or there is | 1847 // - GC is requested by tests or dev-tools (abort_incremental_marking_). |
1828 // - memory pressure (reduce_memory_footprint_), | 1848 bool map_retaining_is_disabled = heap()->ShouldReduceMemory() || |
1829 // - GC is requested by tests or dev-tools (abort_incremental_marking_). | 1849 heap()->ShouldAbortIncrementalMarking() || |
1830 return; | 1850 FLAG_retain_maps_for_n_gc == 0; |
1831 } | |
1832 | 1851 |
1833 ArrayList* retained_maps = heap()->retained_maps(); | 1852 ArrayList* retained_maps = heap()->retained_maps(); |
1834 int length = retained_maps->Length(); | 1853 int length = retained_maps->Length(); |
1835 int new_length = 0; | 1854 int new_length = 0; |
1855 // This loop compacts the array by removing cleared weak cells, | |
1856 // ages and retains dead maps. | |
1836 for (int i = 0; i < length; i += 2) { | 1857 for (int i = 0; i < length; i += 2) { |
1837 DCHECK(retained_maps->Get(i)->IsWeakCell()); | 1858 DCHECK(retained_maps->Get(i)->IsWeakCell()); |
1838 WeakCell* cell = WeakCell::cast(retained_maps->Get(i)); | 1859 WeakCell* cell = WeakCell::cast(retained_maps->Get(i)); |
1839 if (cell->cleared()) continue; | 1860 if (cell->cleared()) continue; |
1840 int age = Smi::cast(retained_maps->Get(i + 1))->value(); | 1861 int age = Smi::cast(retained_maps->Get(i + 1))->value(); |
1841 int new_age; | 1862 int new_age; |
1842 Map* map = Map::cast(cell->value()); | 1863 Map* map = Map::cast(cell->value()); |
1843 MarkBit map_mark = Marking::MarkBitFrom(map); | 1864 MarkBit map_mark = Marking::MarkBitFrom(map); |
1844 if (Marking::IsWhite(map_mark)) { | 1865 // Age the map and retain it if necessary. |
1845 if (age == 0) { | 1866 if (!map_retaining_is_disabled && Marking::IsWhite(map_mark)) { |
1846 // The map has aged. Do not retain this map. | 1867 if (ShouldRetainMap(map, age)) { |
1847 continue; | 1868 MarkObject(map, map_mark); |
1848 } | |
1849 Object* constructor = map->GetConstructor(); | |
1850 if (!constructor->IsHeapObject() || Marking::IsWhite(Marking::MarkBitFrom( | |
1851 HeapObject::cast(constructor)))) { | |
1852 // The constructor is dead, no new objects with this map can | |
1853 // be created. Do not retain this map. | |
1854 continue; | |
1855 } | 1869 } |
1856 Object* prototype = map->prototype(); | 1870 Object* prototype = map->prototype(); |
1857 if (prototype->IsHeapObject() && | 1871 if (age > 0 && prototype->IsHeapObject() && |
1858 Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(prototype)))) { | 1872 Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(prototype)))) { |
1859 // The prototype is not marked, age the map. | 1873 // The prototype is not marked, age the map. |
1860 new_age = age - 1; | 1874 new_age = age - 1; |
1861 } else { | 1875 } else { |
1862 // The prototype and the constructor are marked, this map keeps only | 1876 // The prototype and the constructor are marked, this map keeps only |
1863 // transition tree alive, not JSObjects. Do not age the map. | 1877 // transition tree alive, not JSObjects. Do not age the map. |
1864 new_age = age; | 1878 new_age = age; |
1865 } | 1879 } |
1866 MarkObject(map, map_mark); | |
1867 } else { | 1880 } else { |
1868 new_age = FLAG_retain_maps_for_n_gc; | 1881 new_age = FLAG_retain_maps_for_n_gc; |
1869 } | 1882 } |
1883 // Compact the array and update the age. | |
1870 if (i != new_length) { | 1884 if (i != new_length) { |
1871 retained_maps->Set(new_length, cell); | 1885 retained_maps->Set(new_length, cell); |
1872 Object** slot = retained_maps->Slot(new_length); | 1886 Object** slot = retained_maps->Slot(new_length); |
1873 RecordSlot(retained_maps, slot, cell); | 1887 RecordSlot(retained_maps, slot, cell); |
1874 retained_maps->Set(new_length + 1, Smi::FromInt(new_age)); | 1888 retained_maps->Set(new_length + 1, Smi::FromInt(new_age)); |
1875 } else if (new_age != age) { | 1889 } else if (new_age != age) { |
1876 retained_maps->Set(new_length + 1, Smi::FromInt(new_age)); | 1890 retained_maps->Set(new_length + 1, Smi::FromInt(new_age)); |
1877 } | 1891 } |
1878 new_length += 2; | 1892 new_length += 2; |
1879 } | 1893 } |
1880 Object* undefined = heap()->undefined_value(); | 1894 Object* undefined = heap()->undefined_value(); |
1881 for (int i = new_length; i < length; i++) { | 1895 for (int i = new_length; i < length; i++) { |
1882 retained_maps->Clear(i, undefined); | 1896 retained_maps->Clear(i, undefined); |
1883 } | 1897 } |
1884 if (new_length != length) retained_maps->SetLength(new_length); | 1898 if (new_length != length) retained_maps->SetLength(new_length); |
1885 ProcessMarkingDeque(); | 1899 ProcessMarkingDeque(); |
1886 } | 1900 } |
1887 | 1901 |
1888 | 1902 |
1903 DependentCode* MarkCompactCollector::DependentCodeListFromNonLiveMaps() { | |
1904 ArrayList* retained_maps = heap()->retained_maps(); | |
1905 int length = retained_maps->Length(); | |
1906 DependentCode* head = DependentCode::cast(heap()->empty_fixed_array()); | |
1907 for (int i = 0; i < length; i += 2) { | |
1908 DCHECK(retained_maps->Get(i)->IsWeakCell()); | |
1909 WeakCell* cell = WeakCell::cast(retained_maps->Get(i)); | |
1910 DCHECK(!cell->cleared()); | |
1911 Map* map = Map::cast(cell->value()); | |
1912 MarkBit map_mark = Marking::MarkBitFrom(map); | |
1913 if (Marking::IsWhite(map_mark)) { | |
1914 DependentCode* new_head = map->dependent_code(); | |
1915 DCHECK_EQ(DependentCode::kWeakCodeGroup, new_head->group()); | |
1916 new_head->set_next_link(head); | |
1917 head = new_head; | |
1918 } | |
1919 } | |
1920 return head; | |
1921 } | |
1922 | |
1923 | |
1889 void MarkCompactCollector::EnsureMarkingDequeIsReserved() { | 1924 void MarkCompactCollector::EnsureMarkingDequeIsReserved() { |
1890 DCHECK(!marking_deque_.in_use()); | 1925 DCHECK(!marking_deque_.in_use()); |
1891 if (marking_deque_memory_ == NULL) { | 1926 if (marking_deque_memory_ == NULL) { |
1892 marking_deque_memory_ = new base::VirtualMemory(kMaxMarkingDequeSize); | 1927 marking_deque_memory_ = new base::VirtualMemory(kMaxMarkingDequeSize); |
1893 marking_deque_memory_committed_ = 0; | 1928 marking_deque_memory_committed_ = 0; |
1894 } | 1929 } |
1895 if (marking_deque_memory_ == NULL) { | 1930 if (marking_deque_memory_ == NULL) { |
1896 V8::FatalProcessOutOfMemory("EnsureMarkingDequeIsReserved"); | 1931 V8::FatalProcessOutOfMemory("EnsureMarkingDequeIsReserved"); |
1897 } | 1932 } |
1898 } | 1933 } |
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2202 for (HeapObject* obj = map_iterator.Next(); obj != NULL; | 2237 for (HeapObject* obj = map_iterator.Next(); obj != NULL; |
2203 obj = map_iterator.Next()) { | 2238 obj = map_iterator.Next()) { |
2204 Map* map = Map::cast(obj); | 2239 Map* map = Map::cast(obj); |
2205 if (!map->CanTransition()) continue; | 2240 if (!map->CanTransition()) continue; |
2206 MarkBit map_mark = Marking::MarkBitFrom(map); | 2241 MarkBit map_mark = Marking::MarkBitFrom(map); |
2207 bool alive = Marking::IsBlackOrGrey(map_mark); | 2242 bool alive = Marking::IsBlackOrGrey(map_mark); |
2208 if (alive) { | 2243 if (alive) { |
2209 ClearNonLivePrototypeTransitions(map); | 2244 ClearNonLivePrototypeTransitions(map); |
2210 } else { | 2245 } else { |
2211 ClearNonLiveMapTransitions(map); | 2246 ClearNonLiveMapTransitions(map); |
2212 have_code_to_deoptimize_ |= | |
ulan
2015/11/23 12:16:13
Moving this code out is the main change.
| |
2213 map->dependent_code()->MarkCodeForDeoptimization( | |
2214 isolate(), DependentCode::kWeakCodeGroup); | |
2215 map->set_dependent_code(DependentCode::cast(heap()->empty_fixed_array())); | |
2216 } | 2247 } |
2217 } | 2248 } |
2218 | 2249 |
2219 WeakHashTable* table = heap_->weak_object_to_code_table(); | 2250 WeakHashTable* table = heap_->weak_object_to_code_table(); |
2220 uint32_t capacity = table->Capacity(); | 2251 uint32_t capacity = table->Capacity(); |
2221 for (uint32_t i = 0; i < capacity; i++) { | 2252 for (uint32_t i = 0; i < capacity; i++) { |
2222 uint32_t key_index = table->EntryToIndex(i); | 2253 uint32_t key_index = table->EntryToIndex(i); |
2223 Object* key = table->get(key_index); | 2254 Object* key = table->get(key_index); |
2224 if (!table->IsKey(key)) continue; | 2255 if (!table->IsKey(key)) continue; |
2225 uint32_t value_index = table->EntryToValueIndex(i); | 2256 uint32_t value_index = table->EntryToValueIndex(i); |
2226 Object* value = table->get(value_index); | 2257 Object* value = table->get(value_index); |
2227 DCHECK(key->IsWeakCell()); | 2258 DCHECK(key->IsWeakCell()); |
2228 if (WeakCell::cast(key)->cleared()) { | 2259 if (WeakCell::cast(key)->cleared()) { |
2229 have_code_to_deoptimize_ |= | 2260 have_code_to_deoptimize_ |= |
2230 DependentCode::cast(value)->MarkCodeForDeoptimization( | 2261 DependentCode::cast(value)->MarkCodeForDeoptimization( |
2231 isolate(), DependentCode::kWeakCodeGroup); | 2262 isolate(), DependentCode::kWeakCodeGroup); |
2232 table->set(key_index, heap_->the_hole_value()); | 2263 table->set(key_index, heap_->the_hole_value()); |
2233 table->set(value_index, heap_->the_hole_value()); | 2264 table->set(value_index, heap_->the_hole_value()); |
2234 table->ElementRemoved(); | 2265 table->ElementRemoved(); |
2235 } | 2266 } |
2236 } | 2267 } |
2237 } | 2268 } |
2238 | 2269 |
2239 | 2270 |
2271 void MarkCompactCollector::MarkDependentCodeListForDeoptimization( | |
2272 DependentCode* list_head) { | |
2273 Isolate* isolate = this->isolate(); | |
2274 DependentCode* current = list_head; | |
2275 while (current->length() > 0) { | |
2276 have_code_to_deoptimize_ |= current->MarkCodeForDeoptimization( | |
2277 isolate, DependentCode::kWeakCodeGroup); | |
2278 current = current->next_link(); | |
2279 } | |
2280 } | |
2281 | |
2282 | |
2240 void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) { | 2283 void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) { |
2241 FixedArray* prototype_transitions = | 2284 FixedArray* prototype_transitions = |
2242 TransitionArray::GetPrototypeTransitions(map); | 2285 TransitionArray::GetPrototypeTransitions(map); |
2243 int number_of_transitions = | 2286 int number_of_transitions = |
2244 TransitionArray::NumberOfPrototypeTransitions(prototype_transitions); | 2287 TransitionArray::NumberOfPrototypeTransitions(prototype_transitions); |
2245 | 2288 |
2246 const int header = TransitionArray::kProtoTransitionHeaderSize; | 2289 const int header = TransitionArray::kProtoTransitionHeaderSize; |
2247 int new_number_of_transitions = 0; | 2290 int new_number_of_transitions = 0; |
2248 for (int i = 0; i < number_of_transitions; i++) { | 2291 for (int i = 0; i < number_of_transitions; i++) { |
2249 Object* cell = prototype_transitions->get(header + i); | 2292 Object* cell = prototype_transitions->get(header + i); |
(...skipping 2237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4487 MarkBit mark_bit = Marking::MarkBitFrom(host); | 4530 MarkBit mark_bit = Marking::MarkBitFrom(host); |
4488 if (Marking::IsBlack(mark_bit)) { | 4531 if (Marking::IsBlack(mark_bit)) { |
4489 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host); | 4532 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host); |
4490 RecordRelocSlot(&rinfo, target); | 4533 RecordRelocSlot(&rinfo, target); |
4491 } | 4534 } |
4492 } | 4535 } |
4493 } | 4536 } |
4494 | 4537 |
4495 } // namespace internal | 4538 } // namespace internal |
4496 } // namespace v8 | 4539 } // namespace v8 |
OLD | NEW |