From ad8b7ff6450e01349dffddc42674ce7d896d09a1 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 28 Aug 2019 15:29:02 +0200 Subject: [PATCH] Minor, extract PsiInlineCodegen to a separate file --- .../kotlin/codegen/inline/InlineCodegen.kt | 167 ---------------- .../kotlin/codegen/inline/PsiInlineCodegen.kt | 182 ++++++++++++++++++ 2 files changed, 182 insertions(+), 167 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt index da4629c759e..c708051c998 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -10,35 +10,24 @@ import com.intellij.util.ArrayUtil import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.isSuspendFunctionTypeOrSubtype import org.jetbrains.kotlin.codegen.* -import org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive -import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.context.ClosureContext import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructors import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper -import org.jetbrains.kotlin.config.isReleaseCoroutines import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.psi.KtCallableReferenceExpression -import org.jetbrains.kotlin.psi.KtExpression -import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor -import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.inline.InlineUtil -import org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlinableParameterExpression import org.jetbrains.kotlin.resolve.inline.isInlineOnly -import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature -import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.scopes.MemberScope -import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral @@ -705,159 +694,3 @@ abstract class InlineCodegen( val BaseExpressionCodegen.v: InstructionAdapter get() = visitor - -class PsiInlineCodegen( - codegen: ExpressionCodegen, - state: GenerationState, - function: FunctionDescriptor, - typeParameterMappings: TypeParameterMappings, - sourceCompiler: SourceCompilerForInline -) : InlineCodegen(codegen, state, function, typeParameterMappings, sourceCompiler), CallGenerator { - - override fun generateAssertFieldIfNeeded(info: RootInliningContext) { - if (info.generateAssertField) { - codegen.parentCodegen.generateAssertField() - } - } - - override fun genCallInner( - callableMethod: Callable, - resolvedCall: ResolvedCall<*>?, - callDefault: Boolean, - codegen: ExpressionCodegen - ) { - if (!state.globalInlineContext.enterIntoInlining(resolvedCall)) { - generateStub(resolvedCall, codegen) - return - } - try { - performInline(resolvedCall?.typeArguments, callDefault, codegen) - } finally { - state.globalInlineContext.exitFromInliningOf(resolvedCall) - } - } - - override fun processAndPutHiddenParameters(justProcess: Boolean) { - if (getMethodAsmFlags(functionDescriptor, sourceCompiler.contextKind, state) and Opcodes.ACC_STATIC == 0) { - invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false) - } - - for (param in jvmSignature.valueParameters) { - if (param.kind == JvmMethodParameterKind.VALUE) { - break - } - invocationParamBuilder.addNextParameter(param.asmType, false) - } - - invocationParamBuilder.markValueParametersStart() - val hiddenParameters = invocationParamBuilder.buildParameters().parameters - - delayedHiddenWriting = recordParameterValueInLocalVal(justProcess, false, *hiddenParameters.toTypedArray()) - } - - override fun putClosureParametersOnStack(next: LambdaInfo, functionReferenceReceiver: StackValue?) { - activeLambda = next - when (next) { - is PsiExpressionLambda -> codegen.pushClosureOnStack(next.classDescriptor, true, this, functionReferenceReceiver) - is DefaultLambda -> rememberCapturedForDefaultLambda(next) - else -> throw RuntimeException("Unknown lambda: $next") - } - activeLambda = null - } - - private fun getBoundCallableReferenceReceiver(argumentExpression: KtExpression): ReceiverValue? { - val deparenthesized = KtPsiUtil.deparenthesize(argumentExpression) as? KtCallableReferenceExpression ?: return null - val resolvedCall = deparenthesized.callableReference.getResolvedCallWithAssert(state.bindingContext) - return JvmCodegenUtil.getBoundCallableReferenceReceiver(resolvedCall) - } - - /*lambda or callable reference*/ - private fun isInliningParameter(expression: KtExpression, valueParameterDescriptor: ValueParameterDescriptor): Boolean { - //TODO deparenthisise typed - val deparenthesized = KtPsiUtil.deparenthesize(expression) - - return InlineUtil.isInlineParameter(valueParameterDescriptor) && isInlinableParameterExpression(deparenthesized) - } - - override fun genValueAndPut( - valueParameterDescriptor: ValueParameterDescriptor?, - argumentExpression: KtExpression, - parameterType: JvmKotlinType, - parameterIndex: Int - ) { - requireNotNull(valueParameterDescriptor) { - "Parameter descriptor can only be null in case a @PolymorphicSignature function is called, " + - "which cannot be declared in Kotlin and thus be inline: $codegen" - } - - if (isInliningParameter(argumentExpression, valueParameterDescriptor)) { - val lambdaInfo = rememberClosure(argumentExpression, parameterType.type, valueParameterDescriptor) - - val receiverValue = getBoundCallableReferenceReceiver(argumentExpression) - if (receiverValue != null) { - val receiver = codegen.generateReceiverValue(receiverValue, false) - val receiverKotlinType = receiver.kotlinType - val boxedReceiver = - if (receiverKotlinType != null) - receiver.type.boxReceiverForBoundReference(receiverKotlinType, state.typeMapper) - else - receiver.type.boxReceiverForBoundReference() - - putClosureParametersOnStack( - lambdaInfo, - StackValue.coercion(receiver, boxedReceiver, receiverKotlinType) - ) - } - } else { - val value = codegen.gen(argumentExpression) - val kind = when { - isCallSiteIsSuspend(valueParameterDescriptor) -> ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND - isInlineSuspendParameter(valueParameterDescriptor) -> ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER - else -> ValueKind.GENERAL - } - putValueIfNeeded(parameterType, value, kind, parameterIndex) - } - } - - private fun isInlineSuspendParameter(descriptor: ValueParameterDescriptor): Boolean = - functionDescriptor.isInline && !descriptor.isNoinline && descriptor.type.isSuspendFunctionTypeOrSubtype - - private fun isCallSiteIsSuspend(descriptor: ValueParameterDescriptor): Boolean = - state.bindingContext[CodegenBinding.CALL_SITE_IS_SUSPEND_FOR_CROSSINLINE_LAMBDA, descriptor] == true - - private fun rememberClosure(expression: KtExpression, type: Type, parameter: ValueParameterDescriptor): LambdaInfo { - val ktLambda = KtPsiUtil.deparenthesize(expression) - assert(isInlinableParameterExpression(ktLambda)) { "Couldn't find inline expression in ${expression.text}" } - - return PsiExpressionLambda( - ktLambda!!, typeMapper, state.languageVersionSettings, - parameter.isCrossinline, getBoundCallableReferenceReceiver(expression) != null - ).also { lambda -> - val closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameter.index) - closureInfo.functionalArgument = lambda - expressionMap.put(closureInfo.index, lambda) - } - } - - override fun putValueIfNeeded(parameterType: JvmKotlinType, value: StackValue, kind: ValueKind, parameterIndex: Int) { - if (processDefaultMaskOrMethodHandler(value, kind)) return - - assert(maskValues.isEmpty()) { "Additional default call arguments should be last ones, but " + value } - - putArgumentOrCapturedToLocalVal(parameterType, value, -1, parameterIndex, kind) - } - - override fun putCapturedValueOnStack(stackValue: StackValue, valueType: Type, paramIndex: Int) { - putArgumentOrCapturedToLocalVal( - JvmKotlinType(stackValue.type, stackValue.kotlinType), stackValue, paramIndex, paramIndex, ValueKind.CAPTURED - ) - } - - override fun reorderArgumentsIfNeeded(actualArgsWithDeclIndex: List, valueParameterTypes: List) = Unit - - override fun putHiddenParamsIntoLocals() { - assert(delayedHiddenWriting != null) { "processAndPutHiddenParameters(true) should be called before putHiddenParamsIntoLocals" } - delayedHiddenWriting!!.invoke() - delayedHiddenWriting = null - } -} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt new file mode 100644 index 00000000000..0ba094dcb06 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt @@ -0,0 +1,182 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.codegen.inline + +import org.jetbrains.kotlin.builtins.isSuspendFunctionTypeOrSubtype +import org.jetbrains.kotlin.codegen.* +import org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags +import org.jetbrains.kotlin.codegen.binding.CodegenBinding +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.psi.KtCallableReferenceExpression +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtPsiUtil +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.inline.InlineUtil +import org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlinableParameterExpression +import org.jetbrains.kotlin.resolve.jvm.AsmTypes +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.org.objectweb.asm.Opcodes +import org.jetbrains.org.objectweb.asm.Type + +class PsiInlineCodegen( + codegen: ExpressionCodegen, + state: GenerationState, + function: FunctionDescriptor, + typeParameterMappings: TypeParameterMappings, + sourceCompiler: SourceCompilerForInline +) : InlineCodegen(codegen, state, function, typeParameterMappings, sourceCompiler), CallGenerator { + + override fun generateAssertFieldIfNeeded(info: RootInliningContext) { + if (info.generateAssertField) { + codegen.parentCodegen.generateAssertField() + } + } + + override fun genCallInner( + callableMethod: Callable, + resolvedCall: ResolvedCall<*>?, + callDefault: Boolean, + codegen: ExpressionCodegen + ) { + if (!state.globalInlineContext.enterIntoInlining(resolvedCall)) { + generateStub(resolvedCall, codegen) + return + } + try { + performInline(resolvedCall?.typeArguments, callDefault, codegen) + } finally { + state.globalInlineContext.exitFromInliningOf(resolvedCall) + } + } + + override fun processAndPutHiddenParameters(justProcess: Boolean) { + if (getMethodAsmFlags(functionDescriptor, sourceCompiler.contextKind, state) and Opcodes.ACC_STATIC == 0) { + invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false) + } + + for (param in jvmSignature.valueParameters) { + if (param.kind == JvmMethodParameterKind.VALUE) { + break + } + invocationParamBuilder.addNextParameter(param.asmType, false) + } + + invocationParamBuilder.markValueParametersStart() + val hiddenParameters = invocationParamBuilder.buildParameters().parameters + + delayedHiddenWriting = recordParameterValueInLocalVal(justProcess, false, *hiddenParameters.toTypedArray()) + } + + override fun putClosureParametersOnStack(next: LambdaInfo, functionReferenceReceiver: StackValue?) { + activeLambda = next + when (next) { + is PsiExpressionLambda -> codegen.pushClosureOnStack(next.classDescriptor, true, this, functionReferenceReceiver) + is DefaultLambda -> rememberCapturedForDefaultLambda(next) + else -> throw RuntimeException("Unknown lambda: $next") + } + activeLambda = null + } + + private fun getBoundCallableReferenceReceiver(argumentExpression: KtExpression): ReceiverValue? { + val deparenthesized = KtPsiUtil.deparenthesize(argumentExpression) as? KtCallableReferenceExpression ?: return null + val resolvedCall = deparenthesized.callableReference.getResolvedCallWithAssert(state.bindingContext) + return JvmCodegenUtil.getBoundCallableReferenceReceiver(resolvedCall) + } + + /*lambda or callable reference*/ + private fun isInliningParameter(expression: KtExpression, valueParameterDescriptor: ValueParameterDescriptor): Boolean { + //TODO deparenthesize typed + val deparenthesized = KtPsiUtil.deparenthesize(expression) + + return InlineUtil.isInlineParameter(valueParameterDescriptor) && isInlinableParameterExpression(deparenthesized) + } + + override fun genValueAndPut( + valueParameterDescriptor: ValueParameterDescriptor?, + argumentExpression: KtExpression, + parameterType: JvmKotlinType, + parameterIndex: Int + ) { + requireNotNull(valueParameterDescriptor) { + "Parameter descriptor can only be null in case a @PolymorphicSignature function is called, " + + "which cannot be declared in Kotlin and thus be inline: $codegen" + } + + if (isInliningParameter(argumentExpression, valueParameterDescriptor)) { + val lambdaInfo = rememberClosure(argumentExpression, parameterType.type, valueParameterDescriptor) + + val receiverValue = getBoundCallableReferenceReceiver(argumentExpression) + if (receiverValue != null) { + val receiver = codegen.generateReceiverValue(receiverValue, false) + val receiverKotlinType = receiver.kotlinType + val boxedReceiver = + if (receiverKotlinType != null) + receiver.type.boxReceiverForBoundReference(receiverKotlinType, state.typeMapper) + else + receiver.type.boxReceiverForBoundReference() + + putClosureParametersOnStack( + lambdaInfo, + StackValue.coercion(receiver, boxedReceiver, receiverKotlinType) + ) + } + } else { + val value = codegen.gen(argumentExpression) + val kind = when { + isCallSiteIsSuspend(valueParameterDescriptor) -> ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND + isInlineSuspendParameter(valueParameterDescriptor) -> ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER + else -> ValueKind.GENERAL + } + putValueIfNeeded(parameterType, value, kind, parameterIndex) + } + } + + private fun isInlineSuspendParameter(descriptor: ValueParameterDescriptor): Boolean = + functionDescriptor.isInline && !descriptor.isNoinline && descriptor.type.isSuspendFunctionTypeOrSubtype + + private fun isCallSiteIsSuspend(descriptor: ValueParameterDescriptor): Boolean = + state.bindingContext[CodegenBinding.CALL_SITE_IS_SUSPEND_FOR_CROSSINLINE_LAMBDA, descriptor] == true + + private fun rememberClosure(expression: KtExpression, type: Type, parameter: ValueParameterDescriptor): LambdaInfo { + val ktLambda = KtPsiUtil.deparenthesize(expression) + assert(isInlinableParameterExpression(ktLambda)) { "Couldn't find inline expression in ${expression.text}" } + + return PsiExpressionLambda( + ktLambda!!, typeMapper, state.languageVersionSettings, + parameter.isCrossinline, getBoundCallableReferenceReceiver(expression) != null + ).also { lambda -> + val closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameter.index) + closureInfo.functionalArgument = lambda + expressionMap[closureInfo.index] = lambda + } + } + + override fun putValueIfNeeded(parameterType: JvmKotlinType, value: StackValue, kind: ValueKind, parameterIndex: Int) { + if (processDefaultMaskOrMethodHandler(value, kind)) return + + assert(maskValues.isEmpty()) { "Additional default call arguments should be last ones, but $value" } + + putArgumentOrCapturedToLocalVal(parameterType, value, -1, parameterIndex, kind) + } + + override fun putCapturedValueOnStack(stackValue: StackValue, valueType: Type, paramIndex: Int) { + putArgumentOrCapturedToLocalVal( + JvmKotlinType(stackValue.type, stackValue.kotlinType), stackValue, paramIndex, paramIndex, ValueKind.CAPTURED + ) + } + + override fun reorderArgumentsIfNeeded(actualArgsWithDeclIndex: List, valueParameterTypes: List) = Unit + + override fun putHiddenParamsIntoLocals() { + assert(delayedHiddenWriting != null) { "processAndPutHiddenParameters(true) should be called before putHiddenParamsIntoLocals" } + delayedHiddenWriting!!.invoke() + delayedHiddenWriting = null + } +}