diff options
Diffstat (limited to 'erts/emulator/hipe/hipe_gc.c')
-rw-r--r-- | erts/emulator/hipe/hipe_gc.c | 556 |
1 files changed, 556 insertions, 0 deletions
diff --git a/erts/emulator/hipe/hipe_gc.c b/erts/emulator/hipe/hipe_gc.c new file mode 100644 index 0000000000..e57e293547 --- /dev/null +++ b/erts/emulator/hipe/hipe_gc.c @@ -0,0 +1,556 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2009. 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% + */ +/* $Id$ + * 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(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_non_value(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(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_non_value(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 */ |