Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Commit

Permalink
Merge pull request #864 from Orvid/structDestructors
Browse files Browse the repository at this point in the history
Fix Issue 2834 - The GC will now call destructors on heap allocated structs
  • Loading branch information
MartinNowak committed Jan 15, 2015
2 parents 9dfde19 + bfaa918 commit dbbea7c
Show file tree
Hide file tree
Showing 6 changed files with 593 additions and 181 deletions.
23 changes: 14 additions & 9 deletions src/core/exception.d
Original file line number Diff line number Diff line change
Expand Up @@ -120,22 +120,22 @@ unittest
*/
class FinalizeError : Error
{
ClassInfo info;
TypeInfo info;

@safe pure nothrow this( ClassInfo ci, Throwable next, string file = __FILE__, size_t line = __LINE__ )
@safe pure nothrow this( TypeInfo ci, Throwable next, string file = __FILE__, size_t line = __LINE__ )
{
this(ci, file, line, next);
}

@safe pure nothrow this( ClassInfo ci, string file = __FILE__, size_t line = __LINE__, Throwable next = null )
@safe pure nothrow this( TypeInfo ci, string file = __FILE__, size_t line = __LINE__, Throwable next = null )
{
super( "Finalization error", file, line, next );
info = ci;
}

@safe override string toString() const
{
return "An exception was thrown while finalizing an instance of class " ~ info.name;
return "An exception was thrown while finalizing an instance of " ~ info.toString();
}
}

Expand Down Expand Up @@ -181,7 +181,6 @@ unittest
}
}


/**
* Thrown on hidden function error.
*/
Expand Down Expand Up @@ -453,7 +452,6 @@ extern (C) void onUnittestErrorMsg( string file, size_t line, string msg ) nothr
// Internal Error Callbacks
///////////////////////////////////////////////////////////////////////////////


/**
* A callback for array bounds errors in D. A $(LREF RangeError) will be thrown.
*
Expand All @@ -474,17 +472,24 @@ extern (C) void onRangeError( string file = __FILE__, size_t line = __LINE__ ) @
* A callback for finalize errors in D. A $(LREF FinalizeError) will be thrown.
*
* Params:
* info = The ClassInfo instance for the object that failed finalization.
* info = The TypeInfo instance for the object that failed finalization.
* e = The exception thrown during finalization.
* file = The name of the file that signaled this error.
* line = The line number on which this error occurred.
*
* Throws:
* $(LREF FinalizeError).
*/
extern (C) void onFinalizeError( ClassInfo info, Throwable e, string file = __FILE__, size_t line = __LINE__ ) @safe pure nothrow
extern (C) void onFinalizeError( TypeInfo info, Throwable e, string file = __FILE__, size_t line = __LINE__ ) @trusted nothrow
{
throw new FinalizeError( info, file, line, e );
// This error is thrown during a garbage collection, so no allocation must occur while
// generating this object. So we use a preallocated instance
__gshared FinalizeError err = new FinalizeError( null );
err.info = info;
err.next = e;
err.file = file;
err.line = line;
throw err;
}


Expand Down
6 changes: 4 additions & 2 deletions src/core/memory.d
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ struct GC
and is only implemented for data structures at least a page in size.
*/
NO_INTERIOR = 0b0001_0000,

STRUCTFINAL = 0b0010_0000, // the block has a finalizer for (an array of) structs
}


Expand Down Expand Up @@ -458,8 +460,8 @@ struct GC
* p = A pointer to the root of a valid memory block or to null.
* mx = The minimum extension size in bytes.
* sz = The desired extension size in bytes.
* ti = TypeInfo to describe the full memory block. The GC might use
* this information to improve scanning for pointers or to
* ti = TypeInfo to describe the full memory block. The GC might use
* this information to improve scanning for pointers or to
* call finalizers.
*
* Returns:
Expand Down
75 changes: 57 additions & 18 deletions src/gc/gc.d
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ private
{
// to allow compilation of this module without access to the rt package,
// make these functions available from rt.lifetime
void rt_finalize2(void* p, bool det, bool resetMemory) nothrow;
int rt_hasFinalizerInSegment(void* p, in void[] segment) nothrow;
void rt_finalizeFromGC(void* p, size_t size, uint attr) nothrow;
int rt_hasFinalizerInSegment(void* p, size_t size, uint attr, in void[] segment) nothrow;

// Declared as an extern instead of importing core.exception
// to avoid inlining - see issue 13725.
Expand Down Expand Up @@ -1548,13 +1548,18 @@ struct Gcx
if (bin > B_PAGE) continue;
size_t biti = pn;

auto p = pool.baseAddr + pn * PAGESIZE;
if (!pool.finals.test(biti))
continue;

auto p = sentinel_add(pool.baseAddr + pn * PAGESIZE);
size_t size = pool.bPageOffsets[pn] * PAGESIZE - SENTINEL_EXTRA;
uint attr = getBits(pool, biti);

if (!pool.finals.test(biti) ||
!rt_hasFinalizerInSegment(sentinel_add(p), segment))
if(!rt_hasFinalizerInSegment(p, size, attr, segment))
continue;

rt_finalize2(sentinel_add(p), false, false);
rt_finalizeFromGC(p, size, attr);

clrBits(pool, biti, ~BlkAttr.NONE);

if (pn < pool.searchStart) pool.searchStart = pn;
Expand Down Expand Up @@ -1601,11 +1606,17 @@ struct Gcx
clearIndex = biti & GCBits.BITS_MASK;
}

if (!pool.finals.test(biti) ||
!rt_hasFinalizerInSegment(sentinel_add(p), segment))
if (!pool.finals.test(biti))
continue;

rt_finalize2(sentinel_add(p), false, false);
auto q = sentinel_add(p);
uint attr = getBits(pool, biti);

if(!rt_hasFinalizerInSegment(q, size, attr, segment))
continue;

rt_finalizeFromGC(q, size, attr);

toClear |= GCBits.BITS_1 << clearIndex;

debug(COLLECT_PRINTF) printf("\tcollecting %p\n", p);
Expand Down Expand Up @@ -2120,7 +2131,7 @@ struct Gcx
* Allocate a chunk of memory that is larger than a page.
* Return null if out of memory.
*/
void* bigAlloc(size_t size, ref size_t alloc_size, uint bits) nothrow
void* bigAlloc(size_t size, ref size_t alloc_size, uint bits, const TypeInfo ti = null) nothrow
{
debug(PRINTF) printf("In bigAlloc. Size: %d\n", size);

Expand Down Expand Up @@ -2627,15 +2638,22 @@ struct Gcx
size_t biti = pn;

if (!pool.mark.test(biti))
{ byte *p = pool.baseAddr + pn * PAGESIZE;
{
byte *p = pool.baseAddr + pn * PAGESIZE;
void* q = sentinel_add(p);
sentinel_Invariant(q);

sentinel_Invariant(sentinel_add(p));
if (pool.finals.nbits && pool.finals.testClear(biti))
rt_finalize2(sentinel_add(p), false, false);
{
size_t size = pool.bPageOffsets[pn] * PAGESIZE - SENTINEL_EXTRA;
uint attr = getBits(pool, biti);
rt_finalizeFromGC(q, size, attr);
}

clrBits(pool, biti, ~BlkAttr.NONE ^ BlkAttr.FINALIZE);

debug(COLLECT_PRINTF) printf("\tcollecting big %p\n", p);
log_free(sentinel_add(p));
log_free(q);
pool.pagetable[pn] = B_FREE;
if(pn < pool.searchStart) pool.searchStart = pn;
freedpages++;
Expand Down Expand Up @@ -2697,11 +2715,14 @@ struct Gcx

if (!pool.mark.test(biti))
{
sentinel_Invariant(sentinel_add(p));
void* q = sentinel_add(p);
sentinel_Invariant(q);

pool.freebits.set(biti);

if (pool.finals.nbits && pool.finals.test(biti))
rt_finalize2(sentinel_add(p), false, false);
rt_finalizeFromGC(q, size - SENTINEL_EXTRA, getBits(pool, biti));

toClear |= GCBits.BITS_1 << clearIndex;

List *list = cast(List *)p;
Expand Down Expand Up @@ -2848,9 +2869,10 @@ struct Gcx
{
uint bits;

if (pool.finals.nbits &&
pool.finals.test(biti))
if (pool.finals.nbits && pool.finals.test(biti))
bits |= BlkAttr.FINALIZE;
if (pool.structFinals.nbits && pool.structFinals.test(biti))
bits |= BlkAttr.STRUCTFINAL;
if (pool.noscan.test(biti))
bits |= BlkAttr.NO_SCAN;
if (pool.nointerior.nbits && pool.nointerior.test(biti))
Expand Down Expand Up @@ -2880,12 +2902,20 @@ struct Gcx
immutable bitOffset = biti & GCBits.BITS_MASK;
immutable orWith = GCBits.BITS_1 << bitOffset;

if (mask & BlkAttr.STRUCTFINAL)
{
if (!pool.structFinals.nbits)
pool.structFinals.alloc(pool.mark.nbits);
pool.structFinals.data[dataIndex] |= orWith;
}

if (mask & BlkAttr.FINALIZE)
{
if (!pool.finals.nbits)
pool.finals.alloc(pool.mark.nbits);
pool.finals.data[dataIndex] |= orWith;
}

if (mask & BlkAttr.NO_SCAN)
{
pool.noscan.data[dataIndex] |= orWith;
Expand Down Expand Up @@ -2926,6 +2956,10 @@ struct Gcx

if (mask & BlkAttr.FINALIZE && pool.finals.nbits)
pool.finals.data[dataIndex] &= keep;

if (pool.structFinals.nbits && (mask & BlkAttr.STRUCTFINAL))
pool.structFinals.data[dataIndex] &= keep;

if (mask & BlkAttr.NO_SCAN)
pool.noscan.data[dataIndex] &= keep;
// if (mask & BlkAttr.NO_MOVE && pool.nomove.nbits)
Expand All @@ -2946,6 +2980,8 @@ struct Gcx
immutable toKeep = ~toClear;
if (pool.finals.nbits)
pool.finals.data[dataIndex] &= toKeep;
if (pool.structFinals.nbits)
pool.structFinals.data[dataIndex] &= toKeep;

pool.noscan.data[dataIndex] &= toKeep;

Expand Down Expand Up @@ -3091,6 +3127,7 @@ struct Pool
GCBits scan; // entries that need to be scanned
GCBits freebits; // entries that are on the free list
GCBits finals; // entries that need finalizer run on them
GCBits structFinals;// struct entries that need a finalzier run on them
GCBits noscan; // entries that should not be scanned
GCBits appendable; // entries that are appendable
GCBits nointerior; // interior pointers should be ignored.
Expand Down Expand Up @@ -3211,6 +3248,7 @@ struct Pool
freebits.Dtor();
}
finals.Dtor();
structFinals.Dtor();
noscan.Dtor();
appendable.Dtor();
}
Expand All @@ -3226,6 +3264,7 @@ struct Pool
//scan.Invariant();
//freebits.Invariant();
//finals.Invariant();
//structFinals.Invariant();
//noscan.Invariant();
//appendable.Invariant();
//nointerior.Invariant();
Expand Down
2 changes: 2 additions & 0 deletions src/object_.d
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,9 @@ class TypeInfo_Struct : TypeInfo
override void destroy(void* p) const
{
if (xdtor)
{
(*xdtor)(p);
}
}

override void postblit(void* p) const
Expand Down
2 changes: 2 additions & 0 deletions src/rt/dmain2.d
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ extern (C) void _STI_critical_init();
extern (C) void _STD_critical_term();
extern (C) void gc_init();
extern (C) void gc_term();
extern (C) void lifetime_init();
extern (C) void rt_moduleCtor();
extern (C) void rt_moduleTlsCtor();
extern (C) void rt_moduleDtor();
Expand Down Expand Up @@ -166,6 +167,7 @@ extern (C) int rt_init()
initSections();
gc_init();
initStaticDataGC();
lifetime_init();
rt_moduleCtor();
rt_moduleTlsCtor();
return 1;
Expand Down
Loading

0 comments on commit dbbea7c

Please sign in to comment.