FTR: JVM Lang Summit presentation

Remi Forax forax at univ-mlv.fr
Tue Sep 2 18:02:13 UTC 2014


On 09/02/2014 06:59 PM, Paul Sandoz wrote:
> On Aug 8, 2014, at 11:34 PM, Remi Forax <forax at univ-mlv.fr> wrote:
>> Something along :
>>
>>   private static MethodHandle compareAndSet(Lookup lookup, Class<?> declaringClass, String fieldName, Class<?> fieldType)
>>         throws NoSuchFieldException, IllegalAccessException {
>>     MethodHandle getter = lookup.findGetter(declaringClass, fieldName, fieldType);
>>     MethodHandleInfo methodHandleInfo = lookup.revealDirect(getter);
>>     Field field = methodHandleInfo.reflectAs(Field.class, lookup);
>>     long offset = UNSAFE.objectFieldOffset(field);
>>     MethodHandle mh = MethodHandles.insertArguments(COMPARE_AND_SWAP_OBJECT, 1, offset);
>>     return mh.asType(MethodType.methodType(boolean.class, declaringClass, fieldType, fieldType));
>>   }
>>
>>   public class VarHandle<T, U> {
>>     private final @Stable MethodHandle compareAndSet;
>>
>>     VarHandle(MethodHandle compareAndSet) {
>>         this.compareAndSet = compareAndSet;
>>     }
>>
>>     public boolean compareAndSet(T object, U expected, U value) {
>>       try {
>>         return (boolean)compareAndSet.invoke(object, expected, value);
>>       } catch (Throwable e) {
>>         if (e instanceof RuntimeException) throw (RuntimeException)e;
>>         if (e instanceof Error) throw (Error)e;
>>         throw new AssertionError(e);
>>       }
>>     }
>>   }
>>
> (FWIW i initially modified the DHM code to expose out MethodHandles to CAS etc along similar lines to existing DHMs and LFs corresponding to get/putfield.)
>
> Performance-wise, as of now, the above is likely to be slower or on a par with AtomicReferenceFieldUpdater or reflection (if there was a CAS op on Field). Perhaps it will eventually be possible to achieve that with the above, but from what John says it sounds like much investigation is required.

back from vacation too,
slowly trying to anwser to a pile of emails ...

I was to answer yes, but I think the code can be modified a little to 
avoid the invoke() and use invokeExact instead
so what about:

private static MethodHandle compareAndSet(Lookup lookup, Class<?> declaringClass, String fieldName, Class<?> fieldType)
        throws NoSuchFieldException, IllegalAccessException {
    MethodHandle getter = lookup.findGetter(declaringClass, fieldName, fieldType);
    MethodHandleInfo methodHandleInfo = lookup.revealDirect(getter);
    Field field = methodHandleInfo.reflectAs(Field.class, lookup);
    long offset = UNSAFE.objectFieldOffset(field);
    MethodHandle mh = MethodHandles.insertArguments(COMPARE_AND_SWAP_OBJECT, 1, offset);
    return mh.asType(MethodType.methodType(boolean.class, declaringClass, fieldType, fieldType))
              asType(MethodType.methodType(boolea,.class, Object.class, Object.class, Object.class));
  }

  public class VarHandle<T, U> {
    private final @Stable MethodHandle compareAndSet;

    VarHandle(MethodHandle compareAndSet) {
        this.compareAndSet = compareAndSet;
    }

    public boolean compareAndSet(T object, U expected, U value) {
      try {
        return (boolean)compareAndSet.invokeExact(object, expected, value);
      } catch (Throwable e) {
        if (e instanceof RuntimeException) throw (RuntimeException)e;
        if (e instanceof Error) throw (Error)e;
        throw new AssertionError(e);
      }
    }
  }

if the VarHandle is stored in a static final, the JIT should be able to 
remove the downcast/upcast pair.

>
> Any replacement of Unsafe in j.u.concurrent classes has to be almost, if not, as performant as that of direct Unsafe usage. It's proving quite useful to have something that works along similar fundamental lines (w.r.t. method invocation) that already gets quite close to Unsafe performance and from which we can evaluate and improve certain aspects.

Anyway, i still think that the best way to write a safe compareAndSet is 
not to use a Varandle or any polymorphic signature method, but to let 
the compiler generate an invokedynamic with the right signature. The 
bootstrap method will verify the signature once (at link time) and so 
the generated method handle will only do downcasts to j.l.Object, 
something that the JIT will trivially consider as a no-op.

>
> Paul.

Rémi



More information about the valhalla-dev mailing list