Package erjang.beam

Source Code of erjang.beam.ModuleAnalyzer$FunInfo

package erjang.beam;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import erjang.EAtom;
import erjang.EObject;
import erjang.ERT;
import erjang.FunID;
import erjang.beam.repr.Insn;
import erjang.beam.repr.Insn.IE;
import erjang.beam.repr.Insn.IL;
import erjang.beam.repr.Insn.ILI;
import erjang.beam.repr.Operands.Label;
import erjang.beam.repr.Operands.SourceOperand;

public class ModuleAnalyzer implements ModuleVisitor {

  static Logger log = Logger.getLogger("erjang.beam.analyze");
  Map<Label, FunInfo> info = new HashMap<Label, FunInfo>();

  static class FunInfo {
    Set<FunInfo> callers = new HashSet<FunInfo>();
    Set<FunInfo> tail_callers = new HashSet<FunInfo>();
    FunID name;
    boolean may_return_tail_marker, is_pausable, call_is_pausable;
    public boolean exported;
    protected boolean is_called_locally_in_tail_position;
    protected boolean is_anon_fun;
    protected boolean is_called_locally_in_nontail_position;
    protected boolean call_on_load;

    boolean mustHaveFun() {
      return exported
        || is_called_locally_in_tail_position
        || is_anon_fun;
    }
   
    @Override
    public String toString() {
      return (may_return_tail_marker ? "T" : "-") + (is_pausable ? "P" : "-")
          + " " + name;

    }

    void addCaller(FunInfo caller) {
      callers.add(caller);
    }

    void addTailCaller(FunInfo caller) {
      tail_callers.add(caller);
    }

    @Override
    public int hashCode() {
      return name.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
      if (obj instanceof FunInfo) {
        FunInfo fi = (FunInfo) obj;
        return name.equals(fi.name);
      }
      return false;
    }
  }

  void propagate() {
    while (propagate_one())
      ;
  }

  /** */
  boolean propagate_one() {
    boolean effect = false;

    for (FunInfo fun : info.values()) {
      if (fun.is_pausable || fun.call_is_pausable) {
        for (FunInfo caller : fun.callers) {
         
          if (!caller.is_pausable) {
            effect = caller.is_pausable = true;
           
            if (log.isLoggable(Level.FINE)) {
              log.fine("propagate " +fun+ " -> " + caller);
            }
          }
        }

        for (FunInfo caller : fun.tail_callers) {
         
          if (!caller.call_is_pausable) {
            effect = caller.call_is_pausable = true;
           
            if (log.isLoggable(Level.FINE)) {
              log.fine("propagate " +fun+ " -> " + caller);
            }
          }
        }
     
      }
    }

    return effect;
  }

  FunInfo get(Label label) {
    FunInfo fi = info.get(label);
    if (fi == null) {
      fi = new FunInfo();
      info.put(label, fi);
    }

    return fi;
  }

  FunInfo get(EAtom fun, int arity, Label label) {
    FunInfo fi = get(label);
    fi.name = new FunID(name, fun, arity);
    return fi;
  }

  private EAtom name;

  @Override
  public void visitAttribute(EAtom att, EObject value) {
  }

  @Override
  public void visitCompile(EAtom att, EObject value) {
  }

  @Override
  public void visitExport(EAtom fun, int arity, int entry) {
    Label label = new Label(entry);
    FunInfo fi = get(label);
    fi.exported = true;
  }


  @Override
  public void visitEnd() {
    propagate();

    if (log.isLoggable(Level.FINE)) {
    for (Map.Entry<Label, FunInfo> e : info.entrySet()) {
      log.fine(e.getValue().toString());
    }
    }

  }
 
  @Override
  public void declareFunction(EAtom fun, int arity, int startLabel) {
    Label label = new Label(startLabel);
    get(fun,arity,label);
  }

  @Override
  public FunctionVisitor visitFunction(EAtom name, int arity,
      final int startLabel) {
   
    if (log.isLoggable(Level.FINE)) {
      log.fine("== analyzing "+ModuleAnalyzer.this.name+":"+name+"/"+arity);
    }

    Label start = new Label(startLabel);
    final FunInfo self = get(name, arity, start);

    return new FunctionVisitor() {

      @Override
      public BlockVisitor visitLabeledBlock(int label) {

        return new BlockVisitor() {

          @Override
          public void visitInsn(Insn insn) {

            BeamOpcode op;
            switch (op = insn.opcode()) {

            case on_load:
              self.call_on_load = true;
              break;

            case send: {
              if (log.isLoggable(Level.FINE) && !self.is_pausable) {
                log.fine("pausable: send");
              }
             
              self.is_pausable = true;
              break;
            }
           
            case call: {
              Insn.IL cl = (Insn.IL) insn;
              FunInfo target = get(cl.label);
             
              BuiltInFunction bif =
                BIFUtil.getMethod(target.name.module,
                  target.name.function, target.name.arity, false, false);

              if (bif == null) {             
                target.addCaller(self);
                target.is_called_locally_in_nontail_position = true;
              }
              break;
            }

            case call_last: {
              ILI cl = (Insn.ILI) insn;
              boolean is_self_call = cl.label.nr == startLabel; 
              self.may_return_tail_marker |= !is_self_call;
              FunInfo target = get(cl.label);
             
              BuiltInFunction bif =
                BIFUtil.getMethod(target.name.module,
                  target.name.function, target.name.arity, false, false);

              if (bif == null) {             
                target.addTailCaller(self);
                target.is_called_locally_in_tail_position |= !is_self_call;
              }
              break;
            }

            case call_only: {
              IL cl = (Insn.IL) insn;
              boolean is_self_call = cl.label.nr == startLabel;
              self.may_return_tail_marker |= !is_self_call;
              FunInfo target = get(cl.label);
              BuiltInFunction bif =                
                BIFUtil.getMethod(target.name.module,
                  target.name.function, target.name.arity, false, false);

              if (bif == null) {             
                target.addTailCaller(self);
                target.is_called_locally_in_tail_position |= !is_self_call;
              }
              break;
            }
           
            case make_fun2: {
              Insn.F fi = (Insn.F) insn;
              Label anon = new Label(fi.anon_fun.label);
              get(anon).is_anon_fun = true;
              break;
            }

            case apply_last:
            case i_call_fun_last: {
              if (log.isLoggable(Level.FINE) && !self.call_is_pausable) {
                log.fine("call_pausable: " + op);
              }

              self.may_return_tail_marker = true;
              self.call_is_pausable = true;
              break;
            }

            case call_ext_last:
            case call_ext_only:
            {
              Insn.IE e = (IE) insn;

              String mod = e.ext_fun.mod.getName();
              String fun = e.ext_fun.fun.getName();
              int arity = e.ext_fun.arity;
             
              if (mod.equals("erlang")
                && arity == 1
                && (fun.equals("throw") || fun.equals("error") || fun.equals("exit") || fun.equals("nif_error"))) {
                break;
              }
            }             
             
            {
              if (log.isLoggable(Level.FINE) && !self.call_is_pausable) {
                log.fine("call_pausable: " + op);
              }

              Insn.IE e = (IE) insn;
              String mod = e.ext_fun.mod.getName();
              String fun = e.ext_fun.fun.getName();
              int arity = e.ext_fun.arity;
              BuiltInFunction bif = BIFUtil.getMethod(mod,
                  fun, arity, false, false);
             
              if (bif != null) {
               
                if (log.isLoggable(Level.FINE) && !self.is_pausable && bif.isPausable()) {
                  log.fine("pausable: calls " + bif.javaMethod);
                }

               
                self.is_pausable |= bif.isPausable();
                break;
              }
             
              self.may_return_tail_marker = true;
              self.call_is_pausable = true;
              /* FALL THRU */
            }

            case call_ext:
              if (self.is_pausable) {
                break;
              }
             
              Insn.IE e = (IE) insn;

              String mod = e.ext_fun.mod.getName();
              String fun = e.ext_fun.fun.getName();
              int arity = e.ext_fun.arity;
              BuiltInFunction bif = BIFUtil.getMethod(mod,
                  fun, arity, false, false);
             
              if (bif != null) {
               
                if (log.isLoggable(Level.FINE) && !self.is_pausable && bif.isPausable()) {
                  log.fine("pausable: calls " + bif.javaMethod);
                }

               
                self.is_pausable |= bif.isPausable();
               

              } else if (op == BeamOpcode.call_ext) {

                if (log.isLoggable(Level.FINE) && !self.is_pausable) {
                  log.fine("pausable: calls "+mod+":"+fun+"/"+arity);
                }

                self.is_pausable = true;
              }

              break;

            case apply:
            case call_fun:
            case wait:
            case wait_timeout:
              if (log.isLoggable(Level.FINE) && !self.is_pausable) {
                log.fine("pausable: "+op);
              }
              self.is_pausable = true;
             
              break;

            case bif:
            case bif0:
            case bif1:
            case bif2: {
              // no reason to go through this pain, if we're
              // already pausable
              if (self.is_pausable)
                break;

              Insn.Bif bi = (Insn.Bif) insn;
              EAtom name = bi.ext_fun.fun;
              SourceOperand[] srcs = bi.args;

              bif = BIFUtil.getMethod("erlang",
                  name.getName(), srcs.length,
                  false, true);
             
              if (bif == null) {
                throw new Error("missing bif: "+bi.ext_fun);
              }

              self.is_pausable |= bif.isPausable();

              if (log.isLoggable(Level.FINE) && self.is_pausable) {
                log.fine("pausable: calls "+bif.javaMethod);
              }

            }
            default:
              break;
            }

          }

          @Override
          public void visitEnd() {
          }
        };

      }

      @Override
      public void visitEnd() {
      }
    };

  }

  @Override
  public void visitModule(EAtom name) {
    this.name = name;
  }

  public Map<FunID,FunInfo> getFunInfos() {
   
   
   
    Map<FunID, FunInfo> res = new HashMap<FunID, FunInfo>();
   
    for (FunInfo fi : info.values()) {
      res.put(fi.name, fi);
    }
   
    return res;

   
  }

}
TOP

Related Classes of erjang.beam.ModuleAnalyzer$FunInfo

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.