Codegen: coroutines support

This commit is contained in:
Igor Chevdar
2017-04-25 17:21:07 +03:00
parent bd6a091088
commit 01b6ab74a5
3 changed files with 135 additions and 29 deletions
@@ -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())
@@ -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 {
@@ -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 {