I was looking into the disassembly of the following java program
public class ASMPlayground {
private String bar;
public String getBar(){
return bar;
}
public void setBar(String bar) throws IllegalAccessException, InstantiationException {
String name = String.class.newInstance();
System.out.println(name);
}
public static void main(String[] args) {
}
}
The following bytecode snippet caught my eye and seemed sub-optimal
LDC Ljava/lang/String;.class
INVOKEVIRTUAL java/lang/Class.newInstance ()Ljava/lang/Object;
CHECKCAST java/lang/String
Question:
InvokeVirtual is used when the method to be executed is dependent on the object reference. Given that "Class" is final and newInstance() exists only in the "Class" why not use InvokeSpecial instead of InvokeVirtual ? Wouldn't it be more performant?
InvokeSpecial
is used to designate invocations that are
superclass, private, and instance initialization method invocations
Spec: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokespecial
Class.newInstance
is neither superclass method call nor private method call nor call to initialization method. It also isn't a dynamic method, InvokeDynamic
has nothing to do here. Both instructions cannot be used here because it would confront jvms. At the time of creating jvms it was possible to allow substitute of some instructions with "more performant" ones, but as I see in jvms it hasn't been done.
Wouldn't it be more performant?
JIT is smart enough to understand that there's no need to traverse virtual method table in such cases, so it shouldn't slow execution down. Actual performance should be compared by actual tests, but I see no reasons to expect significant difference there.
The fact that a target method or class is final
does never change the compiled form a class using the other class/calling the method.
This is mandated by the JLS, Chapter 13. “Binary Compatibility”, §13.4.17, final
methods :
Changing a method that is declared
final
to no longer be declaredfinal
does not break compatibility with pre-existing binaries.
Likewise §13.4.2. final
Classes
Changing a class that is declared
final
to no longer be declaredfinal
does not break compatibility with pre-existing binaries.
Obviously, an invocation instruction relying on the target method's final
nature would violate this specification.
There is no relevant performance impact to expect. There is always a first time overhead, when the symbolic reference has to be resolved to the actual method (in terms of the JVM's runtime representation). Right at this point, the JVM can also record the fact that this method or its declaring class is actually final
to the invocation instruction, if there is a benefit. Modern JVMs go even farther and, eg utilize the fact that a non- final
method has not been actually overridden to the same effect, though these invocations would need to be deoptimized if a subclass gets loaded and instantiated, which has an overriding method. So the only difference is that a final
modifier guarantees that such deoptimization will never be necessary.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.