New copier for inliner
This commit is contained in:
+198
-17
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.konan.lower
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.*
|
import org.jetbrains.kotlin.backend.common.*
|
||||||
import org.jetbrains.kotlin.backend.common.IrElementVisitorVoidWithContext
|
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.common.lower.SimpleMemberScope
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
import org.jetbrains.kotlin.backend.konan.Context
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.createExtensionReceiver
|
import org.jetbrains.kotlin.backend.konan.descriptors.createExtensionReceiver
|
||||||
@@ -19,37 +20,217 @@ import org.jetbrains.kotlin.ir.declarations.impl.*
|
|||||||
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
|
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.createClassSymbolOrNull
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||||
import org.jetbrains.kotlin.ir.types.toKotlinType
|
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
|
||||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
|
||||||
import org.jetbrains.kotlin.types.Variance
|
val typeArguments: Map<IrTypeParameterSymbol, IrType?>?,
|
||||||
|
val parent: IrDeclarationParent?) : IrCopierForInliner {
|
||||||
|
|
||||||
|
override fun copy(irElement: IrElement): IrElement {
|
||||||
|
// Create new symbols.
|
||||||
|
irElement.acceptVoid(symbolRemapper)
|
||||||
|
|
||||||
|
// Make symbol remapper aware of the callsite's type arguments.
|
||||||
|
symbolRemapper.typeArguments = typeArguments
|
||||||
|
|
||||||
|
// Copy IR.
|
||||||
|
val result = irElement.transform(copier, data = null)
|
||||||
|
|
||||||
|
// Bind newly created IR with wrapped descriptors.
|
||||||
|
result.acceptVoid(object: IrElementVisitorVoid {
|
||||||
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitClass(declaration: IrClass) {
|
||||||
|
(declaration.descriptor as WrappedClassDescriptor).bind(declaration)
|
||||||
|
declaration.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitConstructor(declaration: IrConstructor) {
|
||||||
|
(declaration.descriptor as WrappedClassConstructorDescriptor).bind(declaration)
|
||||||
|
declaration.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitEnumEntry(declaration: IrEnumEntry) {
|
||||||
|
(declaration.descriptor as WrappedClassDescriptor).bind(
|
||||||
|
declaration.correspondingClass ?: declaration.parentAsClass)
|
||||||
|
declaration.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitField(declaration: IrField) {
|
||||||
|
(declaration.descriptor as WrappedPropertyDescriptor).bind(declaration)
|
||||||
|
declaration.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunction(declaration: IrFunction) {
|
||||||
|
(declaration.descriptor as WrappedSimpleFunctionDescriptor).bind(declaration as IrSimpleFunction)
|
||||||
|
declaration.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitValueParameter(declaration: IrValueParameter) {
|
||||||
|
(declaration.descriptor as? WrappedValueParameterDescriptor)?.bind(declaration)
|
||||||
|
(declaration.descriptor as? WrappedReceiverParameterDescriptor)?.bind(declaration)
|
||||||
|
declaration.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitTypeParameter(declaration: IrTypeParameter) {
|
||||||
|
(declaration.descriptor as WrappedTypeParameterDescriptor).bind(declaration)
|
||||||
|
declaration.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitVariable(declaration: IrVariable) {
|
||||||
|
(declaration.descriptor as WrappedVariableDescriptor).bind(declaration)
|
||||||
|
declaration.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
result.patchDeclarationParents(parent)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private var nameIndex = 0
|
||||||
|
|
||||||
|
private fun generateCopyName(name: Name) = Name.identifier(name.toString() + "_" + (nameIndex++).toString())
|
||||||
|
|
||||||
|
private inner class InlinerSymbolRenamer : SymbolRenamer {
|
||||||
|
private val map = mutableMapOf<IrSymbol, Name>()
|
||||||
|
|
||||||
|
override fun getClassName(symbol: IrClassSymbol) = map.getOrPut(symbol) { generateCopyName(symbol.owner.name) }
|
||||||
|
override fun getFunctionName(symbol: IrSimpleFunctionSymbol) = map.getOrPut(symbol) { generateCopyName(symbol.owner.name) }
|
||||||
|
override fun getFieldName(symbol: IrFieldSymbol) = symbol.owner.name
|
||||||
|
override fun getFileName(symbol: IrFileSymbol) = symbol.owner.fqName
|
||||||
|
override fun getExternalPackageFragmentName(symbol: IrExternalPackageFragmentSymbol) = symbol.owner.fqName
|
||||||
|
override fun getEnumEntryName(symbol: IrEnumEntrySymbol) = symbol.owner.name
|
||||||
|
override fun getVariableName(symbol: IrVariableSymbol) = map.getOrPut(symbol) { generateCopyName(symbol.owner.name) }
|
||||||
|
override fun getTypeParameterName(symbol: IrTypeParameterSymbol) = symbol.owner.name
|
||||||
|
override fun getValueParameterName(symbol: IrValueParameterSymbol) = symbol.owner.name
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class DescriptorsToIrRemapper : DescriptorsRemapper {
|
||||||
|
override fun remapDeclaredClass(descriptor: ClassDescriptor) =
|
||||||
|
WrappedClassDescriptor(descriptor.annotations, descriptor.source)
|
||||||
|
|
||||||
|
override fun remapDeclaredConstructor(descriptor: ClassConstructorDescriptor) =
|
||||||
|
WrappedClassConstructorDescriptor(descriptor.annotations, descriptor.source)
|
||||||
|
|
||||||
|
override fun remapDeclaredEnumEntry(descriptor: ClassDescriptor) =
|
||||||
|
WrappedClassDescriptor(descriptor.annotations, descriptor.source)
|
||||||
|
|
||||||
|
override fun remapDeclaredField(descriptor: PropertyDescriptor) =
|
||||||
|
WrappedPropertyDescriptor(descriptor.annotations, descriptor.source)
|
||||||
|
|
||||||
|
override fun remapDeclaredSimpleFunction(descriptor: FunctionDescriptor) =
|
||||||
|
WrappedSimpleFunctionDescriptor(descriptor.annotations, descriptor.source)
|
||||||
|
|
||||||
|
override fun remapDeclaredTypeParameter(descriptor: TypeParameterDescriptor) =
|
||||||
|
WrappedTypeParameterDescriptor(descriptor.annotations, descriptor.source)
|
||||||
|
|
||||||
|
override fun remapDeclaredVariable(descriptor: VariableDescriptor) =
|
||||||
|
WrappedVariableDescriptor(descriptor.annotations, descriptor.source)
|
||||||
|
|
||||||
|
override fun remapDeclaredValueParameter(descriptor: ParameterDescriptor): ParameterDescriptor =
|
||||||
|
if (descriptor is ReceiverParameterDescriptor)
|
||||||
|
WrappedReceiverParameterDescriptor(descriptor.annotations, descriptor.source)
|
||||||
|
else
|
||||||
|
WrappedValueParameterDescriptor(descriptor.annotations, descriptor.source)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class InlinerTypeRemapper(val symbolRemapper: SymbolRemapper,
|
||||||
|
val typeArguments: Map<IrTypeParameterSymbol, IrType?>?) : TypeRemapper {
|
||||||
|
|
||||||
|
override fun enterScope(irTypeParametersContainer: IrTypeParametersContainer) { }
|
||||||
|
|
||||||
|
override fun leaveScope() { }
|
||||||
|
|
||||||
|
private fun remapTypeArguments(arguments: List<IrTypeArgument>) =
|
||||||
|
arguments.map { argument ->
|
||||||
|
(argument as? IrTypeProjection)?.let { makeTypeProjection(remapType(it.type), it.variance) }
|
||||||
|
?: argument
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remapType(type: IrType): IrType {
|
||||||
|
if (type !is IrSimpleType) return type
|
||||||
|
|
||||||
|
val substitutedType = typeArguments?.get(type.classifier)
|
||||||
|
if (substitutedType != null) {
|
||||||
|
substitutedType as IrSimpleType
|
||||||
|
return IrSimpleTypeImpl(
|
||||||
|
kotlinType = null,
|
||||||
|
classifier = substitutedType.classifier,
|
||||||
|
hasQuestionMark = type.hasQuestionMark or substitutedType.isMarkedNullable(),
|
||||||
|
arguments = substitutedType.arguments,
|
||||||
|
annotations = substitutedType.annotations
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return IrSimpleTypeImpl(
|
||||||
|
kotlinType = null,
|
||||||
|
classifier = symbolRemapper.getReferencedClassifier(type.classifier),
|
||||||
|
hasQuestionMark = type.hasQuestionMark,
|
||||||
|
arguments = remapTypeArguments(type.arguments),
|
||||||
|
annotations = type.annotations.map { it.transform(copier, null) as IrCall }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>) { }
|
||||||
|
|
||||||
|
private class SymbolRemapperImpl(descriptorsRemapper: DescriptorsRemapper)
|
||||||
|
: DeepCopySymbolRemapper(descriptorsRemapper) {
|
||||||
|
|
||||||
|
var typeArguments: Map<IrTypeParameterSymbol, IrType?>? = null
|
||||||
|
set(value) {
|
||||||
|
if (field != null) return
|
||||||
|
field = value?.asSequence()?.associate {
|
||||||
|
(getReferencedClassifier(it.key) as IrTypeParameterSymbol) to it.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getReferencedClassifier(symbol: IrClassifierSymbol): IrClassifierSymbol {
|
||||||
|
val result = super.getReferencedClassifier(symbol)
|
||||||
|
if (result !is IrTypeParameterSymbol)
|
||||||
|
return result
|
||||||
|
return typeArguments?.get(result)?.classifierOrNull ?: result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val symbolRemapper = SymbolRemapperImpl(DescriptorsToIrRemapper())
|
||||||
|
private val copier = DeepCopyIrTreeWithSymbols(
|
||||||
|
symbolRemapper,
|
||||||
|
InlinerTypeRemapper(symbolRemapper, typeArguments),
|
||||||
|
InlinerSymbolRenamer()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal interface IrCopierForInliner {
|
||||||
|
fun copy(irElement: IrElement): IrElement
|
||||||
|
fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>)
|
||||||
|
}
|
||||||
|
|
||||||
internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
|
internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
|
||||||
val parentDescriptor: DeclarationDescriptor,
|
val parentDescriptor: DeclarationDescriptor,
|
||||||
val context: Context) {
|
val context: Context,
|
||||||
|
val typeSubstitutor: TypeSubstitutor?) : IrCopierForInliner {
|
||||||
|
|
||||||
private val descriptorSubstituteMap: MutableMap<DeclarationDescriptor, DeclarationDescriptor> = mutableMapOf()
|
private val descriptorSubstituteMap: MutableMap<DeclarationDescriptor, DeclarationDescriptor> = mutableMapOf()
|
||||||
private var typeSubstitutor: TypeSubstitutor? = null
|
|
||||||
private var nameIndex = 0
|
private var nameIndex = 0
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
fun copy(irElement: IrElement, typeSubstitutor: TypeSubstitutor?): IrElement {
|
override fun copy(irElement: IrElement): IrElement {
|
||||||
this.typeSubstitutor = typeSubstitutor
|
|
||||||
// Create all class descriptors and all necessary descriptors in order to create KotlinTypes.
|
// Create all class descriptors and all necessary descriptors in order to create KotlinTypes.
|
||||||
irElement.acceptVoid(DescriptorCollectorCreatePhase())
|
irElement.acceptVoid(DescriptorCollectorCreatePhase())
|
||||||
// Initialize all created descriptors possibly using previously created types.
|
// Initialize all created descriptors possibly using previously created types.
|
||||||
@@ -762,7 +943,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
|
|||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>) {
|
override fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>) {
|
||||||
descriptorSubstituteMap.forEach { t, u ->
|
descriptorSubstituteMap.forEach { t, u ->
|
||||||
globalSubstituteMap[t] = SubstitutedDescriptor(targetDescriptor, u)
|
globalSubstituteMap[t] = SubstitutedDescriptor(targetDescriptor, u)
|
||||||
}
|
}
|
||||||
|
|||||||
+226
-160
@@ -9,6 +9,7 @@ package org.jetbrains.kotlin.backend.konan.lower
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.*
|
import org.jetbrains.kotlin.backend.common.*
|
||||||
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
|
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
|
||||||
|
import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
import org.jetbrains.kotlin.backend.konan.Context
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke
|
import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke
|
||||||
@@ -16,26 +17,23 @@ import org.jetbrains.kotlin.backend.konan.descriptors.needsInlining
|
|||||||
import org.jetbrains.kotlin.backend.konan.descriptors.propertyIfAccessor
|
import org.jetbrains.kotlin.backend.konan.descriptors.propertyIfAccessor
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride
|
import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.DeserializerDriver
|
import org.jetbrains.kotlin.backend.konan.ir.DeserializerDriver
|
||||||
|
import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass
|
||||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
|
||||||
import org.jetbrains.kotlin.ir.types.toKotlinType
|
import org.jetbrains.kotlin.ir.types.toKotlinType
|
||||||
import org.jetbrains.kotlin.ir.util.getArguments
|
import org.jetbrains.kotlin.ir.util.getArguments
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||||
@@ -44,70 +42,154 @@ import org.jetbrains.kotlin.types.TypeProjection
|
|||||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------//
|
abstract class IrElementTransformerWithContext<D> : IrElementTransformer<D> {
|
||||||
|
|
||||||
internal class FunctionInlining(val context: Context): IrElementTransformerVoidWithContext() {
|
private val scopeStack = mutableListOf<ScopeWithIr>()
|
||||||
|
|
||||||
|
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 deserializer = DeserializerDriver(context)
|
private val deserializer = DeserializerDriver(context)
|
||||||
private val globalSubstituteMap = mutableMapOf<DeclarationDescriptor, SubstitutedDescriptor>()
|
private val globalSubstituteMap = mutableMapOf<DeclarationDescriptor, SubstitutedDescriptor>()
|
||||||
|
private val inlineFunctions = mutableMapOf<FunctionDescriptor, Boolean>()
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
fun inline(irModule: IrModuleFragment): IrElement {
|
fun inline(irModule: IrModuleFragment): IrElement {
|
||||||
val transformedModule = irModule.accept(this, null)
|
val transformedModule = irModule.accept(this, Ref(false))
|
||||||
DescriptorSubstitutorForExternalScope(globalSubstituteMap, context).run(transformedModule) // Transform calls to object that might be returned from inline function call.
|
DescriptorSubstitutorForExternalScope(globalSubstituteMap, context).run(transformedModule) // Transform calls to object that might be returned from inline function call.
|
||||||
return transformedModule
|
return transformedModule
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
override fun visitFunctionNew(declaration: IrFunction, data: Ref<Boolean>): IrStatement {
|
||||||
|
val descriptor = declaration.descriptor
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall): IrExpression {
|
val localData = Ref(inlineFunctions[descriptor] ?: false)
|
||||||
|
val result = super.visitFunctionNew(declaration, localData)
|
||||||
|
data.value = data.value or localData.value
|
||||||
|
|
||||||
val irCall = super.visitCall(expression) as IrCall
|
if (descriptor.needsInlining)
|
||||||
val functionDescriptor = irCall.descriptor
|
inlineFunctions[descriptor] = localData.value
|
||||||
if (!functionDescriptor.needsInlining || functionDescriptor == context.ir.symbols.isInitializedGetterDescriptor) {
|
return result
|
||||||
return irCall // This call does not need inlining.
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val functionDeclaration = getFunctionDeclaration(functionDescriptor) // Get declaration of the function to be inlined.
|
override fun visitCall(expression: IrCall, data: Ref<Boolean>): IrExpression {
|
||||||
if (functionDeclaration == null) { // We failed to get the declaration.
|
|
||||||
|
val argsAreBad = Ref(false)
|
||||||
|
val callSite = super.visitCall(expression, argsAreBad) as IrCall
|
||||||
|
data.value = data.value or argsAreBad.value
|
||||||
|
if (!callSite.descriptor.needsInlining)
|
||||||
|
return callSite
|
||||||
|
val functionDescriptor = callSite.descriptor.resolveFakeOverride().original
|
||||||
|
if (functionDescriptor == context.ir.symbols.isInitializedGetterDescriptor)
|
||||||
|
return callSite
|
||||||
|
|
||||||
|
val callee = getFunctionDeclaration(functionDescriptor)
|
||||||
|
if (callee == null) {
|
||||||
val message = "Inliner failed to obtain function declaration: " +
|
val message = "Inliner failed to obtain function declaration: " +
|
||||||
functionDescriptor.fqNameSafe.toString()
|
functionDescriptor.fqNameSafe.toString()
|
||||||
context.reportWarning(message, currentFile, irCall) // Report warning.
|
context.reportWarning(message, currentFile, callSite)
|
||||||
return irCall
|
return callSite
|
||||||
}
|
}
|
||||||
|
data.value = data.value or callee.second
|
||||||
|
|
||||||
functionDeclaration.transformChildrenVoid(this) // Process recursive inline.
|
val childIsBad = Ref(inlineFunctions[functionDescriptor] ?: false)
|
||||||
val inliner = Inliner(globalSubstituteMap, functionDeclaration, currentScope!!, context, this) // Create inliner for this scope.
|
callee.first.transformChildren(this, childIsBad) // Process recursive inline.
|
||||||
return inliner.inline(irCall) // Return newly created IrInlineBody instead of IrCall.
|
inlineFunctions[functionDescriptor] = childIsBad.value
|
||||||
|
data.value = data.value or childIsBad.value
|
||||||
|
|
||||||
|
val currentCalleeIsBad = argsAreBad.value or childIsBad.value or callee.second
|
||||||
|
val inliner = Inliner(globalSubstituteMap, callSite, callee.first, !currentCalleeIsBad, currentScope!!,
|
||||||
|
allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull(), context, this)
|
||||||
|
return inliner.inline()
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private fun getFunctionDeclaration(descriptor: FunctionDescriptor): IrFunction? =
|
private fun getFunctionDeclaration(descriptor: FunctionDescriptor): Pair<IrFunction, Boolean>? =
|
||||||
descriptor.resolveFakeOverride().original.let {
|
when {
|
||||||
when {
|
descriptor.isBuiltInIntercepted(context.config.configuration.languageVersionSettings) ->
|
||||||
it.isBuiltInIntercepted(context.config.configuration.languageVersionSettings) ->
|
error("Continuation.intercepted is not available with release coroutines")
|
||||||
error("Continuation.intercepted is not available with release coroutines")
|
|
||||||
|
|
||||||
it.isBuiltInSuspendCoroutineUninterceptedOrReturn(context.config.configuration.languageVersionSettings) ->
|
descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(context.config.configuration.languageVersionSettings) ->
|
||||||
getFunctionDeclaration(context.ir.symbols.konanSuspendCoroutineUninterceptedOrReturn.descriptor)
|
getFunctionDeclaration(context.ir.symbols.konanSuspendCoroutineUninterceptedOrReturn.descriptor)
|
||||||
|
|
||||||
it == context.ir.symbols.coroutineContextGetter ->
|
descriptor == context.ir.symbols.coroutineContextGetter ->
|
||||||
getFunctionDeclaration(context.ir.symbols.konanCoroutineContextGetter.descriptor)
|
getFunctionDeclaration(context.ir.symbols.konanCoroutineContextGetter.descriptor)
|
||||||
|
|
||||||
else -> {
|
else ->
|
||||||
val functionDeclaration =
|
context.ir.originalModuleIndex.functions[descriptor]?.let { it to false }
|
||||||
context.ir.originalModuleIndex.functions[it] ?: // If function is declared in the current module.
|
?: deserializer.deserializeInlineBody(descriptor)?.let { it as IrFunction to true }
|
||||||
deserializer.deserializeInlineBody(it) // Function is declared in another module.
|
|
||||||
functionDeclaration as IrFunction?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
override fun visitElement(element: IrElement) = element.accept(this, null)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val inlineConstructor = FqName("kotlin.native.internal.InlineConstructor")
|
private val inlineConstructor = FqName("kotlin.native.internal.InlineConstructor")
|
||||||
@@ -116,22 +198,34 @@ private val FunctionDescriptor.isInlineConstructor get() = annotations.hasAnnota
|
|||||||
//-----------------------------------------------------------------------------//
|
//-----------------------------------------------------------------------------//
|
||||||
|
|
||||||
private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>,
|
private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>,
|
||||||
val functionDeclaration: IrFunction, // Function to substitute.
|
val callSite: IrCall,
|
||||||
|
val callee: IrFunction,
|
||||||
|
val local: Boolean,
|
||||||
val currentScope: ScopeWithIr,
|
val currentScope: ScopeWithIr,
|
||||||
|
val parent: IrDeclarationParent?,
|
||||||
val context: Context,
|
val context: Context,
|
||||||
val owner: FunctionInlining /*TODO: make inner*/) {
|
val owner: FunctionInlining /*TODO: make inner*/) {
|
||||||
|
|
||||||
val copyIrElement = DeepCopyIrTreeWithDescriptors(functionDeclaration.descriptor, currentScope.scope.scopeOwner, context) // Create DeepCopy for current scope.
|
val copyIrElement =
|
||||||
|
if (!local)
|
||||||
|
DeepCopyIrTreeWithDescriptors(callee.descriptor, currentScope.scope.scopeOwner,
|
||||||
|
context, createTypeSubstitutor(callSite))
|
||||||
|
else {
|
||||||
|
val typeParameters =
|
||||||
|
if (callee is IrConstructor)
|
||||||
|
callee.parentAsClass.typeParameters
|
||||||
|
else callee.typeParameters
|
||||||
|
val typeArguments =
|
||||||
|
(0 until callSite.typeArgumentsCount).map {
|
||||||
|
typeParameters[it].symbol to callSite.getTypeArgument(it)
|
||||||
|
}.associate { it }
|
||||||
|
DeepCopyIrTreeWithSymbolsForInliner(context, typeArguments, parent)
|
||||||
|
}
|
||||||
|
|
||||||
val substituteMap = mutableMapOf<ValueDescriptor, IrExpression>()
|
val substituteMap = mutableMapOf<ValueDescriptor, IrExpression>()
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
fun inline() = inlineFunction(callSite, callee)
|
||||||
|
|
||||||
fun inline(irCall: IrCall): IrReturnableBlockImpl { // Call to be substituted.
|
|
||||||
val inlineFunctionBody = inlineFunction(irCall, functionDeclaration)
|
|
||||||
return inlineFunctionBody
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
|
||||||
/**
|
/**
|
||||||
* TODO: JVM inliner crashed on attempt inline this function from transform.kt with:
|
* TODO: JVM inliner crashed on attempt inline this function from transform.kt with:
|
||||||
* j.l.IllegalStateException: Couldn't obtain compiled function body for
|
* j.l.IllegalStateException: Couldn't obtain compiled function body for
|
||||||
@@ -143,29 +237,23 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun inlineFunction(callee: IrCall, // Call to be substituted.
|
private fun inlineFunction(callSite: IrCall, callee: IrFunction): IrReturnableBlockImpl {
|
||||||
caller: IrFunction): IrReturnableBlockImpl { // Function to substitute.
|
val copiedCallee = copyIrElement.copy(callee) as IrFunction
|
||||||
|
|
||||||
val copyFunctionDeclaration = copyIrElement.copy( // Create copy of original function.
|
val evaluationStatements = evaluateArguments(callSite, copiedCallee)
|
||||||
irElement = caller, // Descriptors declared inside the function will be copied.
|
val statements = (copiedCallee.body as IrBlockBody).statements
|
||||||
typeSubstitutor = createTypeSubstitutor(callee) // Type parameters will be substituted with type arguments.
|
|
||||||
) as IrFunction
|
|
||||||
|
|
||||||
val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copyFunctionDeclaration.descriptor.original)
|
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)
|
||||||
|
|
||||||
val evaluationStatements = evaluateArguments(callee, copyFunctionDeclaration) // And list of evaluation statements.
|
|
||||||
|
|
||||||
val statements = (copyFunctionDeclaration.body as IrBlockBody).statements // IR statements from function copy.
|
|
||||||
|
|
||||||
val startOffset = caller.startOffset
|
|
||||||
val endOffset = caller.endOffset
|
|
||||||
val descriptor = caller.descriptor.original
|
|
||||||
if (descriptor.isInlineConstructor) {
|
if (descriptor.isInlineConstructor) {
|
||||||
val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
|
val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
|
||||||
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
|
|
||||||
irBuilder.run {
|
irBuilder.run {
|
||||||
val constructorDescriptor = delegatingConstructorCall.descriptor.original
|
val constructorDescriptor = delegatingConstructorCall.descriptor.original
|
||||||
val constructorCall = irCall(delegatingConstructorCall.symbol, callee.type,
|
val constructorCall = irCall(delegatingConstructorCall.symbol, callSite.type,
|
||||||
constructorDescriptor.typeParameters.map { delegatingConstructorCall.getTypeArgument(it)!! }).apply {
|
constructorDescriptor.typeParameters.map { delegatingConstructorCall.getTypeArgument(it)!! }).apply {
|
||||||
constructorDescriptor.valueParameters.forEach { putValueArgument(it, delegatingConstructorCall.getValueArgument(it)) }
|
constructorDescriptor.valueParameters.forEach { putValueArgument(it, delegatingConstructorCall.getValueArgument(it)) }
|
||||||
}
|
}
|
||||||
@@ -180,31 +268,36 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val sourceFileName = context.ir.originalModuleIndex.declarationToFile[caller.descriptor.original]?:""
|
val sourceFileName = context.ir.originalModuleIndex.declarationToFile[callee.descriptor.original] ?: ""
|
||||||
|
|
||||||
// Update globalSubstituteMap before computing return type.
|
|
||||||
// This is needed because of nested inlining.
|
|
||||||
copyIrElement.addCurrentSubstituteMap(globalSubstituteMap)
|
copyIrElement.addCurrentSubstituteMap(globalSubstituteMap)
|
||||||
|
|
||||||
val transformer = ParameterSubstitutor()
|
val transformer = ParameterSubstitutor()
|
||||||
statements.transform { it.transform(transformer, data = null) }
|
statements.transform { it.transform(transformer, data = null) }
|
||||||
statements.addAll(0, evaluationStatements)
|
statements.addAll(0, evaluationStatements)
|
||||||
val oldDescriptor = (copyFunctionDeclaration.returnType.classifierOrNull as? IrClassSymbol)?.descriptor
|
|
||||||
val substitutedDescriptor = oldDescriptor?.let { globalSubstituteMap[it] }
|
|
||||||
val returnType = substitutedDescriptor?.let { context.ir.translateErased((it.descriptor as ClassDescriptor).defaultType) }
|
|
||||||
?: copyFunctionDeclaration.returnType
|
|
||||||
|
|
||||||
val isCoroutineIntrinsicCall = callee.descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(context.config.configuration.languageVersionSettings)
|
val isCoroutineIntrinsicCall = callSite.descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(
|
||||||
|
context.config.configuration.languageVersionSettings)
|
||||||
|
|
||||||
return IrReturnableBlockImpl( // Create new IR element to replace "call".
|
return IrReturnableBlockImpl(
|
||||||
startOffset = startOffset,
|
startOffset = startOffset,
|
||||||
endOffset = endOffset,
|
endOffset = endOffset,
|
||||||
type = returnType,
|
type = copiedCallee.returnType,
|
||||||
symbol = irReturnableBlockSymbol,
|
symbol = irReturnableBlockSymbol,
|
||||||
origin = if (isCoroutineIntrinsicCall) CoroutineIntrinsicLambdaOrigin else null,
|
origin = if (isCoroutineIntrinsicCall) CoroutineIntrinsicLambdaOrigin else null,
|
||||||
statements = statements,
|
statements = statements,
|
||||||
sourceFileName = sourceFileName
|
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
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
//---------------------------------------------------------------------//
|
||||||
@@ -214,14 +307,12 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
|
|||||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
val newExpression = super.visitGetValue(expression) as IrGetValue
|
val newExpression = super.visitGetValue(expression) as IrGetValue
|
||||||
val descriptor = newExpression.descriptor
|
val descriptor = newExpression.descriptor
|
||||||
val argument = substituteMap[descriptor] // Find expression to replace this parameter.
|
val argument = substituteMap[descriptor]
|
||||||
if (argument == null) return newExpression // If there is no such expression - do nothing.
|
|
||||||
|
|
||||||
argument.transformChildrenVoid(this) // Default argument can contain subjects for substitution.
|
if (argument == null) return newExpression
|
||||||
return copyIrElement.copy( // Make copy of argument expression.
|
|
||||||
irElement = argument,
|
argument.transformChildrenVoid(this) // Default argument can contain subjects for substitution.
|
||||||
typeSubstitutor = null
|
return copyIrElement.copy(argument) as IrExpression
|
||||||
) as IrExpression
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------//
|
//-----------------------------------------------------------------//
|
||||||
@@ -267,14 +358,14 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
|
|||||||
else -> putValueArgument((it as ValueParameterDescriptor).index, argument)
|
else -> putValueArgument((it as ValueParameterDescriptor).index, argument)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(unboundIndex == valueParameters.size, { "Not all arguments of <invoke> are used" })
|
assert(unboundIndex == valueParameters.size) { "Not all arguments of <invoke> are used" }
|
||||||
}
|
}
|
||||||
return owner.visitCall(super.visitCall(immediateCall) as IrCall)
|
return owner.visitCall(super.visitCall(immediateCall) as IrCall, Ref(false))
|
||||||
}
|
}
|
||||||
if (functionArgument !is IrBlock)
|
if (functionArgument !is IrBlock)
|
||||||
return super.visitCall(expression)
|
return super.visitCall(expression)
|
||||||
|
|
||||||
val functionDeclaration = getLambdaFunction(functionArgument)
|
val functionDeclaration = functionArgument.statements[0] as IrFunction
|
||||||
val newExpression = inlineFunction(expression, functionDeclaration) // Inline the lambda. Lambda parameters will be substituted with lambda arguments.
|
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.
|
return newExpression.transform(this, null) // Substitute lambda arguments with target function arguments.
|
||||||
}
|
}
|
||||||
@@ -284,22 +375,7 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
|
|||||||
override fun visitElement(element: IrElement) = element.accept(this, null)
|
override fun visitElement(element: IrElement) = element.accept(this, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
//--- Helpers -------------------------------------------------------------//
|
private fun isLambdaCall(irCall: IrCall) = irCall.descriptor.isFunctionInvoke && irCall.dispatchReceiver is IrGetValue
|
||||||
|
|
||||||
private fun isLambdaCall(irCall: IrCall) : Boolean {
|
|
||||||
if (!irCall.descriptor.isFunctionInvoke) return false // Lambda mast be called by "invoke".
|
|
||||||
if (irCall.dispatchReceiver !is IrGetValue) return false // Dispatch receiver mast be IrGetValue.
|
|
||||||
return true // It is lambda call.
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
private fun getLambdaFunction(lambdaArgument: IrBlock): IrFunction {
|
|
||||||
val statements = lambdaArgument.statements
|
|
||||||
return statements[0] as IrFunction
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
private fun createTypeSubstitutor(irCall: IrCall): TypeSubstitutor? {
|
private fun createTypeSubstitutor(irCall: IrCall): TypeSubstitutor? {
|
||||||
if (irCall.typeArgumentsCount == 0) return null
|
if (irCall.typeArgumentsCount == 0) return null
|
||||||
@@ -344,45 +420,43 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
|
|||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private fun buildParameterToArgument(irCall : IrCall, // Call site.
|
private fun buildParameterToArgument(callSite: IrCall, callee: IrFunction): List<ParameterToArgument> {
|
||||||
irFunction: IrFunction // Function to be called.
|
|
||||||
): List<ParameterToArgument> {
|
|
||||||
|
|
||||||
val parameterToArgument = mutableListOf<ParameterToArgument>() // Result list.
|
val parameterToArgument = mutableListOf<ParameterToArgument>()
|
||||||
|
|
||||||
if (irCall.dispatchReceiver != null && // Only if there are non null dispatch receivers both
|
if (callSite.dispatchReceiver != null && // Only if there are non null dispatch receivers both
|
||||||
irFunction.dispatchReceiverParameter != null) // on call site and in function declaration.
|
callee.dispatchReceiverParameter != null) // on call site and in function declaration.
|
||||||
parameterToArgument += ParameterToArgument(
|
parameterToArgument += ParameterToArgument(
|
||||||
parameter = irFunction.dispatchReceiverParameter!!,
|
parameter = callee.dispatchReceiverParameter!!,
|
||||||
argumentExpression = irCall.dispatchReceiver!!
|
argumentExpression = callSite.dispatchReceiver!!
|
||||||
)
|
)
|
||||||
|
|
||||||
val valueArguments =
|
val valueArguments =
|
||||||
irCall.descriptor.valueParameters.map { irCall.getValueArgument(it) }.toMutableList()
|
callSite.descriptor.valueParameters.map { callSite.getValueArgument(it) }.toMutableList()
|
||||||
|
|
||||||
if (irFunction.extensionReceiverParameter != null) {
|
if (callee.extensionReceiverParameter != null) {
|
||||||
parameterToArgument += ParameterToArgument(
|
parameterToArgument += ParameterToArgument(
|
||||||
parameter = irFunction.extensionReceiverParameter!!,
|
parameter = callee.extensionReceiverParameter!!,
|
||||||
argumentExpression = if (irCall.extensionReceiver != null) {
|
argumentExpression = if (callSite.extensionReceiver != null) {
|
||||||
irCall.extensionReceiver!!
|
callSite.extensionReceiver!!
|
||||||
} else {
|
} else {
|
||||||
// Special case: lambda with receiver is called as usual lambda:
|
// Special case: lambda with receiver is called as usual lambda:
|
||||||
valueArguments.removeAt(0)!!
|
valueArguments.removeAt(0)!!
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
} else if (irCall.extensionReceiver != null) {
|
} else if (callSite.extensionReceiver != null) {
|
||||||
// Special case: usual lambda is called as lambda with receiver:
|
// Special case: usual lambda is called as lambda with receiver:
|
||||||
valueArguments.add(0, irCall.extensionReceiver!!)
|
valueArguments.add(0, callSite.extensionReceiver!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>()
|
val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>()
|
||||||
irFunction.valueParameters.forEach { parameter -> // Iterate value parameters.
|
for (parameter in callee.valueParameters) {
|
||||||
val argument = valueArguments[parameter.index] // Get appropriate argument from call site.
|
val argument = valueArguments[parameter.index]
|
||||||
when {
|
when {
|
||||||
argument != null -> { // Argument is good enough.
|
argument != null -> {
|
||||||
parameterToArgument += ParameterToArgument( // Associate current parameter with the argument.
|
parameterToArgument += ParameterToArgument(
|
||||||
parameter = parameter,
|
parameter = parameter,
|
||||||
argumentExpression = argument
|
argumentExpression = argument
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,43 +464,41 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
|
|||||||
// are represented correctly in IR.
|
// are represented correctly in IR.
|
||||||
parameter.defaultValue != null -> { // There is no argument - try default value.
|
parameter.defaultValue != null -> { // There is no argument - try default value.
|
||||||
parametersWithDefaultToArgument += ParameterToArgument(
|
parametersWithDefaultToArgument += ParameterToArgument(
|
||||||
parameter = parameter,
|
parameter = parameter,
|
||||||
argumentExpression = parameter.defaultValue!!.expression
|
argumentExpression = parameter.defaultValue!!.expression
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
parameter.varargElementType != null -> {
|
parameter.varargElementType != null -> {
|
||||||
val emptyArray = IrVarargImpl(
|
val emptyArray = IrVarargImpl(
|
||||||
startOffset = irCall.startOffset,
|
startOffset = callSite.startOffset,
|
||||||
endOffset = irCall.endOffset,
|
endOffset = callSite.endOffset,
|
||||||
type = parameter.type,
|
type = parameter.type,
|
||||||
varargElementType = parameter.varargElementType!!
|
varargElementType = parameter.varargElementType!!
|
||||||
)
|
)
|
||||||
parameterToArgument += ParameterToArgument(
|
parameterToArgument += ParameterToArgument(
|
||||||
parameter = parameter,
|
parameter = parameter,
|
||||||
argumentExpression = emptyArray
|
argumentExpression = emptyArray
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
val message = "Incomplete expression: call to ${irFunction.descriptor} " +
|
val message = "Incomplete expression: call to ${callee.descriptor} " +
|
||||||
"has no argument at index ${parameter.index}"
|
"has no argument at index ${parameter.index}"
|
||||||
throw Error(message)
|
throw Error(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return parameterToArgument + parametersWithDefaultToArgument // All arguments except default are evaluated at callsite,
|
return parameterToArgument + parametersWithDefaultToArgument // All arguments except default are evaluated at callsite,
|
||||||
// but default arguments are evaluated inside callee.
|
// but default arguments are evaluated inside callee.
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private fun evaluateArguments(irCall : IrCall, // Call site.
|
private fun evaluateArguments(callSite: IrCall, callee: IrFunction): List<IrStatement> {
|
||||||
functionDeclaration: IrFunction // Function to be called.
|
|
||||||
): List<IrStatement> {
|
|
||||||
|
|
||||||
val parameterToArgumentOld = buildParameterToArgument(irCall, functionDeclaration) // Create map parameter_descriptor -> original_argument_expression.
|
val parameterToArgumentOld = buildParameterToArgument(callSite, callee)
|
||||||
val evaluationStatements = mutableListOf<IrStatement>() // List of evaluation statements.
|
val evaluationStatements = mutableListOf<IrStatement>()
|
||||||
val substitutor = ParameterSubstitutor()
|
val substitutor = ParameterSubstitutor()
|
||||||
parameterToArgumentOld.forEach {
|
parameterToArgumentOld.forEach {
|
||||||
val parameterDescriptor = it.parameter.descriptor
|
val parameterDescriptor = it.parameter.descriptor
|
||||||
@@ -446,26 +518,20 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
|
|||||||
return@forEach
|
return@forEach
|
||||||
}
|
}
|
||||||
|
|
||||||
val newVariable = currentScope.scope.createTemporaryVariable( // Create new variable and init it with the parameter expression.
|
val newVariable = currentScope.scope.createTemporaryVariable(
|
||||||
irExpression = it.argumentExpression.transform(substitutor, data = null), // Arguments may reference the previous ones - substitute them.
|
irExpression = it.argumentExpression.transform(substitutor, data = null), // Arguments may reference the previous ones - substitute them.
|
||||||
nameHint = functionDeclaration.descriptor.name.toString(),
|
nameHint = callee.descriptor.name.toString(),
|
||||||
isMutable = false)
|
isMutable = false)
|
||||||
|
|
||||||
evaluationStatements.add(newVariable) // Add initialization of the new variable in statement list.
|
evaluationStatements.add(newVariable)
|
||||||
val getVal = IrGetValueImpl( // Create new expression, representing access the new variable.
|
val getVal = IrGetValueImpl(
|
||||||
startOffset = currentScope.irElement.startOffset,
|
startOffset = currentScope.irElement.startOffset,
|
||||||
endOffset = currentScope.irElement.endOffset,
|
endOffset = currentScope.irElement.endOffset,
|
||||||
type = newVariable.type,
|
type = newVariable.type,
|
||||||
symbol = newVariable.symbol
|
symbol = newVariable.symbol
|
||||||
)
|
)
|
||||||
substituteMap[parameterDescriptor] = getVal // Parameter will be replaced with the new variable.
|
substituteMap[parameterDescriptor] = getVal
|
||||||
}
|
}
|
||||||
return evaluationStatements
|
return evaluationStatements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+4
-6
@@ -21,9 +21,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
|||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.util.constructors
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.util.createDispatchReceiverParameter
|
|
||||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.js.descriptorUtils.hasPrimaryConstructor
|
import org.jetbrains.kotlin.js.descriptorUtils.hasPrimaryConstructor
|
||||||
@@ -88,7 +86,7 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createInitializerMethod(): IrSimpleFunctionSymbol? {
|
private fun createInitializerMethod(): IrSimpleFunctionSymbol? {
|
||||||
if (irClass.descriptor.hasPrimaryConstructor())
|
if (irClass.declarations.any { it is IrConstructor && it.isPrimary })
|
||||||
return null // Place initializers in the primary constructor.
|
return null // Place initializers in the primary constructor.
|
||||||
val initializerMethodDescriptor = SimpleFunctionDescriptorImpl.create(
|
val initializerMethodDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||||
/* containingDeclaration = */ irClass.descriptor,
|
/* containingDeclaration = */ irClass.descriptor,
|
||||||
@@ -125,9 +123,8 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
|
|||||||
initializer.dispatchReceiverParameter!!.type,
|
initializer.dispatchReceiverParameter!!.type,
|
||||||
initializer.dispatchReceiverParameter!!.symbol
|
initializer.dispatchReceiverParameter!!.symbol
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
return expression
|
|
||||||
}
|
}
|
||||||
|
return expression
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -191,6 +188,7 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
declaration.parent = irClass
|
||||||
|
|
||||||
return declaration
|
return declaration
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-4
@@ -1309,10 +1309,9 @@ internal class IrDeserializer(val context: Context,
|
|||||||
(key,value) ->
|
(key,value) ->
|
||||||
key to value}
|
key to value}
|
||||||
|
|
||||||
return DeepCopyIrTreeWithDescriptors(rootFunction, rootFunction.parents.first(), context).copy(
|
return DeepCopyIrTreeWithDescriptors(rootFunction, rootFunction.parents.first(), context,
|
||||||
irElement = declaration,
|
TypeSubstitutor.create(substitutionContext)
|
||||||
typeSubstitutor = TypeSubstitutor.create(substitutionContext)
|
).copy(declaration) as IrFunction
|
||||||
) as IrFunction
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val extractInlineProto: KonanProtoBuf.InlineIrBody
|
private val extractInlineProto: KonanProtoBuf.InlineIrBody
|
||||||
|
|||||||
Reference in New Issue
Block a user