Exception OCaml内部:异常

Exception OCaml内部:异常,exception,compiler-construction,ocaml,internals,setjmp,Exception,Compiler Construction,Ocaml,Internals,Setjmp,我很想知道如何在OCaml运行时处理异常,使它们变得如此轻量级。它们是使用setjmp/longjmp还是在每个函数中返回一个特殊值并传播它 在我看来,longjmp会给系统带来一点压力,但只有在引发异常时,而检查每个函数的返回值需要在调用函数后检查每个值,在我看来,这会导致很多检查和跳转,而且它的性能最差 通过查看OCaml如何与C()接口,以及callback.h,似乎可以通过使用对象的内存对齐来标记异常(#define is_exception_result(v)((v)&3)==2))。

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

在我看来,longjmp会给系统带来一点压力,但只有在引发异常时,而检查每个函数的返回值需要在调用函数后检查每个值,在我看来,这会导致很多检查和跳转,而且它的性能最差

通过查看OCaml如何与C()接口,以及callback.h,似乎可以通过使用对象的内存对齐来标记异常(#define is_exception_result(v)((v)&3)==2))。这似乎表明它的实现没有使用longjmp,而是在每次函数调用后检查每个函数的结果。是这样吗?或者C函数已经尝试捕获任何异常,然后将其转换为这种格式

谢谢大家!

OCaml异常处理 它不使用
setjmp/longjmp
。当计算
try with
时,堆栈上会放置一个“陷阱”,其中包含有关处理程序的信息。最顶层陷阱的地址保存在寄存器ª中,当您提升时,它会直接跳到此陷阱,一次释放几个堆栈帧(这比检查每个返回代码要好)。陷阱还存储前一个陷阱的地址,该地址在提升时恢复到寄存器中

⑨:或全局,在寄存器不足的体系结构上

您可以在代码中自己看到:

  • :第635-641行,两个
    Kpushtrap/Kpoptrap
    字节码围绕
    try..with
    ed表达式
  • :第254-260行,同样是表达式周围的说明
    Lpushtrap/Lpoptrap
  • 对于字节码
    PUSHTRAP
    (放置陷阱/处理程序)、
    POPTRAP
    (移除它,非错误情况)和
    提升
    (跳转到陷阱)
  • 本机代码发射和(例如)
setjmp
Ocaml使用非标准的调用约定,很少或没有保存被调用方的寄存器,这使得这种(和尾部递归)高效。我想(但我不是专家)这就是为什么C
longjmp/setjmp
在大多数体系结构上效率不高的原因。例如,请参阅与前面的捕获机制加上被调用方寄存器保存完全相同的示例


在中考虑了这一点:从C代码调用Caml函数的常用方法,
Caml_callback
,不会捕获OCaml和异常;如果愿意,您必须使用特定的
caml\u callback\u exn
,它设置陷阱处理程序并保存/恢复C调用约定的被调用方保存的寄存器。参见例如,保存寄存器,然后跳转到设置异常陷阱。

Wow!很不错的!非常感谢。您知道setjmp/longjmp为什么不使用类似的方法吗?除了asm调用之外,还有其他方法可以从C访问这些原语吗?再次感谢你@Waneck我想,
setjmp/longjmp
在体系结构上使用了类似的实现,使之成为现实。但是呼叫约定中被呼叫方保存的寄存器使得这些事情更加昂贵。我加了一句关于他们的话。