// precise GC related:
// https://issues.dlang.org/show_bug.cgi?id=3463
// https://issues.dlang.org/show_bug.cgi?id=4358
// https://issues.dlang.org/show_bug.cgi?id=9094
// https://issues.dlang.org/show_bug.cgi?id=13801
// https://issues.dlang.org/show_bug.cgi?id=18900
module testgc;
import core.memory;
import core.stdc.stdio;
class C
{
    __gshared int dtors;
    ~this() { dtors++; }
    C next;
    size_t val;
}
struct S
{
    __gshared int dtors;
    ~this() { dtors++; }
    size_t val;
    S* next;
}
struct L
{
    __gshared int dtors;
    ~this() { dtors++; }
    size_t[1000] data;
    S* node;
}
struct Roots
{
    C c;
    S *s;
    L *l;
};
Roots* roots;
size_t iroots;
void init()
{
    roots = new Roots;
    roots.c = new C;
    roots.c.next = new C;
    roots.s = new S;
    roots.s.next = new S;
    roots.l = new L;
    roots.l.node = new S;
}
void verifyPointers()
{
    assert(C.dtors == 0);
    assert(S.dtors == 0);
    assert(L.dtors == 0);
}
// compiling with -gx should help eliminating false pointers on the stack
Roots makeFalsePointers()
{
    roots.c.val = cast(size_t) cast(void*) roots.c.next;
    roots.c.next = null;
    roots.s.val = cast(size_t) cast(void*) roots.s.next;
    roots.s.next = null;
    roots.l.data[7] = cast(size_t) cast(void*) roots.l.node;
    roots.l.node = null;
    return Roots(null, null, null); // try to spill register contents
}
Roots moveRoot()
{
    iroots = cast(size_t)roots;
    roots = null;
    return Roots(null, null, null); // try to spill register contents
}
// compiling with -gx should help eliminating false pointers on the stack
void verifyFalsePointers()
{
    assert(C.dtors <= 1);
    if (C.dtors < 1) printf ("False pointers? C.dtors = %d, 1 expected\n", C.dtors);
    assert(S.dtors <= 2);
    if (S.dtors < 2) printf ("False pointers? S.dtors = %d, 2 expected\n", S.dtors);
    assert(L.dtors == 0);
}
extern(C) __gshared string[] rt_options = [ "gcopt=gc:precise", "scanDataSeg=precise" ];
void main()
{
    GC.collect(); // cleanup from unittests
    init();
    GC.collect(); // should collect nothing
    verifyPointers();
    makeFalsePointers();
    GC.collect(); // should collect roots.c.next, roots.s.next and roots.l.node
    verifyFalsePointers();
    moveRoot();
    GC.collect(); // should collect all
    version(Windows) // precise DATA scanning only implemented on Windows
    {
        assert(C.dtors <= 2);
        if (C.dtors < 2) printf ("False DATA pointers? C.dtors = %d, 2 expected\n", C.dtors);
        assert(S.dtors <= 3);
        if (S.dtors < 3) printf ("False DATA pointers? S.dtors = %d, 2 expected\n", S.dtors);
        assert(L.dtors <= 1);
        if (L.dtors < 1) printf ("False DATA pointers? L.dtors = %d, 1 expected\n", L.dtors);
    }
}