I am currently writing an application that creates Java byte code and also writes method calls. Until now, the module writing this byte code does not have information on the actual type of the instance a method call is invoked on but it does know the type for which a particular method was defined for. For example:
class Foo {
public void foo() { }
}
class Bar extends Foo {
public void bar() { }
}
the current version of the engine would execute
INVOKEVIRTUAL Foo.foo
even on objects of type Bar
because it knows that foo
was defined in Foo
. This is legal in the JVM (of course) but the Java compiler would translate it to
INVOKEVIRTUAL Bar.foo
when it was "normal" Java source code. I am currently wondering if the JVM actually uses the information of the explicit subtype or if this is ignored / optimized when the class is loaded. I was wondering since the verifier is figuring out the actual type anyways and will not let me write illegal method calls and I wonder why the runtime would not make use of this information when it already is available. I am in particularly wondering if it has a performance impact when super types are interfaces (INVOKEINTERFACE
) where the virtual method table cannot be used if the JVM would not figure out the actual type.
I can of course extend my module but I would need to provide additional information to it which would bloat my code and which I do not want to do if it did not have an effect. So I ask: Does the type effect performance or does the JVM take care of this explicit resolution?
None of the distinctions in the bytecode will matter much for performance of JIT-compiled code.
HotSpot will routinely keep a type profile for each invokevirtual
call site. If the record indicates only one type being dispatched on, the JIT compiler will treat it as an invokespecial
call, basically a direct jump to the callee, or even inlining of the callee.
The above describes the optimization of the hardest case, a fully general virtual method. HotSpot also knows which methods are effectively final: in the set of loaded classes there is no occurrence of an override for that method. In that case HotSpot proceeds similar to above, but with a few instructions omitted (those which perform the type assertion).
I have additionally put some effort into hacking the .class file such that an invokevirtual
instruction was replaced by invokespecial
. The result was a VerifyError
:
Exception in thread "main" java.lang.VerifyError:
Bad invokespecial instruction: current class isn't assignable to reference class.
You can use invokespecial
only for methods of the current class or its ancestor, and this is in fact specified by the Java Virtual Machine Specification, §4.9.2:
Each
invokespecial
instruction must name an instance initialization method (§2.9), a method in the current class, or a method in a superclass of the current class.
invokeinterface
is known to be slower than invokevirtual
/invokestatic
, especially when it comes to so-called "megamorphic calls": where a method has very many implementations, and the JIT-compiler has no way to optimize. So it's wise to prefer invokevirtual
to invokeinterface
. And the more specific the type you mention the more probably the optimistic optimizations (we consider this method final until a class that overrides it is loaded) will work.
Some more information is available here: http://java.dzone.com/articles/invoke-interface-optimisations
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