Refine VarHandle::GetMethodTypeMatchForAccessMode()
Treat assignable types as exact to broaden cases in the runtime that
take the faster path. Also treat parameters of type j.l.Void as
assignable since this means the parameter value is null.
Remove unused VarHandle::IsInvokerMethodTypeCompatible().
Bug: 65872996
Test: art/test.py --host -r -t 712
Test: m test-art-host-gtest
Change-Id: I0aea10b53d03a1a13ff23dfedaeb0d1c75c3f1ff
diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc
index 9a78758..202134a 100644
--- a/runtime/mirror/var_handle.cc
+++ b/runtime/mirror/var_handle.cc
@@ -1429,18 +1429,19 @@
ObjPtr<VarHandle> vh = this;
ObjPtr<Class> var_type = vh->GetVarType();
ObjPtr<Class> mt_rtype = method_type->GetRType();
+ ObjPtr<Class> void_type = WellKnownClasses::ToClass(WellKnownClasses::java_lang_Void);
AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode);
- // 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);
- if (vh_rtype != mt_rtype) {
- if (!IsReturnTypeConvertible(vh_rtype, mt_rtype)) {
- return MatchKind::kNone;
- }
- match = MatchKind::kWithConversions;
+ // Check return type first.
+ ObjPtr<Class> vh_rtype = GetReturnType(access_mode_template, var_type);
+ if (mt_rtype->GetPrimitiveType() != Primitive::Type::kPrimVoid &&
+ !mt_rtype->IsAssignableFrom(vh_rtype)) {
+ // Call-site is an expression (expects a return value) and the value returned by the accessor
+ // is not assignable to the expected return type.
+ if (!IsReturnTypeConvertible(vh_rtype, mt_rtype)) {
+ return MatchKind::kNone;
}
+ match = MatchKind::kWithConversions;
}
// Check the number of parameters matches.
@@ -1457,7 +1458,12 @@
// 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]) {
+ if (vh_ptypes[i]->IsAssignableFrom(mt_ptypes->Get(i))) {
+ continue;
+ }
+ if (mt_ptypes->Get(i) == void_type && !vh_ptypes[i]->IsPrimitive()) {
+ // The expected parameter is a reference and the parameter type from the call site is j.l.Void
+ // which means the value is null. It is always valid for a reference parameter to be null.
continue;
}
if (!IsParameterTypeConvertible(mt_ptypes->Get(i), vh_ptypes[i])) {
@@ -1468,47 +1474,6 @@
return match;
}
-bool VarHandle::IsInvokerMethodTypeCompatible(AccessMode access_mode,
- ObjPtr<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()));
- 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 the number of parameters matches (ignoring the VarHandle parameter).
- static const int32_t kVarHandleParameters = 1;
- ObjPtr<Class> vh_ptypes[VarHandle::kMaxAccessorParameters];
- const int32_t vh_ptypes_count = BuildParameterArray(vh_ptypes,
- access_mode_template,
- var_type.Get(),
- GetCoordinateType0(),
- GetCoordinateType1());
- if (vh_ptypes_count != method_type->GetPTypes()->GetLength() - kVarHandleParameters) {
- return false;
- }
-
- // Check the parameter types are compatible (ignoring the VarHandle parameter).
- ObjPtr<ObjectArray<Class>> mt_ptypes = method_type->GetPTypes();
- for (int32_t i = 0; i < vh_ptypes_count; ++i) {
- if (!IsParameterTypeConvertible(mt_ptypes->Get(i + kVarHandleParameters), vh_ptypes[i])) {
- return false;
- }
- }
- return true;
-}
-
ObjPtr<MethodType> VarHandle::GetMethodTypeForAccessMode(Thread* self,
ObjPtr<VarHandle> var_handle,
AccessMode access_mode) {
diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h
index 01920bd..83cf2e1 100644
--- a/runtime/mirror/var_handle.h
+++ b/runtime/mirror/var_handle.h
@@ -111,13 +111,6 @@
MatchKind GetMethodTypeMatchForAccessMode(AccessMode access_mode, ObjPtr<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, ObjPtr<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
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 8f0581e..3b3a1a3 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -75,6 +75,7 @@
jclass WellKnownClasses::java_lang_Thread;
jclass WellKnownClasses::java_lang_ThreadGroup;
jclass WellKnownClasses::java_lang_Throwable;
+jclass WellKnownClasses::java_lang_Void;
jclass WellKnownClasses::java_nio_Buffer;
jclass WellKnownClasses::java_nio_ByteBuffer;
jclass WellKnownClasses::java_nio_DirectByteBuffer;
@@ -366,6 +367,7 @@
java_lang_Thread = CacheClass(env, "java/lang/Thread");
java_lang_ThreadGroup = CacheClass(env, "java/lang/ThreadGroup");
java_lang_Throwable = CacheClass(env, "java/lang/Throwable");
+ java_lang_Void = CacheClass(env, "java/lang/Void");
java_nio_Buffer = CacheClass(env, "java/nio/Buffer");
java_nio_ByteBuffer = CacheClass(env, "java/nio/ByteBuffer");
java_nio_DirectByteBuffer = CacheClass(env, "java/nio/DirectByteBuffer");
@@ -543,6 +545,7 @@
java_lang_Thread = nullptr;
java_lang_ThreadGroup = nullptr;
java_lang_Throwable = nullptr;
+ java_lang_Void = nullptr;
java_util_Collections = nullptr;
java_nio_Buffer = nullptr;
java_nio_ByteBuffer = nullptr;
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 35c007d..b2e01ae 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -88,6 +88,7 @@
static jclass java_lang_Thread;
static jclass java_lang_ThreadGroup;
static jclass java_lang_Throwable;
+ static jclass java_lang_Void;
static jclass java_nio_Buffer;
static jclass java_nio_ByteBuffer;
static jclass java_nio_DirectByteBuffer;