digitalmars.D - Proposal: Exceptions and nogc
- Walter Bright (72/72) Apr 01 2017 Problem
- rikki cattermole (11/84) Apr 01 2017 Questions:
- Walter Bright (11/19) Apr 01 2017 I don't see a purpose for a custom allocator with this. The exception ob...
- Walter Bright (1/1) Apr 01 2017 I should have noted that this does not involve any syntax changes.
- Nicholas Wilson (3/6) Apr 01 2017 How will this interact with preallocated exceptions (e.g. from
- Walter Bright (2/9) Apr 02 2017 It will copy them and throw the copy.
- Dmitry Olshansky (11/22) Apr 02 2017 Copy means allocate and then deallocate in the catch, defeating the
- Walter Bright (15/19) Apr 02 2017 Yes, it's possible. But I'd have to be convinced that there isn't some o...
- Atila Neves (5/13) Apr 04 2017 I think the point here is that some people already use
- Walter Bright (4/7) Apr 04 2017 High performance code should never have exceptions in the fast path. The...
- Atila Neves (5/15) Apr 04 2017 Right, but that doesn't mean the slow path should become all the
- Walter Bright (5/8) Apr 04 2017 A year ago or so, I switched the exception unwinding mechanism for D on ...
- Nick Sabalausky (Abscissa) (7/10) Apr 04 2017 Isn't the main point of pre-allocated exceptions to improve
- Shachar Shemesh (5/28) Apr 06 2017 The preallocated exceptions in weka were created as a work around for
- Walter Bright (2/6) Apr 07 2017 That's what I thought. Thanks for the confirmation.
- crimaniak (5/10) Apr 02 2017 Please describe in more detail the problems in this part. If you
- Walter Bright (2/10) Apr 02 2017 RC objects in D will be done with structs, not classes, due to this prob...
- Jerry (2/2) Apr 03 2017 What would happen if the exception gets assigned to a global/TLS
- Walter Bright (3/5) Apr 03 2017 You'd have to insert code to manually make a clone of the exception obje...
- Jack Stouffer (10/11) Apr 03 2017 Sounds like using compiler magic for changing the behavior of
- Kagamin (3/5) Apr 03 2017 druntime is not GC.
- Jack Stouffer (5/10) Apr 03 2017 I don't know if you've been following some of the discussions
- Kagamin (5/9) Apr 03 2017 I suppose they link-hack GC, not druntime. If they want to remove
- Jack Stouffer (3/4) Apr 03 2017 Nope, they get rid of everything, see
- Kagamin (8/16) Apr 04 2017 Also see the next post
- Walter Bright (11/18) Apr 03 2017 I don't see a point to having disparate allocation strategies for except...
- Jonathan M Davis via Digitalmars-d (9/13) Apr 03 2017 Yeah, the simple fact that you can't allocate exceptions in @nogc code i...
- Adam D. Ruppe (13/17) Apr 03 2017 This is why strings are considered harmful to me. Instead, you
- Daniel N (3/8) Apr 06 2017 I was going to propose the same thing, thanks for writing it for
- Walter Bright (4/11) Apr 03 2017 You're right that this proposal does not address how memory is allocated...
- deadalnix (2/6) Apr 03 2017 There is no issue specific to Exception here.
- Jonathan M Davis via Digitalmars-d (14/26) Apr 03 2017 No, it's not a problem that's specific to exceptions, but the string for...
- Walter Bright (2/14) Apr 04 2017 https://github.com/dlang/druntime/blob/master/src/object.d#L1701
- Johannes Pfau (8/25) Apr 03 2017 Am Mon, 03 Apr 2017 14:31:39 -0700
- David Nadlinger (10/14) Apr 03 2017 You could use an exception instance allocated in TLS (which is,
- Walter Bright (3/16) Apr 03 2017 Using a singleton in TLS is indeed memory safe, as long as you don't do ...
- Guillaume Piolat (4/7) Apr 05 2017 But those of us with the runtime disabled don't have TLS.
- David Nadlinger (9/10) Apr 05 2017 This is only true on DMD/OS X x86, where TLS is emulated in
- Guillaume Piolat (6/16) Apr 05 2017 Sure.
- David Nadlinger (3/6) Apr 05 2017 You can still lazily initialise TLS data, though. — David
- Kagamin (5/8) Apr 06 2017 Good, it provides options with various tradeoffs that fulfill
- Jack Stouffer (9/12) Apr 05 2017 I'm going to be harsh here and say that the D team members should
- Guillaume Piolat (4/7) Apr 06 2017 s/wan't/can't
- Jack Stouffer (25/31) Apr 03 2017 Example: company wants to use their custom GC (like sociomantic)
- Moritz Maxeiner (21/39) Apr 03 2017 AFAIK if an exception is going to be triggered, you've already
- Jack Stouffer (25/27) Apr 04 2017 Yes, because you can no longer assume that the GC is being used,
- Walter Bright (2/2) Apr 05 2017 Much of Phobos has been redone to not assume/require the GC. A glaring e...
- Jack Stouffer (10/13) Apr 05 2017 Much, but not most. Dynamic arrays, AAs, closures, and all
- deadalnix (2/5) Apr 05 2017 Make the exception owned, and let the caller decide.
- Dukc (12/19) Apr 05 2017 I think that because of that, the following should be possible:
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 2017
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.htmlQuestions: 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 2017
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 2017
I should have noted that this does not involve any syntax changes.
Apr 01 2017
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 2017
On 4/1/2017 11:50 PM, Nicholas Wilson wrote:On Sunday, 2 April 2017 at 05:16:23 UTC, Walter Bright wrote:It will copy them and throw the copy.Problem ======= [...]How will this interact with preallocated exceptions (e.g. from Liran's dconf talk last year)?
Apr 02 2017
On 4/2/17 9:14 AM, Walter Bright wrote:On 4/1/2017 11:50 PM, Nicholas Wilson wrote: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 OlshanskyOn Sunday, 2 April 2017 at 05:16:23 UTC, Walter Bright wrote:It will copy them and throw the copy.Problem ======= [...]How will this interact with preallocated exceptions (e.g. from Liran's dconf talk last year)?
Apr 02 2017
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 2017
On Sunday, 2 April 2017 at 20:35:27 UTC, Walter Bright wrote:On 4/2/2017 8:24 AM, Dmitry Olshansky 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. Atila[...]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. [...]
Apr 04 2017
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 2017
On Tuesday, 4 April 2017 at 08:41:51 UTC, Walter Bright wrote:On 4/4/2017 1:08 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. AtilaI 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 2017
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 2017
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 2017
On 02/04/17 18:24, Dmitry Olshansky wrote:On 4/2/17 9:14 AM, Walter Bright 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. ShacharOn 4/1/2017 11:50 PM, Nicholas Wilson wrote: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 OlshanskyOn Sunday, 2 April 2017 at 05:16:23 UTC, Walter Bright wrote:It will copy them and throw the copy.Problem ======= [...]How will this interact with preallocated exceptions (e.g. from Liran's dconf talk last year)?
Apr 06 2017
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. ShacharThat's what I thought. Thanks for the confirmation.
Apr 07 2017
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 2017
On 4/2/2017 7:02 PM, crimaniak wrote:On Sunday, 2 April 2017 at 05:16:23 UTC, Walter Bright wrote:RC objects in D will be done with structs, not classes, due to this problem.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 2017
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 2017
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 2017
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 2017
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 2017
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: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.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 2017
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 2017
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 2017
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:That article is pretty careful:I suppose they link-hack GC, not druntime.Nope, they get rid of everything, see https://theartofmachinery.com/2016/12/18/d_without_runtime.htmlAs 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 2017
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 2017
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 2017
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 literalsThis 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 2017
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 2017
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 2017
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 2017
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: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 DavisYeah, 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 2017
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 2017
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: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. -- JohannesThe 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 2017
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 2017
On 4/3/2017 2:38 PM, David Nadlinger wrote:On Monday, 3 April 2017 at 21:00:53 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.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 2017
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 2017
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 2017
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:TIL, thanks.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. — DavidSure. This means TLS is here but uninitialized and eg. core.cpuid has to be duplicated. Fragmentation ensues.
Apr 05 2017
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 2017
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 2017
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 2017
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 2017
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 2017
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: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.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.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 exceptionConsider 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 2017
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 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 2017
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 2017
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 2017
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 2017
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 2017