| /* |
| * 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 "gc_root.h" |
| #include "jvalue.h" |
| #include "object.h" |
| |
| namespace art { |
| |
| template<class T> class Handle; |
| class InstructionOperands; |
| |
| enum class Intrinsics; |
| |
| struct VarHandleOffsets; |
| struct FieldVarHandleOffsets; |
| struct ArrayElementVarHandleOffsets; |
| struct ByteArrayViewVarHandleOffsets; |
| struct ByteBufferViewVarHandleOffsets; |
| |
| 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<size_t>(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<uint32_t>(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, MethodType* 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, MethodType* 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. |
| MethodType* 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. |
| Class* 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); |
| |
| static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); |
| static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); |
| static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); |
| static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); |
| |
| private: |
| Class* GetCoordinateType0() REQUIRES_SHARED(Locks::mutator_lock_); |
| Class* GetCoordinateType1() REQUIRES_SHARED(Locks::mutator_lock_); |
| int32_t GetAccessModesBitMask() REQUIRES_SHARED(Locks::mutator_lock_); |
| |
| static MethodType* GetMethodTypeForAccessMode(Thread* self, |
| ObjPtr<VarHandle> 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<mirror::Class> coordinate_type0_; |
| HeapReference<mirror::Class> coordinate_type1_; |
| HeapReference<mirror::Class> var_type_; |
| int32_t access_modes_bit_mask_; |
| |
| // Root representing java.lang.invoke.VarHandle.class. |
| static GcRoot<mirror::Class> static_class_; |
| |
| 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_); |
| |
| static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); |
| static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); |
| static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); |
| static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(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_; |
| |
| // Root representing java.lang.invoke.FieldVarHandle.class. |
| static GcRoot<mirror::Class> static_class_; |
| |
| 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_); |
| |
| static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); |
| static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); |
| static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); |
| static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); |
| |
| private: |
| // Root representing java.lang.invoke.ArrayElementVarHandle.class. |
| static GcRoot<mirror::Class> static_class_; |
| |
| 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_); |
| |
| static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); |
| static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); |
| static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); |
| static void VisitRoots(RootVisitor* visitor) 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_; |
| |
| // Root representing java.lang.invoke.ByteArrayViewVarHandle.class. |
| static GcRoot<mirror::Class> static_class_; |
| |
| 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_); |
| |
| static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); |
| static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); |
| static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); |
| static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); |
| |
| private: |
| bool AccessHeapBuffer(AccessMode access_mode, |
| ObjPtr<Object> byte_buffer, |
| int buffer_offset, |
| ObjPtr<ByteArray> heap_byte_array, |
| ShadowFrameGetter* getter, |
| JValue* result) |
| REQUIRES_SHARED(Locks::mutator_lock_); |
| |
| bool AccessFixedMemory(AccessMode access_mode, |
| ObjPtr<Object> 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_; |
| |
| // Root representing java.lang.invoke.ByteBufferViewVarHandle.class. |
| static GcRoot<mirror::Class> static_class_; |
| |
| 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_ |