Introduce new Kotlin Daemon without RMI abstraction

This commit is contained in:
Vadim Brilyantov
2019-02-28 17:30:35 +03:00
parent a3f718733d
commit ced973b707
107 changed files with 8866 additions and 523 deletions
@@ -0,0 +1,105 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.daemon.client
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.daemon.client.KotlinCompilerDaemonClient.Companion.instantiate
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.daemon.common.ReportSeverity
import org.jetbrains.kotlin.daemon.common.DummyProfiler
import org.jetbrains.kotlin.daemon.common.Profiler
import java.io.File
data class CompileServiceSessionAsync(val compileService: CompileServiceAsync, val sessionId: Int)
fun CompileServiceSession.toAsync() = CompileServiceSessionAsync(this.compileService.toClient(), this.sessionId)
fun CompileServiceSessionAsync.toRMI() = CompileServiceSession(this.compileService.toRMI(), this.sessionId)
interface KotlinCompilerDaemonClient {
suspend fun connectToCompileService(
compilerId: CompilerId,
daemonJVMOptions: DaemonJVMOptions,
daemonOptions: DaemonOptions,
reportingTargets: DaemonReportingTargets,
autostart: Boolean,
checkId: Boolean
): CompileServiceAsync?
suspend fun connectToCompileService(
compilerId: CompilerId,
clientAliveFlagFile: File,
daemonJVMOptions: DaemonJVMOptions,
daemonOptions: DaemonOptions,
reportingTargets: DaemonReportingTargets,
autostart: Boolean
): CompileServiceAsync?
suspend fun connectAndLease(
compilerId: CompilerId,
clientAliveFlagFile: File,
daemonJVMOptions: DaemonJVMOptions,
daemonOptions: DaemonOptions,
reportingTargets: DaemonReportingTargets,
autostart: Boolean,
leaseSession: Boolean,
sessionAliveFlagFile: File? = null
): CompileServiceSessionAsync?
suspend fun shutdownCompileService(compilerId: CompilerId, daemonOptions: DaemonOptions)
suspend fun leaseCompileSession(compilerService: CompileServiceAsync, aliveFlagPath: String?): Int
suspend fun releaseCompileSession(compilerService: CompileServiceAsync, sessionId: Int): Unit
suspend fun compile(
compilerService: CompileServiceAsync,
sessionId: Int,
targetPlatform: CompileService.TargetPlatform,
args: Array<out String>,
messageCollector: MessageCollector,
outputsCollector: ((File, List<File>) -> Unit)? = null,
compilerMode: CompilerMode = CompilerMode.NON_INCREMENTAL_COMPILER,
reportSeverity: ReportSeverity = ReportSeverity.INFO,
port: Int = SOCKET_ANY_FREE_PORT,
profiler: Profiler = DummyProfiler()
): Int
fun getOrCreateClientFlagFile(daemonOptions: DaemonOptions): File
fun createCompResults(): CompilationResultsAsync
fun main(vararg args: String)
companion object {
fun instantiate(daemonProtocolVariant: DaemonProtocolVariant): KotlinCompilerDaemonClient =
KotlinCompilerDaemonClient::class.java
.classLoader
.loadClass(
when(daemonProtocolVariant) {
DaemonProtocolVariant.RMI -> "org.jetbrains.kotlin.daemon.client.impls.KotlinCompilerClientImpl"
DaemonProtocolVariant.SOCKETS -> "org.jetbrains.kotlin.daemon.client.experimental.KotlinCompilerClient"
}
)
.newInstance() as KotlinCompilerDaemonClient
}
}
object KotlinCompilerClientInstance {
const val RMI_FLAG = "-old"
const val SOCKETS_FLAG = "-new_with_sockets"
@JvmStatic
fun main(vararg args: String) {
val clientInstance: KotlinCompilerDaemonClient? = when (args.last()) {
SOCKETS_FLAG ->
instantiate(DaemonProtocolVariant.SOCKETS)
else ->
instantiate(DaemonProtocolVariant.RMI)
}
clientInstance?.main(*args.sliceArray(0..args.lastIndex))
}
}
@@ -19,40 +19,40 @@ package org.jetbrains.kotlin.daemon.client
import org.jetbrains.kotlin.daemon.common.DaemonReportCategory
import java.io.IOException
private class NativePlatformLauncherWrapper {
class NativePlatformLauncherWrapper {
private val nativeLauncher: net.rubygrapefruit.platform.ProcessLauncher by lazy {
net.rubygrapefruit.platform.Native.get(net.rubygrapefruit.platform.ProcessLauncher::class.java)
}
fun launch(processBuilder: ProcessBuilder): Process =
try {
nativeLauncher.start(processBuilder)
}
catch (e: net.rubygrapefruit.platform.NativeException) {
throw IOException(e)
}
try {
nativeLauncher.start(processBuilder)
}
catch (e: net.rubygrapefruit.platform.NativeException) {
throw IOException(e)
}
}
fun launchProcessWithFallback(processBuilder: ProcessBuilder, reportingTargets: DaemonReportingTargets, reportingSource: String = "process launcher"): Process =
try {
// A separate class to delay classloading until this point, where we can catch class loading errors in case then the native lib is not in the classpath
NativePlatformLauncherWrapper().launch(processBuilder)
}
catch (e: UnsatisfiedLinkError) {
reportingTargets.report(DaemonReportCategory.DEBUG, "Could not start process with native process launcher, falling back to ProcessBuilder#start ($e)", reportingSource)
null
}
catch (e: IOException) {
reportingTargets.report(DaemonReportCategory.DEBUG, "Could not start process with native process launcher, falling back to ProcessBuilder#start (${e.cause})", reportingSource)
null
}
catch (e: NoClassDefFoundError) {
reportingTargets.report(DaemonReportCategory.DEBUG, "net.rubygrapefruit.platform library is not in the classpath, falling back to ProcessBuilder#start ($e)", reportingSource)
null
}
catch (e: ClassNotFoundException) {
reportingTargets.report(DaemonReportCategory.DEBUG, "net.rubygrapefruit.platform library is not in the classpath, falling back to ProcessBuilder#start ($e)", reportingSource)
null
}
try {
// A separate class to delay classloading until this point, where we can catch class loading errors in case then the native lib is not in the classpath
NativePlatformLauncherWrapper().launch(processBuilder)
}
catch (e: UnsatisfiedLinkError) {
reportingTargets.report(DaemonReportCategory.DEBUG, "Could not start process with native process launcher, falling back to ProcessBuilder#start ($e)", reportingSource)
null
}
catch (e: IOException) {
reportingTargets.report(DaemonReportCategory.DEBUG, "Could not start process with native process launcher, falling back to ProcessBuilder#start (${e.cause})", reportingSource)
null
}
catch (e: NoClassDefFoundError) {
reportingTargets.report(DaemonReportCategory.DEBUG, "net.rubygrapefruit.platform library is not in the classpath, falling back to ProcessBuilder#start ($e)", reportingSource)
null
}
catch (e: ClassNotFoundException) {
reportingTargets.report(DaemonReportCategory.DEBUG, "net.rubygrapefruit.platform library is not in the classpath, falling back to ProcessBuilder#start ($e)", reportingSource)
null
}
?: processBuilder.start()
@@ -50,7 +50,10 @@ class RemoteReplCompilerStateHistory(private val state: RemoteReplCompilerState)
override val lock: ReentrantReadWriteLock get() = state.lock
}
class RemoteReplCompilerState(internal val replStateFacade: ReplStateFacade, override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()) : IReplStageState<Unit> {
class RemoteReplCompilerState(
internal val replStateFacade: ReplStateFacade,
override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()
) : IReplStageState<Unit> {
override val currentGeneration: Int get() = (history as RemoteReplCompilerStateHistory).currentGeneration.get()
@@ -0,0 +1,125 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.daemon.client.impls
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.daemon.client.*
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.daemon.common.ReportSeverity
import org.jetbrains.kotlin.daemon.common.Profiler
import java.io.File
object KotlinCompilerClientImpl : KotlinCompilerDaemonClient {
val oldClient = KotlinCompilerClient
override suspend fun connectToCompileService(
compilerId: CompilerId,
daemonJVMOptions: DaemonJVMOptions,
daemonOptions: DaemonOptions,
reportingTargets: DaemonReportingTargets,
autostart: Boolean,
checkId: Boolean
): CompileServiceAsync? = oldClient.connectToCompileService(
compilerId,
daemonJVMOptions,
daemonOptions,
reportingTargets,
autostart,
checkId
)?.toClient()
override suspend fun connectToCompileService(
compilerId: CompilerId,
clientAliveFlagFile: File,
daemonJVMOptions: DaemonJVMOptions,
daemonOptions: DaemonOptions,
reportingTargets: DaemonReportingTargets,
autostart: Boolean
): CompileServiceAsync? = oldClient.connectToCompileService(
compilerId,
clientAliveFlagFile,
daemonJVMOptions,
daemonOptions,
reportingTargets,
autostart
)?.toClient()
override suspend fun connectAndLease(
compilerId: CompilerId,
clientAliveFlagFile: File,
daemonJVMOptions: DaemonJVMOptions,
daemonOptions: DaemonOptions,
reportingTargets: DaemonReportingTargets,
autostart: Boolean,
leaseSession: Boolean,
sessionAliveFlagFile: File?
): CompileServiceSessionAsync? = oldClient.connectAndLease(
compilerId,
clientAliveFlagFile,
daemonJVMOptions,
daemonOptions,
reportingTargets,
autostart,
leaseSession,
sessionAliveFlagFile
)?.toAsync()
override suspend fun shutdownCompileService(
compilerId: CompilerId,
daemonOptions: DaemonOptions
) = oldClient.shutdownCompileService(
compilerId,
daemonOptions
)
override suspend fun leaseCompileSession(
compilerService: CompileServiceAsync,
aliveFlagPath: String?
) = oldClient.leaseCompileSession(
compilerService.toRMI(),
aliveFlagPath
)
override suspend fun releaseCompileSession(
compilerService: CompileServiceAsync,
sessionId: Int
) = oldClient.releaseCompileSession(
compilerService.toRMI(),
sessionId
)
override suspend fun compile(
compilerService: CompileServiceAsync,
sessionId: Int,
targetPlatform: CompileService.TargetPlatform,
args: Array<out String>,
messageCollector: MessageCollector,
outputsCollector: ((File, List<File>) -> Unit)?,
compilerMode: CompilerMode,
reportSeverity: ReportSeverity,
port: Int,
profiler: Profiler
): Int = oldClient.compile(
compilerService.toRMI(),
sessionId,
targetPlatform,
args,
messageCollector,
outputsCollector,
compilerMode,
reportSeverity,
port,
profiler
)
override fun getOrCreateClientFlagFile(daemonOptions: DaemonOptions): File = oldClient.getOrCreateClientFlagFile(daemonOptions)
override fun createCompResults() = TODO("not implemented")
override fun main(vararg args: String) = oldClient.main(*args)
}