OCaml 内部结构:异常

发布于 2024-12-22 07:55:57 字数 546 浏览 3 评论 0原文

我很想知道 OCaml 运行时如何处理异常以使它们如此轻量。他们是使用 setjmp/longjmp 还是在每个函数中返回一个特殊值并传播它?

在我看来, longjmp 会给系统带来一点压力,但只有在引发异常时,在检查每个函数返回值时才需要在调用函数后检查每个值,在我看来,这会导致大量的检查和跳跃,看起来它的表现会最差。

通过查看 OCaml 如何与 C 交互(http://caml. inria.fr/pub/docs/manual-ocaml/manual032.html#toc142 ),并查看callback.h,似乎是通过使用内存来标记异常的对象对齐( #define Is_exception_result(v) (((v) & 3) == 2) )。这似乎表明它的实现不使用 longjmp 并在每次函数调用后检查每个函数结果。是这样吗?或者 C 函数已经尝试捕获任何异常,然后将其转换为这种格式?

谢谢你!

I'm curious to know how exceptions are dealt with in OCaml runtime to make them so lightweight. Do they use setjmp/longjmp or do they return a special value in each function, and propagate it?

It seems to me that longjmp would put a little strain on the system, but only when an exception is raised, while checking for each function return value would need to check for every and each value after calling a function, which seems to me would put a lot of checks and jumps, and it seems it would perform worst.

By looking at how OCaml interfaces with C ( http://caml.inria.fr/pub/docs/manual-ocaml/manual032.html#toc142 ), and looking at callback.h, it seems that an exception is tagged by using the memory alignment of objects ( #define Is_exception_result(v) (((v) & 3) == 2) ). This seems to indicate that its implementation doesn't use longjmp and checks each function result after each function call. Is that it? Or the C function already tries to catch any exception, and then converts it to this format?

Thank you!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

爱你不解释 2024-12-29 07:55:57

OCaml 异常处理

它不使用setjmp/longjmp。当 try时当 被评估时,一个“陷阱”被放置在堆栈上,其中包含有关处理程序的信息。最顶层陷阱的地址保存在寄存器中,当您引发时,它会直接跳转到该陷阱,一次性展开多个堆栈帧(这比检查每个返回代码更好)。陷阱还存储前一个陷阱的地址,该地址在上升时间恢复到寄存器中。

¹:或全局,在寄存器不足的架构上

您可以在代码中亲自查看:

  • 字节码编译:第635-641行,两行Kpushtrap/Kpoptrap 字节码围绕 try..withed 表达式
  • 本机编译:第 254-260 行,再次围绕表达式
  • 字节码执行用于字节码PUSHTRAP(放置陷阱/处理程序), POPTRAP(删除它,非错误情况)和RAISE(跳转到陷阱)
  • 本机代码发射在 mips在 amd64 上(例如)

setjmp 的比较

Ocaml 使用非标准调用约定,很少或没有被调用者保存寄存器,这使得这个(和尾递归)变得高效。我想(但我不是专家)这就是 C longjmp/setjmp 在大多数架构上效率不高的原因。请参阅示例 此 x86_64 setjmp 实现 看起来与之前的捕获机制加上被调用者寄存器保存完全一样。

C/OCaml 接口 中考虑了这一点:调用C 代码中的 Caml 函数 caml_callback 不会捕获 OCaml 领域的异常;如果您愿意,您必须使用特定的 caml_callback_exn 来设置其陷阱处理程序并保存/恢复 C 调用约定的被调用者保存的寄存器。参见例如。 amd64 代码,保存寄存器然后跳转到此标签进行设置异常陷阱。

OCaml exception handling

It doesn't use setjmp/longjmp. When a try <expr> with <handle> is evaluated, a "trap" is placed on the stack, that contains information about the handler. The address of the topmost trap is kept in a register¹, and when you raise, it jumps directly to this trap, unwinding several stack frames in one go (this is better than checking each return code). A trap also stores the address of the previous trap, which is restored in the register at raise time.

¹: or a global, on architectures with not enough registers

You can see for yourself in the code:

  • bytecode compilation: lines 635-641, two Kpushtrap/Kpoptrap bytecodes surround the try..withed expression
  • native compilation: lines 254-260, again instructions Lpushtrap/Lpoptrap around the expression
  • bytecode execution for the bytecode PUSHTRAP (places the trap/handler), POPTRAP (remove it, non-error case) and RAISE (jump to the trap)
  • native code emission on mips and on amd64 (for example)

Comparison with setjmp

Ocaml uses a non-standard calling convention with few or no callee-saved registers, which makes this (and tail-recursion) efficient. I suppose (but I'm no expert) that's the reason why C longjmp/setjmp isn't as efficient on most architectures. See for example this x86_64 setjmp implementation that looks exactly like the previous trapping mechanism plus callee-registers save.

This is taken into account in the C/OCaml interface: the usual way to call a Caml function from C code, caml_callback, doesn't catch OCaml-land exceptions; you have to use a specific caml_callback_exn if you wish to, which setups its trap handler and saves/restores callee-saved registers of the C calling convention. See eg. the amd64 code, which saves the registers then jump to this label to setup the exception trap.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文