blob: cbd47a8763ed1f64e3c91d05390fe60eea94280e [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "execution.h"
31#include "global-handles.h"
32#include "ic-inl.h"
33#include "mark-compact.h"
34#include "stub-cache.h"
35
36namespace v8 {
37namespace internal {
38
39// -------------------------------------------------------------------------
40// MarkCompactCollector
41
42bool MarkCompactCollector::force_compaction_ = false;
43bool MarkCompactCollector::compacting_collection_ = false;
44bool MarkCompactCollector::compact_on_next_gc_ = false;
45
46int MarkCompactCollector::previous_marked_count_ = 0;
47GCTracer* MarkCompactCollector::tracer_ = NULL;
48
49
50#ifdef DEBUG
51MarkCompactCollector::CollectorState MarkCompactCollector::state_ = IDLE;
52
53// Counters used for debugging the marking phase of mark-compact or mark-sweep
54// collection.
55int MarkCompactCollector::live_bytes_ = 0;
56int MarkCompactCollector::live_young_objects_ = 0;
57int MarkCompactCollector::live_old_data_objects_ = 0;
58int MarkCompactCollector::live_old_pointer_objects_ = 0;
59int MarkCompactCollector::live_code_objects_ = 0;
60int MarkCompactCollector::live_map_objects_ = 0;
61int MarkCompactCollector::live_cell_objects_ = 0;
62int MarkCompactCollector::live_lo_objects_ = 0;
63#endif
64
65void MarkCompactCollector::CollectGarbage() {
66 // Make sure that Prepare() has been called. The individual steps below will
67 // update the state as they proceed.
68 ASSERT(state_ == PREPARE_GC);
69
70 // Prepare has selected whether to compact the old generation or not.
71 // Tell the tracer.
72 if (IsCompacting()) tracer_->set_is_compacting();
73
74 MarkLiveObjects();
75
76 if (FLAG_collect_maps) ClearNonLiveTransitions();
77
78 SweepLargeObjectSpace();
79
80 if (IsCompacting()) {
81 EncodeForwardingAddresses();
82
83 UpdatePointers();
84
85 RelocateObjects();
86
87 RebuildRSets();
88
89 } else {
90 SweepSpaces();
91 }
92
93 Finish();
94
95 // Save the count of marked objects remaining after the collection and
96 // null out the GC tracer.
97 previous_marked_count_ = tracer_->marked_count();
98 ASSERT(previous_marked_count_ == 0);
99 tracer_ = NULL;
100}
101
102
103void MarkCompactCollector::Prepare(GCTracer* tracer) {
104 // Rather than passing the tracer around we stash it in a static member
105 // variable.
106 tracer_ = tracer;
107
108#ifdef DEBUG
109 ASSERT(state_ == IDLE);
110 state_ = PREPARE_GC;
111#endif
112 ASSERT(!FLAG_always_compact || !FLAG_never_compact);
113
114 compacting_collection_ =
115 FLAG_always_compact || force_compaction_ || compact_on_next_gc_;
116 compact_on_next_gc_ = false;
117
118 if (FLAG_never_compact) compacting_collection_ = false;
119 if (FLAG_collect_maps) CreateBackPointers();
120
121#ifdef DEBUG
122 if (compacting_collection_) {
123 // We will write bookkeeping information to the remembered set area
124 // starting now.
125 Page::set_rset_state(Page::NOT_IN_USE);
126 }
127#endif
128
129 PagedSpaces spaces;
130 while (PagedSpace* space = spaces.next()) {
131 space->PrepareForMarkCompact(compacting_collection_);
132 }
133
134#ifdef DEBUG
135 live_bytes_ = 0;
136 live_young_objects_ = 0;
137 live_old_pointer_objects_ = 0;
138 live_old_data_objects_ = 0;
139 live_code_objects_ = 0;
140 live_map_objects_ = 0;
141 live_cell_objects_ = 0;
142 live_lo_objects_ = 0;
143#endif
144}
145
146
147void MarkCompactCollector::Finish() {
148#ifdef DEBUG
149 ASSERT(state_ == SWEEP_SPACES || state_ == REBUILD_RSETS);
150 state_ = IDLE;
151#endif
152 // The stub cache is not traversed during GC; clear the cache to
153 // force lazy re-initialization of it. This must be done after the
154 // GC, because it relies on the new address of certain old space
155 // objects (empty string, illegal builtin).
156 StubCache::Clear();
157
158 // If we've just compacted old space there's no reason to check the
159 // fragmentation limit. Just return.
160 if (HasCompacted()) return;
161
162 // We compact the old generation on the next GC if it has gotten too
163 // fragmented (ie, we could recover an expected amount of space by
164 // reclaiming the waste and free list blocks).
165 static const int kFragmentationLimit = 15; // Percent.
166 static const int kFragmentationAllowed = 1 * MB; // Absolute.
167 int old_gen_recoverable = 0;
168 int old_gen_used = 0;
169
170 OldSpaces spaces;
171 while (OldSpace* space = spaces.next()) {
172 old_gen_recoverable += space->Waste() + space->AvailableFree();
173 old_gen_used += space->Size();
174 }
175
176 int old_gen_fragmentation =
177 static_cast<int>((old_gen_recoverable * 100.0) / old_gen_used);
178 if (old_gen_fragmentation > kFragmentationLimit &&
179 old_gen_recoverable > kFragmentationAllowed) {
180 compact_on_next_gc_ = true;
181 }
182}
183
184
185// -------------------------------------------------------------------------
186// Phase 1: tracing and marking live objects.
187// before: all objects are in normal state.
188// after: a live object's map pointer is marked as '00'.
189
190// Marking all live objects in the heap as part of mark-sweep or mark-compact
191// collection. Before marking, all objects are in their normal state. After
192// marking, live objects' map pointers are marked indicating that the object
193// has been found reachable.
194//
195// The marking algorithm is a (mostly) depth-first (because of possible stack
196// overflow) traversal of the graph of objects reachable from the roots. It
197// uses an explicit stack of pointers rather than recursion. The young
198// generation's inactive ('from') space is used as a marking stack. The
199// objects in the marking stack are the ones that have been reached and marked
200// but their children have not yet been visited.
201//
202// The marking stack can overflow during traversal. In that case, we set an
203// overflow flag. When the overflow flag is set, we continue marking objects
204// reachable from the objects on the marking stack, but no longer push them on
205// the marking stack. Instead, we mark them as both marked and overflowed.
206// When the stack is in the overflowed state, objects marked as overflowed
207// have been reached and marked but their children have not been visited yet.
208// After emptying the marking stack, we clear the overflow flag and traverse
209// the heap looking for objects marked as overflowed, push them on the stack,
210// and continue with marking. This process repeats until all reachable
211// objects have been marked.
212
213static MarkingStack marking_stack;
214
215
216static inline HeapObject* ShortCircuitConsString(Object** p) {
217 // Optimization: If the heap object pointed to by p is a non-symbol
218 // cons string whose right substring is Heap::empty_string, update
219 // it in place to its left substring. Return the updated value.
220 //
221 // Here we assume that if we change *p, we replace it with a heap object
222 // (ie, the left substring of a cons string is always a heap object).
223 //
224 // The check performed is:
225 // object->IsConsString() && !object->IsSymbol() &&
226 // (ConsString::cast(object)->second() == Heap::empty_string())
227 // except the maps for the object and its possible substrings might be
228 // marked.
229 HeapObject* object = HeapObject::cast(*p);
230 MapWord map_word = object->map_word();
231 map_word.ClearMark();
232 InstanceType type = map_word.ToMap()->instance_type();
233 if ((type & kShortcutTypeMask) != kShortcutTypeTag) return object;
234
235 Object* second = reinterpret_cast<ConsString*>(object)->unchecked_second();
236 if (second != Heap::raw_unchecked_empty_string()) {
237 return object;
238 }
239
240 // Since we don't have the object's start, it is impossible to update the
241 // remembered set. Therefore, we only replace the string with its left
242 // substring when the remembered set does not change.
243 Object* first = reinterpret_cast<ConsString*>(object)->unchecked_first();
244 if (!Heap::InNewSpace(object) && Heap::InNewSpace(first)) return object;
245
246 *p = first;
247 return HeapObject::cast(first);
248}
249
250
251// Helper class for marking pointers in HeapObjects.
252class MarkingVisitor : public ObjectVisitor {
253 public:
254 void VisitPointer(Object** p) {
255 MarkObjectByPointer(p);
256 }
257
258 void VisitPointers(Object** start, Object** end) {
259 // Mark all objects pointed to in [start, end).
260 const int kMinRangeForMarkingRecursion = 64;
261 if (end - start >= kMinRangeForMarkingRecursion) {
262 if (VisitUnmarkedObjects(start, end)) return;
263 // We are close to a stack overflow, so just mark the objects.
264 }
265 for (Object** p = start; p < end; p++) MarkObjectByPointer(p);
266 }
267
268 void VisitCodeTarget(RelocInfo* rinfo) {
269 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
270 Code* code = Code::GetCodeFromTargetAddress(rinfo->target_address());
271 if (FLAG_cleanup_ics_at_gc && code->is_inline_cache_stub()) {
272 IC::Clear(rinfo->pc());
273 // Please note targets for cleared inline cached do not have to be
274 // marked since they are contained in Heap::non_monomorphic_cache().
275 } else {
276 MarkCompactCollector::MarkObject(code);
277 }
278 }
279
280 void VisitDebugTarget(RelocInfo* rinfo) {
281 ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()) &&
282 rinfo->IsCallInstruction());
283 HeapObject* code = Code::GetCodeFromTargetAddress(rinfo->call_address());
284 MarkCompactCollector::MarkObject(code);
285 // When compacting we convert the call to a real object pointer.
286 if (IsCompacting()) rinfo->set_call_object(code);
287 }
288
289 private:
290 // Mark object pointed to by p.
291 void MarkObjectByPointer(Object** p) {
292 if (!(*p)->IsHeapObject()) return;
293 HeapObject* object = ShortCircuitConsString(p);
294 MarkCompactCollector::MarkObject(object);
295 }
296
297 // Tells whether the mark sweep collection will perform compaction.
298 bool IsCompacting() { return MarkCompactCollector::IsCompacting(); }
299
300 // Visit an unmarked object.
301 void VisitUnmarkedObject(HeapObject* obj) {
302#ifdef DEBUG
303 ASSERT(Heap::Contains(obj));
304 ASSERT(!obj->IsMarked());
305#endif
306 Map* map = obj->map();
307 MarkCompactCollector::SetMark(obj);
308 // Mark the map pointer and the body.
309 MarkCompactCollector::MarkObject(map);
310 obj->IterateBody(map->instance_type(), obj->SizeFromMap(map), this);
311 }
312
313 // Visit all unmarked objects pointed to by [start, end).
314 // Returns false if the operation fails (lack of stack space).
315 inline bool VisitUnmarkedObjects(Object** start, Object** end) {
316 // Return false is we are close to the stack limit.
317 StackLimitCheck check;
318 if (check.HasOverflowed()) return false;
319
320 // Visit the unmarked objects.
321 for (Object** p = start; p < end; p++) {
322 if (!(*p)->IsHeapObject()) continue;
323 HeapObject* obj = HeapObject::cast(*p);
324 if (obj->IsMarked()) continue;
325 VisitUnmarkedObject(obj);
326 }
327 return true;
328 }
329};
330
331
332// Visitor class for marking heap roots.
333class RootMarkingVisitor : public ObjectVisitor {
334 public:
335 void VisitPointer(Object** p) {
336 MarkObjectByPointer(p);
337 }
338
339 void VisitPointers(Object** start, Object** end) {
340 for (Object** p = start; p < end; p++) MarkObjectByPointer(p);
341 }
342
343 MarkingVisitor* stack_visitor() { return &stack_visitor_; }
344
345 private:
346 MarkingVisitor stack_visitor_;
347
348 void MarkObjectByPointer(Object** p) {
349 if (!(*p)->IsHeapObject()) return;
350
351 // Replace flat cons strings in place.
352 HeapObject* object = ShortCircuitConsString(p);
353 if (object->IsMarked()) return;
354
355 Map* map = object->map();
356 // Mark the object.
357 MarkCompactCollector::SetMark(object);
358 // Mark the map pointer and body, and push them on the marking stack.
359 MarkCompactCollector::MarkObject(map);
360 object->IterateBody(map->instance_type(), object->SizeFromMap(map),
361 &stack_visitor_);
362
363 // Mark all the objects reachable from the map and body. May leave
364 // overflowed objects in the heap.
365 MarkCompactCollector::EmptyMarkingStack(&stack_visitor_);
366 }
367};
368
369
370// Helper class for pruning the symbol table.
371class SymbolTableCleaner : public ObjectVisitor {
372 public:
373 SymbolTableCleaner() : pointers_removed_(0) { }
374 void VisitPointers(Object** start, Object** end) {
375 // Visit all HeapObject pointers in [start, end).
376 for (Object** p = start; p < end; p++) {
377 if ((*p)->IsHeapObject() && !HeapObject::cast(*p)->IsMarked()) {
378 // Check if the symbol being pruned is an external symbol. We need to
379 // delete the associated external data as this symbol is going away.
380
381 // Since the object is not marked we can access its map word safely
382 // without having to worry about marking bits in the object header.
383 Map* map = HeapObject::cast(*p)->map();
384 // Since no objects have yet been moved we can safely access the map of
385 // the object.
386 uint32_t type = map->instance_type();
387 bool is_external = (type & kStringRepresentationMask) ==
388 kExternalStringTag;
389 if (is_external) {
390 bool is_two_byte = (type & kStringEncodingMask) == kTwoByteStringTag;
391 byte* resource_addr = reinterpret_cast<byte*>(*p) +
392 ExternalString::kResourceOffset -
393 kHeapObjectTag;
394 if (is_two_byte) {
395 v8::String::ExternalStringResource** resource =
396 reinterpret_cast<v8::String::ExternalStringResource**>
397 (resource_addr);
398 delete *resource;
399 // Clear the resource pointer in the symbol.
400 *resource = NULL;
401 } else {
402 v8::String::ExternalAsciiStringResource** resource =
403 reinterpret_cast<v8::String::ExternalAsciiStringResource**>
404 (resource_addr);
405 delete *resource;
406 // Clear the resource pointer in the symbol.
407 *resource = NULL;
408 }
409 }
410 // Set the entry to null_value (as deleted).
411 *p = Heap::raw_unchecked_null_value();
412 pointers_removed_++;
413 }
414 }
415 }
416
417 int PointersRemoved() {
418 return pointers_removed_;
419 }
420 private:
421 int pointers_removed_;
422};
423
424
425void MarkCompactCollector::MarkUnmarkedObject(HeapObject* object) {
426 ASSERT(!object->IsMarked());
427 ASSERT(Heap::Contains(object));
428 if (object->IsMap()) {
429 Map* map = Map::cast(object);
430 if (FLAG_cleanup_caches_in_maps_at_gc) {
431 map->ClearCodeCache();
432 }
433 SetMark(map);
434 if (FLAG_collect_maps &&
435 map->instance_type() >= FIRST_JS_OBJECT_TYPE &&
436 map->instance_type() <= JS_FUNCTION_TYPE) {
437 MarkMapContents(map);
438 } else {
439 marking_stack.Push(map);
440 }
441 } else {
442 SetMark(object);
443 marking_stack.Push(object);
444 }
445}
446
447
448void MarkCompactCollector::MarkMapContents(Map* map) {
449 MarkDescriptorArray(reinterpret_cast<DescriptorArray*>(
450 *HeapObject::RawField(map, Map::kInstanceDescriptorsOffset)));
451
452 // Mark the Object* fields of the Map.
453 // Since the descriptor array has been marked already, it is fine
454 // that one of these fields contains a pointer to it.
455 MarkingVisitor visitor; // Has no state or contents.
456 visitor.VisitPointers(HeapObject::RawField(map, Map::kPrototypeOffset),
457 HeapObject::RawField(map, Map::kSize));
458}
459
460
461void MarkCompactCollector::MarkDescriptorArray(
462 DescriptorArray* descriptors) {
463 if (descriptors->IsMarked()) return;
464 // Empty descriptor array is marked as a root before any maps are marked.
465 ASSERT(descriptors != Heap::raw_unchecked_empty_descriptor_array());
466 SetMark(descriptors);
467
468 FixedArray* contents = reinterpret_cast<FixedArray*>(
469 descriptors->get(DescriptorArray::kContentArrayIndex));
470 ASSERT(contents->IsHeapObject());
471 ASSERT(!contents->IsMarked());
472 ASSERT(contents->IsFixedArray());
473 ASSERT(contents->length() >= 2);
474 SetMark(contents);
475 // Contents contains (value, details) pairs. If the details say
476 // that the type of descriptor is MAP_TRANSITION, CONSTANT_TRANSITION,
477 // or NULL_DESCRIPTOR, we don't mark the value as live. Only for
478 // type MAP_TRANSITION is the value a Object* (a Map*).
479 for (int i = 0; i < contents->length(); i += 2) {
480 // If the pair (value, details) at index i, i+1 is not
481 // a transition or null descriptor, mark the value.
482 PropertyDetails details(Smi::cast(contents->get(i + 1)));
483 if (details.type() < FIRST_PHANTOM_PROPERTY_TYPE) {
484 HeapObject* object = reinterpret_cast<HeapObject*>(contents->get(i));
485 if (object->IsHeapObject() && !object->IsMarked()) {
486 SetMark(object);
487 marking_stack.Push(object);
488 }
489 }
490 }
491 // The DescriptorArray descriptors contains a pointer to its contents array,
492 // but the contents array is already marked.
493 marking_stack.Push(descriptors);
494}
495
496
497void MarkCompactCollector::CreateBackPointers() {
498 HeapObjectIterator iterator(Heap::map_space());
499 while (iterator.has_next()) {
500 Object* next_object = iterator.next();
501 if (next_object->IsMap()) { // Could also be ByteArray on free list.
502 Map* map = Map::cast(next_object);
503 if (map->instance_type() >= FIRST_JS_OBJECT_TYPE &&
504 map->instance_type() <= JS_FUNCTION_TYPE) {
505 map->CreateBackPointers();
506 } else {
507 ASSERT(map->instance_descriptors() == Heap::empty_descriptor_array());
508 }
509 }
510 }
511}
512
513
514static int OverflowObjectSize(HeapObject* obj) {
515 // Recover the normal map pointer, it might be marked as live and
516 // overflowed.
517 MapWord map_word = obj->map_word();
518 map_word.ClearMark();
519 map_word.ClearOverflow();
520 return obj->SizeFromMap(map_word.ToMap());
521}
522
523
524// Fill the marking stack with overflowed objects returned by the given
525// iterator. Stop when the marking stack is filled or the end of the space
526// is reached, whichever comes first.
527template<class T>
528static void ScanOverflowedObjects(T* it) {
529 // The caller should ensure that the marking stack is initially not full,
530 // so that we don't waste effort pointlessly scanning for objects.
531 ASSERT(!marking_stack.is_full());
532
533 while (it->has_next()) {
534 HeapObject* object = it->next();
535 if (object->IsOverflowed()) {
536 object->ClearOverflow();
537 ASSERT(object->IsMarked());
538 ASSERT(Heap::Contains(object));
539 marking_stack.Push(object);
540 if (marking_stack.is_full()) return;
541 }
542 }
543}
544
545
546bool MarkCompactCollector::IsUnmarkedHeapObject(Object** p) {
547 return (*p)->IsHeapObject() && !HeapObject::cast(*p)->IsMarked();
548}
549
550
551class SymbolMarkingVisitor : public ObjectVisitor {
552 public:
553 void VisitPointers(Object** start, Object** end) {
554 MarkingVisitor marker;
555 for (Object** p = start; p < end; p++) {
556 if (!(*p)->IsHeapObject()) continue;
557
558 HeapObject* object = HeapObject::cast(*p);
559 // If the object is marked, we have marked or are in the process
560 // of marking subparts.
561 if (object->IsMarked()) continue;
562
563 // The object is unmarked, we do not need to unmark to use its
564 // map.
565 Map* map = object->map();
566 object->IterateBody(map->instance_type(),
567 object->SizeFromMap(map),
568 &marker);
569 }
570 }
571};
572
573
574void MarkCompactCollector::MarkSymbolTable() {
575 // Objects reachable from symbols are marked as live so as to ensure
576 // that if the symbol itself remains alive after GC for any reason,
577 // and if it is a sliced string or a cons string backed by an
578 // external string (even indirectly), then the external string does
579 // not receive a weak reference callback.
580 SymbolTable* symbol_table = Heap::raw_unchecked_symbol_table();
581 // Mark the symbol table itself.
582 SetMark(symbol_table);
583 // Explicitly mark the prefix.
584 MarkingVisitor marker;
585 symbol_table->IteratePrefix(&marker);
586 ProcessMarkingStack(&marker);
587 // Mark subparts of the symbols but not the symbols themselves
588 // (unless reachable from another symbol).
589 SymbolMarkingVisitor symbol_marker;
590 symbol_table->IterateElements(&symbol_marker);
591 ProcessMarkingStack(&marker);
592}
593
594
595void MarkCompactCollector::MarkRoots(RootMarkingVisitor* visitor) {
596 // Mark the heap roots including global variables, stack variables,
597 // etc., and all objects reachable from them.
598 Heap::IterateStrongRoots(visitor);
599
600 // Handle the symbol table specially.
601 MarkSymbolTable();
602
603 // There may be overflowed objects in the heap. Visit them now.
604 while (marking_stack.overflowed()) {
605 RefillMarkingStack();
606 EmptyMarkingStack(visitor->stack_visitor());
607 }
608}
609
610
611void MarkCompactCollector::MarkObjectGroups() {
612 List<ObjectGroup*>* object_groups = GlobalHandles::ObjectGroups();
613
614 for (int i = 0; i < object_groups->length(); i++) {
615 ObjectGroup* entry = object_groups->at(i);
616 if (entry == NULL) continue;
617
618 List<Object**>& objects = entry->objects_;
619 bool group_marked = false;
620 for (int j = 0; j < objects.length(); j++) {
621 Object* object = *objects[j];
622 if (object->IsHeapObject() && HeapObject::cast(object)->IsMarked()) {
623 group_marked = true;
624 break;
625 }
626 }
627
628 if (!group_marked) continue;
629
630 // An object in the group is marked, so mark as gray all white heap
631 // objects in the group.
632 for (int j = 0; j < objects.length(); ++j) {
633 if ((*objects[j])->IsHeapObject()) {
634 MarkObject(HeapObject::cast(*objects[j]));
635 }
636 }
637 // Once the entire group has been colored gray, set the object group
638 // to NULL so it won't be processed again.
639 delete object_groups->at(i);
640 object_groups->at(i) = NULL;
641 }
642}
643
644
645// Mark all objects reachable from the objects on the marking stack.
646// Before: the marking stack contains zero or more heap object pointers.
647// After: the marking stack is empty, and all objects reachable from the
648// marking stack have been marked, or are overflowed in the heap.
649void MarkCompactCollector::EmptyMarkingStack(MarkingVisitor* visitor) {
650 while (!marking_stack.is_empty()) {
651 HeapObject* object = marking_stack.Pop();
652 ASSERT(object->IsHeapObject());
653 ASSERT(Heap::Contains(object));
654 ASSERT(object->IsMarked());
655 ASSERT(!object->IsOverflowed());
656
657 // Because the object is marked, we have to recover the original map
658 // pointer and use it to mark the object's body.
659 MapWord map_word = object->map_word();
660 map_word.ClearMark();
661 Map* map = map_word.ToMap();
662 MarkObject(map);
663 object->IterateBody(map->instance_type(), object->SizeFromMap(map),
664 visitor);
665 }
666}
667
668
669// Sweep the heap for overflowed objects, clear their overflow bits, and
670// push them on the marking stack. Stop early if the marking stack fills
671// before sweeping completes. If sweeping completes, there are no remaining
672// overflowed objects in the heap so the overflow flag on the markings stack
673// is cleared.
674void MarkCompactCollector::RefillMarkingStack() {
675 ASSERT(marking_stack.overflowed());
676
677 SemiSpaceIterator new_it(Heap::new_space(), &OverflowObjectSize);
678 ScanOverflowedObjects(&new_it);
679 if (marking_stack.is_full()) return;
680
681 HeapObjectIterator old_pointer_it(Heap::old_pointer_space(),
682 &OverflowObjectSize);
683 ScanOverflowedObjects(&old_pointer_it);
684 if (marking_stack.is_full()) return;
685
686 HeapObjectIterator old_data_it(Heap::old_data_space(), &OverflowObjectSize);
687 ScanOverflowedObjects(&old_data_it);
688 if (marking_stack.is_full()) return;
689
690 HeapObjectIterator code_it(Heap::code_space(), &OverflowObjectSize);
691 ScanOverflowedObjects(&code_it);
692 if (marking_stack.is_full()) return;
693
694 HeapObjectIterator map_it(Heap::map_space(), &OverflowObjectSize);
695 ScanOverflowedObjects(&map_it);
696 if (marking_stack.is_full()) return;
697
698 HeapObjectIterator cell_it(Heap::cell_space(), &OverflowObjectSize);
699 ScanOverflowedObjects(&cell_it);
700 if (marking_stack.is_full()) return;
701
702 LargeObjectIterator lo_it(Heap::lo_space(), &OverflowObjectSize);
703 ScanOverflowedObjects(&lo_it);
704 if (marking_stack.is_full()) return;
705
706 marking_stack.clear_overflowed();
707}
708
709
710// Mark all objects reachable (transitively) from objects on the marking
711// stack. Before: the marking stack contains zero or more heap object
712// pointers. After: the marking stack is empty and there are no overflowed
713// objects in the heap.
714void MarkCompactCollector::ProcessMarkingStack(MarkingVisitor* visitor) {
715 EmptyMarkingStack(visitor);
716 while (marking_stack.overflowed()) {
717 RefillMarkingStack();
718 EmptyMarkingStack(visitor);
719 }
720}
721
722
723void MarkCompactCollector::ProcessObjectGroups(MarkingVisitor* visitor) {
724 bool work_to_do = true;
725 ASSERT(marking_stack.is_empty());
726 while (work_to_do) {
727 MarkObjectGroups();
728 work_to_do = !marking_stack.is_empty();
729 ProcessMarkingStack(visitor);
730 }
731}
732
733
734void MarkCompactCollector::MarkLiveObjects() {
735#ifdef DEBUG
736 ASSERT(state_ == PREPARE_GC);
737 state_ = MARK_LIVE_OBJECTS;
738#endif
739 // The to space contains live objects, the from space is used as a marking
740 // stack.
741 marking_stack.Initialize(Heap::new_space()->FromSpaceLow(),
742 Heap::new_space()->FromSpaceHigh());
743
744 ASSERT(!marking_stack.overflowed());
745
746 RootMarkingVisitor root_visitor;
747 MarkRoots(&root_visitor);
748
749 // The objects reachable from the roots are marked, yet unreachable
750 // objects are unmarked. Mark objects reachable from object groups
751 // containing at least one marked object, and continue until no new
752 // objects are reachable from the object groups.
753 ProcessObjectGroups(root_visitor.stack_visitor());
754
755 // The objects reachable from the roots or object groups are marked,
756 // yet unreachable objects are unmarked. Mark objects reachable
757 // only from weak global handles.
758 //
759 // First we identify nonlive weak handles and mark them as pending
760 // destruction.
761 GlobalHandles::IdentifyWeakHandles(&IsUnmarkedHeapObject);
762 // Then we mark the objects and process the transitive closure.
763 GlobalHandles::IterateWeakRoots(&root_visitor);
764 while (marking_stack.overflowed()) {
765 RefillMarkingStack();
766 EmptyMarkingStack(root_visitor.stack_visitor());
767 }
768
769 // Repeat the object groups to mark unmarked groups reachable from the
770 // weak roots.
771 ProcessObjectGroups(root_visitor.stack_visitor());
772
773 // Prune the symbol table removing all symbols only pointed to by the
774 // symbol table. Cannot use symbol_table() here because the symbol
775 // table is marked.
776 SymbolTable* symbol_table = Heap::raw_unchecked_symbol_table();
777 SymbolTableCleaner v;
778 symbol_table->IterateElements(&v);
779 symbol_table->ElementsRemoved(v.PointersRemoved());
780
781 // Remove object groups after marking phase.
782 GlobalHandles::RemoveObjectGroups();
783}
784
785
786static int CountMarkedCallback(HeapObject* obj) {
787 MapWord map_word = obj->map_word();
788 map_word.ClearMark();
789 return obj->SizeFromMap(map_word.ToMap());
790}
791
792
793#ifdef DEBUG
794void MarkCompactCollector::UpdateLiveObjectCount(HeapObject* obj) {
795 live_bytes_ += obj->Size();
796 if (Heap::new_space()->Contains(obj)) {
797 live_young_objects_++;
798 } else if (Heap::map_space()->Contains(obj)) {
799 ASSERT(obj->IsMap());
800 live_map_objects_++;
801 } else if (Heap::cell_space()->Contains(obj)) {
802 ASSERT(obj->IsJSGlobalPropertyCell());
803 live_cell_objects_++;
804 } else if (Heap::old_pointer_space()->Contains(obj)) {
805 live_old_pointer_objects_++;
806 } else if (Heap::old_data_space()->Contains(obj)) {
807 live_old_data_objects_++;
808 } else if (Heap::code_space()->Contains(obj)) {
809 live_code_objects_++;
810 } else if (Heap::lo_space()->Contains(obj)) {
811 live_lo_objects_++;
812 } else {
813 UNREACHABLE();
814 }
815}
816#endif // DEBUG
817
818
819void MarkCompactCollector::SweepLargeObjectSpace() {
820#ifdef DEBUG
821 ASSERT(state_ == MARK_LIVE_OBJECTS);
822 state_ =
823 compacting_collection_ ? ENCODE_FORWARDING_ADDRESSES : SWEEP_SPACES;
824#endif
825 // Deallocate unmarked objects and clear marked bits for marked objects.
826 Heap::lo_space()->FreeUnmarkedObjects();
827}
828
829// Safe to use during marking phase only.
830bool MarkCompactCollector::SafeIsMap(HeapObject* object) {
831 MapWord metamap = object->map_word();
832 metamap.ClearMark();
833 return metamap.ToMap()->instance_type() == MAP_TYPE;
834}
835
836void MarkCompactCollector::ClearNonLiveTransitions() {
837 HeapObjectIterator map_iterator(Heap::map_space(), &CountMarkedCallback);
838 // Iterate over the map space, setting map transitions that go from
839 // a marked map to an unmarked map to null transitions. At the same time,
840 // set all the prototype fields of maps back to their original value,
841 // dropping the back pointers temporarily stored in the prototype field.
842 // Setting the prototype field requires following the linked list of
843 // back pointers, reversing them all at once. This allows us to find
844 // those maps with map transitions that need to be nulled, and only
845 // scan the descriptor arrays of those maps, not all maps.
846 // All of these actions are carried out only on maps of JSObects
847 // and related subtypes.
848 while (map_iterator.has_next()) {
849 Map* map = reinterpret_cast<Map*>(map_iterator.next());
850 if (!map->IsMarked() && map->IsByteArray()) continue;
851
852 ASSERT(SafeIsMap(map));
853 // Only JSObject and subtypes have map transitions and back pointers.
854 if (map->instance_type() < FIRST_JS_OBJECT_TYPE) continue;
855 if (map->instance_type() > JS_FUNCTION_TYPE) continue;
856 // Follow the chain of back pointers to find the prototype.
857 Map* current = map;
858 while (SafeIsMap(current)) {
859 current = reinterpret_cast<Map*>(current->prototype());
860 ASSERT(current->IsHeapObject());
861 }
862 Object* real_prototype = current;
863
864 // Follow back pointers, setting them to prototype,
865 // clearing map transitions when necessary.
866 current = map;
867 bool on_dead_path = !current->IsMarked();
868 Object* next;
869 while (SafeIsMap(current)) {
870 next = current->prototype();
871 // There should never be a dead map above a live map.
872 ASSERT(on_dead_path || current->IsMarked());
873
874 // A live map above a dead map indicates a dead transition.
875 // This test will always be false on the first iteration.
876 if (on_dead_path && current->IsMarked()) {
877 on_dead_path = false;
878 current->ClearNonLiveTransitions(real_prototype);
879 }
880 *HeapObject::RawField(current, Map::kPrototypeOffset) =
881 real_prototype;
882 current = reinterpret_cast<Map*>(next);
883 }
884 }
885}
886
887// -------------------------------------------------------------------------
888// Phase 2: Encode forwarding addresses.
889// When compacting, forwarding addresses for objects in old space and map
890// space are encoded in their map pointer word (along with an encoding of
891// their map pointers).
892//
893// 31 21 20 10 9 0
894// +-----------------+------------------+-----------------+
895// |forwarding offset|page offset of map|page index of map|
896// +-----------------+------------------+-----------------+
897// 11 bits 11 bits 10 bits
898//
899// An address range [start, end) can have both live and non-live objects.
900// Maximal non-live regions are marked so they can be skipped on subsequent
901// sweeps of the heap. A distinguished map-pointer encoding is used to mark
902// free regions of one-word size (in which case the next word is the start
903// of a live object). A second distinguished map-pointer encoding is used
904// to mark free regions larger than one word, and the size of the free
905// region (including the first word) is written to the second word of the
906// region.
907//
908// Any valid map page offset must lie in the object area of the page, so map
909// page offsets less than Page::kObjectStartOffset are invalid. We use a
910// pair of distinguished invalid map encodings (for single word and multiple
911// words) to indicate free regions in the page found during computation of
912// forwarding addresses and skipped over in subsequent sweeps.
913static const uint32_t kSingleFreeEncoding = 0;
914static const uint32_t kMultiFreeEncoding = 1;
915
916
917// Encode a free region, defined by the given start address and size, in the
918// first word or two of the region.
919void EncodeFreeRegion(Address free_start, int free_size) {
920 ASSERT(free_size >= kIntSize);
921 if (free_size == kIntSize) {
922 Memory::uint32_at(free_start) = kSingleFreeEncoding;
923 } else {
924 ASSERT(free_size >= 2 * kIntSize);
925 Memory::uint32_at(free_start) = kMultiFreeEncoding;
926 Memory::int_at(free_start + kIntSize) = free_size;
927 }
928
929#ifdef DEBUG
930 // Zap the body of the free region.
931 if (FLAG_enable_slow_asserts) {
932 for (int offset = 2 * kIntSize;
933 offset < free_size;
934 offset += kPointerSize) {
935 Memory::Address_at(free_start + offset) = kZapValue;
936 }
937 }
938#endif
939}
940
941
942// Try to promote all objects in new space. Heap numbers and sequential
943// strings are promoted to the code space, large objects to large object space,
944// and all others to the old space.
945inline Object* MCAllocateFromNewSpace(HeapObject* object, int object_size) {
946 Object* forwarded;
947 if (object_size > Heap::MaxObjectSizeInPagedSpace()) {
948 forwarded = Failure::Exception();
949 } else {
950 OldSpace* target_space = Heap::TargetSpace(object);
951 ASSERT(target_space == Heap::old_pointer_space() ||
952 target_space == Heap::old_data_space());
953 forwarded = target_space->MCAllocateRaw(object_size);
954 }
955 if (forwarded->IsFailure()) {
956 forwarded = Heap::new_space()->MCAllocateRaw(object_size);
957 }
958 return forwarded;
959}
960
961
962// Allocation functions for the paged spaces call the space's MCAllocateRaw.
963inline Object* MCAllocateFromOldPointerSpace(HeapObject* ignore,
964 int object_size) {
965 return Heap::old_pointer_space()->MCAllocateRaw(object_size);
966}
967
968
969inline Object* MCAllocateFromOldDataSpace(HeapObject* ignore, int object_size) {
970 return Heap::old_data_space()->MCAllocateRaw(object_size);
971}
972
973
974inline Object* MCAllocateFromCodeSpace(HeapObject* ignore, int object_size) {
975 return Heap::code_space()->MCAllocateRaw(object_size);
976}
977
978
979inline Object* MCAllocateFromMapSpace(HeapObject* ignore, int object_size) {
980 return Heap::map_space()->MCAllocateRaw(object_size);
981}
982
983
984inline Object* MCAllocateFromCellSpace(HeapObject* ignore, int object_size) {
985 return Heap::cell_space()->MCAllocateRaw(object_size);
986}
987
988
989// The forwarding address is encoded at the same offset as the current
990// to-space object, but in from space.
991inline void EncodeForwardingAddressInNewSpace(HeapObject* old_object,
992 int object_size,
993 Object* new_object,
994 int* ignored) {
995 int offset =
996 Heap::new_space()->ToSpaceOffsetForAddress(old_object->address());
997 Memory::Address_at(Heap::new_space()->FromSpaceLow() + offset) =
998 HeapObject::cast(new_object)->address();
999}
1000
1001
1002// The forwarding address is encoded in the map pointer of the object as an
1003// offset (in terms of live bytes) from the address of the first live object
1004// in the page.
1005inline void EncodeForwardingAddressInPagedSpace(HeapObject* old_object,
1006 int object_size,
1007 Object* new_object,
1008 int* offset) {
1009 // Record the forwarding address of the first live object if necessary.
1010 if (*offset == 0) {
1011 Page::FromAddress(old_object->address())->mc_first_forwarded =
1012 HeapObject::cast(new_object)->address();
1013 }
1014
1015 MapWord encoding =
1016 MapWord::EncodeAddress(old_object->map()->address(), *offset);
1017 old_object->set_map_word(encoding);
1018 *offset += object_size;
1019 ASSERT(*offset <= Page::kObjectAreaSize);
1020}
1021
1022
1023// Most non-live objects are ignored.
1024inline void IgnoreNonLiveObject(HeapObject* object) {}
1025
1026
1027// A code deletion event is logged for non-live code objects.
1028inline void LogNonLiveCodeObject(HeapObject* object) {
1029 if (object->IsCode()) LOG(CodeDeleteEvent(object->address()));
1030}
1031
1032
1033// Function template that, given a range of addresses (eg, a semispace or a
1034// paged space page), iterates through the objects in the range to clear
1035// mark bits and compute and encode forwarding addresses. As a side effect,
1036// maximal free chunks are marked so that they can be skipped on subsequent
1037// sweeps.
1038//
1039// The template parameters are an allocation function, a forwarding address
1040// encoding function, and a function to process non-live objects.
1041template<MarkCompactCollector::AllocationFunction Alloc,
1042 MarkCompactCollector::EncodingFunction Encode,
1043 MarkCompactCollector::ProcessNonLiveFunction ProcessNonLive>
1044inline void EncodeForwardingAddressesInRange(Address start,
1045 Address end,
1046 int* offset) {
1047 // The start address of the current free region while sweeping the space.
1048 // This address is set when a transition from live to non-live objects is
1049 // encountered. A value (an encoding of the 'next free region' pointer)
1050 // is written to memory at this address when a transition from non-live to
1051 // live objects is encountered.
1052 Address free_start = NULL;
1053
1054 // A flag giving the state of the previously swept object. Initially true
1055 // to ensure that free_start is initialized to a proper address before
1056 // trying to write to it.
1057 bool is_prev_alive = true;
1058
1059 int object_size; // Will be set on each iteration of the loop.
1060 for (Address current = start; current < end; current += object_size) {
1061 HeapObject* object = HeapObject::FromAddress(current);
1062 if (object->IsMarked()) {
1063 object->ClearMark();
1064 MarkCompactCollector::tracer()->decrement_marked_count();
1065 object_size = object->Size();
1066
1067 Object* forwarded = Alloc(object, object_size);
1068 // Allocation cannot fail, because we are compacting the space.
1069 ASSERT(!forwarded->IsFailure());
1070 Encode(object, object_size, forwarded, offset);
1071
1072#ifdef DEBUG
1073 if (FLAG_gc_verbose) {
1074 PrintF("forward %p -> %p.\n", object->address(),
1075 HeapObject::cast(forwarded)->address());
1076 }
1077#endif
1078 if (!is_prev_alive) { // Transition from non-live to live.
1079 EncodeFreeRegion(free_start, current - free_start);
1080 is_prev_alive = true;
1081 }
1082 } else { // Non-live object.
1083 object_size = object->Size();
1084 ProcessNonLive(object);
1085 if (is_prev_alive) { // Transition from live to non-live.
1086 free_start = current;
1087 is_prev_alive = false;
1088 }
1089 }
1090 }
1091
1092 // If we ended on a free region, mark it.
1093 if (!is_prev_alive) EncodeFreeRegion(free_start, end - free_start);
1094}
1095
1096
1097// Functions to encode the forwarding pointers in each compactable space.
1098void MarkCompactCollector::EncodeForwardingAddressesInNewSpace() {
1099 int ignored;
1100 EncodeForwardingAddressesInRange<MCAllocateFromNewSpace,
1101 EncodeForwardingAddressInNewSpace,
1102 IgnoreNonLiveObject>(
1103 Heap::new_space()->bottom(),
1104 Heap::new_space()->top(),
1105 &ignored);
1106}
1107
1108
1109template<MarkCompactCollector::AllocationFunction Alloc,
1110 MarkCompactCollector::ProcessNonLiveFunction ProcessNonLive>
1111void MarkCompactCollector::EncodeForwardingAddressesInPagedSpace(
1112 PagedSpace* space) {
1113 PageIterator it(space, PageIterator::PAGES_IN_USE);
1114 while (it.has_next()) {
1115 Page* p = it.next();
1116 // The offset of each live object in the page from the first live object
1117 // in the page.
1118 int offset = 0;
1119 EncodeForwardingAddressesInRange<Alloc,
1120 EncodeForwardingAddressInPagedSpace,
1121 ProcessNonLive>(
1122 p->ObjectAreaStart(),
1123 p->AllocationTop(),
1124 &offset);
1125 }
1126}
1127
1128
1129static void SweepSpace(NewSpace* space) {
1130 HeapObject* object;
1131 for (Address current = space->bottom();
1132 current < space->top();
1133 current += object->Size()) {
1134 object = HeapObject::FromAddress(current);
1135 if (object->IsMarked()) {
1136 object->ClearMark();
1137 MarkCompactCollector::tracer()->decrement_marked_count();
1138 } else {
1139 // We give non-live objects a map that will correctly give their size,
1140 // since their existing map might not be live after the collection.
1141 int size = object->Size();
1142 if (size >= ByteArray::kHeaderSize) {
1143 object->set_map(Heap::raw_unchecked_byte_array_map());
1144 ByteArray::cast(object)->set_length(ByteArray::LengthFor(size));
1145 } else {
1146 ASSERT(size == kPointerSize);
1147 object->set_map(Heap::raw_unchecked_one_pointer_filler_map());
1148 }
1149 ASSERT(object->Size() == size);
1150 }
1151 // The object is now unmarked for the call to Size() at the top of the
1152 // loop.
1153 }
1154}
1155
1156
1157static void SweepSpace(PagedSpace* space, DeallocateFunction dealloc) {
1158 PageIterator it(space, PageIterator::PAGES_IN_USE);
1159 while (it.has_next()) {
1160 Page* p = it.next();
1161
1162 bool is_previous_alive = true;
1163 Address free_start = NULL;
1164 HeapObject* object;
1165
1166 for (Address current = p->ObjectAreaStart();
1167 current < p->AllocationTop();
1168 current += object->Size()) {
1169 object = HeapObject::FromAddress(current);
1170 if (object->IsMarked()) {
1171 object->ClearMark();
1172 MarkCompactCollector::tracer()->decrement_marked_count();
1173 if (!is_previous_alive) { // Transition from free to live.
1174 dealloc(free_start, current - free_start);
1175 is_previous_alive = true;
1176 }
1177 } else {
1178 if (object->IsCode()) {
1179 // Notify the logger that compiled code has been collected.
1180 LOG(CodeDeleteEvent(Code::cast(object)->address()));
1181 }
1182 if (is_previous_alive) { // Transition from live to free.
1183 free_start = current;
1184 is_previous_alive = false;
1185 }
1186 }
1187 // The object is now unmarked for the call to Size() at the top of the
1188 // loop.
1189 }
1190
1191 // If the last region was not live we need to deallocate from
1192 // free_start to the allocation top in the page.
1193 if (!is_previous_alive) {
1194 int free_size = p->AllocationTop() - free_start;
1195 if (free_size > 0) {
1196 dealloc(free_start, free_size);
1197 }
1198 }
1199 }
1200}
1201
1202
1203void MarkCompactCollector::DeallocateOldPointerBlock(Address start,
1204 int size_in_bytes) {
1205 Heap::ClearRSetRange(start, size_in_bytes);
1206 Heap::old_pointer_space()->Free(start, size_in_bytes);
1207}
1208
1209
1210void MarkCompactCollector::DeallocateOldDataBlock(Address start,
1211 int size_in_bytes) {
1212 Heap::old_data_space()->Free(start, size_in_bytes);
1213}
1214
1215
1216void MarkCompactCollector::DeallocateCodeBlock(Address start,
1217 int size_in_bytes) {
1218 Heap::code_space()->Free(start, size_in_bytes);
1219}
1220
1221
1222void MarkCompactCollector::DeallocateMapBlock(Address start,
1223 int size_in_bytes) {
1224 // Objects in map space are frequently assumed to have size Map::kSize and a
1225 // valid map in their first word. Thus, we break the free block up into
1226 // chunks and free them separately.
1227 ASSERT(size_in_bytes % Map::kSize == 0);
1228 Heap::ClearRSetRange(start, size_in_bytes);
1229 Address end = start + size_in_bytes;
1230 for (Address a = start; a < end; a += Map::kSize) {
1231 Heap::map_space()->Free(a);
1232 }
1233}
1234
1235
1236void MarkCompactCollector::DeallocateCellBlock(Address start,
1237 int size_in_bytes) {
1238 // Free-list elements in cell space are assumed to have a fixed size.
1239 // We break the free block into chunks and add them to the free list
1240 // individually.
1241 int size = Heap::cell_space()->object_size_in_bytes();
1242 ASSERT(size_in_bytes % size == 0);
1243 Heap::ClearRSetRange(start, size_in_bytes);
1244 Address end = start + size_in_bytes;
1245 for (Address a = start; a < end; a += size) {
1246 Heap::cell_space()->Free(a);
1247 }
1248}
1249
1250
1251void MarkCompactCollector::EncodeForwardingAddresses() {
1252 ASSERT(state_ == ENCODE_FORWARDING_ADDRESSES);
1253 // Objects in the active semispace of the young generation may be
1254 // relocated to the inactive semispace (if not promoted). Set the
1255 // relocation info to the beginning of the inactive semispace.
1256 Heap::new_space()->MCResetRelocationInfo();
1257
1258 // Compute the forwarding pointers in each space.
1259 EncodeForwardingAddressesInPagedSpace<MCAllocateFromOldPointerSpace,
1260 IgnoreNonLiveObject>(
1261 Heap::old_pointer_space());
1262
1263 EncodeForwardingAddressesInPagedSpace<MCAllocateFromOldDataSpace,
1264 IgnoreNonLiveObject>(
1265 Heap::old_data_space());
1266
1267 EncodeForwardingAddressesInPagedSpace<MCAllocateFromCodeSpace,
1268 LogNonLiveCodeObject>(
1269 Heap::code_space());
1270
1271 EncodeForwardingAddressesInPagedSpace<MCAllocateFromCellSpace,
1272 IgnoreNonLiveObject>(
1273 Heap::cell_space());
1274
1275
1276 // Compute new space next to last after the old and code spaces have been
1277 // compacted. Objects in new space can be promoted to old or code space.
1278 EncodeForwardingAddressesInNewSpace();
1279
1280 // Compute map space last because computing forwarding addresses
1281 // overwrites non-live objects. Objects in the other spaces rely on
1282 // non-live map pointers to get the sizes of non-live objects.
1283 EncodeForwardingAddressesInPagedSpace<MCAllocateFromMapSpace,
1284 IgnoreNonLiveObject>(
1285 Heap::map_space());
1286
1287 // Write relocation info to the top page, so we can use it later. This is
1288 // done after promoting objects from the new space so we get the correct
1289 // allocation top.
1290 Heap::old_pointer_space()->MCWriteRelocationInfoToPage();
1291 Heap::old_data_space()->MCWriteRelocationInfoToPage();
1292 Heap::code_space()->MCWriteRelocationInfoToPage();
1293 Heap::map_space()->MCWriteRelocationInfoToPage();
1294 Heap::cell_space()->MCWriteRelocationInfoToPage();
1295}
1296
1297
1298void MarkCompactCollector::SweepSpaces() {
1299 ASSERT(state_ == SWEEP_SPACES);
1300 ASSERT(!IsCompacting());
1301 // Noncompacting collections simply sweep the spaces to clear the mark
1302 // bits and free the nonlive blocks (for old and map spaces). We sweep
1303 // the map space last because freeing non-live maps overwrites them and
1304 // the other spaces rely on possibly non-live maps to get the sizes for
1305 // non-live objects.
1306 SweepSpace(Heap::old_pointer_space(), &DeallocateOldPointerBlock);
1307 SweepSpace(Heap::old_data_space(), &DeallocateOldDataBlock);
1308 SweepSpace(Heap::code_space(), &DeallocateCodeBlock);
1309 SweepSpace(Heap::cell_space(), &DeallocateCellBlock);
1310 SweepSpace(Heap::new_space());
1311 SweepSpace(Heap::map_space(), &DeallocateMapBlock);
1312}
1313
1314
1315// Iterate the live objects in a range of addresses (eg, a page or a
1316// semispace). The live regions of the range have been linked into a list.
1317// The first live region is [first_live_start, first_live_end), and the last
1318// address in the range is top. The callback function is used to get the
1319// size of each live object.
1320int MarkCompactCollector::IterateLiveObjectsInRange(
1321 Address start,
1322 Address end,
1323 HeapObjectCallback size_func) {
1324 int live_objects = 0;
1325 Address current = start;
1326 while (current < end) {
1327 uint32_t encoded_map = Memory::uint32_at(current);
1328 if (encoded_map == kSingleFreeEncoding) {
1329 current += kPointerSize;
1330 } else if (encoded_map == kMultiFreeEncoding) {
1331 current += Memory::int_at(current + kIntSize);
1332 } else {
1333 live_objects++;
1334 current += size_func(HeapObject::FromAddress(current));
1335 }
1336 }
1337 return live_objects;
1338}
1339
1340
1341int MarkCompactCollector::IterateLiveObjects(NewSpace* space,
1342 HeapObjectCallback size_f) {
1343 ASSERT(MARK_LIVE_OBJECTS < state_ && state_ <= RELOCATE_OBJECTS);
1344 return IterateLiveObjectsInRange(space->bottom(), space->top(), size_f);
1345}
1346
1347
1348int MarkCompactCollector::IterateLiveObjects(PagedSpace* space,
1349 HeapObjectCallback size_f) {
1350 ASSERT(MARK_LIVE_OBJECTS < state_ && state_ <= RELOCATE_OBJECTS);
1351 int total = 0;
1352 PageIterator it(space, PageIterator::PAGES_IN_USE);
1353 while (it.has_next()) {
1354 Page* p = it.next();
1355 total += IterateLiveObjectsInRange(p->ObjectAreaStart(),
1356 p->AllocationTop(),
1357 size_f);
1358 }
1359 return total;
1360}
1361
1362
1363// -------------------------------------------------------------------------
1364// Phase 3: Update pointers
1365
1366// Helper class for updating pointers in HeapObjects.
1367class UpdatingVisitor: public ObjectVisitor {
1368 public:
1369 void VisitPointer(Object** p) {
1370 UpdatePointer(p);
1371 }
1372
1373 void VisitPointers(Object** start, Object** end) {
1374 // Mark all HeapObject pointers in [start, end)
1375 for (Object** p = start; p < end; p++) UpdatePointer(p);
1376 }
1377
1378 void VisitCodeTarget(RelocInfo* rinfo) {
1379 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
1380 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
1381 VisitPointer(&target);
1382 rinfo->set_target_address(
1383 reinterpret_cast<Code*>(target)->instruction_start());
1384 }
1385
1386 private:
1387 void UpdatePointer(Object** p) {
1388 if (!(*p)->IsHeapObject()) return;
1389
1390 HeapObject* obj = HeapObject::cast(*p);
1391 Address old_addr = obj->address();
1392 Address new_addr;
1393 ASSERT(!Heap::InFromSpace(obj));
1394
1395 if (Heap::new_space()->Contains(obj)) {
1396 Address forwarding_pointer_addr =
1397 Heap::new_space()->FromSpaceLow() +
1398 Heap::new_space()->ToSpaceOffsetForAddress(old_addr);
1399 new_addr = Memory::Address_at(forwarding_pointer_addr);
1400
1401#ifdef DEBUG
1402 ASSERT(Heap::old_pointer_space()->Contains(new_addr) ||
1403 Heap::old_data_space()->Contains(new_addr) ||
1404 Heap::new_space()->FromSpaceContains(new_addr) ||
1405 Heap::lo_space()->Contains(HeapObject::FromAddress(new_addr)));
1406
1407 if (Heap::new_space()->FromSpaceContains(new_addr)) {
1408 ASSERT(Heap::new_space()->FromSpaceOffsetForAddress(new_addr) <=
1409 Heap::new_space()->ToSpaceOffsetForAddress(old_addr));
1410 }
1411#endif
1412
1413 } else if (Heap::lo_space()->Contains(obj)) {
1414 // Don't move objects in the large object space.
1415 return;
1416
1417 } else {
1418#ifdef DEBUG
1419 PagedSpaces spaces;
1420 PagedSpace* original_space = spaces.next();
1421 while (original_space != NULL) {
1422 if (original_space->Contains(obj)) break;
1423 original_space = spaces.next();
1424 }
1425 ASSERT(original_space != NULL);
1426#endif
1427 new_addr = MarkCompactCollector::GetForwardingAddressInOldSpace(obj);
1428 ASSERT(original_space->Contains(new_addr));
1429 ASSERT(original_space->MCSpaceOffsetForAddress(new_addr) <=
1430 original_space->MCSpaceOffsetForAddress(old_addr));
1431 }
1432
1433 *p = HeapObject::FromAddress(new_addr);
1434
1435#ifdef DEBUG
1436 if (FLAG_gc_verbose) {
1437 PrintF("update %p : %p -> %p\n",
1438 reinterpret_cast<Address>(p), old_addr, new_addr);
1439 }
1440#endif
1441 }
1442};
1443
1444
1445void MarkCompactCollector::UpdatePointers() {
1446#ifdef DEBUG
1447 ASSERT(state_ == ENCODE_FORWARDING_ADDRESSES);
1448 state_ = UPDATE_POINTERS;
1449#endif
1450 UpdatingVisitor updating_visitor;
1451 Heap::IterateRoots(&updating_visitor);
1452 GlobalHandles::IterateWeakRoots(&updating_visitor);
1453
1454 int live_maps = IterateLiveObjects(Heap::map_space(),
1455 &UpdatePointersInOldObject);
1456 int live_pointer_olds = IterateLiveObjects(Heap::old_pointer_space(),
1457 &UpdatePointersInOldObject);
1458 int live_data_olds = IterateLiveObjects(Heap::old_data_space(),
1459 &UpdatePointersInOldObject);
1460 int live_codes = IterateLiveObjects(Heap::code_space(),
1461 &UpdatePointersInOldObject);
1462 int live_cells = IterateLiveObjects(Heap::cell_space(),
1463 &UpdatePointersInOldObject);
1464 int live_news = IterateLiveObjects(Heap::new_space(),
1465 &UpdatePointersInNewObject);
1466
1467 // Large objects do not move, the map word can be updated directly.
1468 LargeObjectIterator it(Heap::lo_space());
1469 while (it.has_next()) UpdatePointersInNewObject(it.next());
1470
1471 USE(live_maps);
1472 USE(live_pointer_olds);
1473 USE(live_data_olds);
1474 USE(live_codes);
1475 USE(live_cells);
1476 USE(live_news);
1477 ASSERT(live_maps == live_map_objects_);
1478 ASSERT(live_data_olds == live_old_data_objects_);
1479 ASSERT(live_pointer_olds == live_old_pointer_objects_);
1480 ASSERT(live_codes == live_code_objects_);
1481 ASSERT(live_cells == live_cell_objects_);
1482 ASSERT(live_news == live_young_objects_);
1483}
1484
1485
1486int MarkCompactCollector::UpdatePointersInNewObject(HeapObject* obj) {
1487 // Keep old map pointers
1488 Map* old_map = obj->map();
1489 ASSERT(old_map->IsHeapObject());
1490
1491 Address forwarded = GetForwardingAddressInOldSpace(old_map);
1492
1493 ASSERT(Heap::map_space()->Contains(old_map));
1494 ASSERT(Heap::map_space()->Contains(forwarded));
1495#ifdef DEBUG
1496 if (FLAG_gc_verbose) {
1497 PrintF("update %p : %p -> %p\n", obj->address(), old_map->address(),
1498 forwarded);
1499 }
1500#endif
1501 // Update the map pointer.
1502 obj->set_map(reinterpret_cast<Map*>(HeapObject::FromAddress(forwarded)));
1503
1504 // We have to compute the object size relying on the old map because
1505 // map objects are not relocated yet.
1506 int obj_size = obj->SizeFromMap(old_map);
1507
1508 // Update pointers in the object body.
1509 UpdatingVisitor updating_visitor;
1510 obj->IterateBody(old_map->instance_type(), obj_size, &updating_visitor);
1511 return obj_size;
1512}
1513
1514
1515int MarkCompactCollector::UpdatePointersInOldObject(HeapObject* obj) {
1516 // Decode the map pointer.
1517 MapWord encoding = obj->map_word();
1518 Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
1519 ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr)));
1520
1521 // At this point, the first word of map_addr is also encoded, cannot
1522 // cast it to Map* using Map::cast.
1523 Map* map = reinterpret_cast<Map*>(HeapObject::FromAddress(map_addr));
1524 int obj_size = obj->SizeFromMap(map);
1525 InstanceType type = map->instance_type();
1526
1527 // Update map pointer.
1528 Address new_map_addr = GetForwardingAddressInOldSpace(map);
1529 int offset = encoding.DecodeOffset();
1530 obj->set_map_word(MapWord::EncodeAddress(new_map_addr, offset));
1531
1532#ifdef DEBUG
1533 if (FLAG_gc_verbose) {
1534 PrintF("update %p : %p -> %p\n", obj->address(),
1535 map_addr, new_map_addr);
1536 }
1537#endif
1538
1539 // Update pointers in the object body.
1540 UpdatingVisitor updating_visitor;
1541 obj->IterateBody(type, obj_size, &updating_visitor);
1542 return obj_size;
1543}
1544
1545
1546Address MarkCompactCollector::GetForwardingAddressInOldSpace(HeapObject* obj) {
1547 // Object should either in old or map space.
1548 MapWord encoding = obj->map_word();
1549
1550 // Offset to the first live object's forwarding address.
1551 int offset = encoding.DecodeOffset();
1552 Address obj_addr = obj->address();
1553
1554 // Find the first live object's forwarding address.
1555 Page* p = Page::FromAddress(obj_addr);
1556 Address first_forwarded = p->mc_first_forwarded;
1557
1558 // Page start address of forwarded address.
1559 Page* forwarded_page = Page::FromAddress(first_forwarded);
1560 int forwarded_offset = forwarded_page->Offset(first_forwarded);
1561
1562 // Find end of allocation of in the page of first_forwarded.
1563 Address mc_top = forwarded_page->mc_relocation_top;
1564 int mc_top_offset = forwarded_page->Offset(mc_top);
1565
1566 // Check if current object's forward pointer is in the same page
1567 // as the first live object's forwarding pointer
1568 if (forwarded_offset + offset < mc_top_offset) {
1569 // In the same page.
1570 return first_forwarded + offset;
1571 }
1572
1573 // Must be in the next page, NOTE: this may cross chunks.
1574 Page* next_page = forwarded_page->next_page();
1575 ASSERT(next_page->is_valid());
1576
1577 offset -= (mc_top_offset - forwarded_offset);
1578 offset += Page::kObjectStartOffset;
1579
1580 ASSERT_PAGE_OFFSET(offset);
1581 ASSERT(next_page->OffsetToAddress(offset) < next_page->mc_relocation_top);
1582
1583 return next_page->OffsetToAddress(offset);
1584}
1585
1586
1587// -------------------------------------------------------------------------
1588// Phase 4: Relocate objects
1589
1590void MarkCompactCollector::RelocateObjects() {
1591#ifdef DEBUG
1592 ASSERT(state_ == UPDATE_POINTERS);
1593 state_ = RELOCATE_OBJECTS;
1594#endif
1595 // Relocates objects, always relocate map objects first. Relocating
1596 // objects in other space relies on map objects to get object size.
1597 int live_maps = IterateLiveObjects(Heap::map_space(), &RelocateMapObject);
1598 int live_pointer_olds = IterateLiveObjects(Heap::old_pointer_space(),
1599 &RelocateOldPointerObject);
1600 int live_data_olds = IterateLiveObjects(Heap::old_data_space(),
1601 &RelocateOldDataObject);
1602 int live_codes = IterateLiveObjects(Heap::code_space(), &RelocateCodeObject);
1603 int live_cells = IterateLiveObjects(Heap::cell_space(), &RelocateCellObject);
1604 int live_news = IterateLiveObjects(Heap::new_space(), &RelocateNewObject);
1605
1606 USE(live_maps);
1607 USE(live_data_olds);
1608 USE(live_pointer_olds);
1609 USE(live_codes);
1610 USE(live_cells);
1611 USE(live_news);
1612 ASSERT(live_maps == live_map_objects_);
1613 ASSERT(live_data_olds == live_old_data_objects_);
1614 ASSERT(live_pointer_olds == live_old_pointer_objects_);
1615 ASSERT(live_codes == live_code_objects_);
1616 ASSERT(live_cells == live_cell_objects_);
1617 ASSERT(live_news == live_young_objects_);
1618
1619 // Flip from and to spaces
1620 Heap::new_space()->Flip();
1621
1622 // Set age_mark to bottom in to space
1623 Address mark = Heap::new_space()->bottom();
1624 Heap::new_space()->set_age_mark(mark);
1625
1626 Heap::new_space()->MCCommitRelocationInfo();
1627#ifdef DEBUG
1628 // It is safe to write to the remembered sets as remembered sets on a
1629 // page-by-page basis after committing the m-c forwarding pointer.
1630 Page::set_rset_state(Page::IN_USE);
1631#endif
1632 PagedSpaces spaces;
1633 while (PagedSpace* space = spaces.next()) space->MCCommitRelocationInfo();
1634}
1635
1636
1637int MarkCompactCollector::RelocateMapObject(HeapObject* obj) {
1638 // Recover map pointer.
1639 MapWord encoding = obj->map_word();
1640 Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
1641 ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr)));
1642
1643 // Get forwarding address before resetting map pointer
1644 Address new_addr = GetForwardingAddressInOldSpace(obj);
1645
1646 // Reset map pointer. The meta map object may not be copied yet so
1647 // Map::cast does not yet work.
1648 obj->set_map(reinterpret_cast<Map*>(HeapObject::FromAddress(map_addr)));
1649
1650 Address old_addr = obj->address();
1651
1652 if (new_addr != old_addr) {
1653 memmove(new_addr, old_addr, Map::kSize); // copy contents
1654 }
1655
1656#ifdef DEBUG
1657 if (FLAG_gc_verbose) {
1658 PrintF("relocate %p -> %p\n", old_addr, new_addr);
1659 }
1660#endif
1661
1662 return Map::kSize;
1663}
1664
1665
1666static inline int RestoreMap(HeapObject* obj,
1667 PagedSpace* space,
1668 Address new_addr,
1669 Address map_addr) {
1670 // This must be a non-map object, and the function relies on the
1671 // assumption that the Map space is compacted before the other paged
1672 // spaces (see RelocateObjects).
1673
1674 // Reset map pointer.
1675 obj->set_map(Map::cast(HeapObject::FromAddress(map_addr)));
1676
1677 int obj_size = obj->Size();
1678 ASSERT_OBJECT_SIZE(obj_size);
1679
1680 ASSERT(space->MCSpaceOffsetForAddress(new_addr) <=
1681 space->MCSpaceOffsetForAddress(obj->address()));
1682
1683#ifdef DEBUG
1684 if (FLAG_gc_verbose) {
1685 PrintF("relocate %p -> %p\n", obj->address(), new_addr);
1686 }
1687#endif
1688
1689 return obj_size;
1690}
1691
1692
1693int MarkCompactCollector::RelocateOldNonCodeObject(HeapObject* obj,
1694 PagedSpace* space) {
1695 // Recover map pointer.
1696 MapWord encoding = obj->map_word();
1697 Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
1698 ASSERT(Heap::map_space()->Contains(map_addr));
1699
1700 // Get forwarding address before resetting map pointer.
1701 Address new_addr = GetForwardingAddressInOldSpace(obj);
1702
1703 // Reset the map pointer.
1704 int obj_size = RestoreMap(obj, space, new_addr, map_addr);
1705
1706 Address old_addr = obj->address();
1707
1708 if (new_addr != old_addr) {
1709 memmove(new_addr, old_addr, obj_size); // Copy contents
1710 }
1711
1712 ASSERT(!HeapObject::FromAddress(new_addr)->IsCode());
1713
1714 return obj_size;
1715}
1716
1717
1718int MarkCompactCollector::RelocateOldPointerObject(HeapObject* obj) {
1719 return RelocateOldNonCodeObject(obj, Heap::old_pointer_space());
1720}
1721
1722
1723int MarkCompactCollector::RelocateOldDataObject(HeapObject* obj) {
1724 return RelocateOldNonCodeObject(obj, Heap::old_data_space());
1725}
1726
1727
1728int MarkCompactCollector::RelocateCellObject(HeapObject* obj) {
1729 return RelocateOldNonCodeObject(obj, Heap::cell_space());
1730}
1731
1732
1733int MarkCompactCollector::RelocateCodeObject(HeapObject* obj) {
1734 // Recover map pointer.
1735 MapWord encoding = obj->map_word();
1736 Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
1737 ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr)));
1738
1739 // Get forwarding address before resetting map pointer
1740 Address new_addr = GetForwardingAddressInOldSpace(obj);
1741
1742 // Reset the map pointer.
1743 int obj_size = RestoreMap(obj, Heap::code_space(), new_addr, map_addr);
1744
1745 Address old_addr = obj->address();
1746
1747 if (new_addr != old_addr) {
1748 memmove(new_addr, old_addr, obj_size); // Copy contents.
1749 }
1750
1751 HeapObject* copied_to = HeapObject::FromAddress(new_addr);
1752 if (copied_to->IsCode()) {
1753 // May also update inline cache target.
1754 Code::cast(copied_to)->Relocate(new_addr - old_addr);
1755 // Notify the logger that compiled code has moved.
1756 LOG(CodeMoveEvent(old_addr, new_addr));
1757 }
1758
1759 return obj_size;
1760}
1761
1762
1763int MarkCompactCollector::RelocateNewObject(HeapObject* obj) {
1764 int obj_size = obj->Size();
1765
1766 // Get forwarding address
1767 Address old_addr = obj->address();
1768 int offset = Heap::new_space()->ToSpaceOffsetForAddress(old_addr);
1769
1770 Address new_addr =
1771 Memory::Address_at(Heap::new_space()->FromSpaceLow() + offset);
1772
1773#ifdef DEBUG
1774 if (Heap::new_space()->FromSpaceContains(new_addr)) {
1775 ASSERT(Heap::new_space()->FromSpaceOffsetForAddress(new_addr) <=
1776 Heap::new_space()->ToSpaceOffsetForAddress(old_addr));
1777 } else {
1778 ASSERT(Heap::TargetSpace(obj) == Heap::old_pointer_space() ||
1779 Heap::TargetSpace(obj) == Heap::old_data_space());
1780 }
1781#endif
1782
1783 // New and old addresses cannot overlap.
1784 memcpy(reinterpret_cast<void*>(new_addr),
1785 reinterpret_cast<void*>(old_addr),
1786 obj_size);
1787
1788#ifdef DEBUG
1789 if (FLAG_gc_verbose) {
1790 PrintF("relocate %p -> %p\n", old_addr, new_addr);
1791 }
1792#endif
1793
1794 return obj_size;
1795}
1796
1797
1798// -------------------------------------------------------------------------
1799// Phase 5: rebuild remembered sets
1800
1801void MarkCompactCollector::RebuildRSets() {
1802#ifdef DEBUG
1803 ASSERT(state_ == RELOCATE_OBJECTS);
1804 state_ = REBUILD_RSETS;
1805#endif
1806 Heap::RebuildRSets();
1807}
1808
1809} } // namespace v8::internal