Minor, extract PsiInlineCodegen to a separate file
This commit is contained in:
@@ -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<out T : BaseExpressionCodegen>(
|
||||
|
||||
val BaseExpressionCodegen.v: InstructionAdapter
|
||||
get() = visitor
|
||||
|
||||
class PsiInlineCodegen(
|
||||
codegen: ExpressionCodegen,
|
||||
state: GenerationState,
|
||||
function: FunctionDescriptor,
|
||||
typeParameterMappings: TypeParameterMappings,
|
||||
sourceCompiler: SourceCompilerForInline
|
||||
) : InlineCodegen<ExpressionCodegen>(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<ArgumentAndDeclIndex>, valueParameterTypes: List<Type>) = Unit
|
||||
|
||||
override fun putHiddenParamsIntoLocals() {
|
||||
assert(delayedHiddenWriting != null) { "processAndPutHiddenParameters(true) should be called before putHiddenParamsIntoLocals" }
|
||||
delayedHiddenWriting!!.invoke()
|
||||
delayedHiddenWriting = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<ExpressionCodegen>(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<ArgumentAndDeclIndex>, valueParameterTypes: List<Type>) = Unit
|
||||
|
||||
override fun putHiddenParamsIntoLocals() {
|
||||
assert(delayedHiddenWriting != null) { "processAndPutHiddenParameters(true) should be called before putHiddenParamsIntoLocals" }
|
||||
delayedHiddenWriting!!.invoke()
|
||||
delayedHiddenWriting = null
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user