这个问题是对eliminate unused virtual functions的一种跟进,对我的兴趣不够深入。
问题:在定义具有虚函数的类时,编译器为虚函数表分配存储,并存储指向表中函数的指针。这会导致链接器保留这些函数的代码,无论它们是否被调用。这可能会导致大量死代码保留在可执行文件中,即使编译器优化设置要求消除死代码。
现在,如果在可执行文件中没有调用特定的虚函数(或者换句话说,访问虚函数表的相应插槽),则可以从虚函数中省略相应的函数指针表,链接器将删除函数的代码,可能进一步遗漏其他未被引用的代码。
显然,这不能由编译器完成,因为它只在链接时变得清晰,是否调用了特定的虚函数(假设静态链接 - 很明显它不能完成动态链接)。我对链接器不够熟悉,以便判断编译器是否可以以链接器可以选择性地忽略表中单个未使用的条目的方式发出虚函数表。
基本上,我的思路是这样的:虚函数表中的函数指针是对函数的引用,链接器使用该函数来确定函数的代码需要保留在可执行文件中。以类似的方式,虚函数调用是对从其虚函数被调用的类派生的所有虚函数表中的特定槽的引用。这种引用是否可以以这样一种方式传递给链接器:当零引用时它可以忽略虚函数表槽?
请注意,当编译器可以在编译时确定调用目标时,这与使用直接调用替换虚函数调用相同。我知道有些编译器可以做到这一点,但这是一个不同的情况,因为实际调用了函数,并且删除了虚函数调度的开销。就我而言,我希望删除所有未被调用的函数的代码。
如果我可以控制所有类定义,我可以手动删除所有不被调用的虚函数。但是使用库时这是不现实的。
这是否可以通过"链接时间优化来实现?#34;或"整个计划优化"?是否有成功的编译器?
答案 0 :(得分:2)
死代码的问题在于,从动态库的角度来看,编译器无法确定代码是否已死。可执行文件可以动态地包含使用死代码的库(从拥有死代码的类派生)。
除此之外,如果可执行文件是唯一进行函数调用的,则在链接时更改v表的结构可能会完全正常。但是,如果动态库进行任何调用,它将对v表有不同的理解,并且它将调用错误的函数。
由于这些事实,并且在表面上获得的表现并不多(如果有的话),优化链接器不太可能具有此功能。
虚拟功能的去虚拟化实际上与此相关,安全优化链接器只能对非常少量的函数调用进行去虚拟化。例如,如果它可以保证没有动态库可以在callstack中扮演任何角色,它只能对函数进行去虚拟化。
编辑 @curiousguy提出了一个案例,编译器可以通过优化更加自由,也就是说链接器可以知道没有外部代码知道该类。一个示例是具有文件范围的类。