Add AsyncEntryPoint SILDeclRef type

The AsyncEntryPoint represents the thunk that is wrapped in a task. This
thunk is used to ensure that the main function explicitly calls "exit",
and to properly unwrap and report any unhandled errors returned from the
user-written main. The function takes on the name `@async_main` in the
emitted SIL.
This commit is contained in:
Evan Wilde
2021-07-29 17:00:27 -07:00
parent b10c2c89a9
commit 552ae0635a
9 changed files with 67 additions and 3 deletions

View File

@@ -156,8 +156,11 @@ struct SILDeclRef {
/// The main entry-point function. This may reference a SourceFile for a /// The main entry-point function. This may reference a SourceFile for a
/// top-level main, or a decl for e.g an @main decl. /// top-level main, or a decl for e.g an @main decl.
EntryPoint, EntryPoint,
/// The asynchronous main entry-point function.
AsyncEntryPoint,
}; };
/// The AST node represented by this SILDeclRef. /// The AST node represented by this SILDeclRef.
Loc loc; Loc loc;
/// The Kind of this SILDeclRef. /// The Kind of this SILDeclRef.
@@ -231,6 +234,9 @@ struct SILDeclRef {
/// Produces a SILDeclRef for a synthetic main entry-point such as @main. /// Produces a SILDeclRef for a synthetic main entry-point such as @main.
static SILDeclRef getMainDeclEntryPoint(ValueDecl *decl); static SILDeclRef getMainDeclEntryPoint(ValueDecl *decl);
/// Produces a SILDeclRef for the synthesized async main entry-point
static SILDeclRef getAsyncMainDeclEntryPoint(ValueDecl *decl);
/// Produces a SILDeclRef for the entry-point of a main FileUnit. /// Produces a SILDeclRef for the entry-point of a main FileUnit.
static SILDeclRef getMainFileEntryPoint(FileUnit *file); static SILDeclRef getMainFileEntryPoint(FileUnit *file);

View File

@@ -474,6 +474,7 @@ namespace {
case SILDeclRef::Kind::PropertyWrapperBackingInitializer: case SILDeclRef::Kind::PropertyWrapperBackingInitializer:
case SILDeclRef::Kind::PropertyWrapperInitFromProjectedValue: case SILDeclRef::Kind::PropertyWrapperInitFromProjectedValue:
case SILDeclRef::Kind::EntryPoint: case SILDeclRef::Kind::EntryPoint:
case SILDeclRef::Kind::AsyncEntryPoint:
llvm_unreachable("Method does not have a selector"); llvm_unreachable("Method does not have a selector");
case SILDeclRef::Kind::Destroyer: case SILDeclRef::Kind::Destroyer:

View File

@@ -273,6 +273,8 @@ SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const {
// The main entry-point is public. // The main entry-point is public.
if (kind == Kind::EntryPoint) if (kind == Kind::EntryPoint)
return SILLinkage::Public; return SILLinkage::Public;
if (kind == Kind::AsyncEntryPoint)
return SILLinkage::Hidden;
// Add External to the linkage (e.g. Public -> PublicExternal) if this is a // Add External to the linkage (e.g. Public -> PublicExternal) if this is a
// declaration not a definition. // declaration not a definition.
@@ -448,6 +450,15 @@ SILDeclRef SILDeclRef::getMainDeclEntryPoint(ValueDecl *decl) {
return result; return result;
} }
SILDeclRef SILDeclRef::getAsyncMainDeclEntryPoint(ValueDecl *decl) {
auto *file = cast<FileUnit>(decl->getDeclContext()->getModuleScopeContext());
assert(file->getMainDecl() == decl);
SILDeclRef result;
result.loc = decl;
result.kind = Kind::AsyncEntryPoint;
return result;
}
SILDeclRef SILDeclRef::getMainFileEntryPoint(FileUnit *file) { SILDeclRef SILDeclRef::getMainFileEntryPoint(FileUnit *file) {
assert(file->hasEntryPoint() && !file->getMainDecl()); assert(file->hasEntryPoint() && !file->getMainDecl());
SILDeclRef result; SILDeclRef result;
@@ -539,7 +550,7 @@ IsSerialized_t SILDeclRef::isSerialized() const {
return IsNotSerialized; return IsNotSerialized;
} }
if (kind == Kind::EntryPoint) if (kind == Kind::EntryPoint || kind == Kind::AsyncEntryPoint)
return IsNotSerialized; return IsNotSerialized;
if (isIVarInitializerOrDestroyer()) if (isIVarInitializerOrDestroyer())
@@ -925,6 +936,9 @@ std::string SILDeclRef::mangle(ManglingKind MKind) const {
return mangler.mangleInitFromProjectedValueEntity(cast<VarDecl>(getDecl()), return mangler.mangleInitFromProjectedValueEntity(cast<VarDecl>(getDecl()),
SKind); SKind);
case SILDeclRef::Kind::AsyncEntryPoint: {
return "async_Main";
}
case SILDeclRef::Kind::EntryPoint: { case SILDeclRef::Kind::EntryPoint: {
return getASTContext().getEntryPointFunctionName(); return getASTContext().getEntryPointFunctionName();
} }
@@ -1257,7 +1271,8 @@ unsigned SILDeclRef::getParameterListCount() const {
return 1; return 1;
// Always uncurried even if the underlying function is curried. // Always uncurried even if the underlying function is curried.
if (kind == Kind::DefaultArgGenerator || kind == Kind::EntryPoint) if (kind == Kind::DefaultArgGenerator || kind == Kind::EntryPoint ||
kind == Kind::AsyncEntryPoint)
return 1; return 1;
auto *vd = getDecl(); auto *vd = getDecl();

View File

@@ -2526,6 +2526,9 @@ static CanSILFunctionType getNativeSILFunctionType(
case SILDeclRef::Kind::Deallocator: case SILDeclRef::Kind::Deallocator:
return getSILFunctionTypeForConventions(DeallocatorConventions()); return getSILFunctionTypeForConventions(DeallocatorConventions());
case SILDeclRef::Kind::AsyncEntryPoint:
return getSILFunctionTypeForConventions(
DefaultConventions(NormalParameterConvention::Guaranteed));
case SILDeclRef::Kind::EntryPoint: case SILDeclRef::Kind::EntryPoint:
llvm_unreachable("Handled by getSILFunctionTypeForAbstractCFunction"); llvm_unreachable("Handled by getSILFunctionTypeForAbstractCFunction");
} }
@@ -3071,6 +3074,7 @@ static ObjCSelectorFamily getObjCSelectorFamily(SILDeclRef c) {
case SILDeclRef::Kind::PropertyWrapperBackingInitializer: case SILDeclRef::Kind::PropertyWrapperBackingInitializer:
case SILDeclRef::Kind::PropertyWrapperInitFromProjectedValue: case SILDeclRef::Kind::PropertyWrapperInitFromProjectedValue:
case SILDeclRef::Kind::EntryPoint: case SILDeclRef::Kind::EntryPoint:
case SILDeclRef::Kind::AsyncEntryPoint:
llvm_unreachable("Unexpected Kind of foreign SILDeclRef"); llvm_unreachable("Unexpected Kind of foreign SILDeclRef");
} }
@@ -3343,6 +3347,8 @@ TypeConverter::getDeclRefRepresentation(SILDeclRef c) {
case SILDeclRef::Kind::IVarDestroyer: case SILDeclRef::Kind::IVarDestroyer:
return SILFunctionTypeRepresentation::Method; return SILFunctionTypeRepresentation::Method;
case SILDeclRef::Kind::AsyncEntryPoint:
return SILFunctionTypeRepresentation::Thin;
case SILDeclRef::Kind::EntryPoint: case SILDeclRef::Kind::EntryPoint:
return SILFunctionTypeRepresentation::CFunctionPointer; return SILFunctionTypeRepresentation::CFunctionPointer;
} }
@@ -4170,6 +4176,7 @@ static AbstractFunctionDecl *getBridgedFunction(SILDeclRef declRef) {
case SILDeclRef::Kind::IVarInitializer: case SILDeclRef::Kind::IVarInitializer:
case SILDeclRef::Kind::IVarDestroyer: case SILDeclRef::Kind::IVarDestroyer:
case SILDeclRef::Kind::EntryPoint: case SILDeclRef::Kind::EntryPoint:
case SILDeclRef::Kind::AsyncEntryPoint:
return nullptr; return nullptr;
} }
llvm_unreachable("bad SILDeclRef kind"); llvm_unreachable("bad SILDeclRef kind");

View File

@@ -316,6 +316,7 @@ void SILDeclRef::print(raw_ostream &OS) const {
switch (kind) { switch (kind) {
case SILDeclRef::Kind::Func: case SILDeclRef::Kind::Func:
case SILDeclRef::Kind::EntryPoint: case SILDeclRef::Kind::EntryPoint:
case SILDeclRef::Kind::AsyncEntryPoint:
break; break;
case SILDeclRef::Kind::Allocator: case SILDeclRef::Kind::Allocator:
OS << "!allocator"; OS << "!allocator";

View File

@@ -2556,6 +2556,32 @@ getFunctionInterfaceTypeWithCaptures(TypeConverter &TC,
innerExtInfo); innerExtInfo);
} }
static CanAnyFunctionType getAsyncEntryPoint(ASTContext &C) {
// @main struct Main {
// static func main() async throws {}
// static func $main() async throws { try await main() }
// }
//
// func @async_main() async -> Void {
// do {
// try await Main.$main()
// exit(0)
// } catch {
// _emitErrorInMain(error)
// }
// }
//
// This generates the type signature for @async_main
// TODO: 'Never' return type would be more accurate.
CanType returnType = C.getVoidType()->getCanonicalType();
FunctionType::ExtInfo extInfo =
FunctionType::ExtInfoBuilder().withAsync(true).withThrows(false).build();
return CanAnyFunctionType::get(/*genericSig*/ nullptr, {}, returnType,
extInfo);
}
static CanAnyFunctionType getEntryPointInterfaceType(ASTContext &C) { static CanAnyFunctionType getEntryPointInterfaceType(ASTContext &C) {
// Use standard library types if we have them; otherwise, fall back to // Use standard library types if we have them; otherwise, fall back to
// builtins. // builtins.
@@ -2675,6 +2701,8 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) {
case SILDeclRef::Kind::IVarDestroyer: case SILDeclRef::Kind::IVarDestroyer:
return getIVarInitDestroyerInterfaceType(cast<ClassDecl>(vd), return getIVarInitDestroyerInterfaceType(cast<ClassDecl>(vd),
c.isForeign, true); c.isForeign, true);
case SILDeclRef::Kind::AsyncEntryPoint:
return getAsyncEntryPoint(Context);
case SILDeclRef::Kind::EntryPoint: case SILDeclRef::Kind::EntryPoint:
return getEntryPointInterfaceType(Context); return getEntryPointInterfaceType(Context);
} }
@@ -2729,6 +2757,7 @@ TypeConverter::getConstantGenericSignature(SILDeclRef c) {
case SILDeclRef::Kind::StoredPropertyInitializer: case SILDeclRef::Kind::StoredPropertyInitializer:
return vd->getDeclContext()->getGenericSignatureOfContext(); return vd->getDeclContext()->getGenericSignatureOfContext();
case SILDeclRef::Kind::EntryPoint: case SILDeclRef::Kind::EntryPoint:
case SILDeclRef::Kind::AsyncEntryPoint:
llvm_unreachable("Doesn't have generic signature"); llvm_unreachable("Doesn't have generic signature");
} }

View File

@@ -1039,6 +1039,7 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) {
postEmitFunction(constant, f); postEmitFunction(constant, f);
return; return;
} }
case SILDeclRef::Kind::AsyncEntryPoint:
case SILDeclRef::Kind::EntryPoint: { case SILDeclRef::Kind::EntryPoint: {
f->setBare(IsBare); f->setBare(IsBare);

View File

@@ -141,6 +141,7 @@ DeclName SILGenModule::getMagicFunctionName(SILDeclRef ref) {
case SILDeclRef::Kind::EnumElement: case SILDeclRef::Kind::EnumElement:
return getMagicFunctionName(cast<EnumElementDecl>(ref.getDecl()) return getMagicFunctionName(cast<EnumElementDecl>(ref.getDecl())
->getDeclContext()); ->getDeclContext());
case SILDeclRef::Kind::AsyncEntryPoint:
case SILDeclRef::Kind::EntryPoint: case SILDeclRef::Kind::EntryPoint:
auto *file = ref.getDecl()->getDeclContext()->getParentSourceFile(); auto *file = ref.getDecl()->getDeclContext()->getParentSourceFile();
return getMagicFunctionName(file); return getMagicFunctionName(file);

View File

@@ -638,6 +638,9 @@ public:
/// application based on a main type and optionally a main type. /// application based on a main type and optionally a main type.
void emitArtificialTopLevel(Decl *mainDecl); void emitArtificialTopLevel(Decl *mainDecl);
/// Generate code into @main for starting the async main on the main thread.
void emitAsyncMainThreadStart(SILDeclRef entryPoint);
/// Generates code for a class deallocating destructor. This /// Generates code for a class deallocating destructor. This
/// calls the destroying destructor and then deallocates 'self'. /// calls the destroying destructor and then deallocates 'self'.
void emitDeallocatingDestructor(DestructorDecl *dd); void emitDeallocatingDestructor(DestructorDecl *dd);