discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: does GNUstep support exception as well as apple implementation?


From: David Chisnall
Subject: Re: does GNUstep support exception as well as apple implementation?
Date: Fri, 4 Jun 2010 16:24:12 +0100

Hi Nikolaus,

On 4 Jun 2010, at 16:04, Dr. H. Nikolaus Schaller wrote:

> Hi David,
> 
> Am 04.06.2010 um 15:30 schrieb David Chisnall:
> 
>> On 4 Jun 2010, at 12:18, Shuduo Sang wrote:
>> 
>>> Does it mean the exception implementation of GNUstep is not complete as 
>>> well as Apple runtime?
>> 
>> 
>> There are two implementations of exception handling for use with GNUstep.  
>> One is the old NeXT-style implementation, using setjmp()/longjmp(), which is 
>> slow, unsafe, and needs to die a quick and peaceful death.  You may only use 
>> this with the NS_DURING family of macros.
> 
> Can you explain that a little?
> 
> My view is:
> 
> Exceptions are exceptions and should never occur in normal operation. So it 
> does not matter that they are slow when they got rised (is this currect 
> English?). Or you have a fundamental design problem.

Absolutely - they're called exceptions because they should happen in 
exceptional circumstances.

> So, IMHO the only "cost" is the setjmp() hidden by the NS_DURING macro which 
> AFAIK fills an array with some pointers and values.

setjmp() is required to dump all of the registers in the CPU into a buffer.  
This is not hugely expensive, but is a significantly greater cost than nothing. 
 It's typically at least 16 or so instructions (including stores from FPU 
registers - more if you have a vector unit) every time that you go over an 
NS_DURING macro, even when no exception is thrown.  This costs memory 
bandwidth, d-cache usage to store the buffer, and i-cache usage to store the 
string of instructions required for saving the CPU state. 

In contrast, the zero-cost exceptions cost nothing unless they are actually 
used.  Entering an @try block does not involve executing any instructions.  The 
only cost is a slight increase in the size of the binary, but because the 
unwinding tables are only used during unwinding they do not need to be loaded 
into memory unless an exception is thrown.

When an exception is thrown with the zero-cost mechanism, the unwind library 
parses these tables and calls the correct personality function for every frame 
on the stack, asking it if it has cleanup code or if it has a handler.  If a 
handler is not found, the unwind library just aborts.  If there is a handler, 
then the intervening unwind code is called and then the handler.

> And what is specifically unsafe with using them? They have been in use for 20 
> years now.

They are unsafe because they do not do anything like graceful unwinding of the 
stack.  They just load a set of CPU registers from a buffer.  This gives none 
of the intervening stack frames a chance to call cleanup code.  For example, 
you can't release a lock or deallocate on-heap temporaries if an exception is 
thrown over your stack frame.

If you mix Objective-C and C++ this is especially bad.  If you have C++ stack 
frames, they will typically involve things like destructor calls that happen 
automatically when C++ on-stack variables go out of scope.  This also happens 
with C code if you use __attribute__((cleanup)).  

There is a reason why the NeXT documentation recommends against using 
exceptions for anything other than printing a message and aborting - they leave 
your program in an undefined state.  Using setjmp()/longjmp() instructions is 
an absolutely terrible idea and should not be done unless there are absolutely 
no other options.  

Note: Windows' SEH also involves a cost for entering and leaving exception 
blocks, but does not have the other problems of setjmp() exceptions.

David


reply via email to

[Prev in Thread] Current Thread [Next in Thread]