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 #1212 from rainers/aa_entry_typeinfo
Browse files Browse the repository at this point in the history
fix Issue 14423 - struct destructors not finalized for AA values
  • Loading branch information
MartinNowak committed Apr 17, 2015
2 parents 9cb2f2d + 7dd76e0 commit cfcf748
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 52 deletions.
17 changes: 11 additions & 6 deletions src/object.di
Expand Up @@ -206,7 +206,7 @@ class TypeInfo_Class : TypeInfo
void* deallocator;
OffsetTypeInfo[] m_offTi;
void* defaultConstructor;
immutable(void)* m_rtInfo; // data for precise GC
immutable(void)* m_RTInfo; // data for precise GC

static const(TypeInfo_Class) find(in char[] classname);
Object create() const;
Expand Down Expand Up @@ -234,11 +234,16 @@ class TypeInfo_Struct : TypeInfo
enum StructFlags : uint
{
hasPointers = 0x1,
isDynamicType = 0x2, // built at runtime, needs type info in xdtor
}
StructFlags m_flags;
}
void function(void*) xdtor;
void function(void*) xpostblit;
union
{
void function(void*) xdtor;
void function(void*, const TypeInfo_Struct ti) xdtorti;
}
void function(void*) xpostblit;

uint m_align;

Expand All @@ -247,7 +252,7 @@ class TypeInfo_Struct : TypeInfo
TypeInfo m_arg1;
TypeInfo m_arg2;
}
immutable(void)* m_rtInfo;
immutable(void)* m_RTInfo;
}

class TypeInfo_Tuple : TypeInfo
Expand Down Expand Up @@ -394,7 +399,7 @@ extern (C)
// from druntime/src/rt/aaA.d

// size_t _aaLen(in void* p) pure nothrow @nogc;
private void* _aaGetX(void** paa, const TypeInfo keyti, in size_t valuesize, in void* pkey) pure nothrow;
private void* _aaGetY(void** paa, const TypeInfo_AssociativeArray ti, in size_t valuesize, in void* pkey) pure nothrow;
// inout(void)* _aaGetRvalueX(inout void* p, in TypeInfo keyti, in size_t valuesize, in void* pkey);
inout(void)[] _aaValues(inout void* p, in size_t keysize, in size_t valuesize, const TypeInfo tiValArray) pure nothrow;
inout(void)[] _aaKeys(inout void* p, in size_t keysize, const TypeInfo tiKeyArray) pure nothrow;
Expand Down Expand Up @@ -468,7 +473,7 @@ V[K] dup(T : V[K], K, V)(T aa)
{
import core.stdc.string : memcpy;

void* pv = _aaGetX(cast(void**)&result, typeid(K), V.sizeof, &k);
void* pv = _aaGetY(cast(void**)&result, typeid(V[K]), V.sizeof, &k);
memcpy(pv, &v, V.sizeof);
return *cast(V*)pv;
}
Expand Down
18 changes: 13 additions & 5 deletions src/object_.d
Expand Up @@ -1054,11 +1054,14 @@ class TypeInfo_Struct : TypeInfo

override @property size_t talign() nothrow pure const { return m_align; }

override void destroy(void* p) const
final override void destroy(void* p) const
{
if (xdtor)
{
(*xdtor)(p);
if (m_flags & StructFlags.isDynamicType)
(*xdtorti)(p, this);
else
(*xdtor)(p);
}
}

Expand All @@ -1081,10 +1084,15 @@ class TypeInfo_Struct : TypeInfo
enum StructFlags : uint
{
hasPointers = 0x1,
isDynamicType = 0x2, // built at runtime, needs type info in xdtor
}
StructFlags m_flags;
}
void function(void*) xdtor;
union
{
void function(void*) xdtor;
void function(void*, const TypeInfo_Struct ti) xdtorti;
}
void function(void*) xpostblit;

uint m_align;
Expand Down Expand Up @@ -1983,7 +1991,7 @@ extern (C)
// from druntime/src/rt/aaA.d

// size_t _aaLen(in void* p) pure nothrow @nogc;
private void* _aaGetX(void** paa, const TypeInfo keyti, in size_t valuesize, in void* pkey) pure nothrow;
private void* _aaGetY(void** paa, const TypeInfo_AssociativeArray ti, in size_t valuesize, in void* pkey) pure nothrow;
// inout(void)* _aaGetRvalueX(inout void* p, in TypeInfo keyti, in size_t valuesize, in void* pkey);
inout(void)[] _aaValues(inout void* p, in size_t keysize, in size_t valuesize, const TypeInfo tiValArray) pure nothrow;
inout(void)[] _aaKeys(inout void* p, in size_t keysize, const TypeInfo tiKeyArray) pure nothrow;
Expand Down Expand Up @@ -2062,7 +2070,7 @@ V[K] dup(T : V[K], K, V)(T aa)
{
import core.stdc.string : memcpy;

void* pv = _aaGetX(cast(void**)&result, typeid(K), V.sizeof, &k);
void* pv = _aaGetY(cast(void**)&result, typeid(V[K]), V.sizeof, &k);
memcpy(pv, &v, V.sizeof);
return *cast(V*)pv;
}
Expand Down
125 changes: 89 additions & 36 deletions src/rt/aaA.d
Expand Up @@ -19,7 +19,7 @@ private
import core.stdc.string;
import core.stdc.stdio;
import core.memory;
import rt.lifetime : _d_newarrayU;
import rt.lifetime : _d_newarrayU, _d_newitemT, unqualify, __doPostblit;

// Convenience function to make sure the NO_INTERIOR gets set on the
// bucket array.
Expand Down Expand Up @@ -64,14 +64,82 @@ struct Entry
size_t hash;
/* key */
/* value */

static void Dtor(void*p, const TypeInfo_Struct sti)
{
// key and value type info stored after the TypeInfo_Struct by tiEntry()
auto sizeti = __traits(classInstanceSize, TypeInfo_Struct);
auto extra = cast(const(TypeInfo)*) (cast(void*)sti + sizeti);
extra[0].destroy(p + Entry.sizeof);
extra[1].destroy(p + Entry.sizeof + aligntsize(extra[0].tsize));
}
}

private bool hasDtor(const TypeInfo ti)
{
if (!ti)
return false;
if (typeid(ti) is typeid(TypeInfo_Struct))
if ((cast(TypeInfo_Struct)cast(void*)ti).xdtor)
return true;
if (typeid(ti) is typeid(TypeInfo_StaticArray))
return hasDtor(unqualify(ti.next()));

return false;
}

// build type info for Entry with additional key and value fields
TypeInfo_Struct tiEntry(const TypeInfo keyti, const TypeInfo valti)
{
auto kti = unqualify(keyti);
auto vti = unqualify(valti);
if (!hasDtor(kti) && !hasDtor(vti))
return null;

// save kti and vti after type info for struct
auto sizeti = __traits(classInstanceSize, TypeInfo_Struct);
auto sizeall = sizeti + 2 * (void*).sizeof;
void* p = GC.malloc(sizeall);
memcpy(p, typeid(TypeInfo_Struct).init().ptr, sizeti);

auto ti = cast(TypeInfo_Struct)p;
auto extra = cast(TypeInfo*) (p + sizeti);
extra[0] = cast() kti;
extra[1] = cast() vti;

static immutable tiName = __MODULE__ ~ ".Entry!(...)";
ti.name = tiName;

// we don't expect the Entry objects to be used outside of this module, so we have control
// over the non-usage of the callback methods and other entries and can keep these null
// xtoHash, xopEquals, xopCmp, xtoString and xpostblit
ti.m_RTInfo = null;
auto sizeEntry = Entry.sizeof + aligntsize(kti.tsize()) + valti.tsize();
ti.m_init = (cast(char*)null)[0..sizeEntry]; // init length, but not ptr

// xdtor needs to be built from the dtors of key and value for the GC
ti.xdtorti = &Entry.Dtor;

ti.m_flags = TypeInfo_Struct.StructFlags.hasPointers | TypeInfo_Struct.StructFlags.isDynamicType;
ti.m_align = cast(uint) aligntsize(1);

return ti;
}

struct Impl
{
this(const TypeInfo_AssociativeArray ti)
{
_keyti = cast() ti.key;
_entryti = cast() tiEntry(_keyti, ti.next);
}

Entry*[] buckets;
size_t nodes; // total number of entries
size_t firstUsedBucket; // starting index for first used bucket.
TypeInfo _keyti;
TypeInfo _keyti; // these should be const, but missing tail const for classes make this ugly
TypeInfo_Struct _entryti;

Entry*[4] binit; // initial value of buckets[]

@property const(TypeInfo) keyti() const @safe pure nothrow @nogc
Expand Down Expand Up @@ -160,31 +228,13 @@ body
* Get pointer to value in associative array indexed by key.
* Add entry for key if it is not already there.
*/
void* _aaGetX(AA* aa, const TypeInfo keyti, in size_t valuesize, in void* pkey)
in
{
assert(aa);
}
body
{
if (aa.impl is null)
{
aa.impl = new Impl();
aa.impl.buckets = aa.impl.binit[];
aa.impl.firstUsedBucket = aa.impl.buckets.length;
aa.impl._keyti = cast() keyti;
}
return _aaGetImpl(aa, keyti, valuesize, pkey);
}

void* _aaGetY(AA* aa, const TypeInfo_AssociativeArray ti, in size_t valuesize, in void* pkey)
{
if (aa.impl is null)
{
aa.impl = new Impl();
aa.impl = new Impl(ti);
aa.impl.buckets = aa.impl.binit[];
aa.impl.firstUsedBucket = aa.impl.buckets.length;
aa.impl._keyti = cast() ti.key;
}
return _aaGetImpl(aa, ti.key, valuesize, pkey);
}
Expand All @@ -202,13 +252,6 @@ body
//printf("keyti = %p\n", keyti);
//printf("aa = %p\n", aa);

if (aa.impl is null)
{
aa.impl = new Impl();
aa.impl.buckets = aa.impl.binit[];
aa.impl.firstUsedBucket = aa.impl.buckets.length;
aa.impl._keyti = cast() keyti;
}
//printf("aa = %p\n", aa);
//printf("aa.a = %p\n", aa.a);

Expand All @@ -234,11 +277,15 @@ body
// Not found, create new elem
//printf("create new one\n");
size_t size = Entry.sizeof + aligntsize(keytitsize) + valuesize;
e = cast(Entry *) GC.malloc(size, 0); // TODO: needs typeid(Entry+)
if (aa.impl._entryti)
e = cast(Entry *) _d_newitemT(aa.impl._entryti);
else
e = cast(Entry *) GC.malloc(size, 0); // TODO: needs typeid(Entry+)
e.next = null;
e.hash = key_hash;
ubyte* ptail = cast(ubyte*)(e + 1);
memcpy(ptail, pkey, keytitsize);
__doPostblit(ptail, keytitsize, unqualify(keyti));
memset(ptail + aligntsize(keytitsize), 0, valuesize); // zero value
*pe = e;

Expand All @@ -264,7 +311,8 @@ Lret:
void* _aaGetZ(AA* aa, const TypeInfo keyti, in size_t valuesize, in void* pkey,
void *function(void[], void[]) @trusted pure aaLiteral)
{
return _aaGetX(aa, keyti, valuesize, pkey);
assert(false, "_aaGetZ not implemented");
//return _aaGetX(aa, keyti, valuesize, pkey);
}

// bug 13748
Expand Down Expand Up @@ -356,7 +404,7 @@ bool _aaDelX(AA aa, in TypeInfo keyti, in void* pkey)
if (!(--aa.impl.nodes))
// reset cache, we know there are no nodes in the aa.
aa.impl.firstUsedBucket = aa.impl.buckets.length;
// ee could be freed here, but user code may
// ee could be freed here, but user code may
// hold pointers to it
return true;
}
Expand Down Expand Up @@ -386,12 +434,13 @@ inout(ArrayRet_t) _aaValues(inout AA aa, in size_t keysize, in size_t valuesize,
memcpy(a.ptr + resi * valuesize,
cast(byte*)e + Entry.sizeof + alignsize,
valuesize);
// TODO: no postblit here?
resi++;
e = e.next;
}
}
assert(resi == a.length);
// cannot postblit, it might not be pure
//__doPostblit(a.ptr, alignsize, unqualify(tiValueArray.next));
}
return *cast(inout ArrayRet_t*)(&a);
}
Expand Down Expand Up @@ -450,6 +499,7 @@ body

newImpl.nodes = oldImpl.nodes;
newImpl._keyti = oldImpl._keyti;
newImpl._entryti = oldImpl._entryti;

*paa.impl = newImpl;
}
Expand Down Expand Up @@ -482,12 +532,13 @@ inout(ArrayRet_t) _aaKeys(inout AA aa, in size_t keysize, const TypeInfo tiKeyAr
while (e)
{
memcpy(&res[resi * keysize], cast(byte*)(e + 1), keysize);
// TODO: no postblit here?
resi++;
e = e.next;
}
}
assert(resi == len);
// cannot postblit, it might not be pure
//__doPostblit(res, len * kisize, unqualify(tiKeyArray.next));

Array a;
a.length = len;
Expand Down Expand Up @@ -629,8 +680,7 @@ Impl* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void[] keys, vo
}
else
{
result = new Impl();
result._keyti = cast() keyti;
result = new Impl(ti);

size_t i;
for (i = 0; i < prime_list.length - 1; i++)
Expand Down Expand Up @@ -662,7 +712,10 @@ Impl* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void[] keys, vo
{
// Not found, create new elem
//printf("create new one\n");
e = cast(Entry *) GC.malloc(Entry.sizeof + keytsize + valuesize); // TODO: needs typeid(Entry+)
if (result._entryti)
e = cast(Entry *) _d_newitemT(result._entryti);
else
e = cast(Entry *) GC.malloc(Entry.sizeof + keytsize + valuesize); // TODO: needs typeid(Entry+)
memcpy(e + 1, pkey, keysize);
e.next = null;
e.hash = key_hash;
Expand Down

0 comments on commit cfcf748

Please sign in to comment.