can moderm JVMs optimize different instances of the same class differently?
Asked Answered
S

2

8

say I have 2 instances of the same class, but they behave differently (follow different code paths) based on a final boolean field set at construction time. so something like:

public class Foo {
   private final boolean flag;

   public Foo(boolean flagValue) {
      this.flag = flagValue;
   }

   public void f() {
      if (flag) {
         doSomething();
      } else {
         doSomethingElse();
      }
   }
}

2 instances of Foo with different values for flag could in theory be backed by 2 different assemblies, thereby eliminating the cost of the if (sorry for the contrived example, its the simplest one I could come up with).

so my question is - do any JVMs actually do this? or is a single class always backed by a single assembly?

Sinew answered 8/11, 2016 at 18:22 Comment(5)
What you're describing sounds an awful lot like subclassing, can you clarify why that won't work? I'm not challenging just trying to understand the boundaries of the problem.Bersagliere
All instances share the same code. Your question doesn't make sense.Delegacy
@Bersagliere Excuse me if I dare to interpret the OP, but I guess that what he/she is asking is not a proper pattern (which would be obviously inheritance), but if JVMs are "intelligent" enough to remove the use of the flag variable and produce two different bytecodes for the whole class (one corresponding to the true branches, and the other for the false ones).Ectype
@LittleSanti - exactly. thank you.Sinew
Appreciate the interpretation, @LittleSanti. I would say, to answer that question, that I doubt it, and am not aware of any doing that, as the primary mechanism for this would be inheritance. That being said there are more jvm impl's than one can shake a stick at, so it's possible.Bersagliere
J
7

Yes, JVMs do this form of optimization. In your case, this would be a result of inlining and adaptive optimization for being a value to always be true. Consider the following code:

Foo foo = new Foo(true);
foo.f();

It is trivial to prove for HotSpot that Foo is always an actual instance of Foo at the call site of f what allows the VM to simply copy-paste the code of the method, thus eliminating the virtual dispatch. After inlining, the example is reduced to:

Foo foo = new Foo(true);
if (foo.flag) {
  doSomething();
} else {
  doSomethingElse();
}

This again, allows to reduce the code to:

Foo foo = new Foo(true);
foo.doSomething();

If the optimization can be applied does therefore depend on the monomorphism of the call site of foo and the stability of flag at this call site. (The VM profiles your methods for such patterns.) The less the VM is able to predict the outcome of your program, the less optimization is applied.

If the example was so trivial as the above code, the JIT would probably also erase the object allocation and simply call doSomething. Also, for the trivial example case where the value of the field can be proven to be true trivially, the VM does not even need to optimize adaptively but simply applies the above optimization. There is a great tool named JITWatch that allows you to look into how your code gets optimized.

Jaffa answered 9/11, 2016 at 9:14 Comment(3)
In this specific case, the JVM can even produce the result by static analysis without profiling data. It would become more intuitive by also showing the result of inlining the constructor’s code, as the result basically is foo.flag=true; if(foo.flag) … which doesn’t even require flag to be final to get optimized. Depending of the follow-up code, it won’t even create the Foo instance for this specific code path.Syreetasyria
What about when the flag value can't be known statically (e.g., it's loaded from a file or the network)? Is there any path for this kind of optimization to still happen?Cacomistle
Yes, the JVM optimizes code at runtime when this value is known, assuming that it is only read once and not on any invocation.Jaffa
G
5

The following applies to hotspot, other JVMs may apply different optimizations.

If those instances are in turned assigned to static final fields and then referred to by other code and the VM is started with -XX:+TrustFinalNonStaticFields then those instances can participate in constant folding and inlining CONSTANT.f() can result in different branches being eliminated.

Another approach available to privileged code is creating anonymous classes instead of instances via sun.misc.Unsafe.defineAnonymousClass(Class<?>, byte[], Object[]) and patching a class constant for each class, but ultimately that also has to be referenced through a class constant to have any effect on optimizations.

Grad answered 8/11, 2016 at 19:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.