Line data Source code
1 : /*
2 : * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
3 : * Copyright (c) 1999-2000 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 :
16 : #include "private/gc_pmark.h"
17 :
18 : /*
19 : * Some simple primitives for allocation with explicit type information.
20 : * Simple objects are allocated such that they contain a GC_descr at the
21 : * end (in the last allocated word). This descriptor may be a procedure
22 : * which then examines an extended descriptor passed as its environment.
23 : *
24 : * Arrays are treated as simple objects if they have sufficiently simple
25 : * structure. Otherwise they are allocated from an array kind that supplies
26 : * a special mark procedure. These arrays contain a pointer to a
27 : * complex_descriptor as their last word.
28 : * This is done because the environment field is too small, and the collector
29 : * must trace the complex_descriptor.
30 : *
31 : * Note that descriptors inside objects may appear cleared, if we encounter a
32 : * false reference to an object on a free list. In the GC_descr case, this
33 : * is OK, since a 0 descriptor corresponds to examining no fields.
34 : * In the complex_descriptor case, we explicitly check for that case.
35 : *
36 : * MAJOR PARTS OF THIS CODE HAVE NOT BEEN TESTED AT ALL and are not testable,
37 : * since they are not accessible through the current interface.
38 : */
39 :
40 : #include "gc_typed.h"
41 :
42 : #define TYPD_EXTRA_BYTES (sizeof(word) - EXTRA_BYTES)
43 :
44 : STATIC GC_bool GC_explicit_typing_initialized = FALSE;
45 :
46 : STATIC int GC_explicit_kind = 0;
47 : /* Object kind for objects with indirect */
48 : /* (possibly extended) descriptors. */
49 :
50 : STATIC int GC_array_kind = 0;
51 : /* Object kind for objects with complex */
52 : /* descriptors and GC_array_mark_proc. */
53 :
54 : /* Extended descriptors. GC_typed_mark_proc understands these. */
55 : /* These are used for simple objects that are larger than what */
56 : /* can be described by a BITMAP_BITS sized bitmap. */
57 : typedef struct {
58 : word ed_bitmap; /* lsb corresponds to first word. */
59 : GC_bool ed_continued; /* next entry is continuation. */
60 : } ext_descr;
61 :
62 : /* Array descriptors. GC_array_mark_proc understands these. */
63 : /* We may eventually need to add provisions for headers and */
64 : /* trailers. Hence we provide for tree structured descriptors, */
65 : /* though we don't really use them currently. */
66 : typedef union ComplexDescriptor {
67 : struct LeafDescriptor { /* Describes simple array */
68 : word ld_tag;
69 : # define LEAF_TAG 1
70 : size_t ld_size; /* bytes per element */
71 : /* multiple of ALIGNMENT */
72 : size_t ld_nelements; /* Number of elements. */
73 : GC_descr ld_descriptor; /* A simple length, bitmap, */
74 : /* or procedure descriptor. */
75 : } ld;
76 : struct ComplexArrayDescriptor {
77 : word ad_tag;
78 : # define ARRAY_TAG 2
79 : size_t ad_nelements;
80 : union ComplexDescriptor * ad_element_descr;
81 : } ad;
82 : struct SequenceDescriptor {
83 : word sd_tag;
84 : # define SEQUENCE_TAG 3
85 : union ComplexDescriptor * sd_first;
86 : union ComplexDescriptor * sd_second;
87 : } sd;
88 : } complex_descriptor;
89 : #define TAG ld.ld_tag
90 :
91 : STATIC ext_descr * GC_ext_descriptors = NULL;
92 : /* Points to array of extended */
93 : /* descriptors. */
94 :
95 : STATIC size_t GC_ed_size = 0; /* Current size of above arrays. */
96 : #define ED_INITIAL_SIZE 100
97 :
98 : STATIC size_t GC_avail_descr = 0; /* Next available slot. */
99 :
100 : STATIC int GC_typed_mark_proc_index = 0; /* Indices of my mark */
101 : STATIC int GC_array_mark_proc_index = 0; /* procedures. */
102 :
103 0 : STATIC void GC_push_typed_structures_proc(void)
104 : {
105 0 : GC_push_all((ptr_t)&GC_ext_descriptors,
106 : (ptr_t)&GC_ext_descriptors + sizeof(word));
107 0 : }
108 :
109 : /* Add a multiword bitmap to GC_ext_descriptors arrays. Return */
110 : /* starting index. */
111 : /* Returns -1 on failure. */
112 : /* Caller does not hold allocation lock. */
113 0 : STATIC signed_word GC_add_ext_descriptor(const GC_word * bm, word nbits)
114 : {
115 0 : size_t nwords = divWORDSZ(nbits + WORDSZ-1);
116 : signed_word result;
117 : size_t i;
118 : word last_part;
119 : size_t extra_bits;
120 : DCL_LOCK_STATE;
121 :
122 0 : LOCK();
123 0 : while (GC_avail_descr + nwords >= GC_ed_size) {
124 : ext_descr * new;
125 : size_t new_size;
126 0 : word ed_size = GC_ed_size;
127 :
128 0 : if (ed_size == 0) {
129 : GC_ASSERT((word)&GC_ext_descriptors % sizeof(word) == 0);
130 0 : GC_push_typed_structures = GC_push_typed_structures_proc;
131 0 : UNLOCK();
132 0 : new_size = ED_INITIAL_SIZE;
133 : } else {
134 0 : UNLOCK();
135 0 : new_size = 2 * ed_size;
136 0 : if (new_size > MAX_ENV) return(-1);
137 : }
138 0 : new = (ext_descr *) GC_malloc_atomic(new_size * sizeof(ext_descr));
139 0 : if (new == 0) return(-1);
140 0 : LOCK();
141 0 : if (ed_size == GC_ed_size) {
142 0 : if (GC_avail_descr != 0) {
143 0 : BCOPY(GC_ext_descriptors, new,
144 : GC_avail_descr * sizeof(ext_descr));
145 : }
146 0 : GC_ed_size = new_size;
147 0 : GC_ext_descriptors = new;
148 : } /* else another thread already resized it in the meantime */
149 : }
150 0 : result = GC_avail_descr;
151 0 : for (i = 0; i < nwords-1; i++) {
152 0 : GC_ext_descriptors[result + i].ed_bitmap = bm[i];
153 0 : GC_ext_descriptors[result + i].ed_continued = TRUE;
154 : }
155 0 : last_part = bm[i];
156 : /* Clear irrelevant bits. */
157 0 : extra_bits = nwords * WORDSZ - nbits;
158 0 : last_part <<= extra_bits;
159 0 : last_part >>= extra_bits;
160 0 : GC_ext_descriptors[result + i].ed_bitmap = last_part;
161 0 : GC_ext_descriptors[result + i].ed_continued = FALSE;
162 0 : GC_avail_descr += nwords;
163 0 : UNLOCK();
164 0 : return(result);
165 : }
166 :
167 : /* Table of bitmap descriptors for n word long all pointer objects. */
168 : STATIC GC_descr GC_bm_table[WORDSZ/2];
169 :
170 : /* Return a descriptor for the concatenation of 2 nwords long objects, */
171 : /* each of which is described by descriptor. */
172 : /* The result is known to be short enough to fit into a bitmap */
173 : /* descriptor. */
174 : /* Descriptor is a GC_DS_LENGTH or GC_DS_BITMAP descriptor. */
175 0 : STATIC GC_descr GC_double_descr(GC_descr descriptor, word nwords)
176 : {
177 0 : if ((descriptor & GC_DS_TAGS) == GC_DS_LENGTH) {
178 0 : descriptor = GC_bm_table[BYTES_TO_WORDS((word)descriptor)];
179 : };
180 0 : descriptor |= (descriptor & ~GC_DS_TAGS) >> nwords;
181 0 : return(descriptor);
182 : }
183 :
184 : STATIC complex_descriptor *
185 : GC_make_sequence_descriptor(complex_descriptor *first,
186 : complex_descriptor *second);
187 :
188 : /* Build a descriptor for an array with nelements elements, */
189 : /* each of which can be described by a simple descriptor. */
190 : /* We try to optimize some common cases. */
191 : /* If the result is COMPLEX, then a complex_descr* is returned */
192 : /* in *complex_d. */
193 : /* If the result is LEAF, then we built a LeafDescriptor in */
194 : /* the structure pointed to by leaf. */
195 : /* The tag in the leaf structure is not set. */
196 : /* If the result is SIMPLE, then a GC_descr */
197 : /* is returned in *simple_d. */
198 : /* If the result is NO_MEM, then */
199 : /* we failed to allocate the descriptor. */
200 : /* The implementation knows that GC_DS_LENGTH is 0. */
201 : /* *leaf, *complex_d, and *simple_d may be used as temporaries */
202 : /* during the construction. */
203 : #define COMPLEX 2
204 : #define LEAF 1
205 : #define SIMPLE 0
206 : #define NO_MEM (-1)
207 0 : STATIC int GC_make_array_descriptor(size_t nelements, size_t size,
208 : GC_descr descriptor, GC_descr *simple_d,
209 : complex_descriptor **complex_d,
210 : struct LeafDescriptor * leaf)
211 : {
212 : # define OPT_THRESHOLD 50
213 : /* For larger arrays, we try to combine descriptors of adjacent */
214 : /* descriptors to speed up marking, and to reduce the amount */
215 : /* of space needed on the mark stack. */
216 0 : if ((descriptor & GC_DS_TAGS) == GC_DS_LENGTH) {
217 0 : if (descriptor == (GC_descr)size) {
218 0 : *simple_d = nelements * descriptor;
219 0 : return(SIMPLE);
220 0 : } else if ((word)descriptor == 0) {
221 0 : *simple_d = (GC_descr)0;
222 0 : return(SIMPLE);
223 : }
224 : }
225 0 : if (nelements <= OPT_THRESHOLD) {
226 0 : if (nelements <= 1) {
227 0 : if (nelements == 1) {
228 0 : *simple_d = descriptor;
229 0 : return(SIMPLE);
230 : } else {
231 0 : *simple_d = (GC_descr)0;
232 0 : return(SIMPLE);
233 : }
234 : }
235 0 : } else if (size <= BITMAP_BITS/2
236 0 : && (descriptor & GC_DS_TAGS) != GC_DS_PROC
237 0 : && (size & (sizeof(word)-1)) == 0) {
238 : int result =
239 0 : GC_make_array_descriptor(nelements/2, 2*size,
240 : GC_double_descr(descriptor,
241 : BYTES_TO_WORDS(size)),
242 0 : simple_d, complex_d, leaf);
243 0 : if ((nelements & 1) == 0) {
244 0 : return(result);
245 : } else {
246 : struct LeafDescriptor * one_element =
247 0 : (struct LeafDescriptor *)
248 0 : GC_malloc_atomic(sizeof(struct LeafDescriptor));
249 :
250 0 : if (result == NO_MEM || one_element == 0) return(NO_MEM);
251 0 : one_element -> ld_tag = LEAF_TAG;
252 0 : one_element -> ld_size = size;
253 0 : one_element -> ld_nelements = 1;
254 0 : one_element -> ld_descriptor = descriptor;
255 0 : switch(result) {
256 : case SIMPLE:
257 : {
258 : struct LeafDescriptor * beginning =
259 0 : (struct LeafDescriptor *)
260 0 : GC_malloc_atomic(sizeof(struct LeafDescriptor));
261 0 : if (beginning == 0) return(NO_MEM);
262 0 : beginning -> ld_tag = LEAF_TAG;
263 0 : beginning -> ld_size = size;
264 0 : beginning -> ld_nelements = 1;
265 0 : beginning -> ld_descriptor = *simple_d;
266 0 : *complex_d = GC_make_sequence_descriptor(
267 : (complex_descriptor *)beginning,
268 : (complex_descriptor *)one_element);
269 0 : break;
270 : }
271 : case LEAF:
272 : {
273 : struct LeafDescriptor * beginning =
274 0 : (struct LeafDescriptor *)
275 0 : GC_malloc_atomic(sizeof(struct LeafDescriptor));
276 0 : if (beginning == 0) return(NO_MEM);
277 0 : beginning -> ld_tag = LEAF_TAG;
278 0 : beginning -> ld_size = leaf -> ld_size;
279 0 : beginning -> ld_nelements = leaf -> ld_nelements;
280 0 : beginning -> ld_descriptor = leaf -> ld_descriptor;
281 0 : *complex_d = GC_make_sequence_descriptor(
282 : (complex_descriptor *)beginning,
283 : (complex_descriptor *)one_element);
284 0 : break;
285 : }
286 : case COMPLEX:
287 0 : *complex_d = GC_make_sequence_descriptor(
288 : *complex_d,
289 : (complex_descriptor *)one_element);
290 : break;
291 : }
292 0 : return(COMPLEX);
293 : }
294 : }
295 :
296 0 : leaf -> ld_size = size;
297 0 : leaf -> ld_nelements = nelements;
298 0 : leaf -> ld_descriptor = descriptor;
299 0 : return(LEAF);
300 : }
301 :
302 : STATIC complex_descriptor *
303 0 : GC_make_sequence_descriptor(complex_descriptor *first,
304 : complex_descriptor *second)
305 : {
306 : struct SequenceDescriptor * result =
307 0 : (struct SequenceDescriptor *)
308 0 : GC_malloc(sizeof(struct SequenceDescriptor));
309 : /* Can't result in overly conservative marking, since tags are */
310 : /* very small integers. Probably faster than maintaining type */
311 : /* info. */
312 0 : if (result != 0) {
313 0 : result -> sd_tag = SEQUENCE_TAG;
314 0 : result -> sd_first = first;
315 0 : result -> sd_second = second;
316 : }
317 0 : return((complex_descriptor *)result);
318 : }
319 :
320 : #ifdef UNDEFINED
321 : complex_descriptor * GC_make_complex_array_descriptor(word nelements,
322 : complex_descriptor *descr)
323 : {
324 : struct ComplexArrayDescriptor * result =
325 : (struct ComplexArrayDescriptor *)
326 : GC_malloc(sizeof(struct ComplexArrayDescriptor));
327 :
328 : if (result != 0) {
329 : result -> ad_tag = ARRAY_TAG;
330 : result -> ad_nelements = nelements;
331 : result -> ad_element_descr = descr;
332 : }
333 : return((complex_descriptor *)result);
334 : }
335 : #endif
336 :
337 : STATIC ptr_t * GC_eobjfreelist = NULL;
338 :
339 : STATIC ptr_t * GC_arobjfreelist = NULL;
340 :
341 : STATIC mse * GC_typed_mark_proc(word * addr, mse * mark_stack_ptr,
342 : mse * mark_stack_limit, word env);
343 :
344 : STATIC mse * GC_array_mark_proc(word * addr, mse * mark_stack_ptr,
345 : mse * mark_stack_limit, word env);
346 :
347 : /* Caller does not hold allocation lock. */
348 0 : STATIC void GC_init_explicit_typing(void)
349 : {
350 : register unsigned i;
351 : DCL_LOCK_STATE;
352 :
353 : GC_STATIC_ASSERT(sizeof(struct LeafDescriptor) % sizeof(word) == 0);
354 0 : LOCK();
355 0 : if (GC_explicit_typing_initialized) {
356 0 : UNLOCK();
357 0 : return;
358 : }
359 0 : GC_explicit_typing_initialized = TRUE;
360 : /* Set up object kind with simple indirect descriptor. */
361 0 : GC_eobjfreelist = (ptr_t *)GC_new_free_list_inner();
362 0 : GC_explicit_kind = GC_new_kind_inner(
363 : (void **)GC_eobjfreelist,
364 : (WORDS_TO_BYTES((word)-1) | GC_DS_PER_OBJECT),
365 : TRUE, TRUE);
366 : /* Descriptors are in the last word of the object. */
367 0 : GC_typed_mark_proc_index = GC_new_proc_inner(GC_typed_mark_proc);
368 : /* Set up object kind with array descriptor. */
369 0 : GC_arobjfreelist = (ptr_t *)GC_new_free_list_inner();
370 0 : GC_array_mark_proc_index = GC_new_proc_inner(GC_array_mark_proc);
371 0 : GC_array_kind = GC_new_kind_inner(
372 : (void **)GC_arobjfreelist,
373 0 : GC_MAKE_PROC(GC_array_mark_proc_index, 0),
374 : FALSE, TRUE);
375 0 : for (i = 0; i < WORDSZ/2; i++) {
376 0 : GC_bm_table[i] = (((word)-1) << (WORDSZ - i)) | GC_DS_BITMAP;
377 : }
378 0 : UNLOCK();
379 : }
380 :
381 0 : STATIC mse * GC_typed_mark_proc(word * addr, mse * mark_stack_ptr,
382 : mse * mark_stack_limit, word env)
383 : {
384 0 : word bm = GC_ext_descriptors[env].ed_bitmap;
385 0 : word * current_p = addr;
386 : word current;
387 0 : ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
388 0 : ptr_t least_ha = GC_least_plausible_heap_addr;
389 : DECLARE_HDR_CACHE;
390 :
391 0 : INIT_HDR_CACHE;
392 0 : for (; bm != 0; bm >>= 1, current_p++) {
393 0 : if (bm & 1) {
394 0 : current = *current_p;
395 : FIXUP_POINTER(current);
396 0 : if (current >= (word)least_ha && current <= (word)greatest_ha) {
397 0 : PUSH_CONTENTS((ptr_t)current, mark_stack_ptr,
398 : mark_stack_limit, (ptr_t)current_p, exit1);
399 : }
400 : }
401 : }
402 0 : if (GC_ext_descriptors[env].ed_continued) {
403 : /* Push an entry with the rest of the descriptor back onto the */
404 : /* stack. Thus we never do too much work at once. Note that */
405 : /* we also can't overflow the mark stack unless we actually */
406 : /* mark something. */
407 0 : mark_stack_ptr++;
408 0 : if ((word)mark_stack_ptr >= (word)mark_stack_limit) {
409 0 : mark_stack_ptr = GC_signal_mark_stack_overflow(mark_stack_ptr);
410 : }
411 0 : mark_stack_ptr -> mse_start = (ptr_t)(addr + WORDSZ);
412 0 : mark_stack_ptr -> mse_descr.w =
413 0 : GC_MAKE_PROC(GC_typed_mark_proc_index, env + 1);
414 : }
415 0 : return(mark_stack_ptr);
416 : }
417 :
418 : /* Return the size of the object described by d. It would be faster to */
419 : /* store this directly, or to compute it as part of */
420 : /* GC_push_complex_descriptor, but hopefully it doesn't matter. */
421 0 : STATIC word GC_descr_obj_size(complex_descriptor *d)
422 : {
423 0 : switch(d -> TAG) {
424 : case LEAF_TAG:
425 0 : return(d -> ld.ld_nelements * d -> ld.ld_size);
426 : case ARRAY_TAG:
427 0 : return(d -> ad.ad_nelements
428 0 : * GC_descr_obj_size(d -> ad.ad_element_descr));
429 : case SEQUENCE_TAG:
430 0 : return(GC_descr_obj_size(d -> sd.sd_first)
431 0 : + GC_descr_obj_size(d -> sd.sd_second));
432 : default:
433 0 : ABORT_RET("Bad complex descriptor");
434 0 : return 0;
435 : }
436 : }
437 :
438 : /* Push descriptors for the object at addr with complex descriptor d */
439 : /* onto the mark stack. Return 0 if the mark stack overflowed. */
440 0 : STATIC mse * GC_push_complex_descriptor(word *addr, complex_descriptor *d,
441 : mse *msp, mse *msl)
442 : {
443 0 : register ptr_t current = (ptr_t) addr;
444 : register word nelements;
445 : register word sz;
446 : register word i;
447 :
448 0 : switch(d -> TAG) {
449 : case LEAF_TAG:
450 : {
451 0 : register GC_descr descr = d -> ld.ld_descriptor;
452 :
453 0 : nelements = d -> ld.ld_nelements;
454 0 : if (msl - msp <= (ptrdiff_t)nelements) return(0);
455 0 : sz = d -> ld.ld_size;
456 0 : for (i = 0; i < nelements; i++) {
457 0 : msp++;
458 0 : msp -> mse_start = current;
459 0 : msp -> mse_descr.w = descr;
460 0 : current += sz;
461 : }
462 0 : return(msp);
463 : }
464 : case ARRAY_TAG:
465 : {
466 0 : register complex_descriptor *descr = d -> ad.ad_element_descr;
467 :
468 0 : nelements = d -> ad.ad_nelements;
469 0 : sz = GC_descr_obj_size(descr);
470 0 : for (i = 0; i < nelements; i++) {
471 0 : msp = GC_push_complex_descriptor((word *)current, descr,
472 : msp, msl);
473 0 : if (msp == 0) return(0);
474 0 : current += sz;
475 : }
476 0 : return(msp);
477 : }
478 : case SEQUENCE_TAG:
479 : {
480 0 : sz = GC_descr_obj_size(d -> sd.sd_first);
481 0 : msp = GC_push_complex_descriptor((word *)current, d -> sd.sd_first,
482 : msp, msl);
483 0 : if (msp == 0) return(0);
484 0 : current += sz;
485 0 : msp = GC_push_complex_descriptor((word *)current, d -> sd.sd_second,
486 : msp, msl);
487 0 : return(msp);
488 : }
489 : default:
490 0 : ABORT_RET("Bad complex descriptor");
491 0 : return 0;
492 : }
493 : }
494 :
495 0 : STATIC mse * GC_array_mark_proc(word * addr, mse * mark_stack_ptr,
496 : mse * mark_stack_limit,
497 : word env GC_ATTR_UNUSED)
498 : {
499 0 : hdr * hhdr = HDR(addr);
500 0 : size_t sz = hhdr -> hb_sz;
501 0 : size_t nwords = BYTES_TO_WORDS(sz);
502 0 : complex_descriptor * descr = (complex_descriptor *)(addr[nwords-1]);
503 0 : mse * orig_mark_stack_ptr = mark_stack_ptr;
504 : mse * new_mark_stack_ptr;
505 :
506 0 : if (descr == 0) {
507 : /* Found a reference to a free list entry. Ignore it. */
508 0 : return(orig_mark_stack_ptr);
509 : }
510 : /* In use counts were already updated when array descriptor was */
511 : /* pushed. Here we only replace it by subobject descriptors, so */
512 : /* no update is necessary. */
513 0 : new_mark_stack_ptr = GC_push_complex_descriptor(addr, descr,
514 : mark_stack_ptr,
515 : mark_stack_limit-1);
516 0 : if (new_mark_stack_ptr == 0) {
517 : /* Doesn't fit. Conservatively push the whole array as a unit */
518 : /* and request a mark stack expansion. */
519 : /* This cannot cause a mark stack overflow, since it replaces */
520 : /* the original array entry. */
521 0 : GC_mark_stack_too_small = TRUE;
522 0 : new_mark_stack_ptr = orig_mark_stack_ptr + 1;
523 0 : new_mark_stack_ptr -> mse_start = (ptr_t)addr;
524 0 : new_mark_stack_ptr -> mse_descr.w = sz | GC_DS_LENGTH;
525 : } else {
526 : /* Push descriptor itself */
527 0 : new_mark_stack_ptr++;
528 0 : new_mark_stack_ptr -> mse_start = (ptr_t)(addr + nwords - 1);
529 0 : new_mark_stack_ptr -> mse_descr.w = sizeof(word) | GC_DS_LENGTH;
530 : }
531 0 : return new_mark_stack_ptr;
532 : }
533 :
534 0 : GC_API GC_descr GC_CALL GC_make_descriptor(const GC_word * bm, size_t len)
535 : {
536 0 : signed_word last_set_bit = len - 1;
537 : GC_descr result;
538 : signed_word i;
539 : # define HIGH_BIT (((word)1) << (WORDSZ - 1))
540 :
541 0 : if (!EXPECT(GC_explicit_typing_initialized, TRUE))
542 0 : GC_init_explicit_typing();
543 :
544 0 : while (last_set_bit >= 0 && !GC_get_bit(bm, last_set_bit))
545 0 : last_set_bit--;
546 0 : if (last_set_bit < 0) return(0 /* no pointers */);
547 : # if ALIGNMENT == CPP_WORDSZ/8
548 : {
549 0 : register GC_bool all_bits_set = TRUE;
550 0 : for (i = 0; i < last_set_bit; i++) {
551 0 : if (!GC_get_bit(bm, i)) {
552 0 : all_bits_set = FALSE;
553 0 : break;
554 : }
555 : }
556 0 : if (all_bits_set) {
557 : /* An initial section contains all pointers. Use length descriptor. */
558 0 : return (WORDS_TO_BYTES(last_set_bit+1) | GC_DS_LENGTH);
559 : }
560 : }
561 : # endif
562 0 : if ((word)last_set_bit < BITMAP_BITS) {
563 : /* Hopefully the common case. */
564 : /* Build bitmap descriptor (with bits reversed) */
565 0 : result = HIGH_BIT;
566 0 : for (i = last_set_bit - 1; i >= 0; i--) {
567 0 : result >>= 1;
568 0 : if (GC_get_bit(bm, i)) result |= HIGH_BIT;
569 : }
570 0 : result |= GC_DS_BITMAP;
571 0 : return(result);
572 : } else {
573 : signed_word index;
574 :
575 0 : index = GC_add_ext_descriptor(bm, (word)last_set_bit+1);
576 0 : if (index == -1) return(WORDS_TO_BYTES(last_set_bit+1) | GC_DS_LENGTH);
577 : /* Out of memory: use conservative */
578 : /* approximation. */
579 0 : result = GC_MAKE_PROC(GC_typed_mark_proc_index, (word)index);
580 0 : return result;
581 : }
582 : }
583 :
584 0 : GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_explicitly_typed(size_t lb,
585 : GC_descr d)
586 : {
587 : ptr_t op;
588 : ptr_t * opp;
589 : size_t lg;
590 : DCL_LOCK_STATE;
591 :
592 0 : lb += TYPD_EXTRA_BYTES;
593 0 : if(SMALL_OBJ(lb)) {
594 : GC_DBG_COLLECT_AT_MALLOC(lb);
595 0 : lg = GC_size_map[lb];
596 0 : opp = &(GC_eobjfreelist[lg]);
597 0 : LOCK();
598 0 : op = *opp;
599 0 : if (EXPECT(0 == op, FALSE)) {
600 0 : UNLOCK();
601 0 : op = (ptr_t)GENERAL_MALLOC((word)lb, GC_explicit_kind);
602 0 : if (0 == op) return 0;
603 0 : lg = GC_size_map[lb]; /* May have been uninitialized. */
604 : } else {
605 0 : *opp = obj_link(op);
606 0 : obj_link(op) = 0;
607 0 : GC_bytes_allocd += GRANULES_TO_BYTES(lg);
608 0 : UNLOCK();
609 : }
610 0 : ((word *)op)[GRANULES_TO_WORDS(lg) - 1] = d;
611 : } else {
612 0 : op = (ptr_t)GENERAL_MALLOC((word)lb, GC_explicit_kind);
613 0 : if (op != NULL) {
614 0 : lg = BYTES_TO_GRANULES(GC_size(op));
615 0 : ((word *)op)[GRANULES_TO_WORDS(lg) - 1] = d;
616 : }
617 : }
618 0 : return((void *) op);
619 : }
620 :
621 : GC_API GC_ATTR_MALLOC void * GC_CALL
622 0 : GC_malloc_explicitly_typed_ignore_off_page(size_t lb, GC_descr d)
623 : {
624 : ptr_t op;
625 : ptr_t * opp;
626 : size_t lg;
627 : DCL_LOCK_STATE;
628 :
629 0 : lb += TYPD_EXTRA_BYTES;
630 0 : if( SMALL_OBJ(lb) ) {
631 : GC_DBG_COLLECT_AT_MALLOC(lb);
632 0 : lg = GC_size_map[lb];
633 0 : opp = &(GC_eobjfreelist[lg]);
634 0 : LOCK();
635 0 : op = *opp;
636 0 : if (EXPECT(0 == op, FALSE)) {
637 0 : UNLOCK();
638 0 : op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind);
639 0 : if (0 == op) return 0;
640 0 : lg = GC_size_map[lb]; /* May have been uninitialized. */
641 : } else {
642 0 : *opp = obj_link(op);
643 0 : obj_link(op) = 0;
644 0 : GC_bytes_allocd += GRANULES_TO_BYTES(lg);
645 0 : UNLOCK();
646 : }
647 0 : ((word *)op)[GRANULES_TO_WORDS(lg) - 1] = d;
648 : } else {
649 0 : op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind);
650 0 : if (op != NULL) {
651 0 : lg = BYTES_TO_GRANULES(GC_size(op));
652 0 : ((word *)op)[GRANULES_TO_WORDS(lg) - 1] = d;
653 : }
654 : }
655 0 : return((void *) op);
656 : }
657 :
658 0 : GC_API GC_ATTR_MALLOC void * GC_CALL GC_calloc_explicitly_typed(size_t n,
659 : size_t lb, GC_descr d)
660 : {
661 : ptr_t op;
662 : ptr_t * opp;
663 : size_t lg;
664 : GC_descr simple_descr;
665 : complex_descriptor *complex_descr;
666 : register int descr_type;
667 : struct LeafDescriptor leaf;
668 : DCL_LOCK_STATE;
669 :
670 0 : descr_type = GC_make_array_descriptor((word)n, (word)lb, d,
671 : &simple_descr, &complex_descr, &leaf);
672 0 : switch(descr_type) {
673 0 : case NO_MEM: return(0);
674 0 : case SIMPLE: return(GC_malloc_explicitly_typed(n*lb, simple_descr));
675 : case LEAF:
676 0 : lb *= n;
677 0 : lb += sizeof(struct LeafDescriptor) + TYPD_EXTRA_BYTES;
678 0 : break;
679 : case COMPLEX:
680 0 : lb *= n;
681 0 : lb += TYPD_EXTRA_BYTES;
682 : break;
683 : }
684 0 : if( SMALL_OBJ(lb) ) {
685 0 : lg = GC_size_map[lb];
686 0 : opp = &(GC_arobjfreelist[lg]);
687 0 : LOCK();
688 0 : op = *opp;
689 0 : if (EXPECT(0 == op, FALSE)) {
690 0 : UNLOCK();
691 0 : op = (ptr_t)GENERAL_MALLOC((word)lb, GC_array_kind);
692 0 : if (0 == op) return(0);
693 0 : lg = GC_size_map[lb]; /* May have been uninitialized. */
694 : } else {
695 0 : *opp = obj_link(op);
696 0 : obj_link(op) = 0;
697 0 : GC_bytes_allocd += GRANULES_TO_BYTES(lg);
698 0 : UNLOCK();
699 : }
700 : } else {
701 0 : op = (ptr_t)GENERAL_MALLOC((word)lb, GC_array_kind);
702 0 : if (0 == op) return(0);
703 0 : lg = BYTES_TO_GRANULES(GC_size(op));
704 : }
705 0 : if (descr_type == LEAF) {
706 : /* Set up the descriptor inside the object itself. */
707 : volatile struct LeafDescriptor * lp =
708 : (struct LeafDescriptor *)
709 : ((word *)op
710 0 : + GRANULES_TO_WORDS(lg)
711 0 : - (BYTES_TO_WORDS(sizeof(struct LeafDescriptor)) + 1));
712 :
713 0 : lp -> ld_tag = LEAF_TAG;
714 0 : lp -> ld_size = leaf.ld_size;
715 0 : lp -> ld_nelements = leaf.ld_nelements;
716 0 : lp -> ld_descriptor = leaf.ld_descriptor;
717 0 : ((volatile word *)op)[GRANULES_TO_WORDS(lg) - 1] = (word)lp;
718 : } else {
719 : # ifndef GC_NO_FINALIZATION
720 0 : size_t lw = GRANULES_TO_WORDS(lg);
721 :
722 0 : ((word *)op)[lw - 1] = (word)complex_descr;
723 : /* Make sure the descriptor is cleared once there is any danger */
724 : /* it may have been collected. */
725 0 : if (GC_general_register_disappearing_link((void * *)((word *)op+lw-1),
726 : op) == GC_NO_MEMORY)
727 : # endif
728 : {
729 : /* Couldn't register it due to lack of memory. Punt. */
730 : /* This will probably fail too, but gives the recovery code */
731 : /* a chance. */
732 0 : return(GC_malloc(n*lb));
733 : }
734 : }
735 0 : return((void *) op);
736 : }
|