xref: /netbsd-src/external/gpl3/gcc/dist/libphobos/libdruntime/rt/ehalloc.d (revision b1e838363e3c6fc78a55519254d99869742dd33c)
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 rt/_ehalloc.d)
10  */
11 
12 module rt.ehalloc;
13 
14 //debug = PRINTF;
15 
debug(PRINTF)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 
_d_newThrowable(const TypeInfo_Class ci)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     auto init = ci.initializer;
40     void* p = malloc(init.length);
41     if (!p)
42     {
43         import core.exception : onOutOfMemoryError;
44         onOutOfMemoryError();
45     }
46 
47     debug(PRINTF) printf(" p = %p\n", p);
48 
49     // initialize it
50     p[0 .. init.length] = init[];
51 
52     if (!(ci.m_flags & TypeInfo_Class.ClassFlags.noPointers))
53     {
54         // Inform the GC about the pointers in the object instance
55         import core.memory : GC;
56 
57         GC.addRange(p, init.length, ci);
58     }
59 
60     debug(PRINTF) printf("initialization done\n");
61     Throwable t = cast(Throwable)p;
62     t.refcount() = 1;
63     return t;
64 }
65 
66 
67 /********************************************
68  * Delete exception instance `t` from the exception pool.
69  * Must have been allocated with `_d_newThrowable()`.
70  * This is meant to be called at the close of a catch block.
71  * It's nothrow because otherwise any function with a catch block could
72  * not be nothrow.
73  * Input:
74  *      t = Throwable
75  */
76 
nothrow(C)77 nothrow extern (C) void _d_delThrowable(Throwable t)
78 {
79     if (t)
80     {
81         debug(PRINTF) printf("_d_delThrowable(%p)\n", t);
82 
83         /* If allocated by the GC, don't free it.
84          * Let the GC handle it.
85          * Supporting this is necessary while transitioning
86          * to this new scheme for allocating exceptions.
87          */
88         auto refcount = t.refcount();
89         if (refcount == 0)
90             return;     // it was allocated by the GC
91 
92         if (refcount == 1)
93             assert(0);  // no zombie objects
94 
95         t.refcount() = --refcount;
96         if (refcount > 1)
97             return;
98 
99         TypeInfo_Class **pc = cast(TypeInfo_Class **)t;
100         if (*pc)
101         {
102             TypeInfo_Class ci = **pc;
103 
104             if (!(ci.m_flags & TypeInfo_Class.ClassFlags.noPointers))
105             {
106                 // Inform the GC about the pointers in the object instance
107                 import core.memory : GC;
108                 GC.removeRange(cast(void*) t);
109             }
110         }
111 
112         try
113         {
114             import rt.lifetime : rt_finalize;
115             rt_finalize(cast(void*) t);
116         }
117         catch (Throwable t)
118         {
119             assert(0);  // should never happen since Throwable.~this() is nothrow
120         }
121         import core.stdc.stdlib : free;
122         debug(PRINTF) printf("free(%p)\n", t);
123         free(cast(void*) t);
124     }
125 }
126