分析 obj->initInstanceIsa(cls, hasCxxDtor);
if (!zone && fast) {
obj->initInstanceIsa(cls, hasCxxDtor);
} else {
// Use raw pointer isa on the assumption that they might be
// doing something weird with the zone or RR.
obj->initIsa(cls);
}
对象本质 struct
我们知道 OC 使用 clang 作为编译前端 参考⑦,这里我们可以直接看下编译产物。
- 在
xcode中构建是直接生成了.o文件。这里我们把main.m编译成c++文件 - 把目标文件编译成c++文件
clang -rewrite-objc main.m -o main.cpp
Clang 的主要工作:参考⑦
- 预处理: 比如把宏嵌入到对应的位置,头文件的导入,去除注释( clang -E main.m )
- 词法分析: 这里会把代码切成一个个 Token,比如大小括号,等于号还有字符串等
- 语法分析: 验证语法是否正确
- 生成 AST : 将所有节点组成抽象语法树 AST
- 静态分析:分析代码是否存在问题,给出错误信息和修复方案
- 生成 LLVM IR: CodeGen 会负责将语法树自顶向下遍历逐步翻译成 LLVM IR
所以这里我们可以直接搜索 我们所创建的类内容
这里我们就验证了,oc 对象是结构体
联合体位域 参考 ⑧ ⑨
-
联合体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的联合体,但是任何时候只能有一个成员带有值。联合体提供了一种使用相同的内存位置的有效方式。
-
联合体(union)中是各变量是“互斥”的
经源码查找我们查到 ISA 源码定义如下
static ALWAYS_INLINE id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
int construct_flags = OBJECT_CONSTRUCT_NONE,
bool cxxConstruct = true,
size_t *outAllocatedSize = nil)
{
ASSERT(cls->isRealized());
// Read class's info bits all at once for performance
bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();
bool hasCxxDtor = cls->hasCxxDtor();
bool fast = cls->canAllocNonpointer();
size_t size;
size = cls->instanceSize(extraBytes);
if (outAllocatedSize) *outAllocatedSize = size;
id obj;
if (zone) {
obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
} else {
obj = (id)calloc(1, size);
}
if (slowpath(!obj)) {
if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
return _objc_callBadAllocHandler(cls);
}
return nil;
}
if (!zone && fast) {
// 创建 -
obj->initInstanceIsa(cls, hasCxxDtor);
} else {
// Use raw pointer isa on the assumption that they might be
// doing something weird with the zone or RR.
obj->initIsa(cls);
}
if (fastpath(!hasCxxCtor)) {
return obj;
}
construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE;
return object_cxxConstructFromClass(obj, cls, construct_flags);
}
inline void
objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
{
ASSERT(!cls->instancesRequireRawIsa());
ASSERT(hasCxxDtor == cls->hasCxxDtor());
initIsa(cls, true, hasCxxDtor);
}
inline void
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor)
{
ASSERT(!isTaggedPointer());
if (!nonpointer) {
// 这里创建 ISA
isa = isa_t((uintptr_t)cls);
} else {
ASSERT(!DisableNonpointerIsa);
ASSERT(!cls->instancesRequireRawIsa());
isa_t newisa(0);
#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
newisa.has_cxx_dtor = hasCxxDtor;
newisa.shiftcls = (uintptr_t)cls >> 3;
#endif
// 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;
}
}
- 这里是 我们的
ISA定义isa 8字节 64 位参考② ③ ④ ⑤
union isa_t {
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
// uintptr_t
uintptr_t bits;
#if defined(ISA_BITFIELD)
// 这里是定义的结构体
struct {
// ISA_BITFIELD; // defined in isa.h
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
# define ISA_BITFIELD \
# 表示是否对 isa 指针开启指针优化 0:纯isa指针,1:不止是类对象地址,isa 中包含了类信息、对象的引用计数等
uintptr_t nonpointer : 1; \
# 关联对象标志位,0没有,1存在
uintptr_t has_assoc : 1; \
# 该对象是否有 C++ 或者 Objc 的析构器,如果有析构函数,则需要做析构逻辑, 如果没有,则可以更快的释放对象
uintptr_t has_cxx_dtor : 1; \
# 存储类指针的值。开启指针优化的情况下,在 arm64 架构中有 33 位用来存储类指针。
uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
# 用于调试器判断当前对象是真的对象还是没有初始化的空间
uintptr_t magic : 6; \
# 标志对象是否被指向或者曾经指向一个 ARC 的弱变量,没有弱引用的对象可以更快释放。
uintptr_t weakly_referenced : 1; \
# 标志对象是否正在释放内存
uintptr_t deallocating : 1; \
# 当对象引用技术大于 10 时,则需要借用该变量存储进位
uintptr_t has_sidetable_rc : 1; \
# 当表示该对象的引用计数值,实际上是引用计数值减 1, 例如,如果对象的引用计数为 10,那么 extra_rc 为 9。如果引用计数大于 10, 则需要使用到下面的 has_sidetable_rc。
uintptr_t extra_rc : 19
# define RC_ONE (1ULL<<45)
# define RC_HALF (1ULL<<18)
};
#endif
};
验证以上内容 => 源码分析
inline void
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor)
{
ASSERT(!isTaggedPointer());
if (!nonpointer) {
isa = isa_t((uintptr_t)cls);
} else {
ASSERT(!DisableNonpointerIsa);
ASSERT(!cls->instancesRequireRawIsa());
isa_t newisa(0);
#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
newisa.has_cxx_dtor = hasCxxDtor;
# 关联类信息
newisa.shiftcls = (uintptr_t)cls >> 3;
#endif
// 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;
}
}
关联类信息 newisa.shiftcls = (uintptr_t)cls >> 3;
- 掩码:如果要对一个整数中的某些位进行操作,怎样表示这些位在整数中的位置呢?可以用掩码(Mask)来表示。比如掩码0x0000ff00表示对一个32位整数的8~15位进行操作 参考
①
- 参考① 计算机中的进制&位运算 => 掩码 mask
- 参考② 细说计算机底层整型编码机制
- 参考 ③ 计算机编码 => 8位二进制表示1字节,2位十六进制表示一字节
- 参考 ④ 计算机是如何存储数据的? => 理解编码
- 参考 ⑤ 聊聊从逻辑门到操作系统的计算机 => 理解编码
- 参考 ⑥ 计算机组成原理
- 参考 ⑦ iOS 编译详解 LLVM Clang
- 参考 ⑧ 联合体
- 参考 ⑨ C 联合体