Coroutines lowering

This commit is contained in:
Igor Chevdar
2017-04-27 17:04:03 +03:00
parent 7f9c5e5c8b
commit bd6a091088
16 changed files with 1348 additions and 68 deletions
@@ -200,6 +200,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: DeclarationDe
/* visibility = */ oldDescriptor.visibility
)
isTailrec = oldDescriptor.isTailrec
isSuspend = oldDescriptor.isSuspend
overriddenDescriptors += oldDescriptor.overriddenDescriptors
}
}
@@ -16,10 +16,11 @@
package org.jetbrains.kotlin.backend.common.descriptors
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.coroutines.isSuspendLambda
import org.jetbrains.kotlin.descriptors.*
internal val CallableDescriptor.isSuspend: Boolean
get() = this is FunctionDescriptor && isSuspend
/**
* @return naturally-ordered list of all parameters available inside the function body.
@@ -21,10 +21,7 @@ import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
@@ -456,6 +453,7 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
oldDescriptor.source
).apply {
isTailrec = oldDescriptor.isTailrec
isSuspend = oldDescriptor.isSuspend
// TODO: copy other properties or consider using `FunctionDescriptor.CopyBuilder`.
}
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.konan.util.atMostOne
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.ir.IrElement
@@ -138,11 +139,17 @@ fun computeOverrides(current: ClassDescriptor, functionsFromCurrent: List<Callab
class SimpleMemberScope(val members: List<DeclarationDescriptor>) : MemberScopeImpl() {
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = TODO()
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? =
members.filterIsInstance<ClassifierDescriptor>()
.atMostOne { it.name == name }
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> = TODO()
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> =
members.filterIsInstance<PropertyDescriptor>()
.filter { it.name == name }
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<SimpleFunctionDescriptor> = TODO()
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<SimpleFunctionDescriptor> =
members.filterIsInstance<SimpleFunctionDescriptor>()
.filter { it.name == name }
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> =
@@ -88,11 +88,11 @@ internal class SpecialDescriptorsFactory(val context: Context) {
val bridgeDirections = overriddenFunctionDescriptor.bridgeDirections
return bridgesDescriptors.getOrPut(descriptor to bridgeDirections) {
SimpleFunctionDescriptorImpl.create(
descriptor.containingDeclaration,
Annotations.EMPTY,
("<bridge-" + bridgeDirections.toString() + ">" + descriptor.functionName).synthesizedName,
CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE).apply {
/* containingDeclaration = */ descriptor.containingDeclaration,
/* annotations = */ Annotations.EMPTY,
/* name = */ "<bridge-$bridgeDirections>${descriptor.functionName}".synthesizedName,
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE).apply {
initializeBridgeDescriptor(this, descriptor, bridgeDirections.array)
}
}
@@ -120,31 +120,34 @@ internal class SpecialDescriptorsFactory(val context: Context) {
BridgeDirection.FROM_VALUE_TYPE -> context.builtIns.anyType
}
val valueParameters = descriptor.valueParameters.mapIndexed { index, valueParameterDescriptor ->
when (bridgeDirections[index + 2]) {
BridgeDirection.TO_VALUE_TYPE -> valueParameterDescriptor
BridgeDirection.NOT_NEEDED -> valueParameterDescriptor
BridgeDirection.FROM_VALUE_TYPE -> ValueParameterDescriptorImpl(
containingDeclaration = valueParameterDescriptor.containingDeclaration,
original = null,
index = index,
annotations = Annotations.EMPTY,
name = valueParameterDescriptor.name,
outType = context.builtIns.anyType,
declaresDefaultValue = valueParameterDescriptor.declaresDefaultValue(),
isCrossinline = valueParameterDescriptor.isCrossinline,
isNoinline = valueParameterDescriptor.isNoinline,
varargElementType = valueParameterDescriptor.varargElementType,
source = SourceElement.NO_SOURCE)
}
}
bridgeDescriptor.initialize(
extensionReceiverType,
descriptor.dispatchReceiverParameter,
descriptor.typeParameters,
descriptor.valueParameters.mapIndexed { index, valueParameterDescriptor ->
when (bridgeDirections[index + 2]) {
BridgeDirection.TO_VALUE_TYPE -> valueParameterDescriptor
BridgeDirection.NOT_NEEDED -> valueParameterDescriptor
BridgeDirection.FROM_VALUE_TYPE -> ValueParameterDescriptorImpl(
valueParameterDescriptor.containingDeclaration,
null,
index,
Annotations.EMPTY,
valueParameterDescriptor.name,
context.builtIns.anyType,
valueParameterDescriptor.declaresDefaultValue(),
valueParameterDescriptor.isCrossinline,
valueParameterDescriptor.isNoinline,
valueParameterDescriptor.varargElementType,
SourceElement.NO_SOURCE)
}
},
returnType,
descriptor.modality,
descriptor.visibility)
/* receiverParameterType = */ extensionReceiverType,
/* dispatchReceiverParameter = */ descriptor.dispatchReceiverParameter,
/* typeParameters = */ descriptor.typeParameters,
/* unsubstitutedValueParameters = */ valueParameters,
/* unsubstitutedReturnType = */ returnType,
/* modality = */ descriptor.modality,
/* visibility = */ descriptor.visibility).apply {
isSuspend = descriptor.isSuspend
}
}
}
@@ -62,9 +62,6 @@ internal class KonanLower(val context: Context) {
phaser.phase(KonanPhase.LOWER_DELEGATION) {
PropertyDelegationLowering(context).lower(irFile)
}
phaser.phase(KonanPhase.LOWER_TYPE_OPERATORS) {
TypeOperatorLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.LOWER_LOCAL_FUNCTIONS) {
LocalDeclarationsLowering(context).runOnFilePostfix(irFile)
}
@@ -93,6 +90,12 @@ internal class KonanLower(val context: Context) {
phaser.phase(KonanPhase.LOWER_VARARG) {
VarargInjectionLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.LOWER_COROUTINES) {
SuspendFunctionsLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.LOWER_TYPE_OPERATORS) {
TypeOperatorLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.BRIDGES_BUILDING) {
BridgesBuilding(context).runOnFilePostfix(irFile)
DirectBridgesCallsLowering(context).runOnFilePostfix(irFile)
@@ -44,10 +44,11 @@ enum class KonanPhase(val description: String,
/* ... ... */ LOWER_INNER_CLASSES("Inner classes lowering", LOWER_DEFAULT_PARAMETER_EXTENT),
/* ... ... */ LOWER_LATEINIT("Lateinit properties lowering"),
/* ... ... */ LOWER_BUILTIN_OPERATORS("BuiltIn Operators Lowering", LOWER_DEFAULT_PARAMETER_EXTENT, LOWER_LATEINIT),
/* ... ... */ LOWER_TYPE_OPERATORS("Type operators lowering"),
/* ... ... */ BRIDGES_BUILDING("Bridges building"),
/* ... ... */ LOWER_COROUTINES("Coroutines lowering", LOWER_LOCAL_FUNCTIONS),
/* ... ... */ LOWER_TYPE_OPERATORS("Type operators lowering", LOWER_COROUTINES),
/* ... ... */ BRIDGES_BUILDING("Bridges building", LOWER_COROUTINES),
/* ... ... */ LOWER_STRING_CONCAT("String concatenation lowering"),
/* ... ... */ AUTOBOX("Autoboxing of primitive types", BRIDGES_BUILDING),
/* ... ... */ AUTOBOX("Autoboxing of primitive types", BRIDGES_BUILDING, LOWER_COROUTINES),
/* ... */ BITCODE("LLVM BitCode Generation"),
/* ... ... */ RTTI("RTTI Generation"),
/* ... ... */ CODEGEN("Code Generation"),
@@ -202,7 +202,7 @@ fun ClassDescriptor.isAbstract() = this.modality == Modality.SEALED || this.moda
internal fun FunctionDescriptor.hasValueTypeAt(index: Int): Boolean {
when (index) {
0 -> return returnType.let { it != null && it.isValueType() }
0 -> return !isSuspend && returnType.let { it != null && it.isValueType() }
1 -> return extensionReceiverParameter.let { it != null && it.type.isValueType() }
else -> return this.valueParameters[index - 2].type.isValueType()
}
@@ -210,7 +210,7 @@ internal fun FunctionDescriptor.hasValueTypeAt(index: Int): Boolean {
internal fun FunctionDescriptor.hasReferenceAt(index: Int): Boolean {
when (index) {
0 -> return returnType.let { it != null && !it.isValueType() }
0 -> return isSuspend || returnType.let { it != null && !it.isValueType() }
1 -> return extensionReceiverParameter.let { it != null && !it.type.isValueType() }
else -> return !this.valueParameters[index - 2].type.isValueType()
}
@@ -51,15 +51,7 @@ fun ir2stringWhole(ir: IrElement?, withDescriptors: Boolean = false): String {
internal fun DeclarationDescriptor.createFakeOverrideDescriptor(owner: ClassDescriptor): DeclarationDescriptor? {
// We need to copy descriptors for vtable building, thus take only functions and properties.
return when (this) {
is FunctionDescriptor ->
newCopyBuilder()
.setOwner(owner)
.setKind(CallableMemberDescriptor.Kind.FAKE_OVERRIDE)
.setCopyOverrides(true)
.build()!!.apply {
overriddenDescriptors += this@createFakeOverrideDescriptor
}
is PropertyDescriptor ->
is CallableMemberDescriptor ->
copy(
/* newOwner = */ owner,
/* modality = */ modality,
@@ -72,6 +64,17 @@ internal fun DeclarationDescriptor.createFakeOverrideDescriptor(owner: ClassDesc
}
}
internal 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 += this@createOverriddenDescriptor
}
}
internal fun ClassDescriptor.createSimpleDelegatingConstructorDescriptor(superConstructorDescriptor: ClassConstructorDescriptor, isPrimary: Boolean = false)
: ClassConstructorDescriptor {
val constructorDescriptor = ClassConstructorDescriptorImpl.createSynthesized(
@@ -18,9 +18,12 @@ package org.jetbrains.kotlin.backend.konan.ir
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.IrBlock
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.expressions.impl.IrContainerExpressionBase
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBase
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
@@ -50,3 +53,53 @@ class IrInlineFunctionBody(startOffset: Int, endOffset: Int, type: KotlinType, v
//-----------------------------------------------------------------------------//
interface IrSuspensionPoint : IrExpression {
var suspensionPointIdParameter: IrVariable
var result: IrExpression
var resumeResult: IrExpression
}
interface IrSuspendableExpression : IrExpression {
var suspensionPointId: IrExpression
var result: IrExpression
}
class IrSuspensionPointImpl(startOffset: Int, endOffset: Int, type: KotlinType,
override var suspensionPointIdParameter: IrVariable,
override var result: IrExpression,
override var resumeResult: IrExpression)
: IrExpressionBase(startOffset, endOffset, type), IrSuspensionPoint {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitExpression(this, data)
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
suspensionPointIdParameter.accept(visitor, data)
result.accept(visitor, data)
resumeResult.accept(visitor, data)
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
suspensionPointIdParameter = suspensionPointIdParameter.transform(transformer, data) as IrVariable
result = result.transform(transformer, data)
resumeResult = resumeResult.transform(transformer, data)
}
}
class IrSuspendableExpressionImpl(startOffset: Int, endOffset: Int, type: KotlinType,
override var suspensionPointId: IrExpression, override var result: IrExpression)
: IrExpressionBase(startOffset, endOffset, type), IrSuspendableExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitExpression(this, data)
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
suspensionPointId.accept(visitor, data)
result.accept(visitor, data)
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
suspensionPointId = suspensionPointId.transform(transformer, data)
result = result.transform(transformer, data)
}
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.AbstractValueUsageTransformer
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.isSuspend
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.ValueType
import org.jetbrains.kotlin.backend.konan.descriptors.*
@@ -25,7 +26,9 @@ import org.jetbrains.kotlin.backend.konan.notNullableIsRepresentedAs
import org.jetbrains.kotlin.backend.konan.isRepresentedAs
import org.jetbrains.kotlin.backend.konan.util.atMostOne
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
@@ -123,6 +126,23 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
}
}
private var currentFunctionDescriptor: FunctionDescriptor? = null
override fun visitFunction(declaration: IrFunction): IrStatement {
currentFunctionDescriptor = declaration.descriptor
val result = super.visitFunction(declaration)
currentFunctionDescriptor = null
return result
}
override fun IrExpression.useAsReturnValue(returnTarget: CallableDescriptor): IrExpression {
if (returnTarget.isSuspend && returnTarget == currentFunctionDescriptor)
return this.useAs(context.builtIns.nullableAnyType)
val returnType = returnTarget.returnType
?: return this
return this.useAs(returnType)
}
override fun IrExpression.useAs(type: KotlinType): IrExpression {
val interop = context.interopBuiltIns
if (this.isNullConst() && interop.nullableInteropValueTypes.any { type.isRepresentedAs(it) }) {
@@ -130,7 +150,10 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
}
val actualType = when (this) {
is IrCall -> this.descriptor.original.returnType ?: this.type
is IrCall -> {
if (this.descriptor.isSuspend) context.builtIns.nullableAnyType
else this.descriptor.original.returnType ?: this.type
}
is IrGetField -> this.descriptor.original.type
is IrTypeOperatorCall -> when (this.operator) {
@@ -410,6 +410,7 @@ private fun FunctionDescriptor.generateDefaultsDescription(context: Context): Fu
/* unsubstitutedReturnType = */ returnType,
/* modality = */ Modality.FINAL,
/* visibility = */ this.visibility)
descriptor.isSuspend = this.isSuspend
context.log{"adds to cache[$this] = $descriptor"}
descriptor
}
@@ -27,17 +27,13 @@ import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke
import org.jetbrains.kotlin.backend.konan.descriptors.needsInlining
import org.jetbrains.kotlin.backend.konan.ir.DeserializerDriver
import org.jetbrains.kotlin.backend.konan.ir.IrInlineFunctionBody
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrMemberAccessExpressionBase
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
@@ -3,6 +3,14 @@ package konan.internal
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
@Intrinsic
@PublishedApi
internal fun <T> getContinuation(): Continuation<T> = throw AssertionError("Call to getContinuation should've been lowered")
@Intrinsic
@PublishedApi
internal fun <T> returnIfSuspended(value: Any?): T = throw AssertionError("Call to returnIfSuspended should've been lowered")
// Single-threaded continuation.
class SafeContinuation<in T>
constructor(
@@ -67,6 +75,7 @@ internal fun <T> interceptContinuationIfNeeded(
* @suppress
*/
@ExportForCompiler
@PublishedApi
internal fun <T> normalizeContinuation(continuation: Continuation<T>): Continuation<T> =
(continuation as? CoroutineImpl)?.facade ?: continuation
@@ -80,7 +89,8 @@ abstract internal class CoroutineImpl(
// 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: Int = if (completion != null) 0L else -1L
// TODO: use IntPtr.
protected var label: Long = if (completion != null) 0L else -1L
private val _context: CoroutineContext? = completion?.context
@@ -19,8 +19,7 @@ package kotlin.coroutines.experimental.intrinsics
import kotlin.coroutines.experimental.Continuation
import kotlin.coroutines.experimental.CoroutineContext
import kotlin.coroutines.experimental.processBareContinuationResume
import konan.internal.interceptContinuationIfNeeded
import konan.internal.CoroutineImpl
import konan.internal.*
/**
* Obtains the current continuation instance inside suspend functions and either suspend
@@ -40,7 +39,8 @@ import konan.internal.CoroutineImpl
* continuation instance.
*/
@kotlin.internal.InlineOnly
public inline suspend fun <T> suspendCoroutineOrReturn(crossinline block: (Continuation<T>) -> Any?): T = throw Error("Should've been intrinsified")
public inline suspend fun <T> suspendCoroutineOrReturn(crossinline block: (Continuation<T>) -> Any?): T =
returnIfSuspended<T>(block(normalizeContinuation<T>(getContinuation<T>())))
/**
* This value is used as a return value of [suspendCoroutineOrReturn] `block` argument to state that