ARM C ++ ABI:构造函数/析构函数返回值

时间:2013-03-16 17:08:40

标签: c++ arm abi

我一直在阅读Clang源代码并发现了一些关于ARM C ++ ABI的有趣内容,我似乎无法理解其中的理由。来自ARM ABI documentation的在线版本:

  

这个ABI要求C1和C2构造函数返回 this (而不是void函数),以便C3构造函数   可以尾调用C1构造函数,C1构造函数可以尾调用C2。

(对于非虚拟析构函数也类似)

我不确定C1C2C3在这里引用了什么......这一部分是对通用的§3.1.5的修改(即Itanium)ABI,但该部分(至少在this online verison中)只是声明:

  

构造函数返回 void 结果。

无论如何,我真的无法弄清楚这是什么目的:如何使构造函数返回这个允许尾调用优化,以及在什么情况下?

据我所知,构造函数可以尾部调用具有相同this返回值的另一个的唯一时间是具有单个基类的派生类,一个简单的构造函数体,没有成员的情况非平凡的构造函数,没有虚拟表指针。实际上,使用void返回来优化尾部调用似乎实际上更容易,而不是更难,因为这样可以消除单个基类的限制(在多基类的情况下,从最后一个被调用的构造函数返回的this指针不是派生对象的this指针。)

我在这里缺少什么? ARM调用约定是否有必要使this返回?

1 个答案:

答案 0 :(得分:9)

好的,来自@Michael的有用链接使这一切清楚...... C1C2C3引用了“完整对象构造函数”的名称修改,“基础对象构造函数“和”完整对象分配构造函数“,分别来自Itanium ABI:

  <ctor-dtor-name> ::= C1   # complete object constructor
                   ::= C2   # base object constructor
                   ::= C3   # complete object allocating constructor
                   ::= D0   # deleting destructor
                   ::= D1   # complete object destructor
                   ::= D2   # base object destructor

C3 /“完整对象分配构造函数”是构造函数的一个版本,它不是在通过this参数传递给它的已经分配的存储上运行,而是在内部分配内存(通过{{ 1}})然后调用operator new /“完整对象构造函数”,这是用于完整对象案例的常规构造函数。由于C1构造函数必须将C3指针返回到新分配和构造的对象,因此this构造函数还必须返回C1指针,以便尾部调用为使用

this /“基础对象构造函数”是构造基类子对象时由派生类调用的构造函数; C2C1构造函数的语义在C2继承的情况下有所不同,并且为了优化目的也可以以不同方式实现。在virtual继承的情况下,可以通过调用virtual基类构造函数,然后对C1构造函数进行尾调用来实现virtual构造函数,因此后者应该如果是前者,也会返回C2

析构函数情况略有不同但相关。根据ARM ABI:

  

同样,我们要求D2和D1返回此值,以便D0不需要保存和恢复,D1可以尾调用D2(如果没有虚拟碱基)。 D0仍然是一个无效函数。

删除对象时使用this /“删除析构函数”,它调用D0 /“完整对象析构函数”并使用D1指针调用operator delete之后释放记忆。让this析构函数返回D1允许this析构函数使用其返回值来调用D0,而不必将其保存到另一个寄存器或将其溢出到内存中;同样,operator delete /“基础对象析构函数”也应该返回D2

ARM ABI还补充说:

  

我们不需要thunks到虚拟析构函数来返回 this 。这样的thunk必须调整析构函数   结果,阻止它尾部调用析构函数,并使任何可能的保存无效。

     

因此,只能依赖D1和D2析构函数的非虚拟调用来返回 this

如果我理解正确,则表示只有在this静态调用D0时才会使用此保存 - 恢复 - 省略优化(即非D1的情况析)。