xref: /netbsd-src/external/gpl3/gcc/dist/libiberty/objalloc.c (revision e9e6e0f6fbc36b8de7586170291cf5fc97cab8b6)
14fee23f9Smrg /* objalloc.c -- routines to allocate memory for objects
2*e9e6e0f6Smrg    Copyright (C) 1997-2022 Free Software Foundation, Inc.
34fee23f9Smrg    Written by Ian Lance Taylor, Cygnus Solutions.
44fee23f9Smrg 
54fee23f9Smrg This program is free software; you can redistribute it and/or modify it
64fee23f9Smrg under the terms of the GNU General Public License as published by the
74fee23f9Smrg Free Software Foundation; either version 2, or (at your option) any
84fee23f9Smrg later version.
94fee23f9Smrg 
104fee23f9Smrg This program is distributed in the hope that it will be useful,
114fee23f9Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
124fee23f9Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
134fee23f9Smrg GNU General Public License for more details.
144fee23f9Smrg 
154fee23f9Smrg You should have received a copy of the GNU General Public License
164fee23f9Smrg along with this program; if not, write to the Free Software
174fee23f9Smrg Foundation, 51 Franklin Street - Fifth Floor,
184fee23f9Smrg Boston, MA 02110-1301, USA.  */
194fee23f9Smrg 
204fee23f9Smrg #include "config.h"
214fee23f9Smrg #include "ansidecl.h"
224fee23f9Smrg 
234fee23f9Smrg #include "objalloc.h"
244fee23f9Smrg 
254fee23f9Smrg /* Get a definition for NULL.  */
264fee23f9Smrg #include <stdio.h>
274fee23f9Smrg 
284fee23f9Smrg #if VMS
294fee23f9Smrg #include <stdlib.h>
304fee23f9Smrg #include <unixlib.h>
314fee23f9Smrg #else
324fee23f9Smrg 
334fee23f9Smrg /* Get a definition for size_t.  */
344fee23f9Smrg #include <stddef.h>
354fee23f9Smrg 
364fee23f9Smrg #ifdef HAVE_STDLIB_H
374fee23f9Smrg #include <stdlib.h>
384fee23f9Smrg #else
394fee23f9Smrg /* For systems with larger pointers than ints, this must be declared.  */
404fee23f9Smrg extern PTR malloc (size_t);
414fee23f9Smrg extern void free (PTR);
424fee23f9Smrg #endif
434fee23f9Smrg 
444fee23f9Smrg #endif
454fee23f9Smrg 
464fee23f9Smrg /* These routines allocate space for an object.  Freeing allocated
474fee23f9Smrg    space may or may not free all more recently allocated space.
484fee23f9Smrg 
494fee23f9Smrg    We handle large and small allocation requests differently.  If we
504fee23f9Smrg    don't have enough space in the current block, and the allocation
514fee23f9Smrg    request is for more than 512 bytes, we simply pass it through to
524fee23f9Smrg    malloc.  */
534fee23f9Smrg 
544fee23f9Smrg /* The objalloc structure is defined in objalloc.h.  */
554fee23f9Smrg 
564fee23f9Smrg /* This structure appears at the start of each chunk.  */
574fee23f9Smrg 
584fee23f9Smrg struct objalloc_chunk
594fee23f9Smrg {
604fee23f9Smrg   /* Next chunk.  */
614fee23f9Smrg   struct objalloc_chunk *next;
624fee23f9Smrg   /* If this chunk contains large objects, this is the value of
634fee23f9Smrg      current_ptr when this chunk was allocated.  If this chunk
644fee23f9Smrg      contains small objects, this is NULL.  */
654fee23f9Smrg   char *current_ptr;
664fee23f9Smrg };
674fee23f9Smrg 
684fee23f9Smrg /* The aligned size of objalloc_chunk.  */
694fee23f9Smrg 
704fee23f9Smrg #define CHUNK_HEADER_SIZE					\
714fee23f9Smrg   ((sizeof (struct objalloc_chunk) + OBJALLOC_ALIGN - 1)	\
724fee23f9Smrg    &~ (OBJALLOC_ALIGN - 1))
734fee23f9Smrg 
744fee23f9Smrg /* We ask for this much memory each time we create a chunk which is to
754fee23f9Smrg    hold small objects.  */
764fee23f9Smrg 
774fee23f9Smrg #define CHUNK_SIZE (4096 - 32)
784fee23f9Smrg 
794fee23f9Smrg /* A request for this amount or more is just passed through to malloc.  */
804fee23f9Smrg 
814fee23f9Smrg #define BIG_REQUEST (512)
824fee23f9Smrg 
834fee23f9Smrg /* Create an objalloc structure.  */
844fee23f9Smrg 
854fee23f9Smrg struct objalloc *
objalloc_create(void)864fee23f9Smrg objalloc_create (void)
874fee23f9Smrg {
884fee23f9Smrg   struct objalloc *ret;
894fee23f9Smrg   struct objalloc_chunk *chunk;
904fee23f9Smrg 
914fee23f9Smrg   ret = (struct objalloc *) malloc (sizeof *ret);
924fee23f9Smrg   if (ret == NULL)
934fee23f9Smrg     return NULL;
944fee23f9Smrg 
954fee23f9Smrg   ret->chunks = (PTR) malloc (CHUNK_SIZE);
964fee23f9Smrg   if (ret->chunks == NULL)
974fee23f9Smrg     {
984fee23f9Smrg       free (ret);
994fee23f9Smrg       return NULL;
1004fee23f9Smrg     }
1014fee23f9Smrg 
1024fee23f9Smrg   chunk = (struct objalloc_chunk *) ret->chunks;
1034fee23f9Smrg   chunk->next = NULL;
1044fee23f9Smrg   chunk->current_ptr = NULL;
1054fee23f9Smrg 
1064fee23f9Smrg   ret->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE;
1074fee23f9Smrg   ret->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE;
1084fee23f9Smrg 
1094fee23f9Smrg   return ret;
1104fee23f9Smrg }
1114fee23f9Smrg 
1124fee23f9Smrg /* Allocate space from an objalloc structure.  */
1134fee23f9Smrg 
1144fee23f9Smrg PTR
_objalloc_alloc(struct objalloc * o,unsigned long original_len)115d18545deSdrochner _objalloc_alloc (struct objalloc *o, unsigned long original_len)
1164fee23f9Smrg {
117d18545deSdrochner   unsigned long len = original_len;
118d18545deSdrochner 
1194fee23f9Smrg   /* We avoid confusion from zero sized objects by always allocating
1204fee23f9Smrg      at least 1 byte.  */
1214fee23f9Smrg   if (len == 0)
1224fee23f9Smrg     len = 1;
1234fee23f9Smrg 
1244fee23f9Smrg   len = (len + OBJALLOC_ALIGN - 1) &~ (OBJALLOC_ALIGN - 1);
1254fee23f9Smrg 
126d18545deSdrochner   /* Check for overflow in the alignment operation above and the
127d18545deSdrochner      malloc argument below. */
128d18545deSdrochner   if (len + CHUNK_HEADER_SIZE < original_len)
129d18545deSdrochner     return NULL;
130d18545deSdrochner 
1314fee23f9Smrg   if (len <= o->current_space)
1324fee23f9Smrg     {
1334fee23f9Smrg       o->current_ptr += len;
1344fee23f9Smrg       o->current_space -= len;
1354fee23f9Smrg       return (PTR) (o->current_ptr - len);
1364fee23f9Smrg     }
1374fee23f9Smrg 
1384fee23f9Smrg   if (len >= BIG_REQUEST)
1394fee23f9Smrg     {
1404fee23f9Smrg       char *ret;
1414fee23f9Smrg       struct objalloc_chunk *chunk;
1424fee23f9Smrg 
1434fee23f9Smrg       ret = (char *) malloc (CHUNK_HEADER_SIZE + len);
1444fee23f9Smrg       if (ret == NULL)
1454fee23f9Smrg 	return NULL;
1464fee23f9Smrg 
1474fee23f9Smrg       chunk = (struct objalloc_chunk *) ret;
1484fee23f9Smrg       chunk->next = (struct objalloc_chunk *) o->chunks;
1494fee23f9Smrg       chunk->current_ptr = o->current_ptr;
1504fee23f9Smrg 
1514fee23f9Smrg       o->chunks = (PTR) chunk;
1524fee23f9Smrg 
1534fee23f9Smrg       return (PTR) (ret + CHUNK_HEADER_SIZE);
1544fee23f9Smrg     }
1554fee23f9Smrg   else
1564fee23f9Smrg     {
1574fee23f9Smrg       struct objalloc_chunk *chunk;
1584fee23f9Smrg 
1594fee23f9Smrg       chunk = (struct objalloc_chunk *) malloc (CHUNK_SIZE);
1604fee23f9Smrg       if (chunk == NULL)
1614fee23f9Smrg 	return NULL;
1624fee23f9Smrg       chunk->next = (struct objalloc_chunk *) o->chunks;
1634fee23f9Smrg       chunk->current_ptr = NULL;
1644fee23f9Smrg 
1654fee23f9Smrg       o->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE;
1664fee23f9Smrg       o->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE;
1674fee23f9Smrg 
1684fee23f9Smrg       o->chunks = (PTR) chunk;
1694fee23f9Smrg 
1704fee23f9Smrg       return objalloc_alloc (o, len);
1714fee23f9Smrg     }
1724fee23f9Smrg }
1734fee23f9Smrg 
1744fee23f9Smrg /* Free an entire objalloc structure.  */
1754fee23f9Smrg 
1764fee23f9Smrg void
objalloc_free(struct objalloc * o)1774fee23f9Smrg objalloc_free (struct objalloc *o)
1784fee23f9Smrg {
1794fee23f9Smrg   struct objalloc_chunk *l;
1804fee23f9Smrg 
1814fee23f9Smrg   l = (struct objalloc_chunk *) o->chunks;
1824fee23f9Smrg   while (l != NULL)
1834fee23f9Smrg     {
1844fee23f9Smrg       struct objalloc_chunk *next;
1854fee23f9Smrg 
1864fee23f9Smrg       next = l->next;
1874fee23f9Smrg       free (l);
1884fee23f9Smrg       l = next;
1894fee23f9Smrg     }
1904fee23f9Smrg 
1914fee23f9Smrg   free (o);
1924fee23f9Smrg }
1934fee23f9Smrg 
1944fee23f9Smrg /* Free a block from an objalloc structure.  This also frees all more
1954fee23f9Smrg    recently allocated blocks.  */
1964fee23f9Smrg 
1974fee23f9Smrg void
objalloc_free_block(struct objalloc * o,PTR block)1984fee23f9Smrg objalloc_free_block (struct objalloc *o, PTR block)
1994fee23f9Smrg {
2004fee23f9Smrg   struct objalloc_chunk *p, *small;
2014fee23f9Smrg   char *b = (char *) block;
2024fee23f9Smrg 
2034fee23f9Smrg   /* First set P to the chunk which contains the block we are freeing,
2044fee23f9Smrg      and set Q to the last small object chunk we see before P.  */
2054fee23f9Smrg   small = NULL;
2064fee23f9Smrg   for (p = (struct objalloc_chunk *) o->chunks; p != NULL; p = p->next)
2074fee23f9Smrg     {
2084fee23f9Smrg       if (p->current_ptr == NULL)
2094fee23f9Smrg 	{
2104fee23f9Smrg 	  if (b > (char *) p && b < (char *) p + CHUNK_SIZE)
2114fee23f9Smrg 	    break;
2124fee23f9Smrg 	  small = p;
2134fee23f9Smrg 	}
2144fee23f9Smrg       else
2154fee23f9Smrg 	{
2164fee23f9Smrg 	  if (b == (char *) p + CHUNK_HEADER_SIZE)
2174fee23f9Smrg 	    break;
2184fee23f9Smrg 	}
2194fee23f9Smrg     }
2204fee23f9Smrg 
2214fee23f9Smrg   /* If we can't find the chunk, the caller has made a mistake.  */
2224fee23f9Smrg   if (p == NULL)
2234fee23f9Smrg     abort ();
2244fee23f9Smrg 
2254fee23f9Smrg   if (p->current_ptr == NULL)
2264fee23f9Smrg     {
2274fee23f9Smrg       struct objalloc_chunk *q;
2284fee23f9Smrg       struct objalloc_chunk *first;
2294fee23f9Smrg 
2304fee23f9Smrg       /* The block is in a chunk containing small objects.  We can
2314fee23f9Smrg 	 free every chunk through SMALL, because they have certainly
2324fee23f9Smrg 	 been allocated more recently.  After SMALL, we will not see
2334fee23f9Smrg 	 any chunks containing small objects; we can free any big
2344fee23f9Smrg 	 chunk if the current_ptr is greater than or equal to B.  We
2354fee23f9Smrg 	 can then reset the new current_ptr to B.  */
2364fee23f9Smrg 
2374fee23f9Smrg       first = NULL;
2384fee23f9Smrg       q = (struct objalloc_chunk *) o->chunks;
2394fee23f9Smrg       while (q != p)
2404fee23f9Smrg 	{
2414fee23f9Smrg 	  struct objalloc_chunk *next;
2424fee23f9Smrg 
2434fee23f9Smrg 	  next = q->next;
2444fee23f9Smrg 	  if (small != NULL)
2454fee23f9Smrg 	    {
2464fee23f9Smrg 	      if (small == q)
2474fee23f9Smrg 		small = NULL;
2484fee23f9Smrg 	      free (q);
2494fee23f9Smrg 	    }
2504fee23f9Smrg 	  else if (q->current_ptr > b)
2514fee23f9Smrg 	    free (q);
2524fee23f9Smrg 	  else if (first == NULL)
2534fee23f9Smrg 	    first = q;
2544fee23f9Smrg 
2554fee23f9Smrg 	  q = next;
2564fee23f9Smrg 	}
2574fee23f9Smrg 
2584fee23f9Smrg       if (first == NULL)
2594fee23f9Smrg 	first = p;
2604fee23f9Smrg       o->chunks = (PTR) first;
2614fee23f9Smrg 
2624fee23f9Smrg       /* Now start allocating from this small block again.  */
2634fee23f9Smrg       o->current_ptr = b;
2644fee23f9Smrg       o->current_space = ((char *) p + CHUNK_SIZE) - b;
2654fee23f9Smrg     }
2664fee23f9Smrg   else
2674fee23f9Smrg     {
2684fee23f9Smrg       struct objalloc_chunk *q;
2694fee23f9Smrg       char *current_ptr;
2704fee23f9Smrg 
2714fee23f9Smrg       /* This block is in a large chunk by itself.  We can free
2724fee23f9Smrg          everything on the list up to and including this block.  We
2734fee23f9Smrg          then start allocating from the next chunk containing small
2744fee23f9Smrg          objects, setting current_ptr from the value stored with the
2754fee23f9Smrg          large chunk we are freeing.  */
2764fee23f9Smrg 
2774fee23f9Smrg       current_ptr = p->current_ptr;
2784fee23f9Smrg       p = p->next;
2794fee23f9Smrg 
2804fee23f9Smrg       q = (struct objalloc_chunk *) o->chunks;
2814fee23f9Smrg       while (q != p)
2824fee23f9Smrg 	{
2834fee23f9Smrg 	  struct objalloc_chunk *next;
2844fee23f9Smrg 
2854fee23f9Smrg 	  next = q->next;
2864fee23f9Smrg 	  free (q);
2874fee23f9Smrg 	  q = next;
2884fee23f9Smrg 	}
2894fee23f9Smrg 
2904fee23f9Smrg       o->chunks = (PTR) p;
2914fee23f9Smrg 
2924fee23f9Smrg       while (p->current_ptr != NULL)
2934fee23f9Smrg 	p = p->next;
2944fee23f9Smrg 
2954fee23f9Smrg       o->current_ptr = current_ptr;
2964fee23f9Smrg       o->current_space = ((char *) p + CHUNK_SIZE) - current_ptr;
2974fee23f9Smrg     }
2984fee23f9Smrg }
299