/* * %CopyrightBegin% * * Copyright Ericsson AB 2004-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * %CopyrightEnd% */ /* * GC support procedures */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "global.h" #include "erl_gc.h" #include "hipe_stack.h" #include "hipe_gc.h" #include "hipe_bif0.h" /* for hipe_constants_{start,next} */ Eterm *fullsweep_nstack(Process *p, Eterm *n_htop) { /* known nstack walk state */ Eterm *nsp; Eterm *nsp_end; const struct sdesc *sdesc; unsigned int sdesc_size; unsigned long ra; unsigned int i; unsigned int mask; /* arch-specific nstack walk state */ struct nstack_walk_state walk_state; /* fullsweep-specific state */ char *src, *oh; Uint src_size, oh_size; if (!nstack_walk_init_check(p)) return n_htop; nsp = nstack_walk_nsp_begin(p); nsp_end = p->hipe.nstgraylim; if (nsp_end) nstack_walk_kill_trap(p, nsp_end); nsp_end = nstack_walk_nsp_end(p); sdesc = nstack_walk_init_sdesc(p, &walk_state); src = (char*)HEAP_START(p); src_size = (char*)HEAP_TOP(p) - src; oh = (char*)OLD_HEAP(p); oh_size = (char*)OLD_HTOP(p) - oh; for (;;) { if (nstack_walk_nsp_reached_end(nsp, nsp_end)) { if (nsp == nsp_end) { if (nsp) { /* see the HIGH_WATER update in fullsweep_heap() */ p->hipe.nstblacklim = nsp; /* nsp == nsp_end */ nstack_walk_update_trap(p, walk_state.sdesc0); } return n_htop; } fprintf(stderr, "%s: passed end of stack\r\n", __FUNCTION__); break; } sdesc_size = nstack_walk_frame_size(sdesc); i = 0; mask = sdesc->livebits[0]; for (;;) { if (mask & 1) { Eterm *nsp_i = nstack_walk_frame_index(nsp, i); Eterm gval = *nsp_i; if (is_boxed(gval)) { Eterm *ptr = boxed_val(gval); Eterm val = *ptr; if (IS_MOVED_BOXED(val)) { ASSERT(is_boxed(val)); *nsp_i = val; } else if (in_area(ptr, src, src_size) || in_area(ptr, oh, oh_size)) { MOVE_BOXED(ptr, val, n_htop, nsp_i); } } else if (is_list(gval)) { Eterm *ptr = list_val(gval); Eterm val = *ptr; if (IS_MOVED_CONS(val)) { *nsp_i = ptr[1]; } else if (in_area(ptr, src, src_size) || in_area(ptr, oh, oh_size)) { ASSERT(within(ptr, p)); MOVE_CONS(ptr, val, n_htop, nsp_i); } } } if (++i >= sdesc_size) break; if (i & 31) mask >>= 1; else mask = sdesc->livebits[i >> 5]; } ra = nstack_walk_frame_ra(nsp, sdesc); sdesc = hipe_find_sdesc(ra); nsp = nstack_walk_next_frame(nsp, sdesc_size); } abort(); } void gensweep_nstack(Process *p, Eterm **ptr_old_htop, Eterm **ptr_n_htop) { /* known nstack walk state */ Eterm *nsp; Eterm *nsp_end; const struct sdesc *sdesc; unsigned int sdesc_size; unsigned long ra; unsigned int i; unsigned int mask; /* arch-specific nstack walk state */ struct nstack_walk_state walk_state; /* gensweep-specific state */ Eterm *old_htop, *n_htop; char *heap; Uint heap_size, mature_size; if (!nstack_walk_init_check(p)) return; nsp = nstack_walk_nsp_begin(p); nsp_end = p->hipe.nstgraylim; if (nsp_end) { /* if gray limit passed black limit, reset black limit */ if (nstack_walk_gray_passed_black(nsp_end, p->hipe.nstblacklim)) p->hipe.nstblacklim = nsp_end; nstack_walk_kill_trap(p, nsp_end); nsp_end = p->hipe.nstblacklim; } else nsp_end = nstack_walk_nsp_end(p); sdesc = nstack_walk_init_sdesc(p, &walk_state); old_htop = *ptr_old_htop; n_htop = *ptr_n_htop; heap = (char*)HEAP_START(p); heap_size = (char*)HEAP_TOP(p) - heap; mature_size = (char*)HIGH_WATER(p) - heap; for (;;) { if (nstack_walk_nsp_reached_end(nsp, nsp_end)) { if (nsp == nsp_end) { *ptr_old_htop = old_htop; *ptr_n_htop = n_htop; if (nsp) { /* see the HIGH_WATER update in gen_gc() */ if (HEAP_START(p) != HIGH_WATER(p)) { p->hipe.nstblacklim = p->hipe.nstgraylim ? p->hipe.nstgraylim : nsp; /* nsp == nsp_end */ } else { /* blacklim = graylim ? blacklim : end */ if (!p->hipe.nstgraylim) p->hipe.nstblacklim = nsp; /* nsp == nsp_end */ } nstack_walk_update_trap(p, walk_state.sdesc0); } return; } fprintf(stderr, "%s: passed end of stack\r\n", __FUNCTION__); break; } sdesc_size = nstack_walk_frame_size(sdesc); i = 0; mask = sdesc->livebits[0]; for (;;) { if (mask & 1) { Eterm *nsp_i = nstack_walk_frame_index(nsp, i); Eterm gval = *nsp_i; if (is_boxed(gval)) { Eterm *ptr = boxed_val(gval); Eterm val = *ptr; if (IS_MOVED_BOXED(val)) { ASSERT(is_boxed(val)); *nsp_i = val; } else if (in_area(ptr, heap, mature_size)) { MOVE_BOXED(ptr, val, old_htop, nsp_i); } else if (in_area(ptr, heap, heap_size)) { ASSERT(within(ptr, p)); MOVE_BOXED(ptr, val, n_htop, nsp_i); } } else if (is_list(gval)) { Eterm *ptr = list_val(gval); Eterm val = *ptr; if (IS_MOVED_CONS(val)) { *nsp_i = ptr[1]; } else if (in_area(ptr, heap, mature_size)) { MOVE_CONS(ptr, val, old_htop, nsp_i); } else if (in_area(ptr, heap, heap_size)) { ASSERT(within(ptr, p)); MOVE_CONS(ptr, val, n_htop, nsp_i); } } } if (++i >= sdesc_size) break; if (i & 31) mask >>= 1; else mask = sdesc->livebits[i >> 5]; } ra = nstack_walk_frame_ra(nsp, sdesc); sdesc = hipe_find_sdesc(ra); nsp = nstack_walk_next_frame(nsp, sdesc_size); } abort(); } #ifdef HYBRID #ifdef INCREMENTAL Eterm *ma_fullsweep_nstack(Process *p, Eterm *n_htop, Eterm *n_hend) { /* known nstack walk state */ Eterm *nsp; Eterm *nsp_end; const struct sdesc *sdesc; unsigned int sdesc_size; unsigned long ra; unsigned int i; unsigned int mask; /* arch-specific nstack walk state */ struct nstack_walk_state walk_state; if (!nstack_walk_init_check(p)) return n_htop; nsp = nstack_walk_nsp_begin(p); nsp_end = nstack_walk_nsp_end(p); sdesc = nstack_walk_init_sdesc(p, &walk_state); for (;;) { if (nstack_walk_nsp_reached_end(nsp, nsp_end)) { if (nsp == nsp_end) return n_htop; fprintf(stderr, "%s: passed end of stack\r\n", __FUNCTION__); break; } sdesc_size = nstack_walk_frame_size(sdesc); i = 0; mask = sdesc->livebits[0]; for (;;) { if (mask & 1) { Eterm *nsp_i = nstack_walk_frame_index(nsp, i); Eterm val = *nsp_i; Eterm *obj_ptr = ptr_val(val); switch (primary_tag(val)) { case TAG_PRIMARY_LIST: COPYMARK_CONS(obj_ptr, n_htop, nsp_i, n_hend); break; case TAG_PRIMARY_BOXED: COPYMARK_BOXED(obj_ptr, n_htop, nsp_i, n_hend); break; default: break; } } if (++i >= sdesc_size) break; if (i & 31) mask >>= 1; else mask = sdesc->livebits[i >> 5]; } ra = nstack_walk_frame_ra(nsp, sdesc); if (ra == (unsigned long)nbif_stack_trap_ra) ra = (unsigned long)p->hipe.ngra; sdesc = hipe_find_sdesc(ra); nsp = nstack_walk_next_frame(nsp, sdesc_size); } abort(); } void ma_gensweep_nstack(Process *p, Eterm **ptr_old_htop, Eterm **ptr_n_htop) { /* known nstack walk state */ Eterm *nsp; Eterm *nsp_end; const struct sdesc *sdesc; unsigned int sdesc_size; unsigned long ra; unsigned int i; unsigned int mask; /* arch-specific nstack walk state */ struct nstack_walk_state walk_state; /* ma_gensweep-specific state */ Eterm *low_water, *high_water, *surface; Eterm *n_htop; Eterm *old_htop; if (!nstack_walk_init_check(p)) return; nsp = nstack_walk_nsp_begin(p); nsp_end = nstack_walk_nsp_end(p); low_water = global_heap; //high_water = global_high_water; surface = global_htop; old_htop = *ptr_old_htop; n_htop = *ptr_n_htop; sdesc = nstack_walk_init_sdesc(p, &walk_state); for (;;) { if (nstack_walk_nsp_reached_end(nsp, nsp_end)) { if (nsp == nsp_end) { *ptr_old_htop = old_htop; *ptr_n_htop = n_htop; return; } fprintf(stderr, "%s: passed end of stack\r\n", __FUNCTION__); break; } sdesc_size = nstack_walk_frame_size(sdesc); i = 0; mask = sdesc->livebits[0]; for (;;) { if (mask & 1) { Eterm *nsp_i = nstack_walk_frame_index(nsp, i); Eterm gval = *nsp_i; if (is_boxed(gval)) { Eterm *ptr = boxed_val(gval); Eterm val = *ptr; if (MY_IS_MOVED(val)) { *nsp_i = val; } else if (ptr_within(ptr, low_water, high_water)) { MOVE_BOXED(ptr, val, old_htop, nsp_i); } else if (ptr_within(ptr, high_water, surface)) { MOVE_BOXED(ptr, val, n_htop, nsp_i); } } else if (is_list(gval)) { Eterm *ptr = list_val(gval); Eterm val = *ptr; if (is_non_value(val)) { *nsp_i = ptr[1]; } else if (ptr_within(ptr, low_water, high_water)) { MOVE_CONS(ptr, val, old_htop, nsp_i); } else if (ptr_within(ptr, high_water, surface)) { MOVE_CONS(ptr, val, n_htop, nsp_i); } } } if (++i >= sdesc_size) break; if (i & 31) mask >>= 1; else mask = sdesc->livebits[i >> 5]; } ra = nstack_walk_frame_ra(nsp, sdesc); if (ra == (unsigned long)nbif_stack_trap_ra) ra = (unsigned long)p->hipe.ngra; sdesc = hipe_find_sdesc(ra); nsp = nstack_walk_next_frame(nsp, sdesc_size); } abort(); } #else /* not INCREMENTAL */ Eterm *ma_fullsweep_nstack(Process *p, Eterm *n_htop) { /* known nstack walk state */ Eterm *nsp; Eterm *nsp_end; const struct sdesc *sdesc; unsigned int sdesc_size; unsigned long ra; unsigned int i; unsigned int mask; /* arch-specific nstack walk state */ struct nstack_walk_state walk_state; /* ma_fullsweep-specific state */ Eterm *gheap = global_heap; Eterm *ghtop = global_htop; Eterm *goheap = global_old_heap; Eterm *gohtop = global_old_htop; if (!nstack_walk_init_check(p)) return n_htop; nsp = nstack_walk_nsp_begin(p); nsp_end = nstack_walk_nsp_end(p); sdesc = nstack_walk_init_sdesc(p, &walk_state); for (;;) { if (nstack_walk_nsp_reached_end(nsp, nsp_end)) { if (nsp == nsp_end) return n_htop; fprintf(stderr, "%s: passed end of stack\r\n", __FUNCTION__); break; } sdesc_size = nstack_walk_frame_size(sdesc); i = 0; mask = sdesc->livebits[0]; for (;;) { if (mask & 1) { Eterm *nsp_i = nstack_walk_frame_index(nsp, i); Eterm gval = *nsp_i; if (is_boxed(gval)) { Eterm *ptr = boxed_val(gval); Eterm val = *ptr; if (MY_IS_MOVED(val)) { *nsp_i = val; } else if (ptr_within(ptr, gheap, ghtop)) { MOVE_BOXED(ptr, val, n_htop, nsp_i); } else if (ptr_within(ptr, goheap, gohtop)) { MOVE_BOXED(ptr, val, n_htop, nsp_i); } } else if (is_list(gval)) { Eterm *ptr = list_val(gval); Eterm val = *ptr; if (is_non_value(val)) { *nsp_i = ptr[1]; } else if (ptr_within(ptr, gheap, ghtop)) { MOVE_CONS(ptr, val, n_htop, nsp_i); } else if (ptr_within(ptr, gheap, ghtop)) { MOVE_CONS(ptr, val, n_htop, nsp_i); } } } if (++i >= sdesc_size) break; if (i & 31) mask >>= 1; else mask = sdesc->livebits[i >> 5]; } ra = nstack_walk_frame_ra(nsp, sdesc); if (ra == (unsigned long)nbif_stack_trap_ra) ra = (unsigned long)p->hipe.ngra; sdesc = hipe_find_sdesc(ra); nsp = nstack_walk_next_frame(nsp, sdesc_size); } abort(); } void ma_gensweep_nstack(Process *p, Eterm **ptr_old_htop, Eterm **ptr_n_htop) { /* known nstack walk state */ Eterm *nsp; Eterm *nsp_end; const struct sdesc *sdesc; unsigned int sdesc_size; unsigned long ra; unsigned int i; unsigned int mask; /* arch-specific nstack walk state */ struct nstack_walk_state walk_state; /* ma_gensweep-specific state */ Eterm *low_water, *high_water, *surface; Eterm *n_htop; Eterm *old_htop; if (!nstack_walk_init_check(p)) return; nsp = nstack_walk_nsp_begin(p); nsp_end = nstack_walk_nsp_end(p); low_water = global_heap; high_water = global_high_water; surface = global_htop; old_htop = *ptr_old_htop; n_htop = *ptr_n_htop; sdesc = nstack_walk_init_sdesc(p, &walk_state); for (;;) { if (nstack_walk_nsp_reached_end(nsp, nsp_end)) { if (nsp == nsp_end) { *ptr_old_htop = old_htop; *ptr_n_htop = n_htop; return; } fprintf(stderr, "%s: passed end of stack\r\n", __FUNCTION__); break; } sdesc_size = nstack_walk_frame_size(sdesc); i = 0; mask = sdesc->livebits[0]; for (;;) { if (mask & 1) { Eterm *nsp_i = nstack_walk_frame_index(nsp, i); Eterm gval = *nsp_i; if (is_boxed(gval)) { Eterm *ptr = boxed_val(gval); Eterm val = *ptr; if (MY_IS_MOVED(val)) { *nsp_i = val; } else if (ptr_within(ptr, low_water, high_water)) { MOVE_BOXED(ptr, val, old_htop, nsp_i); } else if (ptr_within(ptr, high_water, surface)) { MOVE_BOXED(ptr, val, n_htop, nsp_i); } } else if (is_list(gval)) { Eterm *ptr = list_val(gval); Eterm val = *ptr; if (is_non_value(val)) { *nsp_i = ptr[1]; } else if (ptr_within(ptr, low_water, high_water)) { MOVE_CONS(ptr, val, old_htop, nsp_i); } else if (ptr_within(ptr, high_water, surface)) { MOVE_CONS(ptr, val, n_htop, nsp_i); } } } if (++i >= sdesc_size) break; if (i & 31) mask >>= 1; else mask = sdesc->livebits[i >> 5]; } ra = nstack_walk_frame_ra(nsp, sdesc); if (ra == (unsigned long)nbif_stack_trap_ra) ra = (unsigned long)p->hipe.ngra; sdesc = hipe_find_sdesc(ra); nsp = nstack_walk_next_frame(nsp, sdesc_size); } abort(); } #endif /* INCREMENTAL */ #endif /* HYBRID */