Codegen: coroutines support
This commit is contained in:
+7
-1
@@ -195,8 +195,14 @@ private fun getStringValue(annotation: AnnotationDescriptor): String? {
|
|||||||
// TODO: bring here dependencies of this method?
|
// TODO: bring here dependencies of this method?
|
||||||
internal fun RuntimeAware.getLlvmFunctionType(function: FunctionDescriptor): LLVMTypeRef {
|
internal fun RuntimeAware.getLlvmFunctionType(function: FunctionDescriptor): LLVMTypeRef {
|
||||||
val original = function.original
|
val original = function.original
|
||||||
val returnType = if (original is ConstructorDescriptor) voidType else getLLVMReturnType(original.returnType!!)
|
val returnType = when {
|
||||||
|
original is ConstructorDescriptor -> voidType
|
||||||
|
original.isSuspend -> kObjHeaderPtr // Suspend functions return Any?.
|
||||||
|
else -> getLLVMReturnType(original.returnType!!)
|
||||||
|
}
|
||||||
val paramTypes = ArrayList(original.allParameters.map { getLLVMType(it.type) })
|
val paramTypes = ArrayList(original.allParameters.map { getLLVMType(it.type) })
|
||||||
|
if (original.isSuspend)
|
||||||
|
paramTypes.add(kObjHeaderPtr) // Suspend functions have implicit parameter of type Continuation<>.
|
||||||
if (isObjectType(returnType)) paramTypes.add(kObjHeaderPtrPtr)
|
if (isObjectType(returnType)) paramTypes.add(kObjHeaderPtrPtr)
|
||||||
|
|
||||||
return functionType(returnType, isVarArg = false, paramTypes = *paramTypes.toTypedArray())
|
return functionType(returnType, isVarArg = false, paramTypes = *paramTypes.toTypedArray())
|
||||||
|
|||||||
+11
-1
@@ -23,7 +23,6 @@ import org.jetbrains.kotlin.backend.konan.Context
|
|||||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
internal class CodeGenerator(override val context: Context) : ContextUtils {
|
internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||||
@@ -400,6 +399,17 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun blockAddress(bbLabel: LLVMBasicBlockRef): LLVMValueRef {
|
||||||
|
return LLVMBlockAddress(function, bbLabel)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun indirectBr(address: LLVMValueRef, destinations: Collection<LLVMBasicBlockRef>): LLVMValueRef? {
|
||||||
|
val indirectBr = LLVMBuildIndirectBr(builder, address, destinations.size)
|
||||||
|
destinations.forEach { LLVMAddDestination(indirectBr, it) }
|
||||||
|
currentPositionHolder.setAfterTerminator()
|
||||||
|
return indirectBr
|
||||||
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
fun gxxLandingpad(numClauses: Int, name: String = ""): LLVMValueRef {
|
fun gxxLandingpad(numClauses: Int, name: String = ""): LLVMValueRef {
|
||||||
|
|||||||
+117
-27
@@ -19,15 +19,19 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
|||||||
import kotlinx.cinterop.*
|
import kotlinx.cinterop.*
|
||||||
import llvm.*
|
import llvm.*
|
||||||
import org.jetbrains.kotlin.backend.common.descriptors.allParameters
|
import org.jetbrains.kotlin.backend.common.descriptors.allParameters
|
||||||
|
import org.jetbrains.kotlin.backend.common.descriptors.isSuspend
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
import org.jetbrains.kotlin.backend.konan.Context
|
||||||
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
||||||
import org.jetbrains.kotlin.backend.konan.KonanPhase
|
import org.jetbrains.kotlin.backend.konan.KonanPhase
|
||||||
import org.jetbrains.kotlin.backend.konan.PhaseManager
|
import org.jetbrains.kotlin.backend.konan.PhaseManager
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.IrInlineFunctionBody
|
import org.jetbrains.kotlin.backend.konan.ir.IrInlineFunctionBody
|
||||||
|
import org.jetbrains.kotlin.backend.konan.ir.IrSuspendableExpression
|
||||||
|
import org.jetbrains.kotlin.backend.konan.ir.IrSuspensionPoint
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.ir2string
|
import org.jetbrains.kotlin.backend.konan.ir.ir2string
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
@@ -37,9 +41,11 @@ import org.jetbrains.kotlin.ir.util.getArguments
|
|||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||||
@@ -197,6 +203,7 @@ internal interface CodeContext {
|
|||||||
* @return the requested value
|
* @return the requested value
|
||||||
*/
|
*/
|
||||||
fun fileScope(): CodeContext?
|
fun fileScope(): CodeContext?
|
||||||
|
fun addResumePoint(bbLabel: LLVMBasicBlockRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -239,6 +246,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
override fun functionScope(): CodeContext? = null
|
override fun functionScope(): CodeContext? = null
|
||||||
|
|
||||||
override fun fileScope(): CodeContext? = null
|
override fun fileScope(): CodeContext? = null
|
||||||
|
|
||||||
|
override fun addResumePoint(bbLabel: LLVMBasicBlockRef) = unsupported(bbLabel)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -329,6 +338,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
override fun visitFile(declaration: IrFile) {
|
override fun visitFile(declaration: IrFile) {
|
||||||
|
|
||||||
context.llvm.fileInitializers.clear()
|
context.llvm.fileInitializers.clear()
|
||||||
@@ -610,30 +620,33 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
|
|
||||||
private fun evaluateExpression(value: IrExpression): LLVMValueRef {
|
private fun evaluateExpression(value: IrExpression): LLVMValueRef {
|
||||||
when (value) {
|
when (value) {
|
||||||
is IrTypeOperatorCall -> return evaluateTypeOperator (value)
|
is IrTypeOperatorCall -> return evaluateTypeOperator (value)
|
||||||
is IrCall -> return evaluateCall (value)
|
is IrCall -> return evaluateCall (value)
|
||||||
is IrDelegatingConstructorCall ->
|
is IrDelegatingConstructorCall ->
|
||||||
return evaluateCall(value)
|
return evaluateCall (value)
|
||||||
is IrInstanceInitializerCall ->
|
is IrInstanceInitializerCall ->
|
||||||
return evaluateInstanceInitializerCall(value)
|
return evaluateInstanceInitializerCall(value)
|
||||||
is IrGetValue -> return evaluateGetValue (value)
|
is IrGetValue -> return evaluateGetValue (value)
|
||||||
is IrSetVariable -> return evaluateSetVariable (value)
|
is IrSetVariable -> return evaluateSetVariable (value)
|
||||||
is IrGetField -> return evaluateGetField (value)
|
is IrGetField -> return evaluateGetField (value)
|
||||||
is IrSetField -> return evaluateSetField (value)
|
is IrSetField -> return evaluateSetField (value)
|
||||||
is IrConst<*> -> return evaluateConst (value)
|
is IrConst<*> -> return evaluateConst (value)
|
||||||
is IrReturn -> return evaluateReturn (value)
|
is IrReturn -> return evaluateReturn (value)
|
||||||
is IrWhen -> return evaluateWhen (value)
|
is IrWhen -> return evaluateWhen (value)
|
||||||
is IrThrow -> return evaluateThrow (value)
|
is IrThrow -> return evaluateThrow (value)
|
||||||
is IrTry -> return evaluateTry (value)
|
is IrTry -> return evaluateTry (value)
|
||||||
is IrInlineFunctionBody -> return evaluateInlineFunction (value)
|
is IrInlineFunctionBody -> return evaluateInlineFunction (value)
|
||||||
is IrContainerExpression -> return evaluateContainerExpression(value)
|
is IrContainerExpression -> return evaluateContainerExpression (value)
|
||||||
is IrWhileLoop -> return evaluateWhileLoop (value)
|
is IrWhileLoop -> return evaluateWhileLoop (value)
|
||||||
is IrDoWhileLoop -> return evaluateDoWhileLoop (value)
|
is IrDoWhileLoop -> return evaluateDoWhileLoop (value)
|
||||||
is IrVararg -> return evaluateVararg (value)
|
is IrVararg -> return evaluateVararg (value)
|
||||||
is IrBreak -> return evaluateBreak (value)
|
is IrBreak -> return evaluateBreak (value)
|
||||||
is IrContinue -> return evaluateContinue (value)
|
is IrContinue -> return evaluateContinue (value)
|
||||||
is IrGetObjectValue -> return evaluateGetObjectValue (value)
|
is IrGetObjectValue -> return evaluateGetObjectValue (value)
|
||||||
is IrCallableReference -> return evaluateCallableReference (value)
|
is IrCallableReference -> return evaluateCallableReference (value)
|
||||||
|
is IrSuspendableExpression ->
|
||||||
|
return evaluateSuspendableExpression (value)
|
||||||
|
is IrSuspensionPoint -> return evaluateSuspensionPoint (value)
|
||||||
else -> {
|
else -> {
|
||||||
TODO("${ir2string(value)}")
|
TODO("${ir2string(value)}")
|
||||||
}
|
}
|
||||||
@@ -1722,6 +1735,23 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private val coroutineImplDescriptor = context.builtIns.getKonanInternalClass("CoroutineImpl")
|
||||||
|
private val doResumeFunctionDescriptor = coroutineImplDescriptor.unsubstitutedMemberScope
|
||||||
|
.getContributedFunctions(Name.identifier("doResume"), NoLookupLocation.FROM_BACKEND).single()
|
||||||
|
|
||||||
|
private fun getContinuation(): LLVMValueRef {
|
||||||
|
val caller = codegen.functionDescriptor!!
|
||||||
|
return if (caller.isSuspend)
|
||||||
|
codegen.param(caller, caller.allParameters.size) // The last argument.
|
||||||
|
else {
|
||||||
|
// Suspend call from non-suspend function - must be [CoroutineImpl].
|
||||||
|
assert (doResumeFunctionDescriptor in caller.overriddenDescriptors,
|
||||||
|
{ "Expected 'CoroutineImpl.doResume' but was '$caller'" })
|
||||||
|
currentCodeContext.genGetValue(caller.dispatchReceiverParameter!!) // Coroutine itself is a continuation.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates all arguments of [expression] that are explicitly represented in the IR.
|
* Evaluates all arguments of [expression] that are explicitly represented in the IR.
|
||||||
* Returns results in the same order as LLVM function expects, assuming that all explicit arguments
|
* Returns results in the same order as LLVM function expects, assuming that all explicit arguments
|
||||||
@@ -1757,23 +1787,81 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private inner class SuspendableExpressionScope(val resumePoints: MutableList<LLVMBasicBlockRef>) : InnerScopeImpl() {
|
||||||
|
override fun addResumePoint(bbLabel: LLVMBasicBlockRef) {
|
||||||
|
resumePoints.add(bbLabel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun evaluateSuspendableExpression(expression: IrSuspendableExpression): LLVMValueRef {
|
||||||
|
val suspensionPointId = evaluateExpression(expression.suspensionPointId)
|
||||||
|
val bbStart = codegen.basicBlock("start")
|
||||||
|
val bbDispatch = codegen.basicBlock("dispatch")
|
||||||
|
|
||||||
|
val resumePoints = mutableListOf<LLVMBasicBlockRef>()
|
||||||
|
using (SuspendableExpressionScope(resumePoints)) {
|
||||||
|
codegen.condBr(codegen.icmpEq(suspensionPointId, kIntPtrZero), bbStart, bbDispatch)
|
||||||
|
|
||||||
|
codegen.positionAtEnd(bbStart)
|
||||||
|
val result = evaluateExpression(expression.result)
|
||||||
|
|
||||||
|
codegen.appendingTo(bbDispatch) {
|
||||||
|
codegen.indirectBr(codegen.intToPtr(suspensionPointId, int8TypePtr), resumePoints)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class SuspensionPointScope(val suspensionPointId: VariableDescriptor,
|
||||||
|
val bbResume: LLVMBasicBlockRef): InnerScopeImpl() {
|
||||||
|
override fun genGetValue(descriptor: ValueDescriptor): LLVMValueRef {
|
||||||
|
if (descriptor == suspensionPointId)
|
||||||
|
return codegen.ptrToInt(codegen.blockAddress(bbResume), LLVMInt64Type()!!) // TODO: intptr.
|
||||||
|
return super.genGetValue(descriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun evaluateSuspensionPoint(expression: IrSuspensionPoint): LLVMValueRef {
|
||||||
|
val bbResume = codegen.basicBlock("resume")
|
||||||
|
currentCodeContext.addResumePoint(bbResume)
|
||||||
|
|
||||||
|
using (SuspensionPointScope(expression.suspensionPointIdParameter.descriptor, bbResume)) {
|
||||||
|
continuationBlock(expression.type).run {
|
||||||
|
val normalResult = evaluateExpression(expression.result)
|
||||||
|
jump(this, normalResult)
|
||||||
|
|
||||||
|
codegen.positionAtEnd(bbResume)
|
||||||
|
val resumeResult = evaluateExpression(expression.resumeResult)
|
||||||
|
jump(this, resumeResult)
|
||||||
|
|
||||||
|
codegen.positionAtEnd(this.block)
|
||||||
|
return this.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private fun evaluateFunctionCall(callee: IrCall, args: List<LLVMValueRef>,
|
private fun evaluateFunctionCall(callee: IrCall, args: List<LLVMValueRef>,
|
||||||
resultLifetime: Lifetime): LLVMValueRef {
|
resultLifetime: Lifetime): LLVMValueRef {
|
||||||
val descriptor:FunctionDescriptor = callee.descriptor as FunctionDescriptor
|
val descriptor = callee.descriptor as FunctionDescriptor
|
||||||
|
|
||||||
|
val argsWithContinuationIfNeeded = if (descriptor.isSuspend)
|
||||||
|
args + getContinuation()
|
||||||
|
else args
|
||||||
if (descriptor.isFunctionInvoke) {
|
if (descriptor.isFunctionInvoke) {
|
||||||
return evaluateFunctionInvoke(descriptor, args, resultLifetime)
|
return evaluateFunctionInvoke(descriptor, argsWithContinuationIfNeeded, resultLifetime)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (descriptor.isIntrinsic) {
|
if (descriptor.isIntrinsic) {
|
||||||
return evaluateIntrinsicCall(callee, args)
|
return evaluateIntrinsicCall(callee, argsWithContinuationIfNeeded)
|
||||||
}
|
}
|
||||||
|
|
||||||
when (descriptor) {
|
when (descriptor) {
|
||||||
is IrBuiltinOperatorDescriptorBase -> return evaluateOperatorCall (callee, args)
|
is IrBuiltinOperatorDescriptorBase -> return evaluateOperatorCall (callee, argsWithContinuationIfNeeded)
|
||||||
is ConstructorDescriptor -> return evaluateConstructorCall (callee, args)
|
is ConstructorDescriptor -> return evaluateConstructorCall (callee, argsWithContinuationIfNeeded)
|
||||||
else -> return evaluateSimpleFunctionCall(
|
else -> return evaluateSimpleFunctionCall(
|
||||||
descriptor, args, resultLifetime, callee.superQualifier)
|
descriptor, argsWithContinuationIfNeeded, resultLifetime, callee.superQualifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1870,6 +1958,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
codegen.icmpEq(arg0, arg1)
|
codegen.icmpEq(arg0, arg1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"konan.internal.getContinuation" -> return getContinuation()
|
||||||
}
|
}
|
||||||
|
|
||||||
val interop = context.interopBuiltIns
|
val interop = context.interopBuiltIns
|
||||||
@@ -1913,6 +2002,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
private val kImmOne = LLVMConstInt(LLVMInt32Type(), 1, 1)!!
|
private val kImmOne = LLVMConstInt(LLVMInt32Type(), 1, 1)!!
|
||||||
private val kTrue = LLVMConstInt(LLVMInt1Type(), 1, 1)!!
|
private val kTrue = LLVMConstInt(LLVMInt1Type(), 1, 1)!!
|
||||||
private val kFalse = LLVMConstInt(LLVMInt1Type(), 0, 1)!!
|
private val kFalse = LLVMConstInt(LLVMInt1Type(), 0, 1)!!
|
||||||
|
private val kIntPtrZero = LLVMConstInt(codegen.intPtrType, 0, 1)!!
|
||||||
|
|
||||||
|
|
||||||
private fun evaluateOperatorCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
|
private fun evaluateOperatorCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
|
||||||
|
|||||||
Reference in New Issue
Block a user