11package com .concurrent_ruby .ext ;
22
3- import java .io .IOException ;
4-
53import org .jruby .Ruby ;
4+ import org .jruby .RubyBasicObject ;
65import org .jruby .RubyClass ;
76import org .jruby .RubyModule ;
87import org .jruby .RubyObject ;
9- import org .jruby .RubyBasicObject ;
108import org .jruby .anno .JRubyClass ;
119import org .jruby .anno .JRubyMethod ;
10+ import org .jruby .runtime .Block ;
1211import org .jruby .runtime .ObjectAllocator ;
12+ import org .jruby .runtime .ThreadContext ;
13+ import org .jruby .runtime .Visibility ;
1314import org .jruby .runtime .builtin .IRubyObject ;
1415import org .jruby .runtime .load .Library ;
15- import org .jruby .runtime .Block ;
16- import org .jruby .runtime .Visibility ;
17- import org .jruby .runtime .ThreadContext ;
1816import org .jruby .util .unsafe .UnsafeHolder ;
1917
18+ import java .io .IOException ;
19+ import java .lang .reflect .Method ;
20+
2021public class SynchronizationLibrary implements Library {
2122
2223 private static final ObjectAllocator JRUBY_OBJECT_ALLOCATOR = new ObjectAllocator () {
@@ -84,10 +85,28 @@ private RubyClass defineClass(Ruby runtime, RubyModule namespace, String parentN
8485 // - writes depend on UnsafeHolder.U, null -> SynchronizedVariableAccessor, !null -> StampedVariableAccessor
8586 // SynchronizedVariableAccessor wraps with synchronized block, StampedVariableAccessor uses fullFence or
8687 // volatilePut
88+ // TODO (pitr 16-Sep-2015): what do we do in Java 9 ?
8789
8890 // module JRubyAttrVolatile
8991 public static class JRubyAttrVolatile {
9092
93+ private static boolean supportsFences () {
94+ if (UnsafeHolder .U == null ) {
95+ return false ;
96+ } else {
97+ try {
98+ Method m = UnsafeHolder .U .getClass ().getDeclaredMethod ("fullFence" , new Class [0 ]);
99+ if (m != null ) {
100+ return true ;
101+ }
102+ } catch (Exception var1 ) {
103+ // nothing
104+ }
105+
106+ return false ;
107+ }
108+ }
109+
91110 // volatile threadContext is used as a memory barrier per the JVM memory model happens-before semantic
92111 // on volatile fields. any volatile field could have been used but using the thread context is an
93112 // attempt to avoid code elimination.
@@ -96,9 +115,10 @@ public static class JRubyAttrVolatile {
96115 @ JRubyMethod (name = "full_memory_barrier" , visibility = Visibility .PUBLIC )
97116 public static IRubyObject fullMemoryBarrier (ThreadContext context , IRubyObject self ) {
98117 // Prevent reordering of ivar writes with publication of this instance
99- if (UnsafeHolder . U == null || ! UnsafeHolder . SUPPORTS_FENCES ) {
118+ if (! supportsFences () ) {
100119 // Assuming that following volatile read and write is not eliminated it simulates fullFence.
101120 // If it's eliminated it'll cause problems only on non-x86 platforms.
121+ // http://shipilev.net/blog/2014/jmm-pragmatics/#_happens_before_test_your_understanding
102122 final ThreadContext oldContext = threadContext ;
103123 threadContext = context ;
104124 } else {
@@ -110,7 +130,7 @@ public static IRubyObject fullMemoryBarrier(ThreadContext context, IRubyObject s
110130 @ JRubyMethod (name = "instance_variable_get_volatile" , visibility = Visibility .PUBLIC )
111131 public static IRubyObject instanceVariableGetVolatile (ThreadContext context , IRubyObject self , IRubyObject name ) {
112132 // Ensure we ses latest value with loadFence
113- if (UnsafeHolder . U == null || ! UnsafeHolder . SUPPORTS_FENCES ) {
133+ if (! supportsFences () ) {
114134 // piggybacking on volatile read, simulating loadFence
115135 final ThreadContext oldContext = threadContext ;
116136 return ((RubyBasicObject )self ).instance_variable_get (context , name );
@@ -123,7 +143,7 @@ public static IRubyObject instanceVariableGetVolatile(ThreadContext context, IRu
123143 @ JRubyMethod (name = "instance_variable_set_volatile" , visibility = Visibility .PUBLIC )
124144 public static IRubyObject InstanceVariableSetVolatile (ThreadContext context , IRubyObject self , IRubyObject name , IRubyObject value ) {
125145 // Ensure we make last update visible
126- if (UnsafeHolder . U == null || ! UnsafeHolder . SUPPORTS_FENCES ) {
146+ if (! supportsFences () ) {
127147 // piggybacking on volatile write, simulating storeFence
128148 final IRubyObject result = ((RubyBasicObject )self ).instance_variable_set (name , value );
129149 threadContext = context ;
0 commit comments