diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/ExitCode.java b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/ExitCode.java index e8c2a283040..1f70b5521cd 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/ExitCode.java +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/ExitCode.java @@ -20,7 +20,9 @@ public enum ExitCode { OK(0), COMPILATION_ERROR(1), INTERNAL_ERROR(2), - SCRIPT_EXECUTION_ERROR(3); + SCRIPT_EXECUTION_ERROR(3), + OOM_ERROR(137), // 137 is commonly used to indicate OOM error + ; private final int code; diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.kt index 6272347ab90..365c77a53ee 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.kt @@ -20,8 +20,7 @@ import com.intellij.openapi.Disposable import com.intellij.openapi.util.Disposer import org.jetbrains.kotlin.analyzer.CompilationErrorException import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY -import org.jetbrains.kotlin.cli.common.ExitCode.COMPILATION_ERROR -import org.jetbrains.kotlin.cli.common.ExitCode.INTERNAL_ERROR +import org.jetbrains.kotlin.cli.common.ExitCode.* import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback import org.jetbrains.kotlin.cli.common.messages.* @@ -122,7 +121,7 @@ abstract class CLICompiler : CLITool() { return COMPILATION_ERROR } catch (t: Throwable) { MessageCollectorUtil.reportException(collector, t) - return INTERNAL_ERROR + return if (t is OutOfMemoryError) OOM_ERROR else INTERNAL_ERROR } finally { collector.flush() } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinDaemonIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinDaemonIT.kt index f155061ceda..1291a0bc49e 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinDaemonIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinDaemonIT.kt @@ -100,6 +100,25 @@ class KotlinDaemonIT : KGPDaemonsBaseTest() { } } + @DisplayName("On Kotlin daemon OOM helpful message is displayed") + @GradleTest + fun displaySpecialMessageOnOOM(gradleVersion: GradleVersion) { + project( + "kotlinProject", + gradleVersion, + buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.INFO) + ) { + gradleProperties.append( + "\nkotlin.daemon.jvmargs=-Xmx16m" + ) + + buildAndFail("assemble") { + assertOutputContains("Not enough memory to run compilation. Try to increase it via 'gradle.properties':") + assertOutputContains("kotlin.daemon.jvmargs=-Xmx") + } + } + } + private fun BuildResult.assertGradleClasspathNotLeaked() { assertOutputContains("Kotlin compiler classpath:") val daemonClasspath = output 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 63dcc3dfe06..5c826382459 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 @@ -127,12 +127,12 @@ internal class GradleKotlinCompilerWork @Inject constructor( override fun run() { try { val messageCollector = GradlePrintingMessageCollector(log, allWarningsAsErrors) - val exitCode = compileWithDaemonOrFallbackImpl(messageCollector) + val (exitCode, executionStrategy) = compileWithDaemonOrFallbackImpl(messageCollector) if (incrementalCompilationEnvironment?.disableMultiModuleIC == true) { incrementalCompilationEnvironment.multiModuleICSettings.buildHistoryFile.delete() } - throwGradleExceptionIfError(exitCode) + throwGradleExceptionIfError(exitCode, executionStrategy) } finally { val properties = ArrayList() COMPILE_INCREMENTAL_WITH_CLASSPATH_SNAPSHOTS.value.toBooleanLenient()?.let { @@ -151,7 +151,7 @@ internal class GradleKotlinCompilerWork @Inject constructor( } } - private fun compileWithDaemonOrFallbackImpl(messageCollector: MessageCollector): ExitCode { + private fun compileWithDaemonOrFallbackImpl(messageCollector: MessageCollector): Pair { with(log) { kotlinDebug { "Kotlin compiler class: ${compilerClassName}" } kotlinDebug { "Kotlin compiler classpath: ${compilerFullClasspath.joinToString { it.canonicalPath }}" } @@ -162,7 +162,7 @@ internal class GradleKotlinCompilerWork @Inject constructor( val daemonExitCode = compileWithDaemon(messageCollector) if (daemonExitCode != null) { - return daemonExitCode + return daemonExitCode to KotlinCompilerExecutionStrategy.DAEMON } else { log.warn("Could not connect to kotlin daemon. Using fallback strategy.") } @@ -170,9 +170,9 @@ internal class GradleKotlinCompilerWork @Inject constructor( val isGradleDaemonUsed = System.getProperty("org.gradle.daemon")?.let(String::toBoolean) return if (compilerExecutionStrategy == KotlinCompilerExecutionStrategy.IN_PROCESS || isGradleDaemonUsed == false) { - compileInProcess(messageCollector) + compileInProcess(messageCollector) to KotlinCompilerExecutionStrategy.IN_PROCESS } else { - compileOutOfProcess() + compileOutOfProcess() to KotlinCompilerExecutionStrategy.OUT_OF_PROCESS } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt index cce4fd6ed50..ed41eb91e53 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt @@ -132,7 +132,7 @@ abstract class KotlinJsDce : AbstractKotlinCompileTool(), Kotl buildDir, jvmArgs ) - throwGradleExceptionIfError(exitCode) + throwGradleExceptionIfError(exitCode, KotlinCompilerExecutionStrategy.OUT_OF_PROCESS) } private fun isDceCandidate(file: File): Boolean { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/tasksUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/tasksUtils.kt index d202141f6e3..c80b73cd459 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/tasksUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/tasksUtils.kt @@ -14,13 +14,26 @@ import org.jetbrains.kotlin.incremental.cleanDirectoryContents import org.jetbrains.kotlin.incremental.forceDeleteRecursively import java.io.File -fun throwGradleExceptionIfError(exitCode: ExitCode) { +fun throwGradleExceptionIfError( + exitCode: ExitCode, + executionStrategy: KotlinCompilerExecutionStrategy +) { when (exitCode) { ExitCode.COMPILATION_ERROR -> throw GradleException("Compilation error. See log for more details") ExitCode.INTERNAL_ERROR -> throw GradleException("Internal compiler error. See log for more details") ExitCode.SCRIPT_EXECUTION_ERROR -> throw GradleException("Script execution error. See log for more details") - ExitCode.OK -> { + ExitCode.OOM_ERROR -> { + var exceptionMessage = "Not enough memory to run compilation." + when (executionStrategy) { + KotlinCompilerExecutionStrategy.DAEMON -> + exceptionMessage += " Try to increase it via 'gradle.properties':\nkotlin.daemon.jvmargs=-Xmx" + KotlinCompilerExecutionStrategy.IN_PROCESS -> + exceptionMessage += " Try to increase it via 'gradle.properties':\norg.gradle.jvmargs=-Xmx" + KotlinCompilerExecutionStrategy.OUT_OF_PROCESS -> Unit + } + throw GradleException(exceptionMessage) } + ExitCode.OK -> Unit else -> throw IllegalStateException("Unexpected exit code: $exitCode") } }