OCaml 编译器 - 2022年3月至2022年9月
我很高兴发布“OCaml 编译器开发新闻通讯”的第六期。您可以使用标签 compiler-newsletter 找到所有期数。
注意:新闻通讯的内容绝非详尽无遗,只有少数编译器维护者和贡献者有时间撰写内容,这完全没问题。
当然,欢迎发表评论或提出问题!
如果您一直在开发 OCaml 编译器并希望发表一些意见,请随时在此主题中发帖!如果您希望我在下次准备新闻通讯时与您联系(未来某个随机时间点),请通过 Discuss 消息或发送电子邮件至 (gabriel.scherer at gmail) 告知我。
背景
多核合并现已完成。我们正处于 5.0 的最终准备阶段(但这绝不意味着与多核相关的开发工作已经结束,许多事情留在了 5.1 和后续版本中)。非多核开发已缓慢但稳步地重启。
@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 的发布,我还一直在努力恢复已禁用的 OCaml 的 Cygwin 端口(#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)是必要的,但更改具有侵入性,并且审查可能需要一段时间。
Coqgen(以前称为 ocaml_in_coq)Coq 后端仍在发展,增加了循环、惰性值和异常等结构 Coqgen,并且我们正在尝试以全面方式包含 GADT。
@gasche Gabriel Scherer
@nojb Nicolás Ojeda Bär 在使用尾模余项列表对标准库的一些列表函数进行优化方面做了非常好的工作,我和 Xavier Leroy 一起帮助审查了它。
其中一些函数已手动优化,以便在较小的输入上使用非尾递归代码。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 版本的 boxroots 是必要的。
与我们的boxroot实验相关,Guillaume希望找到一种有效的方法来检查域线程当前是否持有其运行时锁——在执行不访问OCaml运行时的长时间非OCaml计算时,它不会持有锁。Guillaume修改了Caml_state
宏,以便在不持有域运行时锁的情况下访问域状态时引发错误——这是一种编程错误,在简单的测试中很容易被忽视,但在不同的输入下会导致难以调试的崩溃——并引入了一个新的Caml_state_opt
宏,当未持有运行时锁时,该宏为NULL。(#11138,#11272,#11506)。
Guillaume致力于在新版多核运行时中提高异步操作的质量。(#10915,#11039,#11057,#11095,#11190)。异步操作是由环境(而不是程序员在事件发生时明确请求)由OCaml程序调用的回调函数。例如,它们包括信号处理程序、GC调用的终结器、Statmemprof回调函数。良好地支持它们需要复杂的代码,因为运行时必须确保此类操作能够及时执行,但在运行OCaml代码安全的环境中执行。(例如,很容易出现错误,其中异步操作在运行时函数的中间引发异常,而该函数不是异常安全的。)4.x运行时在4.10到4.14之间修复了许多异步操作问题,但遗憾的是,许多这些改进没有移植到多核分支中(它们需要专家将代码适配到一个非常不同的运行时代码库),因此在多核合并中丢失了。目前的工作试图为5.0和5.1恢复良好的状态——一些修复不幸地没有及时合并到5.0中。Statmemprof支持目前在5.x中已禁用,这项工作也将对Statmemprof有所帮助。