001/*
002 * Copyright (c) 2012-2018 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others
003 *
004 * This program and the accompanying materials are made available under the
005 * terms of the Eclipse Public License 2.0 which is available at
006 * http://www.eclipse.org/legal/epl-2.0.
007 *
008 * SPDX-License-Identifier: EPL-2.0
009 */
010
011package org.eclipse.golo.compiler;
012
013import java.io.InputStream;
014import java.util.List;
015
016import gololang.ir.GoloModule;
017
018/**
019 * Provides a facility to dynamically load Golo source code and access the generated code from a dedicated class loader.
020 * <p>
021 * Golo source files can be compiled and the resulting JVM bytecode be injected into the class loader. It is important
022 * to note that this class loader definition is not thread safe.
023 * <p>
024 * This class loader does not support reloading. Attempts to load source files that may produce the same bytecode
025 * definitions will resulting in exceptions.
026 */
027public class GoloClassLoader extends ClassLoader {
028
029  private final GoloCompiler compiler;
030
031  /**
032   * Creates a class loader from a parent.
033   *
034   * @param parent the parent classloader.
035   */
036  public GoloClassLoader(ClassLoader parent) {
037    super(parent);
038    compiler = new GoloCompiler();
039  }
040
041  /**
042   * Creates a class loader from the default parent.
043   */
044  public GoloClassLoader() {
045    super();
046    compiler = new GoloCompiler();
047  }
048
049  public GoloCompiler getCompiler() {
050    return this.compiler;
051  }
052
053  /**
054   * Compiles and loads the resulting JVM bytecode for a Golo source file.
055   *
056   * @param goloSourceFilename    the source file name.
057   * @param sourceCodeInputStream the source input stream.
058   * @return the class matching the Golo module defined in the source.
059   * @throws GoloCompilationException if either of the compilation phase failed.
060   */
061  public synchronized Class<?> load(String goloSourceFilename, InputStream sourceCodeInputStream) throws GoloCompilationException {
062    return load(compiler.compile(goloSourceFilename, sourceCodeInputStream));
063  }
064
065  /**
066   * Compiles and loads the resulting JVM bytecode for a Golo module IR.
067   *
068   * @param goloSourceFilename    the source file name.
069   * @param module  the Golo module IR to load.
070   * @return the class matching the Golo module defined in the IR.
071   * @throws GoloCompilationException if either of the compilation phase failed.
072   */
073  public synchronized Class<?> load(String goloSourceFilename, GoloModule module) {
074    compiler.refine(module);
075    return load(compiler.generate(module, goloSourceFilename));
076  }
077
078  private Class<?> load(List<CodeGenerationResult> results) {
079    Class<?> lastClassIsModule = null;
080    for (CodeGenerationResult result : results) {
081      byte[] bytecode = result.getBytecode();
082      lastClassIsModule = defineClass(null, bytecode, 0, bytecode.length);
083    }
084    return lastClassIsModule;
085  }
086}