| Index: src/heap/slots-buffer.cc
|
| diff --git a/src/heap/slots-buffer.cc b/src/heap/slots-buffer.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5a3db281fda576180de0b76d8468e3f21d5fe345
|
| --- /dev/null
|
| +++ b/src/heap/slots-buffer.cc
|
| @@ -0,0 +1,164 @@
|
| +// Copyright 2015 the V8 project authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "src/heap/slots-buffer.h"
|
| +
|
| +#include "src/assembler.h"
|
| +#include "src/heap/heap.h"
|
| +#include "src/objects-inl.h"
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +
|
| +bool SlotsBuffer::IsTypedSlot(ObjectSlot slot) {
|
| + return reinterpret_cast<uintptr_t>(slot) < NUMBER_OF_SLOT_TYPES;
|
| +}
|
| +
|
| +
|
| +bool SlotsBuffer::AddTo(SlotsBufferAllocator* allocator,
|
| + SlotsBuffer** buffer_address, SlotType type,
|
| + Address addr, AdditionMode mode) {
|
| + SlotsBuffer* buffer = *buffer_address;
|
| + if (buffer == NULL || !buffer->HasSpaceForTypedSlot()) {
|
| + if (mode == FAIL_ON_OVERFLOW && ChainLengthThresholdReached(buffer)) {
|
| + allocator->DeallocateChain(buffer_address);
|
| + return false;
|
| + }
|
| + buffer = allocator->AllocateBuffer(buffer);
|
| + *buffer_address = buffer;
|
| + }
|
| + DCHECK(buffer->HasSpaceForTypedSlot());
|
| + buffer->Add(reinterpret_cast<ObjectSlot>(type));
|
| + buffer->Add(reinterpret_cast<ObjectSlot>(addr));
|
| + return true;
|
| +}
|
| +
|
| +
|
| +void SlotsBuffer::RemoveInvalidSlots(Heap* heap, SlotsBuffer* buffer) {
|
| + // Remove entries by replacing them with an old-space slot containing a smi
|
| + // that is located in an unmovable page.
|
| + const ObjectSlot kRemovedEntry = HeapObject::RawField(
|
| + heap->empty_fixed_array(), FixedArrayBase::kLengthOffset);
|
| + DCHECK(Page::FromAddress(reinterpret_cast<Address>(kRemovedEntry))
|
| + ->NeverEvacuate());
|
| +
|
| + while (buffer != NULL) {
|
| + SlotsBuffer::ObjectSlot* slots = buffer->slots_;
|
| + intptr_t slots_count = buffer->idx_;
|
| +
|
| + for (int slot_idx = 0; slot_idx < slots_count; ++slot_idx) {
|
| + ObjectSlot slot = slots[slot_idx];
|
| + if (!IsTypedSlot(slot)) {
|
| + Object* object = *slot;
|
| + // Slots are invalid when they currently:
|
| + // - do not point to a heap object (SMI)
|
| + // - point to a heap object in new space
|
| + // - are not within a live heap object on a valid pointer slot
|
| + // - point to a heap object not on an evacuation candidate
|
| + // TODO(mlippautz): Move InNewSpace check above IsSlotInLiveObject once
|
| + // we filter out unboxed double slots eagerly.
|
| + if (!object->IsHeapObject() ||
|
| + !heap->mark_compact_collector()->IsSlotInLiveObject(
|
| + reinterpret_cast<Address>(slot)) ||
|
| + heap->InNewSpace(object) ||
|
| + !Page::FromAddress(reinterpret_cast<Address>(object))
|
| + ->IsEvacuationCandidate()) {
|
| + // TODO(hpayer): Instead of replacing slots with kRemovedEntry we
|
| + // could shrink the slots buffer in-place.
|
| + slots[slot_idx] = kRemovedEntry;
|
| + }
|
| + } else {
|
| + ++slot_idx;
|
| + DCHECK(slot_idx < slots_count);
|
| + }
|
| + }
|
| + buffer = buffer->next();
|
| + }
|
| +}
|
| +
|
| +
|
| +void SlotsBuffer::RemoveObjectSlots(Heap* heap, SlotsBuffer* buffer,
|
| + Address start_slot, Address end_slot) {
|
| + // Remove entries by replacing them with an old-space slot containing a smi
|
| + // that is located in an unmovable page.
|
| + const ObjectSlot kRemovedEntry = HeapObject::RawField(
|
| + heap->empty_fixed_array(), FixedArrayBase::kLengthOffset);
|
| + DCHECK(Page::FromAddress(reinterpret_cast<Address>(kRemovedEntry))
|
| + ->NeverEvacuate());
|
| +
|
| + while (buffer != NULL) {
|
| + SlotsBuffer::ObjectSlot* slots = buffer->slots_;
|
| + intptr_t slots_count = buffer->idx_;
|
| + bool is_typed_slot = false;
|
| +
|
| + for (int slot_idx = 0; slot_idx < slots_count; ++slot_idx) {
|
| + ObjectSlot slot = slots[slot_idx];
|
| + if (!IsTypedSlot(slot)) {
|
| + Address slot_address = reinterpret_cast<Address>(slot);
|
| + if (slot_address >= start_slot && slot_address < end_slot) {
|
| + // TODO(hpayer): Instead of replacing slots with kRemovedEntry we
|
| + // could shrink the slots buffer in-place.
|
| + slots[slot_idx] = kRemovedEntry;
|
| + if (is_typed_slot) {
|
| + slots[slot_idx - 1] = kRemovedEntry;
|
| + }
|
| + }
|
| + is_typed_slot = false;
|
| + } else {
|
| + is_typed_slot = true;
|
| + DCHECK(slot_idx < slots_count);
|
| + }
|
| + }
|
| + buffer = buffer->next();
|
| + }
|
| +}
|
| +
|
| +
|
| +void SlotsBuffer::VerifySlots(Heap* heap, SlotsBuffer* buffer) {
|
| + while (buffer != NULL) {
|
| + SlotsBuffer::ObjectSlot* slots = buffer->slots_;
|
| + intptr_t slots_count = buffer->idx_;
|
| +
|
| + for (int slot_idx = 0; slot_idx < slots_count; ++slot_idx) {
|
| + ObjectSlot slot = slots[slot_idx];
|
| + if (!IsTypedSlot(slot)) {
|
| + Object* object = *slot;
|
| + if (object->IsHeapObject()) {
|
| + HeapObject* heap_object = HeapObject::cast(object);
|
| + CHECK(!heap->InNewSpace(object));
|
| + heap->mark_compact_collector()->VerifyIsSlotInLiveObject(
|
| + reinterpret_cast<Address>(slot), heap_object);
|
| + }
|
| + } else {
|
| + ++slot_idx;
|
| + DCHECK(slot_idx < slots_count);
|
| + }
|
| + }
|
| + buffer = buffer->next();
|
| + }
|
| +}
|
| +
|
| +
|
| +SlotsBuffer* SlotsBufferAllocator::AllocateBuffer(SlotsBuffer* next_buffer) {
|
| + return new SlotsBuffer(next_buffer);
|
| +}
|
| +
|
| +
|
| +void SlotsBufferAllocator::DeallocateBuffer(SlotsBuffer* buffer) {
|
| + delete buffer;
|
| +}
|
| +
|
| +
|
| +void SlotsBufferAllocator::DeallocateChain(SlotsBuffer** buffer_address) {
|
| + SlotsBuffer* buffer = *buffer_address;
|
| + while (buffer != NULL) {
|
| + SlotsBuffer* next_buffer = buffer->next();
|
| + DeallocateBuffer(buffer);
|
| + buffer = next_buffer;
|
| + }
|
| + *buffer_address = NULL;
|
| +}
|
| +
|
| +} // namespace internal
|
| +} // namespace v8
|
|
|