diff options
| -rw-r--r-- | runtime/Android.bp | 1 | ||||
| -rw-r--r-- | runtime/entrypoints/quick/quick_trampoline_entrypoints.cc | 52 | ||||
| -rw-r--r-- | runtime/interpreter/interpreter_common.cc | 85 | ||||
| -rw-r--r-- | runtime/mirror/var_handle.cc | 53 | ||||
| -rw-r--r-- | runtime/mirror/var_handle.h | 28 | ||||
| -rw-r--r-- | runtime/mirror/var_handle_test.cc | 264 | ||||
| -rw-r--r-- | runtime/var_handles.cc | 78 | ||||
| -rw-r--r-- | runtime/var_handles.h | 35 | ||||
| -rw-r--r-- | runtime/verifier/method_verifier.cc | 2 |
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(); |