257 * @exception SecurityException <em>TBD</em> |
295 * @exception SecurityException <em>TBD</em> |
258 * @exception NoAccessException if the method does not exist or access checking fails |
296 * @exception NoAccessException if the method does not exist or access checking fails |
259 */ |
297 */ |
260 public MethodHandle findSpecial(Class<?> defc, String name, MethodType type, |
298 public MethodHandle findSpecial(Class<?> defc, String name, MethodType type, |
261 Class<?> specialCaller) throws NoAccessException { |
299 Class<?> specialCaller) throws NoAccessException { |
262 checkSpecialCaller(specialCaller, lookupClass); |
300 checkSpecialCaller(specialCaller, this); |
263 MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), false, specialCaller); |
301 Lookup slookup = this.in(specialCaller); |
264 checkStatic(false, method, lookupClass); |
302 MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), false, slookup.lookupClass()); |
|
303 VerifyAccess.checkName(method, this); |
|
304 checkStatic(false, method, this); |
265 if (name.equals("<init>")) { |
305 if (name.equals("<init>")) { |
266 throw newNoAccessException("cannot directly invoke a constructor", method, null); |
306 throw newNoAccessException("cannot directly invoke a constructor", method, null); |
267 } else if (defc.isInterface() || !defc.isAssignableFrom(specialCaller)) { |
307 } else if (defc.isInterface() || !defc.isAssignableFrom(specialCaller)) { |
268 throw newNoAccessException("method must be in a superclass of lookup class", method, lookupClass); |
308 throw newNoAccessException("method must be in a superclass of lookup class", method, slookup.lookupClass()); |
269 } |
309 } |
270 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, specialCaller); |
310 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, slookup.lookupClass()); |
271 } |
311 } |
272 |
312 |
273 /** |
313 /** |
274 * Produce an early-bound method handle for a non-static method. |
314 * Produce an early-bound method handle for a non-static method. |
275 * The receiver must have a supertype {@code defc} in which a method |
315 * The receiver must have a supertype {@code defc} in which a method |
276 * of the given name and type is accessible to the lookup class. |
316 * of the given name and type is accessible to the lookup class. |
277 * The method and all its argument types must be accessible to the lookup class. |
317 * The method and all its argument types must be accessible to the lookup class. |
278 * The type of the method handle will be that of the method. |
318 * The type of the method handle will be that of the method, |
279 * The given receiver will be bound into the method handle. |
319 * without any insertion of an additional receiver parameter. |
|
320 * The given receiver will be bound into the method handle, |
|
321 * so that every call to the method handle will invoke the |
|
322 * requested method on the given receiver. |
280 * <p> |
323 * <p> |
281 * Equivalent to the following expression: |
324 * This is equivalent to the following expression: |
282 * <code> |
325 * <code> |
283 * {@link #insertArgument}({@link #findVirtual}(defc, name, type), receiver) |
326 * {@link #insertArguments}({@link #findVirtual}(defc, name, type), receiver) |
284 * </code> |
327 * </code> |
|
328 * where {@code defc} is either {@code receiver.getClass()} or a super |
|
329 * type of that class, in which the requested method is accessible |
|
330 * to the lookup class. |
285 * @param receiver the object from which the method is accessed |
331 * @param receiver the object from which the method is accessed |
286 * @param name the name of the method |
332 * @param name the name of the method |
287 * @param type the type of the method, with the receiver argument omitted |
333 * @param type the type of the method, with the receiver argument omitted |
288 * @return the desired method handle |
334 * @return the desired method handle |
289 * @exception SecurityException <em>TBD</em> |
335 * @exception SecurityException <em>TBD</em> |
290 * @exception NoAccessException if the method does not exist or access checking fails |
336 * @exception NoAccessException if the method does not exist or access checking fails |
291 */ |
337 */ |
292 public MethodHandle bind(Object receiver, String name, MethodType type) throws NoAccessException { |
338 public MethodHandle bind(Object receiver, String name, MethodType type) throws NoAccessException { |
293 Class<? extends Object> rcvc = receiver.getClass(); // may get NPE |
339 Class<? extends Object> rcvc = receiver.getClass(); // may get NPE |
294 MemberName reference = new MemberName(rcvc, name, type); |
340 MemberName reference = new MemberName(rcvc, name, type); |
295 MemberName method = IMPL_NAMES.resolveOrFail(reference, true, lookupClass); |
341 MemberName method = IMPL_NAMES.resolveOrFail(reference, true, lookupClass()); |
296 checkStatic(false, method, lookupClass); |
342 VerifyAccess.checkName(method, this); |
297 MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClass); |
343 checkStatic(false, method, this); |
|
344 MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClass()); |
298 MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, dmh, receiver); |
345 MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, dmh, receiver); |
299 if (bmh == null) |
346 if (bmh == null) |
300 throw newNoAccessException(method, lookupClass); |
347 throw newNoAccessException(method, this); |
301 return bmh; |
348 return bmh; |
302 } |
349 } |
303 |
350 |
304 /** |
351 /** |
|
352 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
305 * Make a direct method handle to <i>m</i>, if the lookup class has permission. |
353 * Make a direct method handle to <i>m</i>, if the lookup class has permission. |
306 * If <i>m</i> is non-static, the receiver argument is treated as an initial argument. |
354 * If <i>m</i> is non-static, the receiver argument is treated as an initial argument. |
307 * If <i>m</i> is virtual, overriding is respected on every call. |
355 * If <i>m</i> is virtual, overriding is respected on every call. |
308 * Unlike the Core Reflection API, exceptions are <em>not</em> wrapped. |
356 * Unlike the Core Reflection API, exceptions are <em>not</em> wrapped. |
309 * The type of the method handle will be that of the method, |
357 * The type of the method handle will be that of the method, |
331 * @param m the reflected method |
380 * @param m the reflected method |
332 * @return a method handle which can invoke the reflected method |
381 * @return a method handle which can invoke the reflected method |
333 * @exception NoAccessException if access checking fails |
382 * @exception NoAccessException if access checking fails |
334 */ |
383 */ |
335 public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws NoAccessException { |
384 public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws NoAccessException { |
336 checkSpecialCaller(specialCaller, lookupClass); |
385 checkSpecialCaller(specialCaller, this); |
|
386 Lookup slookup = this.in(specialCaller); |
337 MemberName mname = new MemberName(m); |
387 MemberName mname = new MemberName(m); |
338 checkStatic(false, mname, lookupClass); |
388 checkStatic(false, mname, this); |
339 return unreflectImpl(mname, m.isAccessible(), false, specialCaller); |
389 return unreflectImpl(mname, m.isAccessible(), false, false, slookup); |
340 } |
390 } |
341 |
391 |
342 /** |
392 /** |
|
393 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
343 * Produce a method handle for a reflected constructor. |
394 * Produce a method handle for a reflected constructor. |
344 * The type of the method handle will be that of the constructor. |
395 * The type of the method handle will be that of the constructor, |
|
396 * with the return type changed to the declaring class. |
345 * The method handle will perform a {@code newInstance} operation, |
397 * The method handle will perform a {@code newInstance} operation, |
346 * creating a new instance of the constructor's class on the |
398 * creating a new instance of the constructor's class on the |
347 * arguments passed to the method handle. |
399 * arguments passed to the method handle. |
348 * <p> |
400 * <p> |
349 * If the constructor's {@code accessible} flag is not set, |
401 * If the constructor's {@code accessible} flag is not set, |
350 * access checking is performed immediately on behalf of the lookup class, |
402 * access checking is performed immediately on behalf of the lookup class. |
351 * as if {@code invokespecial} instruction were being linked. |
|
352 * @param ctor the reflected constructor |
403 * @param ctor the reflected constructor |
353 * @return a method handle which can invoke the reflected constructor |
404 * @return a method handle which can invoke the reflected constructor |
354 * @exception NoAccessException if access checking fails |
405 * @exception NoAccessException if access checking fails |
355 */ |
406 */ |
356 public MethodHandle unreflectConstructor(Constructor ctor) throws NoAccessException { |
407 public MethodHandle unreflectConstructor(Constructor ctor) throws NoAccessException { |
357 MemberName m = new MemberName(ctor); |
408 MemberName m = new MemberName(ctor); |
358 return unreflectImpl(m, ctor.isAccessible(), false, lookupClass); |
409 return unreflectImpl(m, ctor.isAccessible(), false, false, this); |
359 } |
410 } |
360 |
411 |
361 /** |
412 /** |
362 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
413 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
363 * Produce a method handle giving read access to a reflected field. |
414 * Produce a method handle giving read access to a reflected field. |
364 * The type of the method handle will have a return type of the field's |
415 * The type of the method handle will have a return type of the field's |
365 * value type. Its sole argument will be the field's containing class |
416 * value type. |
366 * (but only if it is non-static). |
417 * If the field is static, the method handle will take no arguments. |
|
418 * Otherwise, its single argument will be the instance containing |
|
419 * the field. |
367 * If the method's {@code accessible} flag is not set, |
420 * If the method's {@code accessible} flag is not set, |
368 * access checking is performed immediately on behalf of the lookup class. |
421 * access checking is performed immediately on behalf of the lookup class. |
369 * @param f the reflected field |
422 * @param f the reflected field |
370 * @return a method handle which can load values from the reflected field |
423 * @return a method handle which can load values from the reflected field |
371 * @exception NoAccessException if access checking fails |
424 * @exception NoAccessException if access checking fails |
372 */ |
425 */ |
373 public MethodHandle unreflectGetter(Field f) throws NoAccessException { |
426 public MethodHandle unreflectGetter(Field f) throws NoAccessException { |
374 return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), false, lookupClass); |
427 MemberName m = new MemberName(f); |
|
428 return unreflectImpl(m, f.isAccessible(), false, false, this); |
375 } |
429 } |
376 |
430 |
377 /** |
431 /** |
378 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
432 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
379 * Produce a method handle giving write access to a reflected field. |
433 * Produce a method handle giving write access to a reflected field. |
380 * The type of the method handle will have a void return type. |
434 * The type of the method handle will have a void return type. |
381 * Its last argument will be the field's value type. |
435 * If the field is static, the method handle will take a single |
382 * Its other argument will be the field's containing class |
436 * argument, of the field's value type, the value to be stored. |
383 * (but only if it is non-static). |
437 * Otherwise, the two arguments will be the instance containing |
|
438 * the field, and the value to be stored. |
384 * If the method's {@code accessible} flag is not set, |
439 * If the method's {@code accessible} flag is not set, |
385 * access checking is performed immediately on behalf of the lookup class. |
440 * access checking is performed immediately on behalf of the lookup class. |
386 * @param f the reflected field |
441 * @param f the reflected field |
387 * @return a method handle which can store values into the reflected field |
442 * @return a method handle which can store values into the reflected field |
388 * @exception NoAccessException if access checking fails |
443 * @exception NoAccessException if access checking fails |
389 */ |
444 */ |
390 public MethodHandle unreflectSetter(Field f) throws NoAccessException { |
445 public MethodHandle unreflectSetter(Field f) throws NoAccessException { |
391 return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), true, lookupClass); |
446 MemberName m = new MemberName(f); |
|
447 return unreflectImpl(m, f.isAccessible(), false, true, this); |
392 } |
448 } |
393 |
449 |
394 } |
450 } |
395 |
451 |
396 static /*must not be public*/ |
452 static /*must not be public*/ |
397 MethodHandle findStaticFrom(Class<?> lookupClass, |
453 MethodHandle findStaticFrom(Lookup lookup, |
398 Class<?> defc, String name, MethodType type) throws NoAccessException { |
454 Class<?> defc, String name, MethodType type) throws NoAccessException { |
399 MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookupClass); |
455 MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookup.lookupClass()); |
400 checkStatic(true, method, lookupClass); |
456 VerifyAccess.checkName(method, lookup); |
401 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClass); |
457 checkStatic(true, method, lookup); |
402 } |
458 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookup.lookupClass()); |
403 |
459 } |
404 static void checkStatic(boolean wantStatic, MemberName m, Class<?> lookupClass) { |
460 |
|
461 static void checkStatic(boolean wantStatic, MemberName m, Lookup lookup) { |
405 if (wantStatic != m.isStatic()) { |
462 if (wantStatic != m.isStatic()) { |
406 String message = wantStatic ? "expected a static method" : "expected a non-static method"; |
463 String message = wantStatic ? "expected a static method" : "expected a non-static method"; |
407 throw newNoAccessException(message, m, lookupClass); |
464 throw newNoAccessException(message, m, lookup.lookupClass()); |
408 } |
465 } |
409 } |
466 } |
410 |
467 |
411 static void checkSpecialCaller(Class<?> specialCaller, Class<?> lookupClass) { |
468 static void checkSpecialCaller(Class<?> specialCaller, Lookup lookup) { |
412 if (lookupClass == Lookup.IMPL_LOOKUP.lookupClass()) |
469 if (lookup == Lookup.IMPL_LOOKUP) |
413 return; // privileged action |
470 return; // privileged action |
414 if (lookupClass == null || // public-only access |
471 assert(lookup.lookupClass() != null); |
415 !VerifyAccess.isSamePackageMember(specialCaller, lookupClass)) |
472 if (!VerifyAccess.isSamePackageMember(specialCaller, lookup.lookupClass())) |
416 throw newNoAccessException("no private access", new MemberName(specialCaller), lookupClass); |
473 throw newNoAccessException("no private access", new MemberName(specialCaller), lookup.lookupClass()); |
417 } |
474 } |
418 |
475 |
419 // Helper for creating handles on reflected methods and constructors. |
476 // Helper for creating handles on reflected methods and constructors. |
420 static MethodHandle unreflectImpl(MemberName m, boolean isAccessible, |
477 static MethodHandle unreflectImpl(MemberName m, boolean isAccessible, |
421 boolean doDispatch, Class<?> lookupClass) { |
478 boolean doDispatch, boolean isSetter, Lookup lookup) { |
422 MethodType mtype = m.getInvocationType(); |
479 MethodType narrowMethodType = null; |
423 Class<?> defc = m.getDeclaringClass(); |
480 Class<?> defc = m.getDeclaringClass(); |
|
481 boolean isSpecialInvoke = m.isInvocable() && !doDispatch; |
424 int mods = m.getModifiers(); |
482 int mods = m.getModifiers(); |
425 if (m.isStatic()) { |
483 if (m.isStatic()) { |
426 if (!isAccessible && |
484 if (!isAccessible && |
427 VerifyAccess.isAccessible(defc, mods, false, lookupClass) == null) |
485 VerifyAccess.isAccessible(defc, mods, lookup.lookupClass(), false) == null) |
428 throw newNoAccessException(m, lookupClass); |
486 throw newNoAccessException(m, lookup); |
429 } else { |
487 } else { |
430 Class<?> constraint; |
488 Class<?> constraint; |
431 if (isAccessible) { |
489 if (isAccessible) { |
432 // abbreviated access check for "unlocked" method |
490 // abbreviated access check for "unlocked" method |
433 constraint = doDispatch ? defc : lookupClass; |
491 constraint = doDispatch ? defc : lookup.lookupClass(); |
434 } else { |
492 } else { |
435 constraint = VerifyAccess.isAccessible(defc, mods, doDispatch, lookupClass); |
493 constraint = VerifyAccess.isAccessible(defc, mods, lookup.lookupClass(), isSpecialInvoke); |
|
494 } |
|
495 if (constraint == null) { |
|
496 throw newNoAccessException(m, lookup); |
436 } |
497 } |
437 if (constraint != defc && !constraint.isAssignableFrom(defc)) { |
498 if (constraint != defc && !constraint.isAssignableFrom(defc)) { |
438 if (!defc.isAssignableFrom(constraint)) |
499 if (!defc.isAssignableFrom(constraint)) |
439 throw newNoAccessException("receiver must be in caller class", m, lookupClass); |
500 throw newNoAccessException("receiver must be in caller class", m, lookup.lookupClass()); |
440 mtype = mtype.changeParameterType(0, constraint); |
501 if (m.isInvocable()) |
|
502 narrowMethodType = m.getInvocationType().changeParameterType(0, constraint); |
|
503 else if (m.isField()) |
|
504 narrowMethodType = (!isSetter |
|
505 ? MethodType.methodType(m.getFieldType(), constraint) |
|
506 : MethodType.methodType(void.class, constraint, m.getFieldType())); |
441 } |
507 } |
442 } |
508 } |
443 return MethodHandleImpl.findMethod(IMPL_TOKEN, m, doDispatch, lookupClass); |
509 if (m.isInvocable()) |
|
510 return MethodHandleImpl.findMethod(IMPL_TOKEN, m, doDispatch, lookup.lookupClass()); |
|
511 else if (m.isField()) |
|
512 return MethodHandleImpl.accessField(IMPL_TOKEN, m, isSetter, lookup.lookupClass()); |
|
513 else |
|
514 throw new InternalError(); |
444 } |
515 } |
445 |
516 |
446 /** |
517 /** |
447 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
518 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
448 * Produce a method handle giving read access to elements of an array. |
519 * Produce a method handle giving read access to elements of an array. |
470 public static |
541 public static |
471 MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException { |
542 MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException { |
472 return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, true); |
543 return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, true); |
473 } |
544 } |
474 |
545 |
475 |
|
476 /// method handle invocation (reflective style) |
546 /// method handle invocation (reflective style) |
477 |
547 |
478 /** |
548 /** |
479 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
549 * @deprecated Alias for MethodHandle.invokeVarargs. |
480 * Call the {@code invoke} method of a given method handle, |
550 */ |
481 * with arguments that exactly match the parameter types of the method handle. |
551 @Deprecated |
482 * The length of the arguments array must equal the parameter count |
552 public static |
483 * of the target's type. |
553 Object invokeVarargs(MethodHandle target, Object... arguments) throws Throwable { |
484 * The arguments array is spread into separate arguments, and |
554 return target.invokeVarargs(arguments); |
485 * basic reference and unboxing conversions are applied. |
555 } |
486 * <p> |
556 |
487 * In order to match the type of the target, the following argument |
557 /** |
488 * conversions are applied as necessary: |
558 * @deprecated Alias for MethodHandle.invokeVarargs. |
489 * <ul> |
559 */ |
490 * <li>reference casting |
560 @Deprecated |
491 * <li>unboxing |
561 public static |
492 * </ul> |
562 Object invoke(MethodHandle target, Object... arguments) throws Throwable { |
493 * The following conversions are not applied: |
563 return target.invokeVarargs(arguments); |
494 * <ul> |
564 } |
495 * <li>primitive conversions (e.g., {@code byte} to {@code int} |
565 |
496 * <li>varargs conversions other than the initial spread |
566 /** |
497 * <li>any application-specific conversions (e.g., string to number) |
567 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
498 * </ul> |
568 * Produce a method handle which will invoke any method handle of the |
499 * The result returned by the call is boxed if it is a primitive, |
|
500 * or forced to null if the return type is void. |
|
501 * <p> |
|
502 * This call is a convenience method for the following code: |
|
503 * <pre> |
|
504 * MethodHandle invoker = MethodHandles.genericInvoker(target.type(), 0, true); |
|
505 * Object result = invoker.invoke(arguments); |
|
506 * </pre> |
|
507 * @param target the method handle to invoke |
|
508 * @param arguments the arguments to pass to the target |
|
509 * @return the result returned by the target |
|
510 */ |
|
511 public static |
|
512 Object invoke(MethodHandle target, Object... arguments) { |
|
513 int argc = arguments == null ? 0 : arguments.length; |
|
514 MethodType type = target.type(); |
|
515 if (argc <= 4) { |
|
516 MethodHandle invoker = invokers(type).genericInvoker(); |
|
517 switch (argc) { |
|
518 case 0: return invoker.<Object>invoke(target); |
|
519 case 1: return invoker.<Object>invoke(target, |
|
520 arguments[0]); |
|
521 case 2: return invoker.<Object>invoke(target, |
|
522 arguments[0], arguments[1]); |
|
523 case 3: return invoker.<Object>invoke(target, |
|
524 arguments[0], arguments[1], arguments[2]); |
|
525 case 4: return invoker.<Object>invoke(target, |
|
526 arguments[0], arguments[1], arguments[2], arguments[3]); |
|
527 } |
|
528 } |
|
529 MethodHandle invoker = invokers(type).varargsInvoker(); |
|
530 return invoker.<Object>invoke(target, arguments); |
|
531 } |
|
532 |
|
533 public static |
|
534 Object invoke_0(MethodHandle target) { |
|
535 MethodHandle invoker = invokers(target.type()).genericInvoker(); |
|
536 return invoker.<Object>invoke(target); |
|
537 } |
|
538 public static |
|
539 Object invoke_1(MethodHandle target, Object a0) { |
|
540 MethodHandle invoker = invokers(target.type()).genericInvoker(); |
|
541 return invoker.<Object>invoke(target, a0); |
|
542 } |
|
543 public static |
|
544 Object invoke_2(MethodHandle target, Object a0, Object a1) { |
|
545 MethodHandle invoker = invokers(target.type()).genericInvoker(); |
|
546 return invoker.<Object>invoke(target, a0, a1); |
|
547 } |
|
548 public static |
|
549 Object invoke_3(MethodHandle target, Object a0, Object a1, Object a2) { |
|
550 MethodHandle invoker = invokers(target.type()).genericInvoker(); |
|
551 return invoker.<Object>invoke(target, a0, a1, a2); |
|
552 } |
|
553 public static |
|
554 Object invoke_4(MethodHandle target, Object a0, Object a1, Object a2, Object a3) { |
|
555 MethodHandle invoker = invokers(target.type()).genericInvoker(); |
|
556 return invoker.<Object>invoke(target, a0, a1, a2, a3); |
|
557 } |
|
558 |
|
559 /** |
|
560 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
|
561 * Give a method handle which will invoke any method handle of the |
|
562 * given type on a standard set of {@code Object} type arguments. |
569 * given type on a standard set of {@code Object} type arguments. |
563 * The the resulting invoker will be a method handle with the following |
570 * The resulting invoker will be a method handle with the following |
564 * arguments: |
571 * arguments: |
565 * <ul> |
572 * <ul> |
566 * <li>a single {@code MethodHandle} target |
573 * <li>a single {@code MethodHandle} target |
567 * <li>zero or more {@code Object} values |
574 * <li>zero or more {@code Object} values (one for each argument in {@code type}) |
568 * <li>an optional {@code Object[]} array containing more arguments |
|
569 * </ul> |
575 * </ul> |
570 * The invoker will spread the varargs array (if present), apply |
576 * The invoker will apply reference casts as necessary and unbox primitive arguments, |
|
577 * as if by {@link #convertArguments}. |
|
578 * The return value of the invoker will be an {@code Object} reference, |
|
579 * boxing a primitive value if the original type returns a primitive, |
|
580 * and always null if the original type returns void. |
|
581 * <p> |
|
582 * This method is equivalent to the following code (though it may be more efficient): |
|
583 * <p><blockquote><pre> |
|
584 * MethodHandle invoker = exactInvoker(type); |
|
585 * MethodType genericType = type.generic(); |
|
586 * genericType = genericType.insertParameterType(0, MethodHandle.class); |
|
587 * return convertArguments(invoker, genericType); |
|
588 * </pre></blockquote> |
|
589 * @param type the type of target methods which the invoker will apply to |
|
590 * @return a method handle suitable for invoking any method handle of the given type |
|
591 */ |
|
592 static public |
|
593 MethodHandle genericInvoker(MethodType type) { |
|
594 return invokers(type).genericInvoker(); |
|
595 } |
|
596 |
|
597 /** |
|
598 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
|
599 * Produce a method handle which will invoke any method handle of the |
|
600 * given type on a standard set of {@code Object} type arguments |
|
601 * and a single trailing {@code Object[]} array. |
|
602 * The resulting invoker will be a method handle with the following |
|
603 * arguments: |
|
604 * <ul> |
|
605 * <li>a single {@code MethodHandle} target |
|
606 * <li>zero or more {@code Object} values (counted by {@code objectArgCount}) |
|
607 * <li>an {@code Object[]} array containing more arguments |
|
608 * </ul> |
|
609 * The invoker will spread the varargs array, apply |
571 * reference casts as necessary, and unbox primitive arguments. |
610 * reference casts as necessary, and unbox primitive arguments. |
572 * The return value of the invoker will be an {@code Object} reference, |
611 * The return value of the invoker will be an {@code Object} reference, |
573 * boxing a primitive value if the original type returns a primitive, |
612 * boxing a primitive value if the original type returns a primitive, |
574 * and always null if the original type returns void. |
613 * and always null if the original type returns void. |
575 * <p> |
614 * <p> |
576 * This is a convenience method equivalent to the following code: |
615 * This method is equivalent to the following code (though it may be more efficient): |
577 * <pre> |
616 * <p><blockquote><pre> |
578 * MethodHandle invoker = exactInvoker(type); |
617 * MethodHandle invoker = exactInvoker(type); |
579 * MethodType genericType = MethodType.makeGeneric(objectArgCount, varargs); |
618 * MethodType vaType = MethodType.makeGeneric(objectArgCount, true); |
580 * genericType = genericType.insertParameterType(0, MethodHandle.class); |
619 * vaType = vaType.insertParameterType(0, MethodHandle.class); |
581 * if (!varargs) |
620 * return spreadArguments(invoker, vaType); |
582 * return convertArguments(invoker, genericType); |
621 * </pre></blockquote> |
583 * else |
|
584 * return spreadArguments(invoker, genericType); |
|
585 * </pre> |
|
586 * @param type the desired target type |
622 * @param type the desired target type |
587 * @param objectArgCount number of fixed (non-varargs) {@code Object} arguments |
623 * @param objectArgCount number of fixed (non-varargs) {@code Object} arguments |
588 * @param varargs if true, the invoker will accept a final {@code Object[]} argument |
|
589 * @return a method handle suitable for invoking any method handle of the given type |
624 * @return a method handle suitable for invoking any method handle of the given type |
590 */ |
625 */ |
591 static public |
626 static public |
592 MethodHandle genericInvoker(MethodType type, int objectArgCount, boolean varargs) { |
627 MethodHandle varargsInvoker(MethodType type, int objectArgCount) { |
593 return invokers(type).genericInvoker(); |
628 if (objectArgCount < 0 || objectArgCount > type.parameterCount()) |
594 } |
629 throw new IllegalArgumentException("bad argument count "+objectArgCount); |
595 |
630 return invokers(type).varargsInvoker(objectArgCount); |
596 /** |
631 } |
597 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
632 |
598 * Give a method handle which will take a invoke any method handle of the |
633 /** |
|
634 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
|
635 * Produce a method handle which will take a invoke any method handle of the |
599 * given type. The resulting invoker will have a type which is |
636 * given type. The resulting invoker will have a type which is |
600 * exactly equal to the desired type, except that it will accept |
637 * exactly equal to the desired type, except that it will accept |
601 * an additional leading argument of type {@code MethodHandle}. |
638 * an additional leading argument of type {@code MethodHandle}. |
602 * <p> |
639 * <p> |
603 * This is a convenience method equivalent to the following code: |
640 * This method is equivalent to the following code (though it may be more efficient): |
604 * <pre> |
641 * <p><blockquote><pre> |
605 * MethodHandles.lookup().findVirtual(MethodHandle.class, "invoke", type); |
642 * lookup().findVirtual(MethodHandle.class, "invoke", type); |
606 * </pre> |
643 * </pre></blockquote> |
607 * @param type the desired target type |
644 * @param type the desired target type |
608 * @return a method handle suitable for invoking any method handle of the given type |
645 * @return a method handle suitable for invoking any method handle of the given type |
609 */ |
646 */ |
610 static public |
647 static public |
611 MethodHandle exactInvoker(MethodType type) { |
648 MethodHandle exactInvoker(MethodType type) { |
612 return invokers(type).exactInvoker(); |
649 return invokers(type).exactInvoker(); |
613 } |
650 } |
614 |
651 |
615 static private Invokers invokers(MethodType type) { |
652 /** |
|
653 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
|
654 * Produce a method handle equivalent to an invokedynamic instruction |
|
655 * which has been linked to the given call site. |
|
656 * Along with {@link Lookup#findVirtual}, {@link Lookup#findStatic}, |
|
657 * and {@link Lookup#findSpecial}, this completes the emulation |
|
658 * of the JVM's {@code invoke} instructions. |
|
659 * <p>This method is equivalent to the following code: |
|
660 * <p><blockquote><pre> |
|
661 * MethodHandle getTarget, invoker, result; |
|
662 * getTarget = lookup().bind(site, "getTarget", methodType(MethodHandle.class)); |
|
663 * invoker = exactInvoker(site.type()); |
|
664 * result = foldArguments(invoker, getTarget) |
|
665 * </pre></blockquote> |
|
666 * @return a method handle which always invokes the call site's target |
|
667 */ |
|
668 public static |
|
669 MethodHandle dynamicInvoker(CallSite site) { |
|
670 MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, CallSite.GET_TARGET, site); |
|
671 MethodHandle invoker = exactInvoker(site.type()); |
|
672 return foldArguments(invoker, getTarget); |
|
673 } |
|
674 |
|
675 static Invokers invokers(MethodType type) { |
616 return MethodTypeImpl.invokers(IMPL_TOKEN, type); |
676 return MethodTypeImpl.invokers(IMPL_TOKEN, type); |
617 } |
677 } |
618 |
678 |
619 /** |
679 /** |
620 * <em>WORK IN PROGRESS:</em> |
680 * <em>WORK IN PROGRESS:</em> |
686 } |
746 } |
687 |
747 |
688 /// method handle modification (creation from other method handles) |
748 /// method handle modification (creation from other method handles) |
689 |
749 |
690 /** |
750 /** |
691 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
|
692 * Produce a method handle which adapts the type of the |
751 * Produce a method handle which adapts the type of the |
693 * given method handle to a new type, by pairwise argument conversion, |
752 * given method handle to a new type by pairwise argument conversion. |
694 * and/or varargs conversion. |
753 * The original type and new type must have the same number of arguments. |
695 * The original type and new type must have the same number of |
|
696 * arguments, or else one or both them the must be varargs types. |
|
697 * The resulting method handle is guaranteed to confess a type |
754 * The resulting method handle is guaranteed to confess a type |
698 * which is equal to the desired new type, with any varargs property erased. |
755 * which is equal to the desired new type. |
699 * <p> |
756 * <p> |
700 * If the original type and new type are equal, returns target. |
757 * If the original type and new type are equal, returns target. |
701 * <p> |
758 * <p> |
702 * The following conversions are applied as needed both to |
759 * The following conversions are applied as needed both to |
703 * arguments and return types. Let T0 and T1 be the differing |
760 * arguments and return types. Let T0 and T1 be the differing |
704 * new and old parameter types (or old and new return types) |
761 * new and old parameter types (or old and new return types) |
705 * for corresponding values passed by the new and old method types. |
762 * for corresponding values passed by the new and old method types. |
706 * <p> |
|
707 * If an ordinary (non-varargs) parameter of the new type is |
|
708 * to be boxed in a varargs parameter of the old type of type T1[], |
|
709 * then T1 is the element type of the varargs array. |
|
710 * Otherwise, if a varargs parameter of the new type of type T0[] |
|
711 * is to be spread into one or more outgoing old type parameters, |
|
712 * then T0 is the element type of the |
|
713 * If the new type is varargs and the old type is not, the varargs |
|
714 * argument will be checked and must be a non-null array of exactly |
|
715 * the right length. If there are no parameters in the old type |
|
716 * corresponding to the new varargs parameter, the varargs argument |
|
717 * is also allowed to be null. |
|
718 * <p> |
|
719 * Given those types T0, T1, one of the following conversions is applied |
763 * Given those types T0, T1, one of the following conversions is applied |
720 * if possible: |
764 * if possible: |
721 * <ul> |
765 * <ul> |
722 * <li>If T0 and T1 are references, then a cast to T2 is applied, |
766 * <li>If T0 and T1 are references, and T1 is not an interface type, |
723 * where T2 is Object if T1 is an interface, else T1. |
767 * then a cast to T1 is applied. |
724 * (The types do not need to be related in any particular way. |
768 * (The types do not need to be related in any particular way.) |
725 * The treatment of interfaces follows the usage of the bytecode verifier.) |
769 * <li>If T0 and T1 are references, and T1 is an interface type, |
|
770 * then the value of type T0 is passed as a T1 without a cast. |
|
771 * (This treatment of interfaces follows the usage of the bytecode verifier.) |
726 * <li>If T0 and T1 are primitives, then a Java casting |
772 * <li>If T0 and T1 are primitives, then a Java casting |
727 * conversion (JLS 5.5) is applied, if one exists. |
773 * conversion (JLS 5.5) is applied, if one exists. |
728 * <li>If T0 and T1 are primitives and one is boolean, |
774 * <li>If T0 and T1 are primitives and one is boolean, |
729 * the boolean is treated as a one-bit unsigned integer. |
775 * the boolean is treated as a one-bit unsigned integer. |
730 * (This treatment follows the usage of the bytecode verifier.) |
776 * (This treatment follows the usage of the bytecode verifier.) |
898 int outargs = oldType.parameterCount(); |
939 int outargs = oldType.parameterCount(); |
899 int collectPos = outargs - 1; |
940 int collectPos = outargs - 1; |
900 int numCollect = (inargs - collectPos); |
941 int numCollect = (inargs - collectPos); |
901 if (collectPos < 0 || numCollect < 0) |
942 if (collectPos < 0 || numCollect < 0) |
902 throw newIllegalArgumentException("wrong number of arguments"); |
943 throw newIllegalArgumentException("wrong number of arguments"); |
903 return MethodHandleImpl.collectArguments(IMPL_TOKEN, target, newType, collectPos); |
944 MethodHandle res = MethodHandleImpl.collectArguments(IMPL_TOKEN, target, newType, collectPos, null); |
904 } |
945 if (res == null) { |
905 |
946 throw newIllegalArgumentException("cannot collect from "+newType+" to " +oldType); |
906 /** |
947 } |
907 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
948 return res; |
908 * Produce a method handle which calls the original method handle, |
949 } |
909 * after inserting the given argument at the given position. |
950 |
910 * The type of the new method handle will drop the corresponding argument |
951 /** |
911 * type from the original handle's type. |
952 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
912 * <p> |
953 * Produce a method handle which calls the original method handle {@code target}, |
913 * The given argument object must match the dropped argument type. |
954 * after inserting the given argument(s) at the given position. |
914 * If the dropped argument type is a primitive, the argument object |
955 * The formal parameters to {@code target} which will be supplied by those |
915 * must be a wrapper, and is unboxed to produce the primitive. |
956 * arguments are called <em>bound parameters</em>, because the new method |
|
957 * will contain bindings for those parameters take from {@code values}. |
|
958 * The type of the new method handle will drop the types for the bound |
|
959 * parameters from the original target type, since the new method handle |
|
960 * will no longer require those arguments to be supplied by its callers. |
|
961 * <p> |
|
962 * Each given argument object must match the corresponding bound parameter type. |
|
963 * If a bound parameter type is a primitive, the argument object |
|
964 * must be a wrapper, and will be unboxed to produce the primitive value. |
916 * <p> |
965 * <p> |
917 * The <i>pos</i> may range between zero and <i>N</i> (inclusively), |
966 * The <i>pos</i> may range between zero and <i>N</i> (inclusively), |
918 * where <i>N</i> is the number of argument types in <i>target</i>, |
967 * where <i>N</i> is the number of argument types in resulting method handle |
919 * meaning to insert the new argument as the first or last (respectively), |
968 * (after bound parameter types are dropped). |
920 * or somewhere in between. |
|
921 * @param target the method handle to invoke after the argument is inserted |
969 * @param target the method handle to invoke after the argument is inserted |
922 * @param pos where to insert the argument (zero for the first) |
970 * @param pos where to insert the argument (zero for the first) |
923 * @param value the argument to insert |
971 * @param values the series of arguments to insert |
924 * @return a new method handle which inserts an additional argument, |
972 * @return a new method handle which inserts an additional argument, |
925 * before calling the original method handle |
973 * before calling the original method handle |
926 */ |
974 */ |
927 public static |
975 public static |
928 MethodHandle insertArgument(MethodHandle target, int pos, Object value) { |
976 MethodHandle insertArguments(MethodHandle target, int pos, Object... values) { |
|
977 int insCount = values.length; |
929 MethodType oldType = target.type(); |
978 MethodType oldType = target.type(); |
930 ArrayList<Class<?>> ptypes = |
979 ArrayList<Class<?>> ptypes = |
931 new ArrayList<Class<?>>(oldType.parameterList()); |
980 new ArrayList<Class<?>>(oldType.parameterList()); |
932 int outargs = oldType.parameterCount(); |
981 int outargs = oldType.parameterCount(); |
933 int inargs = outargs - 1; |
982 int inargs = outargs - insCount; |
934 if (pos < 0 || pos >= outargs) |
983 if (inargs < 0) |
|
984 throw newIllegalArgumentException("too many values to insert"); |
|
985 if (pos < 0 || pos > inargs) |
935 throw newIllegalArgumentException("no argument type to append"); |
986 throw newIllegalArgumentException("no argument type to append"); |
936 Class<?> valueType = ptypes.remove(pos); |
987 MethodHandle result = target; |
937 value = checkValue(valueType, value); |
988 for (int i = 0; i < insCount; i++) { |
938 if (pos == 0 && !valueType.isPrimitive()) { |
989 Object value = values[i]; |
939 // At least for now, make bound method handles a special case. |
990 Class<?> valueType = oldType.parameterType(pos+i); |
940 // This lets us get by with minimal JVM support, at the expense |
991 value = checkValue(valueType, value); |
941 // of generating signature-specific adapters as Java bytecodes. |
992 if (pos == 0 && !valueType.isPrimitive()) { |
942 MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, target, value); |
993 // At least for now, make bound method handles a special case. |
943 if (bmh != null) return bmh; |
994 MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, result, value); |
944 // else fall through to general adapter machinery |
995 if (bmh != null) { |
945 } |
996 result = bmh; |
946 return MethodHandleImpl.bindArgument(IMPL_TOKEN, target, pos, value); |
997 continue; |
|
998 } |
|
999 // else fall through to general adapter machinery |
|
1000 } |
|
1001 result = MethodHandleImpl.bindArgument(IMPL_TOKEN, result, pos, value); |
|
1002 } |
|
1003 return result; |
|
1004 } |
|
1005 |
|
1006 @Deprecated // "use MethodHandles.insertArguments instead" |
|
1007 public static |
|
1008 MethodHandle insertArgument(MethodHandle target, int pos, Object value) { |
|
1009 return insertArguments(target, pos, value); |
947 } |
1010 } |
948 |
1011 |
949 /** |
1012 /** |
950 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
1013 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
951 * Produce a method handle which calls the original method handle, |
1014 * Produce a method handle which calls the original method handle, |
952 * after dropping the given argument(s) at the given position. |
1015 * after dropping the given argument(s) at the given position. |
953 * The type of the new method handle will insert the given argument |
1016 * The type of the new method handle will insert the given argument |
954 * type(s), at that position, into the original handle's type. |
1017 * type(s), at that position, into the original handle's type. |
955 * <p> |
1018 * <p> |
956 * The <i>pos</i> may range between zero and <i>N-1</i>, |
1019 * The <i>pos</i> may range between zero and <i>N</i>, |
957 * where <i>N</i> is the number of argument types in <i>target</i>, |
1020 * where <i>N</i> is the number of argument types in <i>target</i>, |
958 * meaning to drop the first or last argument (respectively), |
1021 * meaning to drop the first or last argument (respectively), |
959 * or an argument somewhere in between. |
1022 * or an argument somewhere in between. |
|
1023 * <p> |
|
1024 * <b>Example:</b> |
|
1025 * <p><blockquote><pre> |
|
1026 * MethodHandle cat = MethodHandles.lookup(). |
|
1027 * findVirtual(String.class, "concat", String.class, String.class); |
|
1028 * System.out.println(cat.<String>invoke("x", "y")); // xy |
|
1029 * MethodHandle d0 = dropArguments(cat, 0, String.class); |
|
1030 * System.out.println(d0.<String>invoke("x", "y", "z")); // xy |
|
1031 * MethodHandle d1 = dropArguments(cat, 1, String.class); |
|
1032 * System.out.println(d1.<String>invoke("x", "y", "z")); // xz |
|
1033 * MethodHandle d2 = dropArguments(cat, 2, String.class); |
|
1034 * System.out.println(d2.<String>invoke("x", "y", "z")); // yz |
|
1035 * MethodHandle d12 = dropArguments(cat, 1, String.class, String.class); |
|
1036 * System.out.println(d12.<String>invoke("w", "x", "y", "z")); // wz |
|
1037 * </pre></blockquote> |
960 * @param target the method handle to invoke after the argument is dropped |
1038 * @param target the method handle to invoke after the argument is dropped |
961 * @param valueTypes the type(s) of the argument to drop |
1039 * @param valueTypes the type(s) of the argument to drop |
962 * @param pos which argument to drop (zero for the first) |
1040 * @param pos which argument to drop (zero for the first) |
963 * @return a new method handle which drops an argument of the given type, |
1041 * @return a new method handle which drops an argument of the given type, |
964 * before calling the original method handle |
1042 * before calling the original method handle |
965 */ |
1043 */ |
966 public static |
1044 public static |
967 MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) { |
1045 MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) { |
968 if (valueTypes.length == 0) return target; |
1046 if (valueTypes.size() == 0) return target; |
969 MethodType oldType = target.type(); |
1047 MethodType oldType = target.type(); |
970 int outargs = oldType.parameterCount(); |
1048 int outargs = oldType.parameterCount(); |
971 int inargs = outargs + valueTypes.length; |
1049 int inargs = outargs + valueTypes.size(); |
972 if (pos < 0 || pos >= inargs) |
1050 if (pos < 0 || pos >= inargs) |
973 throw newIllegalArgumentException("no argument type to remove"); |
1051 throw newIllegalArgumentException("no argument type to remove"); |
974 ArrayList<Class<?>> ptypes = |
1052 ArrayList<Class<?>> ptypes = |
975 new ArrayList<Class<?>>(oldType.parameterList()); |
1053 new ArrayList<Class<?>>(oldType.parameterList()); |
976 ptypes.addAll(pos, Arrays.asList(valueTypes)); |
1054 ptypes.addAll(pos, valueTypes); |
977 MethodType newType = MethodType.make(oldType.returnType(), ptypes); |
1055 MethodType newType = MethodType.methodType(oldType.returnType(), ptypes); |
978 return MethodHandleImpl.dropArguments(IMPL_TOKEN, target, newType, pos); |
1056 return MethodHandleImpl.dropArguments(IMPL_TOKEN, target, newType, pos); |
|
1057 } |
|
1058 |
|
1059 public static |
|
1060 MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) { |
|
1061 return dropArguments(target, pos, Arrays.asList(valueTypes)); |
|
1062 } |
|
1063 |
|
1064 /** |
|
1065 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
|
1066 * Adapt a target method handle {@code target} by pre-processing |
|
1067 * one or more of its arguments, each with its own unary filter function, |
|
1068 * and then calling the target with each pre-processed argument |
|
1069 * replaced by the result of its corresponding filter function. |
|
1070 * <p> |
|
1071 * The pre-processing is performed by one or more method handles, |
|
1072 * specified in the non-null elements of the {@code filters} array. |
|
1073 * (If there are no such elements, the original target is returned.) |
|
1074 * Each filter (that is, each non-null element of {@code filters}) |
|
1075 * is applied to the corresponding argument of the adapter. |
|
1076 * <p> |
|
1077 * If a filter {@code F} applies to the {@code N}th argument of |
|
1078 * the method handle, then {@code F} must be a method handle which |
|
1079 * takes exactly one argument. The type of {@code F}'s sole argument |
|
1080 * replaces the corresponding argument type of the target |
|
1081 * in the resulting adapted method handle. |
|
1082 * The return type of {@code F} must be identical to the corresponding |
|
1083 * parameter type of the target. |
|
1084 * <p> |
|
1085 * It is an error if there are non-null elements of {@code filters} |
|
1086 * which do not correspond to argument positions in the target. |
|
1087 * The actual length of the target array may be any number, it need |
|
1088 * not be the same as the parameter count of the target type. |
|
1089 * (This provides an easy way to filter just the first argument or two |
|
1090 * of a target method handle.) |
|
1091 * <p> Here is pseudocode for the resulting adapter: |
|
1092 * <blockquote><pre> |
|
1093 * // there are N arguments in the A sequence |
|
1094 * T target(A[N]...); |
|
1095 * [i<N] V[i] filter[i](B[i]) = filters[i] ?: identity; |
|
1096 * T adapter(B[N]... b) { |
|
1097 * A[N] a...; |
|
1098 * [i<N] a[i] = filter[i](b[i]); |
|
1099 * return target(a...); |
|
1100 * } |
|
1101 * </pre></blockquote> |
|
1102 * @param target the method handle to invoke after arguments are filtered |
|
1103 * @param filters method handles to call initially on filtered arguments |
|
1104 * @return method handle which incorporates the specified argument filtering logic |
|
1105 * @throws IllegalArgumentException if a non-null element of {@code filters} |
|
1106 * does not match a corresponding argument type of {@code target} |
|
1107 */ |
|
1108 public static |
|
1109 MethodHandle filterArguments(MethodHandle target, MethodHandle... filters) { |
|
1110 MethodType targetType = target.type(); |
|
1111 MethodHandle adapter = target; |
|
1112 MethodType adapterType = targetType; |
|
1113 int pos = -1, maxPos = targetType.parameterCount(); |
|
1114 for (MethodHandle filter : filters) { |
|
1115 pos += 1; |
|
1116 if (filter == null) continue; |
|
1117 if (pos >= maxPos) |
|
1118 throw newIllegalArgumentException("too many filters"); |
|
1119 MethodType filterType = filter.type(); |
|
1120 if (filterType.parameterCount() != 1 |
|
1121 || filterType.returnType() != targetType.parameterType(pos)) |
|
1122 throw newIllegalArgumentException("target and filter types do not match"); |
|
1123 adapterType = adapterType.changeParameterType(pos, filterType.parameterType(0)); |
|
1124 adapter = MethodHandleImpl.filterArgument(IMPL_TOKEN, adapter, pos, filter); |
|
1125 } |
|
1126 MethodType midType = adapter.type(); |
|
1127 if (midType != adapterType) |
|
1128 adapter = MethodHandleImpl.convertArguments(IMPL_TOKEN, adapter, adapterType, midType, null); |
|
1129 return adapter; |
|
1130 } |
|
1131 |
|
1132 /** |
|
1133 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
|
1134 * Adapt a target method handle {@code target} by pre-processing |
|
1135 * some of its arguments, and then calling the target with |
|
1136 * the result of the pre-processing, plus all original arguments. |
|
1137 * <p> |
|
1138 * The pre-processing is performed by a second method handle, the {@code combiner}. |
|
1139 * The first {@code N} arguments passed to the adapter, |
|
1140 * are copied to the combiner, which then produces a result. |
|
1141 * (Here, {@code N} is defined as the parameter count of the adapter.) |
|
1142 * After this, control passes to the {@code target}, with both the result |
|
1143 * of the combiner, and all the original incoming arguments. |
|
1144 * <p> |
|
1145 * The first argument type of the target must be identical with the |
|
1146 * return type of the combiner. |
|
1147 * The resulting adapter is the same type as the target, except that the |
|
1148 * initial argument type of the target is dropped. |
|
1149 * <p> |
|
1150 * (Note that {@link #dropArguments} can be used to remove any arguments |
|
1151 * that either the {@code combiner} or {@code target} does not wish to receive. |
|
1152 * If some of the incoming arguments are destined only for the combiner, |
|
1153 * consider using {@link #collectArguments} instead, since those |
|
1154 * arguments will not need to be live on the stack on entry to the |
|
1155 * target.) |
|
1156 * <p> |
|
1157 * The first argument of the target must be identical with the |
|
1158 * return value of the combiner. |
|
1159 * <p> Here is pseudocode for the resulting adapter: |
|
1160 * <blockquote><pre> |
|
1161 * // there are N arguments in the A sequence |
|
1162 * T target(V, A[N]..., B...); |
|
1163 * V combiner(A...); |
|
1164 * T adapter(A... a, B... b) { |
|
1165 * V v = combiner(a...); |
|
1166 * return target(v, a..., b...); |
|
1167 * } |
|
1168 * </pre></blockquote> |
|
1169 * @param target the method handle to invoke after arguments are combined |
|
1170 * @param combiner method handle to call initially on the incoming arguments |
|
1171 * @return method handle which incorporates the specified argument folding logic |
|
1172 * @throws IllegalArgumentException if the first argument type of |
|
1173 * {@code target} is not the same as {@code combiner}'s return type, |
|
1174 * or if the next {@code foldArgs} argument types of {@code target} |
|
1175 * are not identical with the argument types of {@code combiner} |
|
1176 */ |
|
1177 public static |
|
1178 MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) { |
|
1179 MethodType targetType = target.type(); |
|
1180 MethodType combinerType = combiner.type(); |
|
1181 int foldArgs = combinerType.parameterCount(); |
|
1182 boolean ok = (targetType.parameterCount() >= 1 + foldArgs); |
|
1183 if (!ok) |
|
1184 throw misMatchedTypes("target and combiner types", targetType, combinerType); |
|
1185 MethodType newType = targetType.dropParameterTypes(0, 1); |
|
1186 return MethodHandleImpl.foldArguments(IMPL_TOKEN, target, newType, combiner); |
979 } |
1187 } |
980 |
1188 |
981 /** |
1189 /** |
982 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
1190 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
983 * Make a method handle which adapts a target method handle, |
1191 * Make a method handle which adapts a target method handle, |
984 * by guarding it with a test, a boolean-valued method handle. |
1192 * by guarding it with a test, a boolean-valued method handle. |
985 * If the guard fails, a fallback handle is called instead. |
1193 * If the guard fails, a fallback handle is called instead. |
986 * All three method handles must have the same corresponding |
1194 * All three method handles must have the same corresponding |
987 * argument and return types, except that the return type |
1195 * argument and return types, except that the return type |
988 * of the test must be boolean. |
1196 * of the test must be boolean, and the test is allowed |
|
1197 * to have fewer arguments than the other two method handles. |
989 * <p> Here is pseudocode for the resulting adapter: |
1198 * <p> Here is pseudocode for the resulting adapter: |
990 * <blockquote><pre> |
1199 * <blockquote><pre> |
991 * signature T(A...); |
|
992 * boolean test(A...); |
1200 * boolean test(A...); |
993 * T target(A...); |
1201 * T target(A...,B...); |
994 * T fallback(A...); |
1202 * T fallback(A...,B...); |
995 * T adapter(A... a) { |
1203 * T adapter(A... a,B... b) { |
996 * if (test(a...)) |
1204 * if (test(a...)) |
997 * return target(a...); |
1205 * return target(a..., b...); |
998 * else |
1206 * else |
999 * return fallback(a...); |
1207 * return fallback(a..., b...); |
1000 * } |
1208 * } |
1001 * </pre></blockquote> |
1209 * </pre></blockquote> |
1002 * @param test method handle used for test, must return boolean |
1210 * @param test method handle used for test, must return boolean |
1003 * @param target method handle to call if test passes |
1211 * @param target method handle to call if test passes |
1004 * @param fallback method handle to call if test fails |
1212 * @param fallback method handle to call if test fails |
1025 f = dropArguments(f, 1, initargs); // ignore 2nd copy of args |
1246 f = dropArguments(f, 1, initargs); // ignore 2nd copy of args |
1026 return combineArguments(f, g); |
1247 return combineArguments(f, g); |
1027 } |
1248 } |
1028 // choose = \z.(z ? target : fallback) |
1249 // choose = \z.(z ? target : fallback) |
1029 MethodHandle choose = findVirtual(MethodHandles.class, "choose", |
1250 MethodHandle choose = findVirtual(MethodHandles.class, "choose", |
1030 MethodType.make(boolean.class, MethodHandle.class, MethodHandle.class)); |
1251 MethodType.methodType(boolean.class, MethodHandle.class, MethodHandle.class)); |
1031 choose = appendArgument(choose, target); |
1252 choose = appendArgument(choose, target); |
1032 choose = appendArgument(choose, fallback); |
1253 choose = appendArgument(choose, fallback); |
1033 MethodHandle dispatch = compose(choose, test); |
1254 MethodHandle dispatch = compose(choose, test); |
1034 // dispatch = \(a...).(test(a...) ? target : fallback) |
1255 // dispatch = \(a...).(test(a...) ? target : fallback) |
1035 return combineArguments(invoke, dispatch, 0); |
1256 return combineArguments(invoke, dispatch, 0); |
1036 // return \(a...).((test(a...) ? target : fallback).invoke(a...)) |
1257 // return \(a...).((test(a...) ? target : fallback).invoke(a...)) |
1037 } */ |
1258 } */ |
1038 return MethodHandleImpl.makeGuardWithTest(IMPL_TOKEN, test, target, fallback); |
1259 return MethodHandleImpl.makeGuardWithTest(IMPL_TOKEN, test, target, fallback); |
1039 } |
1260 } |
1040 |
1261 |
1041 /** |
1262 static RuntimeException misMatchedTypes(String what, MethodType t1, MethodType t2) { |
1042 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
1263 return newIllegalArgumentException(what + " must match: " + t1 + " != " + t2); |
1043 * Adapt a target method handle {@code target} by first processing |
1264 } |
1044 * its arguments, and then calling the target. |
1265 |
1045 * The initial processing is performed by a second method handle, the {@code combiner}. |
1266 /** |
1046 * After this, control passes to the {@code target}, with the same arguments. |
1267 * <em>PROVISIONAL API, WORK IN PROGRESS:</em> |
1047 * <p> |
1268 * Make a method handle which adapts a target method handle, |
1048 * The return value of the {@code combiner} is inserted into the argument list |
1269 * by running it inside an exception handler. |
1049 * for the {@code target} at the indicated position {@code pos}, if it is non-negative. |
1270 * If the target returns normally, the adapter returns that value. |
1050 * Except for this inserted argument (if any), the argument types of |
1271 * If an exception matching the specified type is thrown, the fallback |
1051 * the target {@code target} and the {@code combiner} must be identical. |
1272 * handle is called instead on the exception, plus the original arguments. |
1052 * <p> |
1273 * <p> |
1053 * (Note that {@link #dropArguments} can be used to remove any arguments |
1274 * The handler must have leading parameter of {@code exType} or a supertype, |
1054 * that either the {@code combiner} or {@code target} does not wish to receive.) |
1275 * followed by arguments which correspond <em>(how? TBD)</em> to |
1055 * <p> |
1276 * all the parameters of the target. |
1056 * The combiner handle must have the same argument types as the |
1277 * The target and handler must return the same type. |
1057 * target handle, but must return {@link MethodHandle} instead of |
|
1058 * the ultimate return type. The returned method handle, in turn, |
|
1059 * is required to have exactly the given final method type. |
|
1060 * <p> Here is pseudocode for the resulting adapter: |
1278 * <p> Here is pseudocode for the resulting adapter: |
1061 * <blockquote><pre> |
1279 * <blockquote><pre> |
1062 * signature V(A[pos]..., B...); |
1280 * T target(A...); |
1063 * signature T(A[pos]..., V, B...); |
1281 * T handler(ExType, A...); |
1064 * T target(A... a, V v, B... b); |
1282 * T adapter(A... a) { |
1065 * V combiner(A..., B...); |
1283 * try { |
1066 * T adapter(A... a, B... b) { |
1284 * return target(a...); |
1067 * V v = combiner(a..., b...); |
1285 * } catch (ExType ex) { |
1068 * return target(a..., v, b...); |
1286 * return handler(ex, a...); |
|
1287 * } |
1069 * } |
1288 * } |
1070 * </pre></blockquote> |
1289 * </pre></blockquote> |
1071 * @param target the method handle to invoke after arguments are combined |
1290 * @param target method handle to call |
1072 * @param pos where the return value of {@code combiner} is to |
1291 * @param exType the type of exception which the handler will catch |
1073 * be inserted as an argument to {@code target} |
1292 * @param handler method handle to call if a matching exception is thrown |
1074 * @param combiner method handle to call initially on the incoming arguments |
1293 * @return method handle which incorporates the specified try/catch logic |
1075 * @return method handle which incorporates the specified dispatch logic |
1294 * @throws IllegalArgumentException if {@code handler} does not accept |
1076 * @throws IllegalArgumentException if {@code combiner} does not itself |
1295 * the given exception type, or if the method handle types do |
1077 * return either void or the {@code pos}-th argument of {@code target}, |
1296 * not match in their return types and their |
1078 * or does not have the same argument types as {@code target} |
1297 * corresponding parameters |
1079 * (minus the inserted argument) |
1298 */ |
1080 */ |
1299 public static |
1081 public static |
1300 MethodHandle catchException(MethodHandle target, |
1082 MethodHandle combineArguments(MethodHandle target, int pos, MethodHandle combiner) { |
1301 Class<? extends Throwable> exType, |
1083 MethodType mhType = target.type(); |
1302 MethodHandle handler) { |
1084 Class<?> combineType = combiner.type().returnType(); |
1303 MethodType targetType = target.type(); |
1085 MethodType incomingArgs; |
1304 MethodType handlerType = handler.type(); |
1086 if (pos < 0) { |
1305 boolean ok = (targetType.parameterCount() == |
1087 // No inserted argument; target & combiner must have same argument types. |
1306 handlerType.parameterCount() - 1); |
1088 incomingArgs = mhType; |
1307 // for (int i = 0; ok && i < numExArgs; i++) { |
1089 if (!incomingArgs.changeReturnType(combineType).equals(combiner.type())) |
1308 // if (targetType.parameterType(i) != handlerType.parameterType(1+i)) |
1090 throw newIllegalArgumentException("target and combiner types do not match"); |
1309 // ok = false; |
1091 } else { |
1310 // } |
1092 // Inserted argument. |
1311 if (!ok) |
1093 if (pos >= mhType.parameterCount() |
1312 throw newIllegalArgumentException("target and handler types do not match"); |
1094 || mhType.parameterType(pos) != combineType) |
1313 return MethodHandleImpl.makeGuardWithCatch(IMPL_TOKEN, target, exType, handler); |
1095 throw newIllegalArgumentException("inserted combiner argument does not match target"); |
1314 } |
1096 incomingArgs = mhType.dropParameterType(pos); |
1315 |
1097 } |
1316 /** |
1098 if (!incomingArgs.changeReturnType(combineType).equals(combiner.type())) { |
1317 * Produce a method handle which will throw exceptions of the given {@code exType}. |
1099 throw newIllegalArgumentException("target and combiner types do not match"); |
1318 * The method handle will accept a single argument of {@code exType}, |
1100 } |
1319 * and immediately throw it as an exception. |
1101 return MethodHandleImpl.combineArguments(IMPL_TOKEN, target, combiner, pos); |
1320 * The method type will nominally specify a return of {@code returnType}. |
1102 } |
1321 * The return type may be anything convenient: It doesn't matter to the |
1103 |
1322 * method handle's behavior, since it will never return normally. |
|
1323 */ |
|
1324 public static |
|
1325 MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType) { |
|
1326 return MethodHandleImpl.throwException(IMPL_TOKEN, MethodType.methodType(returnType, exType)); |
|
1327 } |
|
1328 |
|
1329 /** Alias for {@link MethodType#methodType}. */ |
|
1330 @Deprecated // "use MethodType.methodType instead" |
|
1331 public static MethodType methodType(Class<?> rtype) { |
|
1332 return MethodType.methodType(rtype); |
|
1333 } |
|
1334 |
|
1335 /** Alias for {@link MethodType#methodType}. */ |
|
1336 @Deprecated // "use MethodType.methodType instead" |
|
1337 public static MethodType methodType(Class<?> rtype, Class<?> ptype) { |
|
1338 return MethodType.methodType(rtype, ptype); |
|
1339 } |
|
1340 |
|
1341 /** Alias for {@link MethodType#methodType}. */ |
|
1342 @Deprecated // "use MethodType.methodType instead" |
|
1343 public static MethodType methodType(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) { |
|
1344 return MethodType.methodType(rtype, ptype0, ptypes); |
|
1345 } |
1104 } |
1346 } |