当前位置: 首页 > news >正文

Any metadata 的内存布局

Swiftenumstructclassprotocol都有对应的metadata

metadata用来描述上述这些类型本身,这点和OC的元类有点类似。

1 直观感受 metadata

假设用下面代码定义了一个enum:

enum Direction {case topcase leftcase bottomcase right
}

经过编译链接之后,上面的enum Direction以及对应的metadata都写入到了对应的Mach-O文件中。

假设编译链接之后的Mach-O文件名为A,那么,使用下面命令就可以查看enum Direction以及对应metadata的位置:

nm -n A | xcrun swift-demangle | grep -i Direction

nm 命令读取Mach-O中的所有符号信息。

swift-demangle对已经mangleswift符号名进行demangle

输出的结果如下:

000000000001e004 s _symbolic _____ 7iOSTest9DirectionO
0000000000020820 s full type metadata for iOSTest.Direction
0000000000020830 S type metadata for iOSTest.Direction

1列的数字代表对应项在Mach-O文件中的偏移。

输出的第1行的符号名7iOSTest9DirectionO有点怪。

这是因为swift-demangle没有彻底demangle干净,我们再次手动demangle下:

xcrun swift-demangle s7iOSTest9DirectionO

注意我们在符号名字前加了一个小写字母s

Swift会在mangle名前加一个字母s,代表Swift

再次demangle的输出结果为:

$s7iOSTest9DirectionO ---> iOSTest.Direction

可以看到,它正是enum Direction本身,位于0x1e004

输出第3行可以看到enum Directionmetadata位于0x20830

输出的第2行还有一个full type metadata,这是什么呢?

Swift里,一个类型的metadata前面根据类型的不同,会有一些其他数据。

其中任何类型都有一个数据是value witness table指针。

value witness tableSwift用来管理类型的生命周期,比如怎么复制、怎么销毁。

metadata

可以看到,所谓的full type metadata就是「其他数据」+对应的type metadata

而我们平时使用的.self语法,得到的就是metadata本身:

(lldb) p unsafeBitCast(Direction.self, to: UnsafeRawPointer.self)
(UnsafeRawPointer) 0x100adc830
(lldb) p/x 0x100adc830 - 0x0000000100abc000
(Int) 0x0000000000020830

从上面lldb的输出看到,经过ASLR的调整,Direction.self的位置正是0x20830

2 Any 的 metadata

Any是一个protocol,如下面输出:

(lldb) p Any.self
(Any.Protocol) Any

Any还是一个空协议组合,表示「没有任何要求」。

而「没有任何要求」是任何类型都满足的,这也是任何类型都能转成Any的原因。

2.1 Any metadata 的定义

Anymetadata定义为:

/// stdlib/public/runtime/metadata.cpp
/// The standard metadata for Any.
const FullMetadata<ExistentialTypeMetadata> swift::
METADATA_SYM(ANY_MANGLING) = {{ &OpaqueExistentialValueWitnesses_0 }, // ValueWitnessesExistentialTypeMetadata(ExistentialTypeFlags() // Flags.withNumWitnessTables(0).withClassConstraint(ProtocolClassConstraint::Any).withHasSuperclass(false).withSpecialProtocol(SpecialProtocol::None)),
};

上面的定义准确的说,是Anyfull metadata

定义中的FullMetadata是一个C++结构体,定义为:

/// swift/ABI/metadata.htemplate <class T> struct FullMetadata : T::HeaderType, T {...
};

其中模版参数T = ExistentialTypeMetadata

我们手动代入后,FullMetadata的完整定义为:

struct FullMetadata : ExistentialTypeMetadata::HeaderType, ExistentialMetadata {...
};

从上面代码可以看到,FullMetadata是多重继承。

一部分继承自ExistentialTypeMetadata::HeaderType

一部分继承ExistentialTypeMetadata

要想弄清楚ExistentialTypeMetadata::HeaderType,首先得看下ExistentialTypeMetadata的定义:

/// stdlib/public/runtime/metadata.cppusing ExistentialTypeMetadata= TargetExistentialTypeMetadata<InProcess>;

从代码上可以看到,ExistentialTypeMetadata实际上是TargetExistentialTypeMetadata<InProcess>

接着看TargetExistentialTypeMetadata的定义:

/// swift/ABI/metadata.htemplate <typename Runtime>
struct TargetExistentialTypeMetadata: TargetMetadata<Runtime>,swift::ABI::TrailingObjects<TargetExistentialTypeMetadata<Runtime>,ConstTargetMetadataPointer<Runtime, TargetMetadata>,TargetProtocolDescriptorRef<Runtime>> {using HeaderType = TargetTypeMetadataHeaderBase<Runtime>;...public:using StoredPointer = typename Runtime::StoredPointer;/// The number of witness tables and class-constrained-ness of the type.ExistentialTypeFlags Flags;/// The number of protocols.uint32_t NumProtocols;...
};

从代码里可以看到,TargetExistentialTypeMetadata同样是多重继承。

一部分继承自TargetMetadata

一部分继承自swift::ABI::TrailingObjects

swift::ABI::TrailingObjects结构体没有任何实例变量,可以先不用关心。

swift::ABI::TrailingObjects的定义如下:

/// swift/ABI/TrailingObjects.hemplate <typename BaseTy, typename... TrailingTys>
class swift_ptrauth_struct_derived(BaseTy) TrailingObjects: private trailing_objects_internal::TrailingObjectsImpl<trailing_objects_internal::AlignmentCalcHelper<TrailingTys...>::Alignment,BaseTy, TrailingObjects<BaseTy, TrailingTys...>,BaseTy, TrailingTys...> {...
};

我们继续回到TargetExistentialTypeMetadata结构体上来。

TargetExistentialTypeMetadata内部定义了HeaderType:

using HeaderType = TargetTypeMetadataHeaderBase<Runtime>;

从定义上看,TargetExistentialTypeMetadata::HeaderType实际上是TargetTypeMetadataHeaderBase

呜~~~

现在,FullMetadata完整定义可以重写为:

struct FullMetadata : TargetTypeMetadataHeaderBase, TargetExistentialTypeMetadata {...
};

FullMetadata

2.2 内存布局

有了继承关系,就可以画出full metadata的内存布局。

内存布局

2.2.1 ValueWitness

ValueWitness就是value witness table指针,8字节。

2.2.2 Kind

Kind 是一个标识符,代表了当前是什么类型,8字节。

Kind的定义为:

/// swift/ABI/MetadataValues.henum class MetadataKind : uint32_t {
#define METADATAKIND(name, value) name = value,
#define ABSTRACTMETADATAKIND(name, start, end)                                 \name##_Start = start, name##_End = end,
#include "MetadataKind.def"LastEnumerated = 0x7FF,
};

注意看,这里的MetadataKind32bit的,而Kind本身是8字节的。

之所以这么设计,是因为如果一个class可以与OC交互,此时Kind要当成isa指针看待。

完整的Kind定义在文件MetadaKind.def中。

常见的Kind如下:

// 纯 Swift 类
class - 0x0
struct - 0x200
enum - 0x201
optional - 0x202
opaqual - 0x300
tuple - 0x301
existential - 0x303

2.2.3 Flags

Flags是一个C++类,定义如下:

/// swift/ABI/MetadataValues.hclass ExistentialTypeFlags {
public:typedef uint32_t int_type;private:enum : int_type {NumWitnessTablesMask  = 0x00FFFFFFU,ClassConstraintMask   = 0x80000000U, // Warning: Set if NOT class-constrained!HasSuperclassMask     = 0x40000000U,SpecialProtocolMask   = 0x3F000000U,SpecialProtocolShift  = 24U,};int_type Data;

它里面只有一个实例变量Data,占用4字节32bit

2.3.4 numOfProtocols

numOfProtocols占用4字节。

http://www.jsqmd.com/news/630898/

相关文章:

  • Tomcat配置支持软连接
  • DigitalOcean GPU 选型指南(四):中端AI GPU实战对比 RTX 4000 Ada、A4000、A5000 在出海业务中的表现
  • ZED深度图与点云数据转换指南:如何优化你的3D视觉项目性能
  • 别再被AI术语绕晕!超直白AI知识框架
  • FPGA实战:基于Verilog的BCD码动态扫描显示系统设计
  • 告别枯燥公式!用Matlab动画演示发动机功率与转矩的‘相爱相杀’关系
  • 大华摄像头FLV实时推流全攻略:SpringBoot+WebSocket+flv.js跨平台适配方案
  • ajshxhajzjhsx
  • 圆通批量快递查询软件哪家好?小递查查高效解决批量查件难题
  • ArcGIS Pro2.5深度学习环境配置终极指南:从零到实战
  • 【QML】自定义模块的创建与单例模式实践指南
  • 幻影峡谷工控机实战:FLIR BFS-PGE-16S2C-CS相机ROS驱动配置手记
  • 5分钟掌握QuickRecorder:开源免费的macOS专业录屏方案
  • 基于File-Based App开发MVP项目托
  • 终极Switch注入指南:3步搞定TegraRcmGUI完整教程
  • 告别垂直文字!手把手教你用QProxyStyle定制Qt侧边栏标签页(QTabWidget West位置实战)
  • **发散创新:基于Rust的轻量级权限管理库设计与开源许可证实践**在现代分布式系统中,**权限控制(RBAC
  • 、SEATA分布式事务——XA模式煞
  • SpringBoot+Activiti7+React构建低代码审批流:从零实现钉钉式流程设计器
  • Python 基础知识路线图:从零基础到实战
  • 技术判断力之AI三问垂
  • 告别云函数和自建域名:手把手教你用CDN和合法域名搭建CobaltStrike 4.9.1匿名基础设施
  • 分析管理化技术数据挖掘与预测分析
  • 手把手教你用Simulink搭建二极管钳位型三电平SVPWM闭环系统(附模型下载)
  • Oracle11g安装踩坑实录:手把手解决ORA-12638身份验证失败(附完整卸载指南)
  • 智能的边缘 哈萨比斯谈 AI、科学与人类未来PPT
  • AI开发-python-langchain框架(--langchain与milvus的结合 )在
  • 如何使用 LaTeX 写数学公式及机器学习中常用符号手册
  • 数模竞赛进阶指南:从O奖论文与代码中提炼MATLAB/Python实战策略
  • 传统CV算法——图像特征算法之斑点检测算法