1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #include "compilation-cache.h" 31 #include "execution.h" 32 #include "heap-profiler.h" 33 #include "gdb-jit.h" 34 #include "global-handles.h" 35 #include "ic-inl.h" 36 #include "liveobjectlist-inl.h" 37 #include "mark-compact.h" 38 #include "objects-visiting.h" 39 #include "stub-cache.h" 40 41 namespace v8 { 42 namespace internal { 43 44 // ------------------------------------------------------------------------- 45 // MarkCompactCollector 46 47 MarkCompactCollector::MarkCompactCollector() : // NOLINT 48 #ifdef DEBUG 49 state_(IDLE), 50 #endif 51 force_compaction_(false), 52 compacting_collection_(false), 53 compact_on_next_gc_(false), 54 previous_marked_count_(0), 55 tracer_(NULL), 56 #ifdef DEBUG 57 live_young_objects_size_(0), 58 live_old_pointer_objects_size_(0), 59 live_old_data_objects_size_(0), 60 live_code_objects_size_(0), 61 live_map_objects_size_(0), 62 live_cell_objects_size_(0), 63 live_lo_objects_size_(0), 64 live_bytes_(0), 65 #endif 66 heap_(NULL), 67 code_flusher_(NULL) { } 68 69 70 void MarkCompactCollector::CollectGarbage() { 71 // Make sure that Prepare() has been called. The individual steps below will 72 // update the state as they proceed. 73 ASSERT(state_ == PREPARE_GC); 74 75 // Prepare has selected whether to compact the old generation or not. 76 // Tell the tracer. 77 if (IsCompacting()) tracer_->set_is_compacting(); 78 79 MarkLiveObjects(); 80 81 if (FLAG_collect_maps) ClearNonLiveTransitions(); 82 83 SweepLargeObjectSpace(); 84 85 if (IsCompacting()) { 86 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_COMPACT); 87 EncodeForwardingAddresses(); 88 89 heap()->MarkMapPointersAsEncoded(true); 90 UpdatePointers(); 91 heap()->MarkMapPointersAsEncoded(false); 92 heap()->isolate()->pc_to_code_cache()->Flush(); 93 94 RelocateObjects(); 95 } else { 96 SweepSpaces(); 97 heap()->isolate()->pc_to_code_cache()->Flush(); 98 } 99 100 Finish(); 101 102 // Save the count of marked objects remaining after the collection and 103 // null out the GC tracer. 104 previous_marked_count_ = tracer_->marked_count(); 105 ASSERT(previous_marked_count_ == 0); 106 tracer_ = NULL; 107 } 108 109 110 void MarkCompactCollector::Prepare(GCTracer* tracer) { 111 // Rather than passing the tracer around we stash it in a static member 112 // variable. 113 tracer_ = tracer; 114 115 #ifdef DEBUG 116 ASSERT(state_ == IDLE); 117 state_ = PREPARE_GC; 118 #endif 119 ASSERT(!FLAG_always_compact || !FLAG_never_compact); 120 121 compacting_collection_ = 122 FLAG_always_compact || force_compaction_ || compact_on_next_gc_; 123 compact_on_next_gc_ = false; 124 125 if (FLAG_never_compact) compacting_collection_ = false; 126 if (!heap()->map_space()->MapPointersEncodable()) 127 compacting_collection_ = false; 128 if (FLAG_collect_maps) CreateBackPointers(); 129 #ifdef ENABLE_GDB_JIT_INTERFACE 130 if (FLAG_gdbjit) { 131 // If GDBJIT interface is active disable compaction. 132 compacting_collection_ = false; 133 } 134 #endif 135 136 PagedSpaces spaces; 137 for (PagedSpace* space = spaces.next(); 138 space != NULL; space = spaces.next()) { 139 space->PrepareForMarkCompact(compacting_collection_); 140 } 141 142 #ifdef DEBUG 143 live_bytes_ = 0; 144 live_young_objects_size_ = 0; 145 live_old_pointer_objects_size_ = 0; 146 live_old_data_objects_size_ = 0; 147 live_code_objects_size_ = 0; 148 live_map_objects_size_ = 0; 149 live_cell_objects_size_ = 0; 150 live_lo_objects_size_ = 0; 151 #endif 152 } 153 154 155 void MarkCompactCollector::Finish() { 156 #ifdef DEBUG 157 ASSERT(state_ == SWEEP_SPACES || state_ == RELOCATE_OBJECTS); 158 state_ = IDLE; 159 #endif 160 // The stub cache is not traversed during GC; clear the cache to 161 // force lazy re-initialization of it. This must be done after the 162 // GC, because it relies on the new address of certain old space 163 // objects (empty string, illegal builtin). 164 heap()->isolate()->stub_cache()->Clear(); 165 166 heap()->external_string_table_.CleanUp(); 167 168 // If we've just compacted old space there's no reason to check the 169 // fragmentation limit. Just return. 170 if (HasCompacted()) return; 171 172 // We compact the old generation on the next GC if it has gotten too 173 // fragmented (ie, we could recover an expected amount of space by 174 // reclaiming the waste and free list blocks). 175 static const int kFragmentationLimit = 15; // Percent. 176 static const int kFragmentationAllowed = 1 * MB; // Absolute. 177 intptr_t old_gen_recoverable = 0; 178 intptr_t old_gen_used = 0; 179 180 OldSpaces spaces; 181 for (OldSpace* space = spaces.next(); space != NULL; space = spaces.next()) { 182 old_gen_recoverable += space->Waste() + space->AvailableFree(); 183 old_gen_used += space->Size(); 184 } 185 186 int old_gen_fragmentation = 187 static_cast<int>((old_gen_recoverable * 100.0) / old_gen_used); 188 if (old_gen_fragmentation > kFragmentationLimit && 189 old_gen_recoverable > kFragmentationAllowed) { 190 compact_on_next_gc_ = true; 191 } 192 } 193 194 195 // ------------------------------------------------------------------------- 196 // Phase 1: tracing and marking live objects. 197 // before: all objects are in normal state. 198 // after: a live object's map pointer is marked as '00'. 199 200 // Marking all live objects in the heap as part of mark-sweep or mark-compact 201 // collection. Before marking, all objects are in their normal state. After 202 // marking, live objects' map pointers are marked indicating that the object 203 // has been found reachable. 204 // 205 // The marking algorithm is a (mostly) depth-first (because of possible stack 206 // overflow) traversal of the graph of objects reachable from the roots. It 207 // uses an explicit stack of pointers rather than recursion. The young 208 // generation's inactive ('from') space is used as a marking stack. The 209 // objects in the marking stack are the ones that have been reached and marked 210 // but their children have not yet been visited. 211 // 212 // The marking stack can overflow during traversal. In that case, we set an 213 // overflow flag. When the overflow flag is set, we continue marking objects 214 // reachable from the objects on the marking stack, but no longer push them on 215 // the marking stack. Instead, we mark them as both marked and overflowed. 216 // When the stack is in the overflowed state, objects marked as overflowed 217 // have been reached and marked but their children have not been visited yet. 218 // After emptying the marking stack, we clear the overflow flag and traverse 219 // the heap looking for objects marked as overflowed, push them on the stack, 220 // and continue with marking. This process repeats until all reachable 221 // objects have been marked. 222 223 class CodeFlusher { 224 public: 225 explicit CodeFlusher(Isolate* isolate) 226 : isolate_(isolate), 227 jsfunction_candidates_head_(NULL), 228 shared_function_info_candidates_head_(NULL) {} 229 230 void AddCandidate(SharedFunctionInfo* shared_info) { 231 SetNextCandidate(shared_info, shared_function_info_candidates_head_); 232 shared_function_info_candidates_head_ = shared_info; 233 } 234 235 void AddCandidate(JSFunction* function) { 236 ASSERT(function->unchecked_code() == 237 function->unchecked_shared()->unchecked_code()); 238 239 SetNextCandidate(function, jsfunction_candidates_head_); 240 jsfunction_candidates_head_ = function; 241 } 242 243 void ProcessCandidates() { 244 ProcessSharedFunctionInfoCandidates(); 245 ProcessJSFunctionCandidates(); 246 } 247 248 private: 249 void ProcessJSFunctionCandidates() { 250 Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kLazyCompile); 251 252 JSFunction* candidate = jsfunction_candidates_head_; 253 JSFunction* next_candidate; 254 while (candidate != NULL) { 255 next_candidate = GetNextCandidate(candidate); 256 257 SharedFunctionInfo* shared = candidate->unchecked_shared(); 258 259 Code* code = shared->unchecked_code(); 260 if (!code->IsMarked()) { 261 shared->set_code(lazy_compile); 262 candidate->set_code(lazy_compile); 263 } else { 264 candidate->set_code(shared->unchecked_code()); 265 } 266 267 candidate = next_candidate; 268 } 269 270 jsfunction_candidates_head_ = NULL; 271 } 272 273 274 void ProcessSharedFunctionInfoCandidates() { 275 Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kLazyCompile); 276 277 SharedFunctionInfo* candidate = shared_function_info_candidates_head_; 278 SharedFunctionInfo* next_candidate; 279 while (candidate != NULL) { 280 next_candidate = GetNextCandidate(candidate); 281 SetNextCandidate(candidate, NULL); 282 283 Code* code = candidate->unchecked_code(); 284 if (!code->IsMarked()) { 285 candidate->set_code(lazy_compile); 286 } 287 288 candidate = next_candidate; 289 } 290 291 shared_function_info_candidates_head_ = NULL; 292 } 293 294 static JSFunction** GetNextCandidateField(JSFunction* candidate) { 295 return reinterpret_cast<JSFunction**>( 296 candidate->address() + JSFunction::kCodeEntryOffset); 297 } 298 299 static JSFunction* GetNextCandidate(JSFunction* candidate) { 300 return *GetNextCandidateField(candidate); 301 } 302 303 static void SetNextCandidate(JSFunction* candidate, 304 JSFunction* next_candidate) { 305 *GetNextCandidateField(candidate) = next_candidate; 306 } 307 308 STATIC_ASSERT(kPointerSize <= Code::kHeaderSize - Code::kHeaderPaddingStart); 309 310 static SharedFunctionInfo** GetNextCandidateField( 311 SharedFunctionInfo* candidate) { 312 Code* code = candidate->unchecked_code(); 313 return reinterpret_cast<SharedFunctionInfo**>( 314 code->address() + Code::kHeaderPaddingStart); 315 } 316 317 static SharedFunctionInfo* GetNextCandidate(SharedFunctionInfo* candidate) { 318 return *GetNextCandidateField(candidate); 319 } 320 321 static void SetNextCandidate(SharedFunctionInfo* candidate, 322 SharedFunctionInfo* next_candidate) { 323 *GetNextCandidateField(candidate) = next_candidate; 324 } 325 326 Isolate* isolate_; 327 JSFunction* jsfunction_candidates_head_; 328 SharedFunctionInfo* shared_function_info_candidates_head_; 329 330 DISALLOW_COPY_AND_ASSIGN(CodeFlusher); 331 }; 332 333 334 MarkCompactCollector::~MarkCompactCollector() { 335 if (code_flusher_ != NULL) { 336 delete code_flusher_; 337 code_flusher_ = NULL; 338 } 339 } 340 341 342 static inline HeapObject* ShortCircuitConsString(Object** p) { 343 // Optimization: If the heap object pointed to by p is a non-symbol 344 // cons string whose right substring is HEAP->empty_string, update 345 // it in place to its left substring. Return the updated value. 346 // 347 // Here we assume that if we change *p, we replace it with a heap object 348 // (ie, the left substring of a cons string is always a heap object). 349 // 350 // The check performed is: 351 // object->IsConsString() && !object->IsSymbol() && 352 // (ConsString::cast(object)->second() == HEAP->empty_string()) 353 // except the maps for the object and its possible substrings might be 354 // marked. 355 HeapObject* object = HeapObject::cast(*p); 356 MapWord map_word = object->map_word(); 357 map_word.ClearMark(); 358 InstanceType type = map_word.ToMap()->instance_type(); 359 if ((type & kShortcutTypeMask) != kShortcutTypeTag) return object; 360 361 Object* second = reinterpret_cast<ConsString*>(object)->unchecked_second(); 362 Heap* heap = map_word.ToMap()->heap(); 363 if (second != heap->raw_unchecked_empty_string()) { 364 return object; 365 } 366 367 // Since we don't have the object's start, it is impossible to update the 368 // page dirty marks. Therefore, we only replace the string with its left 369 // substring when page dirty marks do not change. 370 Object* first = reinterpret_cast<ConsString*>(object)->unchecked_first(); 371 if (!heap->InNewSpace(object) && heap->InNewSpace(first)) return object; 372 373 *p = first; 374 return HeapObject::cast(first); 375 } 376 377 378 class StaticMarkingVisitor : public StaticVisitorBase { 379 public: 380 static inline void IterateBody(Map* map, HeapObject* obj) { 381 table_.GetVisitor(map)(map, obj); 382 } 383 384 static void Initialize() { 385 table_.Register(kVisitShortcutCandidate, 386 &FixedBodyVisitor<StaticMarkingVisitor, 387 ConsString::BodyDescriptor, 388 void>::Visit); 389 390 table_.Register(kVisitConsString, 391 &FixedBodyVisitor<StaticMarkingVisitor, 392 ConsString::BodyDescriptor, 393 void>::Visit); 394 395 396 table_.Register(kVisitFixedArray, 397 &FlexibleBodyVisitor<StaticMarkingVisitor, 398 FixedArray::BodyDescriptor, 399 void>::Visit); 400 401 table_.Register(kVisitGlobalContext, 402 &FixedBodyVisitor<StaticMarkingVisitor, 403 Context::MarkCompactBodyDescriptor, 404 void>::Visit); 405 406 table_.Register(kVisitByteArray, &DataObjectVisitor::Visit); 407 table_.Register(kVisitSeqAsciiString, &DataObjectVisitor::Visit); 408 table_.Register(kVisitSeqTwoByteString, &DataObjectVisitor::Visit); 409 410 table_.Register(kVisitOddball, 411 &FixedBodyVisitor<StaticMarkingVisitor, 412 Oddball::BodyDescriptor, 413 void>::Visit); 414 table_.Register(kVisitMap, 415 &FixedBodyVisitor<StaticMarkingVisitor, 416 Map::BodyDescriptor, 417 void>::Visit); 418 419 table_.Register(kVisitCode, &VisitCode); 420 421 table_.Register(kVisitSharedFunctionInfo, 422 &VisitSharedFunctionInfoAndFlushCode); 423 424 table_.Register(kVisitJSFunction, 425 &VisitJSFunctionAndFlushCode); 426 427 table_.Register(kVisitPropertyCell, 428 &FixedBodyVisitor<StaticMarkingVisitor, 429 JSGlobalPropertyCell::BodyDescriptor, 430 void>::Visit); 431 432 table_.RegisterSpecializations<DataObjectVisitor, 433 kVisitDataObject, 434 kVisitDataObjectGeneric>(); 435 436 table_.RegisterSpecializations<JSObjectVisitor, 437 kVisitJSObject, 438 kVisitJSObjectGeneric>(); 439 440 table_.RegisterSpecializations<StructObjectVisitor, 441 kVisitStruct, 442 kVisitStructGeneric>(); 443 } 444 445 INLINE(static void VisitPointer(Heap* heap, Object** p)) { 446 MarkObjectByPointer(heap, p); 447 } 448 449 INLINE(static void VisitPointers(Heap* heap, Object** start, Object** end)) { 450 // Mark all objects pointed to in [start, end). 451 const int kMinRangeForMarkingRecursion = 64; 452 if (end - start >= kMinRangeForMarkingRecursion) { 453 if (VisitUnmarkedObjects(heap, start, end)) return; 454 // We are close to a stack overflow, so just mark the objects. 455 } 456 for (Object** p = start; p < end; p++) MarkObjectByPointer(heap, p); 457 } 458 459 static inline void VisitCodeTarget(Heap* heap, RelocInfo* rinfo) { 460 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); 461 Code* code = Code::GetCodeFromTargetAddress(rinfo->target_address()); 462 if (FLAG_cleanup_ics_at_gc && code->is_inline_cache_stub()) { 463 IC::Clear(rinfo->pc()); 464 // Please note targets for cleared inline cached do not have to be 465 // marked since they are contained in HEAP->non_monomorphic_cache(). 466 } else { 467 heap->mark_compact_collector()->MarkObject(code); 468 } 469 } 470 471 static void VisitGlobalPropertyCell(Heap* heap, RelocInfo* rinfo) { 472 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL); 473 Object* cell = rinfo->target_cell(); 474 Object* old_cell = cell; 475 VisitPointer(heap, &cell); 476 if (cell != old_cell) { 477 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell)); 478 } 479 } 480 481 static inline void VisitDebugTarget(Heap* heap, RelocInfo* rinfo) { 482 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) && 483 rinfo->IsPatchedReturnSequence()) || 484 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && 485 rinfo->IsPatchedDebugBreakSlotSequence())); 486 HeapObject* code = Code::GetCodeFromTargetAddress(rinfo->call_address()); 487 heap->mark_compact_collector()->MarkObject(code); 488 } 489 490 // Mark object pointed to by p. 491 INLINE(static void MarkObjectByPointer(Heap* heap, Object** p)) { 492 if (!(*p)->IsHeapObject()) return; 493 HeapObject* object = ShortCircuitConsString(p); 494 if (!object->IsMarked()) { 495 heap->mark_compact_collector()->MarkUnmarkedObject(object); 496 } 497 } 498 499 500 // Visit an unmarked object. 501 INLINE(static void VisitUnmarkedObject(MarkCompactCollector* collector, 502 HeapObject* obj)) { 503 #ifdef DEBUG 504 ASSERT(Isolate::Current()->heap()->Contains(obj)); 505 ASSERT(!obj->IsMarked()); 506 #endif 507 Map* map = obj->map(); 508 collector->SetMark(obj); 509 // Mark the map pointer and the body. 510 if (!map->IsMarked()) collector->MarkUnmarkedObject(map); 511 IterateBody(map, obj); 512 } 513 514 // Visit all unmarked objects pointed to by [start, end). 515 // Returns false if the operation fails (lack of stack space). 516 static inline bool VisitUnmarkedObjects(Heap* heap, 517 Object** start, 518 Object** end) { 519 // Return false is we are close to the stack limit. 520 StackLimitCheck check(heap->isolate()); 521 if (check.HasOverflowed()) return false; 522 523 MarkCompactCollector* collector = heap->mark_compact_collector(); 524 // Visit the unmarked objects. 525 for (Object** p = start; p < end; p++) { 526 if (!(*p)->IsHeapObject()) continue; 527 HeapObject* obj = HeapObject::cast(*p); 528 if (obj->IsMarked()) continue; 529 VisitUnmarkedObject(collector, obj); 530 } 531 return true; 532 } 533 534 static inline void VisitExternalReference(Address* p) { } 535 static inline void VisitRuntimeEntry(RelocInfo* rinfo) { } 536 537 private: 538 class DataObjectVisitor { 539 public: 540 template<int size> 541 static void VisitSpecialized(Map* map, HeapObject* object) { 542 } 543 544 static void Visit(Map* map, HeapObject* object) { 545 } 546 }; 547 548 typedef FlexibleBodyVisitor<StaticMarkingVisitor, 549 JSObject::BodyDescriptor, 550 void> JSObjectVisitor; 551 552 typedef FlexibleBodyVisitor<StaticMarkingVisitor, 553 StructBodyDescriptor, 554 void> StructObjectVisitor; 555 556 static void VisitCode(Map* map, HeapObject* object) { 557 reinterpret_cast<Code*>(object)->CodeIterateBody<StaticMarkingVisitor>( 558 map->heap()); 559 } 560 561 // Code flushing support. 562 563 // How many collections newly compiled code object will survive before being 564 // flushed. 565 static const int kCodeAgeThreshold = 5; 566 567 inline static bool HasSourceCode(Heap* heap, SharedFunctionInfo* info) { 568 Object* undefined = heap->raw_unchecked_undefined_value(); 569 return (info->script() != undefined) && 570 (reinterpret_cast<Script*>(info->script())->source() != undefined); 571 } 572 573 574 inline static bool IsCompiled(JSFunction* function) { 575 return function->unchecked_code() != 576 function->GetIsolate()->builtins()->builtin(Builtins::kLazyCompile); 577 } 578 579 inline static bool IsCompiled(SharedFunctionInfo* function) { 580 return function->unchecked_code() != 581 function->GetIsolate()->builtins()->builtin(Builtins::kLazyCompile); 582 } 583 584 inline static bool IsFlushable(Heap* heap, JSFunction* function) { 585 SharedFunctionInfo* shared_info = function->unchecked_shared(); 586 587 // Code is either on stack, in compilation cache or referenced 588 // by optimized version of function. 589 if (function->unchecked_code()->IsMarked()) { 590 shared_info->set_code_age(0); 591 return false; 592 } 593 594 // We do not flush code for optimized functions. 595 if (function->code() != shared_info->unchecked_code()) { 596 return false; 597 } 598 599 return IsFlushable(heap, shared_info); 600 } 601 602 inline static bool IsFlushable(Heap* heap, SharedFunctionInfo* shared_info) { 603 // Code is either on stack, in compilation cache or referenced 604 // by optimized version of function. 605 if (shared_info->unchecked_code()->IsMarked()) { 606 shared_info->set_code_age(0); 607 return false; 608 } 609 610 // The function must be compiled and have the source code available, 611 // to be able to recompile it in case we need the function again. 612 if (!(shared_info->is_compiled() && HasSourceCode(heap, shared_info))) { 613 return false; 614 } 615 616 // We never flush code for Api functions. 617 Object* function_data = shared_info->function_data(); 618 if (function_data->IsHeapObject() && 619 (SafeMap(function_data)->instance_type() == 620 FUNCTION_TEMPLATE_INFO_TYPE)) { 621 return false; 622 } 623 624 // Only flush code for functions. 625 if (shared_info->code()->kind() != Code::FUNCTION) return false; 626 627 // Function must be lazy compilable. 628 if (!shared_info->allows_lazy_compilation()) return false; 629 630 // If this is a full script wrapped in a function we do no flush the code. 631 if (shared_info->is_toplevel()) return false; 632 633 // Age this shared function info. 634 if (shared_info->code_age() < kCodeAgeThreshold) { 635 shared_info->set_code_age(shared_info->code_age() + 1); 636 return false; 637 } 638 639 return true; 640 } 641 642 643 static bool FlushCodeForFunction(Heap* heap, JSFunction* function) { 644 if (!IsFlushable(heap, function)) return false; 645 646 // This function's code looks flushable. But we have to postpone the 647 // decision until we see all functions that point to the same 648 // SharedFunctionInfo because some of them might be optimized. 649 // That would make the nonoptimized version of the code nonflushable, 650 // because it is required for bailing out from optimized code. 651 heap->mark_compact_collector()->code_flusher()->AddCandidate(function); 652 return true; 653 } 654 655 656 static inline Map* SafeMap(Object* obj) { 657 MapWord map_word = HeapObject::cast(obj)->map_word(); 658 map_word.ClearMark(); 659 map_word.ClearOverflow(); 660 return map_word.ToMap(); 661 } 662 663 664 static inline bool IsJSBuiltinsObject(Object* obj) { 665 return obj->IsHeapObject() && 666 (SafeMap(obj)->instance_type() == JS_BUILTINS_OBJECT_TYPE); 667 } 668 669 670 static inline bool IsValidNotBuiltinContext(Object* ctx) { 671 if (!ctx->IsHeapObject()) return false; 672 673 Map* map = SafeMap(ctx); 674 Heap* heap = map->heap(); 675 if (!(map == heap->raw_unchecked_context_map() || 676 map == heap->raw_unchecked_catch_context_map() || 677 map == heap->raw_unchecked_global_context_map())) { 678 return false; 679 } 680 681 Context* context = reinterpret_cast<Context*>(ctx); 682 683 if (IsJSBuiltinsObject(context->global())) { 684 return false; 685 } 686 687 return true; 688 } 689 690 691 static void VisitSharedFunctionInfoGeneric(Map* map, HeapObject* object) { 692 SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(object); 693 694 if (shared->IsInobjectSlackTrackingInProgress()) shared->DetachInitialMap(); 695 696 FixedBodyVisitor<StaticMarkingVisitor, 697 SharedFunctionInfo::BodyDescriptor, 698 void>::Visit(map, object); 699 } 700 701 702 static void VisitSharedFunctionInfoAndFlushCode(Map* map, 703 HeapObject* object) { 704 MarkCompactCollector* collector = map->heap()->mark_compact_collector(); 705 if (!collector->is_code_flushing_enabled()) { 706 VisitSharedFunctionInfoGeneric(map, object); 707 return; 708 } 709 VisitSharedFunctionInfoAndFlushCodeGeneric(map, object, false); 710 } 711 712 713 static void VisitSharedFunctionInfoAndFlushCodeGeneric( 714 Map* map, HeapObject* object, bool known_flush_code_candidate) { 715 Heap* heap = map->heap(); 716 SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(object); 717 718 if (shared->IsInobjectSlackTrackingInProgress()) shared->DetachInitialMap(); 719 720 if (!known_flush_code_candidate) { 721 known_flush_code_candidate = IsFlushable(heap, shared); 722 if (known_flush_code_candidate) { 723 heap->mark_compact_collector()->code_flusher()->AddCandidate(shared); 724 } 725 } 726 727 VisitSharedFunctionInfoFields(heap, object, known_flush_code_candidate); 728 } 729 730 731 static void VisitCodeEntry(Heap* heap, Address entry_address) { 732 Object* code = Code::GetObjectFromEntryAddress(entry_address); 733 Object* old_code = code; 734 VisitPointer(heap, &code); 735 if (code != old_code) { 736 Memory::Address_at(entry_address) = 737 reinterpret_cast<Code*>(code)->entry(); 738 } 739 } 740 741 742 static void VisitJSFunctionAndFlushCode(Map* map, HeapObject* object) { 743 Heap* heap = map->heap(); 744 MarkCompactCollector* collector = heap->mark_compact_collector(); 745 if (!collector->is_code_flushing_enabled()) { 746 VisitJSFunction(map, object); 747 return; 748 } 749 750 JSFunction* jsfunction = reinterpret_cast<JSFunction*>(object); 751 // The function must have a valid context and not be a builtin. 752 bool flush_code_candidate = false; 753 if (IsValidNotBuiltinContext(jsfunction->unchecked_context())) { 754 flush_code_candidate = FlushCodeForFunction(heap, jsfunction); 755 } 756 757 if (!flush_code_candidate) { 758 collector->MarkObject(jsfunction->unchecked_shared()->unchecked_code()); 759 760 if (jsfunction->unchecked_code()->kind() == Code::OPTIMIZED_FUNCTION) { 761 // For optimized functions we should retain both non-optimized version 762 // of it's code and non-optimized version of all inlined functions. 763 // This is required to support bailing out from inlined code. 764 DeoptimizationInputData* data = 765 reinterpret_cast<DeoptimizationInputData*>( 766 jsfunction->unchecked_code()->unchecked_deoptimization_data()); 767 768 FixedArray* literals = data->UncheckedLiteralArray(); 769 770 for (int i = 0, count = data->InlinedFunctionCount()->value(); 771 i < count; 772 i++) { 773 JSFunction* inlined = reinterpret_cast<JSFunction*>(literals->get(i)); 774 collector->MarkObject(inlined->unchecked_shared()->unchecked_code()); 775 } 776 } 777 } 778 779 VisitJSFunctionFields(map, 780 reinterpret_cast<JSFunction*>(object), 781 flush_code_candidate); 782 } 783 784 785 static void VisitJSFunction(Map* map, HeapObject* object) { 786 VisitJSFunctionFields(map, 787 reinterpret_cast<JSFunction*>(object), 788 false); 789 } 790 791 792 #define SLOT_ADDR(obj, offset) \ 793 reinterpret_cast<Object**>((obj)->address() + offset) 794 795 796 static inline void VisitJSFunctionFields(Map* map, 797 JSFunction* object, 798 bool flush_code_candidate) { 799 Heap* heap = map->heap(); 800 MarkCompactCollector* collector = heap->mark_compact_collector(); 801 802 VisitPointers(heap, 803 SLOT_ADDR(object, JSFunction::kPropertiesOffset), 804 SLOT_ADDR(object, JSFunction::kCodeEntryOffset)); 805 806 if (!flush_code_candidate) { 807 VisitCodeEntry(heap, object->address() + JSFunction::kCodeEntryOffset); 808 } else { 809 // Don't visit code object. 810 811 // Visit shared function info to avoid double checking of it's 812 // flushability. 813 SharedFunctionInfo* shared_info = object->unchecked_shared(); 814 if (!shared_info->IsMarked()) { 815 Map* shared_info_map = shared_info->map(); 816 collector->SetMark(shared_info); 817 collector->MarkObject(shared_info_map); 818 VisitSharedFunctionInfoAndFlushCodeGeneric(shared_info_map, 819 shared_info, 820 true); 821 } 822 } 823 824 VisitPointers(heap, 825 SLOT_ADDR(object, 826 JSFunction::kCodeEntryOffset + kPointerSize), 827 SLOT_ADDR(object, JSFunction::kNonWeakFieldsEndOffset)); 828 829 // Don't visit the next function list field as it is a weak reference. 830 } 831 832 833 static void VisitSharedFunctionInfoFields(Heap* heap, 834 HeapObject* object, 835 bool flush_code_candidate) { 836 VisitPointer(heap, SLOT_ADDR(object, SharedFunctionInfo::kNameOffset)); 837 838 if (!flush_code_candidate) { 839 VisitPointer(heap, SLOT_ADDR(object, SharedFunctionInfo::kCodeOffset)); 840 } 841 842 VisitPointers(heap, 843 SLOT_ADDR(object, SharedFunctionInfo::kScopeInfoOffset), 844 SLOT_ADDR(object, SharedFunctionInfo::kSize)); 845 } 846 847 #undef SLOT_ADDR 848 849 typedef void (*Callback)(Map* map, HeapObject* object); 850 851 static VisitorDispatchTable<Callback> table_; 852 }; 853 854 855 VisitorDispatchTable<StaticMarkingVisitor::Callback> 856 StaticMarkingVisitor::table_; 857 858 859 class MarkingVisitor : public ObjectVisitor { 860 public: 861 explicit MarkingVisitor(Heap* heap) : heap_(heap) { } 862 863 void VisitPointer(Object** p) { 864 StaticMarkingVisitor::VisitPointer(heap_, p); 865 } 866 867 void VisitPointers(Object** start, Object** end) { 868 StaticMarkingVisitor::VisitPointers(heap_, start, end); 869 } 870 871 void VisitCodeTarget(Heap* heap, RelocInfo* rinfo) { 872 StaticMarkingVisitor::VisitCodeTarget(heap, rinfo); 873 } 874 875 void VisitGlobalPropertyCell(Heap* heap, RelocInfo* rinfo) { 876 StaticMarkingVisitor::VisitGlobalPropertyCell(heap, rinfo); 877 } 878 879 void VisitDebugTarget(Heap* heap, RelocInfo* rinfo) { 880 StaticMarkingVisitor::VisitDebugTarget(heap, rinfo); 881 } 882 883 private: 884 Heap* heap_; 885 }; 886 887 888 class CodeMarkingVisitor : public ThreadVisitor { 889 public: 890 explicit CodeMarkingVisitor(MarkCompactCollector* collector) 891 : collector_(collector) {} 892 893 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { 894 for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) { 895 collector_->MarkObject(it.frame()->unchecked_code()); 896 } 897 } 898 899 private: 900 MarkCompactCollector* collector_; 901 }; 902 903 904 class SharedFunctionInfoMarkingVisitor : public ObjectVisitor { 905 public: 906 explicit SharedFunctionInfoMarkingVisitor(MarkCompactCollector* collector) 907 : collector_(collector) {} 908 909 void VisitPointers(Object** start, Object** end) { 910 for (Object** p = start; p < end; p++) VisitPointer(p); 911 } 912 913 void VisitPointer(Object** slot) { 914 Object* obj = *slot; 915 if (obj->IsSharedFunctionInfo()) { 916 SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(obj); 917 collector_->MarkObject(shared->unchecked_code()); 918 collector_->MarkObject(shared); 919 } 920 } 921 922 private: 923 MarkCompactCollector* collector_; 924 }; 925 926 927 void MarkCompactCollector::PrepareForCodeFlushing() { 928 ASSERT(heap() == Isolate::Current()->heap()); 929 930 if (!FLAG_flush_code) { 931 EnableCodeFlushing(false); 932 return; 933 } 934 935 #ifdef ENABLE_DEBUGGER_SUPPORT 936 if (heap()->isolate()->debug()->IsLoaded() || 937 heap()->isolate()->debug()->has_break_points()) { 938 EnableCodeFlushing(false); 939 return; 940 } 941 #endif 942 EnableCodeFlushing(true); 943 944 // Ensure that empty descriptor array is marked. Method MarkDescriptorArray 945 // relies on it being marked before any other descriptor array. 946 MarkObject(heap()->raw_unchecked_empty_descriptor_array()); 947 948 // Make sure we are not referencing the code from the stack. 949 ASSERT(this == heap()->mark_compact_collector()); 950 for (StackFrameIterator it; !it.done(); it.Advance()) { 951 MarkObject(it.frame()->unchecked_code()); 952 } 953 954 // Iterate the archived stacks in all threads to check if 955 // the code is referenced. 956 CodeMarkingVisitor code_marking_visitor(this); 957 heap()->isolate()->thread_manager()->IterateArchivedThreads( 958 &code_marking_visitor); 959 960 SharedFunctionInfoMarkingVisitor visitor(this); 961 heap()->isolate()->compilation_cache()->IterateFunctions(&visitor); 962 heap()->isolate()->handle_scope_implementer()->Iterate(&visitor); 963 964 ProcessMarkingStack(); 965 } 966 967 968 // Visitor class for marking heap roots. 969 class RootMarkingVisitor : public ObjectVisitor { 970 public: 971 explicit RootMarkingVisitor(Heap* heap) 972 : collector_(heap->mark_compact_collector()) { } 973 974 void VisitPointer(Object** p) { 975 MarkObjectByPointer(p); 976 } 977 978 void VisitPointers(Object** start, Object** end) { 979 for (Object** p = start; p < end; p++) MarkObjectByPointer(p); 980 } 981 982 private: 983 void MarkObjectByPointer(Object** p) { 984 if (!(*p)->IsHeapObject()) return; 985 986 // Replace flat cons strings in place. 987 HeapObject* object = ShortCircuitConsString(p); 988 if (object->IsMarked()) return; 989 990 Map* map = object->map(); 991 // Mark the object. 992 collector_->SetMark(object); 993 994 // Mark the map pointer and body, and push them on the marking stack. 995 collector_->MarkObject(map); 996 StaticMarkingVisitor::IterateBody(map, object); 997 998 // Mark all the objects reachable from the map and body. May leave 999 // overflowed objects in the heap. 1000 collector_->EmptyMarkingStack(); 1001 } 1002 1003 MarkCompactCollector* collector_; 1004 }; 1005 1006 1007 // Helper class for pruning the symbol table. 1008 class SymbolTableCleaner : public ObjectVisitor { 1009 public: 1010 explicit SymbolTableCleaner(Heap* heap) 1011 : heap_(heap), pointers_removed_(0) { } 1012 1013 virtual void VisitPointers(Object** start, Object** end) { 1014 // Visit all HeapObject pointers in [start, end). 1015 for (Object** p = start; p < end; p++) { 1016 if ((*p)->IsHeapObject() && !HeapObject::cast(*p)->IsMarked()) { 1017 // Check if the symbol being pruned is an external symbol. We need to 1018 // delete the associated external data as this symbol is going away. 1019 1020 // Since no objects have yet been moved we can safely access the map of 1021 // the object. 1022 if ((*p)->IsExternalString()) { 1023 heap_->FinalizeExternalString(String::cast(*p)); 1024 } 1025 // Set the entry to null_value (as deleted). 1026 *p = heap_->raw_unchecked_null_value(); 1027 pointers_removed_++; 1028 } 1029 } 1030 } 1031 1032 int PointersRemoved() { 1033 return pointers_removed_; 1034 } 1035 private: 1036 Heap* heap_; 1037 int pointers_removed_; 1038 }; 1039 1040 1041 // Implementation of WeakObjectRetainer for mark compact GCs. All marked objects 1042 // are retained. 1043 class MarkCompactWeakObjectRetainer : public WeakObjectRetainer { 1044 public: 1045 virtual Object* RetainAs(Object* object) { 1046 MapWord first_word = HeapObject::cast(object)->map_word(); 1047 if (first_word.IsMarked()) { 1048 return object; 1049 } else { 1050 return NULL; 1051 } 1052 } 1053 }; 1054 1055 1056 void MarkCompactCollector::MarkUnmarkedObject(HeapObject* object) { 1057 ASSERT(!object->IsMarked()); 1058 ASSERT(HEAP->Contains(object)); 1059 if (object->IsMap()) { 1060 Map* map = Map::cast(object); 1061 if (FLAG_cleanup_caches_in_maps_at_gc) { 1062 map->ClearCodeCache(heap()); 1063 } 1064 SetMark(map); 1065 if (FLAG_collect_maps && 1066 map->instance_type() >= FIRST_JS_OBJECT_TYPE && 1067 map->instance_type() <= JS_FUNCTION_TYPE) { 1068 MarkMapContents(map); 1069 } else { 1070 marking_stack_.Push(map); 1071 } 1072 } else { 1073 SetMark(object); 1074 marking_stack_.Push(object); 1075 } 1076 } 1077 1078 1079 void MarkCompactCollector::MarkMapContents(Map* map) { 1080 // Mark prototype transitions array but don't push it into marking stack. 1081 // This will make references from it weak. We will clean dead prototype 1082 // transitions in ClearNonLiveTransitions. 1083 FixedArray* prototype_transitions = map->unchecked_prototype_transitions(); 1084 if (!prototype_transitions->IsMarked()) SetMark(prototype_transitions); 1085 1086 MarkDescriptorArray(reinterpret_cast<DescriptorArray*>( 1087 *HeapObject::RawField(map, Map::kInstanceDescriptorsOffset))); 1088 1089 // Mark the Object* fields of the Map. 1090 // Since the descriptor array has been marked already, it is fine 1091 // that one of these fields contains a pointer to it. 1092 Object** start_slot = HeapObject::RawField(map, 1093 Map::kPointerFieldsBeginOffset); 1094 1095 Object** end_slot = HeapObject::RawField(map, Map::kPointerFieldsEndOffset); 1096 1097 StaticMarkingVisitor::VisitPointers(map->heap(), start_slot, end_slot); 1098 } 1099 1100 1101 void MarkCompactCollector::MarkDescriptorArray( 1102 DescriptorArray* descriptors) { 1103 if (descriptors->IsMarked()) return; 1104 // Empty descriptor array is marked as a root before any maps are marked. 1105 ASSERT(descriptors != HEAP->raw_unchecked_empty_descriptor_array()); 1106 SetMark(descriptors); 1107 1108 FixedArray* contents = reinterpret_cast<FixedArray*>( 1109 descriptors->get(DescriptorArray::kContentArrayIndex)); 1110 ASSERT(contents->IsHeapObject()); 1111 ASSERT(!contents->IsMarked()); 1112 ASSERT(contents->IsFixedArray()); 1113 ASSERT(contents->length() >= 2); 1114 SetMark(contents); 1115 // Contents contains (value, details) pairs. If the details say that the type 1116 // of descriptor is MAP_TRANSITION, CONSTANT_TRANSITION, 1117 // EXTERNAL_ARRAY_TRANSITION or NULL_DESCRIPTOR, we don't mark the value as 1118 // live. Only for MAP_TRANSITION, EXTERNAL_ARRAY_TRANSITION and 1119 // CONSTANT_TRANSITION is the value an Object* (a Map*). 1120 for (int i = 0; i < contents->length(); i += 2) { 1121 // If the pair (value, details) at index i, i+1 is not 1122 // a transition or null descriptor, mark the value. 1123 PropertyDetails details(Smi::cast(contents->get(i + 1))); 1124 if (details.type() < FIRST_PHANTOM_PROPERTY_TYPE) { 1125 HeapObject* object = reinterpret_cast<HeapObject*>(contents->get(i)); 1126 if (object->IsHeapObject() && !object->IsMarked()) { 1127 SetMark(object); 1128 marking_stack_.Push(object); 1129 } 1130 } 1131 } 1132 // The DescriptorArray descriptors contains a pointer to its contents array, 1133 // but the contents array is already marked. 1134 marking_stack_.Push(descriptors); 1135 } 1136 1137 1138 void MarkCompactCollector::CreateBackPointers() { 1139 HeapObjectIterator iterator(heap()->map_space()); 1140 for (HeapObject* next_object = iterator.next(); 1141 next_object != NULL; next_object = iterator.next()) { 1142 if (next_object->IsMap()) { // Could also be ByteArray on free list. 1143 Map* map = Map::cast(next_object); 1144 if (map->instance_type() >= FIRST_JS_OBJECT_TYPE && 1145 map->instance_type() <= JS_FUNCTION_TYPE) { 1146 map->CreateBackPointers(); 1147 } else { 1148 ASSERT(map->instance_descriptors() == heap()->empty_descriptor_array()); 1149 } 1150 } 1151 } 1152 } 1153 1154 1155 static int OverflowObjectSize(HeapObject* obj) { 1156 // Recover the normal map pointer, it might be marked as live and 1157 // overflowed. 1158 MapWord map_word = obj->map_word(); 1159 map_word.ClearMark(); 1160 map_word.ClearOverflow(); 1161 return obj->SizeFromMap(map_word.ToMap()); 1162 } 1163 1164 1165 class OverflowedObjectsScanner : public AllStatic { 1166 public: 1167 // Fill the marking stack with overflowed objects returned by the given 1168 // iterator. Stop when the marking stack is filled or the end of the space 1169 // is reached, whichever comes first. 1170 template<class T> 1171 static inline void ScanOverflowedObjects(MarkCompactCollector* collector, 1172 T* it) { 1173 // The caller should ensure that the marking stack is initially not full, 1174 // so that we don't waste effort pointlessly scanning for objects. 1175 ASSERT(!collector->marking_stack_.is_full()); 1176 1177 for (HeapObject* object = it->next(); object != NULL; object = it->next()) { 1178 if (object->IsOverflowed()) { 1179 object->ClearOverflow(); 1180 ASSERT(object->IsMarked()); 1181 ASSERT(HEAP->Contains(object)); 1182 collector->marking_stack_.Push(object); 1183 if (collector->marking_stack_.is_full()) return; 1184 } 1185 } 1186 } 1187 }; 1188 1189 1190 bool MarkCompactCollector::IsUnmarkedHeapObject(Object** p) { 1191 return (*p)->IsHeapObject() && !HeapObject::cast(*p)->IsMarked(); 1192 } 1193 1194 1195 void MarkCompactCollector::MarkSymbolTable() { 1196 SymbolTable* symbol_table = heap()->raw_unchecked_symbol_table(); 1197 // Mark the symbol table itself. 1198 SetMark(symbol_table); 1199 // Explicitly mark the prefix. 1200 MarkingVisitor marker(heap()); 1201 symbol_table->IteratePrefix(&marker); 1202 ProcessMarkingStack(); 1203 } 1204 1205 1206 void MarkCompactCollector::MarkRoots(RootMarkingVisitor* visitor) { 1207 // Mark the heap roots including global variables, stack variables, 1208 // etc., and all objects reachable from them. 1209 heap()->IterateStrongRoots(visitor, VISIT_ONLY_STRONG); 1210 1211 // Handle the symbol table specially. 1212 MarkSymbolTable(); 1213 1214 // There may be overflowed objects in the heap. Visit them now. 1215 while (marking_stack_.overflowed()) { 1216 RefillMarkingStack(); 1217 EmptyMarkingStack(); 1218 } 1219 } 1220 1221 1222 void MarkCompactCollector::MarkObjectGroups() { 1223 List<ObjectGroup*>* object_groups = 1224 heap()->isolate()->global_handles()->object_groups(); 1225 1226 int last = 0; 1227 for (int i = 0; i < object_groups->length(); i++) { 1228 ObjectGroup* entry = object_groups->at(i); 1229 ASSERT(entry != NULL); 1230 1231 Object*** objects = entry->objects_; 1232 bool group_marked = false; 1233 for (size_t j = 0; j < entry->length_; j++) { 1234 Object* object = *objects[j]; 1235 if (object->IsHeapObject() && HeapObject::cast(object)->IsMarked()) { 1236 group_marked = true; 1237 break; 1238 } 1239 } 1240 1241 if (!group_marked) { 1242 (*object_groups)[last++] = entry; 1243 continue; 1244 } 1245 1246 // An object in the group is marked, so mark all heap objects in 1247 // the group. 1248 for (size_t j = 0; j < entry->length_; ++j) { 1249 if ((*objects[j])->IsHeapObject()) { 1250 MarkObject(HeapObject::cast(*objects[j])); 1251 } 1252 } 1253 1254 // Once the entire group has been marked, dispose it because it's 1255 // not needed anymore. 1256 entry->Dispose(); 1257 } 1258 object_groups->Rewind(last); 1259 } 1260 1261 1262 void MarkCompactCollector::MarkImplicitRefGroups() { 1263 List<ImplicitRefGroup*>* ref_groups = 1264 heap()->isolate()->global_handles()->implicit_ref_groups(); 1265 1266 int last = 0; 1267 for (int i = 0; i < ref_groups->length(); i++) { 1268 ImplicitRefGroup* entry = ref_groups->at(i); 1269 ASSERT(entry != NULL); 1270 1271 if (!(*entry->parent_)->IsMarked()) { 1272 (*ref_groups)[last++] = entry; 1273 continue; 1274 } 1275 1276 Object*** children = entry->children_; 1277 // A parent object is marked, so mark all child heap objects. 1278 for (size_t j = 0; j < entry->length_; ++j) { 1279 if ((*children[j])->IsHeapObject()) { 1280 MarkObject(HeapObject::cast(*children[j])); 1281 } 1282 } 1283 1284 // Once the entire group has been marked, dispose it because it's 1285 // not needed anymore. 1286 entry->Dispose(); 1287 } 1288 ref_groups->Rewind(last); 1289 } 1290 1291 1292 // Mark all objects reachable from the objects on the marking stack. 1293 // Before: the marking stack contains zero or more heap object pointers. 1294 // After: the marking stack is empty, and all objects reachable from the 1295 // marking stack have been marked, or are overflowed in the heap. 1296 void MarkCompactCollector::EmptyMarkingStack() { 1297 while (!marking_stack_.is_empty()) { 1298 HeapObject* object = marking_stack_.Pop(); 1299 ASSERT(object->IsHeapObject()); 1300 ASSERT(heap()->Contains(object)); 1301 ASSERT(object->IsMarked()); 1302 ASSERT(!object->IsOverflowed()); 1303 1304 // Because the object is marked, we have to recover the original map 1305 // pointer and use it to mark the object's body. 1306 MapWord map_word = object->map_word(); 1307 map_word.ClearMark(); 1308 Map* map = map_word.ToMap(); 1309 MarkObject(map); 1310 1311 StaticMarkingVisitor::IterateBody(map, object); 1312 } 1313 } 1314 1315 1316 // Sweep the heap for overflowed objects, clear their overflow bits, and 1317 // push them on the marking stack. Stop early if the marking stack fills 1318 // before sweeping completes. If sweeping completes, there are no remaining 1319 // overflowed objects in the heap so the overflow flag on the markings stack 1320 // is cleared. 1321 void MarkCompactCollector::RefillMarkingStack() { 1322 ASSERT(marking_stack_.overflowed()); 1323 1324 SemiSpaceIterator new_it(heap()->new_space(), &OverflowObjectSize); 1325 OverflowedObjectsScanner::ScanOverflowedObjects(this, &new_it); 1326 if (marking_stack_.is_full()) return; 1327 1328 HeapObjectIterator old_pointer_it(heap()->old_pointer_space(), 1329 &OverflowObjectSize); 1330 OverflowedObjectsScanner::ScanOverflowedObjects(this, &old_pointer_it); 1331 if (marking_stack_.is_full()) return; 1332 1333 HeapObjectIterator old_data_it(heap()->old_data_space(), &OverflowObjectSize); 1334 OverflowedObjectsScanner::ScanOverflowedObjects(this, &old_data_it); 1335 if (marking_stack_.is_full()) return; 1336 1337 HeapObjectIterator code_it(heap()->code_space(), &OverflowObjectSize); 1338 OverflowedObjectsScanner::ScanOverflowedObjects(this, &code_it); 1339 if (marking_stack_.is_full()) return; 1340 1341 HeapObjectIterator map_it(heap()->map_space(), &OverflowObjectSize); 1342 OverflowedObjectsScanner::ScanOverflowedObjects(this, &map_it); 1343 if (marking_stack_.is_full()) return; 1344 1345 HeapObjectIterator cell_it(heap()->cell_space(), &OverflowObjectSize); 1346 OverflowedObjectsScanner::ScanOverflowedObjects(this, &cell_it); 1347 if (marking_stack_.is_full()) return; 1348 1349 LargeObjectIterator lo_it(heap()->lo_space(), &OverflowObjectSize); 1350 OverflowedObjectsScanner::ScanOverflowedObjects(this, &lo_it); 1351 if (marking_stack_.is_full()) return; 1352 1353 marking_stack_.clear_overflowed(); 1354 } 1355 1356 1357 // Mark all objects reachable (transitively) from objects on the marking 1358 // stack. Before: the marking stack contains zero or more heap object 1359 // pointers. After: the marking stack is empty and there are no overflowed 1360 // objects in the heap. 1361 void MarkCompactCollector::ProcessMarkingStack() { 1362 EmptyMarkingStack(); 1363 while (marking_stack_.overflowed()) { 1364 RefillMarkingStack(); 1365 EmptyMarkingStack(); 1366 } 1367 } 1368 1369 1370 void MarkCompactCollector::ProcessExternalMarking() { 1371 bool work_to_do = true; 1372 ASSERT(marking_stack_.is_empty()); 1373 while (work_to_do) { 1374 MarkObjectGroups(); 1375 MarkImplicitRefGroups(); 1376 work_to_do = !marking_stack_.is_empty(); 1377 ProcessMarkingStack(); 1378 } 1379 } 1380 1381 1382 void MarkCompactCollector::MarkLiveObjects() { 1383 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_MARK); 1384 // The recursive GC marker detects when it is nearing stack overflow, 1385 // and switches to a different marking system. JS interrupts interfere 1386 // with the C stack limit check. 1387 PostponeInterruptsScope postpone(heap()->isolate()); 1388 1389 #ifdef DEBUG 1390 ASSERT(state_ == PREPARE_GC); 1391 state_ = MARK_LIVE_OBJECTS; 1392 #endif 1393 // The to space contains live objects, the from space is used as a marking 1394 // stack. 1395 marking_stack_.Initialize(heap()->new_space()->FromSpaceLow(), 1396 heap()->new_space()->FromSpaceHigh()); 1397 1398 ASSERT(!marking_stack_.overflowed()); 1399 1400 PrepareForCodeFlushing(); 1401 1402 RootMarkingVisitor root_visitor(heap()); 1403 MarkRoots(&root_visitor); 1404 1405 // The objects reachable from the roots are marked, yet unreachable 1406 // objects are unmarked. Mark objects reachable due to host 1407 // application specific logic. 1408 ProcessExternalMarking(); 1409 1410 // The objects reachable from the roots or object groups are marked, 1411 // yet unreachable objects are unmarked. Mark objects reachable 1412 // only from weak global handles. 1413 // 1414 // First we identify nonlive weak handles and mark them as pending 1415 // destruction. 1416 heap()->isolate()->global_handles()->IdentifyWeakHandles( 1417 &IsUnmarkedHeapObject); 1418 // Then we mark the objects and process the transitive closure. 1419 heap()->isolate()->global_handles()->IterateWeakRoots(&root_visitor); 1420 while (marking_stack_.overflowed()) { 1421 RefillMarkingStack(); 1422 EmptyMarkingStack(); 1423 } 1424 1425 // Repeat host application specific marking to mark unmarked objects 1426 // reachable from the weak roots. 1427 ProcessExternalMarking(); 1428 1429 // Prune the symbol table removing all symbols only pointed to by the 1430 // symbol table. Cannot use symbol_table() here because the symbol 1431 // table is marked. 1432 SymbolTable* symbol_table = heap()->raw_unchecked_symbol_table(); 1433 SymbolTableCleaner v(heap()); 1434 symbol_table->IterateElements(&v); 1435 symbol_table->ElementsRemoved(v.PointersRemoved()); 1436 heap()->external_string_table_.Iterate(&v); 1437 heap()->external_string_table_.CleanUp(); 1438 1439 // Process the weak references. 1440 MarkCompactWeakObjectRetainer mark_compact_object_retainer; 1441 heap()->ProcessWeakReferences(&mark_compact_object_retainer); 1442 1443 // Remove object groups after marking phase. 1444 heap()->isolate()->global_handles()->RemoveObjectGroups(); 1445 heap()->isolate()->global_handles()->RemoveImplicitRefGroups(); 1446 1447 // Flush code from collected candidates. 1448 if (is_code_flushing_enabled()) { 1449 code_flusher_->ProcessCandidates(); 1450 } 1451 1452 // Clean up dead objects from the runtime profiler. 1453 heap()->isolate()->runtime_profiler()->RemoveDeadSamples(); 1454 } 1455 1456 1457 #ifdef DEBUG 1458 void MarkCompactCollector::UpdateLiveObjectCount(HeapObject* obj) { 1459 live_bytes_ += obj->Size(); 1460 if (heap()->new_space()->Contains(obj)) { 1461 live_young_objects_size_ += obj->Size(); 1462 } else if (heap()->map_space()->Contains(obj)) { 1463 ASSERT(obj->IsMap()); 1464 live_map_objects_size_ += obj->Size(); 1465 } else if (heap()->cell_space()->Contains(obj)) { 1466 ASSERT(obj->IsJSGlobalPropertyCell()); 1467 live_cell_objects_size_ += obj->Size(); 1468 } else if (heap()->old_pointer_space()->Contains(obj)) { 1469 live_old_pointer_objects_size_ += obj->Size(); 1470 } else if (heap()->old_data_space()->Contains(obj)) { 1471 live_old_data_objects_size_ += obj->Size(); 1472 } else if (heap()->code_space()->Contains(obj)) { 1473 live_code_objects_size_ += obj->Size(); 1474 } else if (heap()->lo_space()->Contains(obj)) { 1475 live_lo_objects_size_ += obj->Size(); 1476 } else { 1477 UNREACHABLE(); 1478 } 1479 } 1480 #endif // DEBUG 1481 1482 1483 void MarkCompactCollector::SweepLargeObjectSpace() { 1484 #ifdef DEBUG 1485 ASSERT(state_ == MARK_LIVE_OBJECTS); 1486 state_ = 1487 compacting_collection_ ? ENCODE_FORWARDING_ADDRESSES : SWEEP_SPACES; 1488 #endif 1489 // Deallocate unmarked objects and clear marked bits for marked objects. 1490 heap()->lo_space()->FreeUnmarkedObjects(); 1491 } 1492 1493 1494 // Safe to use during marking phase only. 1495 bool MarkCompactCollector::SafeIsMap(HeapObject* object) { 1496 MapWord metamap = object->map_word(); 1497 metamap.ClearMark(); 1498 return metamap.ToMap()->instance_type() == MAP_TYPE; 1499 } 1500 1501 1502 void MarkCompactCollector::ClearNonLiveTransitions() { 1503 HeapObjectIterator map_iterator(heap()->map_space(), &SizeOfMarkedObject); 1504 // Iterate over the map space, setting map transitions that go from 1505 // a marked map to an unmarked map to null transitions. At the same time, 1506 // set all the prototype fields of maps back to their original value, 1507 // dropping the back pointers temporarily stored in the prototype field. 1508 // Setting the prototype field requires following the linked list of 1509 // back pointers, reversing them all at once. This allows us to find 1510 // those maps with map transitions that need to be nulled, and only 1511 // scan the descriptor arrays of those maps, not all maps. 1512 // All of these actions are carried out only on maps of JSObjects 1513 // and related subtypes. 1514 for (HeapObject* obj = map_iterator.next(); 1515 obj != NULL; obj = map_iterator.next()) { 1516 Map* map = reinterpret_cast<Map*>(obj); 1517 if (!map->IsMarked() && map->IsByteArray()) continue; 1518 1519 ASSERT(SafeIsMap(map)); 1520 // Only JSObject and subtypes have map transitions and back pointers. 1521 if (map->instance_type() < FIRST_JS_OBJECT_TYPE) continue; 1522 if (map->instance_type() > JS_FUNCTION_TYPE) continue; 1523 1524 if (map->IsMarked() && map->attached_to_shared_function_info()) { 1525 // This map is used for inobject slack tracking and has been detached 1526 // from SharedFunctionInfo during the mark phase. 1527 // Since it survived the GC, reattach it now. 1528 map->unchecked_constructor()->unchecked_shared()->AttachInitialMap(map); 1529 } 1530 1531 // Clear dead prototype transitions. 1532 FixedArray* prototype_transitions = map->unchecked_prototype_transitions(); 1533 if (prototype_transitions->length() > 0) { 1534 int finger = Smi::cast(prototype_transitions->get(0))->value(); 1535 int new_finger = 1; 1536 for (int i = 1; i < finger; i += 2) { 1537 Object* prototype = prototype_transitions->get(i); 1538 Object* cached_map = prototype_transitions->get(i + 1); 1539 if (HeapObject::cast(prototype)->IsMarked() && 1540 HeapObject::cast(cached_map)->IsMarked()) { 1541 if (new_finger != i) { 1542 prototype_transitions->set_unchecked(heap_, 1543 new_finger, 1544 prototype, 1545 UPDATE_WRITE_BARRIER); 1546 prototype_transitions->set_unchecked(heap_, 1547 new_finger + 1, 1548 cached_map, 1549 SKIP_WRITE_BARRIER); 1550 } 1551 new_finger += 2; 1552 } 1553 } 1554 1555 // Fill slots that became free with undefined value. 1556 Object* undefined = heap()->raw_unchecked_undefined_value(); 1557 for (int i = new_finger; i < finger; i++) { 1558 prototype_transitions->set_unchecked(heap_, 1559 i, 1560 undefined, 1561 SKIP_WRITE_BARRIER); 1562 } 1563 prototype_transitions->set_unchecked(0, Smi::FromInt(new_finger)); 1564 } 1565 1566 // Follow the chain of back pointers to find the prototype. 1567 Map* current = map; 1568 while (SafeIsMap(current)) { 1569 current = reinterpret_cast<Map*>(current->prototype()); 1570 ASSERT(current->IsHeapObject()); 1571 } 1572 Object* real_prototype = current; 1573 1574 // Follow back pointers, setting them to prototype, 1575 // clearing map transitions when necessary. 1576 current = map; 1577 bool on_dead_path = !current->IsMarked(); 1578 Object* next; 1579 while (SafeIsMap(current)) { 1580 next = current->prototype(); 1581 // There should never be a dead map above a live map. 1582 ASSERT(on_dead_path || current->IsMarked()); 1583 1584 // A live map above a dead map indicates a dead transition. 1585 // This test will always be false on the first iteration. 1586 if (on_dead_path && current->IsMarked()) { 1587 on_dead_path = false; 1588 current->ClearNonLiveTransitions(heap(), real_prototype); 1589 } 1590 *HeapObject::RawField(current, Map::kPrototypeOffset) = 1591 real_prototype; 1592 current = reinterpret_cast<Map*>(next); 1593 } 1594 } 1595 } 1596 1597 // ------------------------------------------------------------------------- 1598 // Phase 2: Encode forwarding addresses. 1599 // When compacting, forwarding addresses for objects in old space and map 1600 // space are encoded in their map pointer word (along with an encoding of 1601 // their map pointers). 1602 // 1603 // The excact encoding is described in the comments for class MapWord in 1604 // objects.h. 1605 // 1606 // An address range [start, end) can have both live and non-live objects. 1607 // Maximal non-live regions are marked so they can be skipped on subsequent 1608 // sweeps of the heap. A distinguished map-pointer encoding is used to mark 1609 // free regions of one-word size (in which case the next word is the start 1610 // of a live object). A second distinguished map-pointer encoding is used 1611 // to mark free regions larger than one word, and the size of the free 1612 // region (including the first word) is written to the second word of the 1613 // region. 1614 // 1615 // Any valid map page offset must lie in the object area of the page, so map 1616 // page offsets less than Page::kObjectStartOffset are invalid. We use a 1617 // pair of distinguished invalid map encodings (for single word and multiple 1618 // words) to indicate free regions in the page found during computation of 1619 // forwarding addresses and skipped over in subsequent sweeps. 1620 1621 1622 // Encode a free region, defined by the given start address and size, in the 1623 // first word or two of the region. 1624 void EncodeFreeRegion(Address free_start, int free_size) { 1625 ASSERT(free_size >= kIntSize); 1626 if (free_size == kIntSize) { 1627 Memory::uint32_at(free_start) = MarkCompactCollector::kSingleFreeEncoding; 1628 } else { 1629 ASSERT(free_size >= 2 * kIntSize); 1630 Memory::uint32_at(free_start) = MarkCompactCollector::kMultiFreeEncoding; 1631 Memory::int_at(free_start + kIntSize) = free_size; 1632 } 1633 1634 #ifdef DEBUG 1635 // Zap the body of the free region. 1636 if (FLAG_enable_slow_asserts) { 1637 for (int offset = 2 * kIntSize; 1638 offset < free_size; 1639 offset += kPointerSize) { 1640 Memory::Address_at(free_start + offset) = kZapValue; 1641 } 1642 } 1643 #endif 1644 } 1645 1646 1647 // Try to promote all objects in new space. Heap numbers and sequential 1648 // strings are promoted to the code space, large objects to large object space, 1649 // and all others to the old space. 1650 inline MaybeObject* MCAllocateFromNewSpace(Heap* heap, 1651 HeapObject* object, 1652 int object_size) { 1653 MaybeObject* forwarded; 1654 if (object_size > heap->MaxObjectSizeInPagedSpace()) { 1655 forwarded = Failure::Exception(); 1656 } else { 1657 OldSpace* target_space = heap->TargetSpace(object); 1658 ASSERT(target_space == heap->old_pointer_space() || 1659 target_space == heap->old_data_space()); 1660 forwarded = target_space->MCAllocateRaw(object_size); 1661 } 1662 Object* result; 1663 if (!forwarded->ToObject(&result)) { 1664 result = heap->new_space()->MCAllocateRaw(object_size)->ToObjectUnchecked(); 1665 } 1666 return result; 1667 } 1668 1669 1670 // Allocation functions for the paged spaces call the space's MCAllocateRaw. 1671 MUST_USE_RESULT inline MaybeObject* MCAllocateFromOldPointerSpace( 1672 Heap *heap, 1673 HeapObject* ignore, 1674 int object_size) { 1675 return heap->old_pointer_space()->MCAllocateRaw(object_size); 1676 } 1677 1678 1679 MUST_USE_RESULT inline MaybeObject* MCAllocateFromOldDataSpace( 1680 Heap* heap, 1681 HeapObject* ignore, 1682 int object_size) { 1683 return heap->old_data_space()->MCAllocateRaw(object_size); 1684 } 1685 1686 1687 MUST_USE_RESULT inline MaybeObject* MCAllocateFromCodeSpace( 1688 Heap* heap, 1689 HeapObject* ignore, 1690 int object_size) { 1691 return heap->code_space()->MCAllocateRaw(object_size); 1692 } 1693 1694 1695 MUST_USE_RESULT inline MaybeObject* MCAllocateFromMapSpace( 1696 Heap* heap, 1697 HeapObject* ignore, 1698 int object_size) { 1699 return heap->map_space()->MCAllocateRaw(object_size); 1700 } 1701 1702 1703 MUST_USE_RESULT inline MaybeObject* MCAllocateFromCellSpace( 1704 Heap* heap, HeapObject* ignore, int object_size) { 1705 return heap->cell_space()->MCAllocateRaw(object_size); 1706 } 1707 1708 1709 // The forwarding address is encoded at the same offset as the current 1710 // to-space object, but in from space. 1711 inline void EncodeForwardingAddressInNewSpace(Heap* heap, 1712 HeapObject* old_object, 1713 int object_size, 1714 Object* new_object, 1715 int* ignored) { 1716 int offset = 1717 heap->new_space()->ToSpaceOffsetForAddress(old_object->address()); 1718 Memory::Address_at(heap->new_space()->FromSpaceLow() + offset) = 1719 HeapObject::cast(new_object)->address(); 1720 } 1721 1722 1723 // The forwarding address is encoded in the map pointer of the object as an 1724 // offset (in terms of live bytes) from the address of the first live object 1725 // in the page. 1726 inline void EncodeForwardingAddressInPagedSpace(Heap* heap, 1727 HeapObject* old_object, 1728 int object_size, 1729 Object* new_object, 1730 int* offset) { 1731 // Record the forwarding address of the first live object if necessary. 1732 if (*offset == 0) { 1733 Page::FromAddress(old_object->address())->mc_first_forwarded = 1734 HeapObject::cast(new_object)->address(); 1735 } 1736 1737 MapWord encoding = 1738 MapWord::EncodeAddress(old_object->map()->address(), *offset); 1739 old_object->set_map_word(encoding); 1740 *offset += object_size; 1741 ASSERT(*offset <= Page::kObjectAreaSize); 1742 } 1743 1744 1745 // Most non-live objects are ignored. 1746 inline void IgnoreNonLiveObject(HeapObject* object, Isolate* isolate) {} 1747 1748 1749 // Function template that, given a range of addresses (eg, a semispace or a 1750 // paged space page), iterates through the objects in the range to clear 1751 // mark bits and compute and encode forwarding addresses. As a side effect, 1752 // maximal free chunks are marked so that they can be skipped on subsequent 1753 // sweeps. 1754 // 1755 // The template parameters are an allocation function, a forwarding address 1756 // encoding function, and a function to process non-live objects. 1757 template<MarkCompactCollector::AllocationFunction Alloc, 1758 MarkCompactCollector::EncodingFunction Encode, 1759 MarkCompactCollector::ProcessNonLiveFunction ProcessNonLive> 1760 inline void EncodeForwardingAddressesInRange(MarkCompactCollector* collector, 1761 Address start, 1762 Address end, 1763 int* offset) { 1764 // The start address of the current free region while sweeping the space. 1765 // This address is set when a transition from live to non-live objects is 1766 // encountered. A value (an encoding of the 'next free region' pointer) 1767 // is written to memory at this address when a transition from non-live to 1768 // live objects is encountered. 1769 Address free_start = NULL; 1770 1771 // A flag giving the state of the previously swept object. Initially true 1772 // to ensure that free_start is initialized to a proper address before 1773 // trying to write to it. 1774 bool is_prev_alive = true; 1775 1776 int object_size; // Will be set on each iteration of the loop. 1777 for (Address current = start; current < end; current += object_size) { 1778 HeapObject* object = HeapObject::FromAddress(current); 1779 if (object->IsMarked()) { 1780 object->ClearMark(); 1781 collector->tracer()->decrement_marked_count(); 1782 object_size = object->Size(); 1783 1784 Object* forwarded = 1785 Alloc(collector->heap(), object, object_size)->ToObjectUnchecked(); 1786 Encode(collector->heap(), object, object_size, forwarded, offset); 1787 1788 #ifdef DEBUG 1789 if (FLAG_gc_verbose) { 1790 PrintF("forward %p -> %p.\n", object->address(), 1791 HeapObject::cast(forwarded)->address()); 1792 } 1793 #endif 1794 if (!is_prev_alive) { // Transition from non-live to live. 1795 EncodeFreeRegion(free_start, static_cast<int>(current - free_start)); 1796 is_prev_alive = true; 1797 } 1798 } else { // Non-live object. 1799 object_size = object->Size(); 1800 ProcessNonLive(object, collector->heap()->isolate()); 1801 if (is_prev_alive) { // Transition from live to non-live. 1802 free_start = current; 1803 is_prev_alive = false; 1804 } 1805 LiveObjectList::ProcessNonLive(object); 1806 } 1807 } 1808 1809 // If we ended on a free region, mark it. 1810 if (!is_prev_alive) { 1811 EncodeFreeRegion(free_start, static_cast<int>(end - free_start)); 1812 } 1813 } 1814 1815 1816 // Functions to encode the forwarding pointers in each compactable space. 1817 void MarkCompactCollector::EncodeForwardingAddressesInNewSpace() { 1818 int ignored; 1819 EncodeForwardingAddressesInRange<MCAllocateFromNewSpace, 1820 EncodeForwardingAddressInNewSpace, 1821 IgnoreNonLiveObject>( 1822 this, 1823 heap()->new_space()->bottom(), 1824 heap()->new_space()->top(), 1825 &ignored); 1826 } 1827 1828 1829 template<MarkCompactCollector::AllocationFunction Alloc, 1830 MarkCompactCollector::ProcessNonLiveFunction ProcessNonLive> 1831 void MarkCompactCollector::EncodeForwardingAddressesInPagedSpace( 1832 PagedSpace* space) { 1833 PageIterator it(space, PageIterator::PAGES_IN_USE); 1834 while (it.has_next()) { 1835 Page* p = it.next(); 1836 1837 // The offset of each live object in the page from the first live object 1838 // in the page. 1839 int offset = 0; 1840 EncodeForwardingAddressesInRange<Alloc, 1841 EncodeForwardingAddressInPagedSpace, 1842 ProcessNonLive>( 1843 this, 1844 p->ObjectAreaStart(), 1845 p->AllocationTop(), 1846 &offset); 1847 } 1848 } 1849 1850 1851 // We scavange new space simultaneously with sweeping. This is done in two 1852 // passes. 1853 // The first pass migrates all alive objects from one semispace to another or 1854 // promotes them to old space. Forwading address is written directly into 1855 // first word of object without any encoding. If object is dead we are writing 1856 // NULL as a forwarding address. 1857 // The second pass updates pointers to new space in all spaces. It is possible 1858 // to encounter pointers to dead objects during traversal of dirty regions we 1859 // should clear them to avoid encountering them during next dirty regions 1860 // iteration. 1861 static void MigrateObject(Heap* heap, 1862 Address dst, 1863 Address src, 1864 int size, 1865 bool to_old_space) { 1866 if (to_old_space) { 1867 heap->CopyBlockToOldSpaceAndUpdateRegionMarks(dst, src, size); 1868 } else { 1869 heap->CopyBlock(dst, src, size); 1870 } 1871 1872 Memory::Address_at(src) = dst; 1873 } 1874 1875 1876 class StaticPointersToNewGenUpdatingVisitor : public 1877 StaticNewSpaceVisitor<StaticPointersToNewGenUpdatingVisitor> { 1878 public: 1879 static inline void VisitPointer(Heap* heap, Object** p) { 1880 if (!(*p)->IsHeapObject()) return; 1881 1882 HeapObject* obj = HeapObject::cast(*p); 1883 Address old_addr = obj->address(); 1884 1885 if (heap->new_space()->Contains(obj)) { 1886 ASSERT(heap->InFromSpace(*p)); 1887 *p = HeapObject::FromAddress(Memory::Address_at(old_addr)); 1888 } 1889 } 1890 }; 1891 1892 1893 // Visitor for updating pointers from live objects in old spaces to new space. 1894 // It does not expect to encounter pointers to dead objects. 1895 class PointersToNewGenUpdatingVisitor: public ObjectVisitor { 1896 public: 1897 explicit PointersToNewGenUpdatingVisitor(Heap* heap) : heap_(heap) { } 1898 1899 void VisitPointer(Object** p) { 1900 StaticPointersToNewGenUpdatingVisitor::VisitPointer(heap_, p); 1901 } 1902 1903 void VisitPointers(Object** start, Object** end) { 1904 for (Object** p = start; p < end; p++) { 1905 StaticPointersToNewGenUpdatingVisitor::VisitPointer(heap_, p); 1906 } 1907 } 1908 1909 void VisitCodeTarget(RelocInfo* rinfo) { 1910 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); 1911 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); 1912 VisitPointer(&target); 1913 rinfo->set_target_address(Code::cast(target)->instruction_start()); 1914 } 1915 1916 void VisitDebugTarget(RelocInfo* rinfo) { 1917 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) && 1918 rinfo->IsPatchedReturnSequence()) || 1919 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && 1920 rinfo->IsPatchedDebugBreakSlotSequence())); 1921 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address()); 1922 VisitPointer(&target); 1923 rinfo->set_call_address(Code::cast(target)->instruction_start()); 1924 } 1925 private: 1926 Heap* heap_; 1927 }; 1928 1929 1930 // Visitor for updating pointers from live objects in old spaces to new space. 1931 // It can encounter pointers to dead objects in new space when traversing map 1932 // space (see comment for MigrateObject). 1933 static void UpdatePointerToNewGen(HeapObject** p) { 1934 if (!(*p)->IsHeapObject()) return; 1935 1936 Address old_addr = (*p)->address(); 1937 ASSERT(HEAP->InFromSpace(*p)); 1938 1939 Address new_addr = Memory::Address_at(old_addr); 1940 1941 if (new_addr == NULL) { 1942 // We encountered pointer to a dead object. Clear it so we will 1943 // not visit it again during next iteration of dirty regions. 1944 *p = NULL; 1945 } else { 1946 *p = HeapObject::FromAddress(new_addr); 1947 } 1948 } 1949 1950 1951 static String* UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap, 1952 Object** p) { 1953 Address old_addr = HeapObject::cast(*p)->address(); 1954 Address new_addr = Memory::Address_at(old_addr); 1955 return String::cast(HeapObject::FromAddress(new_addr)); 1956 } 1957 1958 1959 static bool TryPromoteObject(Heap* heap, HeapObject* object, int object_size) { 1960 Object* result; 1961 1962 if (object_size > heap->MaxObjectSizeInPagedSpace()) { 1963 MaybeObject* maybe_result = 1964 heap->lo_space()->AllocateRawFixedArray(object_size); 1965 if (maybe_result->ToObject(&result)) { 1966 HeapObject* target = HeapObject::cast(result); 1967 MigrateObject(heap, target->address(), object->address(), object_size, 1968 true); 1969 heap->mark_compact_collector()->tracer()-> 1970 increment_promoted_objects_size(object_size); 1971 return true; 1972 } 1973 } else { 1974 OldSpace* target_space = heap->TargetSpace(object); 1975 1976 ASSERT(target_space == heap->old_pointer_space() || 1977 target_space == heap->old_data_space()); 1978 MaybeObject* maybe_result = target_space->AllocateRaw(object_size); 1979 if (maybe_result->ToObject(&result)) { 1980 HeapObject* target = HeapObject::cast(result); 1981 MigrateObject(heap, 1982 target->address(), 1983 object->address(), 1984 object_size, 1985 target_space == heap->old_pointer_space()); 1986 heap->mark_compact_collector()->tracer()-> 1987 increment_promoted_objects_size(object_size); 1988 return true; 1989 } 1990 } 1991 1992 return false; 1993 } 1994 1995 1996 static void SweepNewSpace(Heap* heap, NewSpace* space) { 1997 heap->CheckNewSpaceExpansionCriteria(); 1998 1999 Address from_bottom = space->bottom(); 2000 Address from_top = space->top(); 2001 2002 // Flip the semispaces. After flipping, to space is empty, from space has 2003 // live objects. 2004 space->Flip(); 2005 space->ResetAllocationInfo(); 2006 2007 int size = 0; 2008 int survivors_size = 0; 2009 2010 // First pass: traverse all objects in inactive semispace, remove marks, 2011 // migrate live objects and write forwarding addresses. 2012 for (Address current = from_bottom; current < from_top; current += size) { 2013 HeapObject* object = HeapObject::FromAddress(current); 2014 2015 if (object->IsMarked()) { 2016 object->ClearMark(); 2017 heap->mark_compact_collector()->tracer()->decrement_marked_count(); 2018 2019 size = object->Size(); 2020 survivors_size += size; 2021 2022 // Aggressively promote young survivors to the old space. 2023 if (TryPromoteObject(heap, object, size)) { 2024 continue; 2025 } 2026 2027 // Promotion failed. Just migrate object to another semispace. 2028 // Allocation cannot fail at this point: semispaces are of equal size. 2029 Object* target = space->AllocateRaw(size)->ToObjectUnchecked(); 2030 2031 MigrateObject(heap, 2032 HeapObject::cast(target)->address(), 2033 current, 2034 size, 2035 false); 2036 } else { 2037 // Process the dead object before we write a NULL into its header. 2038 LiveObjectList::ProcessNonLive(object); 2039 2040 size = object->Size(); 2041 Memory::Address_at(current) = NULL; 2042 } 2043 } 2044 2045 // Second pass: find pointers to new space and update them. 2046 PointersToNewGenUpdatingVisitor updating_visitor(heap); 2047 2048 // Update pointers in to space. 2049 Address current = space->bottom(); 2050 while (current < space->top()) { 2051 HeapObject* object = HeapObject::FromAddress(current); 2052 current += 2053 StaticPointersToNewGenUpdatingVisitor::IterateBody(object->map(), 2054 object); 2055 } 2056 2057 // Update roots. 2058 heap->IterateRoots(&updating_visitor, VISIT_ALL_IN_SCAVENGE); 2059 LiveObjectList::IterateElements(&updating_visitor); 2060 2061 // Update pointers in old spaces. 2062 heap->IterateDirtyRegions(heap->old_pointer_space(), 2063 &Heap::IteratePointersInDirtyRegion, 2064 &UpdatePointerToNewGen, 2065 heap->WATERMARK_SHOULD_BE_VALID); 2066 2067 heap->lo_space()->IterateDirtyRegions(&UpdatePointerToNewGen); 2068 2069 // Update pointers from cells. 2070 HeapObjectIterator cell_iterator(heap->cell_space()); 2071 for (HeapObject* cell = cell_iterator.next(); 2072 cell != NULL; 2073 cell = cell_iterator.next()) { 2074 if (cell->IsJSGlobalPropertyCell()) { 2075 Address value_address = 2076 reinterpret_cast<Address>(cell) + 2077 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag); 2078 updating_visitor.VisitPointer(reinterpret_cast<Object**>(value_address)); 2079 } 2080 } 2081 2082 // Update pointer from the global contexts list. 2083 updating_visitor.VisitPointer(heap->global_contexts_list_address()); 2084 2085 // Update pointers from external string table. 2086 heap->UpdateNewSpaceReferencesInExternalStringTable( 2087 &UpdateNewSpaceReferenceInExternalStringTableEntry); 2088 2089 // All pointers were updated. Update auxiliary allocation info. 2090 heap->IncrementYoungSurvivorsCounter(survivors_size); 2091 space->set_age_mark(space->top()); 2092 2093 // Update JSFunction pointers from the runtime profiler. 2094 heap->isolate()->runtime_profiler()->UpdateSamplesAfterScavenge(); 2095 } 2096 2097 2098 static void SweepSpace(Heap* heap, PagedSpace* space) { 2099 PageIterator it(space, PageIterator::PAGES_IN_USE); 2100 2101 // During sweeping of paged space we are trying to find longest sequences 2102 // of pages without live objects and free them (instead of putting them on 2103 // the free list). 2104 2105 // Page preceding current. 2106 Page* prev = Page::FromAddress(NULL); 2107 2108 // First empty page in a sequence. 2109 Page* first_empty_page = Page::FromAddress(NULL); 2110 2111 // Page preceding first empty page. 2112 Page* prec_first_empty_page = Page::FromAddress(NULL); 2113 2114 // If last used page of space ends with a sequence of dead objects 2115 // we can adjust allocation top instead of puting this free area into 2116 // the free list. Thus during sweeping we keep track of such areas 2117 // and defer their deallocation until the sweeping of the next page 2118 // is done: if one of the next pages contains live objects we have 2119 // to put such area into the free list. 2120 Address last_free_start = NULL; 2121 int last_free_size = 0; 2122 2123 while (it.has_next()) { 2124 Page* p = it.next(); 2125 2126 bool is_previous_alive = true; 2127 Address free_start = NULL; 2128 HeapObject* object; 2129 2130 for (Address current = p->ObjectAreaStart(); 2131 current < p->AllocationTop(); 2132 current += object->Size()) { 2133 object = HeapObject::FromAddress(current); 2134 if (object->IsMarked()) { 2135 object->ClearMark(); 2136 heap->mark_compact_collector()->tracer()->decrement_marked_count(); 2137 2138 if (!is_previous_alive) { // Transition from free to live. 2139 space->DeallocateBlock(free_start, 2140 static_cast<int>(current - free_start), 2141 true); 2142 is_previous_alive = true; 2143 } 2144 } else { 2145 heap->mark_compact_collector()->ReportDeleteIfNeeded( 2146 object, heap->isolate()); 2147 if (is_previous_alive) { // Transition from live to free. 2148 free_start = current; 2149 is_previous_alive = false; 2150 } 2151 LiveObjectList::ProcessNonLive(object); 2152 } 2153 // The object is now unmarked for the call to Size() at the top of the 2154 // loop. 2155 } 2156 2157 bool page_is_empty = (p->ObjectAreaStart() == p->AllocationTop()) 2158 || (!is_previous_alive && free_start == p->ObjectAreaStart()); 2159 2160 if (page_is_empty) { 2161 // This page is empty. Check whether we are in the middle of 2162 // sequence of empty pages and start one if not. 2163 if (!first_empty_page->is_valid()) { 2164 first_empty_page = p; 2165 prec_first_empty_page = prev; 2166 } 2167 2168 if (!is_previous_alive) { 2169 // There are dead objects on this page. Update space accounting stats 2170 // without putting anything into free list. 2171 int size_in_bytes = static_cast<int>(p->AllocationTop() - free_start); 2172 if (size_in_bytes > 0) { 2173 space->DeallocateBlock(free_start, size_in_bytes, false); 2174 } 2175 } 2176 } else { 2177 // This page is not empty. Sequence of empty pages ended on the previous 2178 // one. 2179 if (first_empty_page->is_valid()) { 2180 space->FreePages(prec_first_empty_page, prev); 2181 prec_first_empty_page = first_empty_page = Page::FromAddress(NULL); 2182 } 2183 2184 // If there is a free ending area on one of the previous pages we have 2185 // deallocate that area and put it on the free list. 2186 if (last_free_size > 0) { 2187 Page::FromAddress(last_free_start)-> 2188 SetAllocationWatermark(last_free_start); 2189 space->DeallocateBlock(last_free_start, last_free_size, true); 2190 last_free_start = NULL; 2191 last_free_size = 0; 2192 } 2193 2194 // If the last region of this page was not live we remember it. 2195 if (!is_previous_alive) { 2196 ASSERT(last_free_size == 0); 2197 last_free_size = static_cast<int>(p->AllocationTop() - free_start); 2198 last_free_start = free_start; 2199 } 2200 } 2201 2202 prev = p; 2203 } 2204 2205 // We reached end of space. See if we need to adjust allocation top. 2206 Address new_allocation_top = NULL; 2207 2208 if (first_empty_page->is_valid()) { 2209 // Last used pages in space are empty. We can move allocation top backwards 2210 // to the beginning of first empty page. 2211 ASSERT(prev == space->AllocationTopPage()); 2212 2213 new_allocation_top = first_empty_page->ObjectAreaStart(); 2214 } 2215 2216 if (last_free_size > 0) { 2217 // There was a free ending area on the previous page. 2218 // Deallocate it without putting it into freelist and move allocation 2219 // top to the beginning of this free area. 2220 space->DeallocateBlock(last_free_start, last_free_size, false); 2221 new_allocation_top = last_free_start; 2222 } 2223 2224 if (new_allocation_top != NULL) { 2225 #ifdef DEBUG 2226 Page* new_allocation_top_page = Page::FromAllocationTop(new_allocation_top); 2227 if (!first_empty_page->is_valid()) { 2228 ASSERT(new_allocation_top_page == space->AllocationTopPage()); 2229 } else if (last_free_size > 0) { 2230 ASSERT(new_allocation_top_page == prec_first_empty_page); 2231 } else { 2232 ASSERT(new_allocation_top_page == first_empty_page); 2233 } 2234 #endif 2235 2236 space->SetTop(new_allocation_top); 2237 } 2238 } 2239 2240 2241 void MarkCompactCollector::EncodeForwardingAddresses() { 2242 ASSERT(state_ == ENCODE_FORWARDING_ADDRESSES); 2243 // Objects in the active semispace of the young generation may be 2244 // relocated to the inactive semispace (if not promoted). Set the 2245 // relocation info to the beginning of the inactive semispace. 2246 heap()->new_space()->MCResetRelocationInfo(); 2247 2248 // Compute the forwarding pointers in each space. 2249 EncodeForwardingAddressesInPagedSpace<MCAllocateFromOldPointerSpace, 2250 ReportDeleteIfNeeded>( 2251 heap()->old_pointer_space()); 2252 2253 EncodeForwardingAddressesInPagedSpace<MCAllocateFromOldDataSpace, 2254 IgnoreNonLiveObject>( 2255 heap()->old_data_space()); 2256 2257 EncodeForwardingAddressesInPagedSpace<MCAllocateFromCodeSpace, 2258 ReportDeleteIfNeeded>( 2259 heap()->code_space()); 2260 2261 EncodeForwardingAddressesInPagedSpace<MCAllocateFromCellSpace, 2262 IgnoreNonLiveObject>( 2263 heap()->cell_space()); 2264 2265 2266 // Compute new space next to last after the old and code spaces have been 2267 // compacted. Objects in new space can be promoted to old or code space. 2268 EncodeForwardingAddressesInNewSpace(); 2269 2270 // Compute map space last because computing forwarding addresses 2271 // overwrites non-live objects. Objects in the other spaces rely on 2272 // non-live map pointers to get the sizes of non-live objects. 2273 EncodeForwardingAddressesInPagedSpace<MCAllocateFromMapSpace, 2274 IgnoreNonLiveObject>( 2275 heap()->map_space()); 2276 2277 // Write relocation info to the top page, so we can use it later. This is 2278 // done after promoting objects from the new space so we get the correct 2279 // allocation top. 2280 heap()->old_pointer_space()->MCWriteRelocationInfoToPage(); 2281 heap()->old_data_space()->MCWriteRelocationInfoToPage(); 2282 heap()->code_space()->MCWriteRelocationInfoToPage(); 2283 heap()->map_space()->MCWriteRelocationInfoToPage(); 2284 heap()->cell_space()->MCWriteRelocationInfoToPage(); 2285 } 2286 2287 2288 class MapIterator : public HeapObjectIterator { 2289 public: 2290 explicit MapIterator(Heap* heap) 2291 : HeapObjectIterator(heap->map_space(), &SizeCallback) { } 2292 2293 MapIterator(Heap* heap, Address start) 2294 : HeapObjectIterator(heap->map_space(), start, &SizeCallback) { } 2295 2296 private: 2297 static int SizeCallback(HeapObject* unused) { 2298 USE(unused); 2299 return Map::kSize; 2300 } 2301 }; 2302 2303 2304 class MapCompact { 2305 public: 2306 explicit MapCompact(Heap* heap, int live_maps) 2307 : heap_(heap), 2308 live_maps_(live_maps), 2309 to_evacuate_start_(heap->map_space()->TopAfterCompaction(live_maps)), 2310 vacant_map_it_(heap), 2311 map_to_evacuate_it_(heap, to_evacuate_start_), 2312 first_map_to_evacuate_( 2313 reinterpret_cast<Map*>(HeapObject::FromAddress(to_evacuate_start_))) { 2314 } 2315 2316 void CompactMaps() { 2317 // As we know the number of maps to evacuate beforehand, 2318 // we stop then there is no more vacant maps. 2319 for (Map* next_vacant_map = NextVacantMap(); 2320 next_vacant_map; 2321 next_vacant_map = NextVacantMap()) { 2322 EvacuateMap(next_vacant_map, NextMapToEvacuate()); 2323 } 2324 2325 #ifdef DEBUG 2326 CheckNoMapsToEvacuate(); 2327 #endif 2328 } 2329 2330 void UpdateMapPointersInRoots() { 2331 MapUpdatingVisitor map_updating_visitor; 2332 heap()->IterateRoots(&map_updating_visitor, VISIT_ONLY_STRONG); 2333 heap()->isolate()->global_handles()->IterateWeakRoots( 2334 &map_updating_visitor); 2335 LiveObjectList::IterateElements(&map_updating_visitor); 2336 } 2337 2338 void UpdateMapPointersInPagedSpace(PagedSpace* space) { 2339 ASSERT(space != heap()->map_space()); 2340 2341 PageIterator it(space, PageIterator::PAGES_IN_USE); 2342 while (it.has_next()) { 2343 Page* p = it.next(); 2344 UpdateMapPointersInRange(heap(), 2345 p->ObjectAreaStart(), 2346 p->AllocationTop()); 2347 } 2348 } 2349 2350 void UpdateMapPointersInNewSpace() { 2351 NewSpace* space = heap()->new_space(); 2352 UpdateMapPointersInRange(heap(), space->bottom(), space->top()); 2353 } 2354 2355 void UpdateMapPointersInLargeObjectSpace() { 2356 LargeObjectIterator it(heap()->lo_space()); 2357 for (HeapObject* obj = it.next(); obj != NULL; obj = it.next()) 2358 UpdateMapPointersInObject(heap(), obj); 2359 } 2360 2361 void Finish() { 2362 heap()->map_space()->FinishCompaction(to_evacuate_start_, live_maps_); 2363 } 2364 2365 inline Heap* heap() const { return heap_; } 2366 2367 private: 2368 Heap* heap_; 2369 int live_maps_; 2370 Address to_evacuate_start_; 2371 MapIterator vacant_map_it_; 2372 MapIterator map_to_evacuate_it_; 2373 Map* first_map_to_evacuate_; 2374 2375 // Helper class for updating map pointers in HeapObjects. 2376 class MapUpdatingVisitor: public ObjectVisitor { 2377 public: 2378 MapUpdatingVisitor() {} 2379 2380 void VisitPointer(Object** p) { 2381 UpdateMapPointer(p); 2382 } 2383 2384 void VisitPointers(Object** start, Object** end) { 2385 for (Object** p = start; p < end; p++) UpdateMapPointer(p); 2386 } 2387 2388 private: 2389 void UpdateMapPointer(Object** p) { 2390 if (!(*p)->IsHeapObject()) return; 2391 HeapObject* old_map = reinterpret_cast<HeapObject*>(*p); 2392 2393 // Moved maps are tagged with overflowed map word. They are the only 2394 // objects those map word is overflowed as marking is already complete. 2395 MapWord map_word = old_map->map_word(); 2396 if (!map_word.IsOverflowed()) return; 2397 2398 *p = GetForwardedMap(map_word); 2399 } 2400 }; 2401 2402 static Map* NextMap(MapIterator* it, HeapObject* last, bool live) { 2403 while (true) { 2404 HeapObject* next = it->next(); 2405 ASSERT(next != NULL); 2406 if (next == last) 2407 return NULL; 2408 ASSERT(!next->IsOverflowed()); 2409 ASSERT(!next->IsMarked()); 2410 ASSERT(next->IsMap() || FreeListNode::IsFreeListNode(next)); 2411 if (next->IsMap() == live) 2412 return reinterpret_cast<Map*>(next); 2413 } 2414 } 2415 2416 Map* NextVacantMap() { 2417 Map* map = NextMap(&vacant_map_it_, first_map_to_evacuate_, false); 2418 ASSERT(map == NULL || FreeListNode::IsFreeListNode(map)); 2419 return map; 2420 } 2421 2422 Map* NextMapToEvacuate() { 2423 Map* map = NextMap(&map_to_evacuate_it_, NULL, true); 2424 ASSERT(map != NULL); 2425 ASSERT(map->IsMap()); 2426 return map; 2427 } 2428 2429 static void EvacuateMap(Map* vacant_map, Map* map_to_evacuate) { 2430 ASSERT(FreeListNode::IsFreeListNode(vacant_map)); 2431 ASSERT(map_to_evacuate->IsMap()); 2432 2433 ASSERT(Map::kSize % 4 == 0); 2434 2435 map_to_evacuate->heap()->CopyBlockToOldSpaceAndUpdateRegionMarks( 2436 vacant_map->address(), map_to_evacuate->address(), Map::kSize); 2437 2438 ASSERT(vacant_map->IsMap()); // Due to memcpy above. 2439 2440 MapWord forwarding_map_word = MapWord::FromMap(vacant_map); 2441 forwarding_map_word.SetOverflow(); 2442 map_to_evacuate->set_map_word(forwarding_map_word); 2443 2444 ASSERT(map_to_evacuate->map_word().IsOverflowed()); 2445 ASSERT(GetForwardedMap(map_to_evacuate->map_word()) == vacant_map); 2446 } 2447 2448 static Map* GetForwardedMap(MapWord map_word) { 2449 ASSERT(map_word.IsOverflowed()); 2450 map_word.ClearOverflow(); 2451 Map* new_map = map_word.ToMap(); 2452 ASSERT_MAP_ALIGNED(new_map->address()); 2453 return new_map; 2454 } 2455 2456 static int UpdateMapPointersInObject(Heap* heap, HeapObject* obj) { 2457 ASSERT(!obj->IsMarked()); 2458 Map* map = obj->map(); 2459 ASSERT(heap->map_space()->Contains(map)); 2460 MapWord map_word = map->map_word(); 2461 ASSERT(!map_word.IsMarked()); 2462 if (map_word.IsOverflowed()) { 2463 Map* new_map = GetForwardedMap(map_word); 2464 ASSERT(heap->map_space()->Contains(new_map)); 2465 obj->set_map(new_map); 2466 2467 #ifdef DEBUG 2468 if (FLAG_gc_verbose) { 2469 PrintF("update %p : %p -> %p\n", 2470 obj->address(), 2471 reinterpret_cast<void*>(map), 2472 reinterpret_cast<void*>(new_map)); 2473 } 2474 #endif 2475 } 2476 2477 int size = obj->SizeFromMap(map); 2478 MapUpdatingVisitor map_updating_visitor; 2479 obj->IterateBody(map->instance_type(), size, &map_updating_visitor); 2480 return size; 2481 } 2482 2483 static void UpdateMapPointersInRange(Heap* heap, Address start, Address end) { 2484 HeapObject* object; 2485 int size; 2486 for (Address current = start; current < end; current += size) { 2487 object = HeapObject::FromAddress(current); 2488 size = UpdateMapPointersInObject(heap, object); 2489 ASSERT(size > 0); 2490 } 2491 } 2492 2493 #ifdef DEBUG 2494 void CheckNoMapsToEvacuate() { 2495 if (!FLAG_enable_slow_asserts) 2496 return; 2497 2498 for (HeapObject* obj = map_to_evacuate_it_.next(); 2499 obj != NULL; obj = map_to_evacuate_it_.next()) 2500 ASSERT(FreeListNode::IsFreeListNode(obj)); 2501 } 2502 #endif 2503 }; 2504 2505 2506 void MarkCompactCollector::SweepSpaces() { 2507 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP); 2508 2509 ASSERT(state_ == SWEEP_SPACES); 2510 ASSERT(!IsCompacting()); 2511 // Noncompacting collections simply sweep the spaces to clear the mark 2512 // bits and free the nonlive blocks (for old and map spaces). We sweep 2513 // the map space last because freeing non-live maps overwrites them and 2514 // the other spaces rely on possibly non-live maps to get the sizes for 2515 // non-live objects. 2516 SweepSpace(heap(), heap()->old_pointer_space()); 2517 SweepSpace(heap(), heap()->old_data_space()); 2518 SweepSpace(heap(), heap()->code_space()); 2519 SweepSpace(heap(), heap()->cell_space()); 2520 { GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP_NEWSPACE); 2521 SweepNewSpace(heap(), heap()->new_space()); 2522 } 2523 SweepSpace(heap(), heap()->map_space()); 2524 2525 heap()->IterateDirtyRegions(heap()->map_space(), 2526 &heap()->IteratePointersInDirtyMapsRegion, 2527 &UpdatePointerToNewGen, 2528 heap()->WATERMARK_SHOULD_BE_VALID); 2529 2530 intptr_t live_maps_size = heap()->map_space()->Size(); 2531 int live_maps = static_cast<int>(live_maps_size / Map::kSize); 2532 ASSERT(live_map_objects_size_ == live_maps_size); 2533 2534 if (heap()->map_space()->NeedsCompaction(live_maps)) { 2535 MapCompact map_compact(heap(), live_maps); 2536 2537 map_compact.CompactMaps(); 2538 map_compact.UpdateMapPointersInRoots(); 2539 2540 PagedSpaces spaces; 2541 for (PagedSpace* space = spaces.next(); 2542 space != NULL; space = spaces.next()) { 2543 if (space == heap()->map_space()) continue; 2544 map_compact.UpdateMapPointersInPagedSpace(space); 2545 } 2546 map_compact.UpdateMapPointersInNewSpace(); 2547 map_compact.UpdateMapPointersInLargeObjectSpace(); 2548 2549 map_compact.Finish(); 2550 } 2551 } 2552 2553 2554 // Iterate the live objects in a range of addresses (eg, a page or a 2555 // semispace). The live regions of the range have been linked into a list. 2556 // The first live region is [first_live_start, first_live_end), and the last 2557 // address in the range is top. The callback function is used to get the 2558 // size of each live object. 2559 int MarkCompactCollector::IterateLiveObjectsInRange( 2560 Address start, 2561 Address end, 2562 LiveObjectCallback size_func) { 2563 int live_objects_size = 0; 2564 Address current = start; 2565 while (current < end) { 2566 uint32_t encoded_map = Memory::uint32_at(current); 2567 if (encoded_map == kSingleFreeEncoding) { 2568 current += kPointerSize; 2569 } else if (encoded_map == kMultiFreeEncoding) { 2570 current += Memory::int_at(current + kIntSize); 2571 } else { 2572 int size = (this->*size_func)(HeapObject::FromAddress(current)); 2573 current += size; 2574 live_objects_size += size; 2575 } 2576 } 2577 return live_objects_size; 2578 } 2579 2580 2581 int MarkCompactCollector::IterateLiveObjects( 2582 NewSpace* space, LiveObjectCallback size_f) { 2583 ASSERT(MARK_LIVE_OBJECTS < state_ && state_ <= RELOCATE_OBJECTS); 2584 return IterateLiveObjectsInRange(space->bottom(), space->top(), size_f); 2585 } 2586 2587 2588 int MarkCompactCollector::IterateLiveObjects( 2589 PagedSpace* space, LiveObjectCallback size_f) { 2590 ASSERT(MARK_LIVE_OBJECTS < state_ && state_ <= RELOCATE_OBJECTS); 2591 int total = 0; 2592 PageIterator it(space, PageIterator::PAGES_IN_USE); 2593 while (it.has_next()) { 2594 Page* p = it.next(); 2595 total += IterateLiveObjectsInRange(p->ObjectAreaStart(), 2596 p->AllocationTop(), 2597 size_f); 2598 } 2599 return total; 2600 } 2601 2602 2603 // ------------------------------------------------------------------------- 2604 // Phase 3: Update pointers 2605 2606 // Helper class for updating pointers in HeapObjects. 2607 class UpdatingVisitor: public ObjectVisitor { 2608 public: 2609 explicit UpdatingVisitor(Heap* heap) : heap_(heap) {} 2610 2611 void VisitPointer(Object** p) { 2612 UpdatePointer(p); 2613 } 2614 2615 void VisitPointers(Object** start, Object** end) { 2616 // Mark all HeapObject pointers in [start, end) 2617 for (Object** p = start; p < end; p++) UpdatePointer(p); 2618 } 2619 2620 void VisitCodeTarget(RelocInfo* rinfo) { 2621 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); 2622 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); 2623 VisitPointer(&target); 2624 rinfo->set_target_address( 2625 reinterpret_cast<Code*>(target)->instruction_start()); 2626 } 2627 2628 void VisitDebugTarget(RelocInfo* rinfo) { 2629 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) && 2630 rinfo->IsPatchedReturnSequence()) || 2631 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && 2632 rinfo->IsPatchedDebugBreakSlotSequence())); 2633 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address()); 2634 VisitPointer(&target); 2635 rinfo->set_call_address( 2636 reinterpret_cast<Code*>(target)->instruction_start()); 2637 } 2638 2639 inline Heap* heap() const { return heap_; } 2640 2641 private: 2642 void UpdatePointer(Object** p) { 2643 if (!(*p)->IsHeapObject()) return; 2644 2645 HeapObject* obj = HeapObject::cast(*p); 2646 Address old_addr = obj->address(); 2647 Address new_addr; 2648 ASSERT(!heap()->InFromSpace(obj)); 2649 2650 if (heap()->new_space()->Contains(obj)) { 2651 Address forwarding_pointer_addr = 2652 heap()->new_space()->FromSpaceLow() + 2653 heap()->new_space()->ToSpaceOffsetForAddress(old_addr); 2654 new_addr = Memory::Address_at(forwarding_pointer_addr); 2655 2656 #ifdef DEBUG 2657 ASSERT(heap()->old_pointer_space()->Contains(new_addr) || 2658 heap()->old_data_space()->Contains(new_addr) || 2659 heap()->new_space()->FromSpaceContains(new_addr) || 2660 heap()->lo_space()->Contains(HeapObject::FromAddress(new_addr))); 2661 2662 if (heap()->new_space()->FromSpaceContains(new_addr)) { 2663 ASSERT(heap()->new_space()->FromSpaceOffsetForAddress(new_addr) <= 2664 heap()->new_space()->ToSpaceOffsetForAddress(old_addr)); 2665 } 2666 #endif 2667 2668 } else if (heap()->lo_space()->Contains(obj)) { 2669 // Don't move objects in the large object space. 2670 return; 2671 2672 } else { 2673 #ifdef DEBUG 2674 PagedSpaces spaces; 2675 PagedSpace* original_space = spaces.next(); 2676 while (original_space != NULL) { 2677 if (original_space->Contains(obj)) break; 2678 original_space = spaces.next(); 2679 } 2680 ASSERT(original_space != NULL); 2681 #endif 2682 new_addr = MarkCompactCollector::GetForwardingAddressInOldSpace(obj); 2683 ASSERT(original_space->Contains(new_addr)); 2684 ASSERT(original_space->MCSpaceOffsetForAddress(new_addr) <= 2685 original_space->MCSpaceOffsetForAddress(old_addr)); 2686 } 2687 2688 *p = HeapObject::FromAddress(new_addr); 2689 2690 #ifdef DEBUG 2691 if (FLAG_gc_verbose) { 2692 PrintF("update %p : %p -> %p\n", 2693 reinterpret_cast<Address>(p), old_addr, new_addr); 2694 } 2695 #endif 2696 } 2697 2698 Heap* heap_; 2699 }; 2700 2701 2702 void MarkCompactCollector::UpdatePointers() { 2703 #ifdef DEBUG 2704 ASSERT(state_ == ENCODE_FORWARDING_ADDRESSES); 2705 state_ = UPDATE_POINTERS; 2706 #endif 2707 UpdatingVisitor updating_visitor(heap()); 2708 heap()->isolate()->runtime_profiler()->UpdateSamplesAfterCompact( 2709 &updating_visitor); 2710 heap()->IterateRoots(&updating_visitor, VISIT_ONLY_STRONG); 2711 heap()->isolate()->global_handles()->IterateWeakRoots(&updating_visitor); 2712 2713 // Update the pointer to the head of the weak list of global contexts. 2714 updating_visitor.VisitPointer(&heap()->global_contexts_list_); 2715 2716 LiveObjectList::IterateElements(&updating_visitor); 2717 2718 int live_maps_size = IterateLiveObjects( 2719 heap()->map_space(), &MarkCompactCollector::UpdatePointersInOldObject); 2720 int live_pointer_olds_size = IterateLiveObjects( 2721 heap()->old_pointer_space(), 2722 &MarkCompactCollector::UpdatePointersInOldObject); 2723 int live_data_olds_size = IterateLiveObjects( 2724 heap()->old_data_space(), 2725 &MarkCompactCollector::UpdatePointersInOldObject); 2726 int live_codes_size = IterateLiveObjects( 2727 heap()->code_space(), &MarkCompactCollector::UpdatePointersInOldObject); 2728 int live_cells_size = IterateLiveObjects( 2729 heap()->cell_space(), &MarkCompactCollector::UpdatePointersInOldObject); 2730 int live_news_size = IterateLiveObjects( 2731 heap()->new_space(), &MarkCompactCollector::UpdatePointersInNewObject); 2732 2733 // Large objects do not move, the map word can be updated directly. 2734 LargeObjectIterator it(heap()->lo_space()); 2735 for (HeapObject* obj = it.next(); obj != NULL; obj = it.next()) { 2736 UpdatePointersInNewObject(obj); 2737 } 2738 2739 USE(live_maps_size); 2740 USE(live_pointer_olds_size); 2741 USE(live_data_olds_size); 2742 USE(live_codes_size); 2743 USE(live_cells_size); 2744 USE(live_news_size); 2745 ASSERT(live_maps_size == live_map_objects_size_); 2746 ASSERT(live_data_olds_size == live_old_data_objects_size_); 2747 ASSERT(live_pointer_olds_size == live_old_pointer_objects_size_); 2748 ASSERT(live_codes_size == live_code_objects_size_); 2749 ASSERT(live_cells_size == live_cell_objects_size_); 2750 ASSERT(live_news_size == live_young_objects_size_); 2751 } 2752 2753 2754 int MarkCompactCollector::UpdatePointersInNewObject(HeapObject* obj) { 2755 // Keep old map pointers 2756 Map* old_map = obj->map(); 2757 ASSERT(old_map->IsHeapObject()); 2758 2759 Address forwarded = GetForwardingAddressInOldSpace(old_map); 2760 2761 ASSERT(heap()->map_space()->Contains(old_map)); 2762 ASSERT(heap()->map_space()->Contains(forwarded)); 2763 #ifdef DEBUG 2764 if (FLAG_gc_verbose) { 2765 PrintF("update %p : %p -> %p\n", obj->address(), old_map->address(), 2766 forwarded); 2767 } 2768 #endif 2769 // Update the map pointer. 2770 obj->set_map(reinterpret_cast<Map*>(HeapObject::FromAddress(forwarded))); 2771 2772 // We have to compute the object size relying on the old map because 2773 // map objects are not relocated yet. 2774 int obj_size = obj->SizeFromMap(old_map); 2775 2776 // Update pointers in the object body. 2777 UpdatingVisitor updating_visitor(heap()); 2778 obj->IterateBody(old_map->instance_type(), obj_size, &updating_visitor); 2779 return obj_size; 2780 } 2781 2782 2783 int MarkCompactCollector::UpdatePointersInOldObject(HeapObject* obj) { 2784 // Decode the map pointer. 2785 MapWord encoding = obj->map_word(); 2786 Address map_addr = encoding.DecodeMapAddress(heap()->map_space()); 2787 ASSERT(heap()->map_space()->Contains(HeapObject::FromAddress(map_addr))); 2788 2789 // At this point, the first word of map_addr is also encoded, cannot 2790 // cast it to Map* using Map::cast. 2791 Map* map = reinterpret_cast<Map*>(HeapObject::FromAddress(map_addr)); 2792 int obj_size = obj->SizeFromMap(map); 2793 InstanceType type = map->instance_type(); 2794 2795 // Update map pointer. 2796 Address new_map_addr = GetForwardingAddressInOldSpace(map); 2797 int offset = encoding.DecodeOffset(); 2798 obj->set_map_word(MapWord::EncodeAddress(new_map_addr, offset)); 2799 2800 #ifdef DEBUG 2801 if (FLAG_gc_verbose) { 2802 PrintF("update %p : %p -> %p\n", obj->address(), 2803 map_addr, new_map_addr); 2804 } 2805 #endif 2806 2807 // Update pointers in the object body. 2808 UpdatingVisitor updating_visitor(heap()); 2809 obj->IterateBody(type, obj_size, &updating_visitor); 2810 return obj_size; 2811 } 2812 2813 2814 Address MarkCompactCollector::GetForwardingAddressInOldSpace(HeapObject* obj) { 2815 // Object should either in old or map space. 2816 MapWord encoding = obj->map_word(); 2817 2818 // Offset to the first live object's forwarding address. 2819 int offset = encoding.DecodeOffset(); 2820 Address obj_addr = obj->address(); 2821 2822 // Find the first live object's forwarding address. 2823 Page* p = Page::FromAddress(obj_addr); 2824 Address first_forwarded = p->mc_first_forwarded; 2825 2826 // Page start address of forwarded address. 2827 Page* forwarded_page = Page::FromAddress(first_forwarded); 2828 int forwarded_offset = forwarded_page->Offset(first_forwarded); 2829 2830 // Find end of allocation in the page of first_forwarded. 2831 int mc_top_offset = forwarded_page->AllocationWatermarkOffset(); 2832 2833 // Check if current object's forward pointer is in the same page 2834 // as the first live object's forwarding pointer 2835 if (forwarded_offset + offset < mc_top_offset) { 2836 // In the same page. 2837 return first_forwarded + offset; 2838 } 2839 2840 // Must be in the next page, NOTE: this may cross chunks. 2841 Page* next_page = forwarded_page->next_page(); 2842 ASSERT(next_page->is_valid()); 2843 2844 offset -= (mc_top_offset - forwarded_offset); 2845 offset += Page::kObjectStartOffset; 2846 2847 ASSERT_PAGE_OFFSET(offset); 2848 ASSERT(next_page->OffsetToAddress(offset) < next_page->AllocationTop()); 2849 2850 return next_page->OffsetToAddress(offset); 2851 } 2852 2853 2854 // ------------------------------------------------------------------------- 2855 // Phase 4: Relocate objects 2856 2857 void MarkCompactCollector::RelocateObjects() { 2858 #ifdef DEBUG 2859 ASSERT(state_ == UPDATE_POINTERS); 2860 state_ = RELOCATE_OBJECTS; 2861 #endif 2862 // Relocates objects, always relocate map objects first. Relocating 2863 // objects in other space relies on map objects to get object size. 2864 int live_maps_size = IterateLiveObjects( 2865 heap()->map_space(), &MarkCompactCollector::RelocateMapObject); 2866 int live_pointer_olds_size = IterateLiveObjects( 2867 heap()->old_pointer_space(), 2868 &MarkCompactCollector::RelocateOldPointerObject); 2869 int live_data_olds_size = IterateLiveObjects( 2870 heap()->old_data_space(), &MarkCompactCollector::RelocateOldDataObject); 2871 int live_codes_size = IterateLiveObjects( 2872 heap()->code_space(), &MarkCompactCollector::RelocateCodeObject); 2873 int live_cells_size = IterateLiveObjects( 2874 heap()->cell_space(), &MarkCompactCollector::RelocateCellObject); 2875 int live_news_size = IterateLiveObjects( 2876 heap()->new_space(), &MarkCompactCollector::RelocateNewObject); 2877 2878 USE(live_maps_size); 2879 USE(live_pointer_olds_size); 2880 USE(live_data_olds_size); 2881 USE(live_codes_size); 2882 USE(live_cells_size); 2883 USE(live_news_size); 2884 ASSERT(live_maps_size == live_map_objects_size_); 2885 ASSERT(live_data_olds_size == live_old_data_objects_size_); 2886 ASSERT(live_pointer_olds_size == live_old_pointer_objects_size_); 2887 ASSERT(live_codes_size == live_code_objects_size_); 2888 ASSERT(live_cells_size == live_cell_objects_size_); 2889 ASSERT(live_news_size == live_young_objects_size_); 2890 2891 // Flip from and to spaces 2892 heap()->new_space()->Flip(); 2893 2894 heap()->new_space()->MCCommitRelocationInfo(); 2895 2896 // Set age_mark to bottom in to space 2897 Address mark = heap()->new_space()->bottom(); 2898 heap()->new_space()->set_age_mark(mark); 2899 2900 PagedSpaces spaces; 2901 for (PagedSpace* space = spaces.next(); space != NULL; space = spaces.next()) 2902 space->MCCommitRelocationInfo(); 2903 2904 heap()->CheckNewSpaceExpansionCriteria(); 2905 heap()->IncrementYoungSurvivorsCounter(live_news_size); 2906 } 2907 2908 2909 int MarkCompactCollector::RelocateMapObject(HeapObject* obj) { 2910 // Recover map pointer. 2911 MapWord encoding = obj->map_word(); 2912 Address map_addr = encoding.DecodeMapAddress(heap()->map_space()); 2913 ASSERT(heap()->map_space()->Contains(HeapObject::FromAddress(map_addr))); 2914 2915 // Get forwarding address before resetting map pointer 2916 Address new_addr = GetForwardingAddressInOldSpace(obj); 2917 2918 // Reset map pointer. The meta map object may not be copied yet so 2919 // Map::cast does not yet work. 2920 obj->set_map(reinterpret_cast<Map*>(HeapObject::FromAddress(map_addr))); 2921 2922 Address old_addr = obj->address(); 2923 2924 if (new_addr != old_addr) { 2925 // Move contents. 2926 heap()->MoveBlockToOldSpaceAndUpdateRegionMarks(new_addr, 2927 old_addr, 2928 Map::kSize); 2929 } 2930 2931 #ifdef DEBUG 2932 if (FLAG_gc_verbose) { 2933 PrintF("relocate %p -> %p\n", old_addr, new_addr); 2934 } 2935 #endif 2936 2937 return Map::kSize; 2938 } 2939 2940 2941 static inline int RestoreMap(HeapObject* obj, 2942 PagedSpace* space, 2943 Address new_addr, 2944 Address map_addr) { 2945 // This must be a non-map object, and the function relies on the 2946 // assumption that the Map space is compacted before the other paged 2947 // spaces (see RelocateObjects). 2948 2949 // Reset map pointer. 2950 obj->set_map(Map::cast(HeapObject::FromAddress(map_addr))); 2951 2952 int obj_size = obj->Size(); 2953 ASSERT_OBJECT_SIZE(obj_size); 2954 2955 ASSERT(space->MCSpaceOffsetForAddress(new_addr) <= 2956 space->MCSpaceOffsetForAddress(obj->address())); 2957 2958 #ifdef DEBUG 2959 if (FLAG_gc_verbose) { 2960 PrintF("relocate %p -> %p\n", obj->address(), new_addr); 2961 } 2962 #endif 2963 2964 return obj_size; 2965 } 2966 2967 2968 int MarkCompactCollector::RelocateOldNonCodeObject(HeapObject* obj, 2969 PagedSpace* space) { 2970 // Recover map pointer. 2971 MapWord encoding = obj->map_word(); 2972 Address map_addr = encoding.DecodeMapAddress(heap()->map_space()); 2973 ASSERT(heap()->map_space()->Contains(map_addr)); 2974 2975 // Get forwarding address before resetting map pointer. 2976 Address new_addr = GetForwardingAddressInOldSpace(obj); 2977 2978 // Reset the map pointer. 2979 int obj_size = RestoreMap(obj, space, new_addr, map_addr); 2980 2981 Address old_addr = obj->address(); 2982 2983 if (new_addr != old_addr) { 2984 // Move contents. 2985 if (space == heap()->old_data_space()) { 2986 heap()->MoveBlock(new_addr, old_addr, obj_size); 2987 } else { 2988 heap()->MoveBlockToOldSpaceAndUpdateRegionMarks(new_addr, 2989 old_addr, 2990 obj_size); 2991 } 2992 } 2993 2994 ASSERT(!HeapObject::FromAddress(new_addr)->IsCode()); 2995 2996 HeapObject* copied_to = HeapObject::FromAddress(new_addr); 2997 if (copied_to->IsSharedFunctionInfo()) { 2998 PROFILE(heap()->isolate(), 2999 SharedFunctionInfoMoveEvent(old_addr, new_addr)); 3000 } 3001 HEAP_PROFILE(heap(), ObjectMoveEvent(old_addr, new_addr)); 3002 3003 return obj_size; 3004 } 3005 3006 3007 int MarkCompactCollector::RelocateOldPointerObject(HeapObject* obj) { 3008 return RelocateOldNonCodeObject(obj, heap()->old_pointer_space()); 3009 } 3010 3011 3012 int MarkCompactCollector::RelocateOldDataObject(HeapObject* obj) { 3013 return RelocateOldNonCodeObject(obj, heap()->old_data_space()); 3014 } 3015 3016 3017 int MarkCompactCollector::RelocateCellObject(HeapObject* obj) { 3018 return RelocateOldNonCodeObject(obj, heap()->cell_space()); 3019 } 3020 3021 3022 int MarkCompactCollector::RelocateCodeObject(HeapObject* obj) { 3023 // Recover map pointer. 3024 MapWord encoding = obj->map_word(); 3025 Address map_addr = encoding.DecodeMapAddress(heap()->map_space()); 3026 ASSERT(heap()->map_space()->Contains(HeapObject::FromAddress(map_addr))); 3027 3028 // Get forwarding address before resetting map pointer 3029 Address new_addr = GetForwardingAddressInOldSpace(obj); 3030 3031 // Reset the map pointer. 3032 int obj_size = RestoreMap(obj, heap()->code_space(), new_addr, map_addr); 3033 3034 Address old_addr = obj->address(); 3035 3036 if (new_addr != old_addr) { 3037 // Move contents. 3038 heap()->MoveBlock(new_addr, old_addr, obj_size); 3039 } 3040 3041 HeapObject* copied_to = HeapObject::FromAddress(new_addr); 3042 if (copied_to->IsCode()) { 3043 // May also update inline cache target. 3044 Code::cast(copied_to)->Relocate(new_addr - old_addr); 3045 // Notify the logger that compiled code has moved. 3046 PROFILE(heap()->isolate(), CodeMoveEvent(old_addr, new_addr)); 3047 } 3048 HEAP_PROFILE(heap(), ObjectMoveEvent(old_addr, new_addr)); 3049 3050 return obj_size; 3051 } 3052 3053 3054 int MarkCompactCollector::RelocateNewObject(HeapObject* obj) { 3055 int obj_size = obj->Size(); 3056 3057 // Get forwarding address 3058 Address old_addr = obj->address(); 3059 int offset = heap()->new_space()->ToSpaceOffsetForAddress(old_addr); 3060 3061 Address new_addr = 3062 Memory::Address_at(heap()->new_space()->FromSpaceLow() + offset); 3063 3064 #ifdef DEBUG 3065 if (heap()->new_space()->FromSpaceContains(new_addr)) { 3066 ASSERT(heap()->new_space()->FromSpaceOffsetForAddress(new_addr) <= 3067 heap()->new_space()->ToSpaceOffsetForAddress(old_addr)); 3068 } else { 3069 ASSERT(heap()->TargetSpace(obj) == heap()->old_pointer_space() || 3070 heap()->TargetSpace(obj) == heap()->old_data_space()); 3071 } 3072 #endif 3073 3074 // New and old addresses cannot overlap. 3075 if (heap()->InNewSpace(HeapObject::FromAddress(new_addr))) { 3076 heap()->CopyBlock(new_addr, old_addr, obj_size); 3077 } else { 3078 heap()->CopyBlockToOldSpaceAndUpdateRegionMarks(new_addr, 3079 old_addr, 3080 obj_size); 3081 } 3082 3083 #ifdef DEBUG 3084 if (FLAG_gc_verbose) { 3085 PrintF("relocate %p -> %p\n", old_addr, new_addr); 3086 } 3087 #endif 3088 3089 HeapObject* copied_to = HeapObject::FromAddress(new_addr); 3090 if (copied_to->IsSharedFunctionInfo()) { 3091 PROFILE(heap()->isolate(), 3092 SharedFunctionInfoMoveEvent(old_addr, new_addr)); 3093 } 3094 HEAP_PROFILE(heap(), ObjectMoveEvent(old_addr, new_addr)); 3095 3096 return obj_size; 3097 } 3098 3099 3100 void MarkCompactCollector::EnableCodeFlushing(bool enable) { 3101 if (enable) { 3102 if (code_flusher_ != NULL) return; 3103 code_flusher_ = new CodeFlusher(heap()->isolate()); 3104 } else { 3105 if (code_flusher_ == NULL) return; 3106 delete code_flusher_; 3107 code_flusher_ = NULL; 3108 } 3109 } 3110 3111 3112 void MarkCompactCollector::ReportDeleteIfNeeded(HeapObject* obj, 3113 Isolate* isolate) { 3114 #ifdef ENABLE_GDB_JIT_INTERFACE 3115 if (obj->IsCode()) { 3116 GDBJITInterface::RemoveCode(reinterpret_cast<Code*>(obj)); 3117 } 3118 #endif 3119 #ifdef ENABLE_LOGGING_AND_PROFILING 3120 if (obj->IsCode()) { 3121 PROFILE(isolate, CodeDeleteEvent(obj->address())); 3122 } 3123 #endif 3124 } 3125 3126 3127 int MarkCompactCollector::SizeOfMarkedObject(HeapObject* obj) { 3128 MapWord map_word = obj->map_word(); 3129 map_word.ClearMark(); 3130 return obj->SizeFromMap(map_word.ToMap()); 3131 } 3132 3133 3134 void MarkCompactCollector::Initialize() { 3135 StaticPointersToNewGenUpdatingVisitor::Initialize(); 3136 StaticMarkingVisitor::Initialize(); 3137 } 3138 3139 3140 } } // namespace v8::internal 3141