Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2011 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 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 50 const char* Marking::kImpossibleBitPattern = "01"; | 50 const char* Marking::kImpossibleBitPattern = "01"; |
| 51 | 51 |
| 52 | 52 |
| 53 // ------------------------------------------------------------------------- | 53 // ------------------------------------------------------------------------- |
| 54 // MarkCompactCollector | 54 // MarkCompactCollector |
| 55 | 55 |
| 56 MarkCompactCollector::MarkCompactCollector() : // NOLINT | 56 MarkCompactCollector::MarkCompactCollector() : // NOLINT |
| 57 #ifdef DEBUG | 57 #ifdef DEBUG |
| 58 state_(IDLE), | 58 state_(IDLE), |
| 59 #endif | 59 #endif |
| 60 sweep_precisely_(false), | |
| 61 compacting_(false), | |
| 60 tracer_(NULL), | 62 tracer_(NULL), |
| 61 #ifdef DEBUG | 63 #ifdef DEBUG |
| 62 live_young_objects_size_(0), | 64 live_young_objects_size_(0), |
| 63 live_old_pointer_objects_size_(0), | 65 live_old_pointer_objects_size_(0), |
| 64 live_old_data_objects_size_(0), | 66 live_old_data_objects_size_(0), |
| 65 live_code_objects_size_(0), | 67 live_code_objects_size_(0), |
| 66 live_map_objects_size_(0), | 68 live_map_objects_size_(0), |
| 67 live_cell_objects_size_(0), | 69 live_cell_objects_size_(0), |
| 68 live_lo_objects_size_(0), | 70 live_lo_objects_size_(0), |
| 69 live_bytes_(0), | 71 live_bytes_(0), |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 147 } | 149 } |
| 148 | 150 |
| 149 | 151 |
| 150 class VerifyEvacuationVisitor: public ObjectVisitor { | 152 class VerifyEvacuationVisitor: public ObjectVisitor { |
| 151 public: | 153 public: |
| 152 void VisitPointers(Object** start, Object** end) { | 154 void VisitPointers(Object** start, Object** end) { |
| 153 for (Object** current = start; current < end; current++) { | 155 for (Object** current = start; current < end; current++) { |
| 154 if ((*current)->IsHeapObject()) { | 156 if ((*current)->IsHeapObject()) { |
| 155 HeapObject* object = HeapObject::cast(*current); | 157 HeapObject* object = HeapObject::cast(*current); |
| 156 if (MarkCompactCollector::IsOnEvacuationCandidate(object)) { | 158 if (MarkCompactCollector::IsOnEvacuationCandidate(object)) { |
| 157 HEAP->TracePathToObject(source_); | |
| 158 CHECK(false); | 159 CHECK(false); |
| 159 } | 160 } |
| 160 } | 161 } |
| 161 } | 162 } |
| 162 } | 163 } |
| 163 | 164 |
| 164 HeapObject* source_; | 165 HeapObject* source_; |
| 165 }; | 166 }; |
| 166 | 167 |
| 167 | 168 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 218 } | 219 } |
| 219 #endif | 220 #endif |
| 220 | 221 |
| 221 | 222 |
| 222 void MarkCompactCollector::AddEvacuationCandidate(Page* p) { | 223 void MarkCompactCollector::AddEvacuationCandidate(Page* p) { |
| 223 p->MarkEvacuationCandidate(); | 224 p->MarkEvacuationCandidate(); |
| 224 evacuation_candidates_.Add(p); | 225 evacuation_candidates_.Add(p); |
| 225 } | 226 } |
| 226 | 227 |
| 227 | 228 |
| 229 bool MarkCompactCollector::StartCompaction() { | |
| 230 // Don't start compaction if we are in the middle of incremental | |
| 231 // marking cycle. We did not collect any slots. | |
| 232 if (!compacting_ && !heap_->incremental_marking()->IsMarking()) { | |
| 233 slots_buffer_.Clear(); | |
| 234 evacuation_candidates_.Rewind(0); | |
| 235 | |
| 236 CollectEvacuationCandidates(heap()->old_pointer_space()); | |
| 237 CollectEvacuationCandidates(heap()->old_data_space()); | |
| 238 | |
| 239 heap()->old_pointer_space()->EvictEvacuationCandidatesFromFreeLists(); | |
| 240 heap()->old_data_space()->EvictEvacuationCandidatesFromFreeLists(); | |
| 241 | |
| 242 compacting_ = evacuation_candidates_.length() > 0; | |
| 243 } | |
| 244 | |
| 245 return compacting_; | |
| 246 } | |
| 247 | |
| 248 | |
| 228 void MarkCompactCollector::CollectGarbage() { | 249 void MarkCompactCollector::CollectGarbage() { |
| 229 // Make sure that Prepare() has been called. The individual steps below will | 250 // Make sure that Prepare() has been called. The individual steps below will |
| 230 // update the state as they proceed. | 251 // update the state as they proceed. |
| 231 ASSERT(state_ == PREPARE_GC); | 252 ASSERT(state_ == PREPARE_GC); |
| 232 | 253 |
| 233 MarkLiveObjects(); | 254 MarkLiveObjects(); |
| 234 ASSERT(heap_->incremental_marking()->IsStopped()); | 255 ASSERT(heap_->incremental_marking()->IsStopped()); |
| 235 | 256 |
| 236 if (FLAG_collect_maps) ClearNonLiveTransitions(); | 257 if (FLAG_collect_maps) ClearNonLiveTransitions(); |
| 237 | 258 |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 363 Page* p = it.next(); | 384 Page* p = it.next(); |
| 364 if (space->IsFragmented(p)) { | 385 if (space->IsFragmented(p)) { |
| 365 AddEvacuationCandidate(p); | 386 AddEvacuationCandidate(p); |
| 366 } else { | 387 } else { |
| 367 p->ClearEvacuationCandidate(); | 388 p->ClearEvacuationCandidate(); |
| 368 } | 389 } |
| 369 } | 390 } |
| 370 } | 391 } |
| 371 | 392 |
| 372 | 393 |
| 394 #if 0 | |
| 373 static void ClearEvacuationCandidates(PagedSpace* space) { | 395 static void ClearEvacuationCandidates(PagedSpace* space) { |
|
Erik Corry
2011/07/04 11:04:11
Commented code
Vyacheslav Egorov (Chromium)
2011/08/05 12:50:28
Done.
| |
| 374 ASSERT(space->identity() == OLD_POINTER_SPACE || | 396 ASSERT(space->identity() == OLD_POINTER_SPACE || |
| 375 space->identity() == OLD_DATA_SPACE); | 397 space->identity() == OLD_DATA_SPACE); |
| 376 | 398 |
| 377 PageIterator it(space); | 399 PageIterator it(space); |
| 378 while (it.has_next()) { | 400 while (it.has_next()) { |
| 379 Page* p = it.next(); | 401 Page* p = it.next(); |
| 380 p->ClearEvacuationCandidate(); | 402 p->ClearEvacuationCandidate(); |
| 381 } | 403 } |
| 382 } | 404 } |
| 405 #endif | |
| 383 | 406 |
| 384 | 407 |
| 385 void MarkCompactCollector::Prepare(GCTracer* tracer) { | 408 void MarkCompactCollector::Prepare(GCTracer* tracer) { |
| 386 // TODO(gc) re-enable code flushing. | 409 // TODO(gc) re-enable code flushing. |
| 387 FLAG_flush_code = false; | 410 FLAG_flush_code = false; |
| 388 FLAG_always_compact = false; | 411 FLAG_always_compact = false; |
| 389 | 412 |
| 390 // Disable collection of maps if incremental marking is enabled. | 413 // Disable collection of maps if incremental marking is enabled. |
| 391 // TODO(gc) improve maps collection algorithm to work with incremental | 414 // TODO(gc) improve maps collection algorithm to work with incremental |
| 392 // marking. | 415 // marking. |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 403 ASSERT(!FLAG_always_compact || !FLAG_never_compact); | 426 ASSERT(!FLAG_always_compact || !FLAG_never_compact); |
| 404 | 427 |
| 405 if (FLAG_collect_maps) CreateBackPointers(); | 428 if (FLAG_collect_maps) CreateBackPointers(); |
| 406 #ifdef ENABLE_GDB_JIT_INTERFACE | 429 #ifdef ENABLE_GDB_JIT_INTERFACE |
| 407 if (FLAG_gdbjit) { | 430 if (FLAG_gdbjit) { |
| 408 // If GDBJIT interface is active disable compaction. | 431 // If GDBJIT interface is active disable compaction. |
| 409 compacting_collection_ = false; | 432 compacting_collection_ = false; |
| 410 } | 433 } |
| 411 #endif | 434 #endif |
| 412 | 435 |
| 413 if (!FLAG_never_compact) { | 436 if (!FLAG_never_compact) StartCompaction(); |
| 414 slots_buffer_.Clear(); | |
| 415 evacuation_candidates_.Rewind(0); | |
| 416 | |
| 417 if (!heap()->incremental_marking()->IsMarking()) { | |
| 418 CollectEvacuationCandidates(heap()->old_pointer_space()); | |
| 419 CollectEvacuationCandidates(heap()->old_data_space()); | |
| 420 } else { | |
| 421 ClearEvacuationCandidates(heap()->old_pointer_space()); | |
| 422 ClearEvacuationCandidates(heap()->old_data_space()); | |
| 423 } | |
| 424 } | |
| 425 | 437 |
| 426 PagedSpaces spaces; | 438 PagedSpaces spaces; |
| 427 for (PagedSpace* space = spaces.next(); | 439 for (PagedSpace* space = spaces.next(); |
| 428 space != NULL; | 440 space != NULL; |
| 429 space = spaces.next()) { | 441 space = spaces.next()) { |
| 430 space->PrepareForMarkCompact(); | 442 space->PrepareForMarkCompact(); |
| 431 } | 443 } |
| 432 | 444 |
| 433 if (!heap()->incremental_marking()->IsMarking()) { | 445 if (!heap()->incremental_marking()->IsMarking()) { |
| 434 ClearMarkbits(heap_); | 446 ClearMarkbits(heap_); |
| (...skipping 1872 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2307 | 2319 |
| 2308 void MarkCompactCollector::EvacuatePages() { | 2320 void MarkCompactCollector::EvacuatePages() { |
| 2309 int npages = evacuation_candidates_.length(); | 2321 int npages = evacuation_candidates_.length(); |
| 2310 for (int i = 0; i < npages; i++) { | 2322 for (int i = 0; i < npages; i++) { |
| 2311 Page* p = evacuation_candidates_[i]; | 2323 Page* p = evacuation_candidates_[i]; |
| 2312 EvacuateLiveObjectsFromPage(p); | 2324 EvacuateLiveObjectsFromPage(p); |
| 2313 } | 2325 } |
| 2314 } | 2326 } |
| 2315 | 2327 |
| 2316 | 2328 |
| 2329 class EvacuationWeakObjectRetainer : public WeakObjectRetainer { | |
| 2330 public: | |
| 2331 virtual Object* RetainAs(Object* object) { | |
| 2332 if (object->IsHeapObject()) { | |
| 2333 HeapObject* heap_object = HeapObject::cast(object); | |
| 2334 MapWord map_word = heap_object->map_word(); | |
| 2335 if (map_word.IsForwardingAddress()) { | |
| 2336 return map_word.ToForwardingAddress(); | |
| 2337 } | |
| 2338 } | |
| 2339 return object; | |
| 2340 } | |
| 2341 }; | |
| 2342 | |
| 2343 | |
| 2317 void MarkCompactCollector::EvacuateNewSpaceAndCandidates() { | 2344 void MarkCompactCollector::EvacuateNewSpaceAndCandidates() { |
| 2318 EvacuateNewSpace(); | 2345 EvacuateNewSpace(); |
| 2319 EvacuatePages(); | 2346 EvacuatePages(); |
| 2320 | 2347 |
| 2321 // Second pass: find pointers to new space and update them. | 2348 // Second pass: find pointers to new space and update them. |
| 2322 PointersUpdatingVisitor updating_visitor(heap()); | 2349 PointersUpdatingVisitor updating_visitor(heap()); |
| 2323 | 2350 |
| 2324 // Update pointers in to space. | 2351 // Update pointers in to space. |
| 2325 SemiSpaceIterator to_it(heap()->new_space()->bottom(), | 2352 SemiSpaceIterator to_it(heap()->new_space()->bottom(), |
| 2326 heap()->new_space()->top()); | 2353 heap()->new_space()->top()); |
| 2327 for (HeapObject* object = to_it.Next(); | 2354 for (HeapObject* object = to_it.Next(); |
| 2328 object != NULL; | 2355 object != NULL; |
| 2329 object = to_it.Next()) { | 2356 object = to_it.Next()) { |
| 2330 Map* map = object->map(); | 2357 Map* map = object->map(); |
| 2331 object->IterateBody(map->instance_type(), | 2358 object->IterateBody(map->instance_type(), |
| 2332 object->SizeFromMap(map), | 2359 object->SizeFromMap(map), |
| 2333 &updating_visitor); | 2360 &updating_visitor); |
| 2334 } | 2361 } |
| 2335 | 2362 |
| 2336 // Update roots. | 2363 // Update roots. |
| 2337 heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE); | 2364 heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE); |
| 2338 LiveObjectList::IterateElements(&updating_visitor); | 2365 LiveObjectList::IterateElements(&updating_visitor); |
| 2339 | 2366 |
| 2340 { | 2367 { |
| 2341 StoreBufferRebuildScope scope(heap_, | 2368 StoreBufferRebuildScope scope(heap_, |
| 2342 heap_->store_buffer(), | 2369 heap_->store_buffer(), |
| 2343 &Heap::ScavengeStoreBufferCallback); | 2370 &Heap::ScavengeStoreBufferCallback); |
| 2344 heap_->store_buffer()->IteratePointersToNewSpace(&UpdatePointer); | 2371 heap_->store_buffer()->IteratePointersToNewSpace(&UpdatePointer); |
| 2345 } | 2372 } |
| 2346 slots_buffer_.Iterate(&updating_visitor); | 2373 slots_buffer_.Update(); |
| 2347 | 2374 |
| 2348 // Update pointers from cells. | 2375 // Update pointers from cells. |
| 2349 HeapObjectIterator cell_iterator(heap_->cell_space()); | 2376 HeapObjectIterator cell_iterator(heap_->cell_space()); |
| 2350 for (HeapObject* cell = cell_iterator.Next(); | 2377 for (HeapObject* cell = cell_iterator.Next(); |
| 2351 cell != NULL; | 2378 cell != NULL; |
| 2352 cell = cell_iterator.Next()) { | 2379 cell = cell_iterator.Next()) { |
| 2353 if (cell->IsJSGlobalPropertyCell()) { | 2380 if (cell->IsJSGlobalPropertyCell()) { |
| 2354 Address value_address = | 2381 Address value_address = |
| 2355 reinterpret_cast<Address>(cell) + | 2382 reinterpret_cast<Address>(cell) + |
| 2356 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag); | 2383 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag); |
| 2357 updating_visitor.VisitPointer(reinterpret_cast<Object**>(value_address)); | 2384 updating_visitor.VisitPointer(reinterpret_cast<Object**>(value_address)); |
| 2358 } | 2385 } |
| 2359 } | 2386 } |
| 2360 | 2387 |
| 2361 // Update pointer from the global contexts list. | 2388 // Update pointer from the global contexts list. |
| 2362 updating_visitor.VisitPointer(heap_->global_contexts_list_address()); | 2389 updating_visitor.VisitPointer(heap_->global_contexts_list_address()); |
| 2363 | 2390 |
| 2364 heap_->symbol_table()->Iterate(&updating_visitor); | 2391 heap_->symbol_table()->Iterate(&updating_visitor); |
| 2365 | 2392 |
| 2366 // Update pointers from external string table. | 2393 // Update pointers from external string table. |
| 2367 heap_->UpdateReferencesInExternalStringTable( | 2394 heap_->UpdateReferencesInExternalStringTable( |
| 2368 &UpdateReferenceInExternalStringTableEntry); | 2395 &UpdateReferenceInExternalStringTableEntry); |
| 2369 | 2396 |
| 2370 // Update JSFunction pointers from the runtime profiler. | 2397 // Update JSFunction pointers from the runtime profiler. |
| 2371 heap_->isolate()->runtime_profiler()->UpdateSamplesAfterScavenge(); | 2398 heap_->isolate()->runtime_profiler()->UpdateSamplesAfterScavenge(); |
| 2372 | 2399 |
| 2400 EvacuationWeakObjectRetainer evacuation_object_retainer; | |
| 2401 heap()->ProcessWeakReferences(&evacuation_object_retainer); | |
| 2402 | |
| 2373 #ifdef DEBUG | 2403 #ifdef DEBUG |
| 2374 if (FLAG_verify_heap) { | 2404 if (FLAG_verify_heap) { |
| 2375 VerifyEvacuation(heap_); | 2405 VerifyEvacuation(heap_); |
| 2376 } | 2406 } |
| 2377 #endif | 2407 #endif |
| 2378 | 2408 |
| 2379 int npages = evacuation_candidates_.length(); | 2409 int npages = evacuation_candidates_.length(); |
| 2410 ASSERT(compacting_ == (npages > 0)); | |
| 2380 for (int i = 0; i < npages; i++) { | 2411 for (int i = 0; i < npages; i++) { |
| 2381 Page* p = evacuation_candidates_[i]; | 2412 Page* p = evacuation_candidates_[i]; |
| 2382 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); | 2413 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); |
| 2383 space->Free(p->ObjectAreaStart(), Page::kObjectAreaSize); | 2414 space->Free(p->ObjectAreaStart(), Page::kObjectAreaSize); |
| 2384 p->set_scan_on_scavenge(false); | 2415 p->set_scan_on_scavenge(false); |
| 2385 | 2416 p->ClearEvacuationCandidate(); |
| 2386 // We are not clearing evacuation candidate flag here | 2417 p->SetFlag(MemoryChunk::EVACUATED); |
| 2387 // because it is required to notify lazy sweeper to skip | 2418 p->ClearFlag(MemoryChunk::WAS_SWEPT_CONSERVATIVELY); |
| 2388 // these pages. | |
| 2389 } | 2419 } |
| 2420 compacting_ = false; | |
| 2390 } | 2421 } |
| 2391 | 2422 |
| 2392 | 2423 |
| 2393 INLINE(static uint32_t SweepFree(PagedSpace* space, | 2424 INLINE(static uint32_t SweepFree(PagedSpace* space, |
| 2394 Page* p, | 2425 Page* p, |
| 2395 uint32_t free_start, | 2426 uint32_t free_start, |
| 2396 uint32_t region_end, | 2427 uint32_t region_end, |
| 2397 uint32_t* cells)); | 2428 uint32_t* cells)); |
| 2398 | 2429 |
| 2399 | 2430 |
| (...skipping 651 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3051 if (buffer_idx_ == buffers_.length()) { | 3082 if (buffer_idx_ == buffers_.length()) { |
| 3052 buffers_.Add(new ObjectSlot[kBufferSize]); | 3083 buffers_.Add(new ObjectSlot[kBufferSize]); |
| 3053 } | 3084 } |
| 3054 buffer_ = buffers_[buffer_idx_]; | 3085 buffer_ = buffers_[buffer_idx_]; |
| 3055 } | 3086 } |
| 3056 | 3087 |
| 3057 buffer_[idx_++] = slot; | 3088 buffer_[idx_++] = slot; |
| 3058 } | 3089 } |
| 3059 | 3090 |
| 3060 | 3091 |
| 3061 void SlotsBuffer::Iterate(ObjectVisitor* visitor) { | 3092 static inline void UpdateSlot(Object** slot) { |
| 3093 Object* obj = *slot; | |
| 3094 if (!obj->IsHeapObject()) return; | |
| 3095 | |
| 3096 HeapObject* heap_obj = HeapObject::cast(obj); | |
| 3097 | |
| 3098 MapWord map_word = heap_obj->map_word(); | |
| 3099 if (map_word.IsForwardingAddress()) { | |
| 3100 ASSERT(MarkCompactCollector::IsOnEvacuationCandidate(*slot)); | |
| 3101 *slot = map_word.ToForwardingAddress(); | |
| 3102 ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(*slot)); | |
| 3103 } | |
| 3104 } | |
| 3105 | |
| 3106 | |
| 3107 void SlotsBuffer::Update() { | |
| 3062 if (buffer_idx_ < 0) return; | 3108 if (buffer_idx_ < 0) return; |
| 3063 | 3109 |
| 3064 for (int buffer_index = 0; buffer_index < buffer_idx_; ++buffer_index) { | 3110 for (int buffer_index = 0; buffer_index < buffer_idx_; ++buffer_index) { |
| 3065 ObjectSlot* buffer = buffers_[buffer_index]; | 3111 ObjectSlot* buffer = buffers_[buffer_index]; |
| 3066 for (int slot_idx = 0; slot_idx < kBufferSize; ++slot_idx) { | 3112 for (int slot_idx = 0; slot_idx < kBufferSize; ++slot_idx) { |
| 3067 visitor->VisitPointer(buffer[slot_idx]); | 3113 UpdateSlot(buffer[slot_idx]); |
| 3068 } | 3114 } |
| 3069 } | 3115 } |
| 3070 | 3116 |
| 3071 ObjectSlot* last_buffer = buffers_[buffer_idx_]; | 3117 ObjectSlot* last_buffer = buffers_[buffer_idx_]; |
| 3072 for (int slot_idx = 0; slot_idx < idx_; ++slot_idx) { | 3118 for (int slot_idx = 0; slot_idx < idx_; ++slot_idx) { |
| 3073 visitor->VisitPointer(last_buffer[slot_idx]); | 3119 UpdateSlot(last_buffer[slot_idx]); |
| 3074 } | 3120 } |
| 3075 } | 3121 } |
| 3076 | 3122 |
| 3077 | 3123 |
| 3078 void SlotsBuffer::Report() { | 3124 void SlotsBuffer::Report() { |
| 3079 } | 3125 } |
| 3080 | 3126 |
| 3081 | 3127 |
| 3082 } } // namespace v8::internal | 3128 } } // namespace v8::internal |
| OLD | NEW |