/// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() const {
return bits.data();
void setData(class_rw_t *newData) {
bits.setData(newData);
......
struct class_data_bits_t {
friend objc_class;
// Values are the FAST_ flags above.
uintptr_t bits;
private:
bool getBit(uintptr_t bit) const
return bits & bit;
// Atomically set the bits in `set` and clear the bits in `clear`.
// set and clear must not overlap.
void setAndClearBits(uintptr_t set, uintptr_t clear)
ASSERT((set & clear) == 0);
uintptr_t oldBits;
uintptr_t newBits;
oldBits = LoadExclusive(&bits);
newBits = (oldBits | set) & ~clear;
} while (!StoreReleaseExclusive(&bits, oldBits, newBits));
void setBits(uintptr_t set) {
__c11_atomic_fetch_or((_Atomic(uintptr_t) *)&bits, set, __ATOMIC_RELAXED);
void clearBits(uintptr_t clear) {
__c11_atomic_fetch_and((_Atomic(uintptr_t) *)&bits, ~clear, __ATOMIC_RELAXED);
public:
class_rw_t* data() const {
return (class_rw_t *)(bits & FAST_DATA_MASK);
void setData(class_rw_t *newData)
ASSERT(!data() || (newData->flags & (RW_REALIZING | RW_FUTURE)));
// Set during realization or construction only. No locking needed.
// Use a store-release fence because there may be concurrent
// readers of data and data's contents.
uintptr_t newBits = (bits & ~FAST_DATA_MASK) | (uintptr_t)newData;
atomic_thread_fence(memory_order_release);
bits = newBits;
// Get the class's ro data, even in the presence of concurrent realization.
// fixme this isn't really safe without a compiler barrier at least
// and probably a memory barrier when realizeClass changes the data field
const class_ro_t *safe_ro() {
class_rw_t *maybe_rw = data();
if (maybe_rw->flags & RW_REALIZED) {
// maybe_rw is rw
return maybe_rw->ro();
} else {
// maybe_rw is actually ro
return (class_ro_t *)maybe_rw;
void setClassArrayIndex(unsigned Idx) {
#if SUPPORT_INDEXED_ISA
// 0 is unused as then we can rely on zero-initialisation from calloc.
ASSERT(Idx > 0);
data()->index = Idx;
#endif
unsigned classArrayIndex() {
#if SUPPORT_INDEXED_ISA
return data()->index;
#else
return 0;
#endif
bool isAnySwift() {
return isSwiftStable() || isSwiftLegacy();
bool isSwiftStable() {
return getBit(FAST_IS_SWIFT_STABLE);
void setIsSwiftStable() {
setAndClearBits(FAST_IS_SWIFT_STABLE, FAST_IS_SWIFT_LEGACY);
bool isSwiftLegacy() {
return getBit(FAST_IS_SWIFT_LEGACY);
void setIsSwiftLegacy() {
setAndClearBits(FAST_IS_SWIFT_LEGACY, FAST_IS_SWIFT_STABLE);
// fixme remove this once the Swift runtime uses the stable bits
bool isSwiftStable_ButAllowLegacyForNow() {
return isAnySwift();
_objc_swiftMetadataInitializer swiftMetadataInitializer() {
// This function is called on un-realized classes without
// holding any locks.
// Beware of races with other realizers.
return safe_ro()->swiftMetadataInitializer();
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint16_t witness;
#if SUPPORT_INDEXED_ISA
uint16_t index;
#endif
explicit_atomic<uintptr_t> ro_or_rw_ext;
Class firstSubclass;
Class nextSiblingClass;
private:
using ro_or_rw_ext_t = objc::PointerUnion<const class_ro_t *, class_rw_ext_t *>;
const ro_or_rw_ext_t get_ro_or_rwe() const {
return ro_or_rw_ext_t{ro_or_rw_ext};
void set_ro_or_rwe(const class_ro_t *ro) {
ro_or_rw_ext_t{ro}.storeAt(ro_or_rw_ext, memory_order_relaxed);
void set_ro_or_rwe(class_rw_ext_t *rwe, const class_ro_t *ro) {
// the release barrier is so that the class_rw_ext_t::ro initialization
// is visible to lockless readers
rwe->ro = ro;
ro_or_rw_ext_t{rwe}.storeAt(ro_or_rw_ext, memory_order_release);
class_rw_ext_t *extAlloc(const class_ro_t *ro, bool deep = false);
public:
void setFlags(uint32_t set)
__c11_atomic_fetch_or((_Atomic(uint32_t) *)&flags, set, __ATOMIC_RELAXED);
void clearFlags(uint32_t clear)
__c11_atomic_fetch_and((_Atomic(uint32_t) *)&flags, ~clear, __ATOMIC_RELAXED);
// set and clear must not overlap
void changeFlags(uint32_t set, uint32_t clear)
ASSERT((set & clear) == 0);
uint32_t oldf, newf;
oldf = flags;
newf = (oldf | set) & ~clear;
} while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&flags));
class_rw_ext_t *ext() const {
return get_ro_or_rwe().dyn_cast<class_rw_ext_t *>();
class_rw_ext_t *extAllocIfNeeded() {
auto v = get_ro_or_rwe();
if (fastpath(v.is<class_rw_ext_t *>())) {
return v.get<class_rw_ext_t *>();
} else {
return extAlloc(v.get<const class_ro_t *>());
class_rw_ext_t *deepCopy(const class_ro_t *ro) {
return extAlloc(ro, true);
const class_ro_t *ro() const {
auto v = get_ro_or_rwe();
if (slowpath(v.is<class_rw_ext_t *>())) {
return v.get<class_rw_ext_t *>()->ro;
return v.get<const class_ro_t *>();
void set_ro(const class_ro_t *ro) {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
v.get<class_rw_ext_t *>()->ro = ro;
} else {
set_ro_or_rwe(ro);
const method_array_t methods() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>()->methods;
} else {
return method_array_t{v.get<const class_ro_t *>()->baseMethods()};
const property_array_t properties() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>()->properties;
} else {
return property_array_t{v.get<const class_ro_t *>()->baseProperties};
const protocol_array_t protocols() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>()->protocols;
} else {
return protocol_array_t{v.get<const class_ro_t *>()->baseProtocols};
struct class_rw_ext_t {
const class_ro_t *ro;
method_array_t methods;
property_array_t properties;
protocol_array_t protocols;
char *demangledName;
uint32_t version;
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name;
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
// This field exists only when RO_HAS_SWIFT_INITIALIZER is set.
_objc_swiftMetadataInitializer __ptrauth_objc_method_list_imp _swiftMetadataInitializer_NEVER_USE[0];
_objc_swiftMetadataInitializer swiftMetadataInitializer() const {
if (flags & RO_HAS_SWIFT_INITIALIZER) {
return _swiftMetadataInitializer_NEVER_USE[0];
} else {
return nil;
method_list_t *baseMethods() const {
return baseMethodList;
class_ro_t *duplicate() const {
if (flags & RO_HAS_SWIFT_INITIALIZER) {
size_t size = sizeof(*this) + sizeof(_swiftMetadataInitializer_NEVER_USE[0]);
class_ro_t *ro = (class_ro_t *)memdup(this, size);
ro->_swiftMetadataInitializer_NEVER_USE[0] = this->_swiftMetadataInitializer_NEVER_USE[0];
return ro;
} else {
size_t size = sizeof(*this);
class_ro_t *ro = (class_ro_t *)memdup(this, size);
return ro;
#import <Foundation/Foundation.h>
@interface LGPerson : NSObject {
int age;
@property (nonatomic, copy) NSString *name;
- (void)sayHi;
+ (void)sayHello;
@implementation LGPerson
- (void)sayHi {
+ (void)sayHello{
int main(int argc, const char * argv[]) {
@autoreleasepool {
// NSObject *objc1 = [NSObject alloc];
LGPerson *objc2 = [LGPerson alloc];
NSLog(@"Hello, World! %@",objc2);
return 0;
//控制台输出结果
//获取元类 元类的方法列表
(lldb) x/4gx LGPerson.class
0x1000081f0: 0x00000001000081c8 0x0000000100350140
0x100008200: 0x0000000100347430 0x0000802400000000
(lldb) po 0x00000001000081c8
LGPerson
(lldb) p 0x00000001000081c8
(long) $2 = 4295000520
(lldb) p (class_data_bits_t*)($2+32) //获取bits数据
(class_data_bits_t *) $3 = 0x00000001000081e8
(lldb) p (class_rw_t*) $3->data()
(class_rw_t *) $4 = 0x000000010067abf0
(lldb) p *$4
(class_rw_t) $5 = {
flags = 2684878849
witness = 1
ro_or_rw_ext = {
std::__1::atomic<unsigned long> = {
Value = 4295000120
firstSubclass = nil
nextSiblingClass = 0x00007fff850ffcd8
(lldb) p $5.ro_or_rw_ext
(explicit_atomic<unsigned long>) $6 = {
std::__1::atomic<unsigned long> = {
Value = 4295000120
(lldb) p $5.properties()
(const property_array_t) $7 = {
list_array_tt<property_t, property_list_t> = {
list = 0x0000000000000000
arrayAndFlag = 0
(lldb) p $7.list
(property_list_t *const) $8 = 0x0000000000000000
(lldb) p *$7
error: <user expression 9>:1:1: indirection requires pointer operand ('const property_array_t' invalid)
(lldb) p *$8
error: Couldn't apply expression side effects : Couldn't dematerialize a result variable: couldn't read its memory
(lldb) p $5.methods()
(const method_array_t) $11 = {
list_array_tt<method_t, method_list_t> = {
list = 0x0000000100008080
arrayAndFlag = 4295000192
(lldb) p $11.list
(method_list_t *const) $12 = 0x0000000100008080
(lldb) p *$12
(method_list_t) $13 = {
entsize_list_tt<method_t, method_list_t, 3> = {
entsizeAndFlags = 26
count = 1
first = {
name = "sayHello"
types = 0x0000000100003f4e "v16@0:8"
imp = 0x0000000100003d80 (KCObjc`+[LGPerson sayHello] at main.m:22)
(lldb) p $13.get(0)
(method_t) $14 = {
name = "sayHello"
types = 0x0000000100003f4e "v16@0:8"
imp = 0x0000000100003d80 (KCObjc`+[LGPerson sayHello] at main.m:22)
(lldb) p $13.get(1)
Assertion failed: (i < count), function get, file /Users/xiaokai/Desktop/逻辑IOS/Logic iOS 底层大师班2期班/20200909--大师班第3节课--OC对象原理(下)/20200909-大师班第3天-OC对象下-资料/01--课堂代码/可编译objc源码/runtime/objc-runtime-new.h, line 438.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
//获取类 类的属性列表 类的方法列表
(lldb) x/4gx objc2
0x100676d60: 0x001d8001000081f5 0x0000000000000000
0x100676d70: 0x0000000000000000 0x0000000000000000
(lldb) po 0x001d8001000081f5
8303516107964917
(lldb) p 0x001d8001000081f5
(long) $17 = 8303516107964917
(lldb) p 8303516107964917 & 0x00007ffffffffff8ULL
(unsigned long long) $18 = 4295000560
(lldb) p 4295000560
(long) $19 = 4295000560
(lldb) po 4295000560
LGPerson
(lldb) p (class_data_bits_t*)($19+32) //获取bits数据
(class_data_bits_t *) $21 = 0x0000000100008210
(lldb) p $21->data()
(class_rw_t *) $22 = 0x000000010067ac10
(lldb) p *$22
(class_rw_t) $23 = {
flags = 2148007936
witness = 0
ro_or_rw_ext = {
std::__1::atomic<unsigned long> = {
Value = 4295000224
firstSubclass = nil
nextSiblingClass = NSUUID
(lldb) p $23.properties()
(const property_array_t) $24 = {
list_array_tt<property_t, property_list_t> = {
list = 0x0000000100008198
arrayAndFlag = 4295000472
(lldb) p $24.list
(property_list_t *const) $25 = 0x0000000100008198
(lldb) p *$25
(property_list_t) $26 = {
entsize_list_tt<property_t, property_list_t, 0> = {
entsizeAndFlags = 16
count = 1
first = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
(lldb) p $26.get(0)
(property_t) $27 = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
(lldb) p $26.get(1)
Assertion failed: (i < count), function get, file /Users/xiaokai/Desktop/逻辑IOS/Logic iOS 底层大师班2期班/20200909--大师班第3节课--OC对象原理(下)/20200909-大师班第3天-OC对象下-资料/01--课堂代码/可编译objc源码/runtime/objc-runtime-new.h, line 438.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
(lldb) p $23.methods()
(const method_array_t) $28 = {
list_array_tt<method_t, method_list_t> = {
list = 0x00000001000080e8
arrayAndFlag = 4295000296
(lldb) p $28.list
(method_list_t *const) $29 = 0x00000001000080e8
(lldb) p *$29
(method_list_t) $30 = {
entsize_list_tt<method_t, method_list_t, 3> = {
entsizeAndFlags = 26
count = 4
first = {
name = "sayHi"
types = 0x0000000100003f4e "v16@0:8"
imp = 0x0000000100003d90 (KCObjc`-[LGPerson sayHi] at main.m:19)
(lldb) p $30.get(0)
(method_t) $31 = {
name = "sayHi"
types = 0x0000000100003f4e "v16@0:8"
imp = 0x0000000100003d90 (KCObjc`-[LGPerson sayHi] at main.m:19)
(lldb) p $30.get(1)
(method_t) $32 = {
name = ".cxx_destruct"
types = 0x0000000100003f4e "v16@0:8"
imp = 0x0000000100003e00 (KCObjc`-[LGPerson .cxx_destruct] at main.m:18)
(lldb) p $30.get(2)
(method_t) $33 = {
name = "name"
types = 0x0000000100003f64 "@16@0:8"
imp = 0x0000000100003da0 (KCObjc`-[LGPerson name] at main.m:13)
(lldb) p $30.get(3)
(method_t) $34 = {
name = "setName:"
types = 0x0000000100003f6c "v24@0:8@16"
imp = 0x0000000100003dd0 (KCObjc`-[LGPerson setName:] at main.m:13)
(lldb) p $30.get(4)
Assertion failed: (i < count), function get, file /Users/xiaokai/Desktop/逻辑IOS/Logic iOS 底层大师班2期班/20200909--大师班第3节课--OC对象原理(下)/20200909-大师班第3天-OC对象下-资料/01--课堂代码/可编译objc源码/runtime/objc-runtime-new.h, line 438.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
//获取类 类的成员列表
(lldb) x/4gx objc2
0x101105420: 0x001d8001000081f5 0x0000000000000000
0x101105430: 0x0000000000000000 0x0000000000000000
(lldb) p 0x001d8001000081f5
(long) $1 = 8303516107964917
(lldb) p 0x001d8001000081f5 & 0x00007ffffffffff8ULL
(unsigned long long) $2 = 4295000560
(lldb) p (class_data_bits_t *)($2+32) //获取bits
(class_data_bits_t *) $3 = 0x0000000100008210
(lldb) p $3->data()
(class_rw_t *) $4 = 0x0000000101105830
(lldb) p *$4
(class_rw_t) $5 = {
flags = 2148007936
witness = 0
ro_or_rw_ext = {
std::__1::atomic<unsigned long> = {
Value = 4295000224
firstSubclass = nil
nextSiblingClass = NSUUID
(lldb) p $5.ro
(const class_ro_t *) $6 = 0x00000001000080a0
Fix-it applied, fixed expression was:
$5.ro()
(lldb) p $5.ro()
(const class_ro_t *) $7 = 0x00000001000080a0
(lldb) p *$7
(const class_ro_t) $8 = {
flags = 388
instanceStart = 8
instanceSize = 24
reserved = 0
ivarLayout = 0x0000000100003f17 "\x11"
name = 0x0000000100003f0e "LGPerson"
baseMethodList = 0x00000001000080e8
baseProtocols = 0x0000000000000000
ivars = 0x0000000100008150
weakIvarLayout = 0x0000000000000000
baseProperties = 0x0000000100008198
_swiftMetadataInitializer_NEVER_USE = {}
(lldb) p $8.ivars
(const ivar_list_t *const) $9 = 0x0000000100008150
(lldb) p *$9
(const ivar_list_t) $10 = {
entsize_list_tt<ivar_t, ivar_list_t, 0> = {
entsizeAndFlags = 32
count = 2
first = {
offset = 0x00000001000081b8
name = 0x0000000100003f22 "age"
type = 0x0000000100003f56 "i"
alignment_raw = 2
size = 4
(lldb) p $10.get(0)
(ivar_t) $11 = {
offset = 0x00000001000081b8
name = 0x0000000100003f22 "age"
type = 0x0000000100003f56 "i"
alignment_raw = 2
size = 4
(lldb) p $10.get(1)
(ivar_t) $12 = {
offset = 0x00000001000081c0
name = 0x0000000100003f26 "_name"
type = 0x0000000100003f58 "@\"NSString\""
alignment_raw = 3
size = 8