Commit 064be4c2 authored by hpayer's avatar hpayer Committed by Commit bot

[heap] Move slots buffer into a separate file.

BUG=

Review URL: https://codereview.chromium.org/1343043002

Cr-Commit-Position: refs/heads/master@{#30746}
parent 2b476800
......@@ -987,6 +987,8 @@ source_set("v8_base") {
"src/heap/scavenger-inl.h",
"src/heap/scavenger.cc",
"src/heap/scavenger.h",
"src/heap/slots-buffer.cc",
"src/heap/slots-buffer.h",
"src/heap/spaces-inl.h",
"src/heap/spaces.cc",
"src/heap/spaces.h",
......
......@@ -2852,8 +2852,8 @@ void Heap::AddAllocationSiteToScratchpad(AllocationSite* site,
// candidates are not part of the global list of old space pages and
// releasing an evacuation candidate due to a slots buffer overflow
// results in lost pages.
mark_compact_collector()->RecordSlot(allocation_sites_scratchpad(), slot,
*slot, SlotsBuffer::IGNORE_OVERFLOW);
mark_compact_collector()->ForceRecordSlot(allocation_sites_scratchpad(),
slot, *slot);
}
allocation_sites_scratchpad_length_++;
}
......
......@@ -55,20 +55,6 @@ bool MarkCompactCollector::IsMarked(Object* obj) {
}
void MarkCompactCollector::RecordSlot(HeapObject* object, Object** slot,
Object* target,
SlotsBuffer::AdditionMode mode) {
Page* target_page = Page::FromAddress(reinterpret_cast<Address>(target));
if (target_page->IsEvacuationCandidate() &&
!ShouldSkipEvacuationSlotRecording(object)) {
if (!SlotsBuffer::AddTo(&slots_buffer_allocator_,
target_page->slots_buffer_address(), slot, mode)) {
EvictPopularEvacuationCandidate(target_page);
}
}
}
void CodeFlusher::AddCandidate(SharedFunctionInfo* shared_info) {
if (GetNextCandidate(shared_info) == NULL) {
SetNextCandidate(shared_info, shared_function_info_candidates_head_);
......
This diff is collapsed.
......@@ -24,6 +24,8 @@ class CodeFlusher;
class MarkCompactCollector;
class MarkingVisitor;
class RootMarkingVisitor;
class SlotsBuffer;
class SlotsBufferAllocator;
class Marking : public AllStatic {
......@@ -258,178 +260,6 @@ class MarkingDeque {
};
class SlotsBufferAllocator {
public:
SlotsBuffer* AllocateBuffer(SlotsBuffer* next_buffer);
void DeallocateBuffer(SlotsBuffer* buffer);
void DeallocateChain(SlotsBuffer** buffer_address);
};
// SlotsBuffer records a sequence of slots that has to be updated
// after live objects were relocated from evacuation candidates.
// All slots are either untyped or typed:
// - Untyped slots are expected to contain a tagged object pointer.
// They are recorded by an address.
// - Typed slots are expected to contain an encoded pointer to a heap
// object where the way of encoding depends on the type of the slot.
// They are recorded as a pair (SlotType, slot address).
// We assume that zero-page is never mapped this allows us to distinguish
// untyped slots from typed slots during iteration by a simple comparison:
// if element of slots buffer is less than NUMBER_OF_SLOT_TYPES then it
// is the first element of typed slot's pair.
class SlotsBuffer {
public:
typedef Object** ObjectSlot;
explicit SlotsBuffer(SlotsBuffer* next_buffer)
: idx_(0), chain_length_(1), next_(next_buffer) {
if (next_ != NULL) {
chain_length_ = next_->chain_length_ + 1;
}
}
~SlotsBuffer() {}
void Add(ObjectSlot slot) {
DCHECK(0 <= idx_ && idx_ < kNumberOfElements);
#ifdef DEBUG
if (slot >= reinterpret_cast<ObjectSlot>(NUMBER_OF_SLOT_TYPES)) {
DCHECK_NOT_NULL(*slot);
}
#endif
slots_[idx_++] = slot;
}
// Should be used for testing only.
ObjectSlot Get(intptr_t i) {
DCHECK(i >= 0 && i < kNumberOfElements);
return slots_[i];
}
enum SlotType {
EMBEDDED_OBJECT_SLOT,
OBJECT_SLOT,
RELOCATED_CODE_OBJECT,
CELL_TARGET_SLOT,
CODE_TARGET_SLOT,
CODE_ENTRY_SLOT,
DEBUG_TARGET_SLOT,
NUMBER_OF_SLOT_TYPES
};
static const char* SlotTypeToString(SlotType type) {
switch (type) {
case EMBEDDED_OBJECT_SLOT:
return "EMBEDDED_OBJECT_SLOT";
case OBJECT_SLOT:
return "OBJECT_SLOT";
case RELOCATED_CODE_OBJECT:
return "RELOCATED_CODE_OBJECT";
case CELL_TARGET_SLOT:
return "CELL_TARGET_SLOT";
case CODE_TARGET_SLOT:
return "CODE_TARGET_SLOT";
case CODE_ENTRY_SLOT:
return "CODE_ENTRY_SLOT";
case DEBUG_TARGET_SLOT:
return "DEBUG_TARGET_SLOT";
case NUMBER_OF_SLOT_TYPES:
return "NUMBER_OF_SLOT_TYPES";
}
return "UNKNOWN SlotType";
}
void UpdateSlots(Heap* heap);
void UpdateSlotsWithFilter(Heap* heap);
SlotsBuffer* next() { return next_; }
static int SizeOfChain(SlotsBuffer* buffer) {
if (buffer == NULL) return 0;
return static_cast<int>(buffer->idx_ +
(buffer->chain_length_ - 1) * kNumberOfElements);
}
inline bool IsFull() { return idx_ == kNumberOfElements; }
inline bool HasSpaceForTypedSlot() { return idx_ < kNumberOfElements - 1; }
static void UpdateSlotsRecordedIn(Heap* heap, SlotsBuffer* buffer) {
while (buffer != NULL) {
buffer->UpdateSlots(heap);
buffer = buffer->next();
}
}
enum AdditionMode { FAIL_ON_OVERFLOW, IGNORE_OVERFLOW };
static bool ChainLengthThresholdReached(SlotsBuffer* buffer) {
return buffer != NULL && buffer->chain_length_ >= kChainLengthThreshold;
}
INLINE(static bool AddToSynchronized(SlotsBufferAllocator* allocator,
SlotsBuffer** buffer_address,
base::Mutex* buffer_mutex,
ObjectSlot slot, AdditionMode mode)) {
base::LockGuard<base::Mutex> lock_guard(buffer_mutex);
return AddTo(allocator, buffer_address, slot, mode);
}
INLINE(static bool AddTo(SlotsBufferAllocator* allocator,
SlotsBuffer** buffer_address, ObjectSlot slot,
AdditionMode mode)) {
SlotsBuffer* buffer = *buffer_address;
if (buffer == NULL || buffer->IsFull()) {
if (mode == FAIL_ON_OVERFLOW && ChainLengthThresholdReached(buffer)) {
allocator->DeallocateChain(buffer_address);
return false;
}
buffer = allocator->AllocateBuffer(buffer);
*buffer_address = buffer;
}
buffer->Add(slot);
return true;
}
static bool IsTypedSlot(ObjectSlot slot);
static bool AddToSynchronized(SlotsBufferAllocator* allocator,
SlotsBuffer** buffer_address,
base::Mutex* buffer_mutex, SlotType type,
Address addr, AdditionMode mode);
static bool AddTo(SlotsBufferAllocator* allocator,
SlotsBuffer** buffer_address, SlotType type, Address addr,
AdditionMode mode);
// Eliminates all stale entries from the slots buffer, i.e., slots that
// are not part of live objects anymore. This method must be called after
// marking, when the whole transitive closure is known and must be called
// before sweeping when mark bits are still intact.
static void RemoveInvalidSlots(Heap* heap, SlotsBuffer* buffer);
// Eliminate all slots that are within the given address range.
static void RemoveObjectSlots(Heap* heap, SlotsBuffer* buffer,
Address start_slot, Address end_slot);
// Ensures that there are no invalid slots in the chain of slots buffers.
static void VerifySlots(Heap* heap, SlotsBuffer* buffer);
static const int kNumberOfElements = 1021;
private:
static const int kChainLengthThreshold = 15;
intptr_t idx_;
intptr_t chain_length_;
SlotsBuffer* next_;
ObjectSlot slots_[kNumberOfElements];
};
// CodeFlusher collects candidates for code flushing during marking and
// processes those candidates after marking has completed in order to
// reset those functions referencing code objects that would otherwise
......@@ -589,10 +419,11 @@ class MarkCompactCollector {
void RecordRelocSlot(RelocInfo* rinfo, Object* target);
void RecordCodeEntrySlot(HeapObject* object, Address slot, Code* target);
void RecordCodeTargetPatch(Address pc, Code* target);
void RecordSlot(HeapObject* object, Object** slot, Object* target);
void ForceRecordSlot(HeapObject* object, Object** slot, Object* target);
INLINE(void RecordSlot(
HeapObject* object, Object** slot, Object* target,
SlotsBuffer::AdditionMode mode = SlotsBuffer::FAIL_ON_OVERFLOW));
void UpdateSlots(SlotsBuffer* buffer);
void UpdateSlotsRecordedIn(SlotsBuffer* buffer);
void MigrateObject(HeapObject* dst, HeapObject* src, int size,
AllocationSpace to_old_space);
......@@ -727,7 +558,7 @@ class MarkCompactCollector {
bool evacuation_;
SlotsBufferAllocator slots_buffer_allocator_;
SlotsBufferAllocator* slots_buffer_allocator_;
SlotsBuffer* migration_slots_buffer_;
......
// 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::AddToSynchronized(SlotsBufferAllocator* allocator,
SlotsBuffer** buffer_address,
base::Mutex* buffer_mutex, SlotType type,
Address addr, AdditionMode mode) {
base::LockGuard<base::Mutex> lock_guard(buffer_mutex);
return AddTo(allocator, buffer_address, type, addr, mode);
}
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
if (!object->IsHeapObject() || heap->InNewSpace(object) ||
!heap->mark_compact_collector()->IsSlotInLiveObject(
reinterpret_cast<Address>(slot)) ||
!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
// 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.
#ifndef V8_HEAP_SLOTS_BUFFER_H_
#define V8_HEAP_SLOTS_BUFFER_H_
#include "src/objects.h"
namespace v8 {
namespace internal {
// Forward declarations.
class SlotsBuffer;
// SlotsBufferAllocator manages the allocation and deallocation of slots buffer
// chunks and links them together. Slots buffer chunks are always created by the
// SlotsBufferAllocator.
class SlotsBufferAllocator {
public:
SlotsBuffer* AllocateBuffer(SlotsBuffer* next_buffer);
void DeallocateBuffer(SlotsBuffer* buffer);
void DeallocateChain(SlotsBuffer** buffer_address);
};
// SlotsBuffer records a sequence of slots that has to be updated
// after live objects were relocated from evacuation candidates.
// All slots are either untyped or typed:
// - Untyped slots are expected to contain a tagged object pointer.
// They are recorded by an address.
// - Typed slots are expected to contain an encoded pointer to a heap
// object where the way of encoding depends on the type of the slot.
// They are recorded as a pair (SlotType, slot address).
// We assume that zero-page is never mapped this allows us to distinguish
// untyped slots from typed slots during iteration by a simple comparison:
// if element of slots buffer is less than NUMBER_OF_SLOT_TYPES then it
// is the first element of typed slot's pair.
class SlotsBuffer {
public:
typedef Object** ObjectSlot;
explicit SlotsBuffer(SlotsBuffer* next_buffer)
: idx_(0), chain_length_(1), next_(next_buffer) {
if (next_ != NULL) {
chain_length_ = next_->chain_length_ + 1;
}
}
~SlotsBuffer() {}
void Add(ObjectSlot slot) {
DCHECK(0 <= idx_ && idx_ < kNumberOfElements);
#ifdef DEBUG
if (slot >= reinterpret_cast<ObjectSlot>(NUMBER_OF_SLOT_TYPES)) {
DCHECK_NOT_NULL(*slot);
}
#endif
slots_[idx_++] = slot;
}
ObjectSlot Get(intptr_t i) {
DCHECK(i >= 0 && i < kNumberOfElements);
return slots_[i];
}
size_t Size() {
DCHECK(idx_ <= kNumberOfElements);
return idx_;
}
enum SlotType {
EMBEDDED_OBJECT_SLOT,
OBJECT_SLOT,
RELOCATED_CODE_OBJECT,
CELL_TARGET_SLOT,
CODE_TARGET_SLOT,
CODE_ENTRY_SLOT,
DEBUG_TARGET_SLOT,
NUMBER_OF_SLOT_TYPES
};
static const char* SlotTypeToString(SlotType type) {
switch (type) {
case EMBEDDED_OBJECT_SLOT:
return "EMBEDDED_OBJECT_SLOT";
case OBJECT_SLOT:
return "OBJECT_SLOT";
case RELOCATED_CODE_OBJECT:
return "RELOCATED_CODE_OBJECT";
case CELL_TARGET_SLOT:
return "CELL_TARGET_SLOT";
case CODE_TARGET_SLOT:
return "CODE_TARGET_SLOT";
case CODE_ENTRY_SLOT:
return "CODE_ENTRY_SLOT";
case DEBUG_TARGET_SLOT:
return "DEBUG_TARGET_SLOT";
case NUMBER_OF_SLOT_TYPES:
return "NUMBER_OF_SLOT_TYPES";
}
return "UNKNOWN SlotType";
}
SlotsBuffer* next() { return next_; }
static int SizeOfChain(SlotsBuffer* buffer) {
if (buffer == NULL) return 0;
return static_cast<int>(buffer->idx_ +
(buffer->chain_length_ - 1) * kNumberOfElements);
}
inline bool IsFull() { return idx_ == kNumberOfElements; }
inline bool HasSpaceForTypedSlot() { return idx_ < kNumberOfElements - 1; }
enum AdditionMode { FAIL_ON_OVERFLOW, IGNORE_OVERFLOW };
static bool ChainLengthThresholdReached(SlotsBuffer* buffer) {
return buffer != NULL && buffer->chain_length_ >= kChainLengthThreshold;
}
INLINE(static bool AddToSynchronized(SlotsBufferAllocator* allocator,
SlotsBuffer** buffer_address,
base::Mutex* buffer_mutex,
ObjectSlot slot, AdditionMode mode)) {
base::LockGuard<base::Mutex> lock_guard(buffer_mutex);
return AddTo(allocator, buffer_address, slot, mode);
}
INLINE(static bool AddTo(SlotsBufferAllocator* allocator,
SlotsBuffer** buffer_address, ObjectSlot slot,
AdditionMode mode)) {
SlotsBuffer* buffer = *buffer_address;
if (buffer == NULL || buffer->IsFull()) {
if (mode == FAIL_ON_OVERFLOW && ChainLengthThresholdReached(buffer)) {
allocator->DeallocateChain(buffer_address);
return false;
}
buffer = allocator->AllocateBuffer(buffer);
*buffer_address = buffer;
}
buffer->Add(slot);
return true;
}
static bool IsTypedSlot(ObjectSlot slot);
static bool AddToSynchronized(SlotsBufferAllocator* allocator,
SlotsBuffer** buffer_address,
base::Mutex* buffer_mutex, SlotType type,
Address addr, AdditionMode mode);
static bool AddTo(SlotsBufferAllocator* allocator,
SlotsBuffer** buffer_address, SlotType type, Address addr,
AdditionMode mode);
// Eliminates all stale entries from the slots buffer, i.e., slots that
// are not part of live objects anymore. This method must be called after
// marking, when the whole transitive closure is known and must be called
// before sweeping when mark bits are still intact.
static void RemoveInvalidSlots(Heap* heap, SlotsBuffer* buffer);
// Eliminate all slots that are within the given address range.
static void RemoveObjectSlots(Heap* heap, SlotsBuffer* buffer,
Address start_slot, Address end_slot);
// Ensures that there are no invalid slots in the chain of slots buffers.
static void VerifySlots(Heap* heap, SlotsBuffer* buffer);
static const int kNumberOfElements = 1021;
private:
static const int kChainLengthThreshold = 15;
intptr_t idx_;
intptr_t chain_length_;
SlotsBuffer* next_;
ObjectSlot slots_[kNumberOfElements];
};
} // namespace internal
} // namespace v8
#endif // V8_HEAP_SLOTS_BUFFER_H_
......@@ -7,7 +7,7 @@
#include "src/base/bits.h"
#include "src/base/platform/platform.h"
#include "src/full-codegen/full-codegen.h"
#include "src/heap/mark-compact.h"
#include "src/heap/slots-buffer.h"
#include "src/macro-assembler.h"
#include "src/msan.h"
#include "src/snapshot/snapshot.h"
......
......@@ -155,6 +155,7 @@
'test-sampler-api.cc',
'test-serialize.cc',
'test-simd.cc',
'test-slots-buffer.cc',
'test-spaces.cc',
'test-strings.cc',
'test-symbols.cc',
......
......@@ -6453,127 +6453,6 @@ TEST(AllocationThroughput) {
}
TEST(SlotsBufferObjectSlotsRemoval) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
Isolate* isolate = CcTest::i_isolate();
Heap* heap = isolate->heap();
Factory* factory = isolate->factory();
SlotsBuffer* buffer = new SlotsBuffer(NULL);
void* fake_object[1];
Handle<FixedArray> array = factory->NewFixedArray(2, TENURED);
CHECK(heap->old_space()->Contains(*array));
array->set(0, reinterpret_cast<Object*>(fake_object), SKIP_WRITE_BARRIER);
// Firstly, let's test the regular slots buffer entry.
buffer->Add(HeapObject::RawField(*array, FixedArray::kHeaderSize));
CHECK(reinterpret_cast<void*>(buffer->Get(0)) ==
HeapObject::RawField(*array, FixedArray::kHeaderSize));
SlotsBuffer::RemoveObjectSlots(CcTest::i_isolate()->heap(), buffer,
array->address(),
array->address() + array->Size());
CHECK(reinterpret_cast<void*>(buffer->Get(0)) ==
HeapObject::RawField(heap->empty_fixed_array(),
FixedArrayBase::kLengthOffset));
// Secondly, let's test the typed slots buffer entry.
SlotsBuffer::AddTo(NULL, &buffer, SlotsBuffer::EMBEDDED_OBJECT_SLOT,
array->address() + FixedArray::kHeaderSize,
SlotsBuffer::FAIL_ON_OVERFLOW);
CHECK(reinterpret_cast<void*>(buffer->Get(1)) ==
reinterpret_cast<Object**>(SlotsBuffer::EMBEDDED_OBJECT_SLOT));
CHECK(reinterpret_cast<void*>(buffer->Get(2)) ==
HeapObject::RawField(*array, FixedArray::kHeaderSize));
SlotsBuffer::RemoveObjectSlots(CcTest::i_isolate()->heap(), buffer,
array->address(),
array->address() + array->Size());
CHECK(reinterpret_cast<void*>(buffer->Get(1)) ==
HeapObject::RawField(heap->empty_fixed_array(),
FixedArrayBase::kLengthOffset));
CHECK(reinterpret_cast<void*>(buffer->Get(2)) ==
HeapObject::RawField(heap->empty_fixed_array(),
FixedArrayBase::kLengthOffset));
delete buffer;
}
TEST(FilterInvalidSlotsBufferEntries) {
FLAG_manual_evacuation_candidates_selection = true;
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
Isolate* isolate = CcTest::i_isolate();
Heap* heap = isolate->heap();
Factory* factory = isolate->factory();
SlotsBuffer* buffer = new SlotsBuffer(NULL);
// Set up a fake black object that will contain a recorded SMI, a recorded
// pointer to a new space object, and a recorded pointer to a non-evacuation
// candidate object. These object should be filtered out. Additionally,
// we point to an evacuation candidate object which should not be filtered
// out.
// Create fake object and mark it black.
Handle<FixedArray> fake_object = factory->NewFixedArray(23, TENURED);
MarkBit mark_bit = Marking::MarkBitFrom(*fake_object);
Marking::MarkBlack(mark_bit);
// Write a SMI into field one and record its address;
Object** field_smi = fake_object->RawFieldOfElementAt(0);
*field_smi = Smi::FromInt(100);
buffer->Add(field_smi);
// Write a new space reference into field 2 and record its address;
Handle<FixedArray> new_space_object = factory->NewFixedArray(23);
mark_bit = Marking::MarkBitFrom(*new_space_object);
Marking::MarkBlack(mark_bit);
Object** field_new_space = fake_object->RawFieldOfElementAt(1);
*field_new_space = *new_space_object;
buffer->Add(field_new_space);
// Write an old space reference into field 3 which points to an object not on
// an evacuation candidate.
Handle<FixedArray> old_space_object_non_evacuation =
factory->NewFixedArray(23, TENURED);
mark_bit = Marking::MarkBitFrom(*old_space_object_non_evacuation);
Marking::MarkBlack(mark_bit);
Object** field_old_space_object_non_evacuation =
fake_object->RawFieldOfElementAt(2);
*field_old_space_object_non_evacuation = *old_space_object_non_evacuation;
buffer->Add(field_old_space_object_non_evacuation);
// Write an old space reference into field 4 which points to an object on an
// evacuation candidate.
SimulateFullSpace(heap->old_space());
Handle<FixedArray> valid_object =
isolate->factory()->NewFixedArray(23, TENURED);
Page* page = Page::FromAddress(valid_object->address());
page->SetFlag(MemoryChunk::EVACUATION_CANDIDATE);
Object** valid_field = fake_object->RawFieldOfElementAt(3);
*valid_field = *valid_object;
buffer->Add(valid_field);
SlotsBuffer::RemoveInvalidSlots(heap, buffer);
Object** kRemovedEntry = HeapObject::RawField(heap->empty_fixed_array(),
FixedArrayBase::kLengthOffset);
CHECK_EQ(buffer->Get(0), kRemovedEntry);
CHECK_EQ(buffer->Get(1), kRemovedEntry);
CHECK_EQ(buffer->Get(2), kRemovedEntry);
CHECK_EQ(buffer->Get(3), valid_field);
// Clean-up to make verify heap happy.
mark_bit = Marking::MarkBitFrom(*fake_object);
Marking::MarkWhite(mark_bit);
mark_bit = Marking::MarkBitFrom(*new_space_object);
Marking::MarkWhite(mark_bit);
mark_bit = Marking::MarkBitFrom(*old_space_object_non_evacuation);
Marking::MarkWhite(mark_bit);
delete buffer;
}
TEST(ContextMeasure) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
......
// 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 "test/cctest/cctest.h"
namespace v8 {
namespace internal {
TEST(SlotsBufferObjectSlotsRemoval) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
Isolate* isolate = CcTest::i_isolate();
Heap* heap = isolate->heap();
Factory* factory = isolate->factory();
SlotsBuffer* buffer = new SlotsBuffer(NULL);
void* fake_object[1];
Handle<FixedArray> array = factory->NewFixedArray(2, TENURED);
CHECK(heap->old_space()->Contains(*array));
array->set(0, reinterpret_cast<Object*>(fake_object), SKIP_WRITE_BARRIER);
// Firstly, let's test the regular slots buffer entry.
buffer->Add(HeapObject::RawField(*array, FixedArray::kHeaderSize));
CHECK(reinterpret_cast<void*>(buffer->Get(0)) ==
HeapObject::RawField(*array, FixedArray::kHeaderSize));
SlotsBuffer::RemoveObjectSlots(CcTest::i_isolate()->heap(), buffer,
array->address(),
array->address() + array->Size());
CHECK(reinterpret_cast<void*>(buffer->Get(0)) ==
HeapObject::RawField(heap->empty_fixed_array(),
FixedArrayBase::kLengthOffset));
// Secondly, let's test the typed slots buffer entry.
SlotsBuffer::AddTo(NULL, &buffer, SlotsBuffer::EMBEDDED_OBJECT_SLOT,
array->address() + FixedArray::kHeaderSize,
SlotsBuffer::FAIL_ON_OVERFLOW);
CHECK(reinterpret_cast<void*>(buffer->Get(1)) ==
reinterpret_cast<Object**>(SlotsBuffer::EMBEDDED_OBJECT_SLOT));
CHECK(reinterpret_cast<void*>(buffer->Get(2)) ==
HeapObject::RawField(*array, FixedArray::kHeaderSize));
SlotsBuffer::RemoveObjectSlots(CcTest::i_isolate()->heap(), buffer,
array->address(),
array->address() + array->Size());
CHECK(reinterpret_cast<void*>(buffer->Get(1)) ==
HeapObject::RawField(heap->empty_fixed_array(),
FixedArrayBase::kLengthOffset));
CHECK(reinterpret_cast<void*>(buffer->Get(2)) ==
HeapObject::RawField(heap->empty_fixed_array(),
FixedArrayBase::kLengthOffset));
delete buffer;
}
TEST(FilterInvalidSlotsBufferEntries) {
FLAG_manual_evacuation_candidates_selection = true;
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
Isolate* isolate = CcTest::i_isolate();
Heap* heap = isolate->heap();
Factory* factory = isolate->factory();
SlotsBuffer* buffer = new SlotsBuffer(NULL);
// Set up a fake black object that will contain a recorded SMI, a recorded
// pointer to a new space object, and a recorded pointer to a non-evacuation
// candidate object. These object should be filtered out. Additionally,
// we point to an evacuation candidate object which should not be filtered
// out.
// Create fake object and mark it black.
Handle<FixedArray> fake_object = factory->NewFixedArray(23, TENURED);
MarkBit mark_bit = Marking::MarkBitFrom(*fake_object);
Marking::MarkBlack(mark_bit);
// Write a SMI into field one and record its address;
Object** field_smi = fake_object->RawFieldOfElementAt(0);
*field_smi = Smi::FromInt(100);
buffer->Add(field_smi);
// Write a new space reference into field 2 and record its address;
Handle<FixedArray> new_space_object = factory->NewFixedArray(23);
mark_bit = Marking::MarkBitFrom(*new_space_object);
Marking::MarkBlack(mark_bit);
Object** field_new_space = fake_object->RawFieldOfElementAt(1);
*field_new_space = *new_space_object;
buffer->Add(field_new_space);
// Write an old space reference into field 3 which points to an object not on
// an evacuation candidate.
Handle<FixedArray> old_space_object_non_evacuation =
factory->NewFixedArray(23, TENURED);
mark_bit = Marking::MarkBitFrom(*old_space_object_non_evacuation);
Marking::MarkBlack(mark_bit);
Object** field_old_space_object_non_evacuation =
fake_object->RawFieldOfElementAt(2);
*field_old_space_object_non_evacuation = *old_space_object_non_evacuation;
buffer->Add(field_old_space_object_non_evacuation);
// Write an old space reference into field 4 which points to an object on an
// evacuation candidate.
SimulateFullSpace(heap->old_space());
Handle<FixedArray> valid_object =
isolate->factory()->NewFixedArray(23, TENURED);
Page* page = Page::FromAddress(valid_object->address());
page->SetFlag(MemoryChunk::EVACUATION_CANDIDATE);
Object** valid_field = fake_object->RawFieldOfElementAt(3);
*valid_field = *valid_object;
buffer->Add(valid_field);
SlotsBuffer::RemoveInvalidSlots(heap, buffer);
Object** kRemovedEntry = HeapObject::RawField(heap->empty_fixed_array(),
FixedArrayBase::kLengthOffset);
CHECK_EQ(buffer->Get(0), kRemovedEntry);
CHECK_EQ(buffer->Get(1), kRemovedEntry);
CHECK_EQ(buffer->Get(2), kRemovedEntry);
CHECK_EQ(buffer->Get(3), valid_field);
// Clean-up to make verify heap happy.
mark_bit = Marking::MarkBitFrom(*fake_object);
Marking::MarkWhite(mark_bit);
mark_bit = Marking::MarkBitFrom(*new_space_object);
Marking::MarkWhite(mark_bit);
mark_bit = Marking::MarkBitFrom(*old_space_object_non_evacuation);
Marking::MarkWhite(mark_bit);
delete buffer;
}
} // namespace internal
} // namespace v8
......@@ -11,6 +11,7 @@
#include "src/execution.h"
#include "src/factory.h"
#include "src/global-handles.h"
#include "src/heap/slots-buffer.h"
#include "src/ic/ic.h"
#include "src/macro-assembler.h"
#include "test/cctest/cctest.h"
......
......@@ -737,6 +737,8 @@
'../../src/heap/scavenger-inl.h',
'../../src/heap/scavenger.cc',
'../../src/heap/scavenger.h',
'../../src/heap/slots-buffer.cc',
'../../src/heap/slots-buffer.h',
'../../src/heap/spaces-inl.h',
'../../src/heap/spaces.cc',
'../../src/heap/spaces.h',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment