rt/emul/compact/src/main/java/java/lang/invoke/MethodType.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 17 Jan 2017 07:04:06 +0100
changeset 1985 cd1cc103a03c
permissions -rw-r--r--
Implementation of ClassValue for bck2brwsr
     1 /*
     2  * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    25 
    26 package java.lang.invoke;
    27 
    28 import java.lang.ref.WeakReference;
    29 import java.lang.ref.Reference;
    30 import java.lang.ref.ReferenceQueue;
    31 import java.util.Arrays;
    32 import java.util.Collections;
    33 import java.util.List;
    34 import java.util.Objects;
    35 import java.util.concurrent.ConcurrentMap;
    36 import java.util.concurrent.ConcurrentHashMap;
    37 
    38 /**
    39  * A method type represents the arguments and return type accepted and
    40  * returned by a method handle, or the arguments and return type passed
    41  * and expected  by a method handle caller.  Method types must be properly
    42  * matched between a method handle and all its callers,
    43  * and the JVM's operations enforce this matching at, specifically
    44  * during calls to {@link MethodHandle#invokeExact MethodHandle.invokeExact}
    45  * and {@link MethodHandle#invoke MethodHandle.invoke}, and during execution
    46  * of {@code invokedynamic} instructions.
    47  * <p>
    48  * The structure is a return type accompanied by any number of parameter types.
    49  * The types (primitive, {@code void}, and reference) are represented by {@link Class} objects.
    50  * (For ease of exposition, we treat {@code void} as if it were a type.
    51  * In fact, it denotes the absence of a return type.)
    52  * <p>
    53  * All instances of {@code MethodType} are immutable.
    54  * Two instances are completely interchangeable if they compare equal.
    55  * Equality depends on pairwise correspondence of the return and parameter types and on nothing else.
    56  * <p>
    57  * This type can be created only by factory methods.
    58  * All factory methods may cache values, though caching is not guaranteed.
    59  * Some factory methods are static, while others are virtual methods which
    60  * modify precursor method types, e.g., by changing a selected parameter.
    61  * <p>
    62  * Factory methods which operate on groups of parameter types
    63  * are systematically presented in two versions, so that both Java arrays and
    64  * Java lists can be used to work with groups of parameter types.
    65  * The query methods {@code parameterArray} and {@code parameterList}
    66  * also provide a choice between arrays and lists.
    67  * <p>
    68  * {@code MethodType} objects are sometimes derived from bytecode instructions
    69  * such as {@code invokedynamic}, specifically from the type descriptor strings associated
    70  * with the instructions in a class file's constant pool.
    71  * <p>
    72  * Like classes and strings, method types can also be represented directly
    73  * in a class file's constant pool as constants.
    74  * A method type may be loaded by an {@code ldc} instruction which refers
    75  * to a suitable {@code CONSTANT_MethodType} constant pool entry.
    76  * The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string.
    77  * (For full details on method type constants,
    78  * see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine Specification.)
    79  * <p>
    80  * When the JVM materializes a {@code MethodType} from a descriptor string,
    81  * all classes named in the descriptor must be accessible, and will be loaded.
    82  * (But the classes need not be initialized, as is the case with a {@code CONSTANT_Class}.)
    83  * This loading may occur at any time before the {@code MethodType} object is first derived.
    84  * @author John Rose, JSR 292 EG
    85  */
    86 public final
    87 class MethodType implements java.io.Serializable {
    88     private static final long serialVersionUID = 292L;  // {rtype, {ptype...}}
    89 
    90     // The rtype and ptypes fields define the structural identity of the method type:
    91     private final Class<?>   rtype;
    92     private final Class<?>[] ptypes;
    93 
    94     /**
    95      * Check the given parameters for validity and store them into the final fields.
    96      */
    97     private MethodType(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
    98         this.rtype = rtype;
    99         // defensively copy the array passed in by the user
   100         this.ptypes = trusted ? ptypes : Arrays.copyOf(ptypes, ptypes.length);
   101     }
   102 
   103     /**
   104      * Construct a temporary unchecked instance of MethodType for use only as a key to the intern table.
   105      * Does not check the given parameters for validity, and must be discarded after it is used as a searching key.
   106      * The parameters are reversed for this constructor, so that is is not accidentally used.
   107      */
   108     private MethodType(Class<?>[] ptypes, Class<?> rtype) {
   109         this.rtype = rtype;
   110         this.ptypes = ptypes;
   111     }
   112 
   113     /** This number, mandated by the JVM spec as 255,
   114      *  is the maximum number of <em>slots</em>
   115      *  that any Java method can receive in its argument list.
   116      *  It limits both JVM signatures and method type objects.
   117      *  The longest possible invocation will look like
   118      *  {@code staticMethod(arg1, arg2, ..., arg255)} or
   119      *  {@code x.virtualMethod(arg1, arg2, ..., arg254)}.
   120      */
   121     /*non-public*/ static final int MAX_JVM_ARITY = 255;  // this is mandated by the JVM spec.
   122 
   123     /** This number is the maximum arity of a method handle, 254.
   124      *  It is derived from the absolute JVM-imposed arity by subtracting one,
   125      *  which is the slot occupied by the method handle itself at the
   126      *  beginning of the argument list used to invoke the method handle.
   127      *  The longest possible invocation will look like
   128      *  {@code mh.invoke(arg1, arg2, ..., arg254)}.
   129      */
   130     // Issue:  Should we allow MH.invokeWithArguments to go to the full 255?
   131     /*non-public*/ static final int MAX_MH_ARITY = MAX_JVM_ARITY-1;  // deduct one for mh receiver
   132 
   133     /** This number is the maximum arity of a method handle invoker, 253.
   134      *  It is derived from the absolute JVM-imposed arity by subtracting two,
   135      *  which are the slots occupied by invoke method handle, and the
   136      *  target method handle, which are both at the beginning of the argument
   137      *  list used to invoke the target method handle.
   138      *  The longest possible invocation will look like
   139      *  {@code invokermh.invoke(targetmh, arg1, arg2, ..., arg253)}.
   140      */
   141     /*non-public*/ static final int MAX_MH_INVOKER_ARITY = MAX_MH_ARITY-1;  // deduct one more for invoker
   142 
   143     private static void checkRtype(Class<?> rtype) {
   144         Objects.requireNonNull(rtype);
   145     }
   146 
   147     static final ConcurrentWeakInternSet<MethodType> internTable = new ConcurrentWeakInternSet<>();
   148 
   149     static final Class<?>[] NO_PTYPES = {};
   150 
   151     /**
   152      * Finds or creates an instance of the given method type.
   153      * @param rtype  the return type
   154      * @param ptypes the parameter types
   155      * @return a method type with the given components
   156      * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
   157      * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
   158      */
   159     public static
   160     MethodType methodType(Class<?> rtype, Class<?>[] ptypes) {
   161         return makeImpl(rtype, ptypes, false);
   162     }
   163 
   164     /**
   165      * Finds or creates a method type with the given components.
   166      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   167      * @param rtype  the return type
   168      * @param ptypes the parameter types
   169      * @return a method type with the given components
   170      * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
   171      * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
   172      */
   173     public static
   174     MethodType methodType(Class<?> rtype, List<Class<?>> ptypes) {
   175         boolean notrust = false;  // random List impl. could return evil ptypes array
   176         return makeImpl(rtype, listToArray(ptypes), notrust);
   177     }
   178 
   179     private static Class<?>[] listToArray(List<Class<?>> ptypes) {
   180         return ptypes.toArray(NO_PTYPES);
   181     }
   182 
   183     /**
   184      * Finds or creates a method type with the given components.
   185      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   186      * The leading parameter type is prepended to the remaining array.
   187      * @param rtype  the return type
   188      * @param ptype0 the first parameter type
   189      * @param ptypes the remaining parameter types
   190      * @return a method type with the given components
   191      * @throws NullPointerException if {@code rtype} or {@code ptype0} or {@code ptypes} or any element of {@code ptypes} is null
   192      * @throws IllegalArgumentException if {@code ptype0} or {@code ptypes} or any element of {@code ptypes} is {@code void.class}
   193      */
   194     public static
   195     MethodType methodType(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
   196         Class<?>[] ptypes1 = new Class<?>[1+ptypes.length];
   197         ptypes1[0] = ptype0;
   198         System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
   199         return makeImpl(rtype, ptypes1, true);
   200     }
   201 
   202     /**
   203      * Finds or creates a method type with the given components.
   204      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   205      * The resulting method has no parameter types.
   206      * @param rtype  the return type
   207      * @return a method type with the given return value
   208      * @throws NullPointerException if {@code rtype} is null
   209      */
   210     public static
   211     MethodType methodType(Class<?> rtype) {
   212         return makeImpl(rtype, NO_PTYPES, true);
   213     }
   214 
   215     /**
   216      * Finds or creates a method type with the given components.
   217      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   218      * The resulting method has the single given parameter type.
   219      * @param rtype  the return type
   220      * @param ptype0 the parameter type
   221      * @return a method type with the given return value and parameter type
   222      * @throws NullPointerException if {@code rtype} or {@code ptype0} is null
   223      * @throws IllegalArgumentException if {@code ptype0} is {@code void.class}
   224      */
   225     public static
   226     MethodType methodType(Class<?> rtype, Class<?> ptype0) {
   227         return makeImpl(rtype, new Class<?>[]{ ptype0 }, true);
   228     }
   229 
   230     /**
   231      * Finds or creates a method type with the given components.
   232      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   233      * The resulting method has the same parameter types as {@code ptypes},
   234      * and the specified return type.
   235      * @param rtype  the return type
   236      * @param ptypes the method type which supplies the parameter types
   237      * @return a method type with the given components
   238      * @throws NullPointerException if {@code rtype} or {@code ptypes} is null
   239      */
   240     public static
   241     MethodType methodType(Class<?> rtype, MethodType ptypes) {
   242         return makeImpl(rtype, ptypes.ptypes, true);
   243     }
   244 
   245     /**
   246      * Sole factory method to find or create an interned method type.
   247      * @param rtype desired return type
   248      * @param ptypes desired parameter types
   249      * @param trusted whether the ptypes can be used without cloning
   250      * @return the unique method type of the desired structure
   251      */
   252     /*trusted*/ static
   253     MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
   254         throw new IllegalStateException();
   255     }
   256     private static final MethodType[] objectOnlyTypes = new MethodType[20];
   257 
   258     /**
   259      * Finds or creates a method type whose components are {@code Object} with an optional trailing {@code Object[]} array.
   260      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   261      * All parameters and the return type will be {@code Object},
   262      * except the final array parameter if any, which will be {@code Object[]}.
   263      * @param objectArgCount number of parameters (excluding the final array parameter if any)
   264      * @param finalArray whether there will be a trailing array parameter, of type {@code Object[]}
   265      * @return a generally applicable method type, for all calls of the given fixed argument count and a collected array of further arguments
   266      * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray} is true)
   267      * @see #genericMethodType(int)
   268      */
   269     public static
   270     MethodType genericMethodType(int objectArgCount, boolean finalArray) {
   271         throw new IllegalStateException();
   272     }
   273 
   274     /**
   275      * Finds or creates a method type whose components are all {@code Object}.
   276      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   277      * All parameters and the return type will be Object.
   278      * @param objectArgCount number of parameters
   279      * @return a generally applicable method type, for all calls of the given argument count
   280      * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255
   281      * @see #genericMethodType(int, boolean)
   282      */
   283     public static
   284     MethodType genericMethodType(int objectArgCount) {
   285         return genericMethodType(objectArgCount, false);
   286     }
   287 
   288     /**
   289      * Finds or creates a method type with a single different parameter type.
   290      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   291      * @param num    the index (zero-based) of the parameter type to change
   292      * @param nptype a new parameter type to replace the old one with
   293      * @return the same type, except with the selected parameter changed
   294      * @throws IndexOutOfBoundsException if {@code num} is not a valid index into {@code parameterArray()}
   295      * @throws IllegalArgumentException if {@code nptype} is {@code void.class}
   296      * @throws NullPointerException if {@code nptype} is null
   297      */
   298     public MethodType changeParameterType(int num, Class<?> nptype) {
   299         throw new IllegalStateException();
   300     }
   301 
   302     /**
   303      * Finds or creates a method type with additional parameter types.
   304      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   305      * @param num    the position (zero-based) of the inserted parameter type(s)
   306      * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
   307      * @return the same type, except with the selected parameter(s) inserted
   308      * @throws IndexOutOfBoundsException if {@code num} is negative or greater than {@code parameterCount()}
   309      * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
   310      *                                  or if the resulting method type would have more than 255 parameter slots
   311      * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
   312      */
   313     public MethodType insertParameterTypes(int num, Class<?>... ptypesToInsert) {
   314         throw new IllegalStateException();
   315     }
   316 
   317     /**
   318      * Finds or creates a method type with additional parameter types.
   319      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   320      * @param ptypesToInsert zero or more new parameter types to insert after the end of the parameter list
   321      * @return the same type, except with the selected parameter(s) appended
   322      * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
   323      *                                  or if the resulting method type would have more than 255 parameter slots
   324      * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
   325      */
   326     public MethodType appendParameterTypes(Class<?>... ptypesToInsert) {
   327         return insertParameterTypes(parameterCount(), ptypesToInsert);
   328     }
   329 
   330     /**
   331      * Finds or creates a method type with additional parameter types.
   332      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   333      * @param num    the position (zero-based) of the inserted parameter type(s)
   334      * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
   335      * @return the same type, except with the selected parameter(s) inserted
   336      * @throws IndexOutOfBoundsException if {@code num} is negative or greater than {@code parameterCount()}
   337      * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
   338      *                                  or if the resulting method type would have more than 255 parameter slots
   339      * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
   340      */
   341     public MethodType insertParameterTypes(int num, List<Class<?>> ptypesToInsert) {
   342         return insertParameterTypes(num, listToArray(ptypesToInsert));
   343     }
   344 
   345     /**
   346      * Finds or creates a method type with additional parameter types.
   347      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   348      * @param ptypesToInsert zero or more new parameter types to insert after the end of the parameter list
   349      * @return the same type, except with the selected parameter(s) appended
   350      * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
   351      *                                  or if the resulting method type would have more than 255 parameter slots
   352      * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
   353      */
   354     public MethodType appendParameterTypes(List<Class<?>> ptypesToInsert) {
   355         return insertParameterTypes(parameterCount(), ptypesToInsert);
   356     }
   357 
   358      /**
   359      * Finds or creates a method type with modified parameter types.
   360      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   361      * @param start  the position (zero-based) of the first replaced parameter type(s)
   362      * @param end    the position (zero-based) after the last replaced parameter type(s)
   363      * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
   364      * @return the same type, except with the selected parameter(s) replaced
   365      * @throws IndexOutOfBoundsException if {@code start} is negative or greater than {@code parameterCount()}
   366      *                                  or if {@code end} is negative or greater than {@code parameterCount()}
   367      *                                  or if {@code start} is greater than {@code end}
   368      * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
   369      *                                  or if the resulting method type would have more than 255 parameter slots
   370      * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
   371      */
   372     /*non-public*/ MethodType replaceParameterTypes(int start, int end, Class<?>... ptypesToInsert) {
   373         throw new IllegalStateException();
   374     }
   375 
   376     /**
   377      * Finds or creates a method type with some parameter types omitted.
   378      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   379      * @param start  the index (zero-based) of the first parameter type to remove
   380      * @param end    the index (greater than {@code start}) of the first parameter type after not to remove
   381      * @return the same type, except with the selected parameter(s) removed
   382      * @throws IndexOutOfBoundsException if {@code start} is negative or greater than {@code parameterCount()}
   383      *                                  or if {@code end} is negative or greater than {@code parameterCount()}
   384      *                                  or if {@code start} is greater than {@code end}
   385      */
   386     public MethodType dropParameterTypes(int start, int end) {
   387         throw new IllegalStateException();
   388     }
   389 
   390     /**
   391      * Finds or creates a method type with a different return type.
   392      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   393      * @param nrtype a return parameter type to replace the old one with
   394      * @return the same type, except with the return type change
   395      * @throws NullPointerException if {@code nrtype} is null
   396      */
   397     public MethodType changeReturnType(Class<?> nrtype) {
   398         throw new IllegalStateException();
   399     }
   400 
   401     /**
   402      * Reports if this type contains a primitive argument or return value.
   403      * The return type {@code void} counts as a primitive.
   404      * @return true if any of the types are primitives
   405      */
   406     public boolean hasPrimitives() {
   407         throw new IllegalStateException();
   408     }
   409 
   410     /**
   411      * Reports if this type contains a wrapper argument or return value.
   412      * Wrappers are types which box primitive values, such as {@link Integer}.
   413      * The reference type {@code java.lang.Void} counts as a wrapper,
   414      * if it occurs as a return type.
   415      * @return true if any of the types are wrappers
   416      */
   417     public boolean hasWrappers() {
   418         return unwrap() != this;
   419     }
   420 
   421     /**
   422      * Erases all reference types to {@code Object}.
   423      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   424      * All primitive types (including {@code void}) will remain unchanged.
   425      * @return a version of the original type with all reference types replaced
   426      */
   427     public MethodType erase() {
   428         throw new IllegalStateException();
   429     }
   430 
   431     /**
   432      * Erases all reference types to {@code Object}, and all subword types to {@code int}.
   433      * This is the reduced type polymorphism used by private methods
   434      * such as {@link MethodHandle#invokeBasic invokeBasic}.
   435      * @return a version of the original type with all reference and subword types replaced
   436      */
   437     /*non-public*/ MethodType basicType() {
   438         throw new IllegalStateException();
   439     }
   440 
   441     /**
   442      * @return a version of the original type with MethodHandle prepended as the first argument
   443      */
   444     /*non-public*/ MethodType invokerType() {
   445         throw new IllegalStateException();
   446     }
   447 
   448     /**
   449      * Converts all types, both reference and primitive, to {@code Object}.
   450      * Convenience method for {@link #genericMethodType(int) genericMethodType}.
   451      * The expression {@code type.wrap().erase()} produces the same value
   452      * as {@code type.generic()}.
   453      * @return a version of the original type with all types replaced
   454      */
   455     public MethodType generic() {
   456         return genericMethodType(parameterCount());
   457     }
   458 
   459     /**
   460      * Converts all primitive types to their corresponding wrapper types.
   461      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   462      * All reference types (including wrapper types) will remain unchanged.
   463      * A {@code void} return type is changed to the type {@code java.lang.Void}.
   464      * The expression {@code type.wrap().erase()} produces the same value
   465      * as {@code type.generic()}.
   466      * @return a version of the original type with all primitive types replaced
   467      */
   468     public MethodType wrap() {
   469         return hasPrimitives() ? wrapWithPrims(this) : this;
   470     }
   471 
   472     /**
   473      * Converts all wrapper types to their corresponding primitive types.
   474      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   475      * All primitive types (including {@code void}) will remain unchanged.
   476      * A return type of {@code java.lang.Void} is changed to {@code void}.
   477      * @return a version of the original type with all wrapper types replaced
   478      */
   479     public MethodType unwrap() {
   480         MethodType noprims = !hasPrimitives() ? this : wrapWithPrims(this);
   481         return unwrapWithNoPrims(noprims);
   482     }
   483 
   484     private static MethodType wrapWithPrims(MethodType pt) {
   485         throw new IllegalStateException();
   486     }
   487 
   488     private static MethodType unwrapWithNoPrims(MethodType wt) {
   489         throw new IllegalStateException();
   490     }
   491 
   492     /**
   493      * Returns the parameter type at the specified index, within this method type.
   494      * @param num the index (zero-based) of the desired parameter type
   495      * @return the selected parameter type
   496      * @throws IndexOutOfBoundsException if {@code num} is not a valid index into {@code parameterArray()}
   497      */
   498     public Class<?> parameterType(int num) {
   499         return ptypes[num];
   500     }
   501     /**
   502      * Returns the number of parameter types in this method type.
   503      * @return the number of parameter types
   504      */
   505     public int parameterCount() {
   506         return ptypes.length;
   507     }
   508     /**
   509      * Returns the return type of this method type.
   510      * @return the return type
   511      */
   512     public Class<?> returnType() {
   513         return rtype;
   514     }
   515 
   516     /**
   517      * Presents the parameter types as a list (a convenience method).
   518      * The list will be immutable.
   519      * @return the parameter types (as an immutable list)
   520      */
   521     public List<Class<?>> parameterList() {
   522         return Collections.unmodifiableList(Arrays.asList(ptypes));
   523     }
   524 
   525     /*non-public*/ Class<?> lastParameterType() {
   526         int len = ptypes.length;
   527         return len == 0 ? void.class : ptypes[len-1];
   528     }
   529 
   530     /**
   531      * Presents the parameter types as an array (a convenience method).
   532      * Changes to the array will not result in changes to the type.
   533      * @return the parameter types (as a fresh copy if necessary)
   534      */
   535     public Class<?>[] parameterArray() {
   536         return ptypes.clone();
   537     }
   538 
   539     /**
   540      * Compares the specified object with this type for equality.
   541      * That is, it returns <tt>true</tt> if and only if the specified object
   542      * is also a method type with exactly the same parameters and return type.
   543      * @param x object to compare
   544      * @see Object#equals(Object)
   545      */
   546     @Override
   547     public boolean equals(Object x) {
   548         return this == x || x instanceof MethodType && equals((MethodType)x);
   549     }
   550 
   551     private boolean equals(MethodType that) {
   552         return this.rtype == that.rtype
   553             && Arrays.equals(this.ptypes, that.ptypes);
   554     }
   555 
   556     /**
   557      * Returns the hash code value for this method type.
   558      * It is defined to be the same as the hashcode of a List
   559      * whose elements are the return type followed by the
   560      * parameter types.
   561      * @return the hash code value for this method type
   562      * @see Object#hashCode()
   563      * @see #equals(Object)
   564      * @see List#hashCode()
   565      */
   566     @Override
   567     public int hashCode() {
   568       int hashCode = 31 + rtype.hashCode();
   569       for (Class<?> ptype : ptypes)
   570           hashCode = 31*hashCode + ptype.hashCode();
   571       return hashCode;
   572     }
   573 
   574     /**
   575      * Returns a string representation of the method type,
   576      * of the form {@code "(PT0,PT1...)RT"}.
   577      * The string representation of a method type is a
   578      * parenthesis enclosed, comma separated list of type names,
   579      * followed immediately by the return type.
   580      * <p>
   581      * Each type is represented by its
   582      * {@link java.lang.Class#getSimpleName simple name}.
   583      */
   584     @Override
   585     public String toString() {
   586         StringBuilder sb = new StringBuilder();
   587         sb.append("(");
   588         for (int i = 0; i < ptypes.length; i++) {
   589             if (i > 0)  sb.append(",");
   590             sb.append(ptypes[i].getSimpleName());
   591         }
   592         sb.append(")");
   593         sb.append(rtype.getSimpleName());
   594         return sb.toString();
   595     }
   596 
   597 
   598     /**
   599      * Finds or creates an instance of a method type, given the spelling of its bytecode descriptor.
   600      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   601      * Any class or interface name embedded in the descriptor string
   602      * will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)}
   603      * on the given loader (or if it is null, on the system class loader).
   604      * <p>
   605      * Note that it is possible to encounter method types which cannot be
   606      * constructed by this method, because their component types are
   607      * not all reachable from a common class loader.
   608      * <p>
   609      * This method is included for the benefit of applications that must
   610      * generate bytecodes that process method handles and {@code invokedynamic}.
   611      * @param descriptor a bytecode-level type descriptor string "(T...)T"
   612      * @param loader the class loader in which to look up the types
   613      * @return a method type matching the bytecode-level type descriptor
   614      * @throws NullPointerException if the string is null
   615      * @throws IllegalArgumentException if the string is not well-formed
   616      * @throws TypeNotPresentException if a named type cannot be found
   617      */
   618     public static MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader)
   619         throws IllegalArgumentException
   620     {
   621         throw new IllegalStateException();
   622     }
   623 
   624     /**
   625      * Produces a bytecode descriptor representation of the method type.
   626      * <p>
   627      * Note that this is not a strict inverse of {@link #fromMethodDescriptorString fromMethodDescriptorString}.
   628      * Two distinct classes which share a common name but have different class loaders
   629      * will appear identical when viewed within descriptor strings.
   630      * <p>
   631      * This method is included for the benefit of applications that must
   632      * generate bytecodes that process method handles and {@code invokedynamic}.
   633      * {@link #fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) fromMethodDescriptorString},
   634      * because the latter requires a suitable class loader argument.
   635      * @return the bytecode type descriptor representation
   636      */
   637     public String toMethodDescriptorString() {
   638         throw new IllegalStateException();
   639     }
   640 
   641     /// Serialization.
   642 
   643     /**
   644      * There are no serializable fields for {@code MethodType}.
   645      */
   646     private static final java.io.ObjectStreamField[] serialPersistentFields = { };
   647 
   648 //    /**
   649 //     * Save the {@code MethodType} instance to a stream.
   650 //     *
   651 //     * @serialData
   652 //     * For portability, the serialized format does not refer to named fields.
   653 //     * Instead, the return type and parameter type arrays are written directly
   654 //     * from the {@code writeObject} method, using two calls to {@code s.writeObject}
   655 //     * as follows:
   656 //     * <blockquote><pre>{@code
   657 //s.writeObject(this.returnType());
   658 //s.writeObject(this.parameterArray());
   659 //     * }</pre></blockquote>
   660 //     * <p>
   661 //     * The deserialized field values are checked as if they were
   662 //     * provided to the factory method {@link #methodType(Class,Class[]) methodType}.
   663 //     * For example, null values, or {@code void} parameter types,
   664 //     * will lead to exceptions during deserialization.
   665 //     * @param s the stream to write the object to
   666 //     * @throws java.io.IOException if there is a problem writing the object
   667 //     */
   668 //    private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
   669 //        s.defaultWriteObject();  // requires serialPersistentFields to be an empty array
   670 //        s.writeObject(returnType());
   671 //        s.writeObject(parameterArray());
   672 //    }
   673 //
   674 //    /**
   675 //     * Reconstitute the {@code MethodType} instance from a stream (that is,
   676 //     * deserialize it).
   677 //     * This instance is a scratch object with bogus final fields.
   678 //     * It provides the parameters to the factory method called by
   679 //     * {@link #readResolve readResolve}.
   680 //     * After that call it is discarded.
   681 //     * @param s the stream to read the object from
   682 //     * @throws java.io.IOException if there is a problem reading the object
   683 //     * @throws ClassNotFoundException if one of the component classes cannot be resolved
   684 //     * @see #MethodType()
   685 //     * @see #readResolve
   686 //     * @see #writeObject
   687 //     */
   688 //    private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
   689 //        s.defaultReadObject();  // requires serialPersistentFields to be an empty array
   690 //
   691 //        Class<?>   returnType     = (Class<?>)   s.readObject();
   692 //        Class<?>[] parameterArray = (Class<?>[]) s.readObject();
   693 //
   694 //        // Probably this object will never escape, but let's check
   695 //        // the field values now, just to be sure.
   696 //        checkRtype(returnType);
   697 //        checkPtypes(parameterArray);
   698 //
   699 //        parameterArray = parameterArray.clone();  // make sure it is unshared
   700 //        MethodType_init(returnType, parameterArray);
   701 //    }
   702 
   703     /**
   704      * For serialization only.
   705      * Sets the final fields to null, pending {@code Unsafe.putObject}.
   706      */
   707     private MethodType() {
   708         this.rtype = null;
   709         this.ptypes = null;
   710     }
   711 //    private void MethodType_init(Class<?> rtype, Class<?>[] ptypes) {
   712 //        // In order to communicate these values to readResolve, we must
   713 //        // store them into the implementation-specific final fields.
   714 //        checkRtype(rtype);
   715 //        checkPtypes(ptypes);
   716 //        UNSAFE.putObject(this, rtypeOffset, rtype);
   717 //        UNSAFE.putObject(this, ptypesOffset, ptypes);
   718 //    }
   719 
   720     // Support for resetting final fields while deserializing
   721 //    private static final long rtypeOffset, ptypesOffset;
   722 //    static {
   723 //        try {
   724 //            rtypeOffset = UNSAFE.objectFieldOffset
   725 //                (MethodType.class.getDeclaredField("rtype"));
   726 //            ptypesOffset = UNSAFE.objectFieldOffset
   727 //                (MethodType.class.getDeclaredField("ptypes"));
   728 //        } catch (Exception ex) {
   729 //            throw new Error(ex);
   730 //        }
   731 //    }
   732 
   733     /**
   734      * Resolves and initializes a {@code MethodType} object
   735      * after serialization.
   736      * @return the fully initialized {@code MethodType} object
   737      */
   738     private Object readResolve() {
   739         // Do not use a trusted path for deserialization:
   740         //return makeImpl(rtype, ptypes, true);
   741         // Verify all operands, and make sure ptypes is unshared:
   742         return methodType(rtype, ptypes);
   743     }
   744 
   745     /**
   746      * Simple implementation of weak concurrent intern set.
   747      *
   748      * @param <T> interned type
   749      */
   750     private static class ConcurrentWeakInternSet<T> {
   751 
   752         private final ConcurrentMap<WeakEntry<T>, WeakEntry<T>> map;
   753         private final ReferenceQueue<T> stale;
   754 
   755         public ConcurrentWeakInternSet() {
   756             this.map = new ConcurrentHashMap<>();
   757             this.stale = new ReferenceQueue<>();
   758         }
   759 
   760         /**
   761          * Get the existing interned element.
   762          * This method returns null if no element is interned.
   763          *
   764          * @param elem element to look up
   765          * @return the interned element
   766          */
   767         public T get(T elem) {
   768             if (elem == null) throw new NullPointerException();
   769             expungeStaleElements();
   770 
   771             WeakEntry<T> value = map.get(new WeakEntry<>(elem));
   772             if (value != null) {
   773                 T res = value.get();
   774                 if (res != null) {
   775                     return res;
   776                 }
   777             }
   778             return null;
   779         }
   780 
   781         /**
   782          * Interns the element.
   783          * Always returns non-null element, matching the one in the intern set.
   784          * Under the race against another add(), it can return <i>different</i>
   785          * element, if another thread beats us to interning it.
   786          *
   787          * @param elem element to add
   788          * @return element that was actually added
   789          */
   790         public T add(T elem) {
   791             if (elem == null) throw new NullPointerException();
   792 
   793             // Playing double race here, and so spinloop is required.
   794             // First race is with two concurrent updaters.
   795             // Second race is with GC purging weak ref under our feet.
   796             // Hopefully, we almost always end up with a single pass.
   797             T interned;
   798             WeakEntry<T> e = new WeakEntry<>(elem, stale);
   799             do {
   800                 expungeStaleElements();
   801                 WeakEntry<T> exist = map.putIfAbsent(e, e);
   802                 interned = (exist == null) ? elem : exist.get();
   803             } while (interned == null);
   804             return interned;
   805         }
   806 
   807         private void expungeStaleElements() {
   808             Reference<? extends T> reference;
   809             while ((reference = stale.poll()) != null) {
   810                 map.remove(reference);
   811             }
   812         }
   813 
   814         private static class WeakEntry<T> extends WeakReference<T> {
   815 
   816             public final int hashcode;
   817 
   818             public WeakEntry(T key, ReferenceQueue<T> queue) {
   819                 super(key, queue);
   820                 hashcode = key.hashCode();
   821             }
   822 
   823             public WeakEntry(T key) {
   824                 super(key);
   825                 hashcode = key.hashCode();
   826             }
   827 
   828             @Override
   829             public boolean equals(Object obj) {
   830                 if (obj instanceof WeakEntry) {
   831                     Object that = ((WeakEntry) obj).get();
   832                     Object mine = get();
   833                     return (that == null || mine == null) ? (this == obj) : mine.equals(that);
   834                 }
   835                 return false;
   836             }
   837 
   838             @Override
   839             public int hashCode() {
   840                 return hashcode;
   841             }
   842 
   843         }
   844     }
   845 
   846 }