Coverage Report

Created: 2025-06-10 06:49

/src/ghostpdl/psi/idict.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 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
/* Dictionary implementation */
18
#include "math_.h"    /* for frexp */
19
#include "string_.h"    /* for strlen */
20
#include "ghost.h"
21
#include "gxalloc.h"    /* for accessing masks */
22
#include "ierrors.h"
23
#include "imemory.h"
24
#include "idebug.h"   /* for debug_print_name */
25
#include "inamedef.h"
26
#include "iname.h"
27
#include "ipacked.h"
28
#include "isave.h"    /* for value cache in names */
29
#include "store.h"
30
#include "idict.h"    /* interface definition */
31
#include "idictdef.h"
32
#include "iutil.h"
33
#include "ivmspace.h"   /* for store check */
34
/*
35
#include "idicttpl.h" - Do not remove this comment.
36
                        "idicttpl.h" is included below.
37
*/
38
39
/*
40
 * Dictionaries per se aren't supposed to know anything about the
41
 * dictionary stack, let alone the interpreter's dictionary stack.
42
 * Unfortunately, there is are two design couplings between them:
43
 * dictionary stacks cache some of the elements of their top dictionary
44
 * (requiring updating when that dictionary grows or is unpacked),
45
 * and names may cache a pointer to their definition (requiring a
46
 * check whether a dictionary appears on the dictionary stack).
47
 * Therefore, we need iddstack.h here.
48
 * We'd really like to fix this, but we don't see how.
49
 */
50
#include "iddstack.h"
51
52
/*
53
 * Define the size of the largest valid dictionary.
54
 * This is limited by the size field of the keys and values refs,
55
 * and by the enumeration interface, which requires the size to
56
 * fit in an int.  As it happens, max_array_size will always be
57
 * smaller than max_int.
58
 */
59
const uint dict_max_size = max_array_size - 1;
60
61
/* Define whether dictionaries are packed by default. */
62
enum {
63
    dict_default_pack = true
64
};
65
66
/*
67
 * Define the check for whether we can set the 1-element cache.
68
 * We only set the cache if we aren't inside a save.
69
 * This way, we never have to undo setting the cache.
70
 */
71
#define CAN_SET_PVALUE_CACHE(pds, pdref, mem)\
72
58.9M
  (pds && dstack_dict_is_permanent(pds, pdref) && !ref_saving_in(mem))
73
74
/* Forward references */
75
static int dict_create_contents(uint size, const ref * pdref, bool pack);
76
77
/* Debugging statistics - uses a static, so not threadsafe. */
78
/* #define COLLECT_STATS_IDICT */
79
80
#ifdef COLLECT_STATS_IDICT
81
struct stats_dict_s {
82
    long lookups;   /* total lookups */
83
    long probe1;    /* successful lookups on only 1 probe */
84
    long probe2;    /* successful lookups on 2 probes */
85
} stats_dict;
86
87
/* Wrapper for dict_find */
88
int real_dict_find(const ref * pdref, const ref * key, ref ** ppvalue);
89
int
90
dict_find(const ref * pdref, const ref * pkey, ref ** ppvalue)
91
{
92
    dict *pdict = pdref->value.pdict;
93
    int code = real_dict_find(pdref, pkey, ppvalue);
94
95
    stats_dict.lookups++;
96
    if (r_has_type(pkey, t_name) && dict_is_packed(pdict)) {
97
        uint nidx = name_index(dict_mem(pdict), pkey);
98
        uint hash =
99
        dict_hash_mod(dict_name_index_hash(nidx), npairs(pdict)) + 1;
100
101
        if (pdict->keys.value.packed[hash] ==
102
            pt_tag(pt_literal_name) + nidx
103
            )
104
            stats_dict.probe1++;
105
        else if (pdict->keys.value.packed[hash - 1] ==
106
                 pt_tag(pt_literal_name) + nidx
107
            )
108
            stats_dict.probe2++;
109
    }
110
    /* Do the cheap flag test before the expensive remainder test. */
111
    if (gs_debug_c('d') && !(stats_dict.lookups % 1000))
112
        dlprintf3("[d]lookups=%ld probe1=%ld probe2=%ld\n",
113
                  stats_dict.lookups, stats_dict.probe1, stats_dict.probe2);
114
    return code;
115
}
116
#define dict_find real_dict_find
117
#endif
118
119
/* Round up the size of a dictionary.  Return 0 if too large. */
120
uint
121
dict_round_size_small(uint rsize)
122
0
{
123
0
    return (rsize > dict_max_size ? 0 : rsize);
124
0
}
125
uint
126
dict_round_size_large(uint rsize)
127
6.17M
{       /* Round up to a power of 2 if not huge. */
128
    /* If the addition overflows, the new rsize will be zero, */
129
    /* which will (correctly) be interpreted as a limitcheck. */
130
6.17M
    if (rsize > dict_max_non_huge)
131
2
        return (rsize > dict_max_size ? 0 : rsize);
132
13.4M
    while (rsize & (rsize - 1))
133
7.26M
        rsize = (rsize | (rsize - 1)) + 1;
134
6.17M
    return (rsize <= dict_max_size ? rsize : dict_max_non_huge);
135
6.17M
}
136
137
/* Create a dictionary using the given allocator. */
138
int
139
dict_alloc(gs_ref_memory_t * mem, uint size, ref * pdref)
140
5.35M
{
141
5.35M
    ref arr;
142
5.35M
    int code =
143
5.35M
        gs_alloc_ref_array(mem, &arr, a_all, sizeof(dict) / sizeof(ref),
144
5.35M
                           "dict_alloc");
145
5.35M
    dict *pdict;
146
5.35M
    ref dref;
147
148
5.35M
    if (code < 0)
149
0
        return code;
150
5.35M
    pdict = (dict *) arr.value.refs;
151
5.35M
    make_tav(&dref, t_dictionary,
152
5.35M
             r_space(&arr) | imemory_new_mask(mem) | a_all,
153
5.35M
             pdict, pdict);
154
5.35M
    make_struct(&pdict->memory, avm_foreign, mem);
155
5.35M
    code = dict_create_contents(size, &dref, dict_default_pack);
156
5.35M
    if (code < 0) {
157
2
        gs_free_ref_array(mem, &arr, "dict_alloc");
158
2
        return code;
159
2
    }
160
5.35M
    *pdref = dref;
161
5.35M
    return 0;
162
5.35M
}
163
/* Create unpacked keys for a dictionary. */
164
/* The keys are allocated using the same allocator as the dictionary. */
165
static int
166
dict_create_unpacked_keys(uint asize, const ref * pdref)
167
3.35M
{
168
3.35M
    dict *pdict = pdref->value.pdict;
169
3.35M
    gs_ref_memory_t *mem = dict_memory(pdict);
170
3.35M
    int code;
171
172
3.35M
    code = gs_alloc_ref_array(mem, &pdict->keys, a_all, asize,
173
3.35M
                              "dict_create_unpacked_keys");
174
3.35M
    if (code >= 0) {
175
3.35M
        uint new_mask = imemory_new_mask(mem);
176
3.35M
        ref *kp = pdict->keys.value.refs;
177
178
3.35M
        r_set_attrs(&pdict->keys, new_mask);
179
3.35M
        refset_null_new(kp, asize, new_mask);
180
3.35M
        r_set_attrs(kp, a_executable); /* wraparound entry */
181
3.35M
    }
182
3.35M
    return code;
183
3.35M
}
184
/* Create the contents (keys and values) of a newly allocated dictionary. */
185
/* Allocate in the current VM space, which is assumed to be the same as */
186
/* the VM space where the dictionary is allocated. */
187
static int
188
dict_create_contents(uint size, const ref * pdref, bool pack)
189
6.17M
{
190
6.17M
    dict *pdict = pdref->value.pdict;
191
6.17M
    gs_ref_memory_t *mem = dict_memory(pdict);
192
6.17M
    uint new_mask = imemory_new_mask(mem);
193
6.17M
    uint asize = dict_round_size((size == 0 ? 1 : size));
194
6.17M
    int code;
195
6.17M
    register uint i;
196
197
6.17M
    if (asize == 0 || asize > max_array_size - 1)  /* too large */
198
2
        return_error(gs_error_limitcheck);
199
6.17M
    asize++;      /* allow room for wraparound entry */
200
6.17M
    code = gs_alloc_ref_array(mem, &pdict->values, a_all, asize,
201
6.17M
                              "dict_create_contents(values)");
202
6.17M
    if (code < 0)
203
0
        return code;
204
6.17M
    r_set_attrs(&pdict->values, new_mask);
205
6.17M
    refset_null_new(pdict->values.value.refs, asize, new_mask);
206
6.17M
    if (pack) {
207
5.57M
        uint ksize = (asize + packed_per_ref - 1) / packed_per_ref;
208
5.57M
        ref arr;
209
5.57M
        ref_packed *pkp;
210
5.57M
        ref_packed *pzp;
211
212
5.57M
        code = gs_alloc_ref_array(mem, &arr, a_all, ksize,
213
5.57M
                                  "dict_create_contents(packed keys)");
214
5.57M
        if (code < 0)
215
0
            return code;
216
5.57M
        pkp = (ref_packed *) arr.value.refs;
217
5.57M
        make_tasv(&pdict->keys, t_shortarray,
218
5.57M
                  r_space(&arr) | a_all | new_mask,
219
5.57M
                  asize, packed, pkp);
220
376M
        for (pzp = pkp, i = 0; i < asize || i % packed_per_ref; pzp++, i++)
221
371M
            *pzp = packed_key_empty;
222
5.57M
        *pkp = packed_key_deleted; /* wraparound entry */
223
5.57M
    } else {     /* not packed */
224
599k
        int code = dict_create_unpacked_keys(asize, pdref);
225
226
599k
        if (code < 0)
227
0
            return code;
228
599k
    }
229
6.17M
    make_tav(&pdict->count, t_integer, new_mask, intval, 0);
230
6.17M
    make_tav(&pdict->maxlength, t_integer, new_mask, intval, size);
231
6.17M
    return 0;
232
6.17M
}
233
234
/*
235
 * Ensure that a dictionary uses the unpacked representation for keys.
236
 * We can't just use dict_resize, because the values slots mustn't move.
237
 */
238
int
239
dict_unpack(ref * pdref, dict_stack_t *pds)
240
2.75M
{
241
2.75M
    dict *pdict = pdref->value.pdict;
242
243
2.75M
    if (!dict_is_packed(pdict))
244
0
        return 0;   /* nothing to do */
245
2.75M
    {
246
2.75M
        gs_ref_memory_t *mem = dict_memory(pdict);
247
2.75M
        uint count = nslots(pdict);
248
2.75M
        const ref_packed *okp = pdict->keys.value.packed;
249
2.75M
        ref old_keys;
250
2.75M
        int code;
251
2.75M
        ref *nkp;
252
253
2.75M
        old_keys = pdict->keys;
254
2.75M
        if (ref_must_save_in(mem, &old_keys))
255
1
            ref_do_save_in(mem, pdref, &pdict->keys, "dict_unpack(keys)");
256
2.75M
        code = dict_create_unpacked_keys(count, pdref);
257
2.75M
        if (code < 0)
258
0
            return code;
259
315M
        for (nkp = pdict->keys.value.refs; count--; okp++, nkp++)
260
313M
            if (r_packed_is_name(okp)) {
261
11.5M
                packed_get((const gs_memory_t *)mem, okp, nkp);
262
11.5M
                ref_mark_new_in(mem, nkp);
263
301M
            } else if (*okp == packed_key_deleted)
264
3.41M
                r_set_attrs(nkp, a_executable);
265
2.75M
        if (!ref_must_save_in(mem, &old_keys))
266
2.75M
            gs_free_ref_array(mem, &old_keys, "dict_unpack(old keys)");
267
2.75M
        if (pds)
268
2.75M
            dstack_set_top(pds); /* just in case */
269
2.75M
    }
270
0
    return 0;
271
2.75M
}
272
273
/*
274
 * Look up a key in a dictionary.  Store a pointer to the value slot
275
 * where found, or to the (value) slot for inserting.
276
 * See idict.h for the possible return values.
277
 */
278
int
279
dict_find(const ref * pdref, const ref * pkey,
280
          ref ** ppvalue /* result is stored here */ )
281
605M
{
282
605M
    dict *pdict = pdref->value.pdict;
283
605M
    uint size = npairs(pdict);
284
605M
    register int etype;
285
605M
    uint nidx;
286
605M
    ref_packed kpack;
287
605M
    uint hash;
288
605M
    int ktype;
289
605M
    const gs_memory_t *mem = dict_mem(pdict);
290
291
    /* Compute hash.  The only types we bother with are strings, */
292
    /* names, and (unlikely, but worth checking for) integers. */
293
605M
    switch (r_type(pkey)) {
294
1.24M
    case t_string:    /* convert to a name first */
295
1.24M
        {
296
1.24M
            ref nref;
297
1.24M
            int code;
298
299
1.24M
            if (!r_has_attr(pkey, a_read))
300
0
                return_error(gs_error_invalidaccess);
301
1.24M
            code = name_ref(mem, pkey->value.bytes, r_size(pkey), &nref, 1);
302
1.24M
            if (code < 0)
303
0
                return code;
304
1.24M
            nidx = name_index(mem, &nref);
305
1.24M
        }
306
0
        goto nh;
307
568M
    case t_name:
308
568M
        nidx = name_index(mem, pkey);
309
569M
    nh:
310
569M
        hash = dict_name_index_hash(nidx);
311
569M
        kpack = packed_name_key(nidx);
312
569M
        ktype = t_name;
313
569M
        break;
314
6.61k
    case t_real:
315
        /*
316
         * Make sure that equal reals and integers hash the same.
317
         */
318
6.61k
        {
319
6.61k
            int expt, i;
320
6.61k
            double mant = frexp(pkey->value.realval, &expt);
321
            /*
322
             * The value is mant * 2^expt, where 0.5 <= mant < 1,
323
             * or else expt == mant == 0.
324
             */
325
326
6.61k
            if (expt < sizeof(long) * 8 || pkey->value.realval == min_long)
327
3.75k
                i = (int)pkey->value.realval;
328
2.86k
            else
329
2.86k
                i = (int)(mant * min_long); /* MSVC 6.00.8168.0 cannot compile this */
330
6.61k
            hash = (uint)i * 30503;         /*   with -O2 as a single expression    */
331
6.61k
        }
332
6.61k
        goto ih;
333
36.3M
    case t_integer:
334
36.3M
        hash = (uint)pkey->value.intval * 30503;
335
36.3M
    ih:
336
36.3M
        kpack = packed_key_impossible;
337
36.3M
        ktype = -1;
338
36.3M
        nidx = 0;   /* only to pacify gcc */
339
36.3M
        break;
340
0
    case t_null:    /* not allowed as a key */
341
0
        return_error(gs_error_typecheck);
342
94.1k
    default:
343
94.1k
        hash = r_btype(pkey) * 99;  /* yech */
344
94.1k
        kpack = packed_key_impossible;
345
94.1k
        ktype = -1;
346
94.1k
        nidx = 0;   /* only to pacify gcc */
347
605M
    }
348
    /* Search the dictionary */
349
605M
    if (dict_is_packed(pdict)) {
350
121M
        const ref_packed *pslot = 0;
351
352
121M
# define found *ppvalue = packed_search_value_pointer; return 1
353
121M
# define deleted if (pslot == 0) pslot = kp
354
121M
# define missing goto miss
355
121M
# include "idicttpl.h"
356
39.8M
# undef missing
357
39.8M
# undef deleted
358
39.8M
# undef found
359
        /*
360
         * Double wraparound, dict is full.
361
         * Note that even if there was an empty slot (pslot != 0),
362
         * we must return dictfull if length = maxlength.
363
         */
364
39.8M
        if (pslot == 0 || d_length(pdict) == d_maxlength(pdict))
365
39.8M
            return_error(gs_error_dictfull);
366
0
        *ppvalue = pdict->values.value.refs + (pslot - kbot);
367
0
        return 0;
368
49.7M
      miss:     /* Key is missing, not double wrap.  See above re dictfull. */
369
49.7M
        if (d_length(pdict) == d_maxlength(pdict))
370
3.42M
            return_error(gs_error_dictfull);
371
46.3M
        if (pslot == 0)
372
46.3M
            pslot = kp;
373
46.3M
        *ppvalue = pdict->values.value.refs + (pslot - kbot);
374
46.3M
        return 0;
375
484M
    } else {
376
484M
        ref *kbot = pdict->keys.value.refs;
377
484M
        register ref *kp;
378
484M
        ref *pslot = 0;
379
484M
        int wrap = 0;
380
381
978M
        for (kp = kbot + dict_hash_mod(hash, size) + 2;;) {
382
978M
            --kp;
383
978M
            if ((etype = r_type(kp)) == ktype) { /* Fast comparison if both keys are names */
384
556M
                if (name_index(mem, kp) == nidx) {
385
210M
                    *ppvalue = pdict->values.value.refs + (kp - kbot);
386
210M
                    return 1;
387
210M
                }
388
556M
            } else if (etype == t_null) { /* Empty, deleted, or wraparound. */
389
                /* Figure out which. */
390
328M
                if (kp == kbot) { /* wrap */
391
12.8M
                    if (wrap++) { /* wrapped twice */
392
3.60M
                        if (pslot == 0)
393
3.59M
                            return_error(gs_error_dictfull);
394
8.71k
                        break;
395
3.60M
                    }
396
9.25M
                    kp += size + 1;
397
315M
                } else if (r_has_attr(kp, a_executable)) { /* Deleted entry, save the slot. */
398
46.2M
                    if (pslot == 0)
399
25.4M
                        pslot = kp;
400
46.2M
                } else   /* key not found */
401
269M
                    break;
402
328M
            } else {
403
94.1M
                if (obj_eq(mem, kp, pkey)) {
404
643k
                    *ppvalue = pdict->values.value.refs + (kp - kbot);
405
643k
                    return 1;
406
643k
                }
407
94.1M
            }
408
978M
        }
409
269M
        if (d_length(pdict) == d_maxlength(pdict))
410
36.5M
            return_error(gs_error_dictfull);
411
232M
        *ppvalue = pdict->values.value.refs +
412
232M
            ((pslot != 0 ? pslot : kp) - kbot);
413
232M
        return 0;
414
269M
    }
415
605M
}
416
417
/*
418
 * Look up a (constant) C string in a dictionary.
419
 * Return 1 if found, <= 0 if not.
420
 */
421
int
422
dict_find_string(const ref * pdref, const char *kstr, ref ** ppvalue)
423
44.9M
{
424
44.9M
    int code;
425
44.9M
    ref kname;
426
44.9M
    if ( pdref != 0 ) {
427
44.9M
        dict *pdict = pdref->value.pdict;
428
429
44.9M
        if ((code = name_ref(dict_mem(pdict),
430
44.9M
                             (const byte *)kstr, strlen(kstr), &kname, -1)) < 0)
431
9.32M
            return code;
432
35.6M
        code = dict_find(pdref, &kname, ppvalue);
433
35.6M
        if (code == gs_error_dictfull)
434
395k
            return_error(gs_error_undefined);
435
35.2M
        return code;
436
35.6M
    }
437
8.71k
    return 0;
438
44.9M
}
439
440
/*
441
 * Enter a key-value pair in a dictionary.
442
 * See idict.h for the possible return values.
443
 */
444
int
445
dict_put(ref * pdref /* t_dictionary */ , const ref * pkey, const ref * pvalue,
446
         dict_stack_t *pds)
447
280M
{
448
280M
    dict *pdict = pdref->value.pdict;
449
280M
    gs_ref_memory_t *mem = dict_memory(pdict);
450
280M
    gs_memory_t *pmem = dict_mem(pdict);
451
280M
    int rcode = 0;
452
280M
    int code;
453
280M
    ref *pvslot, kname;
454
455
    /* Check the value. */
456
280M
    store_check_dest(pdref, pvalue);
457
283M
  top:if ((code = dict_find(pdref, pkey, &pvslot)) <= 0) { /* not found *//* Check for overflow */
458
224M
        uint index;
459
460
224M
        switch (code) {
461
223M
            case 0:
462
223M
                break;
463
216k
            case gs_error_dictfull:
464
216k
                if (!pmem->gs_lib_ctx->dict_auto_expand)
465
0
                    return_error(gs_error_dictfull);
466
216k
                code = dict_grow(pdref, pds);
467
216k
                if (code < 0)
468
0
                    return code;
469
216k
                goto top; /* keep things simple */
470
216k
            default:    /* gs_error_typecheck */
471
0
                return code;
472
224M
        }
473
223M
        index = pvslot - pdict->values.value.refs;
474
        /* If the key is a string, convert it to a name. */
475
223M
        if (r_has_type(pkey, t_string)) {
476
636k
            int code;
477
478
636k
            if (!r_has_attr(pkey, a_read))
479
0
                return_error(gs_error_invalidaccess);
480
636k
            code = name_from_string(pmem, pkey, &kname);
481
636k
            if (code < 0)
482
0
                return code;
483
636k
            pkey = &kname;
484
636k
        }
485
223M
        if (dict_is_packed(pdict)) {
486
27.1M
            ref_packed *kp;
487
488
27.1M
            if (!r_has_type(pkey, t_name) ||
489
27.1M
                name_index(pmem, pkey) > packed_name_max_index
490
27.1M
                ) {   /* Change to unpacked representation. */
491
2.75M
                int code = dict_unpack(pdref, pds);
492
493
2.75M
                if (code < 0)
494
0
                    return code;
495
2.75M
                goto top;
496
2.75M
            }
497
24.3M
            kp = pdict->keys.value.writable_packed + index;
498
24.3M
            if (ref_must_save_in(mem, &pdict->keys)) { /* See initial comment for why it is safe */
499
                /* not to save the change if the keys */
500
                /* array itself is new. */
501
24.4k
                ref_do_save_in(mem, &pdict->keys, kp, "dict_put(key)");
502
24.4k
            }
503
24.3M
            *kp = pt_tag(pt_literal_name) + name_index(pmem, pkey);
504
196M
        } else {
505
196M
            ref *kp = pdict->keys.value.refs + index;
506
507
196M
            if_debug2m('d', (const gs_memory_t *)mem, "[d]"PRI_INTPTR": fill key at "PRI_INTPTR"\n",
508
196M
                       (intptr_t)pdict, (intptr_t)kp);
509
196M
            store_check_dest(pdref, pkey);
510
196M
            ref_assign_old_in(mem, &pdict->keys, kp, pkey,
511
196M
                              "dict_put(key)"); /* set key of pair */
512
196M
        }
513
221M
        ref_save_in(mem, pdref, &pdict->count, "dict_put(count)");
514
221M
        pdict->count.value.intval++;
515
        /* If the key is a name, update its 1-element cache. */
516
221M
        if (r_has_type(pkey, t_name)) {
517
186M
            name *pname = pkey->value.pname;
518
519
186M
            if (pname->pvalue == pv_no_defn &&
520
186M
                CAN_SET_PVALUE_CACHE(pds, pdref, mem)
521
186M
                ) {   /* Set the cache. */
522
8.63M
                if_debug0m('d', (const gs_memory_t *)mem, "[d]set cache\n");
523
8.63M
                pname->pvalue = pvslot;
524
177M
            } else {   /* The cache can't be used. */
525
177M
                if_debug0m('d', (const gs_memory_t *)mem, "[d]no cache\n");
526
177M
                pname->pvalue = pv_other;
527
177M
            }
528
186M
        }
529
221M
        rcode = 1;
530
221M
    }
531
283M
    if_debug8m('d', (const gs_memory_t *)mem,
532
280M
               "[d]"PRI_INTPTR": put key 0x%lx 0x%lx\n  value at "PRI_INTPTR": old 0x%lx 0x%lx, new 0x%lx 0x%lx\n",
533
280M
               (intptr_t) pdref->value.pdict,
534
280M
               ((const ulong *)pkey)[0], ((const ulong *)pkey)[1],
535
280M
               (intptr_t) pvslot,
536
280M
               ((const ulong *)pvslot)[0], ((const ulong *)pvslot)[1],
537
280M
               ((const ulong *)pvalue)[0], ((const ulong *)pvalue)[1]);
538
280M
    ref_assign_old_in(mem, &pdref->value.pdict->values, pvslot, pvalue,
539
280M
                      "dict_put(value)");
540
280M
    return rcode;
541
283M
}
542
543
/*
544
 * Enter a key-value pair where the key is a (constant) C string.
545
 */
546
int
547
dict_put_string(ref * pdref, const char *kstr, const ref * pvalue,
548
                dict_stack_t *pds)
549
5.25M
{
550
5.25M
    int code;
551
5.25M
    ref kname;
552
5.25M
    dict *pdict = pdref->value.pdict;
553
554
5.25M
    if ((code = name_ref(dict_mem(pdict),
555
5.25M
                         (const byte *)kstr, strlen(kstr), &kname, 0)) < 0)
556
0
        return code;
557
5.25M
    return dict_put(pdref, &kname, pvalue, pds);
558
5.25M
}
559
560
/*
561
 * Enter a key-value pair where the key is a C string that must be copied.
562
 */
563
int
564
dict_put_string_copy(ref * pdref, const char *kstr, const ref * pvalue,
565
                     dict_stack_t *pds)
566
130k
{
567
130k
    int code;
568
130k
    ref kname;
569
130k
    dict *pdict = pdref->value.pdict;
570
571
130k
    if ((code = name_ref(dict_mem(pdict),
572
130k
                         (const byte *)kstr, strlen(kstr), &kname, 1)) < 0)
573
0
        return code;
574
130k
    return dict_put(pdref, &kname, pvalue, pds);
575
130k
}
576
577
/* Remove an element from a dictionary. */
578
int
579
dict_undef(ref * pdref, const ref * pkey, dict_stack_t *pds)
580
22.0M
{
581
22.0M
    gs_ref_memory_t *mem;
582
22.0M
    ref *pvslot;
583
22.0M
    dict *pdict;
584
22.0M
    uint index;
585
22.0M
    int code = dict_find(pdref, pkey, &pvslot);
586
587
22.0M
    switch (code) {
588
1.06M
    case 0:
589
1.06M
    case gs_error_dictfull:
590
1.06M
        return_error(gs_error_undefined);
591
21.0M
    case 1:
592
21.0M
        break;
593
0
    default:      /* other error */
594
0
        return code;
595
22.0M
    }
596
    /* Remove the entry from the dictionary. */
597
21.0M
    pdict = pdref->value.pdict;
598
21.0M
    index = pvslot - pdict->values.value.refs;
599
21.0M
    mem = dict_memory(pdict);
600
21.0M
    if (dict_is_packed(pdict)) {
601
1.20M
        ref_packed *pkp = pdict->keys.value.writable_packed + index;
602
1.20M
        bool must_save = ref_must_save_in(mem, &pdict->keys);
603
604
1.20M
        if_debug3m('d', (const gs_memory_t *)mem,
605
1.20M
                   "[d]"PRI_INTPTR": removing key at "PRI_INTPTR": 0x%x\n",
606
1.20M
                   (intptr_t)pdict, (intptr_t)pkp, (uint)*pkp);
607
        /* See the initial comment for why it is safe not to save */
608
        /* the change if the keys array itself is new. */
609
1.20M
        if (must_save)
610
10.4k
            ref_do_save_in(mem, &pdict->keys, pkp, "dict_undef(key)");
611
        /*
612
         * Accumulating deleted entries slows down lookup.
613
         * Detect the easy case where we can use an empty entry
614
         * rather than a deleted one, namely, when the next entry
615
         * in the probe order is empty.
616
         */
617
1.20M
        if (pkp[-1] == packed_key_empty) {
618
            /*
619
             * In this case we can replace any preceding deleted keys with
620
             * empty ones as well.
621
             */
622
533k
            uint end = nslots(pdict);
623
624
533k
            *pkp = packed_key_empty;
625
533k
            if (must_save) {
626
10.4k
                while (++index < end && *++pkp == packed_key_deleted) {
627
0
                    ref_do_save_in(mem, &pdict->keys, pkp, "dict_undef(key)");
628
0
                    *pkp = packed_key_empty;
629
0
                }
630
523k
            } else {
631
523k
                while (++index < end && *++pkp == packed_key_deleted)
632
0
                    *pkp = packed_key_empty;
633
523k
            }
634
533k
        } else
635
671k
            *pkp = packed_key_deleted;
636
19.8M
    } else {     /* not packed */
637
19.8M
        ref *kp = pdict->keys.value.refs + index;
638
639
19.8M
        if_debug4m('d', (const gs_memory_t *)mem,
640
19.8M
                   "[d]"PRI_INTPTR": removing key at "PRI_INTPTR": 0x%lx 0x%lx\n",
641
19.8M
                   (intptr_t)pdict, (intptr_t)kp, ((ulong *)kp)[0], ((ulong *)kp)[1]);
642
19.8M
        make_null_old_in(mem, &pdict->keys, kp, "dict_undef(key)");
643
        /*
644
         * Accumulating deleted entries slows down lookup.
645
         * Detect the easy case where we can use an empty entry
646
         * rather than a deleted one, namely, when the next entry
647
         * in the probe order is empty.
648
         */
649
19.8M
        if (!r_has_type(kp - 1, t_null) || /* full entry */
650
19.8M
            r_has_attr(kp - 1, a_executable)  /* deleted or wraparound */
651
19.8M
            )
652
13.1M
            r_set_attrs(kp, a_executable); /* mark as deleted */
653
19.8M
    }
654
21.0M
    ref_save_in(mem, pdref, &pdict->count, "dict_undef(count)");
655
21.0M
    pdict->count.value.intval--;
656
    /* If the key is a name, update its 1-element cache. */
657
21.0M
    if (r_has_type(pkey, t_name)) {
658
20.9M
        name *pname = pkey->value.pname;
659
660
20.9M
        if (pv_valid(pname->pvalue)) {
661
#ifdef DEBUG
662
            /* Check the the cache is correct. */
663
            if (!(pds && dstack_dict_is_permanent(pds, pdref)))
664
                lprintf1("dict_undef: cached name value pointer " PRI_INTPTR " is incorrect!\n",
665
                         (intptr_t) pname->pvalue);
666
#endif
667
            /* Clear the cache */
668
1.34M
            pname->pvalue = pv_no_defn;
669
1.34M
        }
670
20.9M
    }
671
21.0M
    make_null_old_in(mem, &pdict->values, pvslot, "dict_undef(value)");
672
21.0M
    return 0;
673
22.0M
}
674
675
/* Return the number of elements in a dictionary. */
676
uint
677
dict_length(const ref * pdref /* t_dictionary */ )
678
7.69M
{
679
7.69M
    return d_length(pdref->value.pdict);
680
7.69M
}
681
682
/* Return the capacity of a dictionary. */
683
uint
684
dict_maxlength(const ref * pdref /* t_dictionary */ )
685
4.97M
{
686
4.97M
    return d_maxlength(pdref->value.pdict);
687
4.97M
}
688
689
/* Return the maximum index of a slot within a dictionary. */
690
uint
691
dict_max_index(const ref * pdref /* t_dictionary */ )
692
278k
{
693
278k
    return npairs(pdref->value.pdict) - 1;
694
278k
}
695
696
/*
697
 * Copy one dictionary into another.
698
 * If COPY_NEW_ONLY is set, only copy entries whose keys
699
 * aren't already present in the destination.
700
 * If COPY_FOR_RESIZE is set, reset any valid name cache entries to
701
 * pv_no_defn before doing the dict_put.
702
 */
703
14.6M
#define COPY_NEW_ONLY 1
704
13.5M
#define COPY_FOR_RESIZE 2
705
static int
706
dict_copy_elements(const ref * pdrfrom /* t_dictionary */ ,
707
                  ref * pdrto /* t_dictionary */ , int options,
708
                  dict_stack_t *pds)
709
947k
{
710
947k
    int space = r_space(pdrto);
711
947k
    int index;
712
947k
    ref elt[2];
713
947k
    ref *pvslot;
714
947k
    int code;
715
716
947k
    if (space != avm_max) {
717
        /* Do the store check before starting the copy. */
718
122k
        index = dict_first(pdrfrom);
719
1.20M
        while ((index = dict_next(pdrfrom, index, elt)) >= 0)
720
1.08M
            if (!(options & COPY_NEW_ONLY) ||
721
1.08M
                dict_find(pdrto, &elt[0], &pvslot) <= 0
722
1.08M
                ) {
723
1.08M
                store_check_space(space, &elt[0]);
724
1.08M
                store_check_space(space, &elt[1]);
725
1.08M
            }
726
122k
    }
727
    /* Now copy the contents. */
728
947k
    index = dict_first(pdrfrom);
729
14.4M
    while ((index = dict_next(pdrfrom, index, elt)) >= 0) {
730
13.5M
        ref *pvalue = pv_no_defn;
731
732
13.5M
        if ((options & COPY_NEW_ONLY) &&
733
13.5M
            dict_find(pdrto, &elt[0], &pvslot) > 0
734
13.5M
            )
735
6.06k
            continue;
736
13.5M
        if ((options & COPY_FOR_RESIZE) &&
737
13.5M
            r_has_type(&elt[0], t_name) &&
738
13.5M
            (pvalue = elt[0].value.pname->pvalue, pv_valid(pvalue))
739
13.5M
            )
740
0
            elt[0].value.pname->pvalue = pv_no_defn;
741
13.5M
        if ((code = dict_put(pdrto, &elt[0], &elt[1], pds)) < 0) {
742
            /*
743
             * If COPY_FOR_RESIZE is set, the dict_put isn't supposed to
744
             * be able to fail, but we don't want to depend on this.
745
             */
746
0
            if (pvalue != pv_no_defn)
747
0
                elt[0].value.pname->pvalue = pvalue;
748
0
            return code;
749
0
        }
750
13.5M
    }
751
947k
    return 0;
752
947k
}
753
int
754
dict_copy_entries(const ref *pdrfrom, ref *pdrto, bool new_only,
755
                  dict_stack_t *pds)
756
129k
{
757
129k
    return dict_copy_elements(pdrfrom, pdrto, (new_only ? COPY_NEW_ONLY : 0),
758
129k
                              pds);
759
129k
}
760
761
/* Resize a dictionary. */
762
int
763
dict_resize(ref * pdref, uint new_size, dict_stack_t *pds)
764
818k
{
765
818k
    dict *pdict = pdref->value.pdict;
766
818k
    gs_ref_memory_t *mem = dict_memory(pdict);
767
818k
    uint new_mask = imemory_new_mask(mem);
768
818k
    ushort orig_attrs = r_type_attrs(&pdict->values) & (a_all | a_executable);
769
818k
    dict dnew;
770
818k
    ref drto;
771
818k
    int code;
772
773
818k
    if (new_size < d_length(pdict)) {
774
0
        if (!mem->gs_lib_ctx->dict_auto_expand)
775
0
            return_error(gs_error_dictfull);
776
0
        new_size = d_length(pdict);
777
0
    }
778
818k
    make_tav(&drto, t_dictionary, r_space(pdref) | a_all | new_mask,
779
818k
             pdict, &dnew);
780
818k
    dnew.memory = pdict->memory;
781
818k
    if ((code = dict_create_contents(new_size, &drto, dict_is_packed(pdict))) < 0)
782
0
        return code;
783
    /*
784
     * We must suppress the store check, in case we are expanding
785
     * systemdict or another global dictionary that is allowed
786
     * to reference local objects.
787
     */
788
818k
    r_set_space(&drto, avm_local);
789
    /*
790
     * If we are expanding a permanent dictionary, we must make sure that
791
     * dict_put doesn't think this is a second definition for any
792
     * single-definition names.  This in turn requires that
793
     * dstack_dict_is_permanent must be true for the second ("to")
794
     * argument of dict_copy_elements, which requires temporarily
795
     * setting *pdref = drto.
796
     */
797
818k
    if (CAN_SET_PVALUE_CACHE(pds, pdref, mem)) {
798
8.71k
        ref drfrom;
799
800
8.71k
        drfrom = *pdref;
801
8.71k
        *pdref = drto;
802
8.71k
        dict_copy_elements(&drfrom, pdref, COPY_FOR_RESIZE, pds);
803
8.71k
        *pdref = drfrom;
804
809k
    } else {
805
809k
        dict_copy_elements(pdref, &drto, 0, pds);
806
809k
    }
807
    /* Save or free the old dictionary. */
808
818k
    if (ref_must_save_in(mem, &pdict->values))
809
13
        ref_do_save_in(mem, pdref, &pdict->values, "dict_resize(values)");
810
818k
    else
811
818k
        gs_free_ref_array(mem, &pdict->values, "dict_resize(old values)");
812
818k
    if (ref_must_save_in(mem, &pdict->keys))
813
13
        ref_do_save_in(mem, pdref, &pdict->keys, "dict_resize(keys)");
814
818k
    else
815
818k
        gs_free_ref_array(mem, &pdict->keys, "dict_resize(old keys)");
816
818k
    ref_assign(&pdict->keys, &dnew.keys);
817
818k
    ref_assign(&pdict->values, &dnew.values);
818
818k
    r_store_attrs(&pdict->values, a_all | a_executable, orig_attrs);
819
818k
    ref_save_in(dict_memory(pdict), pdref, &pdict->maxlength,
820
818k
                "dict_resize(maxlength)");
821
818k
    d_set_maxlength(pdict, new_size);
822
818k
    if (pds)
823
818k
        dstack_set_top(pds); /* just in case this is the top dict */
824
818k
    return 0;
825
818k
}
826
827
/* Grow a dictionary for dict_put. */
828
int
829
dict_grow(ref * pdref, dict_stack_t *pds)
830
216k
{
831
216k
    dict *pdict = pdref->value.pdict;
832
    /* We might have maxlength < npairs, if */
833
    /* dict_round_size increased the size. */
834
216k
    ulong new_size = (ulong) d_maxlength(pdict);
835
    /* Adobe does this */
836
216k
    if (new_size < 20)
837
169k
        new_size += 10;
838
47.6k
    else if (new_size < 200)
839
47.1k
        new_size *= 2;
840
491
    else
841
491
        new_size += new_size / 2;
842
216k
#if ARCH_SIZEOF_INT < ARCH_SIZEOF_LONG
843
216k
    if (new_size > max_uint)
844
0
        new_size = max_uint;
845
216k
#endif
846
216k
    if (new_size > npairs(pdict)) {
847
208k
        int code = dict_resize(pdref, (uint) new_size, pds);
848
849
208k
        if (code >= 0)
850
208k
            return code;
851
        /* new_size was too big. */
852
0
        if (npairs(pdict) < dict_max_size) {
853
0
            code = dict_resize(pdref, dict_max_size, pds);
854
0
            if (code >= 0)
855
0
                return code;
856
0
        }
857
0
        if (npairs(pdict) == d_maxlength(pdict)) { /* Can't do it. */
858
0
            return code;
859
0
        }
860
        /* We can't grow to new_size, but we can grow to npairs. */
861
0
        new_size = npairs(pdict);
862
0
    }
863
    /* maxlength < npairs, we can grow in place */
864
8.72k
    ref_save_in(dict_memory(pdict), pdref, &pdict->maxlength,
865
8.72k
                "dict_put(maxlength)");
866
8.72k
    d_set_maxlength(pdict, new_size);
867
8.72k
    return 0;
868
216k
}
869
870
/* Prepare to enumerate a dictionary. */
871
int
872
dict_first(const ref * pdref)
873
4.47M
{
874
4.47M
    return (int)nslots(pdref->value.pdict);
875
4.47M
}
876
877
/* Enumerate the next element of a dictionary. */
878
int
879
dict_next(const ref * pdref, int index, ref * eltp /* ref eltp[2] */ )
880
223M
{
881
223M
    dict *pdict = pdref->value.pdict;
882
223M
    ref *vp = pdict->values.value.refs + index;
883
884
538M
    while (vp--, --index >= 0) {
885
534M
        array_get(dict_mem(pdict), &pdict->keys, (long)index, eltp);
886
        /* Make sure this is a valid entry. */
887
534M
        if (r_has_type(eltp, t_name) ||
888
534M
            (!dict_is_packed(pdict) && !r_has_type(eltp, t_null))
889
534M
            ) {
890
219M
            eltp[1] = *vp;
891
219M
            if_debug6m('d', dict_mem(pdict), "[d]0x%lx: index %d: %lx %lx, %lx %lx\n",
892
219M
                       (intptr_t)pdict, index,
893
219M
                       ((ulong *) eltp)[0], ((ulong *) eltp)[1],
894
219M
                       ((ulong *) vp)[0], ((ulong *) vp)[1]);
895
219M
            return index;
896
219M
        }
897
534M
    }
898
4.45M
    return -1;     /* no more elements */
899
223M
}
900
901
/* Return the index of a value within a dictionary. */
902
int
903
dict_value_index(const ref * pdref, const ref * pvalue)
904
946k
{
905
946k
    return (int)(pvalue - pdref->value.pdict->values.value.refs - 1);
906
946k
}
907
908
/* Return the entry at a given index within a dictionary. */
909
/* If the index designates an unoccupied entry, return gs_error_undefined. */
910
int
911
dict_index_entry(const ref * pdref, int index, ref * eltp /* ref eltp[2] */ )
912
0
{
913
0
    const dict *pdict = pdref->value.pdict;
914
915
0
    array_get(dict_mem(pdict), &pdict->keys, (long)(index + 1), eltp);
916
0
    if (r_has_type(eltp, t_name) ||
917
0
        (!dict_is_packed(pdict) && !r_has_type(eltp, t_null))
918
0
        ) {
919
0
        eltp[1] = pdict->values.value.refs[index + 1];
920
0
        return 0;
921
0
    }
922
0
    return gs_error_undefined;
923
0
}