rt/emul/compact/src/main/java/java/lang/invoke/MethodType.java
changeset 1692 2f800fdc371e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodType.java	Sun Sep 14 19:27:44 2014 +0200
     1.3 @@ -0,0 +1,846 @@
     1.4 +/*
     1.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.  Oracle designates this
    1.11 + * particular file as subject to the "Classpath" exception as provided
    1.12 + * by Oracle in the LICENSE file that accompanied this code.
    1.13 + *
    1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.17 + * version 2 for more details (a copy is included in the LICENSE file that
    1.18 + * accompanied this code).
    1.19 + *
    1.20 + * You should have received a copy of the GNU General Public License version
    1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.23 + *
    1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.25 + * or visit www.oracle.com if you need additional information or have any
    1.26 + * questions.
    1.27 + */
    1.28 +
    1.29 +package java.lang.invoke;
    1.30 +
    1.31 +import java.lang.ref.WeakReference;
    1.32 +import java.lang.ref.Reference;
    1.33 +import java.lang.ref.ReferenceQueue;
    1.34 +import java.util.Arrays;
    1.35 +import java.util.Collections;
    1.36 +import java.util.List;
    1.37 +import java.util.Objects;
    1.38 +import java.util.concurrent.ConcurrentMap;
    1.39 +import java.util.concurrent.ConcurrentHashMap;
    1.40 +
    1.41 +/**
    1.42 + * A method type represents the arguments and return type accepted and
    1.43 + * returned by a method handle, or the arguments and return type passed
    1.44 + * and expected  by a method handle caller.  Method types must be properly
    1.45 + * matched between a method handle and all its callers,
    1.46 + * and the JVM's operations enforce this matching at, specifically
    1.47 + * during calls to {@link MethodHandle#invokeExact MethodHandle.invokeExact}
    1.48 + * and {@link MethodHandle#invoke MethodHandle.invoke}, and during execution
    1.49 + * of {@code invokedynamic} instructions.
    1.50 + * <p>
    1.51 + * The structure is a return type accompanied by any number of parameter types.
    1.52 + * The types (primitive, {@code void}, and reference) are represented by {@link Class} objects.
    1.53 + * (For ease of exposition, we treat {@code void} as if it were a type.
    1.54 + * In fact, it denotes the absence of a return type.)
    1.55 + * <p>
    1.56 + * All instances of {@code MethodType} are immutable.
    1.57 + * Two instances are completely interchangeable if they compare equal.
    1.58 + * Equality depends on pairwise correspondence of the return and parameter types and on nothing else.
    1.59 + * <p>
    1.60 + * This type can be created only by factory methods.
    1.61 + * All factory methods may cache values, though caching is not guaranteed.
    1.62 + * Some factory methods are static, while others are virtual methods which
    1.63 + * modify precursor method types, e.g., by changing a selected parameter.
    1.64 + * <p>
    1.65 + * Factory methods which operate on groups of parameter types
    1.66 + * are systematically presented in two versions, so that both Java arrays and
    1.67 + * Java lists can be used to work with groups of parameter types.
    1.68 + * The query methods {@code parameterArray} and {@code parameterList}
    1.69 + * also provide a choice between arrays and lists.
    1.70 + * <p>
    1.71 + * {@code MethodType} objects are sometimes derived from bytecode instructions
    1.72 + * such as {@code invokedynamic}, specifically from the type descriptor strings associated
    1.73 + * with the instructions in a class file's constant pool.
    1.74 + * <p>
    1.75 + * Like classes and strings, method types can also be represented directly
    1.76 + * in a class file's constant pool as constants.
    1.77 + * A method type may be loaded by an {@code ldc} instruction which refers
    1.78 + * to a suitable {@code CONSTANT_MethodType} constant pool entry.
    1.79 + * The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string.
    1.80 + * (For full details on method type constants,
    1.81 + * see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine Specification.)
    1.82 + * <p>
    1.83 + * When the JVM materializes a {@code MethodType} from a descriptor string,
    1.84 + * all classes named in the descriptor must be accessible, and will be loaded.
    1.85 + * (But the classes need not be initialized, as is the case with a {@code CONSTANT_Class}.)
    1.86 + * This loading may occur at any time before the {@code MethodType} object is first derived.
    1.87 + * @author John Rose, JSR 292 EG
    1.88 + */
    1.89 +public final
    1.90 +class MethodType implements java.io.Serializable {
    1.91 +    private static final long serialVersionUID = 292L;  // {rtype, {ptype...}}
    1.92 +
    1.93 +    // The rtype and ptypes fields define the structural identity of the method type:
    1.94 +    private final Class<?>   rtype;
    1.95 +    private final Class<?>[] ptypes;
    1.96 +
    1.97 +    /**
    1.98 +     * Check the given parameters for validity and store them into the final fields.
    1.99 +     */
   1.100 +    private MethodType(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
   1.101 +        this.rtype = rtype;
   1.102 +        // defensively copy the array passed in by the user
   1.103 +        this.ptypes = trusted ? ptypes : Arrays.copyOf(ptypes, ptypes.length);
   1.104 +    }
   1.105 +
   1.106 +    /**
   1.107 +     * Construct a temporary unchecked instance of MethodType for use only as a key to the intern table.
   1.108 +     * Does not check the given parameters for validity, and must be discarded after it is used as a searching key.
   1.109 +     * The parameters are reversed for this constructor, so that is is not accidentally used.
   1.110 +     */
   1.111 +    private MethodType(Class<?>[] ptypes, Class<?> rtype) {
   1.112 +        this.rtype = rtype;
   1.113 +        this.ptypes = ptypes;
   1.114 +    }
   1.115 +
   1.116 +    /** This number, mandated by the JVM spec as 255,
   1.117 +     *  is the maximum number of <em>slots</em>
   1.118 +     *  that any Java method can receive in its argument list.
   1.119 +     *  It limits both JVM signatures and method type objects.
   1.120 +     *  The longest possible invocation will look like
   1.121 +     *  {@code staticMethod(arg1, arg2, ..., arg255)} or
   1.122 +     *  {@code x.virtualMethod(arg1, arg2, ..., arg254)}.
   1.123 +     */
   1.124 +    /*non-public*/ static final int MAX_JVM_ARITY = 255;  // this is mandated by the JVM spec.
   1.125 +
   1.126 +    /** This number is the maximum arity of a method handle, 254.
   1.127 +     *  It is derived from the absolute JVM-imposed arity by subtracting one,
   1.128 +     *  which is the slot occupied by the method handle itself at the
   1.129 +     *  beginning of the argument list used to invoke the method handle.
   1.130 +     *  The longest possible invocation will look like
   1.131 +     *  {@code mh.invoke(arg1, arg2, ..., arg254)}.
   1.132 +     */
   1.133 +    // Issue:  Should we allow MH.invokeWithArguments to go to the full 255?
   1.134 +    /*non-public*/ static final int MAX_MH_ARITY = MAX_JVM_ARITY-1;  // deduct one for mh receiver
   1.135 +
   1.136 +    /** This number is the maximum arity of a method handle invoker, 253.
   1.137 +     *  It is derived from the absolute JVM-imposed arity by subtracting two,
   1.138 +     *  which are the slots occupied by invoke method handle, and the
   1.139 +     *  target method handle, which are both at the beginning of the argument
   1.140 +     *  list used to invoke the target method handle.
   1.141 +     *  The longest possible invocation will look like
   1.142 +     *  {@code invokermh.invoke(targetmh, arg1, arg2, ..., arg253)}.
   1.143 +     */
   1.144 +    /*non-public*/ static final int MAX_MH_INVOKER_ARITY = MAX_MH_ARITY-1;  // deduct one more for invoker
   1.145 +
   1.146 +    private static void checkRtype(Class<?> rtype) {
   1.147 +        Objects.requireNonNull(rtype);
   1.148 +    }
   1.149 +
   1.150 +    static final ConcurrentWeakInternSet<MethodType> internTable = new ConcurrentWeakInternSet<>();
   1.151 +
   1.152 +    static final Class<?>[] NO_PTYPES = {};
   1.153 +
   1.154 +    /**
   1.155 +     * Finds or creates an instance of the given method type.
   1.156 +     * @param rtype  the return type
   1.157 +     * @param ptypes the parameter types
   1.158 +     * @return a method type with the given components
   1.159 +     * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
   1.160 +     * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
   1.161 +     */
   1.162 +    public static
   1.163 +    MethodType methodType(Class<?> rtype, Class<?>[] ptypes) {
   1.164 +        return makeImpl(rtype, ptypes, false);
   1.165 +    }
   1.166 +
   1.167 +    /**
   1.168 +     * Finds or creates a method type with the given components.
   1.169 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.170 +     * @param rtype  the return type
   1.171 +     * @param ptypes the parameter types
   1.172 +     * @return a method type with the given components
   1.173 +     * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
   1.174 +     * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
   1.175 +     */
   1.176 +    public static
   1.177 +    MethodType methodType(Class<?> rtype, List<Class<?>> ptypes) {
   1.178 +        boolean notrust = false;  // random List impl. could return evil ptypes array
   1.179 +        return makeImpl(rtype, listToArray(ptypes), notrust);
   1.180 +    }
   1.181 +
   1.182 +    private static Class<?>[] listToArray(List<Class<?>> ptypes) {
   1.183 +        return ptypes.toArray(NO_PTYPES);
   1.184 +    }
   1.185 +
   1.186 +    /**
   1.187 +     * Finds or creates a method type with the given components.
   1.188 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.189 +     * The leading parameter type is prepended to the remaining array.
   1.190 +     * @param rtype  the return type
   1.191 +     * @param ptype0 the first parameter type
   1.192 +     * @param ptypes the remaining parameter types
   1.193 +     * @return a method type with the given components
   1.194 +     * @throws NullPointerException if {@code rtype} or {@code ptype0} or {@code ptypes} or any element of {@code ptypes} is null
   1.195 +     * @throws IllegalArgumentException if {@code ptype0} or {@code ptypes} or any element of {@code ptypes} is {@code void.class}
   1.196 +     */
   1.197 +    public static
   1.198 +    MethodType methodType(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
   1.199 +        Class<?>[] ptypes1 = new Class<?>[1+ptypes.length];
   1.200 +        ptypes1[0] = ptype0;
   1.201 +        System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
   1.202 +        return makeImpl(rtype, ptypes1, true);
   1.203 +    }
   1.204 +
   1.205 +    /**
   1.206 +     * Finds or creates a method type with the given components.
   1.207 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.208 +     * The resulting method has no parameter types.
   1.209 +     * @param rtype  the return type
   1.210 +     * @return a method type with the given return value
   1.211 +     * @throws NullPointerException if {@code rtype} is null
   1.212 +     */
   1.213 +    public static
   1.214 +    MethodType methodType(Class<?> rtype) {
   1.215 +        return makeImpl(rtype, NO_PTYPES, true);
   1.216 +    }
   1.217 +
   1.218 +    /**
   1.219 +     * Finds or creates a method type with the given components.
   1.220 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.221 +     * The resulting method has the single given parameter type.
   1.222 +     * @param rtype  the return type
   1.223 +     * @param ptype0 the parameter type
   1.224 +     * @return a method type with the given return value and parameter type
   1.225 +     * @throws NullPointerException if {@code rtype} or {@code ptype0} is null
   1.226 +     * @throws IllegalArgumentException if {@code ptype0} is {@code void.class}
   1.227 +     */
   1.228 +    public static
   1.229 +    MethodType methodType(Class<?> rtype, Class<?> ptype0) {
   1.230 +        return makeImpl(rtype, new Class<?>[]{ ptype0 }, true);
   1.231 +    }
   1.232 +
   1.233 +    /**
   1.234 +     * Finds or creates a method type with the given components.
   1.235 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.236 +     * The resulting method has the same parameter types as {@code ptypes},
   1.237 +     * and the specified return type.
   1.238 +     * @param rtype  the return type
   1.239 +     * @param ptypes the method type which supplies the parameter types
   1.240 +     * @return a method type with the given components
   1.241 +     * @throws NullPointerException if {@code rtype} or {@code ptypes} is null
   1.242 +     */
   1.243 +    public static
   1.244 +    MethodType methodType(Class<?> rtype, MethodType ptypes) {
   1.245 +        return makeImpl(rtype, ptypes.ptypes, true);
   1.246 +    }
   1.247 +
   1.248 +    /**
   1.249 +     * Sole factory method to find or create an interned method type.
   1.250 +     * @param rtype desired return type
   1.251 +     * @param ptypes desired parameter types
   1.252 +     * @param trusted whether the ptypes can be used without cloning
   1.253 +     * @return the unique method type of the desired structure
   1.254 +     */
   1.255 +    /*trusted*/ static
   1.256 +    MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
   1.257 +        throw new IllegalStateException();
   1.258 +    }
   1.259 +    private static final MethodType[] objectOnlyTypes = new MethodType[20];
   1.260 +
   1.261 +    /**
   1.262 +     * Finds or creates a method type whose components are {@code Object} with an optional trailing {@code Object[]} array.
   1.263 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.264 +     * All parameters and the return type will be {@code Object},
   1.265 +     * except the final array parameter if any, which will be {@code Object[]}.
   1.266 +     * @param objectArgCount number of parameters (excluding the final array parameter if any)
   1.267 +     * @param finalArray whether there will be a trailing array parameter, of type {@code Object[]}
   1.268 +     * @return a generally applicable method type, for all calls of the given fixed argument count and a collected array of further arguments
   1.269 +     * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray} is true)
   1.270 +     * @see #genericMethodType(int)
   1.271 +     */
   1.272 +    public static
   1.273 +    MethodType genericMethodType(int objectArgCount, boolean finalArray) {
   1.274 +        throw new IllegalStateException();
   1.275 +    }
   1.276 +
   1.277 +    /**
   1.278 +     * Finds or creates a method type whose components are all {@code Object}.
   1.279 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.280 +     * All parameters and the return type will be Object.
   1.281 +     * @param objectArgCount number of parameters
   1.282 +     * @return a generally applicable method type, for all calls of the given argument count
   1.283 +     * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255
   1.284 +     * @see #genericMethodType(int, boolean)
   1.285 +     */
   1.286 +    public static
   1.287 +    MethodType genericMethodType(int objectArgCount) {
   1.288 +        return genericMethodType(objectArgCount, false);
   1.289 +    }
   1.290 +
   1.291 +    /**
   1.292 +     * Finds or creates a method type with a single different parameter type.
   1.293 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.294 +     * @param num    the index (zero-based) of the parameter type to change
   1.295 +     * @param nptype a new parameter type to replace the old one with
   1.296 +     * @return the same type, except with the selected parameter changed
   1.297 +     * @throws IndexOutOfBoundsException if {@code num} is not a valid index into {@code parameterArray()}
   1.298 +     * @throws IllegalArgumentException if {@code nptype} is {@code void.class}
   1.299 +     * @throws NullPointerException if {@code nptype} is null
   1.300 +     */
   1.301 +    public MethodType changeParameterType(int num, Class<?> nptype) {
   1.302 +        throw new IllegalStateException();
   1.303 +    }
   1.304 +
   1.305 +    /**
   1.306 +     * Finds or creates a method type with additional parameter types.
   1.307 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.308 +     * @param num    the position (zero-based) of the inserted parameter type(s)
   1.309 +     * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
   1.310 +     * @return the same type, except with the selected parameter(s) inserted
   1.311 +     * @throws IndexOutOfBoundsException if {@code num} is negative or greater than {@code parameterCount()}
   1.312 +     * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
   1.313 +     *                                  or if the resulting method type would have more than 255 parameter slots
   1.314 +     * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
   1.315 +     */
   1.316 +    public MethodType insertParameterTypes(int num, Class<?>... ptypesToInsert) {
   1.317 +        throw new IllegalStateException();
   1.318 +    }
   1.319 +
   1.320 +    /**
   1.321 +     * Finds or creates a method type with additional parameter types.
   1.322 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.323 +     * @param ptypesToInsert zero or more new parameter types to insert after the end of the parameter list
   1.324 +     * @return the same type, except with the selected parameter(s) appended
   1.325 +     * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
   1.326 +     *                                  or if the resulting method type would have more than 255 parameter slots
   1.327 +     * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
   1.328 +     */
   1.329 +    public MethodType appendParameterTypes(Class<?>... ptypesToInsert) {
   1.330 +        return insertParameterTypes(parameterCount(), ptypesToInsert);
   1.331 +    }
   1.332 +
   1.333 +    /**
   1.334 +     * Finds or creates a method type with additional parameter types.
   1.335 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.336 +     * @param num    the position (zero-based) of the inserted parameter type(s)
   1.337 +     * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
   1.338 +     * @return the same type, except with the selected parameter(s) inserted
   1.339 +     * @throws IndexOutOfBoundsException if {@code num} is negative or greater than {@code parameterCount()}
   1.340 +     * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
   1.341 +     *                                  or if the resulting method type would have more than 255 parameter slots
   1.342 +     * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
   1.343 +     */
   1.344 +    public MethodType insertParameterTypes(int num, List<Class<?>> ptypesToInsert) {
   1.345 +        return insertParameterTypes(num, listToArray(ptypesToInsert));
   1.346 +    }
   1.347 +
   1.348 +    /**
   1.349 +     * Finds or creates a method type with additional parameter types.
   1.350 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.351 +     * @param ptypesToInsert zero or more new parameter types to insert after the end of the parameter list
   1.352 +     * @return the same type, except with the selected parameter(s) appended
   1.353 +     * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
   1.354 +     *                                  or if the resulting method type would have more than 255 parameter slots
   1.355 +     * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
   1.356 +     */
   1.357 +    public MethodType appendParameterTypes(List<Class<?>> ptypesToInsert) {
   1.358 +        return insertParameterTypes(parameterCount(), ptypesToInsert);
   1.359 +    }
   1.360 +
   1.361 +     /**
   1.362 +     * Finds or creates a method type with modified parameter types.
   1.363 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.364 +     * @param start  the position (zero-based) of the first replaced parameter type(s)
   1.365 +     * @param end    the position (zero-based) after the last replaced parameter type(s)
   1.366 +     * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
   1.367 +     * @return the same type, except with the selected parameter(s) replaced
   1.368 +     * @throws IndexOutOfBoundsException if {@code start} is negative or greater than {@code parameterCount()}
   1.369 +     *                                  or if {@code end} is negative or greater than {@code parameterCount()}
   1.370 +     *                                  or if {@code start} is greater than {@code end}
   1.371 +     * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
   1.372 +     *                                  or if the resulting method type would have more than 255 parameter slots
   1.373 +     * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
   1.374 +     */
   1.375 +    /*non-public*/ MethodType replaceParameterTypes(int start, int end, Class<?>... ptypesToInsert) {
   1.376 +        throw new IllegalStateException();
   1.377 +    }
   1.378 +
   1.379 +    /**
   1.380 +     * Finds or creates a method type with some parameter types omitted.
   1.381 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.382 +     * @param start  the index (zero-based) of the first parameter type to remove
   1.383 +     * @param end    the index (greater than {@code start}) of the first parameter type after not to remove
   1.384 +     * @return the same type, except with the selected parameter(s) removed
   1.385 +     * @throws IndexOutOfBoundsException if {@code start} is negative or greater than {@code parameterCount()}
   1.386 +     *                                  or if {@code end} is negative or greater than {@code parameterCount()}
   1.387 +     *                                  or if {@code start} is greater than {@code end}
   1.388 +     */
   1.389 +    public MethodType dropParameterTypes(int start, int end) {
   1.390 +        throw new IllegalStateException();
   1.391 +    }
   1.392 +
   1.393 +    /**
   1.394 +     * Finds or creates a method type with a different return type.
   1.395 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.396 +     * @param nrtype a return parameter type to replace the old one with
   1.397 +     * @return the same type, except with the return type change
   1.398 +     * @throws NullPointerException if {@code nrtype} is null
   1.399 +     */
   1.400 +    public MethodType changeReturnType(Class<?> nrtype) {
   1.401 +        throw new IllegalStateException();
   1.402 +    }
   1.403 +
   1.404 +    /**
   1.405 +     * Reports if this type contains a primitive argument or return value.
   1.406 +     * The return type {@code void} counts as a primitive.
   1.407 +     * @return true if any of the types are primitives
   1.408 +     */
   1.409 +    public boolean hasPrimitives() {
   1.410 +        throw new IllegalStateException();
   1.411 +    }
   1.412 +
   1.413 +    /**
   1.414 +     * Reports if this type contains a wrapper argument or return value.
   1.415 +     * Wrappers are types which box primitive values, such as {@link Integer}.
   1.416 +     * The reference type {@code java.lang.Void} counts as a wrapper,
   1.417 +     * if it occurs as a return type.
   1.418 +     * @return true if any of the types are wrappers
   1.419 +     */
   1.420 +    public boolean hasWrappers() {
   1.421 +        return unwrap() != this;
   1.422 +    }
   1.423 +
   1.424 +    /**
   1.425 +     * Erases all reference types to {@code Object}.
   1.426 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.427 +     * All primitive types (including {@code void}) will remain unchanged.
   1.428 +     * @return a version of the original type with all reference types replaced
   1.429 +     */
   1.430 +    public MethodType erase() {
   1.431 +        throw new IllegalStateException();
   1.432 +    }
   1.433 +
   1.434 +    /**
   1.435 +     * Erases all reference types to {@code Object}, and all subword types to {@code int}.
   1.436 +     * This is the reduced type polymorphism used by private methods
   1.437 +     * such as {@link MethodHandle#invokeBasic invokeBasic}.
   1.438 +     * @return a version of the original type with all reference and subword types replaced
   1.439 +     */
   1.440 +    /*non-public*/ MethodType basicType() {
   1.441 +        throw new IllegalStateException();
   1.442 +    }
   1.443 +
   1.444 +    /**
   1.445 +     * @return a version of the original type with MethodHandle prepended as the first argument
   1.446 +     */
   1.447 +    /*non-public*/ MethodType invokerType() {
   1.448 +        throw new IllegalStateException();
   1.449 +    }
   1.450 +
   1.451 +    /**
   1.452 +     * Converts all types, both reference and primitive, to {@code Object}.
   1.453 +     * Convenience method for {@link #genericMethodType(int) genericMethodType}.
   1.454 +     * The expression {@code type.wrap().erase()} produces the same value
   1.455 +     * as {@code type.generic()}.
   1.456 +     * @return a version of the original type with all types replaced
   1.457 +     */
   1.458 +    public MethodType generic() {
   1.459 +        return genericMethodType(parameterCount());
   1.460 +    }
   1.461 +
   1.462 +    /**
   1.463 +     * Converts all primitive types to their corresponding wrapper types.
   1.464 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.465 +     * All reference types (including wrapper types) will remain unchanged.
   1.466 +     * A {@code void} return type is changed to the type {@code java.lang.Void}.
   1.467 +     * The expression {@code type.wrap().erase()} produces the same value
   1.468 +     * as {@code type.generic()}.
   1.469 +     * @return a version of the original type with all primitive types replaced
   1.470 +     */
   1.471 +    public MethodType wrap() {
   1.472 +        return hasPrimitives() ? wrapWithPrims(this) : this;
   1.473 +    }
   1.474 +
   1.475 +    /**
   1.476 +     * Converts all wrapper types to their corresponding primitive types.
   1.477 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.478 +     * All primitive types (including {@code void}) will remain unchanged.
   1.479 +     * A return type of {@code java.lang.Void} is changed to {@code void}.
   1.480 +     * @return a version of the original type with all wrapper types replaced
   1.481 +     */
   1.482 +    public MethodType unwrap() {
   1.483 +        MethodType noprims = !hasPrimitives() ? this : wrapWithPrims(this);
   1.484 +        return unwrapWithNoPrims(noprims);
   1.485 +    }
   1.486 +
   1.487 +    private static MethodType wrapWithPrims(MethodType pt) {
   1.488 +        throw new IllegalStateException();
   1.489 +    }
   1.490 +
   1.491 +    private static MethodType unwrapWithNoPrims(MethodType wt) {
   1.492 +        throw new IllegalStateException();
   1.493 +    }
   1.494 +
   1.495 +    /**
   1.496 +     * Returns the parameter type at the specified index, within this method type.
   1.497 +     * @param num the index (zero-based) of the desired parameter type
   1.498 +     * @return the selected parameter type
   1.499 +     * @throws IndexOutOfBoundsException if {@code num} is not a valid index into {@code parameterArray()}
   1.500 +     */
   1.501 +    public Class<?> parameterType(int num) {
   1.502 +        return ptypes[num];
   1.503 +    }
   1.504 +    /**
   1.505 +     * Returns the number of parameter types in this method type.
   1.506 +     * @return the number of parameter types
   1.507 +     */
   1.508 +    public int parameterCount() {
   1.509 +        return ptypes.length;
   1.510 +    }
   1.511 +    /**
   1.512 +     * Returns the return type of this method type.
   1.513 +     * @return the return type
   1.514 +     */
   1.515 +    public Class<?> returnType() {
   1.516 +        return rtype;
   1.517 +    }
   1.518 +
   1.519 +    /**
   1.520 +     * Presents the parameter types as a list (a convenience method).
   1.521 +     * The list will be immutable.
   1.522 +     * @return the parameter types (as an immutable list)
   1.523 +     */
   1.524 +    public List<Class<?>> parameterList() {
   1.525 +        return Collections.unmodifiableList(Arrays.asList(ptypes));
   1.526 +    }
   1.527 +
   1.528 +    /*non-public*/ Class<?> lastParameterType() {
   1.529 +        int len = ptypes.length;
   1.530 +        return len == 0 ? void.class : ptypes[len-1];
   1.531 +    }
   1.532 +
   1.533 +    /**
   1.534 +     * Presents the parameter types as an array (a convenience method).
   1.535 +     * Changes to the array will not result in changes to the type.
   1.536 +     * @return the parameter types (as a fresh copy if necessary)
   1.537 +     */
   1.538 +    public Class<?>[] parameterArray() {
   1.539 +        return ptypes.clone();
   1.540 +    }
   1.541 +
   1.542 +    /**
   1.543 +     * Compares the specified object with this type for equality.
   1.544 +     * That is, it returns <tt>true</tt> if and only if the specified object
   1.545 +     * is also a method type with exactly the same parameters and return type.
   1.546 +     * @param x object to compare
   1.547 +     * @see Object#equals(Object)
   1.548 +     */
   1.549 +    @Override
   1.550 +    public boolean equals(Object x) {
   1.551 +        return this == x || x instanceof MethodType && equals((MethodType)x);
   1.552 +    }
   1.553 +
   1.554 +    private boolean equals(MethodType that) {
   1.555 +        return this.rtype == that.rtype
   1.556 +            && Arrays.equals(this.ptypes, that.ptypes);
   1.557 +    }
   1.558 +
   1.559 +    /**
   1.560 +     * Returns the hash code value for this method type.
   1.561 +     * It is defined to be the same as the hashcode of a List
   1.562 +     * whose elements are the return type followed by the
   1.563 +     * parameter types.
   1.564 +     * @return the hash code value for this method type
   1.565 +     * @see Object#hashCode()
   1.566 +     * @see #equals(Object)
   1.567 +     * @see List#hashCode()
   1.568 +     */
   1.569 +    @Override
   1.570 +    public int hashCode() {
   1.571 +      int hashCode = 31 + rtype.hashCode();
   1.572 +      for (Class<?> ptype : ptypes)
   1.573 +          hashCode = 31*hashCode + ptype.hashCode();
   1.574 +      return hashCode;
   1.575 +    }
   1.576 +
   1.577 +    /**
   1.578 +     * Returns a string representation of the method type,
   1.579 +     * of the form {@code "(PT0,PT1...)RT"}.
   1.580 +     * The string representation of a method type is a
   1.581 +     * parenthesis enclosed, comma separated list of type names,
   1.582 +     * followed immediately by the return type.
   1.583 +     * <p>
   1.584 +     * Each type is represented by its
   1.585 +     * {@link java.lang.Class#getSimpleName simple name}.
   1.586 +     */
   1.587 +    @Override
   1.588 +    public String toString() {
   1.589 +        StringBuilder sb = new StringBuilder();
   1.590 +        sb.append("(");
   1.591 +        for (int i = 0; i < ptypes.length; i++) {
   1.592 +            if (i > 0)  sb.append(",");
   1.593 +            sb.append(ptypes[i].getSimpleName());
   1.594 +        }
   1.595 +        sb.append(")");
   1.596 +        sb.append(rtype.getSimpleName());
   1.597 +        return sb.toString();
   1.598 +    }
   1.599 +
   1.600 +
   1.601 +    /**
   1.602 +     * Finds or creates an instance of a method type, given the spelling of its bytecode descriptor.
   1.603 +     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
   1.604 +     * Any class or interface name embedded in the descriptor string
   1.605 +     * will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)}
   1.606 +     * on the given loader (or if it is null, on the system class loader).
   1.607 +     * <p>
   1.608 +     * Note that it is possible to encounter method types which cannot be
   1.609 +     * constructed by this method, because their component types are
   1.610 +     * not all reachable from a common class loader.
   1.611 +     * <p>
   1.612 +     * This method is included for the benefit of applications that must
   1.613 +     * generate bytecodes that process method handles and {@code invokedynamic}.
   1.614 +     * @param descriptor a bytecode-level type descriptor string "(T...)T"
   1.615 +     * @param loader the class loader in which to look up the types
   1.616 +     * @return a method type matching the bytecode-level type descriptor
   1.617 +     * @throws NullPointerException if the string is null
   1.618 +     * @throws IllegalArgumentException if the string is not well-formed
   1.619 +     * @throws TypeNotPresentException if a named type cannot be found
   1.620 +     */
   1.621 +    public static MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader)
   1.622 +        throws IllegalArgumentException
   1.623 +    {
   1.624 +        throw new IllegalStateException();
   1.625 +    }
   1.626 +
   1.627 +    /**
   1.628 +     * Produces a bytecode descriptor representation of the method type.
   1.629 +     * <p>
   1.630 +     * Note that this is not a strict inverse of {@link #fromMethodDescriptorString fromMethodDescriptorString}.
   1.631 +     * Two distinct classes which share a common name but have different class loaders
   1.632 +     * will appear identical when viewed within descriptor strings.
   1.633 +     * <p>
   1.634 +     * This method is included for the benefit of applications that must
   1.635 +     * generate bytecodes that process method handles and {@code invokedynamic}.
   1.636 +     * {@link #fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) fromMethodDescriptorString},
   1.637 +     * because the latter requires a suitable class loader argument.
   1.638 +     * @return the bytecode type descriptor representation
   1.639 +     */
   1.640 +    public String toMethodDescriptorString() {
   1.641 +        throw new IllegalStateException();
   1.642 +    }
   1.643 +
   1.644 +    /// Serialization.
   1.645 +
   1.646 +    /**
   1.647 +     * There are no serializable fields for {@code MethodType}.
   1.648 +     */
   1.649 +    private static final java.io.ObjectStreamField[] serialPersistentFields = { };
   1.650 +
   1.651 +//    /**
   1.652 +//     * Save the {@code MethodType} instance to a stream.
   1.653 +//     *
   1.654 +//     * @serialData
   1.655 +//     * For portability, the serialized format does not refer to named fields.
   1.656 +//     * Instead, the return type and parameter type arrays are written directly
   1.657 +//     * from the {@code writeObject} method, using two calls to {@code s.writeObject}
   1.658 +//     * as follows:
   1.659 +//     * <blockquote><pre>{@code
   1.660 +//s.writeObject(this.returnType());
   1.661 +//s.writeObject(this.parameterArray());
   1.662 +//     * }</pre></blockquote>
   1.663 +//     * <p>
   1.664 +//     * The deserialized field values are checked as if they were
   1.665 +//     * provided to the factory method {@link #methodType(Class,Class[]) methodType}.
   1.666 +//     * For example, null values, or {@code void} parameter types,
   1.667 +//     * will lead to exceptions during deserialization.
   1.668 +//     * @param s the stream to write the object to
   1.669 +//     * @throws java.io.IOException if there is a problem writing the object
   1.670 +//     */
   1.671 +//    private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
   1.672 +//        s.defaultWriteObject();  // requires serialPersistentFields to be an empty array
   1.673 +//        s.writeObject(returnType());
   1.674 +//        s.writeObject(parameterArray());
   1.675 +//    }
   1.676 +//
   1.677 +//    /**
   1.678 +//     * Reconstitute the {@code MethodType} instance from a stream (that is,
   1.679 +//     * deserialize it).
   1.680 +//     * This instance is a scratch object with bogus final fields.
   1.681 +//     * It provides the parameters to the factory method called by
   1.682 +//     * {@link #readResolve readResolve}.
   1.683 +//     * After that call it is discarded.
   1.684 +//     * @param s the stream to read the object from
   1.685 +//     * @throws java.io.IOException if there is a problem reading the object
   1.686 +//     * @throws ClassNotFoundException if one of the component classes cannot be resolved
   1.687 +//     * @see #MethodType()
   1.688 +//     * @see #readResolve
   1.689 +//     * @see #writeObject
   1.690 +//     */
   1.691 +//    private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
   1.692 +//        s.defaultReadObject();  // requires serialPersistentFields to be an empty array
   1.693 +//
   1.694 +//        Class<?>   returnType     = (Class<?>)   s.readObject();
   1.695 +//        Class<?>[] parameterArray = (Class<?>[]) s.readObject();
   1.696 +//
   1.697 +//        // Probably this object will never escape, but let's check
   1.698 +//        // the field values now, just to be sure.
   1.699 +//        checkRtype(returnType);
   1.700 +//        checkPtypes(parameterArray);
   1.701 +//
   1.702 +//        parameterArray = parameterArray.clone();  // make sure it is unshared
   1.703 +//        MethodType_init(returnType, parameterArray);
   1.704 +//    }
   1.705 +
   1.706 +    /**
   1.707 +     * For serialization only.
   1.708 +     * Sets the final fields to null, pending {@code Unsafe.putObject}.
   1.709 +     */
   1.710 +    private MethodType() {
   1.711 +        this.rtype = null;
   1.712 +        this.ptypes = null;
   1.713 +    }
   1.714 +//    private void MethodType_init(Class<?> rtype, Class<?>[] ptypes) {
   1.715 +//        // In order to communicate these values to readResolve, we must
   1.716 +//        // store them into the implementation-specific final fields.
   1.717 +//        checkRtype(rtype);
   1.718 +//        checkPtypes(ptypes);
   1.719 +//        UNSAFE.putObject(this, rtypeOffset, rtype);
   1.720 +//        UNSAFE.putObject(this, ptypesOffset, ptypes);
   1.721 +//    }
   1.722 +
   1.723 +    // Support for resetting final fields while deserializing
   1.724 +//    private static final long rtypeOffset, ptypesOffset;
   1.725 +//    static {
   1.726 +//        try {
   1.727 +//            rtypeOffset = UNSAFE.objectFieldOffset
   1.728 +//                (MethodType.class.getDeclaredField("rtype"));
   1.729 +//            ptypesOffset = UNSAFE.objectFieldOffset
   1.730 +//                (MethodType.class.getDeclaredField("ptypes"));
   1.731 +//        } catch (Exception ex) {
   1.732 +//            throw new Error(ex);
   1.733 +//        }
   1.734 +//    }
   1.735 +
   1.736 +    /**
   1.737 +     * Resolves and initializes a {@code MethodType} object
   1.738 +     * after serialization.
   1.739 +     * @return the fully initialized {@code MethodType} object
   1.740 +     */
   1.741 +    private Object readResolve() {
   1.742 +        // Do not use a trusted path for deserialization:
   1.743 +        //return makeImpl(rtype, ptypes, true);
   1.744 +        // Verify all operands, and make sure ptypes is unshared:
   1.745 +        return methodType(rtype, ptypes);
   1.746 +    }
   1.747 +
   1.748 +    /**
   1.749 +     * Simple implementation of weak concurrent intern set.
   1.750 +     *
   1.751 +     * @param <T> interned type
   1.752 +     */
   1.753 +    private static class ConcurrentWeakInternSet<T> {
   1.754 +
   1.755 +        private final ConcurrentMap<WeakEntry<T>, WeakEntry<T>> map;
   1.756 +        private final ReferenceQueue<T> stale;
   1.757 +
   1.758 +        public ConcurrentWeakInternSet() {
   1.759 +            this.map = new ConcurrentHashMap<>();
   1.760 +            this.stale = new ReferenceQueue<>();
   1.761 +        }
   1.762 +
   1.763 +        /**
   1.764 +         * Get the existing interned element.
   1.765 +         * This method returns null if no element is interned.
   1.766 +         *
   1.767 +         * @param elem element to look up
   1.768 +         * @return the interned element
   1.769 +         */
   1.770 +        public T get(T elem) {
   1.771 +            if (elem == null) throw new NullPointerException();
   1.772 +            expungeStaleElements();
   1.773 +
   1.774 +            WeakEntry<T> value = map.get(new WeakEntry<>(elem));
   1.775 +            if (value != null) {
   1.776 +                T res = value.get();
   1.777 +                if (res != null) {
   1.778 +                    return res;
   1.779 +                }
   1.780 +            }
   1.781 +            return null;
   1.782 +        }
   1.783 +
   1.784 +        /**
   1.785 +         * Interns the element.
   1.786 +         * Always returns non-null element, matching the one in the intern set.
   1.787 +         * Under the race against another add(), it can return <i>different</i>
   1.788 +         * element, if another thread beats us to interning it.
   1.789 +         *
   1.790 +         * @param elem element to add
   1.791 +         * @return element that was actually added
   1.792 +         */
   1.793 +        public T add(T elem) {
   1.794 +            if (elem == null) throw new NullPointerException();
   1.795 +
   1.796 +            // Playing double race here, and so spinloop is required.
   1.797 +            // First race is with two concurrent updaters.
   1.798 +            // Second race is with GC purging weak ref under our feet.
   1.799 +            // Hopefully, we almost always end up with a single pass.
   1.800 +            T interned;
   1.801 +            WeakEntry<T> e = new WeakEntry<>(elem, stale);
   1.802 +            do {
   1.803 +                expungeStaleElements();
   1.804 +                WeakEntry<T> exist = map.putIfAbsent(e, e);
   1.805 +                interned = (exist == null) ? elem : exist.get();
   1.806 +            } while (interned == null);
   1.807 +            return interned;
   1.808 +        }
   1.809 +
   1.810 +        private void expungeStaleElements() {
   1.811 +            Reference<? extends T> reference;
   1.812 +            while ((reference = stale.poll()) != null) {
   1.813 +                map.remove(reference);
   1.814 +            }
   1.815 +        }
   1.816 +
   1.817 +        private static class WeakEntry<T> extends WeakReference<T> {
   1.818 +
   1.819 +            public final int hashcode;
   1.820 +
   1.821 +            public WeakEntry(T key, ReferenceQueue<T> queue) {
   1.822 +                super(key, queue);
   1.823 +                hashcode = key.hashCode();
   1.824 +            }
   1.825 +
   1.826 +            public WeakEntry(T key) {
   1.827 +                super(key);
   1.828 +                hashcode = key.hashCode();
   1.829 +            }
   1.830 +
   1.831 +            @Override
   1.832 +            public boolean equals(Object obj) {
   1.833 +                if (obj instanceof WeakEntry) {
   1.834 +                    Object that = ((WeakEntry) obj).get();
   1.835 +                    Object mine = get();
   1.836 +                    return (that == null || mine == null) ? (this == obj) : mine.equals(that);
   1.837 +                }
   1.838 +                return false;
   1.839 +            }
   1.840 +
   1.841 +            @Override
   1.842 +            public int hashCode() {
   1.843 +                return hashcode;
   1.844 +            }
   1.845 +
   1.846 +        }
   1.847 +    }
   1.848 +
   1.849 +}