-
Notifications
You must be signed in to change notification settings - Fork 10.4k
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
Dynamic function replacement #20333
Dynamic function replacement #20333
Conversation
lib/AST/ASTDumper.cpp
Outdated
@@ -768,8 +768,9 @@ namespace { | |||
OS << " final"; | |||
if (VD->isObjC()) | |||
OS << " @objc"; | |||
if (VD->isDynamic()) | |||
if (VD->isDynamic()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this edit necessary?
lib/SIL/SILVerifier.cpp
Outdated
@@ -1402,6 +1402,14 @@ class SILVerifier : public SILVerifierBase<SILVerifier> { | |||
|
|||
SILFunction *RefF = FRI->getReferencedFunction(); | |||
|
|||
if (isa<FunctionRefInst>(FRI)) | |||
require(!RefF->isDynamicallyReplaceable(), "function_ref cannot reference a [dynamically_replaceable] function"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These lines are too long
How does it work if a class method is dynamically replaceable? Is it still called via class_method and then we have to emit a vtable thunk which does the dynamic_function_ref? |
|
The [dynamically_replaceable] SIL function does the dispatch:
|
dynamic_function_ref is different to function_ref only in that it is verified that we call a SIL function that is [dynamically_replaceable]. |
To answer your question: yes we still dispatch via class_method to the callee. |
Dynamic functions will allow replacement of their implementation at runtime.
'dynamic' functions are marked as [dynamically_replaceable].
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(); }
%0 = dynamic_function_ref @dynamically_replaceable_function apply %0() Calls a [dynamically_replaceable] function. %0 = prev_dynamic_function_ref @dynamic_replacement_function apply %0 Calls the previous implementation that dynamic_replacement_function replaced.
6b85d1b
to
23922dc
Compare
Dynamic replacements are currently written in extensions as extension ExtendedType { @_dynamicReplacement(for: replacedFun()) func replacement() { } } The runtime implementation allows an implementation in the future where dynamic replacements are gather in a scope and can be dynamically enabled and disabled. For example: dynamic_extension_scope CollectionOfReplacements { extension ExtentedType { func replacedFun() {} } extension ExtentedType2 { func replacedFun() {} } } CollectionOfReplacements.enable() CollectionOfReplacements.disable()
23922dc
to
f1b53eb
Compare
@swift-ci Please test |
1 similar comment
@swift-ci Please test |
Build failed |
@swift-ci Please test |
Build failed |
Build failed |
@swift-ci Please test |
1 similar comment
@swift-ci Please test |
Build failed |
@swift-ci Please clean test |
Build failed |
Build failed |
@swift-ci Please test |
Build failed |
Build failed |
@swift-ci Please test os x platform |
@swift-ci Please test source compatibility |
The source compatibility failure is the same that also occurs on trunk. |
Hi, I could not work on the scope:
Is it public? By the way, if there are two replacement methods to replace the original method, how to call the chain?
I hope to get the
Or, get the
But now, I get the
Lost the |
can I use it to class method? |
Implement dynamic function replacement as described in https://forums.swift.org/t/dynamic-method-replacement.
Allow
dynamic
on non-@objc
classes,struct
, andenum
functions, properties, initializers.Dynamic replacements are currently expressed by adding the
@_dynamicReplacement(for:)
attribute on functions defined in an extensions of the type or at the top-level.Dynamic replacements become active at load time of the module containing the replacement.
The runtime implementation allows for an implementation in the future where dynamic replacements can be grouped in an 'dynamic replacement' scope and the scope can be dynamically enabled/disabled.
Dynamic replacements chain such that a dynamic replacement can call the previously active implementation of the dynamically replaced function.