/* * Copyright (C) 2017 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. */ #include "var_handle.h" #include "array-inl.h" #include "art_field-inl.h" #include "base/casts.h" #include "class-inl.h" #include "class_linker.h" #include "class_root-inl.h" #include "intrinsics_enum.h" #include "jni/jni_internal.h" #include "jvalue-inl.h" #include "method_handles-inl.h" #include "method_type-inl.h" #include "object_array-alloc-inl.h" #include "obj_ptr-inl.h" #include "well_known_classes.h" namespace art { namespace mirror { static constexpr bool kTransactionActive = true; static constexpr bool kTransactionInactive = !kTransactionActive; namespace { struct VarHandleAccessorToAccessModeEntry { const char* method_name; VarHandle::AccessMode access_mode; // Binary predicate function for finding access_mode by // method_name. The access_mode field is ignored. static bool 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 coordinateType0, ObjPtr 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 relative_index, int32_t start, int32_t limit) REQUIRES_SHARED(Locks::mutator_lock_) { int64_t index = start + relative_index; int64_t max_index = limit - Primitive::ComponentSize(type); if (index < start || index > max_index) { ThrowIndexOutOfBoundsException(index, limit - start); return false; } return true; } bool CheckElementIndex(Primitive::Type type, int32_t index, int32_t range_limit) REQUIRES_SHARED(Locks::mutator_lock_) { return CheckElementIndex(type, index, 0, range_limit); } // 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 (¶meters)[VarHandle::kMaxAccessorParameters], VarHandle::AccessModeTemplate access_mode_template, ObjPtr varType, ObjPtr coordinateType0, ObjPtr 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 GetReturnType(VarHandle::AccessModeTemplate access_mode_template, ObjPtr 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. inline void ReadBarrierForVarHandleAccess(ObjPtr obj, MemberOffset field_offset) REQUIRES_SHARED(Locks::mutator_lock_) { if (kUseReadBarrier) { // 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(obj.Ptr()) + field_offset.SizeValue(); auto field_addr = reinterpret_cast*>(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( obj.Ptr(), MemberOffset(field_offset), field_addr); } } inline MemberOffset GetMemberOffset(jfieldID field_id) REQUIRES_SHARED(Locks::mutator_lock_) { ArtField* const field = jni::DecodeArtField(field_id); return field->GetOffset(); } // // Helper methods for storing results from atomic operations into // JValue instances. // inline void StoreResult(uint8_t value, JValue* result) { result->SetZ(value); } inline void StoreResult(int8_t value, JValue* result) { result->SetB(value); } inline void StoreResult(uint16_t value, JValue* result) { result->SetC(value); } inline void StoreResult(int16_t value, JValue* result) { result->SetS(value); } inline void StoreResult(int32_t value, JValue* result) { result->SetI(value); } inline void StoreResult(int64_t value, JValue* result) { result->SetJ(value); } inline void StoreResult(float value, JValue* result) { result->SetF(value); } inline void StoreResult(double value, JValue* result) { result->SetD(value); } inline void StoreResult(ObjPtr value, JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { result->SetL(value); } // // Helper class for byte-swapping value that has been stored in a JValue. // template class JValueByteSwapper final { public: static void ByteSwap(JValue* value); static void MaybeByteSwap(bool byte_swap, JValue* value) { if (byte_swap) { ByteSwap(value); } } }; template <> void JValueByteSwapper::ByteSwap(JValue* value) { value->SetC(BSWAP(value->GetC())); } template <> void JValueByteSwapper::ByteSwap(JValue* value) { value->SetS(BSWAP(value->GetS())); } template <> void JValueByteSwapper::ByteSwap(JValue* value) { value->SetI(BSWAP(value->GetI())); } template <> void JValueByteSwapper::ByteSwap(JValue* value) { value->SetJ(BSWAP(value->GetJ())); } // // Accessor implementations, shared across all VarHandle types. // template class AtomicGetAccessor : public Object::Accessor { public: explicit AtomicGetAccessor(JValue* result) : result_(result) {} void Access(T* addr) override { std::atomic* atom = reinterpret_cast*>(addr); StoreResult(atom->load(MO), result_); } private: JValue* result_; }; template class AtomicSetAccessor : public Object::Accessor { public: explicit AtomicSetAccessor(T new_value) : new_value_(new_value) {} void Access(T* addr) override { std::atomic* atom = reinterpret_cast*>(addr); atom->store(new_value_, MO); } private: T new_value_; }; template using GetAccessor = AtomicGetAccessor; template using SetAccessor = AtomicSetAccessor; template using GetVolatileAccessor = AtomicGetAccessor; template using SetVolatileAccessor = AtomicSetAccessor; template class AtomicStrongCompareAndSetAccessor : public Object::Accessor { public: AtomicStrongCompareAndSetAccessor(T expected_value, T desired_value, JValue* result) : expected_value_(expected_value), desired_value_(desired_value), result_(result) {} void Access(T* addr) override { std::atomic* atom = reinterpret_cast*>(addr); bool success = atom->compare_exchange_strong(expected_value_, desired_value_, MOS, MOF); StoreResult(success ? JNI_TRUE : JNI_FALSE, result_); } private: T expected_value_; T desired_value_; JValue* result_; }; template using CompareAndSetAccessor = AtomicStrongCompareAndSetAccessor; template class AtomicStrongCompareAndExchangeAccessor : public Object::Accessor { public: AtomicStrongCompareAndExchangeAccessor(T expected_value, T desired_value, JValue* result) : expected_value_(expected_value), desired_value_(desired_value), result_(result) {} void Access(T* addr) override { std::atomic* atom = reinterpret_cast*>(addr); atom->compare_exchange_strong(expected_value_, desired_value_, MOS, MOF); StoreResult(expected_value_, result_); } private: T expected_value_; T desired_value_; JValue* result_; }; template using CompareAndExchangeAccessor = AtomicStrongCompareAndExchangeAccessor; template class AtomicWeakCompareAndSetAccessor : public Object::Accessor { public: AtomicWeakCompareAndSetAccessor(T expected_value, T desired_value, JValue* result) : expected_value_(expected_value), desired_value_(desired_value), result_(result) {} void Access(T* addr) override { std::atomic* atom = reinterpret_cast*>(addr); bool success = atom->compare_exchange_weak(expected_value_, desired_value_, MOS, MOF); StoreResult(success ? JNI_TRUE : JNI_FALSE, result_); } private: T expected_value_; T desired_value_; JValue* result_; }; template using WeakCompareAndSetAccessor = AtomicWeakCompareAndSetAccessor; template class AtomicGetAndSetAccessor : public Object::Accessor { public: AtomicGetAndSetAccessor(T new_value, JValue* result) : new_value_(new_value), result_(result) {} void Access(T* addr) override { std::atomic* atom = reinterpret_cast*>(addr); T old_value = atom->exchange(new_value_, MO); StoreResult(old_value, result_); } private: T new_value_; JValue* result_; }; template using GetAndSetAccessor = AtomicGetAndSetAccessor; template class AtomicGetAndAddOperator { public: static T Apply(T* addr, T addend) { std::atomic* atom = reinterpret_cast*>(addr); return atom->fetch_add(addend, MO); } }; template class AtomicGetAndAddOperator { public: static T Apply(T* addr, T addend) { // c++11 does not have std::atomic::fetch_and_add for floating // point types, so we effect one with a compare and swap. std::atomic* atom = reinterpret_cast*>(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 class AtomicGetAndAddAccessor : public Object::Accessor { public: AtomicGetAndAddAccessor(T addend, JValue* result) : addend_(addend), result_(result) {} void Access(T* addr) override { constexpr bool kIsFloatingPoint = std::is_floating_point::value; T old_value = AtomicGetAndAddOperator::Apply(addr, addend_); StoreResult(old_value, result_); } private: T addend_; JValue* result_; }; template using GetAndAddAccessor = AtomicGetAndAddAccessor; // 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 class AtomicGetAndAddWithByteSwapAccessor : public Object::Accessor { public: AtomicGetAndAddWithByteSwapAccessor(T value, JValue* result) : value_(value), result_(result) {} void Access(T* addr) override { std::atomic* const atom = reinterpret_cast*>(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::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 using GetAndAddWithByteSwapAccessor = AtomicGetAndAddWithByteSwapAccessor; template class AtomicGetAndBitwiseOrAccessor : public Object::Accessor { public: AtomicGetAndBitwiseOrAccessor(T value, JValue* result) : value_(value), result_(result) {} void Access(T* addr) override { std::atomic* atom = reinterpret_cast*>(addr); T old_value = atom->fetch_or(value_, MO); StoreResult(old_value, result_); } private: T value_; JValue* result_; }; template using GetAndBitwiseOrAccessor = AtomicGetAndBitwiseOrAccessor; template class AtomicGetAndBitwiseAndAccessor : public Object::Accessor { public: AtomicGetAndBitwiseAndAccessor(T value, JValue* result) : value_(value), result_(result) {} void Access(T* addr) override { std::atomic* atom = reinterpret_cast*>(addr); T old_value = atom->fetch_and(value_, MO); StoreResult(old_value, result_); } private: T value_; JValue* result_; }; template using GetAndBitwiseAndAccessor = AtomicGetAndBitwiseAndAccessor; template class AtomicGetAndBitwiseXorAccessor : public Object::Accessor { public: AtomicGetAndBitwiseXorAccessor(T value, JValue* result) : value_(value), result_(result) {} void Access(T* addr) override { std::atomic* atom = reinterpret_cast*>(addr); T old_value = atom->fetch_xor(value_, MO); StoreResult(old_value, result_); } private: T value_; JValue* result_; }; template using GetAndBitwiseXorAccessor = AtomicGetAndBitwiseXorAccessor; // // Unreachable access modes. // NO_RETURN void UnreachableAccessMode(const char* access_mode, const char* type_name) { LOG(FATAL) << "Unreachable access mode :" << access_mode << " for type " << type_name; UNREACHABLE(); } #define UNREACHABLE_ACCESS_MODE(ACCESS_MODE, TYPE) \ template<> void ACCESS_MODE ## Accessor::Access(TYPE*) { \ UnreachableAccessMode(#ACCESS_MODE, #TYPE); \ } // 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 class TypeAdaptorAccessor : public Object::Accessor { public: explicit TypeAdaptorAccessor(Object::Accessor* inner_accessor) : inner_accessor_(inner_accessor) {} void Access(T* addr) override { static_assert(sizeof(T) == sizeof(U), "bad conversion"); inner_accessor_->Access(reinterpret_cast(addr)); } private: Object::Accessor* inner_accessor_; }; template class FieldAccessViaAccessor { public: using Accessor = Object::Accessor; // Apply an Accessor to get a field in an object. static void Get(ObjPtr 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. static void Update(ObjPtr obj, MemberOffset field_offset, Accessor* accessor) REQUIRES_SHARED(Locks::mutator_lock_); }; template <> inline void FieldAccessViaAccessor::Get(ObjPtr obj, MemberOffset field_offset, Accessor* accessor) REQUIRES_SHARED(Locks::mutator_lock_) { TypeAdaptorAccessor float_to_int_accessor(accessor); obj->GetPrimitiveFieldViaAccessor(field_offset, &float_to_int_accessor); } template <> inline void FieldAccessViaAccessor::Get(ObjPtr obj, MemberOffset field_offset, Accessor* accessor) REQUIRES_SHARED(Locks::mutator_lock_) { TypeAdaptorAccessor double_to_int_accessor(accessor); obj->GetPrimitiveFieldViaAccessor(field_offset, &double_to_int_accessor); } template <> void FieldAccessViaAccessor::Update(ObjPtr obj, MemberOffset field_offset, Accessor* accessor) REQUIRES_SHARED(Locks::mutator_lock_) { if (Runtime::Current()->IsActiveTransaction()) { obj->UpdateFieldBooleanViaAccessor(field_offset, accessor); } else { obj->UpdateFieldBooleanViaAccessor(field_offset, accessor); } } template <> void FieldAccessViaAccessor::Update(ObjPtr obj, MemberOffset field_offset, Accessor* accessor) REQUIRES_SHARED(Locks::mutator_lock_) { if (Runtime::Current()->IsActiveTransaction()) { obj->UpdateFieldByteViaAccessor(field_offset, accessor); } else { obj->UpdateFieldByteViaAccessor(field_offset, accessor); } } template <> void FieldAccessViaAccessor::Update(ObjPtr obj, MemberOffset field_offset, Accessor* accessor) REQUIRES_SHARED(Locks::mutator_lock_) { if (Runtime::Current()->IsActiveTransaction()) { obj->UpdateFieldCharViaAccessor(field_offset, accessor); } else { obj->UpdateFieldCharViaAccessor(field_offset, accessor); } } template <> void FieldAccessViaAccessor::Update(ObjPtr obj, MemberOffset field_offset, Accessor* accessor) REQUIRES_SHARED(Locks::mutator_lock_) { if (Runtime::Current()->IsActiveTransaction()) { obj->UpdateFieldShortViaAccessor(field_offset, accessor); } else { obj->UpdateFieldShortViaAccessor(field_offset, accessor); } } template <> void FieldAccessViaAccessor::Update(ObjPtr obj, MemberOffset field_offset, Accessor* accessor) REQUIRES_SHARED(Locks::mutator_lock_) { if (Runtime::Current()->IsActiveTransaction()) { obj->UpdateField32ViaAccessor(field_offset, accessor); } else { obj->UpdateField32ViaAccessor(field_offset, accessor); } } template <> void FieldAccessViaAccessor::Update(ObjPtr obj, MemberOffset field_offset, Accessor* accessor) REQUIRES_SHARED(Locks::mutator_lock_) { if (Runtime::Current()->IsActiveTransaction()) { obj->UpdateField64ViaAccessor(field_offset, accessor); } else { obj->UpdateField64ViaAccessor(field_offset, accessor); } } template <> void FieldAccessViaAccessor::Update(ObjPtr obj, MemberOffset field_offset, Accessor* accessor) REQUIRES_SHARED(Locks::mutator_lock_) { TypeAdaptorAccessor float_to_int_accessor(accessor); if (Runtime::Current()->IsActiveTransaction()) { obj->UpdateField32ViaAccessor(field_offset, &float_to_int_accessor); } else { obj->UpdateField32ViaAccessor(field_offset, &float_to_int_accessor); } } template <> void FieldAccessViaAccessor::Update(ObjPtr obj, MemberOffset field_offset, Accessor* accessor) REQUIRES_SHARED(Locks::mutator_lock_) { TypeAdaptorAccessor double_to_int_accessor(accessor); if (Runtime::Current()->IsActiveTransaction()) { obj->UpdateField64ViaAccessor(field_offset, &double_to_int_accessor); } else { obj->UpdateField64ViaAccessor(field_offset, &double_to_int_accessor); } } // Helper class that gets values from a shadow frame with appropriate type coercion. template 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(); return static_cast(raw_value); } }; template <> int64_t ValueGetter::Get(ShadowFrameGetter* getter) { return getter->GetLong(); } template <> float ValueGetter::Get(ShadowFrameGetter* getter) { uint32_t raw_value = getter->Get(); return *reinterpret_cast(&raw_value); } template <> double ValueGetter::Get(ShadowFrameGetter* getter) { int64_t raw_value = getter->GetLong(); return *reinterpret_cast(&raw_value); } template <> ObjPtr ValueGetter>::Get(ShadowFrameGetter* getter) { return getter->GetReference(); } // Class for accessing fields of Object instances template class FieldAccessor { public: static bool Dispatch(VarHandle::AccessMode access_mode, ObjPtr obj, MemberOffset field_offset, ShadowFrameGetter* getter, JValue* result) REQUIRES_SHARED(Locks::mutator_lock_); }; // Dispatch implementation for primitive fields. template bool FieldAccessor::Dispatch(VarHandle::AccessMode access_mode, ObjPtr obj, MemberOffset field_offset, ShadowFrameGetter* getter, JValue* result) { switch (access_mode) { case VarHandle::AccessMode::kGet: { GetAccessor accessor(result); FieldAccessViaAccessor::Get(obj, field_offset, &accessor); break; } case VarHandle::AccessMode::kSet: { T new_value = ValueGetter::Get(getter); SetAccessor accessor(new_value); FieldAccessViaAccessor::Update(obj, field_offset, &accessor); break; } case VarHandle::AccessMode::kGetAcquire: case VarHandle::AccessMode::kGetOpaque: case VarHandle::AccessMode::kGetVolatile: { GetVolatileAccessor accessor(result); FieldAccessViaAccessor::Get(obj, field_offset, &accessor); break; } case VarHandle::AccessMode::kSetOpaque: case VarHandle::AccessMode::kSetRelease: case VarHandle::AccessMode::kSetVolatile: { T new_value = ValueGetter::Get(getter); SetVolatileAccessor accessor(new_value); FieldAccessViaAccessor::Update(obj, field_offset, &accessor); break; } case VarHandle::AccessMode::kCompareAndSet: { T expected_value = ValueGetter::Get(getter); T desired_value = ValueGetter::Get(getter); CompareAndSetAccessor accessor(expected_value, desired_value, result); FieldAccessViaAccessor::Update(obj, field_offset, &accessor); break; } case VarHandle::AccessMode::kCompareAndExchange: case VarHandle::AccessMode::kCompareAndExchangeAcquire: case VarHandle::AccessMode::kCompareAndExchangeRelease: { T expected_value = ValueGetter::Get(getter); T desired_value = ValueGetter::Get(getter); CompareAndExchangeAccessor accessor(expected_value, desired_value, result); FieldAccessViaAccessor::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::Get(getter); T desired_value = ValueGetter::Get(getter); WeakCompareAndSetAccessor accessor(expected_value, desired_value, result); FieldAccessViaAccessor::Update(obj, field_offset, &accessor); break; } case VarHandle::AccessMode::kGetAndSet: case VarHandle::AccessMode::kGetAndSetAcquire: case VarHandle::AccessMode::kGetAndSetRelease: { T new_value = ValueGetter::Get(getter); GetAndSetAccessor accessor(new_value, result); FieldAccessViaAccessor::Update(obj, field_offset, &accessor); break; } case VarHandle::AccessMode::kGetAndAdd: case VarHandle::AccessMode::kGetAndAddAcquire: case VarHandle::AccessMode::kGetAndAddRelease: { T value = ValueGetter::Get(getter); GetAndAddAccessor accessor(value, result); FieldAccessViaAccessor::Update(obj, field_offset, &accessor); break; } case VarHandle::AccessMode::kGetAndBitwiseOr: case VarHandle::AccessMode::kGetAndBitwiseOrAcquire: case VarHandle::AccessMode::kGetAndBitwiseOrRelease: { T value = ValueGetter::Get(getter); GetAndBitwiseOrAccessor accessor(value, result); FieldAccessViaAccessor::Update(obj, field_offset, &accessor); break; } case VarHandle::AccessMode::kGetAndBitwiseAnd: case VarHandle::AccessMode::kGetAndBitwiseAndAcquire: case VarHandle::AccessMode::kGetAndBitwiseAndRelease: { T value = ValueGetter::Get(getter); GetAndBitwiseAndAccessor accessor(value, result); FieldAccessViaAccessor::Update(obj, field_offset, &accessor); break; } case VarHandle::AccessMode::kGetAndBitwiseXor: case VarHandle::AccessMode::kGetAndBitwiseXorAcquire: case VarHandle::AccessMode::kGetAndBitwiseXorRelease: { T value = ValueGetter::Get(getter); GetAndBitwiseXorAccessor accessor(value, result); FieldAccessViaAccessor::Update(obj, field_offset, &accessor); break; } } return true; } // Dispatch implementation for reference fields. template <> bool FieldAccessor>::Dispatch(VarHandle::AccessMode access_mode, ObjPtr 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(field_offset), result); break; } case VarHandle::AccessMode::kSet: { ObjPtr new_value = ValueGetter>::Get(getter); if (Runtime::Current()->IsActiveTransaction()) { obj->SetFieldObject(field_offset, new_value); } else { obj->SetFieldObject(field_offset, new_value); } break; } case VarHandle::AccessMode::kGetAcquire: case VarHandle::AccessMode::kGetOpaque: case VarHandle::AccessMode::kGetVolatile: { StoreResult(obj->GetFieldObjectVolatile(field_offset), result); break; } case VarHandle::AccessMode::kSetOpaque: case VarHandle::AccessMode::kSetRelease: case VarHandle::AccessMode::kSetVolatile: { ObjPtr new_value = ValueGetter>::Get(getter); if (Runtime::Current()->IsActiveTransaction()) { obj->SetFieldObjectVolatile(field_offset, new_value); } else { obj->SetFieldObjectVolatile(field_offset, new_value); } break; } case VarHandle::AccessMode::kCompareAndSet: { ReadBarrierForVarHandleAccess(obj, field_offset); ObjPtr expected_value = ValueGetter>::Get(getter); ObjPtr desired_value = ValueGetter>::Get(getter); bool cas_result; if (Runtime::Current()->IsActiveTransaction()) { cas_result = obj->CasFieldObject(field_offset, expected_value, desired_value, CASMode::kStrong, std::memory_order_seq_cst); } else { cas_result = obj->CasFieldObject(field_offset, expected_value, desired_value, CASMode::kStrong, std::memory_order_seq_cst); } StoreResult(static_cast(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 expected_value = ValueGetter>::Get(getter); ObjPtr desired_value = ValueGetter>::Get(getter); bool cas_result; if (Runtime::Current()->IsActiveTransaction()) { cas_result = obj->CasFieldObject(field_offset, expected_value, desired_value, CASMode::kWeak, std::memory_order_seq_cst); } else { cas_result = obj->CasFieldObject( field_offset, expected_value, desired_value, CASMode::kWeak, std::memory_order_seq_cst); } StoreResult(static_cast(cas_result), result); break; } case VarHandle::AccessMode::kCompareAndExchange: case VarHandle::AccessMode::kCompareAndExchangeAcquire: case VarHandle::AccessMode::kCompareAndExchangeRelease: { ReadBarrierForVarHandleAccess(obj, field_offset); ObjPtr expected_value = ValueGetter>::Get(getter); ObjPtr desired_value = ValueGetter>::Get(getter); ObjPtr witness_value; if (Runtime::Current()->IsActiveTransaction()) { witness_value = obj->CompareAndExchangeFieldObject(field_offset, expected_value, desired_value); } else { witness_value = obj->CompareAndExchangeFieldObject(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 new_value = ValueGetter>::Get(getter); ObjPtr old_value; if (Runtime::Current()->IsActiveTransaction()) { old_value = obj->ExchangeFieldObject(field_offset, new_value); } else { old_value = obj->ExchangeFieldObject(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(access_mode); const char* access_mode_name = kAccessorToAccessMode[index].method_name; UnreachableAccessMode(access_mode_name, "Object"); } } return true; } // Class for accessing primitive array elements. template class PrimitiveArrayElementAccessor { public: static T* GetElementAddress(ObjPtr target_array, int target_element) REQUIRES_SHARED(Locks::mutator_lock_) { auto primitive_array = ObjPtr>::DownCast(target_array); DCHECK(primitive_array->CheckIsValidIndex(target_element)); return &primitive_array->GetData()[target_element]; } static bool Dispatch(VarHandle::AccessMode access_mode, ObjPtr 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 accessor(result); accessor.Access(element_address); break; } case VarHandle::AccessMode::kSet: { T new_value = ValueGetter::Get(getter); SetAccessor accessor(new_value); accessor.Access(element_address); break; } case VarHandle::AccessMode::kGetAcquire: case VarHandle::AccessMode::kGetOpaque: case VarHandle::AccessMode::kGetVolatile: { GetVolatileAccessor accessor(result); accessor.Access(element_address); break; } case VarHandle::AccessMode::kSetOpaque: case VarHandle::AccessMode::kSetRelease: case VarHandle::AccessMode::kSetVolatile: { T new_value = ValueGetter::Get(getter); SetVolatileAccessor accessor(new_value); accessor.Access(element_address); break; } case VarHandle::AccessMode::kCompareAndSet: { T expected_value = ValueGetter::Get(getter); T desired_value = ValueGetter::Get(getter); CompareAndSetAccessor 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::Get(getter); T desired_value = ValueGetter::Get(getter); CompareAndExchangeAccessor 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::Get(getter); T desired_value = ValueGetter::Get(getter); WeakCompareAndSetAccessor 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::Get(getter); GetAndSetAccessor accessor(new_value, result); accessor.Access(element_address); break; } case VarHandle::AccessMode::kGetAndAdd: case VarHandle::AccessMode::kGetAndAddAcquire: case VarHandle::AccessMode::kGetAndAddRelease: { T value = ValueGetter::Get(getter); GetAndAddAccessor accessor(value, result); accessor.Access(element_address); break; } case VarHandle::AccessMode::kGetAndBitwiseOr: case VarHandle::AccessMode::kGetAndBitwiseOrAcquire: case VarHandle::AccessMode::kGetAndBitwiseOrRelease: { T value = ValueGetter::Get(getter); GetAndBitwiseOrAccessor accessor(value, result); accessor.Access(element_address); break; } case VarHandle::AccessMode::kGetAndBitwiseAnd: case VarHandle::AccessMode::kGetAndBitwiseAndAcquire: case VarHandle::AccessMode::kGetAndBitwiseAndRelease: { T value = ValueGetter::Get(getter); GetAndBitwiseAndAccessor accessor(value, result); accessor.Access(element_address); break; } case VarHandle::AccessMode::kGetAndBitwiseXor: case VarHandle::AccessMode::kGetAndBitwiseXorAcquire: case VarHandle::AccessMode::kGetAndBitwiseXorRelease: { T value = ValueGetter::Get(getter); GetAndBitwiseXorAccessor accessor(value, result); accessor.Access(element_address); break; } } return true; } }; // Class for accessing primitive array elements. template class ByteArrayViewAccessor { public: static inline bool IsAccessAligned(int8_t* data, int data_index) { static_assert(IsPowerOfTwo(sizeof(T)), "unexpected size"); static_assert(std::is_arithmetic::value, "unexpected type"); uintptr_t alignment_mask = sizeof(T) - 1; uintptr_t address = reinterpret_cast(data + data_index); return (address & alignment_mask) == 0; } static inline void MaybeByteSwap(bool byte_swap, T* const value) { if (byte_swap) { *value = BSWAP(*value); } } static bool Dispatch(const VarHandle::AccessMode access_mode, int8_t* const data, const int data_index, const bool byte_swap, ShadowFrameGetter* const getter, JValue* const result) REQUIRES_SHARED(Locks::mutator_lock_) { const bool is_aligned = IsAccessAligned(data, data_index); if (!is_aligned) { switch (access_mode) { case VarHandle::AccessMode::kGet: { T value; memcpy(&value, data + data_index, sizeof(T)); MaybeByteSwap(byte_swap, &value); StoreResult(value, result); return true; } case VarHandle::AccessMode::kSet: { T new_value = ValueGetter::Get(getter); MaybeByteSwap(byte_swap, &new_value); memcpy(data + data_index, &new_value, sizeof(T)); return true; } default: // No other access modes support unaligned access. ThrowIllegalStateException("Unaligned access not supported"); return false; } } T* const element_address = reinterpret_cast(data + data_index); CHECK(IsAccessAligned(reinterpret_cast(element_address), 0)); switch (access_mode) { case VarHandle::AccessMode::kGet: { GetAccessor accessor(result); accessor.Access(element_address); JValueByteSwapper::MaybeByteSwap(byte_swap, result); break; } case VarHandle::AccessMode::kSet: { T new_value = ValueGetter::Get(getter); MaybeByteSwap(byte_swap, &new_value); SetAccessor accessor(new_value); accessor.Access(element_address); break; } case VarHandle::AccessMode::kGetAcquire: case VarHandle::AccessMode::kGetOpaque: case VarHandle::AccessMode::kGetVolatile: { GetVolatileAccessor accessor(result); accessor.Access(element_address); JValueByteSwapper::MaybeByteSwap(byte_swap, result); break; } case VarHandle::AccessMode::kSetOpaque: case VarHandle::AccessMode::kSetRelease: case VarHandle::AccessMode::kSetVolatile: { T new_value = ValueGetter::Get(getter); MaybeByteSwap(byte_swap, &new_value); SetVolatileAccessor accessor(new_value); accessor.Access(element_address); break; } case VarHandle::AccessMode::kCompareAndSet: { T expected_value = ValueGetter::Get(getter); T desired_value = ValueGetter::Get(getter); MaybeByteSwap(byte_swap, &expected_value); MaybeByteSwap(byte_swap, &desired_value); CompareAndSetAccessor 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::Get(getter); T desired_value = ValueGetter::Get(getter); MaybeByteSwap(byte_swap, &expected_value); MaybeByteSwap(byte_swap, &desired_value); CompareAndExchangeAccessor accessor(expected_value, desired_value, result); accessor.Access(element_address); JValueByteSwapper::MaybeByteSwap(byte_swap, result); break; } case VarHandle::AccessMode::kWeakCompareAndSet: case VarHandle::AccessMode::kWeakCompareAndSetAcquire: case VarHandle::AccessMode::kWeakCompareAndSetPlain: case VarHandle::AccessMode::kWeakCompareAndSetRelease: { T expected_value = ValueGetter::Get(getter); T desired_value = ValueGetter::Get(getter); MaybeByteSwap(byte_swap, &expected_value); MaybeByteSwap(byte_swap, &desired_value); WeakCompareAndSetAccessor 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::Get(getter); MaybeByteSwap(byte_swap, &new_value); GetAndSetAccessor accessor(new_value, result); accessor.Access(element_address); JValueByteSwapper::MaybeByteSwap(byte_swap, result); break; } case VarHandle::AccessMode::kGetAndAdd: case VarHandle::AccessMode::kGetAndAddAcquire: case VarHandle::AccessMode::kGetAndAddRelease: { T value = ValueGetter::Get(getter); if (byte_swap) { GetAndAddWithByteSwapAccessor accessor(value, result); accessor.Access(element_address); } else { GetAndAddAccessor accessor(value, result); accessor.Access(element_address); } break; } case VarHandle::AccessMode::kGetAndBitwiseOr: case VarHandle::AccessMode::kGetAndBitwiseOrAcquire: case VarHandle::AccessMode::kGetAndBitwiseOrRelease: { T value = ValueGetter::Get(getter); MaybeByteSwap(byte_swap, &value); GetAndBitwiseOrAccessor accessor(value, result); accessor.Access(element_address); JValueByteSwapper::MaybeByteSwap(byte_swap, result); break; } case VarHandle::AccessMode::kGetAndBitwiseAnd: case VarHandle::AccessMode::kGetAndBitwiseAndAcquire: case VarHandle::AccessMode::kGetAndBitwiseAndRelease: { T value = ValueGetter::Get(getter); MaybeByteSwap(byte_swap, &value); GetAndBitwiseAndAccessor accessor(value, result); accessor.Access(element_address); JValueByteSwapper::MaybeByteSwap(byte_swap, result); break; } case VarHandle::AccessMode::kGetAndBitwiseXor: case VarHandle::AccessMode::kGetAndBitwiseXorAcquire: case VarHandle::AccessMode::kGetAndBitwiseXorRelease: { T value = ValueGetter::Get(getter); MaybeByteSwap(byte_swap, &value); GetAndBitwiseXorAccessor accessor(value, result); accessor.Access(element_address); JValueByteSwapper::MaybeByteSwap(byte_swap, result); break; } } return true; } }; } // namespace ObjPtr VarHandle::GetVarType() { return GetFieldObject(VarTypeOffset()); } ObjPtr VarHandle::GetCoordinateType0() { return GetFieldObject(CoordinateType0Offset()); } ObjPtr VarHandle::GetCoordinateType1() { return GetFieldObject(CoordinateType1Offset()); } int32_t VarHandle::GetAccessModesBitMask() { return GetField32(AccessModesBitMaskOffset()); } VarHandle::MatchKind VarHandle::GetMethodTypeMatchForAccessMode(AccessMode access_mode, ObjPtr method_type) { MatchKind match = MatchKind::kExact; ObjPtr vh = this; ObjPtr var_type = vh->GetVarType(); ObjPtr mt_rtype = method_type->GetRType(); ObjPtr void_type = WellKnownClasses::ToClass(WellKnownClasses::java_lang_Void); AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode); // Check return type first. ObjPtr 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 vh_ptypes[VarHandle::kMaxAccessorParameters]; const int32_t vh_ptypes_count = BuildParameterArray(vh_ptypes, access_mode_template, var_type, GetCoordinateType0(), GetCoordinateType1()); if (vh_ptypes_count != method_type->GetPTypes()->GetLength()) { return MatchKind::kNone; } // Check the parameter types are compatible. ObjPtr> mt_ptypes = method_type->GetPTypes(); 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; } ObjPtr VarHandle::GetMethodTypeForAccessMode(Thread* self, ObjPtr var_handle, AccessMode access_mode) { // This is a static method as the var_handle might be moved by the GC during it's execution. AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode); StackHandleScope<3> hs(self); Handle vh = hs.NewHandle(var_handle); Handle rtype = hs.NewHandle(GetReturnType(access_mode_template, vh->GetVarType())); const int32_t ptypes_count = GetNumberOfParameters(access_mode_template, vh->GetCoordinateType0(), vh->GetCoordinateType1()); ObjPtr array_of_class = GetClassRoot>(); Handle> ptypes = hs.NewHandle(ObjectArray::Alloc(Thread::Current(), array_of_class, ptypes_count)); if (ptypes == nullptr) { return nullptr; } ObjPtr ptypes_array[VarHandle::kMaxAccessorParameters]; BuildParameterArray(ptypes_array, access_mode_template, vh->GetVarType(), vh->GetCoordinateType0(), vh->GetCoordinateType1()); for (int32_t i = 0; i < ptypes_count; ++i) { ptypes->Set(i, ptypes_array[i]); } return MethodType::Create(self, rtype, ptypes); } ObjPtr VarHandle::GetMethodTypeForAccessMode(Thread* self, AccessMode access_mode) { return GetMethodTypeForAccessMode(self, this, access_mode); } std::string VarHandle::PrettyDescriptorForAccessMode(AccessMode access_mode) { // Effect MethodType::PrettyDescriptor() without first creating a method type first. std::ostringstream oss; oss << '('; AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode); ObjPtr var_type = GetVarType(); ObjPtr ctypes[2] = { GetCoordinateType0(), GetCoordinateType1() }; const int32_t ptypes_count = GetNumberOfParameters(access_mode_template, ctypes[0], ctypes[1]); int32_t ptypes_done = 0; for (ObjPtr ctype : ctypes) { if (!ctype.IsNull()) { if (ptypes_done != 0) { oss << ", "; } oss << ctype->PrettyDescriptor();; ptypes_done++; } } while (ptypes_done != ptypes_count) { if (ptypes_done != 0) { oss << ", "; } oss << var_type->PrettyDescriptor(); ptypes_done++; } ObjPtr rtype = GetReturnType(access_mode_template, var_type); oss << ')' << rtype->PrettyDescriptor(); return oss.str(); } bool VarHandle::Access(AccessMode access_mode, ShadowFrame* shadow_frame, const InstructionOperands* const operands, JValue* result) { ObjPtr> class_roots = Runtime::Current()->GetClassLinker()->GetClassRoots(); ObjPtr klass = GetClass(); if (klass == GetClassRoot(class_roots)) { auto vh = reinterpret_cast(this); return vh->Access(access_mode, shadow_frame, operands, result); } else if (klass == GetClassRoot(class_roots)) { auto vh = reinterpret_cast(this); return vh->Access(access_mode, shadow_frame, operands, result); } else if (klass == GetClassRoot(class_roots)) { auto vh = reinterpret_cast(this); return vh->Access(access_mode, shadow_frame, operands, result); } else if (klass == GetClassRoot(class_roots)) { auto vh = reinterpret_cast(this); return vh->Access(access_mode, shadow_frame, operands, result); } else { LOG(FATAL) << "Unknown varhandle kind"; UNREACHABLE(); } } const char* VarHandle::GetReturnTypeDescriptor(const char* accessor_name) { AccessMode access_mode; if (!GetAccessModeByMethodName(accessor_name, &access_mode)) { return nullptr; } AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode); switch (access_mode_template) { case AccessModeTemplate::kGet: case AccessModeTemplate::kCompareAndExchange: case AccessModeTemplate::kGetAndUpdate: return "Ljava/lang/Object;"; case AccessModeTemplate::kCompareAndSet: return "Z"; case AccessModeTemplate::kSet: return "V"; } } VarHandle::AccessMode VarHandle::GetAccessModeByIntrinsic(Intrinsics intrinsic) { #define VAR_HANDLE_ACCESS_MODE(V) \ V(CompareAndExchange) \ V(CompareAndExchangeAcquire) \ V(CompareAndExchangeRelease) \ V(CompareAndSet) \ V(Get) \ V(GetAcquire) \ V(GetAndAdd) \ V(GetAndAddAcquire) \ V(GetAndAddRelease) \ V(GetAndBitwiseAnd) \ V(GetAndBitwiseAndAcquire) \ V(GetAndBitwiseAndRelease) \ V(GetAndBitwiseOr) \ V(GetAndBitwiseOrAcquire) \ V(GetAndBitwiseOrRelease) \ V(GetAndBitwiseXor) \ V(GetAndBitwiseXorAcquire) \ V(GetAndBitwiseXorRelease) \ V(GetAndSet) \ V(GetAndSetAcquire) \ V(GetAndSetRelease) \ V(GetOpaque) \ V(GetVolatile) \ V(Set) \ V(SetOpaque) \ V(SetRelease) \ V(SetVolatile) \ V(WeakCompareAndSet) \ V(WeakCompareAndSetAcquire) \ V(WeakCompareAndSetPlain) \ V(WeakCompareAndSetRelease) switch (intrinsic) { #define INTRINSIC_CASE(Name) \ case Intrinsics::kVarHandle ## Name: \ return VarHandle::AccessMode::k ## Name; VAR_HANDLE_ACCESS_MODE(INTRINSIC_CASE) #undef INTRINSIC_CASE #undef VAR_HANDLE_ACCESS_MODE default: break; } LOG(FATAL) << "Unknown VarHandle instrinsic: " << static_cast(intrinsic); UNREACHABLE(); } bool VarHandle::GetAccessModeByMethodName(const char* method_name, AccessMode* access_mode) { if (method_name == nullptr) { return false; } const auto 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) { return false; } *access_mode = it->access_mode; return true; } // 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; } } VarHandle::AccessModeTemplate VarHandle::GetAccessModeTemplateByIntrinsic(Intrinsics ordinal) { AccessMode access_mode = GetAccessModeByIntrinsic(ordinal); return GetAccessModeTemplate(access_mode); } int32_t VarHandle::GetNumberOfVarTypeParameters(AccessModeTemplate access_mode_template) { switch (access_mode_template) { case AccessModeTemplate::kGet: return 0; case AccessModeTemplate::kSet: case AccessModeTemplate::kGetAndUpdate: return 1; case AccessModeTemplate::kCompareAndSet: case AccessModeTemplate::kCompareAndExchange: return 2; } UNREACHABLE(); } ArtField* FieldVarHandle::GetField() { return reinterpret_cast64(GetField64(ArtFieldOffset())); } bool FieldVarHandle::Access(AccessMode access_mode, ShadowFrame* shadow_frame, const InstructionOperands* const operands, JValue* result) { ShadowFrameGetter getter(*shadow_frame, operands); ArtField* field = GetField(); ObjPtr obj; if (field->IsStatic()) { DCHECK_LE(operands->GetNumberOfOperands(), 2u * (Primitive::Is64BitType(GetVarType()->GetPrimitiveType()) ? 2u : 1u)); obj = field->GetDeclaringClass(); } else { DCHECK_GE(operands->GetNumberOfOperands(), 1u); DCHECK_LE(operands->GetNumberOfOperands(), 1u + 2u * (Primitive::Is64BitType(GetVarType()->GetPrimitiveType()) ? 2u : 1u)); obj = getter.GetReference(); if (obj.IsNull()) { ThrowNullPointerExceptionForCoordinate(); return false; } } DCHECK(!obj.IsNull()); const MemberOffset offset = field->GetOffset(); const Primitive::Type primitive_type = GetVarType()->GetPrimitiveType(); switch (primitive_type) { case Primitive::Type::kPrimNot: return FieldAccessor>::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimBoolean: return FieldAccessor::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimByte: return FieldAccessor::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimChar: return FieldAccessor::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimShort: return FieldAccessor::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimInt: return FieldAccessor::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimFloat: return FieldAccessor::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimLong: return FieldAccessor::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimDouble: return FieldAccessor::Dispatch(access_mode, obj, offset, &getter, result); case Primitive::kPrimVoid: break; } LOG(FATAL) << "Unreachable: Unexpected primitive " << primitive_type; UNREACHABLE(); } bool ArrayElementVarHandle::Access(AccessMode access_mode, ShadowFrame* shadow_frame, const InstructionOperands* const operands, JValue* result) { ShadowFrameGetter getter(*shadow_frame, operands); // The target array is the first co-ordinate type preceeding var type arguments. ObjPtr raw_array(getter.GetReference()); if (raw_array == nullptr) { ThrowNullPointerExceptionForCoordinate(); return false; } ObjPtr target_array(raw_array->AsArray()); // The target array element is the second co-ordinate type preceeding var type arguments. const int target_element = getter.Get(); if (!target_array->CheckIsValidIndex(target_element)) { DCHECK(Thread::Current()->IsExceptionPending()); return false; } const Primitive::Type primitive_type = GetVarType()->GetPrimitiveType(); switch (primitive_type) { case Primitive::Type::kPrimNot: { MemberOffset target_element_offset = target_array->AsObjectArray()->OffsetOfElement(target_element); return FieldAccessor>::Dispatch(access_mode, target_array, target_element_offset, &getter, result); } case Primitive::Type::kPrimBoolean: return PrimitiveArrayElementAccessor::Dispatch(access_mode, target_array, target_element, &getter, result); case Primitive::Type::kPrimByte: return PrimitiveArrayElementAccessor::Dispatch(access_mode, target_array, target_element, &getter, result); case Primitive::Type::kPrimChar: return PrimitiveArrayElementAccessor::Dispatch(access_mode, target_array, target_element, &getter, result); case Primitive::Type::kPrimShort: return PrimitiveArrayElementAccessor::Dispatch(access_mode, target_array, target_element, &getter, result); case Primitive::Type::kPrimInt: return PrimitiveArrayElementAccessor::Dispatch(access_mode, target_array, target_element, &getter, result); case Primitive::Type::kPrimLong: return PrimitiveArrayElementAccessor::Dispatch(access_mode, target_array, target_element, &getter, result); case Primitive::Type::kPrimFloat: return PrimitiveArrayElementAccessor::Dispatch(access_mode, target_array, target_element, &getter, result); case Primitive::Type::kPrimDouble: return PrimitiveArrayElementAccessor::Dispatch(access_mode, target_array, target_element, &getter, result); case Primitive::Type::kPrimVoid: break; } LOG(FATAL) << "Unreachable: Unexpected primitive " << primitive_type; UNREACHABLE(); } bool ByteArrayViewVarHandle::GetNativeByteOrder() { return GetFieldBoolean(NativeByteOrderOffset()); } bool ByteArrayViewVarHandle::Access(AccessMode access_mode, ShadowFrame* shadow_frame, const InstructionOperands* const operands, JValue* result) { ShadowFrameGetter getter(*shadow_frame, operands); // The byte array is the first co-ordinate type preceeding var type arguments. ObjPtr raw_byte_array(getter.GetReference()); if (raw_byte_array == nullptr) { ThrowNullPointerExceptionForCoordinate(); return false; } ObjPtr byte_array(raw_byte_array->AsByteArray()); // The offset in the byte array element is the second co-ordinate type. const int32_t data_offset = getter.Get(); // Bounds check requested access. const Primitive::Type primitive_type = GetVarType()->GetPrimitiveType(); if (!CheckElementIndex(primitive_type, data_offset, byte_array->GetLength())) { return false; } 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::Dispatch(access_mode, data, data_offset, byte_swap, &getter, result); case Primitive::kPrimShort: return ByteArrayViewAccessor::Dispatch(access_mode, data, data_offset, byte_swap, &getter, result); case Primitive::kPrimInt: return ByteArrayViewAccessor::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::Dispatch(access_mode, data, data_offset, byte_swap, &getter, result); case Primitive::kPrimLong: return ByteArrayViewAccessor::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::Dispatch(access_mode, data, data_offset, byte_swap, &getter, result); } LOG(FATAL) << "Unreachable: Unexpected primitive " << primitive_type; UNREACHABLE(); } bool ByteBufferViewVarHandle::GetNativeByteOrder() { return GetFieldBoolean(NativeByteOrderOffset()); } bool ByteBufferViewVarHandle::Access(AccessMode access_mode, ShadowFrame* shadow_frame, const InstructionOperands* const operands, JValue* result) { ShadowFrameGetter getter(*shadow_frame, operands); // The byte buffer is the first co-ordinate argument preceeding var type arguments. ObjPtr byte_buffer(getter.GetReference()); if (byte_buffer == nullptr) { ThrowNullPointerExceptionForCoordinate(); return false; } // 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( GetMemberOffset(WellKnownClasses::java_nio_ByteBuffer_isReadOnly)); if (is_read_only && !IsReadOnlyAccessMode(access_mode)) { ThrowReadOnlyBufferException(); return false; } // The native_address is only set for ByteBuffer instances backed by native memory. const int64_t native_address = byte_buffer->GetField64(GetMemberOffset(WellKnownClasses::java_nio_ByteBuffer_address)); // 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( GetMemberOffset(WellKnownClasses::java_nio_ByteBuffer_offset)); } else { // Accessing direct memory. byte_buffer_offset = 0; } const int32_t byte_buffer_limit = byte_buffer->GetField32( GetMemberOffset(WellKnownClasses::java_nio_ByteBuffer_limit)); const Primitive::Type primitive_type = GetVarType()->GetPrimitiveType(); if (!CheckElementIndex(primitive_type, byte_index, byte_buffer_offset, byte_buffer_limit)) { return false; } const int32_t checked_offset32 = byte_buffer_offset + byte_index; int8_t* data; if (native_address == 0) { ObjPtr heap_byte_array = byte_buffer->GetFieldObject( GetMemberOffset(WellKnownClasses::java_nio_ByteBuffer_hb)); data = heap_byte_array->GetData(); } else { data = reinterpret_cast(static_cast(native_address)); } bool byte_swap = !GetNativeByteOrder(); switch (primitive_type) { case Primitive::kPrimChar: return ByteArrayViewAccessor::Dispatch(access_mode, data, checked_offset32, byte_swap, &getter, result); case Primitive::kPrimShort: return ByteArrayViewAccessor::Dispatch(access_mode, data, checked_offset32, byte_swap, &getter, result); case Primitive::kPrimInt: return ByteArrayViewAccessor::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::Dispatch(access_mode, data, checked_offset32, byte_swap, &getter, result); case Primitive::kPrimLong: return ByteArrayViewAccessor::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::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(); } void FieldVarHandle::VisitTarget(ReflectiveValueVisitor* v) { ArtField* orig = GetField(); ArtField* new_value = v->VisitField(orig, HeapReflectiveSourceInfo(kSourceJavaLangInvokeFieldVarHandle, this)); if (orig != new_value) { SetField64(ArtFieldOffset(), reinterpret_cast(new_value)); } } } // namespace mirror } // namespace art