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 Tue Jan 17 07:04:06 2017 +0100
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 +}