]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | } |