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 #ifndef V8_HEAP_HEAP_INL_H_ 6 #define V8_HEAP_HEAP_INL_H_ 7 8 #include <cmath> 9 10 #include "src/base/platform/platform.h" 11 #include "src/counters.h" 12 #include "src/heap/heap.h" 13 #include "src/heap/incremental-marking-inl.h" 14 #include "src/heap/mark-compact.h" 15 #include "src/heap/spaces-inl.h" 16 #include "src/heap/store-buffer.h" 17 #include "src/heap/store-buffer-inl.h" 18 #include "src/isolate.h" 19 #include "src/list-inl.h" 20 #include "src/log.h" 21 #include "src/msan.h" 22 #include "src/objects-inl.h" 23 #include "src/type-feedback-vector-inl.h" 24 25 namespace v8 { 26 namespace internal { 27 28 void PromotionQueue::insert(HeapObject* target, int size) { 29 if (emergency_stack_ != NULL) { 30 emergency_stack_->Add(Entry(target, size)); 31 return; 32 } 33 34 if ((rear_ - 2) < limit_) { 35 RelocateQueueHead(); 36 emergency_stack_->Add(Entry(target, size)); 37 return; 38 } 39 40 *(--rear_) = reinterpret_cast<intptr_t>(target); 41 *(--rear_) = size; 42 // Assert no overflow into live objects. 43 #ifdef DEBUG 44 SemiSpace::AssertValidRange(target->GetIsolate()->heap()->new_space()->top(), 45 reinterpret_cast<Address>(rear_)); 46 #endif 47 } 48 49 50 #define ROOT_ACCESSOR(type, name, camel_name) \ 51 type* Heap::name() { return type::cast(roots_[k##camel_name##RootIndex]); } 52 ROOT_LIST(ROOT_ACCESSOR) 53 #undef ROOT_ACCESSOR 54 55 #define STRUCT_MAP_ACCESSOR(NAME, Name, name) \ 56 Map* Heap::name##_map() { return Map::cast(roots_[k##Name##MapRootIndex]); } 57 STRUCT_LIST(STRUCT_MAP_ACCESSOR) 58 #undef STRUCT_MAP_ACCESSOR 59 60 #define STRING_ACCESSOR(name, str) \ 61 String* Heap::name() { return String::cast(roots_[k##name##RootIndex]); } 62 INTERNALIZED_STRING_LIST(STRING_ACCESSOR) 63 #undef STRING_ACCESSOR 64 65 #define SYMBOL_ACCESSOR(name) \ 66 Symbol* Heap::name() { return Symbol::cast(roots_[k##name##RootIndex]); } 67 PRIVATE_SYMBOL_LIST(SYMBOL_ACCESSOR) 68 #undef SYMBOL_ACCESSOR 69 70 #define SYMBOL_ACCESSOR(name, description) \ 71 Symbol* Heap::name() { return Symbol::cast(roots_[k##name##RootIndex]); } 72 PUBLIC_SYMBOL_LIST(SYMBOL_ACCESSOR) 73 WELL_KNOWN_SYMBOL_LIST(SYMBOL_ACCESSOR) 74 #undef SYMBOL_ACCESSOR 75 76 #define ROOT_ACCESSOR(type, name, camel_name) \ 77 void Heap::set_##name(type* value) { \ 78 /* The deserializer makes use of the fact that these common roots are */ \ 79 /* never in new space and never on a page that is being compacted. */ \ 80 DCHECK(!deserialization_complete() || \ 81 RootCanBeWrittenAfterInitialization(k##camel_name##RootIndex)); \ 82 DCHECK(k##camel_name##RootIndex >= kOldSpaceRoots || !InNewSpace(value)); \ 83 roots_[k##camel_name##RootIndex] = value; \ 84 } 85 ROOT_LIST(ROOT_ACCESSOR) 86 #undef ROOT_ACCESSOR 87 88 89 template <> 90 bool inline Heap::IsOneByte(Vector<const char> str, int chars) { 91 // TODO(dcarney): incorporate Latin-1 check when Latin-1 is supported? 92 return chars == str.length(); 93 } 94 95 96 template <> 97 bool inline Heap::IsOneByte(String* str, int chars) { 98 return str->IsOneByteRepresentation(); 99 } 100 101 102 AllocationResult Heap::AllocateInternalizedStringFromUtf8( 103 Vector<const char> str, int chars, uint32_t hash_field) { 104 if (IsOneByte(str, chars)) { 105 return AllocateOneByteInternalizedString(Vector<const uint8_t>::cast(str), 106 hash_field); 107 } 108 return AllocateInternalizedStringImpl<false>(str, chars, hash_field); 109 } 110 111 112 template <typename T> 113 AllocationResult Heap::AllocateInternalizedStringImpl(T t, int chars, 114 uint32_t hash_field) { 115 if (IsOneByte(t, chars)) { 116 return AllocateInternalizedStringImpl<true>(t, chars, hash_field); 117 } 118 return AllocateInternalizedStringImpl<false>(t, chars, hash_field); 119 } 120 121 122 AllocationResult Heap::AllocateOneByteInternalizedString( 123 Vector<const uint8_t> str, uint32_t hash_field) { 124 CHECK_GE(String::kMaxLength, str.length()); 125 // Compute map and object size. 126 Map* map = one_byte_internalized_string_map(); 127 int size = SeqOneByteString::SizeFor(str.length()); 128 129 // Allocate string. 130 HeapObject* result = nullptr; 131 { 132 AllocationResult allocation = AllocateRaw(size, OLD_SPACE); 133 if (!allocation.To(&result)) return allocation; 134 } 135 136 // String maps are all immortal immovable objects. 137 result->set_map_no_write_barrier(map); 138 // Set length and hash fields of the allocated string. 139 String* answer = String::cast(result); 140 answer->set_length(str.length()); 141 answer->set_hash_field(hash_field); 142 143 DCHECK_EQ(size, answer->Size()); 144 145 // Fill in the characters. 146 MemCopy(answer->address() + SeqOneByteString::kHeaderSize, str.start(), 147 str.length()); 148 149 return answer; 150 } 151 152 153 AllocationResult Heap::AllocateTwoByteInternalizedString(Vector<const uc16> str, 154 uint32_t hash_field) { 155 CHECK_GE(String::kMaxLength, str.length()); 156 // Compute map and object size. 157 Map* map = internalized_string_map(); 158 int size = SeqTwoByteString::SizeFor(str.length()); 159 160 // Allocate string. 161 HeapObject* result = nullptr; 162 { 163 AllocationResult allocation = AllocateRaw(size, OLD_SPACE); 164 if (!allocation.To(&result)) return allocation; 165 } 166 167 result->set_map(map); 168 // Set length and hash fields of the allocated string. 169 String* answer = String::cast(result); 170 answer->set_length(str.length()); 171 answer->set_hash_field(hash_field); 172 173 DCHECK_EQ(size, answer->Size()); 174 175 // Fill in the characters. 176 MemCopy(answer->address() + SeqTwoByteString::kHeaderSize, str.start(), 177 str.length() * kUC16Size); 178 179 return answer; 180 } 181 182 AllocationResult Heap::CopyFixedArray(FixedArray* src) { 183 if (src->length() == 0) return src; 184 return CopyFixedArrayWithMap(src, src->map()); 185 } 186 187 188 AllocationResult Heap::CopyFixedDoubleArray(FixedDoubleArray* src) { 189 if (src->length() == 0) return src; 190 return CopyFixedDoubleArrayWithMap(src, src->map()); 191 } 192 193 194 AllocationResult Heap::AllocateRaw(int size_in_bytes, AllocationSpace space, 195 AllocationAlignment alignment) { 196 DCHECK(AllowHandleAllocation::IsAllowed()); 197 DCHECK(AllowHeapAllocation::IsAllowed()); 198 DCHECK(gc_state_ == NOT_IN_GC); 199 #ifdef DEBUG 200 if (FLAG_gc_interval >= 0 && !always_allocate() && 201 Heap::allocation_timeout_-- <= 0) { 202 return AllocationResult::Retry(space); 203 } 204 isolate_->counters()->objs_since_last_full()->Increment(); 205 isolate_->counters()->objs_since_last_young()->Increment(); 206 #endif 207 208 bool large_object = size_in_bytes > Page::kMaxRegularHeapObjectSize; 209 HeapObject* object = nullptr; 210 AllocationResult allocation; 211 if (NEW_SPACE == space) { 212 if (large_object) { 213 space = LO_SPACE; 214 } else { 215 allocation = new_space_.AllocateRaw(size_in_bytes, alignment); 216 if (allocation.To(&object)) { 217 OnAllocationEvent(object, size_in_bytes); 218 } 219 return allocation; 220 } 221 } 222 223 // Here we only allocate in the old generation. 224 if (OLD_SPACE == space) { 225 if (large_object) { 226 allocation = lo_space_->AllocateRaw(size_in_bytes, NOT_EXECUTABLE); 227 } else { 228 allocation = old_space_->AllocateRaw(size_in_bytes, alignment); 229 } 230 } else if (CODE_SPACE == space) { 231 if (size_in_bytes <= code_space()->AreaSize()) { 232 allocation = code_space_->AllocateRawUnaligned(size_in_bytes); 233 } else { 234 allocation = lo_space_->AllocateRaw(size_in_bytes, EXECUTABLE); 235 } 236 } else if (LO_SPACE == space) { 237 DCHECK(large_object); 238 allocation = lo_space_->AllocateRaw(size_in_bytes, NOT_EXECUTABLE); 239 } else if (MAP_SPACE == space) { 240 allocation = map_space_->AllocateRawUnaligned(size_in_bytes); 241 } else { 242 // NEW_SPACE is not allowed here. 243 UNREACHABLE(); 244 } 245 if (allocation.To(&object)) { 246 OnAllocationEvent(object, size_in_bytes); 247 } else { 248 old_gen_exhausted_ = true; 249 } 250 return allocation; 251 } 252 253 254 void Heap::OnAllocationEvent(HeapObject* object, int size_in_bytes) { 255 HeapProfiler* profiler = isolate_->heap_profiler(); 256 if (profiler->is_tracking_allocations()) { 257 profiler->AllocationEvent(object->address(), size_in_bytes); 258 } 259 260 if (FLAG_verify_predictable) { 261 ++allocations_count_; 262 // Advance synthetic time by making a time request. 263 MonotonicallyIncreasingTimeInMs(); 264 265 UpdateAllocationsHash(object); 266 UpdateAllocationsHash(size_in_bytes); 267 268 if (allocations_count_ % FLAG_dump_allocations_digest_at_alloc == 0) { 269 PrintAlloctionsHash(); 270 } 271 } 272 273 if (FLAG_trace_allocation_stack_interval > 0) { 274 if (!FLAG_verify_predictable) ++allocations_count_; 275 if (allocations_count_ % FLAG_trace_allocation_stack_interval == 0) { 276 isolate()->PrintStack(stdout, Isolate::kPrintStackConcise); 277 } 278 } 279 } 280 281 282 void Heap::OnMoveEvent(HeapObject* target, HeapObject* source, 283 int size_in_bytes) { 284 HeapProfiler* heap_profiler = isolate_->heap_profiler(); 285 if (heap_profiler->is_tracking_object_moves()) { 286 heap_profiler->ObjectMoveEvent(source->address(), target->address(), 287 size_in_bytes); 288 } 289 if (target->IsSharedFunctionInfo()) { 290 LOG_CODE_EVENT(isolate_, SharedFunctionInfoMoveEvent(source->address(), 291 target->address())); 292 } 293 294 if (FLAG_verify_predictable) { 295 ++allocations_count_; 296 // Advance synthetic time by making a time request. 297 MonotonicallyIncreasingTimeInMs(); 298 299 UpdateAllocationsHash(source); 300 UpdateAllocationsHash(target); 301 UpdateAllocationsHash(size_in_bytes); 302 303 if (allocations_count_ % FLAG_dump_allocations_digest_at_alloc == 0) { 304 PrintAlloctionsHash(); 305 } 306 } 307 } 308 309 310 void Heap::UpdateAllocationsHash(HeapObject* object) { 311 Address object_address = object->address(); 312 MemoryChunk* memory_chunk = MemoryChunk::FromAddress(object_address); 313 AllocationSpace allocation_space = memory_chunk->owner()->identity(); 314 315 STATIC_ASSERT(kSpaceTagSize + kPageSizeBits <= 32); 316 uint32_t value = 317 static_cast<uint32_t>(object_address - memory_chunk->address()) | 318 (static_cast<uint32_t>(allocation_space) << kPageSizeBits); 319 320 UpdateAllocationsHash(value); 321 } 322 323 324 void Heap::UpdateAllocationsHash(uint32_t value) { 325 uint16_t c1 = static_cast<uint16_t>(value); 326 uint16_t c2 = static_cast<uint16_t>(value >> 16); 327 raw_allocations_hash_ = 328 StringHasher::AddCharacterCore(raw_allocations_hash_, c1); 329 raw_allocations_hash_ = 330 StringHasher::AddCharacterCore(raw_allocations_hash_, c2); 331 } 332 333 334 void Heap::RegisterExternalString(String* string) { 335 external_string_table_.AddString(string); 336 } 337 338 339 void Heap::FinalizeExternalString(String* string) { 340 DCHECK(string->IsExternalString()); 341 v8::String::ExternalStringResourceBase** resource_addr = 342 reinterpret_cast<v8::String::ExternalStringResourceBase**>( 343 reinterpret_cast<byte*>(string) + ExternalString::kResourceOffset - 344 kHeapObjectTag); 345 346 // Dispose of the C++ object if it has not already been disposed. 347 if (*resource_addr != NULL) { 348 (*resource_addr)->Dispose(); 349 *resource_addr = NULL; 350 } 351 } 352 353 354 bool Heap::InNewSpace(Object* object) { 355 bool result = new_space_.Contains(object); 356 DCHECK(!result || // Either not in new space 357 gc_state_ != NOT_IN_GC || // ... or in the middle of GC 358 InToSpace(object)); // ... or in to-space (where we allocate). 359 return result; 360 } 361 362 363 bool Heap::InNewSpace(Address address) { return new_space_.Contains(address); } 364 365 366 bool Heap::InFromSpace(Object* object) { 367 return new_space_.FromSpaceContains(object); 368 } 369 370 371 bool Heap::InToSpace(Object* object) { 372 return new_space_.ToSpaceContains(object); 373 } 374 375 376 bool Heap::InOldSpace(Address address) { return old_space_->Contains(address); } 377 378 379 bool Heap::InOldSpace(Object* object) { 380 return InOldSpace(reinterpret_cast<Address>(object)); 381 } 382 383 384 bool Heap::OldGenerationAllocationLimitReached() { 385 if (!incremental_marking()->IsStopped()) return false; 386 return OldGenerationSpaceAvailable() < 0; 387 } 388 389 390 bool Heap::ShouldBePromoted(Address old_address, int object_size) { 391 NewSpacePage* page = NewSpacePage::FromAddress(old_address); 392 Address age_mark = new_space_.age_mark(); 393 return page->IsFlagSet(MemoryChunk::NEW_SPACE_BELOW_AGE_MARK) && 394 (!page->ContainsLimit(age_mark) || old_address < age_mark); 395 } 396 397 398 void Heap::RecordWrite(Address address, int offset) { 399 if (!InNewSpace(address)) store_buffer_.Mark(address + offset); 400 } 401 402 403 void Heap::RecordWrites(Address address, int start, int len) { 404 if (!InNewSpace(address)) { 405 for (int i = 0; i < len; i++) { 406 store_buffer_.Mark(address + start + i * kPointerSize); 407 } 408 } 409 } 410 411 412 bool Heap::AllowedToBeMigrated(HeapObject* obj, AllocationSpace dst) { 413 // Object migration is governed by the following rules: 414 // 415 // 1) Objects in new-space can be migrated to the old space 416 // that matches their target space or they stay in new-space. 417 // 2) Objects in old-space stay in the same space when migrating. 418 // 3) Fillers (two or more words) can migrate due to left-trimming of 419 // fixed arrays in new-space or old space. 420 // 4) Fillers (one word) can never migrate, they are skipped by 421 // incremental marking explicitly to prevent invalid pattern. 422 // 423 // Since this function is used for debugging only, we do not place 424 // asserts here, but check everything explicitly. 425 if (obj->map() == one_pointer_filler_map()) return false; 426 InstanceType type = obj->map()->instance_type(); 427 MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); 428 AllocationSpace src = chunk->owner()->identity(); 429 switch (src) { 430 case NEW_SPACE: 431 return dst == src || dst == OLD_SPACE; 432 case OLD_SPACE: 433 return dst == src && 434 (dst == OLD_SPACE || obj->IsFiller() || obj->IsExternalString()); 435 case CODE_SPACE: 436 return dst == src && type == CODE_TYPE; 437 case MAP_SPACE: 438 case LO_SPACE: 439 return false; 440 } 441 UNREACHABLE(); 442 return false; 443 } 444 445 446 void Heap::CopyBlock(Address dst, Address src, int byte_size) { 447 CopyWords(reinterpret_cast<Object**>(dst), reinterpret_cast<Object**>(src), 448 static_cast<size_t>(byte_size / kPointerSize)); 449 } 450 451 452 void Heap::MoveBlock(Address dst, Address src, int byte_size) { 453 DCHECK(IsAligned(byte_size, kPointerSize)); 454 455 int size_in_words = byte_size / kPointerSize; 456 457 if ((dst < src) || (dst >= (src + byte_size))) { 458 Object** src_slot = reinterpret_cast<Object**>(src); 459 Object** dst_slot = reinterpret_cast<Object**>(dst); 460 Object** end_slot = src_slot + size_in_words; 461 462 while (src_slot != end_slot) { 463 *dst_slot++ = *src_slot++; 464 } 465 } else { 466 MemMove(dst, src, static_cast<size_t>(byte_size)); 467 } 468 } 469 470 471 AllocationMemento* Heap::FindAllocationMemento(HeapObject* object) { 472 // Check if there is potentially a memento behind the object. If 473 // the last word of the memento is on another page we return 474 // immediately. 475 Address object_address = object->address(); 476 Address memento_address = object_address + object->Size(); 477 Address last_memento_word_address = memento_address + kPointerSize; 478 if (!NewSpacePage::OnSamePage(object_address, last_memento_word_address)) { 479 return NULL; 480 } 481 482 HeapObject* candidate = HeapObject::FromAddress(memento_address); 483 Map* candidate_map = candidate->map(); 484 // This fast check may peek at an uninitialized word. However, the slow check 485 // below (memento_address == top) ensures that this is safe. Mark the word as 486 // initialized to silence MemorySanitizer warnings. 487 MSAN_MEMORY_IS_INITIALIZED(&candidate_map, sizeof(candidate_map)); 488 if (candidate_map != allocation_memento_map()) return NULL; 489 490 // Either the object is the last object in the new space, or there is another 491 // object of at least word size (the header map word) following it, so 492 // suffices to compare ptr and top here. Note that technically we do not have 493 // to compare with the current top pointer of the from space page during GC, 494 // since we always install filler objects above the top pointer of a from 495 // space page when performing a garbage collection. However, always performing 496 // the test makes it possible to have a single, unified version of 497 // FindAllocationMemento that is used both by the GC and the mutator. 498 Address top = NewSpaceTop(); 499 DCHECK(memento_address == top || 500 memento_address + HeapObject::kHeaderSize <= top || 501 !NewSpacePage::OnSamePage(memento_address, top - 1)); 502 if (memento_address == top) return NULL; 503 504 AllocationMemento* memento = AllocationMemento::cast(candidate); 505 if (!memento->IsValid()) return NULL; 506 return memento; 507 } 508 509 510 void Heap::UpdateAllocationSite(HeapObject* object, 511 HashMap* pretenuring_feedback) { 512 DCHECK(InFromSpace(object)); 513 if (!FLAG_allocation_site_pretenuring || 514 !AllocationSite::CanTrack(object->map()->instance_type())) 515 return; 516 AllocationMemento* memento = FindAllocationMemento(object); 517 if (memento == nullptr) return; 518 519 AllocationSite* key = memento->GetAllocationSite(); 520 DCHECK(!key->IsZombie()); 521 522 if (pretenuring_feedback == global_pretenuring_feedback_) { 523 // For inserting in the global pretenuring storage we need to first 524 // increment the memento found count on the allocation site. 525 if (key->IncrementMementoFoundCount()) { 526 global_pretenuring_feedback_->LookupOrInsert( 527 key, static_cast<uint32_t>(bit_cast<uintptr_t>(key))); 528 } 529 } else { 530 // Any other pretenuring storage than the global one is used as a cache, 531 // where the count is later on merge in the allocation site. 532 HashMap::Entry* e = pretenuring_feedback->LookupOrInsert( 533 key, static_cast<uint32_t>(bit_cast<uintptr_t>(key))); 534 DCHECK(e != nullptr); 535 (*bit_cast<intptr_t*>(&e->value))++; 536 } 537 } 538 539 540 void Heap::RemoveAllocationSitePretenuringFeedback(AllocationSite* site) { 541 global_pretenuring_feedback_->Remove( 542 site, static_cast<uint32_t>(bit_cast<uintptr_t>(site))); 543 } 544 545 546 bool Heap::CollectGarbage(AllocationSpace space, const char* gc_reason, 547 const v8::GCCallbackFlags callbackFlags) { 548 const char* collector_reason = NULL; 549 GarbageCollector collector = SelectGarbageCollector(space, &collector_reason); 550 return CollectGarbage(collector, gc_reason, collector_reason, callbackFlags); 551 } 552 553 554 Isolate* Heap::isolate() { 555 return reinterpret_cast<Isolate*>( 556 reinterpret_cast<intptr_t>(this) - 557 reinterpret_cast<size_t>(reinterpret_cast<Isolate*>(16)->heap()) + 16); 558 } 559 560 561 void Heap::ExternalStringTable::AddString(String* string) { 562 DCHECK(string->IsExternalString()); 563 if (heap_->InNewSpace(string)) { 564 new_space_strings_.Add(string); 565 } else { 566 old_space_strings_.Add(string); 567 } 568 } 569 570 571 void Heap::ExternalStringTable::Iterate(ObjectVisitor* v) { 572 if (!new_space_strings_.is_empty()) { 573 Object** start = &new_space_strings_[0]; 574 v->VisitPointers(start, start + new_space_strings_.length()); 575 } 576 if (!old_space_strings_.is_empty()) { 577 Object** start = &old_space_strings_[0]; 578 v->VisitPointers(start, start + old_space_strings_.length()); 579 } 580 } 581 582 583 // Verify() is inline to avoid ifdef-s around its calls in release 584 // mode. 585 void Heap::ExternalStringTable::Verify() { 586 #ifdef DEBUG 587 for (int i = 0; i < new_space_strings_.length(); ++i) { 588 Object* obj = Object::cast(new_space_strings_[i]); 589 DCHECK(heap_->InNewSpace(obj)); 590 DCHECK(obj != heap_->the_hole_value()); 591 } 592 for (int i = 0; i < old_space_strings_.length(); ++i) { 593 Object* obj = Object::cast(old_space_strings_[i]); 594 DCHECK(!heap_->InNewSpace(obj)); 595 DCHECK(obj != heap_->the_hole_value()); 596 } 597 #endif 598 } 599 600 601 void Heap::ExternalStringTable::AddOldString(String* string) { 602 DCHECK(string->IsExternalString()); 603 DCHECK(!heap_->InNewSpace(string)); 604 old_space_strings_.Add(string); 605 } 606 607 608 void Heap::ExternalStringTable::ShrinkNewStrings(int position) { 609 new_space_strings_.Rewind(position); 610 #ifdef VERIFY_HEAP 611 if (FLAG_verify_heap) { 612 Verify(); 613 } 614 #endif 615 } 616 617 618 int DescriptorLookupCache::Lookup(Map* source, Name* name) { 619 if (!name->IsUniqueName()) return kAbsent; 620 int index = Hash(source, name); 621 Key& key = keys_[index]; 622 if ((key.source == source) && (key.name == name)) return results_[index]; 623 return kAbsent; 624 } 625 626 627 void DescriptorLookupCache::Update(Map* source, Name* name, int result) { 628 DCHECK(result != kAbsent); 629 if (name->IsUniqueName()) { 630 int index = Hash(source, name); 631 Key& key = keys_[index]; 632 key.source = source; 633 key.name = name; 634 results_[index] = result; 635 } 636 } 637 638 639 void Heap::ClearInstanceofCache() { 640 set_instanceof_cache_function(Smi::FromInt(0)); 641 } 642 643 644 Object* Heap::ToBoolean(bool condition) { 645 return condition ? true_value() : false_value(); 646 } 647 648 649 void Heap::CompletelyClearInstanceofCache() { 650 set_instanceof_cache_map(Smi::FromInt(0)); 651 set_instanceof_cache_function(Smi::FromInt(0)); 652 } 653 654 655 uint32_t Heap::HashSeed() { 656 uint32_t seed = static_cast<uint32_t>(hash_seed()->value()); 657 DCHECK(FLAG_randomize_hashes || seed == 0); 658 return seed; 659 } 660 661 662 int Heap::NextScriptId() { 663 int last_id = last_script_id()->value(); 664 if (last_id == Smi::kMaxValue) { 665 last_id = 1; 666 } else { 667 last_id++; 668 } 669 set_last_script_id(Smi::FromInt(last_id)); 670 return last_id; 671 } 672 673 674 void Heap::SetArgumentsAdaptorDeoptPCOffset(int pc_offset) { 675 DCHECK(arguments_adaptor_deopt_pc_offset() == Smi::FromInt(0)); 676 set_arguments_adaptor_deopt_pc_offset(Smi::FromInt(pc_offset)); 677 } 678 679 680 void Heap::SetConstructStubDeoptPCOffset(int pc_offset) { 681 DCHECK(construct_stub_deopt_pc_offset() == Smi::FromInt(0)); 682 set_construct_stub_deopt_pc_offset(Smi::FromInt(pc_offset)); 683 } 684 685 686 void Heap::SetGetterStubDeoptPCOffset(int pc_offset) { 687 DCHECK(getter_stub_deopt_pc_offset() == Smi::FromInt(0)); 688 set_getter_stub_deopt_pc_offset(Smi::FromInt(pc_offset)); 689 } 690 691 692 void Heap::SetSetterStubDeoptPCOffset(int pc_offset) { 693 DCHECK(setter_stub_deopt_pc_offset() == Smi::FromInt(0)); 694 set_setter_stub_deopt_pc_offset(Smi::FromInt(pc_offset)); 695 } 696 697 698 AlwaysAllocateScope::AlwaysAllocateScope(Isolate* isolate) 699 : heap_(isolate->heap()) { 700 heap_->always_allocate_scope_count_.Increment(1); 701 } 702 703 704 AlwaysAllocateScope::~AlwaysAllocateScope() { 705 heap_->always_allocate_scope_count_.Increment(-1); 706 } 707 708 709 void VerifyPointersVisitor::VisitPointers(Object** start, Object** end) { 710 for (Object** current = start; current < end; current++) { 711 if ((*current)->IsHeapObject()) { 712 HeapObject* object = HeapObject::cast(*current); 713 CHECK(object->GetIsolate()->heap()->Contains(object)); 714 CHECK(object->map()->IsMap()); 715 } 716 } 717 } 718 719 720 void VerifySmisVisitor::VisitPointers(Object** start, Object** end) { 721 for (Object** current = start; current < end; current++) { 722 CHECK((*current)->IsSmi()); 723 } 724 } 725 } // namespace internal 726 } // namespace v8 727 728 #endif // V8_HEAP_HEAP_INL_H_ 729