JITs can identify and eliminate some conditions which can only be known at runtime. A prime example is the elimination of virtual calls modern VMs use - e.g., when the JVM finds an invokevirtual
or invokeinterface
instruction, if only one class overriding the invoked method has been loaded, the VM can actually make that virtual call static and is thus able to inline it. To a C program, on the other hand, a function pointer is always a function pointer, and a call to it can't be inlined (in the general case, anyway).
Here's a situation where the JVM is able to inline a virtual call:
interface I {
I INSTANCE = Boolean.getBoolean("someCondition")? new A() : new B();
void doIt();
}
class A implements I {
void doIt(){ ... }
}
class B implements I {
void doIt(){ ... }
}
// later...
I.INSTANCE.doIt();
Assuming we don't go around creating A
or B
instances elsewhere and that someCondition
is set to true
, the JVM knows that the call to doIt()
always means A.doIt
, and can therefore avoid the method table lookup, and then inline the call. A similar construct in a non-JITted environment would not be inlinable.