OCaml内部:异常 [英] OCaml internals: Exceptions
问题描述
我很想知道如何在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函数已经尝试捕获任何异常,然后将其转换为此格式?
谢谢!
OCaml异常处理
不使用 setjmp / longjmp
。当 try< expr>在评估< handle>
时,在堆栈上放置陷阱,其包含关于处理程序的信息。最上面的陷阱的地址保存在寄存器1中,当你提高时,它直接跳到这个陷阱,一次释放几个堆栈帧(这比检查每个返回码更好)。
¹:或者全局,在没有足够寄存器的体系结构上
p>您可以在代码中看到自己:
- 字节码编译:lines 635-641,两个
Kpushtrap / Kpoptrap
字节码环绕try..with
ed表达式 - native native compilation :lines 254-260,再次在表达式 周围指示
- 字节码执行对于字节码
PUSHTRAP
(放置陷阱/处理程序),POPTRAP
(删除它,非错误的情况) code> RAISE (跳到陷阱) - 本机代码发射和在amd64上的.inria.fr / cgi-bin / viewvc.cgi / ocaml / release / 3.12.1 / asmcomp / amd64 / emit.mlp?revision = 11110& view = markup#l613
Lpushtrap / Lpoptrap
与 setjmp
的比较ocaml使用具有很少或没有被调用保存的寄存器的非标准调用约定,这使得(和尾递归)有效。我想(但我不是专家),这就是为什么C
longjmp / setjmp
在大多数架构上不是那么高效。请参见此x86_64 setjmp实现,它看起来完全像以前的陷阱机制加callee寄存器保存。 这在 C / OCaml接口:从C代码调用Caml函数的常用方法, caml_callback
,不捕获OCaml-land异常;您必须使用特定的 caml_callback_exn
(如果您希望设置其陷阱处理程序并保存/恢复被调用者保存的C调用约定的寄存器。参见例如。 amd64代码,保存寄存器,然后跳转到此标签以设置异常陷阱。
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!
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 thetry..with
ed 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) andRAISE
(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.
这篇关于OCaml内部:异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!