diff options
author | Mathieu Chartier <mathieuc@google.com> | 2013-10-25 10:05:23 -0700 |
---|---|---|
committer | Mathieu Chartier <mathieuc@google.com> | 2013-10-29 12:14:36 -0700 |
commit | ad2541a59c00c2c69e8973088891a2b5257c9780 (patch) | |
tree | 523898cf039c5185352978e71a54fa3a2657a04c /runtime/mirror/object.cc | |
parent | 9780099e445884d8bc9444c8c1261b02d80a26c7 (diff) | |
download | art-ad2541a59c00c2c69e8973088891a2b5257c9780.zip art-ad2541a59c00c2c69e8973088891a2b5257c9780.tar.gz art-ad2541a59c00c2c69e8973088891a2b5257c9780.tar.bz2 |
Fix object identity hash.
The object identity hash is now stored in the monitor word after
being computed. Hashes are computed by a pseudo random number
generator.
When we write the image, we eagerly compute object hashes to
prevent pages getting dirtied.
Bug: 8981901
Change-Id: Ic8edacbacb0afc7055fd740a52444929f88ed564
Diffstat (limited to 'runtime/mirror/object.cc')
-rw-r--r-- | runtime/mirror/object.cc | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc index 92c05b2..49bad4c 100644 --- a/runtime/mirror/object.cc +++ b/runtime/mirror/object.cc @@ -14,6 +14,8 @@ * limitations under the License. */ +#include <ctime> + #include "object.h" #include "art_field.h" @@ -82,6 +84,52 @@ Object* Object::Clone(Thread* self) { return copy.get(); } +uint32_t Object::GenerateIdentityHashCode() { + static AtomicInteger seed(987654321 + std::time(nullptr)); + uint32_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))); + return expected_value & LockWord::kHashMask; +} + +int32_t Object::IdentityHashCode() const { + while (true) { + LockWord lw = GetLockWord(); + 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 + // loop iteration. + LockWord hash_word(LockWord::FromHashCode(GenerateIdentityHashCode())); + DCHECK_EQ(hash_word.GetState(), LockWord::kHashCode); + if (const_cast<Object*>(this)->CasLockWord(lw, hash_word)) { + return hash_word.GetHashCode(); + } + break; + } + case LockWord::kThinLocked: { + // Inflate the thin lock to a monitor and stick the hash code inside of the monitor. + Thread* self = Thread::Current(); + Monitor::InflateThinLocked(self, const_cast<Object*>(this), lw, GenerateIdentityHashCode()); + break; + } + case LockWord::kFatLocked: { + // Already inflated, return the has stored in the monitor. + Monitor* monitor = lw.FatLockMonitor(); + DCHECK(monitor != nullptr); + return monitor->GetHashCode(); + } + case LockWord::kHashCode: { + return lw.GetHashCode(); + } + } + } + LOG(FATAL) << "Unreachable"; + return 0; +} + void Object::CheckFieldAssignmentImpl(MemberOffset field_offset, const Object* new_value) { const Class* c = GetClass(); if (Runtime::Current()->GetClassLinker() == NULL || |