re PR target/78594 (Bug in November 11th, 2016 change to rs6000.md)
[platform/upstream/gcc.git] / boehm-gc / testsuite / boehm-gc.c / gctest.c
1 /* 
2  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
4  * Copyright (c) 1996 by Silicon Graphics.  All rights reserved.
5  *
6  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
7  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
8  *
9  * Permission is hereby granted to use or copy this program
10  * for any purpose,  provided the above notices are retained on all copies.
11  * Permission to modify the code and to distribute modified code is granted,
12  * provided the above notices are retained, and a notice that the code was
13  * modified is included with the above copyright notice.
14  */
15 /* An incomplete test for the garbage collector.                */
16 /* Some more obscure entry points are not tested at all.        */
17 /* This must be compiled with the same flags used to build the  */
18 /* GC.  It uses GC internals to allow more precise results      */
19 /* checking for some of the tests.                              */
20
21 # undef GC_BUILD
22
23 #if defined(DBG_HDRS_ALL) || defined(MAKE_BACK_GRAPH)
24 #  define GC_DEBUG
25 #endif
26
27 # if defined(mips) && defined(SYSTYPE_BSD43)
28     /* MIPS RISCOS 4 */
29 # else
30 #   include <stdlib.h>
31 # endif
32 # include <stdio.h>
33 # ifdef _WIN32_WCE
34 #   include <winbase.h>
35 #   define assert ASSERT
36 # else
37 #   include <assert.h>        /* Not normally used, but handy for debugging. */
38 # endif
39 # include <assert.h>    /* Not normally used, but handy for debugging. */
40 # include "gc.h"
41 # include "gc_typed.h"
42 # ifdef THREAD_LOCAL_ALLOC
43 #   include "gc_local_alloc.h"
44 # endif
45 # include "private/gc_priv.h"   /* For output, locking, MIN_WORDS,      */
46                                 /* and some statistics.                 */
47 # include "private/gcconfig.h"
48
49 # if defined(MSWIN32) || defined(MSWINCE)
50 #   include <windows.h>
51 # endif
52
53 # ifdef PCR
54 #   include "th/PCR_ThCrSec.h"
55 #   include "th/PCR_Th.h"
56 #   undef GC_printf0
57 #   define GC_printf0 printf
58 #   undef GC_printf1
59 #   define GC_printf1 printf
60 # endif
61
62 # if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
63 #   include <thread.h>
64 #   include <synch.h>
65 # endif
66
67 # if defined(GC_PTHREADS)
68 #   include <pthread.h>
69 # endif
70
71 # if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
72     static CRITICAL_SECTION incr_cs;
73 # endif
74
75 #ifdef __STDC__
76 # include <stdarg.h>
77 #endif
78
79
80 /* Allocation Statistics */
81 int stubborn_count = 0;
82 int uncollectable_count = 0;
83 int collectable_count = 0;
84 int atomic_count = 0;
85 int realloc_count = 0;
86
87 #if defined(GC_AMIGA_FASTALLOC) && defined(AMIGA)
88
89   extern void GC_amiga_free_all_mem(void);
90   void Amiga_Fail(void){GC_amiga_free_all_mem();abort();}
91 # define FAIL (void)Amiga_Fail()
92   void *GC_amiga_gctest_malloc_explicitly_typed(size_t lb, GC_descr d){
93     void *ret=GC_malloc_explicitly_typed(lb,d);
94     if(ret==NULL){
95                 if(!GC_dont_gc){
96               GC_gcollect();
97               ret=GC_malloc_explicitly_typed(lb,d);
98                 }
99       if(ret==NULL){
100         GC_printf0("Out of memory, (typed allocations are not directly "
101                    "supported with the GC_AMIGA_FASTALLOC option.)\n");
102         FAIL;
103       }
104     }
105     return ret;
106   }
107   void *GC_amiga_gctest_calloc_explicitly_typed(size_t a,size_t lb, GC_descr d){
108     void *ret=GC_calloc_explicitly_typed(a,lb,d);
109     if(ret==NULL){
110                 if(!GC_dont_gc){
111               GC_gcollect();
112               ret=GC_calloc_explicitly_typed(a,lb,d);
113                 }
114       if(ret==NULL){
115         GC_printf0("Out of memory, (typed allocations are not directly "
116                    "supported with the GC_AMIGA_FASTALLOC option.)\n");
117         FAIL;
118       }
119     }
120     return ret;
121   }
122 # define GC_malloc_explicitly_typed(a,b) GC_amiga_gctest_malloc_explicitly_typed(a,b) 
123 # define GC_calloc_explicitly_typed(a,b,c) GC_amiga_gctest_calloc_explicitly_typed(a,b,c) 
124
125 #else /* !AMIGA_FASTALLOC */
126
127 # ifdef PCR
128 #   define FAIL (void)abort()
129 # else
130 #   ifdef MSWINCE
131 #     define FAIL DebugBreak()
132 #   else
133 #     define FAIL GC_abort("Test failed");
134 #   endif
135 # endif
136
137 #endif /* !AMIGA_FASTALLOC */
138
139 /* AT_END may be defined to exercise the interior pointer test  */
140 /* if the collector is configured with ALL_INTERIOR_POINTERS.   */
141 /* As it stands, this test should succeed with either           */
142 /* configuration.  In the FIND_LEAK configuration, it should    */
143 /* find lots of leaks, since we free almost nothing.            */
144
145 struct SEXPR {
146     struct SEXPR * sexpr_car;
147     struct SEXPR * sexpr_cdr;
148 };
149
150
151 typedef struct SEXPR * sexpr;
152
153 # define INT_TO_SEXPR(x) ((sexpr)(unsigned long)(x))
154
155 # undef nil
156 # define nil (INT_TO_SEXPR(0))
157 # define car(x) ((x) -> sexpr_car)
158 # define cdr(x) ((x) -> sexpr_cdr)
159 # define is_nil(x) ((x) == nil)
160
161
162 int extra_count = 0;        /* Amount of space wasted in cons node */
163
164 /* Silly implementation of Lisp cons. Intentionally wastes lots of space */
165 /* to test collector.                                                    */
166 # ifdef VERY_SMALL_CONFIG
167 #   define cons small_cons
168 # else
169 sexpr cons (x, y)
170 sexpr x;
171 sexpr y;
172 {
173     register sexpr r;
174     register int *p;
175     register int my_extra = extra_count;
176     
177     stubborn_count++;
178     r = (sexpr) GC_MALLOC_STUBBORN(sizeof(struct SEXPR) + my_extra);
179     if (r == 0) {
180         (void)GC_printf0("Out of memory\n");
181         exit(1);
182     }
183     for (p = (int *)r;
184          ((char *)p) < ((char *)r) + my_extra + sizeof(struct SEXPR); p++) {
185         if (*p) {
186             (void)GC_printf1("Found nonzero at 0x%lx - allocator is broken\n",
187                              (unsigned long)p);
188             FAIL;
189         }
190         *p = 13;
191     }
192 #   ifdef AT_END
193         r = (sexpr)((char *)r + (my_extra & ~7));
194 #   endif
195     r -> sexpr_car = x;
196     r -> sexpr_cdr = y;
197     my_extra++;
198     if ( my_extra >= 5000 ) {
199         extra_count = 0;
200     } else {
201         extra_count = my_extra;
202     }
203     GC_END_STUBBORN_CHANGE((char *)r);
204     return(r);
205 }
206 # endif
207
208 #ifdef GC_GCJ_SUPPORT
209
210 #include "gc_mark.h"
211 #include "gc_gcj.h"
212
213 /* The following struct emulates the vtable in gcj.     */
214 /* This assumes the default value of MARK_DESCR_OFFSET. */
215 struct fake_vtable {
216   void * dummy;         /* class pointer in real gcj.   */
217   size_t descr;
218 };
219
220 struct fake_vtable gcj_class_struct1 = { 0, sizeof(struct SEXPR)
221                                             + sizeof(struct fake_vtable *) };
222                         /* length based descriptor.     */
223 struct fake_vtable gcj_class_struct2 =
224                                 { 0, (3l << (CPP_WORDSZ - 3)) | GC_DS_BITMAP};
225                         /* Bitmap based descriptor.     */
226
227 struct GC_ms_entry * fake_gcj_mark_proc(word * addr,
228                                         struct GC_ms_entry *mark_stack_ptr,
229                                         struct GC_ms_entry *mark_stack_limit,
230                                         word env   )
231 {
232     sexpr x;
233     if (1 == env) {
234         /* Object allocated with debug allocator.       */
235         addr = (word *)GC_USR_PTR_FROM_BASE(addr);
236     }
237     x = (sexpr)(addr + 1); /* Skip the vtable pointer. */
238     mark_stack_ptr = GC_MARK_AND_PUSH(
239                               (GC_PTR)(x -> sexpr_cdr), mark_stack_ptr,
240                               mark_stack_limit, (GC_PTR *)&(x -> sexpr_cdr));
241     mark_stack_ptr = GC_MARK_AND_PUSH(
242                               (GC_PTR)(x -> sexpr_car), mark_stack_ptr,
243                               mark_stack_limit, (GC_PTR *)&(x -> sexpr_car));
244     return(mark_stack_ptr);
245 }
246
247 #endif /* GC_GCJ_SUPPORT */
248
249 #ifdef THREAD_LOCAL_ALLOC
250
251 #undef GC_REDIRECT_TO_LOCAL
252 #include "gc_local_alloc.h"
253
254 sexpr local_cons (x, y)
255 sexpr x;
256 sexpr y;
257 {
258     register sexpr r;
259     register int *p;
260     register int my_extra = extra_count;
261     static int my_random = 0;
262     
263     collectable_count++;
264     r = (sexpr) GC_LOCAL_MALLOC(sizeof(struct SEXPR) + my_extra);
265 #   ifdef GC_GCJ_SUPPORT
266       if (collectable_count % 2 == 0) {
267         r = (sexpr) GC_LOCAL_GCJ_MALLOC(sizeof(struct SEXPR) + sizeof(GC_word) + my_extra,
268                                         &gcj_class_struct1);
269         r = (sexpr) ((GC_word *)r + 1);
270       }
271 #   endif
272     if (r == 0) {
273         (void)GC_printf0("Out of memory\n");
274         exit(1);
275     }
276     for (p = (int *)r;
277          ((char *)p) < ((char *)r) + my_extra + sizeof(struct SEXPR); p++) {
278         if (*p) {
279             (void)GC_printf1("Found nonzero at 0x%lx (local) - allocator is broken\n",
280                              (unsigned long)p);
281             FAIL;
282         }
283         *p = 13;
284     }
285     r -> sexpr_car = x;
286     r -> sexpr_cdr = y;
287     my_extra++;
288     if ( my_extra >= 5000 || my_extra == 200 && ++my_random % 37 != 0) {
289         extra_count = 0;
290     } else {
291         extra_count = my_extra;
292     }
293     return(r);
294 }
295 #endif /* THREAD_LOCAL_ALLOC */
296
297 sexpr small_cons (x, y)
298 sexpr x;
299 sexpr y;
300 {
301     register sexpr r;
302     
303     collectable_count++;
304     r = (sexpr) GC_MALLOC(sizeof(struct SEXPR));
305     if (r == 0) {
306         (void)GC_printf0("Out of memory\n");
307         exit(1);
308     }
309     r -> sexpr_car = x;
310     r -> sexpr_cdr = y;
311     return(r);
312 }
313
314 sexpr small_cons_uncollectable (x, y)
315 sexpr x;
316 sexpr y;
317 {
318     register sexpr r;
319     
320     uncollectable_count++;
321     r = (sexpr) GC_MALLOC_UNCOLLECTABLE(sizeof(struct SEXPR));
322     if (r == 0) {
323         (void)GC_printf0("Out of memory\n");
324         exit(1);
325     }
326     r -> sexpr_car = x;
327     r -> sexpr_cdr = (sexpr)(~(unsigned long)y);
328     return(r);
329 }
330
331 #ifdef GC_GCJ_SUPPORT
332
333
334 sexpr gcj_cons(x, y)
335 sexpr x;
336 sexpr y;
337 {
338     GC_word * r;
339     sexpr result;
340     static int count = 0;
341     
342     if (++count & 1) {
343 #     ifdef USE_MARK_BYTES
344         r = (GC_word *) GC_GCJ_FAST_MALLOC(4, &gcj_class_struct1);
345 #     else
346         r = (GC_word *) GC_GCJ_FAST_MALLOC(3, &gcj_class_struct1);
347 #     endif
348     } else {
349         r = (GC_word *) GC_GCJ_MALLOC(sizeof(struct SEXPR)
350                                       + sizeof(struct fake_vtable*),
351                                       &gcj_class_struct2);
352     }
353     if (r == 0) {
354         (void)GC_printf0("Out of memory\n");
355         exit(1);
356     }
357     result = (sexpr)(r + 1);
358     result -> sexpr_car = x;
359     result -> sexpr_cdr = y;
360     return(result);
361 }
362 #endif
363
364 /* Return reverse(x) concatenated with y */
365 sexpr reverse1(x, y)
366 sexpr x, y;
367 {
368     if (is_nil(x)) {
369         return(y);
370     } else {
371         return( reverse1(cdr(x), cons(car(x), y)) );
372     }
373 }
374
375 sexpr reverse(x)
376 sexpr x;
377 {
378 #   ifdef TEST_WITH_SYSTEM_MALLOC
379       malloc(100000);
380 #   endif
381     return( reverse1(x, nil) );
382 }
383
384 sexpr ints(low, up)
385 int low, up;
386 {
387     if (low > up) {
388         return(nil);
389     } else {
390         return(small_cons(small_cons(INT_TO_SEXPR(low), nil), ints(low+1, up)));
391     }
392 }
393
394 #ifdef GC_GCJ_SUPPORT
395 /* Return reverse(x) concatenated with y */
396 sexpr gcj_reverse1(x, y)
397 sexpr x, y;
398 {
399     if (is_nil(x)) {
400         return(y);
401     } else {
402         return( gcj_reverse1(cdr(x), gcj_cons(car(x), y)) );
403     }
404 }
405
406 sexpr gcj_reverse(x)
407 sexpr x;
408 {
409     return( gcj_reverse1(x, nil) );
410 }
411
412 sexpr gcj_ints(low, up)
413 int low, up;
414 {
415     if (low > up) {
416         return(nil);
417     } else {
418         return(gcj_cons(gcj_cons(INT_TO_SEXPR(low), nil), gcj_ints(low+1, up)));
419     }
420 }
421 #endif /* GC_GCJ_SUPPORT */
422
423 #ifdef THREAD_LOCAL_ALLOC
424 /* Return reverse(x) concatenated with y */
425 sexpr local_reverse1(x, y)
426 sexpr x, y;
427 {
428     if (is_nil(x)) {
429         return(y);
430     } else {
431         return( local_reverse1(cdr(x), local_cons(car(x), y)) );
432     }
433 }
434
435 sexpr local_reverse(x)
436 sexpr x;
437 {
438     return( local_reverse1(x, nil) );
439 }
440
441 sexpr local_ints(low, up)
442 int low, up;
443 {
444     if (low > up) {
445         return(nil);
446     } else {
447         return(local_cons(local_cons(INT_TO_SEXPR(low), nil), local_ints(low+1, up)));
448     }
449 }
450 #endif /* THREAD_LOCAL_ALLOC */
451
452 /* To check uncollectable allocation we build lists with disguised cdr  */
453 /* pointers, and make sure they don't go away.                          */
454 sexpr uncollectable_ints(low, up)
455 int low, up;
456 {
457     if (low > up) {
458         return(nil);
459     } else {
460         return(small_cons_uncollectable(small_cons(INT_TO_SEXPR(low), nil),
461                uncollectable_ints(low+1, up)));
462     }
463 }
464
465 void check_ints(list, low, up)
466 sexpr list;
467 int low, up;
468 {
469     if ((int)(GC_word)(car(car(list))) != low) {
470         (void)GC_printf0(
471            "List reversal produced incorrect list - collector is broken\n");
472         FAIL;
473     }
474     if (low == up) {
475         if (cdr(list) != nil) {
476            (void)GC_printf0("List too long - collector is broken\n");
477            FAIL;
478         }
479     } else {
480         check_ints(cdr(list), low+1, up);
481     }
482 }
483
484 # define UNCOLLECTABLE_CDR(x) (sexpr)(~(unsigned long)(cdr(x)))
485
486 void check_uncollectable_ints(list, low, up)
487 sexpr list;
488 int low, up;
489 {
490     if ((int)(GC_word)(car(car(list))) != low) {
491         (void)GC_printf0(
492            "Uncollectable list corrupted - collector is broken\n");
493         FAIL;
494     }
495     if (low == up) {
496         if (UNCOLLECTABLE_CDR(list) != nil) {
497            (void)GC_printf0("Uncollectable list too long - collector is broken\n");
498            FAIL;
499         }
500     } else {
501         check_uncollectable_ints(UNCOLLECTABLE_CDR(list), low+1, up);
502     }
503 }
504
505 /* Not used, but useful for debugging: */
506 void print_int_list(x)
507 sexpr x;
508 {
509     if (is_nil(x)) {
510         (void)GC_printf0("NIL\n");
511     } else {
512         (void)GC_printf1("(%ld)", (long)(car(car(x))));
513         if (!is_nil(cdr(x))) {
514             (void)GC_printf0(", ");
515             (void)print_int_list(cdr(x));
516         } else {
517             (void)GC_printf0("\n");
518         }
519     }
520 }
521
522 /*
523  * A tiny list reversal test to check thread creation.
524  */
525 #ifdef THREADS
526
527 # if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
528     DWORD  __stdcall tiny_reverse_test(void * arg)
529 # else
530     void * tiny_reverse_test(void * arg)
531 # endif
532 {
533     int i;
534     for (i = 0; i < 5; ++i) {
535       check_ints(reverse(reverse(ints(1,10))), 1, 10);
536 #     ifdef THREAD_LOCAL_ALLOC
537         check_ints(local_reverse(local_reverse(local_ints(1,10))), 1, 10);
538 #     endif
539     }
540     return 0;
541 }
542
543 # if defined(GC_PTHREADS)
544     void fork_a_thread()
545     {
546       pthread_t t;
547       int code;
548       if ((code = pthread_create(&t, 0, tiny_reverse_test, 0)) != 0) {
549         (void)GC_printf1("Small thread creation failed %lu\n",
550                          (unsigned long)code);
551         FAIL;
552       }
553       if ((code = pthread_join(t, 0)) != 0) {
554         (void)GC_printf1("Small thread join failed %lu\n",
555         (unsigned long)code);
556         FAIL;
557       }
558     }
559
560 # elif defined(GC_WIN32_THREADS)
561     void fork_a_thread()
562     {
563         DWORD thread_id;
564         HANDLE h;
565         h = GC_CreateThread(NULL, 0, tiny_reverse_test, 0, 0, &thread_id);
566         if (h == (HANDLE)NULL) {
567             (void)GC_printf1("Small thread creation failed %lu\n",
568                              (unsigned long)GetLastError());
569             FAIL;
570         }
571         if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) {
572             (void)GC_printf1("Small thread wait failed %lu\n",
573                              (unsigned long)GetLastError());
574             FAIL;
575         }
576     }
577
578 /* # elif defined(GC_SOLARIS_THREADS) */
579
580 # else
581
582 #   define fork_a_thread()
583
584 # endif
585
586 #else
587
588 # define fork_a_thread()
589
590 #endif 
591
592 /* Try to force a to be strangely aligned */
593 struct {
594   char dummy;
595   sexpr aa;
596 } A;
597 #define a A.aa
598
599 /*
600  * Repeatedly reverse lists built out of very different sized cons cells.
601  * Check that we didn't lose anything.
602  */
603 void reverse_test()
604 {
605     int i;
606     sexpr b;
607     sexpr c;
608     sexpr d;
609     sexpr e;
610     sexpr *f, *g, *h;
611 #   if defined(MSWIN32) || defined(MACOS)
612       /* Win32S only allows 128K stacks */
613 #     define BIG 1000
614 #   else
615 #     if defined PCR
616         /* PCR default stack is 100K.  Stack frames are up to 120 bytes. */
617 #       define BIG 700
618 #     else
619 #       if defined MSWINCE
620           /* WinCE only allows 64K stacks */
621 #         define BIG 500
622 #       else
623 #         if defined(OSF1)
624             /* OSF has limited stack space by default, and large frames. */
625 #           define BIG 200
626 #         else
627 #           if defined(__MACH__) && defined(__ppc64__)
628               /* Small stack and largish frames.  */
629 #             define BIG 2500         
630 #           else
631 #             define BIG 4500
632 #           endif
633 #         endif
634 #       endif
635 #     endif
636 #   endif
637
638     A.dummy = 17;
639     a = ints(1, 49);
640     b = ints(1, 50);
641     c = ints(1, BIG);
642     d = uncollectable_ints(1, 100);
643     e = uncollectable_ints(1, 1);
644     /* Check that realloc updates object descriptors correctly */
645     collectable_count++;
646     f = (sexpr *)GC_MALLOC(4 * sizeof(sexpr));
647     realloc_count++;
648     f = (sexpr *)GC_REALLOC((GC_PTR)f, 6 * sizeof(sexpr));
649     f[5] = ints(1,17);
650     collectable_count++;
651     g = (sexpr *)GC_MALLOC(513 * sizeof(sexpr));
652     realloc_count++;
653     g = (sexpr *)GC_REALLOC((GC_PTR)g, 800 * sizeof(sexpr));
654     g[799] = ints(1,18);
655     collectable_count++;
656     h = (sexpr *)GC_MALLOC(1025 * sizeof(sexpr));
657     realloc_count++;
658     h = (sexpr *)GC_REALLOC((GC_PTR)h, 2000 * sizeof(sexpr));
659 #   ifdef GC_GCJ_SUPPORT
660       h[1999] = gcj_ints(1,200);
661       for (i = 0; i < 51; ++i) 
662         h[1999] = gcj_reverse(h[1999]);
663       /* Leave it as the reveresed list for now. */
664 #   else
665       h[1999] = ints(1,200);
666 #   endif
667     /* Try to force some collections and reuse of small list elements */
668       for (i = 0; i < 10; i++) {
669         (void)ints(1, BIG);
670       }
671     /* Superficially test interior pointer recognition on stack */
672       c = (sexpr)((char *)c + sizeof(char *));
673       d = (sexpr)((char *)d + sizeof(char *));
674
675 #   ifdef __STDC__
676         GC_FREE((void *)e);
677 #   else
678         GC_FREE((char *)e);
679 #   endif
680     check_ints(b,1,50);
681     check_ints(a,1,49);
682     for (i = 0; i < 50; i++) {
683         check_ints(b,1,50);
684         b = reverse(reverse(b));
685     }
686     check_ints(b,1,50);
687     check_ints(a,1,49);
688     for (i = 0; i < 60; i++) {
689         if (i % 10 == 0) fork_a_thread();
690         /* This maintains the invariant that a always points to a list of */
691         /* 49 integers.  Thus this is thread safe without locks,          */
692         /* assuming atomic pointer assignments.                           */
693         a = reverse(reverse(a));
694 #       ifdef THREAD_LOCAL_ALLOC
695           a = local_reverse(local_reverse(a));
696 #       endif
697 #       if !defined(AT_END) && !defined(THREADS)
698           /* This is not thread safe, since realloc explicitly deallocates */
699           if (i & 1) {
700             a = (sexpr)GC_REALLOC((GC_PTR)a, 500);
701           } else {
702             a = (sexpr)GC_REALLOC((GC_PTR)a, 8200);
703           }
704 #       endif
705     }
706     check_ints(a,1,49);
707     check_ints(b,1,50);
708     c = (sexpr)((char *)c - sizeof(char *));
709     d = (sexpr)((char *)d - sizeof(char *));
710     check_ints(c,1,BIG);
711     check_uncollectable_ints(d, 1, 100);
712     check_ints(f[5], 1,17);
713     check_ints(g[799], 1,18);
714 #   ifdef GC_GCJ_SUPPORT
715       h[1999] = gcj_reverse(h[1999]);
716 #   endif
717     check_ints(h[1999], 1,200);
718 #   ifndef THREADS
719         a = 0;
720 #   endif  
721     b = c = 0;
722 }
723
724 #undef a
725
726 /*
727  * The rest of this builds balanced binary trees, checks that they don't
728  * disappear, and tests finalization.
729  */
730 typedef struct treenode {
731     int level;
732     struct treenode * lchild;
733     struct treenode * rchild;
734 } tn;
735
736 int finalizable_count = 0;
737 int finalized_count = 0;
738 VOLATILE int dropped_something = 0;
739
740 # ifdef __STDC__
741   void finalizer(void * obj, void * client_data)
742 # else
743   void finalizer(obj, client_data)
744   char * obj;
745   char * client_data;
746 # endif
747 {
748   tn * t = (tn *)obj;
749
750 # ifdef PCR
751      PCR_ThCrSec_EnterSys();
752 # endif
753 # if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
754     static mutex_t incr_lock;
755     mutex_lock(&incr_lock);
756 # endif
757 # if  defined(GC_PTHREADS)
758     static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
759     pthread_mutex_lock(&incr_lock);
760 # else
761 #   ifdef GC_WIN32_THREADS
762       EnterCriticalSection(&incr_cs);
763 #   endif
764 # endif
765   if ((int)(GC_word)client_data != t -> level) {
766      (void)GC_printf0("Wrong finalization data - collector is broken\n");
767      FAIL;
768   }
769   finalized_count++;
770   t -> level = -1;      /* detect duplicate finalization immediately */
771 # ifdef PCR
772     PCR_ThCrSec_ExitSys();
773 # endif
774 # if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
775     mutex_unlock(&incr_lock);
776 # endif
777 # if defined(GC_PTHREADS)
778     pthread_mutex_unlock(&incr_lock);
779 # else
780 #   ifdef GC_WIN32_THREADS
781       LeaveCriticalSection(&incr_cs);
782 #   endif
783 # endif
784 }
785
786 size_t counter = 0;
787
788 # define MAX_FINALIZED 8000
789
790 # if !defined(MACOS)
791   GC_FAR GC_word live_indicators[MAX_FINALIZED] = {0};
792 #else
793   /* Too big for THINK_C. have to allocate it dynamically. */
794   GC_word *live_indicators = 0;
795 #endif
796
797 int live_indicators_count = 0;
798
799 tn * mktree(n)
800 int n;
801 {
802 #   ifdef THREAD_LOCAL_ALLOC
803       tn * result = (tn *)GC_LOCAL_MALLOC(sizeof(tn));
804 #   else
805       tn * result = (tn *)GC_MALLOC(sizeof(tn));
806 #   endif
807     
808     collectable_count++;
809 #   ifdef THREAD_LOCAL_ALLOC
810        /* Minimally exercise thread local allocation */
811        {
812          char * result = (char *)GC_LOCAL_MALLOC_ATOMIC(17);
813          memset(result, 'a', 17);
814        }
815 #   endif /* THREAD_LOCAL_ALLOC */
816 #   if defined(MACOS)
817         /* get around static data limitations. */
818         if (!live_indicators)
819                 live_indicators =
820                     (GC_word*)NewPtrClear(MAX_FINALIZED * sizeof(GC_word));
821         if (!live_indicators) {
822           (void)GC_printf0("Out of memory\n");
823           exit(1);
824         }
825 #   endif
826     if (n == 0) return(0);
827     if (result == 0) {
828         (void)GC_printf0("Out of memory\n");
829         exit(1);
830     }
831     result -> level = n;
832     result -> lchild = mktree(n-1);
833     result -> rchild = mktree(n-1);
834     if (counter++ % 17 == 0 && n >= 2) {
835         tn * tmp = result -> lchild -> rchild;
836         
837         result -> lchild -> rchild = result -> rchild -> lchild;
838         result -> rchild -> lchild = tmp;
839     }
840     if (counter++ % 119 == 0) {
841         int my_index;
842         
843         {
844 #         ifdef PCR
845             PCR_ThCrSec_EnterSys();
846 #         endif
847 #         if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
848             static mutex_t incr_lock;
849             mutex_lock(&incr_lock);
850 #         endif
851 #         if defined(GC_PTHREADS)
852             static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
853             pthread_mutex_lock(&incr_lock);
854 #         else
855 #           ifdef GC_WIN32_THREADS
856               EnterCriticalSection(&incr_cs);
857 #           endif
858 #         endif
859                 /* Losing a count here causes erroneous report of failure. */
860           finalizable_count++;
861           my_index = live_indicators_count++;
862 #         ifdef PCR
863             PCR_ThCrSec_ExitSys();
864 #         endif
865 #         if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
866             mutex_unlock(&incr_lock);
867 #         endif
868 #         if defined(GC_PTHREADS)
869             pthread_mutex_unlock(&incr_lock);
870 #         else
871 #           ifdef GC_WIN32_THREADS
872               LeaveCriticalSection(&incr_cs);
873 #           endif
874 #         endif
875         }
876
877         GC_REGISTER_FINALIZER((GC_PTR)result, finalizer, (GC_PTR)(GC_word)n,
878                               (GC_finalization_proc *)0, (GC_PTR *)0);
879         if (my_index >= MAX_FINALIZED) {
880                 GC_printf0("live_indicators overflowed\n");
881                 FAIL;
882         }
883         live_indicators[my_index] = 13;
884         if (GC_GENERAL_REGISTER_DISAPPEARING_LINK(
885                 (GC_PTR *)(&(live_indicators[my_index])),
886                 (GC_PTR)result) != 0) {
887                 GC_printf0("GC_general_register_disappearing_link failed\n");
888                 FAIL;
889         }
890         if (GC_unregister_disappearing_link(
891                 (GC_PTR *)
892                    (&(live_indicators[my_index]))) == 0) {
893                 GC_printf0("GC_unregister_disappearing_link failed\n");
894                 FAIL;
895         }
896         if (GC_GENERAL_REGISTER_DISAPPEARING_LINK(
897                 (GC_PTR *)(&(live_indicators[my_index])),
898                 (GC_PTR)result) != 0) {
899                 GC_printf0("GC_general_register_disappearing_link failed 2\n");
900                 FAIL;
901         }
902     }
903     return(result);
904 }
905
906 void chktree(t,n)
907 tn *t;
908 int n;
909 {
910     if (n == 0 && t != 0) {
911         (void)GC_printf0("Clobbered a leaf - collector is broken\n");
912         FAIL;
913     }
914     if (n == 0) return;
915     if (t -> level != n) {
916         (void)GC_printf1("Lost a node at level %lu - collector is broken\n",
917                          (unsigned long)n);
918         FAIL;
919     }
920     if (counter++ % 373 == 0) {
921         collectable_count++;
922         (void) GC_MALLOC(counter%5001);
923     }
924     chktree(t -> lchild, n-1);
925     if (counter++ % 73 == 0) {
926         collectable_count++;
927         (void) GC_MALLOC(counter%373);
928     }
929     chktree(t -> rchild, n-1);
930 }
931
932 # if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
933 thread_key_t fl_key;
934
935 void * alloc8bytes()
936 {
937 # if defined(SMALL_CONFIG) || defined(GC_DEBUG)
938     collectable_count++;
939     return(GC_MALLOC(8));
940 # else
941     void ** my_free_list_ptr;
942     void * my_free_list;
943     
944     if (thr_getspecific(fl_key, (void **)(&my_free_list_ptr)) != 0) {
945         (void)GC_printf0("thr_getspecific failed\n");
946         FAIL;
947     }
948     if (my_free_list_ptr == 0) {
949         uncollectable_count++;
950         my_free_list_ptr = GC_NEW_UNCOLLECTABLE(void *);
951         if (thr_setspecific(fl_key, my_free_list_ptr) != 0) {
952             (void)GC_printf0("thr_setspecific failed\n");
953             FAIL;
954         }
955     }
956     my_free_list = *my_free_list_ptr;
957     if (my_free_list == 0) {
958         collectable_count++;
959         my_free_list = GC_malloc_many(8);
960         if (my_free_list == 0) {
961             (void)GC_printf0("alloc8bytes out of memory\n");
962             FAIL;
963         }
964     }
965     *my_free_list_ptr = GC_NEXT(my_free_list);
966     GC_NEXT(my_free_list) = 0;
967     return(my_free_list);
968 # endif
969 }
970
971 #else
972
973 # if defined(GC_PTHREADS)
974 pthread_key_t fl_key;
975
976 void * alloc8bytes()
977 {
978 # if defined(SMALL_CONFIG) || defined(GC_DEBUG)
979     collectable_count++;
980     return(GC_MALLOC(8));
981 # else
982     void ** my_free_list_ptr;
983     void * my_free_list;
984     
985     my_free_list_ptr = (void **)pthread_getspecific(fl_key);
986     if (my_free_list_ptr == 0) {
987         uncollectable_count++;
988         my_free_list_ptr = GC_NEW_UNCOLLECTABLE(void *);
989         if (pthread_setspecific(fl_key, my_free_list_ptr) != 0) {
990             (void)GC_printf0("pthread_setspecific failed\n");
991             FAIL;
992         }
993     }
994     my_free_list = *my_free_list_ptr;
995     if (my_free_list == 0) {
996         my_free_list = GC_malloc_many(8);
997         if (my_free_list == 0) {
998             (void)GC_printf0("alloc8bytes out of memory\n");
999             FAIL;
1000         }
1001     }
1002     *my_free_list_ptr = GC_NEXT(my_free_list);
1003     GC_NEXT(my_free_list) = 0;
1004     collectable_count++;
1005     return(my_free_list);
1006 # endif
1007 }
1008
1009 # else
1010 #   define alloc8bytes() GC_MALLOC_ATOMIC(8)
1011 # endif
1012 #endif
1013
1014 void alloc_small(n)
1015 int n;
1016 {
1017     register int i;
1018     
1019     for (i = 0; i < n; i += 8) {
1020         atomic_count++;
1021         if (alloc8bytes() == 0) {
1022             (void)GC_printf0("Out of memory\n");
1023             FAIL;
1024         }
1025     }
1026 }
1027
1028 # if defined(THREADS) && defined(GC_DEBUG)
1029 #   ifdef VERY_SMALL_CONFIG
1030 #     define TREE_HEIGHT 12
1031 #   else
1032 #     define TREE_HEIGHT 15
1033 #   endif
1034 # else
1035 #   ifdef VERY_SMALL_CONFIG
1036 #     define TREE_HEIGHT 13
1037 #   else
1038 #     define TREE_HEIGHT 16
1039 #   endif
1040 # endif
1041 void tree_test()
1042 {
1043     tn * root;
1044     register int i;
1045     
1046     root = mktree(TREE_HEIGHT);
1047 #   ifndef VERY_SMALL_CONFIG
1048       alloc_small(5000000);
1049 #   endif
1050     chktree(root, TREE_HEIGHT);
1051     if (finalized_count && ! dropped_something) {
1052         (void)GC_printf0("Premature finalization - collector is broken\n");
1053         FAIL;
1054     }
1055     dropped_something = 1;
1056     GC_noop(root);      /* Root needs to remain live until      */
1057                         /* dropped_something is set.            */
1058     root = mktree(TREE_HEIGHT);
1059     chktree(root, TREE_HEIGHT);
1060     for (i = TREE_HEIGHT; i >= 0; i--) {
1061         root = mktree(i);
1062         chktree(root, i);
1063     }
1064 #   ifndef VERY_SMALL_CONFIG
1065       alloc_small(5000000);
1066 #   endif
1067 }
1068
1069 unsigned n_tests = 0;
1070
1071 GC_word bm_huge[10] = {
1072     0xffffffff,
1073     0xffffffff,
1074     0xffffffff,
1075     0xffffffff,
1076     0xffffffff,
1077     0xffffffff,
1078     0xffffffff,
1079     0xffffffff,
1080     0xffffffff,
1081     0x00ffffff,
1082 };
1083
1084 /* A very simple test of explicitly typed allocation    */
1085 void typed_test()
1086 {
1087     GC_word * old, * new;
1088     GC_word bm3 = 0x3;
1089     GC_word bm2 = 0x2;
1090     GC_word bm_large = 0xf7ff7fff;
1091     GC_descr d1 = GC_make_descriptor(&bm3, 2);
1092     GC_descr d2 = GC_make_descriptor(&bm2, 2);
1093 #   ifndef LINT
1094       GC_descr dummy = GC_make_descriptor(&bm_large, 32);
1095 #   endif
1096     GC_descr d3 = GC_make_descriptor(&bm_large, 32);
1097     GC_descr d4 = GC_make_descriptor(bm_huge, 320);
1098     GC_word * x = (GC_word *)GC_malloc_explicitly_typed(2000, d4);
1099     register int i;
1100     
1101     collectable_count++;
1102     old = 0;
1103     for (i = 0; i < 4000; i++) {
1104         collectable_count++;
1105         new = (GC_word *) GC_malloc_explicitly_typed(4 * sizeof(GC_word), d1);
1106         if (0 != new[0] || 0 != new[1]) {
1107             GC_printf0("Bad initialization by GC_malloc_explicitly_typed\n");
1108             FAIL;
1109         }
1110         new[0] = 17;
1111         new[1] = (GC_word)old;
1112         old = new;
1113         collectable_count++;
1114         new = (GC_word *) GC_malloc_explicitly_typed(4 * sizeof(GC_word), d2);
1115         new[0] = 17;
1116         new[1] = (GC_word)old;
1117         old = new;
1118         collectable_count++;
1119         new = (GC_word *) GC_malloc_explicitly_typed(33 * sizeof(GC_word), d3);
1120         new[0] = 17;
1121         new[1] = (GC_word)old;
1122         old = new;
1123         collectable_count++;
1124         new = (GC_word *) GC_calloc_explicitly_typed(4, 2 * sizeof(GC_word),
1125                                                      d1);
1126         new[0] = 17;
1127         new[1] = (GC_word)old;
1128         old = new;
1129         collectable_count++;
1130         if (i & 0xff) {
1131           new = (GC_word *) GC_calloc_explicitly_typed(7, 3 * sizeof(GC_word),
1132                                                      d2);
1133         } else {
1134           new = (GC_word *) GC_calloc_explicitly_typed(1001,
1135                                                        3 * sizeof(GC_word),
1136                                                        d2);
1137           if (0 != new[0] || 0 != new[1]) {
1138             GC_printf0("Bad initialization by GC_malloc_explicitly_typed\n");
1139             FAIL;
1140           }
1141         }
1142         new[0] = 17;
1143         new[1] = (GC_word)old;
1144         old = new;
1145     }
1146     for (i = 0; i < 20000; i++) {
1147         if (new[0] != 17) {
1148             (void)GC_printf1("typed alloc failed at %lu\n",
1149                              (unsigned long)i);
1150             FAIL;
1151         }
1152         new[0] = 0;
1153         old = new;
1154         new = (GC_word *)(old[1]);
1155     }
1156     GC_gcollect();
1157     GC_noop(x);
1158 }
1159
1160 int fail_count = 0;
1161
1162 #ifndef __STDC__
1163 /*ARGSUSED*/
1164 void fail_proc1(x)
1165 GC_PTR x;
1166 {
1167     fail_count++;
1168 }
1169
1170 #else
1171
1172 /*ARGSUSED*/
1173 void fail_proc1(GC_PTR x)
1174 {
1175     fail_count++;
1176 }   
1177
1178 static void uniq(void *p, ...) {
1179   va_list a;
1180   void *q[100];
1181   int n = 0, i, j;
1182   q[n++] = p;
1183   va_start(a,p);
1184   for (;(q[n] = va_arg(a,void *));n++) ;
1185   va_end(a);
1186   for (i=0; i<n; i++)
1187     for (j=0; j<i; j++)
1188       if (q[i] == q[j]) {
1189         GC_printf0(
1190               "Apparently failed to mark form some function arguments.\n"
1191               "Perhaps GC_push_regs was configured incorrectly?\n"
1192         );
1193         FAIL;
1194       }
1195 }
1196
1197 #endif /* __STDC__ */
1198
1199 #ifdef THREADS
1200 #   define TEST_FAIL_COUNT(n) 1
1201 #else 
1202 #   define TEST_FAIL_COUNT(n) (fail_count >= (n))
1203 #endif
1204
1205 void run_one_test()
1206 {
1207     char *x;
1208 #   ifdef LINT
1209         char *y = 0;
1210 #   else
1211         char *y = (char *)(size_t)fail_proc1;
1212 #   endif
1213     DCL_LOCK_STATE;
1214     
1215 #   ifdef FIND_LEAK
1216         (void)GC_printf0(
1217                 "This test program is not designed for leak detection mode\n");
1218         (void)GC_printf0("Expect lots of problems.\n");
1219 #   endif
1220     GC_FREE(0);
1221 #   ifndef DBG_HDRS_ALL
1222       collectable_count += 3;
1223       if (GC_size(GC_malloc(7)) != 8 &&
1224           GC_size(GC_malloc(7)) != MIN_WORDS * sizeof(GC_word)
1225         || GC_size(GC_malloc(15)) != 16) {
1226             (void)GC_printf0("GC_size produced unexpected results\n");
1227             FAIL;
1228       }
1229       collectable_count += 1;
1230       if (GC_size(GC_malloc(0)) != MIN_WORDS * sizeof(GC_word)) {
1231         (void)GC_printf1("GC_malloc(0) failed: GC_size returns %ld\n",
1232                          GC_size(GC_malloc(0)));
1233             FAIL;
1234       }
1235       collectable_count += 1;
1236       if (GC_size(GC_malloc_uncollectable(0)) != MIN_WORDS * sizeof(GC_word)) {
1237         (void)GC_printf0("GC_malloc_uncollectable(0) failed\n");
1238             FAIL;
1239       }
1240       GC_is_valid_displacement_print_proc = fail_proc1;
1241       GC_is_visible_print_proc = fail_proc1;
1242       collectable_count += 1;
1243       x = GC_malloc(16);
1244       if (GC_base(x + 13) != x) {
1245         (void)GC_printf0("GC_base(heap ptr) produced incorrect result\n");
1246         FAIL;
1247       }
1248 #     ifndef PCR
1249         if (GC_base(y) != 0) {
1250           (void)GC_printf0("GC_base(fn_ptr) produced incorrect result\n");
1251           FAIL;
1252         }
1253 #     endif
1254       if (GC_same_obj(x+5, x) != x + 5) {
1255         (void)GC_printf0("GC_same_obj produced incorrect result\n");
1256         FAIL;
1257       }
1258       if (GC_is_visible(y) != y || GC_is_visible(x) != x) {
1259         (void)GC_printf0("GC_is_visible produced incorrect result\n");
1260         FAIL;
1261       }
1262       if (!TEST_FAIL_COUNT(1)) {
1263 #       if!(defined(RS6000) || defined(POWERPC) || defined(IA64)) || defined(M68K)
1264           /* ON RS6000s function pointers point to a descriptor in the  */
1265           /* data segment, so there should have been no failures.       */
1266           /* The same applies to IA64.  Something similar seems to      */
1267           /* be going on with NetBSD/M68K.                              */
1268           (void)GC_printf0("GC_is_visible produced wrong failure indication\n");
1269           FAIL;
1270 #       endif
1271       }
1272       if (GC_is_valid_displacement(y) != y
1273         || GC_is_valid_displacement(x) != x
1274         || GC_is_valid_displacement(x + 3) != x + 3) {
1275         (void)GC_printf0(
1276                 "GC_is_valid_displacement produced incorrect result\n");
1277         FAIL;
1278       }
1279 #     if defined(__STDC__) && !defined(MSWIN32) && !defined(MSWINCE)
1280         /* Harder to test under Windows without a gc.h declaration.  */
1281         {
1282           size_t i;
1283           extern void *GC_memalign();
1284
1285           GC_malloc(17);
1286           for (i = sizeof(GC_word); i < 512; i *= 2) {
1287             GC_word result = (GC_word) GC_memalign(i, 17);
1288             if (result % i != 0 || result == 0 || *(int *)result != 0) FAIL;
1289           } 
1290         }
1291 #     endif
1292 #     ifndef ALL_INTERIOR_POINTERS
1293 #      if defined(RS6000) || defined(POWERPC)
1294         if (!TEST_FAIL_COUNT(1)) {
1295 #      else
1296         if (GC_all_interior_pointers && !TEST_FAIL_COUNT(1)
1297             || !GC_all_interior_pointers && !TEST_FAIL_COUNT(2)) {
1298 #      endif
1299           (void)GC_printf0("GC_is_valid_displacement produced wrong failure indication\n");
1300           FAIL;
1301         }
1302 #     endif
1303 #   endif /* DBG_HDRS_ALL */
1304     /* Test floating point alignment */
1305    collectable_count += 2;
1306         *(double *)GC_MALLOC(sizeof(double)) = 1.0;
1307         *(double *)GC_MALLOC(sizeof(double)) = 1.0;
1308 #   ifdef GC_GCJ_SUPPORT
1309       GC_REGISTER_DISPLACEMENT(sizeof(struct fake_vtable *));
1310       GC_init_gcj_malloc(0, (void *)fake_gcj_mark_proc);
1311 #   endif
1312     /* Make sure that fn arguments are visible to the collector.        */
1313 #   ifdef __STDC__
1314       uniq(
1315         GC_malloc(12), GC_malloc(12), GC_malloc(12),
1316         (GC_gcollect(),GC_malloc(12)),
1317         GC_malloc(12), GC_malloc(12), GC_malloc(12),
1318         (GC_gcollect(),GC_malloc(12)),
1319         GC_malloc(12), GC_malloc(12), GC_malloc(12),
1320         (GC_gcollect(),GC_malloc(12)),
1321         GC_malloc(12), GC_malloc(12), GC_malloc(12),
1322         (GC_gcollect(),GC_malloc(12)),
1323         GC_malloc(12), GC_malloc(12), GC_malloc(12),
1324         (GC_gcollect(),GC_malloc(12)),
1325         (void *)0);
1326 #   endif
1327     /* Repeated list reversal test. */
1328         reverse_test();
1329 #   ifdef PRINTSTATS
1330         GC_printf0("-------------Finished reverse_test\n");
1331 #   endif
1332 #   ifndef DBG_HDRS_ALL
1333       typed_test();
1334 #     ifdef PRINTSTATS
1335         GC_printf0("-------------Finished typed_test\n");
1336 #     endif
1337 #   endif /* DBG_HDRS_ALL */
1338     tree_test();
1339     LOCK();
1340     n_tests++;
1341     UNLOCK();
1342 #   if defined(THREADS) && defined(HANDLE_FORK)
1343       if (fork() == 0) {
1344         GC_gcollect();
1345         tiny_reverse_test(0);
1346         GC_gcollect();
1347         GC_printf0("Finished a child process\n");
1348         exit(0);
1349       }
1350 #   endif
1351     /* GC_printf1("Finished %x\n", pthread_self()); */
1352 }
1353
1354 void check_heap_stats()
1355 {
1356     unsigned long max_heap_sz;
1357     register int i;
1358     int still_live;
1359     int late_finalize_count = 0;
1360     
1361 #   ifdef VERY_SMALL_CONFIG
1362     /* these are something of a guess */
1363     if (sizeof(char *) > 4) {
1364         max_heap_sz = 4500000;
1365     } else {
1366         max_heap_sz = 2800000;
1367     }
1368 #   else
1369     if (sizeof(char *) > 4) {
1370         max_heap_sz = 19000000;
1371     } else {
1372         max_heap_sz = 11000000;
1373     }
1374 #   endif
1375 #   ifndef ALIGN_DOUBLE
1376         /* We end up needing more small object pages. */
1377         max_heap_sz += 2000000;
1378 #   endif
1379 #   ifdef GC_DEBUG
1380         max_heap_sz *= 2;
1381 #       ifdef SAVE_CALL_CHAIN
1382             max_heap_sz *= 3;
1383 #           ifdef SAVE_CALL_COUNT
1384                 max_heap_sz += max_heap_sz * SAVE_CALL_COUNT/4;
1385 #           endif
1386 #       endif
1387 #   endif
1388     /* Garbage collect repeatedly so that all inaccessible objects      */
1389     /* can be finalized.                                                */
1390       while (GC_collect_a_little()) { }
1391       for (i = 0; i < 16; i++) {
1392         GC_gcollect();
1393         late_finalize_count += GC_invoke_finalizers();
1394       }
1395     (void)GC_printf1("Completed %lu tests\n", (unsigned long)n_tests);
1396     (void)GC_printf1("Allocated %lu collectable objects\n", (unsigned long)collectable_count);
1397     (void)GC_printf1("Allocated %lu uncollectable objects\n", (unsigned long)uncollectable_count);
1398     (void)GC_printf1("Allocated %lu atomic objects\n", (unsigned long)atomic_count);
1399     (void)GC_printf1("Allocated %lu stubborn objects\n", (unsigned long)stubborn_count);
1400     (void)GC_printf2("Finalized %lu/%lu objects - ",
1401                      (unsigned long)finalized_count,
1402                      (unsigned long)finalizable_count);
1403 #   ifdef FINALIZE_ON_DEMAND
1404         if (finalized_count != late_finalize_count) {
1405             (void)GC_printf0("Demand finalization error\n");
1406             FAIL;
1407         }
1408 #   endif
1409     if (finalized_count > finalizable_count
1410         || finalized_count < finalizable_count/2) {
1411         (void)GC_printf0("finalization is probably broken\n");
1412         FAIL;
1413     } else {
1414         (void)GC_printf0("finalization is probably ok\n");
1415     }
1416     still_live = 0;
1417     for (i = 0; i < MAX_FINALIZED; i++) {
1418         if (live_indicators[i] != 0) {
1419             still_live++;
1420         }
1421     }
1422     i = finalizable_count - finalized_count - still_live;
1423     if (0 != i) {
1424         (void)GC_printf2
1425             ("%lu disappearing links remain and %ld more objects were not finalized\n",
1426              (unsigned long) still_live, (long)i);
1427         if (i > 10) {
1428             GC_printf0("\tVery suspicious!\n");
1429         } else {
1430             GC_printf0("\tSlightly suspicious, but probably OK.\n");
1431         }
1432     }
1433     (void)GC_printf1("Total number of bytes allocated is %lu\n",
1434                 (unsigned long)
1435                    WORDS_TO_BYTES(GC_words_allocd + GC_words_allocd_before_gc));
1436     (void)GC_printf1("Final heap size is %lu bytes\n",
1437                      (unsigned long)GC_get_heap_size());
1438     if (WORDS_TO_BYTES(GC_words_allocd + GC_words_allocd_before_gc)
1439 #   ifdef VERY_SMALL_CONFIG
1440         < 2700000*n_tests) {
1441 #   else
1442         < 33500000*n_tests) {
1443 #   endif
1444         (void)GC_printf0("Incorrect execution - missed some allocations\n");
1445         FAIL;
1446     }
1447     if (GC_get_heap_size() > max_heap_sz*n_tests) {
1448         (void)GC_printf0("Unexpected heap growth - collector may be broken\n");
1449         FAIL;
1450     }
1451     (void)GC_printf0("Collector appears to work\n");
1452 }
1453
1454 #if defined(MACOS)
1455 void SetMinimumStack(long minSize)
1456 {
1457         long newApplLimit;
1458
1459         if (minSize > LMGetDefltStack())
1460         {
1461                 newApplLimit = (long) GetApplLimit()
1462                                 - (minSize - LMGetDefltStack());
1463                 SetApplLimit((Ptr) newApplLimit);
1464                 MaxApplZone();
1465         }
1466 }
1467
1468 #define cMinStackSpace (512L * 1024L)
1469
1470 #endif
1471
1472 #ifdef __STDC__
1473     void warn_proc(char *msg, GC_word p)
1474 #else
1475     void warn_proc(msg, p)
1476     char *msg;
1477     GC_word p;
1478 #endif
1479 {
1480     GC_printf1(msg, (unsigned long)p);
1481     /*FAIL;*/
1482 }
1483
1484
1485 #if !defined(PCR) && !defined(GC_SOLARIS_THREADS) \
1486     && !defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS) \
1487     || defined(LINT)
1488 #if defined(MSWIN32) && !defined(__MINGW32__)
1489   int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPTSTR cmd, int n)
1490 #else
1491   int main()
1492 #endif
1493 {
1494 #   if defined(DJGPP)
1495         int dummy;
1496 #   endif
1497     n_tests = 0;
1498     
1499 #   if defined(DJGPP)
1500         /* No good way to determine stack base from library; do it */
1501         /* manually on this platform.                              */
1502         GC_stackbottom = (GC_PTR)(&dummy);
1503 #   endif
1504 #   if defined(MACOS)
1505         /* Make sure we have lots and lots of stack space.      */
1506         SetMinimumStack(cMinStackSpace);
1507         /* Cheat and let stdio initialize toolbox for us.       */
1508         printf("Testing GC Macintosh port.\n");
1509 #   endif
1510     GC_INIT();  /* Only needed on a few platforms.      */
1511     (void) GC_set_warn_proc(warn_proc);
1512 #   if (defined(MPROTECT_VDB) || defined(PROC_VDB)) \
1513           && !defined(MAKE_BACK_GRAPH)
1514       GC_enable_incremental();
1515       (void) GC_printf0("Switched to incremental mode\n");
1516 #     if defined(MPROTECT_VDB)
1517         (void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
1518 #     else
1519 #       ifdef PROC_VDB
1520         (void)GC_printf0("Reading dirty bits from /proc\n");
1521 #       else
1522     (void)GC_printf0("Using DEFAULT_VDB dirty bit implementation\n");
1523 #       endif
1524 #      endif
1525 #   endif
1526     run_one_test();
1527     check_heap_stats();
1528 #   ifndef MSWINCE
1529     (void)fflush(stdout);
1530 #   endif
1531 #   ifdef LINT
1532         /* Entry points we should be testing, but aren't.                  */
1533         /* Some can be tested by defining GC_DEBUG at the top of this file */
1534         /* This is a bit SunOS4 specific.                                  */                   
1535         GC_noop(GC_expand_hp, GC_add_roots, GC_clear_roots,
1536                 GC_register_disappearing_link,
1537                 GC_register_finalizer_ignore_self,
1538                 GC_debug_register_displacement,
1539                 GC_print_obj, GC_debug_change_stubborn,
1540                 GC_debug_end_stubborn_change, GC_debug_malloc_uncollectable,
1541                 GC_debug_free, GC_debug_realloc, GC_generic_malloc_words_small,
1542                 GC_init, GC_make_closure, GC_debug_invoke_finalizer,
1543                 GC_page_was_ever_dirty, GC_is_fresh,
1544                 GC_malloc_ignore_off_page, GC_malloc_atomic_ignore_off_page,
1545                 GC_set_max_heap_size, GC_get_bytes_since_gc,
1546                 GC_get_total_bytes, GC_pre_incr, GC_post_incr);
1547 #   endif
1548 #   ifdef MSWIN32
1549       GC_win32_free_heap();
1550 #   endif
1551     return(0);
1552 }
1553 # endif
1554
1555 #if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
1556
1557 DWORD __stdcall thr_run_one_test(void *arg)
1558 {
1559   run_one_test();
1560   return 0;
1561 }
1562
1563 #ifdef MSWINCE
1564 HANDLE win_created_h;
1565 HWND win_handle;
1566
1567 LRESULT CALLBACK window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1568 {
1569   LRESULT ret = 0;
1570   switch (uMsg) {
1571     case WM_HIBERNATE:
1572       GC_printf0("Received WM_HIBERNATE, calling GC_gcollect\n");
1573       GC_gcollect();
1574       break;
1575     case WM_CLOSE:
1576       GC_printf0("Received WM_CLOSE, closing window\n");
1577       DestroyWindow(hwnd);
1578       break;
1579     case WM_DESTROY:
1580       PostQuitMessage(0);
1581       break;
1582     default:
1583       ret = DefWindowProc(hwnd, uMsg, wParam, lParam);
1584       break;
1585   }
1586   return ret;
1587 }
1588
1589 DWORD __stdcall thr_window(void *arg)
1590 {
1591   WNDCLASS win_class = {
1592     CS_NOCLOSE,
1593     window_proc,
1594     0,
1595     0,
1596     GetModuleHandle(NULL),
1597     NULL,
1598     NULL,
1599     (HBRUSH)(COLOR_APPWORKSPACE+1),
1600     NULL,
1601     L"GCtestWindow"
1602   };
1603   MSG msg;
1604
1605   if (!RegisterClass(&win_class))
1606     FAIL;
1607
1608   win_handle = CreateWindowEx(
1609     0,
1610     L"GCtestWindow",
1611     L"GCtest",
1612     0,
1613     CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1614     NULL,
1615     NULL,
1616     GetModuleHandle(NULL),
1617     NULL);
1618
1619   if (win_handle == NULL)
1620     FAIL;
1621
1622   SetEvent(win_created_h);
1623
1624   ShowWindow(win_handle, SW_SHOW);
1625   UpdateWindow(win_handle);
1626
1627   while (GetMessage(&msg, NULL, 0, 0)) {
1628     TranslateMessage(&msg);
1629     DispatchMessage(&msg);
1630   }
1631
1632   return 0;
1633 }
1634 #endif
1635
1636 #define NTEST 2
1637
1638 # ifdef MSWINCE
1639 int APIENTRY GC_WinMain(HINSTANCE instance, HINSTANCE prev, LPWSTR cmd, int n)
1640 #   else
1641 int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n)
1642 # endif
1643 {
1644 # if NTEST > 0
1645    HANDLE h[NTEST];
1646    int i;
1647 # endif
1648 # ifdef MSWINCE
1649     HANDLE win_thr_h;
1650 # endif
1651   DWORD thread_id;
1652 # if 0
1653     GC_enable_incremental();
1654 # endif
1655   GC_init();
1656   InitializeCriticalSection(&incr_cs);
1657   (void) GC_set_warn_proc(warn_proc);
1658 # ifdef MSWINCE
1659     win_created_h = CreateEvent(NULL, FALSE, FALSE, NULL);
1660     if (win_created_h == (HANDLE)NULL) {
1661       (void)GC_printf1("Event creation failed %lu\n", (unsigned long)GetLastError());
1662       FAIL;
1663     }
1664     win_thr_h = GC_CreateThread(NULL, 0, thr_window, 0, 0, &thread_id);
1665     if (win_thr_h == (HANDLE)NULL) {
1666       (void)GC_printf1("Thread creation failed %lu\n", (unsigned long)GetLastError());
1667       FAIL;
1668     }
1669     if (WaitForSingleObject(win_created_h, INFINITE) != WAIT_OBJECT_0)
1670       FAIL;
1671     CloseHandle(win_created_h);
1672 # endif
1673 # if NTEST > 0
1674    for (i = 0; i < NTEST; i++) {
1675     h[i] = GC_CreateThread(NULL, 0, thr_run_one_test, 0, 0, &thread_id);
1676     if (h[i] == (HANDLE)NULL) {
1677       (void)GC_printf1("Thread creation failed %lu\n", (unsigned long)GetLastError());
1678       FAIL;
1679     }
1680    }
1681 # endif /* NTEST > 0 */
1682   run_one_test();
1683 # if NTEST > 0
1684    for (i = 0; i < NTEST; i++) {
1685     if (WaitForSingleObject(h[i], INFINITE) != WAIT_OBJECT_0) {
1686       (void)GC_printf1("Thread wait failed %lu\n", (unsigned long)GetLastError());
1687       FAIL;
1688     }
1689    }
1690 # endif /* NTEST > 0 */
1691 # ifdef MSWINCE
1692     PostMessage(win_handle, WM_CLOSE, 0, 0);
1693     if (WaitForSingleObject(win_thr_h, INFINITE) != WAIT_OBJECT_0)
1694       FAIL;
1695 # endif
1696   check_heap_stats();
1697   return(0);
1698 }
1699
1700 #endif /* GC_WIN32_THREADS */
1701
1702
1703 #ifdef PCR
1704 int
1705 test()
1706 {
1707     PCR_Th_T * th1;
1708     PCR_Th_T * th2;
1709     int code;
1710
1711     n_tests = 0;
1712     /* GC_enable_incremental(); */
1713     (void) GC_set_warn_proc(warn_proc);
1714     th1 = PCR_Th_Fork(run_one_test, 0);
1715     th2 = PCR_Th_Fork(run_one_test, 0);
1716     run_one_test();
1717     if (PCR_Th_T_Join(th1, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
1718         != PCR_ERes_okay || code != 0) {
1719         (void)GC_printf0("Thread 1 failed\n");
1720     }
1721     if (PCR_Th_T_Join(th2, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
1722         != PCR_ERes_okay || code != 0) {
1723         (void)GC_printf0("Thread 2 failed\n");
1724     }
1725     check_heap_stats();
1726     return(0);
1727 }
1728 #endif
1729
1730 #if defined(GC_SOLARIS_THREADS) || defined(GC_PTHREADS)
1731 void * thr_run_one_test(void * arg)
1732 {
1733     run_one_test();
1734     return(0);
1735 }
1736
1737 #ifdef GC_DEBUG
1738 #  define GC_free GC_debug_free
1739 #endif
1740
1741 #if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
1742 int
1743 main()
1744 {
1745     thread_t th1;
1746     thread_t th2;
1747     int code;
1748
1749     n_tests = 0;
1750     GC_INIT();  /* Only needed if gc is dynamic library.        */
1751 #   ifndef MAKE_BACK_GRAPH
1752       GC_enable_incremental();
1753 #   endif
1754     (void) GC_set_warn_proc(warn_proc);
1755     if (thr_keycreate(&fl_key, GC_free) != 0) {
1756         (void)GC_printf1("Key creation failed %lu\n", (unsigned long)code);
1757         FAIL;
1758     }
1759     if ((code = thr_create(0, 1024*1024, thr_run_one_test, 0, 0, &th1)) != 0) {
1760         (void)GC_printf1("Thread 1 creation failed %lu\n", (unsigned long)code);
1761         FAIL;
1762     }
1763     if ((code = thr_create(0, 1024*1024, thr_run_one_test, 0, THR_NEW_LWP, &th2)) != 0) {
1764         (void)GC_printf1("Thread 2 creation failed %lu\n", (unsigned long)code);
1765         FAIL;
1766     }
1767     run_one_test();
1768     if ((code = thr_join(th1, 0, 0)) != 0) {
1769         (void)GC_printf1("Thread 1 failed %lu\n", (unsigned long)code);
1770         FAIL;
1771     }
1772     if (thr_join(th2, 0, 0) != 0) {
1773         (void)GC_printf1("Thread 2 failed %lu\n", (unsigned long)code);
1774         FAIL;
1775     }
1776     check_heap_stats();
1777     (void)fflush(stdout);
1778     return(0);
1779 }
1780 #else /* pthreads */
1781
1782 #ifndef GC_PTHREADS
1783   --> bad news
1784 #endif
1785
1786 int
1787 main()
1788 {
1789     pthread_t th1;
1790     pthread_t th2;
1791     pthread_attr_t attr;
1792     int code;
1793
1794 #   ifdef GC_IRIX_THREADS
1795         /* Force a larger stack to be preallocated      */
1796         /* Since the initial cant always grow later.    */
1797         *((volatile char *)&code - 1024*1024) = 0;      /* Require 1 Mb */
1798 #   endif /* GC_IRIX_THREADS */
1799 #   if defined(GC_HPUX_THREADS)
1800         /* Default stack size is too small, especially with the 64 bit ABI */
1801         /* Increase it.                                                    */
1802         if (pthread_default_stacksize_np(1024*1024, 0) != 0) {
1803           (void)GC_printf0("pthread_default_stacksize_np failed.\n");
1804         }
1805 #   endif       /* GC_HPUX_THREADS */
1806     GC_INIT();
1807
1808     pthread_attr_init(&attr);
1809 #   if defined(GC_IRIX_THREADS) || defined(GC_FREEBSD_THREADS) \
1810         || defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)
1811         pthread_attr_setstacksize(&attr, 1000000);
1812 #   endif
1813     n_tests = 0;
1814 #   if (defined(MPROTECT_VDB)) \
1815             && !defined(PARALLEL_MARK) &&!defined(REDIRECT_MALLOC) \
1816             && !defined(MAKE_BACK_GRAPH)
1817         GC_enable_incremental();
1818         (void) GC_printf0("Switched to incremental mode\n");
1819 #     if defined(MPROTECT_VDB)
1820         (void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
1821 #     else
1822 #       ifdef PROC_VDB
1823             (void)GC_printf0("Reading dirty bits from /proc\n");
1824 #       else
1825             (void)GC_printf0("Using DEFAULT_VDB dirty bit implementation\n");
1826 #       endif
1827 #     endif
1828 #   endif
1829     (void) GC_set_warn_proc(warn_proc);
1830     if ((code = pthread_key_create(&fl_key, 0)) != 0) {
1831         (void)GC_printf1("Key creation failed %lu\n", (unsigned long)code);
1832         FAIL;
1833     }
1834     if ((code = pthread_create(&th1, &attr, thr_run_one_test, 0)) != 0) {
1835         (void)GC_printf1("Thread 1 creation failed %lu\n", (unsigned long)code);
1836         FAIL;
1837     }
1838     if ((code = pthread_create(&th2, &attr, thr_run_one_test, 0)) != 0) {
1839         (void)GC_printf1("Thread 2 creation failed %lu\n", (unsigned long)code);
1840         FAIL;
1841     }
1842     run_one_test();
1843     if ((code = pthread_join(th1, 0)) != 0) {
1844         (void)GC_printf1("Thread 1 failed %lu\n", (unsigned long)code);
1845         FAIL;
1846     }
1847     if (pthread_join(th2, 0) != 0) {
1848         (void)GC_printf1("Thread 2 failed %lu\n", (unsigned long)code);
1849         FAIL;
1850     }
1851     check_heap_stats();
1852     (void)fflush(stdout);
1853     pthread_attr_destroy(&attr);
1854     GC_printf1("Completed %d collections\n", GC_gc_no);
1855     return(0);
1856 }
1857 #endif /* GC_PTHREADS */
1858 #endif /* GC_SOLARIS_THREADS || GC_PTHREADS */