Sergey Morozov
Sergey Morozov

Reputation: 4628

Why checkcast-instruction is absent for (int)MethodHandle.invokeExact?

I have created 2 simple classes for try Java MethodHandle-API:

public class Foo {
    private static int staticField;

    public static Object getStaticField() {
        return staticField;
    }
}

another class for invoke method Foo.getStaticField() in two ways - direct and using MethodHandle-API:

....
public static void methodHandleGetStaticField() throws Throwable {
    MethodHandle methodHandle = lookup.findStatic(Foo.class, "getStaticField", MethodType.methodType(int.class));
    int i = (int)methodHandle.invokeExact();
}

public static void directGetStaticField() {
    int i = (int)Foo.getStaticField();
}
....

I have decompiled class and saw that directGetStaticField method contains cast instructiona, but method methodHandleGetStaticField doesn't, though java.lang.invoke.MethodHandle.invokeExact() returns java.lang.Object.

public static void directGetStaticField();
descriptor: ()V
Code:
   0: invokestatic  #70    // Method ru/fj/methodhandle/Foo.getStaticField:()Ljava/lang/Object;
   3: checkcast     #33    // class java/lang/Integer
   6: invokevirtual #74    // Method java/lang/Integer.intValue:()I
   9: istore_0
  10: return

public static void methodHandleGetStaticField() throws java.lang.Throwable;
descriptor: ()V
Code:
   0: getstatic     #15    // Field lookup:Ljava/lang/invoke/MethodHandles$Lookup;
   3: ldc           #29    // class ru/fj/methodhandle/Foo
   5: ldc           #90    // String getStaticField
   7: getstatic     #32    // Field java/lang/Integer.TYPE:Ljava/lang/Class;
  10: invokestatic  #38    // Method java/lang/invoke/MethodType.methodType:(Ljava/lang/Class;)Ljava/lang/invoke/MethodType;
  13: invokevirtual #46    // Method java/lang/invoke/MethodHandles$Lookup.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;
  16: astore_0
  17: aload_0
  18: invokevirtual #52    // Method java/lang/invoke/MethodHandle.invokeExact:()I
  21: istore_1
  22: return

Could anyone explain it for me?

Upvotes: 1

Views: 212

Answers (1)

dejvuth
dejvuth

Reputation: 7146

You can notice that invokeExact indeed returns an int from its descriptor ()I:

  18: invokevirtual #52    // Method java/lang/invoke/MethodHandle.invokeExact:()I

As a result, no casting is required.

The reason why it returns an int, not an Object, is that method invokeExact (as well as invoke) in MethodHandle are treated specially, see the invokeExact API

Returns:

the signature-polymorphic result, statically represented using Object

and from the signature polymorphism:

... The unusual part is that the symbolic type descriptor is derived from the actual argument and return types, not from the method declaration.

Upvotes: 3

Related Questions