diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/gc/collector/semi_space-inl.h | 6 | ||||
-rw-r--r-- | runtime/gc/collector/semi_space.cc | 27 | ||||
-rw-r--r-- | runtime/gc/collector/semi_space.h | 5 | ||||
-rw-r--r-- | runtime/mirror/object-inl.h | 9 | ||||
-rw-r--r-- | runtime/mirror/object.cc | 2 | ||||
-rw-r--r-- | runtime/mirror/object.h | 6 | ||||
-rw-r--r-- | runtime/monitor.cc | 64 | ||||
-rw-r--r-- | runtime/thread.cc | 2 | ||||
-rw-r--r-- | runtime/transaction_test.cc | 6 |
9 files changed, 67 insertions, 60 deletions
diff --git a/runtime/gc/collector/semi_space-inl.h b/runtime/gc/collector/semi_space-inl.h index 8a9611f..d03baf1 100644 --- a/runtime/gc/collector/semi_space-inl.h +++ b/runtime/gc/collector/semi_space-inl.h @@ -28,7 +28,7 @@ namespace collector { inline mirror::Object* SemiSpace::GetForwardingAddressInFromSpace(mirror::Object* obj) const { DCHECK(from_space_->HasAddress(obj)); - LockWord lock_word = obj->GetLockWord(); + LockWord lock_word = obj->GetLockWord(false); if (lock_word.GetState() != LockWord::kForwardingAddress) { return nullptr; } @@ -58,8 +58,8 @@ inline void SemiSpace::MarkObject( DCHECK(forward_address != nullptr); // Make sure to only update the forwarding address AFTER you copy the object so that the // monitor word doesn't get stomped over. - obj->SetLockWord(LockWord::FromForwardingAddress( - reinterpret_cast<size_t>(forward_address))); + obj->SetLockWord( + LockWord::FromForwardingAddress(reinterpret_cast<size_t>(forward_address)), false); // Push the object onto the mark stack for later processing. MarkStackPush(forward_address); } diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc index c0e172e..4a1bf18 100644 --- a/runtime/gc/collector/semi_space.cc +++ b/runtime/gc/collector/semi_space.cc @@ -117,6 +117,8 @@ void SemiSpace::InitializePhase() { immune_region_.Reset(); is_large_object_space_immune_ = false; saved_bytes_ = 0; + bytes_moved_ = 0; + objects_moved_ = 0; self_ = Thread::Current(); // Do any pre GC verification. timings_.NewSplit("PreGcVerification"); @@ -382,9 +384,9 @@ void SemiSpace::ReclaimPhase() { } // Record freed memory. uint64_t from_bytes = from_space_->GetBytesAllocated(); - uint64_t to_bytes = to_space_->GetBytesAllocated(); + uint64_t to_bytes = bytes_moved_; uint64_t from_objects = from_space_->GetObjectsAllocated(); - uint64_t to_objects = to_space_->GetObjectsAllocated(); + uint64_t to_objects = objects_moved_; CHECK_LE(to_objects, from_objects); int64_t freed_bytes = from_bytes - to_bytes; int64_t freed_objects = from_objects - to_objects; @@ -521,15 +523,13 @@ mirror::Object* SemiSpace::MarkNonForwardedObject(mirror::Object* obj) { // If it's allocated before the last GC (older), move // (pseudo-promote) it to the main free list space (as sort // of an old generation.) - size_t bytes_promoted; space::MallocSpace* promo_dest_space = GetHeap()->GetPrimaryFreeListSpace(); - forward_address = promo_dest_space->Alloc(self_, object_size, &bytes_promoted, nullptr); - if (forward_address == nullptr) { + forward_address = promo_dest_space->Alloc(self_, object_size, &bytes_allocated, nullptr); + if (UNLIKELY(forward_address == nullptr)) { // If out of space, fall back to the to-space. forward_address = to_space_->Alloc(self_, object_size, &bytes_allocated, nullptr); } else { - GetHeap()->num_bytes_allocated_.FetchAndAdd(bytes_promoted); - bytes_promoted_ += bytes_promoted; + bytes_promoted_ += bytes_allocated; // Dirty the card at the destionation as it may contain // references (including the class pointer) to the bump pointer // space. @@ -573,6 +573,8 @@ mirror::Object* SemiSpace::MarkNonForwardedObject(mirror::Object* obj) { // If it's allocated after the last GC (younger), copy it to the to-space. forward_address = to_space_->Alloc(self_, object_size, &bytes_allocated, nullptr); } + ++objects_moved_; + bytes_moved_ += bytes_allocated; // Copy over the object and add it to the mark stack since we still need to update its // references. saved_bytes_ += @@ -619,10 +621,9 @@ void SemiSpace::MarkRootCallback(Object** root, void* arg, uint32_t /*thread_id* // Marks all objects in the root set. void SemiSpace::MarkRoots() { - timings_.StartSplit("MarkRoots"); + timings_.NewSplit("MarkRoots"); // TODO: Visit up image roots as well? Runtime::Current()->VisitRoots(MarkRootCallback, this); - timings_.EndSplit(); } mirror::Object* SemiSpace::MarkedForwardingAddressCallback(mirror::Object* object, void* arg) { @@ -641,7 +642,7 @@ bool SemiSpace::ShouldSweepSpace(space::ContinuousSpace* space) const { void SemiSpace::Sweep(bool swap_bitmaps) { DCHECK(mark_stack_->IsEmpty()); - TimingLogger::ScopedSplit("Sweep", &timings_); + TimingLogger::ScopedSplit split("Sweep", &timings_); for (const auto& space : GetHeap()->GetContinuousSpaces()) { if (space->IsContinuousMemMapAllocSpace()) { space::ContinuousMemMapAllocSpace* alloc_space = space->AsContinuousMemMapAllocSpace(); @@ -665,13 +666,13 @@ void SemiSpace::Sweep(bool swap_bitmaps) { void SemiSpace::SweepLargeObjects(bool swap_bitmaps) { DCHECK(!is_large_object_space_immune_); - TimingLogger::ScopedSplit("SweepLargeObjects", &timings_); + TimingLogger::ScopedSplit split("SweepLargeObjects", &timings_); size_t freed_objects = 0; size_t freed_bytes = 0; - GetHeap()->GetLargeObjectsSpace()->Sweep(swap_bitmaps, &freed_objects, &freed_bytes); + heap_->GetLargeObjectsSpace()->Sweep(swap_bitmaps, &freed_objects, &freed_bytes); freed_large_objects_.FetchAndAdd(freed_objects); freed_large_object_bytes_.FetchAndAdd(freed_bytes); - GetHeap()->RecordFree(freed_objects, freed_bytes); + heap_->RecordFree(freed_objects, freed_bytes); } // Process the "referent" field in a java.lang.ref.Reference. If the referent has not yet been diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h index 4169ca9..b6726b2 100644 --- a/runtime/gc/collector/semi_space.h +++ b/runtime/gc/collector/semi_space.h @@ -231,6 +231,11 @@ class SemiSpace : public GarbageCollector { // whole_heap_collection_ once per interval. int whole_heap_collection_interval_counter_; + // How many objects and bytes we moved, used so that we don't need to get the size of the + // to_space_ when calculating how many objects and bytes we freed. + size_t bytes_moved_; + size_t objects_moved_; + // How many bytes we avoided dirtying. size_t saved_bytes_; diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h index a6db387..2505855 100644 --- a/runtime/mirror/object-inl.h +++ b/runtime/mirror/object-inl.h @@ -51,13 +51,14 @@ inline void Object::SetClass(Class* new_klass) { OFFSET_OF_OBJECT_MEMBER(Object, klass_), new_klass, false); } -inline LockWord Object::GetLockWord() { - return LockWord(GetField32(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), true)); +inline LockWord Object::GetLockWord(bool is_volatile) { + return LockWord(GetField32(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), is_volatile)); } -inline void Object::SetLockWord(LockWord new_val) { +inline void Object::SetLockWord(LockWord new_val, bool is_volatile) { // Force use of non-transactional mode and do not check. - SetField32<false, false>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), new_val.GetValue(), true); + SetField32<false, false>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), new_val.GetValue(), + is_volatile); } inline bool Object::CasLockWord(LockWord old_val, LockWord new_val) { diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc index be7e9f2..766bbc9 100644 --- a/runtime/mirror/object.cc +++ b/runtime/mirror/object.cc @@ -150,7 +150,7 @@ int32_t Object::GenerateIdentityHashCode() { int32_t Object::IdentityHashCode() const { mirror::Object* current_this = const_cast<mirror::Object*>(this); while (true) { - LockWord lw = current_this->GetLockWord(); + LockWord lw = current_this->GetLockWord(false); switch (lw.GetState()) { case LockWord::kUnlocked: { // Try to compare and swap in a new hash, if we succeed we will return the hash on the next diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h index f652202..fd31dfb 100644 --- a/runtime/mirror/object.h +++ b/runtime/mirror/object.h @@ -100,8 +100,10 @@ class MANAGED LOCKABLE Object { return OFFSET_OF_OBJECT_MEMBER(Object, monitor_); } - LockWord GetLockWord(); - void SetLockWord(LockWord new_val); + // As volatile can be false if the mutators are suspended. This is an optimization since it + // avoids the barriers. + LockWord GetLockWord(bool as_volatile); + void SetLockWord(LockWord new_val, bool as_volatile); bool CasLockWord(LockWord old_val, LockWord new_val) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); uint32_t GetLockOwnerThreadId(); diff --git a/runtime/monitor.cc b/runtime/monitor.cc index bbc7dd0..38b77d1 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -111,7 +111,7 @@ bool Monitor::Install(Thread* self) { MutexLock mu(self, monitor_lock_); // Uncontended mutex acquisition as monitor isn't yet public. CHECK(owner_ == nullptr || owner_ == self || owner_->IsSuspended()); // Propagate the lock state. - LockWord lw(obj_->GetLockWord()); + LockWord lw(obj_->GetLockWord(false)); switch (lw.GetState()) { case LockWord::kThinLocked: { CHECK_EQ(owner_->GetThreadId(), lw.ThinLockOwner()); @@ -574,7 +574,8 @@ void Monitor::NotifyAll(Thread* self) { bool Monitor::Deflate(Thread* self, mirror::Object* obj) { DCHECK(obj != nullptr); - LockWord lw(obj->GetLockWord()); + // Don't need volatile since we only deflate with mutators suspended. + LockWord lw(obj->GetLockWord(false)); // If the lock isn't an inflated monitor, then we don't need to deflate anything. if (lw.GetState() == LockWord::kFatLocked) { Monitor* monitor = lw.FatLockMonitor(); @@ -595,14 +596,15 @@ bool Monitor::Deflate(Thread* self, mirror::Object* obj) { return false; } // Deflate to a thin lock. - obj->SetLockWord(LockWord::FromThinLockId(owner->GetThreadId(), monitor->lock_count_)); - VLOG(monitor) << "Deflated " << obj << " to thin lock " << owner->GetTid() << " / " << monitor->lock_count_; + obj->SetLockWord(LockWord::FromThinLockId(owner->GetThreadId(), monitor->lock_count_), false); + VLOG(monitor) << "Deflated " << obj << " to thin lock " << owner->GetTid() << " / " + << monitor->lock_count_; } else if (monitor->HasHashCode()) { - obj->SetLockWord(LockWord::FromHashCode(monitor->GetHashCode())); + obj->SetLockWord(LockWord::FromHashCode(monitor->GetHashCode()), false); VLOG(monitor) << "Deflated " << obj << " to hash monitor " << monitor->GetHashCode(); } else { // No lock and no hash, just put an empty lock word inside the object. - obj->SetLockWord(LockWord()); + obj->SetLockWord(LockWord(), false); VLOG(monitor) << "Deflated" << obj << " to empty lock word"; } // The monitor is deflated, mark the object as nullptr so that we know to delete it during the @@ -626,7 +628,7 @@ void Monitor::Inflate(Thread* self, Thread* owner, mirror::Object* obj, int32_t VLOG(monitor) << "monitor: thread " << owner->GetThreadId() << " created monitor " << m.get() << " for object " << obj; Runtime::Current()->GetMonitorList()->Add(m.release()); - CHECK_EQ(obj->GetLockWord().GetState(), LockWord::kFatLocked); + CHECK_EQ(obj->GetLockWord(true).GetState(), LockWord::kFatLocked); } } @@ -642,12 +644,12 @@ void Monitor::InflateThinLocked(Thread* self, SirtRef<mirror::Object>& obj, Lock // Suspend the owner, inflate. First change to blocked and give up mutator_lock_. ScopedThreadStateChange tsc(self, kBlocked); self->SetMonitorEnterObject(obj.get()); - if (lock_word == obj->GetLockWord()) { // If lock word hasn't changed. + if (lock_word == obj->GetLockWord(true)) { // If lock word hasn't changed. bool timed_out; Thread* owner = thread_list->SuspendThreadByThreadId(owner_thread_id, false, &timed_out); if (owner != nullptr) { // We succeeded in suspending the thread, check the lock's status didn't change. - lock_word = obj->GetLockWord(); + lock_word = obj->GetLockWord(true); if (lock_word.GetState() == LockWord::kThinLocked && lock_word.ThinLockOwner() == owner_thread_id) { // Go ahead and inflate the lock. @@ -680,7 +682,7 @@ mirror::Object* Monitor::MonitorEnter(Thread* self, mirror::Object* obj) { size_t contention_count = 0; SirtRef<mirror::Object> sirt_obj(self, obj); while (true) { - LockWord lock_word = sirt_obj->GetLockWord(); + LockWord lock_word = sirt_obj->GetLockWord(true); switch (lock_word.GetState()) { case LockWord::kUnlocked: { LockWord thin_locked(LockWord::FromThinLockId(thread_id, 0)); @@ -697,7 +699,7 @@ mirror::Object* Monitor::MonitorEnter(Thread* self, mirror::Object* obj) { uint32_t new_count = lock_word.ThinLockCount() + 1; if (LIKELY(new_count <= LockWord::kThinLockMaxCount)) { LockWord thin_locked(LockWord::FromThinLockId(thread_id, new_count)); - sirt_obj->SetLockWord(thin_locked); + sirt_obj->SetLockWord(thin_locked, true); return sirt_obj.get(); // Success! } else { // We'd overflow the recursion count, so inflate the monitor. @@ -737,13 +739,13 @@ bool Monitor::MonitorExit(Thread* self, mirror::Object* obj) { DCHECK(self != NULL); DCHECK(obj != NULL); obj = FakeUnlock(obj); - LockWord lock_word = obj->GetLockWord(); + LockWord lock_word = obj->GetLockWord(true); SirtRef<mirror::Object> sirt_obj(self, obj); switch (lock_word.GetState()) { case LockWord::kHashCode: // Fall-through. case LockWord::kUnlocked: - FailedUnlock(sirt_obj.get(), self, NULL, NULL); + FailedUnlock(sirt_obj.get(), self, nullptr, nullptr); return false; // Failure. case LockWord::kThinLocked: { uint32_t thread_id = self->GetThreadId(); @@ -752,16 +754,16 @@ bool Monitor::MonitorExit(Thread* self, mirror::Object* obj) { // TODO: there's a race here with the owner dying while we unlock. Thread* owner = Runtime::Current()->GetThreadList()->FindThreadByThreadId(lock_word.ThinLockOwner()); - FailedUnlock(sirt_obj.get(), self, owner, NULL); + FailedUnlock(sirt_obj.get(), self, owner, nullptr); return false; // Failure. } else { // We own the lock, decrease the recursion count. if (lock_word.ThinLockCount() != 0) { uint32_t new_count = lock_word.ThinLockCount() - 1; LockWord thin_locked(LockWord::FromThinLockId(thread_id, new_count)); - sirt_obj->SetLockWord(thin_locked); + sirt_obj->SetLockWord(thin_locked, true); } else { - sirt_obj->SetLockWord(LockWord()); + sirt_obj->SetLockWord(LockWord(), true); } return true; // Success! } @@ -782,10 +784,9 @@ bool Monitor::MonitorExit(Thread* self, mirror::Object* obj) { */ void Monitor::Wait(Thread* self, mirror::Object *obj, int64_t ms, int32_t ns, bool interruptShouldThrow, ThreadState why) { - DCHECK(self != NULL); - DCHECK(obj != NULL); - - LockWord lock_word = obj->GetLockWord(); + DCHECK(self != nullptr); + DCHECK(obj != nullptr); + LockWord lock_word = obj->GetLockWord(true); switch (lock_word.GetState()) { case LockWord::kHashCode: // Fall-through. @@ -801,7 +802,7 @@ void Monitor::Wait(Thread* self, mirror::Object *obj, int64_t ms, int32_t ns, } else { // We own the lock, inflate to enqueue ourself on the Monitor. Inflate(self, self, obj, 0); - lock_word = obj->GetLockWord(); + lock_word = obj->GetLockWord(true); } break; } @@ -817,10 +818,9 @@ void Monitor::Wait(Thread* self, mirror::Object *obj, int64_t ms, int32_t ns, } void Monitor::DoNotify(Thread* self, mirror::Object* obj, bool notify_all) { - DCHECK(self != NULL); - DCHECK(obj != NULL); - - LockWord lock_word = obj->GetLockWord(); + DCHECK(self != nullptr); + DCHECK(obj != nullptr); + LockWord lock_word = obj->GetLockWord(true); switch (lock_word.GetState()) { case LockWord::kHashCode: // Fall-through. @@ -855,9 +855,8 @@ void Monitor::DoNotify(Thread* self, mirror::Object* obj, bool notify_all) { } uint32_t Monitor::GetLockOwnerThreadId(mirror::Object* obj) { - DCHECK(obj != NULL); - - LockWord lock_word = obj->GetLockWord(); + DCHECK(obj != nullptr); + LockWord lock_word = obj->GetLockWord(true); switch (lock_word.GetState()) { case LockWord::kHashCode: // Fall-through. @@ -902,7 +901,7 @@ void Monitor::DescribeWait(std::ostream& os, const Thread* thread) { if (pretty_object == nullptr) { os << wait_message << "an unknown object"; } else { - if ((pretty_object->GetLockWord().GetState() == LockWord::kThinLocked) && + if ((pretty_object->GetLockWord(true).GetState() == LockWord::kThinLocked) && Locks::mutator_lock_->IsExclusiveHeld(Thread::Current())) { // Getting the identity hashcode here would result in lock inflation and suspension of the // current thread, which isn't safe if this is the only runnable thread. @@ -1112,7 +1111,7 @@ void MonitorList::SweepMonitorList(IsMarkedCallback* callback, void* arg) { static mirror::Object* MonitorDeflateCallback(mirror::Object* object, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (Monitor::Deflate(reinterpret_cast<Thread*>(arg), object)) { - DCHECK_NE(object->GetLockWord().GetState(), LockWord::kFatLocked); + DCHECK_NE(object->GetLockWord(true).GetState(), LockWord::kFatLocked); // If we deflated, return nullptr so that the monitor gets removed from the array. return nullptr; } @@ -1126,9 +1125,8 @@ void MonitorList::DeflateMonitors() { } MonitorInfo::MonitorInfo(mirror::Object* obj) : owner_(NULL), entry_count_(0) { - DCHECK(obj != NULL); - - LockWord lock_word = obj->GetLockWord(); + DCHECK(obj != nullptr); + LockWord lock_word = obj->GetLockWord(true); switch (lock_word.GetState()) { case LockWord::kUnlocked: // Fall-through. diff --git a/runtime/thread.cc b/runtime/thread.cc index b3d14f0..8691dec 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -876,7 +876,7 @@ struct StackDumpVisitor : public StackVisitor { if (o == nullptr) { os << "an unknown object"; } else { - if ((o->GetLockWord().GetState() == LockWord::kThinLocked) && + if ((o->GetLockWord(false).GetState() == LockWord::kThinLocked) && Locks::mutator_lock_->IsExclusiveHeld(Thread::Current())) { // Getting the identity hashcode here would result in lock inflation and suspension of the // current thread, which isn't safe if this is the only runnable thread. diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc index 76b6f27..1dc2da0 100644 --- a/runtime/transaction_test.cc +++ b/runtime/transaction_test.cc @@ -55,18 +55,18 @@ TEST_F(TransactionTest, Object_monitor) { // Lock object's monitor outside the transaction. sirt_obj->MonitorEnter(soa.Self()); - uint32_t old_lock_word = sirt_obj->GetLockWord().GetValue(); + uint32_t old_lock_word = sirt_obj->GetLockWord(false).GetValue(); Transaction transaction; Runtime::Current()->EnterTransactionMode(&transaction); // Unlock object's monitor inside the transaction. sirt_obj->MonitorExit(soa.Self()); - uint32_t new_lock_word = sirt_obj->GetLockWord().GetValue(); + uint32_t new_lock_word = sirt_obj->GetLockWord(false).GetValue(); Runtime::Current()->ExitTransactionMode(); // Aborting transaction must not clear the Object::class field. transaction.Abort(); - uint32_t aborted_lock_word = sirt_obj->GetLockWord().GetValue(); + uint32_t aborted_lock_word = sirt_obj->GetLockWord(false).GetValue(); EXPECT_NE(old_lock_word, new_lock_word); EXPECT_EQ(aborted_lock_word, new_lock_word); } |