Remove obsolete experimental coroutines support

in compiler.
This commit is contained in:
Ilmir Usmanov
2021-07-29 08:49:46 +02:00
parent ebb340fe68
commit 486c6b3c15
74 changed files with 349 additions and 1019 deletions
@@ -475,7 +475,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
List<Type> superCtorArgTypes = new ArrayList<>();
if (superClassAsmType.equals(LAMBDA) || functionReferenceTarget != null ||
CoroutineCodegenUtilKt.isCoroutineSuperClass(state.getLanguageVersionSettings(), superClassAsmType.getInternalName())
CoroutineCodegenUtilKt.isCoroutineSuperClass(superClassAsmType.getInternalName())
) {
iv.iconst(CodegenUtilKt.getArity(funDescriptor));
superCtorArgTypes.add(Type.INT_TYPE);
@@ -89,7 +89,6 @@ import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor;
import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.checker.ClassicTypeSystemContextImpl;
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS;
import org.jetbrains.kotlin.types.model.KotlinTypeMarker;
import org.jetbrains.kotlin.types.model.TypeParameterMarker;
import org.jetbrains.kotlin.types.typesApproximation.CapturedTypeApproximationKt;
import org.jetbrains.kotlin.util.OperatorNameConventions;
@@ -1288,11 +1287,11 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
@NotNull
private static CallableDescriptor unwrapOriginalReceiverOwnerForSuspendLambda(@NotNull MethodContext context) {
FunctionDescriptor originalForDoResume =
context.getFunctionDescriptor().getUserData(CoroutineCodegenUtilKt.INITIAL_SUSPEND_DESCRIPTOR_FOR_DO_RESUME);
FunctionDescriptor originalForInvokeSuspend =
context.getFunctionDescriptor().getUserData(CoroutineCodegenUtilKt.INITIAL_SUSPEND_DESCRIPTOR_FOR_INVOKE_SUSPEND);
if (originalForDoResume != null) {
return originalForDoResume;
if (originalForInvokeSuspend != null) {
return originalForInvokeSuspend;
}
if (context.getFunctionDescriptor().isSuspend()) {
@@ -2617,26 +2616,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
? coroutineInstanceValueForSuspensionPoint
: getContinuationParameterFromEnclosingSuspendFunction(resolvedCall);
if (coroutineInstanceValue != null && needsExperimentalCoroutinesWrapper(resolvedCall.getCandidateDescriptor())) {
StackValue releaseContinuation = coroutineInstanceValue;
coroutineInstanceValue = new StackValue(CoroutineCodegenUtilKt.EXPERIMENTAL_CONTINUATION_ASM_TYPE) {
@Override
public void putSelector(
@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v
) {
releaseContinuation.put(CoroutineCodegenUtilKt.RELEASE_CONTINUATION_ASM_TYPE, v);
invokeCoroutineMigrationMethod(
v,
"toExperimentalContinuation",
Type.getMethodDescriptor(
CoroutineCodegenUtilKt.EXPERIMENTAL_CONTINUATION_ASM_TYPE,
CoroutineCodegenUtilKt.RELEASE_CONTINUATION_ASM_TYPE
)
);
}
};
}
tempVariables.put(continuationExpression, coroutineInstanceValue);
}
@@ -2774,7 +2753,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
SuspensionPointKind suspensionPointKind =
CoroutineCodegenUtilKt.isSuspensionPoint(resolvedCall, this, state.getLanguageVersionSettings());
CoroutineCodegenUtilKt.isSuspensionPoint(resolvedCall, this);
boolean maybeSuspensionPoint = suspensionPointKind != SuspensionPointKind.NEVER && !insideCallableReference();
boolean isConstructor = resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor;
if (!(callableMethod instanceof IntrinsicWithSpecialReceiver)) {
@@ -2833,7 +2812,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
KotlinType unboxedInlineClass = CoroutineCodegenUtilKt.originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass(
(FunctionDescriptor) resolvedCall.getResultingDescriptor(), typeMapper);
if (unboxedInlineClass != null) {
CoroutineCodegenUtilKt.generateCoroutineSuspendedCheck(v, state.getLanguageVersionSettings());
CoroutineCodegenUtilKt.generateCoroutineSuspendedCheck(v);
}
}
@@ -2948,7 +2927,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
FunctionDescriptor original =
CoroutineCodegenUtilKt.getOriginalSuspendFunctionView(
unwrapInitialSignatureDescriptor(DescriptorUtils.unwrapFakeOverride((FunctionDescriptor) descriptor.getOriginal())),
bindingContext, state
bindingContext
);
FunctionDescriptor functionDescriptor =
@@ -5243,7 +5222,7 @@ The "returned" value of try expression with no finally is either the last expres
}
CodegenUtilKt.generateAsCast(
v, rightKotlinType, boxedRightType, safeAs, state.getLanguageVersionSettings(), state.getUnifiedNullChecks()
v, rightKotlinType, boxedRightType, safeAs, state.getUnifiedNullChecks()
);
return Unit.INSTANCE;
@@ -5297,7 +5276,7 @@ The "returned" value of try expression with no finally is either the last expres
return null;
}
CodegenUtilKt.generateIsCheck(v, rhsKotlinType, type, state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines));
CodegenUtilKt.generateIsCheck(v, rhsKotlinType, type);
return null;
});
}
@@ -481,8 +481,7 @@ public class FunctionCodegen {
}
if (!functionDescriptor.isExternal()) {
generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy, memberCodegen, state.getJvmDefaultMode(),
state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines));
generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy, memberCodegen, state.getJvmDefaultMode());
}
else if (staticInCompanionObject) {
// native @JvmStatic foo() in companion object should delegate to the static native function moved to the outer class
@@ -583,8 +582,7 @@ public class FunctionCodegen {
@NotNull JvmMethodSignature signature,
@NotNull FunctionGenerationStrategy strategy,
@NotNull MemberCodegen<?> parentCodegen,
@NotNull JvmDefaultMode jvmDefaultMode,
boolean isReleaseCoroutines
@NotNull JvmDefaultMode jvmDefaultMode
) {
mv.visitCode();
@@ -594,8 +592,7 @@ public class FunctionCodegen {
KotlinTypeMapper typeMapper = parentCodegen.typeMapper;
if (BuiltinSpecialBridgesUtil.shouldHaveTypeSafeBarrier(functionDescriptor, typeMapper::mapAsmMethod)) {
generateTypeCheckBarrierIfNeeded(
new InstructionAdapter(mv), functionDescriptor, signature.getReturnType(), null, typeMapper,
isReleaseCoroutines);
new InstructionAdapter(mv), functionDescriptor, signature.getReturnType(), null, typeMapper);
}
Label methodEntry = null;
@@ -1430,8 +1427,7 @@ public class FunctionCodegen {
MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv);
if (delegateTo.getArgumentTypes().length > 0 && isSpecialBridge) {
generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes(), typeMapper,
state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines));
generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes(), typeMapper);
}
iv.load(0, OBJECT_TYPE);
@@ -1477,8 +1473,7 @@ public class FunctionCodegen {
@NotNull FunctionDescriptor descriptor,
@NotNull Type returnType,
@Nullable Type[] delegateParameterTypes,
@NotNull KotlinTypeMapper typeMapper,
boolean isReleaseCoroutines
@NotNull KotlinTypeMapper typeMapper
) {
BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription typeSafeBarrierDescription =
BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor);
@@ -1512,7 +1507,7 @@ public class FunctionCodegen {
} else {
targetBoxedType = boxType(delegateParameterTypes[i]);
}
CodegenUtilKt.generateIsCheck(iv, kotlinType, targetBoxedType, isReleaseCoroutines);
CodegenUtilKt.generateIsCheck(iv, kotlinType, targetBoxedType);
iv.ifeq(defaultBranch);
}
}
@@ -5,13 +5,12 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.builtins.StandardNames.COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME
import org.jetbrains.kotlin.builtins.createFunctionType
import org.jetbrains.kotlin.codegen.coroutines.coroutinesJvmInternalPackageFqName
import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
import org.jetbrains.kotlin.codegen.coroutines.isSuspendLambdaOrLocalFunction
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
@@ -33,8 +32,7 @@ class JvmRuntimeTypes(
private val generateOptimizedCallableReferenceSuperClasses: Boolean
) {
private val kotlinJvmInternalPackage = MutablePackageFragmentDescriptor(module, FqName("kotlin.jvm.internal"))
private val kotlinCoroutinesJvmInternalPackage =
MutablePackageFragmentDescriptor(module, languageVersionSettings.coroutinesJvmInternalPackageFqName())
private val kotlinCoroutinesJvmInternalPackage = MutablePackageFragmentDescriptor(module, COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME)
private fun internal(className: String, packageFragment: PackageFragmentDescriptor = kotlinJvmInternalPackage): Lazy<ClassDescriptor> =
lazy { createClass(packageFragment, className) }
@@ -53,24 +51,16 @@ class JvmRuntimeTypes(
private val localVariableReference: ClassDescriptor by internal("LocalVariableReference")
private val mutableLocalVariableReference: ClassDescriptor by internal("MutableLocalVariableReference")
private val coroutineImpl: ClassDescriptor by internal("CoroutineImpl", kotlinCoroutinesJvmInternalPackage)
private val continuationImpl: ClassDescriptor by coroutinesInternal("ContinuationImpl")
private val restrictedContinuationImpl: ClassDescriptor by coroutinesInternal("RestrictedContinuationImpl")
private val suspendLambda: ClassDescriptor by coroutinesInternal("SuspendLambda")
private val restrictedSuspendLambda: ClassDescriptor by coroutinesInternal("RestrictedSuspendLambda")
private val suspendFunctionInterface: ClassDescriptor? by lazy {
if (languageVersionSettings.isReleaseCoroutines())
createClass(kotlinCoroutinesJvmInternalPackage, "SuspendFunction", ClassKind.INTERFACE)
else null
createClass(kotlinCoroutinesJvmInternalPackage, "SuspendFunction", ClassKind.INTERFACE)
}
private fun createCoroutineSuperClass(className: String): ClassDescriptor {
return if (languageVersionSettings.isReleaseCoroutines())
createClass(kotlinCoroutinesJvmInternalPackage, className)
else
coroutineImpl
}
private fun createCoroutineSuperClass(className: String): ClassDescriptor = createClass(kotlinCoroutinesJvmInternalPackage, className)
private val propertyReferences: List<ClassDescriptor> by propertyClasses("PropertyReference", "")
private val mutablePropertyReferences: List<ClassDescriptor> by propertyClasses("MutablePropertyReference", "")
@@ -94,7 +84,7 @@ class JvmRuntimeTypes(
fun getSupertypesForClosure(descriptor: FunctionDescriptor): Collection<KotlinType> {
val actualFunctionDescriptor =
if (descriptor.isSuspend)
getOrCreateJvmSuspendFunctionView(descriptor, languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines))
getOrCreateJvmSuspendFunctionView(descriptor)
else
descriptor
@@ -118,7 +108,7 @@ class JvmRuntimeTypes(
if (descriptor.isSuspend) {
return mutableListOf<KotlinType>().apply {
if (actualFunctionDescriptor.extensionReceiverParameter?.type
?.isRestrictsSuspensionReceiver(languageVersionSettings) == true
?.isRestrictsSuspensionReceiver() == true
) {
if (descriptor.isSuspendLambdaOrLocalFunction()) {
add(restrictedSuspendLambda.defaultType)
@@ -477,7 +477,6 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
SimpleFunctionDescriptor jvmSuspendFunctionView =
CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(
functionDescriptor,
languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines),
this.bindingContext
);
@@ -714,54 +713,6 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
super.visitCallExpression(expression);
checkSamCall(expression);
checkCrossinlineCall(expression);
recordSuspendFunctionTypeWrapperForArguments(expression);
}
private void recordSuspendFunctionTypeWrapperForArguments(@NotNull KtCallExpression expression) {
ResolvedCall<?> call = CallUtilKt.getResolvedCall(expression, bindingContext);
if (call == null) return;
CallableDescriptor descriptor = call.getResultingDescriptor();
if (!CodegenUtilKt.needsExperimentalCoroutinesWrapper(descriptor)) return;
List<ResolvedValueArgument> argumentsByIndex = call.getValueArgumentsByIndex();
if (argumentsByIndex == null) return;
for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
ResolvedValueArgument resolvedValueArgument = argumentsByIndex.get(parameter.getIndex());
if (!(resolvedValueArgument instanceof ExpressionValueArgument)) continue;
ValueArgument valueArgument = ((ExpressionValueArgument) resolvedValueArgument).getValueArgument();
if (valueArgument == null) continue;
KtExpression argumentExpression = valueArgument.getArgumentExpression();
if (argumentExpression == null) continue;
recordSuspendFunctionTypeWrapperForArgument(parameter, argumentExpression);
}
ReceiverValue receiver = call.getExtensionReceiver();
if (descriptor.getExtensionReceiverParameter() != null && receiver instanceof ExpressionReceiver) {
recordSuspendFunctionTypeWrapperForArgument(
descriptor.getExtensionReceiverParameter(),
((ExpressionReceiver) receiver).getExpression()
);
}
}
private void recordSuspendFunctionTypeWrapperForArgument(ParameterDescriptor parameter, KtExpression argumentExpression) {
if (FunctionTypesKt.isSuspendFunctionTypeOrSubtype(parameter.getType())) {
// SuspendFunctionN type is mapped to is mapped to FunctionTypeN+1, but we also need to remove an argument for return type
// So, it could be parameter.getType().getArguments().size() + 1 - 1
int functionTypeArity = parameter.getType().getArguments().size();
Type functionType = Type.getObjectType(NUMBERED_FUNCTION_PREFIX + functionTypeArity);
bindingTrace.record(
FUNCTION_TYPE_FOR_SUSPEND_WRAPPER,
argumentExpression,
functionType
);
}
}
private void checkCrossinlineCall(@NotNull KtCallExpression expression) {
@@ -13,15 +13,13 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.context.CodegenContext
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext
import org.jetbrains.kotlin.codegen.context.MultifileClassFacadeContext
import org.jetbrains.kotlin.codegen.coroutines.continuationAsmType
import org.jetbrains.kotlin.codegen.coroutines.CONTINUATION_ASM_TYPE
import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction
import org.jetbrains.kotlin.codegen.inline.NUMBERED_FUNCTION_PREFIX
import org.jetbrains.kotlin.codegen.inline.ReificationArgument
import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
@@ -45,8 +43,6 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.Synthetic
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor.CoroutinesCompatibilityMode
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
@@ -70,8 +66,7 @@ internal val JAVA_LANG_DEPRECATED = Type.getType(Deprecated::class.java).descrip
fun generateIsCheck(
v: InstructionAdapter,
kotlinType: KotlinType,
asmType: Type,
isReleaseCoroutines: Boolean
asmType: Type
) {
if (TypeUtils.isNullableType(kotlinType)) {
val nope = Label()
@@ -82,7 +77,7 @@ fun generateIsCheck(
ifnull(nope)
TypeIntrinsics.instanceOf(this, kotlinType, asmType, isReleaseCoroutines)
TypeIntrinsics.instanceOf(this, kotlinType, asmType)
goTo(end)
@@ -93,7 +88,7 @@ fun generateIsCheck(
mark(end)
}
} else {
TypeIntrinsics.instanceOf(v, kotlinType, asmType, isReleaseCoroutines)
TypeIntrinsics.instanceOf(v, kotlinType, asmType)
}
}
@@ -102,7 +97,6 @@ fun generateAsCast(
kotlinType: KotlinType,
asmType: Type,
isSafe: Boolean,
languageVersionSettings: LanguageVersionSettings,
unifiedNullChecks: Boolean,
) {
if (!isSafe) {
@@ -112,7 +106,7 @@ fun generateAsCast(
} else {
with(v) {
dup()
TypeIntrinsics.instanceOf(v, kotlinType, asmType, languageVersionSettings.isReleaseCoroutines())
TypeIntrinsics.instanceOf(v, kotlinType, asmType)
val ok = Label()
ifne(ok)
pop()
@@ -444,14 +438,10 @@ fun KotlinType.isInlineClassTypeWithPrimitiveEquality(): Boolean {
return false
}
fun CallableDescriptor.needsExperimentalCoroutinesWrapper() =
(this as? DeserializedMemberDescriptor)?.coroutinesExperimentalCompatibilityMode == CoroutinesCompatibilityMode.NEEDS_WRAPPER
fun recordCallLabelForLambdaArgument(declaration: KtFunctionLiteral, bindingTrace: BindingTrace) {
val labelName = getCallLabelForLambdaArgument(declaration, bindingTrace.bindingContext) ?: return
val functionDescriptor = bindingTrace[BindingContext.FUNCTION, declaration] ?: return
bindingTrace.record(CodegenBinding.CALL_LABEL_FOR_LAMBDA_ARGUMENT, functionDescriptor, labelName)
}
fun getCallLabelForLambdaArgument(declaration: KtFunctionLiteral, bindingContext: BindingContext): String? {
@@ -647,7 +637,7 @@ private fun generateLambdaForRunSuspend(
}
visitVarInsn(ALOAD, 1)
val continuationInternalName = state.languageVersionSettings.continuationAsmType().internalName
val continuationInternalName = CONTINUATION_ASM_TYPE.internalName
visitTypeInsn(
CHECKCAST,
@@ -6,9 +6,9 @@
package org.jetbrains.kotlin.codegen.context
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineUninterceptedOrReturn
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.binding.MutableClosure
import org.jetbrains.kotlin.config.coroutinesPackageFqName
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
import org.jetbrains.kotlin.descriptors.isTopLevelInPackage
@@ -17,25 +17,26 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getParentResolvedCall
import org.jetbrains.kotlin.resolve.source.getPsi
class InlineLambdaContext(
functionDescriptor: FunctionDescriptor,
contextKind: OwnerKind,
parentContext: CodegenContext<*>,
closure: MutableClosure?,
val isCrossInline: Boolean,
private val isPropertyReference: Boolean
functionDescriptor: FunctionDescriptor,
contextKind: OwnerKind,
parentContext: CodegenContext<*>,
closure: MutableClosure?,
val isCrossInline: Boolean,
private val isPropertyReference: Boolean
) : MethodContext(functionDescriptor, contextKind, parentContext, closure, false) {
override fun getFirstCrossInlineOrNonInlineContext(): CodegenContext<*> {
if (isCrossInline && !isSuspendIntrinsicParameter()) return this
val parent = if (isPropertyReference) parentContext as? AnonymousClassContext else { parentContext as? ClosureContext } ?:
throw AssertionError(
"Parent of inlining lambda body should be " +
"${if (isPropertyReference) "ClosureContext" else "AnonymousClassContext"}, but: $parentContext"
)
val parent = if (isPropertyReference) parentContext as? AnonymousClassContext else {
parentContext as? ClosureContext
} ?: throw AssertionError(
"Parent of inlining lambda body should be " +
"${if (isPropertyReference) "ClosureContext" else "AnonymousClassContext"}, but: $parentContext"
)
val grandParent = parent.parentContext ?:
throw AssertionError("Parent context of lambda class context should exist: $contextDescriptor")
val grandParent =
parent.parentContext ?: throw AssertionError("Parent context of lambda class context should exist: $contextDescriptor")
return grandParent.firstCrossInlineOrNonInlineContext
}
@@ -44,7 +45,7 @@ class InlineLambdaContext(
if (contextDescriptor !is AnonymousFunctionDescriptor) return false
val resolvedCall = (contextDescriptor.source.getPsi() as? KtElement).getParentResolvedCall(state.bindingContext) ?: return false
val descriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return false
return descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(state.languageVersionSettings)
|| descriptor.isTopLevelInPackage("suspendCoroutine", state.languageVersionSettings.coroutinesPackageFqName().asString())
return descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn()
|| descriptor.isTopLevelInPackage("suspendCoroutine", StandardNames.COROUTINES_PACKAGE_FQ_NAME.asString())
}
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.codegen.coroutines
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.optimization.boxing.isPrimitiveBoxing
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
@@ -15,10 +16,9 @@ import org.jetbrains.kotlin.utils.sure
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import java.util.*
private val BOXING_CLASS_INTERNAL_NAME =
RELEASE_COROUTINES_VERSION_SETTINGS.coroutinesJvmInternalPackageFqName().child(Name.identifier("Boxing")).topLevelClassInternalName()
StandardNames.COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(Name.identifier("Boxing")).topLevelClassInternalName()
@OptIn(ExperimentalStdlibApi::class)
object ChangeBoxingMethodTransformer : MethodTransformer() {
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.codegen.coroutines
import com.intellij.util.ArrayUtil
import org.jetbrains.kotlin.backend.common.CodegenUtil
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.binding.CodegenBinding.CAPTURES_CROSSINLINE_LAMBDA
@@ -17,8 +18,6 @@ import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.METHO
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
@@ -41,7 +40,6 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.serialization.DescriptorSerializer
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.utils.sure
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.MethodVisitor
@@ -56,7 +54,7 @@ abstract class AbstractCoroutineCodegen(
element: KtElement,
closureContext: ClosureContext,
classBuilder: ClassBuilder,
private val userDataForDoResume: Map<out CallableDescriptor.UserDataKey<*>, *>? = null
private val userDataForInvokeSuspend: Map<out CallableDescriptor.UserDataKey<*>, *>? = null
) : ClosureCodegen(
outerExpressionCodegen.state,
element, null, closureContext, null,
@@ -67,17 +65,10 @@ abstract class AbstractCoroutineCodegen(
protected val languageVersionSettings = outerExpressionCodegen.state.languageVersionSettings
protected val methodToImplement =
if (languageVersionSettings.isReleaseCoroutines())
createImplMethod(
INVOKE_SUSPEND_METHOD_NAME,
SUSPEND_CALL_RESULT_NAME to classDescriptor.module.getResult(classDescriptor.builtIns.anyType)
)
else
createImplMethod(
DO_RESUME_METHOD_NAME,
"data" to classDescriptor.builtIns.nullableAnyType,
"throwable" to classDescriptor.builtIns.throwable.defaultType.makeNullable()
)
createImplMethod(
INVOKE_SUSPEND_METHOD_NAME,
SUSPEND_CALL_RESULT_NAME to classDescriptor.module.getResult(classDescriptor.builtIns.anyType)
)
private fun createImplMethod(name: String, vararg parameters: Pair<String, KotlinType>) =
SimpleFunctionDescriptorImpl.create(
@@ -94,7 +85,7 @@ abstract class AbstractCoroutineCodegen(
builtIns.nullableAnyType,
Modality.FINAL,
DescriptorVisibilities.PUBLIC,
userDataForDoResume
userDataForInvokeSuspend
)
}
@@ -109,7 +100,7 @@ abstract class AbstractCoroutineCodegen(
override fun generateConstructor(): Method {
val args = calculateConstructorParameters(typeMapper, languageVersionSettings, closure, asmType)
val argTypes = args.map { it.fieldType }.plus(languageVersionSettings.continuationAsmType()).toTypedArray()
val argTypes = args.map { it.fieldType }.plus(CONTINUATION_ASM_TYPE).toTypedArray()
val constructor = Method("<init>", Type.VOID_TYPE, argTypes)
val mv = v.newMethod(
@@ -124,18 +115,17 @@ abstract class AbstractCoroutineCodegen(
iv.generateClosureFieldsInitializationFromParameters(closure, args)
iv.load(0, AsmTypes.OBJECT_TYPE)
val hasArityParameter = !languageVersionSettings.isReleaseCoroutines() || passArityToSuperClass
if (hasArityParameter) {
iv.iconst(if (passArityToSuperClass) funDescriptor.arity else 0)
if (passArityToSuperClass) {
iv.iconst(funDescriptor.arity)
}
iv.load(argTypes.map { it.size }.sum(), AsmTypes.OBJECT_TYPE)
val parameters =
if (hasArityParameter)
listOf(Type.INT_TYPE, languageVersionSettings.continuationAsmType())
if (passArityToSuperClass)
listOf(Type.INT_TYPE, CONTINUATION_ASM_TYPE)
else
listOf(languageVersionSettings.continuationAsmType())
listOf(CONTINUATION_ASM_TYPE)
val superClassConstructorDescriptor = Type.getMethodDescriptor(
Type.VOID_TYPE,
@@ -148,9 +138,7 @@ abstract class AbstractCoroutineCodegen(
FunctionCodegen.endVisit(iv, "constructor", element)
}
if (languageVersionSettings.isReleaseCoroutines()) {
v.newField(JvmDeclarationOrigin.NO_ORIGIN, AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "label", "I", null, null)
}
v.newField(JvmDeclarationOrigin.NO_ORIGIN, AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "label", "I", null, null)
return constructor
}
@@ -167,7 +155,7 @@ class CoroutineCodegenForLambda private constructor(
private val forInline: Boolean
) : AbstractCoroutineCodegen(
outerExpressionCodegen, element, closureContext, classBuilder,
userDataForDoResume = mapOf(INITIAL_SUSPEND_DESCRIPTOR_FOR_DO_RESUME to originalSuspendFunctionDescriptor)
userDataForInvokeSuspend = mapOf(INITIAL_SUSPEND_DESCRIPTOR_FOR_INVOKE_SUSPEND to originalSuspendFunctionDescriptor)
) {
private val builtIns = funDescriptor.builtIns
@@ -215,8 +203,7 @@ class CoroutineCodegenForLambda private constructor(
funDescriptor.typeParameters,
funDescriptor.valueParameters,
funDescriptor.module.getContinuationOfTypeOrAny(
builtIns.unitType,
state.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
builtIns.unitType
),
funDescriptor.modality,
DescriptorVisibilities.PUBLIC
@@ -231,14 +218,11 @@ class CoroutineCodegenForLambda private constructor(
"too many arguments of create to have an erased signature: $argumentsNum: $typedCreate"
}
return typedCreate.module.resolveClassByFqName(
languageVersionSettings.coroutinesJvmInternalPackageFqName().child(
if (languageVersionSettings.isReleaseCoroutines())
Name.identifier("BaseContinuationImpl")
else
Name.identifier("CoroutineImpl")
StandardNames.COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(
Name.identifier("BaseContinuationImpl")
),
NoLookupLocation.FROM_BACKEND
).sure { "BaseContinuationImpl or CoroutineImpl is not found" }.defaultType.memberScope
).sure { "BaseContinuationImpl is not found" }.defaultType.memberScope
.getContributedFunctions(typedCreate.name, NoLookupLocation.FROM_BACKEND)
.find { it.valueParameters.size == argumentsNum }
.sure { "erased parent of $typedCreate is not found" }
@@ -365,7 +349,7 @@ class CoroutineCodegenForLambda private constructor(
v.thisName,
typeMapper.mapFunctionName(createCoroutineDescriptor, null),
Type.getMethodDescriptor(
languageVersionSettings.continuationAsmType(),
CONTINUATION_ASM_TYPE,
*createArgumentTypes.toTypedArray()
),
false
@@ -373,11 +357,7 @@ class CoroutineCodegenForLambda private constructor(
checkcast(Type.getObjectType(v.thisName))
// .doResume(Unit)
if (languageVersionSettings.isReleaseCoroutines()) {
invokeInvokeSuspendWithUnit(v.thisName)
} else {
invokeDoResumeWithUnit(v.thisName)
}
invokeInvokeSuspendWithUnit(v.thisName)
areturn(AsmTypes.OBJECT_TYPE)
}
@@ -540,15 +520,14 @@ class CoroutineCodegenForLambda private constructor(
override fun wrapMethodVisitor(mv: MethodVisitor, access: Int, name: String, desc: String): MethodVisitor {
val stateMachineBuilder = CoroutineTransformerMethodVisitor(
mv, access, name, desc, null, null,
containingClassInternalName = v.thisName,
obtainClassBuilderForCoroutineState = { v },
isForNamedFunction = false,
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
disableTailCallOptimizationForFunctionReturningUnit = false,
reportSuspensionPointInsideMonitor = { reportSuspensionPointInsideMonitor(element, state, it) },
lineNumber = CodegenUtil.getLineNumberForElement(element, false) ?: 0,
sourceFile = element.containingKtFile.name,
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
containingClassInternalName = v.thisName,
isForNamedFunction = false,
languageVersionSettings = languageVersionSettings,
disableTailCallOptimizationForFunctionReturningUnit = false,
useOldSpilledVarTypeAnalysis = state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS),
initialVarsCountByType = varsCountByType
)
@@ -625,7 +604,7 @@ class CoroutineCodegenForNamedFunction private constructor(
private val labelFieldStackValue by lazy {
StackValue.field(
FieldInfo.createForHiddenField(
computeLabelOwner(languageVersionSettings, v.thisName),
Type.getObjectType(v.thisName),
Type.INT_TYPE,
COROUTINE_LABEL_FIELD_NAME
),
@@ -647,44 +626,25 @@ class CoroutineCodegenForNamedFunction private constructor(
}
override fun generateClosureBody() {
generateResumeImpl()
if (!languageVersionSettings.isReleaseCoroutines()) {
generateGetLabelMethod()
generateSetLabelMethod()
}
generateInvokeSuspend()
v.newField(
JvmDeclarationOrigin.NO_ORIGIN, Opcodes.ACC_SYNTHETIC or AsmUtil.NO_FLAG_PACKAGE_PRIVATE,
languageVersionSettings.dataFieldName(), AsmTypes.OBJECT_TYPE.descriptor, null, null
CONTINUATION_RESULT_FIELD_NAME, AsmTypes.OBJECT_TYPE.descriptor, null, null
)
if (!languageVersionSettings.isReleaseCoroutines()) {
v.newField(
JvmDeclarationOrigin.NO_ORIGIN, Opcodes.ACC_SYNTHETIC or AsmUtil.NO_FLAG_PACKAGE_PRIVATE,
EXCEPTION_FIELD_NAME, AsmTypes.JAVA_THROWABLE_TYPE.descriptor, null, null
)
}
}
private fun generateResumeImpl() {
private fun generateInvokeSuspend() {
functionCodegen.generateMethod(
OtherOrigin(element),
methodToImplement,
object : FunctionGenerationStrategy.CodegenBased(state) {
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
StackValue.field(
AsmTypes.OBJECT_TYPE, Type.getObjectType(v.thisName), languageVersionSettings.dataFieldName(), false,
AsmTypes.OBJECT_TYPE, Type.getObjectType(v.thisName), CONTINUATION_RESULT_FIELD_NAME, false,
StackValue.LOCAL_0
).store(StackValue.local(1, AsmTypes.OBJECT_TYPE), codegen.v)
if (!languageVersionSettings.isReleaseCoroutines()) {
StackValue.field(
AsmTypes.JAVA_THROWABLE_TYPE, Type.getObjectType(v.thisName), EXCEPTION_FIELD_NAME, false,
StackValue.LOCAL_0
).store(StackValue.local(2, AsmTypes.JAVA_THROWABLE_TYPE), codegen.v)
}
labelFieldStackValue.store(
StackValue.operation(Type.INT_TYPE) {
labelFieldStackValue.put(Type.INT_TYPE, it)
@@ -736,7 +696,7 @@ class CoroutineCodegenForNamedFunction private constructor(
with(codegen.v) {
// We need to box the returned inline class in resume path.
// But first, check for COROUTINE_SUSPENDED, since the function can return it
generateCoroutineSuspendedCheck(languageVersionSettings)
generateCoroutineSuspendedCheck()
// Now we box the inline class
StackValue.coerce(AsmTypes.OBJECT_TYPE, typeMapper.mapType(inlineClassToBoxInInvokeSuspend), this)
StackValue.boxInlineClass(inlineClassToBoxInInvokeSuspend, this, typeMapper)
@@ -9,15 +9,10 @@ import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.inline.*
import org.jetbrains.kotlin.codegen.optimization.common.*
import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransformer
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.utils.sure
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
@@ -49,7 +44,6 @@ class CoroutineTransformerMethodVisitor(
obtainClassBuilderForCoroutineState: () -> ClassBuilder,
private val isForNamedFunction: Boolean,
private val shouldPreserveClassInitialization: Boolean,
private val languageVersionSettings: LanguageVersionSettings,
// Since tail-call optimization of functions with Unit return type relies on ability of call-site to recognize them,
// in order to ignore return value and push Unit, when we cannot ensure this ability, for example, when the function overrides function,
// returning Any, we need to disable tail-call optimization for these functions.
@@ -73,7 +67,6 @@ class CoroutineTransformerMethodVisitor(
private var continuationIndex = if (isForNamedFunction) -1 else 0
private var dataIndex = if (isForNamedFunction) -1 else 1
private var exceptionIndex = if (isForNamedFunction || languageVersionSettings.isReleaseCoroutines()) -1 else 2
override fun performTransformations(methodNode: MethodNode) {
removeFakeContinuationConstructorCall(methodNode)
@@ -89,9 +82,7 @@ class CoroutineTransformerMethodVisitor(
val suspensionPoints = collectSuspensionPoints(methodNode)
RedundantLocalsEliminationMethodTransformer(suspensionPoints)
.transform(containingClassInternalName, methodNode)
if (languageVersionSettings.isReleaseCoroutines()) {
ChangeBoxingMethodTransformer.transform(containingClassInternalName, methodNode)
}
ChangeBoxingMethodTransformer.transform(containingClassInternalName, methodNode)
updateMaxStack(methodNode)
checkForSuspensionPointInsideMonitor(methodNode, suspensionPoints)
@@ -105,7 +96,6 @@ class CoroutineTransformerMethodVisitor(
}
val examiner = MethodNodeExaminer(
languageVersionSettings,
containingClassInternalName,
methodNode,
suspensionPoints,
@@ -119,9 +109,6 @@ class CoroutineTransformerMethodVisitor(
}
dataIndex = methodNode.maxLocals++
if (!languageVersionSettings.isReleaseCoroutines()) {
exceptionIndex = methodNode.maxLocals++
}
continuationIndex = methodNode.maxLocals++
prepareMethodNodePreludeForNamedFunction(methodNode)
@@ -158,7 +145,7 @@ class CoroutineTransformerMethodVisitor(
insertBefore(
actualCoroutineStart,
insnListOf(
*withInstructionAdapter { loadCoroutineSuspendedMarker(languageVersionSettings) }.toArray(),
*withInstructionAdapter { loadCoroutineSuspendedMarker() }.toArray(),
tableSwitchLabel,
// Allow debugger to stop on enter into suspend function
LineNumberNode(lineNumber, tableSwitchLabel),
@@ -176,7 +163,7 @@ class CoroutineTransformerMethodVisitor(
)
insert(firstStateLabel, withInstructionAdapter {
generateResumeWithExceptionCheck(languageVersionSettings.isReleaseCoroutines(), dataIndex, exceptionIndex)
generateResumeWithExceptionCheck(dataIndex)
})
insert(last, defaultLabel)
@@ -194,9 +181,7 @@ class CoroutineTransformerMethodVisitor(
updateLvtAccordingToLiveness(methodNode, isForNamedFunction, stateLabels)
if (languageVersionSettings.isReleaseCoroutines()) {
writeDebugMetadata(methodNode, suspensionPointLineNumbers, spilledToVariableMapping)
}
writeDebugMetadata(methodNode, suspensionPointLineNumbers, spilledToVariableMapping)
}
// When suspension point is inlined, it is in range of fake inliner variables.
@@ -263,7 +248,7 @@ class CoroutineTransformerMethodVisitor(
methodNode.localVariables.add(
LocalVariableNode(
SUSPEND_FUNCTION_COMPLETION_PARAMETER_NAME,
languageVersionSettings.continuationAsmType().descriptor,
CONTINUATION_ASM_TYPE.descriptor,
null,
startLabel,
endLabel,
@@ -402,7 +387,7 @@ class CoroutineTransformerMethodVisitor(
methodNode.instructions.add(withInstructionAdapter { mark(endLabel) })
methodNode.visitLocalVariable(
CONTINUATION_VARIABLE_NAME,
languageVersionSettings.continuationAsmType().descriptor,
CONTINUATION_ASM_TYPE.descriptor,
null,
startLabel,
endLabel,
@@ -430,33 +415,17 @@ class CoroutineTransformerMethodVisitor(
}
private fun InstructionAdapter.getLabel() {
if (isForNamedFunction && !languageVersionSettings.isReleaseCoroutines())
invokevirtual(
classBuilderForCoroutineState.thisName,
"getLabel",
Type.getMethodDescriptor(Type.INT_TYPE),
false
)
else
getfield(
computeLabelOwner(languageVersionSettings, classBuilderForCoroutineState.thisName).internalName,
COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor
)
getfield(
Type.getObjectType(classBuilderForCoroutineState.thisName).internalName,
COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor
)
}
private fun InstructionAdapter.setLabel() {
if (isForNamedFunction && !languageVersionSettings.isReleaseCoroutines())
invokevirtual(
classBuilderForCoroutineState.thisName,
"setLabel",
Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE),
false
)
else
putfield(
computeLabelOwner(languageVersionSettings, classBuilderForCoroutineState.thisName).internalName,
COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor
)
putfield(
Type.getObjectType(classBuilderForCoroutineState.thisName).internalName,
COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor
)
}
private fun updateMaxStack(methodNode: MethodNode) {
@@ -534,8 +503,7 @@ class CoroutineTransformerMethodVisitor(
needDispatchReceiver,
internalNameForDispatchReceiver,
containingClassInternalName,
classBuilderForCoroutineState,
languageVersionSettings
classBuilderForCoroutineState
)
visitVarInsn(Opcodes.ASTORE, continuationIndex)
@@ -543,19 +511,13 @@ class CoroutineTransformerMethodVisitor(
visitLabel(afterCoroutineStateCreated)
visitVarInsn(Opcodes.ALOAD, continuationIndex)
getfield(classBuilderForCoroutineState.thisName, languageVersionSettings.dataFieldName(), AsmTypes.OBJECT_TYPE.descriptor)
getfield(classBuilderForCoroutineState.thisName, CONTINUATION_RESULT_FIELD_NAME, AsmTypes.OBJECT_TYPE.descriptor)
visitVarInsn(Opcodes.ASTORE, dataIndex)
val resultStartLabel = Label()
visitLabel(resultStartLabel)
addContinuationAndResultToLvt(methodNode, afterCoroutineStateCreated, resultStartLabel)
if (!languageVersionSettings.isReleaseCoroutines()) {
visitVarInsn(Opcodes.ALOAD, continuationIndex)
getfield(classBuilderForCoroutineState.thisName, EXCEPTION_FIELD_NAME, AsmTypes.JAVA_THROWABLE_TYPE.descriptor)
visitVarInsn(Opcodes.ASTORE, exceptionIndex)
}
})
}
@@ -692,7 +654,7 @@ class CoroutineTransformerMethodVisitor(
// k + 1 - data
// k + 2 - exception
for (slot in 0 until localsCount) {
if (slot == continuationIndex || slot == dataIndex || slot == exceptionIndex) continue
if (slot == continuationIndex || slot == dataIndex) continue
val value = frame.getLocal(slot)
if (value.type == null || !livenessFrame.isAlive(slot)) continue
@@ -992,7 +954,7 @@ class CoroutineTransformerMethodVisitor(
insert(possibleTryCatchBlockStart, withInstructionAdapter {
nop()
generateResumeWithExceptionCheck(languageVersionSettings.isReleaseCoroutines(), dataIndex, exceptionIndex)
generateResumeWithExceptionCheck(dataIndex)
// Load continuation argument just like suspending function returns it
load(dataIndex, AsmTypes.OBJECT_TYPE)
@@ -1118,8 +1080,7 @@ internal fun InstructionAdapter.generateContinuationConstructorCall(
needDispatchReceiver: Boolean,
internalNameForDispatchReceiver: String?,
containingClassInternalName: String,
classBuilderForCoroutineState: ClassBuilder,
languageVersionSettings: LanguageVersionSettings
classBuilderForCoroutineState: ClassBuilder
) {
anew(objectTypeForState)
dup()
@@ -1128,8 +1089,7 @@ internal fun InstructionAdapter.generateContinuationConstructorCall(
getParameterTypesIndicesForCoroutineConstructor(
methodNode.desc,
methodNode.access,
needDispatchReceiver, internalNameForDispatchReceiver ?: containingClassInternalName,
languageVersionSettings
needDispatchReceiver, internalNameForDispatchReceiver ?: containingClassInternalName
)
for ((type, index) in parameterTypesAndIndices) {
load(index, type)
@@ -1149,22 +1109,11 @@ internal fun InstructionAdapter.generateContinuationConstructorCall(
)
}
private fun InstructionAdapter.generateResumeWithExceptionCheck(isReleaseCoroutines: Boolean, dataIndex: Int, exceptionIndex: Int) {
private fun InstructionAdapter.generateResumeWithExceptionCheck(dataIndex: Int) {
// Check if resumeWithException has been called
if (isReleaseCoroutines) {
load(dataIndex, AsmTypes.OBJECT_TYPE)
invokestatic("kotlin/ResultKt", "throwOnFailure", "(Ljava/lang/Object;)V", false)
} else {
load(exceptionIndex, AsmTypes.OBJECT_TYPE)
dup()
val noExceptionLabel = Label()
ifnull(noExceptionLabel)
athrow()
mark(noExceptionLabel)
pop()
}
load(dataIndex, AsmTypes.OBJECT_TYPE)
invokestatic("kotlin/ResultKt", "throwOnFailure", "(Ljava/lang/Object;)V", false)
}
private fun Type.fieldNameForVar(index: Int) = descriptor.first() + "$" + index
@@ -1235,16 +1184,15 @@ private fun getParameterTypesIndicesForCoroutineConstructor(
desc: String,
containingFunctionAccess: Int,
needDispatchReceiver: Boolean,
thisName: String,
languageVersionSettings: LanguageVersionSettings
thisName: String
): Collection<Pair<Type, Int>> {
return mutableListOf<Pair<Type, Int>>().apply {
if (needDispatchReceiver) {
add(Type.getObjectType(thisName) to 0)
}
val continuationIndex =
getAllParameterTypes(desc, !isStatic(containingFunctionAccess), thisName).dropLast(1).map(Type::getSize).sum()
add(languageVersionSettings.continuationAsmType() to continuationIndex)
getAllParameterTypes(desc, !isStatic(containingFunctionAccess), thisName).dropLast(1).sumOf(Type::getSize)
add(CONTINUATION_ASM_TYPE to continuationIndex)
}
}
@@ -88,18 +88,17 @@ class SuspendFunctionGenerationStrategy(
return CoroutineTransformerMethodVisitor(
mv, access, name, desc, null, null, containingClassInternalName, this::classBuilderForCoroutineState,
isForNamedFunction = true,
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
disableTailCallOptimizationForFunctionReturningUnit = originalSuspendDescriptor.returnType?.isUnit() == true &&
originalSuspendDescriptor.overriddenDescriptors.isNotEmpty() &&
!originalSuspendDescriptor.allOverriddenFunctionsReturnUnit(),
reportSuspensionPointInsideMonitor = { reportSuspensionPointInsideMonitor(declaration, state, it) },
lineNumber = CodegenUtil.getLineNumberForElement(declaration, false) ?: 0,
sourceFile = declaration.containingKtFile.name,
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
needDispatchReceiver = originalSuspendDescriptor.dispatchReceiverParameter != null,
internalNameForDispatchReceiver = (originalSuspendDescriptor.containingDeclaration as? ClassDescriptor)?.let {
if (it.isInlineClass()) state.typeMapper.mapType(it).internalName else null
} ?: containingClassInternalNameOrNull(),
languageVersionSettings = languageVersionSettings,
disableTailCallOptimizationForFunctionReturningUnit = originalSuspendDescriptor.returnType?.isUnit() == true &&
originalSuspendDescriptor.overriddenDescriptors.isNotEmpty() &&
!originalSuspendDescriptor.allOverriddenFunctionsReturnUnit(),
useOldSpilledVarTypeAnalysis = state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS)
)
}
@@ -155,8 +154,7 @@ class SuspendFunctionGenerationStrategy(
needDispatchReceiver,
internalNameForDispatchReceiver,
containingClassInternalName,
classBuilderForCoroutineState,
languageVersionSettings
classBuilderForCoroutineState
)
addFakeContinuationConstructorCallMarker(this, false)
pop() // Otherwise stack-transformation breaks
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.codegen.optimization.common.asSequence
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.utils.sure
import org.jetbrains.org.objectweb.asm.Label
@@ -27,7 +26,6 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
internal class MethodNodeExaminer(
val languageVersionSettings: LanguageVersionSettings,
containingClassInternalName: String,
val methodNode: MethodNode,
suspensionPoints: List<SuspensionPoint>,
@@ -116,7 +114,7 @@ internal class MethodNodeExaminer(
val label = Label()
methodNode.instructions.insertBefore(pop, withInstructionAdapter {
dup()
loadCoroutineSuspendedMarker(languageVersionSettings)
loadCoroutineSuspendedMarker()
ifacmpne(label)
areturn(AsmTypes.OBJECT_TYPE)
mark(label)
@@ -9,6 +9,8 @@ import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.backend.common.COROUTINE_SUSPENDED_NAME
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineUninterceptedOrReturn
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.builtins.StandardNames.COROUTINES_INTRINSICS_PACKAGE_FQ_NAME
import org.jetbrains.kotlin.builtins.StandardNames.COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalClassDescriptor
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
@@ -54,67 +56,27 @@ import org.jetbrains.org.objectweb.asm.tree.MethodNode
const val COROUTINE_LABEL_FIELD_NAME = "label"
const val SUSPEND_FUNCTION_CREATE_METHOD_NAME = "create"
const val DO_RESUME_METHOD_NAME = "doResume"
const val INVOKE_SUSPEND_METHOD_NAME = "invokeSuspend"
const val EXCEPTION_FIELD_NAME = "exception"
const val CONTINUATION_RESULT_FIELD_NAME = "result"
val RELEASE_COROUTINES_VERSION_SETTINGS = LanguageVersionSettingsImpl(LanguageVersion.KOTLIN_1_3, ApiVersion.KOTLIN_1_3)
private const val GET_CONTEXT_METHOD_NAME = "getContext"
fun LanguageVersionSettings.isResumeImplMethodName(name: String) =
if (isReleaseCoroutines())
name == INVOKE_SUSPEND_METHOD_NAME
else
name == DO_RESUME_METHOD_NAME
val DEBUG_METADATA_ANNOTATION_ASM_TYPE: Type =
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(Name.identifier("DebugMetadata")).topLevelClassAsmType()
fun LanguageVersionSettings.dataFieldName(): String = if (isReleaseCoroutines()) "result" else "data"
fun coroutineContextAsmType(): Type =
StandardNames.COROUTINES_PACKAGE_FQ_NAME.child(Name.identifier("CoroutineContext")).topLevelClassAsmType()
fun isResumeImplMethodNameFromAnyLanguageSettings(name: String) = name == INVOKE_SUSPEND_METHOD_NAME || name == DO_RESUME_METHOD_NAME
fun LanguageVersionSettings.coroutinesJvmInternalPackageFqName() =
coroutinesPackageFqName().child(Name.identifier("jvm")).child(Name.identifier("internal"))
val DEBUG_METADATA_ANNOTATION_ASM_TYPE = RELEASE_COROUTINES_VERSION_SETTINGS.coroutinesJvmInternalPackageFqName()
.child(Name.identifier("DebugMetadata")).topLevelClassAsmType()
fun LanguageVersionSettings.continuationAsmType() =
continuationInterfaceFqName().topLevelClassAsmType()
fun continuationAsmTypes() = listOf(
LanguageVersionSettingsImpl(LanguageVersion.KOTLIN_1_3, ApiVersion.KOTLIN_1_3).continuationAsmType(),
LanguageVersionSettingsImpl(LanguageVersion.KOTLIN_1_2, ApiVersion.KOTLIN_1_2).continuationAsmType()
)
fun LanguageVersionSettings.coroutineContextAsmType() =
coroutinesPackageFqName().child(Name.identifier("CoroutineContext")).topLevelClassAsmType()
fun LanguageVersionSettings.isCoroutineSuperClass(internalName: String): Boolean {
val coroutinesJvmInternalPackage = coroutinesJvmInternalPackageFqName()
return if (isReleaseCoroutines())
coroutinesJvmInternalPackage.identifiedChild("ContinuationImpl") == internalName ||
coroutinesJvmInternalPackage.identifiedChild("RestrictedContinuationImpl") == internalName ||
coroutinesJvmInternalPackage.identifiedChild("SuspendLambda") == internalName ||
coroutinesJvmInternalPackage.identifiedChild("RestrictedSuspendLambda") == internalName
else
coroutinesJvmInternalPackage.identifiedChild("CoroutineImpl") == internalName
}
fun String.isCoroutineSuperClass(): Boolean =
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.identifiedChild("ContinuationImpl") == this ||
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.identifiedChild("RestrictedContinuationImpl") == this ||
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.identifiedChild("SuspendLambda") == this ||
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.identifiedChild("RestrictedSuspendLambda") == this
private fun FqName.identifiedChild(name: String) = child(Name.identifier(name)).topLevelClassInternalName()
private fun LanguageVersionSettings.coroutinesIntrinsicsFileFacadeInternalName() =
coroutinesIntrinsicsPackageFqName().child(Name.identifier("IntrinsicsKt")).topLevelClassAsmType()
private fun LanguageVersionSettings.internalCoroutineIntrinsicsOwnerInternalName() =
coroutinesJvmInternalPackageFqName().child(Name.identifier("CoroutineIntrinsics")).topLevelClassInternalName()
fun computeLabelOwner(languageVersionSettings: LanguageVersionSettings, thisName: String): Type =
if (languageVersionSettings.isReleaseCoroutines())
Type.getObjectType(thisName)
else
languageVersionSettings.coroutinesJvmInternalPackageFqName().child(Name.identifier("CoroutineImpl")).topLevelClassAsmType()
private const val NORMALIZE_CONTINUATION_METHOD_NAME = "normalizeContinuation"
private const val GET_CONTEXT_METHOD_NAME = "getContext"
private val coroutinesIntrinsicsFileFacadeInternalName: Type =
COROUTINES_INTRINSICS_PACKAGE_FQ_NAME.child(Name.identifier("IntrinsicsKt")).topLevelClassAsmType()
data class ResolvedCallWithRealDescriptor(val resolvedCall: ResolvedCall<*>, val fakeContinuationExpression: KtExpression)
@@ -122,7 +84,7 @@ data class ResolvedCallWithRealDescriptor(val resolvedCall: ResolvedCall<*>, val
val INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION = object : CallableDescriptor.UserDataKey<FunctionDescriptor> {}
@JvmField
val INITIAL_SUSPEND_DESCRIPTOR_FOR_DO_RESUME = object : CallableDescriptor.UserDataKey<FunctionDescriptor> {}
val INITIAL_SUSPEND_DESCRIPTOR_FOR_INVOKE_SUSPEND = object : CallableDescriptor.UserDataKey<FunctionDescriptor> {}
val CONTINUATION_PARAMETER_NAME = Name.identifier("continuation")
@@ -158,9 +120,9 @@ fun ResolvedCall<*>.replaceSuspensionFunctionWithRealDescriptor(
val newCandidateDescriptor =
when (function) {
is FunctionImportedFromObject ->
getOrCreateJvmSuspendFunctionView(function.callableFromObject, isReleaseCoroutines, bindingContext).asImportedFromObject()
getOrCreateJvmSuspendFunctionView(function.callableFromObject, bindingContext).asImportedFromObject()
is SimpleFunctionDescriptor ->
getOrCreateJvmSuspendFunctionView(function, isReleaseCoroutines, bindingContext)
getOrCreateJvmSuspendFunctionView(function, bindingContext)
else ->
throw AssertionError("Unexpected suspend function descriptor: $function")
}
@@ -223,10 +185,10 @@ private fun NewResolvedCallImpl<VariableDescriptor>.asDummyOldResolvedCall(bindi
enum class SuspensionPointKind { NEVER, NOT_INLINE, ALWAYS }
fun ResolvedCall<*>.isSuspensionPoint(codegen: ExpressionCodegen, languageVersionSettings: LanguageVersionSettings): SuspensionPointKind {
fun ResolvedCall<*>.isSuspensionPoint(codegen: ExpressionCodegen): SuspensionPointKind {
val functionDescriptor = resultingDescriptor as? FunctionDescriptor ?: return SuspensionPointKind.NEVER
if (!functionDescriptor.unwrapInitialDescriptorForSuspendFunction().isSuspend) return SuspensionPointKind.NEVER
if (functionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm(languageVersionSettings)) return SuspensionPointKind.ALWAYS
if (functionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm()) return SuspensionPointKind.ALWAYS
if (functionDescriptor.isInline) return SuspensionPointKind.NEVER
val isInlineLambda = this.safeAs<VariableAsFunctionResolvedCall>()
@@ -242,7 +204,6 @@ fun CallableDescriptor.isSuspendFunctionNotSuspensionView(): Boolean {
fun <D : FunctionDescriptor> getOrCreateJvmSuspendFunctionView(function: D, state: GenerationState): D = getOrCreateJvmSuspendFunctionView(
function,
state.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines),
state.bindingContext
)
@@ -252,7 +213,6 @@ fun <D : FunctionDescriptor> getOrCreateJvmSuspendFunctionView(function: D, stat
@JvmOverloads
fun <D : FunctionDescriptor> getOrCreateJvmSuspendFunctionView(
function: D,
isReleaseCoroutines: Boolean,
bindingContext: BindingContext? = null
): D {
assert(function.isSuspend) {
@@ -272,7 +232,7 @@ fun <D : FunctionDescriptor> getOrCreateJvmSuspendFunctionView(
outType = if (function.containingDeclaration.safeAs<ClassDescriptor>()?.isBuiltinFunctionalClassDescriptor == true)
function.builtIns.nullableAnyType
else
function.getContinuationParameterTypeOfSuspendFunction(isReleaseCoroutines),
function.getContinuationParameterTypeOfSuspendFunction(),
declaresDefaultValue = false, isCrossinline = false,
isNoinline = false, varargElementType = null,
source = SourceElement.NO_SOURCE
@@ -309,8 +269,7 @@ fun <D : FunctionDescriptor> D.createCustomCopy(
return result as D
}
private fun FunctionDescriptor.getContinuationParameterTypeOfSuspendFunction(isReleaseCoroutines: Boolean) =
module.getContinuationOfTypeOrAny(returnType!!, if (this.needsExperimentalCoroutinesWrapper()) false else isReleaseCoroutines)
private fun FunctionDescriptor.getContinuationParameterTypeOfSuspendFunction() = module.getContinuationOfTypeOrAny(returnType!!)
fun ModuleDescriptor.getResult(kotlinType: KotlinType) =
module.resolveTopLevelClass(
@@ -323,44 +282,11 @@ fun ModuleDescriptor.getResult(kotlinType: KotlinType) =
)
} ?: ErrorUtils.createErrorType("For Result")
private fun MethodNode.invokeNormalizeContinuation(languageVersionSettings: LanguageVersionSettings) {
visitMethodInsn(
Opcodes.INVOKESTATIC,
languageVersionSettings.internalCoroutineIntrinsicsOwnerInternalName(),
NORMALIZE_CONTINUATION_METHOD_NAME,
Type.getMethodDescriptor(languageVersionSettings.continuationAsmType(), languageVersionSettings.continuationAsmType()),
false
)
}
fun FunctionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm() =
getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION)?.isBuiltInSuspendCoroutineUninterceptedOrReturn() == true
fun FunctionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm(languageVersionSettings: LanguageVersionSettings) =
getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION)?.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) == true
fun createMethodNodeForIntercepted(languageVersionSettings: LanguageVersionSettings): MethodNode {
val node =
MethodNode(
Opcodes.API_VERSION,
Opcodes.ACC_STATIC,
"fake",
Type.getMethodDescriptor(languageVersionSettings.continuationAsmType(), languageVersionSettings.continuationAsmType()),
null, null
)
node.visitVarInsn(Opcodes.ALOAD, 0)
node.invokeNormalizeContinuation(languageVersionSettings)
node.visitInsn(Opcodes.ARETURN)
node.visitMaxs(1, 1)
return node
}
fun createMethodNodeForCoroutineContext(
functionDescriptor: FunctionDescriptor,
languageVersionSettings: LanguageVersionSettings
): MethodNode {
assert(functionDescriptor.isBuiltInCoroutineContext(languageVersionSettings)) {
fun createMethodNodeForCoroutineContext(functionDescriptor: FunctionDescriptor): MethodNode {
assert(functionDescriptor.isBuiltInCoroutineContext()) {
"functionDescriptor must be kotlin.coroutines.intrinsics.coroutineContext property getter"
}
@@ -369,7 +295,7 @@ fun createMethodNodeForCoroutineContext(
Opcodes.API_VERSION,
Opcodes.ACC_STATIC,
"fake",
Type.getMethodDescriptor(languageVersionSettings.coroutineContextAsmType()),
Type.getMethodDescriptor(coroutineContextAsmType()),
null, null
)
@@ -377,20 +303,20 @@ fun createMethodNodeForCoroutineContext(
addFakeContinuationMarker(v)
v.invokeGetContext(languageVersionSettings)
v.invokeGetContext()
node.visitMaxs(1, 1)
return node
}
fun createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSettings: LanguageVersionSettings): MethodNode {
fun createMethodNodeForSuspendCoroutineUninterceptedOrReturn(): MethodNode {
val node =
MethodNode(
Opcodes.API_VERSION,
Opcodes.ACC_STATIC,
"fake",
Type.getMethodDescriptor(OBJECT_TYPE, AsmTypes.FUNCTION1, languageVersionSettings.continuationAsmType()),
Type.getMethodDescriptor(OBJECT_TYPE, AsmTypes.FUNCTION1, CONTINUATION_ASM_TYPE),
null, null
)
@@ -405,25 +331,22 @@ fun createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSett
"($OBJECT_TYPE)$OBJECT_TYPE"
)
if (languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)) {
val elseLabel = Label()
// if (result === COROUTINE_SUSPENDED) {
dup()
loadCoroutineSuspendedMarker(languageVersionSettings)
ifacmpne(elseLabel)
// DebugProbesKt.probeCoroutineSuspended(continuation)
load(1, OBJECT_TYPE) // continuation
checkcast(languageVersionSettings.continuationAsmType())
invokestatic(
languageVersionSettings.coroutinesJvmInternalPackageFqName().child(Name.identifier("DebugProbesKt"))
.topLevelClassAsmType().internalName,
"probeCoroutineSuspended",
"(${languageVersionSettings.continuationAsmType()})V",
false
)
// }
mark(elseLabel)
}
val elseLabel = Label()
// if (result === COROUTINE_SUSPENDED) {
dup()
loadCoroutineSuspendedMarker()
ifacmpne(elseLabel)
// DebugProbesKt.probeCoroutineSuspended(continuation)
load(1, OBJECT_TYPE) // continuation
checkcast(CONTINUATION_ASM_TYPE)
invokestatic(
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(Name.identifier("DebugProbesKt")).topLevelClassAsmType().internalName,
"probeCoroutineSuspended",
"($CONTINUATION_ASM_TYPE)V",
false
)
// }
mark(elseLabel)
}
node.visitInsn(Opcodes.ARETURN)
@@ -433,13 +356,13 @@ fun createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSett
}
private fun InstructionAdapter.invokeGetContext(languageVersionSettings: LanguageVersionSettings) {
private fun InstructionAdapter.invokeGetContext() {
invokeinterface(
languageVersionSettings.continuationAsmType().internalName,
CONTINUATION_ASM_TYPE.internalName,
GET_CONTEXT_METHOD_NAME,
Type.getMethodDescriptor(languageVersionSettings.coroutineContextAsmType())
Type.getMethodDescriptor(coroutineContextAsmType())
)
areturn(languageVersionSettings.coroutineContextAsmType())
areturn(coroutineContextAsmType())
}
@Suppress("UNCHECKED_CAST")
@@ -447,15 +370,12 @@ fun <D : CallableDescriptor?> D.unwrapInitialDescriptorForSuspendFunction(): D =
this.safeAs<SimpleFunctionDescriptor>()?.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) as D ?: this
fun FunctionDescriptor.getOriginalSuspendFunctionView(bindingContext: BindingContext, isReleaseCoroutines: Boolean): FunctionDescriptor =
fun FunctionDescriptor.getOriginalSuspendFunctionView(bindingContext: BindingContext): FunctionDescriptor =
if (isSuspend)
getOrCreateJvmSuspendFunctionView(unwrapInitialDescriptorForSuspendFunction().original, isReleaseCoroutines, bindingContext)
getOrCreateJvmSuspendFunctionView(unwrapInitialDescriptorForSuspendFunction().original, bindingContext)
else
this
fun FunctionDescriptor.getOriginalSuspendFunctionView(bindingContext: BindingContext, state: GenerationState) =
getOriginalSuspendFunctionView(bindingContext, state.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines))
// For each suspend function, we have a corresponding JVM view function that has an extra continuation parameter,
// and, more importantly, returns 'kotlin.Any' (so that it can return as a reference value or a special COROUTINE_SUSPENDED object).
// This also causes boxing of primitives and inline class values.
@@ -482,38 +402,24 @@ fun FunctionDescriptor.originalReturnTypeOfSuspendFunctionReturningUnboxedInline
return originalReturnType
}
fun InstructionAdapter.loadCoroutineSuspendedMarker(languageVersionSettings: LanguageVersionSettings) {
fun InstructionAdapter.loadCoroutineSuspendedMarker() {
invokestatic(
languageVersionSettings.coroutinesIntrinsicsFileFacadeInternalName().internalName,
coroutinesIntrinsicsFileFacadeInternalName.internalName,
"get$COROUTINE_SUSPENDED_NAME",
Type.getMethodDescriptor(OBJECT_TYPE),
false
)
}
fun InstructionAdapter.generateCoroutineSuspendedCheck(languageVersionSettings: LanguageVersionSettings) {
fun InstructionAdapter.generateCoroutineSuspendedCheck() {
dup()
loadCoroutineSuspendedMarker(languageVersionSettings)
loadCoroutineSuspendedMarker()
val elseLabel = Label()
ifacmpne(elseLabel)
areturn(OBJECT_TYPE)
mark(elseLabel)
}
fun InstructionAdapter.invokeDoResumeWithUnit(thisName: String) {
// .doResume(Unit, null)
StackValue.putUnitInstance(this)
aconst(null)
invokevirtual(
thisName,
DO_RESUME_METHOD_NAME,
Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE, AsmTypes.JAVA_THROWABLE_TYPE),
false
)
}
fun InstructionAdapter.invokeInvokeSuspendWithUnit(thisName: String) {
StackValue.putUnitInstance(this)
@@ -537,18 +443,14 @@ fun FunctionDescriptor.isSuspendLambdaOrLocalFunction() = this.isSuspend && when
}
fun FunctionDescriptor.isLocalSuspendFunctionNotSuspendLambda() = isSuspendLambdaOrLocalFunction() && this !is AnonymousFunctionDescriptor
@JvmField
val EXPERIMENTAL_CONTINUATION_ASM_TYPE = StandardNames.CONTINUATION_INTERFACE_FQ_NAME_EXPERIMENTAL.topLevelClassAsmType()
@JvmField
val RELEASE_CONTINUATION_ASM_TYPE = StandardNames.CONTINUATION_INTERFACE_FQ_NAME_RELEASE.topLevelClassAsmType()
val CONTINUATION_ASM_TYPE = StandardNames.CONTINUATION_INTERFACE_FQ_NAME.topLevelClassAsmType()
fun FunctionDescriptor.isInvokeSuspendOfLambda(): Boolean {
if (this !is SimpleFunctionDescriptor) return false
if (valueParameters.size != 1 ||
valueParameters[0].name.asString() != SUSPEND_CALL_RESULT_NAME ||
name.asString() != "invokeSuspend"
name.asString() != INVOKE_SUSPEND_METHOD_NAME
) return false
return containingDeclaration is SyntheticClassDescriptorForLambda
}
@@ -62,7 +62,7 @@ class AnonymousObjectTransformer(
createClassReader().accept(object : ClassVisitor(Opcodes.API_VERSION, classBuilder.visitor) {
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<String>) {
classBuilder.defineClass(null, maxOf(version, state.classFileVersion), access, name, signature, superName, interfaces)
if (languageVersionSettings.isCoroutineSuperClass(superName)) {
if (superName.isCoroutineSuperClass()) {
inliningContext.isContinuation = true
}
superClassName = superName
@@ -104,7 +104,7 @@ class DefaultLambda(info: ExtractedDefaultLambda, sourceCompiler: SourceCompiler
// TODO: suspend lambdas are their own continuations, so the body is pre-inlined into `invokeSuspend`
// and thus can't be detangled from the state machine. To make them inlinable, this needs to be redesigned.
// See `SuspendLambdaLowering`.
require(!sourceCompiler.state.languageVersionSettings.isCoroutineSuperClass(superName)) {
require(!superName.isCoroutineSuperClass()) {
"suspend default lambda ${lambdaClassType.internalName} cannot be inlined; use a function reference instead"
}
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.coroutines.continuationAsmType
import org.jetbrains.kotlin.codegen.coroutines.CONTINUATION_ASM_TYPE
import org.jetbrains.kotlin.codegen.inline.FieldRemapper.Companion.foldName
import org.jetbrains.kotlin.codegen.inline.coroutines.CoroutineTransformer
import org.jetbrains.kotlin.codegen.inline.coroutines.markNoinlineLambdaIfSuspend
@@ -688,7 +688,7 @@ class MethodInliner(
}
for ((index, param) in paramTypes.reversed().withIndex()) {
if (param != languageVersionSettings.continuationAsmType() && param != OBJECT_TYPE) continue
if (param != CONTINUATION_ASM_TYPE && param != OBJECT_TYPE) continue
val sourceIndices = (frame.getStack(frame.stackSize - index - 1) as? Aload0BasicValue)?.indices ?: continue
for (sourceIndex in sourceIndices) {
val src = processingNode.instructions[sourceIndex]
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
import org.jetbrains.kotlin.psi.*
@@ -158,8 +157,7 @@ class PsiSourceCompilerForInline(
}
FunctionCodegen.generateMethodBody(
adapter, descriptor, context, jvmMethodSignature, strategy, parentCodegen, state.jvmDefaultMode,
state.languageVersionSettings.isReleaseCoroutines()
adapter, descriptor, context, jvmMethodSignature, strategy, parentCodegen, state.jvmDefaultMode
)
if (isLambda) {
@@ -235,7 +233,7 @@ class PsiSourceCompilerForInline(
}
override fun compileInlineFunction(jvmSignature: JvmMethodSignature): SMAPAndMethodNode {
generateInlineIntrinsic(state.languageVersionSettings, functionDescriptor, jvmSignature.asmMethod, codegen.typeSystem)?.let {
generateInlineIntrinsic(functionDescriptor, jvmSignature.asmMethod, codegen.typeSystem)?.let {
return it
}
@@ -22,8 +22,6 @@ import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
import org.jetbrains.kotlin.codegen.optimization.common.intConstant
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.types.KotlinType
@@ -233,7 +231,7 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
if (stubCheckcast !is TypeInsnNode) return false
val newMethodNode = MethodNode(Opcodes.API_VERSION)
generateAsCast(InstructionAdapter(newMethodNode), kotlinType, asmType, safe, languageVersionSettings, unifiedNullChecks)
generateAsCast(InstructionAdapter(newMethodNode), kotlinType, asmType, safe, unifiedNullChecks)
instructions.insert(insn, newMethodNode.instructions)
// Keep stubCheckcast to avoid VerifyErrors on 1.8+ bytecode,
@@ -257,7 +255,7 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
if (stubInstanceOf !is TypeInsnNode) return false
val newMethodNode = MethodNode(Opcodes.API_VERSION)
generateIsCheck(InstructionAdapter(newMethodNode), kotlinType, asmType, languageVersionSettings.isReleaseCoroutines())
generateIsCheck(InstructionAdapter(newMethodNode), kotlinType, asmType)
instructions.insert(insn, newMethodNode.instructions)
instructions.remove(stubInstanceOf)
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.codegen.inline.*
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.org.objectweb.asm.MethodVisitor
@@ -49,18 +48,16 @@ class CoroutineTransformer(
fun suspendLambdaWithGeneratedStateMachine(node: MethodNode): Boolean =
!isContinuationNotLambda() && isSuspendLambda(node) && isStateMachine(node)
private fun isContinuationNotLambda(): Boolean = inliningContext.isContinuation &&
if (state.languageVersionSettings.isReleaseCoroutines()) superClassName.endsWith("ContinuationImpl")
else methods.any { it.name == "getLabel" }
private fun isContinuationNotLambda(): Boolean = inliningContext.isContinuation && superClassName.endsWith("ContinuationImpl")
private fun isStateMachine(node: MethodNode): Boolean =
node.instructions.asSequence().any { insn -> insn is LdcInsnNode && insn.cst == ILLEGAL_STATE_ERROR_MESSAGE }
private fun isSuspendLambda(node: MethodNode) = isResumeImpl(node)
private fun isSuspendLambda(node: MethodNode) = isInvokeSuspend(node)
fun newMethod(node: MethodNode): DeferredMethodVisitor {
return when {
isResumeImpl(node) -> {
isInvokeSuspend(node) -> {
assert(!isStateMachine(node)) {
"Inlining/transforming state-machine"
}
@@ -71,9 +68,8 @@ class CoroutineTransformer(
}
}
private fun isResumeImpl(node: MethodNode): Boolean =
state.languageVersionSettings.isResumeImplMethodName(node.name.removeSuffix(FOR_INLINE_SUFFIX)) &&
inliningContext.isContinuation
private fun isInvokeSuspend(node: MethodNode): Boolean =
node.name.removeSuffix(FOR_INLINE_SUFFIX) == INVOKE_SUSPEND_METHOD_NAME && inliningContext.isContinuation
private fun isSuspendFunctionWithFakeConstructorCall(node: MethodNode): Boolean = findFakeContinuationConstructorClassName(node) != null
@@ -88,16 +84,15 @@ class CoroutineTransformer(
val sourceCompilerForInline = inliningContext.root.sourceCompilerForInline
val stateMachineBuilder = CoroutineTransformerMethodVisitor(
createNewMethodFrom(node, name), node.access, name, node.desc, null, null,
containingClassInternalName = classBuilder.thisName,
obtainClassBuilderForCoroutineState = { classBuilder },
isForNamedFunction = false,
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
disableTailCallOptimizationForFunctionReturningUnit = false,
reportSuspensionPointInsideMonitor = { sourceCompilerForInline.reportSuspensionPointInsideMonitor(it) },
// TODO: this linenumbers might not be correct and since they are used only for step-over, check them.
lineNumber = inliningContext.callSiteInfo.lineNumber,
sourceFile = inliningContext.callSiteInfo.file?.name ?: "",
languageVersionSettings = state.languageVersionSettings,
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
containingClassInternalName = classBuilder.thisName,
isForNamedFunction = false,
disableTailCallOptimizationForFunctionReturningUnit = false,
useOldSpilledVarTypeAnalysis = state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS)
)
@@ -123,17 +118,16 @@ class CoroutineTransformer(
val sourceCompilerForInline = inliningContext.root.sourceCompilerForInline
val stateMachineBuilder = CoroutineTransformerMethodVisitor(
createNewMethodFrom(node, name), node.access, name, node.desc, null, null,
containingClassInternalName = classBuilder.thisName,
obtainClassBuilderForCoroutineState = { (inliningContext as RegeneratedClassContext).continuationBuilders[continuationClassName]!! },
isForNamedFunction = true,
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
disableTailCallOptimizationForFunctionReturningUnit = disableTailCallOptimization,
reportSuspensionPointInsideMonitor = { sourceCompilerForInline.reportSuspensionPointInsideMonitor(it) },
lineNumber = inliningContext.callSiteInfo.lineNumber,
sourceFile = inliningContext.callSiteInfo.file?.name ?: "",
languageVersionSettings = state.languageVersionSettings,
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
containingClassInternalName = classBuilder.thisName,
isForNamedFunction = true,
needDispatchReceiver = true,
internalNameForDispatchReceiver = classBuilder.thisName,
disableTailCallOptimizationForFunctionReturningUnit = disableTailCallOptimization,
putContinuationParameterToLvt = !state.isIrBackend,
useOldSpilledVarTypeAnalysis = state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS)
)
@@ -5,13 +5,11 @@
package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.backend.common.isBuiltInIntercepted
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineUninterceptedOrReturn
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForCoroutineContext
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForIntercepted
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForSuspendCoroutineUninterceptedOrReturn
import org.jetbrains.kotlin.codegen.createMethodNodeForAlwaysEnabledAssert
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructors
@@ -30,25 +28,22 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.commons.Method
import org.jetbrains.org.objectweb.asm.tree.MethodNode
fun generateInlineIntrinsicForIr(languageVersionSettings: LanguageVersionSettings, descriptor: FunctionDescriptor): SMAPAndMethodNode? =
fun generateInlineIntrinsicForIr(descriptor: FunctionDescriptor): SMAPAndMethodNode? =
when {
// TODO: implement these as codegen intrinsics (see IrIntrinsicMethods)
descriptor.isBuiltInIntercepted(languageVersionSettings) ->
createMethodNodeForIntercepted(languageVersionSettings)
descriptor.isBuiltInCoroutineContext(languageVersionSettings) ->
createMethodNodeForCoroutineContext(descriptor, languageVersionSettings)
descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) ->
createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSettings)
descriptor.isBuiltInCoroutineContext() ->
createMethodNodeForCoroutineContext(descriptor)
descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn() ->
createMethodNodeForSuspendCoroutineUninterceptedOrReturn()
else -> null
}?.let { SMAPAndMethodNode(it, SMAP(listOf())) }
internal fun generateInlineIntrinsic(
languageVersionSettings: LanguageVersionSettings,
descriptor: FunctionDescriptor,
asmMethod: Method,
typeSystem: TypeSystemCommonBackendContext
): SMAPAndMethodNode? {
return generateInlineIntrinsicForIr(languageVersionSettings, descriptor) ?: when {
return generateInlineIntrinsicForIr(descriptor) ?: when {
isSpecialEnumMethod(descriptor) ->
createSpecialEnumMethodBody(descriptor.name.asString(), descriptor.original.typeParameters.single(), typeSystem)
TypeOfChecker.isTypeOf(descriptor) ->
@@ -19,7 +19,7 @@ import org.jetbrains.org.objectweb.asm.tree.*
object TypeIntrinsics {
@JvmStatic
fun instanceOf(v: InstructionAdapter, jetType: KotlinType, boxedAsmType: Type, isReleaseCoroutines: Boolean) {
fun instanceOf(v: InstructionAdapter, jetType: KotlinType, boxedAsmType: Type) {
val functionTypeArity = getFunctionTypeArity(jetType)
if (functionTypeArity >= 0) {
v.iconst(functionTypeArity)
@@ -27,28 +27,26 @@ object TypeIntrinsics {
return
}
if (isReleaseCoroutines) {
val suspendFunctionTypeArity = getSuspendFunctionTypeArity(jetType)
if (suspendFunctionTypeArity >= 0) {
val notSuspendLambda = Label()
val end = Label()
val suspendFunctionTypeArity = getSuspendFunctionTypeArity(jetType)
if (suspendFunctionTypeArity >= 0) {
val notSuspendLambda = Label()
val end = Label()
with(v) {
dup()
instanceOf(AsmTypes.SUSPEND_FUNCTION_TYPE)
ifeq(notSuspendLambda)
iconst(suspendFunctionTypeArity + 1)
typeIntrinsic(IS_FUNCTON_OF_ARITY_METHOD_NAME, IS_FUNCTON_OF_ARITY_DESCRIPTOR)
goTo(end)
with(v) {
dup()
instanceOf(AsmTypes.SUSPEND_FUNCTION_TYPE)
ifeq(notSuspendLambda)
iconst(suspendFunctionTypeArity + 1)
typeIntrinsic(IS_FUNCTON_OF_ARITY_METHOD_NAME, IS_FUNCTON_OF_ARITY_DESCRIPTOR)
goTo(end)
mark(notSuspendLambda)
pop()
iconst(0)
mark(notSuspendLambda)
pop()
iconst(0)
mark(end)
}
return
mark(end)
}
return
}
val isMutableCollectionMethodName = getIsMutableCollectionMethodName(jetType)
@@ -17,9 +17,8 @@
package org.jetbrains.kotlin.codegen.optimization.boxing
import com.google.common.collect.ImmutableSet
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.coroutines.RELEASE_COROUTINES_VERSION_SETTINGS
import org.jetbrains.kotlin.codegen.coroutines.coroutinesJvmInternalPackageFqName
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
@@ -216,7 +215,7 @@ fun AbstractInsnNode.isPrimitiveBoxing() =
}
private val BOXING_CLASS_INTERNAL_NAME =
RELEASE_COROUTINES_VERSION_SETTINGS.coroutinesJvmInternalPackageFqName().child(Name.identifier("Boxing")).topLevelClassInternalName()
StandardNames.COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(Name.identifier("Boxing")).topLevelClassInternalName()
private fun isJvmPrimitiveName(name: String) = JvmPrimitiveType.values().any { it.javaKeywordName == name }
@@ -37,7 +37,6 @@ import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtScript
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.deprecation.CoroutineCompatibilitySupport
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.resolve.diagnostics.PrecomputedSuppressCache
@@ -158,8 +157,7 @@ class GenerationState private constructor(
CompilerDeserializationConfiguration(languageVersionSettings)
val deprecationProvider = DeprecationResolver(
LockBasedStorageManager.NO_LOCKS, languageVersionSettings, CoroutineCompatibilitySupport.ENABLED,
JavaDeprecationSettings
LockBasedStorageManager.NO_LOCKS, languageVersionSettings, JavaDeprecationSettings
)
init {
@@ -193,7 +193,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
}
if (descriptor.isSuspendFunctionNotSuspensionView()) {
return mapReturnType(getOrCreateJvmSuspendFunctionView(descriptor as SimpleFunctionDescriptor, isReleaseCoroutines), sw)
return mapReturnType(getOrCreateJvmSuspendFunctionView(descriptor as SimpleFunctionDescriptor), sw)
}
if (hasVoidReturnType(descriptor)) {
@@ -804,7 +804,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
}
if (f.isSuspendFunctionNotSuspensionView()) {
return mapSignature(getOrCreateJvmSuspendFunctionView(f, isReleaseCoroutines), kind, skipGenericSignature)
return mapSignature(getOrCreateJvmSuspendFunctionView(f), kind, skipGenericSignature)
}
if (isDeclarationOfBigArityFunctionInvoke(f) || isDeclarationOfBigArityCreateCoroutineMethod(f)) {