ARM C ++ ABI: возвращаемые значения конструктора / деструктора

Я читал исходный код Clang и обнаружил кое-что интересное в ARM C ++ ABI, для которого я не могу понять оправдание. Из онлайн-версии ARM ABI документация:

Этот ABI требует конструкторов C1 и C2 для возврата этот (вместо того, чтобы быть пустыми функциями), так что конструктор C3
может завершить вызов конструктора C1, а конструктор C1 может вызвать вызов C2.

(и аналогично для не виртуальных деструкторов)

Я не уверен что C1, C2, а также C3 ссылка здесь … этот раздел предназначен для модификации §3.1.5 от общего (т.е. Itanium) ABI, но этот раздел (по крайней мере, в это онлайн версия) просто заявляет:

Конструкторы возвращают недействительным Результаты.

Во всяком случае, я действительно не могу понять, какова цель этого: как сделать возвращение конструктора этот разрешить оптимизацию хвостового вызова и при каких обстоятельствах?

Насколько я могу судить, единственный раз, когда конструктор мог вызвать другого с тем же this Возвращаемое значение будет иметь место для производного класса с одним базовым классом, тривиальным телом конструктора, без членов с нетривиальными конструкторами и без указателя виртуальной таблицы. На самом деле, кажется, что на самом деле было бы проще, а не сложнее, оптимизировать с помощью хвостового вызова с void возврат, потому что тогда ограничение одного базового класса может быть устранено (в случае нескольких базовых классов, this указатель, возвращаемый из последнего вызванного конструктора, не будет this указатель производного объекта).

Что мне здесь не хватает? Есть ли что-то в соглашении о вызовах ARM, которое делает this вернуть надо?

15

Решение

Хорошо, полезная ссылка от @Michael прояснила все это …C1, C2, а также C3 обратитесь к именованию «полного конструктора объекта», «конструктора базового объекта» и «конструктора выделения полного объекта», соответственно, из ABI Itanium:

  <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 указатель для того, чтобы использовать хвостовой вызов.

C2/ «конструктор базового объекта» — это конструктор, вызываемый производными классами при создании подобъекта базового класса; семантика C1 а также C2 конструкторы различаются в случае virtual наследование и может быть реализован по-разному в целях оптимизации. В случае virtual наследство, а C1 конструктор может быть реализован с вызовами virtual конструкторы базового класса, за которыми следует хвостовой вызов C2 конструктор, поэтому последний также должен вернуть this если первый делает.

Случай деструктора немного другой, но связанный. Согласно ARM ABI:

Точно так же мы требуем, чтобы D2 и D1 возвращали это, так что D0 не нужно сохранять и восстанавливать этот и D1 может завершить вызов D2 (если нет виртуальных баз). D0 по-прежнему является пустой функцией.

D0/ «удаление деструктора» используется при удалении объекта, вызывает D1/ «полный деструктор объекта» и вызовы operator delete с this указатель впоследствии, чтобы освободить память. Имея D1 возвращение деструктора this позволяет D0 деструктор, чтобы использовать его возвращаемое значение для вызова operator deleteвместо того, чтобы сохранять его в другом регистре или помещать в память; аналогично D2/ «деструктор базового объекта» должен вернуть this также.

ARM ABI также добавляет:

Мы не требуем, чтобы виртуальные деструкторы возвращали громкие слова этот. Такой гром должен был бы приспособить деструктора
результат, предотвращая его от вызова вызывающего деструктора, и сводя на нет любое возможное сохранение.

Следовательно, для возврата можно использовать только не виртуальные вызовы деструкторов D1 и D2. этот.

Если я правильно понимаю, это означает, что эта оптимизация save-restore-elision может использоваться только тогда, когда D0 звонки D1 статически (т.е. в случае неvirtual деструктор).

9

Другие решения

Других решений пока нет …