February 17, 2015
On 17/02/2015 16:15, Nick Treleaven wrote:
>> Would RefCounted!T being @nogc help alleviate this issue?
>
> I think Andrei once said that was a good solution for exceptions.

Or rather that refcounting would be appropriate for exceptions, not necessarily RefCounted. (The compiler can't generate code using Phobos symbols, only druntime).
February 17, 2015
On Tuesday, 17 February 2015 at 13:32:40 UTC, Matthias Bentrup wrote:
> Maybe it is possible to have a separate ScopedThrowable exception class.
>
> Those exceptions would be allocated on the stack and would be allowed to carry references to local/scoped data, but they live only for the duration of the corresponding exception handler.
>
> The compiler should check that the exception and its payload don't escape the catch block, and of course the exception handler has to run before the stack unwinding is done.
>
> The whole point is of course that ScopedThrowables could be thrown from @nogc functions.

In response to allocating an exception on the stack...It depends on when you allocate the exception.  If the "catcher" of the exception allocates it on the stack, then you are fine so long as you have a way to pass a reference to it to any children functions, however, if the thrower allocates it on the stack then the memory will be released when the exception gets thrown.  It may make sense in some cases for the "catcher" to allocate the exception but I don't think that would be the norm.

The reason you can't keep the "thrower's" stack memory around for the exception handler is because the exception handler may need that memory.  Once the exception is thrown the stack is unwound to the function that has the exception handler so all the memory gets released. In most cases the exception handler probably won't mess up the memory the exception is using, but that can't be guaranteed.

As far as preventing the exception from escaping the catch block...that's precisely what the scope keyword would ensure.

Exception myException;

try {
   SomethingBad();
} catch(scope Exception e)
{
    myException = e; // Nope. e is a scoped variable
    // Note: if you needed the exception outside this
    // block then you could copy the memory to another
    // location.
}



February 17, 2015
On Tuesday, 17 February 2015 at 17:38:20 UTC, Jonathan Marler wrote:
> The reason you can't keep the "thrower's" stack memory around for the exception handler is because the exception handler may need that memory.  Once the exception is thrown the stack is unwound to the function that has the exception handler so all the memory gets released. In most cases the exception handler probably won't mess up the memory the exception is using, but that can't be guaranteed.
>

The problem I see, is that if I program a @nogc function for performance reasons, I'll likely have some data in scoped memory that is useful for handling the exception. If the stack is unwound before the exception handler, the thrower has to copy it to non-scoped memory and the catcher has to deal with it whether it needs the data or not.

If the unwinding is done after the exception handler is left, the thrower can safely reference the data directly on the stack and the catcher can ignore any data it doesn't need. (It may copy the data to safety if it is needed later, but the catcher knows what it needs, whereas the thrower has to always assume the worst case.)
February 17, 2015
> If the unwinding is done after the exception handler is left

Cannot see how that should work.
February 17, 2015
On Tuesday, 17 February 2015 at 18:04:53 UTC, Matthias Bentrup wrote:
> If the unwinding is done after the exception handler is left, the thrower can safely reference the data directly on the stack and the catcher can ignore any data it doesn't need. (It may copy the data to safety if it is needed later, but the catcher knows what it needs, whereas the thrower has to always assume the worst case.)

That is a good idea, unfortunately this is impossible since the catch block needs to execute code. But this is a good thought process.  I thought of the same thing but then realized that it would be impossible to ensure that the catch block wouldn't stomp on that memory.  This leads to having a second stack...however, we already have a solution...it's called the heap :)  By the time you're done trying to resolve this issue you will have just redesigned the heap.

IMO, Allocating the exception on the non-gc heap and making the catch block responsible for freeing the memory is a pretty good solution.
February 17, 2015
On Tuesday, 17 February 2015 at 18:30:24 UTC, Jonathan Marler wrote:
> I thought of the same thing but then realized that it would be impossible to ensure that the catch block wouldn't stomp on that memory.

The catcher wouldn't stomp any more on the thrower's memory than a function stomps on the memory of its caller. All the data of the thrower is safe, because it is above the stack pointer. The unwinding hasn't been done at that point.
February 17, 2015
On Tuesday, 17 February 2015 at 15:54:17 UTC, Andrei Alexandrescu wrote:
> On 2/16/15 3:17 PM, Jonathan Marler wrote:
>> Is there a proposal for how D will support throwing Exceptions in @nogc
>> code in the future?
>
> Nothing definite. We will get on to that right after 2.067. This is a good time to start discussions. -- Andrei

Could someone give a description of the minutiae of why Exception throwing uses memory allocation as it is and why (for example) passing it back on the stack isn't an option?
February 17, 2015
On Tuesday, 17 February 2015 at 18:40:51 UTC, Matthias Bentrup wrote:
> On Tuesday, 17 February 2015 at 18:30:24 UTC, Jonathan Marler wrote:
>> I thought of the same thing but then realized that it would be impossible to ensure that the catch block wouldn't stomp on that memory.
>
> The catcher wouldn't stomp any more on the thrower's memory than a function stomps on the memory of its caller. All the data of the thrower is safe, because it is above the stack pointer. The unwinding hasn't been done at that point.

That would be a deep change in language semantics. Think scope(exit), scope(failure), destructors of structs.
February 17, 2015
> Could someone give a description of the minutiae of why Exception throwing uses memory allocation as it is and why (for example) passing it back on the stack isn't an option?

The stack frame of the thrower is the first one to be rolled back. So you cannot allocate in the stack frame of the thrower, but a function cannot now, who (if anyone) is catching the exceptions it might throw. So I fear the stack is out.
February 17, 2015
On Tuesday, 17 February 2015 at 18:50:46 UTC, Tobias Pankrath wrote:
>> Could someone give a description of the minutiae of why Exception throwing uses memory allocation as it is and why (for example) passing it back on the stack isn't an option?
>
> The stack frame of the thrower is the first one to be rolled back. So you cannot allocate in the stack frame of the thrower, but a function cannot now, who (if anyone) is catching the exceptions it might throw. So I fear the stack is out.

Every throwable function call could be assumed to have a typed result (even void functions) and if, after the return, the caller checks the type and detects that it was an error, bubbles that up, then eventually you get to wherever the catcher is.

But so basically, the current ABI doesn't support it and there's no desire to change it? How do exceptions currently happen, if not via some official ABI declaration of how throwable methods interact with one another? The compiler/linker determines where the catcher is and inserts code to cut down the stack and perform a long jump all the way back? If so, how do scope statements work?