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