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 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 230 | 230 |
| 231 | 231 |
| 232 bool MarkCompactCollector::StartCompaction() { | 232 bool MarkCompactCollector::StartCompaction() { |
| 233 // Don't start compaction if we are in the middle of incremental | 233 // Don't start compaction if we are in the middle of incremental |
| 234 // marking cycle. We did not collect any slots. | 234 // marking cycle. We did not collect any slots. |
| 235 if (!compacting_ && !heap_->incremental_marking()->IsMarking()) { | 235 if (!compacting_ && !heap_->incremental_marking()->IsMarking()) { |
| 236 ASSERT(evacuation_candidates_.length() == 0); | 236 ASSERT(evacuation_candidates_.length() == 0); |
| 237 | 237 |
| 238 CollectEvacuationCandidates(heap()->old_pointer_space()); | 238 CollectEvacuationCandidates(heap()->old_pointer_space()); |
| 239 CollectEvacuationCandidates(heap()->old_data_space()); | 239 CollectEvacuationCandidates(heap()->old_data_space()); |
| 240 CollectEvacuationCandidates(heap()->code_space()); | |
| 240 | 241 |
| 241 heap()->old_pointer_space()->EvictEvacuationCandidatesFromFreeLists(); | 242 heap()->old_pointer_space()->EvictEvacuationCandidatesFromFreeLists(); |
| 242 heap()->old_data_space()->EvictEvacuationCandidatesFromFreeLists(); | 243 heap()->old_data_space()->EvictEvacuationCandidatesFromFreeLists(); |
| 244 heap()->code_space()->EvictEvacuationCandidatesFromFreeLists(); | |
| 243 | 245 |
| 244 compacting_ = evacuation_candidates_.length() > 0; | 246 compacting_ = evacuation_candidates_.length() > 0; |
| 245 } | 247 } |
| 246 | 248 |
| 247 return compacting_; | 249 return compacting_; |
| 248 } | 250 } |
| 249 | 251 |
| 250 | 252 |
| 251 void MarkCompactCollector::CollectGarbage() { | 253 void MarkCompactCollector::CollectGarbage() { |
| 252 // Make sure that Prepare() has been called. The individual steps below will | 254 // Make sure that Prepare() has been called. The individual steps below will |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 372 } | 374 } |
| 373 MarkBit old_mark_bit = MarkBitFrom(old_start); | 375 MarkBit old_mark_bit = MarkBitFrom(old_start); |
| 374 if (!old_mark_bit.Get()) { | 376 if (!old_mark_bit.Get()) { |
| 375 return false; | 377 return false; |
| 376 } | 378 } |
| 377 new_mark_bit.Set(); | 379 new_mark_bit.Set(); |
| 378 return true; | 380 return true; |
| 379 } | 381 } |
| 380 | 382 |
| 381 | 383 |
| 384 static const char* AllocationSpaceName(AllocationSpace space) { | |
| 385 switch (space) { | |
| 386 case NEW_SPACE: return "NEW_SPACE"; | |
| 387 case OLD_POINTER_SPACE: return "OLD_POINTER_SPACE"; | |
| 388 case OLD_DATA_SPACE: return "OLD_DATA_SPACE"; | |
| 389 case CODE_SPACE: return "CODE_SPACE"; | |
| 390 case MAP_SPACE: return "MAP_SPACE"; | |
| 391 case CELL_SPACE: return "CELL_SPACE"; | |
| 392 case LO_SPACE: return "LO_SPACE"; | |
| 393 default: | |
| 394 UNREACHABLE(); | |
| 395 } | |
| 396 | |
| 397 return NULL; | |
| 398 } | |
| 399 | |
| 400 | |
| 382 void MarkCompactCollector::CollectEvacuationCandidates(PagedSpace* space) { | 401 void MarkCompactCollector::CollectEvacuationCandidates(PagedSpace* space) { |
| 383 ASSERT(space->identity() == OLD_POINTER_SPACE || | 402 ASSERT(space->identity() == OLD_POINTER_SPACE || |
| 384 space->identity() == OLD_DATA_SPACE); | 403 space->identity() == OLD_DATA_SPACE || |
| 404 space->identity() == CODE_SPACE); | |
| 385 | 405 |
| 386 PageIterator it(space); | 406 PageIterator it(space); |
| 407 int count = 0; | |
| 387 if (it.has_next()) it.next(); // Never compact the first page. | 408 if (it.has_next()) it.next(); // Never compact the first page. |
| 388 while (it.has_next()) { | 409 while (it.has_next()) { |
| 389 Page* p = it.next(); | 410 Page* p = it.next(); |
| 390 if (space->IsFragmented(p)) { | 411 if (space->IsFragmented(p)) { |
| 391 AddEvacuationCandidate(p); | 412 AddEvacuationCandidate(p); |
| 413 count++; | |
| 392 } else { | 414 } else { |
| 393 p->ClearEvacuationCandidate(); | 415 p->ClearEvacuationCandidate(); |
| 394 } | 416 } |
| 395 } | 417 } |
| 418 | |
| 419 if (count > 0 && FLAG_trace_fragmentation) { | |
| 420 PrintF("Collected %d evacuation candidates for space %s\n", | |
| 421 count, | |
| 422 AllocationSpaceName(space->identity())); | |
| 423 } | |
| 396 } | 424 } |
| 397 | 425 |
| 398 | 426 |
| 399 void MarkCompactCollector::Prepare(GCTracer* tracer) { | 427 void MarkCompactCollector::Prepare(GCTracer* tracer) { |
| 400 FLAG_flush_code = false; | 428 FLAG_flush_code = false; |
| 401 FLAG_always_compact = false; | 429 FLAG_always_compact = false; |
| 402 | 430 |
| 403 // Disable collection of maps if incremental marking is enabled. | 431 // Disable collection of maps if incremental marking is enabled. |
| 404 // Map collection algorithm relies on a special map transition tree traversal | 432 // Map collection algorithm relies on a special map transition tree traversal |
| 405 // order which is not implemented for incremental marking. | 433 // order which is not implemented for incremental marking. |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 539 | 567 |
| 540 Code* code = shared->unchecked_code(); | 568 Code* code = shared->unchecked_code(); |
| 541 MarkBit code_mark = Marking::MarkBitFrom(code); | 569 MarkBit code_mark = Marking::MarkBitFrom(code); |
| 542 if (!code_mark.Get()) { | 570 if (!code_mark.Get()) { |
| 543 shared->set_code(lazy_compile); | 571 shared->set_code(lazy_compile); |
| 544 candidate->set_code(lazy_compile); | 572 candidate->set_code(lazy_compile); |
| 545 } else { | 573 } else { |
| 546 candidate->set_code(shared->unchecked_code()); | 574 candidate->set_code(shared->unchecked_code()); |
| 547 } | 575 } |
| 548 | 576 |
| 577 Address slot = candidate->address() + JSFunction::kCodeEntryOffset; | |
|
Erik Corry
2011/09/06 14:10:31
This is kind of subtle. Comment?
Vyacheslav Egorov (Chromium)
2011/09/06 15:01:42
Done.
| |
| 578 isolate_->heap()->mark_compact_collector()-> | |
| 579 RecordCodeEntrySlot(slot, Code::cast(Memory::Object_at(slot))); | |
| 580 | |
| 549 candidate = next_candidate; | 581 candidate = next_candidate; |
| 550 } | 582 } |
| 551 | 583 |
| 552 jsfunction_candidates_head_ = NULL; | 584 jsfunction_candidates_head_ = NULL; |
| 553 } | 585 } |
| 554 | 586 |
| 555 | 587 |
| 556 void ProcessSharedFunctionInfoCandidates() { | 588 void ProcessSharedFunctionInfoCandidates() { |
| 557 Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kLazyCompile); | 589 Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kLazyCompile); |
| 558 | 590 |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 737 if (end - start >= kMinRangeForMarkingRecursion) { | 769 if (end - start >= kMinRangeForMarkingRecursion) { |
| 738 if (VisitUnmarkedObjects(heap, start, end)) return; | 770 if (VisitUnmarkedObjects(heap, start, end)) return; |
| 739 // We are close to a stack overflow, so just mark the objects. | 771 // We are close to a stack overflow, so just mark the objects. |
| 740 } | 772 } |
| 741 MarkCompactCollector* collector = heap->mark_compact_collector(); | 773 MarkCompactCollector* collector = heap->mark_compact_collector(); |
| 742 for (Object** p = start; p < end; p++) { | 774 for (Object** p = start; p < end; p++) { |
| 743 MarkObjectByPointer(collector, start, p); | 775 MarkObjectByPointer(collector, start, p); |
| 744 } | 776 } |
| 745 } | 777 } |
| 746 | 778 |
| 747 static inline void VisitCodeTarget(Heap* heap, RelocInfo* rinfo) { | |
| 748 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); | |
| 749 Code* code = Code::GetCodeFromTargetAddress(rinfo->target_address()); | |
| 750 if (FLAG_cleanup_code_caches_at_gc && code->is_inline_cache_stub()) { | |
| 751 IC::Clear(rinfo->pc()); | |
| 752 // Please note targets for cleared inline cached do not have to be | |
| 753 // marked since they are contained in HEAP->non_monomorphic_cache(). | |
| 754 } else { | |
| 755 MarkBit code_mark = Marking::MarkBitFrom(code); | |
| 756 heap->mark_compact_collector()->MarkObject(code, code_mark); | |
| 757 } | |
| 758 } | |
| 759 | |
| 760 static void VisitGlobalPropertyCell(Heap* heap, RelocInfo* rinfo) { | 779 static void VisitGlobalPropertyCell(Heap* heap, RelocInfo* rinfo) { |
| 761 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL); | 780 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL); |
| 762 Object* cell = rinfo->target_cell(); | 781 JSGlobalPropertyCell* cell = |
| 763 Object* old_cell = cell; | 782 JSGlobalPropertyCell::cast(rinfo->target_cell()); |
| 764 VisitPointer(heap, &cell); | 783 MarkBit mark = Marking::MarkBitFrom(cell); |
| 765 if (cell != old_cell) { | 784 heap->mark_compact_collector()->MarkObject(cell, mark); |
| 766 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell), | 785 } |
| 767 NULL); | 786 |
| 787 static inline void VisitCodeTarget(Heap* heap, RelocInfo* rinfo) { | |
| 788 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); | |
| 789 Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); | |
| 790 if (FLAG_cleanup_code_caches_at_gc && target->is_inline_cache_stub()) { | |
| 791 IC::Clear(rinfo->pc()); | |
| 792 // Please note targets for cleared inline cached do not have to be | |
| 793 // marked since they are contained in HEAP->non_monomorphic_cache(). | |
| 794 target = Code::GetCodeFromTargetAddress(rinfo->target_address()); | |
| 795 } else { | |
| 796 MarkBit code_mark = Marking::MarkBitFrom(target); | |
| 797 heap->mark_compact_collector()->MarkObject(target, code_mark); | |
| 768 } | 798 } |
| 799 heap->mark_compact_collector()->RecordRelocSlot(rinfo, target); | |
| 769 } | 800 } |
| 770 | 801 |
| 771 static inline void VisitDebugTarget(Heap* heap, RelocInfo* rinfo) { | 802 static inline void VisitDebugTarget(Heap* heap, RelocInfo* rinfo) { |
| 772 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) && | 803 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) && |
| 773 rinfo->IsPatchedReturnSequence()) || | 804 rinfo->IsPatchedReturnSequence()) || |
| 774 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && | 805 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && |
| 775 rinfo->IsPatchedDebugBreakSlotSequence())); | 806 rinfo->IsPatchedDebugBreakSlotSequence())); |
| 776 HeapObject* code = Code::GetCodeFromTargetAddress(rinfo->call_address()); | 807 Code* target = Code::GetCodeFromTargetAddress(rinfo->call_address()); |
| 777 MarkBit code_mark = Marking::MarkBitFrom(code); | 808 MarkBit code_mark = Marking::MarkBitFrom(target); |
| 778 heap->mark_compact_collector()->MarkObject(code, code_mark); | 809 heap->mark_compact_collector()->MarkObject(target, code_mark); |
| 810 heap->mark_compact_collector()->RecordRelocSlot(rinfo, target); | |
| 779 } | 811 } |
| 780 | 812 |
| 781 // Mark object pointed to by p. | 813 // Mark object pointed to by p. |
| 782 INLINE(static void MarkObjectByPointer(MarkCompactCollector* collector, | 814 INLINE(static void MarkObjectByPointer(MarkCompactCollector* collector, |
| 783 Object** anchor_slot, | 815 Object** anchor_slot, |
| 784 Object** p)) { | 816 Object** p)) { |
| 785 if (!(*p)->IsHeapObject()) return; | 817 if (!(*p)->IsHeapObject()) return; |
| 786 HeapObject* object = ShortCircuitConsString(p); | 818 HeapObject* object = ShortCircuitConsString(p); |
| 787 collector->RecordSlot(anchor_slot, p, object); | 819 collector->RecordSlot(anchor_slot, p, object); |
| 788 MarkBit mark = Marking::MarkBitFrom(object); | 820 MarkBit mark = Marking::MarkBitFrom(object); |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1088 if (known_flush_code_candidate) { | 1120 if (known_flush_code_candidate) { |
| 1089 heap->mark_compact_collector()->code_flusher()->AddCandidate(shared); | 1121 heap->mark_compact_collector()->code_flusher()->AddCandidate(shared); |
| 1090 } | 1122 } |
| 1091 } | 1123 } |
| 1092 | 1124 |
| 1093 VisitSharedFunctionInfoFields(heap, object, known_flush_code_candidate); | 1125 VisitSharedFunctionInfoFields(heap, object, known_flush_code_candidate); |
| 1094 } | 1126 } |
| 1095 | 1127 |
| 1096 | 1128 |
| 1097 static void VisitCodeEntry(Heap* heap, Address entry_address) { | 1129 static void VisitCodeEntry(Heap* heap, Address entry_address) { |
| 1098 Object* code = Code::GetObjectFromEntryAddress(entry_address); | 1130 Code* code = Code::cast(Code::GetObjectFromEntryAddress(entry_address)); |
| 1099 Object* old_code = code; | 1131 MarkBit mark = Marking::MarkBitFrom(code); |
| 1100 VisitPointer(heap, &code); | 1132 heap->mark_compact_collector()->MarkObject(code, mark); |
| 1101 if (code != old_code) { | 1133 heap->mark_compact_collector()-> |
| 1102 Memory::Address_at(entry_address) = | 1134 RecordCodeEntrySlot(entry_address, code); |
| 1103 reinterpret_cast<Code*>(code)->entry(); | |
| 1104 } | |
| 1105 } | 1135 } |
| 1106 | 1136 |
| 1107 static void VisitGlobalContext(Map* map, HeapObject* object) { | 1137 static void VisitGlobalContext(Map* map, HeapObject* object) { |
| 1108 FixedBodyVisitor<StaticMarkingVisitor, | 1138 FixedBodyVisitor<StaticMarkingVisitor, |
| 1109 Context::MarkCompactBodyDescriptor, | 1139 Context::MarkCompactBodyDescriptor, |
| 1110 void>::Visit(map, object); | 1140 void>::Visit(map, object); |
| 1111 | 1141 |
| 1112 MarkCompactCollector* collector = map->GetHeap()->mark_compact_collector(); | 1142 MarkCompactCollector* collector = map->GetHeap()->mark_compact_collector(); |
| 1113 for (int idx = Context::FIRST_WEAK_SLOT; | 1143 for (int idx = Context::FIRST_WEAK_SLOT; |
| 1114 idx < Context::GLOBAL_CONTEXT_SLOTS; | 1144 idx < Context::GLOBAL_CONTEXT_SLOTS; |
| (...skipping 1146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2261 // The second pass updates pointers to new space in all spaces. It is possible | 2291 // The second pass updates pointers to new space in all spaces. It is possible |
| 2262 // to encounter pointers to dead new space objects during traversal of pointers | 2292 // to encounter pointers to dead new space objects during traversal of pointers |
| 2263 // to new space. We should clear them to avoid encountering them during next | 2293 // to new space. We should clear them to avoid encountering them during next |
| 2264 // pointer iteration. This is an issue if the store buffer overflows and we | 2294 // pointer iteration. This is an issue if the store buffer overflows and we |
| 2265 // have to scan the entire old space, including dead objects, looking for | 2295 // have to scan the entire old space, including dead objects, looking for |
| 2266 // pointers to new space. | 2296 // pointers to new space. |
| 2267 void MarkCompactCollector::MigrateObject(Address dst, | 2297 void MarkCompactCollector::MigrateObject(Address dst, |
| 2268 Address src, | 2298 Address src, |
| 2269 int size, | 2299 int size, |
| 2270 AllocationSpace dest) { | 2300 AllocationSpace dest) { |
| 2271 ASSERT(dest == OLD_POINTER_SPACE || | |
| 2272 dest == OLD_DATA_SPACE || | |
| 2273 dest == LO_SPACE || | |
| 2274 dest == NEW_SPACE); | |
| 2275 | |
| 2276 if (dest == OLD_POINTER_SPACE || dest == LO_SPACE) { | 2301 if (dest == OLD_POINTER_SPACE || dest == LO_SPACE) { |
| 2277 Address src_slot = src; | 2302 Address src_slot = src; |
| 2278 Address dst_slot = dst; | 2303 Address dst_slot = dst; |
| 2279 ASSERT(IsAligned(size, kPointerSize)); | 2304 ASSERT(IsAligned(size, kPointerSize)); |
| 2280 | 2305 |
| 2281 for (int remaining = size / kPointerSize; remaining > 0; remaining--) { | 2306 for (int remaining = size / kPointerSize; remaining > 0; remaining--) { |
| 2282 Object* value = Memory::Object_at(src_slot); | 2307 Object* value = Memory::Object_at(src_slot); |
| 2283 | 2308 |
| 2284 Memory::Object_at(dst_slot) = value; | 2309 Memory::Object_at(dst_slot) = value; |
| 2285 | 2310 |
| 2286 if (heap_->InNewSpace(value)) { | 2311 if (heap_->InNewSpace(value)) { |
| 2287 heap_->store_buffer()->Mark(dst_slot); | 2312 heap_->store_buffer()->Mark(dst_slot); |
| 2288 } else if (value->IsHeapObject() && | 2313 } else if (value->IsHeapObject() && IsOnEvacuationCandidate(value)) { |
| 2289 MarkCompactCollector::IsOnEvacuationCandidate(value)) { | |
| 2290 SlotsBuffer::AddTo(&slots_buffer_allocator_, | 2314 SlotsBuffer::AddTo(&slots_buffer_allocator_, |
| 2291 &migration_slots_buffer_, | 2315 &migration_slots_buffer_, |
| 2292 reinterpret_cast<Object**>(dst_slot), | 2316 reinterpret_cast<Object**>(dst_slot), |
| 2293 SlotsBuffer::IGNORE_OVERFLOW); | 2317 SlotsBuffer::IGNORE_OVERFLOW); |
| 2294 } | 2318 } |
| 2295 | 2319 |
| 2296 src_slot += kPointerSize; | 2320 src_slot += kPointerSize; |
| 2297 dst_slot += kPointerSize; | 2321 dst_slot += kPointerSize; |
| 2298 } | 2322 } |
| 2323 | |
| 2324 if (compacting_ && HeapObject::FromAddress(dst)->IsJSFunction()) { | |
| 2325 Address code_entry_slot = dst + JSFunction::kCodeEntryOffset; | |
| 2326 Address code_entry = Memory::Address_at(code_entry_slot); | |
| 2327 | |
| 2328 if (Page::FromAddress(code_entry)->IsEvacuationCandidate()) { | |
| 2329 SlotsBuffer::AddTo(&slots_buffer_allocator_, | |
| 2330 &migration_slots_buffer_, | |
| 2331 SlotsBuffer::CODE_ENTRY_SLOT, | |
| 2332 code_entry_slot, | |
| 2333 SlotsBuffer::IGNORE_OVERFLOW); | |
| 2334 } | |
| 2335 } | |
| 2336 } else if (dest == CODE_SPACE) { | |
| 2337 PROFILE(heap()->isolate(), CodeMoveEvent(src, dst)); | |
| 2338 heap()->MoveBlock(dst, src, size); | |
| 2339 SlotsBuffer::AddTo(&slots_buffer_allocator_, | |
| 2340 &migration_slots_buffer_, | |
| 2341 SlotsBuffer::RELOCATED_CODE_OBJECT, | |
| 2342 dst, | |
| 2343 SlotsBuffer::IGNORE_OVERFLOW); | |
| 2344 Code::cast(HeapObject::FromAddress(dst))->Relocate(dst - src); | |
| 2299 } else { | 2345 } else { |
| 2300 heap_->CopyBlock(dst, src, size); | 2346 ASSERT(dest == OLD_DATA_SPACE || dest == NEW_SPACE); |
| 2347 heap()->MoveBlock(dst, src, size); | |
| 2301 } | 2348 } |
| 2302 Memory::Address_at(src) = dst; | 2349 Memory::Address_at(src) = dst; |
| 2303 } | 2350 } |
| 2304 | 2351 |
| 2305 | 2352 |
| 2306 // Visitor for updating pointers from live objects in old spaces to new space. | 2353 // Visitor for updating pointers from live objects in old spaces to new space. |
| 2307 // It does not expect to encounter pointers to dead objects. | 2354 // It does not expect to encounter pointers to dead objects. |
| 2308 class PointersUpdatingVisitor: public ObjectVisitor { | 2355 class PointersUpdatingVisitor: public ObjectVisitor { |
| 2309 public: | 2356 public: |
| 2310 explicit PointersUpdatingVisitor(Heap* heap) : heap_(heap) { } | 2357 explicit PointersUpdatingVisitor(Heap* heap) : heap_(heap) { } |
| 2311 | 2358 |
| 2312 void VisitPointer(Object** p) { | 2359 void VisitPointer(Object** p) { |
| 2313 UpdatePointer(p); | 2360 UpdatePointer(p); |
| 2314 } | 2361 } |
| 2315 | 2362 |
| 2316 void VisitPointers(Object** start, Object** end) { | 2363 void VisitPointers(Object** start, Object** end) { |
| 2317 for (Object** p = start; p < end; p++) UpdatePointer(p); | 2364 for (Object** p = start; p < end; p++) UpdatePointer(p); |
| 2318 } | 2365 } |
| 2319 | 2366 |
| 2320 void VisitCodeTarget(RelocInfo* rinfo) { | 2367 void VisitCodeTarget(RelocInfo* rinfo) { |
| 2321 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); | 2368 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); |
| 2322 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); | 2369 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); |
| 2323 VisitPointer(&target); | 2370 VisitPointer(&target); |
| 2324 rinfo->set_target_address(Code::cast(target)->instruction_start(), NULL); | 2371 rinfo->set_target_address(Code::cast(target)->instruction_start()); |
| 2325 } | 2372 } |
| 2326 | 2373 |
| 2327 void VisitDebugTarget(RelocInfo* rinfo) { | 2374 void VisitDebugTarget(RelocInfo* rinfo) { |
| 2328 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) && | 2375 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) && |
| 2329 rinfo->IsPatchedReturnSequence()) || | 2376 rinfo->IsPatchedReturnSequence()) || |
| 2330 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && | 2377 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && |
| 2331 rinfo->IsPatchedDebugBreakSlotSequence())); | 2378 rinfo->IsPatchedDebugBreakSlotSequence())); |
| 2332 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address()); | 2379 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address()); |
| 2333 VisitPointer(&target); | 2380 VisitPointer(&target); |
| 2334 rinfo->set_call_address(Code::cast(target)->instruction_start()); | 2381 rinfo->set_call_address(Code::cast(target)->instruction_start()); |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2577 | 2624 |
| 2578 MapWord map_word = heap_obj->map_word(); | 2625 MapWord map_word = heap_obj->map_word(); |
| 2579 if (map_word.IsForwardingAddress()) { | 2626 if (map_word.IsForwardingAddress()) { |
| 2580 ASSERT(MarkCompactCollector::IsOnEvacuationCandidate(*slot)); | 2627 ASSERT(MarkCompactCollector::IsOnEvacuationCandidate(*slot)); |
| 2581 *slot = map_word.ToForwardingAddress(); | 2628 *slot = map_word.ToForwardingAddress(); |
| 2582 ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(*slot)); | 2629 ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(*slot)); |
| 2583 } | 2630 } |
| 2584 } | 2631 } |
| 2585 | 2632 |
| 2586 | 2633 |
| 2634 static inline void UpdateSlot(ObjectVisitor* v, | |
| 2635 SlotsBuffer::SlotType slot_type, | |
| 2636 Address addr) { | |
| 2637 switch (slot_type) { | |
| 2638 case SlotsBuffer::CODE_TARGET_SLOT: { | |
| 2639 RelocInfo rinfo(addr, RelocInfo::CODE_TARGET, NULL, NULL); | |
| 2640 rinfo.Visit(v); | |
| 2641 break; | |
| 2642 } | |
| 2643 case SlotsBuffer::CODE_ENTRY_SLOT: { | |
| 2644 v->VisitCodeEntry(addr); | |
| 2645 break; | |
| 2646 } | |
| 2647 case SlotsBuffer::RELOCATED_CODE_OBJECT: { | |
| 2648 HeapObject* obj = HeapObject::FromAddress(addr); | |
| 2649 Code::cast(obj)->CodeIterateBody(v); | |
| 2650 break; | |
| 2651 } | |
| 2652 case SlotsBuffer::DEBUG_TARGET_SLOT: { | |
| 2653 RelocInfo rinfo(addr, RelocInfo::DEBUG_BREAK_SLOT, NULL, NULL); | |
| 2654 if (rinfo.IsPatchedDebugBreakSlotSequence()) rinfo.Visit(v); | |
| 2655 break; | |
| 2656 } | |
| 2657 case SlotsBuffer::JS_RETURN_SLOT: { | |
| 2658 RelocInfo rinfo(addr, RelocInfo::JS_RETURN, NULL, NULL); | |
| 2659 if (rinfo.IsPatchedReturnSequence()) rinfo.Visit(v); | |
| 2660 break; | |
| 2661 } | |
| 2662 default: | |
| 2663 UNREACHABLE(); | |
| 2664 break; | |
| 2665 } | |
| 2666 } | |
| 2667 | |
| 2668 | |
| 2587 static inline void UpdateSlotsInRange(Object** start, Object** end) { | 2669 static inline void UpdateSlotsInRange(Object** start, Object** end) { |
| 2588 for (Object** slot = start; | 2670 for (Object** slot = start; |
| 2589 slot < end; | 2671 slot < end; |
| 2590 slot++) { | 2672 slot++) { |
| 2591 Object* obj = *slot; | 2673 Object* obj = *slot; |
| 2592 if (obj->IsHeapObject() && | 2674 if (obj->IsHeapObject() && |
| 2593 MarkCompactCollector::IsOnEvacuationCandidate(obj)) { | 2675 MarkCompactCollector::IsOnEvacuationCandidate(obj)) { |
| 2594 MapWord map_word = HeapObject::cast(obj)->map_word(); | 2676 MapWord map_word = HeapObject::cast(obj)->map_word(); |
| 2595 if (map_word.IsForwardingAddress()) { | 2677 if (map_word.IsForwardingAddress()) { |
| 2596 *slot = map_word.ToForwardingAddress(); | 2678 *slot = map_word.ToForwardingAddress(); |
| 2597 ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(*slot)); | 2679 ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(*slot)); |
| 2598 } | 2680 } |
| 2599 } | 2681 } |
| 2600 } | 2682 } |
| 2601 } | 2683 } |
| 2602 | 2684 |
| 2603 | 2685 |
| 2604 enum SweepingMode { | 2686 enum SweepingMode { |
| 2605 SWEEP_ONLY, | 2687 SWEEP_ONLY, |
| 2606 SWEEP_AND_UPDATE_SLOTS | 2688 SWEEP_AND_VISIT_LIVE_OBJECTS |
| 2607 }; | 2689 }; |
| 2608 | 2690 |
| 2609 | 2691 |
| 2610 // Sweep a space precisely. After this has been done the space can | 2692 // Sweep a space precisely. After this has been done the space can |
| 2611 // be iterated precisely, hitting only the live objects. Code space | 2693 // be iterated precisely, hitting only the live objects. Code space |
| 2612 // is always swept precisely because we want to be able to iterate | 2694 // is always swept precisely because we want to be able to iterate |
| 2613 // over it. Map space is swept precisely, because it is not compacted. | 2695 // over it. Map space is swept precisely, because it is not compacted. |
| 2614 // Slots in live objects pointing into evacuation candidates are updated | 2696 // Slots in live objects pointing into evacuation candidates are updated |
| 2615 // if requested. | 2697 // if requested. |
| 2616 static void SweepPrecisely(PagedSpace* space, Page* p, SweepingMode mode) { | 2698 static void SweepPrecisely(PagedSpace* space, |
| 2699 Page* p, | |
| 2700 SweepingMode mode, | |
| 2701 ObjectVisitor* v) { | |
| 2617 ASSERT(!p->IsEvacuationCandidate() && !p->WasSwept()); | 2702 ASSERT(!p->IsEvacuationCandidate() && !p->WasSwept()); |
| 2618 MarkBit::CellType* cells = p->markbits()->cells(); | 2703 MarkBit::CellType* cells = p->markbits()->cells(); |
| 2619 p->MarkSweptPrecisely(); | 2704 p->MarkSweptPrecisely(); |
| 2620 | 2705 |
| 2621 int last_cell_index = | 2706 int last_cell_index = |
| 2622 Bitmap::IndexToCell( | 2707 Bitmap::IndexToCell( |
| 2623 Bitmap::CellAlignIndex( | 2708 Bitmap::CellAlignIndex( |
| 2624 p->AddressToMarkbitIndex(p->ObjectAreaEnd()))); | 2709 p->AddressToMarkbitIndex(p->ObjectAreaEnd()))); |
| 2625 | 2710 |
| 2626 int cell_index = Page::kFirstUsedCell; | 2711 int cell_index = Page::kFirstUsedCell; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 2638 p->AddressToMarkbitIndex(object_address)))); | 2723 p->AddressToMarkbitIndex(object_address)))); |
| 2639 int live_objects = MarkWordToObjectStarts(cells[cell_index], offsets); | 2724 int live_objects = MarkWordToObjectStarts(cells[cell_index], offsets); |
| 2640 int live_index = 0; | 2725 int live_index = 0; |
| 2641 for ( ; live_objects != 0; live_objects--) { | 2726 for ( ; live_objects != 0; live_objects--) { |
| 2642 Address free_end = object_address + offsets[live_index++] * kPointerSize; | 2727 Address free_end = object_address + offsets[live_index++] * kPointerSize; |
| 2643 if (free_end != free_start) { | 2728 if (free_end != free_start) { |
| 2644 space->Free(free_start, static_cast<int>(free_end - free_start)); | 2729 space->Free(free_start, static_cast<int>(free_end - free_start)); |
| 2645 } | 2730 } |
| 2646 HeapObject* live_object = HeapObject::FromAddress(free_end); | 2731 HeapObject* live_object = HeapObject::FromAddress(free_end); |
| 2647 ASSERT(Marking::IsBlack(Marking::MarkBitFrom(live_object))); | 2732 ASSERT(Marking::IsBlack(Marking::MarkBitFrom(live_object))); |
| 2648 int size = live_object->Size(); | 2733 Map* map = live_object->map(); |
| 2649 if (mode == SWEEP_AND_UPDATE_SLOTS) { | 2734 int size = live_object->SizeFromMap(map); |
| 2650 UpdateSlotsInRange(HeapObject::RawField(live_object, kPointerSize), | 2735 if (mode == SWEEP_AND_VISIT_LIVE_OBJECTS) { |
| 2651 HeapObject::RawField(live_object, size)); | 2736 live_object->IterateBody(map->instance_type(), size, v); |
| 2652 } | 2737 } |
| 2653 free_start = free_end + size; | 2738 free_start = free_end + size; |
| 2654 } | 2739 } |
| 2655 // Clear marking bits for current cell. | 2740 // Clear marking bits for current cell. |
| 2656 cells[cell_index] = 0; | 2741 cells[cell_index] = 0; |
| 2657 } | 2742 } |
| 2658 if (free_start != p->ObjectAreaEnd()) { | 2743 if (free_start != p->ObjectAreaEnd()) { |
| 2659 space->Free(free_start, static_cast<int>(p->ObjectAreaEnd() - free_start)); | 2744 space->Free(free_start, static_cast<int>(p->ObjectAreaEnd() - free_start)); |
| 2660 } | 2745 } |
| 2661 } | 2746 } |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 2684 heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE); | 2769 heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE); |
| 2685 LiveObjectList::IterateElements(&updating_visitor); | 2770 LiveObjectList::IterateElements(&updating_visitor); |
| 2686 | 2771 |
| 2687 { | 2772 { |
| 2688 StoreBufferRebuildScope scope(heap_, | 2773 StoreBufferRebuildScope scope(heap_, |
| 2689 heap_->store_buffer(), | 2774 heap_->store_buffer(), |
| 2690 &Heap::ScavengeStoreBufferCallback); | 2775 &Heap::ScavengeStoreBufferCallback); |
| 2691 heap_->store_buffer()->IteratePointersToNewSpace(&UpdatePointer); | 2776 heap_->store_buffer()->IteratePointersToNewSpace(&UpdatePointer); |
| 2692 } | 2777 } |
| 2693 | 2778 |
| 2694 SlotsBuffer::UpdateSlotsRecordedIn(migration_slots_buffer_); | 2779 SlotsBuffer::UpdateSlotsRecordedIn(heap_, migration_slots_buffer_); |
| 2695 if (FLAG_trace_fragmentation) { | 2780 if (FLAG_trace_fragmentation) { |
| 2696 PrintF(" migration slots buffer: %d\n", | 2781 PrintF(" migration slots buffer: %d\n", |
| 2697 SlotsBuffer::SizeOfChain(migration_slots_buffer_)); | 2782 SlotsBuffer::SizeOfChain(migration_slots_buffer_)); |
| 2698 } | 2783 } |
| 2699 | 2784 |
| 2700 int npages = evacuation_candidates_.length(); | 2785 int npages = evacuation_candidates_.length(); |
| 2701 for (int i = 0; i < npages; i++) { | 2786 for (int i = 0; i < npages; i++) { |
| 2702 Page* p = evacuation_candidates_[i]; | 2787 Page* p = evacuation_candidates_[i]; |
| 2703 ASSERT(p->IsEvacuationCandidate() || | 2788 ASSERT(p->IsEvacuationCandidate() || |
| 2704 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); | 2789 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); |
| 2705 | 2790 |
| 2706 if (p->IsEvacuationCandidate()) { | 2791 if (p->IsEvacuationCandidate()) { |
| 2707 SlotsBuffer::UpdateSlotsRecordedIn(p->slots_buffer()); | 2792 SlotsBuffer::UpdateSlotsRecordedIn(heap_, p->slots_buffer()); |
| 2708 if (FLAG_trace_fragmentation) { | 2793 if (FLAG_trace_fragmentation) { |
| 2709 PrintF(" page %p slots buffer: %d\n", | 2794 PrintF(" page %p slots buffer: %d\n", |
| 2710 reinterpret_cast<void*>(p), | 2795 reinterpret_cast<void*>(p), |
| 2711 SlotsBuffer::SizeOfChain(p->slots_buffer())); | 2796 SlotsBuffer::SizeOfChain(p->slots_buffer())); |
| 2712 } | 2797 } |
| 2713 } else { | 2798 } else { |
| 2714 if (FLAG_gc_verbose) { | 2799 if (FLAG_gc_verbose) { |
| 2715 PrintF("Sweeping 0x%" V8PRIxPTR " during evacuation.\n", | 2800 PrintF("Sweeping 0x%" V8PRIxPTR " during evacuation.\n", |
| 2716 reinterpret_cast<intptr_t>(p)); | 2801 reinterpret_cast<intptr_t>(p)); |
| 2717 } | 2802 } |
| 2718 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); | 2803 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); |
| 2719 p->ClearFlag(MemoryChunk::RESCAN_ON_EVACUATION); | 2804 p->ClearFlag(MemoryChunk::RESCAN_ON_EVACUATION); |
| 2720 SweepPrecisely(space, p, SWEEP_AND_UPDATE_SLOTS); | 2805 |
| 2806 SweepPrecisely(space, | |
| 2807 p, | |
| 2808 SWEEP_AND_VISIT_LIVE_OBJECTS, | |
| 2809 &updating_visitor); | |
| 2721 } | 2810 } |
| 2722 } | 2811 } |
| 2723 | 2812 |
| 2724 // Update pointers from cells. | 2813 // Update pointers from cells. |
| 2725 HeapObjectIterator cell_iterator(heap_->cell_space()); | 2814 HeapObjectIterator cell_iterator(heap_->cell_space()); |
| 2726 for (HeapObject* cell = cell_iterator.Next(); | 2815 for (HeapObject* cell = cell_iterator.Next(); |
| 2727 cell != NULL; | 2816 cell != NULL; |
| 2728 cell = cell_iterator.Next()) { | 2817 cell = cell_iterator.Next()) { |
| 2729 if (cell->IsJSGlobalPropertyCell()) { | 2818 if (cell->IsJSGlobalPropertyCell()) { |
| 2730 Address value_address = | 2819 Address value_address = |
| (...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3231 } | 3320 } |
| 3232 case LAZY_CONSERVATIVE: { | 3321 case LAZY_CONSERVATIVE: { |
| 3233 freed_bytes += SweepConservatively(space, p); | 3322 freed_bytes += SweepConservatively(space, p); |
| 3234 if (freed_bytes >= newspace_size && p != space->LastPage()) { | 3323 if (freed_bytes >= newspace_size && p != space->LastPage()) { |
| 3235 space->SetPagesToSweep(p->next_page(), space->LastPage()); | 3324 space->SetPagesToSweep(p->next_page(), space->LastPage()); |
| 3236 lazy_sweeping_active = true; | 3325 lazy_sweeping_active = true; |
| 3237 } | 3326 } |
| 3238 break; | 3327 break; |
| 3239 } | 3328 } |
| 3240 case PRECISE: { | 3329 case PRECISE: { |
| 3241 SweepPrecisely(space, p, SWEEP_ONLY); | 3330 SweepPrecisely(space, p, SWEEP_ONLY, NULL); |
| 3242 break; | 3331 break; |
| 3243 } | 3332 } |
| 3244 default: { | 3333 default: { |
| 3245 UNREACHABLE(); | 3334 UNREACHABLE(); |
| 3246 } | 3335 } |
| 3247 } | 3336 } |
| 3248 } | 3337 } |
| 3249 } | 3338 } |
| 3250 | 3339 |
| 3251 | 3340 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3307 PROFILE(isolate, CodeDeleteEvent(obj->address())); | 3396 PROFILE(isolate, CodeDeleteEvent(obj->address())); |
| 3308 } | 3397 } |
| 3309 } | 3398 } |
| 3310 | 3399 |
| 3311 | 3400 |
| 3312 void MarkCompactCollector::Initialize() { | 3401 void MarkCompactCollector::Initialize() { |
| 3313 StaticMarkingVisitor::Initialize(); | 3402 StaticMarkingVisitor::Initialize(); |
| 3314 } | 3403 } |
| 3315 | 3404 |
| 3316 | 3405 |
| 3317 void SlotsBuffer::UpdateSlots() { | 3406 bool SlotsBuffer::IsTypedSlot(ObjectSlot slot) { |
| 3318 for (int slot_idx = 0; slot_idx < idx_; ++slot_idx) { | 3407 return reinterpret_cast<uintptr_t>(slot) < NUMBER_OF_SLOT_TYPES; |
| 3319 UpdateSlot(slots_[slot_idx]); | 3408 } |
| 3409 | |
| 3410 | |
| 3411 bool SlotsBuffer::AddTo(SlotsBufferAllocator* allocator, | |
| 3412 SlotsBuffer** buffer_address, | |
| 3413 SlotType type, | |
| 3414 Address addr, | |
| 3415 AdditionMode mode) { | |
| 3416 if(!AddTo(allocator, | |
| 3417 buffer_address, | |
| 3418 reinterpret_cast<ObjectSlot>(type), | |
| 3419 mode)) { | |
| 3420 return false; | |
| 3421 } | |
| 3422 return AddTo(allocator, | |
| 3423 buffer_address, | |
| 3424 reinterpret_cast<ObjectSlot>(addr), | |
| 3425 mode); | |
| 3426 } | |
| 3427 | |
| 3428 | |
| 3429 static inline SlotsBuffer::SlotType SlotTypeForRMode(RelocInfo::Mode rmode) { | |
| 3430 if (RelocInfo::IsCodeTarget(rmode)) { | |
| 3431 return SlotsBuffer::CODE_TARGET_SLOT; | |
| 3432 } else if (RelocInfo::IsDebugBreakSlot(rmode)) { | |
| 3433 return SlotsBuffer::DEBUG_TARGET_SLOT; | |
| 3434 } else if (RelocInfo::IsJSReturn(rmode)) { | |
| 3435 return SlotsBuffer::JS_RETURN_SLOT; | |
| 3436 } | |
| 3437 UNREACHABLE(); | |
| 3438 return SlotsBuffer::NONE; | |
| 3439 } | |
| 3440 | |
| 3441 | |
| 3442 void MarkCompactCollector::RecordRelocSlot(RelocInfo* rinfo, Code* target) { | |
| 3443 Page* target_page = Page::FromAddress( | |
| 3444 reinterpret_cast<Address>(target)); | |
| 3445 if (target_page->IsEvacuationCandidate() && | |
| 3446 !ShouldSkipEvacuationSlotRecording(rinfo->host())) { | |
| 3447 if (!SlotsBuffer::AddTo(&slots_buffer_allocator_, | |
| 3448 target_page->slots_buffer_address(), | |
| 3449 SlotTypeForRMode(rinfo->rmode()), | |
| 3450 rinfo->pc(), | |
| 3451 SlotsBuffer::FAIL_ON_OVERFLOW)) { | |
| 3452 EvictEvacuationCandidate(target_page); | |
| 3453 } | |
| 3320 } | 3454 } |
| 3321 } | 3455 } |
| 3322 | 3456 |
| 3323 | 3457 |
| 3458 void MarkCompactCollector::RecordCodeEntrySlot(Address slot, Code* target) { | |
| 3459 Page* target_page = Page::FromAddress( | |
| 3460 reinterpret_cast<Address>(target)); | |
| 3461 if (target_page->IsEvacuationCandidate() && | |
| 3462 !ShouldSkipEvacuationSlotRecording(reinterpret_cast<Object**>(slot))) { | |
| 3463 if (!SlotsBuffer::AddTo(&slots_buffer_allocator_, | |
| 3464 target_page->slots_buffer_address(), | |
| 3465 SlotsBuffer::CODE_ENTRY_SLOT, | |
| 3466 slot, | |
| 3467 SlotsBuffer::FAIL_ON_OVERFLOW)) { | |
| 3468 EvictEvacuationCandidate(target_page); | |
| 3469 } | |
| 3470 } | |
| 3471 } | |
| 3472 | |
| 3473 | |
| 3474 static inline SlotsBuffer::SlotType DecodeSlotType( | |
| 3475 SlotsBuffer::ObjectSlot slot) { | |
| 3476 return static_cast<SlotsBuffer::SlotType>(reinterpret_cast<intptr_t>(slot)); | |
| 3477 } | |
| 3478 | |
| 3479 | |
| 3480 SlotsBuffer::SlotType SlotsBuffer::UpdateSlots( | |
|
Erik Corry
2011/09/06 14:10:31
Somewhere there should be a comment on why this fu
Vyacheslav Egorov (Chromium)
2011/09/06 15:01:42
Done.
| |
| 3481 Heap* heap, | |
| 3482 SlotsBuffer::SlotType pending) { | |
| 3483 PointersUpdatingVisitor v(heap); | |
| 3484 | |
| 3485 if (pending != NONE) { | |
| 3486 UpdateSlot(&v, pending, reinterpret_cast<Address>(slots_[0])); | |
| 3487 } | |
| 3488 | |
| 3489 for (int slot_idx = 0; slot_idx < idx_; ++slot_idx) { | |
| 3490 ObjectSlot slot = slots_[slot_idx]; | |
| 3491 if (!IsTypedSlot(slot)) { | |
| 3492 UpdateSlot(slot); | |
| 3493 } else { | |
| 3494 ++slot_idx; | |
| 3495 if (slot_idx < idx_) { | |
| 3496 UpdateSlot(&v, | |
| 3497 DecodeSlotType(slot), | |
| 3498 reinterpret_cast<Address>(slots_[slot_idx])); | |
| 3499 } else { | |
| 3500 return DecodeSlotType(slot); | |
| 3501 } | |
| 3502 } | |
| 3503 } | |
| 3504 | |
| 3505 return SlotsBuffer::NONE; | |
| 3506 } | |
| 3507 | |
| 3508 | |
| 3324 SlotsBuffer* SlotsBufferAllocator::AllocateBuffer(SlotsBuffer* next_buffer) { | 3509 SlotsBuffer* SlotsBufferAllocator::AllocateBuffer(SlotsBuffer* next_buffer) { |
| 3325 return new SlotsBuffer(next_buffer); | 3510 return new SlotsBuffer(next_buffer); |
| 3326 } | 3511 } |
| 3327 | 3512 |
| 3328 | 3513 |
| 3329 void SlotsBufferAllocator::DeallocateBuffer(SlotsBuffer* buffer) { | 3514 void SlotsBufferAllocator::DeallocateBuffer(SlotsBuffer* buffer) { |
| 3330 delete buffer; | 3515 delete buffer; |
| 3331 } | 3516 } |
| 3332 | 3517 |
| 3333 | 3518 |
| 3334 void SlotsBufferAllocator::DeallocateChain(SlotsBuffer** buffer_address) { | 3519 void SlotsBufferAllocator::DeallocateChain(SlotsBuffer** buffer_address) { |
| 3335 SlotsBuffer* buffer = *buffer_address; | 3520 SlotsBuffer* buffer = *buffer_address; |
| 3336 while (buffer != NULL) { | 3521 while (buffer != NULL) { |
| 3337 SlotsBuffer* next_buffer = buffer->next(); | 3522 SlotsBuffer* next_buffer = buffer->next(); |
| 3338 DeallocateBuffer(buffer); | 3523 DeallocateBuffer(buffer); |
| 3339 buffer = next_buffer; | 3524 buffer = next_buffer; |
| 3340 } | 3525 } |
| 3341 *buffer_address = NULL; | 3526 *buffer_address = NULL; |
| 3342 } | 3527 } |
| 3343 | 3528 |
| 3344 | 3529 |
| 3345 } } // namespace v8::internal | 3530 } } // namespace v8::internal |
| OLD | NEW |