JVM_IR KT-46562 don't use LambdaMetafactory for Serializable SAMs
TODO support serializable lambdas creation with LambdaMetafactory
This commit is contained in:
+12
@@ -20931,6 +20931,18 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/samExtFunWithCapturingLambda.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/samExtFunWithCapturingLambda.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("serializableSam1.kt")
|
||||||
|
public void testSerializableSam1() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/serializableSam1.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("serializableSam2.kt")
|
||||||
|
public void testSerializableSam2() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/serializableSam2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("simpleFunInterfaceConstructor.kt")
|
@TestMetadata("simpleFunInterfaceConstructor.kt")
|
||||||
public void testSimpleFunInterfaceConstructor() throws Exception {
|
public void testSimpleFunInterfaceConstructor() throws Exception {
|
||||||
|
|||||||
@@ -143,8 +143,24 @@ private fun collectAllSupertypes(irType: IrSimpleType, result: MutableSet<IrSimp
|
|||||||
// for the class C, this function constructs:
|
// for the class C, this function constructs:
|
||||||
// { B<List<Z>>, A<List<List<Z>>, Any }
|
// { B<List<Z>>, A<List<List<Z>>, Any }
|
||||||
// where Z is a type parameter of class C.
|
// where Z is a type parameter of class C.
|
||||||
fun getAllSubstitutedSupertypes(irClass: IrClass): MutableSet<IrSimpleType> {
|
fun getAllSubstitutedSupertypes(irClass: IrClass): Set<IrSimpleType> {
|
||||||
val result = HashSet<IrSimpleType>()
|
val result = HashSet<IrSimpleType>()
|
||||||
collectAllSupertypes(irClass.defaultType, result)
|
collectAllSupertypes(irClass.defaultType, result)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun collectAllSuperclasses(irClass: IrClass, set: MutableSet<IrClass>) {
|
||||||
|
for (superType in irClass.superTypes) {
|
||||||
|
val classifier = superType.classifierOrNull as? IrClassSymbol ?: continue
|
||||||
|
val superClass = classifier.owner
|
||||||
|
if (set.add(superClass)) {
|
||||||
|
collectAllSuperclasses(superClass, set)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrClass.getAllSuperclasses(): Set<IrClass> {
|
||||||
|
val result = HashSet<IrClass>()
|
||||||
|
collectAllSuperclasses(this, result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|||||||
+12
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.ir.types.*
|
|||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
@@ -59,6 +60,11 @@ internal class LambdaMetafactoryArgumentsBuilder(
|
|||||||
if (!reference.origin.isLambda && !samClass.isFromJava())
|
if (!reference.origin.isLambda && !samClass.isFromJava())
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
// Don't use JDK LambdaMetafactory for serializable lambdas
|
||||||
|
// TODO implement support for serializable lambdas with LambdaMetafactory (requires additional code for deserialization)
|
||||||
|
if (samClass.isInheritedFromSerializable())
|
||||||
|
return null
|
||||||
|
|
||||||
val samMethod = samClass.getSingleAbstractMethod()
|
val samMethod = samClass.getSingleAbstractMethod()
|
||||||
?: throw AssertionError("SAM class has no single abstract method: ${samClass.render()}")
|
?: throw AssertionError("SAM class has no single abstract method: ${samClass.render()}")
|
||||||
|
|
||||||
@@ -122,6 +128,12 @@ internal class LambdaMetafactoryArgumentsBuilder(
|
|||||||
return getLambdaMetafactoryArgsOrNullInner(reference, samMethod, samType, implFun)
|
return getLambdaMetafactoryArgsOrNullInner(reference, samMethod, samType, implFun)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val javaIoSerializableFqn =
|
||||||
|
FqName("java.io").child(Name.identifier("Serializable"))
|
||||||
|
|
||||||
|
private fun IrClass.isInheritedFromSerializable(): Boolean =
|
||||||
|
getAllSuperclasses().any { it.fqNameWhenAvailable == javaIoSerializableFqn }
|
||||||
|
|
||||||
private fun IrClass.requiresDelegationToDefaultImpls(): Boolean {
|
private fun IrClass.requiresDelegationToDefaultImpls(): Boolean {
|
||||||
for (irMemberFun in functions) {
|
for (irMemberFun in functions) {
|
||||||
if (irMemberFun.modality == Modality.ABSTRACT)
|
if (irMemberFun.modality == Modality.ABSTRACT)
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
// FULL_JDK
|
||||||
|
|
||||||
|
// CHECK_BYTECODE_TEXT
|
||||||
|
// JVM_IR_TEMPLATES
|
||||||
|
// 0 java/lang/invoke/LambdaMetafactory
|
||||||
|
|
||||||
|
// FILE: serializableSam1.kt
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.ObjectInputStream
|
||||||
|
import java.io.ObjectOutputStream
|
||||||
|
|
||||||
|
fun roundtrip(r: Ok): String {
|
||||||
|
val output = ByteArrayOutputStream()
|
||||||
|
ObjectOutputStream(output).writeObject(r)
|
||||||
|
val input = ByteArrayInputStream(output.toByteArray())
|
||||||
|
val rr = ObjectInputStream(input).readObject() as Ok
|
||||||
|
return rr.ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = roundtrip { "OK" }
|
||||||
|
|
||||||
|
// FILE: Ok.java
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public interface Ok extends Serializable {
|
||||||
|
String ok();
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// SAM_CONVERSIONS: INDY
|
||||||
|
// FULL_JDK
|
||||||
|
|
||||||
|
// CHECK_BYTECODE_TEXT
|
||||||
|
// JVM_IR_TEMPLATES
|
||||||
|
// 0 java/lang/invoke/LambdaMetafactory
|
||||||
|
|
||||||
|
// FILE: serializableSam2.kt
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.ObjectInputStream
|
||||||
|
import java.io.ObjectOutputStream
|
||||||
|
|
||||||
|
fun roundtrip(r: Ok): String {
|
||||||
|
val output = ByteArrayOutputStream()
|
||||||
|
ObjectOutputStream(output).writeObject(r)
|
||||||
|
val input = ByteArrayInputStream(output.toByteArray())
|
||||||
|
val rr = ObjectInputStream(input).readObject() as Ok
|
||||||
|
return rr.ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = roundtrip { "OK" }
|
||||||
|
|
||||||
|
// FILE: Ok.java
|
||||||
|
public interface Ok extends Base, Marker {}
|
||||||
|
|
||||||
|
// FILE: Base.java
|
||||||
|
public interface Base {
|
||||||
|
String ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: Marker.java
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public interface Marker extends Serializable {}
|
||||||
+12
@@ -20907,6 +20907,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/samExtFunWithCapturingLambda.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/samExtFunWithCapturingLambda.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("serializableSam1.kt")
|
||||||
|
public void testSerializableSam1() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/serializableSam1.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("serializableSam2.kt")
|
||||||
|
public void testSerializableSam2() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/serializableSam2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("simpleFunInterfaceConstructor.kt")
|
@TestMetadata("simpleFunInterfaceConstructor.kt")
|
||||||
public void testSimpleFunInterfaceConstructor() throws Exception {
|
public void testSimpleFunInterfaceConstructor() throws Exception {
|
||||||
|
|||||||
+12
@@ -20931,6 +20931,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/samExtFunWithCapturingLambda.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/samExtFunWithCapturingLambda.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("serializableSam1.kt")
|
||||||
|
public void testSerializableSam1() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/serializableSam1.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("serializableSam2.kt")
|
||||||
|
public void testSerializableSam2() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/serializableSam2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("simpleFunInterfaceConstructor.kt")
|
@TestMetadata("simpleFunInterfaceConstructor.kt")
|
||||||
public void testSimpleFunInterfaceConstructor() throws Exception {
|
public void testSimpleFunInterfaceConstructor() throws Exception {
|
||||||
|
|||||||
+10
@@ -17478,6 +17478,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/samExtFunWithCapturingLambda.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/samExtFunWithCapturingLambda.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("serializableSam1.kt")
|
||||||
|
public void testSerializableSam1() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/serializableSam1.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("serializableSam2.kt")
|
||||||
|
public void testSerializableSam2() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/serializableSam2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simpleFunInterfaceConstructor.kt")
|
@TestMetadata("simpleFunInterfaceConstructor.kt")
|
||||||
public void testSimpleFunInterfaceConstructor() throws Exception {
|
public void testSimpleFunInterfaceConstructor() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleFunInterfaceConstructor.kt");
|
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleFunInterfaceConstructor.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user