Replace reflection-based compiler arguments copying with generated code

Using of Kotlin reflection for simple operations like bean management is very slow

First time initialization time: 261 ms for `copyBean(K2JVMCompilerArguments())`
Subsequent calls of `copyBean(K2JVMCompilerArguments())` take 1.7 ms per call

Unfortunately compiler argument handling is also used in Kotlin IntelliJ plugin
to parse facet settings. Big projects may have thousands of Kotlin facets

The same `ArgumentUtilsKt.copyProperties` frame is seen across various freezes:
IDEA-252440 2-3 minutes freeze on Kotlin project reimporting in last 203 eap
IDEA-253107 A lot of short freezes (1-3 sec) during Kotlin project development
KTIJ-23501 Make main run configuration detection lighter
KTIJ-22435 Unresponsive UI with 100% cpu

Reflection issue:
KT-56358 KClasses.getMemberProperties takes too much time

This commit replaces all reflection stuff with a simple code generation
Now `K2JVMCompilerArguments().clone()` goes to hard-to-measure time
This commit is contained in:
Leonid Shalupov
2023-03-08 18:20:51 +01:00
parent 56557fb8ff
commit 7480befe32
34 changed files with 744 additions and 75 deletions
+4 -1
View File
@@ -36,7 +36,10 @@ dependencies {
}
sourceSets {
"main" { projectDefault() }
"main" {
projectDefault()
generatedDir()
}
"test" { projectDefault() }
}
@@ -0,0 +1,18 @@
@file:Suppress("unused", "DuplicatedCode")
// DO NOT EDIT MANUALLY!
// Generated by generators/tests/org/jetbrains/kotlin/generators/arguments/GenerateCompilerArgumentsCopy.kt
// To regenerate run 'generateCompilerArgumentsCopy' task
package org.jetbrains.kotlin.config
@OptIn(org.jetbrains.kotlin.utils.IDEAPluginsCompatibilityAPI::class)
fun copyCompilerSettings(from: CompilerSettings, to: CompilerSettings): CompilerSettings {
to.additionalArguments = from.additionalArguments
to.copyJsLibraryFiles = from.copyJsLibraryFiles
to.outputDirectoryForJsLibraryFiles = from.outputDirectoryForJsLibraryFiles
to.scriptTemplates = from.scriptTemplates
to.scriptTemplatesClasspath = from.scriptTemplatesClasspath
return to
}
@@ -0,0 +1,14 @@
@file:Suppress("unused", "DuplicatedCode")
// DO NOT EDIT MANUALLY!
// Generated by generators/tests/org/jetbrains/kotlin/generators/arguments/GenerateCompilerArgumentsCopy.kt
// To regenerate run 'generateCompilerArgumentsCopy' task
package org.jetbrains.kotlin.config
@OptIn(org.jetbrains.kotlin.utils.IDEAPluginsCompatibilityAPI::class)
fun copyJpsPluginSettings(from: JpsPluginSettings, to: JpsPluginSettings): JpsPluginSettings {
to.version = from.version
return to
}
@@ -50,6 +50,8 @@ class CompilerSettings : Freezable() {
val DEFAULT_ADDITIONAL_ARGUMENTS = ""
private val DEFAULT_OUTPUT_DIRECTORY = "lib"
}
override fun copyOf(): Freezable = copyCompilerSettings(this, CompilerSettings())
}
val CompilerSettings.additionalArgumentsAsList: List<String>
@@ -14,4 +14,6 @@ class JpsPluginSettings : Freezable() {
checkFrozen()
field = value
}
override fun copyOf(): Freezable = copyJpsPluginSettings(this, JpsPluginSettings())
}
@@ -177,7 +177,7 @@ class KotlinFacetSettings {
val compilerSettings = compilerSettings
mergedCompilerArguments = if (compilerArguments != null) {
copyBean(compilerArguments).apply {
compilerArguments.copyOf().apply {
if (compilerSettings != null) {
parseCommandLineArguments(compilerSettings.additionalArgumentsAsList, this)
}
@@ -364,14 +364,14 @@ private fun KotlinFacetSettings.writeConfig(element: Element) {
element.addContent(Element("testOutputPath").apply { addContent(FileUtilRt.toSystemIndependentName(it)) })
}
}
compilerSettings?.let { copyBean(it) }?.let {
compilerSettings?.copyOf()?.let {
it.convertPathsToSystemIndependent()
buildChildElement(element, "compilerSettings", it, filter)
}
}
private fun KotlinFacetSettings.writeV2toV4Config(element: Element) = writeConfig(element).apply {
compilerArguments?.let { copyBean(it) }?.let {
compilerArguments?.copyOf()?.let {
it.convertPathsToSystemIndependent()
val compilerArgumentsXml = buildChildElement(element, "compilerArguments", it, SkipDefaultsSerializationFilter())
compilerArgumentsXml.dropVersionsIfNecessary(it)
@@ -379,7 +379,7 @@ private fun KotlinFacetSettings.writeV2toV4Config(element: Element) = writeConfi
}
private fun KotlinFacetSettings.writeLatestConfig(element: Element) = writeConfig(element).apply {
compilerArguments?.let { copyBean(it) }?.let {
compilerArguments?.copyOf()?.let {
it.convertPathsToSystemIndependent()
val compilerArgumentsXml = CompilerArgumentsSerializerV5(it).serializeTo(element)
compilerArgumentsXml.dropVersionsIfNecessary(it)
@@ -9,6 +9,8 @@
package org.jetbrains.kotlin.platform.impl
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.Freezable
import org.jetbrains.kotlin.cli.common.arguments.copyCommonCompilerArguments
import org.jetbrains.kotlin.platform.IdePlatform
import org.jetbrains.kotlin.platform.IdePlatformKind
import org.jetbrains.kotlin.platform.TargetPlatform
@@ -57,7 +59,9 @@ object NativeIdePlatformKind : IdePlatformKind() {
}
// These are fake compiler arguments for Kotlin/Native - only for usage within IDEA plugin:
class FakeK2NativeCompilerArguments : CommonCompilerArguments()
class FakeK2NativeCompilerArguments : CommonCompilerArguments() {
override fun copyOf(): Freezable = copyCommonCompilerArguments(this, FakeK2NativeCompilerArguments())
}
val IdePlatformKind?.isKotlinNative
get() = this is NativeIdePlatformKind
@@ -10,7 +10,9 @@ import org.jetbrains.jps.model.ex.JpsElementChildRoleBase
import org.jetbrains.jps.model.java.JpsJavaExtensionService
import org.jetbrains.jps.model.module.JpsModule
import org.jetbrains.kotlin.cli.common.arguments.*
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.config.CompilerSettings
import org.jetbrains.kotlin.config.KotlinFacetSettings
import org.jetbrains.kotlin.config.KotlinModuleKind
import org.jetbrains.kotlin.platform.TargetPlatform
val JpsModule.kotlinFacet: JpsKotlinFacetModuleExtension?
@@ -70,7 +72,7 @@ val JpsModule.testOutputFilePath: String?
val JpsModule.kotlinCompilerSettings: CompilerSettings
get() {
val defaultSettings = copyBean(project.kotlinCompilerSettings)
val defaultSettings = project.kotlinCompilerSettings.copyOf()
val facetSettings = kotlinFacet?.settings ?: return defaultSettings
if (facetSettings.useProjectSettings) return defaultSettings
return facetSettings.compilerSettings ?: defaultSettings
@@ -90,7 +92,7 @@ val JpsModule.k2JvmCompilerArguments
private inline fun <reified T : CommonCompilerArguments> JpsModule.getCompilerArguments(): T {
val projectSettings = project.kotlinCompilerSettingsContainer[T::class.java]
val projectSettingsCopy = copyBean(projectSettings)
val projectSettingsCopy = projectSettings.copyOf()
val facetSettings = kotlinFacet?.settings ?: return projectSettingsCopy
if (facetSettings.useProjectSettings) return projectSettingsCopy