Skip to content

Commit 44b3a47

Browse files
Merge pull request #20333 from aschwaighofer/dynamic_function_replacement
Dynamic function replacement
2 parents 7fa22c4 + fff1333 commit 44b3a47

File tree

138 files changed

+3875
-551
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

138 files changed

+3875
-551
lines changed

docs/ABI/Mangling.rst

+2
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ 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 'TI' // implementation of a dynamic_replaceable function
175+
global ::= global 'TX' // function pointer of a dynamic_replaceable function
174176
global ::= entity entity 'TV' // vtable override thunk, derived followed by base
175177
global ::= type label-list? 'D' // type mangling for the debugger with label list for function types.
176178
global ::= type 'TC' // continuation prototype (not actually used for real symbols)

include/swift/ABI/Metadata.h

+70
Original file line numberDiff line numberDiff line change
@@ -4231,6 +4231,76 @@ TargetTypeContextDescriptor<Runtime>::getSingletonMetadataInitialization() const
42314231
}
42324232
}
42334233

4234+
/// An entry in the chain of dynamic replacement functions.
4235+
struct DynamicReplacementChainEntry {
4236+
void *implementationFunction;
4237+
DynamicReplacementChainEntry *next;
4238+
};
4239+
4240+
/// A record describing the root of dynamic replacements for a function.
4241+
struct DynamicReplacementKey {
4242+
RelativeDirectPointer<DynamicReplacementChainEntry, false> root;
4243+
uint32_t flags;
4244+
};
4245+
4246+
/// A record describing a dynamic function replacement.
4247+
class DynamicReplacementDescriptor {
4248+
RelativeIndirectablePointer<DynamicReplacementKey, false> replacedFunctionKey;
4249+
RelativeDirectPointer<void, false> replacementFunction;
4250+
RelativeDirectPointer<DynamicReplacementChainEntry, false> chainEntry;
4251+
uint32_t flags;
4252+
4253+
public:
4254+
/// Enable this replacement by changing the function's replacement chain's
4255+
/// root entry.
4256+
/// This replacement must be done while holding a global lock that guards this
4257+
/// function's chain. Currently this is done by holding the
4258+
/// \p DynamicReplacementLock.
4259+
void enableReplacement() const;
4260+
4261+
/// Disable this replacement by changing the function's replacement chain's
4262+
/// root entry.
4263+
/// This replacement must be done while holding a global lock that guards this
4264+
/// function's chain. Currently this is done by holding the
4265+
/// \p DynamicReplacementLock.
4266+
void disableReplacement() const;
4267+
4268+
uint32_t getFlags() const { return flags; }
4269+
};
4270+
4271+
/// A collection of dynamic replacement records.
4272+
class DynamicReplacementScope
4273+
: private swift::ABI::TrailingObjects<DynamicReplacementScope,
4274+
DynamicReplacementDescriptor> {
4275+
4276+
uint32_t flags;
4277+
uint32_t numReplacements;
4278+
4279+
using TrailingObjects =
4280+
swift::ABI::TrailingObjects<DynamicReplacementScope,
4281+
DynamicReplacementDescriptor>;
4282+
friend TrailingObjects;
4283+
4284+
ArrayRef<DynamicReplacementDescriptor> getReplacementDescriptors() const {
4285+
return {this->template getTrailingObjects<DynamicReplacementDescriptor>(),
4286+
numReplacements};
4287+
}
4288+
4289+
public:
4290+
void enable() const {
4291+
for (auto &descriptor : getReplacementDescriptors()) {
4292+
descriptor.enableReplacement();
4293+
}
4294+
}
4295+
4296+
void disable() const {
4297+
for (auto &descriptor : getReplacementDescriptors()) {
4298+
descriptor.disableReplacement();
4299+
}
4300+
}
4301+
uint32_t getFlags() { return flags; }
4302+
};
4303+
42344304
} // end namespace swift
42354305

42364306
#pragma clang diagnostic pop

include/swift/AST/Attr.def

+3
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,9 @@ SIMPLE_DECL_ATTR(_nonoverride, NonOverride,
378378
OnFunc | OnAccessor | OnVar | OnSubscript | OnConstructor | OnAssociatedType |
379379
UserInaccessible | NotSerialized,
380380
79)
381+
DECL_ATTR(_dynamicReplacement, DynamicReplacement,
382+
OnAbstractFunction | OnVar | OnSubscript | UserInaccessible,
383+
80)
381384

382385
#undef TYPE_ATTR
383386
#undef DECL_ATTR_ALIAS

include/swift/AST/Attr.h

+78
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ class ASTPrinter;
4444
class ASTContext;
4545
struct PrintOptions;
4646
class Decl;
47+
class AbstractFunctionDecl;
48+
class FuncDecl;
4749
class ClassDecl;
4850
class GenericFunctionType;
4951
class LazyConformanceLoader;
@@ -205,6 +207,12 @@ class DeclAttribute : public AttributeBase {
205207
Swift3Inferred : 1
206208
);
207209

210+
SWIFT_INLINE_BITFIELD(DynamicReplacementAttr, DeclAttribute, 1,
211+
/// Whether this attribute has location information that trails the main
212+
/// record, which contains the locations of the parentheses and any names.
213+
HasTrailingLocationInfo : 1
214+
);
215+
208216
SWIFT_INLINE_BITFIELD(AbstractAccessControlAttr, DeclAttribute, 3,
209217
AccessLevel : 3
210218
);
@@ -893,6 +901,76 @@ class ObjCAttr final : public DeclAttribute,
893901
}
894902
};
895903

904+
/// The @_dynamicReplacement(for:) attribute.
905+
class DynamicReplacementAttr final
906+
: public DeclAttribute,
907+
private llvm::TrailingObjects<DynamicReplacementAttr, SourceLoc> {
908+
friend TrailingObjects;
909+
910+
DeclName ReplacedFunctionName;
911+
AbstractFunctionDecl *ReplacedFunction;
912+
913+
/// Create an @_dynamicReplacement(for:) attribute written in the source.
914+
DynamicReplacementAttr(SourceLoc atLoc, SourceRange baseRange,
915+
DeclName replacedFunctionName, SourceRange parenRange);
916+
917+
explicit DynamicReplacementAttr(DeclName name)
918+
: DeclAttribute(DAK_DynamicReplacement, SourceLoc(), SourceRange(),
919+
/*Implicit=*/false),
920+
ReplacedFunctionName(name), ReplacedFunction(nullptr) {
921+
Bits.DynamicReplacementAttr.HasTrailingLocationInfo = false;
922+
}
923+
924+
/// Retrieve the trailing location information.
925+
MutableArrayRef<SourceLoc> getTrailingLocations() {
926+
assert(Bits.DynamicReplacementAttr.HasTrailingLocationInfo);
927+
unsigned length = 2;
928+
return {getTrailingObjects<SourceLoc>(), length};
929+
}
930+
931+
/// Retrieve the trailing location information.
932+
ArrayRef<SourceLoc> getTrailingLocations() const {
933+
assert(Bits.DynamicReplacementAttr.HasTrailingLocationInfo);
934+
unsigned length = 2; // lParens, rParens
935+
return {getTrailingObjects<SourceLoc>(), length};
936+
}
937+
938+
public:
939+
static DynamicReplacementAttr *
940+
create(ASTContext &Context, SourceLoc AtLoc, SourceLoc DynReplLoc,
941+
SourceLoc LParenLoc, DeclName replacedFunction, SourceLoc RParenLoc);
942+
943+
static DynamicReplacementAttr *create(ASTContext &ctx,
944+
DeclName replacedFunction);
945+
946+
static DynamicReplacementAttr *create(ASTContext &ctx,
947+
DeclName replacedFunction,
948+
AbstractFunctionDecl *replacedFuncDecl);
949+
950+
DeclName getReplacedFunctionName() const {
951+
return ReplacedFunctionName;
952+
}
953+
954+
AbstractFunctionDecl *getReplacedFunction() const {
955+
return ReplacedFunction;
956+
}
957+
958+
void setReplacedFunction(AbstractFunctionDecl *f) {
959+
assert(ReplacedFunction == nullptr);
960+
ReplacedFunction = f;
961+
}
962+
963+
/// Retrieve the location of the opening parentheses, if there is one.
964+
SourceLoc getLParenLoc() const;
965+
966+
/// Retrieve the location of the closing parentheses, if there is one.
967+
SourceLoc getRParenLoc() const;
968+
969+
static bool classof(const DeclAttribute *DA) {
970+
return DA->getKind() == DAK_DynamicReplacement;
971+
}
972+
};
973+
896974
/// Represents any sort of access control modifier.
897975
class AbstractAccessControlAttr : public DeclAttribute {
898976
protected:

include/swift/AST/Decl.h

+4
Original file line numberDiff line numberDiff line change
@@ -2590,6 +2590,10 @@ class ValueDecl : public Decl {
25902590
/// Is this declaration marked with 'dynamic'?
25912591
bool isDynamic() const;
25922592

2593+
bool isObjCDynamic() const {
2594+
return isObjC() && isDynamic();
2595+
}
2596+
25932597
/// Set whether this type is 'dynamic' or not.
25942598
void setIsDynamic(bool value);
25952599

include/swift/AST/DiagnosticsParse.def

+11
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,8 @@ ERROR(expected_sil_rbrace,none,
625625
"expected '}' at the end of a sil body", ())
626626
ERROR(expected_sil_function_type, none,
627627
"sil function expected to have SIL function type", ())
628+
ERROR(sil_dynamically_replaced_func_not_found,none,
629+
"dynamically replaced function not found %0", (Identifier))
628630

629631
// SIL Stage
630632
ERROR(expected_sil_stage_name, none,
@@ -1406,6 +1408,15 @@ ERROR(attr_nskeyedarchiverencodenongenericsubclassesonly_removed, none,
14061408
"@NSKeyedArchiverEncodeNonGenericSubclassesOnly is no longer necessary",
14071409
())
14081410

1411+
ERROR(attr_dynamic_replacement_expected_rparen,none,
1412+
"expected ')' after function name for @_dynamicReplacement", ())
1413+
ERROR(attr_dynamic_replacement_expected_function,none,
1414+
"expected a function name in @_dynamicReplacement(for:)", ())
1415+
ERROR(attr_dynamic_replacement_expected_for,none,
1416+
"expected 'for' in '_dynamicReplacement' attribute", ())
1417+
ERROR(attr_dynamic_replacement_expected_colon,none,
1418+
"expected ':' after @_dynamicReplacement(for", ())
1419+
14091420
// opened
14101421
ERROR(opened_attribute_expected_lparen,none,
14111422
"expected '(' after 'opened' attribute", ())

include/swift/AST/DiagnosticsSema.def

+27
Original file line numberDiff line numberDiff line change
@@ -3878,10 +3878,37 @@ ERROR(dynamic_with_final,none,
38783878
ERROR(dynamic_with_nonobjc,none,
38793879
"a declaration cannot be both '@nonobjc' and 'dynamic'",
38803880
())
3881+
ERROR(dynamic_with_transparent,none,
3882+
"a declaration cannot be both '@_tranparent' and 'dynamic'",
3883+
())
38813884
ERROR(dynamic_requires_objc,none,
38823885
"'dynamic' %0 %1 must also be '@objc'",
38833886
(DescriptiveDeclKind, DeclName))
38843887

3888+
//------------------------------------------------------------------------------
3889+
// MARK: @_dynamicReplacement(for:)
3890+
//------------------------------------------------------------------------------
3891+
3892+
ERROR(dynamic_replacement_accessor_type_mismatch, none,
3893+
"replaced accessor %0's type does not match", (DeclName))
3894+
ERROR(dynamic_replacement_accessor_not_dynamic, none,
3895+
"replaced accessor for %0 is not marked dynamic", (DeclName))
3896+
ERROR(dynamic_replacement_accessor_not_explicit, none,
3897+
"replaced accessor %select{get|set|_read|_modify|willSet|didSet|unsafeAddress|addressWithOwner|addressWithNativeOwner|unsafeMutableAddress|mutableAddressWithOwner|}0 for %1 is not explicitly defined",
3898+
(unsigned, DeclName))
3899+
ERROR(dynamic_replacement_function_not_dynamic, none,
3900+
"replaced function %0 is not marked dynamic", (DeclName))
3901+
ERROR(dynamic_replacement_function_not_found, none,
3902+
"replaced function %0 could not be found", (DeclName))
3903+
ERROR(dynamic_replacement_accessor_not_found, none,
3904+
"replaced accessor for %0 could not be found", (DeclName))
3905+
ERROR(dynamic_replacement_function_of_type_not_found, none,
3906+
"replaced function %0 of type %1 could not be found", (DeclName, Type))
3907+
NOTE(dynamic_replacement_found_function_of_type, none,
3908+
"found function %0 of type %1", (DeclName, Type))
3909+
ERROR(dynamic_replacement_not_in_extension, none,
3910+
"dynamicReplacement(for:) of %0 is not defined in an extension or at the file level", (DeclName))
3911+
38853912
//------------------------------------------------------------------------------
38863913
// MARK: @available
38873914
//------------------------------------------------------------------------------

include/swift/AST/StorageImpl.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,12 @@ class AccessStrategy {
160160

161161
Kind getKind() const { return TheKind; }
162162

163+
bool hasAccessor() const {
164+
return TheKind == DirectToAccessor || TheKind == DispatchToAccessor;
165+
}
166+
163167
AccessorKind getAccessor() const {
164-
assert(TheKind == DirectToAccessor || TheKind == DispatchToAccessor);
168+
assert(hasAccessor());
165169
return FirstAccessor;
166170
}
167171

include/swift/Basic/LangOptions.h

+4
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ namespace swift {
144144
/// was not compiled with -enable-testing.
145145
bool EnableTestableAttrRequiresTestableModule = true;
146146

147+
/// If true, the 'dynamic' attribute is added to all applicable
148+
/// declarations.
149+
bool EnableImplicitDynamic = false;
150+
147151
///
148152
/// Flags for developers
149153
///

include/swift/Demangling/DemangleNodes.def

+3
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ NODE(Directness)
7171
NODE(DynamicAttribute)
7272
NODE(DirectMethodReferenceAttribute)
7373
NODE(DynamicSelf)
74+
NODE(DynamicallyReplaceableFunctionImpl)
75+
NODE(DynamicallyReplaceableFunctionKey)
76+
NODE(DynamicallyReplaceableFunctionVar)
7477
CONTEXT_NODE(Enum)
7578
NODE(EnumCase)
7679
NODE(ErrorType)

0 commit comments

Comments
 (0)