Coverage Report

Created: 2025-06-10 06:56

/src/ghostpdl/base/gsmchunk.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
/* chunk consolidating wrapper on a base memory allocator */
18
19
/* This uses dual binary trees to handle the free list. One tree
20
 * holds the blocks in size order, one in location order. We use
21
 * a top-down semi-splaying access scheme on lookups and
22
 * insertions. */
23
24
#include "memory_.h"
25
#include "gx.h"
26
#include "gsstruct.h"
27
#include "gxobj.h"
28
#include "gsstype.h"
29
#include "gserrors.h"
30
#include "gsmchunk.h"
31
#include "gxsync.h"
32
#include "malloc_.h" /* For MEMENTO */
33
#include "assert_.h"
34
#include "gsmdebug.h"
35
36
/* Enable DEBUG_CHUNK to check the validity of the heap at every turn */
37
#undef DEBUG_CHUNK
38
39
/* Enable DEBUG_SEQ to keep sequence numbers in every block */
40
#undef DEBUG_SEQ
41
42
/* Enable DEBUG_CHUNK_PRINT to print the heap at every turn */
43
#undef DEBUG_CHUNK_PRINT
44
45
/* Enable DEBUG_CHUNK_PRINT_SLABS to list the slabs in the heap */
46
#undef DEBUG_CHUNK_PRINT_SLABS
47
48
#if defined(DEBUG_CHUNK_PRINT_SLABS) && !defined(DEBUG_CHUNK_PRINT)
49
#define DEBUG_CHUNK_PRINT
50
#endif
51
52
#if defined(DEBUG_CHUNK_PRINT) && !defined(DEBUG_CHUNK)
53
#define DEBUG_CHUNK
54
#endif
55
56
#if defined(DEBUG_CHUNK) && !defined(DEBUG)
57
#define DEBUG
58
#define CHUNK_FAKE_ASSERT
59
#endif
60
61
#ifdef DEBUG
62
#ifdef CHUNK_FAKE_ASSERT
63
#define CHUNK_ASSERT(M,A) gs_chunk_assert(M, A, #A)
64
65
static void gs_chunk_assert(gs_memory_t *m, int v, const char *s)
66
{
67
    void (*crash)(void);
68
    if (v)
69
        return;
70
    dmlprintf1(m, "Assert failed: %s\n", s);
71
    crash = NULL;
72
    crash();
73
}
74
#else
75
#define CHUNK_ASSERT(M,A) assert(A)
76
#endif
77
#endif
78
79
/* Raw memory procedures */
80
static gs_memory_proc_alloc_bytes(chunk_alloc_bytes_immovable);
81
static gs_memory_proc_resize_object(chunk_resize_object);
82
static gs_memory_proc_free_object(chunk_free_object);
83
static gs_memory_proc_stable(chunk_stable);
84
static gs_memory_proc_status(chunk_status);
85
static gs_memory_proc_free_all(chunk_free_all);
86
static gs_memory_proc_consolidate_free(chunk_consolidate_free);
87
88
/* Object memory procedures */
89
static gs_memory_proc_alloc_bytes(chunk_alloc_bytes);
90
static gs_memory_proc_alloc_struct(chunk_alloc_struct);
91
static gs_memory_proc_alloc_struct(chunk_alloc_struct_immovable);
92
static gs_memory_proc_alloc_byte_array(chunk_alloc_byte_array);
93
static gs_memory_proc_alloc_byte_array(chunk_alloc_byte_array_immovable);
94
static gs_memory_proc_alloc_struct_array(chunk_alloc_struct_array);
95
static gs_memory_proc_alloc_struct_array(chunk_alloc_struct_array_immovable);
96
static gs_memory_proc_object_size(chunk_object_size);
97
static gs_memory_proc_object_type(chunk_object_type);
98
static gs_memory_proc_alloc_string(chunk_alloc_string);
99
static gs_memory_proc_alloc_string(chunk_alloc_string_immovable);
100
static gs_memory_proc_resize_string(chunk_resize_string);
101
static gs_memory_proc_free_string(chunk_free_string);
102
static gs_memory_proc_register_root(chunk_register_root);
103
static gs_memory_proc_unregister_root(chunk_unregister_root);
104
static gs_memory_proc_enable_free(chunk_enable_free);
105
static gs_memory_proc_set_object_type(chunk_set_object_type);
106
static gs_memory_proc_defer_frees(chunk_defer_frees);
107
static const gs_memory_procs_t chunk_procs =
108
{
109
    /* Raw memory procedures */
110
    chunk_alloc_bytes_immovable,
111
    chunk_resize_object,
112
    chunk_free_object,
113
    chunk_stable,
114
    chunk_status,
115
    chunk_free_all,
116
    chunk_consolidate_free,
117
    /* Object memory procedures */
118
    chunk_alloc_bytes,
119
    chunk_alloc_struct,
120
    chunk_alloc_struct_immovable,
121
    chunk_alloc_byte_array,
122
    chunk_alloc_byte_array_immovable,
123
    chunk_alloc_struct_array,
124
    chunk_alloc_struct_array_immovable,
125
    chunk_object_size,
126
    chunk_object_type,
127
    chunk_alloc_string,
128
    chunk_alloc_string_immovable,
129
    chunk_resize_string,
130
    chunk_free_string,
131
    chunk_register_root,
132
    chunk_unregister_root,
133
    chunk_enable_free,
134
    chunk_set_object_type,
135
    chunk_defer_frees
136
};
137
138
typedef struct chunk_obj_node_s {
139
    gs_memory_type_ptr_t type;
140
#ifdef DEBUG_SEQ
141
    unsigned int sequence;
142
#endif
143
    struct chunk_obj_node_s *defer_next;
144
    size_t size; /* Actual size of block */
145
    size_t padding; /* Actual size - requested size */
146
} chunk_obj_node_t;
147
148
typedef struct chunk_free_node_s {
149
    struct chunk_free_node_s *left_loc;
150
    struct chunk_free_node_s *right_loc;
151
    struct chunk_free_node_s *left_size;
152
    struct chunk_free_node_s *right_size;
153
    size_t size;                  /* size of entire freelist block */
154
} chunk_free_node_t;
155
156
/*
157
 * Note: All objects within a chunk are 'aligned' since we round_up_to_align
158
 * the free list pointer when removing part of a free area.
159
 */
160
typedef struct chunk_slab_s {
161
    struct chunk_slab_s *next;
162
} chunk_slab_t;
163
164
typedef struct gs_memory_chunk_s {
165
    gs_memory_common;           /* interface outside world sees */
166
    gs_memory_t *target;        /* base allocator */
167
    chunk_slab_t *slabs;         /* list of slabs for freeing */
168
    chunk_free_node_t *free_size;/* free tree */
169
    chunk_free_node_t *free_loc; /* free tree */
170
    chunk_obj_node_t *defer_finalize_list;
171
    chunk_obj_node_t *defer_free_list;
172
    size_t used;
173
    size_t max_used;
174
    size_t total_free;
175
#ifdef DEBUG_SEQ
176
    unsigned int sequence;
177
#endif
178
    int deferring;
179
} gs_memory_chunk_t;
180
181
536M
#define SIZEOF_ROUND_ALIGN(a) ROUND_UP(sizeof(a), obj_align_mod)
182
183
/* ---------- Public constructors/destructors ---------- */
184
185
/* Initialize a gs_memory_chunk_t */
186
int
187
gs_memory_chunk_wrap(gs_memory_t **wrapped,      /* chunk allocator init */
188
                    gs_memory_t  *target)       /* base allocator */
189
15.7k
{
190
    /* Use the non-GC allocator of the target. */
191
15.7k
    gs_memory_t       *non_gc_target = target->non_gc_memory;
192
15.7k
    gs_memory_chunk_t *cmem = NULL;
193
194
15.7k
    if (non_gc_target)
195
15.7k
        cmem = (gs_memory_chunk_t *)gs_alloc_bytes_immovable(non_gc_target,
196
15.7k
                                                            sizeof(gs_memory_chunk_t),
197
15.7k
                                                            "gs_memory_chunk_wrap");
198
15.7k
    if (cmem == NULL) {
199
0
        *wrapped = NULL;
200
0
        return_error(gs_error_VMerror);
201
0
    }
202
15.7k
    cmem->stable_memory = (gs_memory_t *)cmem;  /* we are stable */
203
15.7k
    cmem->procs = chunk_procs;
204
15.7k
    cmem->gs_lib_ctx = non_gc_target->gs_lib_ctx;
205
15.7k
    cmem->non_gc_memory = (gs_memory_t *)cmem;  /* and are not subject to GC */
206
15.7k
    cmem->thread_safe_memory = non_gc_target->thread_safe_memory;
207
15.7k
    cmem->target = non_gc_target;
208
15.7k
    cmem->slabs = NULL;
209
15.7k
    cmem->free_size = NULL;
210
15.7k
    cmem->free_loc = NULL;
211
15.7k
    cmem->used = 0;
212
15.7k
    cmem->max_used = 0;
213
15.7k
    cmem->total_free = 0;
214
#ifdef DEBUG_SEQ
215
    cmem->sequence = 0;
216
#endif
217
15.7k
    cmem->deferring = 0;
218
15.7k
    cmem->defer_finalize_list = NULL;
219
15.7k
    cmem->defer_free_list = NULL;
220
221
#ifdef DEBUG_CHUNK_PRINT
222
    dmlprintf1(non_gc_target, "New chunk "PRI_INTPTR"\n", (intptr_t)cmem);
223
#endif
224
225
    /* Init the chunk management values */
226
15.7k
    *wrapped = (gs_memory_t *)cmem;
227
15.7k
    return 0;
228
15.7k
}
229
230
/* Release a chunk memory manager. */
231
/* Note that this has no effect on the target. */
232
void
233
gs_memory_chunk_release(gs_memory_t *mem)
234
15.7k
{
235
15.7k
    gs_memory_free_all((gs_memory_t *)mem, FREE_ALL_EVERYTHING,
236
15.7k
                       "gs_memory_chunk_release");
237
15.7k
}
238
239
/* Release chunk memory manager, and return the target */
240
gs_memory_t * /* Always succeeds */
241
gs_memory_chunk_unwrap(gs_memory_t *mem)
242
6.04k
{
243
6.04k
    gs_memory_t *tmem;
244
245
    /* If this isn't a chunk, nothing to unwrap */
246
6.04k
    if (mem->procs.status != chunk_status)
247
0
        return mem;
248
249
6.04k
    tmem = ((gs_memory_chunk_t *)mem)->target;
250
6.04k
    gs_memory_chunk_release(mem);
251
252
6.04k
    return tmem;
253
6.04k
}
254
255
/* ---------- Accessors ------------- */
256
257
/* Retrieve this allocator's target */
258
gs_memory_t *
259
gs_memory_chunk_target(const gs_memory_t *mem)
260
0
{
261
0
    gs_memory_chunk_t *cmem = (gs_memory_chunk_t *)mem;
262
0
    return cmem->target;
263
0
}
264
265
/* -------- Private members --------- */
266
267
/* Note that all of the data is 'immovable' and is opaque to the base allocator */
268
/* thus even if it is a GC type of allocator, no GC functions will be applied   */
269
/* All allocations are done in the target */
270
271
/* Procedures */
272
273
static void
274
chunk_mem_node_free_all_slabs(gs_memory_chunk_t *cmem)
275
15.7k
{
276
15.7k
    chunk_slab_t *slab, *next;
277
15.7k
    gs_memory_t *const target = cmem->target;
278
279
66.5k
    for (slab = cmem->slabs; slab != NULL; slab = next) {
280
50.8k
        next = slab->next;
281
50.8k
        gs_free_object(target, slab, "chunk_mem_node_free_all_slabs");
282
50.8k
    }
283
284
15.7k
    cmem->slabs = NULL;
285
15.7k
    cmem->free_size = NULL;
286
15.7k
    cmem->free_loc = NULL;
287
15.7k
    cmem->total_free = 0;
288
15.7k
    cmem->used = 0;
289
15.7k
}
290
291
static void
292
chunk_free_all(gs_memory_t * mem, uint free_mask, client_name_t cname)
293
15.7k
{
294
15.7k
    gs_memory_chunk_t * const cmem = (gs_memory_chunk_t *)mem;
295
15.7k
    gs_memory_t * const target = cmem->target;
296
297
15.7k
    if (free_mask & FREE_ALL_DATA)
298
15.7k
        chunk_mem_node_free_all_slabs(cmem);
299
    /* Only free the structures and the allocator itself. */
300
15.7k
    if (mem->stable_memory) {
301
15.7k
        if (mem->stable_memory != mem)
302
0
            gs_memory_free_all(mem->stable_memory, free_mask, cname);
303
15.7k
        if (free_mask & FREE_ALL_ALLOCATOR)
304
15.7k
            mem->stable_memory = 0;
305
15.7k
    }
306
15.7k
    if (free_mask & FREE_ALL_STRUCTURES) {
307
15.7k
        cmem->target = 0;
308
15.7k
    }
309
15.7k
    if (free_mask & FREE_ALL_ALLOCATOR)
310
15.7k
        gs_free_object(target, cmem, cname);
311
15.7k
}
312
313
extern const gs_memory_struct_type_t st_bytes;
314
315
#ifdef DEBUG
316
static int dump_free_loc(gs_memory_t *mem, chunk_free_node_t *node, int depth, void **limit, uint *total)
317
{
318
#ifdef DEBUG_CHUNK_PRINT
319
    int i;
320
#endif
321
    int count;
322
323
    if (node == NULL)
324
        return 0;
325
326
    count = dump_free_loc(mem, node->left_loc, depth + 1 + (depth&1), limit, total);
327
    *total += node->size;
328
#ifdef DEBUG_CHUNK_PRINT
329
    if (depth != 0) {
330
        for (i = (depth-1)>>1; i != 0; i--)
331
            dmlprintf(mem, " ");
332
        if (depth & 1)
333
            dmlprintf(mem, "/");
334
        else
335
            dmlprintf(mem, "\\");
336
    }
337
    dmlprintf3(mem, PRI_INTPTR"+%x->"PRI_INTPTR"\n", (intptr_t)node, node->size, (intptr_t)((byte *)node)+node->size);
338
#endif
339
    CHUNK_ASSERT(mem, *limit < (void *)node);
340
    *limit = ((byte *)node)+node->size;
341
    return 1 + count + dump_free_loc(mem, node->right_loc, depth + 2 + (depth&1), limit, total);
342
}
343
344
static int dump_free_size(gs_memory_t *mem, chunk_free_node_t *node, int depth, uint *size, void **addr)
345
{
346
#ifdef DEBUG_CHUNK_PRINT
347
    int i;
348
#endif
349
    int count;
350
351
    if (node == NULL)
352
        return 0;
353
354
    count = dump_free_size(mem, node->left_size, depth + 1 + (depth&1), size, addr);
355
#ifdef DEBUG_CHUNK_PRINT
356
    if (depth != 0) {
357
        for (i = (depth-1)>>1; i != 0; i--)
358
            dmlprintf(mem, " ");
359
        if (depth & 1)
360
            dmlprintf(mem, "/");
361
        else
362
            dmlprintf(mem, "\\");
363
    }
364
    dmlprintf3(mem, PRI_INTPTR"+%x->"PRI_INTPTR"\n", (intptr_t)node, node->size, (intptr_t)((byte *)node)+node->size);
365
#endif
366
    CHUNK_ASSERT(mem, *size < node->size || (*size == node->size && *addr < (void *)node));
367
    *size = node->size;
368
    *addr = node;
369
    return 1 + count + dump_free_size(mem, node->right_size, depth + 2 + (depth&1), size, addr);
370
}
371
372
#ifdef DEBUG_CHUNK_PRINT
373
static size_t
374
largest_free_block(chunk_free_node_t *size)
375
{
376
    if (size == NULL)
377
        return 0;
378
    while (1) {
379
        if (size->right_size == NULL)
380
            return size->size;
381
        size = size->right_size;
382
    }
383
}
384
#endif
385
386
void
387
gs_memory_chunk_dump_memory(const gs_memory_t *mem)
388
{
389
    const gs_memory_chunk_t *cmem = (const gs_memory_chunk_t *)mem;
390
    int count1, count2;
391
    void *limit = NULL;
392
    void *addr = NULL;
393
    uint size = 1;
394
    uint total = 0;
395
396
#ifdef DEBUG_CHUNK_PRINT
397
    dmlprintf1(cmem->target, "Chunk "PRI_INTPTR":\n", (intptr_t)cmem);
398
    dmlprintf3(cmem->target, "Used=%"PRIxSIZE", Max Used=%"PRIxSIZE", Total Free=%"PRIxSIZE"\n", cmem->used, cmem->max_used, cmem->total_free);
399
    dmlprintf1(cmem->target, "Largest free block=%d bytes\n", largest_free_block(cmem->free_size));
400
#ifdef DEBUG_CHUNK_PRINT_SLABS
401
    {
402
        chunk_slab_t *slab;
403
        dmlprintf(cmem->target, "Slabs:\n");
404
        for (slab = cmem->slabs; slab != NULL; slab = slab->next)
405
            dmlprintf1(cmem->target, " "PRI_INTPTR"\n", (intptr_t)slab);
406
    }
407
#endif
408
    dmlprintf(cmem->target, "Locs:\n");
409
#endif
410
    count1 = dump_free_loc(cmem->target, cmem->free_loc, 0, &limit, &total);
411
#ifdef DEBUG_CHUNK_PRINT
412
    dmlprintf(cmem->target, "Sizes:\n");
413
#endif
414
    count2 = dump_free_size(cmem->target, cmem->free_size, 0, &size, &addr);
415
    if (count1 != count2) {
416
        void (*crash)(void) = NULL;
417
        dmlprintf2(cmem->target, "Tree mismatch! %d vs %d\n", count1, count2);
418
        crash();
419
    }
420
    if (total != cmem->total_free) {
421
        void (*crash)(void) = NULL;
422
        dmlprintf2(cmem->target, "Free size mismatch! %u vs %lu\n", total, cmem->total_free);
423
        crash();
424
    }
425
}
426
#endif
427
428
/* round up objects to make sure we have room for a header left */
429
inline static uint
430
round_up_to_align(uint size)
431
76.6M
{
432
76.6M
    uint num_node_headers = (size + SIZEOF_ROUND_ALIGN(chunk_obj_node_t) - 1) / SIZEOF_ROUND_ALIGN(chunk_obj_node_t);
433
434
76.6M
    return num_node_headers * SIZEOF_ROUND_ALIGN(chunk_obj_node_t);
435
76.6M
}
436
437
static inline int CMP_SIZE(const chunk_free_node_t * a, const chunk_free_node_t * b)
438
436M
{
439
436M
    if (a->size > b->size)
440
197M
        return 1;
441
238M
    if (a->size < b->size)
442
202M
        return 0;
443
35.9M
    return (a > b);
444
238M
}
445
446
static void insert_free_size(gs_memory_chunk_t *cmem, chunk_free_node_t *node)
447
128M
{
448
128M
    chunk_free_node_t **ap;
449
128M
    chunk_free_node_t *a, *b, *c;
450
451
128M
    node->left_size  = NULL;
452
128M
    node->right_size = NULL;
453
454
    /* Insert into size */
455
128M
    ap = &cmem->free_size;
456
174M
    while ((a = *ap) != NULL) {
457
146M
        if (CMP_SIZE(a, node)) {
458
38.4M
            b = a->left_size;
459
38.4M
            if (b == NULL) {
460
6.17M
                ap = &a->left_size;
461
6.17M
                break; /* Stop searching */
462
6.17M
            }
463
32.2M
            if (CMP_SIZE(b, node)) {
464
12.3M
                c = b->left_size;
465
12.3M
                if (c == NULL) {
466
2.07M
                    ap = &b->left_size;
467
2.07M
                    break;
468
2.07M
                }
469
                /* Splay:        a             c
470
                 *            b     Z   =>  W     b
471
                 *          c   Y               X   a
472
                 *         W X                     Y Z
473
                 */
474
10.2M
                *ap = c;
475
10.2M
                a->left_size  = b->right_size;
476
10.2M
                b->left_size  = c->right_size;
477
10.2M
                b->right_size = a;
478
10.2M
                c->right_size = b;
479
10.2M
                if (CMP_SIZE(c, node))
480
5.76M
                    ap = &c->left_size;
481
4.47M
                else
482
4.47M
                    ap = &b->left_size;
483
19.9M
            } else {
484
19.9M
                c = b->right_size;
485
19.9M
                if (c == NULL) {
486
12.4M
                    ap = &b->right_size;
487
12.4M
                    break;
488
12.4M
                }
489
                /* Splay:         a             c
490
                 *            b       Z  =>   b   a
491
                 *          W   c            W X Y Z
492
                 *             X Y
493
                 */
494
7.54M
                *ap = c;
495
7.54M
                a->left_size  = c->right_size;
496
7.54M
                b->right_size = c->left_size;
497
7.54M
                c->left_size  = b;
498
7.54M
                c->right_size = a;
499
7.54M
                if (CMP_SIZE(c, node))
500
5.06M
                    ap = &b->right_size;
501
2.48M
                else
502
2.48M
                    ap = &a->left_size;
503
7.54M
            }
504
108M
        } else {
505
108M
            b = a->right_size;
506
108M
            if (b == NULL)
507
15.7M
            {
508
15.7M
                ap = &a->right_size;
509
15.7M
                break;
510
15.7M
            }
511
92.6M
            if (CMP_SIZE(b, node)) {
512
78.8M
                c = b->left_size;
513
78.8M
                if (c == NULL) {
514
61.2M
                    ap = &b->left_size;
515
61.2M
                    break;
516
61.2M
                }
517
                /* Splay:      a                c
518
                 *         W       b    =>    a   b
519
                 *               c   Z       W X Y Z
520
                 *              X Y
521
                 */
522
17.6M
                *ap = c;
523
17.6M
                a->right_size = c->left_size;
524
17.6M
                b->left_size  = c->right_size;
525
17.6M
                c->left_size  = a;
526
17.6M
                c->right_size = b;
527
17.6M
                if (CMP_SIZE(c, node))
528
14.4M
                    ap = &a->right_size;
529
3.18M
                else
530
3.18M
                    ap = &b->left_size;
531
17.6M
            } else {
532
13.7M
                c = b->right_size;
533
13.7M
                if (c == NULL) {
534
2.80M
                    ap = &b->right_size;
535
2.80M
                    break;
536
2.80M
                }
537
                /* Splay:    a                   c
538
                 *        W     b      =>     b     Z
539
                 *            X   c         a   Y
540
                 *               Y Z       W X
541
                 */
542
10.9M
                *ap = c;
543
10.9M
                a->right_size = b->left_size;
544
10.9M
                b->right_size = c->left_size;
545
10.9M
                b->left_size  = a;
546
10.9M
                c->left_size  = b;
547
10.9M
                if (CMP_SIZE(c, node))
548
5.54M
                    ap = &b->right_size;
549
5.43M
                else
550
5.43M
                    ap = &c->right_size;
551
10.9M
            }
552
92.6M
        }
553
146M
    }
554
128M
    *ap = node;
555
128M
}
556
557
static void insert_free_loc(gs_memory_chunk_t *cmem, chunk_free_node_t *node)
558
51.8M
{
559
51.8M
    chunk_free_node_t **ap;
560
51.8M
    chunk_free_node_t *a, *b, *c;
561
562
51.8M
    node->left_loc   = NULL;
563
51.8M
    node->right_loc  = NULL;
564
565
    /* Insert into loc */
566
51.8M
    ap = &cmem->free_loc;
567
63.2M
    while ((a = *ap) != NULL) {
568
55.1M
        if (a > node) {
569
18.1M
            b = a->left_loc;
570
18.1M
            if (b == NULL) {
571
6.12M
                ap = &a->left_loc;
572
6.12M
                break; /* Stop searching */
573
6.12M
            }
574
12.0M
            if (b > node) {
575
4.32M
                c = b->left_loc;
576
4.32M
                if (c == NULL) {
577
2.05M
                    ap = &b->left_loc;
578
2.05M
                    break;
579
2.05M
                }
580
                /* Splay:        a             c
581
                 *            b     Z   =>  W     b
582
                 *          c   Y               X   a
583
                 *         W X                     Y Z
584
                 */
585
2.27M
                *ap = c;
586
2.27M
                a->left_loc  = b->right_loc;
587
2.27M
                b->left_loc  = c->right_loc;
588
2.27M
                b->right_loc = a;
589
2.27M
                c->right_loc = b;
590
2.27M
                if (c > node)
591
1.13M
                    ap = &c->left_loc;
592
1.13M
                else
593
1.13M
                    ap = &b->left_loc;
594
7.71M
            } else {
595
7.71M
                c = b->right_loc;
596
7.71M
                if (c == NULL) {
597
6.77M
                    ap = &b->right_loc;
598
6.77M
                    break;
599
6.77M
                }
600
                /* Splay:         a             c
601
                 *            b       Z  =>   b   a
602
                 *          W   c            W X Y Z
603
                 *             X Y
604
                 */
605
935k
                *ap = c;
606
935k
                a->left_loc  = c->right_loc;
607
935k
                b->right_loc = c->left_loc;
608
935k
                c->left_loc  = b;
609
935k
                c->right_loc = a;
610
935k
                if (c > node)
611
767k
                    ap = &b->right_loc;
612
167k
                else
613
167k
                    ap = &a->left_loc;
614
935k
            }
615
37.0M
        } else {
616
37.0M
            b = a->right_loc;
617
37.0M
            if (b == NULL)
618
5.10M
            {
619
5.10M
                ap = &a->right_loc;
620
5.10M
                break;
621
5.10M
            }
622
31.9M
            if (b > node) {
623
22.2M
                c = b->left_loc;
624
22.2M
                if (c == NULL) {
625
20.5M
                    ap = &b->left_loc;
626
20.5M
                    break;
627
20.5M
                }
628
                /* Splay:      a                c
629
                 *         W       b    =>    a   b
630
                 *               c   Z       W X Y Z
631
                 *              X Y
632
                 */
633
1.71M
                *ap = c;
634
1.71M
                a->right_loc = c->left_loc;
635
1.71M
                b->left_loc  = c->right_loc;
636
1.71M
                c->left_loc  = a;
637
1.71M
                c->right_loc = b;
638
1.71M
                if (c > node)
639
1.58M
                    ap = &a->right_loc;
640
134k
                else
641
134k
                    ap = &b->left_loc;
642
9.60M
            } else {
643
9.60M
                c = b->right_loc;
644
9.60M
                if (c == NULL) {
645
3.19M
                    ap = &b->right_loc;
646
3.19M
                    break;
647
3.19M
                }
648
                /* Splay:    a                   c
649
                 *        W     b      =>     b     Z
650
                 *            X   c         a   Y
651
                 *               Y Z       W X
652
                 */
653
6.41M
                *ap = c;
654
6.41M
                a->right_loc = b->left_loc;
655
6.41M
                b->right_loc = c->left_loc;
656
6.41M
                b->left_loc  = a;
657
6.41M
                c->left_loc  = b;
658
6.41M
                if (c > node)
659
2.84M
                    ap = &b->right_loc;
660
3.56M
                else
661
3.56M
                    ap = &c->right_loc;
662
6.41M
            }
663
31.9M
        }
664
55.1M
    }
665
51.8M
    *ap = node;
666
51.8M
}
667
668
static void insert_free(gs_memory_chunk_t *cmem, chunk_free_node_t *node, uint size)
669
51.8M
{
670
51.8M
    node->size = size;
671
51.8M
    insert_free_size(cmem, node);
672
51.8M
    insert_free_loc(cmem, node);
673
51.8M
}
674
675
static void remove_free_loc(gs_memory_chunk_t *cmem, chunk_free_node_t *node)
676
83.8M
{
677
83.8M
    chunk_free_node_t **ap = &cmem->free_loc;
678
679
222M
    while (*ap != node)
680
138M
    {
681
138M
        if (*ap > node)
682
68.4M
            ap = &(*ap)->left_loc;
683
70.2M
        else
684
70.2M
            ap = &(*ap)->right_loc;
685
138M
    }
686
687
83.8M
    if (node->left_loc == NULL)
688
62.2M
        *ap = node->right_loc;
689
21.6M
    else if (node->right_loc == NULL)
690
3.55M
        *ap = node->left_loc;
691
18.0M
    else {
692
        /* Find the in-order predecessor to node and use that to replace node */
693
18.0M
        chunk_free_node_t **bp;
694
18.0M
        chunk_free_node_t  *b;
695
18.0M
        bp = &node->left_loc;
696
20.7M
        while ((*bp)->right_loc)
697
2.67M
            bp = &(*bp)->right_loc;
698
18.0M
        b = (*bp);
699
18.0M
        *bp = b->left_loc;
700
18.0M
        b->left_loc = node->left_loc;
701
18.0M
        b->right_loc = node->right_loc;
702
18.0M
        *ap = b;
703
18.0M
    }
704
83.8M
}
705
706
static void remove_free_size(gs_memory_chunk_t *cmem, chunk_free_node_t *node)
707
51.8M
{
708
51.8M
    chunk_free_node_t **ap = &cmem->free_size;
709
710
169M
    while (*ap != node)
711
118M
    {
712
118M
        if (CMP_SIZE(*ap, node))
713
60.1M
            ap = &(*ap)->left_size;
714
57.9M
        else
715
57.9M
            ap = &(*ap)->right_size;
716
118M
    }
717
718
51.8M
    if (node->left_size == NULL)
719
41.1M
        *ap = node->right_size;
720
10.6M
    else if (node->right_size == NULL)
721
2.33M
        *ap = node->left_size;
722
8.34M
    else {
723
        /* Find the in-order predecessor to node and use that to replace node */
724
8.34M
        chunk_free_node_t **bp;
725
8.34M
        chunk_free_node_t  *b;
726
8.34M
        bp = &node->left_size;
727
12.0M
        while ((*bp)->right_size)
728
3.67M
            bp = &(*bp)->right_size;
729
8.34M
        b = (*bp);
730
8.34M
        *bp = b->left_size;
731
8.34M
        b->left_size = node->left_size;
732
8.34M
        b->right_size = node->right_size;
733
8.34M
        *ap = b;
734
8.34M
    }
735
51.8M
}
736
737
static void remove_free_size_fast(gs_memory_chunk_t *cmem, chunk_free_node_t **ap)
738
76.4M
{
739
76.4M
    chunk_free_node_t *node = *ap;
740
741
76.4M
    if (node->left_size == NULL)
742
31.1M
        *ap = node->right_size;
743
45.3M
    else if (node->right_size == NULL)
744
2.37M
        *ap = node->left_size;
745
42.9M
    else {
746
        /* Find the in-order predecessor to node and use that to replace node */
747
42.9M
        chunk_free_node_t **bp;
748
42.9M
        chunk_free_node_t  *b;
749
42.9M
        bp = &node->left_size;
750
43.2M
        while ((*bp)->right_size)
751
299k
            bp = &(*bp)->right_size;
752
42.9M
        b = (*bp);
753
42.9M
        *bp = b->left_size;
754
42.9M
        b->left_size = node->left_size;
755
42.9M
        b->right_size = node->right_size;
756
42.9M
        *ap = b;
757
42.9M
    }
758
76.4M
}
759
760
static void remove_free(gs_memory_chunk_t *cmem, chunk_free_node_t *node)
761
7.32M
{
762
7.32M
    remove_free_loc(cmem, node);
763
7.32M
    remove_free_size(cmem, node);
764
7.32M
}
765
766
#if defined(MEMENTO) || defined(SINGLE_OBJECT_MEMORY_BLOCKS_ONLY)
767
#define SINGLE_OBJECT_CHUNK(size) (1)
768
#else
769
153M
#define SINGLE_OBJECT_CHUNK(size) ((size) > (CHUNK_SIZE>>1))
770
#endif
771
772
/* All of the allocation routines reduce to this function */
773
static byte *
774
chunk_obj_alloc(gs_memory_t *mem, size_t size, gs_memory_type_ptr_t type, client_name_t cname)
775
76.6M
{
776
76.6M
    gs_memory_chunk_t  *cmem = (gs_memory_chunk_t *)mem;
777
76.6M
    chunk_free_node_t **ap, **okp;
778
76.6M
    chunk_free_node_t  *a, *b, *c;
779
76.6M
    size_t newsize;
780
76.6M
    chunk_obj_node_t *obj = NULL;
781
782
76.6M
    newsize = round_up_to_align(size + SIZEOF_ROUND_ALIGN(chunk_obj_node_t));  /* space we will need */
783
    /* When we free this block it might have to go in free - so it had
784
     * better be large enough to accommodate a complete free node! */
785
76.6M
    if (newsize < SIZEOF_ROUND_ALIGN(chunk_free_node_t))
786
43.7k
        newsize = SIZEOF_ROUND_ALIGN(chunk_free_node_t);
787
    /* Protect against overflow */
788
76.6M
    if (newsize < size)
789
219
        return NULL;
790
791
#ifdef DEBUG_SEQ
792
    cmem->sequence++;
793
#endif
794
795
#ifdef DEBUG_CHUNK_PRINT
796
#ifdef DEBUG_SEQ
797
    dmlprintf4(mem, "Event %x: malloc(chunk="PRI_INTPTR", size=%"PRIxSIZE", cname=%s)\n",
798
               cmem->sequence, (intptr_t)cmem, newsize, cname);
799
#else
800
    dmlprintf3(mem, "malloc(chunk="PRI_INTPTR", size=%"PRIxSIZE", cname=%s)\n",
801
               (intptr_t)cmem, newsize, cname);
802
#endif
803
#endif
804
805
    /* Large blocks are allocated directly */
806
76.6M
    if (SINGLE_OBJECT_CHUNK(size)) {
807
93.3k
        obj = (chunk_obj_node_t *)gs_alloc_bytes_immovable(cmem->target, newsize, cname);
808
93.3k
        if (obj == NULL)
809
1
            return NULL;
810
76.5M
    } else {
811
        /* Find the smallest free block that's large enough */
812
        /* okp points to the parent pointer to the block we pick */
813
76.5M
        ap = &cmem->free_size;
814
76.5M
        okp = NULL;
815
131M
        while ((a = *ap) != NULL) {
816
86.2M
            if (a->size >= newsize) {
817
31.1M
                b = a->left_size;
818
31.1M
                if (b == NULL) {
819
4.83M
                    okp = ap; /* a will do */
820
4.83M
                    break; /* Stop searching */
821
4.83M
                }
822
26.3M
                if (b->size >= newsize) {
823
8.07M
                    c = b->left_size;
824
8.07M
                    if (c == NULL) {
825
1.83M
                        okp = &a->left_size; /* b is as good as we're going to get */
826
1.83M
                        break;
827
1.83M
                    }
828
                    /* Splay:        a             c
829
                     *            b     Z   =>  W     b
830
                     *          c   Y               X   a
831
                     *         W X                     Y Z
832
                     */
833
6.23M
                    *ap = c;
834
6.23M
                    a->left_size  = b->right_size;
835
6.23M
                    b->left_size  = c->right_size;
836
6.23M
                    b->right_size = a;
837
6.23M
                    c->right_size = b;
838
6.23M
                    if (c->size >= newsize) {
839
3.50M
                        okp = ap; /* c is the best so far */
840
3.50M
                        ap = &c->left_size;
841
3.50M
                    } else {
842
2.72M
                        okp = &c->right_size; /* b is the best so far */
843
2.72M
                        ap = &b->left_size;
844
2.72M
                    }
845
18.2M
                } else {
846
18.2M
                    c = b->right_size;
847
18.2M
                    if (c == NULL) {
848
6.33M
                        okp = ap; /* a is as good as we are going to get */
849
6.33M
                        break;
850
6.33M
                    }
851
                    /* Splay:         a             c
852
                     *            b       Z  =>   b   a
853
                     *          W   c            W X Y Z
854
                     *             X Y
855
                     */
856
11.9M
                    *ap = c;
857
11.9M
                    a->left_size  = c->right_size;
858
11.9M
                    b->right_size = c->left_size;
859
11.9M
                    c->left_size  = b;
860
11.9M
                    c->right_size = a;
861
11.9M
                    if (c->size >= newsize) {
862
10.5M
                        okp = ap; /* c is the best so far */
863
10.5M
                        ap = &b->right_size;
864
10.5M
                    } else {
865
1.36M
                        okp = &c->right_size; /* a is the best so far */
866
1.36M
                        ap = &a->left_size;
867
1.36M
                    }
868
11.9M
                }
869
55.0M
            } else {
870
55.0M
                b = a->right_size;
871
55.0M
                if (b == NULL)
872
731k
                    break; /* No better match to be found */
873
54.2M
                if (b->size >= newsize) {
874
47.0M
                    c = b->left_size;
875
47.0M
                    if (c == NULL) {
876
17.3M
                        okp = &a->right_size; /* b is as good as we're going to get */
877
17.3M
                        break;
878
17.3M
                    }
879
                    /* Splay:      a                c
880
                     *         W       b    =>    a   b
881
                     *               c   Z       W X Y Z
882
                     *              X Y
883
                     */
884
29.7M
                    *ap = c;
885
29.7M
                    a->right_size = c->left_size;
886
29.7M
                    b->left_size  = c->right_size;
887
29.7M
                    c->left_size  = a;
888
29.7M
                    c->right_size = b;
889
29.7M
                    if (c->size >= newsize) {
890
25.4M
                        okp = ap; /* c is the best so far */
891
25.4M
                        ap = &a->right_size;
892
25.4M
                    } else {
893
4.30M
                        okp = &c->right_size; /* b is the best so far */
894
4.30M
                        ap = &b->left_size;
895
4.30M
                    }
896
29.7M
                } else {
897
7.20M
                    c = b->right_size;
898
7.20M
                    if (c == NULL)
899
65.1k
                        break; /* No better match to be found */
900
                    /* Splay:    a                   c
901
                     *        W     b      =>     b     Z
902
                     *            X   c         a   Y
903
                     *               Y Z       W X
904
                     */
905
7.13M
                    *ap = c;
906
7.13M
                    a->right_size = b->left_size;
907
7.13M
                    b->right_size = c->left_size;
908
7.13M
                    b->left_size  = a;
909
7.13M
                    c->left_size  = b;
910
7.13M
                    if (c->size >= newsize) {
911
3.74M
                        okp = ap; /* c is the best so far */
912
3.74M
                        ap = &b->right_size;
913
3.74M
                    } else
914
3.38M
                        ap = &c->right_size;
915
7.13M
                }
916
54.2M
            }
917
86.2M
        }
918
919
        /* So *okp points to the most appropriate free tree entry. */
920
921
76.5M
        if (okp == NULL) {
922
            /* No appropriate free space slot. We need to allocate a new slab. */
923
50.8k
            chunk_slab_t *slab;
924
50.8k
            uint slab_size = newsize + SIZEOF_ROUND_ALIGN(chunk_slab_t);
925
926
50.8k
            if (slab_size <= (CHUNK_SIZE>>1))
927
46.7k
                slab_size = CHUNK_SIZE;
928
50.8k
            slab = (chunk_slab_t *)gs_alloc_bytes_immovable(cmem->target, slab_size, cname);
929
50.8k
            if (slab == NULL)
930
0
                return NULL;
931
50.8k
            slab->next = cmem->slabs;
932
50.8k
            cmem->slabs = slab;
933
934
50.8k
            obj = (chunk_obj_node_t *)(((byte *)slab) + SIZEOF_ROUND_ALIGN(chunk_slab_t));
935
50.8k
            if (slab_size != newsize + SIZEOF_ROUND_ALIGN(chunk_slab_t)) {
936
46.7k
                insert_free(cmem, (chunk_free_node_t *)(((byte *)obj)+newsize), slab_size - newsize - SIZEOF_ROUND_ALIGN(chunk_slab_t));
937
46.7k
                cmem->total_free += slab_size - newsize - SIZEOF_ROUND_ALIGN(chunk_slab_t);
938
46.7k
            }
939
76.4M
        } else {
940
76.4M
            chunk_free_node_t *ok = *okp;
941
76.4M
            obj = (chunk_obj_node_t *)(void *)ok;
942
76.4M
            if (ok->size >= newsize + SIZEOF_ROUND_ALIGN(chunk_free_node_t)) {
943
51.8M
                chunk_free_node_t *tail = (chunk_free_node_t *)(((byte *)ok) + newsize);
944
51.8M
                uint tail_size = ok->size - newsize;
945
51.8M
                remove_free_size_fast(cmem, okp);
946
51.8M
                remove_free_loc(cmem, ok);
947
51.8M
                insert_free(cmem, tail, tail_size);
948
51.8M
            } else {
949
24.6M
                newsize = ok->size;
950
24.6M
                remove_free_size_fast(cmem, okp);
951
24.6M
                remove_free_loc(cmem, ok);
952
24.6M
            }
953
76.4M
            cmem->total_free -= newsize;
954
76.4M
        }
955
76.5M
    }
956
957
76.6M
    if (gs_alloc_debug) {
958
0
        memset((byte *)(obj) + SIZEOF_ROUND_ALIGN(chunk_obj_node_t), 0xa1, newsize - SIZEOF_ROUND_ALIGN(chunk_obj_node_t));
959
0
        memset((byte *)(obj) + SIZEOF_ROUND_ALIGN(chunk_obj_node_t), 0xac, size);
960
0
    }
961
962
76.6M
    cmem->used += newsize;
963
76.6M
    obj->size = newsize; /* actual size */
964
76.6M
    obj->padding = newsize - size; /* actual size - client requested size */
965
76.6M
    obj->type = type;    /* and client desired type */
966
76.6M
    obj->defer_next = NULL;
967
968
#ifdef DEBUG_SEQ
969
    obj->sequence = cmem->sequence;
970
#endif
971
76.6M
    if (gs_debug_c('A'))
972
0
        dmlprintf3(mem, "[a+]chunk_obj_alloc (%s)(%"PRIuSIZE") = "PRI_INTPTR": OK.\n",
973
76.6M
                   client_name_string(cname), size, (intptr_t) obj);
974
#ifdef DEBUG_CHUNK_PRINT
975
#ifdef DEBUG_SEQ
976
    dmlprintf5(mem, "Event %x: malloced(chunk="PRI_INTPTR", addr="PRI_INTPTR", size=%"PRIxSIZE", cname=%s)\n",
977
               obj->sequence, (intptr_t)cmem, (intptr_t)obj, obj->size, cname);
978
#else
979
    dmlprintf4(mem, "malloced(chunk="PRI_INTPTR", addr="PRI_INTPTR", size=%"PRIxSIZE", cname=%s)\n",
980
               (intptr_t)cmem, (intptr_t)obj, obj->size, cname);
981
#endif
982
#endif
983
#ifdef DEBUG_CHUNK
984
    gs_memory_chunk_dump_memory(cmem);
985
#endif
986
987
76.6M
    return (byte *)Memento_label((byte *)(obj) + SIZEOF_ROUND_ALIGN(chunk_obj_node_t), cname);
988
76.6M
}
989
990
static byte *
991
chunk_alloc_bytes_immovable(gs_memory_t * mem, size_t size, client_name_t cname)
992
63.9k
{
993
63.9k
    return chunk_obj_alloc(mem, size, &st_bytes, cname);
994
63.9k
}
995
996
static byte *
997
chunk_alloc_bytes(gs_memory_t * mem, size_t size, client_name_t cname)
998
72.3M
{
999
72.3M
    return chunk_obj_alloc(mem, size, &st_bytes, cname);
1000
72.3M
}
1001
1002
static void *
1003
chunk_alloc_struct_immovable(gs_memory_t * mem, gs_memory_type_ptr_t pstype,
1004
                             client_name_t cname)
1005
104k
{
1006
104k
    return chunk_obj_alloc(mem, pstype->ssize, pstype, cname);
1007
104k
}
1008
1009
static void *
1010
chunk_alloc_struct(gs_memory_t * mem, gs_memory_type_ptr_t pstype,
1011
                   client_name_t cname)
1012
4.08M
{
1013
4.08M
    return chunk_obj_alloc(mem, pstype->ssize, pstype, cname);
1014
4.08M
}
1015
1016
static byte *
1017
chunk_alloc_byte_array_immovable(gs_memory_t * mem, size_t num_elements,
1018
                                 size_t elt_size, client_name_t cname)
1019
163k
{
1020
163k
    return chunk_alloc_bytes(mem, num_elements * elt_size, cname);
1021
163k
}
1022
1023
static byte *
1024
chunk_alloc_byte_array(gs_memory_t * mem, size_t num_elements, size_t elt_size,
1025
                   client_name_t cname)
1026
7.52M
{
1027
7.52M
    return chunk_alloc_bytes(mem, num_elements * elt_size, cname);
1028
7.52M
}
1029
1030
static void *
1031
chunk_alloc_struct_array_immovable(gs_memory_t * mem, size_t num_elements,
1032
                                   gs_memory_type_ptr_t pstype, client_name_t cname)
1033
2.83k
{
1034
2.83k
    return chunk_obj_alloc(mem, num_elements * pstype->ssize, pstype, cname);
1035
2.83k
}
1036
1037
static void *
1038
chunk_alloc_struct_array(gs_memory_t * mem, size_t num_elements,
1039
                         gs_memory_type_ptr_t pstype, client_name_t cname)
1040
21.4k
{
1041
21.4k
    return chunk_obj_alloc(mem, num_elements * pstype->ssize, pstype, cname);
1042
21.4k
}
1043
1044
static void *
1045
chunk_resize_object(gs_memory_t * mem, void *ptr, size_t new_num_elements, client_name_t cname)
1046
32.8k
{
1047
32.8k
    void *new_ptr = NULL;
1048
1049
32.8k
    if (ptr != NULL) {
1050
        /* This isn't particularly efficient, but it is rarely used */
1051
32.8k
        chunk_obj_node_t *obj = (chunk_obj_node_t *)(((byte *)ptr) - SIZEOF_ROUND_ALIGN(chunk_obj_node_t));
1052
32.8k
        size_t new_size = (obj->type->ssize * new_num_elements);
1053
32.8k
        size_t old_size = obj->size - obj->padding;
1054
        /* get the type from the old object */
1055
32.8k
        gs_memory_type_ptr_t type = obj->type;
1056
32.8k
        gs_memory_chunk_t *cmem = (gs_memory_chunk_t *)mem;
1057
32.8k
        size_t save_max_used = cmem->max_used;
1058
1059
32.8k
        if (new_size == old_size)
1060
4.40k
            return ptr;
1061
28.4k
        if ((new_ptr = chunk_obj_alloc(mem, new_size, type, cname)) == 0)
1062
0
            return NULL;
1063
28.4k
        memcpy(new_ptr, ptr, min(old_size, new_size));
1064
28.4k
        chunk_free_object(mem, ptr, cname);
1065
28.4k
        cmem->max_used = save_max_used;
1066
28.4k
        if (cmem->used > cmem->max_used)
1067
15.5k
            cmem->max_used = cmem->used;
1068
28.4k
    }
1069
1070
28.4k
    return new_ptr;
1071
32.8k
}
1072
1073
static void
1074
chunk_free_object(gs_memory_t *mem, void *ptr, client_name_t cname)
1075
78.3M
{
1076
78.3M
    gs_memory_chunk_t * const cmem = (gs_memory_chunk_t *)mem;
1077
78.3M
    size_t obj_node_size;
1078
78.3M
    chunk_obj_node_t *obj;
1079
78.3M
    struct_proc_finalize((*finalize));
1080
78.3M
    chunk_free_node_t **ap, **gtp, **ltp;
1081
78.3M
    chunk_free_node_t *a, *b, *c;
1082
1083
78.3M
    if (ptr == NULL)
1084
1.73M
        return;
1085
1086
    /* back up to obj header */
1087
76.6M
    obj_node_size = SIZEOF_ROUND_ALIGN(chunk_obj_node_t);
1088
76.6M
    obj = (chunk_obj_node_t *)(((byte *)ptr) - obj_node_size);
1089
1090
76.6M
    if (cmem->deferring) {
1091
0
        if (obj->defer_next == NULL) {
1092
0
            obj->defer_next = cmem->defer_finalize_list;
1093
0
            cmem->defer_finalize_list = obj;
1094
0
        }
1095
0
        return;
1096
0
    }
1097
1098
#ifdef DEBUG_CHUNK_PRINT
1099
#ifdef DEBUG_SEQ
1100
    cmem->sequence++;
1101
    dmlprintf6(cmem->target, "Event %x: free(chunk="PRI_INTPTR", addr="PRI_INTPTR", size=%x, num=%x, cname=%s)\n",
1102
               cmem->sequence, (intptr_t)cmem, (intptr_t)obj, obj->size, obj->sequence, cname);
1103
#else
1104
    dmlprintf4(cmem->target, "free(chunk="PRI_INTPTR", addr="PRI_INTPTR", size=%x, cname=%s)\n",
1105
               (intptr_t)cmem, (intptr_t)obj, obj->size, cname);
1106
#endif
1107
#endif
1108
1109
76.6M
    if (obj->type) {
1110
76.6M
        finalize = obj->type->finalize;
1111
76.6M
        if (finalize != NULL)
1112
3.04M
            finalize(mem, ptr);
1113
76.6M
    }
1114
    /* finalize may change the head_**_chunk doing free of stuff */
1115
1116
76.6M
    if_debug3m('A', cmem->target, "[a-]chunk_free_object(%s) "PRI_INTPTR"(%"PRIuSIZE")\n",
1117
76.6M
               client_name_string(cname), (intptr_t)ptr, obj->size);
1118
1119
76.6M
    cmem->used -= obj->size;
1120
1121
76.6M
    if (SINGLE_OBJECT_CHUNK(obj->size - obj->padding)) {
1122
93.3k
        gs_free_object(cmem->target, obj, "chunk_free_object(single object)");
1123
#ifdef DEBUG_CHUNK
1124
        gs_memory_chunk_dump_memory(cmem);
1125
#endif
1126
93.3k
        return;
1127
93.3k
    }
1128
1129
    /* We want to find where to insert this free entry into our free tree. We need to know
1130
     * both the point to the left of it, and the point to the right of it, in order to see
1131
     * if we can merge the free entries. Accordingly, we search from the top of the tree
1132
     * and keep pointers to the nodes that we pass that are greater than it, and less than
1133
     * it. */
1134
76.5M
    gtp = NULL; /* gtp is set to the address of the pointer to the node where we last stepped left */
1135
76.5M
    ltp = NULL; /* ltp is set to the address of the pointer to the node where we last stepped right */
1136
76.5M
    ap = &cmem->free_loc;
1137
125M
    while ((a = *ap) != NULL) {
1138
95.8M
        if ((void *)a > (void *)obj) {
1139
49.6M
            b = a->left_loc; /* Try to step left from a */
1140
49.6M
            if (b == NULL) {
1141
7.62M
                gtp = ap; /* a is greater than us */
1142
7.62M
                break;
1143
7.62M
            }
1144
42.0M
            if ((void *)b > (void *)obj) {
1145
20.7M
                c = b->left_loc; /* Try to step left from b */
1146
20.7M
                if (c == NULL) {
1147
6.37M
                    gtp = &a->left_loc; /* b is greater than us */
1148
6.37M
                    break;
1149
6.37M
                }
1150
                /* Splay:        a             c
1151
                 *            b     Z   =>  W     b
1152
                 *          c   Y               X   a
1153
                 *         W X                     Y Z
1154
                 */
1155
14.3M
                *ap = c;
1156
14.3M
                a->left_loc  = b->right_loc;
1157
14.3M
                b->left_loc  = c->right_loc;
1158
14.3M
                b->right_loc = a;
1159
14.3M
                c->right_loc = b;
1160
14.3M
                if ((void *)c > (void *)obj) { /* W */
1161
8.49M
                    gtp = ap; /* c is greater than us */
1162
8.49M
                    ap = &c->left_loc;
1163
8.49M
                } else { /* X */
1164
5.89M
                    gtp = &c->right_loc; /* b is greater than us */
1165
5.89M
                    ltp = ap; /* c is less than us */
1166
5.89M
                    ap = &b->left_loc;
1167
5.89M
                }
1168
21.3M
            } else {
1169
21.3M
                c = b->right_loc; /* Try to step right from b */
1170
21.3M
                if (c == NULL) {
1171
12.3M
                    gtp = ap; /* a is greater than us */
1172
12.3M
                    ltp = &a->left_loc; /* b is less than us */
1173
12.3M
                    break;
1174
12.3M
                }
1175
                /* Splay:         a             c
1176
                 *            b       Z  =>   b   a
1177
                 *          W   c            W X Y Z
1178
                 *             X Y
1179
                 */
1180
8.91M
                *ap = c;
1181
8.91M
                a->left_loc  = c->right_loc;
1182
8.91M
                b->right_loc = c->left_loc;
1183
8.91M
                c->left_loc  = b;
1184
8.91M
                c->right_loc = a;
1185
8.91M
                if ((void *)c > (void *)obj) { /* X */
1186
5.38M
                    gtp = ap; /* c is greater than us */
1187
5.38M
                    ltp = &c->left_loc; /* b is less than us */
1188
5.38M
                    ap = &b->right_loc;
1189
5.38M
                } else { /* Y */
1190
3.53M
                    gtp = &c->right_loc; /* a is greater than us */
1191
3.53M
                    ltp = ap; /* c is less than us */
1192
3.53M
                    ap = &a->left_loc;
1193
3.53M
                }
1194
8.91M
            }
1195
46.1M
        } else {
1196
46.1M
            b = a->right_loc; /* Try to step right from a */
1197
46.1M
            if (b == NULL) {
1198
3.43M
                ltp = ap; /* a is less than us */
1199
3.43M
                break;
1200
3.43M
            }
1201
42.7M
            if ((void *)b > (void *)obj) {
1202
32.2M
                c = b->left_loc;
1203
32.2M
                if (c == NULL) {
1204
16.8M
                    gtp = &a->right_loc; /* b is greater than us */
1205
16.8M
                    ltp = ap; /* a is less than us */
1206
16.8M
                    break;
1207
16.8M
                }
1208
                /* Splay:      a                c
1209
                 *         W       b    =>    a   b
1210
                 *               c   Z       W X Y Z
1211
                 *              X Y
1212
                 */
1213
15.3M
                *ap = c;
1214
15.3M
                a->right_loc = c->left_loc;
1215
15.3M
                b->left_loc  = c->right_loc;
1216
15.3M
                c->left_loc  = a;
1217
15.3M
                c->right_loc = b;
1218
15.3M
                if ((void *)c > (void *)obj) { /* X */
1219
12.3M
                    gtp = ap; /* c is greater than us */
1220
12.3M
                    ltp = &c->left_loc; /* a is less than us */
1221
12.3M
                    ap = &a->right_loc;
1222
12.3M
                } else { /* Y */
1223
3.00M
                    gtp = &c->right_loc; /* b is greater than us */
1224
3.00M
                    ltp = ap; /* c is less than than us */
1225
3.00M
                    ap = &b->left_loc;
1226
3.00M
                }
1227
15.3M
            } else {
1228
10.5M
                c = b->right_loc;
1229
10.5M
                if (c == NULL) {
1230
669k
                    ltp = &a->right_loc; /* b is greater than us */
1231
669k
                    break;
1232
669k
                }
1233
                /* Splay:    a                   c
1234
                 *        W     b      =>     b     Z
1235
                 *            X   c         a   Y
1236
                 *               Y Z       W X
1237
                 */
1238
9.86M
                *ap = c;
1239
9.86M
                a->right_loc = b->left_loc;
1240
9.86M
                b->right_loc = c->left_loc;
1241
9.86M
                b->left_loc  = a;
1242
9.86M
                c->left_loc  = b;
1243
9.86M
                if ((void *)c > (void *)obj) { /* Y */
1244
4.80M
                    gtp = ap; /* c is greater than us */
1245
4.80M
                    ltp = &c->left_loc; /* b is less than us */
1246
4.80M
                    ap = &b->right_loc;
1247
5.05M
                } else { /* Z */
1248
5.05M
                    ltp = ap; /* c is less than than us */
1249
5.05M
                    ap = &c->right_loc;
1250
5.05M
                }
1251
9.86M
            }
1252
42.7M
        }
1253
95.8M
    }
1254
1255
76.5M
    if (ltp) {
1256
        /* There is at least 1 node smaller than us - check for merging */
1257
66.6M
        chunk_free_node_t *ltfree = (chunk_free_node_t *)(*ltp);
1258
66.6M
        if ((((byte *)ltfree) + ltfree->size) == (byte *)(void *)obj) {
1259
            /* Merge! */
1260
18.9M
            cmem->total_free += obj->size;
1261
18.9M
            remove_free_size(cmem, ltfree);
1262
18.9M
            ltfree->size += obj->size;
1263
18.9M
            if (gtp) {
1264
                /* There is at least 1 node greater than us - check for merging */
1265
18.9M
                chunk_free_node_t *gtfree = (chunk_free_node_t *)(*gtp);
1266
18.9M
                if ((((byte *)obj) + obj->size) == (byte *)(void *)gtfree) {
1267
                    /* Double merge! */
1268
7.32M
                    ltfree->size += gtfree->size;
1269
7.32M
                    remove_free(cmem, gtfree);
1270
7.32M
                }
1271
18.9M
                gtp = NULL;
1272
18.9M
            }
1273
18.9M
            insert_free_size(cmem, ltfree);
1274
18.9M
            if (gs_alloc_debug)
1275
0
                memset(((byte *)ltfree) + SIZEOF_ROUND_ALIGN(chunk_free_node_t), 0x69, ltfree->size - SIZEOF_ROUND_ALIGN(chunk_free_node_t));
1276
18.9M
            obj = NULL;
1277
18.9M
        }
1278
66.6M
    }
1279
76.5M
    if (gtp && obj) {
1280
        /* There is at least 1 node greater than us - check for merging */
1281
57.1M
        chunk_free_node_t *gtfree = (chunk_free_node_t *)(*gtp);
1282
57.1M
        if ((((byte *)obj) + obj->size) == (byte *)(void *)gtfree) {
1283
            /* Merge! */
1284
25.5M
            chunk_free_node_t *objfree = (chunk_free_node_t *)(void *)obj;
1285
25.5M
            uint obj_size = obj->size;
1286
25.5M
            cmem->total_free += obj_size;
1287
25.5M
            remove_free_size(cmem, gtfree);
1288
25.5M
            *objfree = *gtfree;
1289
25.5M
            objfree->size += obj_size;
1290
25.5M
            *gtp = objfree;
1291
25.5M
            insert_free_size(cmem, objfree);
1292
25.5M
            if (gs_alloc_debug)
1293
0
                memset(((byte *)objfree) + SIZEOF_ROUND_ALIGN(chunk_free_node_t), 0x96, objfree->size - SIZEOF_ROUND_ALIGN(chunk_free_node_t));
1294
25.5M
            obj = NULL;
1295
25.5M
        }
1296
57.1M
    }
1297
1298
76.5M
    if (obj) {
1299
        /* Insert new one */
1300
31.9M
        chunk_free_node_t *objfree = (chunk_free_node_t *)(void *)obj;
1301
31.9M
        cmem->total_free += obj->size;
1302
31.9M
        objfree->size = obj->size;
1303
31.9M
        objfree->left_loc = NULL;
1304
31.9M
        objfree->right_loc = NULL;
1305
31.9M
        if (gtp) {
1306
31.5M
            ap = &(*gtp)->left_loc;
1307
44.9M
            while (*ap) {
1308
13.3M
                ap = &(*ap)->right_loc;
1309
13.3M
            }
1310
31.5M
        } else if (ltp) {
1311
435k
            ap = &(*ltp)->right_loc;
1312
435k
            while (*ap) {
1313
0
                ap = &(*ap)->left_loc;
1314
0
            }
1315
435k
        } else
1316
2
            ap = &cmem->free_loc;
1317
31.9M
        *ap = objfree;
1318
31.9M
        insert_free_size(cmem, objfree);
1319
31.9M
        if (gs_alloc_debug)
1320
0
            memset(((byte *)objfree) + SIZEOF_ROUND_ALIGN(chunk_free_node_t), 0x9b, objfree->size - SIZEOF_ROUND_ALIGN(chunk_free_node_t));
1321
31.9M
    }
1322
1323
#ifdef DEBUG_CHUNK
1324
    gs_memory_chunk_dump_memory(cmem);
1325
#endif
1326
76.5M
}
1327
1328
static byte *
1329
chunk_alloc_string_immovable(gs_memory_t * mem, size_t nbytes, client_name_t cname)
1330
0
{
1331
    /* we just alloc bytes here */
1332
0
    return chunk_alloc_bytes(mem, nbytes, cname);
1333
0
}
1334
1335
static byte *
1336
chunk_alloc_string(gs_memory_t * mem, size_t nbytes, client_name_t cname)
1337
40.6k
{
1338
    /* we just alloc bytes here */
1339
40.6k
    return chunk_alloc_bytes(mem, nbytes, cname);
1340
40.6k
}
1341
1342
static byte *
1343
chunk_resize_string(gs_memory_t * mem, byte * data, size_t old_num, size_t new_num,
1344
                    client_name_t cname)
1345
0
{
1346
    /* just resize object - ignores old_num */
1347
0
    return chunk_resize_object(mem, data, new_num, cname);
1348
0
}
1349
1350
static void
1351
chunk_free_string(gs_memory_t * mem, byte * data, size_t nbytes,
1352
                  client_name_t cname)
1353
55.6k
{
1354
55.6k
    chunk_free_object(mem, data, cname);
1355
55.6k
}
1356
1357
static void
1358
chunk_status(gs_memory_t * mem, gs_memory_status_t * pstat)
1359
0
{
1360
0
    gs_memory_chunk_t *cmem = (gs_memory_chunk_t *)mem;
1361
1362
0
    pstat->allocated = cmem->used;
1363
0
    pstat->used = cmem->used - cmem->total_free;
1364
0
    pstat->max_used = cmem->max_used;
1365
0
    pstat->limit = (size_t)~1;      /* No limit on allocations */
1366
0
    pstat->is_thread_safe = false; /* this allocator does not have an internal mutex */
1367
0
}
1368
1369
static gs_memory_t *
1370
chunk_stable(gs_memory_t * mem)
1371
2.41M
{
1372
2.41M
    return mem;
1373
2.41M
}
1374
1375
static void
1376
chunk_enable_free(gs_memory_t * mem, bool enable)
1377
0
{
1378
0
}
1379
1380
static void chunk_set_object_type(gs_memory_t *mem, void *ptr, gs_memory_type_ptr_t type)
1381
0
{
1382
0
    chunk_obj_node_t *obj = (chunk_obj_node_t *)(((byte *)ptr) - SIZEOF_ROUND_ALIGN(chunk_obj_node_t));
1383
1384
0
    if (ptr == 0)
1385
0
        return;
1386
0
    obj->type = type;
1387
0
}
1388
1389
static void chunk_defer_frees(gs_memory_t *mem, int defer)
1390
0
{
1391
0
    gs_memory_chunk_t *cmem = (gs_memory_chunk_t *)mem;
1392
0
    chunk_obj_node_t *n;
1393
1394
0
    if (defer == 0) {
1395
        /* Run through and finalise everything on the finalize list. This
1396
         * might cause other stuff to be put onto the finalize list. As we
1397
         * finalize stuff we move it to the free list. */
1398
0
        while (cmem->defer_finalize_list) {
1399
0
            n = cmem->defer_finalize_list;
1400
0
            cmem->defer_finalize_list = n->defer_next;
1401
0
            if (n->type) {
1402
0
                if (n->type->finalize)
1403
0
                    n->type->finalize(mem, ((byte *)n) + SIZEOF_ROUND_ALIGN(chunk_obj_node_t));
1404
0
                n->type = NULL;
1405
0
            }
1406
0
            n->defer_next = cmem->defer_free_list;
1407
0
            cmem->defer_free_list = n;
1408
0
        }
1409
0
    }
1410
0
    cmem->deferring = defer;
1411
0
    if (defer == 0) {
1412
        /* Now run through and free everything on the free list */
1413
0
        while (cmem->defer_free_list) {
1414
0
            n = cmem->defer_free_list;
1415
0
            cmem->defer_free_list = n->defer_next;
1416
0
            chunk_free_object(mem, ((byte *)n) + SIZEOF_ROUND_ALIGN(chunk_obj_node_t), "deferred free");
1417
0
        }
1418
0
    }
1419
0
}
1420
1421
static void
1422
chunk_consolidate_free(gs_memory_t *mem)
1423
0
{
1424
0
}
1425
1426
/* accessors to get size and type given the pointer returned to the client */
1427
static size_t
1428
chunk_object_size(gs_memory_t * mem, const void *ptr)
1429
0
{
1430
0
    if (ptr != NULL) {
1431
0
        chunk_obj_node_t *obj = (chunk_obj_node_t *)(((byte *)ptr) - SIZEOF_ROUND_ALIGN(chunk_obj_node_t));
1432
1433
0
        return obj->size - obj->padding;
1434
0
    }
1435
1436
0
    return 0;
1437
0
}
1438
1439
static gs_memory_type_ptr_t
1440
chunk_object_type(const gs_memory_t * mem, const void *ptr)
1441
0
{
1442
0
    chunk_obj_node_t *obj = (chunk_obj_node_t *)(((byte *)ptr) - SIZEOF_ROUND_ALIGN(chunk_obj_node_t));
1443
0
    return obj->type;
1444
0
}
1445
1446
static int
1447
chunk_register_root(gs_memory_t * mem, gs_gc_root_t ** rp, gs_ptr_type_t ptype,
1448
                 void **up, client_name_t cname)
1449
0
{
1450
0
    return 0;
1451
0
}
1452
1453
static void
1454
chunk_unregister_root(gs_memory_t * mem, gs_gc_root_t * rp, client_name_t cname)
1455
0
{
1456
0
}