Method slow lookup process review
It was analyzed in the last articleMethod is a slow lookup processBut it leaves a point, if we don’t find itimp
What’s going to happen? When not foundimp
Method can not find the error principle
First look at the source code
When no IMP is found, objc_msgForward_impcache is returned, and the global search is performed
foundobjc_msgForward_impcache
Jump straight to__objc_msgForward
TailCallFunctionPinter
Is to call the current$0
The current$0
forx17
.x17
for__objc_forward_handler
, global searchobjc_forward_handler
This is when we finally find when we don’t findimp
Error reporting method, I believe you should have encountered this kind of error. Under this supplementary explanation__attribute__
Here __attribute__ ((noreturn, cold))
noreturn
This property tells the compiler that the function never returns a value. This property prevents error messages when a function needs to return a value but exits before it reaches the return value. The C library functions abort () and exit () are declared in this formatcold
This means that the function is relatively obscure, so that the branch prediction mechanism will not prefetch it, or make it as obscure as the others(cold)
So that it is more likely not to be put in the cache, and that the more popular instructions will be put in the cache. The opposite of that ishot
.
Class object method dynamic resolution
From assembly source code
Can know behaviors = LOOKUP_INITIALIZW | LOOKUP_RESOLVER, Behavior ^ = LOOKUP_RESOLVER, call resolveMethod_locked(inst, sel, CLS, behavior); Static NEVER_INLINE IMP resolveMethod_locked(ID inst, SEL SEL, Class CLS, int behavior)
Follow our current processcls->isMetaClass()
returnfalse
, so I’m going to go inresolveInstanceMethod
First of all, let’s look for it@selector(resolveInstanceMethod:)
.
IMP lookUpImpOrNilTryCache(id inst, SEL sel, Class cls, int behavior)
{
return _lookUpImpTryCache(inst, sel, cls, behavior | LOOKUP_NIL);
}
Copy the code
When _lookUpImpTryCache is called, set it to LOOKUP_NIL, and attach the _lookUpImpTryCache source code
ALWAYS_INLINE static IMP _lookUpImpTryCache(id inst, SEL sel, Class cls, int behavior) { runtimeLock.assertUnlocked(); if(slowpath(! cls->isInitialized())) { // see comment in lookUpImpOrForward return lookUpImpOrForward(inst, sel, cls, behavior); } IMP imp = cache_getImp(cls, sel); if (imp ! = NULL) goto done; if (slowpath(imp == NULL)) { return lookUpImpOrForward(inst, sel, cls, behavior); } done: if ((behavior & LOOKUP_NIL) && imp == (IMP)_objc_msgForward_impcache) { return nil; } return imp; }Copy the code
So sel = @selector(resolveInstanceMethod), If the class implements @selector(resolveInstanceMethod) this class method (NSObject implements resolveInstanceMethod), call resolveInstanceMethod:, + (BOOL)resolveInstanceMethod (SEL)name + (BOOL)resolveInstanceMethod (SEL)name
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
if (sel == @selector(unimplementMethod))
{
IMP setHobby = class_getMethodImplementation(self, @selector(setHobby:));
Method method = class_getInstanceMethod(self, @selector(setHobby:));
const char *type = method_getTypeEncoding(method);
return class_addMethod(self, sel, setHobby, type);
}
return NO;
}
Copy the code
After calling resolveInstanceMethod:, look up imp again
Class method dynamic resolution
As we can see from the previous summary, when CLS is metaClass, execute this code
else {
// try [nonMetaClass resolveClassMethod:sel]
// and [cls resolveInstanceMethod:sel]
resolveClassMethod(inst, sel, cls);
if (!lookUpImpOrNilTryCache(inst, sel, cls)) {
resolveInstanceMethod(inst, sel, cls);
}
}
Copy the code
Now, you might wonder why you’re calling resolveInstanceMethod again, because the class method is stored in the metaclass, and the class method is the metaclass instanceMethod, so you need to call resolveInstanceMethod here. With this in mind, we can add an NSObject class to the resolve method, override the resolveInstanceMethod:, and dynamically add an IMP. You don’t need to implement resolveClassMethod as well, because you’ll find NSObject in the root metaclass.
conclusion
This article has analyzed only a small part of the message processing mechanism shown above, the dynamic resolution of class methods and instance methods. About the second halfforwarding
See the following article