[JS IR BE] updated inliner to the most recent version
FunctionInlining.kt commit 364b7ae72a :
https://github.com/JetBrains/kotlin-native/blob/364b7ae72a49c2a1716c83c1bab0866dfe46fa25/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt
This commit is contained in:
+102
-125
@@ -8,18 +8,16 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.lower.inline
|
package org.jetbrains.kotlin.ir.backend.js.lower.inline
|
||||||
|
|
||||||
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.ir.createTemporaryVariableWithWrappedDescriptor
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.CoroutineIntrinsicLambdaOrigin
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
|
import org.jetbrains.kotlin.backend.common.serialization.fqNameSafe
|
||||||
|
import org.jetbrains.kotlin.backend.common.serialization.hasAnnotation
|
||||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ValueDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
|
||||||
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.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.ArrayConstructorTransformer
|
import org.jetbrains.kotlin.ir.backend.js.lower.ArrayConstructorTransformer
|
||||||
import org.jetbrains.kotlin.ir.builders.irCall
|
|
||||||
import org.jetbrains.kotlin.ir.builders.irGet
|
import org.jetbrains.kotlin.ir.builders.irGet
|
||||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
@@ -35,8 +33,7 @@ import org.jetbrains.kotlin.ir.util.*
|
|||||||
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.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
|
||||||
|
|
||||||
typealias Context = JsIrBackendContext
|
typealias Context = JsIrBackendContext
|
||||||
|
|
||||||
@@ -53,9 +50,9 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
|
|||||||
|
|
||||||
override fun visitCall(expression: IrCall): IrExpression {
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
val callSite = arrayConstructorTransformer.transformCall(super.visitCall(expression) as IrCall)
|
val callSite = arrayConstructorTransformer.transformCall(super.visitCall(expression) as IrCall)
|
||||||
val functionDescriptor = callSite.descriptor
|
|
||||||
|
|
||||||
if (!functionDescriptor.needsInlining) return callSite // This call does not need inlining.
|
if (!callSite.symbol.owner.needsInlining)
|
||||||
|
return callSite
|
||||||
|
|
||||||
val languageVersionSettings = context.configuration.languageVersionSettings
|
val languageVersionSettings = context.configuration.languageVersionSettings
|
||||||
when {
|
when {
|
||||||
@@ -76,19 +73,12 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
|
|||||||
|
|
||||||
val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull()
|
val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull()
|
||||||
val inliner = Inliner(callSite, callee, currentScope!!, parent, context)
|
val inliner = Inliner(callSite, callee, currentScope!!, parent, context)
|
||||||
// Create inliner for this scope.
|
return inliner.inline()
|
||||||
return inliner.inline() // Return newly created IrInlineBody instead of IrCall.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
private fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction {
|
private fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction {
|
||||||
|
|
||||||
val descriptor = symbol.descriptor.original
|
val descriptor = symbol.descriptor.original
|
||||||
// val originalDescriptor = functionDescriptor.resolveFakeOverride().original
|
|
||||||
|
|
||||||
val languageVersionSettings = context.configuration.languageVersionSettings
|
val languageVersionSettings = context.configuration.languageVersionSettings
|
||||||
|
|
||||||
// TODO: Remove these hacks when coroutine intrinsics are fixed.
|
// TODO: Remove these hacks when coroutine intrinsics are fixed.
|
||||||
return when {
|
return when {
|
||||||
// descriptor.isBuiltInIntercepted(languageVersionSettings) ->
|
// descriptor.isBuiltInIntercepted(languageVersionSettings) ->
|
||||||
@@ -104,20 +94,17 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: should we keep this at all?
|
|
||||||
private val inlineConstructor = FqName("kotlin.native.internal.InlineConstructor")
|
private val inlineConstructor = FqName("kotlin.native.internal.InlineConstructor")
|
||||||
private val FunctionDescriptor.isInlineConstructor get() = annotations.hasAnnotation(inlineConstructor)
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------//
|
private val IrFunction.isInlineConstructor get() = annotations.hasAnnotation(inlineConstructor)
|
||||||
|
|
||||||
private inner class Inliner(
|
private val IrFunction.needsInlining get() = isInlineConstructor || (this.isInline && !this.isExternal)
|
||||||
val callSite: IrCall,
|
|
||||||
val callee: IrFunction,
|
private inner class Inliner(val callSite: IrCall,
|
||||||
val currentScope: ScopeWithIr,
|
val callee: IrFunction,
|
||||||
val parent: IrDeclarationParent?,
|
val currentScope: ScopeWithIr,
|
||||||
val context: Context
|
val parent: IrDeclarationParent?,
|
||||||
) {
|
val context: Context) {
|
||||||
|
|
||||||
val copyIrElement = run {
|
val copyIrElement = run {
|
||||||
val typeParameters =
|
val typeParameters =
|
||||||
@@ -131,7 +118,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
|
|||||||
DeepCopyIrTreeWithSymbolsForInliner(context, typeArguments, parent)
|
DeepCopyIrTreeWithSymbolsForInliner(context, typeArguments, parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
val substituteMap = mutableMapOf<ValueDescriptor, IrExpression>()
|
val substituteMap = mutableMapOf<IrValueParameter, IrExpression>()
|
||||||
|
|
||||||
fun inline() = inlineFunction(callSite, callee)
|
fun inline() = inlineFunction(callSite, callee)
|
||||||
|
|
||||||
@@ -146,35 +133,42 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun inlineFunction(callSite: IrCall, callee: IrFunction): IrReturnableBlockImpl {
|
private fun inlineFunction(callSite: IrCall, callee: IrFunction): IrReturnableBlock {
|
||||||
val copiedCallee = copyIrElement.copy(callee) as IrFunction
|
val copiedCallee = copyIrElement.copy(callee) as IrFunction
|
||||||
|
|
||||||
val evaluationStatements = evaluateArguments(callSite, copiedCallee)
|
val evaluationStatements = evaluateArguments(callSite, copiedCallee)
|
||||||
val statements = (copiedCallee.body as IrBlockBody).statements
|
val statements = (copiedCallee.body as IrBlockBody).statements
|
||||||
|
|
||||||
val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copiedCallee.descriptor.original)
|
val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copiedCallee.descriptor.original)
|
||||||
val descriptor = callee.descriptor.original
|
|
||||||
val startOffset = callee.startOffset
|
val startOffset = callee.startOffset
|
||||||
val endOffset = callee.endOffset
|
val endOffset = callee.endOffset
|
||||||
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
|
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
|
||||||
|
|
||||||
if (descriptor.isInlineConstructor) {
|
if (callee.isInlineConstructor) {
|
||||||
|
// Copier sets parent to be the current function but
|
||||||
|
// constructor's parent cannot be a function.
|
||||||
|
val constructedClass = callee.parentAsClass
|
||||||
|
copiedCallee.parent = constructedClass
|
||||||
val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
|
val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
|
||||||
irBuilder.run {
|
irBuilder.run {
|
||||||
val constructorDescriptor = delegatingConstructorCall.descriptor.original
|
val constructorCall = IrCallImpl(
|
||||||
val constructorCall = irCall(delegatingConstructorCall.symbol, callSite.type,
|
startOffset, endOffset,
|
||||||
constructorDescriptor.typeParameters.map { delegatingConstructorCall.getTypeArgument(it)!! }).apply {
|
callSite.type,
|
||||||
constructorDescriptor.valueParameters.forEach {
|
delegatingConstructorCall.symbol, delegatingConstructorCall.descriptor,
|
||||||
putValueArgument(
|
constructedClass.typeParameters.size,
|
||||||
it,
|
delegatingConstructorCall.symbol.owner.valueParameters.size
|
||||||
delegatingConstructorCall.getValueArgument(it)
|
).apply {
|
||||||
)
|
delegatingConstructorCall.symbol.owner.valueParameters.forEach {
|
||||||
|
putValueArgument(it.index, delegatingConstructorCall.getValueArgument(it.index))
|
||||||
|
}
|
||||||
|
constructedClass.typeParameters.forEach {
|
||||||
|
putTypeArgument(it.index, delegatingConstructorCall.getTypeArgument(it.index))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val oldThis = delegatingConstructorCall.descriptor.constructedClass.thisAsReceiverParameter
|
val oldThis = constructedClass.thisReceiver!!
|
||||||
val newThis = currentScope.scope.createTemporaryVariable(
|
val newThis = currentScope.scope.createTemporaryVariableWithWrappedDescriptor(
|
||||||
irExpression = constructorCall,
|
irExpression = constructorCall,
|
||||||
nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this"
|
nameHint = constructedClass.fqNameSafe.toString() + ".this"
|
||||||
)
|
)
|
||||||
statements[0] = newThis
|
statements[0] = newThis
|
||||||
substituteMap[oldThis] = irGet(newThis)
|
substituteMap[oldThis] = irGet(newThis)
|
||||||
@@ -182,20 +176,25 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val sourceFile = callee.file
|
||||||
|
|
||||||
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 isCoroutineIntrinsicCall = callSite.descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(
|
||||||
|
context.configuration.languageVersionSettings)
|
||||||
|
|
||||||
return IrReturnableBlockImpl(
|
return IrReturnableBlockImpl(
|
||||||
startOffset = startOffset,
|
startOffset = startOffset,
|
||||||
endOffset = endOffset,
|
endOffset = endOffset,
|
||||||
type = copiedCallee.returnType,
|
type = callSite.type,
|
||||||
symbol = irReturnableBlockSymbol,
|
symbol = irReturnableBlockSymbol,
|
||||||
origin = null,
|
origin = if (isCoroutineIntrinsicCall) CoroutineIntrinsicLambdaOrigin else null,
|
||||||
statements = statements,
|
statements = statements,
|
||||||
sourceFileSymbol = callee.file.symbol
|
sourceFileSymbol = sourceFile.symbol
|
||||||
).apply {
|
).apply {
|
||||||
transformChildrenVoid(object: IrElementTransformerVoid() {
|
transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||||
override fun visitReturn(expression: IrReturn): IrExpression {
|
override fun visitReturn(expression: IrReturn): IrExpression {
|
||||||
expression.transformChildrenVoid(this)
|
expression.transformChildrenVoid(this)
|
||||||
|
|
||||||
@@ -213,8 +212,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
|
|||||||
|
|
||||||
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 argument = substituteMap[newExpression.symbol.owner] ?: return newExpression
|
||||||
val argument = substituteMap[descriptor] ?: return newExpression
|
|
||||||
|
|
||||||
argument.transformChildrenVoid(this) // Default argument can contain subjects for substitution.
|
argument.transformChildrenVoid(this) // Default argument can contain subjects for substitution.
|
||||||
return copyIrElement.copy(argument) as IrExpression
|
return copyIrElement.copy(argument) as IrExpression
|
||||||
@@ -222,57 +220,46 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
|
|||||||
|
|
||||||
//-----------------------------------------------------------------//
|
//-----------------------------------------------------------------//
|
||||||
|
|
||||||
private val IrFunctionReference.isLambda: Boolean
|
|
||||||
get() {
|
|
||||||
return symbol.owner.visibility == Visibilities.LOCAL && origin == IrStatementOrigin.LAMBDA
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall): IrExpression {
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
if (!isLambdaCall(expression))
|
if (!isLambdaCall(expression))
|
||||||
return super.visitCall(expression)
|
return super.visitCall(expression)
|
||||||
|
|
||||||
val dispatchReceiver = expression.dispatchReceiver as IrGetValue
|
val dispatchReceiver = expression.dispatchReceiver as IrGetValue
|
||||||
val functionArgument = substituteMap[dispatchReceiver.descriptor]
|
val functionArgument = substituteMap[dispatchReceiver.symbol.owner] ?: return super.visitCall(expression)
|
||||||
if (functionArgument == null)
|
if ((dispatchReceiver.symbol.owner as? IrValueParameter)?.isNoinline == true)
|
||||||
return super.visitCall(expression)
|
return super.visitCall(expression)
|
||||||
val dispatchDescriptor = dispatchReceiver.descriptor
|
|
||||||
if (dispatchDescriptor is ValueParameterDescriptor &&
|
|
||||||
dispatchDescriptor.isNoinline
|
|
||||||
) return super.visitCall(expression)
|
|
||||||
|
|
||||||
if (functionArgument is IrFunctionReference) {
|
if (functionArgument is IrFunctionReference) {
|
||||||
if (!functionArgument.isLambda) return super.visitCall(expression)
|
val function = functionArgument.symbol.owner
|
||||||
|
val functionParameters = function.explicitParameters
|
||||||
val functionDescriptor = functionArgument.descriptor
|
val boundFunctionParameters = functionArgument.getArgumentsWithIr()
|
||||||
val functionParameters = functionDescriptor.explicitParameters
|
|
||||||
val boundFunctionParameters = functionArgument.getArguments()
|
|
||||||
val unboundFunctionParameters = functionParameters - boundFunctionParameters.map { it.first }
|
val unboundFunctionParameters = functionParameters - boundFunctionParameters.map { it.first }
|
||||||
val boundFunctionParametersMap = boundFunctionParameters.associate { it.first to it.second }
|
val boundFunctionParametersMap = boundFunctionParameters.associate { it.first to it.second }
|
||||||
|
|
||||||
var unboundIndex = 0
|
var unboundIndex = 0
|
||||||
val unboundArgsSet = unboundFunctionParameters.toSet()
|
val unboundArgsSet = unboundFunctionParameters.toSet()
|
||||||
val valueParameters = expression.getArguments().drop(1) // Skip dispatch receiver.
|
val valueParameters = expression.getArgumentsWithIr().drop(1) // Skip dispatch receiver.
|
||||||
|
|
||||||
val immediateCall = IrCallImpl(
|
val immediateCall = IrCallImpl(
|
||||||
startOffset = expression.startOffset,
|
expression.startOffset, expression.endOffset,
|
||||||
endOffset = expression.endOffset,
|
expression.type,
|
||||||
type = expression.type,
|
functionArgument.symbol
|
||||||
symbol = functionArgument.symbol,
|
|
||||||
descriptor = functionArgument.descriptor
|
|
||||||
).apply {
|
).apply {
|
||||||
functionParameters.forEach {
|
functionParameters.forEach {
|
||||||
val argument =
|
val argument =
|
||||||
if (!unboundArgsSet.contains(it))
|
if (it !in unboundArgsSet)
|
||||||
boundFunctionParametersMap[it]!!
|
boundFunctionParametersMap[it]!!
|
||||||
else
|
else
|
||||||
valueParameters[unboundIndex++].second
|
valueParameters.getOrNull(unboundIndex++)?.second
|
||||||
when (it) {
|
when (it) {
|
||||||
functionDescriptor.dispatchReceiverParameter -> this.dispatchReceiver = argument
|
function.dispatchReceiverParameter -> this.dispatchReceiver = argument
|
||||||
functionDescriptor.extensionReceiverParameter -> this.extensionReceiver = argument
|
function.extensionReceiverParameter -> this.extensionReceiver = argument
|
||||||
else -> putValueArgument((it as ValueParameterDescriptor).index, argument)
|
else -> putValueArgument(it.index, argument)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(unboundIndex == valueParameters.size) { "Not all arguments of <invoke> are used" }
|
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 this@FunctionInlining.visitCall(super.visitCall(immediateCall) as IrCall)
|
||||||
}
|
}
|
||||||
@@ -280,14 +267,8 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
|
|||||||
return super.visitCall(expression)
|
return super.visitCall(expression)
|
||||||
|
|
||||||
val functionDeclaration = functionArgument.statements[0] as IrFunction
|
val functionDeclaration = functionArgument.statements[0] as IrFunction
|
||||||
val newExpression = inlineFunction(
|
val newExpression = inlineFunction(expression, functionDeclaration) // Inline the lambda. Lambda parameters will be substituted with lambda arguments.
|
||||||
expression,
|
return newExpression.transform(this, null) // Substitute lambda arguments with target function arguments.
|
||||||
functionDeclaration
|
|
||||||
) // Inline the lambda. Lambda parameters will be substituted with lambda arguments.
|
|
||||||
return newExpression.transform(
|
|
||||||
this,
|
|
||||||
null
|
|
||||||
) // Substitute lambda arguments with target function arguments.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------//
|
//-----------------------------------------------------------------//
|
||||||
@@ -295,27 +276,33 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
|
|||||||
override fun visitElement(element: IrElement) = element.accept(this, null)
|
override fun visitElement(element: IrElement) = element.accept(this, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isLambdaCall(irCall: IrCall) = irCall.symbol.owner.isFunctionInvoke && irCall.dispatchReceiver is IrGetValue
|
private fun isLambdaCall(irCall: IrCall): Boolean {
|
||||||
|
val callee = irCall.symbol.owner
|
||||||
|
val dispatchReceiver = callee.dispatchReceiverParameter ?: return false
|
||||||
|
assert(!dispatchReceiver.type.isKFunction())
|
||||||
|
|
||||||
|
return (dispatchReceiver.type.isFunction() || dispatchReceiver.type.isSuspendFunction())
|
||||||
|
&& callee.name == OperatorNameConventions.INVOKE
|
||||||
|
&& irCall.dispatchReceiver is IrGetValue
|
||||||
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private inner class ParameterToArgument(
|
private fun IrValueParameter.isInlineParameter() =
|
||||||
val parameter: IrValueParameter,
|
!isNoinline && !type.isNullable() && type.isFunctionOrKFunction()
|
||||||
val argumentExpression: IrExpression
|
|
||||||
) {
|
private inner class ParameterToArgument(val parameter: IrValueParameter,
|
||||||
|
val argumentExpression: IrExpression) {
|
||||||
|
|
||||||
val isInlinableLambdaArgument: Boolean
|
val isInlinableLambdaArgument: Boolean
|
||||||
get() {
|
get() {
|
||||||
if (!InlineUtil.isInlineParameter(parameter.descriptor)) return false
|
if (!parameter.isInlineParameter()) return false
|
||||||
if (argumentExpression is IrFunctionReference
|
if (argumentExpression is IrFunctionReference) return true
|
||||||
&& !argumentExpression.descriptor.isSuspend
|
|
||||||
) return true // Skip suspend functions for now since it's not supported by FE anyway.
|
|
||||||
|
|
||||||
// Do pattern-matching on IR.
|
// Do pattern-matching on IR.
|
||||||
if (argumentExpression !is IrBlock) return false
|
if (argumentExpression !is IrBlock) return false
|
||||||
if (argumentExpression.origin != IrStatementOrigin.LAMBDA &&
|
if (argumentExpression.origin != IrStatementOrigin.LAMBDA &&
|
||||||
argumentExpression.origin != IrStatementOrigin.ANONYMOUS_FUNCTION
|
argumentExpression.origin != IrStatementOrigin.ANONYMOUS_FUNCTION) return false
|
||||||
) return false
|
|
||||||
val statements = argumentExpression.statements
|
val statements = argumentExpression.statements
|
||||||
val irFunction = statements[0]
|
val irFunction = statements[0]
|
||||||
val irCallableReference = statements[1]
|
val irCallableReference = statements[1]
|
||||||
@@ -326,7 +313,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
|
|||||||
|
|
||||||
val isImmutableVariableLoad: Boolean
|
val isImmutableVariableLoad: Boolean
|
||||||
get() = argumentExpression.let {
|
get() = argumentExpression.let {
|
||||||
it is IrGetValue && !it.symbol.owner.let { v -> v is IrVariable && v.isVar }
|
it is IrGetValue && !it.symbol.owner.let { it is IrVariable && it.isVar }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,15 +324,14 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
|
|||||||
val parameterToArgument = mutableListOf<ParameterToArgument>()
|
val parameterToArgument = mutableListOf<ParameterToArgument>()
|
||||||
|
|
||||||
if (callSite.dispatchReceiver != null && // Only if there are non null dispatch receivers both
|
if (callSite.dispatchReceiver != null && // Only if there are non null dispatch receivers both
|
||||||
callee.dispatchReceiverParameter != null
|
callee.dispatchReceiverParameter != null) // on call site and in function declaration.
|
||||||
) // on call site and in function declaration.
|
|
||||||
parameterToArgument += ParameterToArgument(
|
parameterToArgument += ParameterToArgument(
|
||||||
parameter = callee.dispatchReceiverParameter!!,
|
parameter = callee.dispatchReceiverParameter!!,
|
||||||
argumentExpression = callSite.dispatchReceiver!!
|
argumentExpression = callSite.dispatchReceiver!!
|
||||||
)
|
)
|
||||||
|
|
||||||
val valueArguments =
|
val valueArguments =
|
||||||
callSite.descriptor.valueParameters.map { callSite.getValueArgument(it) }.toMutableList()
|
callSite.symbol.owner.valueParameters.map { callSite.getValueArgument(it.index) }.toMutableList()
|
||||||
|
|
||||||
if (callee.extensionReceiverParameter != null) {
|
if (callee.extensionReceiverParameter != null) {
|
||||||
parameterToArgument += ParameterToArgument(
|
parameterToArgument += ParameterToArgument(
|
||||||
@@ -414,34 +400,25 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
|
|||||||
val evaluationStatements = mutableListOf<IrStatement>()
|
val evaluationStatements = mutableListOf<IrStatement>()
|
||||||
val substitutor = ParameterSubstitutor()
|
val substitutor = ParameterSubstitutor()
|
||||||
parameterToArgumentOld.forEach {
|
parameterToArgumentOld.forEach {
|
||||||
val parameterDescriptor = it.parameter.descriptor
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to create temporary variable for each argument except inlinable lambda arguments.
|
* 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,
|
* For simplicity and to produce simpler IR we don't create temporaries for every immutable variable,
|
||||||
* not only for those referring to inlinable lambdas.
|
* not only for those referring to inlinable lambdas.
|
||||||
*/
|
*/
|
||||||
if (it.isInlinableLambdaArgument) {
|
if (it.isInlinableLambdaArgument) {
|
||||||
substituteMap[parameterDescriptor] = it.argumentExpression
|
substituteMap[it.parameter] = it.argumentExpression
|
||||||
return@forEach
|
return@forEach
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it.isImmutableVariableLoad) {
|
if (it.isImmutableVariableLoad) {
|
||||||
substituteMap[parameterDescriptor] = it.argumentExpression.transform(
|
substituteMap[it.parameter] = it.argumentExpression.transform(substitutor, data = null) // Arguments may reference the previous ones - substitute them.
|
||||||
substitutor,
|
|
||||||
data = null
|
|
||||||
) // Arguments may reference the previous ones - substitute them.
|
|
||||||
return@forEach
|
return@forEach
|
||||||
}
|
}
|
||||||
|
|
||||||
val newVariable = currentScope.scope.createTemporaryVariable(
|
val newVariable = currentScope.scope.createTemporaryVariableWithWrappedDescriptor( // Create new variable and init it with the parameter expression.
|
||||||
irExpression = it.argumentExpression.transform(
|
irExpression = it.argumentExpression.transform(substitutor, data = null), // Arguments may reference the previous ones - substitute them.
|
||||||
substitutor,
|
nameHint = callee.symbol.owner.name.toString(),
|
||||||
data = null
|
isMutable = false)
|
||||||
), // Arguments may reference the previous ones - substitute them.
|
|
||||||
nameHint = callee.descriptor.name.toString(),
|
|
||||||
isMutable = false
|
|
||||||
)
|
|
||||||
|
|
||||||
evaluationStatements.add(newVariable)
|
evaluationStatements.add(newVariable)
|
||||||
val getVal = IrGetValueImpl(
|
val getVal = IrGetValueImpl(
|
||||||
@@ -450,7 +427,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
|
|||||||
type = newVariable.type,
|
type = newVariable.type,
|
||||||
symbol = newVariable.symbol
|
symbol = newVariable.symbol
|
||||||
)
|
)
|
||||||
substituteMap[parameterDescriptor] = getVal
|
substituteMap[it.parameter] = getVal
|
||||||
}
|
}
|
||||||
return evaluationStatements
|
return evaluationStatements
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
// IGNORE_BACKEND: JVM_IR, JS_IR
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
// COMMON_COROUTINES_TEST
|
// COMMON_COROUTINES_TEST
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
// !LANGUAGE: +NewInference
|
// !LANGUAGE: +NewInference
|
||||||
// IGNORE_BACKEND: NATIVE
|
// IGNORE_BACKEND: NATIVE
|
||||||
// IGNORE_BACKEND: JVM_IR
|
// IGNORE_BACKEND: JVM_IR
|
||||||
// IGNORE_BACKEND: JS, JS_IR
|
// IGNORE_BACKEND: JS
|
||||||
// NO_CHECK_LAMBDA_INLINING
|
// NO_CHECK_LAMBDA_INLINING
|
||||||
// FILE: test.kt
|
// FILE: test.kt
|
||||||
// We cannot use COMMON_COROUTINES_TEST here due to !LANGUAGE directive
|
// We cannot use COMMON_COROUTINES_TEST here due to !LANGUAGE directive
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
// !LANGUAGE: +NewInference
|
// !LANGUAGE: +NewInference
|
||||||
// IGNORE_BACKEND: NATIVE
|
// IGNORE_BACKEND: NATIVE
|
||||||
// IGNORE_BACKEND: JVM_IR
|
// IGNORE_BACKEND: JVM_IR
|
||||||
// IGNORE_BACKEND: JS, JS_IR
|
// IGNORE_BACKEND: JS
|
||||||
// NO_CHECK_LAMBDA_INLINING
|
// NO_CHECK_LAMBDA_INLINING
|
||||||
// FILE: test.kt
|
// FILE: test.kt
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user