Thread overview
Using static immutable Exceptions (or other way for NON-GC exceptions)
Feb 18, 2015
Liran Zvibel
Feb 18, 2015
Iain Buclaw
Feb 18, 2015
Timo Sintonen
Feb 18, 2015
Iain Buclaw
Feb 18, 2015
Timo Sintonen
Feb 18, 2015
Iain Buclaw
Feb 18, 2015
Liran Zvibel
Feb 18, 2015
Iain Buclaw
Feb 18, 2015
Liran Zvibel
February 18, 2015
Hi,

We would like to use exceptions in some cases, but we don't want to allocate them when we send them.
What we do with dmd is create bunch of "static immutable Throwable" members in our objects during creation (for every possible case), then we just throw these members in the code.

When compiling with GDC we get a segfault in the code that tries to generate the backtrace.

We will start investigate this now so we can create a bug report, I would just like to ask whether anyone else has seen this behavior, and what is the recommended way to raise an exception without GC allocations in GDC.

Thanks!
Liran
February 18, 2015
On 18 February 2015 at 11:57, Liran Zvibel via D.gnu <d.gnu@puremagic.com> wrote:
> Hi,
>
> We would like to use exceptions in some cases, but we don't want to allocate
> them when we send them.
> What we do with dmd is create bunch of "static immutable Throwable" members
> in our objects during creation (for every possible case), then we just throw
> these members in the code.
>
> When compiling with GDC we get a segfault in the code that tries to generate the backtrace.
>
> We will start investigate this now so we can create a bug report, I would just like to ask whether anyone else has seen this behavior, and what is the recommended way to raise an exception without GC allocations in GDC.
>

You can't throw without a GC allocation currently.  I'm open to suggestions and patches welcome.

See here:  https://github.com/D-Programming-GDC/GDC/blob/master/libphobos/libdruntime/gcc/deh.d#L152


Iain.
February 18, 2015
On Wednesday, 18 February 2015 at 12:12:04 UTC, Iain Buclaw wrote:

>
> You can't throw without a GC allocation currently.  I'm open to
> suggestions and patches welcome.
>
> See here:  https://github.com/D-Programming-GDC/GDC/blob/master/libphobos/libdruntime/gcc/deh.d#L152
>
>
> Iain.

I was just goimg to ask about the state of this.
I have understood that this struct carries all the necessary info trough unwinding and it is not freed until gc frees it.
Where is the last place this struct is used. Is it in druntime side or in libgcc side?
Could it be possible to allocate this with malloc and free after unwinding? I have understood that this struct is not available any more in catch block.
Do we need many copies of this. Could it be possible to have a static one?
February 18, 2015
On 18 February 2015 at 12:34, Timo Sintonen via D.gnu <d.gnu@puremagic.com> wrote:
> On Wednesday, 18 February 2015 at 12:12:04 UTC, Iain Buclaw wrote:
>
>>
>> You can't throw without a GC allocation currently.  I'm open to suggestions and patches welcome.
>>
>> See here: https://github.com/D-Programming-GDC/GDC/blob/master/libphobos/libdruntime/gcc/deh.d#L152
>>
>>
>> Iain.
>
>
> I was just goimg to ask about the state of this.
> I have understood that this struct carries all the necessary info trough
> unwinding and it is not freed until gc frees it.
> Where is the last place this struct is used. Is it in druntime side or in
> libgcc side?

The last place it is used is on the libgcc side, or at least the generic exception header that our language-dependent header holds.

It may be a better solution to have a static TLS pointer that gets new'd upon thread start.  Perhaps even make it a pre-allocated array so we might be able to get chained exceptions working in GDC runtime.

> Could it be possible to allocate this with malloc and free after unwinding? I have understood that this struct is not available any more in catch block. Do we need many copies of this. Could it be possible to have a static one?

See __gdc_exception_cleanup just above _d_throw.  We use destroy(p) in the cleanup.  It could work to swap 'destroy' with 'free', and 'new' with 'calloc'.  But that still doesn't help if we are throwing an OutOfMemory exception.  It will still fail hard, rather than bail with a nice backtrace.

Iain
February 18, 2015
On Wednesday, 18 February 2015 at 13:07:12 UTC, Iain Buclaw wrote:
> On 18 February 2015 at 12:34, Timo Sintonen via D.gnu
> <d.gnu@puremagic.com> wrote:
>> On Wednesday, 18 February 2015 at 12:12:04 UTC, Iain Buclaw wrote:
>>
>>>
>>> You can't throw without a GC allocation currently.  I'm open to
>>> suggestions and patches welcome.
>>>
>>> See here:
>>> https://github.com/D-Programming-GDC/GDC/blob/master/libphobos/libdruntime/gcc/deh.d#L152
>>>
>>>
>>> Iain.
>>
>>
>> I was just goimg to ask about the state of this.
>> I have understood that this struct carries all the necessary info trough
>> unwinding and it is not freed until gc frees it.
>> Where is the last place this struct is used. Is it in druntime side or in
>> libgcc side?
>
> The last place it is used is on the libgcc side, or at least the
> generic exception header that our language-dependent header holds.
>
> It may be a better solution to have a static TLS pointer that gets
> new'd upon thread start.  Perhaps even make it a pre-allocated array
> so we might be able to get chained exceptions working in GDC runtime.
>
>> Could it be possible to allocate this with malloc and free after unwinding?
>> I have understood that this struct is not available any more in catch block.
>> Do we need many copies of this. Could it be possible to have a static one?
>
> See __gdc_exception_cleanup just above _d_throw.  We use destroy(p) in
> the cleanup.  It could work to swap 'destroy' with 'free', and 'new'
> with 'calloc'.  But that still doesn't help if we are throwing an
> OutOfMemory exception.  It will still fail hard, rather than bail with
> a nice backtrace.
>
> Iain

Out Of Memory is a special case and usually a fatal case. There was some discussions lately about this but I did not follow it.
If OutOfMemory is not working anyway then we do not loose anything? We may get the other exceptions to work. So why not make this until we find out some better solution?

February 18, 2015
On 18 February 2015 at 13:38, Timo Sintonen via D.gnu <d.gnu@puremagic.com> wrote:
> On Wednesday, 18 February 2015 at 13:07:12 UTC, Iain Buclaw wrote:
>>
>> On 18 February 2015 at 12:34, Timo Sintonen via D.gnu <d.gnu@puremagic.com> wrote:
>>>
>>> On Wednesday, 18 February 2015 at 12:12:04 UTC, Iain Buclaw wrote:
>>>
>>>>
>>>> You can't throw without a GC allocation currently.  I'm open to suggestions and patches welcome.
>>>>
>>>> See here:
>>>>
>>>> https://github.com/D-Programming-GDC/GDC/blob/master/libphobos/libdruntime/gcc/deh.d#L152
>>>>
>>>>
>>>> Iain.
>>>
>>>
>>>
>>> I was just goimg to ask about the state of this.
>>> I have understood that this struct carries all the necessary info trough
>>> unwinding and it is not freed until gc frees it.
>>> Where is the last place this struct is used. Is it in druntime side or in
>>> libgcc side?
>>
>>
>> The last place it is used is on the libgcc side, or at least the generic exception header that our language-dependent header holds.
>>
>> It may be a better solution to have a static TLS pointer that gets new'd upon thread start.  Perhaps even make it a pre-allocated array so we might be able to get chained exceptions working in GDC runtime.
>>
>>> Could it be possible to allocate this with malloc and free after
>>> unwinding?
>>> I have understood that this struct is not available any more in catch
>>> block.
>>> Do we need many copies of this. Could it be possible to have a static
>>> one?
>>
>>
>> See __gdc_exception_cleanup just above _d_throw.  We use destroy(p) in the cleanup.  It could work to swap 'destroy' with 'free', and 'new' with 'calloc'.  But that still doesn't help if we are throwing an OutOfMemory exception.  It will still fail hard, rather than bail with a nice backtrace.
>>
>> Iain
>
>
> Out Of Memory is a special case and usually a fatal case. There was some
> discussions lately about this but I did not follow it.
> If OutOfMemory is not working anyway then we do not loose anything? We may
> get the other exceptions to work. So why not make this until we find out
> some better solution?
>

Regardless, "Out of Memory" is a more informative message than "Segmentation Fault".   Especially so if you are the one trying to debug the program.  And find the 'trigger'.  :-)

Iain
February 18, 2015
On Wednesday, 18 February 2015 at 13:07:12 UTC, Iain Buclaw wrote:
> It may be a better solution to have a static TLS pointer that gets
> new'd upon thread start.  Perhaps even make it a pre-allocated array
> so we might be able to get chained exceptions working in GDC runtime.
>
> Iain

I like the idea of static TLS array that gets initialized at each thread.
Memory/startup time impact should be minimal, but it will allow throwing exceptions without touching the GC.
Some of our code is very latency sensitive, so we try very hard not to use the GC at all in these parts.
February 18, 2015
On 18 February 2015 at 14:54, Liran Zvibel via D.gnu <d.gnu@puremagic.com> wrote:
> On Wednesday, 18 February 2015 at 13:07:12 UTC, Iain Buclaw wrote:
>>
>> It may be a better solution to have a static TLS pointer that gets new'd upon thread start.  Perhaps even make it a pre-allocated array so we might be able to get chained exceptions working in GDC runtime.
>>
>> Iain
>
>
> I like the idea of static TLS array that gets initialized at each thread.
> Memory/startup time impact should be minimal, but it will allow throwing
> exceptions without touching the GC.
> Some of our code is very latency sensitive, so we try very hard not to use
> the GC at all in these parts.

Yah.  The only gotcha is if you fill up the chain, and it needs to realloc/grow the memory.  Would only ever happen if you have deep levels of try { } catch(e) { throw e; }  though....

Iain
February 18, 2015
On Wednesday, 18 February 2015 at 14:59:19 UTC, Iain Buclaw wrote:
> Yah.  The only gotcha is if you fill up the chain, and it needs to
> realloc/grow the memory.  Would only ever happen if you have deep
> levels of try { } catch(e) { throw e; }  though....
>
> Iain

It could be a gcd compile time param, with a big enough default value -- lets say 20.