// Binary predicate function for finding access_mode by // method_name. The access_mode field is ignored. staticbool CompareName(const VarHandleAccessorToAccessModeEntry& lhs, const VarHandleAccessorToAccessModeEntry& rhs) { return strcmp(lhs.method_name, rhs.method_name) < 0;
}
};
// Map of VarHandle accessor method names to access mode values. The list is alpha-sorted to support // binary search. For the usage scenario - lookups in the verifier - a linear scan would likely // suffice since we expect VarHandles to be a lesser encountered class. We could use a std::hashmap // here and this would be easier to maintain if new values are added here. However, this entails // CPU cycles initializing the structure on every execution and uses O(N) more memory for // intermediate nodes and makes that memory dirty. Compile-time magic using constexpr is possible // here, but that's a tax when this code is recompiled. const VarHandleAccessorToAccessModeEntry kAccessorToAccessMode[VarHandle::kNumberOfAccessModes] = {
{ "compareAndExchange", VarHandle::AccessMode::kCompareAndExchange },
{ "compareAndExchangeAcquire", VarHandle::AccessMode::kCompareAndExchangeAcquire },
{ "compareAndExchangeRelease", VarHandle::AccessMode::kCompareAndExchangeRelease },
{ "compareAndSet", VarHandle::AccessMode::kCompareAndSet },
{ "get", VarHandle::AccessMode::kGet },
{ "getAcquire", VarHandle::AccessMode::kGetAcquire },
{ "getAndAdd", VarHandle::AccessMode::kGetAndAdd },
{ "getAndAddAcquire", VarHandle::AccessMode::kGetAndAddAcquire },
{ "getAndAddRelease", VarHandle::AccessMode::kGetAndAddRelease },
{ "getAndBitwiseAnd", VarHandle::AccessMode::kGetAndBitwiseAnd },
{ "getAndBitwiseAndAcquire", VarHandle::AccessMode::kGetAndBitwiseAndAcquire },
{ "getAndBitwiseAndRelease", VarHandle::AccessMode::kGetAndBitwiseAndRelease },
{ "getAndBitwiseOr", VarHandle::AccessMode::kGetAndBitwiseOr },
{ "getAndBitwiseOrAcquire", VarHandle::AccessMode::kGetAndBitwiseOrAcquire },
{ "getAndBitwiseOrRelease", VarHandle::AccessMode::kGetAndBitwiseOrRelease },
{ "getAndBitwiseXor", VarHandle::AccessMode::kGetAndBitwiseXor },
{ "getAndBitwiseXorAcquire", VarHandle::AccessMode::kGetAndBitwiseXorAcquire },
{ "getAndBitwiseXorRelease", VarHandle::AccessMode::kGetAndBitwiseXorRelease },
{ "getAndSet", VarHandle::AccessMode::kGetAndSet },
{ "getAndSetAcquire", VarHandle::AccessMode::kGetAndSetAcquire },
{ "getAndSetRelease", VarHandle::AccessMode::kGetAndSetRelease },
{ "getOpaque", VarHandle::AccessMode::kGetOpaque },
{ "getVolatile", VarHandle::AccessMode::kGetVolatile },
{ "set", VarHandle::AccessMode::kSet },
{ "setOpaque", VarHandle::AccessMode::kSetOpaque },
{ "setRelease", VarHandle::AccessMode::kSetRelease },
{ "setVolatile", VarHandle::AccessMode::kSetVolatile },
{ "weakCompareAndSet", VarHandle::AccessMode::kWeakCompareAndSet },
{ "weakCompareAndSetAcquire", VarHandle::AccessMode::kWeakCompareAndSetAcquire },
{ "weakCompareAndSetPlain", VarHandle::AccessMode::kWeakCompareAndSetPlain },
{ "weakCompareAndSetRelease", VarHandle::AccessMode::kWeakCompareAndSetRelease },
};
// Returns the number of parameters associated with an // AccessModeTemplate and the supplied coordinate types.
int32_t GetNumberOfParameters(VarHandle::AccessModeTemplate access_mode_template,
ObjPtr<Class> coordinateType0,
ObjPtr<Class> coordinateType1) {
int32_t count = 0; if (!coordinateType0.IsNull()) {
count++; if (!coordinateType1.IsNull()) {
count++;
}
} return count + VarHandle::GetNumberOfVarTypeParameters(access_mode_template);
}
void ThrowNullPointerExceptionForCoordinate() REQUIRES_SHARED(Locks::mutator_lock_) {
ThrowNullPointerException("Attempt to access memory on a null object");
}
bool CheckElementIndex(Primitive::Type type,
int32_t index,
int32_t start,
int32_t length) REQUIRES_SHARED(Locks::mutator_lock_) { // The underlying memory may be shared and offset from the start of allocated region, // ie buffers can be created via ByteBuffer.split(). // // `type` is the type of the value the caller is attempting to read / write. // `index` represents the position the caller is trying to access in the underlying ByteBuffer // or byte array. This is an offset from from `start` in bytes. // `start` represents where the addressable memory begins relative to the base of the // the underlying ByteBuffer or byte array. // `length` represents the length of the addressable region. // // Thus the region being operated on is: // `base` + `start` + `index` to `base` + `start` + `index` + `sizeof(type)`
int32_t max_index = length - start - Primitive::ComponentSize(type); if (index < 0 || index > max_index) {
ThrowIndexOutOfBoundsException(index, length - start); returnfalse;
} returntrue;
}
// Returns true if access_mode only entails a memory read. False if // access_mode may write to memory. bool IsReadOnlyAccessMode(VarHandle::AccessMode access_mode) { return VarHandle::GetAccessModeTemplate(access_mode) == VarHandle::AccessModeTemplate::kGet;
}
// Writes the parameter types associated with the AccessModeTemplate // into an array. The parameter types are derived from the specified // variable type and coordinate types. Returns the number of // parameters written.
int32_t BuildParameterArray(ObjPtr<Class> (¶meters)[VarHandle::kMaxAccessorParameters],
VarHandle::AccessModeTemplate access_mode_template,
ObjPtr<Class> varType,
ObjPtr<Class> coordinateType0,
ObjPtr<Class> coordinateType1)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(varType != nullptr);
int32_t index = 0; if (!coordinateType0.IsNull()) {
parameters[index++] = coordinateType0; if (!coordinateType1.IsNull()) {
parameters[index++] = coordinateType1;
}
} else {
DCHECK(coordinateType1.IsNull());
}
switch (access_mode_template) { case VarHandle::AccessModeTemplate::kCompareAndExchange: case VarHandle::AccessModeTemplate::kCompareAndSet:
parameters[index++] = varType;
parameters[index++] = varType; return index; case VarHandle::AccessModeTemplate::kGet: return index; case VarHandle::AccessModeTemplate::kGetAndUpdate: case VarHandle::AccessModeTemplate::kSet:
parameters[index++] = varType; return index;
} return -1;
}
// Returns the return type associated with an VarHandle::AccessModeTemplate based // on the template and the variable type specified. static ObjPtr<Class> GetReturnType(VarHandle::AccessModeTemplate access_mode_template,
ObjPtr<Class> varType)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(varType != nullptr); switch (access_mode_template) { case VarHandle::AccessModeTemplate::kCompareAndSet: return GetClassRoot(ClassRoot::kPrimitiveBoolean); case VarHandle::AccessModeTemplate::kCompareAndExchange: case VarHandle::AccessModeTemplate::kGet: case VarHandle::AccessModeTemplate::kGetAndUpdate: return varType; case VarHandle::AccessModeTemplate::kSet: return GetClassRoot(ClassRoot::kPrimitiveVoid);
} return nullptr;
}
// Method to insert a read barrier for accessors to reference fields. inlinevoid ReadBarrierForVarHandleAccess(ObjPtr<Object> obj, MemberOffset field_offset)
REQUIRES_SHARED(Locks::mutator_lock_) { if (gUseReadBarrier) { // We need to ensure that the reference stored in the field is a to-space one before attempting // the CompareAndSet/CompareAndExchange/Exchange operation otherwise it will fail incorrectly // if obj is in the process of being moved.
uint8_t* raw_field_addr = reinterpret_cast<uint8_t*>(obj.Ptr()) + field_offset.SizeValue(); auto field_addr = reinterpret_cast<mirror::HeapReference<mirror::Object>*>(raw_field_addr); // Note that the read barrier load does NOT need to be volatile. static constexpr bool kIsVolatile = false; static constexpr bool kAlwaysUpdateField = true;
ReadBarrier::Barrier<mirror::Object, kIsVolatile, kWithReadBarrier, kAlwaysUpdateField>(
obj.Ptr(),
MemberOffset(field_offset),
field_addr);
}
}
// // Helper methods for storing results from atomic operations into // JValue instances. //
private:
T expected_value_;
T desired_value_;
JValue* result_;
};
template <typename T> using WeakCompareAndSetAccessor =
AtomicWeakCompareAndSetAccessor<T, std::memory_order_seq_cst, std::memory_order_seq_cst>;
template <typename T, std::memory_order MO> class AtomicGetAndSetAccessor : public Object::Accessor<T> { public:
AtomicGetAndSetAccessor(T new_value, JValue* result) : new_value_(new_value), result_(result) {}
void Access(T* addr) override {
std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr);
T old_value = atom->exchange(new_value_, MO);
StoreResult(old_value, result_);
}
private:
T new_value_;
JValue* result_;
};
template <typename T> using GetAndSetAccessor = AtomicGetAndSetAccessor<T, std::memory_order_seq_cst>;
template <typename T, bool kIsFloat, std::memory_order MO> class AtomicGetAndAddOperator { public: static T Apply(T* addr, T addend) {
std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr); return atom->fetch_add(addend, MO);
}
};
template <typename T, std::memory_order MO> class AtomicGetAndAddOperator<T, /* kIsFloat */ true, MO> { public: static T Apply(T* addr, T addend) { // c++11 does not have std::atomic<T>::fetch_and_add for floating // point types, so we effect one with a compare and swap.
std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr);
T old_value = atom->load(std::memory_order_relaxed);
T new_value; do {
new_value = old_value + addend;
} while (!atom->compare_exchange_weak(old_value, new_value, MO, std::memory_order_relaxed)); return old_value;
}
};
template <typename T, std::memory_order MO> class AtomicGetAndAddAccessor : public Object::Accessor<T> { public:
AtomicGetAndAddAccessor(T addend, JValue* result) : addend_(addend), result_(result) {}
template <typename T> using GetAndAddAccessor = AtomicGetAndAddAccessor<T, std::memory_order_seq_cst>;
// Accessor specifically for memory views where the caller can specify // the byte-ordering. Addition only works outside of the byte-swapped // memory view because of the direction of carries. template <typename T, std::memory_order MO> class AtomicGetAndAddWithByteSwapAccessor : public Object::Accessor<T> { public:
AtomicGetAndAddWithByteSwapAccessor(T value, JValue* result) : value_(value), result_(result) {}
void Access(T* addr) override {
std::atomic<T>* const atom = reinterpret_cast<std::atomic<T>*>(addr);
T current_value = atom->load(std::memory_order_relaxed);
T sum; do {
sum = BSWAP(current_value) + value_; // NB current_value is a pass-by-reference argument in the call to // atomic<T>::compare_exchange_weak().
} while (!atom->compare_exchange_weak(current_value,
BSWAP(sum),
MO,
std::memory_order_relaxed));
StoreResult(BSWAP(current_value), result_);
}
private:
T value_;
JValue* result_;
};
template <typename T> using GetAndAddWithByteSwapAccessor =
AtomicGetAndAddWithByteSwapAccessor<T, std::memory_order_seq_cst>;
template <typename T, std::memory_order MO> class AtomicGetAndBitwiseOrAccessor : public Object::Accessor<T> { public:
AtomicGetAndBitwiseOrAccessor(T value, JValue* result) : value_(value), result_(result) {}
void Access(T* addr) override {
std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr);
T old_value = atom->fetch_or(value_, MO);
StoreResult(old_value, result_);
}
private:
T value_;
JValue* result_;
};
template <typename T> using GetAndBitwiseOrAccessor = AtomicGetAndBitwiseOrAccessor<T, std::memory_order_seq_cst>;
template <typename T, std::memory_order MO> class AtomicGetAndBitwiseAndAccessor : public Object::Accessor<T> { public:
AtomicGetAndBitwiseAndAccessor(T value, JValue* result) : value_(value), result_(result) {}
void Access(T* addr) override {
std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr);
T old_value = atom->fetch_and(value_, MO);
StoreResult(old_value, result_);
}
private:
T value_;
JValue* result_;
};
template <typename T> using GetAndBitwiseAndAccessor =
AtomicGetAndBitwiseAndAccessor<T, std::memory_order_seq_cst>;
template <typename T, std::memory_order MO> class AtomicGetAndBitwiseXorAccessor : public Object::Accessor<T> { public:
AtomicGetAndBitwiseXorAccessor(T value, JValue* result) : value_(value), result_(result) {}
void Access(T* addr) override {
std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr);
T old_value = atom->fetch_xor(value_, MO);
StoreResult(old_value, result_);
}
private:
T value_;
JValue* result_;
};
template <typename T> using GetAndBitwiseXorAccessor = AtomicGetAndBitwiseXorAccessor<T, std::memory_order_seq_cst>;
// The boolean primitive type is not numeric (boolean == std::uint8_t).
UNREACHABLE_ACCESS_MODE(GetAndAdd, uint8_t)
// The floating point types do not support bitwise operations.
UNREACHABLE_ACCESS_MODE(GetAndBitwiseOr, float)
UNREACHABLE_ACCESS_MODE(GetAndBitwiseAnd, float)
UNREACHABLE_ACCESS_MODE(GetAndBitwiseXor, float)
UNREACHABLE_ACCESS_MODE(GetAndBitwiseOr, double)
UNREACHABLE_ACCESS_MODE(GetAndBitwiseAnd, double)
UNREACHABLE_ACCESS_MODE(GetAndBitwiseXor, double)
// A helper class for object field accesses for floats and // doubles. The object interface deals with Field32 and Field64. The // former is used for both integers and floats, the latter for longs // and doubles. This class provides the necessary coercion. template <typename T, typename U> class TypeAdaptorAccessor : public Object::Accessor<T> { public: explicit TypeAdaptorAccessor(Object::Accessor<U>* inner_accessor)
: inner_accessor_(inner_accessor) {}
template <typename T> class FieldAccessViaAccessor { public: using Accessor = Object::Accessor<T>;
// Apply an Accessor to get a field in an object. staticvoid Get(ObjPtr<Object> obj,
MemberOffset field_offset,
Accessor* accessor)
REQUIRES_SHARED(Locks::mutator_lock_) {
obj->GetPrimitiveFieldViaAccessor(field_offset, accessor);
}
// Apply an Accessor to update a field in an object. staticvoid Update(ObjPtr<Object> obj,
MemberOffset field_offset,
Accessor* accessor)
REQUIRES_SHARED(Locks::mutator_lock_);
};
// Helper class that gets values from a shadow frame with appropriate type coercion. template <typename T> class ValueGetter { public: static T Get(ShadowFrameGetter* getter) REQUIRES_SHARED(Locks::mutator_lock_) {
static_assert(sizeof(T) <= sizeof(uint32_t), "Bad size");
uint32_t raw_value = getter->Get(); returnstatic_cast<T>(raw_value);
}
};
// Class for accessing fields of Object instances template <typename T> class FieldAccessor { public: staticbool Dispatch(VarHandle::AccessMode access_mode,
ObjPtr<Object> obj,
MemberOffset field_offset,
ShadowFrameGetter* getter,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
};
// Dispatch implementation for primitive fields. template <typename T> bool FieldAccessor<T>::Dispatch(VarHandle::AccessMode access_mode,
ObjPtr<Object> obj,
MemberOffset field_offset,
ShadowFrameGetter* getter,
JValue* result) { switch (access_mode) { case VarHandle::AccessMode::kGet: {
GetAccessor<T> accessor(result);
FieldAccessViaAccessor<T>::Get(obj, field_offset, &accessor); break;
} case VarHandle::AccessMode::kSet: {
T new_value = ValueGetter<T>::Get(getter);
SetAccessor<T> accessor(new_value);
FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); break;
} case VarHandle::AccessMode::kGetAcquire: case VarHandle::AccessMode::kGetOpaque: case VarHandle::AccessMode::kGetVolatile: {
GetVolatileAccessor<T> accessor(result);
FieldAccessViaAccessor<T>::Get(obj, field_offset, &accessor); break;
} case VarHandle::AccessMode::kSetOpaque: case VarHandle::AccessMode::kSetRelease: case VarHandle::AccessMode::kSetVolatile: {
T new_value = ValueGetter<T>::Get(getter);
SetVolatileAccessor<T> accessor(new_value);
FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); break;
} case VarHandle::AccessMode::kCompareAndSet: {
T expected_value = ValueGetter<T>::Get(getter);
T desired_value = ValueGetter<T>::Get(getter);
CompareAndSetAccessor<T> accessor(expected_value, desired_value, result);
FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); break;
} case VarHandle::AccessMode::kCompareAndExchange: case VarHandle::AccessMode::kCompareAndExchangeAcquire: case VarHandle::AccessMode::kCompareAndExchangeRelease: {
T expected_value = ValueGetter<T>::Get(getter);
T desired_value = ValueGetter<T>::Get(getter);
CompareAndExchangeAccessor<T> accessor(expected_value, desired_value, result);
FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); break;
} case VarHandle::AccessMode::kWeakCompareAndSet: case VarHandle::AccessMode::kWeakCompareAndSetAcquire: case VarHandle::AccessMode::kWeakCompareAndSetPlain: case VarHandle::AccessMode::kWeakCompareAndSetRelease: {
T expected_value = ValueGetter<T>::Get(getter);
T desired_value = ValueGetter<T>::Get(getter);
WeakCompareAndSetAccessor<T> accessor(expected_value, desired_value, result);
FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); break;
} case VarHandle::AccessMode::kGetAndSet: case VarHandle::AccessMode::kGetAndSetAcquire: case VarHandle::AccessMode::kGetAndSetRelease: {
T new_value = ValueGetter<T>::Get(getter);
GetAndSetAccessor<T> accessor(new_value, result);
FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); break;
} case VarHandle::AccessMode::kGetAndAdd: case VarHandle::AccessMode::kGetAndAddAcquire: case VarHandle::AccessMode::kGetAndAddRelease: {
T value = ValueGetter<T>::Get(getter);
GetAndAddAccessor<T> accessor(value, result);
FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); break;
} case VarHandle::AccessMode::kGetAndBitwiseOr: case VarHandle::AccessMode::kGetAndBitwiseOrAcquire: case VarHandle::AccessMode::kGetAndBitwiseOrRelease: {
T value = ValueGetter<T>::Get(getter);
GetAndBitwiseOrAccessor<T> accessor(value, result);
FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); break;
} case VarHandle::AccessMode::kGetAndBitwiseAnd: case VarHandle::AccessMode::kGetAndBitwiseAndAcquire: case VarHandle::AccessMode::kGetAndBitwiseAndRelease: {
T value = ValueGetter<T>::Get(getter);
GetAndBitwiseAndAccessor<T> accessor(value, result);
FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); break;
} case VarHandle::AccessMode::kGetAndBitwiseXor: case VarHandle::AccessMode::kGetAndBitwiseXorAcquire: case VarHandle::AccessMode::kGetAndBitwiseXorRelease: {
T value = ValueGetter<T>::Get(getter);
GetAndBitwiseXorAccessor<T> accessor(value, result);
FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); break;
}
} returntrue;
}
// Dispatch implementation for reference fields. template <> bool FieldAccessor<ObjPtr<Object>>::Dispatch(VarHandle::AccessMode access_mode,
ObjPtr<Object> obj,
MemberOffset field_offset,
ShadowFrameGetter* getter,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) { // To keep things simple, use the minimum strongest existing // field accessor for Object fields. This may be the most // straightforward strategy in general for the interpreter. switch (access_mode) { case VarHandle::AccessMode::kGet: {
StoreResult(obj->GetFieldObject<Object>(field_offset), result); break;
} case VarHandle::AccessMode::kSet: {
ObjPtr<Object> new_value = ValueGetter<ObjPtr<Object>>::Get(getter); if (Runtime::Current()->IsActiveTransaction()) {
obj->SetFieldObject<kTransactionActive>(field_offset, new_value);
} else {
obj->SetFieldObject<kTransactionInactive>(field_offset, new_value);
} break;
} case VarHandle::AccessMode::kGetAcquire: case VarHandle::AccessMode::kGetOpaque: case VarHandle::AccessMode::kGetVolatile: {
StoreResult(obj->GetFieldObjectVolatile<Object>(field_offset), result); break;
} case VarHandle::AccessMode::kSetOpaque: case VarHandle::AccessMode::kSetRelease: case VarHandle::AccessMode::kSetVolatile: {
ObjPtr<Object> new_value = ValueGetter<ObjPtr<Object>>::Get(getter); if (Runtime::Current()->IsActiveTransaction()) {
obj->SetFieldObjectVolatile<kTransactionActive>(field_offset, new_value);
} else {
obj->SetFieldObjectVolatile<kTransactionInactive>(field_offset, new_value);
} break;
} case VarHandle::AccessMode::kCompareAndSet: {
ReadBarrierForVarHandleAccess(obj, field_offset);
ObjPtr<Object> expected_value = ValueGetter<ObjPtr<Object>>::Get(getter);
ObjPtr<Object> desired_value = ValueGetter<ObjPtr<Object>>::Get(getter); bool cas_result; if (Runtime::Current()->IsActiveTransaction()) {
cas_result = obj->CasFieldObject<kTransactionActive>(field_offset,
expected_value,
desired_value,
CASMode::kStrong,
std::memory_order_seq_cst);
} else {
cas_result = obj->CasFieldObject<kTransactionInactive>(field_offset,
expected_value,
desired_value,
CASMode::kStrong,
std::memory_order_seq_cst);
}
StoreResult(static_cast<uint8_t>(cas_result), result); break;
} case VarHandle::AccessMode::kWeakCompareAndSet: case VarHandle::AccessMode::kWeakCompareAndSetAcquire: case VarHandle::AccessMode::kWeakCompareAndSetPlain: case VarHandle::AccessMode::kWeakCompareAndSetRelease: {
ReadBarrierForVarHandleAccess(obj, field_offset);
ObjPtr<Object> expected_value = ValueGetter<ObjPtr<Object>>::Get(getter);
ObjPtr<Object> desired_value = ValueGetter<ObjPtr<Object>>::Get(getter); bool cas_result; if (Runtime::Current()->IsActiveTransaction()) {
cas_result = obj->CasFieldObject<kTransactionActive>(field_offset,
expected_value,
desired_value,
CASMode::kWeak,
std::memory_order_seq_cst);
} else {
cas_result = obj->CasFieldObject<kTransactionInactive>(
field_offset,
expected_value,
desired_value,
CASMode::kWeak,
std::memory_order_seq_cst);
}
StoreResult(static_cast<uint8_t>(cas_result), result); break;
} case VarHandle::AccessMode::kCompareAndExchange: case VarHandle::AccessMode::kCompareAndExchangeAcquire: case VarHandle::AccessMode::kCompareAndExchangeRelease: {
ReadBarrierForVarHandleAccess(obj, field_offset);
ObjPtr<Object> expected_value = ValueGetter<ObjPtr<Object>>::Get(getter);
ObjPtr<Object> desired_value = ValueGetter<ObjPtr<Object>>::Get(getter);
ObjPtr<Object> witness_value; if (Runtime::Current()->IsActiveTransaction()) {
witness_value = obj->CompareAndExchangeFieldObject<kTransactionActive>(field_offset,
expected_value,
desired_value);
} else {
witness_value = obj->CompareAndExchangeFieldObject<kTransactionInactive>(field_offset,
expected_value,
desired_value);
}
StoreResult(witness_value, result); break;
} case VarHandle::AccessMode::kGetAndSet: case VarHandle::AccessMode::kGetAndSetAcquire: case VarHandle::AccessMode::kGetAndSetRelease: {
ReadBarrierForVarHandleAccess(obj, field_offset);
ObjPtr<Object> new_value = ValueGetter<ObjPtr<Object>>::Get(getter);
ObjPtr<Object> old_value; if (Runtime::Current()->IsActiveTransaction()) {
old_value = obj->ExchangeFieldObject<kTransactionActive>(field_offset, new_value);
} else {
old_value = obj->ExchangeFieldObject<kTransactionInactive>(field_offset, new_value);
}
StoreResult(old_value, result); break;
} case VarHandle::AccessMode::kGetAndAdd: case VarHandle::AccessMode::kGetAndAddAcquire: case VarHandle::AccessMode::kGetAndAddRelease: case VarHandle::AccessMode::kGetAndBitwiseOr: case VarHandle::AccessMode::kGetAndBitwiseOrAcquire: case VarHandle::AccessMode::kGetAndBitwiseOrRelease: case VarHandle::AccessMode::kGetAndBitwiseAnd: case VarHandle::AccessMode::kGetAndBitwiseAndAcquire: case VarHandle::AccessMode::kGetAndBitwiseAndRelease: case VarHandle::AccessMode::kGetAndBitwiseXor: case VarHandle::AccessMode::kGetAndBitwiseXorAcquire: case VarHandle::AccessMode::kGetAndBitwiseXorRelease: {
size_t index = static_cast<size_t>(access_mode); constchar* access_mode_name = kAccessorToAccessMode[index].method_name;
UnreachableAccessMode(access_mode_name, "Object");
}
} returntrue;
}
// Class for accessing primitive array elements. template <typename T> class PrimitiveArrayElementAccessor { public: static T* GetElementAddress(ObjPtr<Array> target_array, int target_element)
REQUIRES_SHARED(Locks::mutator_lock_) { auto primitive_array = ObjPtr<PrimitiveArray<T>>::DownCast(target_array);
DCHECK(primitive_array->CheckIsValidIndex(target_element)); return &primitive_array->GetData()[target_element];
}
staticbool Dispatch(VarHandle::AccessMode access_mode,
ObjPtr<Array> target_array, int target_element,
ShadowFrameGetter* getter,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
T* element_address = GetElementAddress(target_array, target_element); switch (access_mode) { case VarHandle::AccessMode::kGet: {
GetAccessor<T> accessor(result);
accessor.Access(element_address); break;
} case VarHandle::AccessMode::kSet: {
T new_value = ValueGetter<T>::Get(getter);
SetAccessor<T> accessor(new_value);
accessor.Access(element_address); break;
} case VarHandle::AccessMode::kGetAcquire: case VarHandle::AccessMode::kGetOpaque: case VarHandle::AccessMode::kGetVolatile: {
GetVolatileAccessor<T> accessor(result);
accessor.Access(element_address); break;
} case VarHandle::AccessMode::kSetOpaque: case VarHandle::AccessMode::kSetRelease: case VarHandle::AccessMode::kSetVolatile: {
T new_value = ValueGetter<T>::Get(getter);
SetVolatileAccessor<T> accessor(new_value);
accessor.Access(element_address); break;
} case VarHandle::AccessMode::kCompareAndSet: {
T expected_value = ValueGetter<T>::Get(getter);
T desired_value = ValueGetter<T>::Get(getter);
CompareAndSetAccessor<T> accessor(expected_value, desired_value, result);
accessor.Access(element_address); break;
} case VarHandle::AccessMode::kCompareAndExchange: case VarHandle::AccessMode::kCompareAndExchangeAcquire: case VarHandle::AccessMode::kCompareAndExchangeRelease: {
T expected_value = ValueGetter<T>::Get(getter);
T desired_value = ValueGetter<T>::Get(getter);
CompareAndExchangeAccessor<T> accessor(expected_value, desired_value, result);
accessor.Access(element_address); break;
} case VarHandle::AccessMode::kWeakCompareAndSet: case VarHandle::AccessMode::kWeakCompareAndSetAcquire: case VarHandle::AccessMode::kWeakCompareAndSetPlain: case VarHandle::AccessMode::kWeakCompareAndSetRelease: {
T expected_value = ValueGetter<T>::Get(getter);
T desired_value = ValueGetter<T>::Get(getter);
WeakCompareAndSetAccessor<T> accessor(expected_value, desired_value, result);
accessor.Access(element_address); break;
} case VarHandle::AccessMode::kGetAndSet: case VarHandle::AccessMode::kGetAndSetAcquire: case VarHandle::AccessMode::kGetAndSetRelease: {
T new_value = ValueGetter<T>::Get(getter);
GetAndSetAccessor<T> accessor(new_value, result);
accessor.Access(element_address); break;
} case VarHandle::AccessMode::kGetAndAdd: case VarHandle::AccessMode::kGetAndAddAcquire: case VarHandle::AccessMode::kGetAndAddRelease: {
T value = ValueGetter<T>::Get(getter);
GetAndAddAccessor<T> accessor(value, result);
accessor.Access(element_address); break;
} case VarHandle::AccessMode::kGetAndBitwiseOr: case VarHandle::AccessMode::kGetAndBitwiseOrAcquire: case VarHandle::AccessMode::kGetAndBitwiseOrRelease: {
T value = ValueGetter<T>::Get(getter);
GetAndBitwiseOrAccessor<T> accessor(value, result);
accessor.Access(element_address); break;
} case VarHandle::AccessMode::kGetAndBitwiseAnd: case VarHandle::AccessMode::kGetAndBitwiseAndAcquire: case VarHandle::AccessMode::kGetAndBitwiseAndRelease: {
T value = ValueGetter<T>::Get(getter);
GetAndBitwiseAndAccessor<T> accessor(value, result);
accessor.Access(element_address); break;
} case VarHandle::AccessMode::kGetAndBitwiseXor: case VarHandle::AccessMode::kGetAndBitwiseXorAcquire: case VarHandle::AccessMode::kGetAndBitwiseXorRelease: {
T value = ValueGetter<T>::Get(getter);
GetAndBitwiseXorAccessor<T> accessor(value, result);
accessor.Access(element_address); break;
}
} returntrue;
}
};
// Check return type first.
ObjPtr<Class> vh_rtype = GetReturnType(access_mode_template, var_type); if (mt_rtype->GetPrimitiveType() != Primitive::Type::kPrimVoid &&
!mt_rtype->IsAssignableFrom(vh_rtype)) { // Call-site is an expression (expects a return value) and the value returned by the accessor // is not assignable to the expected return type. if (!IsReturnTypeConvertible(vh_rtype, mt_rtype)) { return MatchKind::kNone;
}
match = MatchKind::kWithConversions;
}
// Check the number of parameters matches.
ObjPtr<Class> vh_ptypes[kMaxAccessorParameters]; const int32_t vh_ptypes_count = BuildParameterArray(vh_ptypes,
access_mode_template,
var_type,
var_handle->GetCoordinateType0(),
var_handle->GetCoordinateType1()); auto mt_ptypes = MethodType::GetPTypes(method_type); if (vh_ptypes_count != mt_ptypes.GetLength()) { return MatchKind::kNone;
}
// Check the parameter types are compatible. for (int32_t i = 0; i < vh_ptypes_count; ++i) { if (vh_ptypes[i]->IsAssignableFrom(mt_ptypes.Get(i))) { continue;
} if (mt_ptypes.Get(i) == void_type && !vh_ptypes[i]->IsPrimitive()) { // The expected parameter is a reference and the parameter type from the call site is j.l.Void // which means the value is null. It is always valid for a reference parameter to be null. continue;
} if (!IsParameterTypeConvertible(mt_ptypes.Get(i), vh_ptypes[i])) { return MatchKind::kNone;
}
match = MatchKind::kWithConversions;
} return match;
}
// Store return type in `method_type`.
method_type.SetRType(GetReturnType(access_mode_template, GetVarType()));
// Store parameter types in `method_type`.
ObjPtr<Class> ptypes_array[kMaxAccessorParameters];
int32_t ptypes_count = BuildParameterArray(ptypes_array,
access_mode_template,
GetVarType(),
GetCoordinateType0(),
GetCoordinateType1()); for (int32_t i = 0; i < ptypes_count; ++i) {
method_type.AddPType(ptypes_array[i]);
}
}
std::string VarHandle::PrettyDescriptorForAccessMode(AccessMode access_mode) { // Effect MethodType::PrettyDescriptor() without first creating a method type first.
std::ostringstream oss;
oss << '(';
bool VarHandle::GetAccessModeByMethodName(constchar* method_name, AccessMode* access_mode) { if (method_name == nullptr) { returnfalse;
} constauto kUnusedAccessMode = VarHandle::AccessMode::kGet; // arbitrary value.
VarHandleAccessorToAccessModeEntry target = { method_name, kUnusedAccessMode }; auto last = std::cend(kAccessorToAccessMode); auto it = std::lower_bound(std::cbegin(kAccessorToAccessMode),
last,
target,
VarHandleAccessorToAccessModeEntry::CompareName); if (it == last || strcmp(it->method_name, method_name) != 0) { returnfalse;
}
*access_mode = it->access_mode; returntrue;
}
// Look up the AccessModeTemplate for a given VarHandle // AccessMode. This simplifies finding the correct signature for a // VarHandle accessor method.
VarHandle::AccessModeTemplate VarHandle::GetAccessModeTemplate(VarHandle::AccessMode access_mode) { switch (access_mode) { case VarHandle::AccessMode::kGet: return AccessModeTemplate::kGet; case VarHandle::AccessMode::kSet: return AccessModeTemplate::kSet; case VarHandle::AccessMode::kGetVolatile: return AccessModeTemplate::kGet; case VarHandle::AccessMode::kSetVolatile: return AccessModeTemplate::kSet; case VarHandle::AccessMode::kGetAcquire: return AccessModeTemplate::kGet; case VarHandle::AccessMode::kSetRelease: return AccessModeTemplate::kSet; case VarHandle::AccessMode::kGetOpaque: return AccessModeTemplate::kGet; case VarHandle::AccessMode::kSetOpaque: return AccessModeTemplate::kSet; case VarHandle::AccessMode::kCompareAndSet: return AccessModeTemplate::kCompareAndSet; case VarHandle::AccessMode::kCompareAndExchange: return AccessModeTemplate::kCompareAndExchange; case VarHandle::AccessMode::kCompareAndExchangeAcquire: return AccessModeTemplate::kCompareAndExchange; case VarHandle::AccessMode::kCompareAndExchangeRelease: return AccessModeTemplate::kCompareAndExchange; case VarHandle::AccessMode::kWeakCompareAndSetPlain: return AccessModeTemplate::kCompareAndSet; case VarHandle::AccessMode::kWeakCompareAndSet: return AccessModeTemplate::kCompareAndSet; case VarHandle::AccessMode::kWeakCompareAndSetAcquire: return AccessModeTemplate::kCompareAndSet; case VarHandle::AccessMode::kWeakCompareAndSetRelease: return AccessModeTemplate::kCompareAndSet; case VarHandle::AccessMode::kGetAndSet: return AccessModeTemplate::kGetAndUpdate; case VarHandle::AccessMode::kGetAndSetAcquire: return AccessModeTemplate::kGetAndUpdate; case VarHandle::AccessMode::kGetAndSetRelease: return AccessModeTemplate::kGetAndUpdate; case VarHandle::AccessMode::kGetAndAdd: return AccessModeTemplate::kGetAndUpdate; case VarHandle::AccessMode::kGetAndAddAcquire: return AccessModeTemplate::kGetAndUpdate; case VarHandle::AccessMode::kGetAndAddRelease: return AccessModeTemplate::kGetAndUpdate; case VarHandle::AccessMode::kGetAndBitwiseOr: return AccessModeTemplate::kGetAndUpdate; case VarHandle::AccessMode::kGetAndBitwiseOrRelease: return AccessModeTemplate::kGetAndUpdate; case VarHandle::AccessMode::kGetAndBitwiseOrAcquire: return AccessModeTemplate::kGetAndUpdate; case VarHandle::AccessMode::kGetAndBitwiseAnd: return AccessModeTemplate::kGetAndUpdate; case VarHandle::AccessMode::kGetAndBitwiseAndRelease: return AccessModeTemplate::kGetAndUpdate; case VarHandle::AccessMode::kGetAndBitwiseAndAcquire: return AccessModeTemplate::kGetAndUpdate; case VarHandle::AccessMode::kGetAndBitwiseXor: return AccessModeTemplate::kGetAndUpdate; case VarHandle::AccessMode::kGetAndBitwiseXorRelease: return AccessModeTemplate::kGetAndUpdate; case VarHandle::AccessMode::kGetAndBitwiseXorAcquire: return AccessModeTemplate::kGetAndUpdate;
}
}
int32_t VarHandle::GetNumberOfVarTypeParameters(AccessModeTemplate access_mode_template) { switch (access_mode_template) { case AccessModeTemplate::kGet: return0; case AccessModeTemplate::kSet: case AccessModeTemplate::kGetAndUpdate: return1; case AccessModeTemplate::kCompareAndSet: case AccessModeTemplate::kCompareAndExchange: return2;
}
}
const MemberOffset offset = field->GetOffset(); const Primitive::Type primitive_type = GetVarType()->GetPrimitiveType(); switch (primitive_type) { case Primitive::Type::kPrimNot: return FieldAccessor<ObjPtr<Object>>::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimBoolean: return FieldAccessor<uint8_t>::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimByte: return FieldAccessor<int8_t>::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimChar: return FieldAccessor<uint16_t>::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimShort: return FieldAccessor<int16_t>::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimInt: return FieldAccessor<int32_t>::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimFloat: return FieldAccessor<float>::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimLong: return FieldAccessor<int64_t>::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimDouble: return FieldAccessor<double>::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimVoid: break;
}
LOG(FATAL) << "Unreachable: Unexpected primitive " << primitive_type;
UNREACHABLE();
}
bool ArrayElementVarHandle::CheckArrayStore(AccessMode access_mode,
ShadowFrameGetter getter,
ObjPtr<ObjectArray<Object>> array) { // This method checks the element being inserted into the array is correctly assignable. // NB This method assumes it is called from `ArrayElementVarHandle::Access()` and `getter` // has already consumed the array and index arguments.
ObjPtr<Object> new_element; switch (GetAccessModeTemplate(access_mode)) { case AccessModeTemplate::kGet: returntrue; // Not a store. case AccessModeTemplate::kCompareAndExchange: case AccessModeTemplate::kCompareAndSet:
getter.GetReference(); // Skip the comperand.
new_element = getter.GetReference(); break; case AccessModeTemplate::kGetAndUpdate: case AccessModeTemplate::kSet:
new_element = getter.GetReference(); break;
} return array->CheckAssignable(new_element);
}
// The target array is the first co-ordinate type preceeding var type arguments.
ObjPtr<Object> raw_array(getter.GetReference()); if (raw_array == nullptr) {
ThrowNullPointerExceptionForCoordinate(); returnfalse;
}
// The target array element is the second co-ordinate type preceeding var type arguments. constint target_element = getter.Get(); if (!target_array->CheckIsValidIndex(target_element)) {
DCHECK(Thread::Current()->IsExceptionPending()); returnfalse;
}
// The byte array is the first co-ordinate type preceeding var type arguments.
ObjPtr<Object> raw_byte_array(getter.GetReference()); if (raw_byte_array == nullptr) {
ThrowNullPointerExceptionForCoordinate(); returnfalse;
}
int8_t* const data = byte_array->GetData(); bool byte_swap = !GetNativeByteOrder(); switch (primitive_type) { case Primitive::Type::kPrimNot: case Primitive::kPrimBoolean: case Primitive::kPrimByte: case Primitive::kPrimVoid: // These are not supported for byte array views and not instantiable. break; case Primitive::kPrimChar: return ByteArrayViewAccessor<uint16_t>::Dispatch(access_mode,
data,
data_offset,
byte_swap,
&getter,
result); case Primitive::kPrimShort: return ByteArrayViewAccessor<int16_t>::Dispatch(access_mode,
data,
data_offset,
byte_swap,
&getter,
result); case Primitive::kPrimInt: return ByteArrayViewAccessor<int32_t>::Dispatch(access_mode,
data,
data_offset,
byte_swap,
&getter,
result); case Primitive::kPrimFloat: // Treated as a bitwise representation. See javadoc comments for // java.lang.invoke.MethodHandles.byteArrayViewVarHandle(). return ByteArrayViewAccessor<int32_t>::Dispatch(access_mode,
data,
data_offset,
byte_swap,
&getter,
result); case Primitive::kPrimLong: return ByteArrayViewAccessor<int64_t>::Dispatch(access_mode,
data,
data_offset,
byte_swap,
&getter,
result); case Primitive::kPrimDouble: // Treated as a bitwise representation. See javadoc comments for // java.lang.invoke.MethodHandles.byteArrayViewVarHandle(). return ByteArrayViewAccessor<int64_t>::Dispatch(access_mode,
data,
data_offset,
byte_swap,
&getter,
result);
}
LOG(FATAL) << "Unreachable: Unexpected primitive " << primitive_type;
UNREACHABLE();
}
// The byte buffer is the first co-ordinate argument preceeding var type arguments.
ObjPtr<Object> byte_buffer(getter.GetReference()); if (byte_buffer == nullptr) {
ThrowNullPointerExceptionForCoordinate(); returnfalse;
}
// The byte index for access is the second co-ordinate // argument. This is relative to the offset field of the ByteBuffer. const int32_t byte_index = getter.Get();
// Check access_mode is compatible with ByteBuffer's read-only property. bool is_read_only = byte_buffer->GetFieldBoolean(
WellKnownClasses::java_nio_ByteBuffer_isReadOnly->GetOffset()); if (is_read_only && !IsReadOnlyAccessMode(access_mode)) {
ThrowReadOnlyBufferException(); returnfalse;
}
// The native_address is only set for ByteBuffer instances backed by native memory. const int64_t native_address =
byte_buffer->GetField64(WellKnownClasses::java_nio_Buffer_address->GetOffset());
// Determine offset and limit for accesses.
int32_t byte_buffer_offset; if (native_address == 0L) { // Accessing a heap allocated byte buffer.
byte_buffer_offset = byte_buffer->GetField32(
WellKnownClasses::java_nio_ByteBuffer_offset->GetOffset());
} else { // Accessing direct memory.
byte_buffer_offset = 0;
} const int32_t byte_buffer_limit =
byte_buffer->GetField32(WellKnownClasses::java_nio_Buffer_limit->GetOffset()); const int32_t byte_buffer_length = byte_buffer_offset + byte_buffer_limit;
int8_t* data; if (native_address == 0) {
ObjPtr<ByteArray> heap_byte_array = byte_buffer->GetFieldObject<ByteArray>(
WellKnownClasses::java_nio_ByteBuffer_hb->GetOffset());
data = heap_byte_array->GetData();
} else {
data = reinterpret_cast<int8_t*>(native_address);
}
bool byte_swap = !GetNativeByteOrder(); switch (primitive_type) { case Primitive::kPrimChar: return ByteArrayViewAccessor<uint16_t>::Dispatch(access_mode,
data,
checked_offset32,
byte_swap,
&getter,
result); case Primitive::kPrimShort: return ByteArrayViewAccessor<int16_t>::Dispatch(access_mode,
data,
checked_offset32,
byte_swap,
&getter,
result); case Primitive::kPrimInt: return ByteArrayViewAccessor<int32_t>::Dispatch(access_mode,
data,
checked_offset32,
byte_swap,
&getter,
result); case Primitive::kPrimFloat: // Treated as a bitwise representation. See javadoc comments for // java.lang.invoke.MethodHandles.byteArrayViewVarHandle(). return ByteArrayViewAccessor<int32_t>::Dispatch(access_mode,
data,
checked_offset32,
byte_swap,
&getter,
result); case Primitive::kPrimLong: return ByteArrayViewAccessor<int64_t>::Dispatch(access_mode,
data,
checked_offset32,
byte_swap,
&getter,
result); case Primitive::kPrimDouble: // Treated as a bitwise representation. See javadoc comments for // java.lang.invoke.MethodHandles.byteArrayViewVarHandle(). return ByteArrayViewAccessor<int64_t>::Dispatch(access_mode,
data,
checked_offset32,
byte_swap,
&getter,
result); case Primitive::Type::kPrimNot: case Primitive::kPrimBoolean: case Primitive::kPrimByte: case Primitive::kPrimVoid: // These are not supported for byte array views and not instantiable. break;
}
LOG(FATAL) << "Unreachable: Unexpected primitive " << primitive_type;
UNREACHABLE();
}
// The MemorySegment is the first coordinate argument.
ObjPtr<Object> memory_segment(getter.GetReference()); if (memory_segment == nullptr) {
ThrowNullPointerExceptionForCoordinate(); returnfalse;
}
// Check if MemorySegment is NativeMemorySegment // since it is the only supported type at the moment
DCHECK(memory_segment->InstanceOf(
WellKnownClasses::jdk_internal_foreign_NativeMemorySegmentImpl.Get()));
// The byte offset is the second coordinate argument. const int64_t byte_offset = getter.GetLong();
// Check access mode is compatible with MemorySegment's read-only property. bool is_read_only = memory_segment->GetFieldBoolean(
WellKnownClasses::jdk_internal_foreign_AbstractMemorySegmentImpl_readOnly->GetOffset()); if (is_read_only && !IsReadOnlyAccessMode(access_mode)) {
ThrowIllegalArgumentException("Memory segment is read-only"); returnfalse;
}
int8_t* data = reinterpret_cast<int8_t*>(native_address);
int64_t byte_alignment = GetByteAlignment();
if (((native_address + byte_offset) & (byte_alignment - 1)) != 0) {
ThrowIllegalArgumentException(
std::format( "Target offset {} is incompatible with alignment constraint {} for segment 0x{:x}",
byte_offset,
byte_alignment,
native_address)
.c_str()); returnfalse;
}
const int64_t checked_offset64 = byte_offset;
bool byte_swap = !GetNativeByteOrder(); switch (primitive_type) { case Primitive::kPrimInt: return ByteArrayViewAccessor<int32_t>::Dispatch(
access_mode, data, checked_offset64, byte_swap, &getter, result); // TODO: b/446845636 - Support for these types will be added later case Primitive::kPrimBoolean: case Primitive::kPrimByte: case Primitive::kPrimChar: case Primitive::kPrimShort: case Primitive::kPrimFloat: case Primitive::kPrimLong: case Primitive::kPrimDouble: case Primitive::Type::kPrimNot: case Primitive::kPrimVoid: // These are not supported for memory segment views and not instantiable. break;
}
LOG(FATAL) << "Unreachable: Unexpected primitive " << primitive_type;
UNREACHABLE();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.