@@ -74,8 +74,17 @@ private RubyClass defineClass(Ruby runtime, RubyModule namespace, String parentN
74
74
return newClass ;
75
75
}
76
76
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
+
77
84
@ JRubyClass (name = "JRubyObject" , parent = "AbstractObject" )
78
85
public static class JRubyObject extends RubyObject {
86
+ private static volatile ThreadContext threadContext = null ;
87
+
79
88
public JRubyObject (Ruby runtime , RubyClass metaClass ) {
80
89
super (runtime , metaClass );
81
90
}
@@ -87,10 +96,12 @@ public IRubyObject initialize(ThreadContext context) {
87
96
88
97
@ JRubyMethod (name = "full_memory_barrier" , visibility = Visibility .PRIVATE )
89
98
public IRubyObject fullMemoryBarrier (ThreadContext context ) {
99
+ // Prevent reordering of ivar writes with publication of this instance
90
100
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 ;
94
105
} else {
95
106
UnsafeHolder .fullFence ();
96
107
}
@@ -99,34 +110,30 @@ public IRubyObject fullMemoryBarrier(ThreadContext context) {
99
110
100
111
@ JRubyMethod (name = "instance_variable_get_volatile" , visibility = Visibility .PROTECTED )
101
112
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 ;
111
117
return instance_variable_get (context , name );
112
118
} else {
113
- throw new UnsupportedOperationException ();
119
+ UnsafeHolder .loadFence ();
120
+ return instance_variable_get (context , name );
114
121
}
115
122
}
116
123
117
124
@ JRubyMethod (name = "instance_variable_set_volatile" , visibility = Visibility .PROTECTED )
118
125
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
124
129
final IRubyObject result = instance_variable_set (name , value );
125
- // ensure we make latest value visible
126
- UnsafeHolder .storeFence ();
130
+ threadContext = context ;
127
131
return result ;
128
132
} 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 );
130
137
}
131
138
}
132
139
}
0 commit comments