ARM C++ ABI:构造函数/析构函数返回值 [英] ARM C++ ABI: Constructor/destructor return values

查看:34
本文介绍了ARM C++ ABI:构造函数/析构函数返回值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在阅读 Clang 源代码,并发现了一些关于 ARM C++ ABI 的有趣之处,我似乎无法理解其理由.来自 ARM ABI 文档:

I've been reading through Clang source code and discovered something interesting about the ARM C++ ABI that I can't seem to understand the justification for. From the an online version of the ARM ABI documentation:

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

This ABI requires C1 and C2 constructors to return this (instead of being void functions) so that a C3 constructor can tail call the C1 constructor and the C1 constructor can tail call C2.

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

(and similarly for non-virtual destructors)

我不确定这里的 C1C2C3 引用了什么...本节旨在修改来自通用(即安腾)ABI 的 §3.1.5,但该部分(至少在 此在线版本) 简单地说:

I'm not sure what C1, C2, and C3 reference here...this section is meant to be a modification of §3.1.5 from the generic (i.e. Itanium) ABI, but that section (at least in this online verison) simply states:

构造函数返回 void 结果.

Constructors return void results.

无论如何,我真的想不通这样做的目的是什么:让构造函数返回this如何允许尾调用优化,在什么情况下?

Anyway, I really can't figure out what the purpose of this is: how does making a constructor return this allow tail call optimization, and in what circumstances?

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

As far I can tell, the only time a constructor could tail call another with the same this return value would be the case of a derived class with a single base class, a trivial constructor body, no members with non-trivial constructors, and no virtual table pointer. In fact, it seems like it would actually be easier, not harder, to optimize with a tail call with a void return, because then the restriction of a single base class could be eliminated (in the multiple base class case, the this pointer returned from the last called constructor will not be the this pointer of the derived object).

我在这里错过了什么?有什么关于 ARM 调用约定的东西使得 this 返回是必要的?

What am I missing here? Is there something about the ARM calling convention that makes the this return necessary?

推荐答案

好的,@Michael 提供的有用链接让这一切变得清晰......C1C2C3 分别指的是来自 Itanium ABI 的完整对象构造函数"、基础对象构造函数"和完整对象分配构造函数"的名称修改:

Ok, helpful link from @Michael made this all clear...C1, C2, and C3 refer to the name-mangling of the "complete object constructor", "base object constructor", and "complete object allocating constructor", respectively, from the 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 参数传递给它的已分配存储进行操作,而是分配内存内部(通过operator new),然后调用C1/完整对象构造函数",这是用于完整对象情况的普通构造函数.由于 C3 构造函数必须返回指向新分配和构造对象的 this 指针,C1 构造函数也必须返回 this 指针,以便使用尾调用.

The C3/"complete object allocating constructor" is a version of the constructor that, rather than operating on already allocated storage passed to it via the this parameter, allocates memory internally (via operator new) and then calls the C1/"complete object constructor", which is the normal constructor used for the complete object case. Since the C3 constructor must return the this pointer to the newly allocated and constructed object, the C1 constructor must also return the this pointer in order for a tail call to be used.

C2/基对象构造函数"是派生类在构造基类子对象时调用的构造函数;C1C2 构造函数的语义在 virtual 继承的情况下有所不同,并且为了优化目的也可以不同地实现.在 virtual 继承的情况下,C1 构造函数可以通过调用 virtual 基类构造函数和对 的尾调用来实现>C2 构造函数,所以如果前者返回,后者也应该返回 this.

The C2/"base object constructor" is the constructor called by derived classes when constructing a base class subobject; the semantics of C1 and C2 constructors differ in case of virtual inheritance and could be implemented differently for optimization purposes as well. In the case of virtual inheritance, a C1 constructor could be implemented with calls to virtual base class constructors followed by a tail call to a C2 constructor, so the latter should also return this if the former does.

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

The destructor case is slightly different but related. As per the ARM ABI:

同样,我们要求 D2 和 D1 返回 this,这样 D0 就不需要保存和恢复 this 并且 D1 可以尾调用 D2(如果没有虚拟碱基).D0 仍然是一个空函数.

Similarly, we require D2 and D1 to return this so that D0 need not save and restore this and D1 can tail call D2 (if there are no virtual bases). D0 is still a void function.

D0/deleting destructor"用于删除对象时,调用D1/完整对象析构函数",调用operator delete 之后使用 this 指针来释放内存.让 D1 析构函数返回 this 允许 D0 析构函数使用它的返回值来调用 operator delete,而不是必须将其保存到另一个寄存器或将其溢出到内存中;类似地,D2/基础对象析构函数"也应该返回this.

The D0/"deleting destructor" is used when deleting an object, it calls the D1/"complete object destructor" and calls operator delete with the this pointer afterwards to free the memory. Having the D1 destructor return this allows the D0 destructor to use its return value to call operator delete, rather than having to save it to another register or spill it to memory; similarly, the D2/"base object destructor" should return this as well.

ARM ABI 还添加了:

The ARM ABI also adds:

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

We do not require thunks to virtual destructors to return this. Such a thunk would have to adjust the destructor’s result, preventing it from tail calling the destructor, and nullifying any possible saving.

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

Consequently, only non-virtual calls of D1 and D2 destructors can be relied on to return this.

如果我理解正确,这意味着只有在 D0 静态调用 D1 时(即在非-virtual 析构函数).

If I understand this correctly, it means that this save-restore-elision optimization can only be used when D0 calls D1 statically (i.e. in the case of a non-virtual destructor).

这篇关于ARM C++ ABI:构造函数/析构函数返回值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆