From c3b7d5a8c920c859f8d53bfaa4e7a3210be56911 Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Fri, 19 May 2017 16:24:05 +0300 Subject: [PATCH] Inliner: fixed bug with leaking descriptors An inline function might return an object, internal of which are leaked to the outside, we need to substitute those descriptors as well --- .../common/DeepCopyIrTreeWithDescriptoros.kt | 61 ++++++++++++++----- .../backend/konan/lower/FunctionInlining.kt | 22 ++++--- 2 files changed, 58 insertions(+), 25 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDescriptoros.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDescriptoros.kt index 26043857592..f01e998e957 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDescriptoros.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDescriptoros.kt @@ -23,13 +23,12 @@ import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlockImpl import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.* import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl +import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.util.DeepCopyIrTree import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid @@ -555,12 +554,20 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: DeclarationDe val descriptorSubstitutorForExternalScope = object : IrElementTransformerVoid() { + override fun visitFunction(declaration: IrFunction): IrStatement { + if (declaration.descriptor == targetDescriptor) + return declaration + return super.visitFunction(declaration) + } + override fun visitCall(expression: IrCall): IrExpression { val oldExpression = super.visitCall(expression) as IrCall - if (oldExpression is IrCallImpl) - return copyIrCallImpl(oldExpression) - return oldExpression + return when (oldExpression) { + is IrCallImpl -> copyIrCallImpl(oldExpression) + is IrCallWithShallowCopy -> copyIrCallWithShallowCopy(oldExpression) + else -> oldExpression + } } } @@ -569,18 +576,26 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: DeclarationDe private fun copyIrCallImpl(oldExpression: IrCallImpl): IrCallImpl { val oldDescriptor = oldExpression.descriptor - val newDescriptor = descriptorSubstituteMap.getOrDefault(oldDescriptor.original, - oldDescriptor) as FunctionDescriptor + val newDescriptor = (descriptorSubstituteMap[oldDescriptor.original] ?: oldDescriptor) as FunctionDescriptor - val newSuperQualifier = oldExpression.superQualifier?.let { (descriptorSubstituteMap[it] ?: it) as ClassDescriptor } + val oldSuperQualifier = oldExpression.superQualifier + 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 val newExpression = IrCallImpl( - startOffset = oldExpression.startOffset, - endOffset = oldExpression.endOffset, - type = substituteType(oldExpression.type)!!, - calleeDescriptor = newDescriptor, - typeArguments = substituteTypeArguments(oldExpression.typeArguments), - origin = oldExpression.origin, + startOffset = oldExpression.startOffset, + endOffset = oldExpression.endOffset, + type = newType, + calleeDescriptor = newDescriptor, + typeArguments = newTypeArguments, + origin = oldExpression.origin, superQualifierDescriptor = newSuperQualifier ).apply { oldExpression.descriptor.valueParameters.forEach { @@ -593,6 +608,22 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: DeclarationDe return newExpression } + + //-------------------------------------------------------------------------// + + private fun copyIrCallWithShallowCopy(oldExpression: IrCallWithShallowCopy): IrCall { + + val oldDescriptor = oldExpression.descriptor + val newDescriptor = (descriptorSubstituteMap[oldDescriptor.original] ?: oldDescriptor) as FunctionDescriptor + + val oldSuperQualifier = oldExpression.superQualifier + val newSuperQualifier = oldSuperQualifier?.let { (descriptorSubstituteMap[it] ?: it) as ClassDescriptor } + + if (newDescriptor == oldDescriptor && newSuperQualifier == oldSuperQualifier) + return oldExpression + + return oldExpression.shallowCopy(oldExpression.origin, newDescriptor, newSuperQualifier) + } } 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 ed9ce54cb3d..52ad25fd5f8 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 @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.descriptors.ValueDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.ir.IrElement 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.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.getDefault @@ -59,7 +60,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW override fun visitCall(expression: IrCall): IrExpression { val irCall = super.visitCall(expression) as IrCall - val functionDescriptor = irCall.descriptor as FunctionDescriptor + val functionDescriptor = irCall.descriptor if (!functionDescriptor.needsInlining) return irCall // This call does not need inlining. val functionDeclaration = getFunctionDeclaration(irCall) // Get declaration of the function to be inlined. @@ -71,15 +72,15 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW } functionDeclaration.transformChildrenVoid(this) // Process recursive inline. - val inliner = Inliner(currentScope!!, context) // Create inliner for this scope. - return inliner.inline(irCall, functionDeclaration) // Return newly created IrInlineBody instead of IrCall. + val inliner = Inliner(currentFile, functionDeclaration, currentScope!!, context) // Create inliner for this scope. + return inliner.inline(irCall ) // Return newly created IrInlineBody instead of IrCall. } //-------------------------------------------------------------------------// private fun getFunctionDeclaration(irCall: IrCall): IrFunction? { - val functionDescriptor = irCall.descriptor as FunctionDescriptor + val functionDescriptor = irCall.descriptor val originalDescriptor = functionDescriptor.resolveFakeOverride().original val functionDeclaration = context.ir.originalModuleIndex.functions[originalDescriptor] ?: // If function is declared in the current module. @@ -94,19 +95,20 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW //-----------------------------------------------------------------------------// -private class Inliner(val currentScope: ScopeWithIr, val context: Context) { +private class Inliner(val irFile: IrFile, + val functionDeclaration: IrFunction, // Function to substitute. + val currentScope: ScopeWithIr, + val context: Context) { - val copyIrElement = DeepCopyIrTreeWithDescriptors(currentScope.scope.scopeOwner, context) // Create DeepCopy for current scope. + val copyIrElement = DeepCopyIrTreeWithDescriptors(functionDeclaration.descriptor, context) // Create DeepCopy for current scope. val substituteMap = mutableMapOf() //-------------------------------------------------------------------------// - fun inline(irCall : IrCall, // Call to be substituted. - functionDeclaration: IrFunction): IrReturnableBlockImpl { // Function to substitute. - + fun inline(irCall: IrCall): IrReturnableBlockImpl { // Call to be substituted. 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. + irFile.transformChildrenVoid(descriptorSubstitutor) // Transform calls to object that might be returned from inline function call. return inlineFunctionBody }