Coverage Report

Created: 2025-06-10 06:56

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