version 1.1.1.1, 1999/12/03 07:39:10 |
version 1.3, 2000/12/01 09:26:13 |
|
|
/* An incomplete test for the garbage collector. */ |
/* An incomplete test for the garbage collector. */ |
/* Some more obscure entry points are not tested at all. */ |
/* Some more obscure entry points are not tested at all. */ |
|
|
|
# undef GC_BUILD |
|
|
# if defined(mips) && defined(SYSTYPE_BSD43) |
# if defined(mips) && defined(SYSTYPE_BSD43) |
/* MIPS RISCOS 4 */ |
/* MIPS RISCOS 4 */ |
# else |
# else |
|
|
# include <synch.h> |
# include <synch.h> |
# endif |
# endif |
|
|
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) |
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS) |
# include <pthread.h> |
# include <pthread.h> |
# endif |
# endif |
|
|
|
|
# include <process.h> |
# include <process.h> |
static CRITICAL_SECTION incr_cs; |
static CRITICAL_SECTION incr_cs; |
# endif |
# endif |
# if defined(PCR) || defined(SOLARIS_THREADS) || defined(WIN32_THREADS) |
|
# define THREADS |
|
# endif |
|
|
|
# ifdef AMIGA |
# ifdef AMIGA |
long __stack = 200000; |
long __stack = 200000; |
|
|
register sexpr r; |
register sexpr r; |
|
|
r = (sexpr) GC_MALLOC_UNCOLLECTABLE(sizeof(struct SEXPR)); |
r = (sexpr) GC_MALLOC_UNCOLLECTABLE(sizeof(struct SEXPR)); |
assert(GC_is_marked(r)); |
|
if (r == 0) { |
if (r == 0) { |
(void)GC_printf0("Out of memory\n"); |
(void)GC_printf0("Out of memory\n"); |
exit(1); |
exit(1); |
Line 160 assert(GC_is_marked(r)); |
|
Line 158 assert(GC_is_marked(r)); |
|
return(r); |
return(r); |
} |
} |
|
|
|
#ifdef GC_GCJ_SUPPORT |
|
|
|
#include "gc_mark.h" |
|
#include "dbg_mlc.h" |
|
#include "include/gc_gcj.h" |
|
|
|
/* The following struct emulates the vtable in gcj. */ |
|
/* This assumes the default value of MARK_DESCR_OFFSET. */ |
|
struct fake_vtable { |
|
void * dummy; /* class pointer in real gcj. */ |
|
size_t descr; |
|
}; |
|
|
|
struct fake_vtable gcj_class_struct1 = { 0, sizeof(struct SEXPR) |
|
+ sizeof(struct fake_vtable *) }; |
|
/* length based descriptor. */ |
|
struct fake_vtable gcj_class_struct2 = |
|
{ 0, (3l << (CPP_WORDSZ - 3)) | DS_BITMAP}; |
|
/* Bitmap based descriptor. */ |
|
|
|
struct ms_entry * fake_gcj_mark_proc(word * addr, |
|
struct ms_entry *mark_stack_ptr, |
|
struct ms_entry *mark_stack_limit, |
|
word env ) |
|
{ |
|
sexpr x; |
|
if (1 == env) { |
|
/* Object allocated with debug allocator. */ |
|
addr = (word *)USR_PTR_FROM_BASE(addr); |
|
} |
|
x = (sexpr)(addr + 1); /* Skip the vtable pointer. */ |
|
/* We could just call PUSH_CONTENTS directly here. But any real */ |
|
/* real client would try to filter out the obvious misses. */ |
|
if (0 != x -> sexpr_cdr) { |
|
PUSH_CONTENTS((ptr_t)(x -> sexpr_cdr), mark_stack_ptr, |
|
mark_stack_limit, &(x -> sexpr_cdr), exit1); |
|
} |
|
if ((ptr_t)(x -> sexpr_car) > GC_least_plausible_heap_addr) { |
|
PUSH_CONTENTS((ptr_t)(x -> sexpr_car), mark_stack_ptr, |
|
mark_stack_limit, &(x -> sexpr_car), exit2); |
|
} |
|
return(mark_stack_ptr); |
|
} |
|
|
|
sexpr gcj_cons(x, y) |
|
sexpr x; |
|
sexpr y; |
|
{ |
|
GC_word * r; |
|
sexpr result; |
|
static int count = 0; |
|
|
|
if (++count & 1) { |
|
r = (GC_word *) GC_GCJ_FAST_MALLOC(3, &gcj_class_struct1); |
|
} else { |
|
r = (GC_word *) GC_GCJ_MALLOC(sizeof(struct SEXPR) |
|
+ sizeof(struct fake_vtable*), |
|
&gcj_class_struct2); |
|
} |
|
if (r == 0) { |
|
(void)GC_printf0("Out of memory\n"); |
|
exit(1); |
|
} |
|
result = (sexpr)(r + 1); |
|
result -> sexpr_car = x; |
|
result -> sexpr_cdr = y; |
|
return(result); |
|
} |
|
#endif |
|
|
/* Return reverse(x) concatenated with y */ |
/* Return reverse(x) concatenated with y */ |
sexpr reverse1(x, y) |
sexpr reverse1(x, y) |
sexpr x, y; |
sexpr x, y; |
|
|
} |
} |
} |
} |
|
|
|
#ifdef GC_GCJ_SUPPORT |
|
/* Return reverse(x) concatenated with y */ |
|
sexpr gcj_reverse1(x, y) |
|
sexpr x, y; |
|
{ |
|
if (is_nil(x)) { |
|
return(y); |
|
} else { |
|
return( gcj_reverse1(cdr(x), gcj_cons(car(x), y)) ); |
|
} |
|
} |
|
|
|
sexpr gcj_reverse(x) |
|
sexpr x; |
|
{ |
|
return( gcj_reverse1(x, nil) ); |
|
} |
|
|
|
sexpr gcj_ints(low, up) |
|
int low, up; |
|
{ |
|
if (low > up) { |
|
return(nil); |
|
} else { |
|
return(gcj_cons(gcj_cons(INT_TO_SEXPR(low), nil), gcj_ints(low+1, up))); |
|
} |
|
} |
|
#endif /* GC_GCJ_SUPPORT */ |
|
|
/* To check uncollectable allocation we build lists with disguised cdr */ |
/* To check uncollectable allocation we build lists with disguised cdr */ |
/* pointers, and make sure they don't go away. */ |
/* pointers, and make sure they don't go away. */ |
sexpr uncollectable_ints(low, up) |
sexpr uncollectable_ints(low, up) |
|
|
} |
} |
|
|
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) \ |
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) \ |
|| defined(SOLARIS_PTHREADS) |
|| defined(SOLARIS_PTHREADS) || defined(HPUX_THREADS) |
void fork_a_thread() |
void fork_a_thread() |
{ |
{ |
pthread_t t; |
pthread_t t; |
Line 362 void reverse_test() |
|
Line 459 void reverse_test() |
|
d = uncollectable_ints(1, 100); |
d = uncollectable_ints(1, 100); |
e = uncollectable_ints(1, 1); |
e = uncollectable_ints(1, 1); |
/* Check that realloc updates object descriptors correctly */ |
/* Check that realloc updates object descriptors correctly */ |
f = (sexpr *)GC_malloc(4 * sizeof(sexpr)); |
f = (sexpr *)GC_MALLOC(4 * sizeof(sexpr)); |
f = (sexpr *)GC_realloc((GC_PTR)f, 6 * sizeof(sexpr)); |
f = (sexpr *)GC_REALLOC((GC_PTR)f, 6 * sizeof(sexpr)); |
f[5] = ints(1,17); |
f[5] = ints(1,17); |
g = (sexpr *)GC_malloc(513 * sizeof(sexpr)); |
g = (sexpr *)GC_MALLOC(513 * sizeof(sexpr)); |
g = (sexpr *)GC_realloc((GC_PTR)g, 800 * sizeof(sexpr)); |
g = (sexpr *)GC_REALLOC((GC_PTR)g, 800 * sizeof(sexpr)); |
g[799] = ints(1,18); |
g[799] = ints(1,18); |
h = (sexpr *)GC_malloc(1025 * sizeof(sexpr)); |
h = (sexpr *)GC_MALLOC(1025 * sizeof(sexpr)); |
h = (sexpr *)GC_realloc((GC_PTR)h, 2000 * sizeof(sexpr)); |
h = (sexpr *)GC_REALLOC((GC_PTR)h, 2000 * sizeof(sexpr)); |
h[1999] = ints(1,19); |
# ifdef GC_GCJ_SUPPORT |
|
h[1999] = gcj_ints(1,200); |
|
h[1999] = gcj_reverse(h[1999]); |
|
# else |
|
h[1999] = ints(1,200); |
|
# endif |
/* Try to force some collections and reuse of small list elements */ |
/* Try to force some collections and reuse of small list elements */ |
for (i = 0; i < 10; i++) { |
for (i = 0; i < 10; i++) { |
(void)ints(1, BIG); |
(void)ints(1, BIG); |
Line 415 void reverse_test() |
|
Line 517 void reverse_test() |
|
check_uncollectable_ints(d, 1, 100); |
check_uncollectable_ints(d, 1, 100); |
check_ints(f[5], 1,17); |
check_ints(f[5], 1,17); |
check_ints(g[799], 1,18); |
check_ints(g[799], 1,18); |
check_ints(h[1999], 1,19); |
# ifdef GC_GCJ_SUPPORT |
|
h[1999] = gcj_reverse(h[1999]); |
|
# endif |
|
check_ints(h[1999], 1,200); |
# ifndef THREADS |
# ifndef THREADS |
a = 0; |
a = 0; |
# endif |
# endif |
Line 453 VOLATILE int dropped_something = 0; |
|
Line 558 VOLATILE int dropped_something = 0; |
|
static mutex_t incr_lock; |
static mutex_t incr_lock; |
mutex_lock(&incr_lock); |
mutex_lock(&incr_lock); |
# endif |
# endif |
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) |
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS) |
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER; |
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER; |
pthread_mutex_lock(&incr_lock); |
pthread_mutex_lock(&incr_lock); |
# endif |
# endif |
Line 471 VOLATILE int dropped_something = 0; |
|
Line 576 VOLATILE int dropped_something = 0; |
|
# ifdef SOLARIS_THREADS |
# ifdef SOLARIS_THREADS |
mutex_unlock(&incr_lock); |
mutex_unlock(&incr_lock); |
# endif |
# endif |
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) |
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS) |
pthread_mutex_unlock(&incr_lock); |
pthread_mutex_unlock(&incr_lock); |
# endif |
# endif |
# ifdef WIN32_THREADS |
# ifdef WIN32_THREADS |
|
|
static mutex_t incr_lock; |
static mutex_t incr_lock; |
mutex_lock(&incr_lock); |
mutex_lock(&incr_lock); |
# endif |
# endif |
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) |
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) \ |
|
|| defined(HPUX_THREADS) |
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER; |
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER; |
pthread_mutex_lock(&incr_lock); |
pthread_mutex_lock(&incr_lock); |
# endif |
# endif |
|
|
# ifdef SOLARIS_THREADS |
# ifdef SOLARIS_THREADS |
mutex_unlock(&incr_lock); |
mutex_unlock(&incr_lock); |
# endif |
# endif |
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) |
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) \ |
|
|| defined(HPUX_THREADS) |
pthread_mutex_unlock(&incr_lock); |
pthread_mutex_unlock(&incr_lock); |
# endif |
# endif |
# ifdef WIN32_THREADS |
# ifdef WIN32_THREADS |
Line 610 thread_key_t fl_key; |
|
Line 717 thread_key_t fl_key; |
|
|
|
void * alloc8bytes() |
void * alloc8bytes() |
{ |
{ |
# ifdef SMALL_CONFIG |
# if defined(SMALL_CONFIG) || defined(GC_DEBUG) |
return(GC_malloc(8)); |
return(GC_MALLOC(8)); |
# else |
# else |
void ** my_free_list_ptr; |
void ** my_free_list_ptr; |
void * my_free_list; |
void * my_free_list; |
Line 644 void * alloc8bytes() |
|
Line 751 void * alloc8bytes() |
|
#else |
#else |
|
|
# if defined(_SOLARIS_PTHREADS) || defined(IRIX_THREADS) \ |
# if defined(_SOLARIS_PTHREADS) || defined(IRIX_THREADS) \ |
|| defined(LINUX_THREADS) |
|| defined(LINUX_THREADS) || defined(HPUX_THREADS) |
pthread_key_t fl_key; |
pthread_key_t fl_key; |
|
|
void * alloc8bytes() |
void * alloc8bytes() |
Line 760 void typed_test() |
|
Line 867 void typed_test() |
|
old = 0; |
old = 0; |
for (i = 0; i < 4000; i++) { |
for (i = 0; i < 4000; i++) { |
new = (GC_word *) GC_malloc_explicitly_typed(4 * sizeof(GC_word), d1); |
new = (GC_word *) GC_malloc_explicitly_typed(4 * sizeof(GC_word), d1); |
|
if (0 != new[0] || 0 != new[1]) { |
|
GC_printf0("Bad initialization by GC_malloc_explicitly_typed\n"); |
|
FAIL; |
|
} |
new[0] = 17; |
new[0] = 17; |
new[1] = (GC_word)old; |
new[1] = (GC_word)old; |
old = new; |
old = new; |
Line 783 void typed_test() |
|
Line 894 void typed_test() |
|
new = (GC_word *) GC_calloc_explicitly_typed(1001, |
new = (GC_word *) GC_calloc_explicitly_typed(1001, |
3 * sizeof(GC_word), |
3 * sizeof(GC_word), |
d2); |
d2); |
|
if (0 != new[0] || 0 != new[1]) { |
|
GC_printf0("Bad initialization by GC_malloc_explicitly_typed\n"); |
|
FAIL; |
|
} |
} |
} |
new[0] = 17; |
new[0] = 17; |
new[1] = (GC_word)old; |
new[1] = (GC_word)old; |
Line 857 void run_one_test() |
|
Line 972 void run_one_test() |
|
(void)GC_printf0("GC_malloc_uncollectable(0) failed\n"); |
(void)GC_printf0("GC_malloc_uncollectable(0) failed\n"); |
FAIL; |
FAIL; |
} |
} |
|
GC_FREE(0); |
GC_is_valid_displacement_print_proc = fail_proc1; |
GC_is_valid_displacement_print_proc = fail_proc1; |
GC_is_visible_print_proc = fail_proc1; |
GC_is_visible_print_proc = fail_proc1; |
x = GC_malloc(16); |
x = GC_malloc(16); |
Line 879 void run_one_test() |
|
Line 995 void run_one_test() |
|
FAIL; |
FAIL; |
} |
} |
if (!TEST_FAIL_COUNT(1)) { |
if (!TEST_FAIL_COUNT(1)) { |
# if!(defined(RS6000) || defined(POWERPC)) |
# if!(defined(RS6000) || defined(POWERPC) || defined(IA64)) |
/* ON RS6000s function pointers point to a descriptor in the */ |
/* ON RS6000s function pointers point to a descriptor in the */ |
/* data segment, so there should have been no failures. */ |
/* data segment, so there should have been no failures. */ |
(void)GC_printf0("GC_is_visible produced wrong failure indication\n"); |
(void)GC_printf0("GC_is_visible produced wrong failure indication\n"); |
Line 906 void run_one_test() |
|
Line 1022 void run_one_test() |
|
/* Test floating point alignment */ |
/* Test floating point alignment */ |
*(double *)GC_MALLOC(sizeof(double)) = 1.0; |
*(double *)GC_MALLOC(sizeof(double)) = 1.0; |
*(double *)GC_MALLOC(sizeof(double)) = 1.0; |
*(double *)GC_MALLOC(sizeof(double)) = 1.0; |
|
# ifdef GC_GCJ_SUPPORT |
|
GC_REGISTER_DISPLACEMENT(sizeof(struct fake_vtable *)); |
|
GC_init_gcj_malloc(0, (void *)fake_gcj_mark_proc); |
|
# endif |
/* Repeated list reversal test. */ |
/* Repeated list reversal test. */ |
reverse_test(); |
reverse_test(); |
# ifdef PRINTSTATS |
# ifdef PRINTSTATS |
Line 1030 void SetMinimumStack(long minSize) |
|
Line 1150 void SetMinimumStack(long minSize) |
|
|
|
|
|
#if !defined(PCR) && !defined(SOLARIS_THREADS) && !defined(WIN32_THREADS) \ |
#if !defined(PCR) && !defined(SOLARIS_THREADS) && !defined(WIN32_THREADS) \ |
&& !defined(IRIX_THREADS) && !defined(LINUX_THREADS) || defined(LINT) |
&& !defined(IRIX_THREADS) && !defined(LINUX_THREADS) \ |
#ifdef MSWIN32 |
&& !defined(HPUX_THREADS) || defined(LINT) |
|
#if defined(MSWIN32) && !defined(__MINGW32__) |
int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n) |
int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n) |
#else |
#else |
int main() |
int main() |
Line 1113 int APIENTRY WinMain(HINSTANCE instance, HINSTANCE pre |
|
Line 1234 int APIENTRY WinMain(HINSTANCE instance, HINSTANCE pre |
|
# endif |
# endif |
InitializeCriticalSection(&incr_cs); |
InitializeCriticalSection(&incr_cs); |
(void) GC_set_warn_proc(warn_proc); |
(void) GC_set_warn_proc(warn_proc); |
for (i = 0; i < NTEST; i++) { |
# if NTEST > 0 |
|
for (i = 0; i < NTEST; i++) { |
h[i] = (HANDLE)_beginthreadex(NULL, 0, thr_run_one_test, 0, 0, &thread_id); |
h[i] = (HANDLE)_beginthreadex(NULL, 0, thr_run_one_test, 0, 0, &thread_id); |
if (h[i] == (HANDLE)-1) { |
if (h[i] == (HANDLE)-1) { |
(void)GC_printf1("Thread creation failed %lu\n", (unsigned long)GetLastError()); |
(void)GC_printf1("Thread creation failed %lu\n", (unsigned long)GetLastError()); |
FAIL; |
FAIL; |
} |
} |
} |
} |
|
# endif /* NTEST > 0 */ |
run_one_test(); |
run_one_test(); |
for (i = 0; i < NTEST; i++) |
# if NTEST > 0 |
|
for (i = 0; i < NTEST; i++) { |
if (WaitForSingleObject(h[i], INFINITE) != WAIT_OBJECT_0) { |
if (WaitForSingleObject(h[i], INFINITE) != WAIT_OBJECT_0) { |
(void)GC_printf1("Thread wait failed %lu\n", (unsigned long)GetLastError()); |
(void)GC_printf1("Thread wait failed %lu\n", (unsigned long)GetLastError()); |
FAIL; |
FAIL; |
} |
} |
|
} |
|
# endif /* NTEST > 0 */ |
check_heap_stats(); |
check_heap_stats(); |
(void)fflush(stdout); |
(void)fflush(stdout); |
return(0); |
return(0); |
|
|
} |
} |
#endif |
#endif |
|
|
#if defined(SOLARIS_THREADS) || defined(IRIX_THREADS) || defined(LINUX_THREADS) |
#if defined(SOLARIS_THREADS) || defined(IRIX_THREADS) \ |
|
|| defined(HPUX_THREADS) || defined(LINUX_THREADS) |
void * thr_run_one_test(void * arg) |
void * thr_run_one_test(void * arg) |
{ |
{ |
run_one_test(); |
run_one_test(); |
|
|
*((volatile char *)&code - 1024*1024) = 0; /* Require 1 Mb */ |
*((volatile char *)&code - 1024*1024) = 0; /* Require 1 Mb */ |
# endif /* IRIX_THREADS */ |
# endif /* IRIX_THREADS */ |
pthread_attr_init(&attr); |
pthread_attr_init(&attr); |
# ifdef IRIX_THREADS |
# if defined(IRIX_THREADS) || defined(HPUX_THREADS) |
pthread_attr_setstacksize(&attr, 1000000); |
pthread_attr_setstacksize(&attr, 1000000); |
# endif |
# endif |
n_tests = 0; |
n_tests = 0; |
|
|
(void) GC_printf0("Emulating dirty bits with mprotect/signals\n"); |
(void) GC_printf0("Emulating dirty bits with mprotect/signals\n"); |
# endif |
# endif |
(void) GC_set_warn_proc(warn_proc); |
(void) GC_set_warn_proc(warn_proc); |
if (pthread_key_create(&fl_key, 0) != 0) { |
if ((code = pthread_key_create(&fl_key, 0)) != 0) { |
(void)GC_printf1("Key creation failed %lu\n", (unsigned long)code); |
(void)GC_printf1("Key creation failed %lu\n", (unsigned long)code); |
FAIL; |
FAIL; |
} |
} |
|
|
return(0); |
return(0); |
} |
} |
#endif /* pthreads */ |
#endif /* pthreads */ |
#endif /* SOLARIS_THREADS || IRIX_THREADS || LINUX_THREADS */ |
#endif /* SOLARIS_THREADS || IRIX_THREADS || LINUX_THREADS || HPUX_THREADS */ |