2 |
- |
1 |
/* Copyright (C) 1993, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
|
|
|
2 |
|
|
|
3 |
This software is provided AS-IS with no warranty, either express or
|
|
|
4 |
implied.
|
|
|
5 |
|
|
|
6 |
This software is distributed under license and may not be copied,
|
|
|
7 |
modified or distributed except as expressly authorized under the terms
|
|
|
8 |
of the license contained in the file LICENSE in this distribution.
|
|
|
9 |
|
|
|
10 |
For more information about licensing, please refer to
|
|
|
11 |
http://www.ghostscript.com/licensing/. For information on
|
|
|
12 |
commercial licensing, go to http://www.artifex.com/licensing/ or
|
|
|
13 |
contact Artifex Software, Inc., 101 Lucas Valley Road #110,
|
|
|
14 |
San Rafael, CA 94903, U.S.A., +1(415)492-9861.
|
|
|
15 |
*/
|
|
|
16 |
|
|
|
17 |
/* $Id: gsmemory.c,v 1.9 2004/08/04 19:36:12 stefan Exp $ */
|
|
|
18 |
/* Generic allocator support */
|
|
|
19 |
#include "memory_.h"
|
|
|
20 |
#include "gdebug.h"
|
|
|
21 |
#include "gstypes.h"
|
|
|
22 |
#include "gsmemory.h"
|
|
|
23 |
#include "gsmdebug.h"
|
|
|
24 |
#include "gsrefct.h" /* to check prototype */
|
|
|
25 |
#include "gsstruct.h" /* ditto */
|
|
|
26 |
|
|
|
27 |
/* Define the fill patterns for unallocated memory. */
|
|
|
28 |
const byte gs_alloc_fill_alloc = 0xa1;
|
|
|
29 |
const byte gs_alloc_fill_block = 0xb1;
|
|
|
30 |
const byte gs_alloc_fill_collected = 0xc1;
|
|
|
31 |
const byte gs_alloc_fill_deleted = 0xd1;
|
|
|
32 |
const byte gs_alloc_fill_free = 0xf1;
|
|
|
33 |
|
|
|
34 |
/* A 'structure' type descriptor for free blocks. */
|
|
|
35 |
gs_public_st_simple(st_free, byte, "(free)");
|
|
|
36 |
|
|
|
37 |
/* The 'structure' type descriptor for bytes. */
|
|
|
38 |
gs_public_st_simple(st_bytes, byte, "bytes");
|
|
|
39 |
|
|
|
40 |
/* The structure type descriptor for GC roots. */
|
|
|
41 |
public_st_gc_root_t();
|
|
|
42 |
|
|
|
43 |
/* The descriptors for elements and arrays of const strings. */
|
|
|
44 |
private_st_const_string();
|
|
|
45 |
public_st_const_string_element();
|
|
|
46 |
|
|
|
47 |
/* GC procedures for bytestrings */
|
|
|
48 |
gs_ptr_type_t
|
|
|
49 |
enum_bytestring(enum_ptr_t *pep, const gs_bytestring *pbs)
|
|
|
50 |
{
|
|
|
51 |
return (pbs->bytes ? ENUM_OBJ(pbs->bytes) : ENUM_STRING(pbs));
|
|
|
52 |
}
|
|
|
53 |
gs_ptr_type_t
|
|
|
54 |
enum_const_bytestring(enum_ptr_t *pep, const gs_const_bytestring *pbs)
|
|
|
55 |
{
|
|
|
56 |
return (pbs->bytes ? ENUM_OBJ(pbs->bytes) : ENUM_CONST_STRING(pbs));
|
|
|
57 |
}
|
|
|
58 |
void
|
|
|
59 |
reloc_bytestring(gs_bytestring *pbs, gc_state_t *gcst)
|
|
|
60 |
{
|
|
|
61 |
if (pbs->bytes) {
|
|
|
62 |
byte *bytes = pbs->bytes;
|
|
|
63 |
long offset = pbs->data - bytes;
|
|
|
64 |
|
|
|
65 |
pbs->bytes = bytes = RELOC_OBJ(bytes);
|
|
|
66 |
pbs->data = bytes + offset;
|
|
|
67 |
} else
|
|
|
68 |
RELOC_STRING_VAR(*(gs_string *)pbs);
|
|
|
69 |
}
|
|
|
70 |
void
|
|
|
71 |
reloc_const_bytestring(gs_const_bytestring *pbs, gc_state_t *gcst)
|
|
|
72 |
{
|
|
|
73 |
if (pbs->bytes) {
|
|
|
74 |
const byte *bytes = pbs->bytes;
|
|
|
75 |
long offset = pbs->data - bytes;
|
|
|
76 |
|
|
|
77 |
pbs->bytes = bytes = RELOC_OBJ(bytes);
|
|
|
78 |
pbs->data = bytes + offset;
|
|
|
79 |
} else
|
|
|
80 |
RELOC_CONST_STRING_VAR(*(gs_const_string *)pbs);
|
|
|
81 |
}
|
|
|
82 |
|
|
|
83 |
/* Fill an unoccupied block with a pattern. */
|
|
|
84 |
/* Note that the block size may be too large for a single memset. */
|
|
|
85 |
void
|
|
|
86 |
gs_alloc_memset(void *ptr, int /*byte */ fill, ulong lsize)
|
|
|
87 |
{
|
|
|
88 |
ulong msize = lsize;
|
|
|
89 |
char *p = ptr;
|
|
|
90 |
int isize;
|
|
|
91 |
|
|
|
92 |
for (; msize; msize -= isize, p += isize) {
|
|
|
93 |
isize = min(msize, max_int);
|
|
|
94 |
memset(p, fill, isize);
|
|
|
95 |
}
|
|
|
96 |
}
|
|
|
97 |
|
|
|
98 |
/*
|
|
|
99 |
* Either allocate (if obj == 0) or resize (if obj != 0) a structure array.
|
|
|
100 |
* If obj != 0, pstype is used only for checking (in DEBUG configurations).
|
|
|
101 |
*/
|
|
|
102 |
void *
|
|
|
103 |
gs_resize_struct_array(gs_memory_t *mem, void *obj, uint num_elements,
|
|
|
104 |
gs_memory_type_ptr_t pstype, client_name_t cname)
|
|
|
105 |
{
|
|
|
106 |
if (obj == 0)
|
|
|
107 |
return gs_alloc_struct_array(mem, num_elements, void, pstype, cname);
|
|
|
108 |
#ifdef DEBUG
|
|
|
109 |
if (gs_object_type(mem, obj) != pstype) {
|
|
|
110 |
lprintf3("resize_struct_array 0x%lx, type was 0x%lx, expected 0x%lx!\n",
|
|
|
111 |
(ulong)obj, (ulong)gs_object_type(mem, obj), (ulong)pstype);
|
|
|
112 |
return 0;
|
|
|
113 |
}
|
|
|
114 |
#endif
|
|
|
115 |
return gs_resize_object(mem, obj, num_elements, cname);
|
|
|
116 |
}
|
|
|
117 |
|
|
|
118 |
|
|
|
119 |
/* Allocate a structure using a "raw memory" allocator.
|
|
|
120 |
* really just an alias for gs_alloc_struct_immovable
|
|
|
121 |
* with the clients false expectation that it is saving memory
|
|
|
122 |
*/
|
|
|
123 |
|
|
|
124 |
void *
|
|
|
125 |
gs_raw_alloc_struct_immovable(gs_memory_t * rmem,
|
|
|
126 |
gs_memory_type_ptr_t pstype,
|
|
|
127 |
client_name_t cname)
|
|
|
128 |
{
|
|
|
129 |
return gs_alloc_bytes_immovable(rmem, gs_struct_type_size(pstype), cname);
|
|
|
130 |
}
|
|
|
131 |
|
|
|
132 |
/* No-op freeing procedures */
|
|
|
133 |
void
|
|
|
134 |
gs_ignore_free_object(gs_memory_t * mem, void *data, client_name_t cname)
|
|
|
135 |
{
|
|
|
136 |
}
|
|
|
137 |
void
|
|
|
138 |
gs_ignore_free_string(gs_memory_t * mem, byte * data, uint nbytes,
|
|
|
139 |
client_name_t cname)
|
|
|
140 |
{
|
|
|
141 |
}
|
|
|
142 |
|
|
|
143 |
/* Deconstifying freeing procedures. */
|
|
|
144 |
/* These procedures rely on a severely deprecated pun. */
|
|
|
145 |
void
|
|
|
146 |
gs_free_const_object(gs_memory_t * mem, const void *data, client_name_t cname)
|
|
|
147 |
{
|
|
|
148 |
union { const void *r; void *w; } u;
|
|
|
149 |
|
|
|
150 |
u.r = data;
|
|
|
151 |
gs_free_object(mem, u.w, cname);
|
|
|
152 |
}
|
|
|
153 |
void
|
|
|
154 |
gs_free_const_string(gs_memory_t * mem, const byte * data, uint nbytes,
|
|
|
155 |
client_name_t cname)
|
|
|
156 |
{
|
|
|
157 |
union { const byte *r; byte *w; } u;
|
|
|
158 |
|
|
|
159 |
u.r = data;
|
|
|
160 |
gs_free_string(mem, u.w, nbytes, cname);
|
|
|
161 |
}
|
|
|
162 |
|
|
|
163 |
/* Free a [const] bytestring. */
|
|
|
164 |
void
|
|
|
165 |
gs_free_bytestring(gs_memory_t *mem, gs_bytestring *pbs, client_name_t cname)
|
|
|
166 |
{
|
|
|
167 |
if (pbs->bytes)
|
|
|
168 |
gs_free_object(mem, pbs->bytes, cname);
|
|
|
169 |
else
|
|
|
170 |
gs_free_string(mem, pbs->data, pbs->size, cname);
|
|
|
171 |
}
|
|
|
172 |
void
|
|
|
173 |
gs_free_const_bytestring(gs_memory_t *mem, gs_const_bytestring *pbs,
|
|
|
174 |
client_name_t cname)
|
|
|
175 |
{
|
|
|
176 |
if (pbs->bytes)
|
|
|
177 |
gs_free_const_object(mem, pbs->bytes, cname);
|
|
|
178 |
else
|
|
|
179 |
gs_free_const_string(mem, pbs->data, pbs->size, cname);
|
|
|
180 |
}
|
|
|
181 |
|
|
|
182 |
/* No-op consolidation procedure */
|
|
|
183 |
void
|
|
|
184 |
gs_ignore_consolidate_free(gs_memory_t *mem)
|
|
|
185 |
{
|
|
|
186 |
}
|
|
|
187 |
|
|
|
188 |
/* No-op pointer enumeration procedure */
|
|
|
189 |
ENUM_PTRS_BEGIN_PROC(gs_no_struct_enum_ptrs)
|
|
|
190 |
{
|
|
|
191 |
return 0;
|
|
|
192 |
ENUM_PTRS_END_PROC
|
|
|
193 |
}
|
|
|
194 |
|
|
|
195 |
/* No-op pointer relocation procedure */
|
|
|
196 |
RELOC_PTRS_BEGIN(gs_no_struct_reloc_ptrs)
|
|
|
197 |
{
|
|
|
198 |
}
|
|
|
199 |
RELOC_PTRS_END
|
|
|
200 |
|
|
|
201 |
/* Get the size of a structure from the descriptor. */
|
|
|
202 |
uint
|
|
|
203 |
gs_struct_type_size(gs_memory_type_ptr_t pstype)
|
|
|
204 |
{
|
|
|
205 |
return pstype->ssize;
|
|
|
206 |
}
|
|
|
207 |
|
|
|
208 |
/* Get the name of a structure from the descriptor. */
|
|
|
209 |
struct_name_t
|
|
|
210 |
gs_struct_type_name(gs_memory_type_ptr_t pstype)
|
|
|
211 |
{
|
|
|
212 |
return pstype->sname;
|
|
|
213 |
}
|
|
|
214 |
|
|
|
215 |
/* Register a structure root. */
|
|
|
216 |
int
|
|
|
217 |
gs_register_struct_root(gs_memory_t *mem, gs_gc_root_t *root,
|
|
|
218 |
void **pp, client_name_t cname)
|
|
|
219 |
{
|
|
|
220 |
return gs_register_root(mem, root, ptr_struct_type, pp, cname);
|
|
|
221 |
}
|
|
|
222 |
|
|
|
223 |
/* ---------------- Reference counting ---------------- */
|
|
|
224 |
|
|
|
225 |
#ifdef DEBUG
|
|
|
226 |
|
|
|
227 |
private const char *
|
|
|
228 |
rc_object_type_name(const void *vp, const rc_header *prc)
|
|
|
229 |
{
|
|
|
230 |
gs_memory_type_ptr_t pstype;
|
|
|
231 |
|
|
|
232 |
if (prc->memory == 0)
|
|
|
233 |
return "(unknown)";
|
|
|
234 |
pstype = gs_object_type(prc->memory, vp);
|
|
|
235 |
if (prc->free != rc_free_struct_only) {
|
|
|
236 |
/*
|
|
|
237 |
* This object might be stack-allocated or have other unusual memory
|
|
|
238 |
* management properties. Make some reasonableness checks.
|
|
|
239 |
* ****** THIS IS A HACK. ******
|
|
|
240 |
*/
|
|
|
241 |
long dist;
|
|
|
242 |
|
|
|
243 |
dist = (const char *)&dist - (const char *)vp;
|
|
|
244 |
if (dist < 10000 && dist > -10000)
|
|
|
245 |
return "(on stack)";
|
|
|
246 |
if ((ulong)pstype < 0x10000 || (long)pstype < 0)
|
|
|
247 |
return "(anomalous)";
|
|
|
248 |
}
|
|
|
249 |
return client_name_string(gs_struct_type_name(pstype));
|
|
|
250 |
}
|
|
|
251 |
|
|
|
252 |
/* Trace reference count operations. */
|
|
|
253 |
void
|
|
|
254 |
rc_trace_init_free(const void *vp, const rc_header *prc)
|
|
|
255 |
{
|
|
|
256 |
dprintf3("[^]%s 0x%lx init = %ld\n",
|
|
|
257 |
rc_object_type_name(vp, prc), (ulong)vp, (long)prc->ref_count);
|
|
|
258 |
}
|
|
|
259 |
void
|
|
|
260 |
rc_trace_free_struct(const void *vp, const rc_header *prc, client_name_t cname)
|
|
|
261 |
{
|
|
|
262 |
dprintf3("[^]%s 0x%lx => free (%s)\n",
|
|
|
263 |
rc_object_type_name(vp, prc),
|
|
|
264 |
(ulong)vp, client_name_string(cname));
|
|
|
265 |
}
|
|
|
266 |
void
|
|
|
267 |
rc_trace_increment(const void *vp, const rc_header *prc)
|
|
|
268 |
{
|
|
|
269 |
dprintf3("[^]%s 0x%lx ++ => %ld\n",
|
|
|
270 |
rc_object_type_name(vp, prc),
|
|
|
271 |
(ulong)vp, (long)prc->ref_count);
|
|
|
272 |
}
|
|
|
273 |
void
|
|
|
274 |
rc_trace_adjust(const void *vp, const rc_header *prc, int delta)
|
|
|
275 |
{
|
|
|
276 |
dprintf4("[^]%s 0x%lx %+d => %ld\n",
|
|
|
277 |
rc_object_type_name(vp, prc),
|
|
|
278 |
(ulong)vp, delta, (long)(prc->ref_count + delta));
|
|
|
279 |
}
|
|
|
280 |
|
|
|
281 |
#endif /* DEBUG */
|
|
|
282 |
|
|
|
283 |
/* Normal freeing routine for reference-counted structures. */
|
|
|
284 |
void
|
|
|
285 |
rc_free_struct_only(gs_memory_t * mem, void *data, client_name_t cname)
|
|
|
286 |
{
|
|
|
287 |
if (mem != 0)
|
|
|
288 |
gs_free_object(mem, data, cname);
|
|
|
289 |
}
|
|
|
290 |
|
|
|
291 |
/* ---------------- Basic-structure GC procedures ---------------- */
|
|
|
292 |
|
|
|
293 |
/* Enumerate pointers */
|
|
|
294 |
ENUM_PTRS_BEGIN_PROC(basic_enum_ptrs)
|
|
|
295 |
{
|
|
|
296 |
const gc_struct_data_t *psd = pstype->proc_data;
|
|
|
297 |
|
|
|
298 |
/* This check is primarily for misuse of the alloc_struct_array */
|
|
|
299 |
/* with number of elements 0 and allocation not passing 'element' */
|
|
|
300 |
if (size == 0) {
|
|
|
301 |
#ifdef DEBUG
|
|
|
302 |
dprintf2(" basic_enum_ptrs: Attempt to enum 0 size structure at 0x%lx, type: %s\n",
|
|
|
303 |
vptr, pstype->sname);
|
|
|
304 |
#endif
|
|
|
305 |
return 0;
|
|
|
306 |
}
|
|
|
307 |
if (index < psd->num_ptrs) {
|
|
|
308 |
const gc_ptr_element_t *ppe = &psd->ptrs[index];
|
|
|
309 |
EV_CONST char *pptr = (EV_CONST char *)vptr + ppe->offset;
|
|
|
310 |
|
|
|
311 |
#ifdef DEBUG
|
|
|
312 |
/* some extra checking to make sure we aren't out of bounds */
|
|
|
313 |
if (ppe->offset > size - sizeof(void *)) {
|
|
|
314 |
dprintf4(" basic_enum_ptrs: Attempt to enum ptr with offset=%d beyond size=%d: structure at 0x%lx, type: %s\n",
|
|
|
315 |
ppe->offset, size, vptr, pstype->sname);
|
|
|
316 |
return 0;
|
|
|
317 |
}
|
|
|
318 |
#endif
|
|
|
319 |
switch ((gc_ptr_type_index_t)ppe->type) {
|
|
|
320 |
case GC_ELT_OBJ:
|
|
|
321 |
return ENUM_OBJ(*(const void *EV_CONST *)pptr);
|
|
|
322 |
case GC_ELT_STRING:
|
|
|
323 |
return ENUM_STRING((const gs_string *)pptr);
|
|
|
324 |
case GC_ELT_CONST_STRING:
|
|
|
325 |
return ENUM_CONST_STRING((const gs_const_string *)pptr);
|
|
|
326 |
}
|
|
|
327 |
}
|
|
|
328 |
if (!psd->super_type)
|
|
|
329 |
return 0;
|
|
|
330 |
return ENUM_USING(*(psd->super_type),
|
|
|
331 |
(EV_CONST void *)
|
|
|
332 |
((EV_CONST char *)vptr + psd->super_offset),
|
|
|
333 |
pstype->ssize, index - psd->num_ptrs);
|
|
|
334 |
}
|
|
|
335 |
ENUM_PTRS_END_PROC
|
|
|
336 |
|
|
|
337 |
/* Relocate pointers */
|
|
|
338 |
RELOC_PTRS_BEGIN(basic_reloc_ptrs)
|
|
|
339 |
{
|
|
|
340 |
const gc_struct_data_t *psd = pstype->proc_data;
|
|
|
341 |
uint i;
|
|
|
342 |
|
|
|
343 |
for (i = 0; i < psd->num_ptrs; ++i) {
|
|
|
344 |
const gc_ptr_element_t *ppe = &psd->ptrs[i];
|
|
|
345 |
char *pptr = (char *)vptr + ppe->offset;
|
|
|
346 |
|
|
|
347 |
switch ((gc_ptr_type_index_t) ppe->type) {
|
|
|
348 |
case GC_ELT_OBJ:
|
|
|
349 |
RELOC_OBJ_VAR(*(void **)pptr);
|
|
|
350 |
break;
|
|
|
351 |
case GC_ELT_STRING:
|
|
|
352 |
RELOC_STRING_VAR(*(gs_string *)pptr);
|
|
|
353 |
break;
|
|
|
354 |
case GC_ELT_CONST_STRING:
|
|
|
355 |
RELOC_CONST_STRING_VAR(*(gs_const_string *)pptr);
|
|
|
356 |
break;
|
|
|
357 |
}
|
|
|
358 |
}
|
|
|
359 |
if (psd->super_type)
|
|
|
360 |
RELOC_USING(*(psd->super_type),
|
|
|
361 |
(void *)((char *)vptr + psd->super_offset),
|
|
|
362 |
pstype->ssize);
|
|
|
363 |
} RELOC_PTRS_END
|