version 1.1, 1999/12/03 07:39:09 |
version 1.2, 2000/04/10 08:31:31 |
|
|
/* |
/* |
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers |
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers |
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. |
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. |
|
* Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. |
|
* Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. |
* |
* |
|
* |
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED |
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED |
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK. |
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK. |
* |
* |
Line 64 typedef char * ptr_t; /* A generic pointer to which we |
|
Line 67 typedef char * ptr_t; /* A generic pointer to which we |
|
# include <stddef.h> |
# include <stddef.h> |
# endif |
# endif |
# define VOLATILE volatile |
# define VOLATILE volatile |
# define CONST const |
|
#else |
#else |
# ifdef MSWIN32 |
# ifdef MSWIN32 |
# include <stdlib.h> |
# include <stdlib.h> |
# endif |
# endif |
# define VOLATILE |
# define VOLATILE |
# define CONST |
|
#endif |
#endif |
|
|
|
#define CONST GC_CONST |
|
|
#if 0 /* was once defined for AMIGA */ |
#if 0 /* was once defined for AMIGA */ |
# define GC_FAR __far |
# define GC_FAR __far |
#else |
#else |
Line 436 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 439 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
# endif |
# endif |
# ifdef LINUX_THREADS |
# ifdef LINUX_THREADS |
# include <pthread.h> |
# include <pthread.h> |
# ifdef __i386__ |
# if defined(I386) |
inline static int GC_test_and_set(volatile unsigned int *addr) { |
inline static int GC_test_and_set(volatile unsigned int *addr) { |
int oldval; |
int oldval; |
/* Note: the "xchg" instruction does not need a "lock" prefix */ |
/* Note: the "xchg" instruction does not need a "lock" prefix */ |
Line 446 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 449 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
return oldval; |
return oldval; |
} |
} |
# else |
# else |
-- > Need implementation of GC_test_and_set() |
# if defined(POWERPC) |
|
inline static int GC_test_and_set(volatile unsigned int *addr) { |
|
int oldval; |
|
int temp = 1; // locked value |
|
|
|
__asm__ __volatile__( |
|
"1:\tlwarx %0,0,%3\n" // load and reserve |
|
"\tcmpwi %0, 0\n" // if load is |
|
"\tbne 2f\n" // non-zero, return already set |
|
"\tstwcx. %2,0,%1\n" // else store conditional |
|
"\tbne- 1b\n" // retry if lost reservation |
|
"2:\t\n" // oldval is zero if we set |
|
: "=&r"(oldval), "=p"(addr) |
|
: "r"(temp), "1"(addr) |
|
: "memory"); |
|
return (int)oldval; |
|
} |
|
# else |
|
# ifdef ALPHA |
|
inline static int GC_test_and_set(volatile unsigned int * |
|
addr) |
|
{ |
|
unsigned long oldvalue; |
|
unsigned long temp; |
|
|
|
__asm__ __volatile__( |
|
"1: ldl_l %0,%1\n" |
|
" and %0,%3,%2\n" |
|
" bne %2,2f\n" |
|
" xor %0,%3,%0\n" |
|
" stl_c %0,%1\n" |
|
" beq %0,3f\n" |
|
" mb\n" |
|
"2:\n" |
|
".section .text2,\"ax\"\n" |
|
"3: br 1b\n" |
|
".previous" |
|
:"=&r" (temp), "=m" (*addr), "=&r" |
|
(oldvalue) |
|
:"Ir" (1), "m" (*addr)); |
|
|
|
return oldvalue; |
|
} |
|
# else |
|
-- > Need implementation of GC_test_and_set() |
|
# endif |
|
# endif |
# endif |
# endif |
# define GC_clear(addr) (*(addr) = 0) |
inline static void GC_clear(volatile unsigned int *addr) { |
|
*(addr) = 0; |
|
} |
|
|
extern volatile unsigned int GC_allocate_lock; |
extern volatile unsigned int GC_allocate_lock; |
/* This is not a mutex because mutexes that obey the (optional) */ |
/* This is not a mutex because mutexes that obey the (optional) */ |
Line 462 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 513 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
# define NO_THREAD (pthread_t)(-1) |
# define NO_THREAD (pthread_t)(-1) |
# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD |
# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD |
# define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self())) |
# define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self())) |
# ifdef UNDEFINED |
# define LOCK() \ |
# define LOCK() pthread_mutex_lock(&GC_allocate_ml) |
|
# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml) |
|
# else |
|
# define LOCK() \ |
|
{ if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); } |
{ if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); } |
# define UNLOCK() \ |
# define UNLOCK() \ |
GC_clear(&GC_allocate_lock) |
GC_clear(&GC_allocate_lock) |
# endif |
|
extern GC_bool GC_collecting; |
extern GC_bool GC_collecting; |
# define ENTER_GC() \ |
# define ENTER_GC() \ |
{ \ |
{ \ |
Line 478 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 524 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
} |
} |
# define EXIT_GC() GC_collecting = 0; |
# define EXIT_GC() GC_collecting = 0; |
# endif /* LINUX_THREADS */ |
# endif /* LINUX_THREADS */ |
# if defined(IRIX_THREADS) || defined(IRIX_JDK_THREADS) |
# if defined(HPUX_THREADS) |
# include <pthread.h> |
# include <pthread.h> |
# include <mutex.h> |
extern pthread_mutex_t GC_allocate_ml; |
|
# define LOCK() pthread_mutex_lock(&GC_allocate_ml) |
|
# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml) |
|
# endif |
|
# if defined(IRIX_THREADS) || defined(IRIX_JDK_THREADS) |
|
/* This may also eventually be appropriate for HPUX_THREADS */ |
|
# include <pthread.h> |
|
# ifndef HPUX_THREADS |
|
/* This probably should never be included, but I can't test */ |
|
/* on Irix anymore. */ |
|
# include <mutex.h> |
|
# endif |
|
|
# if __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \ |
# ifndef HPUX_THREADS |
|
# if __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \ |
|| !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700 |
|| !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700 |
# define GC_test_and_set(addr, v) test_and_set(addr,v) |
# define GC_test_and_set(addr, v) test_and_set(addr,v) |
# else |
# else |
# define GC_test_and_set(addr, v) __test_and_set(addr,v) |
# define GC_test_and_set(addr, v) __test_and_set(addr,v) |
|
# endif |
|
# else |
|
/* I couldn't find a way to do this inline on HP/UX */ |
# endif |
# endif |
extern unsigned long GC_allocate_lock; |
extern unsigned long GC_allocate_lock; |
/* This is not a mutex because mutexes that obey the (optional) */ |
/* This is not a mutex because mutexes that obey the (optional) */ |
Line 500 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 561 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
# define NO_THREAD (pthread_t)(-1) |
# define NO_THREAD (pthread_t)(-1) |
# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD |
# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD |
# define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self())) |
# define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self())) |
# ifdef UNDEFINED |
# ifdef HPUX_THREADS |
# define LOCK() pthread_mutex_lock(&GC_allocate_ml) |
# define LOCK() { if (!GC_test_and_clear(&GC_allocate_lock)) GC_lock(); } |
# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml) |
/* The following is INCORRECT, since the memory model is too weak. */ |
|
# define UNLOCK() { GC_noop1(&GC_allocate_lock); \ |
|
*(volatile unsigned long *)(&GC_allocate_lock) = 1; } |
# else |
# else |
# define LOCK() { if (GC_test_and_set(&GC_allocate_lock, 1)) GC_lock(); } |
# define LOCK() { if (GC_test_and_set(&GC_allocate_lock, 1)) GC_lock(); } |
# if __mips >= 3 && (defined (_ABIN32) || defined(_ABI64)) \ |
# if __mips >= 3 && (defined (_ABIN32) || defined(_ABI64)) \ |
&& defined(_COMPILER_VERSION) && _COMPILER_VERSION >= 700 |
&& defined(_COMPILER_VERSION) && _COMPILER_VERSION >= 700 |
# define UNLOCK() __lock_release(&GC_allocate_lock) |
# define UNLOCK() __lock_release(&GC_allocate_lock) |
# else |
# else |
/* The function call in the following should prevent the */ |
/* The function call in the following should prevent the */ |
/* compiler from moving assignments to below the UNLOCK. */ |
/* compiler from moving assignments to below the UNLOCK. */ |
/* This is probably not necessary for ucode or gcc 2.8. */ |
/* This is probably not necessary for ucode or gcc 2.8. */ |
Line 516 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 579 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
/* versions. */ |
/* versions. */ |
# define UNLOCK() { GC_noop1(&GC_allocate_lock); \ |
# define UNLOCK() { GC_noop1(&GC_allocate_lock); \ |
*(volatile unsigned long *)(&GC_allocate_lock) = 0; } |
*(volatile unsigned long *)(&GC_allocate_lock) = 0; } |
# endif |
# endif |
# endif |
# endif |
extern GC_bool GC_collecting; |
extern GC_bool GC_collecting; |
# define ENTER_GC() \ |
# define ENTER_GC() \ |
Line 607 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 670 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
# else |
# else |
# if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \ |
# if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \ |
|| defined(IRIX_THREADS) || defined(LINUX_THREADS) \ |
|| defined(IRIX_THREADS) || defined(LINUX_THREADS) \ |
|| defined(IRIX_JDK_THREADS) |
|| defined(IRIX_JDK_THREADS) || defined(HPUX_THREADS) |
void GC_stop_world(); |
void GC_stop_world(); |
void GC_start_world(); |
void GC_start_world(); |
# define STOP_WORLD() GC_stop_world() |
# define STOP_WORLD() GC_stop_world() |
Line 857 struct hblkhdr { |
|
Line 920 struct hblkhdr { |
|
/* object starting at the ith word (header */ |
/* object starting at the ith word (header */ |
/* INCLUDED) in the heap block. */ |
/* INCLUDED) in the heap block. */ |
/* The lsb of word 0 is numbered 0. */ |
/* The lsb of word 0 is numbered 0. */ |
|
/* Unused bits are invalid, and are */ |
|
/* occasionally set, e.g for uncollectable */ |
|
/* objects. */ |
}; |
}; |
|
|
/* heap block body */ |
/* heap block body */ |
Line 1411 extern void (*GC_start_call_back)(/* void */); |
|
Line 1477 extern void (*GC_start_call_back)(/* void */); |
|
/* lock held. */ |
/* lock held. */ |
/* 0 by default. */ |
/* 0 by default. */ |
void GC_push_regs(); /* Push register contents onto mark stack. */ |
void GC_push_regs(); /* Push register contents onto mark stack. */ |
|
/* If NURSERY is defined, the default push */ |
|
/* action can be overridden with GC_push_proc */ |
void GC_remark(); /* Mark from all marked objects. Used */ |
void GC_remark(); /* Mark from all marked objects. Used */ |
/* only if we had to drop something. */ |
/* only if we had to drop something. */ |
|
|
|
# ifdef NURSERY |
|
extern void (*GC_push_proc)(ptr_t); |
|
# endif |
# if defined(MSWIN32) |
# if defined(MSWIN32) |
void __cdecl GC_push_one(); |
void __cdecl GC_push_one(); |
# else |
# else |