* Fix dvi build problem.
[bpt/guile.git] / libguile / debug-malloc.c
CommitLineData
f1322139
MD
1/* Copyright (C) 2000 Free Software Foundation, Inc.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
41
f1322139 42#include <string.h>
67e8151b 43#include <stdio.h>
f1322139 44
a0599745
MD
45#include "libguile/_scm.h"
46#include "libguile/alist.h"
47#include "libguile/strings.h"
f1322139 48
0e850825 49#include "libguile/debug-malloc.h"
f1322139
MD
50
51/*
eb422a4c
MD
52 * The following code is a hack which I wrote quickly in order to
53 * solve a memory leak problem. Since I wanted to have the
54 * application running at close to normal speed, I prioritized speed
55 * over maintainability. /mdj
f1322139
MD
56 */
57
58typedef struct hash_entry {
59 const void *key;
60 const void *data;
61} hash_entry_t;
62
63#define N_SEEK 8
64
65static int malloc_type_size = 31;
66static hash_entry_t *malloc_type = 0;
0e850825 67static int malloc_object_size = 8191;
f1322139
MD
68static hash_entry_t *malloc_object = 0;
69
70#define TABLE(table) malloc_ ## table
71#define SIZE(table) malloc_ ## table ## _size
72#define HASH(table, key) \
73 &TABLE (table)[((unsigned long) key >> 4UL) * 2654435761UL % SIZE (table)]
74
75#define CREATE_HASH_ENTRY_AT(entry, table, h, k, done) \
76{ \
77 int i; \
78 do \
79 { \
80 for (i = 0; i < N_SEEK; ++i) \
81 if (h[i].key == 0) \
82 goto done; \
83 grow (&TABLE (table), &SIZE (table)); \
84 h = HASH (table, k); \
85 } \
86 while (1); \
87 done: \
88 (entry) = &h[i]; \
89}
90
91#define CREATE_HASH_ENTRY(table, k, d, done) \
92 do \
93 { \
94 hash_entry_t *h = HASH (table, k); \
95 hash_entry_t *entry; \
96 CREATE_HASH_ENTRY_AT (entry, table, h, k, done); \
97 entry->key = (k); \
98 entry->data = (d); \
99 } \
100 while (0)
101
102#define GET_CREATE_HASH_ENTRY(entry, table, k, done) \
103 do \
104 { \
105 hash_entry_t *h = HASH (table, k); \
106 int i; \
107 for (i = 0; i < N_SEEK; ++i) \
108 if (h[i].key == (void *) (k)) \
109 goto done; \
110 CREATE_HASH_ENTRY_AT (entry, table, h, k, gche ## done); \
111 entry->key = (k); \
112 entry->data = 0; \
113 break; \
114 done: \
115 (entry) = &h[i]; \
116 } \
117 while (0)
118
119#ifdef MISSING_BZERO_DECL
120extern void bzero (void *, size_t);
121#endif
122
123static void
124grow (hash_entry_t **table, int *size)
125{
126 hash_entry_t *oldtable = *table;
127 int oldsize = *size + N_SEEK;
128 hash_entry_t *TABLE (new) = 0;
129 int SIZE (new);
130 int i, j;
0e850825 131 SIZE (new) = 2 * (oldsize - N_SEEK + 1) - 1;
f1322139
MD
132 again:
133 TABLE (new) = realloc (TABLE (new),
134 sizeof (hash_entry_t) * (SIZE (new) + N_SEEK));
135 bzero (TABLE (new), sizeof (hash_entry_t) * (SIZE (new) + N_SEEK));
136 for (i = 0; i < oldsize; ++i)
137 if (oldtable[i].key)
138 {
139 hash_entry_t *h = HASH (new, oldtable[i].key);
140 for (j = 0; j < N_SEEK; ++j)
141 if (h[j].key == 0)
142 {
143 h[j] = oldtable[i];
144 goto next;
145 }
146 SIZE (new) *= 2;
147 goto again;
148 next:
149 ;
150 }
151 if (table == &malloc_type)
152 {
153 /* relocate malloc_object entries */
154 for (i = 0; i < oldsize; ++i)
155 if (oldtable[i].key)
156 {
157 hash_entry_t *h = HASH (new, oldtable[i].key);
158 while (h->key != oldtable[i].key)
159 ++h;
160 oldtable[i].data = h;
161 }
162 for (i = 0; i < malloc_object_size + N_SEEK; ++i)
163 if (malloc_object[i].key)
164 malloc_object[i].data
165 = ((hash_entry_t *) malloc_object[i].data)->data;
166 }
167 free (*table);
168 *table = TABLE (new);
169 *size = SIZE (new);
170}
171
172void
173scm_malloc_register (void *obj, const char *what)
174{
175 hash_entry_t *type;
176 GET_CREATE_HASH_ENTRY (type, type, what, l1);
177 type->data = (void *) ((int) type->data + 1);
178 CREATE_HASH_ENTRY (object, obj, type, l2);
179}
180
181void
182scm_malloc_unregister (void *obj)
183{
184 hash_entry_t *object, *type;
185 GET_CREATE_HASH_ENTRY (object, object, obj, l1);
186 type = (hash_entry_t *) object->data;
187 if (type == 0)
188 {
189 fprintf (stderr,
190 "scm_must_free called on object not allocated with scm_must_malloc\n");
191 abort ();
192 }
193 type->data = (void *) ((int) type->data - 1);
194 object->key = 0;
195}
196
197void
198scm_malloc_reregister (void *old, void *new, const char *newwhat)
199{
200 hash_entry_t *object, *type;
201 GET_CREATE_HASH_ENTRY (object, object, old, l1);
202 type = (hash_entry_t *) object->data;
203 if (type == 0)
204 {
205 fprintf (stderr,
206 "scm_must_realloc called on object not allocated with scm_must_malloc\n");
207 abort ();
208 }
209 if (strcmp ((char *) type->key, newwhat) != 0)
210 {
211 if (strcmp (newwhat, "vector-set-length!") != 0)
212 {
213 fprintf (stderr,
214 "scm_must_realloc called with arg %s, was %s\n",
215 newwhat,
216 (char *) type->key);
217 abort ();
218 }
219 }
220 if (new != old)
221 {
222 object->key = 0;
223 CREATE_HASH_ENTRY (object, new, type, l2);
224 }
225}
226
227SCM_DEFINE (scm_malloc_stats, "malloc-stats", 0, 0, 0,
228 (),
6836c87b
MG
229 "Return an alist ((@var{what} . @var{n}) ...) describing number\n"
230 "of malloced objects.\n"
231 "@var{what} is the second argument to @code{scm_must_malloc},\n"
232 "@var{n} is the number of objects of that type currently\n"
233 "allocated.")
f1322139
MD
234#define FUNC_NAME s_scm_malloc_stats
235{
236 SCM res = SCM_EOL;
237 int i;
238 for (i = 0; i < malloc_type_size + N_SEEK; ++i)
239 if (malloc_type[i].key)
240 res = scm_acons (scm_makfrom0str ((char *) malloc_type[i].key),
241 SCM_MAKINUM ((int) malloc_type[i].data),
242 res);
243 return res;
244}
245#undef FUNC_NAME
246
247void
248scm_debug_malloc_prehistory ()
249{
250 malloc_type = malloc (sizeof (hash_entry_t)
251 * (malloc_type_size + N_SEEK));
252 bzero (malloc_type, sizeof (hash_entry_t) * (malloc_type_size + N_SEEK));
253 malloc_object = malloc (sizeof (hash_entry_t)
254 * (malloc_object_size + N_SEEK));
255 bzero (malloc_object, sizeof (hash_entry_t) * (malloc_object_size + N_SEEK));
256}
257
258void
259scm_init_debug_malloc ()
260{
8dc9439f 261#ifndef SCM_MAGIC_SNARFER
0e850825 262#include "libguile/debug-malloc.x"
8dc9439f 263#endif
f1322139 264}
8dc9439f 265