Chris said:
I suspect that the binary compatibility stuff might make it effectively
impossible for most cases. The only opportunities I think would survive would
be calls to private, static, or final, methods in the same class. By "the same
class" I mean the /same/ class ;-) Nested classes, etc, don't count.
In fact, HotSpot does a lot of so called speculative optimizations, and
so do some other JIT compilers. Suppose the HotSpot engine decides to
JIT compile a method BigBar() and detects that a certain method
SmallFoo() is worth inlining into BigBar(), but SmallFoo() is not
declared as final. If SmallFoo() is not overridden in any of the
classes loaded so far, HotSpot will inline it into BigBar() and compile
BigBar() to native code. If at some later point a class overriding
SmallFoo() gets loaded, HotSpot will simply discard the results of
BigBar() compilation and BigBar() will again run on the interpreter.
The "binary compatibility stuff" is basically how the dynamic nature of the JVM
is reflected in the Java language spec. I haven't checked how the spec works
for this question, but since the entire section pretty much amounts to
"remember that classfiles can change between compile time and runtime", I would
guess that other inlining optimisations would be ruled out.
The JVM can optimise a lot harder, because it has /all/ the relevant
information available at any given moment.
Basically, at any moment of time the JVM can make whatever assumptions
and do whatever optimizations that are correct for the set of classes
loaded at that moment, provided it will be able to undo any such
optimization should loading a new class break the respective
assumptions.
I suppose that a Java-like architecture could be defined where the compiler
emitted two sets of bytecode, one generated on the assumption that nothing
significant would change (and the classfile would include a list of what
the exact assumptions were), and the other very conservative in its
assumptions. The JVM could then select which bytecode to use depending on
whether the assumptions turned out to be valid at runtime.
I'd say there is no need for such architecture, the JVMs are already
smart enough.
Static compilers
like Excelsior JET could use similar techniques, and -- for all I know -- maybe
that's what they do...
Excelsior JET uses a somewhat different technique for the above
scenario. Being a static compiler, it cannot undo optimizations, so it
implements a very fast runtime check for inlined non-final methods.
That is, if the instance method supposed to be called at the given
point is indeed the method that was inlined during static compilation,
the inlined copy will be executed, otherwise a virtual call will occur.
LDV
http://www.excelsior-usa.com/jet.html