]> git.llucax.com Git - software/dgc/naive.git/blob - gc/cell.d
d196f6010a2b08748808624ce920b27fa73892da
[software/dgc/naive.git] / gc / cell.d
1 /**
2  * Memory Cell header manipulation.
3  *
4  * This module has the Cell header definition and other support stuff (like
5  * BlkAttr) for the Naive Garbage Collector implementation. The Cell header has
6  * all the information needed for the bookkeeping of the GC allocated memory,
7  * like the mark bit, if the cell contents should be finalized or if it has
8  * pointers that should be scanned, etc.
9  *
10  * See_Also:  gc module
11  * Copyright: Public Domain
12  * License:   Public Domain
13  * Authors:   Leandro Lucarella <llucax@gmail.com>
14  */
15
16 module gc.cell;
17
18 package:
19
20 /**
21  * Iterates a range of memory interpreting it as an array of void*.
22  *
23  * This function is designed to be used as a opApply implementation.
24  */
25 int op_apply_ptr_range(void* from, void* to, int delegate(ref void*) dg)
26 {
27     int result = 0;
28     auto start = cast(void**) from;
29     auto end = cast(void**) to;
30     // since we sweep the memory range in word-sized steps, we need to make
31     // sure we don't scan for pointers beyond the end of the memory range
32     for (auto current = start; current + 1 <= end; current++) {
33         result = dg(*current);
34         if (result)
35             break;
36     }
37     return result;
38 }
39
40 /// Memory block (cell) attributes.
41 enum BlkAttr : uint
42 {
43     /// All attributes disabled.
44     NONE     = 0b0000_0000,
45     /// The cell is an object with a finalizer.
46     FINALIZE = 0b0000_0001,
47     /// The cell has no pointers.
48     NO_SCAN  = 0b0000_0010,
49     /// The cell should not be moved (unimplemented).
50     NO_MOVE  = 0b0000_0100,
51     /// All attributes enabled.
52     ALL      = 0b1111_1111,
53 }
54
55 /**
56  * Memory block (cell) header.
57  *
58  * All memory cells in the GC heap has this header.
59  */
60 struct Cell
61 {
62
63     /// Size of the object stored in this memory cell.
64     size_t size = 0;
65
66     /// Real size of the memory cell.
67     size_t capacity = 0;
68
69     /// Mark bit.
70     bool marked = true;
71
72     /// Cell attributes.
73     BlkAttr attr = BlkAttr.NONE;
74
75     /// Next cell (this is used for free/live lists linking).
76     Cell* next = null;
77
78     invariant()
79     {
80         assert (this.size > 0);
81         assert (this.capacity >= this.size);
82     }
83
84     /**
85      * Get a cell pointer for the cell that stores the object pointed by ptr.
86      *
87      * If ptr is null, null is returned.
88      */
89     static Cell* from_ptr(void* ptr)
90     {
91         if (ptr is null)
92             return null;
93         return cast(Cell*) (cast(byte*) ptr - Cell.sizeof);
94     }
95
96     /// Get the base address of the object stored in the cell.
97     void* ptr()
98     {
99         return cast(void*) (cast(byte*) this + Cell.sizeof);
100     }
101
102     /// Return true if the cell should be finalized, false otherwise.
103     bool has_finalizer()
104     {
105         return cast(bool) (this.attr & BlkAttr.FINALIZE);
106     }
107
108     /// Return true if the cell should may have pointers, false otherwise.
109     bool has_pointers()
110     {
111         return !(this.attr & BlkAttr.NO_SCAN);
112     }
113
114     /**
115      * Iterates over the objects pointers.
116      *
117      * Current implementation interprets the whole object as if it were
118      * an array of void*.
119      */
120     int opApply(int delegate(ref void*) dg)
121     {
122         return op_apply_ptr_range(this.ptr, this.ptr + this.size, dg);
123     }
124
125 }
126
127 debug (UnitTest)
128 {
129
130 private:
131
132     import tango.stdc.stdlib: malloc;
133
134     unittest // op_apply_ptr_range()
135     {
136         size_t[10] v;
137         int i = 5;
138         foreach (ref x; v)
139             x = i++;
140         i = 5;
141         int r = op_apply_ptr_range(v.ptr, v.ptr + 10,
142                 (ref void* ptr) {
143                     assert (cast (size_t) ptr == i++);
144                     return 0;
145                 });
146     }
147
148     unittest // Cell
149     {
150         auto N = 10;
151         auto size = N * size_t.sizeof;
152         auto cell = cast(Cell*) malloc(size + Cell.sizeof);
153         assert (cell);
154         assert (cell.ptr is cell + 1);
155         cell.size = size;
156         cell.capacity = size;
157         cell.attr = BlkAttr.FINALIZE | BlkAttr.NO_SCAN;
158         cell.marked = true;
159         for (int i = 0; i < N; ++i) {
160             auto ptr = cast(size_t*) cell.ptr + i;
161             *ptr = i + N;
162         }
163         size_t i = N;
164         foreach (void* ptr; *cell) {
165             assert (cast(size_t) ptr == i++);
166         }
167         assert (*(cast(size_t*) cell.ptr) == N);
168         assert (cell.has_finalizer());
169         assert (!cell.has_pointers());
170         assert (cell is Cell.from_ptr(cell.ptr));
171     }
172
173 } // debug (UnitTest)
174
175 // vim: set et sw=4 sts=4 :