From 6734f542b3d65f07b0460648489ad4fd5868bf4d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 21 Apr 2022 01:57:31 +0200 Subject: [PATCH] JVM IR: sanitize indy lambda proxy names correctly In case there are several proxy functions for indy lambdas in the same container, its names are "...__proxy", "...__proxy-0", "...__proxy-1", ..., yet before this change, only the first one was sanitized. So if it's happening inside a constructor, `` was left unrenamed which led to ClassFormatError. #KT-52040 Fixed --- .../FirBlackBoxCodegenTestGenerated.java | 6 ++ .../common/lower/LocalDeclarationsLowering.kt | 18 ++---- .../jetbrains/kotlin/backend/jvm/JvmLower.kt | 5 +- .../sam/kt52040_severalProxyFunsInInit.kt | 29 ++++++++++ .../sam/severalProxyFunsInInit.kt | 19 ++++++ .../sam/severalProxyFunsInInit.txt | 58 +++++++++++++++++++ .../sam/severalProxyFunsInInit_ir.txt | 21 +++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 ++ .../codegen/BytecodeListingTestGenerated.java | 6 ++ .../IrBlackBoxCodegenTestGenerated.java | 6 ++ .../IrBytecodeListingTestGenerated.java | 6 ++ .../LightAnalysisModeTestGenerated.java | 5 ++ 12 files changed, 168 insertions(+), 17 deletions(-) create mode 100644 compiler/testData/codegen/box/invokedynamic/sam/kt52040_severalProxyFunsInInit.kt create mode 100644 compiler/testData/codegen/bytecodeListing/sam/severalProxyFunsInInit.kt create mode 100644 compiler/testData/codegen/bytecodeListing/sam/severalProxyFunsInInit.txt create mode 100644 compiler/testData/codegen/bytecodeListing/sam/severalProxyFunsInInit_ir.txt 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 80d151cee92..c583d2881f6 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 @@ -25996,6 +25996,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/invokedynamic/sam/kt47510.kt"); } + @Test + @TestMetadata("kt52040_severalProxyFunsInInit.kt") + public void testKt52040_severalProxyFunsInInit() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/kt52040_severalProxyFunsInInit.kt"); + } + @Test @TestMetadata("nullabilityAssertions.kt") public void testNullabilityAssertions() throws Exception { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt index 51ed87f5dff..3c08e53a63b 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt @@ -33,15 +33,6 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.utils.addToStdlib.safeAs -interface LocalNameProvider { - fun localName(declaration: IrDeclarationWithName): String = - declaration.name.asString() - - companion object { - val DEFAULT = object : LocalNameProvider {} - } -} - interface VisibilityPolicy { fun forClass(declaration: IrClass, inInlineFunctionScope: Boolean): DescriptorVisibility = declaration.visibility @@ -77,7 +68,7 @@ object BOUND_RECEIVER_PARAMETER : IrDeclarationOriginImpl("BOUND_RECEIVER_PARAME */ class LocalDeclarationsLowering( val context: CommonBackendContext, - val localNameProvider: LocalNameProvider = LocalNameProvider.DEFAULT, + val localNameSanitizer: (String) -> String = { it }, val visibilityPolicy: VisibilityPolicy = VisibilityPolicy.DEFAULT, val suggestUniqueNames: Boolean = true, // When `true` appends a `-#index` suffix to lifted declaration names val forceFieldsForInlineCaptures: Boolean = false // See `LocalClassContext` @@ -594,13 +585,14 @@ class LocalDeclarationsLowering( } private fun suggestLocalName(declaration: IrDeclarationWithName): String { + val declarationName = localNameSanitizer(declaration.name.asString()) localFunctions[declaration]?.let { - val baseName = if (declaration.name.isSpecial) "lambda" else declaration.name + val baseName = if (declaration.name.isSpecial) "lambda" else declarationName if (it.index >= 0) - return if (suggestUniqueNames) "$baseName-${it.index}" else "$baseName" + return if (suggestUniqueNames) "$baseName-${it.index}" else baseName } - return localNameProvider.localName(declaration) + return declarationName } private fun generateNameForLiftedDeclaration( diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 3b2add6df8c..b6e437a3ede 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -116,10 +116,7 @@ internal val localDeclarationsPhase = makeIrFilePhase( { context -> LocalDeclarationsLowering( context, - object : LocalNameProvider { - override fun localName(declaration: IrDeclarationWithName): String = - NameUtils.sanitizeAsJavaIdentifier(super.localName(declaration)) - }, + NameUtils::sanitizeAsJavaIdentifier, object : VisibilityPolicy { // Note: any condition that results in non-`LOCAL` visibility here should be duplicated in `JvmLocalClassPopupLowering`, // else it won't detect the class as local. diff --git a/compiler/testData/codegen/box/invokedynamic/sam/kt52040_severalProxyFunsInInit.kt b/compiler/testData/codegen/box/invokedynamic/sam/kt52040_severalProxyFunsInInit.kt new file mode 100644 index 00000000000..3dec14dfa5f --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/kt52040_severalProxyFunsInInit.kt @@ -0,0 +1,29 @@ +// TARGET_BACKEND: JVM +// FULL_JDK +// JVM_TARGET: 1.8 +// FILE: J.java + +import java.util.function.*; + +public class J { + public static String f1(Supplier r) { + r.get(); + return "O"; + } + + public static String f2(Supplier r) { + r.get(); + return "K"; + } +} + +// FILE: test.kt + +class C private constructor() { + companion object { + fun x1() = J.f1(::C) + fun x2() = J.f2(::C) + } +} + +fun box(): String = C.x1() + C.x2() diff --git a/compiler/testData/codegen/bytecodeListing/sam/severalProxyFunsInInit.kt b/compiler/testData/codegen/bytecodeListing/sam/severalProxyFunsInInit.kt new file mode 100644 index 00000000000..d7d8069971a --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/sam/severalProxyFunsInInit.kt @@ -0,0 +1,19 @@ +// FULL_JDK +// JVM_TARGET: 1.8 +// FILE: J.java + +import java.util.function.*; + +public class J { + public static void f1(Supplier r) {} + public static void f2(Supplier r) {} +} + +// FILE: test.kt + +class C private constructor() { + companion object { + fun x1() = J.f1(::C) + fun x2() = J.f2(::C) + } +} diff --git a/compiler/testData/codegen/bytecodeListing/sam/severalProxyFunsInInit.txt b/compiler/testData/codegen/bytecodeListing/sam/severalProxyFunsInInit.txt new file mode 100644 index 00000000000..8f5032d2e59 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/sam/severalProxyFunsInInit.txt @@ -0,0 +1,58 @@ +@kotlin.Metadata +synthetic final class C$Companion$x1$1 { + // source: 'test.kt' + enclosing method C$Companion.x1()V + public final static field INSTANCE: C$Companion$x1$1 + inner (anonymous) class C$Companion$x1$1 + static method (): void + method (): void + public final @org.jetbrains.annotations.NotNull method invoke(): C + public synthetic bridge method invoke(): java.lang.Object + public final inner class C$Companion +} + +@kotlin.Metadata +synthetic final class C$Companion$x2$1 { + // source: 'test.kt' + enclosing method C$Companion.x2()V + public final static field INSTANCE: C$Companion$x2$1 + inner (anonymous) class C$Companion$x2$1 + static method (): void + method (): void + public final @org.jetbrains.annotations.NotNull method invoke(): C + public synthetic bridge method invoke(): java.lang.Object + public final inner class C$Companion +} + +@kotlin.Metadata +public final class C$Companion { + // source: 'test.kt' + inner (anonymous) class C$Companion$x1$1 + inner (anonymous) class C$Companion$x2$1 + inner (anonymous) class C$sam$java_util_function_Supplier$0 + private method (): void + public synthetic method (p0: kotlin.jvm.internal.DefaultConstructorMarker): void + public final method x1(): void + public final method x2(): void + public final inner class C$Companion +} + +@kotlin.Metadata +synthetic final class C$sam$java_util_function_Supplier$0 { + // source: 'test.kt' + enclosing method C$Companion.x1()V + private synthetic final field function: kotlin.jvm.functions.Function0 + inner (anonymous) class C$sam$java_util_function_Supplier$0 + method (p0: kotlin.jvm.functions.Function0): void + public synthetic final method get(): java.lang.Object +} + +@kotlin.Metadata +public final class C { + // source: 'test.kt' + public final static @org.jetbrains.annotations.NotNull field Companion: C$Companion + static method (): void + private method (): void + public synthetic method (p0: kotlin.jvm.internal.DefaultConstructorMarker): void + public final inner class C$Companion +} diff --git a/compiler/testData/codegen/bytecodeListing/sam/severalProxyFunsInInit_ir.txt b/compiler/testData/codegen/bytecodeListing/sam/severalProxyFunsInInit_ir.txt new file mode 100644 index 00000000000..b92de74b8b8 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/sam/severalProxyFunsInInit_ir.txt @@ -0,0 +1,21 @@ +@kotlin.Metadata +public final class C$Companion { + // source: 'test.kt' + private method (): void + public synthetic method (p0: kotlin.jvm.internal.DefaultConstructorMarker): void + private synthetic final static method x1$_init___proxy(): C + public final method x1(): void + private synthetic final static method x2$_init___proxy-0(): C + public final method x2(): void + public final inner class C$Companion +} + +@kotlin.Metadata +public final class C { + // source: 'test.kt' + public final static @org.jetbrains.annotations.NotNull field Companion: C$Companion + static method (): void + private method (): void + public synthetic method (p0: kotlin.jvm.internal.DefaultConstructorMarker): void + public final inner class C$Companion +} 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 2e0a753caff..86113f1316b 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 @@ -25540,6 +25540,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/invokedynamic/sam/kt47510.kt"); } + @Test + @TestMetadata("kt52040_severalProxyFunsInInit.kt") + public void testKt52040_severalProxyFunsInInit() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/kt52040_severalProxyFunsInInit.kt"); + } + @Test @TestMetadata("nullabilityAssertions.kt") public void testNullabilityAssertions() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeListingTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeListingTestGenerated.java index 073f5704988..0987f13011c 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeListingTestGenerated.java @@ -2146,6 +2146,12 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { runTest("compiler/testData/codegen/bytecodeListing/sam/samAdapterInInlineLambda.kt"); } + @Test + @TestMetadata("severalProxyFunsInInit.kt") + public void testSeveralProxyFunsInInit() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/sam/severalProxyFunsInInit.kt"); + } + @Test @TestMetadata("specializedFunInterface.kt") public void testSpecializedFunInterface() 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 2c09081e250..733bd623b84 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 @@ -25996,6 +25996,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/invokedynamic/sam/kt47510.kt"); } + @Test + @TestMetadata("kt52040_severalProxyFunsInInit.kt") + public void testKt52040_severalProxyFunsInInit() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/kt52040_severalProxyFunsInInit.kt"); + } + @Test @TestMetadata("nullabilityAssertions.kt") public void testNullabilityAssertions() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeListingTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeListingTestGenerated.java index da116ed8ee4..5d9f39ba192 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeListingTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeListingTestGenerated.java @@ -2242,6 +2242,12 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes runTest("compiler/testData/codegen/bytecodeListing/sam/samAdapterInInlineLambda.kt"); } + @Test + @TestMetadata("severalProxyFunsInInit.kt") + public void testSeveralProxyFunsInInit() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/sam/severalProxyFunsInInit.kt"); + } + @Test @TestMetadata("specializedFunInterface.kt") public void testSpecializedFunInterface() 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 fd4f20a2d5d..4ff02979d0e 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -21506,6 +21506,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/invokedynamic/sam/kt47510.kt"); } + @TestMetadata("kt52040_severalProxyFunsInInit.kt") + public void testKt52040_severalProxyFunsInInit() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/kt52040_severalProxyFunsInInit.kt"); + } + @TestMetadata("nullabilityAssertions.kt") public void testNullabilityAssertions() throws Exception { runTest("compiler/testData/codegen/box/invokedynamic/sam/nullabilityAssertions.kt");