Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(313)

Side by Side Diff: src/heap/mark-compact.cc

Issue 1471703002: Optimize ClearNonLiveReferences: collect dependent code only from maps that are embedded in optimize (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/heap/mark-compact.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 ProcessWeakReferences();
353 // Process weak cells before so that weak cells in dependent code
354 // arrays are cleared or contain only live code objects.
355 ProcessAndClearWeakCells();
356
357 ClearNonLiveReferences();
358
359 ClearWeakCollections();
360
361 heap_->set_encountered_weak_cells(Smi::FromInt(0));
362 353
363 #ifdef VERIFY_HEAP 354 #ifdef VERIFY_HEAP
364 if (FLAG_verify_heap) { 355 if (FLAG_verify_heap) {
365 VerifyMarking(heap_); 356 VerifyMarking(heap_);
366 } 357 }
367 #endif 358 #endif
368 359
369 ClearInvalidStoreAndSlotsBufferEntries(); 360 ClearInvalidStoreAndSlotsBufferEntries();
370 361
371 #ifdef VERIFY_HEAP 362 #ifdef VERIFY_HEAP
(...skipping 1442 matching lines...) Expand 10 before | Expand all | Expand 10 after
1814 if (!code->CanDeoptAt(it.frame()->pc())) { 1805 if (!code->CanDeoptAt(it.frame()->pc())) {
1815 Code::BodyDescriptor::IterateBody(code, visitor); 1806 Code::BodyDescriptor::IterateBody(code, visitor);
1816 } 1807 }
1817 ProcessMarkingDeque(); 1808 ProcessMarkingDeque();
1818 return; 1809 return;
1819 } 1810 }
1820 } 1811 }
1821 } 1812 }
1822 1813
1823 1814
1815 bool ShouldRetainMap(Map* map, int age) {
1816 if (age == 0) {
1817 // The map has aged. Do not retain this map.
1818 return false;
1819 }
1820 Object* constructor = map->GetConstructor();
1821 if (!constructor->IsHeapObject() ||
1822 Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(constructor)))) {
1823 // The constructor is dead, no new objects with this map can
1824 // be created. Do not retain this map.
1825 return false;
1826 }
1827 return true;
1828 }
1829
1830
1824 void MarkCompactCollector::RetainMaps() { 1831 void MarkCompactCollector::RetainMaps() {
1825 if (heap()->ShouldReduceMemory() || heap()->ShouldAbortIncrementalMarking() || 1832 // Do not retain dead maps if flag disables it or there is
1826 FLAG_retain_maps_for_n_gc == 0) { 1833 // - memory pressure (reduce_memory_footprint_),
1827 // Do not retain dead maps if flag disables it or there is 1834 // - GC is requested by tests or dev-tools (abort_incremental_marking_).
1828 // - memory pressure (reduce_memory_footprint_), 1835 bool map_retaining_is_disabled = heap()->ShouldReduceMemory() ||
1829 // - GC is requested by tests or dev-tools (abort_incremental_marking_). 1836 heap()->ShouldAbortIncrementalMarking() ||
1830 return; 1837 FLAG_retain_maps_for_n_gc == 0;
1831 }
1832 1838
1833 ArrayList* retained_maps = heap()->retained_maps(); 1839 ArrayList* retained_maps = heap()->retained_maps();
1834 int length = retained_maps->Length(); 1840 int length = retained_maps->Length();
1835 int new_length = 0; 1841 int new_length = 0;
1842 // The number_of_disposed_maps separates maps in the retained_maps
1843 // array that were created before and after context disposal.
1844 // We do not age and retain disposed maps to avoid memory leaks.
1845 int number_of_disposed_maps = heap()->number_of_disposed_maps_;
1846 int new_number_of_disposed_maps = 0;
1847 // This loop compacts the array by removing cleared weak cells,
1848 // ages and retains dead maps.
1836 for (int i = 0; i < length; i += 2) { 1849 for (int i = 0; i < length; i += 2) {
1837 DCHECK(retained_maps->Get(i)->IsWeakCell()); 1850 DCHECK(retained_maps->Get(i)->IsWeakCell());
1838 WeakCell* cell = WeakCell::cast(retained_maps->Get(i)); 1851 WeakCell* cell = WeakCell::cast(retained_maps->Get(i));
1839 if (cell->cleared()) continue; 1852 if (cell->cleared()) continue;
1840 int age = Smi::cast(retained_maps->Get(i + 1))->value(); 1853 int age = Smi::cast(retained_maps->Get(i + 1))->value();
1841 int new_age; 1854 int new_age;
1842 Map* map = Map::cast(cell->value()); 1855 Map* map = Map::cast(cell->value());
1843 MarkBit map_mark = Marking::MarkBitFrom(map); 1856 MarkBit map_mark = Marking::MarkBitFrom(map);
1844 if (Marking::IsWhite(map_mark)) { 1857 if (i >= number_of_disposed_maps && !map_retaining_is_disabled &&
1845 if (age == 0) { 1858 Marking::IsWhite(map_mark)) {
1846 // The map has aged. Do not retain this map. 1859 if (ShouldRetainMap(map, age)) {
1847 continue; 1860 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 } 1861 }
1856 Object* prototype = map->prototype(); 1862 Object* prototype = map->prototype();
1857 if (prototype->IsHeapObject() && 1863 if (age > 0 && prototype->IsHeapObject() &&
1858 Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(prototype)))) { 1864 Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(prototype)))) {
1859 // The prototype is not marked, age the map. 1865 // The prototype is not marked, age the map.
1860 new_age = age - 1; 1866 new_age = age - 1;
1861 } else { 1867 } else {
1862 // The prototype and the constructor are marked, this map keeps only 1868 // The prototype and the constructor are marked, this map keeps only
1863 // transition tree alive, not JSObjects. Do not age the map. 1869 // transition tree alive, not JSObjects. Do not age the map.
1864 new_age = age; 1870 new_age = age;
1865 } 1871 }
1866 MarkObject(map, map_mark);
1867 } else { 1872 } else {
1868 new_age = FLAG_retain_maps_for_n_gc; 1873 new_age = FLAG_retain_maps_for_n_gc;
1869 } 1874 }
1875 // Compact the array and update the age.
1870 if (i != new_length) { 1876 if (i != new_length) {
1871 retained_maps->Set(new_length, cell); 1877 retained_maps->Set(new_length, cell);
1872 Object** slot = retained_maps->Slot(new_length); 1878 Object** slot = retained_maps->Slot(new_length);
1873 RecordSlot(retained_maps, slot, cell); 1879 RecordSlot(retained_maps, slot, cell);
1874 retained_maps->Set(new_length + 1, Smi::FromInt(new_age)); 1880 retained_maps->Set(new_length + 1, Smi::FromInt(new_age));
1875 } else if (new_age != age) { 1881 } else if (new_age != age) {
1876 retained_maps->Set(new_length + 1, Smi::FromInt(new_age)); 1882 retained_maps->Set(new_length + 1, Smi::FromInt(new_age));
1877 } 1883 }
1884 if (i < number_of_disposed_maps) {
1885 new_number_of_disposed_maps++;
1886 }
1878 new_length += 2; 1887 new_length += 2;
1879 } 1888 }
1889 heap()->number_of_disposed_maps_ = new_number_of_disposed_maps;
1880 Object* undefined = heap()->undefined_value(); 1890 Object* undefined = heap()->undefined_value();
1881 for (int i = new_length; i < length; i++) { 1891 for (int i = new_length; i < length; i++) {
1882 retained_maps->Clear(i, undefined); 1892 retained_maps->Clear(i, undefined);
1883 } 1893 }
1884 if (new_length != length) retained_maps->SetLength(new_length); 1894 if (new_length != length) retained_maps->SetLength(new_length);
1885 ProcessMarkingDeque(); 1895 ProcessMarkingDeque();
1886 } 1896 }
1887 1897
1888 1898
1899 DependentCode* MarkCompactCollector::DependentCodeListFromNonLiveMaps() {
1900 GCTracer::Scope gc_scope(heap()->tracer(),
1901 GCTracer::Scope::MC_EXTRACT_DEPENDENT_CODE);
1902 ArrayList* retained_maps = heap()->retained_maps();
1903 int length = retained_maps->Length();
1904 DependentCode* head = DependentCode::cast(heap()->empty_fixed_array());
1905 for (int i = 0; i < length; i += 2) {
1906 DCHECK(retained_maps->Get(i)->IsWeakCell());
1907 WeakCell* cell = WeakCell::cast(retained_maps->Get(i));
1908 DCHECK(!cell->cleared());
1909 Map* map = Map::cast(cell->value());
1910 MarkBit map_mark = Marking::MarkBitFrom(map);
1911 if (Marking::IsWhite(map_mark)) {
1912 DependentCode* candidate = map->dependent_code();
1913 // We rely on the fact that the weak code group comes first.
1914 STATIC_ASSERT(DependentCode::kWeakCodeGroup == 0);
1915 if (candidate->length() > 0 &&
1916 candidate->group() == DependentCode::kWeakCodeGroup) {
1917 candidate->set_next_link(head);
1918 head = candidate;
1919 }
1920 }
1921 }
1922 return head;
1923 }
1924
1925
1889 void MarkCompactCollector::EnsureMarkingDequeIsReserved() { 1926 void MarkCompactCollector::EnsureMarkingDequeIsReserved() {
1890 DCHECK(!marking_deque_.in_use()); 1927 DCHECK(!marking_deque_.in_use());
1891 if (marking_deque_memory_ == NULL) { 1928 if (marking_deque_memory_ == NULL) {
1892 marking_deque_memory_ = new base::VirtualMemory(kMaxMarkingDequeSize); 1929 marking_deque_memory_ = new base::VirtualMemory(kMaxMarkingDequeSize);
1893 marking_deque_memory_committed_ = 0; 1930 marking_deque_memory_committed_ = 0;
1894 } 1931 }
1895 if (marking_deque_memory_ == NULL) { 1932 if (marking_deque_memory_ == NULL) {
1896 V8::FatalProcessOutOfMemory("EnsureMarkingDequeIsReserved"); 1933 V8::FatalProcessOutOfMemory("EnsureMarkingDequeIsReserved");
1897 } 1934 }
1898 } 1935 }
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after
2185 } 2222 }
2186 2223
2187 // Trim the optimized code map if entries have been removed. 2224 // Trim the optimized code map if entries have been removed.
2188 if (new_length < old_length) { 2225 if (new_length < old_length) {
2189 shared->TrimOptimizedCodeMap(old_length - new_length); 2226 shared->TrimOptimizedCodeMap(old_length - new_length);
2190 } 2227 }
2191 } 2228 }
2192 } 2229 }
2193 2230
2194 2231
2232 void MarkCompactCollector::ProcessWeakReferences() {
2233 // This should be done before processing weak cells because it checks
2234 // mark bits of maps in weak cells.
2235 DependentCode* dependent_code_list = DependentCodeListFromNonLiveMaps();
2236
2237 // Process weak cells before MarkCodeForDeoptimization and
2238 // ClearNonLiveReferences so that weak cells in dependent code arrays are
2239 // cleared or contain only live code objects.
2240 ProcessAndClearWeakCells();
2241
2242 MarkDependentCodeListForDeoptimization(dependent_code_list);
2243
2244 ClearNonLiveReferences();
2245
2246 ClearWeakCollections();
2247
2248 heap_->set_encountered_weak_cells(Smi::FromInt(0));
2249 }
2250
2251
2195 void MarkCompactCollector::ClearNonLiveReferences() { 2252 void MarkCompactCollector::ClearNonLiveReferences() {
2196 GCTracer::Scope gc_scope(heap()->tracer(), 2253 GCTracer::Scope gc_scope(heap()->tracer(),
2197 GCTracer::Scope::MC_NONLIVEREFERENCES); 2254 GCTracer::Scope::MC_NONLIVEREFERENCES);
2198 // Iterate over the map space, setting map transitions that go from 2255 // Iterate over the map space, setting map transitions that go from
2199 // a marked map to an unmarked map to null transitions. This action 2256 // a marked map to an unmarked map to null transitions. This action
2200 // is carried out only on maps of JSObjects and related subtypes. 2257 // is carried out only on maps of JSObjects and related subtypes.
2201 HeapObjectIterator map_iterator(heap()->map_space()); 2258 HeapObjectIterator map_iterator(heap()->map_space());
2202 for (HeapObject* obj = map_iterator.Next(); obj != NULL; 2259 for (HeapObject* obj = map_iterator.Next(); obj != NULL;
2203 obj = map_iterator.Next()) { 2260 obj = map_iterator.Next()) {
2204 Map* map = Map::cast(obj); 2261 Map* map = Map::cast(obj);
2205 if (!map->CanTransition()) continue; 2262 if (!map->CanTransition()) continue;
2206 MarkBit map_mark = Marking::MarkBitFrom(map); 2263 MarkBit map_mark = Marking::MarkBitFrom(map);
2207 bool alive = Marking::IsBlackOrGrey(map_mark); 2264 bool alive = Marking::IsBlackOrGrey(map_mark);
2208 if (alive) { 2265 if (alive) {
2209 ClearNonLivePrototypeTransitions(map); 2266 ClearNonLivePrototypeTransitions(map);
2210 } else { 2267 } else {
2211 ClearNonLiveMapTransitions(map); 2268 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 } 2269 }
2217 } 2270 }
2218 2271
2219 WeakHashTable* table = heap_->weak_object_to_code_table(); 2272 WeakHashTable* table = heap_->weak_object_to_code_table();
2220 uint32_t capacity = table->Capacity(); 2273 uint32_t capacity = table->Capacity();
2221 for (uint32_t i = 0; i < capacity; i++) { 2274 for (uint32_t i = 0; i < capacity; i++) {
2222 uint32_t key_index = table->EntryToIndex(i); 2275 uint32_t key_index = table->EntryToIndex(i);
2223 Object* key = table->get(key_index); 2276 Object* key = table->get(key_index);
2224 if (!table->IsKey(key)) continue; 2277 if (!table->IsKey(key)) continue;
2225 uint32_t value_index = table->EntryToValueIndex(i); 2278 uint32_t value_index = table->EntryToValueIndex(i);
2226 Object* value = table->get(value_index); 2279 Object* value = table->get(value_index);
2227 DCHECK(key->IsWeakCell()); 2280 DCHECK(key->IsWeakCell());
2228 if (WeakCell::cast(key)->cleared()) { 2281 if (WeakCell::cast(key)->cleared()) {
2229 have_code_to_deoptimize_ |= 2282 have_code_to_deoptimize_ |=
2230 DependentCode::cast(value)->MarkCodeForDeoptimization( 2283 DependentCode::cast(value)->MarkCodeForDeoptimization(
2231 isolate(), DependentCode::kWeakCodeGroup); 2284 isolate(), DependentCode::kWeakCodeGroup);
2232 table->set(key_index, heap_->the_hole_value()); 2285 table->set(key_index, heap_->the_hole_value());
2233 table->set(value_index, heap_->the_hole_value()); 2286 table->set(value_index, heap_->the_hole_value());
2234 table->ElementRemoved(); 2287 table->ElementRemoved();
2235 } 2288 }
2236 } 2289 }
2237 } 2290 }
2238 2291
2239 2292
2293 void MarkCompactCollector::MarkDependentCodeListForDeoptimization(
2294 DependentCode* list_head) {
2295 GCTracer::Scope gc_scope(heap()->tracer(),
2296 GCTracer::Scope::MC_DEOPT_DEPENDENT_CODE);
2297 Isolate* isolate = this->isolate();
2298 DependentCode* current = list_head;
2299 while (current->length() > 0) {
2300 have_code_to_deoptimize_ |= current->MarkCodeForDeoptimization(
2301 isolate, DependentCode::kWeakCodeGroup);
2302 current = current->next_link();
2303 }
2304 }
2305
2306
2240 void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) { 2307 void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) {
2241 FixedArray* prototype_transitions = 2308 FixedArray* prototype_transitions =
2242 TransitionArray::GetPrototypeTransitions(map); 2309 TransitionArray::GetPrototypeTransitions(map);
2243 int number_of_transitions = 2310 int number_of_transitions =
2244 TransitionArray::NumberOfPrototypeTransitions(prototype_transitions); 2311 TransitionArray::NumberOfPrototypeTransitions(prototype_transitions);
2245 2312
2246 const int header = TransitionArray::kProtoTransitionHeaderSize; 2313 const int header = TransitionArray::kProtoTransitionHeaderSize;
2247 int new_number_of_transitions = 0; 2314 int new_number_of_transitions = 0;
2248 for (int i = 0; i < number_of_transitions; i++) { 2315 for (int i = 0; i < number_of_transitions; i++) {
2249 Object* cell = prototype_transitions->get(header + i); 2316 Object* cell = prototype_transitions->get(header + i);
(...skipping 2237 matching lines...) Expand 10 before | Expand all | Expand 10 after
4487 MarkBit mark_bit = Marking::MarkBitFrom(host); 4554 MarkBit mark_bit = Marking::MarkBitFrom(host);
4488 if (Marking::IsBlack(mark_bit)) { 4555 if (Marking::IsBlack(mark_bit)) {
4489 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host); 4556 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host);
4490 RecordRelocSlot(&rinfo, target); 4557 RecordRelocSlot(&rinfo, target);
4491 } 4558 }
4492 } 4559 }
4493 } 4560 }
4494 4561
4495 } // namespace internal 4562 } // namespace internal
4496 } // namespace v8 4563 } // namespace v8
OLDNEW
« no previous file with comments | « src/heap/mark-compact.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698