@@ -206,13 +206,86 @@ struct _ObjectiveCBridgeableWitnessTable : WitnessTable {
206206extern " C" const ProtocolDescriptor
207207PROTOCOL_DESCR_SYM (s21_ObjectiveCBridgeable);
208208
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+
209224static const _ObjectiveCBridgeableWitnessTable *
210- findBridgeWitness (const Metadata *T) {
225+ swift_conformsToObjectiveCBridgeableNoCache (const Metadata *T) {
211226 auto w = swift_conformsToProtocolCommon (
212- T, &PROTOCOL_DESCR_SYM (s21_ObjectiveCBridgeable));
227+ T, &PROTOCOL_DESCR_SYM (s21_ObjectiveCBridgeable));
213228 return reinterpret_cast <const _ObjectiveCBridgeableWitnessTable *>(w);
214229}
215230
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+
216289// / Retrieve the bridged Objective-C type for the given type that
217290// / conforms to \c _ObjectiveCBridgeable.
218291MetadataResponse
@@ -734,7 +807,7 @@ struct ObjCBridgeMemo {
734807#if !NDEBUG
735808 memo->destType = setupData->destType ;
736809#endif
737- memo->destBridgeWitness = findBridgeWitness (setupData->destType );
810+ memo->destBridgeWitness = swift_conformsToObjectiveCBridgeableNoCache (setupData->destType );
738811 if (memo->destBridgeWitness == nullptr ) {
739812 memo->targetBridgedType = nullptr ;
740813 memo->targetBridgedObjCClass = nullptr ;
0 commit comments