Swift Digest
Blog | Swift.org Blog

AppleのSwift活用: TrueType の hinting インタプリタを C から Swift へ移行する

Swift at Apple: Migrating the TrueType Hinting Interpreter

このダイジェストはClaude Opus 4.7 / 4.8によって生成されたものです(License)。原文はこちら

この記事の要点

採用前の課題

TrueType は、Webページ・PDF・OS・アプリケーションでテキストを描画するために広く使われているベクトルフォント規格です。Helvetica や Garamond、Monaco といった馴染みのあるフォントも TrueType アウトラインで作られています。

この規格には hinting インタプリタ が定められています。アウトラインだけでも美しいタイポグラフィが得られる現代の高解像度ディスプレイとは異なり、低解像度では hinting によってグリフを読みやすく整える必要があります。TrueType フォントはこのインタプリタが実行するプログラムを内部に含むことができ、インタプリタは入力に応じた制御フロー、複雑なデータ構造、慎重なメモリ管理を伴います。これはまさに正しく書くのが難しく、メモリエラーが悪用されやすいコードです。

TrueType は1994年に PDF へ、2008年に Web ページへ埋め込めるようになり、インターネット上のどこからでも取得した 信頼できないフォント にさらされるようになりました。そのため hinting インタプリタはセキュリティ上クリティカルな攻撃面となっており、これをより堅牢にすることが書き換えの出発点でした。

Swiftでどう改善したのか

書き換えには、既存のコードベースに統合でき、置き換え対象と同等の性能を出せるメモリ安全な言語が必要でした。Swift はこの条件を満たす自然な選択でした。

「正しさ」をピクセル単位の互換性として定義する

このプロジェクトではバイナリ互換性が決定的に重要でした。既存プログラムは新実装の存在に気付かないまま、これまでと同じように動作し続けなければなりません。hinting はグリフの見た目を大きく変えるため、インタプリタの挙動がわずかにずれただけでもユーザーから見える違いが生じます。そこで C 実装の出力とピクセル単位で完全に一致すること を正しさの定義としました。

正しさは2つのテストスイートで検証しています。

最終的に、インタプリタ本体の約4倍の行数のテストコードを書いたとされています。

性能を引き出す4つの工夫

テストをすべて通過させたうえで性能改善に取り組み、その工夫は大きく4つに整理されています。

短命なアロケーションを避ける例として、インタプリタのスタックから末尾の n 要素を取り出す pop が紹介されています。素朴に書くと、取り出した要素を返すためにアロケーションが必要です。

mutating func pop(
  count n: Int
) -> [Element] {
  defer { items.removeLast(n) }
  return Array(items.suffix(n))
}

これを、呼び出し元が渡したブロックに要素のスライスを渡して削除前に処理させる 継続渡し の形に変えると、ヒープへのアロケーションも要素のコピーも構造的に不要になります。コンパイル時の排他的アクセスチェックにより、ブロックの内側からスタックを変更できないことも保証されます。

mutating func pop<R, E: Error>(
  count n: Int,
  _ op: (borrowing Span<Element>) throws(E) -> R
) throws(E) -> R {
  defer { items.removeLast(n) }
  return try op(items.span.extracting(last: n))
}

C 構造体を安全に包む projection type は、WebKit の Safer Swift Guidelines に倣って書かれています。生存期間の安全性を保ちつつ境界安全なアクセスを仲介し、すべての unsafe 式には安全性の根拠を示す // SAFETY: コメントを付けるという方針です。

実運用から得られる示唆

性能改善は可読性を犠牲にして得られた、と思われがちですが、実際には Swift の型システムと最適化器のおかげで、抽象化を使いながら可読性の高いコードを書けたと報告されています。FixedPoint 型は整数型と同じ使い勝手で複雑な丸めとシフトの演算をカプセル化し、projection type は元々その用途を想定していないデータ構造にも安全で自然なアクセスを与えました。最適化を有効にしてビルドすると、これらの抽象化は コストゼロ で可読性だけを大きく改善しています。

成果は当初の目標どおりでした。新しいインタプリタは言語間の境界にごく少数の入念に検証された unsafe 文を含むだけで、有効化以降バグの報告はなく、そのうえで 平均 13% 高速 です。すべてが速くなったわけではなく、内部状態は借用される non-copyable 構造で書かれている一方、トップレベルの型自体は Objective-C++ から呼ばれる @objc class のままにするなど、ホットパスを速く・コールドパスを書きやすく、という割り切りもしています。

non-copyable 型・値型・Span を使ったコードは、デフォルトで安全かつ高速です。モジュール内に閉じた型でアーキテクチャを定義でき、網羅的なテストカバレッジとあわせて、明確な内部境界がリファクタリングを容易にし、「計測して直す」最適化のループを加速させました。重い計算と信頼できない入力を伴うセキュリティクリティカルなコードでも、Swift がメモリ安全性・性能・保守性を両立できることを示す事例です。

関連リンク