Package st.gravel.support.jvm.runtime

Source Code of st.gravel.support.jvm.runtime.MethodTools

package st.gravel.support.jvm.runtime;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;

import st.gravel.core.Symbol;
import st.gravel.support.compiler.ast.SelectorConverter;
import st.gravel.support.jvm.ArrayExtensions;

public class MethodTools {
  private static final SelectorConverter selectorConverter = (SelectorConverter) SelectorConverter.factory
      .r_new();
  private static final HashMap<Class, Class> primitiveMap = buildPrimitiveMap();

  public static java.lang.reflect.Method searchForStaticMethod(Class type,
      String name, int numArgs) {
   
    Class primType = primitiveMap.get(type);
    if ((primType != null) && (numArgs >= 1)) {
      Class[] params = new Class[numArgs];
      params[0]= primType;
      Method method = searchForMethod(type, name, params, true);
      if (method != null ) return method;
    }
    return searchForMethod(type, name, numArgs, true);
  }
 
  private static HashMap<Class, Class> buildPrimitiveMap() {
    HashMap<Class, Class> hashMap = new HashMap<Class,Class>();
    hashMap.put(Boolean.class, Boolean.TYPE);
    hashMap.put(Integer.class, Integer.TYPE );
    hashMap.put(Long.class, Long.TYPE );
    hashMap.put(Double.class, Double.TYPE );
    hashMap.put(Float.class, Float.TYPE );
    hashMap.put(Boolean.class, Boolean.TYPE );
    hashMap.put(Character.class, Character.TYPE );
    hashMap.put(Byte.class, Byte.TYPE );
    hashMap.put(Void.class, Void.TYPE );
    hashMap.put(Short.class, Short.TYPE );
    return hashMap;
  }

  public static java.lang.reflect.Method searchForMethod(Class type,
      String name, int numArgs, boolean isStatic) {
    return searchForMethod(type, name, numArgs, isStatic, true);
  }

  public static java.lang.reflect.Method searchForMethod(Class type,
      String name, int numArgs, boolean isStatic, boolean mayCast) {
    java.lang.reflect.Method[] methods = type.getMethods();
    Method best = null;
    for (int i = 0; i < methods.length; i++) {
      // Has to be named the same of course.
      if (!(methods[i].getName().equals(name)))
        continue;
      if (!(Modifier.isStatic(methods[i].getModifiers()) == isStatic))
        continue;

      Class[] types = methods[i].getParameterTypes();

      // Does it have the same number of arguments that we're looking for.
      if (types.length != numArgs)
        continue;

      // Check for type compatibility
      if (best == null) {
        best = methods[i];

      } else {
        if (mayCast ? areTypesCompatible(methods[i].getParameterTypes(),
            best.getParameterTypes()) : areTypesSame(methods[i].getParameterTypes(),
                best.getParameterTypes())) {
          best = methods[i];
        }
      }
    }
    return best;
  }

  // Following from:
  // http://code.google.com/p/tuprolog/source/browse/2p/branches/TRY-ManninoClassLoading/src/alice/util/InspectionUtils.java?spec=svn639&r=639
  //
  public static java.lang.reflect.Method searchForMethod(Class type,
      String name, Class[] parms, boolean isStatic) {
    java.lang.reflect.Method[] methods = type.getDeclaredMethods();
    Method best = null;
    for (int i = 0; i < methods.length; i++) {
      // Has to be named the same of course.
      Method method = methods[i];
      if (!(method.getName().equals(name)))
        continue;
      if (!(Modifier.isStatic(method.getModifiers()) == isStatic))
        continue;

      Class[] types = method.getParameterTypes();

      // Does it have the same number of arguments that we're looking for.
      if (types.length != parms.length)
        continue;

      // Check for type compatibility
      if (areTypesCompatible(types, parms))
        if (best == null) {
          best = method;

        } else {
          if (method.getDeclaringClass() != best
              .getDeclaringClass()) {
            best = method.getDeclaringClass().isAssignableFrom(
                best.getDeclaringClass()) ? best : method;
          } else {
            if ((ArrayExtensions.equals_(types,
                best.getParameterTypes()))) {
              if (isStatic)
                throw new RuntimeException("Weird");
            } else {
              throw new RuntimeException("TODO: Multiple matches");
            }
          }
        }
    }
    return best;
  }

  public static boolean areTypesSame(Class<?>[] targets,
      Class<?>[] sources) {
    if (targets.length != sources.length)
      return (false);

    for (int i = 0; i < targets.length; i++) {
      if (sources[i] == null)
        continue;

      if (targets[i].isInterface()) {
        Class<?>[] interfaces = sources[i].getInterfaces();
        for (Class<?> in : interfaces) {
          if (targets[i].equals(in))
            return true;
        }
      }

      if (!translateFromPrimitive(targets[i]).equals(
          translateFromPrimitive(sources[i])))
        return false;
    }
    return true;
  }

  public static boolean areTypesCompatible(Class<?>[] targets,
      Class<?>[] sources) {
    if (targets.length != sources.length)
      return (false);

    for (int i = 0; i < targets.length; i++) {
      if (sources[i] == null)
        continue;

      if (targets[i].isInterface()) {
        Class<?>[] interfaces = sources[i].getInterfaces();
        for (Class<?> in : interfaces) {
          if (targets[i].equals(in))
            return true;
        }
      }

      if (!translateFromPrimitive(targets[i]).isAssignableFrom(
          translateFromPrimitive(sources[i])))
        return false;
    }
    return true;
  }

  public static Class<?> translateFromPrimitive(Class<?> primitive) {
    if (!primitive.isPrimitive())
      return (primitive);

    if (Boolean.TYPE.equals(primitive))
      return (Boolean.class);
    if (Character.TYPE.equals(primitive))
      return (Character.class);
    if (Byte.TYPE.equals(primitive))
      return (Byte.class);
    if (Short.TYPE.equals(primitive))
      return (Short.class);
    if (Integer.TYPE.equals(primitive))
      return (Integer.class);
    if (Long.TYPE.equals(primitive))
      return (Long.class);
    if (Float.TYPE.equals(primitive))
      return (Float.class);
    if (Double.TYPE.equals(primitive))
      return (Double.class);

    throw new RuntimeException("Error translating type:" + primitive);
  }

  public static MethodType asMethodType(Method method) {
    return MethodType.methodType(method.getReturnType(),
        method.getParameterTypes());
  }

  public static MethodHandle getHandle(Object receiver, String selectorString) {
    return getHandle(receiver, Symbol.value(selectorString));
  }

  public static MethodHandle getHandle(Object receiver, Symbol selector) {
    MethodHandle methodHandle;
    String methodName = selectorConverter.selectorAsFunctionName_(selector);

    if (receiver == null) {
      methodHandle = ImageBootstrapper.systemMapping
          .methodHandleForNil_(methodName);

    } else {
      Class receiverClass = receiver.getClass();
      methodHandle = ImageBootstrapper.systemMapping
          .methodHandleFor_methodName_(receiverClass, methodName);
    }

    return methodHandle;
  }

  public static Object perform(Object receiver, Symbol selector)
      throws Throwable {
    MethodHandle handle = getHandle(receiver, selector);
    return handle.invoke(receiver);
  }

  public static Object perform(Object receiver, Symbol selector, Object arg1)
      throws Throwable {
    MethodHandle handle = getHandle(receiver, selector);
    return handle.invoke(receiver, arg1);
  }

  public static Object perform(Object receiver, Symbol selector, Object arg1,
      Object arg2) throws Throwable {
    MethodHandle handle = getHandle(receiver, selector);
    return handle.invoke(receiver, arg1, arg2);
  }

  public static Object perform(Object receiver, Symbol selector, Object arg1,
      Object arg2, Object arg3) throws Throwable {
    MethodHandle handle = getHandle(receiver, selector);
    return handle.invoke(receiver, arg1, arg2, arg3);
  }

  public static Object perform(Object receiver, Symbol selector, Object arg1,
      Object arg2, Object arg3, Object arg4) throws Throwable {
    MethodHandle handle = getHandle(receiver, selector);
    return handle.invoke(receiver, arg1, arg2, arg3, arg4);
  }

  public static Object perform_withArguments_(Object receiver,
      Symbol selector, Object[] arguments) throws Throwable {
    MethodHandle handle = getHandle(receiver, selector);
    return handle.bindTo(receiver).invokeWithArguments(arguments);
  }

  public static Object perform(Object receiver, String selector)
      throws Throwable {
    MethodHandle handle = getHandle(receiver, selector);
    return handle.invoke(receiver);
  }

  public static Object perform(Object receiver, String selector, Object arg1)
      throws Throwable {
    MethodHandle handle = getHandle(receiver, selector);
    return handle.invoke(receiver, arg1);
  }

  public static Object safePerform(Object receiver, String selector) {
    try {
      return perform(receiver, selector);
    } catch (Throwable e) {
      if (e instanceof RuntimeException) throw (RuntimeException) e;
      throw new RuntimeException(e);
    }
  }

  public static Object safePerform(Object receiver, String selector,
      Object arg1) {
    try {
      return perform(receiver, selector, arg1);
    } catch (Throwable e) {
      throw new RuntimeException(e);
    }
  }

  public static void debugTest(String reference, String selector) throws Throwable {
    Object testcase = ImageBootstrapper.systemMapping.singletonAtReferenceString_(reference);
    MethodTools.perform(testcase, "debug:", (Symbol.value(selector)));
  }

}
TOP

Related Classes of st.gravel.support.jvm.runtime.MethodTools

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.