PR that was making isolated deinit non-experiment, and which I hoped will be the last one, got reverted, because tests were failing on iOS device.
Which I strongly suspect is just a matter of correct versioning.
Tests pass on simulator, because SIMCTL_CHILD_DYLD_LIBRARY_PATH
is set when running executable tests, and it points to updated stdlib which contains the new runtime function.
/usr/bin/env SIMCTL_CHILD_DYLD_LIBRARY_PATH=$SWIFT_PROJECT_DIR/build/Ninja-RelWithDebInfoAssert/swift-macosx-arm64/lib/swift/iphonesimulator xcrun --toolchain default --sdk /Applications/Xcode-16.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator18.1.sdk simctl spawn --standalone 'iPhone 15' $SWIFT_PROJECT_DIR/build/Ninja-RelWithDebInfoAssert/swift-macosx-arm64/test-iphonesimulator-arm64/Concurrency/Runtime/Output/actor_recursive_deinit.swift.tmp/a.out
But when running on a physical device, IIUC, program is executed against stdlib shipped on the device, which does not have the required runtime function, causing app to crash either during dynamic linking or when trying to call unresolved function pointer.
To fix this in the short term, we need make sure that isolated deinit as a feature is limited only to specific runtime versions and does not produce binaries that use the feature but can target earlier runtime versions.
This needs to be done in at least 3 places:
- In Swift declaration of the
_deinitOnExecutor()
- should it be@available(SwiftStdlib 6.1, *)
? Does it actually do anything, if the call to this function is generated by the compiler in the SILGen phase? Are there versioning checks later in the pipeline that care about this? - In frontend - instead of feature check, it should be a version check. But IIUC, user code cannot check against
SwiftStdlib
, it should be a check against iOS/macOS/tvOS/xrOS version, right? Where is mapping of stdlib version to OS version maintained? - In unit tests - ideally we should skip relevant tests on iOS devices with old runtime, but run them on devices with new one. Is there an existing LIT feature that can be used for this?
In the long-term, we can consider back-deployment of feature.
I was under impression that COMPATIBILITY_OVERRIDE
and friends are responsible exactly for back-deployment of C++ code of the stdlib. Comment in CompatibilityOverride.h
says:
// The compatibility override system supports the back-deployment of
// bug fixes and ABI additions to existing Swift systems.
Is it supposed to work for this case of "ABI addition" or not?
I've tried to look into some examples of back-deployment of the C++ code, and I've found swift_getFunctionTypeMetadataGlobalActorBackDeploy
, which seems to be a relevant example, but I don't fully understand where the actually back-deployment implementation is coming from. Is swift_getFunctionTypeMetadataGlobalActorStandalone
a back-deployed version, or a symbol used for embedded builds? Where is it implemented?
Do I understand correctly that back-deployed implementation cannot depend on private API (DefaultActorImpl
, ExecutorTrackingInfo
), and should only use public ABI-stable API?
If so, back-deployed implementation still should be possible with certain limitations:
- No resetting TLs for the fast path
- No optimization for isolated deinit of default actors
I think it still would be valuable for many users. Is it acceptable for back-deployed version to diverge from the spec approved by the proposal review?