-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Cache the last ObjC bridging conformance we looked up #81545
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -206,13 +206,86 @@ 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 * | ||
findBridgeWitness(const Metadata *T) { | ||
swift_conformsToObjectiveCBridgeableNoCache(const Metadata *T) { | ||
auto w = swift_conformsToProtocolCommon( | ||
T, &PROTOCOL_DESCR_SYM(s21_ObjectiveCBridgeable)); | ||
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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This entire function is duplicated between DynamicCast.cpp and Casting.cpp, along with its memoization variables. There's also a separate memoization of String stuff in DynamicCast.cpp. I'm unifying the behavior of these (yes they had behavior differences), but saving actually unifying the implementations for later. |
||
// 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 | ||
/// conforms to \c _ObjectiveCBridgeable. | ||
MetadataResponse | ||
|
@@ -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; | ||
|
Uh oh!
There was an error while loading. Please reload this page.