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