Question: What does line 14 means?
Use javap -v -c to disassembly the following code:
public class test {
static int i = 2;
public static void main(String[] args) {
test x = new test();
System.out.println("text + String: " + i);
}
}
in the main function we get the following:
14: invokedynamic #20, 0 // InvokeDynamic #0:makeConcatWithConstants:(I)Ljava/lang/String;
19: invokevirtual #24 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
...
BootstrapMethods:
0: #38 REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
Method arguments:
#44 text + String: \u0001
So, for example, line 19 means that invokevirtual function from the #24 item in the runtime constant pool. The method invoked is println()
from the class java/io/PrintStream
, its input is from the class Ljava/lang/String
, its return value is Void.
As for line 14, #0 holds the reference to the BootstrapMethod and returns an Object whose class is CallSite
right?
Then:
#0:makeConcatWithConstants:(I)Ljava/lang/String;
means?Also, where could I find more about the Javap disassembly code's grammar? or what is the right keyword? Oracle's document about the JVM instruction set
does not seems to describe clearly about the meaning of the comment.
The short version: Java uses invokedynamic to concatenate strings since Java 9.
Let's break this down a bit:
Invokedynamic has two steps:
The CallSite is just a holder for that MethodHandle. Depending on the CallSite
subclass used the site might be later relinked.
If we look at the instruction, we see the following at the end:
#0:makeConcatWithConstants:(I)Ljava/lang/String;
The first part (#0
) means: Bootstrap method #0.
The second part is the name - which is passed to the bootstrap method and may or may not be used there.
The third part is the method type of the resulting target. In our case: A method that takes an int
and returns a java.lang.String
.
If we now take a look at the bootstrap method #0 we see a method reference, here to StringConcatFactory.makeConcatWithConstants(...).
We also see that there is an additional argument: The String "text + String: \u0001"
.
The job of the bootstrap method is now to return a MethodHandle (inside a CallSite) which does in this case this string concatenation. But how it does the string concatenation (StringBuilder, String.format, bytecode spinning, chaining MethodHandles...) does not matter for the actual class. It only wants to have Strings concatenated.
Let's try to emulate that behavior by hand. After all, the bootstrap method is an ordinary Java method:
public static void main(String[] args) throws Throwable {
CallSite cs = StringConcatFactory.makeConcatWithConstants(MethodHandles.lookup(),
"makeConcatWithConstants", MethodType.methodType(String.class, int.class),
"text + String: \u0001");
int x = 2;
String result = (String) cs.dynamicInvoker().invokeExact(x);
System.out.println(result);
x = 3;
result = (String) cs.dynamicInvoker().invokeExact(x);
System.out.println(result);
}
(The VM does some more stuff, like it remembers the result and would not call the bootstrap method again, but for our small example this is good enough).
At this point we can take a look under the hood on how the bootstrap method does it's job.
It turns out: You can configure the VM to use different strategies.
And it uses it's privileged position inside java.base
to access a package private constructor for java.lang.String that doesn't copying the array - which is safe if the contents is not modified afterwards.
The default strategy is MethodHandle chaining.
The good news is: If someone writes at some point a better strategy, your program will benefit from it - without recompilation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With