[K/N] Use suspend function desugaring lowerings.
This commit is contained in:
committed by
Space Team
parent
8886e1b8b4
commit
817dba8564
@@ -20,6 +20,7 @@ interface Mapping {
|
||||
val capturedConstructors: Delegate<IrConstructor, IrConstructor>
|
||||
val reflectedNameAccessor: Delegate<IrClass, IrSimpleFunction>
|
||||
val suspendFunctionsToFunctionWithContinuations: Delegate<IrSimpleFunction, IrSimpleFunction>
|
||||
val functionWithContinuationsToSuspendFunctions: Delegate<IrSimpleFunction, IrSimpleFunction>
|
||||
|
||||
abstract class Delegate<K : IrDeclaration, V> {
|
||||
abstract operator fun get(key: K): V?
|
||||
@@ -77,6 +78,7 @@ open class DefaultMapping(delegateFactory: DelegateFactory = DefaultDelegateFact
|
||||
override val capturedConstructors: Mapping.Delegate<IrConstructor, IrConstructor> = delegateFactory.newDeclarationToDeclarationMapping()
|
||||
override val reflectedNameAccessor: Mapping.Delegate<IrClass, IrSimpleFunction> = delegateFactory.newDeclarationToDeclarationMapping()
|
||||
override val suspendFunctionsToFunctionWithContinuations: Mapping.Delegate<IrSimpleFunction, IrSimpleFunction> = delegateFactory.newDeclarationToDeclarationMapping()
|
||||
override val functionWithContinuationsToSuspendFunctions: Mapping.Delegate<IrSimpleFunction, IrSimpleFunction> = delegateFactory.newDeclarationToDeclarationMapping()
|
||||
}
|
||||
|
||||
fun <V : Any> KMutableProperty0<V?>.getOrPut(fn: () -> V) = this.get() ?: fn().also {
|
||||
|
||||
+5
-107
@@ -6,8 +6,6 @@
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.*
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName
|
||||
import org.jetbrains.kotlin.backend.common.ir.*
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
@@ -19,7 +17,6 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -33,9 +30,6 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
protected abstract val stateMachineMethodName: Name
|
||||
protected abstract fun getCoroutineBaseClass(function: IrFunction): IrClassSymbol
|
||||
protected abstract fun nameForCoroutineClass(function: IrFunction): Name
|
||||
protected abstract fun IrBuilderWithScope.launchSuspendFunctionWithGivenContinuation(
|
||||
symbol: IrSimpleFunctionSymbol, superQualifierSymbol: IrClassSymbol?, dispatchReceiver: IrExpression,
|
||||
arguments: List<IrExpression>, continuation: IrExpression) : IrExpression
|
||||
|
||||
protected abstract fun buildStateMachine(
|
||||
stateMachineFunction: IrFunction,
|
||||
@@ -57,106 +51,6 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
markSuspendLambdas(irFile)
|
||||
buildCoroutines(irFile)
|
||||
transformCallableReferencesToSuspendLambdas(irFile)
|
||||
addMissingSupertypesToSuspendFunctionImplementingClasses(irFile)
|
||||
}
|
||||
|
||||
private fun addMissingSupertypesToSuspendFunctionImplementingClasses(irFile: IrFile) {
|
||||
irFile.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
// Don't need to iterate through children. All local classes are already moved to the top level by this moment.
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
addMissingSupertypes(declaration)
|
||||
declaration.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
|
||||
private fun addMissingSupertypes(clazz: IrClass) {
|
||||
val suspendFunctionTypes = getAllSubstitutedSupertypes(clazz).filter {
|
||||
// SuspendFunction class is some hack in old Kotlin/Native compiler versions.
|
||||
// It's not used now, but is considered as SuspendFunction-like class in isSuspendFunction util,
|
||||
// if found in old klib. We need just to ignore it.
|
||||
it.isSuspendFunction() && it.classOrNull?.owner?.name?.toString() != "SuspendFunction"
|
||||
}.toSet()
|
||||
|
||||
for (suspendFunctionType in suspendFunctionTypes) {
|
||||
val suspendFunctionClassSymbol = suspendFunctionType.classOrNull ?: continue
|
||||
val suspendFunction = suspendFunctionClassSymbol.owner.simpleFunctions().single {
|
||||
it.name == OperatorNameConventions.INVOKE
|
||||
}
|
||||
|
||||
val invokeFunction = clazz.simpleFunctions().single {
|
||||
it.name == OperatorNameConventions.INVOKE && it.overrides(suspendFunction)
|
||||
}
|
||||
|
||||
if (invokeFunction.modality == Modality.ABSTRACT) {
|
||||
continue
|
||||
}
|
||||
|
||||
val suspendFunctionArity = suspendFunction.valueParameters.size
|
||||
val functionClassSymbol = symbols.functionN(suspendFunctionArity + 1)
|
||||
val functionSymbol = functionClassSymbol.owner.simpleFunctions().single {
|
||||
it.name == OperatorNameConventions.INVOKE
|
||||
}.symbol
|
||||
|
||||
val functionClassTypeArguments = suspendFunctionType.arguments.mapIndexed { index, argument ->
|
||||
val type = (argument as IrTypeProjection).type
|
||||
if (index == suspendFunctionArity) continuationClassSymbol.typeWith(type) else type
|
||||
} + context.irBuiltIns.anyNType
|
||||
|
||||
val functionType = functionClassSymbol.typeWith(functionClassTypeArguments)
|
||||
|
||||
clazz.superTypes += functionType
|
||||
|
||||
context.irFactory.buildFun {
|
||||
startOffset = SYNTHETIC_OFFSET
|
||||
endOffset = SYNTHETIC_OFFSET
|
||||
origin = DECLARATION_ORIGIN_COROUTINE_IMPL
|
||||
name = OperatorNameConventions.INVOKE
|
||||
visibility = DescriptorVisibilities.PROTECTED
|
||||
returnType = context.irBuiltIns.anyNType
|
||||
}.apply {
|
||||
parent = clazz
|
||||
clazz.declarations += this
|
||||
|
||||
typeParameters = invokeFunction.typeParameters.map { parameter ->
|
||||
parameter.copyToWithoutSuperTypes(this, origin = DECLARATION_ORIGIN_COROUTINE_IMPL)
|
||||
.apply { superTypes += parameter.superTypes }
|
||||
}
|
||||
|
||||
valueParameters = invokeFunction.valueParameters
|
||||
.mapIndexed { index, parameter ->
|
||||
parameter.copyTo(this, DECLARATION_ORIGIN_COROUTINE_IMPL, index)
|
||||
}
|
||||
valueParameters += buildValueParameter(this) {
|
||||
index = valueParameters.size
|
||||
type = context.irBuiltIns.anyNType
|
||||
name = "completion".synthesizedName
|
||||
}
|
||||
|
||||
this.createDispatchReceiverParameter()
|
||||
|
||||
overriddenSymbols += functionSymbol
|
||||
|
||||
val thisReceiver = dispatchReceiverParameter!!
|
||||
|
||||
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
|
||||
body = irBuilder.irBlockBody(startOffset, endOffset) {
|
||||
+irReturn(
|
||||
launchSuspendFunctionWithGivenContinuation(
|
||||
invokeFunction.symbol,
|
||||
superQualifierSymbol = invokeFunction.parentAsClass.symbol, // Call non-virtually.
|
||||
irGet(thisReceiver),
|
||||
valueParameters.dropLast(1).map { irGet(it) },
|
||||
irGet(valueParameters.last())
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun buildCoroutines(irFile: IrFile) {
|
||||
@@ -433,7 +327,9 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
)
|
||||
|
||||
val suspendInvokeFunction =
|
||||
suspendFunctionClass!!.simpleFunctions().single { it.name == OperatorNameConventions.INVOKE }
|
||||
suspendFunctionClass!!.simpleFunctions().single { it.name == OperatorNameConventions.INVOKE }.let {
|
||||
context.mapping.functionWithContinuationsToSuspendFunctions[it] ?: it
|
||||
}
|
||||
|
||||
buildInvokeMethod(
|
||||
functionInvokeFunction = suspendInvokeFunction,
|
||||
@@ -722,3 +618,5 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
private val CREATE_IDENTIFIER = Name.identifier("create")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -226,7 +226,7 @@ abstract class SingleAbstractMethodLowering(val context: CommonBackendContext) :
|
||||
body = context.createIrBuilder(symbol).irBlockBody {
|
||||
+irReturn(
|
||||
irCall(
|
||||
wrappedFunctionClass.functions.single { it.name == OperatorNameConventions.INVOKE }.symbol,
|
||||
getSuspendFunctionWithoutContinuation(wrappedFunctionClass.functions.single { it.name == OperatorNameConventions.INVOKE }).symbol,
|
||||
originalSuperMethod.returnType
|
||||
).apply {
|
||||
dispatchReceiver = irGetField(irGet(dispatchReceiverParameter!!), field)
|
||||
|
||||
+5
-3
@@ -88,12 +88,14 @@ private fun transformSuspendFunction(context: CommonBackendContext, function: Ir
|
||||
|
||||
fun IrSimpleFunction.getOrCreateFunctionWithContinuationStub(context: CommonBackendContext): IrSimpleFunction {
|
||||
return context.mapping.suspendFunctionsToFunctionWithContinuations.getOrPut(this) {
|
||||
createSuspendFunctionStub(context)
|
||||
createSuspendFunctionStub(context).also {
|
||||
context.mapping.functionWithContinuationsToSuspendFunctions[it] = this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.createSuspendFunctionStub(context: CommonBackendContext): IrSimpleFunction {
|
||||
require(this.isSuspend)
|
||||
require(this.isSuspend) { "$fqNameWhenAvailable should be a suspend function to create version with contunation" }
|
||||
return factory.buildFun {
|
||||
updateFrom(this@createSuspendFunctionStub)
|
||||
isSuspend = false
|
||||
@@ -103,9 +105,9 @@ private fun IrSimpleFunction.createSuspendFunctionStub(context: CommonBackendCon
|
||||
}.also { function ->
|
||||
function.parent = parent
|
||||
|
||||
function.annotations += annotations
|
||||
function.metadata = metadata
|
||||
|
||||
function.copyAnnotationsFrom(this)
|
||||
function.copyAttributes(this)
|
||||
function.copyTypeParametersFrom(this)
|
||||
val substitutionMap = makeTypeParameterSubstitutionMap(this, function)
|
||||
|
||||
+8
-2
@@ -2,6 +2,7 @@ package org.jetbrains.kotlin.backend.konan
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.*
|
||||
import org.jetbrains.kotlin.backend.common.lower.*
|
||||
import org.jetbrains.kotlin.backend.common.lower.coroutines.AddContinuationToNonLocalSuspendFunctionsLowering
|
||||
import org.jetbrains.kotlin.backend.common.lower.inline.FunctionInlining
|
||||
import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesExtractionFromInlineFunctionsLowering
|
||||
import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesInInlineFunctionsLowering
|
||||
@@ -383,8 +384,13 @@ internal val varargPhase = makeKonanFileLoweringPhase(
|
||||
prerequisite = setOf(functionReferencePhase, defaultParameterExtentPhase, interopPhase, functionsWithoutBoundCheck)
|
||||
)
|
||||
|
||||
internal val coroutinesPhase = makeKonanFileLoweringPhase(
|
||||
::NativeSuspendFunctionsLowering,
|
||||
internal val coroutinesPhase = makeKonanFileOpPhase(
|
||||
{ context, irFile ->
|
||||
NativeSuspendFunctionsLowering(context).lower(irFile)
|
||||
AddContinuationToNonLocalSuspendFunctionsLowering(context).lower(irFile)
|
||||
NativeAddContinuationToFunctionCallsLowering(context).lower(irFile)
|
||||
AddFunctionSupertypeToSuspendFunctionLowering(context).lower(irFile)
|
||||
},
|
||||
name = "Coroutines",
|
||||
description = "Coroutines lowering",
|
||||
prerequisite = setOf(localFunctionsPhase, finallyBlocksPhase, kotlinNothingValueExceptionPhase)
|
||||
|
||||
+9
-1
@@ -356,6 +356,7 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context) {
|
||||
val interfaceVTableEntries: List<IrSimpleFunction> by lazy {
|
||||
require(irClass.isInterface)
|
||||
irClass.simpleFunctions()
|
||||
.map { it.getLoweredVersion() }
|
||||
.filter { f ->
|
||||
f.isOverridable && f.bridgeTarget == null
|
||||
&& (f.isReal || f.overriddenSymbols.any { f.needBridgeTo(it.owner) })
|
||||
@@ -503,8 +504,15 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normally, function should be already replaced. But if the function come from LazyIr, it can be not replaced.
|
||||
*/
|
||||
fun IrSimpleFunction.getLoweredVersion() = context.mapping.suspendFunctionsToFunctionWithContinuations[this] ?: this
|
||||
|
||||
private val overridableOrOverridingMethods: List<IrSimpleFunction>
|
||||
get() = irClass.simpleFunctions().filter { it.isOverridableOrOverrides && it.bridgeTarget == null }
|
||||
get() = irClass.simpleFunctions()
|
||||
.map {it.getLoweredVersion() }
|
||||
.filter { it.isOverridableOrOverrides && it.bridgeTarget == null }
|
||||
|
||||
private val IrFunction.uniqueName get() = computeFunctionName()
|
||||
}
|
||||
|
||||
-2
@@ -324,8 +324,6 @@ internal class KonanSymbols(
|
||||
|
||||
override val returnIfSuspended = internalFunction("returnIfSuspended")
|
||||
|
||||
val coroutineLaunchpad = internalFunction("coroutineLaunchpad")
|
||||
|
||||
override val suspendCoroutineUninterceptedOrReturn = internalFunction("suspendCoroutineUninterceptedOrReturn")
|
||||
|
||||
private val coroutinesIntrinsicsPackage =
|
||||
|
||||
+1
-14
@@ -72,7 +72,6 @@ internal enum class IntrinsicType {
|
||||
// Coroutines
|
||||
GET_CONTINUATION,
|
||||
RETURN_IF_SUSPENDED,
|
||||
COROUTINE_LAUNCHPAD,
|
||||
// Interop
|
||||
INTEROP_READ_BITS,
|
||||
INTEROP_WRITE_BITS,
|
||||
@@ -160,6 +159,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
||||
* processes it. Otherwise it returns null.
|
||||
*/
|
||||
fun tryEvaluateSpecialCall(callSite: IrFunctionAccessExpression, resultSlot: LLVMValueRef?): LLVMValueRef? {
|
||||
resultSlot.let{}
|
||||
val function = callSite.symbol.owner
|
||||
if (!function.isTypedIntrinsic) {
|
||||
return null
|
||||
@@ -184,18 +184,6 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
||||
)
|
||||
codegen.theUnitInstanceRef.llvm
|
||||
}
|
||||
IntrinsicType.COROUTINE_LAUNCHPAD -> {
|
||||
val suspendFunctionCall = callSite.getValueArgument(0) as IrCall
|
||||
val continuation = environment.evaluateExpression(callSite.getValueArgument(1)!!, null)
|
||||
val suspendFunction = suspendFunctionCall.symbol.owner
|
||||
assert(suspendFunction.isSuspend) { "Call to a suspend function expected but was ${suspendFunction.dump()}" }
|
||||
environment.evaluateCall(suspendFunction,
|
||||
environment.evaluateExplicitArgs(suspendFunctionCall) + listOf(continuation),
|
||||
environment.calculateLifetime(suspendFunctionCall),
|
||||
suspendFunctionCall.superQualifierSymbol?.owner,
|
||||
resultSlot,
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@@ -270,7 +258,6 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
||||
reportNonLoweredIntrinsic(intrinsicType)
|
||||
IntrinsicType.INIT_INSTANCE,
|
||||
IntrinsicType.OBJC_INIT_BY,
|
||||
IntrinsicType.COROUTINE_LAUNCHPAD,
|
||||
IntrinsicType.OBJC_GET_SELECTOR,
|
||||
IntrinsicType.IMMUTABLE_BLOB ->
|
||||
reportSpecialIntrinsic(intrinsicType)
|
||||
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.coroutines.getOrCreateFunctionWithContinuationStub
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
/**
|
||||
* This lowering is a hack, to provide compatibility with leaked jvm implementation detail.
|
||||
*
|
||||
* On jvm SuspendFunctionN<Args, Ret> is implicitly implementing FunctionN+1<Args, Continuation, Any(?)>,
|
||||
* and visa versa, and it can be used for reusing continuation objects for performance improvements.
|
||||
*
|
||||
* Also, it is used in startCoroutineUninterceptedOrReturn intrinsic.
|
||||
*
|
||||
* So we are adding corresponding FunctionN+1 into supper types.
|
||||
* At the current point, lowered suspend function signature is overriding its invoke method.
|
||||
*
|
||||
*/
|
||||
internal class AddFunctionSupertypeToSuspendFunctionLowering(val context: Context) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
// Don't need to iterate through children. All local classes are already moved to the top level by this moment.
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
addMissingSupertypes(declaration)
|
||||
declaration.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.getLowered() = if (isSuspend)
|
||||
getOrCreateFunctionWithContinuationStub(context)
|
||||
else
|
||||
this
|
||||
|
||||
private fun IrClass.getInvokeFunction() = simpleFunctions().single {
|
||||
it.name == OperatorNameConventions.INVOKE
|
||||
}.getLowered()
|
||||
|
||||
private fun addOverride(clazz: IrClass, alreadyOverridden: IrType, toOverride: IrType) {
|
||||
val alreadyOverriddenFunction = alreadyOverridden.classOrNull!!.owner.getInvokeFunction()
|
||||
val functionToOverride = toOverride.classOrNull!!.owner.getInvokeFunction()
|
||||
val invokeFunction = clazz.simpleFunctions().single { it.overrides(alreadyOverriddenFunction) }
|
||||
if (invokeFunction.modality == Modality.ABSTRACT) return
|
||||
clazz.superTypes += toOverride
|
||||
invokeFunction.overriddenSymbols += functionToOverride.symbol
|
||||
}
|
||||
|
||||
|
||||
private fun addMissingSupertypes(clazz: IrClass) {
|
||||
val suspendFunctionSuperTypes = getAllSubstitutedSupertypes(clazz).filter {
|
||||
// SuspendFunction class is some hack in old Kotlin/Native compiler versions.
|
||||
// It's not used now, but is considered as SuspendFunction-like class in isSuspendFunction util,
|
||||
// if found in old klib. We need just to ignore it.
|
||||
it.isSuspendFunction() && it.classOrNull?.owner?.name?.toString() != "SuspendFunction"
|
||||
}.toSet()
|
||||
|
||||
val continuationClassSymbol = context.ir.symbols.continuationClass
|
||||
|
||||
fun IrSimpleType.getClassAt(index: Int) = (this.arguments.getOrNull(index) as? IrTypeProjection)?.type?.classOrNull
|
||||
|
||||
val functionWithContinuationSuperTypes = getAllSubstitutedSupertypes(clazz).filter {
|
||||
it.isFunction() &&
|
||||
it.getClassAt(it.arguments.size - 2) == continuationClassSymbol
|
||||
}.toSet()
|
||||
|
||||
for (suspendFunctionType in suspendFunctionSuperTypes) {
|
||||
val functionClassTypeArguments = suspendFunctionType.arguments.mapIndexed { index, argument ->
|
||||
val type = (argument as IrTypeProjection).type
|
||||
if (index == suspendFunctionType.arguments.indices.last) {
|
||||
continuationClassSymbol.typeWith(type)
|
||||
} else {
|
||||
type
|
||||
}
|
||||
} + context.irBuiltIns.anyNType
|
||||
|
||||
val functionType = context.ir.symbols.functionN(functionClassTypeArguments.size - 1).typeWith(functionClassTypeArguments)
|
||||
|
||||
addOverride(clazz, suspendFunctionType, functionType)
|
||||
}
|
||||
|
||||
for (functionType in functionWithContinuationSuperTypes) {
|
||||
val suspendFunctionClassTypeArguments = functionType.arguments.dropLast(1).mapIndexed { index, argument ->
|
||||
val type = (argument as IrTypeProjection).type
|
||||
if (index == functionType.arguments.indices.last - 1) {
|
||||
require(type.classOrNull == continuationClassSymbol)
|
||||
when (val typeArgument = (type as IrSimpleType).arguments.single()) {
|
||||
is IrTypeProjection -> typeArgument.type
|
||||
else -> context.irBuiltIns.anyNType
|
||||
}
|
||||
} else {
|
||||
type
|
||||
}
|
||||
}
|
||||
|
||||
val suspendFunctionType = context.ir.symbols.suspendFunctionN(suspendFunctionClassTypeArguments.size - 1).typeWith(suspendFunctionClassTypeArguments)
|
||||
addOverride(clazz, functionType, suspendFunctionType)
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
+5
-14
@@ -171,8 +171,6 @@ internal class FunctionReferenceLowering(val context: Context) : FileLoweringPas
|
||||
|
||||
private val irBuiltIns = context.irBuiltIns
|
||||
private val symbols = context.ir.symbols
|
||||
private val getContinuationSymbol = symbols.getContinuation
|
||||
private val continuationClassSymbol = getContinuationSymbol.owner.returnType.classifierOrFail as IrClassSymbol
|
||||
private val startOffset = functionReference.startOffset
|
||||
private val endOffset = functionReference.endOffset
|
||||
private val referencedFunction = functionReference.symbol.owner
|
||||
@@ -268,18 +266,8 @@ internal class FunctionReferenceLowering(val context: Context) : FileLoweringPas
|
||||
superTypes += suspendFunctionClass.typeWith(functionParameterAndReturnTypes)
|
||||
} else {
|
||||
functionClass = (if (isKFunction) symbols.kFunctionN(numberOfParameters) else symbols.functionN(numberOfParameters)).owner
|
||||
suspendFunctionClass = null
|
||||
superTypes += functionClass.typeWith(functionParameterAndReturnTypes)
|
||||
val lastParameterType = unboundFunctionParameters.lastOrNull()?.type
|
||||
if (lastParameterType?.classifierOrNull != continuationClassSymbol)
|
||||
suspendFunctionClass = null
|
||||
else {
|
||||
lastParameterType as IrSimpleType
|
||||
// If the last parameter is Continuation<> inherit from SuspendFunction.
|
||||
suspendFunctionClass = symbols.suspendFunctionN(numberOfParameters - 1).owner
|
||||
val suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) +
|
||||
(lastParameterType.arguments.single().typeOrNull ?: irBuiltIns.anyNType)
|
||||
superTypes += suspendFunctionClass.symbol.typeWith(suspendFunctionClassTypeParameters)
|
||||
}
|
||||
}
|
||||
|
||||
if (functionClass != null)
|
||||
@@ -440,7 +428,10 @@ internal class FunctionReferenceLowering(val context: Context) : FileLoweringPas
|
||||
return false
|
||||
}
|
||||
|
||||
private fun buildInvokeMethod(superFunction: IrSimpleFunction): IrSimpleFunction {
|
||||
private fun buildInvokeMethod(superFunction: IrSimpleFunction) =
|
||||
buildInvokeMethodImpl(context.mapping.functionWithContinuationsToSuspendFunctions[superFunction] ?: superFunction)
|
||||
|
||||
private fun buildInvokeMethodImpl(superFunction: IrSimpleFunction): IrSimpleFunction {
|
||||
return IrFunctionImpl(
|
||||
startOffset, endOffset,
|
||||
DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.lower.coroutines.AbstractAddContinuationToFunctionCallsLowering
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.util.overrides
|
||||
|
||||
internal class NativeAddContinuationToFunctionCallsLowering(override val context: Context) : AbstractAddContinuationToFunctionCallsLowering() {
|
||||
/*
|
||||
* In complex cases suspend functions are converted to state-machine class with invokeSuspend method.
|
||||
* In that case continuation is an object itself
|
||||
* In simple cases, function is left as is, and receives continuation as its last parameter
|
||||
* We should handle both cases here
|
||||
*/
|
||||
override fun IrSimpleFunction.getContinuationParameter() = when {
|
||||
overrides(context.ir.symbols.invokeSuspendFunction.owner) -> dispatchReceiverParameter!!
|
||||
else -> {
|
||||
valueParameters.lastOrNull().also {
|
||||
require(origin == IrDeclarationOrigin.LOWERED_SUSPEND_FUNCTION) { "Continuation parameter only exists in lowered suspend functions, but function origin is $origin" }
|
||||
require(it != null && it.origin == IrDeclarationOrigin.CONTINUATION) { "Continuation parameter is expected to be last one" }
|
||||
}!!
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.ScopeWithIr
|
||||
import org.jetbrains.kotlin.backend.common.lower.SingleAbstractMethodLowering
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
@@ -24,4 +25,8 @@ internal class NativeSingleAbstractMethodLowering(context: Context) : SingleAbst
|
||||
}
|
||||
|
||||
override val IrType.needEqualsHashCodeMethods get() = true
|
||||
|
||||
override fun getSuspendFunctionWithoutContinuation(function: IrSimpleFunction) = function.let {
|
||||
context.mapping.functionWithContinuationsToSuspendFunctions[it] ?: it
|
||||
}
|
||||
}
|
||||
-13
@@ -59,19 +59,6 @@ internal class NativeSuspendFunctionsLowering(ctx: Context): AbstractSuspendFunc
|
||||
}
|
||||
|
||||
|
||||
override fun IrBuilderWithScope.launchSuspendFunctionWithGivenContinuation(
|
||||
symbol: IrSimpleFunctionSymbol, superQualifierSymbol: IrClassSymbol?, dispatchReceiver: IrExpression,
|
||||
arguments: List<IrExpression>, continuation: IrExpression
|
||||
) = irCall(this@NativeSuspendFunctionsLowering.context.ir.symbols.coroutineLaunchpad).apply {
|
||||
putValueArgument(0, irCall(symbol.owner, superQualifierSymbol = superQualifierSymbol).apply {
|
||||
this.dispatchReceiver = dispatchReceiver
|
||||
arguments.forEachIndexed { index, irExpression ->
|
||||
putValueArgument(index, irExpression)
|
||||
}
|
||||
})
|
||||
putValueArgument(1, continuation)
|
||||
}
|
||||
|
||||
override fun buildStateMachine(stateMachineFunction: IrFunction,
|
||||
transformingFunction: IrFunction,
|
||||
argumentToPropertiesMap: Map<IrValueParameter, IrField>) {
|
||||
|
||||
-5
@@ -714,11 +714,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
||||
is IrCall -> when (value.symbol) {
|
||||
getContinuationSymbol -> continuationOverride ?: getContinuation().value
|
||||
|
||||
symbols.coroutineLaunchpad -> getNode(
|
||||
value.getValueArgument(0)!!,
|
||||
continuationOverride = expressionToEdge(value.getValueArgument(1)!!).node
|
||||
).value
|
||||
|
||||
in arrayGetSymbols -> {
|
||||
val actualCallee = value.actualCallee
|
||||
|
||||
|
||||
-3
@@ -234,7 +234,6 @@ internal object FileInitializersOptimization {
|
||||
}
|
||||
|
||||
private val executeImplSymbol = context.ir.symbols.executeImpl
|
||||
private val coroutineLaunchpadSymbol = context.ir.symbols.coroutineLaunchpad
|
||||
private val getContinuationSymbol = context.ir.symbols.getContinuation
|
||||
|
||||
private var dummySet = mutableSetOf<IrFunctionAccessExpression>()
|
||||
@@ -506,8 +505,6 @@ internal object FileInitializersOptimization {
|
||||
return processExecuteImpl(expression, data)
|
||||
if (expression.symbol == getContinuationSymbol)
|
||||
return data
|
||||
if (expression.symbol == coroutineLaunchpadSymbol)
|
||||
return processCoroutineLaunchpad(expression, data)
|
||||
if (!expression.isVirtualCall)
|
||||
return processCall(expression, expression.actualCallee, data)
|
||||
val devirtualizedCallSite = virtualCallSites[expression] ?: return data
|
||||
|
||||
+33
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
package codegen.function.unreachable_statement_after_return
|
||||
import kotlin.coroutines.*
|
||||
|
||||
fun test1(): Any? {
|
||||
return 1
|
||||
@@ -25,10 +26,42 @@ fun test4(): Int {
|
||||
42
|
||||
}
|
||||
|
||||
suspend fun test5(): Any? {
|
||||
return 5
|
||||
42
|
||||
}
|
||||
|
||||
suspend fun test6(): Int? {
|
||||
return 6
|
||||
42
|
||||
}
|
||||
|
||||
suspend fun test7(): Any {
|
||||
return 7
|
||||
42
|
||||
}
|
||||
|
||||
suspend fun test8(): Int {
|
||||
return 8
|
||||
42
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun <T> (suspend () -> T).runCoroutine() : T {
|
||||
var result : Any? = null
|
||||
startCoroutine(Continuation(EmptyCoroutineContext) { result = it.getOrThrow() })
|
||||
return result as T
|
||||
}
|
||||
|
||||
fun main() {
|
||||
println(test1())
|
||||
println(test2())
|
||||
println(test3())
|
||||
println(test4())
|
||||
|
||||
println(::test5.runCoroutine())
|
||||
println(::test6.runCoroutine())
|
||||
println(::test7.runCoroutine())
|
||||
println(::test8.runCoroutine())
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -2,3 +2,7 @@
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
|
||||
@@ -25,6 +25,3 @@ internal inline suspend fun getCoroutineContext(): CoroutineContext =
|
||||
@TypedIntrinsic(IntrinsicType.RETURN_IF_SUSPENDED)
|
||||
@PublishedApi
|
||||
internal external suspend fun <T> returnIfSuspended(@Suppress("UNUSED_PARAMETER") argument: Any?): T
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.COROUTINE_LAUNCHPAD)
|
||||
internal external fun coroutineLaunchpad(suspendFunctionCall: Any?, continuation: Continuation<*>): Any?
|
||||
@@ -61,7 +61,6 @@ class IntrinsicType {
|
||||
// Coroutines
|
||||
const val GET_CONTINUATION = "GET_CONTINUATION"
|
||||
const val RETURN_IF_SUSPENDED = "RETURN_IF_SUSPENDED"
|
||||
const val COROUTINE_LAUNCHPAD = "COROUTINE_LAUNCHPAD"
|
||||
|
||||
// Interop
|
||||
const val INTEROP_READ_PRIMITIVE = "INTEROP_READ_PRIMITIVE"
|
||||
|
||||
Reference in New Issue
Block a user