Is bytecode invokeinterface correct when resolved method from Object?

Liu, Xin xxinliu at amazon.com
Wed Dec 1 19:04:18 UTC 2021


hi, Alex,

Thanks for the explanation! Indeed, JVMS and JLS are aligned and they
cover Object's methods in the interface. I also understand why
InvokeInterfaceTest::bar() can't compile in my example.

thanks,
--lx



On 12/1/21 2:17 AM, Liu, Xin wrote:
> Hello,
> 
> In Java programming language, I think it's legal to invoke
> java.lang.Object's methods via any interface. All classes must be the
> subclass of j.l.Object. Here is my example. Even though the interface
> 'I' doesn't have the symbol getClass, it will certainly resolve it in
> runtime.
> 
> 
> public class InvokeInterfaceTest {
>     interface I {}
>     static class Base {
>         public static int bar() {
>             return 0;
>         }
>     }
>     static class C extends Base implements I {};
> 
>     public static boolean foo(I o) {
>         return o.getClass() == C.class;
>     }
> 
>     // javac compiler-error
>     //public static int bar(I o) {
>     //    return o.bar();
>     //}
> 
>     public static void main(String args[]) {
>         I o = new C();
>         foo(o);
>     }
> }
> 
> 
> For InvokeInterfaceTest::foo(I o), I didn't make it up. I have seen the
> code like this in ArrayList.
> https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/ArrayList.java#L183
> 
> Until jdk17, javac generates 'invokevirtual' in InvokeInterfaceTest::foo.
> 
>   public static boolean foo(InvokeInterfaceTest$I);
>     Code:
>        0: aload_0
>        1: invokevirtual #7                  // Method
> java/lang/Object.getClass:()Ljava/lang/Class;
>        4: ldc           #11                 // class InvokeInterfaceTest$C
>        6: if_acmpne     13
>        9: iconst_1
>       10: goto          14
>       13: iconst_0
>       14: ireturn
> 
> 
> The tip of JDK now replaces 'invokevirtual' with invokeinterface, as
> follows.
> 
>   public static boolean foo(InvokeInterfaceTest$I);
>     Code:
>        0: aload_0
>        1: invokeinterface #7,  1            // InterfaceMethod
> InvokeInterfaceTest$I.getClass:()Ljava/lang/Class;
>        6: ldc           #13                 // class InvokeInterfaceTest$C
> ...
> 
> 
> Not only each call takes 2 more bytes, I feel it doesn't comply with JVM
> spec. JVMS says that 'invokeinterface' resolves an 'interface method'.
> j.l.Object.getClass() is not an interface method, is it?
> https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.invokeinterface
> 
> Is it an intentional change of javac? My concern is that this ambiguity
> makes HotSpot more complex. Further, if it does violate JVMS, it will
> make javac implementation-dependent.
> 
> thanks,
> --lx
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_0xB9D934C61E047B0D.asc
Type: application/pgp-keys
Size: 3674 bytes
Desc: OpenPGP public key
URL: <https://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20211201/b65dc25e/OpenPGP_0xB9D934C61E047B0D-0001.asc>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature
Type: application/pgp-signature
Size: 665 bytes
Desc: OpenPGP digital signature
URL: <https://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20211201/b65dc25e/OpenPGP_signature-0001.bin>


More information about the compiler-dev mailing list