Skip to content

Commit

Permalink
Merge pull request #20333 from aschwaighofer/dynamic_function_replace…
Browse files Browse the repository at this point in the history
…ment

Dynamic function replacement
  • Loading branch information
aschwaighofer authored Nov 7, 2018
2 parents 7fa22c4 + fff1333 commit 44b3a47
Show file tree
Hide file tree
Showing 138 changed files with 3,875 additions and 551 deletions.
2 changes: 2 additions & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ types where the metadata itself has unknown layout.)
global ::= global 'To' // swift-as-ObjC thunk
global ::= global 'TD' // dynamic dispatch thunk
global ::= global 'Td' // direct method reference thunk
global ::= global 'TI' // implementation of a dynamic_replaceable function
global ::= global 'TX' // function pointer of a dynamic_replaceable 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
70 changes: 70 additions & 0 deletions include/swift/ABI/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -4231,6 +4231,76 @@ TargetTypeContextDescriptor<Runtime>::getSingletonMetadataInitialization() const
}
}

/// An entry in the chain of dynamic replacement functions.
struct DynamicReplacementChainEntry {
void *implementationFunction;
DynamicReplacementChainEntry *next;
};

/// A record describing the root of dynamic replacements for a function.
struct DynamicReplacementKey {
RelativeDirectPointer<DynamicReplacementChainEntry, false> root;
uint32_t flags;
};

/// A record describing a dynamic function replacement.
class DynamicReplacementDescriptor {
RelativeIndirectablePointer<DynamicReplacementKey, false> replacedFunctionKey;
RelativeDirectPointer<void, false> replacementFunction;
RelativeDirectPointer<DynamicReplacementChainEntry, false> chainEntry;
uint32_t flags;

public:
/// Enable this replacement by changing the function's replacement chain's
/// root entry.
/// This replacement must be done while holding a global lock that guards this
/// function's chain. Currently this is done by holding the
/// \p DynamicReplacementLock.
void enableReplacement() const;

/// Disable this replacement by changing the function's replacement chain's
/// root entry.
/// This replacement must be done while holding a global lock that guards this
/// function's chain. Currently this is done by holding the
/// \p DynamicReplacementLock.
void disableReplacement() const;

uint32_t getFlags() const { return flags; }
};

/// A collection of dynamic replacement records.
class DynamicReplacementScope
: private swift::ABI::TrailingObjects<DynamicReplacementScope,
DynamicReplacementDescriptor> {

uint32_t flags;
uint32_t numReplacements;

using TrailingObjects =
swift::ABI::TrailingObjects<DynamicReplacementScope,
DynamicReplacementDescriptor>;
friend TrailingObjects;

ArrayRef<DynamicReplacementDescriptor> getReplacementDescriptors() const {
return {this->template getTrailingObjects<DynamicReplacementDescriptor>(),
numReplacements};
}

public:
void enable() const {
for (auto &descriptor : getReplacementDescriptors()) {
descriptor.enableReplacement();
}
}

void disable() const {
for (auto &descriptor : getReplacementDescriptors()) {
descriptor.disableReplacement();
}
}
uint32_t getFlags() { return flags; }
};

} // end namespace swift

#pragma clang diagnostic pop
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,9 @@ SIMPLE_DECL_ATTR(_nonoverride, NonOverride,
OnFunc | OnAccessor | OnVar | OnSubscript | OnConstructor | OnAssociatedType |
UserInaccessible | NotSerialized,
79)
DECL_ATTR(_dynamicReplacement, DynamicReplacement,
OnAbstractFunction | OnVar | OnSubscript | UserInaccessible,
80)

#undef TYPE_ATTR
#undef DECL_ATTR_ALIAS
Expand Down
78 changes: 78 additions & 0 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class ASTPrinter;
class ASTContext;
struct PrintOptions;
class Decl;
class AbstractFunctionDecl;
class FuncDecl;
class ClassDecl;
class GenericFunctionType;
class LazyConformanceLoader;
Expand Down Expand Up @@ -205,6 +207,12 @@ class DeclAttribute : public AttributeBase {
Swift3Inferred : 1
);

SWIFT_INLINE_BITFIELD(DynamicReplacementAttr, DeclAttribute, 1,
/// Whether this attribute has location information that trails the main
/// record, which contains the locations of the parentheses and any names.
HasTrailingLocationInfo : 1
);

SWIFT_INLINE_BITFIELD(AbstractAccessControlAttr, DeclAttribute, 3,
AccessLevel : 3
);
Expand Down Expand Up @@ -893,6 +901,76 @@ class ObjCAttr final : public DeclAttribute,
}
};

/// The @_dynamicReplacement(for:) attribute.
class DynamicReplacementAttr final
: public DeclAttribute,
private llvm::TrailingObjects<DynamicReplacementAttr, SourceLoc> {
friend TrailingObjects;

DeclName ReplacedFunctionName;
AbstractFunctionDecl *ReplacedFunction;

/// Create an @_dynamicReplacement(for:) attribute written in the source.
DynamicReplacementAttr(SourceLoc atLoc, SourceRange baseRange,
DeclName replacedFunctionName, SourceRange parenRange);

explicit DynamicReplacementAttr(DeclName name)
: DeclAttribute(DAK_DynamicReplacement, SourceLoc(), SourceRange(),
/*Implicit=*/false),
ReplacedFunctionName(name), ReplacedFunction(nullptr) {
Bits.DynamicReplacementAttr.HasTrailingLocationInfo = false;
}

/// Retrieve the trailing location information.
MutableArrayRef<SourceLoc> getTrailingLocations() {
assert(Bits.DynamicReplacementAttr.HasTrailingLocationInfo);
unsigned length = 2;
return {getTrailingObjects<SourceLoc>(), length};
}

/// Retrieve the trailing location information.
ArrayRef<SourceLoc> getTrailingLocations() const {
assert(Bits.DynamicReplacementAttr.HasTrailingLocationInfo);
unsigned length = 2; // lParens, rParens
return {getTrailingObjects<SourceLoc>(), length};
}

public:
static DynamicReplacementAttr *
create(ASTContext &Context, SourceLoc AtLoc, SourceLoc DynReplLoc,
SourceLoc LParenLoc, DeclName replacedFunction, SourceLoc RParenLoc);

static DynamicReplacementAttr *create(ASTContext &ctx,
DeclName replacedFunction);

static DynamicReplacementAttr *create(ASTContext &ctx,
DeclName replacedFunction,
AbstractFunctionDecl *replacedFuncDecl);

DeclName getReplacedFunctionName() const {
return ReplacedFunctionName;
}

AbstractFunctionDecl *getReplacedFunction() const {
return ReplacedFunction;
}

void setReplacedFunction(AbstractFunctionDecl *f) {
assert(ReplacedFunction == nullptr);
ReplacedFunction = f;
}

/// Retrieve the location of the opening parentheses, if there is one.
SourceLoc getLParenLoc() const;

/// Retrieve the location of the closing parentheses, if there is one.
SourceLoc getRParenLoc() const;

static bool classof(const DeclAttribute *DA) {
return DA->getKind() == DAK_DynamicReplacement;
}
};

/// Represents any sort of access control modifier.
class AbstractAccessControlAttr : public DeclAttribute {
protected:
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2590,6 +2590,10 @@ class ValueDecl : public Decl {
/// Is this declaration marked with 'dynamic'?
bool isDynamic() const;

bool isObjCDynamic() const {
return isObjC() && isDynamic();
}

/// Set whether this type is 'dynamic' or not.
void setIsDynamic(bool value);

Expand Down
11 changes: 11 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,8 @@ ERROR(expected_sil_rbrace,none,
"expected '}' at the end of a sil body", ())
ERROR(expected_sil_function_type, none,
"sil function expected to have SIL function type", ())
ERROR(sil_dynamically_replaced_func_not_found,none,
"dynamically replaced function not found %0", (Identifier))

// SIL Stage
ERROR(expected_sil_stage_name, none,
Expand Down Expand Up @@ -1406,6 +1408,15 @@ ERROR(attr_nskeyedarchiverencodenongenericsubclassesonly_removed, none,
"@NSKeyedArchiverEncodeNonGenericSubclassesOnly is no longer necessary",
())

ERROR(attr_dynamic_replacement_expected_rparen,none,
"expected ')' after function name for @_dynamicReplacement", ())
ERROR(attr_dynamic_replacement_expected_function,none,
"expected a function name in @_dynamicReplacement(for:)", ())
ERROR(attr_dynamic_replacement_expected_for,none,
"expected 'for' in '_dynamicReplacement' attribute", ())
ERROR(attr_dynamic_replacement_expected_colon,none,
"expected ':' after @_dynamicReplacement(for", ())

// opened
ERROR(opened_attribute_expected_lparen,none,
"expected '(' after 'opened' attribute", ())
Expand Down
27 changes: 27 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -3878,10 +3878,37 @@ ERROR(dynamic_with_final,none,
ERROR(dynamic_with_nonobjc,none,
"a declaration cannot be both '@nonobjc' and 'dynamic'",
())
ERROR(dynamic_with_transparent,none,
"a declaration cannot be both '@_tranparent' and 'dynamic'",
())
ERROR(dynamic_requires_objc,none,
"'dynamic' %0 %1 must also be '@objc'",
(DescriptiveDeclKind, DeclName))

//------------------------------------------------------------------------------
// MARK: @_dynamicReplacement(for:)
//------------------------------------------------------------------------------

ERROR(dynamic_replacement_accessor_type_mismatch, none,
"replaced accessor %0's type does not match", (DeclName))
ERROR(dynamic_replacement_accessor_not_dynamic, none,
"replaced accessor for %0 is not marked dynamic", (DeclName))
ERROR(dynamic_replacement_accessor_not_explicit, none,
"replaced accessor %select{get|set|_read|_modify|willSet|didSet|unsafeAddress|addressWithOwner|addressWithNativeOwner|unsafeMutableAddress|mutableAddressWithOwner|}0 for %1 is not explicitly defined",
(unsigned, DeclName))
ERROR(dynamic_replacement_function_not_dynamic, none,
"replaced function %0 is not marked dynamic", (DeclName))
ERROR(dynamic_replacement_function_not_found, none,
"replaced function %0 could not be found", (DeclName))
ERROR(dynamic_replacement_accessor_not_found, none,
"replaced accessor for %0 could not be found", (DeclName))
ERROR(dynamic_replacement_function_of_type_not_found, none,
"replaced function %0 of type %1 could not be found", (DeclName, Type))
NOTE(dynamic_replacement_found_function_of_type, none,
"found function %0 of type %1", (DeclName, Type))
ERROR(dynamic_replacement_not_in_extension, none,
"dynamicReplacement(for:) of %0 is not defined in an extension or at the file level", (DeclName))

//------------------------------------------------------------------------------
// MARK: @available
//------------------------------------------------------------------------------
Expand Down
6 changes: 5 additions & 1 deletion include/swift/AST/StorageImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,12 @@ class AccessStrategy {

Kind getKind() const { return TheKind; }

bool hasAccessor() const {
return TheKind == DirectToAccessor || TheKind == DispatchToAccessor;
}

AccessorKind getAccessor() const {
assert(TheKind == DirectToAccessor || TheKind == DispatchToAccessor);
assert(hasAccessor());
return FirstAccessor;
}

Expand Down
4 changes: 4 additions & 0 deletions include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ namespace swift {
/// was not compiled with -enable-testing.
bool EnableTestableAttrRequiresTestableModule = true;

/// If true, the 'dynamic' attribute is added to all applicable
/// declarations.
bool EnableImplicitDynamic = false;

///
/// Flags for developers
///
Expand Down
3 changes: 3 additions & 0 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ NODE(Directness)
NODE(DynamicAttribute)
NODE(DirectMethodReferenceAttribute)
NODE(DynamicSelf)
NODE(DynamicallyReplaceableFunctionImpl)
NODE(DynamicallyReplaceableFunctionKey)
NODE(DynamicallyReplaceableFunctionVar)
CONTEXT_NODE(Enum)
NODE(EnumCase)
NODE(ErrorType)
Expand Down
Loading

0 comments on commit 44b3a47

Please sign in to comment.