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 new file mode 100644 index 00000000000..9bfa4896620 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDescriptoros.kt @@ -0,0 +1,332 @@ +/* + * Copyright 2010-2016 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. + */ + +package org.jetbrains.kotlin.backend.common + +import org.jetbrains.kotlin.backend.konan.Context +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrConstructor +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl +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.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.name.Name + +internal class DeepCopyIrTreeWithDescriptors(val targetFunction: IrFunction, val context: Context) { + + private val descriptorSubstituteMap: MutableMap = mutableMapOf() + private var inlinedFunctionName = "" + private var nameIndex = 0 + + //-------------------------------------------------------------------------// + + fun copy(irElement: IrElement, functionName: String) { + inlinedFunctionName = functionName + descriptorSubstituteMap.clear() + irElement.acceptChildrenVoid(descriptorCollector) + irElement.transformChildrenVoid(descriptorSubstitutor) + } + + //-------------------------------------------------------------------------// + + private val descriptorCollector = object : IrElementVisitorVoid { + + override fun visitElement(element: IrElement) { + element.acceptChildren(this, null) + } + + //---------------------------------------------------------------------// + + override fun visitFunction(declaration: IrFunction) { + val oldDescriptor = declaration.descriptor + val newDescriptor = copyFunctionDescriptor(oldDescriptor) + descriptorSubstituteMap[oldDescriptor] = newDescriptor + super.visitFunction(declaration) + } + + //---------------------------------------------------------------------// + + override fun visitClass(declaration: IrClass) { + val oldDescriptor = declaration.descriptor + val newDescriptor = copyClassDescriptor(oldDescriptor) + descriptorSubstituteMap[oldDescriptor] = newDescriptor + super.visitClass(declaration) + + val constructors = oldDescriptor.constructors.map { + descriptorSubstituteMap[it] as ClassConstructorDescriptor + }.toSet() + val oldPrimaryConstructor = oldDescriptor.unsubstitutedPrimaryConstructor!! + val primaryConstructor = descriptorSubstituteMap[oldPrimaryConstructor] as ClassConstructorDescriptor + newDescriptor.initialize( + oldDescriptor.unsubstitutedMemberScope, + constructors, + primaryConstructor + ) + } + + //--- Copy descriptors ------------------------------------------------// + + private fun generateName(name: Name): Name { + val containingName = targetFunction.descriptor.name.toString() // Name of inline target (function we inline in) + val declarationName = name.toString() // Name of declaration + val indexStr = (nameIndex++).toString() // Unique for inline target index + return Name.identifier(containingName + "_" + inlinedFunctionName + "_" + declarationName + "_" + indexStr) + } + + //---------------------------------------------------------------------// + + private fun copyValueParameters(oldValueParameters: List , owner: CallableDescriptor): List { + return oldValueParameters.map { oldDescriptor -> + val newDescriptor = ValueParameterDescriptorImpl( + owner, + oldDescriptor.original, + oldDescriptor.index, + oldDescriptor.annotations, + oldDescriptor.name, + oldDescriptor.type, + oldDescriptor.declaresDefaultValue(), + oldDescriptor.isCrossinline, + oldDescriptor.isNoinline, + oldDescriptor.varargElementType, + oldDescriptor.source + ) + descriptorSubstituteMap[oldDescriptor] = newDescriptor + newDescriptor + } + } + + //---------------------------------------------------------------------// + + private fun copyFunctionDescriptor(oldDescriptor: FunctionDescriptor): FunctionDescriptor { + + return when (oldDescriptor) { + is SimpleFunctionDescriptor -> copySimpleFunctionDescriptor(oldDescriptor) + is ConstructorDescriptor -> copyConstructorDescriptor(oldDescriptor) + else -> TODO("Unsupported FunctionDescriptor subtype") + } + } + + //---------------------------------------------------------------------// + + private fun copySimpleFunctionDescriptor(oldDescriptor: SimpleFunctionDescriptor) : FunctionDescriptor { + + val memberOwner = targetFunction.descriptor + val newDescriptor = SimpleFunctionDescriptorImpl.create( + memberOwner, + oldDescriptor.annotations, + generateName(oldDescriptor.name), + CallableMemberDescriptor.Kind.SYNTHESIZED, + oldDescriptor.source + ).apply { isTailrec = oldDescriptor.isTailrec } + + val newDispatchReceiverParameter = null + val newTypeParameters = oldDescriptor.typeParameters + val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, memberOwner) + + newDescriptor.initialize( + oldDescriptor.extensionReceiverParameter?.type, + newDispatchReceiverParameter, + newTypeParameters, + newValueParameters, + oldDescriptor.returnType, + Modality.FINAL, + Visibilities.LOCAL + ) + return newDescriptor + } + + //---------------------------------------------------------------------// + + private fun copyConstructorDescriptor(oldDescriptor: ConstructorDescriptor) : FunctionDescriptor { + + val oldContainingDeclaration = oldDescriptor.containingDeclaration + val containingDeclaration = descriptorSubstituteMap[oldContainingDeclaration] + val newDescriptor = ClassConstructorDescriptorImpl.create( + containingDeclaration as ClassDescriptor, + oldDescriptor.annotations, + oldDescriptor.isPrimary, + oldDescriptor.source + ) + + val newTypeParameters = oldDescriptor.typeParameters + val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, newDescriptor) + newDescriptor.initialize( + oldDescriptor.dispatchReceiverParameter?.type, + null, // TODO @Nullable ReceiverParameterDescriptor dispatchReceiverParameter, + newTypeParameters, + newValueParameters, + oldDescriptor.returnType, + oldDescriptor.modality, + oldDescriptor.visibility + ) + return newDescriptor + } + + //---------------------------------------------------------------------// + + private fun copyClassDescriptor(oldDescriptor: ClassDescriptor): ClassDescriptorImpl { + + return ClassDescriptorImpl( + targetFunction.descriptor, + generateName(oldDescriptor.name), + oldDescriptor.modality, + oldDescriptor.kind, + listOf(context.builtIns.anyType), + oldDescriptor.source, + oldDescriptor.isExternal + ) + } + } + + //-------------------------------------------------------------------------// + + val descriptorSubstitutor = object : IrElementTransformerVoid() { + + override fun visitElement(element: IrElement): IrElement { + return super.visitElement(element) + } + + //---------------------------------------------------------------------// + + override fun visitClass(declaration: IrClass): IrStatement { + val oldDeclaration = super.visitClass(declaration) as IrClass + val newDescriptor = descriptorSubstituteMap[oldDeclaration.descriptor] + if (newDescriptor == null) return oldDeclaration + + val newDeclaration = IrClassImpl( + oldDeclaration.startOffset, + oldDeclaration.endOffset, + oldDeclaration.origin, + newDescriptor as ClassDescriptor, + oldDeclaration.declarations + ) + + return newDeclaration + } + + //---------------------------------------------------------------------// + + override fun visitFunction(declaration: IrFunction): IrStatement { + val oldDeclaration = super.visitFunction(declaration) as IrFunction + val newDescriptor = descriptorSubstituteMap[oldDeclaration.descriptor] + if (newDescriptor == null) return oldDeclaration + + return when (oldDeclaration) { + is IrFunctionImpl -> copyIrFunctionImpl(oldDeclaration, newDescriptor) + is IrConstructorImpl -> copyIrConstructorImpl(oldDeclaration, newDescriptor) + else -> TODO("Unsupported IrFunction subtype") + } + } + + //---------------------------------------------------------------------// + + override fun visitCall(expression: IrCall): IrExpression { + + val irCall = super.visitCall(expression) as IrCall + if (irCall !is IrCallImpl) return irCall + + val descriptor = descriptorSubstituteMap.getOrDefault(irCall.descriptor, irCall.descriptor) as FunctionDescriptor + return IrCallImpl(irCall.startOffset, irCall.endOffset, irCall.type, descriptor, + irCall.typeArguments, irCall.origin, irCall.superQualifier).apply { + irCall.descriptor.valueParameters.forEach { + val valueArgument = irCall.getValueArgument(it) + putValueArgument(it.index, valueArgument) + } + extensionReceiver = irCall.extensionReceiver + dispatchReceiver = irCall.dispatchReceiver + } + } + + //---------------------------------------------------------------------// + + override fun visitCallableReference(expression: IrCallableReference): IrExpression { + + val oldReference = super.visitCallableReference(expression) as IrCallableReference + val oldDescriptor = oldReference.descriptor + val newDescriptor = descriptorSubstituteMap[oldDescriptor] + if (newDescriptor == null) return oldReference + + val typeArguments = (oldReference as IrMemberAccessExpressionBase).typeArguments + val newReference = IrCallableReferenceImpl(expression.startOffset, + oldReference.endOffset, oldReference.type, newDescriptor as CallableDescriptor, + typeArguments, oldReference.origin) + + return newReference + } + + //---------------------------------------------------------------------// + + override fun visitReturn(expression: IrReturn): IrExpression { + + val oldReturn = super.visitReturn(expression) as IrReturn + val oldDescriptor = oldReturn.returnTarget + val newDescriptor = descriptorSubstituteMap[oldDescriptor] + if (newDescriptor == null) return oldReturn + + val newReturn = IrReturnImpl(oldReturn.startOffset, oldReturn.endOffset, + oldReturn.type, newDescriptor as CallableDescriptor, oldReturn.value) + + return newReturn + } + + //---------------------------------------------------------------------// + + override fun visitGetValue(expression: IrGetValue): IrExpression { + + val oldExpression = super.visitGetValue(expression) as IrGetValue + val oldDescriptor = oldExpression.descriptor + val newDescriptor = descriptorSubstituteMap[oldDescriptor] + if (newDescriptor == null) return oldExpression + + val newExpression = IrGetValueImpl( + oldExpression.startOffset, oldExpression.endOffset, + newDescriptor as ValueParameterDescriptor, oldExpression.origin + ) + return newExpression + } + + //--- Copy declarations -----------------------------------------------// + + private fun copyIrFunctionImpl(oldDeclaration: IrFunction, newDescriptor: DeclarationDescriptor): IrFunction { + return IrFunctionImpl( + oldDeclaration.startOffset, oldDeclaration.endOffset, oldDeclaration.origin, + newDescriptor as FunctionDescriptor, oldDeclaration.body + ) + } + + //---------------------------------------------------------------------// + + private fun copyIrConstructorImpl(oldDeclaration: IrConstructor, newDescriptor: DeclarationDescriptor): IrFunction { + return IrConstructorImpl( + oldDeclaration.startOffset, oldDeclaration.endOffset, oldDeclaration.origin, + newDescriptor as ClassConstructorDescriptor, oldDeclaration.body!! + ) + } + } +} \ No newline at end of file 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 65ea032faea..6f62e629be0 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 @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.backend.konan.lower +import org.jetbrains.kotlin.backend.common.DeepCopyIrTreeWithDescriptors import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke import org.jetbrains.kotlin.backend.konan.ir.DeserializerDriver @@ -31,19 +32,24 @@ import org.jetbrains.kotlin.ir.util.DeepCopyIrTree 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.types.* +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeProjectionImpl +import org.jetbrains.kotlin.types.TypeSubstitutor +import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.typeUtil.makeNullable //-----------------------------------------------------------------------------// internal class FunctionInlining(val context: Context): IrElementTransformerVoid() { - private var currentFile : IrFile? = null - private var currentFunction : IrFunction? = null - private var currentScope : Scope? = null + private var currentFile : IrFile? = null + private var currentFunction : IrFunction? = null + private var currentScope : Scope? = null + private var copyWithDescriptors: DeepCopyIrTreeWithDescriptors? = null + + private val deserializer = DeserializerDriver(context) //-------------------------------------------------------------------------// - private val deserializer = DeserializerDriver(context) fun inline(irModule: IrModuleFragment) = irModule.accept(this, null) @@ -68,8 +74,9 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( //-------------------------------------------------------------------------// override fun visitFunction(declaration: IrFunction): IrStatement { - currentFunction = declaration - currentScope = Scope(declaration.descriptor) + currentFunction = declaration + currentScope = Scope(declaration.descriptor) + copyWithDescriptors = DeepCopyIrTreeWithDescriptors(currentFunction!!, context) return super.visitFunction(declaration) } @@ -80,14 +87,12 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( val fqName = currentFile!!.packageFragmentDescriptor.fqName.asString() // TODO to be removed after stdlib compilation if(fqName.contains("kotlin")) return super.visitCall(expression) // TODO to be removed after stdlib compilation - val functionDescriptor = expression.descriptor as FunctionDescriptor - if (functionDescriptor.isInline) { - val inlineFunctionBody = inlineFunction(expression) - inlineFunctionBody.transformChildrenVoid(this) - return inlineFunctionBody // Return newly created IrInlineBody instead of IrCall. - } + val irCall = super.visitCall(expression) as IrCall - return super.visitCall(expression) + val functionDescriptor = irCall.descriptor as FunctionDescriptor + if (functionDescriptor.isInline) return inlineFunction(irCall) // Return newly created IrInlineBody instead of IrCall. + + return irCall } //---------------------------------------------------------------------// @@ -166,26 +171,48 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( } //-------------------------------------------------------------------------// - private fun inlineFunction(irCall: IrCall): IrExpression { + + private fun getFunctionDeclaration(irCall: IrCall): IrDeclaration? { + val functionDescriptor = irCall.descriptor as FunctionDescriptor val originalDescriptor = functionDescriptor.original - val functionDeclaration = - context.ir.originalModuleIndex.functions[originalDescriptor] ?: // Function is declared in the current module. - deserializer.deserializeInlineBody(originalDescriptor) // Function is declared in another module. - if (functionDeclaration == null) return super.visitCall(irCall) - val copyFuncDeclaration = functionDeclaration.accept(InlineCopyIr(), // Create copy of the function. - null) as IrFunction + val functionDeclaration = + (context.ir.originalModuleIndex.functions[originalDescriptor] ?: // Function is declared in the current module. + deserializer.deserializeInlineBody(originalDescriptor)) // Function is declared in another module. + return functionDeclaration + } - val startOffset = copyFuncDeclaration.startOffset - val endOffset = copyFuncDeclaration.endOffset - val returnType = copyFuncDeclaration.descriptor.returnType!! + //-------------------------------------------------------------------------// - if (copyFuncDeclaration.body == null) return irCall // TODO workaround - val blockBody = copyFuncDeclaration.body!! as IrBlockBody - val statements = blockBody.statements - val inlineBody = IrInlineFunctionBody(startOffset, endOffset, returnType, originalDescriptor, null, statements) + private fun createInlineFunctionBody(functionDeclaration: IrFunction): IrInlineFunctionBody? { - val parametersOld = getArguments(irCall, copyFuncDeclaration) // Create map call_site_argument -> inline_function_parameter. + val originBlockBody = functionDeclaration.body!! + if (originBlockBody == null) return null // TODO workaround + + val copyBlockBody = originBlockBody.accept(InlineCopyIr(), null) as IrBlockBody // Create copy of original function body. + val functionName = functionDeclaration.descriptor.name.toString() + copyWithDescriptors!!.copy(copyBlockBody, functionName) // TODO merge DeepCopyIrTreeWithDescriptors with InlineCopyIr + + val originalDescriptor = functionDeclaration.descriptor.original + val startOffset = functionDeclaration.startOffset + val endOffset = functionDeclaration.endOffset + val returnType = functionDeclaration.descriptor.returnType!! + + return IrInlineFunctionBody(startOffset, endOffset, returnType, originalDescriptor, null, copyBlockBody.statements) + } + + //-------------------------------------------------------------------------// + + private fun inlineFunction(irCall: IrCall): IrExpression { + + val irDeclaration = getFunctionDeclaration(irCall) + if (irDeclaration == null) return irCall + + val functionDeclaration = irDeclaration as IrFunction + val inlineBody = createInlineFunctionBody(functionDeclaration) + if (inlineBody == null) return irCall + + val parametersOld = getArguments(irCall, functionDeclaration) // Create map call_site_argument -> inline_function_parameter. val evaluatedParameters = evaluateParameters(parametersOld) val parameterToArgument = evaluatedParameters.parameters val evaluationStatements = evaluatedParameters.statements @@ -300,20 +327,21 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( //---------------------------------------------------------------------// - override fun visitCall(expression: IrCall): IrExpression { + private fun createTypeSubstitutor(): TypeSubstitutor { - val irCall = super.visitCall(expression) as IrCall - if (irCall !is IrCallImpl) return irCall + val substitutionContext = typeArgsMap!!.entries.associate { + (typeParameter, typeArgument) -> + typeParameter.typeConstructor to TypeProjectionImpl(typeArgument) + } + return TypeSubstitutor.create(substitutionContext) + } + + //---------------------------------------------------------------------// + + private fun substituteTypeArguments(irCall: IrCall, typeSubstitutor: TypeSubstitutor): Map ? { val oldTypeArguments = (irCall as IrMemberAccessExpressionBase).typeArguments - if (typeArgsMap == null) return irCall - if (oldTypeArguments == null) return irCall - - val substitutionContext = typeArgsMap.entries.associate { - (typeParameter, typeArgument) -> - typeParameter.typeConstructor to TypeProjectionImpl(typeArgument) - } - val typeSubstitutor = TypeSubstitutor.create(substitutionContext) + if (oldTypeArguments == null) return null val newTypeArguments = oldTypeArguments.map { val typeParameterDescriptor = it.key @@ -322,16 +350,24 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( typeParameterDescriptor to newTypeArgument }.toMap() - val descriptor = irCall.descriptor - val type = typeSubstitutor.substitute(irCall.type, Variance.INVARIANT) ?: irCall.type - val startOffset = irCall.startOffset - val endOffset = irCall.endOffset - val origin = irCall.origin - val superQualifier = irCall.superQualifier + return newTypeArguments + } - return IrCallImpl(startOffset, endOffset, type, descriptor, newTypeArguments, origin, superQualifier) - .apply { - descriptor.valueParameters.forEach { + //---------------------------------------------------------------------// + + override fun visitCall(expression: IrCall): IrExpression { + + val irCall = super.visitCall(expression) as IrCall + if (irCall !is IrCallImpl) return irCall + if (typeArgsMap == null) return irCall + + val typeSubstitutor = createTypeSubstitutor() + val typeArguments = substituteTypeArguments(irCall, typeSubstitutor) + val returnType = typeSubstitutor.substitute(irCall.type, Variance.INVARIANT) ?: irCall.type + + return IrCallImpl(irCall.startOffset, irCall.endOffset, returnType, irCall.descriptor, + typeArguments, irCall.origin, irCall.superQualifier).apply { + irCall.descriptor.valueParameters.forEach { val valueArgument = irCall.getValueArgument(it) putValueArgument(it.index, valueArgument) } @@ -425,6 +461,8 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( val copyLambdaFunction = lambdaFunction.accept(InlineCopyIr(), // Create copy of the function. null) as IrFunction + copyWithDescriptors!!.copy(copyLambdaFunction, "lambda") // TODO merge DeepCopyIrTreeWithDescriptors with InlineCopyIr + val lambdaStatements = (copyLambdaFunction.body as IrBlockBody).statements val lambdaReturnType = copyLambdaFunction.descriptor.returnType!! val inlineBody = IrInlineFunctionBody(0, 0, lambdaReturnType, lambdaFunction.descriptor, null, lambdaStatements)