1
1
package com .concurrent_ruby .ext ;
2
2
3
- import java .io .IOException ;
4
-
5
3
import org .jruby .Ruby ;
4
+ import org .jruby .RubyBasicObject ;
6
5
import org .jruby .RubyClass ;
7
6
import org .jruby .RubyModule ;
8
7
import org .jruby .RubyObject ;
9
- import org .jruby .RubyBasicObject ;
10
8
import org .jruby .anno .JRubyClass ;
11
9
import org .jruby .anno .JRubyMethod ;
10
+ import org .jruby .runtime .Block ;
12
11
import org .jruby .runtime .ObjectAllocator ;
12
+ import org .jruby .runtime .ThreadContext ;
13
+ import org .jruby .runtime .Visibility ;
13
14
import org .jruby .runtime .builtin .IRubyObject ;
14
15
import org .jruby .runtime .load .Library ;
15
- import org .jruby .runtime .Block ;
16
- import org .jruby .runtime .Visibility ;
17
- import org .jruby .runtime .ThreadContext ;
18
16
import org .jruby .util .unsafe .UnsafeHolder ;
19
17
18
+ import java .io .IOException ;
19
+ import java .lang .reflect .Method ;
20
+
20
21
public class SynchronizationLibrary implements Library {
21
22
22
23
private static final ObjectAllocator JRUBY_OBJECT_ALLOCATOR = new ObjectAllocator () {
@@ -84,10 +85,28 @@ private RubyClass defineClass(Ruby runtime, RubyModule namespace, String parentN
84
85
// - writes depend on UnsafeHolder.U, null -> SynchronizedVariableAccessor, !null -> StampedVariableAccessor
85
86
// SynchronizedVariableAccessor wraps with synchronized block, StampedVariableAccessor uses fullFence or
86
87
// volatilePut
88
+ // TODO (pitr 16-Sep-2015): what do we do in Java 9 ?
87
89
88
90
// module JRubyAttrVolatile
89
91
public static class JRubyAttrVolatile {
90
92
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
+
91
110
// volatile threadContext is used as a memory barrier per the JVM memory model happens-before semantic
92
111
// on volatile fields. any volatile field could have been used but using the thread context is an
93
112
// attempt to avoid code elimination.
@@ -96,9 +115,10 @@ public static class JRubyAttrVolatile {
96
115
@ JRubyMethod (name = "full_memory_barrier" , visibility = Visibility .PUBLIC )
97
116
public static IRubyObject fullMemoryBarrier (ThreadContext context , IRubyObject self ) {
98
117
// Prevent reordering of ivar writes with publication of this instance
99
- if (UnsafeHolder . U == null || ! UnsafeHolder . SUPPORTS_FENCES ) {
118
+ if (! supportsFences () ) {
100
119
// Assuming that following volatile read and write is not eliminated it simulates fullFence.
101
120
// 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
102
122
final ThreadContext oldContext = threadContext ;
103
123
threadContext = context ;
104
124
} else {
@@ -110,7 +130,7 @@ public static IRubyObject fullMemoryBarrier(ThreadContext context, IRubyObject s
110
130
@ JRubyMethod (name = "instance_variable_get_volatile" , visibility = Visibility .PUBLIC )
111
131
public static IRubyObject instanceVariableGetVolatile (ThreadContext context , IRubyObject self , IRubyObject name ) {
112
132
// Ensure we ses latest value with loadFence
113
- if (UnsafeHolder . U == null || ! UnsafeHolder . SUPPORTS_FENCES ) {
133
+ if (! supportsFences () ) {
114
134
// piggybacking on volatile read, simulating loadFence
115
135
final ThreadContext oldContext = threadContext ;
116
136
return ((RubyBasicObject )self ).instance_variable_get (context , name );
@@ -123,7 +143,7 @@ public static IRubyObject instanceVariableGetVolatile(ThreadContext context, IRu
123
143
@ JRubyMethod (name = "instance_variable_set_volatile" , visibility = Visibility .PUBLIC )
124
144
public static IRubyObject InstanceVariableSetVolatile (ThreadContext context , IRubyObject self , IRubyObject name , IRubyObject value ) {
125
145
// Ensure we make last update visible
126
- if (UnsafeHolder . U == null || ! UnsafeHolder . SUPPORTS_FENCES ) {
146
+ if (! supportsFences () ) {
127
147
// piggybacking on volatile write, simulating storeFence
128
148
final IRubyObject result = ((RubyBasicObject )self ).instance_variable_set (name , value );
129
149
threadContext = context ;
0 commit comments