@@ -206,13 +206,86 @@ struct _ObjectiveCBridgeableWitnessTable : WitnessTable {
206
206
extern " C" const ProtocolDescriptor
207
207
PROTOCOL_DESCR_SYM (s21_ObjectiveCBridgeable);
208
208
209
+ #if SWIFT_OBJC_INTEROP
210
+ #define BRIDGING_CONFORMANCE_SYM \
211
+ MANGLE_SYM (s19_BridgeableMetatypeVs21_ObjectiveCBridgeablesWP)
212
+
213
+ extern "C" const _ObjectiveCBridgeableWitnessTable BRIDGING_CONFORMANCE_SYM;
214
+ #endif
215
+
216
+ // / Nominal type descriptor for Swift.String.
217
+ extern " C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM (SS);
218
+
219
+ struct ObjCBridgeWitnessCacheEntry {
220
+ const Metadata *metadata;
221
+ const _ObjectiveCBridgeableWitnessTable *witness;
222
+ };
223
+
209
224
static const _ObjectiveCBridgeableWitnessTable *
210
- findBridgeWitness (const Metadata *T) {
225
+ swift_conformsToObjectiveCBridgeableNoCache (const Metadata *T) {
211
226
auto w = swift_conformsToProtocolCommon (
212
- T, &PROTOCOL_DESCR_SYM (s21_ObjectiveCBridgeable));
227
+ T, &PROTOCOL_DESCR_SYM (s21_ObjectiveCBridgeable));
213
228
return reinterpret_cast <const _ObjectiveCBridgeableWitnessTable *>(w);
214
229
}
215
230
231
+ static const _ObjectiveCBridgeableWitnessTable *
232
+ swift_conformsToObjectiveCBridgeable (const Metadata *T) {
233
+ static std::atomic<ObjCBridgeWitnessCacheEntry> _objcBridgeWitnessCache = {};
234
+ auto cached = _objcBridgeWitnessCache.load (SWIFT_MEMORY_ORDER_CONSUME);
235
+ if (cached.metadata == T) {
236
+ return cached.witness ;
237
+ }
238
+ cached.witness = swift_conformsToObjectiveCBridgeableNoCache (T);
239
+ cached.metadata = T;
240
+ _objcBridgeWitnessCache.store (cached, std::memory_order_release);
241
+ return cached.witness ;
242
+ }
243
+
244
+ static const _ObjectiveCBridgeableWitnessTable *
245
+ findBridgeWitness (const Metadata *T) {
246
+ // Special case: Memoize the bridge witness for Swift.String.
247
+ // Swift.String is the most heavily used bridge because of the prevalence of
248
+ // string-keyed dictionaries in Obj-C. It's worth burning a few words of static
249
+ // storage to avoid repeatedly looking up this conformance.
250
+ if (T->getKind () == MetadataKind::Struct) {
251
+ auto structDescription = cast<StructMetadata>(T)->Description ;
252
+ if (structDescription == &NOMINAL_TYPE_DESCR_SYM (SS)) {
253
+ static auto *Swift_String_ObjectiveCBridgeable = swift_conformsToObjectiveCBridgeableNoCache (T);
254
+ return Swift_String_ObjectiveCBridgeable;
255
+ }
256
+ }
257
+
258
+ auto w = swift_conformsToObjectiveCBridgeable (T);
259
+ if (SWIFT_LIKELY (w))
260
+ return reinterpret_cast <const _ObjectiveCBridgeableWitnessTable *>(w);
261
+ // Class and ObjC existential metatypes can be bridged, but metatypes can't
262
+ // directly conform to protocols yet. Use a stand-in conformance for a type
263
+ // that looks like a metatype value if the metatype can be bridged.
264
+ switch (T->getKind ()) {
265
+ case MetadataKind::Metatype: {
266
+ #if SWIFT_OBJC_INTEROP
267
+ auto metaTy = static_cast <const MetatypeMetadata *>(T);
268
+ if (metaTy->InstanceType ->isAnyClass ())
269
+ return &BRIDGING_CONFORMANCE_SYM;
270
+ #endif
271
+ break ;
272
+ }
273
+ case MetadataKind::ExistentialMetatype: {
274
+ #if SWIFT_OBJC_INTEROP
275
+ auto existentialMetaTy =
276
+ static_cast <const ExistentialMetatypeMetadata *>(T);
277
+ if (existentialMetaTy->isObjC ())
278
+ return &BRIDGING_CONFORMANCE_SYM;
279
+ #endif
280
+ break ;
281
+ }
282
+
283
+ default :
284
+ break ;
285
+ }
286
+ return nullptr ;
287
+ }
288
+
216
289
// / Retrieve the bridged Objective-C type for the given type that
217
290
// / conforms to \c _ObjectiveCBridgeable.
218
291
MetadataResponse
@@ -734,7 +807,7 @@ struct ObjCBridgeMemo {
734
807
#if !NDEBUG
735
808
memo->destType = setupData->destType ;
736
809
#endif
737
- memo->destBridgeWitness = findBridgeWitness (setupData->destType );
810
+ memo->destBridgeWitness = swift_conformsToObjectiveCBridgeableNoCache (setupData->destType );
738
811
if (memo->destBridgeWitness == nullptr ) {
739
812
memo->targetBridgedType = nullptr ;
740
813
memo->targetBridgedObjCClass = nullptr ;
0 commit comments