-
Enhancement
-
Resolution: Unresolved
-
P4
-
19
-
generic
-
generic
A DESCRIPTION OF THE PROBLEM :
h1. Add API to get the {{java.lang.invoke.MethodType}} of a {{java.lang.reflect.Executable}}
h2. Summary
Add a public method to {{java.lang.reflect.Executable}} to get the {{java.lang.invoke.MethodType}} of the executable.
h2. Problem
Getting a {{MethodType}} for a {{java.lang.reflect.Method}} or a {{java.lang.reflect.Constructor}} currently requires calling {{Executable.getParameterTypes()}}, which clones the parameters array, and then calling {{MethodType.methodType(Class<?> rtype, Class<?>[] ptypes)}}, which clones the {{ptypes}} array again, and also the {{MethodType}} instance, if a cache miss occurs in {{MethodType.makeImpl}}.
If this method were implemented in {{java.lang.reflect.Method}} and {{java.lang.reflect.Constructor}}, then the cloning of the parameters array and uncached {{MethodType}}s could be eliminated.
h2. Solution
Add the {{public abstract java.lang.invoke.MethodType methodType()}} method to {{java.lang.reflect.Executable}}, with concrete implementations provided in {{java.lang.reflect.Method}} and {{java.lang.reflect.Constructor}}.
h2. Specification
{code:none}
diff --git a/src/java.base/share/classes/java/lang/invoke/MemberName.java b/src/java.base/share/classes/java/lang/invoke/MemberName.java
--- a/src/java.base/share/classes/java/lang/invoke/MemberName.java
+++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java
@@ -588,7 +588,7 @@ final class MemberName implements Member, Cloneable {
// The JVM did not reify this signature-polymorphic instance.
// Need a special case here.
// See comments on MethodHandleNatives.linkMethod.
- MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes());
+ MethodType type = m.methodType();
int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual);
init(MethodHandle.class, m.getName(), type, flags);
if (isMethodHandleInvoke())
@@ -599,7 +599,7 @@ final class MemberName implements Member, Cloneable {
// The JVM did not reify this signature-polymorphic instance.
// Need a special case here.
// See comments on MethodHandleNatives.linkMethod.
- MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes());
+ MethodType type = m.methodType();
int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual);
init(VarHandle.class, m.getName(), type, flags);
if (isVarHandleMethodInvoke())
diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
@@ -1671,6 +1671,11 @@ abstract class MethodHandleImpl {
public Class<?>[] exceptionTypes(MethodHandle handle) {
return VarHandles.exceptionTypes(handle);
}
+
+ @Override
+ public MethodType makeMethodType(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
+ return MethodType.makeImpl(rtype, ptypes, trusted);
+ }
});
}
diff --git a/src/java.base/share/classes/java/lang/reflect/Constructor.java b/src/java.base/share/classes/java/lang/reflect/Constructor.java
--- a/src/java.base/share/classes/java/lang/reflect/Constructor.java
+++ b/src/java.base/share/classes/java/lang/reflect/Constructor.java
@@ -40,6 +40,7 @@ import sun.reflect.generics.factory.GenericsFactory;
import sun.reflect.generics.scope.ConstructorScope;
import java.lang.annotation.Annotation;
import java.lang.annotation.AnnotationFormatError;
+import java.lang.invoke.MethodType;
import java.util.StringJoiner;
/**
@@ -270,8 +271,19 @@ public final class Constructor<T> extends Executable {
* {@inheritDoc}
* @since 1.8
*/
+ @Override
public int getParameterCount() { return parameterTypes.length; }
+ /**
+ * {@inheritDoc}
+ * @since 19
+ */
+ @Override
+ public MethodType methodType() {
+ return SharedSecrets.getJavaLangInvokeAccess().
+ makeMethodType(void.class, parameterTypes.clone(), true);
+ }
+
/**
* {@inheritDoc}
* @throws GenericSignatureFormatError {@inheritDoc}
diff --git a/src/java.base/share/classes/java/lang/reflect/Executable.java b/src/java.base/share/classes/java/lang/reflect/Executable.java
--- a/src/java.base/share/classes/java/lang/reflect/Executable.java
+++ b/src/java.base/share/classes/java/lang/reflect/Executable.java
@@ -26,6 +26,7 @@
package java.lang.reflect;
import java.lang.annotation.*;
+import java.lang.invoke.MethodType;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
@@ -257,6 +258,15 @@ public abstract sealed class Executable extends AccessibleObject
throw new AbstractMethodError();
}
+ /**
+ * Returns the {@link MethodType} for the executable represented by this
+ * object.
+ *
+ * @return The {@link MethodType} for the executable this object represents
+ * @since 19
+ */
+ public abstract MethodType methodType();
+
/**
* Returns an array of {@code Type} objects that represent the
* formal parameter types, in declaration order, of the executable
diff --git a/src/java.base/share/classes/java/lang/reflect/Method.java b/src/java.base/share/classes/java/lang/reflect/Method.java
--- a/src/java.base/share/classes/java/lang/reflect/Method.java
+++ b/src/java.base/share/classes/java/lang/reflect/Method.java
@@ -44,6 +44,7 @@ import sun.reflect.annotation.AnnotationType;
import sun.reflect.annotation.AnnotationParser;
import java.lang.annotation.Annotation;
import java.lang.annotation.AnnotationFormatError;
+import java.lang.invoke.MethodType;
import java.nio.ByteBuffer;
import java.util.StringJoiner;
@@ -319,8 +320,18 @@ public final class Method extends Executable {
* {@inheritDoc}
* @since 1.8
*/
+ @Override
public int getParameterCount() { return parameterTypes.length; }
+ /**
+ * {@inheritDoc}
+ * @since 19
+ */
+ @Override
+ public MethodType methodType() {
+ return SharedSecrets.getJavaLangInvokeAccess().
+ makeMethodType(returnType, parameterTypes.clone(), true);
+ }
/**
* {@inheritDoc}
diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java
--- a/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java
+++ b/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java
@@ -188,4 +188,10 @@ public interface JavaLangInvokeAccess {
* @return an array of exceptions, or {@code null}.
*/
Class<?>[] exceptionTypes(MethodHandle handle);
+
+ /**
+ * Returns the {@code MethodType} for the given return and parameter types.
+ * If {@code trusted} is true, then the ptypes array is not cloned.
+ */
+ MethodType makeMethodType(Class<?> rtype, Class<?>[] ptypes, boolean trusted);
}
{code}
h1. Add API to get the {{java.lang.invoke.MethodType}} of a {{java.lang.reflect.Executable}}
h2. Summary
Add a public method to {{java.lang.reflect.Executable}} to get the {{java.lang.invoke.MethodType}} of the executable.
h2. Problem
Getting a {{MethodType}} for a {{java.lang.reflect.Method}} or a {{java.lang.reflect.Constructor}} currently requires calling {{Executable.getParameterTypes()}}, which clones the parameters array, and then calling {{MethodType.methodType(Class<?> rtype, Class<?>[] ptypes)}}, which clones the {{ptypes}} array again, and also the {{MethodType}} instance, if a cache miss occurs in {{MethodType.makeImpl}}.
If this method were implemented in {{java.lang.reflect.Method}} and {{java.lang.reflect.Constructor}}, then the cloning of the parameters array and uncached {{MethodType}}s could be eliminated.
h2. Solution
Add the {{public abstract java.lang.invoke.MethodType methodType()}} method to {{java.lang.reflect.Executable}}, with concrete implementations provided in {{java.lang.reflect.Method}} and {{java.lang.reflect.Constructor}}.
h2. Specification
{code:none}
diff --git a/src/java.base/share/classes/java/lang/invoke/MemberName.java b/src/java.base/share/classes/java/lang/invoke/MemberName.java
--- a/src/java.base/share/classes/java/lang/invoke/MemberName.java
+++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java
@@ -588,7 +588,7 @@ final class MemberName implements Member, Cloneable {
// The JVM did not reify this signature-polymorphic instance.
// Need a special case here.
// See comments on MethodHandleNatives.linkMethod.
- MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes());
+ MethodType type = m.methodType();
int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual);
init(MethodHandle.class, m.getName(), type, flags);
if (isMethodHandleInvoke())
@@ -599,7 +599,7 @@ final class MemberName implements Member, Cloneable {
// The JVM did not reify this signature-polymorphic instance.
// Need a special case here.
// See comments on MethodHandleNatives.linkMethod.
- MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes());
+ MethodType type = m.methodType();
int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual);
init(VarHandle.class, m.getName(), type, flags);
if (isVarHandleMethodInvoke())
diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
@@ -1671,6 +1671,11 @@ abstract class MethodHandleImpl {
public Class<?>[] exceptionTypes(MethodHandle handle) {
return VarHandles.exceptionTypes(handle);
}
+
+ @Override
+ public MethodType makeMethodType(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
+ return MethodType.makeImpl(rtype, ptypes, trusted);
+ }
});
}
diff --git a/src/java.base/share/classes/java/lang/reflect/Constructor.java b/src/java.base/share/classes/java/lang/reflect/Constructor.java
--- a/src/java.base/share/classes/java/lang/reflect/Constructor.java
+++ b/src/java.base/share/classes/java/lang/reflect/Constructor.java
@@ -40,6 +40,7 @@ import sun.reflect.generics.factory.GenericsFactory;
import sun.reflect.generics.scope.ConstructorScope;
import java.lang.annotation.Annotation;
import java.lang.annotation.AnnotationFormatError;
+import java.lang.invoke.MethodType;
import java.util.StringJoiner;
/**
@@ -270,8 +271,19 @@ public final class Constructor<T> extends Executable {
* {@inheritDoc}
* @since 1.8
*/
+ @Override
public int getParameterCount() { return parameterTypes.length; }
+ /**
+ * {@inheritDoc}
+ * @since 19
+ */
+ @Override
+ public MethodType methodType() {
+ return SharedSecrets.getJavaLangInvokeAccess().
+ makeMethodType(void.class, parameterTypes.clone(), true);
+ }
+
/**
* {@inheritDoc}
* @throws GenericSignatureFormatError {@inheritDoc}
diff --git a/src/java.base/share/classes/java/lang/reflect/Executable.java b/src/java.base/share/classes/java/lang/reflect/Executable.java
--- a/src/java.base/share/classes/java/lang/reflect/Executable.java
+++ b/src/java.base/share/classes/java/lang/reflect/Executable.java
@@ -26,6 +26,7 @@
package java.lang.reflect;
import java.lang.annotation.*;
+import java.lang.invoke.MethodType;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
@@ -257,6 +258,15 @@ public abstract sealed class Executable extends AccessibleObject
throw new AbstractMethodError();
}
+ /**
+ * Returns the {@link MethodType} for the executable represented by this
+ * object.
+ *
+ * @return The {@link MethodType} for the executable this object represents
+ * @since 19
+ */
+ public abstract MethodType methodType();
+
/**
* Returns an array of {@code Type} objects that represent the
* formal parameter types, in declaration order, of the executable
diff --git a/src/java.base/share/classes/java/lang/reflect/Method.java b/src/java.base/share/classes/java/lang/reflect/Method.java
--- a/src/java.base/share/classes/java/lang/reflect/Method.java
+++ b/src/java.base/share/classes/java/lang/reflect/Method.java
@@ -44,6 +44,7 @@ import sun.reflect.annotation.AnnotationType;
import sun.reflect.annotation.AnnotationParser;
import java.lang.annotation.Annotation;
import java.lang.annotation.AnnotationFormatError;
+import java.lang.invoke.MethodType;
import java.nio.ByteBuffer;
import java.util.StringJoiner;
@@ -319,8 +320,18 @@ public final class Method extends Executable {
* {@inheritDoc}
* @since 1.8
*/
+ @Override
public int getParameterCount() { return parameterTypes.length; }
+ /**
+ * {@inheritDoc}
+ * @since 19
+ */
+ @Override
+ public MethodType methodType() {
+ return SharedSecrets.getJavaLangInvokeAccess().
+ makeMethodType(returnType, parameterTypes.clone(), true);
+ }
/**
* {@inheritDoc}
diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java
--- a/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java
+++ b/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java
@@ -188,4 +188,10 @@ public interface JavaLangInvokeAccess {
* @return an array of exceptions, or {@code null}.
*/
Class<?>[] exceptionTypes(MethodHandle handle);
+
+ /**
+ * Returns the {@code MethodType} for the given return and parameter types.
+ * If {@code trusted} is true, then the ptypes array is not cloned.
+ */
+ MethodType makeMethodType(Class<?> rtype, Class<?>[] ptypes, boolean trusted);
}
{code}