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