src/jdk/internal/dynalink/support/TypeConverterFactory.java

changeset 1090
99571b7922c0
parent 963
e2497b11a021
child 1205
4112748288bb
equal deleted inserted replaced
1089:981feb6ad9cc 1090:99571b7922c0
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;

mercurial