- Exceptions
http://llvm.org/docs/ExceptionHandling.html
LLVM's exception support is tuned toward DWARF "zero-cost exceptions," i.e. C++ exception handling. Anton Korobeynikov and Duncan Sands (who is working on Ada) are probably the experts in this area.
Excellent.
So does zero-cost exception handling in C++ refer to a special case where you can statically prove that there are no destructors to call, or something?
"Zero cost" refers to the overhead introduced in the case when an exception is not thrown at all.
C++ has a guiding principal that "you don't pay for it if you don't use it." In the case of exceptions, this had pretty far-reaching implications, since each stack-based object calls for a destructor cleanup block. The resolution was for implementations to introduce no runtime overhead whatsoever for a try/catch block if no exception is raised, thus "zero cost". Throw actually became more expensive as a result of these implementations.
There is one thing that confuses me about this though. I benchmarked exception handling in OCaml and C++ a while ago and found OCaml to be ~6x faster and the best explanation I got was that C++ does not have zero-cost exceptions
Microbenchmarking raise vs. throw is not very realistic. ZCEH makes a complicated performance tradeoff wherein the exceptional case is penalized in order to optimize the common case. Since C++ code has many implicit try/finally blocks (each stack-based object with a destructor), this is a clear win. Ocaml code is quite different.
because it requires destructors to be called as the stack is unwound, whereas OCaml can just jump back and leave collection to the GC.
GC in general will reduce the amount of cleanup code, which should reduce DWARF EH's actual overhead (fewer cleanup blocks means smaller tables and accordingly cheaper unwinds), especially when unwinding deep stacks. Objective-C 2 on Leopard may be one of the few systems which has this combination of properties. (But exceptions in Cocoa code are discouraged even more strongly than in C++.)
Note that there is nothing in LLVM that prevents alternative exception handling regimes, they just won't benefit from the existing infrastructure, and will not interoperate with the DWARF runtime.
— Gordon
> So does zero-cost exception handling in C++ refer to a special case
> where you can statically prove that there are no destructors to
> call, or something?
"Zero cost" refers to the overhead introduced in the case when an
exception is not thrown at all.
Ah, I see.
> There is one thing that confuses me about this though. I benchmarked
> exception handling in OCaml and C++ a while ago and found OCaml to
> be ~6x faster and the best explanation I got was that C++ does not
> have zero-cost exceptions
Microbenchmarking raise vs. throw is not very realistic...
Just to clarify: the benchmark compared the performance of RB tree
implementations using exceptions to terminate early when an already-present
element was inserted. I found that it is more efficient in C++ (using g++) to
mimic the exception using nested "if"s rather than throw and catch. Although
simple, this benchmark was of practical importance to me at the time.
GC in general will reduce the amount of cleanup code, which should
reduce DWARF EH's actual overhead (fewer cleanup blocks means smaller
tables and accordingly cheaper unwinds), especially when unwinding
deep stacks.
I'm not quite sure I understand this (I don't even know what DWARF EH is!) but
are "cleanup blocks" the construct that I would be using to build exception
handlers?
Objective-C 2 on Leopard may be one of the few systems
which has this combination of properties. (But exceptions in Cocoa
code are discouraged even more strongly than in C++.)
Ok.
Note that there is nothing in LLVM that prevents alternative exception
handling regimes, they just won't benefit from the existing
infrastructure, and will not interoperate with the DWARF runtime.
Ok. Might as well start by reusing as much as possible. Exceptions are very
common in OCaml though. Is my 6x result a fair quantitative estimate of how
much faster exceptions could be make in this system for my compiler if it
were customized?
If so, I don't think that is a problem: exceptions are 600x slower in F# than
in OCaml!
The idea behind the implementation of C++ exceptions is that C++ exceptions
handle "exceptional" conditions, not normal code path. I.e. If you're throwing an
exception in the course of normal execution, there's something wrong with your
code. This means that C++ exceptions handle the normal case very well (no
overhead), but that the exceptional condition is OK with being slower as a tradeoff.
That said, I don't know much about OCaml and so don't know if this philosophy
fits the standard OCaml programming style. If throw/catch/etc are meant to be
normal path of execution then a small cost up front in, for example, try blocks
could easily speed up execution later when you hit the throw.
-eric
Exceptions are often raised and caught in OCaml programs so an optimizing
OCaml compiler would be expected to provide very fast throwing and catching
of exceptions.
However, optimizing them now when we already have an easy to use exception
mechanism would be premature: I'd like to get something useful up and running
first and leave these kinds of optimizations.
I'm not quite sure I understand this (I don't even know what DWARF EH is!) but
are "cleanup blocks" the construct that I would be using to build exception
handlers?
DWARF 2 is is the debug information format that goes with ELF, part of TIS (the Tool Interface Standard) :-
Dr. Dobb's | Good stuff for serious developers: Programming Tools, Code, C++, Java, HTML5, Cloud, Mobile, Testing
Dr. Dobb's | Good stuff for serious developers: Programming Tools, Code, C++, Java, HTML5, Cloud, Mobile, Testing
EH is Exception Handling 
Aaron
Microbenchmarking raise vs. throw is not very realistic...
Just to clarify: the benchmark compared the performance of RB tree implementations using exceptions to terminate early when an already-present element was inserted. I found that it is more efficient in C++ (using g++) to mimic the exception using nested "if"s rather than throw and catch. Although simple, this benchmark was of practical importance to me at the time.
Yes. Not surprising.
GC in general will reduce the amount of cleanup code, which should reduce DWARF EH's actual overhead (fewer cleanup blocks means smaller tables and accordingly cheaper unwinds), especially when unwinding deep stacks.
I'm not quite sure I understand this (I don't even know what DWARF EH is!) but are "cleanup blocks" the construct that I would be using to build exception handlers?
Yes. I should've used the term landing pads (http://llvm.org/docs/ExceptionHandling.html#try_catch).
Note that there is nothing in LLVM that prevents alternative exception handling regimes, they just won't benefit from the existing infrastructure, and will not interoperate with the DWARF runtime.
Ok. Might as well start by reusing as much as possible. Exceptions are very common in OCaml though. Is my 6x result a fair quantitative estimate of how much faster exceptions could be make in this system for my compiler if it were customized?
Likely so. To a reasonable approximation, LLVM EH is C++ EH.
If so, I don't think that is a problem: exceptions are 600x slower in F# than in OCaml!

— Gordon
Note that there is nothing in LLVM that prevents alternative exception
handling regimes, they just won't benefit from the existing
infrastructure, and will not interoperate with the DWARF runtime.
Ok. Might as well start by reusing as much as possible. Exceptions are very
common in OCaml though. Is my 6x result a fair quantitative estimate of how
much faster exceptions could be make in this system for my compiler if it
were customized?
If Ocaml has no landing pads, and if "catch" blocks are infrequent, it would be very reasonable to implement them in terms of setjmp and longjmp (as Gordon is alluding to). This is pretty straight-forward to do, and lets you evaluate the cost tradeoff. The nice thing about LLVM is that it doesn't force you to pick one specific implementation strategy, you can use the one that makes the most sense for your language.
-Chris
Ultimately, a minimal compiler for a statically-typed functional programming
language that gave good performance for some cases (probably non-GC-intensive
numeric code) would be an incredibly compelling demo for the use of LLVM in
general compiler writing. This looks perfectly feasible to me.
That would be very nice!
I got the impression from some of the blurb that I read that the optimizer in
LLVM might even be able to automate localized unboxing. Is that true? If so,
that would make things a lot easier...
I have some crazy ideas for nice language-independent ways to do this in LLVM. Once you have your front-end generating "naive" boxed code, please bring this back up and we can discuss it in more detail,
-Chris
Exception handling can be naively handled via closures, so the
amortized cost is an indirect function call. This requires some
program transformation where try-catch expressions are lifted into
their own functions and passed to callers. What does OCaml actually do
in this case?
Sandro