You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
325 lines
12 KiB
325 lines
12 KiB
/*
|
|
* 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 <cstdint>
|
|
#include <iosfwd>
|
|
|
|
#include <android-base/logging.h>
|
|
|
|
#include "base/bit_utils.h"
|
|
#include "read_barrier.h"
|
|
|
|
namespace art {
|
|
namespace mirror {
|
|
class Object;
|
|
} // namespace mirror
|
|
|
|
class Monitor;
|
|
|
|
/* The lock value itself as stored in mirror::Object::monitor_. The two most significant bits
|
|
* encode the state. The four possible states are fat locked, thin/unlocked, hash code, and
|
|
* forwarding address.
|
|
*
|
|
* When the lock word is in the "thin" state and its bits are formatted as follows:
|
|
*
|
|
* |33|2|2|222222221111|1111110000000000|
|
|
* |10|9|8|765432109876|5432109876543210|
|
|
* |00|m|r| lock count |thread id owner |
|
|
*
|
|
* The lock count is zero, but the owner is nonzero for a simply held lock.
|
|
* When the lock word is in the "fat" state and its bits are formatted as follows:
|
|
*
|
|
* |33|2|2|2222222211111111110000000000|
|
|
* |10|9|8|7654321098765432109876543210|
|
|
* |01|m|r| MonitorId |
|
|
*
|
|
* When the lock word is in hash state and its bits are formatted as follows:
|
|
*
|
|
* |33|2|2|2222222211111111110000000000|
|
|
* |10|9|8|7654321098765432109876543210|
|
|
* |10|m|r| HashCode |
|
|
*
|
|
* When the lock word is in forwarding address state and its bits are formatted as follows:
|
|
*
|
|
* |33|2|22222222211111111110000000000|
|
|
* |10|9|87654321098765432109876543210|
|
|
* |11|0| ForwardingAddress |
|
|
*
|
|
* The `r` bit stores the read barrier state.
|
|
* The `m` bit stores the mark bit state.
|
|
*/
|
|
class LockWord {
|
|
public:
|
|
enum SizeShiftsAndMasks : uint32_t { // private marker to avoid generate-operator-out.py from processing.
|
|
// Number of bits to encode the state, currently just fat or thin/unlocked or hash code.
|
|
kStateSize = 2,
|
|
kReadBarrierStateSize = 1,
|
|
kMarkBitStateSize = 1,
|
|
// Number of bits to encode the thin lock owner.
|
|
kThinLockOwnerSize = 16,
|
|
// Remaining bits are the recursive lock count. Zero means it is locked exactly once
|
|
// and not recursively.
|
|
kThinLockCountSize = 32 - kThinLockOwnerSize - kStateSize - kReadBarrierStateSize -
|
|
kMarkBitStateSize,
|
|
|
|
// Thin lock bits. Owner in lowest bits.
|
|
kThinLockOwnerShift = 0,
|
|
kThinLockOwnerMask = (1 << kThinLockOwnerSize) - 1,
|
|
kThinLockOwnerMaskShifted = kThinLockOwnerMask << kThinLockOwnerShift,
|
|
kThinLockMaxOwner = kThinLockOwnerMask,
|
|
// Count in higher bits.
|
|
kThinLockCountShift = kThinLockOwnerSize + kThinLockOwnerShift,
|
|
kThinLockCountMask = (1 << kThinLockCountSize) - 1,
|
|
kThinLockMaxCount = kThinLockCountMask,
|
|
kThinLockCountOne = 1 << kThinLockCountShift, // == 65536 (0x10000)
|
|
kThinLockCountMaskShifted = kThinLockCountMask << kThinLockCountShift,
|
|
|
|
// State in the highest bits.
|
|
kStateShift = kReadBarrierStateSize + kThinLockCountSize + kThinLockCountShift +
|
|
kMarkBitStateSize,
|
|
kStateMask = (1 << kStateSize) - 1,
|
|
kStateMaskShifted = kStateMask << kStateShift,
|
|
kStateThinOrUnlocked = 0,
|
|
kStateFat = 1,
|
|
kStateHash = 2,
|
|
kStateForwardingAddress = 3,
|
|
kStateForwardingAddressShifted = kStateForwardingAddress << kStateShift,
|
|
kStateForwardingAddressOverflow = (1 + kStateMask - kStateForwardingAddress) << kStateShift,
|
|
|
|
// Read barrier bit.
|
|
kReadBarrierStateShift = kThinLockCountSize + kThinLockCountShift,
|
|
kReadBarrierStateMask = (1 << kReadBarrierStateSize) - 1,
|
|
kReadBarrierStateMaskShifted = kReadBarrierStateMask << kReadBarrierStateShift,
|
|
kReadBarrierStateMaskShiftedToggled = ~kReadBarrierStateMaskShifted,
|
|
|
|
// Mark bit.
|
|
kMarkBitStateShift = kReadBarrierStateSize + kReadBarrierStateShift,
|
|
kMarkBitStateMask = (1 << kMarkBitStateSize) - 1,
|
|
kMarkBitStateMaskShifted = kMarkBitStateMask << kMarkBitStateShift,
|
|
kMarkBitStateMaskShiftedToggled = ~kMarkBitStateMaskShifted,
|
|
|
|
// GC state is mark bit and read barrier state.
|
|
kGCStateSize = kReadBarrierStateSize + kMarkBitStateSize,
|
|
kGCStateShift = kReadBarrierStateShift,
|
|
kGCStateMaskShifted = kReadBarrierStateMaskShifted | kMarkBitStateMaskShifted,
|
|
kGCStateMaskShiftedToggled = ~kGCStateMaskShifted,
|
|
|
|
// When the state is kHashCode, the non-state bits hold the hashcode.
|
|
// Note Object.hashCode() has the hash code layout hardcoded.
|
|
kHashShift = 0,
|
|
kHashSize = 32 - kStateSize - kReadBarrierStateSize - kMarkBitStateSize,
|
|
kHashMask = (1 << kHashSize) - 1,
|
|
kMaxHash = kHashMask,
|
|
|
|
// Forwarding address shift.
|
|
kForwardingAddressShift = kObjectAlignmentShift,
|
|
|
|
kMonitorIdShift = kHashShift,
|
|
kMonitorIdSize = kHashSize,
|
|
kMonitorIdMask = kHashMask,
|
|
kMonitorIdAlignmentShift = 32 - kMonitorIdSize,
|
|
kMonitorIdAlignment = 1 << kMonitorIdAlignmentShift,
|
|
kMaxMonitorId = kMaxHash
|
|
};
|
|
|
|
static LockWord FromThinLockId(uint32_t thread_id, uint32_t count, uint32_t gc_state) {
|
|
CHECK_LE(thread_id, static_cast<uint32_t>(kThinLockMaxOwner));
|
|
CHECK_LE(count, static_cast<uint32_t>(kThinLockMaxCount));
|
|
// DCHECK_EQ(gc_bits & kGCStateMaskToggled, 0U);
|
|
return LockWord((thread_id << kThinLockOwnerShift) |
|
|
(count << kThinLockCountShift) |
|
|
(gc_state << kGCStateShift) |
|
|
(kStateThinOrUnlocked << kStateShift));
|
|
}
|
|
|
|
static LockWord FromForwardingAddress(size_t target) {
|
|
DCHECK_ALIGNED(target, (1 << kStateSize));
|
|
return LockWord((target >> kForwardingAddressShift) | kStateForwardingAddressShifted);
|
|
}
|
|
|
|
static LockWord FromHashCode(uint32_t hash_code, uint32_t gc_state) {
|
|
CHECK_LE(hash_code, static_cast<uint32_t>(kMaxHash));
|
|
// DCHECK_EQ(gc_bits & kGCStateMaskToggled, 0U);
|
|
return LockWord((hash_code << kHashShift) |
|
|
(gc_state << kGCStateShift) |
|
|
(kStateHash << kStateShift));
|
|
}
|
|
|
|
static LockWord FromDefault(uint32_t gc_state) {
|
|
return LockWord(gc_state << kGCStateShift);
|
|
}
|
|
|
|
static bool IsDefault(LockWord lw) {
|
|
return LockWord().GetValue() == lw.GetValue();
|
|
}
|
|
|
|
static LockWord Default() {
|
|
return LockWord();
|
|
}
|
|
|
|
enum LockState {
|
|
kUnlocked, // No lock owners.
|
|
kThinLocked, // Single uncontended owner.
|
|
kFatLocked, // See associated monitor.
|
|
kHashCode, // Lock word contains an identity hash.
|
|
kForwardingAddress, // Lock word contains the forwarding address of an object.
|
|
};
|
|
|
|
LockState GetState() const {
|
|
CheckReadBarrierState();
|
|
if ((!kUseReadBarrier && UNLIKELY(value_ == 0)) ||
|
|
(kUseReadBarrier && UNLIKELY((value_ & kGCStateMaskShiftedToggled) == 0))) {
|
|
return kUnlocked;
|
|
} else {
|
|
uint32_t internal_state = (value_ >> kStateShift) & kStateMask;
|
|
switch (internal_state) {
|
|
case kStateThinOrUnlocked:
|
|
return kThinLocked;
|
|
case kStateHash:
|
|
return kHashCode;
|
|
case kStateForwardingAddress:
|
|
return kForwardingAddress;
|
|
default:
|
|
DCHECK_EQ(internal_state, static_cast<uint32_t>(kStateFat));
|
|
return kFatLocked;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32_t ReadBarrierState() const {
|
|
return (value_ >> kReadBarrierStateShift) & kReadBarrierStateMask;
|
|
}
|
|
|
|
uint32_t GCState() const {
|
|
return (value_ & kGCStateMaskShifted) >> kGCStateShift;
|
|
}
|
|
|
|
void SetReadBarrierState(uint32_t rb_state) {
|
|
DCHECK_EQ(rb_state & ~kReadBarrierStateMask, 0U);
|
|
DCHECK(rb_state == ReadBarrier::NonGrayState() ||
|
|
rb_state == ReadBarrier::GrayState()) << rb_state;
|
|
DCHECK_NE(static_cast<uint32_t>(GetState()), static_cast<uint32_t>(kForwardingAddress));
|
|
// Clear and or the bits.
|
|
value_ &= ~(kReadBarrierStateMask << kReadBarrierStateShift);
|
|
value_ |= (rb_state & kReadBarrierStateMask) << kReadBarrierStateShift;
|
|
}
|
|
|
|
|
|
uint32_t MarkBitState() const {
|
|
return (value_ >> kMarkBitStateShift) & kMarkBitStateMask;
|
|
}
|
|
|
|
void SetMarkBitState(uint32_t mark_bit) {
|
|
DCHECK_EQ(mark_bit & ~kMarkBitStateMask, 0U);
|
|
DCHECK_NE(static_cast<uint32_t>(GetState()), static_cast<uint32_t>(kForwardingAddress));
|
|
// Clear and or the bits.
|
|
value_ &= kMarkBitStateMaskShiftedToggled;
|
|
value_ |= mark_bit << kMarkBitStateShift;
|
|
}
|
|
|
|
// Return the owner thin lock thread id.
|
|
uint32_t ThinLockOwner() const;
|
|
|
|
// Return the number of times a lock value has been re-locked. Only valid in thin-locked state.
|
|
// If the lock is held only once the return value is zero.
|
|
uint32_t ThinLockCount() const;
|
|
|
|
// Return the Monitor encoded in a fat lock.
|
|
Monitor* FatLockMonitor() const;
|
|
|
|
// Return the forwarding address stored in the monitor.
|
|
size_t ForwardingAddress() const;
|
|
|
|
// Constructor a lock word for inflation to use a Monitor.
|
|
LockWord(Monitor* mon, uint32_t gc_state);
|
|
|
|
// Return the hash code stored in the lock word, must be kHashCode state.
|
|
int32_t GetHashCode() const;
|
|
|
|
template <bool kIncludeReadBarrierState>
|
|
static bool Equal(LockWord lw1, LockWord lw2) {
|
|
if (kIncludeReadBarrierState) {
|
|
return lw1.GetValue() == lw2.GetValue();
|
|
}
|
|
return lw1.GetValueWithoutGCState() == lw2.GetValueWithoutGCState();
|
|
}
|
|
|
|
void Dump(std::ostream& os) {
|
|
os << "LockWord:" << std::hex << value_;
|
|
}
|
|
|
|
private:
|
|
// Default constructor with no lock ownership.
|
|
LockWord();
|
|
|
|
explicit LockWord(uint32_t val) : value_(val) {
|
|
// Make sure adding the overflow causes an overflow.
|
|
constexpr uint64_t overflow = static_cast<uint64_t>(kStateForwardingAddressShifted) +
|
|
static_cast<uint64_t>(kStateForwardingAddressOverflow);
|
|
constexpr bool is_larger = overflow > static_cast<uint64_t>(0xFFFFFFFF);
|
|
static_assert(is_larger, "should have overflowed");
|
|
static_assert(
|
|
(~kStateForwardingAddress & kStateMask) == 0,
|
|
"READ_BARRIER_MARK_REG relies on the forwarding address state being only one bits");
|
|
CheckReadBarrierState();
|
|
}
|
|
|
|
// Disallow this in favor of explicit Equal() with the
|
|
// kIncludeReadBarrierState param to make clients be aware of the
|
|
// read barrier state.
|
|
bool operator==(const LockWord& rhs) = delete;
|
|
|
|
void CheckReadBarrierState() const {
|
|
if (kIsDebugBuild && ((value_ >> kStateShift) & kStateMask) != kStateForwardingAddress) {
|
|
uint32_t rb_state = ReadBarrierState();
|
|
if (!kUseReadBarrier) {
|
|
DCHECK_EQ(rb_state, 0U);
|
|
} else {
|
|
DCHECK(rb_state == ReadBarrier::NonGrayState() ||
|
|
rb_state == ReadBarrier::GrayState()) << rb_state;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Note GetValue() includes the read barrier bits and comparing (==)
|
|
// GetValue() between two lock words to compare the lock states may
|
|
// not work. Prefer Equal() or GetValueWithoutReadBarrierState().
|
|
uint32_t GetValue() const {
|
|
CheckReadBarrierState();
|
|
return value_;
|
|
}
|
|
|
|
uint32_t GetValueWithoutGCState() const {
|
|
CheckReadBarrierState();
|
|
return value_ & kGCStateMaskShiftedToggled;
|
|
}
|
|
|
|
// 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, LockWord::LockState code);
|
|
|
|
} // namespace art
|
|
|
|
|
|
#endif // ART_RUNTIME_LOCK_WORD_H_
|