4

For example,a loop with 10000 times in a method.When it runs 1000 times, the backedge_counter triggers the JIT compilation. And the interpreter continue executing. When it loops 4000 times, the JIT compilation completes.

My question is, how does the remainder 6000 times be executed, by interpreter, or execute native code?Or the native code is not executed until this method is invoked next time? And what happens when this method is invoked next time?

  • 4
    Why wouldn't it execute natively? Isn't that the point of JIT compilation? – shmosel Aug 20 '17 at 08:31
  • 2
    +1 It's an interesting, non-trivial question that doen't deserve the downvotes IMHO. Is the Java HotSpot compiler able to change a currently-running method invocation from interpreted to compiled code? The question's wording isn't perfect as JIT and HotSpot are subtly different approaches, but the text made clear that HotSpot is meant. – Ralf Kleberhoff Aug 20 '17 at 09:27
  • @RalfKleberhoff If it wasn't able to change a method what exactly would the point of it be? Maybe it lets the current invocation complete, but surely not the next 5999 times. The question is asinine. – user207421 Aug 20 '17 at 09:56
  • Of course HotSpot is able the exchange methods from interpreted to native while this method is not executing. That's for granted. Is that also possible while the method is in the middle of its execution? – Ralf Kleberhoff Aug 20 '17 at 10:00
  • 2
    @RalfKleberhoff That's not the question that was asked. The question was explicitly about the remaining 6,000 invocations. – user207421 Aug 20 '17 at 10:06
  • @ EJP,Sorry for my unclear expression. I modify it – Bolen.Zhang Aug 20 '17 at 12:08

2 Answers2

9

Assuming you are asking about HotSpot JVM, the answer is the remaining interations will be executed in compiled code.

HotSpot JVM has a technique known as 'on-stack replacement' to switch from interpreter to compiled code while the method is running.

http://openjdk.java.net/groups/hotspot/docs/HotSpotGlossary.html

on-stack replacement
Also known as 'OSR'. The process of converting an interpreted (or less optimized) stack frame into a compiled (or more optimized) stack frame. This happens when the interpreter discovers that a method is looping, requests the compiler to generate a special nmethod with an entry point somewhere in the loop (specifically, at a backward branch), and transfers control to that nmethod. A rough inverse to deoptimization.

If you run JVM with -XX:+PrintCompilation flag, OSR compilations will be marked by % sign:

    274   27       3       java.lang.String::lastIndexOf (52 bytes)
    275   29       3       java.lang.String::startsWith (72 bytes)
    275   28       3       java.lang.String::startsWith (7 bytes)
    275   30       3       java.util.Arrays::copyOf (19 bytes)
    276   32       4       java.lang.AbstractStringBuilder::append (29 bytes)
    276   31  s    3       java.lang.StringBuffer::append (13 bytes)
    283   33 %     3       LoopTest::myLongLoop @ 13 (43 bytes)
             ^                                    ^
            OSR                            bytecode index of OSR entry

UPDATE

Typically after OSR compilation a regular compilation is also queued, so that the next time the method is called, it will start running directly in compiled mode.

    187   32 %     3       LoopTest::myLongLoop @ 13 (43 bytes)
    187   33       3       LoopTest::myLongLoop (43 bytes)

However, if a regular compilation is not complete by the time the method is called again, the method will start running in interpreter, and then will switch to OSR entry inside a loop.

apangin
  • 92,924
  • 10
  • 193
  • 247
2

Let's restate the question:

Is the Java HotSpot compiler able to change a method from interpreted to compiled in the middle of its execution?

I think it can.

The task is not easy for the engine (I collected some experience in that field when working on an Ahead-of-Time compiler called JUMP for the PalmOS handhelds years ago). When the engine decides to switch, it must consider the following points, at least:

  • Where is the program counter? In interpreted code, it's at some bytecode offset from the beginning of the method, knowing exactly which bytecode to execute next. In optimized native code, typically the JVM bytecodes don't translate to isolated blocks of machine instructions, but are dependent on one another, rearranged out-of order and so on. So there might not be a native instruction address that exactly corresponds to the bytecode program counter when switching.

  • Where are the data? The interpreter (probably) keeps everything on the stack, optimized native code uses a mixture of register and stack allocation that will be different for different places in the native translation.

So I read the HotSpot whitepaper. It doesn't answer the question explicitly, but there's a hint under "deoptimization". When a new class is loaded dynamically or even replaced inside a debugging session, previous optimizations like inlining can become invalid.

Therefore the Java HotSpot VM must be able to dynamically deoptimize (and then reoptimize, if necessary) previously optimized hot spots, even while executing code for the hot spot.

This is also switching between compiled and interpreted code, only the other way round. As this is documented behaviour of the HotSpot engine, I come to the conclusion that the switch from interpreted to compiled code within a currently executing method call is possible.

EDIT:

I wasn't explicit enough about what I understood as being the core of the question.

I understood there's a method doing a loop with 10000 iterations as follows:

void loop() {
    for (int i=0; i<10000; i++) {
        // example loop body
        objects[i].doSomething();
    }
}

After e.g. 4000 iterations the HotSpot compiler has optimized that method. What happens then?

There are two aspects, one trivial and one complex:

  • The trivial one is that calls that happen inside the loop (e.g. doSomething()) will call their compiled version as soon as it's available. I didn't mention this in my original answer as I took that for granted.

  • The complex aspect is: will the currently-running loop() execution switch from interpreted to compiled code at i=4000? That's what I understood to be the OP's question.

Ralf Kleberhoff
  • 6,990
  • 1
  • 13
  • 7
  • Let's **not** restate the question. Let's answer the quetsion that was asked. If you have your own question, ask it, and if you have your own answer to your own question, post it there. Stick to the point. – user207421 Aug 20 '17 at 10:07
  • But what happens when this method is invoked next time? – Bolen.Zhang Aug 20 '17 at 12:39