| OLD | NEW |
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 #include "snapshot.h" | 42 #include "snapshot.h" |
| 43 #include "v8threads.h" | 43 #include "v8threads.h" |
| 44 #if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP | 44 #if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP |
| 45 #include "regexp-macro-assembler.h" | 45 #include "regexp-macro-assembler.h" |
| 46 #include "arm/regexp-macro-assembler-arm.h" | 46 #include "arm/regexp-macro-assembler-arm.h" |
| 47 #endif | 47 #endif |
| 48 | 48 |
| 49 namespace v8 { | 49 namespace v8 { |
| 50 namespace internal { | 50 namespace internal { |
| 51 | 51 |
| 52 | 52 // A queue of pointers and maps of to-be-promoted objects during a |
| 53 String* Heap::hidden_symbol_; | 53 // scavenge collection. |
| 54 Object* Heap::roots_[Heap::kRootListLength]; | 54 class PromotionQueue { |
| 55 | 55 public: |
| 56 | 56 void Initialize(Address start_address) { |
| 57 NewSpace Heap::new_space_; | 57 front_ = rear_ = reinterpret_cast<HeapObject**>(start_address); |
| 58 OldSpace* Heap::old_pointer_space_ = NULL; | 58 } |
| 59 OldSpace* Heap::old_data_space_ = NULL; | 59 |
| 60 OldSpace* Heap::code_space_ = NULL; | 60 bool is_empty() { return front_ <= rear_; } |
| 61 MapSpace* Heap::map_space_ = NULL; | 61 |
| 62 CellSpace* Heap::cell_space_ = NULL; | 62 void insert(HeapObject* object, Map* map) { |
| 63 LargeObjectSpace* Heap::lo_space_ = NULL; | 63 *(--rear_) = object; |
| 64 *(--rear_) = map; |
| 65 // Assert no overflow into live objects. |
| 66 ASSERT(reinterpret_cast<Address>(rear_) >= Heap::new_space()->top()); |
| 67 } |
| 68 |
| 69 void remove(HeapObject** object, Map** map) { |
| 70 *object = *(--front_); |
| 71 *map = Map::cast(*(--front_)); |
| 72 // Assert no underflow. |
| 73 ASSERT(front_ >= rear_); |
| 74 } |
| 75 |
| 76 private: |
| 77 // The front of the queue is higher in memory than the rear. |
| 78 HeapObject** front_; |
| 79 HeapObject** rear_; |
| 80 }; |
| 81 |
| 82 class HeapPrivateData { |
| 83 public: |
| 84 // Shared state read by the scavenge collector and set by ScavengeObject. |
| 85 PromotionQueue promotion_queue_; |
| 86 int number_idle_notifications_; |
| 87 int last_gc_count_; |
| 88 void* paged_rset_histogram_; |
| 89 |
| 90 #ifdef DEBUG |
| 91 bool search_for_any_global_; |
| 92 Object* search_target_; |
| 93 bool found_target_; |
| 94 List<Object*> object_stack_; |
| 95 |
| 96 void MarkRootObjectRecursively(Object** root); |
| 97 #endif |
| 98 |
| 99 HeapPrivateData() |
| 100 :number_idle_notifications_(0), |
| 101 last_gc_count_(0), |
| 102 #ifdef DEBUG |
| 103 search_target_(NULL), |
| 104 object_stack_(20), |
| 105 search_for_any_global_(false), |
| 106 found_target_(NULL), |
| 107 #endif |
| 108 paged_rset_histogram_(NULL) { |
| 109 } |
| 110 |
| 111 DISALLOW_COPY_AND_ASSIGN(HeapPrivateData); |
| 112 }; |
| 64 | 113 |
| 65 static const int kMinimumPromotionLimit = 2*MB; | 114 static const int kMinimumPromotionLimit = 2*MB; |
| 66 static const int kMinimumAllocationLimit = 8*MB; | 115 static const int kMinimumAllocationLimit = 8*MB; |
| 67 | 116 |
| 68 int Heap::old_gen_promotion_limit_ = kMinimumPromotionLimit; | |
| 69 int Heap::old_gen_allocation_limit_ = kMinimumAllocationLimit; | |
| 70 | |
| 71 int Heap::old_gen_exhausted_ = false; | |
| 72 | |
| 73 int Heap::amount_of_external_allocated_memory_ = 0; | |
| 74 int Heap::amount_of_external_allocated_memory_at_last_global_gc_ = 0; | |
| 75 | |
| 76 // semispace_size_ should be a power of 2 and old_generation_size_ should be | 117 // semispace_size_ should be a power of 2 and old_generation_size_ should be |
| 77 // a multiple of Page::kPageSize. | 118 // a multiple of Page::kPageSize. |
| 78 #if defined(ANDROID) | 119 #if defined(ANDROID) |
| 79 int Heap::max_semispace_size_ = 512*KB; | 120 static const int kMaxSemispaceSize = 512*KB; |
| 80 int Heap::max_old_generation_size_ = 128*MB; | 121 static const int kMaxOldGenerationSize = 128*MB; |
| 81 int Heap::initial_semispace_size_ = 128*KB; | 122 static const int kInitialSemispaceSize = 128*KB; |
| 82 size_t Heap::code_range_size_ = 0; | 123 static const size_t kCodeRangeSize = 0; |
| 83 #elif defined(V8_TARGET_ARCH_X64) | 124 #elif defined(V8_TARGET_ARCH_X64) |
| 84 int Heap::max_semispace_size_ = 16*MB; | 125 static const int kMaxSemispaceSize = 16*MB; |
| 85 int Heap::max_old_generation_size_ = 1*GB; | 126 static const int kMaxOldGenerationSize = 1*GB; |
| 86 int Heap::initial_semispace_size_ = 1*MB; | 127 static const int kInitialSemispaceSize = 1*MB; |
| 87 size_t Heap::code_range_size_ = 512*MB; | 128 static const size_t kCodeRangeSize = 512*MB; |
| 88 #else | 129 #else |
| 89 int Heap::max_semispace_size_ = 8*MB; | 130 static const int kMaxSemispaceSize = 8*MB; |
| 90 int Heap::max_old_generation_size_ = 512*MB; | 131 static const int kMaxOldGenerationSize = 512*MB; |
| 91 int Heap::initial_semispace_size_ = 512*KB; | 132 static const int kInitialSemispaceSize = 512*KB; |
| 92 size_t Heap::code_range_size_ = 0; | 133 static const size_t kCodeRangeSize = 0; |
| 93 #endif | 134 #endif |
| 94 | 135 |
| 95 // The snapshot semispace size will be the default semispace size if | 136 HeapData::HeapData() |
| 96 // snapshotting is used and will be the requested semispace size as | 137 :hidden_symbol_(NULL), |
| 97 // set up by ConfigureHeap otherwise. | 138 old_pointer_space_(NULL), |
| 98 int Heap::reserved_semispace_size_ = Heap::max_semispace_size_; | 139 old_data_space_(NULL), |
| 99 | 140 code_space_(NULL), |
| 100 GCCallback Heap::global_gc_prologue_callback_ = NULL; | 141 map_space_(NULL), |
| 101 GCCallback Heap::global_gc_epilogue_callback_ = NULL; | 142 cell_space_(NULL), |
| 102 | 143 lo_space_(NULL), |
| 103 // Variables set based on semispace_size_ and old_generation_size_ in | 144 global_gc_prologue_callback_(NULL), |
| 104 // ConfigureHeap. | 145 global_gc_epilogue_callback_(NULL), |
| 105 | 146 old_gen_promotion_limit_(kMinimumPromotionLimit), |
| 106 // Will be 4 * reserved_semispace_size_ to ensure that young | 147 old_gen_allocation_limit_(kMinimumAllocationLimit), |
| 107 // generation can be aligned to its size. | 148 old_gen_exhausted_(false), |
| 108 int Heap::survived_since_last_expansion_ = 0; | 149 amount_of_external_allocated_memory_(0), |
| 109 int Heap::external_allocation_limit_ = 0; | 150 amount_of_external_allocated_memory_at_last_global_gc_(0), |
| 110 | 151 heap_private_data_(*new HeapPrivateData()), |
| 111 Heap::HeapState Heap::gc_state_ = NOT_IN_GC; | 152 |
| 112 | 153 max_semispace_size_(kMaxSemispaceSize), |
| 113 int Heap::mc_count_ = 0; | 154 max_old_generation_size_(kMaxOldGenerationSize), |
| 114 int Heap::gc_count_ = 0; | 155 initial_semispace_size_(kInitialSemispaceSize), |
| 115 | 156 code_range_size_(kCodeRangeSize), |
| 116 int Heap::always_allocate_scope_depth_ = 0; | 157 |
| 117 int Heap::linear_allocation_scope_depth_ = 0; | 158 // The snapshot semispace size will be the default semispace size if |
| 118 bool Heap::context_disposed_pending_ = false; | 159 // snapshotting is used and will be the requested semispace size as |
| 160 // set up by ConfigureHeap otherwise. |
| 161 reserved_semispace_size_(kMaxSemispaceSize), |
| 162 |
| 163 // Variables set based on semispace_size_ and old_generation_size_ in |
| 164 // ConfigureHeap. |
| 165 |
| 166 // Will be 4 * reserved_semispace_size_ to ensure that young |
| 167 // generation can be aligned to its size. |
| 168 |
| 169 survived_since_last_expansion_(0), |
| 170 external_allocation_limit_(0), |
| 171 gc_state_(NOT_IN_GC), |
| 172 mc_count_(0), |
| 173 gc_count_(0), |
| 174 always_allocate_scope_depth_(0), |
| 175 linear_allocation_scope_depth_(0), |
| 176 context_disposed_pending_(false), |
| 119 | 177 |
| 120 #ifdef DEBUG | 178 #ifdef DEBUG |
| 121 bool Heap::allocation_allowed_ = true; | 179 allocation_allowed_(true), |
| 122 | 180 allocation_timeout_(0), |
| 123 int Heap::allocation_timeout_ = 0; | 181 disallow_allocation_failure_(false), |
| 124 bool Heap::disallow_allocation_failure_ = false; | |
| 125 #endif // DEBUG | 182 #endif // DEBUG |
| 126 | 183 heap_configured_(false) { |
| 184 for (int i = 0; i < kRootListLength; ++i) { |
| 185 roots_[i] = NULL; |
| 186 } |
| 187 } |
| 188 |
| 189 HeapData::~HeapData() { |
| 190 delete &heap_private_data_; |
| 191 } |
| 127 | 192 |
| 128 int Heap::Capacity() { | 193 int Heap::Capacity() { |
| 129 if (!HasBeenSetup()) return 0; | 194 if (!HasBeenSetup()) return 0; |
| 130 | 195 HeapData& heap_data = v8_context()->heap_data_; |
| 131 return new_space_.Capacity() + | 196 return heap_data.new_space_.Capacity() + |
| 132 old_pointer_space_->Capacity() + | 197 heap_data.old_pointer_space_->Capacity() + |
| 133 old_data_space_->Capacity() + | 198 heap_data.old_data_space_->Capacity() + |
| 134 code_space_->Capacity() + | 199 heap_data.code_space_->Capacity() + |
| 135 map_space_->Capacity() + | 200 heap_data.map_space_->Capacity() + |
| 136 cell_space_->Capacity(); | 201 heap_data.cell_space_->Capacity(); |
| 137 } | 202 } |
| 138 | 203 |
| 139 | 204 |
| 140 int Heap::CommittedMemory() { | 205 int Heap::CommittedMemory() { |
| 141 if (!HasBeenSetup()) return 0; | 206 if (!HasBeenSetup()) return 0; |
| 142 | 207 |
| 143 return new_space_.CommittedMemory() + | 208 HeapData& heap_data = v8_context()->heap_data_; |
| 144 old_pointer_space_->CommittedMemory() + | 209 return heap_data.new_space_.CommittedMemory() + |
| 145 old_data_space_->CommittedMemory() + | 210 heap_data.old_pointer_space_->CommittedMemory() + |
| 146 code_space_->CommittedMemory() + | 211 heap_data.old_data_space_->CommittedMemory() + |
| 147 map_space_->CommittedMemory() + | 212 heap_data.code_space_->CommittedMemory() + |
| 148 cell_space_->CommittedMemory() + | 213 heap_data.map_space_->CommittedMemory() + |
| 149 lo_space_->Size(); | 214 heap_data.cell_space_->CommittedMemory() + |
| 215 heap_data.lo_space_->Size(); |
| 150 } | 216 } |
| 151 | 217 |
| 152 | 218 |
| 153 int Heap::Available() { | 219 int Heap::Available() { |
| 154 if (!HasBeenSetup()) return 0; | 220 if (!HasBeenSetup()) return 0; |
| 155 | 221 |
| 156 return new_space_.Available() + | 222 HeapData& heap_data = v8_context()->heap_data_; |
| 157 old_pointer_space_->Available() + | 223 return heap_data.new_space_.Available() + |
| 158 old_data_space_->Available() + | 224 heap_data.old_pointer_space_->Available() + |
| 159 code_space_->Available() + | 225 heap_data.old_data_space_->Available() + |
| 160 map_space_->Available() + | 226 heap_data.code_space_->Available() + |
| 161 cell_space_->Available(); | 227 heap_data.map_space_->Available() + |
| 228 heap_data.cell_space_->Available(); |
| 162 } | 229 } |
| 163 | 230 |
| 164 | 231 |
| 165 bool Heap::HasBeenSetup() { | 232 bool Heap::HasBeenSetup() { |
| 166 return old_pointer_space_ != NULL && | 233 HeapData& heap_data = v8_context()->heap_data_; |
| 167 old_data_space_ != NULL && | 234 return heap_data.old_pointer_space_ != NULL && |
| 168 code_space_ != NULL && | 235 heap_data.old_data_space_ != NULL && |
| 169 map_space_ != NULL && | 236 heap_data.code_space_ != NULL && |
| 170 cell_space_ != NULL && | 237 heap_data.map_space_ != NULL && |
| 171 lo_space_ != NULL; | 238 heap_data.cell_space_ != NULL && |
| 239 heap_data.lo_space_ != NULL; |
| 172 } | 240 } |
| 173 | 241 |
| 174 | 242 |
| 175 GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space) { | 243 GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space) { |
| 176 // Is global GC requested? | 244 // Is global GC requested? |
| 177 if (space != NEW_SPACE || FLAG_gc_global) { | 245 if (space != NEW_SPACE || FLAG_gc_global) { |
| 178 Counters::gc_compactor_caused_by_request.Increment(); | 246 INC_COUNTER(gc_compactor_caused_by_request); |
| 179 return MARK_COMPACTOR; | 247 return MARK_COMPACTOR; |
| 180 } | 248 } |
| 181 | 249 |
| 182 // Is enough data promoted to justify a global GC? | 250 // Is enough data promoted to justify a global GC? |
| 183 if (OldGenerationPromotionLimitReached()) { | 251 if (OldGenerationPromotionLimitReached()) { |
| 184 Counters::gc_compactor_caused_by_promoted_data.Increment(); | 252 INC_COUNTER(gc_compactor_caused_by_promoted_data); |
| 185 return MARK_COMPACTOR; | 253 return MARK_COMPACTOR; |
| 186 } | 254 } |
| 187 | 255 |
| 188 // Have allocation in OLD and LO failed? | 256 // Have allocation in OLD and LO failed? |
| 189 if (old_gen_exhausted_) { | 257 if (v8_context()->heap_data_.old_gen_exhausted_) { |
| 190 Counters::gc_compactor_caused_by_oldspace_exhaustion.Increment(); | 258 INC_COUNTER(gc_compactor_caused_by_oldspace_exhaustion); |
| 191 return MARK_COMPACTOR; | 259 return MARK_COMPACTOR; |
| 192 } | 260 } |
| 193 | 261 |
| 194 // Is there enough space left in OLD to guarantee that a scavenge can | 262 // Is there enough space left in OLD to guarantee that a scavenge can |
| 195 // succeed? | 263 // succeed? |
| 196 // | 264 // |
| 197 // Note that MemoryAllocator->MaxAvailable() undercounts the memory available | 265 // Note that MemoryAllocator->MaxAvailable() undercounts the memory available |
| 198 // for object promotion. It counts only the bytes that the memory | 266 // for object promotion. It counts only the bytes that the memory |
| 199 // allocator has not yet allocated from the OS and assigned to any space, | 267 // allocator has not yet allocated from the OS and assigned to any space, |
| 200 // and does not count available bytes already in the old space or code | 268 // and does not count available bytes already in the old space or code |
| 201 // space. Undercounting is safe---we may get an unrequested full GC when | 269 // space. Undercounting is safe---we may get an unrequested full GC when |
| 202 // a scavenge would have succeeded. | 270 // a scavenge would have succeeded. |
| 203 if (MemoryAllocator::MaxAvailable() <= new_space_.Size()) { | 271 if (MemoryAllocator::MaxAvailable() <= |
| 204 Counters::gc_compactor_caused_by_oldspace_exhaustion.Increment(); | 272 v8_context()->heap_data_.new_space_.Size() |
| 273 ) { |
| 274 INC_COUNTER(gc_compactor_caused_by_oldspace_exhaustion); |
| 205 return MARK_COMPACTOR; | 275 return MARK_COMPACTOR; |
| 206 } | 276 } |
| 207 | 277 |
| 208 // Default | 278 // Default |
| 209 return SCAVENGER; | 279 return SCAVENGER; |
| 210 } | 280 } |
| 211 | 281 |
| 212 | 282 |
| 213 // TODO(1238405): Combine the infrastructure for --heap-stats and | 283 // TODO(1238405): Combine the infrastructure for --heap-stats and |
| 214 // --log-gc to avoid the complicated preprocessor and flag testing. | 284 // --log-gc to avoid the complicated preprocessor and flag testing. |
| 215 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) | 285 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
| 216 void Heap::ReportStatisticsBeforeGC() { | 286 void Heap::ReportStatisticsBeforeGC() { |
| 287 HeapData& heap_data = v8_context()->heap_data_; |
| 217 // Heap::ReportHeapStatistics will also log NewSpace statistics when | 288 // Heap::ReportHeapStatistics will also log NewSpace statistics when |
| 218 // compiled with ENABLE_LOGGING_AND_PROFILING and --log-gc is set. The | 289 // compiled with ENABLE_LOGGING_AND_PROFILING and --log-gc is set. The |
| 219 // following logic is used to avoid double logging. | 290 // following logic is used to avoid double logging. |
| 220 #if defined(DEBUG) && defined(ENABLE_LOGGING_AND_PROFILING) | 291 #if defined(DEBUG) && defined(ENABLE_LOGGING_AND_PROFILING) |
| 221 if (FLAG_heap_stats || FLAG_log_gc) new_space_.CollectStatistics(); | 292 if (FLAG_heap_stats || FLAG_log_gc) heap_data.new_space_.CollectStatistics(); |
| 222 if (FLAG_heap_stats) { | 293 if (FLAG_heap_stats) { |
| 223 ReportHeapStatistics("Before GC"); | 294 ReportHeapStatistics("Before GC"); |
| 224 } else if (FLAG_log_gc) { | 295 } else if (FLAG_log_gc) { |
| 225 new_space_.ReportStatistics(); | 296 heap_data.new_space_.ReportStatistics(); |
| 226 } | 297 } |
| 227 if (FLAG_heap_stats || FLAG_log_gc) new_space_.ClearHistograms(); | 298 if (FLAG_heap_stats || FLAG_log_gc) heap_data.new_space_.ClearHistograms(); |
| 228 #elif defined(DEBUG) | 299 #elif defined(DEBUG) |
| 229 if (FLAG_heap_stats) { | 300 if (FLAG_heap_stats) { |
| 230 new_space_.CollectStatistics(); | 301 heap_data.new_space_.CollectStatistics(); |
| 231 ReportHeapStatistics("Before GC"); | 302 ReportHeapStatistics("Before GC"); |
| 232 new_space_.ClearHistograms(); | 303 heap_data.new_space_.ClearHistograms(); |
| 233 } | 304 } |
| 234 #elif defined(ENABLE_LOGGING_AND_PROFILING) | 305 #elif defined(ENABLE_LOGGING_AND_PROFILING) |
| 235 if (FLAG_log_gc) { | 306 if (FLAG_log_gc) { |
| 236 new_space_.CollectStatistics(); | 307 heap_data.new_space_.CollectStatistics(); |
| 237 new_space_.ReportStatistics(); | 308 heap_data.new_space_.ReportStatistics(); |
| 238 new_space_.ClearHistograms(); | 309 heap_data.new_space_.ClearHistograms(); |
| 239 } | 310 } |
| 240 #endif | 311 #endif |
| 241 } | 312 } |
| 242 | 313 |
| 243 | 314 |
| 244 #if defined(ENABLE_LOGGING_AND_PROFILING) | 315 #if defined(ENABLE_LOGGING_AND_PROFILING) |
| 245 void Heap::PrintShortHeapStatistics() { | 316 void Heap::PrintShortHeapStatistics() { |
| 246 if (!FLAG_trace_gc_verbose) return; | 317 if (!FLAG_trace_gc_verbose) return; |
| 318 HeapData& heap_data = v8_context()->heap_data_; |
| 247 PrintF("Memory allocator, used: %8d, available: %8d\n", | 319 PrintF("Memory allocator, used: %8d, available: %8d\n", |
| 248 MemoryAllocator::Size(), | 320 MemoryAllocator::Size(), |
| 249 MemoryAllocator::Available()); | 321 MemoryAllocator::Available()); |
| 250 PrintF("New space, used: %8d, available: %8d\n", | 322 PrintF("New space, used: %8d, available: %8d\n", |
| 251 Heap::new_space_.Size(), | 323 heap_data.new_space_.Size(), |
| 252 new_space_.Available()); | 324 heap_data.new_space_.Available()); |
| 253 PrintF("Old pointers, used: %8d, available: %8d, waste: %8d\n", | 325 PrintF("Old pointers, used: %8d, available: %8d, waste: %8d\n", |
| 254 old_pointer_space_->Size(), | 326 heap_data.old_pointer_space_->Size(), |
| 255 old_pointer_space_->Available(), | 327 heap_data.old_pointer_space_->Available(), |
| 256 old_pointer_space_->Waste()); | 328 heap_data.old_pointer_space_->Waste()); |
| 257 PrintF("Old data space, used: %8d, available: %8d, waste: %8d\n", | 329 PrintF("Old data space, used: %8d, available: %8d, waste: %8d\n", |
| 258 old_data_space_->Size(), | 330 heap_data.old_data_space_->Size(), |
| 259 old_data_space_->Available(), | 331 heap_data.old_data_space_->Available(), |
| 260 old_data_space_->Waste()); | 332 heap_data.old_data_space_->Waste()); |
| 261 PrintF("Code space, used: %8d, available: %8d, waste: %8d\n", | 333 PrintF("Code space, used: %8d, available: %8d, waste: %8d\n", |
| 262 code_space_->Size(), | 334 heap_data.code_space_->Size(), |
| 263 code_space_->Available(), | 335 heap_data.code_space_->Available(), |
| 264 code_space_->Waste()); | 336 heap_data.code_space_->Waste()); |
| 265 PrintF("Map space, used: %8d, available: %8d, waste: %8d\n", | 337 PrintF("Map space, used: %8d, available: %8d, waste: %8d\n", |
| 266 map_space_->Size(), | 338 heap_data.map_space_->Size(), |
| 267 map_space_->Available(), | 339 heap_data.map_space_->Available(), |
| 268 map_space_->Waste()); | 340 heap_data.map_space_->Waste()); |
| 269 PrintF("Cell space, used: %8d, available: %8d, waste: %8d\n", | 341 PrintF("Cell space, used: %8d, available: %8d, waste: %8d\n", |
| 270 cell_space_->Size(), | 342 heap_data.cell_space_->Size(), |
| 271 cell_space_->Available(), | 343 heap_data.cell_space_->Available(), |
| 272 cell_space_->Waste()); | 344 heap_data.cell_space_->Waste()); |
| 273 PrintF("Large object space, used: %8d, avaialble: %8d\n", | 345 PrintF("Large object space, used: %8d, avaialble: %8d\n", |
| 274 lo_space_->Size(), | 346 heap_data.lo_space_->Size(), |
| 275 lo_space_->Available()); | 347 heap_data.lo_space_->Available()); |
| 276 } | 348 } |
| 277 #endif | 349 #endif |
| 278 | 350 |
| 279 | 351 |
| 280 // TODO(1238405): Combine the infrastructure for --heap-stats and | 352 // TODO(1238405): Combine the infrastructure for --heap-stats and |
| 281 // --log-gc to avoid the complicated preprocessor and flag testing. | 353 // --log-gc to avoid the complicated preprocessor and flag testing. |
| 282 void Heap::ReportStatisticsAfterGC() { | 354 void Heap::ReportStatisticsAfterGC() { |
| 355 HeapData& heap_data = v8_context()->heap_data_; |
| 283 // Similar to the before GC, we use some complicated logic to ensure that | 356 // Similar to the before GC, we use some complicated logic to ensure that |
| 284 // NewSpace statistics are logged exactly once when --log-gc is turned on. | 357 // NewSpace statistics are logged exactly once when --log-gc is turned on. |
| 285 #if defined(DEBUG) && defined(ENABLE_LOGGING_AND_PROFILING) | 358 #if defined(DEBUG) && defined(ENABLE_LOGGING_AND_PROFILING) |
| 286 if (FLAG_heap_stats) { | 359 if (FLAG_heap_stats) { |
| 287 new_space_.CollectStatistics(); | 360 heap_data.new_space_.CollectStatistics(); |
| 288 ReportHeapStatistics("After GC"); | 361 ReportHeapStatistics("After GC"); |
| 289 } else if (FLAG_log_gc) { | 362 } else if (FLAG_log_gc) { |
| 290 new_space_.ReportStatistics(); | 363 heap_data.new_space_.ReportStatistics(); |
| 291 } | 364 } |
| 292 #elif defined(DEBUG) | 365 #elif defined(DEBUG) |
| 293 if (FLAG_heap_stats) ReportHeapStatistics("After GC"); | 366 if (FLAG_heap_stats) ReportHeapStatistics("After GC"); |
| 294 #elif defined(ENABLE_LOGGING_AND_PROFILING) | 367 #elif defined(ENABLE_LOGGING_AND_PROFILING) |
| 295 if (FLAG_log_gc) new_space_.ReportStatistics(); | 368 if (FLAG_log_gc) heap_data.new_space_.ReportStatistics(); |
| 296 #endif | 369 #endif |
| 297 } | 370 } |
| 298 #endif // defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) | 371 #endif // defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
| 299 | 372 |
| 300 | 373 |
| 301 void Heap::GarbageCollectionPrologue() { | 374 void Heap::GarbageCollectionPrologue() { |
| 302 TranscendentalCache::Clear(); | 375 TranscendentalCache::Clear(); |
| 303 gc_count_++; | 376 HeapData& heap_data = v8_context()->heap_data_; |
| 377 heap_data.gc_count_++; |
| 304 #ifdef DEBUG | 378 #ifdef DEBUG |
| 305 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC); | 379 ASSERT(heap_data.allocation_allowed_ && heap_data.gc_state_ == NOT_IN_GC); |
| 306 allow_allocation(false); | 380 allow_allocation(false); |
| 307 | 381 |
| 308 if (FLAG_verify_heap) { | 382 if (FLAG_verify_heap) { |
| 309 Verify(); | 383 Verify(); |
| 310 } | 384 } |
| 311 | 385 |
| 312 if (FLAG_gc_verbose) Print(); | 386 if (FLAG_gc_verbose) Print(); |
| 313 | 387 |
| 314 if (FLAG_print_rset) { | 388 if (FLAG_print_rset) { |
| 315 // Not all spaces have remembered set bits that we care about. | 389 // Not all spaces have remembered set bits that we care about. |
| 316 old_pointer_space_->PrintRSet(); | 390 heap_data.old_pointer_space_->PrintRSet(); |
| 317 map_space_->PrintRSet(); | 391 heap_data.map_space_->PrintRSet(); |
| 318 lo_space_->PrintRSet(); | 392 heap_data.lo_space_->PrintRSet(); |
| 319 } | 393 } |
| 320 #endif | 394 #endif |
| 321 | 395 |
| 322 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) | 396 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
| 323 ReportStatisticsBeforeGC(); | 397 ReportStatisticsBeforeGC(); |
| 324 #endif | 398 #endif |
| 325 } | 399 } |
| 326 | 400 |
| 327 int Heap::SizeOfObjects() { | 401 int Heap::SizeOfObjects() { |
| 328 int total = 0; | 402 int total = 0; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 341 if (FLAG_verify_heap) { | 415 if (FLAG_verify_heap) { |
| 342 Verify(); | 416 Verify(); |
| 343 } | 417 } |
| 344 | 418 |
| 345 if (FLAG_print_global_handles) GlobalHandles::Print(); | 419 if (FLAG_print_global_handles) GlobalHandles::Print(); |
| 346 if (FLAG_print_handles) PrintHandles(); | 420 if (FLAG_print_handles) PrintHandles(); |
| 347 if (FLAG_gc_verbose) Print(); | 421 if (FLAG_gc_verbose) Print(); |
| 348 if (FLAG_code_stats) ReportCodeStatistics("After GC"); | 422 if (FLAG_code_stats) ReportCodeStatistics("After GC"); |
| 349 #endif | 423 #endif |
| 350 | 424 |
| 351 Counters::alive_after_last_gc.Set(SizeOfObjects()); | 425 COUNTER(alive_after_last_gc).Set(SizeOfObjects()); |
| 352 | 426 |
| 353 Counters::symbol_table_capacity.Set(symbol_table()->Capacity()); | 427 COUNTER(symbol_table_capacity).Set(symbol_table()->Capacity()); |
| 354 Counters::number_of_symbols.Set(symbol_table()->NumberOfElements()); | 428 COUNTER(number_of_symbols).Set(symbol_table()->NumberOfElements()); |
| 355 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) | 429 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
| 356 ReportStatisticsAfterGC(); | 430 ReportStatisticsAfterGC(); |
| 357 #endif | 431 #endif |
| 358 #ifdef ENABLE_DEBUGGER_SUPPORT | 432 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 359 Debug::AfterGarbageCollection(); | 433 Debug::AfterGarbageCollection(); |
| 360 #endif | 434 #endif |
| 361 } | 435 } |
| 362 | 436 |
| 363 | 437 |
| 364 void Heap::CollectAllGarbage(bool force_compaction) { | 438 void Heap::CollectAllGarbage(bool force_compaction) { |
| 365 // Since we are ignoring the return value, the exact choice of space does | 439 // Since we are ignoring the return value, the exact choice of space does |
| 366 // not matter, so long as we do not specify NEW_SPACE, which would not | 440 // not matter, so long as we do not specify NEW_SPACE, which would not |
| 367 // cause a full GC. | 441 // cause a full GC. |
| 368 MarkCompactCollector::SetForceCompaction(force_compaction); | 442 MarkCompactCollector::SetForceCompaction(force_compaction); |
| 369 CollectGarbage(0, OLD_POINTER_SPACE); | 443 CollectGarbage(0, OLD_POINTER_SPACE); |
| 370 MarkCompactCollector::SetForceCompaction(false); | 444 MarkCompactCollector::SetForceCompaction(false); |
| 371 } | 445 } |
| 372 | 446 |
| 373 | 447 |
| 374 void Heap::CollectAllGarbageIfContextDisposed() { | 448 void Heap::CollectAllGarbageIfContextDisposed() { |
| 449 HeapData& heap_data = v8_context()->heap_data_; |
| 375 // If the garbage collector interface is exposed through the global | 450 // If the garbage collector interface is exposed through the global |
| 376 // gc() function, we avoid being clever about forcing GCs when | 451 // gc() function, we avoid being clever about forcing GCs when |
| 377 // contexts are disposed and leave it to the embedder to make | 452 // contexts are disposed and leave it to the embedder to make |
| 378 // informed decisions about when to force a collection. | 453 // informed decisions about when to force a collection. |
| 379 if (!FLAG_expose_gc && context_disposed_pending_) { | 454 if (!FLAG_expose_gc && heap_data.context_disposed_pending_) { |
| 380 HistogramTimerScope scope(&Counters::gc_context); | 455 HistogramTimerScope scope(&COUNTER(gc_context)); |
| 381 CollectAllGarbage(false); | 456 CollectAllGarbage(false); |
| 382 } | 457 } |
| 383 context_disposed_pending_ = false; | 458 heap_data.context_disposed_pending_ = false; |
| 384 } | 459 } |
| 385 | 460 |
| 386 | 461 |
| 387 void Heap::NotifyContextDisposed() { | 462 void Heap::NotifyContextDisposed() { |
| 388 context_disposed_pending_ = true; | 463 v8_context()->heap_data_.context_disposed_pending_ = true; |
| 389 } | 464 } |
| 390 | 465 |
| 391 | 466 |
| 392 bool Heap::CollectGarbage(int requested_size, AllocationSpace space) { | 467 bool Heap::CollectGarbage(int requested_size, AllocationSpace space) { |
| 393 // The VM is in the GC state until exiting this function. | 468 // The VM is in the GC state until exiting this function. |
| 394 VMState state(GC); | 469 VMState state(GC); |
| 395 | 470 |
| 471 HeapData& heap_data = v8_context()->heap_data_; |
| 472 |
| 396 #ifdef DEBUG | 473 #ifdef DEBUG |
| 397 // Reset the allocation timeout to the GC interval, but make sure to | 474 // Reset the allocation timeout to the GC interval, but make sure to |
| 398 // allow at least a few allocations after a collection. The reason | 475 // allow at least a few allocations after a collection. The reason |
| 399 // for this is that we have a lot of allocation sequences and we | 476 // for this is that we have a lot of allocation sequences and we |
| 400 // assume that a garbage collection will allow the subsequent | 477 // assume that a garbage collection will allow the subsequent |
| 401 // allocation attempts to go through. | 478 // allocation attempts to go through. |
| 402 allocation_timeout_ = Max(6, FLAG_gc_interval); | 479 heap_data.allocation_timeout_ = Max(6, FLAG_gc_interval); |
| 403 #endif | 480 #endif |
| 404 | 481 |
| 405 { GCTracer tracer; | 482 { GCTracer tracer; |
| 406 GarbageCollectionPrologue(); | 483 GarbageCollectionPrologue(); |
| 407 // The GC count was incremented in the prologue. Tell the tracer about | 484 // The GC count was incremented in the prologue. Tell the tracer about |
| 408 // it. | 485 // it. |
| 409 tracer.set_gc_count(gc_count_); | 486 tracer.set_gc_count(heap_data.gc_count_); |
| 410 | 487 |
| 411 GarbageCollector collector = SelectGarbageCollector(space); | 488 GarbageCollector collector = SelectGarbageCollector(space); |
| 412 // Tell the tracer which collector we've selected. | 489 // Tell the tracer which collector we've selected. |
| 413 tracer.set_collector(collector); | 490 tracer.set_collector(collector); |
| 414 | 491 |
| 415 HistogramTimer* rate = (collector == SCAVENGER) | 492 HistogramTimer* rate = (collector == SCAVENGER) |
| 416 ? &Counters::gc_scavenger | 493 ? &COUNTER(gc_scavenger) |
| 417 : &Counters::gc_compactor; | 494 : &COUNTER(gc_compactor); |
| 418 rate->Start(); | 495 rate->Start(); |
| 419 PerformGarbageCollection(space, collector, &tracer); | 496 PerformGarbageCollection(space, collector, &tracer); |
| 420 rate->Stop(); | 497 rate->Stop(); |
| 421 | 498 |
| 422 GarbageCollectionEpilogue(); | 499 GarbageCollectionEpilogue(); |
| 423 } | 500 } |
| 424 | 501 |
| 425 | 502 |
| 426 #ifdef ENABLE_LOGGING_AND_PROFILING | 503 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 427 if (FLAG_log_gc) HeapProfiler::WriteSample(); | 504 if (FLAG_log_gc) HeapProfiler::WriteSample(); |
| 428 #endif | 505 #endif |
| 429 | 506 |
| 430 switch (space) { | 507 switch (space) { |
| 431 case NEW_SPACE: | 508 case NEW_SPACE: |
| 432 return new_space_.Available() >= requested_size; | 509 return heap_data.new_space_.Available() >= requested_size; |
| 433 case OLD_POINTER_SPACE: | 510 case OLD_POINTER_SPACE: |
| 434 return old_pointer_space_->Available() >= requested_size; | 511 return heap_data.old_pointer_space_->Available() >= requested_size; |
| 435 case OLD_DATA_SPACE: | 512 case OLD_DATA_SPACE: |
| 436 return old_data_space_->Available() >= requested_size; | 513 return heap_data.old_data_space_->Available() >= requested_size; |
| 437 case CODE_SPACE: | 514 case CODE_SPACE: |
| 438 return code_space_->Available() >= requested_size; | 515 return heap_data.code_space_->Available() >= requested_size; |
| 439 case MAP_SPACE: | 516 case MAP_SPACE: |
| 440 return map_space_->Available() >= requested_size; | 517 return heap_data.map_space_->Available() >= requested_size; |
| 441 case CELL_SPACE: | 518 case CELL_SPACE: |
| 442 return cell_space_->Available() >= requested_size; | 519 return heap_data.cell_space_->Available() >= requested_size; |
| 443 case LO_SPACE: | 520 case LO_SPACE: |
| 444 return lo_space_->Available() >= requested_size; | 521 return heap_data.lo_space_->Available() >= requested_size; |
| 445 } | 522 } |
| 446 return false; | 523 return false; |
| 447 } | 524 } |
| 448 | 525 |
| 449 | 526 |
| 450 void Heap::PerformScavenge() { | 527 void Heap::PerformScavenge() { |
| 451 GCTracer tracer; | 528 GCTracer tracer; |
| 452 PerformGarbageCollection(NEW_SPACE, SCAVENGER, &tracer); | 529 PerformGarbageCollection(NEW_SPACE, SCAVENGER, &tracer); |
| 453 } | 530 } |
| 454 | 531 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 473 | 550 |
| 474 static void VerifySymbolTable() { | 551 static void VerifySymbolTable() { |
| 475 #ifdef DEBUG | 552 #ifdef DEBUG |
| 476 SymbolTableVerifier verifier; | 553 SymbolTableVerifier verifier; |
| 477 Heap::symbol_table()->IterateElements(&verifier); | 554 Heap::symbol_table()->IterateElements(&verifier); |
| 478 #endif // DEBUG | 555 #endif // DEBUG |
| 479 } | 556 } |
| 480 | 557 |
| 481 | 558 |
| 482 void Heap::EnsureFromSpaceIsCommitted() { | 559 void Heap::EnsureFromSpaceIsCommitted() { |
| 483 if (new_space_.CommitFromSpaceIfNeeded()) return; | 560 HeapData& heap_data = v8_context()->heap_data_; |
| 561 if (heap_data.new_space_.CommitFromSpaceIfNeeded()) return; |
| 484 | 562 |
| 485 // Committing memory to from space failed. | 563 // Committing memory to from space failed. |
| 486 // Try shrinking and try again. | 564 // Try shrinking and try again. |
| 487 Shrink(); | 565 Shrink(); |
| 488 if (new_space_.CommitFromSpaceIfNeeded()) return; | 566 if (heap_data.new_space_.CommitFromSpaceIfNeeded()) return; |
| 489 | 567 |
| 490 // Committing memory to from space failed again. | 568 // Committing memory to from space failed again. |
| 491 // Memory is exhausted and we will die. | 569 // Memory is exhausted and we will die. |
| 492 V8::FatalProcessOutOfMemory("Committing semi space failed."); | 570 V8::FatalProcessOutOfMemory("Committing semi space failed."); |
| 493 } | 571 } |
| 494 | 572 |
| 495 | 573 |
| 496 void Heap::PerformGarbageCollection(AllocationSpace space, | 574 void Heap::PerformGarbageCollection(AllocationSpace space, |
| 497 GarbageCollector collector, | 575 GarbageCollector collector, |
| 498 GCTracer* tracer) { | 576 GCTracer* tracer) { |
| 499 VerifySymbolTable(); | 577 VerifySymbolTable(); |
| 500 if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) { | 578 HeapData& heap_data = v8_context()->heap_data_; |
| 501 ASSERT(!allocation_allowed_); | 579 if (collector == MARK_COMPACTOR && heap_data.global_gc_prologue_callback_) { |
| 502 global_gc_prologue_callback_(); | 580 ASSERT(!heap_data.allocation_allowed_); |
| 581 heap_data.global_gc_prologue_callback_(); |
| 503 } | 582 } |
| 504 EnsureFromSpaceIsCommitted(); | 583 EnsureFromSpaceIsCommitted(); |
| 505 if (collector == MARK_COMPACTOR) { | 584 if (collector == MARK_COMPACTOR) { |
| 506 MarkCompact(tracer); | 585 MarkCompact(tracer); |
| 507 | 586 |
| 508 int old_gen_size = PromotedSpaceSize(); | 587 int old_gen_size = PromotedSpaceSize(); |
| 509 old_gen_promotion_limit_ = | 588 heap_data.old_gen_promotion_limit_ = |
| 510 old_gen_size + Max(kMinimumPromotionLimit, old_gen_size / 3); | 589 old_gen_size + Max(kMinimumPromotionLimit, old_gen_size / 3); |
| 511 old_gen_allocation_limit_ = | 590 heap_data.old_gen_allocation_limit_ = |
| 512 old_gen_size + Max(kMinimumAllocationLimit, old_gen_size / 2); | 591 old_gen_size + Max(kMinimumAllocationLimit, old_gen_size / 2); |
| 513 old_gen_exhausted_ = false; | 592 heap_data.old_gen_exhausted_ = false; |
| 514 } | 593 } |
| 515 Scavenge(); | 594 Scavenge(); |
| 516 | 595 |
| 517 Counters::objs_since_last_young.Set(0); | 596 COUNTER(objs_since_last_young).Set(0); |
| 518 | 597 |
| 519 if (collector == MARK_COMPACTOR) { | 598 if (collector == MARK_COMPACTOR) { |
| 520 DisableAssertNoAllocation allow_allocation; | 599 DisableAssertNoAllocation allow_allocation; |
| 521 GlobalHandles::PostGarbageCollectionProcessing(); | 600 GlobalHandles::PostGarbageCollectionProcessing(); |
| 522 } | 601 } |
| 523 | 602 |
| 524 // Update relocatables. | 603 // Update relocatables. |
| 525 Relocatable::PostGarbageCollectionProcessing(); | 604 Relocatable::PostGarbageCollectionProcessing(); |
| 526 | 605 |
| 527 if (collector == MARK_COMPACTOR) { | 606 if (collector == MARK_COMPACTOR) { |
| 528 // Register the amount of external allocated memory. | 607 // Register the amount of external allocated memory. |
| 529 amount_of_external_allocated_memory_at_last_global_gc_ = | 608 heap_data.amount_of_external_allocated_memory_at_last_global_gc_ = |
| 530 amount_of_external_allocated_memory_; | 609 heap_data.amount_of_external_allocated_memory_; |
| 531 } | 610 } |
| 532 | 611 |
| 533 if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) { | 612 if (collector == MARK_COMPACTOR && heap_data.global_gc_epilogue_callback_) { |
| 534 ASSERT(!allocation_allowed_); | 613 ASSERT(!heap_data.allocation_allowed_); |
| 535 global_gc_epilogue_callback_(); | 614 heap_data.global_gc_epilogue_callback_(); |
| 536 } | 615 } |
| 537 VerifySymbolTable(); | 616 VerifySymbolTable(); |
| 538 } | 617 } |
| 539 | 618 |
| 540 | 619 |
| 541 void Heap::MarkCompact(GCTracer* tracer) { | 620 void Heap::MarkCompact(GCTracer* tracer) { |
| 542 gc_state_ = MARK_COMPACT; | 621 HeapData& heap_data = v8_context()->heap_data_; |
| 543 mc_count_++; | 622 heap_data.gc_state_ = MARK_COMPACT; |
| 544 tracer->set_full_gc_count(mc_count_); | 623 heap_data.mc_count_++; |
| 624 tracer->set_full_gc_count(heap_data.mc_count_); |
| 545 LOG(ResourceEvent("markcompact", "begin")); | 625 LOG(ResourceEvent("markcompact", "begin")); |
| 546 | 626 |
| 547 MarkCompactCollector::Prepare(tracer); | 627 MarkCompactCollector::Prepare(tracer); |
| 548 | 628 |
| 549 bool is_compacting = MarkCompactCollector::IsCompacting(); | 629 bool is_compacting = MarkCompactCollector::IsCompacting(); |
| 550 | 630 |
| 551 MarkCompactPrologue(is_compacting); | 631 MarkCompactPrologue(is_compacting); |
| 552 | 632 |
| 553 MarkCompactCollector::CollectGarbage(); | 633 MarkCompactCollector::CollectGarbage(); |
| 554 | 634 |
| 555 MarkCompactEpilogue(is_compacting); | 635 MarkCompactEpilogue(is_compacting); |
| 556 | 636 |
| 557 LOG(ResourceEvent("markcompact", "end")); | 637 LOG(ResourceEvent("markcompact", "end")); |
| 558 | 638 |
| 559 gc_state_ = NOT_IN_GC; | 639 heap_data.gc_state_ = NOT_IN_GC; |
| 560 | 640 |
| 561 Shrink(); | 641 Shrink(); |
| 562 | 642 |
| 563 Counters::objs_since_last_full.Set(0); | 643 COUNTER(objs_since_last_full).Set(0); |
| 564 context_disposed_pending_ = false; | 644 heap_data.context_disposed_pending_ = false; |
| 565 } | 645 } |
| 566 | 646 |
| 567 | 647 |
| 568 void Heap::MarkCompactPrologue(bool is_compacting) { | 648 void Heap::MarkCompactPrologue(bool is_compacting) { |
| 569 // At any old GC clear the keyed lookup cache to enable collection of unused | 649 // At any old GC clear the keyed lookup cache to enable collection of unused |
| 570 // maps. | 650 // maps. |
| 571 KeyedLookupCache::Clear(); | 651 KeyedLookupCache::Clear(); |
| 572 ContextSlotCache::Clear(); | 652 ContextSlotCache::Clear(); |
| 573 DescriptorLookupCache::Clear(); | 653 DescriptorLookupCache::Clear(); |
| 574 | 654 |
| 575 CompilationCache::MarkCompactPrologue(); | 655 CompilationCache::MarkCompactPrologue(); |
| 576 | 656 |
| 577 Top::MarkCompactPrologue(is_compacting); | 657 Top::MarkCompactPrologue(is_compacting); |
| 578 ThreadManager::MarkCompactPrologue(is_compacting); | 658 ThreadManager::MarkCompactPrologue(is_compacting); |
| 579 } | 659 } |
| 580 | 660 |
| 581 | 661 |
| 582 void Heap::MarkCompactEpilogue(bool is_compacting) { | 662 void Heap::MarkCompactEpilogue(bool is_compacting) { |
| 583 Top::MarkCompactEpilogue(is_compacting); | 663 Top::MarkCompactEpilogue(is_compacting); |
| 584 ThreadManager::MarkCompactEpilogue(is_compacting); | 664 ThreadManager::MarkCompactEpilogue(is_compacting); |
| 585 } | 665 } |
| 586 | 666 |
| 587 | 667 |
| 588 Object* Heap::FindCodeObject(Address a) { | 668 Object* Heap::FindCodeObject(Address a) { |
| 589 Object* obj = code_space_->FindObject(a); | 669 HeapData& heap_data = v8_context()->heap_data_; |
| 670 Object* obj = heap_data.code_space_->FindObject(a); |
| 590 if (obj->IsFailure()) { | 671 if (obj->IsFailure()) { |
| 591 obj = lo_space_->FindObject(a); | 672 obj = heap_data.lo_space_->FindObject(a); |
| 592 } | 673 } |
| 593 ASSERT(!obj->IsFailure()); | 674 ASSERT(!obj->IsFailure()); |
| 594 return obj; | 675 return obj; |
| 595 } | 676 } |
| 596 | 677 |
| 597 | 678 |
| 598 // Helper class for copying HeapObjects | 679 // Helper class for copying HeapObjects |
| 599 class ScavengeVisitor: public ObjectVisitor { | 680 class ScavengeVisitor: public ObjectVisitor { |
| 600 public: | 681 public: |
| 601 | 682 |
| 602 void VisitPointer(Object** p) { ScavengePointer(p); } | 683 void VisitPointer(Object** p) { ScavengePointer(p); } |
| 603 | 684 |
| 604 void VisitPointers(Object** start, Object** end) { | 685 void VisitPointers(Object** start, Object** end) { |
| 605 // Copy all HeapObject pointers in [start, end) | 686 // Copy all HeapObject pointers in [start, end) |
| 606 for (Object** p = start; p < end; p++) ScavengePointer(p); | 687 for (Object** p = start; p < end; p++) ScavengePointer(p); |
| 607 } | 688 } |
| 608 | 689 |
| 609 private: | 690 private: |
| 610 void ScavengePointer(Object** p) { | 691 void ScavengePointer(Object** p) { |
| 611 Object* object = *p; | 692 Object* object = *p; |
| 612 if (!Heap::InNewSpace(object)) return; | 693 if (!Heap::InNewSpace(object)) return; |
| 613 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p), | 694 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p), |
| 614 reinterpret_cast<HeapObject*>(object)); | 695 reinterpret_cast<HeapObject*>(object)); |
| 615 } | 696 } |
| 616 }; | 697 }; |
| 617 | 698 |
| 618 | |
| 619 // A queue of pointers and maps of to-be-promoted objects during a | |
| 620 // scavenge collection. | |
| 621 class PromotionQueue { | |
| 622 public: | |
| 623 void Initialize(Address start_address) { | |
| 624 front_ = rear_ = reinterpret_cast<HeapObject**>(start_address); | |
| 625 } | |
| 626 | |
| 627 bool is_empty() { return front_ <= rear_; } | |
| 628 | |
| 629 void insert(HeapObject* object, Map* map) { | |
| 630 *(--rear_) = object; | |
| 631 *(--rear_) = map; | |
| 632 // Assert no overflow into live objects. | |
| 633 ASSERT(reinterpret_cast<Address>(rear_) >= Heap::new_space()->top()); | |
| 634 } | |
| 635 | |
| 636 void remove(HeapObject** object, Map** map) { | |
| 637 *object = *(--front_); | |
| 638 *map = Map::cast(*(--front_)); | |
| 639 // Assert no underflow. | |
| 640 ASSERT(front_ >= rear_); | |
| 641 } | |
| 642 | |
| 643 private: | |
| 644 // The front of the queue is higher in memory than the rear. | |
| 645 HeapObject** front_; | |
| 646 HeapObject** rear_; | |
| 647 }; | |
| 648 | |
| 649 | |
| 650 // Shared state read by the scavenge collector and set by ScavengeObject. | |
| 651 static PromotionQueue promotion_queue; | |
| 652 | |
| 653 | |
| 654 #ifdef DEBUG | 699 #ifdef DEBUG |
| 655 // Visitor class to verify pointers in code or data space do not point into | 700 // Visitor class to verify pointers in code or data space do not point into |
| 656 // new space. | 701 // new space. |
| 657 class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor { | 702 class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor { |
| 658 public: | 703 public: |
| 659 void VisitPointers(Object** start, Object**end) { | 704 void VisitPointers(Object** start, Object**end) { |
| 660 for (Object** current = start; current < end; current++) { | 705 for (Object** current = start; current < end; current++) { |
| 661 if ((*current)->IsHeapObject()) { | 706 if ((*current)->IsHeapObject()) { |
| 662 ASSERT(!Heap::InNewSpace(HeapObject::cast(*current))); | 707 ASSERT(!Heap::InNewSpace(HeapObject::cast(*current))); |
| 663 } | 708 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 680 while (data_it.has_next()) data_it.next()->Iterate(&v); | 725 while (data_it.has_next()) data_it.next()->Iterate(&v); |
| 681 } | 726 } |
| 682 #endif | 727 #endif |
| 683 | 728 |
| 684 | 729 |
| 685 void Heap::Scavenge() { | 730 void Heap::Scavenge() { |
| 686 #ifdef DEBUG | 731 #ifdef DEBUG |
| 687 if (FLAG_enable_slow_asserts) VerifyNonPointerSpacePointers(); | 732 if (FLAG_enable_slow_asserts) VerifyNonPointerSpacePointers(); |
| 688 #endif | 733 #endif |
| 689 | 734 |
| 690 gc_state_ = SCAVENGE; | 735 HeapData& heap_data = v8_context()->heap_data_; |
| 736 heap_data.gc_state_ = SCAVENGE; |
| 691 | 737 |
| 692 // Implements Cheney's copying algorithm | 738 // Implements Cheney's copying algorithm |
| 693 LOG(ResourceEvent("scavenge", "begin")); | 739 LOG(ResourceEvent("scavenge", "begin")); |
| 694 | 740 |
| 695 // Clear descriptor cache. | 741 // Clear descriptor cache. |
| 696 DescriptorLookupCache::Clear(); | 742 DescriptorLookupCache::Clear(); |
| 697 | 743 |
| 698 // Used for updating survived_since_last_expansion_ at function end. | 744 // Used for updating survived_since_last_expansion_ at function end. |
| 699 int survived_watermark = PromotedSpaceSize(); | 745 int survived_watermark = PromotedSpaceSize(); |
| 700 | 746 |
| 701 if (new_space_.Capacity() < new_space_.MaximumCapacity() && | 747 if (heap_data.new_space_.Capacity() < |
| 702 survived_since_last_expansion_ > new_space_.Capacity()) { | 748 heap_data.new_space_.MaximumCapacity() && |
| 749 heap_data.survived_since_last_expansion_ > |
| 750 heap_data.new_space_.Capacity() |
| 751 ) { |
| 703 // Grow the size of new space if there is room to grow and enough | 752 // Grow the size of new space if there is room to grow and enough |
| 704 // data has survived scavenge since the last expansion. | 753 // data has survived scavenge since the last expansion. |
| 705 new_space_.Grow(); | 754 heap_data.new_space_.Grow(); |
| 706 survived_since_last_expansion_ = 0; | 755 heap_data.survived_since_last_expansion_ = 0; |
| 707 } | 756 } |
| 708 | 757 |
| 709 // Flip the semispaces. After flipping, to space is empty, from space has | 758 // Flip the semispaces. After flipping, to space is empty, from space has |
| 710 // live objects. | 759 // live objects. |
| 711 new_space_.Flip(); | 760 heap_data.new_space_.Flip(); |
| 712 new_space_.ResetAllocationInfo(); | 761 heap_data.new_space_.ResetAllocationInfo(); |
| 713 | 762 |
| 714 // We need to sweep newly copied objects which can be either in the | 763 // We need to sweep newly copied objects which can be either in the |
| 715 // to space or promoted to the old generation. For to-space | 764 // to space or promoted to the old generation. For to-space |
| 716 // objects, we treat the bottom of the to space as a queue. Newly | 765 // objects, we treat the bottom of the to space as a queue. Newly |
| 717 // copied and unswept objects lie between a 'front' mark and the | 766 // copied and unswept objects lie between a 'front' mark and the |
| 718 // allocation pointer. | 767 // allocation pointer. |
| 719 // | 768 // |
| 720 // Promoted objects can go into various old-generation spaces, and | 769 // Promoted objects can go into various old-generation spaces, and |
| 721 // can be allocated internally in the spaces (from the free list). | 770 // can be allocated internally in the spaces (from the free list). |
| 722 // We treat the top of the to space as a queue of addresses of | 771 // We treat the top of the to space as a queue of addresses of |
| 723 // promoted objects. The addresses of newly promoted and unswept | 772 // promoted objects. The addresses of newly promoted and unswept |
| 724 // objects lie between a 'front' mark and a 'rear' mark that is | 773 // objects lie between a 'front' mark and a 'rear' mark that is |
| 725 // updated as a side effect of promoting an object. | 774 // updated as a side effect of promoting an object. |
| 726 // | 775 // |
| 727 // There is guaranteed to be enough room at the top of the to space | 776 // There is guaranteed to be enough room at the top of the to space |
| 728 // for the addresses of promoted objects: every object promoted | 777 // for the addresses of promoted objects: every object promoted |
| 729 // frees up its size in bytes from the top of the new space, and | 778 // frees up its size in bytes from the top of the new space, and |
| 730 // objects are at least one pointer in size. | 779 // objects are at least one pointer in size. |
| 731 Address new_space_front = new_space_.ToSpaceLow(); | 780 Address new_space_front = heap_data.new_space_.ToSpaceLow(); |
| 732 promotion_queue.Initialize(new_space_.ToSpaceHigh()); | 781 PromotionQueue& promotion_queue = |
| 782 heap_data.heap_private_data_.promotion_queue_; |
| 783 promotion_queue.Initialize(heap_data.new_space_.ToSpaceHigh()); |
| 733 | 784 |
| 734 ScavengeVisitor scavenge_visitor; | 785 ScavengeVisitor scavenge_visitor; |
| 735 // Copy roots. | 786 // Copy roots. |
| 736 IterateRoots(&scavenge_visitor, VISIT_ALL); | 787 IterateRoots(&scavenge_visitor, VISIT_ALL); |
| 737 | 788 |
| 738 // Copy objects reachable from the old generation. By definition, | 789 // Copy objects reachable from the old generation. By definition, |
| 739 // there are no intergenerational pointers in code or data spaces. | 790 // there are no intergenerational pointers in code or data spaces. |
| 740 IterateRSet(old_pointer_space_, &ScavengePointer); | 791 IterateRSet(heap_data.old_pointer_space_, &ScavengePointer); |
| 741 IterateRSet(map_space_, &ScavengePointer); | 792 IterateRSet(heap_data.map_space_, &ScavengePointer); |
| 742 lo_space_->IterateRSet(&ScavengePointer); | 793 heap_data.lo_space_->IterateRSet(&ScavengePointer); |
| 743 | 794 |
| 744 // Copy objects reachable from cells by scavenging cell values directly. | 795 // Copy objects reachable from cells by scavenging cell values directly. |
| 745 HeapObjectIterator cell_iterator(cell_space_); | 796 HeapObjectIterator cell_iterator(heap_data.cell_space_); |
| 746 while (cell_iterator.has_next()) { | 797 while (cell_iterator.has_next()) { |
| 747 HeapObject* cell = cell_iterator.next(); | 798 HeapObject* cell = cell_iterator.next(); |
| 748 if (cell->IsJSGlobalPropertyCell()) { | 799 if (cell->IsJSGlobalPropertyCell()) { |
| 749 Address value_address = | 800 Address value_address = |
| 750 reinterpret_cast<Address>(cell) + | 801 reinterpret_cast<Address>(cell) + |
| 751 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag); | 802 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag); |
| 752 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address)); | 803 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address)); |
| 753 } | 804 } |
| 754 } | 805 } |
| 755 | 806 |
| 756 do { | 807 do { |
| 757 ASSERT(new_space_front <= new_space_.top()); | 808 ASSERT(new_space_front <= heap_data.new_space_.top()); |
| 758 | 809 |
| 759 // The addresses new_space_front and new_space_.top() define a | 810 // The addresses new_space_front and new_space_.top() define a |
| 760 // queue of unprocessed copied objects. Process them until the | 811 // queue of unprocessed copied objects. Process them until the |
| 761 // queue is empty. | 812 // queue is empty. |
| 762 while (new_space_front < new_space_.top()) { | 813 while (new_space_front < heap_data.new_space_.top()) { |
| 763 HeapObject* object = HeapObject::FromAddress(new_space_front); | 814 HeapObject* object = HeapObject::FromAddress(new_space_front); |
| 764 object->Iterate(&scavenge_visitor); | 815 object->Iterate(&scavenge_visitor); |
| 765 new_space_front += object->Size(); | 816 new_space_front += object->Size(); |
| 766 } | 817 } |
| 767 | 818 |
| 768 // Promote and process all the to-be-promoted objects. | 819 // Promote and process all the to-be-promoted objects. |
| 769 while (!promotion_queue.is_empty()) { | 820 while (!promotion_queue.is_empty()) { |
| 770 HeapObject* source; | 821 HeapObject* source; |
| 771 Map* map; | 822 Map* map; |
| 772 promotion_queue.remove(&source, &map); | 823 promotion_queue.remove(&source, &map); |
| 773 // Copy the from-space object to its new location (given by the | 824 // Copy the from-space object to its new location (given by the |
| 774 // forwarding address) and fix its map. | 825 // forwarding address) and fix its map. |
| 775 HeapObject* target = source->map_word().ToForwardingAddress(); | 826 HeapObject* target = source->map_word().ToForwardingAddress(); |
| 776 CopyBlock(reinterpret_cast<Object**>(target->address()), | 827 CopyBlock(reinterpret_cast<Object**>(target->address()), |
| 777 reinterpret_cast<Object**>(source->address()), | 828 reinterpret_cast<Object**>(source->address()), |
| 778 source->SizeFromMap(map)); | 829 source->SizeFromMap(map)); |
| 779 target->set_map(map); | 830 target->set_map(map); |
| 780 | 831 |
| 781 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) | 832 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
| 782 // Update NewSpace stats if necessary. | 833 // Update NewSpace stats if necessary. |
| 783 RecordCopiedObject(target); | 834 RecordCopiedObject(target); |
| 784 #endif | 835 #endif |
| 785 // Visit the newly copied object for pointers to new space. | 836 // Visit the newly copied object for pointers to new space. |
| 786 target->Iterate(&scavenge_visitor); | 837 target->Iterate(&scavenge_visitor); |
| 787 UpdateRSet(target); | 838 UpdateRSet(target); |
| 788 } | 839 } |
| 789 | 840 |
| 790 // Take another spin if there are now unswept objects in new space | 841 // Take another spin if there are now unswept objects in new space |
| 791 // (there are currently no more unswept promoted objects). | 842 // (there are currently no more unswept promoted objects). |
| 792 } while (new_space_front < new_space_.top()); | 843 } while (new_space_front < heap_data.new_space_.top()); |
| 793 | 844 |
| 794 // Set age mark. | 845 // Set age mark. |
| 795 new_space_.set_age_mark(new_space_.top()); | 846 heap_data.new_space_.set_age_mark(heap_data.new_space_.top()); |
| 796 | 847 |
| 797 // Update how much has survived scavenge. | 848 // Update how much has survived scavenge. |
| 798 survived_since_last_expansion_ += | 849 heap_data.survived_since_last_expansion_ += |
| 799 (PromotedSpaceSize() - survived_watermark) + new_space_.Size(); | 850 (PromotedSpaceSize() - survived_watermark) + heap_data.new_space_.Size(); |
| 800 | 851 |
| 801 LOG(ResourceEvent("scavenge", "end")); | 852 LOG(ResourceEvent("scavenge", "end")); |
| 802 | 853 |
| 803 gc_state_ = NOT_IN_GC; | 854 heap_data.gc_state_ = NOT_IN_GC; |
| 804 } | 855 } |
| 805 | 856 |
| 806 | 857 |
| 807 void Heap::ClearRSetRange(Address start, int size_in_bytes) { | 858 void Heap::ClearRSetRange(Address start, int size_in_bytes) { |
| 808 uint32_t start_bit; | 859 uint32_t start_bit; |
| 809 Address start_word_address = | 860 Address start_word_address = |
| 810 Page::ComputeRSetBitPosition(start, 0, &start_bit); | 861 Page::ComputeRSetBitPosition(start, 0, &start_bit); |
| 811 uint32_t end_bit; | 862 uint32_t end_bit; |
| 812 Address end_word_address = | 863 Address end_word_address = |
| 813 Page::ComputeRSetBitPosition(start + size_in_bytes - kIntSize, | 864 Page::ComputeRSetBitPosition(start + size_in_bytes - kIntSize, |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 881 // Skip code object, we know it does not contain inter-generational | 932 // Skip code object, we know it does not contain inter-generational |
| 882 // pointers. | 933 // pointers. |
| 883 UpdateRSetVisitor v; | 934 UpdateRSetVisitor v; |
| 884 obj->Iterate(&v); | 935 obj->Iterate(&v); |
| 885 } | 936 } |
| 886 return obj->Size(); | 937 return obj->Size(); |
| 887 } | 938 } |
| 888 | 939 |
| 889 | 940 |
| 890 void Heap::RebuildRSets() { | 941 void Heap::RebuildRSets() { |
| 942 HeapData& heap_data = v8_context()->heap_data_; |
| 891 // By definition, we do not care about remembered set bits in code, | 943 // By definition, we do not care about remembered set bits in code, |
| 892 // data, or cell spaces. | 944 // data, or cell spaces. |
| 893 map_space_->ClearRSet(); | 945 heap_data.map_space_->ClearRSet(); |
| 894 RebuildRSets(map_space_); | 946 RebuildRSets(heap_data.map_space_); |
| 895 | 947 |
| 896 old_pointer_space_->ClearRSet(); | 948 heap_data.old_pointer_space_->ClearRSet(); |
| 897 RebuildRSets(old_pointer_space_); | 949 RebuildRSets(heap_data.old_pointer_space_); |
| 898 | 950 |
| 899 Heap::lo_space_->ClearRSet(); | 951 heap_data.lo_space_->ClearRSet(); |
| 900 RebuildRSets(lo_space_); | 952 RebuildRSets(heap_data.lo_space_); |
| 901 } | 953 } |
| 902 | 954 |
| 903 | 955 |
| 904 void Heap::RebuildRSets(PagedSpace* space) { | 956 void Heap::RebuildRSets(PagedSpace* space) { |
| 905 HeapObjectIterator it(space); | 957 HeapObjectIterator it(space); |
| 906 while (it.has_next()) Heap::UpdateRSet(it.next()); | 958 while (it.has_next()) Heap::UpdateRSet(it.next()); |
| 907 } | 959 } |
| 908 | 960 |
| 909 | 961 |
| 910 void Heap::RebuildRSets(LargeObjectSpace* space) { | 962 void Heap::RebuildRSets(LargeObjectSpace* space) { |
| 911 LargeObjectIterator it(space); | 963 LargeObjectIterator it(space); |
| 912 while (it.has_next()) Heap::UpdateRSet(it.next()); | 964 while (it.has_next()) Heap::UpdateRSet(it.next()); |
| 913 } | 965 } |
| 914 | 966 |
| 915 | 967 |
| 916 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) | 968 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
| 917 void Heap::RecordCopiedObject(HeapObject* obj) { | 969 void Heap::RecordCopiedObject(HeapObject* obj) { |
| 918 bool should_record = false; | 970 bool should_record = false; |
| 919 #ifdef DEBUG | 971 #ifdef DEBUG |
| 920 should_record = FLAG_heap_stats; | 972 should_record = FLAG_heap_stats; |
| 921 #endif | 973 #endif |
| 922 #ifdef ENABLE_LOGGING_AND_PROFILING | 974 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 923 should_record = should_record || FLAG_log_gc; | 975 should_record = should_record || FLAG_log_gc; |
| 924 #endif | 976 #endif |
| 925 if (should_record) { | 977 if (should_record) { |
| 926 if (new_space_.Contains(obj)) { | 978 HeapData& heap_data = v8_context()->heap_data_; |
| 927 new_space_.RecordAllocation(obj); | 979 if (heap_data.new_space_.Contains(obj)) { |
| 980 heap_data.new_space_.RecordAllocation(obj); |
| 928 } else { | 981 } else { |
| 929 new_space_.RecordPromotion(obj); | 982 heap_data.new_space_.RecordPromotion(obj); |
| 930 } | 983 } |
| 931 } | 984 } |
| 932 } | 985 } |
| 933 #endif // defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) | 986 #endif // defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
| 934 | 987 |
| 935 | 988 |
| 936 | 989 |
| 937 HeapObject* Heap::MigrateObject(HeapObject* source, | 990 HeapObject* Heap::MigrateObject(HeapObject* source, |
| 938 HeapObject* target, | 991 HeapObject* target, |
| 939 int size) { | 992 int size) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 977 // active semispace of the young generation and not already copied. | 1030 // active semispace of the young generation and not already copied. |
| 978 if (!InNewSpace(object)) return; | 1031 if (!InNewSpace(object)) return; |
| 979 first_word = object->map_word(); | 1032 first_word = object->map_word(); |
| 980 if (first_word.IsForwardingAddress()) { | 1033 if (first_word.IsForwardingAddress()) { |
| 981 *p = first_word.ToForwardingAddress(); | 1034 *p = first_word.ToForwardingAddress(); |
| 982 return; | 1035 return; |
| 983 } | 1036 } |
| 984 } | 1037 } |
| 985 | 1038 |
| 986 int object_size = object->SizeFromMap(first_word.ToMap()); | 1039 int object_size = object->SizeFromMap(first_word.ToMap()); |
| 1040 HeapData& heap_data = v8_context()->heap_data_; |
| 987 // We rely on live objects in new space to be at least two pointers, | 1041 // We rely on live objects in new space to be at least two pointers, |
| 988 // so we can store the from-space address and map pointer of promoted | 1042 // so we can store the from-space address and map pointer of promoted |
| 989 // objects in the to space. | 1043 // objects in the to space. |
| 990 ASSERT(object_size >= 2 * kPointerSize); | 1044 ASSERT(object_size >= 2 * kPointerSize); |
| 991 | 1045 |
| 992 // If the object should be promoted, we try to copy it to old space. | 1046 // If the object should be promoted, we try to copy it to old space. |
| 993 if (ShouldBePromoted(object->address(), object_size)) { | 1047 if (ShouldBePromoted(object->address(), object_size)) { |
| 994 Object* result; | 1048 Object* result; |
| 1049 PromotionQueue& promotion_queue = |
| 1050 heap_data.heap_private_data_.promotion_queue_; |
| 1051 |
| 995 if (object_size > MaxObjectSizeInPagedSpace()) { | 1052 if (object_size > MaxObjectSizeInPagedSpace()) { |
| 996 result = lo_space_->AllocateRawFixedArray(object_size); | 1053 result = heap_data.lo_space_->AllocateRawFixedArray(object_size); |
| 997 if (!result->IsFailure()) { | 1054 if (!result->IsFailure()) { |
| 998 // Save the from-space object pointer and its map pointer at the | 1055 // Save the from-space object pointer and its map pointer at the |
| 999 // top of the to space to be swept and copied later. Write the | 1056 // top of the to space to be swept and copied later. Write the |
| 1000 // forwarding address over the map word of the from-space | 1057 // forwarding address over the map word of the from-space |
| 1001 // object. | 1058 // object. |
| 1002 HeapObject* target = HeapObject::cast(result); | 1059 HeapObject* target = HeapObject::cast(result); |
| 1003 promotion_queue.insert(object, first_word.ToMap()); | 1060 promotion_queue.insert(object, first_word.ToMap()); |
| 1004 object->set_map_word(MapWord::FromForwardingAddress(target)); | 1061 object->set_map_word(MapWord::FromForwardingAddress(target)); |
| 1005 | 1062 |
| 1006 // Give the space allocated for the result a proper map by | 1063 // Give the space allocated for the result a proper map by |
| 1007 // treating it as a free list node (not linked into the free | 1064 // treating it as a free list node (not linked into the free |
| 1008 // list). | 1065 // list). |
| 1009 FreeListNode* node = FreeListNode::FromAddress(target->address()); | 1066 FreeListNode* node = FreeListNode::FromAddress(target->address()); |
| 1010 node->set_size(object_size); | 1067 node->set_size(object_size); |
| 1011 | 1068 |
| 1012 *p = target; | 1069 *p = target; |
| 1013 return; | 1070 return; |
| 1014 } | 1071 } |
| 1015 } else { | 1072 } else { |
| 1016 OldSpace* target_space = Heap::TargetSpace(object); | 1073 OldSpace* target_space = Heap::TargetSpace(object); |
| 1017 ASSERT(target_space == Heap::old_pointer_space_ || | 1074 ASSERT(target_space == heap_data.old_pointer_space_ || |
| 1018 target_space == Heap::old_data_space_); | 1075 target_space == heap_data.old_data_space_); |
| 1019 result = target_space->AllocateRaw(object_size); | 1076 result = target_space->AllocateRaw(object_size); |
| 1020 if (!result->IsFailure()) { | 1077 if (!result->IsFailure()) { |
| 1021 HeapObject* target = HeapObject::cast(result); | 1078 HeapObject* target = HeapObject::cast(result); |
| 1022 if (target_space == Heap::old_pointer_space_) { | 1079 if (target_space == heap_data.old_pointer_space_) { |
| 1023 // Save the from-space object pointer and its map pointer at the | 1080 // Save the from-space object pointer and its map pointer at the |
| 1024 // top of the to space to be swept and copied later. Write the | 1081 // top of the to space to be swept and copied later. Write the |
| 1025 // forwarding address over the map word of the from-space | 1082 // forwarding address over the map word of the from-space |
| 1026 // object. | 1083 // object. |
| 1027 promotion_queue.insert(object, first_word.ToMap()); | 1084 promotion_queue.insert(object, first_word.ToMap()); |
| 1028 object->set_map_word(MapWord::FromForwardingAddress(target)); | 1085 object->set_map_word(MapWord::FromForwardingAddress(target)); |
| 1029 | 1086 |
| 1030 // Give the space allocated for the result a proper map by | 1087 // Give the space allocated for the result a proper map by |
| 1031 // treating it as a free list node (not linked into the free | 1088 // treating it as a free list node (not linked into the free |
| 1032 // list). | 1089 // list). |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1043 #ifdef DEBUG | 1100 #ifdef DEBUG |
| 1044 VerifyNonPointerSpacePointersVisitor v; | 1101 VerifyNonPointerSpacePointersVisitor v; |
| 1045 (*p)->Iterate(&v); | 1102 (*p)->Iterate(&v); |
| 1046 #endif | 1103 #endif |
| 1047 } | 1104 } |
| 1048 return; | 1105 return; |
| 1049 } | 1106 } |
| 1050 } | 1107 } |
| 1051 } | 1108 } |
| 1052 // The object should remain in new space or the old space allocation failed. | 1109 // The object should remain in new space or the old space allocation failed. |
| 1053 Object* result = new_space_.AllocateRaw(object_size); | 1110 Object* result = heap_data.new_space_.AllocateRaw(object_size); |
| 1054 // Failed allocation at this point is utterly unexpected. | 1111 // Failed allocation at this point is utterly unexpected. |
| 1055 ASSERT(!result->IsFailure()); | 1112 ASSERT(!result->IsFailure()); |
| 1056 *p = MigrateObject(object, HeapObject::cast(result), object_size); | 1113 *p = MigrateObject(object, HeapObject::cast(result), object_size); |
| 1057 } | 1114 } |
| 1058 | 1115 |
| 1059 | 1116 |
| 1060 void Heap::ScavengePointer(HeapObject** p) { | 1117 void Heap::ScavengePointer(HeapObject** p) { |
| 1061 ScavengeObject(p, *p); | 1118 ScavengeObject(p, *p); |
| 1062 } | 1119 } |
| 1063 | 1120 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1116 | 1173 |
| 1117 const Heap::StructTable Heap::struct_table[] = { | 1174 const Heap::StructTable Heap::struct_table[] = { |
| 1118 #define STRUCT_TABLE_ELEMENT(NAME, Name, name) \ | 1175 #define STRUCT_TABLE_ELEMENT(NAME, Name, name) \ |
| 1119 { NAME##_TYPE, Name::kSize, k##Name##MapRootIndex }, | 1176 { NAME##_TYPE, Name::kSize, k##Name##MapRootIndex }, |
| 1120 STRUCT_LIST(STRUCT_TABLE_ELEMENT) | 1177 STRUCT_LIST(STRUCT_TABLE_ELEMENT) |
| 1121 #undef STRUCT_TABLE_ELEMENT | 1178 #undef STRUCT_TABLE_ELEMENT |
| 1122 }; | 1179 }; |
| 1123 | 1180 |
| 1124 | 1181 |
| 1125 bool Heap::CreateInitialMaps() { | 1182 bool Heap::CreateInitialMaps() { |
| 1183 HeapData& heap_data = v8_context()->heap_data_; |
| 1126 Object* obj = AllocatePartialMap(MAP_TYPE, Map::kSize); | 1184 Object* obj = AllocatePartialMap(MAP_TYPE, Map::kSize); |
| 1127 if (obj->IsFailure()) return false; | 1185 if (obj->IsFailure()) return false; |
| 1128 // Map::cast cannot be used due to uninitialized map field. | 1186 // Map::cast cannot be used due to uninitialized map field. |
| 1129 Map* new_meta_map = reinterpret_cast<Map*>(obj); | 1187 Map* new_meta_map = reinterpret_cast<Map*>(obj); |
| 1130 set_meta_map(new_meta_map); | 1188 set_meta_map(new_meta_map); |
| 1131 new_meta_map->set_map(new_meta_map); | 1189 new_meta_map->set_map(new_meta_map); |
| 1132 | 1190 |
| 1133 obj = AllocatePartialMap(FIXED_ARRAY_TYPE, FixedArray::kHeaderSize); | 1191 obj = AllocatePartialMap(FIXED_ARRAY_TYPE, FixedArray::kHeaderSize); |
| 1134 if (obj->IsFailure()) return false; | 1192 if (obj->IsFailure()) return false; |
| 1135 set_fixed_array_map(Map::cast(obj)); | 1193 set_fixed_array_map(Map::cast(obj)); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1177 set_heap_number_map(Map::cast(obj)); | 1235 set_heap_number_map(Map::cast(obj)); |
| 1178 | 1236 |
| 1179 obj = AllocateMap(PROXY_TYPE, Proxy::kSize); | 1237 obj = AllocateMap(PROXY_TYPE, Proxy::kSize); |
| 1180 if (obj->IsFailure()) return false; | 1238 if (obj->IsFailure()) return false; |
| 1181 set_proxy_map(Map::cast(obj)); | 1239 set_proxy_map(Map::cast(obj)); |
| 1182 | 1240 |
| 1183 for (unsigned i = 0; i < ARRAY_SIZE(string_type_table); i++) { | 1241 for (unsigned i = 0; i < ARRAY_SIZE(string_type_table); i++) { |
| 1184 const StringTypeTable& entry = string_type_table[i]; | 1242 const StringTypeTable& entry = string_type_table[i]; |
| 1185 obj = AllocateMap(entry.type, entry.size); | 1243 obj = AllocateMap(entry.type, entry.size); |
| 1186 if (obj->IsFailure()) return false; | 1244 if (obj->IsFailure()) return false; |
| 1187 roots_[entry.index] = Map::cast(obj); | 1245 heap_data.roots_[entry.index] = Map::cast(obj); |
| 1188 } | 1246 } |
| 1189 | 1247 |
| 1190 obj = AllocateMap(STRING_TYPE, SeqTwoByteString::kAlignedSize); | 1248 obj = AllocateMap(STRING_TYPE, SeqTwoByteString::kAlignedSize); |
| 1191 if (obj->IsFailure()) return false; | 1249 if (obj->IsFailure()) return false; |
| 1192 set_undetectable_string_map(Map::cast(obj)); | 1250 set_undetectable_string_map(Map::cast(obj)); |
| 1193 Map::cast(obj)->set_is_undetectable(); | 1251 Map::cast(obj)->set_is_undetectable(); |
| 1194 | 1252 |
| 1195 obj = AllocateMap(ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize); | 1253 obj = AllocateMap(ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize); |
| 1196 if (obj->IsFailure()) return false; | 1254 if (obj->IsFailure()) return false; |
| 1197 set_undetectable_ascii_string_map(Map::cast(obj)); | 1255 set_undetectable_ascii_string_map(Map::cast(obj)); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1254 set_one_pointer_filler_map(Map::cast(obj)); | 1312 set_one_pointer_filler_map(Map::cast(obj)); |
| 1255 | 1313 |
| 1256 obj = AllocateMap(FILLER_TYPE, 2 * kPointerSize); | 1314 obj = AllocateMap(FILLER_TYPE, 2 * kPointerSize); |
| 1257 if (obj->IsFailure()) return false; | 1315 if (obj->IsFailure()) return false; |
| 1258 set_two_pointer_filler_map(Map::cast(obj)); | 1316 set_two_pointer_filler_map(Map::cast(obj)); |
| 1259 | 1317 |
| 1260 for (unsigned i = 0; i < ARRAY_SIZE(struct_table); i++) { | 1318 for (unsigned i = 0; i < ARRAY_SIZE(struct_table); i++) { |
| 1261 const StructTable& entry = struct_table[i]; | 1319 const StructTable& entry = struct_table[i]; |
| 1262 obj = AllocateMap(entry.type, entry.size); | 1320 obj = AllocateMap(entry.type, entry.size); |
| 1263 if (obj->IsFailure()) return false; | 1321 if (obj->IsFailure()) return false; |
| 1264 roots_[entry.index] = Map::cast(obj); | 1322 heap_data.roots_[entry.index] = Map::cast(obj); |
| 1265 } | 1323 } |
| 1266 | 1324 |
| 1267 obj = AllocateMap(FIXED_ARRAY_TYPE, HeapObject::kHeaderSize); | 1325 obj = AllocateMap(FIXED_ARRAY_TYPE, HeapObject::kHeaderSize); |
| 1268 if (obj->IsFailure()) return false; | 1326 if (obj->IsFailure()) return false; |
| 1269 set_hash_table_map(Map::cast(obj)); | 1327 set_hash_table_map(Map::cast(obj)); |
| 1270 | 1328 |
| 1271 obj = AllocateMap(FIXED_ARRAY_TYPE, HeapObject::kHeaderSize); | 1329 obj = AllocateMap(FIXED_ARRAY_TYPE, HeapObject::kHeaderSize); |
| 1272 if (obj->IsFailure()) return false; | 1330 if (obj->IsFailure()) return false; |
| 1273 set_context_map(Map::cast(obj)); | 1331 set_context_map(Map::cast(obj)); |
| 1274 | 1332 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1311 } | 1369 } |
| 1312 | 1370 |
| 1313 | 1371 |
| 1314 Object* Heap::AllocateHeapNumber(double value) { | 1372 Object* Heap::AllocateHeapNumber(double value) { |
| 1315 // Use general version, if we're forced to always allocate. | 1373 // Use general version, if we're forced to always allocate. |
| 1316 if (always_allocate()) return AllocateHeapNumber(value, TENURED); | 1374 if (always_allocate()) return AllocateHeapNumber(value, TENURED); |
| 1317 | 1375 |
| 1318 // This version of AllocateHeapNumber is optimized for | 1376 // This version of AllocateHeapNumber is optimized for |
| 1319 // allocation in new space. | 1377 // allocation in new space. |
| 1320 STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxHeapObjectSize); | 1378 STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxHeapObjectSize); |
| 1321 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC); | 1379 HeapData& heap_data = v8_context()->heap_data_; |
| 1322 Object* result = new_space_.AllocateRaw(HeapNumber::kSize); | 1380 ASSERT(heap_data.allocation_allowed_ && heap_data.gc_state_ == NOT_IN_GC); |
| 1381 Object* result = heap_data.new_space_.AllocateRaw(HeapNumber::kSize); |
| 1323 if (result->IsFailure()) return result; | 1382 if (result->IsFailure()) return result; |
| 1324 HeapObject::cast(result)->set_map(heap_number_map()); | 1383 HeapObject::cast(result)->set_map(heap_number_map()); |
| 1325 HeapNumber::cast(result)->set_value(value); | 1384 HeapNumber::cast(result)->set_value(value); |
| 1326 return result; | 1385 return result; |
| 1327 } | 1386 } |
| 1328 | 1387 |
| 1329 | 1388 |
| 1330 Object* Heap::AllocateJSGlobalPropertyCell(Object* value) { | 1389 Object* Heap::AllocateJSGlobalPropertyCell(Object* value) { |
| 1331 Object* result = AllocateRawCell(); | 1390 Object* result = AllocateRawCell(); |
| 1332 if (result->IsFailure()) return result; | 1391 if (result->IsFailure()) return result; |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1415 Heap::CreateJSEntryStub(); | 1474 Heap::CreateJSEntryStub(); |
| 1416 Heap::CreateJSConstructEntryStub(); | 1475 Heap::CreateJSConstructEntryStub(); |
| 1417 #if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP | 1476 #if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP |
| 1418 Heap::CreateRegExpCEntryStub(); | 1477 Heap::CreateRegExpCEntryStub(); |
| 1419 #endif | 1478 #endif |
| 1420 } | 1479 } |
| 1421 | 1480 |
| 1422 | 1481 |
| 1423 bool Heap::CreateInitialObjects() { | 1482 bool Heap::CreateInitialObjects() { |
| 1424 Object* obj; | 1483 Object* obj; |
| 1484 HeapData& heap_data = v8_context()->heap_data_; |
| 1425 | 1485 |
| 1426 // The -0 value must be set before NumberFromDouble works. | 1486 // The -0 value must be set before NumberFromDouble works. |
| 1427 obj = AllocateHeapNumber(-0.0, TENURED); | 1487 obj = AllocateHeapNumber(-0.0, TENURED); |
| 1428 if (obj->IsFailure()) return false; | 1488 if (obj->IsFailure()) return false; |
| 1429 set_minus_zero_value(obj); | 1489 set_minus_zero_value(obj); |
| 1430 ASSERT(signbit(minus_zero_value()->Number()) != 0); | 1490 ASSERT(signbit(minus_zero_value()->Number()) != 0); |
| 1431 | 1491 |
| 1432 obj = AllocateHeapNumber(OS::nan_value(), TENURED); | 1492 obj = AllocateHeapNumber(OS::nan_value(), TENURED); |
| 1433 if (obj->IsFailure()) return false; | 1493 if (obj->IsFailure()) return false; |
| 1434 set_nan_value(obj); | 1494 set_nan_value(obj); |
| 1435 | 1495 |
| 1436 obj = Allocate(oddball_map(), OLD_DATA_SPACE); | 1496 obj = Allocate(oddball_map(), OLD_DATA_SPACE); |
| 1437 if (obj->IsFailure()) return false; | 1497 if (obj->IsFailure()) return false; |
| 1438 set_undefined_value(obj); | 1498 set_undefined_value(obj); |
| 1439 ASSERT(!InNewSpace(undefined_value())); | 1499 ASSERT(!InNewSpace(undefined_value())); |
| 1440 | 1500 |
| 1441 // Allocate initial symbol table. | 1501 // Allocate initial symbol table. |
| 1442 obj = SymbolTable::Allocate(kInitialSymbolTableSize); | 1502 obj = SymbolTable::Allocate(kInitialSymbolTableSize); |
| 1443 if (obj->IsFailure()) return false; | 1503 if (obj->IsFailure()) return false; |
| 1444 // Don't use set_symbol_table() due to asserts. | 1504 // Don't use set_symbol_table() due to asserts. |
| 1445 roots_[kSymbolTableRootIndex] = obj; | 1505 heap_data.roots_[kSymbolTableRootIndex] = obj; |
| 1446 | 1506 |
| 1447 // Assign the print strings for oddballs after creating symboltable. | 1507 // Assign the print strings for oddballs after creating symboltable. |
| 1448 Object* symbol = LookupAsciiSymbol("undefined"); | 1508 Object* symbol = LookupAsciiSymbol("undefined"); |
| 1449 if (symbol->IsFailure()) return false; | 1509 if (symbol->IsFailure()) return false; |
| 1450 Oddball::cast(undefined_value())->set_to_string(String::cast(symbol)); | 1510 Oddball::cast(undefined_value())->set_to_string(String::cast(symbol)); |
| 1451 Oddball::cast(undefined_value())->set_to_number(nan_value()); | 1511 Oddball::cast(undefined_value())->set_to_number(nan_value()); |
| 1452 | 1512 |
| 1453 // Assign the print strings for oddballs after creating symboltable. | 1513 // Assign the print strings for oddballs after creating symboltable. |
| 1454 symbol = LookupAsciiSymbol("null"); | 1514 symbol = LookupAsciiSymbol("null"); |
| 1455 if (symbol->IsFailure()) return false; | 1515 if (symbol->IsFailure()) return false; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1482 set_termination_exception(obj); | 1542 set_termination_exception(obj); |
| 1483 | 1543 |
| 1484 // Allocate the empty string. | 1544 // Allocate the empty string. |
| 1485 obj = AllocateRawAsciiString(0, TENURED); | 1545 obj = AllocateRawAsciiString(0, TENURED); |
| 1486 if (obj->IsFailure()) return false; | 1546 if (obj->IsFailure()) return false; |
| 1487 set_empty_string(String::cast(obj)); | 1547 set_empty_string(String::cast(obj)); |
| 1488 | 1548 |
| 1489 for (unsigned i = 0; i < ARRAY_SIZE(constant_symbol_table); i++) { | 1549 for (unsigned i = 0; i < ARRAY_SIZE(constant_symbol_table); i++) { |
| 1490 obj = LookupAsciiSymbol(constant_symbol_table[i].contents); | 1550 obj = LookupAsciiSymbol(constant_symbol_table[i].contents); |
| 1491 if (obj->IsFailure()) return false; | 1551 if (obj->IsFailure()) return false; |
| 1492 roots_[constant_symbol_table[i].index] = String::cast(obj); | 1552 heap_data.roots_[constant_symbol_table[i].index] = String::cast(obj); |
| 1493 } | 1553 } |
| 1494 | 1554 |
| 1495 // Allocate the hidden symbol which is used to identify the hidden properties | 1555 // Allocate the hidden symbol which is used to identify the hidden properties |
| 1496 // in JSObjects. The hash code has a special value so that it will not match | 1556 // in JSObjects. The hash code has a special value so that it will not match |
| 1497 // the empty string when searching for the property. It cannot be part of the | 1557 // the empty string when searching for the property. It cannot be part of the |
| 1498 // loop above because it needs to be allocated manually with the special | 1558 // loop above because it needs to be allocated manually with the special |
| 1499 // hash code in place. The hash code for the hidden_symbol is zero to ensure | 1559 // hash code in place. The hash code for the hidden_symbol is zero to ensure |
| 1500 // that it will always be at the first entry in property descriptors. | 1560 // that it will always be at the first entry in property descriptors. |
| 1501 obj = AllocateSymbol(CStrVector(""), 0, String::kHashComputedMask); | 1561 obj = AllocateSymbol(CStrVector(""), 0, String::kHashComputedMask); |
| 1502 if (obj->IsFailure()) return false; | 1562 if (obj->IsFailure()) return false; |
| 1503 hidden_symbol_ = String::cast(obj); | 1563 heap_data.hidden_symbol_ = String::cast(obj); |
| 1504 | 1564 |
| 1505 // Allocate the proxy for __proto__. | 1565 // Allocate the proxy for __proto__. |
| 1506 obj = AllocateProxy((Address) &Accessors::ObjectPrototype); | 1566 obj = AllocateProxy((Address) &Accessors::ObjectPrototype); |
| 1507 if (obj->IsFailure()) return false; | 1567 if (obj->IsFailure()) return false; |
| 1508 set_prototype_accessors(Proxy::cast(obj)); | 1568 set_prototype_accessors(Proxy::cast(obj)); |
| 1509 | 1569 |
| 1510 // Allocate the code_stubs dictionary. The initial size is set to avoid | 1570 // Allocate the code_stubs dictionary. The initial size is set to avoid |
| 1511 // expanding the dictionary during bootstrapping. | 1571 // expanding the dictionary during bootstrapping. |
| 1512 obj = NumberDictionary::Allocate(128); | 1572 obj = NumberDictionary::Allocate(128); |
| 1513 if (obj->IsFailure()) return false; | 1573 if (obj->IsFailure()) return false; |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1654 Object* result = AllocateStringFromAscii(CStrVector(str)); | 1714 Object* result = AllocateStringFromAscii(CStrVector(str)); |
| 1655 | 1715 |
| 1656 if (!result->IsFailure()) { | 1716 if (!result->IsFailure()) { |
| 1657 SetNumberStringCache(number, String::cast(result)); | 1717 SetNumberStringCache(number, String::cast(result)); |
| 1658 } | 1718 } |
| 1659 return result; | 1719 return result; |
| 1660 } | 1720 } |
| 1661 | 1721 |
| 1662 | 1722 |
| 1663 Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) { | 1723 Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) { |
| 1664 return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]); | 1724 return Map::cast(v8_context()->heap_data_.roots_[ |
| 1725 RootIndexForExternalArrayType(array_type)]); |
| 1665 } | 1726 } |
| 1666 | 1727 |
| 1667 | 1728 |
| 1668 Heap::RootListIndex Heap::RootIndexForExternalArrayType( | 1729 Heap::RootListIndex Heap::RootIndexForExternalArrayType( |
| 1669 ExternalArrayType array_type) { | 1730 ExternalArrayType array_type) { |
| 1670 switch (array_type) { | 1731 switch (array_type) { |
| 1671 case kExternalByteArray: | 1732 case kExternalByteArray: |
| 1672 return kExternalByteArrayMapRootIndex; | 1733 return kExternalByteArrayMapRootIndex; |
| 1673 case kExternalUnsignedByteArray: | 1734 case kExternalUnsignedByteArray: |
| 1674 return kExternalUnsignedByteArrayMapRootIndex; | 1735 return kExternalUnsignedByteArrayMapRootIndex; |
| (...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2059 external_pointer); | 2120 external_pointer); |
| 2060 | 2121 |
| 2061 return result; | 2122 return result; |
| 2062 } | 2123 } |
| 2063 | 2124 |
| 2064 | 2125 |
| 2065 Object* Heap::CreateCode(const CodeDesc& desc, | 2126 Object* Heap::CreateCode(const CodeDesc& desc, |
| 2066 ZoneScopeInfo* sinfo, | 2127 ZoneScopeInfo* sinfo, |
| 2067 Code::Flags flags, | 2128 Code::Flags flags, |
| 2068 Handle<Object> self_reference) { | 2129 Handle<Object> self_reference) { |
| 2130 HeapData& heap_data = v8_context()->heap_data_; |
| 2069 // Compute size | 2131 // Compute size |
| 2070 int body_size = RoundUp(desc.instr_size + desc.reloc_size, kObjectAlignment); | 2132 int body_size = RoundUp(desc.instr_size + desc.reloc_size, kObjectAlignment); |
| 2071 int sinfo_size = 0; | 2133 int sinfo_size = 0; |
| 2072 if (sinfo != NULL) sinfo_size = sinfo->Serialize(NULL); | 2134 if (sinfo != NULL) sinfo_size = sinfo->Serialize(NULL); |
| 2073 int obj_size = Code::SizeFor(body_size, sinfo_size); | 2135 int obj_size = Code::SizeFor(body_size, sinfo_size); |
| 2074 ASSERT(IsAligned(obj_size, Code::kCodeAlignment)); | 2136 ASSERT(IsAligned(obj_size, Code::kCodeAlignment)); |
| 2075 Object* result; | 2137 Object* result; |
| 2076 if (obj_size > MaxObjectSizeInPagedSpace()) { | 2138 if (obj_size > MaxObjectSizeInPagedSpace()) { |
| 2077 result = lo_space_->AllocateRawCode(obj_size); | 2139 result = heap_data.lo_space_->AllocateRawCode(obj_size); |
| 2078 } else { | 2140 } else { |
| 2079 result = code_space_->AllocateRaw(obj_size); | 2141 result = heap_data.code_space_->AllocateRaw(obj_size); |
| 2080 } | 2142 } |
| 2081 | 2143 |
| 2082 if (result->IsFailure()) return result; | 2144 if (result->IsFailure()) return result; |
| 2083 | 2145 |
| 2084 // Initialize the object | 2146 // Initialize the object |
| 2085 HeapObject::cast(result)->set_map(code_map()); | 2147 HeapObject::cast(result)->set_map(code_map()); |
| 2086 Code* code = Code::cast(result); | 2148 Code* code = Code::cast(result); |
| 2087 ASSERT(!CodeRange::exists() || CodeRange::contains(code->address())); | 2149 ASSERT(!CodeRange::exists() || CodeRange::contains(code->address())); |
| 2088 code->set_instruction_size(desc.instr_size); | 2150 code->set_instruction_size(desc.instr_size); |
| 2089 code->set_relocation_size(desc.reloc_size); | 2151 code->set_relocation_size(desc.reloc_size); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2103 if (sinfo != NULL) sinfo->Serialize(code); // write scope info | 2165 if (sinfo != NULL) sinfo->Serialize(code); // write scope info |
| 2104 | 2166 |
| 2105 #ifdef DEBUG | 2167 #ifdef DEBUG |
| 2106 code->Verify(); | 2168 code->Verify(); |
| 2107 #endif | 2169 #endif |
| 2108 return code; | 2170 return code; |
| 2109 } | 2171 } |
| 2110 | 2172 |
| 2111 | 2173 |
| 2112 Object* Heap::CopyCode(Code* code) { | 2174 Object* Heap::CopyCode(Code* code) { |
| 2175 HeapData& heap_data = v8_context()->heap_data_; |
| 2113 // Allocate an object the same size as the code object. | 2176 // Allocate an object the same size as the code object. |
| 2114 int obj_size = code->Size(); | 2177 int obj_size = code->Size(); |
| 2115 Object* result; | 2178 Object* result; |
| 2116 if (obj_size > MaxObjectSizeInPagedSpace()) { | 2179 if (obj_size > MaxObjectSizeInPagedSpace()) { |
| 2117 result = lo_space_->AllocateRawCode(obj_size); | 2180 result = heap_data.lo_space_->AllocateRawCode(obj_size); |
| 2118 } else { | 2181 } else { |
| 2119 result = code_space_->AllocateRaw(obj_size); | 2182 result = heap_data.code_space_->AllocateRaw(obj_size); |
| 2120 } | 2183 } |
| 2121 | 2184 |
| 2122 if (result->IsFailure()) return result; | 2185 if (result->IsFailure()) return result; |
| 2123 | 2186 |
| 2124 // Copy code object. | 2187 // Copy code object. |
| 2125 Address old_addr = code->address(); | 2188 Address old_addr = code->address(); |
| 2126 Address new_addr = reinterpret_cast<HeapObject*>(result)->address(); | 2189 Address new_addr = reinterpret_cast<HeapObject*>(result)->address(); |
| 2127 CopyBlock(reinterpret_cast<Object**>(new_addr), | 2190 CopyBlock(reinterpret_cast<Object**>(new_addr), |
| 2128 reinterpret_cast<Object**>(old_addr), | 2191 reinterpret_cast<Object**>(old_addr), |
| 2129 obj_size); | 2192 obj_size); |
| 2130 // Relocate the copy. | 2193 // Relocate the copy. |
| 2131 Code* new_code = Code::cast(result); | 2194 Code* new_code = Code::cast(result); |
| 2132 ASSERT(!CodeRange::exists() || CodeRange::contains(code->address())); | 2195 ASSERT(!CodeRange::exists() || CodeRange::contains(code->address())); |
| 2133 new_code->Relocate(new_addr - old_addr); | 2196 new_code->Relocate(new_addr - old_addr); |
| 2134 return new_code; | 2197 return new_code; |
| 2135 } | 2198 } |
| 2136 | 2199 |
| 2137 | 2200 |
| 2138 Object* Heap::Allocate(Map* map, AllocationSpace space) { | 2201 Object* Heap::Allocate(Map* map, AllocationSpace space) { |
| 2139 ASSERT(gc_state_ == NOT_IN_GC); | 2202 ASSERT(v8_context()->heap_data_.gc_state_ == NOT_IN_GC); |
| 2140 ASSERT(map->instance_type() != MAP_TYPE); | 2203 ASSERT(map->instance_type() != MAP_TYPE); |
| 2141 Object* result = AllocateRaw(map->instance_size(), | 2204 Object* result = AllocateRaw(map->instance_size(), |
| 2142 space, | 2205 space, |
| 2143 TargetSpaceId(map->instance_type())); | 2206 TargetSpaceId(map->instance_type())); |
| 2144 if (result->IsFailure()) return result; | 2207 if (result->IsFailure()) return result; |
| 2145 HeapObject::cast(result)->set_map(map); | 2208 HeapObject::cast(result)->set_map(map); |
| 2146 #ifdef ENABLE_LOGGING_AND_PROFILING | 2209 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 2147 ProducerHeapProfile::RecordJSObjectAllocation(result); | 2210 ProducerHeapProfile::RecordJSObjectAllocation(result); |
| 2148 #endif | 2211 #endif |
| 2149 return result; | 2212 return result; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2191 return InitializeFunction(JSFunction::cast(result), shared, prototype); | 2254 return InitializeFunction(JSFunction::cast(result), shared, prototype); |
| 2192 } | 2255 } |
| 2193 | 2256 |
| 2194 | 2257 |
| 2195 Object* Heap::AllocateArgumentsObject(Object* callee, int length) { | 2258 Object* Heap::AllocateArgumentsObject(Object* callee, int length) { |
| 2196 // To get fast allocation and map sharing for arguments objects we | 2259 // To get fast allocation and map sharing for arguments objects we |
| 2197 // allocate them based on an arguments boilerplate. | 2260 // allocate them based on an arguments boilerplate. |
| 2198 | 2261 |
| 2199 // This calls Copy directly rather than using Heap::AllocateRaw so we | 2262 // This calls Copy directly rather than using Heap::AllocateRaw so we |
| 2200 // duplicate the check here. | 2263 // duplicate the check here. |
| 2201 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC); | 2264 HeapData& heap_data = v8_context()->heap_data_; |
| 2265 ASSERT(heap_data.allocation_allowed_ && heap_data.gc_state_ == NOT_IN_GC); |
| 2202 | 2266 |
| 2203 JSObject* boilerplate = | 2267 JSObject* boilerplate = |
| 2204 Top::context()->global_context()->arguments_boilerplate(); | 2268 Top::context()->global_context()->arguments_boilerplate(); |
| 2205 | 2269 |
| 2206 // Make the clone. | 2270 // Make the clone. |
| 2207 Map* map = boilerplate->map(); | 2271 Map* map = boilerplate->map(); |
| 2208 int object_size = map->instance_size(); | 2272 int object_size = map->instance_size(); |
| 2209 Object* result = AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE); | 2273 Object* result = AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE); |
| 2210 if (result->IsFailure()) return result; | 2274 if (result->IsFailure()) return result; |
| 2211 | 2275 |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2436 CopyBlock(reinterpret_cast<Object**>(clone_address), | 2500 CopyBlock(reinterpret_cast<Object**>(clone_address), |
| 2437 reinterpret_cast<Object**>(source->address()), | 2501 reinterpret_cast<Object**>(source->address()), |
| 2438 object_size); | 2502 object_size); |
| 2439 // Update write barrier for all fields that lie beyond the header. | 2503 // Update write barrier for all fields that lie beyond the header. |
| 2440 for (int offset = JSObject::kHeaderSize; | 2504 for (int offset = JSObject::kHeaderSize; |
| 2441 offset < object_size; | 2505 offset < object_size; |
| 2442 offset += kPointerSize) { | 2506 offset += kPointerSize) { |
| 2443 RecordWrite(clone_address, offset); | 2507 RecordWrite(clone_address, offset); |
| 2444 } | 2508 } |
| 2445 } else { | 2509 } else { |
| 2446 clone = new_space_.AllocateRaw(object_size); | 2510 clone = v8_context()->heap_data_.new_space_.AllocateRaw(object_size); |
| 2447 if (clone->IsFailure()) return clone; | 2511 if (clone->IsFailure()) return clone; |
| 2448 ASSERT(Heap::InNewSpace(clone)); | 2512 ASSERT(Heap::InNewSpace(clone)); |
| 2449 // Since we know the clone is allocated in new space, we can copy | 2513 // Since we know the clone is allocated in new space, we can copy |
| 2450 // the contents without worrying about updating the write barrier. | 2514 // the contents without worrying about updating the write barrier. |
| 2451 CopyBlock(reinterpret_cast<Object**>(HeapObject::cast(clone)->address()), | 2515 CopyBlock(reinterpret_cast<Object**>(HeapObject::cast(clone)->address()), |
| 2452 reinterpret_cast<Object**>(source->address()), | 2516 reinterpret_cast<Object**>(source->address()), |
| 2453 object_size); | 2517 object_size); |
| 2454 } | 2518 } |
| 2455 | 2519 |
| 2456 FixedArray* elements = FixedArray::cast(source->elements()); | 2520 FixedArray* elements = FixedArray::cast(source->elements()); |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2643 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; | 2707 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; |
| 2644 | 2708 |
| 2645 // New space can't cope with forced allocation. | 2709 // New space can't cope with forced allocation. |
| 2646 if (always_allocate()) space = OLD_DATA_SPACE; | 2710 if (always_allocate()) space = OLD_DATA_SPACE; |
| 2647 | 2711 |
| 2648 int size = SeqAsciiString::SizeFor(length); | 2712 int size = SeqAsciiString::SizeFor(length); |
| 2649 | 2713 |
| 2650 Object* result = Failure::OutOfMemoryException(); | 2714 Object* result = Failure::OutOfMemoryException(); |
| 2651 if (space == NEW_SPACE) { | 2715 if (space == NEW_SPACE) { |
| 2652 result = size <= kMaxObjectSizeInNewSpace | 2716 result = size <= kMaxObjectSizeInNewSpace |
| 2653 ? new_space_.AllocateRaw(size) | 2717 ? v8_context()->heap_data_.new_space_.AllocateRaw(size) |
| 2654 : lo_space_->AllocateRaw(size); | 2718 : v8_context()->heap_data_.lo_space_->AllocateRaw(size); |
| 2655 } else { | 2719 } else { |
| 2656 if (size > MaxObjectSizeInPagedSpace()) space = LO_SPACE; | 2720 if (size > MaxObjectSizeInPagedSpace()) space = LO_SPACE; |
| 2657 result = AllocateRaw(size, space, OLD_DATA_SPACE); | 2721 result = AllocateRaw(size, space, OLD_DATA_SPACE); |
| 2658 } | 2722 } |
| 2659 if (result->IsFailure()) return result; | 2723 if (result->IsFailure()) return result; |
| 2660 | 2724 |
| 2661 // Partially initialize the object. | 2725 // Partially initialize the object. |
| 2662 HeapObject::cast(result)->set_map(ascii_string_map()); | 2726 HeapObject::cast(result)->set_map(ascii_string_map()); |
| 2663 String::cast(result)->set_length(length); | 2727 String::cast(result)->set_length(length); |
| 2664 String::cast(result)->set_hash_field(String::kEmptyHashField); | 2728 String::cast(result)->set_hash_field(String::kEmptyHashField); |
| 2665 ASSERT_EQ(size, HeapObject::cast(result)->Size()); | 2729 ASSERT_EQ(size, HeapObject::cast(result)->Size()); |
| 2666 return result; | 2730 return result; |
| 2667 } | 2731 } |
| 2668 | 2732 |
| 2669 | 2733 |
| 2670 Object* Heap::AllocateRawTwoByteString(int length, PretenureFlag pretenure) { | 2734 Object* Heap::AllocateRawTwoByteString(int length, PretenureFlag pretenure) { |
| 2671 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; | 2735 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; |
| 2672 | 2736 |
| 2673 // New space can't cope with forced allocation. | 2737 // New space can't cope with forced allocation. |
| 2674 if (always_allocate()) space = OLD_DATA_SPACE; | 2738 if (always_allocate()) space = OLD_DATA_SPACE; |
| 2675 | 2739 |
| 2676 int size = SeqTwoByteString::SizeFor(length); | 2740 int size = SeqTwoByteString::SizeFor(length); |
| 2677 | 2741 |
| 2678 Object* result = Failure::OutOfMemoryException(); | 2742 Object* result = Failure::OutOfMemoryException(); |
| 2679 if (space == NEW_SPACE) { | 2743 if (space == NEW_SPACE) { |
| 2680 result = size <= kMaxObjectSizeInNewSpace | 2744 result = size <= kMaxObjectSizeInNewSpace |
| 2681 ? new_space_.AllocateRaw(size) | 2745 ? v8_context()->heap_data_.new_space_.AllocateRaw(size) |
| 2682 : lo_space_->AllocateRaw(size); | 2746 : v8_context()->heap_data_.lo_space_->AllocateRaw(size); |
| 2683 } else { | 2747 } else { |
| 2684 if (size > MaxObjectSizeInPagedSpace()) space = LO_SPACE; | 2748 if (size > MaxObjectSizeInPagedSpace()) space = LO_SPACE; |
| 2685 result = AllocateRaw(size, space, OLD_DATA_SPACE); | 2749 result = AllocateRaw(size, space, OLD_DATA_SPACE); |
| 2686 } | 2750 } |
| 2687 if (result->IsFailure()) return result; | 2751 if (result->IsFailure()) return result; |
| 2688 | 2752 |
| 2689 // Partially initialize the object. | 2753 // Partially initialize the object. |
| 2690 HeapObject::cast(result)->set_map(string_map()); | 2754 HeapObject::cast(result)->set_map(string_map()); |
| 2691 String::cast(result)->set_length(length); | 2755 String::cast(result)->set_length(length); |
| 2692 String::cast(result)->set_hash_field(String::kEmptyHashField); | 2756 String::cast(result)->set_hash_field(String::kEmptyHashField); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2705 return result; | 2769 return result; |
| 2706 } | 2770 } |
| 2707 | 2771 |
| 2708 | 2772 |
| 2709 Object* Heap::AllocateRawFixedArray(int length) { | 2773 Object* Heap::AllocateRawFixedArray(int length) { |
| 2710 // Use the general function if we're forced to always allocate. | 2774 // Use the general function if we're forced to always allocate. |
| 2711 if (always_allocate()) return AllocateFixedArray(length, TENURED); | 2775 if (always_allocate()) return AllocateFixedArray(length, TENURED); |
| 2712 // Allocate the raw data for a fixed array. | 2776 // Allocate the raw data for a fixed array. |
| 2713 int size = FixedArray::SizeFor(length); | 2777 int size = FixedArray::SizeFor(length); |
| 2714 return size <= kMaxObjectSizeInNewSpace | 2778 return size <= kMaxObjectSizeInNewSpace |
| 2715 ? new_space_.AllocateRaw(size) | 2779 ? v8_context()->heap_data_.new_space_.AllocateRaw(size) |
| 2716 : lo_space_->AllocateRawFixedArray(size); | 2780 : v8_context()->heap_data_.lo_space_->AllocateRawFixedArray(size); |
| 2717 } | 2781 } |
| 2718 | 2782 |
| 2719 | 2783 |
| 2720 Object* Heap::CopyFixedArray(FixedArray* src) { | 2784 Object* Heap::CopyFixedArray(FixedArray* src) { |
| 2721 int len = src->length(); | 2785 int len = src->length(); |
| 2722 Object* obj = AllocateRawFixedArray(len); | 2786 Object* obj = AllocateRawFixedArray(len); |
| 2723 if (obj->IsFailure()) return obj; | 2787 if (obj->IsFailure()) return obj; |
| 2724 if (Heap::InNewSpace(obj)) { | 2788 if (Heap::InNewSpace(obj)) { |
| 2725 HeapObject* dst = HeapObject::cast(obj); | 2789 HeapObject* dst = HeapObject::cast(obj); |
| 2726 CopyBlock(reinterpret_cast<Object**>(dst->address()), | 2790 CopyBlock(reinterpret_cast<Object**>(dst->address()), |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2759 | 2823 |
| 2760 Object* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) { | 2824 Object* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) { |
| 2761 ASSERT(empty_fixed_array()->IsFixedArray()); | 2825 ASSERT(empty_fixed_array()->IsFixedArray()); |
| 2762 if (length == 0) return empty_fixed_array(); | 2826 if (length == 0) return empty_fixed_array(); |
| 2763 | 2827 |
| 2764 // New space can't cope with forced allocation. | 2828 // New space can't cope with forced allocation. |
| 2765 if (always_allocate()) pretenure = TENURED; | 2829 if (always_allocate()) pretenure = TENURED; |
| 2766 | 2830 |
| 2767 int size = FixedArray::SizeFor(length); | 2831 int size = FixedArray::SizeFor(length); |
| 2768 Object* result = Failure::OutOfMemoryException(); | 2832 Object* result = Failure::OutOfMemoryException(); |
| 2833 HeapData& heap_data = v8_context()->heap_data_; |
| 2769 if (pretenure != TENURED) { | 2834 if (pretenure != TENURED) { |
| 2770 result = size <= kMaxObjectSizeInNewSpace | 2835 result = size <= kMaxObjectSizeInNewSpace |
| 2771 ? new_space_.AllocateRaw(size) | 2836 ? heap_data.new_space_.AllocateRaw(size) |
| 2772 : lo_space_->AllocateRawFixedArray(size); | 2837 : heap_data.lo_space_->AllocateRawFixedArray(size); |
| 2773 } | 2838 } |
| 2774 if (result->IsFailure()) { | 2839 if (result->IsFailure()) { |
| 2775 if (size > MaxObjectSizeInPagedSpace()) { | 2840 if (size > MaxObjectSizeInPagedSpace()) { |
| 2776 result = lo_space_->AllocateRawFixedArray(size); | 2841 result = heap_data.lo_space_->AllocateRawFixedArray(size); |
| 2777 } else { | 2842 } else { |
| 2778 AllocationSpace space = | 2843 AllocationSpace space = |
| 2779 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE; | 2844 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE; |
| 2780 result = AllocateRaw(size, space, OLD_POINTER_SPACE); | 2845 result = AllocateRaw(size, space, OLD_POINTER_SPACE); |
| 2781 } | 2846 } |
| 2782 if (result->IsFailure()) return result; | 2847 if (result->IsFailure()) return result; |
| 2783 } | 2848 } |
| 2784 // Initialize the object. | 2849 // Initialize the object. |
| 2785 reinterpret_cast<Array*>(result)->set_map(fixed_array_map()); | 2850 reinterpret_cast<Array*>(result)->set_map(fixed_array_map()); |
| 2786 FixedArray* array = FixedArray::cast(result); | 2851 FixedArray* array = FixedArray::cast(result); |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2885 if (result->IsFailure()) return result; | 2950 if (result->IsFailure()) return result; |
| 2886 Struct::cast(result)->InitializeBody(size); | 2951 Struct::cast(result)->InitializeBody(size); |
| 2887 return result; | 2952 return result; |
| 2888 } | 2953 } |
| 2889 | 2954 |
| 2890 | 2955 |
| 2891 bool Heap::IdleNotification() { | 2956 bool Heap::IdleNotification() { |
| 2892 static const int kIdlesBeforeScavenge = 4; | 2957 static const int kIdlesBeforeScavenge = 4; |
| 2893 static const int kIdlesBeforeMarkSweep = 7; | 2958 static const int kIdlesBeforeMarkSweep = 7; |
| 2894 static const int kIdlesBeforeMarkCompact = 8; | 2959 static const int kIdlesBeforeMarkCompact = 8; |
| 2895 static int number_idle_notifications = 0; | |
| 2896 static int last_gc_count = gc_count_; | |
| 2897 | 2960 |
| 2961 HeapData& heap_data = v8_context()->heap_data_; |
| 2962 HeapPrivateData& heap_private_data = heap_data.heap_private_data_; |
| 2898 bool finished = false; | 2963 bool finished = false; |
| 2899 | 2964 |
| 2900 if (last_gc_count == gc_count_) { | 2965 if (heap_private_data.last_gc_count_ == heap_data.gc_count_) { |
| 2901 number_idle_notifications++; | 2966 heap_private_data.number_idle_notifications_++; |
| 2902 } else { | 2967 } else { |
| 2903 number_idle_notifications = 0; | 2968 heap_private_data.number_idle_notifications_ = 0; |
| 2904 last_gc_count = gc_count_; | 2969 heap_private_data.last_gc_count_ = heap_data.gc_count_; |
| 2905 } | 2970 } |
| 2906 | 2971 |
| 2907 if (number_idle_notifications == kIdlesBeforeScavenge) { | 2972 if (heap_private_data.number_idle_notifications_ == kIdlesBeforeScavenge) { |
| 2908 CollectGarbage(0, NEW_SPACE); | 2973 CollectGarbage(0, NEW_SPACE); |
| 2909 new_space_.Shrink(); | 2974 heap_data.new_space_.Shrink(); |
| 2910 last_gc_count = gc_count_; | 2975 heap_private_data.last_gc_count_ = heap_data.gc_count_; |
| 2911 | 2976 |
| 2912 } else if (number_idle_notifications == kIdlesBeforeMarkSweep) { | 2977 } else if (heap_private_data.number_idle_notifications_ == |
| 2978 kIdlesBeforeMarkSweep) { |
| 2913 // Before doing the mark-sweep collections we clear the | 2979 // Before doing the mark-sweep collections we clear the |
| 2914 // compilation cache to avoid hanging on to source code and | 2980 // compilation cache to avoid hanging on to source code and |
| 2915 // generated code for cached functions. | 2981 // generated code for cached functions. |
| 2916 CompilationCache::Clear(); | 2982 CompilationCache::Clear(); |
| 2917 | 2983 |
| 2918 CollectAllGarbage(false); | 2984 CollectAllGarbage(false); |
| 2919 new_space_.Shrink(); | 2985 heap_data.new_space_.Shrink(); |
| 2920 last_gc_count = gc_count_; | 2986 heap_private_data.last_gc_count_ = heap_data.gc_count_; |
| 2921 | 2987 |
| 2922 } else if (number_idle_notifications == kIdlesBeforeMarkCompact) { | 2988 } else if (heap_private_data.number_idle_notifications_ == |
| 2989 kIdlesBeforeMarkCompact) { |
| 2923 CollectAllGarbage(true); | 2990 CollectAllGarbage(true); |
| 2924 new_space_.Shrink(); | 2991 heap_data.new_space_.Shrink(); |
| 2925 last_gc_count = gc_count_; | 2992 heap_private_data.last_gc_count_ = heap_data.gc_count_; |
| 2926 number_idle_notifications = 0; | 2993 heap_private_data.number_idle_notifications_ = 0; |
| 2927 finished = true; | 2994 finished = true; |
| 2928 } | 2995 } |
| 2929 | 2996 |
| 2930 // Uncommit unused memory in new space. | 2997 // Uncommit unused memory in new space. |
| 2931 Heap::UncommitFromSpace(); | 2998 Heap::UncommitFromSpace(); |
| 2932 return finished; | 2999 return finished; |
| 2933 } | 3000 } |
| 2934 | 3001 |
| 2935 | 3002 |
| 2936 #ifdef DEBUG | 3003 #ifdef DEBUG |
| 2937 | 3004 |
| 2938 void Heap::Print() { | 3005 void Heap::Print() { |
| 2939 if (!HasBeenSetup()) return; | 3006 if (!HasBeenSetup()) return; |
| 2940 Top::PrintStack(); | 3007 Top::PrintStack(); |
| 2941 AllSpaces spaces; | 3008 AllSpaces spaces; |
| 2942 while (Space* space = spaces.next()) space->Print(); | 3009 while (Space* space = spaces.next()) space->Print(); |
| 2943 } | 3010 } |
| 2944 | 3011 |
| 2945 | 3012 |
| 2946 void Heap::ReportCodeStatistics(const char* title) { | 3013 void Heap::ReportCodeStatistics(const char* title) { |
| 3014 HeapData& heap_data = v8_context()->heap_data_; |
| 2947 PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title); | 3015 PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title); |
| 2948 PagedSpace::ResetCodeStatistics(); | 3016 PagedSpace::ResetCodeStatistics(); |
| 2949 // We do not look for code in new space, map space, or old space. If code | 3017 // We do not look for code in new space, map space, or old space. If code |
| 2950 // somehow ends up in those spaces, we would miss it here. | 3018 // somehow ends up in those spaces, we would miss it here. |
| 2951 code_space_->CollectCodeStatistics(); | 3019 heap_data.code_space_->CollectCodeStatistics(); |
| 2952 lo_space_->CollectCodeStatistics(); | 3020 heap_data.lo_space_->CollectCodeStatistics(); |
| 2953 PagedSpace::ReportCodeStatistics(); | 3021 PagedSpace::ReportCodeStatistics(); |
| 2954 } | 3022 } |
| 2955 | 3023 |
| 2956 | 3024 |
| 2957 // This function expects that NewSpace's allocated objects histogram is | 3025 // This function expects that NewSpace's allocated objects histogram is |
| 2958 // populated (via a call to CollectStatistics or else as a side effect of a | 3026 // populated (via a call to CollectStatistics or else as a side effect of a |
| 2959 // just-completed scavenge collection). | 3027 // just-completed scavenge collection). |
| 2960 void Heap::ReportHeapStatistics(const char* title) { | 3028 void Heap::ReportHeapStatistics(const char* title) { |
| 3029 HeapData& heap_data = v8_context()->heap_data_; |
| 3030 |
| 2961 USE(title); | 3031 USE(title); |
| 2962 PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n", | 3032 PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n", |
| 2963 title, gc_count_); | 3033 title, heap_data.gc_count_); |
| 2964 PrintF("mark-compact GC : %d\n", mc_count_); | 3034 PrintF("mark-compact GC : %d\n", heap_data.mc_count_); |
| 2965 PrintF("old_gen_promotion_limit_ %d\n", old_gen_promotion_limit_); | 3035 PrintF("old_gen_promotion_limit_ %d\n", heap_data.old_gen_promotion_limit_); |
| 2966 PrintF("old_gen_allocation_limit_ %d\n", old_gen_allocation_limit_); | 3036 PrintF("old_gen_allocation_limit_ %d\n", heap_data.old_gen_allocation_limit_); |
| 2967 | 3037 |
| 2968 PrintF("\n"); | 3038 PrintF("\n"); |
| 2969 PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles()); | 3039 PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles()); |
| 2970 GlobalHandles::PrintStats(); | 3040 GlobalHandles::PrintStats(); |
| 2971 PrintF("\n"); | 3041 PrintF("\n"); |
| 2972 | 3042 |
| 2973 PrintF("Heap statistics : "); | 3043 PrintF("Heap statistics : "); |
| 2974 MemoryAllocator::ReportStatistics(); | 3044 MemoryAllocator::ReportStatistics(); |
| 2975 PrintF("To space : "); | 3045 PrintF("To space : "); |
| 2976 new_space_.ReportStatistics(); | 3046 heap_data.new_space_.ReportStatistics(); |
| 2977 PrintF("Old pointer space : "); | 3047 PrintF("Old pointer space : "); |
| 2978 old_pointer_space_->ReportStatistics(); | 3048 heap_data.old_pointer_space_->ReportStatistics(); |
| 2979 PrintF("Old data space : "); | 3049 PrintF("Old data space : "); |
| 2980 old_data_space_->ReportStatistics(); | 3050 heap_data.old_data_space_->ReportStatistics(); |
| 2981 PrintF("Code space : "); | 3051 PrintF("Code space : "); |
| 2982 code_space_->ReportStatistics(); | 3052 heap_data.code_space_->ReportStatistics(); |
| 2983 PrintF("Map space : "); | 3053 PrintF("Map space : "); |
| 2984 map_space_->ReportStatistics(); | 3054 heap_data.map_space_->ReportStatistics(); |
| 2985 PrintF("Cell space : "); | 3055 PrintF("Cell space : "); |
| 2986 cell_space_->ReportStatistics(); | 3056 heap_data.cell_space_->ReportStatistics(); |
| 2987 PrintF("Large object space : "); | 3057 PrintF("Large object space : "); |
| 2988 lo_space_->ReportStatistics(); | 3058 heap_data.lo_space_->ReportStatistics(); |
| 2989 PrintF(">>>>>> ========================================= >>>>>>\n"); | 3059 PrintF(">>>>>> ========================================= >>>>>>\n"); |
| 2990 } | 3060 } |
| 2991 | 3061 |
| 2992 #endif // DEBUG | 3062 #endif // DEBUG |
| 2993 | 3063 |
| 2994 bool Heap::Contains(HeapObject* value) { | 3064 bool Heap::Contains(HeapObject* value) { |
| 2995 return Contains(value->address()); | 3065 return Contains(value->address()); |
| 2996 } | 3066 } |
| 2997 | 3067 |
| 2998 | 3068 |
| 2999 bool Heap::Contains(Address addr) { | 3069 bool Heap::Contains(Address addr) { |
| 3000 if (OS::IsOutsideAllocatedSpace(addr)) return false; | 3070 if (OS::IsOutsideAllocatedSpace(addr)) return false; |
| 3071 HeapData& heap_data = v8_context()->heap_data_; |
| 3001 return HasBeenSetup() && | 3072 return HasBeenSetup() && |
| 3002 (new_space_.ToSpaceContains(addr) || | 3073 (heap_data.new_space_.ToSpaceContains(addr) || |
| 3003 old_pointer_space_->Contains(addr) || | 3074 heap_data.old_pointer_space_->Contains(addr) || |
| 3004 old_data_space_->Contains(addr) || | 3075 heap_data.old_data_space_->Contains(addr) || |
| 3005 code_space_->Contains(addr) || | 3076 heap_data.code_space_->Contains(addr) || |
| 3006 map_space_->Contains(addr) || | 3077 heap_data.map_space_->Contains(addr) || |
| 3007 cell_space_->Contains(addr) || | 3078 heap_data.cell_space_->Contains(addr) || |
| 3008 lo_space_->SlowContains(addr)); | 3079 heap_data.lo_space_->SlowContains(addr)); |
| 3009 } | 3080 } |
| 3010 | 3081 |
| 3011 | 3082 |
| 3012 bool Heap::InSpace(HeapObject* value, AllocationSpace space) { | 3083 bool Heap::InSpace(HeapObject* value, AllocationSpace space) { |
| 3013 return InSpace(value->address(), space); | 3084 return InSpace(value->address(), space); |
| 3014 } | 3085 } |
| 3015 | 3086 |
| 3016 | 3087 |
| 3017 bool Heap::InSpace(Address addr, AllocationSpace space) { | 3088 bool Heap::InSpace(Address addr, AllocationSpace space) { |
| 3018 if (OS::IsOutsideAllocatedSpace(addr)) return false; | 3089 if (OS::IsOutsideAllocatedSpace(addr)) return false; |
| 3019 if (!HasBeenSetup()) return false; | 3090 if (!HasBeenSetup()) return false; |
| 3020 | 3091 |
| 3092 HeapData& heap_data = v8_context()->heap_data_; |
| 3021 switch (space) { | 3093 switch (space) { |
| 3022 case NEW_SPACE: | 3094 case NEW_SPACE: |
| 3023 return new_space_.ToSpaceContains(addr); | 3095 return heap_data.new_space_.ToSpaceContains(addr); |
| 3024 case OLD_POINTER_SPACE: | 3096 case OLD_POINTER_SPACE: |
| 3025 return old_pointer_space_->Contains(addr); | 3097 return heap_data.old_pointer_space_->Contains(addr); |
| 3026 case OLD_DATA_SPACE: | 3098 case OLD_DATA_SPACE: |
| 3027 return old_data_space_->Contains(addr); | 3099 return heap_data.old_data_space_->Contains(addr); |
| 3028 case CODE_SPACE: | 3100 case CODE_SPACE: |
| 3029 return code_space_->Contains(addr); | 3101 return heap_data.code_space_->Contains(addr); |
| 3030 case MAP_SPACE: | 3102 case MAP_SPACE: |
| 3031 return map_space_->Contains(addr); | 3103 return heap_data.map_space_->Contains(addr); |
| 3032 case CELL_SPACE: | 3104 case CELL_SPACE: |
| 3033 return cell_space_->Contains(addr); | 3105 return heap_data.cell_space_->Contains(addr); |
| 3034 case LO_SPACE: | 3106 case LO_SPACE: |
| 3035 return lo_space_->SlowContains(addr); | 3107 return heap_data.lo_space_->SlowContains(addr); |
| 3036 } | 3108 } |
| 3037 | 3109 |
| 3038 return false; | 3110 return false; |
| 3039 } | 3111 } |
| 3040 | 3112 |
| 3041 | 3113 |
| 3042 #ifdef DEBUG | 3114 #ifdef DEBUG |
| 3043 void Heap::Verify() { | 3115 void Heap::Verify() { |
| 3044 ASSERT(HasBeenSetup()); | 3116 ASSERT(HasBeenSetup()); |
| 3045 | 3117 |
| 3118 HeapData& heap_data = v8_context()->heap_data_; |
| 3046 VerifyPointersVisitor visitor; | 3119 VerifyPointersVisitor visitor; |
| 3047 IterateRoots(&visitor, VISIT_ONLY_STRONG); | 3120 IterateRoots(&visitor, VISIT_ONLY_STRONG); |
| 3048 | 3121 |
| 3049 new_space_.Verify(); | 3122 heap_data.new_space_.Verify(); |
| 3050 | 3123 |
| 3051 VerifyPointersAndRSetVisitor rset_visitor; | 3124 VerifyPointersAndRSetVisitor rset_visitor; |
| 3052 old_pointer_space_->Verify(&rset_visitor); | 3125 heap_data.old_pointer_space_->Verify(&rset_visitor); |
| 3053 map_space_->Verify(&rset_visitor); | 3126 heap_data.map_space_->Verify(&rset_visitor); |
| 3054 | 3127 |
| 3055 VerifyPointersVisitor no_rset_visitor; | 3128 VerifyPointersVisitor no_rset_visitor; |
| 3056 old_data_space_->Verify(&no_rset_visitor); | 3129 heap_data.old_data_space_->Verify(&no_rset_visitor); |
| 3057 code_space_->Verify(&no_rset_visitor); | 3130 heap_data.code_space_->Verify(&no_rset_visitor); |
| 3058 cell_space_->Verify(&no_rset_visitor); | 3131 heap_data.cell_space_->Verify(&no_rset_visitor); |
| 3059 | 3132 |
| 3060 lo_space_->Verify(); | 3133 heap_data.lo_space_->Verify(); |
| 3061 } | 3134 } |
| 3062 #endif // DEBUG | 3135 #endif // DEBUG |
| 3063 | 3136 |
| 3064 | 3137 |
| 3065 Object* Heap::LookupSymbol(Vector<const char> string) { | 3138 Object* Heap::LookupSymbol(Vector<const char> string) { |
| 3066 Object* symbol = NULL; | 3139 Object* symbol = NULL; |
| 3067 Object* new_table = symbol_table()->LookupSymbol(string, &symbol); | 3140 Object* new_table = symbol_table()->LookupSymbol(string, &symbol); |
| 3068 if (new_table->IsFailure()) return new_table; | 3141 if (new_table->IsFailure()) return new_table; |
| 3069 // Can't use set_symbol_table because SymbolTable::cast knows that | 3142 // Can't use set_symbol_table because SymbolTable::cast knows that |
| 3070 // SymbolTable is a singleton and checks for identity. | 3143 // SymbolTable is a singleton and checks for identity. |
| 3071 roots_[kSymbolTableRootIndex] = new_table; | 3144 v8_context()->heap_data_.roots_[kSymbolTableRootIndex] = new_table; |
| 3072 ASSERT(symbol != NULL); | 3145 ASSERT(symbol != NULL); |
| 3073 return symbol; | 3146 return symbol; |
| 3074 } | 3147 } |
| 3075 | 3148 |
| 3076 | 3149 |
| 3077 Object* Heap::LookupSymbol(String* string) { | 3150 Object* Heap::LookupSymbol(String* string) { |
| 3078 if (string->IsSymbol()) return string; | 3151 if (string->IsSymbol()) return string; |
| 3079 Object* symbol = NULL; | 3152 Object* symbol = NULL; |
| 3080 Object* new_table = symbol_table()->LookupString(string, &symbol); | 3153 Object* new_table = symbol_table()->LookupString(string, &symbol); |
| 3081 if (new_table->IsFailure()) return new_table; | 3154 if (new_table->IsFailure()) return new_table; |
| 3082 // Can't use set_symbol_table because SymbolTable::cast knows that | 3155 // Can't use set_symbol_table because SymbolTable::cast knows that |
| 3083 // SymbolTable is a singleton and checks for identity. | 3156 // SymbolTable is a singleton and checks for identity. |
| 3084 roots_[kSymbolTableRootIndex] = new_table; | 3157 v8_context()->heap_data_.roots_[kSymbolTableRootIndex] = new_table; |
| 3085 ASSERT(symbol != NULL); | 3158 ASSERT(symbol != NULL); |
| 3086 return symbol; | 3159 return symbol; |
| 3087 } | 3160 } |
| 3088 | 3161 |
| 3089 | 3162 |
| 3090 bool Heap::LookupSymbolIfExists(String* string, String** symbol) { | 3163 bool Heap::LookupSymbolIfExists(String* string, String** symbol) { |
| 3091 if (string->IsSymbol()) { | 3164 if (string->IsSymbol()) { |
| 3092 *symbol = string; | 3165 *symbol = string; |
| 3093 return true; | 3166 return true; |
| 3094 } | 3167 } |
| 3095 return symbol_table()->LookupSymbolIfExists(string, symbol); | 3168 return symbol_table()->LookupSymbolIfExists(string, symbol); |
| 3096 } | 3169 } |
| 3097 | 3170 |
| 3098 | 3171 |
| 3099 #ifdef DEBUG | 3172 #ifdef DEBUG |
| 3100 void Heap::ZapFromSpace() { | 3173 void Heap::ZapFromSpace() { |
| 3101 ASSERT(reinterpret_cast<Object*>(kFromSpaceZapValue)->IsHeapObject()); | 3174 ASSERT(reinterpret_cast<Object*>(kFromSpaceZapValue)->IsHeapObject()); |
| 3102 for (Address a = new_space_.FromSpaceLow(); | 3175 HeapData& heap_data = v8_context()->heap_data_; |
| 3103 a < new_space_.FromSpaceHigh(); | 3176 for (Address a = heap_data.new_space_.FromSpaceLow(); |
| 3177 a < heap_data.new_space_.FromSpaceHigh(); |
| 3104 a += kPointerSize) { | 3178 a += kPointerSize) { |
| 3105 Memory::Address_at(a) = kFromSpaceZapValue; | 3179 Memory::Address_at(a) = kFromSpaceZapValue; |
| 3106 } | 3180 } |
| 3107 } | 3181 } |
| 3108 #endif // DEBUG | 3182 #endif // DEBUG |
| 3109 | 3183 |
| 3110 | 3184 |
| 3111 int Heap::IterateRSetRange(Address object_start, | 3185 int Heap::IterateRSetRange(Address object_start, |
| 3112 Address object_end, | 3186 Address object_end, |
| 3113 Address rset_start, | 3187 Address rset_start, |
| (...skipping 29 matching lines...) Expand all Loading... |
| 3143 // No bits in the word were set. This is the common case. | 3217 // No bits in the word were set. This is the common case. |
| 3144 object_address += kPointerSize * kBitsPerInt; | 3218 object_address += kPointerSize * kBitsPerInt; |
| 3145 } | 3219 } |
| 3146 rset_address += kIntSize; | 3220 rset_address += kIntSize; |
| 3147 } | 3221 } |
| 3148 return set_bits_count; | 3222 return set_bits_count; |
| 3149 } | 3223 } |
| 3150 | 3224 |
| 3151 | 3225 |
| 3152 void Heap::IterateRSet(PagedSpace* space, ObjectSlotCallback copy_object_func) { | 3226 void Heap::IterateRSet(PagedSpace* space, ObjectSlotCallback copy_object_func) { |
| 3227 HeapData& heap_data = v8_context()->heap_data_; |
| 3153 ASSERT(Page::is_rset_in_use()); | 3228 ASSERT(Page::is_rset_in_use()); |
| 3154 ASSERT(space == old_pointer_space_ || space == map_space_); | 3229 ASSERT(space == heap_data.old_pointer_space_ || |
| 3155 | 3230 space == heap_data.map_space_); |
| 3156 static void* paged_rset_histogram = StatsTable::CreateHistogram( | |
| 3157 "V8.RSetPaged", | |
| 3158 0, | |
| 3159 Page::kObjectAreaSize / kPointerSize, | |
| 3160 30); | |
| 3161 | 3231 |
| 3162 PageIterator it(space, PageIterator::PAGES_IN_USE); | 3232 PageIterator it(space, PageIterator::PAGES_IN_USE); |
| 3163 while (it.has_next()) { | 3233 while (it.has_next()) { |
| 3164 Page* page = it.next(); | 3234 Page* page = it.next(); |
| 3165 int count = IterateRSetRange(page->ObjectAreaStart(), page->AllocationTop(), | 3235 int count = IterateRSetRange(page->ObjectAreaStart(), page->AllocationTop(), |
| 3166 page->RSetStart(), copy_object_func); | 3236 page->RSetStart(), copy_object_func); |
| 3167 if (paged_rset_histogram != NULL) { | 3237 if (heap_data.heap_private_data_.paged_rset_histogram_ != NULL) { |
| 3168 StatsTable::AddHistogramSample(paged_rset_histogram, count); | 3238 StatsTable::AddHistogramSample( |
| 3239 heap_data.heap_private_data_.paged_rset_histogram_, count); |
| 3169 } | 3240 } |
| 3170 } | 3241 } |
| 3171 } | 3242 } |
| 3172 | 3243 |
| 3173 | 3244 |
| 3174 void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) { | 3245 void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) { |
| 3175 IterateStrongRoots(v, mode); | 3246 IterateStrongRoots(v, mode); |
| 3176 v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex])); | 3247 v->VisitPointer(reinterpret_cast<Object**>( |
| 3248 &v8_context()->heap_data_.roots_[kSymbolTableRootIndex])); |
| 3177 v->Synchronize("symbol_table"); | 3249 v->Synchronize("symbol_table"); |
| 3178 } | 3250 } |
| 3179 | 3251 |
| 3180 | 3252 |
| 3181 void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) { | 3253 void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) { |
| 3182 v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]); | 3254 HeapData& heap_data = v8_context()->heap_data_; |
| 3255 v->VisitPointers(&heap_data.roots_[0], |
| 3256 &heap_data.roots_[kStrongRootListLength]); |
| 3183 v->Synchronize("strong_root_list"); | 3257 v->Synchronize("strong_root_list"); |
| 3184 | 3258 |
| 3185 v->VisitPointer(bit_cast<Object**, String**>(&hidden_symbol_)); | 3259 v->VisitPointer(bit_cast<Object**, String**>(&heap_data.hidden_symbol_)); |
| 3186 v->Synchronize("symbol"); | 3260 v->Synchronize("symbol"); |
| 3187 | 3261 |
| 3188 Bootstrapper::Iterate(v); | 3262 Bootstrapper::Iterate(v); |
| 3189 v->Synchronize("bootstrapper"); | 3263 v->Synchronize("bootstrapper"); |
| 3190 Top::Iterate(v); | 3264 Top::Iterate(v); |
| 3191 v->Synchronize("top"); | 3265 v->Synchronize("top"); |
| 3192 Relocatable::Iterate(v); | 3266 Relocatable::Iterate(v); |
| 3193 v->Synchronize("relocatable"); | 3267 v->Synchronize("relocatable"); |
| 3194 | 3268 |
| 3195 #ifdef ENABLE_DEBUGGER_SUPPORT | 3269 #ifdef ENABLE_DEBUGGER_SUPPORT |
| (...skipping 20 matching lines...) Expand all Loading... |
| 3216 } else { | 3290 } else { |
| 3217 GlobalHandles::IterateAllRoots(v); | 3291 GlobalHandles::IterateAllRoots(v); |
| 3218 } | 3292 } |
| 3219 v->Synchronize("globalhandles"); | 3293 v->Synchronize("globalhandles"); |
| 3220 | 3294 |
| 3221 // Iterate over pointers being held by inactive threads. | 3295 // Iterate over pointers being held by inactive threads. |
| 3222 ThreadManager::Iterate(v); | 3296 ThreadManager::Iterate(v); |
| 3223 v->Synchronize("threadmanager"); | 3297 v->Synchronize("threadmanager"); |
| 3224 } | 3298 } |
| 3225 | 3299 |
| 3226 | |
| 3227 // Flag is set when the heap has been configured. The heap can be repeatedly | |
| 3228 // configured through the API until it is setup. | |
| 3229 static bool heap_configured = false; | |
| 3230 | |
| 3231 // TODO(1236194): Since the heap size is configurable on the command line | 3300 // TODO(1236194): Since the heap size is configurable on the command line |
| 3232 // and through the API, we should gracefully handle the case that the heap | 3301 // and through the API, we should gracefully handle the case that the heap |
| 3233 // size is not big enough to fit all the initial objects. | 3302 // size is not big enough to fit all the initial objects. |
| 3234 bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) { | 3303 bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) { |
| 3235 if (HasBeenSetup()) return false; | 3304 if (HasBeenSetup()) return false; |
| 3236 | 3305 |
| 3237 if (max_semispace_size > 0) max_semispace_size_ = max_semispace_size; | 3306 HeapData& heap_data = v8_context()->heap_data_; |
| 3307 if (max_semispace_size > 0) |
| 3308 heap_data.max_semispace_size_ = max_semispace_size; |
| 3238 | 3309 |
| 3239 if (Snapshot::IsEnabled()) { | 3310 if (Snapshot::IsEnabled()) { |
| 3240 // If we are using a snapshot we always reserve the default amount | 3311 // If we are using a snapshot we always reserve the default amount |
| 3241 // of memory for each semispace because code in the snapshot has | 3312 // of memory for each semispace because code in the snapshot has |
| 3242 // write-barrier code that relies on the size and alignment of new | 3313 // write-barrier code that relies on the size and alignment of new |
| 3243 // space. We therefore cannot use a larger max semispace size | 3314 // space. We therefore cannot use a larger max semispace size |
| 3244 // than the default reserved semispace size. | 3315 // than the default reserved semispace size. |
| 3245 if (max_semispace_size_ > reserved_semispace_size_) { | 3316 if (heap_data.max_semispace_size_ > heap_data.reserved_semispace_size_) { |
| 3246 max_semispace_size_ = reserved_semispace_size_; | 3317 heap_data.max_semispace_size_ = heap_data.reserved_semispace_size_; |
| 3247 } | 3318 } |
| 3248 } else { | 3319 } else { |
| 3249 // If we are not using snapshots we reserve space for the actual | 3320 // If we are not using snapshots we reserve space for the actual |
| 3250 // max semispace size. | 3321 // max semispace size. |
| 3251 reserved_semispace_size_ = max_semispace_size_; | 3322 heap_data.reserved_semispace_size_ = heap_data.max_semispace_size_; |
| 3252 } | 3323 } |
| 3253 | 3324 |
| 3254 if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size; | 3325 if (max_old_gen_size > 0) |
| 3326 heap_data.max_old_generation_size_ = max_old_gen_size; |
| 3255 | 3327 |
| 3256 // The new space size must be a power of two to support single-bit testing | 3328 // The new space size must be a power of two to support single-bit testing |
| 3257 // for containment. | 3329 // for containment. |
| 3258 max_semispace_size_ = RoundUpToPowerOf2(max_semispace_size_); | 3330 heap_data.max_semispace_size_ = RoundUpToPowerOf2( |
| 3259 reserved_semispace_size_ = RoundUpToPowerOf2(reserved_semispace_size_); | 3331 heap_data.max_semispace_size_); |
| 3260 initial_semispace_size_ = Min(initial_semispace_size_, max_semispace_size_); | 3332 heap_data.reserved_semispace_size_ = RoundUpToPowerOf2( |
| 3261 external_allocation_limit_ = 10 * max_semispace_size_; | 3333 heap_data.reserved_semispace_size_); |
| 3334 heap_data.initial_semispace_size_ = Min(heap_data.initial_semispace_size_, |
| 3335 heap_data.max_semispace_size_); |
| 3336 heap_data.external_allocation_limit_ = 10 * heap_data.max_semispace_size_; |
| 3262 | 3337 |
| 3263 // The old generation is paged. | 3338 // The old generation is paged. |
| 3264 max_old_generation_size_ = RoundUp(max_old_generation_size_, Page::kPageSize); | 3339 heap_data.max_old_generation_size_ = RoundUp( |
| 3340 heap_data.max_old_generation_size_, Page::kPageSize); |
| 3265 | 3341 |
| 3266 heap_configured = true; | 3342 heap_data.heap_configured_ = true; |
| 3267 return true; | 3343 return true; |
| 3268 } | 3344 } |
| 3269 | 3345 |
| 3270 | 3346 |
| 3271 bool Heap::ConfigureHeapDefault() { | 3347 bool Heap::ConfigureHeapDefault() { |
| 3272 return ConfigureHeap(FLAG_max_new_space_size / 2, FLAG_max_old_space_size); | 3348 return ConfigureHeap(FLAG_max_new_space_size / 2, FLAG_max_old_space_size); |
| 3273 } | 3349 } |
| 3274 | 3350 |
| 3275 | 3351 |
| 3276 void Heap::RecordStats(HeapStats* stats) { | 3352 void Heap::RecordStats(HeapStats* stats) { |
| 3277 *stats->start_marker = 0xDECADE00; | 3353 *stats->start_marker = 0xDECADE00; |
| 3278 *stats->end_marker = 0xDECADE01; | 3354 *stats->end_marker = 0xDECADE01; |
| 3279 *stats->new_space_size = new_space_.Size(); | 3355 HeapData& heap_data = v8_context()->heap_data_; |
| 3280 *stats->new_space_capacity = new_space_.Capacity(); | 3356 *stats->new_space_size = heap_data.new_space_.Size(); |
| 3281 *stats->old_pointer_space_size = old_pointer_space_->Size(); | 3357 *stats->new_space_capacity = heap_data.new_space_.Capacity(); |
| 3282 *stats->old_pointer_space_capacity = old_pointer_space_->Capacity(); | 3358 *stats->old_pointer_space_size = heap_data.old_pointer_space_->Size(); |
| 3283 *stats->old_data_space_size = old_data_space_->Size(); | 3359 *stats->old_pointer_space_capacity = heap_data.old_pointer_space_->Capacity(); |
| 3284 *stats->old_data_space_capacity = old_data_space_->Capacity(); | 3360 *stats->old_data_space_size = heap_data.old_data_space_->Size(); |
| 3285 *stats->code_space_size = code_space_->Size(); | 3361 *stats->old_data_space_capacity = heap_data.old_data_space_->Capacity(); |
| 3286 *stats->code_space_capacity = code_space_->Capacity(); | 3362 *stats->code_space_size = heap_data.code_space_->Size(); |
| 3287 *stats->map_space_size = map_space_->Size(); | 3363 *stats->code_space_capacity = heap_data.code_space_->Capacity(); |
| 3288 *stats->map_space_capacity = map_space_->Capacity(); | 3364 *stats->map_space_size = heap_data.map_space_->Size(); |
| 3289 *stats->cell_space_size = cell_space_->Size(); | 3365 *stats->map_space_capacity = heap_data.map_space_->Capacity(); |
| 3290 *stats->cell_space_capacity = cell_space_->Capacity(); | 3366 *stats->cell_space_size = heap_data.cell_space_->Size(); |
| 3291 *stats->lo_space_size = lo_space_->Size(); | 3367 *stats->cell_space_capacity = heap_data.cell_space_->Capacity(); |
| 3368 *stats->lo_space_size = heap_data.lo_space_->Size(); |
| 3292 GlobalHandles::RecordStats(stats); | 3369 GlobalHandles::RecordStats(stats); |
| 3293 } | 3370 } |
| 3294 | 3371 |
| 3295 | 3372 |
| 3296 int Heap::PromotedSpaceSize() { | 3373 int Heap::PromotedSpaceSize() { |
| 3297 return old_pointer_space_->Size() | 3374 HeapData& heap_data = v8_context()->heap_data_; |
| 3298 + old_data_space_->Size() | 3375 return heap_data.old_pointer_space_->Size() |
| 3299 + code_space_->Size() | 3376 + heap_data.old_data_space_->Size() |
| 3300 + map_space_->Size() | 3377 + heap_data.code_space_->Size() |
| 3301 + cell_space_->Size() | 3378 + heap_data.map_space_->Size() |
| 3302 + lo_space_->Size(); | 3379 + heap_data.cell_space_->Size() |
| 3380 + heap_data.lo_space_->Size(); |
| 3303 } | 3381 } |
| 3304 | 3382 |
| 3305 | 3383 |
| 3306 int Heap::PromotedExternalMemorySize() { | 3384 int Heap::PromotedExternalMemorySize() { |
| 3307 if (amount_of_external_allocated_memory_ | 3385 HeapData& heap_data = v8_context()->heap_data_; |
| 3308 <= amount_of_external_allocated_memory_at_last_global_gc_) return 0; | 3386 if (heap_data.amount_of_external_allocated_memory_ |
| 3309 return amount_of_external_allocated_memory_ | 3387 <= heap_data.amount_of_external_allocated_memory_at_last_global_gc_ |
| 3310 - amount_of_external_allocated_memory_at_last_global_gc_; | 3388 ) { |
| 3389 return 0; |
| 3390 } |
| 3391 return heap_data.amount_of_external_allocated_memory_ |
| 3392 - heap_data.amount_of_external_allocated_memory_at_last_global_gc_; |
| 3311 } | 3393 } |
| 3312 | 3394 |
| 3313 | 3395 |
| 3314 bool Heap::Setup(bool create_heap_objects) { | 3396 bool Heap::Setup(bool create_heap_objects) { |
| 3397 HeapData& heap_data = v8_context()->heap_data_; |
| 3315 // Initialize heap spaces and initial maps and objects. Whenever something | 3398 // Initialize heap spaces and initial maps and objects. Whenever something |
| 3316 // goes wrong, just return false. The caller should check the results and | 3399 // goes wrong, just return false. The caller should check the results and |
| 3317 // call Heap::TearDown() to release allocated memory. | 3400 // call Heap::TearDown() to release allocated memory. |
| 3318 // | 3401 // |
| 3319 // If the heap is not yet configured (eg, through the API), configure it. | 3402 // If the heap is not yet configured (eg, through the API), configure it. |
| 3320 // Configuration is based on the flags new-space-size (really the semispace | 3403 // Configuration is based on the flags new-space-size (really the semispace |
| 3321 // size) and old-space-size if set or the initial values of semispace_size_ | 3404 // size) and old-space-size if set or the initial values of semispace_size_ |
| 3322 // and old_generation_size_ otherwise. | 3405 // and old_generation_size_ otherwise. |
| 3323 if (!heap_configured) { | 3406 if (!heap_data.heap_configured_) { |
| 3324 if (!ConfigureHeapDefault()) return false; | 3407 if (!ConfigureHeapDefault()) return false; |
| 3325 } | 3408 } |
| 3326 | 3409 |
| 3327 // Setup memory allocator and reserve a chunk of memory for new | 3410 // Setup memory allocator and reserve a chunk of memory for new |
| 3328 // space. The chunk is double the size of the requested reserved | 3411 // space. The chunk is double the size of the requested reserved |
| 3329 // new space size to ensure that we can find a pair of semispaces that | 3412 // new space size to ensure that we can find a pair of semispaces that |
| 3330 // are contiguous and aligned to their size. | 3413 // are contiguous and aligned to their size. |
| 3331 if (!MemoryAllocator::Setup(MaxReserved())) return false; | 3414 if (!MemoryAllocator::Setup(MaxReserved())) return false; |
| 3332 void* chunk = | 3415 void* chunk = MemoryAllocator::ReserveInitialChunk( |
| 3333 MemoryAllocator::ReserveInitialChunk(4 * reserved_semispace_size_); | 3416 4 * heap_data.reserved_semispace_size_); |
| 3334 if (chunk == NULL) return false; | 3417 if (chunk == NULL) return false; |
| 3335 | 3418 |
| 3336 // Align the pair of semispaces to their size, which must be a power | 3419 // Align the pair of semispaces to their size, which must be a power |
| 3337 // of 2. | 3420 // of 2. |
| 3338 Address new_space_start = | 3421 Address new_space_start = |
| 3339 RoundUp(reinterpret_cast<byte*>(chunk), 2 * reserved_semispace_size_); | 3422 RoundUp(reinterpret_cast<byte*>(chunk), |
| 3340 if (!new_space_.Setup(new_space_start, 2 * reserved_semispace_size_)) { | 3423 2 * heap_data.reserved_semispace_size_); |
| 3424 if (!heap_data.new_space_.Setup(new_space_start, |
| 3425 2 * heap_data.reserved_semispace_size_)) { |
| 3341 return false; | 3426 return false; |
| 3342 } | 3427 } |
| 3343 | 3428 |
| 3344 // Initialize old pointer space. | 3429 // Initialize old pointer space. |
| 3345 old_pointer_space_ = | 3430 heap_data.old_pointer_space_ = new OldSpace( |
| 3346 new OldSpace(max_old_generation_size_, OLD_POINTER_SPACE, NOT_EXECUTABLE); | 3431 heap_data.max_old_generation_size_, OLD_POINTER_SPACE, NOT_EXECUTABLE); |
| 3347 if (old_pointer_space_ == NULL) return false; | 3432 if (heap_data.old_pointer_space_ == NULL) return false; |
| 3348 if (!old_pointer_space_->Setup(NULL, 0)) return false; | 3433 if (!heap_data.old_pointer_space_->Setup(NULL, 0)) return false; |
| 3349 | 3434 |
| 3350 // Initialize old data space. | 3435 // Initialize old data space. |
| 3351 old_data_space_ = | 3436 heap_data.old_data_space_ = new OldSpace( |
| 3352 new OldSpace(max_old_generation_size_, OLD_DATA_SPACE, NOT_EXECUTABLE); | 3437 heap_data.max_old_generation_size_, OLD_DATA_SPACE, NOT_EXECUTABLE); |
| 3353 if (old_data_space_ == NULL) return false; | 3438 if (heap_data.old_data_space_ == NULL) return false; |
| 3354 if (!old_data_space_->Setup(NULL, 0)) return false; | 3439 if (!heap_data.old_data_space_->Setup(NULL, 0)) return false; |
| 3355 | 3440 |
| 3356 // Initialize the code space, set its maximum capacity to the old | 3441 // Initialize the code space, set its maximum capacity to the old |
| 3357 // generation size. It needs executable memory. | 3442 // generation size. It needs executable memory. |
| 3358 // On 64-bit platform(s), we put all code objects in a 2 GB range of | 3443 // On 64-bit platform(s), we put all code objects in a 2 GB range of |
| 3359 // virtual address space, so that they can call each other with near calls. | 3444 // virtual address space, so that they can call each other with near calls. |
| 3360 if (code_range_size_ > 0) { | 3445 if (heap_data.code_range_size_ > 0) { |
| 3361 if (!CodeRange::Setup(code_range_size_)) { | 3446 if (!CodeRange::Setup(heap_data.code_range_size_)) { |
| 3362 return false; | 3447 return false; |
| 3363 } | 3448 } |
| 3364 } | 3449 } |
| 3365 | 3450 |
| 3366 code_space_ = | 3451 heap_data.code_space_ = |
| 3367 new OldSpace(max_old_generation_size_, CODE_SPACE, EXECUTABLE); | 3452 new OldSpace(heap_data.max_old_generation_size_, CODE_SPACE, EXECUTABLE); |
| 3368 if (code_space_ == NULL) return false; | 3453 if (heap_data.code_space_ == NULL) return false; |
| 3369 if (!code_space_->Setup(NULL, 0)) return false; | 3454 if (!heap_data.code_space_->Setup(NULL, 0)) return false; |
| 3370 | 3455 |
| 3371 // Initialize map space. | 3456 // Initialize map space. |
| 3372 map_space_ = new MapSpace(kMaxMapSpaceSize, MAP_SPACE); | 3457 heap_data.map_space_ = new MapSpace(kMaxMapSpaceSize, MAP_SPACE); |
| 3373 if (map_space_ == NULL) return false; | 3458 if (heap_data.map_space_ == NULL) return false; |
| 3374 if (!map_space_->Setup(NULL, 0)) return false; | 3459 if (!heap_data.map_space_->Setup(NULL, 0)) return false; |
| 3375 | 3460 |
| 3376 // Initialize global property cell space. | 3461 // Initialize global property cell space. |
| 3377 cell_space_ = new CellSpace(max_old_generation_size_, CELL_SPACE); | 3462 heap_data.cell_space_ = new CellSpace( |
| 3378 if (cell_space_ == NULL) return false; | 3463 heap_data.max_old_generation_size_, CELL_SPACE); |
| 3379 if (!cell_space_->Setup(NULL, 0)) return false; | 3464 if (heap_data.cell_space_ == NULL) return false; |
| 3465 if (!heap_data.cell_space_->Setup(NULL, 0)) return false; |
| 3380 | 3466 |
| 3381 // The large object code space may contain code or data. We set the memory | 3467 // The large object code space may contain code or data. We set the memory |
| 3382 // to be non-executable here for safety, but this means we need to enable it | 3468 // to be non-executable here for safety, but this means we need to enable it |
| 3383 // explicitly when allocating large code objects. | 3469 // explicitly when allocating large code objects. |
| 3384 lo_space_ = new LargeObjectSpace(LO_SPACE); | 3470 heap_data.lo_space_ = new LargeObjectSpace(LO_SPACE); |
| 3385 if (lo_space_ == NULL) return false; | 3471 if (heap_data.lo_space_ == NULL) return false; |
| 3386 if (!lo_space_->Setup()) return false; | 3472 if (!heap_data.lo_space_->Setup()) return false; |
| 3387 | 3473 |
| 3388 if (create_heap_objects) { | 3474 if (create_heap_objects) { |
| 3389 // Create initial maps. | 3475 // Create initial maps. |
| 3390 if (!CreateInitialMaps()) return false; | 3476 if (!CreateInitialMaps()) return false; |
| 3391 if (!CreateApiObjects()) return false; | 3477 if (!CreateApiObjects()) return false; |
| 3392 | 3478 |
| 3393 // Create initial objects | 3479 // Create initial objects |
| 3394 if (!CreateInitialObjects()) return false; | 3480 if (!CreateInitialObjects()) return false; |
| 3395 } | 3481 } |
| 3396 | 3482 |
| 3397 LOG(IntEvent("heap-capacity", Capacity())); | 3483 LOG(IntEvent("heap-capacity", Capacity())); |
| 3398 LOG(IntEvent("heap-available", Available())); | 3484 LOG(IntEvent("heap-available", Available())); |
| 3399 | 3485 |
| 3400 #ifdef ENABLE_LOGGING_AND_PROFILING | 3486 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 3401 // This should be called only after initial objects have been created. | 3487 // This should be called only after initial objects have been created. |
| 3402 ProducerHeapProfile::Setup(); | 3488 ProducerHeapProfile::Setup(); |
| 3403 #endif | 3489 #endif |
| 3404 | 3490 |
| 3491 if (!heap_data.heap_private_data_.paged_rset_histogram_) { |
| 3492 heap_data.heap_private_data_.paged_rset_histogram_ = |
| 3493 StatsTable::CreateHistogram("V8.RSetPaged", 0, |
| 3494 Page::kObjectAreaSize / kPointerSize, 30); |
| 3495 } |
| 3496 |
| 3405 return true; | 3497 return true; |
| 3406 } | 3498 } |
| 3407 | 3499 |
| 3408 | 3500 |
| 3409 void Heap::SetStackLimits() { | 3501 void Heap::SetStackLimits() { |
| 3502 HeapData& heap_data = v8_context()->heap_data_; |
| 3410 // On 64 bit machines, pointers are generally out of range of Smis. We write | 3503 // On 64 bit machines, pointers are generally out of range of Smis. We write |
| 3411 // something that looks like an out of range Smi to the GC. | 3504 // something that looks like an out of range Smi to the GC. |
| 3412 | 3505 |
| 3413 // Set up the special root array entries containing the stack limits. | 3506 // Set up the special root array entries containing the stack limits. |
| 3414 // These are actually addresses, but the tag makes the GC ignore it. | 3507 // These are actually addresses, but the tag makes the GC ignore it. |
| 3415 roots_[kStackLimitRootIndex] = | 3508 heap_data.roots_[kStackLimitRootIndex] = |
| 3416 reinterpret_cast<Object*>( | 3509 reinterpret_cast<Object*>( |
| 3417 (StackGuard::jslimit() & ~kSmiTagMask) | kSmiTag); | 3510 (StackGuard::jslimit() & ~kSmiTagMask) | kSmiTag); |
| 3418 roots_[kRealStackLimitRootIndex] = | 3511 heap_data.roots_[kRealStackLimitRootIndex] = |
| 3419 reinterpret_cast<Object*>( | 3512 reinterpret_cast<Object*>( |
| 3420 (StackGuard::real_jslimit() & ~kSmiTagMask) | kSmiTag); | 3513 (StackGuard::real_jslimit() & ~kSmiTagMask) | kSmiTag); |
| 3421 } | 3514 } |
| 3422 | 3515 |
| 3423 | 3516 |
| 3424 void Heap::TearDown() { | 3517 void Heap::TearDown() { |
| 3425 GlobalHandles::TearDown(); | 3518 GlobalHandles::TearDown(); |
| 3519 HeapData& heap_data = v8_context()->heap_data_; |
| 3520 heap_data.new_space_.TearDown(); |
| 3426 | 3521 |
| 3427 new_space_.TearDown(); | 3522 if (heap_data.old_pointer_space_ != NULL) { |
| 3428 | 3523 heap_data.old_pointer_space_->TearDown(); |
| 3429 if (old_pointer_space_ != NULL) { | 3524 delete heap_data.old_pointer_space_; |
| 3430 old_pointer_space_->TearDown(); | 3525 heap_data.old_pointer_space_ = NULL; |
| 3431 delete old_pointer_space_; | |
| 3432 old_pointer_space_ = NULL; | |
| 3433 } | 3526 } |
| 3434 | 3527 |
| 3435 if (old_data_space_ != NULL) { | 3528 if (heap_data.old_data_space_ != NULL) { |
| 3436 old_data_space_->TearDown(); | 3529 heap_data.old_data_space_->TearDown(); |
| 3437 delete old_data_space_; | 3530 delete heap_data.old_data_space_; |
| 3438 old_data_space_ = NULL; | 3531 heap_data.old_data_space_ = NULL; |
| 3439 } | 3532 } |
| 3440 | 3533 |
| 3441 if (code_space_ != NULL) { | 3534 if (heap_data.code_space_ != NULL) { |
| 3442 code_space_->TearDown(); | 3535 heap_data.code_space_->TearDown(); |
| 3443 delete code_space_; | 3536 delete heap_data.code_space_; |
| 3444 code_space_ = NULL; | 3537 heap_data.code_space_ = NULL; |
| 3445 } | 3538 } |
| 3446 | 3539 |
| 3447 if (map_space_ != NULL) { | 3540 if (heap_data.map_space_ != NULL) { |
| 3448 map_space_->TearDown(); | 3541 heap_data.map_space_->TearDown(); |
| 3449 delete map_space_; | 3542 delete heap_data.map_space_; |
| 3450 map_space_ = NULL; | 3543 heap_data.map_space_ = NULL; |
| 3451 } | 3544 } |
| 3452 | 3545 |
| 3453 if (cell_space_ != NULL) { | 3546 if (heap_data.cell_space_ != NULL) { |
| 3454 cell_space_->TearDown(); | 3547 heap_data.cell_space_->TearDown(); |
| 3455 delete cell_space_; | 3548 delete heap_data.cell_space_; |
| 3456 cell_space_ = NULL; | 3549 heap_data.cell_space_ = NULL; |
| 3457 } | 3550 } |
| 3458 | 3551 |
| 3459 if (lo_space_ != NULL) { | 3552 if (heap_data.lo_space_ != NULL) { |
| 3460 lo_space_->TearDown(); | 3553 heap_data.lo_space_->TearDown(); |
| 3461 delete lo_space_; | 3554 delete heap_data.lo_space_; |
| 3462 lo_space_ = NULL; | 3555 heap_data.lo_space_ = NULL; |
| 3463 } | 3556 } |
| 3464 | 3557 |
| 3465 MemoryAllocator::TearDown(); | 3558 MemoryAllocator::TearDown(); |
| 3466 } | 3559 } |
| 3467 | 3560 |
| 3468 | 3561 |
| 3469 void Heap::Shrink() { | 3562 void Heap::Shrink() { |
| 3470 // Try to shrink all paged spaces. | 3563 // Try to shrink all paged spaces. |
| 3471 PagedSpaces spaces; | 3564 PagedSpaces spaces; |
| 3472 while (PagedSpace* space = spaces.next()) space->Shrink(); | 3565 while (PagedSpace* space = spaces.next()) space->Shrink(); |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3691 | 3784 |
| 3692 void HeapIterator::reset() { | 3785 void HeapIterator::reset() { |
| 3693 // Restart the iterator. | 3786 // Restart the iterator. |
| 3694 Shutdown(); | 3787 Shutdown(); |
| 3695 Init(); | 3788 Init(); |
| 3696 } | 3789 } |
| 3697 | 3790 |
| 3698 | 3791 |
| 3699 #ifdef DEBUG | 3792 #ifdef DEBUG |
| 3700 | 3793 |
| 3701 static bool search_for_any_global; | |
| 3702 static Object* search_target; | |
| 3703 static bool found_target; | |
| 3704 static List<Object*> object_stack(20); | |
| 3705 | |
| 3706 | |
| 3707 // Tags 0, 1, and 3 are used. Use 2 for marking visited HeapObject. | 3794 // Tags 0, 1, and 3 are used. Use 2 for marking visited HeapObject. |
| 3708 static const int kMarkTag = 2; | 3795 static const int kMarkTag = 2; |
| 3709 | 3796 |
| 3710 static void MarkObjectRecursively(Object** p); | |
| 3711 class MarkObjectVisitor : public ObjectVisitor { | 3797 class MarkObjectVisitor : public ObjectVisitor { |
| 3798 HeapPrivateData* heap_private_data_; |
| 3712 public: | 3799 public: |
| 3800 explicit MarkObjectVisitor(HeapPrivateData* heap_private_data): |
| 3801 heap_private_data_(heap_private_data) {} |
| 3802 |
| 3713 void VisitPointers(Object** start, Object** end) { | 3803 void VisitPointers(Object** start, Object** end) { |
| 3714 // Copy all HeapObject pointers in [start, end) | 3804 // Copy all HeapObject pointers in [start, end) |
| 3715 for (Object** p = start; p < end; p++) { | 3805 for (Object** p = start; p < end; p++) { |
| 3716 if ((*p)->IsHeapObject()) | 3806 if ((*p)->IsHeapObject()) |
| 3717 MarkObjectRecursively(p); | 3807 MarkObjectRecursively(p); |
| 3718 } | 3808 } |
| 3719 } | 3809 } |
| 3810 void MarkObjectRecursively(Object** p); |
| 3720 }; | 3811 }; |
| 3721 | 3812 |
| 3722 static MarkObjectVisitor mark_visitor; | 3813 void MarkObjectVisitor::MarkObjectRecursively(Object** p) { |
| 3723 | |
| 3724 static void MarkObjectRecursively(Object** p) { | |
| 3725 if (!(*p)->IsHeapObject()) return; | 3814 if (!(*p)->IsHeapObject()) return; |
| 3726 | 3815 |
| 3727 HeapObject* obj = HeapObject::cast(*p); | 3816 HeapObject* obj = HeapObject::cast(*p); |
| 3728 | 3817 |
| 3729 Object* map = obj->map(); | 3818 Object* map = obj->map(); |
| 3730 | 3819 |
| 3731 if (!map->IsHeapObject()) return; // visited before | 3820 if (!map->IsHeapObject()) return; // visited before |
| 3732 | 3821 |
| 3733 if (found_target) return; // stop if target found | 3822 if (heap_private_data_->found_target_) return; // stop if target found |
| 3734 object_stack.Add(obj); | 3823 heap_private_data_->object_stack_.Add(obj); |
| 3735 if ((search_for_any_global && obj->IsJSGlobalObject()) || | 3824 if ((heap_private_data_->search_for_any_global_ && obj->IsJSGlobalObject()) || |
| 3736 (!search_for_any_global && (obj == search_target))) { | 3825 (!heap_private_data_->search_for_any_global_ && |
| 3737 found_target = true; | 3826 (obj == heap_private_data_->search_target_) |
| 3827 ) |
| 3828 ) { |
| 3829 heap_private_data_->found_target_ = true; |
| 3738 return; | 3830 return; |
| 3739 } | 3831 } |
| 3740 | 3832 |
| 3741 // not visited yet | 3833 // not visited yet |
| 3742 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map)); | 3834 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map)); |
| 3743 | 3835 |
| 3744 Address map_addr = map_p->address(); | 3836 Address map_addr = map_p->address(); |
| 3745 | 3837 |
| 3746 obj->set_map(reinterpret_cast<Map*>(map_addr + kMarkTag)); | 3838 obj->set_map(reinterpret_cast<Map*>(map_addr + kMarkTag)); |
| 3747 | 3839 |
| 3748 MarkObjectRecursively(&map); | 3840 MarkObjectRecursively(&map); |
| 3749 | 3841 |
| 3750 obj->IterateBody(map_p->instance_type(), obj->SizeFromMap(map_p), | 3842 obj->IterateBody(map_p->instance_type(), obj->SizeFromMap(map_p), |
| 3751 &mark_visitor); | 3843 this); |
| 3752 | 3844 |
| 3753 if (!found_target) // don't pop if found the target | 3845 if (!heap_private_data_->found_target_) // don't pop if found the target |
| 3754 object_stack.RemoveLast(); | 3846 heap_private_data_->object_stack_.RemoveLast(); |
| 3755 } | 3847 } |
| 3756 | 3848 |
| 3757 | 3849 |
| 3758 static void UnmarkObjectRecursively(Object** p); | |
| 3759 class UnmarkObjectVisitor : public ObjectVisitor { | 3850 class UnmarkObjectVisitor : public ObjectVisitor { |
| 3760 public: | 3851 public: |
| 3761 void VisitPointers(Object** start, Object** end) { | 3852 void VisitPointers(Object** start, Object** end) { |
| 3762 // Copy all HeapObject pointers in [start, end) | 3853 // Copy all HeapObject pointers in [start, end) |
| 3763 for (Object** p = start; p < end; p++) { | 3854 for (Object** p = start; p < end; p++) { |
| 3764 if ((*p)->IsHeapObject()) | 3855 if ((*p)->IsHeapObject()) |
| 3765 UnmarkObjectRecursively(p); | 3856 UnmarkObjectRecursively(p); |
| 3766 } | 3857 } |
| 3767 } | 3858 } |
| 3859 void UnmarkObjectRecursively(Object** p); |
| 3768 }; | 3860 }; |
| 3769 | 3861 |
| 3770 static UnmarkObjectVisitor unmark_visitor; | 3862 void UnmarkObjectVisitor::UnmarkObjectRecursively(Object** p) { |
| 3771 | |
| 3772 static void UnmarkObjectRecursively(Object** p) { | |
| 3773 if (!(*p)->IsHeapObject()) return; | 3863 if (!(*p)->IsHeapObject()) return; |
| 3774 | 3864 |
| 3775 HeapObject* obj = HeapObject::cast(*p); | 3865 HeapObject* obj = HeapObject::cast(*p); |
| 3776 | 3866 |
| 3777 Object* map = obj->map(); | 3867 Object* map = obj->map(); |
| 3778 | 3868 |
| 3779 if (map->IsHeapObject()) return; // unmarked already | 3869 if (map->IsHeapObject()) return; // unmarked already |
| 3780 | 3870 |
| 3781 Address map_addr = reinterpret_cast<Address>(map); | 3871 Address map_addr = reinterpret_cast<Address>(map); |
| 3782 | 3872 |
| 3783 map_addr -= kMarkTag; | 3873 map_addr -= kMarkTag; |
| 3784 | 3874 |
| 3785 ASSERT_TAG_ALIGNED(map_addr); | 3875 ASSERT_TAG_ALIGNED(map_addr); |
| 3786 | 3876 |
| 3787 HeapObject* map_p = HeapObject::FromAddress(map_addr); | 3877 HeapObject* map_p = HeapObject::FromAddress(map_addr); |
| 3788 | 3878 |
| 3789 obj->set_map(reinterpret_cast<Map*>(map_p)); | 3879 obj->set_map(reinterpret_cast<Map*>(map_p)); |
| 3790 | 3880 |
| 3791 UnmarkObjectRecursively(reinterpret_cast<Object**>(&map_p)); | 3881 UnmarkObjectRecursively(reinterpret_cast<Object**>(&map_p)); |
| 3792 | 3882 |
| 3793 obj->IterateBody(Map::cast(map_p)->instance_type(), | 3883 obj->IterateBody(Map::cast(map_p)->instance_type(), |
| 3794 obj->SizeFromMap(Map::cast(map_p)), | 3884 obj->SizeFromMap(Map::cast(map_p)), |
| 3795 &unmark_visitor); | 3885 this); |
| 3796 } | 3886 } |
| 3797 | 3887 |
| 3798 | 3888 |
| 3799 static void MarkRootObjectRecursively(Object** root) { | 3889 void HeapPrivateData::MarkRootObjectRecursively(Object** root) { |
| 3800 if (search_for_any_global) { | 3890 if (search_for_any_global_) { |
| 3801 ASSERT(search_target == NULL); | 3891 ASSERT(search_target_ == NULL); |
| 3802 } else { | 3892 } else { |
| 3803 ASSERT(search_target->IsHeapObject()); | 3893 ASSERT(search_target_->IsHeapObject()); |
| 3804 } | 3894 } |
| 3805 found_target = false; | 3895 found_target_ = false; |
| 3806 object_stack.Clear(); | 3896 object_stack_.Clear(); |
| 3807 | 3897 |
| 3808 MarkObjectRecursively(root); | 3898 MarkObjectVisitor mark_object_visitor(this); |
| 3809 UnmarkObjectRecursively(root); | 3899 mark_object_visitor.MarkObjectRecursively(root); |
| 3900 UnmarkObjectVisitor unmark_visitor; |
| 3901 unmark_visitor.UnmarkObjectRecursively(root); |
| 3810 | 3902 |
| 3811 if (found_target) { | 3903 if (found_target_) { |
| 3812 PrintF("=====================================\n"); | 3904 PrintF("=====================================\n"); |
| 3813 PrintF("==== Path to object ====\n"); | 3905 PrintF("==== Path to object ====\n"); |
| 3814 PrintF("=====================================\n\n"); | 3906 PrintF("=====================================\n\n"); |
| 3815 | 3907 |
| 3816 ASSERT(!object_stack.is_empty()); | 3908 ASSERT(!object_stack_.is_empty()); |
| 3817 for (int i = 0; i < object_stack.length(); i++) { | 3909 for (int i = 0; i < object_stack_ .length(); i++) { |
| 3818 if (i > 0) PrintF("\n |\n |\n V\n\n"); | 3910 if (i > 0) PrintF("\n |\n |\n V\n\n"); |
| 3819 Object* obj = object_stack[i]; | 3911 Object* obj = object_stack_[i]; |
| 3820 obj->Print(); | 3912 obj->Print(); |
| 3821 } | 3913 } |
| 3822 PrintF("=====================================\n"); | 3914 PrintF("=====================================\n"); |
| 3823 } | 3915 } |
| 3824 } | 3916 } |
| 3825 | 3917 |
| 3826 | 3918 |
| 3827 // Helper class for visiting HeapObjects recursively. | 3919 // Helper class for visiting HeapObjects recursively. |
| 3828 class MarkRootVisitor: public ObjectVisitor { | 3920 class MarkRootVisitor: public ObjectVisitor { |
| 3921 HeapPrivateData* heap_private_data_; |
| 3829 public: | 3922 public: |
| 3923 explicit MarkRootVisitor(HeapPrivateData* heap_private_data): |
| 3924 heap_private_data_(heap_private_data) {} |
| 3830 void VisitPointers(Object** start, Object** end) { | 3925 void VisitPointers(Object** start, Object** end) { |
| 3831 // Visit all HeapObject pointers in [start, end) | 3926 // Visit all HeapObject pointers in [start, end) |
| 3832 for (Object** p = start; p < end; p++) { | 3927 for (Object** p = start; p < end; p++) { |
| 3833 if ((*p)->IsHeapObject()) | 3928 if ((*p)->IsHeapObject()) |
| 3834 MarkRootObjectRecursively(p); | 3929 heap_private_data_->MarkRootObjectRecursively(p); |
| 3835 } | 3930 } |
| 3836 } | 3931 } |
| 3837 }; | 3932 }; |
| 3838 | 3933 |
| 3839 | 3934 |
| 3840 // Triggers a depth-first traversal of reachable objects from roots | 3935 // Triggers a depth-first traversal of reachable objects from roots |
| 3841 // and finds a path to a specific heap object and prints it. | 3936 // and finds a path to a specific heap object and prints it. |
| 3842 void Heap::TracePathToObject() { | 3937 void Heap::TracePathToObject() { |
| 3843 search_target = NULL; | 3938 HeapData& heap_data = v8_context()->heap_data_; |
| 3844 search_for_any_global = false; | 3939 heap_data.heap_private_data_.search_target_ = NULL; |
| 3940 heap_data.heap_private_data_.search_for_any_global_ = false; |
| 3845 | 3941 |
| 3846 MarkRootVisitor root_visitor; | 3942 MarkRootVisitor root_visitor(&heap_data.heap_private_data_); |
| 3847 IterateRoots(&root_visitor, VISIT_ONLY_STRONG); | 3943 IterateRoots(&root_visitor, VISIT_ONLY_STRONG); |
| 3848 } | 3944 } |
| 3849 | 3945 |
| 3850 | 3946 |
| 3851 // Triggers a depth-first traversal of reachable objects from roots | 3947 // Triggers a depth-first traversal of reachable objects from roots |
| 3852 // and finds a path to any global object and prints it. Useful for | 3948 // and finds a path to any global object and prints it. Useful for |
| 3853 // determining the source for leaks of global objects. | 3949 // determining the source for leaks of global objects. |
| 3854 void Heap::TracePathToGlobal() { | 3950 void Heap::TracePathToGlobal() { |
| 3855 search_target = NULL; | 3951 HeapData& heap_data = v8_context()->heap_data_; |
| 3856 search_for_any_global = true; | 3952 heap_data.heap_private_data_.search_target_ = NULL; |
| 3953 heap_data.heap_private_data_.search_for_any_global_ = true; |
| 3857 | 3954 |
| 3858 MarkRootVisitor root_visitor; | 3955 MarkRootVisitor root_visitor(&heap_data.heap_private_data_); |
| 3859 IterateRoots(&root_visitor, VISIT_ONLY_STRONG); | 3956 IterateRoots(&root_visitor, VISIT_ONLY_STRONG); |
| 3860 } | 3957 } |
| 3861 #endif | 3958 #endif |
| 3862 | 3959 |
| 3863 | 3960 |
| 3864 GCTracer::GCTracer() | 3961 GCTracer::GCTracer() |
| 3865 : start_time_(0.0), | 3962 : start_time_(0.0), |
| 3866 start_size_(0.0), | 3963 start_size_(0.0), |
| 3867 gc_count_(0), | 3964 gc_count_(0), |
| 3868 full_gc_count_(0), | 3965 full_gc_count_(0), |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3901 : "Mark-sweep"; | 3998 : "Mark-sweep"; |
| 3902 } | 3999 } |
| 3903 return "Unknown GC"; | 4000 return "Unknown GC"; |
| 3904 } | 4001 } |
| 3905 | 4002 |
| 3906 | 4003 |
| 3907 int KeyedLookupCache::Hash(Map* map, String* name) { | 4004 int KeyedLookupCache::Hash(Map* map, String* name) { |
| 3908 // Uses only lower 32 bits if pointers are larger. | 4005 // Uses only lower 32 bits if pointers are larger. |
| 3909 uintptr_t addr_hash = | 4006 uintptr_t addr_hash = |
| 3910 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> 2; | 4007 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> 2; |
| 3911 return (addr_hash ^ name->Hash()) % kLength; | 4008 return (addr_hash ^ name->Hash()) % KeyedLookupCacheData::kLength; |
| 3912 } | 4009 } |
| 3913 | 4010 |
| 3914 | 4011 |
| 3915 int KeyedLookupCache::Lookup(Map* map, String* name) { | 4012 int KeyedLookupCache::Lookup(Map* map, String* name) { |
| 3916 int index = Hash(map, name); | 4013 int index = Hash(map, name); |
| 3917 Key& key = keys_[index]; | 4014 KeyedLookupCacheData& keyed_lookup_cache_data = |
| 4015 v8_context()->keyed_lookup_cache_data_; |
| 4016 KeyedLookupCacheData::Key& key = keyed_lookup_cache_data.keys_[index]; |
| 3918 if ((key.map == map) && key.name->Equals(name)) { | 4017 if ((key.map == map) && key.name->Equals(name)) { |
| 3919 return field_offsets_[index]; | 4018 return keyed_lookup_cache_data.field_offsets_[index]; |
| 3920 } | 4019 } |
| 3921 return -1; | 4020 return -1; |
| 3922 } | 4021 } |
| 3923 | 4022 |
| 3924 | 4023 |
| 3925 void KeyedLookupCache::Update(Map* map, String* name, int field_offset) { | 4024 void KeyedLookupCache::Update(Map* map, String* name, int field_offset) { |
| 3926 String* symbol; | 4025 String* symbol; |
| 3927 if (Heap::LookupSymbolIfExists(name, &symbol)) { | 4026 if (Heap::LookupSymbolIfExists(name, &symbol)) { |
| 3928 int index = Hash(map, symbol); | 4027 int index = Hash(map, symbol); |
| 3929 Key& key = keys_[index]; | 4028 KeyedLookupCacheData& keyed_lookup_cache_data = |
| 4029 v8_context()->keyed_lookup_cache_data_; |
| 4030 KeyedLookupCacheData::Key& key = keyed_lookup_cache_data.keys_[index]; |
| 3930 key.map = map; | 4031 key.map = map; |
| 3931 key.name = symbol; | 4032 key.name = symbol; |
| 3932 field_offsets_[index] = field_offset; | 4033 keyed_lookup_cache_data.field_offsets_[index] = field_offset; |
| 3933 } | 4034 } |
| 3934 } | 4035 } |
| 3935 | 4036 |
| 3936 | 4037 |
| 3937 void KeyedLookupCache::Clear() { | 4038 void KeyedLookupCache::Clear() { |
| 3938 for (int index = 0; index < kLength; index++) keys_[index].map = NULL; | 4039 KeyedLookupCacheData& keyed_lookup_cache_data = |
| 4040 v8_context()->keyed_lookup_cache_data_; |
| 4041 for (int index = 0; index < KeyedLookupCacheData::kLength; index++) { |
| 4042 keyed_lookup_cache_data.keys_[index].map = NULL; |
| 4043 } |
| 4044 } |
| 4045 |
| 4046 void DescriptorLookupCache::Clear() { |
| 4047 DescriptorLookupCacheData& descriptor_lookup_cache_data = |
| 4048 v8_context()->descriptor_lookup_cache_data_; |
| 4049 for (int index = 0; index < DescriptorLookupCacheData::kLength; index++) { |
| 4050 descriptor_lookup_cache_data.keys_[index].array = NULL; |
| 4051 } |
| 3939 } | 4052 } |
| 3940 | 4053 |
| 3941 | 4054 |
| 3942 KeyedLookupCache::Key KeyedLookupCache::keys_[KeyedLookupCache::kLength]; | |
| 3943 | |
| 3944 | |
| 3945 int KeyedLookupCache::field_offsets_[KeyedLookupCache::kLength]; | |
| 3946 | |
| 3947 | |
| 3948 void DescriptorLookupCache::Clear() { | |
| 3949 for (int index = 0; index < kLength; index++) keys_[index].array = NULL; | |
| 3950 } | |
| 3951 | |
| 3952 | |
| 3953 DescriptorLookupCache::Key | |
| 3954 DescriptorLookupCache::keys_[DescriptorLookupCache::kLength]; | |
| 3955 | |
| 3956 int DescriptorLookupCache::results_[DescriptorLookupCache::kLength]; | |
| 3957 | 4055 |
| 3958 | 4056 |
| 3959 #ifdef DEBUG | 4057 #ifdef DEBUG |
| 3960 bool Heap::GarbageCollectionGreedyCheck() { | 4058 bool Heap::GarbageCollectionGreedyCheck() { |
| 3961 ASSERT(FLAG_gc_greedy); | 4059 ASSERT(FLAG_gc_greedy); |
| 3962 if (Bootstrapper::IsActive()) return true; | 4060 if (Bootstrapper::IsActive()) return true; |
| 3963 if (disallow_allocation_failure()) return true; | 4061 if (disallow_allocation_failure()) return true; |
| 3964 return CollectGarbage(0, NEW_SPACE); | 4062 return CollectGarbage(0, NEW_SPACE); |
| 3965 } | 4063 } |
| 3966 #endif | 4064 #endif |
| 3967 | 4065 |
| 3968 | 4066 |
| 3969 TranscendentalCache::TranscendentalCache(TranscendentalCache::Type t) | 4067 TranscendentalCache::TranscendentalCache(Type t) |
| 3970 : type_(t) { | 4068 : type_(t) { |
| 3971 uint32_t in0 = 0xffffffffu; // Bit-pattern for a NaN that isn't | 4069 uint32_t in0 = 0xffffffffu; // Bit-pattern for a NaN that isn't |
| 3972 uint32_t in1 = 0xffffffffu; // generated by the FPU. | 4070 uint32_t in1 = 0xffffffffu; // generated by the FPU. |
| 3973 for (int i = 0; i < kCacheSize; i++) { | 4071 for (int i = 0; i < kCacheSize; i++) { |
| 3974 elements_[i].in[0] = in0; | 4072 elements_[i].in[0] = in0; |
| 3975 elements_[i].in[1] = in1; | 4073 elements_[i].in[1] = in1; |
| 3976 elements_[i].output = NULL; | 4074 elements_[i].output = NULL; |
| 3977 } | 4075 } |
| 3978 } | 4076 } |
| 3979 | 4077 |
| 3980 | 4078 |
| 3981 TranscendentalCache* TranscendentalCache::caches_[kNumberOfCaches]; | |
| 3982 | 4079 |
| 3983 | 4080 |
| 3984 void TranscendentalCache::Clear() { | 4081 void TranscendentalCache::Clear() { |
| 4082 TranscendentalCacheData& transcendental_cache_data = |
| 4083 v8_context()->transcendental_cache_data_; |
| 3985 for (int i = 0; i < kNumberOfCaches; i++) { | 4084 for (int i = 0; i < kNumberOfCaches; i++) { |
| 3986 if (caches_[i] != NULL) { | 4085 if (transcendental_cache_data.caches_[i] != NULL) { |
| 3987 delete caches_[i]; | 4086 delete transcendental_cache_data.caches_[i]; |
| 3988 caches_[i] = NULL; | 4087 transcendental_cache_data.caches_[i] = NULL; |
| 3989 } | 4088 } |
| 3990 } | 4089 } |
| 3991 } | 4090 } |
| 3992 | 4091 |
| 3993 | 4092 |
| 3994 } } // namespace v8::internal | 4093 } } // namespace v8::internal |
| OLD | NEW |