JVM_IR: treat suspend-converted references as lambdas for inlining

Again, this is consistent with adapted function references, since
they're pretty much the same anyway.
This commit is contained in:
pyos
2020-10-06 17:06:11 +02:00
committed by max-kammerer
parent 12bec7cca2
commit a4b67f007f
14 changed files with 105 additions and 14 deletions
@@ -8678,6 +8678,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onArgument.kt");
}
@TestMetadata("onInlineArgument.kt")
public void testOnInlineArgument() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onInlineArgument.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToSuspendConversion.kt")
public void testSubtypeOfFunctionalTypeToSuspendConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/subtypeOfFunctionalTypeToSuspendConversion.kt");
@@ -76,7 +76,7 @@ class IrInlineCodegen(
blockInfo: BlockInfo
) {
val isInlineParameter = irValueParameter.isInlineParameter()
if (isInlineParameter && isInlineIrExpression(argumentExpression)) {
if (isInlineParameter && argumentExpression.isInlineIrExpression()) {
val irReference = (argumentExpression as IrBlock).statements.filterIsInstance<IrFunctionReference>().single()
val lambdaInfo = IrExpressionLambdaImpl(codegen, irReference, irValueParameter)
val closureInfo = invocationParamBuilder.addNextValueParameter(parameterType, true, null, irValueParameter.index)
@@ -245,18 +245,19 @@ class IrDefaultLambda(
}.toIrBasedDescriptor()
}
fun isInlineIrExpression(argumentExpression: IrExpression) =
when (argumentExpression) {
is IrBlock -> argumentExpression.isInlineIrBlock()
fun IrExpression.isInlineIrExpression() =
when (this) {
is IrBlock -> origin.isInlineIrExpression()
is IrCallableReference<*> -> true.also {
assert((0 until argumentExpression.valueArgumentsCount).count { argumentExpression.getValueArgument(it) != null } == 0) {
"Expecting 0 value arguments for bounded callable reference: ${argumentExpression.dump()}"
assert((0 until valueArgumentsCount).count { getValueArgument(it) != null } == 0) {
"Expecting 0 value arguments for bounded callable reference: ${dump()}"
}
}
else -> false
}
fun IrBlock.isInlineIrBlock(): Boolean = origin.isLambda || origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE
fun IrStatementOrigin?.isInlineIrExpression() =
isLambda || this == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE || this == IrStatementOrigin.SUSPEND_CONVERSION
fun IrFunction.isInlineFunctionCall(context: JvmBackendContext) =
(!context.state.isInlineDisabled || typeParameters.any { it.isReified }) && isInline
@@ -36,7 +36,7 @@ internal open class IrInlineReferenceLocator(private val context: JvmBackendCont
continue
val valueArgument = expression.getValueArgument(parameter.index) ?: continue
if (!isInlineIrExpression(valueArgument))
if (!valueArgument.isInlineIrExpression())
continue
if (valueArgument is IrBlock) {
@@ -54,7 +54,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
// because they are also their own continuation classes.
// TODO: Currently, origin of callable references explicitly written in source code is null. Do we need to create one?
private fun IrFunctionReference.isSuspendFunctionReference(): Boolean = isSuspend &&
(origin == null || origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE)
(origin == null || origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE || origin == IrStatementOrigin.SUSPEND_CONVERSION)
override fun lower(irFile: IrFile) {
ignoredFunctionReferences.addAll(IrInlineReferenceLocator.scan(context, irFile))
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrClass
@@ -37,7 +38,7 @@ private class RemoveDeclarationsThatWouldBeInlinedLowering(val context: JvmBacke
override fun visitElement(element: IrElement) = element.acceptChildrenVoid(this)
override fun visitFunctionReference(expression: IrFunctionReference) {
if (expression.origin.isLambda || expression.origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE) {
if (expression.origin.isInlineIrExpression()) {
loweredLambdasToDelete.add(expression.symbol.owner)
}
@@ -109,12 +109,9 @@ private class SuspendLambdaLowering(context: JvmBackendContext) : SuspendLowerin
override fun lower(irFile: IrFile) {
val inlineReferences = IrInlineReferenceLocator.scan(context, irFile)
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
private fun IrFunctionReference.shouldBeTreatedAsSuspendLambda() =
isSuspend && (origin == IrStatementOrigin.LAMBDA || origin == IrStatementOrigin.SUSPEND_CONVERSION)
override fun visitBlock(expression: IrBlock): IrExpression {
val reference = expression.statements.lastOrNull() as? IrFunctionReference ?: return super.visitBlock(expression)
if (reference.shouldBeTreatedAsSuspendLambda() && reference !in inlineReferences) {
if (reference.isSuspend && reference.origin.isLambda && reference !in inlineReferences) {
assert(expression.statements.size == 2 && expression.statements[0] is IrFunction)
expression.transformChildrenVoid(this)
val parent = currentDeclarationParent ?: error("No current declaration parent at ${reference.dump()}")
@@ -0,0 +1,21 @@
// !LANGUAGE: +SuspendConversion
// WITH_RUNTIME
// WITH_COROUTINES
// IGNORE_BACKEND: JVM, NATIVE
// IGNORE_LIGHT_ANALYSIS
// `lambda` should not be wrapped in yet another object (so no OnInlineArgumentKt$box$1$1).
// CHECK_BYTECODE_LISTING
import helpers.*
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
inline suspend fun runS(fn: suspend (String) -> String) = fn("O")
fun box(): String {
var test = "Failed"
val lambda: (String) -> String = { it + "K" }
suspend { test = runS(lambda) }.startCoroutine(EmptyContinuation)
return test
}
@@ -0,0 +1,36 @@
@kotlin.coroutines.jvm.internal.DebugMetadata
@kotlin.Metadata
final class OnInlineArgumentKt$box$1 {
// source: 'onInlineArgument.kt'
enclosing method OnInlineArgumentKt.box()Ljava/lang/String;
synthetic final field $lambda: kotlin.jvm.functions.Function1
synthetic final field $test: kotlin.jvm.internal.Ref$ObjectRef
field label: int
inner (anonymous) class OnInlineArgumentKt$box$1
method <init>(p0: kotlin.jvm.internal.Ref$ObjectRef, p1: kotlin.jvm.functions.Function1, p2: kotlin.coroutines.Continuation): void
public final @org.jetbrains.annotations.NotNull method create(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): kotlin.coroutines.Continuation
public final method invoke(p0: java.lang.Object): java.lang.Object
public final @org.jetbrains.annotations.Nullable method invokeSuspend(@org.jetbrains.annotations.NotNull p0: java.lang.Object): java.lang.Object
}
@kotlin.Metadata
final class OnInlineArgumentKt$box$lambda$1 {
// source: 'onInlineArgument.kt'
enclosing method OnInlineArgumentKt.box()Ljava/lang/String;
public final static field INSTANCE: OnInlineArgumentKt$box$lambda$1
inner (anonymous) class OnInlineArgumentKt$box$lambda$1
static method <clinit>(): void
method <init>(): void
public final @org.jetbrains.annotations.NotNull method invoke(@org.jetbrains.annotations.NotNull p0: java.lang.String): java.lang.String
public synthetic bridge method invoke(p0: java.lang.Object): java.lang.Object
}
@kotlin.Metadata
public final class OnInlineArgumentKt {
// source: 'onInlineArgument.kt'
inner (anonymous) class OnInlineArgumentKt$box$1
inner (anonymous) class OnInlineArgumentKt$box$lambda$1
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
private final static method runS$$forInline(p0: kotlin.jvm.functions.Function2, p1: kotlin.coroutines.Continuation): java.lang.Object
public final static @org.jetbrains.annotations.Nullable method runS(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function2, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
}
@@ -9893,6 +9893,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onArgument.kt");
}
@TestMetadata("onInlineArgument.kt")
public void testOnInlineArgument() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onInlineArgument.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToSuspendConversion.kt")
public void testSubtypeOfFunctionalTypeToSuspendConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/subtypeOfFunctionalTypeToSuspendConversion.kt");
@@ -9885,6 +9885,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onArgument.kt");
}
@TestMetadata("onInlineArgument.kt")
public void ignoreOnInlineArgument() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onInlineArgument.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToSuspendConversion.kt")
public void ignoreSubtypeOfFunctionalTypeToSuspendConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/subtypeOfFunctionalTypeToSuspendConversion.kt");
@@ -8678,6 +8678,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onArgument.kt");
}
@TestMetadata("onInlineArgument.kt")
public void testOnInlineArgument() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onInlineArgument.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToSuspendConversion.kt")
public void testSubtypeOfFunctionalTypeToSuspendConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/subtypeOfFunctionalTypeToSuspendConversion.kt");
@@ -7373,6 +7373,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onArgument.kt");
}
@TestMetadata("onInlineArgument.kt")
public void testOnInlineArgument() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onInlineArgument.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToSuspendConversion.kt")
public void testSubtypeOfFunctionalTypeToSuspendConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/subtypeOfFunctionalTypeToSuspendConversion.kt");
@@ -7373,6 +7373,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onArgument.kt");
}
@TestMetadata("onInlineArgument.kt")
public void testOnInlineArgument() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onInlineArgument.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToSuspendConversion.kt")
public void testSubtypeOfFunctionalTypeToSuspendConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/subtypeOfFunctionalTypeToSuspendConversion.kt");
@@ -7373,6 +7373,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onArgument.kt");
}
@TestMetadata("onInlineArgument.kt")
public void testOnInlineArgument() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onInlineArgument.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToSuspendConversion.kt")
public void testSubtypeOfFunctionalTypeToSuspendConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/subtypeOfFunctionalTypeToSuspendConversion.kt");