Apple, TrueType 힌팅 인터프리터를 Swift로 재작성
Swift at Apple: Migrating the TrueType Hinting Interpreter
핵심 요약
- Apple은 신뢰할 수 없는 폰트 입력을 처리하는 TrueType 힌팅 인터프리터를 C에서 메모리 안전한 Swift로 옮기고, C 구현과 픽셀 단위로 같은 렌더링 결과를 유지했다.
- Swift 구현은 평균적으로 기존 C 구현보다 13% 빠르며, 단위 테스트에서 두 구현 모두 99.7% 코드 커버리지를 달성하고 대규모 PDF 코퍼스로 렌더링 호환성을 확인했다.
- 성능 개선에는 비복사 타입과 Span 사용, C 구조체를 복사하지 않는 projection type, 불필요한 할당 제거, 제네릭 특수화와 인라이닝이 활용됐다.
도입
TrueType 폰트에는 글리프를 저해상도 화면에 맞게 조정하는 힌팅 프로그램이 포함될 수 있다. 이 프로그램을 실행하는 인터프리터는 인터넷 등에서 온 신뢰할 수 없는 폰트 데이터를 처리하므로 보안상 중요한 코드다. Apple은 기존 동작과 렌더링 결과를 유지하면서 메모리 안전성을 확보하기 위해 C 구현을 Swift로 재작성했고, 최종적으로 평균 실행 속도도 13% 높였다.
상세 요약
이식 목표와 호환성 기준
TrueType 힌팅 인터프리터는 폰트에 포함된 바이트코드 프로그램을 실행한다. 입력에 따라 제어 흐름이 달라지고 복잡한 자료 구조와 메모리 관리가 필요해, 메모리 오류가 발생하기 쉬운 코드다. PDF와 웹 페이지에 TrueType 폰트가 포함되면서 인터프리터는 신뢰할 수 없는 입력에도 노출됐다.
Apple은 2025년 가을 릴리스를 위해 C 구현을 Swift로 재작성했다. 목표는 메모리 안전성, C 구현과 동일한 관찰 가능한 렌더링 결과, 사용자에게 드러나는 성능 저하 방지였다. 여기서 정확성은 인터페이스 호환성만이 아니라 글리프 비트맵이 픽셀 단위로 일치하는 것을 뜻했다.
테스트로 렌더링 동등성 검증
두 구현을 모두 대상으로 하는 단위 테스트는 각각 99.7% 코드 커버리지를 달성했다. 실제 문서의 입력 특성을 반영하기 위해 1,000만 개 PDF 파일을 퍼징으로 축소해 코드 커버리지를 유지하는 4,200개 코퍼스를 만들었다. 코퍼스에는 폰트 25,572개와 글리프 2,700만 개가 포함됐다. 각 글리프를 네 가지 변환으로 렌더링하고 결과 비트맵을 기준 인터프리터와 비교했다. 테스트 코드의 분량은 Swift 인터프리터 코드의 거의 네 배였다.
성능 최적화
최적화는 PDF 렌더링 시간과 세 가지 폰트의 글리프 렌더링 벤치마크를 기준으로 진행했다.
- 비복사 타입과 Span: 참조 타입의 ARC 비용과 런타임 exclusivity 검사 비용을 줄이기 위해 아키텍처 전반에서
~Copyable값 타입을 사용하고, 참조 타입은 상위 수준 추상화에 한정했다. Swift 6.2의Span으로 이런 타입의 시퀀스를 효율적으로 다뤘다. Span은 macOS 10.14.4와 iOS 12.2까지 back-deployment를 지원한다. - C 구조체에 대한 projection type: C 구현은 글리프 점 데이터를 여덟 개 배열로 저장했다. Swift에서는 점 단위로 다루는 편이 읽기 쉬웠지만, 초기 브리징 방식은 데이터를 Swift로 복사했다가 다시 C로 옮겨야 했고 실행 시간의 약 20%를 차지했다. 이후 projection type을 사용해 원본 C 구조체에 안전하게 접근하면서 불필요한 복사를 없앴다. 경계 검사와 수명 안전성도 이 타입이 담당한다.
- 불필요한 할당 제거:
filter와map결과를 저장할 필요가 없는 경우 반복문에서 직접 처리했다. 스택에서 요소를 꺼내 반환하는 작업은 호출자가 전달한 클로저가Span을 사용하는 continuation-passing 방식으로 바꿨다. 컴파일 타임 exclusivity 검사가 클로저 안에서 스택을 수정하지 못하게 하며, 요소 복사와 힙 할당을 없앤다. - 동적 디스패치 비용 억제: 추상화를 불필요하게 일반화하지 않고 인라이닝을 유도했다. 이를 통해 최적화기가 경계 검사를 끌어올리고 제네릭 문맥을 특수화할 수 있었다.
결과와 공개 범위
Swift 인터프리터는 기존 C 구현보다 평균 13% 빠르게 실행됐다. 새 구현은 내부 상태에 비복사 구조체를 사용하지만, 최상위 타입은 Objective-C++ 모듈 경계에서 호출되는 @objc 클래스다. Apple은 핫 패스는 빠르게 유지하고 콜드 패스는 편리한 형태로 남겼다고 설명했다.
구현에는 언어 경계에 제한된 unsafe 코드가 있으며, 각 사용 지점에 안전성을 보장하는 조건을 주석으로 기록했다. 활성화 이후 보고된 버그는 없었다. 공개된 소스는 지속적으로 관리하는 오픈소스 프로젝트가 아니라 프로덕션 코드 기반의 참고 구현이다.
결론
이번 이식은 메모리 안전성과 기존 C 구현의 픽셀 단위 호환성을 함께 검증한 사례다. 비복사 타입, Span, projection type으로 데이터 복사와 할당을 줄였고, 최적화된 추상화를 통해 코드 가독성도 유지했다. Apple은 Swift 구현 소스를 공개했으며, 이를 지속적으로 개발하는 오픈소스 프로젝트가 아니라 참고 구현으로 제공한다고 밝혔다.