1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 2004-2018. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 */
20 /*
21 * GC support procedures
22 */
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #define ERL_WANT_GC_INTERNALS__
28
29 #include "global.h"
30
31 #include "erl_gc.h"
32
33 #include "hipe_stack.h"
34 #include "hipe_gc.h"
35
fullsweep_nstack(Process * p,Eterm * n_htop)36 Eterm *fullsweep_nstack(Process *p, Eterm *n_htop)
37 {
38 /* known nstack walk state */
39 Eterm *nsp;
40 Eterm *nsp_end;
41 const struct hipe_sdesc *sdesc;
42 unsigned int sdesc_size;
43 unsigned long ra;
44 unsigned int i;
45 unsigned int mask;
46 /* arch-specific nstack walk state */
47 struct nstack_walk_state walk_state;
48
49 ASSERT(!p->hipe.gc_is_unsafe);
50
51 if (!p->hipe.nstack) {
52 ASSERT(!p->hipe.nsp && !p->hipe.nstend);
53 return n_htop;
54 }
55 if (!nstack_walk_init_check(p))
56 return n_htop;
57
58 ASSERT(p->hipe.nsp && p->hipe.nstend);
59 nsp = nstack_walk_nsp_begin(p);
60 nsp_end = p->hipe.nstgraylim;
61 if (nsp_end)
62 nstack_walk_kill_trap(p, nsp_end);
63 nsp_end = nstack_walk_nsp_end(p);
64
65 sdesc = nstack_walk_init_sdesc(p, &walk_state);
66
67 for (;;) {
68 if (nstack_walk_nsp_reached_end(nsp, nsp_end)) {
69 if (nsp == nsp_end) {
70 if (nsp) {
71 /* see the HIGH_WATER update in fullsweep_heap() */
72 p->hipe.nstblacklim = nsp; /* nsp == nsp_end */
73 nstack_walk_update_trap(p, walk_state.sdesc0);
74 }
75 return n_htop;
76 }
77 fprintf(stderr, "%s: passed end of stack\r\n", __FUNCTION__);
78 break;
79 }
80 sdesc_size = nstack_walk_frame_size(sdesc);
81 i = 0;
82 mask = sdesc->livebits[0];
83 for (;;) {
84 if (mask & 1) {
85 Eterm *nsp_i = nstack_walk_frame_index(nsp, i);
86 Eterm gval = *nsp_i;
87 if (is_boxed(gval)) {
88 Eterm *ptr = boxed_val(gval);
89 Eterm val = *ptr;
90 if (IS_MOVED_BOXED(val)) {
91 ASSERT(is_boxed(val));
92 *nsp_i = val;
93 } else if (!erts_is_literal(gval, ptr)) {
94 move_boxed(ptr, val, &n_htop, nsp_i);
95 }
96 } else if (is_list(gval)) {
97 Eterm *ptr = list_val(gval);
98 Eterm val = *ptr;
99 if (IS_MOVED_CONS(val)) {
100 *nsp_i = ptr[1];
101 } else if (!erts_is_literal(gval, ptr)) {
102 ASSERT(erts_dbg_within_proc(ptr, p, NULL));
103 move_cons(ptr, val, &n_htop, nsp_i);
104 }
105 }
106 }
107 if (++i >= sdesc_size)
108 break;
109 if (i & 31)
110 mask >>= 1;
111 else
112 mask = sdesc->livebits[i >> 5];
113 }
114 ra = nstack_walk_frame_ra(nsp, sdesc);
115 sdesc = hipe_find_sdesc(ra);
116 nsp = nstack_walk_next_frame(nsp, sdesc_size);
117 }
118 abort();
119 }
120
gensweep_nstack(Process * p,Eterm ** ptr_old_htop,Eterm ** ptr_n_htop)121 void gensweep_nstack(Process *p, Eterm **ptr_old_htop, Eterm **ptr_n_htop)
122 {
123 /* known nstack walk state */
124 Eterm *nsp;
125 Eterm *nsp_end;
126 const struct hipe_sdesc *sdesc;
127 unsigned int sdesc_size;
128 unsigned long ra;
129 unsigned int i;
130 unsigned int mask;
131 /* arch-specific nstack walk state */
132 struct nstack_walk_state walk_state;
133 char *oh;
134 Uint oh_size;
135
136 /* gensweep-specific state */
137 Eterm *old_htop, *n_htop;
138 char *mature;
139 Uint mature_size;
140
141 ASSERT(!p->hipe.gc_is_unsafe);
142
143 if (!p->hipe.nstack) {
144 ASSERT(!p->hipe.nsp && !p->hipe.nstend);
145 return;
146 }
147 if (!nstack_walk_init_check(p))
148 return;
149
150 ASSERT(p->hipe.nsp && p->hipe.nstend);
151 nsp = nstack_walk_nsp_begin(p);
152 nsp_end = p->hipe.nstgraylim;
153 if (nsp_end) {
154 /* if gray limit passed black limit, reset black limit */
155 if (nstack_walk_gray_passed_black(nsp_end, p->hipe.nstblacklim))
156 p->hipe.nstblacklim = nsp_end;
157 nstack_walk_kill_trap(p, nsp_end);
158 nsp_end = p->hipe.nstblacklim;
159 } else
160 nsp_end = nstack_walk_nsp_end(p);
161
162 sdesc = nstack_walk_init_sdesc(p, &walk_state);
163
164 old_htop = *ptr_old_htop;
165 n_htop = *ptr_n_htop;
166 mature = (char *) (p->abandoned_heap ? p->abandoned_heap : p->heap);
167 mature_size = (char*)HIGH_WATER(p) - mature;
168 oh = (char*)OLD_HEAP(p);
169 oh_size = (char*)OLD_HTOP(p) - oh;
170
171 for (;;) {
172 if (nstack_walk_nsp_reached_end(nsp, nsp_end)) {
173 if (nsp == nsp_end) {
174 *ptr_old_htop = old_htop;
175 *ptr_n_htop = n_htop;
176 if (nsp) {
177 /* see the HIGH_WATER update in gen_gc() */
178 if (HEAP_START(p) != HIGH_WATER(p)) {
179 p->hipe.nstblacklim =
180 p->hipe.nstgraylim
181 ? p->hipe.nstgraylim
182 : nsp; /* nsp == nsp_end */
183 } else {
184 /* blacklim = graylim ? blacklim : end */
185 if (!p->hipe.nstgraylim)
186 p->hipe.nstblacklim = nsp; /* nsp == nsp_end */
187 }
188 nstack_walk_update_trap(p, walk_state.sdesc0);
189 }
190 return;
191 }
192 fprintf(stderr, "%s: passed end of stack\r\n", __FUNCTION__);
193 break;
194 }
195 sdesc_size = nstack_walk_frame_size(sdesc);
196 i = 0;
197 mask = sdesc->livebits[0];
198 for (;;) {
199 if (mask & 1) {
200 Eterm *nsp_i = nstack_walk_frame_index(nsp, i);
201 Eterm gval = *nsp_i;
202 if (is_boxed(gval)) {
203 Eterm *ptr = boxed_val(gval);
204 Eterm val = *ptr;
205 if (IS_MOVED_BOXED(val)) {
206 ASSERT(is_boxed(val));
207 *nsp_i = val;
208 } else if (ErtsInArea(ptr, mature, mature_size)) {
209 move_boxed(ptr, val, &old_htop, nsp_i);
210 } else if (ErtsInYoungGen(gval, ptr, oh, oh_size)) {
211 ASSERT(erts_dbg_within_proc(ptr, p, NULL));
212 move_boxed(ptr, val, &n_htop, nsp_i);
213 }
214 } else if (is_list(gval)) {
215 Eterm *ptr = list_val(gval);
216 Eterm val = *ptr;
217 if (IS_MOVED_CONS(val)) {
218 *nsp_i = ptr[1];
219 } else if (ErtsInArea(ptr, mature, mature_size)) {
220 move_cons(ptr, val, &old_htop, nsp_i);
221 } else if (ErtsInYoungGen(gval, ptr, oh, oh_size)) {
222 ASSERT(erts_dbg_within_proc(ptr, p, NULL));
223 move_cons(ptr, val, &n_htop, nsp_i);
224 }
225 }
226 }
227 if (++i >= sdesc_size)
228 break;
229 if (i & 31)
230 mask >>= 1;
231 else
232 mask = sdesc->livebits[i >> 5];
233 }
234 ra = nstack_walk_frame_ra(nsp, sdesc);
235 sdesc = hipe_find_sdesc(ra);
236 nsp = nstack_walk_next_frame(nsp, sdesc_size);
237 }
238 abort();
239 }
240
sweep_literals_nstack(Process * p,Eterm * old_htop,char * area,Uint area_size)241 Eterm *sweep_literals_nstack(Process *p, Eterm *old_htop, char *area,
242 Uint area_size)
243 {
244 /* known nstack walk state */
245 Eterm *nsp;
246 Eterm *nsp_end;
247 const struct hipe_sdesc *sdesc;
248 /* arch-specific nstack walk state */
249 struct nstack_walk_state walk_state;
250
251 ASSERT(!p->hipe.gc_is_unsafe);
252
253 if (!p->hipe.nstack) {
254 ASSERT(!p->hipe.nsp && !p->hipe.nstend);
255 return old_htop;
256 }
257 if (!nstack_walk_init_check(p))
258 return old_htop;
259
260 ASSERT(p->hipe.nsp && p->hipe.nstend);
261 nsp = nstack_walk_nsp_begin(p);
262 nsp_end = nstack_walk_nsp_end(p);
263 sdesc = nstack_walk_init_sdesc_ignore_trap(p, &walk_state);
264
265 while (!nstack_walk_nsp_reached_end(nsp, nsp_end)) {
266 unsigned long ra;
267 unsigned sdesc_size = nstack_walk_frame_size(sdesc);
268 unsigned i = 0;
269 unsigned mask = sdesc->livebits[0];
270 for (;;) {
271 if (mask & 1) {
272 Eterm *nsp_i = nstack_walk_frame_index(nsp, i);
273 Eterm gval = *nsp_i;
274 if (is_boxed(gval)) {
275 Eterm *ptr = boxed_val(gval);
276 Eterm val = *ptr;
277 if (IS_MOVED_BOXED(val)) {
278 ASSERT(is_boxed(val));
279 *nsp_i = val;
280 } else if (ErtsInArea(ptr, area, area_size)) {
281 move_boxed(ptr, val, &old_htop, nsp_i);
282 }
283 } else if (is_list(gval)) {
284 Eterm *ptr = list_val(gval);
285 Eterm val = *ptr;
286 if (IS_MOVED_CONS(val)) {
287 *nsp_i = ptr[1];
288 } else if (ErtsInArea(ptr, area, area_size)) {
289 move_cons(ptr, val, &old_htop, nsp_i);
290 }
291 }
292 }
293 if (++i >= sdesc_size)
294 break;
295 if (i & 31)
296 mask >>= 1;
297 else
298 mask = sdesc->livebits[i >> 5];
299 }
300 ra = nstack_walk_frame_ra(nsp, sdesc);
301 if (ra == (unsigned long)nbif_stack_trap_ra)
302 ra = (unsigned long)p->hipe.ngra;
303 sdesc = hipe_find_sdesc(ra);
304 nsp = nstack_walk_next_frame(nsp, sdesc_size);
305 }
306 return old_htop;
307 }
308
309 int
nstack_any_heap_ref_ptrs(Process * rp,char * mod_start,Uint mod_size)310 nstack_any_heap_ref_ptrs(Process *rp, char* mod_start, Uint mod_size)
311 {
312 Eterm *nsp;
313 Eterm *nsp_end;
314 const struct hipe_sdesc *sdesc;
315 /* arch-specific nstack walk state */
316 struct nstack_walk_state walk_state;
317
318 ASSERT(!rp->hipe.gc_is_unsafe);
319
320 if (!rp->hipe.nstack || !nstack_walk_init_check(rp)) return 0;
321 ASSERT(rp->hipe.nsp && rp->hipe.nstend);
322 nsp = nstack_walk_nsp_begin(rp);
323 nsp_end = nstack_walk_nsp_end(rp);
324 sdesc = nstack_walk_init_sdesc_ignore_trap(rp, &walk_state);
325
326 while (!nstack_walk_nsp_reached_end(nsp, nsp_end)) {
327 unsigned long ra;
328 unsigned sdesc_size = nstack_walk_frame_size(sdesc);
329 unsigned i = 0;
330 unsigned mask = sdesc->livebits[0];
331 for (;;) {
332 if (mask & 1) {
333 Eterm *nsp_i = nstack_walk_frame_index(nsp, i);
334 Eterm val = *nsp_i;
335 switch (primary_tag(val)) {
336 case TAG_PRIMARY_BOXED:
337 case TAG_PRIMARY_LIST:
338 if (ErtsInArea(val, mod_start, mod_size)) {
339 return 1;
340 }
341 break;
342 }
343 }
344 if (++i >= sdesc_size)
345 break;
346 if (i & 31)
347 mask >>= 1;
348 else
349 mask = sdesc->livebits[i >> 5];
350 }
351 ra = nstack_walk_frame_ra(nsp, sdesc);
352 if (ra == (unsigned long)nbif_stack_trap_ra)
353 ra = (unsigned long)rp->hipe.ngra;
354 sdesc = hipe_find_sdesc(ra);
355 nsp = nstack_walk_next_frame(nsp, sdesc_size);
356 }
357 return 0;
358 }
359
360 int
nstack_any_cps_in_segment(Process * p,char * seg_start,Uint seg_size)361 nstack_any_cps_in_segment(Process *p, char* seg_start, Uint seg_size)
362 {
363 Eterm *nsp;
364 Eterm *nsp_end;
365 const struct hipe_sdesc *sdesc;
366 /* arch-specific nstack walk state */
367 struct nstack_walk_state walk_state;
368
369 if (!p->hipe.nstack || !nstack_walk_init_check(p))
370 return 0;
371 ASSERT(p->hipe.nsp && p->hipe.nstend);
372 nsp = nstack_walk_nsp_begin(p);
373 nsp_end = nstack_walk_nsp_end(p);
374 sdesc = nstack_walk_init_sdesc_ignore_trap(p, &walk_state);
375
376 /* Check the topmost frame */
377 if (ErtsInArea(sdesc->bucket.hvalue, seg_start, seg_size))
378 return 1;
379
380 while (!nstack_walk_nsp_reached_end(nsp, nsp_end)) {
381 unsigned sdesc_size = nstack_walk_frame_size(sdesc);
382 unsigned long ra = nstack_walk_frame_ra(nsp, sdesc);
383 if (ra == (unsigned long)nbif_stack_trap_ra)
384 ra = (unsigned long)p->hipe.ngra;
385 if (ErtsInArea(ra, seg_start, seg_size))
386 return 1;
387 sdesc = hipe_find_sdesc(ra);
388 nsp = nstack_walk_next_frame(nsp, sdesc_size);
389 }
390 return 0;
391 }
392