diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt index 50f55ee8c4e..5b086eb6b35 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.backend.konan import llvm.* +import org.jetbrains.kotlin.backend.common.deepCopyWithVariables import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.ir.KonanIr import org.jetbrains.kotlin.library.SerializedMetadata @@ -47,6 +48,7 @@ import org.jetbrains.kotlin.backend.konan.serialization.KonanIrLinker import org.jetbrains.kotlin.backend.konan.serialization.SerializedClassFields import org.jetbrains.kotlin.backend.konan.serialization.SerializedInlineFunctionReference import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyClass +import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl import org.jetbrains.kotlin.name.FqName @@ -57,7 +59,7 @@ import org.jetbrains.kotlin.konan.util.disposeNativeMemoryAllocator import org.jetbrains.kotlin.library.SerializedIrModule import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal -internal class InlineFunctionOriginInfo(val irFile: IrFile, val startOffset: Int, val endOffset: Int) +internal class InlineFunctionOriginInfo(val irFunction: IrFunction, val irFile: IrFile, val startOffset: Int, val endOffset: Int) /** * Offset for synthetic elements created by lowerings and not attributable to other places in the source code. @@ -73,7 +75,13 @@ internal class SpecialDeclarationsFactory(val context: Context) { private val bridges = mutableMapOf() + private val notLoweredInlineFunctions = mutableMapOf() val loweredInlineFunctions = mutableMapOf() + fun getNonLoweredInlineFunction(function: IrFunction): IrFunction { + return notLoweredInlineFunctions.getOrPut(function.symbol) { + function.deepCopyWithVariables().also { it.patchDeclarationParents(function.parent) } + } + } object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS : IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS") diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt index 39586de7511..cb725d83c37 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt @@ -22,8 +22,12 @@ import org.jetbrains.kotlin.backend.konan.lower.* import org.jetbrains.kotlin.backend.konan.lower.FinallyBlocksLowering import org.jetbrains.kotlin.backend.konan.lower.InitializersLowering import org.jetbrains.kotlin.backend.konan.optimizations.KonanBCEForLoopBodyTransformer +import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid private val validateAll = false @@ -89,13 +93,21 @@ internal val specialBackendChecksPhase = konanUnitPhase( description = "Special backend checks" ) -internal val removeExpectDeclarationsPhase = makeKonanModuleLoweringPhase( +internal val propertyAccessorInlinePhase = makeKonanModuleLoweringPhase( + ::PropertyAccessorInlineLowering, + name = "PropertyAccessorInline", + description = "Property accessor inline lowering" +) + +/* IrFile phases */ + +internal val removeExpectDeclarationsPhase = makeKonanFileLoweringPhase( ::ExpectDeclarationsRemoving, name = "RemoveExpectDeclarations", description = "Expect declarations removing" ) -internal val stripTypeAliasDeclarationsPhase = makeKonanModuleLoweringPhase( +internal val stripTypeAliasDeclarationsPhase = makeKonanFileLoweringPhase( { StripTypeAliasDeclarationsLowering() }, name = "StripTypeAliasDeclarations", description = "Strip typealias declarations" @@ -107,102 +119,90 @@ internal val annotationImplementationPhase = makeKonanFileLoweringPhase( description = "Create synthetic annotations implementations and use them in annotations constructor calls" ) -internal val lowerBeforeInlinePhase = makeKonanModuleLoweringPhase( +internal val lowerBeforeInlinePhase = makeKonanFileLoweringPhase( ::PreInlineLowering, name = "LowerBeforeInline", description = "Special operations processing before inlining" ) -internal val arrayConstructorPhase = makeKonanModuleLoweringPhase( +internal val arrayConstructorPhase = makeKonanFileLoweringPhase( ::ArrayConstructorLowering, name = "ArrayConstructor", description = "Transform `Array(size) { index -> value }` into a loop" ) -internal val lateinitPhase = makeKonanModuleOpPhase( - { context, irModule -> - NullableFieldsForLateinitCreationLowering(context).lower(irModule) - NullableFieldsDeclarationLowering(context).lower(irModule) - LateinitUsageLowering(context).lower(irModule) +internal val lateinitPhase = makeKonanFileOpPhase( + { context, irFile -> + NullableFieldsForLateinitCreationLowering(context).lower(irFile) + NullableFieldsDeclarationLowering(context).lower(irFile) + LateinitUsageLowering(context).lower(irFile) }, name = "Lateinit", description = "Lateinit properties lowering" ) -internal val propertyAccessorInlinePhase = makeKonanModuleLoweringPhase( - ::PropertyAccessorInlineLowering, - name = "PropertyAccessorInline", - description = "Property accessor inline lowering" -) - -internal val sharedVariablesPhase = makeKonanModuleLoweringPhase( +internal val sharedVariablesPhase = makeKonanFileLoweringPhase( ::SharedVariablesLowering, name = "SharedVariables", description = "Shared variable lowering", prerequisite = setOf(lateinitPhase) ) -internal val inventNamesForLocalClasses = makeKonanModuleLoweringPhase( - ::NativeInventNamesForLocalClasses, +internal val inventNamesForLocalClasses = makeKonanFileLoweringPhase( + { NativeInventNamesForLocalClasses(it) }, name = "InventNamesForLocalClasses", description = "Invent names for local classes and anonymous objects" ) -internal val extractLocalClassesFromInlineBodies = NamedCompilerPhase( - lower = object : SameTypeCompilerPhase { - override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, input: IrModuleFragment): IrModuleFragment { - LocalClassesInInlineLambdasLowering(context).run { - input.files.forEach { lower(it) } - } - LocalClassesInInlineFunctionsLowering(context).run { - input.files.forEach { lower(it) } - } - LocalClassesExtractionFromInlineFunctionsLowering(context).run { - input.files.forEach { lower(it) } - } - return input - } +internal val extractLocalClassesFromInlineBodies = makeKonanFileOpPhase( + { context, irFile -> + LocalClassesInInlineLambdasLowering(context).lower(irFile) + LocalClassesInInlineFunctionsLowering(context).lower(irFile) + LocalClassesExtractionFromInlineFunctionsLowering(context).lower(irFile) }, name = "ExtractLocalClassesFromInlineBodies", description = "Extraction of local classes from inline bodies", prerequisite = setOf(sharedVariablesPhase), // TODO: add "soft" dependency on inventNamesForLocalClasses - nlevels = 0, - actions = modulePhaseActions ) -internal val inlinePhase = NamedCompilerPhase( - lower = object : SameTypeCompilerPhase { - override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, input: IrModuleFragment): IrModuleFragment { - FunctionInlining(context, NativeInlineFunctionResolver(context)).run { - input.files.forEach { lower(it) } +internal val inlinePhase = makeKonanFileOpPhase( + { context, irFile -> + irFile.acceptChildrenVoid(object : IrElementVisitorVoid { + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) } - return input - } + + override fun visitFunction(declaration: IrFunction) { + if (declaration.isInline) + context.specialDeclarationsFactory.getNonLoweredInlineFunction(declaration) + declaration.acceptChildrenVoid(this) + } + }) + + FunctionInlining(context, NativeInlineFunctionResolver(context)).lower(irFile) }, name = "Inline", description = "Functions inlining", - prerequisite = setOf(lowerBeforeInlinePhase, arrayConstructorPhase, extractLocalClassesFromInlineBodies), - nlevels = 0, - actions = modulePhaseActions + prerequisite = setOf(lowerBeforeInlinePhase, arrayConstructorPhase, extractLocalClassesFromInlineBodies) ) -internal val lowerAfterInlinePhase = makeKonanModuleOpPhase( - { context, irModule -> - irModule.files.forEach(PostInlineLowering(context)::lower) - // TODO: Seems like this should be deleted in PsiToIR. - irModule.files.forEach(ContractsDslRemover(context)::lower) - }, - name = "LowerAfterInline", - description = "Special operations processing after inlining" +internal val postInlinePhase = makeKonanFileLoweringPhase( + { PostInlineLowering(it) }, + name = "PostInline", + description = "Post-processing after inlining" ) -/* IrFile phases */ +internal val contractsDslRemovePhase = makeKonanFileLoweringPhase( + { ContractsDslRemover(it) }, + name = "RemoveContractsDsl", + description = "Contracts dsl removing" +) // TODO make all lambda-related stuff work with IrFunctionExpression and drop this phase (see kotlin: dd3f8ecaacd) -internal val provisionalFunctionExpressionPhase = makeKonanModuleLoweringPhase( - { ProvisionalFunctionExpressionLowering() }, - name = "FunctionExpression-before-inliner", - description = "Transform IrFunctionExpression to a local function reference" +internal val provisionalFunctionExpressionPhase = makeKonanFileLoweringPhase( + { ProvisionalFunctionExpressionLowering() }, + name = "FunctionExpression", + description = "Transform IrFunctionExpression to a local function reference" ) internal val flattenStringConcatenationPhase = makeKonanFileLoweringPhase( diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt index 82313358352..f1af61356d7 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt @@ -256,56 +256,57 @@ internal val allLoweringsPhase = NamedCompilerPhase( name = "IrLowering", description = "IR Lowering", // TODO: The lowerings before inlinePhase should be aligned with [NativeInlineFunctionResolver.kt] - lower = removeExpectDeclarationsPhase then - stripTypeAliasDeclarationsPhase then - lowerBeforeInlinePhase then - arrayConstructorPhase then - lateinitPhase then - sharedVariablesPhase then - inventNamesForLocalClasses then - extractLocalClassesFromInlineBodies then - inlinePhase then - provisionalFunctionExpressionPhase then - lowerAfterInlinePhase then - performByIrFile( - name = "IrLowerByFile", - description = "IR Lowering by file", - lower = listOf( - annotationImplementationPhase, - rangeContainsLoweringPhase, - forLoopsPhase, - flattenStringConcatenationPhase, - foldConstantLoweringPhase, - computeStringTrimPhase, - stringConcatenationPhase, - enumConstructorsPhase, - initializersPhase, - localFunctionsPhase, - tailrecPhase, - defaultParameterExtentPhase, - innerClassPhase, - dataClassesPhase, - ifNullExpressionsFusionPhase, - testProcessorPhase, - delegationPhase, - functionReferencePhase, - singleAbstractMethodPhase, - enumWhenPhase, - builtinOperatorPhase, - finallyBlocksPhase, - enumClassPhase, - enumUsagePhase, - interopPhase, - varargPhase, - kotlinNothingValueExceptionPhase, - coroutinesPhase, - typeOperatorPhase, - expressionBodyTransformPhase, - fileInitializersPhase, - bridgesPhase, - autoboxPhase, - ) - ), + lower = performByIrFile( + name = "IrLowerByFile", + description = "IR Lowering by file", + lower = listOf( + removeExpectDeclarationsPhase, + stripTypeAliasDeclarationsPhase, + lowerBeforeInlinePhase, + arrayConstructorPhase, + lateinitPhase, + sharedVariablesPhase, + inventNamesForLocalClasses, + extractLocalClassesFromInlineBodies, + inlinePhase, + provisionalFunctionExpressionPhase, + postInlinePhase, + contractsDslRemovePhase, + annotationImplementationPhase, + rangeContainsLoweringPhase, + forLoopsPhase, + flattenStringConcatenationPhase, + foldConstantLoweringPhase, + computeStringTrimPhase, + stringConcatenationPhase, + enumConstructorsPhase, + initializersPhase, + localFunctionsPhase, + tailrecPhase, + defaultParameterExtentPhase, + innerClassPhase, + dataClassesPhase, + ifNullExpressionsFusionPhase, + testProcessorPhase, + delegationPhase, + functionReferencePhase, + singleAbstractMethodPhase, + enumWhenPhase, + builtinOperatorPhase, + finallyBlocksPhase, + enumClassPhase, + enumUsagePhase, + interopPhase, + varargPhase, + kotlinNothingValueExceptionPhase, + coroutinesPhase, + typeOperatorPhase, + expressionBodyTransformPhase, + fileInitializersPhase, + bridgesPhase, + autoboxPhase, + ) + ), actions = setOf(defaultDumper, ::moduleValidationCallback) ) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/NativeInlineFunctionResolver.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/NativeInlineFunctionResolver.kt index 0c8b986f3ea..6596da62dc8 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/NativeInlineFunctionResolver.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/NativeInlineFunctionResolver.kt @@ -26,44 +26,46 @@ internal class NativeInlineFunctionResolver(override val context: Context) : Def override fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction { val function = super.getFunctionDeclaration(symbol) - if (function in context.specialDeclarationsFactory.loweredInlineFunctions) - return function + context.specialDeclarationsFactory.loweredInlineFunctions[function]?.let { return it.irFunction } val packageFragment = function.findPackage() - if (packageFragment !is IrExternalPackageFragment) { - context.specialDeclarationsFactory.loweredInlineFunctions[function] = - InlineFunctionOriginInfo(function.file, function.startOffset, function.endOffset) + val notLoweredFunction = if (packageFragment !is IrExternalPackageFragment) { + context.specialDeclarationsFactory.getNonLoweredInlineFunction(function).also { + context.specialDeclarationsFactory.loweredInlineFunctions[function] = + InlineFunctionOriginInfo(it, function.file, function.startOffset, function.endOffset) + } } else { // The function is from Lazy IR, get its body from the IR linker. val moduleDescriptor = packageFragment.packageFragmentDescriptor.containingDeclaration val moduleDeserializer = context.irLinker.cachedLibraryModuleDeserializers[moduleDescriptor] ?: error("No module deserializer for ${function.render()}") context.specialDeclarationsFactory.loweredInlineFunctions[function] = moduleDeserializer.deserializeInlineFunction(function) + function } - val body = function.body ?: return function + val body = notLoweredFunction.body ?: return notLoweredFunction - PreInlineLowering(context).lower(body, function, context.specialDeclarationsFactory.loweredInlineFunctions[function]!!.irFile) + PreInlineLowering(context).lower(body, notLoweredFunction, context.specialDeclarationsFactory.loweredInlineFunctions[function]!!.irFile) - ArrayConstructorLowering(context).lower(body, function) + ArrayConstructorLowering(context).lower(body, notLoweredFunction) - NullableFieldsForLateinitCreationLowering(context).lowerWithLocalDeclarations(function) - NullableFieldsDeclarationLowering(context).lowerWithLocalDeclarations(function) - LateinitUsageLowering(context).lower(body, function) + NullableFieldsForLateinitCreationLowering(context).lowerWithLocalDeclarations(notLoweredFunction) + NullableFieldsDeclarationLowering(context).lowerWithLocalDeclarations(notLoweredFunction) + LateinitUsageLowering(context).lower(body, notLoweredFunction) - SharedVariablesLowering(context).lower(body, function) + SharedVariablesLowering(context).lower(body, notLoweredFunction) - OuterThisLowering(context).lower(function) + OuterThisLowering(context).lower(notLoweredFunction) - LocalClassesInInlineLambdasLowering(context).lower(body, function) + LocalClassesInInlineLambdasLowering(context).lower(body, notLoweredFunction) if (context.llvmModuleSpecification.containsPackageFragment(packageFragment)) { // Do not extract local classes off of inline functions from cached libraries. - LocalClassesInInlineFunctionsLowering(context).lower(body, function) - LocalClassesExtractionFromInlineFunctionsLowering(context).lower(body, function) + LocalClassesInInlineFunctionsLowering(context).lower(body, notLoweredFunction) + LocalClassesExtractionFromInlineFunctionsLowering(context).lower(body, notLoweredFunction) } - return function + return notLoweredFunction } private fun DeclarationTransformer.lowerWithLocalDeclarations(function: IrFunction) { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrlinker.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrlinker.kt index 5014910dd2b..2fcfb9f40d5 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrlinker.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrlinker.kt @@ -711,6 +711,7 @@ internal class KonanIrLinker( if (function.parents.any { (it as? IrFunction)?.isInline == true}) { // Already deserialized by the top-most inline function. return InlineFunctionOriginInfo( + function, inlineFunctionFiles[packageFragment] ?: error("${function.render()} should've been deserialized along with its parent"), function.startOffset, function.endOffset @@ -777,7 +778,7 @@ internal class KonanIrLinker( } inlineFunctionFiles[packageFragment] = fileDeserializationInfo.file - return InlineFunctionOriginInfo(fileDeserializationInfo.file, inlineFunctionReference.startOffset, inlineFunctionReference.endOffset) + return InlineFunctionOriginInfo(function, fileDeserializationInfo.file, inlineFunctionReference.startOffset, inlineFunctionReference.endOffset) } private val classesFields by lazy {