Skip to content

Commit 66ca0d8

Browse files
committed
[CoroutineAccessors] Use async bit in descriptors.
To facilitate back deployment, make use of the fact that the async bit has up to now never been set for read and modify accessors and claim that set bit to indicate that it is a callee-allocated coroutine. This has the virtue of being completely back deployable because like async function pointers coro function pointers must be auth'd and signed as data.
1 parent 96ea03f commit 66ca0d8

File tree

3 files changed

+42
-29
lines changed

3 files changed

+42
-29
lines changed

include/swift/ABI/MetadataValues.h

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -374,8 +374,6 @@ class MethodDescriptorFlags {
374374
Setter,
375375
ModifyCoroutine,
376376
ReadCoroutine,
377-
Read2Coroutine,
378-
Modify2Coroutine,
379377
};
380378

381379
private:
@@ -438,23 +436,27 @@ class MethodDescriptorFlags {
438436
/// Note that 'init' is not considered an instance member.
439437
bool isInstance() const { return Value & IsInstanceMask; }
440438

441-
bool isAsync() const { return Value & IsAsyncMask; }
439+
bool _hasAsyncBitSet() const { return Value & IsAsyncMask; }
442440

443-
bool isCalleeAllocatedCoroutine() const {
441+
bool isAsync() const { return !isCoroutine() && _hasAsyncBitSet(); }
442+
443+
bool isCoroutine() const {
444444
switch (getKind()) {
445445
case Kind::Method:
446446
case Kind::Init:
447447
case Kind::Getter:
448448
case Kind::Setter:
449+
return false;
449450
case Kind::ModifyCoroutine:
450451
case Kind::ReadCoroutine:
451-
return false;
452-
case Kind::Read2Coroutine:
453-
case Kind::Modify2Coroutine:
454452
return true;
455453
}
456454
}
457455

456+
bool isCalleeAllocatedCoroutine() const {
457+
return isCoroutine() && _hasAsyncBitSet();
458+
}
459+
458460
bool isData() const { return isAsync() || isCalleeAllocatedCoroutine(); }
459461

460462
uint16_t getExtraDiscriminator() const {
@@ -615,8 +617,6 @@ class ProtocolRequirementFlags {
615617
ModifyCoroutine,
616618
AssociatedTypeAccessFunction,
617619
AssociatedConformanceAccessFunction,
618-
Read2Coroutine,
619-
Modify2Coroutine,
620620
};
621621

622622
private:
@@ -666,26 +666,30 @@ class ProtocolRequirementFlags {
666666
/// Note that 'init' is not considered an instance member.
667667
bool isInstance() const { return Value & IsInstanceMask; }
668668

669-
bool isAsync() const { return Value & IsAsyncMask; }
669+
bool _hasAsyncBitSet() const { return Value & IsAsyncMask; }
670670

671-
bool isCalleeAllocatedCoroutine() const {
671+
bool isAsync() const { return !isCoroutine() && _hasAsyncBitSet(); }
672+
673+
bool isCoroutine() const {
672674
switch (getKind()) {
673675
case Kind::BaseProtocol:
674676
case Kind::Method:
675677
case Kind::Init:
676678
case Kind::Getter:
677679
case Kind::Setter:
678-
case Kind::ReadCoroutine:
679-
case Kind::ModifyCoroutine:
680680
case Kind::AssociatedTypeAccessFunction:
681681
case Kind::AssociatedConformanceAccessFunction:
682682
return false;
683-
case Kind::Read2Coroutine:
684-
case Kind::Modify2Coroutine:
683+
case Kind::ReadCoroutine:
684+
case Kind::ModifyCoroutine:
685685
return true;
686686
}
687687
}
688688

689+
bool isCalleeAllocatedCoroutine() const {
690+
return isCoroutine() && _hasAsyncBitSet();
691+
}
692+
689693
bool isData() const { return isAsync() || isCalleeAllocatedCoroutine(); }
690694

691695
bool isSignedWithAddress() const {

lib/IRGen/GenMeta.cpp

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -255,22 +255,24 @@ static Flags getMethodDescriptorFlags(ValueDecl *fn) {
255255
return flags;
256256
}
257257

258-
auto kind = [&] {
258+
auto kindAndIsCalleeAllocatedCoroutine =
259+
[&]() -> std::pair<typename Flags::Kind, bool> {
259260
auto accessor = dyn_cast<AccessorDecl>(fn);
260-
if (!accessor) return Flags::Kind::Method;
261+
if (!accessor)
262+
return {Flags::Kind::Method, false};
261263
switch (accessor->getAccessorKind()) {
262264
case AccessorKind::Get:
263-
return Flags::Kind::Getter;
265+
return {Flags::Kind::Getter, false};
264266
case AccessorKind::Set:
265-
return Flags::Kind::Setter;
267+
return {Flags::Kind::Setter, false};
266268
case AccessorKind::Read:
267-
return Flags::Kind::ReadCoroutine;
269+
return {Flags::Kind::ReadCoroutine, false};
268270
case AccessorKind::Read2:
269-
return Flags::Kind::Read2Coroutine;
271+
return {Flags::Kind::ReadCoroutine, true};
270272
case AccessorKind::Modify:
271-
return Flags::Kind::ModifyCoroutine;
273+
return {Flags::Kind::ModifyCoroutine, false};
272274
case AccessorKind::Modify2:
273-
return Flags::Kind::Modify2Coroutine;
275+
return {Flags::Kind::ModifyCoroutine, true};
274276
#define OPAQUE_ACCESSOR(ID, KEYWORD)
275277
#define ACCESSOR(ID) \
276278
case AccessorKind::ID:
@@ -280,9 +282,20 @@ static Flags getMethodDescriptorFlags(ValueDecl *fn) {
280282
}
281283
llvm_unreachable("bad kind");
282284
}();
283-
bool hasAsync = false;
285+
auto kind = kindAndIsCalleeAllocatedCoroutine.first;
286+
287+
// Because no async old-ABI accessor coroutines exist or presumably ever will
288+
// (if async coroutines accessors are added, they will presumably be new-ABI),
289+
// the pairs {Flags::Kind::ReadCoroutine, isAsync} and
290+
// {Flags::Kind::ModifyCoroutine, isAsync} can't mean "async old-ABI
291+
// accessor coroutine". As such, we repurpose that pair to mean "new-ABI
292+
// accessor coroutine". This has the important virtue of resulting in ptrauth
293+
// authing/signing coro function pointers as data on old OSes where the bit
294+
// means "async" and where adding new accessor kinds requires a back
295+
// deployment library.
296+
bool hasAsync = kindAndIsCalleeAllocatedCoroutine.second;
284297
if (auto *afd = dyn_cast<AbstractFunctionDecl>(fn))
285-
hasAsync = afd->hasAsync();
298+
hasAsync |= afd->hasAsync();
286299
return Flags(kind).withIsInstance(!fn->isStatic()).withIsAsync(hasAsync);
287300
}
288301

stdlib/public/runtime/Metadata.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6162,9 +6162,7 @@ static void initProtocolWitness(void **slot, void *witness,
61626162
case ProtocolRequirementFlags::Kind::Getter:
61636163
case ProtocolRequirementFlags::Kind::Setter:
61646164
case ProtocolRequirementFlags::Kind::ReadCoroutine:
6165-
case ProtocolRequirementFlags::Kind::Read2Coroutine:
61666165
case ProtocolRequirementFlags::Kind::ModifyCoroutine:
6167-
case ProtocolRequirementFlags::Kind::Modify2Coroutine:
61686166
swift_ptrauth_init_code_or_data(slot, witness,
61696167
reqt.Flags.getExtraDiscriminator(),
61706168
!reqt.Flags.isData());
@@ -6205,9 +6203,7 @@ static void copyProtocolWitness(void **dest, void * const *src,
62056203
case ProtocolRequirementFlags::Kind::Getter:
62066204
case ProtocolRequirementFlags::Kind::Setter:
62076205
case ProtocolRequirementFlags::Kind::ReadCoroutine:
6208-
case ProtocolRequirementFlags::Kind::Read2Coroutine:
62096206
case ProtocolRequirementFlags::Kind::ModifyCoroutine:
6210-
case ProtocolRequirementFlags::Kind::Modify2Coroutine:
62116207
swift_ptrauth_copy_code_or_data(
62126208
dest, src, reqt.Flags.getExtraDiscriminator(), !reqt.Flags.isData(),
62136209
/*allowNull*/ true); // NULL allowed for VFE (methods in the vtable

0 commit comments

Comments
 (0)