Skip to content

Commit 9b6e27e

Browse files
authored
Merge pull request #66813 from Catfish-Man/bridge-flip-followup
Use swift::once instead of swift_once to clean up the code a little, and make sure we unconditionally set the state from CF to make sure it's set even if we failed a lazy load earlier
2 parents 80bb497 + 300f3fd commit 9b6e27e

File tree

1 file changed

+63
-60
lines changed

1 file changed

+63
-60
lines changed

stdlib/public/stubs/FoundationHelpers.mm

Lines changed: 63 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#import <objc/runtime.h>
2525
#include "swift/Runtime/Once.h"
2626
#include <dlfcn.h>
27+
#include "swift/Runtime/Atomic.h"
2728

2829
typedef enum {
2930
dyld_objc_string_kind
@@ -47,87 +48,88 @@
4748
//version 0 ends here
4849
} CFBridgingState;
4950

50-
static CFBridgingState *bridgingState;
51+
static std::atomic<CFBridgingState const *> bridgingState;
5152
static swift_once_t initializeBridgingStateOnce;
5253

54+
static CFBridgingState const *getBridgingState() {
55+
return bridgingState.load(SWIFT_MEMORY_ORDER_CONSUME);
56+
}
57+
5358
extern "C" bool _dyld_is_objc_constant(DyldObjCConstantKind kind,
5459
const void *addr) SWIFT_RUNTIME_WEAK_IMPORT;
5560

56-
static void _initializeBridgingFunctionsFromCFImpl(void *ctxt) {
57-
bridgingState = (CFBridgingState *)ctxt;
58-
}
59-
6061
@class __SwiftNativeNSStringBase, __SwiftNativeNSError, __SwiftNativeNSArrayBase, __SwiftNativeNSMutableArrayBase, __SwiftNativeNSDictionaryBase, __SwiftNativeNSSetBase, __SwiftNativeNSEnumeratorBase;
6162

6263
static void _reparentClasses() {
64+
auto state = getBridgingState();
6365
#pragma clang diagnostic push
6466
#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);
67+
if (state->NSStringClass) {
68+
[state->NSStringClass class]; //make sure the class is realized
69+
class_setSuperclass([__SwiftNativeNSStringBase class], state->NSStringClass);
6870
}
69-
if (bridgingState->NSErrorClass) {
70-
[bridgingState->NSErrorClass class]; //make sure the class is realized
71-
class_setSuperclass([__SwiftNativeNSError class], bridgingState->NSErrorClass);
71+
if (state->NSErrorClass) {
72+
[state->NSErrorClass class]; //make sure the class is realized
73+
class_setSuperclass([__SwiftNativeNSError class], state->NSErrorClass);
7274
}
73-
if (bridgingState->NSArrayClass) {
74-
[bridgingState->NSArrayClass class]; //make sure the class is realized
75-
class_setSuperclass([__SwiftNativeNSArrayBase class], bridgingState->NSArrayClass);
75+
if (state->NSArrayClass) {
76+
[state->NSArrayClass class]; //make sure the class is realized
77+
class_setSuperclass([__SwiftNativeNSArrayBase class], state->NSArrayClass);
7678
}
77-
if (bridgingState->NSMutableArrayClass) {
78-
[bridgingState->NSMutableArrayClass class]; //make sure the class is realized
79-
class_setSuperclass([__SwiftNativeNSMutableArrayBase class], bridgingState->NSMutableArrayClass);
79+
if (state->NSMutableArrayClass) {
80+
[state->NSMutableArrayClass class]; //make sure the class is realized
81+
class_setSuperclass([__SwiftNativeNSMutableArrayBase class], state->NSMutableArrayClass);
8082
}
81-
if (bridgingState->NSDictionaryClass) {
82-
[bridgingState->NSDictionaryClass class]; //make sure the class is realized
83-
class_setSuperclass([__SwiftNativeNSDictionaryBase class], bridgingState->NSDictionaryClass);
83+
if (state->NSDictionaryClass) {
84+
[state->NSDictionaryClass class]; //make sure the class is realized
85+
class_setSuperclass([__SwiftNativeNSDictionaryBase class], state->NSDictionaryClass);
8486
}
85-
if (bridgingState->NSSetClass) {
86-
[bridgingState->NSSetClass class]; //make sure the class is realized
87-
class_setSuperclass([__SwiftNativeNSSetBase class], bridgingState->NSSetClass);
87+
if (state->NSSetClass) {
88+
[state->NSSetClass class]; //make sure the class is realized
89+
class_setSuperclass([__SwiftNativeNSSetBase class], state->NSSetClass);
8890
}
89-
if (bridgingState->NSEnumeratorClass) {
90-
[bridgingState->NSEnumeratorClass class]; //make sure the class is realized
91-
class_setSuperclass([__SwiftNativeNSEnumeratorBase class], bridgingState->NSEnumeratorClass);
91+
if (state->NSEnumeratorClass) {
92+
[state->NSEnumeratorClass class]; //make sure the class is realized
93+
class_setSuperclass([__SwiftNativeNSEnumeratorBase class], state->NSEnumeratorClass);
9294
}
9395
#pragma clang diagnostic pop
9496
}
9597

96-
static void _initializeBridgingFunctionsImpl(void *ctxt) {
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();
116-
}
117-
11898
static inline bool initializeBridgingFunctions() {
119-
swift_once(&initializeBridgingStateOnce,
120-
_initializeBridgingFunctionsImpl,
121-
nullptr);
122-
return bridgingState && bridgingState->NSStringClass != nullptr;
99+
swift::once(initializeBridgingStateOnce, [](){
100+
assert(!getBridgingState());
101+
auto getStringTypeID = (CFTypeID(*)(void))dlsym(RTLD_DEFAULT, "CFStringGetTypeID");
102+
if (!getStringTypeID) {
103+
return; //CF not loaded
104+
}
105+
auto state = (CFBridgingState *)calloc(1, sizeof(CFBridgingState));
106+
state->version = 0;
107+
state->_CFStringTypeID = getStringTypeID();
108+
state->_CFGetTypeID = (CFTypeID(*)(CFTypeRef obj))dlsym(RTLD_DEFAULT, "CFGetTypeID");
109+
state->_CFStringHashNSString = (CFHashCode(*)(id))dlsym(RTLD_DEFAULT, "CFStringHashNSString");
110+
state->_CFStringHashCString = (CFHashCode(*)(const uint8_t *, CFIndex))dlsym(RTLD_DEFAULT, "CFStringHashCString");
111+
state->NSErrorClass = objc_lookUpClass("NSError");
112+
state->NSStringClass = objc_lookUpClass("NSString");
113+
state->NSArrayClass = objc_lookUpClass("NSArray");
114+
state->NSMutableArrayClass = objc_lookUpClass("NSMutableArray");
115+
state->NSSetClass = objc_lookUpClass("NSSet");
116+
state->NSDictionaryClass = objc_lookUpClass("NSDictionary");
117+
state->NSEnumeratorClass = objc_lookUpClass("NSEnumerator");
118+
bridgingState.store(state, std::memory_order_relaxed);
119+
_reparentClasses();
120+
});
121+
auto state = getBridgingState();
122+
return state && state->NSStringClass != nullptr;
123123
}
124124

125125
SWIFT_RUNTIME_EXPORT void swift_initializeCoreFoundationState(CFBridgingState const * const state) {
126-
swift_once(&initializeBridgingStateOnce,
127-
_initializeBridgingFunctionsFromCFImpl,
128-
(void *)state);
126+
//Consume the once token to make sure that the lazy version of this in initializeBridgingFunctions only runs if we didn't hit this
127+
swift::once(initializeBridgingStateOnce, [state](){
128+
bridgingState.store(state, std::memory_order_relaxed);
129+
});
129130
//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+
//and we want to make sure it still happens if CF loads late after it failed initially
132+
bridgingState.store(state, std::memory_order_release);
131133
_reparentClasses();
132134
}
133135

@@ -137,7 +139,7 @@ SWIFT_RUNTIME_EXPORT void swift_initializeCoreFoundationState(CFBridgingState co
137139

138140
Class swift::getNSErrorClass() {
139141
if (initializeBridgingFunctions()) {
140-
return bridgingState->NSErrorClass;
142+
return getBridgingState()->NSErrorClass;
141143
}
142144
return nullptr;
143145
}
@@ -151,20 +153,21 @@ SWIFT_RUNTIME_EXPORT void swift_initializeCoreFoundationState(CFBridgingState co
151153
__swift_uint8_t
152154
_swift_stdlib_isNSString(id obj) {
153155
assert(initializeBridgingFunctions());
154-
return bridgingState->_CFGetTypeID((CFTypeRef)obj) == bridgingState->_CFStringTypeID ? 1 : 0;
156+
auto state = getBridgingState();
157+
return state->_CFGetTypeID((CFTypeRef)obj) == state->_CFStringTypeID ? 1 : 0;
155158
}
156159

157160
_swift_shims_CFHashCode
158161
_swift_stdlib_CFStringHashNSString(id _Nonnull obj) {
159162
assert(initializeBridgingFunctions());
160-
return bridgingState->_CFStringHashNSString(obj);
163+
return getBridgingState()->_CFStringHashNSString(obj);
161164
}
162165

163166
_swift_shims_CFHashCode
164167
_swift_stdlib_CFStringHashCString(const _swift_shims_UInt8 * _Nonnull bytes,
165168
_swift_shims_CFIndex length) {
166169
assert(initializeBridgingFunctions());
167-
return bridgingState->_CFStringHashCString(bytes, length);
170+
return getBridgingState()->_CFStringHashCString(bytes, length);
168171
}
169172

170173
const __swift_uint8_t *

0 commit comments

Comments
 (0)