summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathieu Chartier <mathieuc@google.com>2013-10-31 10:35:05 -0700
committerMathieu Chartier <mathieuc@google.com>2013-10-31 13:33:51 -0700
commit4e6a31eb97f22f4480827474b30b9e64f396eace (patch)
tree3afe222c60314a22be8bb8de61cb245e1af2dc92
parent1b8cb967143d5c46db1db8ac940a73d111be3628 (diff)
downloadart-4e6a31eb97f22f4480827474b30b9e64f396eace.tar.gz
art-4e6a31eb97f22f4480827474b30b9e64f396eace.tar.bz2
art-4e6a31eb97f22f4480827474b30b9e64f396eace.zip
Lazily compute object identity hash codes.
Before, we computed identity hashcodes whenever we inflated a monitor. This caused issues since it meant that we would have all of these hash codes in the image, causing locks to excessively inflate during application run time. This change makes it so that we lazily compute hash codes. When a thin lock gets inflated, we assign a hash code of 0 assigned to it. This value signifies no hash code. When we try to get the identity hash code of an object with an inflated monitor, it gets computed if it is 0. Change-Id: Iae6acd1960515a36e74644e5b1323ff336731806
-rw-r--r--compiler/image_writer.cc9
-rw-r--r--runtime/arch/arm/quick_entrypoints_arm.S2
-rw-r--r--runtime/lock_word-inl.h2
-rw-r--r--runtime/lock_word.h2
-rw-r--r--runtime/mirror/object.cc8
-rw-r--r--runtime/mirror/object.h2
-rw-r--r--runtime/monitor.cc20
-rw-r--r--runtime/monitor.h15
8 files changed, 39 insertions, 21 deletions
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index af60a3878a..75be2c9c43 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -504,7 +504,11 @@ void ImageWriter::CopyAndFixupObjectsCallback(Object* object, void* arg) {
Monitor* monitor = lw.FatLockMonitor();
CHECK(monitor != nullptr);
CHECK(!monitor->IsLocked());
- copy->SetLockWord(LockWord::FromHashCode(monitor->GetHashCode()));
+ if (monitor->HasHashCode()) {
+ copy->SetLockWord(LockWord::FromHashCode(monitor->GetHashCode()));
+ } else {
+ copy->SetLockWord(LockWord());
+ }
break;
}
case LockWord::kThinLocked: {
@@ -512,9 +516,10 @@ void ImageWriter::CopyAndFixupObjectsCallback(Object* object, void* arg) {
break;
}
case LockWord::kUnlocked:
- // Fall-through.
+ break;
case LockWord::kHashCode:
// Do nothing since we can just keep the same hash code.
+ CHECK_NE(lw.GetHashCode(), 0);
break;
default:
LOG(FATAL) << "Unreachable.";
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 50a51760ae..9a853d07ab 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -325,7 +325,7 @@ END art_quick_handle_fill_data
ENTRY art_quick_lock_object
cbz r0, slow_lock
retry_lock:
- ldrt r2, [r9, #THREAD_ID_OFFSET]
+ ldr r2, [r9, #THREAD_ID_OFFSET]
ldrex r1, [r0, #LOCK_WORD_OFFSET]
cbnz r1, not_unlocked @ already thin locked
@ unlocked case - r2 holds thread id with count of 0
diff --git a/runtime/lock_word-inl.h b/runtime/lock_word-inl.h
index 59947f5694..efd3d9d25e 100644
--- a/runtime/lock_word-inl.h
+++ b/runtime/lock_word-inl.h
@@ -45,7 +45,7 @@ inline LockWord::LockWord(Monitor* mon)
DCHECK_EQ(FatLockMonitor(), mon);
}
-inline uint32_t LockWord::GetHashCode() const {
+inline int32_t LockWord::GetHashCode() const {
DCHECK_EQ(GetState(), kHashCode);
return (value_ >> kHashShift) & kHashMask;
}
diff --git a/runtime/lock_word.h b/runtime/lock_word.h
index 9b6c64a183..1882ae6504 100644
--- a/runtime/lock_word.h
+++ b/runtime/lock_word.h
@@ -132,7 +132,7 @@ class LockWord {
}
// Return the hash code stored in the lock word, must be kHashCode state.
- uint32_t GetHashCode() const;
+ int32_t GetHashCode() const;
uint32_t GetValue() const {
return value_;
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index 49bad4ccb8..bd187c1835 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -84,14 +84,14 @@ Object* Object::Clone(Thread* self) {
return copy.get();
}
-uint32_t Object::GenerateIdentityHashCode() {
+int32_t Object::GenerateIdentityHashCode() {
static AtomicInteger seed(987654321 + std::time(nullptr));
- uint32_t expected_value, new_value;
+ int32_t expected_value, new_value;
do {
expected_value = static_cast<uint32_t>(seed.load());
new_value = expected_value * 1103515245 + 12345;
- } while (!seed.compare_and_swap(static_cast<int32_t>(expected_value),
- static_cast<int32_t>(new_value)));
+ } while ((expected_value & LockWord::kHashMask) == 0 ||
+ !seed.compare_and_swap(expected_value, new_value));
return expected_value & LockWord::kHashMask;
}
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 11473cd399..e8ea3f2375 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -249,7 +249,7 @@ class MANAGED Object {
}
// Generate an identity hash code.
- static uint32_t GenerateIdentityHashCode();
+ static int32_t GenerateIdentityHashCode();
// Write barrier called post update to a reference bearing field.
static void WriteBarrierField(const Object* dst, MemberOffset offset, const Object* new_value);
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index aa47bdac5a..2abfd3df41 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -79,7 +79,7 @@ void Monitor::Init(uint32_t lock_profiling_threshold, bool (*is_sensitive_thread
is_sensitive_thread_hook_ = is_sensitive_thread_hook;
}
-Monitor::Monitor(Thread* owner, mirror::Object* obj, uint32_t hash_code)
+Monitor::Monitor(Thread* owner, mirror::Object* obj, int32_t hash_code)
: monitor_lock_("a monitor lock", kMonitorLock),
monitor_contenders_("monitor contenders", monitor_lock_),
owner_(owner),
@@ -95,6 +95,16 @@ Monitor::Monitor(Thread* owner, mirror::Object* obj, uint32_t hash_code)
// The identity hash code is set for the life time of the monitor.
}
+int32_t Monitor::GetHashCode() {
+ while (!HasHashCode()) {
+ if (hash_code_.compare_and_swap(0, mirror::Object::GenerateIdentityHashCode())) {
+ break;
+ }
+ }
+ DCHECK(HasHashCode());
+ return hash_code_.load();
+}
+
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());
@@ -107,7 +117,7 @@ bool Monitor::Install(Thread* self) {
break;
}
case LockWord::kHashCode: {
- CHECK_EQ(hash_code_, lw.GetHashCode());
+ CHECK_EQ(hash_code_, static_cast<int32_t>(lw.GetHashCode()));
break;
}
case LockWord::kFatLocked: {
@@ -622,7 +632,7 @@ void Monitor::MonitorEnter(Thread* self, mirror::Object* obj) {
return; // Success!
} else {
// We'd overflow the recursion count, so inflate the monitor.
- InflateThinLocked(self, obj, lock_word, mirror::Object::GenerateIdentityHashCode());
+ InflateThinLocked(self, obj, lock_word, 0);
}
} else {
// Contention.
@@ -632,7 +642,7 @@ void Monitor::MonitorEnter(Thread* self, mirror::Object* obj) {
NanoSleep(1000); // Sleep for 1us and re-attempt.
} else {
contention_count = 0;
- InflateThinLocked(self, obj, lock_word, mirror::Object::GenerateIdentityHashCode());
+ InflateThinLocked(self, obj, lock_word, 0);
}
}
continue; // Start from the beginning.
@@ -716,7 +726,7 @@ void Monitor::Wait(Thread* self, mirror::Object *obj, int64_t ms, int32_t ns,
return; // Failure.
} else {
// We own the lock, inflate to enqueue ourself on the Monitor.
- Inflate(self, self, obj, mirror::Object::GenerateIdentityHashCode());
+ Inflate(self, self, obj, 0);
lock_word = obj->GetLockWord();
}
break;
diff --git a/runtime/monitor.h b/runtime/monitor.h
index c464400f46..09cfafa042 100644
--- a/runtime/monitor.h
+++ b/runtime/monitor.h
@@ -24,6 +24,7 @@
#include <list>
#include <vector>
+#include "atomic_integer.h"
#include "base/mutex.h"
#include "root_visitor.h"
#include "thread_state.h"
@@ -98,17 +99,19 @@ class Monitor {
return owner_;
}
- int32_t GetHashCode() const {
- return hash_code_;
- }
+ int32_t GetHashCode();
bool IsLocked() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool HasHashCode() const {
+ return hash_code_.load() != 0;
+ }
+
static void InflateThinLocked(Thread* self, mirror::Object* obj, LockWord lock_word,
uint32_t hash_code) NO_THREAD_SAFETY_ANALYSIS;
private:
- explicit Monitor(Thread* owner, mirror::Object* obj, uint32_t hash_code)
+ explicit Monitor(Thread* owner, mirror::Object* obj, int32_t hash_code)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Install the monitor into its object, may fail if another thread installs a different monitor
@@ -179,8 +182,8 @@ class Monitor {
// Threads currently waiting on this monitor.
Thread* wait_set_ GUARDED_BY(monitor_lock_);
- // Stored object hash code, always generated.
- const uint32_t hash_code_;
+ // Stored object hash code, generated lazily by GetHashCode.
+ AtomicInteger hash_code_;
// Method and dex pc where the lock owner acquired the lock, used when lock
// sampling is enabled. locking_method_ may be null if the lock is currently