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