1

How does method/field visibility impact on method inlining in Java?

The case I have in mind is something like a public getter for a private field:

private Thing blah;

public Thing getBlah() {
    return blah;
}

There are several issues that arise here.

For one, does the Java compiler itself do any inlining? This question seems to be answered variously, with some saying yes and some saying no. I don't know whether that's because it used not to do any inlining but now does, or whether it's just that some people are right and some people are wrong...

Now, if it does do some inlining, am I right in thinking that it can't possibly inline getBlah() calls? They would be an obvious place for inlining to be useful, because the method is very simple, and the overhead of invoking a method is as big as the code for the method itself. But if it got inlined by the compiler, you'd end up with bytecode that accessed a private field directly; and surely the JVM would then complain? (This would apply even if this method were static final.)

Secondly, what about the JIT compiler? As far as I can see, this problem doesn't apply when it comes to inlining at that level. Once it's producing native code, the JVM has already done its checks, and confirmed that I can invoke the method (because it's public); so it can then generate native code that inlines the call, without any visibility issues... yes?

Community
  • 1
  • 1
chiastic-security
  • 20,430
  • 4
  • 39
  • 67

3 Answers3

1
  1. javac does not inline methods, even as simple as getBlah() and setBlah()
  2. As to HotSpot JVM, JIT compiler does inline all such methods unless it reaches the maximum level of inlining (-XX:MaxInlineLevel)
  3. JIT equally treats public and private methods in terms of inlining. Access modifiers does not generally affect inlining unless some very specific cases.
Community
  • 1
  • 1
apangin
  • 92,924
  • 10
  • 193
  • 247
1

The javac compiler (and any valid java compiler) will not and can not inline getters; think about it: You could extend a class from that class and overwrite the getter. And yes if a compiler would overzealously inline that access it would not pass the verifier (well at least it should not pass the verifier, but they don't verify everything - in java 1.3 you could even make main() private and it would still work... likewise there used to be an -O option in javac that did sometimes screw your code).

The JIT is a whole other beast; it knows (well at least nowadays) at any time if there is an overwite for a method or not. Even if a class is later loaded that overwrites the getter, it can deoptimize already JIT'd methods to refelect alterations on the inhertance tree (thats one of the optimizations AOT compilers lack the information for).

Thus it can safely inline whatever it wants. It also doesn't need to artificially uphold access modfiers, because there is no such thing in the compiled machine code and again it knows what is a vaild code transformatiom (and since getters are so common its also a low hanging fruit for the JIT to optimize).

Edit: To make it absolutely clear, above paragraphs address potentially virtual methods; specifically those that are not private, static or final. Javac could perform inlining in some cases; because it could prove that no override can exist for those. It would be a pointless undertaking in face of the fact that the JIT also does it, and it does a far better job at it.

Durandal
  • 19,919
  • 4
  • 36
  • 70
  • I believe you that javac doesn't inline. Perhaps there's no point anyway, if the JIT can do it later on. But I'm not sure I see that it couldn't be done in principle. Certainly with a `final` method there is no scope for overwriting it in a subclass; but more to the point, a method doesn't need to be either *always* inlined or *never* inlined. The compiler could see that *in this specific context* the method hasn't been overridden, and inline it for this invocation... couldn't it? It doesn't need to be all or nothing. – chiastic-security Oct 02 '14 at 10:50
  • Its not all or nothing, your conclusions are completely technically reasonable. If the method is clearly non-virtual (private, final or static) it *could* already be inlined by the compiler. I am talking about the bukl case (the OP specifically asked about getters and cousins), I though that would be clear enough from the context. So while a few opportunities exist for javac's scope; the bulk can still only be done by the JIT. Now when we already *have* a JIT that does it, why would one *duplicate* that effort in javac? – Durandal Oct 02 '14 at 13:32
0

Whether or not any particular Java compiler -- Oracle's, for instance -- performs any inlining is an implementation detail that you would be better off ignoring. A future generation of your chosen compiler or an alternative compiler might operate differently than the one you happen to be looking at now.

To the extent that a Java compiler did perform inlining, however, it could inline only private methods and constructors. Anything else is a candidate for access from (unknowable) other classes.

A JIT compiler, on the other hand, can do pretty much anything it wants, including inlining public methods. It is responsible for any adjustments that may be needed when new classes are loaded. Beans-style accessor methods are a particularly likely thing for a JIT to optimize, they being such a common pattern.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • The java compiler *can* not inline (getters) by definition; it would break unfixably the moment the method is overwritten by a child class. – Durandal Oct 01 '14 at 17:53
  • I don't see why a Java compiler shouldn't *selectively* inline final public methods. It can't mark a public method as *always* to be inlined, but it could inline it where appropriate. And if it's final then it can't be overridden. – chiastic-security Oct 01 '14 at 17:57
  • Note the little "getter" in brackets. A *private* getter is pretty rare, and getters are usually also not final. – Durandal Oct 02 '14 at 13:47