Package erjang.beam

Source Code of erjang.beam.BIFUtil$BIFHandler

/**
* This file is part of Erjang - A JVM-based Erlang VM
*
* Copyright (c) 2009 by Trifork
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/

package erjang.beam;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;

import org.objectweb.asm.Type;

import erjang.EAtom;
import erjang.EBig;
import erjang.EDouble;
import erjang.ENative;
import erjang.EObject;
import erjang.EProc;
import erjang.ERT;
import erjang.ESmall;
import erjang.m.erlang.BinOps;
import erjang.m.erlang.ErlBif;

/**
* Used by the compiler to find and mange BIF definitions.
*
* To add bifs, add the classes to the first "static" block below.
*
* @author krab
*/
public class BIFUtil {
  public static final Type EOBJECT_TYPE = Type.getType(EObject.class);

  public static final Type EPROC_TYPE = Type.getType(EProc.class);
  static Map<String, BIFHandler> bifs = new HashMap<String, BIFHandler>();
  static Map<String, BIFHandler> guard_bifs = new HashMap<String, BIFHandler>();

  static {
    try {
      loadBIFs(new String[]{"erlang", "error_logger", "ets", "lists", "math",
                  "net_kernel", "os", "re", "unicode",
                                  "io_lib", "crypto", "file", "binary" });
    } catch (Exception e) {
      throw new Error("Missing native module", e);
    }
  }

  static class Args {
    Class<?>[] args;
    private Args generic;
    private int code;

    Args(Type[] types) {
      args = new Class[types.length];
      for (int i = 0; i < types.length; i++) {
        if (types[i] == Type.DOUBLE_TYPE) {
          args[i] = double.class;
          continue;
        }
        if (types[i] == Type.INT_TYPE) {
          args[i] = int.class;
          continue;
        }
        try {
          args[i] = Class.forName(types[i].getClassName());
        } catch (ClassNotFoundException e) {

          if (types[i] == Type.BOOLEAN_TYPE) {
            args[i] = boolean.class;
          } else if (types[i] == Type.INT_TYPE) {
            args[i] = int.class;
          } else if (types[i] == Type.DOUBLE_TYPE) {
            args[i] = double.class;
          } else {
            throw new Error(e);
          }
        }
      }
    }

    public Args(Class<?>[] a) {
      this.args = a;
    }

    @Override
    public int hashCode() {
      if (code != 0)
        return code;
      for (int i = 0; i < args.length; i++) {
        code += args[i].getName().hashCode();
      }
      for (Class<?> c : args) {
        code += c.hashCode();
      }
      return code;
    }

    @Override
    public boolean equals(Object obj) {
      if (obj instanceof Args) {
        Args other = (Args) obj;
        if (other.args.length == args.length) {

          for (int i = 0; i < args.length; i++) {
            if (!args[i].equals(other.args[i])) {
              return false;
            }
          }

          return true;
        }
      }
      return false;
    }

    @Override
    public String toString() {
      StringBuilder sb = new StringBuilder("(");
      boolean first = true;
      for (Class<?> c : args) {
        if (!first)
          sb.append(",");
        else
          first = false;
        sb.append(c.getName());
      }
      sb.append(")");
      return sb.toString();
    }

    public Args generic() {

      if (generic == null) {
        Class<?>[] a = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
          a[i] = EObject.class;
        }
        generic = new Args(a);
      }

      return generic;
    }

    /**
     * @return
     */
    public List<Args> generalize() {
      ArrayList<Args> res = new ArrayList<Args>();

      Class<?>[] aa = this.args.clone();

      for (int i = 0; i < args.length; i++) {
        // aa = this.args.clone();

        // vary over arg[i]'s super types
        for (Class<?> c = args[i]; !c.equals(Object.class); c = super_class(c)) {
          aa[i] = c;
          res.add(new Args(aa.clone()));

          for (int j = i + 1; j < args.length; j++) {

            for (Class<?> cc = args[j]; !cc.equals(Object.class); cc = super_class(cc)) {
              aa[j] = cc;
              res.add(new Args(aa.clone()));
            }
          }
        }
      }

      return res;
    }

    private Class<?> super_class(Class<?> c) {
      if (c.isPrimitive()) {
        if (c == double.class)
          return EDouble.class;
        if (c == int.class)
          return ESmall.class;
        if (c == long.class)
          return EBig.class;
        if (c == boolean.class)
          return EAtom.class;
        return EObject.class;
      } else {
        return c.getSuperclass();
      }
    }
  }

  static class BIFHandler {

    Map<Args, BuiltInFunction> found = new HashMap<Args, BuiltInFunction>();

    private final String name;
    private final String javaName;

    @Override
    public int hashCode() {
      return name.hashCode() + javaName.hashCode()
        + found.values().hashCode();
    }
   
    public BIFHandler(String name) {
      this.name = name;
      this.javaName = name;
    }

    public BIFHandler(String name, String javaName) {
      this.name = name;
      this.javaName = javaName;
    }

    public Type getResult(Type[] parmTypes) {
      BuiltInFunction method = getMethod(parmTypes);
      if (method == null) {
        throw new Error("no bif name " + this.name + " for parms "
            + new Args(parmTypes));
      }
      return method.getReturnType();
    }

    public void registerMethod(Method method) {
      Args a;
     
      Class<?>[] pt = method.getParameterTypes();
     
      if (!Modifier.isStatic(method.getModifiers())) {
        Class<?>[] all = new Class[pt.length + 1];
        all[0] = method.getDeclaringClass();
        System.arraycopy(pt, 0, all, 1, pt.length);
        a = new Args(all);
      } else {
        a = new Args(pt);
      }
     
      found.put(a, new BuiltInFunction(method));
    }

    /**
     * @param parmTypes
     * @return
     */
    public BuiltInFunction getMethod(Type[] parmTypes) {

      BuiltInFunction m = find_bif(parmTypes);
      if (m != null)
        return m;

      // try with EProc as first argument
      if (parmTypes.length == 0 || !EPROC_TYPE.equals(parmTypes[0])) {
        Type[] extra = new Type[parmTypes.length + 1];
        extra[0] = EPROC_TYPE;
        for (int i = 0; i < parmTypes.length; i++) {
          extra[i + 1] = parmTypes[i];
        }

        m = find_bif(extra);
        if (m != null)
          return m;
      }

      return m;

    }

    private BuiltInFunction find_bif(Type[] parmTypes) {
      Args args = new Args(parmTypes);
      BuiltInFunction m = found.get(args);
      if (m != null) {
        return m;
      }

      for (Args a : args.generalize()) {
        m = found.get(a);
        if (m != null) {
          if (ERT.log.isLoggable(Level.FINE))
            ERT.log.fine("missed opportunity erlang:"
              + EAtom.intern(name) + "/" + parmTypes.length + " "
              + args + ", \n\tusing " + m);

          return m;
        }
      }
      return null;
    }

  }

  public static Type getBifResult(String module, String name, Type[] parmTypes,
      boolean isGuard) {

    Map<String, BIFHandler> tab = isGuard ? guard_bifs : bifs;

    BIFHandler bif = null;
    String key = module + ":" + name;
    if (tab.containsKey(key)) {
      bif = tab.get(key);
    } else {
      throw new Error("no " + (isGuard ? "guard" : "normal")
          + " bif named "+module+":'" + name + "'/" + parmTypes.length );
    }

    return bif.getResult(parmTypes);
  }

  @SuppressWarnings("unchecked")
  private static void loadBIFs(String[] mods) throws Exception {
    for (String mod : mods) {
      Class<ENative> en =
        (Class<ENative>) Class.forName("erjang.m." + mod + ".Native");
      registerBifs(mod, en);
      ENative enative = en.newInstance();
      for (Class<?> c : enative.getNativeClasses()) {
        if (c != en) {
          registerBifs(mod, c);
        }
      }
    }

    registerBifs("erlang", ERT.class);
    registerBifs("erlang", EObject.class);
    registerBifs("erlang", ESmall.class);
    registerBifs("erlang", EBig.class);
  }
 
  public static void registerBifs(String module, Class<?> clazz) {
    Method[] m = clazz.getMethods();
    for (int i = 0; i < m.length; i++) {
      Method method = m[i];
      erjang.BIF ann = method.getAnnotation(erjang.BIF.class);
      if (ann != null) {

        if ((method.getModifiers() & Modifier.STATIC) != Modifier.STATIC) {
        //  System.out.println("non-static BIF "+method);
        }

        Map<String, BIFHandler> tab = ann.type() == erjang.BIF.Type.GUARD ? guard_bifs
            : bifs;

        String bifName = ann.name();
        if (bifName.equals("__SELFNAME__")) {
          bifName = method.getName();
        }
       
        String key = module + ":" + bifName;
       
        BIFHandler h = tab.get(key);
        if (h == null) {
          tab.put(key, h = new BIFHandler(bifName));
        }

        h.registerMethod(method);
      }
    }
  }

  public static BuiltInFunction getMethod(String module, String name, int arity,
      boolean isGuard, boolean fail_when_missing)
  {
    return getMethod(module, name, eobjectParmTypes(arity),
             isGuard, fail_when_missing);
  }

  private static Type[] eobjectParmTypes(int length) {
    // TODO: cache these!
    Type[] res = new Type[length];
    for (int i = 0; i < length; i++) {
      res[i] = EOBJECT_TYPE;
    }
    return res;
  }

  /**
   * @param name
   * @param parmTypes
   * @param fail_when_missing TODO
   * @param b
   * @return
   */
  public static BuiltInFunction getMethod(String module, String name, Type[] parmTypes,
      boolean isGuard, boolean fail_when_missing) {

    Map<String, BIFHandler> tab = isGuard ? guard_bifs : bifs;

    BIFHandler bif = null;
    String key = module + ":" + name;
    if (tab.containsKey(key)) {
      bif = tab.get(key);
    } else if (fail_when_missing) {
      throw new Error("no " + (isGuard ? "guard" : "normal")
          + " bif named " + module+ ":'" + name + "'/" + parmTypes.length);
    } else {
      return null;
    }

    return bif.getMethod(parmTypes);
  }

  /**
   * @param module TODO
   * @param name
   * @param args
   * @param isGuard
   * @param fail_when_missing TODO
   * @return
   */
  public static BuiltInFunction getMethod(String module, String name,
      Arg[] args, boolean isGuard, boolean fail_when_missing) {
    Type[] parms = new Type[args.length];
    for (int i = 0; i < args.length; i++) {
      parms[i] = args[i].type;
    }
    return getMethod(module, name, parms, isGuard, fail_when_missing);
  }

  public static BuiltInFunction getMethod(EAtom module, EAtom function,
      int arity, boolean isGuard, boolean failWhenMissing) {
    return getMethod(module.getName(), function.getName(), arity, isGuard, failWhenMissing);
  }

  static long all_bif_hash = 0;
  public static long all_bif_hash() {
    if (all_bif_hash == 0) {
      for (BIFHandler b : bifs.values()) {
        all_bif_hash += b.hashCode();
      }

      for (BIFHandler b : guard_bifs.values()) {
        all_bif_hash += b.hashCode();
      }
    }
   
    return all_bif_hash;
  }

}
TOP

Related Classes of erjang.beam.BIFUtil$BIFHandler

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.