[concurrency] SILGen: emit @asyncHandler functions.

An asyncHandler function is split into two functions:
1. The asyncHandler body function: it contains the body of the function, but is emitted as an async function.
2. The original function: it just contains
      _runAsyncHandler(operation: asyncHandlerBodyFunction)

rdar://problem/71247879
This commit is contained in:
Erik Eckstein
2020-11-26 09:30:27 +01:00
parent 326e578bed
commit 8e03bd3e67
6 changed files with 130 additions and 5 deletions

View File

@@ -517,11 +517,11 @@ void SILGenFunction::emitFunction(FuncDecl *fd) {
fd->getResultInterfaceType(), fd->hasThrows(), fd->getThrowsLoc());
prepareEpilog(true, fd->hasThrows(), CleanupLocation(fd));
if (fd->isAsyncHandler()) {
// Async handlers are need to have their bodies emitted into a
// detached task.
// FIXME: Actually implement these properly.
B.createBuiltinTrap(fd->getTypecheckedBody());
if (fd->isAsyncHandler() &&
// If F.isAsync() we are emitting the asyncHandler body and not the
// original asyncHandler.
!F.isAsync()) {
emitAsyncHandler(fd);
} else {
emitStmt(fd->getTypecheckedBody());
}
@@ -531,6 +531,58 @@ void SILGenFunction::emitFunction(FuncDecl *fd) {
mergeCleanupBlocks();
}
/// An asyncHandler function is split into two functions:
/// 1. The asyncHandler body function: it contains the body of the function, but
/// is emitted as an async function.
/// 2. The original function: it just contains
/// _runAsyncHandler(operation: asyncHandlerBodyFunction)
void SILGenFunction::emitAsyncHandler(FuncDecl *fd) {
// 1. step: create the asyncHandler body function
//
auto origFnTy = F.getLoweredFunctionType();
assert(!F.isAsync() && "an asyncHandler function cannot be async");
// The body function type is the same as the original type, just with "async".
auto bodyFnTy = origFnTy->getWithExtInfo(origFnTy->getExtInfo().withAsync());
SILDeclRef constant(fd, SILDeclRef::Kind::Func);
std::string name = constant.mangle(SILDeclRef::ManglingKind::AsyncHandlerBody);
SILLocation loc = F.getLocation();
SILGenFunctionBuilder builder(*this);
SILFunction *bodyFn = builder.createFunction(
SILLinkage::Hidden, name, bodyFnTy, F.getGenericEnvironment(),
loc, F.isBare(), F.isTransparent(),
F.isSerialized(), IsNotDynamic, ProfileCounter(), IsNotThunk,
F.getClassSubclassScope(), F.getInlineStrategy(), F.getEffectsKind());
bodyFn->setDebugScope(new (getModule()) SILDebugScope(loc, bodyFn));
SILGenFunction(SGM, *bodyFn, fd).emitFunction(fd);
// 2. step: emit the original asyncHandler function
//
Scope scope(*this, loc);
// %bodyFnRef = partial_apply %bodyFn(%originalArg0, %originalArg1, ...)
//
SmallVector<ManagedValue, 4> managedArgs;
for (SILValue arg : F.getArguments()) {
ManagedValue argVal = ManagedValue(arg, CleanupHandle::invalid());
managedArgs.push_back(argVal.copy(*this, loc));
}
auto *bodyFnRef = B.createFunctionRef(loc, bodyFn);
ManagedValue bodyFnValue =
B.createPartialApply(loc, bodyFnRef, F.getForwardingSubstitutionMap(),
managedArgs, ParameterConvention::Direct_Guaranteed);
// apply %_runAsyncHandler(%bodyFnValue)
//
FuncDecl *asyncHandlerDecl = SGM.getRunAsyncHandler();
emitApplyOfLibraryIntrinsic(loc, asyncHandlerDecl, SubstitutionMap(),
{ bodyFnValue }, SGFContext());
}
void SILGenFunction::emitClosure(AbstractClosureExpr *ace) {
MagicFunctionName = SILGenModule::getMagicFunctionName(ace);