| RFC-0048:明確的聯集序數 | |
|---|---|
| 狀態 | 已接受 |
| 區域 |
|
| 說明 | 為了更妥善地因應可擴充聯集 (或簡稱聯集) 的 ABI 影響,我們建議進行變更,讓彈性聯集在語法上更接近表格,並修正目前有關重新命名聯集或聯集成員的奇異 [2] 和過於嚴格的 ABI 限制。 |
| 作者 | |
| 提交日期 (年-月-日) | 2019-08-25 |
| 審查日期 (年-月-日) | 2019-09-26 |
摘要
為進一步配合可擴充聯集 (或簡稱聯集) 的 ABI 影響,我們建議:
- 變更變體成員的語法,要求明確的序數 (類似於表格序數的要求)。
- 請使用這個明確序數,而非先前導入的雜湊序數。
- 最後,我們變更了線路格式,將聯集序數設為 64 位元 (而非 32 位元)。
這些變更可讓彈性聯集在語法上更接近表格,並修正目前有關重新命名聯集或聯集成員的奇怪 1 和過於嚴格的 ABI 限制。
動機與設計
除了聯集之外,名稱不會對型別的 ABI 造成影響:列舉、位元、結構體和表格都可以重新命名,或重新命名成員,而不用擔心二進位檔相容性。由於我們選擇使用雜湊技術指派變體序數 (請參閱 RFC-0061:可擴充的聯集),因此聯集有所不同。
我們已發現這項缺點,並提出解決方法:請參閱「Intent to implement: xunion ordinals change」,其中建議變更雜湊配置,只納入成員名稱。
但這項提案更進一步,直接使用明確的序數,因此避免名稱與 ABI 相容性之間的任何關聯。我們認為在聯集宣告中編寫序數的額外工作量極少:迄今為止,表格中的明確序數並未造成問題,而且有大量先例可供參考,從其他熱門 IDL 編號成員或變體。
此外,為了進一步與表格保持一致,我們要求序數從 1 開始依序指派,並允許使用 reserved 關鍵字明確略過聯集變體。
僅針對通訊協定進行雜湊處理
與型別不同,通訊協定會使用雜湊方法指派序數。這項功能是為了滿足兩項主要用途而推出:
- 通訊協定可以組合,因此我們需要全域序數指派機制,避免遠距問題導致中斷。請參閱 [RFC-0063: OrdinalRange、RFC-0020:介面序數雜湊, 以及 RFC-0029:遞增方法序數。
- 實際上,全域不重複 ID 大幅簡化並強化監控和追蹤等需求,例如 fidlcat 依賴於唯一識別方法調用的能力。
這些用途不會轉換為類型。
這項提案的影響是,雜湊僅適用於通訊協定。只有一種雜湊配置,也就是 RFC-0029 中說明的配置。
64 位元序數是標準
目前,聯集內嵌內容中有 4 個位元組的邊框間距:
- 序數 (
uint32) - 邊框間距 (
uint32) - 信封 (16 個位元組)
相反地,我們希望以格式明確呼叫所有位元組,因此將序數變更為 64b。一般來說,我們偏好無邊框間距的結構,因為這類結構效率較高 (例如不需要明確的 memsets 或額外的編碼表)。
如要瞭解如何軟性轉換至 64 位元序數,請參閱「導入策略」一節。
JSON 線路格式
過去我們曾討論過,建立 JSON 線路格式時,重新命名型別和成員會對該格式造成 ABI 影響。
這有助於根據「線路格式」區分 ABI 中斷情形。我們可以從不同的屬性取得不同的屬性。如果極少數的訊息需要在所有支援的可能連線格式中與 ABI 相容,則這些訊息的演進方式會受到很大限制。如果情況允許,其他使用者應可享有更彈性的規則。
預做準備:稀疏資料表
我們曾討論過支援稀疏資料表,也就是除了「結構」和「資料表」之外,還能記錄類似資料的第三種版面配置。如果我們決定推出第三個選項,建議的語法會遵循這項提案,以及目前表格的語法:
sparse_table Example {
1: T1 field1;
2: reserved; // deprecated
3: T3 field3;
};
導入策略
如要啟用軟性轉換,我們需要釐清傳統 (32 位元雜湊) 序數語法與建議 (64 位元明確) 序數語法之間的差異。您可以透過下列方式完成這項操作:
- 在 fidlc 中新增檢查,確保 32 位元雜湊序數的值永遠不會低於 N。舉例來說,如果 N 為 512,雜湊序數的十六進位值「必須」至少為 0x200。
- 如果雜湊序數小於 0x200,就會導致編譯錯誤,且必須使用
[Selector=]屬性手動重新命名欄位名稱。我們會在 fidlc 中套用這項變更前,在適當的欄位中加入[Selector]。 - 由於現有雜湊配置的隨機性,我們預期雜湊錯誤的發生次數接近零,因此可能不需要手動解決。
- 加入這項檢查後,系統會有效分配
[0..N]序數空間給明確序數,並確保不會與雜湊序數衝突。
- 如果雜湊序數小於 0x200,就會導致編譯錯誤,且必須使用
- 語言繫結解讀序數值時:
- 如果序數介於
[0, N)之間,序數為 64 位元且明確。 - 如果序數介於
[N, UINT32_MAX]之間,序數為 32 位元並經過雜湊處理。 - 如果序數介於
[UINT32_MAX, UINT64_MAX)之間,繫結必須引發錯誤,並以墓誌銘關閉管道。
- 如果序數介於
人體工學
以極少的語法成本提供明確的序數,大幅簡化 ABI 人體工學。
說明文件和範例
須符合以下條件:
回溯相容性
如果定義聯集時未明確使用序數語法,系統會繼續使用現有的 32 位元雜湊序數配置。因此,現有的聯集會繼續與 API 和 ABI 相容。
以明確序數語法定義的聯集會使用本 RFC 中說明的 64 位元序數配置。如要瞭解如何同時支援 32 位元和 64 位元序數配置,請參閱「導入策略」一節。
效能
極小幅度的改善:由於 switch() 陳述式的程式碼產生作業更完善,這個架構比雜湊序數更有效率。
安全性
沒有影響。
測試
跟平常一樣微不足道。
缺點、替代方案和未知事項
替代做法:僅對成員名稱進行序數雜湊
請參閱實作意圖:xunion 序數變更。
經過進一步思考,我們認為上述做法不足,因為語法優勢 (來源中沒有序數) 無法彌補:
- 兩種雜湊配置,導致 ABI 影響更難理解;
- 在重新命名宣告或成員時,可讓聯集與同層級的列舉、位元、結構體和表格保持區別。
既有技術和參考資料
沒有特別相關的內容。
Footnote1
本文中的「聯集」是指可擴充的聯集,而非即將終止的「靜態」聯集。
Footnote3
寄件者:apang@google.com
收件者:fidl 使用者清單
日期:2019 年 5 月 23 日
FIDL 使用者,您好!昨天編寫測試時,FIDL 團隊發現目前的 xunion 規格和實作方式有令人意外的行為。如果有人聲明這點:
xunion MyXUnion {
int32 i; // ordinal might be 0x11111111
}
````
and renames the name of the xunion (not the field), the ordinal of the field
changes:
```fidl
// rename from MyXUnion to MyXUnion2
xunion MyXUnion2 {
int32 i; // ordinal now changes to 0x22222222 since the xunion was renamed. d'oh!
}
這可以說是意料之外的行為:變更 xunion 的名稱不應變更 ABI。
如要改善這項功能,必須做到以下兩點:
- 我們希望修訂 xunion RFC (RFC-0061),讓序數僅衍生自欄位名稱,並從序數雜湊計算中移除 xunion 名稱和程式庫名稱。
- 我們需要變更程式碼,但這代表 xunion ABI 會變更,可能導致建構作業失敗。幸好,我們可以透過 Jeremy Manson 首創的技術,為方法實作序數雜湊,讓用戶端同時檢查舊雜湊和新雜湊,直到變更完全在樹狀結構中推出為止,藉此進行軟轉移。
(我們學到一課:日後應仔細查看序數雜湊中包含的內容,以及變更這些內容是否會變更 ABI)。
我們認為這項計畫風險不高,因為可以進行軟轉換,而且 Jeremy 已成功完成方法序數的轉換。請留下註解,否則我們很快就會開始這項工作。
-
奇怪的是,名稱不會影響訊息的二進位線路格式 (即位元、列舉、結構體、表格),但聯集除外。因此,這個案件與其他案件不同。 ↩