xref: /plan9/sys/src/cmd/gs/src/gsmemory.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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