JVM_IR indy-lambdas: initial implementation and tests

KT-44278 KT-26060 KT-42621
This commit is contained in:
Dmitry Petrov
2021-01-29 16:39:42 +03:00
committed by TeamCityServer
parent 0bc386cb08
commit d94912ed62
41 changed files with 733 additions and 37 deletions
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.codegen.*
import org.jetbrains.kotlin.codegen.inline.v
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.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.*
@@ -101,7 +102,8 @@ object JvmInvokeDynamic : IntrinsicMethod() {
private fun generateMethodHandle(irRawFunctionReference: IrRawFunctionReference, codegen: ExpressionCodegen): Handle {
val irFun = irRawFunctionReference.symbol.owner
val irParentClass = irFun.parentAsClass
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 {
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.ir.*
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi
import org.jetbrains.kotlin.config.JvmSamConversions
import org.jetbrains.kotlin.config.JvmClosureGenerationScheme
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
@@ -74,6 +74,12 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
irFile.transformChildrenVoid(this)
}
private val shouldGenerateIndySamConversions =
context.state.samConversionsScheme == JvmClosureGenerationScheme.INDY
private val shouldGenerateIndyLambdas =
context.state.lambdasScheme == JvmClosureGenerationScheme.INDY
override fun visitBlock(expression: IrBlock): IrExpression {
if (!expression.origin.isLambda)
return super.visitBlock(expression)
@@ -84,9 +90,24 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
expression.statements.dropLast(1).forEach { it.transform(this, null) }
reference.transformChildrenVoid(this)
if (shouldGenerateIndyLambdas && canUseIndySamConversion(reference, reference.type)) {
return wrapLambdaReferenceWithIndySamConversion(expression, reference)
}
return FunctionReferenceBuilder(reference).build()
}
private fun wrapLambdaReferenceWithIndySamConversion(expression: IrBlock, reference: IrFunctionReference): IrBlock {
expression.statements[expression.statements.size - 1] = wrapWithIndySamConversion(reference.type, reference)
val irLambda = reference.symbol.owner
// JDK LambdaMetafactory can't adapt '(...)V' tp '(...)Lkotlin/Unit;'.
if (irLambda.returnType.isUnit()) {
irLambda.returnType = irLambda.returnType.makeNullable()
}
return expression
}
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
expression.transformChildrenVoid(this)
return if (expression.isIgnored)
@@ -95,9 +116,6 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
FunctionReferenceBuilder(expression).build()
}
private val shouldUseIndySamConversions =
context.state.samConversionsScheme == JvmSamConversions.INDY
// Handle SAM conversions which wrap a function reference:
// class sam$n(private val receiver: R) : Interface { override fun method(...) = receiver.target(...) }
//
@@ -121,7 +139,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
reference.transformChildrenVoid()
val samSuperType = expression.typeOperand
return if (shouldUseIndySamConversions && canUseIndySamConversion(reference, samSuperType)) {
return if (shouldGenerateIndySamConversions && canUseIndySamConversion(reference, samSuperType)) {
wrapSamConversionArgumentWithIndySamConversion(expression)
} else {
FunctionReferenceBuilder(reference, samSuperType).build()
@@ -129,7 +147,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
}
private fun canUseIndySamConversion(reference: IrFunctionReference, samSuperType: IrType): Boolean {
// Can't use indy for regular function references by default (because of 'equals').
// Can't use JDK LambdaMetafactory for function references by default (because of 'equals').
// TODO special mode that would generate indy everywhere?
if (reference.origin != IrStatementOrigin.LAMBDA)
return false
@@ -231,10 +231,9 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
}
val targetExtensionReceiverParameter = targetFun.extensionReceiverParameter
if (targetExtensionReceiverParameter != null) {
if (targetExtensionReceiverParameter != null && irFunRef.extensionReceiver != null) {
addValueParameter("p${syntheticParameterIndex++}", targetExtensionReceiverParameter.type)
val extensionReceiver = irFunRef.extensionReceiver
?: fail("Captured extension receiver is not provided")
val extensionReceiver = irFunRef.extensionReceiver!!
dynamicCallArguments.add(extensionReceiver)
}