-
Notifications
You must be signed in to change notification settings - Fork 10.5k
stdlib: Add backward deployment versions for the dynamic-replacement runtime functions #25473
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
stdlib: Add backward deployment versions for the dynamic-replacement runtime functions #25473
Conversation
dynamic-replacement runtime functions. The recent change of how we do dynamic replacements added 2 new runtime functions. This patch adds those functions to the Compatibility50 static archive. This will allow backward deployment to a swift 5.0 runtime. Patch by Erik Eckstein with a modification to call the standard libraries implementation (marked as weak) when it is available. This ensures we can change the implementation in the future and are not ABI locked. rdar://problem/51601233
@jordan I have not moved the functions out into a separate library because we always link in the compatibility library. https://github.com/apple/swift/blob/master/lib/IRGen/GenDecl.cpp#L453
|
@swift-ci please test |
Ah, I didn't realize Joe changed that. Okay. |
@@ -44,13 +44,19 @@ void swift_beginAccess(void *pointer, ValueBuffer *buffer, | |||
/// replacement function if it should be called. | |||
/// Returns null if the original function (which is passed in \p CurrFn) should | |||
/// be called. | |||
#ifdef __APPLE__ | |||
__attribute__((weak)) | |||
#endif |
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.
This will export these symbols as a weak definition, which is probably not what you want (and very bad for load time performance). Did you mean __attribute__((weak_import))
?
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.
Yes. Will fix.
ARGS(FunctionPtrTy->getPointerTo()), | ||
ATTRS(NoUnwind)) | ||
|
||
FUNCTION(GetReplacement50, swift_getFunctionReplacement50, C_CC, |
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.
I had been thinking about this issue of backporting new entry points with the compatibility library, and I wonder whether there might be a more systematic way of going about it. I was thinking that maybe we could turn the return type of the availability function here from a bool
to a tristate, ConditionallyAvailable
| AvailableByCompatibilityLibrary
| AlwaysAvailable
. We could factor the logic for choosing the compatibility library or OS version of the entry point into getRuntimeFn
then (by establishing a mangling pattern for the backport stub like "<swift_runtimeFunctionName>" + compatibility_version
like you have here), instead of repeating this conditional logic for every client of the entry point.
Build failed |
Build failed |
That’s a bug, though, not a feature. The compatibility library should only link into the main executable, and dylibs should get back deployment support from the executable. An approach that should work without a separate library, and without relying on the compatibility library getting linked into dylibs, might be to add the back-deployment functions to the static archive as exported entry points, then emit a common resolution thunk that tries to find the entry point, first by looking in libswiftCore.dylib, then by looking in the main executable. |
@swift-ci Please test |
Build failed |
Build failed |
@swift-ci Please test |
Build failed |
Build failed |
@swift-ci Please test |
Build failed |
Build failed |
@jckarter I think I have addressed your concerns. Are you okay with the latest version? |
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.
There's still the issue of dynamic libraries. Compatibility50
will not be linked into dylibs, so they need to get the back-deployed entry points from the one linked into the main executable, if not from the OS runtime.
@@ -638,7 +638,7 @@ FUNCTION(GetGenericMetadata, swift_getGenericMetadata, | |||
// const OpaqueTypeDescriptor *descriptor, | |||
// uintptr_t index); | |||
FUNCTION(GetOpaqueTypeMetadata, swift_getOpaqueTypeMetadata, | |||
SwiftCC, OpaqueTypeAvailability, | |||
SwiftCC, ConditionallyAvailable, |
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 all still need to call a function to return the availability appropriate for the current deployment target. There will be runtime entry points in the future that are available on a different set of OSes from Swift 5.1, so we shouldn't hardcode that.
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.
This is what conditionally available means?
The code in getRuntimeFn() queries whether the feature is available based on whether something is AlwaysAvailable| ConditionallyAvailable | AvailableByCompatibilityLibrary:
auto isFeatureAvailable = [&]() -> bool {
auto deploymentAvailability =
AvailabilityContext::forDeploymentTarget(*context);
auto featureAvailability = context->getSwift51Availability();
return deploymentAvailability.isContainedIn(featureAvailability);
};
switch (availability) {
case RuntimeAvailability:: AlwaysAvailable:
// Nothing to do.
break;
case RuntimeAvailability::ConditionallyAvailable: {
isWeakLinked = !isFeatureAvailable();
break;
}
case RuntimeAvailability::AvailableByCompatibilityLibrary: {
if (!isFeatureAvailable())
functionName.append("50");
break;
}
}
In the future we can extend this by adding another entry to runtime.def that specifies at which swift version things became available ...
FUNCTION(GetOpaqueTypeMetadata, swift_getOpaqueTypeMetadata,
SwiftCC, ConditionallyAvailable, Swift51
And then generate the availability based on that.
context->get##AVAILVERSION##Availability
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.
An entry point is only ConditionallyAvailable
if we're deploying back to a runtime version that may not have the entry point. If we're deploying to an OS with Swift 5.1, everything is AlwaysAvailable
. Having a single version doesn't seem sufficient to me, because in the future, we may end up in a situation where a runtime entry point can only be back-deployed in the compatibility library to certain runtime versions; for instance, a Swift 5.2 feature may be completely unavailable on Swift 5.0, although we have a compatibility fallback that works for the 5.1 runtime. The most future-proof thing to do is to have the FUNCTION xmacro refer to a function that returns the enum value appropriate to the deployment target, the way it was before.
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.
I will address this in a follow-up patch.
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.
Attempt of follow-up here: #25573
We use one bit of the third reserved swift private tls key. Also move the functionality into a separate static archive that is always linked dependent on deployment target.
@swift-ci Please test |
Build failed |
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.
We can address some of these issues in follow up commits.
Build failed |
include/swift/Option/Options.td
Outdated
: Flag<[ "-" ], | ||
"disable-autolinking-runtime-compatibility-dynamic-replacements">, | ||
Flags<[ FrontendOption ]>, | ||
HelpText<"Do not use autolinking for runtime compatibility libraries">; |
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.
Please fix the formatting here to match the other lines, and please change the help text.
…does this really need a separate flag, though?
lib/Driver/ToolChains.cpp
Outdated
if (context.Args.hasArg(options:: | ||
OPT_disable_autolinking_runtime_compatibility_dynamic_replacements)) { | ||
Arguments.push_back( | ||
"-disable-autolinking-runtime-compatibility-dynamic-replacements"); |
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.
This is just context.Args.AddLastArg(Arguments, OPT_disable_autolinking_runtime_compatibility_dynamic_replacements)
(and Joe should have used that too above).
|
||
# define SWIFT_RUNTIME_TLS_KEY __PTK_FRAMEWORK_SWIFT_KEY0 | ||
# define SWIFT_STDLIB_TLS_KEY __PTK_FRAMEWORK_SWIFT_KEY1 | ||
# define SWIFT_RUNTIME2_TLS_KEY __PTK_FRAMEWORK_SWIFT_KEY2 |
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.
Please give this a more descriptive name, like SWIFT_COMPATIBILITY_50_TLS_KEY
. That'll indicate when it's okay to reuse it.
@swift-ci Please test |
Build failed |
Build failed |
@swift-ci Please test source compatibility |
@swift-ci Please test |
@swit-ci Please test source compatibility |
Build failed |
Build failed |
@swift-ci Please test source compatibility |
SwiftPM will pass a -runtime-compatibility-version none in this case.
@swift-ci Please test |
@swift-ci Please test source compatibility |
Build failed |
Build failed |
@swift-ci Please test linux |
@@ -427,6 +427,22 @@ toolchains::Darwin::constructInvocation(const LinkJobAction &job, | |||
} | |||
} | |||
|
|||
if (job.getKind() == LinkKind::Executable) { |
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.
Er, you don't need this part anymore, right? And you never wanted it to just be Executables-linked-with-swiftc anyway.
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.
We still ultimately want this to only be linked into executables. We were going to handle that as a followup. For these specific backfill entry points, they're small enough that burning them into dylibs and having potentially-mismatching versions in different images is probably OK, but that's not generally a situation we want to be in.
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.
I don't understand that part. We can't rely on executables having any Swift in them, and it's unlikely that Xcode will switch to linking with swiftc anyway. The autolinking part for dynamic replacement isn't going away.
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.
(I do want a resolution for this because it's interfering with me rebasing #24787.)
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.
If there's any Swift in the process, then the executable is the only useful place to put backward-compatibility fills, so much like arclite, we might want eventually for Xcode to link this in unconditionally because a non-Swift executable could be using dylibs with Swift in them.
The recent change of how we do dynamic replacements added 2 new runtime
functions. This patch adds those functions to the Compatibility50 static
archive.
This will allow backward deployment to a swift 5.0 runtime.
Patch by Erik Eckstein with a modification to call the standard
libraries implementation (marked as weak) when it is available.
This ensures we can change the implementation in the future and are not
ABI locked.
rdar://problem/51601233