Coverage Report

Created: 2025-06-10 06:58

/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
93.7M
  (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
8.35M
{       /* 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
8.35M
    if (rsize > dict_max_non_huge)
131
8
        return (rsize > dict_max_size ? 0 : rsize);
132
17.8M
    while (rsize & (rsize - 1))
133
9.49M
        rsize = (rsize | (rsize - 1)) + 1;
134
8.35M
    return (rsize <= dict_max_size ? rsize : dict_max_non_huge);
135
8.35M
}
136
137
/* Create a dictionary using the given allocator. */
138
int
139
dict_alloc(gs_ref_memory_t * mem, uint size, ref * pdref)
140
7.33M
{
141
7.33M
    ref arr;
142
7.33M
    int code =
143
7.33M
        gs_alloc_ref_array(mem, &arr, a_all, sizeof(dict) / sizeof(ref),
144
7.33M
                           "dict_alloc");
145
7.33M
    dict *pdict;
146
7.33M
    ref dref;
147
148
7.33M
    if (code < 0)
149
0
        return code;
150
7.33M
    pdict = (dict *) arr.value.refs;
151
7.33M
    make_tav(&dref, t_dictionary,
152
7.33M
             r_space(&arr) | imemory_new_mask(mem) | a_all,
153
7.33M
             pdict, pdict);
154
7.33M
    make_struct(&pdict->memory, avm_foreign, mem);
155
7.33M
    code = dict_create_contents(size, &dref, dict_default_pack);
156
7.33M
    if (code < 0) {
157
8
        gs_free_ref_array(mem, &arr, "dict_alloc");
158
8
        return code;
159
8
    }
160
7.33M
    *pdref = dref;
161
7.33M
    return 0;
162
7.33M
}
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
4.95M
{
168
4.95M
    dict *pdict = pdref->value.pdict;
169
4.95M
    gs_ref_memory_t *mem = dict_memory(pdict);
170
4.95M
    int code;
171
172
4.95M
    code = gs_alloc_ref_array(mem, &pdict->keys, a_all, asize,
173
4.95M
                              "dict_create_unpacked_keys");
174
4.95M
    if (code >= 0) {
175
4.95M
        uint new_mask = imemory_new_mask(mem);
176
4.95M
        ref *kp = pdict->keys.value.refs;
177
178
4.95M
        r_set_attrs(&pdict->keys, new_mask);
179
4.95M
        refset_null_new(kp, asize, new_mask);
180
4.95M
        r_set_attrs(kp, a_executable); /* wraparound entry */
181
4.95M
    }
182
4.95M
    return code;
183
4.95M
}
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
8.35M
{
190
8.35M
    dict *pdict = pdref->value.pdict;
191
8.35M
    gs_ref_memory_t *mem = dict_memory(pdict);
192
8.35M
    uint new_mask = imemory_new_mask(mem);
193
8.35M
    uint asize = dict_round_size((size == 0 ? 1 : size));
194
8.35M
    int code;
195
8.35M
    register uint i;
196
197
8.35M
    if (asize == 0 || asize > max_array_size - 1)  /* too large */
198
8
        return_error(gs_error_limitcheck);
199
8.35M
    asize++;      /* allow room for wraparound entry */
200
8.35M
    code = gs_alloc_ref_array(mem, &pdict->values, a_all, asize,
201
8.35M
                              "dict_create_contents(values)");
202
8.35M
    if (code < 0)
203
0
        return code;
204
8.35M
    r_set_attrs(&pdict->values, new_mask);
205
8.35M
    refset_null_new(pdict->values.value.refs, asize, new_mask);
206
8.35M
    if (pack) {
207
7.60M
        uint ksize = (asize + packed_per_ref - 1) / packed_per_ref;
208
7.60M
        ref arr;
209
7.60M
        ref_packed *pkp;
210
7.60M
        ref_packed *pzp;
211
212
7.60M
        code = gs_alloc_ref_array(mem, &arr, a_all, ksize,
213
7.60M
                                  "dict_create_contents(packed keys)");
214
7.60M
        if (code < 0)
215
0
            return code;
216
7.60M
        pkp = (ref_packed *) arr.value.refs;
217
7.60M
        make_tasv(&pdict->keys, t_shortarray,
218
7.60M
                  r_space(&arr) | a_all | new_mask,
219
7.60M
                  asize, packed, pkp);
220
563M
        for (pzp = pkp, i = 0; i < asize || i % packed_per_ref; pzp++, i++)
221
556M
            *pzp = packed_key_empty;
222
7.60M
        *pkp = packed_key_deleted; /* wraparound entry */
223
7.60M
    } else {     /* not packed */
224
748k
        int code = dict_create_unpacked_keys(asize, pdref);
225
226
748k
        if (code < 0)
227
0
            return code;
228
748k
    }
229
8.35M
    make_tav(&pdict->count, t_integer, new_mask, intval, 0);
230
8.35M
    make_tav(&pdict->maxlength, t_integer, new_mask, intval, size);
231
8.35M
    return 0;
232
8.35M
}
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
4.20M
{
241
4.20M
    dict *pdict = pdref->value.pdict;
242
243
4.20M
    if (!dict_is_packed(pdict))
244
0
        return 0;   /* nothing to do */
245
4.20M
    {
246
4.20M
        gs_ref_memory_t *mem = dict_memory(pdict);
247
4.20M
        uint count = nslots(pdict);
248
4.20M
        const ref_packed *okp = pdict->keys.value.packed;
249
4.20M
        ref old_keys;
250
4.20M
        int code;
251
4.20M
        ref *nkp;
252
253
4.20M
        old_keys = pdict->keys;
254
4.20M
        if (ref_must_save_in(mem, &old_keys))
255
0
            ref_do_save_in(mem, pdref, &pdict->keys, "dict_unpack(keys)");
256
4.20M
        code = dict_create_unpacked_keys(count, pdref);
257
4.20M
        if (code < 0)
258
0
            return code;
259
423M
        for (nkp = pdict->keys.value.refs; count--; okp++, nkp++)
260
419M
            if (r_packed_is_name(okp)) {
261
13.9M
                packed_get((const gs_memory_t *)mem, okp, nkp);
262
13.9M
                ref_mark_new_in(mem, nkp);
263
405M
            } else if (*okp == packed_key_deleted)
264
4.98M
                r_set_attrs(nkp, a_executable);
265
4.20M
        if (!ref_must_save_in(mem, &old_keys))
266
4.20M
            gs_free_ref_array(mem, &old_keys, "dict_unpack(old keys)");
267
4.20M
        if (pds)
268
3.14M
            dstack_set_top(pds); /* just in case */
269
4.20M
    }
270
0
    return 0;
271
4.20M
}
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
948M
{
282
948M
    dict *pdict = pdref->value.pdict;
283
948M
    uint size = npairs(pdict);
284
948M
    register int etype;
285
948M
    uint nidx;
286
948M
    ref_packed kpack;
287
948M
    uint hash;
288
948M
    int ktype;
289
948M
    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
948M
    switch (r_type(pkey)) {
294
1.33M
    case t_string:    /* convert to a name first */
295
1.33M
        {
296
1.33M
            ref nref;
297
1.33M
            int code;
298
299
1.33M
            if (!r_has_attr(pkey, a_read))
300
0
                return_error(gs_error_invalidaccess);
301
1.33M
            code = name_ref(mem, pkey->value.bytes, r_size(pkey), &nref, 1);
302
1.33M
            if (code < 0)
303
0
                return code;
304
1.33M
            nidx = name_index(mem, &nref);
305
1.33M
        }
306
0
        goto nh;
307
903M
    case t_name:
308
903M
        nidx = name_index(mem, pkey);
309
905M
    nh:
310
905M
        hash = dict_name_index_hash(nidx);
311
905M
        kpack = packed_name_key(nidx);
312
905M
        ktype = t_name;
313
905M
        break;
314
49.9k
    case t_real:
315
        /*
316
         * Make sure that equal reals and integers hash the same.
317
         */
318
49.9k
        {
319
49.9k
            int expt, i;
320
49.9k
            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
49.9k
            if (expt < sizeof(long) * 8 || pkey->value.realval == min_long)
327
44.5k
                i = (int)pkey->value.realval;
328
5.37k
            else
329
5.37k
                i = (int)(mant * min_long); /* MSVC 6.00.8168.0 cannot compile this */
330
49.9k
            hash = (uint)i * 30503;         /*   with -O2 as a single expression    */
331
49.9k
        }
332
49.9k
        goto ih;
333
43.2M
    case t_integer:
334
43.2M
        hash = (uint)pkey->value.intval * 30503;
335
43.2M
    ih:
336
43.2M
        kpack = packed_key_impossible;
337
43.2M
        ktype = -1;
338
43.2M
        nidx = 0;   /* only to pacify gcc */
339
43.2M
        break;
340
1
    case t_null:    /* not allowed as a key */
341
1
        return_error(gs_error_typecheck);
342
455k
    default:
343
455k
        hash = r_btype(pkey) * 99;  /* yech */
344
455k
        kpack = packed_key_impossible;
345
455k
        ktype = -1;
346
455k
        nidx = 0;   /* only to pacify gcc */
347
948M
    }
348
    /* Search the dictionary */
349
948M
    if (dict_is_packed(pdict)) {
350
99.2M
        const ref_packed *pslot = 0;
351
352
99.2M
# define found *ppvalue = packed_search_value_pointer; return 1
353
99.2M
# define deleted if (pslot == 0) pslot = kp
354
99.2M
# define missing goto miss
355
99.2M
# include "idicttpl.h"
356
6.29M
# undef missing
357
6.29M
# undef deleted
358
6.29M
# 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
6.29M
        if (pslot == 0 || d_length(pdict) == d_maxlength(pdict))
365
6.29M
            return_error(gs_error_dictfull);
366
0
        *ppvalue = pdict->values.value.refs + (pslot - kbot);
367
0
        return 0;
368
60.5M
      miss:     /* Key is missing, not double wrap.  See above re dictfull. */
369
60.5M
        if (d_length(pdict) == d_maxlength(pdict))
370
4.48M
            return_error(gs_error_dictfull);
371
56.0M
        if (pslot == 0)
372
56.0M
            pslot = kp;
373
56.0M
        *ppvalue = pdict->values.value.refs + (pslot - kbot);
374
56.0M
        return 0;
375
849M
    } else {
376
849M
        ref *kbot = pdict->keys.value.refs;
377
849M
        register ref *kp;
378
849M
        ref *pslot = 0;
379
849M
        int wrap = 0;
380
381
15.4G
        for (kp = kbot + dict_hash_mod(hash, size) + 2;;) {
382
15.4G
            --kp;
383
15.4G
            if ((etype = r_type(kp)) == ktype) { /* Fast comparison if both keys are names */
384
14.6G
                if (name_index(mem, kp) == nidx) {
385
319M
                    *ppvalue = pdict->values.value.refs + (kp - kbot);
386
319M
                    return 1;
387
319M
                }
388
14.6G
            } else if (etype == t_null) { /* Empty, deleted, or wraparound. */
389
                /* Figure out which. */
390
603M
                if (kp == kbot) { /* wrap */
391
21.7M
                    if (wrap++) { /* wrapped twice */
392
4.26M
                        if (pslot == 0)
393
4.25M
                            return_error(gs_error_dictfull);
394
10.3k
                        break;
395
4.26M
                    }
396
17.5M
                    kp += size + 1;
397
581M
                } else if (r_has_attr(kp, a_executable)) { /* Deleted entry, save the slot. */
398
56.9M
                    if (pslot == 0)
399
30.6M
                        pslot = kp;
400
56.9M
                } else   /* key not found */
401
524M
                    break;
402
603M
            } else {
403
176M
                if (obj_eq(mem, kp, pkey)) {
404
990k
                    *ppvalue = pdict->values.value.refs + (kp - kbot);
405
990k
                    return 1;
406
990k
                }
407
176M
            }
408
15.4G
        }
409
524M
        if (d_length(pdict) == d_maxlength(pdict))
410
46.8M
            return_error(gs_error_dictfull);
411
477M
        *ppvalue = pdict->values.value.refs +
412
477M
            ((pslot != 0 ? pslot : kp) - kbot);
413
477M
        return 0;
414
524M
    }
415
948M
}
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
47.6M
{
424
47.6M
    int code;
425
47.6M
    ref kname;
426
47.6M
    if ( pdref != 0 ) {
427
47.5M
        dict *pdict = pdref->value.pdict;
428
429
47.5M
        if ((code = name_ref(dict_mem(pdict),
430
47.5M
                             (const byte *)kstr, strlen(kstr), &kname, -1)) < 0)
431
5.89M
            return code;
432
41.7M
        code = dict_find(pdref, &kname, ppvalue);
433
41.7M
        if (code == gs_error_dictfull)
434
470k
            return_error(gs_error_undefined);
435
41.2M
        return code;
436
41.7M
    }
437
10.3k
    return 0;
438
47.6M
}
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
527M
{
448
527M
    dict *pdict = pdref->value.pdict;
449
527M
    gs_ref_memory_t *mem = dict_memory(pdict);
450
527M
    gs_memory_t *pmem = dict_mem(pdict);
451
527M
    int rcode = 0;
452
527M
    int code;
453
527M
    ref *pvslot, kname;
454
455
    /* Check the value. */
456
527M
    store_check_dest(pdref, pvalue);
457
531M
  top:if ((code = dict_find(pdref, pkey, &pvslot)) <= 0) { /* not found *//* Check for overflow */
458
399M
        uint index;
459
460
399M
        switch (code) {
461
398M
            case 0:
462
398M
                break;
463
310k
            case gs_error_dictfull:
464
310k
                if (!pmem->gs_lib_ctx->dict_auto_expand)
465
0
                    return_error(gs_error_dictfull);
466
310k
                code = dict_grow(pdref, pds);
467
310k
                if (code < 0)
468
0
                    return code;
469
310k
                goto top; /* keep things simple */
470
310k
            default:    /* gs_error_typecheck */
471
0
                return code;
472
399M
        }
473
398M
        index = pvslot - pdict->values.value.refs;
474
        /* If the key is a string, convert it to a name. */
475
398M
        if (r_has_type(pkey, t_string)) {
476
752k
            int code;
477
478
752k
            if (!r_has_attr(pkey, a_read))
479
0
                return_error(gs_error_invalidaccess);
480
752k
            code = name_from_string(pmem, pkey, &kname);
481
752k
            if (code < 0)
482
0
                return code;
483
752k
            pkey = &kname;
484
752k
        }
485
398M
        if (dict_is_packed(pdict)) {
486
33.2M
            ref_packed *kp;
487
488
33.2M
            if (!r_has_type(pkey, t_name) ||
489
33.2M
                name_index(pmem, pkey) > packed_name_max_index
490
33.2M
                ) {   /* Change to unpacked representation. */
491
4.20M
                int code = dict_unpack(pdref, pds);
492
493
4.20M
                if (code < 0)
494
0
                    return code;
495
4.20M
                goto top;
496
4.20M
            }
497
29.0M
            kp = pdict->keys.value.writable_packed + index;
498
29.0M
            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
27.1k
                ref_do_save_in(mem, &pdict->keys, kp, "dict_put(key)");
502
27.1k
            }
503
29.0M
            *kp = pt_tag(pt_literal_name) + name_index(pmem, pkey);
504
365M
        } else {
505
365M
            ref *kp = pdict->keys.value.refs + index;
506
507
365M
            if_debug2m('d', (const gs_memory_t *)mem, "[d]"PRI_INTPTR": fill key at "PRI_INTPTR"\n",
508
365M
                       (intptr_t)pdict, (intptr_t)kp);
509
365M
            store_check_dest(pdref, pkey);
510
365M
            ref_assign_old_in(mem, &pdict->keys, kp, pkey,
511
365M
                              "dict_put(key)"); /* set key of pair */
512
365M
        }
513
394M
        ref_save_in(mem, pdref, &pdict->count, "dict_put(count)");
514
394M
        pdict->count.value.intval++;
515
        /* If the key is a name, update its 1-element cache. */
516
394M
        if (r_has_type(pkey, t_name)) {
517
353M
            name *pname = pkey->value.pname;
518
519
353M
            if (pname->pvalue == pv_no_defn &&
520
353M
                CAN_SET_PVALUE_CACHE(pds, pdref, mem)
521
353M
                ) {   /* Set the cache. */
522
10.2M
                if_debug0m('d', (const gs_memory_t *)mem, "[d]set cache\n");
523
10.2M
                pname->pvalue = pvslot;
524
343M
            } else {   /* The cache can't be used. */
525
343M
                if_debug0m('d', (const gs_memory_t *)mem, "[d]no cache\n");
526
343M
                pname->pvalue = pv_other;
527
343M
            }
528
353M
        }
529
394M
        rcode = 1;
530
394M
    }
531
531M
    if_debug8m('d', (const gs_memory_t *)mem,
532
527M
               "[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
527M
               (intptr_t) pdref->value.pdict,
534
527M
               ((const ulong *)pkey)[0], ((const ulong *)pkey)[1],
535
527M
               (intptr_t) pvslot,
536
527M
               ((const ulong *)pvslot)[0], ((const ulong *)pvslot)[1],
537
527M
               ((const ulong *)pvalue)[0], ((const ulong *)pvalue)[1]);
538
527M
    ref_assign_old_in(mem, &pdref->value.pdict->values, pvslot, pvalue,
539
527M
                      "dict_put(value)");
540
527M
    return rcode;
541
531M
}
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
6.22M
{
550
6.22M
    int code;
551
6.22M
    ref kname;
552
6.22M
    dict *pdict = pdref->value.pdict;
553
554
6.22M
    if ((code = name_ref(dict_mem(pdict),
555
6.22M
                         (const byte *)kstr, strlen(kstr), &kname, 0)) < 0)
556
0
        return code;
557
6.22M
    return dict_put(pdref, &kname, pvalue, pds);
558
6.22M
}
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
154k
{
567
154k
    int code;
568
154k
    ref kname;
569
154k
    dict *pdict = pdref->value.pdict;
570
571
154k
    if ((code = name_ref(dict_mem(pdict),
572
154k
                         (const byte *)kstr, strlen(kstr), &kname, 1)) < 0)
573
0
        return code;
574
154k
    return dict_put(pdref, &kname, pvalue, pds);
575
154k
}
576
577
/* Remove an element from a dictionary. */
578
int
579
dict_undef(ref * pdref, const ref * pkey, dict_stack_t *pds)
580
26.0M
{
581
26.0M
    gs_ref_memory_t *mem;
582
26.0M
    ref *pvslot;
583
26.0M
    dict *pdict;
584
26.0M
    uint index;
585
26.0M
    int code = dict_find(pdref, pkey, &pvslot);
586
587
26.0M
    switch (code) {
588
1.18M
    case 0:
589
1.18M
    case gs_error_dictfull:
590
1.18M
        return_error(gs_error_undefined);
591
24.8M
    case 1:
592
24.8M
        break;
593
0
    default:      /* other error */
594
0
        return code;
595
26.0M
    }
596
    /* Remove the entry from the dictionary. */
597
24.8M
    pdict = pdref->value.pdict;
598
24.8M
    index = pvslot - pdict->values.value.refs;
599
24.8M
    mem = dict_memory(pdict);
600
24.8M
    if (dict_is_packed(pdict)) {
601
1.42M
        ref_packed *pkp = pdict->keys.value.writable_packed + index;
602
1.42M
        bool must_save = ref_must_save_in(mem, &pdict->keys);
603
604
1.42M
        if_debug3m('d', (const gs_memory_t *)mem,
605
1.42M
                   "[d]"PRI_INTPTR": removing key at "PRI_INTPTR": 0x%x\n",
606
1.42M
                   (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.42M
        if (must_save)
610
9.10k
            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.42M
        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
627k
            uint end = nslots(pdict);
623
624
627k
            *pkp = packed_key_empty;
625
627k
            if (must_save) {
626
9.10k
                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
618k
            } else {
631
618k
                while (++index < end && *++pkp == packed_key_deleted)
632
0
                    *pkp = packed_key_empty;
633
618k
            }
634
627k
        } else
635
793k
            *pkp = packed_key_deleted;
636
23.4M
    } else {     /* not packed */
637
23.4M
        ref *kp = pdict->keys.value.refs + index;
638
639
23.4M
        if_debug4m('d', (const gs_memory_t *)mem,
640
23.4M
                   "[d]"PRI_INTPTR": removing key at "PRI_INTPTR": 0x%lx 0x%lx\n",
641
23.4M
                   (intptr_t)pdict, (intptr_t)kp, ((ulong *)kp)[0], ((ulong *)kp)[1]);
642
23.4M
        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
23.4M
        if (!r_has_type(kp - 1, t_null) || /* full entry */
650
23.4M
            r_has_attr(kp - 1, a_executable)  /* deleted or wraparound */
651
23.4M
            )
652
15.5M
            r_set_attrs(kp, a_executable); /* mark as deleted */
653
23.4M
    }
654
24.8M
    ref_save_in(mem, pdref, &pdict->count, "dict_undef(count)");
655
24.8M
    pdict->count.value.intval--;
656
    /* If the key is a name, update its 1-element cache. */
657
24.8M
    if (r_has_type(pkey, t_name)) {
658
24.8M
        name *pname = pkey->value.pname;
659
660
24.8M
        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.58M
            pname->pvalue = pv_no_defn;
669
1.58M
        }
670
24.8M
    }
671
24.8M
    make_null_old_in(mem, &pdict->values, pvslot, "dict_undef(value)");
672
24.8M
    return 0;
673
26.0M
}
674
675
/* Return the number of elements in a dictionary. */
676
uint
677
dict_length(const ref * pdref /* t_dictionary */ )
678
8.74M
{
679
8.74M
    return d_length(pdref->value.pdict);
680
8.74M
}
681
682
/* Return the capacity of a dictionary. */
683
uint
684
dict_maxlength(const ref * pdref /* t_dictionary */ )
685
5.92M
{
686
5.92M
    return d_maxlength(pdref->value.pdict);
687
5.92M
}
688
689
/* Return the maximum index of a slot within a dictionary. */
690
uint
691
dict_max_index(const ref * pdref /* t_dictionary */ )
692
382k
{
693
382k
    return npairs(pdref->value.pdict) - 1;
694
382k
}
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
93.1M
#define COPY_NEW_ONLY 1
704
91.7M
#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
1.18M
{
710
1.18M
    int space = r_space(pdrto);
711
1.18M
    int index;
712
1.18M
    ref elt[2];
713
1.18M
    ref *pvslot;
714
1.18M
    int code;
715
716
1.18M
    if (space != avm_max) {
717
        /* Do the store check before starting the copy. */
718
145k
        index = dict_first(pdrfrom);
719
1.43M
        while ((index = dict_next(pdrfrom, index, elt)) >= 0)
720
1.29M
            if (!(options & COPY_NEW_ONLY) ||
721
1.29M
                dict_find(pdrto, &elt[0], &pvslot) <= 0
722
1.29M
                ) {
723
1.29M
                store_check_space(space, &elt[0]);
724
1.29M
                store_check_space(space, &elt[1]);
725
1.29M
            }
726
145k
    }
727
    /* Now copy the contents. */
728
1.18M
    index = dict_first(pdrfrom);
729
92.9M
    while ((index = dict_next(pdrfrom, index, elt)) >= 0) {
730
91.8M
        ref *pvalue = pv_no_defn;
731
732
91.8M
        if ((options & COPY_NEW_ONLY) &&
733
91.8M
            dict_find(pdrto, &elt[0], &pvslot) > 0
734
91.8M
            )
735
36.3k
            continue;
736
91.7M
        if ((options & COPY_FOR_RESIZE) &&
737
91.7M
            r_has_type(&elt[0], t_name) &&
738
91.7M
            (pvalue = elt[0].value.pname->pvalue, pv_valid(pvalue))
739
91.7M
            )
740
0
            elt[0].value.pname->pvalue = pv_no_defn;
741
91.7M
        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
91.7M
    }
751
1.18M
    return 0;
752
1.18M
}
753
int
754
dict_copy_entries(const ref *pdrfrom, ref *pdrto, bool new_only,
755
                  dict_stack_t *pds)
756
163k
{
757
163k
    return dict_copy_elements(pdrfrom, pdrto, (new_only ? COPY_NEW_ONLY : 0),
758
163k
                              pds);
759
163k
}
760
761
/* Resize a dictionary. */
762
int
763
dict_resize(ref * pdref, uint new_size, dict_stack_t *pds)
764
1.01M
{
765
1.01M
    dict *pdict = pdref->value.pdict;
766
1.01M
    gs_ref_memory_t *mem = dict_memory(pdict);
767
1.01M
    uint new_mask = imemory_new_mask(mem);
768
1.01M
    ushort orig_attrs = r_type_attrs(&pdict->values) & (a_all | a_executable);
769
1.01M
    dict dnew;
770
1.01M
    ref drto;
771
1.01M
    int code;
772
773
1.01M
    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
1.01M
    make_tav(&drto, t_dictionary, r_space(pdref) | a_all | new_mask,
779
1.01M
             pdict, &dnew);
780
1.01M
    dnew.memory = pdict->memory;
781
1.01M
    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
1.01M
    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
1.01M
    if (CAN_SET_PVALUE_CACHE(pds, pdref, mem)) {
798
10.3k
        ref drfrom;
799
800
10.3k
        drfrom = *pdref;
801
10.3k
        *pdref = drto;
802
10.3k
        dict_copy_elements(&drfrom, pdref, COPY_FOR_RESIZE, pds);
803
10.3k
        *pdref = drfrom;
804
1.00M
    } else {
805
1.00M
        dict_copy_elements(pdref, &drto, 0, pds);
806
1.00M
    }
807
    /* Save or free the old dictionary. */
808
1.01M
    if (ref_must_save_in(mem, &pdict->values))
809
199
        ref_do_save_in(mem, pdref, &pdict->values, "dict_resize(values)");
810
1.01M
    else
811
1.01M
        gs_free_ref_array(mem, &pdict->values, "dict_resize(old values)");
812
1.01M
    if (ref_must_save_in(mem, &pdict->keys))
813
199
        ref_do_save_in(mem, pdref, &pdict->keys, "dict_resize(keys)");
814
1.01M
    else
815
1.01M
        gs_free_ref_array(mem, &pdict->keys, "dict_resize(old keys)");
816
1.01M
    ref_assign(&pdict->keys, &dnew.keys);
817
1.01M
    ref_assign(&pdict->values, &dnew.values);
818
1.01M
    r_store_attrs(&pdict->values, a_all | a_executable, orig_attrs);
819
1.01M
    ref_save_in(dict_memory(pdict), pdref, &pdict->maxlength,
820
1.01M
                "dict_resize(maxlength)");
821
1.01M
    d_set_maxlength(pdict, new_size);
822
1.01M
    if (pds)
823
1.01M
        dstack_set_top(pds); /* just in case this is the top dict */
824
1.01M
    return 0;
825
1.01M
}
826
827
/* Grow a dictionary for dict_put. */
828
int
829
dict_grow(ref * pdref, dict_stack_t *pds)
830
310k
{
831
310k
    dict *pdict = pdref->value.pdict;
832
    /* We might have maxlength < npairs, if */
833
    /* dict_round_size increased the size. */
834
310k
    ulong new_size = (ulong) d_maxlength(pdict);
835
    /* Adobe does this */
836
310k
    if (new_size < 20)
837
213k
        new_size += 10;
838
96.8k
    else if (new_size < 200)
839
42.3k
        new_size *= 2;
840
54.5k
    else
841
54.5k
        new_size += new_size / 2;
842
310k
#if ARCH_SIZEOF_INT < ARCH_SIZEOF_LONG
843
310k
    if (new_size > max_uint)
844
0
        new_size = max_uint;
845
310k
#endif
846
310k
    if (new_size > npairs(pdict)) {
847
297k
        int code = dict_resize(pdref, (uint) new_size, pds);
848
849
297k
        if (code >= 0)
850
297k
            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
12.7k
    ref_save_in(dict_memory(pdict), pdref, &pdict->maxlength,
865
12.7k
                "dict_put(maxlength)");
866
12.7k
    d_set_maxlength(pdict, new_size);
867
12.7k
    return 0;
868
310k
}
869
870
/* Prepare to enumerate a dictionary. */
871
int
872
dict_first(const ref * pdref)
873
4.76M
{
874
4.76M
    return (int)nslots(pdref->value.pdict);
875
4.76M
}
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
301M
{
881
301M
    dict *pdict = pdref->value.pdict;
882
301M
    ref *vp = pdict->values.value.refs + index;
883
884
615M
    while (vp--, --index >= 0) {
885
610M
        array_get(dict_mem(pdict), &pdict->keys, (long)index, eltp);
886
        /* Make sure this is a valid entry. */
887
610M
        if (r_has_type(eltp, t_name) ||
888
610M
            (!dict_is_packed(pdict) && !r_has_type(eltp, t_null))
889
610M
            ) {
890
296M
            eltp[1] = *vp;
891
296M
            if_debug6m('d', dict_mem(pdict), "[d]0x%lx: index %d: %lx %lx, %lx %lx\n",
892
296M
                       (intptr_t)pdict, index,
893
296M
                       ((ulong *) eltp)[0], ((ulong *) eltp)[1],
894
296M
                       ((ulong *) vp)[0], ((ulong *) vp)[1]);
895
296M
            return index;
896
296M
        }
897
610M
    }
898
4.73M
    return -1;     /* no more elements */
899
301M
}
900
901
/* Return the index of a value within a dictionary. */
902
int
903
dict_value_index(const ref * pdref, const ref * pvalue)
904
1.57M
{
905
1.57M
    return (int)(pvalue - pdref->value.pdict->values.value.refs - 1);
906
1.57M
}
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
}