diff options
author | Ian Rogers <irogers@google.com> | 2013-10-01 19:45:43 -0700 |
---|---|---|
committer | Ian Rogers <irogers@google.com> | 2013-10-02 09:31:55 -0700 |
commit | d9c4fc94fa618617f94e1de9af5f034549100753 (patch) | |
tree | 1305efbbc3d4bc306c0947bb6d4b01553667f98e /runtime/lock_word.h | |
parent | 7ef126ce0593929bcf8fb73d8b1119ce3b95b3f2 (diff) | |
download | art-d9c4fc94fa618617f94e1de9af5f034549100753.zip art-d9c4fc94fa618617f94e1de9af5f034549100753.tar.gz art-d9c4fc94fa618617f94e1de9af5f034549100753.tar.bz2 |
Inflate contended lock word by suspending owner.
Bug 6961405.
Don't inflate monitors for Notify and NotifyAll.
Tidy lock word, handle recursive lock case alongside unlocked case and move
assembly out of line (except for ARM quick). Also handle null in out-of-line
assembly as the test is quick and the enter/exit code is already a safepoint.
To gain ownership of a monitor on behalf of another thread, monitor contenders
must not hold the monitor_lock_, so they wait on a condition variable.
Reduce size of per mutex contention log.
Be consistent in calling thin lock thread ids just thread ids.
Fix potential thread death races caused by the use of FindThreadByThreadId,
make it invariant that returned threads are either self or suspended now.
Code size reduction on ARM boot.oat 0.2%.
Old nexus 7 speedup 0.25%, new nexus 7 speedup 1.4%, nexus 10 speedup 2.24%,
nexus 4 speedup 2.09% on DeltaBlue.
Change-Id: Id52558b914f160d9c8578fdd7fc8199a9598576a
Diffstat (limited to 'runtime/lock_word.h')
-rw-r--r-- | runtime/lock_word.h | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/runtime/lock_word.h b/runtime/lock_word.h new file mode 100644 index 0000000..cd4bfbb --- /dev/null +++ b/runtime/lock_word.h @@ -0,0 +1,128 @@ +/* + * 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_RUNTIME_LOCK_WORD_H_ +#define ART_RUNTIME_LOCK_WORD_H_ + +#include <iosfwd> +#include <stdint.h> + +#include "base/logging.h" + +namespace art { +namespace mirror { + class Object; +} // namespace mirror + +class Monitor; + +/* The lock value itself as stored in mirror::Object::monitor_. The MSB of the lock encodes its + * state. When cleared, the lock is in the "thin" state and its bits are formatted as follows: + * + * |3|32222222222111|11111110000000000| + * |1|09876543210987|65432109876543210| + * |0| lock count | thread id | + * + * When set, the lock is in the "fat" state and its bits are formatted as follows: + * + * |3|3222222222211111111110000000000| + * |1|0987654321098765432109876543210| + * |1| Monitor* >> 1 | + */ +class LockWord { + public: + enum { + // Number of bits to encode the state, currently just fat or thin/unlocked. + kStateSize = 1, + // Number of bits to encode the thin lock owner. + kThinLockOwnerSize = 16, + // Remaining bits are the recursive lock count. + kThinLockCountSize = 32 - kThinLockOwnerSize - kStateSize, + + // Thin lock bits. Owner in lowest bits. + kThinLockOwnerShift = 0, + kThinLockOwnerMask = (1 << kThinLockOwnerSize) - 1, + // Count in higher bits. + kThinLockCountShift = kThinLockOwnerSize + kThinLockOwnerShift, + kThinLockCountMask = (1 << kThinLockCountShift) - 1, + kThinLockMaxCount = kThinLockCountMask, + + // State in the highest bits. + kStateShift = kThinLockCountSize + kThinLockCountShift, + kStateMask = (1 << kStateSize) - 1, + kStateThinOrUnlocked = 0, + kStateFat = 1, + }; + + static LockWord FromThinLockId(uint32_t thread_id, uint32_t count) { + CHECK_LE(thread_id, static_cast<uint32_t>(kThinLockOwnerMask)); + return LockWord((thread_id << kThinLockOwnerShift) | (count << kThinLockCountShift)); + } + + enum LockState { + kUnlocked, // No lock owners. + kThinLocked, // Single uncontended owner. + kFatLocked // See associated monitor. + }; + + LockState GetState() const { + if (value_ == 0) { + return kUnlocked; + } else if (((value_ >> kStateShift) & kStateMask) == kStateThinOrUnlocked) { + return kThinLocked; + } else { + return kFatLocked; + } + } + + // Return the owner thin lock thread id. + uint32_t ThinLockOwner() const; + + // Return the number of times a lock value has been locked. + uint32_t ThinLockCount() const; + + // Return the Monitor encoded in a fat lock. + Monitor* FatLockMonitor() const; + + // Default constructor with no lock ownership. + LockWord(); + + // Constructor a lock word for inflation to use a Monitor. + explicit LockWord(Monitor* mon); + + bool operator==(const LockWord& rhs) { + return GetValue() == rhs.GetValue(); + } + + private: + explicit LockWord(uint32_t val) : value_(val) {} + + uint32_t GetValue() const { + return value_; + } + + // Only Object should be converting LockWords to/from uints. + friend class mirror::Object; + + // The encoded value holding all the state. + uint32_t value_; +}; +std::ostream& operator<<(std::ostream& os, const LockWord::LockState& code); + +} // namespace art + + +#endif // ART_RUNTIME_LOCK_WORD_H_ |