summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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