JVM_IR serializable indy method references
This commit is contained in:
committed by
teamcityserver
parent
eec16b83c6
commit
1dbbe22c8c
+148
@@ -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
|
||||
|
||||
+1
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+328
-46
@@ -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(
|
||||
|
||||
+32
-23
@@ -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
|
||||
|
||||
|
||||
+103
-108
@@ -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
|
||||
|
||||
+62
@@ -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);
|
||||
}
|
||||
Vendored
+47
@@ -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);
|
||||
}
|
||||
Vendored
+33
@@ -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);
|
||||
}
|
||||
Vendored
+35
@@ -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);
|
||||
}
|
||||
Vendored
+38
@@ -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);
|
||||
}
|
||||
compiler/testData/codegen/box/invokedynamic/serializable/serializableBoundTopLevelExtensionFunRef.kt
Vendored
+31
@@ -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);
|
||||
}
|
||||
+31
@@ -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);
|
||||
}
|
||||
+33
@@ -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);
|
||||
}
|
||||
+31
@@ -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);
|
||||
}
|
||||
+39
@@ -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);
|
||||
}
|
||||
Vendored
+35
@@ -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);
|
||||
}
|
||||
Vendored
+37
@@ -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);
|
||||
}
|
||||
Vendored
+36
@@ -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";
|
||||
}
|
||||
}
|
||||
+29
@@ -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);
|
||||
}
|
||||
+32
@@ -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);
|
||||
}
|
||||
+32
@@ -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);
|
||||
}
|
||||
+32
@@ -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);
|
||||
}
|
||||
+32
@@ -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);
|
||||
}
|
||||
Vendored
+26
@@ -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
|
||||
}
|
||||
+30
@@ -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);
|
||||
}
|
||||
+31
@@ -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);
|
||||
}
|
||||
+31
@@ -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);
|
||||
}
|
||||
+38
@@ -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 {
|
||||
}
|
||||
+148
@@ -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
|
||||
|
||||
+148
@@ -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
|
||||
|
||||
+128
@@ -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")
|
||||
|
||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java
Generated
+13
@@ -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")
|
||||
|
||||
Generated
+13
@@ -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")
|
||||
|
||||
Generated
+13
@@ -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")
|
||||
|
||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java
Generated
+13
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user