Move inline constructor transformation to separate compilation pass
This commit is contained in:
committed by
KonstantinAnisimov
parent
daa302e233
commit
de5ff23a2b
+4
@@ -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)
|
||||
|
||||
+1
@@ -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"),
|
||||
|
||||
+5
-73
@@ -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<ValueDescriptor, IrExpression>()
|
||||
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<IrStatement>, irCall: IrCall): List<IrStatement> {
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+178
@@ -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<ValueDescriptor, IrExpression>()
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
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<IrStatement>, 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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user