Beispiel #1
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;
}
Beispiel #2
0
/* Append a user path to the current path. */
static inline int
upath_append_aux(os_ptr oppath, i_ctx_t *i_ctx_p, int *pnargs, bool upath_compat)
{
    upath_state ups = UPS_INITIAL;
    ref opcodes;

    if (r_has_type(oppath, t__invalid))
        return_error(e_stackunderflow);
    if (!r_is_array(oppath))
        return_error(e_typecheck);
    check_read(*oppath);
    gs_newpath(igs);
    /****** ROUND tx AND ty ******/

    if ( r_size(oppath) == 2 &&
         array_get(imemory, oppath, 1, &opcodes) >= 0 &&
         r_has_type(&opcodes, t_string)
        ) {			/* 1st element is operands, 2nd is operators */
        ref operands;
        int code, format;
        int repcount = 1;
        const byte *opp;
        uint ocount, i = 0;

        array_get(imemory, oppath, 0, &operands);
        code = num_array_format(&operands);
        if (code < 0)
            return code;
        format = code;
        check_read(opcodes);
        opp = opcodes.value.bytes;
        ocount = r_size(&opcodes);
        while (ocount--) {
            byte opx = *opp++;

            if (opx > UPATH_REPEAT)
                repcount = opx - UPATH_REPEAT;
            else if (opx > UPATH_MAX_OP)
                return_error(e_rangecheck);
            else {		/* operator */
                const up_data_t data = up_data[opx];

                *pnargs = 0;	/* in case of error */
                if (upath_compat && opx == upath_op_ucache) {
                    /* CPSI does not complain about incorrect ucache
                       placement, even though PLRM3 says it's illegal. */
                    ups = ups > UPS_UCACHE ? ups : data.state_after;
                } else {
                    if (!(ups & data.states_before))
                        return_error(e_typecheck);
                    ups = data.state_after;
                }
                do {
                    os_ptr op = osp;
                    byte opargs = data.num_args;

                    while (opargs--) {
                        push(1);
                        (*pnargs)++; /* in case of error */
                        code = num_array_get(imemory, &operands, format, i++, op);
                        switch (code) {
                            case t_integer:
                                r_set_type_attrs(op, t_integer, 0);
                                break;
                            case t_real:
                                r_set_type_attrs(op, t_real, 0);
                                break;
                            default:
                                return_error(e_typecheck);
                        }
                    }
                    code = (*up_ops[opx])(i_ctx_p);
                    if (code < 0)
                        return code;
                }
                while (--repcount);
                repcount = 1;
            }
        }
    } else {	/* Ordinary executable array. */
        const ref *arp = oppath;
        uint ocount = r_size(oppath);
        long index = 0;
        int argcount = 0;
        op_proc_t oproc;
        int opx, code;

        for (; index < ocount; index++) {
            ref rup;
            ref *defp;
            os_ptr op = osp;
            up_data_t data;

            *pnargs = argcount;
            array_get(imemory, arp, index, &rup);
            switch (r_type(&rup)) {
                case t_integer:
                case t_real:
                    argcount++;
                    push(1);
                    *op = rup;
                    break;
                case t_name:
                    if (!r_has_attr(&rup, a_executable) ||
                        dict_find(systemdict, &rup, &defp) <= 0 ||
                        r_btype(defp) != t_operator)
                        return_error(e_typecheck); /* all errors = typecheck */
                    goto xop;
                case t_operator:
                    defp = &rup;
                  xop:if (!r_has_attr(defp, a_executable))
                        return_error(e_typecheck);
                    oproc = real_opproc(defp);
                    for (opx = 0; opx <= UPATH_MAX_OP; opx++)
                        if (oproc == up_ops[opx])
                            break;
                    if (opx > UPATH_MAX_OP)
                        return_error(e_typecheck);
                    data = up_data[opx];
                    if (argcount != data.num_args)
                        return_error(e_typecheck);
                    if (upath_compat && opx == upath_op_ucache) {
                        /* CPSI does not complain about incorrect ucache
                           placement, even though PLRM3 says it's illegal. */
                        ups = ups > UPS_UCACHE ? ups : data.state_after;
                    } else {
                        if (!(ups & data.states_before))
                            return_error(e_typecheck);
                        ups = data.state_after;
                    }
                    code = (*up_ops[opx])(i_ctx_p);
                    if (code < 0) {
                        if (code == e_nocurrentpoint)
                            return_error(e_rangecheck); /* CET 11-22 */
                        return code;
                    }
                    argcount = 0;
                    break;
                default:
                    return_error(e_typecheck);
            }
        }
        if (argcount) {
            *pnargs = argcount;
            return_error(e_typecheck);	/* leftover args */
        }
    }
    if (ups < UPS_SETBBOX)
        return_error(e_typecheck);	/* no setbbox */
    if (ups == UPS_SETBBOX && upath_compat) {
        /*
         * In CPSI compatibility mode, an empty path with a setbbox also
         * does a moveto (but only if the path is empty).  Since setbbox
         * was the last operator, its operands are still on the o-stack.
         */
        osp += 2;
        return zmoveto(i_ctx_p);
    }
    return 0;
}