Proposal: Exceptions and @nogc

Walter Bright via Digitalmars-d digitalmars-d at puremagic.com
Sat Apr 1 22:16:23 PDT 2017


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


More information about the Digitalmars-d mailing list