phobos/internal/gc/gc.d
2007-09-10 04:02:50 +00:00

433 lines
8.7 KiB
D

//
// Copyright (C) 2001-2004 by Digital Mars
// All Rights Reserved
// Written by Walter Bright
// www.digitalmars.com
// Storage allocation
module std.gc;
//debug = PRINTF;
import std.c.stdlib;
import std.string;
import gcx;
import std.outofmemory;
import gcstats;
GC* _gc;
void addRoot(void *p) { _gc.addRoot(p); }
void removeRoot(void *p) { _gc.removeRoot(p); }
void addRange(void *pbot, void *ptop) { _gc.addRange(pbot, ptop); }
void removeRange(void *pbot) { _gc.removeRange(pbot); }
void fullCollect() { _gc.fullCollect(); }
void fullCollectNoStack() { _gc.fullCollectNoStack(); }
void genCollect() { _gc.genCollect(); }
void minimize() { _gc.minimize(); }
void disable() { _gc.disable(); }
void enable() { _gc.enable(); }
void getStats(out GCStats stats) { _gc.getStats(stats); }
extern (C)
{
void _d_monitorrelease(Object h);
void gc_init()
{
_gc = cast(GC *) std.c.stdlib.calloc(1, GC.sizeof);
_gc.initialize();
//_gc.setStackBottom(_atopsp);
_gc.scanStaticData();
}
void gc_term()
{
_gc.fullCollectNoStack();
}
Object _d_newclass(ClassInfo ci)
{
void *p;
debug(PRINTF) printf("_d_newclass(ci = %p)\n", ci);
if (ci.flags & 1) // if COM object
{
p = cast(Object)std.c.stdlib.malloc(ci.init.length);
if (!p)
_d_OutOfMemory();
}
else
{
p = _gc.malloc(ci.init.length);
debug(PRINTF) printf(" p = %p\n", p);
_gc.setFinalizer(p, &new_finalizer);
}
debug (PRINTF)
{
printf("p = %p\n", p);
printf("ci = %p, ci.init = %p, len = %d\n", ci, ci.init, ci.init.length);
printf("vptr = %p\n", *cast(void **)ci.init);
printf("vtbl[0] = %p\n", (*cast(void ***)ci.init)[0]);
printf("vtbl[1] = %p\n", (*cast(void ***)ci.init)[1]);
printf("init[0] = %x\n", (cast(uint *)ci.init)[0]);
printf("init[1] = %x\n", (cast(uint *)ci.init)[1]);
printf("init[2] = %x\n", (cast(uint *)ci.init)[2]);
printf("init[3] = %x\n", (cast(uint *)ci.init)[3]);
printf("init[4] = %x\n", (cast(uint *)ci.init)[4]);
}
// Initialize it
(cast(byte*)p)[0 .. ci.init.length] = ci.init[];
//printf("initialization done\n");
return cast(Object)p;
}
extern (D) alias void (*fp_t)(Object); // generic function pointer
void _d_delinterface(void** p)
{
if (*p)
{
Interface *pi = **cast(Interface ***)*p;
Object o;
o = cast(Object)(*p - pi.offset);
_d_delclass(&o);
*p = null;
}
}
void _d_delclass(Object *p)
{
if (*p)
{
debug (PRINTF) printf("_d_delclass(%p)\n", *p);
version(0)
{
ClassInfo **pc = cast(ClassInfo **)*p;
if (*pc)
{
ClassInfo c = **pc;
if (c.deallocator)
{
_d_callfinalizer(*p);
fp_t fp = cast(fp_t)c.deallocator;
(*fp)(*p); // call deallocator
*p = null;
return;
}
}
}
_gc.free(*p);
*p = null;
}
}
ulong _d_new(uint length, uint size)
{
void *p;
ulong result;
debug(PRINTF) printf("_d_new(length = %d, size = %d)\n", length, size);
if (length == 0 || size == 0)
result = 0;
else
{
p = _gc.malloc(length * size);
debug(PRINTF) printf(" p = %p\n", p);
memset(p, 0, length * size);
result = cast(ulong)length + (cast(ulong)cast(uint)p << 32);
}
return result;
}
ulong _d_newarrayi(uint length, uint size, ...)
{
void *p;
ulong result;
debug(PRINTF) printf("_d_newarrayi(length = %d, size = %d)\n", length, size);
if (length == 0 || size == 0)
result = 0;
else
{ void* q = cast(void*)(&size + 1); // pointer to initializer
p = _gc.malloc(length * size);
debug(PRINTF) printf(" p = %p\n", p);
if (size == 1)
memset(p, *cast(ubyte*)q, length);
else
{
for (uint u = 0; u < length; u++)
{
memcpy(p + u * size, q, size);
}
}
result = cast(ulong)length + (cast(ulong)cast(uint)p << 32);
}
return result;
}
ulong _d_newbitarray(uint length, bit value)
{
void *p;
ulong result;
debug(PRINTF) printf("_d_newbitarray(length = %d, value = %d)\n", length, value);
if (length == 0)
result = 0;
else
{ uint size = (length + 7) >> 3; // number of bytes
ubyte fill = value ? 0xFF : 0;
p = _gc.malloc(size);
debug(PRINTF) printf(" p = %p\n", p);
memset(p, fill, size);
result = cast(ulong)length + (cast(ulong)cast(uint)p << 32);
}
return result;
}
struct Array
{
uint length;
byte *data;
};
// Perhaps we should get a a size argument like _d_new(), so we
// can zero out the array?
void _d_delarray(Array *p)
{
if (p)
{
assert(!p.length || p.data);
if (p.data)
_gc.free(p.data);
p.data = null;
p.length = 0;
}
}
void _d_delmemory(void* *p)
{
if (*p)
{
_gc.free(*p);
*p = null;
}
}
}
void new_finalizer(void *p, void *dummy)
{
//printf("new_finalizer(p = %p)\n", p);
_d_callfinalizer(p);
}
extern (C)
void _d_callfinalizer(void *p)
{
//printf("_d_callfinalizer(p = %p)\n", p);
if (p) // not necessary if called from gc
{
ClassInfo **pc = cast(ClassInfo **)p;
if (*pc)
{
ClassInfo c = **pc;
do
{
if (c.destructor)
{
fp_t fp = cast(fp_t)c.destructor;
(*fp)(cast(Object)p); // call destructor
}
c = c.base;
} while (c);
if ((cast(void**)p)[1]) // if monitor is not null
_d_monitorrelease(cast(Object)p);
*pc = null; // zero vptr
}
}
}
/+ ------------------------------------------------ +/
/******************************
* Resize dynamic arrays other than bit[].
*/
extern (C)
byte[] _d_arraysetlength(uint newlength, uint sizeelem, Array *p)
{
byte* newdata;
uint newsize;
debug(PRINTF)
{
printf("_d_arraysetlength(p = %p, sizeelem = %d, newlength = %d)\n", p, sizeelem, newlength);
if (p)
printf("\tp.data = %p, p.length = %d\n", p.data, p.length);
}
assert(sizeelem);
assert(!p.length || p.data);
if (newlength)
{
newsize = sizeelem * newlength;
if (p.length)
{ uint size = p.length * sizeelem;
newdata = p.data;
if (newsize > size)
{
uint cap = _gc.capacity(p.data);
if (cap < newsize)
{
newdata = cast(byte *)_gc.malloc(newsize);
newdata[0 .. size] = p.data[0 .. size];
}
newdata[size .. newsize] = 0;
}
}
else
{
newdata = cast(byte *)_gc.calloc(newsize, 1);
}
}
else
{
newdata = null;
}
p.data = newdata;
p.length = newlength;
return newdata[0 .. newlength];
}
/***************************
* Resize bit[] arrays.
*/
extern (C)
bit[] _d_arraysetlengthb(uint newlength, Array *p)
{
byte* newdata;
uint newsize;
debug (PRINTF)
printf("p = %p, newlength = %d\n", p, newlength);
assert(!p.length || p.data);
if (newlength)
{
newsize = ((newlength + 31) >> 5) * 4; // # bytes rounded up to uint
if (p.length)
{ uint size = ((p.length + 31) >> 5) * 4;
newdata = p.data;
if (newsize > size)
{
uint cap = _gc.capacity(p.data);
if (cap < newsize)
{
newdata = cast(byte *)_gc.malloc(newsize);
newdata[0 .. size] = p.data[0 .. size];
}
newdata[size .. newsize] = 0;
}
}
else
{
newdata = cast(byte *)_gc.calloc(newsize, 1);
}
}
else
{
newdata = null;
}
p.data = newdata;
p.length = newlength;
return (cast(bit *)newdata)[0 .. newlength];
}
/****************************************
* Append y[] to array x[].
* size is size of each array element.
*/
extern (C)
Array _d_arrayappend(Array *px, byte[] y, uint size)
{
uint cap = _gc.capacity(px.data);
uint length = px.length;
uint newlength = length + y.length;
if (newlength * size > cap)
{ byte* newdata;
newdata = cast(byte *)_gc.malloc(newlength * size);
memcpy(newdata, px.data, length * size);
px.data = newdata;
}
px.length = newlength;
px.data[length * size .. newlength * size] = y[];
return *px;
}
extern (C)
byte[] _d_arrayappendc(inout byte[] x, in uint size, ...)
{
uint cap = _gc.capacity(x);
uint length = x.length;
uint newlength = length + 1;
if (newlength * size > cap)
{ byte* newdata;
newdata = cast(byte *)_gc.malloc(newlength * size);
memcpy(newdata, x, length * size);
(cast(void **)(&x))[1] = newdata;
}
byte *argp = cast(byte *)(&size + 1);
*cast(int *)&x = newlength;
(cast(byte *)x)[length * size .. newlength * size] = argp[0 .. size];
return x;
/+
byte[] a;
uint length;
void *argp;
//printf("size = %d\n", size);
length = x.length + 1;
a = new byte[length * size];
memcpy(a, x, x.length * size);
argp = &size + 1;
//printf("*argp = %llx\n", *cast(long *)argp);
memcpy(&a[x.length * size], argp, size);
//printf("a[0] = %llx\n", *cast(long *)&a[0]);
*cast(int *)&a = length; // jam length
//printf("a[0] = %llx\n", *cast(long *)&a[0]);
x = a;
return a;
+/
}