| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 | 29 |
| 30 #include "accessors.h" | 30 #include "accessors.h" |
| 31 #include "api.h" | 31 #include "api.h" |
| 32 #include "bootstrapper.h" | 32 #include "bootstrapper.h" |
| 33 #include "codegen.h" | 33 #include "codegen.h" |
| 34 #include "compilation-cache.h" | 34 #include "compilation-cache.h" |
| 35 #include "debug.h" | 35 #include "debug.h" |
| 36 #include "deoptimizer.h" | 36 #include "deoptimizer.h" |
| 37 #include "global-handles.h" | 37 #include "global-handles.h" |
| 38 #include "heap-profiler.h" | 38 #include "heap-profiler.h" |
| 39 #include "incremental-marking.h" |
| 39 #include "liveobjectlist-inl.h" | 40 #include "liveobjectlist-inl.h" |
| 40 #include "mark-compact.h" | 41 #include "mark-compact.h" |
| 41 #include "natives.h" | 42 #include "natives.h" |
| 42 #include "objects-visiting.h" | 43 #include "objects-visiting.h" |
| 44 #include "objects-visiting-inl.h" |
| 43 #include "runtime-profiler.h" | 45 #include "runtime-profiler.h" |
| 44 #include "scopeinfo.h" | 46 #include "scopeinfo.h" |
| 45 #include "snapshot.h" | 47 #include "snapshot.h" |
| 48 #include "store-buffer.h" |
| 46 #include "v8threads.h" | 49 #include "v8threads.h" |
| 47 #include "vm-state-inl.h" | 50 #include "vm-state-inl.h" |
| 48 #if V8_TARGET_ARCH_ARM && !V8_INTERPRETED_REGEXP | 51 #if V8_TARGET_ARCH_ARM && !V8_INTERPRETED_REGEXP |
| 49 #include "regexp-macro-assembler.h" | 52 #include "regexp-macro-assembler.h" |
| 50 #include "arm/regexp-macro-assembler-arm.h" | 53 #include "arm/regexp-macro-assembler-arm.h" |
| 51 #endif | 54 #endif |
| 52 #if V8_TARGET_ARCH_MIPS && !V8_INTERPRETED_REGEXP | 55 #if V8_TARGET_ARCH_MIPS && !V8_INTERPRETED_REGEXP |
| 53 #include "regexp-macro-assembler.h" | 56 #include "regexp-macro-assembler.h" |
| 54 #include "mips/regexp-macro-assembler-mips.h" | 57 #include "mips/regexp-macro-assembler-mips.h" |
| 55 #endif | 58 #endif |
| 56 | 59 |
| 57 namespace v8 { | 60 namespace v8 { |
| 58 namespace internal { | 61 namespace internal { |
| 59 | 62 |
| 60 | 63 |
| 61 static const intptr_t kMinimumPromotionLimit = 2 * MB; | |
| 62 static const intptr_t kMinimumAllocationLimit = 8 * MB; | |
| 63 | |
| 64 | |
| 65 static Mutex* gc_initializer_mutex = OS::CreateMutex(); | 64 static Mutex* gc_initializer_mutex = OS::CreateMutex(); |
| 66 | 65 |
| 67 | 66 |
| 68 Heap::Heap() | 67 Heap::Heap() |
| 69 : isolate_(NULL), | 68 : isolate_(NULL), |
| 70 // semispace_size_ should be a power of 2 and old_generation_size_ should be | 69 // semispace_size_ should be a power of 2 and old_generation_size_ should be |
| 71 // a multiple of Page::kPageSize. | 70 // a multiple of Page::kPageSize. |
| 72 #if defined(ANDROID) | 71 #if defined(ANDROID) |
| 73 reserved_semispace_size_(2*MB), | 72 #define LUMP_OF_MEMORY (128 * KB) |
| 74 max_semispace_size_(2*MB), | |
| 75 initial_semispace_size_(128*KB), | |
| 76 max_old_generation_size_(192*MB), | |
| 77 max_executable_size_(max_old_generation_size_), | |
| 78 code_range_size_(0), | 73 code_range_size_(0), |
| 79 #elif defined(V8_TARGET_ARCH_X64) | 74 #elif defined(V8_TARGET_ARCH_X64) |
| 80 reserved_semispace_size_(16*MB), | 75 #define LUMP_OF_MEMORY (2 * MB) |
| 81 max_semispace_size_(16*MB), | |
| 82 initial_semispace_size_(1*MB), | |
| 83 max_old_generation_size_(1400*MB), | |
| 84 max_executable_size_(256*MB), | |
| 85 code_range_size_(512*MB), | 76 code_range_size_(512*MB), |
| 86 #else | 77 #else |
| 87 reserved_semispace_size_(8*MB), | 78 #define LUMP_OF_MEMORY MB |
| 88 max_semispace_size_(8*MB), | |
| 89 initial_semispace_size_(512*KB), | |
| 90 max_old_generation_size_(700*MB), | |
| 91 max_executable_size_(128*MB), | |
| 92 code_range_size_(0), | 79 code_range_size_(0), |
| 93 #endif | 80 #endif |
| 81 reserved_semispace_size_(8 * Max(LUMP_OF_MEMORY, Page::kPageSize)), |
| 82 max_semispace_size_(8 * Max(LUMP_OF_MEMORY, Page::kPageSize)), |
| 83 initial_semispace_size_(Max(LUMP_OF_MEMORY, Page::kPageSize)), |
| 84 max_old_generation_size_(1400ul * LUMP_OF_MEMORY), |
| 85 max_executable_size_(256l * LUMP_OF_MEMORY), |
| 86 |
| 94 // Variables set based on semispace_size_ and old_generation_size_ in | 87 // Variables set based on semispace_size_ and old_generation_size_ in |
| 95 // ConfigureHeap (survived_since_last_expansion_, external_allocation_limit_) | 88 // ConfigureHeap (survived_since_last_expansion_, external_allocation_limit_) |
| 96 // Will be 4 * reserved_semispace_size_ to ensure that young | 89 // Will be 4 * reserved_semispace_size_ to ensure that young |
| 97 // generation can be aligned to its size. | 90 // generation can be aligned to its size. |
| 98 survived_since_last_expansion_(0), | 91 survived_since_last_expansion_(0), |
| 99 sweep_generation_(0), | 92 sweep_generation_(0), |
| 100 always_allocate_scope_depth_(0), | 93 always_allocate_scope_depth_(0), |
| 101 linear_allocation_scope_depth_(0), | 94 linear_allocation_scope_depth_(0), |
| 102 contexts_disposed_(0), | 95 contexts_disposed_(0), |
| 96 scan_on_scavenge_pages_(0), |
| 103 new_space_(this), | 97 new_space_(this), |
| 104 old_pointer_space_(NULL), | 98 old_pointer_space_(NULL), |
| 105 old_data_space_(NULL), | 99 old_data_space_(NULL), |
| 106 code_space_(NULL), | 100 code_space_(NULL), |
| 107 map_space_(NULL), | 101 map_space_(NULL), |
| 108 cell_space_(NULL), | 102 cell_space_(NULL), |
| 109 lo_space_(NULL), | 103 lo_space_(NULL), |
| 110 gc_state_(NOT_IN_GC), | 104 gc_state_(NOT_IN_GC), |
| 111 gc_post_processing_depth_(0), | 105 gc_post_processing_depth_(0), |
| 112 mc_count_(0), | |
| 113 ms_count_(0), | 106 ms_count_(0), |
| 114 gc_count_(0), | 107 gc_count_(0), |
| 115 unflattened_strings_length_(0), | 108 unflattened_strings_length_(0), |
| 116 #ifdef DEBUG | 109 #ifdef DEBUG |
| 117 allocation_allowed_(true), | 110 allocation_allowed_(true), |
| 118 allocation_timeout_(0), | 111 allocation_timeout_(0), |
| 119 disallow_allocation_failure_(false), | 112 disallow_allocation_failure_(false), |
| 120 debug_utils_(NULL), | 113 debug_utils_(NULL), |
| 121 #endif // DEBUG | 114 #endif // DEBUG |
| 122 old_gen_promotion_limit_(kMinimumPromotionLimit), | 115 old_gen_promotion_limit_(kMinimumPromotionLimit), |
| 123 old_gen_allocation_limit_(kMinimumAllocationLimit), | 116 old_gen_allocation_limit_(kMinimumAllocationLimit), |
| 117 old_gen_limit_factor_(1), |
| 118 size_of_old_gen_at_last_old_space_gc_(0), |
| 124 external_allocation_limit_(0), | 119 external_allocation_limit_(0), |
| 125 amount_of_external_allocated_memory_(0), | 120 amount_of_external_allocated_memory_(0), |
| 126 amount_of_external_allocated_memory_at_last_global_gc_(0), | 121 amount_of_external_allocated_memory_at_last_global_gc_(0), |
| 127 old_gen_exhausted_(false), | 122 old_gen_exhausted_(false), |
| 123 store_buffer_rebuilder_(store_buffer()), |
| 128 hidden_symbol_(NULL), | 124 hidden_symbol_(NULL), |
| 129 global_gc_prologue_callback_(NULL), | 125 global_gc_prologue_callback_(NULL), |
| 130 global_gc_epilogue_callback_(NULL), | 126 global_gc_epilogue_callback_(NULL), |
| 131 gc_safe_size_of_old_object_(NULL), | 127 gc_safe_size_of_old_object_(NULL), |
| 132 total_regexp_code_generated_(0), | 128 total_regexp_code_generated_(0), |
| 133 tracer_(NULL), | 129 tracer_(NULL), |
| 134 young_survivors_after_last_gc_(0), | 130 young_survivors_after_last_gc_(0), |
| 135 high_survival_rate_period_length_(0), | 131 high_survival_rate_period_length_(0), |
| 136 survival_rate_(0), | 132 survival_rate_(0), |
| 137 previous_survival_rate_trend_(Heap::STABLE), | 133 previous_survival_rate_trend_(Heap::STABLE), |
| 138 survival_rate_trend_(Heap::STABLE), | 134 survival_rate_trend_(Heap::STABLE), |
| 139 max_gc_pause_(0), | 135 max_gc_pause_(0), |
| 140 max_alive_after_gc_(0), | 136 max_alive_after_gc_(0), |
| 141 min_in_mutator_(kMaxInt), | 137 min_in_mutator_(kMaxInt), |
| 142 alive_after_last_gc_(0), | 138 alive_after_last_gc_(0), |
| 143 last_gc_end_timestamp_(0.0), | 139 last_gc_end_timestamp_(0.0), |
| 144 page_watermark_invalidated_mark_(1 << Page::WATERMARK_INVALIDATED), | 140 store_buffer_(this), |
| 141 marking_(this), |
| 142 incremental_marking_(this), |
| 145 number_idle_notifications_(0), | 143 number_idle_notifications_(0), |
| 146 last_idle_notification_gc_count_(0), | 144 last_idle_notification_gc_count_(0), |
| 147 last_idle_notification_gc_count_init_(false), | 145 last_idle_notification_gc_count_init_(false), |
| 148 configured_(false), | 146 configured_(false), |
| 149 is_safe_to_read_maps_(true) { | 147 last_empty_page_was_given_back_to_the_os_(false), |
| 148 chunks_queued_for_free_(NULL) { |
| 150 // Allow build-time customization of the max semispace size. Building | 149 // Allow build-time customization of the max semispace size. Building |
| 151 // V8 with snapshots and a non-default max semispace size is much | 150 // V8 with snapshots and a non-default max semispace size is much |
| 152 // easier if you can define it as part of the build environment. | 151 // easier if you can define it as part of the build environment. |
| 153 #if defined(V8_MAX_SEMISPACE_SIZE) | 152 #if defined(V8_MAX_SEMISPACE_SIZE) |
| 154 max_semispace_size_ = reserved_semispace_size_ = V8_MAX_SEMISPACE_SIZE; | 153 max_semispace_size_ = reserved_semispace_size_ = V8_MAX_SEMISPACE_SIZE; |
| 155 #endif | 154 #endif |
| 156 | 155 |
| 157 intptr_t max_virtual = OS::MaxVirtualMemory(); | 156 intptr_t max_virtual = OS::MaxVirtualMemory(); |
| 158 | 157 |
| 159 if (max_virtual > 0) { | 158 if (max_virtual > 0) { |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 return old_pointer_space_ != NULL && | 216 return old_pointer_space_ != NULL && |
| 218 old_data_space_ != NULL && | 217 old_data_space_ != NULL && |
| 219 code_space_ != NULL && | 218 code_space_ != NULL && |
| 220 map_space_ != NULL && | 219 map_space_ != NULL && |
| 221 cell_space_ != NULL && | 220 cell_space_ != NULL && |
| 222 lo_space_ != NULL; | 221 lo_space_ != NULL; |
| 223 } | 222 } |
| 224 | 223 |
| 225 | 224 |
| 226 int Heap::GcSafeSizeOfOldObject(HeapObject* object) { | 225 int Heap::GcSafeSizeOfOldObject(HeapObject* object) { |
| 227 ASSERT(!HEAP->InNewSpace(object)); // Code only works for old objects. | 226 if (IntrusiveMarking::IsMarked(object)) { |
| 228 ASSERT(!HEAP->mark_compact_collector()->are_map_pointers_encoded()); | 227 return IntrusiveMarking::SizeOfMarkedObject(object); |
| 229 MapWord map_word = object->map_word(); | 228 } |
| 230 map_word.ClearMark(); | 229 return object->SizeFromMap(object->map()); |
| 231 map_word.ClearOverflow(); | |
| 232 return object->SizeFromMap(map_word.ToMap()); | |
| 233 } | 230 } |
| 234 | 231 |
| 235 | 232 |
| 236 int Heap::GcSafeSizeOfOldObjectWithEncodedMap(HeapObject* object) { | |
| 237 ASSERT(!HEAP->InNewSpace(object)); // Code only works for old objects. | |
| 238 ASSERT(HEAP->mark_compact_collector()->are_map_pointers_encoded()); | |
| 239 uint32_t marker = Memory::uint32_at(object->address()); | |
| 240 if (marker == MarkCompactCollector::kSingleFreeEncoding) { | |
| 241 return kIntSize; | |
| 242 } else if (marker == MarkCompactCollector::kMultiFreeEncoding) { | |
| 243 return Memory::int_at(object->address() + kIntSize); | |
| 244 } else { | |
| 245 MapWord map_word = object->map_word(); | |
| 246 Address map_address = map_word.DecodeMapAddress(HEAP->map_space()); | |
| 247 Map* map = reinterpret_cast<Map*>(HeapObject::FromAddress(map_address)); | |
| 248 return object->SizeFromMap(map); | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 | |
| 253 GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space) { | 233 GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space) { |
| 254 // Is global GC requested? | 234 // Is global GC requested? |
| 255 if (space != NEW_SPACE || FLAG_gc_global) { | 235 if (space != NEW_SPACE || FLAG_gc_global) { |
| 256 isolate_->counters()->gc_compactor_caused_by_request()->Increment(); | 236 isolate_->counters()->gc_compactor_caused_by_request()->Increment(); |
| 257 return MARK_COMPACTOR; | 237 return MARK_COMPACTOR; |
| 258 } | 238 } |
| 259 | 239 |
| 260 // Is enough data promoted to justify a global GC? | 240 // Is enough data promoted to justify a global GC? |
| 261 if (OldGenerationPromotionLimitReached()) { | 241 if (OldGenerationPromotionLimitReached()) { |
| 262 isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment(); | 242 isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment(); |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 393 } | 373 } |
| 394 | 374 |
| 395 if (FLAG_gc_verbose) Print(); | 375 if (FLAG_gc_verbose) Print(); |
| 396 #endif // DEBUG | 376 #endif // DEBUG |
| 397 | 377 |
| 398 #if defined(DEBUG) | 378 #if defined(DEBUG) |
| 399 ReportStatisticsBeforeGC(); | 379 ReportStatisticsBeforeGC(); |
| 400 #endif // DEBUG | 380 #endif // DEBUG |
| 401 | 381 |
| 402 LiveObjectList::GCPrologue(); | 382 LiveObjectList::GCPrologue(); |
| 383 store_buffer()->GCPrologue(); |
| 403 } | 384 } |
| 404 | 385 |
| 405 intptr_t Heap::SizeOfObjects() { | 386 intptr_t Heap::SizeOfObjects() { |
| 406 intptr_t total = 0; | 387 intptr_t total = 0; |
| 407 AllSpaces spaces; | 388 AllSpaces spaces; |
| 408 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) { | 389 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) { |
| 409 total += space->SizeOfObjects(); | 390 total += space->SizeOfObjects(); |
| 410 } | 391 } |
| 411 return total; | 392 return total; |
| 412 } | 393 } |
| 413 | 394 |
| 414 void Heap::GarbageCollectionEpilogue() { | 395 void Heap::GarbageCollectionEpilogue() { |
| 396 store_buffer()->GCEpilogue(); |
| 415 LiveObjectList::GCEpilogue(); | 397 LiveObjectList::GCEpilogue(); |
| 416 #ifdef DEBUG | 398 #ifdef DEBUG |
| 417 allow_allocation(true); | 399 allow_allocation(true); |
| 418 ZapFromSpace(); | 400 ZapFromSpace(); |
| 419 | 401 |
| 420 if (FLAG_verify_heap) { | 402 if (FLAG_verify_heap) { |
| 421 Verify(); | 403 Verify(); |
| 422 } | 404 } |
| 423 | 405 |
| 424 if (FLAG_print_global_handles) isolate_->global_handles()->Print(); | 406 if (FLAG_print_global_handles) isolate_->global_handles()->Print(); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 436 symbol_table()->NumberOfElements()); | 418 symbol_table()->NumberOfElements()); |
| 437 #if defined(DEBUG) | 419 #if defined(DEBUG) |
| 438 ReportStatisticsAfterGC(); | 420 ReportStatisticsAfterGC(); |
| 439 #endif // DEBUG | 421 #endif // DEBUG |
| 440 #ifdef ENABLE_DEBUGGER_SUPPORT | 422 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 441 isolate_->debug()->AfterGarbageCollection(); | 423 isolate_->debug()->AfterGarbageCollection(); |
| 442 #endif // ENABLE_DEBUGGER_SUPPORT | 424 #endif // ENABLE_DEBUGGER_SUPPORT |
| 443 } | 425 } |
| 444 | 426 |
| 445 | 427 |
| 446 void Heap::CollectAllGarbage(bool force_compaction) { | 428 void Heap::CollectAllGarbage(int flags) { |
| 447 // Since we are ignoring the return value, the exact choice of space does | 429 // Since we are ignoring the return value, the exact choice of space does |
| 448 // not matter, so long as we do not specify NEW_SPACE, which would not | 430 // not matter, so long as we do not specify NEW_SPACE, which would not |
| 449 // cause a full GC. | 431 // cause a full GC. |
| 450 mark_compact_collector_.SetForceCompaction(force_compaction); | 432 mark_compact_collector_.SetFlags(flags); |
| 451 CollectGarbage(OLD_POINTER_SPACE); | 433 CollectGarbage(OLD_POINTER_SPACE); |
| 452 mark_compact_collector_.SetForceCompaction(false); | 434 mark_compact_collector_.SetFlags(kNoGCFlags); |
| 453 } | 435 } |
| 454 | 436 |
| 455 | 437 |
| 456 void Heap::CollectAllAvailableGarbage() { | 438 void Heap::CollectAllAvailableGarbage() { |
| 457 // Since we are ignoring the return value, the exact choice of space does | 439 // Since we are ignoring the return value, the exact choice of space does |
| 458 // not matter, so long as we do not specify NEW_SPACE, which would not | 440 // not matter, so long as we do not specify NEW_SPACE, which would not |
| 459 // cause a full GC. | 441 // cause a full GC. |
| 460 mark_compact_collector()->SetForceCompaction(true); | |
| 461 | |
| 462 // Major GC would invoke weak handle callbacks on weakly reachable | 442 // Major GC would invoke weak handle callbacks on weakly reachable |
| 463 // handles, but won't collect weakly reachable objects until next | 443 // handles, but won't collect weakly reachable objects until next |
| 464 // major GC. Therefore if we collect aggressively and weak handle callback | 444 // major GC. Therefore if we collect aggressively and weak handle callback |
| 465 // has been invoked, we rerun major GC to release objects which become | 445 // has been invoked, we rerun major GC to release objects which become |
| 466 // garbage. | 446 // garbage. |
| 467 // Note: as weak callbacks can execute arbitrary code, we cannot | 447 // Note: as weak callbacks can execute arbitrary code, we cannot |
| 468 // hope that eventually there will be no weak callbacks invocations. | 448 // hope that eventually there will be no weak callbacks invocations. |
| 469 // Therefore stop recollecting after several attempts. | 449 // Therefore stop recollecting after several attempts. |
| 450 mark_compact_collector()->SetFlags(kMakeHeapIterableMask); |
| 470 const int kMaxNumberOfAttempts = 7; | 451 const int kMaxNumberOfAttempts = 7; |
| 471 for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) { | 452 for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) { |
| 472 if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR)) { | 453 if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR)) { |
| 473 break; | 454 break; |
| 474 } | 455 } |
| 475 } | 456 } |
| 476 mark_compact_collector()->SetForceCompaction(false); | 457 mark_compact_collector()->SetFlags(kNoGCFlags); |
| 477 } | 458 } |
| 478 | 459 |
| 479 | 460 |
| 480 bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) { | 461 bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) { |
| 481 // The VM is in the GC state until exiting this function. | 462 // The VM is in the GC state until exiting this function. |
| 482 VMState state(isolate_, GC); | 463 VMState state(isolate_, GC); |
| 483 | 464 |
| 484 #ifdef DEBUG | 465 #ifdef DEBUG |
| 485 // Reset the allocation timeout to the GC interval, but make sure to | 466 // Reset the allocation timeout to the GC interval, but make sure to |
| 486 // allow at least a few allocations after a collection. The reason | 467 // allow at least a few allocations after a collection. The reason |
| 487 // for this is that we have a lot of allocation sequences and we | 468 // for this is that we have a lot of allocation sequences and we |
| 488 // assume that a garbage collection will allow the subsequent | 469 // assume that a garbage collection will allow the subsequent |
| 489 // allocation attempts to go through. | 470 // allocation attempts to go through. |
| 490 allocation_timeout_ = Max(6, FLAG_gc_interval); | 471 allocation_timeout_ = Max(6, FLAG_gc_interval); |
| 491 #endif | 472 #endif |
| 492 | 473 |
| 474 if (collector == SCAVENGER && !incremental_marking()->IsStopped()) { |
| 475 if (FLAG_trace_incremental_marking) { |
| 476 PrintF("[IncrementalMarking] Scavenge during marking.\n"); |
| 477 } |
| 478 } |
| 479 |
| 480 if (collector == MARK_COMPACTOR && |
| 481 !mark_compact_collector()->PreciseSweepingRequired() && |
| 482 !incremental_marking()->IsStopped() && |
| 483 !incremental_marking()->should_hurry() && |
| 484 FLAG_incremental_marking_steps) { |
| 485 if (FLAG_trace_incremental_marking) { |
| 486 PrintF("[IncrementalMarking] Delaying MarkSweep.\n"); |
| 487 } |
| 488 collector = SCAVENGER; |
| 489 } |
| 490 |
| 493 bool next_gc_likely_to_collect_more = false; | 491 bool next_gc_likely_to_collect_more = false; |
| 494 | 492 |
| 495 { GCTracer tracer(this); | 493 { GCTracer tracer(this); |
| 496 GarbageCollectionPrologue(); | 494 GarbageCollectionPrologue(); |
| 497 // The GC count was incremented in the prologue. Tell the tracer about | 495 // The GC count was incremented in the prologue. Tell the tracer about |
| 498 // it. | 496 // it. |
| 499 tracer.set_gc_count(gc_count_); | 497 tracer.set_gc_count(gc_count_); |
| 500 | 498 |
| 501 // Tell the tracer which collector we've selected. | 499 // Tell the tracer which collector we've selected. |
| 502 tracer.set_collector(collector); | 500 tracer.set_collector(collector); |
| 503 | 501 |
| 504 HistogramTimer* rate = (collector == SCAVENGER) | 502 HistogramTimer* rate = (collector == SCAVENGER) |
| 505 ? isolate_->counters()->gc_scavenger() | 503 ? isolate_->counters()->gc_scavenger() |
| 506 : isolate_->counters()->gc_compactor(); | 504 : isolate_->counters()->gc_compactor(); |
| 507 rate->Start(); | 505 rate->Start(); |
| 508 next_gc_likely_to_collect_more = | 506 next_gc_likely_to_collect_more = |
| 509 PerformGarbageCollection(collector, &tracer); | 507 PerformGarbageCollection(collector, &tracer); |
| 510 rate->Stop(); | 508 rate->Stop(); |
| 511 | 509 |
| 512 GarbageCollectionEpilogue(); | 510 GarbageCollectionEpilogue(); |
| 513 } | 511 } |
| 514 | 512 |
| 513 ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped()); |
| 514 if (incremental_marking()->IsStopped()) { |
| 515 if (incremental_marking()->WorthActivating() && NextGCIsLikelyToBeFull()) { |
| 516 incremental_marking()->Start(); |
| 517 } |
| 518 } |
| 519 |
| 515 return next_gc_likely_to_collect_more; | 520 return next_gc_likely_to_collect_more; |
| 516 } | 521 } |
| 517 | 522 |
| 518 | 523 |
| 519 void Heap::PerformScavenge() { | 524 void Heap::PerformScavenge() { |
| 520 GCTracer tracer(this); | 525 GCTracer tracer(this); |
| 521 PerformGarbageCollection(SCAVENGER, &tracer); | 526 if (incremental_marking()->IsStopped()) { |
| 527 PerformGarbageCollection(SCAVENGER, &tracer); |
| 528 } else { |
| 529 PerformGarbageCollection(MARK_COMPACTOR, &tracer); |
| 530 } |
| 522 } | 531 } |
| 523 | 532 |
| 524 | 533 |
| 525 #ifdef DEBUG | 534 #ifdef DEBUG |
| 526 // Helper class for verifying the symbol table. | 535 // Helper class for verifying the symbol table. |
| 527 class SymbolTableVerifier : public ObjectVisitor { | 536 class SymbolTableVerifier : public ObjectVisitor { |
| 528 public: | 537 public: |
| 529 void VisitPointers(Object** start, Object** end) { | 538 void VisitPointers(Object** start, Object** end) { |
| 530 // Visit all HeapObject pointers in [start, end). | 539 // Visit all HeapObject pointers in [start, end). |
| 531 for (Object** p = start; p < end; p++) { | 540 for (Object** p = start; p < end; p++) { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 603 } | 612 } |
| 604 } | 613 } |
| 605 } | 614 } |
| 606 | 615 |
| 607 | 616 |
| 608 void Heap::EnsureFromSpaceIsCommitted() { | 617 void Heap::EnsureFromSpaceIsCommitted() { |
| 609 if (new_space_.CommitFromSpaceIfNeeded()) return; | 618 if (new_space_.CommitFromSpaceIfNeeded()) return; |
| 610 | 619 |
| 611 // Committing memory to from space failed. | 620 // Committing memory to from space failed. |
| 612 // Try shrinking and try again. | 621 // Try shrinking and try again. |
| 613 PagedSpaces spaces; | |
| 614 for (PagedSpace* space = spaces.next(); | |
| 615 space != NULL; | |
| 616 space = spaces.next()) { | |
| 617 space->RelinkPageListInChunkOrder(true); | |
| 618 } | |
| 619 | |
| 620 Shrink(); | 622 Shrink(); |
| 621 if (new_space_.CommitFromSpaceIfNeeded()) return; | 623 if (new_space_.CommitFromSpaceIfNeeded()) return; |
| 622 | 624 |
| 623 // Committing memory to from space failed again. | 625 // Committing memory to from space failed again. |
| 624 // Memory is exhausted and we will die. | 626 // Memory is exhausted and we will die. |
| 625 V8::FatalProcessOutOfMemory("Committing semi space failed."); | 627 V8::FatalProcessOutOfMemory("Committing semi space failed."); |
| 626 } | 628 } |
| 627 | 629 |
| 628 | 630 |
| 629 void Heap::ClearJSFunctionResultCaches() { | 631 void Heap::ClearJSFunctionResultCaches() { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 640 JSFunctionResultCache::cast(caches->get(i))->Clear(); | 642 JSFunctionResultCache::cast(caches->get(i))->Clear(); |
| 641 } | 643 } |
| 642 // Get the next context: | 644 // Get the next context: |
| 643 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); | 645 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); |
| 644 } | 646 } |
| 645 } | 647 } |
| 646 | 648 |
| 647 | 649 |
| 648 | 650 |
| 649 void Heap::ClearNormalizedMapCaches() { | 651 void Heap::ClearNormalizedMapCaches() { |
| 650 if (isolate_->bootstrapper()->IsActive()) return; | 652 if (isolate_->bootstrapper()->IsActive() && |
| 653 !incremental_marking()->IsMarking()) { |
| 654 return; |
| 655 } |
| 651 | 656 |
| 652 Object* context = global_contexts_list_; | 657 Object* context = global_contexts_list_; |
| 653 while (!context->IsUndefined()) { | 658 while (!context->IsUndefined()) { |
| 654 Context::cast(context)->normalized_map_cache()->Clear(); | 659 Context::cast(context)->normalized_map_cache()->Clear(); |
| 655 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); | 660 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); |
| 656 } | 661 } |
| 657 } | 662 } |
| 658 | 663 |
| 659 | 664 |
| 660 #ifdef DEBUG | |
| 661 | |
| 662 enum PageWatermarkValidity { | |
| 663 ALL_VALID, | |
| 664 ALL_INVALID | |
| 665 }; | |
| 666 | |
| 667 static void VerifyPageWatermarkValidity(PagedSpace* space, | |
| 668 PageWatermarkValidity validity) { | |
| 669 PageIterator it(space, PageIterator::PAGES_IN_USE); | |
| 670 bool expected_value = (validity == ALL_VALID); | |
| 671 while (it.has_next()) { | |
| 672 Page* page = it.next(); | |
| 673 ASSERT(page->IsWatermarkValid() == expected_value); | |
| 674 } | |
| 675 } | |
| 676 #endif | |
| 677 | |
| 678 void Heap::UpdateSurvivalRateTrend(int start_new_space_size) { | 665 void Heap::UpdateSurvivalRateTrend(int start_new_space_size) { |
| 679 double survival_rate = | 666 double survival_rate = |
| 680 (static_cast<double>(young_survivors_after_last_gc_) * 100) / | 667 (static_cast<double>(young_survivors_after_last_gc_) * 100) / |
| 681 start_new_space_size; | 668 start_new_space_size; |
| 682 | 669 |
| 683 if (survival_rate > kYoungSurvivalRateThreshold) { | 670 if (survival_rate > kYoungSurvivalRateThreshold) { |
| 684 high_survival_rate_period_length_++; | 671 high_survival_rate_period_length_++; |
| 685 } else { | 672 } else { |
| 686 high_survival_rate_period_length_ = 0; | 673 high_survival_rate_period_length_ = 0; |
| 687 } | 674 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 720 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) { | 707 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) { |
| 721 if (gc_type & gc_prologue_callbacks_[i].gc_type) { | 708 if (gc_type & gc_prologue_callbacks_[i].gc_type) { |
| 722 gc_prologue_callbacks_[i].callback(gc_type, kNoGCCallbackFlags); | 709 gc_prologue_callbacks_[i].callback(gc_type, kNoGCCallbackFlags); |
| 723 } | 710 } |
| 724 } | 711 } |
| 725 | 712 |
| 726 EnsureFromSpaceIsCommitted(); | 713 EnsureFromSpaceIsCommitted(); |
| 727 | 714 |
| 728 int start_new_space_size = Heap::new_space()->SizeAsInt(); | 715 int start_new_space_size = Heap::new_space()->SizeAsInt(); |
| 729 | 716 |
| 717 if (IsHighSurvivalRate()) { |
| 718 // We speed up the incremental marker if it is running so that it |
| 719 // does not fall behind the rate of promotion, which would cause a |
| 720 // constantly growing old space. |
| 721 incremental_marking()->NotifyOfHighPromotionRate(); |
| 722 } |
| 723 |
| 730 if (collector == MARK_COMPACTOR) { | 724 if (collector == MARK_COMPACTOR) { |
| 731 // Perform mark-sweep with optional compaction. | 725 // Perform mark-sweep with optional compaction. |
| 732 MarkCompact(tracer); | 726 MarkCompact(tracer); |
| 733 sweep_generation_++; | 727 sweep_generation_++; |
| 734 bool high_survival_rate_during_scavenges = IsHighSurvivalRate() && | 728 bool high_survival_rate_during_scavenges = IsHighSurvivalRate() && |
| 735 IsStableOrIncreasingSurvivalTrend(); | 729 IsStableOrIncreasingSurvivalTrend(); |
| 736 | 730 |
| 737 UpdateSurvivalRateTrend(start_new_space_size); | 731 UpdateSurvivalRateTrend(start_new_space_size); |
| 738 | 732 |
| 739 intptr_t old_gen_size = PromotedSpaceSize(); | 733 size_of_old_gen_at_last_old_space_gc_ = PromotedSpaceSize(); |
| 740 old_gen_promotion_limit_ = | |
| 741 old_gen_size + Max(kMinimumPromotionLimit, old_gen_size / 3); | |
| 742 old_gen_allocation_limit_ = | |
| 743 old_gen_size + Max(kMinimumAllocationLimit, old_gen_size / 2); | |
| 744 | 734 |
| 745 if (high_survival_rate_during_scavenges && | 735 if (high_survival_rate_during_scavenges && |
| 746 IsStableOrIncreasingSurvivalTrend()) { | 736 IsStableOrIncreasingSurvivalTrend()) { |
| 747 // Stable high survival rates of young objects both during partial and | 737 // Stable high survival rates of young objects both during partial and |
| 748 // full collection indicate that mutator is either building or modifying | 738 // full collection indicate that mutator is either building or modifying |
| 749 // a structure with a long lifetime. | 739 // a structure with a long lifetime. |
| 750 // In this case we aggressively raise old generation memory limits to | 740 // In this case we aggressively raise old generation memory limits to |
| 751 // postpone subsequent mark-sweep collection and thus trade memory | 741 // postpone subsequent mark-sweep collection and thus trade memory |
| 752 // space for the mutation speed. | 742 // space for the mutation speed. |
| 753 old_gen_promotion_limit_ *= 2; | 743 old_gen_limit_factor_ = 2; |
| 754 old_gen_allocation_limit_ *= 2; | 744 } else { |
| 745 old_gen_limit_factor_ = 1; |
| 755 } | 746 } |
| 756 | 747 |
| 748 old_gen_promotion_limit_ = |
| 749 OldGenPromotionLimit(size_of_old_gen_at_last_old_space_gc_); |
| 750 old_gen_allocation_limit_ = |
| 751 OldGenAllocationLimit(size_of_old_gen_at_last_old_space_gc_); |
| 752 |
| 757 old_gen_exhausted_ = false; | 753 old_gen_exhausted_ = false; |
| 758 } else { | 754 } else { |
| 759 tracer_ = tracer; | 755 tracer_ = tracer; |
| 760 Scavenge(); | 756 Scavenge(); |
| 761 tracer_ = NULL; | 757 tracer_ = NULL; |
| 762 | 758 |
| 763 UpdateSurvivalRateTrend(start_new_space_size); | 759 UpdateSurvivalRateTrend(start_new_space_size); |
| 764 } | 760 } |
| 765 | 761 |
| 766 isolate_->counters()->objs_since_last_young()->Set(0); | 762 isolate_->counters()->objs_since_last_young()->Set(0); |
| 767 | 763 |
| 768 gc_post_processing_depth_++; | 764 gc_post_processing_depth_++; |
| 769 { DisableAssertNoAllocation allow_allocation; | 765 { DisableAssertNoAllocation allow_allocation; |
| 770 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); | 766 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); |
| 771 next_gc_likely_to_collect_more = | 767 next_gc_likely_to_collect_more = |
| 772 isolate_->global_handles()->PostGarbageCollectionProcessing(collector); | 768 isolate_->global_handles()->PostGarbageCollectionProcessing(collector); |
| 773 } | 769 } |
| 774 gc_post_processing_depth_--; | 770 gc_post_processing_depth_--; |
| 775 | 771 |
| 776 // Update relocatables. | 772 // Update relocatables. |
| 777 Relocatable::PostGarbageCollectionProcessing(); | 773 Relocatable::PostGarbageCollectionProcessing(); |
| 778 | 774 |
| 779 if (collector == MARK_COMPACTOR) { | 775 if (collector == MARK_COMPACTOR) { |
| 780 // Register the amount of external allocated memory. | 776 // Register the amount of external allocated memory. |
| 781 amount_of_external_allocated_memory_at_last_global_gc_ = | 777 amount_of_external_allocated_memory_at_last_global_gc_ = |
| 782 amount_of_external_allocated_memory_; | 778 amount_of_external_allocated_memory_; |
| 783 } | 779 } |
| 784 | 780 |
| 785 GCCallbackFlags callback_flags = tracer->is_compacting() | 781 GCCallbackFlags callback_flags = kNoGCCallbackFlags; |
| 786 ? kGCCallbackFlagCompacted | |
| 787 : kNoGCCallbackFlags; | |
| 788 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) { | 782 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) { |
| 789 if (gc_type & gc_epilogue_callbacks_[i].gc_type) { | 783 if (gc_type & gc_epilogue_callbacks_[i].gc_type) { |
| 790 gc_epilogue_callbacks_[i].callback(gc_type, callback_flags); | 784 gc_epilogue_callbacks_[i].callback(gc_type, callback_flags); |
| 791 } | 785 } |
| 792 } | 786 } |
| 793 | 787 |
| 794 if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) { | 788 if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) { |
| 795 ASSERT(!allocation_allowed_); | 789 ASSERT(!allocation_allowed_); |
| 796 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); | 790 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); |
| 797 global_gc_epilogue_callback_(); | 791 global_gc_epilogue_callback_(); |
| 798 } | 792 } |
| 799 VerifySymbolTable(); | 793 VerifySymbolTable(); |
| 800 | 794 |
| 801 return next_gc_likely_to_collect_more; | 795 return next_gc_likely_to_collect_more; |
| 802 } | 796 } |
| 803 | 797 |
| 804 | 798 |
| 805 void Heap::MarkCompact(GCTracer* tracer) { | 799 void Heap::MarkCompact(GCTracer* tracer) { |
| 806 gc_state_ = MARK_COMPACT; | 800 gc_state_ = MARK_COMPACT; |
| 807 LOG(isolate_, ResourceEvent("markcompact", "begin")); | 801 LOG(isolate_, ResourceEvent("markcompact", "begin")); |
| 808 | 802 |
| 809 mark_compact_collector_.Prepare(tracer); | 803 mark_compact_collector_.Prepare(tracer); |
| 810 | 804 |
| 811 bool is_compacting = mark_compact_collector_.IsCompacting(); | 805 ms_count_++; |
| 806 tracer->set_full_gc_count(ms_count_); |
| 812 | 807 |
| 813 if (is_compacting) { | 808 MarkCompactPrologue(); |
| 814 mc_count_++; | |
| 815 } else { | |
| 816 ms_count_++; | |
| 817 } | |
| 818 tracer->set_full_gc_count(mc_count_ + ms_count_); | |
| 819 | 809 |
| 820 MarkCompactPrologue(is_compacting); | |
| 821 | |
| 822 is_safe_to_read_maps_ = false; | |
| 823 mark_compact_collector_.CollectGarbage(); | 810 mark_compact_collector_.CollectGarbage(); |
| 824 is_safe_to_read_maps_ = true; | |
| 825 | 811 |
| 826 LOG(isolate_, ResourceEvent("markcompact", "end")); | 812 LOG(isolate_, ResourceEvent("markcompact", "end")); |
| 827 | 813 |
| 828 gc_state_ = NOT_IN_GC; | 814 gc_state_ = NOT_IN_GC; |
| 829 | 815 |
| 830 Shrink(); | 816 Shrink(); |
| 831 | 817 |
| 832 isolate_->counters()->objs_since_last_full()->Set(0); | 818 isolate_->counters()->objs_since_last_full()->Set(0); |
| 833 | 819 |
| 834 contexts_disposed_ = 0; | 820 contexts_disposed_ = 0; |
| 835 } | 821 } |
| 836 | 822 |
| 837 | 823 |
| 838 void Heap::MarkCompactPrologue(bool is_compacting) { | 824 void Heap::MarkCompactPrologue() { |
| 839 // At any old GC clear the keyed lookup cache to enable collection of unused | 825 // At any old GC clear the keyed lookup cache to enable collection of unused |
| 840 // maps. | 826 // maps. |
| 841 isolate_->keyed_lookup_cache()->Clear(); | 827 isolate_->keyed_lookup_cache()->Clear(); |
| 842 isolate_->context_slot_cache()->Clear(); | 828 isolate_->context_slot_cache()->Clear(); |
| 843 isolate_->descriptor_lookup_cache()->Clear(); | 829 isolate_->descriptor_lookup_cache()->Clear(); |
| 844 StringSplitCache::Clear(string_split_cache()); | 830 StringSplitCache::Clear(string_split_cache()); |
| 845 | 831 |
| 846 isolate_->compilation_cache()->MarkCompactPrologue(); | 832 isolate_->compilation_cache()->MarkCompactPrologue(); |
| 847 | 833 |
| 848 CompletelyClearInstanceofCache(); | 834 CompletelyClearInstanceofCache(); |
| 849 | 835 |
| 850 if (is_compacting) FlushNumberStringCache(); | 836 // TODO(1605) select heuristic for flushing NumberString cache with |
| 837 // FlushNumberStringCache |
| 851 if (FLAG_cleanup_code_caches_at_gc) { | 838 if (FLAG_cleanup_code_caches_at_gc) { |
| 852 polymorphic_code_cache()->set_cache(undefined_value()); | 839 polymorphic_code_cache()->set_cache(undefined_value()); |
| 853 } | 840 } |
| 854 | 841 |
| 855 ClearNormalizedMapCaches(); | 842 ClearNormalizedMapCaches(); |
| 856 } | 843 } |
| 857 | 844 |
| 858 | 845 |
| 859 Object* Heap::FindCodeObject(Address a) { | 846 Object* Heap::FindCodeObject(Address a) { |
| 860 Object* obj = NULL; // Initialization to please compiler. | 847 Object* obj = NULL; // Initialization to please compiler. |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 904 } | 891 } |
| 905 } | 892 } |
| 906 }; | 893 }; |
| 907 | 894 |
| 908 | 895 |
| 909 static void VerifyNonPointerSpacePointers() { | 896 static void VerifyNonPointerSpacePointers() { |
| 910 // Verify that there are no pointers to new space in spaces where we | 897 // Verify that there are no pointers to new space in spaces where we |
| 911 // do not expect them. | 898 // do not expect them. |
| 912 VerifyNonPointerSpacePointersVisitor v; | 899 VerifyNonPointerSpacePointersVisitor v; |
| 913 HeapObjectIterator code_it(HEAP->code_space()); | 900 HeapObjectIterator code_it(HEAP->code_space()); |
| 914 for (HeapObject* object = code_it.next(); | 901 for (HeapObject* object = code_it.Next(); |
| 915 object != NULL; object = code_it.next()) | 902 object != NULL; object = code_it.Next()) |
| 916 object->Iterate(&v); | 903 object->Iterate(&v); |
| 917 | 904 |
| 918 HeapObjectIterator data_it(HEAP->old_data_space()); | 905 // The old data space was normally swept conservatively so that the iterator |
| 919 for (HeapObject* object = data_it.next(); | 906 // doesn't work, so we normally skip the next bit. |
| 920 object != NULL; object = data_it.next()) | 907 if (!HEAP->old_data_space()->was_swept_conservatively()) { |
| 921 object->Iterate(&v); | 908 HeapObjectIterator data_it(HEAP->old_data_space()); |
| 909 for (HeapObject* object = data_it.Next(); |
| 910 object != NULL; object = data_it.Next()) |
| 911 object->Iterate(&v); |
| 912 } |
| 922 } | 913 } |
| 923 #endif | 914 #endif |
| 924 | 915 |
| 925 | 916 |
| 926 void Heap::CheckNewSpaceExpansionCriteria() { | 917 void Heap::CheckNewSpaceExpansionCriteria() { |
| 927 if (new_space_.Capacity() < new_space_.MaximumCapacity() && | 918 if (new_space_.Capacity() < new_space_.MaximumCapacity() && |
| 928 survived_since_last_expansion_ > new_space_.Capacity()) { | 919 survived_since_last_expansion_ > new_space_.Capacity()) { |
| 929 // Grow the size of new space if there is room to grow and enough | 920 // Grow the size of new space if there is room to grow and enough |
| 930 // data has survived scavenge since the last expansion. | 921 // data has survived scavenge since the last expansion. |
| 931 new_space_.Grow(); | 922 new_space_.Grow(); |
| 932 survived_since_last_expansion_ = 0; | 923 survived_since_last_expansion_ = 0; |
| 933 } | 924 } |
| 934 } | 925 } |
| 935 | 926 |
| 936 | 927 |
| 937 static bool IsUnscavengedHeapObject(Heap* heap, Object** p) { | 928 static bool IsUnscavengedHeapObject(Heap* heap, Object** p) { |
| 938 return heap->InNewSpace(*p) && | 929 return heap->InNewSpace(*p) && |
| 939 !HeapObject::cast(*p)->map_word().IsForwardingAddress(); | 930 !HeapObject::cast(*p)->map_word().IsForwardingAddress(); |
| 940 } | 931 } |
| 941 | 932 |
| 942 | 933 |
| 934 void Heap::ScavengeStoreBufferCallback( |
| 935 Heap* heap, |
| 936 MemoryChunk* page, |
| 937 StoreBufferEvent event) { |
| 938 heap->store_buffer_rebuilder_.Callback(page, event); |
| 939 } |
| 940 |
| 941 |
| 942 void StoreBufferRebuilder::Callback(MemoryChunk* page, StoreBufferEvent event) { |
| 943 if (event == kStoreBufferStartScanningPagesEvent) { |
| 944 start_of_current_page_ = NULL; |
| 945 current_page_ = NULL; |
| 946 } else if (event == kStoreBufferScanningPageEvent) { |
| 947 if (current_page_ != NULL) { |
| 948 // If this page already overflowed the store buffer during this iteration. |
| 949 if (current_page_->scan_on_scavenge()) { |
| 950 // Then we should wipe out the entries that have been added for it. |
| 951 store_buffer_->SetTop(start_of_current_page_); |
| 952 } else if (store_buffer_->Top() - start_of_current_page_ >= |
| 953 (store_buffer_->Limit() - store_buffer_->Top()) >> 2) { |
| 954 // Did we find too many pointers in the previous page? The heuristic is |
| 955 // that no page can take more then 1/5 the remaining slots in the store |
| 956 // buffer. |
| 957 current_page_->set_scan_on_scavenge(true); |
| 958 store_buffer_->SetTop(start_of_current_page_); |
| 959 } else { |
| 960 // In this case the page we scanned took a reasonable number of slots in |
| 961 // the store buffer. It has now been rehabilitated and is no longer |
| 962 // marked scan_on_scavenge. |
| 963 ASSERT(!current_page_->scan_on_scavenge()); |
| 964 } |
| 965 } |
| 966 start_of_current_page_ = store_buffer_->Top(); |
| 967 current_page_ = page; |
| 968 } else if (event == kStoreBufferFullEvent) { |
| 969 // The current page overflowed the store buffer again. Wipe out its entries |
| 970 // in the store buffer and mark it scan-on-scavenge again. This may happen |
| 971 // several times while scanning. |
| 972 if (current_page_ == NULL) { |
| 973 // Store Buffer overflowed while scanning promoted objects. These are not |
| 974 // in any particular page, though they are likely to be clustered by the |
| 975 // allocation routines. |
| 976 store_buffer_->HandleFullness(); |
| 977 } else { |
| 978 // Store Buffer overflowed while scanning a particular old space page for |
| 979 // pointers to new space. |
| 980 ASSERT(current_page_ == page); |
| 981 ASSERT(page != NULL); |
| 982 current_page_->set_scan_on_scavenge(true); |
| 983 ASSERT(start_of_current_page_ != store_buffer_->Top()); |
| 984 store_buffer_->SetTop(start_of_current_page_); |
| 985 } |
| 986 } else { |
| 987 UNREACHABLE(); |
| 988 } |
| 989 } |
| 990 |
| 991 |
| 943 void Heap::Scavenge() { | 992 void Heap::Scavenge() { |
| 944 #ifdef DEBUG | 993 #ifdef DEBUG |
| 945 if (FLAG_enable_slow_asserts) VerifyNonPointerSpacePointers(); | 994 if (FLAG_enable_slow_asserts) VerifyNonPointerSpacePointers(); |
| 946 #endif | 995 #endif |
| 947 | 996 |
| 948 gc_state_ = SCAVENGE; | 997 gc_state_ = SCAVENGE; |
| 949 | 998 |
| 950 SwitchScavengingVisitorsTableIfProfilingWasEnabled(); | |
| 951 | |
| 952 Page::FlipMeaningOfInvalidatedWatermarkFlag(this); | |
| 953 #ifdef DEBUG | |
| 954 VerifyPageWatermarkValidity(old_pointer_space_, ALL_VALID); | |
| 955 VerifyPageWatermarkValidity(map_space_, ALL_VALID); | |
| 956 #endif | |
| 957 | |
| 958 // We do not update an allocation watermark of the top page during linear | |
| 959 // allocation to avoid overhead. So to maintain the watermark invariant | |
| 960 // we have to manually cache the watermark and mark the top page as having an | |
| 961 // invalid watermark. This guarantees that dirty regions iteration will use a | |
| 962 // correct watermark even if a linear allocation happens. | |
| 963 old_pointer_space_->FlushTopPageWatermark(); | |
| 964 map_space_->FlushTopPageWatermark(); | |
| 965 | |
| 966 // Implements Cheney's copying algorithm | 999 // Implements Cheney's copying algorithm |
| 967 LOG(isolate_, ResourceEvent("scavenge", "begin")); | 1000 LOG(isolate_, ResourceEvent("scavenge", "begin")); |
| 968 | 1001 |
| 969 // Clear descriptor cache. | 1002 // Clear descriptor cache. |
| 970 isolate_->descriptor_lookup_cache()->Clear(); | 1003 isolate_->descriptor_lookup_cache()->Clear(); |
| 971 | 1004 |
| 972 // Used for updating survived_since_last_expansion_ at function end. | 1005 // Used for updating survived_since_last_expansion_ at function end. |
| 973 intptr_t survived_watermark = PromotedSpaceSize(); | 1006 intptr_t survived_watermark = PromotedSpaceSize(); |
| 974 | 1007 |
| 975 CheckNewSpaceExpansionCriteria(); | 1008 CheckNewSpaceExpansionCriteria(); |
| 976 | 1009 |
| 1010 SelectScavengingVisitorsTable(); |
| 1011 |
| 1012 incremental_marking()->PrepareForScavenge(); |
| 1013 |
| 1014 old_pointer_space()->AdvanceSweeper(new_space_.Size()); |
| 1015 old_data_space()->AdvanceSweeper(new_space_.Size()); |
| 1016 |
| 977 // Flip the semispaces. After flipping, to space is empty, from space has | 1017 // Flip the semispaces. After flipping, to space is empty, from space has |
| 978 // live objects. | 1018 // live objects. |
| 979 new_space_.Flip(); | 1019 new_space_.Flip(); |
| 980 new_space_.ResetAllocationInfo(); | 1020 new_space_.ResetAllocationInfo(); |
| 981 | 1021 |
| 982 // We need to sweep newly copied objects which can be either in the | 1022 // We need to sweep newly copied objects which can be either in the |
| 983 // to space or promoted to the old generation. For to-space | 1023 // to space or promoted to the old generation. For to-space |
| 984 // objects, we treat the bottom of the to space as a queue. Newly | 1024 // objects, we treat the bottom of the to space as a queue. Newly |
| 985 // copied and unswept objects lie between a 'front' mark and the | 1025 // copied and unswept objects lie between a 'front' mark and the |
| 986 // allocation pointer. | 1026 // allocation pointer. |
| 987 // | 1027 // |
| 988 // Promoted objects can go into various old-generation spaces, and | 1028 // Promoted objects can go into various old-generation spaces, and |
| 989 // can be allocated internally in the spaces (from the free list). | 1029 // can be allocated internally in the spaces (from the free list). |
| 990 // We treat the top of the to space as a queue of addresses of | 1030 // We treat the top of the to space as a queue of addresses of |
| 991 // promoted objects. The addresses of newly promoted and unswept | 1031 // promoted objects. The addresses of newly promoted and unswept |
| 992 // objects lie between a 'front' mark and a 'rear' mark that is | 1032 // objects lie between a 'front' mark and a 'rear' mark that is |
| 993 // updated as a side effect of promoting an object. | 1033 // updated as a side effect of promoting an object. |
| 994 // | 1034 // |
| 995 // There is guaranteed to be enough room at the top of the to space | 1035 // There is guaranteed to be enough room at the top of the to space |
| 996 // for the addresses of promoted objects: every object promoted | 1036 // for the addresses of promoted objects: every object promoted |
| 997 // frees up its size in bytes from the top of the new space, and | 1037 // frees up its size in bytes from the top of the new space, and |
| 998 // objects are at least one pointer in size. | 1038 // objects are at least one pointer in size. |
| 999 Address new_space_front = new_space_.ToSpaceLow(); | 1039 Address new_space_front = new_space_.ToSpaceStart(); |
| 1000 promotion_queue_.Initialize(new_space_.ToSpaceHigh()); | 1040 promotion_queue_.Initialize(new_space_.ToSpaceEnd()); |
| 1001 | 1041 |
| 1002 is_safe_to_read_maps_ = false; | 1042 #ifdef DEBUG |
| 1043 store_buffer()->Clean(); |
| 1044 #endif |
| 1045 |
| 1003 ScavengeVisitor scavenge_visitor(this); | 1046 ScavengeVisitor scavenge_visitor(this); |
| 1004 // Copy roots. | 1047 // Copy roots. |
| 1005 IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE); | 1048 IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE); |
| 1006 | 1049 |
| 1007 // Copy objects reachable from the old generation. By definition, | 1050 // Copy objects reachable from the old generation. |
| 1008 // there are no intergenerational pointers in code or data spaces. | 1051 { |
| 1009 IterateDirtyRegions(old_pointer_space_, | 1052 StoreBufferRebuildScope scope(this, |
| 1010 &Heap::IteratePointersInDirtyRegion, | 1053 store_buffer(), |
| 1011 &ScavengePointer, | 1054 &ScavengeStoreBufferCallback); |
| 1012 WATERMARK_CAN_BE_INVALID); | 1055 store_buffer()->IteratePointersToNewSpace(&ScavengeObject); |
| 1013 | 1056 } |
| 1014 IterateDirtyRegions(map_space_, | |
| 1015 &IteratePointersInDirtyMapsRegion, | |
| 1016 &ScavengePointer, | |
| 1017 WATERMARK_CAN_BE_INVALID); | |
| 1018 | |
| 1019 lo_space_->IterateDirtyRegions(&ScavengePointer); | |
| 1020 | 1057 |
| 1021 // Copy objects reachable from cells by scavenging cell values directly. | 1058 // Copy objects reachable from cells by scavenging cell values directly. |
| 1022 HeapObjectIterator cell_iterator(cell_space_); | 1059 HeapObjectIterator cell_iterator(cell_space_); |
| 1023 for (HeapObject* cell = cell_iterator.next(); | 1060 for (HeapObject* cell = cell_iterator.Next(); |
| 1024 cell != NULL; cell = cell_iterator.next()) { | 1061 cell != NULL; cell = cell_iterator.Next()) { |
| 1025 if (cell->IsJSGlobalPropertyCell()) { | 1062 if (cell->IsJSGlobalPropertyCell()) { |
| 1026 Address value_address = | 1063 Address value_address = |
| 1027 reinterpret_cast<Address>(cell) + | 1064 reinterpret_cast<Address>(cell) + |
| 1028 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag); | 1065 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag); |
| 1029 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address)); | 1066 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address)); |
| 1030 } | 1067 } |
| 1031 } | 1068 } |
| 1032 | 1069 |
| 1033 // Scavenge object reachable from the global contexts list directly. | 1070 // Scavenge object reachable from the global contexts list directly. |
| 1034 scavenge_visitor.VisitPointer(BitCast<Object**>(&global_contexts_list_)); | 1071 scavenge_visitor.VisitPointer(BitCast<Object**>(&global_contexts_list_)); |
| 1035 | 1072 |
| 1036 new_space_front = DoScavenge(&scavenge_visitor, new_space_front); | 1073 new_space_front = DoScavenge(&scavenge_visitor, new_space_front); |
| 1037 isolate_->global_handles()->IdentifyNewSpaceWeakIndependentHandles( | 1074 isolate_->global_handles()->IdentifyNewSpaceWeakIndependentHandles( |
| 1038 &IsUnscavengedHeapObject); | 1075 &IsUnscavengedHeapObject); |
| 1039 isolate_->global_handles()->IterateNewSpaceWeakIndependentRoots( | 1076 isolate_->global_handles()->IterateNewSpaceWeakIndependentRoots( |
| 1040 &scavenge_visitor); | 1077 &scavenge_visitor); |
| 1041 new_space_front = DoScavenge(&scavenge_visitor, new_space_front); | 1078 new_space_front = DoScavenge(&scavenge_visitor, new_space_front); |
| 1042 | 1079 |
| 1043 | 1080 |
| 1044 UpdateNewSpaceReferencesInExternalStringTable( | 1081 UpdateNewSpaceReferencesInExternalStringTable( |
| 1045 &UpdateNewSpaceReferenceInExternalStringTableEntry); | 1082 &UpdateNewSpaceReferenceInExternalStringTableEntry); |
| 1046 | 1083 |
| 1047 LiveObjectList::UpdateReferencesForScavengeGC(); | 1084 LiveObjectList::UpdateReferencesForScavengeGC(); |
| 1048 isolate()->runtime_profiler()->UpdateSamplesAfterScavenge(); | 1085 isolate()->runtime_profiler()->UpdateSamplesAfterScavenge(); |
| 1086 incremental_marking()->UpdateMarkingDequeAfterScavenge(); |
| 1049 | 1087 |
| 1050 ASSERT(new_space_front == new_space_.top()); | 1088 ASSERT(new_space_front == new_space_.top()); |
| 1051 | 1089 |
| 1052 is_safe_to_read_maps_ = true; | |
| 1053 | |
| 1054 // Set age mark. | 1090 // Set age mark. |
| 1055 new_space_.set_age_mark(new_space_.top()); | 1091 new_space_.set_age_mark(new_space_.top()); |
| 1056 | 1092 |
| 1093 new_space_.LowerInlineAllocationLimit( |
| 1094 new_space_.inline_allocation_limit_step()); |
| 1095 |
| 1057 // Update how much has survived scavenge. | 1096 // Update how much has survived scavenge. |
| 1058 IncrementYoungSurvivorsCounter(static_cast<int>( | 1097 IncrementYoungSurvivorsCounter(static_cast<int>( |
| 1059 (PromotedSpaceSize() - survived_watermark) + new_space_.Size())); | 1098 (PromotedSpaceSize() - survived_watermark) + new_space_.Size())); |
| 1060 | 1099 |
| 1061 LOG(isolate_, ResourceEvent("scavenge", "end")); | 1100 LOG(isolate_, ResourceEvent("scavenge", "end")); |
| 1062 | 1101 |
| 1063 gc_state_ = NOT_IN_GC; | 1102 gc_state_ = NOT_IN_GC; |
| 1064 } | 1103 } |
| 1065 | 1104 |
| 1066 | 1105 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1105 // String got promoted. Move it to the old string list. | 1144 // String got promoted. Move it to the old string list. |
| 1106 external_string_table_.AddOldString(target); | 1145 external_string_table_.AddOldString(target); |
| 1107 } | 1146 } |
| 1108 } | 1147 } |
| 1109 | 1148 |
| 1110 ASSERT(last <= end); | 1149 ASSERT(last <= end); |
| 1111 external_string_table_.ShrinkNewStrings(static_cast<int>(last - start)); | 1150 external_string_table_.ShrinkNewStrings(static_cast<int>(last - start)); |
| 1112 } | 1151 } |
| 1113 | 1152 |
| 1114 | 1153 |
| 1154 void Heap::UpdateReferencesInExternalStringTable( |
| 1155 ExternalStringTableUpdaterCallback updater_func) { |
| 1156 |
| 1157 // Update old space string references. |
| 1158 if (external_string_table_.old_space_strings_.length() > 0) { |
| 1159 Object** start = &external_string_table_.old_space_strings_[0]; |
| 1160 Object** end = start + external_string_table_.old_space_strings_.length(); |
| 1161 for (Object** p = start; p < end; ++p) *p = updater_func(this, p); |
| 1162 } |
| 1163 |
| 1164 UpdateNewSpaceReferencesInExternalStringTable(updater_func); |
| 1165 } |
| 1166 |
| 1167 |
| 1115 static Object* ProcessFunctionWeakReferences(Heap* heap, | 1168 static Object* ProcessFunctionWeakReferences(Heap* heap, |
| 1116 Object* function, | 1169 Object* function, |
| 1117 WeakObjectRetainer* retainer) { | 1170 WeakObjectRetainer* retainer) { |
| 1118 Object* head = heap->undefined_value(); | 1171 Object* undefined = heap->undefined_value(); |
| 1172 Object* head = undefined; |
| 1119 JSFunction* tail = NULL; | 1173 JSFunction* tail = NULL; |
| 1120 Object* candidate = function; | 1174 Object* candidate = function; |
| 1121 while (candidate != heap->undefined_value()) { | 1175 while (candidate != undefined) { |
| 1122 // Check whether to keep the candidate in the list. | 1176 // Check whether to keep the candidate in the list. |
| 1123 JSFunction* candidate_function = reinterpret_cast<JSFunction*>(candidate); | 1177 JSFunction* candidate_function = reinterpret_cast<JSFunction*>(candidate); |
| 1124 Object* retain = retainer->RetainAs(candidate); | 1178 Object* retain = retainer->RetainAs(candidate); |
| 1125 if (retain != NULL) { | 1179 if (retain != NULL) { |
| 1126 if (head == heap->undefined_value()) { | 1180 if (head == undefined) { |
| 1127 // First element in the list. | 1181 // First element in the list. |
| 1128 head = candidate_function; | 1182 head = retain; |
| 1129 } else { | 1183 } else { |
| 1130 // Subsequent elements in the list. | 1184 // Subsequent elements in the list. |
| 1131 ASSERT(tail != NULL); | 1185 ASSERT(tail != NULL); |
| 1132 tail->set_next_function_link(candidate_function); | 1186 tail->set_next_function_link(retain); |
| 1133 } | 1187 } |
| 1134 // Retained function is new tail. | 1188 // Retained function is new tail. |
| 1189 candidate_function = reinterpret_cast<JSFunction*>(retain); |
| 1135 tail = candidate_function; | 1190 tail = candidate_function; |
| 1191 |
| 1192 ASSERT(retain->IsUndefined() || retain->IsJSFunction()); |
| 1193 |
| 1194 if (retain == undefined) break; |
| 1136 } | 1195 } |
| 1196 |
| 1137 // Move to next element in the list. | 1197 // Move to next element in the list. |
| 1138 candidate = candidate_function->next_function_link(); | 1198 candidate = candidate_function->next_function_link(); |
| 1139 } | 1199 } |
| 1140 | 1200 |
| 1141 // Terminate the list if there is one or more elements. | 1201 // Terminate the list if there is one or more elements. |
| 1142 if (tail != NULL) { | 1202 if (tail != NULL) { |
| 1143 tail->set_next_function_link(heap->undefined_value()); | 1203 tail->set_next_function_link(undefined); |
| 1144 } | 1204 } |
| 1145 | 1205 |
| 1146 return head; | 1206 return head; |
| 1147 } | 1207 } |
| 1148 | 1208 |
| 1149 | 1209 |
| 1150 void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) { | 1210 void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) { |
| 1151 Object* head = undefined_value(); | 1211 Object* undefined = undefined_value(); |
| 1212 Object* head = undefined; |
| 1152 Context* tail = NULL; | 1213 Context* tail = NULL; |
| 1153 Object* candidate = global_contexts_list_; | 1214 Object* candidate = global_contexts_list_; |
| 1154 while (candidate != undefined_value()) { | 1215 while (candidate != undefined) { |
| 1155 // Check whether to keep the candidate in the list. | 1216 // Check whether to keep the candidate in the list. |
| 1156 Context* candidate_context = reinterpret_cast<Context*>(candidate); | 1217 Context* candidate_context = reinterpret_cast<Context*>(candidate); |
| 1157 Object* retain = retainer->RetainAs(candidate); | 1218 Object* retain = retainer->RetainAs(candidate); |
| 1158 if (retain != NULL) { | 1219 if (retain != NULL) { |
| 1159 if (head == undefined_value()) { | 1220 if (head == undefined) { |
| 1160 // First element in the list. | 1221 // First element in the list. |
| 1161 head = candidate_context; | 1222 head = retain; |
| 1162 } else { | 1223 } else { |
| 1163 // Subsequent elements in the list. | 1224 // Subsequent elements in the list. |
| 1164 ASSERT(tail != NULL); | 1225 ASSERT(tail != NULL); |
| 1165 tail->set_unchecked(this, | 1226 tail->set_unchecked(this, |
| 1166 Context::NEXT_CONTEXT_LINK, | 1227 Context::NEXT_CONTEXT_LINK, |
| 1167 candidate_context, | 1228 retain, |
| 1168 UPDATE_WRITE_BARRIER); | 1229 UPDATE_WRITE_BARRIER); |
| 1169 } | 1230 } |
| 1170 // Retained context is new tail. | 1231 // Retained context is new tail. |
| 1232 candidate_context = reinterpret_cast<Context*>(retain); |
| 1171 tail = candidate_context; | 1233 tail = candidate_context; |
| 1172 | 1234 |
| 1235 if (retain == undefined) break; |
| 1236 |
| 1173 // Process the weak list of optimized functions for the context. | 1237 // Process the weak list of optimized functions for the context. |
| 1174 Object* function_list_head = | 1238 Object* function_list_head = |
| 1175 ProcessFunctionWeakReferences( | 1239 ProcessFunctionWeakReferences( |
| 1176 this, | 1240 this, |
| 1177 candidate_context->get(Context::OPTIMIZED_FUNCTIONS_LIST), | 1241 candidate_context->get(Context::OPTIMIZED_FUNCTIONS_LIST), |
| 1178 retainer); | 1242 retainer); |
| 1179 candidate_context->set_unchecked(this, | 1243 candidate_context->set_unchecked(this, |
| 1180 Context::OPTIMIZED_FUNCTIONS_LIST, | 1244 Context::OPTIMIZED_FUNCTIONS_LIST, |
| 1181 function_list_head, | 1245 function_list_head, |
| 1182 UPDATE_WRITE_BARRIER); | 1246 UPDATE_WRITE_BARRIER); |
| 1183 } | 1247 } |
| 1248 |
| 1184 // Move to next element in the list. | 1249 // Move to next element in the list. |
| 1185 candidate = candidate_context->get(Context::NEXT_CONTEXT_LINK); | 1250 candidate = candidate_context->get(Context::NEXT_CONTEXT_LINK); |
| 1186 } | 1251 } |
| 1187 | 1252 |
| 1188 // Terminate the list if there is one or more elements. | 1253 // Terminate the list if there is one or more elements. |
| 1189 if (tail != NULL) { | 1254 if (tail != NULL) { |
| 1190 tail->set_unchecked(this, | 1255 tail->set_unchecked(this, |
| 1191 Context::NEXT_CONTEXT_LINK, | 1256 Context::NEXT_CONTEXT_LINK, |
| 1192 Heap::undefined_value(), | 1257 Heap::undefined_value(), |
| 1193 UPDATE_WRITE_BARRIER); | 1258 UPDATE_WRITE_BARRIER); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1205 if (!heap->InNewSpace(object)) return; | 1270 if (!heap->InNewSpace(object)) return; |
| 1206 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p), | 1271 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p), |
| 1207 reinterpret_cast<HeapObject*>(object)); | 1272 reinterpret_cast<HeapObject*>(object)); |
| 1208 } | 1273 } |
| 1209 }; | 1274 }; |
| 1210 | 1275 |
| 1211 | 1276 |
| 1212 Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor, | 1277 Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor, |
| 1213 Address new_space_front) { | 1278 Address new_space_front) { |
| 1214 do { | 1279 do { |
| 1215 ASSERT(new_space_front <= new_space_.top()); | 1280 SemiSpace::AssertValidRange(new_space_front, new_space_.top()); |
| 1216 | |
| 1217 // The addresses new_space_front and new_space_.top() define a | 1281 // The addresses new_space_front and new_space_.top() define a |
| 1218 // queue of unprocessed copied objects. Process them until the | 1282 // queue of unprocessed copied objects. Process them until the |
| 1219 // queue is empty. | 1283 // queue is empty. |
| 1220 while (new_space_front < new_space_.top()) { | 1284 while (new_space_front != new_space_.top()) { |
| 1221 HeapObject* object = HeapObject::FromAddress(new_space_front); | 1285 if (!NewSpacePage::IsAtEnd(new_space_front)) { |
| 1222 new_space_front += NewSpaceScavenger::IterateBody(object->map(), object); | 1286 HeapObject* object = HeapObject::FromAddress(new_space_front); |
| 1287 new_space_front += |
| 1288 NewSpaceScavenger::IterateBody(object->map(), object); |
| 1289 } else { |
| 1290 new_space_front = |
| 1291 NewSpacePage::FromLimit(new_space_front)->next_page()->body(); |
| 1292 } |
| 1223 } | 1293 } |
| 1224 | 1294 |
| 1225 // Promote and process all the to-be-promoted objects. | 1295 // Promote and process all the to-be-promoted objects. |
| 1226 while (!promotion_queue_.is_empty()) { | 1296 { |
| 1227 HeapObject* target; | 1297 StoreBufferRebuildScope scope(this, |
| 1228 int size; | 1298 store_buffer(), |
| 1229 promotion_queue_.remove(&target, &size); | 1299 &ScavengeStoreBufferCallback); |
| 1300 while (!promotion_queue()->is_empty()) { |
| 1301 HeapObject* target; |
| 1302 int size; |
| 1303 promotion_queue()->remove(&target, &size); |
| 1230 | 1304 |
| 1231 // Promoted object might be already partially visited | 1305 // Promoted object might be already partially visited |
| 1232 // during dirty regions iteration. Thus we search specificly | 1306 // during old space pointer iteration. Thus we search specificly |
| 1233 // for pointers to from semispace instead of looking for pointers | 1307 // for pointers to from semispace instead of looking for pointers |
| 1234 // to new space. | 1308 // to new space. |
| 1235 ASSERT(!target->IsMap()); | 1309 ASSERT(!target->IsMap()); |
| 1236 IterateAndMarkPointersToFromSpace(target->address(), | 1310 IterateAndMarkPointersToFromSpace(target->address(), |
| 1237 target->address() + size, | 1311 target->address() + size, |
| 1238 &ScavengePointer); | 1312 &ScavengeObject); |
| 1313 } |
| 1239 } | 1314 } |
| 1240 | 1315 |
| 1241 // Take another spin if there are now unswept objects in new space | 1316 // Take another spin if there are now unswept objects in new space |
| 1242 // (there are currently no more unswept promoted objects). | 1317 // (there are currently no more unswept promoted objects). |
| 1243 } while (new_space_front < new_space_.top()); | 1318 } while (new_space_front != new_space_.top()); |
| 1244 | 1319 |
| 1245 return new_space_front; | 1320 return new_space_front; |
| 1246 } | 1321 } |
| 1247 | 1322 |
| 1248 | 1323 |
| 1249 enum LoggingAndProfiling { | 1324 enum LoggingAndProfiling { |
| 1250 LOGGING_AND_PROFILING_ENABLED, | 1325 LOGGING_AND_PROFILING_ENABLED, |
| 1251 LOGGING_AND_PROFILING_DISABLED | 1326 LOGGING_AND_PROFILING_DISABLED |
| 1252 }; | 1327 }; |
| 1253 | 1328 |
| 1254 | 1329 |
| 1255 typedef void (*ScavengingCallback)(Map* map, | 1330 enum MarksHandling { TRANSFER_MARKS, IGNORE_MARKS }; |
| 1256 HeapObject** slot, | |
| 1257 HeapObject* object); | |
| 1258 | 1331 |
| 1259 | 1332 |
| 1260 static Atomic32 scavenging_visitors_table_mode_; | 1333 template<MarksHandling marks_handling, |
| 1261 static VisitorDispatchTable<ScavengingCallback> scavenging_visitors_table_; | 1334 LoggingAndProfiling logging_and_profiling_mode> |
| 1262 | |
| 1263 | |
| 1264 INLINE(static void DoScavengeObject(Map* map, | |
| 1265 HeapObject** slot, | |
| 1266 HeapObject* obj)); | |
| 1267 | |
| 1268 | |
| 1269 void DoScavengeObject(Map* map, HeapObject** slot, HeapObject* obj) { | |
| 1270 scavenging_visitors_table_.GetVisitor(map)(map, slot, obj); | |
| 1271 } | |
| 1272 | |
| 1273 | |
| 1274 template<LoggingAndProfiling logging_and_profiling_mode> | |
| 1275 class ScavengingVisitor : public StaticVisitorBase { | 1335 class ScavengingVisitor : public StaticVisitorBase { |
| 1276 public: | 1336 public: |
| 1277 static void Initialize() { | 1337 static void Initialize() { |
| 1278 table_.Register(kVisitSeqAsciiString, &EvacuateSeqAsciiString); | 1338 table_.Register(kVisitSeqAsciiString, &EvacuateSeqAsciiString); |
| 1279 table_.Register(kVisitSeqTwoByteString, &EvacuateSeqTwoByteString); | 1339 table_.Register(kVisitSeqTwoByteString, &EvacuateSeqTwoByteString); |
| 1280 table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate); | 1340 table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate); |
| 1281 table_.Register(kVisitByteArray, &EvacuateByteArray); | 1341 table_.Register(kVisitByteArray, &EvacuateByteArray); |
| 1282 table_.Register(kVisitFixedArray, &EvacuateFixedArray); | 1342 table_.Register(kVisitFixedArray, &EvacuateFixedArray); |
| 1283 table_.Register(kVisitFixedDoubleArray, &EvacuateFixedDoubleArray); | 1343 table_.Register(kVisitFixedDoubleArray, &EvacuateFixedDoubleArray); |
| 1284 | 1344 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1299 template VisitSpecialized<SharedFunctionInfo::kSize>); | 1359 template VisitSpecialized<SharedFunctionInfo::kSize>); |
| 1300 | 1360 |
| 1301 table_.Register(kVisitJSWeakMap, | 1361 table_.Register(kVisitJSWeakMap, |
| 1302 &ObjectEvacuationStrategy<POINTER_OBJECT>:: | 1362 &ObjectEvacuationStrategy<POINTER_OBJECT>:: |
| 1303 Visit); | 1363 Visit); |
| 1304 | 1364 |
| 1305 table_.Register(kVisitJSRegExp, | 1365 table_.Register(kVisitJSRegExp, |
| 1306 &ObjectEvacuationStrategy<POINTER_OBJECT>:: | 1366 &ObjectEvacuationStrategy<POINTER_OBJECT>:: |
| 1307 Visit); | 1367 Visit); |
| 1308 | 1368 |
| 1309 table_.Register(kVisitJSFunction, | 1369 if (marks_handling == IGNORE_MARKS) { |
| 1310 &ObjectEvacuationStrategy<POINTER_OBJECT>:: | 1370 table_.Register(kVisitJSFunction, |
| 1311 template VisitSpecialized<JSFunction::kSize>); | 1371 &ObjectEvacuationStrategy<POINTER_OBJECT>:: |
| 1372 template VisitSpecialized<JSFunction::kSize>); |
| 1373 } else { |
| 1374 table_.Register(kVisitJSFunction, &EvacuateJSFunction); |
| 1375 } |
| 1312 | 1376 |
| 1313 table_.RegisterSpecializations<ObjectEvacuationStrategy<DATA_OBJECT>, | 1377 table_.RegisterSpecializations<ObjectEvacuationStrategy<DATA_OBJECT>, |
| 1314 kVisitDataObject, | 1378 kVisitDataObject, |
| 1315 kVisitDataObjectGeneric>(); | 1379 kVisitDataObjectGeneric>(); |
| 1316 | 1380 |
| 1317 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>, | 1381 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>, |
| 1318 kVisitJSObject, | 1382 kVisitJSObject, |
| 1319 kVisitJSObjectGeneric>(); | 1383 kVisitJSObjectGeneric>(); |
| 1320 | 1384 |
| 1321 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>, | 1385 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>, |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1366 Isolate* isolate = heap->isolate(); | 1430 Isolate* isolate = heap->isolate(); |
| 1367 if (isolate->logger()->is_logging() || | 1431 if (isolate->logger()->is_logging() || |
| 1368 CpuProfiler::is_profiling(isolate)) { | 1432 CpuProfiler::is_profiling(isolate)) { |
| 1369 if (target->IsSharedFunctionInfo()) { | 1433 if (target->IsSharedFunctionInfo()) { |
| 1370 PROFILE(isolate, SharedFunctionInfoMoveEvent( | 1434 PROFILE(isolate, SharedFunctionInfoMoveEvent( |
| 1371 source->address(), target->address())); | 1435 source->address(), target->address())); |
| 1372 } | 1436 } |
| 1373 } | 1437 } |
| 1374 } | 1438 } |
| 1375 | 1439 |
| 1440 if (marks_handling == TRANSFER_MARKS) { |
| 1441 if (Marking::TransferColor(source, target)) { |
| 1442 MemoryChunk::IncrementLiveBytes(target->address(), size); |
| 1443 } |
| 1444 } |
| 1445 |
| 1376 return target; | 1446 return target; |
| 1377 } | 1447 } |
| 1378 | 1448 |
| 1379 | |
| 1380 template<ObjectContents object_contents, SizeRestriction size_restriction> | 1449 template<ObjectContents object_contents, SizeRestriction size_restriction> |
| 1381 static inline void EvacuateObject(Map* map, | 1450 static inline void EvacuateObject(Map* map, |
| 1382 HeapObject** slot, | 1451 HeapObject** slot, |
| 1383 HeapObject* object, | 1452 HeapObject* object, |
| 1384 int object_size) { | 1453 int object_size) { |
| 1385 ASSERT((size_restriction != SMALL) || | 1454 ASSERT((size_restriction != SMALL) || |
| 1386 (object_size <= Page::kMaxHeapObjectSize)); | 1455 (object_size <= Page::kMaxHeapObjectSize)); |
| 1387 ASSERT(object->Size() == object_size); | 1456 ASSERT(object->Size() == object_size); |
| 1388 | 1457 |
| 1389 Heap* heap = map->heap(); | 1458 Heap* heap = map->GetHeap(); |
| 1390 if (heap->ShouldBePromoted(object->address(), object_size)) { | 1459 if (heap->ShouldBePromoted(object->address(), object_size)) { |
| 1391 MaybeObject* maybe_result; | 1460 MaybeObject* maybe_result; |
| 1392 | 1461 |
| 1393 if ((size_restriction != SMALL) && | 1462 if ((size_restriction != SMALL) && |
| 1394 (object_size > Page::kMaxHeapObjectSize)) { | 1463 (object_size > Page::kMaxHeapObjectSize)) { |
| 1395 maybe_result = heap->lo_space()->AllocateRawFixedArray(object_size); | 1464 maybe_result = heap->lo_space()->AllocateRaw(object_size, |
| 1465 NOT_EXECUTABLE); |
| 1396 } else { | 1466 } else { |
| 1397 if (object_contents == DATA_OBJECT) { | 1467 if (object_contents == DATA_OBJECT) { |
| 1398 maybe_result = heap->old_data_space()->AllocateRaw(object_size); | 1468 maybe_result = heap->old_data_space()->AllocateRaw(object_size); |
| 1399 } else { | 1469 } else { |
| 1400 maybe_result = heap->old_pointer_space()->AllocateRaw(object_size); | 1470 maybe_result = heap->old_pointer_space()->AllocateRaw(object_size); |
| 1401 } | 1471 } |
| 1402 } | 1472 } |
| 1403 | 1473 |
| 1404 Object* result = NULL; // Initialization to please compiler. | 1474 Object* result = NULL; // Initialization to please compiler. |
| 1405 if (maybe_result->ToObject(&result)) { | 1475 if (maybe_result->ToObject(&result)) { |
| 1406 HeapObject* target = HeapObject::cast(result); | 1476 HeapObject* target = HeapObject::cast(result); |
| 1407 *slot = MigrateObject(heap, object , target, object_size); | 1477 *slot = MigrateObject(heap, object , target, object_size); |
| 1408 | 1478 |
| 1409 if (object_contents == POINTER_OBJECT) { | 1479 if (object_contents == POINTER_OBJECT) { |
| 1410 heap->promotion_queue()->insert(target, object_size); | 1480 heap->promotion_queue()->insert(target, object_size); |
| 1411 } | 1481 } |
| 1412 | 1482 |
| 1413 heap->tracer()->increment_promoted_objects_size(object_size); | 1483 heap->tracer()->increment_promoted_objects_size(object_size); |
| 1414 return; | 1484 return; |
| 1415 } | 1485 } |
| 1416 } | 1486 } |
| 1417 Object* result = | 1487 MaybeObject* allocation = heap->new_space()->AllocateRaw(object_size); |
| 1418 heap->new_space()->AllocateRaw(object_size)->ToObjectUnchecked(); | 1488 Object* result = allocation->ToObjectUnchecked(); |
| 1489 |
| 1419 *slot = MigrateObject(heap, object, HeapObject::cast(result), object_size); | 1490 *slot = MigrateObject(heap, object, HeapObject::cast(result), object_size); |
| 1420 return; | 1491 return; |
| 1421 } | 1492 } |
| 1422 | 1493 |
| 1423 | 1494 |
| 1495 static inline void EvacuateJSFunction(Map* map, |
| 1496 HeapObject** slot, |
| 1497 HeapObject* object) { |
| 1498 ObjectEvacuationStrategy<POINTER_OBJECT>:: |
| 1499 template VisitSpecialized<JSFunction::kSize>(map, slot, object); |
| 1500 |
| 1501 HeapObject* target = *slot; |
| 1502 MarkBit mark_bit = Marking::MarkBitFrom(target); |
| 1503 if (Marking::IsBlack(mark_bit)) { |
| 1504 // This object is black and it might not be rescanned by marker. |
| 1505 // We should explicitly record code entry slot for compaction because |
| 1506 // promotion queue processing (IterateAndMarkPointersToFromSpace) will |
| 1507 // miss it as it is not HeapObject-tagged. |
| 1508 Address code_entry_slot = |
| 1509 target->address() + JSFunction::kCodeEntryOffset; |
| 1510 Code* code = Code::cast(Code::GetObjectFromEntryAddress(code_entry_slot)); |
| 1511 map->GetHeap()->mark_compact_collector()-> |
| 1512 RecordCodeEntrySlot(code_entry_slot, code); |
| 1513 } |
| 1514 } |
| 1515 |
| 1516 |
| 1424 static inline void EvacuateFixedArray(Map* map, | 1517 static inline void EvacuateFixedArray(Map* map, |
| 1425 HeapObject** slot, | 1518 HeapObject** slot, |
| 1426 HeapObject* object) { | 1519 HeapObject* object) { |
| 1427 int object_size = FixedArray::BodyDescriptor::SizeOf(map, object); | 1520 int object_size = FixedArray::BodyDescriptor::SizeOf(map, object); |
| 1428 EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE>(map, | 1521 EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE>(map, |
| 1429 slot, | 1522 slot, |
| 1430 object, | 1523 object, |
| 1431 object_size); | 1524 object_size); |
| 1432 } | 1525 } |
| 1433 | 1526 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1472 | 1565 |
| 1473 static inline bool IsShortcutCandidate(int type) { | 1566 static inline bool IsShortcutCandidate(int type) { |
| 1474 return ((type & kShortcutTypeMask) == kShortcutTypeTag); | 1567 return ((type & kShortcutTypeMask) == kShortcutTypeTag); |
| 1475 } | 1568 } |
| 1476 | 1569 |
| 1477 static inline void EvacuateShortcutCandidate(Map* map, | 1570 static inline void EvacuateShortcutCandidate(Map* map, |
| 1478 HeapObject** slot, | 1571 HeapObject** slot, |
| 1479 HeapObject* object) { | 1572 HeapObject* object) { |
| 1480 ASSERT(IsShortcutCandidate(map->instance_type())); | 1573 ASSERT(IsShortcutCandidate(map->instance_type())); |
| 1481 | 1574 |
| 1482 if (ConsString::cast(object)->unchecked_second() == | 1575 Heap* heap = map->GetHeap(); |
| 1483 map->heap()->empty_string()) { | 1576 |
| 1577 if (marks_handling == IGNORE_MARKS && |
| 1578 ConsString::cast(object)->unchecked_second() == |
| 1579 heap->empty_string()) { |
| 1484 HeapObject* first = | 1580 HeapObject* first = |
| 1485 HeapObject::cast(ConsString::cast(object)->unchecked_first()); | 1581 HeapObject::cast(ConsString::cast(object)->unchecked_first()); |
| 1486 | 1582 |
| 1487 *slot = first; | 1583 *slot = first; |
| 1488 | 1584 |
| 1489 if (!map->heap()->InNewSpace(first)) { | 1585 if (!heap->InNewSpace(first)) { |
| 1490 object->set_map_word(MapWord::FromForwardingAddress(first)); | 1586 object->set_map_word(MapWord::FromForwardingAddress(first)); |
| 1491 return; | 1587 return; |
| 1492 } | 1588 } |
| 1493 | 1589 |
| 1494 MapWord first_word = first->map_word(); | 1590 MapWord first_word = first->map_word(); |
| 1495 if (first_word.IsForwardingAddress()) { | 1591 if (first_word.IsForwardingAddress()) { |
| 1496 HeapObject* target = first_word.ToForwardingAddress(); | 1592 HeapObject* target = first_word.ToForwardingAddress(); |
| 1497 | 1593 |
| 1498 *slot = target; | 1594 *slot = target; |
| 1499 object->set_map_word(MapWord::FromForwardingAddress(target)); | 1595 object->set_map_word(MapWord::FromForwardingAddress(target)); |
| 1500 return; | 1596 return; |
| 1501 } | 1597 } |
| 1502 | 1598 |
| 1503 DoScavengeObject(first->map(), slot, first); | 1599 heap->DoScavengeObject(first->map(), slot, first); |
| 1504 object->set_map_word(MapWord::FromForwardingAddress(*slot)); | 1600 object->set_map_word(MapWord::FromForwardingAddress(*slot)); |
| 1505 return; | 1601 return; |
| 1506 } | 1602 } |
| 1507 | 1603 |
| 1508 int object_size = ConsString::kSize; | 1604 int object_size = ConsString::kSize; |
| 1509 EvacuateObject<POINTER_OBJECT, SMALL>(map, slot, object, object_size); | 1605 EvacuateObject<POINTER_OBJECT, SMALL>(map, slot, object, object_size); |
| 1510 } | 1606 } |
| 1511 | 1607 |
| 1512 template<ObjectContents object_contents> | 1608 template<ObjectContents object_contents> |
| 1513 class ObjectEvacuationStrategy { | 1609 class ObjectEvacuationStrategy { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1524 HeapObject* object) { | 1620 HeapObject* object) { |
| 1525 int object_size = map->instance_size(); | 1621 int object_size = map->instance_size(); |
| 1526 EvacuateObject<object_contents, SMALL>(map, slot, object, object_size); | 1622 EvacuateObject<object_contents, SMALL>(map, slot, object, object_size); |
| 1527 } | 1623 } |
| 1528 }; | 1624 }; |
| 1529 | 1625 |
| 1530 static VisitorDispatchTable<ScavengingCallback> table_; | 1626 static VisitorDispatchTable<ScavengingCallback> table_; |
| 1531 }; | 1627 }; |
| 1532 | 1628 |
| 1533 | 1629 |
| 1534 template<LoggingAndProfiling logging_and_profiling_mode> | 1630 template<MarksHandling marks_handling, |
| 1631 LoggingAndProfiling logging_and_profiling_mode> |
| 1535 VisitorDispatchTable<ScavengingCallback> | 1632 VisitorDispatchTable<ScavengingCallback> |
| 1536 ScavengingVisitor<logging_and_profiling_mode>::table_; | 1633 ScavengingVisitor<marks_handling, logging_and_profiling_mode>::table_; |
| 1537 | 1634 |
| 1538 | 1635 |
| 1539 static void InitializeScavengingVisitorsTables() { | 1636 static void InitializeScavengingVisitorsTables() { |
| 1540 ScavengingVisitor<LOGGING_AND_PROFILING_DISABLED>::Initialize(); | 1637 ScavengingVisitor<TRANSFER_MARKS, |
| 1541 ScavengingVisitor<LOGGING_AND_PROFILING_ENABLED>::Initialize(); | 1638 LOGGING_AND_PROFILING_DISABLED>::Initialize(); |
| 1542 scavenging_visitors_table_.CopyFrom( | 1639 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_DISABLED>::Initialize(); |
| 1543 ScavengingVisitor<LOGGING_AND_PROFILING_DISABLED>::GetTable()); | 1640 ScavengingVisitor<TRANSFER_MARKS, |
| 1544 scavenging_visitors_table_mode_ = LOGGING_AND_PROFILING_DISABLED; | 1641 LOGGING_AND_PROFILING_ENABLED>::Initialize(); |
| 1642 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_ENABLED>::Initialize(); |
| 1545 } | 1643 } |
| 1546 | 1644 |
| 1547 | 1645 |
| 1548 void Heap::SwitchScavengingVisitorsTableIfProfilingWasEnabled() { | 1646 void Heap::SelectScavengingVisitorsTable() { |
| 1549 if (scavenging_visitors_table_mode_ == LOGGING_AND_PROFILING_ENABLED) { | 1647 bool logging_and_profiling = |
| 1550 // Table was already updated by some isolate. | 1648 isolate()->logger()->is_logging() || |
| 1551 return; | |
| 1552 } | |
| 1553 | |
| 1554 if (isolate()->logger()->is_logging() | | |
| 1555 CpuProfiler::is_profiling(isolate()) || | 1649 CpuProfiler::is_profiling(isolate()) || |
| 1556 (isolate()->heap_profiler() != NULL && | 1650 (isolate()->heap_profiler() != NULL && |
| 1557 isolate()->heap_profiler()->is_profiling())) { | 1651 isolate()->heap_profiler()->is_profiling()); |
| 1558 // If one of the isolates is doing scavenge at this moment of time | |
| 1559 // it might see this table in an inconsitent state when | |
| 1560 // some of the callbacks point to | |
| 1561 // ScavengingVisitor<LOGGING_AND_PROFILING_ENABLED> and others | |
| 1562 // to ScavengingVisitor<LOGGING_AND_PROFILING_DISABLED>. | |
| 1563 // However this does not lead to any bugs as such isolate does not have | |
| 1564 // profiling enabled and any isolate with enabled profiling is guaranteed | |
| 1565 // to see the table in the consistent state. | |
| 1566 scavenging_visitors_table_.CopyFrom( | |
| 1567 ScavengingVisitor<LOGGING_AND_PROFILING_ENABLED>::GetTable()); | |
| 1568 | 1652 |
| 1569 // We use Release_Store to prevent reordering of this write before writes | 1653 if (!incremental_marking()->IsMarking()) { |
| 1570 // to the table. | 1654 if (!logging_and_profiling) { |
| 1571 Release_Store(&scavenging_visitors_table_mode_, | 1655 scavenging_visitors_table_.CopyFrom( |
| 1572 LOGGING_AND_PROFILING_ENABLED); | 1656 ScavengingVisitor<IGNORE_MARKS, |
| 1657 LOGGING_AND_PROFILING_DISABLED>::GetTable()); |
| 1658 } else { |
| 1659 scavenging_visitors_table_.CopyFrom( |
| 1660 ScavengingVisitor<IGNORE_MARKS, |
| 1661 LOGGING_AND_PROFILING_ENABLED>::GetTable()); |
| 1662 } |
| 1663 } else { |
| 1664 if (!logging_and_profiling) { |
| 1665 scavenging_visitors_table_.CopyFrom( |
| 1666 ScavengingVisitor<TRANSFER_MARKS, |
| 1667 LOGGING_AND_PROFILING_DISABLED>::GetTable()); |
| 1668 } else { |
| 1669 scavenging_visitors_table_.CopyFrom( |
| 1670 ScavengingVisitor<TRANSFER_MARKS, |
| 1671 LOGGING_AND_PROFILING_ENABLED>::GetTable()); |
| 1672 } |
| 1573 } | 1673 } |
| 1574 } | 1674 } |
| 1575 | 1675 |
| 1576 | 1676 |
| 1577 void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) { | 1677 void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) { |
| 1578 ASSERT(HEAP->InFromSpace(object)); | 1678 ASSERT(HEAP->InFromSpace(object)); |
| 1579 MapWord first_word = object->map_word(); | 1679 MapWord first_word = object->map_word(); |
| 1580 ASSERT(!first_word.IsForwardingAddress()); | 1680 ASSERT(!first_word.IsForwardingAddress()); |
| 1581 Map* map = first_word.ToMap(); | 1681 Map* map = first_word.ToMap(); |
| 1582 DoScavengeObject(map, p, object); | 1682 map->GetHeap()->DoScavengeObject(map, p, object); |
| 1583 } | 1683 } |
| 1584 | 1684 |
| 1585 | 1685 |
| 1586 MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type, | 1686 MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type, |
| 1587 int instance_size) { | 1687 int instance_size) { |
| 1588 Object* result; | 1688 Object* result; |
| 1589 { MaybeObject* maybe_result = AllocateRawMap(); | 1689 { MaybeObject* maybe_result = AllocateRawMap(); |
| 1590 if (!maybe_result->ToObject(&result)) return maybe_result; | 1690 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 1591 } | 1691 } |
| 1592 | 1692 |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1700 if (!maybe_obj->ToObject(&obj)) return false; | 1800 if (!maybe_obj->ToObject(&obj)) return false; |
| 1701 } | 1801 } |
| 1702 set_oddball_map(Map::cast(obj)); | 1802 set_oddball_map(Map::cast(obj)); |
| 1703 | 1803 |
| 1704 // Allocate the empty array. | 1804 // Allocate the empty array. |
| 1705 { MaybeObject* maybe_obj = AllocateEmptyFixedArray(); | 1805 { MaybeObject* maybe_obj = AllocateEmptyFixedArray(); |
| 1706 if (!maybe_obj->ToObject(&obj)) return false; | 1806 if (!maybe_obj->ToObject(&obj)) return false; |
| 1707 } | 1807 } |
| 1708 set_empty_fixed_array(FixedArray::cast(obj)); | 1808 set_empty_fixed_array(FixedArray::cast(obj)); |
| 1709 | 1809 |
| 1710 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_DATA_SPACE); | 1810 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE); |
| 1711 if (!maybe_obj->ToObject(&obj)) return false; | 1811 if (!maybe_obj->ToObject(&obj)) return false; |
| 1712 } | 1812 } |
| 1713 set_null_value(obj); | 1813 set_null_value(obj); |
| 1714 Oddball::cast(obj)->set_kind(Oddball::kNull); | 1814 Oddball::cast(obj)->set_kind(Oddball::kNull); |
| 1715 | 1815 |
| 1716 // Allocate the empty descriptor array. | 1816 // Allocate the empty descriptor array. |
| 1717 { MaybeObject* maybe_obj = AllocateEmptyFixedArray(); | 1817 { MaybeObject* maybe_obj = AllocateEmptyFixedArray(); |
| 1718 if (!maybe_obj->ToObject(&obj)) return false; | 1818 if (!maybe_obj->ToObject(&obj)) return false; |
| 1719 } | 1819 } |
| 1720 set_empty_descriptor_array(DescriptorArray::cast(obj)); | 1820 set_empty_descriptor_array(DescriptorArray::cast(obj)); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1791 if (!maybe_obj->ToObject(&obj)) return false; | 1891 if (!maybe_obj->ToObject(&obj)) return false; |
| 1792 } | 1892 } |
| 1793 set_fixed_double_array_map(Map::cast(obj)); | 1893 set_fixed_double_array_map(Map::cast(obj)); |
| 1794 | 1894 |
| 1795 { MaybeObject* maybe_obj = | 1895 { MaybeObject* maybe_obj = |
| 1796 AllocateMap(BYTE_ARRAY_TYPE, kVariableSizeSentinel); | 1896 AllocateMap(BYTE_ARRAY_TYPE, kVariableSizeSentinel); |
| 1797 if (!maybe_obj->ToObject(&obj)) return false; | 1897 if (!maybe_obj->ToObject(&obj)) return false; |
| 1798 } | 1898 } |
| 1799 set_byte_array_map(Map::cast(obj)); | 1899 set_byte_array_map(Map::cast(obj)); |
| 1800 | 1900 |
| 1901 { MaybeObject* maybe_obj = |
| 1902 AllocateMap(FREE_SPACE_TYPE, kVariableSizeSentinel); |
| 1903 if (!maybe_obj->ToObject(&obj)) return false; |
| 1904 } |
| 1905 set_free_space_map(Map::cast(obj)); |
| 1906 |
| 1801 { MaybeObject* maybe_obj = AllocateByteArray(0, TENURED); | 1907 { MaybeObject* maybe_obj = AllocateByteArray(0, TENURED); |
| 1802 if (!maybe_obj->ToObject(&obj)) return false; | 1908 if (!maybe_obj->ToObject(&obj)) return false; |
| 1803 } | 1909 } |
| 1804 set_empty_byte_array(ByteArray::cast(obj)); | 1910 set_empty_byte_array(ByteArray::cast(obj)); |
| 1805 | 1911 |
| 1806 { MaybeObject* maybe_obj = | 1912 { MaybeObject* maybe_obj = |
| 1807 AllocateMap(EXTERNAL_PIXEL_ARRAY_TYPE, ExternalArray::kAlignedSize); | 1913 AllocateMap(EXTERNAL_PIXEL_ARRAY_TYPE, ExternalArray::kAlignedSize); |
| 1808 if (!maybe_obj->ToObject(&obj)) return false; | 1914 if (!maybe_obj->ToObject(&obj)) return false; |
| 1809 } | 1915 } |
| 1810 set_external_pixel_array_map(Map::cast(obj)); | 1916 set_external_pixel_array_map(Map::cast(obj)); |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1991 HeapObject::cast(result)->set_map(global_property_cell_map()); | 2097 HeapObject::cast(result)->set_map(global_property_cell_map()); |
| 1992 JSGlobalPropertyCell::cast(result)->set_value(value); | 2098 JSGlobalPropertyCell::cast(result)->set_value(value); |
| 1993 return result; | 2099 return result; |
| 1994 } | 2100 } |
| 1995 | 2101 |
| 1996 | 2102 |
| 1997 MaybeObject* Heap::CreateOddball(const char* to_string, | 2103 MaybeObject* Heap::CreateOddball(const char* to_string, |
| 1998 Object* to_number, | 2104 Object* to_number, |
| 1999 byte kind) { | 2105 byte kind) { |
| 2000 Object* result; | 2106 Object* result; |
| 2001 { MaybeObject* maybe_result = Allocate(oddball_map(), OLD_DATA_SPACE); | 2107 { MaybeObject* maybe_result = Allocate(oddball_map(), OLD_POINTER_SPACE); |
| 2002 if (!maybe_result->ToObject(&result)) return maybe_result; | 2108 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 2003 } | 2109 } |
| 2004 return Oddball::cast(result)->Initialize(to_string, to_number, kind); | 2110 return Oddball::cast(result)->Initialize(to_string, to_number, kind); |
| 2005 } | 2111 } |
| 2006 | 2112 |
| 2007 | 2113 |
| 2008 bool Heap::CreateApiObjects() { | 2114 bool Heap::CreateApiObjects() { |
| 2009 Object* obj; | 2115 Object* obj; |
| 2010 | 2116 |
| 2011 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); | 2117 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2076 if (!maybe_obj->ToObject(&obj)) return false; | 2182 if (!maybe_obj->ToObject(&obj)) return false; |
| 2077 } | 2183 } |
| 2078 set_minus_zero_value(obj); | 2184 set_minus_zero_value(obj); |
| 2079 ASSERT(signbit(minus_zero_value()->Number()) != 0); | 2185 ASSERT(signbit(minus_zero_value()->Number()) != 0); |
| 2080 | 2186 |
| 2081 { MaybeObject* maybe_obj = AllocateHeapNumber(OS::nan_value(), TENURED); | 2187 { MaybeObject* maybe_obj = AllocateHeapNumber(OS::nan_value(), TENURED); |
| 2082 if (!maybe_obj->ToObject(&obj)) return false; | 2188 if (!maybe_obj->ToObject(&obj)) return false; |
| 2083 } | 2189 } |
| 2084 set_nan_value(obj); | 2190 set_nan_value(obj); |
| 2085 | 2191 |
| 2086 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_DATA_SPACE); | 2192 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE); |
| 2087 if (!maybe_obj->ToObject(&obj)) return false; | 2193 if (!maybe_obj->ToObject(&obj)) return false; |
| 2088 } | 2194 } |
| 2089 set_undefined_value(obj); | 2195 set_undefined_value(obj); |
| 2090 Oddball::cast(obj)->set_kind(Oddball::kUndefined); | 2196 Oddball::cast(obj)->set_kind(Oddball::kUndefined); |
| 2091 ASSERT(!InNewSpace(undefined_value())); | 2197 ASSERT(!InNewSpace(undefined_value())); |
| 2092 | 2198 |
| 2093 // Allocate initial symbol table. | 2199 // Allocate initial symbol table. |
| 2094 { MaybeObject* maybe_obj = SymbolTable::Allocate(kInitialSymbolTableSize); | 2200 { MaybeObject* maybe_obj = SymbolTable::Allocate(kInitialSymbolTableSize); |
| 2095 if (!maybe_obj->ToObject(&obj)) return false; | 2201 if (!maybe_obj->ToObject(&obj)) return false; |
| 2096 } | 2202 } |
| (...skipping 801 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2898 if (length < 0 || length > ByteArray::kMaxLength) { | 3004 if (length < 0 || length > ByteArray::kMaxLength) { |
| 2899 return Failure::OutOfMemoryException(); | 3005 return Failure::OutOfMemoryException(); |
| 2900 } | 3006 } |
| 2901 if (pretenure == NOT_TENURED) { | 3007 if (pretenure == NOT_TENURED) { |
| 2902 return AllocateByteArray(length); | 3008 return AllocateByteArray(length); |
| 2903 } | 3009 } |
| 2904 int size = ByteArray::SizeFor(length); | 3010 int size = ByteArray::SizeFor(length); |
| 2905 Object* result; | 3011 Object* result; |
| 2906 { MaybeObject* maybe_result = (size <= MaxObjectSizeInPagedSpace()) | 3012 { MaybeObject* maybe_result = (size <= MaxObjectSizeInPagedSpace()) |
| 2907 ? old_data_space_->AllocateRaw(size) | 3013 ? old_data_space_->AllocateRaw(size) |
| 2908 : lo_space_->AllocateRaw(size); | 3014 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE); |
| 2909 if (!maybe_result->ToObject(&result)) return maybe_result; | 3015 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 2910 } | 3016 } |
| 2911 | 3017 |
| 2912 reinterpret_cast<ByteArray*>(result)->set_map(byte_array_map()); | 3018 reinterpret_cast<ByteArray*>(result)->set_map(byte_array_map()); |
| 2913 reinterpret_cast<ByteArray*>(result)->set_length(length); | 3019 reinterpret_cast<ByteArray*>(result)->set_length(length); |
| 2914 return result; | 3020 return result; |
| 2915 } | 3021 } |
| 2916 | 3022 |
| 2917 | 3023 |
| 2918 MaybeObject* Heap::AllocateByteArray(int length) { | 3024 MaybeObject* Heap::AllocateByteArray(int length) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2934 | 3040 |
| 2935 | 3041 |
| 2936 void Heap::CreateFillerObjectAt(Address addr, int size) { | 3042 void Heap::CreateFillerObjectAt(Address addr, int size) { |
| 2937 if (size == 0) return; | 3043 if (size == 0) return; |
| 2938 HeapObject* filler = HeapObject::FromAddress(addr); | 3044 HeapObject* filler = HeapObject::FromAddress(addr); |
| 2939 if (size == kPointerSize) { | 3045 if (size == kPointerSize) { |
| 2940 filler->set_map(one_pointer_filler_map()); | 3046 filler->set_map(one_pointer_filler_map()); |
| 2941 } else if (size == 2 * kPointerSize) { | 3047 } else if (size == 2 * kPointerSize) { |
| 2942 filler->set_map(two_pointer_filler_map()); | 3048 filler->set_map(two_pointer_filler_map()); |
| 2943 } else { | 3049 } else { |
| 2944 filler->set_map(byte_array_map()); | 3050 filler->set_map(free_space_map()); |
| 2945 ByteArray::cast(filler)->set_length(ByteArray::LengthFor(size)); | 3051 FreeSpace::cast(filler)->set_size(size); |
| 2946 } | 3052 } |
| 2947 } | 3053 } |
| 2948 | 3054 |
| 2949 | 3055 |
| 2950 MaybeObject* Heap::AllocateExternalArray(int length, | 3056 MaybeObject* Heap::AllocateExternalArray(int length, |
| 2951 ExternalArrayType array_type, | 3057 ExternalArrayType array_type, |
| 2952 void* external_pointer, | 3058 void* external_pointer, |
| 2953 PretenureFlag pretenure) { | 3059 PretenureFlag pretenure) { |
| 2954 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; | 3060 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; |
| 2955 Object* result; | 3061 Object* result; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2981 } | 3087 } |
| 2982 | 3088 |
| 2983 // Compute size. | 3089 // Compute size. |
| 2984 int body_size = RoundUp(desc.instr_size, kObjectAlignment); | 3090 int body_size = RoundUp(desc.instr_size, kObjectAlignment); |
| 2985 int obj_size = Code::SizeFor(body_size); | 3091 int obj_size = Code::SizeFor(body_size); |
| 2986 ASSERT(IsAligned(static_cast<intptr_t>(obj_size), kCodeAlignment)); | 3092 ASSERT(IsAligned(static_cast<intptr_t>(obj_size), kCodeAlignment)); |
| 2987 MaybeObject* maybe_result; | 3093 MaybeObject* maybe_result; |
| 2988 // Large code objects and code objects which should stay at a fixed address | 3094 // Large code objects and code objects which should stay at a fixed address |
| 2989 // are allocated in large object space. | 3095 // are allocated in large object space. |
| 2990 if (obj_size > MaxObjectSizeInPagedSpace() || immovable) { | 3096 if (obj_size > MaxObjectSizeInPagedSpace() || immovable) { |
| 2991 maybe_result = lo_space_->AllocateRawCode(obj_size); | 3097 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE); |
| 2992 } else { | 3098 } else { |
| 2993 maybe_result = code_space_->AllocateRaw(obj_size); | 3099 maybe_result = code_space_->AllocateRaw(obj_size); |
| 2994 } | 3100 } |
| 2995 | 3101 |
| 2996 Object* result; | 3102 Object* result; |
| 2997 if (!maybe_result->ToObject(&result)) return maybe_result; | 3103 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 2998 | 3104 |
| 2999 // Initialize the object | 3105 // Initialize the object |
| 3000 HeapObject::cast(result)->set_map(code_map()); | 3106 HeapObject::cast(result)->set_map(code_map()); |
| 3001 Code* code = Code::cast(result); | 3107 Code* code = Code::cast(result); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 3026 #endif | 3132 #endif |
| 3027 return code; | 3133 return code; |
| 3028 } | 3134 } |
| 3029 | 3135 |
| 3030 | 3136 |
| 3031 MaybeObject* Heap::CopyCode(Code* code) { | 3137 MaybeObject* Heap::CopyCode(Code* code) { |
| 3032 // Allocate an object the same size as the code object. | 3138 // Allocate an object the same size as the code object. |
| 3033 int obj_size = code->Size(); | 3139 int obj_size = code->Size(); |
| 3034 MaybeObject* maybe_result; | 3140 MaybeObject* maybe_result; |
| 3035 if (obj_size > MaxObjectSizeInPagedSpace()) { | 3141 if (obj_size > MaxObjectSizeInPagedSpace()) { |
| 3036 maybe_result = lo_space_->AllocateRawCode(obj_size); | 3142 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE); |
| 3037 } else { | 3143 } else { |
| 3038 maybe_result = code_space_->AllocateRaw(obj_size); | 3144 maybe_result = code_space_->AllocateRaw(obj_size); |
| 3039 } | 3145 } |
| 3040 | 3146 |
| 3041 Object* result; | 3147 Object* result; |
| 3042 if (!maybe_result->ToObject(&result)) return maybe_result; | 3148 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 3043 | 3149 |
| 3044 // Copy code object. | 3150 // Copy code object. |
| 3045 Address old_addr = code->address(); | 3151 Address old_addr = code->address(); |
| 3046 Address new_addr = reinterpret_cast<HeapObject*>(result)->address(); | 3152 Address new_addr = reinterpret_cast<HeapObject*>(result)->address(); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 3069 | 3175 |
| 3070 int new_obj_size = Code::SizeFor(new_body_size); | 3176 int new_obj_size = Code::SizeFor(new_body_size); |
| 3071 | 3177 |
| 3072 Address old_addr = code->address(); | 3178 Address old_addr = code->address(); |
| 3073 | 3179 |
| 3074 size_t relocation_offset = | 3180 size_t relocation_offset = |
| 3075 static_cast<size_t>(code->instruction_end() - old_addr); | 3181 static_cast<size_t>(code->instruction_end() - old_addr); |
| 3076 | 3182 |
| 3077 MaybeObject* maybe_result; | 3183 MaybeObject* maybe_result; |
| 3078 if (new_obj_size > MaxObjectSizeInPagedSpace()) { | 3184 if (new_obj_size > MaxObjectSizeInPagedSpace()) { |
| 3079 maybe_result = lo_space_->AllocateRawCode(new_obj_size); | 3185 maybe_result = lo_space_->AllocateRaw(new_obj_size, EXECUTABLE); |
| 3080 } else { | 3186 } else { |
| 3081 maybe_result = code_space_->AllocateRaw(new_obj_size); | 3187 maybe_result = code_space_->AllocateRaw(new_obj_size); |
| 3082 } | 3188 } |
| 3083 | 3189 |
| 3084 Object* result; | 3190 Object* result; |
| 3085 if (!maybe_result->ToObject(&result)) return maybe_result; | 3191 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 3086 | 3192 |
| 3087 // Copy code object. | 3193 // Copy code object. |
| 3088 Address new_addr = reinterpret_cast<HeapObject*>(result)->address(); | 3194 Address new_addr = reinterpret_cast<HeapObject*>(result)->address(); |
| 3089 | 3195 |
| (...skipping 731 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3821 if (chars > SeqTwoByteString::kMaxLength) { | 3927 if (chars > SeqTwoByteString::kMaxLength) { |
| 3822 return Failure::OutOfMemoryException(); | 3928 return Failure::OutOfMemoryException(); |
| 3823 } | 3929 } |
| 3824 map = symbol_map(); | 3930 map = symbol_map(); |
| 3825 size = SeqTwoByteString::SizeFor(chars); | 3931 size = SeqTwoByteString::SizeFor(chars); |
| 3826 } | 3932 } |
| 3827 | 3933 |
| 3828 // Allocate string. | 3934 // Allocate string. |
| 3829 Object* result; | 3935 Object* result; |
| 3830 { MaybeObject* maybe_result = (size > MaxObjectSizeInPagedSpace()) | 3936 { MaybeObject* maybe_result = (size > MaxObjectSizeInPagedSpace()) |
| 3831 ? lo_space_->AllocateRaw(size) | 3937 ? lo_space_->AllocateRaw(size, NOT_EXECUTABLE) |
| 3832 : old_data_space_->AllocateRaw(size); | 3938 : old_data_space_->AllocateRaw(size); |
| 3833 if (!maybe_result->ToObject(&result)) return maybe_result; | 3939 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 3834 } | 3940 } |
| 3835 | 3941 |
| 3836 reinterpret_cast<HeapObject*>(result)->set_map(map); | 3942 reinterpret_cast<HeapObject*>(result)->set_map(map); |
| 3837 // Set length and hash fields of the allocated string. | 3943 // Set length and hash fields of the allocated string. |
| 3838 String* answer = String::cast(result); | 3944 String* answer = String::cast(result); |
| 3839 answer->set_length(chars); | 3945 answer->set_length(chars); |
| 3840 answer->set_hash_field(hash_field); | 3946 answer->set_hash_field(hash_field); |
| 3841 | 3947 |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3938 if (length < 0 || length > FixedArray::kMaxLength) { | 4044 if (length < 0 || length > FixedArray::kMaxLength) { |
| 3939 return Failure::OutOfMemoryException(); | 4045 return Failure::OutOfMemoryException(); |
| 3940 } | 4046 } |
| 3941 ASSERT(length > 0); | 4047 ASSERT(length > 0); |
| 3942 // Use the general function if we're forced to always allocate. | 4048 // Use the general function if we're forced to always allocate. |
| 3943 if (always_allocate()) return AllocateFixedArray(length, TENURED); | 4049 if (always_allocate()) return AllocateFixedArray(length, TENURED); |
| 3944 // Allocate the raw data for a fixed array. | 4050 // Allocate the raw data for a fixed array. |
| 3945 int size = FixedArray::SizeFor(length); | 4051 int size = FixedArray::SizeFor(length); |
| 3946 return size <= kMaxObjectSizeInNewSpace | 4052 return size <= kMaxObjectSizeInNewSpace |
| 3947 ? new_space_.AllocateRaw(size) | 4053 ? new_space_.AllocateRaw(size) |
| 3948 : lo_space_->AllocateRawFixedArray(size); | 4054 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE); |
| 3949 } | 4055 } |
| 3950 | 4056 |
| 3951 | 4057 |
| 3952 MaybeObject* Heap::CopyFixedArrayWithMap(FixedArray* src, Map* map) { | 4058 MaybeObject* Heap::CopyFixedArrayWithMap(FixedArray* src, Map* map) { |
| 3953 int len = src->length(); | 4059 int len = src->length(); |
| 3954 Object* obj; | 4060 Object* obj; |
| 3955 { MaybeObject* maybe_obj = AllocateRawFixedArray(len); | 4061 { MaybeObject* maybe_obj = AllocateRawFixedArray(len); |
| 3956 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 4062 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 3957 } | 4063 } |
| 3958 if (InNewSpace(obj)) { | 4064 if (InNewSpace(obj)) { |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4269 (size > MaxObjectSizeInPagedSpace()) ? LO_SPACE : OLD_POINTER_SPACE; | 4375 (size > MaxObjectSizeInPagedSpace()) ? LO_SPACE : OLD_POINTER_SPACE; |
| 4270 Object* result; | 4376 Object* result; |
| 4271 { MaybeObject* maybe_result = Allocate(map, space); | 4377 { MaybeObject* maybe_result = Allocate(map, space); |
| 4272 if (!maybe_result->ToObject(&result)) return maybe_result; | 4378 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 4273 } | 4379 } |
| 4274 Struct::cast(result)->InitializeBody(size); | 4380 Struct::cast(result)->InitializeBody(size); |
| 4275 return result; | 4381 return result; |
| 4276 } | 4382 } |
| 4277 | 4383 |
| 4278 | 4384 |
| 4385 bool Heap::IsHeapIterable() { |
| 4386 return (!old_pointer_space()->was_swept_conservatively() && |
| 4387 !old_data_space()->was_swept_conservatively()); |
| 4388 } |
| 4389 |
| 4390 |
| 4391 void Heap::EnsureHeapIsIterable() { |
| 4392 ASSERT(IsAllocationAllowed()); |
| 4393 if (!IsHeapIterable()) { |
| 4394 CollectAllGarbage(kMakeHeapIterableMask); |
| 4395 } |
| 4396 ASSERT(IsHeapIterable()); |
| 4397 } |
| 4398 |
| 4399 |
| 4279 bool Heap::IdleNotification() { | 4400 bool Heap::IdleNotification() { |
| 4280 static const int kIdlesBeforeScavenge = 4; | 4401 static const int kIdlesBeforeScavenge = 4; |
| 4281 static const int kIdlesBeforeMarkSweep = 7; | 4402 static const int kIdlesBeforeMarkSweep = 7; |
| 4282 static const int kIdlesBeforeMarkCompact = 8; | 4403 static const int kIdlesBeforeMarkCompact = 8; |
| 4283 static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1; | 4404 static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1; |
| 4284 static const unsigned int kGCsBetweenCleanup = 4; | 4405 static const unsigned int kGCsBetweenCleanup = 4; |
| 4285 | 4406 |
| 4286 if (!last_idle_notification_gc_count_init_) { | 4407 if (!last_idle_notification_gc_count_init_) { |
| 4287 last_idle_notification_gc_count_ = gc_count_; | 4408 last_idle_notification_gc_count_ = gc_count_; |
| 4288 last_idle_notification_gc_count_init_ = true; | 4409 last_idle_notification_gc_count_init_ = true; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 4299 number_idle_notifications_ = | 4420 number_idle_notifications_ = |
| 4300 Min(number_idle_notifications_ + 1, kMaxIdleCount); | 4421 Min(number_idle_notifications_ + 1, kMaxIdleCount); |
| 4301 } else { | 4422 } else { |
| 4302 number_idle_notifications_ = 0; | 4423 number_idle_notifications_ = 0; |
| 4303 last_idle_notification_gc_count_ = gc_count_; | 4424 last_idle_notification_gc_count_ = gc_count_; |
| 4304 } | 4425 } |
| 4305 | 4426 |
| 4306 if (number_idle_notifications_ == kIdlesBeforeScavenge) { | 4427 if (number_idle_notifications_ == kIdlesBeforeScavenge) { |
| 4307 if (contexts_disposed_ > 0) { | 4428 if (contexts_disposed_ > 0) { |
| 4308 HistogramTimerScope scope(isolate_->counters()->gc_context()); | 4429 HistogramTimerScope scope(isolate_->counters()->gc_context()); |
| 4309 CollectAllGarbage(false); | 4430 CollectAllGarbage(kNoGCFlags); |
| 4310 } else { | 4431 } else { |
| 4311 CollectGarbage(NEW_SPACE); | 4432 CollectGarbage(NEW_SPACE); |
| 4312 } | 4433 } |
| 4313 new_space_.Shrink(); | 4434 new_space_.Shrink(); |
| 4314 last_idle_notification_gc_count_ = gc_count_; | 4435 last_idle_notification_gc_count_ = gc_count_; |
| 4315 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) { | 4436 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) { |
| 4316 // Before doing the mark-sweep collections we clear the | 4437 // Before doing the mark-sweep collections we clear the |
| 4317 // compilation cache to avoid hanging on to source code and | 4438 // compilation cache to avoid hanging on to source code and |
| 4318 // generated code for cached functions. | 4439 // generated code for cached functions. |
| 4319 isolate_->compilation_cache()->Clear(); | 4440 isolate_->compilation_cache()->Clear(); |
| 4320 | 4441 |
| 4321 CollectAllGarbage(false); | 4442 CollectAllGarbage(kNoGCFlags); |
| 4322 new_space_.Shrink(); | 4443 new_space_.Shrink(); |
| 4323 last_idle_notification_gc_count_ = gc_count_; | 4444 last_idle_notification_gc_count_ = gc_count_; |
| 4324 | 4445 |
| 4325 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) { | 4446 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) { |
| 4326 CollectAllGarbage(true); | 4447 CollectAllGarbage(kNoGCFlags); |
| 4327 new_space_.Shrink(); | 4448 new_space_.Shrink(); |
| 4328 last_idle_notification_gc_count_ = gc_count_; | 4449 last_idle_notification_gc_count_ = gc_count_; |
| 4329 number_idle_notifications_ = 0; | 4450 number_idle_notifications_ = 0; |
| 4330 finished = true; | 4451 finished = true; |
| 4331 } else if (contexts_disposed_ > 0) { | 4452 } else if (contexts_disposed_ > 0) { |
| 4332 if (FLAG_expose_gc) { | 4453 if (FLAG_expose_gc) { |
| 4333 contexts_disposed_ = 0; | 4454 contexts_disposed_ = 0; |
| 4334 } else { | 4455 } else { |
| 4335 HistogramTimerScope scope(isolate_->counters()->gc_context()); | 4456 HistogramTimerScope scope(isolate_->counters()->gc_context()); |
| 4336 CollectAllGarbage(false); | 4457 CollectAllGarbage(kNoGCFlags); |
| 4337 last_idle_notification_gc_count_ = gc_count_; | 4458 last_idle_notification_gc_count_ = gc_count_; |
| 4338 } | 4459 } |
| 4339 // If this is the first idle notification, we reset the | 4460 // If this is the first idle notification, we reset the |
| 4340 // notification count to avoid letting idle notifications for | 4461 // notification count to avoid letting idle notifications for |
| 4341 // context disposal garbage collections start a potentially too | 4462 // context disposal garbage collections start a potentially too |
| 4342 // aggressive idle GC cycle. | 4463 // aggressive idle GC cycle. |
| 4343 if (number_idle_notifications_ <= 1) { | 4464 if (number_idle_notifications_ <= 1) { |
| 4344 number_idle_notifications_ = 0; | 4465 number_idle_notifications_ = 0; |
| 4345 uncommit = false; | 4466 uncommit = false; |
| 4346 } | 4467 } |
| 4347 } else if (number_idle_notifications_ > kIdlesBeforeMarkCompact) { | 4468 } else if (number_idle_notifications_ > kIdlesBeforeMarkCompact) { |
| 4348 // If we have received more than kIdlesBeforeMarkCompact idle | 4469 // If we have received more than kIdlesBeforeMarkCompact idle |
| 4349 // notifications we do not perform any cleanup because we don't | 4470 // notifications we do not perform any cleanup because we don't |
| 4350 // expect to gain much by doing so. | 4471 // expect to gain much by doing so. |
| 4351 finished = true; | 4472 finished = true; |
| 4352 } | 4473 } |
| 4353 | 4474 |
| 4354 // Make sure that we have no pending context disposals and | 4475 // Make sure that we have no pending context disposals and |
| 4355 // conditionally uncommit from space. | 4476 // conditionally uncommit from space. |
| 4356 ASSERT(contexts_disposed_ == 0); | 4477 ASSERT((contexts_disposed_ == 0) || incremental_marking()->IsMarking()); |
| 4357 if (uncommit) UncommitFromSpace(); | 4478 if (uncommit) UncommitFromSpace(); |
| 4358 return finished; | 4479 return finished; |
| 4359 } | 4480 } |
| 4360 | 4481 |
| 4361 | 4482 |
| 4362 #ifdef DEBUG | 4483 #ifdef DEBUG |
| 4363 | 4484 |
| 4364 void Heap::Print() { | 4485 void Heap::Print() { |
| 4365 if (!HasBeenSetup()) return; | 4486 if (!HasBeenSetup()) return; |
| 4366 isolate()->PrintStack(); | 4487 isolate()->PrintStack(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 4381 } | 4502 } |
| 4382 | 4503 |
| 4383 | 4504 |
| 4384 // This function expects that NewSpace's allocated objects histogram is | 4505 // This function expects that NewSpace's allocated objects histogram is |
| 4385 // populated (via a call to CollectStatistics or else as a side effect of a | 4506 // populated (via a call to CollectStatistics or else as a side effect of a |
| 4386 // just-completed scavenge collection). | 4507 // just-completed scavenge collection). |
| 4387 void Heap::ReportHeapStatistics(const char* title) { | 4508 void Heap::ReportHeapStatistics(const char* title) { |
| 4388 USE(title); | 4509 USE(title); |
| 4389 PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n", | 4510 PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n", |
| 4390 title, gc_count_); | 4511 title, gc_count_); |
| 4391 PrintF("mark-compact GC : %d\n", mc_count_); | |
| 4392 PrintF("old_gen_promotion_limit_ %" V8_PTR_PREFIX "d\n", | 4512 PrintF("old_gen_promotion_limit_ %" V8_PTR_PREFIX "d\n", |
| 4393 old_gen_promotion_limit_); | 4513 old_gen_promotion_limit_); |
| 4394 PrintF("old_gen_allocation_limit_ %" V8_PTR_PREFIX "d\n", | 4514 PrintF("old_gen_allocation_limit_ %" V8_PTR_PREFIX "d\n", |
| 4395 old_gen_allocation_limit_); | 4515 old_gen_allocation_limit_); |
| 4516 PrintF("old_gen_limit_factor_ %d\n", old_gen_limit_factor_); |
| 4396 | 4517 |
| 4397 PrintF("\n"); | 4518 PrintF("\n"); |
| 4398 PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles()); | 4519 PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles()); |
| 4399 isolate_->global_handles()->PrintStats(); | 4520 isolate_->global_handles()->PrintStats(); |
| 4400 PrintF("\n"); | 4521 PrintF("\n"); |
| 4401 | 4522 |
| 4402 PrintF("Heap statistics : "); | 4523 PrintF("Heap statistics : "); |
| 4403 isolate_->memory_allocator()->ReportStatistics(); | 4524 isolate_->memory_allocator()->ReportStatistics(); |
| 4404 PrintF("To space : "); | 4525 PrintF("To space : "); |
| 4405 new_space_.ReportStatistics(); | 4526 new_space_.ReportStatistics(); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4462 return cell_space_->Contains(addr); | 4583 return cell_space_->Contains(addr); |
| 4463 case LO_SPACE: | 4584 case LO_SPACE: |
| 4464 return lo_space_->SlowContains(addr); | 4585 return lo_space_->SlowContains(addr); |
| 4465 } | 4586 } |
| 4466 | 4587 |
| 4467 return false; | 4588 return false; |
| 4468 } | 4589 } |
| 4469 | 4590 |
| 4470 | 4591 |
| 4471 #ifdef DEBUG | 4592 #ifdef DEBUG |
| 4472 static void DummyScavengePointer(HeapObject** p) { | |
| 4473 } | |
| 4474 | |
| 4475 | |
| 4476 static void VerifyPointersUnderWatermark( | |
| 4477 PagedSpace* space, | |
| 4478 DirtyRegionCallback visit_dirty_region) { | |
| 4479 PageIterator it(space, PageIterator::PAGES_IN_USE); | |
| 4480 | |
| 4481 while (it.has_next()) { | |
| 4482 Page* page = it.next(); | |
| 4483 Address start = page->ObjectAreaStart(); | |
| 4484 Address end = page->AllocationWatermark(); | |
| 4485 | |
| 4486 HEAP->IterateDirtyRegions(Page::kAllRegionsDirtyMarks, | |
| 4487 start, | |
| 4488 end, | |
| 4489 visit_dirty_region, | |
| 4490 &DummyScavengePointer); | |
| 4491 } | |
| 4492 } | |
| 4493 | |
| 4494 | |
| 4495 static void VerifyPointersUnderWatermark(LargeObjectSpace* space) { | |
| 4496 LargeObjectIterator it(space); | |
| 4497 for (HeapObject* object = it.next(); object != NULL; object = it.next()) { | |
| 4498 if (object->IsFixedArray()) { | |
| 4499 Address slot_address = object->address(); | |
| 4500 Address end = object->address() + object->Size(); | |
| 4501 | |
| 4502 while (slot_address < end) { | |
| 4503 HeapObject** slot = reinterpret_cast<HeapObject**>(slot_address); | |
| 4504 // When we are not in GC the Heap::InNewSpace() predicate | |
| 4505 // checks that pointers which satisfy predicate point into | |
| 4506 // the active semispace. | |
| 4507 HEAP->InNewSpace(*slot); | |
| 4508 slot_address += kPointerSize; | |
| 4509 } | |
| 4510 } | |
| 4511 } | |
| 4512 } | |
| 4513 | |
| 4514 | |
| 4515 void Heap::Verify() { | 4593 void Heap::Verify() { |
| 4516 ASSERT(HasBeenSetup()); | 4594 ASSERT(HasBeenSetup()); |
| 4517 | 4595 |
| 4596 store_buffer()->Verify(); |
| 4597 |
| 4518 VerifyPointersVisitor visitor; | 4598 VerifyPointersVisitor visitor; |
| 4519 IterateRoots(&visitor, VISIT_ONLY_STRONG); | 4599 IterateRoots(&visitor, VISIT_ONLY_STRONG); |
| 4520 | 4600 |
| 4521 new_space_.Verify(); | 4601 new_space_.Verify(); |
| 4522 | 4602 |
| 4523 VerifyPointersAndDirtyRegionsVisitor dirty_regions_visitor; | 4603 old_pointer_space_->Verify(&visitor); |
| 4524 old_pointer_space_->Verify(&dirty_regions_visitor); | 4604 map_space_->Verify(&visitor); |
| 4525 map_space_->Verify(&dirty_regions_visitor); | |
| 4526 | |
| 4527 VerifyPointersUnderWatermark(old_pointer_space_, | |
| 4528 &IteratePointersInDirtyRegion); | |
| 4529 VerifyPointersUnderWatermark(map_space_, | |
| 4530 &IteratePointersInDirtyMapsRegion); | |
| 4531 VerifyPointersUnderWatermark(lo_space_); | |
| 4532 | |
| 4533 VerifyPageWatermarkValidity(old_pointer_space_, ALL_INVALID); | |
| 4534 VerifyPageWatermarkValidity(map_space_, ALL_INVALID); | |
| 4535 | 4605 |
| 4536 VerifyPointersVisitor no_dirty_regions_visitor; | 4606 VerifyPointersVisitor no_dirty_regions_visitor; |
| 4537 old_data_space_->Verify(&no_dirty_regions_visitor); | 4607 old_data_space_->Verify(&no_dirty_regions_visitor); |
| 4538 code_space_->Verify(&no_dirty_regions_visitor); | 4608 code_space_->Verify(&no_dirty_regions_visitor); |
| 4539 cell_space_->Verify(&no_dirty_regions_visitor); | 4609 cell_space_->Verify(&no_dirty_regions_visitor); |
| 4540 | 4610 |
| 4541 lo_space_->Verify(); | 4611 lo_space_->Verify(); |
| 4542 } | 4612 } |
| 4613 |
| 4543 #endif // DEBUG | 4614 #endif // DEBUG |
| 4544 | 4615 |
| 4545 | 4616 |
| 4546 MaybeObject* Heap::LookupSymbol(Vector<const char> string) { | 4617 MaybeObject* Heap::LookupSymbol(Vector<const char> string) { |
| 4547 Object* symbol = NULL; | 4618 Object* symbol = NULL; |
| 4548 Object* new_table; | 4619 Object* new_table; |
| 4549 { MaybeObject* maybe_new_table = | 4620 { MaybeObject* maybe_new_table = |
| 4550 symbol_table()->LookupSymbol(string, &symbol); | 4621 symbol_table()->LookupSymbol(string, &symbol); |
| 4551 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table; | 4622 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table; |
| 4552 } | 4623 } |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4628 if (string->IsSymbol()) { | 4699 if (string->IsSymbol()) { |
| 4629 *symbol = string; | 4700 *symbol = string; |
| 4630 return true; | 4701 return true; |
| 4631 } | 4702 } |
| 4632 return symbol_table()->LookupSymbolIfExists(string, symbol); | 4703 return symbol_table()->LookupSymbolIfExists(string, symbol); |
| 4633 } | 4704 } |
| 4634 | 4705 |
| 4635 | 4706 |
| 4636 #ifdef DEBUG | 4707 #ifdef DEBUG |
| 4637 void Heap::ZapFromSpace() { | 4708 void Heap::ZapFromSpace() { |
| 4638 ASSERT(reinterpret_cast<Object*>(kFromSpaceZapValue)->IsFailure()); | 4709 NewSpacePageIterator it(new_space_.FromSpaceStart(), |
| 4639 for (Address a = new_space_.FromSpaceLow(); | 4710 new_space_.FromSpaceEnd()); |
| 4640 a < new_space_.FromSpaceHigh(); | 4711 while (it.has_next()) { |
| 4641 a += kPointerSize) { | 4712 NewSpacePage* page = it.next(); |
| 4642 Memory::Address_at(a) = kFromSpaceZapValue; | 4713 for (Address cursor = page->body(), limit = page->body_limit(); |
| 4714 cursor < limit; |
| 4715 cursor += kPointerSize) { |
| 4716 Memory::Address_at(cursor) = kFromSpaceZapValue; |
| 4717 } |
| 4643 } | 4718 } |
| 4644 } | 4719 } |
| 4645 #endif // DEBUG | 4720 #endif // DEBUG |
| 4646 | 4721 |
| 4647 | 4722 |
| 4648 bool Heap::IteratePointersInDirtyRegion(Heap* heap, | |
| 4649 Address start, | |
| 4650 Address end, | |
| 4651 ObjectSlotCallback copy_object_func) { | |
| 4652 Address slot_address = start; | |
| 4653 bool pointers_to_new_space_found = false; | |
| 4654 | |
| 4655 while (slot_address < end) { | |
| 4656 Object** slot = reinterpret_cast<Object**>(slot_address); | |
| 4657 if (heap->InNewSpace(*slot)) { | |
| 4658 ASSERT((*slot)->IsHeapObject()); | |
| 4659 copy_object_func(reinterpret_cast<HeapObject**>(slot)); | |
| 4660 if (heap->InNewSpace(*slot)) { | |
| 4661 ASSERT((*slot)->IsHeapObject()); | |
| 4662 pointers_to_new_space_found = true; | |
| 4663 } | |
| 4664 } | |
| 4665 slot_address += kPointerSize; | |
| 4666 } | |
| 4667 return pointers_to_new_space_found; | |
| 4668 } | |
| 4669 | |
| 4670 | |
| 4671 // Compute start address of the first map following given addr. | |
| 4672 static inline Address MapStartAlign(Address addr) { | |
| 4673 Address page = Page::FromAddress(addr)->ObjectAreaStart(); | |
| 4674 return page + (((addr - page) + (Map::kSize - 1)) / Map::kSize * Map::kSize); | |
| 4675 } | |
| 4676 | |
| 4677 | |
| 4678 // Compute end address of the first map preceding given addr. | |
| 4679 static inline Address MapEndAlign(Address addr) { | |
| 4680 Address page = Page::FromAllocationTop(addr)->ObjectAreaStart(); | |
| 4681 return page + ((addr - page) / Map::kSize * Map::kSize); | |
| 4682 } | |
| 4683 | |
| 4684 | |
| 4685 static bool IteratePointersInDirtyMaps(Address start, | |
| 4686 Address end, | |
| 4687 ObjectSlotCallback copy_object_func) { | |
| 4688 ASSERT(MapStartAlign(start) == start); | |
| 4689 ASSERT(MapEndAlign(end) == end); | |
| 4690 | |
| 4691 Address map_address = start; | |
| 4692 bool pointers_to_new_space_found = false; | |
| 4693 | |
| 4694 Heap* heap = HEAP; | |
| 4695 while (map_address < end) { | |
| 4696 ASSERT(!heap->InNewSpace(Memory::Object_at(map_address))); | |
| 4697 ASSERT(Memory::Object_at(map_address)->IsMap()); | |
| 4698 | |
| 4699 Address pointer_fields_start = map_address + Map::kPointerFieldsBeginOffset; | |
| 4700 Address pointer_fields_end = map_address + Map::kPointerFieldsEndOffset; | |
| 4701 | |
| 4702 if (Heap::IteratePointersInDirtyRegion(heap, | |
| 4703 pointer_fields_start, | |
| 4704 pointer_fields_end, | |
| 4705 copy_object_func)) { | |
| 4706 pointers_to_new_space_found = true; | |
| 4707 } | |
| 4708 | |
| 4709 map_address += Map::kSize; | |
| 4710 } | |
| 4711 | |
| 4712 return pointers_to_new_space_found; | |
| 4713 } | |
| 4714 | |
| 4715 | |
| 4716 bool Heap::IteratePointersInDirtyMapsRegion( | |
| 4717 Heap* heap, | |
| 4718 Address start, | |
| 4719 Address end, | |
| 4720 ObjectSlotCallback copy_object_func) { | |
| 4721 Address map_aligned_start = MapStartAlign(start); | |
| 4722 Address map_aligned_end = MapEndAlign(end); | |
| 4723 | |
| 4724 bool contains_pointers_to_new_space = false; | |
| 4725 | |
| 4726 if (map_aligned_start != start) { | |
| 4727 Address prev_map = map_aligned_start - Map::kSize; | |
| 4728 ASSERT(Memory::Object_at(prev_map)->IsMap()); | |
| 4729 | |
| 4730 Address pointer_fields_start = | |
| 4731 Max(start, prev_map + Map::kPointerFieldsBeginOffset); | |
| 4732 | |
| 4733 Address pointer_fields_end = | |
| 4734 Min(prev_map + Map::kPointerFieldsEndOffset, end); | |
| 4735 | |
| 4736 contains_pointers_to_new_space = | |
| 4737 IteratePointersInDirtyRegion(heap, | |
| 4738 pointer_fields_start, | |
| 4739 pointer_fields_end, | |
| 4740 copy_object_func) | |
| 4741 || contains_pointers_to_new_space; | |
| 4742 } | |
| 4743 | |
| 4744 contains_pointers_to_new_space = | |
| 4745 IteratePointersInDirtyMaps(map_aligned_start, | |
| 4746 map_aligned_end, | |
| 4747 copy_object_func) | |
| 4748 || contains_pointers_to_new_space; | |
| 4749 | |
| 4750 if (map_aligned_end != end) { | |
| 4751 ASSERT(Memory::Object_at(map_aligned_end)->IsMap()); | |
| 4752 | |
| 4753 Address pointer_fields_start = | |
| 4754 map_aligned_end + Map::kPointerFieldsBeginOffset; | |
| 4755 | |
| 4756 Address pointer_fields_end = | |
| 4757 Min(end, map_aligned_end + Map::kPointerFieldsEndOffset); | |
| 4758 | |
| 4759 contains_pointers_to_new_space = | |
| 4760 IteratePointersInDirtyRegion(heap, | |
| 4761 pointer_fields_start, | |
| 4762 pointer_fields_end, | |
| 4763 copy_object_func) | |
| 4764 || contains_pointers_to_new_space; | |
| 4765 } | |
| 4766 | |
| 4767 return contains_pointers_to_new_space; | |
| 4768 } | |
| 4769 | |
| 4770 | |
| 4771 void Heap::IterateAndMarkPointersToFromSpace(Address start, | 4723 void Heap::IterateAndMarkPointersToFromSpace(Address start, |
| 4772 Address end, | 4724 Address end, |
| 4773 ObjectSlotCallback callback) { | 4725 ObjectSlotCallback callback) { |
| 4774 Address slot_address = start; | 4726 Address slot_address = start; |
| 4775 Page* page = Page::FromAddress(start); | 4727 |
| 4776 | 4728 // We are not collecting slots on new space objects during mutation |
| 4777 uint32_t marks = page->GetRegionMarks(); | 4729 // thus we have to scan for pointers to evacuation candidates when we |
| 4730 // promote objects. But we should not record any slots in non-black |
| 4731 // objects. Grey object's slots would be rescanned. |
| 4732 // White object might not survive until the end of collection |
| 4733 // it would be a violation of the invariant to record it's slots. |
| 4734 bool record_slots = false; |
| 4735 if (incremental_marking()->IsCompacting()) { |
| 4736 MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::FromAddress(start)); |
| 4737 record_slots = Marking::IsBlack(mark_bit); |
| 4738 } |
| 4778 | 4739 |
| 4779 while (slot_address < end) { | 4740 while (slot_address < end) { |
| 4780 Object** slot = reinterpret_cast<Object**>(slot_address); | 4741 Object** slot = reinterpret_cast<Object**>(slot_address); |
| 4781 if (InFromSpace(*slot)) { | 4742 Object* object = *slot; |
| 4782 ASSERT((*slot)->IsHeapObject()); | 4743 // If the store buffer becomes overfull we mark pages as being exempt from |
| 4783 callback(reinterpret_cast<HeapObject**>(slot)); | 4744 // the store buffer. These pages are scanned to find pointers that point |
| 4784 if (InNewSpace(*slot)) { | 4745 // to the new space. In that case we may hit newly promoted objects and |
| 4785 ASSERT((*slot)->IsHeapObject()); | 4746 // fix the pointers before the promotion queue gets to them. Thus the 'if'. |
| 4786 marks |= page->GetRegionMaskForAddress(slot_address); | 4747 if (object->IsHeapObject()) { |
| 4748 if (Heap::InFromSpace(object)) { |
| 4749 callback(reinterpret_cast<HeapObject**>(slot), |
| 4750 HeapObject::cast(object)); |
| 4751 Object* new_object = *slot; |
| 4752 if (InNewSpace(new_object)) { |
| 4753 ASSERT(Heap::InToSpace(new_object)); |
| 4754 ASSERT(new_object->IsHeapObject()); |
| 4755 store_buffer_.EnterDirectlyIntoStoreBuffer( |
| 4756 reinterpret_cast<Address>(slot)); |
| 4757 } |
| 4758 ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(new_object)); |
| 4759 } else if (record_slots && |
| 4760 MarkCompactCollector::IsOnEvacuationCandidate(object)) { |
| 4761 mark_compact_collector()->RecordSlot(slot, slot, object); |
| 4787 } | 4762 } |
| 4788 } | 4763 } |
| 4789 slot_address += kPointerSize; | 4764 slot_address += kPointerSize; |
| 4790 } | 4765 } |
| 4791 | 4766 } |
| 4792 page->SetRegionMarks(marks); | 4767 |
| 4793 } | 4768 |
| 4794 | 4769 #ifdef DEBUG |
| 4795 | 4770 typedef bool (*CheckStoreBufferFilter)(Object** addr); |
| 4796 uint32_t Heap::IterateDirtyRegions( | 4771 |
| 4797 uint32_t marks, | 4772 |
| 4798 Address area_start, | 4773 bool IsAMapPointerAddress(Object** addr) { |
| 4799 Address area_end, | 4774 uintptr_t a = reinterpret_cast<uintptr_t>(addr); |
| 4800 DirtyRegionCallback visit_dirty_region, | 4775 int mod = a % Map::kSize; |
| 4801 ObjectSlotCallback copy_object_func) { | 4776 return mod >= Map::kPointerFieldsBeginOffset && |
| 4802 uint32_t newmarks = 0; | 4777 mod < Map::kPointerFieldsEndOffset; |
| 4803 uint32_t mask = 1; | 4778 } |
| 4804 | 4779 |
| 4805 if (area_start >= area_end) { | 4780 |
| 4806 return newmarks; | 4781 bool EverythingsAPointer(Object** addr) { |
| 4807 } | 4782 return true; |
| 4808 | 4783 } |
| 4809 Address region_start = area_start; | 4784 |
| 4810 | 4785 |
| 4811 // area_start does not necessarily coincide with start of the first region. | 4786 static void CheckStoreBuffer(Heap* heap, |
| 4812 // Thus to calculate the beginning of the next region we have to align | 4787 Object** current, |
| 4813 // area_start by Page::kRegionSize. | 4788 Object** limit, |
| 4814 Address second_region = | 4789 Object**** store_buffer_position, |
| 4815 reinterpret_cast<Address>( | 4790 Object*** store_buffer_top, |
| 4816 reinterpret_cast<intptr_t>(area_start + Page::kRegionSize) & | 4791 CheckStoreBufferFilter filter, |
| 4817 ~Page::kRegionAlignmentMask); | 4792 Address special_garbage_start, |
| 4818 | 4793 Address special_garbage_end) { |
| 4819 // Next region might be beyond area_end. | 4794 Map* free_space_map = heap->free_space_map(); |
| 4820 Address region_end = Min(second_region, area_end); | 4795 for ( ; current < limit; current++) { |
| 4821 | 4796 Object* o = *current; |
| 4822 if (marks & mask) { | 4797 Address current_address = reinterpret_cast<Address>(current); |
| 4823 if (visit_dirty_region(this, region_start, region_end, copy_object_func)) { | 4798 // Skip free space. |
| 4824 newmarks |= mask; | 4799 if (o == free_space_map) { |
| 4825 } | 4800 Address current_address = reinterpret_cast<Address>(current); |
| 4826 } | 4801 FreeSpace* free_space = |
| 4827 mask <<= 1; | 4802 FreeSpace::cast(HeapObject::FromAddress(current_address)); |
| 4828 | 4803 int skip = free_space->Size(); |
| 4829 // Iterate subsequent regions which fully lay inside [area_start, area_end[. | 4804 ASSERT(current_address + skip <= reinterpret_cast<Address>(limit)); |
| 4830 region_start = region_end; | 4805 ASSERT(skip > 0); |
| 4831 region_end = region_start + Page::kRegionSize; | 4806 current_address += skip - kPointerSize; |
| 4832 | 4807 current = reinterpret_cast<Object**>(current_address); |
| 4833 while (region_end <= area_end) { | 4808 continue; |
| 4834 if (marks & mask) { | 4809 } |
| 4835 if (visit_dirty_region(this, | 4810 // Skip the current linear allocation space between top and limit which is |
| 4836 region_start, | 4811 // unmarked with the free space map, but can contain junk. |
| 4837 region_end, | 4812 if (current_address == special_garbage_start && |
| 4838 copy_object_func)) { | 4813 special_garbage_end != special_garbage_start) { |
| 4839 newmarks |= mask; | 4814 current_address = special_garbage_end - kPointerSize; |
| 4840 } | 4815 current = reinterpret_cast<Object**>(current_address); |
| 4841 } | 4816 continue; |
| 4842 | 4817 } |
| 4843 region_start = region_end; | 4818 if (!(*filter)(current)) continue; |
| 4844 region_end = region_start + Page::kRegionSize; | 4819 ASSERT(current_address < special_garbage_start || |
| 4845 | 4820 current_address >= special_garbage_end); |
| 4846 mask <<= 1; | 4821 ASSERT(reinterpret_cast<uintptr_t>(o) != kFreeListZapValue); |
| 4847 } | 4822 // We have to check that the pointer does not point into new space |
| 4848 | 4823 // without trying to cast it to a heap object since the hash field of |
| 4849 if (region_start != area_end) { | 4824 // a string can contain values like 1 and 3 which are tagged null |
| 4850 // A small piece of area left uniterated because area_end does not coincide | 4825 // pointers. |
| 4851 // with region end. Check whether region covering last part of area is | 4826 if (!heap->InNewSpace(o)) continue; |
| 4852 // dirty. | 4827 while (**store_buffer_position < current && |
| 4853 if (marks & mask) { | 4828 *store_buffer_position < store_buffer_top) { |
| 4854 if (visit_dirty_region(this, region_start, area_end, copy_object_func)) { | 4829 (*store_buffer_position)++; |
| 4855 newmarks |= mask; | 4830 } |
| 4856 } | 4831 if (**store_buffer_position != current || |
| 4857 } | 4832 *store_buffer_position == store_buffer_top) { |
| 4858 } | 4833 Object** obj_start = current; |
| 4859 | 4834 while (!(*obj_start)->IsMap()) obj_start--; |
| 4860 return newmarks; | 4835 UNREACHABLE(); |
| 4861 } | 4836 } |
| 4862 | 4837 } |
| 4863 | 4838 } |
| 4864 | 4839 |
| 4865 void Heap::IterateDirtyRegions( | 4840 |
| 4866 PagedSpace* space, | 4841 // Check that the store buffer contains all intergenerational pointers by |
| 4867 DirtyRegionCallback visit_dirty_region, | 4842 // scanning a page and ensuring that all pointers to young space are in the |
| 4868 ObjectSlotCallback copy_object_func, | 4843 // store buffer. |
| 4869 ExpectedPageWatermarkState expected_page_watermark_state) { | 4844 void Heap::OldPointerSpaceCheckStoreBuffer() { |
| 4870 | 4845 OldSpace* space = old_pointer_space(); |
| 4871 PageIterator it(space, PageIterator::PAGES_IN_USE); | 4846 PageIterator pages(space); |
| 4872 | 4847 |
| 4873 while (it.has_next()) { | 4848 store_buffer()->SortUniq(); |
| 4874 Page* page = it.next(); | 4849 |
| 4875 uint32_t marks = page->GetRegionMarks(); | 4850 while (pages.has_next()) { |
| 4876 | 4851 Page* page = pages.next(); |
| 4877 if (marks != Page::kAllRegionsCleanMarks) { | 4852 Object** current = reinterpret_cast<Object**>(page->ObjectAreaStart()); |
| 4878 Address start = page->ObjectAreaStart(); | 4853 |
| 4879 | 4854 Address end = page->ObjectAreaEnd(); |
| 4880 // Do not try to visit pointers beyond page allocation watermark. | 4855 |
| 4881 // Page can contain garbage pointers there. | 4856 Object*** store_buffer_position = store_buffer()->Start(); |
| 4882 Address end; | 4857 Object*** store_buffer_top = store_buffer()->Top(); |
| 4883 | 4858 |
| 4884 if ((expected_page_watermark_state == WATERMARK_SHOULD_BE_VALID) || | 4859 Object** limit = reinterpret_cast<Object**>(end); |
| 4885 page->IsWatermarkValid()) { | 4860 CheckStoreBuffer(this, |
| 4886 end = page->AllocationWatermark(); | 4861 current, |
| 4887 } else { | 4862 limit, |
| 4888 end = page->CachedAllocationWatermark(); | 4863 &store_buffer_position, |
| 4889 } | 4864 store_buffer_top, |
| 4890 | 4865 &EverythingsAPointer, |
| 4891 ASSERT(space == old_pointer_space_ || | 4866 space->top(), |
| 4892 (space == map_space_ && | 4867 space->limit()); |
| 4893 ((page->ObjectAreaStart() - end) % Map::kSize == 0))); | 4868 } |
| 4894 | 4869 } |
| 4895 page->SetRegionMarks(IterateDirtyRegions(marks, | 4870 |
| 4896 start, | 4871 |
| 4897 end, | 4872 void Heap::MapSpaceCheckStoreBuffer() { |
| 4898 visit_dirty_region, | 4873 MapSpace* space = map_space(); |
| 4899 copy_object_func)); | 4874 PageIterator pages(space); |
| 4900 } | 4875 |
| 4901 | 4876 store_buffer()->SortUniq(); |
| 4902 // Mark page watermark as invalid to maintain watermark validity invariant. | 4877 |
| 4903 // See Page::FlipMeaningOfInvalidatedWatermarkFlag() for details. | 4878 while (pages.has_next()) { |
| 4904 page->InvalidateWatermark(true); | 4879 Page* page = pages.next(); |
| 4905 } | 4880 Object** current = reinterpret_cast<Object**>(page->ObjectAreaStart()); |
| 4906 } | 4881 |
| 4882 Address end = page->ObjectAreaEnd(); |
| 4883 |
| 4884 Object*** store_buffer_position = store_buffer()->Start(); |
| 4885 Object*** store_buffer_top = store_buffer()->Top(); |
| 4886 |
| 4887 Object** limit = reinterpret_cast<Object**>(end); |
| 4888 CheckStoreBuffer(this, |
| 4889 current, |
| 4890 limit, |
| 4891 &store_buffer_position, |
| 4892 store_buffer_top, |
| 4893 &IsAMapPointerAddress, |
| 4894 space->top(), |
| 4895 space->limit()); |
| 4896 } |
| 4897 } |
| 4898 |
| 4899 |
| 4900 void Heap::LargeObjectSpaceCheckStoreBuffer() { |
| 4901 LargeObjectIterator it(lo_space()); |
| 4902 for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) { |
| 4903 // We only have code, sequential strings, or fixed arrays in large |
| 4904 // object space, and only fixed arrays can possibly contain pointers to |
| 4905 // the young generation. |
| 4906 if (object->IsFixedArray()) { |
| 4907 Object*** store_buffer_position = store_buffer()->Start(); |
| 4908 Object*** store_buffer_top = store_buffer()->Top(); |
| 4909 Object** current = reinterpret_cast<Object**>(object->address()); |
| 4910 Object** limit = |
| 4911 reinterpret_cast<Object**>(object->address() + object->Size()); |
| 4912 CheckStoreBuffer(this, |
| 4913 current, |
| 4914 limit, |
| 4915 &store_buffer_position, |
| 4916 store_buffer_top, |
| 4917 &EverythingsAPointer, |
| 4918 NULL, |
| 4919 NULL); |
| 4920 } |
| 4921 } |
| 4922 } |
| 4923 #endif |
| 4907 | 4924 |
| 4908 | 4925 |
| 4909 void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) { | 4926 void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) { |
| 4910 IterateStrongRoots(v, mode); | 4927 IterateStrongRoots(v, mode); |
| 4911 IterateWeakRoots(v, mode); | 4928 IterateWeakRoots(v, mode); |
| 4912 } | 4929 } |
| 4913 | 4930 |
| 4914 | 4931 |
| 4915 void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) { | 4932 void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) { |
| 4916 v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex])); | 4933 v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex])); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4948 isolate_->compilation_cache()->Iterate(v); | 4965 isolate_->compilation_cache()->Iterate(v); |
| 4949 v->Synchronize("compilationcache"); | 4966 v->Synchronize("compilationcache"); |
| 4950 | 4967 |
| 4951 // Iterate over local handles in handle scopes. | 4968 // Iterate over local handles in handle scopes. |
| 4952 isolate_->handle_scope_implementer()->Iterate(v); | 4969 isolate_->handle_scope_implementer()->Iterate(v); |
| 4953 v->Synchronize("handlescope"); | 4970 v->Synchronize("handlescope"); |
| 4954 | 4971 |
| 4955 // Iterate over the builtin code objects and code stubs in the | 4972 // Iterate over the builtin code objects and code stubs in the |
| 4956 // heap. Note that it is not necessary to iterate over code objects | 4973 // heap. Note that it is not necessary to iterate over code objects |
| 4957 // on scavenge collections. | 4974 // on scavenge collections. |
| 4958 if (mode != VISIT_ALL_IN_SCAVENGE && | 4975 if (mode != VISIT_ALL_IN_SCAVENGE) { |
| 4959 mode != VISIT_ALL_IN_SWEEP_NEWSPACE) { | |
| 4960 isolate_->builtins()->IterateBuiltins(v); | 4976 isolate_->builtins()->IterateBuiltins(v); |
| 4961 } | 4977 } |
| 4962 v->Synchronize("builtins"); | 4978 v->Synchronize("builtins"); |
| 4963 | 4979 |
| 4964 // Iterate over global handles. | 4980 // Iterate over global handles. |
| 4965 switch (mode) { | 4981 switch (mode) { |
| 4966 case VISIT_ONLY_STRONG: | 4982 case VISIT_ONLY_STRONG: |
| 4967 isolate_->global_handles()->IterateStrongRoots(v); | 4983 isolate_->global_handles()->IterateStrongRoots(v); |
| 4968 break; | 4984 break; |
| 4969 case VISIT_ALL_IN_SCAVENGE: | 4985 case VISIT_ALL_IN_SCAVENGE: |
| (...skipping 23 matching lines...) Expand all Loading... |
| 4993 // output a flag to the snapshot. However at this point the serializer and | 5009 // output a flag to the snapshot. However at this point the serializer and |
| 4994 // deserializer are deliberately a little unsynchronized (see above) so the | 5010 // deserializer are deliberately a little unsynchronized (see above) so the |
| 4995 // checking of the sync flag in the snapshot would fail. | 5011 // checking of the sync flag in the snapshot would fail. |
| 4996 } | 5012 } |
| 4997 | 5013 |
| 4998 | 5014 |
| 4999 // TODO(1236194): Since the heap size is configurable on the command line | 5015 // TODO(1236194): Since the heap size is configurable on the command line |
| 5000 // and through the API, we should gracefully handle the case that the heap | 5016 // and through the API, we should gracefully handle the case that the heap |
| 5001 // size is not big enough to fit all the initial objects. | 5017 // size is not big enough to fit all the initial objects. |
| 5002 bool Heap::ConfigureHeap(int max_semispace_size, | 5018 bool Heap::ConfigureHeap(int max_semispace_size, |
| 5003 int max_old_gen_size, | 5019 intptr_t max_old_gen_size, |
| 5004 int max_executable_size) { | 5020 intptr_t max_executable_size) { |
| 5005 if (HasBeenSetup()) return false; | 5021 if (HasBeenSetup()) return false; |
| 5006 | 5022 |
| 5007 if (max_semispace_size > 0) max_semispace_size_ = max_semispace_size; | 5023 if (max_semispace_size > 0) { |
| 5024 if (max_semispace_size < Page::kPageSize) { |
| 5025 max_semispace_size = Page::kPageSize; |
| 5026 if (FLAG_trace_gc) { |
| 5027 PrintF("Max semispace size cannot be less than %dkbytes", |
| 5028 Page::kPageSize >> 10); |
| 5029 } |
| 5030 } |
| 5031 max_semispace_size_ = max_semispace_size; |
| 5032 } |
| 5008 | 5033 |
| 5009 if (Snapshot::IsEnabled()) { | 5034 if (Snapshot::IsEnabled()) { |
| 5010 // If we are using a snapshot we always reserve the default amount | 5035 // If we are using a snapshot we always reserve the default amount |
| 5011 // of memory for each semispace because code in the snapshot has | 5036 // of memory for each semispace because code in the snapshot has |
| 5012 // write-barrier code that relies on the size and alignment of new | 5037 // write-barrier code that relies on the size and alignment of new |
| 5013 // space. We therefore cannot use a larger max semispace size | 5038 // space. We therefore cannot use a larger max semispace size |
| 5014 // than the default reserved semispace size. | 5039 // than the default reserved semispace size. |
| 5015 if (max_semispace_size_ > reserved_semispace_size_) { | 5040 if (max_semispace_size_ > reserved_semispace_size_) { |
| 5016 max_semispace_size_ = reserved_semispace_size_; | 5041 max_semispace_size_ = reserved_semispace_size_; |
| 5042 if (FLAG_trace_gc) { |
| 5043 PrintF("Max semispace size cannot be more than %dkbytes", |
| 5044 reserved_semispace_size_ >> 10); |
| 5045 } |
| 5017 } | 5046 } |
| 5018 } else { | 5047 } else { |
| 5019 // If we are not using snapshots we reserve space for the actual | 5048 // If we are not using snapshots we reserve space for the actual |
| 5020 // max semispace size. | 5049 // max semispace size. |
| 5021 reserved_semispace_size_ = max_semispace_size_; | 5050 reserved_semispace_size_ = max_semispace_size_; |
| 5022 } | 5051 } |
| 5023 | 5052 |
| 5024 if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size; | 5053 if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size; |
| 5025 if (max_executable_size > 0) { | 5054 if (max_executable_size > 0) { |
| 5026 max_executable_size_ = RoundUp(max_executable_size, Page::kPageSize); | 5055 max_executable_size_ = RoundUp(max_executable_size, Page::kPageSize); |
| 5027 } | 5056 } |
| 5028 | 5057 |
| 5029 // The max executable size must be less than or equal to the max old | 5058 // The max executable size must be less than or equal to the max old |
| 5030 // generation size. | 5059 // generation size. |
| 5031 if (max_executable_size_ > max_old_generation_size_) { | 5060 if (max_executable_size_ > max_old_generation_size_) { |
| 5032 max_executable_size_ = max_old_generation_size_; | 5061 max_executable_size_ = max_old_generation_size_; |
| 5033 } | 5062 } |
| 5034 | 5063 |
| 5035 // The new space size must be a power of two to support single-bit testing | 5064 // The new space size must be a power of two to support single-bit testing |
| 5036 // for containment. | 5065 // for containment. |
| 5037 max_semispace_size_ = RoundUpToPowerOf2(max_semispace_size_); | 5066 max_semispace_size_ = RoundUpToPowerOf2(max_semispace_size_); |
| 5038 reserved_semispace_size_ = RoundUpToPowerOf2(reserved_semispace_size_); | 5067 reserved_semispace_size_ = RoundUpToPowerOf2(reserved_semispace_size_); |
| 5039 initial_semispace_size_ = Min(initial_semispace_size_, max_semispace_size_); | 5068 initial_semispace_size_ = Min(initial_semispace_size_, max_semispace_size_); |
| 5040 external_allocation_limit_ = 10 * max_semispace_size_; | 5069 external_allocation_limit_ = 10 * max_semispace_size_; |
| 5041 | 5070 |
| 5042 // The old generation is paged. | 5071 // The old generation is paged and needs at least one page for each space. |
| 5043 max_old_generation_size_ = RoundUp(max_old_generation_size_, Page::kPageSize); | 5072 int paged_space_count = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1; |
| 5073 max_old_generation_size_ = Max(static_cast<intptr_t>(paged_space_count * |
| 5074 Page::kPageSize), |
| 5075 RoundUp(max_old_generation_size_, |
| 5076 Page::kPageSize)); |
| 5044 | 5077 |
| 5045 configured_ = true; | 5078 configured_ = true; |
| 5046 return true; | 5079 return true; |
| 5047 } | 5080 } |
| 5048 | 5081 |
| 5049 | 5082 |
| 5050 bool Heap::ConfigureHeapDefault() { | 5083 bool Heap::ConfigureHeapDefault() { |
| 5051 return ConfigureHeap(FLAG_max_new_space_size / 2 * KB, | 5084 return ConfigureHeap(static_cast<intptr_t>(FLAG_max_new_space_size / 2) * KB, |
| 5052 FLAG_max_old_space_size * MB, | 5085 static_cast<intptr_t>(FLAG_max_old_space_size) * MB, |
| 5053 FLAG_max_executable_size * MB); | 5086 static_cast<intptr_t>(FLAG_max_executable_size) * MB); |
| 5054 } | 5087 } |
| 5055 | 5088 |
| 5056 | 5089 |
| 5057 void Heap::RecordStats(HeapStats* stats, bool take_snapshot) { | 5090 void Heap::RecordStats(HeapStats* stats, bool take_snapshot) { |
| 5058 *stats->start_marker = HeapStats::kStartMarker; | 5091 *stats->start_marker = HeapStats::kStartMarker; |
| 5059 *stats->end_marker = HeapStats::kEndMarker; | 5092 *stats->end_marker = HeapStats::kEndMarker; |
| 5060 *stats->new_space_size = new_space_.SizeAsInt(); | 5093 *stats->new_space_size = new_space_.SizeAsInt(); |
| 5061 *stats->new_space_capacity = static_cast<int>(new_space_.Capacity()); | 5094 *stats->new_space_capacity = static_cast<int>(new_space_.Capacity()); |
| 5062 *stats->old_pointer_space_size = old_pointer_space_->Size(); | 5095 *stats->old_pointer_space_size = old_pointer_space_->Size(); |
| 5063 *stats->old_pointer_space_capacity = old_pointer_space_->Capacity(); | 5096 *stats->old_pointer_space_capacity = old_pointer_space_->Capacity(); |
| 5064 *stats->old_data_space_size = old_data_space_->Size(); | 5097 *stats->old_data_space_size = old_data_space_->Size(); |
| 5065 *stats->old_data_space_capacity = old_data_space_->Capacity(); | 5098 *stats->old_data_space_capacity = old_data_space_->Capacity(); |
| 5066 *stats->code_space_size = code_space_->Size(); | 5099 *stats->code_space_size = code_space_->Size(); |
| 5067 *stats->code_space_capacity = code_space_->Capacity(); | 5100 *stats->code_space_capacity = code_space_->Capacity(); |
| 5068 *stats->map_space_size = map_space_->Size(); | 5101 *stats->map_space_size = map_space_->Size(); |
| 5069 *stats->map_space_capacity = map_space_->Capacity(); | 5102 *stats->map_space_capacity = map_space_->Capacity(); |
| 5070 *stats->cell_space_size = cell_space_->Size(); | 5103 *stats->cell_space_size = cell_space_->Size(); |
| 5071 *stats->cell_space_capacity = cell_space_->Capacity(); | 5104 *stats->cell_space_capacity = cell_space_->Capacity(); |
| 5072 *stats->lo_space_size = lo_space_->Size(); | 5105 *stats->lo_space_size = lo_space_->Size(); |
| 5073 isolate_->global_handles()->RecordStats(stats); | 5106 isolate_->global_handles()->RecordStats(stats); |
| 5074 *stats->memory_allocator_size = isolate()->memory_allocator()->Size(); | 5107 *stats->memory_allocator_size = isolate()->memory_allocator()->Size(); |
| 5075 *stats->memory_allocator_capacity = | 5108 *stats->memory_allocator_capacity = |
| 5076 isolate()->memory_allocator()->Size() + | 5109 isolate()->memory_allocator()->Size() + |
| 5077 isolate()->memory_allocator()->Available(); | 5110 isolate()->memory_allocator()->Available(); |
| 5078 *stats->os_error = OS::GetLastError(); | 5111 *stats->os_error = OS::GetLastError(); |
| 5079 isolate()->memory_allocator()->Available(); | 5112 isolate()->memory_allocator()->Available(); |
| 5080 if (take_snapshot) { | 5113 if (take_snapshot) { |
| 5081 HeapIterator iterator(HeapIterator::kFilterFreeListNodes); | 5114 HeapIterator iterator; |
| 5082 for (HeapObject* obj = iterator.next(); | 5115 for (HeapObject* obj = iterator.next(); |
| 5083 obj != NULL; | 5116 obj != NULL; |
| 5084 obj = iterator.next()) { | 5117 obj = iterator.next()) { |
| 5085 InstanceType type = obj->map()->instance_type(); | 5118 InstanceType type = obj->map()->instance_type(); |
| 5086 ASSERT(0 <= type && type <= LAST_TYPE); | 5119 ASSERT(0 <= type && type <= LAST_TYPE); |
| 5087 stats->objects_per_type[type]++; | 5120 stats->objects_per_type[type]++; |
| 5088 stats->size_per_type[type] += obj->Size(); | 5121 stats->size_per_type[type] += obj->Size(); |
| 5089 } | 5122 } |
| 5090 } | 5123 } |
| 5091 } | 5124 } |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5287 // Configuration is based on the flags new-space-size (really the semispace | 5320 // Configuration is based on the flags new-space-size (really the semispace |
| 5288 // size) and old-space-size if set or the initial values of semispace_size_ | 5321 // size) and old-space-size if set or the initial values of semispace_size_ |
| 5289 // and old_generation_size_ otherwise. | 5322 // and old_generation_size_ otherwise. |
| 5290 if (!configured_) { | 5323 if (!configured_) { |
| 5291 if (!ConfigureHeapDefault()) return false; | 5324 if (!ConfigureHeapDefault()) return false; |
| 5292 } | 5325 } |
| 5293 | 5326 |
| 5294 gc_initializer_mutex->Lock(); | 5327 gc_initializer_mutex->Lock(); |
| 5295 static bool initialized_gc = false; | 5328 static bool initialized_gc = false; |
| 5296 if (!initialized_gc) { | 5329 if (!initialized_gc) { |
| 5297 initialized_gc = true; | 5330 initialized_gc = true; |
| 5298 InitializeScavengingVisitorsTables(); | 5331 InitializeScavengingVisitorsTables(); |
| 5299 NewSpaceScavenger::Initialize(); | 5332 NewSpaceScavenger::Initialize(); |
| 5300 MarkCompactCollector::Initialize(); | 5333 MarkCompactCollector::Initialize(); |
| 5301 } | 5334 } |
| 5302 gc_initializer_mutex->Unlock(); | 5335 gc_initializer_mutex->Unlock(); |
| 5303 | 5336 |
| 5304 MarkMapPointersAsEncoded(false); | 5337 MarkMapPointersAsEncoded(false); |
| 5305 | 5338 |
| 5306 // Setup memory allocator and reserve a chunk of memory for new | 5339 // Setup memory allocator. |
| 5307 // space. The chunk is double the size of the requested reserved | |
| 5308 // new space size to ensure that we can find a pair of semispaces that | |
| 5309 // are contiguous and aligned to their size. | |
| 5310 if (!isolate_->memory_allocator()->Setup(MaxReserved(), MaxExecutableSize())) | 5340 if (!isolate_->memory_allocator()->Setup(MaxReserved(), MaxExecutableSize())) |
| 5311 return false; | 5341 return false; |
| 5312 void* chunk = | |
| 5313 isolate_->memory_allocator()->ReserveInitialChunk( | |
| 5314 4 * reserved_semispace_size_); | |
| 5315 if (chunk == NULL) return false; | |
| 5316 | 5342 |
| 5317 // Align the pair of semispaces to their size, which must be a power | 5343 // Setup new space. |
| 5318 // of 2. | 5344 if (!new_space_.Setup(reserved_semispace_size_, max_semispace_size_)) { |
| 5319 Address new_space_start = | |
| 5320 RoundUp(reinterpret_cast<byte*>(chunk), 2 * reserved_semispace_size_); | |
| 5321 if (!new_space_.Setup(new_space_start, 2 * reserved_semispace_size_)) { | |
| 5322 return false; | 5345 return false; |
| 5323 } | 5346 } |
| 5324 | 5347 |
| 5325 // Initialize old pointer space. | 5348 // Initialize old pointer space. |
| 5326 old_pointer_space_ = | 5349 old_pointer_space_ = |
| 5327 new OldSpace(this, | 5350 new OldSpace(this, |
| 5328 max_old_generation_size_, | 5351 max_old_generation_size_, |
| 5329 OLD_POINTER_SPACE, | 5352 OLD_POINTER_SPACE, |
| 5330 NOT_EXECUTABLE); | 5353 NOT_EXECUTABLE); |
| 5331 if (old_pointer_space_ == NULL) return false; | 5354 if (old_pointer_space_ == NULL) return false; |
| 5332 if (!old_pointer_space_->Setup(NULL, 0)) return false; | 5355 if (!old_pointer_space_->Setup()) return false; |
| 5333 | 5356 |
| 5334 // Initialize old data space. | 5357 // Initialize old data space. |
| 5335 old_data_space_ = | 5358 old_data_space_ = |
| 5336 new OldSpace(this, | 5359 new OldSpace(this, |
| 5337 max_old_generation_size_, | 5360 max_old_generation_size_, |
| 5338 OLD_DATA_SPACE, | 5361 OLD_DATA_SPACE, |
| 5339 NOT_EXECUTABLE); | 5362 NOT_EXECUTABLE); |
| 5340 if (old_data_space_ == NULL) return false; | 5363 if (old_data_space_ == NULL) return false; |
| 5341 if (!old_data_space_->Setup(NULL, 0)) return false; | 5364 if (!old_data_space_->Setup()) return false; |
| 5342 | 5365 |
| 5343 // Initialize the code space, set its maximum capacity to the old | 5366 // Initialize the code space, set its maximum capacity to the old |
| 5344 // generation size. It needs executable memory. | 5367 // generation size. It needs executable memory. |
| 5345 // On 64-bit platform(s), we put all code objects in a 2 GB range of | 5368 // On 64-bit platform(s), we put all code objects in a 2 GB range of |
| 5346 // virtual address space, so that they can call each other with near calls. | 5369 // virtual address space, so that they can call each other with near calls. |
| 5347 if (code_range_size_ > 0) { | 5370 if (code_range_size_ > 0) { |
| 5348 if (!isolate_->code_range()->Setup(code_range_size_)) { | 5371 if (!isolate_->code_range()->Setup(code_range_size_)) { |
| 5349 return false; | 5372 return false; |
| 5350 } | 5373 } |
| 5351 } | 5374 } |
| 5352 | 5375 |
| 5353 code_space_ = | 5376 code_space_ = |
| 5354 new OldSpace(this, max_old_generation_size_, CODE_SPACE, EXECUTABLE); | 5377 new OldSpace(this, max_old_generation_size_, CODE_SPACE, EXECUTABLE); |
| 5355 if (code_space_ == NULL) return false; | 5378 if (code_space_ == NULL) return false; |
| 5356 if (!code_space_->Setup(NULL, 0)) return false; | 5379 if (!code_space_->Setup()) return false; |
| 5357 | 5380 |
| 5358 // Initialize map space. | 5381 // Initialize map space. |
| 5359 map_space_ = new MapSpace(this, FLAG_use_big_map_space | 5382 map_space_ = new MapSpace(this, |
| 5360 ? max_old_generation_size_ | 5383 max_old_generation_size_, |
| 5361 : MapSpace::kMaxMapPageIndex * Page::kPageSize, | 5384 FLAG_max_map_space_pages, |
| 5362 FLAG_max_map_space_pages, | 5385 MAP_SPACE); |
| 5363 MAP_SPACE); | |
| 5364 if (map_space_ == NULL) return false; | 5386 if (map_space_ == NULL) return false; |
| 5365 if (!map_space_->Setup(NULL, 0)) return false; | 5387 if (!map_space_->Setup()) return false; |
| 5366 | 5388 |
| 5367 // Initialize global property cell space. | 5389 // Initialize global property cell space. |
| 5368 cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE); | 5390 cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE); |
| 5369 if (cell_space_ == NULL) return false; | 5391 if (cell_space_ == NULL) return false; |
| 5370 if (!cell_space_->Setup(NULL, 0)) return false; | 5392 if (!cell_space_->Setup()) return false; |
| 5371 | 5393 |
| 5372 // The large object code space may contain code or data. We set the memory | 5394 // The large object code space may contain code or data. We set the memory |
| 5373 // to be non-executable here for safety, but this means we need to enable it | 5395 // to be non-executable here for safety, but this means we need to enable it |
| 5374 // explicitly when allocating large code objects. | 5396 // explicitly when allocating large code objects. |
| 5375 lo_space_ = new LargeObjectSpace(this, LO_SPACE); | 5397 lo_space_ = new LargeObjectSpace(this, LO_SPACE); |
| 5376 if (lo_space_ == NULL) return false; | 5398 if (lo_space_ == NULL) return false; |
| 5377 if (!lo_space_->Setup()) return false; | 5399 if (!lo_space_->Setup()) return false; |
| 5378 | |
| 5379 if (create_heap_objects) { | 5400 if (create_heap_objects) { |
| 5380 // Create initial maps. | 5401 // Create initial maps. |
| 5381 if (!CreateInitialMaps()) return false; | 5402 if (!CreateInitialMaps()) return false; |
| 5382 if (!CreateApiObjects()) return false; | 5403 if (!CreateApiObjects()) return false; |
| 5383 | 5404 |
| 5384 // Create initial objects | 5405 // Create initial objects |
| 5385 if (!CreateInitialObjects()) return false; | 5406 if (!CreateInitialObjects()) return false; |
| 5386 | 5407 |
| 5387 global_contexts_list_ = undefined_value(); | 5408 global_contexts_list_ = undefined_value(); |
| 5388 } | 5409 } |
| 5389 | 5410 |
| 5390 LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity())); | 5411 LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity())); |
| 5391 LOG(isolate_, IntPtrTEvent("heap-available", Available())); | 5412 LOG(isolate_, IntPtrTEvent("heap-available", Available())); |
| 5392 | 5413 |
| 5414 store_buffer()->Setup(); |
| 5415 |
| 5393 return true; | 5416 return true; |
| 5394 } | 5417 } |
| 5395 | 5418 |
| 5396 | 5419 |
| 5397 void Heap::SetStackLimits() { | 5420 void Heap::SetStackLimits() { |
| 5398 ASSERT(isolate_ != NULL); | 5421 ASSERT(isolate_ != NULL); |
| 5399 ASSERT(isolate_ == isolate()); | 5422 ASSERT(isolate_ == isolate()); |
| 5400 // On 64 bit machines, pointers are generally out of range of Smis. We write | 5423 // On 64 bit machines, pointers are generally out of range of Smis. We write |
| 5401 // something that looks like an out of range Smi to the GC. | 5424 // something that looks like an out of range Smi to the GC. |
| 5402 | 5425 |
| 5403 // Set up the special root array entries containing the stack limits. | 5426 // Set up the special root array entries containing the stack limits. |
| 5404 // These are actually addresses, but the tag makes the GC ignore it. | 5427 // These are actually addresses, but the tag makes the GC ignore it. |
| 5405 roots_[kStackLimitRootIndex] = | 5428 roots_[kStackLimitRootIndex] = |
| 5406 reinterpret_cast<Object*>( | 5429 reinterpret_cast<Object*>( |
| 5407 (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag); | 5430 (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag); |
| 5408 roots_[kRealStackLimitRootIndex] = | 5431 roots_[kRealStackLimitRootIndex] = |
| 5409 reinterpret_cast<Object*>( | 5432 reinterpret_cast<Object*>( |
| 5410 (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag); | 5433 (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag); |
| 5411 } | 5434 } |
| 5412 | 5435 |
| 5413 | 5436 |
| 5414 void Heap::TearDown() { | 5437 void Heap::TearDown() { |
| 5415 if (FLAG_print_cumulative_gc_stat) { | 5438 if (FLAG_print_cumulative_gc_stat) { |
| 5416 PrintF("\n\n"); | 5439 PrintF("\n\n"); |
| 5417 PrintF("gc_count=%d ", gc_count_); | 5440 PrintF("gc_count=%d ", gc_count_); |
| 5418 PrintF("mark_sweep_count=%d ", ms_count_); | 5441 PrintF("mark_sweep_count=%d ", ms_count_); |
| 5419 PrintF("mark_compact_count=%d ", mc_count_); | |
| 5420 PrintF("max_gc_pause=%d ", get_max_gc_pause()); | 5442 PrintF("max_gc_pause=%d ", get_max_gc_pause()); |
| 5421 PrintF("min_in_mutator=%d ", get_min_in_mutator()); | 5443 PrintF("min_in_mutator=%d ", get_min_in_mutator()); |
| 5422 PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ", | 5444 PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ", |
| 5423 get_max_alive_after_gc()); | 5445 get_max_alive_after_gc()); |
| 5424 PrintF("\n\n"); | 5446 PrintF("\n\n"); |
| 5425 } | 5447 } |
| 5426 | 5448 |
| 5427 isolate_->global_handles()->TearDown(); | 5449 isolate_->global_handles()->TearDown(); |
| 5428 | 5450 |
| 5429 external_string_table_.TearDown(); | 5451 external_string_table_.TearDown(); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 5459 delete cell_space_; | 5481 delete cell_space_; |
| 5460 cell_space_ = NULL; | 5482 cell_space_ = NULL; |
| 5461 } | 5483 } |
| 5462 | 5484 |
| 5463 if (lo_space_ != NULL) { | 5485 if (lo_space_ != NULL) { |
| 5464 lo_space_->TearDown(); | 5486 lo_space_->TearDown(); |
| 5465 delete lo_space_; | 5487 delete lo_space_; |
| 5466 lo_space_ = NULL; | 5488 lo_space_ = NULL; |
| 5467 } | 5489 } |
| 5468 | 5490 |
| 5491 store_buffer()->TearDown(); |
| 5492 incremental_marking()->TearDown(); |
| 5493 |
| 5469 isolate_->memory_allocator()->TearDown(); | 5494 isolate_->memory_allocator()->TearDown(); |
| 5470 | 5495 |
| 5471 #ifdef DEBUG | 5496 #ifdef DEBUG |
| 5472 delete debug_utils_; | 5497 delete debug_utils_; |
| 5473 debug_utils_ = NULL; | 5498 debug_utils_ = NULL; |
| 5474 #endif | 5499 #endif |
| 5475 } | 5500 } |
| 5476 | 5501 |
| 5477 | 5502 |
| 5478 void Heap::Shrink() { | 5503 void Heap::Shrink() { |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5675 } | 5700 } |
| 5676 | 5701 |
| 5677 | 5702 |
| 5678 class HeapObjectsFilter { | 5703 class HeapObjectsFilter { |
| 5679 public: | 5704 public: |
| 5680 virtual ~HeapObjectsFilter() {} | 5705 virtual ~HeapObjectsFilter() {} |
| 5681 virtual bool SkipObject(HeapObject* object) = 0; | 5706 virtual bool SkipObject(HeapObject* object) = 0; |
| 5682 }; | 5707 }; |
| 5683 | 5708 |
| 5684 | 5709 |
| 5685 class FreeListNodesFilter : public HeapObjectsFilter { | |
| 5686 public: | |
| 5687 FreeListNodesFilter() { | |
| 5688 MarkFreeListNodes(); | |
| 5689 } | |
| 5690 | |
| 5691 bool SkipObject(HeapObject* object) { | |
| 5692 if (object->IsMarked()) { | |
| 5693 object->ClearMark(); | |
| 5694 return true; | |
| 5695 } else { | |
| 5696 return false; | |
| 5697 } | |
| 5698 } | |
| 5699 | |
| 5700 private: | |
| 5701 void MarkFreeListNodes() { | |
| 5702 Heap* heap = HEAP; | |
| 5703 heap->old_pointer_space()->MarkFreeListNodes(); | |
| 5704 heap->old_data_space()->MarkFreeListNodes(); | |
| 5705 MarkCodeSpaceFreeListNodes(heap); | |
| 5706 heap->map_space()->MarkFreeListNodes(); | |
| 5707 heap->cell_space()->MarkFreeListNodes(); | |
| 5708 } | |
| 5709 | |
| 5710 void MarkCodeSpaceFreeListNodes(Heap* heap) { | |
| 5711 // For code space, using FreeListNode::IsFreeListNode is OK. | |
| 5712 HeapObjectIterator iter(heap->code_space()); | |
| 5713 for (HeapObject* obj = iter.next_object(); | |
| 5714 obj != NULL; | |
| 5715 obj = iter.next_object()) { | |
| 5716 if (FreeListNode::IsFreeListNode(obj)) obj->SetMark(); | |
| 5717 } | |
| 5718 } | |
| 5719 | |
| 5720 AssertNoAllocation no_alloc; | |
| 5721 }; | |
| 5722 | |
| 5723 | |
| 5724 class UnreachableObjectsFilter : public HeapObjectsFilter { | 5710 class UnreachableObjectsFilter : public HeapObjectsFilter { |
| 5725 public: | 5711 public: |
| 5726 UnreachableObjectsFilter() { | 5712 UnreachableObjectsFilter() { |
| 5727 MarkUnreachableObjects(); | 5713 MarkUnreachableObjects(); |
| 5728 } | 5714 } |
| 5729 | 5715 |
| 5730 bool SkipObject(HeapObject* object) { | 5716 bool SkipObject(HeapObject* object) { |
| 5731 if (object->IsMarked()) { | 5717 if (IntrusiveMarking::IsMarked(object)) { |
| 5732 object->ClearMark(); | 5718 IntrusiveMarking::ClearMark(object); |
| 5733 return true; | 5719 return true; |
| 5734 } else { | 5720 } else { |
| 5735 return false; | 5721 return false; |
| 5736 } | 5722 } |
| 5737 } | 5723 } |
| 5738 | 5724 |
| 5739 private: | 5725 private: |
| 5740 class UnmarkingVisitor : public ObjectVisitor { | 5726 class UnmarkingVisitor : public ObjectVisitor { |
| 5741 public: | 5727 public: |
| 5742 UnmarkingVisitor() : list_(10) {} | 5728 UnmarkingVisitor() : list_(10) {} |
| 5743 | 5729 |
| 5744 void VisitPointers(Object** start, Object** end) { | 5730 void VisitPointers(Object** start, Object** end) { |
| 5745 for (Object** p = start; p < end; p++) { | 5731 for (Object** p = start; p < end; p++) { |
| 5746 if (!(*p)->IsHeapObject()) continue; | 5732 if (!(*p)->IsHeapObject()) continue; |
| 5747 HeapObject* obj = HeapObject::cast(*p); | 5733 HeapObject* obj = HeapObject::cast(*p); |
| 5748 if (obj->IsMarked()) { | 5734 if (IntrusiveMarking::IsMarked(obj)) { |
| 5749 obj->ClearMark(); | 5735 IntrusiveMarking::ClearMark(obj); |
| 5750 list_.Add(obj); | 5736 list_.Add(obj); |
| 5751 } | 5737 } |
| 5752 } | 5738 } |
| 5753 } | 5739 } |
| 5754 | 5740 |
| 5755 bool can_process() { return !list_.is_empty(); } | 5741 bool can_process() { return !list_.is_empty(); } |
| 5756 | 5742 |
| 5757 void ProcessNext() { | 5743 void ProcessNext() { |
| 5758 HeapObject* obj = list_.RemoveLast(); | 5744 HeapObject* obj = list_.RemoveLast(); |
| 5759 obj->Iterate(this); | 5745 obj->Iterate(this); |
| 5760 } | 5746 } |
| 5761 | 5747 |
| 5762 private: | 5748 private: |
| 5763 List<HeapObject*> list_; | 5749 List<HeapObject*> list_; |
| 5764 }; | 5750 }; |
| 5765 | 5751 |
| 5766 void MarkUnreachableObjects() { | 5752 void MarkUnreachableObjects() { |
| 5767 HeapIterator iterator; | 5753 HeapIterator iterator; |
| 5768 for (HeapObject* obj = iterator.next(); | 5754 for (HeapObject* obj = iterator.next(); |
| 5769 obj != NULL; | 5755 obj != NULL; |
| 5770 obj = iterator.next()) { | 5756 obj = iterator.next()) { |
| 5771 obj->SetMark(); | 5757 IntrusiveMarking::SetMark(obj); |
| 5772 } | 5758 } |
| 5773 UnmarkingVisitor visitor; | 5759 UnmarkingVisitor visitor; |
| 5774 HEAP->IterateRoots(&visitor, VISIT_ALL); | 5760 HEAP->IterateRoots(&visitor, VISIT_ALL); |
| 5775 while (visitor.can_process()) | 5761 while (visitor.can_process()) |
| 5776 visitor.ProcessNext(); | 5762 visitor.ProcessNext(); |
| 5777 } | 5763 } |
| 5778 | 5764 |
| 5779 AssertNoAllocation no_alloc; | 5765 AssertNoAllocation no_alloc; |
| 5780 }; | 5766 }; |
| 5781 | 5767 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 5795 | 5781 |
| 5796 | 5782 |
| 5797 HeapIterator::~HeapIterator() { | 5783 HeapIterator::~HeapIterator() { |
| 5798 Shutdown(); | 5784 Shutdown(); |
| 5799 } | 5785 } |
| 5800 | 5786 |
| 5801 | 5787 |
| 5802 void HeapIterator::Init() { | 5788 void HeapIterator::Init() { |
| 5803 // Start the iteration. | 5789 // Start the iteration. |
| 5804 space_iterator_ = filtering_ == kNoFiltering ? new SpaceIterator : | 5790 space_iterator_ = filtering_ == kNoFiltering ? new SpaceIterator : |
| 5805 new SpaceIterator(MarkCompactCollector::SizeOfMarkedObject); | 5791 new SpaceIterator(Isolate::Current()->heap()-> |
| 5792 GcSafeSizeOfOldObjectFunction()); |
| 5806 switch (filtering_) { | 5793 switch (filtering_) { |
| 5807 case kFilterFreeListNodes: | 5794 case kFilterFreeListNodes: |
| 5808 filter_ = new FreeListNodesFilter; | 5795 // TODO(gc): Not handled. |
| 5809 break; | 5796 break; |
| 5810 case kFilterUnreachable: | 5797 case kFilterUnreachable: |
| 5811 filter_ = new UnreachableObjectsFilter; | 5798 filter_ = new UnreachableObjectsFilter; |
| 5812 break; | 5799 break; |
| 5813 default: | 5800 default: |
| 5814 break; | 5801 break; |
| 5815 } | 5802 } |
| 5816 object_iterator_ = space_iterator_->next(); | 5803 object_iterator_ = space_iterator_->next(); |
| 5817 } | 5804 } |
| 5818 | 5805 |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5935 MarkVisitor mark_visitor(this); | 5922 MarkVisitor mark_visitor(this); |
| 5936 MarkRecursively(root, &mark_visitor); | 5923 MarkRecursively(root, &mark_visitor); |
| 5937 | 5924 |
| 5938 UnmarkVisitor unmark_visitor(this); | 5925 UnmarkVisitor unmark_visitor(this); |
| 5939 UnmarkRecursively(root, &unmark_visitor); | 5926 UnmarkRecursively(root, &unmark_visitor); |
| 5940 | 5927 |
| 5941 ProcessResults(); | 5928 ProcessResults(); |
| 5942 } | 5929 } |
| 5943 | 5930 |
| 5944 | 5931 |
| 5932 static bool SafeIsGlobalContext(HeapObject* obj) { |
| 5933 return obj->map() == obj->GetHeap()->raw_unchecked_global_context_map(); |
| 5934 } |
| 5935 |
| 5936 |
| 5945 void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) { | 5937 void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) { |
| 5946 if (!(*p)->IsHeapObject()) return; | 5938 if (!(*p)->IsHeapObject()) return; |
| 5947 | 5939 |
| 5948 HeapObject* obj = HeapObject::cast(*p); | 5940 HeapObject* obj = HeapObject::cast(*p); |
| 5949 | 5941 |
| 5950 Object* map = obj->map(); | 5942 Object* map = obj->map(); |
| 5951 | 5943 |
| 5952 if (!map->IsHeapObject()) return; // visited before | 5944 if (!map->IsHeapObject()) return; // visited before |
| 5953 | 5945 |
| 5954 if (found_target_in_trace_) return; // stop if target found | 5946 if (found_target_in_trace_) return; // stop if target found |
| 5955 object_stack_.Add(obj); | 5947 object_stack_.Add(obj); |
| 5956 if (((search_target_ == kAnyGlobalObject) && obj->IsJSGlobalObject()) || | 5948 if (((search_target_ == kAnyGlobalObject) && obj->IsJSGlobalObject()) || |
| 5957 (obj == search_target_)) { | 5949 (obj == search_target_)) { |
| 5958 found_target_in_trace_ = true; | 5950 found_target_in_trace_ = true; |
| 5959 found_target_ = true; | 5951 found_target_ = true; |
| 5960 return; | 5952 return; |
| 5961 } | 5953 } |
| 5962 | 5954 |
| 5963 bool is_global_context = obj->IsGlobalContext(); | 5955 bool is_global_context = SafeIsGlobalContext(obj); |
| 5964 | 5956 |
| 5965 // not visited yet | 5957 // not visited yet |
| 5966 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map)); | 5958 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map)); |
| 5967 | 5959 |
| 5968 Address map_addr = map_p->address(); | 5960 Address map_addr = map_p->address(); |
| 5969 | 5961 |
| 5970 obj->set_map(reinterpret_cast<Map*>(map_addr + kMarkTag)); | 5962 obj->set_map(reinterpret_cast<Map*>(map_addr + kMarkTag)); |
| 5971 | 5963 |
| 5972 // Scan the object body. | 5964 // Scan the object body. |
| 5973 if (is_global_context && (visit_mode_ == VISIT_ONLY_STRONG)) { | 5965 if (is_global_context && (visit_mode_ == VISIT_ONLY_STRONG)) { |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6061 } | 6053 } |
| 6062 #endif | 6054 #endif |
| 6063 | 6055 |
| 6064 | 6056 |
| 6065 static intptr_t CountTotalHolesSize() { | 6057 static intptr_t CountTotalHolesSize() { |
| 6066 intptr_t holes_size = 0; | 6058 intptr_t holes_size = 0; |
| 6067 OldSpaces spaces; | 6059 OldSpaces spaces; |
| 6068 for (OldSpace* space = spaces.next(); | 6060 for (OldSpace* space = spaces.next(); |
| 6069 space != NULL; | 6061 space != NULL; |
| 6070 space = spaces.next()) { | 6062 space = spaces.next()) { |
| 6071 holes_size += space->Waste() + space->AvailableFree(); | 6063 holes_size += space->Waste() + space->Available(); |
| 6072 } | 6064 } |
| 6073 return holes_size; | 6065 return holes_size; |
| 6074 } | 6066 } |
| 6075 | 6067 |
| 6076 | 6068 |
| 6077 GCTracer::GCTracer(Heap* heap) | 6069 GCTracer::GCTracer(Heap* heap) |
| 6078 : start_time_(0.0), | 6070 : start_time_(0.0), |
| 6079 start_size_(0), | 6071 start_size_(0), |
| 6080 gc_count_(0), | 6072 gc_count_(0), |
| 6081 full_gc_count_(0), | 6073 full_gc_count_(0), |
| 6082 is_compacting_(false), | |
| 6083 marked_count_(0), | |
| 6084 allocated_since_last_gc_(0), | 6074 allocated_since_last_gc_(0), |
| 6085 spent_in_mutator_(0), | 6075 spent_in_mutator_(0), |
| 6086 promoted_objects_size_(0), | 6076 promoted_objects_size_(0), |
| 6087 heap_(heap) { | 6077 heap_(heap) { |
| 6088 // These two fields reflect the state of the previous full collection. | |
| 6089 // Set them before they are changed by the collector. | |
| 6090 previous_has_compacted_ = heap_->mark_compact_collector_.HasCompacted(); | |
| 6091 previous_marked_count_ = | |
| 6092 heap_->mark_compact_collector_.previous_marked_count(); | |
| 6093 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; | 6078 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; |
| 6094 start_time_ = OS::TimeCurrentMillis(); | 6079 start_time_ = OS::TimeCurrentMillis(); |
| 6095 start_size_ = heap_->SizeOfObjects(); | 6080 start_size_ = heap_->SizeOfObjects(); |
| 6096 | 6081 |
| 6097 for (int i = 0; i < Scope::kNumberOfScopes; i++) { | 6082 for (int i = 0; i < Scope::kNumberOfScopes; i++) { |
| 6098 scopes_[i] = 0; | 6083 scopes_[i] = 0; |
| 6099 } | 6084 } |
| 6100 | 6085 |
| 6101 in_free_list_or_wasted_before_gc_ = CountTotalHolesSize(); | 6086 in_free_list_or_wasted_before_gc_ = CountTotalHolesSize(); |
| 6102 | 6087 |
| 6103 allocated_since_last_gc_ = | 6088 allocated_since_last_gc_ = |
| 6104 heap_->SizeOfObjects() - heap_->alive_after_last_gc_; | 6089 heap_->SizeOfObjects() - heap_->alive_after_last_gc_; |
| 6105 | 6090 |
| 6106 if (heap_->last_gc_end_timestamp_ > 0) { | 6091 if (heap_->last_gc_end_timestamp_ > 0) { |
| 6107 spent_in_mutator_ = Max(start_time_ - heap_->last_gc_end_timestamp_, 0.0); | 6092 spent_in_mutator_ = Max(start_time_ - heap_->last_gc_end_timestamp_, 0.0); |
| 6108 } | 6093 } |
| 6094 |
| 6095 steps_count_ = heap_->incremental_marking()->steps_count(); |
| 6096 steps_took_ = heap_->incremental_marking()->steps_took(); |
| 6097 longest_step_ = heap_->incremental_marking()->longest_step(); |
| 6098 steps_count_since_last_gc_ = |
| 6099 heap_->incremental_marking()->steps_count_since_last_gc(); |
| 6100 steps_took_since_last_gc_ = |
| 6101 heap_->incremental_marking()->steps_took_since_last_gc(); |
| 6109 } | 6102 } |
| 6110 | 6103 |
| 6111 | 6104 |
| 6112 GCTracer::~GCTracer() { | 6105 GCTracer::~GCTracer() { |
| 6113 // Printf ONE line iff flag is set. | 6106 // Printf ONE line iff flag is set. |
| 6114 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; | 6107 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; |
| 6115 | 6108 |
| 6116 bool first_gc = (heap_->last_gc_end_timestamp_ == 0); | 6109 bool first_gc = (heap_->last_gc_end_timestamp_ == 0); |
| 6117 | 6110 |
| 6118 heap_->alive_after_last_gc_ = heap_->SizeOfObjects(); | 6111 heap_->alive_after_last_gc_ = heap_->SizeOfObjects(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 6133 | 6126 |
| 6134 if (!FLAG_trace_gc_nvp) { | 6127 if (!FLAG_trace_gc_nvp) { |
| 6135 int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]); | 6128 int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]); |
| 6136 | 6129 |
| 6137 PrintF("%s %.1f -> %.1f MB, ", | 6130 PrintF("%s %.1f -> %.1f MB, ", |
| 6138 CollectorString(), | 6131 CollectorString(), |
| 6139 static_cast<double>(start_size_) / MB, | 6132 static_cast<double>(start_size_) / MB, |
| 6140 SizeOfHeapObjects()); | 6133 SizeOfHeapObjects()); |
| 6141 | 6134 |
| 6142 if (external_time > 0) PrintF("%d / ", external_time); | 6135 if (external_time > 0) PrintF("%d / ", external_time); |
| 6143 PrintF("%d ms.\n", time); | 6136 PrintF("%d ms", time); |
| 6137 if (steps_count_ > 0) { |
| 6138 if (collector_ == SCAVENGER) { |
| 6139 PrintF(" (+ %d ms in %d steps since last GC)", |
| 6140 static_cast<int>(steps_took_since_last_gc_), |
| 6141 steps_count_since_last_gc_); |
| 6142 } else { |
| 6143 PrintF(" (+ %d ms in %d steps since start of marking, " |
| 6144 "biggest step %f ms)", |
| 6145 static_cast<int>(steps_took_), |
| 6146 steps_count_, |
| 6147 longest_step_); |
| 6148 } |
| 6149 } |
| 6150 PrintF(".\n"); |
| 6144 } else { | 6151 } else { |
| 6145 PrintF("pause=%d ", time); | 6152 PrintF("pause=%d ", time); |
| 6146 PrintF("mutator=%d ", | 6153 PrintF("mutator=%d ", |
| 6147 static_cast<int>(spent_in_mutator_)); | 6154 static_cast<int>(spent_in_mutator_)); |
| 6148 | 6155 |
| 6149 PrintF("gc="); | 6156 PrintF("gc="); |
| 6150 switch (collector_) { | 6157 switch (collector_) { |
| 6151 case SCAVENGER: | 6158 case SCAVENGER: |
| 6152 PrintF("s"); | 6159 PrintF("s"); |
| 6153 break; | 6160 break; |
| 6154 case MARK_COMPACTOR: | 6161 case MARK_COMPACTOR: |
| 6155 PrintF("%s", | 6162 PrintF("ms"); |
| 6156 heap_->mark_compact_collector_.HasCompacted() ? "mc" : "ms"); | |
| 6157 break; | 6163 break; |
| 6158 default: | 6164 default: |
| 6159 UNREACHABLE(); | 6165 UNREACHABLE(); |
| 6160 } | 6166 } |
| 6161 PrintF(" "); | 6167 PrintF(" "); |
| 6162 | 6168 |
| 6163 PrintF("external=%d ", static_cast<int>(scopes_[Scope::EXTERNAL])); | 6169 PrintF("external=%d ", static_cast<int>(scopes_[Scope::EXTERNAL])); |
| 6164 PrintF("mark=%d ", static_cast<int>(scopes_[Scope::MC_MARK])); | 6170 PrintF("mark=%d ", static_cast<int>(scopes_[Scope::MC_MARK])); |
| 6165 PrintF("sweep=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP])); | 6171 PrintF("sweep=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP])); |
| 6166 PrintF("sweepns=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP_NEWSPACE])); | 6172 PrintF("sweepns=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP_NEWSPACE])); |
| 6167 PrintF("compact=%d ", static_cast<int>(scopes_[Scope::MC_COMPACT])); | 6173 PrintF("compact=%d ", static_cast<int>(scopes_[Scope::MC_COMPACT])); |
| 6168 | 6174 |
| 6169 PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_size_); | 6175 PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_size_); |
| 6170 PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects()); | 6176 PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects()); |
| 6171 PrintF("holes_size_before=%" V8_PTR_PREFIX "d ", | 6177 PrintF("holes_size_before=%" V8_PTR_PREFIX "d ", |
| 6172 in_free_list_or_wasted_before_gc_); | 6178 in_free_list_or_wasted_before_gc_); |
| 6173 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize()); | 6179 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize()); |
| 6174 | 6180 |
| 6175 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_); | 6181 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_); |
| 6176 PrintF("promoted=%" V8_PTR_PREFIX "d ", promoted_objects_size_); | 6182 PrintF("promoted=%" V8_PTR_PREFIX "d ", promoted_objects_size_); |
| 6177 | 6183 |
| 6184 if (collector_ == SCAVENGER) { |
| 6185 PrintF("stepscount=%d ", steps_count_since_last_gc_); |
| 6186 PrintF("stepstook=%d ", static_cast<int>(steps_took_since_last_gc_)); |
| 6187 } else { |
| 6188 PrintF("stepscount=%d ", steps_count_); |
| 6189 PrintF("stepstook=%d ", static_cast<int>(steps_took_)); |
| 6190 } |
| 6191 |
| 6178 PrintF("\n"); | 6192 PrintF("\n"); |
| 6179 } | 6193 } |
| 6180 | 6194 |
| 6181 heap_->PrintShortHeapStatistics(); | 6195 heap_->PrintShortHeapStatistics(); |
| 6182 } | 6196 } |
| 6183 | 6197 |
| 6184 | 6198 |
| 6185 const char* GCTracer::CollectorString() { | 6199 const char* GCTracer::CollectorString() { |
| 6186 switch (collector_) { | 6200 switch (collector_) { |
| 6187 case SCAVENGER: | 6201 case SCAVENGER: |
| 6188 return "Scavenge"; | 6202 return "Scavenge"; |
| 6189 case MARK_COMPACTOR: | 6203 case MARK_COMPACTOR: |
| 6190 return heap_->mark_compact_collector_.HasCompacted() ? "Mark-compact" | 6204 return "Mark-sweep"; |
| 6191 : "Mark-sweep"; | |
| 6192 } | 6205 } |
| 6193 return "Unknown GC"; | 6206 return "Unknown GC"; |
| 6194 } | 6207 } |
| 6195 | 6208 |
| 6196 | 6209 |
| 6197 int KeyedLookupCache::Hash(Map* map, String* name) { | 6210 int KeyedLookupCache::Hash(Map* map, String* name) { |
| 6198 // Uses only lower 32 bits if pointers are larger. | 6211 // Uses only lower 32 bits if pointers are larger. |
| 6199 uintptr_t addr_hash = | 6212 uintptr_t addr_hash = |
| 6200 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift; | 6213 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift; |
| 6201 return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask); | 6214 return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6288 Verify(); | 6301 Verify(); |
| 6289 } | 6302 } |
| 6290 | 6303 |
| 6291 | 6304 |
| 6292 void ExternalStringTable::TearDown() { | 6305 void ExternalStringTable::TearDown() { |
| 6293 new_space_strings_.Free(); | 6306 new_space_strings_.Free(); |
| 6294 old_space_strings_.Free(); | 6307 old_space_strings_.Free(); |
| 6295 } | 6308 } |
| 6296 | 6309 |
| 6297 | 6310 |
| 6311 void Heap::QueueMemoryChunkForFree(MemoryChunk* chunk) { |
| 6312 chunk->set_next_chunk(chunks_queued_for_free_); |
| 6313 chunks_queued_for_free_ = chunk; |
| 6314 } |
| 6315 |
| 6316 |
| 6317 void Heap::FreeQueuedChunks() { |
| 6318 if (chunks_queued_for_free_ == NULL) return; |
| 6319 MemoryChunk* next; |
| 6320 MemoryChunk* chunk; |
| 6321 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) { |
| 6322 next = chunk->next_chunk(); |
| 6323 chunk->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED); |
| 6324 |
| 6325 if (chunk->owner()->identity() == LO_SPACE) { |
| 6326 // StoreBuffer::Filter relies on MemoryChunk::FromAnyPointerAddress. |
| 6327 // If FromAnyPointerAddress encounters a slot that belongs to a large |
| 6328 // chunk queued for deletion it will fail to find the chunk because |
| 6329 // it try to perform a search in the list of pages owned by of the large |
| 6330 // object space and queued chunks were detached from that list. |
| 6331 // To work around this we split large chunk into normal kPageSize aligned |
| 6332 // pieces and initialize owner field and flags of every piece. |
| 6333 // If FromAnyPointerAddress encounteres a slot that belongs to one of |
| 6334 // these smaller pieces it will treat it as a slot on a normal Page. |
| 6335 MemoryChunk* inner = MemoryChunk::FromAddress( |
| 6336 chunk->address() + Page::kPageSize); |
| 6337 MemoryChunk* inner_last = MemoryChunk::FromAddress( |
| 6338 chunk->address() + chunk->size() - 1); |
| 6339 while (inner <= inner_last) { |
| 6340 // Size of a large chunk is always a multiple of |
| 6341 // OS::AllocationAlignment() so there is always |
| 6342 // enough space for a fake MemoryChunk header. |
| 6343 inner->set_owner(lo_space()); |
| 6344 inner->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED); |
| 6345 inner = MemoryChunk::FromAddress( |
| 6346 inner->address() + Page::kPageSize); |
| 6347 } |
| 6348 } |
| 6349 } |
| 6350 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED); |
| 6351 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) { |
| 6352 next = chunk->next_chunk(); |
| 6353 isolate_->memory_allocator()->Free(chunk); |
| 6354 } |
| 6355 chunks_queued_for_free_ = NULL; |
| 6356 } |
| 6357 |
| 6298 } } // namespace v8::internal | 6358 } } // namespace v8::internal |
| OLD | NEW |