Discussion:
Why is "checkcast MethodHandle" necessary in methodHandleInvokeLinkerMethod?
Ioi Lam
2018-04-09 19:49:50 UTC
Permalink
I am looking at the code generated by MethodHandleNatives.linkMethod:

(note the output was edited for brevity)

$ cat HelloMH.java
import java.lang.invoke.*;

public class HelloMH {
    public static void main(String ...args) throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType mt = MethodType.methodType(void.class, float.class);
        MethodHandle mh = lookup.findStatic(HelloMH.class, "callme", mt);
        mh.invokeExact(4.0f);
    }

    private static void callme(float x) {
        System.out.println("Hello MH.invoke: " + x);
        Thread.dumpStack();
    }
}

$ javac HelloMH.java

$ java -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true \
    -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames -cp . HelloMH
[...]
Hello MH.invoke: 4.0
java.lang.Exception: Stack trace
    at java.base/java.lang.Thread.dumpStack(Thread.java:1434)
    at HelloMH.callme(HelloMH.java:13)
    at java.base/java.lang.invoke.LambdaForm$DM.invokeStatic_LF_V()
    at java.base/java.lang.invoke.LambdaForm$MH.invokeExact_MT_LFL_V()
    at HelloMH.main(HelloMH.java:8)


$ javap -c 'DUMP_CLASS_FILES/java/lang/invoke/LambdaForm$MH.class'
final class java.lang.invoke.LambdaForm$MH {
  static void invokeExact_MT000_LFL_V(java.lang.Object, float,
java.lang.Object);
    Code:
       0: aload_0
       1: checkcast     #14    // class java/lang/invoke/MethodHandle
       4: dup
       ...


Why is the checkcast necessary here?

I thought the verifier would ensure that local#0 must of type MethodHandle.

Is this checkcast needed only for reflective invocation of
MethodHandle.invokeExact()?

Thanks
- Ioi
Attila Szegedi
2018-04-09 20:00:46 UTC
Permalink
invokeExact_MT000_LFL_V is a static method and its first declared argument type is java.lang.Object, not MethodHandle. So aload_0 will load a reference with static type of Object, hence making a checkcast necessary to cast it to a MethodHandle.

HTH,
Attila.
Post by Ioi Lam
(note the output was edited for brevity)
$ cat HelloMH.java
import java.lang.invoke.*;
public class HelloMH {
public static void main(String ...args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType mt = MethodType.methodType(void.class, float.class);
MethodHandle mh = lookup.findStatic(HelloMH.class, "callme", mt);
mh.invokeExact(4.0f);
}
private static void callme(float x) {
System.out.println("Hello MH.invoke: " + x);
Thread.dumpStack();
}
}
$ javac HelloMH.java
$ java -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true \
-XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames -cp . HelloMH
[...]
Hello MH.invoke: 4.0
java.lang.Exception: Stack trace
at java.base/java.lang.Thread.dumpStack(Thread.java:1434)
at HelloMH.callme(HelloMH.java:13)
at java.base/java.lang.invoke.LambdaForm$DM.invokeStatic_LF_V()
at java.base/java.lang.invoke.LambdaForm$MH.invokeExact_MT_LFL_V()
at HelloMH.main(HelloMH.java:8)
$ javap -c 'DUMP_CLASS_FILES/java/lang/invoke/LambdaForm$MH.class'
final class java.lang.invoke.LambdaForm$MH {
static void invokeExact_MT000_LFL_V(java.lang.Object, float, java.lang.Object);
0: aload_0
1: checkcast #14 // class java/lang/invoke/MethodHandle
4: dup
...
Why is the checkcast necessary here?
I thought the verifier would ensure that local#0 must of type MethodHandle.
Is this checkcast needed only for reflective invocation of MethodHandle.invokeExact()?
Thanks
- Ioi
_______________________________________________
mlvm-dev mailing list
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
Ioi Lam
2018-04-09 20:17:12 UTC
Permalink
So why is this first argument not declared as a MethodHandle?

Thanks

- Ioi
Post by Attila Szegedi
invokeExact_MT000_LFL_V is a static method and its first declared argument type is java.lang.Object, not MethodHandle. So aload_0 will load a reference with static type of Object, hence making a checkcast necessary to cast it to a MethodHandle.
HTH,
Attila.
Post by Ioi Lam
(note the output was edited for brevity)
$ cat HelloMH.java
import java.lang.invoke.*;
public class HelloMH {
public static void main(String ...args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType mt = MethodType.methodType(void.class, float.class);
MethodHandle mh = lookup.findStatic(HelloMH.class, "callme", mt);
mh.invokeExact(4.0f);
}
private static void callme(float x) {
System.out.println("Hello MH.invoke: " + x);
Thread.dumpStack();
}
}
$ javac HelloMH.java
$ java -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true \
-XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames -cp . HelloMH
[...]
Hello MH.invoke: 4.0
java.lang.Exception: Stack trace
at java.base/java.lang.Thread.dumpStack(Thread.java:1434)
at HelloMH.callme(HelloMH.java:13)
at java.base/java.lang.invoke.LambdaForm$DM.invokeStatic_LF_V()
at java.base/java.lang.invoke.LambdaForm$MH.invokeExact_MT_LFL_V()
at HelloMH.main(HelloMH.java:8)
$ javap -c 'DUMP_CLASS_FILES/java/lang/invoke/LambdaForm$MH.class'
final class java.lang.invoke.LambdaForm$MH {
static void invokeExact_MT000_LFL_V(java.lang.Object, float, java.lang.Object);
0: aload_0
1: checkcast #14 // class java/lang/invoke/MethodHandle
4: dup
...
Why is the checkcast necessary here?
I thought the verifier would ensure that local#0 must of type MethodHandle.
Is this checkcast needed only for reflective invocation of MethodHandle.invokeExact()?
Thanks
- Ioi
_______________________________________________
mlvm-dev mailing list
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
_______________________________________________
mlvm-dev mailing list
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
John Rose
2018-04-09 20:32:25 UTC
Permalink
Post by Ioi Lam
So why is this first argument not declared as a MethodHandle?
The short answer is to simplify the plumbing of lambda forms.

Method handles are strongly typed but the underlying IR of
lambda forms is weakly typed. This keeps the IR simple.
To make up the difference, casts are inserted where necessary.
Most (not all) uses of MHs are inlined and/or customized,
in which case the JIT simply drops the casts.

— John
Ioi Lam
2018-04-09 21:06:43 UTC
Permalink
Hi John,

That was my suspicion and thanks for confirming it.

I wrote a simple benchmark to try to compare the speed of a 'real'
method invocation vs MH.invokeExact

http://cr.openjdk.java.net/~iklam/misc/method_handle_bench/BenchMH.java

Basically

    private static void loopMH(int loops, MethodHandle mh) throws
Throwable {
        for (int i=0; i<loops; i++) {
            mh.invokeExact("yo!");
        }
    }

   -vs-


    private static void loopDirect(int loops) {
        for (int i=0; i<loops; i++) {
            callme("yo!");
        }
    }

$ java -cp . BenchMH 1000000000
...
MH:      loops = 1000000000: elapsed = 10332 ms
direct:  loops = 1000000000: elapsed = 7500 ms

So it seems like the JIT still can't handle such a simple case ... :-(
Post by John Rose
Post by Ioi Lam
So why is this first argument not declared as a MethodHandle?
The short answer is to simplify the plumbing of lambda forms.
Method handles are strongly typed but the underlying IR of
lambda forms is weakly typed.  This keeps the IR simple.
To make up the difference, casts are inserted where necessary.
Most (not all) uses of MHs are inlined and/or customized,
in which case the JIT simply drops the casts.
— John
_______________________________________________ mlvm-dev mailing list
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
Paul Sandoz
2018-04-09 21:10:42 UTC
Permalink
Place the MH in a static final, then the JIT can constant fold.

You might find the following helpful:

https://wiki.openjdk.java.net/display/HotSpot/Method+handles+and+invokedynamic <https://wiki.openjdk.java.net/display/HotSpot/Method+handles+and+invokedynamic>
https://wiki.openjdk.java.net/display/HotSpot/Deconstructing+MethodHandles <https://wiki.openjdk.java.net/display/HotSpot/Deconstructing+MethodHandles>

Paul.
Post by Ioi Lam
Hi John,
That was my suspicion and thanks for confirming it.
I wrote a simple benchmark to try to compare the speed of a 'real' method invocation vs MH.invokeExact
http://cr.openjdk.java.net/~iklam/misc/method_handle_bench/BenchMH.java <http://cr.openjdk.java.net/~iklam/misc/method_handle_bench/BenchMH.java>
Basically
private static void loopMH(int loops, MethodHandle mh) throws Throwable {
for (int i=0; i<loops; i++) {
mh.invokeExact("yo!");
}
}
-vs-
private static void loopDirect(int loops) {
for (int i=0; i<loops; i++) {
callme("yo!");
}
}
$ java -cp . BenchMH 1000000000
...
MH: loops = 1000000000: elapsed = 10332 ms
direct: loops = 1000000000: elapsed = 7500 ms
So it seems like the JIT still can't handle such a simple case ... :-(
Post by John Rose
Post by Ioi Lam
So why is this first argument not declared as a MethodHandle?
The short answer is to simplify the plumbing of lambda forms.
Method handles are strongly typed but the underlying IR of
lambda forms is weakly typed. This keeps the IR simple.
To make up the difference, casts are inserted where necessary.
Most (not all) uses of MHs are inlined and/or customized,
in which case the JIT simply drops the casts.
— John
_______________________________________________
mlvm-dev mailing list
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
Loading...