3
3
import org .jruby .*;
4
4
import org .jruby .anno .JRubyClass ;
5
5
import org .jruby .anno .JRubyMethod ;
6
+ import com .concurrent_ruby .ext .jsr166e .ConcurrentHashMap ;
7
+ import com .concurrent_ruby .ext .jsr166e .ConcurrentHashMapV8 ;
8
+ import com .concurrent_ruby .ext .jsr166e .nounsafe .*;
6
9
import org .jruby .runtime .Block ;
7
10
import org .jruby .runtime .ObjectAllocator ;
8
11
import org .jruby .runtime .ThreadContext ;
9
12
import org .jruby .runtime .builtin .IRubyObject ;
10
13
import org .jruby .runtime .load .Library ;
11
- import java .util .Iterator ;
12
- import java .util .function .BiFunction ;
13
- import java .util .function .Function ;
14
- import java .util .concurrent .ConcurrentHashMap ;
15
14
16
15
import java .io .IOException ;
17
16
import java .util .Map ;
@@ -45,16 +44,35 @@ public static class JRubyMapBackend extends RubyObject {
45
44
static final int DEFAULT_INITIAL_CAPACITY = 16 ;
46
45
static final float DEFAULT_LOAD_FACTOR = 0.75f ;
47
46
47
+ public static final boolean CAN_USE_UNSAFE_CHM = canUseUnsafeCHM ();
48
+
48
49
private ConcurrentHashMap <IRubyObject , IRubyObject > map ;
49
50
50
51
private static ConcurrentHashMap <IRubyObject , IRubyObject > newCHM (int initialCapacity , float loadFactor ) {
51
- return new java .util .concurrent .ConcurrentHashMap <IRubyObject , IRubyObject >(initialCapacity , loadFactor );
52
+ if (CAN_USE_UNSAFE_CHM ) {
53
+ return new ConcurrentHashMapV8 <IRubyObject , IRubyObject >(initialCapacity , loadFactor );
54
+ } else {
55
+ return new com .concurrent_ruby .ext .jsr166e .nounsafe .ConcurrentHashMapV8 <IRubyObject , IRubyObject >(initialCapacity , loadFactor );
56
+ }
52
57
}
53
58
54
59
private static ConcurrentHashMap <IRubyObject , IRubyObject > newCHM () {
55
60
return newCHM (DEFAULT_INITIAL_CAPACITY , DEFAULT_LOAD_FACTOR );
56
61
}
57
62
63
+ private static boolean canUseUnsafeCHM () {
64
+ try {
65
+ new com .concurrent_ruby .ext .jsr166e .ConcurrentHashMapV8 (); // force class load and initialization
66
+ return true ;
67
+ } catch (Throwable t ) { // ensuring we really do catch everything
68
+ // Doug's Unsafe setup errors always have this "Could not ini.." message
69
+ if (isCausedBySecurityException (t )) {
70
+ return false ;
71
+ }
72
+ throw (t instanceof RuntimeException ? (RuntimeException ) t : new RuntimeException (t ));
73
+ }
74
+ }
75
+
58
76
private static boolean isCausedBySecurityException (Throwable t ) {
59
77
while (t != null ) {
60
78
if ((t .getMessage () != null && t .getMessage ().contains ("Could not initialize intrinsics" )) || t instanceof SecurityException ) {
@@ -114,7 +132,7 @@ public IRubyObject put_if_absent(IRubyObject key, IRubyObject value) {
114
132
115
133
@ JRubyMethod
116
134
public IRubyObject compute_if_absent (final ThreadContext context , final IRubyObject key , final Block block ) {
117
- return map .computeIfAbsent (key , new java . util . function . Function <IRubyObject , IRubyObject >() {
135
+ return map .computeIfAbsent (key , new ConcurrentHashMap . Fun <IRubyObject , IRubyObject >() {
118
136
@ Override
119
137
public IRubyObject apply (IRubyObject key ) {
120
138
return block .yieldSpecific (context );
@@ -124,7 +142,7 @@ public IRubyObject apply(IRubyObject key) {
124
142
125
143
@ JRubyMethod
126
144
public IRubyObject compute_if_present (final ThreadContext context , final IRubyObject key , final Block block ) {
127
- IRubyObject result = map .computeIfPresent (key , new java . util . function . BiFunction <IRubyObject , IRubyObject , IRubyObject >() {
145
+ IRubyObject result = map .computeIfPresent (key , new ConcurrentHashMap . BiFun <IRubyObject , IRubyObject , IRubyObject >() {
128
146
@ Override
129
147
public IRubyObject apply (IRubyObject key , IRubyObject oldValue ) {
130
148
IRubyObject result = block .yieldSpecific (context , oldValue == null ? context .getRuntime ().getNil () : oldValue );
@@ -136,7 +154,7 @@ public IRubyObject apply(IRubyObject key, IRubyObject oldValue) {
136
154
137
155
@ JRubyMethod
138
156
public IRubyObject compute (final ThreadContext context , final IRubyObject key , final Block block ) {
139
- IRubyObject result = map .compute (key , new java . util . function . BiFunction <IRubyObject , IRubyObject , IRubyObject >() {
157
+ IRubyObject result = map .compute (key , new ConcurrentHashMap . BiFun <IRubyObject , IRubyObject , IRubyObject >() {
140
158
@ Override
141
159
public IRubyObject apply (IRubyObject key , IRubyObject oldValue ) {
142
160
IRubyObject result = block .yieldSpecific (context , oldValue == null ? context .getRuntime ().getNil () : oldValue );
@@ -148,7 +166,7 @@ public IRubyObject apply(IRubyObject key, IRubyObject oldValue) {
148
166
149
167
@ JRubyMethod
150
168
public IRubyObject merge_pair (final ThreadContext context , final IRubyObject key , final IRubyObject value , final Block block ) {
151
- IRubyObject result = map .merge (key , value , new java . util . function . BiFunction <IRubyObject , IRubyObject , IRubyObject >() {
169
+ IRubyObject result = map .merge (key , value , new ConcurrentHashMap . BiFun <IRubyObject , IRubyObject , IRubyObject >() {
152
170
@ Override
153
171
public IRubyObject apply (IRubyObject oldValue , IRubyObject newValue ) {
154
172
IRubyObject result = block .yieldSpecific (context , oldValue == null ? context .getRuntime ().getNil () : oldValue );
@@ -164,20 +182,14 @@ public RubyBoolean replace_pair(IRubyObject key, IRubyObject oldValue, IRubyObje
164
182
}
165
183
166
184
@ JRubyMethod (name = "key?" , required = 1 )
167
- public RubyBoolean has_key_p (IRubyObject key ) {
168
- return map .containsKey (key ) ? getRuntime ().getTrue () : getRuntime ().getFalse ();
169
- }
185
+ public RubyBoolean has_key_p (IRubyObject key ) {
186
+ return map .containsKey (key ) ? getRuntime ().getTrue () : getRuntime ().getFalse ();
187
+ }
170
188
171
189
@ JRubyMethod
172
190
public IRubyObject key (IRubyObject value ) {
173
- Iterator itr = map .entrySet ().iterator ();
174
- while (itr .hasNext ()) {
175
- Map .Entry <IRubyObject , IRubyObject > entry = (Map .Entry <IRubyObject , IRubyObject >) itr .next ();
176
- if (entry .getValue () == value ) {
177
- return entry .getKey ();
178
- }
179
- }
180
- return null ;
191
+ final IRubyObject key = map .findKey (value );
192
+ return key == null ? getRuntime ().getNil () : key ;
181
193
}
182
194
183
195
@ JRubyMethod
@@ -224,7 +236,7 @@ public RubyFixnum size(ThreadContext context) {
224
236
225
237
@ JRubyMethod
226
238
public IRubyObject get_or_default (IRubyObject key , IRubyObject defaultValue ) {
227
- return map .getOrDefault (key , defaultValue );
239
+ return map .getValueOrDefault (key , defaultValue );
228
240
}
229
241
230
242
@ JRubyMethod (visibility = PRIVATE )
0 commit comments