/** * This module contains a minimal garbage collector implementation according to * published requirements. This library is mostly intended to serve as an * example, but it is usable in applications which do not rely on a garbage * collector to clean up memory (ie. when dynamic array resizing is not used, * and all memory allocated with 'new' is freed deterministically with * 'delete'). * * Please note that block attribute data must be tracked, or at a minimum, the * FINALIZE bit must be tracked for any allocated memory block because calling * rt_finalize on a non-object block can result in an access violation. In the * allocator below, this tracking is done via a leading uint bitmask. A real * allocator may do better to store this data separately, similar to the basic * GC. * * Copyright: Copyright Sean Kelly 2005 - 2016. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly */ /* Copyright Sean Kelly 2005 - 2016. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module gc.impl.manual.gc; import gc.config; import gc.gcinterface; import rt.util.container.array; import cstdlib = core.stdc.stdlib : calloc, free, malloc, realloc; static import core.memory; extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc; /* dmd @@@BUG11461@@@ */ class ManualGC : GC { __gshared Array!Root roots; __gshared Array!Range ranges; static void initialize(ref GC gc) { import core.stdc.string; if (config.gc != "manual") return; auto p = cstdlib.malloc(__traits(classInstanceSize, ManualGC)); if (!p) onOutOfMemoryError(); auto init = typeid(ManualGC).initializer(); assert(init.length == __traits(classInstanceSize, ManualGC)); auto instance = cast(ManualGC) memcpy(p, init.ptr, init.length); instance.__ctor(); gc = instance; } static void finalize(ref GC gc) { if (config.gc != "manual") return; auto instance = cast(ManualGC) gc; instance.Dtor(); cstdlib.free(cast(void*) instance); } this() { } void Dtor() { } void enable() { } void disable() { } void collect() nothrow { } void collectNoStack() nothrow { } void minimize() nothrow { } uint getAttr(void* p) nothrow { return 0; } uint setAttr(void* p, uint mask) nothrow { return 0; } uint clrAttr(void* p, uint mask) nothrow { return 0; } void* malloc(size_t size, uint bits, const TypeInfo ti) nothrow { void* p = cstdlib.malloc(size); if (size && p is null) onOutOfMemoryError(); return p; } BlkInfo qalloc(size_t size, uint bits, const TypeInfo ti) nothrow { BlkInfo retval; retval.base = malloc(size, bits, ti); retval.size = size; retval.attr = bits; return retval; } void* calloc(size_t size, uint bits, const TypeInfo ti) nothrow { void* p = cstdlib.calloc(1, size); if (size && p is null) onOutOfMemoryError(); return p; } void* realloc(void* p, size_t size, uint bits, const TypeInfo ti) nothrow { p = cstdlib.realloc(p, size); if (size && p is null) onOutOfMemoryError(); return p; } size_t extend(void* p, size_t minsize, size_t maxsize, const TypeInfo ti) nothrow { return 0; } size_t reserve(size_t size) nothrow { return 0; } void free(void* p) nothrow { cstdlib.free(p); } /** * Determine the base address of the block containing p. If p is not a gc * allocated pointer, return null. */ void* addrOf(void* p) nothrow { return null; } /** * Determine the allocated size of pointer p. If p is an interior pointer * or not a gc allocated pointer, return 0. */ size_t sizeOf(void* p) nothrow { return 0; } /** * Determine the base address of the block containing p. If p is not a gc * allocated pointer, return null. */ BlkInfo query(void* p) nothrow { return BlkInfo.init; } core.memory.GC.Stats stats() nothrow { return typeof(return).init; } void addRoot(void* p) nothrow @nogc { roots.insertBack(Root(p)); } void removeRoot(void* p) nothrow @nogc { foreach (ref r; roots) { if (r is p) { r = roots.back; roots.popBack(); return; } } assert(false); } @property RootIterator rootIter() return @nogc { return &rootsApply; } private int rootsApply(scope int delegate(ref Root) nothrow dg) { foreach (ref r; roots) { if (auto result = dg(r)) return result; } return 0; } void addRange(void* p, size_t sz, const TypeInfo ti = null) nothrow @nogc { ranges.insertBack(Range(p, p + sz, cast() ti)); } void removeRange(void* p) nothrow @nogc { foreach (ref r; ranges) { if (r.pbot is p) { r = ranges.back; ranges.popBack(); return; } } assert(false); } @property RangeIterator rangeIter() return @nogc { return &rangesApply; } private int rangesApply(scope int delegate(ref Range) nothrow dg) { foreach (ref r; ranges) { if (auto result = dg(r)) return result; } return 0; } void runFinalizers(in void[] segment) nothrow { } bool inFinalizer() nothrow { return false; } }