Package erjang.beam

Source Code of erjang.beam.Compiler$ErjangDetector

/**
* 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.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.CRC32;
import java.util.zip.CheckedInputStream;

import kilim.analysis.ClassInfo;
import kilim.analysis.ClassWeaver;
import kilim.mirrors.Detector;
import kilim.mirrors.ClassMirrorNotFoundException;
import kilim.mirrors.Mirrors;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.util.CheckClassAdapter;

import com.ericsson.otp.erlang.OtpAuthException;

import erjang.EBinary;
import erjang.EFun;
import erjang.EObject;
import erjang.ERT;
import erjang.ETuple;
import erjang.beam.analysis.BeamTypeAnalysis;
import erjang.ErjangCodeCache;

import erjang.beam.loader.ErjangBeamDisLoader;

public class Compiler implements Opcodes {
  private ClassRepo classRepo;

  /**
   * @param repo
   * @throws IOException
   * @throws OtpAuthException
   *
   */
  public Compiler(ClassRepo repo) throws OtpAuthException, IOException {
    this.classRepo = repo;
  }

  public static void compile(BeamFileData data, ClassRepo repo) throws IOException {
    // reset thread-local data
    ClassWeaver.reset();
   
    // class writer, phase 4
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);

    // class checker, optional phase
    //CheckClassAdapter ca = new CheckClassAdapter(cw);

    // the java bytecode generator, phase 3
    CompilerVisitor cv = new CompilerVisitor(cw, repo);

    // the type analysis, phase 2
    BeamTypeAnalysis analysis = new BeamTypeAnalysis(cv);

    // the module analyzer, phase 1 (not chained to phase 2)
    ModuleAnalyzer ma = new ModuleAnalyzer();
    data.accept(ma);

    cv.setFunInfos(ma.getFunInfos());

    try {
      // go!
      data.accept(analysis);
    } catch (Error e) {
      e.printStackTrace();
    }

    byte[] byteArray = cw.toByteArray();

     // to emit pre-kilim code [for debugging] 
    repo.store("raw/"+cv.getInternalClassName(), byteArray);

    boolean written = false;
    ClassWeaver cwe = new ClassWeaver(byteArray, new ErjangDetector(
        cv.getInternalClassName(), cv.non_pausable_methods));
    cwe.weave();
    for (ClassInfo ci : cwe.getClassInfos()) {
      String name = ci.className;
      byte[] bytes = ci.bytes;

      String iname = name.replace('.', '/');
      if (iname.equals(cv.getInternalClassName())) {
        written = true;
      }

      repo.store(iname, bytes);
    }

    if (!written) {
      // no pausable functions in module!
      repo.store(cv.getInternalClassName(), byteArray);
    }
  }

  public void compile(File file, BeamLoader beam_parser) throws IOException {
    EBinary eb = EUtil.readFile(file);
    BeamFileData bfd = beam_parser.load(eb.getByteArray());
    compile(bfd, this.classRepo);
  }

  static public class ErjangDetector extends Detector {

    private final String className;
    private final Set<String> nonPausableMethods;

    /**
     * @param className
     * @param nonPausableMethods
     * @param mirrors
     */
    public ErjangDetector(String className, Set<String> nonPausableMethods) {
      super(Detector.DEFAULT.mirrors);
      this.className = className;
      this.nonPausableMethods = nonPausableMethods;
    }

   
    static Pattern FUN = Pattern.compile("^erjang\\.m\\..*\\$FN_.*__([0-9])+$");
   
    /* (non-Javadoc)
     * @see kilim.analysis.Detector#getSuperClasses(java.lang.String)
     */
    @Override
    public ArrayList<String> getSuperClasses(String cc)
        throws ClassMirrorNotFoundException {
      Matcher m = FUN.matcher(cc);
      if (m.matches()) {
        int arity = Integer.parseInt(m.group(1));
       
        ArrayList<String> result = new ArrayList<String>();
        result.add(EFun.class.getName()+arity);
        result.add(EFun.class.getName());
        result.add(EObject.class.getName());
        result.add(Object.class.getName());
        return result;
      }
     
      return super.getSuperClasses(cc);
    }
   
    @Override
    public int getPausableStatus(String className, String methodName,
        String desc) {

      // System.out.println("status? "+className+"#"+methodName+""+desc);

      if (className.startsWith(CompilerVisitor.ETUPLE_NAME)) {
        return Detector.METHOD_NOT_PAUSABLE;
      }

      if (className.startsWith(CompilerVisitor.EFUN_NAME)) {
        if (methodName.equals("go"))
          return Detector.PAUSABLE_METHOD_FOUND;
        if (methodName.equals("invoke"))
          return Detector.PAUSABLE_METHOD_FOUND;

        return Detector.METHOD_NOT_PAUSABLE;
      }

      if (className.equals(this.className)) {
        if (methodName.endsWith("$tail"))
          return Detector.METHOD_NOT_PAUSABLE;
        if (methodName.endsWith("init>"))
          return Detector.METHOD_NOT_PAUSABLE;
        if (methodName.equals("module_name"))
          return Detector.METHOD_NOT_PAUSABLE;
        if (nonPausableMethods.contains(methodName))
          return Detector.METHOD_NOT_PAUSABLE;
        return Detector.PAUSABLE_METHOD_FOUND;
      }

      return super.getPausableStatus(className, methodName, desc);
    }
  }

  public static String moduleClassName(String moduleName) {
    String cn = EUtil.toJavaIdentifier(moduleName);

    String base = "erjang/m/" + cn + "/" + cn;

    return base;

  }

  public static void main(String[] args) throws Exception {

    File out_dir = new File("target/compiled");
    out_dir.mkdirs();
    BeamLoader beamParser = new ErjangBeamDisLoader();

    for (int i = 0; i < args.length; i++) {
      if (args[i].endsWith(".beam")) {
        File in = new File(args[i]);
        if (!in.exists() || !in.isFile() || !in.canRead())
          throw new IOException("bad permissions for " + in);

        int idx = args[i].lastIndexOf('.');
        int idx0 = args[i].lastIndexOf(File.separator);

        String shortName = args[i].substring(idx0 + 1, idx);
        File out = new File(out_dir, ErjangCodeCache.moduleJarFileName(shortName, crcFile(in))); // TODO: don't use the code cache location.
        JarClassRepo jcp = new JarClassRepo(out);

        System.out.println("compiling " + in + " -> " + out + " ...");
        new Compiler(jcp).compile(in, beamParser);

        jcp.close();
      }
    }
  }

  private static long crcFile(File file) throws IOException {

    CheckedInputStream cis = null;
    long fileSize = 0;
    cis = new CheckedInputStream(new FileInputStream(file), new CRC32());
    try {
      byte[] buf = new byte[4 * 1024];
      while (cis.read(buf) >= 0)
        ;

      return cis.getChecksum().getValue();
    } finally {
      cis.close();
    }
  }
}
TOP

Related Classes of erjang.beam.Compiler$ErjangDetector

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.