Skip to content

Commit 9e4ba44

Browse files
authored
Merge pull request #41416 from tshortli/back-deploy-thunk
Emit and call thunks for back deployed functions
2 parents a9e7726 + 5339dae commit 9e4ba44

27 files changed

+683
-59
lines changed

docs/ABI/Mangling.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ types where the metadata itself has unknown layout.)
223223
global ::= global 'TI' // implementation of a dynamic_replaceable function
224224
global ::= global 'Tu' // async function pointer of a function
225225
global ::= global 'TX' // function pointer of a dynamic_replaceable function
226+
global ::= global 'Twb' // back deployment thunk
227+
global ::= global 'TwB' // back deployment fallback function
226228
global ::= entity entity 'TV' // vtable override thunk, derived followed by base
227229
global ::= type label-list? 'D' // type mangling for the debugger with label list for function types.
228230
global ::= type 'TC' // continuation prototype (not actually used for real symbols)

include/swift/AST/ASTMangler.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,9 @@ class ASTMangler : public Mangler {
105105
ObjCAsSwiftThunk,
106106
DistributedThunk,
107107
DistributedAccessor,
108-
AccessibleFunctionRecord
108+
AccessibleFunctionRecord,
109+
BackDeploymentThunk,
110+
BackDeploymentFallback,
109111
};
110112

111113
ASTMangler(bool DWARFMangling = false)

include/swift/AST/Decl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6282,6 +6282,9 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
62826282
/// Returns 'true' if the function is distributed.
62836283
bool isDistributed() const;
62846284

6285+
/// Returns 'true' if the function has the @c @_backDeploy attribute.
6286+
bool isBackDeployed() const;
6287+
62856288
PolymorphicEffectKind getPolymorphicEffectKind(EffectKind kind) const;
62866289

62876290
// FIXME: Hack that provides names with keyword arguments for accessors.

include/swift/Demangling/DemangleNodes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,8 @@ NODE(CompileTimeConst)
332332

333333
// Added in Swift 5.7
334334
NODE(OpaqueReturnTypeIndexed)
335+
NODE(BackDeploymentThunk)
336+
NODE(BackDeploymentFallback)
335337

336338
#undef CONTEXT_NODE
337339
#undef NODE

include/swift/SIL/SILDeclRef.h

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,21 @@ struct SILDeclRef {
162162
AsyncEntryPoint,
163163
};
164164

165+
/// Represents the variants of a back deployable function.
166+
enum class BackDeploymentKind : unsigned {
167+
/// Default value. If a SILDecRef references a function that has been back
168+
/// deployed and has this back deployment kind, then it references the
169+
/// original ABI stable function.
170+
None,
171+
/// The thunk variant of a function that calls either the original function
172+
/// or the fallback variant if the original is unavailable. This thunk will
173+
/// be emitted with PublicNonABI linkage.
174+
Thunk,
175+
/// The fallback variant of the function. This function will be emitted with
176+
/// PublicNonABI linkage.
177+
Fallback,
178+
};
179+
165180
/// The AST node represented by this SILDeclRef.
166181
Loc loc;
167182
/// The Kind of this SILDeclRef.
@@ -170,6 +185,8 @@ struct SILDeclRef {
170185
unsigned isForeign : 1;
171186
/// True if this references a distributed function.
172187
unsigned isDistributed : 1;
188+
/// The BackDeploymentKind of this SILDeclRef.
189+
BackDeploymentKind backDeploymentKind : 2;
173190
/// The default argument index for a default argument getter.
174191
unsigned defaultArgIndex : 10;
175192

@@ -204,13 +221,15 @@ struct SILDeclRef {
204221

205222
/// Produces a null SILDeclRef.
206223
SILDeclRef()
207-
: loc(), kind(Kind::Func), isForeign(0), isDistributed(0), defaultArgIndex(0) {}
224+
: loc(), kind(Kind::Func), isForeign(0), isDistributed(0),
225+
backDeploymentKind(BackDeploymentKind::None), defaultArgIndex(0) {}
208226

209227
/// Produces a SILDeclRef of the given kind for the given decl.
210228
explicit SILDeclRef(
211229
ValueDecl *decl, Kind kind,
212230
bool isForeign = false,
213231
bool isDistributed = false,
232+
BackDeploymentKind backDeploymentKind = BackDeploymentKind::None,
214233
AutoDiffDerivativeFunctionIdentifier *derivativeId = nullptr);
215234

216235
/// Produces a SILDeclRef for the given ValueDecl or
@@ -224,7 +243,10 @@ struct SILDeclRef {
224243
/// for the containing ClassDecl.
225244
/// - If 'loc' is a global VarDecl, this returns its GlobalAccessor
226245
/// SILDeclRef.
227-
explicit SILDeclRef(Loc loc, bool isForeign = false, bool isDistributed = false);
246+
explicit SILDeclRef(
247+
Loc loc,
248+
bool isForeign = false,
249+
bool isDistributed = false);
228250

229251
/// See above put produces a prespecialization according to the signature.
230252
explicit SILDeclRef(Loc loc, GenericSignature prespecializationSig);
@@ -360,6 +382,7 @@ struct SILDeclRef {
360382
return loc.getOpaqueValue() == rhs.loc.getOpaqueValue() &&
361383
kind == rhs.kind && isForeign == rhs.isForeign &&
362384
isDistributed == rhs.isDistributed &&
385+
backDeploymentKind == rhs.backDeploymentKind &&
363386
defaultArgIndex == rhs.defaultArgIndex &&
364387
pointer == rhs.pointer;
365388
}
@@ -378,6 +401,7 @@ struct SILDeclRef {
378401
return SILDeclRef(loc.getOpaqueValue(), kind,
379402
/*foreign=*/foreign,
380403
/*distributed=*/false,
404+
backDeploymentKind,
381405
defaultArgIndex,
382406
pointer.get<AutoDiffDerivativeFunctionIdentifier *>());
383407
}
@@ -387,6 +411,16 @@ struct SILDeclRef {
387411
return SILDeclRef(loc.getOpaqueValue(), kind,
388412
/*foreign=*/false,
389413
/*distributed=*/distributed,
414+
backDeploymentKind,
415+
defaultArgIndex,
416+
pointer.get<AutoDiffDerivativeFunctionIdentifier *>());
417+
}
418+
/// Returns a copy of the decl with the given back deployment kind.
419+
SILDeclRef asBackDeploymentKind(BackDeploymentKind backDeploymentKind) const {
420+
return SILDeclRef(loc.getOpaqueValue(), kind,
421+
isForeign,
422+
isDistributed,
423+
backDeploymentKind,
390424
defaultArgIndex,
391425
pointer.get<AutoDiffDerivativeFunctionIdentifier *>());
392426
}
@@ -431,6 +465,14 @@ struct SILDeclRef {
431465
/// True if the decl ref references a thunk handling potentially distributed actor functions
432466
bool isDistributedThunk() const;
433467

468+
/// True if the decl ref references a thunk handling a call to a function that
469+
/// supports back deployment.
470+
bool isBackDeploymentThunk() const;
471+
472+
/// True if the decl ref references a function that is the back deployment
473+
/// fallback for an original function which may be unavailable at runtime.
474+
bool isBackDeploymentFallback() const;
475+
434476
/// True if the decl ref references a method which introduces a new vtable
435477
/// entry.
436478
bool requiresNewVTableEntry() const;
@@ -508,10 +550,12 @@ struct SILDeclRef {
508550
explicit SILDeclRef(void *opaqueLoc, Kind kind,
509551
bool isForeign,
510552
bool isDistributed,
553+
BackDeploymentKind backDeploymentKind,
511554
unsigned defaultArgIndex,
512555
AutoDiffDerivativeFunctionIdentifier *derivativeId)
513556
: loc(Loc::getFromOpaqueValue(opaqueLoc)), kind(kind),
514557
isForeign(isForeign), isDistributed(isDistributed),
558+
backDeploymentKind(backDeploymentKind),
515559
defaultArgIndex(defaultArgIndex),
516560
pointer(derivativeId) {}
517561
};
@@ -529,17 +573,18 @@ namespace llvm {
529573
template<> struct DenseMapInfo<swift::SILDeclRef> {
530574
using SILDeclRef = swift::SILDeclRef;
531575
using Kind = SILDeclRef::Kind;
576+
using BackDeploymentKind = SILDeclRef::BackDeploymentKind;
532577
using Loc = SILDeclRef::Loc;
533578
using PointerInfo = DenseMapInfo<void*>;
534579
using UnsignedInfo = DenseMapInfo<unsigned>;
535580

536581
static SILDeclRef getEmptyKey() {
537-
return SILDeclRef(PointerInfo::getEmptyKey(), Kind::Func, false, false, 0,
538-
nullptr);
582+
return SILDeclRef(PointerInfo::getEmptyKey(), Kind::Func, false, false,
583+
BackDeploymentKind::None, 0, nullptr);
539584
}
540585
static SILDeclRef getTombstoneKey() {
541586
return SILDeclRef(PointerInfo::getTombstoneKey(), Kind::Func, false, false,
542-
0, nullptr);
587+
BackDeploymentKind::None, 0, nullptr);
543588
}
544589
static unsigned getHashValue(swift::SILDeclRef Val) {
545590
unsigned h1 = PointerInfo::getHashValue(Val.loc.getOpaqueValue());
@@ -550,7 +595,9 @@ template<> struct DenseMapInfo<swift::SILDeclRef> {
550595
unsigned h4 = UnsignedInfo::getHashValue(Val.isForeign);
551596
unsigned h5 = PointerInfo::getHashValue(Val.pointer.getOpaqueValue());
552597
unsigned h6 = UnsignedInfo::getHashValue(Val.isDistributed);
553-
return h1 ^ (h2 << 4) ^ (h3 << 9) ^ (h4 << 7) ^ (h5 << 11) ^ (h6 << 8);
598+
unsigned h7 = UnsignedInfo::getHashValue(unsigned(Val.backDeploymentKind));
599+
return h1 ^ (h2 << 4) ^ (h3 << 9) ^ (h4 << 7) ^ (h5 << 11) ^ (h6 << 8) ^
600+
(h7 << 10);
554601
}
555602
static bool isEqual(swift::SILDeclRef const &LHS,
556603
swift::SILDeclRef const &RHS) {

lib/AST/ASTMangler.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,8 @@ void ASTMangler::appendSymbolKind(SymbolKind SKind) {
857857
case SymbolKind::DistributedThunk: return appendOperator("TE");
858858
case SymbolKind::DistributedAccessor: return appendOperator("TF");
859859
case SymbolKind::AccessibleFunctionRecord: return appendOperator("HF");
860+
case SymbolKind::BackDeploymentThunk: return appendOperator("Twb");
861+
case SymbolKind::BackDeploymentFallback: return appendOperator("TwB");
860862
}
861863
}
862864

lib/AST/Decl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7616,6 +7616,10 @@ bool AbstractFunctionDecl::isSendable() const {
76167616
return getAttrs().hasAttribute<SendableAttr>();
76177617
}
76187618

7619+
bool AbstractFunctionDecl::isBackDeployed() const {
7620+
return getAttrs().hasAttribute<BackDeployAttr>();
7621+
}
7622+
76197623
BraceStmt *AbstractFunctionDecl::getBody(bool canSynthesize) const {
76207624
if ((getBodyKind() == BodyKind::Synthesize ||
76217625
getBodyKind() == BodyKind::Unparsed) &&

lib/Demangling/Demangler.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ bool swift::Demangle::isFunctionAttr(Node::Kind kind) {
139139
case Node::Kind::AsyncAwaitResumePartialFunction:
140140
case Node::Kind::AsyncSuspendResumePartialFunction:
141141
case Node::Kind::AccessibleFunctionRecord:
142+
case Node::Kind::BackDeploymentThunk:
143+
case Node::Kind::BackDeploymentFallback:
142144
return true;
143145
default:
144146
return false;
@@ -2641,6 +2643,13 @@ NodePointer Demangler::demangleThunkOrSpecialization() {
26412643
return demangleAutoDiffFunctionOrSimpleThunk(
26422644
Node::Kind::AutoDiffFunction);
26432645
}
2646+
case 'w':
2647+
switch (nextChar()) {
2648+
case 'b': return createNode(Node::Kind::BackDeploymentThunk);
2649+
case 'B': return createNode(Node::Kind::BackDeploymentFallback);
2650+
default:
2651+
return nullptr;
2652+
}
26442653
default:
26452654
return nullptr;
26462655
}

lib/Demangling/NodePrinter.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,8 @@ class NodePrinter {
591591
case Node::Kind::AsyncAwaitResumePartialFunction:
592592
case Node::Kind::AsyncSuspendResumePartialFunction:
593593
case Node::Kind::AccessibleFunctionRecord:
594+
case Node::Kind::BackDeploymentThunk:
595+
case Node::Kind::BackDeploymentFallback:
594596
return false;
595597
}
596598
printer_unreachable("bad node kind");
@@ -2050,6 +2052,14 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth,
20502052
Printer << "dynamically replaceable variable for ";
20512053
}
20522054
return nullptr;
2055+
case Node::Kind::BackDeploymentThunk:
2056+
if (!Options.ShortenThunk) {
2057+
Printer << "back deployment thunk for ";
2058+
}
2059+
return nullptr;
2060+
case Node::Kind::BackDeploymentFallback:
2061+
Printer << "back deployment fallback for ";
2062+
return nullptr;
20532063
case Node::Kind::ProtocolSymbolicReference:
20542064
Printer << "protocol symbolic reference 0x";
20552065
Printer.writeHex(Node->getIndex());

lib/Demangling/OldRemangler.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2800,3 +2800,14 @@ ManglingError Remangler::mangleAccessibleFunctionRecord(Node *node,
28002800
Buffer << "HF";
28012801
return ManglingError::Success;
28022802
}
2803+
2804+
ManglingError Remangler::mangleBackDeploymentThunk(Node *node, unsigned depth) {
2805+
Buffer << "Twb";
2806+
return ManglingError::Success;
2807+
}
2808+
2809+
ManglingError Remangler::mangleBackDeploymentFallback(Node *node,
2810+
unsigned depth) {
2811+
Buffer << "TwB";
2812+
return ManglingError::Success;
2813+
}

lib/Demangling/Remangler.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,6 +1627,8 @@ ManglingError Remangler::mangleGlobal(Node *node, unsigned depth) {
16271627
case Node::Kind::AsyncAwaitResumePartialFunction:
16281628
case Node::Kind::AsyncSuspendResumePartialFunction:
16291629
case Node::Kind::AccessibleFunctionRecord:
1630+
case Node::Kind::BackDeploymentThunk:
1631+
case Node::Kind::BackDeploymentFallback:
16301632
mangleInReverseOrder = true;
16311633
break;
16321634
default:
@@ -3407,6 +3409,18 @@ ManglingError Remangler::mangleAccessibleFunctionRecord(Node *node,
34073409
return ManglingError::Success;
34083410
}
34093411

3412+
ManglingError Remangler::mangleBackDeploymentThunk(Node *node,
3413+
unsigned depth) {
3414+
Buffer << "Twb";
3415+
return ManglingError::Success;
3416+
}
3417+
3418+
ManglingError Remangler::mangleBackDeploymentFallback(Node *node,
3419+
unsigned depth) {
3420+
Buffer << "TwB";
3421+
return ManglingError::Success;
3422+
}
3423+
34103424
} // anonymous namespace
34113425

34123426
/// The top-level interface to the remangler.

0 commit comments

Comments
 (0)