nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/TypeConverterFactory.java
changeset 27360 a19c14022fa4
parent 25865 d38d876f1654
child 31549 b627094c5649
equal deleted inserted replaced
27359:59d61197a3f3 27360:a19c14022fa4
    95 import jdk.internal.dynalink.linker.ConversionComparator.Comparison;
    95 import jdk.internal.dynalink.linker.ConversionComparator.Comparison;
    96 import jdk.internal.dynalink.linker.GuardedInvocation;
    96 import jdk.internal.dynalink.linker.GuardedInvocation;
    97 import jdk.internal.dynalink.linker.GuardedTypeConversion;
    97 import jdk.internal.dynalink.linker.GuardedTypeConversion;
    98 import jdk.internal.dynalink.linker.GuardingTypeConverterFactory;
    98 import jdk.internal.dynalink.linker.GuardingTypeConverterFactory;
    99 import jdk.internal.dynalink.linker.LinkerServices;
    99 import jdk.internal.dynalink.linker.LinkerServices;
       
   100 import jdk.internal.dynalink.linker.MethodTypeConversionStrategy;
   100 
   101 
   101 /**
   102 /**
   102  * A factory for type converters. This class is the main implementation behind the
   103  * A factory for type converters. This class is the main implementation behind the
   103  * {@link LinkerServices#asType(MethodHandle, MethodType)}. It manages the known {@link GuardingTypeConverterFactory}
   104  * {@link LinkerServices#asType(MethodHandle, MethodType)}. It manages the known {@link GuardingTypeConverterFactory}
   104  * instances and creates appropriate converters for method handles.
   105  * instances and creates appropriate converters for method handles.
   107  */
   108  */
   108 public class TypeConverterFactory {
   109 public class TypeConverterFactory {
   109 
   110 
   110     private final GuardingTypeConverterFactory[] factories;
   111     private final GuardingTypeConverterFactory[] factories;
   111     private final ConversionComparator[] comparators;
   112     private final ConversionComparator[] comparators;
       
   113     private final MethodTypeConversionStrategy autoConversionStrategy;
   112 
   114 
   113     private final ClassValue<ClassMap<MethodHandle>> converterMap = new ClassValue<ClassMap<MethodHandle>>() {
   115     private final ClassValue<ClassMap<MethodHandle>> converterMap = new ClassValue<ClassMap<MethodHandle>>() {
   114         @Override
   116         @Override
   115         protected ClassMap<MethodHandle> computeValue(final Class<?> sourceType) {
   117         protected ClassMap<MethodHandle> computeValue(final Class<?> sourceType) {
   116             return new ClassMap<MethodHandle>(getClassLoader(sourceType)) {
   118             return new ClassMap<MethodHandle>(getClassLoader(sourceType)) {
   175 
   177 
   176     /**
   178     /**
   177      * Creates a new type converter factory from the available {@link GuardingTypeConverterFactory} instances.
   179      * Creates a new type converter factory from the available {@link GuardingTypeConverterFactory} instances.
   178      *
   180      *
   179      * @param factories the {@link GuardingTypeConverterFactory} instances to compose.
   181      * @param factories the {@link GuardingTypeConverterFactory} instances to compose.
   180      */
   182      * @param autoConversionStrategy conversion strategy for automatic type conversions. After
   181     public TypeConverterFactory(final Iterable<? extends GuardingTypeConverterFactory> factories) {
   183      * {@link #asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)} has applied all custom
       
   184      * conversions to a method handle, it still needs to effect
       
   185      * {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method invocation conversions} that
       
   186      * can usually be automatically applied as per
       
   187      * {@link java.lang.invoke.MethodHandle#asType(java.lang.invoke.MethodType)}.
       
   188      * However, sometimes language runtimes will want to customize even those conversions for their own call
       
   189      * sites. A typical example is allowing unboxing of null return values, which is by default prohibited by
       
   190      * ordinary {@code MethodHandles.asType}. In this case, a language runtime can install its own custom
       
   191      * automatic conversion strategy, that can deal with null values. Note that when the strategy's
       
   192      * {@link MethodTypeConversionStrategy#asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)}
       
   193      * is invoked, the custom language conversions will already have been applied to the method handle, so by
       
   194      * design the difference between the handle's current method type and the desired final type will always
       
   195      * only be ones that can be subjected to method invocation conversions. Can be null, in which case no
       
   196      * custom strategy is employed.
       
   197      */
       
   198     public TypeConverterFactory(final Iterable<? extends GuardingTypeConverterFactory> factories,
       
   199             final MethodTypeConversionStrategy autoConversionStrategy) {
   182         final List<GuardingTypeConverterFactory> l = new LinkedList<>();
   200         final List<GuardingTypeConverterFactory> l = new LinkedList<>();
   183         final List<ConversionComparator> c = new LinkedList<>();
   201         final List<ConversionComparator> c = new LinkedList<>();
   184         for(final GuardingTypeConverterFactory factory: factories) {
   202         for(final GuardingTypeConverterFactory factory: factories) {
   185             l.add(factory);
   203             l.add(factory);
   186             if(factory instanceof ConversionComparator) {
   204             if(factory instanceof ConversionComparator) {
   187                 c.add((ConversionComparator)factory);
   205                 c.add((ConversionComparator)factory);
   188             }
   206             }
   189         }
   207         }
   190         this.factories = l.toArray(new GuardingTypeConverterFactory[l.size()]);
   208         this.factories = l.toArray(new GuardingTypeConverterFactory[l.size()]);
   191         this.comparators = c.toArray(new ConversionComparator[c.size()]);
   209         this.comparators = c.toArray(new ConversionComparator[c.size()]);
   192 
   210         this.autoConversionStrategy = autoConversionStrategy;
   193     }
   211     }
   194 
   212 
   195     /**
   213     /**
   196      * Similar to {@link MethodHandle#asType(MethodType)} except it also hooks in method handles produced by
   214      * Similar to {@link MethodHandle#asType(MethodType)} except it also hooks in method handles produced by
   197      * {@link GuardingTypeConverterFactory} implementations, providing for language-specific type coercing of
   215      * {@link GuardingTypeConverterFactory} implementations, providing for language-specific type coercing of
   198      * parameters. It will apply {@link MethodHandle#asType(MethodType)} for all primitive-to-primitive,
   216      * parameters. For all conversions that are not a JLS method invocation conversion it'll insert
   199      * wrapper-to-primitive, primitive-to-wrapper conversions as well as for all upcasts. For all other conversions,
   217      * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with composite filters
   200      * it'll insert {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with composite filters
   218      * provided by {@link GuardingTypeConverterFactory} implementations. For the remaining JLS method invocation
   201      * provided by {@link GuardingTypeConverterFactory} implementations.
   219      * conversions, it will invoke {@link MethodTypeConversionStrategy#asType(MethodHandle, MethodType)} first
       
   220      * if an automatic conversion strategy was specified in the
       
   221      * {@link #TypeConverterFactory(Iterable, MethodTypeConversionStrategy) constructor}, and finally apply
       
   222      * {@link MethodHandle#asType(MethodType)} for any remaining conversions.
   202      *
   223      *
   203      * @param handle target method handle
   224      * @param handle target method handle
   204      * @param fromType the types of source arguments
   225      * @param fromType the types of source arguments
   205      * @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)} and
   226      * @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)},
       
   227      * {@link MethodTypeConversionStrategy#asType(MethodHandle, MethodType)}, and
   206      * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with
   228      * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with
   207      * {@link GuardingTypeConverterFactory} produced type converters as filters.
   229      * {@link GuardingTypeConverterFactory} produced type converters as filters.
   208      */
   230      */
   209     public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
   231     public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
   210         MethodHandle newHandle = handle;
   232         MethodHandle newHandle = handle;
   244                     newHandle = MethodHandles.filterReturnValue(newHandle, converter);
   266                     newHandle = MethodHandles.filterReturnValue(newHandle, converter);
   245                 }
   267                 }
   246             }
   268             }
   247         }
   269         }
   248 
   270 
   249         // Take care of automatic conversions
   271         // Give change to automatic conversion strategy, if one is present.
   250         return newHandle.asType(fromType);
   272         final MethodHandle autoConvertedHandle =
       
   273                 autoConversionStrategy != null ? autoConversionStrategy.asType(newHandle, fromType) : newHandle;
       
   274 
       
   275         // Do a final asType for any conversions that remain.
       
   276         return autoConvertedHandle.asType(fromType);
   251     }
   277     }
   252 
   278 
   253     private static MethodHandle applyConverters(final MethodHandle handle, final int pos, final List<MethodHandle> converters) {
   279     private static MethodHandle applyConverters(final MethodHandle handle, final int pos, final List<MethodHandle> converters) {
   254         if(converters.isEmpty()) {
   280         if(converters.isEmpty()) {
   255             return handle;
   281             return handle;