boehm-gc: revert all CACAO-specific modifications; this is now an exact copy of the...
[cacao.git] / src / mm / boehm-gc / include / gc_inline.h
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 /* WARNING:                                                             */
17 /* Note that for these routines, it is the clients responsibility to    */
18 /* add the extra byte at the end to deal with one-past-the-end pointers.*/
19 /* In the standard collector configuration, the collector assumes that  */
20 /* such a byte has been added, and hence does not trace the last word   */
21 /* in the resulting object.                                             */
22 /* This is not an issue if the collector is compiled with               */
23 /* -DDONT_ADD_BYTE_AT_END, or if GC_all_interior_pointers is not set.   */
24 /* This interface is most useful for compilers that generate C.         */
25 /* It is also used internally for thread-local allocation.              */
26 /* Manual use is hereby discouraged.                                    */
27
28 #include "gc.h"
29 #include "gc_tiny_fl.h"
30
31 #if __GNUC__ >= 3
32 # define GC_EXPECT(expr, outcome) __builtin_expect(expr,outcome)
33   /* Equivalent to (expr), but predict that usually (expr)==outcome. */
34 #else
35 # define GC_EXPECT(expr, outcome) (expr)
36 #endif /* __GNUC__ */
37
38 /* The ultimately general inline allocation macro.  Allocate an object  */
39 /* of size granules, putting the resulting pointer in result.  Tiny_fl  */
40 /* is a "tiny" free list array, which will be used first, if the size   */
41 /* is appropriate.  If granules is too large, we allocate with          */
42 /* default_expr instead.  If we need to refill the free list, we use    */
43 /* GC_generic_malloc_many with the indicated kind.                      */
44 /* Tiny_fl should be an array of GC_TINY_FREELISTS void * pointers.     */
45 /* If num_direct is nonzero, and the individual free list pointers      */
46 /* are initialized to (void *)1, then we allocate numdirect granules    */
47 /* directly using gmalloc before putting multiple objects into the      */
48 /* tiny_fl entry.  If num_direct is zero, then the free lists may also  */
49 /* be initialized to (void *)0.                                         */
50 /* Note that we use the zeroth free list to hold objects 1 granule in   */
51 /* size that are used to satisfy size 0 allocation requests.            */
52 /* We rely on much of this hopefully getting optimized away in the      */
53 /* num_direct = 0 case.                                                 */
54 /* Particularly if granules is constant, this should generate a small   */
55 /* amount of code.                                                      */
56 # define GC_FAST_MALLOC_GRANS(result,granules,tiny_fl,num_direct,\
57                               kind,default_expr,init) \
58 { \
59     if (GC_EXPECT((granules) >= GC_TINY_FREELISTS,0)) { \
60         result = (default_expr); \
61     } else { \
62         void **my_fl = (tiny_fl) + (granules); \
63         void *my_entry=*my_fl; \
64         void *next; \
65  \
66         while (GC_EXPECT((GC_word)my_entry \
67                         <= (num_direct) + GC_TINY_FREELISTS + 1, 0)) { \
68             /* Entry contains counter or NULL */ \
69             if ((GC_word)my_entry - 1 < (num_direct)) { \
70                 /* Small counter value, not NULL */ \
71                 *my_fl = (char *)my_entry + (granules) + 1; \
72                 result = (default_expr); \
73                 goto out; \
74             } else { \
75                 /* Large counter or NULL */ \
76                 GC_generic_malloc_many(((granules) == 0? GC_GRANULE_BYTES : \
77                                           GC_RAW_BYTES_FROM_INDEX(granules)), \
78                                        kind, my_fl); \
79                 my_entry = *my_fl; \
80                 if (my_entry == 0) { \
81                     result = GC_oom_fn((granules)*GC_GRANULE_BYTES); \
82                     goto out; \
83                 } \
84             } \
85         } \
86         next = *(void **)(my_entry); \
87         result = (void *)my_entry; \
88         *my_fl = next; \
89         init; \
90         PREFETCH_FOR_WRITE(next); \
91         GC_ASSERT(GC_size(result) >= (granules)*GC_GRANULE_BYTES); \
92         GC_ASSERT((kind) == PTRFREE || ((GC_word *)result)[1] == 0); \
93       out: ; \
94    } \
95 }
96
97 # define GC_WORDS_TO_WHOLE_GRANULES(n) \
98         GC_WORDS_TO_GRANULES((n) + GC_GRANULE_WORDS - 1)
99
100 /* Allocate n words (NOT BYTES).  X is made to point to the result.     */
101 /* This should really only be used if GC_all_interior_pointers is       */
102 /* not set, or DONT_ADD_BYTE_AT_END is set.  See above.                 */
103 /* The semantics changed in version 7.0; we no longer lock, and         */
104 /* the caller is responsible for supplying a cleared tiny_fl            */
105 /* free list array.  For single-threaded applications, this may be      */
106 /* a global array.                                                      */
107 # define GC_MALLOC_WORDS(result,n,tiny_fl) \
108 {       \
109     size_t grans = GC_WORDS_TO_WHOLE_GRANULES(n); \
110     GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
111                          NORMAL, GC_malloc(grans*GC_GRANULE_BYTES), \
112                          *(void **)result = 0); \
113 }
114
115 # define GC_MALLOC_ATOMIC_WORDS(result,n,tiny_fl) \
116 {       \
117     size_t grans = GC_WORDS_TO_WHOLE_GRANULES(n); \
118     GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
119                          PTRFREE, GC_malloc_atomic(grans*GC_GRANULE_BYTES), \
120                          (void)0 /* no initialization */); \
121 }
122
123
124 /* And once more for two word initialized objects: */
125 # define GC_CONS(result, first, second, tiny_fl) \
126 {       \
127     size_t grans = GC_WORDS_TO_WHOLE_GRANULES(2); \
128     GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
129                          NORMAL, GC_malloc(grans*GC_GRANULE_BYTES), \
130                          *(void **)result = (void *)(first)); \
131     ((void **)(result))[1] = (void *)(second);  \
132 }