mirror of
https://github.com/autc04/Retro68.git
synced 2024-11-29 12:50:35 +00:00
275 lines
6.0 KiB
D
275 lines
6.0 KiB
D
/**
|
|
* 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;
|
|
}
|
|
}
|