From 83e3a702c513e86fbfc5668c3afe4dae2ac3c893 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Fri, 30 Apr 2021 13:24:40 +0300 Subject: [PATCH] JVM_IR KT-46408 properly map fake overrides in method handles --- .../FirBlackBoxCodegenTestGenerated.java | 6 +++ .../jvm/codegen/MethodSignatureMapper.kt | 2 +- .../jvm/intrinsics/JvmInvokeDynamic.kt | 16 ++++++- .../sam/functionRefToJavaInterface/kt46408.kt | 43 +++++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 +++ .../IrBlackBoxCodegenTestGenerated.java | 6 +++ .../LightAnalysisModeTestGenerated.java | 5 +++ 7 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/kt46408.kt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 3c0a00e72c2..c015b111e89 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -21070,6 +21070,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/kt45581.kt"); } + @Test + @TestMetadata("kt46408.kt") + public void testKt46408() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/kt46408.kt"); + } + @Test @TestMetadata("localFunction1.kt") public void testLocalFunction1() throws Exception { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt index 4c400d30d52..6620a1f291a 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt @@ -438,7 +438,7 @@ class MethodSignatureMapper(private val context: JvmBackendContext) { mapAsmMethod(findSuperDeclaration(function, isSuperCall)) // Copied from KotlinTypeMapper.findSuperDeclaration. - private fun findSuperDeclaration(function: IrSimpleFunction, isSuperCall: Boolean): IrSimpleFunction { + internal fun findSuperDeclaration(function: IrSimpleFunction, isSuperCall: Boolean): IrSimpleFunction { var current = function while (current.isFakeOverride) { // TODO: probably isJvmInterface instead of isInterface, here and in KotlinTypeMapper diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/JvmInvokeDynamic.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/JvmInvokeDynamic.kt index 9ba8cac121f..60fa956b85a 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/JvmInvokeDynamic.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/JvmInvokeDynamic.kt @@ -101,11 +101,24 @@ object JvmInvokeDynamic : IntrinsicMethod() { } private fun generateMethodHandle(irRawFunctionReference: IrRawFunctionReference, codegen: ExpressionCodegen): Handle { - val irFun = irRawFunctionReference.symbol.owner + val irFun = when (val irFun0 = irRawFunctionReference.symbol.owner) { + is IrConstructor -> + irFun0 + is IrSimpleFunction -> { + // Note that if the given function is a fake override, we emit a method handle with explicit super class. + // This has the same binary compatibility guarantees as in Java. + codegen.methodSignatureMapper.findSuperDeclaration(irFun0, false) + } + else -> + throw java.lang.AssertionError("Simple function or constructor expected: ${irFun0.render()}") + } + val irParentClass = irFun.parent as? IrClass ?: throw AssertionError("Unexpected parent: ${irFun.parent.render()}") val owner = codegen.typeMapper.mapOwner(irParentClass) + val asmMethod = codegen.methodSignatureMapper.mapAsmMethod(irFun) + val handleTag = when { irFun is IrConstructor -> Opcodes.H_NEWINVOKESPECIAL @@ -116,6 +129,7 @@ object JvmInvokeDynamic : IntrinsicMethod() { else -> Opcodes.H_INVOKEVIRTUAL } + return Handle(handleTag, owner.internalName, asmMethod.name, asmMethod.descriptor, irParentClass.isJvmInterface) } diff --git a/compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/kt46408.kt b/compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/kt46408.kt new file mode 100644 index 00000000000..8f0b83aa770 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/kt46408.kt @@ -0,0 +1,43 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +// FILE: kt46408.kt + +open class User { + protected fun processIdentity(identity: IT) { + identity.ok = "OK" + } +} + +class UserAc : User() { + fun doStuff(data: Container) { + data.processEachWith(this::processIdentity) + } +} + +interface Identity { + var ok: String +} + +class AcIdentity(override var ok: String) : Identity + +class Container { + var id = AcIdentity("xxx") + + fun processEachWith(action: Action) { + action.execute(id) + } +} + +fun box(): String { + val c = Container() + UserAc().doStuff(c) + return c.id.ok +} + +// FILE: Action.java + +public interface Action { + void execute(T var1); +} \ No newline at end of file diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 3e1953c2ccc..e5bc5a08f64 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -21046,6 +21046,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/kt45581.kt"); } + @Test + @TestMetadata("kt46408.kt") + public void testKt46408() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/kt46408.kt"); + } + @Test @TestMetadata("localFunction1.kt") public void testLocalFunction1() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index d160ee91e0c..b9bd230dddc 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -21070,6 +21070,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/kt45581.kt"); } + @Test + @TestMetadata("kt46408.kt") + public void testKt46408() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/kt46408.kt"); + } + @Test @TestMetadata("localFunction1.kt") public void testLocalFunction1() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index c23f4c737f6..f1d132bf87a 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -17598,6 +17598,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/kt45581.kt"); } + @TestMetadata("kt46408.kt") + public void testKt46408() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/kt46408.kt"); + } + @TestMetadata("localFunction1.kt") public void testLocalFunction1() throws Exception { runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/localFunction1.kt");