Support for ClassDescriptor and FunctionDescriptor copy

This commit is contained in:
Konstantin Anisimov
2017-03-30 19:42:01 +07:00
committed by KonstantinAnisimov
parent 4572b27592
commit 14fb3b87b6
2 changed files with 419 additions and 49 deletions
@@ -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<DeclarationDescriptor, DeclarationDescriptor> = 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 <ValueParameterDescriptor>, owner: CallableDescriptor): List <ValueParameterDescriptor> {
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!!
)
}
}
}
@@ -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 <TypeParameterDescriptor, KotlinType>? {
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)