Coverage Report

Created: 2025-06-10 07:06

/src/ghostpdl/psi/zpacked.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2024 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Packed array operators */
18
#include "ghost.h"
19
#include "ialloc.h"
20
#include "idict.h"
21
#include "iname.h"
22
#include "istack.h"   /* for iparray.h */
23
#include "ipacked.h"
24
#include "iparray.h"
25
#include "ivmspace.h"
26
#include "oper.h"
27
#include "store.h"
28
#include "gxalloc.h"
29
30
/* - currentpacking <bool> */
31
static int
32
zcurrentpacking(i_ctx_t *i_ctx_p)
33
37.2k
{
34
37.2k
    os_ptr op = osp;
35
36
37.2k
    push(1);
37
37.2k
    ref_assign(op, &ref_array_packing);
38
37.2k
    return 0;
39
37.2k
}
40
41
/* <obj_0> ... <obj_n-1> <n> packedarray <packedarray> */
42
int
43
zpackedarray(i_ctx_t *i_ctx_p)
44
635k
{
45
635k
    os_ptr op = osp;
46
635k
    int code;
47
635k
    ref parr;
48
49
635k
    check_type(*op, t_integer);
50
51
    /* This avoids a valgrind error */
52
635k
    parr.tas.type_attrs = 0;
53
54
635k
    if (op->value.intval < 0)
55
0
        return_error(gs_error_rangecheck);
56
635k
    if (op->value.intval > op - osbot &&
57
635k
        op->value.intval >= ref_stack_count(&o_stack)
58
635k
        )
59
0
        return_error(gs_error_stackunderflow);
60
635k
    osp--;
61
635k
    code = make_packed_array(&parr, &o_stack, (uint) op->value.intval,
62
635k
                             idmemory, "packedarray");
63
635k
    osp++;
64
635k
    if (code >= 0)
65
635k
        *osp = parr;
66
635k
    return code;
67
635k
}
68
69
/* <bool> setpacking - */
70
static int
71
zsetpacking(i_ctx_t *i_ctx_p)
72
92.1k
{
73
92.1k
    os_ptr op = osp;
74
92.1k
    ref cont;
75
92.1k
    check_op(1);
76
92.1k
    check_type(*op, t_boolean);
77
92.1k
    make_struct(&cont, avm_local, ref_array_packing_container);
78
92.1k
    ref_assign_old(&cont, &ref_array_packing, op, "setpacking");
79
92.1k
    pop(1);
80
92.1k
    return 0;
81
92.1k
}
82
83
/* ------ Non-operator routines ------ */
84
85
/* Make a packed array.  See the comment in packed.h about */
86
/* ensuring that refs in mixed arrays are properly aligned. */
87
#undef idmemory     /****** NOTA BENE ******/
88
int
89
make_packed_array(ref * parr, ref_stack_t * pstack, uint size,
90
                  gs_dual_memory_t *idmemory, client_name_t cname)
91
43.1M
{
92
43.1M
    uint i;
93
43.1M
    const ref *pref;
94
43.1M
    uint idest = 0, ishort = 0;
95
43.1M
    ref_packed *pbody;
96
43.1M
    ref_packed *pdest;
97
43.1M
    ref_packed *pshort;   /* points to start of */
98
                                /* last run of short elements */
99
43.1M
    gs_ref_memory_t *imem = idmemory->current;
100
43.1M
    uint space = imemory_space(imem);
101
43.1M
    int skip = 0, pad;
102
43.1M
    ref rtemp;
103
43.1M
    int code;
104
105
    /* Do a first pass to calculate the size of the array, */
106
    /* and to detect local-into-global stores. */
107
108
377M
    for (i = size; i != 0; i--) {
109
334M
        pref = ref_stack_index(pstack, i - 1);
110
334M
        if (pref == NULL)
111
0
            return_error(gs_error_stackunderflow);
112
113
334M
        switch (r_btype(pref)) { /* not r_type, opers are special */
114
241M
            case t_name:
115
241M
              if (name_index(imem, pref) >= packed_name_max_index)
116
22.0M
                    break;  /* can't pack */
117
219M
                idest++;
118
219M
                continue;
119
40.5M
            case t_integer:
120
40.5M
                if (pref->value.intval < packed_min_intval ||
121
40.5M
                    pref->value.intval > packed_max_intval
122
40.5M
                    )
123
856k
                    break;
124
39.6M
                idest++;
125
39.6M
                continue;
126
386k
            case t_oparray:
127
                /* Check for local-into-global store. */
128
386k
                store_check_space(space, pref);
129
                /* falls through */
130
1.28M
            case t_operator:
131
1.28M
                {
132
1.28M
                    uint oidx;
133
134
1.28M
                    if (!r_has_attr(pref, a_executable))
135
0
                        break;
136
1.28M
                    oidx = op_index(pref);
137
1.28M
                    if (oidx == 0 || oidx > packed_int_mask)
138
0
                        break;
139
1.28M
                }
140
1.28M
                idest++;
141
1.28M
                continue;
142
51.2M
            default:
143
                /* Check for local-into-global store. */
144
51.2M
                store_check_space(space, pref);
145
334M
        }
146
        /* Can't pack this element, use a full ref. */
147
        /* We may have to unpack up to align_packed_per_ref - 1 */
148
        /* preceding short elements. */
149
        /* If we are at the beginning of the array, however, */
150
        /* we can just move the elements up. */
151
74.1M
        {
152
74.1M
            int i = (idest - ishort) & (align_packed_per_ref - 1);
153
154
74.1M
            if (ishort == 0)  /* first time */
155
28.6M
                idest += skip = -i & (align_packed_per_ref - 1);
156
45.5M
            else
157
45.5M
                idest += (packed_per_ref - 1) * i;
158
74.1M
        }
159
74.1M
        ishort = idest += packed_per_ref;
160
74.1M
    }
161
43.1M
    pad = (packed_per_ref - idest % packed_per_ref) % packed_per_ref; /* padding at end */
162
163
    /* Now we can allocate the array. */
164
165
43.1M
    code = gs_alloc_ref_array(imem, &rtemp, 0, (idest + pad) / packed_per_ref,
166
43.1M
                              cname);
167
43.1M
    if (code < 0)
168
0
        return code;
169
43.1M
    pbody = (ref_packed *) rtemp.value.refs;
170
171
    /* Make sure any initial skipped elements contain legal packed */
172
    /* refs, so that the garbage collector can scan storage. */
173
174
43.1M
    pshort = pbody;
175
76.7M
    for (; skip; skip--)
176
33.6M
        *pbody++ = pt_tag(pt_integer);
177
43.1M
    pdest = pbody;
178
179
377M
    for (i = size; i != 0; i--) {
180
334M
        pref = ref_stack_index(pstack, i - 1);
181
334M
        if (pref == NULL)
182
0
            return_error(gs_error_stackunderflow);
183
184
334M
        switch (r_btype(pref)) { /* not r_type, opers are special */
185
241M
            case t_name:
186
241M
                {
187
241M
                    uint nidx = name_index(imem, pref);
188
189
241M
                    if (nidx >= packed_name_max_index)
190
22.0M
                        break;  /* can't pack */
191
219M
                    *pdest++ = nidx +
192
219M
                        (r_has_attr(pref, a_executable) ?
193
178M
                         pt_tag(pt_executable_name) :
194
219M
                         pt_tag(pt_literal_name));
195
219M
                }
196
0
                continue;
197
40.5M
            case t_integer:
198
40.5M
                if (pref->value.intval < packed_min_intval ||
199
40.5M
                    pref->value.intval > packed_max_intval
200
40.5M
                    )
201
856k
                    break;
202
39.6M
                *pdest++ = pt_tag(pt_integer) +
203
39.6M
                    ((short)pref->value.intval - packed_min_intval);
204
39.6M
                continue;
205
386k
            case t_oparray:
206
1.28M
            case t_operator:
207
1.28M
                {
208
1.28M
                    uint oidx;
209
210
1.28M
                    if (!r_has_attr(pref, a_executable))
211
0
                        break;
212
1.28M
                    oidx = op_index(pref);
213
1.28M
                    if (oidx == 0 || oidx > packed_int_mask)
214
0
                        break;
215
1.28M
                    *pdest++ = pt_tag(pt_executable_operator) + oidx;
216
1.28M
                }
217
0
                continue;
218
334M
        }
219
        /* Can't pack this element, use a full ref. */
220
        /* We may have to unpack up to align_packed_per_ref - 1 */
221
        /* preceding short elements. */
222
        /* Note that if we are at the beginning of the array, */
223
        /* 'skip' already ensures that we don't need to do this. */
224
74.1M
        {
225
74.1M
            int i = (pdest - pshort) & (align_packed_per_ref - 1);
226
74.1M
            const ref_packed *psrc = pdest;
227
74.1M
            ref *pmove =
228
74.1M
            (ref *) (pdest += (packed_per_ref - 1) * i);
229
230
74.1M
            ref_assign_new(pmove, pref);
231
116M
            while (--i >= 0) {
232
42.7M
                --psrc;
233
42.7M
                --pmove;
234
42.7M
                packed_get(imem->non_gc_memory, psrc, pmove);
235
42.7M
            }
236
74.1M
        }
237
74.1M
        pshort = pdest += packed_per_ref;
238
74.1M
    }
239
240
43.1M
    {
241
43.1M
        int atype =
242
43.1M
        (pdest == pbody + size ? t_shortarray : t_mixedarray);
243
244
        /* Pad with legal packed refs so that the garbage collector */
245
        /* can scan storage. */
246
247
221M
        for (; pad; pad--)
248
178M
            *pdest++ = pt_tag(pt_integer);
249
250
        /* Finally, make the array. */
251
252
43.1M
        ref_stack_pop(pstack, size);
253
43.1M
        make_tasv_new(parr, atype, a_readonly | space, size,
254
43.1M
                      packed, pbody + skip);
255
43.1M
    }
256
43.1M
    return 0;
257
43.1M
}
258
259
/* ------ Initialization procedure ------ */
260
261
const op_def zpacked_op_defs[] =
262
{
263
    {"0currentpacking", zcurrentpacking},
264
    {"1packedarray", zpackedarray},
265
    {"1setpacking", zsetpacking},
266
    op_def_end(0)
267
};