Backport from sid to buster
[hcoop/debian/mlton.git] / runtime / gc / foreach.c
CommitLineData
7f918cf1
CE
1/* Copyright (C) 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.
5 *
6 * MLton is released under a BSD-style license.
7 * See the file MLton-LICENSE for details.
8 */
9
10void callIfIsObjptr (GC_state s, GC_foreachObjptrFun f, objptr *opp) {
11 if (isObjptr (*opp))
12 f (s, opp);
13}
14
15/* foreachGlobalObjptr (s, f)
16 *
17 * Apply f to each global object pointer into the heap.
18 */
19void foreachGlobalObjptr (GC_state s, GC_foreachObjptrFun f) {
20 for (unsigned int i = 0; i < s->globalsLength; ++i) {
21 if (DEBUG_DETAILED)
22 fprintf (stderr, "foreachGlobal %u\n", i);
23 callIfIsObjptr (s, f, &s->globals [i]);
24 }
25 if (DEBUG_DETAILED)
26 fprintf (stderr, "foreachGlobal threads\n");
27 callIfIsObjptr (s, f, &s->callFromCHandlerThread);
28 callIfIsObjptr (s, f, &s->currentThread);
29 callIfIsObjptr (s, f, &s->savedThread);
30 callIfIsObjptr (s, f, &s->signalHandlerThread);
31}
32
33
34/* foreachObjptrInObject (s, p, f, skipWeaks)
35 *
36 * Applies f to each object pointer in the object pointed to by p.
37 * Returns pointer to the end of object, i.e. just past object.
38 *
39 * If skipWeaks, then the object pointer in weak objects is skipped.
40 */
41pointer foreachObjptrInObject (GC_state s, pointer p,
42 GC_foreachObjptrFun f, bool skipWeaks) {
43 GC_header header;
44 uint16_t bytesNonObjptrs;
45 uint16_t numObjptrs;
46 GC_objectTypeTag tag;
47
48 header = getHeader (p);
49 splitHeader(s, header, &tag, NULL, &bytesNonObjptrs, &numObjptrs);
50 if (DEBUG_DETAILED)
51 fprintf (stderr,
52 "foreachObjptrInObject ("FMTPTR")"
53 " header = "FMTHDR
54 " tag = %s"
55 " bytesNonObjptrs = %d"
56 " numObjptrs = %d\n",
57 (uintptr_t)p, header, objectTypeTagToString (tag),
58 bytesNonObjptrs, numObjptrs);
59 if (NORMAL_TAG == tag) {
60 p += bytesNonObjptrs;
61 pointer max = p + (numObjptrs * OBJPTR_SIZE);
62 /* Apply f to all internal pointers. */
63 for ( ; p < max; p += OBJPTR_SIZE) {
64 if (DEBUG_DETAILED)
65 fprintf (stderr,
66 " p = "FMTPTR" *p = "FMTOBJPTR"\n",
67 (uintptr_t)p, *(objptr*)p);
68 callIfIsObjptr (s, f, (objptr*)p);
69 }
70 } else if (WEAK_TAG == tag) {
71 p += bytesNonObjptrs;
72 if (1 == numObjptrs) {
73 if (not skipWeaks)
74 callIfIsObjptr (s, f, (objptr*)p);
75 p += OBJPTR_SIZE;
76 }
77 } else if (ARRAY_TAG == tag) {
78 size_t bytesPerElement;
79 size_t dataBytes;
80 pointer last;
81 GC_arrayLength numElements;
82
83 numElements = getArrayLength (p);
84 bytesPerElement = bytesNonObjptrs + (numObjptrs * OBJPTR_SIZE);
85 dataBytes = numElements * bytesPerElement;
86 if (0 == numObjptrs) {
87 /* No objptrs to process. */
88 ;
89 } else {
90 last = p + dataBytes;
91 if (0 == bytesNonObjptrs)
92 /* Array with only pointers. */
93 for ( ; p < last; p += OBJPTR_SIZE)
94 callIfIsObjptr (s, f, (objptr*)p);
95 else {
96 /* Array with a mix of pointers and non-pointers. */
97 size_t bytesObjptrs;
98
99 bytesObjptrs = numObjptrs * OBJPTR_SIZE;
100
101 /* For each array element. */
102 for ( ; p < last; ) {
103 pointer next;
104
105 /* Skip the non-pointers. */
106 p += bytesNonObjptrs;
107 next = p + bytesObjptrs;
108 /* For each internal pointer. */
109 for ( ; p < next; p += OBJPTR_SIZE)
110 callIfIsObjptr (s, f, (objptr*)p);
111 }
112 }
113 assert (p == last);
114 p -= dataBytes;
115 }
116 p += alignWithExtra (s, dataBytes, GC_ARRAY_METADATA_SIZE);
117 } else { /* stack */
118 GC_stack stack;
119 pointer top, bottom;
120 unsigned int i;
121 GC_returnAddress returnAddress;
122 GC_frameLayout frameLayout;
123 GC_frameOffsets frameOffsets;
124
125 assert (STACK_TAG == tag);
126 stack = (GC_stack)p;
127 bottom = getStackBottom (s, stack);
128 top = getStackTop (s, stack);
129 if (DEBUG) {
130 fprintf (stderr, " bottom = "FMTPTR" top = "FMTPTR"\n",
131 (uintptr_t)bottom, (uintptr_t)top);
132 }
133 assert (stack->used <= stack->reserved);
134 while (top > bottom) {
135 /* Invariant: top points just past a "return address". */
136 returnAddress = *((GC_returnAddress*)(top - GC_RETURNADDRESS_SIZE));
137 if (DEBUG) {
138 fprintf (stderr, " top = "FMTPTR" return address = "FMTRA"\n",
139 (uintptr_t)top, returnAddress);
140 }
141 frameLayout = getFrameLayoutFromReturnAddress (s, returnAddress);
142 frameOffsets = frameLayout->offsets;
143 top -= frameLayout->size;
144 for (i = 0 ; i < frameOffsets[0] ; ++i) {
145 if (DEBUG)
146 fprintf(stderr, " offset %"PRIx16" address "FMTOBJPTR"\n",
147 frameOffsets[i + 1], *(objptr*)(top + frameOffsets[i + 1]));
148 callIfIsObjptr (s, f, (objptr*)(top + frameOffsets[i + 1]));
149 }
150 }
151 assert(top == bottom);
152 p += sizeof (struct GC_stack) + stack->reserved;
153 }
154 return p;
155}
156
157/* foreachObjptrInRange (s, front, back, f, skipWeaks)
158 *
159 * Apply f to each pointer between front and *back, which should be a
160 * contiguous sequence of objects, where front points at the beginning
161 * of the first object and *back points just past the end of the last
162 * object. f may increase *back (for example, this is done by
163 * forward). foreachObjptrInRange returns a pointer to the end of
164 * the last object it visits.
165 *
166 * If skipWeaks, then the object pointer in weak objects is skipped.
167 */
168
169pointer foreachObjptrInRange (GC_state s, pointer front, pointer *back,
170 GC_foreachObjptrFun f, bool skipWeaks) {
171 pointer b;
172
173 assert (isFrontierAligned (s, front));
174 if (DEBUG_DETAILED)
175 fprintf (stderr,
176 "foreachObjptrInRange front = "FMTPTR" *back = "FMTPTR"\n",
177 (uintptr_t)front, (uintptr_t)(*back));
178 b = *back;
179 assert (front <= b);
180 while (front < b) {
181 while (front < b) {
182 assert (isAligned ((size_t)front, GC_MODEL_MINALIGN));
183 if (DEBUG_DETAILED)
184 fprintf (stderr,
185 " front = "FMTPTR" *back = "FMTPTR"\n",
186 (uintptr_t)front, (uintptr_t)(*back));
187 pointer p = advanceToObjectData (s, front);
188 assert (isAligned ((size_t)p, s->alignment));
189 front = foreachObjptrInObject (s, p, f, skipWeaks);
190 }
191 b = *back;
192 }
193 return front;
194}
195
196
197/* Apply f to the frame index of each frame in the current thread's stack. */
198void foreachStackFrame (GC_state s, GC_foreachStackFrameFun f) {
199 pointer bottom;
200 GC_frameIndex findex;
201 GC_frameLayout layout;
202 GC_returnAddress returnAddress;
203 pointer top;
204
205 if (DEBUG_PROFILE)
206 fprintf (stderr, "foreachStackFrame\n");
207 bottom = getStackBottom (s, getStackCurrent(s));
208 if (DEBUG_PROFILE)
209 fprintf (stderr, " bottom = "FMTPTR" top = "FMTPTR".\n",
210 (uintptr_t)bottom, (uintptr_t)s->stackTop);
211 for (top = s->stackTop; top > bottom; top -= layout->size) {
212 returnAddress = *((GC_returnAddress*)(top - GC_RETURNADDRESS_SIZE));
213 findex = getFrameIndexFromReturnAddress (s, returnAddress);
214 if (DEBUG_PROFILE)
215 fprintf (stderr, "top = "FMTPTR" findex = "FMTFI"\n",
216 (uintptr_t)top, findex);
217 unless (findex < s->frameLayoutsLength)
218 die ("top = "FMTPTR" returnAddress = "FMTRA" findex = "FMTFI"\n",
219 (uintptr_t)top, (uintptr_t)returnAddress, findex);
220 f (s, findex);
221 layout = &(s->frameLayouts[findex]);
222 assert (layout->size > 0);
223 }
224 if (DEBUG_PROFILE)
225 fprintf (stderr, "done foreachStackFrame\n");
226}