blob: 554b5795de92e49ed29734e949768c12ff4cf625 [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;
Steve Block6ded16b2010-05-10 14:33:55 +010056int MarkCompactCollector::live_young_objects_size_ = 0;
57int MarkCompactCollector::live_old_data_objects_size_ = 0;
58int MarkCompactCollector::live_old_pointer_objects_size_ = 0;
59int MarkCompactCollector::live_code_objects_size_ = 0;
60int MarkCompactCollector::live_map_objects_size_ = 0;
61int MarkCompactCollector::live_cell_objects_size_ = 0;
62int MarkCompactCollector::live_lo_objects_size_ = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000063#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()) {
Leon Clarkef7060e22010-06-03 12:02:55 +010081 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_COMPACT);
Steve Blocka7e24c12009-10-30 11:49:00 +000082 EncodeForwardingAddresses();
83
84 UpdatePointers();
85
86 RelocateObjects();
87
88 RebuildRSets();
89
90 } else {
91 SweepSpaces();
92 }
93
94 Finish();
95
96 // Save the count of marked objects remaining after the collection and
97 // null out the GC tracer.
98 previous_marked_count_ = tracer_->marked_count();
99 ASSERT(previous_marked_count_ == 0);
100 tracer_ = NULL;
101}
102
103
104void MarkCompactCollector::Prepare(GCTracer* tracer) {
105 // Rather than passing the tracer around we stash it in a static member
106 // variable.
107 tracer_ = tracer;
108
109#ifdef DEBUG
110 ASSERT(state_ == IDLE);
111 state_ = PREPARE_GC;
112#endif
113 ASSERT(!FLAG_always_compact || !FLAG_never_compact);
114
115 compacting_collection_ =
116 FLAG_always_compact || force_compaction_ || compact_on_next_gc_;
117 compact_on_next_gc_ = false;
118
119 if (FLAG_never_compact) compacting_collection_ = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000120 if (!Heap::map_space()->MapPointersEncodable())
121 compacting_collection_ = false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000122 if (FLAG_collect_maps) CreateBackPointers();
123
124#ifdef DEBUG
125 if (compacting_collection_) {
126 // We will write bookkeeping information to the remembered set area
127 // starting now.
128 Page::set_rset_state(Page::NOT_IN_USE);
129 }
130#endif
131
132 PagedSpaces spaces;
Leon Clarked91b9f72010-01-27 17:25:45 +0000133 for (PagedSpace* space = spaces.next();
134 space != NULL; space = spaces.next()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000135 space->PrepareForMarkCompact(compacting_collection_);
136 }
137
138#ifdef DEBUG
139 live_bytes_ = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100140 live_young_objects_size_ = 0;
141 live_old_pointer_objects_size_ = 0;
142 live_old_data_objects_size_ = 0;
143 live_code_objects_size_ = 0;
144 live_map_objects_size_ = 0;
145 live_cell_objects_size_ = 0;
146 live_lo_objects_size_ = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000147#endif
148}
149
150
151void MarkCompactCollector::Finish() {
152#ifdef DEBUG
153 ASSERT(state_ == SWEEP_SPACES || state_ == REBUILD_RSETS);
154 state_ = IDLE;
155#endif
156 // The stub cache is not traversed during GC; clear the cache to
157 // force lazy re-initialization of it. This must be done after the
158 // GC, because it relies on the new address of certain old space
159 // objects (empty string, illegal builtin).
160 StubCache::Clear();
161
Leon Clarkee46be812010-01-19 14:06:41 +0000162 ExternalStringTable::CleanUp();
163
Steve Blocka7e24c12009-10-30 11:49:00 +0000164 // If we've just compacted old space there's no reason to check the
165 // fragmentation limit. Just return.
166 if (HasCompacted()) return;
167
168 // We compact the old generation on the next GC if it has gotten too
169 // fragmented (ie, we could recover an expected amount of space by
170 // reclaiming the waste and free list blocks).
171 static const int kFragmentationLimit = 15; // Percent.
172 static const int kFragmentationAllowed = 1 * MB; // Absolute.
173 int old_gen_recoverable = 0;
174 int old_gen_used = 0;
175
176 OldSpaces spaces;
Leon Clarked91b9f72010-01-27 17:25:45 +0000177 for (OldSpace* space = spaces.next(); space != NULL; space = spaces.next()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000178 old_gen_recoverable += space->Waste() + space->AvailableFree();
179 old_gen_used += space->Size();
180 }
181
182 int old_gen_fragmentation =
183 static_cast<int>((old_gen_recoverable * 100.0) / old_gen_used);
184 if (old_gen_fragmentation > kFragmentationLimit &&
185 old_gen_recoverable > kFragmentationAllowed) {
186 compact_on_next_gc_ = true;
187 }
188}
189
190
191// -------------------------------------------------------------------------
192// Phase 1: tracing and marking live objects.
193// before: all objects are in normal state.
194// after: a live object's map pointer is marked as '00'.
195
196// Marking all live objects in the heap as part of mark-sweep or mark-compact
197// collection. Before marking, all objects are in their normal state. After
198// marking, live objects' map pointers are marked indicating that the object
199// has been found reachable.
200//
201// The marking algorithm is a (mostly) depth-first (because of possible stack
202// overflow) traversal of the graph of objects reachable from the roots. It
203// uses an explicit stack of pointers rather than recursion. The young
204// generation's inactive ('from') space is used as a marking stack. The
205// objects in the marking stack are the ones that have been reached and marked
206// but their children have not yet been visited.
207//
208// The marking stack can overflow during traversal. In that case, we set an
209// overflow flag. When the overflow flag is set, we continue marking objects
210// reachable from the objects on the marking stack, but no longer push them on
211// the marking stack. Instead, we mark them as both marked and overflowed.
212// When the stack is in the overflowed state, objects marked as overflowed
213// have been reached and marked but their children have not been visited yet.
214// After emptying the marking stack, we clear the overflow flag and traverse
215// the heap looking for objects marked as overflowed, push them on the stack,
216// and continue with marking. This process repeats until all reachable
217// objects have been marked.
218
219static MarkingStack marking_stack;
220
221
222static inline HeapObject* ShortCircuitConsString(Object** p) {
223 // Optimization: If the heap object pointed to by p is a non-symbol
224 // cons string whose right substring is Heap::empty_string, update
225 // it in place to its left substring. Return the updated value.
226 //
227 // Here we assume that if we change *p, we replace it with a heap object
228 // (ie, the left substring of a cons string is always a heap object).
229 //
230 // The check performed is:
231 // object->IsConsString() && !object->IsSymbol() &&
232 // (ConsString::cast(object)->second() == Heap::empty_string())
233 // except the maps for the object and its possible substrings might be
234 // marked.
235 HeapObject* object = HeapObject::cast(*p);
236 MapWord map_word = object->map_word();
237 map_word.ClearMark();
238 InstanceType type = map_word.ToMap()->instance_type();
239 if ((type & kShortcutTypeMask) != kShortcutTypeTag) return object;
240
241 Object* second = reinterpret_cast<ConsString*>(object)->unchecked_second();
242 if (second != Heap::raw_unchecked_empty_string()) {
243 return object;
244 }
245
246 // Since we don't have the object's start, it is impossible to update the
247 // remembered set. Therefore, we only replace the string with its left
248 // substring when the remembered set does not change.
249 Object* first = reinterpret_cast<ConsString*>(object)->unchecked_first();
250 if (!Heap::InNewSpace(object) && Heap::InNewSpace(first)) return object;
251
252 *p = first;
253 return HeapObject::cast(first);
254}
255
256
257// Helper class for marking pointers in HeapObjects.
258class MarkingVisitor : public ObjectVisitor {
259 public:
260 void VisitPointer(Object** p) {
261 MarkObjectByPointer(p);
262 }
263
264 void VisitPointers(Object** start, Object** end) {
265 // Mark all objects pointed to in [start, end).
266 const int kMinRangeForMarkingRecursion = 64;
267 if (end - start >= kMinRangeForMarkingRecursion) {
268 if (VisitUnmarkedObjects(start, end)) return;
269 // We are close to a stack overflow, so just mark the objects.
270 }
271 for (Object** p = start; p < end; p++) MarkObjectByPointer(p);
272 }
273
274 void VisitCodeTarget(RelocInfo* rinfo) {
275 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
276 Code* code = Code::GetCodeFromTargetAddress(rinfo->target_address());
277 if (FLAG_cleanup_ics_at_gc && code->is_inline_cache_stub()) {
278 IC::Clear(rinfo->pc());
279 // Please note targets for cleared inline cached do not have to be
280 // marked since they are contained in Heap::non_monomorphic_cache().
281 } else {
282 MarkCompactCollector::MarkObject(code);
283 }
284 }
285
286 void VisitDebugTarget(RelocInfo* rinfo) {
287 ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()) &&
Steve Block3ce2e202009-11-05 08:53:23 +0000288 rinfo->IsPatchedReturnSequence());
Steve Blocka7e24c12009-10-30 11:49:00 +0000289 HeapObject* code = Code::GetCodeFromTargetAddress(rinfo->call_address());
290 MarkCompactCollector::MarkObject(code);
Steve Blocka7e24c12009-10-30 11:49:00 +0000291 }
292
293 private:
294 // Mark object pointed to by p.
295 void MarkObjectByPointer(Object** p) {
296 if (!(*p)->IsHeapObject()) return;
297 HeapObject* object = ShortCircuitConsString(p);
298 MarkCompactCollector::MarkObject(object);
299 }
300
301 // Tells whether the mark sweep collection will perform compaction.
302 bool IsCompacting() { return MarkCompactCollector::IsCompacting(); }
303
304 // Visit an unmarked object.
305 void VisitUnmarkedObject(HeapObject* obj) {
306#ifdef DEBUG
307 ASSERT(Heap::Contains(obj));
308 ASSERT(!obj->IsMarked());
309#endif
310 Map* map = obj->map();
311 MarkCompactCollector::SetMark(obj);
312 // Mark the map pointer and the body.
313 MarkCompactCollector::MarkObject(map);
314 obj->IterateBody(map->instance_type(), obj->SizeFromMap(map), this);
315 }
316
317 // Visit all unmarked objects pointed to by [start, end).
318 // Returns false if the operation fails (lack of stack space).
319 inline bool VisitUnmarkedObjects(Object** start, Object** end) {
320 // Return false is we are close to the stack limit.
321 StackLimitCheck check;
322 if (check.HasOverflowed()) return false;
323
324 // Visit the unmarked objects.
325 for (Object** p = start; p < end; p++) {
326 if (!(*p)->IsHeapObject()) continue;
327 HeapObject* obj = HeapObject::cast(*p);
328 if (obj->IsMarked()) continue;
329 VisitUnmarkedObject(obj);
330 }
331 return true;
332 }
333};
334
335
336// Visitor class for marking heap roots.
337class RootMarkingVisitor : public ObjectVisitor {
338 public:
339 void VisitPointer(Object** p) {
340 MarkObjectByPointer(p);
341 }
342
343 void VisitPointers(Object** start, Object** end) {
344 for (Object** p = start; p < end; p++) MarkObjectByPointer(p);
345 }
346
347 MarkingVisitor* stack_visitor() { return &stack_visitor_; }
348
349 private:
350 MarkingVisitor stack_visitor_;
351
352 void MarkObjectByPointer(Object** p) {
353 if (!(*p)->IsHeapObject()) return;
354
355 // Replace flat cons strings in place.
356 HeapObject* object = ShortCircuitConsString(p);
357 if (object->IsMarked()) return;
358
359 Map* map = object->map();
360 // Mark the object.
361 MarkCompactCollector::SetMark(object);
362 // Mark the map pointer and body, and push them on the marking stack.
363 MarkCompactCollector::MarkObject(map);
364 object->IterateBody(map->instance_type(), object->SizeFromMap(map),
365 &stack_visitor_);
366
367 // Mark all the objects reachable from the map and body. May leave
368 // overflowed objects in the heap.
369 MarkCompactCollector::EmptyMarkingStack(&stack_visitor_);
370 }
371};
372
373
374// Helper class for pruning the symbol table.
375class SymbolTableCleaner : public ObjectVisitor {
376 public:
377 SymbolTableCleaner() : pointers_removed_(0) { }
Leon Clarkee46be812010-01-19 14:06:41 +0000378
379 virtual void VisitPointers(Object** start, Object** end) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000380 // Visit all HeapObject pointers in [start, end).
381 for (Object** p = start; p < end; p++) {
382 if ((*p)->IsHeapObject() && !HeapObject::cast(*p)->IsMarked()) {
383 // Check if the symbol being pruned is an external symbol. We need to
384 // delete the associated external data as this symbol is going away.
385
Steve Blocka7e24c12009-10-30 11:49:00 +0000386 // Since no objects have yet been moved we can safely access the map of
387 // the object.
Leon Clarkee46be812010-01-19 14:06:41 +0000388 if ((*p)->IsExternalString()) {
389 Heap::FinalizeExternalString(String::cast(*p));
Steve Blocka7e24c12009-10-30 11:49:00 +0000390 }
391 // Set the entry to null_value (as deleted).
392 *p = Heap::raw_unchecked_null_value();
393 pointers_removed_++;
394 }
395 }
396 }
397
398 int PointersRemoved() {
399 return pointers_removed_;
400 }
401 private:
402 int pointers_removed_;
403};
404
405
406void MarkCompactCollector::MarkUnmarkedObject(HeapObject* object) {
407 ASSERT(!object->IsMarked());
408 ASSERT(Heap::Contains(object));
409 if (object->IsMap()) {
410 Map* map = Map::cast(object);
411 if (FLAG_cleanup_caches_in_maps_at_gc) {
412 map->ClearCodeCache();
413 }
414 SetMark(map);
415 if (FLAG_collect_maps &&
416 map->instance_type() >= FIRST_JS_OBJECT_TYPE &&
417 map->instance_type() <= JS_FUNCTION_TYPE) {
418 MarkMapContents(map);
419 } else {
420 marking_stack.Push(map);
421 }
422 } else {
423 SetMark(object);
424 marking_stack.Push(object);
425 }
426}
427
428
429void MarkCompactCollector::MarkMapContents(Map* map) {
430 MarkDescriptorArray(reinterpret_cast<DescriptorArray*>(
431 *HeapObject::RawField(map, Map::kInstanceDescriptorsOffset)));
432
433 // Mark the Object* fields of the Map.
434 // Since the descriptor array has been marked already, it is fine
435 // that one of these fields contains a pointer to it.
436 MarkingVisitor visitor; // Has no state or contents.
437 visitor.VisitPointers(HeapObject::RawField(map, Map::kPrototypeOffset),
438 HeapObject::RawField(map, Map::kSize));
439}
440
441
442void MarkCompactCollector::MarkDescriptorArray(
443 DescriptorArray* descriptors) {
444 if (descriptors->IsMarked()) return;
445 // Empty descriptor array is marked as a root before any maps are marked.
446 ASSERT(descriptors != Heap::raw_unchecked_empty_descriptor_array());
447 SetMark(descriptors);
448
449 FixedArray* contents = reinterpret_cast<FixedArray*>(
450 descriptors->get(DescriptorArray::kContentArrayIndex));
451 ASSERT(contents->IsHeapObject());
452 ASSERT(!contents->IsMarked());
453 ASSERT(contents->IsFixedArray());
454 ASSERT(contents->length() >= 2);
455 SetMark(contents);
456 // Contents contains (value, details) pairs. If the details say
457 // that the type of descriptor is MAP_TRANSITION, CONSTANT_TRANSITION,
458 // or NULL_DESCRIPTOR, we don't mark the value as live. Only for
459 // type MAP_TRANSITION is the value a Object* (a Map*).
460 for (int i = 0; i < contents->length(); i += 2) {
461 // If the pair (value, details) at index i, i+1 is not
462 // a transition or null descriptor, mark the value.
463 PropertyDetails details(Smi::cast(contents->get(i + 1)));
464 if (details.type() < FIRST_PHANTOM_PROPERTY_TYPE) {
465 HeapObject* object = reinterpret_cast<HeapObject*>(contents->get(i));
466 if (object->IsHeapObject() && !object->IsMarked()) {
467 SetMark(object);
468 marking_stack.Push(object);
469 }
470 }
471 }
472 // The DescriptorArray descriptors contains a pointer to its contents array,
473 // but the contents array is already marked.
474 marking_stack.Push(descriptors);
475}
476
477
478void MarkCompactCollector::CreateBackPointers() {
479 HeapObjectIterator iterator(Heap::map_space());
Leon Clarked91b9f72010-01-27 17:25:45 +0000480 for (HeapObject* next_object = iterator.next();
481 next_object != NULL; next_object = iterator.next()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000482 if (next_object->IsMap()) { // Could also be ByteArray on free list.
483 Map* map = Map::cast(next_object);
484 if (map->instance_type() >= FIRST_JS_OBJECT_TYPE &&
485 map->instance_type() <= JS_FUNCTION_TYPE) {
486 map->CreateBackPointers();
487 } else {
488 ASSERT(map->instance_descriptors() == Heap::empty_descriptor_array());
489 }
490 }
491 }
492}
493
494
495static int OverflowObjectSize(HeapObject* obj) {
496 // Recover the normal map pointer, it might be marked as live and
497 // overflowed.
498 MapWord map_word = obj->map_word();
499 map_word.ClearMark();
500 map_word.ClearOverflow();
501 return obj->SizeFromMap(map_word.ToMap());
502}
503
504
505// Fill the marking stack with overflowed objects returned by the given
506// iterator. Stop when the marking stack is filled or the end of the space
507// is reached, whichever comes first.
508template<class T>
509static void ScanOverflowedObjects(T* it) {
510 // The caller should ensure that the marking stack is initially not full,
511 // so that we don't waste effort pointlessly scanning for objects.
512 ASSERT(!marking_stack.is_full());
513
Leon Clarked91b9f72010-01-27 17:25:45 +0000514 for (HeapObject* object = it->next(); object != NULL; object = it->next()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000515 if (object->IsOverflowed()) {
516 object->ClearOverflow();
517 ASSERT(object->IsMarked());
518 ASSERT(Heap::Contains(object));
519 marking_stack.Push(object);
520 if (marking_stack.is_full()) return;
521 }
522 }
523}
524
525
526bool MarkCompactCollector::IsUnmarkedHeapObject(Object** p) {
527 return (*p)->IsHeapObject() && !HeapObject::cast(*p)->IsMarked();
528}
529
530
Steve Blocka7e24c12009-10-30 11:49:00 +0000531void MarkCompactCollector::MarkSymbolTable() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000532 SymbolTable* symbol_table = Heap::raw_unchecked_symbol_table();
533 // Mark the symbol table itself.
534 SetMark(symbol_table);
535 // Explicitly mark the prefix.
536 MarkingVisitor marker;
537 symbol_table->IteratePrefix(&marker);
538 ProcessMarkingStack(&marker);
Steve Blocka7e24c12009-10-30 11:49:00 +0000539}
540
541
542void MarkCompactCollector::MarkRoots(RootMarkingVisitor* visitor) {
543 // Mark the heap roots including global variables, stack variables,
544 // etc., and all objects reachable from them.
Steve Blockd0582a62009-12-15 09:54:21 +0000545 Heap::IterateStrongRoots(visitor, VISIT_ONLY_STRONG);
Steve Blocka7e24c12009-10-30 11:49:00 +0000546
547 // Handle the symbol table specially.
548 MarkSymbolTable();
549
550 // There may be overflowed objects in the heap. Visit them now.
551 while (marking_stack.overflowed()) {
552 RefillMarkingStack();
553 EmptyMarkingStack(visitor->stack_visitor());
554 }
555}
556
557
558void MarkCompactCollector::MarkObjectGroups() {
559 List<ObjectGroup*>* object_groups = GlobalHandles::ObjectGroups();
560
561 for (int i = 0; i < object_groups->length(); i++) {
562 ObjectGroup* entry = object_groups->at(i);
563 if (entry == NULL) continue;
564
565 List<Object**>& objects = entry->objects_;
566 bool group_marked = false;
567 for (int j = 0; j < objects.length(); j++) {
568 Object* object = *objects[j];
569 if (object->IsHeapObject() && HeapObject::cast(object)->IsMarked()) {
570 group_marked = true;
571 break;
572 }
573 }
574
575 if (!group_marked) continue;
576
577 // An object in the group is marked, so mark as gray all white heap
578 // objects in the group.
579 for (int j = 0; j < objects.length(); ++j) {
580 if ((*objects[j])->IsHeapObject()) {
581 MarkObject(HeapObject::cast(*objects[j]));
582 }
583 }
584 // Once the entire group has been colored gray, set the object group
585 // to NULL so it won't be processed again.
586 delete object_groups->at(i);
587 object_groups->at(i) = NULL;
588 }
589}
590
591
592// Mark all objects reachable from the objects on the marking stack.
593// Before: the marking stack contains zero or more heap object pointers.
594// After: the marking stack is empty, and all objects reachable from the
595// marking stack have been marked, or are overflowed in the heap.
596void MarkCompactCollector::EmptyMarkingStack(MarkingVisitor* visitor) {
597 while (!marking_stack.is_empty()) {
598 HeapObject* object = marking_stack.Pop();
599 ASSERT(object->IsHeapObject());
600 ASSERT(Heap::Contains(object));
601 ASSERT(object->IsMarked());
602 ASSERT(!object->IsOverflowed());
603
604 // Because the object is marked, we have to recover the original map
605 // pointer and use it to mark the object's body.
606 MapWord map_word = object->map_word();
607 map_word.ClearMark();
608 Map* map = map_word.ToMap();
609 MarkObject(map);
610 object->IterateBody(map->instance_type(), object->SizeFromMap(map),
611 visitor);
612 }
613}
614
615
616// Sweep the heap for overflowed objects, clear their overflow bits, and
617// push them on the marking stack. Stop early if the marking stack fills
618// before sweeping completes. If sweeping completes, there are no remaining
619// overflowed objects in the heap so the overflow flag on the markings stack
620// is cleared.
621void MarkCompactCollector::RefillMarkingStack() {
622 ASSERT(marking_stack.overflowed());
623
624 SemiSpaceIterator new_it(Heap::new_space(), &OverflowObjectSize);
625 ScanOverflowedObjects(&new_it);
626 if (marking_stack.is_full()) return;
627
628 HeapObjectIterator old_pointer_it(Heap::old_pointer_space(),
629 &OverflowObjectSize);
630 ScanOverflowedObjects(&old_pointer_it);
631 if (marking_stack.is_full()) return;
632
633 HeapObjectIterator old_data_it(Heap::old_data_space(), &OverflowObjectSize);
634 ScanOverflowedObjects(&old_data_it);
635 if (marking_stack.is_full()) return;
636
637 HeapObjectIterator code_it(Heap::code_space(), &OverflowObjectSize);
638 ScanOverflowedObjects(&code_it);
639 if (marking_stack.is_full()) return;
640
641 HeapObjectIterator map_it(Heap::map_space(), &OverflowObjectSize);
642 ScanOverflowedObjects(&map_it);
643 if (marking_stack.is_full()) return;
644
645 HeapObjectIterator cell_it(Heap::cell_space(), &OverflowObjectSize);
646 ScanOverflowedObjects(&cell_it);
647 if (marking_stack.is_full()) return;
648
649 LargeObjectIterator lo_it(Heap::lo_space(), &OverflowObjectSize);
650 ScanOverflowedObjects(&lo_it);
651 if (marking_stack.is_full()) return;
652
653 marking_stack.clear_overflowed();
654}
655
656
657// Mark all objects reachable (transitively) from objects on the marking
658// stack. Before: the marking stack contains zero or more heap object
659// pointers. After: the marking stack is empty and there are no overflowed
660// objects in the heap.
661void MarkCompactCollector::ProcessMarkingStack(MarkingVisitor* visitor) {
662 EmptyMarkingStack(visitor);
663 while (marking_stack.overflowed()) {
664 RefillMarkingStack();
665 EmptyMarkingStack(visitor);
666 }
667}
668
669
670void MarkCompactCollector::ProcessObjectGroups(MarkingVisitor* visitor) {
671 bool work_to_do = true;
672 ASSERT(marking_stack.is_empty());
673 while (work_to_do) {
674 MarkObjectGroups();
675 work_to_do = !marking_stack.is_empty();
676 ProcessMarkingStack(visitor);
677 }
678}
679
680
681void MarkCompactCollector::MarkLiveObjects() {
Leon Clarkef7060e22010-06-03 12:02:55 +0100682 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_MARK);
Steve Blocka7e24c12009-10-30 11:49:00 +0000683#ifdef DEBUG
684 ASSERT(state_ == PREPARE_GC);
685 state_ = MARK_LIVE_OBJECTS;
686#endif
687 // The to space contains live objects, the from space is used as a marking
688 // stack.
689 marking_stack.Initialize(Heap::new_space()->FromSpaceLow(),
690 Heap::new_space()->FromSpaceHigh());
691
692 ASSERT(!marking_stack.overflowed());
693
694 RootMarkingVisitor root_visitor;
695 MarkRoots(&root_visitor);
696
697 // The objects reachable from the roots are marked, yet unreachable
698 // objects are unmarked. Mark objects reachable from object groups
699 // containing at least one marked object, and continue until no new
700 // objects are reachable from the object groups.
701 ProcessObjectGroups(root_visitor.stack_visitor());
702
703 // The objects reachable from the roots or object groups are marked,
704 // yet unreachable objects are unmarked. Mark objects reachable
705 // only from weak global handles.
706 //
707 // First we identify nonlive weak handles and mark them as pending
708 // destruction.
709 GlobalHandles::IdentifyWeakHandles(&IsUnmarkedHeapObject);
710 // Then we mark the objects and process the transitive closure.
711 GlobalHandles::IterateWeakRoots(&root_visitor);
712 while (marking_stack.overflowed()) {
713 RefillMarkingStack();
714 EmptyMarkingStack(root_visitor.stack_visitor());
715 }
716
717 // Repeat the object groups to mark unmarked groups reachable from the
718 // weak roots.
719 ProcessObjectGroups(root_visitor.stack_visitor());
720
721 // Prune the symbol table removing all symbols only pointed to by the
722 // symbol table. Cannot use symbol_table() here because the symbol
723 // table is marked.
724 SymbolTable* symbol_table = Heap::raw_unchecked_symbol_table();
725 SymbolTableCleaner v;
726 symbol_table->IterateElements(&v);
727 symbol_table->ElementsRemoved(v.PointersRemoved());
Leon Clarkee46be812010-01-19 14:06:41 +0000728 ExternalStringTable::Iterate(&v);
729 ExternalStringTable::CleanUp();
Steve Blocka7e24c12009-10-30 11:49:00 +0000730
731 // Remove object groups after marking phase.
732 GlobalHandles::RemoveObjectGroups();
733}
734
735
736static int CountMarkedCallback(HeapObject* obj) {
737 MapWord map_word = obj->map_word();
738 map_word.ClearMark();
739 return obj->SizeFromMap(map_word.ToMap());
740}
741
742
743#ifdef DEBUG
744void MarkCompactCollector::UpdateLiveObjectCount(HeapObject* obj) {
745 live_bytes_ += obj->Size();
746 if (Heap::new_space()->Contains(obj)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100747 live_young_objects_size_ += obj->Size();
Steve Blocka7e24c12009-10-30 11:49:00 +0000748 } else if (Heap::map_space()->Contains(obj)) {
749 ASSERT(obj->IsMap());
Steve Block6ded16b2010-05-10 14:33:55 +0100750 live_map_objects_size_ += obj->Size();
Steve Blocka7e24c12009-10-30 11:49:00 +0000751 } else if (Heap::cell_space()->Contains(obj)) {
752 ASSERT(obj->IsJSGlobalPropertyCell());
Steve Block6ded16b2010-05-10 14:33:55 +0100753 live_cell_objects_size_ += obj->Size();
Steve Blocka7e24c12009-10-30 11:49:00 +0000754 } else if (Heap::old_pointer_space()->Contains(obj)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100755 live_old_pointer_objects_size_ += obj->Size();
Steve Blocka7e24c12009-10-30 11:49:00 +0000756 } else if (Heap::old_data_space()->Contains(obj)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100757 live_old_data_objects_size_ += obj->Size();
Steve Blocka7e24c12009-10-30 11:49:00 +0000758 } else if (Heap::code_space()->Contains(obj)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100759 live_code_objects_size_ += obj->Size();
Steve Blocka7e24c12009-10-30 11:49:00 +0000760 } else if (Heap::lo_space()->Contains(obj)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100761 live_lo_objects_size_ += obj->Size();
Steve Blocka7e24c12009-10-30 11:49:00 +0000762 } else {
763 UNREACHABLE();
764 }
765}
766#endif // DEBUG
767
768
769void MarkCompactCollector::SweepLargeObjectSpace() {
770#ifdef DEBUG
771 ASSERT(state_ == MARK_LIVE_OBJECTS);
772 state_ =
773 compacting_collection_ ? ENCODE_FORWARDING_ADDRESSES : SWEEP_SPACES;
774#endif
775 // Deallocate unmarked objects and clear marked bits for marked objects.
776 Heap::lo_space()->FreeUnmarkedObjects();
777}
778
779// Safe to use during marking phase only.
780bool MarkCompactCollector::SafeIsMap(HeapObject* object) {
781 MapWord metamap = object->map_word();
782 metamap.ClearMark();
783 return metamap.ToMap()->instance_type() == MAP_TYPE;
784}
785
786void MarkCompactCollector::ClearNonLiveTransitions() {
787 HeapObjectIterator map_iterator(Heap::map_space(), &CountMarkedCallback);
788 // Iterate over the map space, setting map transitions that go from
789 // a marked map to an unmarked map to null transitions. At the same time,
790 // set all the prototype fields of maps back to their original value,
791 // dropping the back pointers temporarily stored in the prototype field.
792 // Setting the prototype field requires following the linked list of
793 // back pointers, reversing them all at once. This allows us to find
794 // those maps with map transitions that need to be nulled, and only
795 // scan the descriptor arrays of those maps, not all maps.
Leon Clarkee46be812010-01-19 14:06:41 +0000796 // All of these actions are carried out only on maps of JSObjects
Steve Blocka7e24c12009-10-30 11:49:00 +0000797 // and related subtypes.
Leon Clarked91b9f72010-01-27 17:25:45 +0000798 for (HeapObject* obj = map_iterator.next();
799 obj != NULL; obj = map_iterator.next()) {
800 Map* map = reinterpret_cast<Map*>(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +0000801 if (!map->IsMarked() && map->IsByteArray()) continue;
802
803 ASSERT(SafeIsMap(map));
804 // Only JSObject and subtypes have map transitions and back pointers.
805 if (map->instance_type() < FIRST_JS_OBJECT_TYPE) continue;
806 if (map->instance_type() > JS_FUNCTION_TYPE) continue;
807 // Follow the chain of back pointers to find the prototype.
808 Map* current = map;
809 while (SafeIsMap(current)) {
810 current = reinterpret_cast<Map*>(current->prototype());
811 ASSERT(current->IsHeapObject());
812 }
813 Object* real_prototype = current;
814
815 // Follow back pointers, setting them to prototype,
816 // clearing map transitions when necessary.
817 current = map;
818 bool on_dead_path = !current->IsMarked();
819 Object* next;
820 while (SafeIsMap(current)) {
821 next = current->prototype();
822 // There should never be a dead map above a live map.
823 ASSERT(on_dead_path || current->IsMarked());
824
825 // A live map above a dead map indicates a dead transition.
826 // This test will always be false on the first iteration.
827 if (on_dead_path && current->IsMarked()) {
828 on_dead_path = false;
829 current->ClearNonLiveTransitions(real_prototype);
830 }
831 *HeapObject::RawField(current, Map::kPrototypeOffset) =
832 real_prototype;
833 current = reinterpret_cast<Map*>(next);
834 }
835 }
836}
837
838// -------------------------------------------------------------------------
839// Phase 2: Encode forwarding addresses.
840// When compacting, forwarding addresses for objects in old space and map
841// space are encoded in their map pointer word (along with an encoding of
842// their map pointers).
843//
Leon Clarkee46be812010-01-19 14:06:41 +0000844// The excact encoding is described in the comments for class MapWord in
845// objects.h.
Steve Blocka7e24c12009-10-30 11:49:00 +0000846//
847// An address range [start, end) can have both live and non-live objects.
848// Maximal non-live regions are marked so they can be skipped on subsequent
849// sweeps of the heap. A distinguished map-pointer encoding is used to mark
850// free regions of one-word size (in which case the next word is the start
851// of a live object). A second distinguished map-pointer encoding is used
852// to mark free regions larger than one word, and the size of the free
853// region (including the first word) is written to the second word of the
854// region.
855//
856// Any valid map page offset must lie in the object area of the page, so map
857// page offsets less than Page::kObjectStartOffset are invalid. We use a
858// pair of distinguished invalid map encodings (for single word and multiple
859// words) to indicate free regions in the page found during computation of
860// forwarding addresses and skipped over in subsequent sweeps.
861static const uint32_t kSingleFreeEncoding = 0;
862static const uint32_t kMultiFreeEncoding = 1;
863
864
865// Encode a free region, defined by the given start address and size, in the
866// first word or two of the region.
867void EncodeFreeRegion(Address free_start, int free_size) {
868 ASSERT(free_size >= kIntSize);
869 if (free_size == kIntSize) {
870 Memory::uint32_at(free_start) = kSingleFreeEncoding;
871 } else {
872 ASSERT(free_size >= 2 * kIntSize);
873 Memory::uint32_at(free_start) = kMultiFreeEncoding;
874 Memory::int_at(free_start + kIntSize) = free_size;
875 }
876
877#ifdef DEBUG
878 // Zap the body of the free region.
879 if (FLAG_enable_slow_asserts) {
880 for (int offset = 2 * kIntSize;
881 offset < free_size;
882 offset += kPointerSize) {
883 Memory::Address_at(free_start + offset) = kZapValue;
884 }
885 }
886#endif
887}
888
889
890// Try to promote all objects in new space. Heap numbers and sequential
891// strings are promoted to the code space, large objects to large object space,
892// and all others to the old space.
893inline Object* MCAllocateFromNewSpace(HeapObject* object, int object_size) {
894 Object* forwarded;
895 if (object_size > Heap::MaxObjectSizeInPagedSpace()) {
896 forwarded = Failure::Exception();
897 } else {
898 OldSpace* target_space = Heap::TargetSpace(object);
899 ASSERT(target_space == Heap::old_pointer_space() ||
900 target_space == Heap::old_data_space());
901 forwarded = target_space->MCAllocateRaw(object_size);
902 }
903 if (forwarded->IsFailure()) {
904 forwarded = Heap::new_space()->MCAllocateRaw(object_size);
905 }
906 return forwarded;
907}
908
909
910// Allocation functions for the paged spaces call the space's MCAllocateRaw.
911inline Object* MCAllocateFromOldPointerSpace(HeapObject* ignore,
912 int object_size) {
913 return Heap::old_pointer_space()->MCAllocateRaw(object_size);
914}
915
916
917inline Object* MCAllocateFromOldDataSpace(HeapObject* ignore, int object_size) {
918 return Heap::old_data_space()->MCAllocateRaw(object_size);
919}
920
921
922inline Object* MCAllocateFromCodeSpace(HeapObject* ignore, int object_size) {
923 return Heap::code_space()->MCAllocateRaw(object_size);
924}
925
926
927inline Object* MCAllocateFromMapSpace(HeapObject* ignore, int object_size) {
928 return Heap::map_space()->MCAllocateRaw(object_size);
929}
930
931
932inline Object* MCAllocateFromCellSpace(HeapObject* ignore, int object_size) {
933 return Heap::cell_space()->MCAllocateRaw(object_size);
934}
935
936
937// The forwarding address is encoded at the same offset as the current
938// to-space object, but in from space.
939inline void EncodeForwardingAddressInNewSpace(HeapObject* old_object,
940 int object_size,
941 Object* new_object,
942 int* ignored) {
943 int offset =
944 Heap::new_space()->ToSpaceOffsetForAddress(old_object->address());
945 Memory::Address_at(Heap::new_space()->FromSpaceLow() + offset) =
946 HeapObject::cast(new_object)->address();
947}
948
949
950// The forwarding address is encoded in the map pointer of the object as an
951// offset (in terms of live bytes) from the address of the first live object
952// in the page.
953inline void EncodeForwardingAddressInPagedSpace(HeapObject* old_object,
954 int object_size,
955 Object* new_object,
956 int* offset) {
957 // Record the forwarding address of the first live object if necessary.
958 if (*offset == 0) {
959 Page::FromAddress(old_object->address())->mc_first_forwarded =
960 HeapObject::cast(new_object)->address();
961 }
962
963 MapWord encoding =
964 MapWord::EncodeAddress(old_object->map()->address(), *offset);
965 old_object->set_map_word(encoding);
966 *offset += object_size;
967 ASSERT(*offset <= Page::kObjectAreaSize);
968}
969
970
971// Most non-live objects are ignored.
972inline void IgnoreNonLiveObject(HeapObject* object) {}
973
974
Steve Blocka7e24c12009-10-30 11:49:00 +0000975// Function template that, given a range of addresses (eg, a semispace or a
976// paged space page), iterates through the objects in the range to clear
977// mark bits and compute and encode forwarding addresses. As a side effect,
978// maximal free chunks are marked so that they can be skipped on subsequent
979// sweeps.
980//
981// The template parameters are an allocation function, a forwarding address
982// encoding function, and a function to process non-live objects.
983template<MarkCompactCollector::AllocationFunction Alloc,
984 MarkCompactCollector::EncodingFunction Encode,
985 MarkCompactCollector::ProcessNonLiveFunction ProcessNonLive>
986inline void EncodeForwardingAddressesInRange(Address start,
987 Address end,
988 int* offset) {
989 // The start address of the current free region while sweeping the space.
990 // This address is set when a transition from live to non-live objects is
991 // encountered. A value (an encoding of the 'next free region' pointer)
992 // is written to memory at this address when a transition from non-live to
993 // live objects is encountered.
994 Address free_start = NULL;
995
996 // A flag giving the state of the previously swept object. Initially true
997 // to ensure that free_start is initialized to a proper address before
998 // trying to write to it.
999 bool is_prev_alive = true;
1000
1001 int object_size; // Will be set on each iteration of the loop.
1002 for (Address current = start; current < end; current += object_size) {
1003 HeapObject* object = HeapObject::FromAddress(current);
1004 if (object->IsMarked()) {
1005 object->ClearMark();
1006 MarkCompactCollector::tracer()->decrement_marked_count();
1007 object_size = object->Size();
1008
1009 Object* forwarded = Alloc(object, object_size);
1010 // Allocation cannot fail, because we are compacting the space.
1011 ASSERT(!forwarded->IsFailure());
1012 Encode(object, object_size, forwarded, offset);
1013
1014#ifdef DEBUG
1015 if (FLAG_gc_verbose) {
1016 PrintF("forward %p -> %p.\n", object->address(),
1017 HeapObject::cast(forwarded)->address());
1018 }
1019#endif
1020 if (!is_prev_alive) { // Transition from non-live to live.
Steve Blockd0582a62009-12-15 09:54:21 +00001021 EncodeFreeRegion(free_start, static_cast<int>(current - free_start));
Steve Blocka7e24c12009-10-30 11:49:00 +00001022 is_prev_alive = true;
1023 }
1024 } else { // Non-live object.
1025 object_size = object->Size();
1026 ProcessNonLive(object);
1027 if (is_prev_alive) { // Transition from live to non-live.
1028 free_start = current;
1029 is_prev_alive = false;
1030 }
1031 }
1032 }
1033
1034 // If we ended on a free region, mark it.
Steve Blockd0582a62009-12-15 09:54:21 +00001035 if (!is_prev_alive) {
1036 EncodeFreeRegion(free_start, static_cast<int>(end - free_start));
1037 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001038}
1039
1040
1041// Functions to encode the forwarding pointers in each compactable space.
1042void MarkCompactCollector::EncodeForwardingAddressesInNewSpace() {
1043 int ignored;
1044 EncodeForwardingAddressesInRange<MCAllocateFromNewSpace,
1045 EncodeForwardingAddressInNewSpace,
1046 IgnoreNonLiveObject>(
1047 Heap::new_space()->bottom(),
1048 Heap::new_space()->top(),
1049 &ignored);
1050}
1051
1052
1053template<MarkCompactCollector::AllocationFunction Alloc,
1054 MarkCompactCollector::ProcessNonLiveFunction ProcessNonLive>
1055void MarkCompactCollector::EncodeForwardingAddressesInPagedSpace(
1056 PagedSpace* space) {
1057 PageIterator it(space, PageIterator::PAGES_IN_USE);
1058 while (it.has_next()) {
1059 Page* p = it.next();
Steve Block6ded16b2010-05-10 14:33:55 +01001060
Steve Blocka7e24c12009-10-30 11:49:00 +00001061 // The offset of each live object in the page from the first live object
1062 // in the page.
1063 int offset = 0;
1064 EncodeForwardingAddressesInRange<Alloc,
1065 EncodeForwardingAddressInPagedSpace,
1066 ProcessNonLive>(
1067 p->ObjectAreaStart(),
1068 p->AllocationTop(),
1069 &offset);
1070 }
1071}
1072
1073
Steve Block6ded16b2010-05-10 14:33:55 +01001074// We scavange new space simultaneously with sweeping. This is done in two
1075// passes.
1076// The first pass migrates all alive objects from one semispace to another or
1077// promotes them to old space. Forwading address is written directly into
1078// first word of object without any encoding. If object is dead we are writing
1079// NULL as a forwarding address.
1080// The second pass updates pointers to new space in all spaces. It is possible
1081// to encounter pointers to dead objects during traversal of remembered set for
1082// map space because remembered set bits corresponding to dead maps are cleared
1083// later during map space sweeping.
1084static void MigrateObject(Address dst, Address src, int size) {
1085 Heap::CopyBlock(reinterpret_cast<Object**>(dst),
1086 reinterpret_cast<Object**>(src),
1087 size);
1088
1089 Memory::Address_at(src) = dst;
1090}
1091
1092
1093// Visitor for updating pointers from live objects in old spaces to new space.
1094// It does not expect to encounter pointers to dead objects.
1095class PointersToNewGenUpdatingVisitor: public ObjectVisitor {
1096 public:
1097 void VisitPointer(Object** p) {
1098 UpdatePointer(p);
1099 }
1100
1101 void VisitPointers(Object** start, Object** end) {
1102 for (Object** p = start; p < end; p++) UpdatePointer(p);
1103 }
1104
1105 void VisitCodeTarget(RelocInfo* rinfo) {
1106 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
1107 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
1108 VisitPointer(&target);
1109 rinfo->set_target_address(Code::cast(target)->instruction_start());
1110 }
1111
1112 void VisitDebugTarget(RelocInfo* rinfo) {
1113 ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()) &&
1114 rinfo->IsPatchedReturnSequence());
1115 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
1116 VisitPointer(&target);
1117 rinfo->set_call_address(Code::cast(target)->instruction_start());
1118 }
1119
1120 private:
1121 void UpdatePointer(Object** p) {
1122 if (!(*p)->IsHeapObject()) return;
1123
1124 HeapObject* obj = HeapObject::cast(*p);
1125 Address old_addr = obj->address();
1126
1127 if (Heap::new_space()->Contains(obj)) {
1128 ASSERT(Heap::InFromSpace(*p));
1129 *p = HeapObject::FromAddress(Memory::Address_at(old_addr));
1130 }
1131 }
1132};
1133
1134// Visitor for updating pointers from live objects in old spaces to new space.
1135// It can encounter pointers to dead objects in new space when traversing map
1136// space (see comment for MigrateObject).
1137static void UpdatePointerToNewGen(HeapObject** p) {
1138 if (!(*p)->IsHeapObject()) return;
1139
1140 Address old_addr = (*p)->address();
1141 ASSERT(Heap::InFromSpace(*p));
1142
1143 Address new_addr = Memory::Address_at(old_addr);
1144
1145 // Object pointed by *p is dead. Update is not required.
1146 if (new_addr == NULL) return;
1147
1148 *p = HeapObject::FromAddress(new_addr);
1149}
1150
1151
1152static String* UpdateNewSpaceReferenceInExternalStringTableEntry(Object **p) {
1153 Address old_addr = HeapObject::cast(*p)->address();
1154 Address new_addr = Memory::Address_at(old_addr);
1155 return String::cast(HeapObject::FromAddress(new_addr));
1156}
1157
1158
1159static bool TryPromoteObject(HeapObject* object, int object_size) {
1160 Object* result;
1161
1162 if (object_size > Heap::MaxObjectSizeInPagedSpace()) {
1163 result = Heap::lo_space()->AllocateRawFixedArray(object_size);
1164 if (!result->IsFailure()) {
1165 HeapObject* target = HeapObject::cast(result);
1166 MigrateObject(target->address(), object->address(), object_size);
1167 Heap::UpdateRSet(target);
Leon Clarkef7060e22010-06-03 12:02:55 +01001168 MarkCompactCollector::tracer()->
1169 increment_promoted_objects_size(object_size);
Steve Block6ded16b2010-05-10 14:33:55 +01001170 return true;
1171 }
1172 } else {
1173 OldSpace* target_space = Heap::TargetSpace(object);
1174
1175 ASSERT(target_space == Heap::old_pointer_space() ||
1176 target_space == Heap::old_data_space());
1177 result = target_space->AllocateRaw(object_size);
1178 if (!result->IsFailure()) {
1179 HeapObject* target = HeapObject::cast(result);
1180 MigrateObject(target->address(), object->address(), object_size);
1181 if (target_space == Heap::old_pointer_space()) {
1182 Heap::UpdateRSet(target);
1183 }
Leon Clarkef7060e22010-06-03 12:02:55 +01001184 MarkCompactCollector::tracer()->
1185 increment_promoted_objects_size(object_size);
Steve Block6ded16b2010-05-10 14:33:55 +01001186 return true;
1187 }
1188 }
1189
1190 return false;
1191}
1192
1193
1194static void SweepNewSpace(NewSpace* space) {
1195 Heap::CheckNewSpaceExpansionCriteria();
1196
1197 Address from_bottom = space->bottom();
1198 Address from_top = space->top();
1199
1200 // Flip the semispaces. After flipping, to space is empty, from space has
1201 // live objects.
1202 space->Flip();
1203 space->ResetAllocationInfo();
1204
1205 int size = 0;
1206 int survivors_size = 0;
1207
1208 // First pass: traverse all objects in inactive semispace, remove marks,
1209 // migrate live objects and write forwarding addresses.
1210 for (Address current = from_bottom; current < from_top; current += size) {
1211 HeapObject* object = HeapObject::FromAddress(current);
1212
1213 if (object->IsMarked()) {
1214 object->ClearMark();
1215 MarkCompactCollector::tracer()->decrement_marked_count();
1216
1217 size = object->Size();
1218 survivors_size += size;
1219
1220 // Aggressively promote young survivors to the old space.
1221 if (TryPromoteObject(object, size)) {
1222 continue;
1223 }
1224
1225 // Promotion either failed or not required.
1226 // Copy the content of the object.
1227 Object* target = space->AllocateRaw(size);
1228
1229 // Allocation cannot fail at this point: semispaces are of equal size.
1230 ASSERT(!target->IsFailure());
1231
1232 MigrateObject(HeapObject::cast(target)->address(), current, size);
1233 } else {
1234 size = object->Size();
1235 Memory::Address_at(current) = NULL;
1236 }
1237 }
1238
1239 // Second pass: find pointers to new space and update them.
1240 PointersToNewGenUpdatingVisitor updating_visitor;
1241
1242 // Update pointers in to space.
Steve Blocka7e24c12009-10-30 11:49:00 +00001243 HeapObject* object;
1244 for (Address current = space->bottom();
1245 current < space->top();
1246 current += object->Size()) {
1247 object = HeapObject::FromAddress(current);
Steve Block6ded16b2010-05-10 14:33:55 +01001248
1249 object->IterateBody(object->map()->instance_type(),
1250 object->Size(),
1251 &updating_visitor);
Steve Blocka7e24c12009-10-30 11:49:00 +00001252 }
Steve Block6ded16b2010-05-10 14:33:55 +01001253
1254 // Update roots.
1255 Heap::IterateRoots(&updating_visitor, VISIT_ALL_IN_SCAVENGE);
1256
1257 // Update pointers in old spaces.
1258 Heap::IterateRSet(Heap::old_pointer_space(), &UpdatePointerToNewGen);
1259 Heap::IterateRSet(Heap::map_space(), &UpdatePointerToNewGen);
1260 Heap::lo_space()->IterateRSet(&UpdatePointerToNewGen);
1261
1262 // Update pointers from cells.
1263 HeapObjectIterator cell_iterator(Heap::cell_space());
1264 for (HeapObject* cell = cell_iterator.next();
1265 cell != NULL;
1266 cell = cell_iterator.next()) {
1267 if (cell->IsJSGlobalPropertyCell()) {
1268 Address value_address =
1269 reinterpret_cast<Address>(cell) +
1270 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag);
1271 updating_visitor.VisitPointer(reinterpret_cast<Object**>(value_address));
1272 }
1273 }
1274
1275 // Update pointers from external string table.
1276 Heap::UpdateNewSpaceReferencesInExternalStringTable(
1277 &UpdateNewSpaceReferenceInExternalStringTableEntry);
1278
1279 // All pointers were updated. Update auxiliary allocation info.
1280 Heap::IncrementYoungSurvivorsCounter(survivors_size);
1281 space->set_age_mark(space->top());
Steve Blocka7e24c12009-10-30 11:49:00 +00001282}
1283
1284
1285static void SweepSpace(PagedSpace* space, DeallocateFunction dealloc) {
1286 PageIterator it(space, PageIterator::PAGES_IN_USE);
Steve Block6ded16b2010-05-10 14:33:55 +01001287
1288 // During sweeping of paged space we are trying to find longest sequences
1289 // of pages without live objects and free them (instead of putting them on
1290 // the free list).
1291
1292 // Page preceding current.
1293 Page* prev = Page::FromAddress(NULL);
1294
1295 // First empty page in a sequence.
1296 Page* first_empty_page = Page::FromAddress(NULL);
1297
1298 // Page preceding first empty page.
1299 Page* prec_first_empty_page = Page::FromAddress(NULL);
1300
1301 // If last used page of space ends with a sequence of dead objects
1302 // we can adjust allocation top instead of puting this free area into
1303 // the free list. Thus during sweeping we keep track of such areas
1304 // and defer their deallocation until the sweeping of the next page
1305 // is done: if one of the next pages contains live objects we have
1306 // to put such area into the free list.
1307 Address last_free_start = NULL;
1308 int last_free_size = 0;
1309
Steve Blocka7e24c12009-10-30 11:49:00 +00001310 while (it.has_next()) {
1311 Page* p = it.next();
1312
1313 bool is_previous_alive = true;
1314 Address free_start = NULL;
1315 HeapObject* object;
1316
1317 for (Address current = p->ObjectAreaStart();
1318 current < p->AllocationTop();
1319 current += object->Size()) {
1320 object = HeapObject::FromAddress(current);
1321 if (object->IsMarked()) {
1322 object->ClearMark();
1323 MarkCompactCollector::tracer()->decrement_marked_count();
Steve Block6ded16b2010-05-10 14:33:55 +01001324
Steve Blocka7e24c12009-10-30 11:49:00 +00001325 if (!is_previous_alive) { // Transition from free to live.
Steve Block6ded16b2010-05-10 14:33:55 +01001326 dealloc(free_start, static_cast<int>(current - free_start), true);
Steve Blocka7e24c12009-10-30 11:49:00 +00001327 is_previous_alive = true;
1328 }
1329 } else {
Leon Clarked91b9f72010-01-27 17:25:45 +00001330 MarkCompactCollector::ReportDeleteIfNeeded(object);
Steve Blocka7e24c12009-10-30 11:49:00 +00001331 if (is_previous_alive) { // Transition from live to free.
1332 free_start = current;
1333 is_previous_alive = false;
1334 }
1335 }
1336 // The object is now unmarked for the call to Size() at the top of the
1337 // loop.
1338 }
1339
Steve Block6ded16b2010-05-10 14:33:55 +01001340 bool page_is_empty = (p->ObjectAreaStart() == p->AllocationTop())
1341 || (!is_previous_alive && free_start == p->ObjectAreaStart());
1342
1343 if (page_is_empty) {
1344 // This page is empty. Check whether we are in the middle of
1345 // sequence of empty pages and start one if not.
1346 if (!first_empty_page->is_valid()) {
1347 first_empty_page = p;
1348 prec_first_empty_page = prev;
1349 }
1350
1351 if (!is_previous_alive) {
1352 // There are dead objects on this page. Update space accounting stats
1353 // without putting anything into free list.
1354 int size_in_bytes = static_cast<int>(p->AllocationTop() - free_start);
1355 if (size_in_bytes > 0) {
1356 dealloc(free_start, size_in_bytes, false);
1357 }
1358 }
1359 } else {
1360 // This page is not empty. Sequence of empty pages ended on the previous
1361 // one.
1362 if (first_empty_page->is_valid()) {
1363 space->FreePages(prec_first_empty_page, prev);
1364 prec_first_empty_page = first_empty_page = Page::FromAddress(NULL);
1365 }
1366
1367 // If there is a free ending area on one of the previous pages we have
1368 // deallocate that area and put it on the free list.
1369 if (last_free_size > 0) {
1370 dealloc(last_free_start, last_free_size, true);
1371 last_free_start = NULL;
1372 last_free_size = 0;
1373 }
1374
1375 // If the last region of this page was not live we remember it.
1376 if (!is_previous_alive) {
1377 ASSERT(last_free_size == 0);
1378 last_free_size = static_cast<int>(p->AllocationTop() - free_start);
1379 last_free_start = free_start;
Steve Blocka7e24c12009-10-30 11:49:00 +00001380 }
1381 }
Steve Block6ded16b2010-05-10 14:33:55 +01001382
1383 prev = p;
1384 }
1385
1386 // We reached end of space. See if we need to adjust allocation top.
1387 Address new_allocation_top = NULL;
1388
1389 if (first_empty_page->is_valid()) {
1390 // Last used pages in space are empty. We can move allocation top backwards
1391 // to the beginning of first empty page.
1392 ASSERT(prev == space->AllocationTopPage());
1393
1394 new_allocation_top = first_empty_page->ObjectAreaStart();
1395 }
1396
1397 if (last_free_size > 0) {
1398 // There was a free ending area on the previous page.
1399 // Deallocate it without putting it into freelist and move allocation
1400 // top to the beginning of this free area.
1401 dealloc(last_free_start, last_free_size, false);
1402 new_allocation_top = last_free_start;
1403 }
1404
1405 if (new_allocation_top != NULL) {
1406#ifdef DEBUG
1407 Page* new_allocation_top_page = Page::FromAllocationTop(new_allocation_top);
1408 if (!first_empty_page->is_valid()) {
1409 ASSERT(new_allocation_top_page == space->AllocationTopPage());
1410 } else if (last_free_size > 0) {
1411 ASSERT(new_allocation_top_page == prec_first_empty_page);
1412 } else {
1413 ASSERT(new_allocation_top_page == first_empty_page);
1414 }
1415#endif
1416
1417 space->SetTop(new_allocation_top);
Steve Blocka7e24c12009-10-30 11:49:00 +00001418 }
1419}
1420
1421
1422void MarkCompactCollector::DeallocateOldPointerBlock(Address start,
Steve Block6ded16b2010-05-10 14:33:55 +01001423 int size_in_bytes,
1424 bool add_to_freelist) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001425 Heap::ClearRSetRange(start, size_in_bytes);
Steve Block6ded16b2010-05-10 14:33:55 +01001426 Heap::old_pointer_space()->Free(start, size_in_bytes, add_to_freelist);
Steve Blocka7e24c12009-10-30 11:49:00 +00001427}
1428
1429
1430void MarkCompactCollector::DeallocateOldDataBlock(Address start,
Steve Block6ded16b2010-05-10 14:33:55 +01001431 int size_in_bytes,
1432 bool add_to_freelist) {
1433 Heap::old_data_space()->Free(start, size_in_bytes, add_to_freelist);
Steve Blocka7e24c12009-10-30 11:49:00 +00001434}
1435
1436
1437void MarkCompactCollector::DeallocateCodeBlock(Address start,
Steve Block6ded16b2010-05-10 14:33:55 +01001438 int size_in_bytes,
1439 bool add_to_freelist) {
1440 Heap::code_space()->Free(start, size_in_bytes, add_to_freelist);
Steve Blocka7e24c12009-10-30 11:49:00 +00001441}
1442
1443
1444void MarkCompactCollector::DeallocateMapBlock(Address start,
Steve Block6ded16b2010-05-10 14:33:55 +01001445 int size_in_bytes,
1446 bool add_to_freelist) {
Leon Clarkee46be812010-01-19 14:06:41 +00001447 // Objects in map space are assumed to have size Map::kSize and a
Steve Blocka7e24c12009-10-30 11:49:00 +00001448 // valid map in their first word. Thus, we break the free block up into
1449 // chunks and free them separately.
1450 ASSERT(size_in_bytes % Map::kSize == 0);
1451 Heap::ClearRSetRange(start, size_in_bytes);
1452 Address end = start + size_in_bytes;
1453 for (Address a = start; a < end; a += Map::kSize) {
Steve Block6ded16b2010-05-10 14:33:55 +01001454 Heap::map_space()->Free(a, add_to_freelist);
Steve Blocka7e24c12009-10-30 11:49:00 +00001455 }
1456}
1457
1458
1459void MarkCompactCollector::DeallocateCellBlock(Address start,
Steve Block6ded16b2010-05-10 14:33:55 +01001460 int size_in_bytes,
1461 bool add_to_freelist) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001462 // Free-list elements in cell space are assumed to have a fixed size.
1463 // We break the free block into chunks and add them to the free list
1464 // individually.
1465 int size = Heap::cell_space()->object_size_in_bytes();
1466 ASSERT(size_in_bytes % size == 0);
1467 Heap::ClearRSetRange(start, size_in_bytes);
1468 Address end = start + size_in_bytes;
1469 for (Address a = start; a < end; a += size) {
Steve Block6ded16b2010-05-10 14:33:55 +01001470 Heap::cell_space()->Free(a, add_to_freelist);
Steve Blocka7e24c12009-10-30 11:49:00 +00001471 }
1472}
1473
1474
1475void MarkCompactCollector::EncodeForwardingAddresses() {
1476 ASSERT(state_ == ENCODE_FORWARDING_ADDRESSES);
1477 // Objects in the active semispace of the young generation may be
1478 // relocated to the inactive semispace (if not promoted). Set the
1479 // relocation info to the beginning of the inactive semispace.
1480 Heap::new_space()->MCResetRelocationInfo();
1481
1482 // Compute the forwarding pointers in each space.
1483 EncodeForwardingAddressesInPagedSpace<MCAllocateFromOldPointerSpace,
Leon Clarked91b9f72010-01-27 17:25:45 +00001484 ReportDeleteIfNeeded>(
Steve Blocka7e24c12009-10-30 11:49:00 +00001485 Heap::old_pointer_space());
1486
1487 EncodeForwardingAddressesInPagedSpace<MCAllocateFromOldDataSpace,
1488 IgnoreNonLiveObject>(
1489 Heap::old_data_space());
1490
1491 EncodeForwardingAddressesInPagedSpace<MCAllocateFromCodeSpace,
Leon Clarked91b9f72010-01-27 17:25:45 +00001492 ReportDeleteIfNeeded>(
Steve Blocka7e24c12009-10-30 11:49:00 +00001493 Heap::code_space());
1494
1495 EncodeForwardingAddressesInPagedSpace<MCAllocateFromCellSpace,
1496 IgnoreNonLiveObject>(
1497 Heap::cell_space());
1498
1499
1500 // Compute new space next to last after the old and code spaces have been
1501 // compacted. Objects in new space can be promoted to old or code space.
1502 EncodeForwardingAddressesInNewSpace();
1503
1504 // Compute map space last because computing forwarding addresses
1505 // overwrites non-live objects. Objects in the other spaces rely on
1506 // non-live map pointers to get the sizes of non-live objects.
1507 EncodeForwardingAddressesInPagedSpace<MCAllocateFromMapSpace,
1508 IgnoreNonLiveObject>(
1509 Heap::map_space());
1510
1511 // Write relocation info to the top page, so we can use it later. This is
1512 // done after promoting objects from the new space so we get the correct
1513 // allocation top.
1514 Heap::old_pointer_space()->MCWriteRelocationInfoToPage();
1515 Heap::old_data_space()->MCWriteRelocationInfoToPage();
1516 Heap::code_space()->MCWriteRelocationInfoToPage();
1517 Heap::map_space()->MCWriteRelocationInfoToPage();
1518 Heap::cell_space()->MCWriteRelocationInfoToPage();
1519}
1520
1521
Leon Clarkee46be812010-01-19 14:06:41 +00001522class MapIterator : public HeapObjectIterator {
1523 public:
1524 MapIterator() : HeapObjectIterator(Heap::map_space(), &SizeCallback) { }
1525
1526 explicit MapIterator(Address start)
1527 : HeapObjectIterator(Heap::map_space(), start, &SizeCallback) { }
1528
1529 private:
1530 static int SizeCallback(HeapObject* unused) {
1531 USE(unused);
1532 return Map::kSize;
1533 }
1534};
1535
1536
1537class MapCompact {
1538 public:
1539 explicit MapCompact(int live_maps)
1540 : live_maps_(live_maps),
1541 to_evacuate_start_(Heap::map_space()->TopAfterCompaction(live_maps)),
1542 map_to_evacuate_it_(to_evacuate_start_),
1543 first_map_to_evacuate_(
1544 reinterpret_cast<Map*>(HeapObject::FromAddress(to_evacuate_start_))) {
1545 }
1546
1547 void CompactMaps() {
1548 // As we know the number of maps to evacuate beforehand,
1549 // we stop then there is no more vacant maps.
1550 for (Map* next_vacant_map = NextVacantMap();
1551 next_vacant_map;
1552 next_vacant_map = NextVacantMap()) {
1553 EvacuateMap(next_vacant_map, NextMapToEvacuate());
1554 }
1555
1556#ifdef DEBUG
1557 CheckNoMapsToEvacuate();
1558#endif
1559 }
1560
1561 void UpdateMapPointersInRoots() {
1562 Heap::IterateRoots(&map_updating_visitor_, VISIT_ONLY_STRONG);
1563 GlobalHandles::IterateWeakRoots(&map_updating_visitor_);
1564 }
1565
1566 void FinishMapSpace() {
1567 // Iterate through to space and finish move.
1568 MapIterator it;
1569 HeapObject* o = it.next();
1570 for (; o != first_map_to_evacuate_; o = it.next()) {
Leon Clarked91b9f72010-01-27 17:25:45 +00001571 ASSERT(o != NULL);
Leon Clarkee46be812010-01-19 14:06:41 +00001572 Map* map = reinterpret_cast<Map*>(o);
1573 ASSERT(!map->IsMarked());
1574 ASSERT(!map->IsOverflowed());
1575 ASSERT(map->IsMap());
1576 Heap::UpdateRSet(map);
1577 }
1578 }
1579
1580 void UpdateMapPointersInPagedSpace(PagedSpace* space) {
1581 ASSERT(space != Heap::map_space());
1582
1583 PageIterator it(space, PageIterator::PAGES_IN_USE);
1584 while (it.has_next()) {
1585 Page* p = it.next();
1586 UpdateMapPointersInRange(p->ObjectAreaStart(), p->AllocationTop());
1587 }
1588 }
1589
1590 void UpdateMapPointersInNewSpace() {
1591 NewSpace* space = Heap::new_space();
1592 UpdateMapPointersInRange(space->bottom(), space->top());
1593 }
1594
1595 void UpdateMapPointersInLargeObjectSpace() {
1596 LargeObjectIterator it(Heap::lo_space());
Leon Clarked91b9f72010-01-27 17:25:45 +00001597 for (HeapObject* obj = it.next(); obj != NULL; obj = it.next())
1598 UpdateMapPointersInObject(obj);
Leon Clarkee46be812010-01-19 14:06:41 +00001599 }
1600
1601 void Finish() {
1602 Heap::map_space()->FinishCompaction(to_evacuate_start_, live_maps_);
1603 }
1604
1605 private:
1606 int live_maps_;
1607 Address to_evacuate_start_;
1608 MapIterator vacant_map_it_;
1609 MapIterator map_to_evacuate_it_;
1610 Map* first_map_to_evacuate_;
1611
1612 // Helper class for updating map pointers in HeapObjects.
1613 class MapUpdatingVisitor: public ObjectVisitor {
1614 public:
1615 void VisitPointer(Object** p) {
1616 UpdateMapPointer(p);
1617 }
1618
1619 void VisitPointers(Object** start, Object** end) {
1620 for (Object** p = start; p < end; p++) UpdateMapPointer(p);
1621 }
1622
1623 private:
1624 void UpdateMapPointer(Object** p) {
1625 if (!(*p)->IsHeapObject()) return;
1626 HeapObject* old_map = reinterpret_cast<HeapObject*>(*p);
1627
1628 // Moved maps are tagged with overflowed map word. They are the only
1629 // objects those map word is overflowed as marking is already complete.
1630 MapWord map_word = old_map->map_word();
1631 if (!map_word.IsOverflowed()) return;
1632
1633 *p = GetForwardedMap(map_word);
1634 }
1635 };
1636
1637 static MapUpdatingVisitor map_updating_visitor_;
1638
1639 static Map* NextMap(MapIterator* it, HeapObject* last, bool live) {
1640 while (true) {
Leon Clarkee46be812010-01-19 14:06:41 +00001641 HeapObject* next = it->next();
Leon Clarked91b9f72010-01-27 17:25:45 +00001642 ASSERT(next != NULL);
Leon Clarkee46be812010-01-19 14:06:41 +00001643 if (next == last)
1644 return NULL;
1645 ASSERT(!next->IsOverflowed());
1646 ASSERT(!next->IsMarked());
1647 ASSERT(next->IsMap() || FreeListNode::IsFreeListNode(next));
1648 if (next->IsMap() == live)
1649 return reinterpret_cast<Map*>(next);
1650 }
1651 }
1652
1653 Map* NextVacantMap() {
1654 Map* map = NextMap(&vacant_map_it_, first_map_to_evacuate_, false);
1655 ASSERT(map == NULL || FreeListNode::IsFreeListNode(map));
1656 return map;
1657 }
1658
1659 Map* NextMapToEvacuate() {
1660 Map* map = NextMap(&map_to_evacuate_it_, NULL, true);
1661 ASSERT(map != NULL);
1662 ASSERT(map->IsMap());
1663 return map;
1664 }
1665
1666 static void EvacuateMap(Map* vacant_map, Map* map_to_evacuate) {
1667 ASSERT(FreeListNode::IsFreeListNode(vacant_map));
1668 ASSERT(map_to_evacuate->IsMap());
1669
Steve Block6ded16b2010-05-10 14:33:55 +01001670 ASSERT(Map::kSize % 4 == 0);
1671
1672 Heap::CopyBlock(reinterpret_cast<Object**>(vacant_map->address()),
1673 reinterpret_cast<Object**>(map_to_evacuate->address()),
1674 Map::kSize);
1675
Leon Clarkee46be812010-01-19 14:06:41 +00001676 ASSERT(vacant_map->IsMap()); // Due to memcpy above.
1677
1678 MapWord forwarding_map_word = MapWord::FromMap(vacant_map);
1679 forwarding_map_word.SetOverflow();
1680 map_to_evacuate->set_map_word(forwarding_map_word);
1681
1682 ASSERT(map_to_evacuate->map_word().IsOverflowed());
1683 ASSERT(GetForwardedMap(map_to_evacuate->map_word()) == vacant_map);
1684 }
1685
1686 static Map* GetForwardedMap(MapWord map_word) {
1687 ASSERT(map_word.IsOverflowed());
1688 map_word.ClearOverflow();
1689 Map* new_map = map_word.ToMap();
1690 ASSERT_MAP_ALIGNED(new_map->address());
1691 return new_map;
1692 }
1693
1694 static int UpdateMapPointersInObject(HeapObject* obj) {
1695 ASSERT(!obj->IsMarked());
1696 Map* map = obj->map();
1697 ASSERT(Heap::map_space()->Contains(map));
1698 MapWord map_word = map->map_word();
1699 ASSERT(!map_word.IsMarked());
1700 if (map_word.IsOverflowed()) {
1701 Map* new_map = GetForwardedMap(map_word);
1702 ASSERT(Heap::map_space()->Contains(new_map));
1703 obj->set_map(new_map);
1704
1705#ifdef DEBUG
1706 if (FLAG_gc_verbose) {
1707 PrintF("update %p : %p -> %p\n", obj->address(),
1708 map, new_map);
1709 }
1710#endif
1711 }
1712
1713 int size = obj->SizeFromMap(map);
1714 obj->IterateBody(map->instance_type(), size, &map_updating_visitor_);
1715 return size;
1716 }
1717
1718 static void UpdateMapPointersInRange(Address start, Address end) {
1719 HeapObject* object;
1720 int size;
1721 for (Address current = start; current < end; current += size) {
1722 object = HeapObject::FromAddress(current);
1723 size = UpdateMapPointersInObject(object);
1724 ASSERT(size > 0);
1725 }
1726 }
1727
1728#ifdef DEBUG
1729 void CheckNoMapsToEvacuate() {
1730 if (!FLAG_enable_slow_asserts)
1731 return;
1732
Leon Clarked91b9f72010-01-27 17:25:45 +00001733 for (HeapObject* obj = map_to_evacuate_it_.next();
1734 obj != NULL; obj = map_to_evacuate_it_.next())
1735 ASSERT(FreeListNode::IsFreeListNode(obj));
Leon Clarkee46be812010-01-19 14:06:41 +00001736 }
1737#endif
1738};
1739
1740MapCompact::MapUpdatingVisitor MapCompact::map_updating_visitor_;
1741
1742
Steve Blocka7e24c12009-10-30 11:49:00 +00001743void MarkCompactCollector::SweepSpaces() {
Leon Clarkef7060e22010-06-03 12:02:55 +01001744 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP);
1745
Steve Blocka7e24c12009-10-30 11:49:00 +00001746 ASSERT(state_ == SWEEP_SPACES);
1747 ASSERT(!IsCompacting());
1748 // Noncompacting collections simply sweep the spaces to clear the mark
1749 // bits and free the nonlive blocks (for old and map spaces). We sweep
1750 // the map space last because freeing non-live maps overwrites them and
1751 // the other spaces rely on possibly non-live maps to get the sizes for
1752 // non-live objects.
1753 SweepSpace(Heap::old_pointer_space(), &DeallocateOldPointerBlock);
1754 SweepSpace(Heap::old_data_space(), &DeallocateOldDataBlock);
1755 SweepSpace(Heap::code_space(), &DeallocateCodeBlock);
1756 SweepSpace(Heap::cell_space(), &DeallocateCellBlock);
Steve Block6ded16b2010-05-10 14:33:55 +01001757 SweepNewSpace(Heap::new_space());
Steve Blocka7e24c12009-10-30 11:49:00 +00001758 SweepSpace(Heap::map_space(), &DeallocateMapBlock);
Steve Block6ded16b2010-05-10 14:33:55 +01001759 int live_maps_size = Heap::map_space()->Size();
1760 int live_maps = live_maps_size / Map::kSize;
1761 ASSERT(live_map_objects_size_ == live_maps_size);
Leon Clarkee46be812010-01-19 14:06:41 +00001762
1763 if (Heap::map_space()->NeedsCompaction(live_maps)) {
1764 MapCompact map_compact(live_maps);
1765
1766 map_compact.CompactMaps();
1767 map_compact.UpdateMapPointersInRoots();
1768
1769 map_compact.FinishMapSpace();
1770 PagedSpaces spaces;
Leon Clarked91b9f72010-01-27 17:25:45 +00001771 for (PagedSpace* space = spaces.next();
1772 space != NULL; space = spaces.next()) {
Leon Clarkee46be812010-01-19 14:06:41 +00001773 if (space == Heap::map_space()) continue;
1774 map_compact.UpdateMapPointersInPagedSpace(space);
1775 }
1776 map_compact.UpdateMapPointersInNewSpace();
1777 map_compact.UpdateMapPointersInLargeObjectSpace();
1778
1779 map_compact.Finish();
1780 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001781}
1782
1783
1784// Iterate the live objects in a range of addresses (eg, a page or a
1785// semispace). The live regions of the range have been linked into a list.
1786// The first live region is [first_live_start, first_live_end), and the last
1787// address in the range is top. The callback function is used to get the
1788// size of each live object.
1789int MarkCompactCollector::IterateLiveObjectsInRange(
1790 Address start,
1791 Address end,
1792 HeapObjectCallback size_func) {
Steve Block6ded16b2010-05-10 14:33:55 +01001793 int live_objects_size = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001794 Address current = start;
1795 while (current < end) {
1796 uint32_t encoded_map = Memory::uint32_at(current);
1797 if (encoded_map == kSingleFreeEncoding) {
1798 current += kPointerSize;
1799 } else if (encoded_map == kMultiFreeEncoding) {
1800 current += Memory::int_at(current + kIntSize);
1801 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001802 int size = size_func(HeapObject::FromAddress(current));
1803 current += size;
1804 live_objects_size += size;
Steve Blocka7e24c12009-10-30 11:49:00 +00001805 }
1806 }
Steve Block6ded16b2010-05-10 14:33:55 +01001807 return live_objects_size;
Steve Blocka7e24c12009-10-30 11:49:00 +00001808}
1809
1810
1811int MarkCompactCollector::IterateLiveObjects(NewSpace* space,
1812 HeapObjectCallback size_f) {
1813 ASSERT(MARK_LIVE_OBJECTS < state_ && state_ <= RELOCATE_OBJECTS);
1814 return IterateLiveObjectsInRange(space->bottom(), space->top(), size_f);
1815}
1816
1817
1818int MarkCompactCollector::IterateLiveObjects(PagedSpace* space,
1819 HeapObjectCallback size_f) {
1820 ASSERT(MARK_LIVE_OBJECTS < state_ && state_ <= RELOCATE_OBJECTS);
1821 int total = 0;
1822 PageIterator it(space, PageIterator::PAGES_IN_USE);
1823 while (it.has_next()) {
1824 Page* p = it.next();
1825 total += IterateLiveObjectsInRange(p->ObjectAreaStart(),
1826 p->AllocationTop(),
1827 size_f);
1828 }
1829 return total;
1830}
1831
1832
1833// -------------------------------------------------------------------------
1834// Phase 3: Update pointers
1835
1836// Helper class for updating pointers in HeapObjects.
1837class UpdatingVisitor: public ObjectVisitor {
1838 public:
1839 void VisitPointer(Object** p) {
1840 UpdatePointer(p);
1841 }
1842
1843 void VisitPointers(Object** start, Object** end) {
1844 // Mark all HeapObject pointers in [start, end)
1845 for (Object** p = start; p < end; p++) UpdatePointer(p);
1846 }
1847
1848 void VisitCodeTarget(RelocInfo* rinfo) {
1849 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
1850 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
1851 VisitPointer(&target);
1852 rinfo->set_target_address(
1853 reinterpret_cast<Code*>(target)->instruction_start());
1854 }
1855
Steve Block3ce2e202009-11-05 08:53:23 +00001856 void VisitDebugTarget(RelocInfo* rinfo) {
1857 ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()) &&
1858 rinfo->IsPatchedReturnSequence());
1859 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
1860 VisitPointer(&target);
1861 rinfo->set_call_address(
1862 reinterpret_cast<Code*>(target)->instruction_start());
1863 }
1864
Steve Blocka7e24c12009-10-30 11:49:00 +00001865 private:
1866 void UpdatePointer(Object** p) {
1867 if (!(*p)->IsHeapObject()) return;
1868
1869 HeapObject* obj = HeapObject::cast(*p);
1870 Address old_addr = obj->address();
1871 Address new_addr;
1872 ASSERT(!Heap::InFromSpace(obj));
1873
1874 if (Heap::new_space()->Contains(obj)) {
1875 Address forwarding_pointer_addr =
1876 Heap::new_space()->FromSpaceLow() +
1877 Heap::new_space()->ToSpaceOffsetForAddress(old_addr);
1878 new_addr = Memory::Address_at(forwarding_pointer_addr);
1879
1880#ifdef DEBUG
1881 ASSERT(Heap::old_pointer_space()->Contains(new_addr) ||
1882 Heap::old_data_space()->Contains(new_addr) ||
1883 Heap::new_space()->FromSpaceContains(new_addr) ||
1884 Heap::lo_space()->Contains(HeapObject::FromAddress(new_addr)));
1885
1886 if (Heap::new_space()->FromSpaceContains(new_addr)) {
1887 ASSERT(Heap::new_space()->FromSpaceOffsetForAddress(new_addr) <=
1888 Heap::new_space()->ToSpaceOffsetForAddress(old_addr));
1889 }
1890#endif
1891
1892 } else if (Heap::lo_space()->Contains(obj)) {
1893 // Don't move objects in the large object space.
1894 return;
1895
1896 } else {
1897#ifdef DEBUG
1898 PagedSpaces spaces;
1899 PagedSpace* original_space = spaces.next();
1900 while (original_space != NULL) {
1901 if (original_space->Contains(obj)) break;
1902 original_space = spaces.next();
1903 }
1904 ASSERT(original_space != NULL);
1905#endif
1906 new_addr = MarkCompactCollector::GetForwardingAddressInOldSpace(obj);
1907 ASSERT(original_space->Contains(new_addr));
1908 ASSERT(original_space->MCSpaceOffsetForAddress(new_addr) <=
1909 original_space->MCSpaceOffsetForAddress(old_addr));
1910 }
1911
1912 *p = HeapObject::FromAddress(new_addr);
1913
1914#ifdef DEBUG
1915 if (FLAG_gc_verbose) {
1916 PrintF("update %p : %p -> %p\n",
1917 reinterpret_cast<Address>(p), old_addr, new_addr);
1918 }
1919#endif
1920 }
1921};
1922
1923
1924void MarkCompactCollector::UpdatePointers() {
1925#ifdef DEBUG
1926 ASSERT(state_ == ENCODE_FORWARDING_ADDRESSES);
1927 state_ = UPDATE_POINTERS;
1928#endif
1929 UpdatingVisitor updating_visitor;
Steve Blockd0582a62009-12-15 09:54:21 +00001930 Heap::IterateRoots(&updating_visitor, VISIT_ONLY_STRONG);
Steve Blocka7e24c12009-10-30 11:49:00 +00001931 GlobalHandles::IterateWeakRoots(&updating_visitor);
1932
Steve Block6ded16b2010-05-10 14:33:55 +01001933 int live_maps_size = IterateLiveObjects(Heap::map_space(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001934 &UpdatePointersInOldObject);
Steve Block6ded16b2010-05-10 14:33:55 +01001935 int live_pointer_olds_size = IterateLiveObjects(Heap::old_pointer_space(),
1936 &UpdatePointersInOldObject);
1937 int live_data_olds_size = IterateLiveObjects(Heap::old_data_space(),
1938 &UpdatePointersInOldObject);
1939 int live_codes_size = IterateLiveObjects(Heap::code_space(),
1940 &UpdatePointersInOldObject);
1941 int live_cells_size = IterateLiveObjects(Heap::cell_space(),
1942 &UpdatePointersInOldObject);
1943 int live_news_size = IterateLiveObjects(Heap::new_space(),
1944 &UpdatePointersInNewObject);
Steve Blocka7e24c12009-10-30 11:49:00 +00001945
1946 // Large objects do not move, the map word can be updated directly.
1947 LargeObjectIterator it(Heap::lo_space());
Leon Clarked91b9f72010-01-27 17:25:45 +00001948 for (HeapObject* obj = it.next(); obj != NULL; obj = it.next())
1949 UpdatePointersInNewObject(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00001950
Steve Block6ded16b2010-05-10 14:33:55 +01001951 USE(live_maps_size);
1952 USE(live_pointer_olds_size);
1953 USE(live_data_olds_size);
1954 USE(live_codes_size);
1955 USE(live_cells_size);
1956 USE(live_news_size);
1957 ASSERT(live_maps_size == live_map_objects_size_);
1958 ASSERT(live_data_olds_size == live_old_data_objects_size_);
1959 ASSERT(live_pointer_olds_size == live_old_pointer_objects_size_);
1960 ASSERT(live_codes_size == live_code_objects_size_);
1961 ASSERT(live_cells_size == live_cell_objects_size_);
1962 ASSERT(live_news_size == live_young_objects_size_);
Steve Blocka7e24c12009-10-30 11:49:00 +00001963}
1964
1965
1966int MarkCompactCollector::UpdatePointersInNewObject(HeapObject* obj) {
1967 // Keep old map pointers
1968 Map* old_map = obj->map();
1969 ASSERT(old_map->IsHeapObject());
1970
1971 Address forwarded = GetForwardingAddressInOldSpace(old_map);
1972
1973 ASSERT(Heap::map_space()->Contains(old_map));
1974 ASSERT(Heap::map_space()->Contains(forwarded));
1975#ifdef DEBUG
1976 if (FLAG_gc_verbose) {
1977 PrintF("update %p : %p -> %p\n", obj->address(), old_map->address(),
1978 forwarded);
1979 }
1980#endif
1981 // Update the map pointer.
1982 obj->set_map(reinterpret_cast<Map*>(HeapObject::FromAddress(forwarded)));
1983
1984 // We have to compute the object size relying on the old map because
1985 // map objects are not relocated yet.
1986 int obj_size = obj->SizeFromMap(old_map);
1987
1988 // Update pointers in the object body.
1989 UpdatingVisitor updating_visitor;
1990 obj->IterateBody(old_map->instance_type(), obj_size, &updating_visitor);
1991 return obj_size;
1992}
1993
1994
1995int MarkCompactCollector::UpdatePointersInOldObject(HeapObject* obj) {
1996 // Decode the map pointer.
1997 MapWord encoding = obj->map_word();
1998 Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
1999 ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr)));
2000
2001 // At this point, the first word of map_addr is also encoded, cannot
2002 // cast it to Map* using Map::cast.
2003 Map* map = reinterpret_cast<Map*>(HeapObject::FromAddress(map_addr));
2004 int obj_size = obj->SizeFromMap(map);
2005 InstanceType type = map->instance_type();
2006
2007 // Update map pointer.
2008 Address new_map_addr = GetForwardingAddressInOldSpace(map);
2009 int offset = encoding.DecodeOffset();
2010 obj->set_map_word(MapWord::EncodeAddress(new_map_addr, offset));
2011
2012#ifdef DEBUG
2013 if (FLAG_gc_verbose) {
2014 PrintF("update %p : %p -> %p\n", obj->address(),
2015 map_addr, new_map_addr);
2016 }
2017#endif
2018
2019 // Update pointers in the object body.
2020 UpdatingVisitor updating_visitor;
2021 obj->IterateBody(type, obj_size, &updating_visitor);
2022 return obj_size;
2023}
2024
2025
2026Address MarkCompactCollector::GetForwardingAddressInOldSpace(HeapObject* obj) {
2027 // Object should either in old or map space.
2028 MapWord encoding = obj->map_word();
2029
2030 // Offset to the first live object's forwarding address.
2031 int offset = encoding.DecodeOffset();
2032 Address obj_addr = obj->address();
2033
2034 // Find the first live object's forwarding address.
2035 Page* p = Page::FromAddress(obj_addr);
2036 Address first_forwarded = p->mc_first_forwarded;
2037
2038 // Page start address of forwarded address.
2039 Page* forwarded_page = Page::FromAddress(first_forwarded);
2040 int forwarded_offset = forwarded_page->Offset(first_forwarded);
2041
2042 // Find end of allocation of in the page of first_forwarded.
2043 Address mc_top = forwarded_page->mc_relocation_top;
2044 int mc_top_offset = forwarded_page->Offset(mc_top);
2045
2046 // Check if current object's forward pointer is in the same page
2047 // as the first live object's forwarding pointer
2048 if (forwarded_offset + offset < mc_top_offset) {
2049 // In the same page.
2050 return first_forwarded + offset;
2051 }
2052
2053 // Must be in the next page, NOTE: this may cross chunks.
2054 Page* next_page = forwarded_page->next_page();
2055 ASSERT(next_page->is_valid());
2056
2057 offset -= (mc_top_offset - forwarded_offset);
2058 offset += Page::kObjectStartOffset;
2059
2060 ASSERT_PAGE_OFFSET(offset);
2061 ASSERT(next_page->OffsetToAddress(offset) < next_page->mc_relocation_top);
2062
2063 return next_page->OffsetToAddress(offset);
2064}
2065
2066
2067// -------------------------------------------------------------------------
2068// Phase 4: Relocate objects
2069
2070void MarkCompactCollector::RelocateObjects() {
2071#ifdef DEBUG
2072 ASSERT(state_ == UPDATE_POINTERS);
2073 state_ = RELOCATE_OBJECTS;
2074#endif
2075 // Relocates objects, always relocate map objects first. Relocating
2076 // objects in other space relies on map objects to get object size.
Steve Block6ded16b2010-05-10 14:33:55 +01002077 int live_maps_size = IterateLiveObjects(Heap::map_space(),
2078 &RelocateMapObject);
2079 int live_pointer_olds_size = IterateLiveObjects(Heap::old_pointer_space(),
2080 &RelocateOldPointerObject);
2081 int live_data_olds_size = IterateLiveObjects(Heap::old_data_space(),
2082 &RelocateOldDataObject);
2083 int live_codes_size = IterateLiveObjects(Heap::code_space(),
2084 &RelocateCodeObject);
2085 int live_cells_size = IterateLiveObjects(Heap::cell_space(),
2086 &RelocateCellObject);
2087 int live_news_size = IterateLiveObjects(Heap::new_space(),
2088 &RelocateNewObject);
Steve Blocka7e24c12009-10-30 11:49:00 +00002089
Steve Block6ded16b2010-05-10 14:33:55 +01002090 USE(live_maps_size);
2091 USE(live_pointer_olds_size);
2092 USE(live_data_olds_size);
2093 USE(live_codes_size);
2094 USE(live_cells_size);
2095 USE(live_news_size);
2096 ASSERT(live_maps_size == live_map_objects_size_);
2097 ASSERT(live_data_olds_size == live_old_data_objects_size_);
2098 ASSERT(live_pointer_olds_size == live_old_pointer_objects_size_);
2099 ASSERT(live_codes_size == live_code_objects_size_);
2100 ASSERT(live_cells_size == live_cell_objects_size_);
2101 ASSERT(live_news_size == live_young_objects_size_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002102
2103 // Flip from and to spaces
2104 Heap::new_space()->Flip();
2105
2106 // Set age_mark to bottom in to space
2107 Address mark = Heap::new_space()->bottom();
2108 Heap::new_space()->set_age_mark(mark);
2109
2110 Heap::new_space()->MCCommitRelocationInfo();
2111#ifdef DEBUG
2112 // It is safe to write to the remembered sets as remembered sets on a
2113 // page-by-page basis after committing the m-c forwarding pointer.
2114 Page::set_rset_state(Page::IN_USE);
2115#endif
2116 PagedSpaces spaces;
Leon Clarked91b9f72010-01-27 17:25:45 +00002117 for (PagedSpace* space = spaces.next(); space != NULL; space = spaces.next())
2118 space->MCCommitRelocationInfo();
Steve Block6ded16b2010-05-10 14:33:55 +01002119
2120 Heap::CheckNewSpaceExpansionCriteria();
2121 Heap::IncrementYoungSurvivorsCounter(live_news_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00002122}
2123
2124
2125int MarkCompactCollector::RelocateMapObject(HeapObject* obj) {
2126 // Recover map pointer.
2127 MapWord encoding = obj->map_word();
2128 Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
2129 ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr)));
2130
2131 // Get forwarding address before resetting map pointer
2132 Address new_addr = GetForwardingAddressInOldSpace(obj);
2133
2134 // Reset map pointer. The meta map object may not be copied yet so
2135 // Map::cast does not yet work.
2136 obj->set_map(reinterpret_cast<Map*>(HeapObject::FromAddress(map_addr)));
2137
2138 Address old_addr = obj->address();
2139
2140 if (new_addr != old_addr) {
Steve Block6ded16b2010-05-10 14:33:55 +01002141 // Move contents.
2142 Heap::MoveBlock(reinterpret_cast<Object**>(new_addr),
2143 reinterpret_cast<Object**>(old_addr),
2144 Map::kSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00002145 }
2146
2147#ifdef DEBUG
2148 if (FLAG_gc_verbose) {
2149 PrintF("relocate %p -> %p\n", old_addr, new_addr);
2150 }
2151#endif
2152
2153 return Map::kSize;
2154}
2155
2156
2157static inline int RestoreMap(HeapObject* obj,
2158 PagedSpace* space,
2159 Address new_addr,
2160 Address map_addr) {
2161 // This must be a non-map object, and the function relies on the
2162 // assumption that the Map space is compacted before the other paged
2163 // spaces (see RelocateObjects).
2164
2165 // Reset map pointer.
2166 obj->set_map(Map::cast(HeapObject::FromAddress(map_addr)));
2167
2168 int obj_size = obj->Size();
2169 ASSERT_OBJECT_SIZE(obj_size);
2170
2171 ASSERT(space->MCSpaceOffsetForAddress(new_addr) <=
2172 space->MCSpaceOffsetForAddress(obj->address()));
2173
2174#ifdef DEBUG
2175 if (FLAG_gc_verbose) {
2176 PrintF("relocate %p -> %p\n", obj->address(), new_addr);
2177 }
2178#endif
2179
2180 return obj_size;
2181}
2182
2183
2184int MarkCompactCollector::RelocateOldNonCodeObject(HeapObject* obj,
2185 PagedSpace* space) {
2186 // Recover map pointer.
2187 MapWord encoding = obj->map_word();
2188 Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
2189 ASSERT(Heap::map_space()->Contains(map_addr));
2190
2191 // Get forwarding address before resetting map pointer.
2192 Address new_addr = GetForwardingAddressInOldSpace(obj);
2193
2194 // Reset the map pointer.
2195 int obj_size = RestoreMap(obj, space, new_addr, map_addr);
2196
2197 Address old_addr = obj->address();
2198
2199 if (new_addr != old_addr) {
Steve Block6ded16b2010-05-10 14:33:55 +01002200 // Move contents.
2201 Heap::MoveBlock(reinterpret_cast<Object**>(new_addr),
2202 reinterpret_cast<Object**>(old_addr),
2203 obj_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00002204 }
2205
2206 ASSERT(!HeapObject::FromAddress(new_addr)->IsCode());
2207
Leon Clarked91b9f72010-01-27 17:25:45 +00002208 HeapObject* copied_to = HeapObject::FromAddress(new_addr);
2209 if (copied_to->IsJSFunction()) {
Steve Block6ded16b2010-05-10 14:33:55 +01002210 PROFILE(FunctionMoveEvent(old_addr, new_addr));
Leon Clarked91b9f72010-01-27 17:25:45 +00002211 }
2212
Steve Blocka7e24c12009-10-30 11:49:00 +00002213 return obj_size;
2214}
2215
2216
2217int MarkCompactCollector::RelocateOldPointerObject(HeapObject* obj) {
2218 return RelocateOldNonCodeObject(obj, Heap::old_pointer_space());
2219}
2220
2221
2222int MarkCompactCollector::RelocateOldDataObject(HeapObject* obj) {
2223 return RelocateOldNonCodeObject(obj, Heap::old_data_space());
2224}
2225
2226
2227int MarkCompactCollector::RelocateCellObject(HeapObject* obj) {
2228 return RelocateOldNonCodeObject(obj, Heap::cell_space());
2229}
2230
2231
2232int MarkCompactCollector::RelocateCodeObject(HeapObject* obj) {
2233 // Recover map pointer.
2234 MapWord encoding = obj->map_word();
2235 Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
2236 ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr)));
2237
2238 // Get forwarding address before resetting map pointer
2239 Address new_addr = GetForwardingAddressInOldSpace(obj);
2240
2241 // Reset the map pointer.
2242 int obj_size = RestoreMap(obj, Heap::code_space(), new_addr, map_addr);
2243
2244 Address old_addr = obj->address();
2245
2246 if (new_addr != old_addr) {
Steve Block6ded16b2010-05-10 14:33:55 +01002247 // Move contents.
2248 Heap::MoveBlock(reinterpret_cast<Object**>(new_addr),
2249 reinterpret_cast<Object**>(old_addr),
2250 obj_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00002251 }
2252
2253 HeapObject* copied_to = HeapObject::FromAddress(new_addr);
2254 if (copied_to->IsCode()) {
2255 // May also update inline cache target.
2256 Code::cast(copied_to)->Relocate(new_addr - old_addr);
2257 // Notify the logger that compiled code has moved.
Steve Block6ded16b2010-05-10 14:33:55 +01002258 PROFILE(CodeMoveEvent(old_addr, new_addr));
Steve Blocka7e24c12009-10-30 11:49:00 +00002259 }
2260
2261 return obj_size;
2262}
2263
2264
2265int MarkCompactCollector::RelocateNewObject(HeapObject* obj) {
2266 int obj_size = obj->Size();
2267
2268 // Get forwarding address
2269 Address old_addr = obj->address();
2270 int offset = Heap::new_space()->ToSpaceOffsetForAddress(old_addr);
2271
2272 Address new_addr =
2273 Memory::Address_at(Heap::new_space()->FromSpaceLow() + offset);
2274
2275#ifdef DEBUG
2276 if (Heap::new_space()->FromSpaceContains(new_addr)) {
2277 ASSERT(Heap::new_space()->FromSpaceOffsetForAddress(new_addr) <=
2278 Heap::new_space()->ToSpaceOffsetForAddress(old_addr));
2279 } else {
2280 ASSERT(Heap::TargetSpace(obj) == Heap::old_pointer_space() ||
2281 Heap::TargetSpace(obj) == Heap::old_data_space());
2282 }
2283#endif
2284
2285 // New and old addresses cannot overlap.
Steve Block6ded16b2010-05-10 14:33:55 +01002286 Heap::CopyBlock(reinterpret_cast<Object**>(new_addr),
2287 reinterpret_cast<Object**>(old_addr),
2288 obj_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00002289
2290#ifdef DEBUG
2291 if (FLAG_gc_verbose) {
2292 PrintF("relocate %p -> %p\n", old_addr, new_addr);
2293 }
2294#endif
2295
Leon Clarked91b9f72010-01-27 17:25:45 +00002296 HeapObject* copied_to = HeapObject::FromAddress(new_addr);
2297 if (copied_to->IsJSFunction()) {
Steve Block6ded16b2010-05-10 14:33:55 +01002298 PROFILE(FunctionMoveEvent(old_addr, new_addr));
Leon Clarked91b9f72010-01-27 17:25:45 +00002299 }
2300
Steve Blocka7e24c12009-10-30 11:49:00 +00002301 return obj_size;
2302}
2303
2304
2305// -------------------------------------------------------------------------
2306// Phase 5: rebuild remembered sets
2307
2308void MarkCompactCollector::RebuildRSets() {
2309#ifdef DEBUG
2310 ASSERT(state_ == RELOCATE_OBJECTS);
2311 state_ = REBUILD_RSETS;
2312#endif
2313 Heap::RebuildRSets();
2314}
2315
Leon Clarked91b9f72010-01-27 17:25:45 +00002316
2317void MarkCompactCollector::ReportDeleteIfNeeded(HeapObject* obj) {
2318#ifdef ENABLE_LOGGING_AND_PROFILING
2319 if (obj->IsCode()) {
Steve Block6ded16b2010-05-10 14:33:55 +01002320 PROFILE(CodeDeleteEvent(obj->address()));
Leon Clarked91b9f72010-01-27 17:25:45 +00002321 } else if (obj->IsJSFunction()) {
Steve Block6ded16b2010-05-10 14:33:55 +01002322 PROFILE(FunctionDeleteEvent(obj->address()));
Leon Clarked91b9f72010-01-27 17:25:45 +00002323 }
2324#endif
2325}
2326
Steve Blocka7e24c12009-10-30 11:49:00 +00002327} } // namespace v8::internal