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?
|
||||
internal fun RuntimeAware.getLlvmFunctionType(function: FunctionDescriptor): LLVMTypeRef {
|
||||
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) })
|
||||
if (original.isSuspend)
|
||||
paramTypes.add(kObjHeaderPtr) // Suspend functions have implicit parameter of type Continuation<>.
|
||||
if (isObjectType(returnType)) paramTypes.add(kObjHeaderPtrPtr)
|
||||
|
||||
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.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
@@ -400,6 +399,17 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
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 {
|
||||
|
||||
+117
-27
@@ -19,15 +19,19 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
||||
import kotlinx.cinterop.*
|
||||
import llvm.*
|
||||
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.KonanConfigKeys
|
||||
import org.jetbrains.kotlin.backend.konan.KonanPhase
|
||||
import org.jetbrains.kotlin.backend.konan.PhaseManager
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
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.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
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.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
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.TypeUtils
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
@@ -197,6 +203,7 @@ internal interface CodeContext {
|
||||
* @return the requested value
|
||||
*/
|
||||
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 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) {
|
||||
|
||||
context.llvm.fileInitializers.clear()
|
||||
@@ -610,30 +620,33 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
private fun evaluateExpression(value: IrExpression): LLVMValueRef {
|
||||
when (value) {
|
||||
is IrTypeOperatorCall -> return evaluateTypeOperator (value)
|
||||
is IrCall -> return evaluateCall (value)
|
||||
is IrTypeOperatorCall -> return evaluateTypeOperator (value)
|
||||
is IrCall -> return evaluateCall (value)
|
||||
is IrDelegatingConstructorCall ->
|
||||
return evaluateCall(value)
|
||||
return evaluateCall (value)
|
||||
is IrInstanceInitializerCall ->
|
||||
return evaluateInstanceInitializerCall(value)
|
||||
is IrGetValue -> return evaluateGetValue (value)
|
||||
is IrSetVariable -> return evaluateSetVariable (value)
|
||||
is IrGetField -> return evaluateGetField (value)
|
||||
is IrSetField -> return evaluateSetField (value)
|
||||
is IrConst<*> -> return evaluateConst (value)
|
||||
is IrReturn -> return evaluateReturn (value)
|
||||
is IrWhen -> return evaluateWhen (value)
|
||||
is IrThrow -> return evaluateThrow (value)
|
||||
is IrTry -> return evaluateTry (value)
|
||||
is IrInlineFunctionBody -> return evaluateInlineFunction (value)
|
||||
is IrContainerExpression -> return evaluateContainerExpression(value)
|
||||
is IrWhileLoop -> return evaluateWhileLoop (value)
|
||||
is IrDoWhileLoop -> return evaluateDoWhileLoop (value)
|
||||
is IrVararg -> return evaluateVararg (value)
|
||||
is IrBreak -> return evaluateBreak (value)
|
||||
is IrContinue -> return evaluateContinue (value)
|
||||
is IrGetObjectValue -> return evaluateGetObjectValue (value)
|
||||
is IrCallableReference -> return evaluateCallableReference (value)
|
||||
is IrGetValue -> return evaluateGetValue (value)
|
||||
is IrSetVariable -> return evaluateSetVariable (value)
|
||||
is IrGetField -> return evaluateGetField (value)
|
||||
is IrSetField -> return evaluateSetField (value)
|
||||
is IrConst<*> -> return evaluateConst (value)
|
||||
is IrReturn -> return evaluateReturn (value)
|
||||
is IrWhen -> return evaluateWhen (value)
|
||||
is IrThrow -> return evaluateThrow (value)
|
||||
is IrTry -> return evaluateTry (value)
|
||||
is IrInlineFunctionBody -> return evaluateInlineFunction (value)
|
||||
is IrContainerExpression -> return evaluateContainerExpression (value)
|
||||
is IrWhileLoop -> return evaluateWhileLoop (value)
|
||||
is IrDoWhileLoop -> return evaluateDoWhileLoop (value)
|
||||
is IrVararg -> return evaluateVararg (value)
|
||||
is IrBreak -> return evaluateBreak (value)
|
||||
is IrContinue -> return evaluateContinue (value)
|
||||
is IrGetObjectValue -> return evaluateGetObjectValue (value)
|
||||
is IrCallableReference -> return evaluateCallableReference (value)
|
||||
is IrSuspendableExpression ->
|
||||
return evaluateSuspendableExpression (value)
|
||||
is IrSuspensionPoint -> return evaluateSuspensionPoint (value)
|
||||
else -> {
|
||||
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.
|
||||
* 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>,
|
||||
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) {
|
||||
return evaluateFunctionInvoke(descriptor, args, resultLifetime)
|
||||
return evaluateFunctionInvoke(descriptor, argsWithContinuationIfNeeded, resultLifetime)
|
||||
}
|
||||
|
||||
if (descriptor.isIntrinsic) {
|
||||
return evaluateIntrinsicCall(callee, args)
|
||||
return evaluateIntrinsicCall(callee, argsWithContinuationIfNeeded)
|
||||
}
|
||||
|
||||
when (descriptor) {
|
||||
is IrBuiltinOperatorDescriptorBase -> return evaluateOperatorCall (callee, args)
|
||||
is ConstructorDescriptor -> return evaluateConstructorCall (callee, args)
|
||||
is IrBuiltinOperatorDescriptorBase -> return evaluateOperatorCall (callee, argsWithContinuationIfNeeded)
|
||||
is ConstructorDescriptor -> return evaluateConstructorCall (callee, argsWithContinuationIfNeeded)
|
||||
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)
|
||||
}
|
||||
}
|
||||
"konan.internal.getContinuation" -> return getContinuation()
|
||||
}
|
||||
|
||||
val interop = context.interopBuiltIns
|
||||
@@ -1913,6 +2002,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
private val kImmOne = LLVMConstInt(LLVMInt32Type(), 1, 1)!!
|
||||
private val kTrue = LLVMConstInt(LLVMInt1Type(), 1, 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 {
|
||||
|
||||
Reference in New Issue
Block a user