1 /* 2 * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers 3 * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. 4 * Copyright (c) 2005 Hewlett-Packard Development Company, L.P. 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 16 /* USE OF THIS FILE IS NOT RECOMMENDED unless GC_all_interior_pointers */ 17 /* is not set, or the collector has been built with */ 18 /* -DDONT_ADD_BYTE_AT_END, or the specified size includes a pointerfree */ 19 /* word at the end. In the standard collector configuration, */ 20 /* the final word of each object may not be scanned. */ 21 /* This interface is most useful for compilers that generate C. */ 22 /* It is also used internally for thread-local allocation, in which */ 23 /* case, the size is suitably adjusted by the caller. */ 24 /* Manual use is hereby discouraged. */ 25 26 #include "gc.h" 27 #include "gc_tiny_fl.h" 28 29 #if __GNUC__ >= 3 30 # define GC_EXPECT(expr, outcome) __builtin_expect(expr,outcome) 31 /* Equivalent to (expr), but predict that usually (expr)==outcome. */ 32 #else 33 # define GC_EXPECT(expr, outcome) (expr) 34 #endif /* __GNUC__ */ 35 36 /* The ultimately general inline allocation macro. Allocate an object */ 37 /* of size bytes, putting the resulting pointer in result. Tiny_fl is */ 38 /* a "tiny" free list array, which will be used first, if the size */ 39 /* is appropriate. If bytes is too large, we allocate with */ 40 /* default_expr instead. If we need to refill the free list, we use */ 41 /* GC_generic_malloc_many with the indicated kind. */ 42 /* Tiny_fl should be an array of GC_TINY_FREELISTS void * pointers. */ 43 /* If num_direct is nonzero, and the individual free list pointers */ 44 /* are initialized to (void *)1, then we allocate numdirect granules */ 45 /* directly using gmalloc before putting multiple objects into the */ 46 /* tiny_fl entry. If num_direct is zero, then the free lists may also */ 47 /* be initialized to (void *)0. */ 48 /* We rely on much of this hopefully getting optimized away in the */ 49 /* num_direct = 0 case. */ 50 /* Particularly if bytes is constant, this should generate a small */ 51 /* amount of code. */ 52 # define GC_FAST_MALLOC_GRANS(result,granules,tiny_fl,num_direct,\ 53 kind,default_expr,init) \ 54 { \ 55 if (GC_EXPECT(granules >= GC_TINY_FREELISTS,0)) { \ 56 result = default_expr; \ 57 } else { \ 58 void **my_fl = tiny_fl + granules; \ 59 void *my_entry=*my_fl; \ 60 void *next; \ 61 \ 62 while (GC_EXPECT((GC_word)my_entry \ 63 <= num_direct + GC_TINY_FREELISTS + 1, 0)) { \ 64 /* Entry contains counter or NULL */ \ 65 if ((GC_word)my_entry - 1 < num_direct) { \ 66 /* Small counter value, not NULL */ \ 67 *my_fl = (ptr_t)my_entry + granules + 1; \ 68 result = default_expr; \ 69 goto out; \ 70 } else { \ 71 /* Large counter or NULL */ \ 72 GC_generic_malloc_many(((granules) == 0? GC_GRANULE_BYTES : \ 73 RAW_BYTES_FROM_INDEX(granules)), \ 74 kind, my_fl); \ 75 my_entry = *my_fl; \ 76 if (my_entry == 0) { \ 77 result = GC_oom_fn(bytes); \ 78 goto out; \ 79 } \ 80 } \ 81 } \ 82 next = *(void **)(my_entry); \ 83 result = (void *)my_entry; \ 84 *my_fl = next; \ 85 init; \ 86 PREFETCH_FOR_WRITE(next); \ 87 GC_ASSERT(GC_size(result) >= bytes + EXTRA_BYTES); \ 88 GC_ASSERT((kind) == PTRFREE || ((GC_word *)result)[1] == 0); \ 89 out: ; \ 90 } \ 91 } 92 93 # define GC_WORDS_TO_WHOLE_GRANULES(n) \ 94 GC_WORDS_TO_GRANULES((n) + GC_GRANULE_WORDS - 1) 95 96 /* Allocate n words (NOT BYTES). X is made to point to the result. */ 97 /* This should really only be used if GC_all_interior_pointers is */ 98 /* not set, or DONT_ADD_BYTE_AT_END is set. See above. */ 99 /* The semantics changed in version 7.0; we no longer lock, and */ 100 /* the caller is responsible for supplying a cleared tiny_fl */ 101 /* free list array. For single-threaded applications, this may be */ 102 /* a global array. */ 103 # define GC_MALLOC_WORDS(result,n,tiny_fl) \ 104 { \ 105 size_t grans = WORDS_TO_WHOLE_GRANULES(n); \ 106 GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \ 107 NORMAL, GC_malloc(grans*GRANULE_BYTES), \ 108 *(void **)result = 0); \ 109 } 110 111 # define GC_MALLOC_ATOMIC_WORDS(result,n,tiny_fl) \ 112 { \ 113 size_t grans = WORDS_TO_WHOLE_GRANULES(n); \ 114 GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \ 115 PTRFREE, GC_malloc_atomic(grans*GRANULE_BYTES), \ 116 /* no initialization */); \ 117 } 118 119 120 /* And once more for two word initialized objects: */ 121 # define GC_CONS(result, first, second, tiny_fl) \ 122 { \ 123 size_t grans = WORDS_TO_WHOLE_GRANULES(2); \ 124 GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \ 125 NORMAL, GC_malloc(grans*GRANULE_BYTES), \ 126 *(void **)result = (void *)(first)); \ 127 ((void **)(result))[1] = (void *)(second); \ 128 } 129