From 1ba6d5361bd4986a96540c5bffdf0bb847b0a6e9 Mon Sep 17 00:00:00 2001 From: Alexey Tsvetkov Date: Wed, 14 Nov 2018 12:45:18 +0300 Subject: [PATCH] Run in-process compiler in separate thread The compiler uses thread local values, so when the compiler runs Gradle's thread, it leaks classes preventing a compiler's classloader from being collected. #KT-28037 fixed --- .../GradleKotlinCompilerWork.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt index ccc2af96221..258c2bbf54f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.compilerRunner import org.gradle.api.Project +import org.gradle.api.invocation.Gradle import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity @@ -24,7 +25,11 @@ import org.slf4j.LoggerFactory import java.io.* import java.net.URLClassLoader import java.rmi.RemoteException +import java.util.concurrent.Callable +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors import javax.inject.Inject +import kotlin.concurrent.thread internal class ProjectFilesForCompilation( val projectRootFile: File, @@ -247,6 +252,20 @@ internal class GradleKotlinCompilerWork @Inject constructor( runToolInSeparateProcess(compilerArgs, compilerClassName, compilerFullClasspath, log, loggingMessageCollector) private fun compileInProcess(): ExitCode { + // in-process compiler should always be run in a different thread + // to avoid leaking thread locals from compiler (see KT-28037) + val threadPool = Executors.newSingleThreadExecutor() + try { + val future = threadPool.submit(Callable { + compileInProcessImpl() + }) + return future.get() + } finally { + threadPool.shutdown() + } + } + + private fun compileInProcessImpl(): ExitCode { val stream = ByteArrayOutputStream() val out = PrintStream(stream) // todo: cache classloader?