static void reset_back_edge(ptr_t p, size_t n_bytes GC_ATTR_UNUSED, word gc_descr GC_ATTR_UNUSED) { /* Skip any free list links, or dropped blocks */ if (GC_HAS_DEBUG_INFO(p)) { ptr_t old_back_ptr = GET_OH_BG_PTR(p); if ((word)old_back_ptr & FLAG_MANY) { back_edges *be = (back_edges *)((word)old_back_ptr & ~FLAG_MANY); if (!(be -> flags & RETAIN)) { deallocate_back_edges(be); SET_OH_BG_PTR(p, 0); } else { GC_ASSERT(GC_is_marked(p)); /* Back edges may point to objects that will not be retained. */ /* Delete them for now, but remember the height. */ /* Some will be added back at next GC. */ be -> n_edges = 0; if (0 != be -> cont) { deallocate_back_edges(be -> cont); be -> cont = 0; } GC_ASSERT(GC_is_marked(p)); /* We only retain things for one GC cycle at a time. */ be -> flags &= ~RETAIN; } } else /* Simple back pointer */ { /* Clear to avoid dangling pointer. */ SET_OH_BG_PTR(p, 0); } } }
/* q are pointers to the object base, i.e. pointers to an oh. */ static void add_edge(ptr_t p, ptr_t q) { ptr_t old_back_ptr = GET_OH_BG_PTR(q); back_edges * be, *be_cont; word i; static unsigned random_number = 13; # define GOT_LUCKY_NUMBER (((++random_number) & 0x7f) == 0) /* A not very random number we use to occasionally allocate a */ /* back_edges structure even for a single backward edge. This */ /* prevents us from repeatedly tracing back through very long */ /* chains, since we will have some place to store height and */ /* in_progress flags along the way. */ GC_ASSERT(p == GC_base(p) && q == GC_base(q)); if (!GC_HAS_DEBUG_INFO(q) || !GC_HAS_DEBUG_INFO(p)) { /* This is really a misinterpreted free list link, since we saw */ /* a pointer to a free list. Dont overwrite it! */ return; } if (0 == old_back_ptr) { SET_OH_BG_PTR(q, p); if (GOT_LUCKY_NUMBER) ensure_struct(q); return; } /* Check whether it was already in the list of predecessors. */ FOR_EACH_PRED(pred, q, { if (p == pred) return; });
/* Ensure that p has a back_edges structure associated with it. */ static void ensure_struct(ptr_t p) { ptr_t old_back_ptr = GET_OH_BG_PTR(p); if (!((word)old_back_ptr & FLAG_MANY)) { back_edges *be = new_back_edges(); be -> flags = 0; if (0 == old_back_ptr) { be -> n_edges = 0; } else { be -> n_edges = 1; be -> edges[0] = old_back_ptr; } be -> height = HEIGHT_UNKNOWN; be -> height_gc_no = (unsigned short)(GC_gc_no - 1); GC_ASSERT(be >= back_edge_space); SET_OH_BG_PTR(p, (word)be | FLAG_MANY); } }
GC_ASSERT(p == GC_base(p) && q == GC_base(q)); if (!GC_HAS_DEBUG_INFO(q) || !GC_HAS_DEBUG_INFO(p)) { /* This is really a misinterpreted free list link, since we saw */ /* a pointer to a free list. Dont overwrite it! */ return; } if (0 == old_back_ptr) { SET_OH_BG_PTR(q, p); if (GOT_LUCKY_NUMBER) ensure_struct(q); return; } /* Check whether it was already in the list of predecessors. */ FOR_EACH_PRED(pred, q, { if (p == pred) return; }); ensure_struct(q); old_back_ptr = GET_OH_BG_PTR(q); be = (back_edges *)((word)old_back_ptr & ~FLAG_MANY); for (i = be -> n_edges, be_cont = be; i > MAX_IN; be_cont = be_cont -> cont, i -= MAX_IN) {} if (i == MAX_IN) { be_cont -> cont = new_back_edges(); be_cont = be_cont -> cont; i = 0; } be_cont -> edges[i] = p; be -> n_edges++; if (be -> n_edges == 100) { # if 0 if (GC_print_stats) { GC_err_printf("The following object has in-degree >= 100:\n"); GC_print_heap_obj(q);
/* GC_deepest_obj to be the corresponding object. */ static void update_max_height(ptr_t p, size_t n_bytes GC_ATTR_UNUSED, word gc_descr GC_ATTR_UNUSED) { if (GC_is_marked(p) && GC_HAS_DEBUG_INFO(p)) { word p_height = 0; ptr_t p_deepest_obj = 0; ptr_t back_ptr; back_edges *be = 0; /* If we remembered a height last time, use it as a minimum. */ /* It may have increased due to newly unreachable chains pointing */ /* to p, but it can't have decreased. */ back_ptr = GET_OH_BG_PTR(p); if (0 != back_ptr && ((word)back_ptr & FLAG_MANY)) { be = (back_edges *)((word)back_ptr & ~FLAG_MANY); if (be -> height != HEIGHT_UNKNOWN) p_height = be -> height; } { ptr_t pred = GET_OH_BG_PTR(p); back_edges *e = (back_edges *)((word)pred & ~FLAG_MANY); word n_edges; word total; int local = 0; if (((word)pred & FLAG_MANY) != 0) { n_edges = e -> n_edges; } else if (pred != NULL && ((word)pred & 1) == 0) { /* A misinterpreted freelist link. */ n_edges = 1; local = -1; } else { n_edges = 0; } for (total = 0; total < n_edges; ++total) { if (local == MAX_IN) { e = e -> cont; local = 0; } if (local >= 0) pred = e -> edges[local++]; /* Execute the following once for each predecessor pred of p */ /* in the points-to graph. */ if (!GC_is_marked(pred) && GC_HAS_DEBUG_INFO(pred)) { word this_height = backwards_height(pred); if (this_height > p_height) { p_height = this_height; p_deepest_obj = pred; } } } } if (p_height > 0) { /* Remember the height for next time. */ if (be == 0) { ensure_struct(p); back_ptr = GET_OH_BG_PTR(p); be = (back_edges *)((word)back_ptr & ~FLAG_MANY); } be -> flags |= RETAIN; be -> height = p_height; be -> height_gc_no = (unsigned short)GC_gc_no; } if (p_height > GC_max_height) { GC_max_height = p_height; GC_deepest_obj = p_deepest_obj; } } }
/* of p. */ static word backwards_height(ptr_t p) { word result; ptr_t pred = GET_OH_BG_PTR(p); back_edges *be; if (NULL == pred) return 1; if (((word)pred & FLAG_MANY) == 0) { if (is_in_progress(p)) return 0; /* DFS back edge, i.e. we followed */ /* an edge to an object already */ /* on our stack: ignore */ push_in_progress(p); result = backwards_height(pred) + 1; pop_in_progress(p); return result; } be = (back_edges *)((word)pred & ~FLAG_MANY); if (be -> height >= 0 && be -> height_gc_no == (unsigned short)GC_gc_no) return be -> height; /* Ignore back edges in DFS */ if (be -> height == HEIGHT_IN_PROGRESS) return 0; result = (be -> height > 0? be -> height : 1); be -> height = HEIGHT_IN_PROGRESS; { back_edges *e = be; word n_edges; word total; int local = 0; if (((word)pred & FLAG_MANY) != 0) { n_edges = e -> n_edges; } else if (pred != NULL && ((word)pred & 1) == 0) { /* A misinterpreted freelist link. */ n_edges = 1; local = -1; } else { n_edges = 0; } for (total = 0; total < n_edges; ++total) { word this_height; if (local == MAX_IN) { e = e -> cont; local = 0; } if (local >= 0) pred = e -> edges[local++]; /* Execute the following once for each predecessor pred of p */ /* in the points-to graph. */ if (GC_is_marked(pred) && ((word)GET_OH_BG_PTR(p) & FLAG_MANY) == 0) { GC_COND_LOG_PRINTF("Found bogus pointer from %p to %p\n", (void *)pred, (void *)p); /* Reachable object "points to" unreachable one. */ /* Could be caused by our lax treatment of GC descriptors. */ this_height = 1; } else { this_height = backwards_height(pred); } if (this_height >= result) result = this_height + 1; } } be -> height = result; be -> height_gc_no = (unsigned short)GC_gc_no; return result; }
/* q are pointers to the object base, i.e. pointers to an oh. */ static void add_edge(ptr_t p, ptr_t q) { ptr_t pred = GET_OH_BG_PTR(q); back_edges * be, *be_cont; word i; GC_ASSERT(p == GC_base(p) && q == GC_base(q)); if (!GC_HAS_DEBUG_INFO(q) || !GC_HAS_DEBUG_INFO(p)) { /* This is really a misinterpreted free list link, since we saw */ /* a pointer to a free list. Don't overwrite it! */ return; } if (NULL == pred) { static unsigned random_number = 13; # define GOT_LUCKY_NUMBER (((++random_number) & 0x7f) == 0) /* A not very random number we use to occasionally allocate a */ /* back_edges structure even for a single backward edge. This */ /* prevents us from repeatedly tracing back through very long */ /* chains, since we will have some place to store height and */ /* in_progress flags along the way. */ SET_OH_BG_PTR(q, p); if (GOT_LUCKY_NUMBER) ensure_struct(q); return; } /* Check whether it was already in the list of predecessors. */ { back_edges *e = (back_edges *)((word)pred & ~FLAG_MANY); word n_edges; word total; int local = 0; if (((word)pred & FLAG_MANY) != 0) { n_edges = e -> n_edges; } else if (pred != NULL && ((word)pred & 1) == 0) { /* A misinterpreted freelist link. */ n_edges = 1; local = -1; } else { n_edges = 0; } for (total = 0; total < n_edges; ++total) { if (local == MAX_IN) { e = e -> cont; local = 0; } if (local >= 0) pred = e -> edges[local++]; if (pred == p) return; } } ensure_struct(q); be = (back_edges *)((word)GET_OH_BG_PTR(q) & ~FLAG_MANY); for (i = be -> n_edges, be_cont = be; i > MAX_IN; i -= MAX_IN) be_cont = be_cont -> cont; if (i == MAX_IN) { be_cont -> cont = new_back_edges(); be_cont = be_cont -> cont; i = 0; } be_cont -> edges[i] = p; be -> n_edges++; # ifdef DEBUG_PRINT_BIG_N_EDGES if (GC_print_stats == VERBOSE && be -> n_edges == 100) { GC_err_printf("The following object has big in-degree:\n"); GC_print_heap_obj(q); } # endif }