Coverage Report

Created: 2025-06-24 07:01

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