/** -*- tab-width: 4 -*- * This file is part of Erjang - A JVM-based Erlang VM * * Copyright (c) 2010 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; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import kilim.Pausable; import erjang.beam.BeamFileData; import erjang.beam.BeamLoader; import erjang.beam.EUtil; import erjang.beam.loader.ErjangBeamDisLoader; import erjang.driver.efile.ClassPathResource; import erjang.util.Progress; /** Handles the part of module loading that involves going from module name, * or module name plus beam file name, to a BeamFileData representation; * and chooses how to convert that into an EModule instance. * The EModule instance may be compiled, interpreted, or whatever. * * The entire procedure looks roughly like this: * - File resolution: from module name to beam file name. * - File reading: from beam file name to raw beam data. * - Beam parsing: From raw beam data to beam representation (BeamFileData). * - Module creation: From beam representation to executable module (EModule). */ public class EModuleLoader { static final Logger log = Logger.getLogger("erjang.module.load"); final static BeamLoader beamParser = new ErjangBeamDisLoader(); /*==================== API ====================*/ public static EModule find_and_load_module(String moduleName) throws IOException { File input = findBeamFile(moduleName); if (input == null) throw new FileNotFoundException(moduleName); // Is this the right error message? return load_module(moduleName, EUtil.readFile(input)); } static long acc_int_load = 0; static long acc_load = 0; public static EModule load_module(String moduleName, EBinary beamBin) throws IOException { // This is where the module creation mode is selected. boolean use_interpreter = ErjangConfig.getBoolean("erjang.beam.option.i"); long before = System.currentTimeMillis(); long after; EModule loaded_module; Progress.activity("loading "+moduleName+"..."); if (use_interpreter || moduleName.startsWith("elixir_compiler_")) { BeamFileData bfd = beamParser.load(beamBin.toByteArray()); loaded_module = erjang.beam.interpreter.Interpreter.beamFileToEModule(bfd); after = System.currentTimeMillis(); } else { // Use compiler EModuleClassLoader moduleClassLoader; try { moduleClassLoader = ErjangCodeCache.getModuleClassLoader(moduleName, beamBin, beamParser); } catch (RuntimeException e) { moduleClassLoader = null; } if (moduleClassLoader != null) { after = System.currentTimeMillis(); loaded_module = load_compiled_module(moduleName, moduleClassLoader); } else { log.warning("Compiling "+moduleName+" failed - falling back to interpreter"); BeamFileData bfd = beamParser.load(beamBin.toByteArray()); loaded_module = erjang.beam.interpreter.Interpreter.beamFileToEModule(bfd); after = System.currentTimeMillis(); } } if (log.isLoggable(Level.FINE)) { long after_load = System.currentTimeMillis(); if (use_interpreter) acc_int_load += (after_load-after); else acc_load += (after_load-after); log.fine("[" + moduleName + ":" + ""+(after-before)+"ms" + ";"+(after_load-after)+"ms]" + "("+acc_load+")"); } Progress.done(); return loaded_module; } /*==================== BEAM FILE RESOLUTION STEP ====================*/ private static File findBeamFile(String module) { String n = module; for (File e : loadPath) { File beam = new File(e, n + ".beam"); if (beam.exists()) return beam; if (ClassPathResource.read_file(beam.getPath()) != null) return beam; } return null; } final static List<File> loadPath = new ArrayList<File>(); static { String sys_path = System.getenv("ERJ_PATH"); if (sys_path != null) addLoadPaths(loadPath, sys_path); String path = ErjangConfig.getString("erjang.path", "."); addLoadPaths(loadPath, path); } private static void addLoadPaths(List<File> out, String path) { for (String s : path.split(File.pathSeparator)) { File elem = ERT.newFile(s); if (elem.exists() && elem.isDirectory()) { out.add(elem); } } } /*==================== MODULE CREATION STEP ====================*/ @SuppressWarnings("unchecked") public static EModule load_compiled_module(String mod, EModuleClassLoader loader) { if (log.isLoggable(Level.FINE)) { log.fine("EML| load_compiled_module: "+mod+" @ "+loader); } String internalName = erjang.beam.Compiler.moduleClassName(mod); String java_name = internalName.replace('/', '.'); Class<? extends EModule> clazz; try { clazz = (Class<? extends EModule>) loader.loadClass(java_name); } catch (ClassNotFoundException e1) { e1.printStackTrace(); throw new ErlangError(e1); } EModule mi; try { mi = clazz.newInstance(); } catch (Exception e) { e.printStackTrace(); throw new ErlangError(e); } return mi; } public static EObject call_on_load_function(EProc proc, EAtom modName) throws Pausable { EModule mod = EModuleManager.get_loaded_module(modName); if (mod == null) { throw ERT.badarg(modName); } return mod.on_load(proc); } }