98
99
/* *table is a pointer to an array of hash headers. If we succeed, we */
99
100
/* update both *table and *log_size_ptr. */
100
101
/* Lock is held. Signals are disabled. */
101
void GC_grow_table(table, log_size_ptr)
102
struct hash_chain_entry ***table;
103
signed_word * log_size_ptr;
102
void GC_grow_table(struct hash_chain_entry ***table,
103
signed_word *log_size_ptr)
106
106
register struct hash_chain_entry *p;
107
int log_old_size = *log_size_ptr;
108
register int log_new_size = log_old_size + 1;
107
signed_word log_old_size = *log_size_ptr;
108
signed_word log_new_size = log_old_size + 1;
109
109
word old_size = ((log_old_size == -1)? 0: (1 << log_old_size));
110
register word new_size = 1 << log_new_size;
110
word new_size = (word)1 << log_new_size;
111
/* FIXME: Power of 2 size often gets rounded up to one more page. */
111
112
struct hash_chain_entry **new_table = (struct hash_chain_entry **)
112
113
GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
113
114
(size_t)new_size * sizeof(struct hash_chain_entry *), NORMAL);
115
116
if (new_table == 0) {
117
118
ABORT("Insufficient space for initial table allocation");
122
123
for (i = 0; i < old_size; i++) {
125
register ptr_t real_key = (ptr_t)REVEAL_POINTER(p -> hidden_key);
126
register struct hash_chain_entry *next = p -> next;
127
register int new_hash = HASH3(real_key, new_size, log_new_size);
126
ptr_t real_key = (ptr_t)REVEAL_POINTER(p -> hidden_key);
127
struct hash_chain_entry *next = p -> next;
128
size_t new_hash = HASH3(real_key, new_size, log_new_size);
129
130
p -> next = new_table[new_hash];
130
131
new_table[new_hash] = p;
135
136
*table = new_table;
138
# if defined(__STDC__) || defined(__cplusplus)
139
int GC_register_disappearing_link(GC_PTR * link)
141
int GC_register_disappearing_link(link)
139
int GC_register_disappearing_link(void * * link)
147
base = (ptr_t)GC_base((GC_PTR)link);
143
base = (ptr_t)GC_base((void *)link);
149
145
ABORT("Bad arg to GC_register_disappearing_link");
150
146
return(GC_general_register_disappearing_link(link, base));
153
# if defined(__STDC__) || defined(__cplusplus)
154
int GC_general_register_disappearing_link(GC_PTR * link,
157
int GC_general_register_disappearing_link(link, obj)
149
int GC_general_register_disappearing_link(void * * link, void * obj)
163
151
struct disappearing_link *curr_dl;
165
153
struct disappearing_link * new_dl;
168
156
if ((word)link & (ALIGNMENT-1))
169
157
ABORT("Bad arg to GC_general_register_disappearing_link");
174
161
if (log_dl_table_size == -1
175
162
|| GC_dl_entries > ((word)1 << log_dl_table_size)) {
179
163
GC_grow_table((struct hash_chain_entry ***)(&dl_head),
180
164
&log_dl_table_size);
182
if (GC_print_stats) {
183
GC_printf1("Grew dl table to %lu entries\n",
184
(unsigned long)(1 << log_dl_table_size));
165
if (GC_print_stats) {
166
GC_log_printf("Grew dl table to %u entries\n",
167
(1 << log_dl_table_size));
191
170
index = HASH2(link, log_dl_table_size);
192
171
curr_dl = dl_head[index];
234
# if defined(__STDC__) || defined(__cplusplus)
235
int GC_unregister_disappearing_link(GC_PTR * link)
237
int GC_unregister_disappearing_link(link)
209
int GC_unregister_disappearing_link(void * * link)
241
211
struct disappearing_link *curr_dl, *prev_dl;
247
216
index = HASH2(link, log_dl_table_size);
248
if (((unsigned long)link & (ALIGNMENT-1))) goto out;
217
if (((word)link & (ALIGNMENT-1))) goto out;
249
218
prev_dl = 0; curr_dl = dl_head[index];
250
219
while (curr_dl != 0) {
251
220
if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
276
243
/* Possible finalization_marker procedures. Note that mark stack */
277
244
/* overflow is handled by the caller, and is not a disaster. */
278
GC_API void GC_normal_finalize_mark_proc(p)
245
GC_API void GC_normal_finalize_mark_proc(ptr_t p)
281
247
hdr * hhdr = HDR(p);
283
PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top,
249
PUSH_OBJ(p, hhdr, GC_mark_stack_top,
284
250
&(GC_mark_stack[GC_mark_stack_size]));
287
253
/* This only pays very partial attention to the mark descriptor. */
288
254
/* It does the right thing for normal and atomic objects, and treats */
289
255
/* most others as normal. */
290
GC_API void GC_ignore_self_finalize_mark_proc(p)
256
GC_API void GC_ignore_self_finalize_mark_proc(ptr_t p)
293
258
hdr * hhdr = HDR(p);
294
259
word descr = hhdr -> hb_descr;
296
261
ptr_t scan_limit;
297
ptr_t target_limit = p + WORDS_TO_BYTES(hhdr -> hb_sz) - 1;
262
ptr_t target_limit = p + hhdr -> hb_sz - 1;
299
264
if ((descr & GC_DS_TAGS) == GC_DS_LENGTH) {
300
265
scan_limit = p + descr - sizeof(word);
304
269
for (q = p; q <= scan_limit; q += ALIGNMENT) {
306
271
if (r < p || r > target_limit) {
307
GC_PUSH_ONE_HEAP((word)r, q);
272
GC_PUSH_ONE_HEAP(r, q);
313
GC_API void GC_null_finalize_mark_proc(p)
278
GC_API void GC_null_finalize_mark_proc(ptr_t p)
282
/* Possible finalization_marker procedures. Note that mark stack */
283
/* overflow is handled by the caller, and is not a disaster. */
285
/* GC_unreachable_finalize_mark_proc is an alias for normal marking, */
286
/* but it is explicitly tested for, and triggers different */
287
/* behavior. Objects registered in this way are not finalized */
288
/* if they are reachable by other finalizable objects, eve if those */
289
/* other objects specify no ordering. */
290
GC_API void GC_unreachable_finalize_mark_proc(ptr_t p)
292
GC_normal_finalize_mark_proc(p);
325
302
/* marking for finalization ordering. Any objects marked */
326
303
/* by that procedure will be guaranteed to not have been */
327
304
/* finalized when this finalizer is invoked. */
328
GC_API void GC_register_finalizer_inner(obj, fn, cd, ofn, ocd, mp)
330
GC_finalization_proc fn;
332
GC_finalization_proc * ofn;
334
finalization_mark_proc * mp;
305
GC_API void GC_register_finalizer_inner(void * obj,
306
GC_finalization_proc fn, void *cd,
307
GC_finalization_proc *ofn, void **ocd,
308
finalization_mark_proc mp)
337
311
struct finalizable_object * curr_fo, * prev_fo;
339
313
struct finalizable_object *new_fo;
347
320
if (log_fo_table_size == -1
348
321
|| GC_fo_entries > ((word)1 << log_fo_table_size)) {
352
322
GC_grow_table((struct hash_chain_entry ***)(&fo_head),
353
323
&log_fo_table_size);
355
if (GC_print_stats) {
356
GC_printf1("Grew fo table to %lu entries\n",
357
(unsigned long)(1 << log_fo_table_size));
324
if (GC_print_stats) {
325
GC_log_printf("Grew fo table to %u entries\n",
326
(1 << log_fo_table_size));
364
329
/* in the THREADS case signals are disabled and we hold allocation */
365
330
/* lock; otherwise neither is true. Proceed carefully. */
367
332
index = HASH2(base, log_fo_table_size);
368
333
prev_fo = 0; curr_fo = fo_head[index];
369
334
while (curr_fo != 0) {
335
GC_ASSERT(GC_size(curr_fo) >= sizeof(struct finalizable_object));
370
336
if (curr_fo -> fo_hidden_base == HIDE_POINTER(base)) {
371
337
/* Interruption by a signal in the middle of this */
372
338
/* should be safe. The client may see only *ocd */
373
339
/* updated, but we'll declare that to be his */
375
if (ocd) *ocd = (GC_PTR) curr_fo -> fo_client_data;
341
if (ocd) *ocd = (void *) (curr_fo -> fo_client_data);
376
342
if (ofn) *ofn = curr_fo -> fo_fn;
377
343
/* Delete the structure for base. */
378
344
if (prev_fo == 0) {
456
418
fo_head[index] = new_fo;
463
# if defined(__STDC__)
464
void GC_register_finalizer(void * obj,
424
void GC_register_finalizer(void * obj,
465
425
GC_finalization_proc fn, void * cd,
466
426
GC_finalization_proc *ofn, void ** ocd)
468
void GC_register_finalizer(obj, fn, cd, ofn, ocd)
470
GC_finalization_proc fn;
472
GC_finalization_proc * ofn;
476
428
GC_register_finalizer_inner(obj, fn, cd, ofn,
477
429
ocd, GC_normal_finalize_mark_proc);
480
# if defined(__STDC__)
481
void GC_register_finalizer_ignore_self(void * obj,
432
void GC_register_finalizer_ignore_self(void * obj,
482
433
GC_finalization_proc fn, void * cd,
483
434
GC_finalization_proc *ofn, void ** ocd)
485
void GC_register_finalizer_ignore_self(obj, fn, cd, ofn, ocd)
487
GC_finalization_proc fn;
489
GC_finalization_proc * ofn;
493
436
GC_register_finalizer_inner(obj, fn, cd, ofn,
494
437
ocd, GC_ignore_self_finalize_mark_proc);
497
# if defined(__STDC__)
498
void GC_register_finalizer_no_order(void * obj,
440
void GC_register_finalizer_no_order(void * obj,
499
441
GC_finalization_proc fn, void * cd,
500
442
GC_finalization_proc *ofn, void ** ocd)
502
void GC_register_finalizer_no_order(obj, fn, cd, ofn, ocd)
504
GC_finalization_proc fn;
506
GC_finalization_proc * ofn;
510
444
GC_register_finalizer_inner(obj, fn, cd, ofn,
511
445
ocd, GC_null_finalize_mark_proc);
448
static GC_bool need_unreachable_finalization = FALSE;
449
/* Avoid the work if this isn't used. */
451
void GC_register_finalizer_unreachable(void * obj,
452
GC_finalization_proc fn, void * cd,
453
GC_finalization_proc *ofn, void ** ocd)
455
need_unreachable_finalization = TRUE;
456
GC_ASSERT(GC_java_finalization);
457
GC_register_finalizer_inner(obj, fn, cd, ofn,
458
ocd, GC_unreachable_finalize_mark_proc);
514
461
#ifndef NO_DEBUGGING
515
void GC_dump_finalization()
462
void GC_dump_finalization(void)
517
464
struct disappearing_link * curr_dl;
518
465
struct finalizable_object * curr_fo;
521
468
int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
524
GC_printf0("Disappearing links:\n");
471
GC_printf("Disappearing links:\n");
525
472
for (i = 0; i < dl_size; i++) {
526
473
for (curr_dl = dl_head[i]; curr_dl != 0; curr_dl = dl_next(curr_dl)) {
527
474
real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
528
475
real_link = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link);
529
GC_printf2("Object: 0x%lx, Link:0x%lx\n", real_ptr, real_link);
476
GC_printf("Object: %p, Link:%p\n", real_ptr, real_link);
532
GC_printf0("Finalizers:\n");
479
GC_printf("Finalizers:\n");
533
480
for (i = 0; i < fo_size; i++) {
534
481
for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
535
482
real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
536
GC_printf1("Finalizable object: 0x%lx\n", real_ptr);
483
GC_printf("Finalizable object: %p\n", real_ptr);
542
489
/* Called with world stopped. Cause disappearing links to disappear, */
543
490
/* and invoke finalizers. */
491
void GC_finalize(void)
546
493
struct disappearing_link * curr_dl, * prev_dl, * next_dl;
547
494
struct finalizable_object * curr_fo, * prev_fo, * next_fo;
548
495
ptr_t real_ptr, real_link;
550
int dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
551
int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
497
size_t dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
498
size_t fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
553
500
/* Make disappearing links disappear */
554
501
for (i = 0; i < dl_size; i++) {
638
586
if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
639
587
GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
641
GC_set_mark_bit(real_ptr);
589
if (curr_fo -> fo_mark_proc != GC_unreachable_finalize_mark_proc) {
590
GC_set_mark_bit(real_ptr);
595
/* now revive finalize-when-unreachable objects reachable from
596
other finalizable objects */
597
if (need_unreachable_finalization) {
598
curr_fo = GC_finalize_now;
600
while (curr_fo != 0) {
601
next_fo = fo_next(curr_fo);
602
if (curr_fo -> fo_mark_proc == GC_unreachable_finalize_mark_proc) {
603
real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
604
if (!GC_is_marked(real_ptr)) {
605
GC_set_mark_bit(real_ptr);
608
GC_finalize_now = next_fo;
610
fo_set_next(prev_fo, next_fo);
612
curr_fo -> fo_hidden_base =
613
(word) HIDE_POINTER(curr_fo -> fo_hidden_base);
614
GC_bytes_finalized -=
615
curr_fo -> fo_object_size + sizeof(struct finalizable_object);
617
i = HASH2(real_ptr, log_fo_table_size);
618
fo_set_next (curr_fo, fo_head[i]);
620
fo_head[i] = curr_fo;
646
630
/* Remove dangling disappearing links. */
730
713
* This routine is externally callable, so is called without
731
714
* the allocation lock.
733
GC_API void GC_finalize_all()
716
GC_API void GC_finalize_all(void)
739
721
while (GC_fo_entries > 0) {
740
722
GC_enqueue_all_finalizers();
743
724
GC_INVOKE_FINALIZERS();
752
731
/* Returns true if it is worth calling GC_invoke_finalizers. (Useful if */
753
732
/* finalizers can only be called from some kind of `safe state' and */
754
733
/* getting into that safe state is expensive.) */
755
int GC_should_invoke_finalizers GC_PROTO((void))
734
int GC_should_invoke_finalizers(void)
757
736
return GC_finalize_now != 0;
760
739
/* Invoke finalizers for all objects that are ready to be finalized. */
761
740
/* Should be called without allocation lock. */
762
int GC_invoke_finalizers()
741
int GC_invoke_finalizers(void)
764
743
struct finalizable_object * curr_fo;
766
word mem_freed_before;
745
word bytes_freed_before;
769
748
while (GC_finalize_now != 0) {
774
752
if (count == 0) {
775
mem_freed_before = GC_mem_freed;
753
bytes_freed_before = GC_bytes_freed;
754
/* Don't do this outside, since we need the lock. */
777
756
curr_fo = GC_finalize_now;
779
758
if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
782
760
if (curr_fo == 0) break;
784
762
GC_finalize_now = fo_next(curr_fo);
792
770
/* This is probably a bad idea. It throws off accounting if */
793
771
/* nearly all objects are finalizable. O.w. it shouldn't */
795
GC_free((GC_PTR)curr_fo);
773
GC_free((void *)curr_fo);
798
if (count != 0 && mem_freed_before != GC_mem_freed) {
776
/* bytes_freed_before is initialized whenever count != 0 */
777
if (count != 0 && bytes_freed_before != GC_bytes_freed) {
800
GC_finalizer_mem_freed += (GC_mem_freed - mem_freed_before);
779
GC_finalizer_bytes_freed += (GC_bytes_freed - bytes_freed_before);
806
void (* GC_finalizer_notifier)() = (void (*) GC_PROTO((void)))0;
785
void (* GC_finalizer_notifier)() = (void (*) (void))0;
808
787
static GC_word last_finalizer_notification = 0;
810
void GC_notify_or_invoke_finalizers GC_PROTO((void))
789
void GC_notify_or_invoke_finalizers(void)
812
791
/* This is a convenient place to generate backtraces if appropriate, */
813
792
/* since that code is not callable with the allocation lock. */
847
826
# endif /* Otherwise GC can run concurrently and add more */
850
if (GC_finalizer_notifier != (void (*) GC_PROTO((void)))0
829
if (GC_finalizer_notifier != (void (*) (void))0
851
830
&& last_finalizer_notification != GC_gc_no) {
852
831
last_finalizer_notification = GC_gc_no;
853
832
GC_finalizer_notifier();
858
GC_PTR GC_call_with_alloc_lock(GC_fn_type fn,
861
GC_PTR GC_call_with_alloc_lock(fn, client_data)
836
void * GC_call_with_alloc_lock(GC_fn_type fn, void * client_data)
843
/* FIXME - This looks wrong!! */
872
844
SET_LOCK_HOLDER();
874
846
result = (*fn)(client_data);
877
849
UNSET_LOCK_HOLDER();
878
850
# endif /* o.w. UNLOCK() does it implicitly */
885
856
#if !defined(NO_DEBUGGING)
887
void GC_print_finalization_stats()
858
void GC_print_finalization_stats(void)
889
860
struct finalizable_object *fo = GC_finalize_now;
890
861
size_t ready = 0;
892
GC_printf2("%lu finalization table entries; %lu disappearing links\n",
863
GC_printf("%u finalization table entries; %u disappearing links\n",
893
864
GC_fo_entries, GC_dl_entries);
894
865
for (; 0 != fo; fo = fo_next(fo)) ++ready;
895
GC_printf1("%lu objects are eligible for immediate finalization\n", ready);
866
GC_printf("%u objects are eligible for immediate finalization\n", ready);
898
869
#endif /* NO_DEBUGGING */