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