< prev index next >

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

Print this page

250 public final class LambdaMetafactory {
251 
252     private LambdaMetafactory() {}
253 
254     /** Flag for {@link #altMetafactory} indicating the lambda object
255      * must be serializable */
256     public static final int FLAG_SERIALIZABLE = 1 << 0;
257 
258     /**
259      * Flag for {@link #altMetafactory} indicating the lambda object implements
260      * other interfaces besides {@code Serializable}
261      */
262     public static final int FLAG_MARKERS = 1 << 1;
263 
264     /**
265      * Flag for alternate metafactories indicating the lambda object requires
266      * additional methods that invoke the {@code implementation}
267      */
268     public static final int FLAG_BRIDGES = 1 << 2;
269 




270     private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
271     private static final MethodType[] EMPTY_MT_ARRAY = new MethodType[0];
272 
273     // LambdaMetafactory bootstrap methods are startup sensitive, and may be
274     // special cased in java.lang.invoke.BootstrapMethodInvoker to ensure
275     // methods are invoked with exact type information to avoid generating
276     // code for runtime checks. Take care any changes or additions here are
277     // reflected there as appropriate.
278 
279     /**
280      * Facilitates the creation of simple "function objects" that implement one
281      * or more interfaces by delegation to a provided {@link MethodHandle},
282      * after appropriate type adaptation and partial evaluation of arguments.
283      * Typically used as a <em>bootstrap method</em> for {@code invokedynamic}
284      * call sites, to support the <em>lambda expression</em> and <em>method
285      * reference expression</em> features of the Java Programming Language.
286      *
287      * <p>This is the standard, streamlined metafactory; additional flexibility
288      * is provided by {@link #altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)}.
289      * A general description of the behavior of this method is provided

332      *         handle referencing a method or constructor, or if the linkage
333      *         invariants are violated, as defined {@link LambdaMetafactory above}.
334      * @throws NullPointerException If any argument is {@code null}.
335      */
336     public static CallSite metafactory(MethodHandles.Lookup caller,
337                                        String interfaceMethodName,
338                                        MethodType factoryType,
339                                        MethodType interfaceMethodType,
340                                        MethodHandle implementation,
341                                        MethodType dynamicMethodType)
342             throws LambdaConversionException {
343         AbstractValidatingLambdaMetafactory mf;
344         mf = new InnerClassLambdaMetafactory(Objects.requireNonNull(caller),
345                                              Objects.requireNonNull(factoryType),
346                                              Objects.requireNonNull(interfaceMethodName),
347                                              Objects.requireNonNull(interfaceMethodType),
348                                              Objects.requireNonNull(implementation),
349                                              Objects.requireNonNull(dynamicMethodType),
350                                              false,
351                                              EMPTY_CLASS_ARRAY,
352                                              EMPTY_MT_ARRAY);

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

378      *  CallSite altMetafactory(MethodHandles.Lookup caller,
379      *                          String interfaceMethodName,
380      *                          MethodType factoryType,
381      *                          Object... args)
382      * }</pre>
383      *
384      * <p>but it behaves as if the argument list is as follows:
385      *
386      * <pre>{@code
387      *  CallSite altMetafactory(MethodHandles.Lookup caller,
388      *                          String interfaceMethodName,
389      *                          MethodType factoryType,
390      *                          MethodType interfaceMethodType,
391      *                          MethodHandle implementation,
392      *                          MethodType dynamicMethodType,
393      *                          int flags,
394      *                          int altInterfaceCount,        // IF flags has MARKERS set
395      *                          Class... altInterfaces,       // IF flags has MARKERS set
396      *                          int altMethodCount,           // IF flags has BRIDGES set
397      *                          MethodType... altMethods      // IF flags has BRIDGES set

398      *                          )
399      * }</pre>
400      *
401      * <p>Arguments that appear in the argument list for
402      * {@link #metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)}
403      * have the same specification as in that method.  The additional arguments
404      * are interpreted as follows:
405      * <ul>
406      *     <li>{@code flags} indicates additional options; this is a bitwise
407      *     OR of desired flags.  Defined flags are {@link #FLAG_BRIDGES},
408      *     {@link #FLAG_MARKERS}, and {@link #FLAG_SERIALIZABLE}.</li>
409      *     <li>{@code altInterfaceCount} is the number of additional interfaces
410      *     the function object should implement, and is present if and only if the
411      *     {@code FLAG_MARKERS} flag is set.</li>
412      *     <li>{@code altInterfaces} is a variable-length list of additional
413      *     interfaces to implement, whose length equals {@code altInterfaceCount},
414      *     and is present if and only if the {@code FLAG_MARKERS} flag is set.</li>
415      *     <li>{@code altMethodCount} is the number of additional method signatures
416      *     the function object should implement, and is present if and only if
417      *     the {@code FLAG_BRIDGES} flag is set.</li>
418      *     <li>{@code altMethods} is a variable-length list of additional
419      *     methods signatures to implement, whose length equals {@code altMethodCount},
420      *     and is present if and only if the {@code FLAG_BRIDGES} flag is set.</li>




421      * </ul>
422      *
423      * <p>Each class named by {@code altInterfaces} is subject to the same
424      * restrictions as {@code Rd}, the return type of {@code factoryType},
425      * as described {@link LambdaMetafactory above}.  Each {@code MethodType}
426      * named by {@code altMethods} is subject to the same restrictions as
427      * {@code interfaceMethodType}, as described {@link LambdaMetafactory above}.
428      *
429      * <p>When FLAG_SERIALIZABLE is set in {@code flags}, the function objects
430      * will implement {@code Serializable}, and will have a {@code writeReplace}
431      * method that returns an appropriate {@link SerializedLambda}.  The
432      * {@code caller} class must have an appropriate {@code $deserializeLambda$}
433      * method, as described in {@link SerializedLambda}.
434      *



435      * <p>When the target of the {@code CallSite} returned from this method is
436      * invoked, the resulting function objects are instances of a class with
437      * the following properties:
438      * <ul>
439      *     <li>The class implements the interface named by the return type
440      *     of {@code factoryType} and any interfaces named by {@code altInterfaces}</li>
441      *     <li>The class declares methods with the name given by {@code interfaceMethodName},
442      *     and the signature given by {@code interfaceMethodType} and additional signatures
443      *     given by {@code altMethods}</li>
444      *     <li>The class may override methods from {@code Object}, and may
445      *     implement methods related to serialization.</li>
446      * </ul>
447      *
448      * @param caller Represents a lookup context with the accessibility
449      *               privileges of the caller.  Specifically, the lookup context
450      *               must have {@linkplain MethodHandles.Lookup#hasFullPrivilegeAccess()
451      *               full privilege access}.
452      *               When used with {@code invokedynamic}, this is stacked
453      *               automatically by the VM.
454      * @param interfaceMethodName The name of the method to implement.  When used with

480      *         of {@code args} do not follow the above rules, or if
481      *         {@code altInterfaceCount} or {@code altMethodCount} are negative
482      *         integers.
483      */
484     public static CallSite altMetafactory(MethodHandles.Lookup caller,
485                                           String interfaceMethodName,
486                                           MethodType factoryType,
487                                           Object... args)
488             throws LambdaConversionException {
489         Objects.requireNonNull(caller);
490         Objects.requireNonNull(interfaceMethodName);
491         Objects.requireNonNull(factoryType);
492         Objects.requireNonNull(args);
493         int argIndex = 0;
494         MethodType interfaceMethodType = extractArg(args, argIndex++, MethodType.class);
495         MethodHandle implementation = extractArg(args, argIndex++, MethodHandle.class);
496         MethodType dynamicMethodType = extractArg(args, argIndex++, MethodType.class);
497         int flags = extractArg(args, argIndex++, Integer.class);
498         Class<?>[] altInterfaces = EMPTY_CLASS_ARRAY;
499         MethodType[] altMethods = EMPTY_MT_ARRAY;


500         if ((flags & FLAG_MARKERS) != 0) {
501             int altInterfaceCount = extractArg(args, argIndex++, Integer.class);
502             if (altInterfaceCount < 0) {
503                 throw new IllegalArgumentException("negative argument count");
504             }
505             if (altInterfaceCount > 0) {
506                 altInterfaces = extractArgs(args, argIndex, Class.class, altInterfaceCount);
507                 argIndex += altInterfaceCount;
508             }
509         }
510         if ((flags & FLAG_BRIDGES) != 0) {
511             int altMethodCount = extractArg(args, argIndex++, Integer.class);
512             if (altMethodCount < 0) {
513                 throw new IllegalArgumentException("negative argument count");
514             }
515             if (altMethodCount > 0) {
516                 altMethods = extractArgs(args, argIndex, MethodType.class, altMethodCount);
517                 argIndex += altMethodCount;
518             }
519         }





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

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

250 public final class LambdaMetafactory {
251 
252     private LambdaMetafactory() {}
253 
254     /** Flag for {@link #altMetafactory} indicating the lambda object
255      * must be serializable */
256     public static final int FLAG_SERIALIZABLE = 1 << 0;
257 
258     /**
259      * Flag for {@link #altMetafactory} indicating the lambda object implements
260      * other interfaces besides {@code Serializable}
261      */
262     public static final int FLAG_MARKERS = 1 << 1;
263 
264     /**
265      * Flag for alternate metafactories indicating the lambda object requires
266      * additional methods that invoke the {@code implementation}
267      */
268     public static final int FLAG_BRIDGES = 1 << 2;
269 
270     /** Flag for {@link #altMetafactory} indicating the lambda object
271      * must be a {@code Quotable} object, inspectable using code reflection. */
272     public static final int FLAG_QUOTABLE = 1 << 3;
273 
274     private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
275     private static final MethodType[] EMPTY_MT_ARRAY = new MethodType[0];
276 
277     // LambdaMetafactory bootstrap methods are startup sensitive, and may be
278     // special cased in java.lang.invoke.BootstrapMethodInvoker to ensure
279     // methods are invoked with exact type information to avoid generating
280     // code for runtime checks. Take care any changes or additions here are
281     // reflected there as appropriate.
282 
283     /**
284      * Facilitates the creation of simple "function objects" that implement one
285      * or more interfaces by delegation to a provided {@link MethodHandle},
286      * after appropriate type adaptation and partial evaluation of arguments.
287      * Typically used as a <em>bootstrap method</em> for {@code invokedynamic}
288      * call sites, to support the <em>lambda expression</em> and <em>method
289      * reference expression</em> features of the Java Programming Language.
290      *
291      * <p>This is the standard, streamlined metafactory; additional flexibility
292      * is provided by {@link #altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)}.
293      * A general description of the behavior of this method is provided

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         AbstractValidatingLambdaMetafactory mf;
348         mf = new InnerClassLambdaMetafactory(Objects.requireNonNull(caller),
349                                              Objects.requireNonNull(factoryType),
350                                              Objects.requireNonNull(interfaceMethodName),
351                                              Objects.requireNonNull(interfaceMethodType),
352                                              Objects.requireNonNull(implementation),
353                                              Objects.requireNonNull(dynamicMethodType),
354                                              false,
355                                              EMPTY_CLASS_ARRAY,
356                                              EMPTY_MT_ARRAY,
357                                  null);
358         mf.validateMetafactoryArgs();
359         return mf.buildCallSite();
360     }
361 
362     /**
363      * Facilitates the creation of simple "function objects" that implement one
364      * or more interfaces by delegation to a provided {@link MethodHandle},
365      * after appropriate type adaptation and partial evaluation of arguments.
366      * Typically used as a <em>bootstrap method</em> for {@code invokedynamic}
367      * call sites, to support the <em>lambda expression</em> and <em>method
368      * reference expression</em> features of the Java Programming Language.
369      *
370      * <p>This is the general, more flexible metafactory; a streamlined version
371      * is provided by {@link #metafactory(java.lang.invoke.MethodHandles.Lookup,
372      * String, MethodType, MethodType, MethodHandle, MethodType)}.
373      * A general description of the behavior of this method is provided
374      * {@link LambdaMetafactory above}.
375      *
376      * <p>The argument list for this method includes three fixed parameters,
377      * corresponding to the parameters automatically stacked by the VM for the

383      *  CallSite altMetafactory(MethodHandles.Lookup caller,
384      *                          String interfaceMethodName,
385      *                          MethodType factoryType,
386      *                          Object... args)
387      * }</pre>
388      *
389      * <p>but it behaves as if the argument list is as follows:
390      *
391      * <pre>{@code
392      *  CallSite altMetafactory(MethodHandles.Lookup caller,
393      *                          String interfaceMethodName,
394      *                          MethodType factoryType,
395      *                          MethodType interfaceMethodType,
396      *                          MethodHandle implementation,
397      *                          MethodType dynamicMethodType,
398      *                          int flags,
399      *                          int altInterfaceCount,        // IF flags has MARKERS set
400      *                          Class... altInterfaces,       // IF flags has MARKERS set
401      *                          int altMethodCount,           // IF flags has BRIDGES set
402      *                          MethodType... altMethods      // IF flags has BRIDGES set
403      *                          MethodHandle quotableField    // IF flags has QUOTABLE set
404      *                          )
405      * }</pre>
406      *
407      * <p>Arguments that appear in the argument list for
408      * {@link #metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)}
409      * have the same specification as in that method.  The additional arguments
410      * are interpreted as follows:
411      * <ul>
412      *     <li>{@code flags} indicates additional options; this is a bitwise
413      *     OR of desired flags.  Defined flags are {@link #FLAG_BRIDGES},
414      *     {@link #FLAG_MARKERS}, and {@link #FLAG_SERIALIZABLE}.</li>
415      *     <li>{@code altInterfaceCount} is the number of additional interfaces
416      *     the function object should implement, and is present if and only if the
417      *     {@code FLAG_MARKERS} flag is set.</li>
418      *     <li>{@code altInterfaces} is a variable-length list of additional
419      *     interfaces to implement, whose length equals {@code altInterfaceCount},
420      *     and is present if and only if the {@code FLAG_MARKERS} flag is set.</li>
421      *     <li>{@code altMethodCount} is the number of additional method signatures
422      *     the function object should implement, and is present if and only if
423      *     the {@code FLAG_BRIDGES} flag is set.</li>
424      *     <li>{@code altMethods} is a variable-length list of additional
425      *     methods signatures to implement, whose length equals {@code altMethodCount},
426      *     and is present if and only if the {@code FLAG_BRIDGES} flag is set.</li>
427      *     <li>{@code quotableField} is a
428      *     {@linkplain MethodHandles.Lookup#findGetter(Class, String, Class) getter} method handle
429      *     that is used to retrieve the string representation of the quotable lambda's associated
430      *     intermediate representation.</li>
431      * </ul>
432      *
433      * <p>Each class named by {@code altInterfaces} is subject to the same
434      * restrictions as {@code Rd}, the return type of {@code factoryType},
435      * as described {@link LambdaMetafactory above}.  Each {@code MethodType}
436      * named by {@code altMethods} is subject to the same restrictions as
437      * {@code interfaceMethodType}, as described {@link LambdaMetafactory above}.
438      *
439      * <p>When FLAG_SERIALIZABLE is set in {@code flags}, the function objects
440      * will implement {@code Serializable}, and will have a {@code writeReplace}
441      * method that returns an appropriate {@link SerializedLambda}.  The
442      * {@code caller} class must have an appropriate {@code $deserializeLambda$}
443      * method, as described in {@link SerializedLambda}.
444      *
445      * <p>When FLAG_QUOTABLE is set in {@code flags}, the function objects
446      * will implement {@code Quotable}.
447      *
448      * <p>When the target of the {@code CallSite} returned from this method is
449      * invoked, the resulting function objects are instances of a class with
450      * the following properties:
451      * <ul>
452      *     <li>The class implements the interface named by the return type
453      *     of {@code factoryType} and any interfaces named by {@code altInterfaces}</li>
454      *     <li>The class declares methods with the name given by {@code interfaceMethodName},
455      *     and the signature given by {@code interfaceMethodType} and additional signatures
456      *     given by {@code altMethods}</li>
457      *     <li>The class may override methods from {@code Object}, and may
458      *     implement methods related to serialization.</li>
459      * </ul>
460      *
461      * @param caller Represents a lookup context with the accessibility
462      *               privileges of the caller.  Specifically, the lookup context
463      *               must have {@linkplain MethodHandles.Lookup#hasFullPrivilegeAccess()
464      *               full privilege access}.
465      *               When used with {@code invokedynamic}, this is stacked
466      *               automatically by the VM.
467      * @param interfaceMethodName The name of the method to implement.  When used with

493      *         of {@code args} do not follow the above rules, or if
494      *         {@code altInterfaceCount} or {@code altMethodCount} are negative
495      *         integers.
496      */
497     public static CallSite altMetafactory(MethodHandles.Lookup caller,
498                                           String interfaceMethodName,
499                                           MethodType factoryType,
500                                           Object... args)
501             throws LambdaConversionException {
502         Objects.requireNonNull(caller);
503         Objects.requireNonNull(interfaceMethodName);
504         Objects.requireNonNull(factoryType);
505         Objects.requireNonNull(args);
506         int argIndex = 0;
507         MethodType interfaceMethodType = extractArg(args, argIndex++, MethodType.class);
508         MethodHandle implementation = extractArg(args, argIndex++, MethodHandle.class);
509         MethodType dynamicMethodType = extractArg(args, argIndex++, MethodType.class);
510         int flags = extractArg(args, argIndex++, Integer.class);
511         Class<?>[] altInterfaces = EMPTY_CLASS_ARRAY;
512         MethodType[] altMethods = EMPTY_MT_ARRAY;
513         // Getter that returns the op of a Quotable instance
514         MethodHandle quotableOpGetter = null;
515         if ((flags & FLAG_MARKERS) != 0) {
516             int altInterfaceCount = extractArg(args, argIndex++, Integer.class);
517             if (altInterfaceCount < 0) {
518                 throw new IllegalArgumentException("negative argument count");
519             }
520             if (altInterfaceCount > 0) {
521                 altInterfaces = extractArgs(args, argIndex, Class.class, altInterfaceCount);
522                 argIndex += altInterfaceCount;
523             }
524         }
525         if ((flags & FLAG_BRIDGES) != 0) {
526             int altMethodCount = extractArg(args, argIndex++, Integer.class);
527             if (altMethodCount < 0) {
528                 throw new IllegalArgumentException("negative argument count");
529             }
530             if (altMethodCount > 0) {
531                 altMethods = extractArgs(args, argIndex, MethodType.class, altMethodCount);
532                 argIndex += altMethodCount;
533             }
534         }
535         if ((flags & FLAG_QUOTABLE) != 0) {
536             quotableOpGetter = extractArg(args, argIndex++, MethodHandle.class);
537             altInterfaces = Arrays.copyOf(altInterfaces, altInterfaces.length + 1);
538             altInterfaces[altInterfaces.length-1] = InnerClassLambdaMetafactory.CodeReflectionSupport.QUOTABLE_CLASS;
539         }
540         if (argIndex < args.length) {
541             throw new IllegalArgumentException("too many arguments");
542         }
543 
544         boolean isSerializable = ((flags & FLAG_SERIALIZABLE) != 0);
545         if (isSerializable) {
546             boolean foundSerializableSupertype = Serializable.class.isAssignableFrom(factoryType.returnType());
547             for (Class<?> c : altInterfaces)
548                 foundSerializableSupertype |= Serializable.class.isAssignableFrom(c);
549             if (!foundSerializableSupertype) {
550                 altInterfaces = Arrays.copyOf(altInterfaces, altInterfaces.length + 1);
551                 altInterfaces[altInterfaces.length-1] = Serializable.class;
552             }
553         }
554 
555         AbstractValidatingLambdaMetafactory mf
556                 = new InnerClassLambdaMetafactory(caller,
557                                                   factoryType,
558                                                   interfaceMethodName,
559                                                   interfaceMethodType,
560                                                   implementation,
561                                                   dynamicMethodType,
562                                                   isSerializable,
563                                                   altInterfaces,
564                                                   altMethods,
565                                                   quotableOpGetter);
566         mf.validateMetafactoryArgs();
567         return mf.buildCallSite();
568     }
569 
570     private static <T> T extractArg(Object[] args, int index, Class<T> type) {
571         if (index >= args.length) {
572             throw new IllegalArgumentException("missing argument");
573         }
574         Object result = Objects.requireNonNull(args[index]);
575         if (!type.isInstance(result)) {
576             throw new IllegalArgumentException("argument has wrong type");
577         }
578         return type.cast(result);
579     }
580 
581     private static <T> T[] extractArgs(Object[] args, int index, Class<T> type, int count) {
582         @SuppressWarnings("unchecked")
583         T[] result = (T[]) Array.newInstance(type, count);
584         for (int i = 0; i < count; i++) {
585             result[i] = extractArg(args, index + i, type);
< prev index next >