JDK-8036851 : volatile double accesses are not explicitly atomic in C2
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 8u20,9
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2014-03-07
  • Updated: 2019-09-13
  • Resolved: 2014-05-06
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 8 JDK 9
8u60Fixed 9 b14Fixed
Description
In the Java programming language accesses to 64-bit long and double fields are not required to be atomic, unless the fields are declared volatile. For volatile longs we have special handling in C2. AFAICS the final call for a volatile load (and similarly for store) goes down to this method:

Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt,
                         int adr_idx,
                         bool require_atomic_access) {
 assert(adr_idx != Compile::AliasIdxTop, "use other make_load factory" );
 const TypePtr* adr_type = NULL; // debug-mode-only argument
 debug_only(adr_type = C->get_adr_type(adr_idx));
 Node* mem = memory(adr_idx);
 Node* ld;
 if (require_atomic_access && bt == T_LONG) {
   ld = LoadLNode::make_atomic(C, ctl, mem, adr, adr_type, t);
 } else {
   ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt);
 }
 ld = _gvn.transform(ld);
 if ((bt == T_OBJECT) && C->do_escape_analysis() || C->eliminate_boxing()) {
   // Improve graph before escape analysis and boxing elimination.
   record_for_igvn(ld);
 }
 return ld;
}

which only performs an atomic access for T_LONG! And going further down here is the node for accessing doubles:

// Load a double (64 bits) from memory
class LoadDNode : public LoadNode {
public:
 LoadDNode( Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *t = Type::DOUBLE )
   : LoadNode(c,mem,adr,at,t) {}
 virtual int Opcode() const;
 virtual uint ideal_reg() const { return Op_RegD; }
 virtual int store_Opcode() const { return Op_StoreD; }
 virtual BasicType memory_type() const { return T_DOUBLE; }
};

no mention of need for atomic access at all. 

It appears that because double accesses on x86 and sparc were always atomic, there was no need to call this out in the C2 structure. However it need not be the case on other architectures, which means they must provide atomic access for all double accesses, not just volatile accesses.

We should add support for atomic double access so that it can be distinguished from non-atomic accesses on platforms where the distinction is significant.
Comments
I think volatile doubles should be handled the same as volatile longs. There should be explicit volatile handling code within the methods that are clearly marked as requiring atomicity. That way any future port will recognize that it must provide atomic access for the volatiles. It can choose whether to also provide atomic access for non-volatiles. We should not assume that all double accesses are atomic on all platforms - even if that happens to be the case so far. Or if we think it is a safe and reasonable assumption then we should clearly document why there are no volatile specific code sections and that we assume/require that all double accesses are atomic.
04-05-2014