Package st.gravel.support.jvm.runtime

Source Code of st.gravel.support.jvm.runtime.PolymorphicCallSite$CacheEntry

package st.gravel.support.jvm.runtime;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;

import st.gravel.support.jvm.ArrayExtensions;

public abstract class PolymorphicCallSite extends BaseCallSite {

  private static final MethodHandle TYPE_TEST_METHOD_HANDLE = getTypeTestMethodHandle();
  private static final MethodHandle NIL_TEST_METHOD_HANDLE = getNilTestMethodHandle();

  public static boolean typeTest(Object receiver,
      Class testClass) {
    return receiver != null && receiver.getClass() == testClass;
  }

  public static boolean nilTest(Object receiver) {
    return receiver == null;
  }

  protected static MethodHandle getTypeTestMethodHandle() {
    try {
      return MethodHandles.lookup().findStatic(
          PolymorphicCallSite.class,
          "typeTest",
          MethodType.methodType(boolean.class, Object.class,
              Class.class));
    } catch (NoSuchMethodException | IllegalAccessException e) {
      throw new RuntimeException(e);
    }
  }

  protected static MethodHandle getNilTestMethodHandle() {
    try {
      return MethodHandles.lookup()
          .findStatic(
              PolymorphicCallSite.class,
              "nilTest",
              MethodType.methodType(boolean.class, Object.class));
    } catch (NoSuchMethodException | IllegalAccessException e) {
      throw new RuntimeException(e);
    }
  }

  protected CacheEntry[] cache;

  public static class CacheEntry {
    public CacheEntry(Class<? extends Object> receiverClass,
        MethodHandle methodHandle) {
      super();
      this.receiverClass = receiverClass;
      this.methodHandle = methodHandle;
    }

    public final Class<? extends Object> receiverClass;
    public final MethodHandle methodHandle;
  }

  public PolymorphicCallSite(Lookup lookup, MethodType type, String selector) {
    super(lookup, type, selector);
  }

  @Override
  protected synchronized void resetCache() {
    this.cache = new CacheEntry[0];
  }

  private MethodHandle lookupMethodForNil() {
    MethodHandle castHandle = findMethodForNil();
    addCacheEntry(null, castHandle);
    return castHandle;
  }

  private MethodHandle lookupMethod(final Class receiverClass) {
    MethodHandle castHandle = findMethod(receiverClass);
    addCacheEntry(receiverClass, castHandle);
    return castHandle;
  }

  protected abstract MethodHandle findMethodForNil();

  protected abstract MethodHandle findMethod(Class receiverClass);

  @Override
  protected synchronized void addTargetToCache(Object receiver) {
    if (receiver == null) {
      if (cacheIncludesReceiverClass(null))
        return;
      lookupMethodForNil();
    } else {
      Class<? extends Object> receiverClass = receiver.getClass();
      if (cacheIncludesReceiverClass(receiverClass))
        return;
      lookupMethod(receiverClass);
    }
    setTargetFromCache();
  }

  private boolean cacheIncludesReceiverClass(
      Class<? extends Object> receiverClass) {
    for (CacheEntry entry : cache) {
      if (entry.receiverClass == receiverClass)
        return true;
    }
    return false;
  }

  private MethodHandle getGuardedMethod(CacheEntry entry,
      MethodHandle fallback) {
    MethodHandle test = entry.receiverClass == null ? NIL_TEST_METHOD_HANDLE
         : MethodHandles.insertArguments(
        TYPE_TEST_METHOD_HANDLE, 1, entry.receiverClass);
    Class[] tail = ArrayExtensions.tail(type.parameterArray());
    test = MethodHandles.dropArguments(test, 1, tail);
    test = test.asType(MethodType.methodType(Boolean.TYPE,
        type.parameterArray()));
    MethodHandle guard1 = MethodHandles.guardWithTest(test,
        entry.methodHandle, fallback);
    return guard1;
  }

  private void addCacheEntry(final Class receiverClass,
      MethodHandle castHandle) {
//    if (cache.length == 0 && receiverClass != null) {
//      cache = ArrayExtensions.copyWith_(cache, new CacheEntry(null,
//          findMethodForNil()));
//    }
    cache = ArrayExtensions.copyWith_(cache, new CacheEntry(receiverClass,
        castHandle));
  }

  private void setTargetFromCache() {
    MethodHandle sum = fallback;
    for (int i = cache.length - 1; i >= 0; i--) {
      CacheEntry entry = cache[i];
      sum = getGuardedMethod(entry, sum);
    }
    setTarget(sum);
  }
 
}
TOP

Related Classes of st.gravel.support.jvm.runtime.PolymorphicCallSite$CacheEntry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.