www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Idea: norecover blocks

reply dsimcha <dsimcha yahoo.com> writes:
I've been thinking about exception handling in D as it relates to nothrow.
The obvious benefit of nothrow is compiler-enforced documentation, but a
second benefit is performance with scope statements and RAII.  If the compiler
knows some function call can't throw, it can generate better code.

In some cases, it's possible to call a function that throws an exception, but
because of the nature of the client code, this exception would be deemed
unrecoverable anyhow, and the program should simply die.  However, the fact
that these lower-level functions still throw prevents the higher level
functions from being marked nothrow, hurting performance.  Catching the
exception is no help, because the try-catch block has its own performance
cost.  It would be nice if these function calls could be marked as norecover,
thus preventing the compiler from generating any finally blocks for scope
statements and RAII, and allowing the higher level functions to be marked as
nothrow.  For example:

void foo() nothrow {
    auto scratch = new uint[1_000];  // May throw outOfMemoryError.
    // Use scratch.
}

The above wouldn't work because new throws an outOfMemoryError, but:

void foo() nothrow {
    norecover auto scratch = new uint[1_000];
    // Use scratch.
}

would work. I honestly don't know much about how exception handling is
implemented at the ASM level, but I do know that scope statements and RAII are
in practice performance killers in the presence of throwing code.  Does this
sound like a reasonable strategy for mitigating this performance drain?
Jan 17 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Throwing unrecoverable exceptions still allows a function to be marked 
as nothrow.
Jan 17 2009
parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Throwing unrecoverable exceptions still allows a function to be marked
 as nothrow.

This misses the point. The idea is, you have a function A that calls a library function B. B throws an exception that is considered recoverable by whoever wrote B. However, within A, you want to treat the exception thrown by B as unrecoverable. void A() nothrow { B(); } void B() { if(someCondition) { throw new bException("Some Error"); } // Do stuff. } You could catch the bException in A, but that would require enough of a performance hit that any gain from having A be nothrow would likely be lost (at least in the cases I've tested). The idea is that you would declare something like: void A() nothrow { norecover { B(); } } and all exceptions thrown by code inside the norecover block would be treated as unrecoverable, even if they would normally be considered recoverable.
Jan 17 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
dsimcha wrote:
 This misses the point.  The idea is, you have a function A that calls a library
 function B.  B throws an exception that is considered recoverable by whoever
wrote
 B.  However, within A, you want to treat the exception thrown by B as
unrecoverable.
 
 void A() nothrow {
     B();
 }
 
 void B() {
     if(someCondition) {
         throw new bException("Some Error");
     }
     // Do stuff.
 }
 
 You could catch the bException in A, but that would require enough of a
 performance hit that any gain from having A be nothrow would likely be lost (at
 least in the cases I've tested).  The idea is that you would declare something
like:
 
 void A() nothrow {
     norecover {
         B();
     }
 }
 
 and all exceptions thrown by code inside the norecover block would be treated
as
 unrecoverable, even if they would normally be considered recoverable.

void A() nothrow { try { B(); } catch (Object o) { abort(); } } will do it.
Jan 17 2009
parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 void A() nothrow {
     try
     {
         B();
     }
     catch (Object o)
     {
         abort();
     }
 }
 will do it.

The problem is that, at least according to my testing, this has significant overhead, to the point where you may as well just not make A nothrow, from a performance perspective. Basically, what I'm asking is, if the compiler knew that you weren't going to try to recover from a bException, could it do better than catch { abort(); }?
Jan 17 2009
parent Walter Bright <newshound1 digitalmars.com> writes:
dsimcha wrote:
 The problem is that, at least according to my testing, this has significant
 overhead, to the point where you may as well just not make A nothrow, from a
 performance perspective.  Basically, what I'm asking is, if the compiler knew
that
 you weren't going to try to recover from a bException, could it do better than
 catch { abort(); }?

Try casting B to be a nothrow function.
Jan 17 2009