| 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_(700ul * LUMP_OF_MEMORY), |
| 85 max_executable_size_(128l * 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 chunks_queued_for_free_(NULL) { |
| 150 // Allow build-time customization of the max semispace size. Building | 148 // Allow build-time customization of the max semispace size. Building |
| 151 // V8 with snapshots and a non-default max semispace size is much | 149 // 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. | 150 // easier if you can define it as part of the build environment. |
| 153 #if defined(V8_MAX_SEMISPACE_SIZE) | 151 #if defined(V8_MAX_SEMISPACE_SIZE) |
| 154 max_semispace_size_ = reserved_semispace_size_ = V8_MAX_SEMISPACE_SIZE; | 152 max_semispace_size_ = reserved_semispace_size_ = V8_MAX_SEMISPACE_SIZE; |
| 155 #endif | 153 #endif |
| 156 | 154 |
| 157 intptr_t max_virtual = OS::MaxVirtualMemory(); | 155 intptr_t max_virtual = OS::MaxVirtualMemory(); |
| 158 | 156 |
| 159 if (max_virtual > 0) { | 157 if (max_virtual > 0) { |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 return old_pointer_space_ != NULL && | 215 return old_pointer_space_ != NULL && |
| 218 old_data_space_ != NULL && | 216 old_data_space_ != NULL && |
| 219 code_space_ != NULL && | 217 code_space_ != NULL && |
| 220 map_space_ != NULL && | 218 map_space_ != NULL && |
| 221 cell_space_ != NULL && | 219 cell_space_ != NULL && |
| 222 lo_space_ != NULL; | 220 lo_space_ != NULL; |
| 223 } | 221 } |
| 224 | 222 |
| 225 | 223 |
| 226 int Heap::GcSafeSizeOfOldObject(HeapObject* object) { | 224 int Heap::GcSafeSizeOfOldObject(HeapObject* object) { |
| 227 ASSERT(!HEAP->InNewSpace(object)); // Code only works for old objects. | 225 if (IntrusiveMarking::IsMarked(object)) { |
| 228 ASSERT(!HEAP->mark_compact_collector()->are_map_pointers_encoded()); | 226 return IntrusiveMarking::SizeOfMarkedObject(object); |
| 229 MapWord map_word = object->map_word(); | 227 } |
| 230 map_word.ClearMark(); | 228 return object->SizeFromMap(object->map()); |
| 231 map_word.ClearOverflow(); | |
| 232 return object->SizeFromMap(map_word.ToMap()); | |
| 233 } | 229 } |
| 234 | 230 |
| 235 | 231 |
| 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) { | 232 GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space) { |
| 254 // Is global GC requested? | 233 // Is global GC requested? |
| 255 if (space != NEW_SPACE || FLAG_gc_global) { | 234 if (space != NEW_SPACE || FLAG_gc_global) { |
| 256 isolate_->counters()->gc_compactor_caused_by_request()->Increment(); | 235 isolate_->counters()->gc_compactor_caused_by_request()->Increment(); |
| 257 return MARK_COMPACTOR; | 236 return MARK_COMPACTOR; |
| 258 } | 237 } |
| 259 | 238 |
| 260 // Is enough data promoted to justify a global GC? | 239 // Is enough data promoted to justify a global GC? |
| 261 if (OldGenerationPromotionLimitReached()) { | 240 if (OldGenerationPromotionLimitReached()) { |
| 262 isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment(); | 241 isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment(); |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 393 } | 372 } |
| 394 | 373 |
| 395 if (FLAG_gc_verbose) Print(); | 374 if (FLAG_gc_verbose) Print(); |
| 396 #endif // DEBUG | 375 #endif // DEBUG |
| 397 | 376 |
| 398 #if defined(DEBUG) | 377 #if defined(DEBUG) |
| 399 ReportStatisticsBeforeGC(); | 378 ReportStatisticsBeforeGC(); |
| 400 #endif // DEBUG | 379 #endif // DEBUG |
| 401 | 380 |
| 402 LiveObjectList::GCPrologue(); | 381 LiveObjectList::GCPrologue(); |
| 382 store_buffer()->GCPrologue(); |
| 403 } | 383 } |
| 404 | 384 |
| 405 intptr_t Heap::SizeOfObjects() { | 385 intptr_t Heap::SizeOfObjects() { |
| 406 intptr_t total = 0; | 386 intptr_t total = 0; |
| 407 AllSpaces spaces; | 387 AllSpaces spaces; |
| 408 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) { | 388 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) { |
| 409 total += space->SizeOfObjects(); | 389 total += space->SizeOfObjects(); |
| 410 } | 390 } |
| 411 return total; | 391 return total; |
| 412 } | 392 } |
| 413 | 393 |
| 414 void Heap::GarbageCollectionEpilogue() { | 394 void Heap::GarbageCollectionEpilogue() { |
| 395 store_buffer()->GCEpilogue(); |
| 415 LiveObjectList::GCEpilogue(); | 396 LiveObjectList::GCEpilogue(); |
| 416 #ifdef DEBUG | 397 #ifdef DEBUG |
| 417 allow_allocation(true); | 398 allow_allocation(true); |
| 418 ZapFromSpace(); | 399 ZapFromSpace(); |
| 419 | 400 |
| 420 if (FLAG_verify_heap) { | 401 if (FLAG_verify_heap) { |
| 421 Verify(); | 402 Verify(); |
| 422 } | 403 } |
| 423 | 404 |
| 424 if (FLAG_print_global_handles) isolate_->global_handles()->Print(); | 405 if (FLAG_print_global_handles) isolate_->global_handles()->Print(); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 436 symbol_table()->NumberOfElements()); | 417 symbol_table()->NumberOfElements()); |
| 437 #if defined(DEBUG) | 418 #if defined(DEBUG) |
| 438 ReportStatisticsAfterGC(); | 419 ReportStatisticsAfterGC(); |
| 439 #endif // DEBUG | 420 #endif // DEBUG |
| 440 #ifdef ENABLE_DEBUGGER_SUPPORT | 421 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 441 isolate_->debug()->AfterGarbageCollection(); | 422 isolate_->debug()->AfterGarbageCollection(); |
| 442 #endif // ENABLE_DEBUGGER_SUPPORT | 423 #endif // ENABLE_DEBUGGER_SUPPORT |
| 443 } | 424 } |
| 444 | 425 |
| 445 | 426 |
| 446 void Heap::CollectAllGarbage(bool force_compaction) { | 427 void Heap::CollectAllGarbage(int flags) { |
| 447 // Since we are ignoring the return value, the exact choice of space does | 428 // 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 | 429 // not matter, so long as we do not specify NEW_SPACE, which would not |
| 449 // cause a full GC. | 430 // cause a full GC. |
| 450 mark_compact_collector_.SetForceCompaction(force_compaction); | 431 mark_compact_collector_.SetFlags(flags); |
| 451 CollectGarbage(OLD_POINTER_SPACE); | 432 CollectGarbage(OLD_POINTER_SPACE); |
| 452 mark_compact_collector_.SetForceCompaction(false); | 433 mark_compact_collector_.SetFlags(kNoGCFlags); |
| 453 } | 434 } |
| 454 | 435 |
| 455 | 436 |
| 456 void Heap::CollectAllAvailableGarbage() { | 437 void Heap::CollectAllAvailableGarbage() { |
| 457 // Since we are ignoring the return value, the exact choice of space does | 438 // 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 | 439 // not matter, so long as we do not specify NEW_SPACE, which would not |
| 459 // cause a full GC. | 440 // cause a full GC. |
| 460 mark_compact_collector()->SetForceCompaction(true); | |
| 461 | |
| 462 // Major GC would invoke weak handle callbacks on weakly reachable | 441 // Major GC would invoke weak handle callbacks on weakly reachable |
| 463 // handles, but won't collect weakly reachable objects until next | 442 // handles, but won't collect weakly reachable objects until next |
| 464 // major GC. Therefore if we collect aggressively and weak handle callback | 443 // major GC. Therefore if we collect aggressively and weak handle callback |
| 465 // has been invoked, we rerun major GC to release objects which become | 444 // has been invoked, we rerun major GC to release objects which become |
| 466 // garbage. | 445 // garbage. |
| 467 // Note: as weak callbacks can execute arbitrary code, we cannot | 446 // Note: as weak callbacks can execute arbitrary code, we cannot |
| 468 // hope that eventually there will be no weak callbacks invocations. | 447 // hope that eventually there will be no weak callbacks invocations. |
| 469 // Therefore stop recollecting after several attempts. | 448 // Therefore stop recollecting after several attempts. |
| 449 mark_compact_collector()->SetFlags(kMakeHeapIterableMask); |
| 470 const int kMaxNumberOfAttempts = 7; | 450 const int kMaxNumberOfAttempts = 7; |
| 471 for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) { | 451 for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) { |
| 472 if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR)) { | 452 if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR)) { |
| 473 break; | 453 break; |
| 474 } | 454 } |
| 475 } | 455 } |
| 476 mark_compact_collector()->SetForceCompaction(false); | 456 mark_compact_collector()->SetFlags(kNoGCFlags); |
| 477 } | 457 } |
| 478 | 458 |
| 479 | 459 |
| 480 bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) { | 460 bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) { |
| 481 // The VM is in the GC state until exiting this function. | 461 // The VM is in the GC state until exiting this function. |
| 482 VMState state(isolate_, GC); | 462 VMState state(isolate_, GC); |
| 483 | 463 |
| 484 #ifdef DEBUG | 464 #ifdef DEBUG |
| 485 // Reset the allocation timeout to the GC interval, but make sure to | 465 // Reset the allocation timeout to the GC interval, but make sure to |
| 486 // allow at least a few allocations after a collection. The reason | 466 // 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 | 467 // for this is that we have a lot of allocation sequences and we |
| 488 // assume that a garbage collection will allow the subsequent | 468 // assume that a garbage collection will allow the subsequent |
| 489 // allocation attempts to go through. | 469 // allocation attempts to go through. |
| 490 allocation_timeout_ = Max(6, FLAG_gc_interval); | 470 allocation_timeout_ = Max(6, FLAG_gc_interval); |
| 491 #endif | 471 #endif |
| 492 | 472 |
| 473 if (collector == SCAVENGER && !incremental_marking()->IsStopped()) { |
| 474 if (FLAG_trace_incremental_marking) { |
| 475 PrintF("[IncrementalMarking] Scavenge during marking.\n"); |
| 476 } |
| 477 } |
| 478 |
| 479 if (collector == MARK_COMPACTOR && |
| 480 !mark_compact_collector()->PreciseSweepingRequired() && |
| 481 !incremental_marking()->IsStopped() && |
| 482 !incremental_marking()->should_hurry() && |
| 483 FLAG_incremental_marking_steps) { |
| 484 if (FLAG_trace_incremental_marking) { |
| 485 PrintF("[IncrementalMarking] Delaying MarkSweep.\n"); |
| 486 } |
| 487 collector = SCAVENGER; |
| 488 } |
| 489 |
| 493 bool next_gc_likely_to_collect_more = false; | 490 bool next_gc_likely_to_collect_more = false; |
| 494 | 491 |
| 495 { GCTracer tracer(this); | 492 { GCTracer tracer(this); |
| 496 GarbageCollectionPrologue(); | 493 GarbageCollectionPrologue(); |
| 497 // The GC count was incremented in the prologue. Tell the tracer about | 494 // The GC count was incremented in the prologue. Tell the tracer about |
| 498 // it. | 495 // it. |
| 499 tracer.set_gc_count(gc_count_); | 496 tracer.set_gc_count(gc_count_); |
| 500 | 497 |
| 501 // Tell the tracer which collector we've selected. | 498 // Tell the tracer which collector we've selected. |
| 502 tracer.set_collector(collector); | 499 tracer.set_collector(collector); |
| 503 | 500 |
| 504 HistogramTimer* rate = (collector == SCAVENGER) | 501 HistogramTimer* rate = (collector == SCAVENGER) |
| 505 ? isolate_->counters()->gc_scavenger() | 502 ? isolate_->counters()->gc_scavenger() |
| 506 : isolate_->counters()->gc_compactor(); | 503 : isolate_->counters()->gc_compactor(); |
| 507 rate->Start(); | 504 rate->Start(); |
| 508 next_gc_likely_to_collect_more = | 505 next_gc_likely_to_collect_more = |
| 509 PerformGarbageCollection(collector, &tracer); | 506 PerformGarbageCollection(collector, &tracer); |
| 510 rate->Stop(); | 507 rate->Stop(); |
| 511 | 508 |
| 512 GarbageCollectionEpilogue(); | 509 GarbageCollectionEpilogue(); |
| 513 } | 510 } |
| 514 | 511 |
| 512 ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped()); |
| 513 if (incremental_marking()->IsStopped()) { |
| 514 if (incremental_marking()->WorthActivating() && NextGCIsLikelyToBeFull()) { |
| 515 incremental_marking()->Start(); |
| 516 } |
| 517 } |
| 518 |
| 515 return next_gc_likely_to_collect_more; | 519 return next_gc_likely_to_collect_more; |
| 516 } | 520 } |
| 517 | 521 |
| 518 | 522 |
| 519 void Heap::PerformScavenge() { | 523 void Heap::PerformScavenge() { |
| 520 GCTracer tracer(this); | 524 GCTracer tracer(this); |
| 521 PerformGarbageCollection(SCAVENGER, &tracer); | 525 if (incremental_marking()->IsStopped()) { |
| 526 PerformGarbageCollection(SCAVENGER, &tracer); |
| 527 } else { |
| 528 PerformGarbageCollection(MARK_COMPACTOR, &tracer); |
| 529 } |
| 522 } | 530 } |
| 523 | 531 |
| 524 | 532 |
| 525 #ifdef DEBUG | 533 #ifdef DEBUG |
| 526 // Helper class for verifying the symbol table. | 534 // Helper class for verifying the symbol table. |
| 527 class SymbolTableVerifier : public ObjectVisitor { | 535 class SymbolTableVerifier : public ObjectVisitor { |
| 528 public: | 536 public: |
| 529 void VisitPointers(Object** start, Object** end) { | 537 void VisitPointers(Object** start, Object** end) { |
| 530 // Visit all HeapObject pointers in [start, end). | 538 // Visit all HeapObject pointers in [start, end). |
| 531 for (Object** p = start; p < end; p++) { | 539 for (Object** p = start; p < end; p++) { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 603 } | 611 } |
| 604 } | 612 } |
| 605 } | 613 } |
| 606 | 614 |
| 607 | 615 |
| 608 void Heap::EnsureFromSpaceIsCommitted() { | 616 void Heap::EnsureFromSpaceIsCommitted() { |
| 609 if (new_space_.CommitFromSpaceIfNeeded()) return; | 617 if (new_space_.CommitFromSpaceIfNeeded()) return; |
| 610 | 618 |
| 611 // Committing memory to from space failed. | 619 // Committing memory to from space failed. |
| 612 // Try shrinking and try again. | 620 // 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(); | 621 Shrink(); |
| 621 if (new_space_.CommitFromSpaceIfNeeded()) return; | 622 if (new_space_.CommitFromSpaceIfNeeded()) return; |
| 622 | 623 |
| 623 // Committing memory to from space failed again. | 624 // Committing memory to from space failed again. |
| 624 // Memory is exhausted and we will die. | 625 // Memory is exhausted and we will die. |
| 625 V8::FatalProcessOutOfMemory("Committing semi space failed."); | 626 V8::FatalProcessOutOfMemory("Committing semi space failed."); |
| 626 } | 627 } |
| 627 | 628 |
| 628 | 629 |
| 629 void Heap::ClearJSFunctionResultCaches() { | 630 void Heap::ClearJSFunctionResultCaches() { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 640 JSFunctionResultCache::cast(caches->get(i))->Clear(); | 641 JSFunctionResultCache::cast(caches->get(i))->Clear(); |
| 641 } | 642 } |
| 642 // Get the next context: | 643 // Get the next context: |
| 643 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); | 644 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); |
| 644 } | 645 } |
| 645 } | 646 } |
| 646 | 647 |
| 647 | 648 |
| 648 | 649 |
| 649 void Heap::ClearNormalizedMapCaches() { | 650 void Heap::ClearNormalizedMapCaches() { |
| 650 if (isolate_->bootstrapper()->IsActive()) return; | 651 if (isolate_->bootstrapper()->IsActive() && |
| 652 !incremental_marking()->IsMarking()) { |
| 653 return; |
| 654 } |
| 651 | 655 |
| 652 Object* context = global_contexts_list_; | 656 Object* context = global_contexts_list_; |
| 653 while (!context->IsUndefined()) { | 657 while (!context->IsUndefined()) { |
| 654 Context::cast(context)->normalized_map_cache()->Clear(); | 658 Context::cast(context)->normalized_map_cache()->Clear(); |
| 655 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); | 659 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); |
| 656 } | 660 } |
| 657 } | 661 } |
| 658 | 662 |
| 659 | 663 |
| 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) { | 664 void Heap::UpdateSurvivalRateTrend(int start_new_space_size) { |
| 679 double survival_rate = | 665 double survival_rate = |
| 680 (static_cast<double>(young_survivors_after_last_gc_) * 100) / | 666 (static_cast<double>(young_survivors_after_last_gc_) * 100) / |
| 681 start_new_space_size; | 667 start_new_space_size; |
| 682 | 668 |
| 683 if (survival_rate > kYoungSurvivalRateThreshold) { | 669 if (survival_rate > kYoungSurvivalRateThreshold) { |
| 684 high_survival_rate_period_length_++; | 670 high_survival_rate_period_length_++; |
| 685 } else { | 671 } else { |
| 686 high_survival_rate_period_length_ = 0; | 672 high_survival_rate_period_length_ = 0; |
| 687 } | 673 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 720 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) { | 706 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) { |
| 721 if (gc_type & gc_prologue_callbacks_[i].gc_type) { | 707 if (gc_type & gc_prologue_callbacks_[i].gc_type) { |
| 722 gc_prologue_callbacks_[i].callback(gc_type, kNoGCCallbackFlags); | 708 gc_prologue_callbacks_[i].callback(gc_type, kNoGCCallbackFlags); |
| 723 } | 709 } |
| 724 } | 710 } |
| 725 | 711 |
| 726 EnsureFromSpaceIsCommitted(); | 712 EnsureFromSpaceIsCommitted(); |
| 727 | 713 |
| 728 int start_new_space_size = Heap::new_space()->SizeAsInt(); | 714 int start_new_space_size = Heap::new_space()->SizeAsInt(); |
| 729 | 715 |
| 716 if (IsHighSurvivalRate()) { |
| 717 // We speed up the incremental marker if it is running so that it |
| 718 // does not fall behind the rate of promotion, which would cause a |
| 719 // constantly growing old space. |
| 720 incremental_marking()->NotifyOfHighPromotionRate(); |
| 721 } |
| 722 |
| 730 if (collector == MARK_COMPACTOR) { | 723 if (collector == MARK_COMPACTOR) { |
| 731 // Perform mark-sweep with optional compaction. | 724 // Perform mark-sweep with optional compaction. |
| 732 MarkCompact(tracer); | 725 MarkCompact(tracer); |
| 733 sweep_generation_++; | 726 sweep_generation_++; |
| 734 bool high_survival_rate_during_scavenges = IsHighSurvivalRate() && | 727 bool high_survival_rate_during_scavenges = IsHighSurvivalRate() && |
| 735 IsStableOrIncreasingSurvivalTrend(); | 728 IsStableOrIncreasingSurvivalTrend(); |
| 736 | 729 |
| 737 UpdateSurvivalRateTrend(start_new_space_size); | 730 UpdateSurvivalRateTrend(start_new_space_size); |
| 738 | 731 |
| 739 intptr_t old_gen_size = PromotedSpaceSize(); | 732 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 | 733 |
| 745 if (high_survival_rate_during_scavenges && | 734 if (high_survival_rate_during_scavenges && |
| 746 IsStableOrIncreasingSurvivalTrend()) { | 735 IsStableOrIncreasingSurvivalTrend()) { |
| 747 // Stable high survival rates of young objects both during partial and | 736 // Stable high survival rates of young objects both during partial and |
| 748 // full collection indicate that mutator is either building or modifying | 737 // full collection indicate that mutator is either building or modifying |
| 749 // a structure with a long lifetime. | 738 // a structure with a long lifetime. |
| 750 // In this case we aggressively raise old generation memory limits to | 739 // In this case we aggressively raise old generation memory limits to |
| 751 // postpone subsequent mark-sweep collection and thus trade memory | 740 // postpone subsequent mark-sweep collection and thus trade memory |
| 752 // space for the mutation speed. | 741 // space for the mutation speed. |
| 753 old_gen_promotion_limit_ *= 2; | 742 old_gen_limit_factor_ = 2; |
| 754 old_gen_allocation_limit_ *= 2; | 743 } else { |
| 744 old_gen_limit_factor_ = 1; |
| 755 } | 745 } |
| 756 | 746 |
| 747 old_gen_promotion_limit_ = |
| 748 OldGenPromotionLimit(size_of_old_gen_at_last_old_space_gc_); |
| 749 old_gen_allocation_limit_ = |
| 750 OldGenAllocationLimit(size_of_old_gen_at_last_old_space_gc_); |
| 751 |
| 757 old_gen_exhausted_ = false; | 752 old_gen_exhausted_ = false; |
| 758 } else { | 753 } else { |
| 759 tracer_ = tracer; | 754 tracer_ = tracer; |
| 760 Scavenge(); | 755 Scavenge(); |
| 761 tracer_ = NULL; | 756 tracer_ = NULL; |
| 762 | 757 |
| 763 UpdateSurvivalRateTrend(start_new_space_size); | 758 UpdateSurvivalRateTrend(start_new_space_size); |
| 764 } | 759 } |
| 765 | 760 |
| 766 isolate_->counters()->objs_since_last_young()->Set(0); | 761 isolate_->counters()->objs_since_last_young()->Set(0); |
| 767 | 762 |
| 768 gc_post_processing_depth_++; | 763 gc_post_processing_depth_++; |
| 769 { DisableAssertNoAllocation allow_allocation; | 764 { DisableAssertNoAllocation allow_allocation; |
| 770 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); | 765 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); |
| 771 next_gc_likely_to_collect_more = | 766 next_gc_likely_to_collect_more = |
| 772 isolate_->global_handles()->PostGarbageCollectionProcessing(collector); | 767 isolate_->global_handles()->PostGarbageCollectionProcessing(collector); |
| 773 } | 768 } |
| 774 gc_post_processing_depth_--; | 769 gc_post_processing_depth_--; |
| 775 | 770 |
| 776 // Update relocatables. | 771 // Update relocatables. |
| 777 Relocatable::PostGarbageCollectionProcessing(); | 772 Relocatable::PostGarbageCollectionProcessing(); |
| 778 | 773 |
| 779 if (collector == MARK_COMPACTOR) { | 774 if (collector == MARK_COMPACTOR) { |
| 780 // Register the amount of external allocated memory. | 775 // Register the amount of external allocated memory. |
| 781 amount_of_external_allocated_memory_at_last_global_gc_ = | 776 amount_of_external_allocated_memory_at_last_global_gc_ = |
| 782 amount_of_external_allocated_memory_; | 777 amount_of_external_allocated_memory_; |
| 783 } | 778 } |
| 784 | 779 |
| 785 GCCallbackFlags callback_flags = tracer->is_compacting() | 780 GCCallbackFlags callback_flags = kNoGCCallbackFlags; |
| 786 ? kGCCallbackFlagCompacted | |
| 787 : kNoGCCallbackFlags; | |
| 788 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) { | 781 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) { |
| 789 if (gc_type & gc_epilogue_callbacks_[i].gc_type) { | 782 if (gc_type & gc_epilogue_callbacks_[i].gc_type) { |
| 790 gc_epilogue_callbacks_[i].callback(gc_type, callback_flags); | 783 gc_epilogue_callbacks_[i].callback(gc_type, callback_flags); |
| 791 } | 784 } |
| 792 } | 785 } |
| 793 | 786 |
| 794 if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) { | 787 if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) { |
| 795 ASSERT(!allocation_allowed_); | 788 ASSERT(!allocation_allowed_); |
| 796 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); | 789 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); |
| 797 global_gc_epilogue_callback_(); | 790 global_gc_epilogue_callback_(); |
| 798 } | 791 } |
| 799 VerifySymbolTable(); | 792 VerifySymbolTable(); |
| 800 | 793 |
| 801 return next_gc_likely_to_collect_more; | 794 return next_gc_likely_to_collect_more; |
| 802 } | 795 } |
| 803 | 796 |
| 804 | 797 |
| 805 void Heap::MarkCompact(GCTracer* tracer) { | 798 void Heap::MarkCompact(GCTracer* tracer) { |
| 806 gc_state_ = MARK_COMPACT; | 799 gc_state_ = MARK_COMPACT; |
| 807 LOG(isolate_, ResourceEvent("markcompact", "begin")); | 800 LOG(isolate_, ResourceEvent("markcompact", "begin")); |
| 808 | 801 |
| 809 mark_compact_collector_.Prepare(tracer); | 802 mark_compact_collector_.Prepare(tracer); |
| 810 | 803 |
| 811 bool is_compacting = mark_compact_collector_.IsCompacting(); | 804 ms_count_++; |
| 805 tracer->set_full_gc_count(ms_count_); |
| 812 | 806 |
| 813 if (is_compacting) { | 807 MarkCompactPrologue(); |
| 814 mc_count_++; | |
| 815 } else { | |
| 816 ms_count_++; | |
| 817 } | |
| 818 tracer->set_full_gc_count(mc_count_ + ms_count_); | |
| 819 | 808 |
| 820 MarkCompactPrologue(is_compacting); | |
| 821 | |
| 822 is_safe_to_read_maps_ = false; | |
| 823 mark_compact_collector_.CollectGarbage(); | 809 mark_compact_collector_.CollectGarbage(); |
| 824 is_safe_to_read_maps_ = true; | |
| 825 | 810 |
| 826 LOG(isolate_, ResourceEvent("markcompact", "end")); | 811 LOG(isolate_, ResourceEvent("markcompact", "end")); |
| 827 | 812 |
| 828 gc_state_ = NOT_IN_GC; | 813 gc_state_ = NOT_IN_GC; |
| 829 | 814 |
| 830 Shrink(); | |
| 831 | |
| 832 isolate_->counters()->objs_since_last_full()->Set(0); | 815 isolate_->counters()->objs_since_last_full()->Set(0); |
| 833 | 816 |
| 834 contexts_disposed_ = 0; | 817 contexts_disposed_ = 0; |
| 835 } | 818 } |
| 836 | 819 |
| 837 | 820 |
| 838 void Heap::MarkCompactPrologue(bool is_compacting) { | 821 void Heap::MarkCompactPrologue() { |
| 839 // At any old GC clear the keyed lookup cache to enable collection of unused | 822 // At any old GC clear the keyed lookup cache to enable collection of unused |
| 840 // maps. | 823 // maps. |
| 841 isolate_->keyed_lookup_cache()->Clear(); | 824 isolate_->keyed_lookup_cache()->Clear(); |
| 842 isolate_->context_slot_cache()->Clear(); | 825 isolate_->context_slot_cache()->Clear(); |
| 843 isolate_->descriptor_lookup_cache()->Clear(); | 826 isolate_->descriptor_lookup_cache()->Clear(); |
| 844 StringSplitCache::Clear(string_split_cache()); | 827 StringSplitCache::Clear(string_split_cache()); |
| 845 | 828 |
| 846 isolate_->compilation_cache()->MarkCompactPrologue(); | 829 isolate_->compilation_cache()->MarkCompactPrologue(); |
| 847 | 830 |
| 848 CompletelyClearInstanceofCache(); | 831 CompletelyClearInstanceofCache(); |
| 849 | 832 |
| 850 if (is_compacting) FlushNumberStringCache(); | 833 // TODO(1605) select heuristic for flushing NumberString cache with |
| 834 // FlushNumberStringCache |
| 851 if (FLAG_cleanup_code_caches_at_gc) { | 835 if (FLAG_cleanup_code_caches_at_gc) { |
| 852 polymorphic_code_cache()->set_cache(undefined_value()); | 836 polymorphic_code_cache()->set_cache(undefined_value()); |
| 853 } | 837 } |
| 854 | 838 |
| 855 ClearNormalizedMapCaches(); | 839 ClearNormalizedMapCaches(); |
| 856 } | 840 } |
| 857 | 841 |
| 858 | 842 |
| 859 Object* Heap::FindCodeObject(Address a) { | 843 Object* Heap::FindCodeObject(Address a) { |
| 860 Object* obj = NULL; // Initialization to please compiler. | 844 return isolate()->inner_pointer_to_code_cache()-> |
| 861 { MaybeObject* maybe_obj = code_space_->FindObject(a); | 845 GcSafeFindCodeForInnerPointer(a); |
| 862 if (!maybe_obj->ToObject(&obj)) { | |
| 863 obj = lo_space_->FindObject(a)->ToObjectUnchecked(); | |
| 864 } | |
| 865 } | |
| 866 return obj; | |
| 867 } | 846 } |
| 868 | 847 |
| 869 | 848 |
| 870 // Helper class for copying HeapObjects | 849 // Helper class for copying HeapObjects |
| 871 class ScavengeVisitor: public ObjectVisitor { | 850 class ScavengeVisitor: public ObjectVisitor { |
| 872 public: | 851 public: |
| 873 explicit ScavengeVisitor(Heap* heap) : heap_(heap) {} | 852 explicit ScavengeVisitor(Heap* heap) : heap_(heap) {} |
| 874 | 853 |
| 875 void VisitPointer(Object** p) { ScavengePointer(p); } | 854 void VisitPointer(Object** p) { ScavengePointer(p); } |
| 876 | 855 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 904 } | 883 } |
| 905 } | 884 } |
| 906 }; | 885 }; |
| 907 | 886 |
| 908 | 887 |
| 909 static void VerifyNonPointerSpacePointers() { | 888 static void VerifyNonPointerSpacePointers() { |
| 910 // Verify that there are no pointers to new space in spaces where we | 889 // Verify that there are no pointers to new space in spaces where we |
| 911 // do not expect them. | 890 // do not expect them. |
| 912 VerifyNonPointerSpacePointersVisitor v; | 891 VerifyNonPointerSpacePointersVisitor v; |
| 913 HeapObjectIterator code_it(HEAP->code_space()); | 892 HeapObjectIterator code_it(HEAP->code_space()); |
| 914 for (HeapObject* object = code_it.next(); | 893 for (HeapObject* object = code_it.Next(); |
| 915 object != NULL; object = code_it.next()) | 894 object != NULL; object = code_it.Next()) |
| 916 object->Iterate(&v); | 895 object->Iterate(&v); |
| 917 | 896 |
| 918 HeapObjectIterator data_it(HEAP->old_data_space()); | 897 // The old data space was normally swept conservatively so that the iterator |
| 919 for (HeapObject* object = data_it.next(); | 898 // doesn't work, so we normally skip the next bit. |
| 920 object != NULL; object = data_it.next()) | 899 if (!HEAP->old_data_space()->was_swept_conservatively()) { |
| 921 object->Iterate(&v); | 900 HeapObjectIterator data_it(HEAP->old_data_space()); |
| 901 for (HeapObject* object = data_it.Next(); |
| 902 object != NULL; object = data_it.Next()) |
| 903 object->Iterate(&v); |
| 904 } |
| 922 } | 905 } |
| 923 #endif | 906 #endif |
| 924 | 907 |
| 925 | 908 |
| 926 void Heap::CheckNewSpaceExpansionCriteria() { | 909 void Heap::CheckNewSpaceExpansionCriteria() { |
| 927 if (new_space_.Capacity() < new_space_.MaximumCapacity() && | 910 if (new_space_.Capacity() < new_space_.MaximumCapacity() && |
| 928 survived_since_last_expansion_ > new_space_.Capacity()) { | 911 survived_since_last_expansion_ > new_space_.Capacity()) { |
| 929 // Grow the size of new space if there is room to grow and enough | 912 // Grow the size of new space if there is room to grow and enough |
| 930 // data has survived scavenge since the last expansion. | 913 // data has survived scavenge since the last expansion. |
| 931 new_space_.Grow(); | 914 new_space_.Grow(); |
| 932 survived_since_last_expansion_ = 0; | 915 survived_since_last_expansion_ = 0; |
| 933 } | 916 } |
| 934 } | 917 } |
| 935 | 918 |
| 936 | 919 |
| 937 static bool IsUnscavengedHeapObject(Heap* heap, Object** p) { | 920 static bool IsUnscavengedHeapObject(Heap* heap, Object** p) { |
| 938 return heap->InNewSpace(*p) && | 921 return heap->InNewSpace(*p) && |
| 939 !HeapObject::cast(*p)->map_word().IsForwardingAddress(); | 922 !HeapObject::cast(*p)->map_word().IsForwardingAddress(); |
| 940 } | 923 } |
| 941 | 924 |
| 942 | 925 |
| 926 void Heap::ScavengeStoreBufferCallback( |
| 927 Heap* heap, |
| 928 MemoryChunk* page, |
| 929 StoreBufferEvent event) { |
| 930 heap->store_buffer_rebuilder_.Callback(page, event); |
| 931 } |
| 932 |
| 933 |
| 934 void StoreBufferRebuilder::Callback(MemoryChunk* page, StoreBufferEvent event) { |
| 935 if (event == kStoreBufferStartScanningPagesEvent) { |
| 936 start_of_current_page_ = NULL; |
| 937 current_page_ = NULL; |
| 938 } else if (event == kStoreBufferScanningPageEvent) { |
| 939 if (current_page_ != NULL) { |
| 940 // If this page already overflowed the store buffer during this iteration. |
| 941 if (current_page_->scan_on_scavenge()) { |
| 942 // Then we should wipe out the entries that have been added for it. |
| 943 store_buffer_->SetTop(start_of_current_page_); |
| 944 } else if (store_buffer_->Top() - start_of_current_page_ >= |
| 945 (store_buffer_->Limit() - store_buffer_->Top()) >> 2) { |
| 946 // Did we find too many pointers in the previous page? The heuristic is |
| 947 // that no page can take more then 1/5 the remaining slots in the store |
| 948 // buffer. |
| 949 current_page_->set_scan_on_scavenge(true); |
| 950 store_buffer_->SetTop(start_of_current_page_); |
| 951 } else { |
| 952 // In this case the page we scanned took a reasonable number of slots in |
| 953 // the store buffer. It has now been rehabilitated and is no longer |
| 954 // marked scan_on_scavenge. |
| 955 ASSERT(!current_page_->scan_on_scavenge()); |
| 956 } |
| 957 } |
| 958 start_of_current_page_ = store_buffer_->Top(); |
| 959 current_page_ = page; |
| 960 } else if (event == kStoreBufferFullEvent) { |
| 961 // The current page overflowed the store buffer again. Wipe out its entries |
| 962 // in the store buffer and mark it scan-on-scavenge again. This may happen |
| 963 // several times while scanning. |
| 964 if (current_page_ == NULL) { |
| 965 // Store Buffer overflowed while scanning promoted objects. These are not |
| 966 // in any particular page, though they are likely to be clustered by the |
| 967 // allocation routines. |
| 968 store_buffer_->HandleFullness(); |
| 969 } else { |
| 970 // Store Buffer overflowed while scanning a particular old space page for |
| 971 // pointers to new space. |
| 972 ASSERT(current_page_ == page); |
| 973 ASSERT(page != NULL); |
| 974 current_page_->set_scan_on_scavenge(true); |
| 975 ASSERT(start_of_current_page_ != store_buffer_->Top()); |
| 976 store_buffer_->SetTop(start_of_current_page_); |
| 977 } |
| 978 } else { |
| 979 UNREACHABLE(); |
| 980 } |
| 981 } |
| 982 |
| 983 |
| 943 void Heap::Scavenge() { | 984 void Heap::Scavenge() { |
| 944 #ifdef DEBUG | 985 #ifdef DEBUG |
| 945 if (FLAG_enable_slow_asserts) VerifyNonPointerSpacePointers(); | 986 if (FLAG_enable_slow_asserts) VerifyNonPointerSpacePointers(); |
| 946 #endif | 987 #endif |
| 947 | 988 |
| 948 gc_state_ = SCAVENGE; | 989 gc_state_ = SCAVENGE; |
| 949 | 990 |
| 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 | 991 // Implements Cheney's copying algorithm |
| 967 LOG(isolate_, ResourceEvent("scavenge", "begin")); | 992 LOG(isolate_, ResourceEvent("scavenge", "begin")); |
| 968 | 993 |
| 969 // Clear descriptor cache. | 994 // Clear descriptor cache. |
| 970 isolate_->descriptor_lookup_cache()->Clear(); | 995 isolate_->descriptor_lookup_cache()->Clear(); |
| 971 | 996 |
| 972 // Used for updating survived_since_last_expansion_ at function end. | 997 // Used for updating survived_since_last_expansion_ at function end. |
| 973 intptr_t survived_watermark = PromotedSpaceSize(); | 998 intptr_t survived_watermark = PromotedSpaceSize(); |
| 974 | 999 |
| 975 CheckNewSpaceExpansionCriteria(); | 1000 CheckNewSpaceExpansionCriteria(); |
| 976 | 1001 |
| 1002 SelectScavengingVisitorsTable(); |
| 1003 |
| 1004 incremental_marking()->PrepareForScavenge(); |
| 1005 |
| 1006 old_pointer_space()->AdvanceSweeper(new_space_.Size()); |
| 1007 old_data_space()->AdvanceSweeper(new_space_.Size()); |
| 1008 |
| 977 // Flip the semispaces. After flipping, to space is empty, from space has | 1009 // Flip the semispaces. After flipping, to space is empty, from space has |
| 978 // live objects. | 1010 // live objects. |
| 979 new_space_.Flip(); | 1011 new_space_.Flip(); |
| 980 new_space_.ResetAllocationInfo(); | 1012 new_space_.ResetAllocationInfo(); |
| 981 | 1013 |
| 982 // We need to sweep newly copied objects which can be either in the | 1014 // 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 | 1015 // 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 | 1016 // 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 | 1017 // copied and unswept objects lie between a 'front' mark and the |
| 986 // allocation pointer. | 1018 // allocation pointer. |
| 987 // | 1019 // |
| 988 // Promoted objects can go into various old-generation spaces, and | 1020 // Promoted objects can go into various old-generation spaces, and |
| 989 // can be allocated internally in the spaces (from the free list). | 1021 // 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 | 1022 // We treat the top of the to space as a queue of addresses of |
| 991 // promoted objects. The addresses of newly promoted and unswept | 1023 // promoted objects. The addresses of newly promoted and unswept |
| 992 // objects lie between a 'front' mark and a 'rear' mark that is | 1024 // objects lie between a 'front' mark and a 'rear' mark that is |
| 993 // updated as a side effect of promoting an object. | 1025 // updated as a side effect of promoting an object. |
| 994 // | 1026 // |
| 995 // There is guaranteed to be enough room at the top of the to space | 1027 // There is guaranteed to be enough room at the top of the to space |
| 996 // for the addresses of promoted objects: every object promoted | 1028 // for the addresses of promoted objects: every object promoted |
| 997 // frees up its size in bytes from the top of the new space, and | 1029 // frees up its size in bytes from the top of the new space, and |
| 998 // objects are at least one pointer in size. | 1030 // objects are at least one pointer in size. |
| 999 Address new_space_front = new_space_.ToSpaceLow(); | 1031 Address new_space_front = new_space_.ToSpaceStart(); |
| 1000 promotion_queue_.Initialize(new_space_.ToSpaceHigh()); | 1032 promotion_queue_.Initialize(new_space_.ToSpaceEnd()); |
| 1001 | 1033 |
| 1002 is_safe_to_read_maps_ = false; | 1034 #ifdef DEBUG |
| 1035 store_buffer()->Clean(); |
| 1036 #endif |
| 1037 |
| 1003 ScavengeVisitor scavenge_visitor(this); | 1038 ScavengeVisitor scavenge_visitor(this); |
| 1004 // Copy roots. | 1039 // Copy roots. |
| 1005 IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE); | 1040 IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE); |
| 1006 | 1041 |
| 1007 // Copy objects reachable from the old generation. By definition, | 1042 // Copy objects reachable from the old generation. |
| 1008 // there are no intergenerational pointers in code or data spaces. | 1043 { |
| 1009 IterateDirtyRegions(old_pointer_space_, | 1044 StoreBufferRebuildScope scope(this, |
| 1010 &Heap::IteratePointersInDirtyRegion, | 1045 store_buffer(), |
| 1011 &ScavengePointer, | 1046 &ScavengeStoreBufferCallback); |
| 1012 WATERMARK_CAN_BE_INVALID); | 1047 store_buffer()->IteratePointersToNewSpace(&ScavengeObject); |
| 1013 | 1048 } |
| 1014 IterateDirtyRegions(map_space_, | |
| 1015 &IteratePointersInDirtyMapsRegion, | |
| 1016 &ScavengePointer, | |
| 1017 WATERMARK_CAN_BE_INVALID); | |
| 1018 | |
| 1019 lo_space_->IterateDirtyRegions(&ScavengePointer); | |
| 1020 | 1049 |
| 1021 // Copy objects reachable from cells by scavenging cell values directly. | 1050 // Copy objects reachable from cells by scavenging cell values directly. |
| 1022 HeapObjectIterator cell_iterator(cell_space_); | 1051 HeapObjectIterator cell_iterator(cell_space_); |
| 1023 for (HeapObject* cell = cell_iterator.next(); | 1052 for (HeapObject* cell = cell_iterator.Next(); |
| 1024 cell != NULL; cell = cell_iterator.next()) { | 1053 cell != NULL; cell = cell_iterator.Next()) { |
| 1025 if (cell->IsJSGlobalPropertyCell()) { | 1054 if (cell->IsJSGlobalPropertyCell()) { |
| 1026 Address value_address = | 1055 Address value_address = |
| 1027 reinterpret_cast<Address>(cell) + | 1056 reinterpret_cast<Address>(cell) + |
| 1028 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag); | 1057 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag); |
| 1029 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address)); | 1058 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address)); |
| 1030 } | 1059 } |
| 1031 } | 1060 } |
| 1032 | 1061 |
| 1033 // Scavenge object reachable from the global contexts list directly. | 1062 // Scavenge object reachable from the global contexts list directly. |
| 1034 scavenge_visitor.VisitPointer(BitCast<Object**>(&global_contexts_list_)); | 1063 scavenge_visitor.VisitPointer(BitCast<Object**>(&global_contexts_list_)); |
| 1035 | 1064 |
| 1036 new_space_front = DoScavenge(&scavenge_visitor, new_space_front); | 1065 new_space_front = DoScavenge(&scavenge_visitor, new_space_front); |
| 1037 isolate_->global_handles()->IdentifyNewSpaceWeakIndependentHandles( | 1066 isolate_->global_handles()->IdentifyNewSpaceWeakIndependentHandles( |
| 1038 &IsUnscavengedHeapObject); | 1067 &IsUnscavengedHeapObject); |
| 1039 isolate_->global_handles()->IterateNewSpaceWeakIndependentRoots( | 1068 isolate_->global_handles()->IterateNewSpaceWeakIndependentRoots( |
| 1040 &scavenge_visitor); | 1069 &scavenge_visitor); |
| 1041 new_space_front = DoScavenge(&scavenge_visitor, new_space_front); | 1070 new_space_front = DoScavenge(&scavenge_visitor, new_space_front); |
| 1042 | 1071 |
| 1043 | 1072 |
| 1044 UpdateNewSpaceReferencesInExternalStringTable( | 1073 UpdateNewSpaceReferencesInExternalStringTable( |
| 1045 &UpdateNewSpaceReferenceInExternalStringTableEntry); | 1074 &UpdateNewSpaceReferenceInExternalStringTableEntry); |
| 1046 | 1075 |
| 1047 LiveObjectList::UpdateReferencesForScavengeGC(); | 1076 LiveObjectList::UpdateReferencesForScavengeGC(); |
| 1048 isolate()->runtime_profiler()->UpdateSamplesAfterScavenge(); | 1077 isolate()->runtime_profiler()->UpdateSamplesAfterScavenge(); |
| 1078 incremental_marking()->UpdateMarkingDequeAfterScavenge(); |
| 1049 | 1079 |
| 1050 ASSERT(new_space_front == new_space_.top()); | 1080 ASSERT(new_space_front == new_space_.top()); |
| 1051 | 1081 |
| 1052 is_safe_to_read_maps_ = true; | |
| 1053 | |
| 1054 // Set age mark. | 1082 // Set age mark. |
| 1055 new_space_.set_age_mark(new_space_.top()); | 1083 new_space_.set_age_mark(new_space_.top()); |
| 1056 | 1084 |
| 1085 new_space_.LowerInlineAllocationLimit( |
| 1086 new_space_.inline_allocation_limit_step()); |
| 1087 |
| 1057 // Update how much has survived scavenge. | 1088 // Update how much has survived scavenge. |
| 1058 IncrementYoungSurvivorsCounter(static_cast<int>( | 1089 IncrementYoungSurvivorsCounter(static_cast<int>( |
| 1059 (PromotedSpaceSize() - survived_watermark) + new_space_.Size())); | 1090 (PromotedSpaceSize() - survived_watermark) + new_space_.Size())); |
| 1060 | 1091 |
| 1061 LOG(isolate_, ResourceEvent("scavenge", "end")); | 1092 LOG(isolate_, ResourceEvent("scavenge", "end")); |
| 1062 | 1093 |
| 1063 gc_state_ = NOT_IN_GC; | 1094 gc_state_ = NOT_IN_GC; |
| 1064 } | 1095 } |
| 1065 | 1096 |
| 1066 | 1097 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1105 // String got promoted. Move it to the old string list. | 1136 // String got promoted. Move it to the old string list. |
| 1106 external_string_table_.AddOldString(target); | 1137 external_string_table_.AddOldString(target); |
| 1107 } | 1138 } |
| 1108 } | 1139 } |
| 1109 | 1140 |
| 1110 ASSERT(last <= end); | 1141 ASSERT(last <= end); |
| 1111 external_string_table_.ShrinkNewStrings(static_cast<int>(last - start)); | 1142 external_string_table_.ShrinkNewStrings(static_cast<int>(last - start)); |
| 1112 } | 1143 } |
| 1113 | 1144 |
| 1114 | 1145 |
| 1146 void Heap::UpdateReferencesInExternalStringTable( |
| 1147 ExternalStringTableUpdaterCallback updater_func) { |
| 1148 |
| 1149 // Update old space string references. |
| 1150 if (external_string_table_.old_space_strings_.length() > 0) { |
| 1151 Object** start = &external_string_table_.old_space_strings_[0]; |
| 1152 Object** end = start + external_string_table_.old_space_strings_.length(); |
| 1153 for (Object** p = start; p < end; ++p) *p = updater_func(this, p); |
| 1154 } |
| 1155 |
| 1156 UpdateNewSpaceReferencesInExternalStringTable(updater_func); |
| 1157 } |
| 1158 |
| 1159 |
| 1115 static Object* ProcessFunctionWeakReferences(Heap* heap, | 1160 static Object* ProcessFunctionWeakReferences(Heap* heap, |
| 1116 Object* function, | 1161 Object* function, |
| 1117 WeakObjectRetainer* retainer) { | 1162 WeakObjectRetainer* retainer) { |
| 1118 Object* head = heap->undefined_value(); | 1163 Object* undefined = heap->undefined_value(); |
| 1164 Object* head = undefined; |
| 1119 JSFunction* tail = NULL; | 1165 JSFunction* tail = NULL; |
| 1120 Object* candidate = function; | 1166 Object* candidate = function; |
| 1121 while (candidate != heap->undefined_value()) { | 1167 while (candidate != undefined) { |
| 1122 // Check whether to keep the candidate in the list. | 1168 // Check whether to keep the candidate in the list. |
| 1123 JSFunction* candidate_function = reinterpret_cast<JSFunction*>(candidate); | 1169 JSFunction* candidate_function = reinterpret_cast<JSFunction*>(candidate); |
| 1124 Object* retain = retainer->RetainAs(candidate); | 1170 Object* retain = retainer->RetainAs(candidate); |
| 1125 if (retain != NULL) { | 1171 if (retain != NULL) { |
| 1126 if (head == heap->undefined_value()) { | 1172 if (head == undefined) { |
| 1127 // First element in the list. | 1173 // First element in the list. |
| 1128 head = candidate_function; | 1174 head = retain; |
| 1129 } else { | 1175 } else { |
| 1130 // Subsequent elements in the list. | 1176 // Subsequent elements in the list. |
| 1131 ASSERT(tail != NULL); | 1177 ASSERT(tail != NULL); |
| 1132 tail->set_next_function_link(candidate_function); | 1178 tail->set_next_function_link(retain); |
| 1133 } | 1179 } |
| 1134 // Retained function is new tail. | 1180 // Retained function is new tail. |
| 1181 candidate_function = reinterpret_cast<JSFunction*>(retain); |
| 1135 tail = candidate_function; | 1182 tail = candidate_function; |
| 1183 |
| 1184 ASSERT(retain->IsUndefined() || retain->IsJSFunction()); |
| 1185 |
| 1186 if (retain == undefined) break; |
| 1136 } | 1187 } |
| 1188 |
| 1137 // Move to next element in the list. | 1189 // Move to next element in the list. |
| 1138 candidate = candidate_function->next_function_link(); | 1190 candidate = candidate_function->next_function_link(); |
| 1139 } | 1191 } |
| 1140 | 1192 |
| 1141 // Terminate the list if there is one or more elements. | 1193 // Terminate the list if there is one or more elements. |
| 1142 if (tail != NULL) { | 1194 if (tail != NULL) { |
| 1143 tail->set_next_function_link(heap->undefined_value()); | 1195 tail->set_next_function_link(undefined); |
| 1144 } | 1196 } |
| 1145 | 1197 |
| 1146 return head; | 1198 return head; |
| 1147 } | 1199 } |
| 1148 | 1200 |
| 1149 | 1201 |
| 1150 void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) { | 1202 void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) { |
| 1151 Object* head = undefined_value(); | 1203 Object* undefined = undefined_value(); |
| 1204 Object* head = undefined; |
| 1152 Context* tail = NULL; | 1205 Context* tail = NULL; |
| 1153 Object* candidate = global_contexts_list_; | 1206 Object* candidate = global_contexts_list_; |
| 1154 while (candidate != undefined_value()) { | 1207 while (candidate != undefined) { |
| 1155 // Check whether to keep the candidate in the list. | 1208 // Check whether to keep the candidate in the list. |
| 1156 Context* candidate_context = reinterpret_cast<Context*>(candidate); | 1209 Context* candidate_context = reinterpret_cast<Context*>(candidate); |
| 1157 Object* retain = retainer->RetainAs(candidate); | 1210 Object* retain = retainer->RetainAs(candidate); |
| 1158 if (retain != NULL) { | 1211 if (retain != NULL) { |
| 1159 if (head == undefined_value()) { | 1212 if (head == undefined) { |
| 1160 // First element in the list. | 1213 // First element in the list. |
| 1161 head = candidate_context; | 1214 head = retain; |
| 1162 } else { | 1215 } else { |
| 1163 // Subsequent elements in the list. | 1216 // Subsequent elements in the list. |
| 1164 ASSERT(tail != NULL); | 1217 ASSERT(tail != NULL); |
| 1165 tail->set_unchecked(this, | 1218 tail->set_unchecked(this, |
| 1166 Context::NEXT_CONTEXT_LINK, | 1219 Context::NEXT_CONTEXT_LINK, |
| 1167 candidate_context, | 1220 retain, |
| 1168 UPDATE_WRITE_BARRIER); | 1221 UPDATE_WRITE_BARRIER); |
| 1169 } | 1222 } |
| 1170 // Retained context is new tail. | 1223 // Retained context is new tail. |
| 1224 candidate_context = reinterpret_cast<Context*>(retain); |
| 1171 tail = candidate_context; | 1225 tail = candidate_context; |
| 1172 | 1226 |
| 1227 if (retain == undefined) break; |
| 1228 |
| 1173 // Process the weak list of optimized functions for the context. | 1229 // Process the weak list of optimized functions for the context. |
| 1174 Object* function_list_head = | 1230 Object* function_list_head = |
| 1175 ProcessFunctionWeakReferences( | 1231 ProcessFunctionWeakReferences( |
| 1176 this, | 1232 this, |
| 1177 candidate_context->get(Context::OPTIMIZED_FUNCTIONS_LIST), | 1233 candidate_context->get(Context::OPTIMIZED_FUNCTIONS_LIST), |
| 1178 retainer); | 1234 retainer); |
| 1179 candidate_context->set_unchecked(this, | 1235 candidate_context->set_unchecked(this, |
| 1180 Context::OPTIMIZED_FUNCTIONS_LIST, | 1236 Context::OPTIMIZED_FUNCTIONS_LIST, |
| 1181 function_list_head, | 1237 function_list_head, |
| 1182 UPDATE_WRITE_BARRIER); | 1238 UPDATE_WRITE_BARRIER); |
| 1183 } | 1239 } |
| 1240 |
| 1184 // Move to next element in the list. | 1241 // Move to next element in the list. |
| 1185 candidate = candidate_context->get(Context::NEXT_CONTEXT_LINK); | 1242 candidate = candidate_context->get(Context::NEXT_CONTEXT_LINK); |
| 1186 } | 1243 } |
| 1187 | 1244 |
| 1188 // Terminate the list if there is one or more elements. | 1245 // Terminate the list if there is one or more elements. |
| 1189 if (tail != NULL) { | 1246 if (tail != NULL) { |
| 1190 tail->set_unchecked(this, | 1247 tail->set_unchecked(this, |
| 1191 Context::NEXT_CONTEXT_LINK, | 1248 Context::NEXT_CONTEXT_LINK, |
| 1192 Heap::undefined_value(), | 1249 Heap::undefined_value(), |
| 1193 UPDATE_WRITE_BARRIER); | 1250 UPDATE_WRITE_BARRIER); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1205 if (!heap->InNewSpace(object)) return; | 1262 if (!heap->InNewSpace(object)) return; |
| 1206 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p), | 1263 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p), |
| 1207 reinterpret_cast<HeapObject*>(object)); | 1264 reinterpret_cast<HeapObject*>(object)); |
| 1208 } | 1265 } |
| 1209 }; | 1266 }; |
| 1210 | 1267 |
| 1211 | 1268 |
| 1212 Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor, | 1269 Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor, |
| 1213 Address new_space_front) { | 1270 Address new_space_front) { |
| 1214 do { | 1271 do { |
| 1215 ASSERT(new_space_front <= new_space_.top()); | 1272 SemiSpace::AssertValidRange(new_space_front, new_space_.top()); |
| 1216 | |
| 1217 // The addresses new_space_front and new_space_.top() define a | 1273 // The addresses new_space_front and new_space_.top() define a |
| 1218 // queue of unprocessed copied objects. Process them until the | 1274 // queue of unprocessed copied objects. Process them until the |
| 1219 // queue is empty. | 1275 // queue is empty. |
| 1220 while (new_space_front < new_space_.top()) { | 1276 while (new_space_front != new_space_.top()) { |
| 1221 HeapObject* object = HeapObject::FromAddress(new_space_front); | 1277 if (!NewSpacePage::IsAtEnd(new_space_front)) { |
| 1222 new_space_front += NewSpaceScavenger::IterateBody(object->map(), object); | 1278 HeapObject* object = HeapObject::FromAddress(new_space_front); |
| 1279 new_space_front += |
| 1280 NewSpaceScavenger::IterateBody(object->map(), object); |
| 1281 } else { |
| 1282 new_space_front = |
| 1283 NewSpacePage::FromLimit(new_space_front)->next_page()->body(); |
| 1284 } |
| 1223 } | 1285 } |
| 1224 | 1286 |
| 1225 // Promote and process all the to-be-promoted objects. | 1287 // Promote and process all the to-be-promoted objects. |
| 1226 while (!promotion_queue_.is_empty()) { | 1288 { |
| 1227 HeapObject* target; | 1289 StoreBufferRebuildScope scope(this, |
| 1228 int size; | 1290 store_buffer(), |
| 1229 promotion_queue_.remove(&target, &size); | 1291 &ScavengeStoreBufferCallback); |
| 1292 while (!promotion_queue()->is_empty()) { |
| 1293 HeapObject* target; |
| 1294 int size; |
| 1295 promotion_queue()->remove(&target, &size); |
| 1230 | 1296 |
| 1231 // Promoted object might be already partially visited | 1297 // Promoted object might be already partially visited |
| 1232 // during dirty regions iteration. Thus we search specificly | 1298 // during old space pointer iteration. Thus we search specificly |
| 1233 // for pointers to from semispace instead of looking for pointers | 1299 // for pointers to from semispace instead of looking for pointers |
| 1234 // to new space. | 1300 // to new space. |
| 1235 ASSERT(!target->IsMap()); | 1301 ASSERT(!target->IsMap()); |
| 1236 IterateAndMarkPointersToFromSpace(target->address(), | 1302 IterateAndMarkPointersToFromSpace(target->address(), |
| 1237 target->address() + size, | 1303 target->address() + size, |
| 1238 &ScavengePointer); | 1304 &ScavengeObject); |
| 1305 } |
| 1239 } | 1306 } |
| 1240 | 1307 |
| 1241 // Take another spin if there are now unswept objects in new space | 1308 // Take another spin if there are now unswept objects in new space |
| 1242 // (there are currently no more unswept promoted objects). | 1309 // (there are currently no more unswept promoted objects). |
| 1243 } while (new_space_front < new_space_.top()); | 1310 } while (new_space_front != new_space_.top()); |
| 1244 | 1311 |
| 1245 return new_space_front; | 1312 return new_space_front; |
| 1246 } | 1313 } |
| 1247 | 1314 |
| 1248 | 1315 |
| 1249 enum LoggingAndProfiling { | 1316 enum LoggingAndProfiling { |
| 1250 LOGGING_AND_PROFILING_ENABLED, | 1317 LOGGING_AND_PROFILING_ENABLED, |
| 1251 LOGGING_AND_PROFILING_DISABLED | 1318 LOGGING_AND_PROFILING_DISABLED |
| 1252 }; | 1319 }; |
| 1253 | 1320 |
| 1254 | 1321 |
| 1255 typedef void (*ScavengingCallback)(Map* map, | 1322 enum MarksHandling { TRANSFER_MARKS, IGNORE_MARKS }; |
| 1256 HeapObject** slot, | |
| 1257 HeapObject* object); | |
| 1258 | 1323 |
| 1259 | 1324 |
| 1260 static Atomic32 scavenging_visitors_table_mode_; | 1325 template<MarksHandling marks_handling, |
| 1261 static VisitorDispatchTable<ScavengingCallback> scavenging_visitors_table_; | 1326 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 { | 1327 class ScavengingVisitor : public StaticVisitorBase { |
| 1276 public: | 1328 public: |
| 1277 static void Initialize() { | 1329 static void Initialize() { |
| 1278 table_.Register(kVisitSeqAsciiString, &EvacuateSeqAsciiString); | 1330 table_.Register(kVisitSeqAsciiString, &EvacuateSeqAsciiString); |
| 1279 table_.Register(kVisitSeqTwoByteString, &EvacuateSeqTwoByteString); | 1331 table_.Register(kVisitSeqTwoByteString, &EvacuateSeqTwoByteString); |
| 1280 table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate); | 1332 table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate); |
| 1281 table_.Register(kVisitByteArray, &EvacuateByteArray); | 1333 table_.Register(kVisitByteArray, &EvacuateByteArray); |
| 1282 table_.Register(kVisitFixedArray, &EvacuateFixedArray); | 1334 table_.Register(kVisitFixedArray, &EvacuateFixedArray); |
| 1283 table_.Register(kVisitFixedDoubleArray, &EvacuateFixedDoubleArray); | 1335 table_.Register(kVisitFixedDoubleArray, &EvacuateFixedDoubleArray); |
| 1284 | 1336 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1299 template VisitSpecialized<SharedFunctionInfo::kSize>); | 1351 template VisitSpecialized<SharedFunctionInfo::kSize>); |
| 1300 | 1352 |
| 1301 table_.Register(kVisitJSWeakMap, | 1353 table_.Register(kVisitJSWeakMap, |
| 1302 &ObjectEvacuationStrategy<POINTER_OBJECT>:: | 1354 &ObjectEvacuationStrategy<POINTER_OBJECT>:: |
| 1303 Visit); | 1355 Visit); |
| 1304 | 1356 |
| 1305 table_.Register(kVisitJSRegExp, | 1357 table_.Register(kVisitJSRegExp, |
| 1306 &ObjectEvacuationStrategy<POINTER_OBJECT>:: | 1358 &ObjectEvacuationStrategy<POINTER_OBJECT>:: |
| 1307 Visit); | 1359 Visit); |
| 1308 | 1360 |
| 1309 table_.Register(kVisitJSFunction, | 1361 if (marks_handling == IGNORE_MARKS) { |
| 1310 &ObjectEvacuationStrategy<POINTER_OBJECT>:: | 1362 table_.Register(kVisitJSFunction, |
| 1311 template VisitSpecialized<JSFunction::kSize>); | 1363 &ObjectEvacuationStrategy<POINTER_OBJECT>:: |
| 1364 template VisitSpecialized<JSFunction::kSize>); |
| 1365 } else { |
| 1366 table_.Register(kVisitJSFunction, &EvacuateJSFunction); |
| 1367 } |
| 1312 | 1368 |
| 1313 table_.RegisterSpecializations<ObjectEvacuationStrategy<DATA_OBJECT>, | 1369 table_.RegisterSpecializations<ObjectEvacuationStrategy<DATA_OBJECT>, |
| 1314 kVisitDataObject, | 1370 kVisitDataObject, |
| 1315 kVisitDataObjectGeneric>(); | 1371 kVisitDataObjectGeneric>(); |
| 1316 | 1372 |
| 1317 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>, | 1373 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>, |
| 1318 kVisitJSObject, | 1374 kVisitJSObject, |
| 1319 kVisitJSObjectGeneric>(); | 1375 kVisitJSObjectGeneric>(); |
| 1320 | 1376 |
| 1321 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>, | 1377 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>, |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1366 Isolate* isolate = heap->isolate(); | 1422 Isolate* isolate = heap->isolate(); |
| 1367 if (isolate->logger()->is_logging() || | 1423 if (isolate->logger()->is_logging() || |
| 1368 CpuProfiler::is_profiling(isolate)) { | 1424 CpuProfiler::is_profiling(isolate)) { |
| 1369 if (target->IsSharedFunctionInfo()) { | 1425 if (target->IsSharedFunctionInfo()) { |
| 1370 PROFILE(isolate, SharedFunctionInfoMoveEvent( | 1426 PROFILE(isolate, SharedFunctionInfoMoveEvent( |
| 1371 source->address(), target->address())); | 1427 source->address(), target->address())); |
| 1372 } | 1428 } |
| 1373 } | 1429 } |
| 1374 } | 1430 } |
| 1375 | 1431 |
| 1432 if (marks_handling == TRANSFER_MARKS) { |
| 1433 if (Marking::TransferColor(source, target)) { |
| 1434 MemoryChunk::IncrementLiveBytes(target->address(), size); |
| 1435 } |
| 1436 } |
| 1437 |
| 1376 return target; | 1438 return target; |
| 1377 } | 1439 } |
| 1378 | 1440 |
| 1379 | |
| 1380 template<ObjectContents object_contents, SizeRestriction size_restriction> | 1441 template<ObjectContents object_contents, SizeRestriction size_restriction> |
| 1381 static inline void EvacuateObject(Map* map, | 1442 static inline void EvacuateObject(Map* map, |
| 1382 HeapObject** slot, | 1443 HeapObject** slot, |
| 1383 HeapObject* object, | 1444 HeapObject* object, |
| 1384 int object_size) { | 1445 int object_size) { |
| 1385 ASSERT((size_restriction != SMALL) || | 1446 ASSERT((size_restriction != SMALL) || |
| 1386 (object_size <= Page::kMaxHeapObjectSize)); | 1447 (object_size <= Page::kMaxHeapObjectSize)); |
| 1387 ASSERT(object->Size() == object_size); | 1448 ASSERT(object->Size() == object_size); |
| 1388 | 1449 |
| 1389 Heap* heap = map->heap(); | 1450 Heap* heap = map->GetHeap(); |
| 1390 if (heap->ShouldBePromoted(object->address(), object_size)) { | 1451 if (heap->ShouldBePromoted(object->address(), object_size)) { |
| 1391 MaybeObject* maybe_result; | 1452 MaybeObject* maybe_result; |
| 1392 | 1453 |
| 1393 if ((size_restriction != SMALL) && | 1454 if ((size_restriction != SMALL) && |
| 1394 (object_size > Page::kMaxHeapObjectSize)) { | 1455 (object_size > Page::kMaxHeapObjectSize)) { |
| 1395 maybe_result = heap->lo_space()->AllocateRawFixedArray(object_size); | 1456 maybe_result = heap->lo_space()->AllocateRaw(object_size, |
| 1457 NOT_EXECUTABLE); |
| 1396 } else { | 1458 } else { |
| 1397 if (object_contents == DATA_OBJECT) { | 1459 if (object_contents == DATA_OBJECT) { |
| 1398 maybe_result = heap->old_data_space()->AllocateRaw(object_size); | 1460 maybe_result = heap->old_data_space()->AllocateRaw(object_size); |
| 1399 } else { | 1461 } else { |
| 1400 maybe_result = heap->old_pointer_space()->AllocateRaw(object_size); | 1462 maybe_result = heap->old_pointer_space()->AllocateRaw(object_size); |
| 1401 } | 1463 } |
| 1402 } | 1464 } |
| 1403 | 1465 |
| 1404 Object* result = NULL; // Initialization to please compiler. | 1466 Object* result = NULL; // Initialization to please compiler. |
| 1405 if (maybe_result->ToObject(&result)) { | 1467 if (maybe_result->ToObject(&result)) { |
| 1406 HeapObject* target = HeapObject::cast(result); | 1468 HeapObject* target = HeapObject::cast(result); |
| 1407 *slot = MigrateObject(heap, object , target, object_size); | 1469 *slot = MigrateObject(heap, object , target, object_size); |
| 1408 | 1470 |
| 1409 if (object_contents == POINTER_OBJECT) { | 1471 if (object_contents == POINTER_OBJECT) { |
| 1410 heap->promotion_queue()->insert(target, object_size); | 1472 heap->promotion_queue()->insert(target, object_size); |
| 1411 } | 1473 } |
| 1412 | 1474 |
| 1413 heap->tracer()->increment_promoted_objects_size(object_size); | 1475 heap->tracer()->increment_promoted_objects_size(object_size); |
| 1414 return; | 1476 return; |
| 1415 } | 1477 } |
| 1416 } | 1478 } |
| 1417 Object* result = | 1479 MaybeObject* allocation = heap->new_space()->AllocateRaw(object_size); |
| 1418 heap->new_space()->AllocateRaw(object_size)->ToObjectUnchecked(); | 1480 Object* result = allocation->ToObjectUnchecked(); |
| 1481 |
| 1419 *slot = MigrateObject(heap, object, HeapObject::cast(result), object_size); | 1482 *slot = MigrateObject(heap, object, HeapObject::cast(result), object_size); |
| 1420 return; | 1483 return; |
| 1421 } | 1484 } |
| 1422 | 1485 |
| 1423 | 1486 |
| 1487 static inline void EvacuateJSFunction(Map* map, |
| 1488 HeapObject** slot, |
| 1489 HeapObject* object) { |
| 1490 ObjectEvacuationStrategy<POINTER_OBJECT>:: |
| 1491 template VisitSpecialized<JSFunction::kSize>(map, slot, object); |
| 1492 |
| 1493 HeapObject* target = *slot; |
| 1494 MarkBit mark_bit = Marking::MarkBitFrom(target); |
| 1495 if (Marking::IsBlack(mark_bit)) { |
| 1496 // This object is black and it might not be rescanned by marker. |
| 1497 // We should explicitly record code entry slot for compaction because |
| 1498 // promotion queue processing (IterateAndMarkPointersToFromSpace) will |
| 1499 // miss it as it is not HeapObject-tagged. |
| 1500 Address code_entry_slot = |
| 1501 target->address() + JSFunction::kCodeEntryOffset; |
| 1502 Code* code = Code::cast(Code::GetObjectFromEntryAddress(code_entry_slot)); |
| 1503 map->GetHeap()->mark_compact_collector()-> |
| 1504 RecordCodeEntrySlot(code_entry_slot, code); |
| 1505 } |
| 1506 } |
| 1507 |
| 1508 |
| 1424 static inline void EvacuateFixedArray(Map* map, | 1509 static inline void EvacuateFixedArray(Map* map, |
| 1425 HeapObject** slot, | 1510 HeapObject** slot, |
| 1426 HeapObject* object) { | 1511 HeapObject* object) { |
| 1427 int object_size = FixedArray::BodyDescriptor::SizeOf(map, object); | 1512 int object_size = FixedArray::BodyDescriptor::SizeOf(map, object); |
| 1428 EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE>(map, | 1513 EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE>(map, |
| 1429 slot, | 1514 slot, |
| 1430 object, | 1515 object, |
| 1431 object_size); | 1516 object_size); |
| 1432 } | 1517 } |
| 1433 | 1518 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1472 | 1557 |
| 1473 static inline bool IsShortcutCandidate(int type) { | 1558 static inline bool IsShortcutCandidate(int type) { |
| 1474 return ((type & kShortcutTypeMask) == kShortcutTypeTag); | 1559 return ((type & kShortcutTypeMask) == kShortcutTypeTag); |
| 1475 } | 1560 } |
| 1476 | 1561 |
| 1477 static inline void EvacuateShortcutCandidate(Map* map, | 1562 static inline void EvacuateShortcutCandidate(Map* map, |
| 1478 HeapObject** slot, | 1563 HeapObject** slot, |
| 1479 HeapObject* object) { | 1564 HeapObject* object) { |
| 1480 ASSERT(IsShortcutCandidate(map->instance_type())); | 1565 ASSERT(IsShortcutCandidate(map->instance_type())); |
| 1481 | 1566 |
| 1482 if (ConsString::cast(object)->unchecked_second() == | 1567 Heap* heap = map->GetHeap(); |
| 1483 map->heap()->empty_string()) { | 1568 |
| 1569 if (marks_handling == IGNORE_MARKS && |
| 1570 ConsString::cast(object)->unchecked_second() == |
| 1571 heap->empty_string()) { |
| 1484 HeapObject* first = | 1572 HeapObject* first = |
| 1485 HeapObject::cast(ConsString::cast(object)->unchecked_first()); | 1573 HeapObject::cast(ConsString::cast(object)->unchecked_first()); |
| 1486 | 1574 |
| 1487 *slot = first; | 1575 *slot = first; |
| 1488 | 1576 |
| 1489 if (!map->heap()->InNewSpace(first)) { | 1577 if (!heap->InNewSpace(first)) { |
| 1490 object->set_map_word(MapWord::FromForwardingAddress(first)); | 1578 object->set_map_word(MapWord::FromForwardingAddress(first)); |
| 1491 return; | 1579 return; |
| 1492 } | 1580 } |
| 1493 | 1581 |
| 1494 MapWord first_word = first->map_word(); | 1582 MapWord first_word = first->map_word(); |
| 1495 if (first_word.IsForwardingAddress()) { | 1583 if (first_word.IsForwardingAddress()) { |
| 1496 HeapObject* target = first_word.ToForwardingAddress(); | 1584 HeapObject* target = first_word.ToForwardingAddress(); |
| 1497 | 1585 |
| 1498 *slot = target; | 1586 *slot = target; |
| 1499 object->set_map_word(MapWord::FromForwardingAddress(target)); | 1587 object->set_map_word(MapWord::FromForwardingAddress(target)); |
| 1500 return; | 1588 return; |
| 1501 } | 1589 } |
| 1502 | 1590 |
| 1503 DoScavengeObject(first->map(), slot, first); | 1591 heap->DoScavengeObject(first->map(), slot, first); |
| 1504 object->set_map_word(MapWord::FromForwardingAddress(*slot)); | 1592 object->set_map_word(MapWord::FromForwardingAddress(*slot)); |
| 1505 return; | 1593 return; |
| 1506 } | 1594 } |
| 1507 | 1595 |
| 1508 int object_size = ConsString::kSize; | 1596 int object_size = ConsString::kSize; |
| 1509 EvacuateObject<POINTER_OBJECT, SMALL>(map, slot, object, object_size); | 1597 EvacuateObject<POINTER_OBJECT, SMALL>(map, slot, object, object_size); |
| 1510 } | 1598 } |
| 1511 | 1599 |
| 1512 template<ObjectContents object_contents> | 1600 template<ObjectContents object_contents> |
| 1513 class ObjectEvacuationStrategy { | 1601 class ObjectEvacuationStrategy { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1524 HeapObject* object) { | 1612 HeapObject* object) { |
| 1525 int object_size = map->instance_size(); | 1613 int object_size = map->instance_size(); |
| 1526 EvacuateObject<object_contents, SMALL>(map, slot, object, object_size); | 1614 EvacuateObject<object_contents, SMALL>(map, slot, object, object_size); |
| 1527 } | 1615 } |
| 1528 }; | 1616 }; |
| 1529 | 1617 |
| 1530 static VisitorDispatchTable<ScavengingCallback> table_; | 1618 static VisitorDispatchTable<ScavengingCallback> table_; |
| 1531 }; | 1619 }; |
| 1532 | 1620 |
| 1533 | 1621 |
| 1534 template<LoggingAndProfiling logging_and_profiling_mode> | 1622 template<MarksHandling marks_handling, |
| 1623 LoggingAndProfiling logging_and_profiling_mode> |
| 1535 VisitorDispatchTable<ScavengingCallback> | 1624 VisitorDispatchTable<ScavengingCallback> |
| 1536 ScavengingVisitor<logging_and_profiling_mode>::table_; | 1625 ScavengingVisitor<marks_handling, logging_and_profiling_mode>::table_; |
| 1537 | 1626 |
| 1538 | 1627 |
| 1539 static void InitializeScavengingVisitorsTables() { | 1628 static void InitializeScavengingVisitorsTables() { |
| 1540 ScavengingVisitor<LOGGING_AND_PROFILING_DISABLED>::Initialize(); | 1629 ScavengingVisitor<TRANSFER_MARKS, |
| 1541 ScavengingVisitor<LOGGING_AND_PROFILING_ENABLED>::Initialize(); | 1630 LOGGING_AND_PROFILING_DISABLED>::Initialize(); |
| 1542 scavenging_visitors_table_.CopyFrom( | 1631 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_DISABLED>::Initialize(); |
| 1543 ScavengingVisitor<LOGGING_AND_PROFILING_DISABLED>::GetTable()); | 1632 ScavengingVisitor<TRANSFER_MARKS, |
| 1544 scavenging_visitors_table_mode_ = LOGGING_AND_PROFILING_DISABLED; | 1633 LOGGING_AND_PROFILING_ENABLED>::Initialize(); |
| 1634 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_ENABLED>::Initialize(); |
| 1545 } | 1635 } |
| 1546 | 1636 |
| 1547 | 1637 |
| 1548 void Heap::SwitchScavengingVisitorsTableIfProfilingWasEnabled() { | 1638 void Heap::SelectScavengingVisitorsTable() { |
| 1549 if (scavenging_visitors_table_mode_ == LOGGING_AND_PROFILING_ENABLED) { | 1639 bool logging_and_profiling = |
| 1550 // Table was already updated by some isolate. | 1640 isolate()->logger()->is_logging() || |
| 1551 return; | |
| 1552 } | |
| 1553 | |
| 1554 if (isolate()->logger()->is_logging() | | |
| 1555 CpuProfiler::is_profiling(isolate()) || | 1641 CpuProfiler::is_profiling(isolate()) || |
| 1556 (isolate()->heap_profiler() != NULL && | 1642 (isolate()->heap_profiler() != NULL && |
| 1557 isolate()->heap_profiler()->is_profiling())) { | 1643 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 | 1644 |
| 1569 // We use Release_Store to prevent reordering of this write before writes | 1645 if (!incremental_marking()->IsMarking()) { |
| 1570 // to the table. | 1646 if (!logging_and_profiling) { |
| 1571 Release_Store(&scavenging_visitors_table_mode_, | 1647 scavenging_visitors_table_.CopyFrom( |
| 1572 LOGGING_AND_PROFILING_ENABLED); | 1648 ScavengingVisitor<IGNORE_MARKS, |
| 1649 LOGGING_AND_PROFILING_DISABLED>::GetTable()); |
| 1650 } else { |
| 1651 scavenging_visitors_table_.CopyFrom( |
| 1652 ScavengingVisitor<IGNORE_MARKS, |
| 1653 LOGGING_AND_PROFILING_ENABLED>::GetTable()); |
| 1654 } |
| 1655 } else { |
| 1656 if (!logging_and_profiling) { |
| 1657 scavenging_visitors_table_.CopyFrom( |
| 1658 ScavengingVisitor<TRANSFER_MARKS, |
| 1659 LOGGING_AND_PROFILING_DISABLED>::GetTable()); |
| 1660 } else { |
| 1661 scavenging_visitors_table_.CopyFrom( |
| 1662 ScavengingVisitor<TRANSFER_MARKS, |
| 1663 LOGGING_AND_PROFILING_ENABLED>::GetTable()); |
| 1664 } |
| 1573 } | 1665 } |
| 1574 } | 1666 } |
| 1575 | 1667 |
| 1576 | 1668 |
| 1577 void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) { | 1669 void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) { |
| 1578 ASSERT(HEAP->InFromSpace(object)); | 1670 ASSERT(HEAP->InFromSpace(object)); |
| 1579 MapWord first_word = object->map_word(); | 1671 MapWord first_word = object->map_word(); |
| 1580 ASSERT(!first_word.IsForwardingAddress()); | 1672 ASSERT(!first_word.IsForwardingAddress()); |
| 1581 Map* map = first_word.ToMap(); | 1673 Map* map = first_word.ToMap(); |
| 1582 DoScavengeObject(map, p, object); | 1674 map->GetHeap()->DoScavengeObject(map, p, object); |
| 1583 } | 1675 } |
| 1584 | 1676 |
| 1585 | 1677 |
| 1586 MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type, | 1678 MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type, |
| 1587 int instance_size) { | 1679 int instance_size) { |
| 1588 Object* result; | 1680 Object* result; |
| 1589 { MaybeObject* maybe_result = AllocateRawMap(); | 1681 { MaybeObject* maybe_result = AllocateRawMap(); |
| 1590 if (!maybe_result->ToObject(&result)) return maybe_result; | 1682 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 1591 } | 1683 } |
| 1592 | 1684 |
| 1593 // Map::cast cannot be used due to uninitialized map field. | 1685 // Map::cast cannot be used due to uninitialized map field. |
| 1594 reinterpret_cast<Map*>(result)->set_map(raw_unchecked_meta_map()); | 1686 reinterpret_cast<Map*>(result)->set_map(raw_unchecked_meta_map()); |
| 1595 reinterpret_cast<Map*>(result)->set_instance_type(instance_type); | 1687 reinterpret_cast<Map*>(result)->set_instance_type(instance_type); |
| 1596 reinterpret_cast<Map*>(result)->set_instance_size(instance_size); | 1688 reinterpret_cast<Map*>(result)->set_instance_size(instance_size); |
| 1597 reinterpret_cast<Map*>(result)->set_visitor_id( | 1689 reinterpret_cast<Map*>(result)->set_visitor_id( |
| 1598 StaticVisitorBase::GetVisitorId(instance_type, instance_size)); | 1690 StaticVisitorBase::GetVisitorId(instance_type, instance_size)); |
| 1599 reinterpret_cast<Map*>(result)->set_inobject_properties(0); | 1691 reinterpret_cast<Map*>(result)->set_inobject_properties(0); |
| 1600 reinterpret_cast<Map*>(result)->set_pre_allocated_property_fields(0); | 1692 reinterpret_cast<Map*>(result)->set_pre_allocated_property_fields(0); |
| 1601 reinterpret_cast<Map*>(result)->set_unused_property_fields(0); | 1693 reinterpret_cast<Map*>(result)->set_unused_property_fields(0); |
| 1602 reinterpret_cast<Map*>(result)->set_bit_field(0); | 1694 reinterpret_cast<Map*>(result)->set_bit_field(0); |
| 1603 reinterpret_cast<Map*>(result)->set_bit_field2(0); | 1695 reinterpret_cast<Map*>(result)->set_bit_field2(0); |
| 1604 return result; | 1696 return result; |
| 1605 } | 1697 } |
| 1606 | 1698 |
| 1607 | 1699 |
| 1608 MaybeObject* Heap::AllocateMap(InstanceType instance_type, int instance_size) { | 1700 MaybeObject* Heap::AllocateMap(InstanceType instance_type, |
| 1701 int instance_size, |
| 1702 ElementsKind elements_kind) { |
| 1609 Object* result; | 1703 Object* result; |
| 1610 { MaybeObject* maybe_result = AllocateRawMap(); | 1704 { MaybeObject* maybe_result = AllocateRawMap(); |
| 1611 if (!maybe_result->ToObject(&result)) return maybe_result; | 1705 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 1612 } | 1706 } |
| 1613 | 1707 |
| 1614 Map* map = reinterpret_cast<Map*>(result); | 1708 Map* map = reinterpret_cast<Map*>(result); |
| 1615 map->set_map(meta_map()); | 1709 map->set_map(meta_map()); |
| 1616 map->set_instance_type(instance_type); | 1710 map->set_instance_type(instance_type); |
| 1617 map->set_visitor_id( | 1711 map->set_visitor_id( |
| 1618 StaticVisitorBase::GetVisitorId(instance_type, instance_size)); | 1712 StaticVisitorBase::GetVisitorId(instance_type, instance_size)); |
| 1619 map->set_prototype(null_value()); | 1713 map->set_prototype(null_value()); |
| 1620 map->set_constructor(null_value()); | 1714 map->set_constructor(null_value()); |
| 1621 map->set_instance_size(instance_size); | 1715 map->set_instance_size(instance_size); |
| 1622 map->set_inobject_properties(0); | 1716 map->set_inobject_properties(0); |
| 1623 map->set_pre_allocated_property_fields(0); | 1717 map->set_pre_allocated_property_fields(0); |
| 1624 map->init_instance_descriptors(); | 1718 map->init_instance_descriptors(); |
| 1625 map->set_code_cache(empty_fixed_array()); | 1719 map->set_code_cache(empty_fixed_array()); |
| 1626 map->set_prototype_transitions(empty_fixed_array()); | 1720 map->set_prototype_transitions(empty_fixed_array()); |
| 1627 map->set_unused_property_fields(0); | 1721 map->set_unused_property_fields(0); |
| 1628 map->set_bit_field(0); | 1722 map->set_bit_field(0); |
| 1629 map->set_bit_field2(1 << Map::kIsExtensible); | 1723 map->set_bit_field2(1 << Map::kIsExtensible); |
| 1630 map->set_elements_kind(FAST_ELEMENTS); | 1724 map->set_elements_kind(elements_kind); |
| 1631 | 1725 |
| 1632 // If the map object is aligned fill the padding area with Smi 0 objects. | 1726 // If the map object is aligned fill the padding area with Smi 0 objects. |
| 1633 if (Map::kPadStart < Map::kSize) { | 1727 if (Map::kPadStart < Map::kSize) { |
| 1634 memset(reinterpret_cast<byte*>(map) + Map::kPadStart - kHeapObjectTag, | 1728 memset(reinterpret_cast<byte*>(map) + Map::kPadStart - kHeapObjectTag, |
| 1635 0, | 1729 0, |
| 1636 Map::kSize - Map::kPadStart); | 1730 Map::kSize - Map::kPadStart); |
| 1637 } | 1731 } |
| 1638 return map; | 1732 return map; |
| 1639 } | 1733 } |
| 1640 | 1734 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1700 if (!maybe_obj->ToObject(&obj)) return false; | 1794 if (!maybe_obj->ToObject(&obj)) return false; |
| 1701 } | 1795 } |
| 1702 set_oddball_map(Map::cast(obj)); | 1796 set_oddball_map(Map::cast(obj)); |
| 1703 | 1797 |
| 1704 // Allocate the empty array. | 1798 // Allocate the empty array. |
| 1705 { MaybeObject* maybe_obj = AllocateEmptyFixedArray(); | 1799 { MaybeObject* maybe_obj = AllocateEmptyFixedArray(); |
| 1706 if (!maybe_obj->ToObject(&obj)) return false; | 1800 if (!maybe_obj->ToObject(&obj)) return false; |
| 1707 } | 1801 } |
| 1708 set_empty_fixed_array(FixedArray::cast(obj)); | 1802 set_empty_fixed_array(FixedArray::cast(obj)); |
| 1709 | 1803 |
| 1710 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_DATA_SPACE); | 1804 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE); |
| 1711 if (!maybe_obj->ToObject(&obj)) return false; | 1805 if (!maybe_obj->ToObject(&obj)) return false; |
| 1712 } | 1806 } |
| 1713 set_null_value(obj); | 1807 set_null_value(obj); |
| 1714 Oddball::cast(obj)->set_kind(Oddball::kNull); | 1808 Oddball::cast(obj)->set_kind(Oddball::kNull); |
| 1715 | 1809 |
| 1716 // Allocate the empty descriptor array. | 1810 // Allocate the empty descriptor array. |
| 1717 { MaybeObject* maybe_obj = AllocateEmptyFixedArray(); | 1811 { MaybeObject* maybe_obj = AllocateEmptyFixedArray(); |
| 1718 if (!maybe_obj->ToObject(&obj)) return false; | 1812 if (!maybe_obj->ToObject(&obj)) return false; |
| 1719 } | 1813 } |
| 1720 set_empty_descriptor_array(DescriptorArray::cast(obj)); | 1814 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; | 1885 if (!maybe_obj->ToObject(&obj)) return false; |
| 1792 } | 1886 } |
| 1793 set_fixed_double_array_map(Map::cast(obj)); | 1887 set_fixed_double_array_map(Map::cast(obj)); |
| 1794 | 1888 |
| 1795 { MaybeObject* maybe_obj = | 1889 { MaybeObject* maybe_obj = |
| 1796 AllocateMap(BYTE_ARRAY_TYPE, kVariableSizeSentinel); | 1890 AllocateMap(BYTE_ARRAY_TYPE, kVariableSizeSentinel); |
| 1797 if (!maybe_obj->ToObject(&obj)) return false; | 1891 if (!maybe_obj->ToObject(&obj)) return false; |
| 1798 } | 1892 } |
| 1799 set_byte_array_map(Map::cast(obj)); | 1893 set_byte_array_map(Map::cast(obj)); |
| 1800 | 1894 |
| 1895 { MaybeObject* maybe_obj = |
| 1896 AllocateMap(FREE_SPACE_TYPE, kVariableSizeSentinel); |
| 1897 if (!maybe_obj->ToObject(&obj)) return false; |
| 1898 } |
| 1899 set_free_space_map(Map::cast(obj)); |
| 1900 |
| 1801 { MaybeObject* maybe_obj = AllocateByteArray(0, TENURED); | 1901 { MaybeObject* maybe_obj = AllocateByteArray(0, TENURED); |
| 1802 if (!maybe_obj->ToObject(&obj)) return false; | 1902 if (!maybe_obj->ToObject(&obj)) return false; |
| 1803 } | 1903 } |
| 1804 set_empty_byte_array(ByteArray::cast(obj)); | 1904 set_empty_byte_array(ByteArray::cast(obj)); |
| 1805 | 1905 |
| 1806 { MaybeObject* maybe_obj = | 1906 { MaybeObject* maybe_obj = |
| 1807 AllocateMap(EXTERNAL_PIXEL_ARRAY_TYPE, ExternalArray::kAlignedSize); | 1907 AllocateMap(EXTERNAL_PIXEL_ARRAY_TYPE, ExternalArray::kAlignedSize); |
| 1808 if (!maybe_obj->ToObject(&obj)) return false; | 1908 if (!maybe_obj->ToObject(&obj)) return false; |
| 1809 } | 1909 } |
| 1810 set_external_pixel_array_map(Map::cast(obj)); | 1910 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()); | 2091 HeapObject::cast(result)->set_map(global_property_cell_map()); |
| 1992 JSGlobalPropertyCell::cast(result)->set_value(value); | 2092 JSGlobalPropertyCell::cast(result)->set_value(value); |
| 1993 return result; | 2093 return result; |
| 1994 } | 2094 } |
| 1995 | 2095 |
| 1996 | 2096 |
| 1997 MaybeObject* Heap::CreateOddball(const char* to_string, | 2097 MaybeObject* Heap::CreateOddball(const char* to_string, |
| 1998 Object* to_number, | 2098 Object* to_number, |
| 1999 byte kind) { | 2099 byte kind) { |
| 2000 Object* result; | 2100 Object* result; |
| 2001 { MaybeObject* maybe_result = Allocate(oddball_map(), OLD_DATA_SPACE); | 2101 { MaybeObject* maybe_result = Allocate(oddball_map(), OLD_POINTER_SPACE); |
| 2002 if (!maybe_result->ToObject(&result)) return maybe_result; | 2102 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 2003 } | 2103 } |
| 2004 return Oddball::cast(result)->Initialize(to_string, to_number, kind); | 2104 return Oddball::cast(result)->Initialize(to_string, to_number, kind); |
| 2005 } | 2105 } |
| 2006 | 2106 |
| 2007 | 2107 |
| 2008 bool Heap::CreateApiObjects() { | 2108 bool Heap::CreateApiObjects() { |
| 2009 Object* obj; | 2109 Object* obj; |
| 2010 | 2110 |
| 2011 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); | 2111 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); |
| 2012 if (!maybe_obj->ToObject(&obj)) return false; | 2112 if (!maybe_obj->ToObject(&obj)) return false; |
| 2013 } | 2113 } |
| 2014 set_neander_map(Map::cast(obj)); | 2114 // Don't use Smi-only elements optimizations for objects with the neander |
| 2115 // map. There are too many cases where element values are set directly with a |
| 2116 // bottleneck to trap the Smi-only -> fast elements transition, and there |
| 2117 // appears to be no benefit for optimize this case. |
| 2118 Map* new_neander_map = Map::cast(obj); |
| 2119 new_neander_map->set_elements_kind(FAST_ELEMENTS); |
| 2120 set_neander_map(new_neander_map); |
| 2015 | 2121 |
| 2016 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(neander_map()); | 2122 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(neander_map()); |
| 2017 if (!maybe_obj->ToObject(&obj)) return false; | 2123 if (!maybe_obj->ToObject(&obj)) return false; |
| 2018 } | 2124 } |
| 2019 Object* elements; | 2125 Object* elements; |
| 2020 { MaybeObject* maybe_elements = AllocateFixedArray(2); | 2126 { MaybeObject* maybe_elements = AllocateFixedArray(2); |
| 2021 if (!maybe_elements->ToObject(&elements)) return false; | 2127 if (!maybe_elements->ToObject(&elements)) return false; |
| 2022 } | 2128 } |
| 2023 FixedArray::cast(elements)->set(0, Smi::FromInt(0)); | 2129 FixedArray::cast(elements)->set(0, Smi::FromInt(0)); |
| 2024 JSObject::cast(obj)->set_elements(FixedArray::cast(elements)); | 2130 JSObject::cast(obj)->set_elements(FixedArray::cast(elements)); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2049 // gcc-4.4 has problem generating correct code of following snippet: | 2155 // gcc-4.4 has problem generating correct code of following snippet: |
| 2050 // { JSEntryStub stub; | 2156 // { JSEntryStub stub; |
| 2051 // js_entry_code_ = *stub.GetCode(); | 2157 // js_entry_code_ = *stub.GetCode(); |
| 2052 // } | 2158 // } |
| 2053 // { JSConstructEntryStub stub; | 2159 // { JSConstructEntryStub stub; |
| 2054 // js_construct_entry_code_ = *stub.GetCode(); | 2160 // js_construct_entry_code_ = *stub.GetCode(); |
| 2055 // } | 2161 // } |
| 2056 // To workaround the problem, make separate functions without inlining. | 2162 // To workaround the problem, make separate functions without inlining. |
| 2057 Heap::CreateJSEntryStub(); | 2163 Heap::CreateJSEntryStub(); |
| 2058 Heap::CreateJSConstructEntryStub(); | 2164 Heap::CreateJSConstructEntryStub(); |
| 2165 |
| 2166 // Create stubs that should be there, so we don't unexpectedly have to |
| 2167 // create them if we need them during the creation of another stub. |
| 2168 // Stub creation mixes raw pointers and handles in an unsafe manner so |
| 2169 // we cannot create stubs while we are creating stubs. |
| 2170 CodeStub::GenerateStubsAheadOfTime(); |
| 2059 } | 2171 } |
| 2060 | 2172 |
| 2061 | 2173 |
| 2062 bool Heap::CreateInitialObjects() { | 2174 bool Heap::CreateInitialObjects() { |
| 2063 Object* obj; | 2175 Object* obj; |
| 2064 | 2176 |
| 2065 // The -0 value must be set before NumberFromDouble works. | 2177 // The -0 value must be set before NumberFromDouble works. |
| 2066 { MaybeObject* maybe_obj = AllocateHeapNumber(-0.0, TENURED); | 2178 { MaybeObject* maybe_obj = AllocateHeapNumber(-0.0, TENURED); |
| 2067 if (!maybe_obj->ToObject(&obj)) return false; | 2179 if (!maybe_obj->ToObject(&obj)) return false; |
| 2068 } | 2180 } |
| 2069 set_minus_zero_value(obj); | 2181 set_minus_zero_value(obj); |
| 2070 ASSERT(signbit(minus_zero_value()->Number()) != 0); | 2182 ASSERT(signbit(minus_zero_value()->Number()) != 0); |
| 2071 | 2183 |
| 2072 { MaybeObject* maybe_obj = AllocateHeapNumber(OS::nan_value(), TENURED); | 2184 { MaybeObject* maybe_obj = AllocateHeapNumber(OS::nan_value(), TENURED); |
| 2073 if (!maybe_obj->ToObject(&obj)) return false; | 2185 if (!maybe_obj->ToObject(&obj)) return false; |
| 2074 } | 2186 } |
| 2075 set_nan_value(obj); | 2187 set_nan_value(obj); |
| 2076 | 2188 |
| 2077 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_DATA_SPACE); | 2189 { MaybeObject* maybe_obj = AllocateHeapNumber(V8_INFINITY, TENURED); |
| 2190 if (!maybe_obj->ToObject(&obj)) return false; |
| 2191 } |
| 2192 set_infinity_value(obj); |
| 2193 |
| 2194 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE); |
| 2078 if (!maybe_obj->ToObject(&obj)) return false; | 2195 if (!maybe_obj->ToObject(&obj)) return false; |
| 2079 } | 2196 } |
| 2080 set_undefined_value(obj); | 2197 set_undefined_value(obj); |
| 2081 Oddball::cast(obj)->set_kind(Oddball::kUndefined); | 2198 Oddball::cast(obj)->set_kind(Oddball::kUndefined); |
| 2082 ASSERT(!InNewSpace(undefined_value())); | 2199 ASSERT(!InNewSpace(undefined_value())); |
| 2083 | 2200 |
| 2084 // Allocate initial symbol table. | 2201 // Allocate initial symbol table. |
| 2085 { MaybeObject* maybe_obj = SymbolTable::Allocate(kInitialSymbolTableSize); | 2202 { MaybeObject* maybe_obj = SymbolTable::Allocate(kInitialSymbolTableSize); |
| 2086 if (!maybe_obj->ToObject(&obj)) return false; | 2203 if (!maybe_obj->ToObject(&obj)) return false; |
| 2087 } | 2204 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2119 set_false_value(obj); | 2236 set_false_value(obj); |
| 2120 | 2237 |
| 2121 { MaybeObject* maybe_obj = CreateOddball("hole", | 2238 { MaybeObject* maybe_obj = CreateOddball("hole", |
| 2122 Smi::FromInt(-1), | 2239 Smi::FromInt(-1), |
| 2123 Oddball::kTheHole); | 2240 Oddball::kTheHole); |
| 2124 if (!maybe_obj->ToObject(&obj)) return false; | 2241 if (!maybe_obj->ToObject(&obj)) return false; |
| 2125 } | 2242 } |
| 2126 set_the_hole_value(obj); | 2243 set_the_hole_value(obj); |
| 2127 | 2244 |
| 2128 { MaybeObject* maybe_obj = CreateOddball("arguments_marker", | 2245 { MaybeObject* maybe_obj = CreateOddball("arguments_marker", |
| 2129 Smi::FromInt(-4), | 2246 Smi::FromInt(-2), |
| 2130 Oddball::kArgumentMarker); | 2247 Oddball::kArgumentMarker); |
| 2131 if (!maybe_obj->ToObject(&obj)) return false; | 2248 if (!maybe_obj->ToObject(&obj)) return false; |
| 2132 } | 2249 } |
| 2133 set_arguments_marker(obj); | 2250 set_arguments_marker(obj); |
| 2134 | 2251 |
| 2135 { MaybeObject* maybe_obj = CreateOddball("no_interceptor_result_sentinel", | 2252 { MaybeObject* maybe_obj = CreateOddball("no_interceptor_result_sentinel", |
| 2136 Smi::FromInt(-2), | 2253 Smi::FromInt(-3), |
| 2137 Oddball::kOther); | 2254 Oddball::kOther); |
| 2138 if (!maybe_obj->ToObject(&obj)) return false; | 2255 if (!maybe_obj->ToObject(&obj)) return false; |
| 2139 } | 2256 } |
| 2140 set_no_interceptor_result_sentinel(obj); | 2257 set_no_interceptor_result_sentinel(obj); |
| 2141 | 2258 |
| 2142 { MaybeObject* maybe_obj = CreateOddball("termination_exception", | 2259 { MaybeObject* maybe_obj = CreateOddball("termination_exception", |
| 2143 Smi::FromInt(-3), | 2260 Smi::FromInt(-4), |
| 2144 Oddball::kOther); | 2261 Oddball::kOther); |
| 2145 if (!maybe_obj->ToObject(&obj)) return false; | 2262 if (!maybe_obj->ToObject(&obj)) return false; |
| 2146 } | 2263 } |
| 2147 set_termination_exception(obj); | 2264 set_termination_exception(obj); |
| 2148 | 2265 |
| 2266 { MaybeObject* maybe_obj = CreateOddball("frame_alignment_marker", |
| 2267 Smi::FromInt(-5), |
| 2268 Oddball::kOther); |
| 2269 if (!maybe_obj->ToObject(&obj)) return false; |
| 2270 } |
| 2271 set_frame_alignment_marker(obj); |
| 2272 STATIC_ASSERT(Oddball::kLeastHiddenOddballNumber == -5); |
| 2273 |
| 2149 // Allocate the empty string. | 2274 // Allocate the empty string. |
| 2150 { MaybeObject* maybe_obj = AllocateRawAsciiString(0, TENURED); | 2275 { MaybeObject* maybe_obj = AllocateRawAsciiString(0, TENURED); |
| 2151 if (!maybe_obj->ToObject(&obj)) return false; | 2276 if (!maybe_obj->ToObject(&obj)) return false; |
| 2152 } | 2277 } |
| 2153 set_empty_string(String::cast(obj)); | 2278 set_empty_string(String::cast(obj)); |
| 2154 | 2279 |
| 2155 for (unsigned i = 0; i < ARRAY_SIZE(constant_symbol_table); i++) { | 2280 for (unsigned i = 0; i < ARRAY_SIZE(constant_symbol_table); i++) { |
| 2156 { MaybeObject* maybe_obj = | 2281 { MaybeObject* maybe_obj = |
| 2157 LookupAsciiSymbol(constant_symbol_table[i].contents); | 2282 LookupAsciiSymbol(constant_symbol_table[i].contents); |
| 2158 if (!maybe_obj->ToObject(&obj)) return false; | 2283 if (!maybe_obj->ToObject(&obj)) return false; |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2415 | 2540 |
| 2416 Object* js_string; | 2541 Object* js_string; |
| 2417 MaybeObject* maybe_js_string = AllocateStringFromAscii(CStrVector(str)); | 2542 MaybeObject* maybe_js_string = AllocateStringFromAscii(CStrVector(str)); |
| 2418 if (maybe_js_string->ToObject(&js_string)) { | 2543 if (maybe_js_string->ToObject(&js_string)) { |
| 2419 SetNumberStringCache(number, String::cast(js_string)); | 2544 SetNumberStringCache(number, String::cast(js_string)); |
| 2420 } | 2545 } |
| 2421 return maybe_js_string; | 2546 return maybe_js_string; |
| 2422 } | 2547 } |
| 2423 | 2548 |
| 2424 | 2549 |
| 2550 MaybeObject* Heap::Uint32ToString(uint32_t value, |
| 2551 bool check_number_string_cache) { |
| 2552 Object* number; |
| 2553 MaybeObject* maybe = NumberFromUint32(value); |
| 2554 if (!maybe->To<Object>(&number)) return maybe; |
| 2555 return NumberToString(number, check_number_string_cache); |
| 2556 } |
| 2557 |
| 2558 |
| 2425 Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) { | 2559 Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) { |
| 2426 return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]); | 2560 return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]); |
| 2427 } | 2561 } |
| 2428 | 2562 |
| 2429 | 2563 |
| 2430 Heap::RootListIndex Heap::RootIndexForExternalArrayType( | 2564 Heap::RootListIndex Heap::RootIndexForExternalArrayType( |
| 2431 ExternalArrayType array_type) { | 2565 ExternalArrayType array_type) { |
| 2432 switch (array_type) { | 2566 switch (array_type) { |
| 2433 case kExternalByteArray: | 2567 case kExternalByteArray: |
| 2434 return kExternalByteArrayMapRootIndex; | 2568 return kExternalByteArrayMapRootIndex; |
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2730 // dictionary. Check whether we already have the string in the symbol | 2864 // dictionary. Check whether we already have the string in the symbol |
| 2731 // table to prevent creation of many unneccesary strings. | 2865 // table to prevent creation of many unneccesary strings. |
| 2732 unsigned c1 = buffer->Get(start); | 2866 unsigned c1 = buffer->Get(start); |
| 2733 unsigned c2 = buffer->Get(start + 1); | 2867 unsigned c2 = buffer->Get(start + 1); |
| 2734 return MakeOrFindTwoCharacterString(this, c1, c2); | 2868 return MakeOrFindTwoCharacterString(this, c1, c2); |
| 2735 } | 2869 } |
| 2736 | 2870 |
| 2737 // Make an attempt to flatten the buffer to reduce access time. | 2871 // Make an attempt to flatten the buffer to reduce access time. |
| 2738 buffer = buffer->TryFlattenGetString(); | 2872 buffer = buffer->TryFlattenGetString(); |
| 2739 | 2873 |
| 2740 // TODO(1626): For now slicing external strings is not supported. However, | |
| 2741 // a flat cons string can have an external string as first part in some cases. | |
| 2742 // Therefore we have to single out this case as well. | |
| 2743 if (!FLAG_string_slices || | 2874 if (!FLAG_string_slices || |
| 2744 (buffer->IsConsString() && | 2875 !buffer->IsFlat() || |
| 2745 (!buffer->IsFlat() || | |
| 2746 !ConsString::cast(buffer)->first()->IsSeqString())) || | |
| 2747 buffer->IsExternalString() || | |
| 2748 length < SlicedString::kMinLength || | 2876 length < SlicedString::kMinLength || |
| 2749 pretenure == TENURED) { | 2877 pretenure == TENURED) { |
| 2750 Object* result; | 2878 Object* result; |
| 2751 { MaybeObject* maybe_result = buffer->IsAsciiRepresentation() | 2879 // WriteToFlat takes care of the case when an indirect string has a |
| 2752 ? AllocateRawAsciiString(length, pretenure) | 2880 // different encoding from its underlying string. These encodings may |
| 2753 : AllocateRawTwoByteString(length, pretenure); | 2881 // differ because of externalization. |
| 2882 bool is_ascii = buffer->IsAsciiRepresentation(); |
| 2883 { MaybeObject* maybe_result = is_ascii |
| 2884 ? AllocateRawAsciiString(length, pretenure) |
| 2885 : AllocateRawTwoByteString(length, pretenure); |
| 2754 if (!maybe_result->ToObject(&result)) return maybe_result; | 2886 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 2755 } | 2887 } |
| 2756 String* string_result = String::cast(result); | 2888 String* string_result = String::cast(result); |
| 2757 // Copy the characters into the new object. | 2889 // Copy the characters into the new object. |
| 2758 if (buffer->IsAsciiRepresentation()) { | 2890 if (is_ascii) { |
| 2759 ASSERT(string_result->IsAsciiRepresentation()); | 2891 ASSERT(string_result->IsAsciiRepresentation()); |
| 2760 char* dest = SeqAsciiString::cast(string_result)->GetChars(); | 2892 char* dest = SeqAsciiString::cast(string_result)->GetChars(); |
| 2761 String::WriteToFlat(buffer, dest, start, end); | 2893 String::WriteToFlat(buffer, dest, start, end); |
| 2762 } else { | 2894 } else { |
| 2763 ASSERT(string_result->IsTwoByteRepresentation()); | 2895 ASSERT(string_result->IsTwoByteRepresentation()); |
| 2764 uc16* dest = SeqTwoByteString::cast(string_result)->GetChars(); | 2896 uc16* dest = SeqTwoByteString::cast(string_result)->GetChars(); |
| 2765 String::WriteToFlat(buffer, dest, start, end); | 2897 String::WriteToFlat(buffer, dest, start, end); |
| 2766 } | 2898 } |
| 2767 return result; | 2899 return result; |
| 2768 } | 2900 } |
| 2769 | 2901 |
| 2770 ASSERT(buffer->IsFlat()); | 2902 ASSERT(buffer->IsFlat()); |
| 2771 ASSERT(!buffer->IsExternalString()); | |
| 2772 #if DEBUG | 2903 #if DEBUG |
| 2773 buffer->StringVerify(); | 2904 buffer->StringVerify(); |
| 2774 #endif | 2905 #endif |
| 2775 | 2906 |
| 2776 Object* result; | 2907 Object* result; |
| 2908 // When slicing an indirect string we use its encoding for a newly created |
| 2909 // slice and don't check the encoding of the underlying string. This is safe |
| 2910 // even if the encodings are different because of externalization. If an |
| 2911 // indirect ASCII string is pointing to a two-byte string, the two-byte char |
| 2912 // codes of the underlying string must still fit into ASCII (because |
| 2913 // externalization must not change char codes). |
| 2777 { Map* map = buffer->IsAsciiRepresentation() | 2914 { Map* map = buffer->IsAsciiRepresentation() |
| 2778 ? sliced_ascii_string_map() | 2915 ? sliced_ascii_string_map() |
| 2779 : sliced_string_map(); | 2916 : sliced_string_map(); |
| 2780 MaybeObject* maybe_result = Allocate(map, NEW_SPACE); | 2917 MaybeObject* maybe_result = Allocate(map, NEW_SPACE); |
| 2781 if (!maybe_result->ToObject(&result)) return maybe_result; | 2918 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 2782 } | 2919 } |
| 2783 | 2920 |
| 2784 AssertNoAllocation no_gc; | 2921 AssertNoAllocation no_gc; |
| 2785 SlicedString* sliced_string = SlicedString::cast(result); | 2922 SlicedString* sliced_string = SlicedString::cast(result); |
| 2786 sliced_string->set_length(length); | 2923 sliced_string->set_length(length); |
| 2787 sliced_string->set_hash_field(String::kEmptyHashField); | 2924 sliced_string->set_hash_field(String::kEmptyHashField); |
| 2788 if (buffer->IsConsString()) { | 2925 if (buffer->IsConsString()) { |
| 2789 ConsString* cons = ConsString::cast(buffer); | 2926 ConsString* cons = ConsString::cast(buffer); |
| 2790 ASSERT(cons->second()->length() == 0); | 2927 ASSERT(cons->second()->length() == 0); |
| 2791 sliced_string->set_parent(cons->first()); | 2928 sliced_string->set_parent(cons->first()); |
| 2792 sliced_string->set_offset(start); | 2929 sliced_string->set_offset(start); |
| 2793 } else if (buffer->IsSlicedString()) { | 2930 } else if (buffer->IsSlicedString()) { |
| 2794 // Prevent nesting sliced strings. | 2931 // Prevent nesting sliced strings. |
| 2795 SlicedString* parent_slice = SlicedString::cast(buffer); | 2932 SlicedString* parent_slice = SlicedString::cast(buffer); |
| 2796 sliced_string->set_parent(parent_slice->parent()); | 2933 sliced_string->set_parent(parent_slice->parent()); |
| 2797 sliced_string->set_offset(start + parent_slice->offset()); | 2934 sliced_string->set_offset(start + parent_slice->offset()); |
| 2798 } else { | 2935 } else { |
| 2799 sliced_string->set_parent(buffer); | 2936 sliced_string->set_parent(buffer); |
| 2800 sliced_string->set_offset(start); | 2937 sliced_string->set_offset(start); |
| 2801 } | 2938 } |
| 2802 ASSERT(sliced_string->parent()->IsSeqString()); | 2939 ASSERT(sliced_string->parent()->IsSeqString() || |
| 2940 sliced_string->parent()->IsExternalString()); |
| 2803 return result; | 2941 return result; |
| 2804 } | 2942 } |
| 2805 | 2943 |
| 2806 | 2944 |
| 2807 MaybeObject* Heap::AllocateExternalStringFromAscii( | 2945 MaybeObject* Heap::AllocateExternalStringFromAscii( |
| 2808 ExternalAsciiString::Resource* resource) { | 2946 const ExternalAsciiString::Resource* resource) { |
| 2809 size_t length = resource->length(); | 2947 size_t length = resource->length(); |
| 2810 if (length > static_cast<size_t>(String::kMaxLength)) { | 2948 if (length > static_cast<size_t>(String::kMaxLength)) { |
| 2811 isolate()->context()->mark_out_of_memory(); | 2949 isolate()->context()->mark_out_of_memory(); |
| 2812 return Failure::OutOfMemoryException(); | 2950 return Failure::OutOfMemoryException(); |
| 2813 } | 2951 } |
| 2814 | 2952 |
| 2815 Map* map = external_ascii_string_map(); | 2953 Map* map = external_ascii_string_map(); |
| 2816 Object* result; | 2954 Object* result; |
| 2817 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE); | 2955 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE); |
| 2818 if (!maybe_result->ToObject(&result)) return maybe_result; | 2956 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 2819 } | 2957 } |
| 2820 | 2958 |
| 2821 ExternalAsciiString* external_string = ExternalAsciiString::cast(result); | 2959 ExternalAsciiString* external_string = ExternalAsciiString::cast(result); |
| 2822 external_string->set_length(static_cast<int>(length)); | 2960 external_string->set_length(static_cast<int>(length)); |
| 2823 external_string->set_hash_field(String::kEmptyHashField); | 2961 external_string->set_hash_field(String::kEmptyHashField); |
| 2824 external_string->set_resource(resource); | 2962 external_string->set_resource(resource); |
| 2825 | 2963 |
| 2826 return result; | 2964 return result; |
| 2827 } | 2965 } |
| 2828 | 2966 |
| 2829 | 2967 |
| 2830 MaybeObject* Heap::AllocateExternalStringFromTwoByte( | 2968 MaybeObject* Heap::AllocateExternalStringFromTwoByte( |
| 2831 ExternalTwoByteString::Resource* resource) { | 2969 const ExternalTwoByteString::Resource* resource) { |
| 2832 size_t length = resource->length(); | 2970 size_t length = resource->length(); |
| 2833 if (length > static_cast<size_t>(String::kMaxLength)) { | 2971 if (length > static_cast<size_t>(String::kMaxLength)) { |
| 2834 isolate()->context()->mark_out_of_memory(); | 2972 isolate()->context()->mark_out_of_memory(); |
| 2835 return Failure::OutOfMemoryException(); | 2973 return Failure::OutOfMemoryException(); |
| 2836 } | 2974 } |
| 2837 | 2975 |
| 2838 // For small strings we check whether the resource contains only | 2976 // For small strings we check whether the resource contains only |
| 2839 // ASCII characters. If yes, we use a different string map. | 2977 // ASCII characters. If yes, we use a different string map. |
| 2840 static const size_t kAsciiCheckLengthLimit = 32; | 2978 static const size_t kAsciiCheckLengthLimit = 32; |
| 2841 bool is_ascii = length <= kAsciiCheckLengthLimit && | 2979 bool is_ascii = length <= kAsciiCheckLengthLimit && |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2885 if (length < 0 || length > ByteArray::kMaxLength) { | 3023 if (length < 0 || length > ByteArray::kMaxLength) { |
| 2886 return Failure::OutOfMemoryException(); | 3024 return Failure::OutOfMemoryException(); |
| 2887 } | 3025 } |
| 2888 if (pretenure == NOT_TENURED) { | 3026 if (pretenure == NOT_TENURED) { |
| 2889 return AllocateByteArray(length); | 3027 return AllocateByteArray(length); |
| 2890 } | 3028 } |
| 2891 int size = ByteArray::SizeFor(length); | 3029 int size = ByteArray::SizeFor(length); |
| 2892 Object* result; | 3030 Object* result; |
| 2893 { MaybeObject* maybe_result = (size <= MaxObjectSizeInPagedSpace()) | 3031 { MaybeObject* maybe_result = (size <= MaxObjectSizeInPagedSpace()) |
| 2894 ? old_data_space_->AllocateRaw(size) | 3032 ? old_data_space_->AllocateRaw(size) |
| 2895 : lo_space_->AllocateRaw(size); | 3033 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE); |
| 2896 if (!maybe_result->ToObject(&result)) return maybe_result; | 3034 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 2897 } | 3035 } |
| 2898 | 3036 |
| 2899 reinterpret_cast<ByteArray*>(result)->set_map(byte_array_map()); | 3037 reinterpret_cast<ByteArray*>(result)->set_map(byte_array_map()); |
| 2900 reinterpret_cast<ByteArray*>(result)->set_length(length); | 3038 reinterpret_cast<ByteArray*>(result)->set_length(length); |
| 2901 return result; | 3039 return result; |
| 2902 } | 3040 } |
| 2903 | 3041 |
| 2904 | 3042 |
| 2905 MaybeObject* Heap::AllocateByteArray(int length) { | 3043 MaybeObject* Heap::AllocateByteArray(int length) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2921 | 3059 |
| 2922 | 3060 |
| 2923 void Heap::CreateFillerObjectAt(Address addr, int size) { | 3061 void Heap::CreateFillerObjectAt(Address addr, int size) { |
| 2924 if (size == 0) return; | 3062 if (size == 0) return; |
| 2925 HeapObject* filler = HeapObject::FromAddress(addr); | 3063 HeapObject* filler = HeapObject::FromAddress(addr); |
| 2926 if (size == kPointerSize) { | 3064 if (size == kPointerSize) { |
| 2927 filler->set_map(one_pointer_filler_map()); | 3065 filler->set_map(one_pointer_filler_map()); |
| 2928 } else if (size == 2 * kPointerSize) { | 3066 } else if (size == 2 * kPointerSize) { |
| 2929 filler->set_map(two_pointer_filler_map()); | 3067 filler->set_map(two_pointer_filler_map()); |
| 2930 } else { | 3068 } else { |
| 2931 filler->set_map(byte_array_map()); | 3069 filler->set_map(free_space_map()); |
| 2932 ByteArray::cast(filler)->set_length(ByteArray::LengthFor(size)); | 3070 FreeSpace::cast(filler)->set_size(size); |
| 2933 } | 3071 } |
| 2934 } | 3072 } |
| 2935 | 3073 |
| 2936 | 3074 |
| 2937 MaybeObject* Heap::AllocateExternalArray(int length, | 3075 MaybeObject* Heap::AllocateExternalArray(int length, |
| 2938 ExternalArrayType array_type, | 3076 ExternalArrayType array_type, |
| 2939 void* external_pointer, | 3077 void* external_pointer, |
| 2940 PretenureFlag pretenure) { | 3078 PretenureFlag pretenure) { |
| 2941 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; | 3079 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; |
| 2942 Object* result; | 3080 Object* result; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2968 } | 3106 } |
| 2969 | 3107 |
| 2970 // Compute size. | 3108 // Compute size. |
| 2971 int body_size = RoundUp(desc.instr_size, kObjectAlignment); | 3109 int body_size = RoundUp(desc.instr_size, kObjectAlignment); |
| 2972 int obj_size = Code::SizeFor(body_size); | 3110 int obj_size = Code::SizeFor(body_size); |
| 2973 ASSERT(IsAligned(static_cast<intptr_t>(obj_size), kCodeAlignment)); | 3111 ASSERT(IsAligned(static_cast<intptr_t>(obj_size), kCodeAlignment)); |
| 2974 MaybeObject* maybe_result; | 3112 MaybeObject* maybe_result; |
| 2975 // Large code objects and code objects which should stay at a fixed address | 3113 // Large code objects and code objects which should stay at a fixed address |
| 2976 // are allocated in large object space. | 3114 // are allocated in large object space. |
| 2977 if (obj_size > MaxObjectSizeInPagedSpace() || immovable) { | 3115 if (obj_size > MaxObjectSizeInPagedSpace() || immovable) { |
| 2978 maybe_result = lo_space_->AllocateRawCode(obj_size); | 3116 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE); |
| 2979 } else { | 3117 } else { |
| 2980 maybe_result = code_space_->AllocateRaw(obj_size); | 3118 maybe_result = code_space_->AllocateRaw(obj_size); |
| 2981 } | 3119 } |
| 2982 | 3120 |
| 2983 Object* result; | 3121 Object* result; |
| 2984 if (!maybe_result->ToObject(&result)) return maybe_result; | 3122 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 2985 | 3123 |
| 2986 // Initialize the object | 3124 // Initialize the object |
| 2987 HeapObject::cast(result)->set_map(code_map()); | 3125 HeapObject::cast(result)->set_map(code_map()); |
| 2988 Code* code = Code::cast(result); | 3126 Code* code = Code::cast(result); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 3013 #endif | 3151 #endif |
| 3014 return code; | 3152 return code; |
| 3015 } | 3153 } |
| 3016 | 3154 |
| 3017 | 3155 |
| 3018 MaybeObject* Heap::CopyCode(Code* code) { | 3156 MaybeObject* Heap::CopyCode(Code* code) { |
| 3019 // Allocate an object the same size as the code object. | 3157 // Allocate an object the same size as the code object. |
| 3020 int obj_size = code->Size(); | 3158 int obj_size = code->Size(); |
| 3021 MaybeObject* maybe_result; | 3159 MaybeObject* maybe_result; |
| 3022 if (obj_size > MaxObjectSizeInPagedSpace()) { | 3160 if (obj_size > MaxObjectSizeInPagedSpace()) { |
| 3023 maybe_result = lo_space_->AllocateRawCode(obj_size); | 3161 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE); |
| 3024 } else { | 3162 } else { |
| 3025 maybe_result = code_space_->AllocateRaw(obj_size); | 3163 maybe_result = code_space_->AllocateRaw(obj_size); |
| 3026 } | 3164 } |
| 3027 | 3165 |
| 3028 Object* result; | 3166 Object* result; |
| 3029 if (!maybe_result->ToObject(&result)) return maybe_result; | 3167 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 3030 | 3168 |
| 3031 // Copy code object. | 3169 // Copy code object. |
| 3032 Address old_addr = code->address(); | 3170 Address old_addr = code->address(); |
| 3033 Address new_addr = reinterpret_cast<HeapObject*>(result)->address(); | 3171 Address new_addr = reinterpret_cast<HeapObject*>(result)->address(); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 3056 | 3194 |
| 3057 int new_obj_size = Code::SizeFor(new_body_size); | 3195 int new_obj_size = Code::SizeFor(new_body_size); |
| 3058 | 3196 |
| 3059 Address old_addr = code->address(); | 3197 Address old_addr = code->address(); |
| 3060 | 3198 |
| 3061 size_t relocation_offset = | 3199 size_t relocation_offset = |
| 3062 static_cast<size_t>(code->instruction_end() - old_addr); | 3200 static_cast<size_t>(code->instruction_end() - old_addr); |
| 3063 | 3201 |
| 3064 MaybeObject* maybe_result; | 3202 MaybeObject* maybe_result; |
| 3065 if (new_obj_size > MaxObjectSizeInPagedSpace()) { | 3203 if (new_obj_size > MaxObjectSizeInPagedSpace()) { |
| 3066 maybe_result = lo_space_->AllocateRawCode(new_obj_size); | 3204 maybe_result = lo_space_->AllocateRaw(new_obj_size, EXECUTABLE); |
| 3067 } else { | 3205 } else { |
| 3068 maybe_result = code_space_->AllocateRaw(new_obj_size); | 3206 maybe_result = code_space_->AllocateRaw(new_obj_size); |
| 3069 } | 3207 } |
| 3070 | 3208 |
| 3071 Object* result; | 3209 Object* result; |
| 3072 if (!maybe_result->ToObject(&result)) return maybe_result; | 3210 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 3073 | 3211 |
| 3074 // Copy code object. | 3212 // Copy code object. |
| 3075 Address new_addr = reinterpret_cast<HeapObject*>(result)->address(); | 3213 Address new_addr = reinterpret_cast<HeapObject*>(result)->address(); |
| 3076 | 3214 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 3105 Object* result; | 3243 Object* result; |
| 3106 { MaybeObject* maybe_result = | 3244 { MaybeObject* maybe_result = |
| 3107 AllocateRaw(map->instance_size(), space, retry_space); | 3245 AllocateRaw(map->instance_size(), space, retry_space); |
| 3108 if (!maybe_result->ToObject(&result)) return maybe_result; | 3246 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 3109 } | 3247 } |
| 3110 HeapObject::cast(result)->set_map(map); | 3248 HeapObject::cast(result)->set_map(map); |
| 3111 return result; | 3249 return result; |
| 3112 } | 3250 } |
| 3113 | 3251 |
| 3114 | 3252 |
| 3115 MaybeObject* Heap::InitializeFunction(JSFunction* function, | 3253 void Heap::InitializeFunction(JSFunction* function, |
| 3116 SharedFunctionInfo* shared, | 3254 SharedFunctionInfo* shared, |
| 3117 Object* prototype) { | 3255 Object* prototype) { |
| 3118 ASSERT(!prototype->IsMap()); | 3256 ASSERT(!prototype->IsMap()); |
| 3119 function->initialize_properties(); | 3257 function->initialize_properties(); |
| 3120 function->initialize_elements(); | 3258 function->initialize_elements(); |
| 3121 function->set_shared(shared); | 3259 function->set_shared(shared); |
| 3122 function->set_code(shared->code()); | 3260 function->set_code(shared->code()); |
| 3123 function->set_prototype_or_initial_map(prototype); | 3261 function->set_prototype_or_initial_map(prototype); |
| 3124 function->set_context(undefined_value()); | 3262 function->set_context(undefined_value()); |
| 3125 function->set_literals(empty_fixed_array()); | 3263 function->set_literals(empty_fixed_array()); |
| 3126 function->set_next_function_link(undefined_value()); | 3264 function->set_next_function_link(undefined_value()); |
| 3127 return function; | |
| 3128 } | 3265 } |
| 3129 | 3266 |
| 3130 | 3267 |
| 3131 MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) { | 3268 MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) { |
| 3132 // Allocate the prototype. Make sure to use the object function | 3269 // Allocate the prototype. Make sure to use the object function |
| 3133 // from the function's context, since the function can be from a | 3270 // from the function's context, since the function can be from a |
| 3134 // different context. | 3271 // different context. |
| 3135 JSFunction* object_function = | 3272 JSFunction* object_function = |
| 3136 function->context()->global_context()->object_function(); | 3273 function->context()->global_context()->object_function(); |
| 3274 |
| 3275 // Each function prototype gets a copy of the object function map. |
| 3276 // This avoid unwanted sharing of maps between prototypes of different |
| 3277 // constructors. |
| 3278 Map* new_map; |
| 3279 ASSERT(object_function->has_initial_map()); |
| 3280 { MaybeObject* maybe_map = |
| 3281 object_function->initial_map()->CopyDropTransitions(); |
| 3282 if (!maybe_map->To<Map>(&new_map)) return maybe_map; |
| 3283 } |
| 3137 Object* prototype; | 3284 Object* prototype; |
| 3138 { MaybeObject* maybe_prototype = AllocateJSObject(object_function); | 3285 { MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map); |
| 3139 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype; | 3286 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype; |
| 3140 } | 3287 } |
| 3141 // When creating the prototype for the function we must set its | 3288 // When creating the prototype for the function we must set its |
| 3142 // constructor to the function. | 3289 // constructor to the function. |
| 3143 Object* result; | 3290 Object* result; |
| 3144 { MaybeObject* maybe_result = | 3291 { MaybeObject* maybe_result = |
| 3145 JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes( | 3292 JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes( |
| 3146 constructor_symbol(), function, DONT_ENUM); | 3293 constructor_symbol(), function, DONT_ENUM); |
| 3147 if (!maybe_result->ToObject(&result)) return maybe_result; | 3294 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 3148 } | 3295 } |
| 3149 return prototype; | 3296 return prototype; |
| 3150 } | 3297 } |
| 3151 | 3298 |
| 3152 | 3299 |
| 3153 MaybeObject* Heap::AllocateFunction(Map* function_map, | 3300 MaybeObject* Heap::AllocateFunction(Map* function_map, |
| 3154 SharedFunctionInfo* shared, | 3301 SharedFunctionInfo* shared, |
| 3155 Object* prototype, | 3302 Object* prototype, |
| 3156 PretenureFlag pretenure) { | 3303 PretenureFlag pretenure) { |
| 3157 AllocationSpace space = | 3304 AllocationSpace space = |
| 3158 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE; | 3305 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE; |
| 3159 Object* result; | 3306 Object* result; |
| 3160 { MaybeObject* maybe_result = Allocate(function_map, space); | 3307 { MaybeObject* maybe_result = Allocate(function_map, space); |
| 3161 if (!maybe_result->ToObject(&result)) return maybe_result; | 3308 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 3162 } | 3309 } |
| 3163 return InitializeFunction(JSFunction::cast(result), shared, prototype); | 3310 InitializeFunction(JSFunction::cast(result), shared, prototype); |
| 3311 return result; |
| 3164 } | 3312 } |
| 3165 | 3313 |
| 3166 | 3314 |
| 3167 MaybeObject* Heap::AllocateArgumentsObject(Object* callee, int length) { | 3315 MaybeObject* Heap::AllocateArgumentsObject(Object* callee, int length) { |
| 3168 // To get fast allocation and map sharing for arguments objects we | 3316 // To get fast allocation and map sharing for arguments objects we |
| 3169 // allocate them based on an arguments boilerplate. | 3317 // allocate them based on an arguments boilerplate. |
| 3170 | 3318 |
| 3171 JSObject* boilerplate; | 3319 JSObject* boilerplate; |
| 3172 int arguments_object_size; | 3320 int arguments_object_size; |
| 3173 bool strict_mode_callee = callee->IsJSFunction() && | 3321 bool strict_mode_callee = callee->IsJSFunction() && |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3323 // according to the object's initial map. For example, if the map's | 3471 // according to the object's initial map. For example, if the map's |
| 3324 // instance type is JS_ARRAY_TYPE, the length field should be initialized | 3472 // instance type is JS_ARRAY_TYPE, the length field should be initialized |
| 3325 // to a number (eg, Smi::FromInt(0)) and the elements initialized to a | 3473 // to a number (eg, Smi::FromInt(0)) and the elements initialized to a |
| 3326 // fixed array (eg, Heap::empty_fixed_array()). Currently, the object | 3474 // fixed array (eg, Heap::empty_fixed_array()). Currently, the object |
| 3327 // verification code has to cope with (temporarily) invalid objects. See | 3475 // verification code has to cope with (temporarily) invalid objects. See |
| 3328 // for example, JSArray::JSArrayVerify). | 3476 // for example, JSArray::JSArrayVerify). |
| 3329 Object* filler; | 3477 Object* filler; |
| 3330 // We cannot always fill with one_pointer_filler_map because objects | 3478 // We cannot always fill with one_pointer_filler_map because objects |
| 3331 // created from API functions expect their internal fields to be initialized | 3479 // created from API functions expect their internal fields to be initialized |
| 3332 // with undefined_value. | 3480 // with undefined_value. |
| 3481 // Pre-allocated fields need to be initialized with undefined_value as well |
| 3482 // so that object accesses before the constructor completes (e.g. in the |
| 3483 // debugger) will not cause a crash. |
| 3333 if (map->constructor()->IsJSFunction() && | 3484 if (map->constructor()->IsJSFunction() && |
| 3334 JSFunction::cast(map->constructor())->shared()-> | 3485 JSFunction::cast(map->constructor())->shared()-> |
| 3335 IsInobjectSlackTrackingInProgress()) { | 3486 IsInobjectSlackTrackingInProgress()) { |
| 3336 // We might want to shrink the object later. | 3487 // We might want to shrink the object later. |
| 3337 ASSERT(obj->GetInternalFieldCount() == 0); | 3488 ASSERT(obj->GetInternalFieldCount() == 0); |
| 3338 filler = Heap::one_pointer_filler_map(); | 3489 filler = Heap::one_pointer_filler_map(); |
| 3339 } else { | 3490 } else { |
| 3340 filler = Heap::undefined_value(); | 3491 filler = Heap::undefined_value(); |
| 3341 } | 3492 } |
| 3342 obj->InitializeBody(map->instance_size(), filler); | 3493 obj->InitializeBody(map, Heap::undefined_value(), filler); |
| 3343 } | 3494 } |
| 3344 | 3495 |
| 3345 | 3496 |
| 3346 MaybeObject* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) { | 3497 MaybeObject* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) { |
| 3347 // JSFunctions should be allocated using AllocateFunction to be | 3498 // JSFunctions should be allocated using AllocateFunction to be |
| 3348 // properly initialized. | 3499 // properly initialized. |
| 3349 ASSERT(map->instance_type() != JS_FUNCTION_TYPE); | 3500 ASSERT(map->instance_type() != JS_FUNCTION_TYPE); |
| 3350 | 3501 |
| 3351 // Both types of global objects should be allocated using | 3502 // Both types of global objects should be allocated using |
| 3352 // AllocateGlobalObject to be properly initialized. | 3503 // AllocateGlobalObject to be properly initialized. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 3370 if (map->instance_size() > MaxObjectSizeInPagedSpace()) space = LO_SPACE; | 3521 if (map->instance_size() > MaxObjectSizeInPagedSpace()) space = LO_SPACE; |
| 3371 Object* obj; | 3522 Object* obj; |
| 3372 { MaybeObject* maybe_obj = Allocate(map, space); | 3523 { MaybeObject* maybe_obj = Allocate(map, space); |
| 3373 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 3524 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 3374 } | 3525 } |
| 3375 | 3526 |
| 3376 // Initialize the JSObject. | 3527 // Initialize the JSObject. |
| 3377 InitializeJSObjectFromMap(JSObject::cast(obj), | 3528 InitializeJSObjectFromMap(JSObject::cast(obj), |
| 3378 FixedArray::cast(properties), | 3529 FixedArray::cast(properties), |
| 3379 map); | 3530 map); |
| 3380 ASSERT(JSObject::cast(obj)->HasFastElements()); | 3531 ASSERT(JSObject::cast(obj)->HasFastSmiOnlyElements() || |
| 3532 JSObject::cast(obj)->HasFastElements()); |
| 3381 return obj; | 3533 return obj; |
| 3382 } | 3534 } |
| 3383 | 3535 |
| 3384 | 3536 |
| 3385 MaybeObject* Heap::AllocateJSObject(JSFunction* constructor, | 3537 MaybeObject* Heap::AllocateJSObject(JSFunction* constructor, |
| 3386 PretenureFlag pretenure) { | 3538 PretenureFlag pretenure) { |
| 3387 // Allocate the initial map if absent. | 3539 // Allocate the initial map if absent. |
| 3388 if (!constructor->has_initial_map()) { | 3540 if (!constructor->has_initial_map()) { |
| 3389 Object* initial_map; | 3541 Object* initial_map; |
| 3390 { MaybeObject* maybe_initial_map = AllocateInitialMap(constructor); | 3542 { MaybeObject* maybe_initial_map = AllocateInitialMap(constructor); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 3413 MaybeObject* maybe_map_obj = AllocateMap(JS_PROXY_TYPE, JSProxy::kSize); | 3565 MaybeObject* maybe_map_obj = AllocateMap(JS_PROXY_TYPE, JSProxy::kSize); |
| 3414 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj; | 3566 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj; |
| 3415 map->set_prototype(prototype); | 3567 map->set_prototype(prototype); |
| 3416 | 3568 |
| 3417 // Allocate the proxy object. | 3569 // Allocate the proxy object. |
| 3418 JSProxy* result; | 3570 JSProxy* result; |
| 3419 MaybeObject* maybe_result = Allocate(map, NEW_SPACE); | 3571 MaybeObject* maybe_result = Allocate(map, NEW_SPACE); |
| 3420 if (!maybe_result->To<JSProxy>(&result)) return maybe_result; | 3572 if (!maybe_result->To<JSProxy>(&result)) return maybe_result; |
| 3421 result->InitializeBody(map->instance_size(), Smi::FromInt(0)); | 3573 result->InitializeBody(map->instance_size(), Smi::FromInt(0)); |
| 3422 result->set_handler(handler); | 3574 result->set_handler(handler); |
| 3575 result->set_hash(undefined_value()); |
| 3423 return result; | 3576 return result; |
| 3424 } | 3577 } |
| 3425 | 3578 |
| 3426 | 3579 |
| 3427 MaybeObject* Heap::AllocateJSFunctionProxy(Object* handler, | 3580 MaybeObject* Heap::AllocateJSFunctionProxy(Object* handler, |
| 3428 Object* call_trap, | 3581 Object* call_trap, |
| 3429 Object* construct_trap, | 3582 Object* construct_trap, |
| 3430 Object* prototype) { | 3583 Object* prototype) { |
| 3431 // Allocate map. | 3584 // Allocate map. |
| 3432 // TODO(rossberg): Once we optimize proxies, think about a scheme to share | 3585 // TODO(rossberg): Once we optimize proxies, think about a scheme to share |
| 3433 // maps. Will probably depend on the identity of the handler object, too. | 3586 // maps. Will probably depend on the identity of the handler object, too. |
| 3434 Map* map; | 3587 Map* map; |
| 3435 MaybeObject* maybe_map_obj = | 3588 MaybeObject* maybe_map_obj = |
| 3436 AllocateMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize); | 3589 AllocateMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize); |
| 3437 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj; | 3590 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj; |
| 3438 map->set_prototype(prototype); | 3591 map->set_prototype(prototype); |
| 3439 | 3592 |
| 3440 // Allocate the proxy object. | 3593 // Allocate the proxy object. |
| 3441 JSFunctionProxy* result; | 3594 JSFunctionProxy* result; |
| 3442 MaybeObject* maybe_result = Allocate(map, NEW_SPACE); | 3595 MaybeObject* maybe_result = Allocate(map, NEW_SPACE); |
| 3443 if (!maybe_result->To<JSFunctionProxy>(&result)) return maybe_result; | 3596 if (!maybe_result->To<JSFunctionProxy>(&result)) return maybe_result; |
| 3444 result->InitializeBody(map->instance_size(), Smi::FromInt(0)); | 3597 result->InitializeBody(map->instance_size(), Smi::FromInt(0)); |
| 3445 result->set_handler(handler); | 3598 result->set_handler(handler); |
| 3599 result->set_hash(undefined_value()); |
| 3446 result->set_call_trap(call_trap); | 3600 result->set_call_trap(call_trap); |
| 3447 result->set_construct_trap(construct_trap); | 3601 result->set_construct_trap(construct_trap); |
| 3448 return result; | 3602 return result; |
| 3449 } | 3603 } |
| 3450 | 3604 |
| 3451 | 3605 |
| 3452 MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) { | 3606 MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) { |
| 3453 ASSERT(constructor->has_initial_map()); | 3607 ASSERT(constructor->has_initial_map()); |
| 3454 Map* map = constructor->initial_map(); | 3608 Map* map = constructor->initial_map(); |
| 3455 | 3609 |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3552 if (!maybe_clone->ToObject(&clone)) return maybe_clone; | 3706 if (!maybe_clone->ToObject(&clone)) return maybe_clone; |
| 3553 } | 3707 } |
| 3554 ASSERT(InNewSpace(clone)); | 3708 ASSERT(InNewSpace(clone)); |
| 3555 // Since we know the clone is allocated in new space, we can copy | 3709 // Since we know the clone is allocated in new space, we can copy |
| 3556 // the contents without worrying about updating the write barrier. | 3710 // the contents without worrying about updating the write barrier. |
| 3557 CopyBlock(HeapObject::cast(clone)->address(), | 3711 CopyBlock(HeapObject::cast(clone)->address(), |
| 3558 source->address(), | 3712 source->address(), |
| 3559 object_size); | 3713 object_size); |
| 3560 } | 3714 } |
| 3561 | 3715 |
| 3716 ASSERT(JSObject::cast(clone)->GetElementsKind() == source->GetElementsKind()); |
| 3562 FixedArrayBase* elements = FixedArrayBase::cast(source->elements()); | 3717 FixedArrayBase* elements = FixedArrayBase::cast(source->elements()); |
| 3563 FixedArray* properties = FixedArray::cast(source->properties()); | 3718 FixedArray* properties = FixedArray::cast(source->properties()); |
| 3564 // Update elements if necessary. | 3719 // Update elements if necessary. |
| 3565 if (elements->length() > 0) { | 3720 if (elements->length() > 0) { |
| 3566 Object* elem; | 3721 Object* elem; |
| 3567 { MaybeObject* maybe_elem; | 3722 { MaybeObject* maybe_elem; |
| 3568 if (elements->map() == fixed_cow_array_map()) { | 3723 if (elements->map() == fixed_cow_array_map()) { |
| 3569 maybe_elem = FixedArray::cast(elements); | 3724 maybe_elem = FixedArray::cast(elements); |
| 3570 } else if (source->HasFastDoubleElements()) { | 3725 } else if (source->HasFastDoubleElements()) { |
| 3571 maybe_elem = CopyFixedDoubleArray(FixedDoubleArray::cast(elements)); | 3726 maybe_elem = CopyFixedDoubleArray(FixedDoubleArray::cast(elements)); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3584 } | 3739 } |
| 3585 JSObject::cast(clone)->set_properties(FixedArray::cast(prop)); | 3740 JSObject::cast(clone)->set_properties(FixedArray::cast(prop)); |
| 3586 } | 3741 } |
| 3587 // Return the new clone. | 3742 // Return the new clone. |
| 3588 return clone; | 3743 return clone; |
| 3589 } | 3744 } |
| 3590 | 3745 |
| 3591 | 3746 |
| 3592 MaybeObject* Heap::ReinitializeJSReceiver( | 3747 MaybeObject* Heap::ReinitializeJSReceiver( |
| 3593 JSReceiver* object, InstanceType type, int size) { | 3748 JSReceiver* object, InstanceType type, int size) { |
| 3594 ASSERT(type >= FIRST_JS_RECEIVER_TYPE); | 3749 ASSERT(type >= FIRST_JS_OBJECT_TYPE); |
| 3595 | 3750 |
| 3596 // Allocate fresh map. | 3751 // Allocate fresh map. |
| 3597 // TODO(rossberg): Once we optimize proxies, cache these maps. | 3752 // TODO(rossberg): Once we optimize proxies, cache these maps. |
| 3598 Map* map; | 3753 Map* map; |
| 3599 MaybeObject* maybe_map_obj = AllocateMap(type, size); | 3754 MaybeObject* maybe = AllocateMap(type, size); |
| 3600 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj; | 3755 if (!maybe->To<Map>(&map)) return maybe; |
| 3601 | 3756 |
| 3602 // Check that the receiver has at least the size of the fresh object. | 3757 // Check that the receiver has at least the size of the fresh object. |
| 3603 int size_difference = object->map()->instance_size() - map->instance_size(); | 3758 int size_difference = object->map()->instance_size() - map->instance_size(); |
| 3604 ASSERT(size_difference >= 0); | 3759 ASSERT(size_difference >= 0); |
| 3605 | 3760 |
| 3606 map->set_prototype(object->map()->prototype()); | 3761 map->set_prototype(object->map()->prototype()); |
| 3607 | 3762 |
| 3608 // Allocate the backing storage for the properties. | 3763 // Allocate the backing storage for the properties. |
| 3609 int prop_size = map->unused_property_fields() - map->inobject_properties(); | 3764 int prop_size = map->unused_property_fields() - map->inobject_properties(); |
| 3610 Object* properties; | 3765 Object* properties; |
| 3611 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, TENURED); | 3766 maybe = AllocateFixedArray(prop_size, TENURED); |
| 3612 if (!maybe_properties->ToObject(&properties)) return maybe_properties; | 3767 if (!maybe->ToObject(&properties)) return maybe; |
| 3768 |
| 3769 // Functions require some allocation, which might fail here. |
| 3770 SharedFunctionInfo* shared = NULL; |
| 3771 if (type == JS_FUNCTION_TYPE) { |
| 3772 String* name; |
| 3773 maybe = LookupAsciiSymbol("<freezing call trap>"); |
| 3774 if (!maybe->To<String>(&name)) return maybe; |
| 3775 maybe = AllocateSharedFunctionInfo(name); |
| 3776 if (!maybe->To<SharedFunctionInfo>(&shared)) return maybe; |
| 3613 } | 3777 } |
| 3614 | 3778 |
| 3779 // Because of possible retries of this function after failure, |
| 3780 // we must NOT fail after this point, where we have changed the type! |
| 3781 |
| 3615 // Reset the map for the object. | 3782 // Reset the map for the object. |
| 3616 object->set_map(map); | 3783 object->set_map(map); |
| 3784 JSObject* jsobj = JSObject::cast(object); |
| 3617 | 3785 |
| 3618 // Reinitialize the object from the constructor map. | 3786 // Reinitialize the object from the constructor map. |
| 3619 InitializeJSObjectFromMap(JSObject::cast(object), | 3787 InitializeJSObjectFromMap(jsobj, FixedArray::cast(properties), map); |
| 3620 FixedArray::cast(properties), map); | |
| 3621 | 3788 |
| 3622 // Functions require some minimal initialization. | 3789 // Functions require some minimal initialization. |
| 3623 if (type == JS_FUNCTION_TYPE) { | 3790 if (type == JS_FUNCTION_TYPE) { |
| 3624 String* name; | 3791 map->set_function_with_prototype(true); |
| 3625 MaybeObject* maybe_name = LookupAsciiSymbol("<freezing call trap>"); | 3792 InitializeFunction(JSFunction::cast(object), shared, the_hole_value()); |
| 3626 if (!maybe_name->To<String>(&name)) return maybe_name; | 3793 JSFunction::cast(object)->set_context( |
| 3627 SharedFunctionInfo* shared; | 3794 isolate()->context()->global_context()); |
| 3628 MaybeObject* maybe_shared = AllocateSharedFunctionInfo(name); | |
| 3629 if (!maybe_shared->To<SharedFunctionInfo>(&shared)) return maybe_shared; | |
| 3630 JSFunction* func; | |
| 3631 MaybeObject* maybe_func = | |
| 3632 InitializeFunction(JSFunction::cast(object), shared, the_hole_value()); | |
| 3633 if (!maybe_func->To<JSFunction>(&func)) return maybe_func; | |
| 3634 func->set_context(isolate()->context()->global_context()); | |
| 3635 } | 3795 } |
| 3636 | 3796 |
| 3637 // Put in filler if the new object is smaller than the old. | 3797 // Put in filler if the new object is smaller than the old. |
| 3638 if (size_difference > 0) { | 3798 if (size_difference > 0) { |
| 3639 CreateFillerObjectAt( | 3799 CreateFillerObjectAt( |
| 3640 object->address() + map->instance_size(), size_difference); | 3800 object->address() + map->instance_size(), size_difference); |
| 3641 } | 3801 } |
| 3642 | 3802 |
| 3643 return object; | 3803 return object; |
| 3644 } | 3804 } |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3807 if (chars > SeqTwoByteString::kMaxLength) { | 3967 if (chars > SeqTwoByteString::kMaxLength) { |
| 3808 return Failure::OutOfMemoryException(); | 3968 return Failure::OutOfMemoryException(); |
| 3809 } | 3969 } |
| 3810 map = symbol_map(); | 3970 map = symbol_map(); |
| 3811 size = SeqTwoByteString::SizeFor(chars); | 3971 size = SeqTwoByteString::SizeFor(chars); |
| 3812 } | 3972 } |
| 3813 | 3973 |
| 3814 // Allocate string. | 3974 // Allocate string. |
| 3815 Object* result; | 3975 Object* result; |
| 3816 { MaybeObject* maybe_result = (size > MaxObjectSizeInPagedSpace()) | 3976 { MaybeObject* maybe_result = (size > MaxObjectSizeInPagedSpace()) |
| 3817 ? lo_space_->AllocateRaw(size) | 3977 ? lo_space_->AllocateRaw(size, NOT_EXECUTABLE) |
| 3818 : old_data_space_->AllocateRaw(size); | 3978 : old_data_space_->AllocateRaw(size); |
| 3819 if (!maybe_result->ToObject(&result)) return maybe_result; | 3979 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 3820 } | 3980 } |
| 3821 | 3981 |
| 3822 reinterpret_cast<HeapObject*>(result)->set_map(map); | 3982 reinterpret_cast<HeapObject*>(result)->set_map(map); |
| 3823 // Set length and hash fields of the allocated string. | 3983 // Set length and hash fields of the allocated string. |
| 3824 String* answer = String::cast(result); | 3984 String* answer = String::cast(result); |
| 3825 answer->set_length(chars); | 3985 answer->set_length(chars); |
| 3826 answer->set_hash_field(hash_field); | 3986 answer->set_hash_field(hash_field); |
| 3827 | 3987 |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3924 if (length < 0 || length > FixedArray::kMaxLength) { | 4084 if (length < 0 || length > FixedArray::kMaxLength) { |
| 3925 return Failure::OutOfMemoryException(); | 4085 return Failure::OutOfMemoryException(); |
| 3926 } | 4086 } |
| 3927 ASSERT(length > 0); | 4087 ASSERT(length > 0); |
| 3928 // Use the general function if we're forced to always allocate. | 4088 // Use the general function if we're forced to always allocate. |
| 3929 if (always_allocate()) return AllocateFixedArray(length, TENURED); | 4089 if (always_allocate()) return AllocateFixedArray(length, TENURED); |
| 3930 // Allocate the raw data for a fixed array. | 4090 // Allocate the raw data for a fixed array. |
| 3931 int size = FixedArray::SizeFor(length); | 4091 int size = FixedArray::SizeFor(length); |
| 3932 return size <= kMaxObjectSizeInNewSpace | 4092 return size <= kMaxObjectSizeInNewSpace |
| 3933 ? new_space_.AllocateRaw(size) | 4093 ? new_space_.AllocateRaw(size) |
| 3934 : lo_space_->AllocateRawFixedArray(size); | 4094 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE); |
| 3935 } | 4095 } |
| 3936 | 4096 |
| 3937 | 4097 |
| 3938 MaybeObject* Heap::CopyFixedArrayWithMap(FixedArray* src, Map* map) { | 4098 MaybeObject* Heap::CopyFixedArrayWithMap(FixedArray* src, Map* map) { |
| 3939 int len = src->length(); | 4099 int len = src->length(); |
| 3940 Object* obj; | 4100 Object* obj; |
| 3941 { MaybeObject* maybe_obj = AllocateRawFixedArray(len); | 4101 { MaybeObject* maybe_obj = AllocateRawFixedArray(len); |
| 3942 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 4102 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 3943 } | 4103 } |
| 3944 if (InNewSpace(obj)) { | 4104 if (InNewSpace(obj)) { |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4255 (size > MaxObjectSizeInPagedSpace()) ? LO_SPACE : OLD_POINTER_SPACE; | 4415 (size > MaxObjectSizeInPagedSpace()) ? LO_SPACE : OLD_POINTER_SPACE; |
| 4256 Object* result; | 4416 Object* result; |
| 4257 { MaybeObject* maybe_result = Allocate(map, space); | 4417 { MaybeObject* maybe_result = Allocate(map, space); |
| 4258 if (!maybe_result->ToObject(&result)) return maybe_result; | 4418 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 4259 } | 4419 } |
| 4260 Struct::cast(result)->InitializeBody(size); | 4420 Struct::cast(result)->InitializeBody(size); |
| 4261 return result; | 4421 return result; |
| 4262 } | 4422 } |
| 4263 | 4423 |
| 4264 | 4424 |
| 4425 bool Heap::IsHeapIterable() { |
| 4426 return (!old_pointer_space()->was_swept_conservatively() && |
| 4427 !old_data_space()->was_swept_conservatively()); |
| 4428 } |
| 4429 |
| 4430 |
| 4431 void Heap::EnsureHeapIsIterable() { |
| 4432 ASSERT(IsAllocationAllowed()); |
| 4433 if (!IsHeapIterable()) { |
| 4434 CollectAllGarbage(kMakeHeapIterableMask); |
| 4435 } |
| 4436 ASSERT(IsHeapIterable()); |
| 4437 } |
| 4438 |
| 4439 |
| 4265 bool Heap::IdleNotification() { | 4440 bool Heap::IdleNotification() { |
| 4266 static const int kIdlesBeforeScavenge = 4; | 4441 static const int kIdlesBeforeScavenge = 4; |
| 4267 static const int kIdlesBeforeMarkSweep = 7; | 4442 static const int kIdlesBeforeMarkSweep = 7; |
| 4268 static const int kIdlesBeforeMarkCompact = 8; | 4443 static const int kIdlesBeforeMarkCompact = 8; |
| 4269 static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1; | 4444 static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1; |
| 4270 static const unsigned int kGCsBetweenCleanup = 4; | 4445 static const unsigned int kGCsBetweenCleanup = 4; |
| 4271 | 4446 |
| 4272 if (!last_idle_notification_gc_count_init_) { | 4447 if (!last_idle_notification_gc_count_init_) { |
| 4273 last_idle_notification_gc_count_ = gc_count_; | 4448 last_idle_notification_gc_count_ = gc_count_; |
| 4274 last_idle_notification_gc_count_init_ = true; | 4449 last_idle_notification_gc_count_init_ = true; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 4285 number_idle_notifications_ = | 4460 number_idle_notifications_ = |
| 4286 Min(number_idle_notifications_ + 1, kMaxIdleCount); | 4461 Min(number_idle_notifications_ + 1, kMaxIdleCount); |
| 4287 } else { | 4462 } else { |
| 4288 number_idle_notifications_ = 0; | 4463 number_idle_notifications_ = 0; |
| 4289 last_idle_notification_gc_count_ = gc_count_; | 4464 last_idle_notification_gc_count_ = gc_count_; |
| 4290 } | 4465 } |
| 4291 | 4466 |
| 4292 if (number_idle_notifications_ == kIdlesBeforeScavenge) { | 4467 if (number_idle_notifications_ == kIdlesBeforeScavenge) { |
| 4293 if (contexts_disposed_ > 0) { | 4468 if (contexts_disposed_ > 0) { |
| 4294 HistogramTimerScope scope(isolate_->counters()->gc_context()); | 4469 HistogramTimerScope scope(isolate_->counters()->gc_context()); |
| 4295 CollectAllGarbage(false); | 4470 CollectAllGarbage(kNoGCFlags); |
| 4296 } else { | 4471 } else { |
| 4297 CollectGarbage(NEW_SPACE); | 4472 CollectGarbage(NEW_SPACE); |
| 4298 } | 4473 } |
| 4299 new_space_.Shrink(); | 4474 new_space_.Shrink(); |
| 4300 last_idle_notification_gc_count_ = gc_count_; | 4475 last_idle_notification_gc_count_ = gc_count_; |
| 4301 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) { | 4476 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) { |
| 4302 // Before doing the mark-sweep collections we clear the | 4477 // Before doing the mark-sweep collections we clear the |
| 4303 // compilation cache to avoid hanging on to source code and | 4478 // compilation cache to avoid hanging on to source code and |
| 4304 // generated code for cached functions. | 4479 // generated code for cached functions. |
| 4305 isolate_->compilation_cache()->Clear(); | 4480 isolate_->compilation_cache()->Clear(); |
| 4306 | 4481 |
| 4307 CollectAllGarbage(false); | 4482 CollectAllGarbage(kNoGCFlags); |
| 4308 new_space_.Shrink(); | 4483 new_space_.Shrink(); |
| 4309 last_idle_notification_gc_count_ = gc_count_; | 4484 last_idle_notification_gc_count_ = gc_count_; |
| 4310 | 4485 |
| 4311 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) { | 4486 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) { |
| 4312 CollectAllGarbage(true); | 4487 CollectAllGarbage(kNoGCFlags); |
| 4313 new_space_.Shrink(); | 4488 new_space_.Shrink(); |
| 4314 last_idle_notification_gc_count_ = gc_count_; | 4489 last_idle_notification_gc_count_ = gc_count_; |
| 4315 number_idle_notifications_ = 0; | 4490 number_idle_notifications_ = 0; |
| 4316 finished = true; | 4491 finished = true; |
| 4317 } else if (contexts_disposed_ > 0) { | 4492 } else if (contexts_disposed_ > 0) { |
| 4318 if (FLAG_expose_gc) { | 4493 if (FLAG_expose_gc) { |
| 4319 contexts_disposed_ = 0; | 4494 contexts_disposed_ = 0; |
| 4320 } else { | 4495 } else { |
| 4321 HistogramTimerScope scope(isolate_->counters()->gc_context()); | 4496 HistogramTimerScope scope(isolate_->counters()->gc_context()); |
| 4322 CollectAllGarbage(false); | 4497 CollectAllGarbage(kNoGCFlags); |
| 4323 last_idle_notification_gc_count_ = gc_count_; | 4498 last_idle_notification_gc_count_ = gc_count_; |
| 4324 } | 4499 } |
| 4325 // If this is the first idle notification, we reset the | 4500 // If this is the first idle notification, we reset the |
| 4326 // notification count to avoid letting idle notifications for | 4501 // notification count to avoid letting idle notifications for |
| 4327 // context disposal garbage collections start a potentially too | 4502 // context disposal garbage collections start a potentially too |
| 4328 // aggressive idle GC cycle. | 4503 // aggressive idle GC cycle. |
| 4329 if (number_idle_notifications_ <= 1) { | 4504 if (number_idle_notifications_ <= 1) { |
| 4330 number_idle_notifications_ = 0; | 4505 number_idle_notifications_ = 0; |
| 4331 uncommit = false; | 4506 uncommit = false; |
| 4332 } | 4507 } |
| 4333 } else if (number_idle_notifications_ > kIdlesBeforeMarkCompact) { | 4508 } else if (number_idle_notifications_ > kIdlesBeforeMarkCompact) { |
| 4334 // If we have received more than kIdlesBeforeMarkCompact idle | 4509 // If we have received more than kIdlesBeforeMarkCompact idle |
| 4335 // notifications we do not perform any cleanup because we don't | 4510 // notifications we do not perform any cleanup because we don't |
| 4336 // expect to gain much by doing so. | 4511 // expect to gain much by doing so. |
| 4337 finished = true; | 4512 finished = true; |
| 4338 } | 4513 } |
| 4339 | 4514 |
| 4340 // Make sure that we have no pending context disposals and | 4515 // Make sure that we have no pending context disposals and |
| 4341 // conditionally uncommit from space. | 4516 // conditionally uncommit from space. |
| 4342 ASSERT(contexts_disposed_ == 0); | 4517 // Take into account that we might have decided to delay full collection |
| 4518 // because incremental marking is in progress. |
| 4519 ASSERT((contexts_disposed_ == 0) || !incremental_marking()->IsStopped()); |
| 4343 if (uncommit) UncommitFromSpace(); | 4520 if (uncommit) UncommitFromSpace(); |
| 4521 |
| 4344 return finished; | 4522 return finished; |
| 4345 } | 4523 } |
| 4346 | 4524 |
| 4347 | 4525 |
| 4348 #ifdef DEBUG | 4526 #ifdef DEBUG |
| 4349 | 4527 |
| 4350 void Heap::Print() { | 4528 void Heap::Print() { |
| 4351 if (!HasBeenSetup()) return; | 4529 if (!HasBeenSetup()) return; |
| 4352 isolate()->PrintStack(); | 4530 isolate()->PrintStack(); |
| 4353 AllSpaces spaces; | 4531 AllSpaces spaces; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 4367 } | 4545 } |
| 4368 | 4546 |
| 4369 | 4547 |
| 4370 // This function expects that NewSpace's allocated objects histogram is | 4548 // This function expects that NewSpace's allocated objects histogram is |
| 4371 // populated (via a call to CollectStatistics or else as a side effect of a | 4549 // populated (via a call to CollectStatistics or else as a side effect of a |
| 4372 // just-completed scavenge collection). | 4550 // just-completed scavenge collection). |
| 4373 void Heap::ReportHeapStatistics(const char* title) { | 4551 void Heap::ReportHeapStatistics(const char* title) { |
| 4374 USE(title); | 4552 USE(title); |
| 4375 PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n", | 4553 PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n", |
| 4376 title, gc_count_); | 4554 title, gc_count_); |
| 4377 PrintF("mark-compact GC : %d\n", mc_count_); | |
| 4378 PrintF("old_gen_promotion_limit_ %" V8_PTR_PREFIX "d\n", | 4555 PrintF("old_gen_promotion_limit_ %" V8_PTR_PREFIX "d\n", |
| 4379 old_gen_promotion_limit_); | 4556 old_gen_promotion_limit_); |
| 4380 PrintF("old_gen_allocation_limit_ %" V8_PTR_PREFIX "d\n", | 4557 PrintF("old_gen_allocation_limit_ %" V8_PTR_PREFIX "d\n", |
| 4381 old_gen_allocation_limit_); | 4558 old_gen_allocation_limit_); |
| 4559 PrintF("old_gen_limit_factor_ %d\n", old_gen_limit_factor_); |
| 4382 | 4560 |
| 4383 PrintF("\n"); | 4561 PrintF("\n"); |
| 4384 PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles()); | 4562 PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles()); |
| 4385 isolate_->global_handles()->PrintStats(); | 4563 isolate_->global_handles()->PrintStats(); |
| 4386 PrintF("\n"); | 4564 PrintF("\n"); |
| 4387 | 4565 |
| 4388 PrintF("Heap statistics : "); | 4566 PrintF("Heap statistics : "); |
| 4389 isolate_->memory_allocator()->ReportStatistics(); | 4567 isolate_->memory_allocator()->ReportStatistics(); |
| 4390 PrintF("To space : "); | 4568 PrintF("To space : "); |
| 4391 new_space_.ReportStatistics(); | 4569 new_space_.ReportStatistics(); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4448 return cell_space_->Contains(addr); | 4626 return cell_space_->Contains(addr); |
| 4449 case LO_SPACE: | 4627 case LO_SPACE: |
| 4450 return lo_space_->SlowContains(addr); | 4628 return lo_space_->SlowContains(addr); |
| 4451 } | 4629 } |
| 4452 | 4630 |
| 4453 return false; | 4631 return false; |
| 4454 } | 4632 } |
| 4455 | 4633 |
| 4456 | 4634 |
| 4457 #ifdef DEBUG | 4635 #ifdef DEBUG |
| 4458 static void DummyScavengePointer(HeapObject** p) { | |
| 4459 } | |
| 4460 | |
| 4461 | |
| 4462 static void VerifyPointersUnderWatermark( | |
| 4463 PagedSpace* space, | |
| 4464 DirtyRegionCallback visit_dirty_region) { | |
| 4465 PageIterator it(space, PageIterator::PAGES_IN_USE); | |
| 4466 | |
| 4467 while (it.has_next()) { | |
| 4468 Page* page = it.next(); | |
| 4469 Address start = page->ObjectAreaStart(); | |
| 4470 Address end = page->AllocationWatermark(); | |
| 4471 | |
| 4472 HEAP->IterateDirtyRegions(Page::kAllRegionsDirtyMarks, | |
| 4473 start, | |
| 4474 end, | |
| 4475 visit_dirty_region, | |
| 4476 &DummyScavengePointer); | |
| 4477 } | |
| 4478 } | |
| 4479 | |
| 4480 | |
| 4481 static void VerifyPointersUnderWatermark(LargeObjectSpace* space) { | |
| 4482 LargeObjectIterator it(space); | |
| 4483 for (HeapObject* object = it.next(); object != NULL; object = it.next()) { | |
| 4484 if (object->IsFixedArray()) { | |
| 4485 Address slot_address = object->address(); | |
| 4486 Address end = object->address() + object->Size(); | |
| 4487 | |
| 4488 while (slot_address < end) { | |
| 4489 HeapObject** slot = reinterpret_cast<HeapObject**>(slot_address); | |
| 4490 // When we are not in GC the Heap::InNewSpace() predicate | |
| 4491 // checks that pointers which satisfy predicate point into | |
| 4492 // the active semispace. | |
| 4493 HEAP->InNewSpace(*slot); | |
| 4494 slot_address += kPointerSize; | |
| 4495 } | |
| 4496 } | |
| 4497 } | |
| 4498 } | |
| 4499 | |
| 4500 | |
| 4501 void Heap::Verify() { | 4636 void Heap::Verify() { |
| 4502 ASSERT(HasBeenSetup()); | 4637 ASSERT(HasBeenSetup()); |
| 4503 | 4638 |
| 4639 store_buffer()->Verify(); |
| 4640 |
| 4504 VerifyPointersVisitor visitor; | 4641 VerifyPointersVisitor visitor; |
| 4505 IterateRoots(&visitor, VISIT_ONLY_STRONG); | 4642 IterateRoots(&visitor, VISIT_ONLY_STRONG); |
| 4506 | 4643 |
| 4507 new_space_.Verify(); | 4644 new_space_.Verify(); |
| 4508 | 4645 |
| 4509 VerifyPointersAndDirtyRegionsVisitor dirty_regions_visitor; | 4646 old_pointer_space_->Verify(&visitor); |
| 4510 old_pointer_space_->Verify(&dirty_regions_visitor); | 4647 map_space_->Verify(&visitor); |
| 4511 map_space_->Verify(&dirty_regions_visitor); | |
| 4512 | |
| 4513 VerifyPointersUnderWatermark(old_pointer_space_, | |
| 4514 &IteratePointersInDirtyRegion); | |
| 4515 VerifyPointersUnderWatermark(map_space_, | |
| 4516 &IteratePointersInDirtyMapsRegion); | |
| 4517 VerifyPointersUnderWatermark(lo_space_); | |
| 4518 | |
| 4519 VerifyPageWatermarkValidity(old_pointer_space_, ALL_INVALID); | |
| 4520 VerifyPageWatermarkValidity(map_space_, ALL_INVALID); | |
| 4521 | 4648 |
| 4522 VerifyPointersVisitor no_dirty_regions_visitor; | 4649 VerifyPointersVisitor no_dirty_regions_visitor; |
| 4523 old_data_space_->Verify(&no_dirty_regions_visitor); | 4650 old_data_space_->Verify(&no_dirty_regions_visitor); |
| 4524 code_space_->Verify(&no_dirty_regions_visitor); | 4651 code_space_->Verify(&no_dirty_regions_visitor); |
| 4525 cell_space_->Verify(&no_dirty_regions_visitor); | 4652 cell_space_->Verify(&no_dirty_regions_visitor); |
| 4526 | 4653 |
| 4527 lo_space_->Verify(); | 4654 lo_space_->Verify(); |
| 4528 } | 4655 } |
| 4656 |
| 4529 #endif // DEBUG | 4657 #endif // DEBUG |
| 4530 | 4658 |
| 4531 | 4659 |
| 4532 MaybeObject* Heap::LookupSymbol(Vector<const char> string) { | 4660 MaybeObject* Heap::LookupSymbol(Vector<const char> string) { |
| 4533 Object* symbol = NULL; | 4661 Object* symbol = NULL; |
| 4534 Object* new_table; | 4662 Object* new_table; |
| 4535 { MaybeObject* maybe_new_table = | 4663 { MaybeObject* maybe_new_table = |
| 4536 symbol_table()->LookupSymbol(string, &symbol); | 4664 symbol_table()->LookupSymbol(string, &symbol); |
| 4537 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table; | 4665 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table; |
| 4538 } | 4666 } |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4614 if (string->IsSymbol()) { | 4742 if (string->IsSymbol()) { |
| 4615 *symbol = string; | 4743 *symbol = string; |
| 4616 return true; | 4744 return true; |
| 4617 } | 4745 } |
| 4618 return symbol_table()->LookupSymbolIfExists(string, symbol); | 4746 return symbol_table()->LookupSymbolIfExists(string, symbol); |
| 4619 } | 4747 } |
| 4620 | 4748 |
| 4621 | 4749 |
| 4622 #ifdef DEBUG | 4750 #ifdef DEBUG |
| 4623 void Heap::ZapFromSpace() { | 4751 void Heap::ZapFromSpace() { |
| 4624 ASSERT(reinterpret_cast<Object*>(kFromSpaceZapValue)->IsFailure()); | 4752 NewSpacePageIterator it(new_space_.FromSpaceStart(), |
| 4625 for (Address a = new_space_.FromSpaceLow(); | 4753 new_space_.FromSpaceEnd()); |
| 4626 a < new_space_.FromSpaceHigh(); | 4754 while (it.has_next()) { |
| 4627 a += kPointerSize) { | 4755 NewSpacePage* page = it.next(); |
| 4628 Memory::Address_at(a) = kFromSpaceZapValue; | 4756 for (Address cursor = page->body(), limit = page->body_limit(); |
| 4757 cursor < limit; |
| 4758 cursor += kPointerSize) { |
| 4759 Memory::Address_at(cursor) = kFromSpaceZapValue; |
| 4760 } |
| 4629 } | 4761 } |
| 4630 } | 4762 } |
| 4631 #endif // DEBUG | 4763 #endif // DEBUG |
| 4632 | 4764 |
| 4633 | 4765 |
| 4634 bool Heap::IteratePointersInDirtyRegion(Heap* heap, | |
| 4635 Address start, | |
| 4636 Address end, | |
| 4637 ObjectSlotCallback copy_object_func) { | |
| 4638 Address slot_address = start; | |
| 4639 bool pointers_to_new_space_found = false; | |
| 4640 | |
| 4641 while (slot_address < end) { | |
| 4642 Object** slot = reinterpret_cast<Object**>(slot_address); | |
| 4643 if (heap->InNewSpace(*slot)) { | |
| 4644 ASSERT((*slot)->IsHeapObject()); | |
| 4645 copy_object_func(reinterpret_cast<HeapObject**>(slot)); | |
| 4646 if (heap->InNewSpace(*slot)) { | |
| 4647 ASSERT((*slot)->IsHeapObject()); | |
| 4648 pointers_to_new_space_found = true; | |
| 4649 } | |
| 4650 } | |
| 4651 slot_address += kPointerSize; | |
| 4652 } | |
| 4653 return pointers_to_new_space_found; | |
| 4654 } | |
| 4655 | |
| 4656 | |
| 4657 // Compute start address of the first map following given addr. | |
| 4658 static inline Address MapStartAlign(Address addr) { | |
| 4659 Address page = Page::FromAddress(addr)->ObjectAreaStart(); | |
| 4660 return page + (((addr - page) + (Map::kSize - 1)) / Map::kSize * Map::kSize); | |
| 4661 } | |
| 4662 | |
| 4663 | |
| 4664 // Compute end address of the first map preceding given addr. | |
| 4665 static inline Address MapEndAlign(Address addr) { | |
| 4666 Address page = Page::FromAllocationTop(addr)->ObjectAreaStart(); | |
| 4667 return page + ((addr - page) / Map::kSize * Map::kSize); | |
| 4668 } | |
| 4669 | |
| 4670 | |
| 4671 static bool IteratePointersInDirtyMaps(Address start, | |
| 4672 Address end, | |
| 4673 ObjectSlotCallback copy_object_func) { | |
| 4674 ASSERT(MapStartAlign(start) == start); | |
| 4675 ASSERT(MapEndAlign(end) == end); | |
| 4676 | |
| 4677 Address map_address = start; | |
| 4678 bool pointers_to_new_space_found = false; | |
| 4679 | |
| 4680 Heap* heap = HEAP; | |
| 4681 while (map_address < end) { | |
| 4682 ASSERT(!heap->InNewSpace(Memory::Object_at(map_address))); | |
| 4683 ASSERT(Memory::Object_at(map_address)->IsMap()); | |
| 4684 | |
| 4685 Address pointer_fields_start = map_address + Map::kPointerFieldsBeginOffset; | |
| 4686 Address pointer_fields_end = map_address + Map::kPointerFieldsEndOffset; | |
| 4687 | |
| 4688 if (Heap::IteratePointersInDirtyRegion(heap, | |
| 4689 pointer_fields_start, | |
| 4690 pointer_fields_end, | |
| 4691 copy_object_func)) { | |
| 4692 pointers_to_new_space_found = true; | |
| 4693 } | |
| 4694 | |
| 4695 map_address += Map::kSize; | |
| 4696 } | |
| 4697 | |
| 4698 return pointers_to_new_space_found; | |
| 4699 } | |
| 4700 | |
| 4701 | |
| 4702 bool Heap::IteratePointersInDirtyMapsRegion( | |
| 4703 Heap* heap, | |
| 4704 Address start, | |
| 4705 Address end, | |
| 4706 ObjectSlotCallback copy_object_func) { | |
| 4707 Address map_aligned_start = MapStartAlign(start); | |
| 4708 Address map_aligned_end = MapEndAlign(end); | |
| 4709 | |
| 4710 bool contains_pointers_to_new_space = false; | |
| 4711 | |
| 4712 if (map_aligned_start != start) { | |
| 4713 Address prev_map = map_aligned_start - Map::kSize; | |
| 4714 ASSERT(Memory::Object_at(prev_map)->IsMap()); | |
| 4715 | |
| 4716 Address pointer_fields_start = | |
| 4717 Max(start, prev_map + Map::kPointerFieldsBeginOffset); | |
| 4718 | |
| 4719 Address pointer_fields_end = | |
| 4720 Min(prev_map + Map::kPointerFieldsEndOffset, end); | |
| 4721 | |
| 4722 contains_pointers_to_new_space = | |
| 4723 IteratePointersInDirtyRegion(heap, | |
| 4724 pointer_fields_start, | |
| 4725 pointer_fields_end, | |
| 4726 copy_object_func) | |
| 4727 || contains_pointers_to_new_space; | |
| 4728 } | |
| 4729 | |
| 4730 contains_pointers_to_new_space = | |
| 4731 IteratePointersInDirtyMaps(map_aligned_start, | |
| 4732 map_aligned_end, | |
| 4733 copy_object_func) | |
| 4734 || contains_pointers_to_new_space; | |
| 4735 | |
| 4736 if (map_aligned_end != end) { | |
| 4737 ASSERT(Memory::Object_at(map_aligned_end)->IsMap()); | |
| 4738 | |
| 4739 Address pointer_fields_start = | |
| 4740 map_aligned_end + Map::kPointerFieldsBeginOffset; | |
| 4741 | |
| 4742 Address pointer_fields_end = | |
| 4743 Min(end, map_aligned_end + Map::kPointerFieldsEndOffset); | |
| 4744 | |
| 4745 contains_pointers_to_new_space = | |
| 4746 IteratePointersInDirtyRegion(heap, | |
| 4747 pointer_fields_start, | |
| 4748 pointer_fields_end, | |
| 4749 copy_object_func) | |
| 4750 || contains_pointers_to_new_space; | |
| 4751 } | |
| 4752 | |
| 4753 return contains_pointers_to_new_space; | |
| 4754 } | |
| 4755 | |
| 4756 | |
| 4757 void Heap::IterateAndMarkPointersToFromSpace(Address start, | 4766 void Heap::IterateAndMarkPointersToFromSpace(Address start, |
| 4758 Address end, | 4767 Address end, |
| 4759 ObjectSlotCallback callback) { | 4768 ObjectSlotCallback callback) { |
| 4760 Address slot_address = start; | 4769 Address slot_address = start; |
| 4761 Page* page = Page::FromAddress(start); | 4770 |
| 4762 | 4771 // We are not collecting slots on new space objects during mutation |
| 4763 uint32_t marks = page->GetRegionMarks(); | 4772 // thus we have to scan for pointers to evacuation candidates when we |
| 4773 // promote objects. But we should not record any slots in non-black |
| 4774 // objects. Grey object's slots would be rescanned. |
| 4775 // White object might not survive until the end of collection |
| 4776 // it would be a violation of the invariant to record it's slots. |
| 4777 bool record_slots = false; |
| 4778 if (incremental_marking()->IsCompacting()) { |
| 4779 MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::FromAddress(start)); |
| 4780 record_slots = Marking::IsBlack(mark_bit); |
| 4781 } |
| 4764 | 4782 |
| 4765 while (slot_address < end) { | 4783 while (slot_address < end) { |
| 4766 Object** slot = reinterpret_cast<Object**>(slot_address); | 4784 Object** slot = reinterpret_cast<Object**>(slot_address); |
| 4767 if (InFromSpace(*slot)) { | 4785 Object* object = *slot; |
| 4768 ASSERT((*slot)->IsHeapObject()); | 4786 // If the store buffer becomes overfull we mark pages as being exempt from |
| 4769 callback(reinterpret_cast<HeapObject**>(slot)); | 4787 // the store buffer. These pages are scanned to find pointers that point |
| 4770 if (InNewSpace(*slot)) { | 4788 // to the new space. In that case we may hit newly promoted objects and |
| 4771 ASSERT((*slot)->IsHeapObject()); | 4789 // fix the pointers before the promotion queue gets to them. Thus the 'if'. |
| 4772 marks |= page->GetRegionMaskForAddress(slot_address); | 4790 if (object->IsHeapObject()) { |
| 4791 if (Heap::InFromSpace(object)) { |
| 4792 callback(reinterpret_cast<HeapObject**>(slot), |
| 4793 HeapObject::cast(object)); |
| 4794 Object* new_object = *slot; |
| 4795 if (InNewSpace(new_object)) { |
| 4796 ASSERT(Heap::InToSpace(new_object)); |
| 4797 ASSERT(new_object->IsHeapObject()); |
| 4798 store_buffer_.EnterDirectlyIntoStoreBuffer( |
| 4799 reinterpret_cast<Address>(slot)); |
| 4800 } |
| 4801 ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(new_object)); |
| 4802 } else if (record_slots && |
| 4803 MarkCompactCollector::IsOnEvacuationCandidate(object)) { |
| 4804 mark_compact_collector()->RecordSlot(slot, slot, object); |
| 4773 } | 4805 } |
| 4774 } | 4806 } |
| 4775 slot_address += kPointerSize; | 4807 slot_address += kPointerSize; |
| 4776 } | 4808 } |
| 4777 | 4809 } |
| 4778 page->SetRegionMarks(marks); | 4810 |
| 4779 } | 4811 |
| 4780 | 4812 #ifdef DEBUG |
| 4781 | 4813 typedef bool (*CheckStoreBufferFilter)(Object** addr); |
| 4782 uint32_t Heap::IterateDirtyRegions( | 4814 |
| 4783 uint32_t marks, | 4815 |
| 4784 Address area_start, | 4816 bool IsAMapPointerAddress(Object** addr) { |
| 4785 Address area_end, | 4817 uintptr_t a = reinterpret_cast<uintptr_t>(addr); |
| 4786 DirtyRegionCallback visit_dirty_region, | 4818 int mod = a % Map::kSize; |
| 4787 ObjectSlotCallback copy_object_func) { | 4819 return mod >= Map::kPointerFieldsBeginOffset && |
| 4788 uint32_t newmarks = 0; | 4820 mod < Map::kPointerFieldsEndOffset; |
| 4789 uint32_t mask = 1; | 4821 } |
| 4790 | 4822 |
| 4791 if (area_start >= area_end) { | 4823 |
| 4792 return newmarks; | 4824 bool EverythingsAPointer(Object** addr) { |
| 4793 } | 4825 return true; |
| 4794 | 4826 } |
| 4795 Address region_start = area_start; | 4827 |
| 4796 | 4828 |
| 4797 // area_start does not necessarily coincide with start of the first region. | 4829 static void CheckStoreBuffer(Heap* heap, |
| 4798 // Thus to calculate the beginning of the next region we have to align | 4830 Object** current, |
| 4799 // area_start by Page::kRegionSize. | 4831 Object** limit, |
| 4800 Address second_region = | 4832 Object**** store_buffer_position, |
| 4801 reinterpret_cast<Address>( | 4833 Object*** store_buffer_top, |
| 4802 reinterpret_cast<intptr_t>(area_start + Page::kRegionSize) & | 4834 CheckStoreBufferFilter filter, |
| 4803 ~Page::kRegionAlignmentMask); | 4835 Address special_garbage_start, |
| 4804 | 4836 Address special_garbage_end) { |
| 4805 // Next region might be beyond area_end. | 4837 Map* free_space_map = heap->free_space_map(); |
| 4806 Address region_end = Min(second_region, area_end); | 4838 for ( ; current < limit; current++) { |
| 4807 | 4839 Object* o = *current; |
| 4808 if (marks & mask) { | 4840 Address current_address = reinterpret_cast<Address>(current); |
| 4809 if (visit_dirty_region(this, region_start, region_end, copy_object_func)) { | 4841 // Skip free space. |
| 4810 newmarks |= mask; | 4842 if (o == free_space_map) { |
| 4811 } | 4843 Address current_address = reinterpret_cast<Address>(current); |
| 4812 } | 4844 FreeSpace* free_space = |
| 4813 mask <<= 1; | 4845 FreeSpace::cast(HeapObject::FromAddress(current_address)); |
| 4814 | 4846 int skip = free_space->Size(); |
| 4815 // Iterate subsequent regions which fully lay inside [area_start, area_end[. | 4847 ASSERT(current_address + skip <= reinterpret_cast<Address>(limit)); |
| 4816 region_start = region_end; | 4848 ASSERT(skip > 0); |
| 4817 region_end = region_start + Page::kRegionSize; | 4849 current_address += skip - kPointerSize; |
| 4818 | 4850 current = reinterpret_cast<Object**>(current_address); |
| 4819 while (region_end <= area_end) { | 4851 continue; |
| 4820 if (marks & mask) { | 4852 } |
| 4821 if (visit_dirty_region(this, | 4853 // Skip the current linear allocation space between top and limit which is |
| 4822 region_start, | 4854 // unmarked with the free space map, but can contain junk. |
| 4823 region_end, | 4855 if (current_address == special_garbage_start && |
| 4824 copy_object_func)) { | 4856 special_garbage_end != special_garbage_start) { |
| 4825 newmarks |= mask; | 4857 current_address = special_garbage_end - kPointerSize; |
| 4826 } | 4858 current = reinterpret_cast<Object**>(current_address); |
| 4827 } | 4859 continue; |
| 4828 | 4860 } |
| 4829 region_start = region_end; | 4861 if (!(*filter)(current)) continue; |
| 4830 region_end = region_start + Page::kRegionSize; | 4862 ASSERT(current_address < special_garbage_start || |
| 4831 | 4863 current_address >= special_garbage_end); |
| 4832 mask <<= 1; | 4864 ASSERT(reinterpret_cast<uintptr_t>(o) != kFreeListZapValue); |
| 4833 } | 4865 // We have to check that the pointer does not point into new space |
| 4834 | 4866 // without trying to cast it to a heap object since the hash field of |
| 4835 if (region_start != area_end) { | 4867 // a string can contain values like 1 and 3 which are tagged null |
| 4836 // A small piece of area left uniterated because area_end does not coincide | 4868 // pointers. |
| 4837 // with region end. Check whether region covering last part of area is | 4869 if (!heap->InNewSpace(o)) continue; |
| 4838 // dirty. | 4870 while (**store_buffer_position < current && |
| 4839 if (marks & mask) { | 4871 *store_buffer_position < store_buffer_top) { |
| 4840 if (visit_dirty_region(this, region_start, area_end, copy_object_func)) { | 4872 (*store_buffer_position)++; |
| 4841 newmarks |= mask; | 4873 } |
| 4842 } | 4874 if (**store_buffer_position != current || |
| 4843 } | 4875 *store_buffer_position == store_buffer_top) { |
| 4844 } | 4876 Object** obj_start = current; |
| 4845 | 4877 while (!(*obj_start)->IsMap()) obj_start--; |
| 4846 return newmarks; | 4878 UNREACHABLE(); |
| 4847 } | 4879 } |
| 4848 | 4880 } |
| 4849 | 4881 } |
| 4850 | 4882 |
| 4851 void Heap::IterateDirtyRegions( | 4883 |
| 4852 PagedSpace* space, | 4884 // Check that the store buffer contains all intergenerational pointers by |
| 4853 DirtyRegionCallback visit_dirty_region, | 4885 // scanning a page and ensuring that all pointers to young space are in the |
| 4854 ObjectSlotCallback copy_object_func, | 4886 // store buffer. |
| 4855 ExpectedPageWatermarkState expected_page_watermark_state) { | 4887 void Heap::OldPointerSpaceCheckStoreBuffer() { |
| 4856 | 4888 OldSpace* space = old_pointer_space(); |
| 4857 PageIterator it(space, PageIterator::PAGES_IN_USE); | 4889 PageIterator pages(space); |
| 4858 | 4890 |
| 4859 while (it.has_next()) { | 4891 store_buffer()->SortUniq(); |
| 4860 Page* page = it.next(); | 4892 |
| 4861 uint32_t marks = page->GetRegionMarks(); | 4893 while (pages.has_next()) { |
| 4862 | 4894 Page* page = pages.next(); |
| 4863 if (marks != Page::kAllRegionsCleanMarks) { | 4895 Object** current = reinterpret_cast<Object**>(page->ObjectAreaStart()); |
| 4864 Address start = page->ObjectAreaStart(); | 4896 |
| 4865 | 4897 Address end = page->ObjectAreaEnd(); |
| 4866 // Do not try to visit pointers beyond page allocation watermark. | 4898 |
| 4867 // Page can contain garbage pointers there. | 4899 Object*** store_buffer_position = store_buffer()->Start(); |
| 4868 Address end; | 4900 Object*** store_buffer_top = store_buffer()->Top(); |
| 4869 | 4901 |
| 4870 if ((expected_page_watermark_state == WATERMARK_SHOULD_BE_VALID) || | 4902 Object** limit = reinterpret_cast<Object**>(end); |
| 4871 page->IsWatermarkValid()) { | 4903 CheckStoreBuffer(this, |
| 4872 end = page->AllocationWatermark(); | 4904 current, |
| 4873 } else { | 4905 limit, |
| 4874 end = page->CachedAllocationWatermark(); | 4906 &store_buffer_position, |
| 4875 } | 4907 store_buffer_top, |
| 4876 | 4908 &EverythingsAPointer, |
| 4877 ASSERT(space == old_pointer_space_ || | 4909 space->top(), |
| 4878 (space == map_space_ && | 4910 space->limit()); |
| 4879 ((page->ObjectAreaStart() - end) % Map::kSize == 0))); | 4911 } |
| 4880 | 4912 } |
| 4881 page->SetRegionMarks(IterateDirtyRegions(marks, | 4913 |
| 4882 start, | 4914 |
| 4883 end, | 4915 void Heap::MapSpaceCheckStoreBuffer() { |
| 4884 visit_dirty_region, | 4916 MapSpace* space = map_space(); |
| 4885 copy_object_func)); | 4917 PageIterator pages(space); |
| 4886 } | 4918 |
| 4887 | 4919 store_buffer()->SortUniq(); |
| 4888 // Mark page watermark as invalid to maintain watermark validity invariant. | 4920 |
| 4889 // See Page::FlipMeaningOfInvalidatedWatermarkFlag() for details. | 4921 while (pages.has_next()) { |
| 4890 page->InvalidateWatermark(true); | 4922 Page* page = pages.next(); |
| 4891 } | 4923 Object** current = reinterpret_cast<Object**>(page->ObjectAreaStart()); |
| 4892 } | 4924 |
| 4925 Address end = page->ObjectAreaEnd(); |
| 4926 |
| 4927 Object*** store_buffer_position = store_buffer()->Start(); |
| 4928 Object*** store_buffer_top = store_buffer()->Top(); |
| 4929 |
| 4930 Object** limit = reinterpret_cast<Object**>(end); |
| 4931 CheckStoreBuffer(this, |
| 4932 current, |
| 4933 limit, |
| 4934 &store_buffer_position, |
| 4935 store_buffer_top, |
| 4936 &IsAMapPointerAddress, |
| 4937 space->top(), |
| 4938 space->limit()); |
| 4939 } |
| 4940 } |
| 4941 |
| 4942 |
| 4943 void Heap::LargeObjectSpaceCheckStoreBuffer() { |
| 4944 LargeObjectIterator it(lo_space()); |
| 4945 for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) { |
| 4946 // We only have code, sequential strings, or fixed arrays in large |
| 4947 // object space, and only fixed arrays can possibly contain pointers to |
| 4948 // the young generation. |
| 4949 if (object->IsFixedArray()) { |
| 4950 Object*** store_buffer_position = store_buffer()->Start(); |
| 4951 Object*** store_buffer_top = store_buffer()->Top(); |
| 4952 Object** current = reinterpret_cast<Object**>(object->address()); |
| 4953 Object** limit = |
| 4954 reinterpret_cast<Object**>(object->address() + object->Size()); |
| 4955 CheckStoreBuffer(this, |
| 4956 current, |
| 4957 limit, |
| 4958 &store_buffer_position, |
| 4959 store_buffer_top, |
| 4960 &EverythingsAPointer, |
| 4961 NULL, |
| 4962 NULL); |
| 4963 } |
| 4964 } |
| 4965 } |
| 4966 #endif |
| 4893 | 4967 |
| 4894 | 4968 |
| 4895 void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) { | 4969 void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) { |
| 4896 IterateStrongRoots(v, mode); | 4970 IterateStrongRoots(v, mode); |
| 4897 IterateWeakRoots(v, mode); | 4971 IterateWeakRoots(v, mode); |
| 4898 } | 4972 } |
| 4899 | 4973 |
| 4900 | 4974 |
| 4901 void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) { | 4975 void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) { |
| 4902 v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex])); | 4976 v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex])); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4934 isolate_->compilation_cache()->Iterate(v); | 5008 isolate_->compilation_cache()->Iterate(v); |
| 4935 v->Synchronize("compilationcache"); | 5009 v->Synchronize("compilationcache"); |
| 4936 | 5010 |
| 4937 // Iterate over local handles in handle scopes. | 5011 // Iterate over local handles in handle scopes. |
| 4938 isolate_->handle_scope_implementer()->Iterate(v); | 5012 isolate_->handle_scope_implementer()->Iterate(v); |
| 4939 v->Synchronize("handlescope"); | 5013 v->Synchronize("handlescope"); |
| 4940 | 5014 |
| 4941 // Iterate over the builtin code objects and code stubs in the | 5015 // Iterate over the builtin code objects and code stubs in the |
| 4942 // heap. Note that it is not necessary to iterate over code objects | 5016 // heap. Note that it is not necessary to iterate over code objects |
| 4943 // on scavenge collections. | 5017 // on scavenge collections. |
| 4944 if (mode != VISIT_ALL_IN_SCAVENGE && | 5018 if (mode != VISIT_ALL_IN_SCAVENGE) { |
| 4945 mode != VISIT_ALL_IN_SWEEP_NEWSPACE) { | |
| 4946 isolate_->builtins()->IterateBuiltins(v); | 5019 isolate_->builtins()->IterateBuiltins(v); |
| 4947 } | 5020 } |
| 4948 v->Synchronize("builtins"); | 5021 v->Synchronize("builtins"); |
| 4949 | 5022 |
| 4950 // Iterate over global handles. | 5023 // Iterate over global handles. |
| 4951 switch (mode) { | 5024 switch (mode) { |
| 4952 case VISIT_ONLY_STRONG: | 5025 case VISIT_ONLY_STRONG: |
| 4953 isolate_->global_handles()->IterateStrongRoots(v); | 5026 isolate_->global_handles()->IterateStrongRoots(v); |
| 4954 break; | 5027 break; |
| 4955 case VISIT_ALL_IN_SCAVENGE: | 5028 case VISIT_ALL_IN_SCAVENGE: |
| (...skipping 23 matching lines...) Expand all Loading... |
| 4979 // output a flag to the snapshot. However at this point the serializer and | 5052 // output a flag to the snapshot. However at this point the serializer and |
| 4980 // deserializer are deliberately a little unsynchronized (see above) so the | 5053 // deserializer are deliberately a little unsynchronized (see above) so the |
| 4981 // checking of the sync flag in the snapshot would fail. | 5054 // checking of the sync flag in the snapshot would fail. |
| 4982 } | 5055 } |
| 4983 | 5056 |
| 4984 | 5057 |
| 4985 // TODO(1236194): Since the heap size is configurable on the command line | 5058 // TODO(1236194): Since the heap size is configurable on the command line |
| 4986 // and through the API, we should gracefully handle the case that the heap | 5059 // and through the API, we should gracefully handle the case that the heap |
| 4987 // size is not big enough to fit all the initial objects. | 5060 // size is not big enough to fit all the initial objects. |
| 4988 bool Heap::ConfigureHeap(int max_semispace_size, | 5061 bool Heap::ConfigureHeap(int max_semispace_size, |
| 4989 int max_old_gen_size, | 5062 intptr_t max_old_gen_size, |
| 4990 int max_executable_size) { | 5063 intptr_t max_executable_size) { |
| 4991 if (HasBeenSetup()) return false; | 5064 if (HasBeenSetup()) return false; |
| 4992 | 5065 |
| 4993 if (max_semispace_size > 0) max_semispace_size_ = max_semispace_size; | 5066 if (max_semispace_size > 0) { |
| 5067 if (max_semispace_size < Page::kPageSize) { |
| 5068 max_semispace_size = Page::kPageSize; |
| 5069 if (FLAG_trace_gc) { |
| 5070 PrintF("Max semispace size cannot be less than %dkbytes", |
| 5071 Page::kPageSize >> 10); |
| 5072 } |
| 5073 } |
| 5074 max_semispace_size_ = max_semispace_size; |
| 5075 } |
| 4994 | 5076 |
| 4995 if (Snapshot::IsEnabled()) { | 5077 if (Snapshot::IsEnabled()) { |
| 4996 // If we are using a snapshot we always reserve the default amount | 5078 // If we are using a snapshot we always reserve the default amount |
| 4997 // of memory for each semispace because code in the snapshot has | 5079 // of memory for each semispace because code in the snapshot has |
| 4998 // write-barrier code that relies on the size and alignment of new | 5080 // write-barrier code that relies on the size and alignment of new |
| 4999 // space. We therefore cannot use a larger max semispace size | 5081 // space. We therefore cannot use a larger max semispace size |
| 5000 // than the default reserved semispace size. | 5082 // than the default reserved semispace size. |
| 5001 if (max_semispace_size_ > reserved_semispace_size_) { | 5083 if (max_semispace_size_ > reserved_semispace_size_) { |
| 5002 max_semispace_size_ = reserved_semispace_size_; | 5084 max_semispace_size_ = reserved_semispace_size_; |
| 5085 if (FLAG_trace_gc) { |
| 5086 PrintF("Max semispace size cannot be more than %dkbytes", |
| 5087 reserved_semispace_size_ >> 10); |
| 5088 } |
| 5003 } | 5089 } |
| 5004 } else { | 5090 } else { |
| 5005 // If we are not using snapshots we reserve space for the actual | 5091 // If we are not using snapshots we reserve space for the actual |
| 5006 // max semispace size. | 5092 // max semispace size. |
| 5007 reserved_semispace_size_ = max_semispace_size_; | 5093 reserved_semispace_size_ = max_semispace_size_; |
| 5008 } | 5094 } |
| 5009 | 5095 |
| 5010 if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size; | 5096 if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size; |
| 5011 if (max_executable_size > 0) { | 5097 if (max_executable_size > 0) { |
| 5012 max_executable_size_ = RoundUp(max_executable_size, Page::kPageSize); | 5098 max_executable_size_ = RoundUp(max_executable_size, Page::kPageSize); |
| 5013 } | 5099 } |
| 5014 | 5100 |
| 5015 // The max executable size must be less than or equal to the max old | 5101 // The max executable size must be less than or equal to the max old |
| 5016 // generation size. | 5102 // generation size. |
| 5017 if (max_executable_size_ > max_old_generation_size_) { | 5103 if (max_executable_size_ > max_old_generation_size_) { |
| 5018 max_executable_size_ = max_old_generation_size_; | 5104 max_executable_size_ = max_old_generation_size_; |
| 5019 } | 5105 } |
| 5020 | 5106 |
| 5021 // The new space size must be a power of two to support single-bit testing | 5107 // The new space size must be a power of two to support single-bit testing |
| 5022 // for containment. | 5108 // for containment. |
| 5023 max_semispace_size_ = RoundUpToPowerOf2(max_semispace_size_); | 5109 max_semispace_size_ = RoundUpToPowerOf2(max_semispace_size_); |
| 5024 reserved_semispace_size_ = RoundUpToPowerOf2(reserved_semispace_size_); | 5110 reserved_semispace_size_ = RoundUpToPowerOf2(reserved_semispace_size_); |
| 5025 initial_semispace_size_ = Min(initial_semispace_size_, max_semispace_size_); | 5111 initial_semispace_size_ = Min(initial_semispace_size_, max_semispace_size_); |
| 5026 external_allocation_limit_ = 10 * max_semispace_size_; | 5112 external_allocation_limit_ = 10 * max_semispace_size_; |
| 5027 | 5113 |
| 5028 // The old generation is paged. | 5114 // The old generation is paged and needs at least one page for each space. |
| 5029 max_old_generation_size_ = RoundUp(max_old_generation_size_, Page::kPageSize); | 5115 int paged_space_count = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1; |
| 5116 max_old_generation_size_ = Max(static_cast<intptr_t>(paged_space_count * |
| 5117 Page::kPageSize), |
| 5118 RoundUp(max_old_generation_size_, |
| 5119 Page::kPageSize)); |
| 5030 | 5120 |
| 5031 configured_ = true; | 5121 configured_ = true; |
| 5032 return true; | 5122 return true; |
| 5033 } | 5123 } |
| 5034 | 5124 |
| 5035 | 5125 |
| 5036 bool Heap::ConfigureHeapDefault() { | 5126 bool Heap::ConfigureHeapDefault() { |
| 5037 return ConfigureHeap(FLAG_max_new_space_size / 2 * KB, | 5127 return ConfigureHeap(static_cast<intptr_t>(FLAG_max_new_space_size / 2) * KB, |
| 5038 FLAG_max_old_space_size * MB, | 5128 static_cast<intptr_t>(FLAG_max_old_space_size) * MB, |
| 5039 FLAG_max_executable_size * MB); | 5129 static_cast<intptr_t>(FLAG_max_executable_size) * MB); |
| 5040 } | 5130 } |
| 5041 | 5131 |
| 5042 | 5132 |
| 5043 void Heap::RecordStats(HeapStats* stats, bool take_snapshot) { | 5133 void Heap::RecordStats(HeapStats* stats, bool take_snapshot) { |
| 5044 *stats->start_marker = HeapStats::kStartMarker; | 5134 *stats->start_marker = HeapStats::kStartMarker; |
| 5045 *stats->end_marker = HeapStats::kEndMarker; | 5135 *stats->end_marker = HeapStats::kEndMarker; |
| 5046 *stats->new_space_size = new_space_.SizeAsInt(); | 5136 *stats->new_space_size = new_space_.SizeAsInt(); |
| 5047 *stats->new_space_capacity = static_cast<int>(new_space_.Capacity()); | 5137 *stats->new_space_capacity = static_cast<int>(new_space_.Capacity()); |
| 5048 *stats->old_pointer_space_size = old_pointer_space_->Size(); | 5138 *stats->old_pointer_space_size = old_pointer_space_->Size(); |
| 5049 *stats->old_pointer_space_capacity = old_pointer_space_->Capacity(); | 5139 *stats->old_pointer_space_capacity = old_pointer_space_->Capacity(); |
| 5050 *stats->old_data_space_size = old_data_space_->Size(); | 5140 *stats->old_data_space_size = old_data_space_->Size(); |
| 5051 *stats->old_data_space_capacity = old_data_space_->Capacity(); | 5141 *stats->old_data_space_capacity = old_data_space_->Capacity(); |
| 5052 *stats->code_space_size = code_space_->Size(); | 5142 *stats->code_space_size = code_space_->Size(); |
| 5053 *stats->code_space_capacity = code_space_->Capacity(); | 5143 *stats->code_space_capacity = code_space_->Capacity(); |
| 5054 *stats->map_space_size = map_space_->Size(); | 5144 *stats->map_space_size = map_space_->Size(); |
| 5055 *stats->map_space_capacity = map_space_->Capacity(); | 5145 *stats->map_space_capacity = map_space_->Capacity(); |
| 5056 *stats->cell_space_size = cell_space_->Size(); | 5146 *stats->cell_space_size = cell_space_->Size(); |
| 5057 *stats->cell_space_capacity = cell_space_->Capacity(); | 5147 *stats->cell_space_capacity = cell_space_->Capacity(); |
| 5058 *stats->lo_space_size = lo_space_->Size(); | 5148 *stats->lo_space_size = lo_space_->Size(); |
| 5059 isolate_->global_handles()->RecordStats(stats); | 5149 isolate_->global_handles()->RecordStats(stats); |
| 5060 *stats->memory_allocator_size = isolate()->memory_allocator()->Size(); | 5150 *stats->memory_allocator_size = isolate()->memory_allocator()->Size(); |
| 5061 *stats->memory_allocator_capacity = | 5151 *stats->memory_allocator_capacity = |
| 5062 isolate()->memory_allocator()->Size() + | 5152 isolate()->memory_allocator()->Size() + |
| 5063 isolate()->memory_allocator()->Available(); | 5153 isolate()->memory_allocator()->Available(); |
| 5064 *stats->os_error = OS::GetLastError(); | 5154 *stats->os_error = OS::GetLastError(); |
| 5065 isolate()->memory_allocator()->Available(); | 5155 isolate()->memory_allocator()->Available(); |
| 5066 if (take_snapshot) { | 5156 if (take_snapshot) { |
| 5067 HeapIterator iterator(HeapIterator::kFilterFreeListNodes); | 5157 HeapIterator iterator; |
| 5068 for (HeapObject* obj = iterator.next(); | 5158 for (HeapObject* obj = iterator.next(); |
| 5069 obj != NULL; | 5159 obj != NULL; |
| 5070 obj = iterator.next()) { | 5160 obj = iterator.next()) { |
| 5071 InstanceType type = obj->map()->instance_type(); | 5161 InstanceType type = obj->map()->instance_type(); |
| 5072 ASSERT(0 <= type && type <= LAST_TYPE); | 5162 ASSERT(0 <= type && type <= LAST_TYPE); |
| 5073 stats->objects_per_type[type]++; | 5163 stats->objects_per_type[type]++; |
| 5074 stats->size_per_type[type] += obj->Size(); | 5164 stats->size_per_type[type] += obj->Size(); |
| 5075 } | 5165 } |
| 5076 } | 5166 } |
| 5077 } | 5167 } |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5273 // Configuration is based on the flags new-space-size (really the semispace | 5363 // Configuration is based on the flags new-space-size (really the semispace |
| 5274 // size) and old-space-size if set or the initial values of semispace_size_ | 5364 // size) and old-space-size if set or the initial values of semispace_size_ |
| 5275 // and old_generation_size_ otherwise. | 5365 // and old_generation_size_ otherwise. |
| 5276 if (!configured_) { | 5366 if (!configured_) { |
| 5277 if (!ConfigureHeapDefault()) return false; | 5367 if (!ConfigureHeapDefault()) return false; |
| 5278 } | 5368 } |
| 5279 | 5369 |
| 5280 gc_initializer_mutex->Lock(); | 5370 gc_initializer_mutex->Lock(); |
| 5281 static bool initialized_gc = false; | 5371 static bool initialized_gc = false; |
| 5282 if (!initialized_gc) { | 5372 if (!initialized_gc) { |
| 5283 initialized_gc = true; | 5373 initialized_gc = true; |
| 5284 InitializeScavengingVisitorsTables(); | 5374 InitializeScavengingVisitorsTables(); |
| 5285 NewSpaceScavenger::Initialize(); | 5375 NewSpaceScavenger::Initialize(); |
| 5286 MarkCompactCollector::Initialize(); | 5376 MarkCompactCollector::Initialize(); |
| 5287 } | 5377 } |
| 5288 gc_initializer_mutex->Unlock(); | 5378 gc_initializer_mutex->Unlock(); |
| 5289 | 5379 |
| 5290 MarkMapPointersAsEncoded(false); | 5380 MarkMapPointersAsEncoded(false); |
| 5291 | 5381 |
| 5292 // Setup memory allocator and reserve a chunk of memory for new | 5382 // Setup memory allocator. |
| 5293 // space. The chunk is double the size of the requested reserved | |
| 5294 // new space size to ensure that we can find a pair of semispaces that | |
| 5295 // are contiguous and aligned to their size. | |
| 5296 if (!isolate_->memory_allocator()->Setup(MaxReserved(), MaxExecutableSize())) | 5383 if (!isolate_->memory_allocator()->Setup(MaxReserved(), MaxExecutableSize())) |
| 5297 return false; | 5384 return false; |
| 5298 void* chunk = | |
| 5299 isolate_->memory_allocator()->ReserveInitialChunk( | |
| 5300 4 * reserved_semispace_size_); | |
| 5301 if (chunk == NULL) return false; | |
| 5302 | 5385 |
| 5303 // Align the pair of semispaces to their size, which must be a power | 5386 // Setup new space. |
| 5304 // of 2. | 5387 if (!new_space_.Setup(reserved_semispace_size_, max_semispace_size_)) { |
| 5305 Address new_space_start = | |
| 5306 RoundUp(reinterpret_cast<byte*>(chunk), 2 * reserved_semispace_size_); | |
| 5307 if (!new_space_.Setup(new_space_start, 2 * reserved_semispace_size_)) { | |
| 5308 return false; | 5388 return false; |
| 5309 } | 5389 } |
| 5310 | 5390 |
| 5311 // Initialize old pointer space. | 5391 // Initialize old pointer space. |
| 5312 old_pointer_space_ = | 5392 old_pointer_space_ = |
| 5313 new OldSpace(this, | 5393 new OldSpace(this, |
| 5314 max_old_generation_size_, | 5394 max_old_generation_size_, |
| 5315 OLD_POINTER_SPACE, | 5395 OLD_POINTER_SPACE, |
| 5316 NOT_EXECUTABLE); | 5396 NOT_EXECUTABLE); |
| 5317 if (old_pointer_space_ == NULL) return false; | 5397 if (old_pointer_space_ == NULL) return false; |
| 5318 if (!old_pointer_space_->Setup(NULL, 0)) return false; | 5398 if (!old_pointer_space_->Setup()) return false; |
| 5319 | 5399 |
| 5320 // Initialize old data space. | 5400 // Initialize old data space. |
| 5321 old_data_space_ = | 5401 old_data_space_ = |
| 5322 new OldSpace(this, | 5402 new OldSpace(this, |
| 5323 max_old_generation_size_, | 5403 max_old_generation_size_, |
| 5324 OLD_DATA_SPACE, | 5404 OLD_DATA_SPACE, |
| 5325 NOT_EXECUTABLE); | 5405 NOT_EXECUTABLE); |
| 5326 if (old_data_space_ == NULL) return false; | 5406 if (old_data_space_ == NULL) return false; |
| 5327 if (!old_data_space_->Setup(NULL, 0)) return false; | 5407 if (!old_data_space_->Setup()) return false; |
| 5328 | 5408 |
| 5329 // Initialize the code space, set its maximum capacity to the old | 5409 // Initialize the code space, set its maximum capacity to the old |
| 5330 // generation size. It needs executable memory. | 5410 // generation size. It needs executable memory. |
| 5331 // On 64-bit platform(s), we put all code objects in a 2 GB range of | 5411 // On 64-bit platform(s), we put all code objects in a 2 GB range of |
| 5332 // virtual address space, so that they can call each other with near calls. | 5412 // virtual address space, so that they can call each other with near calls. |
| 5333 if (code_range_size_ > 0) { | 5413 if (code_range_size_ > 0) { |
| 5334 if (!isolate_->code_range()->Setup(code_range_size_)) { | 5414 if (!isolate_->code_range()->Setup(code_range_size_)) { |
| 5335 return false; | 5415 return false; |
| 5336 } | 5416 } |
| 5337 } | 5417 } |
| 5338 | 5418 |
| 5339 code_space_ = | 5419 code_space_ = |
| 5340 new OldSpace(this, max_old_generation_size_, CODE_SPACE, EXECUTABLE); | 5420 new OldSpace(this, max_old_generation_size_, CODE_SPACE, EXECUTABLE); |
| 5341 if (code_space_ == NULL) return false; | 5421 if (code_space_ == NULL) return false; |
| 5342 if (!code_space_->Setup(NULL, 0)) return false; | 5422 if (!code_space_->Setup()) return false; |
| 5343 | 5423 |
| 5344 // Initialize map space. | 5424 // Initialize map space. |
| 5345 map_space_ = new MapSpace(this, FLAG_use_big_map_space | 5425 map_space_ = new MapSpace(this, |
| 5346 ? max_old_generation_size_ | 5426 max_old_generation_size_, |
| 5347 : MapSpace::kMaxMapPageIndex * Page::kPageSize, | 5427 FLAG_max_map_space_pages, |
| 5348 FLAG_max_map_space_pages, | 5428 MAP_SPACE); |
| 5349 MAP_SPACE); | |
| 5350 if (map_space_ == NULL) return false; | 5429 if (map_space_ == NULL) return false; |
| 5351 if (!map_space_->Setup(NULL, 0)) return false; | 5430 if (!map_space_->Setup()) return false; |
| 5352 | 5431 |
| 5353 // Initialize global property cell space. | 5432 // Initialize global property cell space. |
| 5354 cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE); | 5433 cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE); |
| 5355 if (cell_space_ == NULL) return false; | 5434 if (cell_space_ == NULL) return false; |
| 5356 if (!cell_space_->Setup(NULL, 0)) return false; | 5435 if (!cell_space_->Setup()) return false; |
| 5357 | 5436 |
| 5358 // The large object code space may contain code or data. We set the memory | 5437 // The large object code space may contain code or data. We set the memory |
| 5359 // to be non-executable here for safety, but this means we need to enable it | 5438 // to be non-executable here for safety, but this means we need to enable it |
| 5360 // explicitly when allocating large code objects. | 5439 // explicitly when allocating large code objects. |
| 5361 lo_space_ = new LargeObjectSpace(this, LO_SPACE); | 5440 lo_space_ = new LargeObjectSpace(this, LO_SPACE); |
| 5362 if (lo_space_ == NULL) return false; | 5441 if (lo_space_ == NULL) return false; |
| 5363 if (!lo_space_->Setup()) return false; | 5442 if (!lo_space_->Setup()) return false; |
| 5364 | |
| 5365 if (create_heap_objects) { | 5443 if (create_heap_objects) { |
| 5366 // Create initial maps. | 5444 // Create initial maps. |
| 5367 if (!CreateInitialMaps()) return false; | 5445 if (!CreateInitialMaps()) return false; |
| 5368 if (!CreateApiObjects()) return false; | 5446 if (!CreateApiObjects()) return false; |
| 5369 | 5447 |
| 5370 // Create initial objects | 5448 // Create initial objects |
| 5371 if (!CreateInitialObjects()) return false; | 5449 if (!CreateInitialObjects()) return false; |
| 5372 | 5450 |
| 5373 global_contexts_list_ = undefined_value(); | 5451 global_contexts_list_ = undefined_value(); |
| 5374 } | 5452 } |
| 5375 | 5453 |
| 5376 LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity())); | 5454 LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity())); |
| 5377 LOG(isolate_, IntPtrTEvent("heap-available", Available())); | 5455 LOG(isolate_, IntPtrTEvent("heap-available", Available())); |
| 5378 | 5456 |
| 5457 store_buffer()->Setup(); |
| 5458 |
| 5379 return true; | 5459 return true; |
| 5380 } | 5460 } |
| 5381 | 5461 |
| 5382 | 5462 |
| 5383 void Heap::SetStackLimits() { | 5463 void Heap::SetStackLimits() { |
| 5384 ASSERT(isolate_ != NULL); | 5464 ASSERT(isolate_ != NULL); |
| 5385 ASSERT(isolate_ == isolate()); | 5465 ASSERT(isolate_ == isolate()); |
| 5386 // On 64 bit machines, pointers are generally out of range of Smis. We write | 5466 // On 64 bit machines, pointers are generally out of range of Smis. We write |
| 5387 // something that looks like an out of range Smi to the GC. | 5467 // something that looks like an out of range Smi to the GC. |
| 5388 | 5468 |
| 5389 // Set up the special root array entries containing the stack limits. | 5469 // Set up the special root array entries containing the stack limits. |
| 5390 // These are actually addresses, but the tag makes the GC ignore it. | 5470 // These are actually addresses, but the tag makes the GC ignore it. |
| 5391 roots_[kStackLimitRootIndex] = | 5471 roots_[kStackLimitRootIndex] = |
| 5392 reinterpret_cast<Object*>( | 5472 reinterpret_cast<Object*>( |
| 5393 (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag); | 5473 (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag); |
| 5394 roots_[kRealStackLimitRootIndex] = | 5474 roots_[kRealStackLimitRootIndex] = |
| 5395 reinterpret_cast<Object*>( | 5475 reinterpret_cast<Object*>( |
| 5396 (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag); | 5476 (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag); |
| 5397 } | 5477 } |
| 5398 | 5478 |
| 5399 | 5479 |
| 5400 void Heap::TearDown() { | 5480 void Heap::TearDown() { |
| 5401 if (FLAG_print_cumulative_gc_stat) { | 5481 if (FLAG_print_cumulative_gc_stat) { |
| 5402 PrintF("\n\n"); | 5482 PrintF("\n\n"); |
| 5403 PrintF("gc_count=%d ", gc_count_); | 5483 PrintF("gc_count=%d ", gc_count_); |
| 5404 PrintF("mark_sweep_count=%d ", ms_count_); | 5484 PrintF("mark_sweep_count=%d ", ms_count_); |
| 5405 PrintF("mark_compact_count=%d ", mc_count_); | |
| 5406 PrintF("max_gc_pause=%d ", get_max_gc_pause()); | 5485 PrintF("max_gc_pause=%d ", get_max_gc_pause()); |
| 5407 PrintF("min_in_mutator=%d ", get_min_in_mutator()); | 5486 PrintF("min_in_mutator=%d ", get_min_in_mutator()); |
| 5408 PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ", | 5487 PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ", |
| 5409 get_max_alive_after_gc()); | 5488 get_max_alive_after_gc()); |
| 5410 PrintF("\n\n"); | 5489 PrintF("\n\n"); |
| 5411 } | 5490 } |
| 5412 | 5491 |
| 5413 isolate_->global_handles()->TearDown(); | 5492 isolate_->global_handles()->TearDown(); |
| 5414 | 5493 |
| 5415 external_string_table_.TearDown(); | 5494 external_string_table_.TearDown(); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 5445 delete cell_space_; | 5524 delete cell_space_; |
| 5446 cell_space_ = NULL; | 5525 cell_space_ = NULL; |
| 5447 } | 5526 } |
| 5448 | 5527 |
| 5449 if (lo_space_ != NULL) { | 5528 if (lo_space_ != NULL) { |
| 5450 lo_space_->TearDown(); | 5529 lo_space_->TearDown(); |
| 5451 delete lo_space_; | 5530 delete lo_space_; |
| 5452 lo_space_ = NULL; | 5531 lo_space_ = NULL; |
| 5453 } | 5532 } |
| 5454 | 5533 |
| 5534 store_buffer()->TearDown(); |
| 5535 incremental_marking()->TearDown(); |
| 5536 |
| 5455 isolate_->memory_allocator()->TearDown(); | 5537 isolate_->memory_allocator()->TearDown(); |
| 5456 | 5538 |
| 5457 #ifdef DEBUG | 5539 #ifdef DEBUG |
| 5458 delete debug_utils_; | 5540 delete debug_utils_; |
| 5459 debug_utils_ = NULL; | 5541 debug_utils_ = NULL; |
| 5460 #endif | 5542 #endif |
| 5461 } | 5543 } |
| 5462 | 5544 |
| 5463 | 5545 |
| 5464 void Heap::Shrink() { | 5546 void Heap::Shrink() { |
| 5465 // Try to shrink all paged spaces. | 5547 // Try to shrink all paged spaces. |
| 5466 PagedSpaces spaces; | 5548 PagedSpaces spaces; |
| 5467 for (PagedSpace* space = spaces.next(); space != NULL; space = spaces.next()) | 5549 for (PagedSpace* space = spaces.next(); space != NULL; space = spaces.next()) |
| 5468 space->Shrink(); | 5550 space->ReleaseAllUnusedPages(); |
| 5469 } | 5551 } |
| 5470 | 5552 |
| 5471 | 5553 |
| 5472 void Heap::AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type) { | 5554 void Heap::AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type) { |
| 5473 ASSERT(callback != NULL); | 5555 ASSERT(callback != NULL); |
| 5474 GCPrologueCallbackPair pair(callback, gc_type); | 5556 GCPrologueCallbackPair pair(callback, gc_type); |
| 5475 ASSERT(!gc_prologue_callbacks_.Contains(pair)); | 5557 ASSERT(!gc_prologue_callbacks_.Contains(pair)); |
| 5476 return gc_prologue_callbacks_.Add(pair); | 5558 return gc_prologue_callbacks_.Add(pair); |
| 5477 } | 5559 } |
| 5478 | 5560 |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5661 } | 5743 } |
| 5662 | 5744 |
| 5663 | 5745 |
| 5664 class HeapObjectsFilter { | 5746 class HeapObjectsFilter { |
| 5665 public: | 5747 public: |
| 5666 virtual ~HeapObjectsFilter() {} | 5748 virtual ~HeapObjectsFilter() {} |
| 5667 virtual bool SkipObject(HeapObject* object) = 0; | 5749 virtual bool SkipObject(HeapObject* object) = 0; |
| 5668 }; | 5750 }; |
| 5669 | 5751 |
| 5670 | 5752 |
| 5671 class FreeListNodesFilter : public HeapObjectsFilter { | |
| 5672 public: | |
| 5673 FreeListNodesFilter() { | |
| 5674 MarkFreeListNodes(); | |
| 5675 } | |
| 5676 | |
| 5677 bool SkipObject(HeapObject* object) { | |
| 5678 if (object->IsMarked()) { | |
| 5679 object->ClearMark(); | |
| 5680 return true; | |
| 5681 } else { | |
| 5682 return false; | |
| 5683 } | |
| 5684 } | |
| 5685 | |
| 5686 private: | |
| 5687 void MarkFreeListNodes() { | |
| 5688 Heap* heap = HEAP; | |
| 5689 heap->old_pointer_space()->MarkFreeListNodes(); | |
| 5690 heap->old_data_space()->MarkFreeListNodes(); | |
| 5691 MarkCodeSpaceFreeListNodes(heap); | |
| 5692 heap->map_space()->MarkFreeListNodes(); | |
| 5693 heap->cell_space()->MarkFreeListNodes(); | |
| 5694 } | |
| 5695 | |
| 5696 void MarkCodeSpaceFreeListNodes(Heap* heap) { | |
| 5697 // For code space, using FreeListNode::IsFreeListNode is OK. | |
| 5698 HeapObjectIterator iter(heap->code_space()); | |
| 5699 for (HeapObject* obj = iter.next_object(); | |
| 5700 obj != NULL; | |
| 5701 obj = iter.next_object()) { | |
| 5702 if (FreeListNode::IsFreeListNode(obj)) obj->SetMark(); | |
| 5703 } | |
| 5704 } | |
| 5705 | |
| 5706 AssertNoAllocation no_alloc; | |
| 5707 }; | |
| 5708 | |
| 5709 | |
| 5710 class UnreachableObjectsFilter : public HeapObjectsFilter { | 5753 class UnreachableObjectsFilter : public HeapObjectsFilter { |
| 5711 public: | 5754 public: |
| 5712 UnreachableObjectsFilter() { | 5755 UnreachableObjectsFilter() { |
| 5713 MarkUnreachableObjects(); | 5756 MarkUnreachableObjects(); |
| 5714 } | 5757 } |
| 5715 | 5758 |
| 5716 bool SkipObject(HeapObject* object) { | 5759 bool SkipObject(HeapObject* object) { |
| 5717 if (object->IsMarked()) { | 5760 if (IntrusiveMarking::IsMarked(object)) { |
| 5718 object->ClearMark(); | 5761 IntrusiveMarking::ClearMark(object); |
| 5719 return true; | 5762 return true; |
| 5720 } else { | 5763 } else { |
| 5721 return false; | 5764 return false; |
| 5722 } | 5765 } |
| 5723 } | 5766 } |
| 5724 | 5767 |
| 5725 private: | 5768 private: |
| 5726 class UnmarkingVisitor : public ObjectVisitor { | 5769 class UnmarkingVisitor : public ObjectVisitor { |
| 5727 public: | 5770 public: |
| 5728 UnmarkingVisitor() : list_(10) {} | 5771 UnmarkingVisitor() : list_(10) {} |
| 5729 | 5772 |
| 5730 void VisitPointers(Object** start, Object** end) { | 5773 void VisitPointers(Object** start, Object** end) { |
| 5731 for (Object** p = start; p < end; p++) { | 5774 for (Object** p = start; p < end; p++) { |
| 5732 if (!(*p)->IsHeapObject()) continue; | 5775 if (!(*p)->IsHeapObject()) continue; |
| 5733 HeapObject* obj = HeapObject::cast(*p); | 5776 HeapObject* obj = HeapObject::cast(*p); |
| 5734 if (obj->IsMarked()) { | 5777 if (IntrusiveMarking::IsMarked(obj)) { |
| 5735 obj->ClearMark(); | 5778 IntrusiveMarking::ClearMark(obj); |
| 5736 list_.Add(obj); | 5779 list_.Add(obj); |
| 5737 } | 5780 } |
| 5738 } | 5781 } |
| 5739 } | 5782 } |
| 5740 | 5783 |
| 5741 bool can_process() { return !list_.is_empty(); } | 5784 bool can_process() { return !list_.is_empty(); } |
| 5742 | 5785 |
| 5743 void ProcessNext() { | 5786 void ProcessNext() { |
| 5744 HeapObject* obj = list_.RemoveLast(); | 5787 HeapObject* obj = list_.RemoveLast(); |
| 5745 obj->Iterate(this); | 5788 obj->Iterate(this); |
| 5746 } | 5789 } |
| 5747 | 5790 |
| 5748 private: | 5791 private: |
| 5749 List<HeapObject*> list_; | 5792 List<HeapObject*> list_; |
| 5750 }; | 5793 }; |
| 5751 | 5794 |
| 5752 void MarkUnreachableObjects() { | 5795 void MarkUnreachableObjects() { |
| 5753 HeapIterator iterator; | 5796 HeapIterator iterator; |
| 5754 for (HeapObject* obj = iterator.next(); | 5797 for (HeapObject* obj = iterator.next(); |
| 5755 obj != NULL; | 5798 obj != NULL; |
| 5756 obj = iterator.next()) { | 5799 obj = iterator.next()) { |
| 5757 obj->SetMark(); | 5800 IntrusiveMarking::SetMark(obj); |
| 5758 } | 5801 } |
| 5759 UnmarkingVisitor visitor; | 5802 UnmarkingVisitor visitor; |
| 5760 HEAP->IterateRoots(&visitor, VISIT_ALL); | 5803 HEAP->IterateRoots(&visitor, VISIT_ALL); |
| 5761 while (visitor.can_process()) | 5804 while (visitor.can_process()) |
| 5762 visitor.ProcessNext(); | 5805 visitor.ProcessNext(); |
| 5763 } | 5806 } |
| 5764 | 5807 |
| 5765 AssertNoAllocation no_alloc; | 5808 AssertNoAllocation no_alloc; |
| 5766 }; | 5809 }; |
| 5767 | 5810 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 5781 | 5824 |
| 5782 | 5825 |
| 5783 HeapIterator::~HeapIterator() { | 5826 HeapIterator::~HeapIterator() { |
| 5784 Shutdown(); | 5827 Shutdown(); |
| 5785 } | 5828 } |
| 5786 | 5829 |
| 5787 | 5830 |
| 5788 void HeapIterator::Init() { | 5831 void HeapIterator::Init() { |
| 5789 // Start the iteration. | 5832 // Start the iteration. |
| 5790 space_iterator_ = filtering_ == kNoFiltering ? new SpaceIterator : | 5833 space_iterator_ = filtering_ == kNoFiltering ? new SpaceIterator : |
| 5791 new SpaceIterator(MarkCompactCollector::SizeOfMarkedObject); | 5834 new SpaceIterator(Isolate::Current()->heap()-> |
| 5835 GcSafeSizeOfOldObjectFunction()); |
| 5792 switch (filtering_) { | 5836 switch (filtering_) { |
| 5793 case kFilterFreeListNodes: | 5837 case kFilterFreeListNodes: |
| 5794 filter_ = new FreeListNodesFilter; | 5838 // TODO(gc): Not handled. |
| 5795 break; | 5839 break; |
| 5796 case kFilterUnreachable: | 5840 case kFilterUnreachable: |
| 5797 filter_ = new UnreachableObjectsFilter; | 5841 filter_ = new UnreachableObjectsFilter; |
| 5798 break; | 5842 break; |
| 5799 default: | 5843 default: |
| 5800 break; | 5844 break; |
| 5801 } | 5845 } |
| 5802 object_iterator_ = space_iterator_->next(); | 5846 object_iterator_ = space_iterator_->next(); |
| 5803 } | 5847 } |
| 5804 | 5848 |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5921 MarkVisitor mark_visitor(this); | 5965 MarkVisitor mark_visitor(this); |
| 5922 MarkRecursively(root, &mark_visitor); | 5966 MarkRecursively(root, &mark_visitor); |
| 5923 | 5967 |
| 5924 UnmarkVisitor unmark_visitor(this); | 5968 UnmarkVisitor unmark_visitor(this); |
| 5925 UnmarkRecursively(root, &unmark_visitor); | 5969 UnmarkRecursively(root, &unmark_visitor); |
| 5926 | 5970 |
| 5927 ProcessResults(); | 5971 ProcessResults(); |
| 5928 } | 5972 } |
| 5929 | 5973 |
| 5930 | 5974 |
| 5975 static bool SafeIsGlobalContext(HeapObject* obj) { |
| 5976 return obj->map() == obj->GetHeap()->raw_unchecked_global_context_map(); |
| 5977 } |
| 5978 |
| 5979 |
| 5931 void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) { | 5980 void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) { |
| 5932 if (!(*p)->IsHeapObject()) return; | 5981 if (!(*p)->IsHeapObject()) return; |
| 5933 | 5982 |
| 5934 HeapObject* obj = HeapObject::cast(*p); | 5983 HeapObject* obj = HeapObject::cast(*p); |
| 5935 | 5984 |
| 5936 Object* map = obj->map(); | 5985 Object* map = obj->map(); |
| 5937 | 5986 |
| 5938 if (!map->IsHeapObject()) return; // visited before | 5987 if (!map->IsHeapObject()) return; // visited before |
| 5939 | 5988 |
| 5940 if (found_target_in_trace_) return; // stop if target found | 5989 if (found_target_in_trace_) return; // stop if target found |
| 5941 object_stack_.Add(obj); | 5990 object_stack_.Add(obj); |
| 5942 if (((search_target_ == kAnyGlobalObject) && obj->IsJSGlobalObject()) || | 5991 if (((search_target_ == kAnyGlobalObject) && obj->IsJSGlobalObject()) || |
| 5943 (obj == search_target_)) { | 5992 (obj == search_target_)) { |
| 5944 found_target_in_trace_ = true; | 5993 found_target_in_trace_ = true; |
| 5945 found_target_ = true; | 5994 found_target_ = true; |
| 5946 return; | 5995 return; |
| 5947 } | 5996 } |
| 5948 | 5997 |
| 5949 bool is_global_context = obj->IsGlobalContext(); | 5998 bool is_global_context = SafeIsGlobalContext(obj); |
| 5950 | 5999 |
| 5951 // not visited yet | 6000 // not visited yet |
| 5952 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map)); | 6001 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map)); |
| 5953 | 6002 |
| 5954 Address map_addr = map_p->address(); | 6003 Address map_addr = map_p->address(); |
| 5955 | 6004 |
| 5956 obj->set_map(reinterpret_cast<Map*>(map_addr + kMarkTag)); | 6005 obj->set_map(reinterpret_cast<Map*>(map_addr + kMarkTag)); |
| 5957 | 6006 |
| 5958 // Scan the object body. | 6007 // Scan the object body. |
| 5959 if (is_global_context && (visit_mode_ == VISIT_ONLY_STRONG)) { | 6008 if (is_global_context && (visit_mode_ == VISIT_ONLY_STRONG)) { |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6047 } | 6096 } |
| 6048 #endif | 6097 #endif |
| 6049 | 6098 |
| 6050 | 6099 |
| 6051 static intptr_t CountTotalHolesSize() { | 6100 static intptr_t CountTotalHolesSize() { |
| 6052 intptr_t holes_size = 0; | 6101 intptr_t holes_size = 0; |
| 6053 OldSpaces spaces; | 6102 OldSpaces spaces; |
| 6054 for (OldSpace* space = spaces.next(); | 6103 for (OldSpace* space = spaces.next(); |
| 6055 space != NULL; | 6104 space != NULL; |
| 6056 space = spaces.next()) { | 6105 space = spaces.next()) { |
| 6057 holes_size += space->Waste() + space->AvailableFree(); | 6106 holes_size += space->Waste() + space->Available(); |
| 6058 } | 6107 } |
| 6059 return holes_size; | 6108 return holes_size; |
| 6060 } | 6109 } |
| 6061 | 6110 |
| 6062 | 6111 |
| 6063 GCTracer::GCTracer(Heap* heap) | 6112 GCTracer::GCTracer(Heap* heap) |
| 6064 : start_time_(0.0), | 6113 : start_time_(0.0), |
| 6065 start_size_(0), | 6114 start_size_(0), |
| 6066 gc_count_(0), | 6115 gc_count_(0), |
| 6067 full_gc_count_(0), | 6116 full_gc_count_(0), |
| 6068 is_compacting_(false), | |
| 6069 marked_count_(0), | |
| 6070 allocated_since_last_gc_(0), | 6117 allocated_since_last_gc_(0), |
| 6071 spent_in_mutator_(0), | 6118 spent_in_mutator_(0), |
| 6072 promoted_objects_size_(0), | 6119 promoted_objects_size_(0), |
| 6073 heap_(heap) { | 6120 heap_(heap) { |
| 6074 // These two fields reflect the state of the previous full collection. | |
| 6075 // Set them before they are changed by the collector. | |
| 6076 previous_has_compacted_ = heap_->mark_compact_collector_.HasCompacted(); | |
| 6077 previous_marked_count_ = | |
| 6078 heap_->mark_compact_collector_.previous_marked_count(); | |
| 6079 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; | 6121 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; |
| 6080 start_time_ = OS::TimeCurrentMillis(); | 6122 start_time_ = OS::TimeCurrentMillis(); |
| 6081 start_size_ = heap_->SizeOfObjects(); | 6123 start_size_ = heap_->SizeOfObjects(); |
| 6082 | 6124 |
| 6083 for (int i = 0; i < Scope::kNumberOfScopes; i++) { | 6125 for (int i = 0; i < Scope::kNumberOfScopes; i++) { |
| 6084 scopes_[i] = 0; | 6126 scopes_[i] = 0; |
| 6085 } | 6127 } |
| 6086 | 6128 |
| 6087 in_free_list_or_wasted_before_gc_ = CountTotalHolesSize(); | 6129 in_free_list_or_wasted_before_gc_ = CountTotalHolesSize(); |
| 6088 | 6130 |
| 6089 allocated_since_last_gc_ = | 6131 allocated_since_last_gc_ = |
| 6090 heap_->SizeOfObjects() - heap_->alive_after_last_gc_; | 6132 heap_->SizeOfObjects() - heap_->alive_after_last_gc_; |
| 6091 | 6133 |
| 6092 if (heap_->last_gc_end_timestamp_ > 0) { | 6134 if (heap_->last_gc_end_timestamp_ > 0) { |
| 6093 spent_in_mutator_ = Max(start_time_ - heap_->last_gc_end_timestamp_, 0.0); | 6135 spent_in_mutator_ = Max(start_time_ - heap_->last_gc_end_timestamp_, 0.0); |
| 6094 } | 6136 } |
| 6137 |
| 6138 steps_count_ = heap_->incremental_marking()->steps_count(); |
| 6139 steps_took_ = heap_->incremental_marking()->steps_took(); |
| 6140 longest_step_ = heap_->incremental_marking()->longest_step(); |
| 6141 steps_count_since_last_gc_ = |
| 6142 heap_->incremental_marking()->steps_count_since_last_gc(); |
| 6143 steps_took_since_last_gc_ = |
| 6144 heap_->incremental_marking()->steps_took_since_last_gc(); |
| 6095 } | 6145 } |
| 6096 | 6146 |
| 6097 | 6147 |
| 6098 GCTracer::~GCTracer() { | 6148 GCTracer::~GCTracer() { |
| 6099 // Printf ONE line iff flag is set. | 6149 // Printf ONE line iff flag is set. |
| 6100 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; | 6150 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; |
| 6101 | 6151 |
| 6102 bool first_gc = (heap_->last_gc_end_timestamp_ == 0); | 6152 bool first_gc = (heap_->last_gc_end_timestamp_ == 0); |
| 6103 | 6153 |
| 6104 heap_->alive_after_last_gc_ = heap_->SizeOfObjects(); | 6154 heap_->alive_after_last_gc_ = heap_->SizeOfObjects(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 6119 | 6169 |
| 6120 if (!FLAG_trace_gc_nvp) { | 6170 if (!FLAG_trace_gc_nvp) { |
| 6121 int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]); | 6171 int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]); |
| 6122 | 6172 |
| 6123 PrintF("%s %.1f -> %.1f MB, ", | 6173 PrintF("%s %.1f -> %.1f MB, ", |
| 6124 CollectorString(), | 6174 CollectorString(), |
| 6125 static_cast<double>(start_size_) / MB, | 6175 static_cast<double>(start_size_) / MB, |
| 6126 SizeOfHeapObjects()); | 6176 SizeOfHeapObjects()); |
| 6127 | 6177 |
| 6128 if (external_time > 0) PrintF("%d / ", external_time); | 6178 if (external_time > 0) PrintF("%d / ", external_time); |
| 6129 PrintF("%d ms.\n", time); | 6179 PrintF("%d ms", time); |
| 6180 if (steps_count_ > 0) { |
| 6181 if (collector_ == SCAVENGER) { |
| 6182 PrintF(" (+ %d ms in %d steps since last GC)", |
| 6183 static_cast<int>(steps_took_since_last_gc_), |
| 6184 steps_count_since_last_gc_); |
| 6185 } else { |
| 6186 PrintF(" (+ %d ms in %d steps since start of marking, " |
| 6187 "biggest step %f ms)", |
| 6188 static_cast<int>(steps_took_), |
| 6189 steps_count_, |
| 6190 longest_step_); |
| 6191 } |
| 6192 } |
| 6193 PrintF(".\n"); |
| 6130 } else { | 6194 } else { |
| 6131 PrintF("pause=%d ", time); | 6195 PrintF("pause=%d ", time); |
| 6132 PrintF("mutator=%d ", | 6196 PrintF("mutator=%d ", |
| 6133 static_cast<int>(spent_in_mutator_)); | 6197 static_cast<int>(spent_in_mutator_)); |
| 6134 | 6198 |
| 6135 PrintF("gc="); | 6199 PrintF("gc="); |
| 6136 switch (collector_) { | 6200 switch (collector_) { |
| 6137 case SCAVENGER: | 6201 case SCAVENGER: |
| 6138 PrintF("s"); | 6202 PrintF("s"); |
| 6139 break; | 6203 break; |
| 6140 case MARK_COMPACTOR: | 6204 case MARK_COMPACTOR: |
| 6141 PrintF("%s", | 6205 PrintF("ms"); |
| 6142 heap_->mark_compact_collector_.HasCompacted() ? "mc" : "ms"); | |
| 6143 break; | 6206 break; |
| 6144 default: | 6207 default: |
| 6145 UNREACHABLE(); | 6208 UNREACHABLE(); |
| 6146 } | 6209 } |
| 6147 PrintF(" "); | 6210 PrintF(" "); |
| 6148 | 6211 |
| 6149 PrintF("external=%d ", static_cast<int>(scopes_[Scope::EXTERNAL])); | 6212 PrintF("external=%d ", static_cast<int>(scopes_[Scope::EXTERNAL])); |
| 6150 PrintF("mark=%d ", static_cast<int>(scopes_[Scope::MC_MARK])); | 6213 PrintF("mark=%d ", static_cast<int>(scopes_[Scope::MC_MARK])); |
| 6151 PrintF("sweep=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP])); | 6214 PrintF("sweep=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP])); |
| 6152 PrintF("sweepns=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP_NEWSPACE])); | 6215 PrintF("sweepns=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP_NEWSPACE])); |
| 6153 PrintF("compact=%d ", static_cast<int>(scopes_[Scope::MC_COMPACT])); | 6216 PrintF("compact=%d ", static_cast<int>(scopes_[Scope::MC_COMPACT])); |
| 6154 | 6217 |
| 6155 PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_size_); | 6218 PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_size_); |
| 6156 PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects()); | 6219 PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects()); |
| 6157 PrintF("holes_size_before=%" V8_PTR_PREFIX "d ", | 6220 PrintF("holes_size_before=%" V8_PTR_PREFIX "d ", |
| 6158 in_free_list_or_wasted_before_gc_); | 6221 in_free_list_or_wasted_before_gc_); |
| 6159 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize()); | 6222 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize()); |
| 6160 | 6223 |
| 6161 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_); | 6224 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_); |
| 6162 PrintF("promoted=%" V8_PTR_PREFIX "d ", promoted_objects_size_); | 6225 PrintF("promoted=%" V8_PTR_PREFIX "d ", promoted_objects_size_); |
| 6163 | 6226 |
| 6227 if (collector_ == SCAVENGER) { |
| 6228 PrintF("stepscount=%d ", steps_count_since_last_gc_); |
| 6229 PrintF("stepstook=%d ", static_cast<int>(steps_took_since_last_gc_)); |
| 6230 } else { |
| 6231 PrintF("stepscount=%d ", steps_count_); |
| 6232 PrintF("stepstook=%d ", static_cast<int>(steps_took_)); |
| 6233 } |
| 6234 |
| 6164 PrintF("\n"); | 6235 PrintF("\n"); |
| 6165 } | 6236 } |
| 6166 | 6237 |
| 6167 heap_->PrintShortHeapStatistics(); | 6238 heap_->PrintShortHeapStatistics(); |
| 6168 } | 6239 } |
| 6169 | 6240 |
| 6170 | 6241 |
| 6171 const char* GCTracer::CollectorString() { | 6242 const char* GCTracer::CollectorString() { |
| 6172 switch (collector_) { | 6243 switch (collector_) { |
| 6173 case SCAVENGER: | 6244 case SCAVENGER: |
| 6174 return "Scavenge"; | 6245 return "Scavenge"; |
| 6175 case MARK_COMPACTOR: | 6246 case MARK_COMPACTOR: |
| 6176 return heap_->mark_compact_collector_.HasCompacted() ? "Mark-compact" | 6247 return "Mark-sweep"; |
| 6177 : "Mark-sweep"; | |
| 6178 } | 6248 } |
| 6179 return "Unknown GC"; | 6249 return "Unknown GC"; |
| 6180 } | 6250 } |
| 6181 | 6251 |
| 6182 | 6252 |
| 6183 int KeyedLookupCache::Hash(Map* map, String* name) { | 6253 int KeyedLookupCache::Hash(Map* map, String* name) { |
| 6184 // Uses only lower 32 bits if pointers are larger. | 6254 // Uses only lower 32 bits if pointers are larger. |
| 6185 uintptr_t addr_hash = | 6255 uintptr_t addr_hash = |
| 6186 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift; | 6256 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift; |
| 6187 return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask); | 6257 return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6274 Verify(); | 6344 Verify(); |
| 6275 } | 6345 } |
| 6276 | 6346 |
| 6277 | 6347 |
| 6278 void ExternalStringTable::TearDown() { | 6348 void ExternalStringTable::TearDown() { |
| 6279 new_space_strings_.Free(); | 6349 new_space_strings_.Free(); |
| 6280 old_space_strings_.Free(); | 6350 old_space_strings_.Free(); |
| 6281 } | 6351 } |
| 6282 | 6352 |
| 6283 | 6353 |
| 6354 void Heap::QueueMemoryChunkForFree(MemoryChunk* chunk) { |
| 6355 chunk->set_next_chunk(chunks_queued_for_free_); |
| 6356 chunks_queued_for_free_ = chunk; |
| 6357 } |
| 6358 |
| 6359 |
| 6360 void Heap::FreeQueuedChunks() { |
| 6361 if (chunks_queued_for_free_ == NULL) return; |
| 6362 MemoryChunk* next; |
| 6363 MemoryChunk* chunk; |
| 6364 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) { |
| 6365 next = chunk->next_chunk(); |
| 6366 chunk->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED); |
| 6367 |
| 6368 if (chunk->owner()->identity() == LO_SPACE) { |
| 6369 // StoreBuffer::Filter relies on MemoryChunk::FromAnyPointerAddress. |
| 6370 // If FromAnyPointerAddress encounters a slot that belongs to a large |
| 6371 // chunk queued for deletion it will fail to find the chunk because |
| 6372 // it try to perform a search in the list of pages owned by of the large |
| 6373 // object space and queued chunks were detached from that list. |
| 6374 // To work around this we split large chunk into normal kPageSize aligned |
| 6375 // pieces and initialize owner field and flags of every piece. |
| 6376 // If FromAnyPointerAddress encounteres a slot that belongs to one of |
| 6377 // these smaller pieces it will treat it as a slot on a normal Page. |
| 6378 MemoryChunk* inner = MemoryChunk::FromAddress( |
| 6379 chunk->address() + Page::kPageSize); |
| 6380 MemoryChunk* inner_last = MemoryChunk::FromAddress( |
| 6381 chunk->address() + chunk->size() - 1); |
| 6382 while (inner <= inner_last) { |
| 6383 // Size of a large chunk is always a multiple of |
| 6384 // OS::AllocationAlignment() so there is always |
| 6385 // enough space for a fake MemoryChunk header. |
| 6386 inner->set_owner(lo_space()); |
| 6387 inner->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED); |
| 6388 inner = MemoryChunk::FromAddress( |
| 6389 inner->address() + Page::kPageSize); |
| 6390 } |
| 6391 } |
| 6392 } |
| 6393 isolate_->heap()->store_buffer()->Compact(); |
| 6394 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED); |
| 6395 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) { |
| 6396 next = chunk->next_chunk(); |
| 6397 isolate_->memory_allocator()->Free(chunk); |
| 6398 } |
| 6399 chunks_queued_for_free_ = NULL; |
| 6400 } |
| 6401 |
| 6284 } } // namespace v8::internal | 6402 } } // namespace v8::internal |
| OLD | NEW |