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
This commit is contained in:
@@ -17,12 +17,15 @@
|
|||||||
package org.jetbrains.jet.compiler.runner;
|
package org.jetbrains.jet.compiler.runner;
|
||||||
|
|
||||||
import com.intellij.util.Function;
|
import com.intellij.util.Function;
|
||||||
|
import kotlin.Function1;
|
||||||
|
import kotlin.KotlinPackage;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.cli.common.messages.MessageCollector;
|
import org.jetbrains.jet.cli.common.messages.MessageCollector;
|
||||||
import org.jetbrains.jet.preloading.ClassCondition;
|
import org.jetbrains.jet.preloading.ClassCondition;
|
||||||
import org.jetbrains.jet.preloading.ClassPreloadingUtils;
|
import org.jetbrains.jet.preloading.ClassPreloadingUtils;
|
||||||
import org.jetbrains.jet.utils.KotlinPaths;
|
import org.jetbrains.jet.utils.KotlinPaths;
|
||||||
|
import org.jetbrains.jet.utils.UtilsPackage;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.ref.SoftReference;
|
import java.lang.ref.SoftReference;
|
||||||
@@ -30,8 +33,10 @@ import java.lang.reflect.Method;
|
|||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.util.Arrays;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
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.CompilerMessageLocation.NO_LOCATION;
|
||||||
import static org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity.ERROR;
|
import static org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity.ERROR;
|
||||||
@@ -55,32 +60,45 @@ public class CompilerRunnerUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static List<File> compilerClasspath(@NotNull File libs) {
|
private static File compilerJar(@NotNull File libPath) {
|
||||||
return Arrays.asList(
|
return new File(libPath, "kotlin-compiler.jar");
|
||||||
new File(libs, "kotlin-compiler.jar"),
|
|
||||||
new File(libs, "kotlin-runtime.jar")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static ClassLoader createPreloader(
|
private static String loadCompilerClasspathSpaceSeparated(@NotNull File libPath) throws IOException {
|
||||||
@NotNull File libPath,
|
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 ClassLoader parentClassLoader,
|
||||||
@Nullable ClassCondition classToLoadByParent
|
@Nullable ClassCondition classToLoadByParent
|
||||||
) throws IOException {
|
) throws IOException {
|
||||||
return ClassPreloadingUtils.preloadClasses(
|
List<URL> classpath = KotlinPackage.map(loadCompilerClasspathSpaceSeparated(libPath).split(" "), new Function1<String, URL>() {
|
||||||
compilerClasspath(libPath), /* estimatedClassNumber = */ 4096, parentClassLoader, classToLoadByParent
|
@Override
|
||||||
);
|
public URL invoke(String dependency) {
|
||||||
}
|
try {
|
||||||
|
return new File(libPath, dependency).toURI().toURL();
|
||||||
|
}
|
||||||
|
catch (MalformedURLException e) {
|
||||||
|
throw UtilsPackage.rethrow(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
@NotNull
|
return ClassPreloadingUtils.preloadClasses(
|
||||||
private static URLClassLoader createClassLoader(@NotNull File libPath) throws MalformedURLException {
|
Collections.singletonList(compilerJar(libPath)),
|
||||||
List<File> jars = compilerClasspath(libPath);
|
/* estimatedClassNumber = */ 4096,
|
||||||
URL[] urls = new URL[jars.size()];
|
new URLClassLoader(classpath.toArray(new URL[classpath.size()]), parentClassLoader),
|
||||||
for (int i = 0; i < urls.length; i++) {
|
classToLoadByParent
|
||||||
urls[i] = jars.get(i).toURI().toURL();
|
);
|
||||||
}
|
|
||||||
return new URLClassLoader(urls, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void handleProcessTermination(int exitCode, @NotNull MessageCollector messageCollector) {
|
private static void handleProcessTermination(int exitCode, @NotNull MessageCollector messageCollector) {
|
||||||
@@ -107,17 +125,14 @@ public class CompilerRunnerUtil {
|
|||||||
@NotNull String[] arguments,
|
@NotNull String[] arguments,
|
||||||
@NotNull CompilerEnvironment environment,
|
@NotNull CompilerEnvironment environment,
|
||||||
@NotNull MessageCollector messageCollector,
|
@NotNull MessageCollector messageCollector,
|
||||||
@NotNull PrintStream out,
|
@NotNull PrintStream out
|
||||||
boolean usePreloader
|
|
||||||
) throws Exception {
|
) throws Exception {
|
||||||
File libPath = getLibPath(environment.getKotlinPaths(), messageCollector);
|
File libPath = getLibPath(environment.getKotlinPaths(), messageCollector);
|
||||||
if (libPath == null) return null;
|
if (libPath == null) return null;
|
||||||
|
|
||||||
ClassLoader classLoader = ourClassLoaderRef.get();
|
ClassLoader classLoader = ourClassLoaderRef.get();
|
||||||
if (classLoader == null) {
|
if (classLoader == null) {
|
||||||
classLoader = usePreloader
|
classLoader = createClassLoader(libPath, environment.getParentClassLoader(), environment.getClassesToLoadByParent());
|
||||||
? createPreloader(libPath, environment.getParentClassLoader(), environment.getClassesToLoadByParent())
|
|
||||||
: createClassLoader(libPath);
|
|
||||||
ourClassLoaderRef = new SoftReference<ClassLoader>(classLoader);
|
ourClassLoaderRef = new SoftReference<ClassLoader>(classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -108,8 +108,7 @@ public class KotlinCompilerRunner {
|
|||||||
"Using kotlin-home = " + environment.getKotlinPaths().getHomePath(),
|
"Using kotlin-home = " + environment.getKotlinPaths().getHomePath(),
|
||||||
CompilerMessageLocation.NO_LOCATION);
|
CompilerMessageLocation.NO_LOCATION);
|
||||||
|
|
||||||
Object rc = CompilerRunnerUtil.invokeExecMethod(compilerClassName, arguments, environment,
|
Object rc = CompilerRunnerUtil.invokeExecMethod(compilerClassName, arguments, environment, messageCollector, out);
|
||||||
messageCollector, out, /*usePreloader=*/true);
|
|
||||||
// exec() returns a K2JVMCompiler.ExitCode object, that class is not accessible here,
|
// exec() returns a K2JVMCompiler.ExitCode object, that class is not accessible here,
|
||||||
// so we take it's contents through reflection
|
// so we take it's contents through reflection
|
||||||
return CompilerRunnerUtil.getReturnCodeFromObject(rc);
|
return CompilerRunnerUtil.getReturnCodeFromObject(rc);
|
||||||
|
|||||||
Reference in New Issue
Block a user