JS: coroutines: fix inlining of suspend functions

This commit is contained in:
Alexey Andreev
2016-11-21 16:44:56 +03:00
parent 8b9852edec
commit e44edf12e0
6 changed files with 30 additions and 36 deletions
@@ -1,5 +1,8 @@
// WITH_RUNTIME // WITH_RUNTIME
// WITH_REFLECT // WITH_REFLECT
// CHECK_NOT_CALLED: suspendInline_die06n$
// CHECK_NOT_CALLED: suspendInline_nesahw$
// CHECK_NOT_CALLED: suspendInline_grpnnl$
class Controller { class Controller {
fun withValue(v: String, x: Continuation<String>) { fun withValue(v: String, x: Continuation<String>) {
x.resume(v) x.resume(v)
@@ -27,9 +27,12 @@ import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.general.Translation import org.jetbrains.kotlin.js.translate.general.Translation
import org.jetbrains.kotlin.js.translate.reference.CallArgumentTranslator import org.jetbrains.kotlin.js.translate.reference.CallArgumentTranslator
import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.utils.setInlineCallMetadata
import org.jetbrains.kotlin.psi.Call.CallType import org.jetbrains.kotlin.psi.Call.CallType
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInvokeCallOnVariable import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInvokeCallOnVariable
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
@@ -96,32 +99,43 @@ private fun translateCall(context: TranslationContext,
if (resolvedCall is VariableAsFunctionResolvedCall) { if (resolvedCall is VariableAsFunctionResolvedCall) {
assert(explicitReceivers.extensionReceiver == null) { "VariableAsFunctionResolvedCall must have one receiver" } assert(explicitReceivers.extensionReceiver == null) { "VariableAsFunctionResolvedCall must have one receiver" }
val variableCall = resolvedCall.variableCall val variableCall = resolvedCall.variableCall
if (variableCall.expectedReceivers()) {
return if (variableCall.expectedReceivers()) {
val newReceiver = CallTranslator.translateGet(context, variableCall, explicitReceivers.extensionOrDispatchReceiver) val newReceiver = CallTranslator.translateGet(context, variableCall, explicitReceivers.extensionOrDispatchReceiver)
return translateFunctionCall(context, resolvedCall.functionCall, ExplicitReceivers(newReceiver)) translateFunctionCall(context, resolvedCall.functionCall, resolvedCall.variableCall, ExplicitReceivers(newReceiver))
} else { } else {
val dispatchReceiver = CallTranslator.translateGet(context, variableCall, null) val dispatchReceiver = CallTranslator.translateGet(context, variableCall, null)
if (explicitReceivers.extensionOrDispatchReceiver == null) if (explicitReceivers.extensionOrDispatchReceiver == null) {
return translateFunctionCall(context, resolvedCall.functionCall, ExplicitReceivers(dispatchReceiver)) translateFunctionCall(context, resolvedCall.functionCall, resolvedCall.variableCall, ExplicitReceivers(dispatchReceiver))
else }
return translateFunctionCall(context, resolvedCall.functionCall, ExplicitReceivers(dispatchReceiver, explicitReceivers.extensionOrDispatchReceiver)) else {
translateFunctionCall(context, resolvedCall.functionCall, resolvedCall.variableCall,
ExplicitReceivers(dispatchReceiver, explicitReceivers.extensionOrDispatchReceiver))
}
} }
} }
val call = resolvedCall.call val call = resolvedCall.call
if (call.callType == CallType.INVOKE && !isInvokeCallOnVariable(call)) { if (call.callType == CallType.INVOKE && !isInvokeCallOnVariable(call)) {
val explicitReceiversForInvoke = computeExplicitReceiversForInvoke(context, resolvedCall, explicitReceivers) val explicitReceiversForInvoke = computeExplicitReceiversForInvoke(context, resolvedCall, explicitReceivers)
return translateFunctionCall(context, resolvedCall, explicitReceiversForInvoke) return translateFunctionCall(context, resolvedCall, resolvedCall, explicitReceiversForInvoke)
} }
return translateFunctionCall(context, resolvedCall, explicitReceivers) return translateFunctionCall(context, resolvedCall, resolvedCall, explicitReceivers)
} }
private fun translateFunctionCall(context: TranslationContext, private fun translateFunctionCall(context: TranslationContext,
resolvedCall: ResolvedCall<out FunctionDescriptor>, resolvedCall: ResolvedCall<out FunctionDescriptor>,
inlineResolvedCall: ResolvedCall<out CallableDescriptor>,
explicitReceivers: ExplicitReceivers explicitReceivers: ExplicitReceivers
): JsExpression { ): JsExpression {
val callExpression = context.getCallInfo(resolvedCall, explicitReceivers).translateFunctionCall() val callExpression = context.getCallInfo(resolvedCall, explicitReceivers).translateFunctionCall()
if (CallExpressionTranslator.shouldBeInlined(inlineResolvedCall.resultingDescriptor, context)) {
setInlineCallMetadata(callExpression, resolvedCall.call.callElement as KtExpression,
inlineResolvedCall.resultingDescriptor, context)
}
if (resolvedCall.resultingDescriptor.isSuspend && resolvedCall.resultingDescriptor.initialSignatureDescriptor != null) { if (resolvedCall.resultingDescriptor.isSuspend && resolvedCall.resultingDescriptor.initialSignatureDescriptor != null) {
context.currentBlock.statements += JsAstUtils.asSyntheticStatement((callExpression as JsInvocation).apply { context.currentBlock.statements += JsAstUtils.asSyntheticStatement((callExpression as JsInvocation).apply {
isSuspend = true isSuspend = true
@@ -90,7 +90,7 @@ public class DestructuringDeclarationTranslator extends AbstractTranslator {
assert entryInitCall != null : "Entry init call must be not null"; assert entryInitCall != null : "Entry init call must be not null";
JsExpression entryInitializer = CallTranslator.translate(context(), entryInitCall, multiObjNameRef); JsExpression entryInitializer = CallTranslator.translate(context(), entryInitCall, multiObjNameRef);
FunctionDescriptor candidateDescriptor = entryInitCall.getCandidateDescriptor(); FunctionDescriptor candidateDescriptor = entryInitCall.getCandidateDescriptor();
if (CallExpressionTranslator.shouldBeInlined(candidateDescriptor)) { if (CallExpressionTranslator.shouldBeInlined(candidateDescriptor, context())) {
setInlineCallMetadata(entryInitializer, entry, entryInitCall, context()); setInlineCallMetadata(entryInitializer, entry, entryInitCall, context());
} }
@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.js.translate.context.AliasingContext;
import org.jetbrains.kotlin.js.translate.context.Namer; import org.jetbrains.kotlin.js.translate.context.Namer;
import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator; import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils; import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
import org.jetbrains.kotlin.psi.KtDeclarationWithBody; import org.jetbrains.kotlin.psi.KtDeclarationWithBody;
import org.jetbrains.kotlin.psi.KtLambdaExpression; import org.jetbrains.kotlin.psi.KtLambdaExpression;
@@ -107,7 +106,7 @@ public final class FunctionTranslator extends AbstractTranslator {
public JsExpression translateAsMethod() { public JsExpression translateAsMethod() {
translateAsMethodWithoutMetadata(); translateAsMethodWithoutMetadata();
if (shouldBeInlined(descriptor) && DescriptorUtilsKt.isEffectivelyPublicApi(descriptor)) { if (shouldBeInlined(descriptor, context()) && DescriptorUtilsKt.isEffectivelyPublicApi(descriptor)) {
InlineMetadata metadata = InlineMetadata.compose(functionObject, descriptor); InlineMetadata metadata = InlineMetadata.compose(functionObject, descriptor);
return metadata.getFunctionWithMetadata(); return metadata.getFunctionWithMetadata();
} }
@@ -36,8 +36,6 @@ import org.jetbrains.kotlin.resolve.inline.InlineUtil;
import java.util.List; import java.util.List;
import static org.jetbrains.kotlin.js.resolve.diagnostics.JsCallChecker.isJsCall; import static org.jetbrains.kotlin.js.resolve.diagnostics.JsCallChecker.isJsCall;
import static org.jetbrains.kotlin.js.translate.utils.InlineUtils.setInlineCallMetadata;
import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.getFunctionDescriptor;
import static org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator.getConstant; import static org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator.getConstant;
public final class CallExpressionTranslator extends AbstractCallExpressionTranslator { public final class CallExpressionTranslator extends AbstractCallExpressionTranslator {
@@ -55,19 +53,12 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl
return (new CallExpressionTranslator(expression, receiver, context)).translateJsCode(); return (new CallExpressionTranslator(expression, receiver, context)).translateJsCode();
} }
JsExpression callExpression = (new CallExpressionTranslator(expression, receiver, context)).translate(); return (new CallExpressionTranslator(expression, receiver, context)).translate();
if (shouldBeInlined(expression, context)) {
setInlineCallMetadata(callExpression, expression, resolvedCall, context);
}
return callExpression;
} }
public static boolean shouldBeInlined(@NotNull KtCallExpression expression, @NotNull TranslationContext context) { public static boolean shouldBeInlined(@NotNull CallableDescriptor descriptor, @NotNull TranslationContext context) {
if (context.getConfig().getConfiguration().getBoolean(CommonConfigurationKeys.DISABLE_INLINE)) return false; if (context.getConfig().getConfiguration().getBoolean(CommonConfigurationKeys.DISABLE_INLINE)) return false;
CallableDescriptor descriptor = getFunctionDescriptor(expression, context);
return shouldBeInlined(descriptor); return shouldBeInlined(descriptor);
} }
@@ -20,11 +20,9 @@ import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.CallableDescriptor; import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.lexer.KtToken; import org.jetbrains.kotlin.lexer.KtToken;
import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
@@ -99,7 +97,7 @@ public final class PsiUtils {
return isInOperation(binaryExpression) || isNotInOperation(binaryExpression); return isInOperation(binaryExpression) || isNotInOperation(binaryExpression);
} }
public static boolean isNotInOperation(@NotNull KtBinaryExpression binaryExpression) { private static boolean isNotInOperation(@NotNull KtBinaryExpression binaryExpression) {
return (binaryExpression.getOperationToken() == KtTokens.NOT_IN); return (binaryExpression.getOperationToken() == KtTokens.NOT_IN);
} }
@@ -126,17 +124,6 @@ public final class PsiUtils {
return rangeExpression; return rangeExpression;
} }
@NotNull
public static CallableDescriptor getFunctionDescriptor(
@NotNull KtCallExpression expression,
@NotNull TranslationContext context
) {
ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCall(expression, context.bindingContext());
assert resolvedCall != null;
return getFunctionDescriptor(resolvedCall);
}
@NotNull @NotNull
public static CallableDescriptor getFunctionDescriptor(ResolvedCall<?> resolvedCall) { public static CallableDescriptor getFunctionDescriptor(ResolvedCall<?> resolvedCall) {
if (resolvedCall instanceof VariableAsFunctionResolvedCall) { if (resolvedCall instanceof VariableAsFunctionResolvedCall) {