Chromium Code Reviews| 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 |