当无法在缓存中找到方法时,
cbz p9, \MissLabelDynamic调用__objc_msgSend_uncached
lookUpImpOrForward
- IMP lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior)
- 为什么用汇编查找缓存,慢速查找则使用c++,
- 1.汇编查找缓存更加快速查找
- 2.参数未知,汇编则更加动态化
- 是一个遍历methodlist的过程
IMP lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior)
{
const IMP forward_imp = (IMP)_objc_msgForward_impcache;
IMP imp = nil;
Class curClass;
runtimeLock.assertUnlocked();
if (slowpath(!cls->isInitialized())) {
//...
behavior |= LOOKUP_NOCACHE;
}
//...
runtimeLock.lock();
//...
checkIsKnownClass(cls); //判断class是否已经完成注册
cls = realizeAndInitializeIfNeeded_locked(inst, cls, behavior & LOOKUP_INITIALIZE);
// runtimeLock may have been dropped but is now locked again
runtimeLock.assertLocked();
curClass = cls;
//..
for (unsigned attempts = unreasonableClassCount();;) {
if (curClass->cache.isConstantOptimizedCache(/* strict */true)) {
#if CONFIG_USE_PREOPT_CACHES //是否有共享缓存
imp = cache_getImp(curClass, sel);
if (imp) goto done_unlock;
curClass = curClass->cache.preoptFallbackClass();
#endif
} else {
// curClass method list.
Method meth = getMethodNoSuper_nolock(curClass, sel);
if (meth) {
imp = meth->imp(false);
goto done;
}
if (slowpath((curClass = curClass->getSuperclass()) == nil)) {
// No implementation found, and method resolver didn't help.
// Use forwarding.
imp = forward_imp;
break;
}
}
// Halt if there is a cycle in the superclass chain.
if (slowpath(--attempts == 0)) {
_objc_fatal("Memory corruption in class list.");
}
// Superclass cache.
imp = cache_getImp(curClass, sel);
if (slowpath(imp == forward_imp)) {
// Found a forward:: entry in a superclass.
// Stop searching, but don't cache yet; call method
// resolver for this class first.
break;
}
if (fastpath(imp)) {
// Found the method in a superclass. Cache it in this class.
goto done;
}
}
// No implementation found. Try method resolver once.
if (slowpath(behavior & LOOKUP_RESOLVER)) {
behavior ^= LOOKUP_RESOLVER;
return resolveMethod_locked(inst, sel, cls, behavior);
}
done:
if (fastpath((behavior & LOOKUP_NOCACHE) == 0)) {
#if CONFIG_USE_PREOPT_CACHES
while (cls->cache.isConstantOptimizedCache(/* strict */true)) {
cls = cls->cache.preoptFallbackClass();
}
#endif
log_and_fill_cache(cls, imp, sel, inst, curClass);
}
done_unlock:
runtimeLock.unlock();
if (slowpath((behavior & LOOKUP_NIL) && imp == forward_imp)) {
return nil;
}
return imp;
}
方法列表查找前准备
1.checkIsKnownClass(cls); //判断class是否已经完成注册
-
流程顺序是 lookUpImpOrForward - > checkIsKnownClass(cls) -> checkIsKnownClass - > isKnownClass
-
realizeAndInitializeIfNeeded_locked
static Class
realizeAndInitializeIfNeeded_locked(id inst, Class cls, bool initialize)
{
runtimeLock.assertLocked();
if (slowpath(!cls->isRealized())) {
cls = realizeClassMaybeSwiftAndLeaveLocked(cls, runtimeLock);
// runtimeLock may have been dropped but is now locked again
}
if (slowpath(initialize && !cls->isInitialized())) {
cls = initializeAndLeaveLocked(cls, inst, runtimeLock);
// runtimeLock may have been dropped but is now locked again
// If sel == initialize, class_initialize will send +initialize and
// then the messenger will send +initialize again after this
// procedure finishes. Of course, if this is not being called
// from the messenger then it won't happen. 2778172
}
return cls;
}
- realizeClassMaybeSwiftAndLeaveLocked
static Class
realizeClassMaybeSwiftAndLeaveLocked(Class cls, mutex_t& lock)
{
return realizeClassMaybeSwiftMaybeRelock(cls, lock, true);
}
- realizeClassMaybeSwiftMaybeRelock
static Class
realizeClassMaybeSwiftMaybeRelock(Class cls, mutex_t& lock, bool leaveLocked)
{
lock.assertLocked();
if (!cls->isSwiftStable_ButAllowLegacyForNow()) {
// Non-Swift class. Realize it now with the lock still held.
// fixme wrong in the future for objc subclasses of swift classes
realizeClassWithoutSwift(cls, nil);
if (!leaveLocked) lock.unlock();
} else {
// Swift class. We need to drop locks and call the Swift
// runtime to initialize it.
lock.unlock();
cls = realizeSwiftClass(cls);
ASSERT(cls->isRealized()); // callback must have provoked realization
if (leaveLocked) lock.lock();
}
return cls;
}
- realizeClassWithoutSwift
static Class realizeClassWithoutSwift(Class cls, Class previously)
{
runtimeLock.assertLocked();
class_rw_t *rw;
Class supercls;
Class metacls;
if (!cls) return nil;
if (cls->isRealized()) {
validateAlreadyRealizedClass(cls);
return cls;
}
ASSERT(cls == remapClass(cls));
// fixme verify class is not in an un-dlopened part of the shared cache?
auto ro = (const class_ro_t *)cls->data();
auto isMeta = ro->flags & RO_META;
if (ro->flags & RO_FUTURE) {
// This was a future class. rw data is already allocated.
rw = cls->data();
ro = cls->data()->ro();
ASSERT(!isMeta);
cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
} else {
// Normal class. Allocate writeable class data.
rw = objc::zalloc<class_rw_t>();
rw->set_ro(ro);
rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
cls->setData(rw);
}
cls->cache.initializeToEmptyOrPreoptimizedInDisguise();
#if FAST_CACHE_META
if (isMeta) cls->cache.setBit(FAST_CACHE_META);
#endif
// Choose an index for this class.
// Sets cls->instancesRequireRawIsa if indexes no more indexes are available
cls->chooseClassArrayIndex();
if (PrintConnecting) {
_objc_inform("CLASS: realizing class '%s'%s %p %p #%u %s%s",
cls->nameForLogging(), isMeta ? " (meta)" : "",
(void*)cls, ro, cls->classArrayIndex(),
cls->isSwiftStable() ? "(swift)" : "",
cls->isSwiftLegacy() ? "(pre-stable swift)" : "");
}
// Realize superclass and metaclass, if they aren't already.
// This needs to be done after RW_REALIZED is set above, for root classes.
// This needs to be done after class index is chosen, for root metaclasses.
// This assumes that none of those classes have Swift contents,
// or that Swift's initializers have already been called.
// fixme that assumption will be wrong if we add support
// for ObjC subclasses of Swift classes.
supercls = realizeClassWithoutSwift(remapClass(cls->getSuperclass()), nil); //注册父类
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil); //注册元类
#if SUPPORT_NONPOINTER_ISA
if (isMeta) {
// Metaclasses do not need any features from non pointer ISA
// This allows for a faspath for classes in objc_retain/objc_release.
cls->setInstancesRequireRawIsa();
} else {
// Disable non-pointer isa for some classes and/or platforms.
// Set instancesRequireRawIsa.
bool instancesRequireRawIsa = cls->instancesRequireRawIsa();
bool rawIsaIsInherited = false;
static bool hackedDispatch = false;
if (DisableNonpointerIsa) {
// Non-pointer isa disabled by environment or app SDK version
instancesRequireRawIsa = true;
}
else if (!hackedDispatch && 0 == strcmp(ro->getName(), "OS_object"))
{
// hack for libdispatch et al - isa also acts as vtable pointer
hackedDispatch = true;
instancesRequireRawIsa = true;
}
else if (supercls && supercls->getSuperclass() &&
supercls->instancesRequireRawIsa())
{
// This is also propagated by addSubclass()
// but nonpointer isa setup needs it earlier.
// Special case: instancesRequireRawIsa does not propagate
// from root class to root metaclass
instancesRequireRawIsa = true;
rawIsaIsInherited = true;
}
if (instancesRequireRawIsa) {
cls->setInstancesRequireRawIsaRecursively(rawIsaIsInherited);
}
}
// SUPPORT_NONPOINTER_ISA
#endif
// Update superclass and metaclass in case of remapping
cls->setSuperclass(supercls); //设置父类
cls->initClassIsa(metacls); //设置元类
// Reconcile instance variable offsets / layout.
// This may reallocate class_ro_t, updating our ro variable.
if (supercls && !isMeta) reconcileInstanceVariables(cls, supercls, ro);
// Set fastInstanceSize if it wasn't set already.
cls->setInstanceSize(ro->instanceSize);
// Copy some flags from ro to rw
if (ro->flags & RO_HAS_CXX_STRUCTORS) {
cls->setHasCxxDtor();
if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
cls->setHasCxxCtor();
}
}
// Propagate the associated objects forbidden flag from ro or from
// the superclass.
if ((ro->flags & RO_FORBIDS_ASSOCIATED_OBJECTS) ||
(supercls && supercls->forbidsAssociatedObjects()))
{
rw->flags |= RW_FORBIDS_ASSOCIATED_OBJECTS;
}
// Connect this class to its superclass's subclass lists
if (supercls) {
addSubclass(supercls, cls);
} else {
addRootClass(cls);
}
// Attach categories
methodizeClass(cls, previously);
return cls;
}
- 当前类以及相关类的注册,为方法的查找做准备。
进入循环
for (unsigned attempts = unreasonableClassCount();;)慢速查找流程重点部分 这是一个死循环,除非return 出去。- 查自己 methodList-sel-imp
- 父类-> NSObject->nil->跳出
- 1.再次查找缓存。
- 2.二分查找找到方法
- 二维大数组的遍历循环
static method_t *
getMethodNoSuper_nolock(Class cls, SEL sel)
{
runtimeLock.assertLocked();
ASSERT(cls->isRealized());
// fixme nil cls?
// fixme nil sel?
auto const methods = cls->data()->methods(); //获取方法列表
//这个并不是二分查找,因为方法列表是一个二维数组,即大数组中的元素还是数组,为了避免遗漏,外部的大数组必须是依次遍历查找,自己(数组)元素,而(数组)元素,中的数组可以进行二分查找。
for (auto mlists = methods.beginLists(),
end = methods.endLists();
mlists != end;
++mlists) //for循环 设置两个变量 mlists 头部指针,end尾部指针,头部不等于尾部,则++
{
// <rdar://problem/46904873> getMethodNoSuper_nolock is the hottest
// caller of search_method_list, inlining it turns
// getMethodNoSuper_nolock into a frame-less function and eliminates
// any store from this codepath.
method_t *m = search_method_list_inline(*mlists, sel);
if (m) return m;
}
return nil;
}
- findMethodInSortedMethodList 传入方法名和方法列表开始进行二分查找
ALWAYS_INLINE static method_t *
search_method_list_inline(const method_list_t *mlist, SEL sel)
{
int methodListIsFixedUp = mlist->isFixedUp(); //方法列表是否完成排序
int methodListHasExpectedSize = mlist->isExpectedSize(); //针对分类处理
if (fastpath(methodListIsFixedUp && methodListHasExpectedSize)) {
return findMethodInSortedMethodList(sel, mlist); //查找已经排序好的方法列表
} else {
// Linear search of unsorted method list
if (auto *m = findMethodInUnsortedMethodList(sel, mlist))
return m;
}
#if DEBUG
// sanity-check negative results
if (mlist->isFixedUp()) {
for (auto& meth : *mlist) {
if (meth.name() == sel) {
_objc_fatal("linear search worked when binary search did not");
}
}
}
#endif
return nil;
}
- 查找已经排序好的方法列表
最重要的关键方法中了
ALWAYS_INLINE static method_t *
findMethodInSortedMethodList(SEL key, const method_list_t *list, const getNameFunc &getName)
{
ASSERT(list);
auto first = list->begin();
auto base = first;
decltype(first) probe;
uintptr_t keyValue = (uintptr_t)key;
uint32_t count;
for (count = list->count; count != 0; count >>= 1) {
probe = base + (count >> 1);
uintptr_t probeValue = (uintptr_t)getName(probe);
if (keyValue == probeValue) {
// `probe` is a match.
// Rewind looking for the *first* occurrence of this value.
// This is required for correct category overrides.
while (probe > first && keyValue == (uintptr_t)getName((probe - 1))) {
probe--;
}
return &*probe;
}
if (keyValue > probeValue) {
base = probe + 1;
count--;
}
}
return nil;
}
for example
- 假设 count = list->count = 8 正确的位置 在 6 或者 7 在 中间的后面
- 1.probe = 0 + 8>>1 =0+4 = 4
uintptr_t probeValue = (uintptr_t)getName(probe);//得到第4个当前的方法名- 如果找到了,判断当前下标大于first && 前一个的方法名也是相同的(有分类的时候)
- 则减一 传出这个方法
- 否则直接返回这个方法
- 2.没有找到 则 base = probe + 1 = 5, count -- -> 7, count = count >> 1 = 3
- probe = base + (count >> 1) = 6
uintptr_t probeValue = (uintptr_t)getName(probe);//得到第6个当前的方法名
- probe = base + (count >> 1) = 6
- 3.还是没有找到 base = probe + 1 = 7, count -- -> 2,count = count >> 1 = 1
- probe = base + (count >> 1) = 7 + 0 = 7
- 4.还是没有找到 count -- = 0 则跳出循环 返回 nil
- 1.probe = 0 + 8>>1 =0+4 = 4
- 疑惑目前这个方法是向后对半的查找 没有向前呀???
- 假设 count = list->count = 8 正确的位置 在 2 或者 3 在 中间的前面
- 1.probe = 0 + 8>>1 =0+4 = 4
uintptr_t probeValue = (uintptr_t)getName(probe);//得到第4个当前的方法名- 没有找到 并且 keyValue < probeValue
- 2.
if (keyValue > probeValue)判断不成立 返回上面再次循环- count >>= 1 ,count = 4 开始循环
- probe = base + (count >> 1) = 0 + 4>> 1 = 2
- 位置2 则正确返回
-
- 位置3 则进入这个判断
-
base = probe + 1 = 3 ,count -- = 3
-
count >>= 1 -> 1
-
probe = base + (count >> 1) = 3
-
找到了3
- 1.probe = 0 + 8>>1 =0+4 = 4
goto done;
缓存填充
父类查找如果没有找到则继续向父类查找直到nil
nil forward_imp 打上标记
动态方法决议查找
const IMP forward_imp = (IMP)_objc_msgForward_impcache;