summaryrefslogtreecommitdiff
path: root/ar/alloca.c
blob: 80c95e2b08596b3c9d677699108400469820e5b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

#ifdef __STDC__
#include <stdlib.h>
#else
#include <memory.h>
#include <string.h>
#endif

#if defined(__TINYC__) || defined(__HP_cc)
typedef union mem_cell
{
   union mem_cell *next;	/* A pointer to the next mem */
   unsigned int size;		/* An int >= sizeof pointer */
   char *depth;			/* For the alloca hack */
}
mem;

#define m_size(p)  ((p) [0].size)	/* For malloc */
#define m_next(p)  ((p) [1].next)	/* For malloc and alloca */
#define m_deep(p)  ((p) [0].depth)	/* For alloca */

static mem *alloca_stack = 0;

void *
alloca(size)
size_t size;
{
   auto char probe;		/* Probes stack depth: */
   register mem *hp;

   /*
    * Reclaim garbage, defined as all alloca'd storage that was allocated
    * from deeper in the stack than currently.
    */

   for (hp = alloca_stack; hp != 0;)
      if (m_deep(hp) < &probe)
      {
	 register mem *np = m_next(hp);
	 free((void *) hp);	/* Collect garbage.  */
	 hp = np;		/* -> next header.  */
      }
      else
	 break;			/* Rest are not deeper.  */

   alloca_stack = hp;		/* -> last valid storage.  */
   if (size == 0)
      return 0;			/* No allocation required.  */

   hp = (mem *) malloc(sizeof(mem)*2 + size);
   if (hp == 0)
      return hp;

   m_next(hp) = alloca_stack;
   m_deep(hp) = &probe;
   alloca_stack = hp;

   /* User storage begins just after header.  */
   return (void *) (hp + 2);
}
#endif