Use daemon if available for parsing files in JPS

This commit is contained in:
Alexey Tsvetkov
2018-04-03 21:09:29 +03:00
parent 3eb968807e
commit 6f59b6da8e
5 changed files with 63 additions and 20 deletions
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.daemon.common
import org.jetbrains.kotlin.cli.common.repl.*
import org.jetbrains.kotlin.parsing.util.classesFqNames
import java.io.File
import java.io.Serializable
import java.rmi.Remote
@@ -140,6 +141,12 @@ interface CompileService : Remote {
compilationResults: CompilationResults?
): CallResult<Int>
@Throws(RemoteException::class)
fun classesFqNamesByFiles(
sessionId: Int,
sourceFiles: Set<File>
): CallResult<Set<String>>
@Throws(RemoteException::class)
fun clearJarCache()
@@ -51,6 +51,7 @@ import org.jetbrains.kotlin.incremental.*
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
import org.jetbrains.kotlin.modules.Module
import org.jetbrains.kotlin.parsing.util.classesFqNames
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
import java.io.BufferedOutputStream
import java.io.ByteArrayOutputStream
@@ -352,6 +353,15 @@ class CompileServiceImpl(
}
}
override fun classesFqNamesByFiles(
sessionId: Int, sourceFiles: Set<File>
): CompileService.CallResult<Set<String>> =
ifAlive {
withValidClientOrSessionProxy(sessionId) {
CompileService.CallResult.Good(classesFqNames(sourceFiles))
}
}
override fun compile(
sessionId: Int,
compilerArguments: Array<out String>,
@@ -101,8 +101,8 @@ object CompilerRunnerUtil {
}
fun invokeClassesFqNames(
files: Set<File>,
environment: JpsCompilerEnvironment
environment: JpsCompilerEnvironment,
files: Set<File>
): Set<String> = withCompilerClassloader(environment) { classLoader ->
val klass = Class.forName("org.jetbrains.kotlin.parsing.util.ParseFileUtilsKt", true, classLoader)
val method = klass.getMethod("classesFqNames", Set::class.java)
@@ -72,6 +72,20 @@ class JpsKotlinCompilerRunner : KotlinCompilerRunner<JpsCompilerEnvironment>() {
const val FAIL_ON_FALLBACK_PROPERTY = "test.kotlin.jps.compiler.runner.fail.on.fallback"
}
fun classesFqNamesByFiles(
environment: JpsCompilerEnvironment,
files: Set<File>
): Set<String> = withDaemonOrFallback(
withDaemon = {
doWithDaemon(environment) { sessionId, daemon ->
daemon.classesFqNamesByFiles(sessionId, files)
}
},
fallback = {
CompilerRunnerUtil.invokeClassesFqNames(environment, files)
}
)
fun runK2JvmCompiler(
commonArguments: CommonCompilerArguments,
k2jvmArguments: K2JVMCompilerArguments,
@@ -122,12 +136,10 @@ class JpsKotlinCompilerRunner : KotlinCompilerRunner<JpsCompilerEnvironment>() {
): ExitCode {
log.debug("Using kotlin-home = " + environment.kotlinPaths.homePath)
return if (isDaemonEnabled()) {
val daemonExitCode = compileWithDaemon(compilerClassName, compilerArgs, environment)
daemonExitCode ?: fallbackCompileStrategy(compilerArgs, compilerClassName, environment)
} else {
fallbackCompileStrategy(compilerArgs, compilerClassName, environment)
}
return withDaemonOrFallback(
withDaemon = { compileWithDaemon(compilerClassName, compilerArgs, environment) },
fallback = { fallbackCompileStrategy(compilerArgs, compilerClassName, environment) }
)
}
override fun compileWithDaemon(
@@ -141,15 +153,6 @@ class JpsKotlinCompilerRunner : KotlinCompilerRunner<JpsCompilerEnvironment>() {
K2METADATA_COMPILER -> CompileService.TargetPlatform.METADATA
else -> throw IllegalArgumentException("Unknown compiler type $compilerClassName")
}
log.debug("Try to connect to daemon")
val connection = getDaemonConnection(environment)
if (connection == null) {
log.info("Could not connect to daemon")
return null
}
val (daemon, sessionId) = connection
val compilerMode = CompilerMode.JPS_COMPILER
val verbose = compilerArgs.verbose
val options = CompilationOptions(
@@ -159,10 +162,33 @@ class JpsKotlinCompilerRunner : KotlinCompilerRunner<JpsCompilerEnvironment>() {
reportSeverity(verbose),
requestedCompilationResults = emptyArray()
)
val res =
return doWithDaemon(environment) { sessionId, daemon ->
daemon.compile(sessionId, withAdditionalCompilerArgs(compilerArgs), options, JpsCompilerServicesFacadeImpl(environment), null)
}?.let { exitCodeFromProcessExitCode(it) }
}
private fun <T> withDaemonOrFallback(withDaemon: () -> T?, fallback: () -> T): T =
if (isDaemonEnabled()) {
withDaemon() ?: fallback()
} else {
fallback()
}
private fun <T> doWithDaemon(
environment: JpsCompilerEnvironment,
fn: (sessionId: Int, daemon: CompileService) -> CompileService.CallResult<T>
): T? {
log.debug("Try to connect to daemon")
val connection = getDaemonConnection(environment)
if (connection == null) {
log.info("Could not connect to daemon")
return null
}
val (daemon, sessionId) = connection
val res = fn(sessionId, daemon)
// TODO: consider implementing connection retry, instead of fallback here
return res.takeUnless { it is CompileService.CallResult.Dying }?.let { exitCodeFromProcessExitCode(it.get()) }
return res.takeUnless { it is CompileService.CallResult.Dying }?.get()
}
private fun withAdditionalCompilerArgs(compilerArgs: CommonCompilerArguments): Array<String> {
@@ -190,7 +190,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
val dirtyFiles = chunkDirtyFiles[target]
val removedFiles = chunkRemovedFiles[target] ?: emptyList()
val existingClasses = CompilerRunnerUtil.invokeClassesFqNames(dirtyFiles.toHashSet(), environment)
val existingClasses = JpsKotlinCompilerRunner().classesFqNamesByFiles(environment, dirtyFiles.toHashSet())
val previousClasses = cache.classesBySources(dirtyFiles + removedFiles)
for (jvmClassName in previousClasses) {
val fqName = jvmClassName.fqNameForClassNameWithoutDollars.asString()