United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-8003135 : HotSpot inlines and hoists the Thread.currentThread().isInterrupted() out of the loop

Details
Type:
Bug
Submit Date:
2012-11-08
Status:
Resolved
Updated Date:
2013-04-30
Project Name:
JDK
Resolved Date:
2012-12-18
Component:
hotspot
OS:
generic
Sub-Component:
compiler
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
7u7
Fixed Versions:
hs25 (b14)

Related Reports
Backport:
Backport:
Backport:

Sub Tasks

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.
                                     
2012-11-08
URL:   http://hg.openjdk.java.net/hsx/hotspot-comp/hotspot/rev/eb409f2f146e
User:  vlivanov
Date:  2012-12-18 18:08:26 +0000

                                     
2012-12-18
URL:   http://hg.openjdk.java.net/hsx/hsx25/hotspot/rev/eb409f2f146e
User:  amurillo
Date:  2012-12-21 20:28:27 +0000

                                     
2012-12-21



Hardware and Software, Engineered to Work Together