Apple 將 TrueType Hinting 解釋器遷移至 Swift
Apple 已使用具備記憶體安全性(memory-safe)的 Swift 重寫了其平台的 TrueType hinting 解釋器,並將在 2025 年秋季版本中取代原有的 C 實作。這次遷移是為了因應保護關鍵攻擊面的需求——因為字體解析器會處理來自網路的不可信數據——同時也藉此提升執行速度。
效能提升與記憶體安全性
基於 Swift 的解釋器平均比其取代的 C 實作快了 13%。透過利用 Swift 現代的型別系統與優化器,Apple 在不犧牲可讀性或安全性的情況下實現了此效能提升。新的實作包含少量的已驗證 unsafe 陳述式,特別是在語言互操作(interop)邊界處,但核心邏輯完全符合記憶體安全性。
確保像素級的正確性
在這次遷移中,正確性被定義為與 C 實作的輸出具有完全相同的二進位與像素級相容性。為了確保這一點,Apple 採用了兩種嚴格的測試策略:
- 單元測試: 為 C 與 Swift 實作提供 99.7% 的程式碼覆蓋率。
- 模糊測試(Fuzzing)與語料庫分析: 一個 fuzzer 將 1,000 萬個 PDF 檔案的語料庫縮減至 4,200 個。這導致了對 25,572 種字體中的 2,700 萬個字形進行渲染,並在四種不同的轉換中分別與參考的 C 解釋器進行比較。
Apple 表示,為該專案編寫的測試程式碼量幾乎是解釋器本身程式碼量的四倍。
Swift 中的技術優化
為了達到或超越 C 的效能,Apple 專注於四個主要的優化類別,以消除執行時開銷(runtime overhead)與記憶體配置(memory allocations)。
消除引用計數與排他性開銷
Swift 的自動引用計數(ARC)與執行時排他性檢查(runtime exclusivity checking)可能會引入開銷,特別是在存在別名(aliasing)的情況下。Apple 藉此緩解了此問題:
- 在整個架構中採用
~Copyable值型別,以消除對引用計數的需求。 - 使用
Span(於 Swift 6.2 中引入)來高效地對這些不可複製型別的序列進行操作。
優化跨語言數據橋接
解釋器最初的版本會將數據從 C structs 複製到 Swift 並回傳,這佔據了執行時的 20% 的時間。Apple 使用**投影型別(projection types)**取代了此做法。這些型別提供對底層 C 結構的安全且經過邊界檢查的存取,而無需複製或轉換數據,在維持原 C 佈局的快取友善性(cache-friendliness)的同時,提供了符合 Swift 慣用法(idiomatic Swift)的可讀性。
減少堆積配置(Heap Allocations)
為了避免與 map 和 filter 等函數相關的短期記憶體配置成本,團隊使用了 .lazy 序列或帶有 continue 的標準迴圈。
對於堆疊(stack)操作,Apple 實作了傳遞續行(continuation-passing)方法。與其配置一個新陣列來回傳彈出的元素,不如讓呼叫者傳遞一個在元素被移除前對 Span 的堆疊元素進行操作的區塊(block),從而在結構上消除了堆積配置與元素複製。
社群洞察與背景
在公告發布後,技術討論強調了這次轉型的成功與挑戰:
工具鏈穩定性: 一位開發者指出,在嘗試使用文中所述的生命週期(lifetime)特性時遇到了編譯器崩潰,這顯示這些進階特性在 Apple 內部環境之外的通用用途中可能仍不穩定。
更廣泛的 OS 策略: 評論指出,這是 Apple 在將各種 OS 層級遷移至記憶體安全語言的更大努力的一部分,正如最近的「State of Platform」主題演講中所提到的。
AI 集成: Apple 明確提到,他們將遷移過程中的學習心得轉化為指令,提供給 LLM 編碼助手,隨後用於加速後續專案中 C/C++ 到 Swift 的轉換。
Apple 已在 GitHub 上以 MIT 授權條款發布了 Swift TrueType hinting 解釋器的原始碼,作為參考實作。