diff --git a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/commonCoroutineCodegenUtil.kt b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/commonCoroutineCodegenUtil.kt index 57bd84ee578..87a51976e7d 100644 --- a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/commonCoroutineCodegenUtil.kt +++ b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/commonCoroutineCodegenUtil.kt @@ -5,14 +5,15 @@ package org.jetbrains.kotlin.backend.common +import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.coroutinesIntrinsicsPackageFqName +import org.jetbrains.kotlin.config.isReleaseCoroutines import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorEquivalenceForOverrides import org.jetbrains.kotlin.resolve.descriptorUtil.module -import org.jetbrains.kotlin.config.LanguageVersionSettings val SUSPEND_COROUTINE_OR_RETURN_NAME = Name.identifier("suspendCoroutineOrReturn") val INTERCEPTED_NAME = Name.identifier("intercepted") @@ -21,7 +22,7 @@ val COROUTINE_SUSPENDED_NAME = Name.identifier("COROUTINE_SUSPENDED") val SUSPEND_COROUTINE_UNINTERCEPTED_OR_RETURN_NAME = Name.identifier("suspendCoroutineUninterceptedOrReturn") fun FunctionDescriptor.isBuiltInIntercepted(languageVersionSettings: LanguageVersionSettings): Boolean { - if (name != INTERCEPTED_NAME) return false + if (name != INTERCEPTED_NAME || languageVersionSettings.isReleaseCoroutines()) return false val original = module.getPackage(languageVersionSettings.coroutinesIntrinsicsPackageFqName()).memberScope .getContributedFunctions(INTERCEPTED_NAME, NoLookupLocation.FROM_BACKEND) @@ -30,7 +31,7 @@ fun FunctionDescriptor.isBuiltInIntercepted(languageVersionSettings: LanguageVer } fun FunctionDescriptor.isBuiltInSuspendCoroutineOrReturn(languageVersionSettings: LanguageVersionSettings): Boolean { - if (name != SUSPEND_COROUTINE_OR_RETURN_NAME) return false + if (name != SUSPEND_COROUTINE_OR_RETURN_NAME || languageVersionSettings.isReleaseCoroutines()) return false val originalDeclaration = getBuiltInSuspendCoroutineOrReturn(languageVersionSettings) ?: return false diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java index 57a7531292e..edc63d0126f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java @@ -422,7 +422,7 @@ public class ClosureCodegen extends MemberCodegen { String superClassConstructorDescriptor; if (superClassAsmType.equals(LAMBDA) || superClassAsmType.equals(FUNCTION_REFERENCE) || - superClassAsmType.equals(CoroutineCodegenUtilKt.coroutineImplAsmType(state.getLanguageVersionSettings()))) { + CoroutineCodegenUtilKt.isCoroutineSuperClass(state.getLanguageVersionSettings(), superClassAsmType.getInternalName())) { int arity = calculateArity(); iv.iconst(arity); if (shouldHaveBoundReferenceReceiver) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 39fce5ed5b9..710193f1471 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -38,7 +38,6 @@ import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.SpecialBuiltinMembers; import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor; import org.jetbrains.kotlin.name.FqName; -import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; @@ -688,7 +687,10 @@ public class FunctionCodegen { } } else { FunctionDescriptor lambdaDescriptor = ((ClosureContext) context.getParentContext()).getOriginalSuspendLambdaDescriptor(); - if (lambdaDescriptor != null && functionDescriptor.getName().equals(Name.identifier("doResume"))) { + if (lambdaDescriptor != null && + CoroutineCodegenUtilKt.isResumeImplMethodName( + parentCodegen.state.getLanguageVersionSettings(), functionDescriptor.getName().asString() + )) { destructuredParametersForSuspendLambda.addAll(lambdaDescriptor.getValueParameters()); } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.kt index d86b15bcb0c..9d51af05667 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.kt @@ -8,9 +8,10 @@ package org.jetbrains.kotlin.codegen import org.jetbrains.kotlin.builtins.createFunctionType import org.jetbrains.kotlin.codegen.coroutines.coroutinesJvmInternalPackageFqName import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView -import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.codegen.coroutines.isSuspendLambdaOrLocalFunction import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.coroutines.isSuspendLambda +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 @@ -19,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.impl.MutableClassDescriptor import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.calls.checkers.isRestrictsSuspensionReceiver import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.types.KotlinType @@ -34,7 +36,33 @@ class JvmRuntimeTypes(module: ModuleDescriptor, private val languageVersionSetti val functionReference: ClassDescriptor by klass("FunctionReference") private val localVariableReference: ClassDescriptor by klass("LocalVariableReference") private val mutableLocalVariableReference: ClassDescriptor by klass("MutableLocalVariableReference") - private val coroutineImplClass by lazy { createClass(kotlinCoroutinesJvmInternalPackage, "CoroutineImpl") } + + private val coroutineImpl: ClassDescriptor by lazy { + createClass(kotlinCoroutinesJvmInternalPackage, "CoroutineImpl") + } + + private val continuationImpl by lazy { + createCoroutineSuperClass("ContinuationImpl") + } + + private val restrictedContinuationImpl by lazy { + createCoroutineSuperClass("RestrictedContinuationImpl") + } + + private val suspendLambda by lazy { + createCoroutineSuperClass("SuspendLambda") + } + + private val restrictedSuspendLambda by lazy { + createCoroutineSuperClass("RestrictedSuspendLambda") + } + + private fun createCoroutineSuperClass(className: String): ClassDescriptor { + return if (languageVersionSettings.isReleaseCoroutines()) + createClass(kotlinCoroutinesJvmInternalPackage, className) + else + coroutineImpl + } private val propertyReferences: List by lazy { (0..2).map { i -> createClass(kotlinJvmInternalPackage, "PropertyReference$i") } @@ -76,8 +104,21 @@ class JvmRuntimeTypes(module: ModuleDescriptor, private val languageVersionSetti if (descriptor.isSuspend) { return mutableListOf().apply { - add(coroutineImplClass.defaultType) - if (descriptor.isSuspendLambda) { + if (actualFunctionDescriptor.extensionReceiverParameter?.type?.isRestrictsSuspensionReceiver(languageVersionSettings) == true) { + if (descriptor.isSuspendLambdaOrLocalFunction()) { + add(restrictedSuspendLambda.defaultType) + } else { + add(restrictedContinuationImpl.defaultType) + } + } else { + if (descriptor.isSuspendLambdaOrLocalFunction()) { + add(suspendLambda.defaultType) + } else { + add(continuationImpl.defaultType) + } + } + + if (descriptor.isSuspendLambdaOrLocalFunction()) { add(functionType) } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt index c5f354203b7..e358843fc98 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.codegen.context.ClosureContext import org.jetbrains.kotlin.codegen.context.MethodContext import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension 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.SimpleFunctionDescriptorImpl @@ -48,7 +49,7 @@ abstract class AbstractCoroutineCodegen( element: KtElement, closureContext: ClosureContext, classBuilder: ClassBuilder, - userDataForDoResume: Map, *>? = null + private val userDataForDoResume: Map, *>? = null ) : ClosureCodegen( outerExpressionCodegen.state, element, null, closureContext, null, @@ -58,19 +59,31 @@ abstract class AbstractCoroutineCodegen( protected val classDescriptor = closureContext.contextDescriptor protected val languageVersionSettings = outerExpressionCodegen.state.languageVersionSettings - protected val doResumeDescriptor = + protected val methodToImplement = + if (languageVersionSettings.isReleaseCoroutines()) + createImplMethod( + INVOKE_SUSPEND_METHOD_NAME, + "result" to classDescriptor.module.getSuccessOrFailure(classDescriptor.builtIns.anyType) + ) + else + createImplMethod( + DO_RESUME_METHOD_NAME, + "data" to classDescriptor.builtIns.nullableAnyType, + "throwable" to classDescriptor.builtIns.throwable.defaultType.makeNullable() + ) + + private fun createImplMethod(name: String, vararg parameters: Pair) = SimpleFunctionDescriptorImpl.create( - classDescriptor, Annotations.EMPTY, Name.identifier(DO_RESUME_METHOD_NAME), CallableMemberDescriptor.Kind.DECLARATION, + classDescriptor, Annotations.EMPTY, Name.identifier(name), CallableMemberDescriptor.Kind.DECLARATION, funDescriptor.source - ).apply doResume@{ + ).apply { initialize( null, classDescriptor.thisAsReceiverParameter, emptyList(), - listOf( - createValueParameterForDoResume(Name.identifier("data"), builtIns.nullableAnyType, 0), - createValueParameterForDoResume(Name.identifier("throwable"), builtIns.throwable.defaultType.makeNullable(), 1) - ), + parameters.withIndex().map { (index, nameAndType) -> + createValueParameterForDoResume(Name.identifier(nameAndType.first), nameAndType.second, index) + }, builtIns.nullableAnyType, Modality.FINAL, Visibilities.PUBLIC, @@ -104,13 +117,22 @@ abstract class AbstractCoroutineCodegen( iv.generateClosureFieldsInitializationFromParameters(closure, args) iv.load(0, AsmTypes.OBJECT_TYPE) - iv.iconst(if (passArityToSuperClass) calculateArity() else 0) + val hasArityParameter = !languageVersionSettings.isReleaseCoroutines() || passArityToSuperClass + if (hasArityParameter) { + iv.iconst(if (passArityToSuperClass) calculateArity() else 0) + } + iv.load(argTypes.map { it.size }.sum(), AsmTypes.OBJECT_TYPE) + val parameters = + if (hasArityParameter) + listOf(Type.INT_TYPE, languageVersionSettings.continuationAsmType()) + else + listOf(languageVersionSettings.continuationAsmType()) + val superClassConstructorDescriptor = Type.getMethodDescriptor( Type.VOID_TYPE, - Type.INT_TYPE, - languageVersionSettings.continuationAsmType() + *parameters.toTypedArray() ) iv.invokespecial(superClassAsmType.internalName, "", superClassConstructorDescriptor, false) @@ -119,6 +141,10 @@ 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) + } + return constructor } @@ -174,7 +200,7 @@ class CoroutineCodegenForLambda private constructor( ) } - generateDoResume() + generateResumeImpl() } override fun generateBody() { @@ -227,7 +253,11 @@ class CoroutineCodegenForLambda private constructor( checkcast(Type.getObjectType(v.thisName)) // .doResume(Unit) - invokeDoResumeWithUnit(v.thisName) + if (languageVersionSettings.isReleaseCoroutines()) { + invokeInvokeSuspendWithUnit(v.thisName) + } else { + invokeDoResumeWithUnit(v.thisName) + } areturn(AsmTypes.OBJECT_TYPE) } @@ -307,10 +337,10 @@ class CoroutineCodegenForLambda private constructor( name ) - private fun generateDoResume() { + private fun generateResumeImpl() { functionCodegen.generateMethod( OtherOrigin(element), - doResumeDescriptor, + methodToImplement, object : FunctionGenerationStrategy.FunctionDefault(state, element as KtDeclarationWithBody) { override fun wrapMethodVisitor(mv: MethodVisitor, access: Int, name: String, desc: String): MethodVisitor { @@ -370,14 +400,18 @@ class CoroutineCodegenForNamedFunction private constructor( classBuilder: ClassBuilder, originalSuspendFunctionDescriptor: FunctionDescriptor ) : AbstractCoroutineCodegen(outerExpressionCodegen, element, closureContext, classBuilder) { - private val labelFieldStackValue = StackValue.field( - FieldInfo.createForHiddenField( - outerExpressionCodegen.state.languageVersionSettings.coroutineImplAsmType(), - Type.INT_TYPE, - COROUTINE_LABEL_FIELD_NAME - ), - StackValue.LOCAL_0 - ) + private val labelFieldStackValue by lazy { + StackValue.field( + FieldInfo.createForHiddenField( + computeLabelOwner(languageVersionSettings, v.thisName), + Type.INT_TYPE, + COROUTINE_LABEL_FIELD_NAME + ), + StackValue.LOCAL_0 + ) + } + + private val suspendFunctionJvmView = bindingContext[CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, originalSuspendFunctionDescriptor]!! @@ -388,7 +422,7 @@ class CoroutineCodegenForNamedFunction private constructor( } override fun generateClosureBody() { - generateDoResume() + generateResumeImpl() generateGetLabelMethod() generateSetLabelMethod() @@ -397,16 +431,19 @@ class CoroutineCodegenForNamedFunction private constructor( JvmDeclarationOrigin.NO_ORIGIN, Opcodes.ACC_SYNTHETIC or AsmUtil.NO_FLAG_PACKAGE_PRIVATE, DATA_FIELD_NAME, AsmTypes.OBJECT_TYPE.descriptor, null, null ) - v.newField( - JvmDeclarationOrigin.NO_ORIGIN, Opcodes.ACC_SYNTHETIC or AsmUtil.NO_FLAG_PACKAGE_PRIVATE, - EXCEPTION_FIELD_NAME, AsmTypes.JAVA_THROWABLE_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 generateDoResume() { + private fun generateResumeImpl() { functionCodegen.generateMethod( OtherOrigin(element), - doResumeDescriptor, + methodToImplement, object : FunctionGenerationStrategy.CodegenBased(state) { override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) { StackValue.field( @@ -414,10 +451,12 @@ class CoroutineCodegenForNamedFunction private constructor( StackValue.LOCAL_0 ).store(StackValue.local(1, AsmTypes.OBJECT_TYPE), codegen.v) - 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) + 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) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt index 2dd375eb3f7..a9fc0fec973 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransfor 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.config.isReleaseCoroutines import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.utils.sure @@ -53,7 +54,7 @@ class CoroutineTransformerMethodVisitor( private var continuationIndex = if (isForNamedFunction) -1 else 0 private var dataIndex = if (isForNamedFunction) -1 else 1 - private var exceptionIndex = if (isForNamedFunction) -1 else 2 + private var exceptionIndex = if (isForNamedFunction || languageVersionSettings.isReleaseCoroutines()) -1 else 2 override fun performTransformations(methodNode: MethodNode) { removeFakeContinuationConstructorCall(methodNode) @@ -81,7 +82,9 @@ class CoroutineTransformerMethodVisitor( } dataIndex = methodNode.maxLocals++ - exceptionIndex = methodNode.maxLocals++ + if (!languageVersionSettings.isReleaseCoroutines()) { + exceptionIndex = methodNode.maxLocals++ + } continuationIndex = methodNode.maxLocals++ prepareMethodNodePreludeForNamedFunction(methodNode) @@ -136,7 +139,9 @@ class CoroutineTransformerMethodVisitor( ) ) - insert(startLabel, withInstructionAdapter { generateResumeWithExceptionCheck(exceptionIndex) }) + insert(startLabel, withInstructionAdapter { + generateResumeWithExceptionCheck(languageVersionSettings.isReleaseCoroutines(), dataIndex, exceptionIndex) + }) insert(last, defaultLabel) insert(last, withInstructionAdapter { @@ -161,7 +166,7 @@ class CoroutineTransformerMethodVisitor( } private fun createInsnForReadingLabel() = - if (isForNamedFunction) + if (isForNamedFunction && !languageVersionSettings.isReleaseCoroutines()) MethodInsnNode( Opcodes.INVOKEVIRTUAL, classBuilderForCoroutineState.thisName, @@ -172,12 +177,12 @@ class CoroutineTransformerMethodVisitor( else FieldInsnNode( Opcodes.GETFIELD, - languageVersionSettings.coroutineImplAsmType().internalName, + computeLabelOwner(languageVersionSettings, classBuilderForCoroutineState.thisName).internalName, COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor ) private fun createInsnForSettingLabel() = - if (isForNamedFunction) + if (isForNamedFunction && !languageVersionSettings.isReleaseCoroutines()) MethodInsnNode( Opcodes.INVOKEVIRTUAL, classBuilderForCoroutineState.thisName, @@ -188,7 +193,7 @@ class CoroutineTransformerMethodVisitor( else FieldInsnNode( Opcodes.PUTFIELD, - languageVersionSettings.coroutineImplAsmType().internalName, + computeLabelOwner(languageVersionSettings, classBuilderForCoroutineState.thisName).internalName, COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor ) @@ -294,9 +299,11 @@ class CoroutineTransformerMethodVisitor( getfield(classBuilderForCoroutineState.thisName, DATA_FIELD_NAME, AsmTypes.OBJECT_TYPE.descriptor) visitVarInsn(Opcodes.ASTORE, dataIndex) - visitVarInsn(Opcodes.ALOAD, continuationIndex) - getfield(classBuilderForCoroutineState.thisName, EXCEPTION_FIELD_NAME, AsmTypes.JAVA_THROWABLE_TYPE.descriptor) - visitVarInsn(Opcodes.ASTORE, exceptionIndex) + if (!languageVersionSettings.isReleaseCoroutines()) { + visitVarInsn(Opcodes.ALOAD, continuationIndex) + getfield(classBuilderForCoroutineState.thisName, EXCEPTION_FIELD_NAME, AsmTypes.JAVA_THROWABLE_TYPE.descriptor) + visitVarInsn(Opcodes.ASTORE, exceptionIndex) + } }) } @@ -517,7 +524,7 @@ class CoroutineTransformerMethodVisitor( remove(possibleTryCatchBlockStart.previous) insert(possibleTryCatchBlockStart, withInstructionAdapter { - generateResumeWithExceptionCheck(exceptionIndex) + generateResumeWithExceptionCheck(languageVersionSettings.isReleaseCoroutines(), dataIndex, exceptionIndex) // Load continuation argument just like suspending function returns it load(dataIndex, AsmTypes.OBJECT_TYPE) @@ -628,12 +635,21 @@ internal fun InstructionAdapter.generateContinuationConstructorCall( ) } -private fun InstructionAdapter.generateResumeWithExceptionCheck(exceptionIndex: Int) { +private fun InstructionAdapter.generateResumeWithExceptionCheck(isReleaseCoroutines: Boolean, dataIndex: Int, exceptionIndex: Int) { // Check if resumeWithException has been called - load(exceptionIndex, AsmTypes.OBJECT_TYPE) + load(if (isReleaseCoroutines) dataIndex else exceptionIndex, AsmTypes.OBJECT_TYPE) dup() val noExceptionLabel = Label() - ifnull(noExceptionLabel) + + if (isReleaseCoroutines) { + instanceOf(AsmTypes.SUCCESS_OR_FAILURE_FAILURE) + ifeq(noExceptionLabel) + // TODO: do we need this checkcast? + checkcast(AsmTypes.SUCCESS_OR_FAILURE_FAILURE) + getfield(AsmTypes.SUCCESS_OR_FAILURE_FAILURE.internalName, "exception", AsmTypes.JAVA_THROWABLE_TYPE.descriptor) + } else { + ifnull(noExceptionLabel) + } athrow() mark(noExceptionLabel) @@ -823,4 +839,4 @@ private fun replaceFakeContinuationsWithRealOnes(methodNode: MethodNode, continu methodNode.instructions.removeAll(listOf(fakeContinuation.previous.previous, fakeContinuation.previous)) methodNode.instructions.set(fakeContinuation, VarInsnNode(Opcodes.ALOAD, continuationIndex)) } -} \ No newline at end of file +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt index 85c7f836b62..57f8ac252d7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtPsiFactory @@ -37,7 +38,9 @@ import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.module +import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass import org.jetbrains.kotlin.resolve.jvm.AsmTypes +import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinTypeFactory import org.jetbrains.kotlin.types.TypeConstructorSubstitution @@ -53,9 +56,18 @@ 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 DATA_FIELD_NAME = "data" const val EXCEPTION_FIELD_NAME = "exception" +fun LanguageVersionSettings.isResumeImplMethodName(name: String) = + if (isReleaseCoroutines()) + name == INVOKE_SUSPEND_METHOD_NAME + else + name == DO_RESUME_METHOD_NAME + +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")) @@ -70,8 +82,19 @@ fun continuationAsmTypes() = listOf( fun LanguageVersionSettings.coroutineContextAsmType() = coroutinesPackageFqName().child(Name.identifier("CoroutineContext")).topLevelClassAsmType() -fun LanguageVersionSettings.coroutineImplAsmType() = - coroutinesJvmInternalPackageFqName().child(Name.identifier("CoroutineImpl")).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 +} + +private fun FqName.identifiedChild(name: String) = child(Name.identifier(name)).topLevelClassInternalName() private fun LanguageVersionSettings.coroutinesIntrinsicsFileFacadeInternalName() = coroutinesIntrinsicsPackageFqName().child(Name.identifier("IntrinsicsKt")).topLevelClassAsmType() @@ -79,6 +102,12 @@ private fun LanguageVersionSettings.coroutinesIntrinsicsFileFacadeInternalName() 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 val NORMALIZE_CONTINUATION_METHOD_NAME = "normalizeContinuation" private val GET_CONTEXT_METHOD_NAME = "getContext" @@ -284,6 +313,17 @@ fun ModuleDescriptor.getContinuationOfTypeOrAny(kotlinType: KotlinType, isReleas ) } ?: module.builtIns.nullableAnyType +fun ModuleDescriptor.getSuccessOrFailure(kotlinType: KotlinType) = + module.resolveTopLevelClass( + DescriptorUtils.SUCCESS_OR_FAILURE_FQ_NAME, + NoLookupLocation.FROM_BACKEND + )?.defaultType?.let { + KotlinTypeFactory.simpleType( + it, + arguments = listOf(kotlinType.asTypeProjection()) + ) + } ?: ErrorUtils.createErrorType("For SuccessOrFailure") + fun FunctionDescriptor.isBuiltInSuspendCoroutineOrReturnInJvm(languageVersionSettings: LanguageVersionSettings) = getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION)?.isBuiltInSuspendCoroutineOrReturn(languageVersionSettings) == true @@ -470,6 +510,17 @@ fun InstructionAdapter.invokeDoResumeWithUnit(thisName: String) { ) } +fun InstructionAdapter.invokeInvokeSuspendWithUnit(thisName: String) { + StackValue.putUnitInstance(this) + + invokevirtual( + thisName, + INVOKE_SUSPEND_METHOD_NAME, + Type.getMethodDescriptor(AsmTypes.OBJECT_TYPE, AsmTypes.OBJECT_TYPE), + false + ) +} + fun Method.getImplForOpenMethod(ownerInternalName: String) = Method("$name\$suspendImpl", returnType, arrayOf(Type.getObjectType(ownerInternalName)) + argumentTypes) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt index 16a4751de38..2752aa77641 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt @@ -10,17 +10,18 @@ import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.ClassBuilder import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.coroutines.CoroutineTransformerMethodVisitor +import org.jetbrains.kotlin.codegen.coroutines.isCoroutineSuperClass +import org.jetbrains.kotlin.codegen.coroutines.isResumeImplMethodName import org.jetbrains.kotlin.codegen.optimization.common.asSequence import org.jetbrains.kotlin.codegen.serialization.JvmCodegenStringTable -import org.jetbrains.kotlin.codegen.coroutines.coroutineImplAsmType import org.jetbrains.kotlin.codegen.writeKotlinMetadata import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass +import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader +import org.jetbrains.kotlin.load.kotlin.header.ReadKotlinClassHeaderAnnotationVisitor import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil import org.jetbrains.kotlin.metadata.jvm.serialization.JvmStringTable -import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader -import org.jetbrains.kotlin.load.kotlin.header.ReadKotlinClassHeaderAnnotationVisitor import org.jetbrains.kotlin.protobuf.MessageLite import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN @@ -55,7 +56,7 @@ class AnonymousObjectTransformer( createClassReader().accept(object : ClassVisitor(API, classBuilder.visitor) { override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array) { classBuilder.defineClass(null, version, access, name, signature, superName, interfaces) - if (languageVersionSettings.coroutineImplAsmType().internalName == superName) { + if (languageVersionSettings.isCoroutineSuperClass(superName)) { inliningContext.isContinuation = true } } @@ -152,7 +153,7 @@ class AnonymousObjectTransformer( // 2) Suspend named function // Iff it captures crossinline suspend lambda val generateStateMachineForLambda = - next.name == "doResume" && capturesCrossinlineSuspend && inliningContext.isContinuation && + languageVersionSettings.isResumeImplMethodName(next.name) && capturesCrossinlineSuspend && inliningContext.isContinuation && !isLambdaAlreadyGeneratedAndNotGoingToBeInlined && hasLambdasToInline val continuationClassName = findFakeContinuationConstructorClassName(next) val generateStateMachineForNamedFunction = diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java index b22967c171b..e3f17b96a82 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java @@ -47,6 +47,7 @@ public class AsmTypes { public static final Type MUTABLE_PROPERTY_REFERENCE1 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference1"); public static final Type MUTABLE_PROPERTY_REFERENCE2 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference2"); + public static final Type SUCCESS_OR_FAILURE_FAILURE = Type.getObjectType("kotlin/SuccessOrFailure$Failure"); public static final Type[] PROPERTY_REFERENCE_IMPL = { Type.getObjectType("kotlin/jvm/internal/PropertyReference0Impl"), diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/coroutineCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/coroutineCallChecker.kt index 0cc968904c4..ca5549b0564 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/coroutineCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/coroutineCallChecker.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.supertypes import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -130,15 +131,17 @@ fun checkCoroutinesFeature(languageVersionSettings: LanguageVersionSettings, dia } } +fun KotlinType.isRestrictsSuspensionReceiver(languageVersionSettings: LanguageVersionSettings) = (listOf(this) + this.supertypes()).any { + it.constructor.declarationDescriptor?.annotations?.hasAnnotation(languageVersionSettings.restrictsSuspensionFqName()) == true +} + private fun checkRestrictsSuspension( enclosingSuspendCallableDescriptor: CallableDescriptor, resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext ) { - fun ReceiverValue.isRestrictsSuspensionReceiver() = (listOf(type) + type.supertypes()).any { - it.constructor.declarationDescriptor?.annotations?.hasAnnotation(context.languageVersionSettings.restrictsSuspensionFqName()) == true - } + fun ReceiverValue.isRestrictsSuspensionReceiver() = type.isRestrictsSuspensionReceiver(context.languageVersionSettings) infix fun ReceiverValue.sameInstance(other: ReceiverValue?): Boolean { if (other == null) return false diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt index 0719a40cd8c..e7ab205ed6d 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt @@ -17,6 +17,8 @@ package org.jetbrains.kotlin.codegen import org.jetbrains.kotlin.backend.common.output.OutputFile +import org.jetbrains.kotlin.codegen.coroutines.DO_RESUME_METHOD_NAME +import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME import org.jetbrains.kotlin.inline.inlineFunctionsJvmNames import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAnnotationNames @@ -128,7 +130,12 @@ object InlineTestUtil { if (skipMethodsOfThisClass) { return null } - if (name == "doResume" && desc == "(Ljava/lang/Object;Ljava/lang/Throwable;)Ljava/lang/Object;") { + + if (name == DO_RESUME_METHOD_NAME && desc == "(Ljava/lang/Object;Ljava/lang/Throwable;)Ljava/lang/Object;") { + return null + } + + if (name == INVOKE_SUSPEND_METHOD_NAME && desc == "(Ljava/lang/Object;)Ljava/lang/Object;") { return null } diff --git a/compiler/util/src/org/jetbrains/kotlin/config/CoroutineLanguageVersionSettingsUtil.kt b/compiler/util/src/org/jetbrains/kotlin/config/CoroutineLanguageVersionSettingsUtil.kt index 44a976e3cdc..0012e258cb7 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/CoroutineLanguageVersionSettingsUtil.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/CoroutineLanguageVersionSettingsUtil.kt @@ -5,14 +5,16 @@ package org.jetbrains.kotlin.config -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorUtils fun LanguageVersionSettings.coroutinesPackageFqName(): FqName { - return coroutinesPackageFqName(supportsFeature(LanguageFeature.ReleaseCoroutines)) + return coroutinesPackageFqName(isReleaseCoroutines()) } +fun LanguageVersionSettings.isReleaseCoroutines() = supportsFeature(LanguageFeature.ReleaseCoroutines) + private fun coroutinesPackageFqName(isReleaseCoroutines: Boolean): FqName { return if (isReleaseCoroutines) DescriptorUtils.COROUTINES_PACKAGE_FQ_NAME_RELEASE @@ -34,4 +36,4 @@ fun FqName.isBuiltInCoroutineContext(languageVersionSettings: LanguageVersionSet this == DescriptorUtils.COROUTINES_PACKAGE_FQ_NAME_RELEASE.child(Name.identifier("coroutineContext")) else this == DescriptorUtils.COROUTINES_PACKAGE_FQ_NAME_EXPERIMENTAL.child(Name.identifier("coroutineContext")) || - this == DescriptorUtils.COROUTINES_INTRINSICS_PACKAGE_FQ_NAME_EXPERIMENTAL.child(Name.identifier("coroutineContext")) \ No newline at end of file + this == DescriptorUtils.COROUTINES_INTRINSICS_PACKAGE_FQ_NAME_EXPERIMENTAL.child(Name.identifier("coroutineContext")) diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java index d2b1733e871..c9e2f790a92 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java @@ -49,6 +49,8 @@ public class DescriptorUtils { public static final FqName CONTINUATION_INTERFACE_FQ_NAME_RELEASE = COROUTINES_PACKAGE_FQ_NAME_RELEASE.child(Name.identifier("Continuation")); + public static final FqName SUCCESS_OR_FAILURE_FQ_NAME = new FqName("kotlin.SuccessOrFailure"); + private DescriptorUtils() { } diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/debuggerUtil.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/debuggerUtil.kt index e5ead557a39..8d16e4e819f 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/debuggerUtil.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/debuggerUtil.kt @@ -16,6 +16,7 @@ import com.sun.jdi.* import com.sun.tools.jdi.LocalVariableImpl import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.coroutines.DO_RESUME_METHOD_NAME +import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME import org.jetbrains.kotlin.codegen.coroutines.continuationAsmTypes import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches @@ -180,7 +181,8 @@ private class MockStackFrame(private val location: Location, private val vm: Vir override fun virtualMachine() = vm } -private val DO_RESUME_SIGNATURE = "(Ljava/lang/Object;Ljava/lang/Throwable;)Ljava/lang/Object;" +private const val DO_RESUME_SIGNATURE = "(Ljava/lang/Object;Ljava/lang/Throwable;)Ljava/lang/Object;" +private const val INVOKE_SUSPEND_SIGNATURE = "(Ljava/lang/Object;)Ljava/lang/Object;" fun isInSuspendMethod(location: Location): Boolean { val method = location.method() @@ -188,7 +190,8 @@ fun isInSuspendMethod(location: Location): Boolean { for (continuationAsmType in continuationAsmTypes()) { if (signature.contains(continuationAsmType.toString()) || - (method.name() == DO_RESUME_METHOD_NAME && signature == DO_RESUME_SIGNATURE) + (method.name() == DO_RESUME_METHOD_NAME && signature == DO_RESUME_SIGNATURE) || + (method.name() == INVOKE_SUSPEND_METHOD_NAME && signature == INVOKE_SUSPEND_SIGNATURE) ) return true } return false diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinLambdaMethodFilter.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinLambdaMethodFilter.kt index b478196709b..a8fed0f6b72 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinLambdaMethodFilter.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinLambdaMethodFilter.kt @@ -21,7 +21,7 @@ import com.intellij.debugger.engine.BreakpointStepMethodFilter import com.intellij.debugger.engine.DebugProcessImpl import com.intellij.util.Range import com.sun.jdi.Location -import org.jetbrains.kotlin.codegen.coroutines.DO_RESUME_METHOD_NAME +import org.jetbrains.kotlin.codegen.coroutines.isResumeImplMethodNameFromAnyLanguageSettings import org.jetbrains.kotlin.idea.debugger.isInsideInlineArgument import org.jetbrains.kotlin.idea.refactoring.isMultiLine import org.jetbrains.kotlin.psi.KtBlockExpression @@ -74,11 +74,11 @@ class KotlinLambdaMethodFilter( override fun getCallingExpressionLines() = if (isInline) Range(0, 999) else myCallingExpressionLines private fun isLambdaName(name: String?): Boolean { - if (isSuspend) { - return name == DO_RESUME_METHOD_NAME + if (isSuspend && name != null) { + return isResumeImplMethodNameFromAnyLanguageSettings(name) } return name == OperatorNameConventions.INVOKE.asString() } -} \ No newline at end of file +}