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:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
18 * Authors:   Sean Kelly
19 */
20module core.internal.gc.impl.manual.gc;
21
22import core.gc.gcinterface;
23
24import core.internal.container.array;
25
26import cstdlib = core.stdc.stdlib : calloc, free, malloc, realloc;
27static import core.memory;
28
29extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc; /* dmd @@@BUG11461@@@ */
30
31// register GC in C constructor (_STI_)
32extern(C) pragma(crt_constructor) void _d_register_manual_gc()
33{
34    import core.gc.registry;
35    registerGCFactory("manual", &initialize);
36}
37
38private GC initialize()
39{
40    import core.lifetime : emplace;
41
42    auto gc = cast(ManualGC) cstdlib.malloc(__traits(classInstanceSize, ManualGC));
43    if (!gc)
44        onOutOfMemoryError();
45
46    return emplace(gc);
47}
48
49class ManualGC : GC
50{
51    Array!Root roots;
52    Array!Range ranges;
53
54    this()
55    {
56    }
57
58    ~this()
59    {
60        // TODO: cannot free as memory is overwritten and
61        //  the monitor is still read in rt_finalize (called by destroy)
62        // cstdlib.free(cast(void*) this);
63    }
64
65    void enable()
66    {
67    }
68
69    void disable()
70    {
71    }
72
73    void collect() nothrow
74    {
75    }
76
77    void collectNoStack() nothrow
78    {
79    }
80
81    void minimize() nothrow
82    {
83    }
84
85    uint getAttr(void* p) nothrow
86    {
87        return 0;
88    }
89
90    uint setAttr(void* p, uint mask) nothrow
91    {
92        return 0;
93    }
94
95    uint clrAttr(void* p, uint mask) nothrow
96    {
97        return 0;
98    }
99
100    void* malloc(size_t size, uint bits, const TypeInfo ti) nothrow
101    {
102        void* p = cstdlib.malloc(size);
103
104        if (size && p is null)
105            onOutOfMemoryError();
106        return p;
107    }
108
109    BlkInfo qalloc(size_t size, uint bits, const scope TypeInfo ti) nothrow
110    {
111        BlkInfo retval;
112        retval.base = malloc(size, bits, ti);
113        retval.size = size;
114        retval.attr = bits;
115        return retval;
116    }
117
118    void* calloc(size_t size, uint bits, const TypeInfo ti) nothrow
119    {
120        void* p = cstdlib.calloc(1, size);
121
122        if (size && p is null)
123            onOutOfMemoryError();
124        return p;
125    }
126
127    void* realloc(void* p, size_t size, uint bits, const TypeInfo ti) nothrow
128    {
129        p = cstdlib.realloc(p, size);
130
131        if (size && p is null)
132            onOutOfMemoryError();
133        return p;
134    }
135
136    size_t extend(void* p, size_t minsize, size_t maxsize, const TypeInfo ti) nothrow
137    {
138        return 0;
139    }
140
141    size_t reserve(size_t size) nothrow
142    {
143        return 0;
144    }
145
146    void free(void* p) nothrow @nogc
147    {
148        cstdlib.free(p);
149    }
150
151    /**
152     * Determine the base address of the block containing p.  If p is not a gc
153     * allocated pointer, return null.
154     */
155    void* addrOf(void* p) nothrow @nogc
156    {
157        return null;
158    }
159
160    /**
161     * Determine the allocated size of pointer p.  If p is an interior pointer
162     * or not a gc allocated pointer, return 0.
163     */
164    size_t sizeOf(void* p) nothrow @nogc
165    {
166        return 0;
167    }
168
169    /**
170     * Determine the base address of the block containing p.  If p is not a gc
171     * allocated pointer, return null.
172     */
173    BlkInfo query(void* p) nothrow
174    {
175        return BlkInfo.init;
176    }
177
178    core.memory.GC.Stats stats() nothrow
179    {
180        return typeof(return).init;
181    }
182
183    core.memory.GC.ProfileStats profileStats() nothrow
184    {
185        return typeof(return).init;
186    }
187
188    void addRoot(void* p) nothrow @nogc
189    {
190        roots.insertBack(Root(p));
191    }
192
193    void removeRoot(void* p) nothrow @nogc
194    {
195        foreach (ref r; roots)
196        {
197            if (r is p)
198            {
199                r = roots.back;
200                roots.popBack();
201                return;
202            }
203        }
204        assert(false);
205    }
206
207    @property RootIterator rootIter() return @nogc
208    {
209        return &rootsApply;
210    }
211
212    private int rootsApply(scope int delegate(ref Root) nothrow dg)
213    {
214        foreach (ref r; roots)
215        {
216            if (auto result = dg(r))
217                return result;
218        }
219        return 0;
220    }
221
222    void addRange(void* p, size_t sz, const TypeInfo ti = null) nothrow @nogc
223    {
224        ranges.insertBack(Range(p, p + sz, cast() ti));
225    }
226
227    void removeRange(void* p) nothrow @nogc
228    {
229        foreach (ref r; ranges)
230        {
231            if (r.pbot is p)
232            {
233                r = ranges.back;
234                ranges.popBack();
235                return;
236            }
237        }
238        assert(false);
239    }
240
241    @property RangeIterator rangeIter() return @nogc
242    {
243        return &rangesApply;
244    }
245
246    private int rangesApply(scope int delegate(ref Range) nothrow dg)
247    {
248        foreach (ref r; ranges)
249        {
250            if (auto result = dg(r))
251                return result;
252        }
253        return 0;
254    }
255
256    void runFinalizers(const scope void[] segment) nothrow
257    {
258    }
259
260    bool inFinalizer() nothrow
261    {
262        return false;
263    }
264
265    ulong allocatedInCurrentThread() nothrow
266    {
267        return typeof(return).init;
268    }
269}
270