OCaml 内部结构:异常 [英] OCaml internals: Exceptions

查看:17
本文介绍了OCaml 内部结构:异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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?

在我看来 longjmp 会给系统带来一点压力,但只有在引发异常时,同时检查每个函数返回值需要在调用函数后检查每个值,这似乎我会进行很多检查和跳转,似乎它会表现最差.

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.

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

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?

谢谢!

推荐答案

OCaml异常处理

它不使用 setjmp/longjmp.当一个 尝试 <expr>在评估 <handle> 时,会在堆栈上放置一个陷阱",其中包含有关处理程序的信息.最顶层陷阱的地址保存在寄存器中¹,当你提高时,它会直接跳转到这个陷阱,一次展开几个堆栈帧(这比检查每个返回码要好).陷阱还存储前一个陷阱的地址,该地址在引发时在寄存器中恢复.

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:

  • 字节码编译:第635-641行,两个Kpushtrap/Kpoptrap字节码围绕着try..withed表达式
  • 本地编译:第 254-260 行,再次说明 Lpushtrap/Lpoptrap 围绕表达式
  • 字节码执行字节码PUSHTRAP(放置陷阱/处理程序),POPTRAP(删除它,非错误情况)和RAISE(跳到陷阱)
  • 本机代码发射在 mips 上在 amd64 上(例如)
  • 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)

Ocaml 使用非标准调用约定,很少或没有保存被调用者的寄存器,这使得这种(和尾递归)高效.我想(但我不是专家)这就是 C longjmp/setjmp 在大多数架构上效率不高的原因.参见例如 this x86_64 setjmp implementation 看起来就像之前的捕获机制加上 callee-registers 保存.

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.

这在 C/OCaml 界面中考虑到了:通常的方式从 C 代码中调用 Caml 函数,caml_callback 不会捕获 OCaml-land 异常;如果您愿意,您必须使用特定的 caml_callback_exn,它会设置其陷阱处理程序 保存/恢复 C 调用约定的被调用者保存的寄存器.参见例如.amd64 代码,保存寄存器然后跳转到 这个标签来设置异常陷阱.

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.

这篇关于OCaml 内部结构:异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆