Перейти к содержанию
Автор: LUMD

Swift заменил C‑интерпретатор TrueType‑хинтинга: безопаснее и быстрее

Apple переписал интерпретатор хинтинга TrueType‑шрифтов с C на Swift, добившись 13 % прироста скорости и полной памяти‑безопасности.

Apple объявила о завершении миграции интерпретатора хинтинга TrueType‑шрифтов с C на Swift, запланированной к выпуску в осеннем обновлении 2025 года. Переписанный модуль стал полностью memory‑safe и в среднем работает на 13 % быстрее, чем его предшественник.

Почему потребовалась переписка?

TrueType‑шрифты используют байткод‑интерпретатор, который обрабатывает данные из потенциально недоверенных источников. Ошибки в управлении памятью в таком коде легко превращаются в уязвимости. Перенос на Swift позволил избавиться от классических проблем с указателями и переполнениями, сохранив при этом совместимость с существующим API.

Как обеспечивалась совместимость?

Была поставлена задача достичь пиксель‑идентичного рендеринга, как у C‑версии. Для этого разработчики создали два набора тестов: единичные тесты, покрывающие 99,7 % кода, и масштабный фузз‑тест, в котором из 10 млн PDF‑файлов отобрали 4 200, содержащие 25 572 шрифта и 27 млн глифов. Рендеринг всех глифов сравнивался с результатом референс‑интерпретатора.

Какие оптимизации дали прирост скорости?

  1. Отказ от копируемых типов – вместо классов использованы ~Copyable value‑типы, что устранило накладные расходы ARC и проверок эксклюзивности.
  2. Span – структура из Swift 6.2, позволяющая работать с последовательностями без копирования, применена к массивам точек глифа.
  3. Проекции вместо копий – вместо копирования данных из C‑структуры в Swift был введён «projection type», дающий безопасный доступ к оригинальному блоку памяти.
  4. Ленивая обработка – заменены map/filter на прямые циклы с continue и локальными переменными, что убрало лишние аллокации.
  5. Оптимизированный стек – вместо возврата массива при pop использован continuation‑passing, позволяющий работать с Span‑срезом без выделения памяти.

Что изменилось в кодовой базе?

Интерпретатор теперь реализован как @objc‑класс, вызываемый из Objective‑C++, но внутренние структуры объявлены как non‑copyable. Абстракции через протоколы и дженерики сохраняют читаемость без потери производительности, так как компилятор успешно их инлайнит.

Как проверяли производительность?

Сравнительные измерения проводились на уровне рендеринга PDF‑документов и на уровне микросекундных затрат CPU на один глиф. Диаграмма в оригинальном посте показывает, что для системных шрифтов Swift‑интерпретатор consistently быстрее, а для некоторых сторонних шрифтов C‑версия всё ещё выигрывает в отдельных случаях.

Что это значит для бизнеса?

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