From bdd88e16553acc165aaf39c07ccf9ead9daee242 Mon Sep 17 00:00:00 2001 From: pyos Date: Fri, 13 Mar 2020 13:14:37 +0100 Subject: [PATCH] JVM_IR: place suspend markers in faux lambdas around inline references Otherwise, the assumption that coroutine codegen makes about every inlined function already having the markers breaks and it is no longer true that calls to inline lambdas do not require them. --- .../backend/jvm/codegen/CoroutineCodegen.kt | 1 - .../lower/InlineCallableReferenceToLambda.kt | 5 ++- .../jvm/lower/TailCallOptimizationLowering.kt | 4 +-- .../suspend/callableReference/nonTailCall.kt | 36 +++++++++++++++++++ .../suspend/callableReference/unitReturn.kt | 33 +++++++++++++++++ .../BlackBoxInlineCodegenTestGenerated.java | 10 ++++++ ...otlinAgainstInlineKotlinTestGenerated.java | 10 ++++++ .../IrBlackBoxInlineCodegenTestGenerated.java | 10 ++++++ ...otlinAgainstInlineKotlinTestGenerated.java | 10 ++++++ .../IrJsCodegenInlineTestGenerated.java | 10 ++++++ .../JsCodegenInlineTestGenerated.java | 10 ++++++ 11 files changed, 133 insertions(+), 6 deletions(-) create mode 100644 compiler/testData/codegen/boxInline/suspend/callableReference/nonTailCall.kt create mode 100644 compiler/testData/codegen/boxInline/suspend/callableReference/unitReturn.kt diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt index e25bf902bf3..bb2e8b68ae1 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt @@ -102,7 +102,6 @@ internal fun IrFunction.shouldContainSuspendMarkers(): Boolean = !isInvokeSuspen origin != JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR && origin != JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE && origin != JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE_TO_SYNTHETIC && - origin != JvmLoweredDeclarationOrigin.GENERATED_MEMBER_IN_CALLABLE_REFERENCE && origin != IrDeclarationOrigin.BRIDGE && origin != IrDeclarationOrigin.BRIDGE_SPECIAL && origin != IrDeclarationOrigin.DELEGATED_MEMBER && diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InlineCallableReferenceToLambda.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InlineCallableReferenceToLambda.kt index 04589ee50ed..64f1ad2ebe8 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InlineCallableReferenceToLambda.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InlineCallableReferenceToLambda.kt @@ -12,7 +12,6 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irBlock import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.jvm.JvmBackendContext -import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder import org.jetbrains.kotlin.backend.jvm.ir.irArray @@ -78,7 +77,7 @@ internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendConte return irBuilder.irBlock(expression, IrStatementOrigin.LAMBDA) { val function = buildFun { setSourceRange(expression) - origin = JvmLoweredDeclarationOrigin.GENERATED_MEMBER_IN_CALLABLE_REFERENCE + origin = IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA name = Name.identifier("stub_for_inline") visibility = Visibilities.LOCAL returnType = field.type @@ -135,7 +134,7 @@ internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendConte val function = buildFun { setSourceRange(expression) - origin = JvmLoweredDeclarationOrigin.GENERATED_MEMBER_IN_CALLABLE_REFERENCE + origin = IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA name = Name.identifier("stub_for_inlining") visibility = Visibilities.LOCAL returnType = referencedFunction.returnType diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/TailCallOptimizationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/TailCallOptimizationLowering.kt index 6221cc85cbe..b71915e08e5 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/TailCallOptimizationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/TailCallOptimizationLowering.kt @@ -46,7 +46,7 @@ private class TailCallOptimizationLowering(private val context: JvmBackendContex }, null) } - private fun IrExpression.coerceToUnit() = IrTypeOperatorCallImpl( + private fun IrExpression.coerceToUnit() = if (type == context.irBuiltIns.unitType) this else IrTypeOperatorCallImpl( startOffset, endOffset, context.irBuiltIns.unitType, IrTypeOperator.IMPLICIT_COERCION_TO_UNIT, context.irBuiltIns.unitType, this ) } @@ -75,7 +75,7 @@ private class TailCallOptimizationData(val function: IrSimpleFunction) { init { when (val body = function.body) { is IrBlockBody -> body.statements.findTailCall(returnsUnit)?.findCallsOnTailPositionWithoutImmediateReturn() - is IrExpressionBody -> body.expression.findCallsOnTailPositionWithoutImmediateReturn() + is IrExpressionBody -> body.expression.findCallsOnTailPositionWithoutImmediateReturn(immediateReturn = true) } } } diff --git a/compiler/testData/codegen/boxInline/suspend/callableReference/nonTailCall.kt b/compiler/testData/codegen/boxInline/suspend/callableReference/nonTailCall.kt new file mode 100644 index 00000000000..c8a26003cff --- /dev/null +++ b/compiler/testData/codegen/boxInline/suspend/callableReference/nonTailCall.kt @@ -0,0 +1,36 @@ +// WITH_RUNTIME +// WITH_COROUTINES +// NO_CHECK_LAMBDA_INLINING +// FILE: 1.kt +import kotlin.coroutines.intrinsics.* +import kotlin.coroutines.* + +class Delayed(val run: suspend() -> Unit) + +inline fun asyncThenAddK(crossinline block: suspend () -> Unit) = + Delayed { + block() + result += "K" + } + +suspend fun pause(): Unit = suspendCoroutineUninterceptedOrReturn { cont -> + cont.resume(Unit) + COROUTINE_SUSPENDED +} + +var result = "" + +suspend fun addO(): Unit { + pause() + result += "O" +} + +// FILE: 2.kt +import kotlin.coroutines.intrinsics.* +import kotlin.coroutines.* +import helpers.* + +fun box(): String { + suspend { asyncThenAddK(::addO).run() }.startCoroutine(EmptyContinuation) + return result +} diff --git a/compiler/testData/codegen/boxInline/suspend/callableReference/unitReturn.kt b/compiler/testData/codegen/boxInline/suspend/callableReference/unitReturn.kt new file mode 100644 index 00000000000..9cf78d99439 --- /dev/null +++ b/compiler/testData/codegen/boxInline/suspend/callableReference/unitReturn.kt @@ -0,0 +1,33 @@ +// WITH_RUNTIME +// WITH_COROUTINES +// NO_CHECK_LAMBDA_INLINING +// FILE: 1.kt +import kotlin.coroutines.intrinsics.* +import kotlin.coroutines.* + +class Delayed(val run: suspend() -> Unit) + +inline fun async(crossinline block: suspend () -> Unit) = + Delayed { block() } + +suspend fun pause(): Unit = suspendCoroutineUninterceptedOrReturn { cont -> + cont.resume(Unit) + COROUTINE_SUSPENDED +} + +var result = "" + +suspend fun addOK(): Unit { + pause() + result += "OK" +} + +// FILE: 2.kt +import kotlin.coroutines.intrinsics.* +import kotlin.coroutines.* +import helpers.* + +fun box(): String { + suspend { async(::addOK).run() }.startCoroutine(EmptyContinuation) + return result +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index 53d96357a27..80a3637ddee 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -3885,10 +3885,20 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/callableReference"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @TestMetadata("nonTailCall.kt") + public void testNonTailCall() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/callableReference/nonTailCall.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/callableReference/simple.kt"); } + + @TestMetadata("unitReturn.kt") + public void testUnitReturn() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/callableReference/unitReturn.kt"); + } } @TestMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index 57f99e548cf..1088a5931e4 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -3885,10 +3885,20 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/callableReference"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @TestMetadata("nonTailCall.kt") + public void testNonTailCall() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/callableReference/nonTailCall.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/callableReference/simple.kt"); } + + @TestMetadata("unitReturn.kt") + public void testUnitReturn() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/callableReference/unitReturn.kt"); + } } @TestMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java index 7885de0e2b9..25e2ad78b7e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java @@ -3780,10 +3780,20 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/callableReference"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @TestMetadata("nonTailCall.kt") + public void testNonTailCall() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/callableReference/nonTailCall.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/callableReference/simple.kt"); } + + @TestMetadata("unitReturn.kt") + public void testUnitReturn() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/callableReference/unitReturn.kt"); + } } @TestMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java index 01c928aca19..90a1515bd73 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java @@ -3780,10 +3780,20 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/callableReference"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @TestMetadata("nonTailCall.kt") + public void testNonTailCall() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/callableReference/nonTailCall.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/callableReference/simple.kt"); } + + @TestMetadata("unitReturn.kt") + public void testUnitReturn() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/callableReference/unitReturn.kt"); + } } @TestMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter") diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java index 558aaa61885..4a8492506cb 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java @@ -3355,10 +3355,20 @@ public class IrJsCodegenInlineTestGenerated extends AbstractIrJsCodegenInlineTes KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/callableReference"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); } + @TestMetadata("nonTailCall.kt") + public void testNonTailCall() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/callableReference/nonTailCall.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/callableReference/simple.kt"); } + + @TestMetadata("unitReturn.kt") + public void testUnitReturn() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/callableReference/unitReturn.kt"); + } } @TestMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter") diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java index d32ccbc8af6..8059248bf42 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java @@ -3355,10 +3355,20 @@ public class JsCodegenInlineTestGenerated extends AbstractJsCodegenInlineTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/callableReference"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); } + @TestMetadata("nonTailCall.kt") + public void testNonTailCall() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/callableReference/nonTailCall.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/callableReference/simple.kt"); } + + @TestMetadata("unitReturn.kt") + public void testUnitReturn() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/callableReference/unitReturn.kt"); + } } @TestMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter")