diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/atomic_integer.h | 12 | ||||
| -rw-r--r-- | src/atomic_stack.h | 173 | ||||
| -rw-r--r-- | src/class_linker.cc | 1 | ||||
| -rw-r--r-- | src/heap.cc | 82 | ||||
| -rw-r--r-- | src/heap.h | 25 | ||||
| -rw-r--r-- | src/mark_stack.cc | 65 | ||||
| -rw-r--r-- | src/mark_stack.h | 111 | ||||
| -rw-r--r-- | src/mark_sweep.cc | 86 | ||||
| -rw-r--r-- | src/mark_sweep.h | 12 |
9 files changed, 303 insertions, 264 deletions
diff --git a/src/atomic_integer.h b/src/atomic_integer.h index 61b93cca37..54d5fd88a9 100644 --- a/src/atomic_integer.h +++ b/src/atomic_integer.h @@ -25,8 +25,14 @@ class AtomicInteger { public: AtomicInteger(int32_t value) : value_(value) { } + // Unsafe = operator for non atomic operations on the integer. + AtomicInteger& operator = (int32_t new_value) { + value_ = new_value; + return *this; + } + operator int32_t () const { - return get(); + return value_; } int32_t get() const { @@ -49,11 +55,11 @@ class AtomicInteger { return android_atomic_and(-value, &value_); } - int32_t operator ++ () { + int32_t operator ++ (int32_t) { return android_atomic_inc(&value_); } - int32_t operator -- () { + int32_t operator -- (int32_t) { return android_atomic_dec(&value_); } private: diff --git a/src/atomic_stack.h b/src/atomic_stack.h new file mode 100644 index 0000000000..349486101d --- /dev/null +++ b/src/atomic_stack.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_SRC_ATOMIC_STACK_H_ +#define ART_SRC_ATOMIC_STACK_H_ + +#include <string> + +#include "atomic_integer.h" +#include "UniquePtr.h" +#include "logging.h" +#include "macros.h" +#include "mem_map.h" +#include "utils.h" + +namespace art { + +template <typename T> +class AtomicStack { + public: + // Capacity is how many elements we can store in the stack. + static AtomicStack* Create(const std::string& name, size_t capacity) { + UniquePtr<AtomicStack> mark_stack(new AtomicStack(name, capacity)); + mark_stack->Init(); + return mark_stack.release(); + } + + ~AtomicStack(){ + + } + + void Reset() { + DCHECK(mem_map_.get() != NULL); + DCHECK(begin_ != NULL); + front_index_ = 0; + back_index_ = 0; + int result = madvise(begin_, sizeof(T) * capacity_, MADV_DONTNEED); + if (result == -1) { + PLOG(WARNING) << "madvise failed"; + } + } + + // Beware: Mixing atomic pushes and atomic pops will cause ABA problem. + + // Returns false if we overflowed the stack. + bool AtomicPushBack(const T& value) { + const int32_t index = back_index_++; + if (UNLIKELY(static_cast<size_t>(index) >= capacity_)) { + // Stack overflow. + back_index_--; + return false; + } + begin_[index] = value; + return true; + } + + void PushBack(const T& value) { + int32_t index = back_index_; + DCHECK_LT(static_cast<size_t>(index), capacity_); + back_index_ = index + 1; + begin_[index] = value; + } + + T PopBack() { + DCHECK_GT(back_index_, front_index_); + // Decrement the back index non atomically. + back_index_ = back_index_ - 1; + return begin_[back_index_]; + } + + T AtomicPopBack() { + // Decrement the back index non atomically. + int back_index = back_index_--; + DCHECK_GT(back_index, front_index_); + return begin_[back_index - 1]; + } + + // Take an item from the front of the stack. + T PopFront() { + int32_t index = front_index_; + DCHECK_LT(index, back_index_.get()); + front_index_ = front_index_ + 1; + return begin_[index]; + } + + bool IsEmpty() const { + return Size() == 0; + } + + size_t Size() const { + DCHECK_LE(front_index_, back_index_); + return back_index_ - front_index_; + } + + T* Begin() { + return const_cast<Object**>(begin_ + front_index_); + } + + T* End() { + return const_cast<Object**>(begin_ + back_index_); + } + + size_t Capacity() const { + return capacity_; + } + + // Will clear the stack. + void Resize(size_t new_capacity) { + capacity_ = new_capacity; + Init(); + } + + private: + AtomicStack(const std::string& name, const size_t capacity) + : name_(name), + back_index_(0), + front_index_(0), + begin_(NULL), + capacity_(capacity) { + + } + + // Size in number of elements. + void Init() { + mem_map_.reset(MemMap::MapAnonymous(name_.c_str(), NULL, capacity_ * sizeof(T), PROT_READ | PROT_WRITE)); + if (mem_map_.get() == NULL) { + std::string maps; + ReadFileToString("/proc/self/maps", &maps); + LOG(FATAL) << "couldn't allocate mark stack\n" << maps; + } + byte* addr = mem_map_->Begin(); + CHECK(addr != NULL); + begin_ = reinterpret_cast<T*>(addr); + Reset(); + } + + // Name of the mark stack. + std::string name_; + + // Memory mapping of the atomic stack. + UniquePtr<MemMap> mem_map_; + + // Back index (index after the last element pushed). + AtomicInteger back_index_; + + // Front index, used for implementing PopFront. + AtomicInteger front_index_; + + // Base of the atomic stack. + T* begin_; + + // Maximum number of elements. + size_t capacity_; + + DISALLOW_COPY_AND_ASSIGN(AtomicStack); +}; + +} // namespace art + +#endif // ART_SRC_MARK_STACK_H_ diff --git a/src/class_linker.cc b/src/class_linker.cc index 8a655bde1c..929582ae10 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -702,6 +702,7 @@ OatFile* ClassLinker::OpenOat(const ImageSpace* space) { std::string oat_filename; oat_filename += runtime->GetHostPrefix(); oat_filename += oat_location->ToModifiedUtf8(); + runtime->GetHeap()->UnReserveOatFileAddressRange(); OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, image_header.GetOatBegin(), OatFile::kRelocNone); diff --git a/src/heap.cc b/src/heap.cc index f7cb68d05d..e2190ec22a 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -22,6 +22,7 @@ #include <limits> #include <vector> +#include "atomic_stack.h" #include "card_table.h" #include "debugger.h" #include "heap_bitmap.h" @@ -121,6 +122,10 @@ static bool GenerateImage(const std::string& image_file_name) { return true; } +void Heap::UnReserveOatFileAddressRange() { + oat_file_map_.reset(NULL); +} + Heap::Heap(size_t initial_size, size_t growth_limit, size_t capacity, const std::string& original_image_file_name, bool concurrent_gc) : alloc_space_(NULL), @@ -149,6 +154,7 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t capacity, last_trim_time_(0), try_running_gc_(false), requesting_gc_(false), + max_allocation_stack_size_(MB), reference_referent_offset_(0), reference_queue_offset_(0), reference_queueNext_offset_(0), @@ -187,21 +193,29 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t capacity, image_space = ImageSpace::Create(image_file_name); } } + CHECK(image_space != NULL) << "Failed to create space from " << image_file_name; AddSpace(image_space); // Oat files referenced by image files immediately follow them in memory, ensure alloc space // isn't going to get in the middle - byte* oat_end_addr = GetImageSpace()->GetImageHeader().GetOatEnd(); - CHECK_GT(oat_end_addr, GetImageSpace()->End()); + byte* oat_end_addr = image_space->GetImageHeader().GetOatEnd(); + CHECK_GT(oat_end_addr, image_space->End()); + + // Reserve address range from image_space->End() to image_space->GetImageHeader().GetOatEnd() + uintptr_t reserve_begin = RoundUp(reinterpret_cast<uintptr_t>(image_space->End()), kPageSize); + uintptr_t reserve_end = RoundUp(reinterpret_cast<uintptr_t>(oat_end_addr), kPageSize); + oat_file_map_.reset(MemMap::MapAnonymous("oat file reserve", + reinterpret_cast<byte*>(reserve_begin), + reserve_end - reserve_begin, PROT_READ)); + if (oat_end_addr > requested_begin) { requested_begin = reinterpret_cast<byte*>(RoundUp(reinterpret_cast<uintptr_t>(oat_end_addr), kPageSize)); } } - // Allocate the large object space (placed after the alloc space). - large_object_space_.reset(FreeListSpace::Create("large object space", requested_begin + capacity, - capacity)); + // Allocate the large object space. + large_object_space_.reset(FreeListSpace::Create("large object space", NULL, capacity)); live_bitmap_->SetLargeObjects(large_object_space_->GetLiveObjects()); mark_bitmap_->SetLargeObjects(large_object_space_->GetMarkObjects()); @@ -242,12 +256,12 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t capacity, num_bytes_allocated_ = 0; // Max stack size in bytes. - static const size_t max_stack_size = capacity / SpaceBitmap::kAlignment * kWordSize; - - // TODO: Rename MarkStack to a more generic name? - mark_stack_.reset(MarkStack::Create("dalvik-mark-stack", max_stack_size)); - allocation_stack_.reset(MarkStack::Create("dalvik-allocation-stack", max_stack_size)); - live_stack_.reset(MarkStack::Create("dalvik-live-stack", max_stack_size)); + static const size_t default_mark_stack_size = 64 * KB; + mark_stack_.reset(ObjectStack::Create("dalvik-mark-stack", default_mark_stack_size)); + allocation_stack_.reset(ObjectStack::Create("dalvik-allocation-stack", + max_allocation_stack_size_)); + live_stack_.reset(ObjectStack::Create("dalvik-live-stack", + max_allocation_stack_size_)); // It's still too early to take a lock because there are no threads yet, // but we can create the heap lock now. We don't create it earlier to @@ -523,7 +537,7 @@ void Heap::VerifyHeap() { GetLiveBitmap()->Walk(Heap::VerificationCallback, this); } -void Heap::RecordAllocation(size_t size, const Object* obj) { +void Heap::RecordAllocation(size_t size, Object* obj) { DCHECK(obj != NULL); DCHECK_GT(size, 0u); num_bytes_allocated_ += size; @@ -539,7 +553,15 @@ void Heap::RecordAllocation(size_t size, const Object* obj) { global_stats->allocated_bytes += size; } - allocation_stack_->AtomicPush(obj); + // This is safe to do since the GC will never free objects which are neither in the allocation + // stack or the live bitmap. + while (!allocation_stack_->AtomicPushBack(obj)) { + Thread* self = Thread::Current(); + self->TransitionFromRunnableToSuspended(kWaitingPerformingGc); + // If we actually ran a different type of Gc than requested, we can skip the index forwards. + CollectGarbageInternal(kGcTypeSticky, kGcCauseForAlloc, false); + self->TransitionFromSuspendedToRunnable(); + } } void Heap::RecordFree(size_t freed_objects, size_t freed_bytes) { @@ -784,10 +806,10 @@ size_t Heap::GetUsedMemorySize() const { return num_bytes_allocated_; } -void Heap::MarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, MarkStack* stack) { - const size_t count = stack->Size(); - for (size_t i = 0; i < count; ++i) { - const Object* obj = stack->Get(i); +void Heap::MarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, ObjectStack* stack) { + Object** limit = stack->End(); + for (Object** it = stack->Begin(); it != limit; ++it) { + const Object* obj = *it; DCHECK(obj != NULL); if (LIKELY(bitmap->HasAddress(obj))) { bitmap->Set(obj); @@ -797,10 +819,10 @@ void Heap::MarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, MarkS } } -void Heap::UnMarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, MarkStack* stack) { - size_t count = stack->Size(); - for (size_t i = 0; i < count; ++i) { - const Object* obj = stack->Get(i); +void Heap::UnMarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, ObjectStack* stack) { + Object** limit = stack->End(); + for (Object** it = stack->Begin(); it != limit; ++it) { + const Object* obj = *it; DCHECK(obj != NULL); if (LIKELY(bitmap->HasAddress(obj))) { bitmap->Clear(obj); @@ -970,7 +992,7 @@ void Heap::CollectGarbageMarkSweepPlan(Thread* self, GcType gc_type, GcCause gc_ timings.AddSplit("MarkRoots"); // Roots are marked on the bitmap and the mark_stack is empty. - DCHECK(mark_sweep.IsMarkStackEmpty()); + DCHECK(mark_stack_->IsEmpty()); UpdateAndMarkModUnion(timings, gc_type); @@ -1121,8 +1143,8 @@ class VerifyReferenceVisitor { // Verify that the reference is live. if (ref != NULL && !IsLive(ref)) { CardTable* card_table = heap_->GetCardTable(); - MarkStack* alloc_stack = heap_->allocation_stack_.get(); - MarkStack* live_stack = heap_->live_stack_.get(); + ObjectStack* alloc_stack = heap_->allocation_stack_.get(); + ObjectStack* live_stack = heap_->live_stack_.get(); byte* card_addr = card_table->CardFromAddr(obj); LOG(ERROR) << "Object " << obj << " references dead object " << ref << " on IsDirty = " @@ -1161,7 +1183,7 @@ class VerifyReferenceVisitor { IdentityFunctor()); // Try and see if a mark sweep collector scans the reference. - MarkStack* mark_stack = heap_->mark_stack_.get(); + ObjectStack* mark_stack = heap_->mark_stack_.get(); MarkSweep ms(mark_stack); ms.Init(); mark_stack->Reset(); @@ -1198,7 +1220,7 @@ class VerifyReferenceVisitor { heap_->DumpSpaces(); LOG(ERROR) << "Object " << obj << " not found in any spaces"; } - MarkStack* alloc_stack = heap_->allocation_stack_.get(); + ObjectStack* alloc_stack = heap_->allocation_stack_.get(); // At this point we need to search the allocation since things in the live stack may get swept. if (std::binary_search(alloc_stack->Begin(), alloc_stack->End(), const_cast<Object*>(obj))) { return true; @@ -1271,7 +1293,7 @@ class VerifyReferenceCardVisitor { // If the object is not dirty and it is referencing something in the live stack other than // class, then it must be on a dirty card. if (!card_table->IsDirty(obj)) { - MarkStack* live_stack = heap_->live_stack_.get(); + ObjectStack* live_stack = heap_->live_stack_.get(); if (std::binary_search(live_stack->Begin(), live_stack->End(), ref) && !ref->IsClass()) { if (std::binary_search(live_stack->Begin(), live_stack->End(), obj)) { LOG(ERROR) << "Object " << obj << " found in live stack"; @@ -1379,7 +1401,7 @@ void Heap::SwapBitmaps(Thread* self) { } void Heap::SwapStacks() { - MarkStack* temp = allocation_stack_.release(); + ObjectStack* temp = allocation_stack_.release(); allocation_stack_.reset(live_stack_.release()); live_stack_.reset(temp); @@ -1464,7 +1486,7 @@ void Heap::CollectGarbageConcurrentMarkSweepPlan(Thread* self, GcType gc_type, G WriterMutexLock mu(self, *Locks::heap_bitmap_lock_); for (Object** it = live_stack_->Begin(); it != live_stack_->End(); ++it) { - CHECK(!GetLiveBitmap()->Test(*it)); + DCHECK(!GetLiveBitmap()->Test(*it)); } if (gc_type == kGcTypePartial) { @@ -1507,7 +1529,7 @@ void Heap::CollectGarbageConcurrentMarkSweepPlan(Thread* self, GcType gc_type, G } // Roots are marked on the bitmap and the mark_stack is empty. - DCHECK(mark_sweep.IsMarkStackEmpty()); + DCHECK(mark_stack_->IsEmpty()); // Allow mutators to go again, acquire share on mutator_lock_ to continue. thread_list->ResumeAll(); diff --git a/src/heap.h b/src/heap.h index 7a96fd61d6..b4bc22f08e 100644 --- a/src/heap.h +++ b/src/heap.h @@ -21,6 +21,7 @@ #include <string> #include <vector> +#include "atomic_stack.h" #include "atomic_integer.h" #include "card_table.h" #include "globals.h" @@ -44,7 +45,6 @@ class ConditionVariable; class HeapBitmap; class ImageSpace; class LargeObjectSpace; -class MarkStack; class ModUnionTable; class Mutex; class Object; @@ -53,6 +53,7 @@ class SpaceTest; class Thread; class TimingLogger; +typedef AtomicStack<Object*> ObjectStack; typedef std::vector<ContinuousSpace*> Spaces; // The ordering of the enum matters, it is used to determine which GCs are run first. @@ -273,11 +274,11 @@ class Heap { EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); // Mark all the objects in the allocation stack in the specified bitmap. - void MarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, MarkStack* stack) + void MarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, ObjectStack* stack) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); // Unmark all the objects in the allocation stack in the specified bitmap. - void UnMarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, MarkStack* stack) + void UnMarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, ObjectStack* stack) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); // Update and mark mod union table based on gc type. @@ -293,6 +294,9 @@ class Heap { } void DumpSpaces(); + // UnReserve the address range where the oat file will be placed. + void UnReserveOatFileAddressRange(); + private: // Allocates uninitialized storage. Passing in a null space tries to place the object in the // large object space. @@ -314,8 +318,9 @@ class Heap { // Swap bitmaps (if we are a full Gc then we swap the zygote bitmap too). void SwapBitmaps(Thread* self) EXCLUSIVE_LOCKS_REQUIRED(GlobalSynchronization::heap_bitmap_lock_); - void RecordAllocation(size_t size, const Object* object) - LOCKS_EXCLUDED(GlobalSynchronization::heap_bitmap_lock_); + void RecordAllocation(size_t size, Object* object) + LOCKS_EXCLUDED(GlobalSynchronization::heap_bitmap_lock_) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Sometimes CollectGarbageInternal decides to run a different Gc than you requested. Returns // which type of Gc was actually ran. @@ -355,6 +360,9 @@ class Heap { Spaces spaces_; + // A map that we use to temporarily reserve address range for the oat file. + UniquePtr<MemMap> oat_file_map_; + // The alloc space which we are currently allocating into. AllocSpace* alloc_space_; @@ -447,14 +455,15 @@ class Heap { volatile bool requesting_gc_; // Mark stack that we reuse to avoid re-allocating the mark stack. - UniquePtr<MarkStack> mark_stack_; + UniquePtr<ObjectStack> mark_stack_; // Allocation stack, new allocations go here so that we can do sticky mark bits. This enables us // to use the live bitmap as the old mark bitmap. - UniquePtr<MarkStack> allocation_stack_; + const size_t max_allocation_stack_size_; + UniquePtr<ObjectStack> allocation_stack_; // Second allocation stack so that we can process allocation with the heap unlocked. - UniquePtr<MarkStack> live_stack_; + UniquePtr<ObjectStack> live_stack_; // offset of java.lang.ref.Reference.referent MemberOffset reference_referent_offset_; diff --git a/src/mark_stack.cc b/src/mark_stack.cc deleted file mode 100644 index 2f188984dd..0000000000 --- a/src/mark_stack.cc +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "mark_stack.h" - -#include "globals.h" -#include "logging.h" -#include "UniquePtr.h" -#include "utils.h" - -namespace art { - -MarkStack* MarkStack::Create(const std::string& name, size_t length) { - UniquePtr<MarkStack> mark_stack(new MarkStack(name)); - mark_stack->Init(length); - return mark_stack.release(); -} - -void MarkStack::Init(size_t length) { - mem_map_.reset(MemMap::MapAnonymous(name_.c_str(), NULL, length, PROT_READ | PROT_WRITE)); - if (mem_map_.get() == NULL) { - std::string maps; - ReadFileToString("/proc/self/maps", &maps); - LOG(FATAL) << "couldn't allocate mark stack\n" << maps; - } - byte* addr = mem_map_->Begin(); - CHECK(addr != NULL); - - begin_ = reinterpret_cast<const Object**>(addr); - limit_ = reinterpret_cast<const Object**>(addr + length); - - Reset(); -} - -void MarkStack::Reset() { - DCHECK(mem_map_.get() != NULL); - DCHECK(begin_ != NULL); - DCHECK(limit_ != NULL); - byte* addr = const_cast<byte*>(reinterpret_cast<const byte*>(begin_)); - const size_t length = limit_ - begin_; - ptr_ = reinterpret_cast<const Object**>(addr); - int result = madvise(addr, length, MADV_DONTNEED); - if (result == -1) { - PLOG(WARNING) << "madvise failed"; - } -} - -MarkStack::~MarkStack() { - CHECK(IsEmpty()); -} - -} // namespace art diff --git a/src/mark_stack.h b/src/mark_stack.h deleted file mode 100644 index 7e4cec0d91..0000000000 --- a/src/mark_stack.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_SRC_MARK_STACK_H_ -#define ART_SRC_MARK_STACK_H_ - -#include <string> - -#include "atomic.h" -#include "UniquePtr.h" -#include "logging.h" -#include "macros.h" -#include "mem_map.h" - -namespace art { - -class Object; - -class MarkStack { - public: - // Length is in bytes. - static MarkStack* Create(const std::string& name, size_t length); - - ~MarkStack(); - - void Push(const Object* obj) { - DCHECK(obj != NULL); - DCHECK_NE(ptr_, limit_); - *ptr_ = obj; - ++ptr_; - } - - // Beware: Atomic pushes and pops don't mix well. - void AtomicPush(const Object* obj) { - DCHECK(obj != NULL); - DCHECK_NE(ptr_, limit_); - DCHECK_EQ(sizeof(ptr_), sizeof(int32_t)); - int32_t* ptr = reinterpret_cast<int32_t*>(reinterpret_cast<size_t>(&ptr_)); - *reinterpret_cast<const Object**>(android_atomic_add(sizeof(*ptr_), ptr)) = obj; - } - - const Object* Pop() { - DCHECK_NE(ptr_, begin_); - --ptr_; - DCHECK(*ptr_ != NULL); - return *ptr_; - } - - bool IsEmpty() const { - return ptr_ == begin_; - } - - size_t Size() const { - DCHECK_GE(ptr_, begin_); - return ptr_ - begin_; - } - - const Object* Get(size_t index) const { - DCHECK_LT(index, Size()); - return begin_[index]; - } - - Object** Begin() { - return const_cast<Object**>(begin_); - } - - Object** End() { - return const_cast<Object**>(ptr_); - } - - void Reset(); - - private: - MarkStack(const std::string& name) : name_(name), begin_(NULL), limit_(NULL), ptr_(NULL) {} - - void Init(size_t length); - - // Name of the mark stack. - const std::string& name_; - - // Memory mapping of the mark stack. - UniquePtr<MemMap> mem_map_; - - // Base of the mark stack. - const Object* const* begin_; - - // Exclusive limit of the mark stack. - const Object* const* limit_; - - // Pointer to the top of the mark stack. - const Object** ptr_; - - DISALLOW_COPY_AND_ASSIGN(MarkStack); -}; - -} // namespace art - -#endif // ART_SRC_MARK_STACK_H_ diff --git a/src/mark_sweep.cc b/src/mark_sweep.cc index 96223a98e2..34e5e2cd7e 100644 --- a/src/mark_sweep.cc +++ b/src/mark_sweep.cc @@ -28,7 +28,6 @@ #include "jni_internal.h" #include "logging.h" #include "macros.h" -#include "mark_stack.h" #include "monitor.h" #include "mutex.h" #include "object.h" @@ -37,7 +36,7 @@ #include "timing_logger.h" #include "thread.h" -#define MARK_STACK_PREFETCH 1 +static const bool kUseMarkStackPrefetch = true; namespace art { @@ -55,7 +54,7 @@ class SetFingerVisitor { MarkSweep* const mark_sweep_; }; -MarkSweep::MarkSweep(MarkStack* mark_stack) +MarkSweep::MarkSweep(ObjectStack* mark_stack) : current_mark_bitmap_(NULL), mark_stack_(mark_stack), heap_(NULL), @@ -123,8 +122,17 @@ inline void MarkSweep::MarkObject0(const Object* obj, bool check_finger) { if (!current_mark_bitmap_->Test(obj)) { current_mark_bitmap_->Set(obj); if (check_finger && obj < finger_) { + // Do we need to expand the mark stack? + if (UNLIKELY(mark_stack_->Size() >= mark_stack_->Capacity())) { + std::vector<Object*> temp; + temp.insert(temp.begin(), mark_stack_->Begin(), mark_stack_->End()); + mark_stack_->Resize(mark_stack_->Capacity() * 2); + for (size_t i = 0; i < temp.size(); ++i) { + mark_stack_->PushBack(temp[i]); + } + } // The object must be pushed on to the mark stack. - mark_stack_->Push(obj); + mark_stack_->PushBack(const_cast<Object*>(obj)); } } } @@ -489,7 +497,7 @@ void MarkSweep::ZygoteSweepCallback(size_t num_ptrs, Object** ptrs, void* arg) { } } -void MarkSweep::SweepArray(TimingLogger& logger, MarkStack* allocations, bool swap_bitmaps) { +void MarkSweep::SweepArray(TimingLogger& logger, ObjectStack* allocations, bool swap_bitmaps) { size_t freed_bytes = 0; AllocSpace* space = heap_->GetAllocSpace(); @@ -512,7 +520,7 @@ void MarkSweep::SweepArray(TimingLogger& logger, MarkStack* allocations, bool sw size_t freed_large_objects = 0; size_t count = allocations->Size(); - Object** objects = allocations->Begin(); + Object** objects = const_cast<Object**>(allocations->Begin()); Object** out = objects; // Empty the allocation stack. @@ -796,44 +804,44 @@ void MarkSweep::ScanObject(const Object* obj) { // Scan anything that's on the mark stack. void MarkSweep::ProcessMarkStack() { -#if MARK_STACK_PREFETCH - const size_t fifo_size = 4; - const size_t fifo_mask = fifo_size - 1; - const Object* fifo[fifo_size]; - for (size_t i = 0;i < fifo_size;++i) { - fifo[i] = NULL; - } - size_t fifo_pos = 0; - size_t fifo_count = 0; - for (;;) { - const Object* obj = fifo[fifo_pos & fifo_mask]; - if (obj != NULL) { - ScanObject(obj); - fifo[fifo_pos & fifo_mask] = NULL; - --fifo_count; + if (kUseMarkStackPrefetch) { + const size_t fifo_size = 4; + const size_t fifo_mask = fifo_size - 1; + const Object* fifo[fifo_size]; + for (size_t i = 0;i < fifo_size;++i) { + fifo[i] = NULL; } + size_t fifo_pos = 0; + size_t fifo_count = 0; + for (;;) { + const Object* obj = fifo[fifo_pos & fifo_mask]; + if (obj != NULL) { + ScanObject(obj); + fifo[fifo_pos & fifo_mask] = NULL; + --fifo_count; + } - if (!mark_stack_->IsEmpty()) { - const Object* obj = mark_stack_->Pop(); - DCHECK(obj != NULL); - fifo[fifo_pos & fifo_mask] = obj; - __builtin_prefetch(obj); - fifo_count++; - } - fifo_pos++; + if (!mark_stack_->IsEmpty()) { + const Object* obj = mark_stack_->PopBack(); + DCHECK(obj != NULL); + fifo[fifo_pos & fifo_mask] = obj; + __builtin_prefetch(obj); + fifo_count++; + } + fifo_pos++; - if (!fifo_count) { - CHECK(mark_stack_->IsEmpty()) << mark_stack_->Size(); - break; + if (!fifo_count) { + CHECK(mark_stack_->IsEmpty()) << mark_stack_->Size(); + break; + } + } + } else { + while (!mark_stack_->IsEmpty()) { + const Object* obj = mark_stack_->PopBack(); + DCHECK(obj != NULL); + ScanObject(obj); } } -#else - while (!mark_stack_->IsEmpty()) { - const Object* obj = mark_stack_->Pop(); - DCHECK(obj != NULL); - ScanObject(obj); - } -#endif } // Walks the reference list marking any references subject to the diff --git a/src/mark_sweep.h b/src/mark_sweep.h index 7ef681793e..7b4ff6ef32 100644 --- a/src/mark_sweep.h +++ b/src/mark_sweep.h @@ -17,8 +17,8 @@ #ifndef ART_SRC_MARK_SWEEP_H_ #define ART_SRC_MARK_SWEEP_H_ +#include "atomic_stack.h" #include "macros.h" -#include "mark_stack.h" #include "heap_bitmap.h" #include "object.h" #include "offsets.h" @@ -37,7 +37,7 @@ class TimingLogger; class MarkSweep { public: - explicit MarkSweep(MarkStack* mark_stack); + explicit MarkSweep(ObjectStack* mark_stack); ~MarkSweep(); @@ -52,10 +52,6 @@ class MarkSweep { // Verify that image roots point to only marked objects within the alloc space. void VerifyImageRoots() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); - bool IsMarkStackEmpty() const { - return mark_stack_->IsEmpty(); - } - // Builds a mark stack and recursively mark until it empties. void RecursiveMark(bool partial, TimingLogger& timings) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) @@ -103,7 +99,7 @@ class MarkSweep { EXCLUSIVE_LOCKS_REQUIRED(GlobalSynchronization::heap_bitmap_lock_); // Sweep only pointers within an array. WARNING: Trashes objects. - void SweepArray(TimingLogger& logger, MarkStack* allocation_stack_, bool swap_bitmaps) + void SweepArray(TimingLogger& logger, ObjectStack* allocation_stack_, bool swap_bitmaps) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); Object* GetClearedReferences() { @@ -373,7 +369,7 @@ class MarkSweep { // Current space, we check this space first to avoid searching for the appropriate space for an object. SpaceBitmap* current_mark_bitmap_; - MarkStack* mark_stack_; + ObjectStack* mark_stack_; Heap* heap_; |