00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "v8.h"
00029
00030 #include "execution.h"
00031 #include "global-handles.h"
00032 #include "ic-inl.h"
00033 #include "mark-compact.h"
00034 #include "stub-cache.h"
00035
00036 namespace v8 { namespace internal {
00037
00038 #ifdef DEBUG
00039
00040
00041
00042
00043
00044 static const bool FLAG_verify_global_gc = false;
00045 #endif // DEBUG
00046
00047
00048
00049
00050 bool MarkCompactCollector::compacting_collection_ = false;
00051
00052 int MarkCompactCollector::previous_marked_count_ = 0;
00053 GCTracer* MarkCompactCollector::tracer_ = NULL;
00054
00055
00056 #ifdef DEBUG
00057 MarkCompactCollector::CollectorState MarkCompactCollector::state_ = IDLE;
00058
00059
00060
00061 int MarkCompactCollector::live_bytes_ = 0;
00062 int MarkCompactCollector::live_young_objects_ = 0;
00063 int MarkCompactCollector::live_old_data_objects_ = 0;
00064 int MarkCompactCollector::live_old_pointer_objects_ = 0;
00065 int MarkCompactCollector::live_code_objects_ = 0;
00066 int MarkCompactCollector::live_map_objects_ = 0;
00067 int MarkCompactCollector::live_lo_objects_ = 0;
00068 #endif
00069
00070 void MarkCompactCollector::CollectGarbage(GCTracer* tracer) {
00071
00072
00073 tracer_ = tracer;
00074 Prepare();
00075
00076
00077 if (IsCompacting()) tracer_->set_is_compacting();
00078
00079 MarkLiveObjects();
00080
00081 if (FLAG_collect_maps) ClearNonLiveTransitions();
00082
00083 SweepLargeObjectSpace();
00084
00085 if (compacting_collection_) {
00086 EncodeForwardingAddresses();
00087
00088 UpdatePointers();
00089
00090 RelocateObjects();
00091
00092 RebuildRSets();
00093
00094 } else {
00095 SweepSpaces();
00096 }
00097
00098 Finish();
00099
00100
00101
00102 previous_marked_count_ = tracer_->marked_count();
00103 ASSERT(previous_marked_count_ == 0);
00104 tracer_ = NULL;
00105 }
00106
00107
00108 void MarkCompactCollector::Prepare() {
00109 static const int kFragmentationLimit = 50;
00110 #ifdef DEBUG
00111 ASSERT(state_ == IDLE);
00112 state_ = PREPARE_GC;
00113 #endif
00114 ASSERT(!FLAG_always_compact || !FLAG_never_compact);
00115
00116 compacting_collection_ = FLAG_always_compact;
00117
00118
00119
00120
00121
00122
00123 if (!compacting_collection_) {
00124 int old_gen_recoverable = 0;
00125 int old_gen_used = 0;
00126
00127 OldSpaces spaces;
00128 while (OldSpace* space = spaces.next()) {
00129 old_gen_recoverable += space->Waste() + space->AvailableFree();
00130 old_gen_used += space->Size();
00131 }
00132 int old_gen_fragmentation =
00133 static_cast<int>((old_gen_recoverable * 100.0) / old_gen_used);
00134 if (old_gen_fragmentation > kFragmentationLimit) {
00135 compacting_collection_ = true;
00136 }
00137 }
00138
00139 if (FLAG_never_compact) compacting_collection_ = false;
00140 if (FLAG_collect_maps) CreateBackPointers();
00141
00142 #ifdef DEBUG
00143 if (compacting_collection_) {
00144
00145
00146 Page::set_rset_state(Page::NOT_IN_USE);
00147 }
00148 #endif
00149
00150 PagedSpaces spaces;
00151 while (PagedSpace* space = spaces.next()) {
00152 space->PrepareForMarkCompact(compacting_collection_);
00153 }
00154
00155 Counters::global_objects.Set(0);
00156
00157 #ifdef DEBUG
00158 live_bytes_ = 0;
00159 live_young_objects_ = 0;
00160 live_old_pointer_objects_ = 0;
00161 live_old_data_objects_ = 0;
00162 live_code_objects_ = 0;
00163 live_map_objects_ = 0;
00164 live_lo_objects_ = 0;
00165 #endif
00166 }
00167
00168
00169 void MarkCompactCollector::Finish() {
00170 #ifdef DEBUG
00171 ASSERT(state_ == SWEEP_SPACES || state_ == REBUILD_RSETS);
00172 state_ = IDLE;
00173 #endif
00174
00175
00176
00177
00178 StubCache::Clear();
00179 }
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210 static MarkingStack marking_stack;
00211
00212
00213 static inline HeapObject* ShortCircuitConsString(Object** p) {
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226 HeapObject* object = HeapObject::cast(*p);
00227 MapWord map_word = object->map_word();
00228 map_word.ClearMark();
00229 InstanceType type = map_word.ToMap()->instance_type();
00230 if (type >= FIRST_NONSTRING_TYPE || (type & kIsSymbolMask) != 0) {
00231 return object;
00232 }
00233
00234 StringRepresentationTag rep =
00235 static_cast<StringRepresentationTag>(type & kStringRepresentationMask);
00236 if (rep != kConsStringTag) return object;
00237
00238 Object* second = reinterpret_cast<ConsString*>(object)->second();
00239 if (reinterpret_cast<String*>(second) != Heap::empty_string()) return object;
00240
00241
00242
00243
00244 Object* first = reinterpret_cast<ConsString*>(object)->first();
00245 if (!Heap::InNewSpace(object) && Heap::InNewSpace(first)) return object;
00246
00247 *p = first;
00248 return HeapObject::cast(first);
00249 }
00250
00251
00252
00253 class MarkingVisitor : public ObjectVisitor {
00254 public:
00255
00256 void VisitPointer(Object** p) {
00257 MarkObjectByPointer(p);
00258 }
00259
00260 void VisitPointers(Object** start, Object** end) {
00261
00262 const int kMinRangeForMarkingRecursion = 64;
00263 if (end - start >= kMinRangeForMarkingRecursion) {
00264 if (VisitUnmarkedObjects(start, end)) return;
00265
00266 }
00267 for (Object** p = start; p < end; p++) MarkObjectByPointer(p);
00268 }
00269
00270 void BeginCodeIteration(Code* code) {
00271
00272
00273 ASSERT(code->ic_flag() == Code::IC_TARGET_IS_ADDRESS);
00274 }
00275
00276 void EndCodeIteration(Code* code) {
00277
00278
00279 if (IsCompacting()) code->set_ic_flag(Code::IC_TARGET_IS_OBJECT);
00280 }
00281
00282 void VisitCodeTarget(RelocInfo* rinfo) {
00283 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
00284 Code* code = CodeFromDerivedPointer(rinfo->target_address());
00285 if (FLAG_cleanup_ics_at_gc && code->is_inline_cache_stub()) {
00286 IC::Clear(rinfo->pc());
00287
00288
00289 } else {
00290 MarkCompactCollector::MarkObject(code);
00291 }
00292 if (IsCompacting()) {
00293
00294 code = CodeFromDerivedPointer(rinfo->target_address());
00295 rinfo->set_target_object(code);
00296 }
00297 }
00298
00299 void VisitDebugTarget(RelocInfo* rinfo) {
00300 ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()) &&
00301 rinfo->is_call_instruction());
00302 HeapObject* code = CodeFromDerivedPointer(rinfo->call_address());
00303 MarkCompactCollector::MarkObject(code);
00304
00305 if (IsCompacting()) rinfo->set_call_object(code);
00306 }
00307
00308 private:
00309
00310 void MarkObjectByPointer(Object** p) {
00311 if (!(*p)->IsHeapObject()) return;
00312 HeapObject* object = ShortCircuitConsString(p);
00313 MarkCompactCollector::MarkObject(object);
00314 }
00315
00316
00317 bool IsCompacting() { return MarkCompactCollector::IsCompacting(); }
00318
00319
00320 Code* CodeFromDerivedPointer(Address addr) {
00321 ASSERT(addr != NULL);
00322 return reinterpret_cast<Code*>(
00323 HeapObject::FromAddress(addr - Code::kHeaderSize));
00324 }
00325
00326
00327 void VisitUnmarkedObject(HeapObject* obj) {
00328 #ifdef DEBUG
00329 ASSERT(Heap::Contains(obj));
00330 MarkCompactCollector::UpdateLiveObjectCount(obj);
00331 ASSERT(!obj->IsMarked());
00332 #endif
00333 Map* map = obj->map();
00334 obj->SetMark();
00335 MarkCompactCollector::tracer()->increment_marked_count();
00336
00337 MarkCompactCollector::MarkObject(map);
00338 obj->IterateBody(map->instance_type(), obj->SizeFromMap(map), this);
00339 }
00340
00341
00342
00343 inline bool VisitUnmarkedObjects(Object** start, Object** end) {
00344
00345 StackLimitCheck check;
00346 if (check.HasOverflowed()) return false;
00347
00348
00349 for (Object** p = start; p < end; p++) {
00350 if (!(*p)->IsHeapObject()) continue;
00351 HeapObject* obj = HeapObject::cast(*p);
00352 if (obj->IsMarked()) continue;
00353 VisitUnmarkedObject(obj);
00354 }
00355 return true;
00356 }
00357 };
00358
00359
00360
00361 class RootMarkingVisitor : public ObjectVisitor {
00362 public:
00363 void VisitPointer(Object** p) {
00364 MarkObjectByPointer(p);
00365 }
00366
00367 void VisitPointers(Object** start, Object** end) {
00368 for (Object** p = start; p < end; p++) MarkObjectByPointer(p);
00369 }
00370
00371 MarkingVisitor* stack_visitor() { return &stack_visitor_; }
00372
00373 private:
00374 MarkingVisitor stack_visitor_;
00375
00376 void MarkObjectByPointer(Object** p) {
00377 if (!(*p)->IsHeapObject()) return;
00378
00379
00380 HeapObject* object = ShortCircuitConsString(p);
00381 if (object->IsMarked()) return;
00382
00383 #ifdef DEBUG
00384 MarkCompactCollector::UpdateLiveObjectCount(object);
00385 #endif
00386 Map* map = object->map();
00387
00388 object->SetMark();
00389 MarkCompactCollector::tracer()->increment_marked_count();
00390
00391 MarkCompactCollector::MarkObject(map);
00392 object->IterateBody(map->instance_type(), object->SizeFromMap(map),
00393 &stack_visitor_);
00394
00395
00396
00397 MarkCompactCollector::EmptyMarkingStack(&stack_visitor_);
00398 }
00399 };
00400
00401
00402
00403 class SymbolTableCleaner : public ObjectVisitor {
00404 public:
00405 SymbolTableCleaner() : pointers_removed_(0) { }
00406 void VisitPointers(Object** start, Object** end) {
00407
00408 for (Object** p = start; p < end; p++) {
00409 if ((*p)->IsHeapObject() && !HeapObject::cast(*p)->IsMarked()) {
00410
00411 *p = Heap::null_value();
00412 pointers_removed_++;
00413 }
00414 }
00415 }
00416
00417 int PointersRemoved() {
00418 return pointers_removed_;
00419 }
00420 private:
00421 int pointers_removed_;
00422 };
00423
00424
00425 void MarkCompactCollector::MarkUnmarkedObject(HeapObject* object) {
00426 #ifdef DEBUG
00427 UpdateLiveObjectCount(object);
00428 #endif
00429 ASSERT(!object->IsMarked());
00430 if (object->IsJSGlobalObject()) Counters::global_objects.Increment();
00431
00432 tracer_->increment_marked_count();
00433 ASSERT(Heap::Contains(object));
00434 if (object->IsMap()) {
00435 Map* map = Map::cast(object);
00436 if (FLAG_cleanup_caches_in_maps_at_gc) {
00437 map->ClearCodeCache();
00438 }
00439 map->SetMark();
00440 if (FLAG_collect_maps &&
00441 map->instance_type() >= FIRST_JS_OBJECT_TYPE &&
00442 map->instance_type() <= JS_FUNCTION_TYPE) {
00443 MarkMapContents(map);
00444 } else {
00445 marking_stack.Push(map);
00446 }
00447 } else {
00448 object->SetMark();
00449 marking_stack.Push(object);
00450 }
00451 }
00452
00453
00454 void MarkCompactCollector::MarkMapContents(Map* map) {
00455 MarkDescriptorArray(reinterpret_cast<DescriptorArray*>(
00456 *HeapObject::RawField(map, Map::kInstanceDescriptorsOffset)));
00457
00458
00459
00460
00461 MarkingVisitor visitor;
00462 visitor.VisitPointers(HeapObject::RawField(map, Map::kPrototypeOffset),
00463 HeapObject::RawField(map, Map::kSize));
00464 }
00465
00466
00467 void MarkCompactCollector::MarkDescriptorArray(
00468 DescriptorArray *descriptors) {
00469 if (descriptors->IsMarked()) return;
00470
00471 ASSERT(descriptors != Heap::empty_descriptor_array());
00472
00473 tracer_->increment_marked_count();
00474 #ifdef DEBUG
00475 UpdateLiveObjectCount(descriptors);
00476 #endif
00477 descriptors->SetMark();
00478
00479 FixedArray* contents = reinterpret_cast<FixedArray*>(
00480 descriptors->get(DescriptorArray::kContentArrayIndex));
00481 ASSERT(contents->IsHeapObject());
00482 ASSERT(!contents->IsMarked());
00483 ASSERT(contents->IsFixedArray());
00484 ASSERT(contents->length() >= 2);
00485 tracer_->increment_marked_count();
00486 #ifdef DEBUG
00487 UpdateLiveObjectCount(contents);
00488 #endif
00489 contents->SetMark();
00490
00491
00492
00493
00494 for (int i = 0; i < contents->length(); i += 2) {
00495
00496
00497 PropertyDetails details(Smi::cast(contents->get(i + 1)));
00498 if (details.type() < FIRST_PHANTOM_PROPERTY_TYPE) {
00499 HeapObject* object = reinterpret_cast<HeapObject*>(contents->get(i));
00500 if (object->IsHeapObject() && !object->IsMarked()) {
00501 tracer_->increment_marked_count();
00502 #ifdef DEBUG
00503 UpdateLiveObjectCount(object);
00504 #endif
00505 object->SetMark();
00506 marking_stack.Push(object);
00507 }
00508 }
00509 }
00510
00511
00512 marking_stack.Push(descriptors);
00513 }
00514
00515
00516 void MarkCompactCollector::CreateBackPointers() {
00517 HeapObjectIterator iterator(Heap::map_space());
00518 while (iterator.has_next()) {
00519 Object* next_object = iterator.next();
00520 if (next_object->IsMap()) {
00521 Map* map = Map::cast(next_object);
00522 if (map->instance_type() >= FIRST_JS_OBJECT_TYPE &&
00523 map->instance_type() <= JS_FUNCTION_TYPE) {
00524 map->CreateBackPointers();
00525 } else {
00526 ASSERT(map->instance_descriptors() == Heap::empty_descriptor_array());
00527 }
00528 }
00529 }
00530 }
00531
00532
00533 static int OverflowObjectSize(HeapObject* obj) {
00534
00535
00536 MapWord map_word = obj->map_word();
00537 map_word.ClearMark();
00538 map_word.ClearOverflow();
00539 return obj->SizeFromMap(map_word.ToMap());
00540 }
00541
00542
00543
00544
00545
00546 template<class T>
00547 static void ScanOverflowedObjects(T* it) {
00548
00549
00550 ASSERT(!marking_stack.is_full());
00551
00552 while (it->has_next()) {
00553 HeapObject* object = it->next();
00554 if (object->IsOverflowed()) {
00555 object->ClearOverflow();
00556 ASSERT(object->IsMarked());
00557 ASSERT(Heap::Contains(object));
00558 marking_stack.Push(object);
00559 if (marking_stack.is_full()) return;
00560 }
00561 }
00562 }
00563
00564
00565 bool MarkCompactCollector::MustBeMarked(Object** p) {
00566
00567 if (!(*p)->IsHeapObject()) return false;
00568 return !HeapObject::cast(*p)->IsMarked();
00569 }
00570
00571
00572 void MarkCompactCollector::ProcessRoots(RootMarkingVisitor* visitor) {
00573
00574
00575 Heap::IterateStrongRoots(visitor);
00576
00577
00578 SymbolTable* symbol_table = SymbolTable::cast(Heap::symbol_table());
00579
00580 symbol_table->IteratePrefix(visitor);
00581 #ifdef DEBUG
00582 UpdateLiveObjectCount(symbol_table);
00583 #endif
00584
00585
00586 symbol_table->SetMark();
00587 tracer_->increment_marked_count();
00588
00589
00590 while (marking_stack.overflowed()) {
00591 RefillMarkingStack();
00592 EmptyMarkingStack(visitor->stack_visitor());
00593 }
00594 }
00595
00596
00597 void MarkCompactCollector::MarkObjectGroups() {
00598 List<ObjectGroup*>& object_groups = GlobalHandles::ObjectGroups();
00599
00600 for (int i = 0; i < object_groups.length(); i++) {
00601 ObjectGroup* entry = object_groups[i];
00602 if (entry == NULL) continue;
00603
00604 List<Object**>& objects = entry->objects_;
00605 bool group_marked = false;
00606 for (int j = 0; j < objects.length(); j++) {
00607 Object* object = *objects[j];
00608 if (object->IsHeapObject() && HeapObject::cast(object)->IsMarked()) {
00609 group_marked = true;
00610 break;
00611 }
00612 }
00613
00614 if (!group_marked) continue;
00615
00616
00617
00618 for (int j = 0; j < objects.length(); ++j) {
00619 if ((*objects[j])->IsHeapObject()) {
00620 MarkObject(HeapObject::cast(*objects[j]));
00621 }
00622 }
00623
00624
00625 delete object_groups[i];
00626 object_groups[i] = NULL;
00627 }
00628 }
00629
00630
00631
00632
00633
00634
00635 void MarkCompactCollector::EmptyMarkingStack(MarkingVisitor* visitor) {
00636 while (!marking_stack.is_empty()) {
00637 HeapObject* object = marking_stack.Pop();
00638 ASSERT(object->IsHeapObject());
00639 ASSERT(Heap::Contains(object));
00640 ASSERT(object->IsMarked());
00641 ASSERT(!object->IsOverflowed());
00642
00643
00644
00645 MapWord map_word = object->map_word();
00646 map_word.ClearMark();
00647 Map* map = map_word.ToMap();
00648 MarkObject(map);
00649 object->IterateBody(map->instance_type(), object->SizeFromMap(map),
00650 visitor);
00651 }
00652 }
00653
00654
00655
00656
00657
00658
00659
00660 void MarkCompactCollector::RefillMarkingStack() {
00661 ASSERT(marking_stack.overflowed());
00662
00663 SemiSpaceIterator new_it(Heap::new_space(), &OverflowObjectSize);
00664 ScanOverflowedObjects(&new_it);
00665 if (marking_stack.is_full()) return;
00666
00667 HeapObjectIterator old_pointer_it(Heap::old_pointer_space(),
00668 &OverflowObjectSize);
00669 ScanOverflowedObjects(&old_pointer_it);
00670 if (marking_stack.is_full()) return;
00671
00672 HeapObjectIterator old_data_it(Heap::old_data_space(), &OverflowObjectSize);
00673 ScanOverflowedObjects(&old_data_it);
00674 if (marking_stack.is_full()) return;
00675
00676 HeapObjectIterator code_it(Heap::code_space(), &OverflowObjectSize);
00677 ScanOverflowedObjects(&code_it);
00678 if (marking_stack.is_full()) return;
00679
00680 HeapObjectIterator map_it(Heap::map_space(), &OverflowObjectSize);
00681 ScanOverflowedObjects(&map_it);
00682 if (marking_stack.is_full()) return;
00683
00684 LargeObjectIterator lo_it(Heap::lo_space(), &OverflowObjectSize);
00685 ScanOverflowedObjects(&lo_it);
00686 if (marking_stack.is_full()) return;
00687
00688 marking_stack.clear_overflowed();
00689 }
00690
00691
00692
00693
00694
00695
00696 void MarkCompactCollector::ProcessMarkingStack(MarkingVisitor* visitor) {
00697 EmptyMarkingStack(visitor);
00698 while (marking_stack.overflowed()) {
00699 RefillMarkingStack();
00700 EmptyMarkingStack(visitor);
00701 }
00702 }
00703
00704
00705 void MarkCompactCollector::ProcessObjectGroups(MarkingVisitor* visitor) {
00706 bool work_to_do = true;
00707 ASSERT(marking_stack.is_empty());
00708 while (work_to_do) {
00709 MarkObjectGroups();
00710 work_to_do = !marking_stack.is_empty();
00711 ProcessMarkingStack(visitor);
00712 }
00713 }
00714
00715
00716 void MarkCompactCollector::MarkLiveObjects() {
00717 #ifdef DEBUG
00718 ASSERT(state_ == PREPARE_GC);
00719 state_ = MARK_LIVE_OBJECTS;
00720 #endif
00721
00722
00723 marking_stack.Initialize(Heap::new_space()->FromSpaceLow(),
00724 Heap::new_space()->FromSpaceHigh());
00725
00726 ASSERT(!marking_stack.overflowed());
00727
00728 RootMarkingVisitor root_visitor;
00729 ProcessRoots(&root_visitor);
00730
00731
00732
00733
00734
00735 ProcessObjectGroups(root_visitor.stack_visitor());
00736
00737
00738
00739
00740
00741
00742 GlobalHandles::MarkWeakRoots(&MustBeMarked);
00743
00744 GlobalHandles::IterateWeakRoots(&root_visitor);
00745 while (marking_stack.overflowed()) {
00746 RefillMarkingStack();
00747 EmptyMarkingStack(root_visitor.stack_visitor());
00748 }
00749
00750
00751
00752 ProcessObjectGroups(root_visitor.stack_visitor());
00753
00754
00755
00756
00757 SymbolTable* symbol_table =
00758 reinterpret_cast<SymbolTable*>(Heap::symbol_table());
00759 SymbolTableCleaner v;
00760 symbol_table->IterateElements(&v);
00761 symbol_table->ElementsRemoved(v.PointersRemoved());
00762
00763 #ifdef DEBUG
00764 if (FLAG_verify_global_gc) VerifyHeapAfterMarkingPhase();
00765 #endif
00766
00767
00768 GlobalHandles::RemoveObjectGroups();
00769 }
00770
00771
00772 static int CountMarkedCallback(HeapObject* obj) {
00773 MapWord map_word = obj->map_word();
00774 map_word.ClearMark();
00775 return obj->SizeFromMap(map_word.ToMap());
00776 }
00777
00778
00779 #ifdef DEBUG
00780 void MarkCompactCollector::UpdateLiveObjectCount(HeapObject* obj) {
00781 live_bytes_ += obj->Size();
00782 if (Heap::new_space()->Contains(obj)) {
00783 live_young_objects_++;
00784 } else if (Heap::map_space()->Contains(obj)) {
00785 ASSERT(obj->IsMap());
00786 live_map_objects_++;
00787 } else if (Heap::old_pointer_space()->Contains(obj)) {
00788 live_old_pointer_objects_++;
00789 } else if (Heap::old_data_space()->Contains(obj)) {
00790 live_old_data_objects_++;
00791 } else if (Heap::code_space()->Contains(obj)) {
00792 live_code_objects_++;
00793 } else if (Heap::lo_space()->Contains(obj)) {
00794 live_lo_objects_++;
00795 } else {
00796 UNREACHABLE();
00797 }
00798 }
00799
00800
00801 void MarkCompactCollector::VerifyHeapAfterMarkingPhase() {
00802 Heap::new_space()->Verify();
00803 Heap::old_pointer_space()->Verify();
00804 Heap::old_data_space()->Verify();
00805 Heap::code_space()->Verify();
00806 Heap::map_space()->Verify();
00807
00808 int live_objects;
00809
00810 #define CHECK_LIVE_OBJECTS(it, expected) \
00811 live_objects = 0; \
00812 while (it.has_next()) { \
00813 HeapObject* obj = HeapObject::cast(it.next()); \
00814 if (obj->IsMarked()) live_objects++; \
00815 } \
00816 ASSERT(live_objects == expected);
00817
00818 SemiSpaceIterator new_it(Heap::new_space(), &CountMarkedCallback);
00819 CHECK_LIVE_OBJECTS(new_it, live_young_objects_);
00820
00821 HeapObjectIterator old_pointer_it(Heap::old_pointer_space(),
00822 &CountMarkedCallback);
00823 CHECK_LIVE_OBJECTS(old_pointer_it, live_old_pointer_objects_);
00824
00825 HeapObjectIterator old_data_it(Heap::old_data_space(), &CountMarkedCallback);
00826 CHECK_LIVE_OBJECTS(old_data_it, live_old_data_objects_);
00827
00828 HeapObjectIterator code_it(Heap::code_space(), &CountMarkedCallback);
00829 CHECK_LIVE_OBJECTS(code_it, live_code_objects_);
00830
00831 HeapObjectIterator map_it(Heap::map_space(), &CountMarkedCallback);
00832 CHECK_LIVE_OBJECTS(map_it, live_map_objects_);
00833
00834 LargeObjectIterator lo_it(Heap::lo_space(), &CountMarkedCallback);
00835 CHECK_LIVE_OBJECTS(lo_it, live_lo_objects_);
00836
00837 #undef CHECK_LIVE_OBJECTS
00838 }
00839 #endif // DEBUG
00840
00841
00842 void MarkCompactCollector::SweepLargeObjectSpace() {
00843 #ifdef DEBUG
00844 ASSERT(state_ == MARK_LIVE_OBJECTS);
00845 state_ =
00846 compacting_collection_ ? ENCODE_FORWARDING_ADDRESSES : SWEEP_SPACES;
00847 #endif
00848
00849 Heap::lo_space()->FreeUnmarkedObjects();
00850 }
00851
00852
00853 bool MarkCompactCollector::SafeIsMap(HeapObject* object) {
00854 MapWord metamap = object->map_word();
00855 metamap.ClearMark();
00856 return metamap.ToMap()->instance_type() == MAP_TYPE;
00857 }
00858
00859 void MarkCompactCollector::ClearNonLiveTransitions() {
00860 HeapObjectIterator map_iterator(Heap::map_space(), &CountMarkedCallback);
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871 while (map_iterator.has_next()) {
00872 Map* map = reinterpret_cast<Map*>(map_iterator.next());
00873 if (!map->IsMarked() && map->IsByteArray()) continue;
00874
00875 ASSERT(SafeIsMap(map));
00876
00877 if (map->instance_type() < FIRST_JS_OBJECT_TYPE) continue;
00878 if (map->instance_type() > JS_FUNCTION_TYPE) continue;
00879
00880 Map* current = map;
00881 while (SafeIsMap(current)) {
00882 current = reinterpret_cast<Map*>(current->prototype());
00883 ASSERT(current->IsHeapObject());
00884 }
00885 Object* real_prototype = current;
00886
00887
00888
00889 current = map;
00890 bool on_dead_path = !current->IsMarked();
00891 Object *next;
00892 while (SafeIsMap(current)) {
00893 next = current->prototype();
00894
00895 ASSERT(on_dead_path || current->IsMarked());
00896
00897
00898
00899 if (on_dead_path && current->IsMarked()) {
00900 on_dead_path = false;
00901 current->ClearNonLiveTransitions(real_prototype);
00902 }
00903 *HeapObject::RawField(current, Map::kPrototypeOffset) =
00904 real_prototype;
00905 current = reinterpret_cast<Map*>(next);
00906 }
00907 }
00908 }
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936 static const uint32_t kSingleFreeEncoding = 0;
00937 static const uint32_t kMultiFreeEncoding = 1;
00938
00939
00940
00941
00942 void EncodeFreeRegion(Address free_start, int free_size) {
00943 ASSERT(free_size >= kIntSize);
00944 if (free_size == kIntSize) {
00945 Memory::uint32_at(free_start) = kSingleFreeEncoding;
00946 } else {
00947 ASSERT(free_size >= 2 * kIntSize);
00948 Memory::uint32_at(free_start) = kMultiFreeEncoding;
00949 Memory::int_at(free_start + kIntSize) = free_size;
00950 }
00951
00952 #ifdef DEBUG
00953
00954 if (FLAG_enable_slow_asserts) {
00955 for (int offset = 2 * kIntSize;
00956 offset < free_size;
00957 offset += kPointerSize) {
00958 Memory::Address_at(free_start + offset) = kZapValue;
00959 }
00960 }
00961 #endif
00962 }
00963
00964
00965
00966
00967 inline Object* MCAllocateFromNewSpace(HeapObject* object, int object_size) {
00968 OldSpace* target_space = Heap::TargetSpace(object);
00969 ASSERT(target_space == Heap::old_pointer_space() ||
00970 target_space == Heap::old_data_space());
00971 Object* forwarded = target_space->MCAllocateRaw(object_size);
00972
00973 if (forwarded->IsFailure()) {
00974 forwarded = Heap::new_space()->MCAllocateRaw(object_size);
00975 }
00976 return forwarded;
00977 }
00978
00979
00980
00981 inline Object* MCAllocateFromOldPointerSpace(HeapObject* object,
00982 int object_size) {
00983 return Heap::old_pointer_space()->MCAllocateRaw(object_size);
00984 }
00985
00986
00987 inline Object* MCAllocateFromOldDataSpace(HeapObject* object, int object_size) {
00988 return Heap::old_data_space()->MCAllocateRaw(object_size);
00989 }
00990
00991
00992 inline Object* MCAllocateFromCodeSpace(HeapObject* object, int object_size) {
00993 return Heap::code_space()->MCAllocateRaw(object_size);
00994 }
00995
00996
00997 inline Object* MCAllocateFromMapSpace(HeapObject* object, int object_size) {
00998 return Heap::map_space()->MCAllocateRaw(object_size);
00999 }
01000
01001
01002
01003
01004 inline void EncodeForwardingAddressInNewSpace(HeapObject* old_object,
01005 int object_size,
01006 Object* new_object,
01007 int* ignored) {
01008 int offset =
01009 Heap::new_space()->ToSpaceOffsetForAddress(old_object->address());
01010 Memory::Address_at(Heap::new_space()->FromSpaceLow() + offset) =
01011 HeapObject::cast(new_object)->address();
01012 }
01013
01014
01015
01016
01017
01018 inline void EncodeForwardingAddressInPagedSpace(HeapObject* old_object,
01019 int object_size,
01020 Object* new_object,
01021 int* offset) {
01022
01023 if (*offset == 0) {
01024 Page::FromAddress(old_object->address())->mc_first_forwarded =
01025 HeapObject::cast(new_object)->address();
01026 }
01027
01028 MapWord encoding =
01029 MapWord::EncodeAddress(old_object->map()->address(), *offset);
01030 old_object->set_map_word(encoding);
01031 *offset += object_size;
01032 ASSERT(*offset <= Page::kObjectAreaSize);
01033 }
01034
01035
01036
01037 inline void IgnoreNonLiveObject(HeapObject* object) {}
01038
01039
01040
01041 inline void LogNonLiveCodeObject(HeapObject* object) {
01042 if (object->IsCode()) LOG(CodeDeleteEvent(object->address()));
01043 }
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054 template<MarkCompactCollector::AllocationFunction Alloc,
01055 MarkCompactCollector::EncodingFunction Encode,
01056 MarkCompactCollector::ProcessNonLiveFunction ProcessNonLive>
01057 inline void EncodeForwardingAddressesInRange(Address start,
01058 Address end,
01059 int* offset) {
01060
01061
01062
01063
01064
01065 Address free_start = NULL;
01066
01067
01068
01069
01070 bool is_prev_alive = true;
01071
01072 int object_size;
01073 for (Address current = start; current < end; current += object_size) {
01074 HeapObject* object = HeapObject::FromAddress(current);
01075 if (object->IsMarked()) {
01076 object->ClearMark();
01077 MarkCompactCollector::tracer()->decrement_marked_count();
01078 object_size = object->Size();
01079
01080 Object* forwarded = Alloc(object, object_size);
01081
01082 ASSERT(!forwarded->IsFailure());
01083 Encode(object, object_size, forwarded, offset);
01084
01085 #ifdef DEBUG
01086 if (FLAG_gc_verbose) {
01087 PrintF("forward %p -> %p.\n", object->address(),
01088 HeapObject::cast(forwarded)->address());
01089 }
01090 #endif
01091 if (!is_prev_alive) {
01092 EncodeFreeRegion(free_start, current - free_start);
01093 is_prev_alive = true;
01094 }
01095 } else {
01096 object_size = object->Size();
01097 ProcessNonLive(object);
01098 if (is_prev_alive) {
01099 free_start = current;
01100 is_prev_alive = false;
01101 }
01102 }
01103 }
01104
01105
01106 if (!is_prev_alive) EncodeFreeRegion(free_start, end - free_start);
01107 }
01108
01109
01110
01111 void MarkCompactCollector::EncodeForwardingAddressesInNewSpace() {
01112 int ignored;
01113 EncodeForwardingAddressesInRange<MCAllocateFromNewSpace,
01114 EncodeForwardingAddressInNewSpace,
01115 IgnoreNonLiveObject>(
01116 Heap::new_space()->bottom(),
01117 Heap::new_space()->top(),
01118 &ignored);
01119 }
01120
01121
01122 template<MarkCompactCollector::AllocationFunction Alloc,
01123 MarkCompactCollector::ProcessNonLiveFunction ProcessNonLive>
01124 void MarkCompactCollector::EncodeForwardingAddressesInPagedSpace(
01125 PagedSpace* space) {
01126 PageIterator it(space, PageIterator::PAGES_IN_USE);
01127 while (it.has_next()) {
01128 Page* p = it.next();
01129
01130
01131 int offset = 0;
01132 EncodeForwardingAddressesInRange<Alloc,
01133 EncodeForwardingAddressInPagedSpace,
01134 ProcessNonLive>(
01135 p->ObjectAreaStart(),
01136 p->AllocationTop(),
01137 &offset);
01138 }
01139 }
01140
01141
01142 static void SweepSpace(NewSpace* space) {
01143 HeapObject* object;
01144 for (Address current = space->bottom();
01145 current < space->top();
01146 current += object->Size()) {
01147 object = HeapObject::FromAddress(current);
01148 if (object->IsMarked()) {
01149 object->ClearMark();
01150 MarkCompactCollector::tracer()->decrement_marked_count();
01151 } else {
01152
01153
01154 int size = object->Size();
01155 if (size >= Array::kHeaderSize) {
01156 object->set_map(Heap::byte_array_map());
01157 ByteArray::cast(object)->set_length(ByteArray::LengthFor(size));
01158 } else {
01159 ASSERT(size == kPointerSize);
01160 object->set_map(Heap::one_word_filler_map());
01161 }
01162 ASSERT(object->Size() == size);
01163 }
01164
01165
01166 }
01167 }
01168
01169
01170 static void SweepSpace(PagedSpace* space, DeallocateFunction dealloc) {
01171 PageIterator it(space, PageIterator::PAGES_IN_USE);
01172 while (it.has_next()) {
01173 Page* p = it.next();
01174
01175 bool is_previous_alive = true;
01176 Address free_start = NULL;
01177 HeapObject* object;
01178
01179 for (Address current = p->ObjectAreaStart();
01180 current < p->AllocationTop();
01181 current += object->Size()) {
01182 object = HeapObject::FromAddress(current);
01183 if (object->IsMarked()) {
01184 object->ClearMark();
01185 MarkCompactCollector::tracer()->decrement_marked_count();
01186 if (MarkCompactCollector::IsCompacting() && object->IsCode()) {
01187
01188
01189
01190 Code::cast(object)->ConvertICTargetsFromObjectToAddress();
01191 }
01192 if (!is_previous_alive) {
01193 dealloc(free_start, current - free_start);
01194 is_previous_alive = true;
01195 }
01196 } else {
01197 if (object->IsCode()) {
01198 LOG(CodeDeleteEvent(Code::cast(object)->address()));
01199 }
01200 if (is_previous_alive) {
01201 free_start = current;
01202 is_previous_alive = false;
01203 }
01204 }
01205
01206
01207 }
01208
01209
01210
01211 if (!is_previous_alive) {
01212 int free_size = p->AllocationTop() - free_start;
01213 if (free_size > 0) {
01214 dealloc(free_start, free_size);
01215 }
01216 }
01217 }
01218 }
01219
01220
01221 void MarkCompactCollector::DeallocateOldPointerBlock(Address start,
01222 int size_in_bytes) {
01223 Heap::ClearRSetRange(start, size_in_bytes);
01224 Heap::old_pointer_space()->Free(start, size_in_bytes);
01225 }
01226
01227
01228 void MarkCompactCollector::DeallocateOldDataBlock(Address start,
01229 int size_in_bytes) {
01230 Heap::old_data_space()->Free(start, size_in_bytes);
01231 }
01232
01233
01234 void MarkCompactCollector::DeallocateCodeBlock(Address start,
01235 int size_in_bytes) {
01236 Heap::code_space()->Free(start, size_in_bytes);
01237 }
01238
01239
01240 void MarkCompactCollector::DeallocateMapBlock(Address start,
01241 int size_in_bytes) {
01242
01243
01244
01245 ASSERT(size_in_bytes % Map::kSize == 0);
01246 Heap::ClearRSetRange(start, size_in_bytes);
01247 Address end = start + size_in_bytes;
01248 for (Address a = start; a < end; a += Map::kSize) {
01249 Heap::map_space()->Free(a);
01250 }
01251 }
01252
01253
01254 void MarkCompactCollector::EncodeForwardingAddresses() {
01255 ASSERT(state_ == ENCODE_FORWARDING_ADDRESSES);
01256
01257
01258
01259 Heap::new_space()->MCResetRelocationInfo();
01260
01261
01262 EncodeForwardingAddressesInPagedSpace<MCAllocateFromOldPointerSpace,
01263 IgnoreNonLiveObject>(
01264 Heap::old_pointer_space());
01265
01266 EncodeForwardingAddressesInPagedSpace<MCAllocateFromOldDataSpace,
01267 IgnoreNonLiveObject>(
01268 Heap::old_data_space());
01269
01270 EncodeForwardingAddressesInPagedSpace<MCAllocateFromCodeSpace,
01271 LogNonLiveCodeObject>(
01272 Heap::code_space());
01273
01274
01275
01276 EncodeForwardingAddressesInNewSpace();
01277
01278
01279
01280
01281 EncodeForwardingAddressesInPagedSpace<MCAllocateFromMapSpace,
01282 IgnoreNonLiveObject>(
01283 Heap::map_space());
01284
01285
01286
01287
01288 Heap::old_pointer_space()->MCWriteRelocationInfoToPage();
01289 Heap::old_data_space()->MCWriteRelocationInfoToPage();
01290 Heap::code_space()->MCWriteRelocationInfoToPage();
01291 Heap::map_space()->MCWriteRelocationInfoToPage();
01292 }
01293
01294
01295 void MarkCompactCollector::SweepSpaces() {
01296 ASSERT(state_ == SWEEP_SPACES);
01297 ASSERT(!IsCompacting());
01298
01299
01300
01301
01302
01303 SweepSpace(Heap::old_pointer_space(), &DeallocateOldPointerBlock);
01304 SweepSpace(Heap::old_data_space(), &DeallocateOldDataBlock);
01305 SweepSpace(Heap::code_space(), &DeallocateCodeBlock);
01306 SweepSpace(Heap::new_space());
01307 SweepSpace(Heap::map_space(), &DeallocateMapBlock);
01308 }
01309
01310
01311
01312
01313
01314
01315
01316 int MarkCompactCollector::IterateLiveObjectsInRange(
01317 Address start,
01318 Address end,
01319 HeapObjectCallback size_func) {
01320 int live_objects = 0;
01321 Address current = start;
01322 while (current < end) {
01323 uint32_t encoded_map = Memory::uint32_at(current);
01324 if (encoded_map == kSingleFreeEncoding) {
01325 current += kPointerSize;
01326 } else if (encoded_map == kMultiFreeEncoding) {
01327 current += Memory::int_at(current + kIntSize);
01328 } else {
01329 live_objects++;
01330 current += size_func(HeapObject::FromAddress(current));
01331 }
01332 }
01333 return live_objects;
01334 }
01335
01336
01337 int MarkCompactCollector::IterateLiveObjects(NewSpace* space,
01338 HeapObjectCallback size_f) {
01339 ASSERT(MARK_LIVE_OBJECTS < state_ && state_ <= RELOCATE_OBJECTS);
01340 return IterateLiveObjectsInRange(space->bottom(), space->top(), size_f);
01341 }
01342
01343
01344 int MarkCompactCollector::IterateLiveObjects(PagedSpace* space,
01345 HeapObjectCallback size_f) {
01346 ASSERT(MARK_LIVE_OBJECTS < state_ && state_ <= RELOCATE_OBJECTS);
01347 int total = 0;
01348 PageIterator it(space, PageIterator::PAGES_IN_USE);
01349 while (it.has_next()) {
01350 Page* p = it.next();
01351 total += IterateLiveObjectsInRange(p->ObjectAreaStart(),
01352 p->AllocationTop(),
01353 size_f);
01354 }
01355 return total;
01356 }
01357
01358
01359 #ifdef DEBUG
01360 static int VerifyMapObject(HeapObject* obj) {
01361 InstanceType type = reinterpret_cast<Map*>(obj)->instance_type();
01362 ASSERT(FIRST_TYPE <= type && type <= LAST_TYPE);
01363 return Map::kSize;
01364 }
01365
01366
01367 void MarkCompactCollector::VerifyHeapAfterEncodingForwardingAddresses() {
01368 AllSpaces spaces;
01369 while (Space* space = spaces.next()) space->Verify();
01370
01371 ASSERT(state_ == ENCODE_FORWARDING_ADDRESSES);
01372 int live_maps = IterateLiveObjects(Heap::map_space(), &VerifyMapObject);
01373 ASSERT(live_maps == live_map_objects_);
01374
01375
01376 PagedSpaces paged_spaces;
01377 while (PagedSpace* space = paged_spaces.next()) VerifyPageHeaders(space);
01378 }
01379
01380
01381 void MarkCompactCollector::VerifyPageHeaders(PagedSpace* space) {
01382 PageIterator mc_it(space, PageIterator::PAGES_USED_BY_MC);
01383 while (mc_it.has_next()) {
01384 Page* p = mc_it.next();
01385 Address mc_alloc_top = p->mc_relocation_top;
01386 ASSERT(p->ObjectAreaStart() <= mc_alloc_top &&
01387 mc_alloc_top <= p->ObjectAreaEnd());
01388 }
01389
01390 int page_count = 0;
01391 PageIterator it(space, PageIterator::PAGES_IN_USE);
01392 while (it.has_next()) {
01393 Page* p = it.next();
01394 ASSERT(p->mc_page_index == page_count);
01395 page_count++;
01396
01397
01398 Address first_forwarded = p->mc_first_forwarded;
01399 ASSERT(first_forwarded == kZapValue ||
01400 space->Contains(first_forwarded));
01401 }
01402 }
01403 #endif
01404
01405
01406
01407
01408
01409
01410 class UpdatingVisitor: public ObjectVisitor {
01411 public:
01412 void VisitPointer(Object** p) {
01413 UpdatePointer(p);
01414 }
01415
01416 void VisitPointers(Object** start, Object** end) {
01417
01418 for (Object** p = start; p < end; p++) UpdatePointer(p);
01419 }
01420
01421 private:
01422 void UpdatePointer(Object** p) {
01423 if (!(*p)->IsHeapObject()) return;
01424
01425 HeapObject* obj = HeapObject::cast(*p);
01426 Address old_addr = obj->address();
01427 Address new_addr;
01428 ASSERT(!Heap::InFromSpace(obj));
01429
01430 if (Heap::new_space()->Contains(obj)) {
01431 Address f_addr = Heap::new_space()->FromSpaceLow() +
01432 Heap::new_space()->ToSpaceOffsetForAddress(old_addr);
01433 new_addr = Memory::Address_at(f_addr);
01434
01435 #ifdef DEBUG
01436 ASSERT(Heap::old_pointer_space()->Contains(new_addr) ||
01437 Heap::old_data_space()->Contains(new_addr) ||
01438 Heap::code_space()->Contains(new_addr) ||
01439 Heap::new_space()->FromSpaceContains(new_addr));
01440
01441 if (Heap::new_space()->FromSpaceContains(new_addr)) {
01442 ASSERT(Heap::new_space()->FromSpaceOffsetForAddress(new_addr) <=
01443 Heap::new_space()->ToSpaceOffsetForAddress(old_addr));
01444 }
01445 #endif
01446
01447 } else if (Heap::lo_space()->Contains(obj)) {
01448
01449 return;
01450
01451 } else {
01452 ASSERT(Heap::old_pointer_space()->Contains(obj) ||
01453 Heap::old_data_space()->Contains(obj) ||
01454 Heap::code_space()->Contains(obj) ||
01455 Heap::map_space()->Contains(obj));
01456
01457 new_addr = MarkCompactCollector::GetForwardingAddressInOldSpace(obj);
01458 ASSERT(Heap::old_pointer_space()->Contains(new_addr) ||
01459 Heap::old_data_space()->Contains(new_addr) ||
01460 Heap::code_space()->Contains(new_addr) ||
01461 Heap::map_space()->Contains(new_addr));
01462
01463 #ifdef DEBUG
01464 if (Heap::old_pointer_space()->Contains(obj)) {
01465 ASSERT(Heap::old_pointer_space()->MCSpaceOffsetForAddress(new_addr) <=
01466 Heap::old_pointer_space()->MCSpaceOffsetForAddress(old_addr));
01467 } else if (Heap::old_data_space()->Contains(obj)) {
01468 ASSERT(Heap::old_data_space()->MCSpaceOffsetForAddress(new_addr) <=
01469 Heap::old_data_space()->MCSpaceOffsetForAddress(old_addr));
01470 } else if (Heap::code_space()->Contains(obj)) {
01471 ASSERT(Heap::code_space()->MCSpaceOffsetForAddress(new_addr) <=
01472 Heap::code_space()->MCSpaceOffsetForAddress(old_addr));
01473 } else {
01474 ASSERT(Heap::map_space()->MCSpaceOffsetForAddress(new_addr) <=
01475 Heap::map_space()->MCSpaceOffsetForAddress(old_addr));
01476 }
01477 #endif
01478 }
01479
01480 *p = HeapObject::FromAddress(new_addr);
01481
01482 #ifdef DEBUG
01483 if (FLAG_gc_verbose) {
01484 PrintF("update %p : %p -> %p\n",
01485 reinterpret_cast<Address>(p), old_addr, new_addr);
01486 }
01487 #endif
01488 }
01489 };
01490
01491
01492 void MarkCompactCollector::UpdatePointers() {
01493 #ifdef DEBUG
01494 ASSERT(state_ == ENCODE_FORWARDING_ADDRESSES);
01495 state_ = UPDATE_POINTERS;
01496 #endif
01497 UpdatingVisitor updating_visitor;
01498 Heap::IterateRoots(&updating_visitor);
01499 GlobalHandles::IterateWeakRoots(&updating_visitor);
01500
01501 int live_maps = IterateLiveObjects(Heap::map_space(),
01502 &UpdatePointersInOldObject);
01503 int live_pointer_olds = IterateLiveObjects(Heap::old_pointer_space(),
01504 &UpdatePointersInOldObject);
01505 int live_data_olds = IterateLiveObjects(Heap::old_data_space(),
01506 &UpdatePointersInOldObject);
01507 int live_codes = IterateLiveObjects(Heap::code_space(),
01508 &UpdatePointersInOldObject);
01509 int live_news = IterateLiveObjects(Heap::new_space(),
01510 &UpdatePointersInNewObject);
01511
01512
01513 LargeObjectIterator it(Heap::lo_space());
01514 while (it.has_next()) UpdatePointersInNewObject(it.next());
01515
01516 USE(live_maps);
01517 USE(live_pointer_olds);
01518 USE(live_data_olds);
01519 USE(live_codes);
01520 USE(live_news);
01521
01522 #ifdef DEBUG
01523 ASSERT(live_maps == live_map_objects_);
01524 ASSERT(live_data_olds == live_old_data_objects_);
01525 ASSERT(live_pointer_olds == live_old_pointer_objects_);
01526 ASSERT(live_codes == live_code_objects_);
01527 ASSERT(live_news == live_young_objects_);
01528
01529 if (FLAG_verify_global_gc) VerifyHeapAfterUpdatingPointers();
01530 #endif
01531 }
01532
01533
01534 int MarkCompactCollector::UpdatePointersInNewObject(HeapObject* obj) {
01535
01536 Map* old_map = obj->map();
01537 ASSERT(old_map->IsHeapObject());
01538
01539 Address forwarded = GetForwardingAddressInOldSpace(old_map);
01540
01541 ASSERT(Heap::map_space()->Contains(old_map));
01542 ASSERT(Heap::map_space()->Contains(forwarded));
01543 #ifdef DEBUG
01544 if (FLAG_gc_verbose) {
01545 PrintF("update %p : %p -> %p\n", obj->address(), old_map->address(),
01546 forwarded);
01547 }
01548 #endif
01549
01550 obj->set_map(reinterpret_cast<Map*>(HeapObject::FromAddress(forwarded)));
01551
01552
01553
01554 int obj_size = obj->SizeFromMap(old_map);
01555
01556
01557 UpdatingVisitor updating_visitor;
01558 obj->IterateBody(old_map->instance_type(), obj_size, &updating_visitor);
01559 return obj_size;
01560 }
01561
01562
01563 int MarkCompactCollector::UpdatePointersInOldObject(HeapObject* obj) {
01564
01565 MapWord encoding = obj->map_word();
01566 Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
01567 ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr)));
01568
01569
01570
01571 Map* map = reinterpret_cast<Map*>(HeapObject::FromAddress(map_addr));
01572 int obj_size = obj->SizeFromMap(map);
01573 InstanceType type = map->instance_type();
01574
01575
01576 Address new_map_addr = GetForwardingAddressInOldSpace(map);
01577 int offset = encoding.DecodeOffset();
01578 obj->set_map_word(MapWord::EncodeAddress(new_map_addr, offset));
01579
01580 #ifdef DEBUG
01581 if (FLAG_gc_verbose) {
01582 PrintF("update %p : %p -> %p\n", obj->address(),
01583 map_addr, new_map_addr);
01584 }
01585 #endif
01586
01587
01588 UpdatingVisitor updating_visitor;
01589 obj->IterateBody(type, obj_size, &updating_visitor);
01590 return obj_size;
01591 }
01592
01593
01594 Address MarkCompactCollector::GetForwardingAddressInOldSpace(HeapObject* obj) {
01595
01596 MapWord encoding = obj->map_word();
01597
01598
01599 int offset = encoding.DecodeOffset();
01600 Address obj_addr = obj->address();
01601
01602
01603 Page* p = Page::FromAddress(obj_addr);
01604 Address first_forwarded = p->mc_first_forwarded;
01605
01606
01607 Page* forwarded_page = Page::FromAddress(first_forwarded);
01608 int forwarded_offset = forwarded_page->Offset(first_forwarded);
01609
01610
01611 Address mc_top = forwarded_page->mc_relocation_top;
01612 int mc_top_offset = forwarded_page->Offset(mc_top);
01613
01614
01615
01616 if (forwarded_offset + offset < mc_top_offset) {
01617
01618 return first_forwarded + offset;
01619 }
01620
01621
01622 Page* next_page = forwarded_page->next_page();
01623 ASSERT(next_page->is_valid());
01624
01625 offset -= (mc_top_offset - forwarded_offset);
01626 offset += Page::kObjectStartOffset;
01627
01628 ASSERT_PAGE_OFFSET(offset);
01629 ASSERT(next_page->OffsetToAddress(offset) < next_page->mc_relocation_top);
01630
01631 return next_page->OffsetToAddress(offset);
01632 }
01633
01634
01635 #ifdef DEBUG
01636 void MarkCompactCollector::VerifyHeapAfterUpdatingPointers() {
01637 ASSERT(state_ == UPDATE_POINTERS);
01638
01639 AllSpaces spaces;
01640 while (Space* space = spaces.next()) space->Verify();
01641 PagedSpaces paged_spaces;
01642 while (PagedSpace* space = paged_spaces.next()) VerifyPageHeaders(space);
01643 }
01644 #endif
01645
01646
01647
01648
01649
01650 void MarkCompactCollector::RelocateObjects() {
01651 #ifdef DEBUG
01652 ASSERT(state_ == UPDATE_POINTERS);
01653 state_ = RELOCATE_OBJECTS;
01654 #endif
01655
01656
01657 int live_maps = IterateLiveObjects(Heap::map_space(), &RelocateMapObject);
01658 int live_pointer_olds = IterateLiveObjects(Heap::old_pointer_space(),
01659 &RelocateOldPointerObject);
01660 int live_data_olds = IterateLiveObjects(Heap::old_data_space(),
01661 &RelocateOldDataObject);
01662 int live_codes = IterateLiveObjects(Heap::code_space(), &RelocateCodeObject);
01663 int live_news = IterateLiveObjects(Heap::new_space(), &RelocateNewObject);
01664
01665 USE(live_maps);
01666 USE(live_data_olds);
01667 USE(live_pointer_olds);
01668 USE(live_codes);
01669 USE(live_news);
01670 #ifdef DEBUG
01671 ASSERT(live_maps == live_map_objects_);
01672 ASSERT(live_data_olds == live_old_data_objects_);
01673 ASSERT(live_pointer_olds == live_old_pointer_objects_);
01674 ASSERT(live_codes == live_code_objects_);
01675 ASSERT(live_news == live_young_objects_);
01676 #endif
01677
01678
01679
01680 LargeObjectIterator it(Heap::lo_space());
01681 while (it.has_next()) { ConvertCodeICTargetToAddress(it.next()); }
01682
01683
01684 Heap::new_space()->Flip();
01685
01686
01687 Address mark = Heap::new_space()->bottom();
01688 Heap::new_space()->set_age_mark(mark);
01689
01690 Heap::new_space()->MCCommitRelocationInfo();
01691 #ifdef DEBUG
01692
01693
01694 Page::set_rset_state(Page::IN_USE);
01695 #endif
01696 PagedSpaces spaces;
01697 while (PagedSpace* space = spaces.next()) space->MCCommitRelocationInfo();
01698
01699 #ifdef DEBUG
01700 if (FLAG_verify_global_gc) VerifyHeapAfterRelocatingObjects();
01701 #endif
01702 }
01703
01704
01705 int MarkCompactCollector::ConvertCodeICTargetToAddress(HeapObject* obj) {
01706 if (obj->IsCode()) {
01707 Code::cast(obj)->ConvertICTargetsFromObjectToAddress();
01708 }
01709 return obj->Size();
01710 }
01711
01712
01713 int MarkCompactCollector::RelocateMapObject(HeapObject* obj) {
01714
01715 MapWord encoding = obj->map_word();
01716 Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
01717 ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr)));
01718
01719
01720 Address new_addr = GetForwardingAddressInOldSpace(obj);
01721
01722
01723 obj->set_map(reinterpret_cast<Map*>(HeapObject::FromAddress(map_addr)));
01724
01725
01726 Address old_addr = obj->address();
01727
01728 if (new_addr != old_addr) {
01729 memmove(new_addr, old_addr, Map::kSize);
01730 }
01731
01732 #ifdef DEBUG
01733 if (FLAG_gc_verbose) {
01734 PrintF("relocate %p -> %p\n", old_addr, new_addr);
01735 }
01736 #endif
01737
01738 return Map::kSize;
01739 }
01740
01741
01742 static inline int RelocateOldObject(HeapObject* obj,
01743 OldSpace* space,
01744 Address new_addr,
01745 Address map_addr) {
01746
01747 obj->set_map(reinterpret_cast<Map*>(HeapObject::FromAddress(map_addr)));
01748
01749
01750
01751 int obj_size = obj->Size();
01752 ASSERT_OBJECT_SIZE(obj_size);
01753
01754 ASSERT(space->MCSpaceOffsetForAddress(new_addr) <=
01755 space->MCSpaceOffsetForAddress(obj->address()));
01756
01757 space->MCAdjustRelocationEnd(new_addr, obj_size);
01758
01759 #ifdef DEBUG
01760 if (FLAG_gc_verbose) {
01761 PrintF("relocate %p -> %p\n", obj->address(), new_addr);
01762 }
01763 #endif
01764
01765 return obj_size;
01766 }
01767
01768
01769 int MarkCompactCollector::RelocateOldNonCodeObject(HeapObject* obj,
01770 OldSpace* space) {
01771
01772 MapWord encoding = obj->map_word();
01773 Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
01774 ASSERT(Heap::map_space()->Contains(map_addr));
01775
01776
01777 Address new_addr = GetForwardingAddressInOldSpace(obj);
01778
01779 int obj_size = RelocateOldObject(obj, space, new_addr, map_addr);
01780
01781 Address old_addr = obj->address();
01782
01783 if (new_addr != old_addr) {
01784 memmove(new_addr, old_addr, obj_size);
01785 }
01786
01787 ASSERT(!HeapObject::FromAddress(new_addr)->IsCode());
01788
01789 return obj_size;
01790 }
01791
01792
01793 int MarkCompactCollector::RelocateOldPointerObject(HeapObject* obj) {
01794 return RelocateOldNonCodeObject(obj, Heap::old_pointer_space());
01795 }
01796
01797
01798 int MarkCompactCollector::RelocateOldDataObject(HeapObject* obj) {
01799 return RelocateOldNonCodeObject(obj, Heap::old_data_space());
01800 }
01801
01802
01803 int MarkCompactCollector::RelocateCodeObject(HeapObject* obj) {
01804
01805 MapWord encoding = obj->map_word();
01806 Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
01807 ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr)));
01808
01809
01810 Address new_addr = GetForwardingAddressInOldSpace(obj);
01811
01812 int obj_size = RelocateOldObject(obj, Heap::code_space(), new_addr, map_addr);
01813
01814
01815 if (obj->IsCode()) {
01816
01817 Code::cast(obj)->ConvertICTargetsFromObjectToAddress();
01818 }
01819
01820 Address old_addr = obj->address();
01821
01822 if (new_addr != old_addr) {
01823 memmove(new_addr, old_addr, obj_size);
01824 }
01825
01826 HeapObject* copied_to = HeapObject::FromAddress(new_addr);
01827 if (copied_to->IsCode()) {
01828
01829 Code::cast(copied_to)->Relocate(new_addr - old_addr);
01830
01831 LOG(CodeMoveEvent(old_addr, new_addr));
01832 }
01833
01834 return obj_size;
01835 }
01836
01837
01838 #ifdef DEBUG
01839 class VerifyCopyingVisitor: public ObjectVisitor {
01840 public:
01841 void VisitPointers(Object** start, Object** end) {
01842 for (Object** p = start; p < end; p++) {
01843 MarkCompactCollector::VerifyCopyingObjects(p);
01844 }
01845 }
01846 };
01847
01848 #endif
01849
01850 int MarkCompactCollector::RelocateNewObject(HeapObject* obj) {
01851 int obj_size = obj->Size();
01852
01853
01854 Address old_addr = obj->address();
01855 int offset = Heap::new_space()->ToSpaceOffsetForAddress(old_addr);
01856
01857 Address new_addr =
01858 Memory::Address_at(Heap::new_space()->FromSpaceLow() + offset);
01859
01860 if (Heap::new_space()->FromSpaceContains(new_addr)) {
01861 ASSERT(Heap::new_space()->FromSpaceOffsetForAddress(new_addr) <=
01862 Heap::new_space()->ToSpaceOffsetForAddress(old_addr));
01863 } else {
01864 OldSpace* target_space = Heap::TargetSpace(obj);
01865 ASSERT(target_space == Heap::old_pointer_space() ||
01866 target_space == Heap::old_data_space());
01867 target_space->MCAdjustRelocationEnd(new_addr, obj_size);
01868 }
01869
01870
01871 memcpy(reinterpret_cast<void*>(new_addr),
01872 reinterpret_cast<void*>(old_addr),
01873 obj_size);
01874
01875 #ifdef DEBUG
01876 if (FLAG_gc_verbose) {
01877 PrintF("relocate %p -> %p\n", old_addr, new_addr);
01878 }
01879 if (FLAG_verify_global_gc) {
01880 VerifyCopyingVisitor v;
01881 HeapObject* copied_to = HeapObject::FromAddress(new_addr);
01882 copied_to->Iterate(&v);
01883 }
01884 #endif
01885
01886 return obj_size;
01887 }
01888
01889
01890 #ifdef DEBUG
01891 void MarkCompactCollector::VerifyHeapAfterRelocatingObjects() {
01892 ASSERT(state_ == RELOCATE_OBJECTS);
01893
01894 Heap::new_space()->Verify();
01895 PagedSpaces spaces;
01896 while (PagedSpace* space = spaces.next()) {
01897 space->Verify();
01898 PageIterator it(space, PageIterator::PAGES_IN_USE);
01899 while (it.has_next()) {
01900 Page* p = it.next();
01901 ASSERT_PAGE_OFFSET(p->Offset(p->AllocationTop()));
01902 }
01903 }
01904 }
01905 #endif
01906
01907
01908 #ifdef DEBUG
01909 void MarkCompactCollector::VerifyCopyingObjects(Object** p) {
01910 if (!(*p)->IsHeapObject()) return;
01911 ASSERT(!Heap::InToSpace(*p));
01912 }
01913 #endif // DEBUG
01914
01915
01916
01917
01918
01919 void MarkCompactCollector::RebuildRSets() {
01920 #ifdef DEBUG
01921 ASSERT(state_ == RELOCATE_OBJECTS);
01922 state_ = REBUILD_RSETS;
01923 #endif
01924 Heap::RebuildRSets();
01925 }
01926
01927 } }