236 // Examples: Object->int, Number->int, Comparable->int; Byte->int, Character->int
237 // must include additional conversions
238 // src must be examined at runtime, to detect Byte, Character, etc.
239 MethodHandle unboxMethod = (level == 1
240 ? ValueConversions.unbox(dst)
241 : ValueConversions.unboxCast(dst));
242 fn = unboxMethod;
243 } else {
244 // Example: Byte->int
245 // Do this by reformulating the problem to Byte->byte.
246 Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
247 MethodHandle unbox = ValueConversions.unbox(srcPrim);
248 // Compose the two conversions. FIXME: should make two Names for this job
249 fn = unbox.asType(MethodType.methodType(dst, src));
250 }
251 } else {
252 // Simple reference conversion.
253 // Note: Do not check for a class hierarchy relation
254 // between src and dst. In all cases a 'null' argument
255 // will pass the cast conversion.
256 fn = ValueConversions.cast(dst);
257 }
258 }
259 Name conv = new Name(fn, names[INARG_BASE + i]);
260 assert(names[nameCursor] == null);
261 names[nameCursor++] = conv;
262 assert(outArgs[OUTARG_BASE + i] == null);
263 outArgs[OUTARG_BASE + i] = conv;
264 }
265
266 // Build argument array for the call.
267 assert(nameCursor == OUT_CALL);
268 names[OUT_CALL] = new Name(target, outArgs);
269
270 if (RETURN_CONV < 0) {
271 assert(OUT_CALL == names.length-1);
272 } else {
273 Class<?> needReturn = srcType.returnType();
274 Class<?> haveReturn = dstType.returnType();
275 MethodHandle fn;
276 Object[] arg = { names[OUT_CALL] };
277 if (haveReturn == void.class) {
278 // synthesize a zero value for the given void
279 Object zero = Wrapper.forBasicType(needReturn).zero();
280 fn = MethodHandles.constant(needReturn, zero);
281 arg = new Object[0]; // don't pass names[OUT_CALL] to conversion
282 } else {
283 MethodHandle identity = MethodHandles.identity(needReturn);
284 MethodType needConversion = identity.type().changeParameterType(0, haveReturn);
285 fn = makePairwiseConvert(identity, needConversion, level);
286 }
287 assert(names[RETURN_CONV] == null);
288 names[RETURN_CONV] = new Name(fn, arg);
289 assert(RETURN_CONV == names.length-1);
290 }
291
292 LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names);
293 return SimpleMethodHandle.make(srcType, form);
294 }
295
296 static MethodHandle makeReferenceIdentity(Class<?> refType) {
297 MethodType lambdaType = MethodType.genericMethodType(1).invokerType();
298 Name[] names = arguments(1, lambdaType);
299 names[names.length - 1] = new Name(ValueConversions.identity(), names[1]);
300 LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names);
301 return SimpleMethodHandle.make(MethodType.methodType(refType, refType), form);
302 }
303
304 static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
305 MethodType type = target.type();
306 int last = type.parameterCount() - 1;
307 if (type.parameterType(last) != arrayType)
308 target = target.asType(type.changeParameterType(last, arrayType));
309 target = target.asFixedArity(); // make sure this attribute is turned off
310 return new AsVarargsCollector(target, target.type(), arrayType);
311 }
312
313 static class AsVarargsCollector extends MethodHandle {
314 private final MethodHandle target;
315 private final Class<?> arrayType;
471 } else {
472 int len = java.lang.reflect.Array.getLength(av);
473 if (len == n) return;
474 }
475 // fall through to error:
476 throw newIllegalArgumentException("array is not of length "+n);
477 }
478
479 /**
480 * Pre-initialized NamedFunctions for bootstrapping purposes.
481 * Factored in an inner class to delay initialization until first usage.
482 */
483 private static class Lazy {
484 private static final Class<?> MHI = MethodHandleImpl.class;
485
486 static final NamedFunction NF_checkSpreadArgument;
487 static final NamedFunction NF_guardWithCatch;
488 static final NamedFunction NF_selectAlternative;
489 static final NamedFunction NF_throwException;
490
491 static {
492 try {
493 NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
494 NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
495 MethodHandle.class, Object[].class));
496 NF_selectAlternative = new NamedFunction(MHI.getDeclaredMethod("selectAlternative", boolean.class, MethodHandle.class,
497 MethodHandle.class));
498 NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class));
499
500 NF_checkSpreadArgument.resolve();
501 NF_guardWithCatch.resolve();
502 NF_selectAlternative.resolve();
503 NF_throwException.resolve();
504 } catch (ReflectiveOperationException ex) {
505 throw newInternalError(ex);
506 }
507 }
508 }
509
510 /** Factory method: Collect or filter selected argument(s). */
511 static MethodHandle makeCollectArguments(MethodHandle target,
512 MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) {
513 MethodType targetType = target.type(); // (a..., c, [b...])=>r
514 MethodType collectorType = collector.type(); // (b...)=>c
515 int collectArgCount = collectorType.parameterCount();
516 Class<?> collectValType = collectorType.returnType();
517 int collectValCount = (collectValType == void.class ? 0 : 1);
518 MethodType srcType = targetType // (a..., [b...])=>r
519 .dropParameterTypes(collectArgPos, collectArgPos+collectValCount);
520 if (!retainOriginalArgs) { // (a..., b...)=>r
521 srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList());
522 }
523 // in arglist: [0: ...keep1 | cpos: collect... | cpos+cacount: keep2... ]
|
236 // Examples: Object->int, Number->int, Comparable->int; Byte->int, Character->int
237 // must include additional conversions
238 // src must be examined at runtime, to detect Byte, Character, etc.
239 MethodHandle unboxMethod = (level == 1
240 ? ValueConversions.unbox(dst)
241 : ValueConversions.unboxCast(dst));
242 fn = unboxMethod;
243 } else {
244 // Example: Byte->int
245 // Do this by reformulating the problem to Byte->byte.
246 Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
247 MethodHandle unbox = ValueConversions.unbox(srcPrim);
248 // Compose the two conversions. FIXME: should make two Names for this job
249 fn = unbox.asType(MethodType.methodType(dst, src));
250 }
251 } else {
252 // Simple reference conversion.
253 // Note: Do not check for a class hierarchy relation
254 // between src and dst. In all cases a 'null' argument
255 // will pass the cast conversion.
256 fn = ValueConversions.cast(dst, Lazy.MH_castReference);
257 }
258 }
259 Name conv = new Name(fn, names[INARG_BASE + i]);
260 assert(names[nameCursor] == null);
261 names[nameCursor++] = conv;
262 assert(outArgs[OUTARG_BASE + i] == null);
263 outArgs[OUTARG_BASE + i] = conv;
264 }
265
266 // Build argument array for the call.
267 assert(nameCursor == OUT_CALL);
268 names[OUT_CALL] = new Name(target, outArgs);
269
270 if (RETURN_CONV < 0) {
271 assert(OUT_CALL == names.length-1);
272 } else {
273 Class<?> needReturn = srcType.returnType();
274 Class<?> haveReturn = dstType.returnType();
275 MethodHandle fn;
276 Object[] arg = { names[OUT_CALL] };
277 if (haveReturn == void.class) {
278 // synthesize a zero value for the given void
279 Object zero = Wrapper.forBasicType(needReturn).zero();
280 fn = MethodHandles.constant(needReturn, zero);
281 arg = new Object[0]; // don't pass names[OUT_CALL] to conversion
282 } else {
283 MethodHandle identity = MethodHandles.identity(needReturn);
284 MethodType needConversion = identity.type().changeParameterType(0, haveReturn);
285 fn = makePairwiseConvert(identity, needConversion, level);
286 }
287 assert(names[RETURN_CONV] == null);
288 names[RETURN_CONV] = new Name(fn, arg);
289 assert(RETURN_CONV == names.length-1);
290 }
291
292 LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names);
293 return SimpleMethodHandle.make(srcType, form);
294 }
295
296 /**
297 * Identity function, with reference cast.
298 * @param t an arbitrary reference type
299 * @param x an arbitrary reference value
300 * @return the same value x
301 */
302 @ForceInline
303 @SuppressWarnings("unchecked")
304 static <T,U> T castReference(Class<? extends T> t, U x) {
305 // inlined Class.cast because we can't ForceInline it
306 if (x != null && !t.isInstance(x))
307 throw newClassCastException(t, x);
308 return (T) x;
309 }
310
311 private static ClassCastException newClassCastException(Class<?> t, Object obj) {
312 return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());
313 }
314
315 static MethodHandle makeReferenceIdentity(Class<?> refType) {
316 MethodType lambdaType = MethodType.genericMethodType(1).invokerType();
317 Name[] names = arguments(1, lambdaType);
318 names[names.length - 1] = new Name(ValueConversions.identity(), names[1]);
319 LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names);
320 return SimpleMethodHandle.make(MethodType.methodType(refType, refType), form);
321 }
322
323 static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
324 MethodType type = target.type();
325 int last = type.parameterCount() - 1;
326 if (type.parameterType(last) != arrayType)
327 target = target.asType(type.changeParameterType(last, arrayType));
328 target = target.asFixedArity(); // make sure this attribute is turned off
329 return new AsVarargsCollector(target, target.type(), arrayType);
330 }
331
332 static class AsVarargsCollector extends MethodHandle {
333 private final MethodHandle target;
334 private final Class<?> arrayType;
490 } else {
491 int len = java.lang.reflect.Array.getLength(av);
492 if (len == n) return;
493 }
494 // fall through to error:
495 throw newIllegalArgumentException("array is not of length "+n);
496 }
497
498 /**
499 * Pre-initialized NamedFunctions for bootstrapping purposes.
500 * Factored in an inner class to delay initialization until first usage.
501 */
502 private static class Lazy {
503 private static final Class<?> MHI = MethodHandleImpl.class;
504
505 static final NamedFunction NF_checkSpreadArgument;
506 static final NamedFunction NF_guardWithCatch;
507 static final NamedFunction NF_selectAlternative;
508 static final NamedFunction NF_throwException;
509
510 static final MethodHandle MH_castReference;
511
512 static {
513 try {
514 NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
515 NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
516 MethodHandle.class, Object[].class));
517 NF_selectAlternative = new NamedFunction(MHI.getDeclaredMethod("selectAlternative", boolean.class, MethodHandle.class,
518 MethodHandle.class));
519 NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class));
520
521 NF_checkSpreadArgument.resolve();
522 NF_guardWithCatch.resolve();
523 NF_selectAlternative.resolve();
524 NF_throwException.resolve();
525
526 MethodType mt = MethodType.methodType(Object.class, Class.class, Object.class);
527 MH_castReference = IMPL_LOOKUP.findStatic(MHI, "castReference", mt);
528 } catch (ReflectiveOperationException ex) {
529 throw newInternalError(ex);
530 }
531 }
532 }
533
534 /** Factory method: Collect or filter selected argument(s). */
535 static MethodHandle makeCollectArguments(MethodHandle target,
536 MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) {
537 MethodType targetType = target.type(); // (a..., c, [b...])=>r
538 MethodType collectorType = collector.type(); // (b...)=>c
539 int collectArgCount = collectorType.parameterCount();
540 Class<?> collectValType = collectorType.returnType();
541 int collectValCount = (collectValType == void.class ? 0 : 1);
542 MethodType srcType = targetType // (a..., [b...])=>r
543 .dropParameterTypes(collectArgPos, collectArgPos+collectValCount);
544 if (!retainOriginalArgs) { // (a..., b...)=>r
545 srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList());
546 }
547 // in arglist: [0: ...keep1 | cpos: collect... | cpos+cacount: keep2... ]
|