1238106Sdes/**
2238106Sdes * Exception allocation, cloning, and release compiler support routines.
3238106Sdes *
4238106Sdes * Copyright: Copyright (c) 2017 by D Language Foundation
5238106Sdes * License: Distributed under the
6238106Sdes *      $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
7238106Sdes *    (See accompanying file LICENSE)
8238106Sdes * Authors: Walter Bright
9238106Sdes * Source: $(DRUNTIMESRC rt/_ehalloc.d)
10238106Sdes */
11238106Sdes
12238106Sdesmodule rt.ehalloc;
13238106Sdes
14238106Sdes//debug = PRINTF;
15238106Sdes
16238106Sdesdebug(PRINTF)
17238106Sdes{
18238106Sdes    import core.stdc.stdio;
19238106Sdes}
20238106Sdes
21238106Sdes/**********************************************
22238106Sdes * Allocate an exception of type `ci` from the exception pool.
23238106Sdes * It has the same interface as `rt.lifetime._d_newclass()`.
24266114Sdes * The class type must be Throwable or derived from it,
25266114Sdes * and cannot be a COM or C++ class. The compiler must enforce
26266114Sdes * this.
27266114Sdes * Returns:
28266114Sdes *      default initialized instance of the type
29266114Sdes */
30266114Sdes
31266114Sdesextern (C) Throwable _d_newThrowable(const TypeInfo_Class ci)
32266114Sdes{
33266114Sdes    debug(PRINTF) printf("_d_newThrowable(ci = %p, %s)\n", ci, cast(char *)ci.name);
34238106Sdes
35238106Sdes    assert(!(ci.m_flags & TypeInfo_Class.ClassFlags.isCOMclass));
36238106Sdes    assert(!(ci.m_flags & TypeInfo_Class.ClassFlags.isCPPclass));
37238106Sdes
38238106Sdes    import core.stdc.stdlib : malloc;
39238106Sdes    auto init = ci.initializer;
40238106Sdes    void* p = malloc(init.length);
41238106Sdes    if (!p)
42238106Sdes    {
43266114Sdes        import core.exception : onOutOfMemoryError;
44266114Sdes        onOutOfMemoryError();
45266114Sdes    }
46266114Sdes
47266114Sdes    debug(PRINTF) printf(" p = %p\n", p);
48238106Sdes
49238106Sdes    // initialize it
50238106Sdes    p[0 .. init.length] = init[];
51238106Sdes
52238106Sdes    if (!(ci.m_flags & TypeInfo_Class.ClassFlags.noPointers))
53287917Sdes    {
54238106Sdes        // Inform the GC about the pointers in the object instance
55238106Sdes        import core.memory : GC;
56238106Sdes
57238106Sdes        GC.addRange(p, init.length, ci);
58238106Sdes    }
59287917Sdes
60276605Sdes    debug(PRINTF) printf("initialization done\n");
61276605Sdes    Throwable t = cast(Throwable)p;
62276605Sdes    t.refcount() = 1;
63238106Sdes    return t;
64238106Sdes}
65238106Sdes
66238106Sdes
67238106Sdes/********************************************
68238106Sdes * Delete exception instance `t` from the exception pool.
69238106Sdes * Must have been allocated with `_d_newThrowable()`.
70238106Sdes * This is meant to be called at the close of a catch block.
71238106Sdes * It's nothrow because otherwise any function with a catch block could
72238106Sdes * not be nothrow.
73238106Sdes * Input:
74238106Sdes *      t = Throwable
75238106Sdes */
76238106Sdes
77238106Sdesnothrow extern (C) void _d_delThrowable(Throwable t)
78238106Sdes{
79238106Sdes    if (t)
80238106Sdes    {
81238106Sdes        debug(PRINTF) printf("_d_delThrowable(%p)\n", t);
82238106Sdes
83238106Sdes        /* If allocated by the GC, don't free it.
84238106Sdes         * Let the GC handle it.
85238106Sdes         * Supporting this is necessary while transitioning
86238106Sdes         * to this new scheme for allocating exceptions.
87238106Sdes         */
88238106Sdes        auto refcount = t.refcount();
89238106Sdes        if (refcount == 0)
90238106Sdes            return;     // it was allocated by the GC
91238106Sdes
92238106Sdes        if (refcount == 1)
93238106Sdes            assert(0);  // no zombie objects
94238106Sdes
95238106Sdes        t.refcount() = --refcount;
96238106Sdes        if (refcount > 1)
97238106Sdes            return;
98238106Sdes
99238106Sdes        TypeInfo_Class **pc = cast(TypeInfo_Class **)t;
100238106Sdes        if (*pc)
101238106Sdes        {
102238106Sdes            TypeInfo_Class ci = **pc;
103238106Sdes
104238106Sdes            if (!(ci.m_flags & TypeInfo_Class.ClassFlags.noPointers))
105238106Sdes            {
106238106Sdes                // Inform the GC about the pointers in the object instance
107238106Sdes                import core.memory : GC;
108238106Sdes                GC.removeRange(cast(void*) t);
109238106Sdes            }
110238106Sdes        }
111238106Sdes
112238106Sdes        try
113238106Sdes        {
114238106Sdes            import rt.lifetime : rt_finalize;
115238106Sdes            rt_finalize(cast(void*) t);
116238106Sdes        }
117238106Sdes        catch (Throwable t)
118238106Sdes        {
119238106Sdes            assert(0);  // should never happen since Throwable.~this() is nothrow
120238106Sdes        }
121238106Sdes        import core.stdc.stdlib : free;
122238106Sdes        debug(PRINTF) printf("free(%p)\n", t);
123238106Sdes        free(cast(void*) t);
124238106Sdes    }
125238106Sdes}
126238106Sdes