JDK-8003135 : HotSpot inlines and hoists the Thread.currentThread().isInterrupted() out of the loop
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 7u7
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: x86
  • Submitted: 2012-11-08
  • Updated: 2013-06-26
  • Resolved: 2012-12-18
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7 JDK 8 Other
7u40Fixed 8Fixed hs24Fixed
Description
See discussion and complete test case at http://cs.oswego.edu/pipermail/concurrency-interest/2012-November/010184.html

It reproduces perfectly on server VMs tested: all existing 7u*, many 6u* tested. The test passes with -XX:-Inline. The assembly shows that this loop:

   public void think() {
       while (true) {
           if (checkInterruptedStatus()) break;
       }
       System.out.println("We're done thinking");
   }

   private boolean checkInterruptedStatus() {
       return Thread.currentThread().isInterrupted();
   }

...is being reduced to:

# {method} 'think' '()V' in 'InterruptedVisibilityTest'
  ...
  0x00007f31890601a3: mov    0x14(%r10),%r11d      // read $interrupted
  0x00007f31890601a7: test   %r11d,%r11d           // test $interrupted
  0x00007f31890601aa: jne    0x00007f31890601c9    // exit branch
  0x00007f31890601ac: mov    %rbp,%r10             // LOOP START
  0x00007f31890601af: test   %eax,0xb15ee4b(%rip)  // safepoint
  0x00007f31890601b5: jmp    0x00007f31890601ac    // LOOP END

...effectively to non-terminating busy loop, which ignores interrupts.

The interesting part is that this loop is working just fine:

   public void think() {
       while (true) {
           if (Thread.currentThread().isInterrupted()) break;
       }
       System.out.println("We're done thinking");
   }

...which means there is either a weird interaction with inlining, which either loses barriers, or intrinsics inlining which gets isInterrupted() inlined into the leaf callee, and then being treated as usual read with final inlining into think().
Comments
I also tend to think this has the interaction with OSR. Running with latest hotspot-comp, and the extended case which calls the main() many times in the loop: PASSES: ~/trunks/hotspot-comp/build/linux-x86_64-normal-server-fastdebug/images/j2sdk-image/bin/java -Xbatch -XX:-TieredCompilation -XX:+PrintAssembly -XX:-UseOnStackReplacement InterruptedVisibilityTest The relevant part of OptoAssembly: 040 B2: # B2 B3 <- B1 B2 Loop: B2-B2 inner Freq: 986894 040 movl R11, [R10 + #28 (8-bit)] # int 044 testl rax, [rip + #offset_to_poll_page] # Safepoint: poll for GC # InterruptedVisibilityTest::think @ bci:4 L[0]=RSI STK[0]=R11 # OopMap{rsi=Oop off=68} 04a testl R11, R11 04d je,s B2 P=0.999999 C=10950547.000000 Notice the re-read to R11, and re-test is there. FAILS: ~/trunks/hotspot-comp/build/linux-x86_64-normal-server-fastdebug/images/j2sdk-image/bin/java -Xbatch -XX:-TieredCompilation -XX:+PrintAssembly -XX:+UseOnStackReplacement InterruptedVisibilityTest Relevant part of OptoAssembly: 056 B6: # B6 <- B5 B6 top-of-loop Freq: 1e-35 056 testl rax, [rip + #offset_to_poll_page] # Safepoint: poll for GC # InterruptedVisibilityTest::think @ bci:4 L[0]=RBP STK[0]=R11 # OopMap{rbp=Oop off=86} 05c jmp,s B6 The same reduced loop.
08-11-2012