1// precise GC related:
2// https://issues.dlang.org/show_bug.cgi?id=3463
3// https://issues.dlang.org/show_bug.cgi?id=4358
4// https://issues.dlang.org/show_bug.cgi?id=9094
5// https://issues.dlang.org/show_bug.cgi?id=13801
6// https://issues.dlang.org/show_bug.cgi?id=18900
7module testgc;
8
9import core.memory;
10import core.stdc.stdio;
11
12class C
13{
14    __gshared int dtors;
15    ~this() { dtors++; }
16
17    C next;
18    size_t val;
19}
20
21struct S
22{
23    __gshared int dtors;
24    ~this() { dtors++; }
25
26    size_t val;
27    S* next;
28}
29
30struct L
31{
32    __gshared int dtors;
33    ~this() { dtors++; }
34
35    size_t[1000] data;
36    S* node;
37}
38
39struct Roots
40{
41    C c;
42    S *s;
43    L *l;
44};
45
46Roots* roots;
47size_t iroots;
48
49void init()
50{
51    roots = new Roots;
52    roots.c = new C;
53    roots.c.next = new C;
54
55    roots.s = new S;
56    roots.s.next = new S;
57
58    roots.l = new L;
59    roots.l.node = new S;
60}
61
62void verifyPointers()
63{
64    assert(C.dtors == 0);
65    assert(S.dtors == 0);
66    assert(L.dtors == 0);
67}
68
69// compiling with -gx should help eliminating false pointers on the stack
70Roots makeFalsePointers()
71{
72    roots.c.val = cast(size_t) cast(void*) roots.c.next;
73    roots.c.next = null;
74    roots.s.val = cast(size_t) cast(void*) roots.s.next;
75    roots.s.next = null;
76    roots.l.data[7] = cast(size_t) cast(void*) roots.l.node;
77    roots.l.node = null;
78
79    return Roots(null, null, null); // try to spill register contents
80}
81
82Roots moveRoot()
83{
84    iroots = cast(size_t)roots;
85    roots = null;
86
87    return Roots(null, null, null); // try to spill register contents
88}
89
90// compiling with -gx should help eliminating false pointers on the stack
91void verifyFalsePointers()
92{
93    assert(C.dtors <= 1);
94    if (C.dtors < 1) printf ("False pointers? C.dtors = %d, 1 expected\n", C.dtors);
95    assert(S.dtors <= 2);
96    if (S.dtors < 2) printf ("False pointers? S.dtors = %d, 2 expected\n", S.dtors);
97    assert(L.dtors == 0);
98}
99
100extern(C) __gshared string[] rt_options = [ "gcopt=gc:precise", "scanDataSeg=precise" ];
101
102void main()
103{
104    GC.collect(); // cleanup from unittests
105
106    init();
107    GC.collect(); // should collect nothing
108    verifyPointers();
109
110    makeFalsePointers();
111    GC.collect(); // should collect roots.c.next, roots.s.next and roots.l.node
112    verifyFalsePointers();
113
114    moveRoot();
115    GC.collect(); // should collect all
116
117    version(Windows) // precise DATA scanning only implemented on Windows
118    {
119        assert(C.dtors <= 2);
120        if (C.dtors < 2) printf ("False DATA pointers? C.dtors = %d, 2 expected\n", C.dtors);
121        assert(S.dtors <= 3);
122        if (S.dtors < 3) printf ("False DATA pointers? S.dtors = %d, 2 expected\n", S.dtors);
123        assert(L.dtors <= 1);
124        if (L.dtors < 1) printf ("False DATA pointers? L.dtors = %d, 1 expected\n", L.dtors);
125    }
126}
127