1.CacheRead process analysis

Based on thecache_tBy learning, we learn that the method of a class or object is passedinsertOperation to add to the cache, when exactlyinsertOperation, we are ininsertTo add a breakpoint to the function call stack:

log_and_fill_cacheCall theinsert:

LookUpImpOrForward calls log_AND_fill_cache

This is how C++ calls the cache.

2. Runtime understanding of Runtime

1.RuntimePosition in OC framework:

2, callRuntimeIn three ways:

3, compile,OCCode, byclanggenerate.cppFile.

xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc main.m -o main.cpp
Copy the code
LGPerson *person = [LGPerson alloc];
[person sayNB];
[person sayHello];

// Compare the compiled results

LGPerson *person = ((LGPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("LGPerson"),sel_registerName("alloc"));
((void(*) (id, SEL))(void *)objc_msgSend)((id)person,sel_registerName("sayNB"));
((void(*) (id, SEL))(void *)objc_msgSend)((id)person,sel_registerName("sayHello"));

// Call method = message send: objc_msgSend(receiver of message, body of message (sel+ argument))
Copy the code

Objc_msgSend and objc_msgSendSuper

OBJC_EXPORT id _Nullable
objc_msgSend(id _Nullable self, SEL _Nonnull op, ...)
    OBJC_AVAILABLE(10.0.2.0.9.0.1.0.2.0);

OBJC_EXPORT id _Nullable
objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
    OBJC_AVAILABLE(10.0.2.0.9.0.1.0.2.0);

Copy the code

Objc_super structure

struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained _Nonnull id receiver;

    /// Specifies the particular superclass of the instance to message. 
#if! defined(__cplusplus) && ! __OBJC2__
    /* For compatibility with old objc-runtime.h header */
    __unsafe_unretained _Nonnull Class class;
#else
    __unsafe_unretained _Nonnull Class super_class;// is the first class to look up
#endif
    /* super_class is the first class to search */
};
#endif
Copy the code

Address: apple document developer.apple.com/documentati…

3. Objc_msgSend process

Find the objc_msgSend assembly source code

Share a shortcut key to use: Command + click on a left arrow to collapse all items

Find the ENTRY ENTRY and here is the assembly implementation of _objc_msgSend and detailed analysis:

_objc_msgSend

· · · · · ·ENTRY _objc_msgSend
	UNWIND _objc_msgSend, NoFrame
        P0 is the address of the message receiver, which determines whether the message receiver exists
	cmp	p0.# 0			// nil check and tagged pointer check
        // Check whether the Taggedpointer type is supported
#if SUPPORT_TAGGED_POINTERS
        // If the Taggedpointer type is supported, process it according to LNilOrTagged
	b.le	LNilOrTagged		// (MSB tagged pointer looks negative)
#else
        // If Taggedpointer is not supported, LReturnZero is returned
	b.eq	LReturnZero
#endif
        // p13 = isa [x0]
	ldr	p13, [x0]		// p13 = isa
	GetClassFromIsa_p16 p13.1, x0	// p16 = class
        
  //receiver -> class -> objc_msgSend -> cache
LGetIsaDone:
	// calls imp or objc_msgSend_uncached
	CacheLookup NORMAL, _objc_msgSend, __objc_msgSend_uncached

#if SUPPORT_TAGGED_POINTERS
LNilOrTagged:
	b.eq	LReturnZero		// nil check
	GetTaggedClass
	b	LGetIsaDone
// SUPPORT_TAGGED_POINTERS
#endif· · · · · ·Copy the code

GetClassFromIsa_p16, p13, 1, x0, what does this method do?

GetClassFromIsa_p16

// GetClassFromIsa_p16 p13, 1, x0; src=p13=isa needs_auth=1 auth_address=x0
.macro GetClassFromIsa_p16 src, needs_auth, auth_address / *note:auth_address is not required if ! needs_auth */

#if SUPPORT_INDEXED_ISA
	// Indexed isa
	mov	p16, \src			// optimistically set dst = src
	tbz	p16, #ISA_INDEX_IS_NPI_BIT.1f	// done if not non-pointer isa
	// isa in p16 is indexed
	adrp	x10, _objc_indexed_classes@PAGE
	add	x10, x10, _objc_indexed_classes@PAGEOFF
	ubfx	p16, p16, #ISA_INDEX_SHIFT.#ISA_INDEX_BITS  // extract index
	ldr	p16, [x10, p16, UXTP #PTRSHIFT]	// load class from array
1:

#elif __LP64__
.if \needs_auth == 0 // _cache_getImp takes an authed class already
	mov	p16, \src
.else
	// 64-bit packed isa
        After the operation, p16 is the receiver's class
	ExtractISA p16, \src, \auth_address
.endif
#else
	// 32-bit raw isa
	mov	p16, \src

#endif

.endmacro
Copy the code

ExtractISA

.macro ExtractISA
        $0=p16, $1= isa, $1= isa, $0=p16, $1= isa
	and    $0.The $1.#ISA_MASK
.endmacro
Copy the code

Knowledge:

[1] when the pointer is shifted by one unit, it is equivalent to $3+1