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 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 356 #endif | 356 #endif |
| 357 if (Marking::IsBlack(old_mark_bit)) { | 357 if (Marking::IsBlack(old_mark_bit)) { |
| 358 Marking::MarkBlack(new_mark_bit); | 358 Marking::MarkBlack(new_mark_bit); |
| 359 old_mark_bit.Clear(); | 359 old_mark_bit.Clear(); |
| 360 return true; | 360 return true; |
| 361 } else if (Marking::IsGrey(old_mark_bit)) { | 361 } else if (Marking::IsGrey(old_mark_bit)) { |
| 362 old_mark_bit.Next().Clear(); | 362 old_mark_bit.Next().Clear(); |
| 363 heap_->incremental_marking()->WhiteToGreyAndPush( | 363 heap_->incremental_marking()->WhiteToGreyAndPush( |
| 364 HeapObject::FromAddress(new_start), new_mark_bit); | 364 HeapObject::FromAddress(new_start), new_mark_bit); |
| 365 heap_->incremental_marking()->RestartIfNotMarking(); | 365 heap_->incremental_marking()->RestartIfNotMarking(); |
| 366 // TODO(gc): if we shift huge array in the loop we might end up pushing | |
| 367 // too much into the marking deque. Maybe we should check one or two | |
| 368 // elements on top/bottom of the marking deque to see whether they are | |
| 369 // equal to old_start. | |
| 370 } | 366 } |
| 371 | 367 |
| 372 #ifdef DEBUG | 368 #ifdef DEBUG |
| 373 ObjectColor new_color = Color(new_mark_bit); | 369 ObjectColor new_color = Color(new_mark_bit); |
| 374 ASSERT(new_color == old_color); | 370 ASSERT(new_color == old_color); |
| 375 #endif | 371 #endif |
| 376 return false; | 372 return false; |
| 377 } | 373 } |
| 378 MarkBit old_mark_bit = MarkBitFrom(old_start); | 374 MarkBit old_mark_bit = MarkBitFrom(old_start); |
| 379 if (!old_mark_bit.Get()) { | 375 if (!old_mark_bit.Get()) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 395 if (space->IsFragmented(p)) { | 391 if (space->IsFragmented(p)) { |
| 396 AddEvacuationCandidate(p); | 392 AddEvacuationCandidate(p); |
| 397 } else { | 393 } else { |
| 398 p->ClearEvacuationCandidate(); | 394 p->ClearEvacuationCandidate(); |
| 399 } | 395 } |
| 400 } | 396 } |
| 401 } | 397 } |
| 402 | 398 |
| 403 | 399 |
| 404 void MarkCompactCollector::Prepare(GCTracer* tracer) { | 400 void MarkCompactCollector::Prepare(GCTracer* tracer) { |
| 405 // TODO(gc) re-enable code flushing. | |
| 406 FLAG_flush_code = false; | 401 FLAG_flush_code = false; |
| 407 FLAG_always_compact = false; | 402 FLAG_always_compact = false; |
| 408 | 403 |
| 409 // Disable collection of maps if incremental marking is enabled. | 404 // Disable collection of maps if incremental marking is enabled. |
| 410 // TODO(gc) improve maps collection algorithm to work with incremental | 405 // Map collection algorithm relies on a special map transition tree traversal |
| 411 // marking. | 406 // order which is not implemented for incremental marking. |
|
Erik Corry
2011/08/16 11:17:20
Do we have a bug number for map collection?
| |
| 412 // TODO(gc) consider oscillating collect_maps_ on and off when possible. This | |
| 413 // will allow map transition trees to die from both root and leaves. | |
| 414 collect_maps_ = FLAG_collect_maps && | 407 collect_maps_ = FLAG_collect_maps && |
| 415 !heap()->incremental_marking()->IsMarking(); | 408 !heap()->incremental_marking()->IsMarking(); |
| 416 | 409 |
| 417 // Rather than passing the tracer around we stash it in a static member | 410 // Rather than passing the tracer around we stash it in a static member |
| 418 // variable. | 411 // variable. |
| 419 tracer_ = tracer; | 412 tracer_ = tracer; |
| 420 | 413 |
| 421 #ifdef DEBUG | 414 #ifdef DEBUG |
| 422 ASSERT(state_ == IDLE); | 415 ASSERT(state_ == IDLE); |
| 423 state_ = PREPARE_GC; | 416 state_ = PREPARE_GC; |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 647 | 640 |
| 648 Object* second = reinterpret_cast<ConsString*>(object)->unchecked_second(); | 641 Object* second = reinterpret_cast<ConsString*>(object)->unchecked_second(); |
| 649 Heap* heap = map->GetHeap(); | 642 Heap* heap = map->GetHeap(); |
| 650 if (second != heap->empty_string()) { | 643 if (second != heap->empty_string()) { |
| 651 return object; | 644 return object; |
| 652 } | 645 } |
| 653 | 646 |
| 654 // Since we don't have the object's start, it is impossible to update the | 647 // Since we don't have the object's start, it is impossible to update the |
| 655 // page dirty marks. Therefore, we only replace the string with its left | 648 // page dirty marks. Therefore, we only replace the string with its left |
| 656 // substring when page dirty marks do not change. | 649 // substring when page dirty marks do not change. |
| 657 // TODO(gc): Seems like we could relax this restriction with store buffers. | |
| 658 Object* first = reinterpret_cast<ConsString*>(object)->unchecked_first(); | 650 Object* first = reinterpret_cast<ConsString*>(object)->unchecked_first(); |
| 659 if (!heap->InNewSpace(object) && heap->InNewSpace(first)) return object; | 651 if (!heap->InNewSpace(object) && heap->InNewSpace(first)) return object; |
| 660 | 652 |
| 661 *p = first; | 653 *p = first; |
| 662 return HeapObject::cast(first); | 654 return HeapObject::cast(first); |
| 663 } | 655 } |
| 664 | 656 |
| 665 | 657 |
| 666 class StaticMarkingVisitor : public StaticVisitorBase { | 658 class StaticMarkingVisitor : public StaticVisitorBase { |
| 667 public: | 659 public: |
| (...skipping 1498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2166 // Fill slots that became free with undefined value. | 2158 // Fill slots that became free with undefined value. |
| 2167 Object* undefined = heap()->undefined_value(); | 2159 Object* undefined = heap()->undefined_value(); |
| 2168 for (int i = new_number_of_transitions * step; | 2160 for (int i = new_number_of_transitions * step; |
| 2169 i < number_of_transitions * step; | 2161 i < number_of_transitions * step; |
| 2170 i++) { | 2162 i++) { |
| 2171 prototype_transitions->set_unchecked(heap_, | 2163 prototype_transitions->set_unchecked(heap_, |
| 2172 header + i, | 2164 header + i, |
| 2173 undefined, | 2165 undefined, |
| 2174 SKIP_WRITE_BARRIER); | 2166 SKIP_WRITE_BARRIER); |
| 2175 | 2167 |
| 2176 // TODO(gc) we should not evacuate first page of data space. | |
| 2177 // but we are doing it now to increase coverage. | |
| 2178 Object** undefined_slot = | 2168 Object** undefined_slot = |
| 2179 prototype_transitions->data_start() + i; | 2169 prototype_transitions->data_start() + i; |
| 2180 RecordSlot(undefined_slot, undefined_slot, undefined); | 2170 RecordSlot(undefined_slot, undefined_slot, undefined); |
| 2181 } | 2171 } |
| 2182 map->SetNumberOfProtoTransitions(new_number_of_transitions); | 2172 map->SetNumberOfProtoTransitions(new_number_of_transitions); |
| 2183 } | 2173 } |
| 2184 | 2174 |
| 2185 // Follow the chain of back pointers to find the prototype. | 2175 // Follow the chain of back pointers to find the prototype. |
| 2186 Map* current = map; | 2176 Map* current = map; |
| 2187 while (current->IsMap()) { | 2177 while (current->IsMap()) { |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2394 return String::cast(*p); | 2384 return String::cast(*p); |
| 2395 } | 2385 } |
| 2396 | 2386 |
| 2397 | 2387 |
| 2398 bool MarkCompactCollector::TryPromoteObject(HeapObject* object, | 2388 bool MarkCompactCollector::TryPromoteObject(HeapObject* object, |
| 2399 int object_size) { | 2389 int object_size) { |
| 2400 Object* result; | 2390 Object* result; |
| 2401 | 2391 |
| 2402 if (object_size > heap()->MaxObjectSizeInPagedSpace()) { | 2392 if (object_size > heap()->MaxObjectSizeInPagedSpace()) { |
| 2403 MaybeObject* maybe_result = | 2393 MaybeObject* maybe_result = |
| 2404 heap()->lo_space()->AllocateRawFixedArray(object_size); | 2394 heap()->lo_space()->AllocateRaw(object_size, NOT_EXECUTABLE); |
| 2405 if (maybe_result->ToObject(&result)) { | 2395 if (maybe_result->ToObject(&result)) { |
| 2406 HeapObject* target = HeapObject::cast(result); | 2396 HeapObject* target = HeapObject::cast(result); |
| 2407 MigrateObject(target->address(), | 2397 MigrateObject(target->address(), |
| 2408 object->address(), | 2398 object->address(), |
| 2409 object_size, | 2399 object_size, |
| 2410 LO_SPACE); | 2400 LO_SPACE); |
| 2411 heap()->mark_compact_collector()->tracer()-> | 2401 heap()->mark_compact_collector()->tracer()-> |
| 2412 increment_promoted_objects_size(object_size); | 2402 increment_promoted_objects_size(object_size); |
| 2413 return true; | 2403 return true; |
| 2414 } | 2404 } |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2604 if (map_word.IsForwardingAddress()) { | 2594 if (map_word.IsForwardingAddress()) { |
| 2605 *slot = map_word.ToForwardingAddress(); | 2595 *slot = map_word.ToForwardingAddress(); |
| 2606 ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(*slot)); | 2596 ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(*slot)); |
| 2607 } | 2597 } |
| 2608 } | 2598 } |
| 2609 } | 2599 } |
| 2610 } | 2600 } |
| 2611 | 2601 |
| 2612 | 2602 |
| 2613 static void UpdateSlotsOnPage(Page* p, ObjectVisitor* visitor) { | 2603 static void UpdateSlotsOnPage(Page* p, ObjectVisitor* visitor) { |
| 2614 // TODO(gc) this is basically clone of SweepPrecisely | |
| 2615 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); | 2604 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); |
| 2616 MarkBit::CellType* cells = p->markbits()->cells(); | 2605 MarkBit::CellType* cells = p->markbits()->cells(); |
| 2617 | 2606 |
| 2618 p->ClearFlag(MemoryChunk::WAS_SWEPT_CONSERVATIVELY); | 2607 p->ClearFlag(MemoryChunk::WAS_SWEPT_CONSERVATIVELY); |
| 2619 p->ClearFlag(MemoryChunk::RESCAN_ON_EVACUATION); | 2608 p->ClearFlag(MemoryChunk::RESCAN_ON_EVACUATION); |
| 2620 p->MarkSwept(); | 2609 p->MarkSwept(); |
| 2621 | 2610 |
| 2622 int last_cell_index = | 2611 int last_cell_index = |
| 2623 Bitmap::IndexToCell( | 2612 Bitmap::IndexToCell( |
| 2624 Bitmap::CellAlignIndex( | 2613 Bitmap::CellAlignIndex( |
| (...skipping 622 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3247 } | 3236 } |
| 3248 | 3237 |
| 3249 switch (sweeper) { | 3238 switch (sweeper) { |
| 3250 case CONSERVATIVE: { | 3239 case CONSERVATIVE: { |
| 3251 SweepConservatively(space, p); | 3240 SweepConservatively(space, p); |
| 3252 break; | 3241 break; |
| 3253 } | 3242 } |
| 3254 case LAZY_CONSERVATIVE: { | 3243 case LAZY_CONSERVATIVE: { |
| 3255 Page* next_page = p->next_page(); | 3244 Page* next_page = p->next_page(); |
| 3256 freed_bytes += SweepConservatively(space, p); | 3245 freed_bytes += SweepConservatively(space, p); |
| 3257 // TODO(gc): tweak the heuristic. | |
| 3258 if (freed_bytes >= newspace_size && p != space->LastPage()) { | 3246 if (freed_bytes >= newspace_size && p != space->LastPage()) { |
| 3259 space->SetPagesToSweep(next_page, space->LastPage()); | 3247 space->SetPagesToSweep(next_page, space->LastPage()); |
| 3260 return; | 3248 return; |
| 3261 } | 3249 } |
| 3262 break; | 3250 break; |
| 3263 } | 3251 } |
| 3264 case PRECISE: { | 3252 case PRECISE: { |
| 3265 SweepPrecisely(space, p); | 3253 SweepPrecisely(space, p); |
| 3266 break; | 3254 break; |
| 3267 } | 3255 } |
| 3268 default: { | 3256 default: { |
| 3269 UNREACHABLE(); | 3257 UNREACHABLE(); |
| 3270 } | 3258 } |
| 3271 } | 3259 } |
| 3272 } | 3260 } |
| 3273 | |
| 3274 // TODO(gc): set up allocation top and limit using the free list. | |
| 3275 } | 3261 } |
| 3276 | 3262 |
| 3277 | 3263 |
| 3278 void MarkCompactCollector::SweepSpaces() { | 3264 void MarkCompactCollector::SweepSpaces() { |
| 3279 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP); | 3265 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP); |
| 3280 #ifdef DEBUG | 3266 #ifdef DEBUG |
| 3281 state_ = SWEEP_SPACES; | 3267 state_ = SWEEP_SPACES; |
| 3282 #endif | 3268 #endif |
| 3283 SweeperType how_to_sweep = | 3269 SweeperType how_to_sweep = |
| 3284 FLAG_lazy_sweeping ? LAZY_CONSERVATIVE : CONSERVATIVE; | 3270 FLAG_lazy_sweeping ? LAZY_CONSERVATIVE : CONSERVATIVE; |
| 3285 if (sweep_precisely_) how_to_sweep = PRECISE; | 3271 if (sweep_precisely_) how_to_sweep = PRECISE; |
| 3286 // Noncompacting collections simply sweep the spaces to clear the mark | 3272 // Noncompacting collections simply sweep the spaces to clear the mark |
| 3287 // bits and free the nonlive blocks (for old and map spaces). We sweep | 3273 // bits and free the nonlive blocks (for old and map spaces). We sweep |
| 3288 // the map space last because freeing non-live maps overwrites them and | 3274 // the map space last because freeing non-live maps overwrites them and |
| 3289 // the other spaces rely on possibly non-live maps to get the sizes for | 3275 // the other spaces rely on possibly non-live maps to get the sizes for |
| 3290 // non-live objects. | 3276 // non-live objects. |
| 3291 SweepSpace(heap()->old_pointer_space(), how_to_sweep); | 3277 SweepSpace(heap()->old_pointer_space(), how_to_sweep); |
| 3292 SweepSpace(heap()->old_data_space(), how_to_sweep); | 3278 SweepSpace(heap()->old_data_space(), how_to_sweep); |
| 3293 SweepSpace(heap()->code_space(), PRECISE); | 3279 SweepSpace(heap()->code_space(), PRECISE); |
| 3294 // TODO(gc): implement specialized sweeper for cell space. | |
| 3295 SweepSpace(heap()->cell_space(), PRECISE); | 3280 SweepSpace(heap()->cell_space(), PRECISE); |
| 3296 { GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP_NEWSPACE); | 3281 { GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP_NEWSPACE); |
| 3297 EvacuateNewSpaceAndCandidates(); | 3282 EvacuateNewSpaceAndCandidates(); |
| 3298 } | 3283 } |
| 3299 // TODO(gc): ClearNonLiveTransitions depends on precise sweeping of | 3284 // ClearNonLiveTransitions depends on precise sweeping of map space to |
| 3300 // map space to detect whether unmarked map became dead in this | 3285 // detect whether unmarked map became dead in this collection or in one |
| 3301 // collection or in one of the previous ones. | 3286 // of the previous ones. |
| 3302 // TODO(gc): Implement specialized sweeper for map space. | |
| 3303 SweepSpace(heap()->map_space(), PRECISE); | 3287 SweepSpace(heap()->map_space(), PRECISE); |
| 3304 | 3288 |
| 3305 ASSERT(live_map_objects_size_ <= heap()->map_space()->Size()); | 3289 ASSERT(live_map_objects_size_ <= heap()->map_space()->Size()); |
| 3306 | 3290 |
| 3307 // Deallocate unmarked objects and clear marked bits for marked objects. | 3291 // Deallocate unmarked objects and clear marked bits for marked objects. |
| 3308 heap_->lo_space()->FreeUnmarkedObjects(); | 3292 heap_->lo_space()->FreeUnmarkedObjects(); |
| 3309 } | 3293 } |
| 3310 | 3294 |
| 3311 | 3295 |
| 3312 // Iterate the live objects in a range of addresses (eg, a page or a | 3296 // TODO(1466) ReportDeleteIfNeeded is not called currently. |
| 3313 // semispace). The live regions of the range have been linked into a list. | |
| 3314 // The first live region is [first_live_start, first_live_end), and the last | |
| 3315 // address in the range is top. The callback function is used to get the | |
| 3316 // size of each live object. | |
| 3317 int MarkCompactCollector::IterateLiveObjectsInRange( | |
| 3318 Address start, | |
| 3319 Address end, | |
| 3320 LiveObjectCallback size_func) { | |
| 3321 int live_objects_size = 0; | |
| 3322 Address current = start; | |
| 3323 while (current < end) { | |
| 3324 uint32_t encoded_map = Memory::uint32_at(current); | |
| 3325 if (encoded_map == kSingleFreeEncoding) { | |
| 3326 current += kPointerSize; | |
| 3327 } else if (encoded_map == kMultiFreeEncoding) { | |
| 3328 current += Memory::int_at(current + kIntSize); | |
| 3329 } else { | |
| 3330 int size = (this->*size_func)(HeapObject::FromAddress(current)); | |
| 3331 current += size; | |
| 3332 live_objects_size += size; | |
| 3333 } | |
| 3334 } | |
| 3335 return live_objects_size; | |
| 3336 } | |
| 3337 | |
| 3338 | |
| 3339 int MarkCompactCollector::IterateLiveObjects( | |
| 3340 NewSpace* space, LiveObjectCallback size_f) { | |
| 3341 ASSERT(MARK_LIVE_OBJECTS < state_ && state_ <= RELOCATE_OBJECTS); | |
| 3342 int accumulator = 0; | |
| 3343 Address end = space->top(); | |
| 3344 NewSpacePageIterator it(space->bottom(), end); | |
| 3345 // The bottom is at the start of its page. | |
| 3346 ASSERT_EQ(space->bottom(), | |
| 3347 NewSpacePage::FromAddress(space->bottom())->body()); | |
| 3348 while (it.has_next()) { | |
| 3349 NewSpacePage* page = it.next(); | |
| 3350 Address start = page->body(); | |
| 3351 Address limit = it.has_next() ? page->body_limit() : end; | |
| 3352 accumulator += IterateLiveObjectsInRange(start, limit, size_f); | |
| 3353 } | |
| 3354 return accumulator; | |
| 3355 } | |
| 3356 | |
| 3357 | |
| 3358 int MarkCompactCollector::IterateLiveObjects( | |
| 3359 PagedSpace* space, LiveObjectCallback size_f) { | |
| 3360 ASSERT(MARK_LIVE_OBJECTS < state_ && state_ <= RELOCATE_OBJECTS); | |
| 3361 // TODO(gc): Do a mark-sweep first with precise sweeping. | |
| 3362 int total = 0; | |
| 3363 PageIterator it(space); | |
| 3364 while (it.has_next()) { | |
| 3365 Page* p = it.next(); | |
| 3366 total += IterateLiveObjectsInRange(p->ObjectAreaStart(), | |
| 3367 p->ObjectAreaEnd(), | |
| 3368 size_f); | |
| 3369 } | |
| 3370 return total; | |
| 3371 } | |
| 3372 | |
| 3373 | |
| 3374 // TODO(gc) ReportDeleteIfNeeded is not called currently. | |
| 3375 // Our profiling tools do not expect intersections between | 3297 // Our profiling tools do not expect intersections between |
| 3376 // code objects. We should either reenable it or change our tools. | 3298 // code objects. We should either reenable it or change our tools. |
| 3377 void MarkCompactCollector::EnableCodeFlushing(bool enable) { | 3299 void MarkCompactCollector::EnableCodeFlushing(bool enable) { |
| 3378 if (enable) { | 3300 if (enable) { |
| 3379 if (code_flusher_ != NULL) return; | 3301 if (code_flusher_ != NULL) return; |
| 3380 code_flusher_ = new CodeFlusher(heap()->isolate()); | 3302 code_flusher_ = new CodeFlusher(heap()->isolate()); |
| 3381 } else { | 3303 } else { |
| 3382 if (code_flusher_ == NULL) return; | 3304 if (code_flusher_ == NULL) return; |
| 3383 delete code_flusher_; | 3305 delete code_flusher_; |
| 3384 code_flusher_ = NULL; | 3306 code_flusher_ = NULL; |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 3405 | 3327 |
| 3406 | 3328 |
| 3407 void SlotsBuffer::UpdateSlots() { | 3329 void SlotsBuffer::UpdateSlots() { |
| 3408 for (int slot_idx = 0; slot_idx < idx_; ++slot_idx) { | 3330 for (int slot_idx = 0; slot_idx < idx_; ++slot_idx) { |
| 3409 UpdateSlot(slots_[slot_idx]); | 3331 UpdateSlot(slots_[slot_idx]); |
| 3410 } | 3332 } |
| 3411 } | 3333 } |
| 3412 | 3334 |
| 3413 | 3335 |
| 3414 SlotsBuffer* SlotsBufferAllocator::AllocateBuffer(SlotsBuffer* next_buffer) { | 3336 SlotsBuffer* SlotsBufferAllocator::AllocateBuffer(SlotsBuffer* next_buffer) { |
| 3415 // TODO(gc) Consider maintaining local cache of buffers. | |
| 3416 return new SlotsBuffer(next_buffer); | 3337 return new SlotsBuffer(next_buffer); |
| 3417 } | 3338 } |
| 3418 | 3339 |
| 3419 | 3340 |
| 3420 void SlotsBufferAllocator::DeallocateBuffer(SlotsBuffer* buffer) { | 3341 void SlotsBufferAllocator::DeallocateBuffer(SlotsBuffer* buffer) { |
| 3421 delete buffer; | 3342 delete buffer; |
| 3422 } | 3343 } |
| 3423 | 3344 |
| 3424 | 3345 |
| 3425 void SlotsBufferAllocator::DeallocateChain(SlotsBuffer** buffer_address) { | 3346 void SlotsBufferAllocator::DeallocateChain(SlotsBuffer** buffer_address) { |
| 3426 SlotsBuffer* buffer = *buffer_address; | 3347 SlotsBuffer* buffer = *buffer_address; |
| 3427 while (buffer != NULL) { | 3348 while (buffer != NULL) { |
| 3428 SlotsBuffer* next_buffer = buffer->next(); | 3349 SlotsBuffer* next_buffer = buffer->next(); |
| 3429 DeallocateBuffer(buffer); | 3350 DeallocateBuffer(buffer); |
| 3430 buffer = next_buffer; | 3351 buffer = next_buffer; |
| 3431 } | 3352 } |
| 3432 *buffer_address = NULL; | 3353 *buffer_address = NULL; |
| 3433 } | 3354 } |
| 3434 | 3355 |
| 3435 | 3356 |
| 3436 } } // namespace v8::internal | 3357 } } // namespace v8::internal |
| OLD | NEW |