Inliner: removed old copier + refactor

This commit is contained in:
Igor Chevdar
2019-01-28 18:11:49 +03:00
parent d9263e0fc2
commit fbd49a94e1
2 changed files with 325 additions and 1285 deletions
@@ -5,24 +5,13 @@
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
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
import org.jetbrains.kotlin.backend.konan.descriptors.initialize
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
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.expressions.IrCall
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.createClassSymbolOrNull
import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
@@ -30,22 +19,13 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
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
internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
val typeArguments: Map<IrTypeParameterSymbol, IrType?>?,
val parent: IrDeclarationParent?) : IrCopierForInliner {
val parent: IrDeclarationParent?) {
override fun copy(irElement: IrElement): IrElement {
fun copy(irElement: IrElement): IrElement {
// Create new symbols.
irElement.acceptVoid(symbolRemapper)
@@ -196,8 +176,6 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
}
}
override fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>) { }
private class SymbolRemapperImpl(descriptorsRemapper: DescriptorsRemapper)
: DeepCopySymbolRemapper(descriptorsRemapper) {
@@ -223,804 +201,4 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
InlinerTypeRemapper(symbolRemapper, typeArguments),
InlinerSymbolRenamer()
)
}
internal interface IrCopierForInliner {
fun copy(irElement: IrElement): IrElement
fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>)
}
internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
val parentDescriptor: DeclarationDescriptor,
val context: Context,
val typeSubstitutor: TypeSubstitutor?) : IrCopierForInliner {
private val descriptorSubstituteMap: MutableMap<DeclarationDescriptor, DeclarationDescriptor> = mutableMapOf()
private var nameIndex = 0
//-------------------------------------------------------------------------//
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.
irElement.acceptVoid(DescriptorCollectorInitPhase())
return irElement.accept(InlineCopyIr(), null)
}
inner class DescriptorCollectorCreatePhase : IrElementVisitorVoidWithContext() {
override fun visitElement(element: IrElement) {
element.acceptChildren(this, null)
}
//---------------------------------------------------------------------//
override fun visitClassNew(declaration: IrClass) {
val oldDescriptor = declaration.descriptor
val newDescriptor = copyClassDescriptor(oldDescriptor)
descriptorSubstituteMap[oldDescriptor] = newDescriptor
descriptorSubstituteMap[oldDescriptor.thisAsReceiverParameter] = newDescriptor.thisAsReceiverParameter
super.visitClassNew(declaration)
val constructors = oldDescriptor.constructors.map { oldConstructorDescriptor ->
descriptorSubstituteMap[oldConstructorDescriptor] as ClassConstructorDescriptor
}.toSet()
val oldPrimaryConstructor = oldDescriptor.unsubstitutedPrimaryConstructor
val primaryConstructor = oldPrimaryConstructor?.let { descriptorSubstituteMap[it] as ClassConstructorDescriptor }
val contributedDescriptors = oldDescriptor.unsubstitutedMemberScope
.getContributedDescriptors()
.map { descriptorSubstituteMap[it]!! }
newDescriptor.initialize(
SimpleMemberScope(contributedDescriptors),
constructors,
primaryConstructor
)
}
//---------------------------------------------------------------------//
override fun visitPropertyNew(declaration: IrProperty) {
copyPropertyOrField(declaration.descriptor)
super.visitPropertyNew(declaration)
}
//---------------------------------------------------------------------//
override fun visitFieldNew(declaration: IrField) {
val oldDescriptor = declaration.descriptor
if (descriptorSubstituteMap[oldDescriptor] == null) {
copyPropertyOrField(oldDescriptor) // A field without a property or a field of a delegated property.
}
super.visitFieldNew(declaration)
}
//---------------------------------------------------------------------//
override fun visitFunctionNew(declaration: IrFunction) {
val oldDescriptor = declaration.descriptor
if (oldDescriptor !is PropertyAccessorDescriptor) { // Property accessors are copied along with their property.
val oldContainingDeclaration =
if (oldDescriptor.visibility == Visibilities.LOCAL)
parentDescriptor
else
oldDescriptor.containingDeclaration
descriptorSubstituteMap[oldDescriptor] = copyFunctionDescriptor(oldDescriptor, oldContainingDeclaration)
}
super.visitFunctionNew(declaration)
}
//--- Copy descriptors ------------------------------------------------//
private fun generateCopyName(name: Name): Name {
val declarationName = name.toString() // Name of declaration
val indexStr = (nameIndex++).toString() // Unique for inline target index
return Name.identifier(declarationName + "_" + indexStr)
}
//---------------------------------------------------------------------//
private fun copyFunctionDescriptor(oldDescriptor: CallableDescriptor, oldContainingDeclaration: DeclarationDescriptor) =
when (oldDescriptor) {
is ConstructorDescriptor -> copyConstructorDescriptor(oldDescriptor)
is SimpleFunctionDescriptor -> copySimpleFunctionDescriptor(oldDescriptor, oldContainingDeclaration)
else -> TODO("Unsupported FunctionDescriptor subtype: $oldDescriptor")
}
//---------------------------------------------------------------------//
private fun copySimpleFunctionDescriptor(oldDescriptor: SimpleFunctionDescriptor, oldContainingDeclaration: DeclarationDescriptor) : FunctionDescriptor {
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
return SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ newContainingDeclaration,
/* annotations = */ oldDescriptor.annotations,
/* name = */ generateCopyName(oldDescriptor.name),
/* kind = */ oldDescriptor.kind,
/* source = */ oldDescriptor.source
)
}
//---------------------------------------------------------------------//
private fun copyConstructorDescriptor(oldDescriptor: ConstructorDescriptor) : FunctionDescriptor {
val oldContainingDeclaration = oldDescriptor.containingDeclaration
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
return ClassConstructorDescriptorImpl.create(
/* containingDeclaration = */ newContainingDeclaration as ClassDescriptor,
/* annotations = */ oldDescriptor.annotations,
/* isPrimary = */ oldDescriptor.isPrimary,
/* source = */ oldDescriptor.source
)
}
//---------------------------------------------------------------------//
private fun copyPropertyOrField(oldDescriptor: PropertyDescriptor) {
val oldContainingDeclaration = oldDescriptor.containingDeclaration
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) as ClassDescriptor
@Suppress("DEPRECATION")
val newDescriptor = PropertyDescriptorImpl.create(
/* containingDeclaration = */ newContainingDeclaration,
/* annotations = */ oldDescriptor.annotations,
/* modality = */ oldDescriptor.modality,
/* visibility = */ oldDescriptor.visibility,
/* isVar = */ oldDescriptor.isVar,
/* name = */ oldDescriptor.name,
/* kind = */ oldDescriptor.kind,
/* source = */ oldDescriptor.source,
/* lateInit = */ oldDescriptor.isLateInit,
/* isConst = */ oldDescriptor.isConst,
/* isExpect = */ oldDescriptor.isExpect,
/* isActual = */ oldDescriptor.isActual,
/* isExternal = */ oldDescriptor.isExternal,
/* isDelegated = */ oldDescriptor.isDelegated
)
descriptorSubstituteMap[oldDescriptor] = newDescriptor
}
//---------------------------------------------------------------------//
private fun copyClassDescriptor(oldDescriptor: ClassDescriptor): ClassDescriptorImpl {
val oldSuperClass = oldDescriptor.getSuperClassOrAny()
val newSuperClass = descriptorSubstituteMap.getOrDefault(oldSuperClass, oldSuperClass) as ClassDescriptor
val oldInterfaces = oldDescriptor.getSuperInterfaces()
val newInterfaces = oldInterfaces.map { descriptorSubstituteMap.getOrDefault(it, it) as ClassDescriptor }
val oldContainingDeclaration = oldDescriptor.containingDeclaration
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
val newName = if (DescriptorUtils.isAnonymousObject(oldDescriptor)) // Anonymous objects are identified by their name.
oldDescriptor.name // We need to preserve it for LocalDeclarationsLowering.
else
generateCopyName(oldDescriptor.name)
val visibility = oldDescriptor.visibility
return object : ClassDescriptorImpl(
/* containingDeclaration = */ newContainingDeclaration,
/* name = */ newName,
/* modality = */ oldDescriptor.modality,
/* kind = */ oldDescriptor.kind,
/* supertypes = */ listOf(newSuperClass.defaultType) + newInterfaces.map { it.defaultType },
/* source = */ oldDescriptor.source,
/* isExternal = */ oldDescriptor.isExternal,
/* storageManager = */ LockBasedStorageManager.NO_LOCKS
) {
override fun getVisibility() = visibility
override fun getDeclaredTypeParameters(): List<TypeParameterDescriptor> {
return oldDescriptor.declaredTypeParameters
}
}
}
}
//-------------------------------------------------------------------------//
inner class DescriptorCollectorInitPhase : IrElementVisitorVoidWithContext() {
private val initializedProperties = mutableSetOf<PropertyDescriptor>()
override fun visitElement(element: IrElement) {
element.acceptChildren(this, null)
}
//---------------------------------------------------------------------//
override fun visitPropertyNew(declaration: IrProperty) {
initPropertyOrField(declaration.descriptor)
super.visitPropertyNew(declaration)
}
//---------------------------------------------------------------------//
override fun visitFieldNew(declaration: IrField) {
val oldDescriptor = declaration.descriptor
if (!initializedProperties.contains(oldDescriptor)) {
initPropertyOrField(oldDescriptor) // A field without a property or a field of a delegated property.
}
super.visitFieldNew(declaration)
}
//---------------------------------------------------------------------//
override fun visitFunctionNew(declaration: IrFunction) {
val oldDescriptor = declaration.descriptor
if (oldDescriptor !is PropertyAccessorDescriptor) { // Property accessors are copied along with their property.
val newDescriptor = initFunctionDescriptor(oldDescriptor)
oldDescriptor.extensionReceiverParameter?.let {
descriptorSubstituteMap[it] = newDescriptor.extensionReceiverParameter!!
}
}
super.visitFunctionNew(declaration)
}
//---------------------------------------------------------------------//
override fun visitVariable(declaration: IrVariable) {
declaration.descriptor.let { descriptorSubstituteMap[it] = copyVariableDescriptor(it) }
super.visitVariable(declaration)
}
//---------------------------------------------------------------------//
override fun visitCatch(aCatch: IrCatch) {
aCatch.parameter.let { descriptorSubstituteMap[it] = copyVariableDescriptor(it) }
super.visitCatch(aCatch)
}
//--- Copy descriptors ------------------------------------------------//
//---------------------------------------------------------------------//
private fun copyVariableDescriptor(oldDescriptor: VariableDescriptor): VariableDescriptor {
val oldContainingDeclaration = oldDescriptor.containingDeclaration
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
return IrTemporaryVariableDescriptorImpl(
containingDeclaration = newContainingDeclaration,
name = oldDescriptor.name,
outType = substituteType(oldDescriptor.type)!!,
isMutable = oldDescriptor.isVar
)
}
//---------------------------------------------------------------------//
private fun initFunctionDescriptor(oldDescriptor: CallableDescriptor): CallableDescriptor =
when (oldDescriptor) {
is ConstructorDescriptor -> initConstructorDescriptor(oldDescriptor)
is SimpleFunctionDescriptor -> initSimpleFunctionDescriptor(oldDescriptor)
else -> TODO("Unsupported FunctionDescriptor subtype: $oldDescriptor")
}
//---------------------------------------------------------------------//
private fun initSimpleFunctionDescriptor(oldDescriptor: SimpleFunctionDescriptor): FunctionDescriptor =
(descriptorSubstituteMap[oldDescriptor] as SimpleFunctionDescriptorImpl).apply {
val oldDispatchReceiverParameter = oldDescriptor.dispatchReceiverParameter
val newDispatchReceiverParameter = oldDispatchReceiverParameter?.let { descriptorSubstituteMap.getOrDefault(it, it) as ReceiverParameterDescriptor }
val newTypeParameters = oldDescriptor.typeParameters // TODO substitute types
val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this)
val newReceiverParameterType = substituteType(oldDescriptor.extensionReceiverParameter?.type)
val newReturnType = substituteType(oldDescriptor.returnType)
initialize(
/* receiverParameterType = */ newReceiverParameterType,
/* dispatchReceiverParameter = */ newDispatchReceiverParameter,
/* typeParameters = */ newTypeParameters,
/* unsubstitutedValueParameters = */ newValueParameters,
/* unsubstitutedReturnType = */ newReturnType,
/* modality = */ oldDescriptor.modality,
/* visibility = */ oldDescriptor.visibility
)
isTailrec = oldDescriptor.isTailrec
isSuspend = oldDescriptor.isSuspend
overriddenDescriptors += oldDescriptor.overriddenDescriptors
}
//---------------------------------------------------------------------//
private fun initConstructorDescriptor(oldDescriptor: ConstructorDescriptor): FunctionDescriptor =
(descriptorSubstituteMap[oldDescriptor] as ClassConstructorDescriptorImpl).apply {
val newTypeParameters = oldDescriptor.typeParameters
val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this)
val receiverParameterType = substituteType(oldDescriptor.dispatchReceiverParameter?.type)
val returnType = substituteType(oldDescriptor.returnType)
initialize(
/* receiverParameterType = */ receiverParameterType,
/* dispatchReceiverParameter = */ null, // For constructor there is no explicit dispatch receiver.
/* typeParameters = */ newTypeParameters,
/* unsubstitutedValueParameters = */ newValueParameters,
/* unsubstitutedReturnType = */ returnType,
/* modality = */ oldDescriptor.modality,
/* visibility = */ oldDescriptor.visibility
)
}
//---------------------------------------------------------------------//
private fun initPropertyOrField(oldDescriptor: PropertyDescriptor) {
val newDescriptor = (descriptorSubstituteMap[oldDescriptor] as PropertyDescriptorImpl).apply {
setType(
/* outType = */ substituteType(oldDescriptor.type)!!,
/* typeParameters = */ oldDescriptor.typeParameters,
/* dispatchReceiverParameter = */ (containingDeclaration as ClassDescriptor).thisAsReceiverParameter,
/* extensionReceiverParamter = */ substituteType(oldDescriptor.extensionReceiverParameter?.type).createExtensionReceiver(this))
initialize(
/* getter = */ oldDescriptor.getter?.let { copyPropertyGetterDescriptor(it, this) },
/* setter = */ oldDescriptor.setter?.let { copyPropertySetterDescriptor(it, this) })
overriddenDescriptors += oldDescriptor.overriddenDescriptors
}
oldDescriptor.getter?.let { descriptorSubstituteMap[it] = newDescriptor.getter!! }
oldDescriptor.setter?.let { descriptorSubstituteMap[it] = newDescriptor.setter!! }
oldDescriptor.extensionReceiverParameter?.let {
descriptorSubstituteMap[it] = newDescriptor.extensionReceiverParameter!!
}
initializedProperties.add(oldDescriptor)
}
//---------------------------------------------------------------------//
private fun copyPropertyGetterDescriptor(oldDescriptor: PropertyGetterDescriptor, newPropertyDescriptor: PropertyDescriptor) =
PropertyGetterDescriptorImpl(
/* correspondingProperty = */ newPropertyDescriptor,
/* annotations = */ oldDescriptor.annotations,
/* modality = */ oldDescriptor.modality,
/* visibility = */ oldDescriptor.visibility,
/* isDefault = */ oldDescriptor.isDefault,
/* isExternal = */ oldDescriptor.isExternal,
/* isInline = */ oldDescriptor.isInline,
/* kind = */ oldDescriptor.kind,
/* original = */ null,
/* source = */ oldDescriptor.source).apply {
initialize(substituteType(oldDescriptor.returnType))
}
//---------------------------------------------------------------------//
private fun copyPropertySetterDescriptor(oldDescriptor: PropertySetterDescriptor, newPropertyDescriptor: PropertyDescriptor) =
PropertySetterDescriptorImpl(
/* correspondingProperty = */ newPropertyDescriptor,
/* annotations = */ oldDescriptor.annotations,
/* modality = */ oldDescriptor.modality,
/* visibility = */ oldDescriptor.visibility,
/* isDefault = */ oldDescriptor.isDefault,
/* isExternal = */ oldDescriptor.isExternal,
/* isInline = */ oldDescriptor.isInline,
/* kind = */ oldDescriptor.kind,
/* original = */ null,
/* source = */ oldDescriptor.source).apply {
initialize(copyValueParameters(oldDescriptor.valueParameters, this).single())
}
//-------------------------------------------------------------------------//
private fun copyValueParameters(oldValueParameters: List <ValueParameterDescriptor>, containingDeclaration: CallableDescriptor) =
oldValueParameters.map { oldDescriptor ->
val newDescriptor = ValueParameterDescriptorImpl(
containingDeclaration = containingDeclaration,
original = oldDescriptor.original,
index = oldDescriptor.index,
annotations = oldDescriptor.annotations,
name = oldDescriptor.name,
outType = substituteType(oldDescriptor.type)!!,
declaresDefaultValue = oldDescriptor.declaresDefaultValue(),
isCrossinline = oldDescriptor.isCrossinline,
isNoinline = oldDescriptor.isNoinline,
varargElementType = substituteType(oldDescriptor.varargElementType),
source = oldDescriptor.source
)
descriptorSubstituteMap[oldDescriptor] = newDescriptor
newDescriptor
}
}
//-----------------------------------------------------------------------------//
@Suppress("DEPRECATION")
inner class InlineCopyIr : DeepCopyIrTree() {
override fun mapClassDeclaration (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
override fun mapTypeAliasDeclaration (descriptor: TypeAliasDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as TypeAliasDescriptor
override fun mapFunctionDeclaration (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
override fun mapConstructorDeclaration (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
override fun mapPropertyDeclaration (descriptor: PropertyDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as PropertyDescriptor
override fun mapLocalPropertyDeclaration (descriptor: VariableDescriptorWithAccessors) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptorWithAccessors
override fun mapEnumEntryDeclaration (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
override fun mapVariableDeclaration (descriptor: VariableDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptor
override fun mapErrorDeclaration (descriptor: DeclarationDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor)
override fun mapClassReference (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
override fun mapValueReference (descriptor: ValueDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ValueDescriptor
override fun mapVariableReference (descriptor: VariableDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptor
override fun mapPropertyReference (descriptor: PropertyDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as PropertyDescriptor
override fun mapCallee (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
override fun mapDelegatedConstructorCallee (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
override fun mapEnumConstructorCallee (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
override fun mapLocalPropertyReference (descriptor: VariableDescriptorWithAccessors) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptorWithAccessors
override fun mapClassifierReference (descriptor: ClassifierDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassifierDescriptor
override fun mapReturnTarget (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
//---------------------------------------------------------------------//
override fun mapSuperQualifier(qualifier: ClassDescriptor?): ClassDescriptor? {
if (qualifier == null) return null
return descriptorSubstituteMap.getOrDefault(qualifier, qualifier) as ClassDescriptor
}
//--- Visits ----------------------------------------------------------//
override fun visitCall(expression: IrCall): IrCall {
if (expression !is IrCallImpl) return super.visitCall(expression)
val newDescriptor = mapCallee(expression.descriptor)
return IrCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = context.ir.translateErased(newDescriptor.returnType!!),
descriptor = newDescriptor,
typeArgumentsCount = expression.typeArgumentsCount,
origin = expression.origin,
superQualifierDescriptor = mapSuperQualifier(expression.superQualifier)
).apply {
transformValueArguments(expression)
substituteTypeArguments(expression)
}
}
override fun visitField(declaration: IrField): IrField {
val descriptor = mapPropertyDeclaration(declaration.descriptor)
return IrFieldImpl(
declaration.startOffset, declaration.endOffset,
mapDeclarationOrigin(declaration.origin),
descriptor,
context.ir.translateErased(descriptor.type),
declaration.initializer?.transform(this@InlineCopyIr, null)
).apply {
transformAnnotations(declaration)
}
}
//---------------------------------------------------------------------//
override fun visitSimpleFunction(declaration: IrSimpleFunction): IrFunction {
val descriptor = mapFunctionDeclaration(declaration.descriptor)
return IrFunctionImpl(
startOffset = declaration.startOffset,
endOffset = declaration.endOffset,
origin = mapDeclarationOrigin(declaration.origin),
descriptor = descriptor,
returnType = context.ir.translateErased(descriptor.returnType!!),
body = declaration.body?.transform(this, null)
).also {
it.setOverrides(context.ir.symbols.symbolTable)
}.transformParameters1(declaration)
}
override fun visitConstructor(declaration: IrConstructor): IrConstructor {
val descriptor = mapConstructorDeclaration(declaration.descriptor)
return IrConstructorImpl(
startOffset = declaration.startOffset,
endOffset = declaration.endOffset,
origin = mapDeclarationOrigin(declaration.origin),
descriptor = descriptor,
returnType = context.ir.translateErased(descriptor.returnType),
body = declaration.body?.transform(this, null)
).transformParameters1(declaration)
}
private fun FunctionDescriptor.getTypeParametersToTransform() =
when {
this is PropertyAccessorDescriptor -> correspondingProperty.typeParameters
else -> typeParameters
}
protected fun <T : IrFunction> T.transformParameters1(original: T): T =
apply {
transformTypeParameters(original, descriptor.getTypeParametersToTransform())
transformValueParameters1(original)
}
protected fun <T : IrFunction> T.transformValueParameters1(original: T) =
apply {
dispatchReceiverParameter =
original.dispatchReceiverParameter?.replaceDescriptor1(
descriptor.dispatchReceiverParameter ?: throw AssertionError("No dispatch receiver in $descriptor")
)
extensionReceiverParameter =
original.extensionReceiverParameter?.replaceDescriptor1(
descriptor.extensionReceiverParameter ?: throw AssertionError("No extension receiver in $descriptor")
)
original.valueParameters.mapIndexedTo(valueParameters) { i, originalValueParameter ->
originalValueParameter.replaceDescriptor1(descriptor.valueParameters[i])
}
}
protected fun IrValueParameter.replaceDescriptor1(newDescriptor: ParameterDescriptor) =
IrValueParameterImpl(
startOffset, endOffset,
mapDeclarationOrigin(origin),
newDescriptor,
context.ir.translateErased(newDescriptor.type),
(newDescriptor as? ValueParameterDescriptor)?.varargElementType?.let { context.ir.translateErased(it) },
defaultValue?.transform(this@InlineCopyIr, null)
).apply {
transformAnnotations(this)
}
//---------------------------------------------------------------------//
override fun visitGetValue(expression: IrGetValue): IrGetValue {
val descriptor = mapValueReference(expression.descriptor)
return IrGetValueImpl(
expression.startOffset, expression.endOffset,
context.ir.translateErased(descriptor.type),
descriptor,
mapStatementOrigin(expression.origin)
)
}
override fun visitVariable(declaration: IrVariable): IrVariable {
val descriptor = mapVariableDeclaration(declaration.descriptor)
return IrVariableImpl(
declaration.startOffset, declaration.endOffset,
mapDeclarationOrigin(declaration.origin),
descriptor,
context.ir.translateErased(descriptor.type),
declaration.initializer?.transform(this, null)
).apply {
transformAnnotations(declaration)
}
}
private fun <T : IrFunction> T.transformDefaults(original: T): T {
for (originalValueParameter in original.descriptor.valueParameters) {
val valueParameter = descriptor.valueParameters[originalValueParameter.index]
original.getDefault(originalValueParameter)?.let { irDefaultParameterValue ->
putDefault(valueParameter, irDefaultParameterValue.transform(this@InlineCopyIr, null))
}
}
return this
}
//---------------------------------------------------------------------//
fun getTypeOperatorReturnType(operator: IrTypeOperator, type: IrType) : IrType {
return when (operator) {
IrTypeOperator.CAST,
IrTypeOperator.IMPLICIT_CAST,
IrTypeOperator.IMPLICIT_NOTNULL,
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
IrTypeOperator.IMPLICIT_INTEGER_COERCION,
IrTypeOperator.SAM_CONVERSION -> type
IrTypeOperator.SAFE_CAST -> type.makeNullable()
IrTypeOperator.INSTANCEOF,
IrTypeOperator.NOT_INSTANCEOF -> context.irBuiltIns.booleanType
}
}
//---------------------------------------------------------------------//
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrTypeOperatorCall {
val erasedTypeOperand = substituteAndEraseType(expression.typeOperand)!!
val typeOperand = substituteAndBreakType(expression.typeOperand)
val returnType = getTypeOperatorReturnType(expression.operator, erasedTypeOperand)
return IrTypeOperatorCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = returnType,
operator = expression.operator,
typeOperand = typeOperand,
argument = expression.argument.transform(this, null),
typeOperandClassifier = (typeOperand as IrSimpleType).classifier
)
}
//---------------------------------------------------------------------//
override fun visitReturn(expression: IrReturn): IrReturn =
IrReturnImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = substituteAndEraseType(expression.type)!!,
returnTargetDescriptor = mapReturnTarget(expression.returnTarget),
value = expression.value.transform(this, null)
)
//---------------------------------------------------------------------//
override fun visitBlock(expression: IrBlock): IrBlock {
return if (expression is IrReturnableBlock) {
IrReturnableBlockImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = expression.type,
descriptor = expression.descriptor,
origin = mapStatementOrigin(expression.origin),
statements = expression.statements.map { it.transform(this, null) },
sourceFileName = expression.sourceFileName
)
} else {
IrBlockImpl(
expression.startOffset, expression.endOffset,
substituteAndEraseType(expression.type)!!,
mapStatementOrigin(expression.origin),
expression.statements.map { it.transform(this, null) }
)
}
}
//-------------------------------------------------------------------------//
override fun visitClassReference(expression: IrClassReference): IrClassReference {
val newExpressionType = substituteAndEraseType(expression.type)!! // Substituted expression type.
val newDescriptorType = substituteType(expression.descriptor.defaultType)!! // Substituted type of referenced class.
val classDescriptor = newDescriptorType.constructor.declarationDescriptor!! // Get ClassifierDescriptor of the referenced class.
return IrClassReferenceImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = newExpressionType,
descriptor = classDescriptor,
classType = expression.classType
)
}
//-------------------------------------------------------------------------//
override fun visitGetClass(expression: IrGetClass): IrGetClass {
val type = substituteAndEraseType(expression.type)!!
return IrGetClassImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = type,
argument = expression.argument.transform(this, null)
)
}
//-------------------------------------------------------------------------//
override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop {
return irLoop
}
override fun visitClass(declaration: IrClass): IrClass {
val descriptor = this.mapClassDeclaration(declaration.descriptor)
return context.ir.symbols.symbolTable.declareClass(
declaration.startOffset, declaration.endOffset, mapDeclarationOrigin(declaration.origin),
descriptor
).apply {
declaration.declarations.mapTo(this.declarations) {
it.transform(this@InlineCopyIr, null) as IrDeclaration
}
this.transformAnnotations(declaration)
this.thisReceiver = declaration.thisReceiver?.replaceDescriptor1(this.descriptor.thisAsReceiverParameter)
this.transformTypeParameters(declaration, this.descriptor.declaredTypeParameters)
descriptor.defaultType.constructor.supertypes.mapTo(this.superTypes) {
context.ir.translateErased(it)
}
}
}
}
//-------------------------------------------------------------------------//
private fun substituteType(type: KotlinType?): KotlinType? {
val substitutedType = (type?.let { typeSubstitutor?.substitute(it, Variance.INVARIANT) } ?: type)
?: return null
val oldClassDescriptor = TypeUtils.getClassDescriptor(substitutedType) ?: return substitutedType
return descriptorSubstituteMap[oldClassDescriptor]?.let { (it as ClassDescriptor).defaultType } ?: substitutedType
}
private fun substituteAndEraseType(oldType: IrType?): IrType? {
oldType ?: return null
val substitutedKotlinType = substituteType(oldType.toKotlinType())
?: return oldType
return context.ir.translateErased(substitutedKotlinType)
}
private fun substituteAndBreakType(oldType: IrType): IrType {
return context.ir.translateBroken(substituteType(oldType.toKotlinType())!!)
}
//-------------------------------------------------------------------------//
private fun IrMemberAccessExpression.substituteTypeArguments(original: IrMemberAccessExpression) {
for (index in 0 until original.typeArgumentsCount) {
val originalTypeArgument = original.getTypeArgument(index)
val newTypeArgument = substituteAndBreakType(originalTypeArgument!!)
this.putTypeArgument(index, newTypeArgument)
}
}
//-------------------------------------------------------------------------//
override fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>) {
descriptorSubstituteMap.forEach { t, u ->
globalSubstituteMap[t] = SubstitutedDescriptor(targetDescriptor, u)
}
}
}
class SubstitutedDescriptor(val inlinedFunction: FunctionDescriptor, val descriptor: DeclarationDescriptor)
internal class DescriptorSubstitutorForExternalScope(
val globalSubstituteMap: Map<DeclarationDescriptor, SubstitutedDescriptor>,
val context: Context
)
: IrElementTransformerVoidWithContext() {
fun run(element: IrElement) {
element.transformChildrenVoid(this)
}
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, substitutedDescriptor: SubstitutedDescriptor): IrCallImpl {
val oldDescriptor = oldExpression.descriptor
val newDescriptor = substitutedDescriptor.descriptor as FunctionDescriptor
if (newDescriptor == oldDescriptor)
return oldExpression
return IrCallImpl(
startOffset = oldExpression.startOffset,
endOffset = oldExpression.endOffset,
type = context.ir.translateErased(newDescriptor.returnType!!),
symbol = createFunctionSymbol(newDescriptor),
descriptor = newDescriptor,
typeArgumentsCount = oldExpression.typeArgumentsCount,
origin = oldExpression.origin,
superQualifierSymbol = createClassSymbolOrNull(oldExpression.superQualifier)
).apply {
copyTypeArgumentsFrom(oldExpression)
oldExpression.descriptor.valueParameters.forEach {
val valueArgument = oldExpression.getValueArgument(it)
putValueArgument(it.index, valueArgument)
}
extensionReceiver = oldExpression.extensionReceiver
dispatchReceiver = oldExpression.dispatchReceiver
}
}
//-------------------------------------------------------------------------//
private fun copyIrCallWithShallowCopy(oldExpression: IrCallWithShallowCopy, substitutedDescriptor: SubstitutedDescriptor): IrCall {
val oldDescriptor = oldExpression.descriptor
val newDescriptor = substitutedDescriptor.descriptor as FunctionDescriptor
if (newDescriptor == oldDescriptor)
return oldExpression
return oldExpression.shallowCopy(oldExpression.origin, createFunctionSymbol(newDescriptor), oldExpression.superQualifierSymbol)
}
}
}
@@ -3,539 +3,401 @@
* that can be found in the LICENSE file.
*/
@file:Suppress("FoldInitializerAndIfToElvis")
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.ScopeWithIr
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
import org.jetbrains.kotlin.backend.common.lower.CoroutineIntrinsicLambdaOrigin
import org.jetbrains.kotlin.backend.common.ir.createTemporaryVariableWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.isBuiltInIntercepted
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineUninterceptedOrReturn
import org.jetbrains.kotlin.backend.common.lower.CoroutineIntrinsicLambdaOrigin
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke
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.irasdescriptors.constructedClass
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isInlineParameter
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irReturn
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.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.referenceFunction
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.TypeProjection
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.TypeSubstitutor
abstract class IrElementTransformerWithContext<D> : IrElementTransformer<D> {
internal class FunctionInlining(val context: Context) : IrElementTransformerVoidWithContext() {
private val scopeStack = mutableListOf<ScopeWithIr>()
fun inline(irModule: IrModuleFragment) = irModule.accept(this, data = null)
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<T>(var value: T)
internal class FunctionInlining(val context: Context): IrElementTransformerWithContext<Ref<Boolean>>() {
private val globalSubstituteMap = mutableMapOf<DeclarationDescriptor, SubstitutedDescriptor>()
private val inlineFunctions = mutableMapOf<FunctionDescriptor, Boolean>()
//-------------------------------------------------------------------------//
fun inline(irModule: IrModuleFragment): IrElement {
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<Boolean>): IrStatement {
val descriptor = declaration.descriptor
val localData = Ref(inlineFunctions[descriptor] ?: false)
val result = super.visitFunctionNew(declaration, localData)
data.value = data.value or localData.value
if (descriptor.needsInlining) {
inlineFunctions[descriptor] = localData.value
}
return result
}
override fun visitCall(expression: IrCall, data: Ref<Boolean>): IrExpression {
val argsAreBad = Ref(false)
val callSite = super.visitCall(expression, argsAreBad) as IrCall
data.value = data.value or argsAreBad.value
override fun visitCall(expression: IrCall): IrExpression {
val callSite = super.visitCall(expression) as IrCall
if (!callSite.descriptor.needsInlining)
return callSite
val functionDescriptor = callSite.descriptor.resolveFakeOverride().original
if (callSite.symbol == context.ir.symbols.isInitializedGetter)
return callSite
val callee = getFunctionDeclaration(functionDescriptor)
if (callee == null) {
val message = "Inliner failed to obtain function declaration: " +
functionDescriptor.fqNameSafe.toString()
context.reportWarning(message, currentFile, callSite)
return callSite
}
data.value = data.value or callee.second
val callee = getFunctionDeclaration(callSite.symbol)
// TODO: do we still need this Ref<Boolean> mechanism?
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
callee.transformChildrenVoid(this) // Process recursive inline.
val currentCalleeIsBad = false
val inliner = Inliner(globalSubstituteMap, callSite, callee.first, !currentCalleeIsBad, currentScope!!,
allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull(), context, this)
val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull()
val inliner = Inliner(callSite, callee, currentScope!!, parent, context)
return inliner.inline()
}
// TODO: do we really need this function anymore?
private fun getFunctionDeclaration(descriptor: FunctionDescriptor): Pair<IrFunction, Boolean>? =
when {
descriptor.isBuiltInIntercepted(context.config.configuration.languageVersionSettings) ->
error("Continuation.intercepted is not available with release coroutines")
private fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction {
val descriptor = symbol.descriptor.original
val languageVersionSettings = context.config.configuration.languageVersionSettings
// TODO: Remove these hacks when coroutine intrinsics are fixed.
return when {
descriptor.isBuiltInIntercepted(languageVersionSettings) ->
error("Continuation.intercepted is not available with release coroutines")
descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(context.config.configuration.languageVersionSettings) ->
getFunctionDeclaration(context.ir.symbols.konanSuspendCoroutineUninterceptedOrReturn.descriptor)
descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) ->
context.ir.symbols.konanSuspendCoroutineUninterceptedOrReturn.owner
descriptor == context.ir.symbols.coroutineContextGetter ->
getFunctionDeclaration(context.ir.symbols.konanCoroutineContextGetter.descriptor)
descriptor == context.ir.symbols.coroutineContextGetter ->
context.ir.symbols.konanCoroutineContextGetter.owner
else ->
context.ir.originalModuleIndex.functions[descriptor]?.let { it to false }
?: context.ir.symbols.symbolTable.referenceFunction(descriptor).owner to true
}
}
private val inlineConstructor = FqName("kotlin.native.internal.InlineConstructor")
private val FunctionDescriptor.isInlineConstructor get() = annotations.hasAnnotation(inlineConstructor)
//-----------------------------------------------------------------------------//
private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>,
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 =
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<ValueDescriptor, IrExpression>()
fun inline() = inlineFunction(callSite, callee)
/**
* TODO: JVM inliner crashed on attempt inline this function from transform.kt with:
* j.l.IllegalStateException: Couldn't obtain compiled function body for
* public inline fun <reified T : org.jetbrains.kotlin.ir.IrElement> kotlin.collections.MutableList<T>.transform...
*/
private inline fun <reified T : IrElement> MutableList<T>.transform(transformation: (T) -> IrElement) {
forEachIndexed { i, item ->
set(i, transformation(item) as T)
}
}
private fun inlineFunction(callSite: IrCall, callee: IrFunction): IrReturnableBlockImpl {
val copiedCallee = copyIrElement.copy(callee) as IrFunction
val evaluationStatements = evaluateArguments(callSite, copiedCallee)
val statements = (copiedCallee.body as IrBlockBody).statements
val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copiedCallee.descriptor.original)
val descriptor = callee.descriptor.original
val startOffset = callee.startOffset
val endOffset = callee.endOffset
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
if (descriptor.isInlineConstructor) {
val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
irBuilder.run {
val constructorDescriptor = delegatingConstructorCall.descriptor.original
val constructorCall = irCall(delegatingConstructorCall.symbol, callSite.type,
constructorDescriptor.typeParameters.map { delegatingConstructorCall.getTypeArgument(it)!! }).apply {
constructorDescriptor.valueParameters.forEach { putValueArgument(it, delegatingConstructorCall.getValueArgument(it)) }
}
val oldThis = (callee as IrConstructor).constructedClass.thisReceiver!!.descriptor
val newThis = currentScope.scope.createTemporaryVariableWithWrappedDescriptor(
irExpression = constructorCall,
nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this"
)
statements[0] = newThis
substituteMap[oldThis] = irGet(newThis)
statements.add(irReturn(irGet(newThis)))
}
}
val sourceFileName = context.ir.originalModuleIndex.declarationToFile[callee.descriptor.original] ?: ""
copyIrElement.addCurrentSubstituteMap(globalSubstituteMap)
val transformer = ParameterSubstitutor()
statements.transform { it.transform(transformer, data = null) }
statements.addAll(0, evaluationStatements)
val isCoroutineIntrinsicCall = callSite.descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(
context.config.configuration.languageVersionSettings)
return IrReturnableBlockImpl(
startOffset = startOffset,
endOffset = endOffset,
type = callSite.type,
symbol = irReturnableBlockSymbol,
origin = if (isCoroutineIntrinsicCall) CoroutineIntrinsicLambdaOrigin else null,
statements = statements,
sourceFileName = sourceFileName
).apply {
transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitReturn(expression: IrReturn): IrExpression {
expression.transformChildrenVoid(this)
if (expression.returnTargetSymbol == copiedCallee.symbol)
return irBuilder.irReturn(expression.value)
return expression
}
})
else -> (symbol.owner as? IrSimpleFunction)?.resolveFakeOverride() ?: symbol.owner
}
}
//---------------------------------------------------------------------//
private val inlineConstructor = FqName("kotlin.native.internal.InlineConstructor")
private val FunctionDescriptor.isInlineConstructor get() = annotations.hasAnnotation(inlineConstructor)
private inner class ParameterSubstitutor: IrElementTransformerVoid() {
private inner class Inliner(val callSite: IrCall,
val callee: IrFunction,
val currentScope: ScopeWithIr,
val parent: IrDeclarationParent?,
val context: Context) {
override fun visitGetValue(expression: IrGetValue): IrExpression {
val newExpression = super.visitGetValue(expression) as IrGetValue
val descriptor = newExpression.descriptor
val argument = substituteMap[descriptor]
if (argument == null) return newExpression
argument.transformChildrenVoid(this) // Default argument can contain subjects for substitution.
return copyIrElement.copy(argument) as IrExpression
val copyIrElement = run {
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<ValueDescriptor, IrExpression>()
override fun visitCall(expression: IrCall): IrExpression {
if (!isLambdaCall(expression))
return super.visitCall(expression)
fun inline() = inlineFunction(callSite, callee)
val dispatchReceiver = expression.dispatchReceiver as IrGetValue
val functionArgument = substituteMap[dispatchReceiver.descriptor]
if (functionArgument == null)
return super.visitCall(expression)
val dispatchDescriptor = dispatchReceiver.descriptor
if (dispatchDescriptor is ValueParameterDescriptor &&
dispatchDescriptor.isNoinline) return super.visitCall(expression)
/**
* TODO: JVM inliner crashed on attempt inline this function from transform.kt with:
* j.l.IllegalStateException: Couldn't obtain compiled function body for
* public inline fun <reified T : org.jetbrains.kotlin.ir.IrElement> kotlin.collections.MutableList<T>.transform...
*/
private inline fun <reified T : IrElement> MutableList<T>.transform(transformation: (T) -> IrElement) {
forEachIndexed { i, item ->
set(i, transformation(item) as T)
}
}
if (functionArgument is IrFunctionReference) {
val functionDescriptor = functionArgument.descriptor
val functionParameters = functionDescriptor.explicitParameters
val boundFunctionParameters = functionArgument.getArguments()
val unboundFunctionParameters = functionParameters - boundFunctionParameters.map { it.first }
val boundFunctionParametersMap = boundFunctionParameters.associate { it.first to it.second }
private fun inlineFunction(callSite: IrCall, callee: IrFunction): IrReturnableBlockImpl {
val copiedCallee = copyIrElement.copy(callee) as IrFunction
var unboundIndex = 0
val unboundArgsSet = unboundFunctionParameters.toSet()
val valueParameters = expression.getArguments().drop(1) // Skip dispatch receiver.
val evaluationStatements = evaluateArguments(callSite, copiedCallee)
val statements = (copiedCallee.body as IrBlockBody).statements
val immediateCall = IrCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = expression.type,
symbol = functionArgument.symbol,
descriptor = functionArgument.descriptor).apply {
functionParameters.forEach {
val argument =
if (!unboundArgsSet.contains(it))
boundFunctionParametersMap[it]!!
else
valueParameters[unboundIndex++].second
when (it) {
functionDescriptor.dispatchReceiverParameter -> this.dispatchReceiver = argument
functionDescriptor.extensionReceiverParameter -> this.extensionReceiver = argument
else -> putValueArgument((it as ValueParameterDescriptor).index, argument)
val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copiedCallee.descriptor.original)
val descriptor = callee.descriptor.original
val startOffset = callee.startOffset
val endOffset = callee.endOffset
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
if (descriptor.isInlineConstructor) {
val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
irBuilder.run {
val constructorDescriptor = delegatingConstructorCall.descriptor.original
val constructorCall = irCall(delegatingConstructorCall.symbol, callSite.type,
constructorDescriptor.typeParameters.map { delegatingConstructorCall.getTypeArgument(it)!! }).apply {
constructorDescriptor.valueParameters.forEach { putValueArgument(it, delegatingConstructorCall.getValueArgument(it)) }
}
val oldThis = (callee as IrConstructor).constructedClass.thisReceiver!!.descriptor
val newThis = currentScope.scope.createTemporaryVariableWithWrappedDescriptor(
irExpression = constructorCall,
nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this"
)
statements[0] = newThis
substituteMap[oldThis] = irGet(newThis)
statements.add(irReturn(irGet(newThis)))
}
}
val sourceFileName = context.ir.originalModuleIndex.declarationToFile[callee.descriptor.original] ?: ""
val transformer = ParameterSubstitutor()
statements.transform { it.transform(transformer, data = null) }
statements.addAll(0, evaluationStatements)
val isCoroutineIntrinsicCall = callSite.descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(
context.config.configuration.languageVersionSettings)
return IrReturnableBlockImpl(
startOffset = startOffset,
endOffset = endOffset,
type = callSite.type,
symbol = irReturnableBlockSymbol,
origin = if (isCoroutineIntrinsicCall) CoroutineIntrinsicLambdaOrigin else null,
statements = statements,
sourceFileName = sourceFileName
).apply {
transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitReturn(expression: IrReturn): IrExpression {
expression.transformChildrenVoid(this)
if (expression.returnTargetSymbol == copiedCallee.symbol)
return irBuilder.irReturn(expression.value)
return expression
}
})
}
}
//---------------------------------------------------------------------//
private inner class ParameterSubstitutor : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
val newExpression = super.visitGetValue(expression) as IrGetValue
val descriptor = newExpression.descriptor
val argument = substituteMap[descriptor] ?: return newExpression
argument.transformChildrenVoid(this) // Default argument can contain subjects for substitution.
return copyIrElement.copy(argument) as IrExpression
}
//-----------------------------------------------------------------//
override fun visitCall(expression: IrCall): IrExpression {
if (!isLambdaCall(expression))
return super.visitCall(expression)
val dispatchReceiver = expression.dispatchReceiver as IrGetValue
val functionArgument = substituteMap[dispatchReceiver.descriptor] ?: return super.visitCall(expression)
val dispatchDescriptor = dispatchReceiver.descriptor
if (dispatchDescriptor is ValueParameterDescriptor && dispatchDescriptor.isNoinline)
return super.visitCall(expression)
if (functionArgument is IrFunctionReference) {
val functionDescriptor = functionArgument.descriptor
val functionParameters = functionDescriptor.explicitParameters
val boundFunctionParameters = functionArgument.getArguments()
val unboundFunctionParameters = functionParameters - boundFunctionParameters.map { it.first }
val boundFunctionParametersMap = boundFunctionParameters.associate { it.first to it.second }
var unboundIndex = 0
val unboundArgsSet = unboundFunctionParameters.toSet()
val valueParameters = expression.getArguments().drop(1) // Skip dispatch receiver.
val immediateCall = IrCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = expression.type,
symbol = functionArgument.symbol,
descriptor = functionArgument.descriptor).apply {
functionParameters.forEach {
val argument =
if (!unboundArgsSet.contains(it))
boundFunctionParametersMap[it]!!
else
valueParameters[unboundIndex++].second
when (it) {
functionDescriptor.dispatchReceiverParameter -> this.dispatchReceiver = argument
functionDescriptor.extensionReceiverParameter -> this.extensionReceiver = argument
else -> putValueArgument((it as ValueParameterDescriptor).index, argument)
}
}
assert(unboundIndex == valueParameters.size) { "Not all arguments of <invoke> are used" }
for (index in 0 until functionArgument.typeArgumentsCount)
putTypeArgument(index, functionArgument.getTypeArgument(index))
}
assert(unboundIndex == valueParameters.size) { "Not all arguments of <invoke> are used" }
for (index in 0 until functionArgument.typeArgumentsCount)
putTypeArgument(index, functionArgument.getTypeArgument(index))
return this@FunctionInlining.visitCall(super.visitCall(immediateCall) as IrCall)
}
return owner.visitCall(super.visitCall(immediateCall) as IrCall, Ref(false))
}
if (functionArgument !is IrBlock)
return super.visitCall(expression)
if (functionArgument !is IrBlock)
return super.visitCall(expression)
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.
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.
}
//-----------------------------------------------------------------//
override fun visitElement(element: IrElement) = element.accept(this, null)
}
//-----------------------------------------------------------------//
private fun isLambdaCall(irCall: IrCall) = irCall.descriptor.isFunctionInvoke && irCall.dispatchReceiver is IrGetValue
override fun visitElement(element: IrElement) = element.accept(this, null)
}
//-------------------------------------------------------------------------//
private fun isLambdaCall(irCall: IrCall) = irCall.descriptor.isFunctionInvoke && irCall.dispatchReceiver is IrGetValue
private inner class ParameterToArgument(val parameter: IrValueParameter,
val argumentExpression: IrExpression) {
private fun createTypeSubstitutor(irCall: IrCall): TypeSubstitutor? {
if (irCall.typeArgumentsCount == 0) return null
val descriptor = irCall.descriptor.resolveFakeOverride().original
val typeParameters = descriptor.propertyIfAccessor.typeParameters
val substitutionContext = mutableMapOf<TypeConstructor, TypeProjection>()
for (index in 0 until irCall.typeArgumentsCount) {
val typeArgument = irCall.getTypeArgument(index) ?: continue
substitutionContext[typeParameters[index].typeConstructor] = TypeProjectionImpl(typeArgument.toKotlinType())
val isInlinableLambdaArgument: Boolean
get() {
if (!parameter.isInlineParameter()) return false
if (argumentExpression is IrFunctionReference
&& !argumentExpression.descriptor.isSuspend) return true // Skip suspend functions for now since it's not supported by FE anyway.
// Do pattern-matching on IR.
if (argumentExpression !is IrBlock) return false
if (argumentExpression.origin != IrStatementOrigin.LAMBDA &&
argumentExpression.origin != IrStatementOrigin.ANONYMOUS_FUNCTION) return false
val statements = argumentExpression.statements
val irFunction = statements[0]
val irCallableReference = statements[1]
if (irFunction !is IrFunction) return false
if (irCallableReference !is IrCallableReference) return false
return true
}
val isImmutableVariableLoad: Boolean
get() = argumentExpression.let {
it is IrGetValue && !it.descriptor.let { it is VariableDescriptor && it.isVar }
}
}
return TypeSubstitutor.create(substitutionContext)
}
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
private class ParameterToArgument(val parameter: IrValueParameter,
val argumentExpression : IrExpression) {
private fun buildParameterToArgument(callSite: IrCall, callee: IrFunction): List<ParameterToArgument> {
val isInlinableLambdaArgument : Boolean
get() {
if (!parameter.isInlineParameter()) return false
if (argumentExpression is IrFunctionReference
&& !argumentExpression.descriptor.isSuspend) return true // Skip suspend functions for now since it's not supported by FE anyway.
val parameterToArgument = mutableListOf<ParameterToArgument>()
// Do pattern-matching on IR.
if (argumentExpression !is IrBlock) return false
if (argumentExpression.origin != IrStatementOrigin.LAMBDA &&
argumentExpression.origin != IrStatementOrigin.ANONYMOUS_FUNCTION) return false
val statements = argumentExpression.statements
val irFunction = statements[0]
val irCallableReference = statements[1]
if (irFunction !is IrFunction) return false
if (irCallableReference !is IrCallableReference) return false
return true
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 = callee.dispatchReceiverParameter!!,
argumentExpression = callSite.dispatchReceiver!!
)
val valueArguments =
callSite.descriptor.valueParameters.map { callSite.getValueArgument(it) }.toMutableList()
if (callee.extensionReceiverParameter != null) {
parameterToArgument += ParameterToArgument(
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 (callSite.extensionReceiver != null) {
// Special case: usual lambda is called as lambda with receiver:
valueArguments.add(0, callSite.extensionReceiver!!)
}
val isImmutableVariableLoad: Boolean
get() = argumentExpression.let {
it is IrGetValue && !it.descriptor.let { it is VariableDescriptor && it.isVar }
}
}
//-------------------------------------------------------------------------//
private fun buildParameterToArgument(callSite: IrCall, callee: IrFunction): List<ParameterToArgument> {
val parameterToArgument = mutableListOf<ParameterToArgument>()
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 = callee.dispatchReceiverParameter!!,
argumentExpression = callSite.dispatchReceiver!!
)
val valueArguments =
callSite.descriptor.valueParameters.map { callSite.getValueArgument(it) }.toMutableList()
if (callee.extensionReceiverParameter != null) {
parameterToArgument += ParameterToArgument(
parameter = callee.extensionReceiverParameter!!,
argumentExpression = if (callSite.extensionReceiver != null) {
callSite.extensionReceiver!!
} else {
// Special case: lambda with receiver is called as usual lambda:
valueArguments.removeAt(0)!!
val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>()
for (parameter in callee.valueParameters) {
val argument = valueArguments[parameter.index]
when {
argument != null -> {
parameterToArgument += ParameterToArgument(
parameter = parameter,
argumentExpression = argument
)
}
)
} else if (callSite.extensionReceiver != null) {
// Special case: usual lambda is called as lambda with receiver:
valueArguments.add(0, callSite.extensionReceiver!!)
}
val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>()
for (parameter in callee.valueParameters) {
val argument = valueArguments[parameter.index]
when {
argument != null -> {
parameterToArgument += ParameterToArgument(
parameter = parameter,
argumentExpression = argument
)
}
// After ExpectDeclarationsRemoving pass default values from expect declarations
// are represented correctly in IR.
parameter.defaultValue != null -> { // There is no argument - try default value.
parametersWithDefaultToArgument += ParameterToArgument(
parameter = parameter,
argumentExpression = parameter.defaultValue!!.expression
)
}
// After ExpectDeclarationsRemoving pass default values from expect declarations
// are represented correctly in IR.
parameter.defaultValue != null -> { // There is no argument - try default value.
parametersWithDefaultToArgument += ParameterToArgument(
parameter = parameter,
argumentExpression = parameter.defaultValue!!.expression
)
}
parameter.varargElementType != null -> {
val emptyArray = IrVarargImpl(
startOffset = callSite.startOffset,
endOffset = callSite.endOffset,
type = parameter.type,
varargElementType = parameter.varargElementType!!
)
parameterToArgument += ParameterToArgument(
parameter = parameter,
argumentExpression = emptyArray
)
}
parameter.varargElementType != null -> {
val emptyArray = IrVarargImpl(
startOffset = callSite.startOffset,
endOffset = callSite.endOffset,
type = parameter.type,
varargElementType = parameter.varargElementType!!
)
parameterToArgument += ParameterToArgument(
parameter = parameter,
argumentExpression = emptyArray
)
}
else -> {
val message = "Incomplete expression: call to ${callee.descriptor} " +
"has no argument at index ${parameter.index}"
throw Error(message)
else -> {
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.
}
//-------------------------------------------------------------------------//
private fun evaluateArguments(callSite: IrCall, callee: IrFunction): List<IrStatement> {
val parameterToArgumentOld = buildParameterToArgument(callSite, callee)
val evaluationStatements = mutableListOf<IrStatement>()
val substitutor = ParameterSubstitutor()
parameterToArgumentOld.forEach {
val parameterDescriptor = it.parameter.descriptor
/*
* We need to create temporary variable for each argument except inlinable lambda arguments.
* For simplicity and to produce simpler IR we don't create temporaries for every immutable variable,
* not only for those referring to inlinable lambdas.
*/
if (it.isInlinableLambdaArgument) {
substituteMap[parameterDescriptor] = it.argumentExpression
return@forEach
}
if (it.isImmutableVariableLoad) {
substituteMap[parameterDescriptor] = it.argumentExpression.transform(substitutor, data = null) // Arguments may reference the previous ones - substitute them.
return@forEach
}
val newVariable = currentScope.scope.createTemporaryVariableWithWrappedDescriptor( // Create new variable and init it with the parameter expression.
irExpression = it.argumentExpression.transform(substitutor, data = null), // Arguments may reference the previous ones - substitute them.
nameHint = callee.descriptor.name.toString(),
isMutable = false)
evaluationStatements.add(newVariable)
val getVal = IrGetValueImpl(
startOffset = currentScope.irElement.startOffset,
endOffset = currentScope.irElement.endOffset,
type = newVariable.type,
symbol = newVariable.symbol
)
substituteMap[parameterDescriptor] = getVal
}
return evaluationStatements
}
return parameterToArgument + parametersWithDefaultToArgument // All arguments except default are evaluated at callsite,
// but default arguments are evaluated inside callee.
}
//-------------------------------------------------------------------------//
private fun evaluateArguments(callSite: IrCall, callee: IrFunction): List<IrStatement> {
val parameterToArgumentOld = buildParameterToArgument(callSite, callee)
val evaluationStatements = mutableListOf<IrStatement>()
val substitutor = ParameterSubstitutor()
parameterToArgumentOld.forEach {
val parameterDescriptor = it.parameter.descriptor
/*
* We need to create temporary variable for each argument except inlinable lambda arguments.
* For simplicity and to produce simpler IR we don't create temporaries for every immutable variable,
* not only for those referring to inlinable lambdas.
*/
if (it.isInlinableLambdaArgument) {
substituteMap[parameterDescriptor] = it.argumentExpression
return@forEach
}
if (it.isImmutableVariableLoad) {
substituteMap[parameterDescriptor] = it.argumentExpression.transform(substitutor, data = null) // Arguments may reference the previous ones - substitute them.
return@forEach
}
val newVariable = currentScope.scope.createTemporaryVariableWithWrappedDescriptor( // Create new variable and init it with the parameter expression.
irExpression = it.argumentExpression.transform(substitutor, data = null), // Arguments may reference the previous ones - substitute them.
nameHint = callee.descriptor.name.toString(),
isMutable = false)
evaluationStatements.add(newVariable)
val getVal = IrGetValueImpl(
startOffset = currentScope.irElement.startOffset,
endOffset = currentScope.irElement.endOffset,
type = newVariable.type,
symbol = newVariable.symbol
)
substituteMap[parameterDescriptor] = getVal
}
return evaluationStatements
}
}
}