From 7de9a3f029c98f5171980d8be329fabb7cd70834 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 15 Dec 2014 13:08:42 +0300 Subject: [PATCH] Load compiler dependencies in a separate class loader in IDE compiler runner To be able to invoke the intermediate compiler built on the first step of bootstrap: in contrast to the distributed compiler, it's incompatible with the runtime produced by itself and should instead be run with the runtime in the classpath which was used to compile it. Drop the non-preloader mode of running compiler, because it would require using a special parent-last class loader with exceptions specified by ClassCondition --- .../compiler/runner/CompilerRunnerUtil.java | 65 ++++++++++++------- .../compiler/runner/KotlinCompilerRunner.java | 3 +- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/CompilerRunnerUtil.java b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/CompilerRunnerUtil.java index f8efcecbd30..ef74f50ee58 100644 --- a/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/CompilerRunnerUtil.java +++ b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/CompilerRunnerUtil.java @@ -17,12 +17,15 @@ package org.jetbrains.jet.compiler.runner; import com.intellij.util.Function; +import kotlin.Function1; +import kotlin.KotlinPackage; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.cli.common.messages.MessageCollector; import org.jetbrains.jet.preloading.ClassCondition; import org.jetbrains.jet.preloading.ClassPreloadingUtils; import org.jetbrains.jet.utils.KotlinPaths; +import org.jetbrains.jet.utils.UtilsPackage; import java.io.*; import java.lang.ref.SoftReference; @@ -30,8 +33,10 @@ import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; -import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.jar.Attributes; +import java.util.jar.JarFile; import static org.jetbrains.jet.cli.common.messages.CompilerMessageLocation.NO_LOCATION; import static org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity.ERROR; @@ -55,32 +60,45 @@ public class CompilerRunnerUtil { } @NotNull - private static List compilerClasspath(@NotNull File libs) { - return Arrays.asList( - new File(libs, "kotlin-compiler.jar"), - new File(libs, "kotlin-runtime.jar") - ); + private static File compilerJar(@NotNull File libPath) { + return new File(libPath, "kotlin-compiler.jar"); } @NotNull - private static ClassLoader createPreloader( - @NotNull File libPath, + private static String loadCompilerClasspathSpaceSeparated(@NotNull File libPath) throws IOException { + JarFile jar = new JarFile(compilerJar(libPath)); + try { + return (String) jar.getManifest().getMainAttributes().get(Attributes.Name.CLASS_PATH); + } + finally { + jar.close(); + } + } + + @NotNull + private static ClassLoader createClassLoader( + @NotNull final File libPath, @Nullable ClassLoader parentClassLoader, @Nullable ClassCondition classToLoadByParent ) throws IOException { - return ClassPreloadingUtils.preloadClasses( - compilerClasspath(libPath), /* estimatedClassNumber = */ 4096, parentClassLoader, classToLoadByParent - ); - } + List classpath = KotlinPackage.map(loadCompilerClasspathSpaceSeparated(libPath).split(" "), new Function1() { + @Override + public URL invoke(String dependency) { + try { + return new File(libPath, dependency).toURI().toURL(); + } + catch (MalformedURLException e) { + throw UtilsPackage.rethrow(e); + } + } + }); - @NotNull - private static URLClassLoader createClassLoader(@NotNull File libPath) throws MalformedURLException { - List jars = compilerClasspath(libPath); - URL[] urls = new URL[jars.size()]; - for (int i = 0; i < urls.length; i++) { - urls[i] = jars.get(i).toURI().toURL(); - } - return new URLClassLoader(urls, null); + return ClassPreloadingUtils.preloadClasses( + Collections.singletonList(compilerJar(libPath)), + /* estimatedClassNumber = */ 4096, + new URLClassLoader(classpath.toArray(new URL[classpath.size()]), parentClassLoader), + classToLoadByParent + ); } private static void handleProcessTermination(int exitCode, @NotNull MessageCollector messageCollector) { @@ -107,17 +125,14 @@ public class CompilerRunnerUtil { @NotNull String[] arguments, @NotNull CompilerEnvironment environment, @NotNull MessageCollector messageCollector, - @NotNull PrintStream out, - boolean usePreloader + @NotNull PrintStream out ) throws Exception { File libPath = getLibPath(environment.getKotlinPaths(), messageCollector); if (libPath == null) return null; ClassLoader classLoader = ourClassLoaderRef.get(); if (classLoader == null) { - classLoader = usePreloader - ? createPreloader(libPath, environment.getParentClassLoader(), environment.getClassesToLoadByParent()) - : createClassLoader(libPath); + classLoader = createClassLoader(libPath, environment.getParentClassLoader(), environment.getClassesToLoadByParent()); ourClassLoaderRef = new SoftReference(classLoader); } diff --git a/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/KotlinCompilerRunner.java b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/KotlinCompilerRunner.java index ec9eef259fa..df9e9f78bf5 100644 --- a/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/KotlinCompilerRunner.java +++ b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/KotlinCompilerRunner.java @@ -108,8 +108,7 @@ public class KotlinCompilerRunner { "Using kotlin-home = " + environment.getKotlinPaths().getHomePath(), CompilerMessageLocation.NO_LOCATION); - Object rc = CompilerRunnerUtil.invokeExecMethod(compilerClassName, arguments, environment, - messageCollector, out, /*usePreloader=*/true); + Object rc = CompilerRunnerUtil.invokeExecMethod(compilerClassName, arguments, environment, messageCollector, out); // exec() returns a K2JVMCompiler.ExitCode object, that class is not accessible here, // so we take it's contents through reflection return CompilerRunnerUtil.getReturnCodeFromObject(rc);