edA-qa mort-ora-y
2013-Apr-25 05:38 UTC
[LLVMdev] trouble understanding value in dwarf exception mechanism
I'm having trouble understanding the value in the way exceptions are handled on Linux, the dwarf/system V ABI exception spec. The mechanism allows for both cleanup routines and catch handlers, where by cleanup handlers don't stop the search for a normal handler. The personality function (I guess no longer part of the standard, but a C++ thing) can also compare types of the landingpads. I'm having trouble understanding a few points. I would like to understand since I have exceptions in my language as well and want to make effective use of the model. 1. The way basic blocks come together often means you can have embedded try/catch handlers without an intervening function call. You can't have multiple landingpads without an intervening invoke thus one block needs to branch/include the other handler. This appears to result in the need to check the types of exceptions in the landingpad. This seems wasteful to check the types in both the personality and the landingpad. 2. Cleanup landingpads, in the general case, will need to call functions. Not knowing what is in these functions one must assume they could in turn have their own exception flow: they have a try/catch but don't allow exceptions to escape. The ABI mechanism though seems like only one exception at a time can be in progress. This would mean that cleanup code would have to register as catch handlers and rethrow the exception -- they cannot be "cleanup" routines according to the standard. In all I don't see why the current approach is better than simply treating all landingpads equally in the personality. Each landingpad would do its own type checking and rethrow or continue as appropriate. That is, no cleanup routines, and no type matching in the personality. -- edA-qa mort-ora-y -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Sign: Please digitally sign your emails. Encrypt: I'm also happy to receive encrypted mail. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 261 bytes Desc: OpenPGP digital signature URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20130425/df0a30a4/attachment.sig>
David Chisnall
2013-Apr-25 08:38 UTC
[LLVMdev] trouble understanding value in dwarf exception mechanism
Hi, On 25 Apr 2013, at 06:38, edA-qa mort-ora-y <eda-qa at disemia.com> wrote:> I'm having trouble understanding the value in the way exceptions are > handled on Linux, the dwarf/system V ABI exception spec. The mechanism > allows for both cleanup routines and catch handlers, where by cleanup > handlers don't stop the search for a normal handler. The personality > function (I guess no longer part of the standard, but a C++ thing) can > also compare types of the landingpads. > > I'm having trouble understanding a few points. I would like to > understand since I have exceptions in my language as well and want to > make effective use of the model.Yes, it's not the most well-written spec I've ever had to read...> 1. The way basic blocks come together often means you can have embedded > try/catch handlers without an intervening function call. You can't have > multiple landingpads without an intervening invoke thus one block needs > to branch/include the other handler. This appears to result in the need > to check the types of exceptions in the landingpad. This seems wasteful > to check the types in both the personality and the landingpad.You can optimise this in the front end, by generating a single landing pad for invokes in the nested try blocks and having them emit a single landing pad that declares all of the catchable types in the order that they'll be tested and then jumps to the correct one. I'm not sure if clang does this for C++ or not. LLVM could do this, but it requires some knowledge of the semantics of the personality function, so it's something that is only safe to turn on for known personality functions. Again, I'm not sure if LLVM does this (there are some optimisations that check the name of the personality function against ones that have known semantics).> 2. Cleanup landingpads, in the general case, will need to call > functions. Not knowing what is in these functions one must assume they > could in turn have their own exception flow: they have a try/catch but > don't allow exceptions to escape. The ABI mechanism though seems like > only one exception at a time can be in progress. This would mean that > cleanup code would have to register as catch handlers and rethrow the > exception -- they cannot be "cleanup" routines according to the standard.C++ supports nested exceptions, so when you throw an exception while catching another, the runtime library maintains a stack of them. The semantics of this are quite messy, and I don't remember them exactly, but they are (not very well) documented in Part III of the Itanium EH ABI doc. When something is thrown from a catch block in C++, the compiler emits an invoke for the throwing function that jumps to a block that calls the end-catch function and then resumes. A simpler model is to have every call in a cleanup be an invoke with the unwind target a basic block that calls abort(). In practice, this is often enough...> In all I don't see why the current approach is better than simply > treating all landingpads equally in the personality. Each landingpad > would do its own type checking and rethrow or continue as appropriate. > That is, no cleanup routines, and no type matching in the personality.There are three factors: 1) Having the personality function in a separate shared library means that you can modify its semantics (e.g. add support for dependent exceptions or add an optimised path if a new kind of type info is present) without having to recompile every shared library. 2) Exceptions are supposed to be infrequent and so shouldn't cause much code bloat. The unwind tables are in a separate section and so (hopefully) will only be paged in when an exception is thrown. Code at the landing pad is typically very close to the call[1] and so will not just be paged in, it will probably also even be in the instruction cache. You want to minimise this, especially in a language like C++ that is designed for running microbenchmarks and already has significant problems with i-cache churn. 3) The code for selecting the correct exception can be very complex, especially in the presence of foreign exceptions. Inlining that is not likely to be a significant performance win, and will be optimising for the code path that, by definition, happens in exceptional circumstances. David [1] One interesting optimisation would be to move all basic blocks that are landing pads, or solely reachable from landing pads, away from the rest of the code when codegening the module, so that they will not even be swapped in when they are not used. The unwind ABI allows the unwind target to be a very large offset from the rest of the function, so it would be possible to stick all landing pads right at the end of the text section...
Renato Golin
2013-Apr-25 09:02 UTC
[LLVMdev] trouble understanding value in dwarf exception mechanism
On 25 April 2013 06:38, edA-qa mort-ora-y <eda-qa at disemia.com> wrote:> I'm having trouble understanding a few points. I would like to > understand since I have exceptions in my language as well and want to > make effective use of the model. >Hi, You probably got there, but just reiterating: LLVM EH is not modelled with only C++ exceptions in mind, so some things will look redundant for C++, but they could not be for other languages. For instance, C++ can only have one exception, Ada can have as many as you like, and you have to express both on the same IR language, possibly both styles on the same module! But also, the IR has to be generic AND efficient, so having more information on the IR than needed at a lower level might mean that you'll have better ways to prune stuff at all levels on all EH styles. 1. The way basic blocks come together often means you can have embedded> try/catch handlers without an intervening function call. You can't have > multiple landingpads without an intervening invoke thus one block needs > to branch/include the other handler. This appears to result in the need > to check the types of exceptions in the landingpad. This seems wasteful > to check the types in both the personality and the landingpad. >There are two ways to get to landing pads: when an exception is thrown and when you're unwinding. On the first case, you go straight to the right landing pad and it looks a bit redundant, but on the second case, the type of the exception can be anything, so the personality (or whatever will scan the landing table) has to go over all types, and you have to have types that bail, types that continue and types that are treated here and now. Why not leave all to the personality, you ask down there: because it can take a considerable amount of time to go all the way to runtime library code and back, just to go to the right place. Compilers can make that a jump with a very small immediate instead. 2. Cleanup landingpads, in the general case, will need to call> functions. Not knowing what is in these functions one must assume they > could in turn have their own exception flow: they have a try/catch but > don't allow exceptions to escape. The ABI mechanism though seems like > only one exception at a time can be in progress. This would mean that > cleanup code would have to register as catch handlers and rethrow the > exception -- they cannot be "cleanup" routines according to the standard. >The runtime exception library, at least in C++, has THE exception object allocated and freed, so if you try to throw another object while one is being handled, it'll detect and call terminate() in the run time code, not clean ups, not landing pads, not user code. This is a not-so-hidden contract[1] between user code, landing pads and the runtime library that has to be followed, and why it's so hard to implement (and test) exception handling. cheers, --renato [1] http://mentorembedded.github.io/cxx-abi/abi-eh.html -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20130425/7887d792/attachment.html>
Duncan Sands
2013-May-04 07:37 UTC
[LLVMdev] trouble understanding value in dwarf exception mechanism
Hi, On 25/04/13 07:38, edA-qa mort-ora-y wrote:> I'm having trouble understanding the value in the way exceptions are > handled on Linux, the dwarf/system V ABI exception spec. The mechanism > allows for both cleanup routines and catch handlers, where by cleanup > handlers don't stop the search for a normal handler. The personality > function (I guess no longer part of the standard, but a C++ thing) can > also compare types of the landingpads. > > I'm having trouble understanding a few points. I would like to > understand since I have exceptions in my language as well and want to > make effective use of the model. > > 1. The way basic blocks come together often means you can have embedded > try/catch handlers without an intervening function call. You can't have > multiple landingpads without an intervening invoke thus one block needs > to branch/include the other handler. This appears to result in the need > to check the types of exceptions in the landingpad.the kind of test involved is completely different. The personality function has to do language specific tests with a type, eg class comparisons, which might be complicated. The landing pad is essentially just executing a switch instruction (in GCC they experimented with having codegen output a real switch, but found that a series of "if" comparisons was usually faster). Also, inlining naturally creates nested catch blocks, so I don't see how you can escape something like this (need to test multiple catch possibilities in one landing pad) in general. This seems wasteful> to check the types in both the personality and the landingpad. > > 2. Cleanup landingpads, in the general case, will need to call > functions. Not knowing what is in these functions one must assume they > could in turn have their own exception flow: they have a try/catch but > don't allow exceptions to escape. The ABI mechanism though seems like > only one exception at a time can be in progress. This would mean that > cleanup code would have to register as catch handlers and rethrow the > exception -- they cannot be "cleanup" routines according to the standard.It is perfectly fine to have a cleanup throw an exception (and maybe catch it or maybe let it propagate, or whatever), the unwind library doesn't care. Ada does this and doesn't have to jump through any hoops to get it to work. The reason that C++ has trouble with this is not coming from the unwind library, it's coming from C++ semantics (the fact that exception objects themselves may need complicated destructing IIRC). It's a C++ problem.> > In all I don't see why the current approach is better than simply > treating all landingpads equally in the personality. Each landingpad > would do its own type checking and rethrow or continue as appropriate. > That is, no cleanup routines, and no type matching in the personality.Wouldn't that mean that for every stack frame, you would have to restore all registers, jump to your code for the stack frame (which would then do the type testing, i.e. in essence be an inlined version of the personality function), then maybe continue unwinding. That seems expensive, and like a good way to get very fat landing pad code. Anyway you can always have your personality function be very simple: it can not bother with any type comparisons, just always say "yes, there is a match", causing control to always branch to your landing pad, giving the effect that you want. Ciao, Duncan.
edA-qa mort-ora-y
2013-May-04 08:32 UTC
[LLVMdev] trouble understanding value in dwarf exception mechanism
On 04/05/13 09:37, Duncan Sands wrote:> Wouldn't that mean that for every stack frame, you would have to restore > all registers, jump to your code for the stack frame (which would then do > the type testing, i.e. in essence be an inlined version of the personality > function), then maybe continue unwinding. That seems expensive, and like > a good way to get very fat landing pad code. Anyway you can always have > your personality function be very simple: it can not bother with any type > comparisons, just always say "yes, there is a match", causing control to > always branch to your landing pad, giving the effect that you want.I guess I'm looking at my language, and even considering C++, where once you start using closures, destructors, and defer statements, the frames which have handling code greatly exceeds those which have no handling code. Frames which don't need cleanup are often small enough to be inlined. So the likelihood that an exception can skip over a frame is very unlikely. Whereas the exception model seems to be optimized with the assumption that a lot of stack frames can be skipped entirely. -- edA-qa mort-ora-y -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Sign: Please digitally sign your emails. Encrypt: I'm also happy to receive encrypted mail. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 261 bytes Desc: OpenPGP digital signature URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20130504/5a6f7a2c/attachment.sig>