JVM: Only produce inline SAM wrappers in public inline scope

This commit is contained in:
Steven Schäfer
2021-01-26 18:20:44 +01:00
committed by Alexander Udalov
parent 50bbf4f269
commit c9b0cc5b32
16 changed files with 204 additions and 11 deletions
@@ -38,8 +38,7 @@ class SamWrapperClasses(private val state: GenerationState) {
contextDescriptor: CallableMemberDescriptor
): Type {
val parentContext = expressionCodegen.context
val isInsideInline = InlineUtil.isInlineOrContainingInline(parentContext.contextDescriptor) ||
isInsideInlineLambdaContext(parentContext, state)
val isInsideInline = InlineUtil.isInPublicInlineScope(parentContext.contextDescriptor)
return samInterfaceToWrapperClass.getOrPut(WrapperKey(samType, file, isInsideInline)) {
SamWrapperCodegen(state, samType, expressionCodegen.parentCodegen, parentContext, isInsideInline)
.genWrapper(file, contextDescriptor)
@@ -224,7 +224,7 @@ internal fun isSamWrapperConstructorCall(internalName: String, methodName: Strin
isConstructor(methodName) && isSamWrapper(internalName)
internal fun isAnonymousClass(internalName: String) =
!isSamWrapper(internalName) &&
!internalName.contains("\$sam\$") &&
internalName.substringAfterLast('/').substringAfterLast("$", "").isInteger()
fun wrapWithMaxLocalCalc(methodNode: MethodNode) =
@@ -4996,6 +4996,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda.kt");
}
@Test
@TestMetadata("samWrapperInInlineLambda2.kt")
public void testSamWrapperInInlineLambda2() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda2.kt");
}
@Test
@TestMetadata("samWrapperOfLambda.kt")
public void testSamWrapperOfLambda() throws Exception {
@@ -10,12 +10,14 @@ import org.jetbrains.kotlin.backend.common.lower.SingleAbstractMethodLowering
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
import org.jetbrains.kotlin.backend.jvm.ir.isInPublicInlineScope
import org.jetbrains.kotlin.backend.jvm.ir.rawType
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.declarations.IrFunctionBuilder
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
@@ -31,14 +33,8 @@ internal val singleAbstractMethodPhase = makeIrFilePhase(
)
private class JvmSingleAbstractMethodLowering(context: JvmBackendContext) : SingleAbstractMethodLowering(context) {
// The JVM BE produces inline SAM wrappers both in the scope of an inline function as well as in the scope
// of an inline lambda. Compare with `SamWrapperClasses.getSamWrapperClass`.
override val inInlineFunctionScope: Boolean
get() = allScopes.any { scope ->
scope.irElement.safeAs<IrFunction>()?.let {
it.isInline || it.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
} ?: false
}
get() = allScopes.any { it.irElement.safeAs<IrDeclaration>()?.isInPublicInlineScope == true }
override fun getWrapperVisibility(expression: IrTypeOperatorCall, scopes: List<ScopeWithIr>) =
if (inInlineFunctionScope) DescriptorVisibilities.PUBLIC else JavaDescriptorVisibilities.PACKAGE_VISIBILITY
@@ -0,0 +1,10 @@
// KOTLIN_CONFIGURATION_FLAGS: SAM_CONVERSIONS=CLASS
// WITH_SIGNATURES
package test
// SAM adapters inside of private inline functions don't need to be public,
// since we do not refer to them from other packages.
fun test() {
val lambda = { }
1.apply { Runnable(lambda) }
}
@@ -0,0 +1,28 @@
@kotlin.Metadata
synthetic final class<null> test/PrivateInlineSamAdapterKt$sam$java_lang_Runnable$0 {
// source: 'privateInlineSamAdapter.kt'
<null> method <init>(p0: kotlin.jvm.functions.Function0): void
public synthetic final <null> method run(): void
enclosing method test/PrivateInlineSamAdapterKt.test()V
private synthetic final field <null> function: kotlin.jvm.functions.Function0
inner (anonymous) class test/PrivateInlineSamAdapterKt$sam$java_lang_Runnable$0
}
@kotlin.Metadata
final class<Lkotlin/jvm/internal/Lambda;Lkotlin/jvm/functions/Function0<Lkotlin/Unit;>;> test/PrivateInlineSamAdapterKt$test$lambda$1 {
// source: 'privateInlineSamAdapter.kt'
static <null> method <clinit>(): void
<null> method <init>(): void
public synthetic bridge <null> method invoke(): java.lang.Object
public final <null> method invoke(): void
enclosing method test/PrivateInlineSamAdapterKt.test()V
public final static field <null> INSTANCE: test.PrivateInlineSamAdapterKt$test$lambda$1
inner (anonymous) class test/PrivateInlineSamAdapterKt$test$lambda$1
}
@kotlin.Metadata
public final class<null> test/PrivateInlineSamAdapterKt {
// source: 'privateInlineSamAdapter.kt'
public final static <null> method test(): void
inner (anonymous) class test/PrivateInlineSamAdapterKt$test$lambda$1
}
@@ -0,0 +1,29 @@
@kotlin.Metadata
synthetic final class<null> test/PrivateInlineSamAdapterKt$sam$java_lang_Runnable$0 {
// source: 'privateInlineSamAdapter.kt'
<null> method <init>(p0: kotlin.jvm.functions.Function0): void
public synthetic final <null> method run(): void
enclosing class test/PrivateInlineSamAdapterKt
private synthetic final field <null> function: kotlin.jvm.functions.Function0
inner (anonymous) class test/PrivateInlineSamAdapterKt$sam$java_lang_Runnable$0
}
@kotlin.Metadata
final class<Lkotlin/jvm/internal/Lambda;Lkotlin/jvm/functions/Function0<Lkotlin/Unit;>;> test/PrivateInlineSamAdapterKt$test$lambda$1 {
// source: 'privateInlineSamAdapter.kt'
static <null> method <clinit>(): void
<null> method <init>(): void
public synthetic bridge <null> method invoke(): java.lang.Object
public final <null> method invoke(): void
enclosing method test/PrivateInlineSamAdapterKt.test()V
public final static field <null> INSTANCE: test.PrivateInlineSamAdapterKt$test$lambda$1
inner (anonymous) class test/PrivateInlineSamAdapterKt$test$lambda$1
}
@kotlin.Metadata
public final class<null> test/PrivateInlineSamAdapterKt {
// source: 'privateInlineSamAdapter.kt'
public final static <null> method test(): void
inner (anonymous) class test/PrivateInlineSamAdapterKt$sam$java_lang_Runnable$0
inner (anonymous) class test/PrivateInlineSamAdapterKt$test$lambda$1
}
@@ -0,0 +1,11 @@
// KOTLIN_CONFIGURATION_FLAGS: SAM_CONVERSIONS=CLASS
// WITH_SIGNATURES
package test
// We used to generate SAM adapters inside of inline lambdas as
// inline SAM wrappers (`...$sam$i$...`). This is unnecessary, unless
// the code is itself contained in an inline function.
fun test() {
val lambda = { }
1.apply { Runnable(lambda) }
}
@@ -0,0 +1,28 @@
@kotlin.Metadata
synthetic final class<null> test/SamAdapterInInlineLambdaKt$sam$java_lang_Runnable$0 {
// source: 'samAdapterInInlineLambda.kt'
<null> method <init>(p0: kotlin.jvm.functions.Function0): void
public synthetic final <null> method run(): void
enclosing method test/SamAdapterInInlineLambdaKt.test()V
private synthetic final field <null> function: kotlin.jvm.functions.Function0
inner (anonymous) class test/SamAdapterInInlineLambdaKt$sam$java_lang_Runnable$0
}
@kotlin.Metadata
final class<Lkotlin/jvm/internal/Lambda;Lkotlin/jvm/functions/Function0<Lkotlin/Unit;>;> test/SamAdapterInInlineLambdaKt$test$lambda$1 {
// source: 'samAdapterInInlineLambda.kt'
static <null> method <clinit>(): void
<null> method <init>(): void
public synthetic bridge <null> method invoke(): java.lang.Object
public final <null> method invoke(): void
enclosing method test/SamAdapterInInlineLambdaKt.test()V
public final static field <null> INSTANCE: test.SamAdapterInInlineLambdaKt$test$lambda$1
inner (anonymous) class test/SamAdapterInInlineLambdaKt$test$lambda$1
}
@kotlin.Metadata
public final class<null> test/SamAdapterInInlineLambdaKt {
// source: 'samAdapterInInlineLambda.kt'
public final static <null> method test(): void
inner (anonymous) class test/SamAdapterInInlineLambdaKt$test$lambda$1
}
@@ -0,0 +1,29 @@
@kotlin.Metadata
synthetic final class<null> test/SamAdapterInInlineLambdaKt$sam$java_lang_Runnable$0 {
// source: 'samAdapterInInlineLambda.kt'
<null> method <init>(p0: kotlin.jvm.functions.Function0): void
public synthetic final <null> method run(): void
enclosing class test/SamAdapterInInlineLambdaKt
private synthetic final field <null> function: kotlin.jvm.functions.Function0
inner (anonymous) class test/SamAdapterInInlineLambdaKt$sam$java_lang_Runnable$0
}
@kotlin.Metadata
final class<Lkotlin/jvm/internal/Lambda;Lkotlin/jvm/functions/Function0<Lkotlin/Unit;>;> test/SamAdapterInInlineLambdaKt$test$lambda$1 {
// source: 'samAdapterInInlineLambda.kt'
static <null> method <clinit>(): void
<null> method <init>(): void
public synthetic bridge <null> method invoke(): java.lang.Object
public final <null> method invoke(): void
enclosing method test/SamAdapterInInlineLambdaKt.test()V
public final static field <null> INSTANCE: test.SamAdapterInInlineLambdaKt$test$lambda$1
inner (anonymous) class test/SamAdapterInInlineLambdaKt$test$lambda$1
}
@kotlin.Metadata
public final class<null> test/SamAdapterInInlineLambdaKt {
// source: 'samAdapterInInlineLambda.kt'
public final static <null> method test(): void
inner (anonymous) class test/SamAdapterInInlineLambdaKt$sam$java_lang_Runnable$0
inner (anonymous) class test/SamAdapterInInlineLambdaKt$test$lambda$1
}
@@ -16,4 +16,5 @@ fun box(): String {
return result
}
// 1 INVOKESPECIAL TestKt\$sam\$i\$java_lang_Runnable\$0.<init> \(Lkotlin/jvm/functions/Function0;\)V
// 1 INVOKESPECIAL TestKt\$sam\$java_lang_Runnable\$0.<init> \(Lkotlin/jvm/functions/Function0;\)V
// 0 INVOKESPECIAL TestKt\$sam\$i\$java_lang_Runnable\$0.<init> \(Lkotlin/jvm/functions/Function0;\)V
@@ -0,0 +1,20 @@
// SAM_CONVERSIONS: CLASS
// FILE: J.java
public class J {
public static void g(Runnable r) {
r.run();
}
}
// FILE: test.kt
inline fun box(): String {
var result = "Fail"
val setter = { result = "OK" }
1.apply { J.g(setter) }
return result
}
// 0 INVOKESPECIAL TestKt\$sam\$java_lang_Runnable\$0.<init> \(Lkotlin/jvm/functions/Function0;\)V
// 1 INVOKESPECIAL TestKt\$sam\$i\$java_lang_Runnable\$0.<init> \(Lkotlin/jvm/functions/Function0;\)V
@@ -2052,6 +2052,12 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
runTest("compiler/testData/codegen/bytecodeListing/sam/nonApproxToValidSupertype2.kt");
}
@Test
@TestMetadata("privateInlineSamAdapter.kt")
public void testPrivateInlineSamAdapter() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/sam/privateInlineSamAdapter.kt");
}
@Test
@TestMetadata("reusedSamWrapperClasses.kt")
public void testReusedSamWrapperClasses() throws Exception {
@@ -2064,6 +2070,12 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
runTest("compiler/testData/codegen/bytecodeListing/sam/samAdapterAndInlinedOne.kt");
}
@Test
@TestMetadata("samAdapterInInlineLambda.kt")
public void testSamAdapterInInlineLambda() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/sam/samAdapterInInlineLambda.kt");
}
@Test
@TestMetadata("specializedFunInterface.kt")
public void testSpecializedFunInterface() throws Exception {
@@ -4852,6 +4852,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda.kt");
}
@Test
@TestMetadata("samWrapperInInlineLambda2.kt")
public void testSamWrapperInInlineLambda2() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda2.kt");
}
@Test
@TestMetadata("samWrapperOfLambda.kt")
public void testSamWrapperOfLambda() throws Exception {
@@ -2100,6 +2100,12 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
runTest("compiler/testData/codegen/bytecodeListing/sam/nonApproxToValidSupertype2.kt");
}
@Test
@TestMetadata("privateInlineSamAdapter.kt")
public void testPrivateInlineSamAdapter() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/sam/privateInlineSamAdapter.kt");
}
@Test
@TestMetadata("reusedSamWrapperClasses.kt")
public void testReusedSamWrapperClasses() throws Exception {
@@ -2112,6 +2118,12 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
runTest("compiler/testData/codegen/bytecodeListing/sam/samAdapterAndInlinedOne.kt");
}
@Test
@TestMetadata("samAdapterInInlineLambda.kt")
public void testSamAdapterInInlineLambda() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/sam/samAdapterInInlineLambda.kt");
}
@Test
@TestMetadata("specializedFunInterface.kt")
public void testSpecializedFunInterface() throws Exception {
@@ -4996,6 +4996,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda.kt");
}
@Test
@TestMetadata("samWrapperInInlineLambda2.kt")
public void testSamWrapperInInlineLambda2() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda2.kt");
}
@Test
@TestMetadata("samWrapperOfLambda.kt")
public void testSamWrapperOfLambda() throws Exception {