diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt index 6ce4d554cd7..401678da29c 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt @@ -38,6 +38,10 @@ internal class KonanLower(val context: Context) { fun lowerModule(irModule: IrModuleFragment) { val phaser = PhaseManager(context) + phaser.phase(KonanPhase.LOWER_INLINE_CONSTRUCTORS) { + InlineConstructorsTransformation(context).lower(irModule) + } + // Inlining must be run before other phases. phaser.phase(KonanPhase.LOWER_INLINE) { FunctionInlining(context).inline(irModule) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt index a73095141c5..0523be033a0 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt @@ -27,6 +27,7 @@ enum class KonanPhase(val description: String, /* */ SERIALIZER("Serialize descriptor tree and inline IR bodies"), /* */ BACKEND("All backend"), /* ... */ LOWER("IR Lowering"), + /* ... ... */ LOWER_INLINE_CONSTRUCTORS("Inline constructors transformation"), /* ... ... */ LOWER_INLINE("Functions inlining"), /* ... ... ... */ DESERIALIZER("Deserialize inline bodies"), /* ... ... */ LOWER_ENUMS("Enum classes lowering"), diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt index b9430724319..f3cb9a48945 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt @@ -35,20 +35,18 @@ import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrModuleFragment -import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.getDefault import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrMemberAccessExpressionBase +import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid -import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue import org.jetbrains.kotlin.types.TypeProjectionImpl import org.jetbrains.kotlin.types.TypeSubstitutor -private val inlineConstructor = FqName("konan.internal.InlineConstructor") - //-----------------------------------------------------------------------------// internal class FunctionInlining(val context: Context): IrElementTransformerVoidWithContext() { @@ -103,14 +101,12 @@ private class Inliner(val currentScope: ScopeWithIr, val context: Context) { val copyIrElement = DeepCopyIrTreeWithDescriptors(currentScope.scope.scopeOwner, context) // Create DeepCopy for current scope. val substituteMap = mutableMapOf() - var isInlineConstructor = false //-------------------------------------------------------------------------// fun inline(irCall : IrCall, // Call to be substituted. functionDeclaration: IrFunction): IrReturnableBlockImpl { // Function to substitute. - isInlineConstructor = irCall.descriptor.annotations.hasAnnotation(inlineConstructor) val inlineFunctionBody = inlineFunction(irCall, functionDeclaration) val descriptorSubstitutor = copyIrElement.descriptorSubstitutorForExternalScope currentScope.irElement.transformChildrenVoid(descriptorSubstitutor) // Transform calls to object that might be returned from inline function call. @@ -129,9 +125,8 @@ private class Inliner(val currentScope: ScopeWithIr, val context: Context) { typeSubstitutor = createTypeSubstitutor(irCall) // Type parameters will be substituted with type arguments. ) as IrFunction - val copyStatements = (copyFunctionDeclaration.body as IrBlockBody).statements // IR statements from function copy. - val statements = replaceDelegatingConstructorCall(copyStatements, irCall) - val returnType = copyFunctionDeclaration.descriptor.returnType!! // Substituted return type. + val statements = (copyFunctionDeclaration.body as IrBlockBody).statements // IR statements from function copy. + val returnType = copyFunctionDeclaration.descriptor.returnType!! // Substituted return type. val inlineFunctionBody = IrReturnableBlockImpl( // Create new IR element to replace "call". startOffset = copyFunctionDeclaration.startOffset, endOffset = copyFunctionDeclaration.endOffset, @@ -356,69 +351,6 @@ private class Inliner(val currentScope: ScopeWithIr, val context: Context) { } return evaluationStatements } - - //-------------------------------------------------------------------------// - - private fun replaceDelegatingConstructorCall(statements: List, irCall: IrCall): List { - - if (!isInlineConstructor) return statements - - val delegatingCall = statements[0] - if (delegatingCall !is IrDelegatingConstructorCallImpl) return statements - - val thisVariable = generateIrCall(delegatingCall) - - val newThisGetValue = IrGetValueImpl( // Create new expression, representing access the new variable. - startOffset = currentScope.irElement.startOffset, - endOffset = currentScope.irElement.endOffset, - descriptor = thisVariable.descriptor - ) - - val classDescriptor = delegatingCall.descriptor.constructedClass - val oldThisGetValue = classDescriptor.thisAsReceiverParameter - substituteMap[oldThisGetValue] = newThisGetValue - - val newStatements = statements.toMutableList() - newStatements[0] = thisVariable - newStatements += newThisGetValue - - val block = IrBlockImpl( - startOffset = 0, - endOffset = 0, - type = newThisGetValue.type, - origin = null, - statements = newStatements - ) - - val returnThis = IrReturnImpl(0, 0, irCall.descriptor, block) - return listOf(returnThis) - } - - //-------------------------------------------------------------------------// - - fun generateIrCall(expression: IrDelegatingConstructorCallImpl): IrVariable { - - val newExpression = IrCallImpl( - expression.startOffset, - expression.endOffset, - expression.descriptor.returnType, - expression.descriptor, - expression.typeArguments, - expression.origin - ).apply { - expression.descriptor.valueParameters.forEach { - val valueArgument = expression.getValueArgument(it) - putValueArgument(it.index, valueArgument) - } - } - - val newVariable = currentScope.scope.createTemporaryVariable( // Create new variable and init it with constructor call. - irExpression = newExpression, - nameHint = newExpression.descriptor.fqNameSafe.toString() + ".this", - isMutable = false) - - return newVariable - } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InlineConstructorsTransformation.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InlineConstructorsTransformation.kt new file mode 100644 index 00000000000..6a87e3147ea --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InlineConstructorsTransformation.kt @@ -0,0 +1,178 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("FoldInitializerAndIfToElvis") + +package org.jetbrains.kotlin.backend.konan.lower + +import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.reportWarning +import org.jetbrains.kotlin.backend.konan.Context +import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride +import org.jetbrains.kotlin.backend.konan.ir.DeserializerDriver +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.ValueDescriptor +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.declarations.IrVariable +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe + +private val inlineConstructor = FqName("konan.internal.InlineConstructor") + +//-----------------------------------------------------------------------------// + +internal class InlineConstructorsTransformation(val context: Context): IrElementTransformerVoidWithContext() { + + private val deserializer = DeserializerDriver(context) + val substituteMap = mutableMapOf() + + //-------------------------------------------------------------------------// + + fun lower(irModule: IrModuleFragment) = irModule.accept(this, null) + + //-------------------------------------------------------------------------// + + override fun visitCall(expression: IrCall): IrExpression { + + val irCall = super.visitCall(expression) as IrCall + val functionDescriptor = irCall.descriptor + if (!functionDescriptor.annotations.hasAnnotation(inlineConstructor)) return irCall // This call does not need inlining. + + val functionDeclaration = getFunctionDeclaration(irCall) // Get declaration of the function to be inlined. + if (functionDeclaration == null) { // We failed to get the declaration. + val message = "Inliner failed to obtain function declaration: " + + functionDescriptor.fqNameSafe.toString() + context.reportWarning(message, currentFile, irCall) // Report warning. + return irCall + } + + val statements = (functionDeclaration.body as IrBlockBody).statements + replaceDelegatingConstructorCall(statements, functionDescriptor) + functionDeclaration.transformChildrenVoid(ValueSubstitutor()) + context.ir.originalModuleIndex.functions[functionDescriptor] = functionDeclaration + + return irCall + } + + //-------------------------------------------------------------------------// + + private fun getFunctionDeclaration(irCall: IrCall): IrFunction? { + + val functionDescriptor = irCall.descriptor + val originalDescriptor = functionDescriptor.resolveFakeOverride().original + val functionDeclaration = + context.ir.originalModuleIndex.functions[originalDescriptor] ?: // If function is declared in the current module. + deserializer.deserializeInlineBody(originalDescriptor) // Function is declared in another module. + return functionDeclaration as IrFunction? + } + + //-------------------------------------------------------------------------// + + private fun replaceDelegatingConstructorCall(statements: MutableList, functionDescriptor: FunctionDescriptor) { + + val delegatingCall = statements[0] + if (delegatingCall !is IrDelegatingConstructorCallImpl) return + + val thisVariable = generateIrCall(delegatingCall) + + val newThisGetValue = IrGetValueImpl( // Create new expression, representing access the new variable. + startOffset = 0, + endOffset = 0, + descriptor = thisVariable.descriptor + ) + + val classDescriptor = delegatingCall.descriptor.constructedClass + val oldThisGetValue = classDescriptor.thisAsReceiverParameter + substituteMap[oldThisGetValue] = newThisGetValue + + val newStatements = statements.toMutableList() + newStatements[0] = thisVariable + newStatements += newThisGetValue + + val block = IrBlockImpl( + startOffset = 0, + endOffset = 0, + type = newThisGetValue.type, + origin = null, + statements = newStatements + ) + + val returnThis = IrReturnImpl(0, 0, functionDescriptor, block) + + statements.clear() + statements += returnThis + } + + //-------------------------------------------------------------------------// + + fun generateIrCall(expression: IrDelegatingConstructorCallImpl): IrVariable { + + val newExpression = IrCallImpl( + expression.startOffset, + expression.endOffset, + expression.descriptor.returnType, + expression.descriptor, + expression.typeArguments, + expression.origin + ).apply { + expression.descriptor.valueParameters.forEach { + val valueArgument = expression.getValueArgument(it) + putValueArgument(it.index, valueArgument) + } + } + + val newVariable = currentScope!!.scope.createTemporaryVariable( // Create new variable and init it with constructor call. + irExpression = newExpression, + nameHint = newExpression.descriptor.fqNameSafe.toString() + ".this", + isMutable = false) + + return newVariable + } + + //-------------------------------------------------------------------------// + + override fun visitElement(element: IrElement) = element.accept(this, null) + + //-------------------------------------------------------------------------// + + private inner class ValueSubstitutor: IrElementTransformerVoid() { + + override fun visitGetValue(expression: IrGetValue): IrExpression { + val newExpression = super.visitGetValue(expression) as IrGetValue + val descriptor = newExpression.descriptor + val argument = substituteMap[descriptor] // Find expression to replace this parameter. + if (argument == null) return newExpression // If there is no such expression - do nothing. + return argument + } + + //---------------------------------------------------------------------// + + override fun visitElement(element: IrElement) = element.accept(this, null) + } +} + + + + + +