Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 24c814d

Browse files
authored
Merge pull request #1804 from WalterBright/dip1006
implement druntime side of DIP1008 merged-on-behalf-of: Andrei Alexandrescu <andralex@users.noreply.github.com>
2 parents 8909127 + 14f2812 commit 24c814d

File tree

7 files changed

+179
-5
lines changed

7 files changed

+179
-5
lines changed

mak/SRCS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ SRCS=\
302302
src\rt\deh_win64_posix.d \
303303
src\rt\dmain2.d \
304304
src\rt\dwarfeh.d \
305+
src\rt\ehalloc.d \
305306
src\rt\invariant.d \
306307
src\rt\lifetime.d \
307308
src\rt\llmath.d \

src/core/thread.d

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ version( Windows )
223223

224224
void append( Throwable t )
225225
{
226+
if (t.refcount())
227+
++t.refcount();
226228
if( obj.m_unhandled is null )
227229
obj.m_unhandled = t;
228230
else
@@ -377,6 +379,8 @@ else version( Posix )
377379

378380
void append( Throwable t )
379381
{
382+
if (t.refcount())
383+
++t.refcount();
380384
if( obj.m_unhandled is null )
381385
obj.m_unhandled = t;
382386
else

src/object.d

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ private
1616
extern (C) void rt_finalize(void *data, bool det=true);
1717
}
1818

19+
public @trusted @nogc nothrow pure extern (C) void _d_delThrowable(scope Throwable);
20+
1921
// NOTE: For some reason, this declaration method doesn't work
2022
// in this particular file (and this file only). It must
2123
// be a DMD thing.
@@ -1704,6 +1706,18 @@ class Throwable : Object
17041706
*/
17051707
Throwable next;
17061708

1709+
private uint _refcount; // 0 : allocated by GC
1710+
// 1 : allocated by _d_newThrowable()
1711+
// 2.. : reference count + 1
1712+
1713+
/**
1714+
* Returns:
1715+
* mutable reference to the reference count, which is
1716+
* 0 - allocated by the GC, 1 - allocated by _d_newThrowable(),
1717+
* and >=2 which is the reference count + 1
1718+
*/
1719+
@system @nogc final pure nothrow ref uint refcount() return scope { return _refcount; }
1720+
17071721
@nogc @safe pure nothrow this(string msg, Throwable next = null)
17081722
{
17091723
this.msg = msg;
@@ -1719,6 +1733,12 @@ class Throwable : Object
17191733
//this.info = _d_traceContext();
17201734
}
17211735

1736+
@trusted nothrow ~this()
1737+
{
1738+
if (next && next._refcount)
1739+
_d_delThrowable(next);
1740+
}
1741+
17221742
/**
17231743
* Overrides $(D Object.toString) and returns the error message.
17241744
* Internally this forwards to the $(D toString) overload that

src/rt/deh_win32.d

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -611,21 +611,33 @@ int _d_exception_filter(EXCEPTION_POINTERS *eptrs,
611611
}
612612

613613
/***********************************
614-
* Throw a D object.
614+
* Throw a D instance of Throwable.
615615
*/
616616

617-
private void throwImpl(Object h)
617+
private void throwImpl(Throwable h)
618618
{
619-
// @@@ TODO @@@ Signature should change: h will always be a Throwable.
620619
//printf("_d_throw(h = %p, &h = %p)\n", h, &h);
621620
//printf("\tvptr = %p\n", *(void **)h);
621+
622+
/* Increment reference count if `h` is a refcounted Throwable
623+
*/
624+
auto refcount = h.refcount();
625+
if (refcount) // non-zero means it's refcounted
626+
h.refcount() = refcount + 1;
627+
622628
_d_createTrace(h, null);
623629
RaiseException(STATUS_DIGITAL_MARS_D_EXCEPTION,
624630
EXCEPTION_NONCONTINUABLE,
625631
1, cast(void *)&h);
626632
}
627633

628-
extern(C) void _d_throwc(Object h)
634+
/***************************************
635+
* The compiler converts:
636+
* throw h;
637+
* into a call to:
638+
* _d_throwc(h);
639+
*/
640+
extern(C) void _d_throwc(Throwable h)
629641
{
630642
// set up a stack frame for trace unwinding
631643
version (AsmX86)

src/rt/deh_win64_posix.d

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ size_t __eh_find_caller(size_t regbp, size_t *pretaddr)
219219
* Throw a D object.
220220
*/
221221

222-
extern (C) void _d_throwc(Object h)
222+
extern (C) void _d_throwc(Throwable h)
223223
{
224224
size_t regebp;
225225

@@ -242,6 +242,12 @@ extern (C) void _d_throwc(Object h)
242242
else
243243
static assert(0);
244244

245+
/* Increment reference count if `h` is a refcounted Throwable
246+
*/
247+
auto refcount = h.refcount();
248+
if (refcount) // non-zero means it's refcounted
249+
h.refcount() = refcount + 1;
250+
245251
_d_createTrace(h, null);
246252

247253
//static uint abc;

src/rt/dwarfeh.d

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,12 @@ extern(C) void _d_throwdwarf(Throwable o)
183183
eh.push(); // add to thrown exception stack
184184
//printf("_d_throwdwarf: eh = %p, eh.next = %p\n", eh, eh.next);
185185

186+
/* Increment reference count if `o` is a refcounted Throwable
187+
*/
188+
auto refcount = o.refcount();
189+
if (refcount) // non-zero means it's refcounted
190+
o.refcount() = refcount + 1;
191+
186192
/* Called by unwinder when exception object needs destruction by other than our code.
187193
*/
188194
extern (C) static void exception_cleanup(_Unwind_Reason_Code reason, _Unwind_Exception* eo)

src/rt/ehalloc.d

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/**
2+
* Exception allocation, cloning, and release compiler support routines.
3+
*
4+
* Copyright: Copyright (c) 2017 by D Language Foundation
5+
* License: Distributed under the
6+
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
7+
* (See accompanying file LICENSE)
8+
* Authors: Walter Bright
9+
* Source: $(DRUNTIMESRC src/rt/_dwarfeh.d)
10+
*/
11+
12+
module rt.ehalloc;
13+
14+
//debug = PRINTF;
15+
16+
debug(PRINTF)
17+
{
18+
import core.stdc.stdio;
19+
}
20+
21+
/**********************************************
22+
* Allocate an exception of type `ci` from the exception pool.
23+
* It has the same interface as `rt.lifetime._d_newclass()`.
24+
* The class type must be Throwable or derived from it,
25+
* and cannot be a COM or C++ class. The compiler must enforce
26+
* this.
27+
* Returns:
28+
* default initialized instance of the type
29+
*/
30+
31+
extern (C) Throwable _d_newThrowable(const TypeInfo_Class ci)
32+
{
33+
debug(PRINTF) printf("_d_newThrowable(ci = %p, %s)\n", ci, cast(char *)ci.name);
34+
35+
assert(!(ci.m_flags & TypeInfo_Class.ClassFlags.isCOMclass));
36+
assert(!(ci.m_flags & TypeInfo_Class.ClassFlags.isCPPclass));
37+
38+
import core.stdc.stdlib : malloc;
39+
void* p = malloc(ci.initializer.length);
40+
if (!p)
41+
{
42+
import core.exception : onOutOfMemoryError;
43+
onOutOfMemoryError();
44+
}
45+
46+
debug(PRINTF) printf(" p = %p\n", p);
47+
48+
// initialize it
49+
p[0 .. ci.initializer.length] = ci.initializer[];
50+
51+
if (!(ci.m_flags & TypeInfo_Class.ClassFlags.noPointers))
52+
{
53+
// Inform the GC about the pointers in the object instance
54+
import core.memory : GC;
55+
56+
GC.addRange(p, ci.initializer.length, ci);
57+
}
58+
59+
debug(PRINTF) printf("initialization done\n");
60+
Throwable t = cast(Throwable)p;
61+
t.refcount() = 1;
62+
return t;
63+
}
64+
65+
66+
/********************************************
67+
* Delete exception instance `t` from the exception pool.
68+
* Must have been allocated with `_d_newThrowable()`.
69+
* This is meant to be called at the close of a catch block.
70+
* It's nothrow because otherwise any function with a catch block could
71+
* not be nothrow.
72+
* Input:
73+
* t = Throwable
74+
*/
75+
76+
nothrow extern (C) void _d_delThrowable(Throwable t)
77+
{
78+
if (t)
79+
{
80+
debug(PRINTF) printf("_d_delThrowable(%p)\n", t);
81+
82+
/* If allocated by the GC, don't free it.
83+
* Let the GC handle it.
84+
* Supporting this is necessary while transitioning
85+
* to this new scheme for allocating exceptions.
86+
*/
87+
auto refcount = t.refcount();
88+
if (refcount == 0)
89+
return; // it was allocated by the GC
90+
91+
if (refcount == 1)
92+
assert(0); // no zombie objects
93+
94+
t.refcount() = --refcount;
95+
if (refcount > 1)
96+
return;
97+
98+
TypeInfo_Class **pc = cast(TypeInfo_Class **)t;
99+
if (*pc)
100+
{
101+
TypeInfo_Class ci = **pc;
102+
103+
if (!(ci.m_flags & TypeInfo_Class.ClassFlags.noPointers))
104+
{
105+
// Inform the GC about the pointers in the object instance
106+
import core.memory : GC;
107+
GC.removeRange(cast(void*) t);
108+
}
109+
}
110+
111+
try
112+
{
113+
import rt.lifetime : rt_finalize;
114+
rt_finalize(cast(void*) t);
115+
}
116+
catch (Throwable t)
117+
{
118+
assert(0); // should never happen since Throwable.~this() is nothrow
119+
}
120+
import core.stdc.stdlib : free;
121+
debug(PRINTF) printf("free(%p)\n", t);
122+
free(cast(void*) t);
123+
}
124+
}
125+

0 commit comments

Comments
 (0)