1/**
2 * This module contains a minimal garbage collector implementation according to
3 * published requirements.  This library is mostly intended to serve as an
4 * example, but it is usable in applications which do not rely on a garbage
5 * collector to clean up memory (ie. when dynamic array resizing is not used,
6 * and all memory allocated with 'new' is freed deterministically with
7 * 'delete').
8 *
9 * Please note that block attribute data must be tracked, or at a minimum, the
10 * FINALIZE bit must be tracked for any allocated memory block because calling
11 * rt_finalize on a non-object block can result in an access violation.  In the
12 * allocator below, this tracking is done via a leading uint bitmask.  A real
13 * allocator may do better to store this data separately, similar to the basic
14 * GC.
15 *
16 * Copyright: Copyright Sean Kelly 2005 - 2016.
17 * License:   $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
18 * Authors:   Sean Kelly
19 */
20
21/*          Copyright Sean Kelly 2005 - 2016.
22 * Distributed under the Boost Software License, Version 1.0.
23 *    (See accompanying file LICENSE or copy at
24 *          http://www.boost.org/LICENSE_1_0.txt)
25 */
26module gc.impl.manual.gc;
27
28import gc.config;
29import gc.gcinterface;
30
31import rt.util.container.array;
32
33import cstdlib = core.stdc.stdlib : calloc, free, malloc, realloc;
34static import core.memory;
35
36extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc; /* dmd @@@BUG11461@@@ */
37
38class ManualGC : GC
39{
40    __gshared Array!Root roots;
41    __gshared Array!Range ranges;
42
43    static void initialize(ref GC gc)
44    {
45        import core.stdc.string;
46
47        if (config.gc != "manual")
48            return;
49
50        auto p = cstdlib.malloc(__traits(classInstanceSize, ManualGC));
51        if (!p)
52            onOutOfMemoryError();
53
54        auto init = typeid(ManualGC).initializer();
55        assert(init.length == __traits(classInstanceSize, ManualGC));
56        auto instance = cast(ManualGC) memcpy(p, init.ptr, init.length);
57        instance.__ctor();
58
59        gc = instance;
60    }
61
62    static void finalize(ref GC gc)
63    {
64        if (config.gc != "manual")
65            return;
66
67        auto instance = cast(ManualGC) gc;
68        instance.Dtor();
69        cstdlib.free(cast(void*) instance);
70    }
71
72    this()
73    {
74    }
75
76    void Dtor()
77    {
78    }
79
80    void enable()
81    {
82    }
83
84    void disable()
85    {
86    }
87
88    void collect() nothrow
89    {
90    }
91
92    void collectNoStack() nothrow
93    {
94    }
95
96    void minimize() nothrow
97    {
98    }
99
100    uint getAttr(void* p) nothrow
101    {
102        return 0;
103    }
104
105    uint setAttr(void* p, uint mask) nothrow
106    {
107        return 0;
108    }
109
110    uint clrAttr(void* p, uint mask) nothrow
111    {
112        return 0;
113    }
114
115    void* malloc(size_t size, uint bits, const TypeInfo ti) nothrow
116    {
117        void* p = cstdlib.malloc(size);
118
119        if (size && p is null)
120            onOutOfMemoryError();
121        return p;
122    }
123
124    BlkInfo qalloc(size_t size, uint bits, const TypeInfo ti) nothrow
125    {
126        BlkInfo retval;
127        retval.base = malloc(size, bits, ti);
128        retval.size = size;
129        retval.attr = bits;
130        return retval;
131    }
132
133    void* calloc(size_t size, uint bits, const TypeInfo ti) nothrow
134    {
135        void* p = cstdlib.calloc(1, size);
136
137        if (size && p is null)
138            onOutOfMemoryError();
139        return p;
140    }
141
142    void* realloc(void* p, size_t size, uint bits, const TypeInfo ti) nothrow
143    {
144        p = cstdlib.realloc(p, size);
145
146        if (size && p is null)
147            onOutOfMemoryError();
148        return p;
149    }
150
151    size_t extend(void* p, size_t minsize, size_t maxsize, const TypeInfo ti) nothrow
152    {
153        return 0;
154    }
155
156    size_t reserve(size_t size) nothrow
157    {
158        return 0;
159    }
160
161    void free(void* p) nothrow
162    {
163        cstdlib.free(p);
164    }
165
166    /**
167     * Determine the base address of the block containing p.  If p is not a gc
168     * allocated pointer, return null.
169     */
170    void* addrOf(void* p) nothrow
171    {
172        return null;
173    }
174
175    /**
176     * Determine the allocated size of pointer p.  If p is an interior pointer
177     * or not a gc allocated pointer, return 0.
178     */
179    size_t sizeOf(void* p) nothrow
180    {
181        return 0;
182    }
183
184    /**
185     * Determine the base address of the block containing p.  If p is not a gc
186     * allocated pointer, return null.
187     */
188    BlkInfo query(void* p) nothrow
189    {
190        return BlkInfo.init;
191    }
192
193    core.memory.GC.Stats stats() nothrow
194    {
195        return typeof(return).init;
196    }
197
198    void addRoot(void* p) nothrow @nogc
199    {
200        roots.insertBack(Root(p));
201    }
202
203    void removeRoot(void* p) nothrow @nogc
204    {
205        foreach (ref r; roots)
206        {
207            if (r is p)
208            {
209                r = roots.back;
210                roots.popBack();
211                return;
212            }
213        }
214        assert(false);
215    }
216
217    @property RootIterator rootIter() return @nogc
218    {
219        return &rootsApply;
220    }
221
222    private int rootsApply(scope int delegate(ref Root) nothrow dg)
223    {
224        foreach (ref r; roots)
225        {
226            if (auto result = dg(r))
227                return result;
228        }
229        return 0;
230    }
231
232    void addRange(void* p, size_t sz, const TypeInfo ti = null) nothrow @nogc
233    {
234        ranges.insertBack(Range(p, p + sz, cast() ti));
235    }
236
237    void removeRange(void* p) nothrow @nogc
238    {
239        foreach (ref r; ranges)
240        {
241            if (r.pbot is p)
242            {
243                r = ranges.back;
244                ranges.popBack();
245                return;
246            }
247        }
248        assert(false);
249    }
250
251    @property RangeIterator rangeIter() return @nogc
252    {
253        return &rangesApply;
254    }
255
256    private int rangesApply(scope int delegate(ref Range) nothrow dg)
257    {
258        foreach (ref r; ranges)
259        {
260            if (auto result = dg(r))
261                return result;
262        }
263        return 0;
264    }
265
266    void runFinalizers(in void[] segment) nothrow
267    {
268    }
269
270    bool inFinalizer() nothrow
271    {
272        return false;
273    }
274}
275