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