Skip to content

[CoroutineAccessors] Use async bit in descriptors. #80520

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 19 additions & 15 deletions include/swift/ABI/MetadataValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,8 +374,6 @@ class MethodDescriptorFlags {
Setter,
ModifyCoroutine,
ReadCoroutine,
Read2Coroutine,
Modify2Coroutine,
};

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

bool isAsync() const { return Value & IsAsyncMask; }
bool _hasAsyncBitSet() const { return Value & IsAsyncMask; }

bool isCalleeAllocatedCoroutine() const {
bool isAsync() const { return !isCoroutine() && _hasAsyncBitSet(); }

bool isCoroutine() const {
switch (getKind()) {
case Kind::Method:
case Kind::Init:
case Kind::Getter:
case Kind::Setter:
return false;
case Kind::ModifyCoroutine:
case Kind::ReadCoroutine:
return false;
case Kind::Read2Coroutine:
case Kind::Modify2Coroutine:
return true;
}
}

bool isCalleeAllocatedCoroutine() const {
return isCoroutine() && _hasAsyncBitSet();
}

bool isData() const { return isAsync() || isCalleeAllocatedCoroutine(); }

uint16_t getExtraDiscriminator() const {
Expand Down Expand Up @@ -615,8 +617,6 @@ class ProtocolRequirementFlags {
ModifyCoroutine,
AssociatedTypeAccessFunction,
AssociatedConformanceAccessFunction,
Read2Coroutine,
Modify2Coroutine,
};

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

bool isAsync() const { return Value & IsAsyncMask; }
bool _hasAsyncBitSet() const { return Value & IsAsyncMask; }

bool isCalleeAllocatedCoroutine() const {
bool isAsync() const { return !isCoroutine() && _hasAsyncBitSet(); }

bool isCoroutine() const {
switch (getKind()) {
case Kind::BaseProtocol:
case Kind::Method:
case Kind::Init:
case Kind::Getter:
case Kind::Setter:
case Kind::ReadCoroutine:
case Kind::ModifyCoroutine:
case Kind::AssociatedTypeAccessFunction:
case Kind::AssociatedConformanceAccessFunction:
return false;
case Kind::Read2Coroutine:
case Kind::Modify2Coroutine:
case Kind::ReadCoroutine:
case Kind::ModifyCoroutine:
return true;
}
}

bool isCalleeAllocatedCoroutine() const {
return isCoroutine() && _hasAsyncBitSet();
}

bool isData() const { return isAsync() || isCalleeAllocatedCoroutine(); }

bool isSignedWithAddress() const {
Expand Down
33 changes: 23 additions & 10 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,22 +255,24 @@ static Flags getMethodDescriptorFlags(ValueDecl *fn) {
return flags;
}

auto kind = [&] {
auto kindAndIsCalleeAllocatedCoroutine =
[&]() -> std::pair<typename Flags::Kind, bool> {
auto accessor = dyn_cast<AccessorDecl>(fn);
if (!accessor) return Flags::Kind::Method;
if (!accessor)
return {Flags::Kind::Method, false};
switch (accessor->getAccessorKind()) {
case AccessorKind::Get:
return Flags::Kind::Getter;
return {Flags::Kind::Getter, false};
case AccessorKind::Set:
return Flags::Kind::Setter;
return {Flags::Kind::Setter, false};
case AccessorKind::Read:
return Flags::Kind::ReadCoroutine;
return {Flags::Kind::ReadCoroutine, false};
case AccessorKind::Read2:
return Flags::Kind::Read2Coroutine;
return {Flags::Kind::ReadCoroutine, true};
case AccessorKind::Modify:
return Flags::Kind::ModifyCoroutine;
return {Flags::Kind::ModifyCoroutine, false};
case AccessorKind::Modify2:
return Flags::Kind::Modify2Coroutine;
return {Flags::Kind::ModifyCoroutine, true};
#define OPAQUE_ACCESSOR(ID, KEYWORD)
#define ACCESSOR(ID) \
case AccessorKind::ID:
Expand All @@ -280,9 +282,20 @@ static Flags getMethodDescriptorFlags(ValueDecl *fn) {
}
llvm_unreachable("bad kind");
}();
bool hasAsync = false;
auto kind = kindAndIsCalleeAllocatedCoroutine.first;

// Because no async old-ABI accessor coroutines exist or presumably ever will
// (if async coroutines accessors are added, they will presumably be new-ABI),
// the pairs {Flags::Kind::ReadCoroutine, isAsync} and
// {Flags::Kind::ModifyCoroutine, isAsync} can't mean "async old-ABI
// accessor coroutine". As such, we repurpose that pair to mean "new-ABI
// accessor coroutine". This has the important virtue of resulting in ptrauth
// authing/signing coro function pointers as data on old OSes where the bit
// means "async" and where adding new accessor kinds requires a back
// deployment library.
bool hasAsync = kindAndIsCalleeAllocatedCoroutine.second;
if (auto *afd = dyn_cast<AbstractFunctionDecl>(fn))
hasAsync = afd->hasAsync();
hasAsync |= afd->hasAsync();
return Flags(kind).withIsInstance(!fn->isStatic()).withIsAsync(hasAsync);
}

Expand Down
4 changes: 0 additions & 4 deletions stdlib/public/runtime/Metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6162,9 +6162,7 @@ static void initProtocolWitness(void **slot, void *witness,
case ProtocolRequirementFlags::Kind::Getter:
case ProtocolRequirementFlags::Kind::Setter:
case ProtocolRequirementFlags::Kind::ReadCoroutine:
case ProtocolRequirementFlags::Kind::Read2Coroutine:
case ProtocolRequirementFlags::Kind::ModifyCoroutine:
case ProtocolRequirementFlags::Kind::Modify2Coroutine:
swift_ptrauth_init_code_or_data(slot, witness,
reqt.Flags.getExtraDiscriminator(),
!reqt.Flags.isData());
Expand Down Expand Up @@ -6205,9 +6203,7 @@ static void copyProtocolWitness(void **dest, void * const *src,
case ProtocolRequirementFlags::Kind::Getter:
case ProtocolRequirementFlags::Kind::Setter:
case ProtocolRequirementFlags::Kind::ReadCoroutine:
case ProtocolRequirementFlags::Kind::Read2Coroutine:
case ProtocolRequirementFlags::Kind::ModifyCoroutine:
case ProtocolRequirementFlags::Kind::Modify2Coroutine:
swift_ptrauth_copy_code_or_data(
dest, src, reqt.Flags.getExtraDiscriminator(), !reqt.Flags.isData(),
/*allowNull*/ true); // NULL allowed for VFE (methods in the vtable
Expand Down