Виртуальные функции C ++: может ли компоновщик удалить записи в таблице виртуальных функций, которые не были вызваны?

Этот вопрос является своего рода продолжением устранить неиспользуемые виртуальные функции, что не достаточно глубоко для моего интереса.

Проблема: при определении классов, имеющих виртуальные функции, компилятор выделяет хранилище для таблицы виртуальных функций и сохраняет указатели на функции в таблице. Это заставляет компоновщик сохранять код этих функций независимо от того, вызывались ли они когда-либо. Это может привести к тому, что в исполняемом файле останется много мертвого кода, даже если настройки оптимизации компилятора требуют устранения мертвого кода.

Теперь, если нигде в исполняемом файле нет вызова определенной виртуальной функции (или, другими словами, доступа к соответствующему слоту таблицы виртуальных функций), соответствующий указатель функции может быть опущен из таблицы виртуальных функций, и компоновщик удалит код функции с возможными дальнейшими пропусками другого кода, на который не будет ссылаться.

Очевидно, что это не может быть сделано компилятором, поскольку во время компоновки становится ясно только, вызывается ли конкретная виртуальная функция (при условии статического связывания — ясно, что это невозможно сделать с помощью динамического связывания). Я недостаточно знаком с компоновщиками, чтобы сказать, может ли компилятор создавать таблицы виртуальных функций таким образом, чтобы компоновщик мог выборочно исключать отдельные неиспользуемые записи в таблице.

По сути, мой ход мысли таков: указатель на функцию в таблице виртуальных функций — это ссылка на функцию, которую компоновщик использует для определения необходимости сохранения кода функции в исполняемом файле. Аналогичным образом, вызов виртуальной функции — это ссылка на определенный слот во всех таблицах виртуальных функций, которые происходят от класса, виртуальная функция которого вызывается. Может ли такой тип ссылки быть передан компоновщику таким образом, чтобы он мог исключить виртуальный слот таблицы функций, когда на него нет нулевых ссылок?

Обратите внимание, что это не то же самое, что замена вызова виртуальной функции прямым вызовом, когда компилятор может определить цель вызова во время компиляции. Я знаю, что некоторые компиляторы могут сделать это, но это другой случай, потому что функция на самом деле вызывается, и это накладные расходы на удаление виртуальных функций. В моем случае я хочу, чтобы весь код был удален для функций, которые не вызываются.

Если бы у меня был контроль над всеми определениями классов, я мог бы вручную удалить все виртуальные функции, которые не были вызваны. Но это нереально при использовании библиотек.

Это можно сделать с помощью «оптимизации времени соединения» или «оптимизации всей программы»? Есть ли компиляторы, которые успешно это делают?

10

Решение

Проблема с мертвым кодом заключается в том, что компилятор не может быть уверен, что код мертв с точки зрения динамических библиотек. Исполняемый файл может динамически включать библиотеку, которая использует мертвый код (происходит от классов, владеющих мертвым кодом).

Кроме того, изменение структуры v-таблицы во время компоновки может прекрасно работать, если только исполняемый файл выполняет вызовы функций. Однако, если динамическая библиотека делает какие-либо вызовы, она будет по-разному понимать v-таблицу и будет вызывать неправильную функцию.

Из-за этих фактов и из-за незначительной производительности (если таковая имеется) производительность оптимизирующих компоновщиков весьма маловероятна.

Де-виртуализация виртуальных функций на самом деле связана с этим, и безопасные оптимизирующие компоновщики могут де-виртуализировать только очень небольшое количество вызовов функций. Например, он может де-виртуализировать функцию, только если он может гарантировать, что никакая динамическая библиотека не может играть какую-либо роль в стеке вызовов.

редактировать @curiousguy привел случай, когда компилятор может быть немного более либеральным с оптимизацией, и именно тогда компоновщик может знать, что никакой внешний код не знает о классе. Примером этого является класс с областью файла.

2

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


По вопросам рекламы [email protected]