/*
* 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;
}
// Returns true if the MethodType specified is compatible with the
// method type associated with the specified AccessMode. The
// supplied MethodType is assumed to be from the point of invocation
// so it is valid for the supplied MethodType to have a void return
// value when the return value for the AccessMode is non-void. This
// corresponds to the result of the accessor being discarded.
bool IsMethodTypeCompatible(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_);
bool Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
InstructionOperands* 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,
InstructionOperands* 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,
InstructionOperands* 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,
InstructionOperands* 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,
InstructionOperands* 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_