diff --git a/compiler/daemon/daemon-client/src/main/kotlin/KotlinCompilerClient.kt b/compiler/daemon/daemon-client/src/main/kotlin/KotlinCompilerClient.kt index e528bd7d2eb..dd9994358fe 100644 --- a/compiler/daemon/daemon-client/src/main/kotlin/KotlinCompilerClient.kt +++ b/compiler/daemon/daemon-client/src/main/kotlin/KotlinCompilerClient.kt @@ -470,11 +470,18 @@ object KotlinCompilerClient { if (javaVersion != null && javaVersion >= 16) listOf("--add-exports", "java.base/sun.nio.ch=ALL-UNNAMED") else emptyList() + val jvmArguments = daemonJVMOptions.mappers.flatMap { it.toArgs("-") } + val additionalOptimizationOptions = listOfNotNull( + "-XX:+UseCodeCacheFlushing", + // enable parallel gc only if it's not explicitly disabled and no other GC is selected + "-XX:+UseParallelGC".takeIf { jvmArguments.none { it == "-XX:-UseParallelGC" || (it.startsWith("-XX:+Use") && it.endsWith("GC")) } }, + ) val args = listOf( javaExecutable.absolutePath, "-cp", compilerId.compilerClasspath.joinToString(File.pathSeparator) ) + platformSpecificOptions + - daemonJVMOptions.mappers.flatMap { it.toArgs("-") } + + jvmArguments + + additionalOptimizationOptions + javaIllegalAccessWorkaround + COMPILER_DAEMON_CLASS_FQN + daemonOptions.mappers.flatMap { it.toArgs(COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX) } + diff --git a/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/DaemonParams.kt b/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/DaemonParams.kt index a2bf98aa99a..550884a9f60 100644 --- a/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/DaemonParams.kt +++ b/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/DaemonParams.kt @@ -181,7 +181,7 @@ fun Iterable.filterExtractProps(vararg groups: OptionsGroup, prefix: Str data class DaemonJVMOptions( var maxMemory: String = "", var maxMetaspaceSize: String = "", - var reservedCodeCacheSize: String = "", + var reservedCodeCacheSize: String = "320m", var jvmParams: MutableCollection = arrayListOf() ) : OptionsGroup { override val mappers: List> diff --git a/compiler/daemon/daemon-tests/test/org/jetbrains/kotlin/daemon/BaseDaemonSessionTest.kt b/compiler/daemon/daemon-tests/test/org/jetbrains/kotlin/daemon/BaseDaemonSessionTest.kt index 323f02b342b..d2a61418add 100644 --- a/compiler/daemon/daemon-tests/test/org/jetbrains/kotlin/daemon/BaseDaemonSessionTest.kt +++ b/compiler/daemon/daemon-tests/test/org/jetbrains/kotlin/daemon/BaseDaemonSessionTest.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.daemon import org.jetbrains.kotlin.cli.common.CompilerSystemProperties 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.CompileService @@ -74,6 +75,7 @@ abstract class BaseDaemonSessionTest { jvmOptions: DaemonJVMOptions = defaultDaemonJvmOptions, daemonOptions: DaemonOptions = defaultDaemonOptions, logFile: File? = null, + daemonMessagesCollector: MutableCollection? = null, ): CompileServiceSession { val actualJvmOptions = logFile?.let { jvmOptions.withLogFile(it) } ?: jvmOptions println("Leasing a session with $actualJvmOptions and $daemonOptions") @@ -85,7 +87,7 @@ abstract class BaseDaemonSessionTest { clientMarkerFile, actualJvmOptions, daemonOptions, - DaemonReportingTargets(out = System.err), + DaemonReportingTargets(messages = daemonMessagesCollector, out = System.err), autostart = true, leaseSession = true, sessionAliveFlagFile = sessionMarkerFile, diff --git a/compiler/daemon/daemon-tests/test/org/jetbrains/kotlin/daemon/JvmArgumentsModificationTest.kt b/compiler/daemon/daemon-tests/test/org/jetbrains/kotlin/daemon/JvmArgumentsModificationTest.kt new file mode 100644 index 00000000000..2552e250d96 --- /dev/null +++ b/compiler/daemon/daemon-tests/test/org/jetbrains/kotlin/daemon/JvmArgumentsModificationTest.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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 + +import org.jetbrains.kotlin.daemon.client.DaemonReportMessage +import org.jetbrains.kotlin.daemon.common.filterExtractProps +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import kotlin.test.assertContains +import kotlin.test.assertEquals + +class JvmArgumentsModificationTest : BaseDaemonSessionTest() { + @DisplayName("Default jvm arguments contain expected gc and code cache options") + @Test + fun testDefaultGcArguments() { + val commandParts = leaseSessionAndExtractCommand() + val xmxArgument = commandParts.single { it.startsWith("-Xmx") } + val codeCacheSizeArgument = commandParts.single { it.startsWith("-XX:ReservedCodeCacheSize") } + val useGcArgument = commandParts.single { it.startsWith("-XX:+Use") && it.endsWith("GC") } + assertEquals("-Xmx384m", xmxArgument) + assertEquals("-XX:ReservedCodeCacheSize=320m", codeCacheSizeArgument) + assertEquals("-XX:+UseParallelGC", useGcArgument) + assertContains(commandParts, "-XX:+UseCodeCacheFlushing") + } + + @DisplayName("Gc and code cache options may be properly overridden") + @Test + fun testModification() { + val commandParts = leaseSessionAndExtractCommand(listOf("Xmx400m", "XX:ReservedCodeCacheSize=280m", "XX:+UseG1GC")) + val xmxArgument = commandParts.single { it.startsWith("-Xmx") } + val codeCacheSizeArgument = commandParts.single { it.startsWith("-XX:ReservedCodeCacheSize") } + val useGcArgument = commandParts.single { it.startsWith("-XX:+Use") && it.endsWith("GC") } + assertEquals("-Xmx400m", xmxArgument) + assertEquals("-XX:ReservedCodeCacheSize=280m", codeCacheSizeArgument) + assertEquals("-XX:+UseG1GC", useGcArgument) + assertContains(commandParts, "-XX:+UseCodeCacheFlushing") + } + + @DisplayName("-XX:-UseParallelGC is handled") + @Test + fun testDisablingParallelGC() { + val commandParts = leaseSessionAndExtractCommand(listOf("XX:-UseParallelGC")) + assert(commandParts.none { it.startsWith("-XX:+Use") && it.endsWith("GC") }) { + "Expected no explicitly enabled garbage collector via JVM arguments: $commandParts" + } + } + + private fun leaseSessionAndExtractCommand(additionalJvmArguments: List = emptyList()): List { + val daemonMessagesCollector = mutableListOf() + leaseSession( + daemonMessagesCollector = daemonMessagesCollector, + jvmOptions = defaultDaemonJvmOptions.copy().apply { + jvmParams.addAll( + additionalJvmArguments.filterExtractProps(mappers, "", restMapper) + ) + } + ) + val prefix = "starting the daemon as: " + return daemonMessagesCollector.single { it.message.startsWith(prefix) }.message.substring(prefix.length).split(" ") + } +} \ No newline at end of file