xref: /dflybsd-src/contrib/gdb-7/libiberty/objalloc.c (revision 5796c8dc12c637f18a1740c26afd8d40ffa9b719)
1*5796c8dcSSimon Schubert /* objalloc.c -- routines to allocate memory for objects
2*5796c8dcSSimon Schubert    Copyright 1997 Free Software Foundation, Inc.
3*5796c8dcSSimon Schubert    Written by Ian Lance Taylor, Cygnus Solutions.
4*5796c8dcSSimon Schubert 
5*5796c8dcSSimon Schubert This program is free software; you can redistribute it and/or modify it
6*5796c8dcSSimon Schubert under the terms of the GNU General Public License as published by the
7*5796c8dcSSimon Schubert Free Software Foundation; either version 2, or (at your option) any
8*5796c8dcSSimon Schubert later version.
9*5796c8dcSSimon Schubert 
10*5796c8dcSSimon Schubert This program is distributed in the hope that it will be useful,
11*5796c8dcSSimon Schubert but WITHOUT ANY WARRANTY; without even the implied warranty of
12*5796c8dcSSimon Schubert MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*5796c8dcSSimon Schubert GNU General Public License for more details.
14*5796c8dcSSimon Schubert 
15*5796c8dcSSimon Schubert You should have received a copy of the GNU General Public License
16*5796c8dcSSimon Schubert along with this program; if not, write to the Free Software
17*5796c8dcSSimon Schubert Foundation, 51 Franklin Street - Fifth Floor,
18*5796c8dcSSimon Schubert Boston, MA 02110-1301, USA.  */
19*5796c8dcSSimon Schubert 
20*5796c8dcSSimon Schubert #include "config.h"
21*5796c8dcSSimon Schubert #include "ansidecl.h"
22*5796c8dcSSimon Schubert 
23*5796c8dcSSimon Schubert #include "objalloc.h"
24*5796c8dcSSimon Schubert 
25*5796c8dcSSimon Schubert /* Get a definition for NULL.  */
26*5796c8dcSSimon Schubert #include <stdio.h>
27*5796c8dcSSimon Schubert 
28*5796c8dcSSimon Schubert #if VMS
29*5796c8dcSSimon Schubert #include <stdlib.h>
30*5796c8dcSSimon Schubert #include <unixlib.h>
31*5796c8dcSSimon Schubert #else
32*5796c8dcSSimon Schubert 
33*5796c8dcSSimon Schubert /* Get a definition for size_t.  */
34*5796c8dcSSimon Schubert #include <stddef.h>
35*5796c8dcSSimon Schubert 
36*5796c8dcSSimon Schubert #ifdef HAVE_STDLIB_H
37*5796c8dcSSimon Schubert #include <stdlib.h>
38*5796c8dcSSimon Schubert #else
39*5796c8dcSSimon Schubert /* For systems with larger pointers than ints, this must be declared.  */
40*5796c8dcSSimon Schubert extern PTR malloc (size_t);
41*5796c8dcSSimon Schubert extern void free (PTR);
42*5796c8dcSSimon Schubert #endif
43*5796c8dcSSimon Schubert 
44*5796c8dcSSimon Schubert #endif
45*5796c8dcSSimon Schubert 
46*5796c8dcSSimon Schubert /* These routines allocate space for an object.  Freeing allocated
47*5796c8dcSSimon Schubert    space may or may not free all more recently allocated space.
48*5796c8dcSSimon Schubert 
49*5796c8dcSSimon Schubert    We handle large and small allocation requests differently.  If we
50*5796c8dcSSimon Schubert    don't have enough space in the current block, and the allocation
51*5796c8dcSSimon Schubert    request is for more than 512 bytes, we simply pass it through to
52*5796c8dcSSimon Schubert    malloc.  */
53*5796c8dcSSimon Schubert 
54*5796c8dcSSimon Schubert /* The objalloc structure is defined in objalloc.h.  */
55*5796c8dcSSimon Schubert 
56*5796c8dcSSimon Schubert /* This structure appears at the start of each chunk.  */
57*5796c8dcSSimon Schubert 
58*5796c8dcSSimon Schubert struct objalloc_chunk
59*5796c8dcSSimon Schubert {
60*5796c8dcSSimon Schubert   /* Next chunk.  */
61*5796c8dcSSimon Schubert   struct objalloc_chunk *next;
62*5796c8dcSSimon Schubert   /* If this chunk contains large objects, this is the value of
63*5796c8dcSSimon Schubert      current_ptr when this chunk was allocated.  If this chunk
64*5796c8dcSSimon Schubert      contains small objects, this is NULL.  */
65*5796c8dcSSimon Schubert   char *current_ptr;
66*5796c8dcSSimon Schubert };
67*5796c8dcSSimon Schubert 
68*5796c8dcSSimon Schubert /* The aligned size of objalloc_chunk.  */
69*5796c8dcSSimon Schubert 
70*5796c8dcSSimon Schubert #define CHUNK_HEADER_SIZE					\
71*5796c8dcSSimon Schubert   ((sizeof (struct objalloc_chunk) + OBJALLOC_ALIGN - 1)	\
72*5796c8dcSSimon Schubert    &~ (OBJALLOC_ALIGN - 1))
73*5796c8dcSSimon Schubert 
74*5796c8dcSSimon Schubert /* We ask for this much memory each time we create a chunk which is to
75*5796c8dcSSimon Schubert    hold small objects.  */
76*5796c8dcSSimon Schubert 
77*5796c8dcSSimon Schubert #define CHUNK_SIZE (4096 - 32)
78*5796c8dcSSimon Schubert 
79*5796c8dcSSimon Schubert /* A request for this amount or more is just passed through to malloc.  */
80*5796c8dcSSimon Schubert 
81*5796c8dcSSimon Schubert #define BIG_REQUEST (512)
82*5796c8dcSSimon Schubert 
83*5796c8dcSSimon Schubert /* Create an objalloc structure.  */
84*5796c8dcSSimon Schubert 
85*5796c8dcSSimon Schubert struct objalloc *
86*5796c8dcSSimon Schubert objalloc_create (void)
87*5796c8dcSSimon Schubert {
88*5796c8dcSSimon Schubert   struct objalloc *ret;
89*5796c8dcSSimon Schubert   struct objalloc_chunk *chunk;
90*5796c8dcSSimon Schubert 
91*5796c8dcSSimon Schubert   ret = (struct objalloc *) malloc (sizeof *ret);
92*5796c8dcSSimon Schubert   if (ret == NULL)
93*5796c8dcSSimon Schubert     return NULL;
94*5796c8dcSSimon Schubert 
95*5796c8dcSSimon Schubert   ret->chunks = (PTR) malloc (CHUNK_SIZE);
96*5796c8dcSSimon Schubert   if (ret->chunks == NULL)
97*5796c8dcSSimon Schubert     {
98*5796c8dcSSimon Schubert       free (ret);
99*5796c8dcSSimon Schubert       return NULL;
100*5796c8dcSSimon Schubert     }
101*5796c8dcSSimon Schubert 
102*5796c8dcSSimon Schubert   chunk = (struct objalloc_chunk *) ret->chunks;
103*5796c8dcSSimon Schubert   chunk->next = NULL;
104*5796c8dcSSimon Schubert   chunk->current_ptr = NULL;
105*5796c8dcSSimon Schubert 
106*5796c8dcSSimon Schubert   ret->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE;
107*5796c8dcSSimon Schubert   ret->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE;
108*5796c8dcSSimon Schubert 
109*5796c8dcSSimon Schubert   return ret;
110*5796c8dcSSimon Schubert }
111*5796c8dcSSimon Schubert 
112*5796c8dcSSimon Schubert /* Allocate space from an objalloc structure.  */
113*5796c8dcSSimon Schubert 
114*5796c8dcSSimon Schubert PTR
115*5796c8dcSSimon Schubert _objalloc_alloc (struct objalloc *o, unsigned long len)
116*5796c8dcSSimon Schubert {
117*5796c8dcSSimon Schubert   /* We avoid confusion from zero sized objects by always allocating
118*5796c8dcSSimon Schubert      at least 1 byte.  */
119*5796c8dcSSimon Schubert   if (len == 0)
120*5796c8dcSSimon Schubert     len = 1;
121*5796c8dcSSimon Schubert 
122*5796c8dcSSimon Schubert   len = (len + OBJALLOC_ALIGN - 1) &~ (OBJALLOC_ALIGN - 1);
123*5796c8dcSSimon Schubert 
124*5796c8dcSSimon Schubert   if (len <= o->current_space)
125*5796c8dcSSimon Schubert     {
126*5796c8dcSSimon Schubert       o->current_ptr += len;
127*5796c8dcSSimon Schubert       o->current_space -= len;
128*5796c8dcSSimon Schubert       return (PTR) (o->current_ptr - len);
129*5796c8dcSSimon Schubert     }
130*5796c8dcSSimon Schubert 
131*5796c8dcSSimon Schubert   if (len >= BIG_REQUEST)
132*5796c8dcSSimon Schubert     {
133*5796c8dcSSimon Schubert       char *ret;
134*5796c8dcSSimon Schubert       struct objalloc_chunk *chunk;
135*5796c8dcSSimon Schubert 
136*5796c8dcSSimon Schubert       ret = (char *) malloc (CHUNK_HEADER_SIZE + len);
137*5796c8dcSSimon Schubert       if (ret == NULL)
138*5796c8dcSSimon Schubert 	return NULL;
139*5796c8dcSSimon Schubert 
140*5796c8dcSSimon Schubert       chunk = (struct objalloc_chunk *) ret;
141*5796c8dcSSimon Schubert       chunk->next = (struct objalloc_chunk *) o->chunks;
142*5796c8dcSSimon Schubert       chunk->current_ptr = o->current_ptr;
143*5796c8dcSSimon Schubert 
144*5796c8dcSSimon Schubert       o->chunks = (PTR) chunk;
145*5796c8dcSSimon Schubert 
146*5796c8dcSSimon Schubert       return (PTR) (ret + CHUNK_HEADER_SIZE);
147*5796c8dcSSimon Schubert     }
148*5796c8dcSSimon Schubert   else
149*5796c8dcSSimon Schubert     {
150*5796c8dcSSimon Schubert       struct objalloc_chunk *chunk;
151*5796c8dcSSimon Schubert 
152*5796c8dcSSimon Schubert       chunk = (struct objalloc_chunk *) malloc (CHUNK_SIZE);
153*5796c8dcSSimon Schubert       if (chunk == NULL)
154*5796c8dcSSimon Schubert 	return NULL;
155*5796c8dcSSimon Schubert       chunk->next = (struct objalloc_chunk *) o->chunks;
156*5796c8dcSSimon Schubert       chunk->current_ptr = NULL;
157*5796c8dcSSimon Schubert 
158*5796c8dcSSimon Schubert       o->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE;
159*5796c8dcSSimon Schubert       o->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE;
160*5796c8dcSSimon Schubert 
161*5796c8dcSSimon Schubert       o->chunks = (PTR) chunk;
162*5796c8dcSSimon Schubert 
163*5796c8dcSSimon Schubert       return objalloc_alloc (o, len);
164*5796c8dcSSimon Schubert     }
165*5796c8dcSSimon Schubert }
166*5796c8dcSSimon Schubert 
167*5796c8dcSSimon Schubert /* Free an entire objalloc structure.  */
168*5796c8dcSSimon Schubert 
169*5796c8dcSSimon Schubert void
170*5796c8dcSSimon Schubert objalloc_free (struct objalloc *o)
171*5796c8dcSSimon Schubert {
172*5796c8dcSSimon Schubert   struct objalloc_chunk *l;
173*5796c8dcSSimon Schubert 
174*5796c8dcSSimon Schubert   l = (struct objalloc_chunk *) o->chunks;
175*5796c8dcSSimon Schubert   while (l != NULL)
176*5796c8dcSSimon Schubert     {
177*5796c8dcSSimon Schubert       struct objalloc_chunk *next;
178*5796c8dcSSimon Schubert 
179*5796c8dcSSimon Schubert       next = l->next;
180*5796c8dcSSimon Schubert       free (l);
181*5796c8dcSSimon Schubert       l = next;
182*5796c8dcSSimon Schubert     }
183*5796c8dcSSimon Schubert 
184*5796c8dcSSimon Schubert   free (o);
185*5796c8dcSSimon Schubert }
186*5796c8dcSSimon Schubert 
187*5796c8dcSSimon Schubert /* Free a block from an objalloc structure.  This also frees all more
188*5796c8dcSSimon Schubert    recently allocated blocks.  */
189*5796c8dcSSimon Schubert 
190*5796c8dcSSimon Schubert void
191*5796c8dcSSimon Schubert objalloc_free_block (struct objalloc *o, PTR block)
192*5796c8dcSSimon Schubert {
193*5796c8dcSSimon Schubert   struct objalloc_chunk *p, *small;
194*5796c8dcSSimon Schubert   char *b = (char *) block;
195*5796c8dcSSimon Schubert 
196*5796c8dcSSimon Schubert   /* First set P to the chunk which contains the block we are freeing,
197*5796c8dcSSimon Schubert      and set Q to the last small object chunk we see before P.  */
198*5796c8dcSSimon Schubert   small = NULL;
199*5796c8dcSSimon Schubert   for (p = (struct objalloc_chunk *) o->chunks; p != NULL; p = p->next)
200*5796c8dcSSimon Schubert     {
201*5796c8dcSSimon Schubert       if (p->current_ptr == NULL)
202*5796c8dcSSimon Schubert 	{
203*5796c8dcSSimon Schubert 	  if (b > (char *) p && b < (char *) p + CHUNK_SIZE)
204*5796c8dcSSimon Schubert 	    break;
205*5796c8dcSSimon Schubert 	  small = p;
206*5796c8dcSSimon Schubert 	}
207*5796c8dcSSimon Schubert       else
208*5796c8dcSSimon Schubert 	{
209*5796c8dcSSimon Schubert 	  if (b == (char *) p + CHUNK_HEADER_SIZE)
210*5796c8dcSSimon Schubert 	    break;
211*5796c8dcSSimon Schubert 	}
212*5796c8dcSSimon Schubert     }
213*5796c8dcSSimon Schubert 
214*5796c8dcSSimon Schubert   /* If we can't find the chunk, the caller has made a mistake.  */
215*5796c8dcSSimon Schubert   if (p == NULL)
216*5796c8dcSSimon Schubert     abort ();
217*5796c8dcSSimon Schubert 
218*5796c8dcSSimon Schubert   if (p->current_ptr == NULL)
219*5796c8dcSSimon Schubert     {
220*5796c8dcSSimon Schubert       struct objalloc_chunk *q;
221*5796c8dcSSimon Schubert       struct objalloc_chunk *first;
222*5796c8dcSSimon Schubert 
223*5796c8dcSSimon Schubert       /* The block is in a chunk containing small objects.  We can
224*5796c8dcSSimon Schubert 	 free every chunk through SMALL, because they have certainly
225*5796c8dcSSimon Schubert 	 been allocated more recently.  After SMALL, we will not see
226*5796c8dcSSimon Schubert 	 any chunks containing small objects; we can free any big
227*5796c8dcSSimon Schubert 	 chunk if the current_ptr is greater than or equal to B.  We
228*5796c8dcSSimon Schubert 	 can then reset the new current_ptr to B.  */
229*5796c8dcSSimon Schubert 
230*5796c8dcSSimon Schubert       first = NULL;
231*5796c8dcSSimon Schubert       q = (struct objalloc_chunk *) o->chunks;
232*5796c8dcSSimon Schubert       while (q != p)
233*5796c8dcSSimon Schubert 	{
234*5796c8dcSSimon Schubert 	  struct objalloc_chunk *next;
235*5796c8dcSSimon Schubert 
236*5796c8dcSSimon Schubert 	  next = q->next;
237*5796c8dcSSimon Schubert 	  if (small != NULL)
238*5796c8dcSSimon Schubert 	    {
239*5796c8dcSSimon Schubert 	      if (small == q)
240*5796c8dcSSimon Schubert 		small = NULL;
241*5796c8dcSSimon Schubert 	      free (q);
242*5796c8dcSSimon Schubert 	    }
243*5796c8dcSSimon Schubert 	  else if (q->current_ptr > b)
244*5796c8dcSSimon Schubert 	    free (q);
245*5796c8dcSSimon Schubert 	  else if (first == NULL)
246*5796c8dcSSimon Schubert 	    first = q;
247*5796c8dcSSimon Schubert 
248*5796c8dcSSimon Schubert 	  q = next;
249*5796c8dcSSimon Schubert 	}
250*5796c8dcSSimon Schubert 
251*5796c8dcSSimon Schubert       if (first == NULL)
252*5796c8dcSSimon Schubert 	first = p;
253*5796c8dcSSimon Schubert       o->chunks = (PTR) first;
254*5796c8dcSSimon Schubert 
255*5796c8dcSSimon Schubert       /* Now start allocating from this small block again.  */
256*5796c8dcSSimon Schubert       o->current_ptr = b;
257*5796c8dcSSimon Schubert       o->current_space = ((char *) p + CHUNK_SIZE) - b;
258*5796c8dcSSimon Schubert     }
259*5796c8dcSSimon Schubert   else
260*5796c8dcSSimon Schubert     {
261*5796c8dcSSimon Schubert       struct objalloc_chunk *q;
262*5796c8dcSSimon Schubert       char *current_ptr;
263*5796c8dcSSimon Schubert 
264*5796c8dcSSimon Schubert       /* This block is in a large chunk by itself.  We can free
265*5796c8dcSSimon Schubert          everything on the list up to and including this block.  We
266*5796c8dcSSimon Schubert          then start allocating from the next chunk containing small
267*5796c8dcSSimon Schubert          objects, setting current_ptr from the value stored with the
268*5796c8dcSSimon Schubert          large chunk we are freeing.  */
269*5796c8dcSSimon Schubert 
270*5796c8dcSSimon Schubert       current_ptr = p->current_ptr;
271*5796c8dcSSimon Schubert       p = p->next;
272*5796c8dcSSimon Schubert 
273*5796c8dcSSimon Schubert       q = (struct objalloc_chunk *) o->chunks;
274*5796c8dcSSimon Schubert       while (q != p)
275*5796c8dcSSimon Schubert 	{
276*5796c8dcSSimon Schubert 	  struct objalloc_chunk *next;
277*5796c8dcSSimon Schubert 
278*5796c8dcSSimon Schubert 	  next = q->next;
279*5796c8dcSSimon Schubert 	  free (q);
280*5796c8dcSSimon Schubert 	  q = next;
281*5796c8dcSSimon Schubert 	}
282*5796c8dcSSimon Schubert 
283*5796c8dcSSimon Schubert       o->chunks = (PTR) p;
284*5796c8dcSSimon Schubert 
285*5796c8dcSSimon Schubert       while (p->current_ptr != NULL)
286*5796c8dcSSimon Schubert 	p = p->next;
287*5796c8dcSSimon Schubert 
288*5796c8dcSSimon Schubert       o->current_ptr = current_ptr;
289*5796c8dcSSimon Schubert       o->current_space = ((char *) p + CHUNK_SIZE) - current_ptr;
290*5796c8dcSSimon Schubert     }
291*5796c8dcSSimon Schubert }
292