Home | History | Annotate | Download | only in heap
      1 // Copyright 2015 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/heap/slots-buffer.h"
      6 
      7 #include "src/assembler.h"
      8 #include "src/heap/heap.h"
      9 #include "src/objects-inl.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 
     14 bool SlotsBuffer::IsTypedSlot(ObjectSlot slot) {
     15   return reinterpret_cast<uintptr_t>(slot) < NUMBER_OF_SLOT_TYPES;
     16 }
     17 
     18 
     19 bool SlotsBuffer::AddTo(SlotsBufferAllocator* allocator,
     20                         SlotsBuffer** buffer_address, SlotType type,
     21                         Address addr, AdditionMode mode) {
     22   SlotsBuffer* buffer = *buffer_address;
     23   if (buffer == NULL || !buffer->HasSpaceForTypedSlot()) {
     24     if (mode == FAIL_ON_OVERFLOW && ChainLengthThresholdReached(buffer)) {
     25       allocator->DeallocateChain(buffer_address);
     26       return false;
     27     }
     28     buffer = allocator->AllocateBuffer(buffer);
     29     *buffer_address = buffer;
     30   }
     31   DCHECK(buffer->HasSpaceForTypedSlot());
     32   buffer->Add(reinterpret_cast<ObjectSlot>(type));
     33   buffer->Add(reinterpret_cast<ObjectSlot>(addr));
     34   return true;
     35 }
     36 
     37 
     38 void SlotsBuffer::RemoveInvalidSlots(Heap* heap, SlotsBuffer* buffer) {
     39   // Remove entries by replacing them with an old-space slot containing a smi
     40   // that is located in an unmovable page.
     41   const ObjectSlot kRemovedEntry = HeapObject::RawField(
     42       heap->empty_fixed_array(), FixedArrayBase::kLengthOffset);
     43   DCHECK(Page::FromAddress(reinterpret_cast<Address>(kRemovedEntry))
     44              ->NeverEvacuate());
     45 
     46   while (buffer != NULL) {
     47     SlotsBuffer::ObjectSlot* slots = buffer->slots_;
     48     intptr_t slots_count = buffer->idx_;
     49 
     50     for (int slot_idx = 0; slot_idx < slots_count; ++slot_idx) {
     51       ObjectSlot slot = slots[slot_idx];
     52       if (!IsTypedSlot(slot)) {
     53         Object* object = *slot;
     54         // Slots are invalid when they currently:
     55         // - do not point to a heap object (SMI)
     56         // - point to a heap object in new space
     57         // - are not within a live heap object on a valid pointer slot
     58         // - point to a heap object not on an evacuation candidate
     59         if (!object->IsHeapObject() || heap->InNewSpace(object) ||
     60             !heap->mark_compact_collector()->IsSlotInLiveObject(
     61                 reinterpret_cast<Address>(slot)) ||
     62             !Page::FromAddress(reinterpret_cast<Address>(object))
     63                  ->IsEvacuationCandidate()) {
     64           // TODO(hpayer): Instead of replacing slots with kRemovedEntry we
     65           // could shrink the slots buffer in-place.
     66           slots[slot_idx] = kRemovedEntry;
     67         }
     68       } else {
     69         ++slot_idx;
     70         DCHECK(slot_idx < slots_count);
     71       }
     72     }
     73     buffer = buffer->next();
     74   }
     75 }
     76 
     77 
     78 void SlotsBuffer::RemoveObjectSlots(Heap* heap, SlotsBuffer* buffer,
     79                                     Address start_slot, Address end_slot) {
     80   // Remove entries by replacing them with an old-space slot containing a smi
     81   // that is located in an unmovable page.
     82   const ObjectSlot kRemovedEntry = HeapObject::RawField(
     83       heap->empty_fixed_array(), FixedArrayBase::kLengthOffset);
     84   DCHECK(Page::FromAddress(reinterpret_cast<Address>(kRemovedEntry))
     85              ->NeverEvacuate());
     86 
     87   while (buffer != NULL) {
     88     SlotsBuffer::ObjectSlot* slots = buffer->slots_;
     89     intptr_t slots_count = buffer->idx_;
     90     bool is_typed_slot = false;
     91 
     92     for (int slot_idx = 0; slot_idx < slots_count; ++slot_idx) {
     93       ObjectSlot slot = slots[slot_idx];
     94       if (!IsTypedSlot(slot)) {
     95         Address slot_address = reinterpret_cast<Address>(slot);
     96         if (slot_address >= start_slot && slot_address < end_slot) {
     97           // TODO(hpayer): Instead of replacing slots with kRemovedEntry we
     98           // could shrink the slots buffer in-place.
     99           slots[slot_idx] = kRemovedEntry;
    100           if (is_typed_slot) {
    101             slots[slot_idx - 1] = kRemovedEntry;
    102           }
    103         }
    104         is_typed_slot = false;
    105       } else {
    106         is_typed_slot = true;
    107         DCHECK(slot_idx < slots_count);
    108       }
    109     }
    110     buffer = buffer->next();
    111   }
    112 }
    113 
    114 
    115 void SlotsBuffer::VerifySlots(Heap* heap, SlotsBuffer* buffer) {
    116   while (buffer != NULL) {
    117     SlotsBuffer::ObjectSlot* slots = buffer->slots_;
    118     intptr_t slots_count = buffer->idx_;
    119 
    120     for (int slot_idx = 0; slot_idx < slots_count; ++slot_idx) {
    121       ObjectSlot slot = slots[slot_idx];
    122       if (!IsTypedSlot(slot)) {
    123         Object* object = *slot;
    124         if (object->IsHeapObject()) {
    125           HeapObject* heap_object = HeapObject::cast(object);
    126           CHECK(!heap->InNewSpace(object));
    127           heap->mark_compact_collector()->VerifyIsSlotInLiveObject(
    128               reinterpret_cast<Address>(slot), heap_object);
    129         }
    130       } else {
    131         ++slot_idx;
    132         DCHECK(slot_idx < slots_count);
    133       }
    134     }
    135     buffer = buffer->next();
    136   }
    137 }
    138 
    139 
    140 SlotsBuffer* SlotsBufferAllocator::AllocateBuffer(SlotsBuffer* next_buffer) {
    141   return new SlotsBuffer(next_buffer);
    142 }
    143 
    144 
    145 void SlotsBufferAllocator::DeallocateBuffer(SlotsBuffer* buffer) {
    146   delete buffer;
    147 }
    148 
    149 
    150 void SlotsBufferAllocator::DeallocateChain(SlotsBuffer** buffer_address) {
    151   SlotsBuffer* buffer = *buffer_address;
    152   while (buffer != NULL) {
    153     SlotsBuffer* next_buffer = buffer->next();
    154     DeallocateBuffer(buffer);
    155     buffer = next_buffer;
    156   }
    157   *buffer_address = NULL;
    158 }
    159 
    160 }  // namespace internal
    161 }  // namespace v8
    162