Use memset instead of bzero.
[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
f1322139
MD
119static void
120grow (hash_entry_t **table, int *size)
121{
122 hash_entry_t *oldtable = *table;
123 int oldsize = *size + N_SEEK;
124 hash_entry_t *TABLE (new) = 0;
125 int SIZE (new);
126 int i, j;
0e850825 127 SIZE (new) = 2 * (oldsize - N_SEEK + 1) - 1;
f1322139
MD
128 again:
129 TABLE (new) = realloc (TABLE (new),
130 sizeof (hash_entry_t) * (SIZE (new) + N_SEEK));
f22ed5a0 131 memset (TABLE (new), 0, sizeof (hash_entry_t) * (SIZE (new) + N_SEEK));
f1322139
MD
132 for (i = 0; i < oldsize; ++i)
133 if (oldtable[i].key)
134 {
135 hash_entry_t *h = HASH (new, oldtable[i].key);
136 for (j = 0; j < N_SEEK; ++j)
137 if (h[j].key == 0)
138 {
139 h[j] = oldtable[i];
140 goto next;
141 }
142 SIZE (new) *= 2;
143 goto again;
144 next:
145 ;
146 }
147 if (table == &malloc_type)
148 {
149 /* relocate malloc_object entries */
150 for (i = 0; i < oldsize; ++i)
151 if (oldtable[i].key)
152 {
153 hash_entry_t *h = HASH (new, oldtable[i].key);
154 while (h->key != oldtable[i].key)
155 ++h;
156 oldtable[i].data = h;
157 }
158 for (i = 0; i < malloc_object_size + N_SEEK; ++i)
159 if (malloc_object[i].key)
160 malloc_object[i].data
161 = ((hash_entry_t *) malloc_object[i].data)->data;
162 }
163 free (*table);
164 *table = TABLE (new);
165 *size = SIZE (new);
166}
167
168void
169scm_malloc_register (void *obj, const char *what)
170{
171 hash_entry_t *type;
172 GET_CREATE_HASH_ENTRY (type, type, what, l1);
173 type->data = (void *) ((int) type->data + 1);
174 CREATE_HASH_ENTRY (object, obj, type, l2);
175}
176
177void
178scm_malloc_unregister (void *obj)
179{
180 hash_entry_t *object, *type;
181 GET_CREATE_HASH_ENTRY (object, object, obj, l1);
182 type = (hash_entry_t *) object->data;
183 if (type == 0)
184 {
185 fprintf (stderr,
186 "scm_must_free called on object not allocated with scm_must_malloc\n");
187 abort ();
188 }
189 type->data = (void *) ((int) type->data - 1);
190 object->key = 0;
191}
192
193void
194scm_malloc_reregister (void *old, void *new, const char *newwhat)
195{
196 hash_entry_t *object, *type;
197 GET_CREATE_HASH_ENTRY (object, object, old, l1);
198 type = (hash_entry_t *) object->data;
199 if (type == 0)
200 {
201 fprintf (stderr,
202 "scm_must_realloc called on object not allocated with scm_must_malloc\n");
203 abort ();
204 }
205 if (strcmp ((char *) type->key, newwhat) != 0)
206 {
207 if (strcmp (newwhat, "vector-set-length!") != 0)
208 {
209 fprintf (stderr,
210 "scm_must_realloc called with arg %s, was %s\n",
211 newwhat,
212 (char *) type->key);
213 abort ();
214 }
215 }
216 if (new != old)
217 {
218 object->key = 0;
219 CREATE_HASH_ENTRY (object, new, type, l2);
220 }
221}
222
223SCM_DEFINE (scm_malloc_stats, "malloc-stats", 0, 0, 0,
224 (),
6836c87b
MG
225 "Return an alist ((@var{what} . @var{n}) ...) describing number\n"
226 "of malloced objects.\n"
227 "@var{what} is the second argument to @code{scm_must_malloc},\n"
228 "@var{n} is the number of objects of that type currently\n"
229 "allocated.")
f1322139
MD
230#define FUNC_NAME s_scm_malloc_stats
231{
232 SCM res = SCM_EOL;
233 int i;
234 for (i = 0; i < malloc_type_size + N_SEEK; ++i)
235 if (malloc_type[i].key)
236 res = scm_acons (scm_makfrom0str ((char *) malloc_type[i].key),
237 SCM_MAKINUM ((int) malloc_type[i].data),
238 res);
239 return res;
240}
241#undef FUNC_NAME
242
243void
244scm_debug_malloc_prehistory ()
245{
246 malloc_type = malloc (sizeof (hash_entry_t)
247 * (malloc_type_size + N_SEEK));
f22ed5a0 248 memset (malloc_type, 0, sizeof (hash_entry_t) * (malloc_type_size + N_SEEK));
f1322139
MD
249 malloc_object = malloc (sizeof (hash_entry_t)
250 * (malloc_object_size + N_SEEK));
f22ed5a0 251 memset (malloc_object, 0, sizeof (hash_entry_t) * (malloc_object_size + N_SEEK));
f1322139
MD
252}
253
254void
255scm_init_debug_malloc ()
256{
8dc9439f 257#ifndef SCM_MAGIC_SNARFER
0e850825 258#include "libguile/debug-malloc.x"
8dc9439f 259#endif
f1322139 260}
8dc9439f 261