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 */
20 module core.internal.gc.impl.manual.gc;
21
22 import core.gc.gcinterface;
23
24 import core.internal.container.array;
25
26 import cstdlib = core.stdc.stdlib : calloc, free, malloc, realloc;
27 static import core.memory;
28
29 extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc; /* dmd @@@BUG11461@@@ */
30
31 // register GC in C constructor (_STI_)
pragma(crt_constructor)32 extern(C) pragma(crt_constructor) void _d_register_manual_gc()
33 {
34 import core.gc.registry;
35 registerGCFactory("manual", &initialize);
36 }
37
initialize()38 private 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
49 class ManualGC : GC
50 {
51 Array!Root roots;
52 Array!Range ranges;
53
this()54 this()
55 {
56 }
57
~this()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
enable()65 void enable()
66 {
67 }
68
disable()69 void disable()
70 {
71 }
72
collect()73 void collect() nothrow
74 {
75 }
76
collectNoStack()77 void collectNoStack() nothrow
78 {
79 }
80
minimize()81 void minimize() nothrow
82 {
83 }
84
getAttr(void * p)85 uint getAttr(void* p) nothrow
86 {
87 return 0;
88 }
89
setAttr(void * p,uint mask)90 uint setAttr(void* p, uint mask) nothrow
91 {
92 return 0;
93 }
94
clrAttr(void * p,uint mask)95 uint clrAttr(void* p, uint mask) nothrow
96 {
97 return 0;
98 }
99
malloc(size_t size,uint bits,const TypeInfo ti)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
qalloc(size_t size,uint bits,const scope TypeInfo ti)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
calloc(size_t size,uint bits,const TypeInfo ti)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
realloc(void * p,size_t size,uint bits,const TypeInfo ti)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
extend(void * p,size_t minsize,size_t maxsize,const TypeInfo ti)136 size_t extend(void* p, size_t minsize, size_t maxsize, const TypeInfo ti) nothrow
137 {
138 return 0;
139 }
140
reserve(size_t size)141 size_t reserve(size_t size) nothrow
142 {
143 return 0;
144 }
145
free(void * p)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 */
addrOf(void * p)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 */
sizeOf(void * p)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 */
query(void * p)173 BlkInfo query(void* p) nothrow
174 {
175 return BlkInfo.init;
176 }
177
stats()178 core.memory.GC.Stats stats() nothrow
179 {
180 return typeof(return).init;
181 }
182
profileStats()183 core.memory.GC.ProfileStats profileStats() nothrow
184 {
185 return typeof(return).init;
186 }
187
addRoot(void * p)188 void addRoot(void* p) nothrow @nogc
189 {
190 roots.insertBack(Root(p));
191 }
192
removeRoot(void * p)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