JVM_IR: skip SAM lambdas when computing enclosing method of objects

This is what Java 15+ does, and it permits accessing captured type
parameters via reflection. The alternative is to emit generic signatures
on the lambda methods, but that was disabled and I have no clue why.

^KT-52417 Fixed
This commit is contained in:
pyos
2022-05-24 09:23:41 +02:00
committed by Alexander Udalov
parent f81d47bad6
commit 27c51f5f88
21 changed files with 211 additions and 6 deletions
@@ -44955,6 +44955,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/sam/kt50477Enabled.kt");
}
@Test
@TestMetadata("kt52417.kt")
public void testKt52417() throws Exception {
runTest("compiler/testData/codegen/box/sam/kt52417.kt");
}
@Test
@TestMetadata("nonInlinedSamWrapper.kt")
public void testNonInlinedSamWrapper() throws Exception {
@@ -2230,6 +2230,12 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
}
@Test
@TestMetadata("kt52417.kt")
public void testKt52417() throws Exception {
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
}
@Test
@TestMetadata("objectInInlineFun.kt")
public void testObjectInInlineFun() throws Exception {
@@ -2230,6 +2230,12 @@ public class FirLightTreeBlackBoxInlineCodegenTestGenerated extends AbstractFirL
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
}
@Test
@TestMetadata("kt52417.kt")
public void testKt52417() throws Exception {
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
}
@Test
@TestMetadata("objectInInlineFun.kt")
public void testObjectInInlineFun() throws Exception {
@@ -2230,6 +2230,12 @@ public class FirSerializeCompileKotlinAgainstInlineKotlinTestGenerated extends A
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
}
@Test
@TestMetadata("kt52417.kt")
public void testKt52417() throws Exception {
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
}
@Test
@TestMetadata("objectInInlineFun.kt")
public void testObjectInInlineFun() throws Exception {
@@ -148,6 +148,12 @@ class ExpressionCodegen(
var finallyDepth = 0
val inlineRoot: ExpressionCodegen
get() = inlinedInto ?: this
val enclosingFunctionForLocalObjects: IrFunction
get() = generateSequence(inlineRoot.irFunction) { context.enclosingMethodOverride[it] }.last()
val context = classCodegen.context
val typeMapper = context.typeMapper
val methodSignatureMapper = context.methodSignatureMapper
@@ -862,7 +868,7 @@ class ExpressionCodegen(
override fun visitClass(declaration: IrClass, data: BlockInfo): PromisedValue {
if (declaration.origin != JvmLoweredDeclarationOrigin.CONTINUATION_CLASS) {
val childCodegen = ClassCodegen.getOrCreate(declaration, context, generateSequence(this) { it.inlinedInto }.last().irFunction)
val childCodegen = ClassCodegen.getOrCreate(declaration, context, enclosingFunctionForLocalObjects)
childCodegen.generate()
closureReifiedMarkers[declaration] = childCodegen.reifiedTypeParametersUsages
}
@@ -42,12 +42,16 @@ class IrSourceCompilerForInline(
override val inlineCallSiteInfo: InlineCallSiteInfo
get() {
val root = generateSequence(codegen) { it.inlinedInto }.last()
val root = codegen.inlineRoot
val rootFunction = root.enclosingFunctionForLocalObjects
return InlineCallSiteInfo(
root.classCodegen.type.internalName,
root.signature.asmMethod,
root.irFunction.inlineScopeVisibility,
root.irFunction.fileParent.getIoFile(),
if (rootFunction === root.irFunction)
root.signature.asmMethod
else
codegen.methodSignatureMapper.mapAsmMethod(rootFunction),
rootFunction.inlineScopeVisibility,
rootFunction.fileParent.getIoFile(),
callElement.psiElement?.let { CodegenUtil.getLineNumberForElement(it, false) } ?: 0
)
}
@@ -62,7 +66,7 @@ class IrSourceCompilerForInline(
reifiedTypeParameters.addUsedReifiedParameter(typeParameter.name.asString())
}
}
return FunctionCodegen(lambdaInfo.function, codegen.classCodegen).generate(codegen, reifiedTypeParameters)
return FunctionCodegen(lambdaInfo.function, codegen.classCodegen).generate(codegen.inlineRoot, reifiedTypeParameters)
}
override fun compileInlineFunction(jvmSignature: JvmMethodSignature): SMAPAndMethodNode {
@@ -367,6 +367,7 @@ private val jvmFilePhases = listOf(
jvmSafeCallFoldingPhase,
jvmOptimizationLoweringPhase,
additionalClassAnnotationPhase,
recordEnclosingMethodsPhase,
typeOperatorLowering,
replaceKFunctionInvokeWithFunctionInvokePhase,
kotlinNothingValueExceptionPhase,
@@ -0,0 +1,64 @@
/*
* Copyright 2010-2022 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.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.isInlineFunctionCall
import org.jetbrains.kotlin.backend.jvm.ir.unwrapInlineLambda
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.util.isLambda
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.primaryConstructor
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
internal val recordEnclosingMethodsPhase = makeIrFilePhase(
::RecordEnclosingMethodsLowering,
name = "RecordEnclosingMethods",
description = "Find enclosing methods for objects inside inline and dynamic lambdas"
)
private class RecordEnclosingMethodsLowering(val context: JvmBackendContext) : FileLoweringPass {
override fun lower(irFile: IrFile) =
irFile.accept(object : IrElementVisitor<Unit, IrFunction?> {
override fun visitElement(element: IrElement, data: IrFunction?) =
element.acceptChildren(this, element as? IrFunction ?: data)
override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: IrFunction?) {
require(data != null) { "function call not in a method: ${expression.render()}" }
when {
expression.symbol == context.ir.symbols.indyLambdaMetafactoryIntrinsic -> {
val reference = expression.getValueArgument(1)
if (reference is IrFunctionReference && reference.origin.isLambda) {
recordEnclosingMethodOverride(reference.symbol.owner, data)
}
}
expression.symbol.owner.isInlineFunctionCall(context) -> {
for (parameter in expression.symbol.owner.valueParameters) {
val lambda = expression.getValueArgument(parameter.index)?.unwrapInlineLambda() ?: continue
recordEnclosingMethodOverride(lambda.symbol.owner, data)
}
}
}
return super.visitFunctionAccess(expression, data)
}
private fun recordEnclosingMethodOverride(from: IrFunction, to: IrFunction) =
context.enclosingMethodOverride.merge(from, to) { old, new ->
// A single lambda can be referenced multiple times if it is in a field initializer
// or an anonymous initializer block and there are multiple non-delegating constructors.
assert(old.parentAsClass == new.parentAsClass && old is IrConstructor && new is IrConstructor)
old.parentAsClass.primaryConstructor ?: old
}
}, null)
}
@@ -99,6 +99,7 @@ class JvmBackendContext(
}
val isEnclosedInConstructor = ConcurrentHashMap.newKeySet<IrAttributeContainer>()
val enclosingMethodOverride = ConcurrentHashMap<IrFunction, IrFunction>()
private val classCodegens = ConcurrentHashMap<IrClass, Any>()
+18
View File
@@ -0,0 +1,18 @@
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// WITH_STDLIB
package test
abstract class TypeToken<T>
fun interface I {
fun foo(): String
}
fun <T> foo() =
I {
(object : TypeToken<T>() {})::class.java.genericSuperclass.toString()
}.foo()
fun box(): String =
foo<String>().let { if (it == "test.TypeToken<T>") "OK" else it }
@@ -0,0 +1,28 @@
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// WITH_STDLIB
// FILE: 1.kt
package test
abstract class TypeToken<U>
// Although V is not reified, if the object happens to be regenerated, V will be replaced with its value in signatures
inline fun <V> typeTokenOf(crossinline forceRegeneration: () -> Unit = {}) =
object : TypeToken<V>() {
fun unused() = forceRegeneration()
}
// FILE: 2.kt
import test.*
fun interface I {
fun foo(): String
}
fun <T> foo() =
I {
typeTokenOf<T>()::class.java.genericSuperclass.toString()
}.foo()
fun box(): String =
foo<String>().let { if (it == "test.TypeToken<T>") "OK" else it }
@@ -44391,6 +44391,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/sam/kt50171.kt");
}
@Test
@TestMetadata("kt52417.kt")
public void testKt52417() throws Exception {
runTest("compiler/testData/codegen/box/sam/kt52417.kt");
}
@Test
@TestMetadata("nonInlinedSamWrapper.kt")
public void testNonInlinedSamWrapper() throws Exception {
@@ -2230,6 +2230,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
}
@Test
@TestMetadata("kt52417.kt")
public void testKt52417() throws Exception {
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
}
@Test
@TestMetadata("objectInInlineFun.kt")
public void testObjectInInlineFun() throws Exception {
@@ -2230,6 +2230,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
}
@Test
@TestMetadata("kt52417.kt")
public void testKt52417() throws Exception {
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
}
@Test
@TestMetadata("objectInInlineFun.kt")
public void testObjectInInlineFun() throws Exception {
@@ -44955,6 +44955,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/sam/kt50477Enabled.kt");
}
@Test
@TestMetadata("kt52417.kt")
public void testKt52417() throws Exception {
runTest("compiler/testData/codegen/box/sam/kt52417.kt");
}
@Test
@TestMetadata("nonInlinedSamWrapper.kt")
public void testNonInlinedSamWrapper() throws Exception {
@@ -2230,6 +2230,12 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
}
@Test
@TestMetadata("kt52417.kt")
public void testKt52417() throws Exception {
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
}
@Test
@TestMetadata("objectInInlineFun.kt")
public void testObjectInInlineFun() throws Exception {
@@ -2230,6 +2230,12 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
}
@Test
@TestMetadata("kt52417.kt")
public void testKt52417() throws Exception {
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
}
@Test
@TestMetadata("objectInInlineFun.kt")
public void testObjectInInlineFun() throws Exception {
@@ -2230,6 +2230,12 @@ public class IrSerializeCompileKotlinAgainstInlineKotlinTestGenerated extends Ab
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
}
@Test
@TestMetadata("kt52417.kt")
public void testKt52417() throws Exception {
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
}
@Test
@TestMetadata("objectInInlineFun.kt")
public void testObjectInInlineFun() throws Exception {
@@ -2230,6 +2230,12 @@ public class JvmIrAgainstOldBoxInlineTestGenerated extends AbstractJvmIrAgainstO
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
}
@Test
@TestMetadata("kt52417.kt")
public void testKt52417() throws Exception {
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
}
@Test
@TestMetadata("objectInInlineFun.kt")
public void testObjectInInlineFun() throws Exception {
@@ -2230,6 +2230,12 @@ public class JvmOldAgainstIrBoxInlineTestGenerated extends AbstractJvmOldAgainst
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
}
@Test
@TestMetadata("kt52417.kt")
public void testKt52417() throws Exception {
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
}
@Test
@TestMetadata("objectInInlineFun.kt")
public void testObjectInInlineFun() throws Exception {
@@ -35870,6 +35870,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/sam/kt50171.kt");
}
@TestMetadata("kt52417.kt")
public void testKt52417() throws Exception {
runTest("compiler/testData/codegen/box/sam/kt52417.kt");
}
@TestMetadata("nonInlinedSamWrapper.kt")
public void testNonInlinedSamWrapper() throws Exception {
runTest("compiler/testData/codegen/box/sam/nonInlinedSamWrapper.kt");