Skip to content

Understanding the On Stack Replacement (OSR) optimisation in the HotSpot C1 compiler

Chris Newland edited this page Oct 24, 2017 · 5 revisions

Here is an explanation by Kris Mok (@rednaxelafx) of why an OSR compilation performed by HotSpot's C1 compiler produces native code for the entire method that contains the loop being OSR-compiled instead of just for the hot loop itself:

It's quirky. C1 OSR was added later, in a pretty "hacky" way. The method is still compiled just like normal, with an OSR entry bolted on to the CFG, and that entry is marked as a special loop header and is pretty much ignored through the compilation until RA (chriswhocodes: register allocator?) and codegen but currently only a single OSR entry point is allowed/used.

This "hacky" way of doing it makes the implementation really simple: it doesn't require a separate pre-pass like C2's ciTypeFlow (well C1's CFG + IR construction is a two pass thing anyway... it wouldn't be that hard to make C1 compile only the loop, it's just more work, unless C1 opts to use the same ciTypeFlow like C2, which is going to impact compilation speed.

By the way the OSR entry block introduces extra Phi nodes for things in the JVM state: locals, operand stack. That's necessary because the interpreter may have seen state that's different from what C1 would have seen from the standard entry up to the OSR entry.

E.g. The original bytecode may have two consecutive non-volatile loads from the same field, and C1 would optimize them into one load, but the interpreter would actually do two loads and may observe different values from the loads, so it's not valid to simply/blindly optimize that out in OSR.

Clone this wiki locally