JVM_IR: do not use invokedynamic for inline fun references

This commit is contained in:
pyos
2021-06-01 11:52:30 +02:00
committed by Dmitry Petrov
parent 5d53d34d85
commit 4128d27510
2 changed files with 18 additions and 8 deletions
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.inline.INLINE_ONLY_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.addIfNotNull
@@ -76,20 +75,25 @@ internal class LambdaMetafactoryArgumentsBuilder(
if (samClass.requiresDelegationToDefaultImpls())
return null
// 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).
if (context.irIntrinsics.getIntrinsic(implFun.symbol) != null)
return null
// Don't generate reference to inlineOnly methods as those do not exist at runtime.
if (implFun.hasAnnotation(INLINE_ONLY_ANNOTATION_FQ_NAME))
// Can't use invokedynamic if the referenced function has to be inlined for correct semantics
// Also in some cases like `private inline fun` we'd need accessors, which `SyntheticAccessorLowering`
// won't generate under the assumption that the inline function will be inlined. Plus if the function
// is in a different module we should probably copy it anyway (and regenerate all objects in it).
if (implFun.isInline)
return null
if (implFun is IrConstructor && implFun.visibility.isPrivate) {
// Kotlin generates constructor accessors differently from Java.
// TODO more precise accessibility check (see SyntheticAccessorLowering::isAccessible)
// TODO wrap inaccessible constructor with a local function
return null
}
@@ -10,11 +10,17 @@
import java.util.function.Consumer
fun call(c: Consumer<String>) {
}
inline fun <reified T> f(x: T) =
println("${T::class.simpleName}($x)")
private inline fun g(x: String) = println(x)
fun call(c: Consumer<String>) = c.accept("")
fun box(): String {
// println is inline only and therefore we cannot use invoke-dynamic to target it.
call(::println)
call(::println) // `println` is `@InlineOnly`
call(::f) // `f` has a reified type parameter and thus isn't callable directly
val obj = { call(::g) } // `g` is inaccessible in this scope
obj()
return "OK"
}