summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/Android.bp1
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc52
-rw-r--r--runtime/interpreter/interpreter_common.cc85
-rw-r--r--runtime/mirror/var_handle.cc53
-rw-r--r--runtime/mirror/var_handle.h28
-rw-r--r--runtime/mirror/var_handle_test.cc264
-rw-r--r--runtime/var_handles.cc78
-rw-r--r--runtime/var_handles.h35
-rw-r--r--runtime/verifier/method_verifier.cc2
9 files changed, 360 insertions, 238 deletions
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 3db4ee54c1..0540b2087e 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -195,6 +195,7 @@ libart_cc_defaults {
"ti/agent.cc",
"trace.cc",
"transaction.cc",
+ "var_handles.cc",
"vdex_file.cc",
"verifier/instruction_flags.cc",
"verifier/method_verifier.cc",
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 7e3c3dbaa6..0a186f4dc5 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -42,6 +42,7 @@
#include "mirror/method_handle_impl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
+#include "mirror/var_handle.h"
#include "oat_file.h"
#include "oat_quick_method_header.h"
#include "quick_exception_handler.h"
@@ -49,6 +50,7 @@
#include "scoped_thread_state_change-inl.h"
#include "stack.h"
#include "thread-inl.h"
+#include "var_handles.h"
#include "well_known_classes.h"
namespace art {
@@ -2789,13 +2791,6 @@ extern "C" uintptr_t artInvokePolymorphic(
return static_cast<uintptr_t>('V');
}
- // TODO(oth): Ensure this path isn't taken for VarHandle accessors (b/65872996).
- DCHECK_EQ(resolved_method->GetDeclaringClass(),
- WellKnownClasses::ToClass(WellKnownClasses::java_lang_invoke_MethodHandle));
-
- Handle<mirror::MethodHandle> method_handle(hs.NewHandle(
- ObjPtr<mirror::MethodHandle>::DownCast(MakeObjPtr(receiver_handle.Get()))));
-
Handle<mirror::MethodType> method_type(
hs.NewHandle(linker->ResolveMethodType(self, proto_idx, caller_method)));
@@ -2835,24 +2830,43 @@ extern "C" uintptr_t artInvokePolymorphic(
// Call DoInvokePolymorphic with |is_range| = true, as shadow frame has argument registers in
// consecutive order.
RangeInstructionOperands operands(first_arg + 1, num_vregs - 1);
- bool isExact = (jni::EncodeArtMethod(resolved_method) ==
- WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact);
+ Intrinsics intrinsic = static_cast<Intrinsics>(resolved_method->GetIntrinsic());
bool success = false;
- if (isExact) {
- success = MethodHandleInvokeExact(self,
+ if (resolved_method->GetDeclaringClass() == mirror::MethodHandle::StaticClass()) {
+ Handle<mirror::MethodHandle> method_handle(hs.NewHandle(
+ ObjPtr<mirror::MethodHandle>::DownCast(MakeObjPtr(receiver_handle.Get()))));
+ if (intrinsic == Intrinsics::kMethodHandleInvokeExact) {
+ success = MethodHandleInvokeExact(self,
+ *shadow_frame,
+ method_handle,
+ method_type,
+ &operands,
+ result);
+ } else {
+ DCHECK_EQ(static_cast<uint32_t>(intrinsic),
+ static_cast<uint32_t>(Intrinsics::kMethodHandleInvoke));
+ success = MethodHandleInvoke(self,
+ *shadow_frame,
+ method_handle,
+ method_type,
+ &operands,
+ result);
+ }
+ } else {
+ DCHECK_EQ(mirror::VarHandle::StaticClass(), resolved_method->GetDeclaringClass());
+ Handle<mirror::VarHandle> var_handle(hs.NewHandle(
+ ObjPtr<mirror::VarHandle>::DownCast(MakeObjPtr(receiver_handle.Get()))));
+ mirror::VarHandle::AccessMode access_mode =
+ mirror::VarHandle::GetAccessModeByIntrinsic(intrinsic);
+ success = VarHandleInvokeAccessor(self,
*shadow_frame,
- method_handle,
+ var_handle,
method_type,
+ access_mode,
&operands,
result);
- } else {
- success = MethodHandleInvoke(self,
- *shadow_frame,
- method_handle,
- method_type,
- &operands,
- result);
}
+
DCHECK(success || self->IsExceptionPending());
// Pop transition record.
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index ded8cefb8f..d30bc10450 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -37,6 +37,7 @@
#include "stack.h"
#include "thread-inl.h"
#include "transaction.h"
+#include "var_handles.h"
#include "well_known_classes.h"
namespace art {
@@ -725,38 +726,6 @@ bool DoMethodHandleInvoke(Thread* self,
}
}
-static bool DoVarHandleInvokeChecked(Thread* self,
- Handle<mirror::VarHandle> var_handle,
- Handle<mirror::MethodType> callsite_type,
- mirror::VarHandle::AccessMode access_mode,
- ShadowFrame& shadow_frame,
- InstructionOperands* operands,
- JValue* result)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- // TODO(oth): GetMethodTypeForAccessMode() allocates a MethodType()
- // which is only required if we need to convert argument and/or
- // return types.
- StackHandleScope<1> hs(self);
- Handle<mirror::MethodType> accessor_type(hs.NewHandle(
- var_handle->GetMethodTypeForAccessMode(self, access_mode)));
- const size_t num_vregs = accessor_type->NumberOfVRegs();
- const int num_params = accessor_type->GetPTypes()->GetLength();
- ShadowFrameAllocaUniquePtr accessor_frame =
- CREATE_SHADOW_FRAME(num_vregs, nullptr, shadow_frame.GetMethod(), shadow_frame.GetDexPC());
- ShadowFrameGetter getter(shadow_frame, operands);
- static const uint32_t kFirstDestinationReg = 0;
- ShadowFrameSetter setter(accessor_frame.get(), kFirstDestinationReg);
- if (!PerformConversions(self, callsite_type, accessor_type, &getter, &setter, num_params)) {
- return false;
- }
- RangeInstructionOperands accessor_operands(kFirstDestinationReg,
- kFirstDestinationReg + num_vregs);
- if (!var_handle->Access(access_mode, accessor_frame.get(), &accessor_operands, result)) {
- return false;
- }
- return ConvertReturnValue(callsite_type, accessor_type, result);
-}
-
static bool DoVarHandleInvokeCommon(Thread* self,
ShadowFrame& shadow_frame,
const Instruction* inst,
@@ -769,21 +738,8 @@ static bool DoVarHandleInvokeCommon(Thread* self,
return false;
}
- bool is_var_args = inst->HasVarArgs();
- const uint32_t vRegC = is_var_args ? inst->VRegC_45cc() : inst->VRegC_4rcc();
- ObjPtr<mirror::Object> receiver(shadow_frame.GetVRegReference(vRegC));
- if (receiver.IsNull()) {
- ThrowNullPointerExceptionFromDexPC();
- return false;
- }
-
StackHandleScope<2> hs(self);
- Handle<mirror::VarHandle> var_handle(hs.NewHandle(down_cast<mirror::VarHandle*>(receiver.Ptr())));
- if (!var_handle->IsAccessModeSupported(access_mode)) {
- ThrowUnsupportedOperationException();
- return false;
- }
-
+ bool is_var_args = inst->HasVarArgs();
const uint16_t vRegH = is_var_args ? inst->VRegH_45cc() : inst->VRegH_4rcc();
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
Handle<mirror::MethodType> callsite_type(hs.NewHandle(
@@ -794,34 +750,31 @@ static bool DoVarHandleInvokeCommon(Thread* self,
return false;
}
- if (!var_handle->IsMethodTypeCompatible(access_mode, callsite_type.Get())) {
- ThrowWrongMethodTypeException(var_handle->GetMethodTypeForAccessMode(self, access_mode),
- callsite_type.Get());
- return false;
- }
-
+ const uint32_t vRegC = is_var_args ? inst->VRegC_45cc() : inst->VRegC_4rcc();
+ ObjPtr<mirror::Object> receiver(shadow_frame.GetVRegReference(vRegC));
+ Handle<mirror::VarHandle> var_handle(hs.NewHandle(down_cast<mirror::VarHandle*>(receiver.Ptr())));
if (is_var_args) {
uint32_t args[Instruction::kMaxVarArgRegs];
inst->GetVarArgs(args, inst_data);
VarArgsInstructionOperands all_operands(args, inst->VRegA_45cc());
NoReceiverInstructionOperands operands(&all_operands);
- return DoVarHandleInvokeChecked(self,
- var_handle,
- callsite_type,
- access_mode,
- shadow_frame,
- &operands,
- result);
+ return VarHandleInvokeAccessor(self,
+ shadow_frame,
+ var_handle,
+ callsite_type,
+ access_mode,
+ &operands,
+ result);
} else {
RangeInstructionOperands all_operands(inst->VRegC_4rcc(), inst->VRegA_4rcc());
NoReceiverInstructionOperands operands(&all_operands);
- return DoVarHandleInvokeChecked(self,
- var_handle,
- callsite_type,
- access_mode,
- shadow_frame,
- &operands,
- result);
+ return VarHandleInvokeAccessor(self,
+ shadow_frame,
+ var_handle,
+ callsite_type,
+ access_mode,
+ &operands,
+ result);
}
}
diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc
index b309f596fd..d31e06cf36 100644
--- a/runtime/mirror/var_handle.cc
+++ b/runtime/mirror/var_handle.cc
@@ -1425,21 +1425,24 @@ int32_t VarHandle::GetAccessModesBitMask() {
return GetField32(AccessModesBitMaskOffset());
}
-bool VarHandle::IsMethodTypeCompatible(AccessMode access_mode, MethodType* method_type) {
- StackHandleScope<3> hs(Thread::Current());
- Handle<Class> mt_rtype(hs.NewHandle(method_type->GetRType()));
- Handle<VarHandle> vh(hs.NewHandle(this));
- Handle<Class> var_type(hs.NewHandle(vh->GetVarType()));
+VarHandle::MatchKind VarHandle::GetMethodTypeMatchForAccessMode(AccessMode access_mode,
+ MethodType* method_type) {
+ MatchKind match = MatchKind::kExact;
+
+ ObjPtr<VarHandle> vh = this;
+ ObjPtr<Class> var_type = vh->GetVarType();
+ ObjPtr<Class> mt_rtype = method_type->GetRType();
AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode);
- // Check return type first.
- if (mt_rtype->GetPrimitiveType() == Primitive::Type::kPrimVoid) {
- // The result of the operation will be discarded. The return type
- // of the VarHandle is immaterial.
- } else {
- ObjPtr<Class> vh_rtype(GetReturnType(access_mode_template, var_type.Get()));
- if (!IsReturnTypeConvertible(vh_rtype, mt_rtype.Get())) {
- return false;
+ // Check return type first. If the return type of the method
+ // of the VarHandle is immaterial.
+ if (mt_rtype->GetPrimitiveType() != Primitive::Type::kPrimVoid) {
+ ObjPtr<Class> vh_rtype = GetReturnType(access_mode_template, var_type.Ptr());
+ if (vh_rtype != mt_rtype) {
+ if (!IsReturnTypeConvertible(vh_rtype, mt_rtype)) {
+ return MatchKind::kNone;
+ }
+ match = MatchKind::kWithConversions;
}
}
@@ -1447,21 +1450,25 @@ bool VarHandle::IsMethodTypeCompatible(AccessMode access_mode, MethodType* metho
ObjPtr<Class> vh_ptypes[VarHandle::kMaxAccessorParameters];
const int32_t vh_ptypes_count = BuildParameterArray(vh_ptypes,
access_mode_template,
- var_type.Get(),
+ var_type,
GetCoordinateType0(),
GetCoordinateType1());
if (vh_ptypes_count != method_type->GetPTypes()->GetLength()) {
- return false;
+ return MatchKind::kNone;
}
// Check the parameter types are compatible.
ObjPtr<ObjectArray<Class>> mt_ptypes = method_type->GetPTypes();
for (int32_t i = 0; i < vh_ptypes_count; ++i) {
+ if (mt_ptypes->Get(i) == vh_ptypes[i]) {
+ continue;
+ }
if (!IsParameterTypeConvertible(mt_ptypes->Get(i), vh_ptypes[i])) {
- return false;
+ return MatchKind::kNone;
}
+ match = MatchKind::kWithConversions;
}
- return true;
+ return match;
}
bool VarHandle::IsInvokerMethodTypeCompatible(AccessMode access_mode,
@@ -1508,7 +1515,7 @@ bool VarHandle::IsInvokerMethodTypeCompatible(AccessMode access_mode,
MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self,
ObjPtr<VarHandle> var_handle,
AccessMode access_mode) {
- // This is a static as the var_handle might be moved by the GC during it's execution.
+ // 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);
@@ -1540,7 +1547,7 @@ MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self, AccessMode acces
bool VarHandle::Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result) {
Class* klass = GetClass();
if (klass == FieldVarHandle::StaticClass()) {
@@ -1671,7 +1678,7 @@ ArtField* FieldVarHandle::GetField() {
bool FieldVarHandle::Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result) {
ShadowFrameGetter getter(*shadow_frame, operands);
ArtField* field = GetField();
@@ -1743,7 +1750,7 @@ GcRoot<Class> FieldVarHandle::static_class_;
bool ArrayElementVarHandle::Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result) {
ShadowFrameGetter getter(*shadow_frame, operands);
@@ -1856,7 +1863,7 @@ bool ByteArrayViewVarHandle::GetNativeByteOrder() {
bool ByteArrayViewVarHandle::Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result) {
ShadowFrameGetter getter(*shadow_frame, operands);
@@ -1965,7 +1972,7 @@ bool ByteBufferViewVarHandle::GetNativeByteOrder() {
bool ByteBufferViewVarHandle::Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result) {
ShadowFrameGetter getter(*shadow_frame, operands);
diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h
index d46d900a8d..eb3704ee48 100644
--- a/runtime/mirror/var_handle.h
+++ b/runtime/mirror/var_handle.h
@@ -99,14 +99,16 @@ class MANAGED VarHandle : public Object {
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_);
+ 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
@@ -124,7 +126,7 @@ class MANAGED VarHandle : public Object {
bool Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -192,7 +194,7 @@ class MANAGED FieldVarHandle : public VarHandle {
public:
bool Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -225,7 +227,7 @@ class MANAGED ArrayElementVarHandle : public VarHandle {
public:
bool Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -248,7 +250,7 @@ class MANAGED ByteArrayViewVarHandle : public VarHandle {
public:
bool Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -281,7 +283,7 @@ class MANAGED ByteBufferViewVarHandle : public VarHandle {
public:
bool Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/mirror/var_handle_test.cc b/runtime/mirror/var_handle_test.cc
index d9fa07f207..005aba3edd 100644
--- a/runtime/mirror/var_handle_test.cc
+++ b/runtime/mirror/var_handle_test.cc
@@ -246,6 +246,47 @@ static MethodType* MethodTypeOf(const std::string& method_descriptor) {
return MethodType::Create(self, rtype, ptypes);
}
+static bool AccessModeMatch(VarHandle* vh,
+ VarHandle::AccessMode access_mode,
+ MethodType* method_type,
+ VarHandle::MatchKind expected_match)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return vh->GetMethodTypeMatchForAccessMode(access_mode, method_type) == expected_match;
+}
+
+template <typename VH>
+static bool AccessModeExactMatch(Handle<VH> vh,
+ VarHandle::AccessMode access_mode,
+ const char* descriptor)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return AccessModeMatch(vh.Get(),
+ access_mode,
+ MethodTypeOf(descriptor),
+ VarHandle::MatchKind::kExact);
+}
+
+template <typename VH>
+static bool AccessModeWithConversionsMatch(Handle<VH> vh,
+ VarHandle::AccessMode access_mode,
+ const char* descriptor)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return AccessModeMatch(vh.Get(),
+ access_mode,
+ MethodTypeOf(descriptor),
+ VarHandle::MatchKind::kWithConversions);
+}
+
+template <typename VH>
+static bool AccessModeNoMatch(Handle<VH> vh,
+ VarHandle::AccessMode access_mode,
+ const char* descriptor)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return AccessModeMatch(vh.Get(),
+ access_mode,
+ MethodTypeOf(descriptor),
+ VarHandle::MatchKind::kNone);
+}
+
TEST_F(VarHandleTest, InstanceFieldVarHandle) {
Thread * const self = Thread::Current();
ScopedObjectAccess soa(self);
@@ -296,47 +337,53 @@ TEST_F(VarHandleTest, InstanceFieldVarHandle) {
// Check compatibility - "Get" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)I")));
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;)I"));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;)V"));
+ EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;)D"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Z)Z"));
}
// Check compatibility - "Set" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;I)V"));
+ EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;S)V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;)V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndSet" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;II)Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode,
- MethodTypeOf("(Ljava/lang/Integer;II)I")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;II)Z"));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;II)V"));
+ EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;II)Ljava/lang/Boolean;"));
+ EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;IB)V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;II)I"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndExchange" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;II)I")));
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;II)V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(IIII)V")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;II)I"));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;II)V"));
+ EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;II)J"));
+ EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;BS)F"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;I)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(IIII)V"));
}
// Check compatibility - "GetAndUpdate" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)I")));
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)S")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;I)I"));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;I)V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;I)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(II)S"));
}
// Check synthesized method types match expected forms.
@@ -430,48 +477,47 @@ TEST_F(VarHandleTest, StaticFieldVarHandle) {
// Check compatibility - "Get" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()I")));
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "()I"));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "()V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "()Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Z)Z"));
}
// Check compatibility - "Set" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(I)V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(F)V")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(I)V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "()V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "()Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(F)V"));
}
// Check compatibility - "CompareAndSet" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode,
- MethodTypeOf("(II)Ljava/lang/String;")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(II)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(II)Ljava/lang/String;"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "()Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndExchange" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)I")));
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(ID)I")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)S")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(IIJ)V")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(II)I"));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(II)V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(ID)I"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(II)S"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(IIJ)V"));
}
// Check compatibility - "GetAndUpdate" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(I)I")));
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(I)V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(I)Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(I)I"));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(I)V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(I)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(II)V"));
}
// Check synthesized method types match expected forms.
@@ -594,50 +640,46 @@ TEST_F(VarHandleTest, ArrayElementVarHandle) {
// Check compatibility - "Get" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)Ljava/lang/String;")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;Ljava/lang/String;)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;I)Ljava/lang/String;"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;I)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;Ljava/lang/String;)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)Z"));
}
// Check compatibility - "Set" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;I)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;I)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndSet" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet;
- EXPECT_TRUE(
- vh->IsMethodTypeCompatible(
- access_mode,
- MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode,
- MethodTypeOf("([Ljava/lang/String;III)I")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;III)I"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;I)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndExchange" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;II)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(III)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;II)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(III)V"));
}
// Check compatibility - "GetAndUpdate" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(II)V"));
}
// Check synthesized method types match expected forms.
@@ -747,50 +789,46 @@ TEST_F(VarHandleTest, ByteArrayViewVarHandle) {
// Check compatibility - "Get" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)C")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BC)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BI)C"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BI)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BC)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)Z"));
}
// Check compatibility - "Set" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BIC)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BIC)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BI)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BI)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndSet" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet;
- EXPECT_TRUE(
- vh->IsMethodTypeCompatible(
- access_mode,
- MethodTypeOf("([BICC)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode,
- MethodTypeOf("([BIII)I")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BICC)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BIII)I"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BI)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndExchange" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BICC)C")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BICC)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BII)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(III)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BICC)C"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BICC)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BII)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(III)V"));
}
// Check compatibility - "GetAndUpdate" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BIC)C")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BIC)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BIC)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BIC)C"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BIC)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BIC)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(II)V"));
}
// Check synthesized method types match expected forms.
@@ -900,50 +938,46 @@ TEST_F(VarHandleTest, ByteBufferViewVarHandle) {
// Check compatibility - "Get" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)D")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;D)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;I)D"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;I)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;D)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)Z"));
}
// Check compatibility - "Set" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;ID)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;ID)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;I)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;I)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndSet" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet;
- EXPECT_TRUE(
- vh->IsMethodTypeCompatible(
- access_mode,
- MethodTypeOf("(Ljava/nio/ByteBuffer;IDD)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode,
- MethodTypeOf("(Ljava/nio/ByteBuffer;IDI)D")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;IDD)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;IDI)D"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;I)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndExchange" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;IDD)D")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;IDD)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;II)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(III)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;IDD)D"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;IDD)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;II)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(III)V"));
}
// Check compatibility - "GetAndUpdate" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;ID)D")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;ID)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;ID)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;ID)D"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;ID)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;ID)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(II)V"));
}
// Check synthesized method types match expected forms.
diff --git a/runtime/var_handles.cc b/runtime/var_handles.cc
new file mode 100644
index 0000000000..d71745e531
--- /dev/null
+++ b/runtime/var_handles.cc
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 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_handles.h"
+
+#include "common_throws.h"
+#include "dex/dex_instruction.h"
+#include "handle.h"
+#include "method_handles-inl.h"
+#include "mirror/method_type.h"
+#include "mirror/var_handle.h"
+
+namespace art {
+
+bool VarHandleInvokeAccessor(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::VarHandle> var_handle,
+ Handle<mirror::MethodType> callsite_type,
+ const mirror::VarHandle::AccessMode access_mode,
+ const InstructionOperands* const operands,
+ JValue* result) {
+ if (var_handle.IsNull()) {
+ ThrowNullPointerExceptionFromDexPC();
+ return false;
+ }
+
+ if (!var_handle->IsAccessModeSupported(access_mode)) {
+ ThrowUnsupportedOperationException();
+ return false;
+ }
+
+ mirror::VarHandle::MatchKind match_kind =
+ var_handle->GetMethodTypeMatchForAccessMode(access_mode, callsite_type.Get());
+ if (match_kind == mirror::VarHandle::MatchKind::kExact) {
+ return var_handle->Access(access_mode, &shadow_frame, operands, result);
+ }
+ if (match_kind == mirror::VarHandle::MatchKind::kNone) {
+ ThrowWrongMethodTypeException(var_handle->GetMethodTypeForAccessMode(self, access_mode),
+ callsite_type.Get());
+ return false;
+ }
+ DCHECK_EQ(mirror::VarHandle::MatchKind::kWithConversions, match_kind);
+
+ StackHandleScope<1> hs(self);
+ Handle<mirror::MethodType> accessor_type(hs.NewHandle(
+ var_handle->GetMethodTypeForAccessMode(self, access_mode)));
+ const size_t num_vregs = accessor_type->NumberOfVRegs();
+ const int num_params = accessor_type->GetPTypes()->GetLength();
+ ShadowFrameAllocaUniquePtr accessor_frame =
+ CREATE_SHADOW_FRAME(num_vregs, nullptr, shadow_frame.GetMethod(), shadow_frame.GetDexPC());
+ ShadowFrameGetter getter(shadow_frame, operands);
+ static const uint32_t kFirstDestinationReg = 0;
+ ShadowFrameSetter setter(accessor_frame.get(), kFirstDestinationReg);
+ if (!PerformConversions(self, callsite_type, accessor_type, &getter, &setter, num_params)) {
+ return false;
+ }
+ RangeInstructionOperands accessor_operands(kFirstDestinationReg,
+ kFirstDestinationReg + num_vregs);
+ if (!var_handle->Access(access_mode, accessor_frame.get(), &accessor_operands, result)) {
+ return false;
+ }
+ return ConvertReturnValue(callsite_type, accessor_type, result);
+}
+
+} // namespace art
diff --git a/runtime/var_handles.h b/runtime/var_handles.h
new file mode 100644
index 0000000000..2ff8405f03
--- /dev/null
+++ b/runtime/var_handles.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 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_VAR_HANDLES_H_
+#define ART_RUNTIME_VAR_HANDLES_H_
+
+#include "mirror/var_handle.h"
+
+namespace art {
+
+bool VarHandleInvokeAccessor(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::VarHandle> var_handle,
+ Handle<mirror::MethodType> callsite_type,
+ const mirror::VarHandle::AccessMode access_mode,
+ const InstructionOperands* const operands,
+ JValue* result)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+} // namespace art
+
+#endif // ART_RUNTIME_VAR_HANDLES_H_
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 92ee98ae8a..91cec23dd5 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -4210,8 +4210,6 @@ bool MethodVerifier::CheckSignaturePolymorphicMethod(ArtMethod* method) {
expected_return_descriptor = mirror::MethodHandle::GetReturnTypeDescriptor(method_name);
} else if (klass == mirror::VarHandle::StaticClass()) {
expected_return_descriptor = mirror::VarHandle::GetReturnTypeDescriptor(method_name);
- // TODO: add compiler support for VarHandle accessor methods (b/71781600)
- Fail(VERIFY_ERROR_FORCE_INTERPRETER);
} else {
Fail(VERIFY_ERROR_BAD_CLASS_HARD)
<< "Signature polymorphic method in unsuppported class: " << klass->PrettyDescriptor();