[IR] Optimize a few hot spots to reduce total CPU time
^KT-61121
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 c922efe..f8f3c55 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 @@
}
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 974f5c4..d33ca7b 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 @@
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 03263e7..ef39478 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.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.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 2e1d04b..84c8854 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 @@
)
// Set inter-dependencies between module descriptors, add forwarding declarations module.
+ val additionalDependencyModulesCopy = additionalDependencyModules.toSet()
+ val friendsForNonIncludedModule = additionalDependencyModulesCopy
+ val friendsForIncludedModule = buildSet<ModuleDescriptorImpl> {
+ 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 c5c312a..a6d5e99 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 @@
manifestProperties.propertyList(KLIB_PROPERTY_DEPENDS, escapeInQuotes = true)
.map { UnresolvedLibrary(it, manifestProperties.getProperty("dependency_version_$it"), lenient = lenient) }
+val BaseKotlinLibrary.hasDependencies: Boolean
+ get() = !manifestProperties.getProperty(KLIB_PROPERTY_DEPENDS).isNullOrBlank()
+
interface KotlinLibrary : BaseKotlinLibrary, MetadataLibrary, IrLibrary
// TODO: should we move the below ones to Native?
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LlvmModuleSpecificationImpl.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LlvmModuleSpecificationImpl.kt
index 194bb39..3c37027 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LlvmModuleSpecificationImpl.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LlvmModuleSpecificationImpl.kt
@@ -9,6 +9,7 @@
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.util.fileOrNull
+import org.jetbrains.kotlin.backend.konan.llvm.KonanMetadata
import org.jetbrains.kotlin.ir.util.getPackageFragment
import org.jetbrains.kotlin.library.KotlinLibrary
@@ -28,10 +29,20 @@
override fun containsPackageFragment(packageFragment: IrPackageFragment): Boolean =
packageFragment.konanLibrary.let { it == null || containsLibrary(it) }
- override fun containsDeclaration(declaration: IrDeclaration): Boolean =
- declaration.konanLibrary.let { it == null || containsLibrary(it) }
- // When producing per-file caches, some declarations might be generated by the stub generator.
- && declaration.getPackageFragment() !is IrExternalPackageFragment
+ private val containsCache = mutableMapOf<IrDeclaration, Boolean>()
+
+ // 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 abd54bb..8a1677e 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 @@
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<ModuleDescriptor>): Collection<ModuleDescriptor> {
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 20ad034..a026274 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 @@
}
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 953e917..5951346 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 @@
)
}
- 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 3fb04cd..44893ee 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 @@
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 @@
return expression
}
- private fun ieee754EqualsSymbols(): List<IrSimpleFunctionSymbol> =
- irBuiltins.ieee754equalsFunByOperandType.values.toList()
+ private val ieee754EqualsSymbols: Set<IrSimpleFunctionSymbol> =
+ irBuiltins.ieee754equalsFunByOperandType.values.toSet()
private fun lowerEqeqeq(expression: IrCall): IrExpression {
val lhs = expression.getValueArgument(0)!!
@@ -191,7 +191,7 @@
// 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 @@
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 421e895..f9bd288 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 @@
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 a1c833e..6e3cba2 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 @@
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,