Avoid catching exceptions from workers in GradleKotlinCompilerRunner

Exceptions were catched in `KotlinCompilerRunner.runCompiler`.
When the method from superclass is not used in
`GradleKotlinCompilerRunner`, the superclass does not make much sense
anymore, so I turned it into util object.
This commit is contained in:
Alexey Tsvetkov
2018-10-29 20:59:13 +03:00
parent 37dfe2b608
commit a41c2d759a
5 changed files with 138 additions and 156 deletions
@@ -1,144 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.compilerRunner
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.MessageCollectorUtil
import org.jetbrains.kotlin.daemon.client.CompileServiceSession
import org.jetbrains.kotlin.daemon.client.DaemonReportMessage
import org.jetbrains.kotlin.daemon.client.DaemonReportingTargets
import org.jetbrains.kotlin.daemon.client.KotlinCompilerClient
import org.jetbrains.kotlin.daemon.common.*
import java.io.BufferedReader
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.StringReader
import java.util.*
import java.util.concurrent.TimeUnit
interface KotlinLogger {
fun error(msg: String)
fun warn(msg: String)
fun info(msg: String)
fun debug(msg: String)
val isDebugEnabled: Boolean
}
abstract class KotlinCompilerRunner<in Env : CompilerEnvironment> {
protected val INTERNAL_ERROR = ExitCode.INTERNAL_ERROR.toString()
protected abstract val log: KotlinLogger
protected open fun runCompiler(
compilerClassName: String,
compilerArgs: CommonCompilerArguments,
environment: Env
) {
try {
compileWithDaemonOrFallback(compilerClassName, compilerArgs, environment)
} catch (e: Throwable) {
MessageCollectorUtil.reportException(environment.messageCollector, e)
reportInternalCompilerError(environment.messageCollector)
}
}
protected abstract fun compileWithDaemonOrFallback(
compilerClassName: String,
compilerArgs: CommonCompilerArguments,
environment: Env
)
protected fun exitCodeFromProcessExitCode(code: Int): ExitCode = Companion.exitCodeFromProcessExitCode(log, code)
companion object {
fun exitCodeFromProcessExitCode(log: KotlinLogger, code: Int): ExitCode {
val exitCode = ExitCode.values().find { it.code == code }
if (exitCode != null) return exitCode
log.debug("Could not find exit code by value: $code")
return if (code == 0) ExitCode.OK else ExitCode.COMPILATION_ERROR
}
@Synchronized
@JvmStatic
protected fun newDaemonConnection(
compilerId: CompilerId,
clientAliveFlagFile: File,
sessionAliveFlagFile: File,
messageCollector: MessageCollector,
isDebugEnabled: Boolean,
daemonOptions: DaemonOptions = configureDaemonOptions(),
additionalJvmParams: Array<String> = arrayOf()
): CompileServiceSession? {
val daemonJVMOptions = configureDaemonJVMOptions(
additionalParams = *additionalJvmParams,
inheritMemoryLimits = true,
inheritOtherJvmOptions = false,
inheritAdditionalProperties = true
)
val daemonReportMessages = ArrayList<DaemonReportMessage>()
val daemonReportingTargets = DaemonReportingTargets(messages = daemonReportMessages)
val profiler = if (daemonOptions.reportPerf) WallAndThreadAndMemoryTotalProfiler(withGC = false) else DummyProfiler()
val connection = profiler.withMeasure(null) {
KotlinCompilerClient.connectAndLease(
compilerId,
clientAliveFlagFile,
daemonJVMOptions,
daemonOptions,
daemonReportingTargets,
autostart = true,
leaseSession = true,
sessionAliveFlagFile = sessionAliveFlagFile
)
}
if (connection == null || isDebugEnabled) {
for (message in daemonReportMessages) {
val severity = when (message.category) {
DaemonReportCategory.DEBUG -> CompilerMessageSeverity.INFO
DaemonReportCategory.INFO -> CompilerMessageSeverity.INFO
DaemonReportCategory.EXCEPTION -> CompilerMessageSeverity.EXCEPTION
}
messageCollector.report(severity, message.message)
}
}
fun reportTotalAndThreadPerf(
message: String, daemonOptions: DaemonOptions, messageCollector: MessageCollector, profiler: Profiler
) {
if (daemonOptions.reportPerf) {
fun Long.ms() = TimeUnit.NANOSECONDS.toMillis(this)
val counters = profiler.getTotalCounters()
messageCollector.report(
CompilerMessageSeverity.INFO, "PERF: $message ${counters.time.ms()} ms, thread ${counters.threadTime.ms()}"
)
}
}
reportTotalAndThreadPerf("Daemon connect", daemonOptions, MessageCollector.NONE, profiler)
return connection
}
}
}
@@ -0,0 +1,103 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.compilerRunner
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.daemon.client.CompileServiceSession
import org.jetbrains.kotlin.daemon.client.DaemonReportMessage
import org.jetbrains.kotlin.daemon.client.DaemonReportingTargets
import org.jetbrains.kotlin.daemon.client.KotlinCompilerClient
import org.jetbrains.kotlin.daemon.common.*
import java.io.File
import java.util.*
import java.util.concurrent.TimeUnit
object KotlinCompilerRunnerUtils {
fun exitCodeFromProcessExitCode(log: KotlinLogger, code: Int): ExitCode {
val exitCode = ExitCode.values().find { it.code == code }
if (exitCode != null) return exitCode
log.debug("Could not find exit code by value: $code")
return if (code == 0) ExitCode.OK else ExitCode.COMPILATION_ERROR
}
@Synchronized
@JvmStatic
fun newDaemonConnection(
compilerId: CompilerId,
clientAliveFlagFile: File,
sessionAliveFlagFile: File,
messageCollector: MessageCollector,
isDebugEnabled: Boolean,
daemonOptions: DaemonOptions = configureDaemonOptions(),
additionalJvmParams: Array<String> = arrayOf()
): CompileServiceSession? {
val daemonJVMOptions = configureDaemonJVMOptions(
additionalParams = *additionalJvmParams,
inheritMemoryLimits = true,
inheritOtherJvmOptions = false,
inheritAdditionalProperties = true
)
val daemonReportMessages = ArrayList<DaemonReportMessage>()
val daemonReportingTargets = DaemonReportingTargets(messages = daemonReportMessages)
val profiler = if (daemonOptions.reportPerf) WallAndThreadAndMemoryTotalProfiler(withGC = false) else DummyProfiler()
val connection = profiler.withMeasure(null) {
KotlinCompilerClient.connectAndLease(
compilerId,
clientAliveFlagFile,
daemonJVMOptions,
daemonOptions,
daemonReportingTargets,
autostart = true,
leaseSession = true,
sessionAliveFlagFile = sessionAliveFlagFile
)
}
if (connection == null || isDebugEnabled) {
for (message in daemonReportMessages) {
val severity = when (message.category) {
DaemonReportCategory.DEBUG -> CompilerMessageSeverity.INFO
DaemonReportCategory.INFO -> CompilerMessageSeverity.INFO
DaemonReportCategory.EXCEPTION -> CompilerMessageSeverity.EXCEPTION
}
messageCollector.report(severity, message.message)
}
}
fun reportTotalAndThreadPerf(
message: String, daemonOptions: DaemonOptions, messageCollector: MessageCollector, profiler: Profiler
) {
if (daemonOptions.reportPerf) {
fun Long.ms() = TimeUnit.NANOSECONDS.toMillis(this)
val counters = profiler.getTotalCounters()
messageCollector.report(
CompilerMessageSeverity.INFO, "PERF: $message ${counters.time.ms()} ms, thread ${counters.threadTime.ms()}"
)
}
}
reportTotalAndThreadPerf("Daemon connect", daemonOptions, MessageCollector.NONE, profiler)
return connection
}
}
@@ -0,0 +1,15 @@
/*
* Copyright 2010-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.compilerRunner
interface KotlinLogger {
fun error(msg: String)
fun warn(msg: String)
fun info(msg: String)
fun debug(msg: String)
val isDebugEnabled: Boolean
}
@@ -21,6 +21,7 @@ import org.jetbrains.jps.api.GlobalOptions
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY
import org.jetbrains.kotlin.cli.common.arguments.*
import org.jetbrains.kotlin.cli.common.messages.MessageCollectorUtil
import org.jetbrains.kotlin.config.CompilerSettings
import org.jetbrains.kotlin.config.IncrementalCompilation
import org.jetbrains.kotlin.config.additionalArgumentsAsList
@@ -32,8 +33,8 @@ import java.io.ByteArrayOutputStream
import java.io.File
import java.io.PrintStream
class JpsKotlinCompilerRunner : KotlinCompilerRunner<JpsCompilerEnvironment>() {
override val log: KotlinLogger = JpsKotlinLogger(KotlinBuilder.LOG)
class JpsKotlinCompilerRunner {
private val log: KotlinLogger = JpsKotlinLogger(KotlinBuilder.LOG)
private var compilerSettings: CompilerSettings? = null
@@ -153,7 +154,7 @@ class JpsKotlinCompilerRunner : KotlinCompilerRunner<JpsCompilerEnvironment>() {
}
}
override fun compileWithDaemonOrFallback(
private fun compileWithDaemonOrFallback(
compilerClassName: String,
compilerArgs: CommonCompilerArguments,
environment: JpsCompilerEnvironment
@@ -166,6 +167,15 @@ class JpsKotlinCompilerRunner : KotlinCompilerRunner<JpsCompilerEnvironment>() {
)
}
private fun runCompiler(compilerClassName: String, compilerArgs: CommonCompilerArguments, environment: JpsCompilerEnvironment) {
try {
compileWithDaemonOrFallback(compilerClassName, compilerArgs, environment)
} catch (e: Throwable) {
MessageCollectorUtil.reportException(environment.messageCollector, e)
reportInternalCompilerError(environment.messageCollector)
}
}
private fun compileWithDaemon(
compilerClassName: String,
compilerArgs: CommonCompilerArguments,
@@ -311,7 +321,7 @@ class JpsKotlinCompilerRunner : KotlinCompilerRunner<JpsCompilerEnvironment>() {
}
private fun getReturnCodeFromObject(rc: Any?): String = when {
rc == null -> INTERNAL_ERROR
rc == null -> ExitCode.INTERNAL_ERROR.toString()
ExitCode::class.java.name == rc::class.java.name -> rc.toString()
else -> throw IllegalStateException("Unexpected return: " + rc)
}
@@ -333,7 +343,7 @@ class JpsKotlinCompilerRunner : KotlinCompilerRunner<JpsCompilerEnvironment>() {
environment.withProgressReporter { progress ->
progress.progress("connecting to daemon")
newDaemonConnection(
KotlinCompilerRunnerUtils.newDaemonConnection(
compilerId,
clientFlagFile,
sessionFlagFile,
@@ -50,9 +50,7 @@ const val COULD_NOT_CONNECT_TO_DAEMON_MESSAGE = "Could not connect to Kotlin com
internal fun kotlinCompilerExecutionStrategy(): String =
System.getProperty(KOTLIN_COMPILER_EXECUTION_STRATEGY_PROPERTY) ?: DAEMON_EXECUTION_STRATEGY
internal open class GradleCompilerRunner(protected val project: Project) : KotlinCompilerRunner<GradleCompilerEnvironment>() {
override val log = GradleKotlinLogger(project.logger)
internal open class GradleCompilerRunner(protected val project: Project) {
fun runJvmCompiler(
sourcesToCompile: List<File>,
commonSources: List<File>,
@@ -106,7 +104,7 @@ internal open class GradleCompilerRunner(protected val project: Project) : Kotli
return runCompiler(KotlinCompilerClass.METADATA, args, environment)
}
override fun runCompiler(
private fun runCompiler(
compilerClassName: String,
compilerArgs: CommonCompilerArguments,
environment: GradleCompilerEnvironment
@@ -118,10 +116,10 @@ internal open class GradleCompilerRunner(protected val project: Project) : Kotli
)
compilerArgs.version = false
}
super.runCompiler(compilerClassName, compilerArgs, environment)
compileWithDaemonOrFallback(compilerClassName, compilerArgs, environment)
}
override fun compileWithDaemonOrFallback(
protected open fun compileWithDaemonOrFallback(
compilerClassName: String,
compilerArgs: CommonCompilerArguments,
environment: GradleCompilerEnvironment
@@ -148,7 +146,7 @@ internal open class GradleCompilerRunner(protected val project: Project) : Kotli
isDebugEnabled: Boolean
): CompileServiceSession? {
val compilerId = CompilerId.makeCompilerId(compilerFullClasspath)
return newDaemonConnection(
return KotlinCompilerRunnerUtils.newDaemonConnection(
compilerId, clientIsAliveFlagFile, sessionIsAliveFlagFile,
messageCollector = messageCollector,
isDebugEnabled = isDebugEnabled