Skip to content

Commit

Permalink
Migrate NonBlockingHashMapLong to VarHandle
Browse files Browse the repository at this point in the history
This eliminates both the Unsafe code and the AtomicReference
fallback logic, plus improves atomicity along a couple paths.
  • Loading branch information
headius committed Feb 9, 2025
1 parent c78adae commit af85341
Showing 1 changed file with 20 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

import java.io.IOException;
import java.io.Serializable;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
Expand Down Expand Up @@ -82,67 +84,29 @@ public class NonBlockingHashMapLong<TypeV>

private static final int REPROBE_LIMIT = 10; // Too many reprobes then force a table-resize

private static final Unsafe _unsafe = org.jruby.util.unsafe.UnsafeHolder.U;
// --- Bits to allow Unsafe access to arrays
private static final int _Obase;
private static final int _Oscale;
private static final int _Lbase;
private static final int _Lscale;
// --- Bits to allow Unsafe CAS'ing of the CHM field
//private static final long _chm_offset;
//private static final long _val_1_offset;
private static final VarHandle objectArrayHandle = MethodHandles.arrayElementVarHandle(Object[].class);
private static final VarHandle longArrayHandle = MethodHandles.arrayElementVarHandle(long[].class);
private static final VarHandle chmHandle;
private static final VarHandle val1Handle;

static {
if ( _unsafe != null ) {
_Obase = _unsafe.arrayBaseOffset(Object[].class);
_Oscale = _unsafe.arrayIndexScale(Object[].class);
_Lbase = _unsafe.arrayBaseOffset(long[].class);
_Lscale = _unsafe.arrayIndexScale(long[].class);

//Field f; long offset;
//try {
// f = NonBlockingHashMapLong.class.getDeclaredField("_chm");
// offset = _unsafe.objectFieldOffset(f);
//}
//catch ( java.lang.NoSuchFieldException e ) { offset = 0; }
//_chm_offset = offset;
//try {
// f = NonBlockingHashMapLong.class.getDeclaredField("_val_1");
// offset = _unsafe.objectFieldOffset(f);
//}
//catch( java.lang.NoSuchFieldException e ) { offset = 0; }
//_val_1_offset = offset;
}
else {
_Obase = _Oscale = _Lbase = _Lscale = 0;
//_chm_offset = _val_1_offset = 0;
}
try {
chmHandle = MethodHandles.lookup().findVarHandle(NonBlockingHashMapLong.class, "_chm", CHM.class);
val1Handle = MethodHandles.lookup().findVarHandle(NonBlockingHashMapLong.class, "_val_1", Object.class);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}

//private final boolean CAS( final long offset, final Object old, final Object nnn ) {
// return _unsafe.compareAndSwapObject(this, offset, old, nnn );
//}

private static final AtomicReferenceFieldUpdater<NonBlockingHashMapLong, CHM> _chmUpdater =
AtomicReferenceFieldUpdater.newUpdater(NonBlockingHashMapLong.class, CHM.class, "_chm");

private final boolean CAS_chm( final CHM old, final CHM nnn ) {
return _chmUpdater.compareAndSet(this, old, nnn);
//final long offset = _chm_offset;
//return offset != 0 ?
//_unsafe.compareAndSwapObject(this, offset, old, nnn ) :
//CAS_chmFallback(old, nnn);
private boolean CAS_chm( final CHM old, final CHM nnn ) {
return chmHandle.compareAndSet(this, old, nnn);
}

private static final AtomicReferenceFieldUpdater<NonBlockingHashMapLong, Object> _val_1Updater =
AtomicReferenceFieldUpdater.newUpdater(NonBlockingHashMapLong.class, Object.class, "_val_1");

private final boolean CAS_val_1( final Object old, final Object nnn ) {
return _val_1Updater.compareAndSet(this, old, nnn);
//final long offset = _val_1_offset;
//return offset != 0 ?
//_unsafe.compareAndSwapObject(this, offset, old, nnn ) :
//CAS_val_1Fallback(old, nnn);
private boolean CAS_val_1( final Object old, final Object nnn ) {
return val1Handle.compareAndSet(this, old, nnn);
}

// --- Adding a 'prime' bit onto Values via wrapping with a junk wrapper class
Expand Down Expand Up @@ -472,35 +436,11 @@ final boolean CAS_newchm( CHM newchm ) {
// Access K,V for a given idx
private final boolean CAS_key( int idx, long old, long key ) {
assert idx >= 0 && idx < _keys.length;
if ( _unsafe != null ) {
final int rawIndex = _Lbase + idx * _Lscale;
return _unsafe.compareAndSwapLong( _keys, rawIndex, old, key );
}
return CAS_keyFallback( idx, old, key );
}
private final boolean CAS_keyFallback( int idx, long old, long key ) {
final long[] keys = this._keys;
synchronized ( keys ) { // TODO: not really same atomic semantics!
if ( keys[idx] != old ) return false;
keys[idx] = key;
}
return true;
return longArrayHandle.compareAndSet(_keys, idx, old, key);
}
private final boolean CAS_val( int idx, Object old, Object val ) {
assert idx >= 0 && idx < _vals.length;
if ( _unsafe != null ) {
final int rawIndex = _Obase + idx * _Oscale;
return _unsafe.compareAndSwapObject( _vals, rawIndex, old, val );
}
return CAS_valFallback( idx, old, val );
}
private final boolean CAS_valFallback( int idx, Object old, Object val ) {
final Object[] vals = this._vals;
synchronized ( vals ) { // TODO: not really same atomic semantics!
if ( vals[idx] != old ) return false;
vals[idx] = val;
}
return true;
return objectArrayHandle.compareAndSet(_vals, idx, old, val);
}

final long [] _keys;
Expand Down

0 comments on commit af85341

Please sign in to comment.