< prev index next >

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

Print this page

   1 /*
   2  * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.invoke;
  27 
  28 import java.lang.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;

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




















































1400 }

   1 /*
   2  * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.invoke;
  27 
  28 import java.lang.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;

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