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
enum_bytestring(enum_ptr_t * pep,const gs_bytestring * pbs)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
enum_const_bytestring(enum_ptr_t * pep,const gs_const_bytestring * pbs)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
reloc_bytestring(gs_bytestring * pbs,gc_state_t * gcst)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
reloc_const_bytestring(gs_const_bytestring * pbs,gc_state_t * gcst)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
gs_alloc_memset(void * ptr,int fill,ulong lsize)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 *
gs_resize_struct_array(gs_memory_t * mem,void * obj,uint num_elements,gs_memory_type_ptr_t pstype,client_name_t cname)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 *
gs_raw_alloc_struct_immovable(gs_memory_t * rmem,gs_memory_type_ptr_t pstype,client_name_t cname)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
gs_ignore_free_object(gs_memory_t * mem,void * data,client_name_t cname)134 gs_ignore_free_object(gs_memory_t * mem, void *data, client_name_t cname)
135 {
136 }
137 void
gs_ignore_free_string(gs_memory_t * mem,byte * data,uint nbytes,client_name_t cname)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
gs_free_const_object(gs_memory_t * mem,const void * data,client_name_t cname)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
gs_free_const_string(gs_memory_t * mem,const byte * data,uint nbytes,client_name_t cname)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
gs_free_bytestring(gs_memory_t * mem,gs_bytestring * pbs,client_name_t cname)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
gs_free_const_bytestring(gs_memory_t * mem,gs_const_bytestring * pbs,client_name_t cname)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
gs_ignore_consolidate_free(gs_memory_t * mem)184 gs_ignore_consolidate_free(gs_memory_t *mem)
185 {
186 }
187
188 /* No-op pointer enumeration procedure */
ENUM_PTRS_BEGIN_PROC(gs_no_struct_enum_ptrs)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 */
RELOC_PTRS_BEGIN(gs_no_struct_reloc_ptrs)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
gs_struct_type_size(gs_memory_type_ptr_t pstype)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
gs_struct_type_name(gs_memory_type_ptr_t pstype)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
gs_register_struct_root(gs_memory_t * mem,gs_gc_root_t * root,void ** pp,client_name_t cname)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 *
rc_object_type_name(const void * vp,const rc_header * prc)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
rc_trace_init_free(const void * vp,const rc_header * prc)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
rc_trace_free_struct(const void * vp,const rc_header * prc,client_name_t cname)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
rc_trace_increment(const void * vp,const rc_header * prc)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
rc_trace_adjust(const void * vp,const rc_header * prc,int delta)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
rc_free_struct_only(gs_memory_t * mem,void * data,client_name_t cname)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 */
ENUM_PTRS_BEGIN_PROC(basic_enum_ptrs)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 */
RELOC_PTRS_BEGIN(basic_reloc_ptrs)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
364