1 /* Copyright (C) 2012,2016 Matthew Fluet.
2 * Copyright (C) 1999-2008 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.
11 bool isPointerInToSpace (GC_state s
, pointer p
) {
12 return (not (isPointer (p
))
13 or (s
->forwardState
.toStart
<= p
and p
< s
->forwardState
.toLimit
));
16 bool isObjptrInToSpace (GC_state s
, objptr op
) {
19 if (not (isObjptr (op
)))
21 p
= objptrToPointer (op
, s
->forwardState
.toStart
);
22 return isPointerInToSpace (s
, p
);
28 * Returns a pointer to the forwarding pointer for the object pointed to by p.
30 objptr
* getFwdPtrp (pointer p
) {
31 return (objptr
*)(getHeaderp(p
));
36 * Returns the forwarding pointer for the object pointed to by p.
38 objptr
getFwdPtr (pointer p
) {
39 return *(getFwdPtrp(p
));
44 * Returns true if the object pointed to by p has a valid forwarding pointer.
46 bool hasFwdPtr (pointer p
) {
47 return (not (GC_VALID_HEADER_MASK
& getHeader(p
)));
51 * Forwards the object pointed to by *opp and updates *opp to point to
54 void forwardObjptr (GC_state s
, objptr
*opp
) {
59 p
= objptrToPointer (op
, s
->heap
.start
);
62 "forwardObjptr opp = "FMTPTR
" op = "FMTOBJPTR
" p = "FMTPTR
"\n",
63 (uintptr_t)opp
, op
, (uintptr_t)p
);
64 assert (isObjptrInFromSpace (s
, *opp
));
65 if (DEBUG_DETAILED
and hasFwdPtr(p
))
66 fprintf (stderr
, " already FORWARDED\n");
67 if (not (hasFwdPtr(p
))) { /* forward the object */
70 size_t metaDataBytes
, objectBytes
;
72 uint16_t bytesNonObjptrs
, numObjptrs
;
74 splitHeader(s
, getHeader(p
), &tag
, NULL
, &bytesNonObjptrs
, &numObjptrs
);
76 /* Compute the space taken by the header and object body. */
77 if ((NORMAL_TAG
== tag
) or (WEAK_TAG
== tag
)) { /* Fixed size object. */
78 metaDataBytes
= GC_NORMAL_METADATA_SIZE
;
79 objectBytes
= bytesNonObjptrs
+ (numObjptrs
* OBJPTR_SIZE
);
81 } else if (ARRAY_TAG
== tag
) {
82 metaDataBytes
= GC_ARRAY_METADATA_SIZE
;
83 objectBytes
= sizeofArrayNoMetaData (s
, getArrayLength (p
),
84 bytesNonObjptrs
, numObjptrs
);
91 assert (STACK_TAG
== tag
);
92 metaDataBytes
= GC_STACK_METADATA_SIZE
;
94 current
= getStackCurrent(s
) == stack
;
96 reservedNew
= sizeofStackShrinkReserved (s
, stack
, current
);
97 if (reservedNew
< stack
->reserved
) {
98 if (DEBUG_STACKS
or s
->controls
.messages
)
100 "[GC: Shrinking stack of size %s bytes to size %s bytes, using %s bytes.]\n",
101 uintmaxToCommaString(stack
->reserved
),
102 uintmaxToCommaString(reservedNew
),
103 uintmaxToCommaString(stack
->used
));
104 stack
->reserved
= reservedNew
;
106 objectBytes
= sizeof (struct GC_stack
) + stack
->used
;
107 skip
= stack
->reserved
- stack
->used
;
109 size
= metaDataBytes
+ objectBytes
;
110 assert (s
->forwardState
.back
+ size
+ skip
<= s
->forwardState
.toLimit
);
111 /* Copy the object. */
112 GC_memcpy (p
- metaDataBytes
, s
->forwardState
.back
, size
);
113 /* If the object has a valid weak pointer, link it into the weaks
114 * for update after the copying GC is done.
116 if ((WEAK_TAG
== tag
) and (numObjptrs
== 1)) {
119 w
= (GC_weak
)(s
->forwardState
.back
+ GC_NORMAL_METADATA_SIZE
+ offsetofWeak (s
));
121 fprintf (stderr
, "forwarding weak "FMTPTR
" ",
123 if (isObjptr (w
->objptr
)
124 and (not s
->forwardState
.amInMinorGC
125 or isObjptrInNursery (s
, w
->objptr
))) {
127 fprintf (stderr
, "linking\n");
132 fprintf (stderr
, "not linking\n");
135 /* Store the forwarding pointer in the old object header. */
136 *(getFwdPtrp(p
)) = pointerToObjptr (s
->forwardState
.back
+ metaDataBytes
,
137 s
->forwardState
.toStart
);
138 assert (hasFwdPtr(p
));
139 /* Update the back of the queue. */
140 s
->forwardState
.back
+= size
+ skip
;
141 assert (isAligned ((size_t)s
->forwardState
.back
+ GC_NORMAL_METADATA_SIZE
,
147 "forwardObjptr --> *opp = "FMTPTR
"\n",
149 assert (isObjptrInToSpace (s
, *opp
));
152 void forwardObjptrIfInNursery (GC_state s
, objptr
*opp
) {
157 p
= objptrToPointer (op
, s
->heap
.start
);
158 if (p
< s
->heap
.nursery
)
160 if (DEBUG_GENERATIONAL
)
162 "forwardObjptrIfInNursery opp = "FMTPTR
" op = "FMTOBJPTR
" p = "FMTPTR
"\n",
163 (uintptr_t)opp
, op
, (uintptr_t)p
);
164 assert (s
->heap
.nursery
<= p
and p
< s
->limitPlusSlop
);
165 forwardObjptr (s
, opp
);
168 /* Walk through all the cards and forward all intergenerational pointers. */
169 void forwardInterGenerationalObjptrs (GC_state s
) {
170 GC_cardMapElem
*cardMap
;
171 GC_crossMapElem
*crossMap
;
172 pointer oldGenStart
, oldGenEnd
;
174 size_t cardIndex
, maxCardIndex
;
175 pointer cardStart
, cardEnd
;
178 if (DEBUG_GENERATIONAL
)
179 fprintf (stderr
, "Forwarding inter-generational pointers.\n");
182 cardMap
= s
->generationalMaps
.cardMap
;
183 crossMap
= s
->generationalMaps
.crossMap
;
184 maxCardIndex
= sizeToCardMapIndex (align (s
->heap
.oldGenSize
, CARD_SIZE
));
185 oldGenStart
= s
->heap
.start
;
186 oldGenEnd
= oldGenStart
+ s
->heap
.oldGenSize
;
188 objectStart
= alignFrontier (s
, s
->heap
.start
);
190 cardStart
= oldGenStart
;
192 assert (cardIndex
<= maxCardIndex
);
193 assert (isFrontierAligned (s
, objectStart
));
194 if (cardIndex
== maxCardIndex
)
197 if (DEBUG_GENERATIONAL
)
198 fprintf (stderr
, "checking card %"PRIuMAX
" objectStart = "FMTPTR
"\n",
199 (uintmax_t)cardIndex
, (uintptr_t)objectStart
);
200 assert (objectStart
< oldGenStart
+ cardMapIndexToSize (cardIndex
+ 1));
201 if (cardMap
[cardIndex
]) {
204 s
->cumulativeStatistics
.numCardsMarked
++;
205 if (DEBUG_GENERATIONAL
)
206 fprintf (stderr
, "card %"PRIuMAX
" is marked objectStart = "FMTPTR
"\n",
207 (uintmax_t)cardIndex
, (uintptr_t)objectStart
);
208 assert (isFrontierAligned (s
, objectStart
));
209 cardEnd
= cardStart
+ CARD_SIZE
;
210 if (oldGenEnd
< cardEnd
)
212 assert (objectStart
< cardEnd
);
213 lastObject
= objectStart
;
214 /* If we ever add Weak.set, then there could be intergenerational
215 * weak pointers, in which case we would need to link the weak
216 * objects into s->weaks. But for now, since there is no
217 * Weak.set, the foreachObjptrInRange will do the right thing on
218 * weaks, since the weak pointer will never be into the nursery.
220 objectStart
= foreachObjptrInRange (s
, objectStart
, &cardEnd
,
221 forwardObjptrIfInNursery
, FALSE
);
222 s
->cumulativeStatistics
.bytesScannedMinor
+= (uintmax_t)(objectStart
- lastObject
);
223 if (objectStart
== oldGenEnd
)
225 cardIndex
= sizeToCardMapIndex ((size_t)(objectStart
- oldGenStart
));
226 cardStart
= oldGenStart
+ cardMapIndexToSize (cardIndex
);
229 unless (CROSS_MAP_EMPTY
== crossMap
[cardIndex
])
230 objectStart
= cardStart
+ (size_t)(crossMap
[cardIndex
] * CROSS_MAP_OFFSET_SCALE
);
231 if (DEBUG_GENERATIONAL
)
233 "card %"PRIuMAX
" is not marked"
234 " crossMap[%"PRIuMAX
"] == %"PRIuMAX
""
235 " objectStart = "FMTPTR
"\n",
236 (uintmax_t)cardIndex
, (uintmax_t)cardIndex
,
237 (uintmax_t)(crossMap
[cardIndex
] * CROSS_MAP_OFFSET_SCALE
),
238 (uintptr_t)objectStart
);
240 cardStart
+= CARD_SIZE
;
245 if (DEBUG_GENERATIONAL
)
246 fprintf (stderr
, "Forwarding inter-generational pointers done.\n");