FTR: JVM Lang Summit presentation

Remi Forax forax at univ-mlv.fr
Wed Sep 3 15:28:40 UTC 2014


On 09/03/2014 04:44 PM, Paul Sandoz wrote:
> On Sep 2, 2014, at 8:02 PM, Remi Forax <forax at univ-mlv.fr> wrote:
>> back from vacation too,
>> slowly trying to anwser to a pile of emails ...
>>
> I know how you feel :-)

A drawback of the 5 weeks of vacation policy in France :)

>
>
>> 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.
>>
> Thanks, that's a rather neat trick!
>
> It triggered the following thought, why not just do (assuming identical access control checks on construction of the handle):
>
>      public boolean compareAndSet_direct(R r, V e, V v) {
>          r.getClass(); // check for null
>          MethodHandleImpl.castReference(rType, r);
>          MethodHandleImpl.castReference(vType, e);
>          MethodHandleImpl.castReference(vType, v);
>          return MethodHandleStatics.UNSAFE.compareAndSwapObject(r, v_offset, e, v);
>      }
>
> There is no class spinning and the inline trace is much smaller (although much could be reduced with specific D-like MHs).
>
> I experimented a bit with both of the above (see end of email for code) and each gets really rather close perf-wise and assembly-wise. I never quite realized how aggressive the JIT is at optimizing this area. Those casts can get reduced to almost no-ops (like the possibly redundant cast of the value in accessor DHMs). There are some redundant null-checks, as previously discussed on core-libs.

I use mh instead of plain code to avoid profile pollution. The profile 
is attached to the mh tree so you have as many profile sites as 
VarHandles instead of having one (or three in fact) profile site for all 
VarHandles. Maybe it's not needed, I don't know.

>
> Are those casts always guaranteed to get optimized away if the handle is static final and an invocation on that handle is inlined?

good question, indeed.

>
>
>>> 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.
>>
> I consider that as possible further steps, requiring some syntax bike shedding and a mechanism for how javac produces the indy call. Regardless we still need to evaluate the low-level plumbing.

but what you call a 'further step' removes the need to those 
castReference calls, making the low-level plumbing easier.

>
> Paul.
>
>

Rémi



More information about the valhalla-dev mailing list