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 // This should be done before processing weak cells because it checks |
Hannes Payer (out of office)
2015/11/24 09:35:36
Let's add here a special category: ProcessWeakRefe
ulan
2015/11/24 12:00:08
Done.
| |
353 // Process weak cells before so that weak cells in dependent code | 353 // mark bits of maps in weak cells. |
354 // arrays are cleared or contain only live code objects. | 354 DependentCode* dependent_code_list = DependentCodeListFromNonLiveMaps(); |
355 | |
356 // Process weak cells before MarkCodeForDeoptimization and | |
357 // ClearNonLiveReferences so that weak cells in dependent code arrays are | |
358 // cleared or contain only live code objects. | |
355 ProcessAndClearWeakCells(); | 359 ProcessAndClearWeakCells(); |
356 | 360 |
361 MarkDependentCodeListForDeoptimization(dependent_code_list); | |
362 | |
357 ClearNonLiveReferences(); | 363 ClearNonLiveReferences(); |
358 | 364 |
359 ClearWeakCollections(); | 365 ClearWeakCollections(); |
360 | 366 |
361 heap_->set_encountered_weak_cells(Smi::FromInt(0)); | 367 heap_->set_encountered_weak_cells(Smi::FromInt(0)); |
362 | 368 |
363 #ifdef VERIFY_HEAP | 369 #ifdef VERIFY_HEAP |
364 if (FLAG_verify_heap) { | 370 if (FLAG_verify_heap) { |
365 VerifyMarking(heap_); | 371 VerifyMarking(heap_); |
366 } | 372 } |
(...skipping 1447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1814 if (!code->CanDeoptAt(it.frame()->pc())) { | 1820 if (!code->CanDeoptAt(it.frame()->pc())) { |
1815 Code::BodyDescriptor::IterateBody(code, visitor); | 1821 Code::BodyDescriptor::IterateBody(code, visitor); |
1816 } | 1822 } |
1817 ProcessMarkingDeque(); | 1823 ProcessMarkingDeque(); |
1818 return; | 1824 return; |
1819 } | 1825 } |
1820 } | 1826 } |
1821 } | 1827 } |
1822 | 1828 |
1823 | 1829 |
1830 bool ShouldRetainMap(Map* map, int age) { | |
1831 if (age == 0) { | |
1832 // The map has aged. Do not retain this map. | |
1833 return false; | |
1834 } | |
1835 Object* constructor = map->GetConstructor(); | |
1836 if (!constructor->IsHeapObject() || | |
1837 Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(constructor)))) { | |
1838 // The constructor is dead, no new objects with this map can | |
1839 // be created. Do not retain this map. | |
1840 return false; | |
1841 } | |
1842 return true; | |
1843 } | |
1844 | |
1845 | |
1824 void MarkCompactCollector::RetainMaps() { | 1846 void MarkCompactCollector::RetainMaps() { |
1825 if (heap()->ShouldReduceMemory() || heap()->ShouldAbortIncrementalMarking() || | 1847 // Do not retain dead maps if flag disables it or there is |
1826 FLAG_retain_maps_for_n_gc == 0) { | 1848 // - memory pressure (reduce_memory_footprint_), |
1827 // Do not retain dead maps if flag disables it or there is | 1849 // - GC is requested by tests or dev-tools (abort_incremental_marking_). |
1828 // - memory pressure (reduce_memory_footprint_), | 1850 bool map_retaining_is_disabled = heap()->ShouldReduceMemory() || |
1829 // - GC is requested by tests or dev-tools (abort_incremental_marking_). | 1851 heap()->ShouldAbortIncrementalMarking() || |
1830 return; | 1852 FLAG_retain_maps_for_n_gc == 0; |
1831 } | |
1832 | 1853 |
1833 ArrayList* retained_maps = heap()->retained_maps(); | 1854 ArrayList* retained_maps = heap()->retained_maps(); |
1834 int length = retained_maps->Length(); | 1855 int length = retained_maps->Length(); |
1835 int new_length = 0; | 1856 int new_length = 0; |
1857 // This loop compacts the array by removing cleared weak cells, | |
1858 // ages and retains dead maps. | |
1836 for (int i = 0; i < length; i += 2) { | 1859 for (int i = 0; i < length; i += 2) { |
1837 DCHECK(retained_maps->Get(i)->IsWeakCell()); | 1860 DCHECK(retained_maps->Get(i)->IsWeakCell()); |
1838 WeakCell* cell = WeakCell::cast(retained_maps->Get(i)); | 1861 WeakCell* cell = WeakCell::cast(retained_maps->Get(i)); |
1839 if (cell->cleared()) continue; | 1862 if (cell->cleared()) continue; |
1840 int age = Smi::cast(retained_maps->Get(i + 1))->value(); | 1863 int age = Smi::cast(retained_maps->Get(i + 1))->value(); |
1841 int new_age; | 1864 int new_age; |
1842 Map* map = Map::cast(cell->value()); | 1865 Map* map = Map::cast(cell->value()); |
1843 MarkBit map_mark = Marking::MarkBitFrom(map); | 1866 MarkBit map_mark = Marking::MarkBitFrom(map); |
1844 if (Marking::IsWhite(map_mark)) { | 1867 // Age the map and retain it if necessary. |
1845 if (age == 0) { | 1868 if (!map_retaining_is_disabled && Marking::IsWhite(map_mark)) { |
1846 // The map has aged. Do not retain this map. | 1869 if (ShouldRetainMap(map, age)) { |
1847 continue; | 1870 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 } | 1871 } |
1856 Object* prototype = map->prototype(); | 1872 Object* prototype = map->prototype(); |
1857 if (prototype->IsHeapObject() && | 1873 if (age > 0 && prototype->IsHeapObject() && |
1858 Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(prototype)))) { | 1874 Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(prototype)))) { |
1859 // The prototype is not marked, age the map. | 1875 // The prototype is not marked, age the map. |
1860 new_age = age - 1; | 1876 new_age = age - 1; |
1861 } else { | 1877 } else { |
1862 // The prototype and the constructor are marked, this map keeps only | 1878 // The prototype and the constructor are marked, this map keeps only |
1863 // transition tree alive, not JSObjects. Do not age the map. | 1879 // transition tree alive, not JSObjects. Do not age the map. |
1864 new_age = age; | 1880 new_age = age; |
1865 } | 1881 } |
1866 MarkObject(map, map_mark); | |
1867 } else { | 1882 } else { |
1868 new_age = FLAG_retain_maps_for_n_gc; | 1883 new_age = FLAG_retain_maps_for_n_gc; |
1869 } | 1884 } |
1885 // Compact the array and update the age. | |
1870 if (i != new_length) { | 1886 if (i != new_length) { |
1871 retained_maps->Set(new_length, cell); | 1887 retained_maps->Set(new_length, cell); |
1872 Object** slot = retained_maps->Slot(new_length); | 1888 Object** slot = retained_maps->Slot(new_length); |
1873 RecordSlot(retained_maps, slot, cell); | 1889 RecordSlot(retained_maps, slot, cell); |
1874 retained_maps->Set(new_length + 1, Smi::FromInt(new_age)); | 1890 retained_maps->Set(new_length + 1, Smi::FromInt(new_age)); |
1875 } else if (new_age != age) { | 1891 } else if (new_age != age) { |
1876 retained_maps->Set(new_length + 1, Smi::FromInt(new_age)); | 1892 retained_maps->Set(new_length + 1, Smi::FromInt(new_age)); |
1877 } | 1893 } |
1878 new_length += 2; | 1894 new_length += 2; |
1879 } | 1895 } |
1880 Object* undefined = heap()->undefined_value(); | 1896 Object* undefined = heap()->undefined_value(); |
1881 for (int i = new_length; i < length; i++) { | 1897 for (int i = new_length; i < length; i++) { |
1882 retained_maps->Clear(i, undefined); | 1898 retained_maps->Clear(i, undefined); |
1883 } | 1899 } |
1884 if (new_length != length) retained_maps->SetLength(new_length); | 1900 if (new_length != length) retained_maps->SetLength(new_length); |
1885 ProcessMarkingDeque(); | 1901 ProcessMarkingDeque(); |
1886 } | 1902 } |
1887 | 1903 |
1888 | 1904 |
1905 DependentCode* MarkCompactCollector::DependentCodeListFromNonLiveMaps() { | |
Hannes Payer (out of office)
2015/11/24 09:35:37
Timer scope.
ulan
2015/11/24 12:00:08
Done.
| |
1906 ArrayList* retained_maps = heap()->retained_maps(); | |
1907 int length = retained_maps->Length(); | |
1908 DependentCode* head = DependentCode::cast(heap()->empty_fixed_array()); | |
1909 for (int i = 0; i < length; i += 2) { | |
1910 DCHECK(retained_maps->Get(i)->IsWeakCell()); | |
1911 WeakCell* cell = WeakCell::cast(retained_maps->Get(i)); | |
1912 DCHECK(!cell->cleared()); | |
1913 Map* map = Map::cast(cell->value()); | |
1914 MarkBit map_mark = Marking::MarkBitFrom(map); | |
1915 if (Marking::IsWhite(map_mark)) { | |
1916 DependentCode* candidate = map->dependent_code(); | |
1917 // We rely on the fact that the weak code group comes first. | |
1918 STATIC_ASSERT(DependentCode::kWeakCodeGroup == 0); | |
1919 if (candidate->length() > 0 && | |
1920 candidate->group() == DependentCode::kWeakCodeGroup) { | |
1921 candidate->set_next_link(head); | |
1922 head = candidate; | |
1923 } | |
1924 } | |
1925 } | |
1926 return head; | |
1927 } | |
1928 | |
1929 | |
1889 void MarkCompactCollector::EnsureMarkingDequeIsReserved() { | 1930 void MarkCompactCollector::EnsureMarkingDequeIsReserved() { |
1890 DCHECK(!marking_deque_.in_use()); | 1931 DCHECK(!marking_deque_.in_use()); |
1891 if (marking_deque_memory_ == NULL) { | 1932 if (marking_deque_memory_ == NULL) { |
1892 marking_deque_memory_ = new base::VirtualMemory(kMaxMarkingDequeSize); | 1933 marking_deque_memory_ = new base::VirtualMemory(kMaxMarkingDequeSize); |
1893 marking_deque_memory_committed_ = 0; | 1934 marking_deque_memory_committed_ = 0; |
1894 } | 1935 } |
1895 if (marking_deque_memory_ == NULL) { | 1936 if (marking_deque_memory_ == NULL) { |
1896 V8::FatalProcessOutOfMemory("EnsureMarkingDequeIsReserved"); | 1937 V8::FatalProcessOutOfMemory("EnsureMarkingDequeIsReserved"); |
1897 } | 1938 } |
1898 } | 1939 } |
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2202 for (HeapObject* obj = map_iterator.Next(); obj != NULL; | 2243 for (HeapObject* obj = map_iterator.Next(); obj != NULL; |
2203 obj = map_iterator.Next()) { | 2244 obj = map_iterator.Next()) { |
2204 Map* map = Map::cast(obj); | 2245 Map* map = Map::cast(obj); |
2205 if (!map->CanTransition()) continue; | 2246 if (!map->CanTransition()) continue; |
2206 MarkBit map_mark = Marking::MarkBitFrom(map); | 2247 MarkBit map_mark = Marking::MarkBitFrom(map); |
2207 bool alive = Marking::IsBlackOrGrey(map_mark); | 2248 bool alive = Marking::IsBlackOrGrey(map_mark); |
2208 if (alive) { | 2249 if (alive) { |
2209 ClearNonLivePrototypeTransitions(map); | 2250 ClearNonLivePrototypeTransitions(map); |
2210 } else { | 2251 } else { |
2211 ClearNonLiveMapTransitions(map); | 2252 ClearNonLiveMapTransitions(map); |
2212 have_code_to_deoptimize_ |= | |
2213 map->dependent_code()->MarkCodeForDeoptimization( | |
2214 isolate(), DependentCode::kWeakCodeGroup); | |
2215 map->set_dependent_code(DependentCode::cast(heap()->empty_fixed_array())); | |
2216 } | 2253 } |
2217 } | 2254 } |
2218 | 2255 |
2219 WeakHashTable* table = heap_->weak_object_to_code_table(); | 2256 WeakHashTable* table = heap_->weak_object_to_code_table(); |
2220 uint32_t capacity = table->Capacity(); | 2257 uint32_t capacity = table->Capacity(); |
2221 for (uint32_t i = 0; i < capacity; i++) { | 2258 for (uint32_t i = 0; i < capacity; i++) { |
2222 uint32_t key_index = table->EntryToIndex(i); | 2259 uint32_t key_index = table->EntryToIndex(i); |
2223 Object* key = table->get(key_index); | 2260 Object* key = table->get(key_index); |
2224 if (!table->IsKey(key)) continue; | 2261 if (!table->IsKey(key)) continue; |
2225 uint32_t value_index = table->EntryToValueIndex(i); | 2262 uint32_t value_index = table->EntryToValueIndex(i); |
2226 Object* value = table->get(value_index); | 2263 Object* value = table->get(value_index); |
2227 DCHECK(key->IsWeakCell()); | 2264 DCHECK(key->IsWeakCell()); |
2228 if (WeakCell::cast(key)->cleared()) { | 2265 if (WeakCell::cast(key)->cleared()) { |
2229 have_code_to_deoptimize_ |= | 2266 have_code_to_deoptimize_ |= |
2230 DependentCode::cast(value)->MarkCodeForDeoptimization( | 2267 DependentCode::cast(value)->MarkCodeForDeoptimization( |
2231 isolate(), DependentCode::kWeakCodeGroup); | 2268 isolate(), DependentCode::kWeakCodeGroup); |
2232 table->set(key_index, heap_->the_hole_value()); | 2269 table->set(key_index, heap_->the_hole_value()); |
2233 table->set(value_index, heap_->the_hole_value()); | 2270 table->set(value_index, heap_->the_hole_value()); |
2234 table->ElementRemoved(); | 2271 table->ElementRemoved(); |
2235 } | 2272 } |
2236 } | 2273 } |
2237 } | 2274 } |
2238 | 2275 |
2239 | 2276 |
2277 void MarkCompactCollector::MarkDependentCodeListForDeoptimization( | |
Hannes Payer (out of office)
2015/11/24 09:35:36
Timer scope.
ulan
2015/11/24 12:00:08
Done.
| |
2278 DependentCode* list_head) { | |
2279 Isolate* isolate = this->isolate(); | |
2280 DependentCode* current = list_head; | |
2281 while (current->length() > 0) { | |
2282 have_code_to_deoptimize_ |= current->MarkCodeForDeoptimization( | |
2283 isolate, DependentCode::kWeakCodeGroup); | |
2284 current = current->next_link(); | |
2285 } | |
2286 } | |
2287 | |
2288 | |
2240 void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) { | 2289 void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) { |
2241 FixedArray* prototype_transitions = | 2290 FixedArray* prototype_transitions = |
2242 TransitionArray::GetPrototypeTransitions(map); | 2291 TransitionArray::GetPrototypeTransitions(map); |
2243 int number_of_transitions = | 2292 int number_of_transitions = |
2244 TransitionArray::NumberOfPrototypeTransitions(prototype_transitions); | 2293 TransitionArray::NumberOfPrototypeTransitions(prototype_transitions); |
2245 | 2294 |
2246 const int header = TransitionArray::kProtoTransitionHeaderSize; | 2295 const int header = TransitionArray::kProtoTransitionHeaderSize; |
2247 int new_number_of_transitions = 0; | 2296 int new_number_of_transitions = 0; |
2248 for (int i = 0; i < number_of_transitions; i++) { | 2297 for (int i = 0; i < number_of_transitions; i++) { |
2249 Object* cell = prototype_transitions->get(header + i); | 2298 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); | 4536 MarkBit mark_bit = Marking::MarkBitFrom(host); |
4488 if (Marking::IsBlack(mark_bit)) { | 4537 if (Marking::IsBlack(mark_bit)) { |
4489 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host); | 4538 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host); |
4490 RecordRelocSlot(&rinfo, target); | 4539 RecordRelocSlot(&rinfo, target); |
4491 } | 4540 } |
4492 } | 4541 } |
4493 } | 4542 } |
4494 | 4543 |
4495 } // namespace internal | 4544 } // namespace internal |
4496 } // namespace v8 | 4545 } // namespace v8 |
OLD | NEW |