JVM: erase conditional suspension markers from inline-only functions

Otherwise, the generated bytecode is unnecessarily suboptimal in some
(arguably weird) cases.

In the JVM backend, this was an accidental regression in #3260, as I had
not noticed that effectively inline-only functions were handled by a
separate branch in FunctionCodegen. In JVM_IR, I'm pretty sure the
redundant markers have always been there as `isSuspensionPoint` in
ExpressionCodegen never checked for effectively-inline-only-ness.
This commit is contained in:
pyos
2020-04-07 18:08:33 +02:00
committed by Ilmir Usmanov
parent f6d9867fa4
commit 0037d5a7c8
6 changed files with 34 additions and 14 deletions
@@ -80,7 +80,6 @@ import static org.jetbrains.kotlin.descriptors.ModalityKt.isOverridable;
import static org.jetbrains.kotlin.load.java.JvmAbi.LOCAL_VARIABLE_INLINE_ARGUMENT_SYNTHETIC_LINE_NUMBER;
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromDescriptor;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
import static org.jetbrains.kotlin.resolve.inline.InlineOnlyKt.isEffectivelyInlineOnly;
import static org.jetbrains.kotlin.resolve.inline.InlineOnlyKt.isInlineOnlyPrivateInBytecode;
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE;
import static org.jetbrains.kotlin.resolve.jvm.InlineClassManglingRulesKt.shouldHideConstructorDueToInlineClassTypeValueParameters;
@@ -124,18 +123,14 @@ public class FunctionCodegen {
if (owner.getContextKind() != OwnerKind.DEFAULT_IMPLS || function.hasBody()) {
FunctionGenerationStrategy strategy;
if (functionDescriptor.isSuspend()) {
if (isEffectivelyInlineOnly(functionDescriptor)) {
strategy = new FunctionGenerationStrategy.FunctionDefault(state, function);
} else {
strategy = new SuspendFunctionGenerationStrategy(
state,
CoroutineCodegenUtilKt.<FunctionDescriptor>unwrapInitialDescriptorForSuspendFunction(functionDescriptor),
function,
v.getThisName(),
state.getConstructorCallNormalizationMode(),
this
);
}
strategy = new SuspendFunctionGenerationStrategy(
state,
CoroutineCodegenUtilKt.<FunctionDescriptor>unwrapInitialDescriptorForSuspendFunction(functionDescriptor),
function,
v.getThisName(),
state.getConstructorCallNormalizationMode(),
this
);
} else {
strategy = new FunctionGenerationStrategy.FunctionDefault(state, function);
}
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.resolve.inline.isEffectivelyInlineOnly
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
@@ -56,6 +57,9 @@ class SuspendFunctionGenerationStrategy(
override fun wrapMethodVisitor(mv: MethodVisitor, access: Int, name: String, desc: String): MethodVisitor {
if (access and Opcodes.ACC_ABSTRACT != 0) return mv
if (originalSuspendDescriptor.isEffectivelyInlineOnly()) {
return SuspendForInlineOnlyMethodVisitor(mv, access, name, desc)
}
val stateMachineBuilder = createStateMachineBuilder(mv, access, name, desc)
if (originalSuspendDescriptor.isInline) {
return SuspendForInlineCopyingMethodVisitor(stateMachineBuilder, access, name, desc, functionCodegen::newMethod, keepAccess = false)
@@ -156,6 +160,13 @@ class SuspendFunctionGenerationStrategy(
}
}
private class SuspendForInlineOnlyMethodVisitor(delegate: MethodVisitor, access: Int, name: String, desc: String) :
TransformationMethodVisitor(delegate, access, name, desc, null, null) {
override fun performTransformations(methodNode: MethodNode) {
methodNode.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false)
}
}
// For named suspend function we generate two methods:
// 1) to use as noinline function, which have state machine
// 2) to use from inliner: private one without state machine