Skip to content

Commit c79de40

Browse files
committed
IRGen: Emit async function pointers for resilient class and protocol dispatch thunks
This adds new kinds of link entities corresponding to the three dispatch thunk link entity kinds: - DispatchThunkAsyncFunctionPointer - DispatchThunkInitializerAsyncFunctionPointer - DispatchThunkAllocatorAsyncFunctionPointer
1 parent 8440a82 commit c79de40

File tree

12 files changed

+199
-17
lines changed

12 files changed

+199
-17
lines changed

include/swift/IRGen/Linking.h

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,20 @@ class LinkEntity {
134134
/// a ConstructorDecl* inside a protocol or a class.
135135
DispatchThunkAllocator,
136136

137+
/// An async function pointer for a method dispatch thunk. The pointer is
138+
/// a FuncDecl* inside a protocol or a class.
139+
DispatchThunkAsyncFunctionPointer,
140+
141+
/// An async function pointer for a method dispatch thunk for an
142+
/// initializing constructor. The pointer is a ConstructorDecl* inside a
143+
/// class.
144+
DispatchThunkInitializerAsyncFunctionPointer,
145+
146+
/// An async function pointer for a method dispatch thunk for an allocating
147+
/// constructor. The pointer is a ConstructorDecl* inside a protocol or
148+
/// a class.
149+
DispatchThunkAllocatorAsyncFunctionPointer,
150+
137151
/// A method descriptor. The pointer is a FuncDecl* inside a protocol
138152
/// or a class.
139153
MethodDescriptor,
@@ -1103,15 +1117,30 @@ class LinkEntity {
11031117

11041118
static LinkEntity forAsyncFunctionPointer(LinkEntity other) {
11051119
LinkEntity entity;
1120+
entity.Pointer = other.Pointer;
1121+
entity.SecondaryPointer = nullptr;
11061122

11071123
switch (other.getKind()) {
11081124
case LinkEntity::Kind::SILFunction:
1109-
entity.Pointer = other.getSILFunction();
1110-
entity.SecondaryPointer = nullptr;
11111125
entity.Data = LINKENTITY_SET_FIELD(
11121126
Kind, unsigned(LinkEntity::Kind::AsyncFunctionPointer));
11131127
break;
11141128

1129+
case LinkEntity::Kind::DispatchThunk:
1130+
entity.Data = LINKENTITY_SET_FIELD(
1131+
Kind, unsigned(LinkEntity::Kind::DispatchThunkAsyncFunctionPointer));
1132+
break;
1133+
1134+
case LinkEntity::Kind::DispatchThunkInitializer:
1135+
entity.Data = LINKENTITY_SET_FIELD(
1136+
Kind, unsigned(LinkEntity::Kind::DispatchThunkInitializerAsyncFunctionPointer));
1137+
break;
1138+
1139+
case LinkEntity::Kind::DispatchThunkAllocator:
1140+
entity.Data = LINKENTITY_SET_FIELD(
1141+
Kind, unsigned(LinkEntity::Kind::DispatchThunkAllocatorAsyncFunctionPointer));
1142+
break;
1143+
11151144
default:
11161145
llvm_unreachable("Link entity kind cannot have an async function pointer");
11171146
}
@@ -1125,6 +1154,39 @@ class LinkEntity {
11251154
return entity;
11261155
}
11271156

1157+
LinkEntity getUnderlyingEntityForAsyncFunctionPointer() const {
1158+
LinkEntity entity;
1159+
entity.Pointer = Pointer;
1160+
entity.SecondaryPointer = nullptr;
1161+
1162+
switch (getKind()) {
1163+
case LinkEntity::Kind::AsyncFunctionPointer:
1164+
entity.Data = LINKENTITY_SET_FIELD(
1165+
Kind, unsigned(LinkEntity::Kind::SILFunction));
1166+
break;
1167+
1168+
case LinkEntity::Kind::DispatchThunkAsyncFunctionPointer:
1169+
entity.Data = LINKENTITY_SET_FIELD(
1170+
Kind, unsigned(LinkEntity::Kind::DispatchThunk));
1171+
break;
1172+
1173+
case LinkEntity::Kind::DispatchThunkInitializerAsyncFunctionPointer:
1174+
entity.Data = LINKENTITY_SET_FIELD(
1175+
Kind, unsigned(LinkEntity::Kind::DispatchThunkInitializer));
1176+
break;
1177+
1178+
case LinkEntity::Kind::DispatchThunkAllocatorAsyncFunctionPointer:
1179+
entity.Data = LINKENTITY_SET_FIELD(
1180+
Kind, unsigned(LinkEntity::Kind::DispatchThunkAllocator));
1181+
break;
1182+
1183+
default:
1184+
llvm_unreachable("Link entity is not an async function pointer");
1185+
}
1186+
1187+
return entity;
1188+
}
1189+
11281190
void mangle(llvm::raw_ostream &out) const;
11291191
void mangle(SmallVectorImpl<char> &buffer) const;
11301192
std::string mangleAsString() const;

lib/IRGen/GenCall.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/ASTContext.h"
2121
#include "swift/AST/GenericEnvironment.h"
2222
#include "swift/Runtime/Config.h"
23+
#include "swift/IRGen/Linking.h"
2324
#include "swift/SIL/SILModule.h"
2425
#include "swift/SIL/SILType.h"
2526
#include "clang/AST/ASTContext.h"
@@ -379,7 +380,7 @@ llvm::CallInst *IRGenFunction::emitSuspendAsyncCall(ArrayRef<llvm::Value *> args
379380
auto *calleeContext = Builder.CreateExtractValue(id,
380381
(unsigned)AsyncFunctionArgumentIndex::Context);
381382
llvm::Constant *projectFn = cast<llvm::Constant>(args[1])->stripPointerCasts();
382-
// Get the caller context from the calle context.
383+
// Get the caller context from the callee context.
383384
llvm::Value *context = Builder.CreateCall(projectFn, {calleeContext});
384385
context = Builder.CreateBitCast(context, IGM.SwiftContextPtrTy);
385386
Builder.CreateStore(context, asyncContextLocation);
@@ -3586,9 +3587,10 @@ emitRetconCoroutineEntry(IRGenFunction &IGF, CanSILFunctionType fnType,
35863587
}
35873588

35883589
void irgen::emitAsyncFunctionEntry(IRGenFunction &IGF,
3589-
SILFunction *asyncFunction) {
3590+
const AsyncContextLayout &layout,
3591+
LinkEntity asyncFunction) {
35903592
auto &IGM = IGF.IGM;
3591-
auto size = getAsyncContextLayout(IGM, asyncFunction).getSize();
3593+
auto size = layout.getSize();
35923594
auto asyncFuncPointer = IGF.Builder.CreateBitOrPointerCast(
35933595
IGM.getAddrOfAsyncFunctionPointer(asyncFunction), IGM.Int8PtrTy);
35943596
auto *id = IGF.Builder.CreateIntrinsicCall(

lib/IRGen/GenCall.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,9 @@ namespace irgen {
414414
Address emitAllocAsyncContext(IRGenFunction &IGF, llvm::Value *sizeValue);
415415
void emitDeallocAsyncContext(IRGenFunction &IGF, Address context);
416416

417-
void emitAsyncFunctionEntry(IRGenFunction &IGF, SILFunction *asyncFunc);
417+
void emitAsyncFunctionEntry(IRGenFunction &IGF,
418+
const AsyncContextLayout &layout,
419+
LinkEntity asyncFunction);
418420

419421
/// Yield the given values from the current continuation.
420422
///

lib/IRGen/GenThunk.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@ static FunctionPointer lookupMethod(IRGenFunction &IGF, SILDeclRef declRef) {
8181
return layout;
8282
};
8383

84+
if (funcTy->isAsync()) {
85+
auto layout = getAsyncContextLayout();
86+
auto entity = LinkEntity::forDispatchThunk(declRef);
87+
emitAsyncFunctionEntry(IGF, layout, entity);
88+
emitAsyncFunctionPointer(IGF.IGM, IGF.CurFn, entity, layout.getSize());
89+
}
90+
8491
// Protocol case.
8592
if (isa<ProtocolDecl>(decl->getDeclContext())) {
8693
// Find the witness table.
@@ -162,12 +169,18 @@ void IRGenModule::emitDispatchThunk(SILDeclRef declRef) {
162169
IGF.Builder.CreateRet(result);
163170
}
164171

172+
llvm::Constant *
173+
IRGenModule::getAddrOfAsyncFunctionPointer(LinkEntity entity) {
174+
return getAddrOfLLVMVariable(
175+
LinkEntity::forAsyncFunctionPointer(entity),
176+
NotForDefinition, DebugTypeInfo());
177+
}
178+
165179
llvm::Constant *
166180
IRGenModule::getAddrOfAsyncFunctionPointer(SILFunction *function) {
167181
(void)getAddrOfSILFunction(function, NotForDefinition);
168-
auto entity = LinkEntity::forAsyncFunctionPointer(
182+
return getAddrOfAsyncFunctionPointer(
169183
LinkEntity::forSILFunction(function));
170-
return getAddrOfLLVMVariable(entity, NotForDefinition, DebugTypeInfo());
171184
}
172185

173186
llvm::Constant *IRGenModule::defineAsyncFunctionPointer(LinkEntity entity,

lib/IRGen/IRGenModule.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,6 +1396,7 @@ private: \
13961396
/// Cast the given constant to i8*.
13971397
llvm::Constant *getOpaquePtr(llvm::Constant *pointer);
13981398

1399+
llvm::Constant *getAddrOfAsyncFunctionPointer(LinkEntity entity);
13991400
llvm::Constant *getAddrOfAsyncFunctionPointer(SILFunction *function);
14001401
llvm::Constant *defineAsyncFunctionPointer(LinkEntity entity,
14011402
ConstantInit init);

lib/IRGen/IRGenSIL.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1722,7 +1722,9 @@ static void emitEntryPointArgumentsNativeCC(IRGenSILFunction &IGF,
17221722
}
17231723

17241724
if (funcTy->isAsync()) {
1725-
emitAsyncFunctionEntry(IGF, IGF.CurSILFn);
1725+
emitAsyncFunctionEntry(IGF,
1726+
getAsyncContextLayout(IGF.IGM, IGF.CurSILFn),
1727+
LinkEntity::forSILFunction(IGF.CurSILFn));
17261728
}
17271729

17281730
SILFunctionConventions conv(funcTy, IGF.getSILModule());

lib/IRGen/Linking.cpp

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -430,11 +430,17 @@ std::string LinkEntity::mangleAsString() const {
430430
return mangler.mangleSILDifferentiabilityWitnessKey(
431431
{getSILDifferentiabilityWitness()->getOriginalFunction()->getName(),
432432
getSILDifferentiabilityWitness()->getConfig()});
433-
case Kind::AsyncFunctionPointer: {
434-
std::string Result(getSILFunction()->getName());
433+
434+
case Kind::AsyncFunctionPointer:
435+
case Kind::DispatchThunkAsyncFunctionPointer:
436+
case Kind::DispatchThunkInitializerAsyncFunctionPointer:
437+
case Kind::DispatchThunkAllocatorAsyncFunctionPointer: {
438+
std::string Result(getUnderlyingEntityForAsyncFunctionPointer()
439+
.mangleAsString());
435440
Result.append("Tu");
436441
return Result;
437442
}
443+
438444
case Kind::AsyncFunctionPointerAST: {
439445
std::string Result;
440446
Result = mangler.mangleEntity(getDecl());
@@ -570,7 +576,6 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
570576
case Kind::CoroutineContinuationPrototype:
571577
return SILLinkage::PublicExternal;
572578

573-
574579
case Kind::ObjCResilientClassStub: {
575580
switch (getMetadataAddress()) {
576581
case TypeMetadataAddress::FullMetadata:
@@ -674,7 +679,6 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
674679
case Kind::DynamicallyReplaceableFunctionKey:
675680
return getSILFunction()->getLinkage();
676681

677-
case Kind::AsyncFunctionPointer:
678682
case Kind::SILFunction:
679683
return getSILFunction()->getEffectiveSymbolLinkage();
680684

@@ -714,6 +718,13 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
714718
return SILLinkage::Shared;
715719
case Kind::DifferentiabilityWitness:
716720
return getSILDifferentiabilityWitness()->getLinkage();
721+
722+
case Kind::AsyncFunctionPointer:
723+
case Kind::DispatchThunkAsyncFunctionPointer:
724+
case Kind::DispatchThunkInitializerAsyncFunctionPointer:
725+
case Kind::DispatchThunkAllocatorAsyncFunctionPointer:
726+
return getUnderlyingEntityForAsyncFunctionPointer()
727+
.getLinkage(ForDefinition);
717728
}
718729
llvm_unreachable("bad link entity kind");
719730
}
@@ -733,6 +744,9 @@ bool LinkEntity::isContextDescriptor() const {
733744
case Kind::DispatchThunk:
734745
case Kind::DispatchThunkInitializer:
735746
case Kind::DispatchThunkAllocator:
747+
case Kind::DispatchThunkAsyncFunctionPointer:
748+
case Kind::DispatchThunkInitializerAsyncFunctionPointer:
749+
case Kind::DispatchThunkAllocatorAsyncFunctionPointer:
736750
case Kind::MethodDescriptor:
737751
case Kind::MethodDescriptorInitializer:
738752
case Kind::MethodDescriptorAllocator:
@@ -797,8 +811,6 @@ bool LinkEntity::isContextDescriptor() const {
797811

798812
llvm::Type *LinkEntity::getDefaultDeclarationType(IRGenModule &IGM) const {
799813
switch (getKind()) {
800-
case Kind::AsyncFunctionPointer:
801-
return IGM.AsyncFunctionPointerTy;
802814
case Kind::ModuleDescriptor:
803815
case Kind::ExtensionDescriptor:
804816
case Kind::AnonymousDescriptor:
@@ -901,6 +913,12 @@ llvm::Type *LinkEntity::getDefaultDeclarationType(IRGenModule &IGM) const {
901913
return IGM.DifferentiabilityWitnessTy;
902914
case Kind::CanonicalPrespecializedGenericTypeCachingOnceToken:
903915
return IGM.OnceTy;
916+
case Kind::AsyncFunctionPointer:
917+
case Kind::DispatchThunkAsyncFunctionPointer:
918+
case Kind::DispatchThunkInitializerAsyncFunctionPointer:
919+
case Kind::DispatchThunkAllocatorAsyncFunctionPointer:
920+
case Kind::AsyncFunctionPointerAST:
921+
return IGM.AsyncFunctionPointerTy;
904922
default:
905923
llvm_unreachable("declaration LLVM type not specified");
906924
}
@@ -929,6 +947,9 @@ Alignment LinkEntity::getAlignment(IRGenModule &IGM) const {
929947
case Kind::OpaqueTypeDescriptor:
930948
return Alignment(4);
931949
case Kind::AsyncFunctionPointer:
950+
case Kind::DispatchThunkAsyncFunctionPointer:
951+
case Kind::DispatchThunkInitializerAsyncFunctionPointer:
952+
case Kind::DispatchThunkAllocatorAsyncFunctionPointer:
932953
case Kind::ObjCClassRef:
933954
case Kind::ObjCClass:
934955
case Kind::TypeMetadataLazyCacheVariable:
@@ -971,7 +992,6 @@ bool LinkEntity::isWeakImported(ModuleDecl *module) const {
971992
return getSILGlobalVariable()->getDecl()->isWeakImported(module);
972993
}
973994
return false;
974-
case Kind::AsyncFunctionPointer:
975995
case Kind::DynamicallyReplaceableFunctionKey:
976996
case Kind::DynamicallyReplaceableFunctionVariable:
977997
case Kind::SILFunction: {
@@ -1068,6 +1088,13 @@ bool LinkEntity::isWeakImported(ModuleDecl *module) const {
10681088
case Kind::CoroutineContinuationPrototype:
10691089
case Kind::DifferentiabilityWitness:
10701090
return false;
1091+
1092+
case Kind::AsyncFunctionPointer:
1093+
case Kind::DispatchThunkAsyncFunctionPointer:
1094+
case Kind::DispatchThunkInitializerAsyncFunctionPointer:
1095+
case Kind::DispatchThunkAllocatorAsyncFunctionPointer:
1096+
return getUnderlyingEntityForAsyncFunctionPointer()
1097+
.isWeakImported(module);
10711098
}
10721099

10731100
llvm_unreachable("Bad link entity kind");
@@ -1118,7 +1145,6 @@ DeclContext *LinkEntity::getDeclContextForEmission() const {
11181145
case Kind::CanonicalSpecializedGenericSwiftMetaclassStub:
11191146
return getType()->getClassOrBoundGenericClass()->getDeclContext();
11201147

1121-
case Kind::AsyncFunctionPointer:
11221148
case Kind::SILFunction:
11231149
case Kind::DynamicallyReplaceableFunctionVariable:
11241150
case Kind::DynamicallyReplaceableFunctionKey:
@@ -1174,6 +1200,13 @@ DeclContext *LinkEntity::getDeclContextForEmission() const {
11741200
case Kind::ValueWitnessTable:
11751201
case Kind::DifferentiabilityWitness:
11761202
return nullptr;
1203+
1204+
case Kind::AsyncFunctionPointer:
1205+
case Kind::DispatchThunkAsyncFunctionPointer:
1206+
case Kind::DispatchThunkInitializerAsyncFunctionPointer:
1207+
case Kind::DispatchThunkAllocatorAsyncFunctionPointer:
1208+
return getUnderlyingEntityForAsyncFunctionPointer()
1209+
.getDeclContextForEmission();
11771210
}
11781211
llvm_unreachable("invalid decl kind");
11791212
}

lib/TBDGen/TBDGen.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,9 @@ void TBDGenVisitor::addSymbol(LinkEntity entity) {
449449
void TBDGenVisitor::addDispatchThunk(SILDeclRef declRef) {
450450
auto entity = LinkEntity::forDispatchThunk(declRef);
451451
addSymbol(entity);
452+
453+
if (declRef.getAbstractFunctionDecl()->hasAsync())
454+
addSymbol(LinkEntity::forAsyncFunctionPointer(entity));
452455
}
453456

454457
void TBDGenVisitor::addMethodDescriptor(SILDeclRef declRef) {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
open class BaseClass<T> {
2+
var value: T
3+
4+
open func wait() async -> T {
5+
return value
6+
}
7+
8+
public init(_ value: T) {
9+
self.value = value
10+
}
11+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
public protocol Awaitable {
2+
associatedtype Result
3+
func wait() async -> Result
4+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -enable-experimental-concurrency -enable-library-evolution -emit-module-path=%t/resilient_class.swiftmodule -module-name=resilient_class %S/Inputs/resilient_class.swift
3+
// RUN: %target-swift-frontend -I %t -emit-ir -enable-experimental-concurrency -enable-library-evolution %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-cpu %s
4+
5+
import resilient_class
6+
7+
open class MyBaseClass<T> {
8+
var value: T
9+
10+
open func wait() async -> T {
11+
return value
12+
}
13+
14+
open func waitThrows() async throws -> T {
15+
return value
16+
}
17+
18+
// FIXME
19+
// open func waitGeneric<T>(_: T) async -> T
20+
// open func waitGenericThrows<T>(_: T) async throws -> T
21+
22+
public init(_ value: T) {
23+
self.value = value
24+
}
25+
}
26+
27+
// CHECK-LABEL: @"$s16class_resilience11MyBaseClassC4waitxyYFTjTu" = {{(dllexport )?}}{{(protected )?}}global %swift.async_func_pointer
28+
29+
// CHECK-LABEL: define {{(dllexport )?}}{{(protected )?}}swiftcc void @"$s16class_resilience11MyBaseClassC4waitxyYFTj"(%swift.task* %0, %swift.executor* %1, %swift.context* swiftasync %2) #0 {

0 commit comments

Comments
 (0)