Skip to content
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

Emit and call thunks for back deployed functions #41416

Merged
merged 6 commits into from
Feb 26, 2022
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
2 changes: 2 additions & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ types where the metadata itself has unknown layout.)
global ::= global 'TI' // implementation of a dynamic_replaceable function
global ::= global 'Tu' // async function pointer of a function
global ::= global 'TX' // function pointer of a dynamic_replaceable function
global ::= global 'Twb' // back deployment thunk
global ::= global 'TwB' // back deployment fallback function
global ::= entity entity 'TV' // vtable override thunk, derived followed by base
global ::= type label-list? 'D' // type mangling for the debugger with label list for function types.
global ::= type 'TC' // continuation prototype (not actually used for real symbols)
Expand Down
4 changes: 3 additions & 1 deletion include/swift/AST/ASTMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ class ASTMangler : public Mangler {
ObjCAsSwiftThunk,
DistributedThunk,
DistributedAccessor,
AccessibleFunctionRecord
AccessibleFunctionRecord,
BackDeploymentThunk,
BackDeploymentFallback,
};

ASTMangler(bool DWARFMangling = false)
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -6268,6 +6268,9 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
/// Returns 'true' if the function is distributed.
bool isDistributed() const;

/// Returns 'true' if the function has the @c @_backDeploy attribute.
bool isBackDeployed() const;

PolymorphicEffectKind getPolymorphicEffectKind(EffectKind kind) const;

// FIXME: Hack that provides names with keyword arguments for accessors.
Expand Down
2 changes: 2 additions & 0 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,8 @@ NODE(CompileTimeConst)

// Added in Swift 5.7
NODE(OpaqueReturnTypeIndexed)
NODE(BackDeploymentThunk)
NODE(BackDeploymentFallback)

#undef CONTEXT_NODE
#undef NODE
59 changes: 53 additions & 6 deletions include/swift/SIL/SILDeclRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,21 @@ struct SILDeclRef {
AsyncEntryPoint,
};

/// Represents the variants of a back deployable function.
enum class BackDeploymentKind : unsigned {
/// Default value. If a SILDecRef references a function that has been back
/// deployed and has this back deployment kind, then it references the
/// original ABI stable function.
None,
/// The thunk variant of a function that calls either the original function
/// or the fallback variant if the original is unavailable. This thunk will
/// be emitted with PublicNonABI linkage.
Thunk,
/// The fallback variant of the function. This function will be emitted with
/// PublicNonABI linkage.
Fallback,
};

/// The AST node represented by this SILDeclRef.
Loc loc;
/// The Kind of this SILDeclRef.
Expand All @@ -170,6 +185,8 @@ struct SILDeclRef {
unsigned isForeign : 1;
/// True if this references a distributed function.
unsigned isDistributed : 1;
/// The BackDeploymentKind of this SILDeclRef.
BackDeploymentKind backDeploymentKind : 2;
/// The default argument index for a default argument getter.
unsigned defaultArgIndex : 10;

Expand Down Expand Up @@ -204,13 +221,15 @@ struct SILDeclRef {

/// Produces a null SILDeclRef.
SILDeclRef()
: loc(), kind(Kind::Func), isForeign(0), isDistributed(0), defaultArgIndex(0) {}
: loc(), kind(Kind::Func), isForeign(0), isDistributed(0),
backDeploymentKind(BackDeploymentKind::None), defaultArgIndex(0) {}

/// Produces a SILDeclRef of the given kind for the given decl.
explicit SILDeclRef(
ValueDecl *decl, Kind kind,
bool isForeign = false,
bool isDistributed = false,
BackDeploymentKind backDeploymentKind = BackDeploymentKind::None,
AutoDiffDerivativeFunctionIdentifier *derivativeId = nullptr);

/// Produces a SILDeclRef for the given ValueDecl or
Expand All @@ -224,7 +243,10 @@ struct SILDeclRef {
/// for the containing ClassDecl.
/// - If 'loc' is a global VarDecl, this returns its GlobalAccessor
/// SILDeclRef.
explicit SILDeclRef(Loc loc, bool isForeign = false, bool isDistributed = false);
explicit SILDeclRef(
Loc loc,
bool isForeign = false,
bool isDistributed = false);

/// See above put produces a prespecialization according to the signature.
explicit SILDeclRef(Loc loc, GenericSignature prespecializationSig);
Expand Down Expand Up @@ -360,6 +382,7 @@ struct SILDeclRef {
return loc.getOpaqueValue() == rhs.loc.getOpaqueValue() &&
kind == rhs.kind && isForeign == rhs.isForeign &&
isDistributed == rhs.isDistributed &&
backDeploymentKind == rhs.backDeploymentKind &&
defaultArgIndex == rhs.defaultArgIndex &&
pointer == rhs.pointer;
}
Expand All @@ -378,6 +401,7 @@ struct SILDeclRef {
return SILDeclRef(loc.getOpaqueValue(), kind,
/*foreign=*/foreign,
/*distributed=*/false,
backDeploymentKind,
defaultArgIndex,
pointer.get<AutoDiffDerivativeFunctionIdentifier *>());
}
Expand All @@ -387,6 +411,16 @@ struct SILDeclRef {
return SILDeclRef(loc.getOpaqueValue(), kind,
/*foreign=*/false,
/*distributed=*/distributed,
backDeploymentKind,
defaultArgIndex,
pointer.get<AutoDiffDerivativeFunctionIdentifier *>());
}
/// Returns a copy of the decl with the given back deployment kind.
SILDeclRef asBackDeploymentKind(BackDeploymentKind backDeploymentKind) const {
return SILDeclRef(loc.getOpaqueValue(), kind,
isForeign,
isDistributed,
backDeploymentKind,
defaultArgIndex,
pointer.get<AutoDiffDerivativeFunctionIdentifier *>());
}
Expand Down Expand Up @@ -431,6 +465,14 @@ struct SILDeclRef {
/// True if the decl ref references a thunk handling potentially distributed actor functions
bool isDistributedThunk() const;

/// True if the decl ref references a thunk handling a call to a function that
/// supports back deployment.
bool isBackDeploymentThunk() const;

/// True if the decl ref references a function that is the back deployment
/// fallback for an original function which may be unavailable at runtime.
bool isBackDeploymentFallback() const;

/// True if the decl ref references a method which introduces a new vtable
/// entry.
bool requiresNewVTableEntry() const;
Expand Down Expand Up @@ -508,10 +550,12 @@ struct SILDeclRef {
explicit SILDeclRef(void *opaqueLoc, Kind kind,
bool isForeign,
bool isDistributed,
BackDeploymentKind backDeploymentKind,
unsigned defaultArgIndex,
AutoDiffDerivativeFunctionIdentifier *derivativeId)
: loc(Loc::getFromOpaqueValue(opaqueLoc)), kind(kind),
isForeign(isForeign), isDistributed(isDistributed),
backDeploymentKind(backDeploymentKind),
defaultArgIndex(defaultArgIndex),
pointer(derivativeId) {}
};
Expand All @@ -529,17 +573,18 @@ namespace llvm {
template<> struct DenseMapInfo<swift::SILDeclRef> {
using SILDeclRef = swift::SILDeclRef;
using Kind = SILDeclRef::Kind;
using BackDeploymentKind = SILDeclRef::BackDeploymentKind;
using Loc = SILDeclRef::Loc;
using PointerInfo = DenseMapInfo<void*>;
using UnsignedInfo = DenseMapInfo<unsigned>;

static SILDeclRef getEmptyKey() {
return SILDeclRef(PointerInfo::getEmptyKey(), Kind::Func, false, false, 0,
nullptr);
return SILDeclRef(PointerInfo::getEmptyKey(), Kind::Func, false, false,
BackDeploymentKind::None, 0, nullptr);
}
static SILDeclRef getTombstoneKey() {
return SILDeclRef(PointerInfo::getTombstoneKey(), Kind::Func, false, false,
0, nullptr);
BackDeploymentKind::None, 0, nullptr);
}
static unsigned getHashValue(swift::SILDeclRef Val) {
unsigned h1 = PointerInfo::getHashValue(Val.loc.getOpaqueValue());
Expand All @@ -550,7 +595,9 @@ template<> struct DenseMapInfo<swift::SILDeclRef> {
unsigned h4 = UnsignedInfo::getHashValue(Val.isForeign);
unsigned h5 = PointerInfo::getHashValue(Val.pointer.getOpaqueValue());
unsigned h6 = UnsignedInfo::getHashValue(Val.isDistributed);
return h1 ^ (h2 << 4) ^ (h3 << 9) ^ (h4 << 7) ^ (h5 << 11) ^ (h6 << 8);
unsigned h7 = UnsignedInfo::getHashValue(unsigned(Val.backDeploymentKind));
return h1 ^ (h2 << 4) ^ (h3 << 9) ^ (h4 << 7) ^ (h5 << 11) ^ (h6 << 8) ^
(h7 << 10);
}
static bool isEqual(swift::SILDeclRef const &LHS,
swift::SILDeclRef const &RHS) {
Expand Down
2 changes: 2 additions & 0 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,8 @@ void ASTMangler::appendSymbolKind(SymbolKind SKind) {
case SymbolKind::DistributedThunk: return appendOperator("TE");
case SymbolKind::DistributedAccessor: return appendOperator("TF");
case SymbolKind::AccessibleFunctionRecord: return appendOperator("HF");
case SymbolKind::BackDeploymentThunk: return appendOperator("Twb");
case SymbolKind::BackDeploymentFallback: return appendOperator("TwB");
}
}

Expand Down
4 changes: 4 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7531,6 +7531,10 @@ bool AbstractFunctionDecl::isSendable() const {
return getAttrs().hasAttribute<SendableAttr>();
}

bool AbstractFunctionDecl::isBackDeployed() const {
return getAttrs().hasAttribute<BackDeployAttr>();
}

BraceStmt *AbstractFunctionDecl::getBody(bool canSynthesize) const {
if ((getBodyKind() == BodyKind::Synthesize ||
getBodyKind() == BodyKind::Unparsed) &&
Expand Down
9 changes: 9 additions & 0 deletions lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ bool swift::Demangle::isFunctionAttr(Node::Kind kind) {
case Node::Kind::AsyncAwaitResumePartialFunction:
case Node::Kind::AsyncSuspendResumePartialFunction:
case Node::Kind::AccessibleFunctionRecord:
case Node::Kind::BackDeploymentThunk:
case Node::Kind::BackDeploymentFallback:
return true;
default:
return false;
Expand Down Expand Up @@ -2641,6 +2643,13 @@ NodePointer Demangler::demangleThunkOrSpecialization() {
return demangleAutoDiffFunctionOrSimpleThunk(
Node::Kind::AutoDiffFunction);
}
case 'w':
switch (nextChar()) {
case 'b': return createNode(Node::Kind::BackDeploymentThunk);
case 'B': return createNode(Node::Kind::BackDeploymentFallback);
default:
return nullptr;
}
default:
return nullptr;
}
Expand Down
10 changes: 10 additions & 0 deletions lib/Demangling/NodePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,8 @@ class NodePrinter {
case Node::Kind::AsyncAwaitResumePartialFunction:
case Node::Kind::AsyncSuspendResumePartialFunction:
case Node::Kind::AccessibleFunctionRecord:
case Node::Kind::BackDeploymentThunk:
case Node::Kind::BackDeploymentFallback:
return false;
}
printer_unreachable("bad node kind");
Expand Down Expand Up @@ -2050,6 +2052,14 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth,
Printer << "dynamically replaceable variable for ";
}
return nullptr;
case Node::Kind::BackDeploymentThunk:
if (!Options.ShortenThunk) {
Printer << "back deployment thunk for ";
}
return nullptr;
case Node::Kind::BackDeploymentFallback:
Printer << "back deployment fallback for ";
return nullptr;
case Node::Kind::ProtocolSymbolicReference:
Printer << "protocol symbolic reference 0x";
Printer.writeHex(Node->getIndex());
Expand Down
11 changes: 11 additions & 0 deletions lib/Demangling/OldRemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2800,3 +2800,14 @@ ManglingError Remangler::mangleAccessibleFunctionRecord(Node *node,
Buffer << "HF";
return ManglingError::Success;
}

ManglingError Remangler::mangleBackDeploymentThunk(Node *node, unsigned depth) {
Buffer << "Twb";
return ManglingError::Success;
}

ManglingError Remangler::mangleBackDeploymentFallback(Node *node,
unsigned depth) {
Buffer << "TwB";
return ManglingError::Success;
}
14 changes: 14 additions & 0 deletions lib/Demangling/Remangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1627,6 +1627,8 @@ ManglingError Remangler::mangleGlobal(Node *node, unsigned depth) {
case Node::Kind::AsyncAwaitResumePartialFunction:
case Node::Kind::AsyncSuspendResumePartialFunction:
case Node::Kind::AccessibleFunctionRecord:
case Node::Kind::BackDeploymentThunk:
case Node::Kind::BackDeploymentFallback:
mangleInReverseOrder = true;
break;
default:
Expand Down Expand Up @@ -3407,6 +3409,18 @@ ManglingError Remangler::mangleAccessibleFunctionRecord(Node *node,
return ManglingError::Success;
}

ManglingError Remangler::mangleBackDeploymentThunk(Node *node,
unsigned depth) {
Buffer << "Twb";
return ManglingError::Success;
}

ManglingError Remangler::mangleBackDeploymentFallback(Node *node,
unsigned depth) {
Buffer << "TwB";
return ManglingError::Success;
}

} // anonymous namespace

/// The top-level interface to the remangler.
Expand Down
Loading