Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/psi/zgeneric.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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
/* Array/string/dictionary generic operators for PostScript */
18
#include "memory_.h"
19
#include "ghost.h"
20
#include "gsstruct.h"   /* for st_bytes */
21
#include "oper.h"
22
#include "dstack.h"   /* for systemdict */
23
#include "estack.h"   /* for forall */
24
#include "iddict.h"
25
#include "iname.h"
26
#include "ipacked.h"
27
#include "ivmspace.h"
28
#include "store.h"
29
30
/* This file implements copy, get, put, getinterval, putinterval, */
31
/* length, and forall, which apply generically to */
32
/* arrays, strings, and dictionaries.  (Copy also has a special */
33
/* meaning for copying the top N elements of the stack.) */
34
35
/* See the comment in opdef.h for an invariant which allows */
36
/* more efficient implementation of forall. */
37
38
/* Forward references */
39
static int zcopy_integer(i_ctx_t *);
40
static int zcopy_interval(i_ctx_t *);
41
static int copy_interval(i_ctx_t *, os_ptr, uint, os_ptr, client_name_t);
42
43
/* <various1> <various2> copy <various> */
44
/* <obj1> ... <objn> <int> copy <obj1> ... <objn> <obj1> ... <objn> */
45
/* Note that this implements copy for arrays and strings, */
46
/* but not for dictionaries (see zcopy_dict in zdict.c). */
47
int
48
zcopy(i_ctx_t *i_ctx_p)
49
891M
{
50
891M
    os_ptr op = osp;
51
891M
    int type;
52
891M
    check_op(1);
53
891M
    type = r_type(op);
54
891M
    if (type == t_integer)
55
842M
        return zcopy_integer(i_ctx_p);
56
48.5M
    check_op(2);
57
48.5M
    switch (type) {
58
21.5M
        case t_array:
59
46.2M
        case t_string:
60
46.2M
            return zcopy_interval(i_ctx_p);
61
2.27M
        case t_dictionary:
62
2.27M
            return zcopy_dict(i_ctx_p);
63
9
        default:
64
9
            return_op_typecheck(op);
65
48.5M
    }
66
48.5M
}
67
68
/* <obj1> ... <objn> <int> copy <obj1> ... <objn> <obj1> ... <objn> */
69
static int
70
zcopy_integer(i_ctx_t *i_ctx_p)
71
842M
{
72
842M
    os_ptr op = osp;
73
842M
    os_ptr op1 = op - 1;
74
842M
    int count, i;
75
842M
    int code;
76
77
842M
    if ((uint) op->value.intval > (uint)(op - osbot)) {
78
        /* There might be enough elements in other blocks. */
79
33
        check_type(*op, t_integer);
80
33
        if (op->value.intval >= (int)ref_stack_count(&o_stack))
81
8
            return_error(gs_error_stackunderflow);
82
25
        if (op->value.intval < 0)
83
25
            return_error(gs_error_rangecheck);
84
25
        check_int_ltu(*op, ref_stack_count(&o_stack));
85
0
        count = op->value.intval;
86
842M
    } else if (op1 + (count = op->value.intval) <= ostop) {
87
        /* Fast case. */
88
842M
        memcpy((char *)op, (char *)(op - count), count * sizeof(ref));
89
842M
        push(count - 1);
90
842M
        return 0;
91
842M
    }
92
    /* Do it the slow, general way. */
93
31
    code = ref_stack_push(&o_stack, count - 1);
94
31
    if (code < 0)
95
0
        return code;
96
149
    for (i = 0; i < count; i++) {
97
118
        ref *o = ref_stack_index(&o_stack, i);
98
118
        ref *o1 = ref_stack_index(&o_stack, i + count);
99
100
118
        if (o == NULL || o1 == NULL)
101
0
            return_error(gs_error_stackunderflow);
102
118
        *o = *o1;
103
118
    }
104
31
    return 0;
105
31
}
106
107
/* <array1> <array2> copy <subarray2> */
108
/* <string1> <string2> copy <substring2> */
109
static int
110
zcopy_interval(i_ctx_t *i_ctx_p)
111
46.2M
{
112
46.2M
    os_ptr op = osp;
113
46.2M
    os_ptr op1 = op - 1;
114
46.2M
    int code = copy_interval(i_ctx_p, op, 0, op1, "copy");
115
116
46.2M
    if (code < 0)
117
3
        return code;
118
46.2M
    r_set_size(op, r_size(op1));
119
46.2M
    *op1 = *op;
120
46.2M
    pop(1);
121
46.2M
    return 0;
122
46.2M
}
123
124
/* <array|dict|name|packedarray|string> length <int> */
125
static int
126
zlength(i_ctx_t *i_ctx_p)
127
486M
{
128
486M
    os_ptr op = osp;
129
130
486M
    check_op(1);
131
486M
    switch (r_type(op)) {
132
49.8M
        case t_array:
133
361M
        case t_string:
134
363M
        case t_mixedarray:
135
366M
        case t_shortarray:
136
366M
            check_read(*op);
137
366M
            make_int(op, r_size(op));
138
366M
            return 0;
139
118M
        case t_dictionary:
140
118M
            check_dict_read(*op);
141
118M
            make_int(op, dict_length(op));
142
118M
            return 0;
143
1.69M
        case t_name: {
144
1.69M
            ref str;
145
146
1.69M
            name_string_ref(imemory, op, &str);
147
1.69M
            make_int(op, r_size(&str));
148
1.69M
            return 0;
149
118M
        }
150
2
        case t_astruct:
151
2
            if (gs_object_type(imemory, op->value.pstruct) != &st_bytes)
152
2
                return_error(gs_error_typecheck);
153
0
            check_read(*op);
154
0
            make_int(op, gs_object_size(imemory, op->value.pstruct));
155
0
            return 0;
156
12
        default:
157
12
            return_op_typecheck(op);
158
486M
    }
159
486M
}
160
161
/* <array|packedarray|string> <index> get <obj> */
162
/* <dict> <key> get <obj> */
163
static int
164
zget(i_ctx_t *i_ctx_p)
165
1.79G
{
166
1.79G
    int code;
167
1.79G
    os_ptr op = osp;
168
1.79G
    os_ptr op1 = op - 1;
169
1.79G
    ref *pvalue;
170
171
1.79G
    check_op(2);
172
173
1.79G
    switch (r_type(op1)) {
174
335M
        case t_dictionary:
175
335M
            check_dict_read(*op1);
176
335M
            if (dict_find(op1, op, &pvalue) <= 0)
177
23
                return_error(gs_error_undefined);
178
335M
            op[-1] = *pvalue;
179
335M
            break;
180
426M
        case t_string:
181
426M
            check_read(*op1);
182
426M
            check_int_ltu(*op, r_size(op1));
183
426M
            make_int(op1, op1->value.bytes[(uint) op->value.intval]);
184
426M
            break;
185
951M
        case t_array:
186
995M
        case t_mixedarray:
187
1.03G
        case t_shortarray:
188
1.03G
            check_type(*op, t_integer);
189
1.03G
            check_read(*op1);
190
1.03G
            code = array_get(imemory, op1, op->value.intval, op1);
191
1.03G
            if (code < 0)
192
3
                return code;
193
1.03G
            break;
194
1.03G
        case t__invalid:
195
0
            return_error(gs_error_stackunderflow);
196
16
        default:
197
16
            return_error(gs_error_typecheck);
198
1.79G
    }
199
1.79G
    pop(1);
200
1.79G
    return 0;
201
1.79G
}
202
203
/* <array> <index> <obj> put - */
204
/* <dict> <key> <value> put - */
205
/* <string> <index> <int> put - */
206
static int
207
zput(i_ctx_t *i_ctx_p)
208
1.09G
{
209
1.09G
    os_ptr op = osp;
210
1.09G
    os_ptr op1 = op - 1;
211
1.09G
    os_ptr op2 = op1 - 1;
212
1.09G
    byte *sdata;
213
1.09G
    uint ssize;
214
215
1.09G
    check_op(3);
216
1.09G
    switch (r_type(op2)) {
217
833M
        case t_dictionary:
218
833M
            check_dict_write(*op2);
219
833M
            {
220
833M
                int code = idict_put(op2, op1, op);
221
222
833M
                if (code < 0)
223
0
                    return code; /* error */
224
833M
            }
225
833M
            break;
226
833M
        case t_array:
227
78.4M
            check_write(*op2);
228
78.4M
            check_int_ltu(*op1, r_size(op2));
229
78.4M
            store_check_dest(op2, op);
230
78.4M
            {
231
78.4M
                ref *eltp = op2->value.refs + (uint) op1->value.intval;
232
233
78.4M
                ref_assign_old(op2, eltp, op, "put");
234
78.4M
            }
235
78.4M
            break;
236
0
        case t_mixedarray:  /* packed arrays are read-only */
237
0
        case t_shortarray:
238
0
            return_error(gs_error_invalidaccess);
239
180M
        case t_string:
240
180M
            sdata = op2->value.bytes;
241
180M
            ssize = r_size(op2);
242
180M
str:      check_write(*op2);
243
180M
            check_int_ltu(*op1, ssize);
244
180M
            check_int_leu(*op, 0xff);
245
180M
            sdata[(uint)op1->value.intval] = (byte)op->value.intval;
246
180M
            break;
247
0
        case t_astruct:
248
0
            if (gs_object_type(imemory, op2->value.pstruct) != &st_bytes)
249
0
                return_error(gs_error_typecheck);
250
0
            sdata = r_ptr(op2, byte);
251
0
            ssize = gs_object_size(imemory, op2->value.pstruct);
252
0
            goto str;
253
11
        default:
254
11
            return_op_typecheck(op2);
255
1.09G
    }
256
1.09G
    pop(3);
257
1.09G
    return 0;
258
1.09G
}
259
260
/* <seq:array|packedarray|string> <index> <count> getinterval <subseq> */
261
static int
262
zgetinterval(i_ctx_t *i_ctx_p)
263
65.7M
{
264
65.7M
    os_ptr op = osp;
265
65.7M
    os_ptr op1 = op - 1;
266
65.7M
    os_ptr op2 = op1 - 1;
267
65.7M
    uint index;
268
65.7M
    uint count;
269
270
65.7M
    check_op(3);
271
272
65.7M
    switch (r_type(op2)) {
273
3
        default:
274
3
            return_op_typecheck(op2);
275
3.94M
        case t_array:
276
40.6M
        case t_string:
277
65.7M
        case t_mixedarray:
278
65.7M
        case t_shortarray:;
279
65.7M
    }
280
65.7M
    check_read(*op2);
281
65.7M
    check_int_leu(*op1, r_size(op2));
282
65.7M
    index = op1->value.intval;
283
65.7M
    check_int_leu(*op, r_size(op2) - index);
284
65.7M
    count = op->value.intval;
285
65.7M
    switch (r_type(op2)) {
286
3.94M
        case t_array:
287
3.94M
            op2->value.refs += index;
288
3.94M
            break;
289
36.6M
        case t_string:
290
36.6M
            op2->value.bytes += index;
291
36.6M
            break;
292
25.1M
        case t_mixedarray: {
293
25.1M
            const ref_packed *packed = op2->value.packed;
294
295
198M
            for (; index--;)
296
173M
                packed = packed_next(packed);
297
25.1M
            op2->value.packed = packed;
298
25.1M
            break;
299
0
        }
300
0
        case t_shortarray:
301
0
            op2->value.packed += index;
302
0
            break;
303
65.7M
    }
304
65.7M
    r_set_size(op2, count);
305
65.7M
    pop(2);
306
65.7M
    return 0;
307
65.7M
}
308
309
/* <array1> <index> <array2|packedarray2> putinterval - */
310
/* <string1> <index> <string2> putinterval - */
311
/* <bytestring1> <index> <string2> putinterval - */
312
static int
313
zputinterval(i_ctx_t *i_ctx_p)
314
19.9M
{
315
19.9M
    os_ptr op = osp;
316
19.9M
    os_ptr opindex = op - 1;
317
19.9M
    os_ptr opto = opindex - 1;
318
19.9M
    int code;
319
320
19.9M
    check_op(3);
321
322
19.9M
    switch (r_type(opto)) {
323
4
        default:
324
4
            return_error(gs_error_typecheck);
325
0
        case t__invalid:
326
0
            if (r_type(op) != t_array && r_type(op) != t_string && r_type(op) != t__invalid)
327
0
                return_error(gs_error_typecheck); /* to match Distiller */
328
0
            else
329
0
                return_error(gs_error_stackunderflow);
330
0
        case t_mixedarray:
331
0
        case t_shortarray:
332
0
            return_error(gs_error_invalidaccess);
333
2.45M
        case t_array:
334
19.9M
        case t_string:
335
19.9M
            check_write(*opto);
336
19.9M
            check_int_leu(*opindex, r_size(opto));
337
19.9M
            code = copy_interval(i_ctx_p, opto, (uint)(opindex->value.intval),
338
19.9M
                                 op, "putinterval");
339
19.9M
            break;
340
0
        case t_astruct: {
341
0
            uint dsize, ssize, index;
342
343
0
            check_write(*opto);
344
0
            if (gs_object_type(imemory, opto->value.pstruct) != &st_bytes)
345
0
                return_error(gs_error_typecheck);
346
0
            dsize = gs_object_size(imemory, opto->value.pstruct);
347
0
            check_int_leu(*opindex, dsize);
348
0
            index = (uint)opindex->value.intval;
349
0
            check_read_type(*op, t_string);
350
0
            ssize = r_size(op);
351
0
            if (ssize > dsize - index)
352
0
                return_error(gs_error_rangecheck);
353
0
            memcpy(r_ptr(opto, byte) + index, op->value.const_bytes, ssize);
354
0
            code = 0;
355
0
            break;
356
0
        }
357
19.9M
    }
358
19.9M
    if (code >= 0)
359
19.9M
        pop(3);
360
19.9M
    return code;
361
19.9M
}
362
363
/*  <dict> <name> <string> .putgstringcopy - */
364
static int
365
zputgstringcopy(i_ctx_t *i_ctx_p)
366
10.1k
{
367
10.1k
    os_ptr op = osp;
368
10.1k
    byte *sbody;
369
10.1k
    uint size;
370
10.1k
    int code;
371
10.1k
    avm_space cs = ialloc_space(idmemory);
372
10.1k
    avm_space ds = r_space((op - 2));
373
10.1k
    avm_space ss = r_space(op);
374
375
    /* first, check our operands */
376
10.1k
    check_op(3);
377
10.1k
    check_read_type(*op, t_string);
378
10.1k
    check_type(*(op - 1), t_name);
379
10.1k
    check_type(*(op - 2), t_dictionary);
380
381
    /* If the string and the dictionary differ in globalness... */
382
10.1k
    if (ss != ds) {
383
0
        size = r_size(op);
384
0
        ialloc_set_space(idmemory, ds);
385
386
0
        sbody = ialloc_string(size, "string");
387
0
        if (sbody == 0) {
388
0
            ialloc_set_space(idmemory, cs);
389
0
            return_error(gs_error_VMerror);
390
0
        }
391
0
        memcpy(sbody, op->value.bytes, size);
392
0
        make_string(op, a_all | icurrent_space, size, sbody);
393
0
    }
394
    /* use dict_put() directly here, because we want to return
395
       the VM space back before we return in the event of an error
396
     */
397
10.1k
    code = dict_put(op - 2, op - 1, op, &(i_ctx_p->dict_stack));
398
399
    /* put the space back how it was */
400
10.1k
    if (ss != ds)
401
0
        ialloc_set_space(idmemory, cs);
402
403
10.1k
    if (code < 0)
404
0
        return code;
405
406
10.1k
    pop(3);
407
10.1k
    return 0;
408
10.1k
}
409
410
/* <array|packedarray|string> <<element> proc> forall - */
411
/* <dict> <<key> <value> proc> forall - */
412
static int
413
    array_continue(i_ctx_t *),
414
    dict_continue(i_ctx_t *),
415
    string_continue(i_ctx_t *),
416
    packedarray_continue(i_ctx_t *);
417
static int forall_cleanup(i_ctx_t *);
418
static int
419
zforall(i_ctx_t *i_ctx_p)
420
55.6M
{
421
55.6M
    os_ptr op = osp;
422
55.6M
    os_ptr obj = op - 1;
423
55.6M
    es_ptr ep;
424
55.6M
    es_ptr cproc;
425
426
55.6M
    check_estack(6);
427
    /* check_estack() could cause the exec stack to be copied to a new block
428
     * so don't caulculate ep and things based on ep until *after* the check
429
     */
430
55.6M
    ep = esp;
431
55.6M
    cproc = ep + 4;
432
55.6M
    check_proc(*op);
433
55.6M
    switch (r_type(obj)) {
434
12
        default:
435
12
            return_op_typecheck(obj);
436
16.6M
        case t_array:
437
16.6M
            check_read(*obj);
438
16.6M
            make_op_estack(cproc, array_continue);
439
16.6M
            break;
440
29.2M
        case t_dictionary:
441
29.2M
            check_dict_read(*obj);
442
29.2M
            make_int(cproc, dict_first(obj));
443
29.2M
            ++cproc;
444
29.2M
            make_op_estack(cproc, dict_continue);
445
29.2M
            break;
446
161k
        case t_string:
447
161k
            check_read(*obj);
448
161k
            make_op_estack(cproc, string_continue);
449
161k
            break;
450
7.33M
        case t_mixedarray:
451
9.58M
        case t_shortarray:
452
9.58M
            check_read(*obj);
453
9.58M
            make_op_estack(cproc, packedarray_continue);
454
9.58M
            break;
455
55.6M
    }
456
    /*
457
     * Push:
458
     *   - a mark;
459
     *   - the composite object;
460
     *   - the procedure;
461
     *   - the iteration index (only for dictionaries, done above);
462
     * and invoke the continuation operator.
463
     */
464
55.6M
    make_mark_estack(ep + 1, es_for, forall_cleanup);
465
55.6M
    ep[2] = *obj;
466
55.6M
    ep[3] = *op;
467
55.6M
    esp = cproc - 1;
468
55.6M
    ref_stack_pop(&o_stack, 2);
469
55.6M
    return (*real_opproc(cproc))(i_ctx_p);
470
55.6M
}
471
/* Continuation operator for arrays */
472
static int
473
array_continue(i_ctx_t *i_ctx_p)
474
189M
{
475
189M
    os_ptr op = osp;
476
189M
    es_ptr obj = esp - 1;
477
478
189M
    if (r_size(obj)) {   /* continue */
479
173M
        push(1);
480
173M
        r_dec_size(obj, 1);
481
173M
        *op = *obj->value.refs;
482
173M
        obj->value.refs++;
483
173M
        esp += 2;
484
173M
        *esp = obj[1];
485
173M
        return o_push_estack;
486
173M
    } else {     /* done */
487
16.3M
        esp -= 3;    /* pop mark, object, proc */
488
16.3M
        return o_pop_estack;
489
16.3M
    }
490
189M
}
491
/* Continuation operator for dictionaries */
492
static int
493
dict_continue(i_ctx_t *i_ctx_p)
494
1.37G
{
495
1.37G
    os_ptr op = osp;
496
1.37G
    es_ptr obj = esp - 2;
497
1.37G
    int index = esp->value.intval;
498
499
1.37G
    if (r_type(obj) != t_dictionary)
500
0
        return_error(gs_error_typecheck);
501
502
1.37G
    push(2);     /* make room for key and value */
503
1.37G
    if ((index = dict_next(obj, index, op - 1)) >= 0) { /* continue */
504
1.34G
        esp->value.intval = index;
505
1.34G
        esp += 2;
506
1.34G
        *esp = obj[1];
507
1.34G
        return o_push_estack;
508
1.34G
    } else {     /* done */
509
28.7M
        pop(2);      /* undo push */
510
28.7M
        esp -= 4;    /* pop mark, object, proc, index */
511
28.7M
        return o_pop_estack;
512
28.7M
    }
513
1.37G
}
514
/* Continuation operator for strings */
515
static int
516
string_continue(i_ctx_t *i_ctx_p)
517
162k
{
518
162k
    os_ptr op = osp;
519
162k
    es_ptr obj = esp - 1;
520
521
162k
    if (r_size(obj)) {   /* continue */
522
150
        push(1);    /* check for result space on stack BEFORE changing string size */
523
150
        r_dec_size(obj, 1); /* Bug 701550 :-O */
524
150
        make_int(op, *obj->value.bytes);
525
150
        obj->value.bytes++;
526
150
        esp += 2;
527
150
        *esp = obj[1];
528
150
        return o_push_estack;
529
161k
    } else {     /* done */
530
161k
        esp -= 3;    /* pop mark, object, proc */
531
161k
        return o_pop_estack;
532
161k
    }
533
162k
}
534
/* Continuation operator for packed arrays */
535
static int
536
packedarray_continue(i_ctx_t *i_ctx_p)
537
49.1M
{
538
49.1M
    os_ptr op = osp;
539
49.1M
    es_ptr obj = esp - 1;
540
541
49.1M
    if (r_size(obj)) {   /* continue */
542
39.5M
        const ref_packed *packed = obj->value.packed;
543
544
39.5M
        push(1);
545
39.5M
        r_dec_size(obj, 1);
546
39.5M
        packed_get(imemory, packed, op);
547
39.5M
        obj->value.packed = packed_next(packed);
548
39.5M
        esp += 2;
549
39.5M
        *esp = obj[1];
550
39.5M
        return o_push_estack;
551
39.5M
    } else {     /* done */
552
9.58M
        esp -= 3;    /* pop mark, object, proc */
553
9.58M
        return o_pop_estack;
554
9.58M
    }
555
49.1M
}
556
/* Vacuous cleanup procedure */
557
static int
558
forall_cleanup(i_ctx_t *i_ctx_p)
559
821k
{
560
821k
    return 0;
561
821k
}
562
563
/* ------ Initialization procedure ------ */
564
565
const op_def zgeneric_op_defs[] =
566
{
567
    {"1copy", zcopy},
568
    {"2forall", zforall},
569
    {"2get", zget},
570
    {"3getinterval", zgetinterval},
571
    {"1length", zlength},
572
    {"3put", zput},
573
    {"3putinterval", zputinterval},
574
    {"3.putgstringcopy", zputgstringcopy},
575
                /* Internal operators */
576
    {"0%array_continue", array_continue},
577
    {"0%dict_continue", dict_continue},
578
    {"0%packedarray_continue", packedarray_continue},
579
    {"0%string_continue", string_continue},
580
    op_def_end(0)
581
};
582
583
/* ------ Shared routines ------ */
584
585
/* Copy an interval from one operand to another. */
586
/* This is used by both putinterval and string/array copy. */
587
/* The destination is known to be an array or string, */
588
/* and the starting index is known to be less than or equal to */
589
/* its length; nothing else has been checked. */
590
static int
591
copy_interval(i_ctx_t *i_ctx_p /* for ref_assign_old */, os_ptr prto,
592
              uint index, os_ptr prfrom, client_name_t cname)
593
66.2M
{
594
66.2M
    int fromtype = r_type(prfrom);
595
66.2M
    uint fromsize = r_size(prfrom);
596
597
66.2M
    if (!(fromtype == r_type(prto) ||
598
162k
          ((fromtype == t_shortarray || fromtype == t_mixedarray) &&
599
162k
           r_type(prto) == t_array))
600
66.2M
        )
601
66.2M
        return_op_typecheck(prfrom);
602
66.2M
    check_read(*prfrom);
603
66.2M
    check_write(*prto);
604
66.2M
    if (fromsize > r_size(prto) - index)
605
0
        return_error(gs_error_rangecheck);
606
66.2M
    switch (fromtype) {
607
23.8M
        case t_array:
608
23.8M
            {     /* We have to worry about aliasing, */
609
                /* but refcpy_to_old takes care of it for us. */
610
23.8M
                return refcpy_to_old(prto, index, prfrom->value.refs,
611
23.8M
                                     fromsize, idmemory, cname);
612
0
            }
613
42.2M
        case t_string:
614
42.2M
            { /* memmove takes care of aliasing. */
615
42.2M
                memmove(prto->value.bytes + index, prfrom->value.bytes,
616
42.2M
                        fromsize);
617
42.2M
            }
618
42.2M
            break;
619
162k
        case t_mixedarray:
620
162k
        case t_shortarray:
621
162k
            { /* We don't have to worry about aliasing, because */
622
                /* packed arrays are read-only and hence the destination */
623
                /* can't be a packed array. */
624
162k
                uint i;
625
162k
                const ref_packed *packed = prfrom->value.packed;
626
162k
                ref *pdest = prto->value.refs + index;
627
162k
                ref elt;
628
629
41.6M
                for (i = 0; i < fromsize; i++, pdest++) {
630
41.5M
                    packed_get(imemory, packed, &elt);
631
41.5M
                    ref_assign_old(prto, pdest, &elt, cname);
632
41.5M
                    packed = packed_next(packed);
633
41.5M
                }
634
162k
            }
635
162k
            break;
636
66.2M
    }
637
42.3M
    return 0;
638
66.2M
}