< prev index next >

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

Print this page

 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.io.Serializable;
 29 import java.util.Arrays;
 30 import java.lang.reflect.Array;
 31 import java.util.Objects;
 32 

 33 import jdk.internal.vm.annotation.AOTSafeClassInitializer;
 34 
 35 /**
 36  * <p>Methods to facilitate the creation of simple "function objects" that
 37  * implement one or more interfaces by delegation to a provided {@link MethodHandle},
 38  * possibly after type adaptation and partial evaluation of arguments.  These
 39  * methods are typically used as <em>bootstrap methods</em> for {@code invokedynamic}
 40  * call sites, to support the <em>lambda expression</em> and <em>method
 41  * reference expression</em> features of the Java Programming Language.
 42  *
 43  * <p>Indirect access to the behavior specified by the provided {@code MethodHandle}
 44  * proceeds in order through three phases:
 45  * <ul>
 46  *     <li><p><em>Linkage</em> occurs when the methods in this class are invoked.
 47  *     They take as arguments an interface to be implemented (typically a
 48  *     <em>functional interface</em>, one with a single abstract method), a
 49  *     name and signature of a method from that interface to be implemented, a
 50  *     {@linkplain MethodHandleInfo direct method handle} describing the desired
 51  *     implementation behavior for that method, and possibly other additional
 52  *     metadata, and produce a {@link CallSite} whose target can be used to

326      *                          be enforced dynamically at invocation time.
327      *                          In simple use cases this is the same as
328      *                          {@code interfaceMethodType}.
329      * @return a CallSite whose target can be used to perform capture, generating
330      *         instances of the interface named by {@code factoryType}
331      * @throws LambdaConversionException If {@code caller} does not have full privilege
332      *         access, or if {@code interfaceMethodName} is not a valid JVM
333      *         method name, or if the return type of {@code factoryType} is not
334      *         an interface, or if {@code implementation} is not a direct method
335      *         handle referencing a method or constructor, or if the linkage
336      *         invariants are violated, as defined {@link LambdaMetafactory above}.
337      * @throws NullPointerException If any argument is {@code null}.
338      */
339     public static CallSite metafactory(MethodHandles.Lookup caller,
340                                        String interfaceMethodName,
341                                        MethodType factoryType,
342                                        MethodType interfaceMethodType,
343                                        MethodHandle implementation,
344                                        MethodType dynamicMethodType)
345             throws LambdaConversionException {
346         AbstractValidatingLambdaMetafactory mf;
347         mf = new InnerClassLambdaMetafactory(Objects.requireNonNull(caller),
348                                              Objects.requireNonNull(factoryType),
349                                              Objects.requireNonNull(interfaceMethodName),
350                                              Objects.requireNonNull(interfaceMethodType),
351                                              Objects.requireNonNull(implementation),
352                                              Objects.requireNonNull(dynamicMethodType),
353                                              false,
354                                              EMPTY_CLASS_ARRAY,
355                                              EMPTY_MT_ARRAY);












356         mf.validateMetafactoryArgs();
357         return mf.buildCallSite();
358     }
359 
360     /**
361      * Facilitates the creation of simple "function objects" that implement one
362      * or more interfaces by delegation to a provided {@link MethodHandle},
363      * after appropriate type adaptation and partial evaluation of arguments.
364      * Typically used as a <em>bootstrap method</em> for {@code invokedynamic}
365      * call sites, to support the <em>lambda expression</em> and <em>method
366      * reference expression</em> features of the Java Programming Language.
367      *
368      * <p>This is the general, more flexible metafactory; a streamlined version
369      * is provided by {@link #metafactory(java.lang.invoke.MethodHandles.Lookup,
370      * String, MethodType, MethodType, MethodHandle, MethodType)}.
371      * A general description of the behavior of this method is provided
372      * {@link LambdaMetafactory above}.
373      *
374      * <p>The argument list for this method includes three fixed parameters,
375      * corresponding to the parameters automatically stacked by the VM for the

472      *         instances of the interface named by {@code factoryType}
473      * @throws LambdaConversionException If {@code caller} does not have full privilege
474      *         access, or if {@code interfaceMethodName} is not a valid JVM
475      *         method name, or if the return type of {@code factoryType} is not
476      *         an interface, or if any of {@code altInterfaces} is not an
477      *         interface, or if {@code implementation} is not a direct method
478      *         handle referencing a method or constructor, or if the linkage
479      *         invariants are violated, as defined {@link LambdaMetafactory above}.
480      * @throws NullPointerException If any argument, or any component of {@code args},
481      *         is {@code null}.
482      * @throws IllegalArgumentException If the number or types of the components
483      *         of {@code args} do not follow the above rules, or if
484      *         {@code altInterfaceCount} or {@code altMethodCount} are negative
485      *         integers.
486      */
487     public static CallSite altMetafactory(MethodHandles.Lookup caller,
488                                           String interfaceMethodName,
489                                           MethodType factoryType,
490                                           Object... args)
491             throws LambdaConversionException {









492         Objects.requireNonNull(caller);
493         Objects.requireNonNull(interfaceMethodName);
494         Objects.requireNonNull(factoryType);
495         Objects.requireNonNull(args);
496         int argIndex = 0;
497         MethodType interfaceMethodType = extractArg(args, argIndex++, MethodType.class);
498         MethodHandle implementation = extractArg(args, argIndex++, MethodHandle.class);
499         MethodType dynamicMethodType = extractArg(args, argIndex++, MethodType.class);
500         int flags = extractArg(args, argIndex++, Integer.class);
501         Class<?>[] altInterfaces = EMPTY_CLASS_ARRAY;
502         MethodType[] altMethods = EMPTY_MT_ARRAY;
503         if ((flags & FLAG_MARKERS) != 0) {
504             int altInterfaceCount = extractArg(args, argIndex++, Integer.class);
505             if (altInterfaceCount < 0) {
506                 throw new IllegalArgumentException("negative argument count");
507             }
508             if (altInterfaceCount > 0) {
509                 altInterfaces = extractArgs(args, argIndex, Class.class, altInterfaceCount);
510                 argIndex += altInterfaceCount;
511             }
512         }

513         if ((flags & FLAG_BRIDGES) != 0) {
514             int altMethodCount = extractArg(args, argIndex++, Integer.class);
515             if (altMethodCount < 0) {
516                 throw new IllegalArgumentException("negative argument count");
517             }
518             if (altMethodCount > 0) {
519                 altMethods = extractArgs(args, argIndex, MethodType.class, altMethodCount);
520                 argIndex += altMethodCount;
521             }
522         }
523         if (argIndex < args.length) {
524             throw new IllegalArgumentException("too many arguments");
525         }
526 
527         boolean isSerializable = ((flags & FLAG_SERIALIZABLE) != 0);
528         if (isSerializable) {
529             boolean foundSerializableSupertype = Serializable.class.isAssignableFrom(factoryType.returnType());
530             for (Class<?> c : altInterfaces)
531                 foundSerializableSupertype |= Serializable.class.isAssignableFrom(c);
532             if (!foundSerializableSupertype) {
533                 altInterfaces = Arrays.copyOf(altInterfaces, altInterfaces.length + 1);
534                 altInterfaces[altInterfaces.length-1] = Serializable.class;
535             }
536         }
537 
538         AbstractValidatingLambdaMetafactory mf
539                 = new InnerClassLambdaMetafactory(caller,
540                                                   factoryType,
541                                                   interfaceMethodName,
542                                                   interfaceMethodType,
543                                                   implementation,
544                                                   dynamicMethodType,
545                                                   isSerializable,
546                                                   altInterfaces,
547                                                   altMethods);

548         mf.validateMetafactoryArgs();
549         return mf.buildCallSite();
550     }
551 
552     private static <T> T extractArg(Object[] args, int index, Class<T> type) {
553         if (index >= args.length) {
554             throw new IllegalArgumentException("missing argument");
555         }
556         Object result = Objects.requireNonNull(args[index]);
557         if (!type.isInstance(result)) {
558             throw new IllegalArgumentException("argument has wrong type");
559         }
560         return type.cast(result);
561     }
562 
563     private static <T> T[] extractArgs(Object[] args, int index, Class<T> type, int count) {
564         @SuppressWarnings("unchecked")
565         T[] result = (T[]) Array.newInstance(type, count);
566         for (int i = 0; i < count; i++) {
567             result[i] = extractArg(args, index + i, type);

 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.io.Serializable;
 29 import java.util.Arrays;
 30 import java.lang.reflect.Array;
 31 import java.util.Objects;
 32 
 33 import jdk.internal.access.JavaLangInvokeAccess.ReflectableLambdaInfo;
 34 import jdk.internal.vm.annotation.AOTSafeClassInitializer;
 35 
 36 /**
 37  * <p>Methods to facilitate the creation of simple "function objects" that
 38  * implement one or more interfaces by delegation to a provided {@link MethodHandle},
 39  * possibly after type adaptation and partial evaluation of arguments.  These
 40  * methods are typically used as <em>bootstrap methods</em> for {@code invokedynamic}
 41  * call sites, to support the <em>lambda expression</em> and <em>method
 42  * reference expression</em> features of the Java Programming Language.
 43  *
 44  * <p>Indirect access to the behavior specified by the provided {@code MethodHandle}
 45  * proceeds in order through three phases:
 46  * <ul>
 47  *     <li><p><em>Linkage</em> occurs when the methods in this class are invoked.
 48  *     They take as arguments an interface to be implemented (typically a
 49  *     <em>functional interface</em>, one with a single abstract method), a
 50  *     name and signature of a method from that interface to be implemented, a
 51  *     {@linkplain MethodHandleInfo direct method handle} describing the desired
 52  *     implementation behavior for that method, and possibly other additional
 53  *     metadata, and produce a {@link CallSite} whose target can be used to

327      *                          be enforced dynamically at invocation time.
328      *                          In simple use cases this is the same as
329      *                          {@code interfaceMethodType}.
330      * @return a CallSite whose target can be used to perform capture, generating
331      *         instances of the interface named by {@code factoryType}
332      * @throws LambdaConversionException If {@code caller} does not have full privilege
333      *         access, or if {@code interfaceMethodName} is not a valid JVM
334      *         method name, or if the return type of {@code factoryType} is not
335      *         an interface, or if {@code implementation} is not a direct method
336      *         handle referencing a method or constructor, or if the linkage
337      *         invariants are violated, as defined {@link LambdaMetafactory above}.
338      * @throws NullPointerException If any argument is {@code null}.
339      */
340     public static CallSite metafactory(MethodHandles.Lookup caller,
341                                        String interfaceMethodName,
342                                        MethodType factoryType,
343                                        MethodType interfaceMethodType,
344                                        MethodHandle implementation,
345                                        MethodType dynamicMethodType)
346             throws LambdaConversionException {
347         return metafactoryInternal(caller, interfaceMethodName, factoryType, interfaceMethodType,
348                 implementation, dynamicMethodType, null);
349     }
350 
351     static CallSite metafactoryInternal(MethodHandles.Lookup caller,
352                                                String interfaceMethodName,
353                                                MethodType factoryType,
354                                                MethodType interfaceMethodType,
355                                                MethodHandle implementation,
356                                                MethodType dynamicMethodType,
357                                                ReflectableLambdaInfo reflectableLambdaInfo)
358             throws LambdaConversionException {
359         AbstractValidatingLambdaMetafactory mf = new InnerClassLambdaMetafactory(Objects.requireNonNull(caller),
360                 Objects.requireNonNull(factoryType),
361                 Objects.requireNonNull(interfaceMethodName),
362                 Objects.requireNonNull(interfaceMethodType),
363                 Objects.requireNonNull(implementation),
364                 Objects.requireNonNull(dynamicMethodType),
365                 false,
366                 EMPTY_CLASS_ARRAY,
367                 EMPTY_MT_ARRAY,
368                 reflectableLambdaInfo);
369         mf.validateMetafactoryArgs();
370         return mf.buildCallSite();
371     }
372 
373     /**
374      * Facilitates the creation of simple "function objects" that implement one
375      * or more interfaces by delegation to a provided {@link MethodHandle},
376      * after appropriate type adaptation and partial evaluation of arguments.
377      * Typically used as a <em>bootstrap method</em> for {@code invokedynamic}
378      * call sites, to support the <em>lambda expression</em> and <em>method
379      * reference expression</em> features of the Java Programming Language.
380      *
381      * <p>This is the general, more flexible metafactory; a streamlined version
382      * is provided by {@link #metafactory(java.lang.invoke.MethodHandles.Lookup,
383      * String, MethodType, MethodType, MethodHandle, MethodType)}.
384      * A general description of the behavior of this method is provided
385      * {@link LambdaMetafactory above}.
386      *
387      * <p>The argument list for this method includes three fixed parameters,
388      * corresponding to the parameters automatically stacked by the VM for the

485      *         instances of the interface named by {@code factoryType}
486      * @throws LambdaConversionException If {@code caller} does not have full privilege
487      *         access, or if {@code interfaceMethodName} is not a valid JVM
488      *         method name, or if the return type of {@code factoryType} is not
489      *         an interface, or if any of {@code altInterfaces} is not an
490      *         interface, or if {@code implementation} is not a direct method
491      *         handle referencing a method or constructor, or if the linkage
492      *         invariants are violated, as defined {@link LambdaMetafactory above}.
493      * @throws NullPointerException If any argument, or any component of {@code args},
494      *         is {@code null}.
495      * @throws IllegalArgumentException If the number or types of the components
496      *         of {@code args} do not follow the above rules, or if
497      *         {@code altInterfaceCount} or {@code altMethodCount} are negative
498      *         integers.
499      */
500     public static CallSite altMetafactory(MethodHandles.Lookup caller,
501                                           String interfaceMethodName,
502                                           MethodType factoryType,
503                                           Object... args)
504             throws LambdaConversionException {
505         return altMetafactoryInternal(caller, interfaceMethodName, factoryType, null, args);
506     }
507 
508     static CallSite altMetafactoryInternal(MethodHandles.Lookup caller,
509                                           String interfaceMethodName,
510                                           MethodType factoryType,
511                                           ReflectableLambdaInfo reflectableLambdaInfo,
512                                           Object... args)
513             throws LambdaConversionException {
514         Objects.requireNonNull(caller);
515         Objects.requireNonNull(interfaceMethodName);
516         Objects.requireNonNull(factoryType);
517         Objects.requireNonNull(args);
518         int argIndex = 0;
519         MethodType interfaceMethodType = extractArg(args, argIndex++, MethodType.class);
520         MethodHandle implementation = extractArg(args, argIndex++, MethodHandle.class);
521         MethodType dynamicMethodType = extractArg(args, argIndex++, MethodType.class);
522         int flags = extractArg(args, argIndex++, Integer.class);
523         Class<?>[] altInterfaces = EMPTY_CLASS_ARRAY;
524         MethodType[] altMethods = EMPTY_MT_ARRAY;
525         if ((flags & FLAG_MARKERS) != 0) {
526             int altInterfaceCount = extractArg(args, argIndex++, Integer.class);
527             if (altInterfaceCount < 0) {
528                 throw new IllegalArgumentException("negative argument count");
529             }
530             if (altInterfaceCount > 0) {
531                 altInterfaces = extractArgs(args, argIndex, Class.class, altInterfaceCount);
532                 argIndex += altInterfaceCount;
533             }
534         }
535 
536         if ((flags & FLAG_BRIDGES) != 0) {
537             int altMethodCount = extractArg(args, argIndex++, Integer.class);
538             if (altMethodCount < 0) {
539                 throw new IllegalArgumentException("negative argument count");
540             }
541             if (altMethodCount > 0) {
542                 altMethods = extractArgs(args, argIndex, MethodType.class, altMethodCount);
543                 argIndex += altMethodCount;
544             }
545         }
546         if (argIndex < args.length) {
547             throw new IllegalArgumentException("too many arguments");
548         }
549 
550         boolean isSerializable = ((flags & FLAG_SERIALIZABLE) != 0);
551         if (isSerializable) {
552             boolean foundSerializableSupertype = Serializable.class.isAssignableFrom(factoryType.returnType());
553             for (Class<?> c : altInterfaces)
554                 foundSerializableSupertype |= Serializable.class.isAssignableFrom(c);
555             if (!foundSerializableSupertype) {
556                 altInterfaces = Arrays.copyOf(altInterfaces, altInterfaces.length + 1);
557                 altInterfaces[altInterfaces.length-1] = Serializable.class;
558             }
559         }
560 
561         AbstractValidatingLambdaMetafactory mf
562                 = new InnerClassLambdaMetafactory(caller,
563                 factoryType,
564                 interfaceMethodName,
565                 interfaceMethodType,
566                 implementation,
567                 dynamicMethodType,
568                 isSerializable,
569                 altInterfaces,
570                 altMethods,
571                 reflectableLambdaInfo);
572         mf.validateMetafactoryArgs();
573         return mf.buildCallSite();
574     }
575 
576     private static <T> T extractArg(Object[] args, int index, Class<T> type) {
577         if (index >= args.length) {
578             throw new IllegalArgumentException("missing argument");
579         }
580         Object result = Objects.requireNonNull(args[index]);
581         if (!type.isInstance(result)) {
582             throw new IllegalArgumentException("argument has wrong type");
583         }
584         return type.cast(result);
585     }
586 
587     private static <T> T[] extractArgs(Object[] args, int index, Class<T> type, int count) {
588         @SuppressWarnings("unchecked")
589         T[] result = (T[]) Array.newInstance(type, count);
590         for (int i = 0; i < count; i++) {
591             result[i] = extractArg(args, index + i, type);
< prev index next >