My understanding is that there is another optimization happening under the hood, identical code folding.
Code for CustObj::methodCall
and CustObj2::methodCall
are very similar and differ only by printed string. JVM compiler is thus able to generate identical code for them:
$ javac tmp.java
$ javap -c -constants 'TestVirtualCall2$CustObj.class'
Compiled from "tmp.java"
class TestVirtualCall2$CustObj {
public void methodCall();
Code:
0: invokestatic #2 // Method java/lang/System.currentTimeMillis:()J
3: lconst_0
4: lcmp
5: ifne 16
8: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
11: ldc #4 // String CustObj is very good!
13: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
16: return
}
$ javap -c -constants 'TestVirtualCall2$CustObj2.class'
Compiled from "tmp.java"
class TestVirtualCall2$CustObj2 extends TestVirtualCall2$CustObj {
public final void methodCall();
Code:
0: invokestatic #2 // Method java/lang/System.currentTimeMillis:()J
3: lconst_0
4: lcmp
5: ifne 16
8: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
11: ldc #4 // String CustObj2 is very good!
13: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
16: return
}
Note that even string loading command ldc #4
happens to be the same because compiler put strings into same locations in respective classes constant pools.
So JIT will definitely generate just one instance of x86 code for both virtual methods.
P.S.
I think this optimization is more of a random side-effect and wasn't the author's intent. It may make sense to ask him to do more changes for code in CustObj2
class in next revision of his article.