JVM_IR serializable indy method references

This commit is contained in:
Dmitry Petrov
2021-10-18 12:46:58 +03:00
committed by teamcityserver
parent eec16b83c6
commit 1dbbe22c8c
38 changed files with 1960 additions and 221 deletions
@@ -23001,6 +23001,154 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
}
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/invokedynamic/serializable")
@TestDataPath("$PROJECT_ROOT")
public class Serializable {
@Test
public void testAllFilesPresentInSerializable() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/serializable"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("multipleTopLevelFunRefs.kt")
public void testMultipleTopLevelFunRefs() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/multipleTopLevelFunRefs.kt");
}
@Test
@TestMetadata("sameImplMethodDifferentInterfaces.kt")
public void testSameImplMethodDifferentInterfaces() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/sameImplMethodDifferentInterfaces.kt");
}
@Test
@TestMetadata("serializableBoundClassMemberFunRef.kt")
public void testSerializableBoundClassMemberFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundClassMemberFunRef.kt");
}
@Test
@TestMetadata("serializableBoundInnerConstructorRef.kt")
public void testSerializableBoundInnerConstructorRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundInnerConstructorRef.kt");
}
@Test
@TestMetadata("serializableBoundInterfaceMemberFunRef.kt")
public void testSerializableBoundInterfaceMemberFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundInterfaceMemberFunRef.kt");
}
@Test
@TestMetadata("serializableBoundTopLevelExtensionFunRef.kt")
public void testSerializableBoundTopLevelExtensionFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundTopLevelExtensionFunRef.kt");
}
@Test
@TestMetadata("serializableBoundTopLevelExtensionFunRefPrimitiveReceiver.kt")
public void testSerializableBoundTopLevelExtensionFunRefPrimitiveReceiver() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundTopLevelExtensionFunRefPrimitiveReceiver.kt");
}
@Test
@TestMetadata("serializableClassMemberFunRef.kt")
public void testSerializableClassMemberFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableClassMemberFunRef.kt");
}
@Test
@TestMetadata("serializableConstructorRef.kt")
public void testSerializableConstructorRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableConstructorRef.kt");
}
@Test
@TestMetadata("serializableFakeOverrideFunRef.kt")
public void testSerializableFakeOverrideFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableFakeOverrideFunRef.kt");
}
@Test
@TestMetadata("serializableInnerConstructorRef.kt")
public void testSerializableInnerConstructorRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableInnerConstructorRef.kt");
}
@Test
@TestMetadata("serializableInterfaceMemberFunRef.kt")
public void testSerializableInterfaceMemberFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableInterfaceMemberFunRef.kt");
}
@Test
@TestMetadata("serializableJavaStaticMethodRef.kt")
public void testSerializableJavaStaticMethodRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableJavaStaticMethodRef.kt");
}
@Test
@TestMetadata("serializableLambda.kt")
public void testSerializableLambda() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambda.kt");
}
@Test
@TestMetadata("serializableLambdaCapturingBoxedInlineClassAny.kt")
public void testSerializableLambdaCapturingBoxedInlineClassAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaCapturingBoxedInlineClassAny.kt");
}
@Test
@TestMetadata("serializableLambdaCapturingInlineClassAny.kt")
public void testSerializableLambdaCapturingInlineClassAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaCapturingInlineClassAny.kt");
}
@Test
@TestMetadata("serializableLambdaCapturingInlineClassInt.kt")
public void testSerializableLambdaCapturingInlineClassInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaCapturingInlineClassInt.kt");
}
@Test
@TestMetadata("serializableLambdaCapturingNullableInlineClassAny.kt")
public void testSerializableLambdaCapturingNullableInlineClassAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaCapturingNullableInlineClassAny.kt");
}
@Test
@TestMetadata("serializableLambdaToKotlinInterface.kt")
public void testSerializableLambdaToKotlinInterface() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaToKotlinInterface.kt");
}
@Test
@TestMetadata("serializableLambdaWithCapture.kt")
public void testSerializableLambdaWithCapture() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaWithCapture.kt");
}
@Test
@TestMetadata("serializableTopLevelFunRef.kt")
public void testSerializableTopLevelFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableTopLevelFunRef.kt");
}
@Test
@TestMetadata("serializableTopLevelFunRefAsGenericInterface.kt")
public void testSerializableTopLevelFunRefAsGenericInterface() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableTopLevelFunRefAsGenericInterface.kt");
}
@Test
@TestMetadata("serializableWithBridge.kt")
public void testSerializableWithBridge() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableWithBridge.kt");
}
}
}
@Nested
@@ -504,6 +504,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
putValueArgument(1, lambdaMetafactoryArguments.implMethodReference)
putValueArgument(2, irRawFunctionRef(lambdaMetafactoryArguments.fakeInstanceMethod))
putValueArgument(3, irVarargOfRawFunctionRefs(lambdaMetafactoryArguments.extraOverriddenMethods))
putValueArgument(4, irBoolean(lambdaMetafactoryArguments.shouldBeSerializable))
}
}
}
@@ -10,12 +10,20 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.IrBuildingTransformer
import org.jetbrains.kotlin.backend.common.lower.at
import org.jetbrains.kotlin.backend.common.lower.irNot
import org.jetbrains.kotlin.backend.common.lower.irThrow
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.codegen.fileParent
import org.jetbrains.kotlin.backend.jvm.intrinsics.generateMethodHandle
import org.jetbrains.kotlin.backend.jvm.intrinsics.getBooleanConstArgument
import org.jetbrains.kotlin.backend.jvm.ir.*
import org.jetbrains.kotlin.backend.jvm.unboxInlineClass
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
@@ -26,13 +34,11 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.Handle
import org.jetbrains.org.objectweb.asm.Opcodes
@@ -101,35 +107,29 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
private val jvmIndyLambdaMetafactoryIntrinsic = context.ir.symbols.indyLambdaMetafactoryIntrinsic
private val indyIntrinsic = context.ir.symbols.jvmIndyIntrinsic
private fun JvmIrBuilder.jvmMethodHandle(handle: Handle) =
irCall(backendContext.ir.symbols.jvmMethodHandle).apply {
putValueArgument(0, irInt(handle.tag))
putValueArgument(1, irString(handle.owner))
putValueArgument(2, irString(handle.name))
putValueArgument(3, irString(handle.desc))
putValueArgument(4, irBoolean(handle.isInterface))
}
private fun IrBuilderWithScope.jvmInvokeDynamic(
private fun JvmIrBuilder.jvmInvokeDynamic(
dynamicCall: IrCall,
bootstrapMethod: Handle,
bootstrapMethodHandle: Handle,
bootstrapMethodArguments: List<IrExpression>
) =
irCall(indyIntrinsic, dynamicCall.type).apply {
irCall(backendContext.ir.symbols.jvmIndyIntrinsic, dynamicCall.type).apply {
putTypeArgument(0, dynamicCall.type)
putValueArgument(0, dynamicCall)
putValueArgument(1, irInt(bootstrapMethod.tag))
putValueArgument(2, irString(bootstrapMethod.owner))
putValueArgument(3, irString(bootstrapMethod.name))
putValueArgument(4, irString(bootstrapMethod.desc))
putValueArgument(5, irVararg(context.irBuiltIns.anyType, bootstrapMethodArguments))
putValueArgument(1, jvmMethodHandle(bootstrapMethodHandle))
putValueArgument(2, irVararg(context.irBuiltIns.anyType, bootstrapMethodArguments))
}
private val originalMethodTypeIntrinsic = context.ir.symbols.jvmOriginalMethodTypeIntrinsic
private val substitutedMethodTypeIntrinsic = context.ir.symbols.jvmSubstitutedMethodTypeIntrinsic
private fun IrBuilderWithScope.jvmOriginalMethodType(methodSymbol: IrFunctionSymbol) =
irCall(originalMethodTypeIntrinsic, context.irBuiltIns.anyType).apply {
putValueArgument(0, irRawFunctionReferefence(context.irBuiltIns.anyType, methodSymbol))
}
@Suppress("unused")
private fun IrBuilderWithScope.jvmSubstitutedMethodType(ownerType: IrType, methodSymbol: IrFunctionSymbol) =
irCall(substitutedMethodTypeIntrinsic, context.irBuiltIns.anyType).apply {
putTypeArgument(0, ownerType)
private fun JvmIrBuilder.jvmOriginalMethodType(methodSymbol: IrFunctionSymbol) =
irCall(backendContext.ir.symbols.jvmOriginalMethodTypeIntrinsic, context.irBuiltIns.anyType).apply {
putValueArgument(0, irRawFunctionReferefence(context.irBuiltIns.anyType, methodSymbol))
}
@@ -179,6 +179,236 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
}
}
private class SerializableMethodRefInfo(
val samType: IrType,
val samMethodSymbol: IrSimpleFunctionSymbol,
val implFunSymbol: IrFunctionSymbol,
val instanceFunSymbol: IrFunctionSymbol,
val requiredBridges: Collection<IrSimpleFunction>,
val dynamicCallSymbol: IrSimpleFunctionSymbol
)
private class ClassContext {
val serializableMethodRefInfos = ArrayList<SerializableMethodRefInfo>()
}
private val classContextStack = ArrayDeque<ClassContext>()
private fun enterClass(): ClassContext {
return ClassContext().also {
classContextStack.push(it)
}
}
private fun leaveClass() {
classContextStack.pop()
}
private fun getClassContext(): ClassContext {
if (classContextStack.isEmpty()) {
throw AssertionError("No class context")
}
return classContextStack.last()
}
override fun visitClass(declaration: IrClass): IrStatement {
val context = enterClass()
val result = super.visitClass(declaration)
if (context.serializableMethodRefInfos.isNotEmpty()) {
generateDeserializeLambdaMethod(declaration, context.serializableMethodRefInfos)
}
leaveClass()
return result
}
private data class DeserializedLambdaInfo(
val functionalInterfaceClass: String,
val implMethodHandle: Handle,
val functionalInterfaceMethod: Method
)
private fun generateDeserializeLambdaMethod(
irClass: IrClass,
serializableMethodRefInfos: List<SerializableMethodRefInfo>
) {
// fun `$deserializeLambda$`(lambda: java.lang.invoke.SerializedLambda): Object {
// val tmp = lambda.getImplMethodName()
// when {
// ...
// tmp == NAME_i -> {
// when {
// ...
// lambda.getImplMethodKind() == [LAMBDA_i_k].implMethodKind &&
// lambda.getFunctionalInterfaceClass() == [LAMBDA_i_k].functionalInterfaceClass &&
// lambda.getFunctionalInterfaceMethodName() == [LAMBDA_i_k].functionalInterfaceMethodName &&
// lambda.getFunctionalInterfaceMethodSignature() == [LAMBDA_i_k].functionalInterfaceMethodSignature &&
// lambda.getImplClass() == [LAMBDA_i_k].implClass &&
// lambda.getImplMethodSignature() = [LAMBDA_i_k].implMethodSignature ->
// `<jvm-indy>`([LAMBDA_i_k])
// ...
// }
// }
// ...
// }
// throw IllegalArgumentException("Invalid lambda deserialization")
// }
val groupedByImplMethodName = HashMap<String, HashMap<DeserializedLambdaInfo, SerializableMethodRefInfo>>()
for (serializableMethodRefInfo in serializableMethodRefInfos) {
val deserializedLambdaInfo = mapDeserializedLambda(serializableMethodRefInfo)
val implMethodName = deserializedLambdaInfo.implMethodHandle.name
val byDeserializedLambdaInfo = groupedByImplMethodName.getOrPut(implMethodName) { HashMap() }
byDeserializedLambdaInfo[deserializedLambdaInfo] = serializableMethodRefInfo
}
val deserializeLambdaFun = context.irFactory.buildFun {
name = Name.identifier("\$deserializeLambda\$")
visibility = DescriptorVisibilities.PRIVATE
}
deserializeLambdaFun.parent = irClass
val lambdaParameter = deserializeLambdaFun.addValueParameter("lambda", context.ir.symbols.serializedLambda.irType)
deserializeLambdaFun.returnType = context.irBuiltIns.anyType
deserializeLambdaFun.body = context.createJvmIrBuilder(deserializeLambdaFun.symbol, UNDEFINED_OFFSET, UNDEFINED_OFFSET).run {
irBlockBody {
val tmp = irTemporary(
irCall(backendContext.ir.symbols.serializedLambda.getImplMethodName).apply {
dispatchReceiver = irGet(lambdaParameter)
}
)
+irWhen(
backendContext.irBuiltIns.unitType,
groupedByImplMethodName.entries.map { (implMethodName, infos) ->
irBranch(
irEquals(irGet(tmp), irString(implMethodName)),
irWhen(
backendContext.irBuiltIns.unitType,
infos.entries.map { (deserializedLambdaInfo, serializedMethodRefInfo) ->
irBranch(
generateSerializedLambdaEquals(lambdaParameter, deserializedLambdaInfo),
irReturn(generateCreateDeserializedMethodRef(lambdaParameter, serializedMethodRefInfo))
)
}
)
)
}
)
+irThrow(
irCall(backendContext.ir.symbols.illegalArgumentExceptionCtorString).also { ctorCall ->
ctorCall.putValueArgument(
0,
// Replace argument with:
// irCall(backendContext.irBuiltIns.anyClass.getSimpleFunction("toString")!!).apply {
// dispatchReceiver = irGet(lambdaParameter)
// }
// for debugging "Invalid lambda deserialization" exceptions.
irString("Invalid lambda deserialization")
)
}
)
}
}
irClass.declarations.add(deserializeLambdaFun)
}
private fun mapDeserializedLambda(info: SerializableMethodRefInfo) =
DeserializedLambdaInfo(
functionalInterfaceClass = context.typeMapper.mapType(info.samType).internalName,
implMethodHandle = generateMethodHandle(context, info.implFunSymbol.owner),
functionalInterfaceMethod = context.methodSignatureMapper.mapAsmMethod(info.samMethodSymbol.owner)
)
private fun JvmIrBuilder.generateSerializedLambdaEquals(
lambdaParameter: IrValueParameter,
deserializedLambdaInfo: DeserializedLambdaInfo
): IrExpression {
val functionalInterfaceClass = deserializedLambdaInfo.functionalInterfaceClass
val implMethodHandle = deserializedLambdaInfo.implMethodHandle
val samMethod = deserializedLambdaInfo.functionalInterfaceMethod
fun irGetLambdaProperty(getter: IrSimpleFunction) =
irCall(getter).apply { dispatchReceiver = irGet(lambdaParameter) }
return irAndAnd(
irEquals(
irGetLambdaProperty(backendContext.ir.symbols.serializedLambda.getImplMethodKind),
irInt(implMethodHandle.tag)
),
irObjectEquals(
irGetLambdaProperty(backendContext.ir.symbols.serializedLambda.getFunctionalInterfaceClass),
irString(functionalInterfaceClass)
),
irObjectEquals(
irGetLambdaProperty(backendContext.ir.symbols.serializedLambda.getFunctionalInterfaceMethodName),
irString(samMethod.name)
),
irObjectEquals(
irGetLambdaProperty(backendContext.ir.symbols.serializedLambda.getFunctionalInterfaceMethodSignature),
irString(samMethod.descriptor)
),
irObjectEquals(
irGetLambdaProperty(backendContext.ir.symbols.serializedLambda.getImplClass),
irString(implMethodHandle.owner)
),
irObjectEquals(
irGetLambdaProperty(backendContext.ir.symbols.serializedLambda.getImplMethodSignature),
irString(implMethodHandle.desc)
)
)
}
private val equalsAny = context.irBuiltIns.anyClass.getSimpleFunction("equals")!!
private fun JvmIrBuilder.irObjectEquals(receiver: IrExpression, arg: IrExpression) =
irCall(equalsAny).apply {
dispatchReceiver = receiver
putValueArgument(0, arg)
}
private fun JvmIrBuilder.irAndAnd(vararg args: IrExpression): IrExpression {
if (args.isEmpty()) throw AssertionError("At least one argument expected")
var result = args[0]
for (i in 1 until args.size) {
result = irCall(backendContext.irBuiltIns.andandSymbol).apply {
putValueArgument(0, result)
putValueArgument(1, args[i])
}
}
return result
}
private fun JvmIrBuilder.generateCreateDeserializedMethodRef(
lambdaParameter: IrValueParameter,
info: SerializableMethodRefInfo
): IrExpression {
val dynamicCall = irCall(info.dynamicCallSymbol)
for ((index, dynamicValueParameter) in info.dynamicCallSymbol.owner.valueParameters.withIndex()) {
val capturedArg = irCall(backendContext.ir.symbols.serializedLambda.getCapturedArg).also { call ->
call.dispatchReceiver = irGet(lambdaParameter)
call.putValueArgument(0, irInt(index))
}
val expectedType = dynamicValueParameter.type
val downcastArg =
if (expectedType.isInlineClassType()) {
// Inline class type arguments are stored as their underlying representation.
val unboxedType = expectedType.unboxInlineClass()
irCall(backendContext.ir.symbols.unsafeCoerceIntrinsic).also { coercion ->
coercion.putTypeArgument(0, unboxedType)
coercion.putTypeArgument(1, expectedType)
coercion.putValueArgument(0, capturedArg)
}
} else {
irAs(capturedArg, expectedType)
}
dynamicCall.putValueArgument(index, downcastArg)
}
return createLambdaMetafactoryCall(
info.samMethodSymbol, info.implFunSymbol, info.instanceFunSymbol, true, info.requiredBridges, dynamicCall
)
}
/**
* @see FunctionReferenceLowering.wrapWithIndySamConversion
*/
@@ -211,6 +441,8 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
}
}
val shouldBeSerializable = call.getBooleanConstArgument(4)
val samMethod = samMethodRef.symbol.owner as? IrSimpleFunction
?: fail("SAM method is expected to be 'IrSimpleFunction': ${samMethodRef.symbol.owner.render()}")
val instanceMethod = instanceMethodRef.symbol.owner as? IrSimpleFunction
@@ -220,30 +452,80 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
val requiredBridges = getOverriddenMethodsRequiringBridges(instanceMethod, samMethod, extraOverriddenMethods)
return context.createJvmIrBuilder(implFunSymbol, startOffset, endOffset).run {
val samMethodType = jvmOriginalMethodType(samMethod.symbol)
val irRawFunRef = irRawFunctionReferefence(implFunRef.type, implFunSymbol)
val instanceMethodType = jvmOriginalMethodType(instanceMethodRef.symbol)
if (shouldBeSerializable) {
getClassContext().serializableMethodRefInfos.add(
SerializableMethodRefInfo(
samType, samMethod.symbol, implFunSymbol, instanceMethodRef.symbol, requiredBridges, dynamicCall.symbol
)
)
}
if (requiredBridges.isNotEmpty()) {
val bridgeMethodTypes = requiredBridges.map { jvmOriginalMethodType(it.symbol) }
jvmInvokeDynamic(
dynamicCall,
jdkAltMetafactoryHandle,
listOf(
samMethodType, irRawFunRef, instanceMethodType,
irInt(LambdaMetafactory.FLAG_BRIDGES),
irInt(requiredBridges.size)
) + bridgeMethodTypes
)
} else {
jvmInvokeDynamic(
dynamicCall,
jdkMetafactoryHandle,
listOf(samMethodType, irRawFunRef, instanceMethodType)
)
return context.createJvmIrBuilder(implFunSymbol, startOffset, endOffset)
.createLambdaMetafactoryCall(
samMethod.symbol, implFunSymbol, instanceMethodRef.symbol, shouldBeSerializable, requiredBridges, dynamicCall
)
}
private fun JvmIrBuilder.createLambdaMetafactoryCall(
samMethodSymbol: IrSimpleFunctionSymbol,
implFunSymbol: IrFunctionSymbol,
instanceMethodSymbol: IrFunctionSymbol,
shouldBeSerializable: Boolean,
requiredBridges: Collection<IrSimpleFunction>,
dynamicCall: IrCall
): IrCall {
val samMethodType = jvmOriginalMethodType(samMethodSymbol)
val implFunRawRef = irRawFunctionReferefence(context.irBuiltIns.anyType, implFunSymbol)
val instanceMethodType = jvmOriginalMethodType(instanceMethodSymbol)
var bootstrapMethod = jdkMetafactoryHandle
val bootstrapMethodArguments = arrayListOf<IrExpression>(
samMethodType,
implFunRawRef,
instanceMethodType
)
var bridgeMethodTypes = emptyList<IrExpression>()
var flags = 0
if (shouldBeSerializable) {
flags += LambdaMetafactory.FLAG_SERIALIZABLE
}
if (requiredBridges.isNotEmpty()) {
flags += LambdaMetafactory.FLAG_BRIDGES
bridgeMethodTypes = requiredBridges.map { jvmOriginalMethodType(it.symbol) }
}
if (flags != 0) {
bootstrapMethod = jdkAltMetafactoryHandle
// Bootstrap arguments for LambdaMetafactory#altMetafactory should be:
// MethodType samMethodType,
// MethodHandle implMethod,
// MethodType instantiatedMethodType,
// // ---------------------------- same as LambdaMetafactory#metafactory until here
// int flags, // combination of LambdaMetafactory.{ FLAG_SERIALIZABLE, FLAG_MARKERS, FLAG_BRIDGES }
// int markerInterfaceCount, // IF flags has MARKERS set
// Class... markerInterfaces, // IF flags has MARKERS set
// int bridgeCount, // IF flags has BRIDGES set
// MethodType... bridges // IF flags has BRIDGES set
// `flags`
bootstrapMethodArguments.add(irInt(flags))
// `markerInterfaceCount`, `markerInterfaces`
// Currently, it looks like there's no way a Kotlin function expression should be SAM-converted to a type implementing
// additional marker interfaces (such as `Runnable r = (Runnable & Marker) () -> { ... }` in Java).
// If such additional marker interfaces would appear, they should go here, between `flags` and `bridgeCount`.
if (bridgeMethodTypes.isNotEmpty()) {
// `bridgeCount`, `bridges`
bootstrapMethodArguments.add(irInt(bridgeMethodTypes.size))
bootstrapMethodArguments.addAll(bridgeMethodTypes)
}
}
return jvmInvokeDynamic(dynamicCall, bootstrapMethod, bootstrapMethodArguments)
}
private fun getOverriddenMethodsRequiringBridges(
@@ -52,7 +52,7 @@ internal sealed class MetafactoryArgumentsResult {
// TODO might use Kotlin-specific metafactory if there would be one.
object LambdaMetafactorySemanticsHazard : Failure()
// There's an ABI incompatibility between classes generated by j.l.invoke.LambdaMetafactory and classes generatede by Kotlin.
// There's an ABI incompatibility between classes generated by j.l.invoke.LambdaMetafactory and classes generated by Kotlin.
// TODO might use Kotlin-specific metafactory if there would be one.
object LambdaMetafactoryAbiHazard : Failure()
@@ -75,7 +75,8 @@ internal class LambdaMetafactoryArguments(
val samMethod: IrSimpleFunction,
val fakeInstanceMethod: IrSimpleFunction,
val implMethodReference: IrFunctionReference,
val extraOverriddenMethods: List<IrSimpleFunction>
val extraOverriddenMethods: List<IrSimpleFunction>,
val shouldBeSerializable: Boolean
) : MetafactoryArgumentsResult.Success()
@@ -203,14 +204,13 @@ internal class LambdaMetafactoryArgumentsBuilder(
semanticsHazard -> return MetafactoryArgumentsResult.Failure.LambdaMetafactorySemanticsHazard
abiHazard -> return MetafactoryArgumentsResult.Failure.LambdaMetafactoryAbiHazard
inliningHazard -> return MetafactoryArgumentsResult.Failure.InliningHazard
shouldBeSerializable -> return MetafactoryArgumentsResult.Failure.SerializationHazard
functionHazard -> return MetafactoryArgumentsResult.Failure.FunctionHazard
}
// Do the hard work of matching Kotlin functional interface hierarchy against LambdaMetafactory constraints.
// Briefly: sometimes we have to force boxing on the primitive and inline class values, sometimes we have to keep them unboxed.
// If this results in conflicting requirements, we can't use INVOKEDYNAMIC with LambdaMetafactory for creating a closure.
return getLambdaMetafactoryArgsOrNullInner(reference, samMethod, samType, implFun)
return getLambdaMetafactoryArgsOrNullInner(reference, samMethod, samType, implFun, shouldBeSerializable)
?: MetafactoryArgumentsResult.Failure.FunctionHazard
}
@@ -242,7 +242,8 @@ internal class LambdaMetafactoryArgumentsBuilder(
reference: IrFunctionReference,
samMethod: IrSimpleFunction,
samType: IrType,
implFun: IrFunction
implFun: IrFunction,
shouldBeSerializable: Boolean
): LambdaMetafactoryArguments? {
val nonFakeOverriddenFuns = samMethod.allOverridden().filterNot { it.isFakeOverride }
val relevantOverriddenFuns = if (samMethod.isFakeOverride) nonFakeOverriddenFuns else nonFakeOverriddenFuns + samMethod
@@ -334,9 +335,15 @@ internal class LambdaMetafactoryArgumentsBuilder(
reference
if (samMethod.isFakeOverride && nonFakeOverriddenFuns.size == 1) {
return LambdaMetafactoryArguments(nonFakeOverriddenFuns.single(), fakeInstanceMethod, newReference, listOf())
return LambdaMetafactoryArguments(
nonFakeOverriddenFuns.single(),
fakeInstanceMethod,
newReference,
listOf(),
shouldBeSerializable
)
}
return LambdaMetafactoryArguments(samMethod, fakeInstanceMethod, newReference, nonFakeOverriddenFuns)
return LambdaMetafactoryArguments(samMethod, fakeInstanceMethod, newReference, nonFakeOverriddenFuns, shouldBeSerializable)
}
private fun checkMethodSignatureCompliance(
@@ -351,14 +358,7 @@ internal class LambdaMetafactoryArgumentsBuilder(
withExtensionReceiver = reference.extensionReceiver == null
)
val methodParameters = collectValueParameters(fakeInstanceMethod)
if (implParameters.size != methodParameters.size)
throw AssertionError(
"Mismatching lambda and instance method parameters:\n" +
"implFun: ${implFun.render()}\n" +
" (${implParameters.size} parameters)\n" +
"instance method: ${fakeInstanceMethod.render()}\n" +
" (${methodParameters.size} parameters)"
)
validateMethodParameters(implParameters, methodParameters, implFun, fakeInstanceMethod)
for ((implParameter, methodParameter) in implParameters.zip(methodParameters)) {
val constraint = constraints.valueParameters[methodParameter]
if (!checkTypeCompliesWithConstraint(implParameter.type, constraint))
@@ -397,14 +397,7 @@ internal class LambdaMetafactoryArgumentsBuilder(
val implParameters = collectValueParameters(implFun)
val methodParameters = collectValueParameters(fakeInstanceMethod)
if (implParameters.size != methodParameters.size)
throw AssertionError(
"Mismatching lambda and instance method parameters:\n" +
"implFun: ${implFun.render()}\n" +
" (${implParameters.size} parameters)\n" +
"instance method: ${fakeInstanceMethod.render()}\n" +
" (${methodParameters.size} parameters)"
)
validateMethodParameters(implParameters, methodParameters, implFun, fakeInstanceMethod)
for ((implParameter, methodParameter) in implParameters.zip(methodParameters)) {
val parameterConstraint = constraints.valueParameters[methodParameter]
if (parameterConstraint.requiresImplLambdaBoxing()) {
@@ -418,6 +411,22 @@ internal class LambdaMetafactoryArgumentsBuilder(
}
}
private fun validateMethodParameters(
implParameters: List<IrValueParameter>,
methodParameters: List<IrValueParameter>,
implFun: IrFunction,
fakeInstanceMethod: IrSimpleFunction
) {
if (implParameters.size != methodParameters.size)
throw AssertionError(
"Mismatching lambda and instance method parameters:\n" +
"implFun: ${implFun.render()}\n" +
" (${implParameters.size} parameters)\n" +
"instance method: ${fakeInstanceMethod.render()}\n" +
" (${methodParameters.size} parameters)"
)
}
private fun remapExtensionLambda(lambda: IrSimpleFunction, reference: IrFunctionReference): IrFunctionReference {
val oldExtensionReceiver = lambda.extensionReceiverParameter
?: return reference
@@ -59,8 +59,10 @@ class JvmSymbols(
private val kotlinJvmFunctionsPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.functions"))
private val kotlinReflectPackage: IrPackageFragment = createPackage(FqName("kotlin.reflect"))
private val javaLangPackage: IrPackageFragment = createPackage(FqName("java.lang"))
private val javaLangInvokePackage: IrPackageFragment = createPackage(FqName("java.lang.invoke"))
private val javaUtilPackage: IrPackageFragment = createPackage(FqName("java.util"))
private val kotlinInternalPackage: IrPackageFragment = createPackage(FqName("kotlin.internal"))
// Special package for functions representing dynamic symbols referenced by 'INVOKEDYNAMIC' instruction - e.g.,
@@ -101,6 +103,7 @@ class JvmSymbols(
"kotlin.jvm" -> kotlinJvmPackage
"kotlin.reflect" -> kotlinReflectPackage
"java.lang" -> javaLangPackage
"java.lang.invoke" -> javaLangInvokePackage
"java.util" -> javaUtilPackage
"kotlin.internal" -> kotlinInternalPackage
else -> error("Other packages are not supported yet: $fqName")
@@ -232,7 +235,7 @@ class JvmSymbols(
klass.addConstructor { isPrimary = true }
}
// This annotations also implies ACC_DEPRECATED flag in generated bytecode
// This annotation also implies ACC_DEPRECATED flag in generated bytecode
val javaLangDeprecatedConstructorWithDeprecatedFlag = javaLangDeprecatedWithDeprecatedFlag.constructors.single()
private val javaLangAssertionError: IrClassSymbol =
@@ -596,14 +599,16 @@ class JvmSymbols(
// samMethodType,
// implMethodReference,
// instantiatedMethodType,
// vararg extraOverriddenMethodTypes
// vararg extraOverriddenMethodTypes,
// shouldBeSerializable
// ): SAM_TYPE
// where:
// `SAM_TYPE` is a single abstract method interface, which is implemented by a resulting closure;
// `samMethodType` is a method type (signature and return type) of a method to be implemented by a closure;
// `implMethodReference` is an actual implementation method (e.g., method for a lambda function);
// `instantiatedMethodType` is a specialized implementation method type;
// `extraOverriddenMethodTypes` is a possibly empty vararg of additional methods to be implemented by a closure.
// `extraOverriddenMethodTypes` is a possibly empty vararg of additional methods to be implemented by a closure;
// `shouldBeSerializable` is true if the class of the resulting object should implement `java.io.Serializable`.
//
// At this stage, "method types" are represented as IrRawFunctionReference nodes for the functions with corresponding signature.
// `<jvm-indy-lambda-metafactory>` call rewriting selects a particular bootstrap method (`metafactory` or `altMetafactory`)
@@ -632,34 +637,74 @@ class JvmSymbols(
type = arrayOfAnyType
varargElementType = irBuiltIns.anyType
}
addValueParameter("shouldBeSerializable", irBuiltIns.booleanType)
returnType = samType.defaultType
}.symbol
inner class SerializedLambdaClass
@Deprecated("Should not be used outside of JvmSymbols") internal constructor() {
val symbol = createClass(FqName("java.lang.invoke.SerializedLambda"))
val irClass = symbol.owner
val irType = irClass.defaultType
val getImplMethodName = irClass.addFunction("getImplMethodName", irBuiltIns.stringType)
val getImplMethodKind = irClass.addFunction("getImplMethodKind", irBuiltIns.intType)
val getImplClass = irClass.addFunction("getImplClass", irBuiltIns.stringType)
val getImplMethodSignature = irClass.addFunction("getImplMethodSignature", irBuiltIns.stringType)
val getFunctionalInterfaceClass = irClass.addFunction("getFunctionalInterfaceClass", irBuiltIns.stringType)
val getFunctionalInterfaceMethodName = irClass.addFunction("getFunctionalInterfaceMethodName", irBuiltIns.stringType)
val getFunctionalInterfaceMethodSignature = irClass.addFunction("getFunctionalInterfaceMethodSignature", irBuiltIns.stringType)
val getCapturedArg = irClass.addFunction("getCapturedArg", irBuiltIns.anyNType).apply {
addValueParameter(Name.identifier("i"), irBuiltIns.intType)
}
}
@Suppress("DEPRECATION")
val serializedLambda = SerializedLambdaClass()
val illegalArgumentException = createClass(FqName("java.lang.IllegalArgumentException")) { irClass ->
irClass.addConstructor {
name = Name.special("<init>")
}.apply {
addValueParameter("message", irBuiltIns.stringType)
}
}
val illegalArgumentExceptionCtorString = illegalArgumentException.constructors.single()
val jvmMethodType: IrSimpleFunctionSymbol =
irFactory.buildFun {
name = Name.special("<jvm-method-type>")
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
}.apply {
returnType = irBuiltIns.anyType
parent = kotlinJvmInternalPackage
addValueParameter("descriptor", irBuiltIns.stringType)
}.symbol
val jvmMethodHandle: IrSimpleFunctionSymbol =
irFactory.buildFun {
name = Name.special("<jvm-method-handle>")
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
}.apply {
returnType = irBuiltIns.anyType
parent = kotlinJvmInternalPackage
addValueParameter("tag", irBuiltIns.intType)
addValueParameter("owner", irBuiltIns.stringType)
addValueParameter("name", irBuiltIns.stringType)
addValueParameter("descriptor", irBuiltIns.stringType)
addValueParameter("isInterface", irBuiltIns.booleanType)
}.symbol
// Intrinsic to represent INVOKEDYNAMIC calls in IR.
// fun <T> `<jvm-indy>`(
// dynamicCall: T,
// bootstrapMethodTag: Int,
// bootstrapMethodOwner: String,
// bootstrapMethodName: String,
// bootstrapMethodDesc: String,
// bootstrapMethodHandle: Any,
// vararg bootstrapMethodArgs: Any
// ): T
// Bootstrap method handle is encoded as a bunch of constants.
// For example,
// REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(
// Ljava/lang/invoke/MethodHandles$Lookup;
// Ljava/lang/String;
// Ljava/lang/invoke/MethodType;
// Ljava/lang/invoke/MethodType;
// Ljava/lang/invoke/MethodHandle;
// Ljava/lang/invoke/MethodType;
// )Ljava/lang/invoke/CallSite;
// is represented as
// bootstrapMethodTag: IrConst<Int>(value = H_INVOKESTATIC)
// bootstrapMethodOwner: IrConst<String>(value = "java/lang/invoke/LambdaMetafactory")
// bootstrapMethodName: IrConst<String>(value = "metafactory")
// bootstrapMethodDesc: IrConst<String>(value = "(...)Ljava/lang/invoke/CallSite;")
// Bootstrap method owner is assumed to be a class (which is true for both LambdaMetafactory and StringConcatFactory).
// Bootstrap method handle is represented as a `<jvm-method-handle>` call.
val jvmIndyIntrinsic: IrSimpleFunctionSymbol =
irFactory.buildFun {
name = Name.special("<jvm-indy>")
@@ -668,10 +713,7 @@ class JvmSymbols(
parent = kotlinJvmInternalPackage
val t = addTypeParameter("T", irBuiltIns.anyNType)
addValueParameter("dynamicCall", t.defaultType)
addValueParameter("bootstrapMethodTag", irBuiltIns.intType)
addValueParameter("bootstrapMethodOwner", irBuiltIns.stringType)
addValueParameter("bootstrapMethodName", irBuiltIns.stringType)
addValueParameter("bootstrapMethodDesc", irBuiltIns.stringType)
addValueParameter("bootstrapMethodHandle", irBuiltIns.anyType)
addValueParameter {
name = Name.identifier("bootstrapMethodArguments")
type = arrayOfAnyType
@@ -693,21 +735,6 @@ class JvmSymbols(
returnType = irBuiltIns.anyType
}.symbol
// Intrinsic used to represent MethodType objects in bootstrap method arguments (see jvmInvokeDynamicIntrinsic above).
// Type argument is a substituted method owner type (e.g., 'java.lang.function.Supplier<String>').
// Value argument is a raw function reference to a corresponding method (e.g., 'java.lang.function.Supplier#get').
// Resulting method type is substituted.
val jvmSubstitutedMethodTypeIntrinsic: IrSimpleFunctionSymbol =
irFactory.buildFun {
name = Name.special("<jvm-substituted-method-type>")
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
}.apply {
parent = kotlinJvmInternalPackage
addTypeParameter("OwnerT", irBuiltIns.anyType)
addValueParameter("method", irBuiltIns.anyType)
returnType = irBuiltIns.anyType
}.symbol
private val collectionToArrayClass: IrClassSymbol = createClass(FqName("kotlin.jvm.internal.CollectionToArray")) { klass ->
klass.origin = JvmLoweredDeclarationOrigin.TO_ARRAY
@@ -5,19 +5,18 @@
package org.jetbrains.kotlin.backend.jvm.intrinsics
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
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
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.overrides.buildFakeOverrideMember
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.Handle
import org.jetbrains.org.objectweb.asm.Opcodes
@@ -36,24 +35,17 @@ object JvmInvokeDynamic : IntrinsicMethod() {
)
fail("Unexpected dynamicCallee: '${dynamicCallee.render()}'")
val bootstrapMethodTag = expression.getValueArgument(1)?.getIntConst()
?: fail("'bootstrapMethodTag' is expected to be an int const")
val bootstrapMethodOwner = expression.getValueArgument(2)?.getStringConst()
?: fail("'bootstrapMethodOwner' is expected to be a string const")
val bootstrapMethodName = expression.getValueArgument(3)?.getStringConst()
?: fail("'bootstrapMethodName' is expected to be a string const")
val bootstrapMethodDesc = expression.getValueArgument(4)?.getStringConst()
?: fail("'bootstrapMethodDesc' is expected to be a string const")
val bootstrapMethodArgs = (expression.getValueArgument(5)?.safeAs<IrVararg>()
?: fail("'bootstrapMethodArgs' is expected to be a vararg"))
val bootstrapMethodHandleArg = expression.getValueArgument(1) as? IrCall
?: fail("'bootstrapMethodHandle' should be a call")
val bootstrapMethodHandle = evalMethodHandle(bootstrapMethodHandleArg)
val bootstrapMethodArgs = (expression.getValueArgument(2)?.safeAs<IrVararg>()
?: fail("'bootstrapMethodArgs' is expected to be a vararg"))
val asmBootstrapMethodArgs = bootstrapMethodArgs.elements
.map { generateBootstrapMethodArg(it, codegen) }
.toTypedArray()
val dynamicCalleeMethod = codegen.methodSignatureMapper.mapAsmMethod(dynamicCallee)
val bootstrapMethodHandle = Handle(bootstrapMethodTag, bootstrapMethodOwner, bootstrapMethodName, bootstrapMethodDesc, false)
val dynamicCallGenerator = IrCallGenerator.DefaultCallGenerator
val dynamicCalleeArgumentTypes = dynamicCalleeMethod.argumentTypes
for (i in dynamicCallee.valueParameters.indices) {
@@ -76,14 +68,8 @@ object JvmInvokeDynamic : IntrinsicMethod() {
is IrRawFunctionReference ->
generateMethodHandle(element, codegen)
is IrCall ->
when (element.symbol) {
codegen.context.ir.symbols.jvmOriginalMethodTypeIntrinsic ->
generateOriginalMethodType(element, codegen)
codegen.context.ir.symbols.jvmSubstitutedMethodTypeIntrinsic ->
generateSubstitutedMethodType(element, codegen)
else ->
throw AssertionError("Unexpected callee in bootstrap method argument:\n${element.dump()}")
}
evalBootstrapArgumentIntrinsicCall(element, codegen)
?: throw AssertionError("Unexpected callee in bootstrap method argument:\n${element.dump()}")
is IrConst<*> ->
when (element.kind) {
IrConstKind.Byte -> (element.value as Byte).toInt()
@@ -100,40 +86,38 @@ object JvmInvokeDynamic : IntrinsicMethod() {
throw AssertionError("Unexpected bootstrap method argument:\n${element.dump()}")
}
private fun generateMethodHandle(irRawFunctionReference: IrRawFunctionReference, codegen: ExpressionCodegen): Handle {
val irFun = when (val irFun0 = irRawFunctionReference.symbol.owner) {
is IrConstructor ->
irFun0
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.
findSuperDeclaration(irFun0, false, codegen.state.jvmDefaultMode)
}
private fun evalBootstrapArgumentIntrinsicCall(irCall: IrCall, codegen: ExpressionCodegen): Any? {
return when (irCall.symbol) {
codegen.context.ir.symbols.jvmOriginalMethodTypeIntrinsic ->
evalOriginalMethodType(irCall, codegen)
codegen.context.ir.symbols.jvmMethodType ->
evalMethodType(irCall)
codegen.context.ir.symbols.jvmMethodHandle ->
evalMethodHandle(irCall)
else ->
throw java.lang.AssertionError("Simple function or constructor expected: ${irFun0.render()}")
null
}
val irParentClass = irFun.parent as? IrClass
?: throw AssertionError("Unexpected parent: ${irFun.parent.render()}")
val owner = codegen.typeMapper.mapOwner(irParentClass)
val asmMethod = codegen.methodSignatureMapper.mapAsmMethod(irFun)
val handleTag = when {
irFun is IrConstructor ->
Opcodes.H_NEWINVOKESPECIAL
irFun.dispatchReceiverParameter == null ->
Opcodes.H_INVOKESTATIC
irParentClass.isJvmInterface ->
Opcodes.H_INVOKEINTERFACE
else ->
Opcodes.H_INVOKEVIRTUAL
}
return Handle(handleTag, owner.internalName, asmMethod.name, asmMethod.descriptor, irParentClass.isJvmInterface)
}
private fun generateOriginalMethodType(irCall: IrCall, codegen: ExpressionCodegen): Type {
private fun evalMethodType(irCall: IrCall): Type {
val descriptor = irCall.getStringConstArgument(0)
return Type.getMethodType(descriptor)
}
private fun evalMethodHandle(irCall: IrCall): Handle {
val tag = irCall.getIntConstArgument(0)
val owner = irCall.getStringConstArgument(1)
val name = irCall.getStringConstArgument(2)
val descriptor = irCall.getStringConstArgument(3)
val isInterface = irCall.getBooleanConstArgument(4)
return Handle(tag, owner, name, descriptor, isInterface)
}
fun generateMethodHandle(irRawFunctionReference: IrRawFunctionReference, codegen: ExpressionCodegen): Handle {
return generateMethodHandle(codegen.context, irRawFunctionReference)
}
private fun evalOriginalMethodType(irCall: IrCall, codegen: ExpressionCodegen): Type {
val irRawFunRef = irCall.getValueArgument(0) as? IrRawFunctionReference
?: throw AssertionError(
"Argument in ${irCall.symbol.owner.name} call is expected to be a raw function reference:\n" +
@@ -144,64 +128,75 @@ object JvmInvokeDynamic : IntrinsicMethod() {
return Type.getMethodType(asmMethod.descriptor)
}
private fun generateSubstitutedMethodType(irCall: IrCall, codegen: ExpressionCodegen): Type {
fun fail(message: String): Nothing =
throw AssertionError("$message; irCall:\n${irCall.dump()}")
}
val irRawFunRef = irCall.getValueArgument(0) as? IrRawFunctionReference
?: fail("Argument in ${irCall.symbol.owner.name} call is expected to be a raw function reference")
val irOriginalFun = irRawFunRef.symbol.owner as? IrSimpleFunction
?: fail("IrSimpleFunction expected: ${irRawFunRef.symbol.owner.render()}")
fun IrCall.getIntConstArgument(i: Int) =
getValueArgument(i)?.getIntConst()
?: throw AssertionError("Value argument #$i should be an Int const: ${dump()}")
val superType = irCall.getTypeArgument(0) as? IrSimpleType
?: fail("Type argument expected")
val patchedSuperType = replaceTypeArgumentsWithNullable(superType)
fun IrCall.getStringConstArgument(i: Int) =
getValueArgument(i)?.getStringConst()
?: throw AssertionError("Value argument #$i should be a String const: ${dump()}")
val fakeClass = codegen.context.irFactory.buildClass { name = Name.special("<fake>") }
fakeClass.parent = codegen.context.ir.symbols.kotlinJvmInternalInvokeDynamicPackage
val irFakeOverride = buildFakeOverrideMember(patchedSuperType, irOriginalFun, fakeClass) as IrSimpleFunction
irFakeOverride.overriddenSymbols = listOf(irOriginalFun.symbol)
fun IrCall.getBooleanConstArgument(i: Int) =
getValueArgument(i)?.getBooleanConst()
?: throw AssertionError("Value argument #$i should be a Boolean const: ${dump()}")
val asmMethod = codegen.methodSignatureMapper.mapAsmMethod(irFakeOverride)
return Type.getMethodType(asmMethod.descriptor)
internal fun IrExpression.getIntConst() =
if (this is IrConst<*> && kind == IrConstKind.Int)
this.value as Int
else
null
internal fun IrExpression.getStringConst() =
if (this is IrConst<*> && kind == IrConstKind.String)
this.value as String
else
null
internal fun IrExpression.getBooleanConst() =
if (this is IrConst<*> && kind == IrConstKind.Boolean)
this.value as Boolean
else
null
internal fun generateMethodHandle(jvmBackendContext: JvmBackendContext, irRawFunctionReference: IrRawFunctionReference): Handle {
return generateMethodHandle(jvmBackendContext, irRawFunctionReference.symbol.owner)
}
fun generateMethodHandle(jvmBackendContext: JvmBackendContext, irFun: IrFunction): Handle {
val irNonFakeFun = when (irFun) {
is IrConstructor ->
irFun
is IrSimpleFunction -> {
findSuperDeclaration(irFun, false, jvmBackendContext.state.jvmDefaultMode)
}
else ->
throw java.lang.AssertionError("Simple function or constructor expected: ${irFun.render()}")
}
// Given the following functional interface
// fun interface IFoo<T> {
// fun foo(x: T): T
// }
// To comply with java.lang.invoke.LambdaMetafactory requirements, we need an instance method that accepts references
// (not primitives, and not unboxed inline classes).
// In order to do so, we replace type arguments with nullable types.
private fun replaceTypeArgumentsWithNullable(substitutedType: IrSimpleType) =
substitutedType.classifier.typeWithArguments(
substitutedType.arguments.map { typeArgument ->
when (typeArgument) {
is IrStarProjection -> typeArgument
is IrTypeProjection -> {
val type = typeArgument.type
if (type !is IrSimpleType || type.hasQuestionMark)
typeArgument
else {
makeTypeProjection(type.withHasQuestionMark(true), typeArgument.variance)
}
}
else ->
throw AssertionError("Unexpected type argument '$typeArgument' :: ${typeArgument::class.simpleName}")
}
}
)
val irParentClass = irNonFakeFun.parent as? IrClass
?: throw AssertionError("Unexpected parent: ${irNonFakeFun.parent.render()}")
val owner = jvmBackendContext.typeMapper.mapOwner(irParentClass)
private fun IrExpression.getIntConst() =
if (this is IrConst<*> && kind == IrConstKind.Int)
this.value as Int
else
null
val asmMethod = jvmBackendContext.methodSignatureMapper.mapAsmMethod(irNonFakeFun)
val handleTag = getMethodKindTag(irNonFakeFun)
return Handle(handleTag, owner.internalName, asmMethod.name, asmMethod.descriptor, irParentClass.isJvmInterface)
}
internal fun getMethodKindTag(irFun: IrFunction) =
when {
irFun is IrConstructor ->
Opcodes.H_NEWINVOKESPECIAL
irFun.dispatchReceiverParameter == null ->
Opcodes.H_INVOKESTATIC
irFun.parentAsClass.isJvmInterface ->
Opcodes.H_INVOKEINTERFACE
else ->
Opcodes.H_INVOKEVIRTUAL
}
private fun IrExpression.getStringConst() =
if (this is IrConst<*> && kind == IrConstKind.String)
this.value as String
else
null
}
@@ -5,7 +5,7 @@
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 0 java/lang/invoke/LambdaMetafactory
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableSam1.kt
import java.io.ByteArrayInputStream
@@ -5,7 +5,7 @@
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 0 java/lang/invoke/LambdaMetafactory
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableSam2.kt
import java.io.ByteArrayInputStream
@@ -0,0 +1,62 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// We generate 1 clause in '$deserializeLambda' for each unique possible combination of deserialized lambda parameters
// (that's all information stored during indy lambda serialization, anyway).
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 12 java/lang/invoke/LambdaMetafactory
// 1 (LOOKUP|TABLE)SWITCH
// 24 java/lang/String\.equals
// FILE: multipleTopLevelFunRefs.kt
import java.io.*
fun plusK1(s: String) = s + "K"
fun plusK2(s: String) = s + "K"
fun plusK3(s: String) = s + "K"
fun plusK4(s: String) = s + "K"
fun box(): String {
val t1 = roundtrip(Sam(::plusK1)).get("O")
if (t1 != "OK") return "Failed: t1='$t1'"
val t1a = roundtrip(Sam(::plusK1)).get("O")
if (t1a != "OK") return "Failed: t1a='$t1a'"
val t1b = roundtrip(Sam(::plusK1)).get("O")
if (t1b != "OK") return "Failed: t1b='$t1b'"
val t2 = roundtrip(Sam(::plusK2)).get("O")
if (t2 != "OK") return "Failed: t2='$t2'"
val t2a = roundtrip(Sam(::plusK2)).get("O")
if (t2a != "OK") return "Failed: t2a='$t2a'"
val t3 = roundtrip(Sam(::plusK3)).get("O")
if (t3 != "OK") return "Failed: t3='$t3'"
val t4 = roundtrip(Sam(::plusK4)).get("O")
if (t4 != "OK") return "Failed: t4='$t4'"
val t4a = roundtrip(Sam(::plusK4)).get("O")
if (t4a != "OK") return "Failed: t4a='$t4a'"
return "OK"
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
String get(String s);
}
@@ -0,0 +1,47 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 4 java/lang/invoke/LambdaMetafactory
// FILE: sameImplMethodDifferentInterfaces.kt
import java.io.*
fun plusK(s: String) = s + "K"
fun box(): String {
val sam1 = roundtrip(Sam1(::plusK))
if (sam1 !is Sam1) return "Failed: $sam1 !is Sam1"
val t1 = sam1.get("O")
if (t1 != "OK") return "Failed: $t1='$t1'"
val sam2 = roundtrip(Sam2(::plusK))
if (sam2 !is Sam2) return "Failed: $sam2 !is Sam2"
val t2 = sam2.get("O")
if (t2 != "OK") return "Failed: $t2='$t2'"
return "OK"
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam1.java
import java.io.*;
public interface Sam1 extends Serializable {
String get(String s);
}
// FILE: Sam2.java
import java.io.*;
public interface Sam2 extends Serializable {
String get(String s);
}
@@ -0,0 +1,33 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableBoundClassMemberFunRef.kt
import java.io.*
class C(val s: String) : Serializable {
fun plus(ss: String) = ss + s
}
fun box(): String {
return roundtrip(Sam(C("K")::plus))
.get("O")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
String get(String s);
}
@@ -0,0 +1,35 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableBoundInnerConstructorRef.kt
import java.io.*
class Outer(val s1: String) : Serializable {
inner class Inner (val s2: String) {
fun test() = s1 + s2
}
}
fun box(): String {
return roundtrip(Sam(Outer("O")::Inner))
.get("K").test()
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
Outer.Inner get(String s);
}
@@ -0,0 +1,38 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableBoundInterfaceMemberFunRef.kt
import java.io.*
interface Plus {
fun plus(ss: String): String
}
class C(val s: String) : Plus, Serializable {
override fun plus(ss: String) = ss + s
}
fun box(): String {
val p: Plus = C("K")
return roundtrip(Sam(p::plus))
.get("O")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
String get(String s);
}
@@ -0,0 +1,31 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableBoundTopLevelExtensionFunRef.kt
import java.io.*
fun String.plusK(k: String) = this + k
fun box(): String {
return roundtrip(Sam("O"::plusK))
.get("K")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
String get(String s);
}
@@ -0,0 +1,31 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableBoundTopLevelExtensionFunRefPrimitiveReceiver.kt
import java.io.*
fun Int.plusK(k: String) = this.toChar().toString() + k
fun box(): String {
return roundtrip(Sam(('O'.toInt())::plusK))
.get("K")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
String get(String s);
}
@@ -0,0 +1,33 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableClassMemberFunRef.kt
import java.io.*
class C(val s: String) {
fun plus(ss: String) = ss + s
}
fun box(): String {
return roundtrip(Sam(C::plus))
.get(C("K"), "O")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
String get(C x, String s);
}
@@ -0,0 +1,31 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableConstructorRef.kt
import java.io.*
class C(val t: String)
fun box(): String {
return roundtrip(Sam(::C))
.get("OK").t
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
C get(String s);
}
@@ -0,0 +1,39 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// 2 A\.plus\(Ljava/lang/String;\)Ljava/lang/String;\,
// ^ check that we generate a reference to A::plus (same as javac)
// FILE: serializableFakeOverrideFunRef.kt
import java.io.*
abstract class A(val s: String) {
fun plus(ss: String) = ss + s
}
abstract class B(s: String) : A(s)
class C(s: String) : B(s)
fun box(): String {
return roundtrip(Sam(C::plus))
.get(C("K"), "O")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
String get(C x, String s);
}
@@ -0,0 +1,35 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableInnerConstructorRef.kt
import java.io.*
class Outer(val s1: String) {
inner class Inner (val s2: String) {
fun test() = s1 + s2
}
}
fun box(): String {
return roundtrip(Sam(Outer::Inner))
.get(Outer("O"), "K").test()
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
Outer.Inner get(Outer outer, String s);
}
@@ -0,0 +1,37 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableInterfaceMemberFunRef.kt
import java.io.*
interface Plus {
fun plus(ss: String): String
}
class C(val s: String) : Plus {
override fun plus(ss: String) = ss + s
}
fun box(): String {
return roundtrip(Sam(Plus::plus))
.get(C("K"), "O")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
String get(Plus x, String s);
}
@@ -0,0 +1,36 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableJavaStaticMethodRef.kt
import java.io.*
fun box(): String {
return roundtrip(Sam(J::plusK))
.get("O")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
String get(String s);
}
// FILE: J.java
public class J {
public static String plusK(String s) {
return s + "K";
}
}
@@ -0,0 +1,29 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableLambda.kt
import java.io.*
fun box(): String {
return roundtrip(Sam { s -> s + "K" })
.get("O")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
String get(String s);
}
@@ -0,0 +1,32 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableLambdaCapturingBoxedInlineClassAny.kt
import java.io.*
inline class IC(val x: Any) : Serializable
fun box(): String {
val k: Any = IC("K")
return roundtrip(Sam { s -> s + (k as IC).x })
.get("O")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
String get(String s);
}
@@ -0,0 +1,32 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableLambdaCapturingInlineClassAny.kt
import java.io.*
inline class IC(val x: Any)
fun box(): String {
val k = IC("K")
return roundtrip(Sam { s -> s + k.x })
.get("O")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
String get(String s);
}
@@ -0,0 +1,32 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableLambdaCapturingInlineClassInt.kt
import java.io.*
inline class IC(val x: Int)
fun box(): String {
val k = IC('K'.toInt())
return roundtrip(Sam { s -> s + k.x.toChar().toString() })
.get("O")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
String get(String s);
}
@@ -0,0 +1,32 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableLambdaCapturingNullableInlineClassAny.kt
import java.io.*
inline class IC(val x: Any) : Serializable
fun box(): String {
val k: IC? = IC("K")
return roundtrip(Sam { s -> s + k!!.x })
.get("O")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
String get(String s);
}
@@ -0,0 +1,26 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableLambdaToKotlinInterface.kt
import java.io.*
fun interface Sam : Serializable {
fun get(s: String): String
}
fun box(): String {
return roundtrip(Sam { s -> s + "K" })
.get("O")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
@@ -0,0 +1,30 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableLambdaWithCapture.kt
import java.io.*
fun box(): String {
val k = "K"
return roundtrip(Sam { s -> s + k })
.get("O")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
String get(String s);
}
@@ -0,0 +1,31 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableTopLevelFunRef.kt
import java.io.*
fun plusK(s: String) = s + "K"
fun box(): String {
return roundtrip(Sam(::plusK))
.get("O")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam extends Serializable {
String get(String s);
}
@@ -0,0 +1,31 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableTopLevelFunRefAsGenericInterface.kt
import java.io.*
fun plusK(s: String) = s + "K"
fun box(): String {
return roundtrip(Sam<String>(::plusK))
.get("O")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Sam.java
import java.io.*;
public interface Sam<T> extends Serializable {
String get(T s);
}
@@ -0,0 +1,38 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// FULL_JDK
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 2 java/lang/invoke/LambdaMetafactory
// FILE: serializableWithBridge.kt
import java.io.*
fun plusK(s: String) = s + "K"
fun box(): String {
return roundtrip(Sam(::plusK))
.get("O")
}
fun <T> roundtrip(x: T): T {
val out1 = ByteArrayOutputStream()
ObjectOutputStream(out1).writeObject(x)
return ObjectInputStream(ByteArrayInputStream(out1.toByteArray())).readObject() as T
}
// FILE: Base1.java
public interface Base1<T1> {
String get(T1 s);
}
// FILE: Base2.java
public interface Base2<T2 extends CharSequence> {
String get(T2 s);
}
// FILE: Sam.java
public interface Sam extends Base1<String>, Base2<String>, java.io.Serializable {
}
@@ -22863,6 +22863,154 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
}
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/invokedynamic/serializable")
@TestDataPath("$PROJECT_ROOT")
public class Serializable {
@Test
public void testAllFilesPresentInSerializable() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/serializable"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@Test
@TestMetadata("multipleTopLevelFunRefs.kt")
public void testMultipleTopLevelFunRefs() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/multipleTopLevelFunRefs.kt");
}
@Test
@TestMetadata("sameImplMethodDifferentInterfaces.kt")
public void testSameImplMethodDifferentInterfaces() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/sameImplMethodDifferentInterfaces.kt");
}
@Test
@TestMetadata("serializableBoundClassMemberFunRef.kt")
public void testSerializableBoundClassMemberFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundClassMemberFunRef.kt");
}
@Test
@TestMetadata("serializableBoundInnerConstructorRef.kt")
public void testSerializableBoundInnerConstructorRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundInnerConstructorRef.kt");
}
@Test
@TestMetadata("serializableBoundInterfaceMemberFunRef.kt")
public void testSerializableBoundInterfaceMemberFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundInterfaceMemberFunRef.kt");
}
@Test
@TestMetadata("serializableBoundTopLevelExtensionFunRef.kt")
public void testSerializableBoundTopLevelExtensionFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundTopLevelExtensionFunRef.kt");
}
@Test
@TestMetadata("serializableBoundTopLevelExtensionFunRefPrimitiveReceiver.kt")
public void testSerializableBoundTopLevelExtensionFunRefPrimitiveReceiver() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundTopLevelExtensionFunRefPrimitiveReceiver.kt");
}
@Test
@TestMetadata("serializableClassMemberFunRef.kt")
public void testSerializableClassMemberFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableClassMemberFunRef.kt");
}
@Test
@TestMetadata("serializableConstructorRef.kt")
public void testSerializableConstructorRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableConstructorRef.kt");
}
@Test
@TestMetadata("serializableFakeOverrideFunRef.kt")
public void testSerializableFakeOverrideFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableFakeOverrideFunRef.kt");
}
@Test
@TestMetadata("serializableInnerConstructorRef.kt")
public void testSerializableInnerConstructorRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableInnerConstructorRef.kt");
}
@Test
@TestMetadata("serializableInterfaceMemberFunRef.kt")
public void testSerializableInterfaceMemberFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableInterfaceMemberFunRef.kt");
}
@Test
@TestMetadata("serializableJavaStaticMethodRef.kt")
public void testSerializableJavaStaticMethodRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableJavaStaticMethodRef.kt");
}
@Test
@TestMetadata("serializableLambda.kt")
public void testSerializableLambda() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambda.kt");
}
@Test
@TestMetadata("serializableLambdaCapturingBoxedInlineClassAny.kt")
public void testSerializableLambdaCapturingBoxedInlineClassAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaCapturingBoxedInlineClassAny.kt");
}
@Test
@TestMetadata("serializableLambdaCapturingInlineClassAny.kt")
public void testSerializableLambdaCapturingInlineClassAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaCapturingInlineClassAny.kt");
}
@Test
@TestMetadata("serializableLambdaCapturingInlineClassInt.kt")
public void testSerializableLambdaCapturingInlineClassInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaCapturingInlineClassInt.kt");
}
@Test
@TestMetadata("serializableLambdaCapturingNullableInlineClassAny.kt")
public void testSerializableLambdaCapturingNullableInlineClassAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaCapturingNullableInlineClassAny.kt");
}
@Test
@TestMetadata("serializableLambdaToKotlinInterface.kt")
public void testSerializableLambdaToKotlinInterface() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaToKotlinInterface.kt");
}
@Test
@TestMetadata("serializableLambdaWithCapture.kt")
public void testSerializableLambdaWithCapture() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaWithCapture.kt");
}
@Test
@TestMetadata("serializableTopLevelFunRef.kt")
public void testSerializableTopLevelFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableTopLevelFunRef.kt");
}
@Test
@TestMetadata("serializableTopLevelFunRefAsGenericInterface.kt")
public void testSerializableTopLevelFunRefAsGenericInterface() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableTopLevelFunRefAsGenericInterface.kt");
}
@Test
@TestMetadata("serializableWithBridge.kt")
public void testSerializableWithBridge() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableWithBridge.kt");
}
}
}
@Nested
@@ -23001,6 +23001,154 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
}
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/invokedynamic/serializable")
@TestDataPath("$PROJECT_ROOT")
public class Serializable {
@Test
public void testAllFilesPresentInSerializable() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/serializable"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("multipleTopLevelFunRefs.kt")
public void testMultipleTopLevelFunRefs() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/multipleTopLevelFunRefs.kt");
}
@Test
@TestMetadata("sameImplMethodDifferentInterfaces.kt")
public void testSameImplMethodDifferentInterfaces() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/sameImplMethodDifferentInterfaces.kt");
}
@Test
@TestMetadata("serializableBoundClassMemberFunRef.kt")
public void testSerializableBoundClassMemberFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundClassMemberFunRef.kt");
}
@Test
@TestMetadata("serializableBoundInnerConstructorRef.kt")
public void testSerializableBoundInnerConstructorRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundInnerConstructorRef.kt");
}
@Test
@TestMetadata("serializableBoundInterfaceMemberFunRef.kt")
public void testSerializableBoundInterfaceMemberFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundInterfaceMemberFunRef.kt");
}
@Test
@TestMetadata("serializableBoundTopLevelExtensionFunRef.kt")
public void testSerializableBoundTopLevelExtensionFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundTopLevelExtensionFunRef.kt");
}
@Test
@TestMetadata("serializableBoundTopLevelExtensionFunRefPrimitiveReceiver.kt")
public void testSerializableBoundTopLevelExtensionFunRefPrimitiveReceiver() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundTopLevelExtensionFunRefPrimitiveReceiver.kt");
}
@Test
@TestMetadata("serializableClassMemberFunRef.kt")
public void testSerializableClassMemberFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableClassMemberFunRef.kt");
}
@Test
@TestMetadata("serializableConstructorRef.kt")
public void testSerializableConstructorRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableConstructorRef.kt");
}
@Test
@TestMetadata("serializableFakeOverrideFunRef.kt")
public void testSerializableFakeOverrideFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableFakeOverrideFunRef.kt");
}
@Test
@TestMetadata("serializableInnerConstructorRef.kt")
public void testSerializableInnerConstructorRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableInnerConstructorRef.kt");
}
@Test
@TestMetadata("serializableInterfaceMemberFunRef.kt")
public void testSerializableInterfaceMemberFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableInterfaceMemberFunRef.kt");
}
@Test
@TestMetadata("serializableJavaStaticMethodRef.kt")
public void testSerializableJavaStaticMethodRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableJavaStaticMethodRef.kt");
}
@Test
@TestMetadata("serializableLambda.kt")
public void testSerializableLambda() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambda.kt");
}
@Test
@TestMetadata("serializableLambdaCapturingBoxedInlineClassAny.kt")
public void testSerializableLambdaCapturingBoxedInlineClassAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaCapturingBoxedInlineClassAny.kt");
}
@Test
@TestMetadata("serializableLambdaCapturingInlineClassAny.kt")
public void testSerializableLambdaCapturingInlineClassAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaCapturingInlineClassAny.kt");
}
@Test
@TestMetadata("serializableLambdaCapturingInlineClassInt.kt")
public void testSerializableLambdaCapturingInlineClassInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaCapturingInlineClassInt.kt");
}
@Test
@TestMetadata("serializableLambdaCapturingNullableInlineClassAny.kt")
public void testSerializableLambdaCapturingNullableInlineClassAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaCapturingNullableInlineClassAny.kt");
}
@Test
@TestMetadata("serializableLambdaToKotlinInterface.kt")
public void testSerializableLambdaToKotlinInterface() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaToKotlinInterface.kt");
}
@Test
@TestMetadata("serializableLambdaWithCapture.kt")
public void testSerializableLambdaWithCapture() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaWithCapture.kt");
}
@Test
@TestMetadata("serializableTopLevelFunRef.kt")
public void testSerializableTopLevelFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableTopLevelFunRef.kt");
}
@Test
@TestMetadata("serializableTopLevelFunRefAsGenericInterface.kt")
public void testSerializableTopLevelFunRefAsGenericInterface() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableTopLevelFunRefAsGenericInterface.kt");
}
@Test
@TestMetadata("serializableWithBridge.kt")
public void testSerializableWithBridge() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableWithBridge.kt");
}
}
}
@Nested
@@ -19158,6 +19158,134 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
}
}
}
@TestMetadata("compiler/testData/codegen/box/invokedynamic/serializable")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Serializable extends AbstractLightAnalysisModeTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
public void testAllFilesPresentInSerializable() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/serializable"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("multipleTopLevelFunRefs.kt")
public void testMultipleTopLevelFunRefs() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/multipleTopLevelFunRefs.kt");
}
@TestMetadata("sameImplMethodDifferentInterfaces.kt")
public void testSameImplMethodDifferentInterfaces() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/sameImplMethodDifferentInterfaces.kt");
}
@TestMetadata("serializableBoundClassMemberFunRef.kt")
public void testSerializableBoundClassMemberFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundClassMemberFunRef.kt");
}
@TestMetadata("serializableBoundInnerConstructorRef.kt")
public void testSerializableBoundInnerConstructorRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundInnerConstructorRef.kt");
}
@TestMetadata("serializableBoundInterfaceMemberFunRef.kt")
public void testSerializableBoundInterfaceMemberFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundInterfaceMemberFunRef.kt");
}
@TestMetadata("serializableBoundTopLevelExtensionFunRef.kt")
public void testSerializableBoundTopLevelExtensionFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundTopLevelExtensionFunRef.kt");
}
@TestMetadata("serializableBoundTopLevelExtensionFunRefPrimitiveReceiver.kt")
public void testSerializableBoundTopLevelExtensionFunRefPrimitiveReceiver() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundTopLevelExtensionFunRefPrimitiveReceiver.kt");
}
@TestMetadata("serializableClassMemberFunRef.kt")
public void testSerializableClassMemberFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableClassMemberFunRef.kt");
}
@TestMetadata("serializableConstructorRef.kt")
public void testSerializableConstructorRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableConstructorRef.kt");
}
@TestMetadata("serializableFakeOverrideFunRef.kt")
public void testSerializableFakeOverrideFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableFakeOverrideFunRef.kt");
}
@TestMetadata("serializableInnerConstructorRef.kt")
public void testSerializableInnerConstructorRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableInnerConstructorRef.kt");
}
@TestMetadata("serializableInterfaceMemberFunRef.kt")
public void testSerializableInterfaceMemberFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableInterfaceMemberFunRef.kt");
}
@TestMetadata("serializableJavaStaticMethodRef.kt")
public void testSerializableJavaStaticMethodRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableJavaStaticMethodRef.kt");
}
@TestMetadata("serializableLambda.kt")
public void testSerializableLambda() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambda.kt");
}
@TestMetadata("serializableLambdaCapturingBoxedInlineClassAny.kt")
public void testSerializableLambdaCapturingBoxedInlineClassAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaCapturingBoxedInlineClassAny.kt");
}
@TestMetadata("serializableLambdaCapturingInlineClassAny.kt")
public void testSerializableLambdaCapturingInlineClassAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaCapturingInlineClassAny.kt");
}
@TestMetadata("serializableLambdaCapturingInlineClassInt.kt")
public void testSerializableLambdaCapturingInlineClassInt() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaCapturingInlineClassInt.kt");
}
@TestMetadata("serializableLambdaCapturingNullableInlineClassAny.kt")
public void testSerializableLambdaCapturingNullableInlineClassAny() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaCapturingNullableInlineClassAny.kt");
}
@TestMetadata("serializableLambdaToKotlinInterface.kt")
public void testSerializableLambdaToKotlinInterface() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaToKotlinInterface.kt");
}
@TestMetadata("serializableLambdaWithCapture.kt")
public void testSerializableLambdaWithCapture() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableLambdaWithCapture.kt");
}
@TestMetadata("serializableTopLevelFunRef.kt")
public void testSerializableTopLevelFunRef() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableTopLevelFunRef.kt");
}
@TestMetadata("serializableTopLevelFunRefAsGenericInterface.kt")
public void testSerializableTopLevelFunRefAsGenericInterface() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableTopLevelFunRefAsGenericInterface.kt");
}
@TestMetadata("serializableWithBridge.kt")
public void testSerializableWithBridge() throws Exception {
runTest("compiler/testData/codegen/box/invokedynamic/serializable/serializableWithBridge.kt");
}
}
}
@TestMetadata("compiler/testData/codegen/box/ir")
@@ -16152,6 +16152,19 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
}
}
}
@TestMetadata("compiler/testData/codegen/box/invokedynamic/serializable")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Serializable extends AbstractIrJsCodegenBoxES6Test {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR_ES6, testDataFilePath);
}
public void testAllFilesPresentInSerializable() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/serializable"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
}
}
}
@TestMetadata("compiler/testData/codegen/box/ir")
@@ -15558,6 +15558,19 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
}
}
}
@TestMetadata("compiler/testData/codegen/box/invokedynamic/serializable")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Serializable extends AbstractIrJsCodegenBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
}
public void testAllFilesPresentInSerializable() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/serializable"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
}
}
@TestMetadata("compiler/testData/codegen/box/ir")
@@ -15588,6 +15588,19 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
}
}
}
@TestMetadata("compiler/testData/codegen/box/invokedynamic/serializable")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Serializable extends AbstractJsCodegenBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
public void testAllFilesPresentInSerializable() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/serializable"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
}
}
@TestMetadata("compiler/testData/codegen/box/ir")
@@ -14884,6 +14884,19 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
}
}
}
@TestMetadata("compiler/testData/codegen/box/invokedynamic/serializable")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Serializable extends AbstractIrCodegenBoxWasmTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
}
public void testAllFilesPresentInSerializable() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/serializable"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
}
}
}
@TestMetadata("compiler/testData/codegen/box/ir")