159 changes: 52 additions & 107 deletions src/gc/gc.d
Original file line number Diff line number Diff line change
Expand Up @@ -256,20 +256,6 @@ debug (LOGGING)
const uint GCVERSION = 1; // increment every time we change interface
// to GC.

// This just makes Mutex final to de-virtualize member function calls.
final class GCMutex : Mutex
{
final override void lock() nothrow @trusted @nogc
{
super.lock_nothrow();
}

final override void unlock() nothrow @trusted @nogc
{
super.unlock_nothrow();
}
}

struct GC
{
// For passing to debug code (not thread safe)
Expand All @@ -282,18 +268,13 @@ struct GC

// We can't allocate a Mutex on the GC heap because we are the GC.
// Store it in the static data segment instead.
__gshared GCMutex gcLock; // global lock
__gshared void[__traits(classInstanceSize, GCMutex)] mutexStorage;

__gshared Config config;

void initialize()
{
config.initialize();

mutexStorage[] = typeid(GCMutex).init[];
gcLock = cast(GCMutex) mutexStorage.ptr;
gcLock.__ctor();
gcx = cast(Gcx*)cstdlib.calloc(1, Gcx.sizeof);
if (!gcx)
onOutOfMemoryError();
Expand Down Expand Up @@ -328,8 +309,8 @@ struct GC
*/
void enable()
{
gcLock.lock();
scope(exit) gcLock.unlock();

scope(exit)
assert(gcx.disabled > 0);
gcx.disabled--;
}
Expand All @@ -340,47 +321,11 @@ struct GC
*/
void disable()
{
gcLock.lock();
scope(exit) gcLock.unlock();

scope(exit)
gcx.disabled++;
}


mixin template doLock()
{
debug(PROFILE_API)
{
long tm = (GC.config.profile > 1 ? currTime.ticks : 0);
}

bool locked = (gcLock.lock(), true);

debug(PROFILE_API)
{
long tm2 = (GC.config.profile > 1 ? currTime.ticks : 0);
}
}

mixin template doUnlock(alias time, alias count)
{
debug(PROFILE_API)
{
bool unlocked = () {
if (GC.config.profile > 1)
{
count++;
long now = currTicks;
lockTime += tm2 - tm;
time += now - tm2;
}
gcLock.unlock();
return true;
}();
}
else
bool unlocked = (gcLock.unlock(), true);
}

/**
*
*/
Expand All @@ -406,9 +351,9 @@ struct GC
return oldb;
}

mixin doLock!();

uint rc = go();
mixin doUnlock!(otherTime, numOthers);

return rc;
}

Expand Down Expand Up @@ -439,9 +384,9 @@ struct GC
return oldb;
}

mixin doLock!();

uint rc = go();
mixin doUnlock!(otherTime, numOthers);

return rc;
}

Expand Down Expand Up @@ -472,9 +417,9 @@ struct GC
return oldb;
}

mixin doLock!();

uint rc = go();
mixin doUnlock!(otherTime, numOthers);

return rc;
}

Expand All @@ -497,9 +442,9 @@ struct GC
// Since a finalizer could launch a new thread, we always need to lock
// when collecting. The safest way to do this is to simply always lock
// when allocating.
mixin doLock!();

p = mallocNoSync(size, bits, *alloc_size, ti);
mixin doUnlock!(mallocTime, numMallocs);


if (!(bits & BlkAttr.NO_SCAN))
{
Expand Down Expand Up @@ -560,9 +505,9 @@ struct GC
// Since a finalizer could launch a new thread, we always need to lock
// when collecting. The safest way to do this is to simply always lock
// when allocating.
mixin doLock!();

p = mallocNoSync(size, bits, *alloc_size, ti);
mixin doUnlock!(mallocTime, numMallocs);


memset(p, 0, size);
if (!(bits & BlkAttr.NO_SCAN))
Expand All @@ -585,9 +530,9 @@ struct GC
// Since a finalizer could launch a new thread, we always need to lock
// when collecting. The safest way to do this is to simply always lock
// when allocating.
mixin doLock!();

p = reallocNoSync(p, size, bits, *alloc_size, ti);
mixin doUnlock!(mallocTime, numMallocs);


if (p !is oldp && !(bits & BlkAttr.NO_SCAN))
{
Expand Down Expand Up @@ -754,9 +699,9 @@ struct GC
*/
size_t extend(void* p, size_t minsize, size_t maxsize, const TypeInfo ti = null) nothrow
{
mixin doLock!();

size_t rc = extendNoSync(p, minsize, maxsize, ti);
mixin doUnlock!(extendTime, numExtends);


return rc;
}
Expand Down Expand Up @@ -832,9 +777,9 @@ struct GC
return 0;
}

gcLock.lock();

auto rc = reserveNoSync(size);
gcLock.unlock();

return rc;
}

Expand Down Expand Up @@ -865,9 +810,9 @@ struct GC
return;
}

mixin doLock!();

freeNoSync(p);
mixin doUnlock!(freeTime, numFrees);

}


Expand Down Expand Up @@ -949,9 +894,9 @@ struct GC
return null;
}

mixin doLock!();

void* rc = addrOfNoSync(p);
mixin doUnlock!(otherTime, numOthers);


return rc;
}
Expand Down Expand Up @@ -985,9 +930,9 @@ struct GC
return 0;
}

mixin doLock!();

size_t rc = sizeOfNoSync(p);
mixin doUnlock!(otherTime, numOthers);


return rc;
}
Expand Down Expand Up @@ -1040,9 +985,9 @@ struct GC
return i;
}

mixin doLock!();

BlkInfo rc = queryNoSync(p);
mixin doUnlock!(otherTime, numOthers);


return rc;
}
Expand Down Expand Up @@ -1081,9 +1026,9 @@ struct GC
return;
}

mixin doLock!();

checkNoSync(p);
mixin doUnlock!(otherTime, numOthers);

}


Expand Down Expand Up @@ -1138,9 +1083,9 @@ struct GC
return;
}

mixin doLock!();

gcx.addRoot(p);
mixin doUnlock!(otherTime, numOthers);

}


Expand All @@ -1154,17 +1099,17 @@ struct GC
return;
}

mixin doLock!();

gcx.removeRoot(p);
mixin doUnlock!(otherTime, numOthers);

}


private auto rootIterImpl(scope int delegate(ref Root) nothrow dg) nothrow
{
gcLock.lock();

auto res = gcx.roots.opApply(dg);
gcLock.unlock();

return res;
}

Expand All @@ -1189,9 +1134,9 @@ struct GC

//debug(PRINTF) printf("+GC.addRange(p = %p, sz = 0x%zx), p + sz = %p\n", p, sz, p + sz);

mixin doLock!();

gcx.addRange(p, p + sz, ti);
mixin doUnlock!(otherTime, numOthers);


//debug(PRINTF) printf("-GC.addRange()\n");
}
Expand All @@ -1207,26 +1152,26 @@ struct GC
return;
}

mixin doLock!();

gcx.removeRange(p);
mixin doUnlock!(otherTime, numOthers);

}

/**
* run finalizers
*/
void runFinalizers(in void[] segment) nothrow
{
mixin doLock!();

gcx.runFinalizers(segment);
mixin doUnlock!(otherTime, numOthers);

}

private auto rangeIterImpl(scope int delegate(ref Range) nothrow dg) nothrow
{
gcLock.lock();

auto res = gcx.ranges.opApply(dg);
gcLock.unlock();

return res;
}

Expand All @@ -1251,9 +1196,9 @@ struct GC
// Since a finalizer could launch a new thread, we always need to lock
// when collecting.
{
gcLock.lock();

result = gcx.fullcollect();
gcLock.unlock();

}

version (none)
Expand All @@ -1278,9 +1223,9 @@ struct GC
// Since a finalizer could launch a new thread, we always need to lock
// when collecting.
{
gcLock.lock();

gcx.fullcollect(true);
gcLock.unlock();

}
}

Expand All @@ -1290,7 +1235,7 @@ struct GC
*/
void minimize() nothrow
{
gcLock.lock();


gcx.minimize();
GCStats stats;
Expand All @@ -1299,7 +1244,7 @@ struct GC
debug(PRINTF) printf("GC pool size: %llu\n", cast(ulong)stats.poolsize);
debug(PRINTF) printf("GC freelist size: %llu\n", cast(ulong)stats.freelistsize);

gcLock.unlock();

}


Expand All @@ -1309,9 +1254,9 @@ struct GC
*/
void getStats(out GCStats stats) nothrow
{
gcLock.lock();

getStatsNoSync(stats);
gcLock.unlock();

}


Expand Down
28 changes: 25 additions & 3 deletions src/gc/proxy.d
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import core.stdc.stdlib;

private
{
__gshared GC _gc;
GC _gc;

static import core.memory;
alias BlkInfo = core.memory.GC.BlkInfo;
Expand Down Expand Up @@ -63,8 +63,8 @@ private
}
}

__gshared Proxy pthis;
__gshared Proxy* proxy;
Proxy pthis;
Proxy* proxy;

void initProxy()
{
Expand Down Expand Up @@ -102,6 +102,28 @@ private
extern (C)
{

void gc_init_tls()
{
_gc.initialize();
initProxy();
}

void gc_term_tls()
{
// NOTE: There may be daemons threads still running when this routine is
// called. If so, cleaning memory out from under then is a good
// way to make them crash horribly. This probably doesn't matter
// much since the app is supposed to be shutting down anyway, but
// I'm disabling cleanup for now until I can think about it some
// more.
//
// NOTE: Due to popular demand, this has been re-enabled. It still has
// the problems mentioned above though, so I guess we'll see.
_gc.fullCollectNoStack(); // not really a 'collect all' -- still scans
// static data area, roots, and ranges.
_gc.Dtor();
}

void gc_init()
{
_gc.initialize();
Expand Down
21 changes: 15 additions & 6 deletions src/gcstub/gc.d
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ private
extern (C) void function(in void[]) gc_runFinalizers;
}

__gshared Proxy pthis;
__gshared Proxy* proxy;
Proxy pthis;
Proxy* proxy;

void initProxy()
{
Expand Down Expand Up @@ -104,8 +104,8 @@ private
pthis.gc_runFinalizers = &gc_runFinalizers;
}

__gshared void** roots = null;
__gshared size_t nroots = 0;
void** roots = null;
size_t nroots = 0;

struct Range
{
Expand All @@ -114,8 +114,17 @@ private
TypeInfo ti; // should be tail const, but doesn't exist for references
}

__gshared Range* ranges = null;
__gshared size_t nranges = 0;
Range* ranges = null;
size_t nranges = 0;
}

extern (C) void gc_init_tls() {
initProxy();
}

extern (C) void gc_term_tls() {
free( roots );
free( ranges );
}

extern (C) void gc_init()
Expand Down
1 change: 1 addition & 0 deletions src/rt/memory.d
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module rt.memory;
import core.memory;
import rt.sections;

extern(C)
void initStaticDataGC()
{
foreach (ref sg; SectionGroup)
Expand Down
4 changes: 2 additions & 2 deletions win64.mak
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ IMPDIR=import

MAKE=make

DFLAGS=-m$(MODEL) -conf= -release -O -dip25 -inline -w -Isrc -Iimport
UDFLAGS=-m$(MODEL) -conf= -release -O -dip25 -w -Isrc -Iimport
DFLAGS=-m$(MODEL) -conf= -debug -g -dip25 -inline -w -Isrc -Iimport
UDFLAGS=-m$(MODEL) -conf= -debug -g -dip25 -w -Isrc -Iimport
DDOCFLAGS=-conf= -c -w -o- -Isrc -Iimport -version=CoreDdoc

#CFLAGS=/O2 /I"$(VCDIR)"\INCLUDE /I"$(SDKDIR)"\Include
Expand Down