iOS之方法的快速查詢流程總結

語言: CN / TW / HK

小知識,大挑戰!本文正在參與“程式設計師必備小知識”創作活動。

快速查詢流程:

  • 將類物件地址,記憶體平移16位元組,取地址,得到cache首地址,即:_bucketsAndMaybeMask
  • _bucketsAndMaybeMask & bucketsMask,獲取buckets首地址
  • 判斷_bucketsAndMaybeMask0號位不為0,進入LLookupPreopt流程,查詢共享快取
  • 否則,通過_bucketsAndMaybeMask >> 48,得到mask
  • (_cmd ^ (_cmd >> 7)) & mask,得到下標i。原始碼中的cache_hash函式
  • 通過i * 16得到偏移值,buckets首地址+偏移值,得到指定下標的bucket
  • 流程1
    • 讀取bucket_t中的impsel
    • 通過bucket_t - 16位元組,讀取上一個bucket
  • 流程2
    • 如果sel存在,並且等於_cmd,進入CacheHit快取命中流程 - CacheHit流程:使用imp = imp ^ cls解碼
    • 跳轉到指定imp函式地址
  • 流程3
    • 如果sel不存在,進入__objc_msgSend_uncached流程
    • 上一個bucket地址和buckets首地址比較,如果>=,進入流程1
    • 否則,<首地址,獲取mask下標的bucket,進入流程4
  • 流程4
    • 讀取bucket_t中的impsel
    • 通過bucket_t - 16位元組,讀取上一個bucket
    • 如果sel等於_cmd,進入流程2
    • 如果sel存在,並且上一個bucket地址>指定下標bucket地址,進入流程4
    • 否則,進入__objc_msgSend_uncached流程

訊息快速查詢流程中,如果無法命中快取,進入MissLabelDynamic流程。而MissLabelDynamic即是呼叫CacheLookup時傳入的__objc_msgSend_uncached 流程探索: - 核心流程:__objc_msgSend_uncachedMethodTableLookup_lookUpImpOrForward - lookUpImpOrForward函式,並且不是彙編程式碼實現,而是C/C++函式 - 彙編和C/C++的相互呼叫: - C/C++中調用匯編,在彙編程式碼中查詢時,在方法名稱最前面加一個下劃線 - 彙編中呼叫C/C++函式,在C/C++程式碼中查詢時,去掉方法名稱最前面的一個下劃線