Clang before we dive into the nature of the object
clang
Clang
Is aC++
Written and based onLLVM
And published inLLVM BSD
Under licenseC
/C++
/Objective-C
/Objective-C++
The compiler.
clang
Terminal compile command
Compile the object file into a c++ file
clang -rewrite-objc main.m -o main.cpp
Copy the code
Xcode is installed with the xcrun command, which is a bit more wrapped around clang to make it easier to use.
The simulator
xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
Copy the code
A:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main arm64.cpp
Copy the code
Nature of object
nature
Run the clang-rewrite-objc main.m -o main. CPP command to compile the main.m file.
#import <Foundation/ foundation.h > #import <objc/runtime.h> NSObject @property (nonatomic, strong) NSString *xhName; @property (nonatomic, assign) int xhAge; @end @implementation XHPerson @end int main(int argc, const char * argv[]) { @autoreleasepool { NSLog(@"Hello, World!" ); } return 0; }Copy the code
The XHPerson in the main.cpp file looks like this:
extern "C" unsigned long OBJC_IVAR_$_XHPerson$_xhName;
extern "C" unsigned long OBJC_IVAR_$_XHPerson$_xhAge;
struct XHPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _xhAge;
NSString *_xhName;
};
typedef struct objc_object XHPerson;
struct NSObject_IMPL {
Class isa;
};
Copy the code
Conclusion: XHPerson is the underlying structure, XHPerson_IMPL structure has three variables, _xhAge, _xhName are custom attributes, NSObject_IVARS is the ISA in NSObject. XHPerson inherits from NSObject, so XHPerson also has all of NSObject’s member variables.
The underlying NSObject is the NSObject_IMPL where only one member variable is Class ISA. It is usually called isa and is called an ISA pointer, so the Class should be a pointer type, searching for *Class globally in the main. CPP file. The following
typedef struct objc_class *Class; Struct objc_object {Class _Nonnull ISA __attribute__((deprecated)); }; Struct NSObject_IMPL {Class isa; };Copy the code
Class
The type is actually oneobjc_class
Pointer to a structure of type,objc_class
Is the underlying implementation of all classes. So we guessisa
There may be important associations with class information, and the specific associations will be explored below.NSObject
What is the difference between the underlying implementation of object and the underlying implementation of object. The structure of both member variables isClass isa
, then there must be inheritance relationship. At the bottom of all objects is inheritanceobjc_object
In theOC
Almost all objects in theNSObject
, but the real underlying implementation isobjc_object
Struct type of.
Object attribute low-level analysis
// getter
// getter
static NSString * _I_XHPerson_xhName(XHPerson * self, SEL _cmd) {
return (*(NSString **)((char *)self + OBJC_IVAR_$_XHPerson$_xhName));
}
// setter
static void _I_XHPerson_setXhName_(XHPerson * self, SEL _cmd, NSString *xhName) {
(*(NSString **)((char *)self + OBJC_IVAR_$_XHPerson$_xhName)) = xhName;
}
Copy the code
Member variables can be accessed by obtaining the first address of the object plus the offset address of the variable, and then accessing the memory according to the calculated address:
(char *)self
: The first address of the objectOBJC_IVAR_$_XHPerson$_xhName
: The offset address of the member variable name*(NSString **)((char *)self + OBJC_IVAR_$_XHPerson$_xhName)
Memory for the member variable name
A domain
/ / 4 * 8 = 32, 0000, 0000, 0000, 0000, 0000, 0000, 1111/0000 / four/three times / 1 byte waste struct XHCar1 {BOOL front; // 0 1 BOOL back; BOOL left; BOOL right; }; Struct XHCar2 {BOOL front: 1; BOOL back : 1; BOOL left : 1; BOOL right: 1; };Copy the code
- The structure of the body
XHCar1
It takes 4 bytes because its internal member variables areBOOL
Type, in fact, can be put down in 1 byte. - The structure of the body
XHCar2
It takes 1 byte, saving 3 bytes.
A consortium
Struct XHTeacher1 {char *name; int age; double height ; }; // Union: mutually exclusive union XHTeacher2 {char *name; int age; double height ; };Copy the code
Teacher1 structure coexistence: Name, age, height all have values. Sizeof is 24
Teacher2 Mutual-exclusive: Only one of name, age, height has a value, the last one is assigned a value and the previous one is cleared. Sizeof is eight
- Structure (
struct
), all variables are “co-existing” — the advantage is “tolerant”, comprehensive; The disadvantage is thatstruct
The allocation of memory space is extensive, regardless of use, full allocation. - A consortium (
union
) is that the variables are mutually exclusive — the disadvantage is that they are not inclusive enough; But the advantage is that memory usage is more delicate and flexible, and also saves memory space.
nonPointerIsa
ISA is divided into pure ISA and NONPOINTER_ISA, which contains some information about the class in addition to a pure pointer.
The alloc underlying text will eventually bind the structure pointer from the heap to the current class via initIsa.
inline void
objc_object::initIsa(Class cls)
{
initIsa(cls, false, false);
}
Copy the code
inline void objc_object::initIsa(Class cls, bool nonpointer, UNUSED_WITHOUT_INDEXED_ISA_AND_DTOR_BIT bool hasCxxDtor) { ASSERT(! isTaggedPointer()); isa_t newisa(0); if (! nonpointer) { newisa.setClass(cls, this); } else { ASSERT(! DisableNonpointerIsa); ASSERT(! cls->instancesRequireRawIsa()); #if SUPPORT_INDEXED_ISA ASSERT(cls->classArrayIndex() > 0); newisa.bits = ISA_INDEX_MAGIC_VALUE; // isa.magic is part of ISA_MAGIC_VALUE // isa.nonpointer is part of ISA_MAGIC_VALUE newisa.has_cxx_dtor = hasCxxDtor; newisa.indexcls = (uintptr_t)cls->classArrayIndex(); #else newisa.bits = ISA_MAGIC_VALUE; // isa.magic is part of ISA_MAGIC_VALUE // isa.nonpointer is part of ISA_MAGIC_VALUE # if ISA_HAS_CXX_DTOR_BIT newisa.has_cxx_dtor = hasCxxDtor; # endif newisa.setClass(cls, this); #endif newisa.extra_rc = 1; } // This write must be performed in a single store in some cases // (for example when realizing a class because other threads // may simultaneously try to use the class). // fixme use atomics here to guarantee single-store and to // guarantee memory order w.r.t. the class index table // ... but not too atomic because we don't want to hurt instantiation isa = newisa; }Copy the code
// uintptr_t () {} isa_t(uintptr_t value) : Bits (value) {} uintptr_t bits; private: // Accessing the class requires custom ptrauth operations, so // force clients to go through setClass/getClass by making this // private. Class cls; public: #if defined(ISA_BITFIELD) struct { ISA_BITFIELD; // defined in isa.h }; bool isDeallocating() { return extra_rc == 0 && has_sidetable_rc == 0; } void setDeallocating() { extra_rc = 0; has_sidetable_rc = 0; } #endif void setClass(Class cls, objc_object *obj); Class getClass(bool authenticated); Class getDecodedClass(bool authenticated); };Copy the code
ISA_BITFIELD definition in ARM64 and X86_64 architecture
# if __arm64__ // ARM64 simulators have a larger address space, so use the ARM64e // scheme even when simulators build for ARM64-not-e. # if __has_feature(ptrauth_calls) || TARGET_OS_SIMULATOR # define ISA_MASK 0x007ffffffffffff8ULL # define ISA_MAGIC_MASK 0x0000000000000001ULL # define ISA_MAGIC_VALUE 0x0000000000000001ULL # define ISA_HAS_CXX_DTOR_BIT 0 # define ISA_BITFIELD \ uintptr_t nonpointer : 1; \ uintptr_t has_assoc : 1; \ uintptr_t weakly_referenced : 1; \ uintptr_t shiftcls_and_sig : 52; \ uintptr_t has_sidetable_rc : 1; \ uintptr_t extra_rc : 8 # define RC_ONE (1ULL<<56) # define RC_HALF (1ULL<<7) # else # define ISA_MASK 0x0000000ffffffff8ULL # define ISA_MAGIC_MASK 0x000003f000000001ULL # define ISA_MAGIC_VALUE 0x000001a000000001ULL # define ISA_HAS_CXX_DTOR_BIT 1 # define ISA_BITFIELD \ uintptr_t nonpointer : 1; \ uintptr_t has_assoc : 1; \ uintptr_t has_cxx_dtor : 1; \ uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \ uintptr_t magic : 6; \ uintptr_t weakly_referenced : 1; \ uintptr_t unused : 1; \ uintptr_t has_sidetable_rc : 1; \ uintptr_t extra_rc : 19 # define RC_ONE (1ULL<<45) # define RC_HALF (1ULL<<18) # endif # elif __x86_64__ # define ISA_MASK 0x00007ffffffffff8ULL # define ISA_MAGIC_MASK 0x001f800000000001ULL # define ISA_MAGIC_VALUE 0x001d800000000001ULL # define ISA_HAS_CXX_DTOR_BIT 1 # 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 weakly_referenced : 1; // uintptr_t unused: 1; \ // uintptr_t has_sidetable_rc : 1; // Uintptr_t extra_rc: 8 // Reference count # define RC_ONE (1ULL<<56) # define RC_HALF (1ULL<<7) # else # Error unknown architecture for Packed ISA # endif // SUPPORT_PACKED_ISA #endifCopy the code
nonpointer
: indicates whether it is correctisa
Pointer Pointer optimization is enabled. 0: pure ISA pointer, 1: not only the address of the class object, ISA contains the class information, reference count of the object, and so on.has_assoc
: Flag bit of the associated object, 0 does not exist, 1 exists.has_cxx_dtor
: Indicates whether the object hasC++
orObjc
If there is a destructor, it needs to do the destructor logic, if there is no, it can be faster to free the object.shiftcls
: Stores the value of the class pointer. Turn on pointer optimization in case ofarm64
In the architecture33
Bits are used to store class Pointers.magic
: used by the debugger to determine whether the current object is a real object or has no space to initialize.weakly_referenced
: indicates whether the object is or has been pointed to oneARC
Objects without weak references can be freed faster.deallocating
: indicates whether the object is freeing memory.has_sidetable_rc
: When the object reference technology is greater than10
, the variable needs to be borrowed to store carryextra_rc
When representing the referential count value of the object, it is actually the referential count value minus1
For example, if the object’s reference count is10
, thenextra_rc
为9
. If the reference count is greater than10
, you need to use the followinghas_sidetable_rc
.
Bit operations for ISA
throughISA
Bit operation to getshiftcls
. In order tox86_64
For example,shiftcls
in64
Position in bit structure: there are on the right3
Bits, on the left17
position His contains44
positionThe red box values are equal, indicating that the bitwise operation was successfulshiftcls
.
conclusion
- The underlying nature of an object is a structure.
ISA
Is determined by the mutually exclusive nature of the Commons (commonwealth)ISA
Is the pureISA
orNONPOINTER_ISA
And realize space saving by bit-field.