import sun.misc.Unsafe; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.Map; import java.util.function.BiFunction; /** * Anyfied API alternative to VarHandle * * @author peter.levart@gmail.com */ public abstract class VarAccessor { private static final Map, BiFunction, String, VarAccessor>> factories = new HashMap, BiFunction, String, VarAccessor>>(); static { factories.put(Any.class, ForByte::new); factories.put(Any.class, ForChar::new); factories.put(Any.class, ForShort::new); factories.put(Any.class, ForInt::new); factories.put(Any.class, ForLong::new); factories.put(Any.class, ForFloat::new); factories.put(Any.class, ForDouble::new); factories.put(Any.class, ForObject::new); } public static VarAccessor findField(Class refc, String name) { BiFunction, String, VarAccessor> factory = factories.get(Any.class); if (factory == null) { throw new IllegalArgumentException("Unsupported VarAccessor type"); } @SuppressWarnings("unchecked") VarAccessor va = (VarAccessor) factory.apply(refc, name); return va; } final Class refc; final Class type; final long offset; VarAccessor(Class refc, String name) { this.refc = refc; try { Field f = refc.getDeclaredField(name); if (Modifier.isStatic(f.getModifiers())) { throw new RuntimeException("Can only access non-static fields"); } type = f.getType(); if (type.isPrimitive() && type != Any.type()) { throw new RuntimeException( "Field: " + f + " has different type from 'V' in VarAccessor<...,V> instantiation"); } offset = UN.SAFE.objectFieldOffset(f); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } } final T checkTarget(T target) { if (target == null) throw new NullPointerException(); if (!refc.isInstance(target)) throw classCastException(target.getClass(), refc); return target; } static ClassCastException classCastException(Class from, Class to) { return new ClassCastException("Can not cast " + from + " to " + to); } // public API public abstract V get(T target); public abstract void set(T target, V value); public abstract V getAcquire(T target); public abstract void setRelease(T target, V value); public abstract V getVolatile(T target); public abstract void setVolatile(T target, V value); public boolean compareAndSet(T target, V cmpValue, V newValue) { throw new UnsupportedOperationException(); } public V getAndAdd(T target, V addition) { throw new UnsupportedOperationException(); } public V addAndGet(T target, V addition) { throw new UnsupportedOperationException(); } public V getAndSet(T target, V newValue) { throw new UnsupportedOperationException(); } // complete implementations for int and long static class ForInt extends VarAccessor { ForInt(Class refc, String name) { super(refc, name); } @Override public int get(T target) { return UN.SAFE.getInt(checkTarget(target), offset); } @Override public void set(T target, int value) { UN.SAFE.putInt(checkTarget(target), offset, value); } @Override public int getAcquire(T target) { int v = UN.SAFE.getInt(checkTarget(target), offset); UN.SAFE.loadFence(); return v; } @Override public void setRelease(T target, int value) { UN.SAFE.putOrderedInt(checkTarget(target), offset, value); } @Override public int getVolatile(T target) { return UN.SAFE.getIntVolatile(checkTarget(target), offset); } @Override public void setVolatile(T target, int value) { UN.SAFE.putIntVolatile(checkTarget(target), offset, value); } @Override public boolean compareAndSet(T target, int cmpValue, int newValue) { return UN.SAFE.compareAndSwapInt(checkTarget(target), offset, cmpValue, newValue); } @Override public int getAndAdd(T target, int addition) { return UN.SAFE.getAndAddInt(checkTarget(target), offset, addition); } @Override public int addAndGet(T target, int addition) { return UN.SAFE.getAndAddInt(checkTarget(target), offset, addition) + addition; } @Override public int getAndSet(T target, int newValue) { return UN.SAFE.getAndSetInt(checkTarget(target), offset, newValue); } } static class ForLong extends VarAccessor { ForLong(Class refc, String name) { super(refc, name); } @Override public long get(T target) { return UN.SAFE.getLong(checkTarget(target), offset); } @Override public void set(T target, long value) { UN.SAFE.putLong(checkTarget(target), offset, value); } @Override public long getAcquire(T target) { long v = UN.SAFE.getLong(checkTarget(target), offset); UN.SAFE.loadFence(); return v; } @Override public void setRelease(T target, long value) { UN.SAFE.putOrderedLong(checkTarget(target), offset, value); } @Override public long getVolatile(T target) { return UN.SAFE.getLongVolatile(checkTarget(target), offset); } @Override public void setVolatile(T target, long value) { UN.SAFE.putLongVolatile(checkTarget(target), offset, value); } @Override public boolean compareAndSet(T target, long cmpValue, long newValue) { return UN.SAFE.compareAndSwapLong(checkTarget(target), offset, cmpValue, newValue); } @Override public long getAndAdd(T target, long addition) { return UN.SAFE.getAndAddLong(checkTarget(target), offset, addition); } @Override public long addAndGet(T target, long addition) { return UN.SAFE.getAndAddLong(checkTarget(target), offset, addition) + addition; } @Override public long getAndSet(T target, long newValue) { return UN.SAFE.getAndSetLong(checkTarget(target), offset, newValue); } } // implementation static class ForObject extends VarAccessor { ForObject(Class refc, String name) { super(refc, name); } private V checkValue(V value) { if (value != null && !type.isInstance(value)) { throw classCastException(value.getClass(), type); } return value; } @SuppressWarnings("unchecked") @Override public V get(T target) { return (V) UN.SAFE.getObject(checkTarget(target), offset); } @Override public void set(T target, V value) { UN.SAFE.putObject(checkTarget(target), offset, checkValue(value)); } @SuppressWarnings("unchecked") @Override public V getAcquire(T target) { V v = (V) UN.SAFE.getObject(checkTarget(target), offset); UN.SAFE.loadFence(); return v; } @Override public void setRelease(T target, V value) { UN.SAFE.putOrderedObject(checkTarget(target), offset, checkValue(value)); } @SuppressWarnings("unchecked") @Override public V getVolatile(T target) { return (V) UN.SAFE.getObjectVolatile(checkTarget(target), offset); } @Override public void setVolatile(T target, V value) { UN.SAFE.putObjectVolatile(checkTarget(target), offset, checkValue(value)); } @Override public boolean compareAndSet(T target, V cmpValue, V newValue) { return UN.SAFE.compareAndSwapObject(checkTarget(target), offset, cmpValue, checkValue(newValue)); } @SuppressWarnings("unchecked") @Override public V getAndSet(T target, V newValue) { return (V) UN.SAFE.getAndSetObject(checkTarget(target), offset, checkValue(newValue)); } } // incomplete implementations for other primitives... static class ForByte extends VarAccessor { ForByte(Class refc, String name) { super(refc, name); } @Override public byte get(T target) { return UN.SAFE.getByte(checkTarget(target), offset); } @Override public void set(T target, byte value) { UN.SAFE.putByte(checkTarget(target), offset, value); } @Override public byte getAcquire(T target) { byte v = UN.SAFE.getByte(checkTarget(target), offset); UN.SAFE.loadFence(); return v; } @Override public void setRelease(T target, byte value) { UN.SAFE.storeFence(); UN.SAFE.putByte(checkTarget(target), offset, value); } @Override public byte getVolatile(T target) { return UN.SAFE.getByteVolatile(checkTarget(target), offset); } @Override public void setVolatile(T target, byte value) { UN.SAFE.putByteVolatile(checkTarget(target), offset, value); } } static class ForChar extends VarAccessor { ForChar(Class refc, String name) { super(refc, name); } @Override public char get(T target) { return UN.SAFE.getChar(checkTarget(target), offset); } @Override public void set(T target, char value) { UN.SAFE.putChar(checkTarget(target), offset, value); } @Override public char getAcquire(T target) { char v = UN.SAFE.getChar(checkTarget(target), offset); UN.SAFE.loadFence(); return v; } @Override public void setRelease(T target, char value) { UN.SAFE.storeFence(); UN.SAFE.putChar(checkTarget(target), offset, value); } @Override public char getVolatile(T target) { return UN.SAFE.getCharVolatile(checkTarget(target), offset); } @Override public void setVolatile(T target, char value) { UN.SAFE.putCharVolatile(checkTarget(target), offset, value); } } static class ForShort extends VarAccessor { ForShort(Class refc, String name) { super(refc, name); } @Override public short get(T target) { return UN.SAFE.getShort(checkTarget(target), offset); } @Override public void set(T target, short value) { UN.SAFE.putShort(checkTarget(target), offset, value); } @Override public short getAcquire(T target) { short v = UN.SAFE.getShort(checkTarget(target), offset); UN.SAFE.loadFence(); return v; } @Override public void setRelease(T target, short value) { UN.SAFE.storeFence(); UN.SAFE.putShort(checkTarget(target), offset, value); } @Override public short getVolatile(T target) { return UN.SAFE.getShortVolatile(checkTarget(target), offset); } @Override public void setVolatile(T target, short value) { UN.SAFE.putShortVolatile(checkTarget(target), offset, value); } } static class ForFloat extends VarAccessor { ForFloat(Class refc, String name) { super(refc, name); } @Override public float get(T target) { return UN.SAFE.getFloat(checkTarget(target), offset); } @Override public void set(T target, float value) { UN.SAFE.putFloat(checkTarget(target), offset, value); } @Override public float getAcquire(T target) { float v = UN.SAFE.getFloat(checkTarget(target), offset); UN.SAFE.loadFence(); return v; } @Override public void setRelease(T target, float value) { UN.SAFE.storeFence(); UN.SAFE.putFloat(checkTarget(target), offset, value); } @Override public float getVolatile(T target) { return UN.SAFE.getFloatVolatile(checkTarget(target), offset); } @Override public void setVolatile(T target, float value) { UN.SAFE.putFloatVolatile(checkTarget(target), offset, value); } } static class ForDouble extends VarAccessor { ForDouble(Class refc, String name) { super(refc, name); } @Override public double get(T target) { return UN.SAFE.getDouble(checkTarget(target), offset); } @Override public void set(T target, double value) { UN.SAFE.putDouble(checkTarget(target), offset, value); } @Override public double getAcquire(T target) { double v = UN.SAFE.getDouble(checkTarget(target), offset); UN.SAFE.loadFence(); return v; } @Override public void setRelease(T target, double value) { UN.SAFE.storeFence(); UN.SAFE.putDouble(checkTarget(target), offset, value); } @Override public double getVolatile(T target) { return UN.SAFE.getDoubleVolatile(checkTarget(target), offset); } @Override public void setVolatile(T target, double value) { UN.SAFE.putDoubleVolatile(checkTarget(target), offset, value); } } // for use as type token or 'T' type extractor static class Any { private T t; static Class type() { try { return Any.class.getDeclaredField("t").getType(); } catch (Exception e) { throw new InternalError(e); } } } // un.safe static class UN { static final Unsafe SAFE; static { try { Field uf = Unsafe.class.getDeclaredField("theUnsafe"); uf.setAccessible(true); SAFE = (Unsafe) uf.get(null); } catch (Exception e) { throw new InternalError(e); } } } }