JVM_IR KT-45998 protected companion object member accessors with indy

This commit is contained in:
Dmitry Petrov
2021-04-16 21:02:25 +03:00
committed by TeamCityServer
parent 9a4a39e680
commit 7f4da93cc3
7 changed files with 128 additions and 27 deletions
@@ -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");
}
}
}
@@ -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).
@@ -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<String>(::test)
fun supplier() = J(::test)
}
// FILE: j/J.java
package j;
public interface J {
public String get();
}
@@ -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();
}
@@ -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");
}
}
}
@@ -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");
}
}
}
@@ -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 {