/* * 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. */ #ifndef ART_RUNTIME_MIRROR_VAR_HANDLE_H_ #define ART_RUNTIME_MIRROR_VAR_HANDLE_H_ #include "handle.h" #include "interpreter/shadow_frame.h" #include "jvalue.h" #include "object.h" namespace art { template class Handle; class InstructionOperands; template class ObjPtr; enum class Intrinsics; struct VarHandleOffsets; struct FieldVarHandleOffsets; struct ArrayElementVarHandleOffsets; struct ByteArrayViewVarHandleOffsets; struct ByteBufferViewVarHandleOffsets; class ReflectiveValueVisitor; class ShadowFrameGetter; namespace mirror { class MethodType; class VarHandleTest; // C++ mirror of java.lang.invoke.VarHandle class MANAGED VarHandle : public Object { public: // The maximum number of parameters a VarHandle accessor method can // take. The Worst case is equivalent to a compare-and-swap // operation on an array element which requires four parameters // (array, index, old, new). static constexpr int kMaxAccessorParameters = 4; // The maximum number of VarType parameters a VarHandle accessor // method can take. static constexpr size_t kMaxVarTypeParameters = 2; // Enumeration of the possible access modes. This mirrors the enum // in java.lang.invoke.VarHandle. enum class AccessMode : uint32_t { kGet, kSet, kGetVolatile, kSetVolatile, kGetAcquire, kSetRelease, kGetOpaque, kSetOpaque, kCompareAndSet, kCompareAndExchange, kCompareAndExchangeAcquire, kCompareAndExchangeRelease, kWeakCompareAndSetPlain, kWeakCompareAndSet, kWeakCompareAndSetAcquire, kWeakCompareAndSetRelease, kGetAndSet, kGetAndSetAcquire, kGetAndSetRelease, kGetAndAdd, kGetAndAddAcquire, kGetAndAddRelease, kGetAndBitwiseOr, kGetAndBitwiseOrRelease, kGetAndBitwiseOrAcquire, kGetAndBitwiseAnd, kGetAndBitwiseAndRelease, kGetAndBitwiseAndAcquire, kGetAndBitwiseXor, kGetAndBitwiseXorRelease, kGetAndBitwiseXorAcquire, kLast = kGetAndBitwiseXorAcquire, }; constexpr static size_t kNumberOfAccessModes = static_cast(AccessMode::kLast) + 1u; // Returns true if the AccessMode specified is a supported operation. bool IsAccessModeSupported(AccessMode accessMode) REQUIRES_SHARED(Locks::mutator_lock_) { return (GetAccessModesBitMask() & (1u << static_cast(accessMode))) != 0; } enum MatchKind : uint8_t { kNone, kWithConversions, kExact }; // Returns match information on the compatability between the exact method type for // 'access_mode' and the provided 'method_type'. MatchKind GetMethodTypeMatchForAccessMode(AccessMode access_mode, ObjPtr method_type) REQUIRES_SHARED(Locks::mutator_lock_); // Returns true if the MethodType specified is compatible with the // specified access_mode if the first parameter of method_type is // ignored. This is useful for comparing MethodType instances when // invoking a VarHandleAccessor via a MethodHandle invoker. bool IsInvokerMethodTypeCompatible(AccessMode access_mode, ObjPtr method_type) REQUIRES_SHARED(Locks::mutator_lock_); // Allocates and returns the MethodType associated with the // AccessMode. No check is made for whether the AccessMode is a // supported operation so the MethodType can be used when raising a // WrongMethodTypeException exception. ObjPtr GetMethodTypeForAccessMode(Thread* self, AccessMode accessMode) REQUIRES_SHARED(Locks::mutator_lock_); // Returns a string representing the descriptor of the MethodType associated with // this AccessMode. std::string PrettyDescriptorForAccessMode(AccessMode access_mode) REQUIRES_SHARED(Locks::mutator_lock_); bool Access(AccessMode access_mode, ShadowFrame* shadow_frame, const InstructionOperands* const operands, JValue* result) REQUIRES_SHARED(Locks::mutator_lock_); // Gets the variable type that is operated on by this VarHandle instance. ObjPtr GetVarType() REQUIRES_SHARED(Locks::mutator_lock_); // Gets the return type descriptor for a named accessor method, // nullptr if accessor_method is not supported. static const char* GetReturnTypeDescriptor(const char* accessor_method); // Returns the AccessMode corresponding to a VarHandle accessor intrinsic. static AccessMode GetAccessModeByIntrinsic(Intrinsics ordinal); // Returns true and sets access_mode if method_name corresponds to a // VarHandle access method, such as "setOpaque". Returns false otherwise. static bool GetAccessModeByMethodName(const char* method_name, AccessMode* access_mode); private: ObjPtr GetCoordinateType0() REQUIRES_SHARED(Locks::mutator_lock_); ObjPtr GetCoordinateType1() REQUIRES_SHARED(Locks::mutator_lock_); int32_t GetAccessModesBitMask() REQUIRES_SHARED(Locks::mutator_lock_); static ObjPtr GetMethodTypeForAccessMode(Thread* self, ObjPtr var_handle, AccessMode access_mode) REQUIRES_SHARED(Locks::mutator_lock_); static MemberOffset VarTypeOffset() { return MemberOffset(OFFSETOF_MEMBER(VarHandle, var_type_)); } static MemberOffset CoordinateType0Offset() { return MemberOffset(OFFSETOF_MEMBER(VarHandle, coordinate_type0_)); } static MemberOffset CoordinateType1Offset() { return MemberOffset(OFFSETOF_MEMBER(VarHandle, coordinate_type1_)); } static MemberOffset AccessModesBitMaskOffset() { return MemberOffset(OFFSETOF_MEMBER(VarHandle, access_modes_bit_mask_)); } HeapReference coordinate_type0_; HeapReference coordinate_type1_; HeapReference var_type_; int32_t access_modes_bit_mask_; friend class VarHandleTest; // for testing purposes friend struct art::VarHandleOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(VarHandle); }; // Represents a VarHandle to a static or instance field. // The corresponding managed class in libart java.lang.invoke.FieldVarHandle. class MANAGED FieldVarHandle : public VarHandle { public: bool Access(AccessMode access_mode, ShadowFrame* shadow_frame, const InstructionOperands* const operands, JValue* result) REQUIRES_SHARED(Locks::mutator_lock_); ArtField* GetField() REQUIRES_SHARED(Locks::mutator_lock_); // Used for updating var-handles to obsolete fields. void VisitTarget(ReflectiveValueVisitor* v) REQUIRES(Locks::mutator_lock_); private: static MemberOffset ArtFieldOffset() { return MemberOffset(OFFSETOF_MEMBER(FieldVarHandle, art_field_)); } // ArtField instance corresponding to variable for accessors. int64_t art_field_; friend class VarHandleTest; // for var_handle_test. friend struct art::FieldVarHandleOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(FieldVarHandle); }; // Represents a VarHandle providing accessors to an array. // The corresponding managed class in libart java.lang.invoke.ArrayElementVarHandle. class MANAGED ArrayElementVarHandle : public VarHandle { public: bool Access(AccessMode access_mode, ShadowFrame* shadow_frame, const InstructionOperands* const operands, JValue* result) REQUIRES_SHARED(Locks::mutator_lock_); private: friend class VarHandleTest; DISALLOW_IMPLICIT_CONSTRUCTORS(ArrayElementVarHandle); }; // Represents a VarHandle providing accessors to a view of a ByteArray. // The corresponding managed class in libart java.lang.invoke.ByteArrayViewVarHandle. class MANAGED ByteArrayViewVarHandle : public VarHandle { public: bool Access(AccessMode access_mode, ShadowFrame* shadow_frame, const InstructionOperands* const operands, JValue* result) REQUIRES_SHARED(Locks::mutator_lock_); bool GetNativeByteOrder() REQUIRES_SHARED(Locks::mutator_lock_); private: static MemberOffset NativeByteOrderOffset() { return MemberOffset(OFFSETOF_MEMBER(ByteArrayViewVarHandle, native_byte_order_)); } // Flag indicating that accessors should use native byte-ordering. uint8_t native_byte_order_; friend class VarHandleTest; // for var_handle_test. friend struct art::ByteArrayViewVarHandleOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(ByteArrayViewVarHandle); }; // Represents a VarHandle providing accessors to a view of a ByteBuffer // The corresponding managed class in libart java.lang.invoke.ByteBufferViewVarHandle. class MANAGED ByteBufferViewVarHandle : public VarHandle { public: bool Access(AccessMode access_mode, ShadowFrame* shadow_frame, const InstructionOperands* const operands, JValue* result) REQUIRES_SHARED(Locks::mutator_lock_); bool GetNativeByteOrder() REQUIRES_SHARED(Locks::mutator_lock_); private: bool AccessHeapBuffer(AccessMode access_mode, ObjPtr byte_buffer, int buffer_offset, ObjPtr heap_byte_array, ShadowFrameGetter* getter, JValue* result) REQUIRES_SHARED(Locks::mutator_lock_); bool AccessFixedMemory(AccessMode access_mode, ObjPtr byte_buffer, int buffer_offset, ShadowFrameGetter* getter, JValue* result) REQUIRES_SHARED(Locks::mutator_lock_); static MemberOffset NativeByteOrderOffset() { return MemberOffset(OFFSETOF_MEMBER(ByteBufferViewVarHandle, native_byte_order_)); } // Flag indicating that accessors should use native byte-ordering. uint8_t native_byte_order_; friend class VarHandleTest; // for var_handle_test. friend struct art::ByteBufferViewVarHandleOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(ByteBufferViewVarHandle); }; } // namespace mirror } // namespace art #endif // ART_RUNTIME_MIRROR_VAR_HANDLE_H_