JS: disable suspend function tail-call optimization based on FE data
Partially fixes KT-21026
This commit is contained in:
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import helpers.*
|
||||
|
||||
@@ -189,15 +189,21 @@ class CoroutineFunctionTransformer(private val function: JsFunction, name: Strin
|
||||
): List<JsStatement> {
|
||||
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)
|
||||
|
||||
+1
-7
@@ -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")
|
||||
|
||||
+6
-14
@@ -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<out CallableDescriptor>.getReturnType(): KotlinType = TranslationUtils.getReturnTypeForCoercion(resultingDescriptor)
|
||||
|
||||
private val TranslationContext.isInStateMachine
|
||||
get() = (declarationDescriptor as? FunctionDescriptor)?.requiresStateMachineTransformation(this) == true
|
||||
|
||||
fun computeExplicitReceiversForInvoke(
|
||||
context: TranslationContext,
|
||||
resolvedCall: ResolvedCall<out FunctionDescriptor>,
|
||||
|
||||
+1
-3
@@ -121,9 +121,7 @@ abstract class AbstractDeclarationVisitor : TranslatorVisitor<Unit>() {
|
||||
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) {
|
||||
|
||||
+1
-7
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user