diff options
Diffstat (limited to 'test.c')
-rw-r--r-- | test.c | 306 |
1 files changed, 256 insertions, 50 deletions
@@ -5,14 +5,21 @@ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. * - * Permission is hereby granted to copy this garbage collector for any purpose, - * provided the above notices are retained on all copies. + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. */ -/* Boehm, May 6, 1994 3:32 pm PDT */ +/* Boehm, September 21, 1995 5:43 pm PDT */ /* An incomplete test for the garbage collector. */ /* Some more obscure entry points are not tested at all. */ -# include <stdlib.h> +# if defined(mips) && defined(SYSTYPE_BSD43) + /* MIPS RISCOS 4 */ +# else +# include <stdlib.h> +# endif # include <stdio.h> # include "gc.h" # include "gc_typed.h" @@ -54,17 +61,15 @@ struct SEXPR { struct SEXPR * sexpr_cdr; }; -# ifdef __STDC__ - typedef void * void_star; -# else - typedef char * void_star; -# endif typedef struct SEXPR * sexpr; +# define INT_TO_SEXPR(x) ((sexpr)(unsigned long)(x)) + extern sexpr cons(); -# define nil ((sexpr) 0) +# undef nil +# define nil (INT_TO_SEXPR(0)) # define car(x) ((x) -> sexpr_car) # define cdr(x) ((x) -> sexpr_cdr) # define is_nil(x) ((x) == nil) @@ -139,7 +144,7 @@ sexpr y; exit(1); } r -> sexpr_car = x; - r -> sexpr_cdr = (sexpr) (~(unsigned long)y); + r -> sexpr_cdr = (sexpr)(~(unsigned long)y); return(r); } @@ -166,7 +171,7 @@ int low, up; if (low > up) { return(nil); } else { - return(small_cons(small_cons((sexpr)low, (sexpr)0), ints(low+1, up))); + return(small_cons(small_cons(INT_TO_SEXPR(low), nil), ints(low+1, up))); } } @@ -178,7 +183,7 @@ int low, up; if (low > up) { return(nil); } else { - return(small_cons_uncollectable(small_cons((sexpr)low, (sexpr)0), + return(small_cons_uncollectable(small_cons(INT_TO_SEXPR(low), nil), uncollectable_ints(low+1, up))); } } @@ -187,15 +192,15 @@ void check_ints(list, low, up) sexpr list; int low, up; { - if ((int)(car(car(list))) != low) { + if ((int)(GC_word)(car(car(list))) != low) { (void)GC_printf0( "List reversal produced incorrect list - collector is broken\n"); - exit(1); + FAIL; } if (low == up) { if (cdr(list) != nil) { (void)GC_printf0("List too long - collector is broken\n"); - exit(1); + FAIL; } } else { check_ints(cdr(list), low+1, up); @@ -208,15 +213,15 @@ void check_uncollectable_ints(list, low, up) sexpr list; int low, up; { - if ((int)(car(car(list))) != low) { + if ((int)(GC_word)(car(car(list))) != low) { (void)GC_printf0( "Uncollectable list corrupted - collector is broken\n"); - exit(1); + FAIL; } if (low == up) { if (UNCOLLECTABLE_CDR(list) != nil) { (void)GC_printf0("Uncollectable ist too long - collector is broken\n"); - exit(1); + FAIL; } } else { check_uncollectable_ints(UNCOLLECTABLE_CDR(list), low+1, up); @@ -258,40 +263,67 @@ void reverse_test() sexpr c; sexpr d; sexpr e; -# if defined(MSWIN32) + sexpr *f, *g, *h; +# if defined(MSWIN32) || defined(MACOS) /* Win32S only allows 128K stacks */ # define BIG 1000 # else -# define BIG 4500 +# if defined PCR + /* PCR default stack is 100K. Stack frames are up to 120 bytes. */ +# define BIG 700 +# else +# define BIG 4500 +# endif # endif + A.dummy = 17; a = ints(1, 49); b = ints(1, 50); c = ints(1, BIG); d = uncollectable_ints(1, 100); e = uncollectable_ints(1, 1); + /* Check that realloc updates object descriptors correctly */ + f = (sexpr *)GC_malloc(4 * sizeof(sexpr)); + f = (sexpr *)GC_realloc((GC_PTR)f, 6 * sizeof(sexpr)); + f[5] = ints(1,17); + g = (sexpr *)GC_malloc(513 * sizeof(sexpr)); + g = (sexpr *)GC_realloc((GC_PTR)g, 800 * sizeof(sexpr)); + g[799] = ints(1,18); + h = (sexpr *)GC_malloc(1025 * sizeof(sexpr)); + h = (sexpr *)GC_realloc((GC_PTR)h, 2000 * sizeof(sexpr)); + h[1999] = ints(1,19); + /* Try to force some collections and reuse of small list elements */ + for (i = 0; i < 10; i++) { + (void)ints(1, BIG); + } /* Superficially test interior pointer recognition on stack */ c = (sexpr)((char *)c + sizeof(char *)); d = (sexpr)((char *)d + sizeof(char *)); + # ifdef __STDC__ GC_FREE((void *)e); # else GC_FREE((char *)e); # endif + check_ints(b,1,50); + check_ints(a,1,49); for (i = 0; i < 50; i++) { + check_ints(b,1,50); b = reverse(reverse(b)); } check_ints(b,1,50); + check_ints(a,1,49); for (i = 0; i < 60; i++) { /* This maintains the invariant that a always points to a list of */ - /* 49 integers. Thus this is thread safe without locks. */ + /* 49 integers. Thus this is thread safe without locks, */ + /* assuming atomic pointer assignments. */ a = reverse(reverse(a)); # if !defined(AT_END) && !defined(THREADS) /* This is not thread safe, since realloc explicitly deallocates */ if (i & 1) { - a = (sexpr)GC_REALLOC((void_star)a, 500); + a = (sexpr)GC_REALLOC((GC_PTR)a, 500); } else { - a = (sexpr)GC_REALLOC((void_star)a, 8200); + a = (sexpr)GC_REALLOC((GC_PTR)a, 8200); } # endif } @@ -301,7 +333,13 @@ void reverse_test() d = (sexpr)((char *)d - sizeof(char *)); check_ints(c,1,BIG); check_uncollectable_ints(d, 1, 100); - a = b = c = 0; + check_ints(f[5], 1,17); + check_ints(g[799], 1,18); + check_ints(h[1999], 1,19); +# ifndef THREADS + a = 0; +# endif + b = c = 0; } /* @@ -316,7 +354,7 @@ typedef struct treenode { int finalizable_count = 0; int finalized_count = 0; -int dropped_something = 0; +VOLATILE int dropped_something = 0; # ifdef __STDC__ void finalizer(void * obj, void * client_data) @@ -335,7 +373,7 @@ int dropped_something = 0; static mutex_t incr_lock; mutex_lock(&incr_lock); # endif - if ((int)client_data != t -> level) { + if ((int)(GC_word)client_data != t -> level) { (void)GC_printf0("Wrong finalization data - collector is broken\n"); FAIL; } @@ -351,7 +389,14 @@ int dropped_something = 0; size_t counter = 0; # define MAX_FINALIZED 8000 -GC_FAR GC_word live_indicators[MAX_FINALIZED] = {0}; + +# if !defined(MACOS) + GC_FAR GC_word live_indicators[MAX_FINALIZED] = {0}; +#else + /* Too big for THINK_C. have to allocate it dynamically. */ + GC_word *live_indicators = 0; +#endif + int live_indicators_count = 0; tn * mktree(n) @@ -359,6 +404,16 @@ int n; { tn * result = (tn *)GC_MALLOC(sizeof(tn)); +#if defined(MACOS) + /* get around static data limitations. */ + if (!live_indicators) + live_indicators = + (GC_word*)NewPtrClear(MAX_FINALIZED * sizeof(GC_word)); + if (!live_indicators) { + (void)GC_printf0("Out of memory\n"); + exit(1); + } +#endif if (n == 0) return(0); if (result == 0) { (void)GC_printf0("Out of memory\n"); @@ -395,24 +450,28 @@ int n; # endif } - GC_REGISTER_FINALIZER((void_star)result, finalizer, (void_star)n, - (GC_finalization_proc *)0, (void_star *)0); + GC_REGISTER_FINALIZER((GC_PTR)result, finalizer, (GC_PTR)(GC_word)n, + (GC_finalization_proc *)0, (GC_PTR *)0); + if (my_index >= MAX_FINALIZED) { + GC_printf0("live_indicators overflowed\n"); + FAIL; + } live_indicators[my_index] = 13; - if (GC_general_register_disappearing_link( - (void_star *)(&(live_indicators[my_index])), - (void_star)result) != 0) { + if (GC_GENERAL_REGISTER_DISAPPEARING_LINK( + (GC_PTR *)(&(live_indicators[my_index])), + (GC_PTR)result) != 0) { GC_printf0("GC_general_register_disappearing_link failed\n"); FAIL; } if (GC_unregister_disappearing_link( - (void_star *) + (GC_PTR *) (&(live_indicators[my_index]))) == 0) { GC_printf0("GC_unregister_disappearing_link failed\n"); FAIL; } - if (GC_general_register_disappearing_link( - (void_star *)(&(live_indicators[my_index])), - (void_star)result) != 0) { + if (GC_GENERAL_REGISTER_DISAPPEARING_LINK( + (GC_PTR *)(&(live_indicators[my_index])), + (GC_PTR)result) != 0) { GC_printf0("GC_general_register_disappearing_link failed 2\n"); FAIL; } @@ -489,22 +548,29 @@ int n; } } +# if defined(THREADS) && defined(GC_DEBUG) +# define TREE_HEIGHT 15 +# else +# define TREE_HEIGHT 16 +# endif void tree_test() { tn * root; register int i; - root = mktree(16); + root = mktree(TREE_HEIGHT); alloc_small(5000000); - chktree(root, 16); + chktree(root, TREE_HEIGHT); if (finalized_count && ! dropped_something) { (void)GC_printf0("Premature finalization - collector is broken\n"); FAIL; } dropped_something = 1; - root = mktree(16); - chktree(root, 16); - for (i = 16; i >= 0; i--) { + GC_noop(root); /* Root needs to remain live until */ + /* dropped_something is set. */ + root = mktree(TREE_HEIGHT); + chktree(root, TREE_HEIGHT); + for (i = TREE_HEIGHT; i >= 0; i--) { root = mktree(i); chktree(root, i); } @@ -571,18 +637,105 @@ void typed_test() } } +int fail_count = 0; + +/*ARGSUSED*/ +void fail_proc(x) +ptr_t x; +{ + fail_count++; +} + +extern void (*GC_is_valid_displacement_print_proc)(); + +extern void (*GC_is_visible_print_proc)(); + +#ifdef THREADS +# define TEST_FAIL_COUNT(n) 1 +#else +# define TEST_FAIL_COUNT(n) (fail_count >= (n)) +#endif + void run_one_test() { + char *x; +# ifdef LINT + char *y = 0; +# else + char *y = (char *)fail_proc; +# endif DCL_LOCK_STATE; -# ifndef GC_DEBUG - if (GC_size(GC_MALLOC(7)) != 8 - || GC_size(GC_MALLOC(15)) != 16) { +# ifdef FIND_LEAK + (void)GC_printf0( + "This test program is not designed for leak detection mode\n"); + (void)GC_printf0("Expect lots of problems.\n"); +# endif + if (GC_size(GC_malloc(7)) != 8 + || GC_size(GC_malloc(15)) != 16) { (void)GC_printf0("GC_size produced unexpected results\n"); FAIL; - } + } + if (GC_size(GC_malloc(0)) != 4 && GC_size(GC_malloc(0)) != 8) { + (void)GC_printf0("GC_malloc(0) failed\n"); + FAIL; + } + if (GC_size(GC_malloc_uncollectable(0)) != 4 + && GC_size(GC_malloc_uncollectable(0)) != 8) { + (void)GC_printf0("GC_malloc_uncollectable(0) failed\n"); + FAIL; + } + GC_is_valid_displacement_print_proc = fail_proc; + GC_is_visible_print_proc = fail_proc; + x = GC_malloc(16); + if (GC_base(x + 13) != x) { + (void)GC_printf0("GC_base(heap ptr) produced incorrect result\n"); + FAIL; + } +# ifndef PCR + if (GC_base(y) != 0) { + (void)GC_printf0("GC_base(fn_ptr) produced incorrect result\n"); + FAIL; + } # endif - reverse_test(); + if (GC_same_obj(x+5, x) != x + 5) { + (void)GC_printf0("GC_same_obj produced incorrect result\n"); + FAIL; + } + if (GC_is_visible(y) != y || GC_is_visible(x) != x) { + (void)GC_printf0("GC_is_visible produced incorrect result\n"); + FAIL; + } + if (!TEST_FAIL_COUNT(1)) { +# ifndef RS6000 + /* ON RS6000s function pointers point to a descriptor in the */ + /* data segment, so there should have been no failures. */ + (void)GC_printf0("GC_is_visible produced wrong failure indication\n"); + FAIL; +# endif + } + if (GC_is_valid_displacement(y) != y + || GC_is_valid_displacement(x) != x + || GC_is_valid_displacement(x + 3) != x + 3) { + (void)GC_printf0( + "GC_is_valid_displacement produced incorrect result\n"); + FAIL; + } +# ifndef ALL_INTERIOR_POINTERS +# ifdef RS6000 + if (!TEST_FAIL_COUNT(1)) { +# else + if (!TEST_FAIL_COUNT(2)) { +# endif + (void)GC_printf0("GC_is_valid_displacement produced wrong failure indication\n"); + FAIL; + } +# endif + /* Test floating point alignment */ + *(double *)GC_MALLOC(sizeof(double)) = 1.0; + *(double *)GC_MALLOC(sizeof(double)) = 1.0; + /* Repeated list reversal test. */ + reverse_test(); # ifdef PRINTSTATS GC_printf0("-------------Finished reverse_test\n"); # endif @@ -606,7 +759,7 @@ void check_heap_stats() if (sizeof(char *) > 4) { max_heap_sz = 13000000; } else { - max_heap_sz = 10000000; + max_heap_sz = 11000000; } # ifdef GC_DEBUG max_heap_sz *= 2; @@ -616,6 +769,7 @@ void check_heap_stats() # endif /* Garbage collect repeatedly so that all inaccessible objects */ /* can be finalized. */ + while (GC_collect_a_little()) { } for (i = 0; i < 16; i++) { GC_gcollect(); } @@ -659,6 +813,37 @@ void check_heap_stats() (void)GC_printf0("Collector appears to work\n"); } +#if defined(MACOS) +void SetMinimumStack(long minSize) +{ + long newApplLimit; + + if (minSize > LMGetDefltStack()) + { + newApplLimit = (long) GetApplLimit() + - (minSize - LMGetDefltStack()); + SetApplLimit((Ptr) newApplLimit); + MaxApplZone(); + } +} + +#define cMinStackSpace (512L * 1024L) + +#endif + +#ifdef __STDC__ + void warn_proc(char *msg, GC_word p) +#else + void warn_proc(msg, p) + char *msg; + GC_word p; +#endif +{ + GC_printf1(msg, (unsigned long)p); + FAIL; +} + + #if !defined(PCR) && !defined(SOLARIS_THREADS) || defined(LINT) #ifdef MSWIN32 int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n) @@ -667,6 +852,15 @@ void check_heap_stats() #endif { n_tests = 0; + +# if defined(MACOS) + /* Make sure we have lots and lots of stack space. */ + SetMinimumStack(cMinStackSpace); + /* Cheat and let stdio initialize toolbox for us. */ + printf("Testing GC Macintosh port.\n"); +# endif + GC_INIT(); /* Only needed if gc is dynamic library. */ + (void) GC_set_warn_proc(warn_proc); # if defined(MPROTECT_VDB) || defined(PROC_VDB) GC_enable_incremental(); (void) GC_printf0("Switched to incremental mode\n"); @@ -685,12 +879,16 @@ void check_heap_stats() /* This is a bit SunOS4 specific. */ GC_noop(GC_expand_hp, GC_add_roots, GC_clear_roots, GC_register_disappearing_link, + GC_register_finalizer_ignore_self, + GC_debug_register_displacement, GC_print_obj, GC_debug_change_stubborn, GC_debug_end_stubborn_change, GC_debug_malloc_uncollectable, GC_debug_free, GC_debug_realloc, GC_generic_malloc_words_small, GC_init, GC_make_closure, GC_debug_invoke_finalizer, GC_page_was_ever_dirty, GC_is_fresh, - GC_malloc_ignore_off_page); + GC_malloc_ignore_off_page, GC_malloc_atomic_ignore_off_page, + GC_set_max_heap_size, GC_get_bytes_since_gc, + GC_pre_incr, GC_post_incr); # endif return(0); } @@ -704,7 +902,8 @@ test() int code; n_tests = 0; - GC_enable_incremental(); + /* GC_enable_incremental(); */ + (void) GC_set_warn_proc(warn_proc); th1 = PCR_Th_Fork(run_one_test, 0); th2 = PCR_Th_Fork(run_one_test, 0); run_one_test(); @@ -728,6 +927,11 @@ void * thr_run_one_test(void * arg) run_one_test(); return(0); } + +#ifdef GC_DEBUG +# define GC_free GC_debug_free +#endif + main() { thread_t th1; @@ -735,7 +939,9 @@ main() int code; n_tests = 0; + GC_INIT(); /* Only needed if gc is dynamic library. */ GC_enable_incremental(); + (void) GC_set_warn_proc(warn_proc); if (thr_keycreate(&fl_key, GC_free) != 0) { (void)GC_printf1("Key creation failed %lu\n", (unsigned long)code); FAIL; |