xref: /plan9/sys/src/cmd/gs/src/zpacked.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1990, 1992, 1993, 1999 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: zpacked.c,v 1.7 2004/08/19 19:33:09 stefan Exp $ */
187dd7cddfSDavid du Colombier /* Packed array operators */
197dd7cddfSDavid du Colombier #include "ghost.h"
207dd7cddfSDavid du Colombier #include "ialloc.h"
217dd7cddfSDavid du Colombier #include "idict.h"
227dd7cddfSDavid du Colombier #include "iname.h"
237dd7cddfSDavid du Colombier #include "istack.h"		/* for iparray.h */
247dd7cddfSDavid du Colombier #include "ipacked.h"
257dd7cddfSDavid du Colombier #include "iparray.h"
267dd7cddfSDavid du Colombier #include "ivmspace.h"
277dd7cddfSDavid du Colombier #include "oper.h"
287dd7cddfSDavid du Colombier #include "store.h"
29*593dc095SDavid du Colombier #include "gxalloc.h"
307dd7cddfSDavid du Colombier 
317dd7cddfSDavid du Colombier /* - currentpacking <bool> */
327dd7cddfSDavid du Colombier private int
zcurrentpacking(i_ctx_t * i_ctx_p)337dd7cddfSDavid du Colombier zcurrentpacking(i_ctx_t *i_ctx_p)
347dd7cddfSDavid du Colombier {
357dd7cddfSDavid du Colombier     os_ptr op = osp;
367dd7cddfSDavid du Colombier 
377dd7cddfSDavid du Colombier     push(1);
387dd7cddfSDavid du Colombier     ref_assign(op, &ref_array_packing);
397dd7cddfSDavid du Colombier     return 0;
407dd7cddfSDavid du Colombier }
417dd7cddfSDavid du Colombier 
427dd7cddfSDavid du Colombier /* <obj_0> ... <obj_n-1> <n> packedarray <packedarray> */
437dd7cddfSDavid du Colombier int
zpackedarray(i_ctx_t * i_ctx_p)447dd7cddfSDavid du Colombier zpackedarray(i_ctx_t *i_ctx_p)
457dd7cddfSDavid du Colombier {
467dd7cddfSDavid du Colombier     os_ptr op = osp;
477dd7cddfSDavid du Colombier     int code;
487dd7cddfSDavid du Colombier     ref parr;
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier     check_type(*op, t_integer);
517dd7cddfSDavid du Colombier     if (op->value.intval < 0 ||
527dd7cddfSDavid du Colombier 	(op->value.intval > op - osbot &&
537dd7cddfSDavid du Colombier 	 op->value.intval >= ref_stack_count(&o_stack))
547dd7cddfSDavid du Colombier 	)
557dd7cddfSDavid du Colombier 	return_error(e_rangecheck);
567dd7cddfSDavid du Colombier     osp--;
577dd7cddfSDavid du Colombier     code = make_packed_array(&parr, &o_stack, (uint) op->value.intval,
587dd7cddfSDavid du Colombier 			     idmemory, "packedarray");
597dd7cddfSDavid du Colombier     osp++;
607dd7cddfSDavid du Colombier     if (code >= 0)
617dd7cddfSDavid du Colombier 	*osp = parr;
627dd7cddfSDavid du Colombier     return code;
637dd7cddfSDavid du Colombier }
647dd7cddfSDavid du Colombier 
657dd7cddfSDavid du Colombier /* <bool> setpacking - */
667dd7cddfSDavid du Colombier private int
zsetpacking(i_ctx_t * i_ctx_p)677dd7cddfSDavid du Colombier zsetpacking(i_ctx_t *i_ctx_p)
687dd7cddfSDavid du Colombier {
697dd7cddfSDavid du Colombier     os_ptr op = osp;
707dd7cddfSDavid du Colombier     ref cont;
717dd7cddfSDavid du Colombier 
727dd7cddfSDavid du Colombier     check_type(*op, t_boolean);
737dd7cddfSDavid du Colombier     make_struct(&cont, avm_local, ref_array_packing_container);
747dd7cddfSDavid du Colombier     ref_assign_old(&cont, &ref_array_packing, op, "setpacking");
757dd7cddfSDavid du Colombier     pop(1);
767dd7cddfSDavid du Colombier     return 0;
777dd7cddfSDavid du Colombier }
787dd7cddfSDavid du Colombier 
797dd7cddfSDavid du Colombier /* ------ Non-operator routines ------ */
807dd7cddfSDavid du Colombier 
817dd7cddfSDavid du Colombier /* Make a packed array.  See the comment in packed.h about */
827dd7cddfSDavid du Colombier /* ensuring that refs in mixed arrays are properly aligned. */
837dd7cddfSDavid du Colombier #undef idmemory			/****** NOTA BENE ******/
847dd7cddfSDavid du Colombier int
make_packed_array(ref * parr,ref_stack_t * pstack,uint size,gs_dual_memory_t * idmemory,client_name_t cname)857dd7cddfSDavid du Colombier make_packed_array(ref * parr, ref_stack_t * pstack, uint size,
867dd7cddfSDavid du Colombier 		  gs_dual_memory_t *idmemory, client_name_t cname)
877dd7cddfSDavid du Colombier {
887dd7cddfSDavid du Colombier     uint i;
897dd7cddfSDavid du Colombier     const ref *pref;
907dd7cddfSDavid du Colombier     uint idest = 0, ishort = 0;
917dd7cddfSDavid du Colombier     ref_packed *pbody;
927dd7cddfSDavid du Colombier     ref_packed *pdest;
937dd7cddfSDavid du Colombier     ref_packed *pshort;		/* points to start of */
947dd7cddfSDavid du Colombier 				/* last run of short elements */
957dd7cddfSDavid du Colombier     gs_ref_memory_t *imem = idmemory->current;
967dd7cddfSDavid du Colombier     uint space = imemory_space(imem);
977dd7cddfSDavid du Colombier     int skip = 0, pad;
987dd7cddfSDavid du Colombier     ref rtemp;
997dd7cddfSDavid du Colombier     int code;
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier     /* Do a first pass to calculate the size of the array, */
1027dd7cddfSDavid du Colombier     /* and to detect local-into-global stores. */
1037dd7cddfSDavid du Colombier 
1047dd7cddfSDavid du Colombier     for (i = size; i != 0; i--) {
1057dd7cddfSDavid du Colombier 	pref = ref_stack_index(pstack, i - 1);
1067dd7cddfSDavid du Colombier 	switch (r_btype(pref)) {	/* not r_type, opers are special */
1077dd7cddfSDavid du Colombier 	    case t_name:
108*593dc095SDavid du Colombier 	      if (name_index(imem, pref) >= packed_name_max_index)
1097dd7cddfSDavid du Colombier 		    break;	/* can't pack */
1107dd7cddfSDavid du Colombier 		idest++;
1117dd7cddfSDavid du Colombier 		continue;
1127dd7cddfSDavid du Colombier 	    case t_integer:
1137dd7cddfSDavid du Colombier 		if (pref->value.intval < packed_min_intval ||
1147dd7cddfSDavid du Colombier 		    pref->value.intval > packed_max_intval
1157dd7cddfSDavid du Colombier 		    )
1167dd7cddfSDavid du Colombier 		    break;
1177dd7cddfSDavid du Colombier 		idest++;
1187dd7cddfSDavid du Colombier 		continue;
1197dd7cddfSDavid du Colombier 	    case t_oparray:
1207dd7cddfSDavid du Colombier 		/* Check for local-into-global store. */
1217dd7cddfSDavid du Colombier 		store_check_space(space, pref);
1227dd7cddfSDavid du Colombier 		/* falls through */
1237dd7cddfSDavid du Colombier 	    case t_operator:
1247dd7cddfSDavid du Colombier 		{
1257dd7cddfSDavid du Colombier 		    uint oidx;
1267dd7cddfSDavid du Colombier 
1277dd7cddfSDavid du Colombier 		    if (!r_has_attr(pref, a_executable))
1287dd7cddfSDavid du Colombier 			break;
1297dd7cddfSDavid du Colombier 		    oidx = op_index(pref);
1307dd7cddfSDavid du Colombier 		    if (oidx == 0 || oidx > packed_int_mask)
1317dd7cddfSDavid du Colombier 			break;
1327dd7cddfSDavid du Colombier 		}
1337dd7cddfSDavid du Colombier 		idest++;
1347dd7cddfSDavid du Colombier 		continue;
1357dd7cddfSDavid du Colombier 	    default:
1367dd7cddfSDavid du Colombier 		/* Check for local-into-global store. */
1377dd7cddfSDavid du Colombier 		store_check_space(space, pref);
1387dd7cddfSDavid du Colombier 	}
1397dd7cddfSDavid du Colombier 	/* Can't pack this element, use a full ref. */
1407dd7cddfSDavid du Colombier 	/* We may have to unpack up to align_packed_per_ref - 1 */
1417dd7cddfSDavid du Colombier 	/* preceding short elements. */
1427dd7cddfSDavid du Colombier 	/* If we are at the beginning of the array, however, */
1437dd7cddfSDavid du Colombier 	/* we can just move the elements up. */
1447dd7cddfSDavid du Colombier 	{
1457dd7cddfSDavid du Colombier 	    int i = (idest - ishort) & (align_packed_per_ref - 1);
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier 	    if (ishort == 0)	/* first time */
1487dd7cddfSDavid du Colombier 		idest += skip = -i & (align_packed_per_ref - 1);
1497dd7cddfSDavid du Colombier 	    else
1507dd7cddfSDavid du Colombier 		idest += (packed_per_ref - 1) * i;
1517dd7cddfSDavid du Colombier 	}
1527dd7cddfSDavid du Colombier 	ishort = idest += packed_per_ref;
1537dd7cddfSDavid du Colombier     }
154*593dc095SDavid du Colombier     pad = -(int)idest & (packed_per_ref - 1);	/* padding at end */
1557dd7cddfSDavid du Colombier 
1567dd7cddfSDavid du Colombier     /* Now we can allocate the array. */
1577dd7cddfSDavid du Colombier 
1587dd7cddfSDavid du Colombier     code = gs_alloc_ref_array(imem, &rtemp, 0, (idest + pad) / packed_per_ref,
1597dd7cddfSDavid du Colombier 			      cname);
1607dd7cddfSDavid du Colombier     if (code < 0)
1617dd7cddfSDavid du Colombier 	return code;
1627dd7cddfSDavid du Colombier     pbody = (ref_packed *) rtemp.value.refs;
1637dd7cddfSDavid du Colombier 
1647dd7cddfSDavid du Colombier     /* Make sure any initial skipped elements contain legal packed */
1657dd7cddfSDavid du Colombier     /* refs, so that the garbage collector can scan storage. */
1667dd7cddfSDavid du Colombier 
1677dd7cddfSDavid du Colombier     pshort = pbody;
1687dd7cddfSDavid du Colombier     for (; skip; skip--)
1697dd7cddfSDavid du Colombier 	*pbody++ = pt_tag(pt_integer);
1707dd7cddfSDavid du Colombier     pdest = pbody;
1717dd7cddfSDavid du Colombier 
1727dd7cddfSDavid du Colombier     for (i = size; i != 0; i--) {
1737dd7cddfSDavid du Colombier 	pref = ref_stack_index(pstack, i - 1);
1747dd7cddfSDavid du Colombier 	switch (r_btype(pref)) {	/* not r_type, opers are special */
1757dd7cddfSDavid du Colombier 	    case t_name:
1767dd7cddfSDavid du Colombier 		{
177*593dc095SDavid du Colombier 		    uint nidx = name_index(imem, pref);
1787dd7cddfSDavid du Colombier 
1797dd7cddfSDavid du Colombier 		    if (nidx >= packed_name_max_index)
1807dd7cddfSDavid du Colombier 			break;	/* can't pack */
1817dd7cddfSDavid du Colombier 		    *pdest++ = nidx +
1827dd7cddfSDavid du Colombier 			(r_has_attr(pref, a_executable) ?
1837dd7cddfSDavid du Colombier 			 pt_tag(pt_executable_name) :
1847dd7cddfSDavid du Colombier 			 pt_tag(pt_literal_name));
1857dd7cddfSDavid du Colombier 		}
1867dd7cddfSDavid du Colombier 		continue;
1877dd7cddfSDavid du Colombier 	    case t_integer:
1887dd7cddfSDavid du Colombier 		if (pref->value.intval < packed_min_intval ||
1897dd7cddfSDavid du Colombier 		    pref->value.intval > packed_max_intval
1907dd7cddfSDavid du Colombier 		    )
1917dd7cddfSDavid du Colombier 		    break;
1927dd7cddfSDavid du Colombier 		*pdest++ = pt_tag(pt_integer) +
1937dd7cddfSDavid du Colombier 		    ((short)pref->value.intval - packed_min_intval);
1947dd7cddfSDavid du Colombier 		continue;
1957dd7cddfSDavid du Colombier 	    case t_oparray:
1967dd7cddfSDavid du Colombier 	    case t_operator:
1977dd7cddfSDavid du Colombier 		{
1987dd7cddfSDavid du Colombier 		    uint oidx;
1997dd7cddfSDavid du Colombier 
2007dd7cddfSDavid du Colombier 		    if (!r_has_attr(pref, a_executable))
2017dd7cddfSDavid du Colombier 			break;
2027dd7cddfSDavid du Colombier 		    oidx = op_index(pref);
2037dd7cddfSDavid du Colombier 		    if (oidx == 0 || oidx > packed_int_mask)
2047dd7cddfSDavid du Colombier 			break;
2057dd7cddfSDavid du Colombier 		    *pdest++ = pt_tag(pt_executable_operator) + oidx;
2067dd7cddfSDavid du Colombier 		}
2077dd7cddfSDavid du Colombier 		continue;
2087dd7cddfSDavid du Colombier 	}
2097dd7cddfSDavid du Colombier 	/* Can't pack this element, use a full ref. */
2107dd7cddfSDavid du Colombier 	/* We may have to unpack up to align_packed_per_ref - 1 */
2117dd7cddfSDavid du Colombier 	/* preceding short elements. */
2127dd7cddfSDavid du Colombier 	/* Note that if we are at the beginning of the array, */
2137dd7cddfSDavid du Colombier 	/* 'skip' already ensures that we don't need to do this. */
2147dd7cddfSDavid du Colombier 	{
2157dd7cddfSDavid du Colombier 	    int i = (pdest - pshort) & (align_packed_per_ref - 1);
2167dd7cddfSDavid du Colombier 	    const ref_packed *psrc = pdest;
2177dd7cddfSDavid du Colombier 	    ref *pmove =
2187dd7cddfSDavid du Colombier 	    (ref *) (pdest += (packed_per_ref - 1) * i);
2197dd7cddfSDavid du Colombier 
2207dd7cddfSDavid du Colombier 	    ref_assign_new(pmove, pref);
2217dd7cddfSDavid du Colombier 	    while (--i >= 0) {
2227dd7cddfSDavid du Colombier 		--psrc;
2237dd7cddfSDavid du Colombier 		--pmove;
224*593dc095SDavid du Colombier 		packed_get(imem->non_gc_memory, psrc, pmove);
2257dd7cddfSDavid du Colombier 	    }
2267dd7cddfSDavid du Colombier 	}
2277dd7cddfSDavid du Colombier 	pshort = pdest += packed_per_ref;
2287dd7cddfSDavid du Colombier     }
2297dd7cddfSDavid du Colombier 
2307dd7cddfSDavid du Colombier     {
2317dd7cddfSDavid du Colombier 	int atype =
2327dd7cddfSDavid du Colombier 	(pdest == pbody + size ? t_shortarray : t_mixedarray);
2337dd7cddfSDavid du Colombier 
2347dd7cddfSDavid du Colombier 	/* Pad with legal packed refs so that the garbage collector */
2357dd7cddfSDavid du Colombier 	/* can scan storage. */
2367dd7cddfSDavid du Colombier 
2377dd7cddfSDavid du Colombier 	for (; pad; pad--)
2387dd7cddfSDavid du Colombier 	    *pdest++ = pt_tag(pt_integer);
2397dd7cddfSDavid du Colombier 
2407dd7cddfSDavid du Colombier 	/* Finally, make the array. */
2417dd7cddfSDavid du Colombier 
2427dd7cddfSDavid du Colombier 	ref_stack_pop(pstack, size);
2437dd7cddfSDavid du Colombier 	make_tasv_new(parr, atype, a_readonly | space, size,
2447dd7cddfSDavid du Colombier 		      packed, pbody + skip);
2457dd7cddfSDavid du Colombier     }
2467dd7cddfSDavid du Colombier     return 0;
2477dd7cddfSDavid du Colombier }
2487dd7cddfSDavid du Colombier 
2497dd7cddfSDavid du Colombier /* ------ Initialization procedure ------ */
2507dd7cddfSDavid du Colombier 
2517dd7cddfSDavid du Colombier const op_def zpacked_op_defs[] =
2527dd7cddfSDavid du Colombier {
2537dd7cddfSDavid du Colombier     {"0currentpacking", zcurrentpacking},
2547dd7cddfSDavid du Colombier     {"1packedarray", zpackedarray},
2557dd7cddfSDavid du Colombier     {"1setpacking", zsetpacking},
2567dd7cddfSDavid du Colombier     op_def_end(0)
2577dd7cddfSDavid du Colombier };
258