Пример #1
0
void
debug_print_ref(const ref *pref)
{	if ( r_is_packed(pref) )
		debug_print_packed_ref((const ref_packed *)pref);
	else
		debug_print_full_ref(pref);
	fflush(dstderr);
}
Пример #2
0
static
CLEAR_MARKS_PROC(change_clear_marks)
{
    alloc_change_t *const ptr = (alloc_change_t *)vptr;

    if (r_is_packed(&ptr->contents))
        r_clear_pmark((ref_packed *) & ptr->contents);
    else
        r_clear_attrs(&ptr->contents, l_mark);
}
Пример #3
0
} RELOC_PTRS_END

/* ------ Unmarking phase ------ */

/* Unmark a single ref. */
void
ptr_ref_unmark(enum_ptr_t *pep, gc_state_t * ignored)
{
    ref_packed *rpp = (ref_packed *)pep->ptr;

    if (r_is_packed(rpp))
	r_clear_pmark(rpp);
    else
	r_clear_attrs((ref *)rpp, l_mark);
}
Пример #4
0
/* Mark a ref.  Return true if new mark. */
bool
ptr_ref_mark(enum_ptr_t *pep, gc_state_t * ignored)
{
    ref_packed *rpp = (void *)pep->ptr;

    if (r_is_packed(rpp)) {
	if (r_has_pmark(rpp))
	    return false;
	r_set_pmark(rpp);
    } else {
	ref *const pref = (ref *)rpp;

	if (r_has_attr(pref, l_mark))
	    return false;
	r_set_attrs(pref, l_mark);
    }
    return true;
}
Пример #5
0
/* Clear the relocation for a ref object. */
static void
refs_clear_reloc(obj_header_t *hdr, uint size)
{
    ref_packed *rp = (ref_packed *) (hdr + 1);
    ref_packed *end = (ref_packed *) ((byte *) rp + size);

    while (rp < end) {
	if (r_is_packed(rp))
	    rp++;
	else {
	    /* Full-size ref.  Store the relocation here if possible. */
	    ref *const pref = (ref *)rp;

	    if (!ref_type_uses_size_or_null(r_type(pref))) {
		if_debug1('8', "  [8]clearing reloc at 0x%lx\n", (ulong) rp);
		r_set_size(pref, 0);
	    }
	    rp += packed_per_ref;
	}
    }
}
Пример #6
0
/* Dump an array. */
void
debug_dump_array(const ref *array)
{	const ref_packed *pp;
	unsigned int type = r_type(array);
	uint len;

	switch (type)
	   {
	default:
		dprintf2 ("%s at 0x%lx isn't an array.\n",
			  (type < countof(type_strings) ?
			   type_strings[type] : "????"),
			  (ulong)array);
		return;
	case t_oparray:
		/* This isn't really an array, but we'd like to see */
		/* its contents anyway. */
		debug_dump_array(op_array_table.value.refs + op_index(array) -
				 op_def_count);
		return;
	case t_array:
	case t_mixedarray:
	case t_shortarray: 
		;
	   }

	/* This "packed" loop works for all array-types. */
	for ( len = r_size (array), pp = array->value.packed;
	      len > 0;
	      len--, pp = packed_next(pp))
	   {	ref temp;
		packed_get(pp, &temp);
		dprintf3("..%04x%c 0x%02x ", 
			 (uint)pp & 0xffff,
			 ((r_is_packed(pp)) ? '*' : ':'),
			 r_type(&temp));
		debug_dump_one_ref(&temp);
		dputc ('\n');
	   }
}
Пример #7
0
/* Unmarking routine for ref objects. */
static void
refs_clear_marks(const gs_memory_t *cmem, 
		 void /*obj_header_t */ *vptr, uint size,
		 const gs_memory_struct_type_t * pstype)
{
    ref_packed *rp = (ref_packed *) vptr;
    ref_packed *end = (ref_packed *) ((byte *) vptr + size);

    /* Since the last ref is full-size, we only need to check for */
    /* the end of the block when we see one of those. */
    for (;;) {
	if (r_is_packed(rp)) {
#ifdef DEBUG
	    if (gs_debug_c('8')) {
		dlprintf1("  [8]unmark packed 0x%lx ", (ulong) rp);
		debug_print_ref(cmem, (const ref *)rp);
		dputs("\n");
	    }
#endif
	    r_clear_pmark(rp);
	    rp++;
	} else {		/* full-size ref */
	    ref *const pref = (ref *)rp;

#ifdef DEBUG
	    if (gs_debug_c('8')) {
		dlprintf1("  [8]unmark ref 0x%lx ", (ulong) rp);
		debug_print_ref(cmem, pref);
		dputs("\n");
	    }
#endif
	    r_clear_attrs(pref, l_mark);
	    rp += packed_per_ref;
	    if (rp >= (ref_packed *) end)
		break;
	}
    }
}
Пример #8
0
ref_packed *
igc_reloc_ref_ptr(const ref_packed * prp, gc_state_t *gcst)
{
    /*
     * Search forward for relocation.  This algorithm is intrinsically very
     * inefficient; we hope eventually to replace it with a better one.
     */
    const ref_packed *rp = prp;
#ifdef ALIGNMENT_ALIASING_BUG
    const ref *rpref;
# define RP_REF(rp) (rpref = (const ref *)rp, rpref)
#else
# define RP_REF(rp) ((const ref *)rp)
#endif
    /*
     * Iff this pointer points into a space that wasn't traced,
     * the referent won't be marked.  In this case, we shouldn't
     * do any relocation.  Check for this first.
     */
    if (r_is_packed(rp)) {
	if (!r_has_pmark(rp))
	    goto ret_rp;
    } else {
	if (!r_has_attr(RP_REF(rp), l_mark))
	    goto ret_rp;
    }
    return igc_reloc_ref_ptr_nocheck(prp, gcst);
ret_rp:
    /* Use a severely deprecated pun to remove the const property. */
    {
	union { const ref_packed *r; ref_packed *w; } u;

	u.r = rp;
	return u.w;
    }
}
Пример #9
0
static int
zbind(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    uint depth = 1;
    ref defn;
    register os_ptr bsp;

    switch (r_type(op)) {
        case t_array:
            if (!r_has_attr(op, a_write)) {
                return 0;	/* per PLRM3 */
            }
        case t_mixedarray:
        case t_shortarray:
            defn = *op;
            break;
        case t_oparray:
            defn = *op->value.const_refs;
            break;
        default:
            return_op_typecheck(op);
    }
    push(1);
    *op = defn;
    bsp = op;
    /*
     * We must not make the top-level procedure read-only,
     * but we must bind it even if it is read-only already.
     *
     * Here are the invariants for the following loop:
     *      `depth' elements have been pushed on the ostack;
     *      For i < depth, p = ref_stack_index(&o_stack, i):
     *        *p is an array (or packedarray) ref.
     */
    while (depth) {
        while (r_size(bsp)) {
            ref_packed *const tpp = (ref_packed *)bsp->value.packed; /* break const */

            r_dec_size(bsp, 1);
            if (r_is_packed(tpp)) {
                /* Check for a packed executable name */
                ushort elt = *tpp;

                if (r_packed_is_exec_name(&elt)) {
                    ref nref;
                    ref *pvalue;

                    name_index_ref(imemory, packed_name_index(&elt),
                                   &nref);
                    if ((pvalue = dict_find_name(&nref)) != 0 &&
                        r_is_ex_oper(pvalue)
                        ) {
                        store_check_dest(bsp, pvalue);
                        /*
                         * Always save the change, since this can only
                         * happen once.
                         */
                        ref_do_save(bsp, tpp, "bind");
                        *tpp = pt_tag(pt_executable_operator) +
                            op_index(pvalue);
                    }
                }
                bsp->value.packed = tpp + 1;
            } else {
                ref *const tp = bsp->value.refs++;

                switch (r_type(tp)) {
                    case t_name:	/* bind the name if an operator */
                        if (r_has_attr(tp, a_executable)) {
                            ref *pvalue;

                            if ((pvalue = dict_find_name(tp)) != 0 &&
                                r_is_ex_oper(pvalue)
                                ) {
                                store_check_dest(bsp, pvalue);
                                ref_assign_old(bsp, tp, pvalue, "bind");
                            }
                        }
                        break;
                    case t_array:	/* push into array if writable */
                        if (!r_has_attr(tp, a_write))
                            break;
                    case t_mixedarray:
                    case t_shortarray:
                        if (r_has_attr(tp, a_executable)) {
                            /* Make reference read-only */
                            r_clear_attrs(tp, a_write);
                            if (bsp >= ostop) {
                                /* Push a new stack block. */
                                ref temp;
                                int code;

                                temp = *tp;
                                osp = bsp;
                                code = ref_stack_push(&o_stack, 1);
                                if (code < 0) {
                                    ref_stack_pop(&o_stack, depth);
                                    return_error(code);
                                }
                                bsp = osp;
                                *bsp = temp;
                            } else
                                *++bsp = *tp;
                            depth++;
                        }
                }
            }
        }
        bsp--;
        depth--;
        if (bsp < osbot) {	/* Pop back to the previous stack block. */
            osp = bsp;
            ref_stack_pop_block(&o_stack);
            bsp = osp;
        }
    }
    osp = bsp;
    return 0;
}
Пример #10
0
/* Remove the marks at the same time. */
static void
refs_compact(const gs_memory_t *mem, obj_header_t * pre, obj_header_t * dpre, uint size)
{
    ref_packed *dest;
    ref_packed *src;
    ref_packed *end;
    uint new_size;

   /* The next switch controls an optimization 
      for the loop termination condition.
      It was useful during the development,
      when some assumptions were temporary wrong.
      We keep it for records. */

    src = (ref_packed *) (pre + 1);
    end = (ref_packed *) ((byte *) src + size);
    /*
     * We know that a block of refs always ends with a
     * full-size ref, so we only need to check for reaching the end
     * of the block when we see one of those.
     */
    if (dpre == pre)		/* Loop while we don't need to copy. */
	for (;;) {
	    if (r_is_packed(src)) {
		if (!r_has_pmark(src))
		    break;
		if_debug1('8', "  [8]packed ref 0x%lx \"copied\"\n",
			  (ulong) src);
		*src &= ~lp_mark;
		src++;
	    } else {		/* full-size ref */
		ref *const pref = (ref *)src;

		if (!r_has_attr(pref, l_mark))
		    break;
		if_debug1('8', "  [8]ref 0x%lx \"copied\"\n", (ulong) src);
		r_clear_attrs(pref, l_mark);
		src += packed_per_ref;
	    }
    } else
	*dpre = *pre;
    dest = (ref_packed *) ((char *)dpre + ((char *)src - (char *)pre));
    for (;;) {
	if (r_is_packed(src)) {
	    if (r_has_pmark(src)) {
		if_debug2('8', "  [8]packed ref 0x%lx copied to 0x%lx\n",
			  (ulong) src, (ulong) dest);
		*dest++ = *src & ~lp_mark;
	    }
	    src++;
	} else {		/* full-size ref */
	    if (r_has_attr((ref *) src, l_mark)) {
		ref rtemp;

		if_debug2('8', "  [8]ref 0x%lx copied to 0x%lx\n",
			  (ulong) src, (ulong) dest);
		/* We can't just use ref_assign_inline, */
		/* because the source and destination */
		/* might overlap! */
		ref_assign_inline(&rtemp, (ref *) src);
		r_clear_attrs(&rtemp, l_mark);
		ref_assign_inline((ref *) dest, &rtemp);
		src += packed_per_ref;
		dest += packed_per_ref;
	    } else {		/* check for end of block */
		src += packed_per_ref;
		if (src >= end)
		    break;
	    }
	}
    }
    new_size = (byte *) dest - (byte *) (dpre + 1) + sizeof(ref);
#ifdef DEBUG
    /* Check that the relocation came out OK. */
    /* NOTE: this check only works within a single chunk. */
    if ((byte *) src - (byte *) dest != r_size((ref *) src - 1) + sizeof(ref)) {
	lprintf3("Reloc error for refs 0x%lx: reloc = %lu, stored = %u\n",
		 (ulong) dpre, (ulong) ((byte *) src - (byte *) dest),
		 (uint) r_size((ref *) src - 1));
	gs_abort(mem);
    }
#endif
    /* Pad to a multiple of sizeof(ref). */
    while (new_size & (sizeof(ref) - 1))
	*dest++ = pt_tag(pt_integer),
	    new_size += sizeof(ref_packed);
    /* We want to make the newly freed space into a free block, */
    /* but we can only do this if we have enough room. */
    if (size - new_size < sizeof(obj_header_t)) {	/* Not enough room.  Pad to original size. */
	while (new_size < size)
	    *dest++ = pt_tag(pt_integer),
		new_size += sizeof(ref_packed);
    } else {
	obj_header_t *pfree = (obj_header_t *) ((ref *) dest + 1);

	pfree->o_alone = 0;
	pfree->o_size = size - new_size - sizeof(obj_header_t);
	pfree->o_type = &st_bytes;
    }
    /* Re-create the final ref. */
    r_set_type((ref *) dest, t_integer);
    dpre->o_size = new_size;
}
Пример #11
0
/* See gsmemory.h for why the argument is const and the result is not. */
ref_packed *
igc_reloc_ref_ptr_nocheck(const ref_packed * prp, gc_state_t *gcst)
{
    /*
     * Search forward for relocation.  This algorithm is intrinsically very
     * inefficient; we hope eventually to replace it with a better one.
     */
    const ref_packed *rp = prp;
    uint dec = 0;
#ifdef ALIGNMENT_ALIASING_BUG
    const ref *rpref;
# define RP_REF(rp) (rpref = (const ref *)rp, rpref)
#else
# define RP_REF(rp) ((const ref *)rp)
#endif
    for (;;) {

	if (r_is_packed(rp)) {
	    /*
	     * Normally, an unmarked packed ref will be an
	     * integer whose value is the amount of relocation.
	     * However, the relocation value might have been
	     * too large to fit.  If this is the case, for
	     * each such unmarked packed ref we pass over,
	     * we have to decrement the final relocation.
	     */
	    rputc((*rp & lp_mark ? '1' : '0'));
	    if (!(*rp & lp_mark)) {
		if (*rp != pt_tag(pt_integer) + packed_max_value) {
		    /* This is a stored relocation value. */
		    rputc('\n');
		    rp = print_reloc(prp, "ref",
				     (const ref_packed *)
				     ((const char *)prp -
				      (*rp & packed_value_mask) + dec));
		    break;
		}
		/*
		 * We know this is the first of an aligned block
		 * of packed refs.  Skip over the entire block,
		 * decrementing the final relocation.
		 */
		dec += sizeof(ref_packed) * align_packed_per_ref;
		rp += align_packed_per_ref;
	    } else
		rp++;
	    continue;
	}
	if (!ref_type_uses_size_or_null(r_type(RP_REF(rp)))) {
	    /* reloc is in r_size */
	    rputc('\n');
	    rp = print_reloc(prp, "ref",
			     (const ref_packed *)
			     (r_size(RP_REF(rp)) == 0 ? prp :
			      (const ref_packed *)((const char *)prp -
						   r_size(RP_REF(rp)) + dec)));
	    break;
	}
	rputc('u');
	rp += packed_per_ref;
    }
    /* Use a severely deprecated pun to remove the const property. */
    {
	union { const ref_packed *r; ref_packed *w; } u;

	u.r = rp;
	return u.w;
    }
#undef RP_REF
}
Пример #12
0
/* untraced space, so relocate all refs, not just marked ones. */
void
igc_reloc_refs(ref_packed * from, ref_packed * to, gc_state_t * gcst)
{
    int min_trace = gcst->min_collect;
    ref_packed *rp = from;
    bool do_all = gcst->relocating_untraced; 

    vm_spaces spaces = gcst->spaces;
    const gs_memory_t *cmem = space_system->stable_memory;

    while (rp < to) {
	ref *pref;
#ifdef DEBUG
	const void *before = 0;
	const void *after = 0;
# define DO_RELOC(var, stat)\
    BEGIN before = (var); stat; after = (var); END
# define SET_RELOC(var, expr)\
    BEGIN before = (var); after = (var) = (expr); END
#else
# define DO_RELOC(var, stat) stat
# define SET_RELOC(var, expr) var = expr
#endif

	if (r_is_packed(rp)) {
	    rp++;
	    continue;
	}
	/* The following assignment is logically unnecessary; */
	/* we do it only for convenience in debugging. */
	pref = (ref *) rp;
	if_debug3('8', "  [8]relocating %s %d ref at 0x%lx\n",
		  (r_has_attr(pref, l_mark) ? "marked" : "unmarked"),
		  r_btype(pref), (ulong) pref);
	if ((r_has_attr(pref, l_mark) || do_all) &&
	    r_space(pref) >= min_trace
	    ) {
	    switch (r_type(pref)) {
		    /* Struct cases */
		case t_file:
		    DO_RELOC(pref->value.pfile, RELOC_VAR(pref->value.pfile));
		    break;
		case t_device:
		    DO_RELOC(pref->value.pdevice,
			     RELOC_VAR(pref->value.pdevice));
		    break;
		case t_fontID:
		case t_struct:
		case t_astruct:
		    DO_RELOC(pref->value.pstruct,
			     RELOC_VAR(pref->value.pstruct));
		    break;
		    /* Non-trivial non-struct cases */
		case t_dictionary:
		    rputc('d');
		    SET_RELOC(pref->value.pdict,
			      (dict *)igc_reloc_ref_ptr((ref_packed *)pref->value.pdict, gcst));
		    break;
		case t_array:
		    {
			uint size = r_size(pref);

			if (size != 0) {	/* value.refs might be NULL */

			    /*
			     * If the array is large, we allocated it in its
			     * own object (at least originally -- this might
			     * be a pointer to a subarray.)  In this case,
			     * we know it is the only object in its
			     * containing st_refs object, so we know that
			     * the mark containing the relocation appears
			     * just after it.
			     */
			    if (size < max_size_st_refs / sizeof(ref)) {
				rputc('a');
				SET_RELOC(pref->value.refs,
				    (ref *) igc_reloc_ref_ptr(
				     (ref_packed *) pref->value.refs, gcst));
			    } else {
				rputc('A');
				/*
				 * See the t_shortarray case below for why we
				 * decrement size.
				 */
				--size;
				SET_RELOC(pref->value.refs,
				    (ref *) igc_reloc_ref_ptr(
				   (ref_packed *) (pref->value.refs + size),
							       gcst) - size);
			    }
			}
		    }
		    break;
		case t_mixedarray:
		    if (r_size(pref) != 0) {	/* value.refs might be NULL */
			rputc('m');
			SET_RELOC(pref->value.packed,
				  igc_reloc_ref_ptr(pref->value.packed, gcst));
		    }
		    break;
		case t_shortarray:
		    {
			uint size = r_size(pref);

			/*
			 * Since we know that igc_reloc_ref_ptr works by
			 * scanning forward, and we know that all the
			 * elements of this array itself are marked, we can
			 * save some scanning time by relocating the pointer
			 * to the end of the array rather than the
			 * beginning.
			 */
			if (size != 0) {	/* value.refs might be NULL */
			    rputc('s');
			    /*
			     * igc_reloc_ref_ptr has to be able to determine
			     * whether the pointer points into a space that
			     * isn't being collected.  It does this by
			     * checking whether the referent of the pointer
			     * is marked.  For this reason, we have to pass
			     * a pointer to the last real element of the
			     * array, rather than just beyond it.
			     */
			    --size;
			    SET_RELOC(pref->value.packed,
				igc_reloc_ref_ptr(pref->value.packed + size,
						  gcst) - size);
			}
		    }
		    break;
		case t_name:
		    {
			void *psub = name_ref_sub_table(cmem, pref);
			void *rsub = RELOC_OBJ(psub); /* gcst implicit */

			SET_RELOC(pref->value.pname,
				  (name *)
				  ((char *)rsub + ((char *)pref->value.pname -
						   (char *)psub)));
		    } break;
		case t_string:
		    {
			gs_string str;

			str.data = pref->value.bytes;
			str.size = r_size(pref);

			DO_RELOC(str.data, RELOC_STRING_VAR(str));
			pref->value.bytes = str.data;
		    }
		    break;
		case t_oparray:
		    rputc('o');
		    SET_RELOC(pref->value.const_refs,
			(const ref *)igc_reloc_ref_ptr((const ref_packed *)pref->value.const_refs, gcst));
		    break;
		default:
		    goto no_reloc; /* don't print trace message */
	    }
	    if_debug2('8', "  [8]relocated 0x%lx => 0x%lx\n",
		      (ulong)before, (ulong)after);
	}
no_reloc:
	rp += packed_per_ref;
    }
}
Пример #13
0
/* Set the relocation for a ref object. */
static bool
refs_set_reloc(obj_header_t * hdr, uint reloc, uint size)
{
    ref_packed *rp = (ref_packed *) (hdr + 1);
    ref_packed *end = (ref_packed *) ((byte *) rp + size);
    uint freed = 0;

    /*
     * We have to be careful to keep refs aligned properly.
     * For the moment, we do this by either keeping or discarding
     * an entire (aligned) block of align_packed_per_ref packed elements
     * as a unit.  We know that align_packed_per_ref <= packed_per_ref,
     * and we also know that packed refs are always allocated in blocks
     * of align_packed_per_ref, so this makes things relatively easy.
     */
    while (rp < end) {
	if (r_is_packed(rp)) {
#if align_packed_per_ref == 1
	    if (r_has_pmark(rp)) {
		if_debug1('8',
			  "  [8]packed ref 0x%lx is marked\n",
			  (ulong) rp);
		rp++;
	    } else {
#else
	    int i;

	    /*
	     * Note: align_packed_per_ref is typically
	     * 2 or 4 for 32-bit processors.
	     */
#define all_marked (align_packed_per_ref * lp_mark)
# if align_packed_per_ref == 2
#  if arch_sizeof_int == arch_sizeof_short * 2
#    undef all_marked
#    define all_marked ( (lp_mark << (sizeof(short) * 8)) + lp_mark )
#    define marked (*(int *)rp & all_marked)
#  else
#    define marked ((*rp & lp_mark) + (rp[1] & lp_mark))
#  endif
# else
#  if align_packed_per_ref == 4
#    define marked ((*rp & lp_mark) + (rp[1] & lp_mark) +\
		    (rp[2] & lp_mark) + (rp[3] & lp_mark))
#  else
	    /*
	     * The value of marked is logically a uint, not an int:
	     * we declare it as int only to avoid a compiler warning
	     * message about using a non-int value in a switch statement.
	     */
	    int marked = *rp & lp_mark;

	    for (i = 1; i < align_packed_per_ref; i++)
		marked += rp[i] & lp_mark;
#  endif
# endif
	    /*
	     * Now marked is lp_mark * the number of marked
	     * packed refs in the aligned block, except for
	     * a couple of special cases above.
	     */
	    switch (marked) {
		case all_marked:
		    if_debug2('8',
			      "  [8]packed refs 0x%lx..0x%lx are marked\n",
			      (ulong) rp,
			      (ulong) (rp + (align_packed_per_ref - 1)));
		    rp += align_packed_per_ref;
		    break;
		default:
		    /* At least one packed ref in the block */
		    /* is marked: Keep the whole block. */
		    for (i = align_packed_per_ref; i--; rp++) {
			r_set_pmark(rp);
			if_debug1('8',
				  "  [8]packed ref 0x%lx is marked\n",
				  (ulong) rp);
		    }
		    break;
		case 0:
#endif
		    if_debug2('8', "  [8]%d packed ref(s) at 0x%lx are unmarked\n",
			      align_packed_per_ref, (ulong) rp);
		    {
			uint rel = reloc + freed;

			/* Change this to an integer so we can */
			/* store the relocation here. */
			*rp = pt_tag(pt_integer) +
			    min(rel, packed_max_value);
		    }
		    rp += align_packed_per_ref;
		    freed += sizeof(ref_packed) * align_packed_per_ref;
	    }
	} else {		/* full-size ref */
	    uint rel = reloc + freed;

	    /* The following assignment is logically */
	    /* unnecessary; we do it only for convenience */
	    /* in debugging. */
	    ref *pref = (ref *) rp;

	    if (!r_has_attr(pref, l_mark)) {
		if_debug1('8', "  [8]ref 0x%lx is unmarked\n",
			  (ulong) pref);
		/* Change this to a mark so we can */
		/* store the relocation. */
		r_set_type(pref, t_mark);
		r_set_size(pref, rel);
		freed += sizeof(ref);
	    } else {
		if_debug1('8', "  [8]ref 0x%lx is marked\n",
			  (ulong) pref);
		/* Store the relocation here if possible. */
		if (!ref_type_uses_size_or_null(r_type(pref))) {
		    if_debug2('8', "  [8]storing reloc %u at 0x%lx\n",
			      rel, (ulong) pref);
		    r_set_size(pref, rel);
		}
	    }
	    rp += packed_per_ref;
	}
    }
    if_debug3('7', " [7]at end of refs 0x%lx, size = %u, freed = %u\n",
	      (ulong) (hdr + 1), size, freed);
    if (freed == size)
	return false;
#if arch_sizeof_int > arch_sizeof_short
    /*
     * If the final relocation can't fit in the r_size field
     * (which can't happen if the object shares a chunk with
     * any other objects, so we know reloc = 0 in this case),
     * we have to keep the entire object unless there are no
     * references to any ref in it.
     */
    if (freed <= max_ushort)
	return true;
    /*
     * We have to mark all surviving refs, but we also must
     * overwrite any non-surviving refs with something that
     * doesn't contain any pointers.
     */
    rp = (ref_packed *) (hdr + 1);
    while (rp < end) {
	if (r_is_packed(rp)) {
	    if (!r_has_pmark(rp))
		*rp = pt_tag(pt_integer) | lp_mark;
	    ++rp;
	} else {		/* The following assignment is logically */
	    /* unnecessary; we do it only for convenience */
	    /* in debugging. */
	    ref *pref = (ref *) rp;

	    if (!r_has_attr(pref, l_mark)) {
		r_set_type_attrs(pref, t_mark, l_mark);
		r_set_size(pref, reloc);
	    } else {
		if (!ref_type_uses_size_or_null(r_type(pref)))
		    r_set_size(pref, reloc);
	    }
	    rp += packed_per_ref;
	}
    }
    /* The last ref has to remain unmarked. */
    r_clear_attrs((ref *) rp - 1, l_mark);
#endif
    return true;
}