An alternate implementation of exceptions

Hi,

The guys on the Tiny C mailing list referred me to this list because I
suggested adding a simple exception handling mechanism to Tiny C.

I have written a small article on a proposal to add try/catch and throw
statements to C, knowing very well that this is a non-standard extention,
but there are so many of those in the C world that another one shouldn't
be a big issue. The Tiny C guys weren't interested in adding this
extension to Tiny C, but said that you guys might be interested in the
innovative way that I suggest implementing exceptions.

The reason I am posting a link to my article to this mailing list is that
the guys on the Tiny C mailing list said that you guys MIGHT be interested
in the new way I propose to implement exceptions. My method is very, very
fast, very, very small, and also has the added advantage that it does NOT
require run-time library support to implement.

Please ignore the fact that the paper is titled "A Proposal for Exception
Handling in C" and look only on it as proposing a new way of implementing
exception handling in pretty much all contemporary imperative languages.

The link is:

   http://www.lyngvig.org/doc/A%20Proposal%20for%20Exception%20Handling%20in%20C%20(ENU).pdf

Please let me know your comments, critique, and suggestions!

Sincerely,

Mikael Lyngvig

Hi Mikael, the idea of modifying functions so they return two parameters
(the usual one and an exception pointer or some kind of exception flag)
is well known. The LLVM vmkit project actually uses a variant of this:
rather than returning the exception pointer in a register, it sticks it
in a global thread local variable.

I only took a quick look at your paper, but it seems to me that it has
a serious problem: you can't link C code using your exception handling
mechanism with C code compiled using another compiler, since the carry
flag may not be cleared on function return by the code compiled by the
other compiler. Perhaps you addressed this issue in your paper, as I
mentioned I only glanced at it. Vmkit doesn't suffer from this problem,
since only code that is aware of vmkit exceptions will store in the
global.

Also, I don't see the point of the carry flag. Why don't you just
return the exception pointer in another register? If it is non-null
then an exception was raised. Are you trying to avoid register
pressure or save a cycle or two?

Finally, you could implement this (or something close to it) pretty
easily in LLVM. Suppose you have a function "int f(params) {...}".
Rather than outputting this to LLVM IR as
   define i32 @f(params) { ... }
you output it as
   define {i32, i8*} @f(params) { ... }
The additional return value is the exception pointer, which callers
can then inspect to see whether an exception was raised. On x86-64
codegen will return the i32 in RAX and the exception pointer in RDX.

Ciao,

Duncan.

Hi Duncan,

I agree on the problem about linking with code - I actually do mention
this in the paper. I propose adding a new calling convention called
"excall".

The central point of my paper is that only one parameter is needed as the
return value (because of the use of the flag): the EAX register can safely
be used for both the exception instance and the return value as these
never appear simultaneously. That's the primary reason I use the Carry
flag: To avoid allocating a global variable, a thread variable or an
entire register solely for communicating exception conditions. Especially
on register scarce architectures (vink, vink, Intel), it is important to
avoid allocating an entire register for the purpose of signaling a single
bit of information: 1 = an exception has occurred, 0 = no exception has
occurred. Also, when you use a register, instead of a flag, to indicate
the exception condition, the caller must explicitly check if the register
is non-zero - this adds some overhead compared to the simple
"jump-if-carry" instruction.

Thanks for looking at my stuff and I can only say that I am HAPPY that
this method is already known. I have not seen it implemented in any of
the compilers I use, but the most important thing for me is just that the
method is so great -- about four to five times faster than the traditional
stack unwind method (try expands to setjmp, throw expands to longjmp) --
that I wanted to make sure that somebody somewhere knew about the method.

I think I'll take my ideas to the OpenWatcom C++ mailing list as the
OpenWatcom compiler uses setjmp()/longjmp() in its exception handling
implementation (despite being one of the best compilers on the Intel
platform).

Cheers,
Mikael Lyngvig

Thanks for looking at my stuff and I can only say that I am HAPPY that
this method is already known. I have not seen it implemented in any of
the compilers I use, but the most important thing for me is just that the
method is so great -- about four to five times faster than the traditional
stack unwind method (try expands to setjmp, throw expands to longjmp) --
that I wanted to make sure that somebody somewhere knew about the method.
  
C++ exception implementation are optimized for the case where no exception is throw (opposite to what is done in python or maybe in java). Because in C++ exception are exceptionnal and should not be thrown during a normal execution of a program (use return code in this case). At least this is what all the C++ guru preach (that I know of).
I don't think your implementation can be faster than current zero cost exception model used currently (where metainformation is added somewhere for unwinding, but no other code is needed) in the case of no exception throw. And like I said, in the other case we don't care much about speed, since it is an exceptional occurrence.

This is just the way I see it, but at least for C++, the current solution seems more appropriate. obviously, for language like python which use exception to exit loop, this isn't the same thinks at all.

just my 2cents

Cédric

Mikael Lyngvig wrote:

Hi Duncan,

I agree on the problem about linking with code - I actually do mention
this in the paper. I propose adding a new calling convention called
"excall".
  

The problem is that you can't automatically determine from a function
declaration whether it comes from "inside" (is exception-aware) or not.
This means that you'd have to make the user explicitly declare one of
them. This is either a nightmare for using libraries (modify all
headers, or introduce an extern "C"-block-like feature as C++ has it, to
wrap the header includes), or a nightmare for writing new code (every
new function needs to have it, explicitly).

Sebastian

Just throwing the idea in the air: link time optimization of
exception handling? :slight_smile:

Sebastian Redl wrote:

Mikael Lyngvig wrote:
  

Hi Duncan,

I agree on the problem about linking with code - I actually do mention
this in the paper. I propose adding a new calling convention called
"excall".
  

The problem is that you can't automatically determine from a function
declaration whether it comes from "inside" (is exception-aware) or not.
This means that you'd have to make the user explicitly declare one of
them. This is either a nightmare for using libraries (modify all
headers, or introduce an extern "C"-block-like feature as C++ has it, to
wrap the header includes), or a nightmare for writing new code (every
new function needs to have it, explicitly).
  

You could use some form name mangling on all symbols which are exception aware. When there is a mismatch between callee and caller you will get a undefined symbol. You would then add thunks for these symbols (by having a tool which parse error messages from the linker or by modifying the linker to add them).

When an exception aware function calls a non exception aware one the thunk should call the function, clear the flags and then return. When an non exception aware function calls a function which might throw the thunk should check for an exception. If there is a pending exception it should abort, otherwise it would just return.