Proper resort variables on inlining lowered ir closures

Original problem is that lowered ir closures doesn't meet inliner expectations
 about captured variable position in inlining method.
 E.g.: Call 'foo(valueParam) { capturedParam }' to
  inline function 'foo' with declaration

      inline fun foo(valueParam: Foo, inlineParamWithCaptured: Bar.() ->) ....

 is reorganized through inlining to equivalent call foo(valueParam, capturedParam1, cp2 ...).
 But lowered closure for lambda parameter has totally different parameters order:

     fun loweredLambda$x(extensionReceiver, captured1, cp2..., valueParam1, vp2...)

 So before inlining lowered closure should be transformed to

     fun loweredLambda$x(extensionReceiver, valueParam1, vp2..., captured1, cp2..)

 #KT-28547 Fixed
This commit is contained in:
Mikhael Bogdanov
2019-01-02 14:00:43 +01:00
parent fcf8ea44b2
commit 02d9c526e2
19 changed files with 135 additions and 35 deletions
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.backend.jvm.codegen
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
import org.jetbrains.kotlin.codegen.Callable
import org.jetbrains.kotlin.codegen.JvmKotlinType
import org.jetbrains.kotlin.codegen.StackValue
@@ -34,9 +35,8 @@ class IrInlineCodegen(
val lambdaInfo = next as IrExpressionLambda
activeLambda = lambdaInfo
val argumentTypes = lambdaInfo.loweredMethod.argumentTypes
lambdaInfo.reference.getArguments().forEachIndexed { index, (_, ir) ->
putCapturedValueOnStack(ir, argumentTypes[index], index)
putCapturedValueOnStack(ir, lambdaInfo.capturedParamsInDesc[index], index)
}
activeLambda = null
}
@@ -70,10 +70,10 @@ class IrInlineCodegen(
putArgumentOrCapturedToLocalVal(JvmKotlinType(value.type, value.kotlinType), value, -1, parameterIndex, ValueKind.CAPTURED /*kind*/)
}
private fun putCapturedValueOnStack(argumentExpression: IrExpression, valueType: Type, capturedParamindex: Int) {
private fun putCapturedValueOnStack(argumentExpression: IrExpression, valueType: Type, capturedParamIndex: Int) {
val onStack = codegen.gen(argumentExpression, valueType, BlockInfo.create())
putArgumentOrCapturedToLocalVal(
JvmKotlinType(onStack.type, onStack.kotlinType), onStack, capturedParamindex, capturedParamindex, ValueKind.CAPTURED
JvmKotlinType(onStack.type, onStack.kotlinType), onStack, capturedParamIndex, capturedParamIndex, ValueKind.CAPTURED
)
}
@@ -93,10 +93,10 @@ class IrInlineCodegen(
private fun rememberClosure(irReference: IrFunctionReference, type: Type, parameter: ValueParameterDescriptor): LambdaInfo {
//assert(InlineUtil.isInlinableParameterExpression(ktLambda)) { "Couldn't find inline expression in ${expression.text}" }
val expression = irReference.symbol.owner as IrFunction
return IrExpressionLambda(
irReference, expression, typeMapper, parameter.isCrossinline, false/*TODO*/
irReference, expression, typeMapper, parameter.isCrossinline, false/*TODO*/,
parameter.type.isExtensionFunctionType
).also { lambda ->
val closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameter.index)
closureInfo.lambda = lambda
@@ -110,7 +110,8 @@ class IrExpressionLambda(
val function: IrFunction,
typeMapper: KotlinTypeMapper,
isCrossInline: Boolean,
override val isBoundCallableReference: Boolean
override val isBoundCallableReference: Boolean,
val isExtensionLambda: Boolean
) : ExpressionLambda(typeMapper, isCrossInline) {
override fun isMyLabel(name: String): Boolean {
@@ -118,30 +119,35 @@ class IrExpressionLambda(
return false
}
override val lambdaClassType: Type
get() = Type.getObjectType("test123")
override val lambdaClassType: Type = Type.getObjectType("test123")
override val capturedVars: List<CapturedParamDesc> by lazy {
override val capturedVars: List<CapturedParamDesc> =
arrayListOf<CapturedParamDesc>().apply {
reference.getArguments().forEachIndexed { _, (_, ir) ->
val getValue = ir as? IrGetValue ?: error("Unrecognized expression: $ir")
add(capturedParamDesc(getValue.descriptor.name.asString(), typeMapper.mapType(getValue.descriptor.type)))
}
}
}
val loweredMethod: Method
get() = typeMapper.mapAsmMethod(function.descriptor)
private val loweredMethod = typeMapper.mapAsmMethod(function.descriptor)
val capturedParamsInDesc: List<Type> =
loweredMethod.argumentTypes.drop(if (isExtensionLambda) 1 else 0).take(capturedVars.size)
override val invokeMethod: Method = loweredMethod.let {
Method(it.name, it.returnType, it.argumentTypes.drop(capturedVars.size).toTypedArray())
Method(
it.name,
it.returnType,
(
(if (isExtensionLambda) it.argumentTypes.take(1) else emptyList()) +
it.argumentTypes.drop((if (isExtensionLambda) 1 else 0) + capturedVars.size)
).toTypedArray()
)
}
override val invokeMethodDescriptor: FunctionDescriptor
get() = function.descriptor
override val invokeMethodDescriptor: FunctionDescriptor = function.descriptor
override val hasDispatchReceiver: Boolean
get() = false
override val hasDispatchReceiver: Boolean = false
}
fun isInlineIrExpression(argumentExpression: IrExpression) =