Jump to page: 1 24  
Page
Thread overview
Use C++ exception model in D
Apr 08, 2014
Jacob Carlborg
Apr 08, 2014
Iain Buclaw
Apr 08, 2014
Jacob Carlborg
Apr 08, 2014
Iain Buclaw
Apr 08, 2014
Jacob Carlborg
Apr 08, 2014
David Nadlinger
Apr 08, 2014
Brad Roberts
Apr 08, 2014
David Nadlinger
Apr 08, 2014
Brad Roberts
Apr 09, 2014
David Nadlinger
Apr 09, 2014
Daniel Murphy
Apr 09, 2014
Marco Leise
Apr 09, 2014
Iain Buclaw
Apr 09, 2014
Marco Leise
Apr 08, 2014
Iain Buclaw
Apr 09, 2014
David Nadlinger
Apr 09, 2014
Iain Buclaw
Apr 08, 2014
Iain Buclaw
Apr 09, 2014
Dan Olson
Apr 09, 2014
Jacob Carlborg
Apr 09, 2014
David Nadlinger
Apr 09, 2014
Jacob Carlborg
Apr 09, 2014
David Nadlinger
Apr 09, 2014
Jacob Carlborg
Apr 09, 2014
Michel Fortin
Apr 09, 2014
Marco Leise
Apr 09, 2014
David Nadlinger
Apr 10, 2014
Iain Buclaw
Apr 10, 2014
deadalnix
Apr 10, 2014
Jacob Carlborg
Apr 10, 2014
deadalnix
Apr 11, 2014
Jacob Carlborg
Apr 12, 2014
deadalnix
Apr 09, 2014
Iain Buclaw
Apr 09, 2014
Jacob Carlborg
April 08, 2014
How feasible would it be if D moved to using the same exception model as C++?

The advantage of this would be that D exceptions would become compatible with C++ exceptions. It would also mean that D exceptions would become compatible with Objective-C exceptions on OS X 64bit, since they use the same exception model as C++. I'm not sure, but if GDC and LDC already use the C++ exception model it would probably make their lives easier as well.

The disadvantages are that someone needs to implement it. I'm not sure, but it may also break existing code.

Note, I'm mostly interested in Posix 64bit.

-- 
/Jacob Carlborg
April 08, 2014
On 8 April 2014 07:36, Jacob Carlborg <doob@me.com> wrote:
> How feasible would it be if D moved to using the same exception model as C++?
>
> The advantage of this would be that D exceptions would become compatible with C++ exceptions. It would also mean that D exceptions would become compatible with Objective-C exceptions on OS X 64bit, since they use the same exception model as C++. I'm not sure, but if GDC and LDC already use the C++ exception model it would probably make their lives easier as well.
>
> The disadvantages are that someone needs to implement it. I'm not sure, but it may also break existing code.
>
> Note, I'm mostly interested in Posix 64bit.
>

We use libunwind, which is the same as what the C++ exception model uses, but we implement our own EH routines on-top of that to handle D exceptions specifically.  This is typically what all gcc languages with EH do.
April 08, 2014
On 08/04/14 09:51, Iain Buclaw wrote:

> We use libunwind, which is the same as what the C++ exception model
> uses, but we implement our own EH routines on-top of that to handle D
> exceptions specifically.  This is typically what all gcc languages
> with EH do.

Is there a reason to not use the same model, or what's required to be compatible?

-- 
/Jacob Carlborg
April 08, 2014
On 8 April 2014 11:08, Jacob Carlborg <doob@me.com> wrote:
> On 08/04/14 09:51, Iain Buclaw wrote:
>
>> We use libunwind, which is the same as what the C++ exception model uses, but we implement our own EH routines on-top of that to handle D exceptions specifically.  This is typically what all gcc languages with EH do.
>
>
> Is there a reason to not use the same model, or what's required to be compatible?
>

Yes, D exceptions are not packed in the same way as C++. Go and Java also have subtly different ways of passing language-specific data to libunwind.

The closest language D is to is Java, in that they both put in the Object being thrown immediately before the generic libunwind exception header. That's where the similarities end. :)
April 08, 2014
On 08/04/14 12:19, Iain Buclaw wrote:

> Yes, D exceptions are not packed in the same way as C++. Go and Java
> also have subtly different ways of passing language-specific data to
> libunwind.

I do understand that they are different, but why design them like that from the beginning?

-- 
/Jacob Carlborg
April 08, 2014
On Tuesday, 8 April 2014 at 10:08:24 UTC, Jacob Carlborg wrote:
> Is there a reason to not use the same model, or what's required to be compatible?

In short, the reason not to use the same "model" (you could argue that the model is the same, as only the personality functions differ) is that the exception unwinder is intimately tied to both the target language ABI and semantics.

For example, all unwinders need to handle the run-time type information for the exception object to correctly dispatch it. And while e.g. the GNU C++ unwinding implementation needs to pull shenanigans to implement the crazy C++ exception lifetime model (cf. catching by reference vs. by value) and enforce throws(...) specifications, the D unwinder needs to understand the difference between Exception and Error and correctly implement exception chaining.

Now, of course, it is possible to find a middle ground that works as a basis for virtually all languages. In fact, I'd argue that SEH for Windows actually provides such a layer, and libunwind does too. For example, a proper implementation of a libunwind personality function allows you to check whether a given exception originated in your own language, and just pass it on otherwise (such that e.g. C++ exception just bubble through a layer of D code). In theory, it would e.g. also be possible to wrap foreign exceptions in e.g. D Throwable objects to make them catchable in D code. But the lifetime of the foreign object is virtually impossible to get right in the general case, and the benefits of wrapping exceptions like this have turned out not to be worth it, because it is hard to handle them in a sensible way in the receiving language (DMD actually does – did? – something like this on Win32).

David
April 08, 2014
On 4/8/14, 5:03 AM, David Nadlinger wrote:
> On Tuesday, 8 April 2014 at 10:08:24 UTC, Jacob Carlborg wrote:
>> Is there a reason to not use the same model, or what's required to be compatible?
>
> In short, the reason not to use the same "model" (you could argue that the model is the same, as
> only the personality functions differ) is that the exception unwinder is intimately tied to both the
> target language ABI and semantics.
>
> For example, all unwinders need to handle the run-time type information for the exception object to
> correctly dispatch it. And while e.g. the GNU C++ unwinding implementation needs to pull shenanigans
> to implement the crazy C++ exception lifetime model (cf. catching by reference vs. by value) and
> enforce throws(...) specifications, the D unwinder needs to understand the difference between
> Exception and Error and correctly implement exception chaining.
>
> Now, of course, it is possible to find a middle ground that works as a basis for virtually all
> languages. In fact, I'd argue that SEH for Windows actually provides such a layer, and libunwind
> does too. For example, a proper implementation of a libunwind personality function allows you to
> check whether a given exception originated in your own language, and just pass it on otherwise (such
> that e.g. C++ exception just bubble through a layer of D code). In theory, it would e.g. also be
> possible to wrap foreign exceptions in e.g. D Throwable objects to make them catchable in D code.
> But the lifetime of the foreign object is virtually impossible to get right in the general case, and
> the benefits of wrapping exceptions like this have turned out not to be worth it, because it is hard
> to handle them in a sensible way in the receiving language (DMD actually does – did? – something
> like this on Win32).
>
> David

I think, for a mixed language application, that the important part is proper object lifetime management more than being able to catch exceptions from different languages.  When unwinding a c++ exception that has stack frames intermixed with D, destructors need to be executed appropriately, and vice versa.

This is also an important part of having abi compatibility between D compilers, something which we don't have today but really must have eventually.. hopefully not years away.
April 08, 2014
On Tuesday, 8 April 2014 at 18:55:35 UTC, Brad Roberts wrote:
> I think, for a mixed language application, that the important part is proper object lifetime management more than being able to catch exceptions from different languages.  When unwinding a c++ exception that has stack frames intermixed with D, destructors need to be executed appropriately, and vice versa.

I haven't actually tried to do this, but in theory, this should be the easy part with libunwind. You just ignore foreign exceptions during the search phase (i.e. not catch them), and during the unwind phase, your own personality function is called again for cleanup regardless of the handler the stack actually unwinds to.

> This is also an important part of having abi compatibility between D compilers, something which we don't have today but really must have eventually.. hopefully not years away.

This really depends on somebody familiar with the DMD backend committing to going through with it. I think both on the GDC and LDC sides, there is agreement that we need to work on a common ABI. However, the whole thing would be somewhat of a futile effort without DMD on board as well.

On x86_64, ABI compatibility is not an unreasonable goal at all (and a very important one, in my opinion). There are some areas that will need a lot of careful spec'ing and likely entail changes in all three compilers, such as the construction of nested scopes. However, in some cases, e.g. exception unwinding, or proper variadic arguments, it's definitely the case that GDC and LDC would be easy to align, whereas DMD would have to give up its own bespoke solution. Does DMD still do things like magically accessing the scope of the parent function in in/out contract calls?

David
April 08, 2014
On 4/8/14, 12:56 PM, David Nadlinger wrote:
> On Tuesday, 8 April 2014 at 18:55:35 UTC, Brad Roberts wrote:
>> I think, for a mixed language application, that the important part is proper object lifetime
>> management more than being able to catch exceptions from different languages.  When unwinding a
>> c++ exception that has stack frames intermixed with D, destructors need to be executed
>> appropriately, and vice versa.
>
> I haven't actually tried to do this, but in theory, this should be the easy part with libunwind. You
> just ignore foreign exceptions during the search phase (i.e. not catch them), and during the unwind
> phase, your own personality function is called again for cleanup regardless of the handler the stack
> actually unwinds to.
>
>> This is also an important part of having abi compatibility between D compilers, something which we
>> don't have today but really must have eventually.. hopefully not years away.
>
> This really depends on somebody familiar with the DMD backend committing to going through with it. I
> think both on the GDC and LDC sides, there is agreement that we need to work on a common ABI.
> However, the whole thing would be somewhat of a futile effort without DMD on board as well.
>
> On x86_64, ABI compatibility is not an unreasonable goal at all (and a very important one, in my
> opinion). There are some areas that will need a lot of careful spec'ing and likely entail changes in
> all three compilers, such as the construction of nested scopes. However, in some cases, e.g.
> exception unwinding, or proper variadic arguments, it's definitely the case that GDC and LDC would
> be easy to align, whereas DMD would have to give up its own bespoke solution. Does DMD still do
> things like magically accessing the scope of the parent function in in/out contract calls?
>
> David

Most of the areas where DMD is 'odd' are a case of "I can't figure out the right way, so any way is better than no way".  That's particularly true for var args and eh.  I'm confident that pulls that fix these issues can and will be accepted.  I'm less confident that someone will volunteer to fix it, but it's something I care about.
April 08, 2014
On 8 April 2014 20:56, David Nadlinger <code@klickverbot.at> wrote:
> On Tuesday, 8 April 2014 at 18:55:35 UTC, Brad Roberts wrote:
>>
>> I think, for a mixed language application, that the important part is proper object lifetime management more than being able to catch exceptions from different languages.  When unwinding a c++ exception that has stack frames intermixed with D, destructors need to be executed appropriately, and vice versa.
>
>
> I haven't actually tried to do this, but in theory, this should be the easy part with libunwind. You just ignore foreign exceptions during the search phase (i.e. not catch them), and during the unwind phase, your own personality function is called again for cleanup regardless of the handler the stack actually unwinds to.
>
>
>> This is also an important part of having abi compatibility between D compilers, something which we don't have today but really must have eventually.. hopefully not years away.
>
>
> This really depends on somebody familiar with the DMD backend committing to going through with it. I think both on the GDC and LDC sides, there is agreement that we need to work on a common ABI. However, the whole thing would be somewhat of a futile effort without DMD on board as well.
>

Worse, there's even work that is complete for GDC that is critical for ARM support, but breaks ABI - in a positive way that means all targets behave as expected.  However DMD is impeding progress of this work.

The work I'm doing on GDB is somewhat similar in this regards in that what I initially thought would be a walk in the park for GDC turned out to be an almost re-think/write of the situation.  How you emit modules (we didn't), how you emit imported modules, selective imports, renamed imports, enums, methods, vtable layouts in debug, classifying structs, locations, locations, locations, special cases for _Dmain, symbol scope lookup hierachy, function overloading...  Most of which DMD programs may not see all benefits of because they emit debug info as if is C.


> On x86_64, ABI compatibility is not an unreasonable goal at all (and a very important one, in my opinion). There are some areas that will need a lot of careful spec'ing and likely entail changes in all three compilers, such as the construction of nested scopes. However, in some cases, e.g. exception unwinding, or proper variadic arguments, it's definitely the case that GDC and LDC would be easy to align, whereas DMD would have to give up its own bespoke solution. Does DMD still do things like magically accessing the scope of the parent function in in/out contract calls?
>

That magic is still there as I recall that the hacks for GDC custom static chains are still in place.

Regards
Iain
« First   ‹ Prev
1 2 3 4