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