Question about MethodHandles#explicitCastArgument

John Rose john.r.rose at oracle.com
Thu Nov 15 15:32:37 PST 2012


[Repost, moving from jvm-l list.]

On Nov 14, 2012, at 6:16 AM, Jochen Theodorou wrote:

> I have a call to MethodHandles#explicitCastArgument with first argument being my MethodHandle(Groovy3135Bug,String,float,float,float,float,float)Object and the type I cast to being (Groovy3135Bug,String,Byte,Short,Integer,Long,Float)Object
> 
> Ignoring the first two I should have some kind of unboxing followed by casting for most arguments. In the javadoc to that method I read:
> """
> If T0 is a reference and T1 a primitive, an unboxing conversion will be applied at runtime, possibly followed by a Java casting conversion (JLS 5.5) on the primitive value, possibly followed by a conversion from byte to boolean by testing the low-order bit.
> """
> 
> Aren't T0 and T1 in my case for example T0=Byte and T1=float? Unless I mix up T0 and T1, this should be working, or not?

Yes, you are reading it right.  When the call to the MH eventually happens, the actual argument of type T0=java.lang.Byte will be explicitly cast to the required argument type T1=float.

> Well... it fails with a NPE... that can't be right, can it?

It can be right, but only if the actual argument is a null reference.  If it is a non-null Byte, it must unbox to a byte and then widen to a float.

Here's the relevant doc from MethodHandle#asType:
> An unboxing operation may fail because the original reference is null,
> causing a {@link java.lang.NullPointerException NullPointerException}.
> An unboxing operation or a reference cast may also fail on a reference
> to an object of the wrong type,
> causing a {@link java.lang.ClassCastException ClassCastException}.

What you are seeing is a bug.  I can reproduce this in JDK 7 but not in JDK 8.  The upcoming JDK 7 update will fix this, since it is a backport from 8.

> If I first cast to an all-Object signature, and then to the target, then it works... but that can't be how it should be, or not?

The difference between Object and Byte in that context is that the Object must be a wrapper object of any sort, whereas Byte is only a wrapped byte.  In the first case a CCE is possible.  In both cases an NPE is possible.  The second case is probably more efficient, since the JVM doesn't need to test for multiple wrapper types.

Thanks for the report.

— John

— John

P.S.  Here's my test:

import java.lang.invoke.*;
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;

public class ByteBug {
    public static void main(String... av) throws Throwable {
        MethodHandle id_f = identity(float.class);
        System.out.println((float)id_f.invokeExact((float)42.1));
        MethodHandle id_O = id_f.asType(methodType(Object.class, Object.class));
        System.out.println(id_O.invokeExact((Object)(float)42.2));
        System.out.println(id_O.invokeExact((Object)(long)43));
        System.out.println(id_O.invokeExact((Object)(byte)44));
        try {
            System.out.println(id_O.invokeExact((Object)(double)42.99)); //CCE Double=>Float
            throw new AssertionError("notreached");
        } catch (ClassCastException ex) {
            ex.printStackTrace();
        }
        MethodHandle id_b = id_f.asType(methodType(Object.class, byte.class));
        System.out.println(id_b.invokeExact((byte)45));
        MethodHandle id_B = id_f.asType(methodType(Object.class, Byte.class));
        System.out.println(id_B.invokeExact((Byte)(byte)46));
    }
}
/* output:
42.1
42.2
43.0
44.0
java.lang.ClassCastException: Cannot cast java.lang.Double to java.lang.Float
	at java.lang.Class.cast(Class.java:3007)
	at sun.invoke.util.ValueConversions.primitiveConversion(ValueConversions.java:203)
	at sun.invoke.util.ValueConversions.unboxFloat(ValueConversions.java:112)
	at ByteBug.main(ByteBug.java:14)
45.0
46.0
 */

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/mlvm-dev/attachments/20121115/a7370c55/attachment.html 


More information about the mlvm-dev mailing list