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