< prev index next >

src/java.base/share/classes/java/lang/invoke/MethodType.java

Print this page

  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.invoke;
  27 
  28 import java.lang.constant.ClassDesc;
  29 import java.lang.constant.Constable;
  30 import java.lang.constant.MethodTypeDesc;
  31 import java.lang.ref.Reference;
  32 import java.lang.ref.ReferenceQueue;
  33 import java.lang.ref.WeakReference;
  34 import java.util.Arrays;

  35 import java.util.Collections;
  36 import java.util.function.Supplier;


  37 import java.util.List;
  38 import java.util.Map;
  39 import java.util.NoSuchElementException;
  40 import java.util.Objects;
  41 import java.util.Optional;
  42 import java.util.StringJoiner;
  43 import java.util.concurrent.ConcurrentHashMap;
  44 import java.util.concurrent.ConcurrentMap;
  45 import java.util.stream.Stream;
  46 

  47 import jdk.internal.util.ReferencedKeySet;
  48 import jdk.internal.util.ReferenceKey;
  49 import jdk.internal.vm.annotation.Stable;
  50 import sun.invoke.util.BytecodeDescriptor;
  51 import sun.invoke.util.VerifyType;
  52 import sun.invoke.util.Wrapper;
  53 import sun.security.util.SecurityConstants;
  54 
  55 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
  56 import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
  57 
  58 /**
  59  * A method type represents the arguments and return type accepted and
  60  * returned by a method handle, or the arguments and return type passed
  61  * and expected  by a method handle caller.  Method types must be properly
  62  * matched between a method handle and all its callers,
  63  * and the JVM's operations enforce this matching at, specifically
  64  * during calls to {@link MethodHandle#invokeExact MethodHandle.invokeExact}
  65  * and {@link MethodHandle#invoke MethodHandle.invoke}, and during execution
  66  * of {@code invokedynamic} instructions.

 137  */
 138 public final
 139 class MethodType
 140         implements Constable,
 141                    TypeDescriptor.OfMethod<Class<?>, MethodType>,
 142                    java.io.Serializable {
 143     @java.io.Serial
 144     private static final long serialVersionUID = 292L;  // {rtype, {ptype...}}
 145 
 146     // The rtype and ptypes fields define the structural identity of the method type:
 147     private final @Stable Class<?>   rtype;
 148     private final @Stable Class<?>[] ptypes;
 149 
 150     // The remaining fields are caches of various sorts:
 151     private @Stable MethodTypeForm form; // erased form, plus cached data about primitives
 152     private @Stable Object wrapAlt;  // alternative wrapped/unwrapped version and
 153                                      // private communication for readObject and readResolve
 154     private @Stable Invokers invokers;   // cache of handy higher-order adapters
 155     private @Stable String methodDescriptor;  // cache for toMethodDescriptorString
 156 

 157     /**
 158      * Constructor that performs no copying or validation.
 159      * Should only be called from the factory method makeImpl
 160      */
 161     private MethodType(Class<?> rtype, Class<?>[] ptypes) {







 162         this.rtype = rtype;
 163         this.ptypes = ptypes;
 164     }
 165 
 166     /*trusted*/ MethodTypeForm form() { return form; }
 167     /*trusted*/ Class<?> rtype() { return rtype; }
 168     /*trusted*/ Class<?>[] ptypes() { return ptypes; }
 169 
 170     void setForm(MethodTypeForm f) { form = f; }
 171 
 172     /** This number, mandated by the JVM spec as 255,
 173      *  is the maximum number of <em>slots</em>
 174      *  that any Java method can receive in its argument list.
 175      *  It limits both JVM signatures and method type objects.
 176      *  The longest possible invocation will look like
 177      *  {@code staticMethod(arg1, arg2, ..., arg255)} or
 178      *  {@code x.virtualMethod(arg1, arg2, ..., arg254)}.
 179      */
 180     /*non-public*/
 181     static final int MAX_JVM_ARITY = 255;  // this is mandated by the JVM spec.

 223     }
 224     static void checkSlotCount(int count) {
 225         if ((count & MAX_JVM_ARITY) != count)
 226             throw newIllegalArgumentException("bad parameter count "+count);
 227     }
 228     private static IndexOutOfBoundsException newIndexOutOfBoundsException(Object num) {
 229         if (num instanceof Integer)  num = "bad index: "+num;
 230         return new IndexOutOfBoundsException(num.toString());
 231     }
 232 
 233     static final ReferencedKeySet<MethodType> internTable =
 234         ReferencedKeySet.create(false, true, new Supplier<>() {
 235             @Override
 236             public Map<ReferenceKey<MethodType>, ReferenceKey<MethodType>> get() {
 237                 return new ConcurrentHashMap<>(512);
 238             }
 239         });
 240 
 241     static final Class<?>[] NO_PTYPES = {};
 242 




















 243     /**
 244      * Finds or creates an instance of the given method type.
 245      * @param rtype  the return type
 246      * @param ptypes the parameter types
 247      * @return a method type with the given components
 248      * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
 249      * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
 250      */
 251     public static MethodType methodType(Class<?> rtype, Class<?>[] ptypes) {
 252         return methodType(rtype, ptypes, false);
 253     }
 254 
 255     /**
 256      * Finds or creates a method type with the given components.
 257      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
 258      * @param rtype  the return type
 259      * @param ptypes the parameter types
 260      * @return a method type with the given components
 261      * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
 262      * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}

 381         }
 382         return makeImpl(rtype, ptypes, trusted);
 383     }
 384 
 385     /**
 386      * Sole factory method to find or create an interned method type. Will perform
 387      * input validation on behalf of factory methods
 388      *
 389      * @param rtype desired return type
 390      * @param ptypes desired parameter types
 391      * @param trusted whether the ptypes can be used without cloning
 392      * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
 393      * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
 394      * @return the unique method type of the desired structure
 395      */
 396     private static MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
 397         if (ptypes.length == 0) {
 398             ptypes = NO_PTYPES; trusted = true;
 399         }
 400         MethodType primordialMT = new MethodType(rtype, ptypes);







 401         MethodType mt = internTable.get(primordialMT);
 402         if (mt != null)
 403             return mt;
 404 
 405         // promote the object to the Real Thing, and reprobe
 406         Objects.requireNonNull(rtype);
 407         if (trusted) {
 408             MethodType.checkPtypes(ptypes);
 409             mt = primordialMT;
 410         } else {
 411             // Make defensive copy then validate
 412             ptypes = Arrays.copyOf(ptypes, ptypes.length);
 413             MethodType.checkPtypes(ptypes);
 414             mt = new MethodType(rtype, ptypes);
 415         }
 416         mt.form = MethodTypeForm.findForm(mt);
 417         return internTable.intern(mt);
 418     }
 419     private static final @Stable MethodType[] objectOnlyTypes = new MethodType[20];
 420 
 421     /**
 422      * Finds or creates a method type whose components are {@code Object} with an optional trailing {@code Object[]} array.
 423      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
 424      * All parameters and the return type will be {@code Object},
 425      * except the final array parameter if any, which will be {@code Object[]}.
 426      * @param objectArgCount number of parameters (excluding the final array parameter if any)
 427      * @param finalArray whether there will be a trailing array parameter, of type {@code Object[]}
 428      * @return a generally applicable method type, for all calls of the given fixed argument count and a collected array of further arguments
 429      * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray} is true)
 430      * @see #genericMethodType(int)
 431      */
 432     public static MethodType genericMethodType(int objectArgCount, boolean finalArray) {
 433         MethodType mt;
 434         checkSlotCount(objectArgCount);
 435         int ivarargs = (!finalArray ? 0 : 1);
 436         int ootIndex = objectArgCount*2 + ivarargs;
 437         if (ootIndex < objectOnlyTypes.length) {
 438             mt = objectOnlyTypes[ootIndex];
 439             if (mt != null)  return mt;

1374 
1375         static final long ptypesOffset
1376                 = UNSAFE.objectFieldOffset(MethodType.class, "ptypes");
1377     }
1378 
1379     /**
1380      * Resolves and initializes a {@code MethodType} object
1381      * after serialization.
1382      * @return the fully initialized {@code MethodType} object
1383      */
1384     @java.io.Serial
1385     private Object readResolve() {
1386         // Do not use a trusted path for deserialization:
1387         //    return makeImpl(rtype, ptypes, true);
1388         // Verify all operands, and make sure ptypes is unshared:
1389         // Return a new validated MethodType for the rtype and ptypes passed from readObject.
1390         MethodType mt = ((MethodType[])wrapAlt)[0];
1391         wrapAlt = null;
1392         return mt;
1393     }


















































1394 }

  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.invoke;
  27 
  28 import java.lang.constant.ClassDesc;
  29 import java.lang.constant.Constable;
  30 import java.lang.constant.MethodTypeDesc;
  31 import java.lang.ref.Reference;
  32 import java.lang.ref.ReferenceQueue;
  33 import java.lang.ref.WeakReference;
  34 import java.util.Arrays;
  35 import java.util.ArrayList;
  36 import java.util.Collections;
  37 import java.util.function.Supplier;
  38 import java.util.HashMap;
  39 import java.util.Iterator;
  40 import java.util.List;
  41 import java.util.Map;
  42 import java.util.NoSuchElementException;
  43 import java.util.Objects;
  44 import java.util.Optional;
  45 import java.util.StringJoiner;
  46 import java.util.concurrent.ConcurrentHashMap;
  47 import java.util.concurrent.ConcurrentMap;
  48 import java.util.stream.Stream;
  49 
  50 import jdk.internal.misc.CDS;
  51 import jdk.internal.util.ReferencedKeySet;
  52 import jdk.internal.util.ReferenceKey;
  53 import jdk.internal.vm.annotation.Stable;
  54 import sun.invoke.util.BytecodeDescriptor;
  55 import sun.invoke.util.VerifyType;
  56 import sun.invoke.util.Wrapper;
  57 import sun.security.util.SecurityConstants;
  58 
  59 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
  60 import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
  61 
  62 /**
  63  * A method type represents the arguments and return type accepted and
  64  * returned by a method handle, or the arguments and return type passed
  65  * and expected  by a method handle caller.  Method types must be properly
  66  * matched between a method handle and all its callers,
  67  * and the JVM's operations enforce this matching at, specifically
  68  * during calls to {@link MethodHandle#invokeExact MethodHandle.invokeExact}
  69  * and {@link MethodHandle#invoke MethodHandle.invoke}, and during execution
  70  * of {@code invokedynamic} instructions.

 141  */
 142 public final
 143 class MethodType
 144         implements Constable,
 145                    TypeDescriptor.OfMethod<Class<?>, MethodType>,
 146                    java.io.Serializable {
 147     @java.io.Serial
 148     private static final long serialVersionUID = 292L;  // {rtype, {ptype...}}
 149 
 150     // The rtype and ptypes fields define the structural identity of the method type:
 151     private final @Stable Class<?>   rtype;
 152     private final @Stable Class<?>[] ptypes;
 153 
 154     // The remaining fields are caches of various sorts:
 155     private @Stable MethodTypeForm form; // erased form, plus cached data about primitives
 156     private @Stable Object wrapAlt;  // alternative wrapped/unwrapped version and
 157                                      // private communication for readObject and readResolve
 158     private @Stable Invokers invokers;   // cache of handy higher-order adapters
 159     private @Stable String methodDescriptor;  // cache for toMethodDescriptorString
 160 
 161     private final boolean checkArchivable = CDS.isDumpingArchive();
 162     /**
 163      * Constructor that performs no copying or validation.
 164      * Should only be called from the factory method makeImpl
 165      */
 166     private MethodType(Class<?> rtype, Class<?>[] ptypes) {
 167         if (checkArchivable) {
 168             MethodHandleNatives.checkArchivable(rtype);
 169             for (var p : ptypes) {
 170                 MethodHandleNatives.checkArchivable(p);
 171             }
 172         }
 173 
 174         this.rtype = rtype;
 175         this.ptypes = ptypes;
 176     }
 177 
 178     /*trusted*/ MethodTypeForm form() { return form; }
 179     /*trusted*/ Class<?> rtype() { return rtype; }
 180     /*trusted*/ Class<?>[] ptypes() { return ptypes; }
 181 
 182     void setForm(MethodTypeForm f) { form = f; }
 183 
 184     /** This number, mandated by the JVM spec as 255,
 185      *  is the maximum number of <em>slots</em>
 186      *  that any Java method can receive in its argument list.
 187      *  It limits both JVM signatures and method type objects.
 188      *  The longest possible invocation will look like
 189      *  {@code staticMethod(arg1, arg2, ..., arg255)} or
 190      *  {@code x.virtualMethod(arg1, arg2, ..., arg254)}.
 191      */
 192     /*non-public*/
 193     static final int MAX_JVM_ARITY = 255;  // this is mandated by the JVM spec.

 235     }
 236     static void checkSlotCount(int count) {
 237         if ((count & MAX_JVM_ARITY) != count)
 238             throw newIllegalArgumentException("bad parameter count "+count);
 239     }
 240     private static IndexOutOfBoundsException newIndexOutOfBoundsException(Object num) {
 241         if (num instanceof Integer)  num = "bad index: "+num;
 242         return new IndexOutOfBoundsException(num.toString());
 243     }
 244 
 245     static final ReferencedKeySet<MethodType> internTable =
 246         ReferencedKeySet.create(false, true, new Supplier<>() {
 247             @Override
 248             public Map<ReferenceKey<MethodType>, ReferenceKey<MethodType>> get() {
 249                 return new ConcurrentHashMap<>(512);
 250             }
 251         });
 252 
 253     static final Class<?>[] NO_PTYPES = {};
 254 
 255     private static Object[] archivedObjects;
 256 
 257     private static @Stable HashMap<MethodType,MethodType> archivedMethodTypes;
 258 
 259     private static @Stable MethodType[] objectOnlyTypes;
 260 
 261     @SuppressWarnings("unchecked")
 262     static void doit() {
 263         CDS.initializeFromArchive(MethodType.class);
 264         if (archivedObjects != null) {
 265             archivedMethodTypes = (HashMap<MethodType,MethodType>)archivedObjects[0];
 266             objectOnlyTypes = (MethodType[])archivedObjects[1];
 267         } else {
 268             objectOnlyTypes = new MethodType[20];
 269         }
 270     }
 271     static {
 272         doit();
 273     }
 274 
 275     /**
 276      * Finds or creates an instance of the given method type.
 277      * @param rtype  the return type
 278      * @param ptypes the parameter types
 279      * @return a method type with the given components
 280      * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
 281      * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
 282      */
 283     public static MethodType methodType(Class<?> rtype, Class<?>[] ptypes) {
 284         return methodType(rtype, ptypes, false);
 285     }
 286 
 287     /**
 288      * Finds or creates a method type with the given components.
 289      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
 290      * @param rtype  the return type
 291      * @param ptypes the parameter types
 292      * @return a method type with the given components
 293      * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
 294      * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}

 413         }
 414         return makeImpl(rtype, ptypes, trusted);
 415     }
 416 
 417     /**
 418      * Sole factory method to find or create an interned method type. Will perform
 419      * input validation on behalf of factory methods
 420      *
 421      * @param rtype desired return type
 422      * @param ptypes desired parameter types
 423      * @param trusted whether the ptypes can be used without cloning
 424      * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
 425      * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
 426      * @return the unique method type of the desired structure
 427      */
 428     private static MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
 429         if (ptypes.length == 0) {
 430             ptypes = NO_PTYPES; trusted = true;
 431         }
 432         MethodType primordialMT = new MethodType(rtype, ptypes);
 433         if (archivedMethodTypes != null) {
 434             MethodType mt = archivedMethodTypes.get(primordialMT);
 435             if (mt != null) {
 436                 return mt;
 437             }
 438         }
 439 
 440         MethodType mt = internTable.get(primordialMT);
 441         if (mt != null)
 442             return mt;
 443 
 444         // promote the object to the Real Thing, and reprobe
 445         Objects.requireNonNull(rtype);
 446         if (trusted) {
 447             MethodType.checkPtypes(ptypes);
 448             mt = primordialMT;
 449         } else {
 450             // Make defensive copy then validate
 451             ptypes = Arrays.copyOf(ptypes, ptypes.length);
 452             MethodType.checkPtypes(ptypes);
 453             mt = new MethodType(rtype, ptypes);
 454         }
 455         mt.form = MethodTypeForm.findForm(mt);
 456         return internTable.intern(mt);
 457     }

 458 
 459     /**
 460      * Finds or creates a method type whose components are {@code Object} with an optional trailing {@code Object[]} array.
 461      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
 462      * All parameters and the return type will be {@code Object},
 463      * except the final array parameter if any, which will be {@code Object[]}.
 464      * @param objectArgCount number of parameters (excluding the final array parameter if any)
 465      * @param finalArray whether there will be a trailing array parameter, of type {@code Object[]}
 466      * @return a generally applicable method type, for all calls of the given fixed argument count and a collected array of further arguments
 467      * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray} is true)
 468      * @see #genericMethodType(int)
 469      */
 470     public static MethodType genericMethodType(int objectArgCount, boolean finalArray) {
 471         MethodType mt;
 472         checkSlotCount(objectArgCount);
 473         int ivarargs = (!finalArray ? 0 : 1);
 474         int ootIndex = objectArgCount*2 + ivarargs;
 475         if (ootIndex < objectOnlyTypes.length) {
 476             mt = objectOnlyTypes[ootIndex];
 477             if (mt != null)  return mt;

1412 
1413         static final long ptypesOffset
1414                 = UNSAFE.objectFieldOffset(MethodType.class, "ptypes");
1415     }
1416 
1417     /**
1418      * Resolves and initializes a {@code MethodType} object
1419      * after serialization.
1420      * @return the fully initialized {@code MethodType} object
1421      */
1422     @java.io.Serial
1423     private Object readResolve() {
1424         // Do not use a trusted path for deserialization:
1425         //    return makeImpl(rtype, ptypes, true);
1426         // Verify all operands, and make sure ptypes is unshared:
1427         // Return a new validated MethodType for the rtype and ptypes passed from readObject.
1428         MethodType mt = ((MethodType[])wrapAlt)[0];
1429         wrapAlt = null;
1430         return mt;
1431     }
1432 
1433     static HashMap<MethodType,MethodType> archive(Archiver archiver) {
1434         HashMap<MethodType,MethodType> archivedSet = new HashMap<>();
1435 
1436         for (Iterator<MethodType> i = internTable.iterator(); i.hasNext(); ) {
1437             MethodType t = i.next();
1438             MethodType a = archiver.clean(t);
1439             if (a != null) {
1440                 archivedSet.put(a, a);
1441             }
1442         }
1443 
1444         return archivedSet;
1445     }
1446 
1447     static class Archiver {
1448         ArrayList<MethodType> archived = new ArrayList<>();
1449 
1450         MethodType clean(MethodType t) {
1451             if (t == null || t.form == null) { // HACK!
1452                 return null;
1453             }
1454             if (archived.contains(t)) {
1455                 return t;
1456             }
1457 
1458             archived.add(t);
1459             return t;
1460         }
1461     }
1462 
1463     // This is called from C code.
1464     static void dumpSharedArchive() {
1465         Archiver archiver = new Archiver();
1466 
1467         MethodType[] objectOnlyTypesCopy = new MethodType[objectOnlyTypes.length];
1468         for (int i = 0; i < objectOnlyTypes.length; i++) {
1469             MethodType t = archiver.clean(objectOnlyTypes[i]);
1470             if (t != null) {
1471                 objectOnlyTypesCopy[i] = t;
1472             }
1473         }
1474 
1475         archivedObjects = new Object[2];
1476         archivedObjects[0] = archive(archiver);
1477         archivedObjects[1] = objectOnlyTypesCopy;
1478 
1479         DirectMethodHandle.dumpSharedArchive();
1480         LambdaForm.NamedFunction.dumpSharedArchive();
1481     }
1482 }
< prev index next >