| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1 | // Copyright 2012 the V8 project authors. All rights reserved. | 
 | 2 | // Use of this source code is governed by a BSD-style license that can be | 
 | 3 | // found in the LICENSE file. | 
 | 4 |  | 
 | 5 | #include "src/v8.h" | 
 | 6 |  | 
 | 7 | #include "src/accessors.h" | 
 | 8 | #include "src/api.h" | 
 | 9 | #include "src/base/bits.h" | 
 | 10 | #include "src/base/once.h" | 
 | 11 | #include "src/base/utils/random-number-generator.h" | 
 | 12 | #include "src/bootstrapper.h" | 
 | 13 | #include "src/codegen.h" | 
 | 14 | #include "src/compilation-cache.h" | 
 | 15 | #include "src/conversions.h" | 
 | 16 | #include "src/cpu-profiler.h" | 
 | 17 | #include "src/debug.h" | 
 | 18 | #include "src/deoptimizer.h" | 
 | 19 | #include "src/global-handles.h" | 
 | 20 | #include "src/heap/gc-idle-time-handler.h" | 
 | 21 | #include "src/heap/incremental-marking.h" | 
 | 22 | #include "src/heap/mark-compact.h" | 
 | 23 | #include "src/heap/objects-visiting-inl.h" | 
 | 24 | #include "src/heap/objects-visiting.h" | 
 | 25 | #include "src/heap/store-buffer.h" | 
 | 26 | #include "src/heap-profiler.h" | 
 | 27 | #include "src/isolate-inl.h" | 
 | 28 | #include "src/natives.h" | 
 | 29 | #include "src/runtime-profiler.h" | 
 | 30 | #include "src/scopeinfo.h" | 
 | 31 | #include "src/snapshot.h" | 
 | 32 | #include "src/utils.h" | 
 | 33 | #include "src/v8threads.h" | 
 | 34 | #include "src/vm-state-inl.h" | 
 | 35 |  | 
 | 36 | #if V8_TARGET_ARCH_ARM && !V8_INTERPRETED_REGEXP | 
 | 37 | #include "src/regexp-macro-assembler.h"          // NOLINT | 
 | 38 | #include "src/arm/regexp-macro-assembler-arm.h"  // NOLINT | 
 | 39 | #endif | 
 | 40 | #if V8_TARGET_ARCH_MIPS && !V8_INTERPRETED_REGEXP | 
 | 41 | #include "src/regexp-macro-assembler.h"            // NOLINT | 
 | 42 | #include "src/mips/regexp-macro-assembler-mips.h"  // NOLINT | 
 | 43 | #endif | 
 | 44 | #if V8_TARGET_ARCH_MIPS64 && !V8_INTERPRETED_REGEXP | 
 | 45 | #include "src/regexp-macro-assembler.h" | 
 | 46 | #include "src/mips64/regexp-macro-assembler-mips64.h" | 
 | 47 | #endif | 
 | 48 |  | 
 | 49 | namespace v8 { | 
 | 50 | namespace internal { | 
 | 51 |  | 
 | 52 |  | 
 | 53 | Heap::Heap() | 
 | 54 |     : amount_of_external_allocated_memory_(0), | 
 | 55 |       amount_of_external_allocated_memory_at_last_global_gc_(0), | 
 | 56 |       isolate_(NULL), | 
 | 57 |       code_range_size_(0), | 
 | 58 |       // semispace_size_ should be a power of 2 and old_generation_size_ should | 
 | 59 |       // be a multiple of Page::kPageSize. | 
 | 60 |       reserved_semispace_size_(8 * (kPointerSize / 4) * MB), | 
 | 61 |       max_semi_space_size_(8 * (kPointerSize / 4) * MB), | 
 | 62 |       initial_semispace_size_(Page::kPageSize), | 
 | 63 |       max_old_generation_size_(700ul * (kPointerSize / 4) * MB), | 
 | 64 |       max_executable_size_(256ul * (kPointerSize / 4) * MB), | 
 | 65 |       // Variables set based on semispace_size_ and old_generation_size_ in | 
 | 66 |       // ConfigureHeap. | 
 | 67 |       // Will be 4 * reserved_semispace_size_ to ensure that young | 
 | 68 |       // generation can be aligned to its size. | 
 | 69 |       maximum_committed_(0), | 
 | 70 |       survived_since_last_expansion_(0), | 
 | 71 |       sweep_generation_(0), | 
 | 72 |       always_allocate_scope_depth_(0), | 
 | 73 |       contexts_disposed_(0), | 
 | 74 |       global_ic_age_(0), | 
 | 75 |       flush_monomorphic_ics_(false), | 
 | 76 |       scan_on_scavenge_pages_(0), | 
 | 77 |       new_space_(this), | 
 | 78 |       old_pointer_space_(NULL), | 
 | 79 |       old_data_space_(NULL), | 
 | 80 |       code_space_(NULL), | 
 | 81 |       map_space_(NULL), | 
 | 82 |       cell_space_(NULL), | 
 | 83 |       property_cell_space_(NULL), | 
 | 84 |       lo_space_(NULL), | 
 | 85 |       gc_state_(NOT_IN_GC), | 
 | 86 |       gc_post_processing_depth_(0), | 
 | 87 |       allocations_count_(0), | 
 | 88 |       raw_allocations_hash_(0), | 
 | 89 |       dump_allocations_hash_countdown_(FLAG_dump_allocations_digest_at_alloc), | 
 | 90 |       ms_count_(0), | 
 | 91 |       gc_count_(0), | 
 | 92 |       remembered_unmapped_pages_index_(0), | 
 | 93 |       unflattened_strings_length_(0), | 
 | 94 | #ifdef DEBUG | 
 | 95 |       allocation_timeout_(0), | 
 | 96 | #endif  // DEBUG | 
 | 97 |       old_generation_allocation_limit_(kMinimumOldGenerationAllocationLimit), | 
 | 98 |       old_gen_exhausted_(false), | 
 | 99 |       inline_allocation_disabled_(false), | 
 | 100 |       store_buffer_rebuilder_(store_buffer()), | 
 | 101 |       hidden_string_(NULL), | 
 | 102 |       gc_safe_size_of_old_object_(NULL), | 
 | 103 |       total_regexp_code_generated_(0), | 
 | 104 |       tracer_(this), | 
 | 105 |       high_survival_rate_period_length_(0), | 
 | 106 |       promoted_objects_size_(0), | 
 | 107 |       promotion_rate_(0), | 
 | 108 |       semi_space_copied_object_size_(0), | 
 | 109 |       semi_space_copied_rate_(0), | 
 | 110 |       nodes_died_in_new_space_(0), | 
 | 111 |       nodes_copied_in_new_space_(0), | 
 | 112 |       nodes_promoted_(0), | 
 | 113 |       maximum_size_scavenges_(0), | 
 | 114 |       max_gc_pause_(0.0), | 
 | 115 |       total_gc_time_ms_(0.0), | 
 | 116 |       max_alive_after_gc_(0), | 
 | 117 |       min_in_mutator_(kMaxInt), | 
 | 118 |       marking_time_(0.0), | 
 | 119 |       sweeping_time_(0.0), | 
 | 120 |       mark_compact_collector_(this), | 
 | 121 |       store_buffer_(this), | 
 | 122 |       marking_(this), | 
 | 123 |       incremental_marking_(this), | 
 | 124 |       gc_count_at_last_idle_gc_(0), | 
 | 125 |       full_codegen_bytes_generated_(0), | 
 | 126 |       crankshaft_codegen_bytes_generated_(0), | 
 | 127 |       gcs_since_last_deopt_(0), | 
 | 128 | #ifdef VERIFY_HEAP | 
 | 129 |       no_weak_object_verification_scope_depth_(0), | 
 | 130 | #endif | 
 | 131 |       allocation_sites_scratchpad_length_(0), | 
 | 132 |       promotion_queue_(this), | 
 | 133 |       configured_(false), | 
 | 134 |       external_string_table_(this), | 
 | 135 |       chunks_queued_for_free_(NULL), | 
 | 136 |       gc_callbacks_depth_(0) { | 
 | 137 | // Allow build-time customization of the max semispace size. Building | 
 | 138 | // V8 with snapshots and a non-default max semispace size is much | 
 | 139 | // easier if you can define it as part of the build environment. | 
 | 140 | #if defined(V8_MAX_SEMISPACE_SIZE) | 
 | 141 |   max_semi_space_size_ = reserved_semispace_size_ = V8_MAX_SEMISPACE_SIZE; | 
 | 142 | #endif | 
 | 143 |  | 
 | 144 |   // Ensure old_generation_size_ is a multiple of kPageSize. | 
 | 145 |   DCHECK(MB >= Page::kPageSize); | 
 | 146 |  | 
 | 147 |   memset(roots_, 0, sizeof(roots_[0]) * kRootListLength); | 
 | 148 |   set_native_contexts_list(NULL); | 
 | 149 |   set_array_buffers_list(Smi::FromInt(0)); | 
 | 150 |   set_allocation_sites_list(Smi::FromInt(0)); | 
 | 151 |   set_encountered_weak_collections(Smi::FromInt(0)); | 
 | 152 |   // Put a dummy entry in the remembered pages so we can find the list the | 
 | 153 |   // minidump even if there are no real unmapped pages. | 
 | 154 |   RememberUnmappedPage(NULL, false); | 
 | 155 |  | 
 | 156 |   ClearObjectStats(true); | 
 | 157 | } | 
 | 158 |  | 
 | 159 |  | 
 | 160 | intptr_t Heap::Capacity() { | 
 | 161 |   if (!HasBeenSetUp()) return 0; | 
 | 162 |  | 
 | 163 |   return new_space_.Capacity() + old_pointer_space_->Capacity() + | 
 | 164 |          old_data_space_->Capacity() + code_space_->Capacity() + | 
 | 165 |          map_space_->Capacity() + cell_space_->Capacity() + | 
 | 166 |          property_cell_space_->Capacity(); | 
 | 167 | } | 
 | 168 |  | 
 | 169 |  | 
 | 170 | intptr_t Heap::CommittedMemory() { | 
 | 171 |   if (!HasBeenSetUp()) return 0; | 
 | 172 |  | 
 | 173 |   return new_space_.CommittedMemory() + old_pointer_space_->CommittedMemory() + | 
 | 174 |          old_data_space_->CommittedMemory() + code_space_->CommittedMemory() + | 
 | 175 |          map_space_->CommittedMemory() + cell_space_->CommittedMemory() + | 
 | 176 |          property_cell_space_->CommittedMemory() + lo_space_->Size(); | 
 | 177 | } | 
 | 178 |  | 
 | 179 |  | 
 | 180 | size_t Heap::CommittedPhysicalMemory() { | 
 | 181 |   if (!HasBeenSetUp()) return 0; | 
 | 182 |  | 
 | 183 |   return new_space_.CommittedPhysicalMemory() + | 
 | 184 |          old_pointer_space_->CommittedPhysicalMemory() + | 
 | 185 |          old_data_space_->CommittedPhysicalMemory() + | 
 | 186 |          code_space_->CommittedPhysicalMemory() + | 
 | 187 |          map_space_->CommittedPhysicalMemory() + | 
 | 188 |          cell_space_->CommittedPhysicalMemory() + | 
 | 189 |          property_cell_space_->CommittedPhysicalMemory() + | 
 | 190 |          lo_space_->CommittedPhysicalMemory(); | 
 | 191 | } | 
 | 192 |  | 
 | 193 |  | 
 | 194 | intptr_t Heap::CommittedMemoryExecutable() { | 
 | 195 |   if (!HasBeenSetUp()) return 0; | 
 | 196 |  | 
 | 197 |   return isolate()->memory_allocator()->SizeExecutable(); | 
 | 198 | } | 
 | 199 |  | 
 | 200 |  | 
 | 201 | void Heap::UpdateMaximumCommitted() { | 
 | 202 |   if (!HasBeenSetUp()) return; | 
 | 203 |  | 
 | 204 |   intptr_t current_committed_memory = CommittedMemory(); | 
 | 205 |   if (current_committed_memory > maximum_committed_) { | 
 | 206 |     maximum_committed_ = current_committed_memory; | 
 | 207 |   } | 
 | 208 | } | 
 | 209 |  | 
 | 210 |  | 
 | 211 | intptr_t Heap::Available() { | 
 | 212 |   if (!HasBeenSetUp()) return 0; | 
 | 213 |  | 
 | 214 |   return new_space_.Available() + old_pointer_space_->Available() + | 
 | 215 |          old_data_space_->Available() + code_space_->Available() + | 
 | 216 |          map_space_->Available() + cell_space_->Available() + | 
 | 217 |          property_cell_space_->Available(); | 
 | 218 | } | 
 | 219 |  | 
 | 220 |  | 
 | 221 | bool Heap::HasBeenSetUp() { | 
 | 222 |   return old_pointer_space_ != NULL && old_data_space_ != NULL && | 
 | 223 |          code_space_ != NULL && map_space_ != NULL && cell_space_ != NULL && | 
 | 224 |          property_cell_space_ != NULL && lo_space_ != NULL; | 
 | 225 | } | 
 | 226 |  | 
 | 227 |  | 
 | 228 | int Heap::GcSafeSizeOfOldObject(HeapObject* object) { | 
 | 229 |   if (IntrusiveMarking::IsMarked(object)) { | 
 | 230 |     return IntrusiveMarking::SizeOfMarkedObject(object); | 
 | 231 |   } | 
 | 232 |   return object->SizeFromMap(object->map()); | 
 | 233 | } | 
 | 234 |  | 
 | 235 |  | 
 | 236 | GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space, | 
 | 237 |                                               const char** reason) { | 
 | 238 |   // Is global GC requested? | 
 | 239 |   if (space != NEW_SPACE) { | 
 | 240 |     isolate_->counters()->gc_compactor_caused_by_request()->Increment(); | 
 | 241 |     *reason = "GC in old space requested"; | 
 | 242 |     return MARK_COMPACTOR; | 
 | 243 |   } | 
 | 244 |  | 
 | 245 |   if (FLAG_gc_global || (FLAG_stress_compaction && (gc_count_ & 1) != 0)) { | 
 | 246 |     *reason = "GC in old space forced by flags"; | 
 | 247 |     return MARK_COMPACTOR; | 
 | 248 |   } | 
 | 249 |  | 
 | 250 |   // Is enough data promoted to justify a global GC? | 
 | 251 |   if (OldGenerationAllocationLimitReached()) { | 
 | 252 |     isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment(); | 
 | 253 |     *reason = "promotion limit reached"; | 
 | 254 |     return MARK_COMPACTOR; | 
 | 255 |   } | 
 | 256 |  | 
 | 257 |   // Have allocation in OLD and LO failed? | 
 | 258 |   if (old_gen_exhausted_) { | 
 | 259 |     isolate_->counters() | 
 | 260 |         ->gc_compactor_caused_by_oldspace_exhaustion() | 
 | 261 |         ->Increment(); | 
 | 262 |     *reason = "old generations exhausted"; | 
 | 263 |     return MARK_COMPACTOR; | 
 | 264 |   } | 
 | 265 |  | 
 | 266 |   // Is there enough space left in OLD to guarantee that a scavenge can | 
 | 267 |   // succeed? | 
 | 268 |   // | 
 | 269 |   // Note that MemoryAllocator->MaxAvailable() undercounts the memory available | 
 | 270 |   // for object promotion. It counts only the bytes that the memory | 
 | 271 |   // allocator has not yet allocated from the OS and assigned to any space, | 
 | 272 |   // and does not count available bytes already in the old space or code | 
 | 273 |   // space.  Undercounting is safe---we may get an unrequested full GC when | 
 | 274 |   // a scavenge would have succeeded. | 
 | 275 |   if (isolate_->memory_allocator()->MaxAvailable() <= new_space_.Size()) { | 
 | 276 |     isolate_->counters() | 
 | 277 |         ->gc_compactor_caused_by_oldspace_exhaustion() | 
 | 278 |         ->Increment(); | 
 | 279 |     *reason = "scavenge might not succeed"; | 
 | 280 |     return MARK_COMPACTOR; | 
 | 281 |   } | 
 | 282 |  | 
 | 283 |   // Default | 
 | 284 |   *reason = NULL; | 
 | 285 |   return SCAVENGER; | 
 | 286 | } | 
 | 287 |  | 
 | 288 |  | 
 | 289 | // TODO(1238405): Combine the infrastructure for --heap-stats and | 
 | 290 | // --log-gc to avoid the complicated preprocessor and flag testing. | 
 | 291 | void Heap::ReportStatisticsBeforeGC() { | 
 | 292 | // Heap::ReportHeapStatistics will also log NewSpace statistics when | 
 | 293 | // compiled --log-gc is set.  The following logic is used to avoid | 
 | 294 | // double logging. | 
 | 295 | #ifdef DEBUG | 
 | 296 |   if (FLAG_heap_stats || FLAG_log_gc) new_space_.CollectStatistics(); | 
 | 297 |   if (FLAG_heap_stats) { | 
 | 298 |     ReportHeapStatistics("Before GC"); | 
 | 299 |   } else if (FLAG_log_gc) { | 
 | 300 |     new_space_.ReportStatistics(); | 
 | 301 |   } | 
 | 302 |   if (FLAG_heap_stats || FLAG_log_gc) new_space_.ClearHistograms(); | 
 | 303 | #else | 
 | 304 |   if (FLAG_log_gc) { | 
 | 305 |     new_space_.CollectStatistics(); | 
 | 306 |     new_space_.ReportStatistics(); | 
 | 307 |     new_space_.ClearHistograms(); | 
 | 308 |   } | 
 | 309 | #endif  // DEBUG | 
 | 310 | } | 
 | 311 |  | 
 | 312 |  | 
 | 313 | void Heap::PrintShortHeapStatistics() { | 
 | 314 |   if (!FLAG_trace_gc_verbose) return; | 
 | 315 |   PrintPID("Memory allocator,   used: %6" V8_PTR_PREFIX | 
 | 316 |            "d KB" | 
 | 317 |            ", available: %6" V8_PTR_PREFIX "d KB\n", | 
 | 318 |            isolate_->memory_allocator()->Size() / KB, | 
 | 319 |            isolate_->memory_allocator()->Available() / KB); | 
 | 320 |   PrintPID("New space,          used: %6" V8_PTR_PREFIX | 
 | 321 |            "d KB" | 
 | 322 |            ", available: %6" V8_PTR_PREFIX | 
 | 323 |            "d KB" | 
 | 324 |            ", committed: %6" V8_PTR_PREFIX "d KB\n", | 
 | 325 |            new_space_.Size() / KB, new_space_.Available() / KB, | 
 | 326 |            new_space_.CommittedMemory() / KB); | 
 | 327 |   PrintPID("Old pointers,       used: %6" V8_PTR_PREFIX | 
 | 328 |            "d KB" | 
 | 329 |            ", available: %6" V8_PTR_PREFIX | 
 | 330 |            "d KB" | 
 | 331 |            ", committed: %6" V8_PTR_PREFIX "d KB\n", | 
 | 332 |            old_pointer_space_->SizeOfObjects() / KB, | 
 | 333 |            old_pointer_space_->Available() / KB, | 
 | 334 |            old_pointer_space_->CommittedMemory() / KB); | 
 | 335 |   PrintPID("Old data space,     used: %6" V8_PTR_PREFIX | 
 | 336 |            "d KB" | 
 | 337 |            ", available: %6" V8_PTR_PREFIX | 
 | 338 |            "d KB" | 
 | 339 |            ", committed: %6" V8_PTR_PREFIX "d KB\n", | 
 | 340 |            old_data_space_->SizeOfObjects() / KB, | 
 | 341 |            old_data_space_->Available() / KB, | 
 | 342 |            old_data_space_->CommittedMemory() / KB); | 
 | 343 |   PrintPID("Code space,         used: %6" V8_PTR_PREFIX | 
 | 344 |            "d KB" | 
 | 345 |            ", available: %6" V8_PTR_PREFIX | 
 | 346 |            "d KB" | 
 | 347 |            ", committed: %6" V8_PTR_PREFIX "d KB\n", | 
 | 348 |            code_space_->SizeOfObjects() / KB, code_space_->Available() / KB, | 
 | 349 |            code_space_->CommittedMemory() / KB); | 
 | 350 |   PrintPID("Map space,          used: %6" V8_PTR_PREFIX | 
 | 351 |            "d KB" | 
 | 352 |            ", available: %6" V8_PTR_PREFIX | 
 | 353 |            "d KB" | 
 | 354 |            ", committed: %6" V8_PTR_PREFIX "d KB\n", | 
 | 355 |            map_space_->SizeOfObjects() / KB, map_space_->Available() / KB, | 
 | 356 |            map_space_->CommittedMemory() / KB); | 
 | 357 |   PrintPID("Cell space,         used: %6" V8_PTR_PREFIX | 
 | 358 |            "d KB" | 
 | 359 |            ", available: %6" V8_PTR_PREFIX | 
 | 360 |            "d KB" | 
 | 361 |            ", committed: %6" V8_PTR_PREFIX "d KB\n", | 
 | 362 |            cell_space_->SizeOfObjects() / KB, cell_space_->Available() / KB, | 
 | 363 |            cell_space_->CommittedMemory() / KB); | 
 | 364 |   PrintPID("PropertyCell space, used: %6" V8_PTR_PREFIX | 
 | 365 |            "d KB" | 
 | 366 |            ", available: %6" V8_PTR_PREFIX | 
 | 367 |            "d KB" | 
 | 368 |            ", committed: %6" V8_PTR_PREFIX "d KB\n", | 
 | 369 |            property_cell_space_->SizeOfObjects() / KB, | 
 | 370 |            property_cell_space_->Available() / KB, | 
 | 371 |            property_cell_space_->CommittedMemory() / KB); | 
 | 372 |   PrintPID("Large object space, used: %6" V8_PTR_PREFIX | 
 | 373 |            "d KB" | 
 | 374 |            ", available: %6" V8_PTR_PREFIX | 
 | 375 |            "d KB" | 
 | 376 |            ", committed: %6" V8_PTR_PREFIX "d KB\n", | 
 | 377 |            lo_space_->SizeOfObjects() / KB, lo_space_->Available() / KB, | 
 | 378 |            lo_space_->CommittedMemory() / KB); | 
 | 379 |   PrintPID("All spaces,         used: %6" V8_PTR_PREFIX | 
 | 380 |            "d KB" | 
 | 381 |            ", available: %6" V8_PTR_PREFIX | 
 | 382 |            "d KB" | 
 | 383 |            ", committed: %6" V8_PTR_PREFIX "d KB\n", | 
 | 384 |            this->SizeOfObjects() / KB, this->Available() / KB, | 
 | 385 |            this->CommittedMemory() / KB); | 
 | 386 |   PrintPID("External memory reported: %6" V8_PTR_PREFIX "d KB\n", | 
 | 387 |            static_cast<intptr_t>(amount_of_external_allocated_memory_ / KB)); | 
 | 388 |   PrintPID("Total time spent in GC  : %.1f ms\n", total_gc_time_ms_); | 
 | 389 | } | 
 | 390 |  | 
 | 391 |  | 
 | 392 | // TODO(1238405): Combine the infrastructure for --heap-stats and | 
 | 393 | // --log-gc to avoid the complicated preprocessor and flag testing. | 
 | 394 | void Heap::ReportStatisticsAfterGC() { | 
 | 395 | // Similar to the before GC, we use some complicated logic to ensure that | 
 | 396 | // NewSpace statistics are logged exactly once when --log-gc is turned on. | 
 | 397 | #if defined(DEBUG) | 
 | 398 |   if (FLAG_heap_stats) { | 
 | 399 |     new_space_.CollectStatistics(); | 
 | 400 |     ReportHeapStatistics("After GC"); | 
 | 401 |   } else if (FLAG_log_gc) { | 
 | 402 |     new_space_.ReportStatistics(); | 
 | 403 |   } | 
 | 404 | #else | 
 | 405 |   if (FLAG_log_gc) new_space_.ReportStatistics(); | 
 | 406 | #endif  // DEBUG | 
 | 407 | } | 
 | 408 |  | 
 | 409 |  | 
 | 410 | void Heap::GarbageCollectionPrologue() { | 
 | 411 |   { | 
 | 412 |     AllowHeapAllocation for_the_first_part_of_prologue; | 
 | 413 |     ClearJSFunctionResultCaches(); | 
 | 414 |     gc_count_++; | 
 | 415 |     unflattened_strings_length_ = 0; | 
 | 416 |  | 
 | 417 |     if (FLAG_flush_code && FLAG_flush_code_incrementally) { | 
 | 418 |       mark_compact_collector()->EnableCodeFlushing(true); | 
 | 419 |     } | 
 | 420 |  | 
 | 421 | #ifdef VERIFY_HEAP | 
 | 422 |     if (FLAG_verify_heap) { | 
 | 423 |       Verify(); | 
 | 424 |     } | 
 | 425 | #endif | 
 | 426 |   } | 
 | 427 |  | 
 | 428 |   // Reset GC statistics. | 
 | 429 |   promoted_objects_size_ = 0; | 
 | 430 |   semi_space_copied_object_size_ = 0; | 
 | 431 |   nodes_died_in_new_space_ = 0; | 
 | 432 |   nodes_copied_in_new_space_ = 0; | 
 | 433 |   nodes_promoted_ = 0; | 
 | 434 |  | 
 | 435 |   UpdateMaximumCommitted(); | 
 | 436 |  | 
 | 437 | #ifdef DEBUG | 
 | 438 |   DCHECK(!AllowHeapAllocation::IsAllowed() && gc_state_ == NOT_IN_GC); | 
 | 439 |  | 
 | 440 |   if (FLAG_gc_verbose) Print(); | 
 | 441 |  | 
 | 442 |   ReportStatisticsBeforeGC(); | 
 | 443 | #endif  // DEBUG | 
 | 444 |  | 
 | 445 |   store_buffer()->GCPrologue(); | 
 | 446 |  | 
 | 447 |   if (isolate()->concurrent_osr_enabled()) { | 
 | 448 |     isolate()->optimizing_compiler_thread()->AgeBufferedOsrJobs(); | 
 | 449 |   } | 
 | 450 |  | 
 | 451 |   if (new_space_.IsAtMaximumCapacity()) { | 
 | 452 |     maximum_size_scavenges_++; | 
 | 453 |   } else { | 
 | 454 |     maximum_size_scavenges_ = 0; | 
 | 455 |   } | 
 | 456 |   CheckNewSpaceExpansionCriteria(); | 
 | 457 | } | 
 | 458 |  | 
 | 459 |  | 
 | 460 | intptr_t Heap::SizeOfObjects() { | 
 | 461 |   intptr_t total = 0; | 
 | 462 |   AllSpaces spaces(this); | 
 | 463 |   for (Space* space = spaces.next(); space != NULL; space = spaces.next()) { | 
 | 464 |     total += space->SizeOfObjects(); | 
 | 465 |   } | 
 | 466 |   return total; | 
 | 467 | } | 
 | 468 |  | 
 | 469 |  | 
 | 470 | void Heap::ClearAllICsByKind(Code::Kind kind) { | 
 | 471 |   HeapObjectIterator it(code_space()); | 
 | 472 |  | 
 | 473 |   for (Object* object = it.Next(); object != NULL; object = it.Next()) { | 
 | 474 |     Code* code = Code::cast(object); | 
 | 475 |     Code::Kind current_kind = code->kind(); | 
 | 476 |     if (current_kind == Code::FUNCTION || | 
 | 477 |         current_kind == Code::OPTIMIZED_FUNCTION) { | 
 | 478 |       code->ClearInlineCaches(kind); | 
 | 479 |     } | 
 | 480 |   } | 
 | 481 | } | 
 | 482 |  | 
 | 483 |  | 
 | 484 | void Heap::RepairFreeListsAfterBoot() { | 
 | 485 |   PagedSpaces spaces(this); | 
 | 486 |   for (PagedSpace* space = spaces.next(); space != NULL; | 
 | 487 |        space = spaces.next()) { | 
 | 488 |     space->RepairFreeListsAfterBoot(); | 
 | 489 |   } | 
 | 490 | } | 
 | 491 |  | 
 | 492 |  | 
 | 493 | void Heap::ProcessPretenuringFeedback() { | 
 | 494 |   if (FLAG_allocation_site_pretenuring) { | 
 | 495 |     int tenure_decisions = 0; | 
 | 496 |     int dont_tenure_decisions = 0; | 
 | 497 |     int allocation_mementos_found = 0; | 
 | 498 |     int allocation_sites = 0; | 
 | 499 |     int active_allocation_sites = 0; | 
 | 500 |  | 
 | 501 |     // If the scratchpad overflowed, we have to iterate over the allocation | 
 | 502 |     // sites list. | 
 | 503 |     // TODO(hpayer): We iterate over the whole list of allocation sites when | 
 | 504 |     // we grew to the maximum semi-space size to deopt maybe tenured | 
 | 505 |     // allocation sites. We could hold the maybe tenured allocation sites | 
 | 506 |     // in a seperate data structure if this is a performance problem. | 
 | 507 |     bool deopt_maybe_tenured = DeoptMaybeTenuredAllocationSites(); | 
 | 508 |     bool use_scratchpad = | 
 | 509 |         allocation_sites_scratchpad_length_ < kAllocationSiteScratchpadSize && | 
 | 510 |         !deopt_maybe_tenured; | 
 | 511 |  | 
 | 512 |     int i = 0; | 
 | 513 |     Object* list_element = allocation_sites_list(); | 
 | 514 |     bool trigger_deoptimization = false; | 
 | 515 |     bool maximum_size_scavenge = MaximumSizeScavenge(); | 
 | 516 |     while (use_scratchpad ? i < allocation_sites_scratchpad_length_ | 
 | 517 |                           : list_element->IsAllocationSite()) { | 
 | 518 |       AllocationSite* site = | 
 | 519 |           use_scratchpad | 
 | 520 |               ? AllocationSite::cast(allocation_sites_scratchpad()->get(i)) | 
 | 521 |               : AllocationSite::cast(list_element); | 
 | 522 |       allocation_mementos_found += site->memento_found_count(); | 
 | 523 |       if (site->memento_found_count() > 0) { | 
 | 524 |         active_allocation_sites++; | 
 | 525 |         if (site->DigestPretenuringFeedback(maximum_size_scavenge)) { | 
 | 526 |           trigger_deoptimization = true; | 
 | 527 |         } | 
 | 528 |         if (site->GetPretenureMode() == TENURED) { | 
 | 529 |           tenure_decisions++; | 
 | 530 |         } else { | 
 | 531 |           dont_tenure_decisions++; | 
 | 532 |         } | 
 | 533 |         allocation_sites++; | 
 | 534 |       } | 
 | 535 |  | 
 | 536 |       if (deopt_maybe_tenured && site->IsMaybeTenure()) { | 
 | 537 |         site->set_deopt_dependent_code(true); | 
 | 538 |         trigger_deoptimization = true; | 
 | 539 |       } | 
 | 540 |  | 
 | 541 |       if (use_scratchpad) { | 
 | 542 |         i++; | 
 | 543 |       } else { | 
 | 544 |         list_element = site->weak_next(); | 
 | 545 |       } | 
 | 546 |     } | 
 | 547 |  | 
 | 548 |     if (trigger_deoptimization) { | 
 | 549 |       isolate_->stack_guard()->RequestDeoptMarkedAllocationSites(); | 
 | 550 |     } | 
 | 551 |  | 
 | 552 |     FlushAllocationSitesScratchpad(); | 
 | 553 |  | 
 | 554 |     if (FLAG_trace_pretenuring_statistics && | 
 | 555 |         (allocation_mementos_found > 0 || tenure_decisions > 0 || | 
 | 556 |          dont_tenure_decisions > 0)) { | 
 | 557 |       PrintF( | 
 | 558 |           "GC: (mode, #visited allocation sites, #active allocation sites, " | 
 | 559 |           "#mementos, #tenure decisions, #donttenure decisions) " | 
 | 560 |           "(%s, %d, %d, %d, %d, %d)\n", | 
 | 561 |           use_scratchpad ? "use scratchpad" : "use list", allocation_sites, | 
 | 562 |           active_allocation_sites, allocation_mementos_found, tenure_decisions, | 
 | 563 |           dont_tenure_decisions); | 
 | 564 |     } | 
 | 565 |   } | 
 | 566 | } | 
 | 567 |  | 
 | 568 |  | 
 | 569 | void Heap::DeoptMarkedAllocationSites() { | 
 | 570 |   // TODO(hpayer): If iterating over the allocation sites list becomes a | 
 | 571 |   // performance issue, use a cache heap data structure instead (similar to the | 
 | 572 |   // allocation sites scratchpad). | 
 | 573 |   Object* list_element = allocation_sites_list(); | 
 | 574 |   while (list_element->IsAllocationSite()) { | 
 | 575 |     AllocationSite* site = AllocationSite::cast(list_element); | 
 | 576 |     if (site->deopt_dependent_code()) { | 
 | 577 |       site->dependent_code()->MarkCodeForDeoptimization( | 
 | 578 |           isolate_, DependentCode::kAllocationSiteTenuringChangedGroup); | 
 | 579 |       site->set_deopt_dependent_code(false); | 
 | 580 |     } | 
 | 581 |     list_element = site->weak_next(); | 
 | 582 |   } | 
 | 583 |   Deoptimizer::DeoptimizeMarkedCode(isolate_); | 
 | 584 | } | 
 | 585 |  | 
 | 586 |  | 
 | 587 | void Heap::GarbageCollectionEpilogue() { | 
 | 588 |   store_buffer()->GCEpilogue(); | 
 | 589 |  | 
 | 590 |   // In release mode, we only zap the from space under heap verification. | 
 | 591 |   if (Heap::ShouldZapGarbage()) { | 
 | 592 |     ZapFromSpace(); | 
 | 593 |   } | 
 | 594 |  | 
 | 595 |   // Process pretenuring feedback and update allocation sites. | 
 | 596 |   ProcessPretenuringFeedback(); | 
 | 597 |  | 
 | 598 | #ifdef VERIFY_HEAP | 
 | 599 |   if (FLAG_verify_heap) { | 
 | 600 |     Verify(); | 
 | 601 |   } | 
 | 602 | #endif | 
 | 603 |  | 
 | 604 |   AllowHeapAllocation for_the_rest_of_the_epilogue; | 
 | 605 |  | 
 | 606 | #ifdef DEBUG | 
 | 607 |   if (FLAG_print_global_handles) isolate_->global_handles()->Print(); | 
 | 608 |   if (FLAG_print_handles) PrintHandles(); | 
 | 609 |   if (FLAG_gc_verbose) Print(); | 
 | 610 |   if (FLAG_code_stats) ReportCodeStatistics("After GC"); | 
 | 611 | #endif | 
 | 612 |   if (FLAG_deopt_every_n_garbage_collections > 0) { | 
 | 613 |     // TODO(jkummerow/ulan/jarin): This is not safe! We can't assume that | 
 | 614 |     // the topmost optimized frame can be deoptimized safely, because it | 
 | 615 |     // might not have a lazy bailout point right after its current PC. | 
 | 616 |     if (++gcs_since_last_deopt_ == FLAG_deopt_every_n_garbage_collections) { | 
 | 617 |       Deoptimizer::DeoptimizeAll(isolate()); | 
 | 618 |       gcs_since_last_deopt_ = 0; | 
 | 619 |     } | 
 | 620 |   } | 
 | 621 |  | 
 | 622 |   UpdateMaximumCommitted(); | 
 | 623 |  | 
 | 624 |   isolate_->counters()->alive_after_last_gc()->Set( | 
 | 625 |       static_cast<int>(SizeOfObjects())); | 
 | 626 |  | 
 | 627 |   isolate_->counters()->string_table_capacity()->Set( | 
 | 628 |       string_table()->Capacity()); | 
 | 629 |   isolate_->counters()->number_of_symbols()->Set( | 
 | 630 |       string_table()->NumberOfElements()); | 
 | 631 |  | 
 | 632 |   if (full_codegen_bytes_generated_ + crankshaft_codegen_bytes_generated_ > 0) { | 
 | 633 |     isolate_->counters()->codegen_fraction_crankshaft()->AddSample( | 
 | 634 |         static_cast<int>((crankshaft_codegen_bytes_generated_ * 100.0) / | 
 | 635 |                          (crankshaft_codegen_bytes_generated_ + | 
 | 636 |                           full_codegen_bytes_generated_))); | 
 | 637 |   } | 
 | 638 |  | 
 | 639 |   if (CommittedMemory() > 0) { | 
 | 640 |     isolate_->counters()->external_fragmentation_total()->AddSample( | 
 | 641 |         static_cast<int>(100 - (SizeOfObjects() * 100.0) / CommittedMemory())); | 
 | 642 |  | 
 | 643 |     isolate_->counters()->heap_fraction_new_space()->AddSample(static_cast<int>( | 
 | 644 |         (new_space()->CommittedMemory() * 100.0) / CommittedMemory())); | 
 | 645 |     isolate_->counters()->heap_fraction_old_pointer_space()->AddSample( | 
 | 646 |         static_cast<int>((old_pointer_space()->CommittedMemory() * 100.0) / | 
 | 647 |                          CommittedMemory())); | 
 | 648 |     isolate_->counters()->heap_fraction_old_data_space()->AddSample( | 
 | 649 |         static_cast<int>((old_data_space()->CommittedMemory() * 100.0) / | 
 | 650 |                          CommittedMemory())); | 
 | 651 |     isolate_->counters()->heap_fraction_code_space()->AddSample( | 
 | 652 |         static_cast<int>((code_space()->CommittedMemory() * 100.0) / | 
 | 653 |                          CommittedMemory())); | 
 | 654 |     isolate_->counters()->heap_fraction_map_space()->AddSample(static_cast<int>( | 
 | 655 |         (map_space()->CommittedMemory() * 100.0) / CommittedMemory())); | 
 | 656 |     isolate_->counters()->heap_fraction_cell_space()->AddSample( | 
 | 657 |         static_cast<int>((cell_space()->CommittedMemory() * 100.0) / | 
 | 658 |                          CommittedMemory())); | 
 | 659 |     isolate_->counters()->heap_fraction_property_cell_space()->AddSample( | 
 | 660 |         static_cast<int>((property_cell_space()->CommittedMemory() * 100.0) / | 
 | 661 |                          CommittedMemory())); | 
 | 662 |     isolate_->counters()->heap_fraction_lo_space()->AddSample(static_cast<int>( | 
 | 663 |         (lo_space()->CommittedMemory() * 100.0) / CommittedMemory())); | 
 | 664 |  | 
 | 665 |     isolate_->counters()->heap_sample_total_committed()->AddSample( | 
 | 666 |         static_cast<int>(CommittedMemory() / KB)); | 
 | 667 |     isolate_->counters()->heap_sample_total_used()->AddSample( | 
 | 668 |         static_cast<int>(SizeOfObjects() / KB)); | 
 | 669 |     isolate_->counters()->heap_sample_map_space_committed()->AddSample( | 
 | 670 |         static_cast<int>(map_space()->CommittedMemory() / KB)); | 
 | 671 |     isolate_->counters()->heap_sample_cell_space_committed()->AddSample( | 
 | 672 |         static_cast<int>(cell_space()->CommittedMemory() / KB)); | 
 | 673 |     isolate_->counters() | 
 | 674 |         ->heap_sample_property_cell_space_committed() | 
 | 675 |         ->AddSample( | 
 | 676 |             static_cast<int>(property_cell_space()->CommittedMemory() / KB)); | 
 | 677 |     isolate_->counters()->heap_sample_code_space_committed()->AddSample( | 
 | 678 |         static_cast<int>(code_space()->CommittedMemory() / KB)); | 
 | 679 |  | 
 | 680 |     isolate_->counters()->heap_sample_maximum_committed()->AddSample( | 
 | 681 |         static_cast<int>(MaximumCommittedMemory() / KB)); | 
 | 682 |   } | 
 | 683 |  | 
 | 684 | #define UPDATE_COUNTERS_FOR_SPACE(space)                \ | 
 | 685 |   isolate_->counters()->space##_bytes_available()->Set( \ | 
 | 686 |       static_cast<int>(space()->Available()));          \ | 
 | 687 |   isolate_->counters()->space##_bytes_committed()->Set( \ | 
 | 688 |       static_cast<int>(space()->CommittedMemory()));    \ | 
 | 689 |   isolate_->counters()->space##_bytes_used()->Set(      \ | 
 | 690 |       static_cast<int>(space()->SizeOfObjects())); | 
 | 691 | #define UPDATE_FRAGMENTATION_FOR_SPACE(space)                          \ | 
 | 692 |   if (space()->CommittedMemory() > 0) {                                \ | 
 | 693 |     isolate_->counters()->external_fragmentation_##space()->AddSample( \ | 
 | 694 |         static_cast<int>(100 -                                         \ | 
 | 695 |                          (space()->SizeOfObjects() * 100.0) /          \ | 
 | 696 |                              space()->CommittedMemory()));             \ | 
 | 697 |   } | 
 | 698 | #define UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(space) \ | 
 | 699 |   UPDATE_COUNTERS_FOR_SPACE(space)                         \ | 
 | 700 |   UPDATE_FRAGMENTATION_FOR_SPACE(space) | 
 | 701 |  | 
 | 702 |   UPDATE_COUNTERS_FOR_SPACE(new_space) | 
 | 703 |   UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(old_pointer_space) | 
 | 704 |   UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(old_data_space) | 
 | 705 |   UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(code_space) | 
 | 706 |   UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(map_space) | 
 | 707 |   UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(cell_space) | 
 | 708 |   UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(property_cell_space) | 
 | 709 |   UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(lo_space) | 
 | 710 | #undef UPDATE_COUNTERS_FOR_SPACE | 
 | 711 | #undef UPDATE_FRAGMENTATION_FOR_SPACE | 
 | 712 | #undef UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE | 
 | 713 |  | 
 | 714 | #ifdef DEBUG | 
 | 715 |   ReportStatisticsAfterGC(); | 
 | 716 | #endif  // DEBUG | 
 | 717 |  | 
 | 718 |   // Remember the last top pointer so that we can later find out | 
 | 719 |   // whether we allocated in new space since the last GC. | 
 | 720 |   new_space_top_after_last_gc_ = new_space()->top(); | 
 | 721 | } | 
 | 722 |  | 
 | 723 |  | 
 | 724 | void Heap::CollectAllGarbage(int flags, const char* gc_reason, | 
 | 725 |                              const v8::GCCallbackFlags gc_callback_flags) { | 
 | 726 |   // Since we are ignoring the return value, the exact choice of space does | 
 | 727 |   // not matter, so long as we do not specify NEW_SPACE, which would not | 
 | 728 |   // cause a full GC. | 
 | 729 |   mark_compact_collector_.SetFlags(flags); | 
 | 730 |   CollectGarbage(OLD_POINTER_SPACE, gc_reason, gc_callback_flags); | 
 | 731 |   mark_compact_collector_.SetFlags(kNoGCFlags); | 
 | 732 | } | 
 | 733 |  | 
 | 734 |  | 
 | 735 | void Heap::CollectAllAvailableGarbage(const char* gc_reason) { | 
 | 736 |   // Since we are ignoring the return value, the exact choice of space does | 
 | 737 |   // not matter, so long as we do not specify NEW_SPACE, which would not | 
 | 738 |   // cause a full GC. | 
 | 739 |   // Major GC would invoke weak handle callbacks on weakly reachable | 
 | 740 |   // handles, but won't collect weakly reachable objects until next | 
 | 741 |   // major GC.  Therefore if we collect aggressively and weak handle callback | 
 | 742 |   // has been invoked, we rerun major GC to release objects which become | 
 | 743 |   // garbage. | 
 | 744 |   // Note: as weak callbacks can execute arbitrary code, we cannot | 
 | 745 |   // hope that eventually there will be no weak callbacks invocations. | 
 | 746 |   // Therefore stop recollecting after several attempts. | 
 | 747 |   if (isolate()->concurrent_recompilation_enabled()) { | 
 | 748 |     // The optimizing compiler may be unnecessarily holding on to memory. | 
 | 749 |     DisallowHeapAllocation no_recursive_gc; | 
 | 750 |     isolate()->optimizing_compiler_thread()->Flush(); | 
 | 751 |   } | 
 | 752 |   mark_compact_collector()->SetFlags(kMakeHeapIterableMask | | 
 | 753 |                                      kReduceMemoryFootprintMask); | 
 | 754 |   isolate_->compilation_cache()->Clear(); | 
 | 755 |   const int kMaxNumberOfAttempts = 7; | 
 | 756 |   const int kMinNumberOfAttempts = 2; | 
 | 757 |   for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) { | 
 | 758 |     if (!CollectGarbage(MARK_COMPACTOR, gc_reason, NULL) && | 
 | 759 |         attempt + 1 >= kMinNumberOfAttempts) { | 
 | 760 |       break; | 
 | 761 |     } | 
 | 762 |   } | 
 | 763 |   mark_compact_collector()->SetFlags(kNoGCFlags); | 
 | 764 |   new_space_.Shrink(); | 
 | 765 |   UncommitFromSpace(); | 
 | 766 |   incremental_marking()->UncommitMarkingDeque(); | 
 | 767 | } | 
 | 768 |  | 
 | 769 |  | 
 | 770 | void Heap::EnsureFillerObjectAtTop() { | 
 | 771 |   // There may be an allocation memento behind every object in new space. | 
 | 772 |   // If we evacuate a not full new space or if we are on the last page of | 
 | 773 |   // the new space, then there may be uninitialized memory behind the top | 
 | 774 |   // pointer of the new space page. We store a filler object there to | 
 | 775 |   // identify the unused space. | 
 | 776 |   Address from_top = new_space_.top(); | 
 | 777 |   Address from_limit = new_space_.limit(); | 
 | 778 |   if (from_top < from_limit) { | 
 | 779 |     int remaining_in_page = static_cast<int>(from_limit - from_top); | 
 | 780 |     CreateFillerObjectAt(from_top, remaining_in_page); | 
 | 781 |   } | 
 | 782 | } | 
 | 783 |  | 
 | 784 |  | 
 | 785 | bool Heap::CollectGarbage(GarbageCollector collector, const char* gc_reason, | 
 | 786 |                           const char* collector_reason, | 
 | 787 |                           const v8::GCCallbackFlags gc_callback_flags) { | 
 | 788 |   // The VM is in the GC state until exiting this function. | 
 | 789 |   VMState<GC> state(isolate_); | 
 | 790 |  | 
 | 791 | #ifdef DEBUG | 
 | 792 |   // Reset the allocation timeout to the GC interval, but make sure to | 
 | 793 |   // allow at least a few allocations after a collection. The reason | 
 | 794 |   // for this is that we have a lot of allocation sequences and we | 
 | 795 |   // assume that a garbage collection will allow the subsequent | 
 | 796 |   // allocation attempts to go through. | 
 | 797 |   allocation_timeout_ = Max(6, FLAG_gc_interval); | 
 | 798 | #endif | 
 | 799 |  | 
 | 800 |   EnsureFillerObjectAtTop(); | 
 | 801 |  | 
 | 802 |   if (collector == SCAVENGER && !incremental_marking()->IsStopped()) { | 
 | 803 |     if (FLAG_trace_incremental_marking) { | 
 | 804 |       PrintF("[IncrementalMarking] Scavenge during marking.\n"); | 
 | 805 |     } | 
 | 806 |   } | 
 | 807 |  | 
 | 808 |   if (collector == MARK_COMPACTOR && | 
 | 809 |       !mark_compact_collector()->abort_incremental_marking() && | 
 | 810 |       !incremental_marking()->IsStopped() && | 
 | 811 |       !incremental_marking()->should_hurry() && | 
 | 812 |       FLAG_incremental_marking_steps) { | 
 | 813 |     // Make progress in incremental marking. | 
 | 814 |     const intptr_t kStepSizeWhenDelayedByScavenge = 1 * MB; | 
 | 815 |     incremental_marking()->Step(kStepSizeWhenDelayedByScavenge, | 
 | 816 |                                 IncrementalMarking::NO_GC_VIA_STACK_GUARD); | 
 | 817 |     if (!incremental_marking()->IsComplete() && !FLAG_gc_global) { | 
 | 818 |       if (FLAG_trace_incremental_marking) { | 
 | 819 |         PrintF("[IncrementalMarking] Delaying MarkSweep.\n"); | 
 | 820 |       } | 
 | 821 |       collector = SCAVENGER; | 
 | 822 |       collector_reason = "incremental marking delaying mark-sweep"; | 
 | 823 |     } | 
 | 824 |   } | 
 | 825 |  | 
 | 826 |   bool next_gc_likely_to_collect_more = false; | 
 | 827 |  | 
 | 828 |   { | 
 | 829 |     tracer()->Start(collector, gc_reason, collector_reason); | 
 | 830 |     DCHECK(AllowHeapAllocation::IsAllowed()); | 
 | 831 |     DisallowHeapAllocation no_allocation_during_gc; | 
 | 832 |     GarbageCollectionPrologue(); | 
 | 833 |  | 
 | 834 |     { | 
 | 835 |       HistogramTimerScope histogram_timer_scope( | 
 | 836 |           (collector == SCAVENGER) ? isolate_->counters()->gc_scavenger() | 
 | 837 |                                    : isolate_->counters()->gc_compactor()); | 
 | 838 |       next_gc_likely_to_collect_more = | 
 | 839 |           PerformGarbageCollection(collector, gc_callback_flags); | 
 | 840 |     } | 
 | 841 |  | 
 | 842 |     GarbageCollectionEpilogue(); | 
 | 843 |     tracer()->Stop(); | 
 | 844 |   } | 
 | 845 |  | 
 | 846 |   // Start incremental marking for the next cycle. The heap snapshot | 
 | 847 |   // generator needs incremental marking to stay off after it aborted. | 
 | 848 |   if (!mark_compact_collector()->abort_incremental_marking() && | 
 | 849 |       WorthActivatingIncrementalMarking()) { | 
 | 850 |     incremental_marking()->Start(); | 
 | 851 |   } | 
 | 852 |  | 
 | 853 |   return next_gc_likely_to_collect_more; | 
 | 854 | } | 
 | 855 |  | 
 | 856 |  | 
 | 857 | int Heap::NotifyContextDisposed() { | 
 | 858 |   if (isolate()->concurrent_recompilation_enabled()) { | 
 | 859 |     // Flush the queued recompilation tasks. | 
 | 860 |     isolate()->optimizing_compiler_thread()->Flush(); | 
 | 861 |   } | 
 | 862 |   flush_monomorphic_ics_ = true; | 
 | 863 |   AgeInlineCaches(); | 
 | 864 |   return ++contexts_disposed_; | 
 | 865 | } | 
 | 866 |  | 
 | 867 |  | 
 | 868 | void Heap::MoveElements(FixedArray* array, int dst_index, int src_index, | 
 | 869 |                         int len) { | 
 | 870 |   if (len == 0) return; | 
 | 871 |  | 
 | 872 |   DCHECK(array->map() != fixed_cow_array_map()); | 
 | 873 |   Object** dst_objects = array->data_start() + dst_index; | 
 | 874 |   MemMove(dst_objects, array->data_start() + src_index, len * kPointerSize); | 
 | 875 |   if (!InNewSpace(array)) { | 
 | 876 |     for (int i = 0; i < len; i++) { | 
 | 877 |       // TODO(hpayer): check store buffer for entries | 
 | 878 |       if (InNewSpace(dst_objects[i])) { | 
 | 879 |         RecordWrite(array->address(), array->OffsetOfElementAt(dst_index + i)); | 
 | 880 |       } | 
 | 881 |     } | 
 | 882 |   } | 
 | 883 |   incremental_marking()->RecordWrites(array); | 
 | 884 | } | 
 | 885 |  | 
 | 886 |  | 
 | 887 | #ifdef VERIFY_HEAP | 
 | 888 | // Helper class for verifying the string table. | 
 | 889 | class StringTableVerifier : public ObjectVisitor { | 
 | 890 |  public: | 
 | 891 |   void VisitPointers(Object** start, Object** end) { | 
 | 892 |     // Visit all HeapObject pointers in [start, end). | 
 | 893 |     for (Object** p = start; p < end; p++) { | 
 | 894 |       if ((*p)->IsHeapObject()) { | 
 | 895 |         // Check that the string is actually internalized. | 
 | 896 |         CHECK((*p)->IsTheHole() || (*p)->IsUndefined() || | 
 | 897 |               (*p)->IsInternalizedString()); | 
 | 898 |       } | 
 | 899 |     } | 
 | 900 |   } | 
 | 901 | }; | 
 | 902 |  | 
 | 903 |  | 
 | 904 | static void VerifyStringTable(Heap* heap) { | 
 | 905 |   StringTableVerifier verifier; | 
 | 906 |   heap->string_table()->IterateElements(&verifier); | 
 | 907 | } | 
 | 908 | #endif  // VERIFY_HEAP | 
 | 909 |  | 
 | 910 |  | 
 | 911 | static bool AbortIncrementalMarkingAndCollectGarbage( | 
 | 912 |     Heap* heap, AllocationSpace space, const char* gc_reason = NULL) { | 
 | 913 |   heap->mark_compact_collector()->SetFlags(Heap::kAbortIncrementalMarkingMask); | 
 | 914 |   bool result = heap->CollectGarbage(space, gc_reason); | 
 | 915 |   heap->mark_compact_collector()->SetFlags(Heap::kNoGCFlags); | 
 | 916 |   return result; | 
 | 917 | } | 
 | 918 |  | 
 | 919 |  | 
 | 920 | void Heap::ReserveSpace(int* sizes, Address* locations_out) { | 
 | 921 |   bool gc_performed = true; | 
 | 922 |   int counter = 0; | 
 | 923 |   static const int kThreshold = 20; | 
 | 924 |   while (gc_performed && counter++ < kThreshold) { | 
 | 925 |     gc_performed = false; | 
 | 926 |     DCHECK(NEW_SPACE == FIRST_PAGED_SPACE - 1); | 
 | 927 |     for (int space = NEW_SPACE; space <= LAST_PAGED_SPACE; space++) { | 
 | 928 |       if (sizes[space] != 0) { | 
 | 929 |         AllocationResult allocation; | 
 | 930 |         if (space == NEW_SPACE) { | 
 | 931 |           allocation = new_space()->AllocateRaw(sizes[space]); | 
 | 932 |         } else { | 
 | 933 |           allocation = paged_space(space)->AllocateRaw(sizes[space]); | 
 | 934 |         } | 
 | 935 |         FreeListNode* node; | 
 | 936 |         if (!allocation.To(&node)) { | 
 | 937 |           if (space == NEW_SPACE) { | 
 | 938 |             Heap::CollectGarbage(NEW_SPACE, | 
 | 939 |                                  "failed to reserve space in the new space"); | 
 | 940 |           } else { | 
 | 941 |             AbortIncrementalMarkingAndCollectGarbage( | 
 | 942 |                 this, static_cast<AllocationSpace>(space), | 
 | 943 |                 "failed to reserve space in paged space"); | 
 | 944 |           } | 
 | 945 |           gc_performed = true; | 
 | 946 |           break; | 
 | 947 |         } else { | 
 | 948 |           // Mark with a free list node, in case we have a GC before | 
 | 949 |           // deserializing. | 
 | 950 |           node->set_size(this, sizes[space]); | 
 | 951 |           locations_out[space] = node->address(); | 
 | 952 |         } | 
 | 953 |       } | 
 | 954 |     } | 
 | 955 |   } | 
 | 956 |  | 
 | 957 |   if (gc_performed) { | 
 | 958 |     // Failed to reserve the space after several attempts. | 
 | 959 |     V8::FatalProcessOutOfMemory("Heap::ReserveSpace"); | 
 | 960 |   } | 
 | 961 | } | 
 | 962 |  | 
 | 963 |  | 
 | 964 | void Heap::EnsureFromSpaceIsCommitted() { | 
 | 965 |   if (new_space_.CommitFromSpaceIfNeeded()) return; | 
 | 966 |  | 
 | 967 |   // Committing memory to from space failed. | 
 | 968 |   // Memory is exhausted and we will die. | 
 | 969 |   V8::FatalProcessOutOfMemory("Committing semi space failed."); | 
 | 970 | } | 
 | 971 |  | 
 | 972 |  | 
 | 973 | void Heap::ClearJSFunctionResultCaches() { | 
 | 974 |   if (isolate_->bootstrapper()->IsActive()) return; | 
 | 975 |  | 
 | 976 |   Object* context = native_contexts_list(); | 
 | 977 |   while (!context->IsUndefined()) { | 
 | 978 |     // Get the caches for this context. GC can happen when the context | 
 | 979 |     // is not fully initialized, so the caches can be undefined. | 
 | 980 |     Object* caches_or_undefined = | 
 | 981 |         Context::cast(context)->get(Context::JSFUNCTION_RESULT_CACHES_INDEX); | 
 | 982 |     if (!caches_or_undefined->IsUndefined()) { | 
 | 983 |       FixedArray* caches = FixedArray::cast(caches_or_undefined); | 
 | 984 |       // Clear the caches: | 
 | 985 |       int length = caches->length(); | 
 | 986 |       for (int i = 0; i < length; i++) { | 
 | 987 |         JSFunctionResultCache::cast(caches->get(i))->Clear(); | 
 | 988 |       } | 
 | 989 |     } | 
 | 990 |     // Get the next context: | 
 | 991 |     context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); | 
 | 992 |   } | 
 | 993 | } | 
 | 994 |  | 
 | 995 |  | 
 | 996 | void Heap::ClearNormalizedMapCaches() { | 
 | 997 |   if (isolate_->bootstrapper()->IsActive() && | 
 | 998 |       !incremental_marking()->IsMarking()) { | 
 | 999 |     return; | 
 | 1000 |   } | 
 | 1001 |  | 
 | 1002 |   Object* context = native_contexts_list(); | 
 | 1003 |   while (!context->IsUndefined()) { | 
 | 1004 |     // GC can happen when the context is not fully initialized, | 
 | 1005 |     // so the cache can be undefined. | 
 | 1006 |     Object* cache = | 
 | 1007 |         Context::cast(context)->get(Context::NORMALIZED_MAP_CACHE_INDEX); | 
 | 1008 |     if (!cache->IsUndefined()) { | 
 | 1009 |       NormalizedMapCache::cast(cache)->Clear(); | 
 | 1010 |     } | 
 | 1011 |     context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); | 
 | 1012 |   } | 
 | 1013 | } | 
 | 1014 |  | 
 | 1015 |  | 
 | 1016 | void Heap::UpdateSurvivalStatistics(int start_new_space_size) { | 
 | 1017 |   if (start_new_space_size == 0) return; | 
 | 1018 |  | 
 | 1019 |   promotion_rate_ = (static_cast<double>(promoted_objects_size_) / | 
 | 1020 |                      static_cast<double>(start_new_space_size) * 100); | 
 | 1021 |  | 
 | 1022 |   semi_space_copied_rate_ = | 
 | 1023 |       (static_cast<double>(semi_space_copied_object_size_) / | 
 | 1024 |        static_cast<double>(start_new_space_size) * 100); | 
 | 1025 |  | 
 | 1026 |   double survival_rate = promotion_rate_ + semi_space_copied_rate_; | 
 | 1027 |  | 
 | 1028 |   if (survival_rate > kYoungSurvivalRateHighThreshold) { | 
 | 1029 |     high_survival_rate_period_length_++; | 
 | 1030 |   } else { | 
 | 1031 |     high_survival_rate_period_length_ = 0; | 
 | 1032 |   } | 
 | 1033 | } | 
 | 1034 |  | 
 | 1035 | bool Heap::PerformGarbageCollection( | 
 | 1036 |     GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags) { | 
 | 1037 |   int freed_global_handles = 0; | 
 | 1038 |  | 
 | 1039 |   if (collector != SCAVENGER) { | 
 | 1040 |     PROFILE(isolate_, CodeMovingGCEvent()); | 
 | 1041 |   } | 
 | 1042 |  | 
 | 1043 | #ifdef VERIFY_HEAP | 
 | 1044 |   if (FLAG_verify_heap) { | 
 | 1045 |     VerifyStringTable(this); | 
 | 1046 |   } | 
 | 1047 | #endif | 
 | 1048 |  | 
 | 1049 |   GCType gc_type = | 
 | 1050 |       collector == MARK_COMPACTOR ? kGCTypeMarkSweepCompact : kGCTypeScavenge; | 
 | 1051 |  | 
 | 1052 |   { | 
 | 1053 |     GCCallbacksScope scope(this); | 
 | 1054 |     if (scope.CheckReenter()) { | 
 | 1055 |       AllowHeapAllocation allow_allocation; | 
 | 1056 |       GCTracer::Scope scope(tracer(), GCTracer::Scope::EXTERNAL); | 
 | 1057 |       VMState<EXTERNAL> state(isolate_); | 
 | 1058 |       HandleScope handle_scope(isolate_); | 
 | 1059 |       CallGCPrologueCallbacks(gc_type, kNoGCCallbackFlags); | 
 | 1060 |     } | 
 | 1061 |   } | 
 | 1062 |  | 
 | 1063 |   EnsureFromSpaceIsCommitted(); | 
 | 1064 |  | 
 | 1065 |   int start_new_space_size = Heap::new_space()->SizeAsInt(); | 
 | 1066 |  | 
 | 1067 |   if (IsHighSurvivalRate()) { | 
 | 1068 |     // We speed up the incremental marker if it is running so that it | 
 | 1069 |     // does not fall behind the rate of promotion, which would cause a | 
 | 1070 |     // constantly growing old space. | 
 | 1071 |     incremental_marking()->NotifyOfHighPromotionRate(); | 
 | 1072 |   } | 
 | 1073 |  | 
 | 1074 |   if (collector == MARK_COMPACTOR) { | 
 | 1075 |     // Perform mark-sweep with optional compaction. | 
 | 1076 |     MarkCompact(); | 
 | 1077 |     sweep_generation_++; | 
 | 1078 |     // Temporarily set the limit for case when PostGarbageCollectionProcessing | 
 | 1079 |     // allocates and triggers GC. The real limit is set at after | 
 | 1080 |     // PostGarbageCollectionProcessing. | 
 | 1081 |     old_generation_allocation_limit_ = | 
 | 1082 |         OldGenerationAllocationLimit(PromotedSpaceSizeOfObjects(), 0); | 
 | 1083 |     old_gen_exhausted_ = false; | 
 | 1084 |   } else { | 
 | 1085 |     Scavenge(); | 
 | 1086 |   } | 
 | 1087 |  | 
 | 1088 |   UpdateSurvivalStatistics(start_new_space_size); | 
 | 1089 |  | 
 | 1090 |   isolate_->counters()->objs_since_last_young()->Set(0); | 
 | 1091 |  | 
 | 1092 |   // Callbacks that fire after this point might trigger nested GCs and | 
 | 1093 |   // restart incremental marking, the assertion can't be moved down. | 
 | 1094 |   DCHECK(collector == SCAVENGER || incremental_marking()->IsStopped()); | 
 | 1095 |  | 
 | 1096 |   gc_post_processing_depth_++; | 
 | 1097 |   { | 
 | 1098 |     AllowHeapAllocation allow_allocation; | 
 | 1099 |     GCTracer::Scope scope(tracer(), GCTracer::Scope::EXTERNAL); | 
 | 1100 |     freed_global_handles = | 
 | 1101 |         isolate_->global_handles()->PostGarbageCollectionProcessing(collector); | 
 | 1102 |   } | 
 | 1103 |   gc_post_processing_depth_--; | 
 | 1104 |  | 
 | 1105 |   isolate_->eternal_handles()->PostGarbageCollectionProcessing(this); | 
 | 1106 |  | 
 | 1107 |   // Update relocatables. | 
 | 1108 |   Relocatable::PostGarbageCollectionProcessing(isolate_); | 
 | 1109 |  | 
 | 1110 |   if (collector == MARK_COMPACTOR) { | 
 | 1111 |     // Register the amount of external allocated memory. | 
 | 1112 |     amount_of_external_allocated_memory_at_last_global_gc_ = | 
 | 1113 |         amount_of_external_allocated_memory_; | 
 | 1114 |     old_generation_allocation_limit_ = OldGenerationAllocationLimit( | 
 | 1115 |         PromotedSpaceSizeOfObjects(), freed_global_handles); | 
 | 1116 |   } | 
 | 1117 |  | 
 | 1118 |   { | 
 | 1119 |     GCCallbacksScope scope(this); | 
 | 1120 |     if (scope.CheckReenter()) { | 
 | 1121 |       AllowHeapAllocation allow_allocation; | 
 | 1122 |       GCTracer::Scope scope(tracer(), GCTracer::Scope::EXTERNAL); | 
 | 1123 |       VMState<EXTERNAL> state(isolate_); | 
 | 1124 |       HandleScope handle_scope(isolate_); | 
 | 1125 |       CallGCEpilogueCallbacks(gc_type, gc_callback_flags); | 
 | 1126 |     } | 
 | 1127 |   } | 
 | 1128 |  | 
 | 1129 | #ifdef VERIFY_HEAP | 
 | 1130 |   if (FLAG_verify_heap) { | 
 | 1131 |     VerifyStringTable(this); | 
 | 1132 |   } | 
 | 1133 | #endif | 
 | 1134 |  | 
 | 1135 |   return freed_global_handles > 0; | 
 | 1136 | } | 
 | 1137 |  | 
 | 1138 |  | 
 | 1139 | void Heap::CallGCPrologueCallbacks(GCType gc_type, GCCallbackFlags flags) { | 
 | 1140 |   for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) { | 
 | 1141 |     if (gc_type & gc_prologue_callbacks_[i].gc_type) { | 
 | 1142 |       if (!gc_prologue_callbacks_[i].pass_isolate_) { | 
 | 1143 |         v8::GCPrologueCallback callback = | 
 | 1144 |             reinterpret_cast<v8::GCPrologueCallback>( | 
 | 1145 |                 gc_prologue_callbacks_[i].callback); | 
 | 1146 |         callback(gc_type, flags); | 
 | 1147 |       } else { | 
 | 1148 |         v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate()); | 
 | 1149 |         gc_prologue_callbacks_[i].callback(isolate, gc_type, flags); | 
 | 1150 |       } | 
 | 1151 |     } | 
 | 1152 |   } | 
 | 1153 | } | 
 | 1154 |  | 
 | 1155 |  | 
 | 1156 | void Heap::CallGCEpilogueCallbacks(GCType gc_type, | 
 | 1157 |                                    GCCallbackFlags gc_callback_flags) { | 
 | 1158 |   for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) { | 
 | 1159 |     if (gc_type & gc_epilogue_callbacks_[i].gc_type) { | 
 | 1160 |       if (!gc_epilogue_callbacks_[i].pass_isolate_) { | 
 | 1161 |         v8::GCPrologueCallback callback = | 
 | 1162 |             reinterpret_cast<v8::GCPrologueCallback>( | 
 | 1163 |                 gc_epilogue_callbacks_[i].callback); | 
 | 1164 |         callback(gc_type, gc_callback_flags); | 
 | 1165 |       } else { | 
 | 1166 |         v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate()); | 
 | 1167 |         gc_epilogue_callbacks_[i].callback(isolate, gc_type, gc_callback_flags); | 
 | 1168 |       } | 
 | 1169 |     } | 
 | 1170 |   } | 
 | 1171 | } | 
 | 1172 |  | 
 | 1173 |  | 
 | 1174 | void Heap::MarkCompact() { | 
 | 1175 |   gc_state_ = MARK_COMPACT; | 
 | 1176 |   LOG(isolate_, ResourceEvent("markcompact", "begin")); | 
 | 1177 |  | 
 | 1178 |   uint64_t size_of_objects_before_gc = SizeOfObjects(); | 
 | 1179 |  | 
 | 1180 |   mark_compact_collector_.Prepare(); | 
 | 1181 |  | 
 | 1182 |   ms_count_++; | 
 | 1183 |  | 
 | 1184 |   MarkCompactPrologue(); | 
 | 1185 |  | 
 | 1186 |   mark_compact_collector_.CollectGarbage(); | 
 | 1187 |  | 
 | 1188 |   LOG(isolate_, ResourceEvent("markcompact", "end")); | 
 | 1189 |  | 
 | 1190 |   gc_state_ = NOT_IN_GC; | 
 | 1191 |  | 
 | 1192 |   isolate_->counters()->objs_since_last_full()->Set(0); | 
 | 1193 |  | 
 | 1194 |   flush_monomorphic_ics_ = false; | 
 | 1195 |  | 
 | 1196 |   if (FLAG_allocation_site_pretenuring) { | 
 | 1197 |     EvaluateOldSpaceLocalPretenuring(size_of_objects_before_gc); | 
 | 1198 |   } | 
 | 1199 | } | 
 | 1200 |  | 
 | 1201 |  | 
 | 1202 | void Heap::MarkCompactPrologue() { | 
 | 1203 |   // At any old GC clear the keyed lookup cache to enable collection of unused | 
 | 1204 |   // maps. | 
 | 1205 |   isolate_->keyed_lookup_cache()->Clear(); | 
 | 1206 |   isolate_->context_slot_cache()->Clear(); | 
 | 1207 |   isolate_->descriptor_lookup_cache()->Clear(); | 
 | 1208 |   RegExpResultsCache::Clear(string_split_cache()); | 
 | 1209 |   RegExpResultsCache::Clear(regexp_multiple_cache()); | 
 | 1210 |  | 
 | 1211 |   isolate_->compilation_cache()->MarkCompactPrologue(); | 
 | 1212 |  | 
 | 1213 |   CompletelyClearInstanceofCache(); | 
 | 1214 |  | 
 | 1215 |   FlushNumberStringCache(); | 
 | 1216 |   if (FLAG_cleanup_code_caches_at_gc) { | 
 | 1217 |     polymorphic_code_cache()->set_cache(undefined_value()); | 
 | 1218 |   } | 
 | 1219 |  | 
 | 1220 |   ClearNormalizedMapCaches(); | 
 | 1221 | } | 
 | 1222 |  | 
 | 1223 |  | 
 | 1224 | // Helper class for copying HeapObjects | 
 | 1225 | class ScavengeVisitor : public ObjectVisitor { | 
 | 1226 |  public: | 
 | 1227 |   explicit ScavengeVisitor(Heap* heap) : heap_(heap) {} | 
 | 1228 |  | 
 | 1229 |   void VisitPointer(Object** p) { ScavengePointer(p); } | 
 | 1230 |  | 
 | 1231 |   void VisitPointers(Object** start, Object** end) { | 
 | 1232 |     // Copy all HeapObject pointers in [start, end) | 
 | 1233 |     for (Object** p = start; p < end; p++) ScavengePointer(p); | 
 | 1234 |   } | 
 | 1235 |  | 
 | 1236 |  private: | 
 | 1237 |   void ScavengePointer(Object** p) { | 
 | 1238 |     Object* object = *p; | 
 | 1239 |     if (!heap_->InNewSpace(object)) return; | 
 | 1240 |     Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p), | 
 | 1241 |                          reinterpret_cast<HeapObject*>(object)); | 
 | 1242 |   } | 
 | 1243 |  | 
 | 1244 |   Heap* heap_; | 
 | 1245 | }; | 
 | 1246 |  | 
 | 1247 |  | 
 | 1248 | #ifdef VERIFY_HEAP | 
 | 1249 | // Visitor class to verify pointers in code or data space do not point into | 
 | 1250 | // new space. | 
 | 1251 | class VerifyNonPointerSpacePointersVisitor : public ObjectVisitor { | 
 | 1252 |  public: | 
 | 1253 |   explicit VerifyNonPointerSpacePointersVisitor(Heap* heap) : heap_(heap) {} | 
 | 1254 |   void VisitPointers(Object** start, Object** end) { | 
 | 1255 |     for (Object** current = start; current < end; current++) { | 
 | 1256 |       if ((*current)->IsHeapObject()) { | 
 | 1257 |         CHECK(!heap_->InNewSpace(HeapObject::cast(*current))); | 
 | 1258 |       } | 
 | 1259 |     } | 
 | 1260 |   } | 
 | 1261 |  | 
 | 1262 |  private: | 
 | 1263 |   Heap* heap_; | 
 | 1264 | }; | 
 | 1265 |  | 
 | 1266 |  | 
 | 1267 | static void VerifyNonPointerSpacePointers(Heap* heap) { | 
 | 1268 |   // Verify that there are no pointers to new space in spaces where we | 
 | 1269 |   // do not expect them. | 
 | 1270 |   VerifyNonPointerSpacePointersVisitor v(heap); | 
 | 1271 |   HeapObjectIterator code_it(heap->code_space()); | 
 | 1272 |   for (HeapObject* object = code_it.Next(); object != NULL; | 
 | 1273 |        object = code_it.Next()) | 
 | 1274 |     object->Iterate(&v); | 
 | 1275 |  | 
 | 1276 |     HeapObjectIterator data_it(heap->old_data_space()); | 
 | 1277 |     for (HeapObject* object = data_it.Next(); object != NULL; | 
 | 1278 |          object = data_it.Next()) | 
 | 1279 |       object->Iterate(&v); | 
 | 1280 | } | 
 | 1281 | #endif  // VERIFY_HEAP | 
 | 1282 |  | 
 | 1283 |  | 
 | 1284 | void Heap::CheckNewSpaceExpansionCriteria() { | 
 | 1285 |   if (new_space_.TotalCapacity() < new_space_.MaximumCapacity() && | 
 | 1286 |       survived_since_last_expansion_ > new_space_.TotalCapacity()) { | 
 | 1287 |     // Grow the size of new space if there is room to grow, enough data | 
 | 1288 |     // has survived scavenge since the last expansion and we are not in | 
 | 1289 |     // high promotion mode. | 
 | 1290 |     new_space_.Grow(); | 
 | 1291 |     survived_since_last_expansion_ = 0; | 
 | 1292 |   } | 
 | 1293 | } | 
 | 1294 |  | 
 | 1295 |  | 
 | 1296 | static bool IsUnscavengedHeapObject(Heap* heap, Object** p) { | 
 | 1297 |   return heap->InNewSpace(*p) && | 
 | 1298 |          !HeapObject::cast(*p)->map_word().IsForwardingAddress(); | 
 | 1299 | } | 
 | 1300 |  | 
 | 1301 |  | 
 | 1302 | void Heap::ScavengeStoreBufferCallback(Heap* heap, MemoryChunk* page, | 
 | 1303 |                                        StoreBufferEvent event) { | 
 | 1304 |   heap->store_buffer_rebuilder_.Callback(page, event); | 
 | 1305 | } | 
 | 1306 |  | 
 | 1307 |  | 
 | 1308 | void StoreBufferRebuilder::Callback(MemoryChunk* page, StoreBufferEvent event) { | 
 | 1309 |   if (event == kStoreBufferStartScanningPagesEvent) { | 
 | 1310 |     start_of_current_page_ = NULL; | 
 | 1311 |     current_page_ = NULL; | 
 | 1312 |   } else if (event == kStoreBufferScanningPageEvent) { | 
 | 1313 |     if (current_page_ != NULL) { | 
 | 1314 |       // If this page already overflowed the store buffer during this iteration. | 
 | 1315 |       if (current_page_->scan_on_scavenge()) { | 
 | 1316 |         // Then we should wipe out the entries that have been added for it. | 
 | 1317 |         store_buffer_->SetTop(start_of_current_page_); | 
 | 1318 |       } else if (store_buffer_->Top() - start_of_current_page_ >= | 
 | 1319 |                  (store_buffer_->Limit() - store_buffer_->Top()) >> 2) { | 
 | 1320 |         // Did we find too many pointers in the previous page?  The heuristic is | 
 | 1321 |         // that no page can take more then 1/5 the remaining slots in the store | 
 | 1322 |         // buffer. | 
 | 1323 |         current_page_->set_scan_on_scavenge(true); | 
 | 1324 |         store_buffer_->SetTop(start_of_current_page_); | 
 | 1325 |       } else { | 
 | 1326 |         // In this case the page we scanned took a reasonable number of slots in | 
 | 1327 |         // the store buffer.  It has now been rehabilitated and is no longer | 
 | 1328 |         // marked scan_on_scavenge. | 
 | 1329 |         DCHECK(!current_page_->scan_on_scavenge()); | 
 | 1330 |       } | 
 | 1331 |     } | 
 | 1332 |     start_of_current_page_ = store_buffer_->Top(); | 
 | 1333 |     current_page_ = page; | 
 | 1334 |   } else if (event == kStoreBufferFullEvent) { | 
 | 1335 |     // The current page overflowed the store buffer again.  Wipe out its entries | 
 | 1336 |     // in the store buffer and mark it scan-on-scavenge again.  This may happen | 
 | 1337 |     // several times while scanning. | 
 | 1338 |     if (current_page_ == NULL) { | 
 | 1339 |       // Store Buffer overflowed while scanning promoted objects.  These are not | 
 | 1340 |       // in any particular page, though they are likely to be clustered by the | 
 | 1341 |       // allocation routines. | 
 | 1342 |       store_buffer_->EnsureSpace(StoreBuffer::kStoreBufferSize / 2); | 
 | 1343 |     } else { | 
 | 1344 |       // Store Buffer overflowed while scanning a particular old space page for | 
 | 1345 |       // pointers to new space. | 
 | 1346 |       DCHECK(current_page_ == page); | 
 | 1347 |       DCHECK(page != NULL); | 
 | 1348 |       current_page_->set_scan_on_scavenge(true); | 
 | 1349 |       DCHECK(start_of_current_page_ != store_buffer_->Top()); | 
 | 1350 |       store_buffer_->SetTop(start_of_current_page_); | 
 | 1351 |     } | 
 | 1352 |   } else { | 
 | 1353 |     UNREACHABLE(); | 
 | 1354 |   } | 
 | 1355 | } | 
 | 1356 |  | 
 | 1357 |  | 
 | 1358 | void PromotionQueue::Initialize() { | 
 | 1359 |   // Assumes that a NewSpacePage exactly fits a number of promotion queue | 
 | 1360 |   // entries (where each is a pair of intptr_t). This allows us to simplify | 
 | 1361 |   // the test fpr when to switch pages. | 
 | 1362 |   DCHECK((Page::kPageSize - MemoryChunk::kBodyOffset) % (2 * kPointerSize) == | 
 | 1363 |          0); | 
 | 1364 |   limit_ = reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceStart()); | 
 | 1365 |   front_ = rear_ = | 
 | 1366 |       reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceEnd()); | 
 | 1367 |   emergency_stack_ = NULL; | 
 | 1368 | } | 
 | 1369 |  | 
 | 1370 |  | 
 | 1371 | void PromotionQueue::RelocateQueueHead() { | 
 | 1372 |   DCHECK(emergency_stack_ == NULL); | 
 | 1373 |  | 
 | 1374 |   Page* p = Page::FromAllocationTop(reinterpret_cast<Address>(rear_)); | 
 | 1375 |   intptr_t* head_start = rear_; | 
 | 1376 |   intptr_t* head_end = Min(front_, reinterpret_cast<intptr_t*>(p->area_end())); | 
 | 1377 |  | 
 | 1378 |   int entries_count = | 
 | 1379 |       static_cast<int>(head_end - head_start) / kEntrySizeInWords; | 
 | 1380 |  | 
 | 1381 |   emergency_stack_ = new List<Entry>(2 * entries_count); | 
 | 1382 |  | 
 | 1383 |   while (head_start != head_end) { | 
 | 1384 |     int size = static_cast<int>(*(head_start++)); | 
 | 1385 |     HeapObject* obj = reinterpret_cast<HeapObject*>(*(head_start++)); | 
 | 1386 |     emergency_stack_->Add(Entry(obj, size)); | 
 | 1387 |   } | 
 | 1388 |   rear_ = head_end; | 
 | 1389 | } | 
 | 1390 |  | 
 | 1391 |  | 
 | 1392 | class ScavengeWeakObjectRetainer : public WeakObjectRetainer { | 
 | 1393 |  public: | 
 | 1394 |   explicit ScavengeWeakObjectRetainer(Heap* heap) : heap_(heap) {} | 
 | 1395 |  | 
 | 1396 |   virtual Object* RetainAs(Object* object) { | 
 | 1397 |     if (!heap_->InFromSpace(object)) { | 
 | 1398 |       return object; | 
 | 1399 |     } | 
 | 1400 |  | 
 | 1401 |     MapWord map_word = HeapObject::cast(object)->map_word(); | 
 | 1402 |     if (map_word.IsForwardingAddress()) { | 
 | 1403 |       return map_word.ToForwardingAddress(); | 
 | 1404 |     } | 
 | 1405 |     return NULL; | 
 | 1406 |   } | 
 | 1407 |  | 
 | 1408 |  private: | 
 | 1409 |   Heap* heap_; | 
 | 1410 | }; | 
 | 1411 |  | 
 | 1412 |  | 
 | 1413 | void Heap::Scavenge() { | 
 | 1414 |   RelocationLock relocation_lock(this); | 
 | 1415 |  | 
 | 1416 | #ifdef VERIFY_HEAP | 
 | 1417 |   if (FLAG_verify_heap) VerifyNonPointerSpacePointers(this); | 
 | 1418 | #endif | 
 | 1419 |  | 
 | 1420 |   gc_state_ = SCAVENGE; | 
 | 1421 |  | 
 | 1422 |   // Implements Cheney's copying algorithm | 
 | 1423 |   LOG(isolate_, ResourceEvent("scavenge", "begin")); | 
 | 1424 |  | 
 | 1425 |   // Clear descriptor cache. | 
 | 1426 |   isolate_->descriptor_lookup_cache()->Clear(); | 
 | 1427 |  | 
 | 1428 |   // Used for updating survived_since_last_expansion_ at function end. | 
 | 1429 |   intptr_t survived_watermark = PromotedSpaceSizeOfObjects(); | 
 | 1430 |  | 
 | 1431 |   SelectScavengingVisitorsTable(); | 
 | 1432 |  | 
 | 1433 |   incremental_marking()->PrepareForScavenge(); | 
 | 1434 |  | 
 | 1435 |   // Flip the semispaces.  After flipping, to space is empty, from space has | 
 | 1436 |   // live objects. | 
 | 1437 |   new_space_.Flip(); | 
 | 1438 |   new_space_.ResetAllocationInfo(); | 
 | 1439 |  | 
 | 1440 |   // We need to sweep newly copied objects which can be either in the | 
 | 1441 |   // to space or promoted to the old generation.  For to-space | 
 | 1442 |   // objects, we treat the bottom of the to space as a queue.  Newly | 
 | 1443 |   // copied and unswept objects lie between a 'front' mark and the | 
 | 1444 |   // allocation pointer. | 
 | 1445 |   // | 
 | 1446 |   // Promoted objects can go into various old-generation spaces, and | 
 | 1447 |   // can be allocated internally in the spaces (from the free list). | 
 | 1448 |   // We treat the top of the to space as a queue of addresses of | 
 | 1449 |   // promoted objects.  The addresses of newly promoted and unswept | 
 | 1450 |   // objects lie between a 'front' mark and a 'rear' mark that is | 
 | 1451 |   // updated as a side effect of promoting an object. | 
 | 1452 |   // | 
 | 1453 |   // There is guaranteed to be enough room at the top of the to space | 
 | 1454 |   // for the addresses of promoted objects: every object promoted | 
 | 1455 |   // frees up its size in bytes from the top of the new space, and | 
 | 1456 |   // objects are at least one pointer in size. | 
 | 1457 |   Address new_space_front = new_space_.ToSpaceStart(); | 
 | 1458 |   promotion_queue_.Initialize(); | 
 | 1459 |  | 
 | 1460 | #ifdef DEBUG | 
 | 1461 |   store_buffer()->Clean(); | 
 | 1462 | #endif | 
 | 1463 |  | 
 | 1464 |   ScavengeVisitor scavenge_visitor(this); | 
 | 1465 |   // Copy roots. | 
 | 1466 |   IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE); | 
 | 1467 |  | 
 | 1468 |   // Copy objects reachable from the old generation. | 
 | 1469 |   { | 
 | 1470 |     StoreBufferRebuildScope scope(this, store_buffer(), | 
 | 1471 |                                   &ScavengeStoreBufferCallback); | 
 | 1472 |     store_buffer()->IteratePointersToNewSpace(&ScavengeObject); | 
 | 1473 |   } | 
 | 1474 |  | 
 | 1475 |   // Copy objects reachable from simple cells by scavenging cell values | 
 | 1476 |   // directly. | 
 | 1477 |   HeapObjectIterator cell_iterator(cell_space_); | 
 | 1478 |   for (HeapObject* heap_object = cell_iterator.Next(); heap_object != NULL; | 
 | 1479 |        heap_object = cell_iterator.Next()) { | 
 | 1480 |     if (heap_object->IsCell()) { | 
 | 1481 |       Cell* cell = Cell::cast(heap_object); | 
 | 1482 |       Address value_address = cell->ValueAddress(); | 
 | 1483 |       scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address)); | 
 | 1484 |     } | 
 | 1485 |   } | 
 | 1486 |  | 
 | 1487 |   // Copy objects reachable from global property cells by scavenging global | 
 | 1488 |   // property cell values directly. | 
 | 1489 |   HeapObjectIterator js_global_property_cell_iterator(property_cell_space_); | 
 | 1490 |   for (HeapObject* heap_object = js_global_property_cell_iterator.Next(); | 
 | 1491 |        heap_object != NULL; | 
 | 1492 |        heap_object = js_global_property_cell_iterator.Next()) { | 
 | 1493 |     if (heap_object->IsPropertyCell()) { | 
 | 1494 |       PropertyCell* cell = PropertyCell::cast(heap_object); | 
 | 1495 |       Address value_address = cell->ValueAddress(); | 
 | 1496 |       scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address)); | 
 | 1497 |       Address type_address = cell->TypeAddress(); | 
 | 1498 |       scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(type_address)); | 
 | 1499 |     } | 
 | 1500 |   } | 
 | 1501 |  | 
 | 1502 |   // Copy objects reachable from the encountered weak collections list. | 
 | 1503 |   scavenge_visitor.VisitPointer(&encountered_weak_collections_); | 
 | 1504 |  | 
 | 1505 |   // Copy objects reachable from the code flushing candidates list. | 
 | 1506 |   MarkCompactCollector* collector = mark_compact_collector(); | 
 | 1507 |   if (collector->is_code_flushing_enabled()) { | 
 | 1508 |     collector->code_flusher()->IteratePointersToFromSpace(&scavenge_visitor); | 
 | 1509 |   } | 
 | 1510 |  | 
 | 1511 |   new_space_front = DoScavenge(&scavenge_visitor, new_space_front); | 
 | 1512 |  | 
 | 1513 |   while (isolate()->global_handles()->IterateObjectGroups( | 
 | 1514 |       &scavenge_visitor, &IsUnscavengedHeapObject)) { | 
 | 1515 |     new_space_front = DoScavenge(&scavenge_visitor, new_space_front); | 
 | 1516 |   } | 
 | 1517 |   isolate()->global_handles()->RemoveObjectGroups(); | 
 | 1518 |   isolate()->global_handles()->RemoveImplicitRefGroups(); | 
 | 1519 |  | 
 | 1520 |   isolate_->global_handles()->IdentifyNewSpaceWeakIndependentHandles( | 
 | 1521 |       &IsUnscavengedHeapObject); | 
 | 1522 |   isolate_->global_handles()->IterateNewSpaceWeakIndependentRoots( | 
 | 1523 |       &scavenge_visitor); | 
 | 1524 |   new_space_front = DoScavenge(&scavenge_visitor, new_space_front); | 
 | 1525 |  | 
 | 1526 |   UpdateNewSpaceReferencesInExternalStringTable( | 
 | 1527 |       &UpdateNewSpaceReferenceInExternalStringTableEntry); | 
 | 1528 |  | 
 | 1529 |   promotion_queue_.Destroy(); | 
 | 1530 |  | 
 | 1531 |   incremental_marking()->UpdateMarkingDequeAfterScavenge(); | 
 | 1532 |  | 
 | 1533 |   ScavengeWeakObjectRetainer weak_object_retainer(this); | 
 | 1534 |   ProcessWeakReferences(&weak_object_retainer); | 
 | 1535 |  | 
 | 1536 |   DCHECK(new_space_front == new_space_.top()); | 
 | 1537 |  | 
 | 1538 |   // Set age mark. | 
 | 1539 |   new_space_.set_age_mark(new_space_.top()); | 
 | 1540 |  | 
 | 1541 |   new_space_.LowerInlineAllocationLimit( | 
 | 1542 |       new_space_.inline_allocation_limit_step()); | 
 | 1543 |  | 
 | 1544 |   // Update how much has survived scavenge. | 
 | 1545 |   IncrementYoungSurvivorsCounter(static_cast<int>( | 
 | 1546 |       (PromotedSpaceSizeOfObjects() - survived_watermark) + new_space_.Size())); | 
 | 1547 |  | 
 | 1548 |   LOG(isolate_, ResourceEvent("scavenge", "end")); | 
 | 1549 |  | 
 | 1550 |   gc_state_ = NOT_IN_GC; | 
 | 1551 |  | 
 | 1552 |   gc_idle_time_handler_.NotifyScavenge(); | 
 | 1553 | } | 
 | 1554 |  | 
 | 1555 |  | 
 | 1556 | String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap, | 
 | 1557 |                                                                 Object** p) { | 
 | 1558 |   MapWord first_word = HeapObject::cast(*p)->map_word(); | 
 | 1559 |  | 
 | 1560 |   if (!first_word.IsForwardingAddress()) { | 
 | 1561 |     // Unreachable external string can be finalized. | 
 | 1562 |     heap->FinalizeExternalString(String::cast(*p)); | 
 | 1563 |     return NULL; | 
 | 1564 |   } | 
 | 1565 |  | 
 | 1566 |   // String is still reachable. | 
 | 1567 |   return String::cast(first_word.ToForwardingAddress()); | 
 | 1568 | } | 
 | 1569 |  | 
 | 1570 |  | 
 | 1571 | void Heap::UpdateNewSpaceReferencesInExternalStringTable( | 
 | 1572 |     ExternalStringTableUpdaterCallback updater_func) { | 
 | 1573 | #ifdef VERIFY_HEAP | 
 | 1574 |   if (FLAG_verify_heap) { | 
 | 1575 |     external_string_table_.Verify(); | 
 | 1576 |   } | 
 | 1577 | #endif | 
 | 1578 |  | 
 | 1579 |   if (external_string_table_.new_space_strings_.is_empty()) return; | 
 | 1580 |  | 
 | 1581 |   Object** start = &external_string_table_.new_space_strings_[0]; | 
 | 1582 |   Object** end = start + external_string_table_.new_space_strings_.length(); | 
 | 1583 |   Object** last = start; | 
 | 1584 |  | 
 | 1585 |   for (Object** p = start; p < end; ++p) { | 
 | 1586 |     DCHECK(InFromSpace(*p)); | 
 | 1587 |     String* target = updater_func(this, p); | 
 | 1588 |  | 
 | 1589 |     if (target == NULL) continue; | 
 | 1590 |  | 
 | 1591 |     DCHECK(target->IsExternalString()); | 
 | 1592 |  | 
 | 1593 |     if (InNewSpace(target)) { | 
 | 1594 |       // String is still in new space.  Update the table entry. | 
 | 1595 |       *last = target; | 
 | 1596 |       ++last; | 
 | 1597 |     } else { | 
 | 1598 |       // String got promoted.  Move it to the old string list. | 
 | 1599 |       external_string_table_.AddOldString(target); | 
 | 1600 |     } | 
 | 1601 |   } | 
 | 1602 |  | 
 | 1603 |   DCHECK(last <= end); | 
 | 1604 |   external_string_table_.ShrinkNewStrings(static_cast<int>(last - start)); | 
 | 1605 | } | 
 | 1606 |  | 
 | 1607 |  | 
 | 1608 | void Heap::UpdateReferencesInExternalStringTable( | 
 | 1609 |     ExternalStringTableUpdaterCallback updater_func) { | 
 | 1610 |   // Update old space string references. | 
 | 1611 |   if (external_string_table_.old_space_strings_.length() > 0) { | 
 | 1612 |     Object** start = &external_string_table_.old_space_strings_[0]; | 
 | 1613 |     Object** end = start + external_string_table_.old_space_strings_.length(); | 
 | 1614 |     for (Object** p = start; p < end; ++p) *p = updater_func(this, p); | 
 | 1615 |   } | 
 | 1616 |  | 
 | 1617 |   UpdateNewSpaceReferencesInExternalStringTable(updater_func); | 
 | 1618 | } | 
 | 1619 |  | 
 | 1620 |  | 
 | 1621 | void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) { | 
 | 1622 |   ProcessArrayBuffers(retainer); | 
 | 1623 |   ProcessNativeContexts(retainer); | 
 | 1624 |   // TODO(mvstanton): AllocationSites only need to be processed during | 
 | 1625 |   // MARK_COMPACT, as they live in old space. Verify and address. | 
 | 1626 |   ProcessAllocationSites(retainer); | 
 | 1627 | } | 
 | 1628 |  | 
 | 1629 |  | 
 | 1630 | void Heap::ProcessNativeContexts(WeakObjectRetainer* retainer) { | 
 | 1631 |   Object* head = VisitWeakList<Context>(this, native_contexts_list(), retainer); | 
 | 1632 |   // Update the head of the list of contexts. | 
 | 1633 |   set_native_contexts_list(head); | 
 | 1634 | } | 
 | 1635 |  | 
 | 1636 |  | 
 | 1637 | void Heap::ProcessArrayBuffers(WeakObjectRetainer* retainer) { | 
 | 1638 |   Object* array_buffer_obj = | 
 | 1639 |       VisitWeakList<JSArrayBuffer>(this, array_buffers_list(), retainer); | 
 | 1640 |   set_array_buffers_list(array_buffer_obj); | 
 | 1641 | } | 
 | 1642 |  | 
 | 1643 |  | 
 | 1644 | void Heap::TearDownArrayBuffers() { | 
 | 1645 |   Object* undefined = undefined_value(); | 
 | 1646 |   for (Object* o = array_buffers_list(); o != undefined;) { | 
 | 1647 |     JSArrayBuffer* buffer = JSArrayBuffer::cast(o); | 
 | 1648 |     Runtime::FreeArrayBuffer(isolate(), buffer); | 
 | 1649 |     o = buffer->weak_next(); | 
 | 1650 |   } | 
 | 1651 |   set_array_buffers_list(undefined); | 
 | 1652 | } | 
 | 1653 |  | 
 | 1654 |  | 
 | 1655 | void Heap::ProcessAllocationSites(WeakObjectRetainer* retainer) { | 
 | 1656 |   Object* allocation_site_obj = | 
 | 1657 |       VisitWeakList<AllocationSite>(this, allocation_sites_list(), retainer); | 
 | 1658 |   set_allocation_sites_list(allocation_site_obj); | 
 | 1659 | } | 
 | 1660 |  | 
 | 1661 |  | 
 | 1662 | void Heap::ResetAllAllocationSitesDependentCode(PretenureFlag flag) { | 
 | 1663 |   DisallowHeapAllocation no_allocation_scope; | 
 | 1664 |   Object* cur = allocation_sites_list(); | 
 | 1665 |   bool marked = false; | 
 | 1666 |   while (cur->IsAllocationSite()) { | 
 | 1667 |     AllocationSite* casted = AllocationSite::cast(cur); | 
 | 1668 |     if (casted->GetPretenureMode() == flag) { | 
 | 1669 |       casted->ResetPretenureDecision(); | 
 | 1670 |       casted->set_deopt_dependent_code(true); | 
 | 1671 |       marked = true; | 
 | 1672 |     } | 
 | 1673 |     cur = casted->weak_next(); | 
 | 1674 |   } | 
 | 1675 |   if (marked) isolate_->stack_guard()->RequestDeoptMarkedAllocationSites(); | 
 | 1676 | } | 
 | 1677 |  | 
 | 1678 |  | 
 | 1679 | void Heap::EvaluateOldSpaceLocalPretenuring( | 
 | 1680 |     uint64_t size_of_objects_before_gc) { | 
 | 1681 |   uint64_t size_of_objects_after_gc = SizeOfObjects(); | 
 | 1682 |   double old_generation_survival_rate = | 
 | 1683 |       (static_cast<double>(size_of_objects_after_gc) * 100) / | 
 | 1684 |       static_cast<double>(size_of_objects_before_gc); | 
 | 1685 |  | 
 | 1686 |   if (old_generation_survival_rate < kOldSurvivalRateLowThreshold) { | 
 | 1687 |     // Too many objects died in the old generation, pretenuring of wrong | 
 | 1688 |     // allocation sites may be the cause for that. We have to deopt all | 
 | 1689 |     // dependent code registered in the allocation sites to re-evaluate | 
 | 1690 |     // our pretenuring decisions. | 
 | 1691 |     ResetAllAllocationSitesDependentCode(TENURED); | 
 | 1692 |     if (FLAG_trace_pretenuring) { | 
 | 1693 |       PrintF( | 
 | 1694 |           "Deopt all allocation sites dependent code due to low survival " | 
 | 1695 |           "rate in the old generation %f\n", | 
 | 1696 |           old_generation_survival_rate); | 
 | 1697 |     } | 
 | 1698 |   } | 
 | 1699 | } | 
 | 1700 |  | 
 | 1701 |  | 
 | 1702 | void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) { | 
 | 1703 |   DisallowHeapAllocation no_allocation; | 
 | 1704 |   // All external strings are listed in the external string table. | 
 | 1705 |  | 
 | 1706 |   class ExternalStringTableVisitorAdapter : public ObjectVisitor { | 
 | 1707 |    public: | 
 | 1708 |     explicit ExternalStringTableVisitorAdapter( | 
 | 1709 |         v8::ExternalResourceVisitor* visitor) | 
 | 1710 |         : visitor_(visitor) {} | 
 | 1711 |     virtual void VisitPointers(Object** start, Object** end) { | 
 | 1712 |       for (Object** p = start; p < end; p++) { | 
 | 1713 |         DCHECK((*p)->IsExternalString()); | 
 | 1714 |         visitor_->VisitExternalString( | 
 | 1715 |             Utils::ToLocal(Handle<String>(String::cast(*p)))); | 
 | 1716 |       } | 
 | 1717 |     } | 
 | 1718 |  | 
 | 1719 |    private: | 
 | 1720 |     v8::ExternalResourceVisitor* visitor_; | 
 | 1721 |   } external_string_table_visitor(visitor); | 
 | 1722 |  | 
 | 1723 |   external_string_table_.Iterate(&external_string_table_visitor); | 
 | 1724 | } | 
 | 1725 |  | 
 | 1726 |  | 
 | 1727 | class NewSpaceScavenger : public StaticNewSpaceVisitor<NewSpaceScavenger> { | 
 | 1728 |  public: | 
 | 1729 |   static inline void VisitPointer(Heap* heap, Object** p) { | 
 | 1730 |     Object* object = *p; | 
 | 1731 |     if (!heap->InNewSpace(object)) return; | 
 | 1732 |     Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p), | 
 | 1733 |                          reinterpret_cast<HeapObject*>(object)); | 
 | 1734 |   } | 
 | 1735 | }; | 
 | 1736 |  | 
 | 1737 |  | 
 | 1738 | Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor, | 
 | 1739 |                          Address new_space_front) { | 
 | 1740 |   do { | 
 | 1741 |     SemiSpace::AssertValidRange(new_space_front, new_space_.top()); | 
 | 1742 |     // The addresses new_space_front and new_space_.top() define a | 
 | 1743 |     // queue of unprocessed copied objects.  Process them until the | 
 | 1744 |     // queue is empty. | 
 | 1745 |     while (new_space_front != new_space_.top()) { | 
 | 1746 |       if (!NewSpacePage::IsAtEnd(new_space_front)) { | 
 | 1747 |         HeapObject* object = HeapObject::FromAddress(new_space_front); | 
 | 1748 |         new_space_front += | 
 | 1749 |             NewSpaceScavenger::IterateBody(object->map(), object); | 
 | 1750 |       } else { | 
 | 1751 |         new_space_front = | 
 | 1752 |             NewSpacePage::FromLimit(new_space_front)->next_page()->area_start(); | 
 | 1753 |       } | 
 | 1754 |     } | 
 | 1755 |  | 
 | 1756 |     // Promote and process all the to-be-promoted objects. | 
 | 1757 |     { | 
 | 1758 |       StoreBufferRebuildScope scope(this, store_buffer(), | 
 | 1759 |                                     &ScavengeStoreBufferCallback); | 
 | 1760 |       while (!promotion_queue()->is_empty()) { | 
 | 1761 |         HeapObject* target; | 
 | 1762 |         int size; | 
 | 1763 |         promotion_queue()->remove(&target, &size); | 
 | 1764 |  | 
 | 1765 |         // Promoted object might be already partially visited | 
 | 1766 |         // during old space pointer iteration. Thus we search specificly | 
 | 1767 |         // for pointers to from semispace instead of looking for pointers | 
 | 1768 |         // to new space. | 
 | 1769 |         DCHECK(!target->IsMap()); | 
 | 1770 |         IterateAndMarkPointersToFromSpace( | 
 | 1771 |             target->address(), target->address() + size, &ScavengeObject); | 
 | 1772 |       } | 
 | 1773 |     } | 
 | 1774 |  | 
 | 1775 |     // Take another spin if there are now unswept objects in new space | 
 | 1776 |     // (there are currently no more unswept promoted objects). | 
 | 1777 |   } while (new_space_front != new_space_.top()); | 
 | 1778 |  | 
 | 1779 |   return new_space_front; | 
 | 1780 | } | 
 | 1781 |  | 
 | 1782 |  | 
 | 1783 | STATIC_ASSERT((FixedDoubleArray::kHeaderSize & kDoubleAlignmentMask) == | 
 | 1784 |               0);  // NOLINT | 
 | 1785 | STATIC_ASSERT((ConstantPoolArray::kFirstEntryOffset & kDoubleAlignmentMask) == | 
 | 1786 |               0);  // NOLINT | 
 | 1787 | STATIC_ASSERT((ConstantPoolArray::kExtendedFirstOffset & | 
 | 1788 |                kDoubleAlignmentMask) == 0);  // NOLINT | 
 | 1789 |  | 
 | 1790 |  | 
 | 1791 | INLINE(static HeapObject* EnsureDoubleAligned(Heap* heap, HeapObject* object, | 
 | 1792 |                                               int size)); | 
 | 1793 |  | 
 | 1794 | static HeapObject* EnsureDoubleAligned(Heap* heap, HeapObject* object, | 
 | 1795 |                                        int size) { | 
 | 1796 |   if ((OffsetFrom(object->address()) & kDoubleAlignmentMask) != 0) { | 
 | 1797 |     heap->CreateFillerObjectAt(object->address(), kPointerSize); | 
 | 1798 |     return HeapObject::FromAddress(object->address() + kPointerSize); | 
 | 1799 |   } else { | 
 | 1800 |     heap->CreateFillerObjectAt(object->address() + size - kPointerSize, | 
 | 1801 |                                kPointerSize); | 
 | 1802 |     return object; | 
 | 1803 |   } | 
 | 1804 | } | 
 | 1805 |  | 
 | 1806 |  | 
 | 1807 | enum LoggingAndProfiling { | 
 | 1808 |   LOGGING_AND_PROFILING_ENABLED, | 
 | 1809 |   LOGGING_AND_PROFILING_DISABLED | 
 | 1810 | }; | 
 | 1811 |  | 
 | 1812 |  | 
 | 1813 | enum MarksHandling { TRANSFER_MARKS, IGNORE_MARKS }; | 
 | 1814 |  | 
 | 1815 |  | 
 | 1816 | template <MarksHandling marks_handling, | 
 | 1817 |           LoggingAndProfiling logging_and_profiling_mode> | 
 | 1818 | class ScavengingVisitor : public StaticVisitorBase { | 
 | 1819 |  public: | 
 | 1820 |   static void Initialize() { | 
 | 1821 |     table_.Register(kVisitSeqOneByteString, &EvacuateSeqOneByteString); | 
 | 1822 |     table_.Register(kVisitSeqTwoByteString, &EvacuateSeqTwoByteString); | 
 | 1823 |     table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate); | 
 | 1824 |     table_.Register(kVisitByteArray, &EvacuateByteArray); | 
 | 1825 |     table_.Register(kVisitFixedArray, &EvacuateFixedArray); | 
 | 1826 |     table_.Register(kVisitFixedDoubleArray, &EvacuateFixedDoubleArray); | 
 | 1827 |     table_.Register(kVisitFixedTypedArray, &EvacuateFixedTypedArray); | 
 | 1828 |     table_.Register(kVisitFixedFloat64Array, &EvacuateFixedFloat64Array); | 
 | 1829 |  | 
 | 1830 |     table_.Register( | 
 | 1831 |         kVisitNativeContext, | 
 | 1832 |         &ObjectEvacuationStrategy<POINTER_OBJECT>::template VisitSpecialized< | 
 | 1833 |             Context::kSize>); | 
 | 1834 |  | 
 | 1835 |     table_.Register( | 
 | 1836 |         kVisitConsString, | 
 | 1837 |         &ObjectEvacuationStrategy<POINTER_OBJECT>::template VisitSpecialized< | 
 | 1838 |             ConsString::kSize>); | 
 | 1839 |  | 
 | 1840 |     table_.Register( | 
 | 1841 |         kVisitSlicedString, | 
 | 1842 |         &ObjectEvacuationStrategy<POINTER_OBJECT>::template VisitSpecialized< | 
 | 1843 |             SlicedString::kSize>); | 
 | 1844 |  | 
 | 1845 |     table_.Register( | 
 | 1846 |         kVisitSymbol, | 
 | 1847 |         &ObjectEvacuationStrategy<POINTER_OBJECT>::template VisitSpecialized< | 
 | 1848 |             Symbol::kSize>); | 
 | 1849 |  | 
 | 1850 |     table_.Register( | 
 | 1851 |         kVisitSharedFunctionInfo, | 
 | 1852 |         &ObjectEvacuationStrategy<POINTER_OBJECT>::template VisitSpecialized< | 
 | 1853 |             SharedFunctionInfo::kSize>); | 
 | 1854 |  | 
 | 1855 |     table_.Register(kVisitJSWeakCollection, | 
 | 1856 |                     &ObjectEvacuationStrategy<POINTER_OBJECT>::Visit); | 
 | 1857 |  | 
 | 1858 |     table_.Register(kVisitJSArrayBuffer, | 
 | 1859 |                     &ObjectEvacuationStrategy<POINTER_OBJECT>::Visit); | 
 | 1860 |  | 
 | 1861 |     table_.Register(kVisitJSTypedArray, | 
 | 1862 |                     &ObjectEvacuationStrategy<POINTER_OBJECT>::Visit); | 
 | 1863 |  | 
 | 1864 |     table_.Register(kVisitJSDataView, | 
 | 1865 |                     &ObjectEvacuationStrategy<POINTER_OBJECT>::Visit); | 
 | 1866 |  | 
 | 1867 |     table_.Register(kVisitJSRegExp, | 
 | 1868 |                     &ObjectEvacuationStrategy<POINTER_OBJECT>::Visit); | 
 | 1869 |  | 
 | 1870 |     if (marks_handling == IGNORE_MARKS) { | 
 | 1871 |       table_.Register( | 
 | 1872 |           kVisitJSFunction, | 
 | 1873 |           &ObjectEvacuationStrategy<POINTER_OBJECT>::template VisitSpecialized< | 
 | 1874 |               JSFunction::kSize>); | 
 | 1875 |     } else { | 
 | 1876 |       table_.Register(kVisitJSFunction, &EvacuateJSFunction); | 
 | 1877 |     } | 
 | 1878 |  | 
 | 1879 |     table_.RegisterSpecializations<ObjectEvacuationStrategy<DATA_OBJECT>, | 
 | 1880 |                                    kVisitDataObject, kVisitDataObjectGeneric>(); | 
 | 1881 |  | 
 | 1882 |     table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>, | 
 | 1883 |                                    kVisitJSObject, kVisitJSObjectGeneric>(); | 
 | 1884 |  | 
 | 1885 |     table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>, | 
 | 1886 |                                    kVisitStruct, kVisitStructGeneric>(); | 
 | 1887 |   } | 
 | 1888 |  | 
 | 1889 |   static VisitorDispatchTable<ScavengingCallback>* GetTable() { | 
 | 1890 |     return &table_; | 
 | 1891 |   } | 
 | 1892 |  | 
 | 1893 |  private: | 
 | 1894 |   enum ObjectContents { DATA_OBJECT, POINTER_OBJECT }; | 
 | 1895 |  | 
 | 1896 |   static void RecordCopiedObject(Heap* heap, HeapObject* obj) { | 
 | 1897 |     bool should_record = false; | 
 | 1898 | #ifdef DEBUG | 
 | 1899 |     should_record = FLAG_heap_stats; | 
 | 1900 | #endif | 
 | 1901 |     should_record = should_record || FLAG_log_gc; | 
 | 1902 |     if (should_record) { | 
 | 1903 |       if (heap->new_space()->Contains(obj)) { | 
 | 1904 |         heap->new_space()->RecordAllocation(obj); | 
 | 1905 |       } else { | 
 | 1906 |         heap->new_space()->RecordPromotion(obj); | 
 | 1907 |       } | 
 | 1908 |     } | 
 | 1909 |   } | 
 | 1910 |  | 
 | 1911 |   // Helper function used by CopyObject to copy a source object to an | 
 | 1912 |   // allocated target object and update the forwarding pointer in the source | 
 | 1913 |   // object.  Returns the target object. | 
 | 1914 |   INLINE(static void MigrateObject(Heap* heap, HeapObject* source, | 
 | 1915 |                                    HeapObject* target, int size)) { | 
 | 1916 |     // If we migrate into to-space, then the to-space top pointer should be | 
 | 1917 |     // right after the target object. Incorporate double alignment | 
 | 1918 |     // over-allocation. | 
 | 1919 |     DCHECK(!heap->InToSpace(target) || | 
 | 1920 |            target->address() + size == heap->new_space()->top() || | 
 | 1921 |            target->address() + size + kPointerSize == heap->new_space()->top()); | 
 | 1922 |  | 
 | 1923 |     // Make sure that we do not overwrite the promotion queue which is at | 
 | 1924 |     // the end of to-space. | 
 | 1925 |     DCHECK(!heap->InToSpace(target) || | 
 | 1926 |            heap->promotion_queue()->IsBelowPromotionQueue( | 
 | 1927 |                heap->new_space()->top())); | 
 | 1928 |  | 
 | 1929 |     // Copy the content of source to target. | 
 | 1930 |     heap->CopyBlock(target->address(), source->address(), size); | 
 | 1931 |  | 
 | 1932 |     // Set the forwarding address. | 
 | 1933 |     source->set_map_word(MapWord::FromForwardingAddress(target)); | 
 | 1934 |  | 
 | 1935 |     if (logging_and_profiling_mode == LOGGING_AND_PROFILING_ENABLED) { | 
 | 1936 |       // Update NewSpace stats if necessary. | 
 | 1937 |       RecordCopiedObject(heap, target); | 
 | 1938 |       heap->OnMoveEvent(target, source, size); | 
 | 1939 |     } | 
 | 1940 |  | 
 | 1941 |     if (marks_handling == TRANSFER_MARKS) { | 
 | 1942 |       if (Marking::TransferColor(source, target)) { | 
 | 1943 |         MemoryChunk::IncrementLiveBytesFromGC(target->address(), size); | 
 | 1944 |       } | 
 | 1945 |     } | 
 | 1946 |   } | 
 | 1947 |  | 
 | 1948 |   template <int alignment> | 
 | 1949 |   static inline bool SemiSpaceCopyObject(Map* map, HeapObject** slot, | 
 | 1950 |                                          HeapObject* object, int object_size) { | 
 | 1951 |     Heap* heap = map->GetHeap(); | 
 | 1952 |  | 
 | 1953 |     int allocation_size = object_size; | 
 | 1954 |     if (alignment != kObjectAlignment) { | 
 | 1955 |       DCHECK(alignment == kDoubleAlignment); | 
 | 1956 |       allocation_size += kPointerSize; | 
 | 1957 |     } | 
 | 1958 |  | 
 | 1959 |     DCHECK(heap->AllowedToBeMigrated(object, NEW_SPACE)); | 
 | 1960 |     AllocationResult allocation = | 
 | 1961 |         heap->new_space()->AllocateRaw(allocation_size); | 
 | 1962 |  | 
 | 1963 |     HeapObject* target = NULL;  // Initialization to please compiler. | 
 | 1964 |     if (allocation.To(&target)) { | 
 | 1965 |       // Order is important here: Set the promotion limit before storing a | 
 | 1966 |       // filler for double alignment or migrating the object. Otherwise we | 
 | 1967 |       // may end up overwriting promotion queue entries when we migrate the | 
 | 1968 |       // object. | 
 | 1969 |       heap->promotion_queue()->SetNewLimit(heap->new_space()->top()); | 
 | 1970 |  | 
 | 1971 |       if (alignment != kObjectAlignment) { | 
 | 1972 |         target = EnsureDoubleAligned(heap, target, allocation_size); | 
 | 1973 |       } | 
 | 1974 |  | 
 | 1975 |       // Order is important: slot might be inside of the target if target | 
 | 1976 |       // was allocated over a dead object and slot comes from the store | 
 | 1977 |       // buffer. | 
 | 1978 |       *slot = target; | 
 | 1979 |       MigrateObject(heap, object, target, object_size); | 
 | 1980 |  | 
 | 1981 |       heap->IncrementSemiSpaceCopiedObjectSize(object_size); | 
 | 1982 |       return true; | 
 | 1983 |     } | 
 | 1984 |     return false; | 
 | 1985 |   } | 
 | 1986 |  | 
 | 1987 |  | 
 | 1988 |   template <ObjectContents object_contents, int alignment> | 
 | 1989 |   static inline bool PromoteObject(Map* map, HeapObject** slot, | 
 | 1990 |                                    HeapObject* object, int object_size) { | 
 | 1991 |     Heap* heap = map->GetHeap(); | 
 | 1992 |  | 
 | 1993 |     int allocation_size = object_size; | 
 | 1994 |     if (alignment != kObjectAlignment) { | 
 | 1995 |       DCHECK(alignment == kDoubleAlignment); | 
 | 1996 |       allocation_size += kPointerSize; | 
 | 1997 |     } | 
 | 1998 |  | 
 | 1999 |     AllocationResult allocation; | 
 | 2000 |     if (object_contents == DATA_OBJECT) { | 
 | 2001 |       DCHECK(heap->AllowedToBeMigrated(object, OLD_DATA_SPACE)); | 
 | 2002 |       allocation = heap->old_data_space()->AllocateRaw(allocation_size); | 
 | 2003 |     } else { | 
 | 2004 |       DCHECK(heap->AllowedToBeMigrated(object, OLD_POINTER_SPACE)); | 
 | 2005 |       allocation = heap->old_pointer_space()->AllocateRaw(allocation_size); | 
 | 2006 |     } | 
 | 2007 |  | 
 | 2008 |     HeapObject* target = NULL;  // Initialization to please compiler. | 
 | 2009 |     if (allocation.To(&target)) { | 
 | 2010 |       if (alignment != kObjectAlignment) { | 
 | 2011 |         target = EnsureDoubleAligned(heap, target, allocation_size); | 
 | 2012 |       } | 
 | 2013 |  | 
 | 2014 |       // Order is important: slot might be inside of the target if target | 
 | 2015 |       // was allocated over a dead object and slot comes from the store | 
 | 2016 |       // buffer. | 
 | 2017 |       *slot = target; | 
 | 2018 |       MigrateObject(heap, object, target, object_size); | 
 | 2019 |  | 
 | 2020 |       if (object_contents == POINTER_OBJECT) { | 
 | 2021 |         if (map->instance_type() == JS_FUNCTION_TYPE) { | 
 | 2022 |           heap->promotion_queue()->insert(target, | 
 | 2023 |                                           JSFunction::kNonWeakFieldsEndOffset); | 
 | 2024 |         } else { | 
 | 2025 |           heap->promotion_queue()->insert(target, object_size); | 
 | 2026 |         } | 
 | 2027 |       } | 
 | 2028 |       heap->IncrementPromotedObjectsSize(object_size); | 
 | 2029 |       return true; | 
 | 2030 |     } | 
 | 2031 |     return false; | 
 | 2032 |   } | 
 | 2033 |  | 
 | 2034 |  | 
 | 2035 |   template <ObjectContents object_contents, int alignment> | 
 | 2036 |   static inline void EvacuateObject(Map* map, HeapObject** slot, | 
 | 2037 |                                     HeapObject* object, int object_size) { | 
 | 2038 |     SLOW_DCHECK(object_size <= Page::kMaxRegularHeapObjectSize); | 
 | 2039 |     SLOW_DCHECK(object->Size() == object_size); | 
 | 2040 |     Heap* heap = map->GetHeap(); | 
 | 2041 |  | 
 | 2042 |     if (!heap->ShouldBePromoted(object->address(), object_size)) { | 
 | 2043 |       // A semi-space copy may fail due to fragmentation. In that case, we | 
 | 2044 |       // try to promote the object. | 
 | 2045 |       if (SemiSpaceCopyObject<alignment>(map, slot, object, object_size)) { | 
 | 2046 |         return; | 
 | 2047 |       } | 
 | 2048 |     } | 
 | 2049 |  | 
 | 2050 |     if (PromoteObject<object_contents, alignment>(map, slot, object, | 
 | 2051 |                                                   object_size)) { | 
 | 2052 |       return; | 
 | 2053 |     } | 
 | 2054 |  | 
 | 2055 |     // If promotion failed, we try to copy the object to the other semi-space | 
 | 2056 |     if (SemiSpaceCopyObject<alignment>(map, slot, object, object_size)) return; | 
 | 2057 |  | 
 | 2058 |     UNREACHABLE(); | 
 | 2059 |   } | 
 | 2060 |  | 
 | 2061 |  | 
 | 2062 |   static inline void EvacuateJSFunction(Map* map, HeapObject** slot, | 
 | 2063 |                                         HeapObject* object) { | 
 | 2064 |     ObjectEvacuationStrategy<POINTER_OBJECT>::template VisitSpecialized< | 
 | 2065 |         JSFunction::kSize>(map, slot, object); | 
 | 2066 |  | 
 | 2067 |     MapWord map_word = object->map_word(); | 
 | 2068 |     DCHECK(map_word.IsForwardingAddress()); | 
 | 2069 |     HeapObject* target = map_word.ToForwardingAddress(); | 
 | 2070 |  | 
 | 2071 |     MarkBit mark_bit = Marking::MarkBitFrom(target); | 
 | 2072 |     if (Marking::IsBlack(mark_bit)) { | 
 | 2073 |       // This object is black and it might not be rescanned by marker. | 
 | 2074 |       // We should explicitly record code entry slot for compaction because | 
 | 2075 |       // promotion queue processing (IterateAndMarkPointersToFromSpace) will | 
 | 2076 |       // miss it as it is not HeapObject-tagged. | 
 | 2077 |       Address code_entry_slot = | 
 | 2078 |           target->address() + JSFunction::kCodeEntryOffset; | 
 | 2079 |       Code* code = Code::cast(Code::GetObjectFromEntryAddress(code_entry_slot)); | 
 | 2080 |       map->GetHeap()->mark_compact_collector()->RecordCodeEntrySlot( | 
 | 2081 |           code_entry_slot, code); | 
 | 2082 |     } | 
 | 2083 |   } | 
 | 2084 |  | 
 | 2085 |  | 
 | 2086 |   static inline void EvacuateFixedArray(Map* map, HeapObject** slot, | 
 | 2087 |                                         HeapObject* object) { | 
 | 2088 |     int object_size = FixedArray::BodyDescriptor::SizeOf(map, object); | 
 | 2089 |     EvacuateObject<POINTER_OBJECT, kObjectAlignment>(map, slot, object, | 
 | 2090 |                                                      object_size); | 
 | 2091 |   } | 
 | 2092 |  | 
 | 2093 |  | 
 | 2094 |   static inline void EvacuateFixedDoubleArray(Map* map, HeapObject** slot, | 
 | 2095 |                                               HeapObject* object) { | 
 | 2096 |     int length = reinterpret_cast<FixedDoubleArray*>(object)->length(); | 
 | 2097 |     int object_size = FixedDoubleArray::SizeFor(length); | 
 | 2098 |     EvacuateObject<DATA_OBJECT, kDoubleAlignment>(map, slot, object, | 
 | 2099 |                                                   object_size); | 
 | 2100 |   } | 
 | 2101 |  | 
 | 2102 |  | 
 | 2103 |   static inline void EvacuateFixedTypedArray(Map* map, HeapObject** slot, | 
 | 2104 |                                              HeapObject* object) { | 
 | 2105 |     int object_size = reinterpret_cast<FixedTypedArrayBase*>(object)->size(); | 
 | 2106 |     EvacuateObject<DATA_OBJECT, kObjectAlignment>(map, slot, object, | 
 | 2107 |                                                   object_size); | 
 | 2108 |   } | 
 | 2109 |  | 
 | 2110 |  | 
 | 2111 |   static inline void EvacuateFixedFloat64Array(Map* map, HeapObject** slot, | 
 | 2112 |                                                HeapObject* object) { | 
 | 2113 |     int object_size = reinterpret_cast<FixedFloat64Array*>(object)->size(); | 
 | 2114 |     EvacuateObject<DATA_OBJECT, kDoubleAlignment>(map, slot, object, | 
 | 2115 |                                                   object_size); | 
 | 2116 |   } | 
 | 2117 |  | 
 | 2118 |  | 
 | 2119 |   static inline void EvacuateByteArray(Map* map, HeapObject** slot, | 
 | 2120 |                                        HeapObject* object) { | 
 | 2121 |     int object_size = reinterpret_cast<ByteArray*>(object)->ByteArraySize(); | 
 | 2122 |     EvacuateObject<DATA_OBJECT, kObjectAlignment>(map, slot, object, | 
 | 2123 |                                                   object_size); | 
 | 2124 |   } | 
 | 2125 |  | 
 | 2126 |  | 
 | 2127 |   static inline void EvacuateSeqOneByteString(Map* map, HeapObject** slot, | 
 | 2128 |                                               HeapObject* object) { | 
 | 2129 |     int object_size = SeqOneByteString::cast(object) | 
 | 2130 |                           ->SeqOneByteStringSize(map->instance_type()); | 
 | 2131 |     EvacuateObject<DATA_OBJECT, kObjectAlignment>(map, slot, object, | 
 | 2132 |                                                   object_size); | 
 | 2133 |   } | 
 | 2134 |  | 
 | 2135 |  | 
 | 2136 |   static inline void EvacuateSeqTwoByteString(Map* map, HeapObject** slot, | 
 | 2137 |                                               HeapObject* object) { | 
 | 2138 |     int object_size = SeqTwoByteString::cast(object) | 
 | 2139 |                           ->SeqTwoByteStringSize(map->instance_type()); | 
 | 2140 |     EvacuateObject<DATA_OBJECT, kObjectAlignment>(map, slot, object, | 
 | 2141 |                                                   object_size); | 
 | 2142 |   } | 
 | 2143 |  | 
 | 2144 |  | 
 | 2145 |   static inline void EvacuateShortcutCandidate(Map* map, HeapObject** slot, | 
 | 2146 |                                                HeapObject* object) { | 
 | 2147 |     DCHECK(IsShortcutCandidate(map->instance_type())); | 
 | 2148 |  | 
 | 2149 |     Heap* heap = map->GetHeap(); | 
 | 2150 |  | 
 | 2151 |     if (marks_handling == IGNORE_MARKS && | 
 | 2152 |         ConsString::cast(object)->unchecked_second() == heap->empty_string()) { | 
 | 2153 |       HeapObject* first = | 
 | 2154 |           HeapObject::cast(ConsString::cast(object)->unchecked_first()); | 
 | 2155 |  | 
 | 2156 |       *slot = first; | 
 | 2157 |  | 
 | 2158 |       if (!heap->InNewSpace(first)) { | 
 | 2159 |         object->set_map_word(MapWord::FromForwardingAddress(first)); | 
 | 2160 |         return; | 
 | 2161 |       } | 
 | 2162 |  | 
 | 2163 |       MapWord first_word = first->map_word(); | 
 | 2164 |       if (first_word.IsForwardingAddress()) { | 
 | 2165 |         HeapObject* target = first_word.ToForwardingAddress(); | 
 | 2166 |  | 
 | 2167 |         *slot = target; | 
 | 2168 |         object->set_map_word(MapWord::FromForwardingAddress(target)); | 
 | 2169 |         return; | 
 | 2170 |       } | 
 | 2171 |  | 
 | 2172 |       heap->DoScavengeObject(first->map(), slot, first); | 
 | 2173 |       object->set_map_word(MapWord::FromForwardingAddress(*slot)); | 
 | 2174 |       return; | 
 | 2175 |     } | 
 | 2176 |  | 
 | 2177 |     int object_size = ConsString::kSize; | 
 | 2178 |     EvacuateObject<POINTER_OBJECT, kObjectAlignment>(map, slot, object, | 
 | 2179 |                                                      object_size); | 
 | 2180 |   } | 
 | 2181 |  | 
 | 2182 |   template <ObjectContents object_contents> | 
 | 2183 |   class ObjectEvacuationStrategy { | 
 | 2184 |    public: | 
 | 2185 |     template <int object_size> | 
 | 2186 |     static inline void VisitSpecialized(Map* map, HeapObject** slot, | 
 | 2187 |                                         HeapObject* object) { | 
 | 2188 |       EvacuateObject<object_contents, kObjectAlignment>(map, slot, object, | 
 | 2189 |                                                         object_size); | 
 | 2190 |     } | 
 | 2191 |  | 
 | 2192 |     static inline void Visit(Map* map, HeapObject** slot, HeapObject* object) { | 
 | 2193 |       int object_size = map->instance_size(); | 
 | 2194 |       EvacuateObject<object_contents, kObjectAlignment>(map, slot, object, | 
 | 2195 |                                                         object_size); | 
 | 2196 |     } | 
 | 2197 |   }; | 
 | 2198 |  | 
 | 2199 |   static VisitorDispatchTable<ScavengingCallback> table_; | 
 | 2200 | }; | 
 | 2201 |  | 
 | 2202 |  | 
 | 2203 | template <MarksHandling marks_handling, | 
 | 2204 |           LoggingAndProfiling logging_and_profiling_mode> | 
 | 2205 | VisitorDispatchTable<ScavengingCallback> | 
 | 2206 |     ScavengingVisitor<marks_handling, logging_and_profiling_mode>::table_; | 
 | 2207 |  | 
 | 2208 |  | 
 | 2209 | static void InitializeScavengingVisitorsTables() { | 
 | 2210 |   ScavengingVisitor<TRANSFER_MARKS, | 
 | 2211 |                     LOGGING_AND_PROFILING_DISABLED>::Initialize(); | 
 | 2212 |   ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_DISABLED>::Initialize(); | 
 | 2213 |   ScavengingVisitor<TRANSFER_MARKS, | 
 | 2214 |                     LOGGING_AND_PROFILING_ENABLED>::Initialize(); | 
 | 2215 |   ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_ENABLED>::Initialize(); | 
 | 2216 | } | 
 | 2217 |  | 
 | 2218 |  | 
 | 2219 | void Heap::SelectScavengingVisitorsTable() { | 
 | 2220 |   bool logging_and_profiling = | 
 | 2221 |       FLAG_verify_predictable || isolate()->logger()->is_logging() || | 
 | 2222 |       isolate()->cpu_profiler()->is_profiling() || | 
 | 2223 |       (isolate()->heap_profiler() != NULL && | 
 | 2224 |        isolate()->heap_profiler()->is_tracking_object_moves()); | 
 | 2225 |  | 
 | 2226 |   if (!incremental_marking()->IsMarking()) { | 
 | 2227 |     if (!logging_and_profiling) { | 
 | 2228 |       scavenging_visitors_table_.CopyFrom(ScavengingVisitor< | 
 | 2229 |           IGNORE_MARKS, LOGGING_AND_PROFILING_DISABLED>::GetTable()); | 
 | 2230 |     } else { | 
 | 2231 |       scavenging_visitors_table_.CopyFrom(ScavengingVisitor< | 
 | 2232 |           IGNORE_MARKS, LOGGING_AND_PROFILING_ENABLED>::GetTable()); | 
 | 2233 |     } | 
 | 2234 |   } else { | 
 | 2235 |     if (!logging_and_profiling) { | 
 | 2236 |       scavenging_visitors_table_.CopyFrom(ScavengingVisitor< | 
 | 2237 |           TRANSFER_MARKS, LOGGING_AND_PROFILING_DISABLED>::GetTable()); | 
 | 2238 |     } else { | 
 | 2239 |       scavenging_visitors_table_.CopyFrom(ScavengingVisitor< | 
 | 2240 |           TRANSFER_MARKS, LOGGING_AND_PROFILING_ENABLED>::GetTable()); | 
 | 2241 |     } | 
 | 2242 |  | 
 | 2243 |     if (incremental_marking()->IsCompacting()) { | 
 | 2244 |       // When compacting forbid short-circuiting of cons-strings. | 
 | 2245 |       // Scavenging code relies on the fact that new space object | 
 | 2246 |       // can't be evacuated into evacuation candidate but | 
 | 2247 |       // short-circuiting violates this assumption. | 
 | 2248 |       scavenging_visitors_table_.Register( | 
 | 2249 |           StaticVisitorBase::kVisitShortcutCandidate, | 
 | 2250 |           scavenging_visitors_table_.GetVisitorById( | 
 | 2251 |               StaticVisitorBase::kVisitConsString)); | 
 | 2252 |     } | 
 | 2253 |   } | 
 | 2254 | } | 
 | 2255 |  | 
 | 2256 |  | 
 | 2257 | void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) { | 
 | 2258 |   SLOW_DCHECK(object->GetIsolate()->heap()->InFromSpace(object)); | 
 | 2259 |   MapWord first_word = object->map_word(); | 
 | 2260 |   SLOW_DCHECK(!first_word.IsForwardingAddress()); | 
 | 2261 |   Map* map = first_word.ToMap(); | 
 | 2262 |   map->GetHeap()->DoScavengeObject(map, p, object); | 
 | 2263 | } | 
 | 2264 |  | 
 | 2265 |  | 
 | 2266 | AllocationResult Heap::AllocatePartialMap(InstanceType instance_type, | 
 | 2267 |                                           int instance_size) { | 
 | 2268 |   Object* result; | 
 | 2269 |   AllocationResult allocation = AllocateRaw(Map::kSize, MAP_SPACE, MAP_SPACE); | 
 | 2270 |   if (!allocation.To(&result)) return allocation; | 
 | 2271 |  | 
 | 2272 |   // Map::cast cannot be used due to uninitialized map field. | 
 | 2273 |   reinterpret_cast<Map*>(result)->set_map(raw_unchecked_meta_map()); | 
 | 2274 |   reinterpret_cast<Map*>(result)->set_instance_type(instance_type); | 
 | 2275 |   reinterpret_cast<Map*>(result)->set_instance_size(instance_size); | 
 | 2276 |   reinterpret_cast<Map*>(result)->set_visitor_id( | 
 | 2277 |       StaticVisitorBase::GetVisitorId(instance_type, instance_size)); | 
 | 2278 |   reinterpret_cast<Map*>(result)->set_inobject_properties(0); | 
 | 2279 |   reinterpret_cast<Map*>(result)->set_pre_allocated_property_fields(0); | 
 | 2280 |   reinterpret_cast<Map*>(result)->set_unused_property_fields(0); | 
 | 2281 |   reinterpret_cast<Map*>(result)->set_bit_field(0); | 
 | 2282 |   reinterpret_cast<Map*>(result)->set_bit_field2(0); | 
 | 2283 |   int bit_field3 = Map::EnumLengthBits::encode(kInvalidEnumCacheSentinel) | | 
 | 2284 |                    Map::OwnsDescriptors::encode(true); | 
 | 2285 |   reinterpret_cast<Map*>(result)->set_bit_field3(bit_field3); | 
 | 2286 |   return result; | 
 | 2287 | } | 
 | 2288 |  | 
 | 2289 |  | 
 | 2290 | AllocationResult Heap::AllocateMap(InstanceType instance_type, | 
 | 2291 |                                    int instance_size, | 
 | 2292 |                                    ElementsKind elements_kind) { | 
 | 2293 |   HeapObject* result; | 
 | 2294 |   AllocationResult allocation = AllocateRaw(Map::kSize, MAP_SPACE, MAP_SPACE); | 
 | 2295 |   if (!allocation.To(&result)) return allocation; | 
 | 2296 |  | 
 | 2297 |   result->set_map_no_write_barrier(meta_map()); | 
 | 2298 |   Map* map = Map::cast(result); | 
 | 2299 |   map->set_instance_type(instance_type); | 
 | 2300 |   map->set_visitor_id( | 
 | 2301 |       StaticVisitorBase::GetVisitorId(instance_type, instance_size)); | 
 | 2302 |   map->set_prototype(null_value(), SKIP_WRITE_BARRIER); | 
 | 2303 |   map->set_constructor(null_value(), SKIP_WRITE_BARRIER); | 
 | 2304 |   map->set_instance_size(instance_size); | 
 | 2305 |   map->set_inobject_properties(0); | 
 | 2306 |   map->set_pre_allocated_property_fields(0); | 
 | 2307 |   map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER); | 
 | 2308 |   map->set_dependent_code(DependentCode::cast(empty_fixed_array()), | 
 | 2309 |                           SKIP_WRITE_BARRIER); | 
 | 2310 |   map->init_back_pointer(undefined_value()); | 
 | 2311 |   map->set_unused_property_fields(0); | 
 | 2312 |   map->set_instance_descriptors(empty_descriptor_array()); | 
 | 2313 |   map->set_bit_field(0); | 
 | 2314 |   map->set_bit_field2(1 << Map::kIsExtensible); | 
 | 2315 |   int bit_field3 = Map::EnumLengthBits::encode(kInvalidEnumCacheSentinel) | | 
 | 2316 |                    Map::OwnsDescriptors::encode(true); | 
 | 2317 |   map->set_bit_field3(bit_field3); | 
 | 2318 |   map->set_elements_kind(elements_kind); | 
 | 2319 |  | 
 | 2320 |   return map; | 
 | 2321 | } | 
 | 2322 |  | 
 | 2323 |  | 
 | 2324 | AllocationResult Heap::AllocateFillerObject(int size, bool double_align, | 
 | 2325 |                                             AllocationSpace space) { | 
 | 2326 |   HeapObject* obj; | 
 | 2327 |   { | 
 | 2328 |     AllocationResult allocation = AllocateRaw(size, space, space); | 
 | 2329 |     if (!allocation.To(&obj)) return allocation; | 
 | 2330 |   } | 
 | 2331 | #ifdef DEBUG | 
 | 2332 |   MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); | 
 | 2333 |   DCHECK(chunk->owner()->identity() == space); | 
 | 2334 | #endif | 
 | 2335 |   CreateFillerObjectAt(obj->address(), size); | 
 | 2336 |   return obj; | 
 | 2337 | } | 
 | 2338 |  | 
 | 2339 |  | 
 | 2340 | const Heap::StringTypeTable Heap::string_type_table[] = { | 
 | 2341 | #define STRING_TYPE_ELEMENT(type, size, name, camel_name) \ | 
 | 2342 |   { type, size, k##camel_name##MapRootIndex }             \ | 
 | 2343 |   , | 
 | 2344 |     STRING_TYPE_LIST(STRING_TYPE_ELEMENT) | 
 | 2345 | #undef STRING_TYPE_ELEMENT | 
 | 2346 | }; | 
 | 2347 |  | 
 | 2348 |  | 
 | 2349 | const Heap::ConstantStringTable Heap::constant_string_table[] = { | 
 | 2350 | #define CONSTANT_STRING_ELEMENT(name, contents) \ | 
 | 2351 |   { contents, k##name##RootIndex }              \ | 
 | 2352 |   , | 
 | 2353 |     INTERNALIZED_STRING_LIST(CONSTANT_STRING_ELEMENT) | 
 | 2354 | #undef CONSTANT_STRING_ELEMENT | 
 | 2355 | }; | 
 | 2356 |  | 
 | 2357 |  | 
 | 2358 | const Heap::StructTable Heap::struct_table[] = { | 
 | 2359 | #define STRUCT_TABLE_ELEMENT(NAME, Name, name)        \ | 
 | 2360 |   { NAME##_TYPE, Name::kSize, k##Name##MapRootIndex } \ | 
 | 2361 |   , | 
 | 2362 |     STRUCT_LIST(STRUCT_TABLE_ELEMENT) | 
 | 2363 | #undef STRUCT_TABLE_ELEMENT | 
 | 2364 | }; | 
 | 2365 |  | 
 | 2366 |  | 
 | 2367 | bool Heap::CreateInitialMaps() { | 
 | 2368 |   HeapObject* obj; | 
 | 2369 |   { | 
 | 2370 |     AllocationResult allocation = AllocatePartialMap(MAP_TYPE, Map::kSize); | 
 | 2371 |     if (!allocation.To(&obj)) return false; | 
 | 2372 |   } | 
 | 2373 |   // Map::cast cannot be used due to uninitialized map field. | 
 | 2374 |   Map* new_meta_map = reinterpret_cast<Map*>(obj); | 
 | 2375 |   set_meta_map(new_meta_map); | 
 | 2376 |   new_meta_map->set_map(new_meta_map); | 
 | 2377 |  | 
 | 2378 |   {  // Partial map allocation | 
 | 2379 | #define ALLOCATE_PARTIAL_MAP(instance_type, size, field_name)                \ | 
 | 2380 |   {                                                                          \ | 
 | 2381 |     Map* map;                                                                \ | 
 | 2382 |     if (!AllocatePartialMap((instance_type), (size)).To(&map)) return false; \ | 
 | 2383 |     set_##field_name##_map(map);                                             \ | 
 | 2384 |   } | 
 | 2385 |  | 
 | 2386 |     ALLOCATE_PARTIAL_MAP(FIXED_ARRAY_TYPE, kVariableSizeSentinel, fixed_array); | 
 | 2387 |     ALLOCATE_PARTIAL_MAP(ODDBALL_TYPE, Oddball::kSize, undefined); | 
 | 2388 |     ALLOCATE_PARTIAL_MAP(ODDBALL_TYPE, Oddball::kSize, null); | 
 | 2389 |     ALLOCATE_PARTIAL_MAP(CONSTANT_POOL_ARRAY_TYPE, kVariableSizeSentinel, | 
 | 2390 |                          constant_pool_array); | 
 | 2391 |  | 
 | 2392 | #undef ALLOCATE_PARTIAL_MAP | 
 | 2393 |   } | 
 | 2394 |  | 
 | 2395 |   // Allocate the empty array. | 
 | 2396 |   { | 
 | 2397 |     AllocationResult allocation = AllocateEmptyFixedArray(); | 
 | 2398 |     if (!allocation.To(&obj)) return false; | 
 | 2399 |   } | 
 | 2400 |   set_empty_fixed_array(FixedArray::cast(obj)); | 
 | 2401 |  | 
 | 2402 |   { | 
 | 2403 |     AllocationResult allocation = Allocate(null_map(), OLD_POINTER_SPACE); | 
 | 2404 |     if (!allocation.To(&obj)) return false; | 
 | 2405 |   } | 
 | 2406 |   set_null_value(Oddball::cast(obj)); | 
 | 2407 |   Oddball::cast(obj)->set_kind(Oddball::kNull); | 
 | 2408 |  | 
 | 2409 |   { | 
 | 2410 |     AllocationResult allocation = Allocate(undefined_map(), OLD_POINTER_SPACE); | 
 | 2411 |     if (!allocation.To(&obj)) return false; | 
 | 2412 |   } | 
 | 2413 |   set_undefined_value(Oddball::cast(obj)); | 
 | 2414 |   Oddball::cast(obj)->set_kind(Oddball::kUndefined); | 
 | 2415 |   DCHECK(!InNewSpace(undefined_value())); | 
 | 2416 |  | 
 | 2417 |   // Set preliminary exception sentinel value before actually initializing it. | 
 | 2418 |   set_exception(null_value()); | 
 | 2419 |  | 
 | 2420 |   // Allocate the empty descriptor array. | 
 | 2421 |   { | 
 | 2422 |     AllocationResult allocation = AllocateEmptyFixedArray(); | 
 | 2423 |     if (!allocation.To(&obj)) return false; | 
 | 2424 |   } | 
 | 2425 |   set_empty_descriptor_array(DescriptorArray::cast(obj)); | 
 | 2426 |  | 
 | 2427 |   // Allocate the constant pool array. | 
 | 2428 |   { | 
 | 2429 |     AllocationResult allocation = AllocateEmptyConstantPoolArray(); | 
 | 2430 |     if (!allocation.To(&obj)) return false; | 
 | 2431 |   } | 
 | 2432 |   set_empty_constant_pool_array(ConstantPoolArray::cast(obj)); | 
 | 2433 |  | 
 | 2434 |   // Fix the instance_descriptors for the existing maps. | 
 | 2435 |   meta_map()->set_code_cache(empty_fixed_array()); | 
 | 2436 |   meta_map()->set_dependent_code(DependentCode::cast(empty_fixed_array())); | 
 | 2437 |   meta_map()->init_back_pointer(undefined_value()); | 
 | 2438 |   meta_map()->set_instance_descriptors(empty_descriptor_array()); | 
 | 2439 |  | 
 | 2440 |   fixed_array_map()->set_code_cache(empty_fixed_array()); | 
 | 2441 |   fixed_array_map()->set_dependent_code( | 
 | 2442 |       DependentCode::cast(empty_fixed_array())); | 
 | 2443 |   fixed_array_map()->init_back_pointer(undefined_value()); | 
 | 2444 |   fixed_array_map()->set_instance_descriptors(empty_descriptor_array()); | 
 | 2445 |  | 
 | 2446 |   undefined_map()->set_code_cache(empty_fixed_array()); | 
 | 2447 |   undefined_map()->set_dependent_code(DependentCode::cast(empty_fixed_array())); | 
 | 2448 |   undefined_map()->init_back_pointer(undefined_value()); | 
 | 2449 |   undefined_map()->set_instance_descriptors(empty_descriptor_array()); | 
 | 2450 |  | 
 | 2451 |   null_map()->set_code_cache(empty_fixed_array()); | 
 | 2452 |   null_map()->set_dependent_code(DependentCode::cast(empty_fixed_array())); | 
 | 2453 |   null_map()->init_back_pointer(undefined_value()); | 
 | 2454 |   null_map()->set_instance_descriptors(empty_descriptor_array()); | 
 | 2455 |  | 
 | 2456 |   constant_pool_array_map()->set_code_cache(empty_fixed_array()); | 
 | 2457 |   constant_pool_array_map()->set_dependent_code( | 
 | 2458 |       DependentCode::cast(empty_fixed_array())); | 
 | 2459 |   constant_pool_array_map()->init_back_pointer(undefined_value()); | 
 | 2460 |   constant_pool_array_map()->set_instance_descriptors(empty_descriptor_array()); | 
 | 2461 |  | 
 | 2462 |   // Fix prototype object for existing maps. | 
 | 2463 |   meta_map()->set_prototype(null_value()); | 
 | 2464 |   meta_map()->set_constructor(null_value()); | 
 | 2465 |  | 
 | 2466 |   fixed_array_map()->set_prototype(null_value()); | 
 | 2467 |   fixed_array_map()->set_constructor(null_value()); | 
 | 2468 |  | 
 | 2469 |   undefined_map()->set_prototype(null_value()); | 
 | 2470 |   undefined_map()->set_constructor(null_value()); | 
 | 2471 |  | 
 | 2472 |   null_map()->set_prototype(null_value()); | 
 | 2473 |   null_map()->set_constructor(null_value()); | 
 | 2474 |  | 
 | 2475 |   constant_pool_array_map()->set_prototype(null_value()); | 
 | 2476 |   constant_pool_array_map()->set_constructor(null_value()); | 
 | 2477 |  | 
 | 2478 |   {  // Map allocation | 
 | 2479 | #define ALLOCATE_MAP(instance_type, size, field_name)               \ | 
 | 2480 |   {                                                                 \ | 
 | 2481 |     Map* map;                                                       \ | 
 | 2482 |     if (!AllocateMap((instance_type), size).To(&map)) return false; \ | 
 | 2483 |     set_##field_name##_map(map);                                    \ | 
 | 2484 |   } | 
 | 2485 |  | 
 | 2486 | #define ALLOCATE_VARSIZE_MAP(instance_type, field_name) \ | 
 | 2487 |   ALLOCATE_MAP(instance_type, kVariableSizeSentinel, field_name) | 
 | 2488 |  | 
 | 2489 |     ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, fixed_cow_array) | 
 | 2490 |     DCHECK(fixed_array_map() != fixed_cow_array_map()); | 
 | 2491 |  | 
 | 2492 |     ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, scope_info) | 
 | 2493 |     ALLOCATE_MAP(HEAP_NUMBER_TYPE, HeapNumber::kSize, heap_number) | 
 | 2494 |     ALLOCATE_MAP(MUTABLE_HEAP_NUMBER_TYPE, HeapNumber::kSize, | 
 | 2495 |                  mutable_heap_number) | 
 | 2496 |     ALLOCATE_MAP(SYMBOL_TYPE, Symbol::kSize, symbol) | 
 | 2497 |     ALLOCATE_MAP(FOREIGN_TYPE, Foreign::kSize, foreign) | 
 | 2498 |  | 
 | 2499 |     ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, the_hole); | 
 | 2500 |     ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, boolean); | 
 | 2501 |     ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, uninitialized); | 
 | 2502 |     ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, arguments_marker); | 
 | 2503 |     ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, no_interceptor_result_sentinel); | 
 | 2504 |     ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, exception); | 
 | 2505 |     ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, termination_exception); | 
 | 2506 |  | 
 | 2507 |     for (unsigned i = 0; i < arraysize(string_type_table); i++) { | 
 | 2508 |       const StringTypeTable& entry = string_type_table[i]; | 
 | 2509 |       { | 
 | 2510 |         AllocationResult allocation = AllocateMap(entry.type, entry.size); | 
 | 2511 |         if (!allocation.To(&obj)) return false; | 
 | 2512 |       } | 
 | 2513 |       // Mark cons string maps as unstable, because their objects can change | 
 | 2514 |       // maps during GC. | 
 | 2515 |       Map* map = Map::cast(obj); | 
 | 2516 |       if (StringShape(entry.type).IsCons()) map->mark_unstable(); | 
 | 2517 |       roots_[entry.index] = map; | 
 | 2518 |     } | 
 | 2519 |  | 
 | 2520 |     ALLOCATE_VARSIZE_MAP(STRING_TYPE, undetectable_string) | 
 | 2521 |     undetectable_string_map()->set_is_undetectable(); | 
 | 2522 |  | 
 | 2523 |     ALLOCATE_VARSIZE_MAP(ONE_BYTE_STRING_TYPE, undetectable_one_byte_string); | 
 | 2524 |     undetectable_one_byte_string_map()->set_is_undetectable(); | 
 | 2525 |  | 
 | 2526 |     ALLOCATE_VARSIZE_MAP(FIXED_DOUBLE_ARRAY_TYPE, fixed_double_array) | 
 | 2527 |     ALLOCATE_VARSIZE_MAP(BYTE_ARRAY_TYPE, byte_array) | 
 | 2528 |     ALLOCATE_VARSIZE_MAP(FREE_SPACE_TYPE, free_space) | 
 | 2529 |  | 
 | 2530 | #define ALLOCATE_EXTERNAL_ARRAY_MAP(Type, type, TYPE, ctype, size)        \ | 
 | 2531 |   ALLOCATE_MAP(EXTERNAL_##TYPE##_ARRAY_TYPE, ExternalArray::kAlignedSize, \ | 
 | 2532 |                external_##type##_array) | 
 | 2533 |  | 
 | 2534 |     TYPED_ARRAYS(ALLOCATE_EXTERNAL_ARRAY_MAP) | 
 | 2535 | #undef ALLOCATE_EXTERNAL_ARRAY_MAP | 
 | 2536 |  | 
 | 2537 | #define ALLOCATE_FIXED_TYPED_ARRAY_MAP(Type, type, TYPE, ctype, size) \ | 
 | 2538 |   ALLOCATE_VARSIZE_MAP(FIXED_##TYPE##_ARRAY_TYPE, fixed_##type##_array) | 
 | 2539 |  | 
 | 2540 |     TYPED_ARRAYS(ALLOCATE_FIXED_TYPED_ARRAY_MAP) | 
 | 2541 | #undef ALLOCATE_FIXED_TYPED_ARRAY_MAP | 
 | 2542 |  | 
 | 2543 |     ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, sloppy_arguments_elements) | 
 | 2544 |  | 
 | 2545 |     ALLOCATE_VARSIZE_MAP(CODE_TYPE, code) | 
 | 2546 |  | 
 | 2547 |     ALLOCATE_MAP(CELL_TYPE, Cell::kSize, cell) | 
 | 2548 |     ALLOCATE_MAP(PROPERTY_CELL_TYPE, PropertyCell::kSize, global_property_cell) | 
 | 2549 |     ALLOCATE_MAP(FILLER_TYPE, kPointerSize, one_pointer_filler) | 
 | 2550 |     ALLOCATE_MAP(FILLER_TYPE, 2 * kPointerSize, two_pointer_filler) | 
 | 2551 |  | 
 | 2552 |  | 
 | 2553 |     for (unsigned i = 0; i < arraysize(struct_table); i++) { | 
 | 2554 |       const StructTable& entry = struct_table[i]; | 
 | 2555 |       Map* map; | 
 | 2556 |       if (!AllocateMap(entry.type, entry.size).To(&map)) return false; | 
 | 2557 |       roots_[entry.index] = map; | 
 | 2558 |     } | 
 | 2559 |  | 
 | 2560 |     ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, hash_table) | 
 | 2561 |     ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, ordered_hash_table) | 
 | 2562 |  | 
 | 2563 |     ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, function_context) | 
 | 2564 |     ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, catch_context) | 
 | 2565 |     ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, with_context) | 
 | 2566 |     ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, block_context) | 
 | 2567 |     ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, module_context) | 
 | 2568 |     ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, global_context) | 
 | 2569 |  | 
 | 2570 |     ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, native_context) | 
 | 2571 |     native_context_map()->set_dictionary_map(true); | 
 | 2572 |     native_context_map()->set_visitor_id( | 
 | 2573 |         StaticVisitorBase::kVisitNativeContext); | 
 | 2574 |  | 
 | 2575 |     ALLOCATE_MAP(SHARED_FUNCTION_INFO_TYPE, SharedFunctionInfo::kAlignedSize, | 
 | 2576 |                  shared_function_info) | 
 | 2577 |  | 
 | 2578 |     ALLOCATE_MAP(JS_MESSAGE_OBJECT_TYPE, JSMessageObject::kSize, message_object) | 
 | 2579 |     ALLOCATE_MAP(JS_OBJECT_TYPE, JSObject::kHeaderSize + kPointerSize, external) | 
 | 2580 |     external_map()->set_is_extensible(false); | 
 | 2581 | #undef ALLOCATE_VARSIZE_MAP | 
 | 2582 | #undef ALLOCATE_MAP | 
 | 2583 |   } | 
 | 2584 |  | 
 | 2585 |   {  // Empty arrays | 
 | 2586 |     { | 
 | 2587 |       ByteArray* byte_array; | 
 | 2588 |       if (!AllocateByteArray(0, TENURED).To(&byte_array)) return false; | 
 | 2589 |       set_empty_byte_array(byte_array); | 
 | 2590 |     } | 
 | 2591 |  | 
 | 2592 | #define ALLOCATE_EMPTY_EXTERNAL_ARRAY(Type, type, TYPE, ctype, size)  \ | 
 | 2593 |   {                                                                   \ | 
 | 2594 |     ExternalArray* obj;                                               \ | 
 | 2595 |     if (!AllocateEmptyExternalArray(kExternal##Type##Array).To(&obj)) \ | 
 | 2596 |       return false;                                                   \ | 
 | 2597 |     set_empty_external_##type##_array(obj);                           \ | 
 | 2598 |   } | 
 | 2599 |  | 
 | 2600 |     TYPED_ARRAYS(ALLOCATE_EMPTY_EXTERNAL_ARRAY) | 
 | 2601 | #undef ALLOCATE_EMPTY_EXTERNAL_ARRAY | 
 | 2602 |  | 
 | 2603 | #define ALLOCATE_EMPTY_FIXED_TYPED_ARRAY(Type, type, TYPE, ctype, size) \ | 
 | 2604 |   {                                                                     \ | 
 | 2605 |     FixedTypedArrayBase* obj;                                           \ | 
 | 2606 |     if (!AllocateEmptyFixedTypedArray(kExternal##Type##Array).To(&obj)) \ | 
 | 2607 |       return false;                                                     \ | 
 | 2608 |     set_empty_fixed_##type##_array(obj);                                \ | 
 | 2609 |   } | 
 | 2610 |  | 
 | 2611 |     TYPED_ARRAYS(ALLOCATE_EMPTY_FIXED_TYPED_ARRAY) | 
 | 2612 | #undef ALLOCATE_EMPTY_FIXED_TYPED_ARRAY | 
 | 2613 |   } | 
 | 2614 |   DCHECK(!InNewSpace(empty_fixed_array())); | 
 | 2615 |   return true; | 
 | 2616 | } | 
 | 2617 |  | 
 | 2618 |  | 
 | 2619 | AllocationResult Heap::AllocateHeapNumber(double value, MutableMode mode, | 
 | 2620 |                                           PretenureFlag pretenure) { | 
 | 2621 |   // Statically ensure that it is safe to allocate heap numbers in paged | 
 | 2622 |   // spaces. | 
 | 2623 |   int size = HeapNumber::kSize; | 
 | 2624 |   STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxRegularHeapObjectSize); | 
 | 2625 |  | 
 | 2626 |   AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure); | 
 | 2627 |  | 
 | 2628 |   HeapObject* result; | 
 | 2629 |   { | 
 | 2630 |     AllocationResult allocation = AllocateRaw(size, space, OLD_DATA_SPACE); | 
 | 2631 |     if (!allocation.To(&result)) return allocation; | 
 | 2632 |   } | 
 | 2633 |  | 
 | 2634 |   Map* map = mode == MUTABLE ? mutable_heap_number_map() : heap_number_map(); | 
 | 2635 |   HeapObject::cast(result)->set_map_no_write_barrier(map); | 
 | 2636 |   HeapNumber::cast(result)->set_value(value); | 
 | 2637 |   return result; | 
 | 2638 | } | 
 | 2639 |  | 
 | 2640 |  | 
 | 2641 | AllocationResult Heap::AllocateCell(Object* value) { | 
 | 2642 |   int size = Cell::kSize; | 
 | 2643 |   STATIC_ASSERT(Cell::kSize <= Page::kMaxRegularHeapObjectSize); | 
 | 2644 |  | 
 | 2645 |   HeapObject* result; | 
 | 2646 |   { | 
 | 2647 |     AllocationResult allocation = AllocateRaw(size, CELL_SPACE, CELL_SPACE); | 
 | 2648 |     if (!allocation.To(&result)) return allocation; | 
 | 2649 |   } | 
 | 2650 |   result->set_map_no_write_barrier(cell_map()); | 
 | 2651 |   Cell::cast(result)->set_value(value); | 
 | 2652 |   return result; | 
 | 2653 | } | 
 | 2654 |  | 
 | 2655 |  | 
 | 2656 | AllocationResult Heap::AllocatePropertyCell() { | 
 | 2657 |   int size = PropertyCell::kSize; | 
 | 2658 |   STATIC_ASSERT(PropertyCell::kSize <= Page::kMaxRegularHeapObjectSize); | 
 | 2659 |  | 
 | 2660 |   HeapObject* result; | 
 | 2661 |   AllocationResult allocation = | 
 | 2662 |       AllocateRaw(size, PROPERTY_CELL_SPACE, PROPERTY_CELL_SPACE); | 
 | 2663 |   if (!allocation.To(&result)) return allocation; | 
 | 2664 |  | 
 | 2665 |   result->set_map_no_write_barrier(global_property_cell_map()); | 
 | 2666 |   PropertyCell* cell = PropertyCell::cast(result); | 
 | 2667 |   cell->set_dependent_code(DependentCode::cast(empty_fixed_array()), | 
 | 2668 |                            SKIP_WRITE_BARRIER); | 
 | 2669 |   cell->set_value(the_hole_value()); | 
 | 2670 |   cell->set_type(HeapType::None()); | 
 | 2671 |   return result; | 
 | 2672 | } | 
 | 2673 |  | 
 | 2674 |  | 
 | 2675 | void Heap::CreateApiObjects() { | 
 | 2676 |   HandleScope scope(isolate()); | 
 | 2677 |   Factory* factory = isolate()->factory(); | 
 | 2678 |   Handle<Map> new_neander_map = | 
 | 2679 |       factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); | 
 | 2680 |  | 
 | 2681 |   // Don't use Smi-only elements optimizations for objects with the neander | 
 | 2682 |   // map. There are too many cases where element values are set directly with a | 
 | 2683 |   // bottleneck to trap the Smi-only -> fast elements transition, and there | 
 | 2684 |   // appears to be no benefit for optimize this case. | 
 | 2685 |   new_neander_map->set_elements_kind(TERMINAL_FAST_ELEMENTS_KIND); | 
 | 2686 |   set_neander_map(*new_neander_map); | 
 | 2687 |  | 
 | 2688 |   Handle<JSObject> listeners = factory->NewNeanderObject(); | 
 | 2689 |   Handle<FixedArray> elements = factory->NewFixedArray(2); | 
 | 2690 |   elements->set(0, Smi::FromInt(0)); | 
 | 2691 |   listeners->set_elements(*elements); | 
 | 2692 |   set_message_listeners(*listeners); | 
 | 2693 | } | 
 | 2694 |  | 
 | 2695 |  | 
 | 2696 | void Heap::CreateJSEntryStub() { | 
 | 2697 |   JSEntryStub stub(isolate(), StackFrame::ENTRY); | 
 | 2698 |   set_js_entry_code(*stub.GetCode()); | 
 | 2699 | } | 
 | 2700 |  | 
 | 2701 |  | 
 | 2702 | void Heap::CreateJSConstructEntryStub() { | 
 | 2703 |   JSEntryStub stub(isolate(), StackFrame::ENTRY_CONSTRUCT); | 
 | 2704 |   set_js_construct_entry_code(*stub.GetCode()); | 
 | 2705 | } | 
 | 2706 |  | 
 | 2707 |  | 
 | 2708 | void Heap::CreateFixedStubs() { | 
 | 2709 |   // Here we create roots for fixed stubs. They are needed at GC | 
 | 2710 |   // for cooking and uncooking (check out frames.cc). | 
 | 2711 |   // The eliminates the need for doing dictionary lookup in the | 
 | 2712 |   // stub cache for these stubs. | 
 | 2713 |   HandleScope scope(isolate()); | 
 | 2714 |  | 
 | 2715 |   // Create stubs that should be there, so we don't unexpectedly have to | 
 | 2716 |   // create them if we need them during the creation of another stub. | 
 | 2717 |   // Stub creation mixes raw pointers and handles in an unsafe manner so | 
 | 2718 |   // we cannot create stubs while we are creating stubs. | 
 | 2719 |   CodeStub::GenerateStubsAheadOfTime(isolate()); | 
 | 2720 |  | 
 | 2721 |   // MacroAssembler::Abort calls (usually enabled with --debug-code) depend on | 
 | 2722 |   // CEntryStub, so we need to call GenerateStubsAheadOfTime before JSEntryStub | 
 | 2723 |   // is created. | 
 | 2724 |  | 
 | 2725 |   // gcc-4.4 has problem generating correct code of following snippet: | 
 | 2726 |   // {  JSEntryStub stub; | 
 | 2727 |   //    js_entry_code_ = *stub.GetCode(); | 
 | 2728 |   // } | 
 | 2729 |   // {  JSConstructEntryStub stub; | 
 | 2730 |   //    js_construct_entry_code_ = *stub.GetCode(); | 
 | 2731 |   // } | 
 | 2732 |   // To workaround the problem, make separate functions without inlining. | 
 | 2733 |   Heap::CreateJSEntryStub(); | 
 | 2734 |   Heap::CreateJSConstructEntryStub(); | 
 | 2735 | } | 
 | 2736 |  | 
 | 2737 |  | 
 | 2738 | void Heap::CreateInitialObjects() { | 
 | 2739 |   HandleScope scope(isolate()); | 
 | 2740 |   Factory* factory = isolate()->factory(); | 
 | 2741 |  | 
 | 2742 |   // The -0 value must be set before NewNumber works. | 
 | 2743 |   set_minus_zero_value(*factory->NewHeapNumber(-0.0, IMMUTABLE, TENURED)); | 
 | 2744 |   DCHECK(std::signbit(minus_zero_value()->Number()) != 0); | 
 | 2745 |  | 
 | 2746 |   set_nan_value( | 
 | 2747 |       *factory->NewHeapNumber(base::OS::nan_value(), IMMUTABLE, TENURED)); | 
 | 2748 |   set_infinity_value(*factory->NewHeapNumber(V8_INFINITY, IMMUTABLE, TENURED)); | 
 | 2749 |  | 
 | 2750 |   // The hole has not been created yet, but we want to put something | 
 | 2751 |   // predictable in the gaps in the string table, so lets make that Smi zero. | 
 | 2752 |   set_the_hole_value(reinterpret_cast<Oddball*>(Smi::FromInt(0))); | 
 | 2753 |  | 
 | 2754 |   // Allocate initial string table. | 
 | 2755 |   set_string_table(*StringTable::New(isolate(), kInitialStringTableSize)); | 
 | 2756 |  | 
 | 2757 |   // Finish initializing oddballs after creating the string table. | 
 | 2758 |   Oddball::Initialize(isolate(), factory->undefined_value(), "undefined", | 
 | 2759 |                       factory->nan_value(), Oddball::kUndefined); | 
 | 2760 |  | 
 | 2761 |   // Initialize the null_value. | 
 | 2762 |   Oddball::Initialize(isolate(), factory->null_value(), "null", | 
 | 2763 |                       handle(Smi::FromInt(0), isolate()), Oddball::kNull); | 
 | 2764 |  | 
 | 2765 |   set_true_value(*factory->NewOddball(factory->boolean_map(), "true", | 
 | 2766 |                                       handle(Smi::FromInt(1), isolate()), | 
 | 2767 |                                       Oddball::kTrue)); | 
 | 2768 |  | 
 | 2769 |   set_false_value(*factory->NewOddball(factory->boolean_map(), "false", | 
 | 2770 |                                        handle(Smi::FromInt(0), isolate()), | 
 | 2771 |                                        Oddball::kFalse)); | 
 | 2772 |  | 
 | 2773 |   set_the_hole_value(*factory->NewOddball(factory->the_hole_map(), "hole", | 
 | 2774 |                                           handle(Smi::FromInt(-1), isolate()), | 
 | 2775 |                                           Oddball::kTheHole)); | 
 | 2776 |  | 
 | 2777 |   set_uninitialized_value(*factory->NewOddball( | 
 | 2778 |       factory->uninitialized_map(), "uninitialized", | 
 | 2779 |       handle(Smi::FromInt(-1), isolate()), Oddball::kUninitialized)); | 
 | 2780 |  | 
 | 2781 |   set_arguments_marker(*factory->NewOddball( | 
 | 2782 |       factory->arguments_marker_map(), "arguments_marker", | 
 | 2783 |       handle(Smi::FromInt(-4), isolate()), Oddball::kArgumentMarker)); | 
 | 2784 |  | 
 | 2785 |   set_no_interceptor_result_sentinel(*factory->NewOddball( | 
 | 2786 |       factory->no_interceptor_result_sentinel_map(), | 
 | 2787 |       "no_interceptor_result_sentinel", handle(Smi::FromInt(-2), isolate()), | 
 | 2788 |       Oddball::kOther)); | 
 | 2789 |  | 
 | 2790 |   set_termination_exception(*factory->NewOddball( | 
 | 2791 |       factory->termination_exception_map(), "termination_exception", | 
 | 2792 |       handle(Smi::FromInt(-3), isolate()), Oddball::kOther)); | 
 | 2793 |  | 
 | 2794 |   set_exception(*factory->NewOddball(factory->exception_map(), "exception", | 
 | 2795 |                                      handle(Smi::FromInt(-5), isolate()), | 
 | 2796 |                                      Oddball::kException)); | 
 | 2797 |  | 
 | 2798 |   for (unsigned i = 0; i < arraysize(constant_string_table); i++) { | 
 | 2799 |     Handle<String> str = | 
 | 2800 |         factory->InternalizeUtf8String(constant_string_table[i].contents); | 
 | 2801 |     roots_[constant_string_table[i].index] = *str; | 
 | 2802 |   } | 
 | 2803 |  | 
 | 2804 |   // Allocate the hidden string which is used to identify the hidden properties | 
 | 2805 |   // in JSObjects. The hash code has a special value so that it will not match | 
 | 2806 |   // the empty string when searching for the property. It cannot be part of the | 
 | 2807 |   // loop above because it needs to be allocated manually with the special | 
 | 2808 |   // hash code in place. The hash code for the hidden_string is zero to ensure | 
 | 2809 |   // that it will always be at the first entry in property descriptors. | 
 | 2810 |   hidden_string_ = *factory->NewOneByteInternalizedString( | 
 | 2811 |       OneByteVector("", 0), String::kEmptyStringHash); | 
 | 2812 |  | 
 | 2813 |   // Create the code_stubs dictionary. The initial size is set to avoid | 
 | 2814 |   // expanding the dictionary during bootstrapping. | 
 | 2815 |   set_code_stubs(*UnseededNumberDictionary::New(isolate(), 128)); | 
 | 2816 |  | 
 | 2817 |   // Create the non_monomorphic_cache used in stub-cache.cc. The initial size | 
 | 2818 |   // is set to avoid expanding the dictionary during bootstrapping. | 
 | 2819 |   set_non_monomorphic_cache(*UnseededNumberDictionary::New(isolate(), 64)); | 
 | 2820 |  | 
 | 2821 |   set_polymorphic_code_cache(PolymorphicCodeCache::cast( | 
 | 2822 |       *factory->NewStruct(POLYMORPHIC_CODE_CACHE_TYPE))); | 
 | 2823 |  | 
 | 2824 |   set_instanceof_cache_function(Smi::FromInt(0)); | 
 | 2825 |   set_instanceof_cache_map(Smi::FromInt(0)); | 
 | 2826 |   set_instanceof_cache_answer(Smi::FromInt(0)); | 
 | 2827 |  | 
 | 2828 |   CreateFixedStubs(); | 
 | 2829 |  | 
 | 2830 |   // Allocate the dictionary of intrinsic function names. | 
 | 2831 |   Handle<NameDictionary> intrinsic_names = | 
 | 2832 |       NameDictionary::New(isolate(), Runtime::kNumFunctions, TENURED); | 
 | 2833 |   Runtime::InitializeIntrinsicFunctionNames(isolate(), intrinsic_names); | 
 | 2834 |   set_intrinsic_function_names(*intrinsic_names); | 
 | 2835 |  | 
 | 2836 |   set_number_string_cache( | 
 | 2837 |       *factory->NewFixedArray(kInitialNumberStringCacheSize * 2, TENURED)); | 
 | 2838 |  | 
 | 2839 |   // Allocate cache for single character one byte strings. | 
 | 2840 |   set_single_character_string_cache( | 
 | 2841 |       *factory->NewFixedArray(String::kMaxOneByteCharCode + 1, TENURED)); | 
 | 2842 |  | 
 | 2843 |   // Allocate cache for string split and regexp-multiple. | 
 | 2844 |   set_string_split_cache(*factory->NewFixedArray( | 
 | 2845 |       RegExpResultsCache::kRegExpResultsCacheSize, TENURED)); | 
 | 2846 |   set_regexp_multiple_cache(*factory->NewFixedArray( | 
 | 2847 |       RegExpResultsCache::kRegExpResultsCacheSize, TENURED)); | 
 | 2848 |  | 
 | 2849 |   // Allocate cache for external strings pointing to native source code. | 
 | 2850 |   set_natives_source_cache( | 
 | 2851 |       *factory->NewFixedArray(Natives::GetBuiltinsCount())); | 
 | 2852 |  | 
 | 2853 |   set_undefined_cell(*factory->NewCell(factory->undefined_value())); | 
 | 2854 |  | 
 | 2855 |   // The symbol registry is initialized lazily. | 
 | 2856 |   set_symbol_registry(undefined_value()); | 
 | 2857 |  | 
 | 2858 |   // Allocate object to hold object observation state. | 
 | 2859 |   set_observation_state(*factory->NewJSObjectFromMap( | 
 | 2860 |       factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize))); | 
 | 2861 |  | 
 | 2862 |   // Microtask queue uses the empty fixed array as a sentinel for "empty". | 
 | 2863 |   // Number of queued microtasks stored in Isolate::pending_microtask_count(). | 
 | 2864 |   set_microtask_queue(empty_fixed_array()); | 
 | 2865 |  | 
 | 2866 |   set_detailed_stack_trace_symbol(*factory->NewPrivateOwnSymbol()); | 
 | 2867 |   set_elements_transition_symbol(*factory->NewPrivateOwnSymbol()); | 
 | 2868 |   set_frozen_symbol(*factory->NewPrivateOwnSymbol()); | 
 | 2869 |   set_megamorphic_symbol(*factory->NewPrivateOwnSymbol()); | 
 | 2870 |   set_premonomorphic_symbol(*factory->NewPrivateOwnSymbol()); | 
 | 2871 |   set_generic_symbol(*factory->NewPrivateOwnSymbol()); | 
 | 2872 |   set_nonexistent_symbol(*factory->NewPrivateOwnSymbol()); | 
 | 2873 |   set_normal_ic_symbol(*factory->NewPrivateOwnSymbol()); | 
 | 2874 |   set_observed_symbol(*factory->NewPrivateOwnSymbol()); | 
 | 2875 |   set_stack_trace_symbol(*factory->NewPrivateOwnSymbol()); | 
 | 2876 |   set_uninitialized_symbol(*factory->NewPrivateOwnSymbol()); | 
 | 2877 |   set_home_object_symbol(*factory->NewPrivateOwnSymbol()); | 
 | 2878 |  | 
 | 2879 |   Handle<SeededNumberDictionary> slow_element_dictionary = | 
 | 2880 |       SeededNumberDictionary::New(isolate(), 0, TENURED); | 
 | 2881 |   slow_element_dictionary->set_requires_slow_elements(); | 
 | 2882 |   set_empty_slow_element_dictionary(*slow_element_dictionary); | 
 | 2883 |  | 
 | 2884 |   set_materialized_objects(*factory->NewFixedArray(0, TENURED)); | 
 | 2885 |  | 
 | 2886 |   // Handling of script id generation is in Factory::NewScript. | 
 | 2887 |   set_last_script_id(Smi::FromInt(v8::UnboundScript::kNoScriptId)); | 
 | 2888 |  | 
 | 2889 |   set_allocation_sites_scratchpad( | 
 | 2890 |       *factory->NewFixedArray(kAllocationSiteScratchpadSize, TENURED)); | 
 | 2891 |   InitializeAllocationSitesScratchpad(); | 
 | 2892 |  | 
 | 2893 |   // Initialize keyed lookup cache. | 
 | 2894 |   isolate_->keyed_lookup_cache()->Clear(); | 
 | 2895 |  | 
 | 2896 |   // Initialize context slot cache. | 
 | 2897 |   isolate_->context_slot_cache()->Clear(); | 
 | 2898 |  | 
 | 2899 |   // Initialize descriptor cache. | 
 | 2900 |   isolate_->descriptor_lookup_cache()->Clear(); | 
 | 2901 |  | 
 | 2902 |   // Initialize compilation cache. | 
 | 2903 |   isolate_->compilation_cache()->Clear(); | 
 | 2904 | } | 
 | 2905 |  | 
 | 2906 |  | 
 | 2907 | bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) { | 
 | 2908 |   RootListIndex writable_roots[] = { | 
 | 2909 |       kStoreBufferTopRootIndex, | 
 | 2910 |       kStackLimitRootIndex, | 
 | 2911 |       kNumberStringCacheRootIndex, | 
 | 2912 |       kInstanceofCacheFunctionRootIndex, | 
 | 2913 |       kInstanceofCacheMapRootIndex, | 
 | 2914 |       kInstanceofCacheAnswerRootIndex, | 
 | 2915 |       kCodeStubsRootIndex, | 
 | 2916 |       kNonMonomorphicCacheRootIndex, | 
 | 2917 |       kPolymorphicCodeCacheRootIndex, | 
 | 2918 |       kLastScriptIdRootIndex, | 
 | 2919 |       kEmptyScriptRootIndex, | 
 | 2920 |       kRealStackLimitRootIndex, | 
 | 2921 |       kArgumentsAdaptorDeoptPCOffsetRootIndex, | 
 | 2922 |       kConstructStubDeoptPCOffsetRootIndex, | 
 | 2923 |       kGetterStubDeoptPCOffsetRootIndex, | 
 | 2924 |       kSetterStubDeoptPCOffsetRootIndex, | 
 | 2925 |       kStringTableRootIndex, | 
 | 2926 |   }; | 
 | 2927 |  | 
 | 2928 |   for (unsigned int i = 0; i < arraysize(writable_roots); i++) { | 
 | 2929 |     if (root_index == writable_roots[i]) return true; | 
 | 2930 |   } | 
 | 2931 |   return false; | 
 | 2932 | } | 
 | 2933 |  | 
 | 2934 |  | 
 | 2935 | bool Heap::RootCanBeTreatedAsConstant(RootListIndex root_index) { | 
 | 2936 |   return !RootCanBeWrittenAfterInitialization(root_index) && | 
 | 2937 |          !InNewSpace(roots_array_start()[root_index]); | 
 | 2938 | } | 
 | 2939 |  | 
 | 2940 |  | 
 | 2941 | Object* RegExpResultsCache::Lookup(Heap* heap, String* key_string, | 
 | 2942 |                                    Object* key_pattern, ResultsCacheType type) { | 
 | 2943 |   FixedArray* cache; | 
 | 2944 |   if (!key_string->IsInternalizedString()) return Smi::FromInt(0); | 
 | 2945 |   if (type == STRING_SPLIT_SUBSTRINGS) { | 
 | 2946 |     DCHECK(key_pattern->IsString()); | 
 | 2947 |     if (!key_pattern->IsInternalizedString()) return Smi::FromInt(0); | 
 | 2948 |     cache = heap->string_split_cache(); | 
 | 2949 |   } else { | 
 | 2950 |     DCHECK(type == REGEXP_MULTIPLE_INDICES); | 
 | 2951 |     DCHECK(key_pattern->IsFixedArray()); | 
 | 2952 |     cache = heap->regexp_multiple_cache(); | 
 | 2953 |   } | 
 | 2954 |  | 
 | 2955 |   uint32_t hash = key_string->Hash(); | 
 | 2956 |   uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) & | 
 | 2957 |                     ~(kArrayEntriesPerCacheEntry - 1)); | 
 | 2958 |   if (cache->get(index + kStringOffset) == key_string && | 
 | 2959 |       cache->get(index + kPatternOffset) == key_pattern) { | 
 | 2960 |     return cache->get(index + kArrayOffset); | 
 | 2961 |   } | 
 | 2962 |   index = | 
 | 2963 |       ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1)); | 
 | 2964 |   if (cache->get(index + kStringOffset) == key_string && | 
 | 2965 |       cache->get(index + kPatternOffset) == key_pattern) { | 
 | 2966 |     return cache->get(index + kArrayOffset); | 
 | 2967 |   } | 
 | 2968 |   return Smi::FromInt(0); | 
 | 2969 | } | 
 | 2970 |  | 
 | 2971 |  | 
 | 2972 | void RegExpResultsCache::Enter(Isolate* isolate, Handle<String> key_string, | 
 | 2973 |                                Handle<Object> key_pattern, | 
 | 2974 |                                Handle<FixedArray> value_array, | 
 | 2975 |                                ResultsCacheType type) { | 
 | 2976 |   Factory* factory = isolate->factory(); | 
 | 2977 |   Handle<FixedArray> cache; | 
 | 2978 |   if (!key_string->IsInternalizedString()) return; | 
 | 2979 |   if (type == STRING_SPLIT_SUBSTRINGS) { | 
 | 2980 |     DCHECK(key_pattern->IsString()); | 
 | 2981 |     if (!key_pattern->IsInternalizedString()) return; | 
 | 2982 |     cache = factory->string_split_cache(); | 
 | 2983 |   } else { | 
 | 2984 |     DCHECK(type == REGEXP_MULTIPLE_INDICES); | 
 | 2985 |     DCHECK(key_pattern->IsFixedArray()); | 
 | 2986 |     cache = factory->regexp_multiple_cache(); | 
 | 2987 |   } | 
 | 2988 |  | 
 | 2989 |   uint32_t hash = key_string->Hash(); | 
 | 2990 |   uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) & | 
 | 2991 |                     ~(kArrayEntriesPerCacheEntry - 1)); | 
 | 2992 |   if (cache->get(index + kStringOffset) == Smi::FromInt(0)) { | 
 | 2993 |     cache->set(index + kStringOffset, *key_string); | 
 | 2994 |     cache->set(index + kPatternOffset, *key_pattern); | 
 | 2995 |     cache->set(index + kArrayOffset, *value_array); | 
 | 2996 |   } else { | 
 | 2997 |     uint32_t index2 = | 
 | 2998 |         ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1)); | 
 | 2999 |     if (cache->get(index2 + kStringOffset) == Smi::FromInt(0)) { | 
 | 3000 |       cache->set(index2 + kStringOffset, *key_string); | 
 | 3001 |       cache->set(index2 + kPatternOffset, *key_pattern); | 
 | 3002 |       cache->set(index2 + kArrayOffset, *value_array); | 
 | 3003 |     } else { | 
 | 3004 |       cache->set(index2 + kStringOffset, Smi::FromInt(0)); | 
 | 3005 |       cache->set(index2 + kPatternOffset, Smi::FromInt(0)); | 
 | 3006 |       cache->set(index2 + kArrayOffset, Smi::FromInt(0)); | 
 | 3007 |       cache->set(index + kStringOffset, *key_string); | 
 | 3008 |       cache->set(index + kPatternOffset, *key_pattern); | 
 | 3009 |       cache->set(index + kArrayOffset, *value_array); | 
 | 3010 |     } | 
 | 3011 |   } | 
 | 3012 |   // If the array is a reasonably short list of substrings, convert it into a | 
 | 3013 |   // list of internalized strings. | 
 | 3014 |   if (type == STRING_SPLIT_SUBSTRINGS && value_array->length() < 100) { | 
 | 3015 |     for (int i = 0; i < value_array->length(); i++) { | 
 | 3016 |       Handle<String> str(String::cast(value_array->get(i)), isolate); | 
 | 3017 |       Handle<String> internalized_str = factory->InternalizeString(str); | 
 | 3018 |       value_array->set(i, *internalized_str); | 
 | 3019 |     } | 
 | 3020 |   } | 
 | 3021 |   // Convert backing store to a copy-on-write array. | 
 | 3022 |   value_array->set_map_no_write_barrier(*factory->fixed_cow_array_map()); | 
 | 3023 | } | 
 | 3024 |  | 
 | 3025 |  | 
 | 3026 | void RegExpResultsCache::Clear(FixedArray* cache) { | 
 | 3027 |   for (int i = 0; i < kRegExpResultsCacheSize; i++) { | 
 | 3028 |     cache->set(i, Smi::FromInt(0)); | 
 | 3029 |   } | 
 | 3030 | } | 
 | 3031 |  | 
 | 3032 |  | 
 | 3033 | int Heap::FullSizeNumberStringCacheLength() { | 
 | 3034 |   // Compute the size of the number string cache based on the max newspace size. | 
 | 3035 |   // The number string cache has a minimum size based on twice the initial cache | 
 | 3036 |   // size to ensure that it is bigger after being made 'full size'. | 
 | 3037 |   int number_string_cache_size = max_semi_space_size_ / 512; | 
 | 3038 |   number_string_cache_size = Max(kInitialNumberStringCacheSize * 2, | 
 | 3039 |                                  Min(0x4000, number_string_cache_size)); | 
 | 3040 |   // There is a string and a number per entry so the length is twice the number | 
 | 3041 |   // of entries. | 
 | 3042 |   return number_string_cache_size * 2; | 
 | 3043 | } | 
 | 3044 |  | 
 | 3045 |  | 
 | 3046 | void Heap::FlushNumberStringCache() { | 
 | 3047 |   // Flush the number to string cache. | 
 | 3048 |   int len = number_string_cache()->length(); | 
 | 3049 |   for (int i = 0; i < len; i++) { | 
 | 3050 |     number_string_cache()->set_undefined(i); | 
 | 3051 |   } | 
 | 3052 | } | 
 | 3053 |  | 
 | 3054 |  | 
 | 3055 | void Heap::FlushAllocationSitesScratchpad() { | 
 | 3056 |   for (int i = 0; i < allocation_sites_scratchpad_length_; i++) { | 
 | 3057 |     allocation_sites_scratchpad()->set_undefined(i); | 
 | 3058 |   } | 
 | 3059 |   allocation_sites_scratchpad_length_ = 0; | 
 | 3060 | } | 
 | 3061 |  | 
 | 3062 |  | 
 | 3063 | void Heap::InitializeAllocationSitesScratchpad() { | 
 | 3064 |   DCHECK(allocation_sites_scratchpad()->length() == | 
 | 3065 |          kAllocationSiteScratchpadSize); | 
 | 3066 |   for (int i = 0; i < kAllocationSiteScratchpadSize; i++) { | 
 | 3067 |     allocation_sites_scratchpad()->set_undefined(i); | 
 | 3068 |   } | 
 | 3069 | } | 
 | 3070 |  | 
 | 3071 |  | 
 | 3072 | void Heap::AddAllocationSiteToScratchpad(AllocationSite* site, | 
 | 3073 |                                          ScratchpadSlotMode mode) { | 
 | 3074 |   if (allocation_sites_scratchpad_length_ < kAllocationSiteScratchpadSize) { | 
 | 3075 |     // We cannot use the normal write-barrier because slots need to be | 
 | 3076 |     // recorded with non-incremental marking as well. We have to explicitly | 
 | 3077 |     // record the slot to take evacuation candidates into account. | 
 | 3078 |     allocation_sites_scratchpad()->set(allocation_sites_scratchpad_length_, | 
 | 3079 |                                        site, SKIP_WRITE_BARRIER); | 
 | 3080 |     Object** slot = allocation_sites_scratchpad()->RawFieldOfElementAt( | 
 | 3081 |         allocation_sites_scratchpad_length_); | 
 | 3082 |  | 
 | 3083 |     if (mode == RECORD_SCRATCHPAD_SLOT) { | 
 | 3084 |       // We need to allow slots buffer overflow here since the evacuation | 
 | 3085 |       // candidates are not part of the global list of old space pages and | 
 | 3086 |       // releasing an evacuation candidate due to a slots buffer overflow | 
 | 3087 |       // results in lost pages. | 
 | 3088 |       mark_compact_collector()->RecordSlot(slot, slot, *slot, | 
 | 3089 |                                            SlotsBuffer::IGNORE_OVERFLOW); | 
 | 3090 |     } | 
 | 3091 |     allocation_sites_scratchpad_length_++; | 
 | 3092 |   } | 
 | 3093 | } | 
 | 3094 |  | 
 | 3095 |  | 
 | 3096 | Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) { | 
 | 3097 |   return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]); | 
 | 3098 | } | 
 | 3099 |  | 
 | 3100 |  | 
 | 3101 | Heap::RootListIndex Heap::RootIndexForExternalArrayType( | 
 | 3102 |     ExternalArrayType array_type) { | 
 | 3103 |   switch (array_type) { | 
 | 3104 | #define ARRAY_TYPE_TO_ROOT_INDEX(Type, type, TYPE, ctype, size) \ | 
 | 3105 |   case kExternal##Type##Array:                                  \ | 
 | 3106 |     return kExternal##Type##ArrayMapRootIndex; | 
 | 3107 |  | 
 | 3108 |     TYPED_ARRAYS(ARRAY_TYPE_TO_ROOT_INDEX) | 
 | 3109 | #undef ARRAY_TYPE_TO_ROOT_INDEX | 
 | 3110 |  | 
 | 3111 |     default: | 
 | 3112 |       UNREACHABLE(); | 
 | 3113 |       return kUndefinedValueRootIndex; | 
 | 3114 |   } | 
 | 3115 | } | 
 | 3116 |  | 
 | 3117 |  | 
 | 3118 | Map* Heap::MapForFixedTypedArray(ExternalArrayType array_type) { | 
 | 3119 |   return Map::cast(roots_[RootIndexForFixedTypedArray(array_type)]); | 
 | 3120 | } | 
 | 3121 |  | 
 | 3122 |  | 
 | 3123 | Heap::RootListIndex Heap::RootIndexForFixedTypedArray( | 
 | 3124 |     ExternalArrayType array_type) { | 
 | 3125 |   switch (array_type) { | 
 | 3126 | #define ARRAY_TYPE_TO_ROOT_INDEX(Type, type, TYPE, ctype, size) \ | 
 | 3127 |   case kExternal##Type##Array:                                  \ | 
 | 3128 |     return kFixed##Type##ArrayMapRootIndex; | 
 | 3129 |  | 
 | 3130 |     TYPED_ARRAYS(ARRAY_TYPE_TO_ROOT_INDEX) | 
 | 3131 | #undef ARRAY_TYPE_TO_ROOT_INDEX | 
 | 3132 |  | 
 | 3133 |     default: | 
 | 3134 |       UNREACHABLE(); | 
 | 3135 |       return kUndefinedValueRootIndex; | 
 | 3136 |   } | 
 | 3137 | } | 
 | 3138 |  | 
 | 3139 |  | 
 | 3140 | Heap::RootListIndex Heap::RootIndexForEmptyExternalArray( | 
 | 3141 |     ElementsKind elementsKind) { | 
 | 3142 |   switch (elementsKind) { | 
 | 3143 | #define ELEMENT_KIND_TO_ROOT_INDEX(Type, type, TYPE, ctype, size) \ | 
 | 3144 |   case EXTERNAL_##TYPE##_ELEMENTS:                                \ | 
 | 3145 |     return kEmptyExternal##Type##ArrayRootIndex; | 
 | 3146 |  | 
 | 3147 |     TYPED_ARRAYS(ELEMENT_KIND_TO_ROOT_INDEX) | 
 | 3148 | #undef ELEMENT_KIND_TO_ROOT_INDEX | 
 | 3149 |  | 
 | 3150 |     default: | 
 | 3151 |       UNREACHABLE(); | 
 | 3152 |       return kUndefinedValueRootIndex; | 
 | 3153 |   } | 
 | 3154 | } | 
 | 3155 |  | 
 | 3156 |  | 
 | 3157 | Heap::RootListIndex Heap::RootIndexForEmptyFixedTypedArray( | 
 | 3158 |     ElementsKind elementsKind) { | 
 | 3159 |   switch (elementsKind) { | 
 | 3160 | #define ELEMENT_KIND_TO_ROOT_INDEX(Type, type, TYPE, ctype, size) \ | 
 | 3161 |   case TYPE##_ELEMENTS:                                           \ | 
 | 3162 |     return kEmptyFixed##Type##ArrayRootIndex; | 
 | 3163 |  | 
 | 3164 |     TYPED_ARRAYS(ELEMENT_KIND_TO_ROOT_INDEX) | 
 | 3165 | #undef ELEMENT_KIND_TO_ROOT_INDEX | 
 | 3166 |     default: | 
 | 3167 |       UNREACHABLE(); | 
 | 3168 |       return kUndefinedValueRootIndex; | 
 | 3169 |   } | 
 | 3170 | } | 
 | 3171 |  | 
 | 3172 |  | 
 | 3173 | ExternalArray* Heap::EmptyExternalArrayForMap(Map* map) { | 
 | 3174 |   return ExternalArray::cast( | 
 | 3175 |       roots_[RootIndexForEmptyExternalArray(map->elements_kind())]); | 
 | 3176 | } | 
 | 3177 |  | 
 | 3178 |  | 
 | 3179 | FixedTypedArrayBase* Heap::EmptyFixedTypedArrayForMap(Map* map) { | 
 | 3180 |   return FixedTypedArrayBase::cast( | 
 | 3181 |       roots_[RootIndexForEmptyFixedTypedArray(map->elements_kind())]); | 
 | 3182 | } | 
 | 3183 |  | 
 | 3184 |  | 
 | 3185 | AllocationResult Heap::AllocateForeign(Address address, | 
 | 3186 |                                        PretenureFlag pretenure) { | 
 | 3187 |   // Statically ensure that it is safe to allocate foreigns in paged spaces. | 
 | 3188 |   STATIC_ASSERT(Foreign::kSize <= Page::kMaxRegularHeapObjectSize); | 
 | 3189 |   AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; | 
 | 3190 |   Foreign* result; | 
 | 3191 |   AllocationResult allocation = Allocate(foreign_map(), space); | 
 | 3192 |   if (!allocation.To(&result)) return allocation; | 
 | 3193 |   result->set_foreign_address(address); | 
 | 3194 |   return result; | 
 | 3195 | } | 
 | 3196 |  | 
 | 3197 |  | 
 | 3198 | AllocationResult Heap::AllocateByteArray(int length, PretenureFlag pretenure) { | 
 | 3199 |   if (length < 0 || length > ByteArray::kMaxLength) { | 
 | 3200 |     v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", true); | 
 | 3201 |   } | 
 | 3202 |   int size = ByteArray::SizeFor(length); | 
 | 3203 |   AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure); | 
 | 3204 |   HeapObject* result; | 
 | 3205 |   { | 
 | 3206 |     AllocationResult allocation = AllocateRaw(size, space, OLD_DATA_SPACE); | 
 | 3207 |     if (!allocation.To(&result)) return allocation; | 
 | 3208 |   } | 
 | 3209 |  | 
 | 3210 |   result->set_map_no_write_barrier(byte_array_map()); | 
 | 3211 |   ByteArray::cast(result)->set_length(length); | 
 | 3212 |   return result; | 
 | 3213 | } | 
 | 3214 |  | 
 | 3215 |  | 
 | 3216 | void Heap::CreateFillerObjectAt(Address addr, int size) { | 
 | 3217 |   if (size == 0) return; | 
 | 3218 |   HeapObject* filler = HeapObject::FromAddress(addr); | 
 | 3219 |   if (size == kPointerSize) { | 
 | 3220 |     filler->set_map_no_write_barrier(one_pointer_filler_map()); | 
 | 3221 |   } else if (size == 2 * kPointerSize) { | 
 | 3222 |     filler->set_map_no_write_barrier(two_pointer_filler_map()); | 
 | 3223 |   } else { | 
 | 3224 |     filler->set_map_no_write_barrier(free_space_map()); | 
 | 3225 |     FreeSpace::cast(filler)->set_size(size); | 
 | 3226 |   } | 
 | 3227 | } | 
 | 3228 |  | 
 | 3229 |  | 
 | 3230 | bool Heap::CanMoveObjectStart(HeapObject* object) { | 
 | 3231 |   Address address = object->address(); | 
 | 3232 |   bool is_in_old_pointer_space = InOldPointerSpace(address); | 
 | 3233 |   bool is_in_old_data_space = InOldDataSpace(address); | 
 | 3234 |  | 
 | 3235 |   if (lo_space()->Contains(object)) return false; | 
 | 3236 |  | 
 | 3237 |   Page* page = Page::FromAddress(address); | 
 | 3238 |   // We can move the object start if: | 
 | 3239 |   // (1) the object is not in old pointer or old data space, | 
 | 3240 |   // (2) the page of the object was already swept, | 
 | 3241 |   // (3) the page was already concurrently swept. This case is an optimization | 
 | 3242 |   // for concurrent sweeping. The WasSwept predicate for concurrently swept | 
 | 3243 |   // pages is set after sweeping all pages. | 
 | 3244 |   return (!is_in_old_pointer_space && !is_in_old_data_space) || | 
 | 3245 |          page->WasSwept() || page->SweepingCompleted(); | 
 | 3246 | } | 
 | 3247 |  | 
 | 3248 |  | 
 | 3249 | void Heap::AdjustLiveBytes(Address address, int by, InvocationMode mode) { | 
 | 3250 |   if (incremental_marking()->IsMarking() && | 
 | 3251 |       Marking::IsBlack(Marking::MarkBitFrom(address))) { | 
 | 3252 |     if (mode == FROM_GC) { | 
 | 3253 |       MemoryChunk::IncrementLiveBytesFromGC(address, by); | 
 | 3254 |     } else { | 
 | 3255 |       MemoryChunk::IncrementLiveBytesFromMutator(address, by); | 
 | 3256 |     } | 
 | 3257 |   } | 
 | 3258 | } | 
 | 3259 |  | 
 | 3260 |  | 
 | 3261 | FixedArrayBase* Heap::LeftTrimFixedArray(FixedArrayBase* object, | 
 | 3262 |                                          int elements_to_trim) { | 
 | 3263 |   const int element_size = object->IsFixedArray() ? kPointerSize : kDoubleSize; | 
 | 3264 |   const int bytes_to_trim = elements_to_trim * element_size; | 
 | 3265 |   Map* map = object->map(); | 
 | 3266 |  | 
 | 3267 |   // For now this trick is only applied to objects in new and paged space. | 
 | 3268 |   // In large object space the object's start must coincide with chunk | 
 | 3269 |   // and thus the trick is just not applicable. | 
 | 3270 |   DCHECK(!lo_space()->Contains(object)); | 
 | 3271 |   DCHECK(object->map() != fixed_cow_array_map()); | 
 | 3272 |  | 
 | 3273 |   STATIC_ASSERT(FixedArrayBase::kMapOffset == 0); | 
 | 3274 |   STATIC_ASSERT(FixedArrayBase::kLengthOffset == kPointerSize); | 
 | 3275 |   STATIC_ASSERT(FixedArrayBase::kHeaderSize == 2 * kPointerSize); | 
 | 3276 |  | 
 | 3277 |   const int len = object->length(); | 
 | 3278 |   DCHECK(elements_to_trim <= len); | 
 | 3279 |  | 
 | 3280 |   // Calculate location of new array start. | 
 | 3281 |   Address new_start = object->address() + bytes_to_trim; | 
 | 3282 |  | 
 | 3283 |   // Technically in new space this write might be omitted (except for | 
 | 3284 |   // debug mode which iterates through the heap), but to play safer | 
 | 3285 |   // we still do it. | 
 | 3286 |   CreateFillerObjectAt(object->address(), bytes_to_trim); | 
 | 3287 |  | 
 | 3288 |   // Initialize header of the trimmed array. Since left trimming is only | 
 | 3289 |   // performed on pages which are not concurrently swept creating a filler | 
 | 3290 |   // object does not require synchronization. | 
 | 3291 |   DCHECK(CanMoveObjectStart(object)); | 
 | 3292 |   Object** former_start = HeapObject::RawField(object, 0); | 
 | 3293 |   int new_start_index = elements_to_trim * (element_size / kPointerSize); | 
 | 3294 |   former_start[new_start_index] = map; | 
 | 3295 |   former_start[new_start_index + 1] = Smi::FromInt(len - elements_to_trim); | 
 | 3296 |   FixedArrayBase* new_object = | 
 | 3297 |       FixedArrayBase::cast(HeapObject::FromAddress(new_start)); | 
 | 3298 |  | 
 | 3299 |   // Maintain consistency of live bytes during incremental marking | 
 | 3300 |   marking()->TransferMark(object->address(), new_start); | 
 | 3301 |   AdjustLiveBytes(new_start, -bytes_to_trim, Heap::FROM_MUTATOR); | 
 | 3302 |  | 
 | 3303 |   // Notify the heap profiler of change in object layout. | 
 | 3304 |   OnMoveEvent(new_object, object, new_object->Size()); | 
 | 3305 |   return new_object; | 
 | 3306 | } | 
 | 3307 |  | 
 | 3308 |  | 
 | 3309 | // Force instantiation of templatized method. | 
 | 3310 | template | 
 | 3311 | void Heap::RightTrimFixedArray<Heap::FROM_GC>(FixedArrayBase*, int); | 
 | 3312 | template | 
 | 3313 | void Heap::RightTrimFixedArray<Heap::FROM_MUTATOR>(FixedArrayBase*, int); | 
 | 3314 |  | 
 | 3315 |  | 
 | 3316 | template<Heap::InvocationMode mode> | 
 | 3317 | void Heap::RightTrimFixedArray(FixedArrayBase* object, int elements_to_trim) { | 
 | 3318 |   const int element_size = object->IsFixedArray() ? kPointerSize : kDoubleSize; | 
 | 3319 |   const int bytes_to_trim = elements_to_trim * element_size; | 
 | 3320 |  | 
 | 3321 |   // For now this trick is only applied to objects in new and paged space. | 
 | 3322 |   DCHECK(object->map() != fixed_cow_array_map()); | 
 | 3323 |  | 
 | 3324 |   const int len = object->length(); | 
 | 3325 |   DCHECK(elements_to_trim < len); | 
 | 3326 |  | 
 | 3327 |   // Calculate location of new array end. | 
 | 3328 |   Address new_end = object->address() + object->Size() - bytes_to_trim; | 
 | 3329 |  | 
 | 3330 |   // Technically in new space this write might be omitted (except for | 
 | 3331 |   // debug mode which iterates through the heap), but to play safer | 
 | 3332 |   // we still do it. | 
 | 3333 |   // We do not create a filler for objects in large object space. | 
 | 3334 |   // TODO(hpayer): We should shrink the large object page if the size | 
 | 3335 |   // of the object changed significantly. | 
 | 3336 |   if (!lo_space()->Contains(object)) { | 
 | 3337 |     CreateFillerObjectAt(new_end, bytes_to_trim); | 
 | 3338 |   } | 
 | 3339 |  | 
 | 3340 |   // Initialize header of the trimmed array. We are storing the new length | 
 | 3341 |   // using release store after creating a filler for the left-over space to | 
 | 3342 |   // avoid races with the sweeper thread. | 
 | 3343 |   object->synchronized_set_length(len - elements_to_trim); | 
 | 3344 |  | 
 | 3345 |   // Maintain consistency of live bytes during incremental marking | 
 | 3346 |   AdjustLiveBytes(object->address(), -bytes_to_trim, mode); | 
 | 3347 |  | 
 | 3348 |   // Notify the heap profiler of change in object layout. The array may not be | 
 | 3349 |   // moved during GC, and size has to be adjusted nevertheless. | 
 | 3350 |   HeapProfiler* profiler = isolate()->heap_profiler(); | 
 | 3351 |   if (profiler->is_tracking_allocations()) { | 
 | 3352 |     profiler->UpdateObjectSizeEvent(object->address(), object->Size()); | 
 | 3353 |   } | 
 | 3354 | } | 
 | 3355 |  | 
 | 3356 |  | 
 | 3357 | AllocationResult Heap::AllocateExternalArray(int length, | 
 | 3358 |                                              ExternalArrayType array_type, | 
 | 3359 |                                              void* external_pointer, | 
 | 3360 |                                              PretenureFlag pretenure) { | 
 | 3361 |   int size = ExternalArray::kAlignedSize; | 
 | 3362 |   AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure); | 
 | 3363 |   HeapObject* result; | 
 | 3364 |   { | 
 | 3365 |     AllocationResult allocation = AllocateRaw(size, space, OLD_DATA_SPACE); | 
 | 3366 |     if (!allocation.To(&result)) return allocation; | 
 | 3367 |   } | 
 | 3368 |  | 
 | 3369 |   result->set_map_no_write_barrier(MapForExternalArrayType(array_type)); | 
 | 3370 |   ExternalArray::cast(result)->set_length(length); | 
 | 3371 |   ExternalArray::cast(result)->set_external_pointer(external_pointer); | 
 | 3372 |   return result; | 
 | 3373 | } | 
 | 3374 |  | 
 | 3375 | static void ForFixedTypedArray(ExternalArrayType array_type, int* element_size, | 
 | 3376 |                                ElementsKind* element_kind) { | 
 | 3377 |   switch (array_type) { | 
 | 3378 | #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ | 
 | 3379 |   case kExternal##Type##Array:                          \ | 
 | 3380 |     *element_size = size;                               \ | 
 | 3381 |     *element_kind = TYPE##_ELEMENTS;                    \ | 
 | 3382 |     return; | 
 | 3383 |  | 
 | 3384 |     TYPED_ARRAYS(TYPED_ARRAY_CASE) | 
 | 3385 | #undef TYPED_ARRAY_CASE | 
 | 3386 |  | 
 | 3387 |     default: | 
 | 3388 |       *element_size = 0;               // Bogus | 
 | 3389 |       *element_kind = UINT8_ELEMENTS;  // Bogus | 
 | 3390 |       UNREACHABLE(); | 
 | 3391 |   } | 
 | 3392 | } | 
 | 3393 |  | 
 | 3394 |  | 
 | 3395 | AllocationResult Heap::AllocateFixedTypedArray(int length, | 
 | 3396 |                                                ExternalArrayType array_type, | 
 | 3397 |                                                PretenureFlag pretenure) { | 
 | 3398 |   int element_size; | 
 | 3399 |   ElementsKind elements_kind; | 
 | 3400 |   ForFixedTypedArray(array_type, &element_size, &elements_kind); | 
 | 3401 |   int size = OBJECT_POINTER_ALIGN(length * element_size + | 
 | 3402 |                                   FixedTypedArrayBase::kDataOffset); | 
 | 3403 | #ifndef V8_HOST_ARCH_64_BIT | 
 | 3404 |   if (array_type == kExternalFloat64Array) { | 
 | 3405 |     size += kPointerSize; | 
 | 3406 |   } | 
 | 3407 | #endif | 
 | 3408 |   AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure); | 
 | 3409 |  | 
 | 3410 |   HeapObject* object; | 
 | 3411 |   AllocationResult allocation = AllocateRaw(size, space, OLD_DATA_SPACE); | 
 | 3412 |   if (!allocation.To(&object)) return allocation; | 
 | 3413 |  | 
 | 3414 |   if (array_type == kExternalFloat64Array) { | 
 | 3415 |     object = EnsureDoubleAligned(this, object, size); | 
 | 3416 |   } | 
 | 3417 |  | 
 | 3418 |   object->set_map(MapForFixedTypedArray(array_type)); | 
 | 3419 |   FixedTypedArrayBase* elements = FixedTypedArrayBase::cast(object); | 
 | 3420 |   elements->set_length(length); | 
 | 3421 |   memset(elements->DataPtr(), 0, elements->DataSize()); | 
 | 3422 |   return elements; | 
 | 3423 | } | 
 | 3424 |  | 
 | 3425 |  | 
 | 3426 | AllocationResult Heap::AllocateCode(int object_size, bool immovable) { | 
 | 3427 |   DCHECK(IsAligned(static_cast<intptr_t>(object_size), kCodeAlignment)); | 
 | 3428 |   AllocationResult allocation = | 
 | 3429 |       AllocateRaw(object_size, CODE_SPACE, CODE_SPACE); | 
 | 3430 |  | 
 | 3431 |   HeapObject* result; | 
 | 3432 |   if (!allocation.To(&result)) return allocation; | 
 | 3433 |  | 
 | 3434 |   if (immovable) { | 
 | 3435 |     Address address = result->address(); | 
 | 3436 |     // Code objects which should stay at a fixed address are allocated either | 
 | 3437 |     // in the first page of code space (objects on the first page of each space | 
 | 3438 |     // are never moved) or in large object space. | 
 | 3439 |     if (!code_space_->FirstPage()->Contains(address) && | 
 | 3440 |         MemoryChunk::FromAddress(address)->owner()->identity() != LO_SPACE) { | 
 | 3441 |       // Discard the first code allocation, which was on a page where it could | 
 | 3442 |       // be moved. | 
 | 3443 |       CreateFillerObjectAt(result->address(), object_size); | 
 | 3444 |       allocation = lo_space_->AllocateRaw(object_size, EXECUTABLE); | 
 | 3445 |       if (!allocation.To(&result)) return allocation; | 
 | 3446 |       OnAllocationEvent(result, object_size); | 
 | 3447 |     } | 
 | 3448 |   } | 
 | 3449 |  | 
 | 3450 |   result->set_map_no_write_barrier(code_map()); | 
 | 3451 |   Code* code = Code::cast(result); | 
 | 3452 |   DCHECK(isolate_->code_range() == NULL || !isolate_->code_range()->valid() || | 
 | 3453 |          isolate_->code_range()->contains(code->address())); | 
 | 3454 |   code->set_gc_metadata(Smi::FromInt(0)); | 
 | 3455 |   code->set_ic_age(global_ic_age_); | 
 | 3456 |   return code; | 
 | 3457 | } | 
 | 3458 |  | 
 | 3459 |  | 
 | 3460 | AllocationResult Heap::CopyCode(Code* code) { | 
 | 3461 |   AllocationResult allocation; | 
 | 3462 |   HeapObject* new_constant_pool; | 
 | 3463 |   if (FLAG_enable_ool_constant_pool && | 
 | 3464 |       code->constant_pool() != empty_constant_pool_array()) { | 
 | 3465 |     // Copy the constant pool, since edits to the copied code may modify | 
 | 3466 |     // the constant pool. | 
 | 3467 |     allocation = CopyConstantPoolArray(code->constant_pool()); | 
 | 3468 |     if (!allocation.To(&new_constant_pool)) return allocation; | 
 | 3469 |   } else { | 
 | 3470 |     new_constant_pool = empty_constant_pool_array(); | 
 | 3471 |   } | 
 | 3472 |  | 
 | 3473 |   HeapObject* result; | 
 | 3474 |   // Allocate an object the same size as the code object. | 
 | 3475 |   int obj_size = code->Size(); | 
 | 3476 |   allocation = AllocateRaw(obj_size, CODE_SPACE, CODE_SPACE); | 
 | 3477 |   if (!allocation.To(&result)) return allocation; | 
 | 3478 |  | 
 | 3479 |   // Copy code object. | 
 | 3480 |   Address old_addr = code->address(); | 
 | 3481 |   Address new_addr = result->address(); | 
 | 3482 |   CopyBlock(new_addr, old_addr, obj_size); | 
 | 3483 |   Code* new_code = Code::cast(result); | 
 | 3484 |  | 
 | 3485 |   // Update the constant pool. | 
 | 3486 |   new_code->set_constant_pool(new_constant_pool); | 
 | 3487 |  | 
 | 3488 |   // Relocate the copy. | 
 | 3489 |   DCHECK(isolate_->code_range() == NULL || !isolate_->code_range()->valid() || | 
 | 3490 |          isolate_->code_range()->contains(code->address())); | 
 | 3491 |   new_code->Relocate(new_addr - old_addr); | 
 | 3492 |   return new_code; | 
 | 3493 | } | 
 | 3494 |  | 
 | 3495 |  | 
 | 3496 | AllocationResult Heap::CopyCode(Code* code, Vector<byte> reloc_info) { | 
 | 3497 |   // Allocate ByteArray and ConstantPoolArray before the Code object, so that we | 
 | 3498 |   // do not risk leaving uninitialized Code object (and breaking the heap). | 
 | 3499 |   ByteArray* reloc_info_array; | 
 | 3500 |   { | 
 | 3501 |     AllocationResult allocation = | 
 | 3502 |         AllocateByteArray(reloc_info.length(), TENURED); | 
 | 3503 |     if (!allocation.To(&reloc_info_array)) return allocation; | 
 | 3504 |   } | 
 | 3505 |   HeapObject* new_constant_pool; | 
 | 3506 |   if (FLAG_enable_ool_constant_pool && | 
 | 3507 |       code->constant_pool() != empty_constant_pool_array()) { | 
 | 3508 |     // Copy the constant pool, since edits to the copied code may modify | 
 | 3509 |     // the constant pool. | 
 | 3510 |     AllocationResult allocation = CopyConstantPoolArray(code->constant_pool()); | 
 | 3511 |     if (!allocation.To(&new_constant_pool)) return allocation; | 
 | 3512 |   } else { | 
 | 3513 |     new_constant_pool = empty_constant_pool_array(); | 
 | 3514 |   } | 
 | 3515 |  | 
 | 3516 |   int new_body_size = RoundUp(code->instruction_size(), kObjectAlignment); | 
 | 3517 |  | 
 | 3518 |   int new_obj_size = Code::SizeFor(new_body_size); | 
 | 3519 |  | 
 | 3520 |   Address old_addr = code->address(); | 
 | 3521 |  | 
 | 3522 |   size_t relocation_offset = | 
 | 3523 |       static_cast<size_t>(code->instruction_end() - old_addr); | 
 | 3524 |  | 
 | 3525 |   HeapObject* result; | 
 | 3526 |   AllocationResult allocation = | 
 | 3527 |       AllocateRaw(new_obj_size, CODE_SPACE, CODE_SPACE); | 
 | 3528 |   if (!allocation.To(&result)) return allocation; | 
 | 3529 |  | 
 | 3530 |   // Copy code object. | 
 | 3531 |   Address new_addr = result->address(); | 
 | 3532 |  | 
 | 3533 |   // Copy header and instructions. | 
 | 3534 |   CopyBytes(new_addr, old_addr, relocation_offset); | 
 | 3535 |  | 
 | 3536 |   Code* new_code = Code::cast(result); | 
 | 3537 |   new_code->set_relocation_info(reloc_info_array); | 
 | 3538 |  | 
 | 3539 |   // Update constant pool. | 
 | 3540 |   new_code->set_constant_pool(new_constant_pool); | 
 | 3541 |  | 
 | 3542 |   // Copy patched rinfo. | 
 | 3543 |   CopyBytes(new_code->relocation_start(), reloc_info.start(), | 
 | 3544 |             static_cast<size_t>(reloc_info.length())); | 
 | 3545 |  | 
 | 3546 |   // Relocate the copy. | 
 | 3547 |   DCHECK(isolate_->code_range() == NULL || !isolate_->code_range()->valid() || | 
 | 3548 |          isolate_->code_range()->contains(code->address())); | 
 | 3549 |   new_code->Relocate(new_addr - old_addr); | 
 | 3550 |  | 
 | 3551 | #ifdef VERIFY_HEAP | 
 | 3552 |   if (FLAG_verify_heap) code->ObjectVerify(); | 
 | 3553 | #endif | 
 | 3554 |   return new_code; | 
 | 3555 | } | 
 | 3556 |  | 
 | 3557 |  | 
 | 3558 | void Heap::InitializeAllocationMemento(AllocationMemento* memento, | 
 | 3559 |                                        AllocationSite* allocation_site) { | 
 | 3560 |   memento->set_map_no_write_barrier(allocation_memento_map()); | 
 | 3561 |   DCHECK(allocation_site->map() == allocation_site_map()); | 
 | 3562 |   memento->set_allocation_site(allocation_site, SKIP_WRITE_BARRIER); | 
 | 3563 |   if (FLAG_allocation_site_pretenuring) { | 
 | 3564 |     allocation_site->IncrementMementoCreateCount(); | 
 | 3565 |   } | 
 | 3566 | } | 
 | 3567 |  | 
 | 3568 |  | 
 | 3569 | AllocationResult Heap::Allocate(Map* map, AllocationSpace space, | 
 | 3570 |                                 AllocationSite* allocation_site) { | 
 | 3571 |   DCHECK(gc_state_ == NOT_IN_GC); | 
 | 3572 |   DCHECK(map->instance_type() != MAP_TYPE); | 
 | 3573 |   // If allocation failures are disallowed, we may allocate in a different | 
 | 3574 |   // space when new space is full and the object is not a large object. | 
 | 3575 |   AllocationSpace retry_space = | 
 | 3576 |       (space != NEW_SPACE) ? space : TargetSpaceId(map->instance_type()); | 
 | 3577 |   int size = map->instance_size(); | 
 | 3578 |   if (allocation_site != NULL) { | 
 | 3579 |     size += AllocationMemento::kSize; | 
 | 3580 |   } | 
 | 3581 |   HeapObject* result; | 
 | 3582 |   AllocationResult allocation = AllocateRaw(size, space, retry_space); | 
 | 3583 |   if (!allocation.To(&result)) return allocation; | 
 | 3584 |   // No need for write barrier since object is white and map is in old space. | 
 | 3585 |   result->set_map_no_write_barrier(map); | 
 | 3586 |   if (allocation_site != NULL) { | 
 | 3587 |     AllocationMemento* alloc_memento = reinterpret_cast<AllocationMemento*>( | 
 | 3588 |         reinterpret_cast<Address>(result) + map->instance_size()); | 
 | 3589 |     InitializeAllocationMemento(alloc_memento, allocation_site); | 
 | 3590 |   } | 
 | 3591 |   return result; | 
 | 3592 | } | 
 | 3593 |  | 
 | 3594 |  | 
 | 3595 | void Heap::InitializeJSObjectFromMap(JSObject* obj, FixedArray* properties, | 
 | 3596 |                                      Map* map) { | 
 | 3597 |   obj->set_properties(properties); | 
 | 3598 |   obj->initialize_elements(); | 
 | 3599 |   // TODO(1240798): Initialize the object's body using valid initial values | 
 | 3600 |   // according to the object's initial map.  For example, if the map's | 
 | 3601 |   // instance type is JS_ARRAY_TYPE, the length field should be initialized | 
 | 3602 |   // to a number (e.g. Smi::FromInt(0)) and the elements initialized to a | 
 | 3603 |   // fixed array (e.g. Heap::empty_fixed_array()).  Currently, the object | 
 | 3604 |   // verification code has to cope with (temporarily) invalid objects.  See | 
 | 3605 |   // for example, JSArray::JSArrayVerify). | 
 | 3606 |   Object* filler; | 
 | 3607 |   // We cannot always fill with one_pointer_filler_map because objects | 
 | 3608 |   // created from API functions expect their internal fields to be initialized | 
 | 3609 |   // with undefined_value. | 
 | 3610 |   // Pre-allocated fields need to be initialized with undefined_value as well | 
 | 3611 |   // so that object accesses before the constructor completes (e.g. in the | 
 | 3612 |   // debugger) will not cause a crash. | 
 | 3613 |   if (map->constructor()->IsJSFunction() && | 
 | 3614 |       JSFunction::cast(map->constructor()) | 
 | 3615 |           ->IsInobjectSlackTrackingInProgress()) { | 
 | 3616 |     // We might want to shrink the object later. | 
 | 3617 |     DCHECK(obj->GetInternalFieldCount() == 0); | 
 | 3618 |     filler = Heap::one_pointer_filler_map(); | 
 | 3619 |   } else { | 
 | 3620 |     filler = Heap::undefined_value(); | 
 | 3621 |   } | 
 | 3622 |   obj->InitializeBody(map, Heap::undefined_value(), filler); | 
 | 3623 | } | 
 | 3624 |  | 
 | 3625 |  | 
 | 3626 | AllocationResult Heap::AllocateJSObjectFromMap( | 
 | 3627 |     Map* map, PretenureFlag pretenure, bool allocate_properties, | 
 | 3628 |     AllocationSite* allocation_site) { | 
 | 3629 |   // JSFunctions should be allocated using AllocateFunction to be | 
 | 3630 |   // properly initialized. | 
 | 3631 |   DCHECK(map->instance_type() != JS_FUNCTION_TYPE); | 
 | 3632 |  | 
 | 3633 |   // Both types of global objects should be allocated using | 
 | 3634 |   // AllocateGlobalObject to be properly initialized. | 
 | 3635 |   DCHECK(map->instance_type() != JS_GLOBAL_OBJECT_TYPE); | 
 | 3636 |   DCHECK(map->instance_type() != JS_BUILTINS_OBJECT_TYPE); | 
 | 3637 |  | 
 | 3638 |   // Allocate the backing storage for the properties. | 
 | 3639 |   FixedArray* properties; | 
 | 3640 |   if (allocate_properties) { | 
 | 3641 |     int prop_size = map->InitialPropertiesLength(); | 
 | 3642 |     DCHECK(prop_size >= 0); | 
 | 3643 |     { | 
 | 3644 |       AllocationResult allocation = AllocateFixedArray(prop_size, pretenure); | 
 | 3645 |       if (!allocation.To(&properties)) return allocation; | 
 | 3646 |     } | 
 | 3647 |   } else { | 
 | 3648 |     properties = empty_fixed_array(); | 
 | 3649 |   } | 
 | 3650 |  | 
 | 3651 |   // Allocate the JSObject. | 
 | 3652 |   int size = map->instance_size(); | 
 | 3653 |   AllocationSpace space = SelectSpace(size, OLD_POINTER_SPACE, pretenure); | 
 | 3654 |   JSObject* js_obj; | 
 | 3655 |   AllocationResult allocation = Allocate(map, space, allocation_site); | 
 | 3656 |   if (!allocation.To(&js_obj)) return allocation; | 
 | 3657 |  | 
 | 3658 |   // Initialize the JSObject. | 
 | 3659 |   InitializeJSObjectFromMap(js_obj, properties, map); | 
 | 3660 |   DCHECK(js_obj->HasFastElements() || js_obj->HasExternalArrayElements() || | 
 | 3661 |          js_obj->HasFixedTypedArrayElements()); | 
 | 3662 |   return js_obj; | 
 | 3663 | } | 
 | 3664 |  | 
 | 3665 |  | 
 | 3666 | AllocationResult Heap::AllocateJSObject(JSFunction* constructor, | 
 | 3667 |                                         PretenureFlag pretenure, | 
 | 3668 |                                         AllocationSite* allocation_site) { | 
 | 3669 |   DCHECK(constructor->has_initial_map()); | 
 | 3670 |  | 
 | 3671 |   // Allocate the object based on the constructors initial map. | 
 | 3672 |   AllocationResult allocation = AllocateJSObjectFromMap( | 
 | 3673 |       constructor->initial_map(), pretenure, true, allocation_site); | 
 | 3674 | #ifdef DEBUG | 
 | 3675 |   // Make sure result is NOT a global object if valid. | 
 | 3676 |   HeapObject* obj; | 
 | 3677 |   DCHECK(!allocation.To(&obj) || !obj->IsGlobalObject()); | 
 | 3678 | #endif | 
 | 3679 |   return allocation; | 
 | 3680 | } | 
 | 3681 |  | 
 | 3682 |  | 
 | 3683 | AllocationResult Heap::CopyJSObject(JSObject* source, AllocationSite* site) { | 
 | 3684 |   // Never used to copy functions.  If functions need to be copied we | 
 | 3685 |   // have to be careful to clear the literals array. | 
 | 3686 |   SLOW_DCHECK(!source->IsJSFunction()); | 
 | 3687 |  | 
 | 3688 |   // Make the clone. | 
 | 3689 |   Map* map = source->map(); | 
 | 3690 |   int object_size = map->instance_size(); | 
 | 3691 |   HeapObject* clone; | 
 | 3692 |  | 
 | 3693 |   DCHECK(site == NULL || AllocationSite::CanTrack(map->instance_type())); | 
 | 3694 |  | 
 | 3695 |   WriteBarrierMode wb_mode = UPDATE_WRITE_BARRIER; | 
 | 3696 |  | 
 | 3697 |   // If we're forced to always allocate, we use the general allocation | 
 | 3698 |   // functions which may leave us with an object in old space. | 
 | 3699 |   if (always_allocate()) { | 
 | 3700 |     { | 
 | 3701 |       AllocationResult allocation = | 
 | 3702 |           AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE); | 
 | 3703 |       if (!allocation.To(&clone)) return allocation; | 
 | 3704 |     } | 
 | 3705 |     Address clone_address = clone->address(); | 
 | 3706 |     CopyBlock(clone_address, source->address(), object_size); | 
 | 3707 |     // Update write barrier for all fields that lie beyond the header. | 
 | 3708 |     RecordWrites(clone_address, JSObject::kHeaderSize, | 
 | 3709 |                  (object_size - JSObject::kHeaderSize) / kPointerSize); | 
 | 3710 |   } else { | 
 | 3711 |     wb_mode = SKIP_WRITE_BARRIER; | 
 | 3712 |  | 
 | 3713 |     { | 
 | 3714 |       int adjusted_object_size = | 
 | 3715 |           site != NULL ? object_size + AllocationMemento::kSize : object_size; | 
 | 3716 |       AllocationResult allocation = | 
 | 3717 |           AllocateRaw(adjusted_object_size, NEW_SPACE, NEW_SPACE); | 
 | 3718 |       if (!allocation.To(&clone)) return allocation; | 
 | 3719 |     } | 
 | 3720 |     SLOW_DCHECK(InNewSpace(clone)); | 
 | 3721 |     // Since we know the clone is allocated in new space, we can copy | 
 | 3722 |     // the contents without worrying about updating the write barrier. | 
 | 3723 |     CopyBlock(clone->address(), source->address(), object_size); | 
 | 3724 |  | 
 | 3725 |     if (site != NULL) { | 
 | 3726 |       AllocationMemento* alloc_memento = reinterpret_cast<AllocationMemento*>( | 
 | 3727 |           reinterpret_cast<Address>(clone) + object_size); | 
 | 3728 |       InitializeAllocationMemento(alloc_memento, site); | 
 | 3729 |     } | 
 | 3730 |   } | 
 | 3731 |  | 
 | 3732 |   SLOW_DCHECK(JSObject::cast(clone)->GetElementsKind() == | 
 | 3733 |               source->GetElementsKind()); | 
 | 3734 |   FixedArrayBase* elements = FixedArrayBase::cast(source->elements()); | 
 | 3735 |   FixedArray* properties = FixedArray::cast(source->properties()); | 
 | 3736 |   // Update elements if necessary. | 
 | 3737 |   if (elements->length() > 0) { | 
 | 3738 |     FixedArrayBase* elem; | 
 | 3739 |     { | 
 | 3740 |       AllocationResult allocation; | 
 | 3741 |       if (elements->map() == fixed_cow_array_map()) { | 
 | 3742 |         allocation = FixedArray::cast(elements); | 
 | 3743 |       } else if (source->HasFastDoubleElements()) { | 
 | 3744 |         allocation = CopyFixedDoubleArray(FixedDoubleArray::cast(elements)); | 
 | 3745 |       } else { | 
 | 3746 |         allocation = CopyFixedArray(FixedArray::cast(elements)); | 
 | 3747 |       } | 
 | 3748 |       if (!allocation.To(&elem)) return allocation; | 
 | 3749 |     } | 
 | 3750 |     JSObject::cast(clone)->set_elements(elem, wb_mode); | 
 | 3751 |   } | 
 | 3752 |   // Update properties if necessary. | 
 | 3753 |   if (properties->length() > 0) { | 
 | 3754 |     FixedArray* prop; | 
 | 3755 |     { | 
 | 3756 |       AllocationResult allocation = CopyFixedArray(properties); | 
 | 3757 |       if (!allocation.To(&prop)) return allocation; | 
 | 3758 |     } | 
 | 3759 |     JSObject::cast(clone)->set_properties(prop, wb_mode); | 
 | 3760 |   } | 
 | 3761 |   // Return the new clone. | 
 | 3762 |   return clone; | 
 | 3763 | } | 
 | 3764 |  | 
 | 3765 |  | 
 | 3766 | static inline void WriteOneByteData(Vector<const char> vector, uint8_t* chars, | 
 | 3767 |                                     int len) { | 
 | 3768 |   // Only works for one byte strings. | 
 | 3769 |   DCHECK(vector.length() == len); | 
 | 3770 |   MemCopy(chars, vector.start(), len); | 
 | 3771 | } | 
 | 3772 |  | 
 | 3773 | static inline void WriteTwoByteData(Vector<const char> vector, uint16_t* chars, | 
 | 3774 |                                     int len) { | 
 | 3775 |   const uint8_t* stream = reinterpret_cast<const uint8_t*>(vector.start()); | 
 | 3776 |   unsigned stream_length = vector.length(); | 
 | 3777 |   while (stream_length != 0) { | 
 | 3778 |     unsigned consumed = 0; | 
 | 3779 |     uint32_t c = unibrow::Utf8::ValueOf(stream, stream_length, &consumed); | 
 | 3780 |     DCHECK(c != unibrow::Utf8::kBadChar); | 
 | 3781 |     DCHECK(consumed <= stream_length); | 
 | 3782 |     stream_length -= consumed; | 
 | 3783 |     stream += consumed; | 
 | 3784 |     if (c > unibrow::Utf16::kMaxNonSurrogateCharCode) { | 
 | 3785 |       len -= 2; | 
 | 3786 |       if (len < 0) break; | 
 | 3787 |       *chars++ = unibrow::Utf16::LeadSurrogate(c); | 
 | 3788 |       *chars++ = unibrow::Utf16::TrailSurrogate(c); | 
 | 3789 |     } else { | 
 | 3790 |       len -= 1; | 
 | 3791 |       if (len < 0) break; | 
 | 3792 |       *chars++ = c; | 
 | 3793 |     } | 
 | 3794 |   } | 
 | 3795 |   DCHECK(stream_length == 0); | 
 | 3796 |   DCHECK(len == 0); | 
 | 3797 | } | 
 | 3798 |  | 
 | 3799 |  | 
 | 3800 | static inline void WriteOneByteData(String* s, uint8_t* chars, int len) { | 
 | 3801 |   DCHECK(s->length() == len); | 
 | 3802 |   String::WriteToFlat(s, chars, 0, len); | 
 | 3803 | } | 
 | 3804 |  | 
 | 3805 |  | 
 | 3806 | static inline void WriteTwoByteData(String* s, uint16_t* chars, int len) { | 
 | 3807 |   DCHECK(s->length() == len); | 
 | 3808 |   String::WriteToFlat(s, chars, 0, len); | 
 | 3809 | } | 
 | 3810 |  | 
 | 3811 |  | 
 | 3812 | template <bool is_one_byte, typename T> | 
 | 3813 | AllocationResult Heap::AllocateInternalizedStringImpl(T t, int chars, | 
 | 3814 |                                                       uint32_t hash_field) { | 
 | 3815 |   DCHECK(chars >= 0); | 
 | 3816 |   // Compute map and object size. | 
 | 3817 |   int size; | 
 | 3818 |   Map* map; | 
 | 3819 |  | 
 | 3820 |   DCHECK_LE(0, chars); | 
 | 3821 |   DCHECK_GE(String::kMaxLength, chars); | 
 | 3822 |   if (is_one_byte) { | 
 | 3823 |     map = one_byte_internalized_string_map(); | 
 | 3824 |     size = SeqOneByteString::SizeFor(chars); | 
 | 3825 |   } else { | 
 | 3826 |     map = internalized_string_map(); | 
 | 3827 |     size = SeqTwoByteString::SizeFor(chars); | 
 | 3828 |   } | 
 | 3829 |   AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, TENURED); | 
 | 3830 |  | 
 | 3831 |   // Allocate string. | 
 | 3832 |   HeapObject* result; | 
 | 3833 |   { | 
 | 3834 |     AllocationResult allocation = AllocateRaw(size, space, OLD_DATA_SPACE); | 
 | 3835 |     if (!allocation.To(&result)) return allocation; | 
 | 3836 |   } | 
 | 3837 |  | 
 | 3838 |   result->set_map_no_write_barrier(map); | 
 | 3839 |   // Set length and hash fields of the allocated string. | 
 | 3840 |   String* answer = String::cast(result); | 
 | 3841 |   answer->set_length(chars); | 
 | 3842 |   answer->set_hash_field(hash_field); | 
 | 3843 |  | 
 | 3844 |   DCHECK_EQ(size, answer->Size()); | 
 | 3845 |  | 
 | 3846 |   if (is_one_byte) { | 
 | 3847 |     WriteOneByteData(t, SeqOneByteString::cast(answer)->GetChars(), chars); | 
 | 3848 |   } else { | 
 | 3849 |     WriteTwoByteData(t, SeqTwoByteString::cast(answer)->GetChars(), chars); | 
 | 3850 |   } | 
 | 3851 |   return answer; | 
 | 3852 | } | 
 | 3853 |  | 
 | 3854 |  | 
 | 3855 | // Need explicit instantiations. | 
 | 3856 | template AllocationResult Heap::AllocateInternalizedStringImpl<true>(String*, | 
 | 3857 |                                                                      int, | 
 | 3858 |                                                                      uint32_t); | 
 | 3859 | template AllocationResult Heap::AllocateInternalizedStringImpl<false>(String*, | 
 | 3860 |                                                                       int, | 
 | 3861 |                                                                       uint32_t); | 
 | 3862 | template AllocationResult Heap::AllocateInternalizedStringImpl<false>( | 
 | 3863 |     Vector<const char>, int, uint32_t); | 
 | 3864 |  | 
 | 3865 |  | 
 | 3866 | AllocationResult Heap::AllocateRawOneByteString(int length, | 
 | 3867 |                                                 PretenureFlag pretenure) { | 
 | 3868 |   DCHECK_LE(0, length); | 
 | 3869 |   DCHECK_GE(String::kMaxLength, length); | 
 | 3870 |   int size = SeqOneByteString::SizeFor(length); | 
 | 3871 |   DCHECK(size <= SeqOneByteString::kMaxSize); | 
 | 3872 |   AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure); | 
 | 3873 |  | 
 | 3874 |   HeapObject* result; | 
 | 3875 |   { | 
 | 3876 |     AllocationResult allocation = AllocateRaw(size, space, OLD_DATA_SPACE); | 
 | 3877 |     if (!allocation.To(&result)) return allocation; | 
 | 3878 |   } | 
 | 3879 |  | 
 | 3880 |   // Partially initialize the object. | 
 | 3881 |   result->set_map_no_write_barrier(one_byte_string_map()); | 
 | 3882 |   String::cast(result)->set_length(length); | 
 | 3883 |   String::cast(result)->set_hash_field(String::kEmptyHashField); | 
 | 3884 |   DCHECK_EQ(size, HeapObject::cast(result)->Size()); | 
 | 3885 |  | 
 | 3886 |   return result; | 
 | 3887 | } | 
 | 3888 |  | 
 | 3889 |  | 
 | 3890 | AllocationResult Heap::AllocateRawTwoByteString(int length, | 
 | 3891 |                                                 PretenureFlag pretenure) { | 
 | 3892 |   DCHECK_LE(0, length); | 
 | 3893 |   DCHECK_GE(String::kMaxLength, length); | 
 | 3894 |   int size = SeqTwoByteString::SizeFor(length); | 
 | 3895 |   DCHECK(size <= SeqTwoByteString::kMaxSize); | 
 | 3896 |   AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure); | 
 | 3897 |  | 
 | 3898 |   HeapObject* result; | 
 | 3899 |   { | 
 | 3900 |     AllocationResult allocation = AllocateRaw(size, space, OLD_DATA_SPACE); | 
 | 3901 |     if (!allocation.To(&result)) return allocation; | 
 | 3902 |   } | 
 | 3903 |  | 
 | 3904 |   // Partially initialize the object. | 
 | 3905 |   result->set_map_no_write_barrier(string_map()); | 
 | 3906 |   String::cast(result)->set_length(length); | 
 | 3907 |   String::cast(result)->set_hash_field(String::kEmptyHashField); | 
 | 3908 |   DCHECK_EQ(size, HeapObject::cast(result)->Size()); | 
 | 3909 |   return result; | 
 | 3910 | } | 
 | 3911 |  | 
 | 3912 |  | 
 | 3913 | AllocationResult Heap::AllocateEmptyFixedArray() { | 
 | 3914 |   int size = FixedArray::SizeFor(0); | 
 | 3915 |   HeapObject* result; | 
 | 3916 |   { | 
 | 3917 |     AllocationResult allocation = | 
 | 3918 |         AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE); | 
 | 3919 |     if (!allocation.To(&result)) return allocation; | 
 | 3920 |   } | 
 | 3921 |   // Initialize the object. | 
 | 3922 |   result->set_map_no_write_barrier(fixed_array_map()); | 
 | 3923 |   FixedArray::cast(result)->set_length(0); | 
 | 3924 |   return result; | 
 | 3925 | } | 
 | 3926 |  | 
 | 3927 |  | 
 | 3928 | AllocationResult Heap::AllocateEmptyExternalArray( | 
 | 3929 |     ExternalArrayType array_type) { | 
 | 3930 |   return AllocateExternalArray(0, array_type, NULL, TENURED); | 
 | 3931 | } | 
 | 3932 |  | 
 | 3933 |  | 
 | 3934 | AllocationResult Heap::CopyAndTenureFixedCOWArray(FixedArray* src) { | 
 | 3935 |   if (!InNewSpace(src)) { | 
 | 3936 |     return src; | 
 | 3937 |   } | 
 | 3938 |  | 
 | 3939 |   int len = src->length(); | 
 | 3940 |   HeapObject* obj; | 
 | 3941 |   { | 
 | 3942 |     AllocationResult allocation = AllocateRawFixedArray(len, TENURED); | 
 | 3943 |     if (!allocation.To(&obj)) return allocation; | 
 | 3944 |   } | 
 | 3945 |   obj->set_map_no_write_barrier(fixed_array_map()); | 
 | 3946 |   FixedArray* result = FixedArray::cast(obj); | 
 | 3947 |   result->set_length(len); | 
 | 3948 |  | 
 | 3949 |   // Copy the content | 
 | 3950 |   DisallowHeapAllocation no_gc; | 
 | 3951 |   WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); | 
 | 3952 |   for (int i = 0; i < len; i++) result->set(i, src->get(i), mode); | 
 | 3953 |  | 
 | 3954 |   // TODO(mvstanton): The map is set twice because of protection against calling | 
 | 3955 |   // set() on a COW FixedArray. Issue v8:3221 created to track this, and | 
 | 3956 |   // we might then be able to remove this whole method. | 
 | 3957 |   HeapObject::cast(obj)->set_map_no_write_barrier(fixed_cow_array_map()); | 
 | 3958 |   return result; | 
 | 3959 | } | 
 | 3960 |  | 
 | 3961 |  | 
 | 3962 | AllocationResult Heap::AllocateEmptyFixedTypedArray( | 
 | 3963 |     ExternalArrayType array_type) { | 
 | 3964 |   return AllocateFixedTypedArray(0, array_type, TENURED); | 
 | 3965 | } | 
 | 3966 |  | 
 | 3967 |  | 
 | 3968 | AllocationResult Heap::CopyFixedArrayWithMap(FixedArray* src, Map* map) { | 
 | 3969 |   int len = src->length(); | 
 | 3970 |   HeapObject* obj; | 
 | 3971 |   { | 
 | 3972 |     AllocationResult allocation = AllocateRawFixedArray(len, NOT_TENURED); | 
 | 3973 |     if (!allocation.To(&obj)) return allocation; | 
 | 3974 |   } | 
 | 3975 |   if (InNewSpace(obj)) { | 
 | 3976 |     obj->set_map_no_write_barrier(map); | 
 | 3977 |     CopyBlock(obj->address() + kPointerSize, src->address() + kPointerSize, | 
 | 3978 |               FixedArray::SizeFor(len) - kPointerSize); | 
 | 3979 |     return obj; | 
 | 3980 |   } | 
 | 3981 |   obj->set_map_no_write_barrier(map); | 
 | 3982 |   FixedArray* result = FixedArray::cast(obj); | 
 | 3983 |   result->set_length(len); | 
 | 3984 |  | 
 | 3985 |   // Copy the content | 
 | 3986 |   DisallowHeapAllocation no_gc; | 
 | 3987 |   WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); | 
 | 3988 |   for (int i = 0; i < len; i++) result->set(i, src->get(i), mode); | 
 | 3989 |   return result; | 
 | 3990 | } | 
 | 3991 |  | 
 | 3992 |  | 
 | 3993 | AllocationResult Heap::CopyFixedDoubleArrayWithMap(FixedDoubleArray* src, | 
 | 3994 |                                                    Map* map) { | 
 | 3995 |   int len = src->length(); | 
 | 3996 |   HeapObject* obj; | 
 | 3997 |   { | 
 | 3998 |     AllocationResult allocation = AllocateRawFixedDoubleArray(len, NOT_TENURED); | 
 | 3999 |     if (!allocation.To(&obj)) return allocation; | 
 | 4000 |   } | 
 | 4001 |   obj->set_map_no_write_barrier(map); | 
 | 4002 |   CopyBlock(obj->address() + FixedDoubleArray::kLengthOffset, | 
 | 4003 |             src->address() + FixedDoubleArray::kLengthOffset, | 
 | 4004 |             FixedDoubleArray::SizeFor(len) - FixedDoubleArray::kLengthOffset); | 
 | 4005 |   return obj; | 
 | 4006 | } | 
 | 4007 |  | 
 | 4008 |  | 
 | 4009 | AllocationResult Heap::CopyConstantPoolArrayWithMap(ConstantPoolArray* src, | 
 | 4010 |                                                     Map* map) { | 
 | 4011 |   HeapObject* obj; | 
 | 4012 |   if (src->is_extended_layout()) { | 
 | 4013 |     ConstantPoolArray::NumberOfEntries small(src, | 
 | 4014 |                                              ConstantPoolArray::SMALL_SECTION); | 
 | 4015 |     ConstantPoolArray::NumberOfEntries extended( | 
 | 4016 |         src, ConstantPoolArray::EXTENDED_SECTION); | 
 | 4017 |     AllocationResult allocation = | 
 | 4018 |         AllocateExtendedConstantPoolArray(small, extended); | 
 | 4019 |     if (!allocation.To(&obj)) return allocation; | 
 | 4020 |   } else { | 
 | 4021 |     ConstantPoolArray::NumberOfEntries small(src, | 
 | 4022 |                                              ConstantPoolArray::SMALL_SECTION); | 
 | 4023 |     AllocationResult allocation = AllocateConstantPoolArray(small); | 
 | 4024 |     if (!allocation.To(&obj)) return allocation; | 
 | 4025 |   } | 
 | 4026 |   obj->set_map_no_write_barrier(map); | 
 | 4027 |   CopyBlock(obj->address() + ConstantPoolArray::kFirstEntryOffset, | 
 | 4028 |             src->address() + ConstantPoolArray::kFirstEntryOffset, | 
 | 4029 |             src->size() - ConstantPoolArray::kFirstEntryOffset); | 
 | 4030 |   return obj; | 
 | 4031 | } | 
 | 4032 |  | 
 | 4033 |  | 
 | 4034 | AllocationResult Heap::AllocateRawFixedArray(int length, | 
 | 4035 |                                              PretenureFlag pretenure) { | 
 | 4036 |   if (length < 0 || length > FixedArray::kMaxLength) { | 
 | 4037 |     v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", true); | 
 | 4038 |   } | 
 | 4039 |   int size = FixedArray::SizeFor(length); | 
 | 4040 |   AllocationSpace space = SelectSpace(size, OLD_POINTER_SPACE, pretenure); | 
 | 4041 |  | 
 | 4042 |   return AllocateRaw(size, space, OLD_POINTER_SPACE); | 
 | 4043 | } | 
 | 4044 |  | 
 | 4045 |  | 
 | 4046 | AllocationResult Heap::AllocateFixedArrayWithFiller(int length, | 
 | 4047 |                                                     PretenureFlag pretenure, | 
 | 4048 |                                                     Object* filler) { | 
 | 4049 |   DCHECK(length >= 0); | 
 | 4050 |   DCHECK(empty_fixed_array()->IsFixedArray()); | 
 | 4051 |   if (length == 0) return empty_fixed_array(); | 
 | 4052 |  | 
 | 4053 |   DCHECK(!InNewSpace(filler)); | 
 | 4054 |   HeapObject* result; | 
 | 4055 |   { | 
 | 4056 |     AllocationResult allocation = AllocateRawFixedArray(length, pretenure); | 
 | 4057 |     if (!allocation.To(&result)) return allocation; | 
 | 4058 |   } | 
 | 4059 |  | 
 | 4060 |   result->set_map_no_write_barrier(fixed_array_map()); | 
 | 4061 |   FixedArray* array = FixedArray::cast(result); | 
 | 4062 |   array->set_length(length); | 
 | 4063 |   MemsetPointer(array->data_start(), filler, length); | 
 | 4064 |   return array; | 
 | 4065 | } | 
 | 4066 |  | 
 | 4067 |  | 
 | 4068 | AllocationResult Heap::AllocateFixedArray(int length, PretenureFlag pretenure) { | 
 | 4069 |   return AllocateFixedArrayWithFiller(length, pretenure, undefined_value()); | 
 | 4070 | } | 
 | 4071 |  | 
 | 4072 |  | 
 | 4073 | AllocationResult Heap::AllocateUninitializedFixedArray(int length) { | 
 | 4074 |   if (length == 0) return empty_fixed_array(); | 
 | 4075 |  | 
 | 4076 |   HeapObject* obj; | 
 | 4077 |   { | 
 | 4078 |     AllocationResult allocation = AllocateRawFixedArray(length, NOT_TENURED); | 
 | 4079 |     if (!allocation.To(&obj)) return allocation; | 
 | 4080 |   } | 
 | 4081 |  | 
 | 4082 |   obj->set_map_no_write_barrier(fixed_array_map()); | 
 | 4083 |   FixedArray::cast(obj)->set_length(length); | 
 | 4084 |   return obj; | 
 | 4085 | } | 
 | 4086 |  | 
 | 4087 |  | 
 | 4088 | AllocationResult Heap::AllocateUninitializedFixedDoubleArray( | 
 | 4089 |     int length, PretenureFlag pretenure) { | 
 | 4090 |   if (length == 0) return empty_fixed_array(); | 
 | 4091 |  | 
 | 4092 |   HeapObject* elements; | 
 | 4093 |   AllocationResult allocation = AllocateRawFixedDoubleArray(length, pretenure); | 
 | 4094 |   if (!allocation.To(&elements)) return allocation; | 
 | 4095 |  | 
 | 4096 |   elements->set_map_no_write_barrier(fixed_double_array_map()); | 
 | 4097 |   FixedDoubleArray::cast(elements)->set_length(length); | 
 | 4098 |   return elements; | 
 | 4099 | } | 
 | 4100 |  | 
 | 4101 |  | 
 | 4102 | AllocationResult Heap::AllocateRawFixedDoubleArray(int length, | 
 | 4103 |                                                    PretenureFlag pretenure) { | 
 | 4104 |   if (length < 0 || length > FixedDoubleArray::kMaxLength) { | 
 | 4105 |     v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", true); | 
 | 4106 |   } | 
 | 4107 |   int size = FixedDoubleArray::SizeFor(length); | 
 | 4108 | #ifndef V8_HOST_ARCH_64_BIT | 
 | 4109 |   size += kPointerSize; | 
 | 4110 | #endif | 
 | 4111 |   AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure); | 
 | 4112 |  | 
 | 4113 |   HeapObject* object; | 
 | 4114 |   { | 
 | 4115 |     AllocationResult allocation = AllocateRaw(size, space, OLD_DATA_SPACE); | 
 | 4116 |     if (!allocation.To(&object)) return allocation; | 
 | 4117 |   } | 
 | 4118 |  | 
 | 4119 |   return EnsureDoubleAligned(this, object, size); | 
 | 4120 | } | 
 | 4121 |  | 
 | 4122 |  | 
 | 4123 | AllocationResult Heap::AllocateConstantPoolArray( | 
 | 4124 |     const ConstantPoolArray::NumberOfEntries& small) { | 
 | 4125 |   CHECK(small.are_in_range(0, ConstantPoolArray::kMaxSmallEntriesPerType)); | 
 | 4126 |   int size = ConstantPoolArray::SizeFor(small); | 
 | 4127 | #ifndef V8_HOST_ARCH_64_BIT | 
 | 4128 |   size += kPointerSize; | 
 | 4129 | #endif | 
 | 4130 |   AllocationSpace space = SelectSpace(size, OLD_POINTER_SPACE, TENURED); | 
 | 4131 |  | 
 | 4132 |   HeapObject* object; | 
 | 4133 |   { | 
 | 4134 |     AllocationResult allocation = AllocateRaw(size, space, OLD_POINTER_SPACE); | 
 | 4135 |     if (!allocation.To(&object)) return allocation; | 
 | 4136 |   } | 
 | 4137 |   object = EnsureDoubleAligned(this, object, size); | 
 | 4138 |   object->set_map_no_write_barrier(constant_pool_array_map()); | 
 | 4139 |  | 
 | 4140 |   ConstantPoolArray* constant_pool = ConstantPoolArray::cast(object); | 
 | 4141 |   constant_pool->Init(small); | 
 | 4142 |   constant_pool->ClearPtrEntries(isolate()); | 
 | 4143 |   return constant_pool; | 
 | 4144 | } | 
 | 4145 |  | 
 | 4146 |  | 
 | 4147 | AllocationResult Heap::AllocateExtendedConstantPoolArray( | 
 | 4148 |     const ConstantPoolArray::NumberOfEntries& small, | 
 | 4149 |     const ConstantPoolArray::NumberOfEntries& extended) { | 
 | 4150 |   CHECK(small.are_in_range(0, ConstantPoolArray::kMaxSmallEntriesPerType)); | 
 | 4151 |   CHECK(extended.are_in_range(0, kMaxInt)); | 
 | 4152 |   int size = ConstantPoolArray::SizeForExtended(small, extended); | 
 | 4153 | #ifndef V8_HOST_ARCH_64_BIT | 
 | 4154 |   size += kPointerSize; | 
 | 4155 | #endif | 
 | 4156 |   AllocationSpace space = SelectSpace(size, OLD_POINTER_SPACE, TENURED); | 
 | 4157 |  | 
 | 4158 |   HeapObject* object; | 
 | 4159 |   { | 
 | 4160 |     AllocationResult allocation = AllocateRaw(size, space, OLD_POINTER_SPACE); | 
 | 4161 |     if (!allocation.To(&object)) return allocation; | 
 | 4162 |   } | 
 | 4163 |   object = EnsureDoubleAligned(this, object, size); | 
 | 4164 |   object->set_map_no_write_barrier(constant_pool_array_map()); | 
 | 4165 |  | 
 | 4166 |   ConstantPoolArray* constant_pool = ConstantPoolArray::cast(object); | 
 | 4167 |   constant_pool->InitExtended(small, extended); | 
 | 4168 |   constant_pool->ClearPtrEntries(isolate()); | 
 | 4169 |   return constant_pool; | 
 | 4170 | } | 
 | 4171 |  | 
 | 4172 |  | 
 | 4173 | AllocationResult Heap::AllocateEmptyConstantPoolArray() { | 
 | 4174 |   ConstantPoolArray::NumberOfEntries small(0, 0, 0, 0); | 
 | 4175 |   int size = ConstantPoolArray::SizeFor(small); | 
 | 4176 |   HeapObject* result; | 
 | 4177 |   { | 
 | 4178 |     AllocationResult allocation = | 
 | 4179 |         AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE); | 
 | 4180 |     if (!allocation.To(&result)) return allocation; | 
 | 4181 |   } | 
 | 4182 |   result->set_map_no_write_barrier(constant_pool_array_map()); | 
 | 4183 |   ConstantPoolArray::cast(result)->Init(small); | 
 | 4184 |   return result; | 
 | 4185 | } | 
 | 4186 |  | 
 | 4187 |  | 
 | 4188 | AllocationResult Heap::AllocateSymbol() { | 
 | 4189 |   // Statically ensure that it is safe to allocate symbols in paged spaces. | 
 | 4190 |   STATIC_ASSERT(Symbol::kSize <= Page::kMaxRegularHeapObjectSize); | 
 | 4191 |  | 
 | 4192 |   HeapObject* result; | 
 | 4193 |   AllocationResult allocation = | 
 | 4194 |       AllocateRaw(Symbol::kSize, OLD_POINTER_SPACE, OLD_POINTER_SPACE); | 
 | 4195 |   if (!allocation.To(&result)) return allocation; | 
 | 4196 |  | 
 | 4197 |   result->set_map_no_write_barrier(symbol_map()); | 
 | 4198 |  | 
 | 4199 |   // Generate a random hash value. | 
 | 4200 |   int hash; | 
 | 4201 |   int attempts = 0; | 
 | 4202 |   do { | 
 | 4203 |     hash = isolate()->random_number_generator()->NextInt() & Name::kHashBitMask; | 
 | 4204 |     attempts++; | 
 | 4205 |   } while (hash == 0 && attempts < 30); | 
 | 4206 |   if (hash == 0) hash = 1;  // never return 0 | 
 | 4207 |  | 
 | 4208 |   Symbol::cast(result) | 
 | 4209 |       ->set_hash_field(Name::kIsNotArrayIndexMask | (hash << Name::kHashShift)); | 
 | 4210 |   Symbol::cast(result)->set_name(undefined_value()); | 
 | 4211 |   Symbol::cast(result)->set_flags(Smi::FromInt(0)); | 
 | 4212 |  | 
 | 4213 |   DCHECK(!Symbol::cast(result)->is_private()); | 
 | 4214 |   return result; | 
 | 4215 | } | 
 | 4216 |  | 
 | 4217 |  | 
 | 4218 | AllocationResult Heap::AllocateStruct(InstanceType type) { | 
 | 4219 |   Map* map; | 
 | 4220 |   switch (type) { | 
 | 4221 | #define MAKE_CASE(NAME, Name, name) \ | 
 | 4222 |   case NAME##_TYPE:                 \ | 
 | 4223 |     map = name##_map();             \ | 
 | 4224 |     break; | 
 | 4225 |     STRUCT_LIST(MAKE_CASE) | 
 | 4226 | #undef MAKE_CASE | 
 | 4227 |     default: | 
 | 4228 |       UNREACHABLE(); | 
 | 4229 |       return exception(); | 
 | 4230 |   } | 
 | 4231 |   int size = map->instance_size(); | 
 | 4232 |   AllocationSpace space = SelectSpace(size, OLD_POINTER_SPACE, TENURED); | 
 | 4233 |   Struct* result; | 
 | 4234 |   { | 
 | 4235 |     AllocationResult allocation = Allocate(map, space); | 
 | 4236 |     if (!allocation.To(&result)) return allocation; | 
 | 4237 |   } | 
 | 4238 |   result->InitializeBody(size); | 
 | 4239 |   return result; | 
 | 4240 | } | 
 | 4241 |  | 
 | 4242 |  | 
 | 4243 | bool Heap::IsHeapIterable() { | 
 | 4244 |   // TODO(hpayer): This function is not correct. Allocation folding in old | 
 | 4245 |   // space breaks the iterability. | 
 | 4246 |   return new_space_top_after_last_gc_ == new_space()->top(); | 
 | 4247 | } | 
 | 4248 |  | 
 | 4249 |  | 
 | 4250 | void Heap::MakeHeapIterable() { | 
 | 4251 |   DCHECK(AllowHeapAllocation::IsAllowed()); | 
 | 4252 |   if (!IsHeapIterable()) { | 
 | 4253 |     CollectAllGarbage(kMakeHeapIterableMask, "Heap::MakeHeapIterable"); | 
 | 4254 |   } | 
 | 4255 |   if (mark_compact_collector()->sweeping_in_progress()) { | 
 | 4256 |     mark_compact_collector()->EnsureSweepingCompleted(); | 
 | 4257 |   } | 
 | 4258 |   DCHECK(IsHeapIterable()); | 
 | 4259 | } | 
 | 4260 |  | 
 | 4261 |  | 
 | 4262 | void Heap::IdleMarkCompact(const char* message) { | 
 | 4263 |   bool uncommit = false; | 
 | 4264 |   if (gc_count_at_last_idle_gc_ == gc_count_) { | 
 | 4265 |     // No GC since the last full GC, the mutator is probably not active. | 
 | 4266 |     isolate_->compilation_cache()->Clear(); | 
 | 4267 |     uncommit = true; | 
 | 4268 |   } | 
 | 4269 |   CollectAllGarbage(kReduceMemoryFootprintMask, message); | 
 | 4270 |   gc_idle_time_handler_.NotifyIdleMarkCompact(); | 
 | 4271 |   gc_count_at_last_idle_gc_ = gc_count_; | 
 | 4272 |   if (uncommit) { | 
 | 4273 |     new_space_.Shrink(); | 
 | 4274 |     UncommitFromSpace(); | 
 | 4275 |   } | 
 | 4276 | } | 
 | 4277 |  | 
 | 4278 |  | 
 | 4279 | void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) { | 
 | 4280 |   incremental_marking()->Step(step_size, | 
 | 4281 |                               IncrementalMarking::NO_GC_VIA_STACK_GUARD, true); | 
 | 4282 |  | 
 | 4283 |   if (incremental_marking()->IsComplete()) { | 
 | 4284 |     IdleMarkCompact("idle notification: finalize incremental"); | 
 | 4285 |   } | 
 | 4286 | } | 
 | 4287 |  | 
 | 4288 |  | 
 | 4289 | bool Heap::WorthActivatingIncrementalMarking() { | 
 | 4290 |   return incremental_marking()->IsStopped() && | 
 | 4291 |          incremental_marking()->WorthActivating() && NextGCIsLikelyToBeFull(); | 
 | 4292 | } | 
 | 4293 |  | 
 | 4294 |  | 
 | 4295 | bool Heap::IdleNotification(int idle_time_in_ms) { | 
 | 4296 |   // If incremental marking is off, we do not perform idle notification. | 
 | 4297 |   if (!FLAG_incremental_marking) return true; | 
 | 4298 |   base::ElapsedTimer timer; | 
 | 4299 |   timer.Start(); | 
 | 4300 |   isolate()->counters()->gc_idle_time_allotted_in_ms()->AddSample( | 
 | 4301 |       idle_time_in_ms); | 
 | 4302 |   HistogramTimerScope idle_notification_scope( | 
 | 4303 |       isolate_->counters()->gc_idle_notification()); | 
 | 4304 |  | 
 | 4305 |   GCIdleTimeHandler::HeapState heap_state; | 
 | 4306 |   heap_state.contexts_disposed = contexts_disposed_; | 
 | 4307 |   heap_state.size_of_objects = static_cast<size_t>(SizeOfObjects()); | 
 | 4308 |   heap_state.incremental_marking_stopped = incremental_marking()->IsStopped(); | 
 | 4309 |   // TODO(ulan): Start incremental marking only for large heaps. | 
 | 4310 |   heap_state.can_start_incremental_marking = | 
 | 4311 |       incremental_marking()->ShouldActivate(); | 
 | 4312 |   heap_state.sweeping_in_progress = | 
 | 4313 |       mark_compact_collector()->sweeping_in_progress(); | 
 | 4314 |   heap_state.mark_compact_speed_in_bytes_per_ms = | 
 | 4315 |       static_cast<size_t>(tracer()->MarkCompactSpeedInBytesPerMillisecond()); | 
 | 4316 |   heap_state.incremental_marking_speed_in_bytes_per_ms = static_cast<size_t>( | 
 | 4317 |       tracer()->IncrementalMarkingSpeedInBytesPerMillisecond()); | 
 | 4318 |   heap_state.scavenge_speed_in_bytes_per_ms = | 
 | 4319 |       static_cast<size_t>(tracer()->ScavengeSpeedInBytesPerMillisecond()); | 
 | 4320 |   heap_state.available_new_space_memory = new_space_.Available(); | 
 | 4321 |   heap_state.new_space_capacity = new_space_.Capacity(); | 
 | 4322 |   heap_state.new_space_allocation_throughput_in_bytes_per_ms = | 
 | 4323 |       static_cast<size_t>( | 
 | 4324 |           tracer()->NewSpaceAllocationThroughputInBytesPerMillisecond()); | 
 | 4325 |  | 
 | 4326 |   GCIdleTimeAction action = | 
 | 4327 |       gc_idle_time_handler_.Compute(idle_time_in_ms, heap_state); | 
 | 4328 |  | 
 | 4329 |   bool result = false; | 
 | 4330 |   switch (action.type) { | 
 | 4331 |     case DONE: | 
 | 4332 |       result = true; | 
 | 4333 |       break; | 
 | 4334 |     case DO_INCREMENTAL_MARKING: | 
 | 4335 |       if (incremental_marking()->IsStopped()) { | 
 | 4336 |         incremental_marking()->Start(); | 
 | 4337 |       } | 
 | 4338 |       AdvanceIdleIncrementalMarking(action.parameter); | 
 | 4339 |       break; | 
 | 4340 |     case DO_FULL_GC: { | 
 | 4341 |       HistogramTimerScope scope(isolate_->counters()->gc_context()); | 
 | 4342 |       if (contexts_disposed_) { | 
 | 4343 |         CollectAllGarbage(kReduceMemoryFootprintMask, | 
 | 4344 |                           "idle notification: contexts disposed"); | 
 | 4345 |         gc_idle_time_handler_.NotifyIdleMarkCompact(); | 
 | 4346 |         gc_count_at_last_idle_gc_ = gc_count_; | 
 | 4347 |       } else { | 
 | 4348 |         IdleMarkCompact("idle notification: finalize idle round"); | 
 | 4349 |       } | 
 | 4350 |       break; | 
 | 4351 |     } | 
 | 4352 |     case DO_SCAVENGE: | 
 | 4353 |       CollectGarbage(NEW_SPACE, "idle notification: scavenge"); | 
 | 4354 |       break; | 
 | 4355 |     case DO_FINALIZE_SWEEPING: | 
 | 4356 |       mark_compact_collector()->EnsureSweepingCompleted(); | 
 | 4357 |       break; | 
 | 4358 |     case DO_NOTHING: | 
 | 4359 |       break; | 
 | 4360 |   } | 
 | 4361 |  | 
 | 4362 |   int actual_time_ms = static_cast<int>(timer.Elapsed().InMilliseconds()); | 
 | 4363 |   if (actual_time_ms <= idle_time_in_ms) { | 
 | 4364 |     isolate()->counters()->gc_idle_time_limit_undershot()->AddSample( | 
 | 4365 |         idle_time_in_ms - actual_time_ms); | 
 | 4366 |   } else { | 
 | 4367 |     isolate()->counters()->gc_idle_time_limit_overshot()->AddSample( | 
 | 4368 |         actual_time_ms - idle_time_in_ms); | 
 | 4369 |   } | 
 | 4370 |  | 
 | 4371 |   if (FLAG_trace_idle_notification) { | 
 | 4372 |     PrintF("Idle notification: requested idle time %d ms, actual time %d ms [", | 
 | 4373 |            idle_time_in_ms, actual_time_ms); | 
 | 4374 |     action.Print(); | 
 | 4375 |     PrintF("]\n"); | 
 | 4376 |   } | 
 | 4377 |  | 
 | 4378 |   contexts_disposed_ = 0; | 
 | 4379 |   return result; | 
 | 4380 | } | 
 | 4381 |  | 
 | 4382 |  | 
 | 4383 | #ifdef DEBUG | 
 | 4384 |  | 
 | 4385 | void Heap::Print() { | 
 | 4386 |   if (!HasBeenSetUp()) return; | 
 | 4387 |   isolate()->PrintStack(stdout); | 
 | 4388 |   AllSpaces spaces(this); | 
 | 4389 |   for (Space* space = spaces.next(); space != NULL; space = spaces.next()) { | 
 | 4390 |     space->Print(); | 
 | 4391 |   } | 
 | 4392 | } | 
 | 4393 |  | 
 | 4394 |  | 
 | 4395 | void Heap::ReportCodeStatistics(const char* title) { | 
 | 4396 |   PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title); | 
 | 4397 |   PagedSpace::ResetCodeStatistics(isolate()); | 
 | 4398 |   // We do not look for code in new space, map space, or old space.  If code | 
 | 4399 |   // somehow ends up in those spaces, we would miss it here. | 
 | 4400 |   code_space_->CollectCodeStatistics(); | 
 | 4401 |   lo_space_->CollectCodeStatistics(); | 
 | 4402 |   PagedSpace::ReportCodeStatistics(isolate()); | 
 | 4403 | } | 
 | 4404 |  | 
 | 4405 |  | 
 | 4406 | // This function expects that NewSpace's allocated objects histogram is | 
 | 4407 | // populated (via a call to CollectStatistics or else as a side effect of a | 
 | 4408 | // just-completed scavenge collection). | 
 | 4409 | void Heap::ReportHeapStatistics(const char* title) { | 
 | 4410 |   USE(title); | 
 | 4411 |   PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n", title, | 
 | 4412 |          gc_count_); | 
 | 4413 |   PrintF("old_generation_allocation_limit_ %" V8_PTR_PREFIX "d\n", | 
 | 4414 |          old_generation_allocation_limit_); | 
 | 4415 |  | 
 | 4416 |   PrintF("\n"); | 
 | 4417 |   PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles(isolate_)); | 
 | 4418 |   isolate_->global_handles()->PrintStats(); | 
 | 4419 |   PrintF("\n"); | 
 | 4420 |  | 
 | 4421 |   PrintF("Heap statistics : "); | 
 | 4422 |   isolate_->memory_allocator()->ReportStatistics(); | 
 | 4423 |   PrintF("To space : "); | 
 | 4424 |   new_space_.ReportStatistics(); | 
 | 4425 |   PrintF("Old pointer space : "); | 
 | 4426 |   old_pointer_space_->ReportStatistics(); | 
 | 4427 |   PrintF("Old data space : "); | 
 | 4428 |   old_data_space_->ReportStatistics(); | 
 | 4429 |   PrintF("Code space : "); | 
 | 4430 |   code_space_->ReportStatistics(); | 
 | 4431 |   PrintF("Map space : "); | 
 | 4432 |   map_space_->ReportStatistics(); | 
 | 4433 |   PrintF("Cell space : "); | 
 | 4434 |   cell_space_->ReportStatistics(); | 
 | 4435 |   PrintF("PropertyCell space : "); | 
 | 4436 |   property_cell_space_->ReportStatistics(); | 
 | 4437 |   PrintF("Large object space : "); | 
 | 4438 |   lo_space_->ReportStatistics(); | 
 | 4439 |   PrintF(">>>>>> ========================================= >>>>>>\n"); | 
 | 4440 | } | 
 | 4441 |  | 
 | 4442 | #endif  // DEBUG | 
 | 4443 |  | 
 | 4444 | bool Heap::Contains(HeapObject* value) { return Contains(value->address()); } | 
 | 4445 |  | 
 | 4446 |  | 
 | 4447 | bool Heap::Contains(Address addr) { | 
 | 4448 |   if (isolate_->memory_allocator()->IsOutsideAllocatedSpace(addr)) return false; | 
 | 4449 |   return HasBeenSetUp() && | 
 | 4450 |          (new_space_.ToSpaceContains(addr) || | 
 | 4451 |           old_pointer_space_->Contains(addr) || | 
 | 4452 |           old_data_space_->Contains(addr) || code_space_->Contains(addr) || | 
 | 4453 |           map_space_->Contains(addr) || cell_space_->Contains(addr) || | 
 | 4454 |           property_cell_space_->Contains(addr) || | 
 | 4455 |           lo_space_->SlowContains(addr)); | 
 | 4456 | } | 
 | 4457 |  | 
 | 4458 |  | 
 | 4459 | bool Heap::InSpace(HeapObject* value, AllocationSpace space) { | 
 | 4460 |   return InSpace(value->address(), space); | 
 | 4461 | } | 
 | 4462 |  | 
 | 4463 |  | 
 | 4464 | bool Heap::InSpace(Address addr, AllocationSpace space) { | 
 | 4465 |   if (isolate_->memory_allocator()->IsOutsideAllocatedSpace(addr)) return false; | 
 | 4466 |   if (!HasBeenSetUp()) return false; | 
 | 4467 |  | 
 | 4468 |   switch (space) { | 
 | 4469 |     case NEW_SPACE: | 
 | 4470 |       return new_space_.ToSpaceContains(addr); | 
 | 4471 |     case OLD_POINTER_SPACE: | 
 | 4472 |       return old_pointer_space_->Contains(addr); | 
 | 4473 |     case OLD_DATA_SPACE: | 
 | 4474 |       return old_data_space_->Contains(addr); | 
 | 4475 |     case CODE_SPACE: | 
 | 4476 |       return code_space_->Contains(addr); | 
 | 4477 |     case MAP_SPACE: | 
 | 4478 |       return map_space_->Contains(addr); | 
 | 4479 |     case CELL_SPACE: | 
 | 4480 |       return cell_space_->Contains(addr); | 
 | 4481 |     case PROPERTY_CELL_SPACE: | 
 | 4482 |       return property_cell_space_->Contains(addr); | 
 | 4483 |     case LO_SPACE: | 
 | 4484 |       return lo_space_->SlowContains(addr); | 
 | 4485 |     case INVALID_SPACE: | 
 | 4486 |       break; | 
 | 4487 |   } | 
 | 4488 |   UNREACHABLE(); | 
 | 4489 |   return false; | 
 | 4490 | } | 
 | 4491 |  | 
 | 4492 |  | 
 | 4493 | #ifdef VERIFY_HEAP | 
 | 4494 | void Heap::Verify() { | 
 | 4495 |   CHECK(HasBeenSetUp()); | 
 | 4496 |   HandleScope scope(isolate()); | 
 | 4497 |  | 
 | 4498 |   store_buffer()->Verify(); | 
 | 4499 |  | 
 | 4500 |   if (mark_compact_collector()->sweeping_in_progress()) { | 
 | 4501 |     // We have to wait here for the sweeper threads to have an iterable heap. | 
 | 4502 |     mark_compact_collector()->EnsureSweepingCompleted(); | 
 | 4503 |   } | 
 | 4504 |  | 
 | 4505 |   VerifyPointersVisitor visitor; | 
 | 4506 |   IterateRoots(&visitor, VISIT_ONLY_STRONG); | 
 | 4507 |  | 
 | 4508 |   VerifySmisVisitor smis_visitor; | 
 | 4509 |   IterateSmiRoots(&smis_visitor); | 
 | 4510 |  | 
 | 4511 |   new_space_.Verify(); | 
 | 4512 |  | 
 | 4513 |   old_pointer_space_->Verify(&visitor); | 
 | 4514 |   map_space_->Verify(&visitor); | 
 | 4515 |  | 
 | 4516 |   VerifyPointersVisitor no_dirty_regions_visitor; | 
 | 4517 |   old_data_space_->Verify(&no_dirty_regions_visitor); | 
 | 4518 |   code_space_->Verify(&no_dirty_regions_visitor); | 
 | 4519 |   cell_space_->Verify(&no_dirty_regions_visitor); | 
 | 4520 |   property_cell_space_->Verify(&no_dirty_regions_visitor); | 
 | 4521 |  | 
 | 4522 |   lo_space_->Verify(); | 
 | 4523 | } | 
 | 4524 | #endif | 
 | 4525 |  | 
 | 4526 |  | 
 | 4527 | void Heap::ZapFromSpace() { | 
 | 4528 |   NewSpacePageIterator it(new_space_.FromSpaceStart(), | 
 | 4529 |                           new_space_.FromSpaceEnd()); | 
 | 4530 |   while (it.has_next()) { | 
 | 4531 |     NewSpacePage* page = it.next(); | 
 | 4532 |     for (Address cursor = page->area_start(), limit = page->area_end(); | 
 | 4533 |          cursor < limit; cursor += kPointerSize) { | 
 | 4534 |       Memory::Address_at(cursor) = kFromSpaceZapValue; | 
 | 4535 |     } | 
 | 4536 |   } | 
 | 4537 | } | 
 | 4538 |  | 
 | 4539 |  | 
 | 4540 | void Heap::IterateAndMarkPointersToFromSpace(Address start, Address end, | 
 | 4541 |                                              ObjectSlotCallback callback) { | 
 | 4542 |   Address slot_address = start; | 
 | 4543 |  | 
 | 4544 |   // We are not collecting slots on new space objects during mutation | 
 | 4545 |   // thus we have to scan for pointers to evacuation candidates when we | 
 | 4546 |   // promote objects. But we should not record any slots in non-black | 
 | 4547 |   // objects. Grey object's slots would be rescanned. | 
 | 4548 |   // White object might not survive until the end of collection | 
 | 4549 |   // it would be a violation of the invariant to record it's slots. | 
 | 4550 |   bool record_slots = false; | 
 | 4551 |   if (incremental_marking()->IsCompacting()) { | 
 | 4552 |     MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::FromAddress(start)); | 
 | 4553 |     record_slots = Marking::IsBlack(mark_bit); | 
 | 4554 |   } | 
 | 4555 |  | 
 | 4556 |   while (slot_address < end) { | 
 | 4557 |     Object** slot = reinterpret_cast<Object**>(slot_address); | 
 | 4558 |     Object* object = *slot; | 
 | 4559 |     // If the store buffer becomes overfull we mark pages as being exempt from | 
 | 4560 |     // the store buffer.  These pages are scanned to find pointers that point | 
 | 4561 |     // to the new space.  In that case we may hit newly promoted objects and | 
 | 4562 |     // fix the pointers before the promotion queue gets to them.  Thus the 'if'. | 
 | 4563 |     if (object->IsHeapObject()) { | 
 | 4564 |       if (Heap::InFromSpace(object)) { | 
 | 4565 |         callback(reinterpret_cast<HeapObject**>(slot), | 
 | 4566 |                  HeapObject::cast(object)); | 
 | 4567 |         Object* new_object = *slot; | 
 | 4568 |         if (InNewSpace(new_object)) { | 
 | 4569 |           SLOW_DCHECK(Heap::InToSpace(new_object)); | 
 | 4570 |           SLOW_DCHECK(new_object->IsHeapObject()); | 
 | 4571 |           store_buffer_.EnterDirectlyIntoStoreBuffer( | 
 | 4572 |               reinterpret_cast<Address>(slot)); | 
 | 4573 |         } | 
 | 4574 |         SLOW_DCHECK(!MarkCompactCollector::IsOnEvacuationCandidate(new_object)); | 
 | 4575 |       } else if (record_slots && | 
 | 4576 |                  MarkCompactCollector::IsOnEvacuationCandidate(object)) { | 
 | 4577 |         mark_compact_collector()->RecordSlot(slot, slot, object); | 
 | 4578 |       } | 
 | 4579 |     } | 
 | 4580 |     slot_address += kPointerSize; | 
 | 4581 |   } | 
 | 4582 | } | 
 | 4583 |  | 
 | 4584 |  | 
 | 4585 | #ifdef DEBUG | 
 | 4586 | typedef bool (*CheckStoreBufferFilter)(Object** addr); | 
 | 4587 |  | 
 | 4588 |  | 
 | 4589 | bool IsAMapPointerAddress(Object** addr) { | 
 | 4590 |   uintptr_t a = reinterpret_cast<uintptr_t>(addr); | 
 | 4591 |   int mod = a % Map::kSize; | 
 | 4592 |   return mod >= Map::kPointerFieldsBeginOffset && | 
 | 4593 |          mod < Map::kPointerFieldsEndOffset; | 
 | 4594 | } | 
 | 4595 |  | 
 | 4596 |  | 
 | 4597 | bool EverythingsAPointer(Object** addr) { return true; } | 
 | 4598 |  | 
 | 4599 |  | 
 | 4600 | static void CheckStoreBuffer(Heap* heap, Object** current, Object** limit, | 
 | 4601 |                              Object**** store_buffer_position, | 
 | 4602 |                              Object*** store_buffer_top, | 
 | 4603 |                              CheckStoreBufferFilter filter, | 
 | 4604 |                              Address special_garbage_start, | 
 | 4605 |                              Address special_garbage_end) { | 
 | 4606 |   Map* free_space_map = heap->free_space_map(); | 
 | 4607 |   for (; current < limit; current++) { | 
 | 4608 |     Object* o = *current; | 
 | 4609 |     Address current_address = reinterpret_cast<Address>(current); | 
 | 4610 |     // Skip free space. | 
 | 4611 |     if (o == free_space_map) { | 
 | 4612 |       Address current_address = reinterpret_cast<Address>(current); | 
 | 4613 |       FreeSpace* free_space = | 
 | 4614 |           FreeSpace::cast(HeapObject::FromAddress(current_address)); | 
 | 4615 |       int skip = free_space->Size(); | 
 | 4616 |       DCHECK(current_address + skip <= reinterpret_cast<Address>(limit)); | 
 | 4617 |       DCHECK(skip > 0); | 
 | 4618 |       current_address += skip - kPointerSize; | 
 | 4619 |       current = reinterpret_cast<Object**>(current_address); | 
 | 4620 |       continue; | 
 | 4621 |     } | 
 | 4622 |     // Skip the current linear allocation space between top and limit which is | 
 | 4623 |     // unmarked with the free space map, but can contain junk. | 
 | 4624 |     if (current_address == special_garbage_start && | 
 | 4625 |         special_garbage_end != special_garbage_start) { | 
 | 4626 |       current_address = special_garbage_end - kPointerSize; | 
 | 4627 |       current = reinterpret_cast<Object**>(current_address); | 
 | 4628 |       continue; | 
 | 4629 |     } | 
 | 4630 |     if (!(*filter)(current)) continue; | 
 | 4631 |     DCHECK(current_address < special_garbage_start || | 
 | 4632 |            current_address >= special_garbage_end); | 
 | 4633 |     DCHECK(reinterpret_cast<uintptr_t>(o) != kFreeListZapValue); | 
 | 4634 |     // We have to check that the pointer does not point into new space | 
 | 4635 |     // without trying to cast it to a heap object since the hash field of | 
 | 4636 |     // a string can contain values like 1 and 3 which are tagged null | 
 | 4637 |     // pointers. | 
 | 4638 |     if (!heap->InNewSpace(o)) continue; | 
 | 4639 |     while (**store_buffer_position < current && | 
 | 4640 |            *store_buffer_position < store_buffer_top) { | 
 | 4641 |       (*store_buffer_position)++; | 
 | 4642 |     } | 
 | 4643 |     if (**store_buffer_position != current || | 
 | 4644 |         *store_buffer_position == store_buffer_top) { | 
 | 4645 |       Object** obj_start = current; | 
 | 4646 |       while (!(*obj_start)->IsMap()) obj_start--; | 
 | 4647 |       UNREACHABLE(); | 
 | 4648 |     } | 
 | 4649 |   } | 
 | 4650 | } | 
 | 4651 |  | 
 | 4652 |  | 
 | 4653 | // Check that the store buffer contains all intergenerational pointers by | 
 | 4654 | // scanning a page and ensuring that all pointers to young space are in the | 
 | 4655 | // store buffer. | 
 | 4656 | void Heap::OldPointerSpaceCheckStoreBuffer() { | 
 | 4657 |   OldSpace* space = old_pointer_space(); | 
 | 4658 |   PageIterator pages(space); | 
 | 4659 |  | 
 | 4660 |   store_buffer()->SortUniq(); | 
 | 4661 |  | 
 | 4662 |   while (pages.has_next()) { | 
 | 4663 |     Page* page = pages.next(); | 
 | 4664 |     Object** current = reinterpret_cast<Object**>(page->area_start()); | 
 | 4665 |  | 
 | 4666 |     Address end = page->area_end(); | 
 | 4667 |  | 
 | 4668 |     Object*** store_buffer_position = store_buffer()->Start(); | 
 | 4669 |     Object*** store_buffer_top = store_buffer()->Top(); | 
 | 4670 |  | 
 | 4671 |     Object** limit = reinterpret_cast<Object**>(end); | 
 | 4672 |     CheckStoreBuffer(this, current, limit, &store_buffer_position, | 
 | 4673 |                      store_buffer_top, &EverythingsAPointer, space->top(), | 
 | 4674 |                      space->limit()); | 
 | 4675 |   } | 
 | 4676 | } | 
 | 4677 |  | 
 | 4678 |  | 
 | 4679 | void Heap::MapSpaceCheckStoreBuffer() { | 
 | 4680 |   MapSpace* space = map_space(); | 
 | 4681 |   PageIterator pages(space); | 
 | 4682 |  | 
 | 4683 |   store_buffer()->SortUniq(); | 
 | 4684 |  | 
 | 4685 |   while (pages.has_next()) { | 
 | 4686 |     Page* page = pages.next(); | 
 | 4687 |     Object** current = reinterpret_cast<Object**>(page->area_start()); | 
 | 4688 |  | 
 | 4689 |     Address end = page->area_end(); | 
 | 4690 |  | 
 | 4691 |     Object*** store_buffer_position = store_buffer()->Start(); | 
 | 4692 |     Object*** store_buffer_top = store_buffer()->Top(); | 
 | 4693 |  | 
 | 4694 |     Object** limit = reinterpret_cast<Object**>(end); | 
 | 4695 |     CheckStoreBuffer(this, current, limit, &store_buffer_position, | 
 | 4696 |                      store_buffer_top, &IsAMapPointerAddress, space->top(), | 
 | 4697 |                      space->limit()); | 
 | 4698 |   } | 
 | 4699 | } | 
 | 4700 |  | 
 | 4701 |  | 
 | 4702 | void Heap::LargeObjectSpaceCheckStoreBuffer() { | 
 | 4703 |   LargeObjectIterator it(lo_space()); | 
 | 4704 |   for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) { | 
 | 4705 |     // We only have code, sequential strings, or fixed arrays in large | 
 | 4706 |     // object space, and only fixed arrays can possibly contain pointers to | 
 | 4707 |     // the young generation. | 
 | 4708 |     if (object->IsFixedArray()) { | 
 | 4709 |       Object*** store_buffer_position = store_buffer()->Start(); | 
 | 4710 |       Object*** store_buffer_top = store_buffer()->Top(); | 
 | 4711 |       Object** current = reinterpret_cast<Object**>(object->address()); | 
 | 4712 |       Object** limit = | 
 | 4713 |           reinterpret_cast<Object**>(object->address() + object->Size()); | 
 | 4714 |       CheckStoreBuffer(this, current, limit, &store_buffer_position, | 
 | 4715 |                        store_buffer_top, &EverythingsAPointer, NULL, NULL); | 
 | 4716 |     } | 
 | 4717 |   } | 
 | 4718 | } | 
 | 4719 | #endif | 
 | 4720 |  | 
 | 4721 |  | 
 | 4722 | void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) { | 
 | 4723 |   IterateStrongRoots(v, mode); | 
 | 4724 |   IterateWeakRoots(v, mode); | 
 | 4725 | } | 
 | 4726 |  | 
 | 4727 |  | 
 | 4728 | void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) { | 
 | 4729 |   v->VisitPointer(reinterpret_cast<Object**>(&roots_[kStringTableRootIndex])); | 
 | 4730 |   v->Synchronize(VisitorSynchronization::kStringTable); | 
 | 4731 |   if (mode != VISIT_ALL_IN_SCAVENGE && mode != VISIT_ALL_IN_SWEEP_NEWSPACE) { | 
 | 4732 |     // Scavenge collections have special processing for this. | 
 | 4733 |     external_string_table_.Iterate(v); | 
 | 4734 |   } | 
 | 4735 |   v->Synchronize(VisitorSynchronization::kExternalStringsTable); | 
 | 4736 | } | 
 | 4737 |  | 
 | 4738 |  | 
 | 4739 | void Heap::IterateSmiRoots(ObjectVisitor* v) { | 
 | 4740 |   // Acquire execution access since we are going to read stack limit values. | 
 | 4741 |   ExecutionAccess access(isolate()); | 
 | 4742 |   v->VisitPointers(&roots_[kSmiRootsStart], &roots_[kRootListLength]); | 
 | 4743 |   v->Synchronize(VisitorSynchronization::kSmiRootList); | 
 | 4744 | } | 
 | 4745 |  | 
 | 4746 |  | 
 | 4747 | void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) { | 
 | 4748 |   v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]); | 
 | 4749 |   v->Synchronize(VisitorSynchronization::kStrongRootList); | 
 | 4750 |  | 
 | 4751 |   v->VisitPointer(bit_cast<Object**>(&hidden_string_)); | 
 | 4752 |   v->Synchronize(VisitorSynchronization::kInternalizedString); | 
 | 4753 |  | 
 | 4754 |   isolate_->bootstrapper()->Iterate(v); | 
 | 4755 |   v->Synchronize(VisitorSynchronization::kBootstrapper); | 
 | 4756 |   isolate_->Iterate(v); | 
 | 4757 |   v->Synchronize(VisitorSynchronization::kTop); | 
 | 4758 |   Relocatable::Iterate(isolate_, v); | 
 | 4759 |   v->Synchronize(VisitorSynchronization::kRelocatable); | 
 | 4760 |  | 
 | 4761 |   if (isolate_->deoptimizer_data() != NULL) { | 
 | 4762 |     isolate_->deoptimizer_data()->Iterate(v); | 
 | 4763 |   } | 
 | 4764 |   v->Synchronize(VisitorSynchronization::kDebug); | 
 | 4765 |   isolate_->compilation_cache()->Iterate(v); | 
 | 4766 |   v->Synchronize(VisitorSynchronization::kCompilationCache); | 
 | 4767 |  | 
 | 4768 |   // Iterate over local handles in handle scopes. | 
 | 4769 |   isolate_->handle_scope_implementer()->Iterate(v); | 
 | 4770 |   isolate_->IterateDeferredHandles(v); | 
 | 4771 |   v->Synchronize(VisitorSynchronization::kHandleScope); | 
 | 4772 |  | 
 | 4773 |   // Iterate over the builtin code objects and code stubs in the | 
 | 4774 |   // heap. Note that it is not necessary to iterate over code objects | 
 | 4775 |   // on scavenge collections. | 
 | 4776 |   if (mode != VISIT_ALL_IN_SCAVENGE) { | 
 | 4777 |     isolate_->builtins()->IterateBuiltins(v); | 
 | 4778 |   } | 
 | 4779 |   v->Synchronize(VisitorSynchronization::kBuiltins); | 
 | 4780 |  | 
 | 4781 |   // Iterate over global handles. | 
 | 4782 |   switch (mode) { | 
 | 4783 |     case VISIT_ONLY_STRONG: | 
 | 4784 |       isolate_->global_handles()->IterateStrongRoots(v); | 
 | 4785 |       break; | 
 | 4786 |     case VISIT_ALL_IN_SCAVENGE: | 
 | 4787 |       isolate_->global_handles()->IterateNewSpaceStrongAndDependentRoots(v); | 
 | 4788 |       break; | 
 | 4789 |     case VISIT_ALL_IN_SWEEP_NEWSPACE: | 
 | 4790 |     case VISIT_ALL: | 
 | 4791 |       isolate_->global_handles()->IterateAllRoots(v); | 
 | 4792 |       break; | 
 | 4793 |   } | 
 | 4794 |   v->Synchronize(VisitorSynchronization::kGlobalHandles); | 
 | 4795 |  | 
 | 4796 |   // Iterate over eternal handles. | 
 | 4797 |   if (mode == VISIT_ALL_IN_SCAVENGE) { | 
 | 4798 |     isolate_->eternal_handles()->IterateNewSpaceRoots(v); | 
 | 4799 |   } else { | 
 | 4800 |     isolate_->eternal_handles()->IterateAllRoots(v); | 
 | 4801 |   } | 
 | 4802 |   v->Synchronize(VisitorSynchronization::kEternalHandles); | 
 | 4803 |  | 
 | 4804 |   // Iterate over pointers being held by inactive threads. | 
 | 4805 |   isolate_->thread_manager()->Iterate(v); | 
 | 4806 |   v->Synchronize(VisitorSynchronization::kThreadManager); | 
 | 4807 |  | 
 | 4808 |   // Iterate over the pointers the Serialization/Deserialization code is | 
 | 4809 |   // holding. | 
 | 4810 |   // During garbage collection this keeps the partial snapshot cache alive. | 
 | 4811 |   // During deserialization of the startup snapshot this creates the partial | 
 | 4812 |   // snapshot cache and deserializes the objects it refers to.  During | 
 | 4813 |   // serialization this does nothing, since the partial snapshot cache is | 
 | 4814 |   // empty.  However the next thing we do is create the partial snapshot, | 
 | 4815 |   // filling up the partial snapshot cache with objects it needs as we go. | 
 | 4816 |   SerializerDeserializer::Iterate(isolate_, v); | 
 | 4817 |   // We don't do a v->Synchronize call here, because in debug mode that will | 
 | 4818 |   // output a flag to the snapshot.  However at this point the serializer and | 
 | 4819 |   // deserializer are deliberately a little unsynchronized (see above) so the | 
 | 4820 |   // checking of the sync flag in the snapshot would fail. | 
 | 4821 | } | 
 | 4822 |  | 
 | 4823 |  | 
 | 4824 | // TODO(1236194): Since the heap size is configurable on the command line | 
 | 4825 | // and through the API, we should gracefully handle the case that the heap | 
 | 4826 | // size is not big enough to fit all the initial objects. | 
 | 4827 | bool Heap::ConfigureHeap(int max_semi_space_size, int max_old_space_size, | 
 | 4828 |                          int max_executable_size, size_t code_range_size) { | 
 | 4829 |   if (HasBeenSetUp()) return false; | 
 | 4830 |  | 
 | 4831 |   // Overwrite default configuration. | 
 | 4832 |   if (max_semi_space_size > 0) { | 
 | 4833 |     max_semi_space_size_ = max_semi_space_size * MB; | 
 | 4834 |   } | 
 | 4835 |   if (max_old_space_size > 0) { | 
 | 4836 |     max_old_generation_size_ = max_old_space_size * MB; | 
 | 4837 |   } | 
 | 4838 |   if (max_executable_size > 0) { | 
 | 4839 |     max_executable_size_ = max_executable_size * MB; | 
 | 4840 |   } | 
 | 4841 |  | 
 | 4842 |   // If max space size flags are specified overwrite the configuration. | 
 | 4843 |   if (FLAG_max_semi_space_size > 0) { | 
 | 4844 |     max_semi_space_size_ = FLAG_max_semi_space_size * MB; | 
 | 4845 |   } | 
 | 4846 |   if (FLAG_max_old_space_size > 0) { | 
 | 4847 |     max_old_generation_size_ = FLAG_max_old_space_size * MB; | 
 | 4848 |   } | 
 | 4849 |   if (FLAG_max_executable_size > 0) { | 
 | 4850 |     max_executable_size_ = FLAG_max_executable_size * MB; | 
 | 4851 |   } | 
 | 4852 |  | 
 | 4853 |   if (FLAG_stress_compaction) { | 
 | 4854 |     // This will cause more frequent GCs when stressing. | 
 | 4855 |     max_semi_space_size_ = Page::kPageSize; | 
 | 4856 |   } | 
 | 4857 |  | 
 | 4858 |   if (Snapshot::HaveASnapshotToStartFrom()) { | 
 | 4859 |     // If we are using a snapshot we always reserve the default amount | 
 | 4860 |     // of memory for each semispace because code in the snapshot has | 
 | 4861 |     // write-barrier code that relies on the size and alignment of new | 
 | 4862 |     // space.  We therefore cannot use a larger max semispace size | 
 | 4863 |     // than the default reserved semispace size. | 
 | 4864 |     if (max_semi_space_size_ > reserved_semispace_size_) { | 
 | 4865 |       max_semi_space_size_ = reserved_semispace_size_; | 
 | 4866 |       if (FLAG_trace_gc) { | 
 | 4867 |         PrintPID("Max semi-space size cannot be more than %d kbytes\n", | 
 | 4868 |                  reserved_semispace_size_ >> 10); | 
 | 4869 |       } | 
 | 4870 |     } | 
 | 4871 |   } else { | 
 | 4872 |     // If we are not using snapshots we reserve space for the actual | 
 | 4873 |     // max semispace size. | 
 | 4874 |     reserved_semispace_size_ = max_semi_space_size_; | 
 | 4875 |   } | 
 | 4876 |  | 
 | 4877 |   // The max executable size must be less than or equal to the max old | 
 | 4878 |   // generation size. | 
 | 4879 |   if (max_executable_size_ > max_old_generation_size_) { | 
 | 4880 |     max_executable_size_ = max_old_generation_size_; | 
 | 4881 |   } | 
 | 4882 |  | 
 | 4883 |   // The new space size must be a power of two to support single-bit testing | 
 | 4884 |   // for containment. | 
 | 4885 |   max_semi_space_size_ = | 
 | 4886 |       base::bits::RoundUpToPowerOfTwo32(max_semi_space_size_); | 
 | 4887 |   reserved_semispace_size_ = | 
 | 4888 |       base::bits::RoundUpToPowerOfTwo32(reserved_semispace_size_); | 
 | 4889 |  | 
 | 4890 |   if (FLAG_min_semi_space_size > 0) { | 
 | 4891 |     int initial_semispace_size = FLAG_min_semi_space_size * MB; | 
 | 4892 |     if (initial_semispace_size > max_semi_space_size_) { | 
 | 4893 |       initial_semispace_size_ = max_semi_space_size_; | 
 | 4894 |       if (FLAG_trace_gc) { | 
 | 4895 |         PrintPID( | 
 | 4896 |             "Min semi-space size cannot be more than the maximum" | 
 | 4897 |             "semi-space size of %d MB\n", | 
 | 4898 |             max_semi_space_size_); | 
 | 4899 |       } | 
 | 4900 |     } else { | 
 | 4901 |       initial_semispace_size_ = initial_semispace_size; | 
 | 4902 |     } | 
 | 4903 |   } | 
 | 4904 |  | 
 | 4905 |   initial_semispace_size_ = Min(initial_semispace_size_, max_semi_space_size_); | 
 | 4906 |  | 
 | 4907 |   // The old generation is paged and needs at least one page for each space. | 
 | 4908 |   int paged_space_count = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1; | 
 | 4909 |   max_old_generation_size_ = | 
 | 4910 |       Max(static_cast<intptr_t>(paged_space_count * Page::kPageSize), | 
 | 4911 |           max_old_generation_size_); | 
 | 4912 |  | 
 | 4913 |   // We rely on being able to allocate new arrays in paged spaces. | 
 | 4914 |   DCHECK(Page::kMaxRegularHeapObjectSize >= | 
 | 4915 |          (JSArray::kSize + | 
 | 4916 |           FixedArray::SizeFor(JSObject::kInitialMaxFastElementArray) + | 
 | 4917 |           AllocationMemento::kSize)); | 
 | 4918 |  | 
 | 4919 |   code_range_size_ = code_range_size * MB; | 
 | 4920 |  | 
 | 4921 |   configured_ = true; | 
 | 4922 |   return true; | 
 | 4923 | } | 
 | 4924 |  | 
 | 4925 |  | 
 | 4926 | bool Heap::ConfigureHeapDefault() { return ConfigureHeap(0, 0, 0, 0); } | 
 | 4927 |  | 
 | 4928 |  | 
 | 4929 | void Heap::RecordStats(HeapStats* stats, bool take_snapshot) { | 
 | 4930 |   *stats->start_marker = HeapStats::kStartMarker; | 
 | 4931 |   *stats->end_marker = HeapStats::kEndMarker; | 
 | 4932 |   *stats->new_space_size = new_space_.SizeAsInt(); | 
 | 4933 |   *stats->new_space_capacity = static_cast<int>(new_space_.Capacity()); | 
 | 4934 |   *stats->old_pointer_space_size = old_pointer_space_->SizeOfObjects(); | 
 | 4935 |   *stats->old_pointer_space_capacity = old_pointer_space_->Capacity(); | 
 | 4936 |   *stats->old_data_space_size = old_data_space_->SizeOfObjects(); | 
 | 4937 |   *stats->old_data_space_capacity = old_data_space_->Capacity(); | 
 | 4938 |   *stats->code_space_size = code_space_->SizeOfObjects(); | 
 | 4939 |   *stats->code_space_capacity = code_space_->Capacity(); | 
 | 4940 |   *stats->map_space_size = map_space_->SizeOfObjects(); | 
 | 4941 |   *stats->map_space_capacity = map_space_->Capacity(); | 
 | 4942 |   *stats->cell_space_size = cell_space_->SizeOfObjects(); | 
 | 4943 |   *stats->cell_space_capacity = cell_space_->Capacity(); | 
 | 4944 |   *stats->property_cell_space_size = property_cell_space_->SizeOfObjects(); | 
 | 4945 |   *stats->property_cell_space_capacity = property_cell_space_->Capacity(); | 
 | 4946 |   *stats->lo_space_size = lo_space_->Size(); | 
 | 4947 |   isolate_->global_handles()->RecordStats(stats); | 
 | 4948 |   *stats->memory_allocator_size = isolate()->memory_allocator()->Size(); | 
 | 4949 |   *stats->memory_allocator_capacity = | 
 | 4950 |       isolate()->memory_allocator()->Size() + | 
 | 4951 |       isolate()->memory_allocator()->Available(); | 
 | 4952 |   *stats->os_error = base::OS::GetLastError(); | 
 | 4953 |   isolate()->memory_allocator()->Available(); | 
 | 4954 |   if (take_snapshot) { | 
 | 4955 |     HeapIterator iterator(this); | 
 | 4956 |     for (HeapObject* obj = iterator.next(); obj != NULL; | 
 | 4957 |          obj = iterator.next()) { | 
 | 4958 |       InstanceType type = obj->map()->instance_type(); | 
 | 4959 |       DCHECK(0 <= type && type <= LAST_TYPE); | 
 | 4960 |       stats->objects_per_type[type]++; | 
 | 4961 |       stats->size_per_type[type] += obj->Size(); | 
 | 4962 |     } | 
 | 4963 |   } | 
 | 4964 | } | 
 | 4965 |  | 
 | 4966 |  | 
 | 4967 | intptr_t Heap::PromotedSpaceSizeOfObjects() { | 
 | 4968 |   return old_pointer_space_->SizeOfObjects() + | 
 | 4969 |          old_data_space_->SizeOfObjects() + code_space_->SizeOfObjects() + | 
 | 4970 |          map_space_->SizeOfObjects() + cell_space_->SizeOfObjects() + | 
 | 4971 |          property_cell_space_->SizeOfObjects() + lo_space_->SizeOfObjects(); | 
 | 4972 | } | 
 | 4973 |  | 
 | 4974 |  | 
 | 4975 | int64_t Heap::PromotedExternalMemorySize() { | 
 | 4976 |   if (amount_of_external_allocated_memory_ <= | 
 | 4977 |       amount_of_external_allocated_memory_at_last_global_gc_) | 
 | 4978 |     return 0; | 
 | 4979 |   return amount_of_external_allocated_memory_ - | 
 | 4980 |          amount_of_external_allocated_memory_at_last_global_gc_; | 
 | 4981 | } | 
 | 4982 |  | 
 | 4983 |  | 
 | 4984 | intptr_t Heap::OldGenerationAllocationLimit(intptr_t old_gen_size, | 
 | 4985 |                                             int freed_global_handles) { | 
 | 4986 |   const int kMaxHandles = 1000; | 
 | 4987 |   const int kMinHandles = 100; | 
 | 4988 |   double min_factor = 1.1; | 
 | 4989 |   double max_factor = 4; | 
 | 4990 |   // We set the old generation growing factor to 2 to grow the heap slower on | 
 | 4991 |   // memory-constrained devices. | 
 | 4992 |   if (max_old_generation_size_ <= kMaxOldSpaceSizeMediumMemoryDevice) { | 
 | 4993 |     max_factor = 2; | 
 | 4994 |   } | 
 | 4995 |   // If there are many freed global handles, then the next full GC will | 
 | 4996 |   // likely collect a lot of garbage. Choose the heap growing factor | 
 | 4997 |   // depending on freed global handles. | 
 | 4998 |   // TODO(ulan, hpayer): Take into account mutator utilization. | 
 | 4999 |   double factor; | 
 | 5000 |   if (freed_global_handles <= kMinHandles) { | 
 | 5001 |     factor = max_factor; | 
 | 5002 |   } else if (freed_global_handles >= kMaxHandles) { | 
 | 5003 |     factor = min_factor; | 
 | 5004 |   } else { | 
 | 5005 |     // Compute factor using linear interpolation between points | 
 | 5006 |     // (kMinHandles, max_factor) and (kMaxHandles, min_factor). | 
 | 5007 |     factor = max_factor - | 
 | 5008 |              (freed_global_handles - kMinHandles) * (max_factor - min_factor) / | 
 | 5009 |                  (kMaxHandles - kMinHandles); | 
 | 5010 |   } | 
 | 5011 |  | 
 | 5012 |   if (FLAG_stress_compaction || | 
 | 5013 |       mark_compact_collector()->reduce_memory_footprint_) { | 
 | 5014 |     factor = min_factor; | 
 | 5015 |   } | 
 | 5016 |  | 
 | 5017 |   intptr_t limit = static_cast<intptr_t>(old_gen_size * factor); | 
 | 5018 |   limit = Max(limit, kMinimumOldGenerationAllocationLimit); | 
 | 5019 |   limit += new_space_.Capacity(); | 
 | 5020 |   intptr_t halfway_to_the_max = (old_gen_size + max_old_generation_size_) / 2; | 
 | 5021 |   return Min(limit, halfway_to_the_max); | 
 | 5022 | } | 
 | 5023 |  | 
 | 5024 |  | 
 | 5025 | void Heap::EnableInlineAllocation() { | 
 | 5026 |   if (!inline_allocation_disabled_) return; | 
 | 5027 |   inline_allocation_disabled_ = false; | 
 | 5028 |  | 
 | 5029 |   // Update inline allocation limit for new space. | 
 | 5030 |   new_space()->UpdateInlineAllocationLimit(0); | 
 | 5031 | } | 
 | 5032 |  | 
 | 5033 |  | 
 | 5034 | void Heap::DisableInlineAllocation() { | 
 | 5035 |   if (inline_allocation_disabled_) return; | 
 | 5036 |   inline_allocation_disabled_ = true; | 
 | 5037 |  | 
 | 5038 |   // Update inline allocation limit for new space. | 
 | 5039 |   new_space()->UpdateInlineAllocationLimit(0); | 
 | 5040 |  | 
 | 5041 |   // Update inline allocation limit for old spaces. | 
 | 5042 |   PagedSpaces spaces(this); | 
 | 5043 |   for (PagedSpace* space = spaces.next(); space != NULL; | 
 | 5044 |        space = spaces.next()) { | 
 | 5045 |     space->EmptyAllocationInfo(); | 
 | 5046 |   } | 
 | 5047 | } | 
 | 5048 |  | 
 | 5049 |  | 
 | 5050 | V8_DECLARE_ONCE(initialize_gc_once); | 
 | 5051 |  | 
 | 5052 | static void InitializeGCOnce() { | 
 | 5053 |   InitializeScavengingVisitorsTables(); | 
 | 5054 |   NewSpaceScavenger::Initialize(); | 
 | 5055 |   MarkCompactCollector::Initialize(); | 
 | 5056 | } | 
 | 5057 |  | 
 | 5058 |  | 
 | 5059 | bool Heap::SetUp() { | 
 | 5060 | #ifdef DEBUG | 
 | 5061 |   allocation_timeout_ = FLAG_gc_interval; | 
 | 5062 | #endif | 
 | 5063 |  | 
 | 5064 |   // Initialize heap spaces and initial maps and objects. Whenever something | 
 | 5065 |   // goes wrong, just return false. The caller should check the results and | 
 | 5066 |   // call Heap::TearDown() to release allocated memory. | 
 | 5067 |   // | 
 | 5068 |   // If the heap is not yet configured (e.g. through the API), configure it. | 
 | 5069 |   // Configuration is based on the flags new-space-size (really the semispace | 
 | 5070 |   // size) and old-space-size if set or the initial values of semispace_size_ | 
 | 5071 |   // and old_generation_size_ otherwise. | 
 | 5072 |   if (!configured_) { | 
 | 5073 |     if (!ConfigureHeapDefault()) return false; | 
 | 5074 |   } | 
 | 5075 |  | 
 | 5076 |   base::CallOnce(&initialize_gc_once, &InitializeGCOnce); | 
 | 5077 |  | 
 | 5078 |   MarkMapPointersAsEncoded(false); | 
 | 5079 |  | 
 | 5080 |   // Set up memory allocator. | 
 | 5081 |   if (!isolate_->memory_allocator()->SetUp(MaxReserved(), MaxExecutableSize())) | 
 | 5082 |     return false; | 
 | 5083 |  | 
 | 5084 |   // Set up new space. | 
 | 5085 |   if (!new_space_.SetUp(reserved_semispace_size_, max_semi_space_size_)) { | 
 | 5086 |     return false; | 
 | 5087 |   } | 
 | 5088 |   new_space_top_after_last_gc_ = new_space()->top(); | 
 | 5089 |  | 
 | 5090 |   // Initialize old pointer space. | 
 | 5091 |   old_pointer_space_ = new OldSpace(this, max_old_generation_size_, | 
 | 5092 |                                     OLD_POINTER_SPACE, NOT_EXECUTABLE); | 
 | 5093 |   if (old_pointer_space_ == NULL) return false; | 
 | 5094 |   if (!old_pointer_space_->SetUp()) return false; | 
 | 5095 |  | 
 | 5096 |   // Initialize old data space. | 
 | 5097 |   old_data_space_ = new OldSpace(this, max_old_generation_size_, OLD_DATA_SPACE, | 
 | 5098 |                                  NOT_EXECUTABLE); | 
 | 5099 |   if (old_data_space_ == NULL) return false; | 
 | 5100 |   if (!old_data_space_->SetUp()) return false; | 
 | 5101 |  | 
 | 5102 |   if (!isolate_->code_range()->SetUp(code_range_size_)) return false; | 
 | 5103 |  | 
 | 5104 |   // Initialize the code space, set its maximum capacity to the old | 
 | 5105 |   // generation size. It needs executable memory. | 
 | 5106 |   code_space_ = | 
 | 5107 |       new OldSpace(this, max_old_generation_size_, CODE_SPACE, EXECUTABLE); | 
 | 5108 |   if (code_space_ == NULL) return false; | 
 | 5109 |   if (!code_space_->SetUp()) return false; | 
 | 5110 |  | 
 | 5111 |   // Initialize map space. | 
 | 5112 |   map_space_ = new MapSpace(this, max_old_generation_size_, MAP_SPACE); | 
 | 5113 |   if (map_space_ == NULL) return false; | 
 | 5114 |   if (!map_space_->SetUp()) return false; | 
 | 5115 |  | 
 | 5116 |   // Initialize simple cell space. | 
 | 5117 |   cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE); | 
 | 5118 |   if (cell_space_ == NULL) return false; | 
 | 5119 |   if (!cell_space_->SetUp()) return false; | 
 | 5120 |  | 
 | 5121 |   // Initialize global property cell space. | 
 | 5122 |   property_cell_space_ = new PropertyCellSpace(this, max_old_generation_size_, | 
 | 5123 |                                                PROPERTY_CELL_SPACE); | 
 | 5124 |   if (property_cell_space_ == NULL) return false; | 
 | 5125 |   if (!property_cell_space_->SetUp()) return false; | 
 | 5126 |  | 
 | 5127 |   // The large object code space may contain code or data.  We set the memory | 
 | 5128 |   // to be non-executable here for safety, but this means we need to enable it | 
 | 5129 |   // explicitly when allocating large code objects. | 
 | 5130 |   lo_space_ = new LargeObjectSpace(this, max_old_generation_size_, LO_SPACE); | 
 | 5131 |   if (lo_space_ == NULL) return false; | 
 | 5132 |   if (!lo_space_->SetUp()) return false; | 
 | 5133 |  | 
 | 5134 |   // Set up the seed that is used to randomize the string hash function. | 
 | 5135 |   DCHECK(hash_seed() == 0); | 
 | 5136 |   if (FLAG_randomize_hashes) { | 
 | 5137 |     if (FLAG_hash_seed == 0) { | 
 | 5138 |       int rnd = isolate()->random_number_generator()->NextInt(); | 
 | 5139 |       set_hash_seed(Smi::FromInt(rnd & Name::kHashBitMask)); | 
 | 5140 |     } else { | 
 | 5141 |       set_hash_seed(Smi::FromInt(FLAG_hash_seed)); | 
 | 5142 |     } | 
 | 5143 |   } | 
 | 5144 |  | 
 | 5145 |   LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity())); | 
 | 5146 |   LOG(isolate_, IntPtrTEvent("heap-available", Available())); | 
 | 5147 |  | 
 | 5148 |   store_buffer()->SetUp(); | 
 | 5149 |  | 
 | 5150 |   mark_compact_collector()->SetUp(); | 
 | 5151 |  | 
 | 5152 |   return true; | 
 | 5153 | } | 
 | 5154 |  | 
 | 5155 |  | 
 | 5156 | bool Heap::CreateHeapObjects() { | 
 | 5157 |   // Create initial maps. | 
 | 5158 |   if (!CreateInitialMaps()) return false; | 
 | 5159 |   CreateApiObjects(); | 
 | 5160 |  | 
 | 5161 |   // Create initial objects | 
 | 5162 |   CreateInitialObjects(); | 
 | 5163 |   CHECK_EQ(0, gc_count_); | 
 | 5164 |  | 
 | 5165 |   set_native_contexts_list(undefined_value()); | 
 | 5166 |   set_array_buffers_list(undefined_value()); | 
 | 5167 |   set_allocation_sites_list(undefined_value()); | 
 | 5168 |   weak_object_to_code_table_ = undefined_value(); | 
 | 5169 |   return true; | 
 | 5170 | } | 
 | 5171 |  | 
 | 5172 |  | 
 | 5173 | void Heap::SetStackLimits() { | 
 | 5174 |   DCHECK(isolate_ != NULL); | 
 | 5175 |   DCHECK(isolate_ == isolate()); | 
 | 5176 |   // On 64 bit machines, pointers are generally out of range of Smis.  We write | 
 | 5177 |   // something that looks like an out of range Smi to the GC. | 
 | 5178 |  | 
 | 5179 |   // Set up the special root array entries containing the stack limits. | 
 | 5180 |   // These are actually addresses, but the tag makes the GC ignore it. | 
 | 5181 |   roots_[kStackLimitRootIndex] = reinterpret_cast<Object*>( | 
 | 5182 |       (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag); | 
 | 5183 |   roots_[kRealStackLimitRootIndex] = reinterpret_cast<Object*>( | 
 | 5184 |       (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag); | 
 | 5185 | } | 
 | 5186 |  | 
 | 5187 |  | 
 | 5188 | void Heap::TearDown() { | 
 | 5189 | #ifdef VERIFY_HEAP | 
 | 5190 |   if (FLAG_verify_heap) { | 
 | 5191 |     Verify(); | 
 | 5192 |   } | 
 | 5193 | #endif | 
 | 5194 |  | 
 | 5195 |   UpdateMaximumCommitted(); | 
 | 5196 |  | 
 | 5197 |   if (FLAG_print_cumulative_gc_stat) { | 
 | 5198 |     PrintF("\n"); | 
 | 5199 |     PrintF("gc_count=%d ", gc_count_); | 
 | 5200 |     PrintF("mark_sweep_count=%d ", ms_count_); | 
 | 5201 |     PrintF("max_gc_pause=%.1f ", get_max_gc_pause()); | 
 | 5202 |     PrintF("total_gc_time=%.1f ", total_gc_time_ms_); | 
 | 5203 |     PrintF("min_in_mutator=%.1f ", get_min_in_mutator()); | 
 | 5204 |     PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ", get_max_alive_after_gc()); | 
 | 5205 |     PrintF("total_marking_time=%.1f ", tracer_.cumulative_sweeping_duration()); | 
 | 5206 |     PrintF("total_sweeping_time=%.1f ", tracer_.cumulative_sweeping_duration()); | 
 | 5207 |     PrintF("\n\n"); | 
 | 5208 |   } | 
 | 5209 |  | 
 | 5210 |   if (FLAG_print_max_heap_committed) { | 
 | 5211 |     PrintF("\n"); | 
 | 5212 |     PrintF("maximum_committed_by_heap=%" V8_PTR_PREFIX "d ", | 
 | 5213 |            MaximumCommittedMemory()); | 
 | 5214 |     PrintF("maximum_committed_by_new_space=%" V8_PTR_PREFIX "d ", | 
 | 5215 |            new_space_.MaximumCommittedMemory()); | 
 | 5216 |     PrintF("maximum_committed_by_old_pointer_space=%" V8_PTR_PREFIX "d ", | 
 | 5217 |            old_data_space_->MaximumCommittedMemory()); | 
 | 5218 |     PrintF("maximum_committed_by_old_data_space=%" V8_PTR_PREFIX "d ", | 
 | 5219 |            old_pointer_space_->MaximumCommittedMemory()); | 
 | 5220 |     PrintF("maximum_committed_by_old_data_space=%" V8_PTR_PREFIX "d ", | 
 | 5221 |            old_pointer_space_->MaximumCommittedMemory()); | 
 | 5222 |     PrintF("maximum_committed_by_code_space=%" V8_PTR_PREFIX "d ", | 
 | 5223 |            code_space_->MaximumCommittedMemory()); | 
 | 5224 |     PrintF("maximum_committed_by_map_space=%" V8_PTR_PREFIX "d ", | 
 | 5225 |            map_space_->MaximumCommittedMemory()); | 
 | 5226 |     PrintF("maximum_committed_by_cell_space=%" V8_PTR_PREFIX "d ", | 
 | 5227 |            cell_space_->MaximumCommittedMemory()); | 
 | 5228 |     PrintF("maximum_committed_by_property_space=%" V8_PTR_PREFIX "d ", | 
 | 5229 |            property_cell_space_->MaximumCommittedMemory()); | 
 | 5230 |     PrintF("maximum_committed_by_lo_space=%" V8_PTR_PREFIX "d ", | 
 | 5231 |            lo_space_->MaximumCommittedMemory()); | 
 | 5232 |     PrintF("\n\n"); | 
 | 5233 |   } | 
 | 5234 |  | 
 | 5235 |   if (FLAG_verify_predictable) { | 
 | 5236 |     PrintAlloctionsHash(); | 
 | 5237 |   } | 
 | 5238 |  | 
 | 5239 |   TearDownArrayBuffers(); | 
 | 5240 |  | 
 | 5241 |   isolate_->global_handles()->TearDown(); | 
 | 5242 |  | 
 | 5243 |   external_string_table_.TearDown(); | 
 | 5244 |  | 
 | 5245 |   mark_compact_collector()->TearDown(); | 
 | 5246 |  | 
 | 5247 |   new_space_.TearDown(); | 
 | 5248 |  | 
 | 5249 |   if (old_pointer_space_ != NULL) { | 
 | 5250 |     old_pointer_space_->TearDown(); | 
 | 5251 |     delete old_pointer_space_; | 
 | 5252 |     old_pointer_space_ = NULL; | 
 | 5253 |   } | 
 | 5254 |  | 
 | 5255 |   if (old_data_space_ != NULL) { | 
 | 5256 |     old_data_space_->TearDown(); | 
 | 5257 |     delete old_data_space_; | 
 | 5258 |     old_data_space_ = NULL; | 
 | 5259 |   } | 
 | 5260 |  | 
 | 5261 |   if (code_space_ != NULL) { | 
 | 5262 |     code_space_->TearDown(); | 
 | 5263 |     delete code_space_; | 
 | 5264 |     code_space_ = NULL; | 
 | 5265 |   } | 
 | 5266 |  | 
 | 5267 |   if (map_space_ != NULL) { | 
 | 5268 |     map_space_->TearDown(); | 
 | 5269 |     delete map_space_; | 
 | 5270 |     map_space_ = NULL; | 
 | 5271 |   } | 
 | 5272 |  | 
 | 5273 |   if (cell_space_ != NULL) { | 
 | 5274 |     cell_space_->TearDown(); | 
 | 5275 |     delete cell_space_; | 
 | 5276 |     cell_space_ = NULL; | 
 | 5277 |   } | 
 | 5278 |  | 
 | 5279 |   if (property_cell_space_ != NULL) { | 
 | 5280 |     property_cell_space_->TearDown(); | 
 | 5281 |     delete property_cell_space_; | 
 | 5282 |     property_cell_space_ = NULL; | 
 | 5283 |   } | 
 | 5284 |  | 
 | 5285 |   if (lo_space_ != NULL) { | 
 | 5286 |     lo_space_->TearDown(); | 
 | 5287 |     delete lo_space_; | 
 | 5288 |     lo_space_ = NULL; | 
 | 5289 |   } | 
 | 5290 |  | 
 | 5291 |   store_buffer()->TearDown(); | 
 | 5292 |   incremental_marking()->TearDown(); | 
 | 5293 |  | 
 | 5294 |   isolate_->memory_allocator()->TearDown(); | 
 | 5295 | } | 
 | 5296 |  | 
 | 5297 |  | 
 | 5298 | void Heap::AddGCPrologueCallback(v8::Isolate::GCPrologueCallback callback, | 
 | 5299 |                                  GCType gc_type, bool pass_isolate) { | 
 | 5300 |   DCHECK(callback != NULL); | 
 | 5301 |   GCPrologueCallbackPair pair(callback, gc_type, pass_isolate); | 
 | 5302 |   DCHECK(!gc_prologue_callbacks_.Contains(pair)); | 
 | 5303 |   return gc_prologue_callbacks_.Add(pair); | 
 | 5304 | } | 
 | 5305 |  | 
 | 5306 |  | 
 | 5307 | void Heap::RemoveGCPrologueCallback(v8::Isolate::GCPrologueCallback callback) { | 
 | 5308 |   DCHECK(callback != NULL); | 
 | 5309 |   for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) { | 
 | 5310 |     if (gc_prologue_callbacks_[i].callback == callback) { | 
 | 5311 |       gc_prologue_callbacks_.Remove(i); | 
 | 5312 |       return; | 
 | 5313 |     } | 
 | 5314 |   } | 
 | 5315 |   UNREACHABLE(); | 
 | 5316 | } | 
 | 5317 |  | 
 | 5318 |  | 
 | 5319 | void Heap::AddGCEpilogueCallback(v8::Isolate::GCEpilogueCallback callback, | 
 | 5320 |                                  GCType gc_type, bool pass_isolate) { | 
 | 5321 |   DCHECK(callback != NULL); | 
 | 5322 |   GCEpilogueCallbackPair pair(callback, gc_type, pass_isolate); | 
 | 5323 |   DCHECK(!gc_epilogue_callbacks_.Contains(pair)); | 
 | 5324 |   return gc_epilogue_callbacks_.Add(pair); | 
 | 5325 | } | 
 | 5326 |  | 
 | 5327 |  | 
 | 5328 | void Heap::RemoveGCEpilogueCallback(v8::Isolate::GCEpilogueCallback callback) { | 
 | 5329 |   DCHECK(callback != NULL); | 
 | 5330 |   for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) { | 
 | 5331 |     if (gc_epilogue_callbacks_[i].callback == callback) { | 
 | 5332 |       gc_epilogue_callbacks_.Remove(i); | 
 | 5333 |       return; | 
 | 5334 |     } | 
 | 5335 |   } | 
 | 5336 |   UNREACHABLE(); | 
 | 5337 | } | 
 | 5338 |  | 
 | 5339 |  | 
 | 5340 | // TODO(ishell): Find a better place for this. | 
 | 5341 | void Heap::AddWeakObjectToCodeDependency(Handle<Object> obj, | 
 | 5342 |                                          Handle<DependentCode> dep) { | 
 | 5343 |   DCHECK(!InNewSpace(*obj)); | 
 | 5344 |   DCHECK(!InNewSpace(*dep)); | 
 | 5345 |   // This handle scope keeps the table handle local to this function, which | 
 | 5346 |   // allows us to safely skip write barriers in table update operations. | 
 | 5347 |   HandleScope scope(isolate()); | 
 | 5348 |   Handle<WeakHashTable> table(WeakHashTable::cast(weak_object_to_code_table_), | 
 | 5349 |                               isolate()); | 
 | 5350 |   table = WeakHashTable::Put(table, obj, dep); | 
 | 5351 |  | 
 | 5352 |   if (ShouldZapGarbage() && weak_object_to_code_table_ != *table) { | 
 | 5353 |     WeakHashTable::cast(weak_object_to_code_table_)->Zap(the_hole_value()); | 
 | 5354 |   } | 
 | 5355 |   set_weak_object_to_code_table(*table); | 
 | 5356 |   DCHECK_EQ(*dep, table->Lookup(obj)); | 
 | 5357 | } | 
 | 5358 |  | 
 | 5359 |  | 
 | 5360 | DependentCode* Heap::LookupWeakObjectToCodeDependency(Handle<Object> obj) { | 
 | 5361 |   Object* dep = WeakHashTable::cast(weak_object_to_code_table_)->Lookup(obj); | 
 | 5362 |   if (dep->IsDependentCode()) return DependentCode::cast(dep); | 
 | 5363 |   return DependentCode::cast(empty_fixed_array()); | 
 | 5364 | } | 
 | 5365 |  | 
 | 5366 |  | 
 | 5367 | void Heap::EnsureWeakObjectToCodeTable() { | 
 | 5368 |   if (!weak_object_to_code_table()->IsHashTable()) { | 
 | 5369 |     set_weak_object_to_code_table( | 
 | 5370 |         *WeakHashTable::New(isolate(), 16, USE_DEFAULT_MINIMUM_CAPACITY, | 
 | 5371 |                             TENURED)); | 
 | 5372 |   } | 
 | 5373 | } | 
 | 5374 |  | 
 | 5375 |  | 
 | 5376 | void Heap::FatalProcessOutOfMemory(const char* location, bool take_snapshot) { | 
 | 5377 |   v8::internal::V8::FatalProcessOutOfMemory(location, take_snapshot); | 
 | 5378 | } | 
 | 5379 |  | 
 | 5380 | #ifdef DEBUG | 
 | 5381 |  | 
 | 5382 | class PrintHandleVisitor : public ObjectVisitor { | 
 | 5383 |  public: | 
 | 5384 |   void VisitPointers(Object** start, Object** end) { | 
 | 5385 |     for (Object** p = start; p < end; p++) | 
 | 5386 |       PrintF("  handle %p to %p\n", reinterpret_cast<void*>(p), | 
 | 5387 |              reinterpret_cast<void*>(*p)); | 
 | 5388 |   } | 
 | 5389 | }; | 
 | 5390 |  | 
 | 5391 |  | 
 | 5392 | void Heap::PrintHandles() { | 
 | 5393 |   PrintF("Handles:\n"); | 
 | 5394 |   PrintHandleVisitor v; | 
 | 5395 |   isolate_->handle_scope_implementer()->Iterate(&v); | 
 | 5396 | } | 
 | 5397 |  | 
 | 5398 | #endif | 
 | 5399 |  | 
 | 5400 |  | 
 | 5401 | Space* AllSpaces::next() { | 
 | 5402 |   switch (counter_++) { | 
 | 5403 |     case NEW_SPACE: | 
 | 5404 |       return heap_->new_space(); | 
 | 5405 |     case OLD_POINTER_SPACE: | 
 | 5406 |       return heap_->old_pointer_space(); | 
 | 5407 |     case OLD_DATA_SPACE: | 
 | 5408 |       return heap_->old_data_space(); | 
 | 5409 |     case CODE_SPACE: | 
 | 5410 |       return heap_->code_space(); | 
 | 5411 |     case MAP_SPACE: | 
 | 5412 |       return heap_->map_space(); | 
 | 5413 |     case CELL_SPACE: | 
 | 5414 |       return heap_->cell_space(); | 
 | 5415 |     case PROPERTY_CELL_SPACE: | 
 | 5416 |       return heap_->property_cell_space(); | 
 | 5417 |     case LO_SPACE: | 
 | 5418 |       return heap_->lo_space(); | 
 | 5419 |     default: | 
 | 5420 |       return NULL; | 
 | 5421 |   } | 
 | 5422 | } | 
 | 5423 |  | 
 | 5424 |  | 
 | 5425 | PagedSpace* PagedSpaces::next() { | 
 | 5426 |   switch (counter_++) { | 
 | 5427 |     case OLD_POINTER_SPACE: | 
 | 5428 |       return heap_->old_pointer_space(); | 
 | 5429 |     case OLD_DATA_SPACE: | 
 | 5430 |       return heap_->old_data_space(); | 
 | 5431 |     case CODE_SPACE: | 
 | 5432 |       return heap_->code_space(); | 
 | 5433 |     case MAP_SPACE: | 
 | 5434 |       return heap_->map_space(); | 
 | 5435 |     case CELL_SPACE: | 
 | 5436 |       return heap_->cell_space(); | 
 | 5437 |     case PROPERTY_CELL_SPACE: | 
 | 5438 |       return heap_->property_cell_space(); | 
 | 5439 |     default: | 
 | 5440 |       return NULL; | 
 | 5441 |   } | 
 | 5442 | } | 
 | 5443 |  | 
 | 5444 |  | 
 | 5445 | OldSpace* OldSpaces::next() { | 
 | 5446 |   switch (counter_++) { | 
 | 5447 |     case OLD_POINTER_SPACE: | 
 | 5448 |       return heap_->old_pointer_space(); | 
 | 5449 |     case OLD_DATA_SPACE: | 
 | 5450 |       return heap_->old_data_space(); | 
 | 5451 |     case CODE_SPACE: | 
 | 5452 |       return heap_->code_space(); | 
 | 5453 |     default: | 
 | 5454 |       return NULL; | 
 | 5455 |   } | 
 | 5456 | } | 
 | 5457 |  | 
 | 5458 |  | 
 | 5459 | SpaceIterator::SpaceIterator(Heap* heap) | 
 | 5460 |     : heap_(heap), | 
 | 5461 |       current_space_(FIRST_SPACE), | 
 | 5462 |       iterator_(NULL), | 
 | 5463 |       size_func_(NULL) {} | 
 | 5464 |  | 
 | 5465 |  | 
 | 5466 | SpaceIterator::SpaceIterator(Heap* heap, HeapObjectCallback size_func) | 
 | 5467 |     : heap_(heap), | 
 | 5468 |       current_space_(FIRST_SPACE), | 
 | 5469 |       iterator_(NULL), | 
 | 5470 |       size_func_(size_func) {} | 
 | 5471 |  | 
 | 5472 |  | 
 | 5473 | SpaceIterator::~SpaceIterator() { | 
 | 5474 |   // Delete active iterator if any. | 
 | 5475 |   delete iterator_; | 
 | 5476 | } | 
 | 5477 |  | 
 | 5478 |  | 
 | 5479 | bool SpaceIterator::has_next() { | 
 | 5480 |   // Iterate until no more spaces. | 
 | 5481 |   return current_space_ != LAST_SPACE; | 
 | 5482 | } | 
 | 5483 |  | 
 | 5484 |  | 
 | 5485 | ObjectIterator* SpaceIterator::next() { | 
 | 5486 |   if (iterator_ != NULL) { | 
 | 5487 |     delete iterator_; | 
 | 5488 |     iterator_ = NULL; | 
 | 5489 |     // Move to the next space | 
 | 5490 |     current_space_++; | 
 | 5491 |     if (current_space_ > LAST_SPACE) { | 
 | 5492 |       return NULL; | 
 | 5493 |     } | 
 | 5494 |   } | 
 | 5495 |  | 
 | 5496 |   // Return iterator for the new current space. | 
 | 5497 |   return CreateIterator(); | 
 | 5498 | } | 
 | 5499 |  | 
 | 5500 |  | 
 | 5501 | // Create an iterator for the space to iterate. | 
 | 5502 | ObjectIterator* SpaceIterator::CreateIterator() { | 
 | 5503 |   DCHECK(iterator_ == NULL); | 
 | 5504 |  | 
 | 5505 |   switch (current_space_) { | 
 | 5506 |     case NEW_SPACE: | 
 | 5507 |       iterator_ = new SemiSpaceIterator(heap_->new_space(), size_func_); | 
 | 5508 |       break; | 
 | 5509 |     case OLD_POINTER_SPACE: | 
 | 5510 |       iterator_ = | 
 | 5511 |           new HeapObjectIterator(heap_->old_pointer_space(), size_func_); | 
 | 5512 |       break; | 
 | 5513 |     case OLD_DATA_SPACE: | 
 | 5514 |       iterator_ = new HeapObjectIterator(heap_->old_data_space(), size_func_); | 
 | 5515 |       break; | 
 | 5516 |     case CODE_SPACE: | 
 | 5517 |       iterator_ = new HeapObjectIterator(heap_->code_space(), size_func_); | 
 | 5518 |       break; | 
 | 5519 |     case MAP_SPACE: | 
 | 5520 |       iterator_ = new HeapObjectIterator(heap_->map_space(), size_func_); | 
 | 5521 |       break; | 
 | 5522 |     case CELL_SPACE: | 
 | 5523 |       iterator_ = new HeapObjectIterator(heap_->cell_space(), size_func_); | 
 | 5524 |       break; | 
 | 5525 |     case PROPERTY_CELL_SPACE: | 
 | 5526 |       iterator_ = | 
 | 5527 |           new HeapObjectIterator(heap_->property_cell_space(), size_func_); | 
 | 5528 |       break; | 
 | 5529 |     case LO_SPACE: | 
 | 5530 |       iterator_ = new LargeObjectIterator(heap_->lo_space(), size_func_); | 
 | 5531 |       break; | 
 | 5532 |   } | 
 | 5533 |  | 
 | 5534 |   // Return the newly allocated iterator; | 
 | 5535 |   DCHECK(iterator_ != NULL); | 
 | 5536 |   return iterator_; | 
 | 5537 | } | 
 | 5538 |  | 
 | 5539 |  | 
 | 5540 | class HeapObjectsFilter { | 
 | 5541 |  public: | 
 | 5542 |   virtual ~HeapObjectsFilter() {} | 
 | 5543 |   virtual bool SkipObject(HeapObject* object) = 0; | 
 | 5544 | }; | 
 | 5545 |  | 
 | 5546 |  | 
 | 5547 | class UnreachableObjectsFilter : public HeapObjectsFilter { | 
 | 5548 |  public: | 
 | 5549 |   explicit UnreachableObjectsFilter(Heap* heap) : heap_(heap) { | 
 | 5550 |     MarkReachableObjects(); | 
 | 5551 |   } | 
 | 5552 |  | 
 | 5553 |   ~UnreachableObjectsFilter() { | 
 | 5554 |     heap_->mark_compact_collector()->ClearMarkbits(); | 
 | 5555 |   } | 
 | 5556 |  | 
 | 5557 |   bool SkipObject(HeapObject* object) { | 
 | 5558 |     MarkBit mark_bit = Marking::MarkBitFrom(object); | 
 | 5559 |     return !mark_bit.Get(); | 
 | 5560 |   } | 
 | 5561 |  | 
 | 5562 |  private: | 
 | 5563 |   class MarkingVisitor : public ObjectVisitor { | 
 | 5564 |    public: | 
 | 5565 |     MarkingVisitor() : marking_stack_(10) {} | 
 | 5566 |  | 
 | 5567 |     void VisitPointers(Object** start, Object** end) { | 
 | 5568 |       for (Object** p = start; p < end; p++) { | 
 | 5569 |         if (!(*p)->IsHeapObject()) continue; | 
 | 5570 |         HeapObject* obj = HeapObject::cast(*p); | 
 | 5571 |         MarkBit mark_bit = Marking::MarkBitFrom(obj); | 
 | 5572 |         if (!mark_bit.Get()) { | 
 | 5573 |           mark_bit.Set(); | 
 | 5574 |           marking_stack_.Add(obj); | 
 | 5575 |         } | 
 | 5576 |       } | 
 | 5577 |     } | 
 | 5578 |  | 
 | 5579 |     void TransitiveClosure() { | 
 | 5580 |       while (!marking_stack_.is_empty()) { | 
 | 5581 |         HeapObject* obj = marking_stack_.RemoveLast(); | 
 | 5582 |         obj->Iterate(this); | 
 | 5583 |       } | 
 | 5584 |     } | 
 | 5585 |  | 
 | 5586 |    private: | 
 | 5587 |     List<HeapObject*> marking_stack_; | 
 | 5588 |   }; | 
 | 5589 |  | 
 | 5590 |   void MarkReachableObjects() { | 
 | 5591 |     MarkingVisitor visitor; | 
 | 5592 |     heap_->IterateRoots(&visitor, VISIT_ALL); | 
 | 5593 |     visitor.TransitiveClosure(); | 
 | 5594 |   } | 
 | 5595 |  | 
 | 5596 |   Heap* heap_; | 
 | 5597 |   DisallowHeapAllocation no_allocation_; | 
 | 5598 | }; | 
 | 5599 |  | 
 | 5600 |  | 
 | 5601 | HeapIterator::HeapIterator(Heap* heap) | 
 | 5602 |     : make_heap_iterable_helper_(heap), | 
 | 5603 |       no_heap_allocation_(), | 
 | 5604 |       heap_(heap), | 
 | 5605 |       filtering_(HeapIterator::kNoFiltering), | 
 | 5606 |       filter_(NULL) { | 
 | 5607 |   Init(); | 
 | 5608 | } | 
 | 5609 |  | 
 | 5610 |  | 
 | 5611 | HeapIterator::HeapIterator(Heap* heap, | 
 | 5612 |                            HeapIterator::HeapObjectsFiltering filtering) | 
 | 5613 |     : make_heap_iterable_helper_(heap), | 
 | 5614 |       no_heap_allocation_(), | 
 | 5615 |       heap_(heap), | 
 | 5616 |       filtering_(filtering), | 
 | 5617 |       filter_(NULL) { | 
 | 5618 |   Init(); | 
 | 5619 | } | 
 | 5620 |  | 
 | 5621 |  | 
 | 5622 | HeapIterator::~HeapIterator() { Shutdown(); } | 
 | 5623 |  | 
 | 5624 |  | 
 | 5625 | void HeapIterator::Init() { | 
 | 5626 |   // Start the iteration. | 
 | 5627 |   space_iterator_ = new SpaceIterator(heap_); | 
 | 5628 |   switch (filtering_) { | 
 | 5629 |     case kFilterUnreachable: | 
 | 5630 |       filter_ = new UnreachableObjectsFilter(heap_); | 
 | 5631 |       break; | 
 | 5632 |     default: | 
 | 5633 |       break; | 
 | 5634 |   } | 
 | 5635 |   object_iterator_ = space_iterator_->next(); | 
 | 5636 | } | 
 | 5637 |  | 
 | 5638 |  | 
 | 5639 | void HeapIterator::Shutdown() { | 
 | 5640 | #ifdef DEBUG | 
 | 5641 |   // Assert that in filtering mode we have iterated through all | 
 | 5642 |   // objects. Otherwise, heap will be left in an inconsistent state. | 
 | 5643 |   if (filtering_ != kNoFiltering) { | 
 | 5644 |     DCHECK(object_iterator_ == NULL); | 
 | 5645 |   } | 
 | 5646 | #endif | 
 | 5647 |   // Make sure the last iterator is deallocated. | 
 | 5648 |   delete space_iterator_; | 
 | 5649 |   space_iterator_ = NULL; | 
 | 5650 |   object_iterator_ = NULL; | 
 | 5651 |   delete filter_; | 
 | 5652 |   filter_ = NULL; | 
 | 5653 | } | 
 | 5654 |  | 
 | 5655 |  | 
 | 5656 | HeapObject* HeapIterator::next() { | 
 | 5657 |   if (filter_ == NULL) return NextObject(); | 
 | 5658 |  | 
 | 5659 |   HeapObject* obj = NextObject(); | 
 | 5660 |   while (obj != NULL && filter_->SkipObject(obj)) obj = NextObject(); | 
 | 5661 |   return obj; | 
 | 5662 | } | 
 | 5663 |  | 
 | 5664 |  | 
 | 5665 | HeapObject* HeapIterator::NextObject() { | 
 | 5666 |   // No iterator means we are done. | 
 | 5667 |   if (object_iterator_ == NULL) return NULL; | 
 | 5668 |  | 
 | 5669 |   if (HeapObject* obj = object_iterator_->next_object()) { | 
 | 5670 |     // If the current iterator has more objects we are fine. | 
 | 5671 |     return obj; | 
 | 5672 |   } else { | 
 | 5673 |     // Go though the spaces looking for one that has objects. | 
 | 5674 |     while (space_iterator_->has_next()) { | 
 | 5675 |       object_iterator_ = space_iterator_->next(); | 
 | 5676 |       if (HeapObject* obj = object_iterator_->next_object()) { | 
 | 5677 |         return obj; | 
 | 5678 |       } | 
 | 5679 |     } | 
 | 5680 |   } | 
 | 5681 |   // Done with the last space. | 
 | 5682 |   object_iterator_ = NULL; | 
 | 5683 |   return NULL; | 
 | 5684 | } | 
 | 5685 |  | 
 | 5686 |  | 
 | 5687 | void HeapIterator::reset() { | 
 | 5688 |   // Restart the iterator. | 
 | 5689 |   Shutdown(); | 
 | 5690 |   Init(); | 
 | 5691 | } | 
 | 5692 |  | 
 | 5693 |  | 
 | 5694 | #ifdef DEBUG | 
 | 5695 |  | 
 | 5696 | Object* const PathTracer::kAnyGlobalObject = NULL; | 
 | 5697 |  | 
 | 5698 | class PathTracer::MarkVisitor : public ObjectVisitor { | 
 | 5699 |  public: | 
 | 5700 |   explicit MarkVisitor(PathTracer* tracer) : tracer_(tracer) {} | 
 | 5701 |   void VisitPointers(Object** start, Object** end) { | 
 | 5702 |     // Scan all HeapObject pointers in [start, end) | 
 | 5703 |     for (Object** p = start; !tracer_->found() && (p < end); p++) { | 
 | 5704 |       if ((*p)->IsHeapObject()) tracer_->MarkRecursively(p, this); | 
 | 5705 |     } | 
 | 5706 |   } | 
 | 5707 |  | 
 | 5708 |  private: | 
 | 5709 |   PathTracer* tracer_; | 
 | 5710 | }; | 
 | 5711 |  | 
 | 5712 |  | 
 | 5713 | class PathTracer::UnmarkVisitor : public ObjectVisitor { | 
 | 5714 |  public: | 
 | 5715 |   explicit UnmarkVisitor(PathTracer* tracer) : tracer_(tracer) {} | 
 | 5716 |   void VisitPointers(Object** start, Object** end) { | 
 | 5717 |     // Scan all HeapObject pointers in [start, end) | 
 | 5718 |     for (Object** p = start; p < end; p++) { | 
 | 5719 |       if ((*p)->IsHeapObject()) tracer_->UnmarkRecursively(p, this); | 
 | 5720 |     } | 
 | 5721 |   } | 
 | 5722 |  | 
 | 5723 |  private: | 
 | 5724 |   PathTracer* tracer_; | 
 | 5725 | }; | 
 | 5726 |  | 
 | 5727 |  | 
 | 5728 | void PathTracer::VisitPointers(Object** start, Object** end) { | 
 | 5729 |   bool done = ((what_to_find_ == FIND_FIRST) && found_target_); | 
 | 5730 |   // Visit all HeapObject pointers in [start, end) | 
 | 5731 |   for (Object** p = start; !done && (p < end); p++) { | 
 | 5732 |     if ((*p)->IsHeapObject()) { | 
 | 5733 |       TracePathFrom(p); | 
 | 5734 |       done = ((what_to_find_ == FIND_FIRST) && found_target_); | 
 | 5735 |     } | 
 | 5736 |   } | 
 | 5737 | } | 
 | 5738 |  | 
 | 5739 |  | 
 | 5740 | void PathTracer::Reset() { | 
 | 5741 |   found_target_ = false; | 
 | 5742 |   object_stack_.Clear(); | 
 | 5743 | } | 
 | 5744 |  | 
 | 5745 |  | 
 | 5746 | void PathTracer::TracePathFrom(Object** root) { | 
 | 5747 |   DCHECK((search_target_ == kAnyGlobalObject) || | 
 | 5748 |          search_target_->IsHeapObject()); | 
 | 5749 |   found_target_in_trace_ = false; | 
 | 5750 |   Reset(); | 
 | 5751 |  | 
 | 5752 |   MarkVisitor mark_visitor(this); | 
 | 5753 |   MarkRecursively(root, &mark_visitor); | 
 | 5754 |  | 
 | 5755 |   UnmarkVisitor unmark_visitor(this); | 
 | 5756 |   UnmarkRecursively(root, &unmark_visitor); | 
 | 5757 |  | 
 | 5758 |   ProcessResults(); | 
 | 5759 | } | 
 | 5760 |  | 
 | 5761 |  | 
 | 5762 | static bool SafeIsNativeContext(HeapObject* obj) { | 
 | 5763 |   return obj->map() == obj->GetHeap()->raw_unchecked_native_context_map(); | 
 | 5764 | } | 
 | 5765 |  | 
 | 5766 |  | 
 | 5767 | void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) { | 
 | 5768 |   if (!(*p)->IsHeapObject()) return; | 
 | 5769 |  | 
 | 5770 |   HeapObject* obj = HeapObject::cast(*p); | 
 | 5771 |  | 
 | 5772 |   MapWord map_word = obj->map_word(); | 
 | 5773 |   if (!map_word.ToMap()->IsHeapObject()) return;  // visited before | 
 | 5774 |  | 
 | 5775 |   if (found_target_in_trace_) return;  // stop if target found | 
 | 5776 |   object_stack_.Add(obj); | 
 | 5777 |   if (((search_target_ == kAnyGlobalObject) && obj->IsJSGlobalObject()) || | 
 | 5778 |       (obj == search_target_)) { | 
 | 5779 |     found_target_in_trace_ = true; | 
 | 5780 |     found_target_ = true; | 
 | 5781 |     return; | 
 | 5782 |   } | 
 | 5783 |  | 
 | 5784 |   bool is_native_context = SafeIsNativeContext(obj); | 
 | 5785 |  | 
 | 5786 |   // not visited yet | 
 | 5787 |   Map* map = Map::cast(map_word.ToMap()); | 
 | 5788 |  | 
 | 5789 |   MapWord marked_map_word = | 
 | 5790 |       MapWord::FromRawValue(obj->map_word().ToRawValue() + kMarkTag); | 
 | 5791 |   obj->set_map_word(marked_map_word); | 
 | 5792 |  | 
 | 5793 |   // Scan the object body. | 
 | 5794 |   if (is_native_context && (visit_mode_ == VISIT_ONLY_STRONG)) { | 
 | 5795 |     // This is specialized to scan Context's properly. | 
 | 5796 |     Object** start = | 
 | 5797 |         reinterpret_cast<Object**>(obj->address() + Context::kHeaderSize); | 
 | 5798 |     Object** end = | 
 | 5799 |         reinterpret_cast<Object**>(obj->address() + Context::kHeaderSize + | 
 | 5800 |                                    Context::FIRST_WEAK_SLOT * kPointerSize); | 
 | 5801 |     mark_visitor->VisitPointers(start, end); | 
 | 5802 |   } else { | 
 | 5803 |     obj->IterateBody(map->instance_type(), obj->SizeFromMap(map), mark_visitor); | 
 | 5804 |   } | 
 | 5805 |  | 
 | 5806 |   // Scan the map after the body because the body is a lot more interesting | 
 | 5807 |   // when doing leak detection. | 
 | 5808 |   MarkRecursively(reinterpret_cast<Object**>(&map), mark_visitor); | 
 | 5809 |  | 
 | 5810 |   if (!found_target_in_trace_) {  // don't pop if found the target | 
 | 5811 |     object_stack_.RemoveLast(); | 
 | 5812 |   } | 
 | 5813 | } | 
 | 5814 |  | 
 | 5815 |  | 
 | 5816 | void PathTracer::UnmarkRecursively(Object** p, UnmarkVisitor* unmark_visitor) { | 
 | 5817 |   if (!(*p)->IsHeapObject()) return; | 
 | 5818 |  | 
 | 5819 |   HeapObject* obj = HeapObject::cast(*p); | 
 | 5820 |  | 
 | 5821 |   MapWord map_word = obj->map_word(); | 
 | 5822 |   if (map_word.ToMap()->IsHeapObject()) return;  // unmarked already | 
 | 5823 |  | 
 | 5824 |   MapWord unmarked_map_word = | 
 | 5825 |       MapWord::FromRawValue(map_word.ToRawValue() - kMarkTag); | 
 | 5826 |   obj->set_map_word(unmarked_map_word); | 
 | 5827 |  | 
 | 5828 |   Map* map = Map::cast(unmarked_map_word.ToMap()); | 
 | 5829 |  | 
 | 5830 |   UnmarkRecursively(reinterpret_cast<Object**>(&map), unmark_visitor); | 
 | 5831 |  | 
 | 5832 |   obj->IterateBody(map->instance_type(), obj->SizeFromMap(map), unmark_visitor); | 
 | 5833 | } | 
 | 5834 |  | 
 | 5835 |  | 
 | 5836 | void PathTracer::ProcessResults() { | 
 | 5837 |   if (found_target_) { | 
 | 5838 |     OFStream os(stdout); | 
 | 5839 |     os << "=====================================\n" | 
 | 5840 |        << "====        Path to object       ====\n" | 
 | 5841 |        << "=====================================\n\n"; | 
 | 5842 |  | 
 | 5843 |     DCHECK(!object_stack_.is_empty()); | 
 | 5844 |     for (int i = 0; i < object_stack_.length(); i++) { | 
 | 5845 |       if (i > 0) os << "\n     |\n     |\n     V\n\n"; | 
 | 5846 |       object_stack_[i]->Print(os); | 
 | 5847 |     } | 
 | 5848 |     os << "=====================================\n"; | 
 | 5849 |   } | 
 | 5850 | } | 
 | 5851 |  | 
 | 5852 |  | 
 | 5853 | // Triggers a depth-first traversal of reachable objects from one | 
 | 5854 | // given root object and finds a path to a specific heap object and | 
 | 5855 | // prints it. | 
 | 5856 | void Heap::TracePathToObjectFrom(Object* target, Object* root) { | 
 | 5857 |   PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL); | 
 | 5858 |   tracer.VisitPointer(&root); | 
 | 5859 | } | 
 | 5860 |  | 
 | 5861 |  | 
 | 5862 | // Triggers a depth-first traversal of reachable objects from roots | 
 | 5863 | // and finds a path to a specific heap object and prints it. | 
 | 5864 | void Heap::TracePathToObject(Object* target) { | 
 | 5865 |   PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL); | 
 | 5866 |   IterateRoots(&tracer, VISIT_ONLY_STRONG); | 
 | 5867 | } | 
 | 5868 |  | 
 | 5869 |  | 
 | 5870 | // Triggers a depth-first traversal of reachable objects from roots | 
 | 5871 | // and finds a path to any global object and prints it. Useful for | 
 | 5872 | // determining the source for leaks of global objects. | 
 | 5873 | void Heap::TracePathToGlobal() { | 
 | 5874 |   PathTracer tracer(PathTracer::kAnyGlobalObject, PathTracer::FIND_ALL, | 
 | 5875 |                     VISIT_ALL); | 
 | 5876 |   IterateRoots(&tracer, VISIT_ONLY_STRONG); | 
 | 5877 | } | 
 | 5878 | #endif | 
 | 5879 |  | 
 | 5880 |  | 
 | 5881 | void Heap::UpdateCumulativeGCStatistics(double duration, | 
 | 5882 |                                         double spent_in_mutator, | 
 | 5883 |                                         double marking_time) { | 
 | 5884 |   if (FLAG_print_cumulative_gc_stat) { | 
 | 5885 |     total_gc_time_ms_ += duration; | 
 | 5886 |     max_gc_pause_ = Max(max_gc_pause_, duration); | 
 | 5887 |     max_alive_after_gc_ = Max(max_alive_after_gc_, SizeOfObjects()); | 
 | 5888 |     min_in_mutator_ = Min(min_in_mutator_, spent_in_mutator); | 
 | 5889 |   } else if (FLAG_trace_gc_verbose) { | 
 | 5890 |     total_gc_time_ms_ += duration; | 
 | 5891 |   } | 
 | 5892 |  | 
 | 5893 |   marking_time_ += marking_time; | 
 | 5894 | } | 
 | 5895 |  | 
 | 5896 |  | 
 | 5897 | int KeyedLookupCache::Hash(Handle<Map> map, Handle<Name> name) { | 
 | 5898 |   DisallowHeapAllocation no_gc; | 
 | 5899 |   // Uses only lower 32 bits if pointers are larger. | 
 | 5900 |   uintptr_t addr_hash = | 
 | 5901 |       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(*map)) >> kMapHashShift; | 
 | 5902 |   return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask); | 
 | 5903 | } | 
 | 5904 |  | 
 | 5905 |  | 
 | 5906 | int KeyedLookupCache::Lookup(Handle<Map> map, Handle<Name> name) { | 
 | 5907 |   DisallowHeapAllocation no_gc; | 
 | 5908 |   int index = (Hash(map, name) & kHashMask); | 
 | 5909 |   for (int i = 0; i < kEntriesPerBucket; i++) { | 
 | 5910 |     Key& key = keys_[index + i]; | 
 | 5911 |     if ((key.map == *map) && key.name->Equals(*name)) { | 
 | 5912 |       return field_offsets_[index + i]; | 
 | 5913 |     } | 
 | 5914 |   } | 
 | 5915 |   return kNotFound; | 
 | 5916 | } | 
 | 5917 |  | 
 | 5918 |  | 
 | 5919 | void KeyedLookupCache::Update(Handle<Map> map, Handle<Name> name, | 
 | 5920 |                               int field_offset) { | 
 | 5921 |   DisallowHeapAllocation no_gc; | 
 | 5922 |   if (!name->IsUniqueName()) { | 
 | 5923 |     if (!StringTable::InternalizeStringIfExists( | 
 | 5924 |              name->GetIsolate(), Handle<String>::cast(name)).ToHandle(&name)) { | 
 | 5925 |       return; | 
 | 5926 |     } | 
 | 5927 |   } | 
 | 5928 |   // This cache is cleared only between mark compact passes, so we expect the | 
 | 5929 |   // cache to only contain old space names. | 
 | 5930 |   DCHECK(!map->GetIsolate()->heap()->InNewSpace(*name)); | 
 | 5931 |  | 
 | 5932 |   int index = (Hash(map, name) & kHashMask); | 
 | 5933 |   // After a GC there will be free slots, so we use them in order (this may | 
 | 5934 |   // help to get the most frequently used one in position 0). | 
 | 5935 |   for (int i = 0; i < kEntriesPerBucket; i++) { | 
 | 5936 |     Key& key = keys_[index]; | 
 | 5937 |     Object* free_entry_indicator = NULL; | 
 | 5938 |     if (key.map == free_entry_indicator) { | 
 | 5939 |       key.map = *map; | 
 | 5940 |       key.name = *name; | 
 | 5941 |       field_offsets_[index + i] = field_offset; | 
 | 5942 |       return; | 
 | 5943 |     } | 
 | 5944 |   } | 
 | 5945 |   // No free entry found in this bucket, so we move them all down one and | 
 | 5946 |   // put the new entry at position zero. | 
 | 5947 |   for (int i = kEntriesPerBucket - 1; i > 0; i--) { | 
 | 5948 |     Key& key = keys_[index + i]; | 
 | 5949 |     Key& key2 = keys_[index + i - 1]; | 
 | 5950 |     key = key2; | 
 | 5951 |     field_offsets_[index + i] = field_offsets_[index + i - 1]; | 
 | 5952 |   } | 
 | 5953 |  | 
 | 5954 |   // Write the new first entry. | 
 | 5955 |   Key& key = keys_[index]; | 
 | 5956 |   key.map = *map; | 
 | 5957 |   key.name = *name; | 
 | 5958 |   field_offsets_[index] = field_offset; | 
 | 5959 | } | 
 | 5960 |  | 
 | 5961 |  | 
 | 5962 | void KeyedLookupCache::Clear() { | 
 | 5963 |   for (int index = 0; index < kLength; index++) keys_[index].map = NULL; | 
 | 5964 | } | 
 | 5965 |  | 
 | 5966 |  | 
 | 5967 | void DescriptorLookupCache::Clear() { | 
 | 5968 |   for (int index = 0; index < kLength; index++) keys_[index].source = NULL; | 
 | 5969 | } | 
 | 5970 |  | 
 | 5971 |  | 
 | 5972 | void ExternalStringTable::CleanUp() { | 
 | 5973 |   int last = 0; | 
 | 5974 |   for (int i = 0; i < new_space_strings_.length(); ++i) { | 
 | 5975 |     if (new_space_strings_[i] == heap_->the_hole_value()) { | 
 | 5976 |       continue; | 
 | 5977 |     } | 
 | 5978 |     DCHECK(new_space_strings_[i]->IsExternalString()); | 
 | 5979 |     if (heap_->InNewSpace(new_space_strings_[i])) { | 
 | 5980 |       new_space_strings_[last++] = new_space_strings_[i]; | 
 | 5981 |     } else { | 
 | 5982 |       old_space_strings_.Add(new_space_strings_[i]); | 
 | 5983 |     } | 
 | 5984 |   } | 
 | 5985 |   new_space_strings_.Rewind(last); | 
 | 5986 |   new_space_strings_.Trim(); | 
 | 5987 |  | 
 | 5988 |   last = 0; | 
 | 5989 |   for (int i = 0; i < old_space_strings_.length(); ++i) { | 
 | 5990 |     if (old_space_strings_[i] == heap_->the_hole_value()) { | 
 | 5991 |       continue; | 
 | 5992 |     } | 
 | 5993 |     DCHECK(old_space_strings_[i]->IsExternalString()); | 
 | 5994 |     DCHECK(!heap_->InNewSpace(old_space_strings_[i])); | 
 | 5995 |     old_space_strings_[last++] = old_space_strings_[i]; | 
 | 5996 |   } | 
 | 5997 |   old_space_strings_.Rewind(last); | 
 | 5998 |   old_space_strings_.Trim(); | 
 | 5999 | #ifdef VERIFY_HEAP | 
 | 6000 |   if (FLAG_verify_heap) { | 
 | 6001 |     Verify(); | 
 | 6002 |   } | 
 | 6003 | #endif | 
 | 6004 | } | 
 | 6005 |  | 
 | 6006 |  | 
 | 6007 | void ExternalStringTable::TearDown() { | 
 | 6008 |   for (int i = 0; i < new_space_strings_.length(); ++i) { | 
 | 6009 |     heap_->FinalizeExternalString(ExternalString::cast(new_space_strings_[i])); | 
 | 6010 |   } | 
 | 6011 |   new_space_strings_.Free(); | 
 | 6012 |   for (int i = 0; i < old_space_strings_.length(); ++i) { | 
 | 6013 |     heap_->FinalizeExternalString(ExternalString::cast(old_space_strings_[i])); | 
 | 6014 |   } | 
 | 6015 |   old_space_strings_.Free(); | 
 | 6016 | } | 
 | 6017 |  | 
 | 6018 |  | 
 | 6019 | void Heap::QueueMemoryChunkForFree(MemoryChunk* chunk) { | 
 | 6020 |   chunk->set_next_chunk(chunks_queued_for_free_); | 
 | 6021 |   chunks_queued_for_free_ = chunk; | 
 | 6022 | } | 
 | 6023 |  | 
 | 6024 |  | 
 | 6025 | void Heap::FreeQueuedChunks() { | 
 | 6026 |   if (chunks_queued_for_free_ == NULL) return; | 
 | 6027 |   MemoryChunk* next; | 
 | 6028 |   MemoryChunk* chunk; | 
 | 6029 |   for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) { | 
 | 6030 |     next = chunk->next_chunk(); | 
 | 6031 |     chunk->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED); | 
 | 6032 |  | 
 | 6033 |     if (chunk->owner()->identity() == LO_SPACE) { | 
 | 6034 |       // StoreBuffer::Filter relies on MemoryChunk::FromAnyPointerAddress. | 
 | 6035 |       // If FromAnyPointerAddress encounters a slot that belongs to a large | 
 | 6036 |       // chunk queued for deletion it will fail to find the chunk because | 
 | 6037 |       // it try to perform a search in the list of pages owned by of the large | 
 | 6038 |       // object space and queued chunks were detached from that list. | 
 | 6039 |       // To work around this we split large chunk into normal kPageSize aligned | 
 | 6040 |       // pieces and initialize size, owner and flags field of every piece. | 
 | 6041 |       // If FromAnyPointerAddress encounters a slot that belongs to one of | 
 | 6042 |       // these smaller pieces it will treat it as a slot on a normal Page. | 
 | 6043 |       Address chunk_end = chunk->address() + chunk->size(); | 
 | 6044 |       MemoryChunk* inner = | 
 | 6045 |           MemoryChunk::FromAddress(chunk->address() + Page::kPageSize); | 
 | 6046 |       MemoryChunk* inner_last = MemoryChunk::FromAddress(chunk_end - 1); | 
 | 6047 |       while (inner <= inner_last) { | 
 | 6048 |         // Size of a large chunk is always a multiple of | 
 | 6049 |         // OS::AllocateAlignment() so there is always | 
 | 6050 |         // enough space for a fake MemoryChunk header. | 
 | 6051 |         Address area_end = Min(inner->address() + Page::kPageSize, chunk_end); | 
 | 6052 |         // Guard against overflow. | 
 | 6053 |         if (area_end < inner->address()) area_end = chunk_end; | 
 | 6054 |         inner->SetArea(inner->address(), area_end); | 
 | 6055 |         inner->set_size(Page::kPageSize); | 
 | 6056 |         inner->set_owner(lo_space()); | 
 | 6057 |         inner->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED); | 
 | 6058 |         inner = MemoryChunk::FromAddress(inner->address() + Page::kPageSize); | 
 | 6059 |       } | 
 | 6060 |     } | 
 | 6061 |   } | 
 | 6062 |   isolate_->heap()->store_buffer()->Compact(); | 
 | 6063 |   isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED); | 
 | 6064 |   for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) { | 
 | 6065 |     next = chunk->next_chunk(); | 
 | 6066 |     isolate_->memory_allocator()->Free(chunk); | 
 | 6067 |   } | 
 | 6068 |   chunks_queued_for_free_ = NULL; | 
 | 6069 | } | 
 | 6070 |  | 
 | 6071 |  | 
 | 6072 | void Heap::RememberUnmappedPage(Address page, bool compacted) { | 
 | 6073 |   uintptr_t p = reinterpret_cast<uintptr_t>(page); | 
 | 6074 |   // Tag the page pointer to make it findable in the dump file. | 
 | 6075 |   if (compacted) { | 
 | 6076 |     p ^= 0xc1ead & (Page::kPageSize - 1);  // Cleared. | 
 | 6077 |   } else { | 
 | 6078 |     p ^= 0x1d1ed & (Page::kPageSize - 1);  // I died. | 
 | 6079 |   } | 
 | 6080 |   remembered_unmapped_pages_[remembered_unmapped_pages_index_] = | 
 | 6081 |       reinterpret_cast<Address>(p); | 
 | 6082 |   remembered_unmapped_pages_index_++; | 
 | 6083 |   remembered_unmapped_pages_index_ %= kRememberedUnmappedPages; | 
 | 6084 | } | 
 | 6085 |  | 
 | 6086 |  | 
 | 6087 | void Heap::ClearObjectStats(bool clear_last_time_stats) { | 
 | 6088 |   memset(object_counts_, 0, sizeof(object_counts_)); | 
 | 6089 |   memset(object_sizes_, 0, sizeof(object_sizes_)); | 
 | 6090 |   if (clear_last_time_stats) { | 
 | 6091 |     memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_)); | 
 | 6092 |     memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_)); | 
 | 6093 |   } | 
 | 6094 | } | 
 | 6095 |  | 
 | 6096 |  | 
 | 6097 | static base::LazyMutex checkpoint_object_stats_mutex = LAZY_MUTEX_INITIALIZER; | 
 | 6098 |  | 
 | 6099 |  | 
 | 6100 | void Heap::CheckpointObjectStats() { | 
 | 6101 |   base::LockGuard<base::Mutex> lock_guard( | 
 | 6102 |       checkpoint_object_stats_mutex.Pointer()); | 
 | 6103 |   Counters* counters = isolate()->counters(); | 
 | 6104 | #define ADJUST_LAST_TIME_OBJECT_COUNT(name)              \ | 
 | 6105 |   counters->count_of_##name()->Increment(                \ | 
 | 6106 |       static_cast<int>(object_counts_[name]));           \ | 
 | 6107 |   counters->count_of_##name()->Decrement(                \ | 
 | 6108 |       static_cast<int>(object_counts_last_time_[name])); \ | 
 | 6109 |   counters->size_of_##name()->Increment(                 \ | 
 | 6110 |       static_cast<int>(object_sizes_[name]));            \ | 
 | 6111 |   counters->size_of_##name()->Decrement(                 \ | 
 | 6112 |       static_cast<int>(object_sizes_last_time_[name])); | 
 | 6113 |   INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT) | 
 | 6114 | #undef ADJUST_LAST_TIME_OBJECT_COUNT | 
 | 6115 |   int index; | 
 | 6116 | #define ADJUST_LAST_TIME_OBJECT_COUNT(name)               \ | 
 | 6117 |   index = FIRST_CODE_KIND_SUB_TYPE + Code::name;          \ | 
 | 6118 |   counters->count_of_CODE_TYPE_##name()->Increment(       \ | 
 | 6119 |       static_cast<int>(object_counts_[index]));           \ | 
 | 6120 |   counters->count_of_CODE_TYPE_##name()->Decrement(       \ | 
 | 6121 |       static_cast<int>(object_counts_last_time_[index])); \ | 
 | 6122 |   counters->size_of_CODE_TYPE_##name()->Increment(        \ | 
 | 6123 |       static_cast<int>(object_sizes_[index]));            \ | 
 | 6124 |   counters->size_of_CODE_TYPE_##name()->Decrement(        \ | 
 | 6125 |       static_cast<int>(object_sizes_last_time_[index])); | 
 | 6126 |   CODE_KIND_LIST(ADJUST_LAST_TIME_OBJECT_COUNT) | 
 | 6127 | #undef ADJUST_LAST_TIME_OBJECT_COUNT | 
 | 6128 | #define ADJUST_LAST_TIME_OBJECT_COUNT(name)               \ | 
 | 6129 |   index = FIRST_FIXED_ARRAY_SUB_TYPE + name;              \ | 
 | 6130 |   counters->count_of_FIXED_ARRAY_##name()->Increment(     \ | 
 | 6131 |       static_cast<int>(object_counts_[index]));           \ | 
 | 6132 |   counters->count_of_FIXED_ARRAY_##name()->Decrement(     \ | 
 | 6133 |       static_cast<int>(object_counts_last_time_[index])); \ | 
 | 6134 |   counters->size_of_FIXED_ARRAY_##name()->Increment(      \ | 
 | 6135 |       static_cast<int>(object_sizes_[index]));            \ | 
 | 6136 |   counters->size_of_FIXED_ARRAY_##name()->Decrement(      \ | 
 | 6137 |       static_cast<int>(object_sizes_last_time_[index])); | 
 | 6138 |   FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT) | 
 | 6139 | #undef ADJUST_LAST_TIME_OBJECT_COUNT | 
 | 6140 | #define ADJUST_LAST_TIME_OBJECT_COUNT(name)                                   \ | 
 | 6141 |   index =                                                                     \ | 
 | 6142 |       FIRST_CODE_AGE_SUB_TYPE + Code::k##name##CodeAge - Code::kFirstCodeAge; \ | 
 | 6143 |   counters->count_of_CODE_AGE_##name()->Increment(                            \ | 
 | 6144 |       static_cast<int>(object_counts_[index]));                               \ | 
 | 6145 |   counters->count_of_CODE_AGE_##name()->Decrement(                            \ | 
 | 6146 |       static_cast<int>(object_counts_last_time_[index]));                     \ | 
 | 6147 |   counters->size_of_CODE_AGE_##name()->Increment(                             \ | 
 | 6148 |       static_cast<int>(object_sizes_[index]));                                \ | 
 | 6149 |   counters->size_of_CODE_AGE_##name()->Decrement(                             \ | 
 | 6150 |       static_cast<int>(object_sizes_last_time_[index])); | 
 | 6151 |   CODE_AGE_LIST_COMPLETE(ADJUST_LAST_TIME_OBJECT_COUNT) | 
 | 6152 | #undef ADJUST_LAST_TIME_OBJECT_COUNT | 
 | 6153 |  | 
 | 6154 |   MemCopy(object_counts_last_time_, object_counts_, sizeof(object_counts_)); | 
 | 6155 |   MemCopy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_)); | 
 | 6156 |   ClearObjectStats(); | 
 | 6157 | } | 
 | 6158 | } | 
 | 6159 | }  // namespace v8::internal |