United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: 7170319 Bug in GVN code in C1 breaks Java volatile semantics
7170319 : Bug in GVN code in C1 breaks Java volatile semantics

Details
Type:
Bug
Submit Date:
2012-05-21
Status:
Closed
Updated Date:
2012-05-21
Project Name:
JDK
Resolved Date:
2012-05-21
Component:
hotspot
OS:
generic
Sub-Component:
compiler
CPU:
generic
Priority:
P2
Resolution:
Duplicate
Affected Versions:
6
Fixed Versions:
hs24

Related Reports
Duplicate:
Relates:

Sub Tasks

Description
As reported on:

http://stackoverflow.com/questions/10620680/why-volatile-in-java-5-doesnt-synchronize-cached-copies-of-variables-with-main

and discussed on:

http://cs.oswego.edu/pipermail/concurrency-interest/2012-May/009440.html

and

http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/2012-May/007704.html

The following test program reports "Error" where under the Java Memory Model rules it never should:

public class VolatileBug {
    volatile static private int a;
    static private int b;

    public static void main(String [] args) throws Exception {
        for (int i = 0; i < 100; i++) {
            new Thread() {

                @Override
                public void run() {
                    int tt = b; // makes the jvm cache the value of b

                    while (a==0) {

                    }

                    if (b == 0) {
                        System.out.println("error");
                    }
                }

            }.start();
        }

        b = 1;
        a = 1;
    }
}

Investigation shows the problem is in the GlobalValueNumbering code where the load of the volatile field doesn't kill the prevous load of a non-volatile field, resulting in the old value incorrectly being re-used after the volatile field is read.

                                    

Comments
EVALUATION

Christian Thalinger writes:

The fix is actually very simple:

diff --git a/src/share/vm/c1/c1_ValueMap.hpp b/src/share/vm/c1/c1_ValueMap.hpp
--- a/src/share/vm/c1/c1_ValueMap.hpp
+++ b/src/share/vm/c1/c1_ValueMap.hpp
@@ -160,8 +160,8 @@
  void do_Local          (Local*           x) { /* nothing to do */ }
  void do_Constant       (Constant*        x) { /* nothing to do */ }
  void do_LoadField      (LoadField*       x) {
-    if (x->is_init_point()) {
-      // getstatic is an initialization point so treat it as a wide kill
+    if (x->is_init_point() ||         // getstatic is an initialization point so treat it as a wide kill
+        x->field()->is_volatile()) {  // The JMM requires this.
      kill_memory();
    }
  }

This kills all loads after the volatile load.
                                     
2012-05-21
WORK AROUND

In a fastdebug build you can use:

-XX:-UseGlobalOrderNumbering

though it may impact performance significantly.
                                     
2012-05-21



Hardware and Software, Engineered to Work Together