Fix mysterious unremovable file part 2 ?
[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 by Hewlett-Packard Company.  All rights reserved.
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 "config.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) We have an ANSI conforming C compiler.
37  *  2) Counting on explicit initialization of this interface is OK.
38  *  3) FASTLOCK is not a significant win.
39  */
40
41 #include "private/gc_pmark.h"
42 #include "gc_gcj.h"
43 #include "private/dbg_mlc.h"
44
45 GC_bool GC_gcj_malloc_initialized = FALSE;
46
47 int GC_gcj_kind;        /* Object kind for objects with descriptors     */
48                         /* in "vtable".                                 */
49 int GC_gcj_debug_kind;  /* The kind of objects that is always marked    */
50                         /* with a mark proc call.                       */
51
52 ptr_t * GC_gcjobjfreelist;
53 ptr_t * GC_gcjdebugobjfreelist;
54
55 /* Caller does not hold allocation lock. */
56 void GC_init_gcj_malloc(int mp_index, void * /* really GC_mark_proc */mp)
57 {
58     register int i;
59     GC_bool ignore_gcj_info;
60     DCL_LOCK_STATE;
61
62     GC_init();  /* In case it's not already done.       */
63     DISABLE_SIGNALS();
64     LOCK();
65     if (GC_gcj_malloc_initialized) {
66       UNLOCK();
67       ENABLE_SIGNALS();
68       return;
69     }
70     GC_gcj_malloc_initialized = TRUE;
71     ignore_gcj_info = (0 != GETENV("GC_IGNORE_GCJ_INFO"));
72 #   ifdef CONDPRINT
73       if (GC_print_stats && ignore_gcj_info) {
74         GC_printf0("Gcj-style type information is disabled!\n");
75       }
76 #   endif
77     GC_ASSERT(GC_mark_procs[mp_index] == (GC_mark_proc)0); /* unused */
78     GC_mark_procs[mp_index] = (GC_mark_proc)mp;
79     if (mp_index >= GC_n_mark_procs) ABORT("GC_init_gcj_malloc: bad index");
80     /* Set up object kind gcj-style indirect descriptor. */
81       GC_gcjobjfreelist = (ptr_t *)GC_new_free_list_inner();
82       if (ignore_gcj_info) {
83         /* Use a simple length-based descriptor, thus forcing a fully   */
84         /* conservative scan.                                           */
85         GC_gcj_kind = GC_new_kind_inner((void **)GC_gcjobjfreelist,
86                                         (0 | GC_DS_LENGTH),
87                                         TRUE, TRUE);
88       } else {
89         GC_gcj_kind = GC_new_kind_inner(
90                         (void **)GC_gcjobjfreelist,
91                         (((word)(-MARK_DESCR_OFFSET - GC_INDIR_PER_OBJ_BIAS))
92                          | GC_DS_PER_OBJECT),
93                         FALSE, TRUE);
94       }
95     /* Set up object kind for objects that require mark proc call.      */
96       if (ignore_gcj_info) {
97         GC_gcj_debug_kind = GC_gcj_kind;
98         GC_gcjdebugobjfreelist = GC_gcjobjfreelist;
99       } else {
100         GC_gcjdebugobjfreelist = (ptr_t *)GC_new_free_list_inner();
101         GC_gcj_debug_kind = GC_new_kind_inner(
102                                 (void **)GC_gcjdebugobjfreelist,
103                                 GC_MAKE_PROC(mp_index,
104                                              1 /* allocated with debug info */),
105                                 FALSE, TRUE);
106       }
107     UNLOCK();
108     ENABLE_SIGNALS();
109 }
110
111 ptr_t GC_clear_stack();
112
113 #define GENERAL_MALLOC(lb,k) \
114     (GC_PTR)GC_clear_stack(GC_generic_malloc_inner((word)lb, k))
115     
116 #define GENERAL_MALLOC_IOP(lb,k) \
117     (GC_PTR)GC_clear_stack(GC_generic_malloc_inner_ignore_off_page(lb, k))
118
119 /* We need a mechanism to release the lock and invoke finalizers.       */
120 /* We don't really have an opportunity to do this on a rarely executed  */
121 /* path on which the lock is not held.  Thus we check at a              */
122 /* rarely executed point at which it is safe to release the lock.       */
123 /* We do this even where we could just call GC_INVOKE_FINALIZERS,       */
124 /* since it's probably cheaper and certainly more uniform.              */
125 /* FIXME - Consider doing the same elsewhere?                           */
126 static void maybe_finalize()
127 {
128    static int last_finalized_no = 0;
129
130    if (GC_gc_no == last_finalized_no) return;
131    if (!GC_is_initialized) return;
132    UNLOCK();
133    GC_INVOKE_FINALIZERS();
134    last_finalized_no = GC_gc_no;
135    LOCK();
136 }
137
138 /* Allocate an object, clear it, and store the pointer to the   */
139 /* type structure (vtable in gcj).                              */
140 /* This adds a byte at the end of the object if GC_malloc would.*/
141 void * GC_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr)
142 {
143 register ptr_t op;
144 register ptr_t * opp;
145 register word lw;
146 DCL_LOCK_STATE;
147
148     if( EXPECT(SMALL_OBJ(lb), 1) ) {
149 #       ifdef MERGE_SIZES
150           lw = GC_size_map[lb];
151 #       else
152           lw = ALIGNED_WORDS(lb);
153 #       endif
154         opp = &(GC_gcjobjfreelist[lw]);
155         LOCK();
156         op = *opp;
157         if(EXPECT(op == 0, 0)) {
158             maybe_finalize();
159             op = (ptr_t)GENERAL_MALLOC((word)lb, GC_gcj_kind);
160             if (0 == op) {
161                 UNLOCK();
162                 return(GC_oom_fn(lb));
163             }
164 #           ifdef MERGE_SIZES
165                 lw = GC_size_map[lb];   /* May have been uninitialized. */
166 #           endif
167         } else {
168             *opp = obj_link(op);
169             GC_words_allocd += lw;
170         }
171         *(void **)op = ptr_to_struct_containing_descr;
172         GC_ASSERT(((void **)op)[1] == 0);
173         UNLOCK();
174     } else {
175         LOCK();
176         maybe_finalize();
177         op = (ptr_t)GENERAL_MALLOC((word)lb, GC_gcj_kind);
178         if (0 == op) {
179             UNLOCK();
180             return(GC_oom_fn(lb));
181         }
182         *(void **)op = ptr_to_struct_containing_descr;
183         UNLOCK();
184     }
185     return((GC_PTR) op);
186 }
187
188 /* Similar to GC_gcj_malloc, but add debug info.  This is allocated     */
189 /* with GC_gcj_debug_kind.                                              */
190 GC_PTR GC_debug_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr,
191                            GC_EXTRA_PARAMS)
192 {
193     GC_PTR result;
194
195     /* We're careful to avoid extra calls, which could           */
196     /* confuse the backtrace.                                   */
197     LOCK();
198     maybe_finalize();
199     result = GC_generic_malloc_inner(lb + DEBUG_BYTES, GC_gcj_debug_kind);
200     if (result == 0) {
201         UNLOCK();
202         GC_err_printf2("GC_debug_gcj_malloc(%ld, 0x%lx) returning NIL (",
203                        (unsigned long) lb,
204                        (unsigned long) ptr_to_struct_containing_descr);
205         GC_err_puts(s);
206         GC_err_printf1(":%ld)\n", (unsigned long)i);
207         return(GC_oom_fn(lb));
208     }
209     *((void **)((ptr_t)result + sizeof(oh))) = ptr_to_struct_containing_descr;
210     UNLOCK();
211     if (!GC_debugging_started) {
212         GC_start_debugging();
213     }
214     ADD_CALL_CHAIN(result, ra);
215     return (GC_store_debug_info(result, (word)lb, s, (word)i));
216 }
217
218 /* Similar to GC_gcj_malloc, but the size is in words, and we don't     */
219 /* adjust it.  The size is assumed to be such that it can be    */
220 /* allocated as a small object.                                 */
221 void * GC_gcj_fast_malloc(size_t lw, void * ptr_to_struct_containing_descr)
222 {
223 ptr_t op;
224 ptr_t * opp;
225 DCL_LOCK_STATE;
226
227     opp = &(GC_gcjobjfreelist[lw]);
228     LOCK();
229     op = *opp;
230     if( EXPECT(op == 0, 0) ) {
231         maybe_finalize();
232         op = (ptr_t)GC_clear_stack(
233                 GC_generic_malloc_words_small_inner(lw, GC_gcj_kind));
234         if (0 == op) {
235             UNLOCK();
236             return GC_oom_fn(WORDS_TO_BYTES(lw));
237         }
238     } else {
239         *opp = obj_link(op);
240         GC_words_allocd += lw;
241     }
242     *(void **)op = ptr_to_struct_containing_descr;
243     UNLOCK();
244     return((GC_PTR) op);
245 }
246
247 /* And a debugging version of the above:        */
248 void * GC_debug_gcj_fast_malloc(size_t lw,
249                                 void * ptr_to_struct_containing_descr,
250                                 GC_EXTRA_PARAMS)
251 {
252     GC_PTR result;
253     size_t lb = WORDS_TO_BYTES(lw);
254
255     /* We clone the code from GC_debug_gcj_malloc, so that we   */
256     /* dont end up with extra frames on the stack, which could  */
257     /* confuse the backtrace.                                   */
258     LOCK();
259     maybe_finalize();
260     result = GC_generic_malloc_inner(lb + DEBUG_BYTES, GC_gcj_debug_kind);
261     if (result == 0) {
262         UNLOCK();
263         GC_err_printf2("GC_debug_gcj_fast_malloc(%ld, 0x%lx) returning NIL (",
264                        (unsigned long) lw,
265                        (unsigned long) ptr_to_struct_containing_descr);
266         GC_err_puts(s);
267         GC_err_printf1(":%ld)\n", (unsigned long)i);
268         return GC_oom_fn(WORDS_TO_BYTES(lw));
269     }
270     *((void **)((ptr_t)result + sizeof(oh))) = ptr_to_struct_containing_descr;
271     UNLOCK();
272     if (!GC_debugging_started) {
273         GC_start_debugging();
274     }
275     ADD_CALL_CHAIN(result, ra);
276     return (GC_store_debug_info(result, (word)lb, s, (word)i));
277 }
278
279 void * GC_gcj_malloc_ignore_off_page(size_t lb,
280                                      void * ptr_to_struct_containing_descr) 
281 {
282 register ptr_t op;
283 register ptr_t * opp;
284 register word lw;
285 DCL_LOCK_STATE;
286
287     if( SMALL_OBJ(lb) ) {
288 #       ifdef MERGE_SIZES
289           lw = GC_size_map[lb];
290 #       else
291           lw = ALIGNED_WORDS(lb);
292 #       endif
293         opp = &(GC_gcjobjfreelist[lw]);
294         LOCK();
295         if( (op = *opp) == 0 ) {
296             maybe_finalize();
297             op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_gcj_kind);
298 #           ifdef MERGE_SIZES
299                 lw = GC_size_map[lb];   /* May have been uninitialized. */
300 #           endif
301         } else {
302             *opp = obj_link(op);
303             GC_words_allocd += lw;
304         }
305         *(void **)op = ptr_to_struct_containing_descr;
306         UNLOCK();
307     } else {
308         LOCK();
309         maybe_finalize();
310         op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_gcj_kind);
311         if (0 != op) {
312           *(void **)op = ptr_to_struct_containing_descr;
313         }
314         UNLOCK();
315     }
316     return((GC_PTR) op);
317 }
318
319 #else
320
321 char GC_no_gcj_support;
322
323 #endif  /* GC_GCJ_SUPPORT */