mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Cache the last ObjC bridging conformance we looked up (#81545)
Fixes rdar://151475392
This commit is contained in:
@@ -206,11 +206,84 @@ struct _ObjectiveCBridgeableWitnessTable : WitnessTable {
|
||||
extern "C" const ProtocolDescriptor
|
||||
PROTOCOL_DESCR_SYM(s21_ObjectiveCBridgeable);
|
||||
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
#define BRIDGING_CONFORMANCE_SYM \
|
||||
MANGLE_SYM(s19_BridgeableMetatypeVs21_ObjectiveCBridgeablesWP)
|
||||
|
||||
extern "C" const _ObjectiveCBridgeableWitnessTable BRIDGING_CONFORMANCE_SYM;
|
||||
#endif
|
||||
|
||||
/// Nominal type descriptor for Swift.String.
|
||||
extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(SS);
|
||||
|
||||
struct ObjCBridgeWitnessCacheEntry {
|
||||
const Metadata *metadata;
|
||||
const _ObjectiveCBridgeableWitnessTable *witness;
|
||||
};
|
||||
|
||||
static const _ObjectiveCBridgeableWitnessTable *
|
||||
swift_conformsToObjectiveCBridgeableNoCache(const Metadata *T) {
|
||||
auto w = swift_conformsToProtocolCommon(
|
||||
T, &PROTOCOL_DESCR_SYM(s21_ObjectiveCBridgeable));
|
||||
return reinterpret_cast<const _ObjectiveCBridgeableWitnessTable *>(w);
|
||||
}
|
||||
|
||||
static const _ObjectiveCBridgeableWitnessTable *
|
||||
swift_conformsToObjectiveCBridgeable(const Metadata *T) {
|
||||
static std::atomic<ObjCBridgeWitnessCacheEntry> _objcBridgeWitnessCache = {};
|
||||
auto cached = _objcBridgeWitnessCache.load(SWIFT_MEMORY_ORDER_CONSUME);
|
||||
if (cached.metadata == T) {
|
||||
return cached.witness;
|
||||
}
|
||||
cached.witness = swift_conformsToObjectiveCBridgeableNoCache(T);
|
||||
cached.metadata = T;
|
||||
_objcBridgeWitnessCache.store(cached, std::memory_order_release);
|
||||
return cached.witness;
|
||||
}
|
||||
|
||||
static const _ObjectiveCBridgeableWitnessTable *
|
||||
findBridgeWitness(const Metadata *T) {
|
||||
auto w = swift_conformsToProtocolCommon(
|
||||
T, &PROTOCOL_DESCR_SYM(s21_ObjectiveCBridgeable));
|
||||
return reinterpret_cast<const _ObjectiveCBridgeableWitnessTable *>(w);
|
||||
// Special case: Memoize the bridge witness for Swift.String.
|
||||
// Swift.String is the most heavily used bridge because of the prevalence of
|
||||
// string-keyed dictionaries in Obj-C. It's worth burning a few words of static
|
||||
// storage to avoid repeatedly looking up this conformance.
|
||||
if (T->getKind() == MetadataKind::Struct) {
|
||||
auto structDescription = cast<StructMetadata>(T)->Description;
|
||||
if (structDescription == &NOMINAL_TYPE_DESCR_SYM(SS)) {
|
||||
static auto *Swift_String_ObjectiveCBridgeable = swift_conformsToObjectiveCBridgeableNoCache(T);
|
||||
return Swift_String_ObjectiveCBridgeable;
|
||||
}
|
||||
}
|
||||
|
||||
auto w = swift_conformsToObjectiveCBridgeable(T);
|
||||
if (SWIFT_LIKELY(w))
|
||||
return reinterpret_cast<const _ObjectiveCBridgeableWitnessTable *>(w);
|
||||
// Class and ObjC existential metatypes can be bridged, but metatypes can't
|
||||
// directly conform to protocols yet. Use a stand-in conformance for a type
|
||||
// that looks like a metatype value if the metatype can be bridged.
|
||||
switch (T->getKind()) {
|
||||
case MetadataKind::Metatype: {
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
auto metaTy = static_cast<const MetatypeMetadata *>(T);
|
||||
if (metaTy->InstanceType->isAnyClass())
|
||||
return &BRIDGING_CONFORMANCE_SYM;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case MetadataKind::ExistentialMetatype: {
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
auto existentialMetaTy =
|
||||
static_cast<const ExistentialMetatypeMetadata *>(T);
|
||||
if (existentialMetaTy->isObjC())
|
||||
return &BRIDGING_CONFORMANCE_SYM;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Retrieve the bridged Objective-C type for the given type that
|
||||
@@ -734,7 +807,7 @@ struct ObjCBridgeMemo {
|
||||
#if !NDEBUG
|
||||
memo->destType = setupData->destType;
|
||||
#endif
|
||||
memo->destBridgeWitness = findBridgeWitness(setupData->destType);
|
||||
memo->destBridgeWitness = swift_conformsToObjectiveCBridgeableNoCache(setupData->destType);
|
||||
if (memo->destBridgeWitness == nullptr) {
|
||||
memo->targetBridgedType = nullptr;
|
||||
memo->targetBridgedObjCClass = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user