Rewrote coroutines lowering to use symbols

This commit is contained in:
Igor Chevdar
2017-05-16 16:33:17 +03:00
parent 827f92305c
commit c048fcecce
3 changed files with 416 additions and 364 deletions
@@ -24,28 +24,28 @@ import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
abstract class DescriptorWithIrBuilder<out D: DeclarationDescriptor, out B: IrDeclaration> { abstract class SymbolWithIrBuilder<out S: IrSymbol, out D: IrDeclaration> {
protected abstract fun buildDescriptor(): D protected abstract fun buildSymbol(): S
protected open fun doInitialize() { } protected open fun doInitialize() { }
protected abstract fun buildIr(): B protected abstract fun buildIr(): D
val descriptor by lazy { buildDescriptor() } val symbol by lazy { buildSymbol() }
private val builtIr by lazy { buildIr() } private val builtIr by lazy { buildIr() }
private var initialized: Boolean = false private var initialized: Boolean = false
@@ -55,7 +55,7 @@ abstract class DescriptorWithIrBuilder<out D: DeclarationDescriptor, out B: IrDe
initialized = true initialized = true
} }
val ir: B val ir: D
get() { get() {
if (!initialized) if (!initialized)
throw Error("Access to IR before initialization") throw Error("Access to IR before initialization")
@@ -64,11 +64,12 @@ abstract class DescriptorWithIrBuilder<out D: DeclarationDescriptor, out B: IrDe
} }
fun BackendContext.createPropertyGetterBuilder(startOffset: Int, endOffset: Int, origin: IrDeclarationOrigin, fun BackendContext.createPropertyGetterBuilder(startOffset: Int, endOffset: Int, origin: IrDeclarationOrigin,
symbol: IrFieldSymbol, type: KotlinType) fieldSymbol: IrFieldSymbol, type: KotlinType)
= object: DescriptorWithIrBuilder<PropertyGetterDescriptorImpl, IrFunction>() { = object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
override fun buildDescriptor() = PropertyGetterDescriptorImpl( override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
/* correspondingProperty = */ symbol.descriptor, PropertyGetterDescriptorImpl(
/* correspondingProperty = */ fieldSymbol.descriptor,
/* annotations = */ Annotations.EMPTY, /* annotations = */ Annotations.EMPTY,
/* modality = */ Modality.FINAL, /* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE, /* visibility = */ Visibilities.PRIVATE,
@@ -79,8 +80,10 @@ fun BackendContext.createPropertyGetterBuilder(startOffset: Int, endOffset: Int,
/* original = */ null, /* original = */ null,
/* source = */ SourceElement.NO_SOURCE /* source = */ SourceElement.NO_SOURCE
) )
)
override fun doInitialize() { override fun doInitialize() {
val descriptor = symbol.descriptor as PropertyGetterDescriptorImpl
descriptor.apply { descriptor.apply {
initialize(type) initialize(type)
} }
@@ -90,22 +93,23 @@ fun BackendContext.createPropertyGetterBuilder(startOffset: Int, endOffset: Int,
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
origin = origin, origin = origin,
descriptor = descriptor).apply { symbol = symbol).apply {
createParameterDeclarations() createParameterDeclarations()
body = createIrBuilder(this.symbol, startOffset, endOffset).irBlockBody { body = createIrBuilder(this.symbol, startOffset, endOffset).irBlockBody {
+irReturn(irGetField(irGet(this@apply.dispatchReceiverParameter!!.symbol), symbol)) +irReturn(irGetField(irGet(this@apply.dispatchReceiverParameter!!.symbol), fieldSymbol))
} }
} }
} }
private fun BackendContext.createPropertySetterBuilder(startOffset: Int, endOffset: Int, origin: IrDeclarationOrigin, private fun BackendContext.createPropertySetterBuilder(startOffset: Int, endOffset: Int, origin: IrDeclarationOrigin,
symbol: IrFieldSymbol, type: KotlinType) fieldSymbol: IrFieldSymbol, type: KotlinType)
= object: DescriptorWithIrBuilder<PropertySetterDescriptorImpl, IrFunction>() { = object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
override fun buildDescriptor() = PropertySetterDescriptorImpl( override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
/* correspondingProperty = */ symbol.descriptor, PropertySetterDescriptorImpl(
/* correspondingProperty = */ fieldSymbol.descriptor,
/* annotations = */ Annotations.EMPTY, /* annotations = */ Annotations.EMPTY,
/* modality = */ Modality.FINAL, /* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE, /* visibility = */ Visibilities.PRIVATE,
@@ -116,10 +120,12 @@ private fun BackendContext.createPropertySetterBuilder(startOffset: Int, endOffs
/* original = */ null, /* original = */ null,
/* source = */ SourceElement.NO_SOURCE /* source = */ SourceElement.NO_SOURCE
) )
)
lateinit var valueParameterDescriptor: ValueParameterDescriptor lateinit var valueParameterDescriptor: ValueParameterDescriptor
override fun doInitialize() { override fun doInitialize() {
val descriptor = symbol.descriptor as PropertySetterDescriptorImpl
descriptor.apply { descriptor.apply {
valueParameterDescriptor = ValueParameterDescriptorImpl( valueParameterDescriptor = ValueParameterDescriptorImpl(
containingDeclaration = this, containingDeclaration = this,
@@ -143,25 +149,25 @@ private fun BackendContext.createPropertySetterBuilder(startOffset: Int, endOffs
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
origin = origin, origin = origin,
descriptor = descriptor).apply { symbol = symbol).apply {
createParameterDeclarations() createParameterDeclarations()
body = createIrBuilder(this.symbol, startOffset, endOffset).irBlockBody { body = createIrBuilder(this.symbol, startOffset, endOffset).irBlockBody {
+irSetField(irGet(this@apply.dispatchReceiverParameter!!.symbol), symbol, irGet(this@apply.valueParameters.single().symbol)) +irSetField(irGet(this@apply.dispatchReceiverParameter!!.symbol), fieldSymbol, irGet(this@apply.valueParameters.single().symbol))
} }
} }
} }
fun BackendContext.createPropertyWithBackingFieldBuilder(startOffset: Int, endOffset: Int, origin: IrDeclarationOrigin, fun BackendContext.createPropertyWithBackingFieldBuilder(startOffset: Int, endOffset: Int, origin: IrDeclarationOrigin,
owner: ClassDescriptor, name: Name, type: KotlinType, isMutable: Boolean) owner: ClassDescriptor, name: Name, type: KotlinType, isMutable: Boolean)
= object: DescriptorWithIrBuilder<PropertyDescriptorImpl, IrProperty>() { = object: SymbolWithIrBuilder<IrFieldSymbol, IrProperty>() {
private lateinit var getterBuilder: DescriptorWithIrBuilder<PropertyGetterDescriptorImpl, IrFunction> private lateinit var getterBuilder: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>
private var setterBuilder: DescriptorWithIrBuilder<PropertySetterDescriptorImpl, IrFunction>? = null private var setterBuilder: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>? = null
private lateinit var fieldSymbol: IrFieldSymbol
override fun buildDescriptor() = PropertyDescriptorImpl.create( override fun buildSymbol() = IrFieldSymbolImpl(
PropertyDescriptorImpl.create(
/* containingDeclaration = */ owner, /* containingDeclaration = */ owner,
/* annotations = */ Annotations.EMPTY, /* annotations = */ Annotations.EMPTY,
/* modality = */ Modality.FINAL, /* modality = */ Modality.FINAL,
@@ -175,14 +181,18 @@ fun BackendContext.createPropertyWithBackingFieldBuilder(startOffset: Int, endOf
/* isHeader = */ false, /* isHeader = */ false,
/* isImpl = */ false, /* isImpl = */ false,
/* isExternal = */ false, /* isExternal = */ false,
/* isDelegated = */ false) /* isDelegated = */ false
)
)
override fun doInitialize() { override fun doInitialize() {
fieldSymbol = IrFieldSymbolImpl(descriptor) val descriptor = symbol.descriptor as PropertyDescriptorImpl
getterBuilder = createPropertyGetterBuilder(startOffset, endOffset, origin, fieldSymbol, type).apply { initialize() } getterBuilder = createPropertyGetterBuilder(startOffset, endOffset, origin, symbol, type).apply { initialize() }
if (isMutable) if (isMutable)
setterBuilder = createPropertySetterBuilder(startOffset, endOffset, origin, fieldSymbol, type).apply { initialize() } setterBuilder = createPropertySetterBuilder(startOffset, endOffset, origin, symbol, type).apply { initialize() }
descriptor.initialize(getterBuilder.descriptor, setterBuilder?.descriptor) descriptor.initialize(
/* getter = */ getterBuilder.symbol.descriptor as PropertyGetterDescriptorImpl,
/* setter = */ setterBuilder?.symbol?.descriptor as? PropertySetterDescriptorImpl)
val receiverType: KotlinType? = null val receiverType: KotlinType? = null
descriptor.setType(type, emptyList(), owner.thisAsReceiverParameter, receiverType) descriptor.setType(type, emptyList(), owner.thisAsReceiverParameter, receiverType)
} }
@@ -192,13 +202,13 @@ fun BackendContext.createPropertyWithBackingFieldBuilder(startOffset: Int, endOf
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
origin = origin, origin = origin,
symbol = fieldSymbol) symbol = symbol)
return IrPropertyImpl( return IrPropertyImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
origin = origin, origin = origin,
isDelegated = false, isDelegated = false,
descriptor = descriptor, descriptor = symbol.descriptor,
backingField = backingField, backingField = backingField,
getter = getterBuilder.ir, getter = getterBuilder.ir,
setter = setterBuilder?.ir) setter = setterBuilder?.ir)
@@ -38,8 +38,12 @@ import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.getArguments import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -171,9 +175,10 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta
.map { it.createFakeOverrideDescriptor(functionReferenceClassDescriptor) } .map { it.createFakeOverrideDescriptor(functionReferenceClassDescriptor) }
.filterNotNull() .filterNotNull()
val contributedDescriptors = ( val contributedDescriptors = (
inheritedKFunctionImpl + invokeMethodBuilder.descriptor inheritedKFunctionImpl + invokeMethodBuilder.symbol.descriptor
).toList() ).toList()
functionReferenceClassDescriptor.initialize(SimpleMemberScope(contributedDescriptors), setOf(constructorBuilder.descriptor), null) functionReferenceClassDescriptor.initialize(
SimpleMemberScope(contributedDescriptors), setOf(constructorBuilder.symbol.descriptor), null)
constructorBuilder.initialize() constructorBuilder.initialize()
functionReferenceClass.declarations.add(constructorBuilder.ir) functionReferenceClass.declarations.add(constructorBuilder.ir)
@@ -185,20 +190,21 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta
} }
private fun createConstructorBuilder() private fun createConstructorBuilder()
= object : DescriptorWithIrBuilder<ClassConstructorDescriptorImpl, IrConstructor>() { = object : SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>() {
private val kFunctionImplConstructorDescriptor = kFunctionImplClassDescriptor.constructors.single() private val kFunctionImplConstructorDescriptor = kFunctionImplClassDescriptor.constructors.single()
override fun buildDescriptor(): ClassConstructorDescriptorImpl { override fun buildSymbol() = IrConstructorSymbolImpl(
return ClassConstructorDescriptorImpl.create( ClassConstructorDescriptorImpl.create(
/* containingDeclaration = */ functionReferenceClassDescriptor, /* containingDeclaration = */ functionReferenceClassDescriptor,
/* annotations = */ Annotations.EMPTY, /* annotations = */ Annotations.EMPTY,
/* isPrimary = */ false, /* isPrimary = */ false,
/* source = */ SourceElement.NO_SOURCE /* source = */ SourceElement.NO_SOURCE
) )
} )
override fun doInitialize() { override fun doInitialize() {
val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl
val constructorParameters = boundFunctionParameters.mapIndexed { index, parameter -> val constructorParameters = boundFunctionParameters.mapIndexed { index, parameter ->
parameter.copyAsValueParameter(descriptor, index) parameter.copyAsValueParameter(descriptor, index)
} }
@@ -217,7 +223,7 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
descriptor = descriptor).apply { symbol = symbol).apply {
val irBuilder = context.createIrBuilder(this.symbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(this.symbol, startOffset, endOffset)
@@ -261,20 +267,24 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta
} }
private fun createInvokeMethodBuilder(functionInvokeFunctionDescriptor: FunctionDescriptor) private fun createInvokeMethodBuilder(functionInvokeFunctionDescriptor: FunctionDescriptor)
= object : DescriptorWithIrBuilder<SimpleFunctionDescriptorImpl, IrFunction>() { = object : SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
override fun buildDescriptor() = SimpleFunctionDescriptorImpl.create( override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ functionReferenceClassDescriptor, /* containingDeclaration = */ functionReferenceClassDescriptor,
/* annotations = */ Annotations.EMPTY, /* annotations = */ Annotations.EMPTY,
/* name = */ Name.identifier("invoke"), /* name = */ Name.identifier("invoke"),
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION, /* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE) /* source = */ SourceElement.NO_SOURCE
)
)
override fun doInitialize() { override fun doInitialize() {
val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl
val valueParameters = functionInvokeFunctionDescriptor.valueParameters val valueParameters = functionInvokeFunctionDescriptor.valueParameters
.map { it.copyAsValueParameter(this.descriptor, it.index) } .map { it.copyAsValueParameter(descriptor, it.index) }
this.descriptor.initialize( descriptor.initialize(
/* receiverParameterType = */ null, /* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ functionReferenceClassDescriptor.thisAsReceiverParameter, /* dispatchReceiverParameter = */ functionReferenceClassDescriptor.thisAsReceiverParameter,
/* typeParameters = */ emptyList(), /* typeParameters = */ emptyList(),
@@ -286,15 +296,14 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta
} }
} }
override fun buildIr(): IrFunction { override fun buildIr(): IrSimpleFunction {
val startOffset = functionReference.startOffset val startOffset = functionReference.startOffset
val endOffset = functionReference.endOffset val endOffset = functionReference.endOffset
val ourDescriptor = this.descriptor
return IrFunctionImpl( return IrFunctionImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
descriptor = this.descriptor).apply { symbol = symbol).apply {
val function = this val function = this
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
@@ -317,8 +326,7 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta
else -> putValueArgument((it as ValueParameterDescriptor).index, argument) else -> putValueArgument((it as ValueParameterDescriptor).index, argument)
} }
} }
assert(unboundIndex == ourDescriptor.valueParameters.size, assert(unboundIndex == valueParameters.size, { "Not all arguments of <invoke> are used" })
{ "Not all arguments of <invoke> are used" })
} }
) )
} }
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
import org.jetbrains.kotlin.backend.common.descriptors.isSuspend
import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
@@ -40,6 +39,10 @@ import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.getArguments import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.util.transformFlat
@@ -56,7 +59,7 @@ import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
internal class SuspendFunctionsLowering(val context: Context): DeclarationContainerLoweringPass { internal class SuspendFunctionsLowering(val context: Context): DeclarationContainerLoweringPass {
private val builtCoroutines = mutableMapOf<FunctionDescriptor, BuiltCoroutine>() private val builtCoroutines = mutableMapOf<FunctionDescriptor, BuiltCoroutine>()
private val suspendLambdas = mutableMapOf<FunctionDescriptor, IrCallableReference>() private val suspendLambdas = mutableMapOf<FunctionDescriptor, IrFunctionReference>()
override fun lower(irDeclarationContainer: IrDeclarationContainer) { override fun lower(irDeclarationContainer: IrDeclarationContainer) {
markSuspendLambdas(irDeclarationContainer) markSuspendLambdas(irDeclarationContainer)
@@ -76,12 +79,12 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
element.acceptChildrenVoid(this) element.acceptChildrenVoid(this)
} }
override fun visitCallableReference(expression: IrCallableReference) { override fun visitFunctionReference(expression: IrFunctionReference) {
expression.acceptChildrenVoid(this) expression.acceptChildrenVoid(this)
val descriptor = expression.descriptor val descriptor = expression.descriptor
if (descriptor.isSuspend) if (descriptor.isSuspend)
suspendLambdas.put(descriptor as FunctionDescriptor, expression) suspendLambdas.put(descriptor, expression)
} }
}) })
} }
@@ -91,20 +94,21 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
irDeclarationContainer.declarations.forEach { irDeclarationContainer.declarations.forEach {
it.transformChildrenVoid(object: IrElementTransformerVoid() { it.transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitCallableReference(expression: IrCallableReference): IrExpression { override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
val descriptor = expression.descriptor val descriptor = expression.descriptor
if (!descriptor.isSuspend) return expression if (!descriptor.isSuspend)
return expression
val coroutine = builtCoroutines[descriptor] val coroutine = builtCoroutines[descriptor]
?: throw Error("Non-local callable reference to suspend lambda: $descriptor") ?: throw Error("Non-local callable reference to suspend lambda: $descriptor")
val constructorParameters = coroutine.coroutineConstructorDescriptor.valueParameters val constructorParameters = coroutine.coroutineConstructor.valueParameters
val expressionArguments = expression.getArguments().map { it.second } val expressionArguments = expression.getArguments().map { it.second }
assert (constructorParameters.size == expressionArguments.size, assert (constructorParameters.size == expressionArguments.size,
{ "Inconsistency between callable reference to suspend lambda and the corresponding coroutine" }) { "Inconsistency between callable reference to suspend lambda and the corresponding coroutine" })
val irBuilder = context.createIrBuilder(descriptor, expression.startOffset, expression.endOffset) val irBuilder = context.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset)
irBuilder.run { irBuilder.run {
return irCall(coroutine.coroutineConstructorDescriptor).apply { return irCall(coroutine.coroutineConstructor.symbol).apply {
expressionArguments.forEachIndexed { index, argument -> expressionArguments.forEachIndexed { index, argument ->
putValueArgument(index, argument) } putValueArgument(index, argument) }
} }
@@ -150,7 +154,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
NEEDS_STATE_MACHINE NEEDS_STATE_MACHINE
} }
private fun transformSuspendFunction(irFunction: IrFunction, callableReference: IrCallableReference?): List<IrDeclaration>? { private fun transformSuspendFunction(irFunction: IrFunction, functionReference: IrFunctionReference?): List<IrDeclaration>? {
val suspendFunctionKind = getSuspendFunctionKind(irFunction) val suspendFunctionKind = getSuspendFunctionKind(irFunction)
return when (suspendFunctionKind) { return when (suspendFunctionKind) {
SuspendFunctionKind.NO_SUSPEND_CALLS -> { SuspendFunctionKind.NO_SUSPEND_CALLS -> {
@@ -164,7 +168,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
} }
SuspendFunctionKind.NEEDS_STATE_MACHINE -> { SuspendFunctionKind.NEEDS_STATE_MACHINE -> {
val coroutine = buildCoroutine(irFunction, callableReference) // Coroutine implementation. val coroutine = buildCoroutine(irFunction, functionReference) // Coroutine implementation.
if (suspendLambdas.contains(irFunction.descriptor)) // Suspend lambdas are called through factory method <create>, if (suspendLambdas.contains(irFunction.descriptor)) // Suspend lambdas are called through factory method <create>,
listOf(coroutine) // thus we can eliminate original body. listOf(coroutine) // thus we can eliminate original body.
else else
@@ -255,18 +259,18 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
}) })
} }
private fun buildCoroutine(irFunction: IrFunction, callableReference: IrCallableReference?): IrClass { private fun buildCoroutine(irFunction: IrFunction, functionReference: IrFunctionReference?): IrClass {
val descriptor = irFunction.descriptor val descriptor = irFunction.descriptor
val coroutine = CoroutineBuilder(irFunction, callableReference).build() val coroutine = CoroutineBuilder(irFunction, functionReference).build()
builtCoroutines.put(descriptor, coroutine) builtCoroutines.put(descriptor, coroutine)
if (callableReference == null) { if (functionReference == null) {
// It is not a lambda - replace original function with a call to constructor of the built coroutine. // It is not a lambda - replace original function with a call to constructor of the built coroutine.
val irBuilder = context.createIrBuilder(descriptor, 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.doResumeFunctionDescriptor).apply { irCall(coroutine.doResumeFunction.symbol).apply {
dispatchReceiver = irCall(coroutine.coroutineConstructorDescriptor).apply { dispatchReceiver = irCall(coroutine.coroutineConstructor.symbol).apply {
val functionParameters = irFunction.descriptor.explicitParameters val functionParameters = irFunction.descriptor.explicitParameters
functionParameters.forEachIndexed { index, argument -> functionParameters.forEachIndexed { index, argument ->
putValueArgument(index, irGet(argument)) putValueArgument(index, irGet(argument))
@@ -284,8 +288,8 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
} }
private class BuiltCoroutine(val coroutineClass: IrClass, private class BuiltCoroutine(val coroutineClass: IrClass,
val coroutineConstructorDescriptor: ClassConstructorDescriptor, val coroutineConstructor: IrConstructor,
val doResumeFunctionDescriptor: FunctionDescriptor) val doResumeFunction: IrFunction)
private var coroutineId = 0 private var coroutineId = 0
@@ -302,20 +306,21 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
private val COROUTINE_SUSPENDED = coroutinesIntrinsicsScope private val COROUTINE_SUSPENDED = coroutinesIntrinsicsScope
.getContributedVariables(Name.identifier("COROUTINE_SUSPENDED"), NoLookupLocation.FROM_BACKEND).first() .getContributedVariables(Name.identifier("COROUTINE_SUSPENDED"), NoLookupLocation.FROM_BACKEND).first()
private inner class CoroutineBuilder(val irFunction: IrFunction, val callableReference: IrCallableReference?) { private inner class CoroutineBuilder(val irFunction: IrFunction, val functionReference: IrFunctionReference?) {
private val functionParameters = irFunction.descriptor.explicitParameters private val functionParameters = irFunction.descriptor.explicitParameters
private val boundFunctionParameters = callableReference?.getArguments()?.map { it.first } private val boundFunctionParameters = functionReference?.getArguments()?.map { it.first }
private val unboundFunctionParameters = boundFunctionParameters?.let { functionParameters - it } private val unboundFunctionParameters = boundFunctionParameters?.let { functionParameters - it }
private var tempIndex = 0 private var tempIndex = 0
private var suspensionPointIdIndex = 0 private var suspensionPointIdIndex = 0
private lateinit var suspendResult: VariableDescriptor private lateinit var suspendResult: IrVariableSymbol
private lateinit var dataArgument: ValueParameterDescriptor private lateinit var dataArgument: IrValueParameterSymbol
private lateinit var exceptionArgument: ValueParameterDescriptor private lateinit var exceptionArgument: IrValueParameterSymbol
private lateinit var coroutineClassDescriptor: ClassDescriptorImpl private lateinit var coroutineClassDescriptor: ClassDescriptorImpl
private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, PropertyDescriptor> private lateinit var coroutineClass: IrClassImpl
private val coroutineMembers = mutableListOf<IrDeclaration>() private lateinit var coroutineClassThis: IrValueParameterSymbol
private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, IrFieldSymbol>
private val coroutineImplClassDescriptor = context.builtIns.getKonanInternalClass("CoroutineImpl") private val coroutineImplClassDescriptor = context.builtIns.getKonanInternalClass("CoroutineImpl")
private val create1FunctionDescriptor = coroutineImplClassDescriptor.unsubstitutedMemberScope private val create1FunctionDescriptor = coroutineImplClassDescriptor.unsubstitutedMemberScope
@@ -353,23 +358,34 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
/* source = */ SourceElement.NO_SOURCE, /* source = */ SourceElement.NO_SOURCE,
/* isExternal = */ false /* isExternal = */ false
) )
coroutineClass = IrClassImpl(
startOffset = irFunction.startOffset,
endOffset = irFunction.endOffset,
origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
descriptor = coroutineClassDescriptor
)
coroutineClass.createParameterDeclarations()
coroutineClassThis = coroutineClass.thisReceiver!!.symbol
val overriddenMap = mutableMapOf<CallableMemberDescriptor, CallableMemberDescriptor>() val overriddenMap = mutableMapOf<CallableMemberDescriptor, CallableMemberDescriptor>()
val constructors = mutableSetOf<ClassConstructorDescriptor>() val constructors = mutableSetOf<ClassConstructorDescriptor>()
val coroutineConstructorBuilder = createConstructorBuilder() val coroutineConstructorBuilder = createConstructorBuilder()
constructors.add(coroutineConstructorBuilder.descriptor) constructors.add(coroutineConstructorBuilder.symbol.descriptor)
val doResumeFunctionDescriptor = coroutineImplClassDescriptor.unsubstitutedMemberScope val doResumeFunctionDescriptor = coroutineImplClassDescriptor.unsubstitutedMemberScope
.getContributedFunctions(Name.identifier("doResume"), NoLookupLocation.FROM_BACKEND).single() .getContributedFunctions(Name.identifier("doResume"), NoLookupLocation.FROM_BACKEND).single()
val doResumeMethodBuilder = createDoResumeMethodBuilder(doResumeFunctionDescriptor) val doResumeMethodBuilder = createDoResumeMethodBuilder(doResumeFunctionDescriptor)
overriddenMap += doResumeFunctionDescriptor to doResumeMethodBuilder.descriptor overriddenMap += doResumeFunctionDescriptor to doResumeMethodBuilder.symbol.descriptor
var coroutineFactoryConstructorBuilder: DescriptorWithIrBuilder<ClassConstructorDescriptor, IrConstructor>? = null var coroutineFactoryConstructorBuilder: SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>? = null
var createMethodBuilder: DescriptorWithIrBuilder<FunctionDescriptor, IrFunction>? = null var createMethodBuilder: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>? = null
var invokeMethodBuilder: DescriptorWithIrBuilder<FunctionDescriptor, IrFunction>? = null var invokeMethodBuilder: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>? = null
if (callableReference != null) { if (functionReference != null) {
// Suspend lambda - create factory methods. // Suspend lambda - create factory methods.
coroutineFactoryConstructorBuilder = createFactoryConstructorBuilder(boundFunctionParameters!!) coroutineFactoryConstructorBuilder = createFactoryConstructorBuilder(boundFunctionParameters!!)
constructors.add(coroutineFactoryConstructorBuilder.descriptor) constructors.add(coroutineFactoryConstructorBuilder.symbol.descriptor)
val createFunctionDescriptor = coroutineImplClassDescriptor.unsubstitutedMemberScope val createFunctionDescriptor = coroutineImplClassDescriptor.unsubstitutedMemberScope
.getContributedFunctions(Name.identifier("create"), NoLookupLocation.FROM_BACKEND) .getContributedFunctions(Name.identifier("create"), NoLookupLocation.FROM_BACKEND)
@@ -377,9 +393,9 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
createMethodBuilder = createCreateMethodBuilder( createMethodBuilder = createCreateMethodBuilder(
unboundArgs = unboundFunctionParameters!!, unboundArgs = unboundFunctionParameters!!,
superFunctionDescriptor = createFunctionDescriptor, superFunctionDescriptor = createFunctionDescriptor,
coroutineConstructorDescriptor = coroutineConstructorBuilder.descriptor) coroutineConstructorSymbol = coroutineConstructorBuilder.symbol)
if (createFunctionDescriptor != null) if (createFunctionDescriptor != null)
overriddenMap += createFunctionDescriptor to createMethodBuilder.descriptor overriddenMap += createFunctionDescriptor to createMethodBuilder.symbol.descriptor
val invokeFunctionDescriptor = functionClassDescriptor!!.unsubstitutedMemberScope val invokeFunctionDescriptor = functionClassDescriptor!!.unsubstitutedMemberScope
.getContributedFunctions(Name.identifier("invoke"), NoLookupLocation.FROM_BACKEND).single() .getContributedFunctions(Name.identifier("invoke"), NoLookupLocation.FROM_BACKEND).single()
@@ -388,73 +404,63 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
invokeMethodBuilder = createInvokeMethodBuilder( invokeMethodBuilder = createInvokeMethodBuilder(
suspendFunctionInvokeFunctionDescriptor = suspendInvokeFunctionDescriptor, suspendFunctionInvokeFunctionDescriptor = suspendInvokeFunctionDescriptor,
functionInvokeFunctionDescriptor = invokeFunctionDescriptor, functionInvokeFunctionDescriptor = invokeFunctionDescriptor,
createFunctionDescriptor = createMethodBuilder.descriptor, createFunctionSymbol = createMethodBuilder.symbol,
doResumeFunctionDescriptor = doResumeMethodBuilder.descriptor) doResumeFunctionSymbol = doResumeMethodBuilder.symbol)
} }
val inheritedFromCoroutineImpl = coroutineImplClassDescriptor.unsubstitutedMemberScope val inheritedFromCoroutineImpl = coroutineImplClassDescriptor.unsubstitutedMemberScope
.getContributedDescriptors() .getContributedDescriptors()
.map { overriddenMap[it] ?: it.createFakeOverrideDescriptor(coroutineClassDescriptor) } .map { overriddenMap[it] ?: it.createFakeOverrideDescriptor(coroutineClassDescriptor) }
val contributedDescriptors = ( val contributedDescriptors = (
inheritedFromCoroutineImpl + invokeMethodBuilder?.descriptor inheritedFromCoroutineImpl + invokeMethodBuilder?.symbol?.descriptor
).filterNotNull().toList() ).filterNotNull().toList()
coroutineClassDescriptor.initialize(SimpleMemberScope(contributedDescriptors), constructors, null) coroutineClassDescriptor.initialize(SimpleMemberScope(contributedDescriptors), constructors, null)
coroutineConstructorBuilder.initialize() coroutineConstructorBuilder.initialize()
coroutineMembers.add(coroutineConstructorBuilder.ir) coroutineClass.declarations.add(coroutineConstructorBuilder.ir)
coroutineFactoryConstructorBuilder?.let { coroutineFactoryConstructorBuilder?.let {
it.initialize() it.initialize()
coroutineMembers.add(it.ir) coroutineClass.declarations.add(it.ir)
} }
createMethodBuilder?.let { createMethodBuilder?.let {
it.initialize() it.initialize()
coroutineMembers.add(it.ir) coroutineClass.declarations.add(it.ir)
} }
invokeMethodBuilder?.let { invokeMethodBuilder?.let {
it.initialize() it.initialize()
coroutineMembers.add(it.ir) coroutineClass.declarations.add(it.ir)
} }
doResumeMethodBuilder.initialize() doResumeMethodBuilder.initialize()
coroutineMembers.add(doResumeMethodBuilder.ir) coroutineClass.declarations.add(doResumeMethodBuilder.ir)
val coroutineClass = IrClassImpl(
startOffset = irFunction.startOffset,
endOffset = irFunction.endOffset,
origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
descriptor = coroutineClassDescriptor,
members = coroutineMembers
)
coroutineClass.createParameterDeclarations()
return BuiltCoroutine( return BuiltCoroutine(
coroutineClass = coroutineClass, coroutineClass = coroutineClass,
coroutineConstructorDescriptor = coroutineFactoryConstructorBuilder?.descriptor coroutineConstructor = coroutineFactoryConstructorBuilder?.ir
?: coroutineConstructorBuilder.descriptor, ?: coroutineConstructorBuilder.ir,
doResumeFunctionDescriptor = doResumeMethodBuilder.descriptor) doResumeFunction = doResumeMethodBuilder.ir)
} }
private fun createConstructorBuilder() private fun createConstructorBuilder()
= object : DescriptorWithIrBuilder<ClassConstructorDescriptorImpl, IrConstructor>() { = object : SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>() {
private val coroutineImplConstructorDescriptor = coroutineImplClassDescriptor.constructors.single() private val coroutineImplConstructorDescriptor = coroutineImplClassDescriptor.constructors.single()
private lateinit var constructorParameters: List<ValueParameterDescriptor>
override fun buildDescriptor(): ClassConstructorDescriptorImpl { override fun buildSymbol() = IrConstructorSymbolImpl(
return ClassConstructorDescriptorImpl.create( ClassConstructorDescriptorImpl.create(
/* containingDeclaration = */ coroutineClassDescriptor, /* containingDeclaration = */ coroutineClassDescriptor,
/* annotations = */ Annotations.EMPTY, /* annotations = */ Annotations.EMPTY,
/* isPrimary = */ false, /* isPrimary = */ false,
/* source = */ SourceElement.NO_SOURCE /* source = */ SourceElement.NO_SOURCE
) )
} )
override fun doInitialize() { override fun doInitialize() {
constructorParameters = ( val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl
val constructorParameters = (
functionParameters functionParameters
+ coroutineImplConstructorDescriptor.valueParameters[0] // completion. + coroutineImplConstructorDescriptor.valueParameters[0] // completion.
).mapIndexed { index, parameter -> parameter.copyAsValueParameter(descriptor, index) } ).mapIndexed { index, parameter -> parameter.copyAsValueParameter(descriptor, index) }
@@ -471,23 +477,23 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
val startOffset = irFunction.startOffset val startOffset = irFunction.startOffset
val endOffset = irFunction.endOffset val endOffset = irFunction.endOffset
val irBuilder = context.createIrBuilder(descriptor, startOffset, endOffset)
return IrConstructorImpl( return IrConstructorImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
origin = DECLARATION_ORIGIN_COROUTINE_IMPL, origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
descriptor = descriptor).apply { symbol = symbol).apply {
createParameterDeclarations() createParameterDeclarations()
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody { body = irBuilder.irBlockBody {
val completionParameter = descriptor.valueParameters.last() val completionParameter = valueParameters.last()
+IrDelegatingConstructorCallImpl(startOffset, endOffset, coroutineImplConstructorDescriptor).apply { +IrDelegatingConstructorCallImpl(startOffset, endOffset, coroutineImplConstructorDescriptor).apply {
putValueArgument(0, irGet(completionParameter)) putValueArgument(0, irGet(completionParameter.symbol))
} }
+IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClassDescriptor) +IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol)
functionParameters.forEachIndexed { index, parameter -> functionParameters.forEachIndexed { index, parameter ->
+irSetField(irThis(), argumentToPropertiesMap[parameter]!!, irGet(constructorParameters[index])) +irSetField(irGet(coroutineClassThis), argumentToPropertiesMap[parameter]!!, irGet(valueParameters[index].symbol))
} }
} }
} }
@@ -495,22 +501,22 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
} }
private fun createFactoryConstructorBuilder(boundParams: List<ParameterDescriptor>) private fun createFactoryConstructorBuilder(boundParams: List<ParameterDescriptor>)
= object : DescriptorWithIrBuilder<ClassConstructorDescriptorImpl, IrConstructor>() { = object : SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>() {
private val coroutineImplConstructorDescriptor = coroutineImplClassDescriptor.constructors.single() private val coroutineImplConstructorDescriptor = coroutineImplClassDescriptor.constructors.single()
private lateinit var constructorParameters: List<ValueParameterDescriptor>
override fun buildDescriptor(): ClassConstructorDescriptorImpl { override fun buildSymbol() = IrConstructorSymbolImpl(
return ClassConstructorDescriptorImpl.create( ClassConstructorDescriptorImpl.create(
/* containingDeclaration = */ coroutineClassDescriptor, /* containingDeclaration = */ coroutineClassDescriptor,
/* annotations = */ Annotations.EMPTY, /* annotations = */ Annotations.EMPTY,
/* isPrimary = */ false, /* isPrimary = */ false,
/* source = */ SourceElement.NO_SOURCE /* source = */ SourceElement.NO_SOURCE
) )
} )
override fun doInitialize() { override fun doInitialize() {
constructorParameters = boundParams.mapIndexed { index, parameter -> val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl
val constructorParameters = boundParams.mapIndexed { index, parameter ->
parameter.copyAsValueParameter(descriptor, index) parameter.copyAsValueParameter(descriptor, index)
} }
descriptor.initialize(constructorParameters, Visibilities.PUBLIC) descriptor.initialize(constructorParameters, Visibilities.PUBLIC)
@@ -520,23 +526,23 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
override fun buildIr(): IrConstructor { override fun buildIr(): IrConstructor {
val startOffset = irFunction.startOffset val startOffset = irFunction.startOffset
val endOffset = irFunction.endOffset val endOffset = irFunction.endOffset
val irBuilder = context.createIrBuilder(descriptor, startOffset, endOffset)
return IrConstructorImpl( return IrConstructorImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
origin = DECLARATION_ORIGIN_COROUTINE_IMPL, origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
descriptor = descriptor).apply { symbol = symbol).apply {
createParameterDeclarations() createParameterDeclarations()
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody { body = irBuilder.irBlockBody {
+IrDelegatingConstructorCallImpl(startOffset, endOffset, coroutineImplConstructorDescriptor).apply { +IrDelegatingConstructorCallImpl(startOffset, endOffset, coroutineImplConstructorDescriptor).apply {
putValueArgument(0, irNull()) // Completion. putValueArgument(0, irNull()) // Completion.
} }
+IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClassDescriptor) +IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol)
// Save all arguments to fields. // Save all arguments to fields.
boundParams.forEachIndexed { index, parameter -> boundParams.forEachIndexed { index, parameter ->
+irSetField(irThis(), argumentToPropertiesMap[parameter]!!, irGet(constructorParameters[index])) +irSetField(irGet(coroutineClassThis), argumentToPropertiesMap[parameter]!!, irGet(valueParameters[index].symbol))
} }
} }
} }
@@ -545,17 +551,21 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
private fun createCreateMethodBuilder(unboundArgs: List<ParameterDescriptor>, private fun createCreateMethodBuilder(unboundArgs: List<ParameterDescriptor>,
superFunctionDescriptor: FunctionDescriptor?, superFunctionDescriptor: FunctionDescriptor?,
coroutineConstructorDescriptor: ClassConstructorDescriptor) coroutineConstructorSymbol: IrConstructorSymbol)
= object: DescriptorWithIrBuilder<SimpleFunctionDescriptorImpl, IrFunction>() { = object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
override fun buildDescriptor() = SimpleFunctionDescriptorImpl.create( override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ coroutineClassDescriptor, /* containingDeclaration = */ coroutineClassDescriptor,
/* annotations = */ Annotations.EMPTY, /* annotations = */ Annotations.EMPTY,
/* name = */ Name.identifier("create"), /* name = */ Name.identifier("create"),
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION, /* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE) /* source = */ SourceElement.NO_SOURCE
)
)
override fun doInitialize() { override fun doInitialize() {
val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl
val valueParameters = ( val valueParameters = (
unboundArgs + create1CompletionParameter unboundArgs + create1CompletionParameter
).mapIndexed { index, parameter -> ).mapIndexed { index, parameter ->
@@ -577,34 +587,33 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
} }
} }
override fun buildIr(): IrFunction { override fun buildIr(): IrSimpleFunction {
val startOffset = irFunction.startOffset val startOffset = irFunction.startOffset
val endOffset = irFunction.endOffset val endOffset = irFunction.endOffset
val ourDescriptor = descriptor
val irBuilder = context.createIrBuilder(descriptor, startOffset, endOffset)
return IrFunctionImpl( return IrFunctionImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
origin = DECLARATION_ORIGIN_COROUTINE_IMPL, origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
descriptor = descriptor).apply { symbol = symbol).apply {
createParameterDeclarations() createParameterDeclarations()
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody(startOffset, endOffset) { body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn( +irReturn(
irCall(coroutineConstructorDescriptor).apply { irCall(coroutineConstructorSymbol).apply {
var unboundIndex = 0 var unboundIndex = 0
val unboundArgsSet = unboundArgs.toSet() val unboundArgsSet = unboundArgs.toSet()
functionParameters.map { functionParameters.map {
if (unboundArgsSet.contains(it)) if (unboundArgsSet.contains(it))
irGet(ourDescriptor.valueParameters[unboundIndex++]) irGet(valueParameters[unboundIndex++].symbol)
else else
irGet(irThis(), argumentToPropertiesMap[it]!!) irGetField(irGet(coroutineClassThis), argumentToPropertiesMap[it]!!)
}.forEachIndexed { index, argument -> }.forEachIndexed { index, argument ->
putValueArgument(index, argument) putValueArgument(index, argument)
} }
putValueArgument(functionParameters.size, irGet(ourDescriptor.valueParameters[unboundIndex])) putValueArgument(functionParameters.size, irGet(valueParameters[unboundIndex].symbol))
assert(unboundIndex == ourDescriptor.valueParameters.size - 1, assert(unboundIndex == valueParameters.size - 1,
{ "Not all arguments of <create> are used" }) { "Not all arguments of <create> are used" })
}) })
} }
@@ -614,24 +623,28 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
private fun createInvokeMethodBuilder(suspendFunctionInvokeFunctionDescriptor: FunctionDescriptor, private fun createInvokeMethodBuilder(suspendFunctionInvokeFunctionDescriptor: FunctionDescriptor,
functionInvokeFunctionDescriptor: FunctionDescriptor, functionInvokeFunctionDescriptor: FunctionDescriptor,
createFunctionDescriptor: FunctionDescriptor, createFunctionSymbol: IrFunctionSymbol,
doResumeFunctionDescriptor: FunctionDescriptor) doResumeFunctionSymbol: IrFunctionSymbol)
= object: DescriptorWithIrBuilder<SimpleFunctionDescriptorImpl, IrFunction>() { = object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
override fun buildDescriptor() = SimpleFunctionDescriptorImpl.create( override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ coroutineClassDescriptor, /* containingDeclaration = */ coroutineClassDescriptor,
/* annotations = */ Annotations.EMPTY, /* annotations = */ Annotations.EMPTY,
/* name = */ Name.identifier("invoke"), /* name = */ Name.identifier("invoke"),
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION, /* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE) /* source = */ SourceElement.NO_SOURCE
)
)
override fun doInitialize() { override fun doInitialize() {
val valueParameters = createFunctionDescriptor.valueParameters val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl
val valueParameters = createFunctionSymbol.descriptor.valueParameters
// Skip completion - invoke() already has it implicitly as a suspend function. // Skip completion - invoke() already has it implicitly as a suspend function.
.take(createFunctionDescriptor.valueParameters.size - 1) .take(createFunctionSymbol.descriptor.valueParameters.size - 1)
.map { it.copyAsValueParameter(this.descriptor, it.index) } .map { it.copyAsValueParameter(descriptor, it.index) }
this.descriptor.initialize( descriptor.initialize(
/* receiverParameterType = */ null, /* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ coroutineClassDescriptor.thisAsReceiverParameter, /* dispatchReceiverParameter = */ coroutineClassDescriptor.thisAsReceiverParameter,
/* typeParameters = */ emptyList(), /* typeParameters = */ emptyList(),
@@ -645,29 +658,28 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
} }
} }
override fun buildIr(): IrFunction { override fun buildIr(): IrSimpleFunction {
val startOffset = irFunction.startOffset val startOffset = irFunction.startOffset
val endOffset = irFunction.endOffset val endOffset = irFunction.endOffset
val ourDescriptor = this.descriptor
val irBuilder = context.createIrBuilder(this.descriptor, startOffset, endOffset)
return IrFunctionImpl( return IrFunctionImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
origin = DECLARATION_ORIGIN_COROUTINE_IMPL, origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
descriptor = this.descriptor).apply { symbol = symbol).apply {
createParameterDeclarations() createParameterDeclarations()
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody(startOffset, endOffset) { body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn( +irReturn(
irCall(doResumeFunctionDescriptor).apply { irCall(doResumeFunctionSymbol).apply {
dispatchReceiver = irCall(createFunctionDescriptor).apply { dispatchReceiver = irCall(createFunctionSymbol).apply {
dispatchReceiver = irThis() dispatchReceiver = irGet(coroutineClassThis)
ourDescriptor.valueParameters.forEach { valueParameters.forEachIndexed { index, parameter ->
putValueArgument(it.index, irGet(it)) putValueArgument(index, irGet(parameter.symbol))
} }
putValueArgument(ourDescriptor.valueParameters.size, putValueArgument(valueParameters.size,
irCall(getContinuationDescriptor.substitute(ourDescriptor.returnType!!))) irCall(getContinuationDescriptor.substitute(symbol.descriptor.returnType!!)))
} }
putValueArgument(0, irUnit()) // value putValueArgument(0, irUnit()) // value
putValueArgument(1, irNull()) // exception putValueArgument(1, irNull()) // exception
@@ -678,7 +690,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
} }
} }
private fun buildPropertyWithBackingField(name: Name, type: KotlinType, isMutable: Boolean): PropertyDescriptor { private fun buildPropertyWithBackingField(name: Name, type: KotlinType, isMutable: Boolean): IrFieldSymbol {
val propertyBuilder = context.createPropertyWithBackingFieldBuilder( val propertyBuilder = context.createPropertyWithBackingFieldBuilder(
startOffset = irFunction.startOffset, startOffset = irFunction.startOffset,
endOffset = irFunction.endOffset, endOffset = irFunction.endOffset,
@@ -690,65 +702,74 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
initialize() initialize()
} }
coroutineMembers.add(propertyBuilder.ir) coroutineClass.declarations.add(propertyBuilder.ir)
return propertyBuilder.descriptor return propertyBuilder.symbol
} }
private fun createDoResumeMethodBuilder(doResumeFunctionDescriptor: FunctionDescriptor) private fun createDoResumeMethodBuilder(doResumeFunctionDescriptor: FunctionDescriptor)
= object: DescriptorWithIrBuilder<FunctionDescriptor, IrFunction>() { = object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
override fun buildDescriptor() = doResumeFunctionDescriptor.createOverriddenDescriptor(coroutineClassDescriptor) override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
doResumeFunctionDescriptor.createOverriddenDescriptor(coroutineClassDescriptor)
)
override fun doInitialize() { } override fun doInitialize() { }
override fun buildIr(): IrFunction { override fun buildIr(): IrSimpleFunction {
dataArgument = descriptor.valueParameters[0] val originalBody = irFunction.body!!
exceptionArgument = descriptor.valueParameters[1] val startOffset = irFunction.startOffset
suspendResult = IrTemporaryVariableDescriptorImpl( val endOffset = irFunction.endOffset
val function = IrFunctionImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
symbol = symbol).apply {
createParameterDeclarations()
}
dataArgument = function.valueParameters[0].symbol
exceptionArgument = function.valueParameters[1].symbol
suspendResult = IrVariableSymbolImpl(
IrTemporaryVariableDescriptorImpl(
containingDeclaration = irFunction.descriptor, containingDeclaration = irFunction.descriptor,
name = "suspendResult".synthesizedName, name = "suspendResult".synthesizedName,
outType = context.builtIns.nullableAnyType, outType = context.builtIns.nullableAnyType,
isMutable = true) isMutable = true)
)
val label = coroutineClassDescriptor.unsubstitutedMemberScope val label = coroutineClassDescriptor.unsubstitutedMemberScope
.getContributedVariables(Name.identifier("label"), NoLookupLocation.FROM_BACKEND).single() .getContributedVariables(Name.identifier("label"), NoLookupLocation.FROM_BACKEND).single()
val originalBody = irFunction.body!! val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
val startOffset = irFunction.startOffset function.body = irBuilder.irBlockBody(startOffset, endOffset) {
val endOffset = irFunction.endOffset
val irBuilder = context.createIrBuilder(descriptor, startOffset, endOffset)
return IrFunctionImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
descriptor = descriptor).apply {
createParameterDeclarations()
body = irBuilder.irBlockBody(startOffset, endOffset) {
// 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.type)) originalBody.transformChildrenVoid(ExpressionSlicer(label.type))
val liveLocals = computeLivenessAtSuspensionPoints(originalBody) val liveLocals = computeLivenessAtSuspensionPoints(originalBody)
val immutableLiveLocals = liveLocals.values.flatten().filterNot { it.isVar }.toSet() val immutableLiveLocals = liveLocals.values.flatten().filterNot { it.descriptor.isVar }.toSet()
val localsMap = immutableLiveLocals.associate { val localsMap = immutableLiveLocals.associate {
it to IrTemporaryVariableDescriptorImpl( // TODO: Remove .descriptor as soon as all symbols are bound.
it.descriptor to IrVariableSymbolImpl(
IrTemporaryVariableDescriptorImpl(
containingDeclaration = irFunction.descriptor, containingDeclaration = irFunction.descriptor,
name = it.name, name = it.descriptor.name,
outType = it.type, outType = it.descriptor.type,
isMutable = true) isMutable = true)
)
} }
if (localsMap.isNotEmpty()) if (localsMap.isNotEmpty())
transformVariables(originalBody, localsMap) // Make variables mutable in order to save/restore them. transformVariables(originalBody, localsMap) // Make variables mutable in order to save/restore them.
val localToPropertyMap = mutableMapOf<VariableDescriptor, PropertyDescriptor>() val localToPropertyMap = mutableMapOf<IrVariableSymbol, IrFieldSymbol>()
// TODO: optimize by using the same property for different locals. // TODO: optimize by using the same property for different locals.
liveLocals.values.forEach { scope -> liveLocals.values.forEach { scope ->
scope.forEach { scope.forEach {
localToPropertyMap.getOrPut(it) { localToPropertyMap.getOrPut(it) {
buildPropertyWithBackingField(it.name, it.type, true) buildPropertyWithBackingField(it.descriptor.name, it.descriptor.type, true)
} }
} }
} }
@@ -771,7 +792,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
val capturedValue = argumentToPropertiesMap[expression.descriptor] val capturedValue = argumentToPropertiesMap[expression.descriptor]
?: return expression ?: return expression
return irGet(irThis(), capturedValue) return irGetField(irGet(coroutineClassThis), capturedValue)
} }
// Save/restore state at suspension points. // Save/restore state at suspension points.
@@ -785,22 +806,21 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
val descriptor = expression.descriptor when (expression.symbol) {
when (descriptor) { saveStateSymbol -> {
saveStateDescriptor -> {
val scope = liveLocals[suspensionPoint]!! val scope = liveLocals[suspensionPoint]!!
return irBlock(expression) { return irBlock(expression) {
scope.forEach { scope.forEach {
+irSet(irThis(), localToPropertyMap[it]!!, irGet(localsMap[it] ?: it)) +irSetField(irGet(coroutineClassThis), localToPropertyMap[it]!!, irGet(localsMap[it.descriptor] ?: it))
} }
+irSet(irThis(), label, irGet(suspensionPoint.suspensionPointIdParameter.descriptor)) +irSet(irGet(coroutineClassThis), label, irGet(suspensionPoint.suspensionPointIdParameter.symbol))
} }
} }
restoreStateDescriptor -> { restoreStateSymbol -> {
val scope = liveLocals[suspensionPoint]!! val scope = liveLocals[suspensionPoint]!!
return irBlock(expression) { return irBlock(expression) {
scope.forEach { scope.forEach {
+irSetVar(localsMap[it] ?: it, irGet(irThis(), localToPropertyMap[it]!!)) +irSetVar(localsMap[it.descriptor] ?: it, irGetField(irGet(coroutineClassThis), localToPropertyMap[it]!!))
} }
} }
} }
@@ -818,7 +838,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
type = context.builtIns.unitType, type = context.builtIns.unitType,
suspensionPointId = irGet(irThis(), label), suspensionPointId = irGet(irGet(coroutineClassThis), label),
result = irBlock(startOffset, endOffset) { result = irBlock(startOffset, endOffset) {
+irThrowIfNotNull(exceptionArgument) // Coroutine might start with an exception. +irThrowIfNotNull(exceptionArgument) // Coroutine might start with an exception.
statements.forEach { +it } statements.forEach { +it }
@@ -826,36 +846,36 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
if (irFunction.descriptor.returnType!!.isUnit()) if (irFunction.descriptor.returnType!!.isUnit())
+irReturn(irUnit()) // Insert explicit return for Unit functions. +irReturn(irUnit()) // Insert explicit return for Unit functions.
} }
} return function
} }
} }
private fun transformVariables(element: IrElement, variablesMap: Map<VariableDescriptor, VariableDescriptor>) { private fun transformVariables(element: IrElement, variablesMap: Map<VariableDescriptor, IrVariableSymbol>) {
element.transformChildrenVoid(object: IrElementTransformerVoid() { element.transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression { override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
val newVariable = variablesMap[expression.descriptor] val newVariable = variablesMap[expression.symbol.descriptor]
?: return expression ?: return expression
return IrGetValueImpl( return IrGetValueImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
descriptor = newVariable, symbol = newVariable,
origin = expression.origin) origin = expression.origin)
} }
override fun visitSetVariable(expression: IrSetVariable): IrExpression { override fun visitSetVariable(expression: IrSetVariable): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
val newVariable = variablesMap[expression.descriptor] val newVariable = variablesMap[expression.symbol.descriptor]
?: return expression ?: return expression
return IrSetVariableImpl( return IrSetVariableImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
descriptor = newVariable, symbol = newVariable,
value = expression.value, value = expression.value,
origin = expression.origin) origin = expression.origin)
} }
@@ -863,23 +883,24 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
override fun visitVariable(declaration: IrVariable): IrStatement { override fun visitVariable(declaration: IrVariable): IrStatement {
declaration.transformChildrenVoid(this) declaration.transformChildrenVoid(this)
val newVariable = variablesMap[declaration.descriptor] val newVariable = variablesMap[declaration.symbol.descriptor]
?: return declaration ?: return declaration
return IrVariableImpl( return IrVariableImpl(
startOffset = declaration.startOffset, startOffset = declaration.startOffset,
endOffset = declaration.endOffset, endOffset = declaration.endOffset,
origin = declaration.origin, origin = declaration.origin,
descriptor = newVariable, symbol = newVariable).apply {
initializer = declaration.initializer) initializer = declaration.initializer
}
} }
}) })
} }
private fun computeLivenessAtSuspensionPoints(body: IrBody): Map<IrSuspensionPoint, List<VariableDescriptor>> { private fun computeLivenessAtSuspensionPoints(body: IrBody): Map<IrSuspensionPoint, List<IrVariableSymbol>> {
// TODO: data flow analysis. // TODO: data flow analysis.
// Just save all visible for now. // Just save all visible for now.
val result = mutableMapOf<IrSuspensionPoint, List<VariableDescriptor>>() val result = mutableMapOf<IrSuspensionPoint, List<IrVariableSymbol>>()
body.acceptChildrenVoid(object: VariablesScopeTracker() { body.acceptChildrenVoid(object: VariablesScopeTracker() {
override fun visitExpression(expression: IrExpression) { override fun visitExpression(expression: IrExpression) {
@@ -892,7 +913,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
suspensionPoint.result.acceptChildrenVoid(this) suspensionPoint.result.acceptChildrenVoid(this)
suspensionPoint.resumeResult.acceptChildrenVoid(this) suspensionPoint.resumeResult.acceptChildrenVoid(this)
val visibleVariables = mutableListOf<VariableDescriptor>() val visibleVariables = mutableListOf<IrVariableSymbol>()
scopeStack.forEach { visibleVariables += it } scopeStack.forEach { visibleVariables += it }
result.put(suspensionPoint, visibleVariables) result.put(suspensionPoint, visibleVariables)
} }
@@ -902,7 +923,8 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
} }
// These are marker descriptors to split up the lowering on two parts. // These are marker descriptors to split up the lowering on two parts.
private val saveStateDescriptor = SimpleFunctionDescriptorImpl.create( private val saveStateSymbol = IrSimpleFunctionSymbolImpl(
SimpleFunctionDescriptorImpl.create(
irFunction.descriptor, irFunction.descriptor,
Annotations.EMPTY, Annotations.EMPTY,
"saveState".synthesizedName, "saveState".synthesizedName,
@@ -910,8 +932,10 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
SourceElement.NO_SOURCE).apply { SourceElement.NO_SOURCE).apply {
initialize(null, null, emptyList(), emptyList(), context.builtIns.unitType, Modality.ABSTRACT, Visibilities.PRIVATE) initialize(null, null, emptyList(), emptyList(), context.builtIns.unitType, Modality.ABSTRACT, Visibilities.PRIVATE)
} }
)
private val restoreStateDescriptor = SimpleFunctionDescriptorImpl.create( private val restoreStateSymbol = IrSimpleFunctionSymbolImpl(
SimpleFunctionDescriptorImpl.create(
irFunction.descriptor, irFunction.descriptor,
Annotations.EMPTY, Annotations.EMPTY,
"restoreState".synthesizedName, "restoreState".synthesizedName,
@@ -919,6 +943,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
SourceElement.NO_SOURCE).apply { SourceElement.NO_SOURCE).apply {
initialize(null, null, emptyList(), emptyList(), context.builtIns.unitType, Modality.ABSTRACT, Visibilities.PRIVATE) initialize(null, null, emptyList(), emptyList(), context.builtIns.unitType, Modality.ABSTRACT, Visibilities.PRIVATE)
} }
)
private inner class ExpressionSlicer(val suspensionPointIdType: KotlinType): IrElementTransformerVoid() { private inner class ExpressionSlicer(val suspensionPointIdType: KotlinType): IrElementTransformerVoid() {
// TODO: optimize - it has square complexity. // TODO: optimize - it has square complexity.
@@ -936,7 +961,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
} }
private fun sliceExpression(expression: IrExpression): IrExpression { private fun sliceExpression(expression: IrExpression): IrExpression {
val irBuilder = context.createIrBuilder(irFunction.descriptor, expression.startOffset, expression.endOffset) val irBuilder = context.createIrBuilder(irFunction.symbol, expression.startOffset, expression.endOffset)
irBuilder.run { irBuilder.run {
val children = when (expression) { val children = when (expression) {
is IrSetField -> listOf(expression.receiver, expression.value) is IrSetField -> listOf(expression.receiver, expression.value)
@@ -977,10 +1002,12 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
newChildren[index] = transformedChild newChildren[index] = transformedChild
else { else {
// Save to temporary in order to save execution order. // Save to temporary in order to save execution order.
val tmp = IrTemporaryVariableDescriptorImpl( val tmp = IrVariableSymbolImpl(
IrTemporaryVariableDescriptorImpl(
containingDeclaration = irFunction.descriptor, containingDeclaration = irFunction.descriptor,
name = "tmp${tempIndex++}".synthesizedName, name = "tmp${tempIndex++}".synthesizedName,
outType = transformedChild.type) outType = transformedChild.type)
)
tempStatements += irVar(tmp, transformedChild) tempStatements += irVar(tmp, transformedChild)
newChildren[index] = irGet(tmp) newChildren[index] = irGet(tmp)
} }
@@ -995,15 +1022,17 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
newChildren[numberOfChildren - 1] = newChildren[numberOfChildren - 1] =
irBlock(lastChild) { irBlock(lastChild) {
if (lastChild.isPure()) { if (lastChild.isPure()) {
+irCall(saveStateDescriptor) +irCall(saveStateSymbol)
+lastChild +lastChild
} else { } else {
val tmp = IrTemporaryVariableDescriptorImpl( val tmp = IrVariableSymbolImpl(
IrTemporaryVariableDescriptorImpl(
containingDeclaration = irFunction.descriptor, containingDeclaration = irFunction.descriptor,
name = "tmp${tempIndex++}".synthesizedName, name = "tmp${tempIndex++}".synthesizedName,
outType = lastChild.type) outType = lastChild.type)
)
+irVar(tmp, lastChild) +irVar(tmp, lastChild)
+irCall(saveStateDescriptor) +irCall(saveStateSymbol)
+irGet(tmp) +irGet(tmp)
} }
} }
@@ -1041,13 +1070,13 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
suspensionPointIdParameter = irVar(suspensionPointIdParameter, null), suspensionPointIdParameter = irVar(suspensionPointIdParameter, null),
result = irBlock(startOffset, endOffset) { result = irBlock(startOffset, endOffset) {
if (!calledSaveState) if (!calledSaveState)
+irCall(saveStateDescriptor) +irCall(saveStateSymbol)
+irSetVar(suspendResult, suspendCall) +irSetVar(suspendResult, suspendCall)
+irReturnIfSuspended(suspendResult) +irReturnIfSuspended(suspendResult)
+irGet(suspendResult) +irGet(suspendResult)
}, },
resumeResult = irBlock(startOffset, endOffset) { resumeResult = irBlock(startOffset, endOffset) {
+irCall(restoreStateDescriptor) +irCall(restoreStateSymbol)
+irThrowIfNotNull(exceptionArgument) +irThrowIfNotNull(exceptionArgument)
+irGet(dataArgument) +irGet(dataArgument)
}) })
@@ -1116,18 +1145,23 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
private fun IrBuilderWithScope.irVar(descriptor: VariableDescriptor, initializer: IrExpression?) = private fun IrBuilderWithScope.irVar(descriptor: VariableDescriptor, initializer: IrExpression?) =
IrVariableImpl(startOffset, endOffset, DECLARATION_ORIGIN_COROUTINE_IMPL, descriptor, initializer) IrVariableImpl(startOffset, endOffset, DECLARATION_ORIGIN_COROUTINE_IMPL, descriptor, initializer)
private fun IrBuilderWithScope.irReturnIfSuspended(value: ValueDescriptor) = private fun IrBuilderWithScope.irVar(symbol: IrVariableSymbol, initializer: IrExpression?) =
IrVariableImpl(startOffset, endOffset, DECLARATION_ORIGIN_COROUTINE_IMPL, symbol).apply {
this.initializer = initializer
}
private fun IrBuilderWithScope.irReturnIfSuspended(value: IrValueSymbol) =
irIfThen(irEqeqeq(irGet(value), irGet(COROUTINE_SUSPENDED)), irIfThen(irEqeqeq(irGet(value), irGet(COROUTINE_SUSPENDED)),
irReturn(irGet(value))) irReturn(irGet(value)))
private fun IrBuilderWithScope.irThrowIfNotNull(exception: ValueDescriptor) = private fun IrBuilderWithScope.irThrowIfNotNull(exception: IrValueSymbol) =
irIfThen(irNot(irEqeqeq(irGet(exception), irNull())), irIfThen(irNot(irEqeqeq(irGet(exception), irNull())),
irThrow(irImplicitCast(irGet(exception), exception.type.makeNotNullable()))) irThrow(irImplicitCast(irGet(exception), exception.descriptor.type.makeNotNullable())))
} }
private open class VariablesScopeTracker: IrElementVisitorVoid { private open class VariablesScopeTracker: IrElementVisitorVoid {
protected val scopeStack = mutableListOf<MutableSet<VariableDescriptor>>(mutableSetOf()) protected val scopeStack = mutableListOf<MutableSet<IrVariableSymbol>>(mutableSetOf())
override fun visitElement(element: IrElement) { override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this) element.acceptChildrenVoid(this)
@@ -1142,14 +1176,14 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
} }
override fun visitCatch(aCatch: IrCatch) { override fun visitCatch(aCatch: IrCatch) {
scopeStack.push(mutableSetOf(aCatch.parameter)) scopeStack.push(mutableSetOf())
super.visitCatch(aCatch) super.visitCatch(aCatch)
scopeStack.pop() scopeStack.pop()
} }
override fun visitVariable(declaration: IrVariable) { override fun visitVariable(declaration: IrVariable) {
super.visitVariable(declaration) super.visitVariable(declaration)
scopeStack.peek()!!.add(declaration.descriptor) scopeStack.peek()!!.add(declaration.symbol)
} }
} }
} }