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

Commit 75d9d39

Browse files
committed
implement druntime side of DIP1006
1 parent 4eecbc4 commit 75d9d39

7 files changed

Lines changed: 172 additions & 5 deletions

File tree

mak/SRCS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ SRCS=\
269269
src\rt\deh_win64_posix.d \
270270
src\rt\dmain2.d \
271271
src\rt\dwarfeh.d \
272+
src\rt\ehalloc.d \
272273
src\rt\invariant.d \
273274
src\rt\lifetime.d \
274275
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: 13 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.
@@ -1666,6 +1668,11 @@ class Throwable : Object
16661668
*/
16671669
Throwable next;
16681670

1671+
private uint _refcount; // 0 : allocated by GC
1672+
// 1 : allocated by _d_newThrowable()
1673+
// 2.. : reference count + 1
1674+
@system @nogc final pure nothrow ref uint refcount() return scope { return _refcount; }
1675+
16691676
@nogc @safe pure nothrow this(string msg, Throwable next = null)
16701677
{
16711678
this.msg = msg;
@@ -1681,6 +1688,12 @@ class Throwable : Object
16811688
//this.info = _d_traceContext();
16821689
}
16831690

1691+
@trusted nothrow ~this()
1692+
{
1693+
if (next && next._refcount)
1694+
_d_delThrowable(next);
1695+
}
1696+
16841697
/**
16851698
* Overrides $(D Object.toString) and returns the error message.
16861699
* 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
@@ -182,6 +182,12 @@ extern(C) void _d_throwdwarf(Throwable o)
182182
eh.push(); // add to thrown exception stack
183183
//printf("_d_throwdwarf: eh = %p, eh.next = %p\n", eh, eh.next);
184184

185+
/* Increment reference count if `o` is a refcounted Throwable
186+
*/
187+
auto refcount = o.refcount();
188+
if (refcount) // non-zero means it's refcounted
189+
o.refcount() = refcount + 1;
190+
185191
/* Called by unwinder when exception object needs destruction by other than our code.
186192
*/
187193
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)