mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
This patch updates the asynchronous main function to run the first thunk
of the function synchronously through a call to `swift_job_run`.
The runloop is killed by exiting or aborting the task that it is running
on. As such, we need to ensure that the task contains an async function
that either calls exit explicitly or aborts. The AsyncEntryPoint, that
contains this code, was added in the previous patch. This patch adds the
pieces for the actual implementation of this behaviour as well as adding
the necessary code to start the runloop.
There are now four layers of main functions before hitting the "real"
code.
@main: This is the actual main entrypoint of the program. This
constructs the task containing @async_main, grabs the main executor,
runs swift_job_run to run the first part synchronously, and finally
kicks off the runloop with a call to _asyncMainDrainQueue. This is
generated in the call to `emitAsyncMainThreadStart`.
@async_main: This thunk exists to ensure that the main function calls
`exit` at some point so that the runloop stops. It also handles emitting
an error if the user-written main function throws.
e.g:
```
func async_main() async -> () {
do {
try await Main.$main()
exit(0)
} catch {
_errorInMain(error)
}
}
```
Main.$main(): This still has the same behaviour as with the
synchronous case. It just calls `try await Main.main()` and exists to
simplify typechecking.
Main.main(): This is the actual user-specified main. It serves the same
purpose as in the synchronous, allowing the programmer to write code,
but it's async!
The control flow in `emitFunctionDefinition` is a little confusing (to
me anyway), so here it is spelled out:
If the main function is synchronous, the `constant.kind` will be a
`SILDeclRef::Kind::EntryPoint`, but the `decl` won't be async, so it
drops down to `emitArtificalTopLevel` anyway.
If the main function is async and we're generating `@main`, the
`constant.kind` will be `SILDeclRef::Kind::AsyncEntryPoint`, so we also
call `emitArtificalTopLevel`. `emitArtificalTopLevel` is responsible for
detecting whether the decl is async and deciding whether to emit code to
extract the argc/argv variables that get passed into the actual main
entrypoint to the program. If we're generating the `@async_main` body,
the kind will be `SILDeclRef::Kind::EntryPoint` and the `decl` will be
async, so we grab the mainEntryPoint decl and call
`emitAsyncMainThreadStart` to generate the wrapping code.
Note; there is a curious change in `SILLocation::getSourceLoc()`
where instead of simply checking `isFilenameAndLocation()`, I change it
to `getStorageKind() == FilenameAndLocationKind`. This is because the
SILLocation returned is to a FilenameAndLocationKind, but the actual
storage returns true for the call to `isNull()` inside of the
`isFilenameAndLocation()` call. This results in us incorrectly falling
through to the `getASTNode()` call below that, which asserts when asked
to get the AST node of a location.
I also did a little bit of refactoring in the SILGenModule for grabbing
intrinsics. Previously, there was only a `getConcurrencyIntrinsic`
function, which would only load FuncDecls out of the concurrency
module. The `exit` function is in the concurrency shims module, so I
refactored the load code to take a ModuleDecl to search from.
The emitBuiltinCreateAsyncTask function symbol is exposed from
SILGenBuiltin so that it is available from SILGenFunction. There is a
fair bit of work involved going from what is available at the SGF to
what is needed for actually calling the CreateAsyncTask builtin, so in
order to avoid additional maintenance, it's good to re-use that.
245 lines
7.6 KiB
C++
245 lines
7.6 KiB
C++
//===--- SILLocation.cpp - Location information for SIL nodes -------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/SIL/SILLocation.h"
|
|
#include "swift/SIL/SILModule.h"
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/Expr.h"
|
|
#include "swift/AST/Pattern.h"
|
|
#include "swift/AST/Stmt.h"
|
|
#include "swift/AST/Module.h"
|
|
#include "swift/Basic/SourceManager.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
using namespace swift;
|
|
|
|
static_assert(sizeof(SILLocation) <= 2 * sizeof(void *),
|
|
"SILLocation must stay small");
|
|
|
|
SILLocation::FilenameAndLocation *SILLocation::FilenameAndLocation::
|
|
alloc(unsigned line, unsigned column, StringRef filename, SILModule &module) {
|
|
return new (module) FilenameAndLocation(line, column, filename);
|
|
}
|
|
|
|
void SILLocation::FilenameAndLocation::dump() const { print(llvm::dbgs()); }
|
|
|
|
void SILLocation::FilenameAndLocation::print(raw_ostream &OS) const {
|
|
OS << filename << ':' << line << ':' << column;
|
|
}
|
|
|
|
SourceLoc SILLocation::getSourceLoc() const {
|
|
if (isSILFile())
|
|
return storage.sourceLoc;
|
|
|
|
// Don't crash if the location is a FilenameAndLocation.
|
|
// TODO: this is a workaround until rdar://problem/25225083 is implemented.
|
|
if (getStorageKind() == FilenameAndLocationKind)
|
|
return SourceLoc();
|
|
|
|
return getSourceLoc(getPrimaryASTNode());
|
|
}
|
|
|
|
SourceLoc SILLocation::getSourceLoc(ASTNodeTy N) const {
|
|
if (N.isNull())
|
|
return SourceLoc();
|
|
|
|
if (alwaysPointsToEnd() ||
|
|
is<CleanupLocation>() ||
|
|
is<ImplicitReturnLocation>())
|
|
return getEndSourceLoc(N);
|
|
|
|
// Use the start location for the ReturnKind.
|
|
if (is<ReturnLocation>())
|
|
return getStartSourceLoc(N);
|
|
|
|
if (auto *decl = N.dyn_cast<Decl*>())
|
|
return decl->getLoc();
|
|
if (auto *expr = N.dyn_cast<Expr*>())
|
|
return expr->getLoc();
|
|
if (auto *stmt = N.dyn_cast<Stmt*>())
|
|
return stmt->getStartLoc();
|
|
if (auto *patt = N.dyn_cast<Pattern*>())
|
|
return patt->getStartLoc();
|
|
llvm_unreachable("impossible SILLocation");
|
|
}
|
|
|
|
SourceLoc SILLocation::getSourceLocForDebugging() const {
|
|
if (isNull())
|
|
return SourceLoc();
|
|
|
|
if (isSILFile())
|
|
return storage.sourceLoc;
|
|
|
|
if (auto *expr = getPrimaryASTNode().dyn_cast<Expr*>()) {
|
|
// Code that has an autoclosure as location should not show up in
|
|
// the line table (rdar://problem/14627460). Note also that the
|
|
// closure function still has a valid DW_AT_decl_line. Depending
|
|
// on how we decide to resolve rdar://problem/14627460, we may
|
|
// want to use the regular getLoc instead and rather use the
|
|
// column info.
|
|
if (isa<AutoClosureExpr>(expr))
|
|
return SourceLoc();
|
|
}
|
|
|
|
if (hasASTNodeForDebugging())
|
|
return getSourceLoc(storage.extendedASTNodeLoc->forDebugging);
|
|
|
|
return getSourceLoc(getPrimaryASTNode());
|
|
}
|
|
|
|
SourceLoc SILLocation::getStartSourceLoc() const {
|
|
if (isAutoGenerated())
|
|
return SourceLoc();
|
|
if (isSILFile())
|
|
return storage.sourceLoc;
|
|
return getStartSourceLoc(getPrimaryASTNode());
|
|
}
|
|
|
|
SourceLoc SILLocation::getStartSourceLoc(ASTNodeTy N) {
|
|
if (auto *decl = N.dyn_cast<Decl*>())
|
|
return decl->getStartLoc();
|
|
if (auto *expr = N.dyn_cast<Expr*>())
|
|
return expr->getStartLoc();
|
|
if (auto *stmt = N.dyn_cast<Stmt*>())
|
|
return stmt->getStartLoc();
|
|
if (auto *patt = N.dyn_cast<Pattern*>())
|
|
return patt->getStartLoc();
|
|
llvm_unreachable("impossible SILLocation");
|
|
}
|
|
|
|
SourceLoc SILLocation::getEndSourceLoc() const {
|
|
if (isAutoGenerated())
|
|
return SourceLoc();
|
|
if (isSILFile())
|
|
return storage.sourceLoc;
|
|
return getEndSourceLoc(getPrimaryASTNode());
|
|
}
|
|
|
|
SourceLoc SILLocation::getEndSourceLoc(ASTNodeTy N) {
|
|
if (auto decl = N.dyn_cast<Decl*>())
|
|
return decl->getEndLoc();
|
|
if (auto expr = N.dyn_cast<Expr*>())
|
|
return expr->getEndLoc();
|
|
if (auto stmt = N.dyn_cast<Stmt*>())
|
|
return stmt->getEndLoc();
|
|
if (auto patt = N.dyn_cast<Pattern*>())
|
|
return patt->getEndLoc();
|
|
llvm_unreachable("impossible SILLocation");
|
|
}
|
|
|
|
DeclContext *SILLocation::getAsDeclContext() const {
|
|
if (!isASTNode())
|
|
return nullptr;
|
|
if (auto *D = getAsASTNode<Decl>())
|
|
return D->getInnermostDeclContext();
|
|
if (auto *E = getAsASTNode<Expr>())
|
|
if (auto *DC = dyn_cast<AbstractClosureExpr>(E))
|
|
return DC;
|
|
return nullptr;
|
|
}
|
|
|
|
SILLocation::FilenameAndLocation SILLocation::decode(SourceLoc Loc,
|
|
const SourceManager &SM) {
|
|
FilenameAndLocation DL;
|
|
if (Loc.isValid()) {
|
|
DL.filename = SM.getDisplayNameForLoc(Loc);
|
|
std::tie(DL.line, DL.column) = SM.getPresumedLineAndColumnForLoc(Loc);
|
|
}
|
|
return DL;
|
|
}
|
|
|
|
SILLocation::FilenameAndLocation *SILLocation::getCompilerGeneratedLoc() {
|
|
static FilenameAndLocation compilerGenerated({0, 0, "<compiler-generated>"});
|
|
return &compilerGenerated;
|
|
}
|
|
|
|
static void dumpSourceLoc(SourceLoc loc) {
|
|
if (!loc.isValid()) {
|
|
llvm::dbgs() << "<invalid loc>";
|
|
return;
|
|
}
|
|
const char *srcPtr = (const char *)loc.getOpaquePointerValue();
|
|
unsigned len = strnlen(srcPtr, 20);
|
|
if (len < 20) {
|
|
llvm::dbgs() << '"' << StringRef(srcPtr, len) << '"';
|
|
} else {
|
|
llvm::dbgs() << '"' << StringRef(srcPtr, 20) << "[...]\"";
|
|
}
|
|
}
|
|
|
|
void SILLocation::dump() const {
|
|
if (isNull()) {
|
|
llvm::dbgs() << "<no loc>";
|
|
return;
|
|
}
|
|
if (auto D = getAsASTNode<Decl>())
|
|
llvm::dbgs() << Decl::getKindName(D->getKind()) << "Decl @ ";
|
|
if (auto E = getAsASTNode<Expr>())
|
|
llvm::dbgs() << Expr::getKindName(E->getKind()) << "Expr @ ";
|
|
if (auto S = getAsASTNode<Stmt>())
|
|
llvm::dbgs() << Stmt::getKindName(S->getKind()) << "Stmt @ ";
|
|
if (auto P = getAsASTNode<Pattern>())
|
|
llvm::dbgs() << Pattern::getKindName(P->getKind()) << "Pattern @ ";
|
|
|
|
if (isFilenameAndLocation()) {
|
|
getFilenameAndLocation()->dump();
|
|
} else {
|
|
dumpSourceLoc(getSourceLoc());
|
|
}
|
|
|
|
if (isAutoGenerated()) llvm::dbgs() << ":auto";
|
|
if (alwaysPointsToEnd()) llvm::dbgs() << ":end";
|
|
if (isInPrologue()) llvm::dbgs() << ":prologue";
|
|
if (isSILFile()) llvm::dbgs() << ":sil";
|
|
if (hasASTNodeForDebugging()) {
|
|
llvm::dbgs() << ":debug[";
|
|
dumpSourceLoc(getSourceLocForDebugging());
|
|
llvm::dbgs() << "]\n";
|
|
}
|
|
}
|
|
|
|
void SILLocation::print(raw_ostream &OS, const SourceManager &SM) const {
|
|
if (isNull()) {
|
|
OS << "<no loc>";
|
|
} else if (isFilenameAndLocation()) {
|
|
getFilenameAndLocation()->print(OS);
|
|
} else {
|
|
getSourceLoc().print(OS, SM);
|
|
}
|
|
}
|
|
|
|
RegularLocation::RegularLocation(Stmt *S, Pattern *P, SILModule &Module) :
|
|
SILLocation(new (Module) ExtendedASTNodeLoc(S, P), RegularKind) {}
|
|
|
|
ReturnLocation::ReturnLocation(ReturnStmt *RS) :
|
|
SILLocation(ASTNodeTy(RS), ReturnKind) {}
|
|
|
|
ReturnLocation::ReturnLocation(BraceStmt *BS) :
|
|
SILLocation(ASTNodeTy(BS), ReturnKind) {}
|
|
|
|
ImplicitReturnLocation::ImplicitReturnLocation(AbstractClosureExpr *E)
|
|
: SILLocation(ASTNodeTy(E), ImplicitReturnKind) { }
|
|
|
|
ImplicitReturnLocation::ImplicitReturnLocation(ReturnStmt *S)
|
|
: SILLocation(ASTNodeTy(S), ImplicitReturnKind) { }
|
|
|
|
ImplicitReturnLocation::ImplicitReturnLocation(AbstractFunctionDecl *AFD)
|
|
: SILLocation(ASTNodeTy(AFD), ImplicitReturnKind) { }
|
|
|
|
ImplicitReturnLocation::ImplicitReturnLocation(SILLocation L)
|
|
: SILLocation(L, ImplicitReturnKind) {
|
|
assert(L.isASTNode<Expr>() ||
|
|
L.isASTNode<ValueDecl>() ||
|
|
L.isASTNode<PatternBindingDecl>() ||
|
|
L.isNull());
|
|
}
|