changeset 53728:9da7233f3060 jep-334

Consolidate MethodHandleDesc.of() factories
author briangoetz
date Fri, 30 Nov 2018 14:55:32 -0500
parents 7367af6ffbe1
children 0f5b0f28d6b0
files src/java.base/share/classes/java/lang/constant/AsTypeMethodHandleDesc.java src/java.base/share/classes/java/lang/constant/ConstantDescs.java src/java.base/share/classes/java/lang/constant/DirectMethodHandleDesc.java src/java.base/share/classes/java/lang/constant/DirectMethodHandleDescImpl.java src/java.base/share/classes/java/lang/constant/DynamicCallSiteDesc.java src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java src/java.base/share/classes/java/lang/invoke/MethodHandle.java test/jdk/java/lang/constant/CondyDescTest.java test/jdk/java/lang/constant/IndyDescTest.java test/jdk/java/lang/constant/MethodHandleDescTest.java
diffstat 11 files changed, 231 insertions(+), 139 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/constant/AsTypeMethodHandleDesc.java	Fri Nov 30 12:43:55 2018 -0500
+++ b/src/java.base/share/classes/java/lang/constant/AsTypeMethodHandleDesc.java	Fri Nov 30 14:55:32 2018 -0500
@@ -51,7 +51,7 @@
     }
 
     @Override
-    public MethodTypeDesc methodType() {
+    public MethodTypeDesc invocationType() {
         return type;
     }
 
--- a/src/java.base/share/classes/java/lang/constant/ConstantDescs.java	Fri Nov 30 12:43:55 2018 -0500
+++ b/src/java.base/share/classes/java/lang/constant/ConstantDescs.java	Fri Nov 30 14:55:32 2018 -0500
@@ -38,6 +38,7 @@
 import java.util.Map;
 import java.util.Set;
 
+import static java.lang.constant.DirectMethodHandleDesc.*;
 import static java.lang.constant.DirectMethodHandleDesc.Kind.STATIC;
 
 /**
@@ -251,8 +252,8 @@
                                           DEFAULT_NAME, ConstantDescs.CD_Object);
 
     static final DirectMethodHandleDesc MHD_METHODHANDLE_ASTYPE
-            = MethodHandleDesc.of(DirectMethodHandleDesc.Kind.VIRTUAL, CD_MethodHandle, "asType",
-            CD_MethodHandle, CD_MethodType);
+            = MethodHandleDesc.ofMethod(Kind.VIRTUAL, CD_MethodHandle, "asType",
+                                        MethodTypeDesc.of(CD_MethodHandle, CD_MethodType));
     /**
      * Return a {@link MethodHandleDesc} corresponding to a bootstrap method for
      * an {@code invokedynamic} callsite, which is a static method whose leading
@@ -270,8 +271,8 @@
                                                              String name,
                                                              ClassDesc returnType,
                                                              ClassDesc... paramTypes) {
-        return MethodHandleDesc.of(STATIC, clazz, name, MethodTypeDesc.of(returnType, paramTypes)
-                                                                      .insertParameterTypes(0, INDY_BOOTSTRAP_ARGS));
+        return MethodHandleDesc.ofMethod(STATIC, clazz, name, MethodTypeDesc.of(returnType, paramTypes)
+                                                                            .insertParameterTypes(0, INDY_BOOTSTRAP_ARGS));
     }
 
     /**
@@ -291,7 +292,7 @@
                                                              String name,
                                                              ClassDesc returnType,
                                                              ClassDesc... paramTypes) {
-        return MethodHandleDesc.of(STATIC, clazz, name, MethodTypeDesc.of(returnType, paramTypes)
-                                                                      .insertParameterTypes(0, CONDY_BOOTSTRAP_ARGS));
+        return MethodHandleDesc.ofMethod(STATIC, clazz, name, MethodTypeDesc.of(returnType, paramTypes)
+                                                                            .insertParameterTypes(0, CONDY_BOOTSTRAP_ARGS));
     }
 }
--- a/src/java.base/share/classes/java/lang/constant/DirectMethodHandleDesc.java	Fri Nov 30 12:43:55 2018 -0500
+++ b/src/java.base/share/classes/java/lang/constant/DirectMethodHandleDesc.java	Fri Nov 30 14:55:32 2018 -0500
@@ -188,6 +188,23 @@
                 }
             }
         }
+
+        /**
+         * Does this {@code Kind} correspond to a virtual method invocation?
+         *
+         * @return if this {@code Kind} corresponds to a virtual method invocation
+         */
+        boolean isVirtualMethod() {
+            switch (this) {
+                case VIRTUAL:
+                case SPECIAL:
+                case INTERFACE_VIRTUAL:
+                case INTERFACE_SPECIAL:
+                    return true;
+                default:
+                    return false;
+            }
+        }
     }
 
     /**
@@ -229,10 +246,13 @@
     String methodName();
 
     /**
-     * Return a {@link MethodTypeDesc} describing the invocation type of the
-     * method handle described by this nominal descriptor
+     * Return the lookup descriptor of the method handle described by this descriptor,
+     * after adjusting for the invocation mode.  This will correspond to either
+     * a method type descriptor string (for methods and constructors), or a field
+     * descriptor string (for field access method handles).  The lookup descriptor
+     * string is in the same format as accepted by {@link MethodHandleDesc#of(Kind, ClassDesc, String, String)}.
      *
-     * @return the method type
+     * @return the lookup descriptor string
      */
-    MethodTypeDesc methodType();
+    String lookupDescriptor();
 }
--- a/src/java.base/share/classes/java/lang/constant/DirectMethodHandleDescImpl.java	Fri Nov 30 12:43:55 2018 -0500
+++ b/src/java.base/share/classes/java/lang/constant/DirectMethodHandleDescImpl.java	Fri Nov 30 14:55:32 2018 -0500
@@ -29,6 +29,7 @@
 import java.lang.invoke.MethodType;
 import java.util.Objects;
 
+import static java.lang.constant.ConstantDescs.CD_void;
 import static java.lang.constant.ConstantUtils.validateClassOrInterface;
 import static java.lang.constant.ConstantUtils.validateMemberName;
 import static java.lang.constant.DirectMethodHandleDesc.Kind.CONSTRUCTOR;
@@ -44,7 +45,7 @@
     private final Kind kind;
     private final ClassDesc owner;
     private final String name;
-    private final MethodTypeDesc type;
+    private final MethodTypeDesc invocationType;
 
     /**
      * Construct a {@linkplain DirectMethodHandleDescImpl} for a method or field
@@ -53,7 +54,7 @@
      * @param kind the kind of the method handle
      * @param owner the declaring class or interface for the method
      * @param name the unqualified name of the method (ignored if {@code kind} is {@code CONSTRUCTOR})
-     * @param type the type of the method
+     * @param type the lookup type of the method
      * @throws NullPointerException if any non-ignored argument is null
      * @throws IllegalArgumentException if {@code kind} describes a field accessor,
      * and {@code type} is not consistent with that kind of field accessor, or if
@@ -81,7 +82,12 @@
         this.kind = kind;
         this.owner = owner;
         this.name = name;
-        this.type = type;
+        if (kind.isVirtualMethod())
+            this.invocationType = type.insertParameterTypes(0, owner);
+        else if (kind == CONSTRUCTOR)
+            this.invocationType = type.changeReturnType(owner);
+        else
+            this.invocationType = type;
     }
 
     private static void validateFieldType(MethodTypeDesc type, boolean isSetter, boolean isVirtual) {
@@ -122,34 +128,60 @@
     }
 
     @Override
-    public MethodTypeDesc methodType() {
-        return type;
+    public MethodTypeDesc invocationType() {
+        return invocationType;
+    }
+
+    @Override
+    public String lookupDescriptor() {
+        switch (kind) {
+            case VIRTUAL:
+            case SPECIAL:
+            case INTERFACE_VIRTUAL:
+            case INTERFACE_SPECIAL:
+                return invocationType.dropParameterTypes(0, 1).descriptorString();
+            case STATIC:
+            case INTERFACE_STATIC:
+                return invocationType.descriptorString();
+            case CONSTRUCTOR:
+                return invocationType.changeReturnType(CD_void).descriptorString();
+            case GETTER:
+            case STATIC_GETTER:
+                return invocationType.returnType().descriptorString();
+            case SETTER:
+                return invocationType.parameterType(1).descriptorString();
+            case STATIC_SETTER:
+                return invocationType.parameterType(0).descriptorString();
+            default:
+                throw new IllegalStateException(kind.toString());
+        }
     }
 
     public MethodHandle resolveConstantDesc(MethodHandles.Lookup lookup)
             throws ReflectiveOperationException {
         Class<?> resolvedOwner = (Class<?>) owner.resolveConstantDesc(lookup);
-        MethodType resolvedType = (MethodType) this.type.resolveConstantDesc(lookup);
+        MethodType invocationType = (MethodType) this.invocationType().resolveConstantDesc(lookup);
         switch (kind) {
             case STATIC:
             case INTERFACE_STATIC:
-                return lookup.findStatic(resolvedOwner, name, resolvedType);
+                return lookup.findStatic(resolvedOwner, name, invocationType);
             case INTERFACE_VIRTUAL:
             case VIRTUAL:
-                return lookup.findVirtual(resolvedOwner, name, resolvedType);
+                return lookup.findVirtual(resolvedOwner, name, invocationType.dropParameterTypes(0, 1));
             case SPECIAL:
             case INTERFACE_SPECIAL:
-                return lookup.findSpecial(resolvedOwner, name, resolvedType, lookup.lookupClass());
+                return lookup.findSpecial(resolvedOwner, name, invocationType.dropParameterTypes(0, 1),
+                                          lookup.lookupClass());
             case CONSTRUCTOR:
-                return lookup.findConstructor(resolvedOwner, resolvedType);
+                return lookup.findConstructor(resolvedOwner, invocationType.changeReturnType(void.class));
             case GETTER:
-                return lookup.findGetter(resolvedOwner, name, resolvedType.returnType());
+                return lookup.findGetter(resolvedOwner, name, invocationType.returnType());
             case STATIC_GETTER:
-                return lookup.findStaticGetter(resolvedOwner, name, resolvedType.returnType());
+                return lookup.findStaticGetter(resolvedOwner, name, invocationType.returnType());
             case SETTER:
-                return lookup.findSetter(resolvedOwner, name, resolvedType.parameterType(1));
+                return lookup.findSetter(resolvedOwner, name, invocationType.parameterType(1));
             case STATIC_SETTER:
-                return lookup.findStaticSetter(resolvedOwner, name, resolvedType.parameterType(0));
+                return lookup.findStaticSetter(resolvedOwner, name, invocationType.parameterType(0));
             default:
                 throw new IllegalStateException(kind.name());
         }
@@ -173,16 +205,16 @@
         return kind == desc.kind &&
                Objects.equals(owner, desc.owner) &&
                Objects.equals(name, desc.name) &&
-               Objects.equals(type, desc.type);
+               Objects.equals(invocationType, desc.invocationType);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(kind, owner, name, type);
+        return Objects.hash(kind, owner, name, invocationType);
     }
 
     @Override
     public String toString() {
-        return String.format("MethodHandleDesc[%s/%s::%s%s]", kind, owner.displayName(), name, type.displayDescriptor());
+        return String.format("MethodHandleDesc[%s/%s::%s%s]", kind, owner.displayName(), name, invocationType.displayDescriptor());
     }
 }
--- a/src/java.base/share/classes/java/lang/constant/DynamicCallSiteDesc.java	Fri Nov 30 12:43:55 2018 -0500
+++ b/src/java.base/share/classes/java/lang/constant/DynamicCallSiteDesc.java	Fri Nov 30 14:55:32 2018 -0500
@@ -228,7 +228,7 @@
      * @throws Throwable if any exception is thrown by the bootstrap method
      */
     public CallSite resolveCallSiteDesc(MethodHandles.Lookup lookup) throws Throwable {
-        assert bootstrapMethod.methodType().parameterType(1).equals(CD_String);
+        assert bootstrapMethod.invocationType().parameterType(1).equals(CD_String);
         MethodHandle bsm = (MethodHandle) bootstrapMethod.resolveConstantDesc(lookup);
         Object[] args = new Object[bootstrapArgs.length + 3];
         args[0] = lookup;
--- a/src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java	Fri Nov 30 12:43:55 2018 -0500
+++ b/src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java	Fri Nov 30 14:55:32 2018 -0500
@@ -190,7 +190,7 @@
      */
     public static<T> DynamicConstantDesc<T> of(DirectMethodHandleDesc bootstrapMethod,
                                                ConstantDesc... bootstrapArgs) {
-        return ofNamed(bootstrapMethod, DEFAULT_NAME, bootstrapMethod.methodType().returnType(), bootstrapArgs);
+        return ofNamed(bootstrapMethod, DEFAULT_NAME, bootstrapMethod.invocationType().returnType(), bootstrapArgs);
     }
 
     /**
--- a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java	Fri Nov 30 12:43:55 2018 -0500
+++ b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java	Fri Nov 30 14:55:32 2018 -0500
@@ -25,6 +25,7 @@
 package java.lang.constant;
 
 import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 
 import static java.lang.constant.ConstantDescs.CD_void;
@@ -48,98 +49,93 @@
      * Create a {@linkplain MethodHandleDesc} corresponding to an invocation of a
      * declared method, invocation of a constructor, or access to a field.
      *
-     * <p>If {@code kind} is {@code CONSTRUCTOR}, the name is ignored and the return
-     * type of the invocation type must be {@code void}.  If {@code kind} corresponds
-     * to a field access, the invocation type must be consistent with that kind
-     * of field access and the type of the field; instance field accessors must
-     * take a leading receiver parameter, getters must return the type of the
-     * field, setters must take a new value for the field and return {@code void}.
-     *
-     * <p>For constructor and field access, the methods {@link #ofField(DirectMethodHandleDesc.Kind, ClassDesc, String, ClassDesc)}
-     * and {@link #ofConstructor(ClassDesc, ClassDesc...)} may be more convenient.
+     * <p>The lookup descriptor string has the same format as for the various
+     * variants of {@code CONSTANT_MethodHandle_info} and for the lookup
+     * methods on {@link MethodHandles.Lookup}.  For a method or constructor
+     * invocation, it is interpreted as a method type descriptor; for field
+     * access, it is interpreted as a field descriptor.  If {@code kind} is
+     * {@code CONSTRUCTOR}, the {@code name} parameter is ignored and the return
+     * type of the lookup descriptor must be {@code void}.  If {@code kind}
+     * corresponds to a virtual method invocation, the lookup type includes the
+     * method parameters but not the receiver type.
      *
      * @param kind The kind of method handle to be described
      * @param clazz a {@link ClassDesc} describing the class containing the
      *              method, constructor, or field
-     * @param name the unqualified name of the method or field (ignored if {@code kind} is {@code CONSTRUCTOR})
-     * @param type a {@link MethodTypeDesc} describing the invocation type of
-     *             the method handle
-     * @return the {@linkplain MethodHandleDesc}
-     * @throws NullPointerException if any non-ignored arguments are null
-     * @throws IllegalArgumentException if the {@code name} has the incorrect
-     * format
-     * @jvms 4.2.2 Unqualified Names
-     */
-    static DirectMethodHandleDesc of(DirectMethodHandleDesc.Kind kind,
-                                     ClassDesc clazz,
-                                     String name,
-                                     MethodTypeDesc type) {
-        return new DirectMethodHandleDescImpl(kind, clazz, name, type);
-    }
-
-    /**
-     * Create a {@linkplain MethodHandleDesc} corresponding to an invocation of a
-     * declared method, invocation of a constructor, or access to a field.
-     *
-     * <p>If {@code kind} is {@code CONSTRUCTOR}, the name is ignored and the return
-     * type of the invocation type must be {@code void}.  If {@code kind} corresponds
-     * to a field access, the invocation type must be consistent with that kind
-     * of field access and the type of the field; instance field accessors must
-     * take a leading receiver parameter, getters must return the type of the
-     * field, setters must take a new value for the field and return {@code void}.
-     * The method {@link #ofField(DirectMethodHandleDesc.Kind, ClassDesc, String, ClassDesc)} will construct
-     * the appropriate invocation given the type of the field.
-     *
-     * @param kind The kind of method handle to be described
-     * @param clazz a {@link ClassDesc} describing the class containing the
-     *              method, constructor, or field
-     * @param name the unqualified name of the method or field (ignored if {@code kind} is {@code CONSTRUCTOR})
-     * @param descriptorString a method descriptor string for the invocation type
-     * of the method handle
+     * @param name the unqualified name of the method or field (ignored if
+     *             {@code kind} is {@code CONSTRUCTOR})
+     * @param lookupDescriptor a method descriptor string the lookup type,
+     *                         if the request is for a method invocation, or
+     *                         describing the invocation type, if the request is
+     *                         for a field or constructor
      * @return the {@linkplain MethodHandleDesc}
      * @throws NullPointerException if any of the non-ignored arguments are null
+     * @jvms 4.4.8 The CONSTANT_MethodHandle_info Structure
      * @jvms 4.2.2 Unqualified Names
+     * @jvms 4.3.2 Field Descriptors
      * @jvms 4.3.3 Method Descriptors
      */
     static DirectMethodHandleDesc of(DirectMethodHandleDesc.Kind kind,
                                      ClassDesc clazz,
                                      String name,
-                                     String descriptorString) {
-        return of(kind, clazz, name, MethodTypeDesc.ofDescriptor(descriptorString));
+                                     String lookupDescriptor) {
+        switch (kind) {
+            case GETTER:
+            case SETTER:
+            case STATIC_GETTER:
+            case STATIC_SETTER:
+                return ofField(kind, clazz, name, ClassDesc.ofDescriptor(lookupDescriptor));
+            default:
+                return new DirectMethodHandleDescImpl(kind, clazz, name, MethodTypeDesc.ofDescriptor(lookupDescriptor));
+        }
     }
 
     /**
      * Create a {@linkplain MethodHandleDesc} corresponding to an invocation of a
-     * declared method, invocation of a constructor, or access to a field.
+     * declared method or constructor.
      *
-     * <p>If {@code kind} is {@code CONSTRUCTOR}, the name is ignored and the return
-     * type of the invocation type must be {@code void}.  If {@code kind} corresponds
-     * to a field access, the invocation type must be consistent with that kind
-     * of field access and the type of the field; instance field accessors must
-     * take a leading receiver parameter, getters must return the type of the
-     * field, setters must take a new value for the field and return {@code void}.
-     * The method {@link #ofField(DirectMethodHandleDesc.Kind, ClassDesc, String, ClassDesc)} will construct
-     * the appropriate invocation given the type of the field.
+     * <p>The lookup descriptor string has the same format as for the lookup
+     * methods on {@link MethodHandles.Lookup}.  If {@code kind} is
+     * {@code CONSTRUCTOR}, the name is ignored and the return type of the lookup
+     * type must be {@code void}.  If {@code kind} corresponds to a virtual method
+     * invocation, the lookup type includes the method parameters but not the
+     * receiver type.
      *
-     * @param kind The kind of method handle to be described
+     * @param kind The kind of method handle to be described; must be one of
+     *             {@code SPECIAL, VIRTUAL, STATIC, INTERFACE_SPECIAL,
+     *             INTERFACE_VIRTUAL, INTERFACE_STATIC, CONSTRUCTOR}
      * @param clazz a {@link ClassDesc} describing the class containing the
-     *              method, constructor, or field
-     * @param name the unqualified name of the method or field (ignored if {@code kind} is
-     * {@code CONSTRUCTOR})
-     * @param returnType a {@link ClassDesc} describing the return type of the
-     *                   method handle
-     * @param paramTypes {@link ClassDesc}s describing the parameter types of
-     *                                    the method handle
+     *              method or constructor
+     * @param name the unqualified name of the method (ignored if {@code kind}
+     *             is {@code CONSTRUCTOR})
+     * @param lookupMethodType a {@link MethodTypeDesc} describing the lookup type
      * @return the {@linkplain MethodHandleDesc}
-     * @throws NullPointerException if any of the non-ignored arguments are null
+     * @throws NullPointerException if any non-ignored arguments are null
+     * @throws IllegalArgumentException if the {@code name} has the incorrect
+     * format, or the kind is invalid
      * @jvms 4.2.2 Unqualified Names
      */
-    static DirectMethodHandleDesc of(DirectMethodHandleDesc.Kind kind,
-                                     ClassDesc clazz,
-                                     String name,
-                                     ClassDesc returnType,
-                                     ClassDesc... paramTypes) {
-        return of(kind, clazz, name, MethodTypeDesc.of(returnType, paramTypes));
+    static DirectMethodHandleDesc ofMethod(DirectMethodHandleDesc.Kind kind,
+                                           ClassDesc clazz,
+                                           String name,
+                                           MethodTypeDesc lookupMethodType) {
+        switch (kind) {
+            case GETTER:
+            case SETTER:
+            case STATIC_GETTER:
+            case STATIC_SETTER:
+                throw new IllegalArgumentException(kind.toString());
+            case VIRTUAL:
+            case SPECIAL:
+            case INTERFACE_VIRTUAL:
+            case INTERFACE_SPECIAL:
+            case INTERFACE_STATIC:
+            case STATIC:
+            case CONSTRUCTOR:
+                return new DirectMethodHandleDescImpl(kind, clazz, name, lookupMethodType);
+            default:
+                throw new IllegalArgumentException(kind.toString());
+        }
     }
 
     /**
@@ -148,8 +144,7 @@
      *
      * @param kind the kind of the method handle to be described; must be one of {@code GETTER},
      *             {@code SETTER}, {@code STATIC_GETTER}, or {@code STATIC_SETTER}
-     * @param clazz a {@link ClassDesc} describing the class containing the
-     *              method, constructor, or field
+     * @param clazz a {@link ClassDesc} describing the class containing the field
      * @param fieldName the unqualified name of the field
      * @param fieldType a {@link ClassDesc} describing the type of the field
      * @return the {@linkplain MethodHandleDesc}
@@ -171,14 +166,14 @@
             default:
                 throw new IllegalArgumentException(kind.toString());
         }
-        return MethodHandleDesc.of(kind, clazz, fieldName, mtr);
+        return new DirectMethodHandleDescImpl(kind, clazz, fieldName, mtr);
     }
 
     /**
      * Return a {@linkplain MethodHandleDesc} corresponding to invocation of a constructor
      *
      * @param clazz a {@link ClassDesc} describing the class containing the
-     *              method, constructor, or field
+     *              constructor
      * @param paramTypes {@link ClassDesc}s describing the parameter types of
      *                   the constructor
      * @return the {@linkplain MethodHandleDesc}
@@ -186,8 +181,8 @@
      */
     static DirectMethodHandleDesc ofConstructor(ClassDesc clazz,
                                                 ClassDesc... paramTypes) {
-        return MethodHandleDesc.of(CONSTRUCTOR, clazz, ConstantDescs.DEFAULT_NAME,
-                                   MethodTypeDesc.of(CD_void, paramTypes));
+        return MethodHandleDesc.ofMethod(CONSTRUCTOR, clazz, ConstantDescs.DEFAULT_NAME,
+                                         MethodTypeDesc.of(CD_void, paramTypes));
     }
 
     /**
@@ -198,14 +193,16 @@
      * @return a {@linkplain MethodHandleDesc} for the adapted method handle
      */
     default MethodHandleDesc asType(MethodTypeDesc type) {
-        return (methodType().equals(type)) ? this : new AsTypeMethodHandleDesc(this, type);
+        return (invocationType().equals(type)) ? this : new AsTypeMethodHandleDesc(this, type);
     }
 
     /**
-     * Return a {@link MethodTypeDesc} describing the type of the method handle
-     * described by this nominal descriptor
+     * Return a {@link MethodTypeDesc} describing the invocation type of the
+     * method handle described by this nominal descriptor.  The invocation type
+     * describes the full set of stack values that are consumed by the invocation
+     * (including the receiver, if any).
      *
      * @return a {@linkplain MethodHandleDesc} describing the method handle type
      */
-    MethodTypeDesc methodType();
+    MethodTypeDesc invocationType();
 }
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java	Fri Nov 30 12:43:55 2018 -0500
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java	Fri Nov 30 14:55:32 2018 -0500
@@ -1556,19 +1556,19 @@
             case REF_putStatic:
                 return Optional.of(MethodHandleDesc.ofField(DirectMethodHandleDesc.Kind.STATIC_SETTER, owner, name, type.parameterType(0)));
             case REF_invokeVirtual:
-                return Optional.of(MethodHandleDesc.of(DirectMethodHandleDesc.Kind.VIRTUAL, owner, name, type));
+                return Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.VIRTUAL, owner, name, type));
             case REF_invokeStatic:
                 return isInterface ?
-                        Optional.of(MethodHandleDesc.of(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, owner, name, type)) :
-                        Optional.of(MethodHandleDesc.of(DirectMethodHandleDesc.Kind.STATIC, owner, name, type));
+                        Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, owner, name, type)) :
+                        Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, owner, name, type));
             case REF_invokeSpecial:
                 return isInterface ?
-                        Optional.of(MethodHandleDesc.of(DirectMethodHandleDesc.Kind.INTERFACE_SPECIAL, owner, name, type)) :
-                        Optional.of(MethodHandleDesc.of(DirectMethodHandleDesc.Kind.SPECIAL, owner, name, type));
+                        Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_SPECIAL, owner, name, type)) :
+                        Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.SPECIAL, owner, name, type));
             case REF_invokeInterface:
-                return Optional.of(MethodHandleDesc.of(DirectMethodHandleDesc.Kind.INTERFACE_VIRTUAL, owner, name, type));
+                return Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_VIRTUAL, owner, name, type));
             case REF_newInvokeSpecial:
-                return Optional.of(MethodHandleDesc.of(DirectMethodHandleDesc.Kind.CONSTRUCTOR, owner, name, type));
+                return Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.CONSTRUCTOR, owner, name, type));
             default:
                 return Optional.empty();
         }
--- a/test/jdk/java/lang/constant/CondyDescTest.java	Fri Nov 30 12:43:55 2018 -0500
+++ b/test/jdk/java/lang/constant/CondyDescTest.java	Fri Nov 30 14:55:32 2018 -0500
@@ -22,6 +22,7 @@
  */
 
 import java.lang.Enum.EnumDesc;
+import java.lang.constant.MethodTypeDesc;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
@@ -96,7 +97,8 @@
 
     public void testNested() throws Throwable {
         DirectMethodHandleDesc invoker = ConstantDescs.ofConstantBootstrap(CD_ConstantBootstraps, "invoke", CD_Object, CD_MethodHandle, CD_Object.arrayType());
-        DirectMethodHandleDesc format = MethodHandleDesc.of(DirectMethodHandleDesc.Kind.STATIC, CD_String, "format", CD_String, CD_String, CD_Object.arrayType());
+        DirectMethodHandleDesc format = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, CD_String, "format",
+                                                                  MethodTypeDesc.of(CD_String, CD_String, CD_Object.arrayType()));
 
         String s = (String) ((MethodHandle) invoker.resolveConstantDesc(LOOKUP))
                                    .invoke(LOOKUP, "", String.class,
--- a/test/jdk/java/lang/constant/IndyDescTest.java	Fri Nov 30 12:43:55 2018 -0500
+++ b/test/jdk/java/lang/constant/IndyDescTest.java	Fri Nov 30 14:55:32 2018 -0500
@@ -57,7 +57,7 @@
     public void testIndyDesc() throws Throwable {
         ClassDesc c = ClassDesc.of("IndyDescTest");
         MethodTypeDesc mt = MethodTypeDesc.of(CD_CallSite, CD_MethodHandles_Lookup, CD_String, CD_MethodType, CD_Object.arrayType());
-        DirectMethodHandleDesc mh = MethodHandleDesc.of(DirectMethodHandleDesc.Kind.STATIC, c, "bootstrap", mt);
+        DirectMethodHandleDesc mh = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, c, "bootstrap", mt);
         DynamicCallSiteDesc csd = DynamicCallSiteDesc.of(mh, "wooga", MethodTypeDesc.of(CD_String));
         CallSite cs = csd.resolveCallSiteDesc(MethodHandles.lookup());
         MethodHandle target = cs.getTarget();
@@ -92,7 +92,7 @@
     public void testEqualsHashToString() throws Throwable {
         ClassDesc c = ClassDesc.of("IndyDescTest");
         MethodTypeDesc mt = MethodTypeDesc.of(CD_CallSite, CD_MethodHandles_Lookup, CD_String, CD_MethodType, CD_Object.arrayType());
-        DirectMethodHandleDesc mh = MethodHandleDesc.of(DirectMethodHandleDesc.Kind.STATIC, c, "bootstrap", mt);
+        DirectMethodHandleDesc mh = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, c, "bootstrap", mt);
 
         DynamicCallSiteDesc csd1 = DynamicCallSiteDesc.of(mh, "wooga", MethodTypeDesc.of(CD_String));
         DynamicCallSiteDesc csd2 = DynamicCallSiteDesc.of(mh, "wooga", MethodTypeDesc.of(CD_String));
@@ -109,7 +109,7 @@
     public void testEmptyInvocationName() throws Throwable {
         ClassDesc c = ClassDesc.of("IndyDescTest");
         MethodTypeDesc mt = MethodTypeDesc.of(CD_CallSite, CD_MethodHandles_Lookup, CD_String, CD_MethodType, CD_Object.arrayType());
-        DirectMethodHandleDesc mh = MethodHandleDesc.of(DirectMethodHandleDesc.Kind.STATIC, c, "bootstrap", mt);
+        DirectMethodHandleDesc mh = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, c, "bootstrap", mt);
         DynamicCallSiteDesc csd1 = DynamicCallSiteDesc.of(mh, "", MethodTypeDesc.of(CD_String));
     }
 }
--- a/test/jdk/java/lang/constant/MethodHandleDescTest.java	Fri Nov 30 12:43:55 2018 -0500
+++ b/test/jdk/java/lang/constant/MethodHandleDescTest.java	Fri Nov 30 14:55:32 2018 -0500
@@ -39,6 +39,8 @@
 
 import org.testng.annotations.Test;
 
+import static java.lang.constant.ConstantDescs.CD_Void;
+import static java.lang.constant.ConstantDescs.CD_boolean;
 import static java.lang.constant.DirectMethodHandleDesc.*;
 import static java.lang.constant.DirectMethodHandleDesc.Kind.GETTER;
 import static java.lang.constant.DirectMethodHandleDesc.Kind.SETTER;
@@ -53,6 +55,7 @@
 import static java.lang.constant.ConstantDescs.CD_void;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotSame;
+import static org.testng.Assert.assertSame;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
@@ -84,13 +87,28 @@
             testSymbolicDesc(r);
 
             DirectMethodHandleDesc rr = (DirectMethodHandleDesc) r;
-            assertEquals(r, MethodHandleDesc.of(rr.kind(), rr.owner(), rr.methodName(), r.methodType()));
+            assertEquals(r, MethodHandleDesc.of(rr.kind(), rr.owner(), rr.methodName(), rr.lookupDescriptor()));
+            assertEquals(r.invocationType().resolveConstantDesc(LOOKUP), ((MethodHandle) r.resolveConstantDesc(LOOKUP)).type());
         }
         else {
             testSymbolicDescForwardOnly(r);
         }
     }
 
+    private String lookupDescriptor(DirectMethodHandleDesc rr) {
+        switch (rr.kind()) {
+            case VIRTUAL:
+            case SPECIAL:
+            case INTERFACE_VIRTUAL:
+            case INTERFACE_SPECIAL:
+                return rr.invocationType().dropParameterTypes(0, 1).descriptorString();
+            case CONSTRUCTOR:
+                return rr.invocationType().changeReturnType(CD_void).descriptorString();
+            default:
+                return rr.invocationType().descriptorString();
+        }
+    }
+
     private void testMethodHandleDesc(MethodHandleDesc r, MethodHandle mh) throws ReflectiveOperationException {
         testMethodHandleDesc(r);
 
@@ -103,23 +121,33 @@
         assertEquals(mhi.getDeclaringClass().descriptorString(), rr.owner().descriptorString());
         assertEquals(mhi.getName(), rr.methodName());
         assertEquals(mhi.getReferenceKind(), rr.kind().refKind);
-        assertEquals(mhi.getMethodType().toMethodDescriptorString(), r.methodType().descriptorString());
+        MethodType type = mhi.getMethodType();
+        assertEquals(type.toMethodDescriptorString(), lookupDescriptor(rr));
     }
 
     public void testSimpleMHs() throws ReflectiveOperationException {
-        testMethodHandleDesc(MethodHandleDesc.of(Kind.VIRTUAL, CD_String, "isEmpty", "()Z"),
-                            LOOKUP.findVirtual(String.class, "isEmpty", MethodType.fromMethodDescriptorString("()Z", null)));
-        testMethodHandleDesc(MethodHandleDesc.of(Kind.STATIC, CD_String, "format", CD_String, CD_String, CD_Object.arrayType()),
-                            LOOKUP.findStatic(String.class, "format", MethodType.methodType(String.class, String.class, Object[].class)));
-        testMethodHandleDesc(MethodHandleDesc.of(Kind.INTERFACE_VIRTUAL, CD_List, "isEmpty", "()Z"),
-                            LOOKUP.findVirtual(List.class, "isEmpty", MethodType.fromMethodDescriptorString("()Z", null)));
-        testMethodHandleDesc(MethodHandleDesc.of(Kind.CONSTRUCTOR, ClassDesc.of("java.util.ArrayList"), "<init>", CD_void),
-                            LOOKUP.findConstructor(ArrayList.class, MethodType.methodType(void.class)));
-        testMethodHandleDesc(MethodHandleDesc.ofConstructor(ClassDesc.of("java.util.ArrayList")),
-                            LOOKUP.findConstructor(ArrayList.class, MethodType.methodType(void.class)));
+        MethodHandle MH_String_isEmpty = LOOKUP.findVirtual(String.class, "isEmpty", MethodType.fromMethodDescriptorString("()Z", null));
+        testMethodHandleDesc(MethodHandleDesc.of(Kind.VIRTUAL, CD_String, "isEmpty", "()Z"), MH_String_isEmpty);
+        testMethodHandleDesc(MethodHandleDesc.ofMethod(Kind.VIRTUAL, CD_String, "isEmpty", MethodTypeDesc.of(CD_boolean)), MH_String_isEmpty);
+
+        MethodHandle MH_List_isEmpty = LOOKUP.findVirtual(List.class, "isEmpty", MethodType.fromMethodDescriptorString("()Z", null));
+        testMethodHandleDesc(MethodHandleDesc.of(Kind.INTERFACE_VIRTUAL, CD_List, "isEmpty", "()Z"), MH_List_isEmpty);
+        testMethodHandleDesc(MethodHandleDesc.ofMethod(Kind.INTERFACE_VIRTUAL, CD_List, "isEmpty", MethodTypeDesc.of(CD_boolean)), MH_List_isEmpty);
+
+        MethodHandle MH_String_format = LOOKUP.findStatic(String.class, "format", MethodType.methodType(String.class, String.class, Object[].class));
+        testMethodHandleDesc(MethodHandleDesc.of(Kind.STATIC, CD_String, "format", MethodType.methodType(String.class, String.class, Object[].class).descriptorString()),
+                             MH_String_format);
+        testMethodHandleDesc(MethodHandleDesc.ofMethod(Kind.STATIC, CD_String, "format", MethodTypeDesc.of(CD_String, CD_String, CD_Object.arrayType())),
+                             MH_String_format);
+
+        MethodHandle MH_ArrayList_new = LOOKUP.findConstructor(ArrayList.class, MethodType.methodType(void.class));
+        testMethodHandleDesc(MethodHandleDesc.ofMethod(Kind.CONSTRUCTOR, ClassDesc.of("java.util.ArrayList"), "<init>", MethodTypeDesc.of(CD_void)),
+                             MH_ArrayList_new);
+        testMethodHandleDesc(MethodHandleDesc.ofConstructor(ClassDesc.of("java.util.ArrayList")), MH_ArrayList_new);
+
         // bad constructor non void return type
         try {
-            MethodHandleDesc.of(Kind.CONSTRUCTOR, ClassDesc.of("java.util.ArrayList"), "<init>", CD_int);
+            MethodHandleDesc.of(Kind.CONSTRUCTOR, ClassDesc.of("java.util.ArrayList"), "<init>", "()I");
             fail("should have failed: non void return type for constructor");
         } catch (IllegalArgumentException ex) {
             // good
@@ -127,8 +155,8 @@
     }
 
     public void testAsType() throws Throwable {
-        MethodHandleDesc mhr = MethodHandleDesc.of(Kind.STATIC, ClassDesc.of("java.lang.Integer"), "valueOf",
-                                                   MethodTypeDesc.of(CD_Integer, CD_int));
+        MethodHandleDesc mhr = MethodHandleDesc.ofMethod(Kind.STATIC, ClassDesc.of("java.lang.Integer"), "valueOf",
+                                                         MethodTypeDesc.of(CD_Integer, CD_int));
         MethodHandleDesc takesInteger = mhr.asType(MethodTypeDesc.of(CD_Integer, CD_Integer));
         testMethodHandleDesc(takesInteger);
         MethodHandle mh1 = (MethodHandle) takesInteger.resolveConstantDesc(LOOKUP);
@@ -152,14 +180,17 @@
         }
         catch (WrongMethodTypeException ignored) { }
 
-        // @@@ Test short-circuit optimization
+        // Short circuit optimization
+        MethodHandleDesc same = mhr.asType(mhr.invocationType());
+        assertSame(mhr, same);
+
         // @@@ Test varargs adaptation
         // @@@ Test bad adaptations and assert runtime error on resolution
         // @@@ Test intrinsification of adapted MH
     }
 
     public void testMethodHandleDesc() throws Throwable {
-        MethodHandleDesc ctorDesc = MethodHandleDesc.of(Kind.CONSTRUCTOR, testClass, "<ignored!>", CD_void);
+        MethodHandleDesc ctorDesc = MethodHandleDesc.of(Kind.CONSTRUCTOR, testClass, "<ignored!>", "()V");
         MethodHandleDesc staticMethodDesc = MethodHandleDesc.of(Kind.STATIC, testClass, "sm", "(I)I");
         MethodHandleDesc staticIMethodDesc = MethodHandleDesc.of(Kind.INTERFACE_STATIC, testInterface, "sm", "(I)I");
         MethodHandleDesc instanceMethodDesc = MethodHandleDesc.of(Kind.VIRTUAL, testClass, "m", "(I)I");
@@ -171,6 +202,15 @@
         MethodHandleDesc privateStaticMethodDesc = MethodHandleDesc.of(Kind.STATIC, testClass, "psm", "(I)I");
         MethodHandleDesc privateStaticIMethodDesc = MethodHandleDesc.of(Kind.INTERFACE_STATIC, testInterface, "psm", "(I)I");
 
+        assertEquals(ctorDesc.invocationType(), MethodTypeDesc.of(testClass));
+        assertEquals(((DirectMethodHandleDesc) ctorDesc).lookupDescriptor(), "()V");
+
+        assertEquals(staticMethodDesc.invocationType().descriptorString(), "(I)I");
+        assertEquals(((DirectMethodHandleDesc) staticMethodDesc).lookupDescriptor(), "(I)I");
+
+        assertEquals(instanceMethodDesc.invocationType().descriptorString(), "(" + testClass.descriptorString() + "I)I");
+        assertEquals(((DirectMethodHandleDesc) instanceMethodDesc).lookupDescriptor(), "(I)I");
+
         for (MethodHandleDesc r : List.of(ctorDesc, staticMethodDesc, staticIMethodDesc, instanceMethodDesc, instanceIMethodDesc))
             testMethodHandleDesc(r);
 
@@ -267,7 +307,7 @@
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testBadOwners() {
-        MethodHandleDesc.of(VIRTUAL, ClassDesc.ofDescriptor("I"), "x", MethodTypeDesc.ofDescriptor("()I"));
+        MethodHandleDesc.ofMethod(VIRTUAL, ClassDesc.ofDescriptor("I"), "x", MethodTypeDesc.ofDescriptor("()I"));
     }
 
     public void testSymbolicDescsConstants() throws ReflectiveOperationException {