Skip to content

Commit 35d06c3

Browse files
committed
[CoroutineAccessors] Witness and vtable dispatch.
And thunking.
1 parent f5d03a6 commit 35d06c3

27 files changed

+527
-31
lines changed

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ NODE(DependentGenericInverseConformanceRequirement)
408408
NODE(Integer)
409409
NODE(NegativeInteger)
410410
NODE(DependentGenericParamValueMarker)
411+
NODE(CoroFunctionPointer)
411412

412413
#undef CONTEXT_NODE
413414
#undef NODE

include/swift/IRGen/Linking.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,11 @@ class LinkEntity {
585585
/// The pointer is the llvm::Function* for a partial apply forwarder.
586586
PartialApplyForwarderCoroFunctionPointer,
587587

588+
/// An coro function pointer to a function which is known to exist whose
589+
/// name is known.
590+
/// The pointer is a const char* of the name.
591+
KnownCoroFunctionPointer,
592+
588593
/// An coro function pointer for a distributed accessor (method or
589594
/// property).
590595
/// The pointer is a SILFunction*.
@@ -1553,6 +1558,15 @@ class LinkEntity {
15531558
return entity;
15541559
}
15551560

1561+
static LinkEntity forKnownCoroFunctionPointer(const char *name) {
1562+
LinkEntity entity;
1563+
entity.Pointer = const_cast<char *>(name);
1564+
entity.SecondaryPointer = nullptr;
1565+
entity.Data =
1566+
LINKENTITY_SET_FIELD(Kind, unsigned(Kind::KnownCoroFunctionPointer));
1567+
return entity;
1568+
}
1569+
15561570
LinkEntity getUnderlyingEntityForCoroFunctionPointer() const {
15571571
LinkEntity entity;
15581572
entity.Pointer = Pointer;

include/swift/SIL/SILDeclRef.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,7 @@ struct SILDeclRef {
612612
}
613613

614614
bool hasAsync() const;
615+
bool isCalleeAllocatedCoroutine() const;
615616

616617
private:
617618
friend struct llvm::DenseMapInfo<swift::SILDeclRef>;

lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10931,7 +10931,7 @@ bool AccessorDecl::isRequirementWithSynthesizedDefaultImplementation() const {
1093110931
if (!requiresFeatureCoroutineAccessors(getAccessorKind())) {
1093210932
return false;
1093310933
}
10934-
if (getStorage()->getOverrideLoc()) {
10934+
if (!requiresNewWitnessTableEntry()) {
1093510935
return false;
1093610936
}
1093710937
return getStorage()->requiresCorrespondingUnderscoredCoroutineAccessor(

lib/Demangling/NodePrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,7 @@ class NodePrinter {
657657
case Node::Kind::ObjectiveCProtocolSymbolicReference:
658658
case Node::Kind::DependentGenericInverseConformanceRequirement:
659659
case Node::Kind::DependentGenericParamValueMarker:
660+
case Node::Kind::CoroFunctionPointer:
660661
return false;
661662
}
662663
printer_unreachable("bad node kind");
@@ -3478,6 +3479,9 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth,
34783479
Printer << signedValue;
34793480
return nullptr;
34803481
}
3482+
case Node::Kind::CoroFunctionPointer:
3483+
Printer << "coro function pointer to ";
3484+
return nullptr;
34813485
}
34823486

34833487
printer_unreachable("bad node kind!");

lib/IRGen/Callee.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,11 @@ namespace irgen {
206206
FunctionPointerKind(SpecialKind kind)
207207
: value(unsigned(kind) + SpecialOffset) {}
208208
FunctionPointerKind(CanSILFunctionType fnType)
209-
: FunctionPointerKind(fnType->isAsync()
210-
? BasicKind::AsyncFunctionPointer
211-
: BasicKind::Function) {}
209+
: FunctionPointerKind(fnType->isAsync()
210+
? BasicKind::AsyncFunctionPointer
211+
: fnType->isCalleeAllocatedCoroutine()
212+
? BasicKind::CoroFunctionPointer
213+
: BasicKind::Function) {}
212214

213215
static FunctionPointerKind defaultSync() {
214216
return BasicKind::Function;

lib/IRGen/GenCall.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5151,13 +5151,11 @@ static llvm::Constant *getCoroAllocWrapperFn(IRGenModule &IGM) {
51515151
/*optionalLinkageOverride=*/nullptr, llvm::CallingConv::SwiftCoro);
51525152
}
51535153

5154-
void irgen::emitYieldOnce2CoroutineEntry(
5155-
IRGenFunction &IGF, LinkEntity coroFunction, CanSILFunctionType fnType,
5156-
NativeCCEntryPointArgumentEmission &emission) {
5157-
auto *buffer = emission.getCoroutineBuffer();
5158-
auto cfp = cast<llvm::GlobalVariable>(
5159-
IGF.IGM.getAddrOfCoroFunctionPointer(coroFunction));
5160-
llvm::Value *allocator = emission.getCoroutineAllocator();
5154+
void irgen::emitYieldOnce2CoroutineEntry(IRGenFunction &IGF,
5155+
CanSILFunctionType fnType,
5156+
llvm::Value *buffer,
5157+
llvm::Value *allocator,
5158+
llvm::GlobalVariable *cfp) {
51615159
IGF.setCoroutineAllocator(allocator);
51625160
auto isSwiftCoroCCAvailable =
51635161
IGF.IGM.SwiftCoroCC == llvm::CallingConv::SwiftCoro;
@@ -5170,6 +5168,15 @@ void irgen::emitYieldOnce2CoroutineEntry(
51705168
Size(-1) /*dynamic-to-IRGen size*/, IGF.IGM.getCoroStaticFrameAlignment(),
51715169
{cfp, allocator}, allocFn, deallocFn, {});
51725170
}
5171+
void irgen::emitYieldOnce2CoroutineEntry(
5172+
IRGenFunction &IGF, LinkEntity coroFunction, CanSILFunctionType fnType,
5173+
NativeCCEntryPointArgumentEmission &emission) {
5174+
auto *buffer = emission.getCoroutineBuffer();
5175+
auto cfp = cast<llvm::GlobalVariable>(
5176+
IGF.IGM.getAddrOfCoroFunctionPointer(coroFunction));
5177+
llvm::Value *allocator = emission.getCoroutineAllocator();
5178+
emitYieldOnce2CoroutineEntry(IGF, fnType, buffer, allocator, cfp);
5179+
}
51735180

51745181
static Address createOpaqueBufferAlloca(IRGenFunction &IGF,
51755182
Size size, Alignment align) {

lib/IRGen/GenCall.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,10 @@ namespace irgen {
231231
emitYieldOnce2CoroutineEntry(IRGenFunction &IGF, LinkEntity coroFunction,
232232
CanSILFunctionType coroutineType,
233233
NativeCCEntryPointArgumentEmission &emission);
234+
void emitYieldOnce2CoroutineEntry(IRGenFunction &IGF,
235+
CanSILFunctionType fnType,
236+
llvm::Value *buffer, llvm::Value *allocator,
237+
llvm::GlobalVariable *cfp);
234238

235239
Address emitAllocYieldManyCoroutineBuffer(IRGenFunction &IGF);
236240
void emitDeallocYieldManyCoroutineBuffer(IRGenFunction &IGF, Address buffer);

lib/IRGen/GenClass.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3103,11 +3103,19 @@ FunctionPointer irgen::emitVirtualMethodValue(IRGenFunction &IGF,
31033103
auto fnPtr = llvm::ConstantExpr::getBitCast(methodInfo.getDirectImpl(),
31043104
signature.getType()->getPointerTo());
31053105
llvm::Constant *secondaryValue = nullptr;
3106+
auto *accessor = dyn_cast<AccessorDecl>(method.getDecl());
31063107
if (cast<AbstractFunctionDecl>(method.getDecl())->hasAsync()) {
31073108
auto *silFn = IGF.IGM.getSILFunctionForAsyncFunctionPointer(
31083109
methodInfo.getDirectImpl());
31093110
secondaryValue = cast<llvm::Constant>(
31103111
IGF.IGM.getAddrOfSILFunction(silFn, NotForDefinition));
3112+
} else if (accessor &&
3113+
requiresFeatureCoroutineAccessors(accessor->getAccessorKind())) {
3114+
assert(methodType->isCalleeAllocatedCoroutine());
3115+
auto *silFn = IGF.IGM.getSILFunctionForCoroFunctionPointer(
3116+
methodInfo.getDirectImpl());
3117+
secondaryValue = cast<llvm::Constant>(
3118+
IGF.IGM.getAddrOfSILFunction(silFn, NotForDefinition));
31113119
}
31123120
return FunctionPointer::forDirect(methodType, fnPtr, secondaryValue,
31133121
signature, true);

lib/IRGen/GenConstant.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,9 +396,13 @@ Explosion irgen::emitConstantValue(IRGenModule &IGM, SILValue operand,
396396
llvm::Constant *fnPtr = IGM.getAddrOfSILFunction(fn, NotForDefinition);
397397
CanSILFunctionType fnType = FRI->getType().getAs<SILFunctionType>();
398398

399-
if (irgen::classifyFunctionPointerKind(fn).isAsyncFunctionPointer()) {
399+
auto fpKind = irgen::classifyFunctionPointerKind(fn);
400+
if (fpKind.isAsyncFunctionPointer()) {
400401
llvm::Constant *asyncFnPtr = IGM.getAddrOfAsyncFunctionPointer(fn);
401402
fnPtr = llvm::ConstantExpr::getBitCast(asyncFnPtr, fnPtr->getType());
403+
} else if (fpKind.isCoroFunctionPointer()) {
404+
llvm::Constant *coroFnPtr = IGM.getAddrOfCoroFunctionPointer(fn);
405+
fnPtr = llvm::ConstantExpr::getBitCast(coroFnPtr, fnPtr->getType());
402406
}
403407

404408
auto authInfo = PointerAuthInfo::forFunctionPointer(IGM, fnType);

lib/IRGen/GenDecl.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1918,6 +1918,11 @@ void IRGenerator::emitDynamicReplacements() {
19181918
IGM.getAddrOfAsyncFunctionPointer(
19191919
LinkEntity::forSILFunction(newFunc)),
19201920
IGM.Int8PtrTy));
1921+
} else if (newFunc->getLoweredFunctionType()
1922+
->isCalleeAllocatedCoroutine()) {
1923+
replacement.addRelativeAddress(llvm::ConstantExpr::getBitCast(
1924+
IGM.getAddrOfCoroFunctionPointer(LinkEntity::forSILFunction(newFunc)),
1925+
IGM.Int8PtrTy));
19211926
} else {
19221927
replacement.addCompactFunctionReference(IGM.getAddrOfSILFunction(
19231928
newFunc, NotForDefinition)); // direct relative reference.
@@ -2148,6 +2153,15 @@ void IRGenModule::emitVTableStubs() {
21482153
auto entity = LinkEntity::forSILFunction(const_cast<SILFunction *>(&F));
21492154
auto *fnPtr = emitAsyncFunctionPointer(*this, stub, entity, asyncLayout.getSize());
21502155
alias = fnPtr;
2156+
} else if (F.getLoweredFunctionType()->isCalleeAllocatedCoroutine()) {
2157+
// TODO: We cannot directly create a pointer to
2158+
// `swift_deletedCalleeAllocatedCoroutineMethodError` to workaround a
2159+
// linker crash. Instead use the stub, which calls
2160+
// swift_deletedMethodError. This works because swift_deletedMethodError
2161+
// takes no parameters and simply aborts the program.
2162+
auto entity = LinkEntity::forSILFunction(const_cast<SILFunction *>(&F));
2163+
auto *cfp = emitCoroFunctionPointer(*this, stub, entity);
2164+
alias = cfp;
21512165
} else {
21522166
alias = llvm::GlobalAlias::create(llvm::GlobalValue::ExternalLinkage,
21532167
F.getName(), stub);
@@ -2970,6 +2984,8 @@ void IRGenModule::createReplaceableProlog(IRGenFunction &IGF, SILFunction *f) {
29702984
auto *funPtr =
29712985
f->isAsync()
29722986
? IGF.IGM.getAddrOfAsyncFunctionPointer(LinkEntity::forSILFunction(f))
2987+
: f->getLoweredFunctionType()->isCalleeAllocatedCoroutine()
2988+
? IGF.IGM.getAddrOfCoroFunctionPointer(LinkEntity::forSILFunction(f))
29732989
: IGF.CurFn;
29742990
auto linkEntry =
29752991
getChainEntryForDynamicReplacement(*this, varEntity, funPtr);
@@ -3140,6 +3156,9 @@ void IRGenModule::createReplaceableProlog(IRGenFunction &IGF, SILFunction *f) {
31403156

31413157
emitDeallocAsyncContext(IGF, calleeContextBuffer);
31423158
forwardAsyncCallResult(IGF, silFunctionType, layout, suspend);
3159+
} else if (f->getLoweredFunctionType()->isCalleeAllocatedCoroutine()) {
3160+
// TODO: CoroutineAccessors: Implement replaceable function prologs.
3161+
llvm::report_fatal_error("unimplemented");
31433162
} else {
31443163
// Call the replacement function.
31453164
SmallVector<llvm::Value *, 16> forwardedArgs;
@@ -4409,6 +4428,8 @@ AccessibleFunction AccessibleFunction::forSILFunction(IRGenModule &IGM,
44094428
llvm::Constant *funcAddr = nullptr;
44104429
if (func->isAsync()) {
44114430
funcAddr = IGM.getAddrOfAsyncFunctionPointer(func);
4431+
} else if (func->getLoweredFunctionType()->isCalleeAllocatedCoroutine()) {
4432+
funcAddr = IGM.getAddrOfCoroFunctionPointer(func);
44124433
} else {
44134434
funcAddr = IGM.getAddrOfSILFunction(func, NotForDefinition);
44144435
}

lib/IRGen/GenMeta.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,9 @@ static void buildMethodDescriptorFields(IRGenModule &IGM,
317317
if (impl->isAsync()) {
318318
llvm::Constant *implFn = IGM.getAddrOfAsyncFunctionPointer(impl);
319319
descriptor.addRelativeAddress(implFn);
320+
} else if (impl->getLoweredFunctionType()->isCalleeAllocatedCoroutine()) {
321+
llvm::Constant *implFn = IGM.getAddrOfCoroFunctionPointer(impl);
322+
descriptor.addRelativeAddress(implFn);
320323
} else {
321324
llvm::Function *implFn = IGM.getAddrOfSILFunction(impl, NotForDefinition);
322325

@@ -1135,6 +1138,9 @@ namespace {
11351138
if (silFunc->isAsync()) {
11361139
return IGM.getAddrOfAsyncFunctionPointer(silFunc);
11371140
}
1141+
if (silFunc->getLoweredFunctionType()->isCalleeAllocatedCoroutine()) {
1142+
return IGM.getAddrOfCoroFunctionPointer(silFunc);
1143+
}
11381144
return IGM.getAddrOfSILFunction(entry.getMethodWitness().Witness,
11391145
NotForDefinition);
11401146
}
@@ -2237,6 +2243,10 @@ namespace {
22372243
if (impl->isAsync()) {
22382244
llvm::Constant *implFn = IGM.getAddrOfAsyncFunctionPointer(impl);
22392245
descriptor.addRelativeAddress(implFn);
2246+
} else if (impl->getLoweredFunctionType()
2247+
->isCalleeAllocatedCoroutine()) {
2248+
llvm::Constant *implFn = IGM.getAddrOfCoroFunctionPointer(impl);
2249+
descriptor.addRelativeAddress(implFn);
22402250
} else {
22412251
llvm::Function *implFn = IGM.getAddrOfSILFunction(impl, NotForDefinition);
22422252
descriptor.addCompactFunctionReference(implFn);
@@ -4488,17 +4498,27 @@ namespace {
44884498
if (entry) {
44894499
if (entry->getImplementation()->isAsync()) {
44904500
ptr = IGM.getAddrOfAsyncFunctionPointer(entry->getImplementation());
4501+
} else if (entry->getImplementation()
4502+
->getLoweredFunctionType()
4503+
->isCalleeAllocatedCoroutine()) {
4504+
ptr = IGM.getAddrOfCoroFunctionPointer(entry->getImplementation());
44914505
} else {
44924506
ptr = IGM.getAddrOfSILFunction(entry->getImplementation(),
44934507
NotForDefinition);
44944508
}
44954509
} else {
4510+
auto *accessor = dyn_cast<AccessorDecl>(afd);
44964511
// The method is removed by dead method elimination.
44974512
// It should be never called. We add a pointer to an error function.
44984513
if (afd->hasAsync()) {
44994514
ptr = llvm::ConstantExpr::getBitCast(
45004515
IGM.getDeletedAsyncMethodErrorAsyncFunctionPointer(),
45014516
IGM.FunctionPtrTy);
4517+
} else if (accessor && requiresFeatureCoroutineAccessors(
4518+
accessor->getAccessorKind())) {
4519+
ptr = llvm::ConstantExpr::getBitCast(
4520+
IGM.getDeletedCalleeAllocatedCoroutineMethodErrorAsyncFunctionPointer(),
4521+
IGM.FunctionPtrTy);
45024522
} else {
45034523
ptr = llvm::ConstantExpr::getBitCast(IGM.getDeletedMethodErrorFn(),
45044524
IGM.FunctionPtrTy);

lib/IRGen/GenProto.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,6 +1617,10 @@ class AccessorConformanceInfo : public ConformanceInfo {
16171617
SILEntries = SILEntries.slice(1);
16181618

16191619
bool isAsyncRequirement = requirement.hasAsync();
1620+
bool isCalleeAllocatedCoroutineRequirement =
1621+
requirement.isCalleeAllocatedCoroutine();
1622+
assert(!(isAsyncRequirement && isCalleeAllocatedCoroutineRequirement) &&
1623+
"async yield_once coroutines aren't implemented");
16201624

16211625
#ifndef NDEBUG
16221626
assert(entry.getKind() == SILWitnessTable::Method
@@ -1633,8 +1637,12 @@ class AccessorConformanceInfo : public ConformanceInfo {
16331637
llvm::Constant *witness = nullptr;
16341638
if (Func) {
16351639
assert(Func->isAsync() == isAsyncRequirement);
1640+
assert(Func->isCalleeAllocatedCoroutine() ==
1641+
isCalleeAllocatedCoroutineRequirement);
16361642
if (Func->isAsync()) {
16371643
witness = IGM.getAddrOfAsyncFunctionPointer(Func);
1644+
} else if (Func->isCalleeAllocatedCoroutine()) {
1645+
witness = IGM.getAddrOfCoroFunctionPointer(Func);
16381646
} else {
16391647

16401648
auto *conformance = dyn_cast<NormalProtocolConformance>(&Conformance);
@@ -1645,8 +1653,8 @@ class AccessorConformanceInfo : public ConformanceInfo {
16451653
getSelfNominalTypeDecl()->isGenericContext() &&
16461654
!Func->getLoweredFunctionType()->isCoroutine())
16471655
witness = IGM.getAddrOfWitnessTableProfilingThunk(f, *conformance);
1648-
else witness = f;
1649-
1656+
else
1657+
witness = f;
16501658
}
16511659
} else {
16521660
// The method is removed by dead method elimination.
@@ -1655,6 +1663,10 @@ class AccessorConformanceInfo : public ConformanceInfo {
16551663
witness = llvm::ConstantExpr::getBitCast(
16561664
IGM.getDeletedAsyncMethodErrorAsyncFunctionPointer(),
16571665
IGM.FunctionPtrTy);
1666+
} else if (isCalleeAllocatedCoroutineRequirement) {
1667+
witness = llvm::ConstantExpr::getBitCast(
1668+
IGM.getDeletedCalleeAllocatedCoroutineMethodErrorAsyncFunctionPointer(),
1669+
IGM.CoroFunctionPointerPtrTy);
16581670
} else {
16591671
witness = llvm::ConstantExpr::getBitCast(
16601672
IGM.getDeletedMethodErrorFn(), IGM.FunctionPtrTy);
@@ -2028,6 +2040,8 @@ void ResilientWitnessTableBuilder::collectResilientWitnesses(
20282040
if (Func) {
20292041
if (Func->isAsync())
20302042
witness = IGM.getAddrOfAsyncFunctionPointer(Func);
2043+
else if (Func->getLoweredFunctionType()->isCalleeAllocatedCoroutine())
2044+
witness = IGM.getAddrOfCoroFunctionPointer(Func);
20312045
else {
20322046
auto f = IGM.getAddrOfSILFunction(Func, NotForDefinition);
20332047
if (isGenericConformance && IGM.getOptions().UseProfilingMarkerThunks &&

0 commit comments

Comments
 (0)