Home | History | Annotate | Download | only in invoke
      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 sun.invoke.util.Wrapper;
     29 import java.lang.ref.WeakReference;
     30 import java.lang.ref.Reference;
     31 import java.lang.ref.ReferenceQueue;
     32 import java.util.Arrays;
     33 import java.util.Collections;
     34 import java.util.List;
     35 import java.util.Objects;
     36 import java.util.concurrent.ConcurrentMap;
     37 import java.util.concurrent.ConcurrentHashMap;
     38 import sun.invoke.util.BytecodeDescriptor;
     39 import static java.lang.invoke.MethodHandleStatics.*;
     40 
     41 /**
     42  * A method type represents the arguments and return type accepted and
     43  * returned by a method handle, or the arguments and return type passed
     44  * and expected  by a method handle caller.  Method types must be properly
     45  * matched between a method handle and all its callers,
     46  * and the JVM's operations enforce this matching at, specifically
     47  * during calls to {@link MethodHandle#invokeExact MethodHandle.invokeExact}
     48  * and {@link MethodHandle#invoke MethodHandle.invoke}, and during execution
     49  * of {@code invokedynamic} instructions.
     50  * <p>
     51  * The structure is a return type accompanied by any number of parameter types.
     52  * The types (primitive, {@code void}, and reference) are represented by {@link Class} objects.
     53  * (For ease of exposition, we treat {@code void} as if it were a type.
     54  * In fact, it denotes the absence of a return type.)
     55  * <p>
     56  * All instances of {@code MethodType} are immutable.
     57  * Two instances are completely interchangeable if they compare equal.
     58  * Equality depends on pairwise correspondence of the return and parameter types and on nothing else.
     59  * <p>
     60  * This type can be created only by factory methods.
     61  * All factory methods may cache values, though caching is not guaranteed.
     62  * Some factory methods are static, while others are virtual methods which
     63  * modify precursor method types, e.g., by changing a selected parameter.
     64  * <p>
     65  * Factory methods which operate on groups of parameter types
     66  * are systematically presented in two versions, so that both Java arrays and
     67  * Java lists can be used to work with groups of parameter types.
     68  * The query methods {@code parameterArray} and {@code parameterList}
     69  * also provide a choice between arrays and lists.
     70  * <p>
     71  * {@code MethodType} objects are sometimes derived from bytecode instructions
     72  * such as {@code invokedynamic}, specifically from the type descriptor strings associated
     73  * with the instructions in a class file's constant pool.
     74  * <p>
     75  * Like classes and strings, method types can also be represented directly
     76  * in a class file's constant pool as constants.
     77  * A method type may be loaded by an {@code ldc} instruction which refers
     78  * to a suitable {@code CONSTANT_MethodType} constant pool entry.
     79  * The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string.
     80  * (For full details on method type constants,
     81  * see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine Specification.)
     82  * <p>
     83  * When the JVM materializes a {@code MethodType} from a descriptor string,
     84  * all classes named in the descriptor must be accessible, and will be loaded.
     85  * (But the classes need not be initialized, as is the case with a {@code CONSTANT_Class}.)
     86  * This loading may occur at any time before the {@code MethodType} object is first derived.
     87  * @author John Rose, JSR 292 EG
     88  */
     89 public final
     90 class MethodType implements java.io.Serializable {
     91     private static final long serialVersionUID = 292L;  // {rtype, {ptype...}}
     92 
     93     // The rtype and ptypes fields define the structural identity of the method type:
     94     private final Class<?>   rtype;
     95     private final Class<?>[] ptypes;
     96 
     97     // The remaining fields are caches of various sorts:
     98     private @Stable MethodTypeForm form; // erased form, plus cached data about primitives
     99     private @Stable MethodType wrapAlt;  // alternative wrapped/unwrapped version
    100     // Android-changed: Remove adapter cache. We're not dynamically generating any
    101     // adapters at this point.
    102     // private @Stable Invokers invokers;   // cache of handy higher-order adapters
    103     private @Stable String methodDescriptor;  // cache for toMethodDescriptorString
    104 
    105     /**
    106      * Check the given parameters for validity and store them into the final fields.
    107      */
    108     private MethodType(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
    109         checkRtype(rtype);
    110         checkPtypes(ptypes);
    111         this.rtype = rtype;
    112         // defensively copy the array passed in by the user
    113         this.ptypes = trusted ? ptypes : Arrays.copyOf(ptypes, ptypes.length);
    114     }
    115 
    116     /**
    117      * Construct a temporary unchecked instance of MethodType for use only as a key to the intern table.
    118      * Does not check the given parameters for validity, and must be discarded after it is used as a searching key.
    119      * The parameters are reversed for this constructor, so that is is not accidentally used.
    120      */
    121     private MethodType(Class<?>[] ptypes, Class<?> rtype) {
    122         this.rtype = rtype;
    123         this.ptypes = ptypes;
    124     }
    125 
    126     /*trusted*/ MethodTypeForm form() { return form; }
    127     /*trusted*/ /** @hide */ public Class<?> rtype() { return rtype; }
    128     /*trusted*/ /** @hide */ public Class<?>[] ptypes() { return ptypes; }
    129 
    130     // Android-changed: Removed method setForm. It's unused in the JDK and there's no
    131     // good reason to allow the form to be set externally.
    132     //
    133     // void setForm(MethodTypeForm f) { form = f; }
    134 
    135     /** This number, mandated by the JVM spec as 255,
    136      *  is the maximum number of <em>slots</em>
    137      *  that any Java method can receive in its argument list.
    138      *  It limits both JVM signatures and method type objects.
    139      *  The longest possible invocation will look like
    140      *  {@code staticMethod(arg1, arg2, ..., arg255)} or
    141      *  {@code x.virtualMethod(arg1, arg2, ..., arg254)}.
    142      */
    143     /*non-public*/ static final int MAX_JVM_ARITY = 255;  // this is mandated by the JVM spec.
    144 
    145     /** This number is the maximum arity of a method handle, 254.
    146      *  It is derived from the absolute JVM-imposed arity by subtracting one,
    147      *  which is the slot occupied by the method handle itself at the
    148      *  beginning of the argument list used to invoke the method handle.
    149      *  The longest possible invocation will look like
    150      *  {@code mh.invoke(arg1, arg2, ..., arg254)}.
    151      */
    152     // Issue:  Should we allow MH.invokeWithArguments to go to the full 255?
    153     /*non-public*/ static final int MAX_MH_ARITY = MAX_JVM_ARITY-1;  // deduct one for mh receiver
    154 
    155     /** This number is the maximum arity of a method handle invoker, 253.
    156      *  It is derived from the absolute JVM-imposed arity by subtracting two,
    157      *  which are the slots occupied by invoke method handle, and the
    158      *  target method handle, which are both at the beginning of the argument
    159      *  list used to invoke the target method handle.
    160      *  The longest possible invocation will look like
    161      *  {@code invokermh.invoke(targetmh, arg1, arg2, ..., arg253)}.
    162      */
    163     /*non-public*/ static final int MAX_MH_INVOKER_ARITY = MAX_MH_ARITY-1;  // deduct one more for invoker
    164 
    165     private static void checkRtype(Class<?> rtype) {
    166         Objects.requireNonNull(rtype);
    167     }
    168     private static void checkPtype(Class<?> ptype) {
    169         Objects.requireNonNull(ptype);
    170         if (ptype == void.class)
    171             throw newIllegalArgumentException("parameter type cannot be void");
    172     }
    173     /** Return number of extra slots (count of long/double args). */
    174     private static int checkPtypes(Class<?>[] ptypes) {
    175         int slots = 0;
    176         for (Class<?> ptype : ptypes) {
    177             checkPtype(ptype);
    178             if (ptype == double.class || ptype == long.class) {
    179                 slots++;
    180             }
    181         }
    182         checkSlotCount(ptypes.length + slots);
    183         return slots;
    184     }
    185     static void checkSlotCount(int count) {
    186         assert((MAX_JVM_ARITY & (MAX_JVM_ARITY+1)) == 0);
    187         // MAX_JVM_ARITY must be power of 2 minus 1 for following code trick to work:
    188         if ((count & MAX_JVM_ARITY) != count)
    189             throw newIllegalArgumentException("bad parameter count "+count);
    190     }
    191     private static IndexOutOfBoundsException newIndexOutOfBoundsException(Object num) {
    192         if (num instanceof Integer)  num = "bad index: "+num;
    193         return new IndexOutOfBoundsException(num.toString());
    194     }
    195 
    196     static final ConcurrentWeakInternSet<MethodType> internTable = new ConcurrentWeakInternSet<>();
    197 
    198     static final Class<?>[] NO_PTYPES = {};
    199 
    200     /**
    201      * Finds or creates an instance of the given method type.
    202      * @param rtype  the return type
    203      * @param ptypes the parameter types
    204      * @return a method type with the given components
    205      * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
    206      * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
    207      */
    208     public static
    209     MethodType methodType(Class<?> rtype, Class<?>[] ptypes) {
    210         return makeImpl(rtype, ptypes, false);
    211     }
    212 
    213     /**
    214      * Finds or creates a method type with the given components.
    215      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    216      * @param rtype  the return type
    217      * @param ptypes the parameter types
    218      * @return a method type with the given components
    219      * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
    220      * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
    221      */
    222     public static
    223     MethodType methodType(Class<?> rtype, List<Class<?>> ptypes) {
    224         boolean notrust = false;  // random List impl. could return evil ptypes array
    225         return makeImpl(rtype, listToArray(ptypes), notrust);
    226     }
    227 
    228     private static Class<?>[] listToArray(List<Class<?>> ptypes) {
    229         // sanity check the size before the toArray call, since size might be huge
    230         checkSlotCount(ptypes.size());
    231         return ptypes.toArray(NO_PTYPES);
    232     }
    233 
    234     /**
    235      * Finds or creates a method type with the given components.
    236      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    237      * The leading parameter type is prepended to the remaining array.
    238      * @param rtype  the return type
    239      * @param ptype0 the first parameter type
    240      * @param ptypes the remaining parameter types
    241      * @return a method type with the given components
    242      * @throws NullPointerException if {@code rtype} or {@code ptype0} or {@code ptypes} or any element of {@code ptypes} is null
    243      * @throws IllegalArgumentException if {@code ptype0} or {@code ptypes} or any element of {@code ptypes} is {@code void.class}
    244      */
    245     public static
    246     MethodType methodType(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
    247         Class<?>[] ptypes1 = new Class<?>[1+ptypes.length];
    248         ptypes1[0] = ptype0;
    249         System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
    250         return makeImpl(rtype, ptypes1, true);
    251     }
    252 
    253     /**
    254      * Finds or creates a method type with the given components.
    255      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    256      * The resulting method has no parameter types.
    257      * @param rtype  the return type
    258      * @return a method type with the given return value
    259      * @throws NullPointerException if {@code rtype} is null
    260      */
    261     public static
    262     MethodType methodType(Class<?> rtype) {
    263         return makeImpl(rtype, NO_PTYPES, true);
    264     }
    265 
    266     /**
    267      * Finds or creates a method type with the given components.
    268      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    269      * The resulting method has the single given parameter type.
    270      * @param rtype  the return type
    271      * @param ptype0 the parameter type
    272      * @return a method type with the given return value and parameter type
    273      * @throws NullPointerException if {@code rtype} or {@code ptype0} is null
    274      * @throws IllegalArgumentException if {@code ptype0} is {@code void.class}
    275      */
    276     public static
    277     MethodType methodType(Class<?> rtype, Class<?> ptype0) {
    278         return makeImpl(rtype, new Class<?>[]{ ptype0 }, true);
    279     }
    280 
    281     /**
    282      * Finds or creates a method type with the given components.
    283      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    284      * The resulting method has the same parameter types as {@code ptypes},
    285      * and the specified return type.
    286      * @param rtype  the return type
    287      * @param ptypes the method type which supplies the parameter types
    288      * @return a method type with the given components
    289      * @throws NullPointerException if {@code rtype} or {@code ptypes} is null
    290      */
    291     public static
    292     MethodType methodType(Class<?> rtype, MethodType ptypes) {
    293         return makeImpl(rtype, ptypes.ptypes, true);
    294     }
    295 
    296     /**
    297      * Sole factory method to find or create an interned method type.
    298      * @param rtype desired return type
    299      * @param ptypes desired parameter types
    300      * @param trusted whether the ptypes can be used without cloning
    301      * @return the unique method type of the desired structure
    302      */
    303     /*trusted*/ static
    304     MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
    305         MethodType mt = internTable.get(new MethodType(ptypes, rtype));
    306         if (mt != null)
    307             return mt;
    308         if (ptypes.length == 0) {
    309             ptypes = NO_PTYPES; trusted = true;
    310         }
    311         mt = new MethodType(rtype, ptypes, trusted);
    312         // promote the object to the Real Thing, and reprobe
    313         mt.form = MethodTypeForm.findForm(mt);
    314         return internTable.add(mt);
    315     }
    316     private static final MethodType[] objectOnlyTypes = new MethodType[20];
    317 
    318     /**
    319      * Finds or creates a method type whose components are {@code Object} with an optional trailing {@code Object[]} array.
    320      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    321      * All parameters and the return type will be {@code Object},
    322      * except the final array parameter if any, which will be {@code Object[]}.
    323      * @param objectArgCount number of parameters (excluding the final array parameter if any)
    324      * @param finalArray whether there will be a trailing array parameter, of type {@code Object[]}
    325      * @return a generally applicable method type, for all calls of the given fixed argument count and a collected array of further arguments
    326      * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray} is true)
    327      * @see #genericMethodType(int)
    328      */
    329     public static
    330     MethodType genericMethodType(int objectArgCount, boolean finalArray) {
    331         MethodType mt;
    332         checkSlotCount(objectArgCount);
    333         int ivarargs = (!finalArray ? 0 : 1);
    334         int ootIndex = objectArgCount*2 + ivarargs;
    335         if (ootIndex < objectOnlyTypes.length) {
    336             mt = objectOnlyTypes[ootIndex];
    337             if (mt != null)  return mt;
    338         }
    339         Class<?>[] ptypes = new Class<?>[objectArgCount + ivarargs];
    340         Arrays.fill(ptypes, Object.class);
    341         if (ivarargs != 0)  ptypes[objectArgCount] = Object[].class;
    342         mt = makeImpl(Object.class, ptypes, true);
    343         if (ootIndex < objectOnlyTypes.length) {
    344             objectOnlyTypes[ootIndex] = mt;     // cache it here also!
    345         }
    346         return mt;
    347     }
    348 
    349     /**
    350      * Finds or creates a method type whose components are all {@code Object}.
    351      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    352      * All parameters and the return type will be Object.
    353      * @param objectArgCount number of parameters
    354      * @return a generally applicable method type, for all calls of the given argument count
    355      * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255
    356      * @see #genericMethodType(int, boolean)
    357      */
    358     public static
    359     MethodType genericMethodType(int objectArgCount) {
    360         return genericMethodType(objectArgCount, false);
    361     }
    362 
    363     /**
    364      * Finds or creates a method type with a single different parameter type.
    365      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    366      * @param num    the index (zero-based) of the parameter type to change
    367      * @param nptype a new parameter type to replace the old one with
    368      * @return the same type, except with the selected parameter changed
    369      * @throws IndexOutOfBoundsException if {@code num} is not a valid index into {@code parameterArray()}
    370      * @throws IllegalArgumentException if {@code nptype} is {@code void.class}
    371      * @throws NullPointerException if {@code nptype} is null
    372      */
    373     public MethodType changeParameterType(int num, Class<?> nptype) {
    374         if (parameterType(num) == nptype)  return this;
    375         checkPtype(nptype);
    376         Class<?>[] nptypes = ptypes.clone();
    377         nptypes[num] = nptype;
    378         return makeImpl(rtype, nptypes, true);
    379     }
    380 
    381     /**
    382      * Finds or creates a method type with additional parameter types.
    383      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    384      * @param num    the position (zero-based) of the inserted parameter type(s)
    385      * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
    386      * @return the same type, except with the selected parameter(s) inserted
    387      * @throws IndexOutOfBoundsException if {@code num} is negative or greater than {@code parameterCount()}
    388      * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
    389      *                                  or if the resulting method type would have more than 255 parameter slots
    390      * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
    391      */
    392     public MethodType insertParameterTypes(int num, Class<?>... ptypesToInsert) {
    393         int len = ptypes.length;
    394         if (num < 0 || num > len)
    395             throw newIndexOutOfBoundsException(num);
    396         int ins = checkPtypes(ptypesToInsert);
    397         checkSlotCount(parameterSlotCount() + ptypesToInsert.length + ins);
    398         int ilen = ptypesToInsert.length;
    399         if (ilen == 0)  return this;
    400         Class<?>[] nptypes = Arrays.copyOfRange(ptypes, 0, len+ilen);
    401         System.arraycopy(nptypes, num, nptypes, num+ilen, len-num);
    402         System.arraycopy(ptypesToInsert, 0, nptypes, num, ilen);
    403         return makeImpl(rtype, nptypes, true);
    404     }
    405 
    406     /**
    407      * Finds or creates a method type with additional parameter types.
    408      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    409      * @param ptypesToInsert zero or more new parameter types to insert after the end of the parameter list
    410      * @return the same type, except with the selected parameter(s) appended
    411      * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
    412      *                                  or if the resulting method type would have more than 255 parameter slots
    413      * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
    414      */
    415     public MethodType appendParameterTypes(Class<?>... ptypesToInsert) {
    416         return insertParameterTypes(parameterCount(), ptypesToInsert);
    417     }
    418 
    419     /**
    420      * Finds or creates a method type with additional parameter types.
    421      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    422      * @param num    the position (zero-based) of the inserted parameter type(s)
    423      * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
    424      * @return the same type, except with the selected parameter(s) inserted
    425      * @throws IndexOutOfBoundsException if {@code num} is negative or greater than {@code parameterCount()}
    426      * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
    427      *                                  or if the resulting method type would have more than 255 parameter slots
    428      * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
    429      */
    430     public MethodType insertParameterTypes(int num, List<Class<?>> ptypesToInsert) {
    431         return insertParameterTypes(num, listToArray(ptypesToInsert));
    432     }
    433 
    434     /**
    435      * Finds or creates a method type with additional parameter types.
    436      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    437      * @param ptypesToInsert zero or more new parameter types to insert after the end of the parameter list
    438      * @return the same type, except with the selected parameter(s) appended
    439      * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
    440      *                                  or if the resulting method type would have more than 255 parameter slots
    441      * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
    442      */
    443     public MethodType appendParameterTypes(List<Class<?>> ptypesToInsert) {
    444         return insertParameterTypes(parameterCount(), ptypesToInsert);
    445     }
    446 
    447      /**
    448      * Finds or creates a method type with modified parameter types.
    449      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    450      * @param start  the position (zero-based) of the first replaced parameter type(s)
    451      * @param end    the position (zero-based) after the last replaced parameter type(s)
    452      * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
    453      * @return the same type, except with the selected parameter(s) replaced
    454      * @throws IndexOutOfBoundsException if {@code start} is negative or greater than {@code parameterCount()}
    455      *                                  or if {@code end} is negative or greater than {@code parameterCount()}
    456      *                                  or if {@code start} is greater than {@code end}
    457      * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
    458      *                                  or if the resulting method type would have more than 255 parameter slots
    459      * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
    460      */
    461     /*non-public*/ MethodType replaceParameterTypes(int start, int end, Class<?>... ptypesToInsert) {
    462         if (start == end)
    463             return insertParameterTypes(start, ptypesToInsert);
    464         int len = ptypes.length;
    465         if (!(0 <= start && start <= end && end <= len))
    466             throw newIndexOutOfBoundsException("start="+start+" end="+end);
    467         int ilen = ptypesToInsert.length;
    468         if (ilen == 0)
    469             return dropParameterTypes(start, end);
    470         return dropParameterTypes(start, end).insertParameterTypes(start, ptypesToInsert);
    471     }
    472 
    473     /** Replace the last arrayLength parameter types with the component type of arrayType.
    474      * @param arrayType any array type
    475      * @param arrayLength the number of parameter types to change
    476      * @return the resulting type
    477      */
    478     /*non-public*/ MethodType asSpreaderType(Class<?> arrayType, int arrayLength) {
    479         assert(parameterCount() >= arrayLength);
    480         int spreadPos = ptypes.length - arrayLength;
    481         if (arrayLength == 0)  return this;  // nothing to change
    482         if (arrayType == Object[].class) {
    483             if (isGeneric())  return this;  // nothing to change
    484             if (spreadPos == 0) {
    485                 // no leading arguments to preserve; go generic
    486                 MethodType res = genericMethodType(arrayLength);
    487                 if (rtype != Object.class) {
    488                     res = res.changeReturnType(rtype);
    489                 }
    490                 return res;
    491             }
    492         }
    493         Class<?> elemType = arrayType.getComponentType();
    494         assert(elemType != null);
    495         for (int i = spreadPos; i < ptypes.length; i++) {
    496             if (ptypes[i] != elemType) {
    497                 Class<?>[] fixedPtypes = ptypes.clone();
    498                 Arrays.fill(fixedPtypes, i, ptypes.length, elemType);
    499                 return methodType(rtype, fixedPtypes);
    500             }
    501         }
    502         return this;  // arguments check out; no change
    503     }
    504 
    505     /** Return the leading parameter type, which must exist and be a reference.
    506      *  @return the leading parameter type, after error checks
    507      */
    508     /*non-public*/ Class<?> leadingReferenceParameter() {
    509         Class<?> ptype;
    510         if (ptypes.length == 0 ||
    511             (ptype = ptypes[0]).isPrimitive())
    512             throw newIllegalArgumentException("no leading reference parameter");
    513         return ptype;
    514     }
    515 
    516     /** Delete the last parameter type and replace it with arrayLength copies of the component type of arrayType.
    517      * @param arrayType any array type
    518      * @param arrayLength the number of parameter types to insert
    519      * @return the resulting type
    520      */
    521     /*non-public*/ MethodType asCollectorType(Class<?> arrayType, int arrayLength) {
    522         assert(parameterCount() >= 1);
    523         assert(lastParameterType().isAssignableFrom(arrayType));
    524         MethodType res;
    525         if (arrayType == Object[].class) {
    526             res = genericMethodType(arrayLength);
    527             if (rtype != Object.class) {
    528                 res = res.changeReturnType(rtype);
    529             }
    530         } else {
    531             Class<?> elemType = arrayType.getComponentType();
    532             assert(elemType != null);
    533             res = methodType(rtype, Collections.nCopies(arrayLength, elemType));
    534         }
    535         if (ptypes.length == 1) {
    536             return res;
    537         } else {
    538             return res.insertParameterTypes(0, parameterList().subList(0, ptypes.length-1));
    539         }
    540     }
    541 
    542     /**
    543      * Finds or creates a method type with some parameter types omitted.
    544      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    545      * @param start  the index (zero-based) of the first parameter type to remove
    546      * @param end    the index (greater than {@code start}) of the first parameter type after not to remove
    547      * @return the same type, except with the selected parameter(s) removed
    548      * @throws IndexOutOfBoundsException if {@code start} is negative or greater than {@code parameterCount()}
    549      *                                  or if {@code end} is negative or greater than {@code parameterCount()}
    550      *                                  or if {@code start} is greater than {@code end}
    551      */
    552     public MethodType dropParameterTypes(int start, int end) {
    553         int len = ptypes.length;
    554         if (!(0 <= start && start <= end && end <= len))
    555             throw newIndexOutOfBoundsException("start="+start+" end="+end);
    556         if (start == end)  return this;
    557         Class<?>[] nptypes;
    558         if (start == 0) {
    559             if (end == len) {
    560                 // drop all parameters
    561                 nptypes = NO_PTYPES;
    562             } else {
    563                 // drop initial parameter(s)
    564                 nptypes = Arrays.copyOfRange(ptypes, end, len);
    565             }
    566         } else {
    567             if (end == len) {
    568                 // drop trailing parameter(s)
    569                 nptypes = Arrays.copyOfRange(ptypes, 0, start);
    570             } else {
    571                 int tail = len - end;
    572                 nptypes = Arrays.copyOfRange(ptypes, 0, start + tail);
    573                 System.arraycopy(ptypes, end, nptypes, start, tail);
    574             }
    575         }
    576         return makeImpl(rtype, nptypes, true);
    577     }
    578 
    579     /**
    580      * Finds or creates a method type with a different return type.
    581      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    582      * @param nrtype a return parameter type to replace the old one with
    583      * @return the same type, except with the return type change
    584      * @throws NullPointerException if {@code nrtype} is null
    585      */
    586     public MethodType changeReturnType(Class<?> nrtype) {
    587         if (returnType() == nrtype)  return this;
    588         return makeImpl(nrtype, ptypes, true);
    589     }
    590 
    591     /**
    592      * Reports if this type contains a primitive argument or return value.
    593      * The return type {@code void} counts as a primitive.
    594      * @return true if any of the types are primitives
    595      */
    596     public boolean hasPrimitives() {
    597         return form.hasPrimitives();
    598     }
    599 
    600     /**
    601      * Reports if this type contains a wrapper argument or return value.
    602      * Wrappers are types which box primitive values, such as {@link Integer}.
    603      * The reference type {@code java.lang.Void} counts as a wrapper,
    604      * if it occurs as a return type.
    605      * @return true if any of the types are wrappers
    606      */
    607     public boolean hasWrappers() {
    608         return unwrap() != this;
    609     }
    610 
    611     /**
    612      * Erases all reference types to {@code Object}.
    613      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    614      * All primitive types (including {@code void}) will remain unchanged.
    615      * @return a version of the original type with all reference types replaced
    616      */
    617     public MethodType erase() {
    618         return form.erasedType();
    619     }
    620 
    621     /**
    622      * Erases all reference types to {@code Object}, and all subword types to {@code int}.
    623      * This is the reduced type polymorphism used by private methods
    624      * such as {@link MethodHandle#invokeBasic invokeBasic}.
    625      * @return a version of the original type with all reference and subword types replaced
    626      */
    627     /*non-public*/ MethodType basicType() {
    628         return form.basicType();
    629     }
    630 
    631     /**
    632      * @return a version of the original type with MethodHandle prepended as the first argument
    633      */
    634     /*non-public*/ MethodType invokerType() {
    635         return insertParameterTypes(0, MethodHandle.class);
    636     }
    637 
    638     /**
    639      * Converts all types, both reference and primitive, to {@code Object}.
    640      * Convenience method for {@link #genericMethodType(int) genericMethodType}.
    641      * The expression {@code type.wrap().erase()} produces the same value
    642      * as {@code type.generic()}.
    643      * @return a version of the original type with all types replaced
    644      */
    645     public MethodType generic() {
    646         return genericMethodType(parameterCount());
    647     }
    648 
    649     /*non-public*/ boolean isGeneric() {
    650         return this == erase() && !hasPrimitives();
    651     }
    652 
    653     /**
    654      * Converts all primitive types to their corresponding wrapper types.
    655      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    656      * All reference types (including wrapper types) will remain unchanged.
    657      * A {@code void} return type is changed to the type {@code java.lang.Void}.
    658      * The expression {@code type.wrap().erase()} produces the same value
    659      * as {@code type.generic()}.
    660      * @return a version of the original type with all primitive types replaced
    661      */
    662     public MethodType wrap() {
    663         return hasPrimitives() ? wrapWithPrims(this) : this;
    664     }
    665 
    666     /**
    667      * Converts all wrapper types to their corresponding primitive types.
    668      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    669      * All primitive types (including {@code void}) will remain unchanged.
    670      * A return type of {@code java.lang.Void} is changed to {@code void}.
    671      * @return a version of the original type with all wrapper types replaced
    672      */
    673     public MethodType unwrap() {
    674         MethodType noprims = !hasPrimitives() ? this : wrapWithPrims(this);
    675         return unwrapWithNoPrims(noprims);
    676     }
    677 
    678     private static MethodType wrapWithPrims(MethodType pt) {
    679         assert(pt.hasPrimitives());
    680         MethodType wt = pt.wrapAlt;
    681         if (wt == null) {
    682             // fill in lazily
    683             wt = MethodTypeForm.canonicalize(pt, MethodTypeForm.WRAP, MethodTypeForm.WRAP);
    684             assert(wt != null);
    685             pt.wrapAlt = wt;
    686         }
    687         return wt;
    688     }
    689 
    690     private static MethodType unwrapWithNoPrims(MethodType wt) {
    691         assert(!wt.hasPrimitives());
    692         MethodType uwt = wt.wrapAlt;
    693         if (uwt == null) {
    694             // fill in lazily
    695             uwt = MethodTypeForm.canonicalize(wt, MethodTypeForm.UNWRAP, MethodTypeForm.UNWRAP);
    696             if (uwt == null)
    697                 uwt = wt;    // type has no wrappers or prims at all
    698             wt.wrapAlt = uwt;
    699         }
    700         return uwt;
    701     }
    702 
    703     /**
    704      * Returns the parameter type at the specified index, within this method type.
    705      * @param num the index (zero-based) of the desired parameter type
    706      * @return the selected parameter type
    707      * @throws IndexOutOfBoundsException if {@code num} is not a valid index into {@code parameterArray()}
    708      */
    709     public Class<?> parameterType(int num) {
    710         return ptypes[num];
    711     }
    712     /**
    713      * Returns the number of parameter types in this method type.
    714      * @return the number of parameter types
    715      */
    716     public int parameterCount() {
    717         return ptypes.length;
    718     }
    719     /**
    720      * Returns the return type of this method type.
    721      * @return the return type
    722      */
    723     public Class<?> returnType() {
    724         return rtype;
    725     }
    726 
    727     /**
    728      * Presents the parameter types as a list (a convenience method).
    729      * The list will be immutable.
    730      * @return the parameter types (as an immutable list)
    731      */
    732     public List<Class<?>> parameterList() {
    733         return Collections.unmodifiableList(Arrays.asList(ptypes.clone()));
    734     }
    735 
    736     /*non-public*/ Class<?> lastParameterType() {
    737         int len = ptypes.length;
    738         return len == 0 ? void.class : ptypes[len-1];
    739     }
    740 
    741     /**
    742      * Presents the parameter types as an array (a convenience method).
    743      * Changes to the array will not result in changes to the type.
    744      * @return the parameter types (as a fresh copy if necessary)
    745      */
    746     public Class<?>[] parameterArray() {
    747         return ptypes.clone();
    748     }
    749 
    750     /**
    751      * Compares the specified object with this type for equality.
    752      * That is, it returns <tt>true</tt> if and only if the specified object
    753      * is also a method type with exactly the same parameters and return type.
    754      * @param x object to compare
    755      * @see Object#equals(Object)
    756      */
    757     @Override
    758     public boolean equals(Object x) {
    759         return this == x || x instanceof MethodType && equals((MethodType)x);
    760     }
    761 
    762     private boolean equals(MethodType that) {
    763         return this.rtype == that.rtype
    764             && Arrays.equals(this.ptypes, that.ptypes);
    765     }
    766 
    767     /**
    768      * Returns the hash code value for this method type.
    769      * It is defined to be the same as the hashcode of a List
    770      * whose elements are the return type followed by the
    771      * parameter types.
    772      * @return the hash code value for this method type
    773      * @see Object#hashCode()
    774      * @see #equals(Object)
    775      * @see List#hashCode()
    776      */
    777     @Override
    778     public int hashCode() {
    779       int hashCode = 31 + rtype.hashCode();
    780       for (Class<?> ptype : ptypes)
    781           hashCode = 31*hashCode + ptype.hashCode();
    782       return hashCode;
    783     }
    784 
    785     /**
    786      * Returns a string representation of the method type,
    787      * of the form {@code "(PT0,PT1...)RT"}.
    788      * The string representation of a method type is a
    789      * parenthesis enclosed, comma separated list of type names,
    790      * followed immediately by the return type.
    791      * <p>
    792      * Each type is represented by its
    793      * {@link java.lang.Class#getSimpleName simple name}.
    794      */
    795     @Override
    796     public String toString() {
    797         StringBuilder sb = new StringBuilder();
    798         sb.append("(");
    799         for (int i = 0; i < ptypes.length; i++) {
    800             if (i > 0)  sb.append(",");
    801             sb.append(ptypes[i].getSimpleName());
    802         }
    803         sb.append(")");
    804         sb.append(rtype.getSimpleName());
    805         return sb.toString();
    806     }
    807 
    808     /** True if the old return type can always be viewed (w/o casting) under new return type,
    809      *  and the new parameters can be viewed (w/o casting) under the old parameter types.
    810      */
    811     // Android-changed: Removed implementation details.
    812     // boolean isViewableAs(MethodType newType, boolean keepInterfaces);
    813     // boolean parametersAreViewableAs(MethodType newType, boolean keepInterfaces);
    814     /*non-public*/
    815     boolean isConvertibleTo(MethodType newType) {
    816         MethodTypeForm oldForm = this.form();
    817         MethodTypeForm newForm = newType.form();
    818         if (oldForm == newForm)
    819             // same parameter count, same primitive/object mix
    820             return true;
    821         if (!canConvert(returnType(), newType.returnType()))
    822             return false;
    823         Class<?>[] srcTypes = newType.ptypes;
    824         Class<?>[] dstTypes = ptypes;
    825         if (srcTypes == dstTypes)
    826             return true;
    827         int argc;
    828         if ((argc = srcTypes.length) != dstTypes.length)
    829             return false;
    830         if (argc <= 1) {
    831             if (argc == 1 && !canConvert(srcTypes[0], dstTypes[0]))
    832                 return false;
    833             return true;
    834         }
    835         if ((oldForm.primitiveParameterCount() == 0 && oldForm.erasedType == this) ||
    836             (newForm.primitiveParameterCount() == 0 && newForm.erasedType == newType)) {
    837             // Somewhat complicated test to avoid a loop of 2 or more trips.
    838             // If either type has only Object parameters, we know we can convert.
    839             assert(canConvertParameters(srcTypes, dstTypes));
    840             return true;
    841         }
    842         return canConvertParameters(srcTypes, dstTypes);
    843     }
    844 
    845     /** Returns true if MHs.explicitCastArguments produces the same result as MH.asType.
    846      *  If the type conversion is impossible for either, the result should be false.
    847      */
    848     /*non-public*/
    849     boolean explicitCastEquivalentToAsType(MethodType newType) {
    850         if (this == newType)  return true;
    851         if (!explicitCastEquivalentToAsType(rtype, newType.rtype)) {
    852             return false;
    853         }
    854         Class<?>[] srcTypes = newType.ptypes;
    855         Class<?>[] dstTypes = ptypes;
    856         if (dstTypes == srcTypes) {
    857             return true;
    858         }
    859         assert(dstTypes.length == srcTypes.length);
    860         for (int i = 0; i < dstTypes.length; i++) {
    861             if (!explicitCastEquivalentToAsType(srcTypes[i], dstTypes[i])) {
    862                 return false;
    863             }
    864         }
    865         return true;
    866     }
    867 
    868     /** Reports true if the src can be converted to the dst, by both asType and MHs.eCE,
    869      *  and with the same effect.
    870      *  MHs.eCA has the following "upgrades" to MH.asType:
    871      *  1. interfaces are unchecked (that is, treated as if aliased to Object)
    872      *     Therefore, {@code Object->CharSequence} is possible in both cases but has different semantics
    873      *  2a. the full matrix of primitive-to-primitive conversions is supported
    874      *      Narrowing like {@code long->byte} and basic-typing like {@code boolean->int}
    875      *      are not supported by asType, but anything supported by asType is equivalent
    876      *      with MHs.eCE.
    877      *  2b. conversion of void->primitive means explicit cast has to insert zero/false/null.
    878      *  3a. unboxing conversions can be followed by the full matrix of primitive conversions
    879      *  3b. unboxing of null is permitted (creates a zero primitive value)
    880      * Other than interfaces, reference-to-reference conversions are the same.
    881      * Boxing primitives to references is the same for both operators.
    882      */
    883     private static boolean explicitCastEquivalentToAsType(Class<?> src, Class<?> dst) {
    884         if (src == dst || dst == Object.class || dst == void.class) {
    885             return true;
    886         } else if (src.isPrimitive() && src != void.class) {
    887             // Could be a prim/prim conversion, where casting is a strict superset.
    888             // Or a boxing conversion, which is always to an exact wrapper class.
    889             return canConvert(src, dst);
    890         } else if (dst.isPrimitive()) {
    891             // Unboxing behavior is different between MHs.eCA & MH.asType (see 3b).
    892             return false;
    893         } else {
    894             // R->R always works, but we have to avoid a check-cast to an interface.
    895             return !dst.isInterface() || dst.isAssignableFrom(src);
    896         }
    897     }
    898 
    899     private boolean canConvertParameters(Class<?>[] srcTypes, Class<?>[] dstTypes) {
    900         for (int i = 0; i < srcTypes.length; i++) {
    901             if (!canConvert(srcTypes[i], dstTypes[i])) {
    902                 return false;
    903             }
    904         }
    905         return true;
    906     }
    907 
    908     /*non-public*/
    909     static boolean canConvert(Class<?> src, Class<?> dst) {
    910         // short-circuit a few cases:
    911         if (src == dst || src == Object.class || dst == Object.class)  return true;
    912         // the remainder of this logic is documented in MethodHandle.asType
    913         if (src.isPrimitive()) {
    914             // can force void to an explicit null, a la reflect.Method.invoke
    915             // can also force void to a primitive zero, by analogy
    916             if (src == void.class)  return true;  //or !dst.isPrimitive()?
    917             Wrapper sw = Wrapper.forPrimitiveType(src);
    918             if (dst.isPrimitive()) {
    919                 // P->P must widen
    920                 return Wrapper.forPrimitiveType(dst).isConvertibleFrom(sw);
    921             } else {
    922                 // P->R must box and widen
    923                 return dst.isAssignableFrom(sw.wrapperType());
    924             }
    925         } else if (dst.isPrimitive()) {
    926             // any value can be dropped
    927             if (dst == void.class)  return true;
    928             Wrapper dw = Wrapper.forPrimitiveType(dst);
    929             // R->P must be able to unbox (from a dynamically chosen type) and widen
    930             // For example:
    931             //   Byte/Number/Comparable/Object -> dw:Byte -> byte.
    932             //   Character/Comparable/Object -> dw:Character -> char
    933             //   Boolean/Comparable/Object -> dw:Boolean -> boolean
    934             // This means that dw must be cast-compatible with src.
    935             if (src.isAssignableFrom(dw.wrapperType())) {
    936                 return true;
    937             }
    938             // The above does not work if the source reference is strongly typed
    939             // to a wrapper whose primitive must be widened.  For example:
    940             //   Byte -> unbox:byte -> short/int/long/float/double
    941             //   Character -> unbox:char -> int/long/float/double
    942             if (Wrapper.isWrapperType(src) &&
    943                 dw.isConvertibleFrom(Wrapper.forWrapperType(src))) {
    944                 // can unbox from src and then widen to dst
    945                 return true;
    946             }
    947             // We have already covered cases which arise due to runtime unboxing
    948             // of a reference type which covers several wrapper types:
    949             //   Object -> cast:Integer -> unbox:int -> long/float/double
    950             //   Serializable -> cast:Byte -> unbox:byte -> byte/short/int/long/float/double
    951             // An marginal case is Number -> dw:Character -> char, which would be OK if there were a
    952             // subclass of Number which wraps a value that can convert to char.
    953             // Since there is none, we don't need an extra check here to cover char or boolean.
    954             return false;
    955         } else {
    956             // R->R always works, since null is always valid dynamically
    957             return true;
    958         }
    959     }
    960 
    961     /** Reports the number of JVM stack slots required to invoke a method
    962      * of this type.  Note that (for historical reasons) the JVM requires
    963      * a second stack slot to pass long and double arguments.
    964      * So this method returns {@link #parameterCount() parameterCount} plus the
    965      * number of long and double parameters (if any).
    966      * <p>
    967      * This method is included for the benefit of applications that must
    968      * generate bytecodes that process method handles and invokedynamic.
    969      * @return the number of JVM stack slots for this type's parameters
    970      */
    971     /*non-public*/ int parameterSlotCount() {
    972         return form.parameterSlotCount();
    973     }
    974 
    975     /// Queries which have to do with the bytecode architecture
    976 
    977     // Android-changed: These methods aren't needed on Android and are unused within the JDK.
    978     //
    979     // int parameterSlotDepth(int num);
    980     // int returnSlotCount();
    981     //
    982     // Android-changed: Removed cache of higher order adapters.
    983     //
    984     // Invokers invokers();
    985 
    986     /**
    987      * Finds or creates an instance of a method type, given the spelling of its bytecode descriptor.
    988      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
    989      * Any class or interface name embedded in the descriptor string
    990      * will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)}
    991      * on the given loader (or if it is null, on the system class loader).
    992      * <p>
    993      * Note that it is possible to encounter method types which cannot be
    994      * constructed by this method, because their component types are
    995      * not all reachable from a common class loader.
    996      * <p>
    997      * This method is included for the benefit of applications that must
    998      * generate bytecodes that process method handles and {@code invokedynamic}.
    999      * @param descriptor a bytecode-level type descriptor string "(T...)T"
   1000      * @param loader the class loader in which to look up the types
   1001      * @return a method type matching the bytecode-level type descriptor
   1002      * @throws NullPointerException if the string is null
   1003      * @throws IllegalArgumentException if the string is not well-formed
   1004      * @throws TypeNotPresentException if a named type cannot be found
   1005      */
   1006     public static MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader)
   1007         throws IllegalArgumentException, TypeNotPresentException
   1008     {
   1009         if (!descriptor.startsWith("(") ||  // also generates NPE if needed
   1010             descriptor.indexOf(')') < 0 ||
   1011             descriptor.indexOf('.') >= 0)
   1012             throw newIllegalArgumentException("not a method descriptor: "+descriptor);
   1013         List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader);
   1014         Class<?> rtype = types.remove(types.size() - 1);
   1015         checkSlotCount(types.size());
   1016         Class<?>[] ptypes = listToArray(types);
   1017         return makeImpl(rtype, ptypes, true);
   1018     }
   1019 
   1020     /**
   1021      * Produces a bytecode descriptor representation of the method type.
   1022      * <p>
   1023      * Note that this is not a strict inverse of {@link #fromMethodDescriptorString fromMethodDescriptorString}.
   1024      * Two distinct classes which share a common name but have different class loaders
   1025      * will appear identical when viewed within descriptor strings.
   1026      * <p>
   1027      * This method is included for the benefit of applications that must
   1028      * generate bytecodes that process method handles and {@code invokedynamic}.
   1029      * {@link #fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) fromMethodDescriptorString},
   1030      * because the latter requires a suitable class loader argument.
   1031      * @return the bytecode type descriptor representation
   1032      */
   1033     public String toMethodDescriptorString() {
   1034         String desc = methodDescriptor;
   1035         if (desc == null) {
   1036             desc = BytecodeDescriptor.unparse(this);
   1037             methodDescriptor = desc;
   1038         }
   1039         return desc;
   1040     }
   1041 
   1042     /*non-public*/ static String toFieldDescriptorString(Class<?> cls) {
   1043         return BytecodeDescriptor.unparse(cls);
   1044     }
   1045 
   1046     /// Serialization.
   1047 
   1048     /**
   1049      * There are no serializable fields for {@code MethodType}.
   1050      */
   1051     private static final java.io.ObjectStreamField[] serialPersistentFields = { };
   1052 
   1053     /**
   1054      * Save the {@code MethodType} instance to a stream.
   1055      *
   1056      * @serialData
   1057      * For portability, the serialized format does not refer to named fields.
   1058      * Instead, the return type and parameter type arrays are written directly
   1059      * from the {@code writeObject} method, using two calls to {@code s.writeObject}
   1060      * as follows:
   1061      * <blockquote><pre>{@code
   1062 s.writeObject(this.returnType());
   1063 s.writeObject(this.parameterArray());
   1064      * }</pre></blockquote>
   1065      * <p>
   1066      * The deserialized field values are checked as if they were
   1067      * provided to the factory method {@link #methodType(Class,Class[]) methodType}.
   1068      * For example, null values, or {@code void} parameter types,
   1069      * will lead to exceptions during deserialization.
   1070      * @param s the stream to write the object to
   1071      * @throws java.io.IOException if there is a problem writing the object
   1072      */
   1073     private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
   1074         s.defaultWriteObject();  // requires serialPersistentFields to be an empty array
   1075         s.writeObject(returnType());
   1076         s.writeObject(parameterArray());
   1077     }
   1078 
   1079     /**
   1080      * Reconstitute the {@code MethodType} instance from a stream (that is,
   1081      * deserialize it).
   1082      * This instance is a scratch object with bogus final fields.
   1083      * It provides the parameters to the factory method called by
   1084      * {@link #readResolve readResolve}.
   1085      * After that call it is discarded.
   1086      * @param s the stream to read the object from
   1087      * @throws java.io.IOException if there is a problem reading the object
   1088      * @throws ClassNotFoundException if one of the component classes cannot be resolved
   1089      * @see #MethodType()
   1090      * @see #readResolve
   1091      * @see #writeObject
   1092      */
   1093     private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
   1094         s.defaultReadObject();  // requires serialPersistentFields to be an empty array
   1095 
   1096         Class<?>   returnType     = (Class<?>)   s.readObject();
   1097         Class<?>[] parameterArray = (Class<?>[]) s.readObject();
   1098 
   1099         // Probably this object will never escape, but let's check
   1100         // the field values now, just to be sure.
   1101         checkRtype(returnType);
   1102         checkPtypes(parameterArray);
   1103 
   1104         parameterArray = parameterArray.clone();  // make sure it is unshared
   1105         MethodType_init(returnType, parameterArray);
   1106     }
   1107 
   1108     /**
   1109      * For serialization only.
   1110      * Sets the final fields to null, pending {@code Unsafe.putObject}.
   1111      */
   1112     private MethodType() {
   1113         this.rtype = null;
   1114         this.ptypes = null;
   1115     }
   1116     private void MethodType_init(Class<?> rtype, Class<?>[] ptypes) {
   1117         // In order to communicate these values to readResolve, we must
   1118         // store them into the implementation-specific final fields.
   1119         checkRtype(rtype);
   1120         checkPtypes(ptypes);
   1121         UNSAFE.putObject(this, rtypeOffset, rtype);
   1122         UNSAFE.putObject(this, ptypesOffset, ptypes);
   1123     }
   1124 
   1125     // Support for resetting final fields while deserializing
   1126     private static final long rtypeOffset, ptypesOffset;
   1127     static {
   1128         try {
   1129             rtypeOffset = UNSAFE.objectFieldOffset
   1130                 (MethodType.class.getDeclaredField("rtype"));
   1131             ptypesOffset = UNSAFE.objectFieldOffset
   1132                 (MethodType.class.getDeclaredField("ptypes"));
   1133         } catch (Exception ex) {
   1134             throw new Error(ex);
   1135         }
   1136     }
   1137 
   1138     /**
   1139      * Resolves and initializes a {@code MethodType} object
   1140      * after serialization.
   1141      * @return the fully initialized {@code MethodType} object
   1142      */
   1143     private Object readResolve() {
   1144         // Do not use a trusted path for deserialization:
   1145         //return makeImpl(rtype, ptypes, true);
   1146         // Verify all operands, and make sure ptypes is unshared:
   1147         return methodType(rtype, ptypes);
   1148     }
   1149 
   1150     /**
   1151      * Simple implementation of weak concurrent intern set.
   1152      *
   1153      * @param <T> interned type
   1154      */
   1155     private static class ConcurrentWeakInternSet<T> {
   1156 
   1157         private final ConcurrentMap<WeakEntry<T>, WeakEntry<T>> map;
   1158         private final ReferenceQueue<T> stale;
   1159 
   1160         public ConcurrentWeakInternSet() {
   1161             this.map = new ConcurrentHashMap<>();
   1162             this.stale = new ReferenceQueue<>();
   1163         }
   1164 
   1165         /**
   1166          * Get the existing interned element.
   1167          * This method returns null if no element is interned.
   1168          *
   1169          * @param elem element to look up
   1170          * @return the interned element
   1171          */
   1172         public T get(T elem) {
   1173             if (elem == null) throw new NullPointerException();
   1174             expungeStaleElements();
   1175 
   1176             WeakEntry<T> value = map.get(new WeakEntry<>(elem));
   1177             if (value != null) {
   1178                 T res = value.get();
   1179                 if (res != null) {
   1180                     return res;
   1181                 }
   1182             }
   1183             return null;
   1184         }
   1185 
   1186         /**
   1187          * Interns the element.
   1188          * Always returns non-null element, matching the one in the intern set.
   1189          * Under the race against another add(), it can return <i>different</i>
   1190          * element, if another thread beats us to interning it.
   1191          *
   1192          * @param elem element to add
   1193          * @return element that was actually added
   1194          */
   1195         public T add(T elem) {
   1196             if (elem == null) throw new NullPointerException();
   1197 
   1198             // Playing double race here, and so spinloop is required.
   1199             // First race is with two concurrent updaters.
   1200             // Second race is with GC purging weak ref under our feet.
   1201             // Hopefully, we almost always end up with a single pass.
   1202             T interned;
   1203             WeakEntry<T> e = new WeakEntry<>(elem, stale);
   1204             do {
   1205                 expungeStaleElements();
   1206                 WeakEntry<T> exist = map.putIfAbsent(e, e);
   1207                 interned = (exist == null) ? elem : exist.get();
   1208             } while (interned == null);
   1209             return interned;
   1210         }
   1211 
   1212         private void expungeStaleElements() {
   1213             Reference<? extends T> reference;
   1214             while ((reference = stale.poll()) != null) {
   1215                 map.remove(reference);
   1216             }
   1217         }
   1218 
   1219         private static class WeakEntry<T> extends WeakReference<T> {
   1220 
   1221             public final int hashcode;
   1222 
   1223             public WeakEntry(T key, ReferenceQueue<T> queue) {
   1224                 super(key, queue);
   1225                 hashcode = key.hashCode();
   1226             }
   1227 
   1228             public WeakEntry(T key) {
   1229                 super(key);
   1230                 hashcode = key.hashCode();
   1231             }
   1232 
   1233             @Override
   1234             public boolean equals(Object obj) {
   1235                 if (obj instanceof WeakEntry) {
   1236                     Object that = ((WeakEntry) obj).get();
   1237                     Object mine = get();
   1238                     return (that == null || mine == null) ? (this == obj) : mine.equals(that);
   1239                 }
   1240                 return false;
   1241             }
   1242 
   1243             @Override
   1244             public int hashCode() {
   1245                 return hashcode;
   1246             }
   1247 
   1248         }
   1249     }
   1250 
   1251 }
   1252