From 565ea2c4f5fa49bae8195693c086921f11bba680 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Tue, 17 Aug 2021 17:52:31 +0200 Subject: [PATCH] [Commonizer] Improve iteration performance in transformer and mergeCirTree An allocation/iterator free `forEach` is used for lists that are not intended to be modified at the same time. --- .../TypeSubstitutionCirNodeTransformer.kt | 13 ++++++----- .../kotlin/commonizer/tree/mergeCirTree.kt | 21 +++++++++--------- .../jetbrains/kotlin/commonizer/utils/misc.kt | 22 +++++++++++++++++++ 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/transformer/TypeSubstitutionCirNodeTransformer.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/transformer/TypeSubstitutionCirNodeTransformer.kt index f4ec3645359..d6703b83ba0 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/transformer/TypeSubstitutionCirNodeTransformer.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/transformer/TypeSubstitutionCirNodeTransformer.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.commonizer.transformer import org.jetbrains.kotlin.commonizer.mergedtree.* import org.jetbrains.kotlin.commonizer.mergedtree.CirNodeRelationship.ParentNode +import org.jetbrains.kotlin.commonizer.utils.fastForEach import org.jetbrains.kotlin.storage.StorageManager internal class TypeSubstitutionCirNodeTransformer( @@ -26,16 +27,16 @@ internal class TypeSubstitutionCirNodeTransformer( } private operator fun invoke(pkg: CirPackageNode, index: Int) { - pkg.functions.values.toList().forEach { function -> this(pkg, function, index, CirMemberContext.empty) } - pkg.properties.values.toList().forEach { property -> this(pkg, property, index, CirMemberContext.empty) } - pkg.classes.values.toList().forEach { clazz -> this(clazz, index, CirMemberContext.empty) } + pkg.functions.values.toTypedArray().fastForEach { function -> this(pkg, function, index, CirMemberContext.empty) } + pkg.properties.values.toTypedArray().fastForEach { property -> this(pkg, property, index, CirMemberContext.empty) } + pkg.classes.values.toTypedArray().fastForEach { clazz -> this(clazz, index, CirMemberContext.empty) } } private operator fun invoke(clazz: CirClassNode, index: Int, context: CirMemberContext) { val contextWithClass = context.withContextOf(clazz.targetDeclarations[index] ?: return) - clazz.functions.values.toList().forEach { function -> this(clazz, function, index, contextWithClass) } - clazz.properties.values.toList().forEach { property -> this(clazz, property, index, contextWithClass) } - clazz.classes.values.toList().forEach { innerClass -> this(innerClass, index, contextWithClass) } + clazz.functions.values.toTypedArray().fastForEach { function -> this(clazz, function, index, contextWithClass) } + clazz.properties.values.toTypedArray().fastForEach { property -> this(clazz, property, index, contextWithClass) } + clazz.classes.values.toTypedArray().fastForEach { innerClass -> this(innerClass, index, contextWithClass) } } private operator fun invoke(parent: CirNodeWithMembers<*, *>, function: CirFunctionNode, index: Int, context: CirMemberContext) { diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/tree/mergeCirTree.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/tree/mergeCirTree.kt index e9baf46b09d..803d8d28f2a 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/tree/mergeCirTree.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/tree/mergeCirTree.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.commonizer.cir.* import org.jetbrains.kotlin.commonizer.mergedtree.* import org.jetbrains.kotlin.commonizer.mergedtree.CirNodeRelationship.Companion.ParentNode import org.jetbrains.kotlin.commonizer.mergedtree.CirNodeRelationship.ParentNode +import org.jetbrains.kotlin.commonizer.utils.fastForEach import org.jetbrains.kotlin.storage.StorageManager internal data class TargetBuildingContext( @@ -41,7 +42,7 @@ internal fun mergeCirTree( } internal fun CirRootNode.buildModules(context: TargetBuildingContext, modules: List) { - modules.forEach { module -> buildModule(context, module) } + modules.fastForEach { module -> buildModule(context, module) } } internal fun CirRootNode.buildModule(context: TargetBuildingContext, treeModule: CirTreeModule) { @@ -49,7 +50,7 @@ internal fun CirRootNode.buildModule(context: TargetBuildingContext, treeModule: buildModuleNode(context.storageManager, context.targets) } moduleNode.targetDeclarations[context.targetIndex] = treeModule.module - treeModule.packages.forEach { pkg -> moduleNode.buildPackage(context, pkg) } + treeModule.packages.fastForEach { pkg -> moduleNode.buildPackage(context, pkg) } } internal fun CirModuleNode.buildPackage(context: TargetBuildingContext, treePackage: CirTreePackage) { @@ -57,10 +58,10 @@ internal fun CirModuleNode.buildPackage(context: TargetBuildingContext, treePack buildPackageNode(context.storageManager, context.targets) } packageNode.targetDeclarations[context.targetIndex] = treePackage.pkg - treePackage.functions.forEach { function -> packageNode.buildFunction(context, function) } - treePackage.properties.forEach { property -> packageNode.buildProperty(context, property) } - treePackage.typeAliases.forEach { typeAlias -> packageNode.buildTypeAlias(context, typeAlias) } - treePackage.classes.forEach { clazz -> packageNode.buildClass(context, clazz) } + treePackage.functions.fastForEach { function -> packageNode.buildFunction(context, function) } + treePackage.properties.fastForEach { property -> packageNode.buildProperty(context, property) } + treePackage.typeAliases.fastForEach { typeAlias -> packageNode.buildTypeAlias(context, typeAlias) } + treePackage.classes.fastForEach { clazz -> packageNode.buildClass(context, clazz) } } internal fun CirNodeWithMembers<*, *>.buildClass( @@ -71,10 +72,10 @@ internal fun CirNodeWithMembers<*, *>.buildClass( } classNode.targetDeclarations[context.targetIndex] = treeClass.clazz val contextWithClass = context.withMemberContextOf(treeClass.clazz) - treeClass.functions.forEach { function -> classNode.buildFunction(contextWithClass, function, classNode) } - treeClass.properties.forEach { property -> classNode.buildProperty(contextWithClass, property, classNode) } - treeClass.constructors.forEach { constructor -> classNode.buildConstructor(contextWithClass, constructor, classNode) } - treeClass.classes.forEach { clazz -> classNode.buildClass(contextWithClass, clazz, classNode) } + treeClass.functions.fastForEach { function -> classNode.buildFunction(contextWithClass, function, classNode) } + treeClass.properties.fastForEach { property -> classNode.buildProperty(contextWithClass, property, classNode) } + treeClass.constructors.fastForEach { constructor -> classNode.buildConstructor(contextWithClass, constructor, classNode) } + treeClass.classes.fastForEach { clazz -> classNode.buildClass(contextWithClass, clazz, classNode) } } internal fun CirNodeWithMembers<*, *>.buildFunction( diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/utils/misc.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/utils/misc.kt index 75883478d4c..d9b1ef972f1 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/utils/misc.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/utils/misc.kt @@ -100,3 +100,25 @@ inline fun Int.appendHashCode(value: Any?): Int = 31 * this + hashCode(value) @Suppress("NOTHING_TO_INLINE") inline fun Int.appendHashCode(array: Array<*>?): Int = 31 * this + hashCode(array) + +/** + * Allocation Free 'forEach' implementation that won't use any underlying iterator. + * Note: This implementation therefore is unsafe when mutating the collection at the same time!!! + */ +inline fun List.fastForEach(action: (T) -> Unit) { + val size = this.size + for (index in 0 until size) { + action(this[index]) + } +} + +/** + * Allocation Free 'forEach' implementation that won't use any underlying iterator. + * Note: This implementation therefore is unsafe when mutating the collection at the same time!!! + */ +inline fun Array.fastForEach(action: (T) -> Unit) { + val size = this.size + for (index in 0 until size) { + action(this[index]) + } +}