[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,