1 /* Copyright (C) 2012,2016 Matthew Fluet.
2 * Copyright (C) 1999-2007 Henry Cejtin, Matthew Fluet, Suresh
3 * Jagannathan, and Stephen Weeks.
4 * Copyright (C) 1997-2000 NEC Research Institute.
6 * MLton is released under a BSD-style license.
7 * See the file MLton-LICENSE for details.
10 /* ---------------------------------------------------------------- */
11 /* Depth-first Marking */
12 /* ---------------------------------------------------------------- */
14 bool isPointerMarked (pointer p
) {
15 return MARK_MASK
& getHeader (p
);
18 bool isPointerMarkedByMode (pointer p
, GC_markMode m
) {
21 return isPointerMarked (p
);
23 return not isPointerMarked (p
);
25 die ("bad mark mode %u", m
);
29 /* dfsMarkByMode (s, r, m, shc, slw)
31 * Sets all the mark bits in the object graph pointed to by r.
33 * If m is MARK_MODE, it sets the bits to 1.
34 * If m is UNMARK_MODE, it sets the bits to 0.
36 * If shc, it hash-conses the objects marked.
38 * If slw, it links the weak objects marked.
40 * It returns the total size in bytes of the objects marked.
42 size_t dfsMarkByMode (GC_state s
, pointer root
,
45 bool shouldLinkWeaks
) {
46 GC_header mark
; /* Used to set or clear the mark bit. */
47 size_t size
; /* Total number of bytes marked. */
48 pointer cur
; /* The current object being marked. */
49 pointer prev
; /* The previous object on the mark stack. */
50 pointer next
; /* The next object to mark. */
51 pointer todo
; /* A pointer to the pointer in cur to next. */
54 uint16_t bytesNonObjptrs
;
57 uint32_t objptrIndex
; /* The i'th pointer in the object (element) being marked. */
59 GC_header
* nextHeaderp
;
60 GC_arrayCounter arrayIndex
;
61 pointer top
; /* The top of the next stack frame to mark. */
62 GC_returnAddress returnAddress
;
63 GC_frameLayout frameLayout
;
64 GC_frameOffsets frameOffsets
;
66 if (isPointerMarkedByMode (root
, mode
))
67 /* Object has already been marked. */
69 mark
= (MARK_MODE
== mode
) ? MARK_MASK
: 0;
73 headerp
= getHeaderp (cur
);
77 /* cur is the object that was being marked.
78 * prev is the mark stack.
79 * next is the unmarked object to be marked.
80 * nextHeaderp points to the header of next.
81 * nextHeader is the header of next.
82 * todo is a pointer to the pointer inside cur that points to next.
87 " cur = "FMTPTR
" next = "FMTPTR
88 " prev = "FMTPTR
" todo = "FMTPTR
"\n",
89 (uintptr_t)cur
, (uintptr_t)next
,
90 (uintptr_t)prev
, (uintptr_t)todo
);
91 assert (not isPointerMarkedByMode (next
, mode
));
92 assert (nextHeaderp
== getHeaderp (next
));
93 assert (nextHeader
== getHeader (next
));
94 // assert (*(pointer*) todo == next);
95 assert (fetchObjptrToPointer (todo
, s
->heap
.start
) == next
);
96 headerp
= nextHeaderp
;
98 // *(pointer*)todo = prev;
99 storeObjptrFromPointer (todo
, prev
, s
->heap
.start
);
104 fprintf (stderr
, "mark cur = "FMTPTR
" prev = "FMTPTR
" mode = %s\n",
105 (uintptr_t)cur
, (uintptr_t)prev
,
106 (mode
== MARK_MODE
) ? "mark" : "unmark");
107 /* cur is the object to mark.
108 * prev is the mark stack.
109 * headerp points to the header of cur.
110 * header is the header of cur.
112 assert (not isPointerMarkedByMode (cur
, mode
));
113 assert (header
== getHeader (cur
));
114 assert (headerp
== getHeaderp (cur
));
116 /* Store the mark. In the case of an object that contains a pointer to
117 * itself, it is essential that we store the marked header before marking
118 * the internal pointers (markInNormal below). If we didn't, then we
119 * would see the object as unmarked and traverse it again.
122 splitHeader (s
, header
, &tag
, NULL
, &bytesNonObjptrs
, &numObjptrs
);
123 if (NORMAL_TAG
== tag
) {
125 GC_NORMAL_METADATA_SIZE
127 + (numObjptrs
* OBJPTR_SIZE
);
128 if (0 == numObjptrs
) {
129 /* There is nothing to mark. */
132 cur
= hashConsPointer (s
, cur
, TRUE
);
135 todo
= cur
+ bytesNonObjptrs
;
139 fprintf (stderr
, "markInNormal objptrIndex = %"PRIu32
"\n", objptrIndex
);
140 assert (objptrIndex
< numObjptrs
);
141 // next = *(pointer*)todo;
142 next
= fetchObjptrToPointer (todo
, s
->heap
.start
);
143 if (not isPointer (next
)) {
145 assert (objptrIndex
< numObjptrs
);
147 if (objptrIndex
== numObjptrs
) {
148 /* Done. Clear out the counters and return. */
149 *headerp
= header
& ~COUNTER_MASK
;
155 nextHeaderp
= getHeaderp (next
);
156 nextHeader
= *nextHeaderp
;
157 if (mark
== (nextHeader
& MARK_MASK
)) {
159 shareObjptr (s
, (objptr
*)todo
);
160 goto markNextInNormal
;
162 *headerp
= (header
& ~COUNTER_MASK
) | (objptrIndex
<< COUNTER_SHIFT
);
164 } else if (WEAK_TAG
== tag
) {
165 /* Store the marked header and don't follow any pointers. */
166 if (shouldLinkWeaks
) {
169 w
= (GC_weak
)(cur
+ offsetofWeak (s
));
171 fprintf (stderr
, "marking weak "FMTPTR
" ",
173 if (isObjptr (w
->objptr
)) {
175 fprintf (stderr
, "linking\n");
180 fprintf (stderr
, "not linking\n");
184 } else if (ARRAY_TAG
== tag
) {
185 /* When marking arrays:
186 * arrayIndex is the index of the element to mark.
187 * cur is the pointer to the array.
188 * objptrIndex is the index of the pointer within the element
189 * (i.e. the i'th pointer is at index i).
190 * todo is the start of the element.
193 GC_ARRAY_METADATA_SIZE
194 + sizeofArrayNoMetaData (s
, getArrayLength (cur
), bytesNonObjptrs
, numObjptrs
);
195 if (0 == numObjptrs
or 0 == getArrayLength (cur
)) {
196 /* There is nothing to mark. */
199 cur
= hashConsPointer (s
, cur
, TRUE
);
202 /* Begin marking first element. */
206 assert (arrayIndex
< getArrayLength (cur
));
208 /* Skip to the first pointer. */
209 todo
+= bytesNonObjptrs
;
212 fprintf (stderr
, "markInArray arrayIndex = %"PRIxARRCTR
" objptrIndex = %"PRIu32
"\n",
213 arrayIndex
, objptrIndex
);
214 assert (arrayIndex
< getArrayLength (cur
));
215 assert (objptrIndex
< numObjptrs
);
216 assert (todo
== indexArrayAtObjptrIndex (s
, cur
, arrayIndex
, objptrIndex
));
217 // next = *(pointer*)todo;
218 next
= fetchObjptrToPointer (todo
, s
->heap
.start
);
219 if (not (isPointer(next
))) {
221 assert (arrayIndex
< getArrayLength (cur
));
222 assert (objptrIndex
< numObjptrs
);
223 assert (todo
== indexArrayAtObjptrIndex (s
, cur
, arrayIndex
, objptrIndex
));
226 if (objptrIndex
< numObjptrs
)
229 if (arrayIndex
< getArrayLength (cur
))
231 /* Done. Clear out the counters and return. */
232 *getArrayCounterp (cur
) = 0;
233 *headerp
= header
& ~COUNTER_MASK
;
236 nextHeaderp
= getHeaderp (next
);
237 nextHeader
= *nextHeaderp
;
238 if (mark
== (nextHeader
& MARK_MASK
)) {
240 shareObjptr (s
, (objptr
*)todo
);
241 goto markNextInArray
;
243 /* Recur and mark next. */
244 *getArrayCounterp (cur
) = arrayIndex
;
245 *headerp
= (header
& ~COUNTER_MASK
) | (objptrIndex
<< COUNTER_SHIFT
);
248 assert (STACK_TAG
== tag
);
250 GC_STACK_METADATA_SIZE
251 + sizeof (struct GC_stack
) + ((GC_stack
)cur
)->reserved
;
252 top
= getStackTop (s
, (GC_stack
)cur
);
253 assert (((GC_stack
)cur
)->used
<= ((GC_stack
)cur
)->reserved
);
255 /* Invariant: top points just past the return address of the frame
258 assert (getStackBottom (s
, (GC_stack
)cur
) <= top
);
260 fprintf (stderr
, "markInStack top = %"PRIuMAX
"\n",
261 (uintmax_t)(top
- getStackBottom (s
, (GC_stack
)cur
)));
262 if (top
== getStackBottom (s
, (GC_stack
)(cur
)))
265 returnAddress
= *(GC_returnAddress
*) (top
- GC_RETURNADDRESS_SIZE
);
266 frameLayout
= getFrameLayoutFromReturnAddress (s
, returnAddress
);
267 frameOffsets
= frameLayout
->offsets
;
268 ((GC_stack
)cur
)->markTop
= top
;
270 if (objptrIndex
== frameOffsets
[0]) {
271 top
-= frameLayout
->size
;
274 todo
= top
- frameLayout
->size
+ frameOffsets
[objptrIndex
+ 1];
275 // next = *(pointer*)todo;
276 next
= fetchObjptrToPointer (todo
, s
->heap
.start
);
279 " offset %u todo "FMTPTR
" next = "FMTPTR
"\n",
280 frameOffsets
[objptrIndex
+ 1],
281 (uintptr_t)todo
, (uintptr_t)next
);
282 if (not isPointer (next
)) {
286 nextHeaderp
= getHeaderp (next
);
287 nextHeader
= *nextHeaderp
;
288 if (mark
== (nextHeader
& MARK_MASK
)) {
291 shareObjptr (s
, (objptr
*)todo
);
294 ((GC_stack
)cur
)->markIndex
= objptrIndex
;
299 /* Done marking cur, continue with prev.
300 * Need to set the pointer in the prev object that pointed to cur
301 * to point back to prev, and restore prev.
304 fprintf (stderr
, "return cur = "FMTPTR
" prev = "FMTPTR
"\n",
305 (uintptr_t)cur
, (uintptr_t)prev
);
306 assert (isPointerMarkedByMode (cur
, mode
));
311 headerp
= getHeaderp (cur
);
313 splitHeader (s
, header
, &tag
, NULL
, &bytesNonObjptrs
, &numObjptrs
);
314 /* It's impossible to get a WEAK_TAG here, since we would never
315 * follow the weak object pointer.
317 assert (WEAK_TAG
!= tag
);
318 if (NORMAL_TAG
== tag
) {
319 todo
= cur
+ bytesNonObjptrs
;
320 objptrIndex
= (header
& COUNTER_MASK
) >> COUNTER_SHIFT
;
321 todo
+= objptrIndex
* OBJPTR_SIZE
;
322 // prev = *(pointer*)todo;
323 prev
= fetchObjptrToPointer (todo
, s
->heap
.start
);
324 // *(pointer*)todo = next;
325 storeObjptrFromPointer (todo
, next
, s
->heap
.start
);
327 markIntergenerationalPointer (s
, (pointer
*)todo
);
328 goto markNextInNormal
;
329 } else if (ARRAY_TAG
== tag
) {
330 arrayIndex
= getArrayCounter (cur
);
331 todo
= cur
+ arrayIndex
* (bytesNonObjptrs
+ (numObjptrs
* OBJPTR_SIZE
));
332 objptrIndex
= (header
& COUNTER_MASK
) >> COUNTER_SHIFT
;
333 todo
+= bytesNonObjptrs
+ objptrIndex
* OBJPTR_SIZE
;
334 // prev = *(pointer*)todo;
335 prev
= fetchObjptrToPointer (todo
, s
->heap
.start
);
336 // *(pointer*)todo = next;
337 storeObjptrFromPointer (todo
, next
, s
->heap
.start
);
339 markIntergenerationalPointer (s
, (pointer
*)todo
);
340 goto markNextInArray
;
342 assert (STACK_TAG
== tag
);
343 objptrIndex
= ((GC_stack
)cur
)->markIndex
;
344 top
= ((GC_stack
)cur
)->markTop
;
345 /* Invariant: top points just past a "return address". */
346 returnAddress
= *(GC_returnAddress
*) (top
- GC_RETURNADDRESS_SIZE
);
347 frameLayout
= getFrameLayoutFromReturnAddress (s
, returnAddress
);
348 frameOffsets
= frameLayout
->offsets
;
349 todo
= top
- frameLayout
->size
+ frameOffsets
[objptrIndex
+ 1];
350 // prev = *(pointer*)todo;
351 prev
= fetchObjptrToPointer (todo
, s
->heap
.start
);
352 // *(pointer*)todo = next;
353 storeObjptrFromPointer (todo
, next
, s
->heap
.start
);
355 markIntergenerationalPointer (s
, (pointer
*)todo
);
362 void dfsMarkWithHashConsWithLinkWeaks (GC_state s
, objptr
*opp
) {
365 p
= objptrToPointer (*opp
, s
->heap
.start
);
366 dfsMarkByMode (s
, p
, MARK_MODE
, TRUE
, TRUE
);
369 void dfsMarkWithoutHashConsWithLinkWeaks (GC_state s
, objptr
*opp
) {
372 p
= objptrToPointer (*opp
, s
->heap
.start
);
373 dfsMarkByMode (s
, p
, MARK_MODE
, FALSE
, TRUE
);