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 d0d6e25a12c..f75ff1f86d7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.descriptors.ParameterDescriptor import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type @@ -28,9 +29,6 @@ abstract class InlineCodegen( protected val sourceCompiler: SourceCompilerForInline, private val reifiedTypeInliner: ReifiedTypeInliner<*> ) { - // TODO: implement AS_FUNCTION inline strategy - private val asFunctionInline = false - private val initialFrameSize = codegen.frameMap.currentSize protected val invocationParamBuilder = ParametersBuilder.newBuilder() @@ -108,12 +106,6 @@ abstract class InlineCodegen( return true } - protected fun rememberClosure(parameterType: Type, index: Int, lambdaInfo: LambdaInfo) { - val closureInfo = invocationParamBuilder.addNextValueParameter(parameterType, true, null, index) - closureInfo.functionalArgument = lambdaInfo - expressionMap[closureInfo.index] = lambdaInfo - } - private fun inlineCall(nodeAndSmap: SMAPAndMethodNode, isInlineOnly: Boolean, isSuspend: Boolean): InlineResult { val node = nodeAndSmap.node if (maskStartIndex != -1) { @@ -264,50 +256,46 @@ abstract class InlineCodegen( } } - protected fun putArgumentOrCapturedToLocalVal( - jvmKotlinType: JvmKotlinType, - stackValue: StackValue, - capturedParam: CapturedParamDesc?, - parameterIndex: Int, - kind: ValueKind - ) { - val isDefaultParameter = kind === ValueKind.DEFAULT_PARAMETER - val jvmType = jvmKotlinType.type - val kotlinType = jvmKotlinType.kotlinType - val canRemap = isPrimitive(jvmType) == isPrimitive(stackValue.type) && - !StackValue.requiresInlineClassBoxingOrUnboxing(stackValue.type, stackValue.kotlinType, jvmType, kotlinType) && - (stackValue is StackValue.Local || stackValue.isCapturedInlineParameter()) - if (!canRemap && !isDefaultParameter) { - stackValue.put(jvmType, kotlinType, codegen.visitor) + protected fun rememberClosure(parameterType: Type, index: Int, lambdaInfo: LambdaInfo) { + val closureInfo = invocationParamBuilder.addNextValueParameter(parameterType, true, null, index) + closureInfo.functionalArgument = lambdaInfo + expressionMap[closureInfo.index] = lambdaInfo + } + + protected fun putCapturedToLocalVal(stackValue: StackValue, capturedParam: CapturedParamDesc, kotlinType: KotlinType?) { + val info = invocationParamBuilder.addCapturedParam(capturedParam, capturedParam.fieldName, false) + if (stackValue.isLocalWithNoBoxing(JvmKotlinType(info.type, kotlinType))) { + info.remapValue = stackValue + } else { + stackValue.put(info.type, kotlinType, codegen.visitor) + val local = StackValue.local(codegen.frameMap.enterTemp(info.type), info.type) + local.store(StackValue.onStack(info.type), codegen.visitor) + info.remapValue = local + info.isSynthetic = true + } + } + + protected fun putArgumentToLocalVal(jvmKotlinType: JvmKotlinType, stackValue: StackValue, parameterIndex: Int, kind: ValueKind) { + if (kind === ValueKind.DEFAULT_MASK || kind === ValueKind.METHOD_HANDLE_IN_DEFAULT) { + return processDefaultMaskOrMethodHandler(stackValue, kind) } - if (!asFunctionInline && Type.VOID_TYPE !== jvmType) { - //TODO remap only inlinable closure => otherwise we could get a lot of problem - val remappedValue = if (canRemap && !isDefaultParameter) stackValue else null - val info: ParameterInfo - if (capturedParam != null) { - info = invocationParamBuilder.addCapturedParam(capturedParam, capturedParam.fieldName, false) - info.remapValue = remappedValue - } else { - info = invocationParamBuilder.addNextValueParameter(jvmType, false, remappedValue, parameterIndex) - info.functionalArgument = when (kind) { - ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND -> - NonInlineableArgumentForInlineableParameterCalledInSuspend - ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER -> - NonInlineableArgumentForInlineableSuspendParameter - else -> null - } - } - - if (!info.isSkippedOrRemapped) { - val local = StackValue.local(codegen.frameMap.enterTemp(info.type), info.type) - if (!isDefaultParameter) { - local.store(StackValue.onStack(info.typeOnStack), codegen.visitor) - } - if (info is CapturedParamInfo) { - info.remapValue = local - info.isSynthetic = true - } + val info = invocationParamBuilder.addNextValueParameter(jvmKotlinType.type, false, null, parameterIndex) + info.functionalArgument = when (kind) { + ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND -> + NonInlineableArgumentForInlineableParameterCalledInSuspend + ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER -> + NonInlineableArgumentForInlineableSuspendParameter + else -> null + } + when { + kind === ValueKind.DEFAULT_PARAMETER -> + codegen.frameMap.enterTemp(info.type) // the inline function will put the value into this slot + stackValue.isLocalWithNoBoxing(jvmKotlinType) -> + info.remapValue = stackValue + else -> { + stackValue.put(info.type, jvmKotlinType.kotlinType, codegen.visitor) + codegen.visitor.store(codegen.frameMap.enterTemp(info.type), info.type) } } } @@ -321,19 +309,14 @@ abstract class InlineCodegen( } private fun rememberCapturedForDefaultLambda(defaultLambda: DefaultLambda) { - if (!asFunctionInline) { - for (captured in defaultLambda.capturedVars) { - val info = invocationParamBuilder.addCapturedParam(captured, captured.fieldName, false) - info.remapValue = StackValue.local(codegen.frameMap.enterTemp(info.type), info.type) - info.isSynthetic = true - } + for (captured in defaultLambda.capturedVars) { + val info = invocationParamBuilder.addCapturedParam(captured, captured.fieldName, false) + info.remapValue = StackValue.local(codegen.frameMap.enterTemp(info.type), info.type) + info.isSynthetic = true } } - protected fun processDefaultMaskOrMethodHandler(value: StackValue, kind: ValueKind): Boolean { - if (kind !== ValueKind.DEFAULT_MASK && kind !== ValueKind.METHOD_HANDLE_IN_DEFAULT) { - return false - } + private fun processDefaultMaskOrMethodHandler(value: StackValue, kind: ValueKind) { assert(value is StackValue.Constant) { "Additional default method argument should be constant, but $value" } val constantValue = (value as StackValue.Constant).value if (kind === ValueKind.DEFAULT_MASK) { @@ -348,10 +331,14 @@ abstract class InlineCodegen( assert(constantValue == null) { "Additional method handle for default argument should be null, but " + constantValue!! } methodHandleInDefaultMethodIndex = maskStartIndex + maskValues.size } - return true } companion object { + private fun StackValue.isLocalWithNoBoxing(expected: JvmKotlinType): Boolean = + isPrimitive(expected.type) == isPrimitive(type) && + !StackValue.requiresInlineClassBoxingOrUnboxing(type, kotlinType, expected.type, expected.kotlinType) && + (this is StackValue.Local || isCapturedInlineParameter()) + private fun StackValue.isCapturedInlineParameter(): Boolean { val field = if (this is StackValue.FieldForSharedVar) receiver else this return field is StackValue.Field && field.descriptor is ParameterDescriptor && diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt index 1b61a7405a7..389c8a441e0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.load.kotlin.TypeMappingMode import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.psi.psiUtil.isAncestor @@ -192,20 +193,11 @@ class PsiInlineCodegen( activeLambda = null } - override fun putValueIfNeeded(parameterType: JvmKotlinType, value: StackValue, kind: ValueKind, parameterIndex: Int) { - if (processDefaultMaskOrMethodHandler(value, kind)) return + override fun putValueIfNeeded(parameterType: JvmKotlinType, value: StackValue, kind: ValueKind, parameterIndex: Int) = + putArgumentToLocalVal(parameterType, value, parameterIndex, kind) - assert(maskValues.isEmpty()) { "Additional default call arguments should be last ones, but $value" } - - putArgumentOrCapturedToLocalVal(parameterType, value, null, parameterIndex, kind) - } - - override fun putCapturedValueOnStack(stackValue: StackValue, valueType: Type, paramIndex: Int) { - val param = activeLambda!!.capturedVars[paramIndex] - putArgumentOrCapturedToLocalVal( - JvmKotlinType(stackValue.type, stackValue.kotlinType), stackValue, param, paramIndex, ValueKind.CAPTURED - ) - } + override fun putCapturedValueOnStack(stackValue: StackValue, valueType: Type, paramIndex: Int) = + putCapturedToLocalVal(stackValue, activeLambda!!.capturedVars[paramIndex], stackValue.kotlinType) override fun reorderArgumentsIfNeeded(actualArgsWithDeclIndex: List, valueParameterTypes: List) = Unit @@ -294,9 +286,10 @@ class PsiExpressionLambda( val capturedReceiver = closure.capturedReceiverFromOuterContext if (capturedReceiver != null) { val fieldName = closure.getCapturedReceiverFieldName(state.typeMapper.bindingContext, state.languageVersionSettings) - val type = state.typeMapper.mapType(capturedReceiver).let { - if (isBoundCallableReference) AsmUtil.boxType(it) else it - } + val type = if (isBoundCallableReference) + state.typeMapper.mapType(capturedReceiver, null, TypeMappingMode.GENERIC_ARGUMENT) + else + state.typeMapper.mapType(capturedReceiver) add(capturedParamDesc(fieldName, type, isSuspend = false)) } 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 56781c44b14..6b99b793fbb 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 @@ -67,7 +67,9 @@ class IrInlineCodegen( rememberClosure(parameterType, irValueParameter.index, lambdaInfo) lambdaInfo.generateLambdaBody(sourceCompiler) lambdaInfo.reference.getArgumentsWithIr().forEachIndexed { index, (_, ir) -> - putCapturedValueOnStack(ir, lambdaInfo.capturedVars[index], index) + val param = lambdaInfo.capturedVars[index] + val onStack = codegen.genOrGetLocal(ir, param.type, ir.type, BlockInfo()) + putCapturedToLocalVal(onStack, param, ir.type.toIrBasedKotlinType()) } } else { val kind = when (irValueParameter.origin) { @@ -99,21 +101,11 @@ class IrInlineCodegen( -> codegen.gen(argumentExpression, parameterType, irValueParameter.type, blockInfo) } - - //TODO support default argument erasure - if (!processDefaultMaskOrMethodHandler(onStack, kind)) { - val expectedType = JvmKotlinType(parameterType, irValueParameter.type.toIrBasedKotlinType()) - putArgumentOrCapturedToLocalVal(expectedType, onStack, null, irValueParameter.index, kind) - } + val expectedType = JvmKotlinType(parameterType, irValueParameter.type.toIrBasedKotlinType()) + putArgumentToLocalVal(expectedType, onStack, irValueParameter.index, kind) } } - private fun putCapturedValueOnStack(argumentExpression: IrExpression, param: CapturedParamDesc, capturedParamIndex: Int) { - val onStack = codegen.genOrGetLocal(argumentExpression, param.type, argumentExpression.type, BlockInfo()) - val expectedType = JvmKotlinType(param.type, argumentExpression.type.toIrBasedKotlinType()) - putArgumentOrCapturedToLocalVal(expectedType, onStack, param, capturedParamIndex, ValueKind.CAPTURED) - } - override fun beforeValueParametersStart() { invocationParamBuilder.markValueParametersStart() } diff --git a/compiler/testData/codegen/box/callableReference/bound/genericBoundPropertyAsCrossinline.kt b/compiler/testData/codegen/box/callableReference/bound/genericBoundPropertyAsCrossinline.kt index adc5ed04381..7598cc36e16 100644 --- a/compiler/testData/codegen/box/callableReference/bound/genericBoundPropertyAsCrossinline.kt +++ b/compiler/testData/codegen/box/callableReference/bound/genericBoundPropertyAsCrossinline.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM // DONT_TARGET_EXACT_BACKEND: WASM // WASM_MUTE_REASON: BINDING_RECEIVERS // KT-30629 diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index c53e2f3dbd4..8846a8f3237 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -2535,11 +2535,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public static class Bound extends AbstractLightAnalysisModeTest { - @TestMetadata("genericBoundPropertyAsCrossinline.kt") - public void ignoreGenericBoundPropertyAsCrossinline() throws Exception { - runTest("compiler/testData/codegen/box/callableReference/bound/genericBoundPropertyAsCrossinline.kt"); - } - private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); } @@ -2613,6 +2608,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/callableReference/bound/enumEntryMember.kt"); } + @TestMetadata("genericBoundPropertyAsCrossinline.kt") + public void testGenericBoundPropertyAsCrossinline() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/bound/genericBoundPropertyAsCrossinline.kt"); + } + @TestMetadata("genericValOnLHS.kt") public void testGenericValOnLHS() throws Exception { runTest("compiler/testData/codegen/box/callableReference/bound/genericValOnLHS.kt");