unwind/invoke design

The documentation of unwind/invoke is quite clear and does exactly
what I need: unwinding the stack. I don't need it to carry an object
back. I don't need it to figure out what the type of the object is or
what catch() blocks it matches. I just need it to unwind the stack.
The rest is my job as a part of the runtime. Unfortunately, I have
learned that while this works with the bytecode evaluator, it doesn't
work with the JIT or native codegen [1].

There seems to have been discussion about making unwind/invoke
inter-operate with native c++ exceptions, and this complexity was
cited as being the reason it was too complex to implement. I question
whether this is actually needed. In other languages, I >do not< want
C++ exceptions to try and unwind my stack, nor do I want my exceptions
to unwind a C++ stack. The exceptions are completely incompatible and
this would not make sense.

To implement exceptions in a new frontend, unwind functionality is
required. LLVM generates all the stack frame information, so a
front-end author is not in the position to unwind the stack himself.
When I read the LLVM documentation I thought it could do this, and I
was extremely disappointed to learn that it could not.

This missing functionality means (as far as I can tell) that I will
not be able to implement a backend for ML which uses LLVM directly.
Instead I would need to use a trampoline to effectively remove LLVM
from stack control and manage a stack in the heap explicitly. This
seems quite a shame since LLVM was clearly intended to function as a
SSA backend.

I would ask that the documentation for unwind be updated to reflect
that this operation does not actually exist. Such a warning would have
saved me two weeks of wasted implementation effort.

[1] http://www.nabble.com/Unwinds-Gone-Wild-td18747589.html

The documentation of unwind/invoke is quite clear and does exactly
what I need: unwinding the stack. I don't need it to carry an object
back. I don't need it to figure out what the type of the object is or
what catch() blocks it matches. I just need it to unwind the stack.
The rest is my job as a part of the runtime. Unfortunately, I have
learned that while this works with the bytecode evaluator, it doesn't
work with the JIT or native codegen [1].

DWARF EH maybe what you want, it has zero overhead on normal calls and I believe it is built into LLVM's assemblers. A DWARF style EH is also built into the JIT too.

Aaron

How do I tell llc to output dwarf-style 'unwnd' ? Both -enable-eh and
-enable-correct-eh-support compile 'unwind' to nothing on x86 with llc
v2.5.

Write some C++ code into llvm.org/demo, and watch the output assembly,
for example:
int foo() {
throw 1;
}

int bar() {
try {
  foo();
} catch (...) {
}
}

That should show the basics of exception handling.

Best regards,
--Edwin

That shows how to use the c++ runtime for handling c++ style
exceptions. More useful might be an llvm implementation of
__cxa_throw, which I could then modify. :wink:

See http://lists.cs.uiuc.edu/pipermail/llvmdev/2009-May/022618.html .

-Eli

Wesley W. Terpstra wrote:

Hi Wesley,

The documentation of unwind/invoke is quite clear and does exactly
what I need: unwinding the stack. I don't need it to carry an object
back. I don't need it to figure out what the type of the object is or
what catch() blocks it matches. I just need it to unwind the stack.
The rest is my job as a part of the runtime. Unfortunately, I have
learned that while this works with the bytecode evaluator, it doesn't
work with the JIT or native codegen [1].

you can call the libgcc/libunwind routines directly. There was an
example of this on the mailing list by Talin not long ago. That said,
it wouldn't be too hard to support "unwind" in the code generators.
It would basically mean creating thread-local storage to hold dwarf
exception information, and turning "unwind" into some code to set up
the info and call the appropriate libgcc routine. Unfortunately no-one
was interested enough to do it yet.

Ciao,

Duncan.

you can call the libgcc/libunwind routines directly. There was an
example of this on the mailing list by Talin not long ago.

I'll look into this. Thanks.

That said,
it wouldn't be too hard to support "unwind" in the code generators.
It would basically mean creating thread-local storage to hold dwarf
exception information, and turning "unwind" into some code to set up
the info and call the appropriate libgcc routine.

Why does 'unwind' need to setup thread local storage at all? In my
opinion this is the responsibility of the frontend, not LLVM. All I
expect 'unwind' to do is unwind the stack down to the nearest 'unwind
label' of an invoke. Thread-local storage, global variable, or any
other approach one might think of to carry the exception information
is a frontend policy decision. Adding this support to 'unwind'
complicates its implementation and also dilutes its usefulness.

Wesley W. Terpstra wrote:

That said,
it wouldn't be too hard to support "unwind" in the code generators.
It would basically mean creating thread-local storage to hold dwarf
exception information, and turning "unwind" into some code to set up
the info and call the appropriate libgcc routine.
    
Why does 'unwind' need to setup thread local storage at all? In my
opinion this is the responsibility of the frontend, not LLVM. All I
expect 'unwind' to do is unwind the stack down to the nearest 'unwind
label' of an invoke. Thread-local storage, global variable, or any
other approach one might think of to carry the exception information
is a frontend policy decision. Adding this support to 'unwind'
complicates its implementation and also dilutes its usefulness.
  

Much to my surprise, I discovered that you do not need thread-local data at all - the address of the exception object can be passed in to the landing pad code by directly modifying a register (via the libunwind library API). The libunwind API also allows specification of a cleanup function to deallocate the exception object, although this is not needed in my case because I use garbage collection.

Since my previous posted example apparently turned out to be useful after all, maybe I should look in to putting it somewhere more permanent...

-- Talin

Hi Wesley,

Why does 'unwind' need to setup thread local storage at all? In my
opinion this is the responsibility of the frontend, not LLVM. All I
expect 'unwind' to do is unwind the stack down to the nearest 'unwind
label' of an invoke.

sure, but how is it to do that? Answer: using the libgcc unwinder
routines (another possibility is to use libunwind, which seems better
adapted to this but unfortunately isn't available everywhere). But
the libgcc unwinder requires you to supply some storage for it, and
I don't see that you have any choice except to use thread-local
storage.

Thread-local storage, global variable, or any

other approach one might think of to carry the exception information
is a frontend policy decision. Adding this support to 'unwind'
complicates its implementation and also dilutes its usefulness.

It would be entirely for technical reasons, see above.

Ciao,

Duncan.

* Wesley W. Terpstra:

The documentation of unwind/invoke is quite clear and does exactly
what I need: unwinding the stack. I don't need it to carry an object
back. I don't need it to figure out what the type of the object is or
what catch() blocks it matches. I just need it to unwind the stack.

You can use your stack switching mechanism for this purpose.

Florian Weimer wrote:

* Wesley W. Terpstra:

The documentation of unwind/invoke is quite clear and does exactly
what I need: unwinding the stack. I don't need it to carry an object
back. I don't need it to figure out what the type of the object is or
what catch() blocks it matches. I just need it to unwind the stack.

You can use your stack switching mechanism for this purpose.

Or call libunwind directly.

Ciao,

Duncan.

And don't forget good old setjmp/longjmp

Duncan Sands wrote: