Support release coroutines (#1909)

This commit is contained in:
SvyatoslavScherbina
2018-08-24 15:35:35 +03:00
committed by GitHub
parent d52a3f0c3d
commit 29cddb46bf
48 changed files with 712 additions and 388 deletions
@@ -198,7 +198,7 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
} }
override fun createArguments(): K2NativeCompilerArguments { override fun createArguments(): K2NativeCompilerArguments {
return K2NativeCompilerArguments().apply { coroutinesState = "enable" } return K2NativeCompilerArguments()
} }
override fun executableScriptFileName() = "kotlinc-native" override fun executableScriptFileName() = "kotlinc-native"
@@ -18,8 +18,6 @@ package org.jetbrains.kotlin.cli.bc
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.Argument import org.jetbrains.kotlin.cli.common.arguments.Argument
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.LanguageFeature
class K2NativeCompilerArguments : CommonCompilerArguments() { class K2NativeCompilerArguments : CommonCompilerArguments() {
// First go the options interesting to the general public. // First go the options interesting to the general public.
@@ -149,10 +147,5 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
description = "Paths to friend modules" description = "Paths to friend modules"
) )
var friendModules: String? = null var friendModules: String? = null
override fun configureLanguageFeatures(collector: MessageCollector) = super.configureLanguageFeatures(collector).also {
it[LanguageFeature.InlineClasses] = LanguageFeature.State.ENABLED // TODO: remove after updating to 1.3.
it[LanguageFeature.ReleaseCoroutines] = LanguageFeature.State.DISABLED
}
} }
@@ -327,9 +327,6 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val
val getContinuation = symbolTable.referenceSimpleFunction( val getContinuation = symbolTable.referenceSimpleFunction(
context.getInternalFunctions("getContinuation").single()) context.getInternalFunctions("getContinuation").single())
val konanIntercepted = symbolTable.referenceSimpleFunction(
context.getInternalFunctions("intercepted").single())
val konanSuspendCoroutineUninterceptedOrReturn = symbolTable.referenceSimpleFunction( val konanSuspendCoroutineUninterceptedOrReturn = symbolTable.referenceSimpleFunction(
context.getInternalFunctions("suspendCoroutineUninterceptedOrReturn").single()) context.getInternalFunctions("suspendCoroutineUninterceptedOrReturn").single())
@@ -347,7 +344,22 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val
.single() .single()
.getter!! .getter!!
override val coroutineImpl = symbolTable.referenceClass(context.getInternalClass("CoroutineImpl")) override val coroutineImpl get() = TODO()
val baseContinuationImpl = symbolTable.referenceClass(
builtIns.builtInsModule.findClassAcrossModuleDependencies(
ClassId.topLevel(FqName("kotlin.coroutines.native.internal.BaseContinuationImpl")))!!
)
val restrictedContinuationImpl = symbolTable.referenceClass(
builtIns.builtInsModule.findClassAcrossModuleDependencies(
ClassId.topLevel(FqName("kotlin.coroutines.native.internal.RestrictedContinuationImpl")))!!
)
val continuationImpl = symbolTable.referenceClass(
builtIns.builtInsModule.findClassAcrossModuleDependencies(
ClassId.topLevel(FqName("kotlin.coroutines.native.internal.ContinuationImpl")))!!
)
override val coroutineSuspendedGetter = symbolTable.referenceSimpleFunction( override val coroutineSuspendedGetter = symbolTable.referenceSimpleFunction(
coroutinesIntrinsicsPackage coroutinesIntrinsicsPackage
@@ -355,6 +367,11 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val
.filterNot { it.isExpect }.single().getter!! .filterNot { it.isExpect }.single().getter!!
) )
val successOrFailure = symbolTable.referenceClass(
builtIns.builtInsModule.findClassAcrossModuleDependencies(
ClassId.topLevel(FqName("kotlin.SuccessOrFailure")))!!
)
val refClass = symbolTable.referenceClass(context.getInternalClass("Ref")) val refClass = symbolTable.referenceClass(context.getInternalClass("Ref"))
val kLocalDelegatedPropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedPropertyImpl) val kLocalDelegatedPropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedPropertyImpl)
@@ -1920,19 +1920,18 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private val coroutineImplDescriptor = context.ir.symbols.coroutineImpl.owner private val invokeSuspendFunction = context.ir.symbols.baseContinuationImpl.owner.declarations
private val doResumeFunctionDescriptor = coroutineImplDescriptor.declarations .filterIsInstance<IrSimpleFunction>().single { it.name.asString() == "invokeSuspend" }
.filterIsInstance<IrSimpleFunction>().single { it.name.asString() == "doResume" }
private fun getContinuation(): LLVMValueRef { private fun getContinuation(): LLVMValueRef {
val caller = functionGenerationContext.functionDescriptor!! val caller = functionGenerationContext.functionDescriptor!!
return if (caller.isSuspend) return if (caller.isSuspend)
codegen.param(caller, caller.allParameters.size) // The last argument. codegen.param(caller, caller.allParameters.size) // The last argument.
else { else {
// Suspend call from non-suspend function - must be [CoroutineImpl]. // Suspend call from non-suspend function - must be [BaseContinuationImpl].
assert (doResumeFunctionDescriptor.symbol in (caller as IrSimpleFunction).overriddenSymbols, assert ((caller as IrSimpleFunction).overrides(invokeSuspendFunction),
{ "Expected 'CoroutineImpl.doResume' but was '$caller'" }) { "Expected 'BaseContinuationImpl.invokeSuspend' but was '$caller'" })
currentCodeContext.genGetValue(caller.dispatchReceiverParameter!!) // Coroutine itself is a continuation. currentCodeContext.genGetValue(caller.dispatchReceiverParameter!!)
} }
} }
@@ -99,7 +99,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
descriptor.resolveFakeOverride().original.let { descriptor.resolveFakeOverride().original.let {
when { when {
it.isBuiltInIntercepted(context.config.configuration.languageVersionSettings) -> it.isBuiltInIntercepted(context.config.configuration.languageVersionSettings) ->
getFunctionDeclaration(context.ir.symbols.konanIntercepted.descriptor) error("Continuation.intercepted is not available with release coroutines")
it.isBuiltInSuspendCoroutineUninterceptedOrReturn(context.config.configuration.languageVersionSettings) -> it.isBuiltInSuspendCoroutineUninterceptedOrReturn(context.config.configuration.languageVersionSettings) ->
getFunctionDeclaration(context.ir.symbols.konanSuspendCoroutineUninterceptedOrReturn.descriptor) getFunctionDeclaration(context.ir.symbols.konanSuspendCoroutineUninterceptedOrReturn.descriptor)
@@ -18,11 +18,11 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.descriptors.getFunction import org.jetbrains.kotlin.backend.common.descriptors.getFunction
import org.jetbrains.kotlin.backend.common.ir.createOverriddenDescriptor
import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWith import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWith
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
@@ -242,7 +242,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
val irBuilder = context.createIrBuilder(irFunction.symbol, irFunction.startOffset, irFunction.endOffset) val irBuilder = context.createIrBuilder(irFunction.symbol, irFunction.startOffset, irFunction.endOffset)
irFunction.body = irBuilder.irBlockBody(irFunction) { irFunction.body = irBuilder.irBlockBody(irFunction) {
+irReturn( +irReturn(
irCall(coroutine.doResumeFunction.symbol).apply { irCall(coroutine.invokeSuspendFunction.symbol).apply {
dispatchReceiver = irCall(coroutine.coroutineConstructor.symbol).apply { dispatchReceiver = irCall(coroutine.coroutineConstructor.symbol).apply {
val functionParameters = irFunction.explicitParameters val functionParameters = irFunction.explicitParameters
functionParameters.forEachIndexed { index, argument -> functionParameters.forEachIndexed { index, argument ->
@@ -251,8 +251,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
putValueArgument(functionParameters.size, putValueArgument(functionParameters.size,
irCall(getContinuation, listOf(irFunction.returnType))) irCall(getContinuation, listOf(irFunction.returnType)))
} }
putValueArgument(0, irGetObject(symbols.unit)) // value putValueArgument(0, irSuccess(irGetObject(symbols.unit)))
putValueArgument(1, irNull()) // exception
}) })
} }
} }
@@ -262,7 +261,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
private class BuiltCoroutine(val coroutineClass: IrClass, private class BuiltCoroutine(val coroutineClass: IrClass,
val coroutineConstructor: IrConstructor, val coroutineConstructor: IrConstructor,
val doResumeFunction: IrFunction) val invokeSuspendFunction: IrFunction)
private var coroutineId = 0 private var coroutineId = 0
@@ -280,26 +279,28 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
private var tempIndex = 0 private var tempIndex = 0
private var suspensionPointIdIndex = 0 private var suspensionPointIdIndex = 0
private lateinit var labelField: IrField
private lateinit var suspendResult: IrVariable private lateinit var suspendResult: IrVariable
private lateinit var dataArgument: IrValueParameter private lateinit var resultArgument: IrValueParameter
private lateinit var exceptionArgument: IrValueParameter
private lateinit var coroutineClassDescriptor: ClassDescriptorImpl private lateinit var coroutineClassDescriptor: ClassDescriptorImpl
private lateinit var coroutineClass: IrClassImpl private lateinit var coroutineClass: IrClassImpl
private lateinit var coroutineClassThis: IrValueParameter private lateinit var coroutineClassThis: IrValueParameter
private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, IrField> private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, IrField>
private val coroutineImplSymbol = symbols.coroutineImpl private val baseClass =
private val coroutineImplConstructorSymbol = coroutineImplSymbol.constructors.single() (if (irFunction.isRestrictedSuspendFunction(context.config.configuration.languageVersionSettings)) {
private val coroutineImplClassDescriptor = coroutineImplSymbol.descriptor symbols.restrictedContinuationImpl
private val create1Function = coroutineImplSymbol.owner.simpleFunctions() } else {
symbols.continuationImpl
}).owner
private val baseClassConstructor = baseClass.constructors.single { it.valueParameters.size == 1 }
private val create1Function = baseClass.simpleFunctions()
.single { it.name.asString() == "create" && it.valueParameters.size == 1 } .single { it.name.asString() == "create" && it.valueParameters.size == 1 }
private val create1CompletionParameter = create1Function.valueParameters[0] private val create1CompletionParameter = create1Function.valueParameters[0]
private val coroutineImplLabelGetterSymbol = coroutineImplSymbol.getPropertyGetter("label")!!
private val coroutineImplLabelSetterSymbol = coroutineImplSymbol.getPropertySetter("label")!!
fun build(): BuiltCoroutine { fun build(): BuiltCoroutine {
val superTypes = mutableListOf<IrType>(coroutineImplSymbol.owner.defaultType) val superTypes = mutableListOf<IrType>(baseClass.defaultType)
var suspendFunctionClass: IrClass? = null var suspendFunctionClass: IrClass? = null
var functionClass: IrClass? = null var functionClass: IrClass? = null
var suspendFunctionClassTypeArguments: List<IrType>? = null var suspendFunctionClassTypeArguments: List<IrType>? = null
@@ -340,16 +341,27 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
coroutineClass.createParameterDeclarations() coroutineClass.createParameterDeclarations()
coroutineClassThis = coroutineClass.thisReceiver!! coroutineClassThis = coroutineClass.thisReceiver!!
labelField = createField(
irFunction.startOffset,
irFunction.endOffset,
symbols.nativePtrType,
Name.identifier("label"),
true,
IrDeclarationOrigin.DEFINED,
coroutineClass.descriptor
)
coroutineClass.addChild(labelField)
val overriddenMap = mutableMapOf<CallableMemberDescriptor, CallableMemberDescriptor>() val overriddenMap = mutableMapOf<CallableMemberDescriptor, CallableMemberDescriptor>()
val coroutineConstructorBuilder = createConstructorBuilder() val coroutineConstructorBuilder = createConstructorBuilder()
coroutineConstructorBuilder.initialize() coroutineConstructorBuilder.initialize()
val doResumeFunction = coroutineImplSymbol.owner.simpleFunctions() val invokeSuspendFunction = baseClass.simpleFunctions()
.single { it.name.asString() == "doResume" } .single { it.name.asString() == "invokeSuspend" }
val doResumeMethodBuilder = createDoResumeMethodBuilder(doResumeFunction, coroutineClass) val invokeSuspendMethodBuilder = createInvokeSuspendMethodBuilder(invokeSuspendFunction, coroutineClass)
doResumeMethodBuilder.initialize() invokeSuspendMethodBuilder.initialize()
overriddenMap += doResumeFunction.descriptor to doResumeMethodBuilder.symbol.descriptor overriddenMap += invokeSuspendFunction.descriptor to invokeSuspendMethodBuilder.symbol.descriptor
var coroutineFactoryConstructorBuilder: SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>? = null var coroutineFactoryConstructorBuilder: SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>? = null
var createMethodBuilder: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>? = null var createMethodBuilder: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>? = null
@@ -358,7 +370,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
// Suspend lambda - create factory methods. // Suspend lambda - create factory methods.
coroutineFactoryConstructorBuilder = createFactoryConstructorBuilder(boundFunctionParameters!!) coroutineFactoryConstructorBuilder = createFactoryConstructorBuilder(boundFunctionParameters!!)
val createFunctionDescriptor = coroutineImplClassDescriptor.unsubstitutedMemberScope val createFunctionDescriptor = baseClass.descriptor.unsubstitutedMemberScope
.getContributedFunctions(Name.identifier("create"), NoLookupLocation.FROM_BACKEND) .getContributedFunctions(Name.identifier("create"), NoLookupLocation.FROM_BACKEND)
.atMostOne { it.valueParameters.size == unboundFunctionParameters!!.size + 1 } .atMostOne { it.valueParameters.size == unboundFunctionParameters!!.size + 1 }
createMethodBuilder = createCreateMethodBuilder( createMethodBuilder = createCreateMethodBuilder(
@@ -378,7 +390,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
suspendFunctionInvokeFunctionDescriptor = suspendInvokeFunctionDescriptor, suspendFunctionInvokeFunctionDescriptor = suspendInvokeFunctionDescriptor,
functionInvokeFunctionDescriptor = invokeFunctionDescriptor, functionInvokeFunctionDescriptor = invokeFunctionDescriptor,
createFunction = createMethodBuilder.ir, createFunction = createMethodBuilder.ir,
doResumeFunction = doResumeMethodBuilder.ir, invokeSuspendFunction = invokeSuspendMethodBuilder.ir,
coroutineClass = coroutineClass) coroutineClass = coroutineClass)
} }
@@ -398,7 +410,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
coroutineClass.addChild(it.ir) coroutineClass.addChild(it.ir)
} }
coroutineClass.addChild(doResumeMethodBuilder.ir) coroutineClass.addChild(invokeSuspendMethodBuilder.ir)
coroutineClass.setSuperSymbolsAndAddFakeOverrides(superTypes) coroutineClass.setSuperSymbolsAndAddFakeOverrides(superTypes)
@@ -406,7 +418,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
coroutineClass = coroutineClass, coroutineClass = coroutineClass,
coroutineConstructor = coroutineFactoryConstructorBuilder?.ir coroutineConstructor = coroutineFactoryConstructorBuilder?.ir
?: coroutineConstructorBuilder.ir, ?: coroutineConstructorBuilder.ir,
doResumeFunction = doResumeMethodBuilder.ir) invokeSuspendFunction = invokeSuspendMethodBuilder.ir)
} }
private fun createConstructorBuilder() private fun createConstructorBuilder()
@@ -427,7 +439,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl
constructorParameters = ( constructorParameters = (
functionParameters functionParameters
+ coroutineImplConstructorSymbol.owner.valueParameters[0] // completion. + baseClassConstructor.valueParameters[0] // completion.
).mapIndexed { index, parameter -> ).mapIndexed { index, parameter ->
val parameterDescriptor = parameter.descriptor.copyAsValueParameter(descriptor, index) val parameterDescriptor = parameter.descriptor.copyAsValueParameter(descriptor, index)
@@ -464,10 +476,13 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
val completionParameter = valueParameters.last() val completionParameter = valueParameters.last()
+IrDelegatingConstructorCallImpl(startOffset, endOffset, +IrDelegatingConstructorCallImpl(startOffset, endOffset,
context.irBuiltIns.unitType, context.irBuiltIns.unitType,
coroutineImplConstructorSymbol, coroutineImplConstructorSymbol.descriptor).apply { baseClassConstructor.symbol, baseClassConstructor.descriptor).apply {
putValueArgument(0, irGet(completionParameter)) putValueArgument(0, irGet(completionParameter))
} }
+IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol, context.irBuiltIns.unitType) +IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol, context.irBuiltIns.unitType)
+irSetField(irGet(coroutineClassThis), labelField, irCall(symbols.getNativeNullPtr.owner))
functionParameters.forEachIndexed { index, parameter -> functionParameters.forEachIndexed { index, parameter ->
+irSetField( +irSetField(
irGet(coroutineClassThis), irGet(coroutineClassThis),
@@ -523,7 +538,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody { body = irBuilder.irBlockBody {
+IrDelegatingConstructorCallImpl(startOffset, endOffset, context.irBuiltIns.unitType, +IrDelegatingConstructorCallImpl(startOffset, endOffset, context.irBuiltIns.unitType,
coroutineImplConstructorSymbol, coroutineImplConstructorSymbol.descriptor).apply { baseClassConstructor.symbol, baseClassConstructor.descriptor).apply {
putValueArgument(0, irNull()) // Completion. putValueArgument(0, irNull()) // Completion.
} }
+IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol, +IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol,
@@ -573,8 +588,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
/* modality = */ Modality.FINAL, /* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE).apply { /* visibility = */ Visibilities.PRIVATE).apply {
if (superFunctionDescriptor != null) { if (superFunctionDescriptor != null) {
overriddenDescriptors += superFunctionDescriptor.overriddenDescriptors overriddenDescriptors = listOf(superFunctionDescriptor)
overriddenDescriptors += superFunctionDescriptor
} }
} }
} }
@@ -622,7 +636,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
private fun createInvokeMethodBuilder(suspendFunctionInvokeFunctionDescriptor: FunctionDescriptor, private fun createInvokeMethodBuilder(suspendFunctionInvokeFunctionDescriptor: FunctionDescriptor,
functionInvokeFunctionDescriptor: FunctionDescriptor, functionInvokeFunctionDescriptor: FunctionDescriptor,
createFunction: IrFunction, createFunction: IrFunction,
doResumeFunction: IrFunction, invokeSuspendFunction: IrFunction,
coroutineClass: IrClass) coroutineClass: IrClass)
= object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() { = object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
@@ -679,7 +693,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody(startOffset, endOffset) { body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn( +irReturn(
irCall(doResumeFunction).apply { irCall(invokeSuspendFunction).apply {
dispatchReceiver = irCall(createFunction).apply { dispatchReceiver = irCall(createFunction).apply {
dispatchReceiver = irGet(thisReceiver) dispatchReceiver = irGet(thisReceiver)
valueParameters.forEachIndexed { index, parameter -> valueParameters.forEachIndexed { index, parameter ->
@@ -688,8 +702,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
putValueArgument(valueParameters.size, putValueArgument(valueParameters.size,
irCall(getContinuation, listOf(returnType))) irCall(getContinuation, listOf(returnType)))
} }
putValueArgument(0, irGetObject(symbols.unit)) // value putValueArgument(0, irSuccess(irGetObject(symbols.unit)))
putValueArgument(1, irNull()) // exception
} }
) )
} }
@@ -709,11 +722,11 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
coroutineClass.addChild(it) coroutineClass.addChild(it)
} }
private fun createDoResumeMethodBuilder(doResumeFunction: IrFunction, coroutineClass: IrClass) private fun createInvokeSuspendMethodBuilder(invokeSuspendFunction: IrFunction, coroutineClass: IrClass)
= object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() { = object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
override fun buildSymbol() = IrSimpleFunctionSymbolImpl( override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
doResumeFunction.descriptor.createOverriddenDescriptor(coroutineClassDescriptor) invokeSuspendFunction.descriptor.createOverriddenDescriptor(coroutineClassDescriptor)
) )
override fun doInitialize() { } override fun doInitialize() { }
@@ -733,17 +746,13 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
this.createDispatchReceiverParameter() this.createDispatchReceiverParameter()
doResumeFunction.valueParameters.mapIndexedTo(this.valueParameters) { index, it -> invokeSuspendFunction.valueParameters.mapIndexedTo(this.valueParameters) { index, it ->
it.copy(descriptor.valueParameters[index]) it.copy(descriptor.valueParameters[index])
} }
} }
dataArgument = function.valueParameters[0] resultArgument = function.valueParameters.single()
exceptionArgument = function.valueParameters[1]
val label = coroutineImplSymbol.owner.declarations.filterIsInstance<IrProperty>()
.single { it.name.asString() == "label" }
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
function.body = irBuilder.irBlockBody(startOffset, endOffset) { function.body = irBuilder.irBlockBody(startOffset, endOffset) {
@@ -756,7 +765,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
, context.irBuiltIns.anyNType) , context.irBuiltIns.anyNType)
// Extract all suspend calls to temporaries in order to make correct jumps to them. // Extract all suspend calls to temporaries in order to make correct jumps to them.
originalBody.transformChildrenVoid(ExpressionSlicer(label.getter!!.returnType)) originalBody.transformChildrenVoid(ExpressionSlicer(labelField.type))
val liveLocals = computeLivenessAtSuspensionPoints(originalBody) val liveLocals = computeLivenessAtSuspensionPoints(originalBody)
@@ -837,10 +846,11 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
val variable = localsMap[it.descriptor] ?: it val variable = localsMap[it.descriptor] ?: it
+irSetField(irGet(thisReceiver), localToPropertyMap[it.symbol]!!, irGet(variable)) +irSetField(irGet(thisReceiver), localToPropertyMap[it.symbol]!!, irGet(variable))
} }
+irCall(coroutineImplLabelSetterSymbol).apply { +irSetField(
dispatchReceiver = irGet(thisReceiver) irGet(thisReceiver),
putValueArgument(0, irGet(suspensionPoint.suspensionPointIdParameter)) labelField,
} irGet(suspensionPoint.suspensionPointIdParameter)
)
} }
} }
restoreState.symbol -> { restoreState.symbol -> {
@@ -865,11 +875,9 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
type = context.irBuiltIns.unitType, type = context.irBuiltIns.unitType,
suspensionPointId = irCall(coroutineImplLabelGetterSymbol).apply { suspensionPointId = irGetField(irGet(function.dispatchReceiverParameter!!), labelField),
dispatchReceiver = irGet(function.dispatchReceiverParameter!!)
},
result = irBlock(startOffset, endOffset) { result = irBlock(startOffset, endOffset) {
+irThrowIfNotNull(exceptionArgument) // Coroutine might start with an exception. +irThrowIfNotNull(irExceptionOrNull(irGet(resultArgument))) // Coroutine might start with an exception.
statements.forEach { +it } statements.forEach { +it }
}) })
if (irFunction.returnType.isUnit()) if (irFunction.returnType.isUnit())
@@ -1107,8 +1115,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
}, },
resumeResult = irBlock(startOffset, endOffset) { resumeResult = irBlock(startOffset, endOffset) {
+irCall(restoreState) +irCall(restoreState)
+irThrowIfNotNull(exceptionArgument) +irGetOrThrow(irGet(resultArgument))
+irGet(dataArgument)
}) })
val expressionResult = when { val expressionResult = when {
suspendCall.type.isUnit() -> irImplicitCoercionToUnit(suspensionPoint) suspendCall.type.isUnit() -> irImplicitCoercionToUnit(suspensionPoint)
@@ -1188,7 +1195,11 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
irIfThen(irEqeqeq(irGet(value), irCall(symbols.coroutineSuspendedGetter)), irIfThen(irEqeqeq(irGet(value), irCall(symbols.coroutineSuspendedGetter)),
irReturn(irGet(value))) irReturn(irGet(value)))
private fun IrBuilderWithScope.irThrowIfNotNull(exception: IrValueDeclaration) = private fun IrBuilderWithScope.irThrowIfNotNull(exception: IrExpression) = irLetS(exception) {
irThrowIfNotNull(it.owner)
}
fun IrBuilderWithScope.irThrowIfNotNull(exception: IrValueDeclaration) =
irIfThen(irNot(irEqeqeq(irGet(exception), irNull())), irIfThen(irNot(irEqeqeq(irGet(exception), irNull())),
irThrow(irImplicitCast(irGet(exception), exception.type.makeNotNull()))) irThrow(irImplicitCast(irGet(exception), exception.type.makeNotNull())))
@@ -1200,6 +1211,30 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
} }
} }
private fun IrBuilderWithScope.irGetOrThrow(successOrFailure: IrExpression): IrExpression {
// TODO: consider inlining getOrThrow function body here.
val successOrFailureClass = symbols.successOrFailure.owner
val getOrThrow = successOrFailureClass.simpleFunctions().single { it.name.asString() == "getOrThrow" }
return irCall(getOrThrow).apply {
dispatchReceiver = successOrFailure
}
}
private fun IrBuilderWithScope.irExceptionOrNull(successOrFailure: IrExpression): IrExpression {
val successOrFailureClass = symbols.successOrFailure.owner
val exceptionOrNull = successOrFailureClass.simpleFunctions().single { it.name.asString() == "exceptionOrNull" }
return irCall(exceptionOrNull).apply {
dispatchReceiver = successOrFailure
}
}
fun IrBlockBodyBuilder.irSuccess(value: IrExpression): IrCall {
val createSuccessOrFailure = symbols.successOrFailure.owner.constructors.single { it.isPrimary }
return irCall(createSuccessOrFailure).apply {
putValueArgument(0, value)
}
}
private open class VariablesScopeTracker: IrElementVisitorVoid { private open class VariablesScopeTracker: IrElementVisitorVoid {
protected val scopeStack = mutableListOf<MutableSet<IrVariable>>(mutableSetOf()) protected val scopeStack = mutableListOf<MutableSet<IrVariable>>(mutableSetOf())
@@ -403,9 +403,9 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
} }
} }
private val doResumeFunctionSymbol = private val invokeSuspendFunctionSymbol =
context.ir.symbols.coroutineImpl.owner.declarations context.ir.symbols.baseContinuationImpl.owner.declarations
.filterIsInstance<IrSimpleFunction>().single { it.name.asString() == "doResume" }.symbol .filterIsInstance<IrSimpleFunction>().single { it.name.asString() == "invokeSuspend" }.symbol
private val getContinuationSymbol = context.ir.symbols.getContinuation private val getContinuationSymbol = context.ir.symbols.getContinuation
private val continuationType = getContinuationSymbol.owner.returnType private val continuationType = getContinuationSymbol.owner.returnType
@@ -439,7 +439,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
descriptor.isSuspend -> DataFlowIR.Node.Parameter(allParameters.size) descriptor.isSuspend -> DataFlowIR.Node.Parameter(allParameters.size)
doResumeFunctionSymbol in descriptor.overriddenSymbols -> // <this> is a CoroutineImpl inheritor. descriptor.overrides(invokeSuspendFunctionSymbol.owner) -> // <this> is a ContinuationImpl inheritor.
templateParameters[descriptor.dispatchReceiverParameter!!] // It is its own continuation. templateParameters[descriptor.dispatchReceiverParameter!!] // It is its own continuation.
else -> null else -> null
@@ -259,7 +259,7 @@ class KonanDescriptorSerializer private constructor(
if (requirement != null) { if (requirement != null) {
builder.addAllVersionRequirement(requirement) builder.addAllVersionRequirement(requirement)
} }
else if (descriptor.isSuspendOrHasSuspendTypesInSignature()) { if (descriptor.isSuspendOrHasSuspendTypesInSignature()) {
builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion()) builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion())
} }
@@ -342,7 +342,7 @@ class KonanDescriptorSerializer private constructor(
if (requirement != null) { if (requirement != null) {
builder.addAllVersionRequirement(requirement) builder.addAllVersionRequirement(requirement)
} }
else if (descriptor.isSuspendOrHasSuspendTypesInSignature()) { if (descriptor.isSuspendOrHasSuspendTypesInSignature()) {
builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion()) builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion())
} }
@@ -380,7 +380,7 @@ class KonanDescriptorSerializer private constructor(
if (requirement != null) { if (requirement != null) {
builder.addAllVersionRequirement(requirement) builder.addAllVersionRequirement(requirement)
} }
else if (descriptor.isSuspendOrHasSuspendTypesInSignature()) { if (descriptor.isSuspendOrHasSuspendTypesInSignature()) {
builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion()) builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion())
} }
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.backend.konan.serialization package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
@@ -102,6 +104,9 @@ internal class KonanSerializerExtension(val context: Context, override val metad
return IrSerializer( return IrSerializer(
context, inlineDescriptorTable, stringTable, serializer, descriptor).serializeInlineBody() context, inlineDescriptorTable, stringTable, serializer, descriptor).serializeInlineBody()
} }
override fun releaseCoroutines(): Boolean =
context.config.configuration.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
} }
internal interface IrAwareExtension { internal interface IrAwareExtension {
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.backend.konan.KonanBackendContext
import org.jetbrains.kotlin.backend.konan.KonanCompilationException import org.jetbrains.kotlin.backend.konan.KonanCompilationException
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.irasdescriptors.* import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
@@ -50,6 +51,8 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.OverridingStrategy import org.jetbrains.kotlin.resolve.OverridingStrategy
import org.jetbrains.kotlin.resolve.OverridingUtil import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.calls.checkers.isRestrictsSuspensionReceiver
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
@@ -721,3 +724,17 @@ val IrType.isSimpleTypeWithQuestionMark: Boolean
fun IrClass.defaultOrNullableType(hasQuestionMark: Boolean) = fun IrClass.defaultOrNullableType(hasQuestionMark: Boolean) =
if (hasQuestionMark) this.defaultType.makeNullable() else this.defaultType if (hasQuestionMark) this.defaultType.makeNullable() else this.defaultType
fun FunctionDescriptor.createOverriddenDescriptor(owner: ClassDescriptor, final: Boolean = true): FunctionDescriptor {
return this.newCopyBuilder()
.setOwner(owner)
.setCopyOverrides(true)
.setModality(if (final) Modality.FINAL else Modality.OPEN)
.setDispatchReceiverParameter(owner.thisAsReceiverParameter)
.build()!!.apply {
overriddenDescriptors = listOf(this@createOverriddenDescriptor)
}
}
fun IrFunction.isRestrictedSuspendFunction(languageVersionSettings: LanguageVersionSettings): Boolean =
this.descriptor.extensionReceiverParameter?.type?.isRestrictsSuspensionReceiver(languageVersionSettings) == true
+7
View File
@@ -1329,16 +1329,19 @@ task coroutines_controlFlow_finally4(type: RunKonanTest) {
} }
task coroutines_controlFlow_finally5(type: RunKonanTest) { task coroutines_controlFlow_finally5(type: RunKonanTest) {
expectedFail = (project.testTarget == 'wasm32') // Uses exceptions.
goldValue = "s1\nf2\nfinally\n1\n" goldValue = "s1\nf2\nfinally\n1\n"
source = "codegen/coroutines/controlFlow_finally5.kt" source = "codegen/coroutines/controlFlow_finally5.kt"
} }
task coroutines_controlFlow_finally6(type: RunKonanTest) { task coroutines_controlFlow_finally6(type: RunKonanTest) {
expectedFail = (project.testTarget == 'wasm32') // Uses exceptions.
goldValue = "s1\nfinally\nerror\n0\n" goldValue = "s1\nfinally\nerror\n0\n"
source = "codegen/coroutines/controlFlow_finally6.kt" source = "codegen/coroutines/controlFlow_finally6.kt"
} }
task coroutines_controlFlow_finally7(type: RunKonanTest) { task coroutines_controlFlow_finally7(type: RunKonanTest) {
expectedFail = (project.testTarget == 'wasm32') // Uses exceptions.
goldValue = "s1\nf2\nfinally1\ns2\nfinally2\n42\n" goldValue = "s1\nf2\nfinally1\ns2\nfinally2\n42\n"
source = "codegen/coroutines/controlFlow_finally7.kt" source = "codegen/coroutines/controlFlow_finally7.kt"
} }
@@ -1364,21 +1367,25 @@ task coroutines_controlFlow_tryCatch1(type: RunKonanTest) {
} }
task coroutines_controlFlow_tryCatch2(type: RunKonanTest) { task coroutines_controlFlow_tryCatch2(type: RunKonanTest) {
expectedFail = (project.testTarget == 'wasm32') // Uses exceptions.
goldValue = "s1\n42\n" goldValue = "s1\n42\n"
source = "codegen/coroutines/controlFlow_tryCatch2.kt" source = "codegen/coroutines/controlFlow_tryCatch2.kt"
} }
task coroutines_controlFlow_tryCatch3(type: RunKonanTest) { task coroutines_controlFlow_tryCatch3(type: RunKonanTest) {
expectedFail = (project.testTarget == 'wasm32') // Uses exceptions.
goldValue = "s2\nf2\n1\n" goldValue = "s2\nf2\n1\n"
source = "codegen/coroutines/controlFlow_tryCatch3.kt" source = "codegen/coroutines/controlFlow_tryCatch3.kt"
} }
task coroutines_controlFlow_tryCatch4(type: RunKonanTest) { task coroutines_controlFlow_tryCatch4(type: RunKonanTest) {
expectedFail = (project.testTarget == 'wasm32') // Uses exceptions.
goldValue = "s2\nf2\n1\n" goldValue = "s2\nf2\n1\n"
source = "codegen/coroutines/controlFlow_tryCatch4.kt" source = "codegen/coroutines/controlFlow_tryCatch4.kt"
} }
task coroutines_controlFlow_tryCatch5(type: RunKonanTest) { task coroutines_controlFlow_tryCatch5(type: RunKonanTest) {
expectedFail = (project.testTarget == 'wasm32') // Uses exceptions.
goldValue = "s2\ns1\nError\n42\n" goldValue = "s2\ns1\nError\n42\n"
source = "codegen/coroutines/controlFlow_tryCatch5.kt" source = "codegen/coroutines/controlFlow_tryCatch5.kt"
} }
@@ -2,7 +2,7 @@ package codegen.controlflow.for_loops_coroutines
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
@Test fun runTest() { @Test fun runTest() {
val sq = buildSequence { val sq = buildSequence {
@@ -2,16 +2,15 @@ package codegen.coroutines.anonymousObject
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun suspendHere(): Int = suspendCoroutineOrReturn { x -> suspend fun suspendHere(): Int = suspendCoroutineUninterceptedOrReturn { x ->
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
} }
@@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_finally1
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_finally2
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_finally3
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_finally4
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_finally5
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resumeWithException(Error()) x.resumeWithException(Error())
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_finally6
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resumeWithException(Error("error")) x.resumeWithException(Error("error"))
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,22 +2,21 @@ package codegen.coroutines.controlFlow_finally7
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resumeWithException(Error()) x.resumeWithException(Error())
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
} }
suspend fun s2(): Int = suspendCoroutineOrReturn { x -> suspend fun s2(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s2") println("s2")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_if1
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_if2
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_inline1
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_inline2
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_inline3
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_tryCatch1
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_tryCatch2
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,22 +2,21 @@ package codegen.coroutines.controlFlow_tryCatch3
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
} }
suspend fun s2(): Int = suspendCoroutineOrReturn { x -> suspend fun s2(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s2") println("s2")
x.resumeWithException(Error()) x.resumeWithException(Error())
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,22 +2,21 @@ package codegen.coroutines.controlFlow_tryCatch4
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
} }
suspend fun s2(): Int = suspendCoroutineOrReturn { x -> suspend fun s2(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s2") println("s2")
x.resumeWithException(Error()) x.resumeWithException(Error())
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,22 +2,21 @@ package codegen.coroutines.controlFlow_tryCatch5
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
} }
suspend fun s2(): Int = suspendCoroutineOrReturn { x -> suspend fun s2(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s2") println("s2")
x.resumeWithException(Error("Error")) x.resumeWithException(Error("Error"))
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,28 +2,27 @@ package codegen.coroutines.controlFlow_while1
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
} }
suspend fun s2(): Int = suspendCoroutineOrReturn { x -> suspend fun s2(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s2") println("s2")
x.resumeWithException(Error("Error")) x.resumeWithException(Error("Error"))
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
} }
suspend fun s3(value: Int): Int = suspendCoroutineOrReturn { x -> suspend fun s3(value: Int): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s3") println("s3")
x.resume(value) x.resume(value)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,28 +2,27 @@ package codegen.coroutines.controlFlow_while2
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
} }
suspend fun s2(): Int = suspendCoroutineOrReturn { x -> suspend fun s2(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s2") println("s2")
x.resumeWithException(Error("Error")) x.resumeWithException(Error("Error"))
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
} }
suspend fun s3(value: Int): Int = suspendCoroutineOrReturn { x -> suspend fun s3(value: Int): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s3") println("s3")
x.resume(value) x.resume(value)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,13 +2,12 @@ package codegen.coroutines.coroutineContext1
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
fun builder(c: suspend () -> Unit) { fun builder(c: suspend () -> Unit) {
@@ -2,13 +2,12 @@ package codegen.coroutines.coroutineContext2
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
fun builder(c: suspend () -> Unit) { fun builder(c: suspend () -> Unit) {
@@ -2,16 +2,15 @@ package codegen.coroutines.correctOrder1
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Int = suspendCoroutineOrReturn { x -> suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,13 +2,12 @@ package codegen.coroutines.degenerate1
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1() { suspend fun s1() {
@@ -2,16 +2,15 @@ package codegen.coroutines.degenerate2
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Unit = suspendCoroutineOrReturn { x -> suspend fun s1(): Unit = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(Unit) x.resume(Unit)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,16 +2,15 @@ package codegen.coroutines.returnsUnit1
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun s1(): Unit = suspendCoroutineOrReturn { x -> suspend fun s1(): Unit = suspendCoroutineUninterceptedOrReturn { x ->
println("s1") println("s1")
x.resume(Unit) x.resume(Unit)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
@@ -2,16 +2,15 @@ package codegen.coroutines.simple
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
suspend fun suspendHere(): Int = suspendCoroutineOrReturn { x -> suspend fun suspendHere(): Int = suspendCoroutineUninterceptedOrReturn { x ->
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
} }
@@ -2,17 +2,16 @@ package codegen.coroutines.withReceiver
import kotlin.test.* import kotlin.test.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
class Controller { class Controller {
suspend fun suspendHere(): Int = suspendCoroutineOrReturn { x -> suspend fun suspendHere(): Int = suspendCoroutineUninterceptedOrReturn { x ->
x.resume(42) x.resume(42)
COROUTINE_SUSPENDED COROUTINE_SUSPENDED
} }
@@ -151,59 +151,47 @@ abstract class KonanTest extends JavaExec {
} }
void createCoroutineUtil(String file) { void createCoroutineUtil(String file) {
StringBuilder text = new StringBuilder("import kotlin.coroutines.experimental.*\n") StringBuilder text = new StringBuilder("import kotlin.coroutines.*\n")
text.append( text.append(
""" """
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
fun <T> handleResultContinuation(x: (T) -> Unit): Continuation<T> = object: Continuation<T> { fun <T> handleResultContinuation(x: (T) -> Unit): Continuation<T> = object: Continuation<T> {
override val context = EmptyCoroutineContext override val context = EmptyCoroutineContext
override fun resumeWithException(exception: Throwable) { override fun resumeWith(result: SuccessOrFailure<T>) { x(result.getOrThrow()) }
throw exception
}
override fun resume(data: T) = x(data)
} }
fun handleExceptionContinuation(x: (Throwable) -> Unit): Continuation<Any?> = object: Continuation<Any?> { fun handleExceptionContinuation(x: (Throwable) -> Unit): Continuation<Any?> = object: Continuation<Any?> {
override val context = EmptyCoroutineContext override val context = EmptyCoroutineContext
override fun resumeWithException(exception: Throwable) { override fun resumeWith(result: SuccessOrFailure<Any?>) {
val exception = result.exceptionOrNull() ?: return
x(exception) x(exception)
} }
override fun resume(data: Any?) { }
} }
""" ) """ )
createFile(file, text.toString()) createFile(file, text.toString())
} }
String createTextForHelpers() { String createTextForHelpers() {
def coroutinesPackage = "kotlin.coroutines.experimental" def coroutinesPackage = "kotlin.coroutines"
def emptyContinuationBody = def emptyContinuationBody =
""" """
|override fun resume(data: Any?) {} |override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
|override fun resumeWithException(exception: Throwable) { throw exception }
""".stripMargin() """.stripMargin()
def handleResultContinuationBody = """ def handleResultContinuationBody = """
|override fun resumeWithException(exception: Throwable) { |override fun resumeWith(result: SuccessOrFailure<T>) { x(result.getOrThrow()) }
| throw exception
|}
|
|override fun resume(data: T) = x(data)
""".stripMargin() """.stripMargin()
def handleExceptionContinuationBody = """ def handleExceptionContinuationBody = """
|override fun resumeWithException(exception: Throwable) { |override fun resumeWith(result: SuccessOrFailure<Any?>) {
| x(exception) | val exception = result.exceptionOrNull() ?: return
| x(exception)
|} |}
|
|override fun resume(data: Any?) {}
""".stripMargin() """.stripMargin()
return """ return """
@@ -228,6 +216,16 @@ fun handleExceptionContinuation(x: (Throwable) -> Unit): Continuation<Any?> = ob
| |
|abstract class ContinuationAdapter<in T> : Continuation<T> { |abstract class ContinuationAdapter<in T> : Continuation<T> {
| override val context: CoroutineContext = EmptyCoroutineContext | override val context: CoroutineContext = EmptyCoroutineContext
| override fun resumeWith(result: SuccessOrFailure<T>) {
| if (result.isSuccess) {
| resume(result.getOrThrow())
| } else {
| resumeWithException(result.exceptionOrNull()!!)
| }
| }
|
| abstract fun resumeWithException(exception: Throwable)
| abstract fun resume(value: T)
|} |}
""".stripMargin() """.stripMargin()
} }
@@ -741,7 +739,7 @@ class RunExternalTestGroup extends RunStandaloneKonanTest {
for (String filePath : result) { for (String filePath : result) {
def text = project.file(filePath).text def text = project.file(filePath).text
if (text.contains('COROUTINES_PACKAGE')) { if (text.contains('COROUTINES_PACKAGE')) {
text = text.replace('COROUTINES_PACKAGE', 'kotlin.coroutines.experimental') text = text.replace('COROUTINES_PACKAGE', 'kotlin.coroutines')
} }
def pkg = null def pkg = null
if (text =~ packagePattern) { if (text =~ packagePattern) {
@@ -0,0 +1,133 @@
/*
* Copyright 2010-2018 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.coroutines.native.internal
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.CoroutineSingletons
@SinceKotlin("1.3")
internal abstract class BaseContinuationImpl(
// This is `public val` so that it is private on JVM and cannot be modified by untrusted code, yet
// it has a public getter (since even untrusted code is allowed to inspect its call stack).
public val completion: Continuation<Any?>?
) : Continuation<Any?>, Serializable {
// This implementation is final. This fact is used to unroll resumeWith recursion.
public final override fun resumeWith(result: SuccessOrFailure<Any?>) {
// Invoke "resume" debug probe only once, even if previous frames are "resumed" in the loop below, too
probeCoroutineResumed(this)
// This loop unrolls recursion in current.resumeWith(param) to make saner and shorter stack traces on resume
var current = this
var param = result
while (true) {
with(current) {
val completion = completion!! // fail fast when trying to resume continuation without completion
val outcome: SuccessOrFailure<Any?> =
try {
val outcome = invokeSuspend(param)
if (outcome === CoroutineSingletons.COROUTINE_SUSPENDED) return
SuccessOrFailure.success(outcome)
} catch (exception: Throwable) {
SuccessOrFailure.failure(exception)
}
releaseIntercepted() // this state machine instance is terminating
if (completion is BaseContinuationImpl) {
// unrolling recursion via loop
current = completion
param = outcome
} else {
// top-level completion reached -- invoke and return
completion.resumeWith(outcome)
return
}
}
}
}
protected abstract fun invokeSuspend(result: SuccessOrFailure<Any?>): Any?
protected open fun releaseIntercepted() {
// does nothing here, overridden in ContinuationImpl
}
public open fun create(completion: Continuation<*>): Continuation<Unit> {
throw UnsupportedOperationException("create(Continuation) has not been overridden")
}
public open fun create(value: Any?, completion: Continuation<*>): Continuation<Unit> {
throw UnsupportedOperationException("create(Any?;Continuation) has not been overridden")
}
public override fun toString(): String {
// todo: how continuation shall be rendered?
return "Continuation @ ${this::class.simpleName}"
}
}
@SinceKotlin("1.3")
// State machines for named restricted suspend functions extend from this class
internal abstract class RestrictedContinuationImpl(
completion: Continuation<Any?>?
) : BaseContinuationImpl(completion) {
init {
completion?.let {
require(it.context === EmptyCoroutineContext) {
"Coroutines with restricted suspension must have EmptyCoroutineContext"
}
}
}
public override val context: CoroutineContext
get() = EmptyCoroutineContext
}
@SinceKotlin("1.3")
// State machines for named suspend functions extend from this class
internal abstract class ContinuationImpl(
completion: Continuation<Any?>?,
private val _context: CoroutineContext?
) : BaseContinuationImpl(completion) {
constructor(completion: Continuation<Any?>?) : this(completion, completion?.context)
public override val context: CoroutineContext
get() = _context!!
private var intercepted: Continuation<Any?>? = null
public fun intercepted(): Continuation<Any?> =
intercepted
?: (context[ContinuationInterceptor]?.interceptContinuation(this) ?: this)
.also { intercepted = it }
protected override fun releaseIntercepted() {
val intercepted = intercepted
if (intercepted != null && intercepted !== this) {
context[ContinuationInterceptor]!!.releaseInterceptedContinuation(intercepted)
}
this.intercepted = CompletedContinuation // just in case
}
}
internal object CompletedContinuation : Continuation<Any?> {
override val context: CoroutineContext
get() = error("This continuation is already complete")
override fun resumeWith(result: SuccessOrFailure<Any?>) {
error("This continuation is already complete")
}
override fun toString(): String = "This continuation is already complete"
}
@@ -0,0 +1,85 @@
/*
* Copyright 2010-2018 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.coroutines.native.internal
// TODO: support coroutines debugging in Kotlin/Native.
import kotlin.coroutines.Continuation
import kotlin.coroutines.intrinsics.*
/**
* This probe is invoked when coroutine is being created and it can replace completion
* with its own wrapped object to intercept completion of this coroutine.
*
* This probe is invoked from stdlib implementation of [createCoroutineUnintercepted] function.
*
* Once created, coroutine is repeatedly [resumed][probeCoroutineResumed] and [suspended][probeCoroutineSuspended],
* until it is complete. On completion, the object that was returned by this probe is invoked.
*
* ```
* +-------+ probeCoroutineCreated +-----------+
* | START | ---------------------->| SUSPENDED |
* +-------+ +-----------+
* probeCoroutineResumed | ^ probeCoroutineSuspended
* V |
* +------------+ completion invoked +-----------+
* | RUNNING | ------------------->| COMPLETED |
* +------------+ +-----------+
* ```
*
* While the coroutine is resumed and suspended, it is represented by the pointer to its `frame`
* which always extends [BaseContinuationImpl] and represents a pointer to the topmost frame of the
* coroutine. Each [BaseContinuationImpl] object has [completion][BaseContinuationImpl.completion] reference
* that points either to another frame (extending [BaseContinuationImpl]) or to the completion object
* that was returned by this `probeCoroutineCreated` function.
*
* When coroutine is [suspended][probeCoroutineSuspended], then it is later [resumed][probeCoroutineResumed]
* with a reference to the same frame. However, while coroutine is running it can unwind its frames and
* invoke other suspending functions, so its next suspension can happen with a different frame pointer.
*/
@SinceKotlin("1.3")
internal fun <T> probeCoroutineCreated(completion: Continuation<T>): Continuation<T> {
return completion
}
/**
* This probe is invoked when coroutine is resumed using [Continuation.resumeWith].
*
* This probe is invoked from stdlib implementation of [BaseContinuationImpl.resumeWith] function.
*
* Coroutines machinery implementation guarantees that the actual [frame] instance extends
* [BaseContinuationImpl] class, despite the fact that the declared type of [frame]
* parameter in this function is `Continuation<*>`. See [probeCoroutineCreated] for details.
*/
@SinceKotlin("1.3")
internal fun probeCoroutineResumed(frame: Continuation<*>) {
}
/**
* This probe is invoked when coroutine is suspended using [suspendCoroutineUninterceptedOrReturn], that is
* when the corresponding `block` returns [COROUTINE_SUSPENDED].
*
* This probe is invoked from compiler-generated intrinsic for [suspendCoroutineUninterceptedOrReturn] function.
*
* Coroutines machinery implementation guarantees that the actual [frame] instance extends
* [BaseContinuationImpl] class, despite the fact that the declared type of [frame]
* parameter in this function is `Continuation<*>`. See [probeCoroutineCreated] for details.
*/
@SinceKotlin("1.3")
internal fun probeCoroutineSuspended(frame: Continuation<*>) {
}
@@ -16,7 +16,9 @@
package kotlin.coroutines package kotlin.coroutines
// TODO: implement them right. import kotlin.*
import kotlin.coroutines.intrinsics.CoroutineSingletons.*
@PublishedApi @PublishedApi
@SinceKotlin("1.3") @SinceKotlin("1.3")
internal actual class SafeContinuation<in T> internal actual class SafeContinuation<in T>
@@ -24,14 +26,37 @@ internal actual constructor(
private val delegate: Continuation<T>, private val delegate: Continuation<T>,
initialResult: Any? initialResult: Any?
) : Continuation<T> { ) : Continuation<T> {
actual override val context: CoroutineContext
get() = TODO("unimplemented")
@PublishedApi @PublishedApi
internal actual constructor(delegate: Continuation<T>) : this(delegate, /*UNDECIDED*/ null) internal actual constructor(delegate: Continuation<T>) : this(delegate, UNDECIDED)
public actual override val context: CoroutineContext
get() = delegate.context
private var result: Any? = initialResult
public actual override fun resumeWith(result: SuccessOrFailure<T>) {
val cur = this.result
when {
cur === UNDECIDED -> this.result = result.value
cur === COROUTINE_SUSPENDED -> {
this.result = RESUMED
delegate.resumeWith(result)
}
else -> throw IllegalStateException("Already resumed")
}
}
@PublishedApi @PublishedApi
internal actual fun getOrThrow(): Any? = TODO("unimplemented") internal actual fun getOrThrow(): Any? {
val result = this.result
actual override fun resumeWith(result: SuccessOrFailure<T>):Unit = TODO("unimplemented") if (result === UNDECIDED) {
this.result = COROUTINE_SUSPENDED
return COROUTINE_SUSPENDED
}
return when {
result === RESUMED -> COROUTINE_SUSPENDED // already called continuation, indicate COROUTINE_SUSPENDED upstream
result is SuccessOrFailure.Failure -> throw result.exception
else -> result // either COROUTINE_SUSPENDED or data
}
}
} }
@@ -17,9 +17,6 @@
package kotlin.coroutines.experimental.intrinsics package kotlin.coroutines.experimental.intrinsics
import kotlin.coroutines.experimental.Continuation import kotlin.coroutines.experimental.Continuation
import kotlin.coroutines.experimental.CoroutineContext
import kotlin.coroutines.experimental.processBareContinuationResume
import kotlin.native.internal.*
/** /**
@@ -34,13 +31,7 @@ import kotlin.native.internal.*
*/ */
public actual fun <T> (suspend () -> T).createCoroutineUnchecked( public actual fun <T> (suspend () -> T).createCoroutineUnchecked(
completion: Continuation<T> completion: Continuation<T>
): Continuation<Unit> = ): Continuation<Unit> = errorExperimentalCoroutinesAreNoLongerSupported()
if (this !is CoroutineImpl)
buildContinuationByInvokeCall(completion) {
@Suppress("UNCHECKED_CAST") (this as Function1<Continuation<T>, Any?>).invoke(completion)
}
else
(this.create(completion) as CoroutineImpl).facade
/** /**
* Creates a coroutine with receiver type [R] and result type [T]. * Creates a coroutine with receiver type [R] and result type [T].
@@ -55,35 +46,7 @@ public actual fun <T> (suspend () -> T).createCoroutineUnchecked(
public actual fun <R, T> (suspend R.() -> T).createCoroutineUnchecked( public actual fun <R, T> (suspend R.() -> T).createCoroutineUnchecked(
receiver: R, receiver: R,
completion: Continuation<T> completion: Continuation<T>
): Continuation<Unit> = ): Continuation<Unit> = errorExperimentalCoroutinesAreNoLongerSupported()
if (this !is CoroutineImpl)
buildContinuationByInvokeCall(completion) {
@Suppress("UNCHECKED_CAST") (this as Function2<R, Continuation<T>, Any?>).invoke(receiver, completion)
}
else
(this.create(receiver, completion) as CoroutineImpl).facade
// INTERNAL DEFINITIONS
private inline fun <T> buildContinuationByInvokeCall(
completion: Continuation<T>,
crossinline block: () -> Any?
): Continuation<Unit> {
val continuation =
object : Continuation<Unit> {
override val context: CoroutineContext
get() = completion.context
override fun resume(value: Unit) {
processBareContinuationResume(completion, block)
}
override fun resumeWithException(exception: Throwable) {
completion.resumeWithException(exception)
}
}
return interceptContinuationIfNeeded(completion.context, continuation)
}
/** /**
* Starts unintercepted coroutine without receiver and with result type [T] and executes it until its first suspension. * Starts unintercepted coroutine without receiver and with result type [T] and executes it until its first suspension.
@@ -96,7 +59,7 @@ private inline fun <T> buildContinuationByInvokeCall(
@kotlin.internal.InlineOnly @kotlin.internal.InlineOnly
public actual inline fun <T> (suspend () -> T).startCoroutineUninterceptedOrReturn( public actual inline fun <T> (suspend () -> T).startCoroutineUninterceptedOrReturn(
completion: Continuation<T> completion: Continuation<T>
): Any? = (this as Function1<Continuation<T>, Any?>).invoke(completion) ): Any? = errorExperimentalCoroutinesAreNoLongerSupported()
/** /**
* Starts unintercepted coroutine with receiver type [R] and result type [T] and executes it until its first suspension. * Starts unintercepted coroutine with receiver type [R] and result type [T] and executes it until its first suspension.
@@ -110,7 +73,7 @@ public actual inline fun <T> (suspend () -> T).startCoroutineUninterceptedOrRetu
public actual inline fun <R, T> (suspend R.() -> T).startCoroutineUninterceptedOrReturn( public actual inline fun <R, T> (suspend R.() -> T).startCoroutineUninterceptedOrReturn(
receiver: R, receiver: R,
completion: Continuation<T> completion: Continuation<T>
): Any? = (this as Function2<R, Continuation<T>, Any?>).invoke(receiver, completion) ): Any? = errorExperimentalCoroutinesAreNoLongerSupported()
@@ -119,6 +82,8 @@ public actual inline fun <R, T> (suspend R.() -> T).startCoroutineUninterceptedO
* the execution was suspended and will not return any result immediately. * the execution was suspended and will not return any result immediately.
*/ */
@SinceKotlin("1.1") @SinceKotlin("1.1")
public actual val COROUTINE_SUSPENDED: Any = CoroutineSuspendedMarker public actual val COROUTINE_SUSPENDED: Any get() = errorExperimentalCoroutinesAreNoLongerSupported()
private object CoroutineSuspendedMarker @PublishedApi
internal fun errorExperimentalCoroutinesAreNoLongerSupported(): Nothing =
error("kotlin.coroutines.experimental is no longer supported, please migrate to kotlin.coroutines")
@@ -17,35 +17,178 @@
package kotlin.coroutines.intrinsics package kotlin.coroutines.intrinsics
import kotlin.coroutines.* import kotlin.coroutines.*
// TODO: implement them right. import kotlin.coroutines.native.internal.*
import kotlin.native.internal.*
/**
* Starts unintercepted coroutine without receiver and with result type [T] and executes it until its first suspension.
* Returns the result of the coroutine or throws its exception if it does not suspend or [COROUTINE_SUSPENDED] if it suspends.
* In the later case, the [completion] continuation is invoked when coroutine completes with result or exception.
* This function is designed to be used from inside of [suspendCoroutineOrReturn] to resume the execution of suspended
* coroutine using a reference to the suspending function.
*/
@Suppress("UNCHECKED_CAST")
@kotlin.internal.InlineOnly
public actual inline fun <T> (suspend () -> T).startCoroutineUninterceptedOrReturn( public actual inline fun <T> (suspend () -> T).startCoroutineUninterceptedOrReturn(
completion: Continuation<T> completion: Continuation<T>
): Any? { ): Any? = (this as Function1<Continuation<T>, Any?>).invoke(completion)
TODO("Unimplemented")
}
/**
* Starts unintercepted coroutine with receiver type [R] and result type [T] and executes it until its first suspension.
* Returns the result of the coroutine or throws its exception if it does not suspend or [COROUTINE_SUSPENDED] if it suspends.
* In the later case, the [completion] continuation is invoked when coroutine completes with result or exception.
* This function is designed to be used from inside of [suspendCoroutineOrReturn] to resume the execution of suspended
* coroutine using a reference to the suspending function.
*/
@Suppress("UNCHECKED_CAST")
@kotlin.internal.InlineOnly
public actual inline fun <R, T> (suspend R.() -> T).startCoroutineUninterceptedOrReturn( public actual inline fun <R, T> (suspend R.() -> T).startCoroutineUninterceptedOrReturn(
receiver: R, receiver: R,
completion: Continuation<T> completion: Continuation<T>
): Any? { ): Any? = (this as Function2<R, Continuation<T>, Any?>).invoke(receiver, completion)
TODO("Unimplemented")
}
private object CoroutineSuspendedMarker
/**
* Creates unintercepted coroutine without receiver and with result type [T].
* This function creates a new, fresh instance of suspendable computation every time it is invoked.
*
* To start executing the created coroutine, invoke `resume(Unit)` on the returned [Continuation] instance.
* The [completion] continuation is invoked when coroutine completes with result or exception.
*
* This function returns unintercepted continuation.
* Invocation of `resume(Unit)` starts coroutine immediately in the invoker's call stack without going through the
* [ContinuationInterceptor] that might be present in the completion's [CoroutineContext].
* It is invoker's responsibility to ensure that the proper invocation context is established.
* Note that [completion] of this function may get invoked in an arbitrary context.
*
* [Continuation.intercepted] can be used to acquire the intercepted continuation.
* Invocation of `resume(Unit)` on intercepted continuation guarantees that execution of
* both the coroutine and [completion] happens in the invocation context established by
* [ContinuationInterceptor].
*
* Repeated invocation of any resume function on the resulting continuation corrupts the
* state machine of the coroutine and may result in arbitrary behaviour or exception.
*/
@SinceKotlin("1.3") @SinceKotlin("1.3")
public actual fun <T> (suspend () -> T).createCoroutineUnintercepted( public actual fun <T> (suspend () -> T).createCoroutineUnintercepted(
completion: Continuation<T> completion: Continuation<T>
): Continuation<Unit> { ): Continuation<Unit> {
TODO("Unimplemented") val probeCompletion = probeCoroutineCreated(completion)
return if (this is BaseContinuationImpl)
create(probeCompletion)
else
createCoroutineFromSuspendFunction(probeCompletion) {
(this as Function1<Continuation<T>, Any?>).invoke(it)
}
} }
/**
* Creates unintercepted coroutine with receiver type [R] and result type [T].
* This function creates a new, fresh instance of suspendable computation every time it is invoked.
*
* To start executing the created coroutine, invoke `resume(Unit)` on the returned [Continuation] instance.
* The [completion] continuation is invoked when coroutine completes with result or exception.
*
* This function returns unintercepted continuation.
* Invocation of `resume(Unit)` starts coroutine immediately in the invoker's call stack without going through the
* [ContinuationInterceptor] that might be present in the completion's [CoroutineContext].
* It is invoker's responsibility to ensure that the proper invocation context is established.
* Note that [completion] of this function may get invoked in an arbitrary context.
*
* [Continuation.intercepted] can be used to acquire the intercepted continuation.
* Invocation of `resume(Unit)` on intercepted continuation guarantees that execution of
* both the coroutine and [completion] happens in the invocation context established by
* [ContinuationInterceptor].
*
* Repeated invocation of any resume function on the resulting continuation corrupts the
* state machine of the coroutine and may result in arbitrary behaviour or exception.
*/
@SinceKotlin("1.3") @SinceKotlin("1.3")
public actual fun <R, T> (suspend R.() -> T).createCoroutineUnintercepted( public actual fun <R, T> (suspend R.() -> T).createCoroutineUnintercepted(
receiver: R, receiver: R,
completion: Continuation<T> completion: Continuation<T>
): Continuation<Unit> { ): Continuation<Unit> {
TODO("Unimplemented") val probeCompletion = probeCoroutineCreated(completion)
return if (this is BaseContinuationImpl)
create(receiver, probeCompletion)
else {
createCoroutineFromSuspendFunction(probeCompletion) {
(this as Function2<R, Continuation<T>, Any?>).invoke(receiver, it)
}
}
} }
/**
* Intercepts this continuation with [ContinuationInterceptor].
*
* This function shall be used on the immediate result of [createCoroutineUnintercepted] or [suspendCoroutineUninterceptedOrReturn],
* in which case it checks for [ContinuationInterceptor] in the continuation's [context][Continuation.context],
* invokes [ContinuationInterceptor.interceptContinuation], caches and returns result.
*
* If this function is invoked on other [Continuation] instances it returns `this` continuation unchanged.
*/
@SinceKotlin("1.3") @SinceKotlin("1.3")
public actual fun <T> Continuation<T>.intercepted(): Continuation<T> = TODO("unimplemented") public actual fun <T> Continuation<T>.intercepted(): Continuation<T> =
(this as? ContinuationImpl)?.intercepted() ?: this
// INTERNAL DEFINITIONS
/**
* This function is used when [createCoroutineUnintercepted] encounters suspending lambda that does not extend BaseContinuationImpl.
*
* It happens in two cases:
* 1. Callable reference to suspending function,
* 2. Suspending function reference implemented by Java code.
*
* We must wrap it into an instance that extends [BaseContinuationImpl], because that is an expectation of all coroutines machinery.
* As an optimization we use lighter-weight [RestrictedContinuationImpl] base class (it has less fields) if the context is
* [EmptyCoroutineContext], and a full-blown [ContinuationImpl] class otherwise.
*
* The instance of [BaseContinuationImpl] is passed to the [block] so that it can be passed to the corresponding invocation.
*/
@SinceKotlin("1.3")
private inline fun <T> createCoroutineFromSuspendFunction(
completion: Continuation<T>,
crossinline block: (Continuation<T>) -> Any?
): Continuation<Unit> {
val context = completion.context
// label == 0 when coroutine is not started yet (initially) or label == 1 when it was
return if (context === EmptyCoroutineContext)
object : RestrictedContinuationImpl(completion as Continuation<Any?>) {
private var label = 0
override fun invokeSuspend(result: SuccessOrFailure<Any?>): Any? =
when (label) {
0 -> {
label = 1
result.getOrThrow() // Rethrow exception if trying to start with exception (will be caught by BaseContinuationImpl.resumeWith
block(this) // run the block, may return or suspend
}
1 -> {
label = 2
result.getOrThrow() // this is the result if the block had suspended
}
else -> error("This coroutine had already completed")
}
}
else
object : ContinuationImpl(completion as Continuation<Any?>, context) {
private var label = 0
override fun invokeSuspend(result: SuccessOrFailure<Any?>): Any? =
when (label) {
0 -> {
label = 1
result.getOrThrow() // Rethrow exception if trying to start with exception (will be caught by BaseContinuationImpl.resumeWith
block(this) // run the block, may return or suspend
}
1 -> {
label = 2
result.getOrThrow() // this is the result if the block had suspended
}
else -> error("This coroutine had already completed")
}
}
}
@@ -16,19 +16,14 @@
package kotlin.native.internal package kotlin.native.internal
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
@kotlin.internal.InlineOnly @kotlin.internal.InlineOnly
@PublishedApi @PublishedApi
internal inline suspend fun <T> suspendCoroutineUninterceptedOrReturn(crossinline block: (Continuation<T>) -> Any?): T = internal inline suspend fun <T> suspendCoroutineUninterceptedOrReturn(crossinline block: (Continuation<T>) -> Any?): T =
returnIfSuspended<T>(block(getContinuation<T>())) returnIfSuspended<T>(block(getContinuation<T>()))
@kotlin.internal.InlineOnly
@PublishedApi
internal inline fun <T> Continuation<T>.intercepted(): Continuation<T> =
normalizeContinuation<T>(this)
@Intrinsic @Intrinsic
@PublishedApi @PublishedApi
internal external fun <T> getContinuation(): Continuation<T> internal external fun <T> getContinuation(): Continuation<T>
@@ -41,65 +36,3 @@ internal inline suspend fun getCoroutineContext(): CoroutineContext =
@Intrinsic @Intrinsic
@PublishedApi @PublishedApi
internal external suspend fun <T> returnIfSuspended(@Suppress("UNUSED_PARAMETER") argument: Any?): T internal external suspend fun <T> returnIfSuspended(@Suppress("UNUSED_PARAMETER") argument: Any?): T
@ExportForCompiler
internal fun <T> interceptContinuationIfNeeded(
context: CoroutineContext,
continuation: Continuation<T>
) = context[ContinuationInterceptor]?.interceptContinuation(continuation) ?: continuation
/**
* @suppress
*/
@ExportForCompiler
@PublishedApi
internal fun <T> normalizeContinuation(continuation: Continuation<T>): Continuation<T> =
(continuation as? CoroutineImpl)?.facade ?: continuation
/**
* @suppress
*/
@ExportForCompiler
abstract internal class CoroutineImpl(
protected var completion: Continuation<Any?>?
) : Continuation<Any?> {
// label == -1 when coroutine cannot be started (it is just a factory object) or has already finished execution
// label == 0 in initial part of the coroutine
protected var label: NativePtr = if (completion != null) NativePtr.NULL else NativePtr.NULL + (-1L)
private val _context: CoroutineContext? = completion?.context
override val context: CoroutineContext
get() = _context!!
private var _facade: Continuation<Any?>? = null
val facade: Continuation<Any?> get() {
if (_facade == null) _facade = interceptContinuationIfNeeded(_context!!, this)
return _facade!!
}
override fun resume(value: Any?) {
processBareContinuationResume(completion!!) {
doResume(value, null)
}
}
override fun resumeWithException(exception: Throwable) {
processBareContinuationResume(completion!!) {
doResume(null, exception)
}
}
protected abstract fun doResume(data: Any?, exception: Throwable?): Any?
open fun create(completion: Continuation<*>): Continuation<Unit> {
throw IllegalStateException("create(Continuation) has not been overridden")
}
open fun create(value: Any?, completion: Continuation<*>): Continuation<Unit> {
throw IllegalStateException("create(Any?;Continuation) has not been overridden")
}
}
@@ -16,8 +16,8 @@
import kotlinx.cinterop.* import kotlinx.cinterop.*
import platform.posix.* import platform.posix.*
import kotlin.coroutines.experimental.* import kotlin.coroutines.*
import kotlin.coroutines.experimental.intrinsics.* import kotlin.coroutines.intrinsics.*
fun main(args: Array<String>) { fun main(args: Array<String>) {
if (args.size < 1) { if (args.size < 1) {
@@ -96,9 +96,8 @@ class Client(val clientFd: Int, val waitingList: MutableMap<Int, WaitingFor>) {
if (posix_errno() != EWOULDBLOCK) if (posix_errno() != EWOULDBLOCK)
throw IOException(getUnixError()) throw IOException(getUnixError())
// Save continuation and suspend. // Save continuation and suspend.
return suspendCoroutineOrReturn { continuation -> return suspendCoroutine { continuation ->
waitingList.put(clientFd, WaitingFor.Read(data, dataLength, continuation)) waitingList.put(clientFd, WaitingFor.Read(data, dataLength, continuation))
COROUTINE_SUSPENDED
} }
} }
@@ -109,17 +108,15 @@ class Client(val clientFd: Int, val waitingList: MutableMap<Int, WaitingFor>) {
if (posix_errno() != EWOULDBLOCK) if (posix_errno() != EWOULDBLOCK)
throw IOException(getUnixError()) throw IOException(getUnixError())
// Save continuation and suspend. // Save continuation and suspend.
return suspendCoroutineOrReturn { continuation -> return suspendCoroutine { continuation ->
waitingList.put(clientFd, WaitingFor.Write(data, length, continuation)) waitingList.put(clientFd, WaitingFor.Write(data, length, continuation))
COROUTINE_SUSPENDED
} }
} }
} }
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> { open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation() companion object : EmptyContinuation()
override fun resume(value: Any?) {} override fun resumeWith(result: SuccessOrFailure<Any?>) { result.getOrThrow() }
override fun resumeWithException(exception: Throwable) { throw exception }
} }
fun acceptClientsAndRun(serverFd: Int, block: suspend Client.() -> Unit) { fun acceptClientsAndRun(serverFd: Int, block: suspend Client.() -> Unit) {