JVM_IR KT-48954 prohibit indy reference creation in some cases

This commit is contained in:
Dmitry Petrov
2021-10-04 16:45:25 +03:00
committed by TeamCityServer
parent 7552767d85
commit 1dae2aca4c
9 changed files with 107 additions and 24 deletions
@@ -42192,6 +42192,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/syntheticAccessors/kt48331.kt");
}
@Test
@TestMetadata("kt48954.kt")
public void testKt48954() throws Exception {
runTest("compiler/testData/codegen/box/syntheticAccessors/kt48954.kt");
}
@Test
@TestMetadata("kt9717.kt")
public void testKt9717() throws Exception {
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.lower.VariableRemapper
import org.jetbrains.kotlin.backend.common.lower.parents
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
import org.jetbrains.kotlin.backend.jvm.ir.findSuperDeclaration
import org.jetbrains.kotlin.backend.jvm.ir.getSingleAbstractMethod
import org.jetbrains.kotlin.backend.jvm.ir.isCompiledToJvmDefault
import org.jetbrains.kotlin.backend.jvm.lower.findInterfaceImplementation
@@ -26,6 +27,7 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
@@ -78,6 +80,7 @@ internal class LambdaMetafactoryArgumentsBuilder(
// TODO in cases where LambdaMetafactory is unusable directly due to problems with the implementation function,
// we can still avoid generating an entire class by converting the function reference into a lambda first;
// see `InlineCallableReferenceToLambdaPhase`
val implFun = reference.symbol.owner
// Don't generate references to intrinsic functions as invokedynamic (no such method exists at run-time).
@@ -97,6 +100,18 @@ internal class LambdaMetafactoryArgumentsBuilder(
return null
}
// It's possible to reference through a child class a method declared in a package-private base Java class.
// In this case the corresponding method might be inaccessible in the context where it's referenced (see KT-48954).
// For now, just prohibit referencing methods from package-private Java classes through indy (without precise accessibility check).
// TODO wrap into lambda?
if (implFun is IrSimpleFunction) {
val baseFun = findSuperDeclaration(implFun, false, context.state.jvmDefaultMode)
val baseFunClass = baseFun.parent as? IrClass
if (baseFunClass != null && baseFunClass.visibility == JavaDescriptorVisibilities.PACKAGE_VISIBILITY) {
return null
}
}
val implFunParent = implFun.parent
if (implFunParent is IrClass && implFunParent.origin == IrDeclarationOrigin.JVM_MULTIFILE_CLASS) {
// LambdaMetafactory treats multifile class part members as non-accessible,
@@ -428,29 +428,8 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
fun mapCalleeToAsmMethod(function: IrSimpleFunction, isSuperCall: Boolean = false): Method =
mapAsmMethod(findSuperDeclaration(function, isSuperCall))
// Copied from KotlinTypeMapper.findSuperDeclaration.
internal fun findSuperDeclaration(function: IrSimpleFunction, isSuperCall: Boolean): IrSimpleFunction {
var current = function
while (current.isFakeOverride) {
// TODO: probably isJvmInterface instead of isInterface, here and in KotlinTypeMapper
val classCallable = current.overriddenSymbols.firstOrNull { !it.owner.parentAsClass.isInterface }?.owner
if (classCallable != null) {
current = classCallable
continue
}
if (isSuperCall && !current.parentAsClass.isInterface &&
current.resolveFakeOverride()?.run {
isMethodOfAny() || !isCompiledToJvmDefault(context.state.jvmDefaultMode)
} == true
) {
return current
}
current = current.overriddenSymbols.firstOrNull()?.owner
?: error("Fake override should have at least one overridden descriptor: ${current.render()}")
}
return current
}
private fun findSuperDeclaration(function: IrSimpleFunction, isSuperCall: Boolean): IrSimpleFunction =
findSuperDeclaration(function, isSuperCall, context.state.jvmDefaultMode)
private fun getJvmMethodNameIfSpecial(irFunction: IrSimpleFunction): String? {
if (irFunction.origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT) {
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.jvm.intrinsics
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.codegen.*
import org.jetbrains.kotlin.backend.jvm.ir.findSuperDeclaration
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
@@ -106,7 +107,7 @@ object JvmInvokeDynamic : IntrinsicMethod() {
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)
findSuperDeclaration(irFun0, false, codegen.state.jvmDefaultMode)
}
else ->
throw java.lang.AssertionError("Simple function or constructor expected: ${irFun0.render()}")
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.backend.jvm.ir
import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny
import org.jetbrains.kotlin.backend.common.lower.at
import org.jetbrains.kotlin.backend.common.lower.irNot
import org.jetbrains.kotlin.backend.jvm.CachedFieldsForObjectInstances
@@ -395,3 +396,26 @@ fun IrDeclarationParent.getCallableReferenceOwnerKClassType(context: JvmBackendC
fun IrDeclaration.getCallableReferenceTopLevelFlag(): Int =
if (parent.let { it is IrClass && it.isFileClass }) 1 else 0
// Based on KotlinTypeMapper.findSuperDeclaration.
fun findSuperDeclaration(function: IrSimpleFunction, isSuperCall: Boolean, jvmDefaultMode: JvmDefaultMode): IrSimpleFunction {
var current = function
while (current.isFakeOverride) {
// TODO: probably isJvmInterface instead of isInterface, here and in KotlinTypeMapper
val classCallable = current.overriddenSymbols.firstOrNull { !it.owner.parentAsClass.isInterface }?.owner
if (classCallable != null) {
current = classCallable
continue
}
if (isSuperCall && !current.parentAsClass.isInterface) {
val overridden = current.resolveFakeOverride()
if (overridden != null && (overridden.isMethodOfAny() || !overridden.isCompiledToJvmDefault(jvmDefaultMode))) {
return current
}
}
current = current.overriddenSymbols.firstOrNull()?.owner
?: error("Fake override should have at least one overridden descriptor: ${current.render()}")
}
return current
}
@@ -0,0 +1,41 @@
// TARGET_BACKEND: JVM
// FULL_JDK
// JVM_TARGET: 1.8
// FILE: kt48954.kt
import lib.*
import app.*
fun box(): String {
val foo = Foo()
Service(foo::bar).test()
return foo.p
}
// FILE: app/Service.kt
package app
import java.util.function.Consumer
class Service(private val consumer: Consumer<String>) {
fun test() {
consumer.accept("OK")
}
}
// FILE: lib/PackagePrivateBase.java
package lib;
class PackagePrivateBase {
public String p;
public void bar(String param) {
this.p = param;
}
}
// FILE: lib/Foo.java
package lib;
public class Foo extends PackagePrivateBase {
}
@@ -42036,6 +42036,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/syntheticAccessors/kt48331.kt");
}
@Test
@TestMetadata("kt48954.kt")
public void testKt48954() throws Exception {
runTest("compiler/testData/codegen/box/syntheticAccessors/kt48954.kt");
}
@Test
@TestMetadata("kt9717.kt")
public void testKt9717() throws Exception {
@@ -42192,6 +42192,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/syntheticAccessors/kt48331.kt");
}
@Test
@TestMetadata("kt48954.kt")
public void testKt48954() throws Exception {
runTest("compiler/testData/codegen/box/syntheticAccessors/kt48954.kt");
}
@Test
@TestMetadata("kt9717.kt")
public void testKt9717() throws Exception {
@@ -33839,6 +33839,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/syntheticAccessors/kt48331.kt");
}
@TestMetadata("kt48954.kt")
public void testKt48954() throws Exception {
runTest("compiler/testData/codegen/box/syntheticAccessors/kt48954.kt");
}
@TestMetadata("kt9717.kt")
public void testKt9717() throws Exception {
runTest("compiler/testData/codegen/box/syntheticAccessors/kt9717.kt");