[concurrency-interest] CAS using a MethodHandle

√iktor Ҡlang viktor.klang at gmail.com
Mon Dec 19 13:57:28 EST 2011


Hi Rémi,

if this works then it sure has a lot of promise!

Cheers,
√

On Mon, Dec 19, 2011 at 7:28 PM, Rémi Forax <forax at univ-mlv.fr> wrote:

> Hi all,
> Some time ago, I said that we should try to use a MethodHandle instead of
> an Atomic*FieldUpdater and let the VM inline the method handle so there
> should be no cost (or a little one) compared to directly calling
> unsafe.compareAndSwapObject.
>
> The following code does exactly that, I have also include a small test
> that just demonstrates that it works.
> Because I'm neither a benchmark expert nor an assembler expert, I've just
> checked that the method handle is fully inlined by the JIT and that the
> generated code seems to don't have more code than it should.
>
> I know there is a lot of experts on this list, so experts am i wrong ?
>
> cheers,
> Rémi
>
> ------------------------------**------------------------------**
> ----------------------------
> package java.util.concurrent.atomic;
>
> import java.lang.invoke.MethodHandle;
> import java.lang.invoke.**MethodHandles;
> import java.lang.invoke.MethodType;
> import java.lang.reflect.Field;
> import java.lang.reflect.Modifier;
>
> import sun.misc.Unsafe;
>
> public class Volatiles {
>  private static final Unsafe unsafe = Unsafe.getUnsafe();
>
>  private static final MethodHandle CAS_OBJECT;
>  static {
>    try {
>      CAS_OBJECT = MethodHandles.publicLookup().**bind(unsafe,
> "compareAndSwapObject",
>          MethodType.methodType(boolean.**class, Object.class, long.class,
> Object.class, Object.class));
>    } catch (NoSuchMethodException|**IllegalAccessException e) {
>      throw new AssertionError(e.getMessage(), e);
>    }
>  }
>
>  public static MethodHandle compareAnSet(Class<?> declaringClass, String
> fieldName) {
>      Field field;
>      int modifiers;
>      try {
>        field = declaringClass.**getDeclaredField(fieldName);
>        Class<?> caller = sun.reflect.Reflection.**getCallerClass(2);
>        modifiers = field.getModifiers();
>        sun.reflect.misc.ReflectUtil.**ensureMemberAccess(
>            caller, declaringClass, null, modifiers);
>        sun.reflect.misc.ReflectUtil.**checkPackageAccess(**
> declaringClass);
>      } catch (NoSuchFieldException|**IllegalAccessException e) {
>        throw new IllegalArgumentException(e);
>      }
>
>      if (Modifier.isStatic(modifiers)) {
>        throw new IllegalArgumentException("**Field must not be static");
>      }
>      if (!Modifier.isVolatile(**modifiers)) {
>        throw new IllegalArgumentException("**Field must be volatile");
>      }
>
>      long offset = unsafe.objectFieldOffset(**field);
>      MethodHandle mh = MethodHandles.insertArguments(**CAS_OBJECT, 1,
> offset);
>      Class<?> fieldType = field.getType();
>      return mh.asType(MethodType.**methodType(boolean.class,
> declaringClass, fieldType, fieldType));
>  }
> }
>
> ------------------------------**------------------------------**-------
> import java.lang.invoke.MethodHandle;
> import java.util.concurrent.atomic.**Volatiles;
>
>
> public class CASTest {
>  static class Link<E> {
>    final E element;
>    final Link<E> next;
>
>    Link(E element, Link<E> next) {
>      this.element = element;
>      this.next = next;
>    }
>  }
>
>  static class LinkedLink<E> {
>    private volatile Link<E> head;
>
>    private static final MethodHandle headCAS = Volatiles.compareAnSet(**LinkedLink.class,
> "head");
>
>    public void add(E element) {
>      try {
>        for(;;) {
>          Link<E> head = this.head;
>          Link<E> link = new Link<>(element, head);
>          if ((boolean)headCAS.invokeExact(**this, head, link)) {
>            return;
>          }
>        }
>      } catch (Throwable e) {
>        throw new AssertionError(e.getMessage(), e);
>      }
>    }
>
>    @Override
>    public String toString() {
>      StringBuilder builder = new StringBuilder().append('[');
>      for(Link<?> l = head; l!= null; l = l.next) {
>        builder.append(l.element).**append(", ");
>      }
>      int length = builder.length();
>      if (length != 0) {
>        builder.setLength(length - 2);
>      }
>      return builder.append(']').toString()**;
>    }
>  }
>
>
>  public static void main(String[] args) {
>    LinkedLink<String> list = new LinkedLink<>();
>
>    for(int i=0; i<100000; i++) {
>      list.add(Integer.toString(i));
>    }
>
>    //System.out.println(list);
>  }
> }
>
>
>
> ______________________________**_________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.**oswego.edu <Concurrency-interest at cs.oswego.edu>
> http://cs.oswego.edu/mailman/**listinfo/concurrency-interest<http://cs.oswego.edu/mailman/listinfo/concurrency-interest>
>



-- 
Viktor Klang

Akka Tech Lead
Typesafe <http://www.typesafe.com/> - Enterprise-Grade Scala from the
Experts

Twitter: @viktorklang
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20111219/ce74ed48/attachment.html>


More information about the Concurrency-interest mailing list