www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Use C++ exception model in D

reply Jacob Carlborg <doob me.com> writes:
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
Apr 07 2014
parent reply Iain Buclaw <ibuclaw gdcproject.org> writes:
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.
Apr 08 2014
parent reply Jacob Carlborg <doob me.com> writes:
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
Apr 08 2014
next sibling parent reply Iain Buclaw <ibuclaw gdcproject.org> writes:
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. :)
Apr 08 2014
parent Jacob Carlborg <doob me.com> writes:
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
Apr 08 2014
prev sibling parent reply "David Nadlinger" <code klickverbot.at> writes:
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
Apr 08 2014
next sibling parent reply Brad Roberts <braddr puremagic.com> writes:
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.
Apr 08 2014
parent reply "David Nadlinger" <code klickverbot.at> writes:
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
Apr 08 2014
next sibling parent reply Brad Roberts <braddr puremagic.com> writes:
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.
Apr 08 2014
parent reply "David Nadlinger" <code klickverbot.at> writes:
On Tuesday, 8 April 2014 at 20:07:09 UTC, Brad Roberts wrote:
 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.
The problem is that there are only very few people who are familiar enough with the DMD backend to work on such changes. And quite understandably so – to be quite honest, I myself am not particularly interested in spending a nontrivial amount of time to get acquainted with a dated, sparsely documented codebase that I will not be able to use in other projects. It certainly is an interesting piece of software and getting acquainted with its internals is probably a nice intellectual exercise, but so far, most people interested in tackling the ABI situation are already busy with another backend. Sure, one way to go about this would be to just sit down and implement a common ABI in GDC and LDC (hackathon at London/Zürich/… anyone?) and then hope that some random contributor turns up later on and fixes DMD to conform to the standard we agreed on. But this does not necessarily strike me as a productive gamble… David
Apr 09 2014
parent reply "Daniel Murphy" <yebbliesnospam gmail.com> writes:
"David Nadlinger"  wrote in message 
news:bivyxqzewidjylastzbs forum.dlang.org...

 Sure, one way to go about this would be to just sit down and implement a 
 common ABI in GDC and LDC (hackathon at London/Zürich/… anyone?) and then 
 hope that some random contributor turns up later on and fixes DMD to 
 conform to the standard we agreed on. But this does not necessarily strike 
 me as a productive gamble…
You could always go the other way and change GDC and LDC to match what DMD does. :)
Apr 09 2014
parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Wed, 9 Apr 2014 23:11:08 +1000
schrieb "Daniel Murphy" <yebbliesnospam gmail.com>:

 "David Nadlinger"  wrote in message=20
 news:bivyxqzewidjylastzbs forum.dlang.org...
=20
 Sure, one way to go about this would be to just sit down and implement =
a=20
 common ABI in GDC and LDC (hackathon at London/Z=C3=BCrich/=E2=80=A6 an=
yone?) and then=20
 hope that some random contributor turns up later on and fixes DMD to=20
 conform to the standard we agreed on. But this does not necessarily str=
ike=20
 me as a productive gamble=E2=80=A6
=20 You could always go the other way and change GDC and LDC to match what DM=
D=20
 does. :)=20
And precisely that is not always possible. E.g. GCC developers have decided against "naked" asm functions. And this out-contract-accessing-caller-scope thing that David mentioned looks like it could pose trouble with LLVM and/or GCC. A common ground has to be found that likely changes the ABI in all 3 compilers. DMD is actually least restricted by the lack of vetoing "upstream" developers :) --=20 Marco
Apr 09 2014
parent reply Iain Buclaw <ibuclaw gdcproject.org> writes:
On 9 April 2014 14:54, Marco Leise <Marco.Leise gmx.de> wrote:
 Am Wed, 9 Apr 2014 23:11:08 +1000
 schrieb "Daniel Murphy" <yebbliesnospam gmail.com>:

 "David Nadlinger"  wrote in message
 news:bivyxqzewidjylastzbs forum.dlang.org...

 Sure, one way to go about this would be to just sit down and implement a
 common ABI in GDC and LDC (hackathon at London/Zürich/... anyone?) and then
 hope that some random contributor turns up later on and fixes DMD to
 conform to the standard we agreed on. But this does not necessarily strike
 me as a productive gamble...
You could always go the other way and change GDC and LDC to match what DMD does. :)
And precisely that is not always possible. E.g. GCC developers have decided against "naked" asm functions. And this
Naked exists, just not for x86. :o)
 out-contract-accessing-caller-scope thing that David mentioned
 looks like it could pose trouble with LLVM and/or GCC.
It *does* pose trouble. I've just never pointed it out before because GDC builds the stack frame in the front-end (the middle end never got it right anyway because of delegates). The one thing we *do* rely on is that the D front-end marks all closure vars correctly, even if a closure is not required for the function.
 A common ground has to be found that likely changes the ABI in
 all 3 compilers. DMD is actually least restricted by the lack
 of vetoing "upstream" developers :)
I have only vetoed features that are tied to a specific architecture. This is not unreasonable in my eyes.
Apr 09 2014
parent Marco Leise <Marco.Leise gmx.de> writes:
Am Wed, 9 Apr 2014 15:32:56 +0100
schrieb Iain Buclaw <ibuclaw gdcproject.org>:

 On 9 April 2014 14:54, Marco Leise <Marco.Leise gmx.de> wrote:
 Am Wed, 9 Apr 2014 23:11:08 +1000
 schrieb "Daniel Murphy" <yebbliesnospam gmail.com>:

 You could always go the other way and change GDC and LDC to match what DMD
 does. :)
And precisely that is not always possible. E.g. GCC developers have decided against "naked" asm functions. And this
Naked exists, just not for x86. :o)
That slipped my mind, possibly because I still think of D as a programming language for x86 (like Delphi).
 A common ground has to be found that likely changes the ABI in
 all 3 compilers. DMD is actually least restricted by the lack
 of vetoing "upstream" developers :)
I have only vetoed features that are tied to a specific architecture. This is not unreasonable in my eyes.
I meant upstream more literally than I made it look. I.e. even if everyone involved with D found some ABI detail a good idea, it could be that the required changes to the backend, like naked asm for x86 cannot be made by you or David, but require the good will of the core team of the respective backend. And yes, it is good to now and then look beyond x86. The developments were in favour of D it seems. 16-bit chips dimish, TLS became available on Mac OS X. Possibly later Walter's "better C" will be discussed again to not overload simple platforms with GC, exceptions and TLS :) -- Marco
Apr 09 2014
prev sibling next sibling parent reply Iain Buclaw <ibuclaw gdcproject.org> writes:
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
Apr 08 2014
parent reply "David Nadlinger" <code klickverbot.at> writes:
On Tuesday, 8 April 2014 at 22:19:06 UTC, Iain Buclaw wrote:
 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.
What are you referring to here specifically? David
Apr 09 2014
parent Iain Buclaw <ibuclaw gdcproject.org> writes:
On 9 April 2014 09:23, David Nadlinger <code klickverbot.at> wrote:
 On Tuesday, 8 April 2014 at 22:19:06 UTC, Iain Buclaw wrote:
 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.
What are you referring to here specifically?
LTR side effects on array ops. :o)
Apr 09 2014
prev sibling next sibling parent Iain Buclaw <ibuclaw gdcproject.org> writes:
On 8 April 2014 21:06, Brad Roberts <braddr puremagic.com> wrote:
 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.
Hopefully I've convinced Daniel to fix the va_args at least.
Apr 08 2014
prev sibling parent Dan Olson <zans.is.for.cans yahoo.com> writes:
"David Nadlinger" <code klickverbot.at> writes:

 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.
I tried handling foreign exceptions back in Feb with the sjlj personality function I am using in LDC for iOS. Well, at least doing cleanups so that a objc/c++ exception could bubble up and D could call dtors and finally blocks. It was mostly working but I wanted to make progress on other stuff so shelved it since I had normal D sjlj eh working. -- Dan
Apr 09 2014
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 08/04/14 14:03, 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).
A middle ground would help. In the D/Objective-C implementation there is already an exception bridge for 32bit. The 32bit implementation uses setjmp and longjmp. For transferring D exceptions to Objective-C the compiler sets up a try-catch. Then there's a subclass of NSException (the root exception class in Objective-C) which wraps a D Throwable. This NSException is then thrown using the Objective-C runtime function for throwing exceptions. For transferring exceptions in the other direction bascilly the same thing happens. The compiler uses setjmp and longjmp to catch the Objective-C exception. This is then wrapped as a D exception, a subclass of Throwable, and thrown using the D runtime function for throwing exceptions. For 64bit, Objective-C uses the same exception handling as C++. So I need to somehow be able to catch Objective-C exceptions and Objective-C need to be able to catch D exceptions. Although I still expect to need to wrap the exceptions, since D code won't be expecting to catch instances of NSException, which doesn't inherit from Throwable. Same on the Objective-C side. If D would use the C++ exception handling model I hope that the implementation would be a lot simpler. -- /Jacob Carlborg
Apr 09 2014
next sibling parent reply "David Nadlinger" <code klickverbot.at> writes:
On Wednesday, 9 April 2014 at 07:19:54 UTC, Jacob Carlborg wrote:
 For 64bit, Objective-C uses the same exception handling as C++. 
 So I need to somehow be able to catch Objective-C exceptions 
 and Objective-C need to be able to catch D exceptions. Although 
 I still expect to need to wrap the exceptions, since D code 
 won't be expecting to catch instances of NSException, which 
 doesn't inherit from Throwable. Same on the Objective-C side.

 If D would use the C++ exception handling model I hope that the 
 implementation would be a lot simpler.
So, in the last paragraph, you are specifically referring to DMD on x86_64? David
Apr 09 2014
parent reply Jacob Carlborg <doob me.com> writes:
On 2014-04-09 10:27, David Nadlinger wrote:

 So, in the last paragraph, you are specifically referring to DMD on x86_64?
x86_64 yes, not necessarily only for DMD. I thought if DMD, LDC and GDC all used the same exception handling model and the same as C++ it would be easier. Especially for implementing support for Objective-C exceptions, which is why initially started this thread. I don't know which exception model iOS 64bit uses for Objective-C. If it uses the C++ exception model it would apply for that platform as well. -- /Jacob Carlborg
Apr 09 2014
parent reply "David Nadlinger" <code klickverbot.at> writes:
On Wednesday, 9 April 2014 at 16:48:54 UTC, Jacob Carlborg wrote:
 x86_64 yes, not necessarily only for DMD. I thought if DMD, LDC 
 and GDC all used the same exception handling model and the same 
 as C++ it would be easier. Especially for implementing support 
 for Objective-C exceptions, which is why initially started this 
 thread.
They don't. GDC and LDC use libunwind, whereas DMD uses its own custom EH implementation. With GDC and LDC, you'd just need to add your code to handle Objective-C exceptions to the personality functions. libunwind exceptions have a "type"/"source language" field, and by default most implementations either ignore unknown exception types or abort on encountering them. David
Apr 09 2014
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2014-04-09 19:27, David Nadlinger wrote:

 They don't. GDC and LDC use libunwind, whereas DMD uses its own custom
 EH implementation.
That's what I want then, for all implementations to use libunwind.
 With GDC and LDC, you'd just need to add your code to handle Objective-C
 exceptions to the personality functions. libunwind exceptions have a
 "type"/"source language" field, and by default most implementations
 either ignore unknown exception types or abort on encountering them.
That's what I was hoping. -- /Jacob Carlborg
Apr 09 2014
prev sibling next sibling parent Michel Fortin <michel.fortin michelf.ca> writes:
On 2014-04-09 17:27:55 +0000, "David Nadlinger" <code klickverbot.at> said:

 On Wednesday, 9 April 2014 at 16:48:54 UTC, Jacob Carlborg wrote:
 x86_64 yes, not necessarily only for DMD. I thought if DMD, LDC and GDC 
 all used the same exception handling model and the same as C++ it would 
 be easier. Especially for implementing support for Objective-C 
 exceptions, which is why initially started this thread.
They don't. GDC and LDC use libunwind, whereas DMD uses its own custom EH implementation. With GDC and LDC, you'd just need to add your code to handle Objective-C exceptions to the personality functions. libunwind exceptions have a "type"/"source language" field, and by default most implementations either ignore unknown exception types or abort on encountering them.
Maybe the right course of action would be to just ignore Objective-C exceptions in 64-bit DMD and finish the rest of D/Objective-C. The day D/Objective-C is ported to GDC and LDC, it should be much easier to make exceptions work there. The funny thing is that within Cocoa exceptions are usually reserved for logic errors (array out of bound, method calls with unknown selector, assertion errors, etc.). That's the kind of error we consider unrecoverable when they happen in D code. So I think people can manage without Objective-C exceptions for some time. Given what I wrote above, I'll also argue that it's not a wise move to support exceptions in D/Objective-C with the legacy runtime even though I implemented it. Because the legacy runtime uses setjmp/longjmp for exceptions, try blocks in a function that calls extern(Objective-C) functions are costly. And the compiler has to implicitly add those costly try blocks to wrap/unwrap exception objects to prevent unwinding of the wrong kind from leaving the current function. It was fun to implement, but it's also the most intrusive changes D/Objective-C makes to the frontend, and a big parts of the additions to druntime. If we plan to support mixed unwind mechanisms some day it might be useful to keep, because the logic for bridging between two or more unwinding systems is all there. Otherwise I'd probably scrap the whole exception wrapping/unwrapping thing. I doubt the performance cost is worth it, and I doubt the maintenance cost for the additional complexity is worth it. The legacy Objective-C runtime is mostly gone from Apple's ecosystem anyway. -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Apr 09 2014
prev sibling next sibling parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Wed, 09 Apr 2014 17:27:55 +0000
schrieb "David Nadlinger" <code klickverbot.at>:

 They don't. GDC and LDC use libunwind, whereas DMD uses its own 
 custom EH implementation.
Is libunwind somehow copied verbatim in the GDC/LDC sources? Because I'm pretty sure I only installed it 2 weeks ago when some benchmark tool from Google asked me to install it. -- Marco
Apr 09 2014
parent reply "David Nadlinger" <code klickverbot.at> writes:
On Wednesday, 9 April 2014 at 21:19:46 UTC, Marco Leise wrote:
 Am Wed, 09 Apr 2014 17:27:55 +0000
 schrieb "David Nadlinger" <code klickverbot.at>:

 They don't. GDC and LDC use libunwind, whereas DMD uses its 
 own custom EH implementation.
Is libunwind somehow copied verbatim in the GDC/LDC sources? Because I'm pretty sure I only installed it 2 weeks ago when some benchmark tool from Google asked me to install it.
The implementation is part of the runtime libraries shipped by GCC (and installed by default on every system). David
Apr 09 2014
parent Iain Buclaw <ibuclaw gdcproject.org> writes:
On 9 April 2014 23:55, David Nadlinger <code klickverbot.at> wrote:
 On Wednesday, 9 April 2014 at 21:19:46 UTC, Marco Leise wrote:
 Am Wed, 09 Apr 2014 17:27:55 +0000
 schrieb "David Nadlinger" <code klickverbot.at>:

 They don't. GDC and LDC use libunwind, whereas DMD uses its own custom EH
 implementation.
Is libunwind somehow copied verbatim in the GDC/LDC sources? Because I'm pretty sure I only installed it 2 weeks ago when some benchmark tool from Google asked me to install it.
The implementation is part of the runtime libraries shipped by GCC (and installed by default on every system).
Just look for something like /usr/lib/gcc/<xxx>/<x.x>/include if you've installed the libgcc-dev files.
Apr 09 2014
prev sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 9 April 2014 at 17:27:56 UTC, David Nadlinger wrote:
 On Wednesday, 9 April 2014 at 16:48:54 UTC, Jacob Carlborg 
 wrote:
 x86_64 yes, not necessarily only for DMD. I thought if DMD, 
 LDC and GDC all used the same exception handling model and the 
 same as C++ it would be easier. Especially for implementing 
 support for Objective-C exceptions, which is why initially 
 started this thread.
They don't. GDC and LDC use libunwind, whereas DMD uses its own custom EH implementation. With GDC and LDC, you'd just need to add your code to handle Objective-C exceptions to the personality functions. libunwind exceptions have a "type"/"source language" field, and by default most implementations either ignore unknown exception types or abort on encountering them. David
The C++ personality function from GCC does not catch, but do the cleanup on foreign exceptions. That sound like the right behavior to me.
Apr 09 2014
parent reply Jacob Carlborg <doob me.com> writes:
On 2014-04-10 08:53, deadalnix wrote:

 The C++ personality function from GCC does not catch, but do the cleanup
 on foreign exceptions. That sound like the right behavior to me.
As far as I understand the cleaning is only a part of what personality function does. The first thing it does is check if the thrown exception can be handled. Like determine if it's a C++ exception or some other exception. If I recall correctly, it also determines if and where to resume unwinding, where to find catch blocks and so on. This [1] series of blog posts gives a pretty good understanding of how C++ exceptions work under the hood, for those that don't want to read the ABI documentation. [1] http://monoinfinito.wordpress.com/series/exception-handling-in-c/ -- /Jacob Carlborg
Apr 10 2014
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 10 April 2014 at 19:23:12 UTC, Jacob Carlborg wrote:
 On 2014-04-10 08:53, deadalnix wrote:

 The C++ personality function from GCC does not catch, but do 
 the cleanup
 on foreign exceptions. That sound like the right behavior to 
 me.
As far as I understand the cleaning is only a part of what personality function does. The first thing it does is check if the thrown exception can be handled. Like determine if it's a C++ exception or some other exception. If I recall correctly, it also determines if and where to resume unwinding, where to find catch blocks and so on. This [1] series of blog posts gives a pretty good understanding of how C++ exceptions work under the hood, for those that don't want to read the ABI documentation. [1] http://monoinfinito.wordpress.com/series/exception-handling-in-c/
You want to look at libstdc++-v3/libsupc++/eh_personality.cc in gcc's source code. The personality function test if the exception is a C++ exception, in which case the regular flow apply. If not, the foreign_exception flag is set, and some behavior are altered. Basically, for what we are concerned with D, only cleanup will be executed (the filter part is irrelevant to D).
Apr 10 2014
parent reply Jacob Carlborg <doob me.com> writes:
On 11/04/14 00:05, deadalnix wrote:

 You want to look at libstdc++-v3/libsupc++/eh_personality.cc in gcc's
 source code.
If I'm to look at some source code I rather look at libc++abi from LLVM.
 The personality function test if the exception is a C++ exception, in
 which case the regular flow apply. If not, the foreign_exception flag is
 set, and some behavior are altered. Basically, for what we are concerned
 with D, only cleanup will be executed (the filter part is irrelevant to D).
Why is the filter part irrelevant? -- /Jacob Carlborg
Apr 10 2014
parent "deadalnix" <deadalnix gmail.com> writes:
On Friday, 11 April 2014 at 06:29:37 UTC, Jacob Carlborg wrote:
 Why is the filter part irrelevant?
filter is "catch everything but.." kind of clause. The semantic do not exists in D, so we don't really care.
Apr 12 2014
prev sibling parent reply Iain Buclaw <ibuclaw gdcproject.org> writes:
On 9 April 2014 08:19, Jacob Carlborg <doob me.com> wrote:
 On 08/04/14 14:03, 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).
A middle ground would help. In the D/Objective-C implementation there is already an exception bridge for 32bit. The 32bit implementation uses setjmp and longjmp.
The "middle-ground" would be us handling Objective-C foreign exceptions in our EH personality function.
Apr 09 2014
parent Jacob Carlborg <doob me.com> writes:
On 2014-04-09 11:52, Iain Buclaw wrote:

 The "middle-ground" would be us handling Objective-C foreign
 exceptions in our EH personality function.
Yes, exactly. -- /Jacob Carlborg
Apr 09 2014