Optimized inliner: substitute leaking descriptors only once

This commit is contained in:
Igor Chevdar
2017-05-25 14:35:42 +03:00
parent a4ba0fbb32
commit 2dcfdebd5a
4 changed files with 50 additions and 50 deletions
@@ -23,14 +23,12 @@ import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlockImpl
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.* import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.util.DeepCopyIrTree import org.jetbrains.kotlin.ir.util.DeepCopyIrTree
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -41,7 +39,7 @@ import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.makeNullable import org.jetbrains.kotlin.types.typeUtil.makeNullable
internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: DeclarationDescriptor, internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
val context: Context) { val context: Context) {
private val descriptorSubstituteMap: MutableMap<DeclarationDescriptor, DeclarationDescriptor> = mutableMapOf() private val descriptorSubstituteMap: MutableMap<DeclarationDescriptor, DeclarationDescriptor> = mutableMapOf()
@@ -51,7 +49,6 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: DeclarationDe
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
fun copy(irElement: IrElement, typeSubstitutor: TypeSubstitutor?): IrElement { fun copy(irElement: IrElement, typeSubstitutor: TypeSubstitutor?): IrElement {
this.typeSubstitutor = typeSubstitutor this.typeSubstitutor = typeSubstitutor
irElement.acceptChildrenVoid(DescriptorCollector()) irElement.acceptChildrenVoid(DescriptorCollector())
return irElement.accept(InlineCopyIr(), null) return irElement.accept(InlineCopyIr(), null)
@@ -550,51 +547,51 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: DeclarationDe
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
val descriptorSubstitutorForExternalScope = object : IrElementTransformerVoid() { fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>) {
descriptorSubstituteMap.forEach { t, u ->
override fun visitFunction(declaration: IrFunction): IrStatement { globalSubstituteMap.put(t, SubstitutedDescriptor(targetDescriptor, u))
if (declaration.descriptor == targetDescriptor)
return declaration
return super.visitFunction(declaration)
} }
}
override fun visitCall(expression: IrCall): IrExpression { }
val oldExpression = super.visitCall(expression) as IrCall
return when (oldExpression) { internal class SubstitutedDescriptor(val inlinedFunction: FunctionDescriptor, val descriptor: DeclarationDescriptor)
is IrCallImpl -> copyIrCallImpl(oldExpression)
is IrCallWithShallowCopy -> copyIrCallWithShallowCopy(oldExpression) internal class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>)
else -> oldExpression : IrElementTransformerVoidWithContext() {
}
override fun visitCall(expression: IrCall): IrExpression {
val oldExpression = super.visitCall(expression) as IrCall
val substitutedDescriptor = globalSubstituteMap[expression.descriptor.original]
?: return oldExpression
if (allScopes.any { it.scope.scopeOwner == substitutedDescriptor.inlinedFunction })
return oldExpression
return when (oldExpression) {
is IrCallImpl -> copyIrCallImpl(oldExpression, substitutedDescriptor)
is IrCallWithShallowCopy -> copyIrCallWithShallowCopy(oldExpression, substitutedDescriptor)
else -> oldExpression
} }
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun copyIrCallImpl(oldExpression: IrCallImpl): IrCallImpl { private fun copyIrCallImpl(oldExpression: IrCallImpl, substitutedDescriptor: SubstitutedDescriptor): IrCallImpl {
val oldDescriptor = oldExpression.descriptor val oldDescriptor = oldExpression.descriptor
val newDescriptor = (descriptorSubstituteMap[oldDescriptor.original] ?: oldDescriptor) as FunctionDescriptor val newDescriptor = substitutedDescriptor.descriptor as FunctionDescriptor
val oldSuperQualifier = oldExpression.superQualifier if (newDescriptor == oldDescriptor)
val newSuperQualifier = oldSuperQualifier?.let { (descriptorSubstituteMap[it] ?: it) as ClassDescriptor }
val newType = substituteType(oldExpression.type)!!
val newTypeArguments = substituteTypeArguments(oldExpression.typeArguments)
if (newDescriptor == oldDescriptor && newSuperQualifier == oldSuperQualifier && newType == oldExpression.type
&& ((newTypeArguments == null && oldExpression.typeArguments == null)
|| (newTypeArguments!!.all { it.value == oldExpression.typeArguments!![it.key] })))
return oldExpression return oldExpression
val newExpression = IrCallImpl( val newExpression = IrCallImpl(
startOffset = oldExpression.startOffset, startOffset = oldExpression.startOffset,
endOffset = oldExpression.endOffset, endOffset = oldExpression.endOffset,
type = newType, type = oldExpression.type,
calleeDescriptor = newDescriptor, calleeDescriptor = newDescriptor,
typeArguments = newTypeArguments, typeArguments = oldExpression.typeArguments,
origin = oldExpression.origin, origin = oldExpression.origin,
superQualifierDescriptor = newSuperQualifier superQualifierDescriptor = oldExpression.superQualifier
).apply { ).apply {
oldExpression.descriptor.valueParameters.forEach { oldExpression.descriptor.valueParameters.forEach {
val valueArgument = oldExpression.getValueArgument(it) val valueArgument = oldExpression.getValueArgument(it)
@@ -609,19 +606,15 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: DeclarationDe
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun copyIrCallWithShallowCopy(oldExpression: IrCallWithShallowCopy): IrCall { private fun copyIrCallWithShallowCopy(oldExpression: IrCallWithShallowCopy, substitutedDescriptor: SubstitutedDescriptor): IrCall {
val oldDescriptor = oldExpression.descriptor val oldDescriptor = oldExpression.descriptor
val newDescriptor = (descriptorSubstituteMap[oldDescriptor.original] ?: oldDescriptor) as FunctionDescriptor val newDescriptor = substitutedDescriptor.descriptor as FunctionDescriptor
val oldSuperQualifier = oldExpression.superQualifier if (newDescriptor == oldDescriptor)
val newSuperQualifier = oldSuperQualifier?.let { (descriptorSubstituteMap[it] ?: it) as ClassDescriptor }
if (newDescriptor == oldDescriptor && newSuperQualifier == oldSuperQualifier)
return oldExpression return oldExpression
return oldExpression.shallowCopy(oldExpression.origin, newDescriptor, newSuperQualifier) return oldExpression.shallowCopy(oldExpression.origin, newDescriptor, oldExpression.superQualifier)
} }
} }
@@ -71,6 +71,7 @@ abstract internal class IrElementTransformerVoidWithContext : IrElementTransform
protected val currentProperty get() = scopeStack.lastOrNull { it.scope.scopeOwner is PropertyDescriptor } protected val currentProperty get() = scopeStack.lastOrNull { it.scope.scopeOwner is PropertyDescriptor }
protected val currentScope get() = scopeStack.peek() protected val currentScope get() = scopeStack.peek()
protected val parentScope get() = if (scopeStack.size < 2) null else scopeStack[scopeStack.size - 2] protected val parentScope get() = if (scopeStack.size < 2) null else scopeStack[scopeStack.size - 2]
protected val allScopes get() = scopeStack
fun printScopeStack() { fun printScopeStack() {
scopeStack.forEach { println(it.scope.scopeOwner) } scopeStack.forEach { println(it.scope.scopeOwner) }
@@ -25,12 +25,12 @@ import org.jetbrains.kotlin.backend.konan.descriptors.needsInlining
import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride
import org.jetbrains.kotlin.backend.konan.ir.DeserializerDriver import org.jetbrains.kotlin.backend.konan.ir.DeserializerDriver
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlockImpl import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlockImpl
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueDescriptor import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.getDefault import org.jetbrains.kotlin.ir.declarations.getDefault
@@ -50,10 +50,17 @@ import org.jetbrains.kotlin.types.TypeSubstitutor
internal class FunctionInlining(val context: Context): IrElementTransformerVoidWithContext() { internal class FunctionInlining(val context: Context): IrElementTransformerVoidWithContext() {
private val deserializer = DeserializerDriver(context) private val deserializer = DeserializerDriver(context)
private val globalSubstituteMap = mutableMapOf<DeclarationDescriptor, SubstitutedDescriptor>()
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
fun inline(irModule: IrModuleFragment) = irModule.accept(this, null) fun inline(irModule: IrModuleFragment): IrElement {
val transformedModule = irModule.accept(this, null)
transformedModule.transformChildrenVoid(
DescriptorSubstitutorForExternalScope(globalSubstituteMap) // Transform calls to object that might be returned from inline function call.
)
return transformedModule
}
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
@@ -72,7 +79,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
} }
functionDeclaration.transformChildrenVoid(this) // Process recursive inline. functionDeclaration.transformChildrenVoid(this) // Process recursive inline.
val inliner = Inliner(currentFile, functionDeclaration, currentScope!!, context) // Create inliner for this scope. val inliner = Inliner(globalSubstituteMap, functionDeclaration, currentScope!!, context) // Create inliner for this scope.
return inliner.inline(irCall ) // Return newly created IrInlineBody instead of IrCall. return inliner.inline(irCall ) // Return newly created IrInlineBody instead of IrCall.
} }
@@ -95,7 +102,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
//-----------------------------------------------------------------------------// //-----------------------------------------------------------------------------//
private class Inliner(val irFile: IrFile, private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>,
val functionDeclaration: IrFunction, // Function to substitute. val functionDeclaration: IrFunction, // Function to substitute.
val currentScope: ScopeWithIr, val currentScope: ScopeWithIr,
val context: Context) { val context: Context) {
@@ -107,8 +114,7 @@ private class Inliner(val irFile: IrFile,
fun inline(irCall: IrCall): IrReturnableBlockImpl { // Call to be substituted. fun inline(irCall: IrCall): IrReturnableBlockImpl { // Call to be substituted.
val inlineFunctionBody = inlineFunction(irCall, functionDeclaration) val inlineFunctionBody = inlineFunction(irCall, functionDeclaration)
val descriptorSubstitutor = copyIrElement.descriptorSubstitutorForExternalScope copyIrElement.addCurrentSubstituteMap(globalSubstituteMap)
irFile.transformChildrenVoid(descriptorSubstitutor) // Transform calls to object that might be returned from inline function call.
return inlineFunctionBody return inlineFunctionBody
} }
@@ -1166,7 +1166,7 @@ internal class IrDeserializer(val context: Context,
(key,value) -> (key,value) ->
key to value} key to value}
val copyFunctionDeclaration = DeepCopyIrTreeWithDescriptors(rootFunction.containingDeclaration, context).copy( val copyFunctionDeclaration = DeepCopyIrTreeWithDescriptors(rootFunction, context).copy(
irElement = declaration, irElement = declaration,
typeSubstitutor = TypeSubstitutor.create(substitutionContext) typeSubstitutor = TypeSubstitutor.create(substitutionContext)
) as IrFunction ) as IrFunction