< prev index next >

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

Print this page

  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.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

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             }

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);

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

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

487      *         instances of the interface named by {@code factoryType}
488      * @throws LambdaConversionException If {@code caller} does not have full privilege
489      *         access, or if {@code interfaceMethodName} is not a valid JVM
490      *         method name, or if the return type of {@code factoryType} is not
491      *         an interface, or if any of {@code altInterfaces} is not an
492      *         interface, or if {@code implementation} is not a direct method
493      *         handle referencing a method or constructor, or if the linkage
494      *         invariants are violated, as defined {@link LambdaMetafactory above}.
495      * @throws NullPointerException If any argument, or any component of {@code args},
496      *         is {@code null}.
497      * @throws IllegalArgumentException If the number or types of the components
498      *         of {@code args} do not follow the above rules, or if
499      *         {@code altInterfaceCount} or {@code altMethodCount} are negative
500      *         integers.
501      */
502     public static CallSite altMetafactory(MethodHandles.Lookup caller,
503                                           String interfaceMethodName,
504                                           MethodType factoryType,
505                                           Object... args)
506             throws LambdaConversionException {
507         return altMetafactoryInternal(caller, interfaceMethodName, factoryType, null, args);
508     }
509 
510     static CallSite altMetafactoryInternal(MethodHandles.Lookup caller,
511                                            String interfaceMethodName,
512                                            MethodType factoryType,
513                                            Function<ClassBuilder, Object> finisher,
514                                            Object... args)
515             throws LambdaConversionException {
516         Objects.requireNonNull(caller);
517         Objects.requireNonNull(interfaceMethodName);
518         Objects.requireNonNull(factoryType);
519         Objects.requireNonNull(args);
520         int argIndex = 0;
521         MethodType interfaceMethodType = extractArg(args, argIndex++, MethodType.class);
522         MethodHandle implementation = extractArg(args, argIndex++, MethodHandle.class);
523         MethodType dynamicMethodType = extractArg(args, argIndex++, MethodType.class);
524         int flags = extractArg(args, argIndex++, Integer.class);
525         Class<?>[] altInterfaces = EMPTY_CLASS_ARRAY;
526         MethodType[] altMethods = EMPTY_MT_ARRAY;
527         if ((flags & FLAG_MARKERS) != 0) {
528             int altInterfaceCount = extractArg(args, argIndex++, Integer.class);
529             if (altInterfaceCount < 0) {
530                 throw new IllegalArgumentException("negative argument count");
531             }
532             if (altInterfaceCount > 0) {
533                 altInterfaces = extractArgs(args, argIndex, Class.class, altInterfaceCount);
534                 argIndex += altInterfaceCount;
535             }

551         boolean isSerializable = ((flags & FLAG_SERIALIZABLE) != 0);
552         if (isSerializable) {
553             boolean foundSerializableSupertype = Serializable.class.isAssignableFrom(factoryType.returnType());
554             for (Class<?> c : altInterfaces)
555                 foundSerializableSupertype |= Serializable.class.isAssignableFrom(c);
556             if (!foundSerializableSupertype) {
557                 altInterfaces = Arrays.copyOf(altInterfaces, altInterfaces.length + 1);
558                 altInterfaces[altInterfaces.length-1] = Serializable.class;
559             }
560         }
561 
562         AbstractValidatingLambdaMetafactory mf
563                 = new InnerClassLambdaMetafactory(caller,
564                                                   factoryType,
565                                                   interfaceMethodName,
566                                                   interfaceMethodType,
567                                                   implementation,
568                                                   dynamicMethodType,
569                                                   isSerializable,
570                                                   altInterfaces,
571                                                   altMethods,
572                                                   finisher);
573         mf.validateMetafactoryArgs();
574         return mf.buildCallSite();
575     }
576 
577     private static <T> T extractArg(Object[] args, int index, Class<T> type) {
578         if (index >= args.length) {
579             throw new IllegalArgumentException("missing argument");
580         }
581         Object result = Objects.requireNonNull(args[index]);
582         if (!type.isInstance(result)) {
583             throw new IllegalArgumentException("argument has wrong type");
584         }
585         return type.cast(result);
586     }
587 
588     private static <T> T[] extractArgs(Object[] args, int index, Class<T> type, int count) {
589         @SuppressWarnings("unchecked")
590         T[] result = (T[]) Array.newInstance(type, count);
591         for (int i = 0; i < count; i++) {
592             result[i] = extractArg(args, index + i, type);
< prev index next >