[英]How does C++ exception handling translate to machine code
异常处理程序的糟糕实现在进入 try 子句时为每个 try 子句在运行时堆栈上推送某种异常处理程序块,并在退出 try 子句时将其弹出。 还维护保存最近推送的异常处理程序块的地址的位置。 通常,这些异常处理程序链接在一起,因此可以通过从最新版本到旧版本的链接找到它们。 发生异常时,会找到指向最后推送的 EH 处理程序块的指针,并检查对该“try”子句的 EH 情况的处理。 击中 EH 情况会导致堆栈清理发生回到推送 EH 的点,并且控制转移到 EH 情况。 没有命中 EH 会导致找到下一个 EH,并重复该过程。 Windows 32 位 SEH 方案是此方案的一个版本。
这是一个糟糕的实现,因为即使没有发生异常,程序也会为每个 try 子句(push then pop)付出运行时代价。
好的实现只是简单地记录一个范围表,其中出现了 try 子句。 这意味着进入/退出 try 子句的开销为零。 (我的PARLANSE并行编程语言使用这种技术)。 异常在表中查找异常点的PC,将控制权交给表选择的EH。 EH 代码根据需要重置堆栈。 又快又漂亮。 我认为Windows 64位EH是这种类型,但我没有仔细看。
[编辑 2020 年 4 月:最近刚刚测量了 PARLANSE 异常的成本。 如果没有例外,则为 0nS(按设计); 25ns 在 3Ghz i7 上从“抛出”到“捕捉”到“确认”(结束空捕捉)。 OP 为最简单的类型添加了一个大约 1000ns 的测量 C++ 异常处理的链接,以及一个真正的非标准处理方案,在 57ns 处记录异常或无异常; C++ 版本的 CPU 时钟速率稍慢,因此这些数字仅用于粗略比较。]
这是一篇关于该主题的非常有价值的文章: C ++编译器如何实现异常处理
微软期刊的“Under the Hood”系列在1997年对这个主题进行了深入研究:
C++ 标准委员会发布了一份关于“C++ 性能”的技术报告,以揭穿许多关于 C++ 特性如何减慢你的神话。 这还包括有关如何实现异常处理的详细信息。 本技术报告草稿可免费获取。 检查第 5.4.1 节。 “异常处理实施问题和技术”。
来自Godbolt 编译器资源管理器的Asm ,用于 x86-64 System V 调用约定,使用 g++8.2 的 C++ABI,用于捕获函数和抛出函数。
x86-64 System V 将.eh_frame
部分用于堆栈展开元数据,因此异常帮助程序库函数知道如何遍历堆栈并恢复寄存器。 这就是.cfi
指令所做的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.