Skip to content
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

Improve performance in __CF_IsBridgedObject/__CF_IsCFObject #1923

Merged
merged 3 commits into from
Feb 7, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 22 additions & 17 deletions Frameworks/CoreFoundation/Base.subproj/CFInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,17 @@ CF_PRIVATE Boolean __CFProcessIsRestricted();
extern "C" Class _OBJC_CLASS__NSCFNumber;
extern "C" Class _OBJC_CLASS__NSCFBoolean;

// WINOBJC: Returns an empty protocol that is assigned only to bridged classes, so that bridged objects can be distinguished quickly
static Protocol* __CFRuntimeGetBridgeProtocol() {
static Protocol* s_bridgeProtocol = []() {
Protocol* ret = objc_allocateProtocol("_NSCFBridgedType");
objc_registerProtocol(ret);
return ret;
}();

return s_bridgeProtocol;
}

#ifdef __CONSTANT_CFSTRINGS__

#if DEPLOYMENT_RUNTIME_SWIFT
Expand Down Expand Up @@ -684,8 +695,7 @@ extern uintptr_t __CFRuntimeObjCClassTable[];
// WINOBJC: helper function to determine if a cf object is a bridged CF object.
CF_INLINE bool __CF_IsBridgedObject(CFTypeRef obj) {
CFRuntimeBase* object = (CFRuntimeBase*)obj;
if (!object ||
(object->_cfisa == 0)) {
if (!object || (object->_cfisa == 0)) {
return false;
}

Expand All @@ -696,28 +706,23 @@ CF_INLINE bool __CF_IsBridgedObject(CFTypeRef obj) {
return true;
}

for (unsigned int i = 0; i < __CFRuntimeClassTableSize; i++) {
if ((__CFRuntimeObjCClassTable[i] != 0) &&
((object->_cfisa == __CFRuntimeObjCClassTable[i]) ||
([object isKindOfClass:(Class)(__CFRuntimeObjCClassTable[i])]))) {
return true;
}
}

return false;
// Check if the object has the 'bridged object' protocol
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: should have WINOBJC: here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already a WINOBJC: function, so not necessary

// NOTE: because our class_conformsToProtocol() checks based only on name,
// it is possible to spoof a bridged object by stating an object conforms to a protocol with the same name.
// However, this would not grant access to anything that could not be accessed by more conventional means
// (ie: overriding an existing CF/Foundation class)
// and as such would not constitute an escalation of privilege.
return [object conformsToProtocol:__CFRuntimeGetBridgeProtocol()];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer class_conformsToProtocol(object->_cfisa, ...) -- that will remove Objective-C from purely C++ CFInternal.h consumers.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(this header is shared externally -- CoreGraphics, CoreText, etc. use it)

}


// WINOBJC: helper function to determine if an object is actually a CF object.
// Logically this is basically !CF_IS_OBJC except that the expected type is not known ahead of time.
// This is also logically the same as __CF_IsBridgedObject, except for if the object's _cfisa == 0
// (treated as a CF object but not a bridged one)
CF_INLINE bool __CF_IsCFObject(CFTypeRef obj) {
CFRuntimeBase* object = (CFRuntimeBase*)obj;
if ((object->_cfisa == 0) ||
(object->_cfisa == (uintptr_t)(&_OBJC_CLASS__NSCFType)) ||
(object->_cfisa == (uintptr_t)(&_OBJC_CLASS__NSCFString)) ||
(object->_cfisa == (uintptr_t)(&_OBJC_CLASS__NSCFNumber)) ||
(object->_cfisa == (uintptr_t)(&_OBJC_CLASS__NSCFBoolean)) ||
__CF_IsBridgedObject(obj)) {
if ((object->_cfisa == 0) || __CF_IsBridgedObject(obj)) {
return true;
}

Expand Down
4 changes: 4 additions & 0 deletions Frameworks/CoreFoundation/Base.subproj/CFRuntime.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ CFTypeID _CFRuntimeRegisterClass(const CFRuntimeClass * const cls) {
void _CFRuntimeBridgeTypeToClass(CFTypeID cf_typeID, const void *cls_ref) {
__CFLock(&__CFBigRuntimeFunnel);
__CFRuntimeObjCClassTable[cf_typeID] = (uintptr_t)cls_ref;

// WINOBJC: Label the class with the 'bridged object' protocol, so that it can be quickly distinguished from non-bridged objects
class_addProtocol((Class)cls_ref, __CFRuntimeGetBridgeProtocol());

__CFUnlock(&__CFBigRuntimeFunnel);
}

Expand Down