www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Proposal: Exceptions and nogc

reply Walter Bright <newshound2 digitalmars.com> writes:
Problem
=======

Exceptions are assumed to be GC collected by the EH design, in that no
attempt is made to control copies or lifetimes. This dependency is not
a performance issue, as exceptions are presumed to be slow.

The issue is it impairs use of  nogc on any code that throws exceptions,
and prevents building D programs that do not link in the GC runtime.

To fix this, the allocation and destruction of the exception objects
must be completely controlled.

Solution
========

Using a ref counted solution brings with it a host of problems because
the compiler is not set up to ref count class object references, nor
is any existing code set up to deal with that.

Instead, rely on Exception objects having a single, trackable owner.

Create three druntime library functions,

1. allocate an Exception object
2. free an Exception object
3. copy (a.k.a. clone) an Exception object

Whether the implementations use malloc/free, or some other custom allocator,
is immaterial. The contents of the allocated object still need to be
subject to scanning by the GC.

throw Expression
----------------

The Expression is evaluated, and 'copy' is called to make the actual
Exception object that is thrown. If the Expression is:

    new Exception

then it is optimized to call 'allocate' instead.

catch (Exception e)
-------------------

'e' becomes implicitly 'scope', so 'e' cannot escape the
catch clause. At the exit of the catch clause, 'free' is
called on 'e'. If 'e' is rethrown, a 'copy' is made of it.

Chained Exceptions
------------------

These get 'free' called on them when the head of the chain
is free'd. The head of the chain owns these instances.
Access to these by user code needs to be protected by
'scope', and hence must be hidden behind an access function to
enforce that.

Copying Exceptions
------------------

There isn't any current mechanism to copy class objects. The
trouble comes in the form of any postblits that may be required
for fields. An initial solution is to disallow any Exception
objects with postblit fields. The eventual solution is to
auto-generate the copy code, like what is done for structs.

Legacy Code Breakage
--------------------

This will break an unknown amount of existing code.

Breakage will come in the form of:

1. dependency on identifying Exception objects by their addresses,
which won't work anymore because of the copying.
(good code shouldn't rely on this anyway)

2. leaking Exception objects from catch clauses (caught by
the compiler)

3. Disallowing Exception objects with postblit fields.

4. Catch objects being 'scope' will cause problems in that
everything done with those objects will also have to be 'scope'.
The most likely problem will be printing the objects which
relies on Object.toString() which is not 'scope'. One possible
solution is to force Throwable.toString() to be 'scope', which
will likely cause minimal disruption. Of course, compiling
with -dip1000 will disable such checking and can work in
the interim.

Conclusion
----------

The result of this should be no leaking memory, no need to link
in the GC, and memory safety.

References
----------

http://www.digitalmars.com/d/archives/digitalmars/D/Exceptions_in_nogc_code_299261.html
Apr 01
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 02/04/2017 6:16 AM, Walter Bright wrote:
 Problem
 =======

 Exceptions are assumed to be GC collected by the EH design, in that no
 attempt is made to control copies or lifetimes. This dependency is not
 a performance issue, as exceptions are presumed to be slow.

 The issue is it impairs use of  nogc on any code that throws exceptions,
 and prevents building D programs that do not link in the GC runtime.

 To fix this, the allocation and destruction of the exception objects
 must be completely controlled.

 Solution
 ========

 Using a ref counted solution brings with it a host of problems because
 the compiler is not set up to ref count class object references, nor
 is any existing code set up to deal with that.

 Instead, rely on Exception objects having a single, trackable owner.

 Create three druntime library functions,

 1. allocate an Exception object
 2. free an Exception object
 3. copy (a.k.a. clone) an Exception object

 Whether the implementations use malloc/free, or some other custom
 allocator,
 is immaterial. The contents of the allocated object still need to be
 subject to scanning by the GC.

 throw Expression
 ----------------

 The Expression is evaluated, and 'copy' is called to make the actual
 Exception object that is thrown. If the Expression is:

    new Exception

 then it is optimized to call 'allocate' instead.

 catch (Exception e)
 -------------------

 'e' becomes implicitly 'scope', so 'e' cannot escape the
 catch clause. At the exit of the catch clause, 'free' is
 called on 'e'. If 'e' is rethrown, a 'copy' is made of it.

 Chained Exceptions
 ------------------

 These get 'free' called on them when the head of the chain
 is free'd. The head of the chain owns these instances.
 Access to these by user code needs to be protected by
 'scope', and hence must be hidden behind an access function to
 enforce that.

 Copying Exceptions
 ------------------

 There isn't any current mechanism to copy class objects. The
 trouble comes in the form of any postblits that may be required
 for fields. An initial solution is to disallow any Exception
 objects with postblit fields. The eventual solution is to
 auto-generate the copy code, like what is done for structs.

 Legacy Code Breakage
 --------------------

 This will break an unknown amount of existing code.

 Breakage will come in the form of:

 1. dependency on identifying Exception objects by their addresses,
 which won't work anymore because of the copying.
 (good code shouldn't rely on this anyway)

 2. leaking Exception objects from catch clauses (caught by
 the compiler)

 3. Disallowing Exception objects with postblit fields.

 4. Catch objects being 'scope' will cause problems in that
 everything done with those objects will also have to be 'scope'.
 The most likely problem will be printing the objects which
 relies on Object.toString() which is not 'scope'. One possible
 solution is to force Throwable.toString() to be 'scope', which
 will likely cause minimal disruption. Of course, compiling
 with -dip1000 will disable such checking and can work in
 the interim.

 Conclusion
 ----------

 The result of this should be no leaking memory, no need to link
 in the GC, and memory safety.

 References
 ----------

 http://www.digitalmars.com/d/archives/digitalmars/D/Exceptions_in_nogc_code_299261.html
Questions: 1) What if an exception dtor throws (yuck but eh)? 2) Could this in some form be paired with allocators? e.g. typeof(this) dup(IAllocator) { ... } throw new MyException(8); versus throw alloc.make!MyException(8); 3) Do we really need to copy an exception before rethrowing? It seems overkill, couldn't we introduce a new local variable to determine if it should free or not? And as probably expected, DIP please. Its a big set of changes and warrants documenting in that form.
Apr 01
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/1/2017 10:29 PM, rikki cattermole wrote:
 1) What if an exception dtor throws (yuck but eh)?
That's treated as a new exception.
 2) Could this in some form be paired with allocators? e.g.
 typeof(this) dup(IAllocator) { ... }
 throw new MyException(8); versus throw alloc.make!MyException(8);
I don't see a purpose for a custom allocator with this. The exception objects will be totally owned by the druntime EH implementation.
 3) Do we really need to copy an exception before rethrowing? It seems overkill,
 couldn't we introduce a new local variable to determine if it should free or
not?
The vast majority of use cases would be: throw new ExceptionType; which is detected by the compiler and the copy doesn't happen. For the rest of the (presumably) rare cases, an extra copy will be insignificant, and has the advantage of simplicity.
 And as probably expected, DIP please. Its a big set of changes and warrants
 documenting in that form.
If it survives the n.g. discussion I will. Though the DIP process is in limbo at the moment since Dicebot is no longer running it.
Apr 01
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
I should have noted that this does not involve any syntax changes.
Apr 01
prev sibling next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Sunday, 2 April 2017 at 05:16:23 UTC, Walter Bright wrote:
 Problem
 =======

 [...]
How will this interact with preallocated exceptions (e.g. from Liran's dconf talk last year)?
Apr 01
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/1/2017 11:50 PM, Nicholas Wilson wrote:
 On Sunday, 2 April 2017 at 05:16:23 UTC, Walter Bright wrote:
 Problem
 =======

 [...]
How will this interact with preallocated exceptions (e.g. from Liran's dconf talk last year)?
It will copy them and throw the copy.
Apr 02
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 4/2/17 9:14 AM, Walter Bright wrote:
 On 4/1/2017 11:50 PM, Nicholas Wilson wrote:
 On Sunday, 2 April 2017 at 05:16:23 UTC, Walter Bright wrote:
 Problem
 =======

 [...]
How will this interact with preallocated exceptions (e.g. from Liran's dconf talk last year)?
It will copy them and throw the copy.
Copy means allocate and then deallocate in the catch, defeating the whole propose of preallocating. Would it be possible to just set a bit somewhere that indicates that the exception is preallocated and need not be freed. So for instance: throw new Exception; // this is allocated exception auto e = makeMeAnException(); throw e; // this is preallocated exception (need not be freed in the catch) --- Dmitry Olshansky
Apr 02
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/2/2017 8:24 AM, Dmitry Olshansky wrote:
 Copy means allocate and then deallocate in the catch, defeating the whole
 propose of preallocating.
That's right.
 Would it be possible to just set a bit somewhere that
 indicates that the exception is preallocated and need not be freed.
Yes, it's possible. But I'd have to be convinced that there isn't some other problem with a design that requires preallocated exceptions. Exceptions are slow; they are designed to totally favor the non-throwing path. Walking the stack and looking through the tables looking for the right stack frame information is slow. Unwinding is slow. The druntime exception handling code is dog slow (it's just as agonizing in C++, it's not a D thang). If the D exception allocator uses a pool, and exceptions are held to being just a few bytes long (they can always use PIMPL if they have large data requirements), they'll be very cheap to allocate and initialize. It's hard to see how that would be a problem, given the rest of what goes on in throwing/unwinding. I can see preallocated exceptions needed for avoiding GC and hence an adversely timed GC pause/collect cycle. But with this proposal, I can't see the value.
Apr 02
parent reply Atila Neves <atila.neves gmail.com> writes:
On Sunday, 2 April 2017 at 20:35:27 UTC, Walter Bright wrote:
 On 4/2/2017 8:24 AM, Dmitry Olshansky wrote:
 [...]
That's right.
 [...]
Yes, it's possible. But I'd have to be convinced that there isn't some other problem with a design that requires preallocated exceptions. [...]
I think the point here is that some people already use pre-allocated exceptions. With this proposal, they'd have to change their codebase or suddenly have it go much slower. Atila
Apr 04
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/4/2017 1:08 AM, Atila Neves wrote:
 I think the point here is that some people already use pre-allocated
exceptions.
 With this proposal, they'd have to change their codebase or suddenly have it go
 much slower.
High performance code should never have exceptions in the fast path. The code gen is heavily and unapologetically biased towards speed in the non-exception path. This is true for C++ and D.
Apr 04
parent reply Atila Neves <atila.neves gmail.com> writes:
On Tuesday, 4 April 2017 at 08:41:51 UTC, Walter Bright wrote:
 On 4/4/2017 1:08 AM, Atila Neves wrote:
 I think the point here is that some people already use 
 pre-allocated exceptions.
 With this proposal, they'd have to change their codebase or 
 suddenly have it go
 much slower.
High performance code should never have exceptions in the fast path. The code gen is heavily and unapologetically biased towards speed in the non-exception path. This is true for C++ and D.
Right, but that doesn't mean the slow path should become all the more slower for codebases that do this. I haven't, but if I had I'd imagine I'd be none too happy about it. Atila
Apr 04
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/4/2017 10:38 AM, Atila Neves wrote:
 Right, but that doesn't mean the slow path should become all the more slower
for
 codebases that do this. I haven't, but if I had I'd imagine I'd be none too
 happy about it.
A year ago or so, I switched the exception unwinding mechanism for D on Linux from our custom solution to the Elf method used by every other language on Linux. It's a lot slower now - but it's compatible :-) Copying a dozen bytes isn't going to make any measurable difference.
Apr 04
prev sibling parent "Nick Sabalausky (Abscissa)" <SeeWebsiteToContactMe semitwist.com> writes:
On 04/04/2017 04:08 AM, Atila Neves wrote:
 I think the point here is that some people already use pre-allocated
 exceptions. With this proposal, they'd have to change their codebase or
 suddenly have it go much slower.
Isn't the main point of pre-allocated exceptions to improve control/determinism in memory usage/allocation? I don't think speed is the issue. As I see it, the issue is that it takes "this throw was SPECIFICALLY DESIGNED to NOT affect the heap" and turns it into "this throw DOES affect the heap, even though the author went out of their way to deliberately prevent that".
Apr 04
prev sibling parent reply Shachar Shemesh <shachar weka.io> writes:
On 02/04/17 18:24, Dmitry Olshansky wrote:
 On 4/2/17 9:14 AM, Walter Bright wrote:
 On 4/1/2017 11:50 PM, Nicholas Wilson wrote:
 On Sunday, 2 April 2017 at 05:16:23 UTC, Walter Bright wrote:
 Problem
 =======

 [...]
How will this interact with preallocated exceptions (e.g. from Liran's dconf talk last year)?
It will copy them and throw the copy.
Copy means allocate and then deallocate in the catch, defeating the whole propose of preallocating. Would it be possible to just set a bit somewhere that indicates that the exception is preallocated and need not be freed. So for instance: throw new Exception; // this is allocated exception auto e = makeMeAnException(); throw e; // this is preallocated exception (need not be freed in the catch) --- Dmitry Olshansky
The preallocated exceptions in weka were created as a work around for exceptions requiring GC. If we can throw without invoking the GC, we'll probably be fine with tossing them. Shachar
Apr 06
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2017 6:00 AM, Shachar Shemesh wrote:
 The preallocated exceptions in weka were created as a work around for
exceptions
 requiring GC. If we can throw without invoking the GC, we'll probably be fine
 with tossing them.

 Shachar
That's what I thought. Thanks for the confirmation.
Apr 07
prev sibling next sibling parent reply crimaniak <crimaniak gmail.com> writes:
On Sunday, 2 April 2017 at 05:16:23 UTC, Walter Bright wrote:
 Using a ref counted solution brings with it a host of problems 
 because
 the compiler is not set up to ref count class object 
 references, nor
 is any existing code set up to deal with that.
Please describe in more detail the problems in this part. If you are still planning to introduce RC-based objects into the language, then it is not obvious that the dedicated allocators in the runtime are better than using RC-based exception objects.
Apr 02
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/2/2017 7:02 PM, crimaniak wrote:
 On Sunday, 2 April 2017 at 05:16:23 UTC, Walter Bright wrote:
 Using a ref counted solution brings with it a host of problems because
 the compiler is not set up to ref count class object references, nor
 is any existing code set up to deal with that.
Please describe in more detail the problems in this part. If you are still planning to introduce RC-based objects into the language, then it is not obvious that the dedicated allocators in the runtime are better than using RC-based exception objects.
RC objects in D will be done with structs, not classes, due to this problem.
Apr 02
prev sibling next sibling parent reply Jerry <Kickupx gmail.com> writes:
What would happen if the exception gets assigned to a global/TLS 
variable in a catch block. It would be copied to the GC heap?
Apr 03
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/3/2017 3:58 AM, Jerry wrote:
 What would happen if the exception gets assigned to a global/TLS variable in a
 catch block. It would be copied to the GC heap?
You'd have to insert code to manually make a clone of the exception object. The compiler will complain if you try to leak the exception object.
Apr 03
prev sibling parent reply Jack Stouffer <jack jackstouffer.com> writes:
On Sunday, 2 April 2017 at 05:16:23 UTC, Walter Bright wrote:
 then it is optimized to call 'allocate' instead.
Sounds like using compiler magic for changing the behavior of existing syntax rather than fixing the actual problem that std.allocators is trying to solve: unifying disparate allocation strategies/needs across libraries. Do we really want to break a bunch of code and add another special case for this one specific problem, thereby making an already complicated language even more complicated? Also, half of the nogc purists aren't going to be using druntime anyway.
Apr 03
next sibling parent reply Kagamin <spam here.lot> writes:
On Monday, 3 April 2017 at 13:43:35 UTC, Jack Stouffer wrote:
 Also, half of the nogc purists aren't going to be using 
 druntime anyway.
druntime is not GC. C++ uses quite sizable runtime >1mb.
Apr 03
parent reply Jack Stouffer <jack jackstouffer.com> writes:
On Monday, 3 April 2017 at 14:20:48 UTC, Kagamin wrote:
 On Monday, 3 April 2017 at 13:43:35 UTC, Jack Stouffer wrote:
 Also, half of the nogc purists aren't going to be using 
 druntime anyway.
druntime is not GC. C++ uses quite sizable runtime >1mb.
I don't know if you've been following some of the discussions here and on Learn, but there are a couple of people now link-hacking druntime completely out of their binaries in order to avoid implicit GC calls and implicit copying.
Apr 03
parent reply Kagamin <spam here.lot> writes:
On Monday, 3 April 2017 at 14:27:47 UTC, Jack Stouffer wrote:
 I don't know if you've been following some of the discussions 
 here and on Learn, but there are a couple of people now 
 link-hacking druntime completely out of their binaries in order 
 to avoid implicit GC calls and implicit copying.
I suppose they link-hack GC, not druntime. If they want to remove druntime, they can just not link with it in the first place: no druntime, nothing to remove. That's what I do, but never heard of implicit copying.
Apr 03
parent reply Jack Stouffer <jack jackstouffer.com> writes:
On Monday, 3 April 2017 at 14:36:43 UTC, Kagamin wrote:
 I suppose they link-hack GC, not druntime.
Nope, they get rid of everything, see https://theartofmachinery.com/2016/12/18/d_without_runtime.html
Apr 03
parent Kagamin <spam here.lot> writes:
On Monday, 3 April 2017 at 15:16:31 UTC, Jack Stouffer wrote:
 On Monday, 3 April 2017 at 14:36:43 UTC, Kagamin wrote:
 I suppose they link-hack GC, not druntime.
Nope, they get rid of everything, see https://theartofmachinery.com/2016/12/18/d_without_runtime.html
That article is pretty careful:
As an example
as if it were C code to begin with
Even then, there are useful compromises between the extremes of 
“no D runtime” and “full D runtime”.
Also see the next post https://theartofmachinery.com/2017/01/24/boot_to_d.html - not exactly GC purity. Also the removed parts there are not runtime, but compiler generated stuff added to the object file that would need runtime, like reference to the personality function.
Apr 04
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/3/2017 6:43 AM, Jack Stouffer wrote:
 Sounds like using compiler magic for changing the behavior of existing syntax
 rather than fixing the actual problem that std.allocators is trying to solve:
 unifying disparate allocation strategies/needs across libraries.
I don't see a point to having disparate allocation strategies for exception objects. In any case, the compiler will insert calls to specific functions to allocate/free exception objects. Those functions will be in druntime, but anyone can override them with their own implementation.
 Do we really want to break a bunch of code and add another special case for
this
 one specific problem, thereby making an already complicated language even more
 complicated?
This particular solution will break very little existing code, and solves a fairly difficult problem.
 Also, half of the nogc purists aren't going to be using druntime anyway.
The idea of this proposal is to make a nogc program much more achievable. Currently, in order to not link with the GC, you can't use exceptions (or at least not in a memory safe manner). A solution without memory safety is not acceptable.
Apr 03
next sibling parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Monday, April 03, 2017 14:00:53 Walter Bright via Digitalmars-d wrote:
 The idea of this proposal is to make a nogc program much more achievable.
 Currently, in order to not link with the GC, you can't use exceptions (or
 at least not in a memory safe manner). A solution without memory safety
 is not acceptable.
Yeah, the simple fact that you can't allocate exceptions in nogc code is crippling to nogc, and a lot of code that could otherwise be nogc can't be because of exceptions - though the exception message poses a similar problem (especially if you'd normally construct it with format), and I don't know how you get around that other than not using anything more informative than string literals. Unless I missed something, this proposal seems to ignore that particular issue. - Jonathan M Davis
Apr 03
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 3 April 2017 at 21:31:39 UTC, Jonathan M Davis wrote:
 though the exception message poses a similar problem 
 (especially if you'd normally construct it with format), and I 
 don't know how you get around that other than not using 
 anything more informative than string literals
This is why strings are considered harmful to me. Instead, you can make a new exception class inline that stores the data and lazily sinks it to the toString delegate on demand. This doesn't work for all data types, but it does for a lot of useful ones. It is also another reason why this proposal is not that great - having a helper function allocate the exception means you can avoid allocating the string. This file shows like 3 concepts I have with exceptions, but the RaisedExceptionDetails.toString shows this: http://arsdnet.net/exception.d It is an easily solved library problem... and would be *easier* to use than format().
Apr 03
parent Daniel N <no public.email> writes:
On Monday, 3 April 2017 at 21:43:13 UTC, Adam D. Ruppe wrote:
 This file shows like 3 concepts I have with exceptions, but the 
 RaisedExceptionDetails.toString shows this:

 http://arsdnet.net/exception.d


 It is an easily solved library problem... and would be *easier* 
 to use than format().
I was going to propose the same thing, thanks for writing it for me!
Apr 06
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/3/2017 2:31 PM, Jonathan M Davis via Digitalmars-d wrote:
 Yeah, the simple fact that you can't allocate exceptions in  nogc code is
 crippling to  nogc, and a lot of code that could otherwise be  nogc can't be
 because of exceptions - though the exception message poses a similar problem
 (especially if you'd normally construct it with format), and I don't know
 how you get around that other than not using anything more informative than
 string literals. Unless I missed something, this proposal seems to ignore
 that particular issue.
You're right that this proposal does not address how memory is allocated for anything indirectly referenced by the exception object. That is an independent issue, and is not peculiar to exception objects.
Apr 03
next sibling parent deadalnix <deadalnix gmail.com> writes:
On Monday, 3 April 2017 at 22:20:23 UTC, Walter Bright wrote:
 You're right that this proposal does not address how memory is 
 allocated for anything indirectly referenced by the exception 
 object. That is an independent issue, and is not peculiar to 
 exception objects.
There is no issue specific to Exception here.
Apr 03
prev sibling parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Monday, April 03, 2017 15:20:23 Walter Bright via Digitalmars-d wrote:
 On 4/3/2017 2:31 PM, Jonathan M Davis via Digitalmars-d wrote:
 Yeah, the simple fact that you can't allocate exceptions in  nogc code
 is
 crippling to  nogc, and a lot of code that could otherwise be  nogc
 can't be because of exceptions - though the exception message poses a
 similar problem (especially if you'd normally construct it with
 format), and I don't know how you get around that other than not using
 anything more informative than string literals. Unless I missed
 something, this proposal seems to ignore that particular issue.
You're right that this proposal does not address how memory is allocated for anything indirectly referenced by the exception object. That is an independent issue, and is not peculiar to exception objects.
No, it's not a problem that's specific to exceptions, but the string for an exception message is pretty critical and is going to have a significant impact on the ability to use nogc with exceptions. Just being able to have the exception itself be allocated and managed safely via nogc is definitely a step up, but if we don't have a reasonable way to manage the exception's message in nogc code, then in many cases, we have a serious problem with how informative exceptions are. And if you really don't care about the exception message saying anything more than you can put in a string literal, you can always pre-allocate the excetion and avoid the whole nogc problem that way without any of the proposed language changes. As such, I'm inclined to think that the benefits of the proposed changes are minimal if they don't fix the problem with the exception's message being GC-allocated. - Jonathan M Davis
Apr 03
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/3/2017 11:59 PM, Jonathan M Davis via Digitalmars-d wrote:
 No, it's not a problem that's specific to exceptions, but the string for an
 exception message is pretty critical and is going to have a significant
 impact on the ability to use  nogc with exceptions. Just being able to have
 the exception itself be allocated and managed safely via  nogc is definitely
 a step up, but if we don't have a reasonable way to manage the exception's
 message in  nogc code, then in many cases, we have a serious problem with
 how informative exceptions are. And if you really don't care about the
 exception message saying anything more than you can put in a string literal,
 you can always pre-allocate the excetion and avoid the whole  nogc problem
 that way without any of the proposed language changes. As such, I'm inclined
 to think that the benefits of the proposed changes are minimal if they don't
 fix the problem with the exception's message being GC-allocated.
https://github.com/dlang/druntime/blob/master/src/object.d#L1701
Apr 04
prev sibling parent Johannes Pfau <nospam example.com> writes:
Am Mon, 03 Apr 2017 14:31:39 -0700
schrieb Jonathan M Davis via Digitalmars-d
<digitalmars-d puremagic.com>:

 On Monday, April 03, 2017 14:00:53 Walter Bright via Digitalmars-d
 wrote:
 The idea of this proposal is to make a nogc program much more
 achievable. Currently, in order to not link with the GC, you can't
 use exceptions (or at least not in a memory safe manner). A
 solution without memory safety is not acceptable.  
Yeah, the simple fact that you can't allocate exceptions in nogc code is crippling to nogc, and a lot of code that could otherwise be nogc can't be because of exceptions - though the exception message poses a similar problem (especially if you'd normally construct it with format), and I don't know how you get around that other than not using anything more informative than string literals. Unless I missed something, this proposal seems to ignore that particular issue. - Jonathan M Davis
Allocate the string using an Allocator, free in the Exceptions ~this? This has to be integrated somehow with the copying scheme though, so you'll probably need some kind of reference counting for classes again or duplicate the string on every copy. -- Johannes
Apr 03
prev sibling next sibling parent reply David Nadlinger <code klickverbot.at> writes:
On Monday, 3 April 2017 at 21:00:53 UTC, Walter Bright wrote:
 The idea of this proposal is to make a nogc program much more 
 achievable. Currently, in order to not link with the GC, you 
 can't use exceptions (or at least not in a memory safe manner). 
 A solution without memory safety is not acceptable.
You could use an exception instance allocated in TLS (which is, in fact, what Weka does in large parts of the code). This should be perfectly memory safe, although there are of course implications for exception chaining. (By default, you'll still get an allocation for the associated TraceInfo, but you can disable that.) Of course, this is not to say that a nicer/more general solution wouldn't be appreciated. — David
Apr 03
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/3/2017 2:38 PM, David Nadlinger wrote:
 On Monday, 3 April 2017 at 21:00:53 UTC, Walter Bright wrote:
 The idea of this proposal is to make a nogc program much more achievable.
 Currently, in order to not link with the GC, you can't use exceptions (or at
 least not in a memory safe manner). A solution without memory safety is not
 acceptable.
You could use an exception instance allocated in TLS (which is, in fact, what Weka does in large parts of the code). This should be perfectly memory safe, although there are of course implications for exception chaining. (By default, you'll still get an allocation for the associated TraceInfo, but you can disable that.) Of course, this is not to say that a nicer/more general solution wouldn't be appreciated. — David
Using a singleton in TLS is indeed memory safe, as long as you don't do things like keep a reference to it around and expect it not to change.
Apr 03
parent reply Guillaume Piolat <first.last gmail.com> writes:
On Monday, 3 April 2017 at 22:30:46 UTC, Walter Bright wrote:
 Using a singleton in TLS is indeed memory safe, as long as you 
 don't do things like keep a reference to it around and expect 
 it not to change.
But those of us with the runtime disabled don't have TLS. throwing, .destroy, TLS (and static this) are the fragmenting factors between runtime-free and D normal D.
Apr 05
next sibling parent reply David Nadlinger <code klickverbot.at> writes:
On Wednesday, 5 April 2017 at 14:35:18 UTC, Guillaume Piolat 
wrote:
 But those of us with the runtime disabled don't have TLS.
This is only true on DMD/OS X x86, where TLS is emulated in druntime. On other platforms, TLS is implemented by the linker and/or C runtime, so it works without druntime just fine. Regular thread-local module constructors (static this) of course won't work without druntime support, as they are mediated through ModuleInfo. — David
Apr 05
parent reply Guillaume Piolat <first.last gmail.com> writes:
On Wednesday, 5 April 2017 at 16:08:33 UTC, David Nadlinger wrote:
 On Wednesday, 5 April 2017 at 14:35:18 UTC, Guillaume Piolat 
 wrote:
 But those of us with the runtime disabled don't have TLS.
This is only true on DMD/OS X x86, where TLS is emulated in druntime. On other platforms, TLS is implemented by the linker and/or C runtime, so it works without druntime just fine.
TIL, thanks.
 Regular thread-local module constructors (static this) of 
 course won't work without druntime support, as they are 
 mediated through ModuleInfo.

  — David
Sure. This means TLS is here but uninitialized and eg. core.cpuid has to be duplicated. Fragmentation ensues.
Apr 05
next sibling parent David Nadlinger <code klickverbot.at> writes:
On Wednesday, 5 April 2017 at 16:33:42 UTC, Guillaume Piolat 
wrote:
 This means TLS is here but uninitialized and eg. core.cpuid has 
 to be duplicated.
 Fragmentation ensues.
You can still lazily initialise TLS data, though. — David
Apr 05
prev sibling parent Kagamin <spam here.lot> writes:
On Wednesday, 5 April 2017 at 16:33:42 UTC, Guillaume Piolat 
wrote:
 This means TLS is here but uninitialized and eg. core.cpuid has 
 to be duplicated.
 Fragmentation ensues.
Good, it provides options with various tradeoffs that fulfill more needs. If you don't want to have choice, use stock druntime+phobos, that's the way for unification and defaults.
Apr 06
prev sibling parent reply Jack Stouffer <jack jackstouffer.com> writes:
On Wednesday, 5 April 2017 at 14:35:18 UTC, Guillaume Piolat 
wrote:
 But those of us with the runtime disabled don't have TLS.
 throwing, .destroy, TLS (and static this) are the fragmenting 
 factors between runtime-free and D normal D.
I'm going to be harsh here and say that the D team members should focus on it's users who are using druntime + Phobos and allow people to use their own runtime if they wish. Then for the most part, ignore everyone else. We cannot afford to make concessions to a small handful of our userbase with our limited dev time. Suggested party line: if you don't want to use druntime, best of luck, you're on your own. We're not going to gimp Phobos for you.
Apr 05
parent Guillaume Piolat <first.last gmail.com> writes:
On Wednesday, 5 April 2017 at 17:35:01 UTC, Jack Stouffer wrote:
 Suggested party line: if you don't want to use druntime, best 
 of luck, you're on your own. We're not going to gimp Phobos for 
 you.
s/wan't/can't Avoiding druntime is not done for the fun of it, but because there is (in rare cases granted) no other choices.
Apr 06
prev sibling parent reply Jack Stouffer <jack jackstouffer.com> writes:
On Monday, 3 April 2017 at 21:00:53 UTC, Walter Bright wrote:
 I don't see a point to having disparate allocation strategies 
 for exception objects.
Example: company wants to use their custom GC (like sociomantic) with Phobos. They want to do this even for exceptions because they believe that things will be faster if they're able to completely control when any memory is freed. Your solution does not help these people use Phobos because the compiler will be inserting calls to free in places they don't want, which will slow down their program. Solution: 1. allocate exceptions in Phobos with theAllocator 2. if theAllocator is still the default of the GC, then the user doesn't have to do anything else because the exception will be garbage collected. No code is broken (I think) for everyone who doesn't set theAllocator. 3. If theAllocator is different, then the onus is on the user to properly free the exception In my mind, the whole point of std.allocator was to make Phobos allocation strategy agnostic. So, at some point, we're going to have to find a way to integrate std.allocator into Phobos to get rid of the GC usage anyway. Exceptions seem like as good as any other place to start. Or, find a way to get RC with objects.
 In any case, the compiler will insert calls to specific 
 functions to allocate/free exception objects. Those functions 
 will be in druntime, but anyone can override them with their 
 own implementation.
And this will be done by changing the meaning of people's code and adding a special case to new. This smells like C++.
Apr 03
next sibling parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Monday, 3 April 2017 at 23:33:10 UTC, Jack Stouffer wrote:
 On Monday, 3 April 2017 at 21:00:53 UTC, Walter Bright wrote:
 I don't see a point to having disparate allocation strategies 
 for exception objects.
Example: company wants to use their custom GC (like sociomantic) with Phobos. They want to do this even for exceptions because they believe that things will be faster if they're able to completely control when any memory is freed.
AFAIK if an exception is going to be triggered, you've already entered the horribly slow path of stack unwinding that should never occur in the normal operation of any program that cares about performance. I doubt the performance of the exceptions' memory management will register compared to that.
 Your solution does not help these people use Phobos because the 
 compiler will be inserting calls to free in places they don't 
 want, which will slow down their program.
If their program slows noticeably from any changes to the slow path I'm forced to ask why it spends so much time on the slow path; this sounds like there is something fundamentally wrong with the program.
 Solution:

 1. allocate exceptions in Phobos with theAllocator
 2. if theAllocator is still the default of the GC, then the 
 user doesn't have to do anything else because the exception 
 will be garbage collected. No code is broken (I think) for 
 everyone who doesn't set theAllocator.
 3. If theAllocator is different, then the onus is on the user 
 to properly free the exception
Consider the following: - Application sets theAllocator to something different - Application calls into (non-Phobos) library - (non-Phobos) library calls into Phobos - Phobos throws an exception (allocated using theAllocator) - (non-Phobos) library knows how to handle the exception semantically and thus catches it - To properly free the exception the (non-Phobos) library author must defensively call theAllocator.dispose. AFAICT this solution will end up with everyone always calling theAllocator.dispose when catching from Phobos.
Apr 03
parent reply Jack Stouffer <jack jackstouffer.com> writes:
On Tuesday, 4 April 2017 at 00:45:08 UTC, Moritz Maxeiner wrote:
 AFAICT this solution will end up with everyone always calling 
 theAllocator.dispose when catching from Phobos.
Yes, because you can no longer assume that the GC is being used, as all current Phobos code does. Here's the thing, this problem misses the forrest for the trees. Focusing on exceptions is not seeing the broader problem of the user being at the mercy of Phobos devs with their choices of allocations. Exceptions are one aspect of the problem of allocation in a standard library with multiple allocation methods available. It's only as a matter of convenience that we've been using the GC for everything when stack allocation isn't enough. If we want to compete with Rust and C++* need a clean way to let the user control memory throughout their program. As already pointed out, this is one ad-hoc solution to a specific problem rather than a holistic solution. * to be honest, I would be fine if it was concluded that this isn't what we want to compete with. Java and C# didn't mostly replace C++ by being "C++ but slightly different". They won because they were something different that allowed you to get shit done. What does D want to be, a better C++ or a better language? I don't think it's possible to have a clean language + std library and have the same amount of power as C++, the GC is just to convenient and takes off so much cognitive load. If we want to compete with C++ with Phobos, Phobos will need to become more ugly but more flexible.
Apr 04
parent reply Walter Bright <newshound2 digitalmars.com> writes:
Much of Phobos has been redone to not assume/require the GC. A glaring
exception 
(!) is when Exceptions are thrown, which is why we're looking for a solution.
Apr 05
next sibling parent Jack Stouffer <jack jackstouffer.com> writes:
On Wednesday, 5 April 2017 at 09:51:16 UTC, Walter Bright wrote:
 Much of Phobos has been redone to not assume/require the GC. A 
 glaring exception (!) is when Exceptions are thrown, which is 
 why we're looking for a solution.
Much, but not most. Dynamic arrays, AAs, closures, and all classes are still heavily used in Phobos. More than half of all the modules in Phobos rely on GC. Again: making throwing exceptions nogc WILL make a small number of the overall currently allocating functions nogc. It will NOT make the majority of Phobos nogc and it doesn't come close to the main problem already stated in my other comments. You're adding in a confusing special case for a small piece of the overall whole and missing the forrest for the trees.
Apr 05
prev sibling parent deadalnix <deadalnix gmail.com> writes:
On Wednesday, 5 April 2017 at 09:51:16 UTC, Walter Bright wrote:
 Much of Phobos has been redone to not assume/require the GC. A 
 glaring exception (!) is when Exceptions are thrown, which is 
 why we're looking for a solution.
Make the exception owned, and let the caller decide.
Apr 05
prev sibling parent Dukc <ajieskola gmail.com> writes:
On Monday, 3 April 2017 at 23:33:10 UTC, Jack Stouffer wrote:
 Example: company wants to use their custom GC (like 
 sociomantic) with Phobos. They want to do this even for 
 exceptions because they believe that things will be faster if 
 they're able to completely control when any memory is freed. 
 Your solution does not help these people use Phobos because the 
 compiler will be inserting calls to free in places they don't 
 want, which will slow down their program.
I think that because of that, the following should be possible: Exception store; catch(Exception e) { //does not call the destructor store = new Exception(e.move); //still no destructor called because e is null } In case of preallocated exceptions, thats ugly to do everywhere. But it could be argued that so is relying on EH speed on the first place! Form follows the function. Still, I agree that's a problem.
Apr 05