- Removed a few indirections by making the two SemiSpaces
part of NewSpace and made NewSpace statically allocated. - Eliminated indirection in MigrateObject. Review URL: http://codereview.chromium.org/7619 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@517 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
c63477df3d
commit
7cd44cea9b
@ -375,7 +375,6 @@ enum StateTag {
|
||||
#define OBJECT_SIZE_ALIGN(value) \
|
||||
((value + kObjectAlignmentMask) & ~kObjectAlignmentMask)
|
||||
|
||||
|
||||
// The expression OFFSET_OF(type, field) computes the byte-offset
|
||||
// of the specified field relative to the containing type. This
|
||||
// corresponds to 'offsetof' (in stddef.h), except that it doesn't
|
||||
|
@ -51,7 +51,7 @@ Object* Heap::AllocateRaw(int size_in_bytes,
|
||||
Counters::objs_since_last_young.Increment();
|
||||
#endif
|
||||
if (NEW_SPACE == space) {
|
||||
return new_space_->AllocateRaw(size_in_bytes);
|
||||
return new_space_.AllocateRaw(size_in_bytes);
|
||||
}
|
||||
|
||||
Object* result;
|
||||
@ -100,17 +100,17 @@ Object* Heap::AllocateRawMap(int size_in_bytes) {
|
||||
|
||||
|
||||
bool Heap::InNewSpace(Object* object) {
|
||||
return new_space_->Contains(object);
|
||||
return new_space_.Contains(object);
|
||||
}
|
||||
|
||||
|
||||
bool Heap::InFromSpace(Object* object) {
|
||||
return new_space_->FromSpaceContains(object);
|
||||
return new_space_.FromSpaceContains(object);
|
||||
}
|
||||
|
||||
|
||||
bool Heap::InToSpace(Object* object) {
|
||||
return new_space_->ToSpaceContains(object);
|
||||
return new_space_.ToSpaceContains(object);
|
||||
}
|
||||
|
||||
|
||||
@ -118,14 +118,14 @@ bool Heap::ShouldBePromoted(Address old_address, int object_size) {
|
||||
// An object should be promoted if:
|
||||
// - the object has survived a scavenge operation or
|
||||
// - to space is already 25% full.
|
||||
return old_address < new_space_->age_mark()
|
||||
|| (new_space_->Size() + object_size) >= (new_space_->Capacity() >> 2);
|
||||
return old_address < new_space_.age_mark()
|
||||
|| (new_space_.Size() + object_size) >= (new_space_.Capacity() >> 2);
|
||||
}
|
||||
|
||||
|
||||
void Heap::RecordWrite(Address address, int offset) {
|
||||
if (new_space_->Contains(address)) return;
|
||||
ASSERT(!new_space_->FromSpaceContains(address));
|
||||
if (new_space_.Contains(address)) return;
|
||||
ASSERT(!new_space_.FromSpaceContains(address));
|
||||
SLOW_ASSERT(Contains(address + offset));
|
||||
Page::SetRSet(address, offset);
|
||||
}
|
||||
|
119
src/heap.cc
119
src/heap.cc
@ -57,8 +57,7 @@ namespace v8 { namespace internal {
|
||||
SYMBOL_LIST(SYMBOL_ALLOCATION)
|
||||
#undef SYMBOL_ALLOCATION
|
||||
|
||||
|
||||
NewSpace* Heap::new_space_ = NULL;
|
||||
NewSpace Heap::new_space_;
|
||||
OldSpace* Heap::old_pointer_space_ = NULL;
|
||||
OldSpace* Heap::old_data_space_ = NULL;
|
||||
OldSpace* Heap::code_space_ = NULL;
|
||||
@ -103,7 +102,7 @@ bool Heap::disallow_allocation_failure_ = false;
|
||||
int Heap::Capacity() {
|
||||
if (!HasBeenSetup()) return 0;
|
||||
|
||||
return new_space_->Capacity() +
|
||||
return new_space_.Capacity() +
|
||||
old_pointer_space_->Capacity() +
|
||||
old_data_space_->Capacity() +
|
||||
code_space_->Capacity() +
|
||||
@ -114,7 +113,7 @@ int Heap::Capacity() {
|
||||
int Heap::Available() {
|
||||
if (!HasBeenSetup()) return 0;
|
||||
|
||||
return new_space_->Available() +
|
||||
return new_space_.Available() +
|
||||
old_pointer_space_->Available() +
|
||||
old_data_space_->Available() +
|
||||
code_space_->Available() +
|
||||
@ -123,8 +122,7 @@ int Heap::Available() {
|
||||
|
||||
|
||||
bool Heap::HasBeenSetup() {
|
||||
return new_space_ != NULL &&
|
||||
old_pointer_space_ != NULL &&
|
||||
return old_pointer_space_ != NULL &&
|
||||
old_data_space_ != NULL &&
|
||||
code_space_ != NULL &&
|
||||
map_space_ != NULL &&
|
||||
@ -161,7 +159,7 @@ GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space) {
|
||||
// and does not count available bytes already in the old space or code
|
||||
// space. Undercounting is safe---we may get an unrequested full GC when
|
||||
// a scavenge would have succeeded.
|
||||
if (MemoryAllocator::MaxAvailable() <= new_space_->Size()) {
|
||||
if (MemoryAllocator::MaxAvailable() <= new_space_.Size()) {
|
||||
Counters::gc_compactor_caused_by_oldspace_exhaustion.Increment();
|
||||
return MARK_COMPACTOR;
|
||||
}
|
||||
@ -179,24 +177,24 @@ void Heap::ReportStatisticsBeforeGC() {
|
||||
// compiled with ENABLE_LOGGING_AND_PROFILING and --log-gc is set. The
|
||||
// following logic is used to avoid double logging.
|
||||
#if defined(DEBUG) && defined(ENABLE_LOGGING_AND_PROFILING)
|
||||
if (FLAG_heap_stats || FLAG_log_gc) new_space_->CollectStatistics();
|
||||
if (FLAG_heap_stats || FLAG_log_gc) new_space_.CollectStatistics();
|
||||
if (FLAG_heap_stats) {
|
||||
ReportHeapStatistics("Before GC");
|
||||
} else if (FLAG_log_gc) {
|
||||
new_space_->ReportStatistics();
|
||||
new_space_.ReportStatistics();
|
||||
}
|
||||
if (FLAG_heap_stats || FLAG_log_gc) new_space_->ClearHistograms();
|
||||
if (FLAG_heap_stats || FLAG_log_gc) new_space_.ClearHistograms();
|
||||
#elif defined(DEBUG)
|
||||
if (FLAG_heap_stats) {
|
||||
new_space_->CollectStatistics();
|
||||
new_space_.CollectStatistics();
|
||||
ReportHeapStatistics("Before GC");
|
||||
new_space_->ClearHistograms();
|
||||
new_space_.ClearHistograms();
|
||||
}
|
||||
#elif defined(ENABLE_LOGGING_AND_PROFILING)
|
||||
if (FLAG_log_gc) {
|
||||
new_space_->CollectStatistics();
|
||||
new_space_->ReportStatistics();
|
||||
new_space_->ClearHistograms();
|
||||
new_space_.CollectStatistics();
|
||||
new_space_.ReportStatistics();
|
||||
new_space_.ClearHistograms();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -211,12 +209,12 @@ void Heap::ReportStatisticsAfterGC() {
|
||||
if (FLAG_heap_stats) {
|
||||
ReportHeapStatistics("After GC");
|
||||
} else if (FLAG_log_gc) {
|
||||
new_space_->ReportStatistics();
|
||||
new_space_.ReportStatistics();
|
||||
}
|
||||
#elif defined(DEBUG)
|
||||
if (FLAG_heap_stats) ReportHeapStatistics("After GC");
|
||||
#elif defined(ENABLE_LOGGING_AND_PROFILING)
|
||||
if (FLAG_log_gc) new_space_->ReportStatistics();
|
||||
if (FLAG_log_gc) new_space_.ReportStatistics();
|
||||
#endif
|
||||
}
|
||||
#endif // defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
|
||||
@ -329,7 +327,7 @@ bool Heap::CollectGarbage(int requested_size, AllocationSpace space) {
|
||||
|
||||
switch (space) {
|
||||
case NEW_SPACE:
|
||||
return new_space_->Available() >= requested_size;
|
||||
return new_space_.Available() >= requested_size;
|
||||
case OLD_POINTER_SPACE:
|
||||
return old_pointer_space_->Available() >= requested_size;
|
||||
case OLD_DATA_SPACE:
|
||||
@ -461,7 +459,7 @@ class CopyVisitor: public ObjectVisitor {
|
||||
|
||||
private:
|
||||
void CopyObject(Object** p) {
|
||||
if (!Heap::InFromSpace(*p)) return;
|
||||
if (!Heap::InNewSpace(*p)) return;
|
||||
Heap::CopyObject(reinterpret_cast<HeapObject**>(p));
|
||||
}
|
||||
};
|
||||
@ -510,21 +508,21 @@ void Heap::Scavenge() {
|
||||
LOG(ResourceEvent("scavenge", "begin"));
|
||||
|
||||
scavenge_count_++;
|
||||
if (new_space_->Capacity() < new_space_->MaximumCapacity() &&
|
||||
if (new_space_.Capacity() < new_space_.MaximumCapacity() &&
|
||||
scavenge_count_ > new_space_growth_limit_) {
|
||||
// Double the size of the new space, and double the limit. The next
|
||||
// doubling attempt will occur after the current new_space_growth_limit_
|
||||
// more collections.
|
||||
// TODO(1240712): NewSpace::Double has a return value which is
|
||||
// ignored here.
|
||||
new_space_->Double();
|
||||
new_space_.Double();
|
||||
new_space_growth_limit_ *= 2;
|
||||
}
|
||||
|
||||
// Flip the semispaces. After flipping, to space is empty, from space has
|
||||
// live objects.
|
||||
new_space_->Flip();
|
||||
new_space_->ResetAllocationInfo();
|
||||
new_space_.Flip();
|
||||
new_space_.ResetAllocationInfo();
|
||||
|
||||
// We need to sweep newly copied objects which can be in either the to space
|
||||
// or the old space. For to space objects, we use a mark. Newly copied
|
||||
@ -540,9 +538,9 @@ void Heap::Scavenge() {
|
||||
// in size. Using the new space to record promoted addresses makes the
|
||||
// scavenge collector agnostic to the allocation strategy (eg, linear or
|
||||
// free-list) used in old space.
|
||||
Address new_mark = new_space_->ToSpaceLow();
|
||||
Address promoted_mark = new_space_->ToSpaceHigh();
|
||||
promoted_top = new_space_->ToSpaceHigh();
|
||||
Address new_mark = new_space_.ToSpaceLow();
|
||||
Address promoted_mark = new_space_.ToSpaceHigh();
|
||||
promoted_top = new_space_.ToSpaceHigh();
|
||||
|
||||
CopyVisitor copy_visitor;
|
||||
// Copy roots.
|
||||
@ -557,15 +555,15 @@ void Heap::Scavenge() {
|
||||
bool has_processed_weak_pointers = false;
|
||||
|
||||
while (true) {
|
||||
ASSERT(new_mark <= new_space_->top());
|
||||
ASSERT(new_mark <= new_space_.top());
|
||||
ASSERT(promoted_mark >= promoted_top);
|
||||
|
||||
// Copy objects reachable from newly copied objects.
|
||||
while (new_mark < new_space_->top() || promoted_mark > promoted_top) {
|
||||
while (new_mark < new_space_.top() || promoted_mark > promoted_top) {
|
||||
// Sweep newly copied objects in the to space. The allocation pointer
|
||||
// can change during sweeping.
|
||||
Address previous_top = new_space_->top();
|
||||
SemiSpaceIterator new_it(new_space_, new_mark);
|
||||
Address previous_top = new_space_.top();
|
||||
SemiSpaceIterator new_it(new_space(), new_mark);
|
||||
while (new_it.has_next()) {
|
||||
new_it.next()->Iterate(©_visitor);
|
||||
}
|
||||
@ -591,7 +589,7 @@ void Heap::Scavenge() {
|
||||
}
|
||||
|
||||
// Set age mark.
|
||||
new_space_->set_age_mark(new_mark);
|
||||
new_space_.set_age_mark(new_mark);
|
||||
|
||||
LOG(ResourceEvent("scavenge", "end"));
|
||||
|
||||
@ -718,20 +716,20 @@ void Heap::RecordCopiedObject(HeapObject* obj) {
|
||||
should_record = should_record || FLAG_log_gc;
|
||||
#endif
|
||||
if (should_record) {
|
||||
if (new_space_->Contains(obj)) {
|
||||
new_space_->RecordAllocation(obj);
|
||||
if (new_space_.Contains(obj)) {
|
||||
new_space_.RecordAllocation(obj);
|
||||
} else {
|
||||
new_space_->RecordPromotion(obj);
|
||||
new_space_.RecordPromotion(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
|
||||
|
||||
|
||||
HeapObject* Heap::MigrateObject(HeapObject** source_p,
|
||||
HeapObject* Heap::MigrateObject(HeapObject* source,
|
||||
HeapObject* target,
|
||||
int size) {
|
||||
void** src = reinterpret_cast<void**>((*source_p)->address());
|
||||
void** src = reinterpret_cast<void**>(source->address());
|
||||
void** dst = reinterpret_cast<void**>(target->address());
|
||||
|
||||
// Use block copying memcpy if the object we're migrating is big
|
||||
@ -749,7 +747,7 @@ HeapObject* Heap::MigrateObject(HeapObject** source_p,
|
||||
}
|
||||
|
||||
// Set the forwarding address.
|
||||
(*source_p)->set_map_word(MapWord::FromForwardingAddress(target));
|
||||
source->set_map_word(MapWord::FromForwardingAddress(target));
|
||||
|
||||
// Update NewSpace stats if necessary.
|
||||
#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
|
||||
@ -789,7 +787,7 @@ void Heap::CopyObject(HeapObject** p) {
|
||||
*p = object;
|
||||
// After patching *p we have to repeat the checks that object is in the
|
||||
// active semispace of the young generation and not already copied.
|
||||
if (!InFromSpace(object)) return;
|
||||
if (!InNewSpace(object)) return;
|
||||
first_word = object->map_word();
|
||||
if (first_word.IsForwardingAddress()) {
|
||||
*p = first_word.ToForwardingAddress();
|
||||
@ -808,7 +806,7 @@ void Heap::CopyObject(HeapObject** p) {
|
||||
result = target_space->AllocateRaw(object_size);
|
||||
|
||||
if (!result->IsFailure()) {
|
||||
*p = MigrateObject(p, HeapObject::cast(result), object_size);
|
||||
*p = MigrateObject(object, HeapObject::cast(result), object_size);
|
||||
if (target_space == Heap::old_pointer_space_) {
|
||||
// Record the object's address at the top of the to space, to allow
|
||||
// it to be swept by the scavenger.
|
||||
@ -827,10 +825,10 @@ void Heap::CopyObject(HeapObject** p) {
|
||||
}
|
||||
|
||||
// The object should remain in new space or the old space allocation failed.
|
||||
result = new_space_->AllocateRaw(object_size);
|
||||
result = new_space_.AllocateRaw(object_size);
|
||||
// Failed allocation at this point is utterly unexpected.
|
||||
ASSERT(!result->IsFailure());
|
||||
*p = MigrateObject(p, HeapObject::cast(result), object_size);
|
||||
*p = MigrateObject(object, HeapObject::cast(result), object_size);
|
||||
}
|
||||
|
||||
|
||||
@ -1030,7 +1028,7 @@ Object* Heap::AllocateHeapNumber(double value) {
|
||||
// allocation in new space.
|
||||
STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxHeapObjectSize);
|
||||
ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
|
||||
Object* result = new_space_->AllocateRaw(HeapNumber::kSize);
|
||||
Object* result = new_space_.AllocateRaw(HeapNumber::kSize);
|
||||
if (result->IsFailure()) return result;
|
||||
HeapObject::cast(result)->set_map(heap_number_map());
|
||||
HeapNumber::cast(result)->set_value(value);
|
||||
@ -2191,7 +2189,7 @@ void Heap::ReportHeapStatistics(const char* title) {
|
||||
PrintF("Heap statistics : ");
|
||||
MemoryAllocator::ReportStatistics();
|
||||
PrintF("To space : ");
|
||||
new_space_->ReportStatistics();
|
||||
new_space_.ReportStatistics();
|
||||
PrintF("Old pointer space : ");
|
||||
old_pointer_space_->ReportStatistics();
|
||||
PrintF("Old data space : ");
|
||||
@ -2215,7 +2213,7 @@ bool Heap::Contains(HeapObject* value) {
|
||||
bool Heap::Contains(Address addr) {
|
||||
if (OS::IsOutsideAllocatedSpace(addr)) return false;
|
||||
return HasBeenSetup() &&
|
||||
(new_space_->ToSpaceContains(addr) ||
|
||||
(new_space_.ToSpaceContains(addr) ||
|
||||
old_pointer_space_->Contains(addr) ||
|
||||
old_data_space_->Contains(addr) ||
|
||||
code_space_->Contains(addr) ||
|
||||
@ -2235,7 +2233,7 @@ bool Heap::InSpace(Address addr, AllocationSpace space) {
|
||||
|
||||
switch (space) {
|
||||
case NEW_SPACE:
|
||||
return new_space_->ToSpaceContains(addr);
|
||||
return new_space_.ToSpaceContains(addr);
|
||||
case OLD_POINTER_SPACE:
|
||||
return old_pointer_space_->Contains(addr);
|
||||
case OLD_DATA_SPACE:
|
||||
@ -2303,8 +2301,8 @@ bool Heap::LookupSymbolIfExists(String* string, String** symbol) {
|
||||
#ifdef DEBUG
|
||||
void Heap::ZapFromSpace() {
|
||||
ASSERT(HAS_HEAP_OBJECT_TAG(kFromSpaceZapValue));
|
||||
for (Address a = new_space_->FromSpaceLow();
|
||||
a < new_space_->FromSpaceHigh();
|
||||
for (Address a = new_space_.FromSpaceLow();
|
||||
a < new_space_.FromSpaceHigh();
|
||||
a += kPointerSize) {
|
||||
Memory::Address_at(a) = kFromSpaceZapValue;
|
||||
}
|
||||
@ -2322,29 +2320,21 @@ void Heap::IterateRSetRange(Address object_start,
|
||||
// Loop over all the pointers in [object_start, object_end).
|
||||
while (object_address < object_end) {
|
||||
uint32_t rset_word = Memory::uint32_at(rset_address);
|
||||
|
||||
if (rset_word != 0) {
|
||||
// Bits were set.
|
||||
uint32_t result_rset = rset_word;
|
||||
|
||||
// Loop over all the bits in the remembered set word. Though
|
||||
// remembered sets are sparse, faster (eg, binary) search for
|
||||
// set bits does not seem to help much here.
|
||||
for (int bit_offset = 0; bit_offset < kBitsPerInt; bit_offset++) {
|
||||
uint32_t bitmask = 1 << bit_offset;
|
||||
for (uint32_t bitmask = 1; bitmask != 0; bitmask = bitmask << 1) {
|
||||
// Do not dereference pointers at or past object_end.
|
||||
if ((rset_word & bitmask) != 0 && object_address < object_end) {
|
||||
Object** object_p = reinterpret_cast<Object**>(object_address);
|
||||
if (Heap::InFromSpace(*object_p)) {
|
||||
if (Heap::InNewSpace(*object_p)) {
|
||||
copy_object_func(reinterpret_cast<HeapObject**>(object_p));
|
||||
}
|
||||
// If this pointer does not need to be remembered anymore, clear
|
||||
// the remembered set bit.
|
||||
if (!Heap::InToSpace(*object_p)) result_rset &= ~bitmask;
|
||||
if (!Heap::InNewSpace(*object_p)) result_rset &= ~bitmask;
|
||||
}
|
||||
object_address += kPointerSize;
|
||||
}
|
||||
|
||||
// Update the remembered set if it has changed.
|
||||
if (result_rset != rset_word) {
|
||||
Memory::uint32_at(rset_address) = result_rset;
|
||||
@ -2353,7 +2343,6 @@ void Heap::IterateRSetRange(Address object_start,
|
||||
// No bits in the word were set. This is the common case.
|
||||
object_address += kPointerSize * kBitsPerInt;
|
||||
}
|
||||
|
||||
rset_address += kIntSize;
|
||||
}
|
||||
}
|
||||
@ -2517,11 +2506,7 @@ bool Heap::Setup(bool create_heap_objects) {
|
||||
int old_space_size = young_generation_size_ - code_space_size;
|
||||
|
||||
// Initialize new space.
|
||||
new_space_ = new NewSpace(initial_semispace_size_,
|
||||
semispace_size_,
|
||||
NEW_SPACE);
|
||||
if (new_space_ == NULL) return false;
|
||||
if (!new_space_->Setup(new_space_start, young_generation_size_)) return false;
|
||||
if (!new_space_.Setup(new_space_start, young_generation_size_)) return false;
|
||||
|
||||
// Initialize old space, set the maximum capacity to the old generation
|
||||
// size. It will not contain code.
|
||||
@ -2579,11 +2564,7 @@ bool Heap::Setup(bool create_heap_objects) {
|
||||
void Heap::TearDown() {
|
||||
GlobalHandles::TearDown();
|
||||
|
||||
if (new_space_ != NULL) {
|
||||
new_space_->TearDown();
|
||||
delete new_space_;
|
||||
new_space_ = NULL;
|
||||
}
|
||||
new_space_.TearDown();
|
||||
|
||||
if (old_pointer_space_ != NULL) {
|
||||
old_pointer_space_->TearDown();
|
||||
|
16
src/heap.h
16
src/heap.h
@ -244,11 +244,11 @@ class Heap : public AllStatic {
|
||||
// Return the starting address and a mask for the new space. And-masking an
|
||||
// address with the mask will result in the start address of the new space
|
||||
// for all addresses in either semispace.
|
||||
static Address NewSpaceStart() { return new_space_->start(); }
|
||||
static uint32_t NewSpaceMask() { return new_space_->mask(); }
|
||||
static Address NewSpaceTop() { return new_space_->top(); }
|
||||
static Address NewSpaceStart() { return new_space_.start(); }
|
||||
static uint32_t NewSpaceMask() { return new_space_.mask(); }
|
||||
static Address NewSpaceTop() { return new_space_.top(); }
|
||||
|
||||
static NewSpace* new_space() { return new_space_; }
|
||||
static NewSpace* new_space() { return &new_space_; }
|
||||
static OldSpace* old_pointer_space() { return old_pointer_space_; }
|
||||
static OldSpace* old_data_space() { return old_data_space_; }
|
||||
static OldSpace* code_space() { return code_space_; }
|
||||
@ -256,10 +256,10 @@ class Heap : public AllStatic {
|
||||
static LargeObjectSpace* lo_space() { return lo_space_; }
|
||||
|
||||
static Address* NewSpaceAllocationTopAddress() {
|
||||
return new_space_->allocation_top_address();
|
||||
return new_space_.allocation_top_address();
|
||||
}
|
||||
static Address* NewSpaceAllocationLimitAddress() {
|
||||
return new_space_->allocation_limit_address();
|
||||
return new_space_.allocation_limit_address();
|
||||
}
|
||||
|
||||
// Allocates and initializes a new JavaScript object based on a
|
||||
@ -727,7 +727,7 @@ class Heap : public AllStatic {
|
||||
|
||||
static const int kMaxMapSpaceSize = 8*MB;
|
||||
|
||||
static NewSpace* new_space_;
|
||||
static NewSpace new_space_;
|
||||
static OldSpace* old_pointer_space_;
|
||||
static OldSpace* old_data_space_;
|
||||
static OldSpace* code_space_;
|
||||
@ -839,7 +839,7 @@ class Heap : public AllStatic {
|
||||
// Helper function used by CopyObject to copy a source object to an
|
||||
// allocated target object and update the forwarding pointer in the source
|
||||
// object. Returns the target object.
|
||||
static HeapObject* MigrateObject(HeapObject** source_p,
|
||||
static HeapObject* MigrateObject(HeapObject* source,
|
||||
HeapObject* target,
|
||||
int size);
|
||||
|
||||
|
@ -308,7 +308,7 @@ Object* NewSpace::AllocateRawInternal(int size_in_bytes,
|
||||
alloc_info->top = new_top;
|
||||
#ifdef DEBUG
|
||||
SemiSpace* space =
|
||||
(alloc_info == &allocation_info_) ? to_space_ : from_space_;
|
||||
(alloc_info == &allocation_info_) ? &to_space_ : &from_space_;
|
||||
ASSERT(space->low() <= alloc_info->top
|
||||
&& alloc_info->top <= space->high()
|
||||
&& alloc_info->limit == space->high());
|
||||
|
@ -36,9 +36,9 @@ namespace v8 { namespace internal {
|
||||
// For contiguous spaces, top should be in the space (or at the end) and limit
|
||||
// should be the end of the space.
|
||||
#define ASSERT_SEMISPACE_ALLOCATION_INFO(info, space) \
|
||||
ASSERT((space)->low() <= (info).top \
|
||||
&& (info).top <= (space)->high() \
|
||||
&& (info).limit == (space)->high())
|
||||
ASSERT((space).low() <= (info).top \
|
||||
&& (info).top <= (space).high() \
|
||||
&& (info).limit == (space).high())
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -760,16 +760,19 @@ void PagedSpace::Print() { }
|
||||
// -----------------------------------------------------------------------------
|
||||
// NewSpace implementation
|
||||
|
||||
NewSpace::NewSpace(int initial_semispace_capacity,
|
||||
int maximum_semispace_capacity,
|
||||
AllocationSpace id)
|
||||
: Space(id, NOT_EXECUTABLE) {
|
||||
|
||||
bool NewSpace::Setup(Address start, int size) {
|
||||
// Setup new space based on the preallocated memory block defined by
|
||||
// start and size. The provided space is divided into two semi-spaces.
|
||||
// To support fast containment testing in the new space, the size of
|
||||
// this chunk must be a power of two and it must be aligned to its size.
|
||||
int initial_semispace_capacity = Heap::InitialSemiSpaceSize();
|
||||
int maximum_semispace_capacity = Heap::SemiSpaceSize();
|
||||
|
||||
ASSERT(initial_semispace_capacity <= maximum_semispace_capacity);
|
||||
ASSERT(IsPowerOf2(maximum_semispace_capacity));
|
||||
maximum_capacity_ = maximum_semispace_capacity;
|
||||
capacity_ = initial_semispace_capacity;
|
||||
to_space_ = new SemiSpace(capacity_, maximum_capacity_, id);
|
||||
from_space_ = new SemiSpace(capacity_, maximum_capacity_, id);
|
||||
|
||||
// Allocate and setup the histogram arrays if necessary.
|
||||
#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
|
||||
@ -781,19 +784,16 @@ NewSpace::NewSpace(int initial_semispace_capacity,
|
||||
INSTANCE_TYPE_LIST(SET_NAME)
|
||||
#undef SET_NAME
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool NewSpace::Setup(Address start, int size) {
|
||||
ASSERT(size == 2 * maximum_capacity_);
|
||||
ASSERT(IsAddressAligned(start, size, 0));
|
||||
|
||||
if (to_space_ == NULL
|
||||
|| !to_space_->Setup(start, maximum_capacity_)) {
|
||||
if (!to_space_.Setup(start, capacity_, maximum_capacity_)) {
|
||||
return false;
|
||||
}
|
||||
if (from_space_ == NULL
|
||||
|| !from_space_->Setup(start + maximum_capacity_, maximum_capacity_)) {
|
||||
if (!from_space_.Setup(start + maximum_capacity_,
|
||||
capacity_,
|
||||
maximum_capacity_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -802,8 +802,8 @@ bool NewSpace::Setup(Address start, int size) {
|
||||
object_mask_ = address_mask_ | kHeapObjectTag;
|
||||
object_expected_ = reinterpret_cast<uint32_t>(start) | kHeapObjectTag;
|
||||
|
||||
allocation_info_.top = to_space_->low();
|
||||
allocation_info_.limit = to_space_->high();
|
||||
allocation_info_.top = to_space_.low();
|
||||
allocation_info_.limit = to_space_.high();
|
||||
mc_forwarding_info_.top = NULL;
|
||||
mc_forwarding_info_.limit = NULL;
|
||||
|
||||
@ -831,22 +831,13 @@ void NewSpace::TearDown() {
|
||||
mc_forwarding_info_.top = NULL;
|
||||
mc_forwarding_info_.limit = NULL;
|
||||
|
||||
if (to_space_ != NULL) {
|
||||
to_space_->TearDown();
|
||||
delete to_space_;
|
||||
to_space_ = NULL;
|
||||
}
|
||||
|
||||
if (from_space_ != NULL) {
|
||||
from_space_->TearDown();
|
||||
delete from_space_;
|
||||
from_space_ = NULL;
|
||||
}
|
||||
to_space_.TearDown();
|
||||
from_space_.TearDown();
|
||||
}
|
||||
|
||||
|
||||
void NewSpace::Flip() {
|
||||
SemiSpace* tmp = from_space_;
|
||||
SemiSpace tmp = from_space_;
|
||||
from_space_ = to_space_;
|
||||
to_space_ = tmp;
|
||||
}
|
||||
@ -857,24 +848,24 @@ bool NewSpace::Double() {
|
||||
// TODO(1240712): Failure to double the from space can result in
|
||||
// semispaces of different sizes. In the event of that failure, the
|
||||
// to space doubling should be rolled back before returning false.
|
||||
if (!to_space_->Double() || !from_space_->Double()) return false;
|
||||
if (!to_space_.Double() || !from_space_.Double()) return false;
|
||||
capacity_ *= 2;
|
||||
allocation_info_.limit = to_space_->high();
|
||||
allocation_info_.limit = to_space_.high();
|
||||
ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void NewSpace::ResetAllocationInfo() {
|
||||
allocation_info_.top = to_space_->low();
|
||||
allocation_info_.limit = to_space_->high();
|
||||
allocation_info_.top = to_space_.low();
|
||||
allocation_info_.limit = to_space_.high();
|
||||
ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
|
||||
}
|
||||
|
||||
|
||||
void NewSpace::MCResetRelocationInfo() {
|
||||
mc_forwarding_info_.top = from_space_->low();
|
||||
mc_forwarding_info_.limit = from_space_->high();
|
||||
mc_forwarding_info_.top = from_space_.low();
|
||||
mc_forwarding_info_.limit = from_space_.high();
|
||||
ASSERT_SEMISPACE_ALLOCATION_INFO(mc_forwarding_info_, from_space_);
|
||||
}
|
||||
|
||||
@ -883,7 +874,7 @@ void NewSpace::MCCommitRelocationInfo() {
|
||||
// Assumes that the spaces have been flipped so that mc_forwarding_info_ is
|
||||
// valid allocation info for the to space.
|
||||
allocation_info_.top = mc_forwarding_info_.top;
|
||||
allocation_info_.limit = to_space_->high();
|
||||
allocation_info_.limit = to_space_.high();
|
||||
ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
|
||||
}
|
||||
|
||||
@ -897,7 +888,7 @@ void NewSpace::Verify() {
|
||||
|
||||
// There should be objects packed in from the low address up to the
|
||||
// allocation pointer.
|
||||
Address current = to_space_->low();
|
||||
Address current = to_space_.low();
|
||||
while (current < top()) {
|
||||
HeapObject* object = HeapObject::FromAddress(current);
|
||||
|
||||
@ -931,22 +922,24 @@ void NewSpace::Verify() {
|
||||
// -----------------------------------------------------------------------------
|
||||
// SemiSpace implementation
|
||||
|
||||
SemiSpace::SemiSpace(int initial_capacity,
|
||||
int maximum_capacity,
|
||||
AllocationSpace id)
|
||||
: Space(id, NOT_EXECUTABLE), capacity_(initial_capacity),
|
||||
maximum_capacity_(maximum_capacity), start_(NULL), age_mark_(NULL) {
|
||||
}
|
||||
bool SemiSpace::Setup(Address start,
|
||||
int initial_capacity,
|
||||
int maximum_capacity) {
|
||||
// Creates a space in the young generation. The constructor does not
|
||||
// allocate memory from the OS. A SemiSpace is given a contiguous chunk of
|
||||
// memory of size 'capacity' when set up, and does not grow or shrink
|
||||
// otherwise. In the mark-compact collector, the memory region of the from
|
||||
// space is used as the marking stack. It requires contiguous memory
|
||||
// addresses.
|
||||
capacity_ = initial_capacity;
|
||||
maximum_capacity_ = maximum_capacity;
|
||||
|
||||
|
||||
bool SemiSpace::Setup(Address start, int size) {
|
||||
ASSERT(size == maximum_capacity_);
|
||||
if (!MemoryAllocator::CommitBlock(start, capacity_, executable())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
start_ = start;
|
||||
address_mask_ = ~(size - 1);
|
||||
address_mask_ = ~(maximum_capacity - 1);
|
||||
object_mask_ = address_mask_ | kHeapObjectTag;
|
||||
object_expected_ = reinterpret_cast<uint32_t>(start) | kHeapObjectTag;
|
||||
|
||||
@ -1002,7 +995,7 @@ void SemiSpaceIterator::Initialize(NewSpace* space, Address start,
|
||||
ASSERT(space->ToSpaceContains(start));
|
||||
ASSERT(space->ToSpaceLow() <= end
|
||||
&& end <= space->ToSpaceHigh());
|
||||
space_ = space->to_space_;
|
||||
space_ = &space->to_space_;
|
||||
current_ = start;
|
||||
limit_ = end;
|
||||
size_func_ = size_func;
|
||||
|
63
src/spaces.h
63
src/spaces.h
@ -878,19 +878,14 @@ class HistogramInfo BASE_EMBEDDED {
|
||||
|
||||
class SemiSpace : public Space {
|
||||
public:
|
||||
// Creates a space in the young generation. The constructor does not
|
||||
// allocate memory from the OS. A SemiSpace is given a contiguous chunk of
|
||||
// memory of size 'capacity' when set up, and does not grow or shrink
|
||||
// otherwise. In the mark-compact collector, the memory region of the from
|
||||
// space is used as the marking stack. It requires contiguous memory
|
||||
// addresses.
|
||||
SemiSpace(int initial_capacity,
|
||||
int maximum_capacity,
|
||||
AllocationSpace id);
|
||||
virtual ~SemiSpace() {}
|
||||
// Constructor.
|
||||
SemiSpace() :Space(NEW_SPACE, NOT_EXECUTABLE) {
|
||||
start_ = NULL;
|
||||
age_mark_ = NULL;
|
||||
}
|
||||
|
||||
// Sets up the semispace using the given chunk.
|
||||
bool Setup(Address start, int size);
|
||||
bool Setup(Address start, int initial_capacity, int maximum_capacity);
|
||||
|
||||
// Tear down the space. Heap memory was not allocated by the space, so it
|
||||
// is not deallocated here.
|
||||
@ -1016,16 +1011,8 @@ class SemiSpaceIterator : public ObjectIterator {
|
||||
|
||||
class NewSpace : public Space {
|
||||
public:
|
||||
// Create a new space with a given allocation capacity (ie, the capacity of
|
||||
// *one* of the semispaces). The constructor does not allocate heap memory
|
||||
// from the OS. When the space is set up, it is given a contiguous chunk of
|
||||
// memory of size 2 * semispace_capacity. To support fast containment
|
||||
// testing in the new space, the size of this chunk must be a power of two
|
||||
// and it must be aligned to its size.
|
||||
NewSpace(int initial_semispace_capacity,
|
||||
int maximum_semispace_capacity,
|
||||
AllocationSpace id);
|
||||
virtual ~NewSpace() {}
|
||||
// Constructor.
|
||||
NewSpace() : Space(NEW_SPACE, NOT_EXECUTABLE) {}
|
||||
|
||||
// Sets up the new space using the given chunk.
|
||||
bool Setup(Address start, int size);
|
||||
@ -1036,7 +1023,7 @@ class NewSpace : public Space {
|
||||
|
||||
// True if the space has been set up but not torn down.
|
||||
bool HasBeenSetup() {
|
||||
return to_space_->HasBeenSetup() && from_space_->HasBeenSetup();
|
||||
return to_space_.HasBeenSetup() && from_space_.HasBeenSetup();
|
||||
}
|
||||
|
||||
// Flip the pair of spaces.
|
||||
@ -1069,12 +1056,12 @@ class NewSpace : public Space {
|
||||
// Return the address of the allocation pointer in the active semispace.
|
||||
Address top() { return allocation_info_.top; }
|
||||
// Return the address of the first object in the active semispace.
|
||||
Address bottom() { return to_space_->low(); }
|
||||
Address bottom() { return to_space_.low(); }
|
||||
|
||||
// Get the age mark of the inactive semispace.
|
||||
Address age_mark() { return from_space_->age_mark(); }
|
||||
Address age_mark() { return from_space_.age_mark(); }
|
||||
// Set the age mark in the active semispace.
|
||||
void set_age_mark(Address mark) { to_space_->set_age_mark(mark); }
|
||||
void set_age_mark(Address mark) { to_space_.set_age_mark(mark); }
|
||||
|
||||
// The start address of the space and a bit mask. Anding an address in the
|
||||
// new space with the mask will result in the start address.
|
||||
@ -1105,36 +1092,36 @@ class NewSpace : public Space {
|
||||
void MCCommitRelocationInfo();
|
||||
|
||||
// Get the extent of the inactive semispace (for use as a marking stack).
|
||||
Address FromSpaceLow() { return from_space_->low(); }
|
||||
Address FromSpaceHigh() { return from_space_->high(); }
|
||||
Address FromSpaceLow() { return from_space_.low(); }
|
||||
Address FromSpaceHigh() { return from_space_.high(); }
|
||||
|
||||
// Get the extent of the active semispace (to sweep newly copied objects
|
||||
// during a scavenge collection).
|
||||
Address ToSpaceLow() { return to_space_->low(); }
|
||||
Address ToSpaceHigh() { return to_space_->high(); }
|
||||
Address ToSpaceLow() { return to_space_.low(); }
|
||||
Address ToSpaceHigh() { return to_space_.high(); }
|
||||
|
||||
// Offsets from the beginning of the semispaces.
|
||||
int ToSpaceOffsetForAddress(Address a) {
|
||||
return to_space_->SpaceOffsetForAddress(a);
|
||||
return to_space_.SpaceOffsetForAddress(a);
|
||||
}
|
||||
int FromSpaceOffsetForAddress(Address a) {
|
||||
return from_space_->SpaceOffsetForAddress(a);
|
||||
return from_space_.SpaceOffsetForAddress(a);
|
||||
}
|
||||
|
||||
// True if the object is a heap object in the address range of the
|
||||
// respective semispace (not necessarily below the allocation pointer of the
|
||||
// semispace).
|
||||
bool ToSpaceContains(Object* o) { return to_space_->Contains(o); }
|
||||
bool FromSpaceContains(Object* o) { return from_space_->Contains(o); }
|
||||
bool ToSpaceContains(Object* o) { return to_space_.Contains(o); }
|
||||
bool FromSpaceContains(Object* o) { return from_space_.Contains(o); }
|
||||
|
||||
bool ToSpaceContains(Address a) { return to_space_->Contains(a); }
|
||||
bool FromSpaceContains(Address a) { return from_space_->Contains(a); }
|
||||
bool ToSpaceContains(Address a) { return to_space_.Contains(a); }
|
||||
bool FromSpaceContains(Address a) { return from_space_.Contains(a); }
|
||||
|
||||
#ifdef DEBUG
|
||||
// Verify the active semispace.
|
||||
virtual void Verify();
|
||||
// Print the active semispace.
|
||||
virtual void Print() { to_space_->Print(); }
|
||||
virtual void Print() { to_space_.Print(); }
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
|
||||
@ -1158,8 +1145,8 @@ class NewSpace : public Space {
|
||||
int maximum_capacity_;
|
||||
|
||||
// The semispaces.
|
||||
SemiSpace* to_space_;
|
||||
SemiSpace* from_space_;
|
||||
SemiSpace to_space_;
|
||||
SemiSpace from_space_;
|
||||
|
||||
// Start address and bit mask for containment testing.
|
||||
Address start_;
|
||||
|
@ -157,27 +157,23 @@ TEST(NewSpace) {
|
||||
CHECK(Heap::ConfigureHeapDefault());
|
||||
CHECK(MemoryAllocator::Setup(Heap::MaxCapacity()));
|
||||
|
||||
NewSpace* s = new NewSpace(Heap::InitialSemiSpaceSize(),
|
||||
Heap::SemiSpaceSize(),
|
||||
NEW_SPACE);
|
||||
CHECK(s != NULL);
|
||||
NewSpace new_space;
|
||||
|
||||
void* chunk =
|
||||
MemoryAllocator::ReserveInitialChunk(2 * Heap::YoungGenerationSize());
|
||||
CHECK(chunk != NULL);
|
||||
Address start = RoundUp(static_cast<Address>(chunk),
|
||||
Heap::YoungGenerationSize());
|
||||
CHECK(s->Setup(start, Heap::YoungGenerationSize()));
|
||||
CHECK(s->HasBeenSetup());
|
||||
CHECK(new_space.Setup(start, Heap::YoungGenerationSize()));
|
||||
CHECK(new_space.HasBeenSetup());
|
||||
|
||||
while (s->Available() >= Page::kMaxHeapObjectSize) {
|
||||
Object* obj = s->AllocateRaw(Page::kMaxHeapObjectSize);
|
||||
while (new_space.Available() >= Page::kMaxHeapObjectSize) {
|
||||
Object* obj = new_space.AllocateRaw(Page::kMaxHeapObjectSize);
|
||||
CHECK(!obj->IsFailure());
|
||||
CHECK(s->Contains(HeapObject::cast(obj)));
|
||||
CHECK(new_space.Contains(HeapObject::cast(obj)));
|
||||
}
|
||||
|
||||
s->TearDown();
|
||||
delete s;
|
||||
new_space.TearDown();
|
||||
MemoryAllocator::TearDown();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user