@@ -74,8 +74,17 @@ private RubyClass defineClass(Ruby runtime, RubyModule namespace, String parentN
7474 return newClass ;
7575 }
7676
77+ // Facts:
78+ // - all ivar reads are without any synchronisation of fences see
79+ // https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/runtime/ivars/VariableAccessor.java#L110-110
80+ // - writes depend on UnsafeHolder.U, null -> SynchronizedVariableAccessor, !null -> StampedVariableAccessor
81+ // SynchronizedVariableAccessor wraps with synchronized block, StampedVariableAccessor uses fullFence or
82+ // volatilePut
83+
7784 @ JRubyClass (name = "JRubyObject" , parent = "AbstractObject" )
7885 public static class JRubyObject extends RubyObject {
86+ private static volatile ThreadContext threadContext = null ;
87+
7988 public JRubyObject (Ruby runtime , RubyClass metaClass ) {
8089 super (runtime , metaClass );
8190 }
@@ -87,10 +96,12 @@ public IRubyObject initialize(ThreadContext context) {
8796
8897 @ JRubyMethod (name = "full_memory_barrier" , visibility = Visibility .PRIVATE )
8998 public IRubyObject fullMemoryBarrier (ThreadContext context ) {
99+ // Prevent reordering of ivar writes with publication of this instance
90100 if (UnsafeHolder .U == null || !UnsafeHolder .SUPPORTS_FENCES ) {
91- throw new UnsupportedOperationException (
92- "concurrent-ruby requires java with sun.mics.Unsafe fences support, such as Java 8. " +
93- "Current version is: " + System .getProperty ("java.version" ));
101+ // Assuming that following volatile read and write is not eliminated it simulates fullFence.
102+ // If it's eliminated it'll cause problems only on non-x86 platforms.
103+ final ThreadContext oldContext = threadContext ;
104+ threadContext = context ;
94105 } else {
95106 UnsafeHolder .fullFence ();
96107 }
@@ -99,34 +110,30 @@ public IRubyObject fullMemoryBarrier(ThreadContext context) {
99110
100111 @ JRubyMethod (name = "instance_variable_get_volatile" , visibility = Visibility .PROTECTED )
101112 public IRubyObject instanceVariableGetVolatile (ThreadContext context , IRubyObject name ) {
102- if (UnsafeHolder .U == null ) {
103- synchronized (this ) {
104- // TODO (pitr 06-Sep-2015): Possibly dangerous, there may be a deadlock here
105- // TODO (pitr 08-Sep-2015): maybe remove the branch since full_memory_barrier is not supported anyway
106- return instance_variable_get (context , name );
107- }
108- } else if (UnsafeHolder .SUPPORTS_FENCES ) {
109- // ensure we see latest value
110- UnsafeHolder .loadFence ();
113+ // Ensure we ses latest value with loadFence
114+ if (UnsafeHolder .U == null || !UnsafeHolder .SUPPORTS_FENCES ) {
115+ // piggybacking on volatile read, simulating loadFence
116+ final ThreadContext oldContext = threadContext ;
111117 return instance_variable_get (context , name );
112118 } else {
113- throw new UnsupportedOperationException ();
119+ UnsafeHolder .loadFence ();
120+ return instance_variable_get (context , name );
114121 }
115122 }
116123
117124 @ JRubyMethod (name = "instance_variable_set_volatile" , visibility = Visibility .PROTECTED )
118125 public IRubyObject InstanceVariableSetVolatile (ThreadContext context , IRubyObject name , IRubyObject value ) {
119- if (UnsafeHolder .U == null ) {
120- synchronized (this ) {
121- return instance_variable_set (name , value );
122- }
123- } else if (UnsafeHolder .SUPPORTS_FENCES ) {
126+ // Ensure we make last update visible
127+ if (UnsafeHolder .U == null || !UnsafeHolder .SUPPORTS_FENCES ) {
128+ // piggybacking on volatile write, simulating storeFence
124129 final IRubyObject result = instance_variable_set (name , value );
125- // ensure we make latest value visible
126- UnsafeHolder .storeFence ();
130+ threadContext = context ;
127131 return result ;
128132 } else {
129- throw new UnsupportedOperationException ();
133+ // JRuby uses StampedVariableAccessor which calls fullFence
134+ // so no additional steps needed.
135+ // See https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/runtime/ivars/StampedVariableAccessor.java#L151-L159
136+ return instance_variable_set (name , value );
130137 }
131138 }
132139 }
0 commit comments