I am currently looking into how Java bytecode works. I created this simple test class:
class Main {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
With javap -c Main.class
I can get its bytecode:
class Main {
Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #13 // String Hello, World!
5: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
The first instruction that should be executed (according to my understanding) should be the getstatic
instruction in the main
function. This leads to the System
class and others like Console
being loaded.
During the <clinit>
method of Console
:
static {};
Code:
0: ldc #2 // class java/io/Console
2: invokevirtual #203 // Method java/lang/Class.desiredAssertionStatus:()Z
...
a invokevirtual
method is executed to call the desiredAssertionStatus
function on the class Class
. One can already see a difference between this invokevirtual
instruction and the one above: javap
appends the class name before the method name because the function is found in the class Class
and not in Console
.
So finally my question is: What is going on here? According to the JVM 19 specification for invokevirtual
the method should be invoked on the object that was on the stack. In this case Console
but this class doesn't have the requested method nor is it a subclass of Class
. What does the JVM intend to do here/how do JVM implementations like Hotspot go about doing this.
Do they just put the method onto the Console
class for the duration of the instruction or somehow inject the class Class
into Console
or maybe there is something completely different going on here that I am missing?
Anyways thank you for taking your time to read my question!
I hope you have/had a wonderful day :)
I thought about doing the following things:
Adding the method to the
Console
class for the duration of the instruction. This doesn't work because the method requires fields from the classClass
.Actually just calling the method on an instance of
Class
which is created on the fly but I think these seems weird.This might be a very special case because I think that it has something to do with
Console
trying to interact with itsClassLoader
. If this is a special case and there aren't many occurrences of this happening: Maybe the JVM just does some under the hood magic like assigning each class an instance ofClass
after loading which is then used for just this. Also seems weird to me.