Having explored alloc, object initialization, and memory alignment, let’s move on to the nature of objects.

A,clangxcrun

clang

Clang is an Apple-led, LLVM-based C/C++/Objective-C compiler.

Because OC is a superset of C and C++, it is possible to compile m files into CPP files through clang.

Usage:

clang -rewrite-objc xx.m -o xx.cpp 
Copy the code

xcrun

Xcrun is a command tool that comes with Xcode and is packaged on top of Clang.

Usage:

1. Simulator

xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc xx.m -o xx.cpp 
Copy the code

2, mobile phone

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc xx.m -o xx.cpp
Copy the code

2. Object nature and extension

First we compile the following main.m file into a CPP file using clang:

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

// The underlying nature of an object is a structure
@interface LGPerson : NSObject

@end

@implementation LGPerson

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"Hello, World!");
    }
    return 0;
}

Copy the code

Since there are a lot of header expansions in the.cpp file that are irrelevant to our exploration goals, I’ll extract the following key code: clang-rewrite-objc main.m -o main.cpp

#ifndef _REWRITER_typedef_LGPerson
#define _REWRITER_typedef_LGPerson
typedef struct objc_object LGPerson;
typedef struct {} _objc_exc_LGPerson;
#endif

// This is LGPerson object
struct LGPerson_IMPL {
	struct NSObject_IMPL NSObject_IVARS;// Struct inheritance, member variable ISA
};

struct NSObject_IMPL {
	Class isa;
};

//Class is a structure pointer, just an alias of objc_class *
typedef struct objc_class *Class;


struct objc_object {
    Class _Nonnull isa __attribute__((deprecated));
};

//id is the alias of objc_object *
typedef struct objc_object *id;



typedef struct objc_selector *SEL;


int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 

        NSLog((NSString *)&__NSConstantStringImpl__var_folders_vj_4mx0r3r94cb6lxl6pxdh225r0000gn_T_main_f586d8_mi_0);
    }
    return 0;
}

struct _prop_t {
	const char *name;
	const char *attributes;
};

struct _protocol_t;

struct _objc_method {
	struct objc_selector * _cmd;
	const char *method_type;
	void  *_imp;
};

struct _protocol_t {
	void * isa;  // NULL
	const char *protocol_name;
	const struct _protocol_list_t * protocol_list; // super protocols
	const struct method_list_t *instance_methods;
	const struct method_list_t *class_methods;
	const struct method_list_t *optionalInstanceMethods;
	const struct method_list_t *optionalClassMethods;
	const struct _prop_list_t * properties;
	const unsigned int size;  // sizeof(struct _protocol_t)
	const unsigned int flags;  / / = 0
	const char ** extendedMethodTypes;
};

struct _ivar_t {
	unsigned long int *offset;  // pointer to ivar offset location
	const char *name;
	const char *type;
	unsigned int alignment;
	unsigned int  size;
};

struct _class_ro_t {
	unsigned int flags;
	unsigned int instanceStart;
	unsigned int instanceSize;
	unsigned int reserved;
	const unsigned char *ivarLayout;
	const char *name;
	const struct _method_list_t *baseMethods;
	const struct _objc_protocol_list *baseProtocols;
	const struct _ivar_list_t *ivars;
	const unsigned char *weakIvarLayout;
	const struct _prop_list_t *properties;
};

struct _class_t {
	struct _class_t *isa;
	struct _class_t *superclass;
	void *cache;
	void *vtable;
	struct _class_ro_t *ro;
};

struct _category_t {
	const char *name;
	struct _class_t *cls;
	const struct _method_list_t *instance_methods;
	const struct _method_list_t *class_methods;
	const struct _protocol_list_t *protocols;
	const struct _prop_list_t *properties;
};
Copy the code

Expansion and supplement of consortium bit domain

A domain:

struct LGCar1 {
    BOOL front; / / 0 to 1
    BOOL back;
    BOOL left;
    BOOL right;
};

// Bit fields to save memory
/ / the mutex
struct LGCar2 {
    BOOL front: 1;
    BOOL back : 2;
    BOOL left : 6;
    BOOL right: 1;
};

struct LGCar1 car1;
struct LGCar2 car2;
NSLog(@"%ld-%ld".sizeof(car1),sizeof(car2));// Print 4 1
Copy the code

A union (also called a Commons) :

/ / coexistence
struct LGTeacher1 {
    char        *name;
    int         age;
    double      height ;
};

// Combine: mutually exclusive
union LGTeacher2 {
    char        *name;
    int         age;
    double      height ;
};

struct LGTeacher1   teacher1;
teacher1.name = "Cooci";
teacher1.age  = 18;

union LGTeacher2    teacher2;
teacher2.name = "Cooci";
teacher2.age  = 18;
Copy the code

Step by step debug print under breakpoint:

(lldb) p teacher1
(LGTeacher1) $0 = (name = 0x0000000000000000, age = 0, height = 0)
(lldb) p teacher1
(LGTeacher1)The $1= (name = "Cooci", age = 0, height = 0)
(lldb) p teacher1
(LGTeacher1) $2 = (name = "Cooci", age = 18, height = 0)

(lldb) p teacher2
(LGTeacher2)A $5= (name = 0x0000000000000000, age = 0, height = 0)
(lldb) p teacher2
(LGTeacher2) $6 = (name = "Cooci", age = 15964, height = 2.1220036782292425 e-314)
(lldb) p teacher2
(LGTeacher2) $7 = (name = "", age = 18, height = 2.1219957998584539 e-314)
Copy the code

Conclusion: All variables in a structure are “co-existing”; All variables in a union are “mutually exclusive” and only one variable can be assigned at a time;

4. Analysis of nonPointerIsa

union isa_t {
    isa_t() {}isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};

Copy the code
#   define ISA_BITFIELD                                                        \
      uintptr_t nonpointer        : 1;                                         \
      uintptr_t has_assoc         : 1;  // Uintptr_t has_cxx_dtor: 1; // uintptr_t shiftcls: 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \ uintptr_t magic : 6; \ uintptr_t weakly_referenced : 1; // Weak reference \ uintptr_t dealLocating: 1; \ uintptr_t has_sidetable_rc : 1; // hash \ uintptr_t extra_rc: 8// reference count
Copy the code

Resolution:

Nonpointer: indicates whether to enable pointer optimization for the ISA pointer. 0: indicates the pure ISA pointer. 1: Indicates that the ISA contains not only the address of the class object but also the class information and reference count of the object

Has_assoc: flag bit of the associated object. 0 does not exist and 1 exists

Has_cxx_dtor: does the object have a destructor for C++ or Objc? If it has a destructor, the destructor logic needs to be done. If not, the object can be freed faster

Shiftcls: Stores the value of the class pointer. With pointer optimization turned on, 33 bits are used to store class Pointers in the ARM64 architecture.

Magic: Used by the debugger to determine whether the current object is a real object or has no space to initialize

Weakly_referenced: A weak variable that records whether an object is pointed to or used to point to an ARC. Objects without weak references can be released faster.

Deallocating: Indicates whether the object is freeing memory

Has_sidetable_rc: When the object reference technique is greater than 10, this variable is borrowed to store carry

Extra_rc: When representing the reference count of this object, the reference count is actually subtracted by 1. For example, if the object’s reference count is 10, the extra_rc is 9. If the reference count is greater than 10, the following has_sideTABLE_rc is used.

5. Isa derivation class

(lldb) x/4gx p
0x10054fc40: 0x011d800100008275 0x0000000000000000 // The first block is isa
0x10054fc50: 0x0000000000000000 0x0000000000000000
(lldb) p/t 0x011d800100008275
(long) $1 = 0b0000000100011101100000000000000100000000000000001000001001110101
(lldb) p/x LGPerson.class / / class
(Class) $2 = 0x0000000100008270 LGPerson 
(lldb) p/x 0x011d800100008275 & 0x00007ffffffffff8ULL # define ISA_MASK 0x00007FFFFFFFF8ull
(unsigned long long) $3 = 0x0000000100008270  // The same address as the class
Copy the code

This is how to find CLS through isa mask

Bit operations for ISA

Combining with the definition of ISA_BITFIELD, CLS is found through the bit operation of ISA.

(lldb) p/x 0x011d800100008275 >> 3
(long) $9 = 0x0023b0002000104e
(lldb) p/x 0x0023b0002000104e << 20
(long) $10 = 0x0002000104e00000
(lldb) p/x 0x0002000104e00000 >> 17
(long) $11 = 0x0000000100008270
(lldb) p/x LGPerson.class
(Class) $12 = 0x0000000100008270 LGPerson
Copy the code