Как работает objc_msgSend и кэширование селекторов?
Что делает objc_msgSend
objc_msgSend(id self, SEL _cmd, ...) — точка входа каждой отправки сообщения. Это не обычная C-функция, а ручной ассемблер для каждой архитектуры (arm64, x86_64), потому что она должна:
- проверить
selfнаnil(и tagged pointer) — еслиnil, обнулить регистры результата и вернуться; - достать класс из
isa(с маской для non-pointer isa); - найти IMP в кэше класса по селектору;
- сделать tail-call (jump) в найденную IMP, не трогая регистры с аргументами — поэтому IMP видит те же
self,_cmdи параметры, как если бы её вызвали напрямую, а в стекеobjc_msgSendне остаётся.
Без ассемблера пришлось бы копировать произвольное число аргументов, зная сигнатуру, а её objc_msgSend как раз не знает.
Варианты: objc_msgSendSuper (для [super ...] — ищет с суперкласса, но self тот же), objc_msgSend_stret (возврат большой структуры через скрытый указатель, на arm64 не нужен), objc_msgSend_fpret (x86 для long double).
Продолжение ответа с кодом и уточняющими вопросами интервьюера — в приложении DevPrep.
Полный ответ — в DevPrep