Coverage Report

Created: 2022-04-16 11:23

/src/ghostpdl/psi/zpacked.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 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.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, 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
2.73k
{
34
2.73k
    os_ptr op = osp;
35
36
2.73k
    push(1);
37
2.73k
    ref_assign(op, &ref_array_packing);
38
2.73k
    return 0;
39
2.73k
}
40
41
/* <obj_0> ... <obj_n-1> <n> packedarray <packedarray> */
42
int
43
zpackedarray(i_ctx_t *i_ctx_p)
44
47.1k
{
45
47.1k
    os_ptr op = osp;
46
47.1k
    int code;
47
47.1k
    ref parr;
48
49
47.1k
    check_type(*op, t_integer);
50
47.1k
    if (op->value.intval < 0)
51
0
        return_error(gs_error_rangecheck);
52
47.1k
    if (op->value.intval > op - osbot &&
53
47.1k
        op->value.intval >= ref_stack_count(&o_stack)
54
47.1k
        )
55
0
        return_error(gs_error_stackunderflow);
56
47.1k
    osp--;
57
47.1k
    code = make_packed_array(&parr, &o_stack, (uint) op->value.intval,
58
47.1k
                             idmemory, "packedarray");
59
47.1k
    osp++;
60
47.1k
    if (code >= 0)
61
47.1k
        *osp = parr;
62
47.1k
    return code;
63
47.1k
}
64
65
/* <bool> setpacking - */
66
static int
67
zsetpacking(i_ctx_t *i_ctx_p)
68
6.83k
{
69
6.83k
    os_ptr op = osp;
70
6.83k
    ref cont;
71
6.83k
    check_type(*op, t_boolean);
72
6.83k
    make_struct(&cont, avm_local, ref_array_packing_container);
73
6.83k
    ref_assign_old(&cont, &ref_array_packing, op, "setpacking");
74
6.83k
    pop(1);
75
6.83k
    return 0;
76
6.83k
}
77
78
/* ------ Non-operator routines ------ */
79
80
/* Make a packed array.  See the comment in packed.h about */
81
/* ensuring that refs in mixed arrays are properly aligned. */
82
#undef idmemory     /****** NOTA BENE ******/
83
int
84
make_packed_array(ref * parr, ref_stack_t * pstack, uint size,
85
                  gs_dual_memory_t *idmemory, client_name_t cname)
86
6.30M
{
87
6.30M
    uint i;
88
6.30M
    const ref *pref;
89
6.30M
    uint idest = 0, ishort = 0;
90
6.30M
    ref_packed *pbody;
91
6.30M
    ref_packed *pdest;
92
6.30M
    ref_packed *pshort;   /* points to start of */
93
                                /* last run of short elements */
94
6.30M
    gs_ref_memory_t *imem = idmemory->current;
95
6.30M
    uint space = imemory_space(imem);
96
6.30M
    int skip = 0, pad;
97
6.30M
    ref rtemp;
98
6.30M
    int code;
99
100
    /* Do a first pass to calculate the size of the array, */
101
    /* and to detect local-into-global stores. */
102
103
54.5M
    for (i = size; i != 0; i--) {
104
48.2M
        pref = ref_stack_index(pstack, i - 1);
105
48.2M
        switch (r_btype(pref)) { /* not r_type, opers are special */
106
34.2M
            case t_name:
107
34.2M
              if (name_index(imem, pref) >= packed_name_max_index)
108
4.92M
                    break;  /* can't pack */
109
29.3M
                idest++;
110
29.3M
                continue;
111
6.12M
            case t_integer:
112
6.12M
                if (pref->value.intval < packed_min_intval ||
113
6.12M
                    pref->value.intval > packed_max_intval
114
6.12M
                    )
115
90.8k
                    break;
116
6.03M
                idest++;
117
6.03M
                continue;
118
28.6k
            case t_oparray:
119
                /* Check for local-into-global store. */
120
28.6k
                store_check_space(space, pref);
121
                /* falls through */
122
95.6k
            case t_operator:
123
95.6k
                {
124
95.6k
                    uint oidx;
125
126
95.6k
                    if (!r_has_attr(pref, a_executable))
127
0
                        break;
128
95.6k
                    oidx = op_index(pref);
129
95.6k
                    if (oidx == 0 || oidx > packed_int_mask)
130
0
                        break;
131
95.6k
                }
132
95.6k
                idest++;
133
95.6k
                continue;
134
7.75M
            default:
135
                /* Check for local-into-global store. */
136
7.75M
                store_check_space(space, pref);
137
48.2M
        }
138
        /* Can't pack this element, use a full ref. */
139
        /* We may have to unpack up to align_packed_per_ref - 1 */
140
        /* preceding short elements. */
141
        /* If we are at the beginning of the array, however, */
142
        /* we can just move the elements up. */
143
12.7M
        {
144
12.7M
            int i = (idest - ishort) & (align_packed_per_ref - 1);
145
146
12.7M
            if (ishort == 0)  /* first time */
147
4.45M
                idest += skip = -i & (align_packed_per_ref - 1);
148
8.32M
            else
149
8.32M
                idest += (packed_per_ref - 1) * i;
150
12.7M
        }
151
12.7M
        ishort = idest += packed_per_ref;
152
12.7M
    }
153
6.30M
    pad = (packed_per_ref - idest % packed_per_ref) % packed_per_ref; /* padding at end */
154
155
    /* Now we can allocate the array. */
156
157
6.30M
    code = gs_alloc_ref_array(imem, &rtemp, 0, (idest + pad) / packed_per_ref,
158
6.30M
                              cname);
159
6.30M
    if (code < 0)
160
0
        return code;
161
6.30M
    pbody = (ref_packed *) rtemp.value.refs;
162
163
    /* Make sure any initial skipped elements contain legal packed */
164
    /* refs, so that the garbage collector can scan storage. */
165
166
6.30M
    pshort = pbody;
167
11.3M
    for (; skip; skip--)
168
5.04M
        *pbody++ = pt_tag(pt_integer);
169
6.30M
    pdest = pbody;
170
171
54.5M
    for (i = size; i != 0; i--) {
172
48.2M
        pref = ref_stack_index(pstack, i - 1);
173
48.2M
        switch (r_btype(pref)) { /* not r_type, opers are special */
174
34.2M
            case t_name:
175
34.2M
                {
176
34.2M
                    uint nidx = name_index(imem, pref);
177
178
34.2M
                    if (nidx >= packed_name_max_index)
179
4.92M
                        break;  /* can't pack */
180
29.3M
                    *pdest++ = nidx +
181
29.3M
                        (r_has_attr(pref, a_executable) ?
182
25.6M
                         pt_tag(pt_executable_name) :
183
29.3M
                         pt_tag(pt_literal_name));
184
29.3M
                }
185
0
                continue;
186
6.12M
            case t_integer:
187
6.12M
                if (pref->value.intval < packed_min_intval ||
188
6.12M
                    pref->value.intval > packed_max_intval
189
6.12M
                    )
190
90.8k
                    break;
191
6.03M
                *pdest++ = pt_tag(pt_integer) +
192
6.03M
                    ((short)pref->value.intval - packed_min_intval);
193
6.03M
                continue;
194
28.6k
            case t_oparray:
195
95.6k
            case t_operator:
196
95.6k
                {
197
95.6k
                    uint oidx;
198
199
95.6k
                    if (!r_has_attr(pref, a_executable))
200
0
                        break;
201
95.6k
                    oidx = op_index(pref);
202
95.6k
                    if (oidx == 0 || oidx > packed_int_mask)
203
0
                        break;
204
95.6k
                    *pdest++ = pt_tag(pt_executable_operator) + oidx;
205
95.6k
                }
206
0
                continue;
207
48.2M
        }
208
        /* Can't pack this element, use a full ref. */
209
        /* We may have to unpack up to align_packed_per_ref - 1 */
210
        /* preceding short elements. */
211
        /* Note that if we are at the beginning of the array, */
212
        /* 'skip' already ensures that we don't need to do this. */
213
12.7M
        {
214
12.7M
            int i = (pdest - pshort) & (align_packed_per_ref - 1);
215
12.7M
            const ref_packed *psrc = pdest;
216
12.7M
            ref *pmove =
217
12.7M
            (ref *) (pdest += (packed_per_ref - 1) * i);
218
219
12.7M
            ref_assign_new(pmove, pref);
220
19.5M
            while (--i >= 0) {
221
6.79M
                --psrc;
222
6.79M
                --pmove;
223
6.79M
                packed_get(imem->non_gc_memory, psrc, pmove);
224
6.79M
            }
225
12.7M
        }
226
12.7M
        pshort = pdest += packed_per_ref;
227
12.7M
    }
228
229
6.30M
    {
230
6.30M
        int atype =
231
6.30M
        (pdest == pbody + size ? t_shortarray : t_mixedarray);
232
233
        /* Pad with legal packed refs so that the garbage collector */
234
        /* can scan storage. */
235
236
32.6M
        for (; pad; pad--)
237
26.2M
            *pdest++ = pt_tag(pt_integer);
238
239
        /* Finally, make the array. */
240
241
6.30M
        ref_stack_pop(pstack, size);
242
6.30M
        make_tasv_new(parr, atype, a_readonly | space, size,
243
6.30M
                      packed, pbody + skip);
244
6.30M
    }
245
6.30M
    return 0;
246
6.30M
}
247
248
/* ------ Initialization procedure ------ */
249
250
const op_def zpacked_op_defs[] =
251
{
252
    {"0currentpacking", zcurrentpacking},
253
    {"1packedarray", zpackedarray},
254
    {"1setpacking", zsetpacking},
255
    op_def_end(0)
256
};