From 8a31e2ed829939c71018b28f390ffe5a1f73e555 Mon Sep 17 00:00:00 2001 From: Mark Mann Date: Wed, 9 Aug 2023 18:35:45 +0200 Subject: [PATCH] [IR] Optimize a few hot spots to reduce total CPU time ^KT-61121 --- .../backend/common/overrides/FakeOverrides.kt | 6 ++--- .../org/jetbrains/kotlin/konan/file/File.kt | 5 ++-- ...KlibMetadataModuleDescriptorFactoryImpl.kt | 4 ++-- ...libResolvedModuleDescriptorsFactoryImpl.kt | 23 +++++++++++-------- .../jetbrains/kotlin/library/KotlinLibrary.kt | 3 +++ .../konan/LlvmModuleSpecificationImpl.kt | 19 +++++++++++---- .../jetbrains/kotlin/backend/konan/PsiToIr.kt | 3 ++- .../kotlin/backend/konan/ir/NewIrUtils.kt | 2 ++ .../objcexport/ObjCExportCodeGenerator.kt | 2 +- .../konan/lower/BuiltinOperatorLowering.kt | 10 ++++---- .../backend/konan/lower/PreInlineLowering.kt | 2 +- .../StaticInitializersOptimization.kt | 4 ++-- 12 files changed, 53 insertions(+), 30 deletions(-) diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/overrides/FakeOverrides.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/overrides/FakeOverrides.kt index c922efe3c8d..f8f3c55470a 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/overrides/FakeOverrides.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/overrides/FakeOverrides.kt @@ -284,11 +284,11 @@ class FakeOverrideBuilder( } fun provideFakeOverrides() { - val entries = fakeOverrideCandidates.entries + val entries = fakeOverrideCandidates.entries.toMutableList() while (entries.isNotEmpty()) { - val candidate = entries.last() - entries.remove(candidate) + val candidate = entries.removeLast() provideFakeOverrides(candidate.key, candidate.value) } + fakeOverrideCandidates.clear() } } diff --git a/compiler/util-io/src/org/jetbrains/kotlin/konan/file/File.kt b/compiler/util-io/src/org/jetbrains/kotlin/konan/file/File.kt index 974f5c44adb..d33ca7b19c8 100644 --- a/compiler/util-io/src/org/jetbrains/kotlin/konan/file/File.kt +++ b/compiler/util-io/src/org/jetbrains/kotlin/konan/file/File.kt @@ -28,8 +28,9 @@ data class File constructor(internal val javaPath: Path) { get() = javaPath.toAbsolutePath().toString() val absoluteFile: File get() = File(absolutePath) - val canonicalPath: String - get() = javaPath.toFile().canonicalPath + val canonicalPath: String by lazy { + javaPath.toFile().canonicalPath + } val canonicalFile: File get() = File(canonicalPath) diff --git a/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/impl/KlibMetadataModuleDescriptorFactoryImpl.kt b/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/impl/KlibMetadataModuleDescriptorFactoryImpl.kt index 03263e7c61e..ef394784ada 100644 --- a/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/impl/KlibMetadataModuleDescriptorFactoryImpl.kt +++ b/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/impl/KlibMetadataModuleDescriptorFactoryImpl.kt @@ -16,7 +16,7 @@ import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.library.metadata.* -import org.jetbrains.kotlin.library.unresolvedDependencies +import org.jetbrains.kotlin.library.hasDependencies import org.jetbrains.kotlin.name.NativeForwardDeclarationKind import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.parentOrNull @@ -27,7 +27,7 @@ import org.jetbrains.kotlin.serialization.deserialization.* import org.jetbrains.kotlin.storage.StorageManager private val ModuleDescriptorImpl.isStdlibModule - get() = (this.klibModuleOrigin as? DeserializedKlibModuleOrigin)?.library?.unresolvedDependencies?.isEmpty() ?: false + get() = (this.klibModuleOrigin as? DeserializedKlibModuleOrigin)?.library?.let { !it.hasDependencies } ?: false class KlibMetadataModuleDescriptorFactoryImpl( override val descriptorFactory: KlibModuleDescriptorFactory, diff --git a/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/impl/KlibResolvedModuleDescriptorsFactoryImpl.kt b/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/impl/KlibResolvedModuleDescriptorsFactoryImpl.kt index 2e1d04b0b09..84c88545906 100644 --- a/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/impl/KlibResolvedModuleDescriptorsFactoryImpl.kt +++ b/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/impl/KlibResolvedModuleDescriptorsFactoryImpl.kt @@ -91,18 +91,23 @@ class KlibResolvedModuleDescriptorsFactoryImpl( ) // Set inter-dependencies between module descriptors, add forwarding declarations module. + val additionalDependencyModulesCopy = additionalDependencyModules.toSet() + val friendsForNonIncludedModule = additionalDependencyModulesCopy + val friendsForIncludedModule = buildSet { + this += friendsForNonIncludedModule + this += friendModuleDescriptors + this += refinesModuleDescriptors + } + val allDependencies = moduleDescriptors + additionalDependencyModulesCopy + forwardDeclarationsModule for (module in moduleDescriptors) { - val friends = additionalDependencyModules.toMutableSet() - if (module in includedLibraryDescriptors) { - friends.addAll(friendModuleDescriptors) - friends.addAll(refinesModuleDescriptors) + val friends = if (module in includedLibraryDescriptors) { + friendsForIncludedModule + } else { + friendsForNonIncludedModule } - module.setDependencies( - // Yes, just to all of them. - moduleDescriptors + additionalDependencyModules + forwardDeclarationsModule, - friends - ) + // Yes, just to all of them. + module.setDependencies(allDependencies, friends) } return KotlinResolvedModuleDescriptors( diff --git a/compiler/util-klib/src/org/jetbrains/kotlin/library/KotlinLibrary.kt b/compiler/util-klib/src/org/jetbrains/kotlin/library/KotlinLibrary.kt index c5c312a9c97..a6d5e99b0b5 100644 --- a/compiler/util-klib/src/org/jetbrains/kotlin/library/KotlinLibrary.kt +++ b/compiler/util-klib/src/org/jetbrains/kotlin/library/KotlinLibrary.kt @@ -105,6 +105,9 @@ fun BaseKotlinLibrary.unresolvedDependencies(lenient: Boolean = false): List() + + // This is essentially memoizing the IrDeclaration.konanLibrary property -- so much of the implementation + // is inlined here to take greater advantage of the cache. + override fun containsDeclaration(declaration: IrDeclaration): Boolean = containsCache.getOrPut(declaration) { + val metadata = ((declaration as? IrMetadataSourceOwner)?.metadata as? KonanMetadata) + if (metadata != null) { + (metadata.konanLibrary == null || containsLibrary(metadata.konanLibrary)) && declaration.getPackageFragment() !is IrExternalPackageFragment + } else when (val parent = declaration.parent) { + is IrPackageFragment -> parent.konanLibrary.let { it == null || containsLibrary(it) } && parent !is IrExternalPackageFragment + is IrDeclaration -> containsDeclaration(parent) + else -> TODO("Unexpected declaration parent: $parent") + } + } } internal class DefaultLlvmModuleSpecification(cachedLibraries: CachedLibraries) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt index abd54bb7380..8a1677efd1e 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt @@ -163,8 +163,9 @@ internal fun PsiToIrContext.psiToIr( var dependenciesCount = 0 while (true) { // context.config.librariesWithDependencies could change at each iteration. + val libsWithDeps = config.librariesWithDependencies().toSet() val dependencies = moduleDescriptor.allDependencyModules.filter { - config.librariesWithDependencies().contains(it.konanLibrary) + libsWithDeps.contains(it.konanLibrary) } fun sortDependencies(dependencies: List): Collection { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/NewIrUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/NewIrUtils.kt index 20ad03404d0..a0262746c5d 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/NewIrUtils.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/NewIrUtils.kt @@ -110,6 +110,8 @@ val IrPackageFragment.konanLibrary : KotlinLibrary? } return this.packageFragmentDescriptor.containingDeclaration.konanLibrary } +// Any changes made to konanLibrary here should be ported to the containsDeclaration +// function in LlvmModuleSpecificationBase in LlvmModuleSpecificationImpl.kt val IrDeclaration.konanLibrary: KotlinLibrary? get() { ((this as? IrMetadataSourceOwner)?.metadata as? KonanMetadata)?.let { return it.konanLibrary } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt index 953e9172883..595134606c3 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt @@ -1785,7 +1785,7 @@ private fun ObjCExportCodeGenerator.createDirectAdapters( ) } - val inheritedAdapters = superClass?.getAllRequiredDirectAdapters().orEmpty() + val inheritedAdapters = superClass?.getAllRequiredDirectAdapters().orEmpty().toSet() val requiredAdapters = typeDeclaration.getAllRequiredDirectAdapters() - inheritedAdapters return requiredAdapters.distinctBy { it.base.selector }.map { createMethodAdapter(it) } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BuiltinOperatorLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BuiltinOperatorLowering.kt index 3fb04cd6b12..44893ee2771 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BuiltinOperatorLowering.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BuiltinOperatorLowering.kt @@ -43,7 +43,7 @@ internal class BuiltinOperatorLowering(val context: Context) : FileLoweringPass, expression.transformChildrenVoid(this) return when (expression.symbol) { - irBuiltins.eqeqSymbol, in ieee754EqualsSymbols() -> lowerEqeq(expression) + irBuiltins.eqeqSymbol, in ieee754EqualsSymbols -> lowerEqeq(expression) irBuiltins.eqeqeqSymbol -> lowerEqeqeq(expression) @@ -70,8 +70,8 @@ internal class BuiltinOperatorLowering(val context: Context) : FileLoweringPass, return expression } - private fun ieee754EqualsSymbols(): List = - irBuiltins.ieee754equalsFunByOperandType.values.toList() + private val ieee754EqualsSymbols: Set = + irBuiltins.ieee754equalsFunByOperandType.values.toSet() private fun lowerEqeqeq(expression: IrCall): IrExpression { val lhs = expression.getValueArgument(0)!! @@ -191,7 +191,7 @@ internal class BuiltinOperatorLowering(val context: Context) : FileLoweringPass, // TODO: areEqualByValue and ieee754Equals intrinsics are specially treated by code generator // and thus can be declared synthetically in the compiler instead of explicitly in the runtime. fun callEquals(lhs: IrExpression, rhs: IrExpression) = - if (symbol in ieee754EqualsSymbols()) + if (symbol in ieee754EqualsSymbols) // Find a type-compatible `konan.internal.ieee754Equals` intrinsic: irCall(selectIntrinsic(symbols.ieee754Equals, lhs.type, rhs.type, true)!!).apply { putValueArgument(0, lhs) @@ -206,7 +206,7 @@ internal class BuiltinOperatorLowering(val context: Context) : FileLoweringPass, val lhsIsNotNullable = !lhs.type.isNullable() val rhsIsNotNullable = !rhs.type.isNullable() - return if (symbol in ieee754EqualsSymbols()) { + return if (symbol in ieee754EqualsSymbols) { if (lhsIsNotNullable && rhsIsNotNullable) callEquals(lhs, rhs) else irBlock { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/PreInlineLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/PreInlineLowering.kt index 421e8953f11..f9bd2887c39 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/PreInlineLowering.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/PreInlineLowering.kt @@ -33,7 +33,7 @@ internal class PreInlineLowering(val context: Context) : BodyLoweringPass { private val symbols get() = context.ir.symbols - private val asserts = symbols.asserts + private val asserts = symbols.asserts.toSet() private val enableAssertions = context.config.configuration.getBoolean(KonanConfigKeys.ENABLE_ASSERTIONS) override fun lower(irBody: IrBody, container: IrDeclaration) = lower(irBody, container, container.file) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/StaticInitializersOptimization.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/StaticInitializersOptimization.kt index a1c833e247d..6e3cba2d6a0 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/StaticInitializersOptimization.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/StaticInitializersOptimization.kt @@ -179,12 +179,12 @@ internal object StaticInitializersOptimization { val functionsRequiringGlobalInitializerCall = collectFunctionsRequiringInitializerCall( initializedFiles.beforeCallGlobal, callSitesRequiringGlobalInitializerCall.map { it.actualCallee } - .toMutableSet().intersect(callSitesNotRequiringGlobalInitializerCall.map { it.actualCallee }) + .intersect(callSitesNotRequiringGlobalInitializerCall.mapTo(mutableSetOf()) { it.actualCallee }) ) val functionsRequiringThreadLocalInitializerCall = collectFunctionsRequiringInitializerCall( initializedFiles.beforeCallThreadLocal, callSitesRequiringThreadLocalInitializerCall.map { it.actualCallee } - .toMutableSet().intersect(callSitesNotRequiringThreadLocalInitializerCall.map { it.actualCallee }) + .intersect(callSitesNotRequiringThreadLocalInitializerCall.mapTo(mutableSetOf()) { it.actualCallee }) ) return AnalysisResult(functionsRequiringGlobalInitializerCall, functionsRequiringThreadLocalInitializerCall,