Commit | Line | Data |
---|---|---|
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 | ||
10 | void 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 | */ | |
19 | void 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 | */ | |
41 | pointer 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 | ||
169 | pointer 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. */ | |
198 | void 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 | } |