|
31 | 31 |
|
32 | 32 | using namespace swift;
|
33 | 33 |
|
34 |
| -static CFHashCode(*_CFStringHashCString)(const uint8_t *bytes, CFIndex len); |
35 |
| -static CFHashCode(*_CFStringHashNSString)(id str); |
36 |
| -static CFTypeID(*_CFGetTypeID)(CFTypeRef obj); |
37 |
| -static CFTypeID _CFStringTypeID = 0; |
38 |
| -static swift_once_t initializeBridgingFuncsOnce; |
| 34 | +typedef struct _CFBridgingState { |
| 35 | + long version; |
| 36 | + CFHashCode(*_CFStringHashCString)(const uint8_t *bytes, CFIndex len); |
| 37 | + CFHashCode(*_CFStringHashNSString)(id str); |
| 38 | + CFTypeID(*_CFGetTypeID)(CFTypeRef obj); |
| 39 | + CFTypeID _CFStringTypeID = 0; |
| 40 | + Class NSErrorClass; |
| 41 | + Class NSStringClass; |
| 42 | + Class NSArrayClass; |
| 43 | + Class NSMutableArrayClass; |
| 44 | + Class NSSetClass; |
| 45 | + Class NSDictionaryClass; |
| 46 | + Class NSEnumeratorClass; |
| 47 | + //version 0 ends here |
| 48 | +} CFBridgingState; |
| 49 | + |
| 50 | +static CFBridgingState *bridgingState; |
| 51 | +static swift_once_t initializeBridgingStateOnce; |
39 | 52 |
|
40 | 53 | extern "C" bool _dyld_is_objc_constant(DyldObjCConstantKind kind,
|
41 | 54 | const void *addr) SWIFT_RUNTIME_WEAK_IMPORT;
|
42 | 55 |
|
| 56 | +static void _initializeBridgingFunctionsFromCFImpl(void *ctxt) { |
| 57 | + bridgingState = (CFBridgingState *)ctxt; |
| 58 | +} |
| 59 | + |
| 60 | +@class __SwiftNativeNSStringBase, __SwiftNativeNSError, __SwiftNativeNSArrayBase, __SwiftNativeNSMutableArrayBase, __SwiftNativeNSDictionaryBase, __SwiftNativeNSSetBase, __SwiftNativeNSEnumeratorBase; |
| 61 | + |
| 62 | +static void _reparentClasses() { |
| 63 | +#pragma clang diagnostic push |
| 64 | +#pragma clang diagnostic ignored "-Wdeprecated-declarations" |
| 65 | + if (bridgingState->NSStringClass) { |
| 66 | + [bridgingState->NSStringClass class]; //make sure the class is realized |
| 67 | + class_setSuperclass([__SwiftNativeNSStringBase class], bridgingState->NSStringClass); |
| 68 | + } |
| 69 | + if (bridgingState->NSErrorClass) { |
| 70 | + [bridgingState->NSErrorClass class]; //make sure the class is realized |
| 71 | + class_setSuperclass([__SwiftNativeNSError class], bridgingState->NSErrorClass); |
| 72 | + } |
| 73 | + if (bridgingState->NSArrayClass) { |
| 74 | + [bridgingState->NSArrayClass class]; //make sure the class is realized |
| 75 | + class_setSuperclass([__SwiftNativeNSArrayBase class], bridgingState->NSArrayClass); |
| 76 | + } |
| 77 | + if (bridgingState->NSMutableArrayClass) { |
| 78 | + [bridgingState->NSMutableArrayClass class]; //make sure the class is realized |
| 79 | + class_setSuperclass([__SwiftNativeNSMutableArrayBase class], bridgingState->NSMutableArrayClass); |
| 80 | + } |
| 81 | + if (bridgingState->NSDictionaryClass) { |
| 82 | + [bridgingState->NSDictionaryClass class]; //make sure the class is realized |
| 83 | + class_setSuperclass([__SwiftNativeNSDictionaryBase class], bridgingState->NSDictionaryClass); |
| 84 | + } |
| 85 | + if (bridgingState->NSSetClass) { |
| 86 | + [bridgingState->NSSetClass class]; //make sure the class is realized |
| 87 | + class_setSuperclass([__SwiftNativeNSSetBase class], bridgingState->NSSetClass); |
| 88 | + } |
| 89 | + if (bridgingState->NSEnumeratorClass) { |
| 90 | + [bridgingState->NSEnumeratorClass class]; //make sure the class is realized |
| 91 | + class_setSuperclass([__SwiftNativeNSEnumeratorBase class], bridgingState->NSEnumeratorClass); |
| 92 | + } |
| 93 | +#pragma clang diagnostic pop |
| 94 | +} |
| 95 | + |
43 | 96 | static void _initializeBridgingFunctionsImpl(void *ctxt) {
|
44 |
| - auto getStringTypeID = |
45 |
| - (CFTypeID(*)(void)) |
46 |
| - dlsym(RTLD_DEFAULT, "CFStringGetTypeID"); |
47 |
| - assert(getStringTypeID); |
48 |
| - _CFStringTypeID = getStringTypeID(); |
49 |
| - |
50 |
| - _CFGetTypeID = (CFTypeID(*)(CFTypeRef obj))dlsym(RTLD_DEFAULT, "CFGetTypeID"); |
51 |
| - _CFStringHashNSString = (CFHashCode(*)(id))dlsym(RTLD_DEFAULT, |
52 |
| - "CFStringHashNSString"); |
53 |
| - _CFStringHashCString = (CFHashCode(*)(const uint8_t *, CFIndex))dlsym( |
54 |
| - RTLD_DEFAULT, |
55 |
| - "CFStringHashCString"); |
| 97 | + assert(!bridgingState); |
| 98 | + auto getStringTypeID = (CFTypeID(*)(void))dlsym(RTLD_DEFAULT, "CFStringGetTypeID"); |
| 99 | + if (!getStringTypeID) { |
| 100 | + return; //CF not loaded |
| 101 | + } |
| 102 | + bridgingState = (CFBridgingState *)calloc(1, sizeof(CFBridgingState)); |
| 103 | + bridgingState->version = 0; |
| 104 | + bridgingState->_CFStringTypeID = getStringTypeID(); |
| 105 | + bridgingState->_CFGetTypeID = (CFTypeID(*)(CFTypeRef obj))dlsym(RTLD_DEFAULT, "CFGetTypeID"); |
| 106 | + bridgingState->_CFStringHashNSString = (CFHashCode(*)(id))dlsym(RTLD_DEFAULT, "CFStringHashNSString"); |
| 107 | + bridgingState->_CFStringHashCString = (CFHashCode(*)(const uint8_t *, CFIndex))dlsym(RTLD_DEFAULT, "CFStringHashCString"); |
| 108 | + bridgingState->NSErrorClass = objc_lookUpClass("NSError"); |
| 109 | + bridgingState->NSStringClass = objc_lookUpClass("NSString"); |
| 110 | + bridgingState->NSArrayClass = objc_lookUpClass("NSArray"); |
| 111 | + bridgingState->NSMutableArrayClass = objc_lookUpClass("NSMutableArray"); |
| 112 | + bridgingState->NSSetClass = objc_lookUpClass("NSSet"); |
| 113 | + bridgingState->NSDictionaryClass = objc_lookUpClass("NSDictionary"); |
| 114 | + bridgingState->NSEnumeratorClass = objc_lookUpClass("NSEnumerator"); |
| 115 | + _reparentClasses(); |
56 | 116 | }
|
57 | 117 |
|
58 |
| -static inline void initializeBridgingFunctions() { |
59 |
| - swift_once(&initializeBridgingFuncsOnce, |
| 118 | +static inline bool initializeBridgingFunctions() { |
| 119 | + swift_once(&initializeBridgingStateOnce, |
60 | 120 | _initializeBridgingFunctionsImpl,
|
61 | 121 | nullptr);
|
| 122 | + return bridgingState && bridgingState->NSStringClass != nullptr; |
| 123 | +} |
| 124 | + |
| 125 | +SWIFT_RUNTIME_EXPORT void swift_initializeCoreFoundationState(CFBridgingState const * const state) { |
| 126 | + swift_once(&initializeBridgingStateOnce, |
| 127 | + _initializeBridgingFunctionsFromCFImpl, |
| 128 | + (void *)state); |
| 129 | + //It's fine if this runs more than once, it's a noop if it's been done before |
| 130 | + //and we want to make sure it happens if CF loads late after it failed initially |
| 131 | + _reparentClasses(); |
| 132 | +} |
| 133 | + |
| 134 | +namespace swift { |
| 135 | +Class getNSErrorClass(); |
| 136 | +} |
| 137 | + |
| 138 | +Class swift::getNSErrorClass() { |
| 139 | + if (initializeBridgingFunctions()) { |
| 140 | + return bridgingState->NSErrorClass; |
| 141 | + } |
| 142 | + return nullptr; |
| 143 | +} |
| 144 | + |
| 145 | +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_SPI |
| 146 | +bool |
| 147 | +swift_stdlib_connectNSBaseClasses() { |
| 148 | + return initializeBridgingFunctions(); |
62 | 149 | }
|
63 | 150 |
|
64 | 151 | __swift_uint8_t
|
65 | 152 | _swift_stdlib_isNSString(id obj) {
|
66 |
| - initializeBridgingFunctions(); |
67 |
| - return _CFGetTypeID((CFTypeRef)obj) == _CFStringTypeID ? 1 : 0; |
| 153 | + assert(initializeBridgingFunctions()); |
| 154 | + return bridgingState->_CFGetTypeID((CFTypeRef)obj) == bridgingState->_CFStringTypeID ? 1 : 0; |
68 | 155 | }
|
69 | 156 |
|
70 | 157 | _swift_shims_CFHashCode
|
71 | 158 | _swift_stdlib_CFStringHashNSString(id _Nonnull obj) {
|
72 |
| - initializeBridgingFunctions(); |
73 |
| - return _CFStringHashNSString(obj); |
| 159 | + assert(initializeBridgingFunctions()); |
| 160 | + return bridgingState->_CFStringHashNSString(obj); |
74 | 161 | }
|
75 | 162 |
|
76 | 163 | _swift_shims_CFHashCode
|
77 | 164 | _swift_stdlib_CFStringHashCString(const _swift_shims_UInt8 * _Nonnull bytes,
|
78 | 165 | _swift_shims_CFIndex length) {
|
79 |
| - initializeBridgingFunctions(); |
80 |
| - return _CFStringHashCString(bytes, length); |
| 166 | + assert(initializeBridgingFunctions()); |
| 167 | + return bridgingState->_CFStringHashCString(bytes, length); |
81 | 168 | }
|
82 | 169 |
|
83 | 170 | const __swift_uint8_t *
|
|
0 commit comments