OCaml 編譯器 - 2022 年 3 月至 2022 年 9 月

我很樂意發布第六期「OCaml 編譯器開發電子報」。您可以使用標籤 compiler-newsletter 找到所有期數。

注意:電子報的內容絕非詳盡無遺,只有少數編譯器維護者和貢獻者有時間撰寫內容,這完全沒問題。

當然,歡迎評論或提問!

如果您一直在研究 OCaml 編譯器並想說些什麼,請隨時在此討論串中發文!如果您希望我下次準備電子報時與您聯繫(未來的隨機時間點),請透過 Discuss 訊息或電子郵件 (gabriel.scherer at gmail) 告知我。

背景

Multicore 合併已告一段落。我們正在為 5.0 進行最後的準備階段(但絕非 Multicore 相關工作的結束,許多事情將留到 5.1 和後續版本完成)。非 Multicore 的開發已經緩慢但穩步地重新啟動。


@yallop Jeremy Yallop

我們在劍橋重新啟動了模組化巨集工作,目標是為 OCaml 新增對類型化、衛生、編譯時計算的支援。早在 2015 年,我們就在 OCaml 使用者與開發者研討會上提出了我們最初的設計,隨後我們在 OCaml 編譯器的分支中開發了一個原型。我們計劃在未來幾個月內完成、正式化並完整實作該設計。

@dra27 David Allsopp

已針對 5.0 管理編譯器發行版的各種內部管理工作,並利用了主版本號的遞增。編譯器的所有 C 符號現在都加上了 caml_ 前綴,大幅降低了與其他函式庫衝突的風險(#10926 和 #11336)。5.x 編譯器現在會將其所有額外的函式庫(Unix、Str 等)安裝到不同的目錄中,並發出友善的警告,指出您需要指定 -I +unix 等,這讓建置系統稍微容易一些 (#11198),而且編譯器現在預設也會為其所有函式庫提供 META 檔案 (#11007 和 #11399)。其他與 5.0 相關的調整包括不建議使用 ocaml 命令的子命令的可能性。現在應使用 ocaml ./script 而非 ocaml script (#11253)。編譯器的啟動過程(這是一種機制,用於更新 boot/ocamlc 中的初始編譯器,該編譯器用於「從冷啟動」建置編譯器)現在是可重現的 (#11149),簡化了需要包含對啟動編譯器變更的提取請求的審查過程。之前我們需要核心開發人員重新執行啟動並分別合併工作,而現在核心開發人員只需提取分支並檢查已提交的成品是否可重現即可。

展望 OCaml 5.0 的發布,我也一直致力於重新啟用已停用的 Cygwin OCaml 連接埠 (#11642),更重要的是,讓 MSVC 原生 Windows 連接埠再次運作(這仍在開發中!)。

在今年的 OCaml 研討會上,我展示了我的「可重新定位編譯器」專案,該專案旨在消除使用位元組碼可執行檔時的各種「小問題」,但更重要的是,允許將編譯器安裝複製到新的位置仍然可以運作,這為更快地建立 各處 的 opam 切換鋪平了道路。很高興能夠在斯洛維尼亞與這麼多人面對面參加自 2019 年以來的第一次面對面研討會,但不幸的是,這導致我感染了 COVID,這讓我接下來幾週的速度慢了下來!可重新定位編譯器的下一個階段是讓 opam 遠端可以加入,以允許使用 OCaml 4.08-5.0 選擇性測試,然後開始打開提取請求,希望將所需的變更包含在 OCaml 5.1 或 5.2 中。

@sadiqj Sadiq Jaffer

我去年在 OCaml 5.0 中進行的大部分上游工作都是關於執行階段事件,這是一個新的追蹤和度量系統,位於 OCaml 執行階段中。初始 PR 可在 #10964 中找到,而在 #11349 中有一個單獨的文件 PR。Lucas Pluvinage 後續提出了 PR #11474,其中將自訂應用程式事件新增至執行階段事件,我希望它不會離合併太遠。我們在 OCaml 使用者與開發者研討會上發表了關於執行階段事件的演講,我希望很快會有相關影片。

@garrigue Jacques Garrigue

我們持續致力於重構型別檢查器,以提高清晰度和抽象性。一個有趣的結果是 PR #11027:將反例的型別與 Typecore.type_pat 分開。具體而言,大約在 2015 年,type_pat 被轉換為 CPS 樣式,以便更精細地檢查 GADT 模式比對的窮盡性。一些更多的變更使程式碼變得越來越複雜,但在去年的 #10311 中,我們可以提取大量程式碼作為特定情況的約束。這又使將 type_pat 分割為兩個函式成為可能:type_pat 本身,僅用於在原始程式碼中為模式設定型別,不需要回溯,以及 check_counter_example_pat,一個更簡單的函式,可處理窮盡性檢查器產生的反例。我也新增了一個 -safer-matching 旗標,供不希望編譯的正確性取決於此分析中涉及的微妙型別引數的人使用 (#10834)。在另一個方向,我們重組了型別參數變異的表示法,使所涉及的格更為明確 (#11018)。我們有一些 PR 等待合併:#11536 引入了一些用於型別中層級管理的包裝函式,#11569 移除了用於表示與類別相關聯的雜湊型別路徑的編碼,因為它沒有以任何有意義的方式使用。

還有大量錯誤修正 (#10738、#10823、#10959、#11109、#11340、#11648)。其中最有趣的是 #11648,它擴展了 type_desc 以允許在型別內保留擴充。這是修復許多錯誤所必需的,包括 #9314,但變更具有侵入性,審查可能需要一段時間。

Coq 後端 Coqgen(之前名為 ocaml_in_coq)仍在進展中,新增了迴圈、惰性值和例外等結構 Coqgen,我們正嘗試以全面的方式包含 GADT。

@gasche Gabriel Scherer

@nojb Nicolás Ojeda Bär 在使用尾部模數 cons 來處理標準函式庫的一些 List 函式方面做了非常出色的工作,我與 Xavier Leroy 一起協助審查。

  • #11362:List.map、List.mapi、List.map2
  • #11402:List.init、List.filter、List.filteri、List.filter_map

其中一些函式經過手動最佳化,可在小輸入上使用非尾部遞迴程式碼。Nicolás 的微基準測試顯示,通常 TMC 轉換的版本在非常小的清單上速度稍慢,在少於五個元素的清單上速度慢了 20%。我們希望完全保留現有程式碼的效能,因此我們在某些地方進行了一些手動展開。(程式碼的可讀性比明顯的版本稍微差一些,但比之前的程式碼可讀性高得多。)

我致力於修復 5.0 位元組碼編譯程式的效能回歸問題 (#11337)。我一開始的直覺是,額外負荷來自於 5.x 執行階段中有並行跳過清單,而不是 4.x 執行階段中非並行跳過清單,並編寫了棘手的程式碼來再次使用循序跳過清單。很快我發現效能回歸的原因完全不同,不得不深入研究次要根掃描程式碼。

當我開始研究多核心執行階段時,我不知道如何在不使用 valgrind 的情況下從 C 區段錯誤列印回溯。我在 runtime/HACKING.adoc 中撰寫了一些關於偵錯的文件,希望能幫助其他人。

我花了一些時間閱讀 lambda/switch.ml,它將建構函式標記上的淺層比對編譯成條件和跳躍表。該檔案包含一些 90 年代的研究論文參考文獻,但我不清楚它們與實作的關聯性。在與 Luc Maranget 進行精彩討論後,我可以提出文件 PR #11446,以便在原始程式碼本身中說明這一點。感謝 Vincent Laviron 的精彩審查 - 一如既往。

@gadmm Guillaume Munch-Maccagnoni

(由 @gasche 撰寫)

Guillaume 致力於更新 OCaml 執行階段的「GC 計時掛鉤」和 caml_scan_roots_hook,使其具有多核心安全性,並新增了一個新的掛鉤 caml_domain_terminated_hook。(#10965、#11209)我們在實驗性 boxroot 函式庫中依賴執行階段掛鉤,而更新 5.0 的掛鉤對於擁有正確的 5.0 版本 boxroot 是必要的。

同樣與我們的 boxroot 實驗相關,Guillaume 希望找到一種有效的方法來檢查網域執行緒目前是否持有其執行期鎖定 — 當執行不存取 OCaml 執行期的長時間非 OCaml 計算時,它不會持有鎖定。Guillaume 修改了 Caml_state 巨集,使其在未持有網域執行期鎖定的情況下存取網域狀態時觸發錯誤 — 這是一個程式設計上的錯誤,在簡單的測試中可能很容易被忽略,但在不同輸入的情況下可能會以難以除錯的方式崩潰 — 並引入了一個新的 Caml_state_opt 巨集,當執行期鎖定未被持有時,該巨集會是 NULL。(#11138, #11272, #11506)。

Guillaume 致力於新 Multicore 執行期中非同步動作的品質處理。(#10915, #11039, #11057, #11095, #11190)。非同步動作是由環境(而不是程式設計人員在它們發生時的明確請求)呼叫 OCaml 程式的回呼。它們包括例如訊號處理器、由 GC 呼叫的 finalizer、Statmemprof 回呼。要良好地支援它們需要複雜的程式碼,因為執行期必須確保這些動作被及時執行,但在執行 OCaml 程式碼是安全的上下文中。(例如,很容易出現錯誤,其中非同步動作在非例外安全的執行期函數中間引發例外。)4.x 執行期在 4.10 和 4.14 之間有很多非同步動作的修復,但不幸的是,許多這些改進沒有回溯移植到 Multicore 分支(它們需要專家調整到非常不同的執行期程式碼庫),因此在 Multicore 合併中丟失了。目前的工作嘗試恢復到 5.0 和 5.1 的良好狀態 — 不幸的是,某些修復程式未及時合併到 5.0 中。Statmemprof 支援目前已針對 5.x 停用,這項工作也將對 Statmemprof 有用。