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