final variables and hotspot optimization

Hi, haven’t verified it yet, but doas anyone know if such code would be fully optimized by hotspot.

Class Test {
static final boolean DEBUG = GlobalProperties.isDebug();


void test() {
if (DEBUG){ // — > will that be optimized (thrown away) by hotspot is DEBUG = false at runtime ?
// println…
}
}

the javac cannot optmize the code by deleting the if(DEBUG) from the bytecode as its value isn’t known at compile time… but what about hotspot ?

Lilian

Yes that works (and has for years). I use it all the time. The java assert system is done that way too (just a little hidden under the covers).

I seem to recall the optimizing javac compiler option also cuts out dead code at compile time.

Cas :slight_smile:

But this is not dead code…as the value of the flag relies on a dynamic property (e.g. taken from command line).

It’s only dead at runtime.

Lilian

Compile time dead code is always removed (and the optimising option no longer exists anyway), but that is not the query of this thread.

Just covering all the bases :wink:
Hotspot Server VM culls dead code at runtime.

Cas :slight_smile:

I’m not so sure the client VM does this as well (I have to test), and the client VM is the important VM.

I seem to remember testing it on the client VM once and finding that it did work (i.e. there was no detectable slow down caused by the test).

Both the HotSpot client and server compilers perform this optimization of loading the values of static final fields when the bytecodes are compiled to machine code (assuming the class has been initialized, etc.)

This very test was performed on JGO a few years ago but my pot-addled brain tells me that the client VM did not perform this optimisation at runtime, at the time (which would have been a 1.4 VM).

Cas :slight_smile:

I just did some testing on the client and it seems to perform this optimization, but I think there’s a quite annoying limitation.
for example, when you have in your class a

final boolean DO_SOMETHING_MORE = false;

and elsewhere you do somewhere in a tight loop or something

if (DO_SOMETHING_MORE) {
system.out.println(“Doing something more”);
}

this is correctly optimized away.

But, if you set this final boolean in the constructor like this:

public MyClass(boolean doSomethingMore) {
this.DO_SOMETHING_MORE = doSomethingMore;
}

and you instantiate this class like this

MyClass myInstance = new MyClass(false);

this optimization is not done.

It seems like either this optimization is done only by javac, or if such optimizations are done in runtime (which doesn’t seem so) it just fails to optimize this away if the final boolean is set in the constructor. Whatever the case, the optimization seems only to be performed in a static context.
(EDIT: when it’s a static constant, not a constant in an instance)

In any way, this seems like a really annoying limitation for me because I wanted to be able to optimize a CPU emulator if possible by adding a flag in the constructor like this CpuEmulator(boolean strictEmulation) where the CPU will be emulated a little bit more loosely (for example no cycle counting and no addressing exceptions) if strict emulation is set to false.

Isn’t it to be expected that specific instantiations of a class are not taken into account when optimizing? Otherwise if you had two instances of MyClass: new MyClass(false) and new MyClass(true), those two instances would need to have different compiled code behind them…

It is to be expected if it is an ahead of time compilation optimization, but there was talk about it being a runtime optimization. But I suppose it’s maybe a too difficult and expensive optimization to do in runtime (especially in the client VM).

You would have to ask a jvm guru for more details, but I have a gut feeling that you can’t have multiple compiled versions of a bit of bytecode at runtime. (This is just my gut feeling, so I might be completely wrong :)) If my assumption is correct, then that kind of explains why it can’t be optimised (easily). You could compile the case where the field is false, but then once an instance gets created which sets the field to true, the compiled code would have to be invalidated.
Also, if it is possible to have multiple compiled versions per method/class then the number of possible compiled versions would grow exponentially with the number of final booleans…
If the field in question is static and final it might get optimized at runtime? Something like:

private static final boolean STRICT_CPU_EMU;

static {
  STRICT_CPU_EMU = Boolean.valueOf(System.getProperty("strictcpuemulation")).booleanValue();
}

but that’s probably not what you want to achieve.

You’re right, that’s not what I want to achieve :slight_smile:

But maybe something like this could be used to do something like unload a class, set the system property to something else and then reload it? (dunno if this is possible)

It’s possible with a suitable ClassLoader
(you could even have multiple concurrent versions of the same class, )

There’s an article at javalobby today on that topic with a list of classloaders (mainly for embedding plugins into applications).

Lilian

http://javalobby.org/java/forums/t18345.html

As I understand it this optimisation is figured out by Hotspot Server. And don’t forget it can dynamically decompile code when it notices something’s changed.

Cas :slight_smile:

The key issue remains whether or not multiple compiled versions can exist in parallel. Otherwise the following scenario is possible

  • new CpuEmulator(false)
  • hotspot compiles bits of CpuEmulator, optimizing out the unused code
  • new CpuEmulator(true)
  • hotspot detects the change (which isn’t a class level change) and decompiles CpuEmulator

At that point you have two options, either you’re stuck with an unoptimized version of CpuEmulator that handles both cases or two specifically optimized versions exist in parallel…

Anyway I’m going to stop speculating now :slight_smile:

Off the top of my head, that’s a fundamental internal feature of the JVM that’s been around for as long as hotspot has (if not longer).

HotSpot currently only folds static final fields’ values into generated machine code, as they are guaranteed by the language and libraries to be constant over the program’s execution. HotSpot does not (at least currently) generate multiple specialized copies of machine code based on a program’s execution (aside from supporting multiple on-stack-replacement copies with particular entry points), though the same method, when inlined in multiple contexts, may be optimized differently based on the local usage. Note though that specialization is not necessarily required in order to optimize some of the usages of non-static final fields, or in fact non-final fields, because of HotSpot’s ability to dynamically deoptimize under arbitrary conditions. Some work is underway to take advantage of optimization opportunities in this area.