Home | History | Annotate | Download | only in heap
      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