Jump to page: 1 2
Thread overview
Dwarf Exception Handling question
Nov 23, 2015
Walter Bright
Nov 23, 2015
Iain Buclaw
Nov 23, 2015
Walter Bright
Nov 23, 2015
Iain Buclaw
Nov 23, 2015
Walter Bright
Nov 24, 2015
Jacob Carlborg
Nov 24, 2015
deadalnix
Nov 23, 2015
David Nadlinger
Nov 23, 2015
Iain Buclaw
Nov 23, 2015
Walter Bright
Nov 23, 2015
deadalnix
Nov 23, 2015
Walter Bright
Nov 24, 2015
deadalnix
Nov 24, 2015
David Nadlinger
Nov 24, 2015
Walter Bright
November 23, 2015
I'm struggling to understand dwarf EH, and figure it's a good idea to try and make it binary compatible with what gdc does, or at least not gratuitously different. If I use gdc to compile this:

void foo1() {
        abc();
        try {
                def();
        }
        catch(DD t) {
                ghi(t);
        }
        catch(CC t) {
                ghi(t);
        }
        catch {
                mno();
        }
        jkl();
}

the code generated looks like this:

_D3eh54foo1FZv:
                push    RBP
                mov     RBP,RSP
                sub     RSP,010h
                call      abc
                call      def
L12:            call      jkl
                jmp short       L86
                cmp     RDX,2
                je      L59
                cmp     RDX,3
                je      L7F
                cmp     RDX,1
                je      L33
                mov     RDI,RAX
                call    _Unwind_Resume
L33:            sub     RAX,8
                mov     RAX,[RAX]
                mov     ESI,offset _D3eh52DD7__ClassZ
                mov     RDI,RAX
                call    _d_dynamic_cast
                mov     -8[RBP],RAX
                mov     RAX,-8[RBP]
                mov     RDI,RAX
                call      ghi
                jmp short       L12
L59:            sub     RAX,8
                mov     RAX,[RAX]
                mov     ESI,offset _D3eh52CC7__ClassZ
                mov     RDI,RAX
                call    _d_dynamic_cast
                mov     -010h[RBP],RAX
                mov     RAX,-010h[RBP]
                mov     RDI,RAX
                call      ghi
                jmp short       L12
L7F:            call      mno
                jmp short       L12
L86:            leave
                ret

The calls to _d_dynamic cast appear to be redundant - shouldn't the value in RDX be sufficient? And why is there a 'default' call to _Unwind_Resume if RDX isn't an expected value? Shouldn't the personality routine simply not jump to the landing pad if none of the catch types are satisfied?
November 23, 2015
On 23 November 2015 at 18:31, Walter Bright via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> I'm struggling to understand dwarf EH, and figure it's a good idea to try and make it binary compatible with what gdc does, or at least not gratuitously different. If I use gdc to compile this:
>
> void foo1() {
>         abc();
>         try {
>                 def();
>         }
>         catch(DD t) {
>                 ghi(t);
>         }
>         catch(CC t) {
>                 ghi(t);
>         }
>         catch {
>                 mno();
>         }
>         jkl();
> }
>
> the code generated looks like this:
>
> _D3eh54foo1FZv:
>                 push    RBP
>                 mov     RBP,RSP
>                 sub     RSP,010h
>                 call      abc
>                 call      def
> L12:            call      jkl
>                 jmp short       L86
>                 cmp     RDX,2
>                 je      L59
>                 cmp     RDX,3
>                 je      L7F
>                 cmp     RDX,1
>                 je      L33
>                 mov     RDI,RAX
>                 call    _Unwind_Resume
> L33:            sub     RAX,8
>                 mov     RAX,[RAX]
>                 mov     ESI,offset _D3eh52DD7__ClassZ
>                 mov     RDI,RAX
>                 call    _d_dynamic_cast
>                 mov     -8[RBP],RAX
>                 mov     RAX,-8[RBP]
>                 mov     RDI,RAX
>                 call      ghi
>                 jmp short       L12
> L59:            sub     RAX,8
>                 mov     RAX,[RAX]
>                 mov     ESI,offset _D3eh52CC7__ClassZ
>                 mov     RDI,RAX
>                 call    _d_dynamic_cast
>                 mov     -010h[RBP],RAX
>                 mov     RAX,-010h[RBP]
>                 mov     RDI,RAX
>                 call      ghi
>                 jmp short       L12
> L7F:            call      mno
>                 jmp short       L12
> L86:            leave
>                 ret
>
> The calls to _d_dynamic cast appear to be redundant - shouldn't the value in RDX be sufficient? And why is there a 'default' call to _Unwind_Resume if RDX isn't an expected value? Shouldn't the personality routine simply not jump to the landing pad if none of the catch types are satisfied?
>


Yes, the _d_dynamic_cast is redundant.  This happened because the EH pointer was treated as an Object, then upcasted to the catch type via the normal convert() routines.  This is what caused the unnecessary call to _d_dynamic_cast.

This switch statement is generated by GCC itself, and it tries to be accommodating for all supported languages.  I imagine that the default case is there to support `catch(...)` in C++ code, however D has no notion of this construct, so what is instead generated is _Unwind_Resume to tell unwind to keep looking up the call chain.

In other words, the default case should never really happen in D code except in the event of a logic bug in the unwind EH personality function (or possibly corruption). If you feel it more appropriate, I don't see the harm in replacing it with whatever HLT or abort instruction you like. :-)


November 23, 2015
On 11/23/2015 10:07 AM, Iain Buclaw via Digitalmars-d wrote:
> Yes, the _d_dynamic_cast is redundant.  This happened because the EH pointer was
> treated as an Object, then upcasted to the catch type via the normal convert()
> routines.  This is what caused the unnecessary call to _d_dynamic_cast.
>
> This switch statement is generated by GCC itself, and it tries to be
> accommodating for all supported languages.  I imagine that the default case is
> there to support `catch(...)` in C++ code, however D has no notion of this
> construct, so what is instead generated is _Unwind_Resume to tell unwind to keep
> looking up the call chain.
>
> In other words, the default case should never really happen in D code except in
> the event of a logic bug in the unwind EH personality function (or possibly
> corruption). If you feel it more appropriate, I don't see the harm in replacing
> it with whatever HLT or abort instruction you like. :-)

Thanks, this helps a lot, and makes me a lot more comfortable with the notion that I understand what is going on. I won't generate the cast, then, and I'll use a HLT for the default.

BTW, are you working on supporting catching std::exception ?

My eevil plan is to get D exceptions working completely before trying to support std::exception.
November 23, 2015
On 23 November 2015 at 19:18, Walter Bright via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On 11/23/2015 10:07 AM, Iain Buclaw via Digitalmars-d wrote:
>
>> Yes, the _d_dynamic_cast is redundant.  This happened because the EH
>> pointer was
>> treated as an Object, then upcasted to the catch type via the normal
>> convert()
>> routines.  This is what caused the unnecessary call to _d_dynamic_cast.
>>
>> This switch statement is generated by GCC itself, and it tries to be
>> accommodating for all supported languages.  I imagine that the default
>> case is
>> there to support `catch(...)` in C++ code, however D has no notion of this
>> construct, so what is instead generated is _Unwind_Resume to tell unwind
>> to keep
>> looking up the call chain.
>>
>> In other words, the default case should never really happen in D code
>> except in
>> the event of a logic bug in the unwind EH personality function (or
>> possibly
>> corruption). If you feel it more appropriate, I don't see the harm in
>> replacing
>> it with whatever HLT or abort instruction you like. :-)
>>
>
> Thanks, this helps a lot, and makes me a lot more comfortable with the notion that I understand what is going on. I won't generate the cast, then, and I'll use a HLT for the default.
>
> BTW, are you working on supporting catching std::exception ?
>
> My eevil plan is to get D exceptions working completely before trying to support std::exception.
>

Actively?  No.  First comes 2.067, which will have to be updated *as is* without the visitor conversions.

I will need to adjust *my* personality function to be more graceful for handling foreign exceptions.  After that, I can look into C++ typeinfo mangling.  It's just normal C++ mangling with a _ZT prefix, no? :-)

Also, I notice that you are using an older version of GDC.  That version you're using doesn't support exception chaining.  To get that working I had to invent a callback __gdc_begin_catch() which cleans up the chained exceptions list.


November 23, 2015
On Monday, 23 November 2015 at 17:31:51 UTC, Walter Bright wrote:
> The calls to _d_dynamic cast appear to be redundant - shouldn't the value in RDX be sufficient?

This is indeed the case, but of course you need to know in which order the compiler backend wrote the type info entries to the tables. Maybe at the time there didn't exist an intrinsic for that in GDC or something like that.

This is how the function looks in LDC (on OS X, but the libunwind "client"-side code is very similar):

---
0000000100000a40 <__D5test24foo1FZv>:
   100000a40:   53                      push   rbx
   100000a41:   e8 ca fe ff ff          call   100000910 <__D4test3abcFZv>
   100000a46:   e8 d5 fe ff ff          call   100000920 <__D4test3defFZv>
   100000a4b:   5b                      pop    rbx
   100000a4c:   e9 ef fe ff ff          jmp    100000940 <__D4test3jklFZv>
   100000a51:   48 89 c3                mov    rbx,rax
   100000a54:   83 fa 03                cmp    edx,0x3
   100000a57:   74 05                   je     100000a5e <__D5test24foo1FZv+0x1e>
   100000a59:   83 fa 02                cmp    edx,0x2
   100000a5c:   75 0f                   jne    100000a6d <__D5test24foo1FZv+0x2d>
   100000a5e:   e8 5d ff 00 00          call   1000109c0 <__d_eh_enter_catch>
   100000a63:   48 8b 3b                mov    rdi,QWORD PTR [rbx]
   100000a66:   e8 c5 fe ff ff          call   100000930 <__D4test3ghiFC4test2CCZv>
   100000a6b:   eb de                   jmp    100000a4b <__D5test24foo1FZv+0xb>
   100000a6d:   83 fa 01                cmp    edx,0x1
   100000a70:   75 10                   jne    100000a82 <__D5test24foo1FZv+0x42>
   100000a72:   e8 49 ff 00 00          call   1000109c0 <__d_eh_enter_catch>
   100000a77:   e8 d4 fe ff ff          call   100000950 <__D4test3mnoFZv>
   100000a7c:   5b                      pop    rbx
   100000a7d:   e9 be fe ff ff          jmp    100000940 <__D4test3jklFZv>
   100000a82:   48 89 df                mov    rdi,rbx
   100000a85:   e8 16 ff 00 00          call   1000109a0 <__d_eh_resume_unwind>
---

> And why is there a 'default' call to _Unwind_Resume if RDX isn't an expected value? Shouldn't the personality routine simply not jump to the landing pad if none of the catch types are satisfied?

The reason LDC emits the __d_eh_resume_unwind call all the time is because it is needed as soon as there is a cleanup involved anyway, and so far I was just too lazy to optimize the extra branch away in the special case that there are no cleanups.

 — David
November 23, 2015
On 23 November 2015 at 19:32, David Nadlinger via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Monday, 23 November 2015 at 17:31:51 UTC, Walter Bright wrote:
>
>> And why is there a 'default' call to _Unwind_Resume if RDX isn't an expected value? Shouldn't the personality routine simply not jump to the landing pad if none of the catch types are satisfied?
>>
>
> The reason LDC emits the __d_eh_resume_unwind call all the time is because it is needed as soon as there is a cleanup involved anyway, and so far I was just too lazy to optimize the extra branch away in the special case that there are no cleanups.
>
>
We seem to be doing very similar things here.


November 23, 2015
On 11/23/2015 10:31 AM, Iain Buclaw via Digitalmars-d wrote:
> I will need to adjust *my* personality function to be more graceful for handling
> foreign exceptions.  After that, I can look into C++ typeinfo mangling.  It's
> just normal C++ mangling with a _ZT prefix, no? :-)

I think so, but I haven't looked.

> Also, I notice that you are using an older version of GDC.

It's the one I installed recently on Ubuntu with:

    sudo apt-get install gdc

> That version you're
> using doesn't support exception chaining.  To get that working I had to invent a
> callback __gdc_begin_catch() which cleans up the chained exceptions list.

Could you please invent it as Boost licensed code, so I can simply incorporate it?

November 23, 2015
On 11/23/2015 10:32 AM, David Nadlinger wrote:
> This is how the function looks in LDC (on OS X, but the libunwind "client"-side
> code is very similar):
>
> ---
> 0000000100000a40 <__D5test24foo1FZv>:
>     100000a40:   53                      push   rbx
>     100000a41:   e8 ca fe ff ff          call   100000910 <__D4test3abcFZv>
>     100000a46:   e8 d5 fe ff ff          call   100000920 <__D4test3defFZv>
>     100000a4b:   5b                      pop    rbx
>     100000a4c:   e9 ef fe ff ff          jmp    100000940 <__D4test3jklFZv>
>     100000a51:   48 89 c3                mov    rbx,rax
>     100000a54:   83 fa 03                cmp    edx,0x3
>     100000a57:   74 05                   je     100000a5e <__D5test24foo1FZv+0x1e>
>     100000a59:   83 fa 02                cmp    edx,0x2
>     100000a5c:   75 0f                   jne    100000a6d <__D5test24foo1FZv+0x2d>
>     100000a5e:   e8 5d ff 00 00          call   1000109c0 <__d_eh_enter_catch>
>     100000a63:   48 8b 3b                mov    rdi,QWORD PTR [rbx]
>     100000a66:   e8 c5 fe ff ff          call   100000930
> <__D4test3ghiFC4test2CCZv>
>     100000a6b:   eb de                   jmp    100000a4b <__D5test24foo1FZv+0xb>
>     100000a6d:   83 fa 01                cmp    edx,0x1
>     100000a70:   75 10                   jne    100000a82 <__D5test24foo1FZv+0x42>
>     100000a72:   e8 49 ff 00 00          call   1000109c0 <__d_eh_enter_catch>
>     100000a77:   e8 d4 fe ff ff          call   100000950 <__D4test3mnoFZv>
>     100000a7c:   5b                      pop    rbx
>     100000a7d:   e9 be fe ff ff          jmp    100000940 <__D4test3jklFZv>
>     100000a82:   48 89 df                mov    rdi,rbx
>     100000a85:   e8 16 ff 00 00          call   1000109a0 <__d_eh_resume_unwind>
> ---

The code looks quite good. I've been trying to adjust things, however, so there are no pushes and pops in the code, trying to preallocate everything needed in the function prolog.


>> And why is there a 'default' call to _Unwind_Resume if RDX isn't an expected
>> value? Shouldn't the personality routine simply not jump to the landing pad if
>> none of the catch types are satisfied?
>
> The reason LDC emits the __d_eh_resume_unwind call all the time is because it is
> needed as soon as there is a cleanup involved anyway, and so far I was just too
> lazy to optimize the extra branch away in the special case that there are no
> cleanups.

dmd rewrites try-catch-finally into try-{try-catch}-finally, which makes it easier to generate code, because fewer special cases and fewer bugs. I've become a big fan of that technique :-)

November 23, 2015
On Monday, 23 November 2015 at 21:05:29 UTC, Walter Bright wrote:
> dmd rewrites try-catch-finally into try-{try-catch}-finally, which makes it easier to generate code, because fewer special cases and fewer bugs. I've become a big fan of that technique :-)

Wouldn't that makes unwinding slower because one need to go through several landing pads ?

November 23, 2015
On 11/23/2015 1:32 PM, deadalnix wrote:
> On Monday, 23 November 2015 at 21:05:29 UTC, Walter Bright wrote:
>> dmd rewrites try-catch-finally into try-{try-catch}-finally, which makes it
>> easier to generate code, because fewer special cases and fewer bugs. I've
>> become a big fan of that technique :-)
>
> Wouldn't that makes unwinding slower because one need to go through several
> landing pads ?
>

Yes. But if you're choked by unwinding speed, you're doing it wrong.
« First   ‹ Prev
1 2