From 614d52916891ccfcc6ba799518c1fa7fba621897 Mon Sep 17 00:00:00 2001 From: pyos Date: Mon, 10 May 2021 17:22:28 +0200 Subject: [PATCH] JVM: remove LambdaInfo.invokeMethodDescriptor --- .../kotlin/codegen/inline/LambdaInfo.kt | 64 ++++++++++++------- .../kotlin/codegen/inline/MethodInliner.kt | 52 ++++++--------- .../backend/jvm/codegen/IrInlineCodegen.kt | 54 ++++++++-------- 3 files changed, 86 insertions(+), 84 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt index e20441fa587..85555f4a191 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt @@ -47,7 +47,9 @@ abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : FunctionalArgu abstract val invokeMethod: Method - abstract val invokeMethodDescriptor: FunctionDescriptor + abstract val invokeMethodParameters: List + + abstract val invokeMethodReturnType: KotlinType? abstract val capturedVars: List @@ -98,14 +100,16 @@ class PsiDefaultLambda( offset: Int, needReification: Boolean ) : DefaultLambda(lambdaClassType, capturedArgs, parameterDescriptor, offset, needReification) { - override fun mapAsmSignature(sourceCompiler: SourceCompilerForInline): Method { - return sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod - } + override fun mapAsmSignature(sourceCompiler: SourceCompilerForInline, descriptor: FunctionDescriptor): Method = + sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(descriptor).asmMethod - override fun findInvokeMethodDescriptor(): FunctionDescriptor = + override fun findInvokeMethodDescriptor(isPropertyReference: Boolean): FunctionDescriptor = parameterDescriptor.type.memberScope .getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND) - .single() + .single().let { + // property reference generates erased 'get' method + if (isPropertyReference) it.original else it + } } abstract class DefaultLambda( @@ -124,7 +128,13 @@ abstract class DefaultLambda( final override lateinit var invokeMethod: Method private set - override lateinit var invokeMethodDescriptor: FunctionDescriptor + private lateinit var invokeMethodDescriptor: FunctionDescriptor + + override val invokeMethodParameters: List + get() = invokeMethodDescriptor.valueParameters.map { it.returnType } // should be FunctionN, so no extension receiver + + override val invokeMethodReturnType: KotlinType? + get() = invokeMethodDescriptor.returnType final override lateinit var capturedVars: List private set @@ -155,10 +165,7 @@ abstract class DefaultLambda( } }, ClassReader.SKIP_CODE or ClassReader.SKIP_FRAMES or ClassReader.SKIP_DEBUG) - invokeMethodDescriptor = findInvokeMethodDescriptor().let { - //property reference generates erased 'get' method - if (isPropertyReference) it.original else it - } + invokeMethodDescriptor = findInvokeMethodDescriptor(isPropertyReference) val descriptor = Type.getMethodDescriptor(Type.VOID_TYPE, *capturedArgs) val constructor = getMethodNode(classBytes, "", descriptor, lambdaClassType)?.node @@ -182,7 +189,7 @@ abstract class DefaultLambda( val methodName = (if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString() - val signature = mapAsmSignature(sourceCompiler) + val signature = mapAsmSignature(sourceCompiler, invokeMethodDescriptor) node = getMethodNode(classBytes, methodName, signature.descriptor, lambdaClassType, signatureAmbiguity = true) ?: error("Can't find method '$methodName$signature' in '${classReader.className}'") @@ -195,9 +202,10 @@ abstract class DefaultLambda( } } - protected abstract fun mapAsmSignature(sourceCompiler: SourceCompilerForInline): Method + protected abstract fun mapAsmSignature(sourceCompiler: SourceCompilerForInline, descriptor: FunctionDescriptor): Method - protected abstract fun findInvokeMethodDescriptor(): FunctionDescriptor + // TODO: get rid of this; descriptors should *only* be used by PsiDefaultLambda + protected abstract fun findInvokeMethodDescriptor(isPropertyReference: Boolean): FunctionDescriptor private companion object { val PROPERTY_REFERENCE_SUPER_CLASSES = @@ -221,7 +229,6 @@ abstract class ExpressionLambda(isCrossInline: Boolean) : LambdaInfo(isCrossInli node.node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false) } - abstract fun getInlineSuspendLambdaViewDescriptor(): FunctionDescriptor abstract fun isCapturedSuspend(desc: CapturedParamDesc): Boolean } @@ -237,7 +244,24 @@ class PsiExpressionLambda( override val invokeMethod: Method - override val invokeMethodDescriptor: FunctionDescriptor + val invokeMethodDescriptor: FunctionDescriptor + + override val invokeMethodParameters: List + get() { + val actualInvokeDescriptor = if (isSuspend) + getOrCreateJvmSuspendFunctionView( + invokeMethodDescriptor, + languageVersionSettings.isReleaseCoroutines(), + typeMapper.bindingContext + ) + else + invokeMethodDescriptor + val valueParameters = actualInvokeDescriptor.valueParameters.map { it.returnType } + return actualInvokeDescriptor.extensionReceiverParameter?.let { listOf(it.returnType) + valueParameters } ?: valueParameters + } + + override val invokeMethodReturnType: KotlinType? + get() = invokeMethodDescriptor.returnType val classDescriptor: ClassDescriptor @@ -325,14 +349,6 @@ class PsiExpressionLambda( val isPropertyReference: Boolean get() = propertyReferenceInfo != null - override fun getInlineSuspendLambdaViewDescriptor(): FunctionDescriptor { - return getOrCreateJvmSuspendFunctionView( - invokeMethodDescriptor, - languageVersionSettings.isReleaseCoroutines(), - typeMapper.bindingContext - ) - } - override fun isCapturedSuspend(desc: CapturedParamDesc): Boolean = isCapturedSuspendLambda(closure, desc.fieldName, typeMapper.bindingContext) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt index 40973307857..972a404d3d5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt @@ -23,13 +23,13 @@ import org.jetbrains.kotlin.codegen.optimization.fixStack.top import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNotNull import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.ParameterDescriptor -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.load.java.JvmAbi +import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.SmartSet import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -233,38 +233,24 @@ class MethodInliner( return } - // in case of inlining suspend lambda reference as ordinary parameter of inline function: - // suspend fun foo (...) ... - // inline fun inlineMe(c: (...) -> ...) ... - // builder { - // inlineMe(::foo) - // } - // we should create additional parameter for continuation. + val valueParameters = info.invokeMethodParameters + // If suspend lambda has no continuation at the end, add it here. (In the IR backend, suspend lambdas + // always come pre-lowered with the continuation parameter.) var coroutineDesc = desc - val actualInvokeDescriptor: FunctionDescriptor - if (info.isSuspend) { - actualInvokeDescriptor = (info as ExpressionLambda).getInlineSuspendLambdaViewDescriptor() - val parametersSize = actualInvokeDescriptor.valueParameters.size + - (if (actualInvokeDescriptor.extensionReceiverParameter != null) 1 else 0) - // And here we expect invoke(...Ljava/lang/Object;) be replaced with invoke(...Lkotlin/coroutines/Continuation;) - // if this does not happen, insert fake continuation, since we could not have one yet. + if (!inliningContext.root.state.isIrBackend && info.isSuspend) { val argumentTypes = Type.getArgumentTypes(desc) - if (argumentTypes.size != parametersSize && - // But do not add it in IR. In IR we already have lowered lambdas with additional parameter, while in Old BE we don't. - !inliningContext.root.state.isIrBackend - ) { + if (argumentTypes.size != valueParameters.size) { addFakeContinuationMarker(this) coroutineDesc = Type.getMethodDescriptor(Type.getReturnType(desc), *argumentTypes, AsmTypes.OBJECT_TYPE) } - } else { - actualInvokeDescriptor = info.invokeMethodDescriptor } - val valueParameters = - listOfNotNull(actualInvokeDescriptor.extensionReceiverParameter) + actualInvokeDescriptor.valueParameters - - val erasedInvokeFunction = ClosureCodegen.getErasedInvokeFunction(actualInvokeDescriptor) - val invokeParameters = erasedInvokeFunction.valueParameters + // TODO: this is a weird way to get N instances of `Any?` + val moduleBuiltIns = inliningContext.root.sourceCompilerForInline.compilationContextDescriptor.builtIns + val erasedFunctionType = moduleBuiltIns.getFunction(valueParameters.size).defaultType + val erasedInvokeFunction = erasedFunctionType.memberScope + .getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND).first() + val invokeParameters = erasedInvokeFunction.valueParameters.map { it.returnType } val valueParamShift = max(nextLocalIndex, markerShift)//NB: don't inline cause it changes val parameterTypesFromDesc = info.invokeMethod.argumentTypes @@ -305,7 +291,7 @@ class MethodInliner( result.reifiedTypeParametersUsages.mergeAll(lambdaResult.reifiedTypeParametersUsages) StackValue - .onStack(info.invokeMethod.returnType, info.invokeMethodDescriptor.returnType) + .onStack(info.invokeMethod.returnType, info.invokeMethodReturnType) .put(OBJECT_TYPE, erasedInvokeFunction.returnType, this) setLambdaInlining(false) addInlineMarker(this, false) @@ -1075,8 +1061,8 @@ class MethodInliner( private fun putStackValuesIntoLocalsForLambdaOnInvoke( directOrder: List, - directOrderOfArguments: List, - directOrderOfInvokeParameters: List, + directOrderOfArguments: List, + directOrderOfInvokeParameters: List, shift: Int, iv: InstructionAdapter, descriptor: String @@ -1099,8 +1085,8 @@ class MethodInliner( val argumentKotlinType: KotlinType? val invokeParameterKotlinType: KotlinType? if (safeToUseArgumentKotlinType) { - argumentKotlinType = directOrderOfArguments[index].type - invokeParameterKotlinType = directOrderOfInvokeParameters[index].type + argumentKotlinType = directOrderOfArguments[index] + invokeParameterKotlinType = directOrderOfInvokeParameters[index] } else { argumentKotlinType = null invokeParameterKotlinType = null diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt index 872a4fe4834..68217d80f17 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt @@ -20,11 +20,11 @@ import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.descriptors.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.Method @@ -201,27 +201,30 @@ class IrExpressionLambdaImpl( private val loweredMethod = codegen.methodSignatureMapper.mapAsmMethod(function) - val capturedParamsInDesc: List = if (isBoundCallableReference) { - loweredMethod.argumentTypes.take(1) - } else loweredMethod.argumentTypes.drop(if (isExtensionLambda) 1 else 0).take(capturedVars.size) - - override val invokeMethod: Method = loweredMethod.let { - Method( - it.name, - it.returnType, - (if (isBoundCallableReference) it.argumentTypes.drop(1) - else (if (isExtensionLambda) it.argumentTypes.take(1) else emptyList()) + - it.argumentTypes.drop((if (isExtensionLambda) 1 else 0) + capturedVars.size)).toTypedArray() - ) + val capturedParamsInDesc: List = when { + isBoundCallableReference -> loweredMethod.argumentTypes.take(1) + isExtensionLambda -> loweredMethod.argumentTypes.drop(1).take(capturedVars.size) + else -> loweredMethod.argumentTypes.take(capturedVars.size) } - // Need the descriptor without captured parameters here. - override val invokeMethodDescriptor: FunctionDescriptor = function.originalFunction.toIrBasedDescriptor() + override val invokeMethod: Method = loweredMethod.let { + val nonCapturedParameters = when { + isBoundCallableReference -> it.argumentTypes.drop(1) + isExtensionLambda -> it.argumentTypes.take(1) + it.argumentTypes.drop(capturedVars.size + 1) + else -> it.argumentTypes.drop(capturedVars.size) + }.toTypedArray() + Method(it.name, it.returnType, nonCapturedParameters) + } + + // TODO: no extension receiver if bound + override val invokeMethodParameters: List + get() = function.originalFunction.explicitParameters.map { it.type.toIrBasedKotlinType() } + + override val invokeMethodReturnType: KotlinType + get() = function.originalFunction.returnType.toIrBasedKotlinType() // not including COROUTINE_SUSPENDED override val hasDispatchReceiver: Boolean = false - override fun getInlineSuspendLambdaViewDescriptor(): FunctionDescriptor = function.toIrBasedDescriptor() - override fun isCapturedSuspend(desc: CapturedParamDesc): Boolean = capturedParameters[desc]?.let { it.isInlineParameter() && it.type.isSuspendFunctionTypeOrSubtype() } == true } @@ -229,23 +232,20 @@ class IrExpressionLambdaImpl( class IrDefaultLambda( lambdaClassType: Type, capturedArgs: Array, - private val irValueParameter: IrValueParameter, + irValueParameter: IrValueParameter, offset: Int, needReification: Boolean ) : DefaultLambda( lambdaClassType, capturedArgs, irValueParameter.toIrBasedDescriptor() as ValueParameterDescriptor, offset, needReification ) { + private val invoke = + (irValueParameter.type.classifierOrFail.owner as IrClass).functions.single { it.name == OperatorNameConventions.INVOKE } - override fun mapAsmSignature(sourceCompiler: SourceCompilerForInline): Method { - val invoke = - irValueParameter.type.classOrNull!!.owner.declarations.filterIsInstance().single { it.name.asString() == "invoke" } - return (sourceCompiler as IrSourceCompilerForInline).codegen.context.methodSignatureMapper.mapSignatureSkipGeneric(invoke).asmMethod - } + override fun mapAsmSignature(sourceCompiler: SourceCompilerForInline, descriptor: FunctionDescriptor): Method = + (sourceCompiler as IrSourceCompilerForInline).codegen.context.methodSignatureMapper.mapSignatureSkipGeneric(invoke).asmMethod - override fun findInvokeMethodDescriptor(): FunctionDescriptor = - (irValueParameter.type.classifierOrFail.owner as IrClass).functions.single { - it.name == OperatorNameConventions.INVOKE - }.toIrBasedDescriptor() + override fun findInvokeMethodDescriptor(isPropertyReference: Boolean): FunctionDescriptor = + invoke.toIrBasedDescriptor() } fun IrExpression.isInlineIrExpression() =