From 7f4da93cc33243b647788c10c29d0d58fd190aa8 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Fri, 16 Apr 2021 21:02:25 +0300 Subject: [PATCH] JVM_IR KT-45998 protected companion object member accessors with indy --- .../FirBlackBoxCodegenTestGenerated.java | 12 +++- .../jvm/lower/SyntheticAccessorLowering.kt | 55 ++++++++++++++----- ...> protectedCompanionObjectStaticMember.kt} | 12 +++- .../withAccessor/protectedMember.kt | 41 ++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 12 +++- .../IrBlackBoxCodegenTestGenerated.java | 12 +++- .../LightAnalysisModeTestGenerated.java | 11 +++- 7 files changed, 128 insertions(+), 27 deletions(-) rename compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/{protectedSuperclassCompanionObjectMember.kt => protectedCompanionObjectStaticMember.kt} (73%) create mode 100644 compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedMember.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 fc1713aff92..7b5e8f31a46 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 @@ -20960,9 +20960,15 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT } @Test - @TestMetadata("protectedSuperclassCompanionObjectMember.kt") - public void testProtectedSuperclassCompanionObjectMember() throws Exception { - runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedSuperclassCompanionObjectMember.kt"); + @TestMetadata("protectedCompanionObjectStaticMember.kt") + public void testProtectedCompanionObjectStaticMember() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedCompanionObjectStaticMember.kt"); + } + + @Test + @TestMetadata("protectedMember.kt") + public void testProtectedMember() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedMember.kt"); } } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt index beea8d27af5..d70b6eda1ca 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt @@ -178,7 +178,8 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle ?: throw AssertionError("'implMethodReference' is expected to be 'IrFunctionReference': ${call.dump()}") val implFunSymbol = implFunRef.symbol - if (implFunSymbol.isAccessible(false, thisSymbol)) return call + if (implFunSymbol.isAccessibleFromSyntheticProxy(thisSymbol)) + return call val accessorSymbol = createAccessor(implFunSymbol, implFunRef.dispatchReceiver?.type, null) val accessorFun = accessorSymbol.owner @@ -212,6 +213,23 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle return call } + private fun IrFunctionSymbol.isAccessibleFromSyntheticProxy(thisSymbol: IrClassSymbol?): Boolean { + if (!isAccessible(false, thisSymbol)) + return false + + if (owner.visibility != DescriptorVisibilities.PROTECTED && + owner.visibility != JavaDescriptorVisibilities.PROTECTED_STATIC_VISIBILITY + ) { + return true + } + + // We have a protected member. + // It is accessible from a synthetic proxy class (created by LambdaMetafactory) + // if it belongs to the current class. + val outerClassInfo = getOuterClassInfo() ?: return false + return outerClassInfo.outerClass == owner.parentAsClass + } + override fun visitGetField(expression: IrGetField): IrExpression { val dispatchReceiverType = expression.receiver?.type return super.visitExpression( @@ -713,6 +731,25 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle // If local variables are accessible by Kotlin rules, they also are by Java rules. val ownerClass = declaration.parent as? IrClass ?: return true + val outerClassInfo = getOuterClassInfo() ?: return false + val outerClass = outerClassInfo.outerClass + val throughCrossinlineLambda = outerClassInfo.throughCrossinlineLambda + + val samePackage = ownerClass.getPackageFragment()?.fqName == outerClass.getPackageFragment()?.fqName + val fromSubclassOfReceiversClass = !throughCrossinlineLambda && + outerClass.isSubclassOf(ownerClass) && + (thisObjReference == null || outerClass.symbol.isSubtypeOfClass(thisObjReference)) + return when { + declaration.visibility.isPrivate && (throughCrossinlineLambda || ownerClass != outerClass) -> false + declaration.visibility.isProtected && !samePackage && !fromSubclassOfReceiversClass -> false + withSuper && !fromSubclassOfReceiversClass -> false + else -> true + } + } + + private class OuterClassInfo(val outerClass: IrClass, val throughCrossinlineLambda: Boolean) + + private fun getOuterClassInfo(): OuterClassInfo? { var context = currentScope!!.irElement as IrDeclaration var throughCrossinlineLambda = false while (context !is IrClass) { @@ -727,21 +764,13 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle // inlined into a different class, e.g. a callable reference. For protected inline functions // calling methods on `super` we also need an accessor to satisfy INVOKESPECIAL constraints. // TODO scan nested classes for calls to private inline functions? - return false + return null } else { - context = context.parent as? IrDeclaration ?: return false + context = context.parent as? IrDeclaration + ?: return null } } - - val samePackage = ownerClass.getPackageFragment()?.fqName == context.getPackageFragment()?.fqName - val fromSubclassOfReceiversClass = !throughCrossinlineLambda && - context.isSubclassOf(ownerClass) && (thisObjReference == null || context.symbol.isSubtypeOfClass(thisObjReference)) - return when { - declaration.visibility.isPrivate && (throughCrossinlineLambda || ownerClass != context) -> false - declaration.visibility.isProtected && !samePackage && !fromSubclassOfReceiversClass -> false - withSuper && !fromSubclassOfReceiversClass -> false - else -> true - } + return OuterClassInfo(context, throughCrossinlineLambda) } // monitorEnter/monitorExit are the only functions which are accessed "illegally" (see kotlin/util/Synchronized.kt). diff --git a/compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedSuperclassCompanionObjectMember.kt b/compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedCompanionObjectStaticMember.kt similarity index 73% rename from compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedSuperclassCompanionObjectMember.kt rename to compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedCompanionObjectStaticMember.kt index a599eb141f2..1196100d7ad 100644 --- a/compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedSuperclassCompanionObjectMember.kt +++ b/compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedCompanionObjectStaticMember.kt @@ -8,6 +8,7 @@ // CHECK_BYTECODE_TEXT // 1 java/lang/invoke/LambdaMetafactory +// 1 c2/C2\.access\$test\$s[0-9]+\(\)Ljava/lang/String\; // FILE: test.kt import c2.* @@ -29,8 +30,15 @@ open class C1 { package c2 import c1.* -import java.util.function.Supplier +import j.* class C2 : C1() { - fun supplier() = Supplier(::test) + fun supplier() = J(::test) +} + +// FILE: j/J.java +package j; + +public interface J { + public String get(); } diff --git a/compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedMember.kt b/compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedMember.kt new file mode 100644 index 00000000000..3c3f305c6be --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedMember.kt @@ -0,0 +1,41 @@ +// TARGET_BACKEND: JVM +// IGNORE_LIGHT_ANALYSIS +// IGNORE_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY + +// WITH_RUNTIME +// FULL_JDK + +// CHECK_BYTECODE_TEXT +// 1 java/lang/invoke/LambdaMetafactory + +// FILE: test.kt +import c2.* + +fun box(): String = + C2().supplier().get() + +// FILE: C1.kt +package c1 + +open class C1 { + protected fun test(): String = "OK" +} + +// FILE: C2.kt +package c2 + +import c1.* +import j.* + +class C2 : C1() { + fun supplier() = J(this::test) +} + +// FILE: j/J.java +package j; + +public interface J { + public String get(); +} 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 f7a659ff848..90aca518941 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 @@ -20936,9 +20936,15 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } @Test - @TestMetadata("protectedSuperclassCompanionObjectMember.kt") - public void testProtectedSuperclassCompanionObjectMember() throws Exception { - runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedSuperclassCompanionObjectMember.kt"); + @TestMetadata("protectedCompanionObjectStaticMember.kt") + public void testProtectedCompanionObjectStaticMember() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedCompanionObjectStaticMember.kt"); + } + + @Test + @TestMetadata("protectedMember.kt") + public void testProtectedMember() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedMember.kt"); } } } 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 58cd85ecd1b..25715caf6a5 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 @@ -20960,9 +20960,15 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes } @Test - @TestMetadata("protectedSuperclassCompanionObjectMember.kt") - public void testProtectedSuperclassCompanionObjectMember() throws Exception { - runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedSuperclassCompanionObjectMember.kt"); + @TestMetadata("protectedCompanionObjectStaticMember.kt") + public void testProtectedCompanionObjectStaticMember() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedCompanionObjectStaticMember.kt"); + } + + @Test + @TestMetadata("protectedMember.kt") + public void testProtectedMember() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedMember.kt"); } } } diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 6feae2ec201..7204ccccc58 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -17482,9 +17482,14 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public static class WithAccessor extends AbstractLightAnalysisModeTest { - @TestMetadata("protectedSuperclassCompanionObjectMember.kt") - public void ignoreProtectedSuperclassCompanionObjectMember() throws Exception { - runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedSuperclassCompanionObjectMember.kt"); + @TestMetadata("protectedCompanionObjectStaticMember.kt") + public void ignoreProtectedCompanionObjectStaticMember() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedCompanionObjectStaticMember.kt"); + } + + @TestMetadata("protectedMember.kt") + public void ignoreProtectedMember() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedMember.kt"); } private void runTest(String testDataFilePath) throws Exception {