From 0c6471b6cde6676dada500a5d9446f09f4182041 Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Fri, 2 Nov 2018 12:19:10 +0300 Subject: [PATCH] New copier for inliner --- .../lower/DeepCopyIrTreeWithDescriptors.kt | 215 +++++++++- .../backend/konan/lower/FunctionInlining.kt | 388 ++++++++++-------- .../konan/lower/InitializersLowering.kt | 10 +- .../konan/serialization/SerializeIr.kt | 7 +- 4 files changed, 432 insertions(+), 188 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt index fce13e0759e..d19f36cb8ce 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.IrElementVisitorVoidWithContext +import org.jetbrains.kotlin.backend.common.descriptors.* import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.descriptors.createExtensionReceiver @@ -19,37 +20,217 @@ import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* -import org.jetbrains.kotlin.ir.symbols.impl.createClassSymbolOrNull -import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol -import org.jetbrains.kotlin.ir.types.IrSimpleType -import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.makeNullable -import org.jetbrains.kotlin.ir.types.toKotlinType +import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.symbols.impl.* +import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl +import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.ir.visitors.acceptVoid -import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces import org.jetbrains.kotlin.storage.LockBasedStorageManager -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeSubstitutor -import org.jetbrains.kotlin.types.TypeUtils -import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.types.* + +internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context, + val typeArguments: Map?, + val parent: IrDeclarationParent?) : IrCopierForInliner { + + override fun copy(irElement: IrElement): IrElement { + // Create new symbols. + irElement.acceptVoid(symbolRemapper) + + // Make symbol remapper aware of the callsite's type arguments. + symbolRemapper.typeArguments = typeArguments + + // Copy IR. + val result = irElement.transform(copier, data = null) + + // Bind newly created IR with wrapped descriptors. + result.acceptVoid(object: IrElementVisitorVoid { + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + override fun visitClass(declaration: IrClass) { + (declaration.descriptor as WrappedClassDescriptor).bind(declaration) + declaration.acceptChildrenVoid(this) + } + + override fun visitConstructor(declaration: IrConstructor) { + (declaration.descriptor as WrappedClassConstructorDescriptor).bind(declaration) + declaration.acceptChildrenVoid(this) + } + + override fun visitEnumEntry(declaration: IrEnumEntry) { + (declaration.descriptor as WrappedClassDescriptor).bind( + declaration.correspondingClass ?: declaration.parentAsClass) + declaration.acceptChildrenVoid(this) + } + + override fun visitField(declaration: IrField) { + (declaration.descriptor as WrappedPropertyDescriptor).bind(declaration) + declaration.acceptChildrenVoid(this) + } + + override fun visitFunction(declaration: IrFunction) { + (declaration.descriptor as WrappedSimpleFunctionDescriptor).bind(declaration as IrSimpleFunction) + declaration.acceptChildrenVoid(this) + } + + override fun visitValueParameter(declaration: IrValueParameter) { + (declaration.descriptor as? WrappedValueParameterDescriptor)?.bind(declaration) + (declaration.descriptor as? WrappedReceiverParameterDescriptor)?.bind(declaration) + declaration.acceptChildrenVoid(this) + } + + override fun visitTypeParameter(declaration: IrTypeParameter) { + (declaration.descriptor as WrappedTypeParameterDescriptor).bind(declaration) + declaration.acceptChildrenVoid(this) + } + + override fun visitVariable(declaration: IrVariable) { + (declaration.descriptor as WrappedVariableDescriptor).bind(declaration) + declaration.acceptChildrenVoid(this) + } + }) + + result.patchDeclarationParents(parent) + return result + } + + private var nameIndex = 0 + + private fun generateCopyName(name: Name) = Name.identifier(name.toString() + "_" + (nameIndex++).toString()) + + private inner class InlinerSymbolRenamer : SymbolRenamer { + private val map = mutableMapOf() + + override fun getClassName(symbol: IrClassSymbol) = map.getOrPut(symbol) { generateCopyName(symbol.owner.name) } + override fun getFunctionName(symbol: IrSimpleFunctionSymbol) = map.getOrPut(symbol) { generateCopyName(symbol.owner.name) } + override fun getFieldName(symbol: IrFieldSymbol) = symbol.owner.name + override fun getFileName(symbol: IrFileSymbol) = symbol.owner.fqName + override fun getExternalPackageFragmentName(symbol: IrExternalPackageFragmentSymbol) = symbol.owner.fqName + override fun getEnumEntryName(symbol: IrEnumEntrySymbol) = symbol.owner.name + override fun getVariableName(symbol: IrVariableSymbol) = map.getOrPut(symbol) { generateCopyName(symbol.owner.name) } + override fun getTypeParameterName(symbol: IrTypeParameterSymbol) = symbol.owner.name + override fun getValueParameterName(symbol: IrValueParameterSymbol) = symbol.owner.name + } + + private inner class DescriptorsToIrRemapper : DescriptorsRemapper { + override fun remapDeclaredClass(descriptor: ClassDescriptor) = + WrappedClassDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredConstructor(descriptor: ClassConstructorDescriptor) = + WrappedClassConstructorDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredEnumEntry(descriptor: ClassDescriptor) = + WrappedClassDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredField(descriptor: PropertyDescriptor) = + WrappedPropertyDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredSimpleFunction(descriptor: FunctionDescriptor) = + WrappedSimpleFunctionDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredTypeParameter(descriptor: TypeParameterDescriptor) = + WrappedTypeParameterDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredVariable(descriptor: VariableDescriptor) = + WrappedVariableDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredValueParameter(descriptor: ParameterDescriptor): ParameterDescriptor = + if (descriptor is ReceiverParameterDescriptor) + WrappedReceiverParameterDescriptor(descriptor.annotations, descriptor.source) + else + WrappedValueParameterDescriptor(descriptor.annotations, descriptor.source) + } + + private inner class InlinerTypeRemapper(val symbolRemapper: SymbolRemapper, + val typeArguments: Map?) : TypeRemapper { + + override fun enterScope(irTypeParametersContainer: IrTypeParametersContainer) { } + + override fun leaveScope() { } + + private fun remapTypeArguments(arguments: List) = + arguments.map { argument -> + (argument as? IrTypeProjection)?.let { makeTypeProjection(remapType(it.type), it.variance) } + ?: argument + } + + override fun remapType(type: IrType): IrType { + if (type !is IrSimpleType) return type + + val substitutedType = typeArguments?.get(type.classifier) + if (substitutedType != null) { + substitutedType as IrSimpleType + return IrSimpleTypeImpl( + kotlinType = null, + classifier = substitutedType.classifier, + hasQuestionMark = type.hasQuestionMark or substitutedType.isMarkedNullable(), + arguments = substitutedType.arguments, + annotations = substitutedType.annotations + ) + } + + return IrSimpleTypeImpl( + kotlinType = null, + classifier = symbolRemapper.getReferencedClassifier(type.classifier), + hasQuestionMark = type.hasQuestionMark, + arguments = remapTypeArguments(type.arguments), + annotations = type.annotations.map { it.transform(copier, null) as IrCall } + ) + } + } + + override fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap) { } + + private class SymbolRemapperImpl(descriptorsRemapper: DescriptorsRemapper) + : DeepCopySymbolRemapper(descriptorsRemapper) { + + var typeArguments: Map? = null + set(value) { + if (field != null) return + field = value?.asSequence()?.associate { + (getReferencedClassifier(it.key) as IrTypeParameterSymbol) to it.value + } + } + + override fun getReferencedClassifier(symbol: IrClassifierSymbol): IrClassifierSymbol { + val result = super.getReferencedClassifier(symbol) + if (result !is IrTypeParameterSymbol) + return result + return typeArguments?.get(result)?.classifierOrNull ?: result + } + } + + private val symbolRemapper = SymbolRemapperImpl(DescriptorsToIrRemapper()) + private val copier = DeepCopyIrTreeWithSymbols( + symbolRemapper, + InlinerTypeRemapper(symbolRemapper, typeArguments), + InlinerSymbolRenamer() + ) +} + +internal interface IrCopierForInliner { + fun copy(irElement: IrElement): IrElement + fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap) +} internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor, val parentDescriptor: DeclarationDescriptor, - val context: Context) { + val context: Context, + val typeSubstitutor: TypeSubstitutor?) : IrCopierForInliner { private val descriptorSubstituteMap: MutableMap = mutableMapOf() - private var typeSubstitutor: TypeSubstitutor? = null private var nameIndex = 0 //-------------------------------------------------------------------------// - fun copy(irElement: IrElement, typeSubstitutor: TypeSubstitutor?): IrElement { - this.typeSubstitutor = typeSubstitutor + override fun copy(irElement: IrElement): IrElement { // Create all class descriptors and all necessary descriptors in order to create KotlinTypes. irElement.acceptVoid(DescriptorCollectorCreatePhase()) // Initialize all created descriptors possibly using previously created types. @@ -762,7 +943,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr //-------------------------------------------------------------------------// - fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap) { + override fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap) { descriptorSubstituteMap.forEach { t, u -> globalSubstituteMap[t] = SubstitutedDescriptor(targetDescriptor, u) } 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 91f26b6711f..3ece80d6d97 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 @@ -9,6 +9,7 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters +import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke @@ -16,26 +17,23 @@ import org.jetbrains.kotlin.backend.konan.descriptors.needsInlining import org.jetbrains.kotlin.backend.konan.descriptors.propertyIfAccessor import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride import org.jetbrains.kotlin.backend.konan.ir.DeserializerDriver +import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.declarations.IrModuleFragment -import org.jetbrains.kotlin.ir.declarations.IrValueParameter +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl -import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl -import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.util.getArguments -import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid -import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.inline.InlineUtil @@ -44,70 +42,154 @@ import org.jetbrains.kotlin.types.TypeProjection import org.jetbrains.kotlin.types.TypeProjectionImpl import org.jetbrains.kotlin.types.TypeSubstitutor -//-----------------------------------------------------------------------------// +abstract class IrElementTransformerWithContext : IrElementTransformer { -internal class FunctionInlining(val context: Context): IrElementTransformerVoidWithContext() { + private val scopeStack = mutableListOf() + + final override fun visitFile(declaration: IrFile, data: D): IrFile { + scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration)) + val result = visitFileNew(declaration, data) + scopeStack.pop() + return result + } + + final override fun visitClass(declaration: IrClass, data: D): IrStatement { + scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration)) + val result = visitClassNew(declaration, data) + scopeStack.pop() + return result + } + + final override fun visitProperty(declaration: IrProperty, data: D): IrStatement { + scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration)) + val result = visitPropertyNew(declaration, data) + scopeStack.pop() + return result + } + + final override fun visitField(declaration: IrField, data: D): IrStatement { + scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration)) + val result = visitFieldNew(declaration, data) + scopeStack.pop() + return result + } + + final override fun visitFunction(declaration: IrFunction, data: D): IrStatement { + scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration)) + val result = visitFunctionNew(declaration, data) + scopeStack.pop() + return result + } + + protected val currentFile get() = scopeStack.lastOrNull { it.irElement is IrFile }!!.irElement as IrFile + protected val currentClass get() = scopeStack.lastOrNull { it.scope.scopeOwner is ClassDescriptor } + protected val currentFunction get() = scopeStack.lastOrNull { it.scope.scopeOwner is FunctionDescriptor } + protected val currentProperty get() = scopeStack.lastOrNull { it.scope.scopeOwner is PropertyDescriptor } + protected val currentScope get() = scopeStack.peek() + protected val parentScope get() = if (scopeStack.size < 2) null else scopeStack[scopeStack.size - 2] + protected val allScopes get() = scopeStack + + fun printScopeStack() { + scopeStack.forEach { println(it.scope.scopeOwner) } + } + + open fun visitFileNew(declaration: IrFile, data: D): IrFile { + return super.visitFile(declaration, data) + } + + open fun visitClassNew(declaration: IrClass, data: D): IrStatement { + return super.visitClass(declaration, data) + } + + open fun visitFunctionNew(declaration: IrFunction, data: D): IrStatement { + return super.visitFunction(declaration, data) + } + + open fun visitPropertyNew(declaration: IrProperty, data: D): IrStatement { + return super.visitProperty(declaration, data) + } + + open fun visitFieldNew(declaration: IrField, data: D): IrStatement { + return super.visitField(declaration, data) + } +} + +internal class Ref(var value: T) + +internal class FunctionInlining(val context: Context): IrElementTransformerWithContext>() { private val deserializer = DeserializerDriver(context) private val globalSubstituteMap = mutableMapOf() + private val inlineFunctions = mutableMapOf() //-------------------------------------------------------------------------// fun inline(irModule: IrModuleFragment): IrElement { - val transformedModule = irModule.accept(this, null) + val transformedModule = irModule.accept(this, Ref(false)) DescriptorSubstitutorForExternalScope(globalSubstituteMap, context).run(transformedModule) // Transform calls to object that might be returned from inline function call. return transformedModule } - //-------------------------------------------------------------------------// + override fun visitFunctionNew(declaration: IrFunction, data: Ref): IrStatement { + val descriptor = declaration.descriptor - override fun visitCall(expression: IrCall): IrExpression { + val localData = Ref(inlineFunctions[descriptor] ?: false) + val result = super.visitFunctionNew(declaration, localData) + data.value = data.value or localData.value - val irCall = super.visitCall(expression) as IrCall - val functionDescriptor = irCall.descriptor - if (!functionDescriptor.needsInlining || functionDescriptor == context.ir.symbols.isInitializedGetterDescriptor) { - return irCall // This call does not need inlining. - } + if (descriptor.needsInlining) + inlineFunctions[descriptor] = localData.value + return result + } - val functionDeclaration = getFunctionDeclaration(functionDescriptor) // Get declaration of the function to be inlined. - if (functionDeclaration == null) { // We failed to get the declaration. + override fun visitCall(expression: IrCall, data: Ref): IrExpression { + + val argsAreBad = Ref(false) + val callSite = super.visitCall(expression, argsAreBad) as IrCall + data.value = data.value or argsAreBad.value + if (!callSite.descriptor.needsInlining) + return callSite + val functionDescriptor = callSite.descriptor.resolveFakeOverride().original + if (functionDescriptor == context.ir.symbols.isInitializedGetterDescriptor) + return callSite + + val callee = getFunctionDeclaration(functionDescriptor) + if (callee == null) { val message = "Inliner failed to obtain function declaration: " + functionDescriptor.fqNameSafe.toString() - context.reportWarning(message, currentFile, irCall) // Report warning. - return irCall + context.reportWarning(message, currentFile, callSite) + return callSite } + data.value = data.value or callee.second - functionDeclaration.transformChildrenVoid(this) // Process recursive inline. - val inliner = Inliner(globalSubstituteMap, functionDeclaration, currentScope!!, context, this) // Create inliner for this scope. - return inliner.inline(irCall) // Return newly created IrInlineBody instead of IrCall. + val childIsBad = Ref(inlineFunctions[functionDescriptor] ?: false) + callee.first.transformChildren(this, childIsBad) // Process recursive inline. + inlineFunctions[functionDescriptor] = childIsBad.value + data.value = data.value or childIsBad.value + + val currentCalleeIsBad = argsAreBad.value or childIsBad.value or callee.second + val inliner = Inliner(globalSubstituteMap, callSite, callee.first, !currentCalleeIsBad, currentScope!!, + allScopes.map { it.irElement }.filterIsInstance().lastOrNull(), context, this) + return inliner.inline() } //-------------------------------------------------------------------------// - private fun getFunctionDeclaration(descriptor: FunctionDescriptor): IrFunction? = - descriptor.resolveFakeOverride().original.let { - when { - it.isBuiltInIntercepted(context.config.configuration.languageVersionSettings) -> - error("Continuation.intercepted is not available with release coroutines") + private fun getFunctionDeclaration(descriptor: FunctionDescriptor): Pair? = + when { + descriptor.isBuiltInIntercepted(context.config.configuration.languageVersionSettings) -> + error("Continuation.intercepted is not available with release coroutines") - it.isBuiltInSuspendCoroutineUninterceptedOrReturn(context.config.configuration.languageVersionSettings) -> - getFunctionDeclaration(context.ir.symbols.konanSuspendCoroutineUninterceptedOrReturn.descriptor) + descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(context.config.configuration.languageVersionSettings) -> + getFunctionDeclaration(context.ir.symbols.konanSuspendCoroutineUninterceptedOrReturn.descriptor) - it == context.ir.symbols.coroutineContextGetter -> - getFunctionDeclaration(context.ir.symbols.konanCoroutineContextGetter.descriptor) + descriptor == context.ir.symbols.coroutineContextGetter -> + getFunctionDeclaration(context.ir.symbols.konanCoroutineContextGetter.descriptor) - else -> { - val functionDeclaration = - context.ir.originalModuleIndex.functions[it] ?: // If function is declared in the current module. - deserializer.deserializeInlineBody(it) // Function is declared in another module. - functionDeclaration as IrFunction? - } - } + else -> + context.ir.originalModuleIndex.functions[descriptor]?.let { it to false } + ?: deserializer.deserializeInlineBody(descriptor)?.let { it as IrFunction to true } } - - //-------------------------------------------------------------------------// - - override fun visitElement(element: IrElement) = element.accept(this, null) } private val inlineConstructor = FqName("kotlin.native.internal.InlineConstructor") @@ -116,22 +198,34 @@ private val FunctionDescriptor.isInlineConstructor get() = annotations.hasAnnota //-----------------------------------------------------------------------------// private class Inliner(val globalSubstituteMap: MutableMap, - val functionDeclaration: IrFunction, // Function to substitute. + val callSite: IrCall, + val callee: IrFunction, + val local: Boolean, val currentScope: ScopeWithIr, + val parent: IrDeclarationParent?, val context: Context, val owner: FunctionInlining /*TODO: make inner*/) { - val copyIrElement = DeepCopyIrTreeWithDescriptors(functionDeclaration.descriptor, currentScope.scope.scopeOwner, context) // Create DeepCopy for current scope. + val copyIrElement = + if (!local) + DeepCopyIrTreeWithDescriptors(callee.descriptor, currentScope.scope.scopeOwner, + context, createTypeSubstitutor(callSite)) + else { + val typeParameters = + if (callee is IrConstructor) + callee.parentAsClass.typeParameters + else callee.typeParameters + val typeArguments = + (0 until callSite.typeArgumentsCount).map { + typeParameters[it].symbol to callSite.getTypeArgument(it) + }.associate { it } + DeepCopyIrTreeWithSymbolsForInliner(context, typeArguments, parent) + } + val substituteMap = mutableMapOf() - //-------------------------------------------------------------------------// + fun inline() = inlineFunction(callSite, callee) - fun inline(irCall: IrCall): IrReturnableBlockImpl { // Call to be substituted. - val inlineFunctionBody = inlineFunction(irCall, functionDeclaration) - return inlineFunctionBody - } - - //-------------------------------------------------------------------------// /** * TODO: JVM inliner crashed on attempt inline this function from transform.kt with: * j.l.IllegalStateException: Couldn't obtain compiled function body for @@ -143,29 +237,23 @@ private class Inliner(val globalSubstituteMap: MutableMap putValueArgument((it as ValueParameterDescriptor).index, argument) } } - assert(unboundIndex == valueParameters.size, { "Not all arguments of are used" }) + assert(unboundIndex == valueParameters.size) { "Not all arguments of are used" } } - return owner.visitCall(super.visitCall(immediateCall) as IrCall) + return owner.visitCall(super.visitCall(immediateCall) as IrCall, Ref(false)) } if (functionArgument !is IrBlock) return super.visitCall(expression) - val functionDeclaration = getLambdaFunction(functionArgument) + val functionDeclaration = functionArgument.statements[0] as IrFunction val newExpression = inlineFunction(expression, functionDeclaration) // Inline the lambda. Lambda parameters will be substituted with lambda arguments. return newExpression.transform(this, null) // Substitute lambda arguments with target function arguments. } @@ -284,22 +375,7 @@ private class Inliner(val globalSubstituteMap: MutableMap { + private fun buildParameterToArgument(callSite: IrCall, callee: IrFunction): List { - val parameterToArgument = mutableListOf() // Result list. + val parameterToArgument = mutableListOf() - if (irCall.dispatchReceiver != null && // Only if there are non null dispatch receivers both - irFunction.dispatchReceiverParameter != null) // on call site and in function declaration. + if (callSite.dispatchReceiver != null && // Only if there are non null dispatch receivers both + callee.dispatchReceiverParameter != null) // on call site and in function declaration. parameterToArgument += ParameterToArgument( - parameter = irFunction.dispatchReceiverParameter!!, - argumentExpression = irCall.dispatchReceiver!! + parameter = callee.dispatchReceiverParameter!!, + argumentExpression = callSite.dispatchReceiver!! ) val valueArguments = - irCall.descriptor.valueParameters.map { irCall.getValueArgument(it) }.toMutableList() + callSite.descriptor.valueParameters.map { callSite.getValueArgument(it) }.toMutableList() - if (irFunction.extensionReceiverParameter != null) { + if (callee.extensionReceiverParameter != null) { parameterToArgument += ParameterToArgument( - parameter = irFunction.extensionReceiverParameter!!, - argumentExpression = if (irCall.extensionReceiver != null) { - irCall.extensionReceiver!! + parameter = callee.extensionReceiverParameter!!, + argumentExpression = if (callSite.extensionReceiver != null) { + callSite.extensionReceiver!! } else { // Special case: lambda with receiver is called as usual lambda: valueArguments.removeAt(0)!! } ) - } else if (irCall.extensionReceiver != null) { + } else if (callSite.extensionReceiver != null) { // Special case: usual lambda is called as lambda with receiver: - valueArguments.add(0, irCall.extensionReceiver!!) + valueArguments.add(0, callSite.extensionReceiver!!) } val parametersWithDefaultToArgument = mutableListOf() - irFunction.valueParameters.forEach { parameter -> // Iterate value parameters. - val argument = valueArguments[parameter.index] // Get appropriate argument from call site. + for (parameter in callee.valueParameters) { + val argument = valueArguments[parameter.index] when { - argument != null -> { // Argument is good enough. - parameterToArgument += ParameterToArgument( // Associate current parameter with the argument. - parameter = parameter, - argumentExpression = argument + argument != null -> { + parameterToArgument += ParameterToArgument( + parameter = parameter, + argumentExpression = argument ) } @@ -390,43 +464,41 @@ private class Inliner(val globalSubstituteMap: MutableMap { // There is no argument - try default value. parametersWithDefaultToArgument += ParameterToArgument( - parameter = parameter, - argumentExpression = parameter.defaultValue!!.expression + parameter = parameter, + argumentExpression = parameter.defaultValue!!.expression ) } parameter.varargElementType != null -> { val emptyArray = IrVarargImpl( - startOffset = irCall.startOffset, - endOffset = irCall.endOffset, - type = parameter.type, - varargElementType = parameter.varargElementType!! + startOffset = callSite.startOffset, + endOffset = callSite.endOffset, + type = parameter.type, + varargElementType = parameter.varargElementType!! ) parameterToArgument += ParameterToArgument( - parameter = parameter, - argumentExpression = emptyArray + parameter = parameter, + argumentExpression = emptyArray ) } else -> { - val message = "Incomplete expression: call to ${irFunction.descriptor} " + - "has no argument at index ${parameter.index}" + val message = "Incomplete expression: call to ${callee.descriptor} " + + "has no argument at index ${parameter.index}" throw Error(message) } } } - return parameterToArgument + parametersWithDefaultToArgument // All arguments except default are evaluated at callsite, - // but default arguments are evaluated inside callee. + return parameterToArgument + parametersWithDefaultToArgument // All arguments except default are evaluated at callsite, + // but default arguments are evaluated inside callee. } //-------------------------------------------------------------------------// - private fun evaluateArguments(irCall : IrCall, // Call site. - functionDeclaration: IrFunction // Function to be called. - ): List { + private fun evaluateArguments(callSite: IrCall, callee: IrFunction): List { - val parameterToArgumentOld = buildParameterToArgument(irCall, functionDeclaration) // Create map parameter_descriptor -> original_argument_expression. - val evaluationStatements = mutableListOf() // List of evaluation statements. + val parameterToArgumentOld = buildParameterToArgument(callSite, callee) + val evaluationStatements = mutableListOf() val substitutor = ParameterSubstitutor() parameterToArgumentOld.forEach { val parameterDescriptor = it.parameter.descriptor @@ -446,26 +518,20 @@ private class Inliner(val globalSubstituteMap: MutableMap null } } + declaration.parent = irClass return declaration } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/SerializeIr.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/SerializeIr.kt index 6ab74d5b8fa..5aaabd146ba 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/SerializeIr.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/SerializeIr.kt @@ -1309,10 +1309,9 @@ internal class IrDeserializer(val context: Context, (key,value) -> key to value} - return DeepCopyIrTreeWithDescriptors(rootFunction, rootFunction.parents.first(), context).copy( - irElement = declaration, - typeSubstitutor = TypeSubstitutor.create(substitutionContext) - ) as IrFunction + return DeepCopyIrTreeWithDescriptors(rootFunction, rootFunction.parents.first(), context, + TypeSubstitutor.create(substitutionContext) + ).copy(declaration) as IrFunction } private val extractInlineProto: KonanProtoBuf.InlineIrBody