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 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 99 | 99 |
| 100 | 100 |
| 101 class IncrementalMarkingRootMarkingVisitor : public ObjectVisitor { | 101 class IncrementalMarkingRootMarkingVisitor : public ObjectVisitor { |
| 102 public: | 102 public: |
| 103 IncrementalMarkingRootMarkingVisitor(Heap* heap, | 103 IncrementalMarkingRootMarkingVisitor(Heap* heap, |
| 104 IncrementalMarking* incremental_marking) | 104 IncrementalMarking* incremental_marking) |
| 105 : heap_(heap), | 105 : heap_(heap), |
| 106 incremental_marking_(incremental_marking) { | 106 incremental_marking_(incremental_marking) { |
| 107 } | 107 } |
| 108 | 108 |
| 109 | |
| 110 void VisitPointer(Object** p) { | 109 void VisitPointer(Object** p) { |
| 111 MarkObjectByPointer(p); | 110 MarkObjectByPointer(p); |
| 112 } | 111 } |
| 113 | 112 |
| 114 void VisitPointers(Object** start, Object** end) { | 113 void VisitPointers(Object** start, Object** end) { |
| 115 for (Object** p = start; p < end; p++) MarkObjectByPointer(p); | 114 for (Object** p = start; p < end; p++) MarkObjectByPointer(p); |
| 116 } | 115 } |
| 117 | 116 |
| 118 private: | 117 private: |
| 119 void MarkObjectByPointer(Object** p) { | 118 void MarkObjectByPointer(Object** p) { |
| 120 Object* obj = *p; | 119 Object* obj = *p; |
| 121 if (!obj->IsHeapObject()) return; | 120 if (!obj->IsHeapObject()) return; |
| 122 | 121 |
| 123 HeapObject* heap_object = HeapObject::cast(obj); | 122 HeapObject* heap_object = HeapObject::cast(obj); |
| 124 MarkBit mark_bit = heap_->marking()->MarkBitFrom(heap_object); | 123 MarkBit mark_bit = heap_->marking()->MarkBitFrom(heap_object); |
| 125 if (mark_bit.data_only()) { | 124 if (mark_bit.data_only()) { |
| 126 incremental_marking_->MarkBlackOrKeepGrey(mark_bit); | 125 incremental_marking_->MarkBlackOrKeepGrey(mark_bit); |
| 127 } else { | 126 } else { |
| 128 if (IncrementalMarking::IsWhite(mark_bit)) { | 127 if (IncrementalMarking::IsWhite(mark_bit)) { |
| 129 incremental_marking_->WhiteToGreyAndPush(heap_object, mark_bit); | 128 incremental_marking_->WhiteToGreyAndPush(heap_object, mark_bit); |
| 130 } | 129 } |
| 131 } | 130 } |
| 132 } | 131 } |
| 133 | 132 |
| 134 Heap* heap_; | 133 Heap* heap_; |
| 135 IncrementalMarking* incremental_marking_; | 134 IncrementalMarking* incremental_marking_; |
| 136 }; | 135 }; |
| 137 | 136 |
| 138 | 137 |
| 139 static void ClearMarkbits(PagedSpace* space) { | 138 void IncrementalMarking::ClearMarkbits(PagedSpace* space) { |
| 140 PageIterator it(space); | 139 PageIterator it(space); |
| 141 | 140 |
| 142 while (it.has_next()) { | 141 while (it.has_next()) { |
| 143 Page* p = it.next(); | 142 Page* p = it.next(); |
| 144 p->markbits()->Clear(); | 143 p->markbits()->Clear(); |
| 145 } | 144 } |
| 146 } | 145 } |
| 147 | 146 |
| 148 | 147 |
| 149 static void ClearMarkbits() { | 148 void IncrementalMarking::ClearMarkbits() { |
| 150 // TODO(gc): Clear the mark bits in the sweeper. | 149 // TODO(gc): Clear the mark bits in the sweeper. |
| 151 // TODO(gc) ISOLATES MERGE | 150 ClearMarkbits(heap_->old_pointer_space()); |
| 152 ClearMarkbits(HEAP->old_pointer_space()); | 151 ClearMarkbits(heap_->old_data_space()); |
| 153 ClearMarkbits(HEAP->old_data_space()); | 152 ClearMarkbits(heap_->cell_space()); |
| 154 ClearMarkbits(HEAP->cell_space()); | 153 ClearMarkbits(heap_->map_space()); |
| 155 ClearMarkbits(HEAP->map_space()); | 154 ClearMarkbits(heap_->code_space()); |
|
Erik Corry
2011/05/09 21:20:11
Who clears the mark bits in the large object space
| |
| 156 ClearMarkbits(HEAP->code_space()); | |
| 157 } | 155 } |
| 158 | 156 |
| 159 | 157 |
| 160 #ifdef DEBUG | 158 #ifdef DEBUG |
| 161 static void VerifyMarkbitsAreClean(PagedSpace* space) { | 159 void IncrementalMarking::VerifyMarkbitsAreClean(PagedSpace* space) { |
| 162 PageIterator it(space); | 160 PageIterator it(space); |
| 163 | 161 |
| 164 while (it.has_next()) { | 162 while (it.has_next()) { |
| 165 Page* p = it.next(); | 163 Page* p = it.next(); |
| 166 ASSERT(p->markbits()->IsClean()); | 164 ASSERT(p->markbits()->IsClean()); |
| 167 } | |
| 168 } | 165 } |
| 166 } | |
| 169 | 167 |
| 170 static void VerifyMarkbitsAreClean() { | 168 |
| 171 // TODO(gc) ISOLATES MERGE | 169 void IncrementalMarking::VerifyMarkbitsAreClean() { |
| 172 VerifyMarkbitsAreClean(HEAP->old_pointer_space()); | 170 VerifyMarkbitsAreClean(heap_->old_pointer_space()); |
| 173 VerifyMarkbitsAreClean(HEAP->old_data_space()); | 171 VerifyMarkbitsAreClean(heap_->old_data_space()); |
| 174 VerifyMarkbitsAreClean(HEAP->code_space()); | 172 VerifyMarkbitsAreClean(heap_->code_space()); |
| 175 VerifyMarkbitsAreClean(HEAP->cell_space()); | 173 VerifyMarkbitsAreClean(heap_->cell_space()); |
| 176 VerifyMarkbitsAreClean(HEAP->map_space()); | 174 VerifyMarkbitsAreClean(heap_->map_space()); |
| 177 } | 175 } |
| 178 #endif | 176 #endif |
| 179 | 177 |
| 178 | |
| 180 bool IncrementalMarking::WorthActivating() { | 179 bool IncrementalMarking::WorthActivating() { |
| 181 #ifndef DEBUG | 180 #ifndef DEBUG |
| 182 static const intptr_t kActivationThreshold = 8 * MB; | 181 static const intptr_t kActivationThreshold = 8 * MB; |
| 183 #else | 182 #else |
| 184 // TODO(gc) consider setting this to some low level so that some | 183 // TODO(gc) consider setting this to some low level so that some |
| 185 // debug tests run with incremental marking and some without. | 184 // debug tests run with incremental marking and some without. |
| 186 static const intptr_t kActivationThreshold = 0; | 185 static const intptr_t kActivationThreshold = 0; |
| 187 #endif | 186 #endif |
| 188 | 187 |
| 189 // TODO(gc) ISOLATES MERGE | 188 // TODO(gc) ISOLATES MERGE |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 205 CodeStub::RecordWrite) { | 204 CodeStub::RecordWrite) { |
| 206 Object* e = stubs->ValueAt(i); | 205 Object* e = stubs->ValueAt(i); |
| 207 if (e->IsCode()) { | 206 if (e->IsCode()) { |
| 208 RecordWriteStub::Patch(Code::cast(e), enable); | 207 RecordWriteStub::Patch(Code::cast(e), enable); |
| 209 } | 208 } |
| 210 } | 209 } |
| 211 } | 210 } |
| 212 } | 211 } |
| 213 } | 212 } |
| 214 | 213 |
| 214 | |
| 215 static VirtualMemory* marking_deque_memory = NULL; | 215 static VirtualMemory* marking_deque_memory = NULL; |
| 216 | 216 |
| 217 | |
| 217 static void EnsureMarkingDequeIsCommitted() { | 218 static void EnsureMarkingDequeIsCommitted() { |
| 218 if (marking_deque_memory == NULL) { | 219 if (marking_deque_memory == NULL) { |
| 219 marking_deque_memory = new VirtualMemory(4*MB); | 220 marking_deque_memory = new VirtualMemory(4*MB); |
| 220 marking_deque_memory->Commit( | 221 marking_deque_memory->Commit( |
| 221 reinterpret_cast<Address>(marking_deque_memory->address()), | 222 reinterpret_cast<Address>(marking_deque_memory->address()), |
| 222 marking_deque_memory->size(), | 223 marking_deque_memory->size(), |
| 223 false); // Not executable. | 224 false); // Not executable. |
| 224 } | 225 } |
| 225 } | 226 } |
| 226 | 227 |
| 227 | 228 |
| 228 void IncrementalMarking::Start() { | 229 void IncrementalMarking::Start() { |
| 229 if (FLAG_trace_incremental_marking) { | 230 if (FLAG_trace_incremental_marking) { |
| 230 PrintF("[IncrementalMarking] Start\n"); | 231 PrintF("[IncrementalMarking] Start\n"); |
| 231 } | 232 } |
| 232 ASSERT(FLAG_incremental_marking); | 233 ASSERT(FLAG_incremental_marking); |
| 233 ASSERT(state_ == STOPPED); | 234 ASSERT(state_ == STOPPED); |
| 234 state_ = MARKING; | |
| 235 | 235 |
| 236 ResetStepCounters(); | 236 ResetStepCounters(); |
| 237 | 237 |
| 238 if (heap_->old_pointer_space()->IsSweepingComplete() && | |
| 239 heap_->old_data_space()->IsSweepingComplete()) { | |
| 240 StartMarking(); | |
| 241 } else { | |
| 242 PrintF("[IncrementalMarking] Start sweeping.\n"); | |
|
antonm
2011/05/10 13:09:38
if (FLAG_trace_incremental_marking)?
| |
| 243 state_ = SWEEPING; | |
| 244 } | |
| 245 } | |
| 246 | |
| 247 | |
| 248 void IncrementalMarking::StartMarking() { | |
| 249 if (FLAG_trace_incremental_marking) { | |
| 250 PrintF("[IncrementalMarking] Start marking\n"); | |
| 251 } | |
| 252 | |
| 253 state_ = MARKING; | |
| 254 | |
| 238 PatchIncrementalMarkingRecordWriteStubs(true); | 255 PatchIncrementalMarkingRecordWriteStubs(true); |
| 239 | 256 |
| 240 EnsureMarkingDequeIsCommitted(); | 257 EnsureMarkingDequeIsCommitted(); |
| 241 | 258 |
| 242 // Initialize marking stack. | 259 // Initialize marking stack. |
| 243 Address addr = static_cast<Address>(marking_deque_memory->address()); | 260 Address addr = static_cast<Address>(marking_deque_memory->address()); |
| 244 marking_deque_.Initialize(addr, | 261 marking_deque_.Initialize(addr, |
| 245 addr + marking_deque_memory->size()); | 262 addr + marking_deque_memory->size()); |
| 246 | 263 |
| 247 // Clear markbits. | 264 // Clear markbits. |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 334 state_ = COMPLETE; | 351 state_ = COMPLETE; |
| 335 if (FLAG_trace_incremental_marking) { | 352 if (FLAG_trace_incremental_marking) { |
| 336 double end = OS::TimeCurrentMillis(); | 353 double end = OS::TimeCurrentMillis(); |
| 337 PrintF("[IncrementalMarking] Complete (hurry), spent %d ms.\n", | 354 PrintF("[IncrementalMarking] Complete (hurry), spent %d ms.\n", |
| 338 static_cast<int>(end - start)); | 355 static_cast<int>(end - start)); |
| 339 } | 356 } |
| 340 } | 357 } |
| 341 } | 358 } |
| 342 | 359 |
| 343 | 360 |
| 361 void IncrementalMarking::Abort() { | |
| 362 if (IsStopped()) return; | |
| 363 heap_->new_space()->LowerInlineAllocationLimit(0); | |
| 364 IncrementalMarking::set_should_hurry(false); | |
| 365 ResetStepCounters(); | |
| 366 if (IsMarking()) PatchIncrementalMarkingRecordWriteStubs(false); | |
| 367 heap_->isolate()->stack_guard()->Continue(GC_REQUEST); | |
| 368 state_ = STOPPED; | |
| 369 } | |
| 370 | |
| 371 | |
| 344 void IncrementalMarking::Finalize() { | 372 void IncrementalMarking::Finalize() { |
| 345 Hurry(); | 373 Hurry(); |
| 346 state_ = STOPPED; | 374 state_ = STOPPED; |
| 347 heap_->new_space()->LowerInlineAllocationLimit(0); | 375 heap_->new_space()->LowerInlineAllocationLimit(0); |
| 348 IncrementalMarking::set_should_hurry(false); | 376 IncrementalMarking::set_should_hurry(false); |
| 349 ResetStepCounters(); | 377 ResetStepCounters(); |
| 350 PatchIncrementalMarkingRecordWriteStubs(false); | 378 PatchIncrementalMarkingRecordWriteStubs(false); |
| 351 ASSERT(marking_deque_.IsEmpty()); | 379 ASSERT(marking_deque_.IsEmpty()); |
| 352 ISOLATE->stack_guard()->Continue(GC_REQUEST); | 380 heap_->isolate()->stack_guard()->Continue(GC_REQUEST); |
| 353 } | 381 } |
| 354 | 382 |
| 355 | 383 |
| 356 void IncrementalMarking::MarkingComplete() { | 384 void IncrementalMarking::MarkingComplete() { |
| 357 state_ = COMPLETE; | 385 state_ = COMPLETE; |
| 358 // We will set the stack guard to request a GC now. This will mean the rest | 386 // We will set the stack guard to request a GC now. This will mean the rest |
| 359 // of the GC gets performed as soon as possible (we can't do a GC here in a | 387 // of the GC gets performed as soon as possible (we can't do a GC here in a |
| 360 // record-write context). If a few things get allocated between now and then | 388 // record-write context). If a few things get allocated between now and then |
| 361 // that shouldn't make us do a scavenge and keep being incremental, so we set | 389 // that shouldn't make us do a scavenge and keep being incremental, so we set |
| 362 // the should-hurry flag to indicate that there can't be much work left to do. | 390 // the should-hurry flag to indicate that there can't be much work left to do. |
| 363 set_should_hurry(true); | 391 set_should_hurry(true); |
| 364 if (FLAG_trace_incremental_marking) { | 392 if (FLAG_trace_incremental_marking) { |
| 365 PrintF("[IncrementalMarking] Complete (normal).\n"); | 393 PrintF("[IncrementalMarking] Complete (normal).\n"); |
| 366 } | 394 } |
| 367 // TODO(gc) ISOLATES | 395 // TODO(gc) ISOLATES |
| 368 ISOLATE->stack_guard()->RequestGC(); | 396 ISOLATE->stack_guard()->RequestGC(); |
| 369 } | 397 } |
| 370 | 398 |
| 371 | 399 |
| 372 void IncrementalMarking::Step(intptr_t allocated_bytes) { | 400 void IncrementalMarking::Step(intptr_t allocated_bytes) { |
| 373 if (state_ == MARKING && | 401 if (heap_->gc_state() != Heap::NOT_IN_GC) return; |
| 374 heap_->gc_state() == Heap::NOT_IN_GC && | 402 if (!FLAG_incremental_marking_steps) return; |
| 375 FLAG_incremental_marking_steps) { | |
| 376 allocated_ += allocated_bytes; | |
| 377 | 403 |
| 378 if (allocated_ >= kAllocatedThreshold) { | 404 allocated_ += allocated_bytes; |
| 379 double start = 0; | |
| 380 | 405 |
| 381 if (FLAG_trace_incremental_marking || FLAG_trace_gc) { | 406 if (allocated_ < kAllocatedThreshold) return; |
| 382 start = OS::TimeCurrentMillis(); | |
| 383 } | |
| 384 | 407 |
| 385 intptr_t bytes_to_process = allocated_ * allocation_marking_factor_; | 408 intptr_t bytes_to_process = allocated_ * allocation_marking_factor_; |
| 386 int count = 0; | |
| 387 | 409 |
| 388 Map* filler_map = heap_->one_pointer_filler_map(); | 410 double start = 0; |
| 389 IncrementalMarkingMarkingVisitor marking_visitor(heap_, this); | |
| 390 Marking* marking = heap_->marking(); | |
| 391 while (!marking_deque_.IsEmpty() && bytes_to_process > 0) { | |
| 392 HeapObject* obj = marking_deque_.Pop(); | |
| 393 | 411 |
| 394 // Explicitly skip one word fillers. Incremental markbit patterns are | 412 if (FLAG_trace_incremental_marking || FLAG_trace_gc) { |
| 395 // correct only for objects that occupy at least two words. | 413 start = OS::TimeCurrentMillis(); |
| 396 Map* map = obj->map(); | 414 } |
| 397 if (map != filler_map) { | |
| 398 ASSERT(IsGrey(marking->MarkBitFrom(obj))); | |
| 399 int size = obj->SizeFromMap(map); | |
| 400 bytes_to_process -= size; | |
| 401 MarkBit map_mark_bit = marking->MarkBitFromOldSpace(map); | |
| 402 if (IsWhite(map_mark_bit)) WhiteToGreyAndPush(map, map_mark_bit); | |
| 403 // TODO(gc) switch to static visitor instead of normal visitor. | |
| 404 obj->IterateBody(map->instance_type(), size, &marking_visitor); | |
| 405 MarkBit obj_mark_bit = marking->MarkBitFrom(obj); | |
| 406 MarkBlack(obj_mark_bit); | |
| 407 } | |
| 408 count++; | |
| 409 } | |
| 410 allocated_ = 0; | |
| 411 if (marking_deque_.IsEmpty()) MarkingComplete(); | |
| 412 if (FLAG_trace_incremental_marking || FLAG_trace_gc) { | |
| 413 double end = OS::TimeCurrentMillis(); | |
| 414 steps_took_ += (end - start); | |
| 415 } | |
| 416 | 415 |
| 417 steps_count_++; | 416 if (state_ == SWEEPING) { |
| 417 if (heap_->old_pointer_space()->AdvanceSweeper(bytes_to_process) && | |
| 418 heap_->old_data_space()->AdvanceSweeper(bytes_to_process)) { | |
| 419 StartMarking(); | |
| 420 } | |
| 421 } else if (state_ == MARKING) { | |
| 422 Map* filler_map = heap_->one_pointer_filler_map(); | |
| 423 IncrementalMarkingMarkingVisitor marking_visitor(heap_, this); | |
| 424 Marking* marking = heap_->marking(); | |
| 425 while (!marking_deque_.IsEmpty() && bytes_to_process > 0) { | |
| 426 HeapObject* obj = marking_deque_.Pop(); | |
| 418 | 427 |
| 419 if ((steps_count_ % kAllocationMarkingFactorSpeedupInterval) == 0) { | 428 // Explicitly skip one word fillers. Incremental markbit patterns are |
| 420 allocation_marking_factor_ += kAllocationMarkingFactorSpeedup; | 429 // correct only for objects that occupy at least two words. |
| 421 allocation_marking_factor_ *= 1.3; | 430 Map* map = obj->map(); |
| 422 if (FLAG_trace_gc) { | 431 if (map != filler_map) { |
| 423 PrintF("Marking speed increased to %d\n", allocation_marking_factor_); | 432 ASSERT(IsGrey(marking->MarkBitFrom(obj))); |
| 424 } | 433 int size = obj->SizeFromMap(map); |
| 434 bytes_to_process -= size; | |
| 435 MarkBit map_mark_bit = marking->MarkBitFromOldSpace(map); | |
| 436 if (IsWhite(map_mark_bit)) WhiteToGreyAndPush(map, map_mark_bit); | |
| 437 // TODO(gc) switch to static visitor instead of normal visitor. | |
| 438 obj->IterateBody(map->instance_type(), size, &marking_visitor); | |
| 439 MarkBit obj_mark_bit = marking->MarkBitFrom(obj); | |
| 440 MarkBlack(obj_mark_bit); | |
| 425 } | 441 } |
| 426 } | 442 } |
| 443 if (marking_deque_.IsEmpty()) MarkingComplete(); | |
| 444 } | |
| 445 | |
| 446 allocated_ = 0; | |
| 447 | |
| 448 steps_count_++; | |
| 449 | |
| 450 if ((steps_count_ % kAllocationMarkingFactorSpeedupInterval) == 0) { | |
| 451 allocation_marking_factor_ += kAllocationMarkingFactorSpeedup; | |
| 452 allocation_marking_factor_ *= 1.3; | |
| 453 if (FLAG_trace_gc) { | |
| 454 PrintF("Marking speed increased to %d\n", allocation_marking_factor_); | |
| 455 } | |
| 456 } | |
| 457 | |
| 458 if (FLAG_trace_incremental_marking || FLAG_trace_gc) { | |
| 459 double end = OS::TimeCurrentMillis(); | |
| 460 steps_took_ += (end - start); | |
| 427 } | 461 } |
| 428 } | 462 } |
| 429 | 463 |
| 430 | 464 |
| 431 } } // namespace v8::internal | 465 } } // namespace v8::internal |
| OLD | NEW |