boehm-gc: revert all CACAO-specific modifications; this is now an exact copy of the...
[cacao.git] / src / mm / boehm-gc / gcj_mlc.c
1 /*
2  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
3  * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
4  *
5  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
6  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
7  *
8  * Permission is hereby granted to use or copy this program
9  * for any purpose,  provided the above notices are retained on all copies.
10  * Permission to modify the code and to distribute modified code is granted,
11  * provided the above notices are retained, and a notice that the code was
12  * modified is included with the above copyright notice.
13  *
14  */
15 /* Boehm, July 31, 1995 5:02 pm PDT */
16
17 #include "private/gc_pmark.h"  /* includes gc_priv.h */
18
19 #ifdef GC_GCJ_SUPPORT
20
21 /*
22  * This is an allocator interface tuned for gcj (the GNU static
23  * java compiler).
24  *
25  * Each allocated object has a pointer in its first word to a vtable,
26  * which for our purposes is simply a structure describing the type of
27  * the object.
28  * This descriptor structure contains a GC marking descriptor at offset
29  * MARK_DESCR_OFFSET.
30  *
31  * It is hoped that this interface may also be useful for other systems,
32  * possibly with some tuning of the constants.  But the immediate goal
33  * is to get better gcj performance.
34  *
35  * We assume:
36  *  1) Counting on explicit initialization of this interface is OK;
37  *  2) FASTLOCK is not a significant win.
38  */
39
40 #include "gc_gcj.h"
41 #include "private/dbg_mlc.h"
42
43 GC_bool GC_gcj_malloc_initialized = FALSE;
44
45 int GC_gcj_kind;        /* Object kind for objects with descriptors     */
46                         /* in "vtable".                                 */
47 int GC_gcj_debug_kind;  /* The kind of objects that is always marked    */
48                         /* with a mark proc call.                       */
49
50 ptr_t * GC_gcjobjfreelist;
51 ptr_t * GC_gcjdebugobjfreelist;
52
53 /* Caller does not hold allocation lock. */
54 GC_API void GC_CALL GC_init_gcj_malloc(int mp_index,
55                                 void * /* really GC_mark_proc */mp)
56 {
57     GC_bool ignore_gcj_info;
58     DCL_LOCK_STATE;
59
60     GC_init();  /* In case it's not already done.       */
61     LOCK();
62     if (GC_gcj_malloc_initialized) {
63       UNLOCK();
64       return;
65     }
66     GC_gcj_malloc_initialized = TRUE;
67     ignore_gcj_info = (0 != GETENV("GC_IGNORE_GCJ_INFO"));
68     if (GC_print_stats && ignore_gcj_info) {
69         GC_log_printf("Gcj-style type information is disabled!\n");
70     }
71     GC_ASSERT(GC_mark_procs[mp_index] == (GC_mark_proc)0); /* unused */
72     GC_mark_procs[mp_index] = (GC_mark_proc)(word)mp;
73     if ((unsigned)mp_index >= GC_n_mark_procs)
74         ABORT("GC_init_gcj_malloc: bad index");
75     /* Set up object kind gcj-style indirect descriptor. */
76       GC_gcjobjfreelist = (ptr_t *)GC_new_free_list_inner();
77       if (ignore_gcj_info) {
78         /* Use a simple length-based descriptor, thus forcing a fully   */
79         /* conservative scan.                                           */
80         GC_gcj_kind = GC_new_kind_inner((void **)GC_gcjobjfreelist,
81                                         (0 | GC_DS_LENGTH),
82                                         TRUE, TRUE);
83       } else {
84         GC_gcj_kind = GC_new_kind_inner(
85                         (void **)GC_gcjobjfreelist,
86                         (((word)(-(signed_word)MARK_DESCR_OFFSET
87                                  - GC_INDIR_PER_OBJ_BIAS))
88                          | GC_DS_PER_OBJECT),
89                         FALSE, TRUE);
90       }
91     /* Set up object kind for objects that require mark proc call.      */
92       if (ignore_gcj_info) {
93         GC_gcj_debug_kind = GC_gcj_kind;
94         GC_gcjdebugobjfreelist = GC_gcjobjfreelist;
95       } else {
96         GC_gcjdebugobjfreelist = (ptr_t *)GC_new_free_list_inner();
97         GC_gcj_debug_kind = GC_new_kind_inner(
98                                 (void **)GC_gcjdebugobjfreelist,
99                                 GC_MAKE_PROC(mp_index,
100                                              1 /* allocated with debug info */),
101                                 FALSE, TRUE);
102       }
103     UNLOCK();
104 }
105
106 void * GC_clear_stack(void *);
107
108 #define GENERAL_MALLOC(lb,k) \
109     GC_clear_stack(GC_generic_malloc_inner((word)lb, k))
110     
111 #define GENERAL_MALLOC_IOP(lb,k) \
112     GC_clear_stack(GC_generic_malloc_inner_ignore_off_page(lb, k))
113
114 /* We need a mechanism to release the lock and invoke finalizers.       */
115 /* We don't really have an opportunity to do this on a rarely executed  */
116 /* path on which the lock is not held.  Thus we check at a              */
117 /* rarely executed point at which it is safe to release the lock.       */
118 /* We do this even where we could just call GC_INVOKE_FINALIZERS,       */
119 /* since it's probably cheaper and certainly more uniform.              */
120 /* FIXME - Consider doing the same elsewhere?                           */
121 static void maybe_finalize(void)
122 {
123    static word last_finalized_no = 0;
124
125    if (GC_gc_no == last_finalized_no) return;
126    if (!GC_is_initialized) return;
127    UNLOCK();
128    GC_INVOKE_FINALIZERS();
129    last_finalized_no = GC_gc_no;
130    LOCK();
131 }
132
133 /* Allocate an object, clear it, and store the pointer to the   */
134 /* type structure (vtable in gcj).                              */
135 /* This adds a byte at the end of the object if GC_malloc would.*/
136 #ifdef THREAD_LOCAL_ALLOC
137   void * GC_core_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr)
138 #else
139   GC_API void * GC_CALL GC_gcj_malloc(size_t lb,
140                                 void * ptr_to_struct_containing_descr)
141 #endif
142 {
143     ptr_t op;
144     ptr_t * opp;
145     word lg;
146     DCL_LOCK_STATE;
147
148     if(SMALL_OBJ(lb)) {
149         lg = GC_size_map[lb];
150         opp = &(GC_gcjobjfreelist[lg]);
151         LOCK();
152         op = *opp;
153         if(EXPECT(op == 0, 0)) {
154             maybe_finalize();
155             op = (ptr_t)GENERAL_MALLOC((word)lb, GC_gcj_kind);
156             if (0 == op) {
157                 UNLOCK();
158                 return(GC_oom_fn(lb));
159             }
160         } else {
161             *opp = obj_link(op);
162             GC_bytes_allocd += GRANULES_TO_BYTES(lg);
163         }
164         *(void **)op = ptr_to_struct_containing_descr;
165         GC_ASSERT(((void **)op)[1] == 0);
166         UNLOCK();
167     } else {
168         LOCK();
169         maybe_finalize();
170         op = (ptr_t)GENERAL_MALLOC((word)lb, GC_gcj_kind);
171         if (0 == op) {
172             UNLOCK();
173             return(GC_oom_fn(lb));
174         }
175         *(void **)op = ptr_to_struct_containing_descr;
176         UNLOCK();
177     }
178     return((void *) op);
179 }
180
181 void GC_start_debugging(void);
182
183 /* Similar to GC_gcj_malloc, but add debug info.  This is allocated     */
184 /* with GC_gcj_debug_kind.                                              */
185 GC_API void * GC_CALL GC_debug_gcj_malloc(size_t lb,
186                 void * ptr_to_struct_containing_descr, GC_EXTRA_PARAMS)
187 {
188     void * result;
189
190     /* We're careful to avoid extra calls, which could           */
191     /* confuse the backtrace.                                   */
192     LOCK();
193     maybe_finalize();
194     result = GC_generic_malloc_inner(lb + DEBUG_BYTES, GC_gcj_debug_kind);
195     if (result == 0) {
196         UNLOCK();
197         GC_err_printf("GC_debug_gcj_malloc(%ld, %p) returning NIL (",
198                       (unsigned long)lb, ptr_to_struct_containing_descr);
199         GC_err_puts(s);
200         GC_err_printf(":%d)\n", i);
201         return(GC_oom_fn(lb));
202     }
203     *((void **)((ptr_t)result + sizeof(oh))) = ptr_to_struct_containing_descr;
204     UNLOCK();
205     if (!GC_debugging_started) {
206         GC_start_debugging();
207     }
208     ADD_CALL_CHAIN(result, ra);
209     return (GC_store_debug_info(result, (word)lb, s, (word)i));
210 }
211
212 /* There is no THREAD_LOCAL_ALLOC for GC_gcj_malloc_ignore_off_page().  */
213 GC_API void * GC_CALL GC_gcj_malloc_ignore_off_page(size_t lb,
214                                      void * ptr_to_struct_containing_descr) 
215 {
216     ptr_t op;
217     ptr_t * opp;
218     word lg;
219     DCL_LOCK_STATE;
220
221     if(SMALL_OBJ(lb)) {
222         lg = GC_size_map[lb];
223         opp = &(GC_gcjobjfreelist[lg]);
224         LOCK();
225         if( (op = *opp) == 0 ) {
226             maybe_finalize();
227             op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_gcj_kind);
228             if (0 == op) {
229                 UNLOCK();
230                 return(GC_oom_fn(lb));
231             }
232         } else {
233             *opp = obj_link(op);
234             GC_bytes_allocd += GRANULES_TO_BYTES(lg);
235         }
236     } else {
237         LOCK();
238         maybe_finalize();
239         op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_gcj_kind);
240         if (0 == op) {
241             UNLOCK();
242             return(GC_oom_fn(lb));
243         }
244     }
245     *(void **)op = ptr_to_struct_containing_descr;
246     UNLOCK();
247     return((void *) op);
248 }
249
250 #else
251
252 extern int GC_quiet;
253         /* ANSI C doesn't allow translation units to be empty.  */
254
255 #endif  /* GC_GCJ_SUPPORT */