Open eeckstein opened 2 years ago
@compnerd shared the crash info with me. From the point of the crash, I wasn't that I wasn't able to pinpoint the issue, but I'll explain what I can here. Descending along the call chain to the crash:
Foundation.Bundle.localizedInfoDictionary.getter instantiates a CFDictionary, passing it to __SwiftValue.fetch
@Bundle.swift:374
let cfDict: CFDictionary? = CFBundleGetInfoDictionary(_bundle)
__SwiftValue.fetch(cfDict)
__SwiftValue.fetch attempts to cast to _StructBridgeable.
@Bridging.swift:160
static func fetch(nonOptional object: AnyObject) -> Any {
//...
} else if let val = object as? _StructBridgeable {
return val._bridgeToAny() <============
[aside: Casting to _StructBridgeable apparently succeeds with or without optimization, but I don't see any explicit conformance from CFDictionary to _StructBridgeable. Presumably CFDictionary is merely a type alias for NSDictionary in corelibs, which does conform]
_StructTypeBridgeable.bridgeToAny() eventually calls _conditionallyBridgeFromObjectiveC. Here the conversion iterates over key/value pairs, at which point, __SwiftValue.fetch is called recursively, this time on a key object, presumably an NSString.
Dictionary.swift @ 68
let key = __SwiftValue.fetch(nonOptional: unsafeBitCast(keys.advanced(by: idx).pointee!, to: AnyObject.self))
[unsafeBitCast should never be done on a reference! But that's a digression]
__SwiftValue.fetch calls swift_dynamicCast for the attempted cast from NSString to _StructBridgeable.
@Bridging.swift:160
static func fetch(nonOptional object: AnyObject) -> Any {
//...
} else if let val = object as? _StructBridgeable { <============
Ultimiately this crashes deep within the runtime
swiftCore!std::_Atomic_storage<swift::PrivateMetadataTrackingInfo,8>::load (Inline Function @ 00007ffc`5b5e24bf) [C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.32.31302\include\atomic @ 1045]
swiftCore!swift::MetadataCacheEntryBase<(anonymous namespace)::SingletonMetadataCacheEntry,int>::awaitSatisfyingState+0x2f [S:\SourceCache\swift\stdlib\public\runtime\MetadataCache.h @ 1223]
swiftCore!swift::MetadataCacheEntryBase<(anonymous namespace)::SingletonMetadataCacheEntry,int>::await+0xb (Inline Function @ 00007ffc`5b5db86f) [S:\SourceCache\swift\stdlib\public\runtime\MetadataCache.h @ 953]
swiftCore!swift::LockingConcurrentMap<(anonymous namespace)::SingletonMetadataCacheEntry,(anonymous namespace)::SingletonMetadataCacheStorage>::await+0x16 (Inline Function @ 00007ffc`5b5db86f) [S:\SourceCache\swift\stdlib\public\runtime\MetadataCache.h @ 287]
swiftCore!swift_checkMetadataState::CheckStateCallbacks::forSingletonMetadata+0x6c (Inline Function @ 00007ffc`5b5db86f) [S:\SourceCache\swift\stdlib\public\runtime\Metadata.cpp @ 5789]
swiftCore!performOnMetadataCache<swift::MetadataResponse,CheckStateCallbacks>+0x29f [S:\SourceCache\swift\stdlib\public\runtime\Metadata.cpp @ 5750]
swiftCore!swift_checkMetadataState+0x29 [S:\SourceCache\swift\stdlib\public\runtime\Metadata.cpp @ 5803]
swiftCore!tryGetCompleteMetadataNonblocking+0xd (Inline Function @ 00007ffc`5b5ff7f8) [S:\SourceCache\swift\stdlib\public\runtime\ProtocolConformance.cpp @ 187]
swiftCore!getSuperclassForMaybeIncompleteMetadata+0x98 (Inline Function @ 00007ffc`5b5ff7f8) [S:\SourceCache\swift\stdlib\public\runtime\ProtocolConformance.cpp @ 230]
swiftCore!MaybeIncompleteSuperclassIterator::operator+++0x98 (Inline Function @ 00007ffc`5b5ff7f8) [S:\SourceCache\swift\stdlib\public\runtime\ProtocolConformance.cpp @ 271]
swiftCore!searchInConformanceCache+0x197 (Inline Function @ 00007ffc`5b5ff7f8) [S:\SourceCache\swift\stdlib\public\runtime\ProtocolConformance.cpp @ 637]
swiftCore!swift_conformsToProtocolMaybeInstantiateSuperclasses+0x278 [S:\SourceCache\swift\stdlib\public\runtime\ProtocolConformance.cpp @ 990]
swiftCore!swift_conformsToProtocolImpl+0xe (Inline Function @ 00007ffc`5b5ff53f) [S:\SourceCache\swift\stdlib\public\runtime\ProtocolConformance.cpp @ 1112]
swiftCore!swift_conformsToProtocol+0x2f [S:\SourceCache\swift\stdlib\public\CompatibilityOverride\CompatibilityOverrideRuntime.def @ 140]
swiftCore!swift::_conformsToProtocol+0x17 [S:\SourceCache\swift\stdlib\public\runtime\Casting.cpp @ 519]
swiftCore!_conformsToProtocols+0x94 (Inline Function @ 00007ffc`5b5c6762) [S:\SourceCache\swift\stdlib\public\runtime\DynamicCast.cpp @ 1358]
swiftCore!tryCastToConstrainedOpaqueExistential+0xb2 [S:\SourceCache\swift\stdlib\public\runtime\DynamicCast.cpp @ 1415]
swiftCore!tryCast+0x270 [S:\SourceCache\swift\stdlib\public\runtime\DynamicCast.cpp @ 2073]
swiftCore!tryCastUnwrappingExistentialSource+0x123 (Inline Function @ 00007ffc`5b5c5827) [S:\SourceCache\swift\stdlib\public\runtime\DynamicCast.cpp @ 1695]
swiftCore!tryCast+0x487 [S:\SourceCache\swift\stdlib\public\runtime\DynamicCast.cpp @ 2153]
swiftCore!swift_dynamicCastImpl+0x42 (Inline Function @ 00007ffc`5b5c5329) [S:\SourceCache\swift\stdlib\public\runtime\DynamicCast.cpp @ 2353]
swiftCore!swift_dynamicCast+0x69 [S:\SourceCache\swift\stdlib\public\CompatibilityOverride\CompatibilityOverrideRuntime.def @ 80]
All I can guess from this is that the metadata cache is not properly initialized.
To relating the issue back to the original optimization... I'd like to see the output produced by tracing the new code in IRGen and rebuilding Foundation:
// TODO: we could use the ClassHierarchyAnalysis do also handle "effectively"
// final classes, e.g. not-subclassed internal classes in WMO.
// This would need some re-architecting of ClassHierarchyAnalysis to make it
// available in IRGen.
ClassDecl *toClass = classTy->getDecl();
if (!toClass->isFinal())
return nullptr;
<========= let's print both the class name and function being optimized. It should be easy to narrow down from there.
@compnerd says the optimization is only performed for the `Operation` class. But this shouldn't happen because that class is non-final:
open class Operation : NSObject {
If `isFinal` returns an incorrect value in certain modes on certain platforms, that's a serious problem.
@swift-cicreate
From an instrumented compiler, these are all the instances being triggered in a build of Foundation:
(class name :: function name)
_BarrierOperation :: $s10Foundation9OperationC12dependenciesSayACGvg
_BarrierOperation :: $s10Foundation14OperationQueueC18_operationFinishedyyAA0B0C_AF18__NSOperationStateOtF
_BarrierOperation :: $s10Foundation14OperationQueueC9_scheduleyyF
_BarrierOperation :: $s10Foundation14OperationQueueC8_executeyyAA0B0CF
_BarrierOperation :: $s10Foundation14OperationQueueC15_operationCountSivg
_BarrierOperation :: $s10Foundation14OperationQueueC11_operations17includingBarriersSayAA0B0CGSb_tF
IRGen: enable the dynamic cast optimization on Windows by compnerd · Pull Request #42286 · apple/swift (github.com) does seem to repair the test cases. Hopefully we can keep the optimization enabled on all platforms.
Additional Detail from JIRA
| | | |------------------|-----------------| |Votes | 0 | |Component/s | Compiler | |Labels | Bug | |Assignee | None | |Priority | Medium | md5: 348f16b24ead7791d1d5c72261b86e2fIssue Description:
Fast class casting is introduced here: https://github.com/apple/swift/pull/41784
and fails here: https://ci-external.swift.org/job/oss-swift-windows-toolchain-x86_64-vs2019/447/console