Skip to content

Commit ebbe3ae

Browse files
committed
IRGen: Add implementation for dynamically replaceable functions
A dynamically replaceable function calls through a global variable that holds the function pointer. struct ChainEntry { void *(funPtr)(); struct ChainEntry *next; } ChainEntry dynamicallyReplaceableVar; void dynamicallyReplaceableFunction() { dynamicallyReplaceableVar.funPtr() } dynamic replacements will be chainable so the global variable also functions as the root entry in the chain of replacements. A dynamic replacement functions can call the previous implementation by going through its chain entry. ChainEntry chainEntryOf_dynamic_replacement_for_foo; void dynamic_replacement_for_foo() { // call the previous (original) implementation. chainEntryOf_dynamic_replacement_for_foo.funPtr(); }
1 parent 5f4e183 commit ebbe3ae

File tree

14 files changed

+343
-41
lines changed

14 files changed

+343
-41
lines changed

Diff for: docs/ABI/Mangling.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ types where the metadata itself has unknown layout.)
171171
global ::= global 'To' // swift-as-ObjC thunk
172172
global ::= global 'TD' // dynamic dispatch thunk
173173
global ::= global 'Td' // direct method reference thunk
174-
global ::= global 'TR' // implementation of a dynamic_replaceable function
174+
global ::= global 'TI' // implementation of a dynamic_replaceable function
175175
global ::= global 'TX' // function pointer of a dynamic_replaceable function
176176
global ::= entity entity 'TV' // vtable override thunk, derived followed by base
177177
global ::= type label-list? 'D' // type mangling for the debugger with label list for function types.

Diff for: include/swift/Demangling/DemangleNodes.def

+2
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ NODE(Directness)
7171
NODE(DynamicAttribute)
7272
NODE(DirectMethodReferenceAttribute)
7373
NODE(DynamicSelf)
74+
NODE(DynamicallyReplaceableFunctionImpl)
75+
NODE(DynamicallyReplaceableFunctionVar)
7476
CONTEXT_NODE(Enum)
7577
NODE(EnumCase)
7678
NODE(ErrorType)

Diff for: include/swift/IRGen/Linking.h

+51-6
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ class LinkEntity {
103103
// This field appears in associated conformance access functions.
104104
AssociatedConformanceIndexShift = 8,
105105
AssociatedConformanceIndexMask = ~KindMask,
106+
107+
// This field appears in SILFunction.
108+
IsDynamicallyReplaceableImplShift = 8,
109+
IsDynamicallyReplaceableImplMask = ~KindMask,
106110
};
107111
#define LINKENTITY_SET_FIELD(field, value) (value << field##Shift)
108112
#define LINKENTITY_GET_FIELD(value, field) ((value & field##Mask) >> field##Shift)
@@ -226,6 +230,14 @@ class LinkEntity {
226230
/// is stored in the data.
227231
DefaultAssociatedConformanceAccessor,
228232

233+
/// The original implementation of a dynamically replaceable function.
234+
/// The pointer is a AbstractStorageDecl*.
235+
DynamicallyReplaceableFunctionImpl,
236+
237+
/// A global function pointer for dynamically replaceable functions.
238+
/// The pointer is a AbstractStorageDecl*.
239+
DynamicallyReplaceableFunctionVariableAST,
240+
229241
/// A SIL function. The pointer is a SILFunction*.
230242
SILFunction,
231243

@@ -315,6 +327,9 @@ class LinkEntity {
315327

316328
/// A coroutine continuation prototype function.
317329
CoroutineContinuationPrototype,
330+
331+
/// A global function pointer for dynamically replaceable functions.
332+
DynamicallyReplaceableFunctionVariable,
318333
};
319334
friend struct llvm::DenseMapInfo<LinkEntity>;
320335

@@ -323,7 +338,7 @@ class LinkEntity {
323338
}
324339

325340
static bool isDeclKind(Kind k) {
326-
return k <= Kind::DefaultAssociatedConformanceAccessor;
341+
return k <= Kind::DynamicallyReplaceableFunctionVariableAST;
327342
}
328343
static bool isTypeKind(Kind k) {
329344
return k >= Kind::ProtocolWitnessTableLazyAccessFunction;
@@ -705,12 +720,15 @@ class LinkEntity {
705720
return entity;
706721
}
707722

708-
static LinkEntity forSILFunction(SILFunction *F)
709-
{
723+
static LinkEntity
724+
forSILFunction(SILFunction *F, bool IsDynamicallyReplaceableImplementation) {
710725
LinkEntity entity;
711726
entity.Pointer = F;
712727
entity.SecondaryPointer = nullptr;
713-
entity.Data = LINKENTITY_SET_FIELD(Kind, unsigned(Kind::SILFunction));
728+
entity.Data =
729+
LINKENTITY_SET_FIELD(Kind, unsigned(Kind::SILFunction)) |
730+
LINKENTITY_SET_FIELD(IsDynamicallyReplaceableImpl,
731+
(unsigned)IsDynamicallyReplaceableImplementation);
714732
return entity;
715733
}
716734

@@ -837,6 +855,29 @@ class LinkEntity {
837855
return entity;
838856
}
839857

858+
static LinkEntity forDynamicallyReplaceableFunctionVariable(SILFunction *F) {
859+
LinkEntity entity;
860+
entity.Pointer = F;
861+
entity.SecondaryPointer = nullptr;
862+
entity.Data = LINKENTITY_SET_FIELD(
863+
Kind, unsigned(Kind::DynamicallyReplaceableFunctionVariable));
864+
return entity;
865+
}
866+
867+
static LinkEntity
868+
forDynamicallyReplaceableFunctionVariable(AbstractFunctionDecl *decl) {
869+
LinkEntity entity;
870+
entity.setForDecl(Kind::DynamicallyReplaceableFunctionVariableAST, decl);
871+
return entity;
872+
}
873+
874+
static LinkEntity
875+
forDynamicallyReplaceableFunctionImpl(AbstractFunctionDecl *decl) {
876+
LinkEntity entity;
877+
entity.setForDecl(Kind::DynamicallyReplaceableFunctionImpl, decl);
878+
return entity;
879+
}
880+
840881
void mangle(llvm::raw_ostream &out) const;
841882
void mangle(SmallVectorImpl<char> &buffer) const;
842883
std::string mangleAsString() const;
@@ -863,7 +904,8 @@ class LinkEntity {
863904
}
864905

865906
SILFunction *getSILFunction() const {
866-
assert(getKind() == Kind::SILFunction);
907+
assert(getKind() == Kind::SILFunction ||
908+
getKind() == Kind::DynamicallyReplaceableFunctionVariable);
867909
return reinterpret_cast<SILFunction*>(Pointer);
868910
}
869911

@@ -899,7 +941,10 @@ class LinkEntity {
899941
assert(getKind() == Kind::AssociatedTypeWitnessTableAccessFunction);
900942
return reinterpret_cast<ProtocolDecl*>(Pointer);
901943
}
902-
944+
bool isDynamicallyReplaceable() const {
945+
assert(getKind() == Kind::SILFunction);
946+
return LINKENTITY_GET_FIELD(Data, IsDynamicallyReplaceableImpl);
947+
}
903948
bool isValueWitness() const { return getKind() == Kind::ValueWitness; }
904949
CanType getType() const {
905950
assert(isTypeKind(getKind()));

Diff for: lib/Demangling/Demangler.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ static bool isFunctionAttr(Node::Kind kind) {
111111
case Node::Kind::OutlinedVariable:
112112
case Node::Kind::OutlinedBridgedMethod:
113113
case Node::Kind::MergedFunction:
114+
case Node::Kind::DynamicallyReplaceableFunctionImpl:
115+
case Node::Kind::DynamicallyReplaceableFunctionVar:
114116
return true;
115117
default:
116118
return false;
@@ -1933,6 +1935,8 @@ NodePointer Demangler::demangleThunkOrSpecialization() {
19331935
case 'a': return createNode(Node::Kind::PartialApplyObjCForwarder);
19341936
case 'A': return createNode(Node::Kind::PartialApplyForwarder);
19351937
case 'm': return createNode(Node::Kind::MergedFunction);
1938+
case 'X': return createNode(Node::Kind::DynamicallyReplaceableFunctionVar);
1939+
case 'I': return createNode(Node::Kind::DynamicallyReplaceableFunctionImpl);
19361940
case 'C': {
19371941
NodePointer type = popNode(Node::Kind::Type);
19381942
return createWithChild(Node::Kind::CoroutineContinuationPrototype, type);

Diff for: lib/Demangling/NodePrinter.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@ class NodePrinter {
493493
case Node::Kind::DependentProtocolConformanceInherited:
494494
case Node::Kind::DependentProtocolConformanceRoot:
495495
case Node::Kind::ProtocolConformanceRef:
496+
case Node::Kind::DynamicallyReplaceableFunctionImpl:
497+
case Node::Kind::DynamicallyReplaceableFunctionVar:
496498
return false;
497499
}
498500
printer_unreachable("bad node kind");
@@ -1521,6 +1523,16 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
15211523
Printer << "type symbolic reference 0x";
15221524
Printer.writeHex(Node->getIndex());
15231525
return nullptr;
1526+
case Node::Kind::DynamicallyReplaceableFunctionImpl:
1527+
if (!Options.ShortenThunk) {
1528+
Printer << "dynamically replaceable thunk for ";
1529+
}
1530+
return nullptr;
1531+
case Node::Kind::DynamicallyReplaceableFunctionVar:
1532+
if (!Options.ShortenThunk) {
1533+
Printer << "dynamically replaceable variable for ";
1534+
}
1535+
return nullptr;
15241536
case Node::Kind::ProtocolSymbolicReference:
15251537
Printer << "protocol symbolic reference 0x";
15261538
Printer.writeHex(Node->getIndex());

Diff for: lib/Demangling/OldRemangler.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,14 @@ void Remangler::mangleMergedFunction(Node *node) {
832832
Out << "Tm";
833833
}
834834

835+
void Remangler::mangleDynamicallyReplaceableFunctionImpl(Node *node) {
836+
Out << "TI";
837+
}
838+
839+
void Remangler::mangleDynamicallyReplaceableFunctionVar(Node *node) {
840+
Out << "TX";
841+
}
842+
835843
void Remangler::mangleDirectness(Node *node) {
836844
auto getChar = [](Directness d) -> char {
837845
switch (d) {

Diff for: lib/Demangling/Remangler.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,8 @@ void Remangler::mangleGlobal(Node *node) {
12551255
case Node::Kind::VTableAttribute:
12561256
case Node::Kind::DirectMethodReferenceAttribute:
12571257
case Node::Kind::MergedFunction:
1258+
case Node::Kind::DynamicallyReplaceableFunctionImpl:
1259+
case Node::Kind::DynamicallyReplaceableFunctionVar:
12581260
mangleInReverseOrder = true;
12591261
break;
12601262
default:
@@ -1587,6 +1589,14 @@ void Remangler::mangleMergedFunction(Node *node) {
15871589
Buffer << "Tm";
15881590
}
15891591

1592+
void Remangler::mangleDynamicallyReplaceableFunctionImpl(Node *node) {
1593+
Buffer << "TI";
1594+
}
1595+
1596+
void Remangler::mangleDynamicallyReplaceableFunctionVar(Node *node) {
1597+
Buffer << "TX";
1598+
}
1599+
15901600
void Remangler::manglePostfixOperator(Node *node) {
15911601
mangleIdentifierImpl(node, /*isOperator*/ true);
15921602
Buffer << "oP";

0 commit comments

Comments
 (0)