]> git.llucax.com Git - software/dgc/naive.git/blob - gc/cell.d
bdd923464939735ce888b34bb0255bb261f7d922
[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 have 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 to by
86      * ptr.
87      *
88      * If ptr is null, null is returned.
89      */
90     static Cell* from_ptr(void* ptr)
91     {
92         if (ptr is null)
93             return null;
94         return cast(Cell*) (cast(byte*) ptr - Cell.sizeof);
95     }
96
97     /// Get the base address of the object stored in the cell.
98     void* ptr()
99     {
100         return cast(void*) (cast(byte*) this + Cell.sizeof);
101     }
102
103     /// Return true if the cell should be finalized, false otherwise.
104     bool has_finalizer()
105     {
106         return cast(bool) (this.attr & BlkAttr.FINALIZE);
107     }
108
109     /// Return true if the cell should may have pointers, false otherwise.
110     bool has_pointers()
111     {
112         return !(this.attr & BlkAttr.NO_SCAN);
113     }
114
115     /**
116      * Iterates over the objects pointers.
117      *
118      * Current implementation interprets the whole object as if it were
119      * an array of void*.
120      */
121     int opApply(int delegate(ref void*) dg)
122     {
123         return op_apply_ptr_range(this.ptr, this.ptr + this.size, dg);
124     }
125
126 }
127
128 debug (UnitTest)
129 {
130
131 private:
132
133     import tango.stdc.stdlib: malloc;
134
135     unittest // op_apply_ptr_range()
136     {
137         size_t[10] v;
138         int i = 5;
139         foreach (ref x; v)
140             x = i++;
141         i = 5;
142         int r = op_apply_ptr_range(v.ptr, v.ptr + 10,
143                 (ref void* ptr) {
144                     assert (cast (size_t) ptr == i++);
145                     return 0;
146                 });
147     }
148
149     unittest // Cell
150     {
151         auto N = 10;
152         auto size = N * size_t.sizeof;
153         auto cell = cast(Cell*) malloc(size + Cell.sizeof);
154         assert (cell);
155         assert (cell.ptr is cell + 1);
156         cell.size = size;
157         cell.capacity = size;
158         cell.attr = BlkAttr.FINALIZE | BlkAttr.NO_SCAN;
159         cell.marked = true;
160         for (int i = 0; i < N; ++i) {
161             auto ptr = cast(size_t*) cell.ptr + i;
162             *ptr = i + N;
163         }
164         size_t i = N;
165         foreach (void* ptr; *cell) {
166             assert (cast(size_t) ptr == i++);
167         }
168         assert (*(cast(size_t*) cell.ptr) == N);
169         assert (cell.has_finalizer());
170         assert (!cell.has_pointers());
171         assert (cell is Cell.from_ptr(cell.ptr));
172     }
173
174 } // debug (UnitTest)
175
176 // vim: set et sw=4 sts=4 :