aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/hipe/hipe_gc.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/hipe/hipe_gc.c')
-rw-r--r--erts/emulator/hipe/hipe_gc.c556
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 */