From 26843509c7ab14ccc645c303652c23d4c9538154 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 31 Oct 2017 17:36:03 +0300 Subject: [PATCH] JS: disable suspend function tail-call optimization based on FE data Partially fixes KT-21026 --- .../inlineWithStateMachine.kt | 1 - .../coroutine/CoroutineFunctionTransformer.kt | 10 ++++++++-- .../semantics/JsCodegenBoxTestGenerated.java | 8 +------- .../callTranslator/CallTranslator.kt | 20 ++++++------------- .../declaration/AbstractDeclarationVisitor.kt | 4 +--- .../expression/FunctionTranslator.kt | 8 +------- .../kotlin/js/translate/utils/utils.kt | 8 -------- 7 files changed, 17 insertions(+), 42 deletions(-) diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.kt index b8f4a5f4a78..f8cc94527ab 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS // WITH_RUNTIME // WITH_COROUTINES import helpers.* diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineFunctionTransformer.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineFunctionTransformer.kt index 6ece38d8da0..be114ba7475 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineFunctionTransformer.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineFunctionTransformer.kt @@ -189,15 +189,21 @@ class CoroutineFunctionTransformer(private val function: JsFunction, name: Strin ): List { val indexOfGlobalCatch = blocks.indexOf(context.globalCatchBlock) val stateRef = JsNameRef(context.metadata.stateName, JsThisRef()) + val exceptionStateRef = JsNameRef(context.metadata.exceptionStateName, JsThisRef()) val isFromGlobalCatch = JsAstUtils.equality(stateRef, JsIntLiteral(indexOfGlobalCatch)) val catch = JsCatch(functionWithBody.scope, "e") val continueWithException = JsBlock( - JsAstUtils.assignment(stateRef.deepCopy(), JsNameRef(context.metadata.exceptionStateName, JsThisRef())).makeStmt(), + JsAstUtils.assignment(stateRef.deepCopy(), exceptionStateRef.deepCopy()).makeStmt(), JsAstUtils.assignment(JsNameRef(context.metadata.exceptionName, JsThisRef()), catch.parameter.name.makeRef()).makeStmt() ) - catch.body = JsBlock(JsIf(isFromGlobalCatch, JsThrow(catch.parameter.name.makeRef()), continueWithException)) + val adjustExceptionState = JsAstUtils.assignment(exceptionStateRef.deepCopy(), stateRef.deepCopy()).makeStmt() + catch.body = JsBlock(JsIf( + isFromGlobalCatch, + JsBlock(adjustExceptionState, JsThrow(catch.parameter.name.makeRef())), + continueWithException + )) val throwResultRef = JsNameRef(context.metadata.exceptionName, JsThisRef()) context.globalCatchBlock.statements += JsThrow(throwResultRef) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 70e8c663a88..371b623fb9c 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -6862,13 +6862,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("inlineWithStateMachine.kt") public void testInlineWithStateMachine() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("inlineWithoutStateMachine.kt") diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallTranslator.kt index 984b8261458..3c3d3b39f3a 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallTranslator.kt @@ -153,17 +153,12 @@ private fun translateFunctionCall( } if (resolvedCall.resultingDescriptor.isSuspend) { - if (context.isInStateMachine) { - val statement = callInfo.constructSuspendSafeCallIfNeeded(JsAstUtils.asSyntheticStatement(callExpression.apply { - isSuspend = true - source = resolvedCall.call.callElement - })) - context.currentBlock.statements += statement - return context.createCoroutineResult(resolvedCall) - } - else { - callExpression.isTailCallSuspend = true - } + val statement = callInfo.constructSuspendSafeCallIfNeeded(JsAstUtils.asSyntheticStatement(callExpression.apply { + isSuspend = true + source = resolvedCall.call.callElement + })) + context.currentBlock.statements += statement + return context.createCoroutineResult(resolvedCall) } else { callExpression = callInfo.constructSafeCallIfNeeded(callExpression) @@ -200,9 +195,6 @@ private val untilFqName = FqName("kotlin.ranges.until") fun ResolvedCall.getReturnType(): KotlinType = TranslationUtils.getReturnTypeForCoercion(resultingDescriptor) -private val TranslationContext.isInStateMachine - get() = (declarationDescriptor as? FunctionDescriptor)?.requiresStateMachineTransformation(this) == true - fun computeExplicitReceiversForInvoke( context: TranslationContext, resolvedCall: ResolvedCall, diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/AbstractDeclarationVisitor.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/AbstractDeclarationVisitor.kt index 5c9a778fd8d..8275f367347 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/AbstractDeclarationVisitor.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/AbstractDeclarationVisitor.kt @@ -121,9 +121,7 @@ abstract class AbstractDeclarationVisitor : TranslatorVisitor() { val innerContext = context.newDeclaration(descriptor).translateAndAliasParameters(descriptor, function.parameters) if (descriptor.isSuspend) { - if (descriptor.requiresStateMachineTransformation(context)) { - function.fillCoroutineMetadata(context, descriptor, hasController = false) - } + function.fillCoroutineMetadata(context, descriptor, hasController = false) } if (!descriptor.isOverridable) { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt index ae52db9da4a..89a2afe37bb 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt @@ -31,7 +31,6 @@ import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.utils.BindingUtils import org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator.translateFunctionBody import org.jetbrains.kotlin.js.translate.utils.JsAstUtils -import org.jetbrains.kotlin.js.translate.utils.requiresStateMachineTransformation import org.jetbrains.kotlin.psi.KtDeclarationWithBody import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe @@ -76,12 +75,7 @@ fun TranslationContext.translateAndAliasParameters( if (continuationDescriptor != null) { val jsParameter = JsParameter(getNameForDescriptor(continuationDescriptor)) targetList += jsParameter - aliases[continuationDescriptor] = if (!descriptor.requiresStateMachineTransformation(this)) { - JsAstUtils.pureFqn(jsParameter.name, null) - } - else { - JsAstUtils.stateMachineReceiver() - } + aliases[continuationDescriptor] = JsAstUtils.stateMachineReceiver() } return this.innerContextWithDescriptorsAliased(aliases) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt index 6f6e0f4340d..9309c64c095 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt @@ -24,7 +24,6 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor -import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.metadata.* @@ -37,7 +36,6 @@ import org.jetbrains.kotlin.psi.KtBlockExpression import org.jetbrains.kotlin.psi.KtDeclarationWithBody import org.jetbrains.kotlin.psi.KtFunctionLiteral import org.jetbrains.kotlin.psi.KtLambdaExpression -import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.descriptorUtil.hasOrInheritsParametersWithDefaultValue @@ -163,17 +161,11 @@ fun TranslationContext.addAccessorsToPrototype( addDeclarationStatement(defineProperty.makeStmt()) } -fun FunctionDescriptor.requiresStateMachineTransformation(context: TranslationContext): Boolean = - this is AnonymousFunctionDescriptor || - context.bindingContext()[BindingContext.CONTAINS_NON_TAIL_SUSPEND_CALLS, this] == true - fun JsFunction.fillCoroutineMetadata( context: TranslationContext, descriptor: FunctionDescriptor, hasController: Boolean ) { - if (!descriptor.requiresStateMachineTransformation(context)) return - val suspendPropertyDescriptor = context.currentModule.getPackage(COROUTINES_INTRINSICS_PACKAGE_FQ_NAME) .memberScope .getContributedVariables(COROUTINE_SUSPENDED_NAME, NoLookupLocation.FROM_BACKEND).first()