33import org .jruby .*;
44import org .jruby .anno .JRubyClass ;
55import 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 .*;
69import org .jruby .runtime .Block ;
710import org .jruby .runtime .ObjectAllocator ;
811import org .jruby .runtime .ThreadContext ;
912import org .jruby .runtime .builtin .IRubyObject ;
1013import 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 ;
1514
1615import java .io .IOException ;
1716import java .util .Map ;
@@ -45,16 +44,35 @@ public static class JRubyMapBackend extends RubyObject {
4544 static final int DEFAULT_INITIAL_CAPACITY = 16 ;
4645 static final float DEFAULT_LOAD_FACTOR = 0.75f ;
4746
47+ public static final boolean CAN_USE_UNSAFE_CHM = canUseUnsafeCHM ();
48+
4849 private ConcurrentHashMap <IRubyObject , IRubyObject > map ;
4950
5051 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+ }
5257 }
5358
5459 private static ConcurrentHashMap <IRubyObject , IRubyObject > newCHM () {
5560 return newCHM (DEFAULT_INITIAL_CAPACITY , DEFAULT_LOAD_FACTOR );
5661 }
5762
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+
5876 private static boolean isCausedBySecurityException (Throwable t ) {
5977 while (t != null ) {
6078 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) {
114132
115133 @ JRubyMethod
116134 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 >() {
118136 @ Override
119137 public IRubyObject apply (IRubyObject key ) {
120138 return block .yieldSpecific (context );
@@ -124,7 +142,7 @@ public IRubyObject apply(IRubyObject key) {
124142
125143 @ JRubyMethod
126144 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 >() {
128146 @ Override
129147 public IRubyObject apply (IRubyObject key , IRubyObject oldValue ) {
130148 IRubyObject result = block .yieldSpecific (context , oldValue == null ? context .getRuntime ().getNil () : oldValue );
@@ -136,7 +154,7 @@ public IRubyObject apply(IRubyObject key, IRubyObject oldValue) {
136154
137155 @ JRubyMethod
138156 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 >() {
140158 @ Override
141159 public IRubyObject apply (IRubyObject key , IRubyObject oldValue ) {
142160 IRubyObject result = block .yieldSpecific (context , oldValue == null ? context .getRuntime ().getNil () : oldValue );
@@ -148,7 +166,7 @@ public IRubyObject apply(IRubyObject key, IRubyObject oldValue) {
148166
149167 @ JRubyMethod
150168 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 >() {
152170 @ Override
153171 public IRubyObject apply (IRubyObject oldValue , IRubyObject newValue ) {
154172 IRubyObject result = block .yieldSpecific (context , oldValue == null ? context .getRuntime ().getNil () : oldValue );
@@ -164,20 +182,14 @@ public RubyBoolean replace_pair(IRubyObject key, IRubyObject oldValue, IRubyObje
164182 }
165183
166184 @ 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+ }
170188
171189 @ JRubyMethod
172190 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 ;
181193 }
182194
183195 @ JRubyMethod
@@ -224,7 +236,7 @@ public RubyFixnum size(ThreadContext context) {
224236
225237 @ JRubyMethod
226238 public IRubyObject get_or_default (IRubyObject key , IRubyObject defaultValue ) {
227- return map .getOrDefault (key , defaultValue );
239+ return map .getValueOrDefault (key , defaultValue );
228240 }
229241
230242 @ JRubyMethod (visibility = PRIVATE )
0 commit comments