Is bytecode invokeinterface correct when resolved method from Object?

Liu, Xin xxinliu at amazon.com
Wed Dec 1 10:17:26 UTC 2021


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/c6fd1c3b/OpenPGP_0xB9D934C61E047B0D.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/c6fd1c3b/OpenPGP_signature.bin>


More information about the compiler-dev mailing list