source: trunk/gc6.8/malloc.c@ 132

Last change on this file since 132 was 132, checked in by cinc, 19 years ago

Boehm-Demers-Weiser garbage collector. Single-threaded for OS/2.

File size: 14.2 KB
Line 
1/*
2 * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3 * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
4 * Copyright (c) 2000 by Hewlett-Packard Company. All rights reserved.
5 *
6 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
7 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
8 *
9 * Permission is hereby granted to use or copy this program
10 * for any purpose, provided the above notices are retained on all copies.
11 * Permission to modify the code and to distribute modified code is granted,
12 * provided the above notices are retained, and a notice that the code was
13 * modified is included with the above copyright notice.
14 */
15/* Boehm, February 7, 1996 4:32 pm PST */
16
17#include <stdio.h>
18#include <string.h>
19#include <errno.h>
20#include "private/gc_priv.h"
21
22extern ptr_t GC_clear_stack(); /* in misc.c, behaves like identity */
23void GC_extend_size_map(); /* in misc.c. */
24
25/* Allocate reclaim list for kind: */
26/* Return TRUE on success */
27GC_bool GC_alloc_reclaim_list(kind)
28register struct obj_kind * kind;
29{
30 struct hblk ** result = (struct hblk **)
31 GC_scratch_alloc((MAXOBJSZ+1) * sizeof(struct hblk *));
32 if (result == 0) return(FALSE);
33 BZERO(result, (MAXOBJSZ+1)*sizeof(struct hblk *));
34 kind -> ok_reclaim_list = result;
35 return(TRUE);
36}
37
38/* Allocate a large block of size lw words. */
39/* The block is not cleared. */
40/* Flags is 0 or IGNORE_OFF_PAGE. */
41/* We hold the allocation lock. */
42ptr_t GC_alloc_large(lw, k, flags)
43word lw;
44int k;
45unsigned flags;
46{
47 struct hblk * h;
48 word n_blocks = OBJ_SZ_TO_BLOCKS(lw);
49 ptr_t result;
50
51 if (!GC_is_initialized) GC_init_inner();
52 /* Do our share of marking work */
53 if(GC_incremental && !GC_dont_gc)
54 GC_collect_a_little_inner((int)n_blocks);
55 h = GC_allochblk(lw, k, flags);
56# ifdef USE_MUNMAP
57 if (0 == h) {
58 GC_merge_unmapped();
59 h = GC_allochblk(lw, k, flags);
60 }
61# endif
62 while (0 == h && GC_collect_or_expand(n_blocks, (flags != 0))) {
63 h = GC_allochblk(lw, k, flags);
64 }
65 if (h == 0) {
66 result = 0;
67 } else {
68 int total_bytes = n_blocks * HBLKSIZE;
69 if (n_blocks > 1) {
70 GC_large_allocd_bytes += total_bytes;
71 if (GC_large_allocd_bytes > GC_max_large_allocd_bytes)
72 GC_max_large_allocd_bytes = GC_large_allocd_bytes;
73 }
74 result = (ptr_t) (h -> hb_body);
75 GC_words_wasted += BYTES_TO_WORDS(total_bytes) - lw;
76 }
77 return result;
78}
79
80
81/* Allocate a large block of size lb bytes. Clear if appropriate. */
82/* We hold the allocation lock. */
83ptr_t GC_alloc_large_and_clear(lw, k, flags)
84word lw;
85int k;
86unsigned flags;
87{
88 ptr_t result = GC_alloc_large(lw, k, flags);
89 word n_blocks = OBJ_SZ_TO_BLOCKS(lw);
90
91 if (0 == result) return 0;
92 if (GC_debugging_started || GC_obj_kinds[k].ok_init) {
93 /* Clear the whole block, in case of GC_realloc call. */
94 BZERO(result, n_blocks * HBLKSIZE);
95 }
96 return result;
97}
98
99/* allocate lb bytes for an object of kind k. */
100/* Should not be used to directly to allocate */
101/* objects such as STUBBORN objects that */
102/* require special handling on allocation. */
103/* First a version that assumes we already */
104/* hold lock: */
105ptr_t GC_generic_malloc_inner(lb, k)
106register word lb;
107register int k;
108{
109register word lw;
110register ptr_t op;
111register ptr_t *opp;
112
113 if( SMALL_OBJ(lb) ) {
114 register struct obj_kind * kind = GC_obj_kinds + k;
115# ifdef MERGE_SIZES
116 lw = GC_size_map[lb];
117# else
118 lw = ALIGNED_WORDS(lb);
119 if (lw == 0) lw = MIN_WORDS;
120# endif
121 opp = &(kind -> ok_freelist[lw]);
122 if( (op = *opp) == 0 ) {
123# ifdef MERGE_SIZES
124 if (GC_size_map[lb] == 0) {
125 if (!GC_is_initialized) GC_init_inner();
126 if (GC_size_map[lb] == 0) GC_extend_size_map(lb);
127 return(GC_generic_malloc_inner(lb, k));
128 }
129# else
130 if (!GC_is_initialized) {
131 GC_init_inner();
132 return(GC_generic_malloc_inner(lb, k));
133 }
134# endif
135 if (kind -> ok_reclaim_list == 0) {
136 if (!GC_alloc_reclaim_list(kind)) goto out;
137 }
138 op = GC_allocobj(lw, k);
139 if (op == 0) goto out;
140 }
141 /* Here everything is in a consistent state. */
142 /* We assume the following assignment is */
143 /* atomic. If we get aborted */
144 /* after the assignment, we lose an object, */
145 /* but that's benign. */
146 /* Volatile declarations may need to be added */
147 /* to prevent the compiler from breaking things.*/
148 /* If we only execute the second of the */
149 /* following assignments, we lose the free */
150 /* list, but that should still be OK, at least */
151 /* for garbage collected memory. */
152 *opp = obj_link(op);
153 obj_link(op) = 0;
154 } else {
155 lw = ROUNDED_UP_WORDS(lb);
156 op = (ptr_t)GC_alloc_large_and_clear(lw, k, 0);
157 }
158 GC_words_allocd += lw;
159
160out:
161 return op;
162}
163
164/* Allocate a composite object of size n bytes. The caller guarantees */
165/* that pointers past the first page are not relevant. Caller holds */
166/* allocation lock. */
167ptr_t GC_generic_malloc_inner_ignore_off_page(lb, k)
168register size_t lb;
169register int k;
170{
171 register word lw;
172 ptr_t op;
173
174 if (lb <= HBLKSIZE)
175 return(GC_generic_malloc_inner((word)lb, k));
176 lw = ROUNDED_UP_WORDS(lb);
177 op = (ptr_t)GC_alloc_large_and_clear(lw, k, IGNORE_OFF_PAGE);
178 GC_words_allocd += lw;
179 return op;
180}
181
182ptr_t GC_generic_malloc(lb, k)
183register word lb;
184register int k;
185{
186 ptr_t result;
187 DCL_LOCK_STATE;
188
189 if (GC_have_errors) GC_print_all_errors();
190 GC_INVOKE_FINALIZERS();
191 if (SMALL_OBJ(lb)) {
192 DISABLE_SIGNALS();
193 LOCK();
194 result = GC_generic_malloc_inner((word)lb, k);
195 UNLOCK();
196 ENABLE_SIGNALS();
197 } else {
198 word lw;
199 word n_blocks;
200 GC_bool init;
201 lw = ROUNDED_UP_WORDS(lb);
202 n_blocks = OBJ_SZ_TO_BLOCKS(lw);
203 init = GC_obj_kinds[k].ok_init;
204 DISABLE_SIGNALS();
205 LOCK();
206 result = (ptr_t)GC_alloc_large(lw, k, 0);
207 if (0 != result) {
208 if (GC_debugging_started) {
209 BZERO(result, n_blocks * HBLKSIZE);
210 } else {
211# ifdef THREADS
212 /* Clear any memory that might be used for GC descriptors */
213 /* before we release the lock. */
214 ((word *)result)[0] = 0;
215 ((word *)result)[1] = 0;
216 ((word *)result)[lw-1] = 0;
217 ((word *)result)[lw-2] = 0;
218# endif
219 }
220 }
221 GC_words_allocd += lw;
222 UNLOCK();
223 ENABLE_SIGNALS();
224 if (init && !GC_debugging_started && 0 != result) {
225 BZERO(result, n_blocks * HBLKSIZE);
226 }
227 }
228 if (0 == result) {
229 return((*GC_oom_fn)(lb));
230 } else {
231 return(result);
232 }
233}
234
235
236#define GENERAL_MALLOC(lb,k) \
237 (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
238/* We make the GC_clear_stack_call a tail call, hoping to get more of */
239/* the stack. */
240
241/* Allocate lb bytes of atomic (pointerfree) data */
242# ifdef __STDC__
243 GC_PTR GC_malloc_atomic(size_t lb)
244# else
245 GC_PTR GC_malloc_atomic(lb)
246 size_t lb;
247# endif
248{
249register ptr_t op;
250register ptr_t * opp;
251register word lw;
252DCL_LOCK_STATE;
253
254 if( EXPECT(SMALL_OBJ(lb), 1) ) {
255# ifdef MERGE_SIZES
256 lw = GC_size_map[lb];
257# else
258 lw = ALIGNED_WORDS(lb);
259# endif
260 opp = &(GC_aobjfreelist[lw]);
261 FASTLOCK();
262 if( EXPECT(!FASTLOCK_SUCCEEDED() || (op = *opp) == 0, 0) ) {
263 FASTUNLOCK();
264 return(GENERAL_MALLOC((word)lb, PTRFREE));
265 }
266 /* See above comment on signals. */
267 *opp = obj_link(op);
268 GC_words_allocd += lw;
269 FASTUNLOCK();
270 return((GC_PTR) op);
271 } else {
272 return(GENERAL_MALLOC((word)lb, PTRFREE));
273 }
274}
275
276/* provide a version of strdup() that uses the collector to allocate the
277 copy of the string */
278# ifdef __STDC__
279 char *GC_strdup(const char *s)
280# else
281 char *GC_strdup(s)
282 char *s;
283#endif
284{
285 char *copy;
286
287 if (s == NULL) return NULL;
288 if ((copy = GC_malloc_atomic(strlen(s) + 1)) == NULL) {
289 errno = ENOMEM;
290 return NULL;
291 }
292 strcpy(copy, s);
293 return copy;
294}
295
296/* Allocate lb bytes of composite (pointerful) data */
297# ifdef __STDC__
298 GC_PTR GC_malloc(size_t lb)
299# else
300 GC_PTR GC_malloc(lb)
301 size_t lb;
302# endif
303{
304register ptr_t op;
305register ptr_t *opp;
306register word lw;
307DCL_LOCK_STATE;
308
309 if( EXPECT(SMALL_OBJ(lb), 1) ) {
310# ifdef MERGE_SIZES
311 lw = GC_size_map[lb];
312# else
313 lw = ALIGNED_WORDS(lb);
314# endif
315 opp = &(GC_objfreelist[lw]);
316 FASTLOCK();
317 if( EXPECT(!FASTLOCK_SUCCEEDED() || (op = *opp) == 0, 0) ) {
318 FASTUNLOCK();
319 return(GENERAL_MALLOC((word)lb, NORMAL));
320 }
321 /* See above comment on signals. */
322 GC_ASSERT(0 == obj_link(op)
323 || (word)obj_link(op)
324 <= (word)GC_greatest_plausible_heap_addr
325 && (word)obj_link(op)
326 >= (word)GC_least_plausible_heap_addr);
327 *opp = obj_link(op);
328 obj_link(op) = 0;
329 GC_words_allocd += lw;
330 FASTUNLOCK();
331 return((GC_PTR) op);
332 } else {
333 return(GENERAL_MALLOC((word)lb, NORMAL));
334 }
335}
336
337# ifdef REDIRECT_MALLOC
338
339/* Avoid unnecessary nested procedure calls here, by #defining some */
340/* malloc replacements. Otherwise we end up saving a */
341/* meaningless return address in the object. It also speeds things up, */
342/* but it is admittedly quite ugly. */
343# ifdef GC_ADD_CALLER
344# define RA GC_RETURN_ADDR,
345# else
346# define RA
347# endif
348# define GC_debug_malloc_replacement(lb) \
349 GC_debug_malloc(lb, RA "unknown", 0)
350
351# ifdef __STDC__
352 GC_PTR malloc(size_t lb)
353# else
354 GC_PTR malloc(lb)
355 size_t lb;
356# endif
357 {
358# if defined(GC_WIN32_THREADS) && defined(__GNUC__)
359 /* According to Gerard Allen, this helps with MINGW. */
360 /* When using threads need to initalised before use, but GCC uses a malloc
361 in __w32_sharedptr_initialize (w32-shared-ptr.c) */
362 if (!GC_is_initialized) GC_init();
363# endif
364 /* It might help to manually inline the GC_malloc call here. */
365 /* But any decent compiler should reduce the extra procedure call */
366 /* to at most a jump instruction in this case. */
367# if defined(I386) && defined(GC_SOLARIS_THREADS)
368 /*
369 * Thread initialisation can call malloc before
370 * we're ready for it.
371 * It's not clear that this is enough to help matters.
372 * The thread implementation may well call malloc at other
373 * inopportune times.
374 */
375 if (!GC_is_initialized) return sbrk(lb);
376# endif /* I386 && GC_SOLARIS_THREADS */
377 return((GC_PTR)REDIRECT_MALLOC(lb));
378 }
379
380# ifdef __STDC__
381 GC_PTR calloc(size_t n, size_t lb)
382# else
383 GC_PTR calloc(n, lb)
384 size_t n, lb;
385# endif
386 {
387 return((GC_PTR)REDIRECT_MALLOC(n*lb));
388 }
389
390#ifndef strdup
391# include <string.h>
392# ifdef __STDC__
393 char *strdup(const char *s)
394# else
395 char *strdup(s)
396 char *s;
397# endif
398 {
399 size_t len = strlen(s) + 1;
400 char * result = ((char *)REDIRECT_MALLOC(len+1));
401 if (result == 0) {
402 errno = ENOMEM;
403 return 0;
404 }
405 BCOPY(s, result, len+1);
406 return result;
407 }
408#endif /* !defined(strdup) */
409 /* If strdup is macro defined, we assume that it actually calls malloc, */
410 /* and thus the right thing will happen even without overriding it. */
411 /* This seems to be true on most Linux systems. */
412
413#undef GC_debug_malloc_replacement
414
415# endif /* REDIRECT_MALLOC */
416
417/* Explicitly deallocate an object p. */
418# ifdef __STDC__
419 void GC_free(GC_PTR p)
420# else
421 void GC_free(p)
422 GC_PTR p;
423# endif
424{
425 register struct hblk *h;
426 register hdr *hhdr;
427 register signed_word sz;
428 register ptr_t * flh;
429 register int knd;
430 register struct obj_kind * ok;
431 DCL_LOCK_STATE;
432
433 if (p == 0) return;
434 /* Required by ANSI. It's not my fault ... */
435 h = HBLKPTR(p);
436 hhdr = HDR(h);
437 GC_ASSERT(GC_base(p) == p);
438# if defined(REDIRECT_MALLOC) && \
439 (defined(GC_SOLARIS_THREADS) || defined(GC_LINUX_THREADS) \
440 || defined(__MINGW32__)) /* Should this be MSWIN32 in general? */
441 /* For Solaris, we have to redirect malloc calls during */
442 /* initialization. For the others, this seems to happen */
443 /* implicitly. */
444 /* Don't try to deallocate that memory. */
445 if (0 == hhdr) return;
446# endif
447 knd = hhdr -> hb_obj_kind;
448 sz = hhdr -> hb_sz;
449 ok = &GC_obj_kinds[knd];
450 if (EXPECT((sz <= MAXOBJSZ), 1)) {
451# ifdef THREADS
452 DISABLE_SIGNALS();
453 LOCK();
454# endif
455 GC_mem_freed += sz;
456 /* A signal here can make GC_mem_freed and GC_non_gc_bytes */
457 /* inconsistent. We claim this is benign. */
458 if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= WORDS_TO_BYTES(sz);
459 /* Its unnecessary to clear the mark bit. If the */
460 /* object is reallocated, it doesn't matter. O.w. the */
461 /* collector will do it, since it's on a free list. */
462 if (ok -> ok_init) {
463 BZERO((word *)p + 1, WORDS_TO_BYTES(sz-1));
464 }
465 flh = &(ok -> ok_freelist[sz]);
466 obj_link(p) = *flh;
467 *flh = (ptr_t)p;
468# ifdef THREADS
469 UNLOCK();
470 ENABLE_SIGNALS();
471# endif
472 } else {
473 DISABLE_SIGNALS();
474 LOCK();
475 GC_mem_freed += sz;
476 if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= WORDS_TO_BYTES(sz);
477 GC_freehblk(h);
478 UNLOCK();
479 ENABLE_SIGNALS();
480 }
481}
482
483/* Explicitly deallocate an object p when we already hold lock. */
484/* Only used for internally allocated objects, so we can take some */
485/* shortcuts. */
486#ifdef THREADS
487void GC_free_inner(GC_PTR p)
488{
489 register struct hblk *h;
490 register hdr *hhdr;
491 register signed_word sz;
492 register ptr_t * flh;
493 register int knd;
494 register struct obj_kind * ok;
495 DCL_LOCK_STATE;
496
497 h = HBLKPTR(p);
498 hhdr = HDR(h);
499 knd = hhdr -> hb_obj_kind;
500 sz = hhdr -> hb_sz;
501 ok = &GC_obj_kinds[knd];
502 if (sz <= MAXOBJSZ) {
503 GC_mem_freed += sz;
504 if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= WORDS_TO_BYTES(sz);
505 if (ok -> ok_init) {
506 BZERO((word *)p + 1, WORDS_TO_BYTES(sz-1));
507 }
508 flh = &(ok -> ok_freelist[sz]);
509 obj_link(p) = *flh;
510 *flh = (ptr_t)p;
511 } else {
512 GC_mem_freed += sz;
513 if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= WORDS_TO_BYTES(sz);
514 GC_freehblk(h);
515 }
516}
517#endif /* THREADS */
518
519# if defined(REDIRECT_MALLOC) && !defined(REDIRECT_FREE)
520# define REDIRECT_FREE GC_free
521# endif
522# ifdef REDIRECT_FREE
523# ifdef __STDC__
524 void free(GC_PTR p)
525# else
526 void free(p)
527 GC_PTR p;
528# endif
529 {
530# ifndef IGNORE_FREE
531 REDIRECT_FREE(p);
532# endif
533 }
534# endif /* REDIRECT_MALLOC */
Note: See TracBrowser for help on using the repository browser.