On May 15, 2011, at 9:40 AM, Raffaello Giulietti wrote:

> I would expect a WrongMethodTypeException to be thrown by
> convertArguments in the following snippet, on the ground that String
> is neither a wrapper nor a supertype of a wrapper of int, the return
> type of mh0.
> 
>        MethodHandle mh0 = lookup.findVirtual(String.class, "length",
> MethodType.methodType(int.class));
>        MethodHandle mh1 = MethodHandles.convertArguments(mh0,
> MethodType.methodType(String.class, String.class));
> 
> However, build 142 of the JDK 7 (2011-05-12) executes the code without
> errors. Is this expected behavior?

This should throw WMT.

But, a chained conversion from (String)int to (String)Object to (String)Number 
must succeed, producing a method handle that is doomed to throw CCE.

This should be fixed in build 144.

(Note:  convertArguments is being removed, since asType does the same job.  To 
factor out the effect of variable-arity method handles on asType, there will be 
MH.asFixedArity, so that convertArgs(x,y) := x.asFixedArity().asType(y).)

The reverse case, of reference to primitive, is a curious question.  Suppose we 
have:

       MethodHandle mh0 = lookup.findVirtual(Integer.class, "toString",
           methodType(String.class))
           .asType(methodType(String.class, int.class));
       // mh0(int x) := ((Integer)x).toString()
       MethodHandle mh1 = mh0.asType(
           methodType(String.class, String.class));

Here is another case where there is no hope of this conversion succeeding, and 
so asType should throw WMT instead of creating mh1.

But this one must work, obviously:

       MethodHandle mh2 = mh0.asType(methodType(String.class, Integer.class));

More interestingly, this also works:

       MethodHandle mh3 = mh0.asType(methodType(String.class, Object.class));

The semantics of Object->int unboxing is based on 
java.lang.reflect.Method.invoke.  This means that the unboxing can happen from 
any of the types Byte, Short, Character, or Integer:

       MethodHandle mh4 = mh0.asType(methodType(String.class, Byte.class));
       MethodHandle mh5 = mh0.asType(methodType(String.class, Character.class));

But this one needs to fail with WMT, since there is no way to unbox and widen 
to get an int:
       MethodHandle mh6 = mh0.asType(methodType(String.class, Long.class));

Looking back at mh3, we realize that it can fail dynamically in a similar way, 
if passed a value which is not a boxed byte, char, short, or int:
       mh3.invoke(42);  // OK: int -> Integer -> Object -> Integer -> int
       mh3.invoke((byte)4);  // OK: byte -> Byte -> Object -> Byte -> byte -> 
int
       mh3.invoke(0x420000000L);  // FAIL: long -> Long -> Object -> Integer CCE
       mh3.invoke("asdf");  // FAIL: String -> Object -> Integer CCE

These rules for asType arise from a mix of concerns:
 - the normal Java method invocation conversions (JLS 5.3) must be supported, 
at a minimum
 - when the target is a reference type, Java casting conversion (JLS 5.5) must 
be supported also
 - when the target is a primitive type, the conversions supplied by 
java.lang.reflect must be supported also

The union of these rules preserves some important general symmetries:
 - Object is always a universal source and destination type
 - every possible retyping of references is allowed (subject to runtime type 
checks)
 - wrapper types can be freely interconverted with their corresponding 
primitive types
 - primitives will never be narrowed (truncated, discarding sign or magnitude 
bits)

-- John

_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

Reply via email to