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