ftp.nice.ch/pub/next/developer/languages/lisp/AKCL.1.599.s.tar.gz#/akcl-1-599/c/gbc.c

This is gbc.c in view mode; [Download] [Up]

/*
(c) Copyright Taiichi Yuasa and Masami Hagiya, 1984.  All rights reserved.
Copying of this file is authorized to users who have executed the true and
proper "License Agreement for Kyoto Common LISP" with SIGLISP.
*/

/*
	GBC.c
	IMPLEMENTATION-DEPENDENT
*/

#define	DEBUG


#include "include.h"
#include "mp.h"

/* the following in line definitions seem to be twice as fast (at
least on mc68020) as going to the assembly function calls in bitop.c so
since this is more portable and faster lets use them --W. Schelter
These assume that DBEGIN is divisible by 32, or else we should have
#define Shamt(x) (((((int) x -DBEGIN) >> 2) & ~(~0 << 5)))
*/ 

#define Shamt(x) (((((int) x) >> 2) & ~(~0 << 5)))
#define Madr(x) (mark_table+((((int) x) - ((int)DBEGIN)) >> (7)))
#define get_mark_bit(x) (*(Madr(x)) >> Shamt(x) & 1)
#define set_mark_bit(x) ((*(Madr(x))) |= (1 << Shamt(x)))

#ifdef KCLOVM
void mark_all_stacks();
bool ovm_process_created; 
#endif


bool saving_system;
static int gc_time = -1;
static int gc_start = 0;
int runtime();
int sgc_enabled=0;
int  first_protectable_page =0;


#define	round_up(n)	(((n) + 03) & ~03)

char *copy_relblock();

#include "page.h"


#ifdef MV


#endif


int real_maxpage;
int new_holepage;

#define	available_pages	\
	(real_maxpage-page(heap_end)-new_holepage-2*nrbpage-real_maxpage/32)

struct apage {
	char apage_self[PAGESIZE];
};


#define	inheap(pp)	((char *)(pp) < heap_end)

int maxpage;

object siVnotify_gbc;

#ifdef DEBUG
bool debug;
object siVgbc_message;
#endif

#define	MARK_ORIGIN_MAX		300
#define	MARK_ORIGIN_BLOCK_MAX	20

#ifdef AV
/*
	See bitop.c.
*/
#endif
#ifdef MV














#endif

#define	symbol_marked(x)	((x)->d.m)

object *mark_origin[MARK_ORIGIN_MAX];
int mark_origin_max;

struct {
	object	*mob_addr;	/*  mark origin block address  */
	int	mob_size;	/*  mark origin block size  */
} mark_origin_block[MARK_ORIGIN_BLOCK_MAX];
int mark_origin_block_max;

int *mark_table;

enum type what_to_collect;



enter_mark_origin(p)
object *p;
{
	if (mark_origin_max >= MARK_ORIGIN_MAX)
		error("too many mark origins");
#ifdef SGC
	sgc_type_map[page(p)] |= SGC_PERM_WRITABLE ;
#endif	
	mark_origin[mark_origin_max++] = p;
}

enter_mark_origin_block(p, n)
object *p;
int n;
{
	if (mark_origin_block_max >= MARK_ORIGIN_BLOCK_MAX)
		error("too many mark origin blocks");
	mark_origin_block[mark_origin_block_max].mob_addr = p;
	mark_origin_block[mark_origin_block_max++].mob_size = n;
}

mark_cons(x)
object x;
{
  cs_check(x);

	/*  x is already marked.  */

BEGIN:  
	if (x->c.c_car == OBJNULL) goto MARK_CDR;
	if (type_of(x->c.c_car) == t_cons) {
		if (x->c.c_car->c.m)
			;
		else {
			x->c.c_car->c.m = TRUE;
			mark_cons(x->c.c_car);
		}
	} else
		mark_object(x->c.c_car);
MARK_CDR:  
	x = x->c.c_cdr;
	if (x == OBJNULL)
		return;
	if (type_of(x) == t_cons) {
		if (x->c.m)
			return;
		x->c.m = TRUE;
		goto BEGIN;
	}
	if (x == Cnil)
		return;
	mark_object(x);
}

/* Whenever two arrays are linked together by displacement,
   if one is live, the other will be made live */
#define mark_displaced_field(ar) mark_object(ar->a.a_displaced)

mark_object(x)
object x;
{
	int i, j;
	object *p;
	char *cp;
	object y;

	cs_check(x);
BEGIN:
	if (x == OBJNULL)
		return;
	if (x->d.m)
		return;
	x->d.m = TRUE;
	switch (type_of(x)) {
	case t_fixnum:
		break;

	case t_ratio:
		mark_object(x->rat.rat_num);
		x = x->rat.rat_den;
		goto BEGIN;

	case t_shortfloat:
		break;

	case t_longfloat:
		break;

	case t_complex:
		mark_object(x->cmp.cmp_imag);
		x = x->cmp.cmp_real;
		goto BEGIN;

	case t_character:
		break;

	case t_symbol:
		mark_object(x->s.s_plist);
		mark_object(x->s.s_gfdef);
		mark_object(x->s.s_dbind);
		if (x->s.s_self == NULL)
			break;
		if ((int)what_to_collect >= (int)t_contiguous) {
			if (inheap(x->s.s_self)) {
				if (what_to_collect == t_contiguous)
					mark_contblock(x->s.s_self,
						       x->s.s_fillp);
			} else
				x->s.s_self =
				copy_relblock(x->s.s_self, x->s.s_fillp);
		}
		break;

	case t_package:
		mark_object(x->p.p_name);
		mark_object(x->p.p_nicknames);
		mark_object(x->p.p_shadowings);
		mark_object(x->p.p_uselist);
		mark_object(x->p.p_usedbylist);
		if (what_to_collect != t_contiguous)
			break;
		if (x->p.p_internal != NULL)
			mark_contblock((char *)(x->p.p_internal),
				       x->p.p_internal_size*sizeof(object));
		if (x->p.p_external != NULL)
			mark_contblock((char *)(x->p.p_external),
				       x->p.p_external_size*sizeof(object));
		break;

	case t_cons:
/*
		mark_object(x->c.c_car);
		x = x->c.c_cdr;
		goto BEGIN;
*/
		mark_cons(x);
		break;

	case t_hashtable:
		mark_object(x->ht.ht_rhsize);
		mark_object(x->ht.ht_rhthresh);
		if (x->ht.ht_self == NULL)
			break;
		for (i = 0, j = x->ht.ht_size;  i < j;  i++) {
			mark_object(x->ht.ht_self[i].hte_key);
			mark_object(x->ht.ht_self[i].hte_value);
		}
		if ((short)what_to_collect >= (short)t_contiguous) {
			if (inheap(x->ht.ht_self)) {
				if (what_to_collect == t_contiguous)
				    mark_contblock((char *)(x->ht.ht_self),
					           j * sizeof(struct htent));
			} else
				x->ht.ht_self = (struct htent *)
				copy_relblock((char *)(x->ht.ht_self),
					      j * sizeof(struct htent));
		}
		break;

	case t_array:
		if ((x->a.a_displaced) != Cnil)
		  mark_displaced_field(x);
		if ((int)what_to_collect >= (int)t_contiguous &&
		    x->a.a_dims != NULL) {
			if (inheap(x->a.a_dims)) {
				if (what_to_collect == t_contiguous)
				    mark_contblock((char *)(x->a.a_dims),
					           sizeof(int)*x->a.a_rank);
			} else
				x->a.a_dims = (int *)
				copy_relblock((char *)(x->a.a_dims),
					      sizeof(int)*x->a.a_rank);
		}
		if ((enum aelttype)x->a.a_elttype == aet_ch)
			goto CASE_STRING;
		if ((enum aelttype)x->a.a_elttype == aet_bit)
			goto CASE_BITVECTOR;
		if ((enum aelttype)x->a.a_elttype == aet_object)
			goto CASE_GENERAL;

	CASE_SPECIAL:
		cp = (char *)(x->fixa.fixa_self);
		if (cp == NULL)
			break;
		/* set j to the size in char of the body of the array */
		
		switch((enum aelttype)x->a.a_elttype){
#define  ROUND_RB_POINTERS_DOUBLE \
{int tem =  ((long)rb_pointer1) & (sizeof(double)-1); \
   if (tem) \
     { rb_pointer +=  (sizeof(double) - tem); \
       rb_pointer1 +=  (sizeof(double) - tem); \
     }}
		case aet_lf:
		  j= sizeof(longfloat)*x->lfa.lfa_dim;
	          if (((int)what_to_collect >= (int)t_contiguous) &&
			!(inheap(cp))) ROUND_RB_POINTERS_DOUBLE;
		  break;
		case aet_char:
		case aet_uchar:
		  j=sizeof(char)*x->a.a_dim;
		  break;
		case aet_short:
		case aet_ushort:
		  j=sizeof(short)*x->a.a_dim;
		  break;
		default:
		  j=sizeof(fixnum)*x->fixa.fixa_dim;}

		goto COPY;

	CASE_GENERAL:
		p = x->a.a_self;
		if (p == NULL)
			break;
		if (x->a.a_displaced->c.c_car == Cnil)
			for (i = 0, j = x->a.a_dim;  i < j;  i++)
				mark_object(p[i]);
		cp = (char *)p;
		j *= sizeof(object);
	COPY:
		if ((int)what_to_collect >= (int)t_contiguous) {
			if (inheap(cp)) {
				if (what_to_collect == t_contiguous)
					mark_contblock(cp, j);
			} else if (x->a.a_displaced == Cnil) {
#ifdef HAVE_ALLOCA
			  if (cp <= core_end)  /* only if body of array not on C stack */
#endif			  
				x->a.a_self = (object *)copy_relblock(cp, j);}
			else if (x->a.a_displaced->c.c_car == Cnil) {
				i = (int)(object *)copy_relblock(cp, j)
				  - (int)(x->a.a_self);
				adjust_displaced(x, i);
			}
		}
		break;

	case t_vector:
		if ((x->v.v_displaced) != Cnil)
		  mark_displaced_field(x);
		if ((enum aelttype)x->v.v_elttype == aet_object)
			goto CASE_GENERAL;
		else
			goto CASE_SPECIAL;

        case t_bignum:
		if ((int)what_to_collect >= (int)t_contiguous) {
		  j = x->big.big_length;
		  cp = (char *)(x->big.big_self);
		  if (cp == 0)
		    break;
		  if (j != lg(MP(x))  &&
		      /* we don't bother to zero this register,
			 and its contents may get over written */
		      ! (x == big_register_1 &&
			 (int)(cp) <= top &&
			 (int) cp >= bot))
		    printf("bad length 0x%x ",x);
		  j = j * sizeof(int);
		
		  if (inheap(cp)) {
		    if (what_to_collect == t_contiguous)
		      mark_contblock(cp, j);
		  } else 
		    x->big.big_self = (long *) copy_relblock(cp, j);}
		break;

	CASE_STRING:
	case t_string:
		if ((x->st.st_displaced) != Cnil)
		  mark_displaced_field(x);
		j = x->st.st_dim;
		cp = x->st.st_self;
		if (cp == NULL)
			break;
	COPY_STRING:
		if ((int)what_to_collect >= (int)t_contiguous) {
			if (inheap(cp)) {
				if (what_to_collect == t_contiguous)
					mark_contblock(cp, j);
			} else if (x->st.st_displaced == Cnil)
				x->st.st_self = copy_relblock(cp, j);
			else if (x->st.st_displaced->c.c_car == Cnil) {
				i = copy_relblock(cp, j) - cp;
				adjust_displaced(x, i);
			}
		}
		break;

	CASE_BITVECTOR:
	case t_bitvector:
		if ((x->bv.bv_displaced) != Cnil)
		  mark_displaced_field(x);
/* We make bitvectors multiple of sizeof(int) in size allocated
 Assume 8 = number of bits in char */

#define W_SIZE (8*sizeof(int))
		j= sizeof(int) *
		   ((x->bv.bv_offset + x->bv.bv_dim + W_SIZE -1)/W_SIZE);
		cp = x->bv.bv_self;
		if (cp == NULL)
			break;
		goto COPY_STRING;

	case t_structure:
		mark_object(x->str.str_def);
		p = x->str.str_self;
		if (p == NULL)
			break;
		{object def=x->str.str_def;
		 unsigned char * s_type = &SLOT_TYPE(def,0);
		 unsigned short *s_pos= & SLOT_POS(def,0);
		 for (i = 0, j = S_DATA(def)->length;  i < j;  i++)
		   if (s_type[i]==0) mark_object(STREF(object,x,s_pos[i]));
		 if ((int)what_to_collect >= (int)t_contiguous) {
		     if (inheap(x->str.str_self)) {
		       if (what_to_collect == t_contiguous)
			 mark_contblock((char *)p,
					S_DATA(def)->size);

		     } else
		       x->str.str_self = (object *)
			 copy_relblock((char *)p, S_DATA(def)->size);
		   }}
		break;

	case t_stream:
		switch (x->sm.sm_mode) {
		case smm_input:
		case smm_output:
		case smm_io:
		case smm_probe:
			mark_object(x->sm.sm_object0);
			mark_object(x->sm.sm_object1);
			if (saving_system)
			  {FILE *fp = x->sm.sm_fp;
			     if (fp != 0 && fp != stdin && fp !=stdout
				 )
			     {fclose(fp);
			      x->sm.sm_fp=0;
			    }}
			else
			if (what_to_collect == t_contiguous &&
			    x->sm.sm_fp &&
			    x->sm.sm_buffer)
				mark_contblock(x->sm.sm_buffer, BUFSIZ);
			break;

		case smm_synonym:
			mark_object(x->sm.sm_object0);
			break;

		case smm_broadcast:
		case smm_concatenated:
			mark_object(x->sm.sm_object0);
			break;

		case smm_two_way:
		case smm_echo:
			mark_object(x->sm.sm_object0);
			mark_object(x->sm.sm_object1);
			break;

		case smm_string_input:
		case smm_string_output:
			mark_object(x->sm.sm_object0);
			break;
#ifdef USER_DEFINED_STREAMS
   	        case smm_user_defined:
			mark_object(x->sm.sm_object0);
			mark_object(x->sm.sm_object1);
			break;
#endif
		default:
			error("mark stream botch");
		}
		break;

	case t_random:
		break;

	case t_readtable:
		if (x->rt.rt_self == NULL)
			break;
		if (what_to_collect == t_contiguous)
			mark_contblock((char *)(x->rt.rt_self),
				       RTABSIZE*sizeof(struct rtent));
		for (i = 0;  i < RTABSIZE;  i++) {
			mark_object(x->rt.rt_self[i].rte_macro);
			if (x->rt.rt_self[i].rte_dtab != NULL) {
/**/
	if (what_to_collect == t_contiguous)
		mark_contblock((char *)(x->rt.rt_self[i].rte_dtab),
			       RTABSIZE*sizeof(object));
	for (j = 0;  j < RTABSIZE;  j++)
		mark_object(x->rt.rt_self[i].rte_dtab[j]);
/**/
			}
		}
		break;

	case t_pathname:
		mark_object(x->pn.pn_host);
		mark_object(x->pn.pn_device);
		mark_object(x->pn.pn_directory);
		mark_object(x->pn.pn_name);
		mark_object(x->pn.pn_type);
		mark_object(x->pn.pn_version);
		break;

	case t_cfun:
        case t_sfun:
        case t_vfun:
	case t_gfun:	
		mark_object(x->cf.cf_name);
		mark_object(x->cf.cf_data);
		break;
		
        case t_cfdata:

	        if (x->cfd.cfd_self != NULL)
		  {int i=x->cfd.cfd_fillp;
		   while(i-- > 0)
		     mark_object(x->cfd.cfd_self[i]);}
		if (x->cfd.cfd_start == NULL)
			break;
		if (what_to_collect == t_contiguous) {
			if (!MAYBE_DATA_P((x->cfd.cfd_start)) ||
			    get_mark_bit((int *)(x->cfd.cfd_start)))
				break;
			mark_contblock(x->cfd.cfd_start, x->cfd.cfd_size);}
		break;
	case t_cclosure:
                mark_object(x->cc.cc_name);
                mark_object(x->cc.cc_env);
                mark_object(x->cc.cc_data);
                if (what_to_collect == t_contiguous) {
                  if (x->cc.cc_turbo != NULL)
                    mark_contblock((char *)(x->cc.cc_turbo-1),
                                   (1+fix(*(x->cc.cc_turbo-1)))*sizeof(object));
                }
                break;

	case t_spice:
		break;
        case t_fat_string:
		mark_fat_string(x);
		break;
        case t_dclosure:
                break;
	default:
#ifdef DEBUG
		if (debug)
			printf("\ttype = %d\n", type_of(x));
#endif
		error("mark botch");
	}
}

mark_stack_carefully(top,bottom,offset)
int *bottom,*top;
{int p,m,pageoffset;
 object x;
 struct typemanager *tm;
 register int *j;

 /* if either of these happens we are marking the C stack
    and need to use a local */

 if (top==0) top = (int *) &top ;
 if (bottom==0) bottom= (int *)&top;

 /* On machines which align local pointers on multiple of 2 rather
    than 4 we need to mark twice
   */

 if (offset) {mark_stack_carefully(bottom,(((char *) top) +offset),0);}
 for (j=top ; j >= bottom ; j--)
   {if (VALID_DATA_ADDRESS_P(*j)
	&& type_map[(p=page(*j))]< (char)t_end)
      {pageoffset=((char *)*j - pagetochar(p));
       tm=tm_of((enum type) type_map[p]);
       x= (object)
	 ((char *)(*j) -
	  ((pageoffset=((char *)*j - pagetochar(p))) %
	   tm->tm_size));
       if ((pageoffset <  (tm->tm_size * tm->tm_nppage))
	   && (m=x->d.m) != FREE)
       {if (m==TRUE) continue;
	  if (m!=0)
	    {fprintf(stdout,
		     "**bad value %d of d.m in gbc page %d skipping mark**"
		     ,m,p);fflush(stdout);
	     continue;
	   };
	  mark_object(x);}}}}


mark_phase()
{
	STATIC object *p;
	STATIC int i, j, k, n;
	STATIC struct package *pp;
	STATIC object s, l, *lp;
	STATIC bds_ptr bdp;
	STATIC frame_ptr frp;
	STATIC ihs_ptr ihsp;
	STATIC char *cp;

	mark_object(Cnil);
	mark_object(Ct);

	mark_stack_carefully(vs_top-1,vs_org,0);
	clear_stack(vs_top,vs_limit);
	mark_stack_carefully(MVloc,MVloc+(sizeof(MVloc)/sizeof(object)),0);
	/* 
	for (p = vs_org;  p < vs_top;  p++) {
	  if (p && (inheap(*p)))
		mark_object(*p);
	}
	*/
#ifdef DEBUG
	if (debug) {
		printf("value stack marked\n");
		fflush(stdout);
	}
#endif

	for (bdp = bds_org;  bdp<=bds_top;  bdp++) {
	 	mark_object(bdp->bds_sym);
		mark_object(bdp->bds_val);
	}

	for (frp = frs_org;  frp <= frs_top;  frp++)
		mark_object(frp->frs_val);

	for (ihsp = ihs_org;  ihsp <= ihs_top;  ihsp++)
		mark_object(ihsp->ihs_function);

	for (i = 0;  i < mark_origin_max;  i++)
		mark_object(*mark_origin[i]);
	for (i = 0;  i < mark_origin_block_max;  i++)
		for (j = 0;  j < mark_origin_block[i].mob_size;  j++)
			mark_object(mark_origin_block[i].mob_addr[j]);

	for (pp = pack_pointer;  pp != NULL;  pp = pp->p_link)
		mark_object(pp);
#ifdef KCLOVM
	if (ovm_process_created)
	  mark_all_stacks();
#endif

#ifdef DEBUG
	if (debug) {
		printf("symbol navigation\n");
		fflush(stdout);
	}
#endif

/*
	if (what_to_collect != t_symbol &&
	    (int)what_to_collect < (int)t_contiguous) {
*/

	{int size;
	 
	 for (pp = pack_pointer;  pp != NULL;  pp = pp->p_link) {
	                size = pp->p_internal_size;
			if (pp->p_internal != NULL)
				for (i = 0;  i < size;  i++)
					mark_object(pp->p_internal[i]);
			size = pp->p_external_size;
			if (pp->p_external != NULL)
				for (i = 0;  i < size;  i++)
					mark_object(pp->p_external[i]);
		}}

   /* mark the c stack */
#ifndef N_RECURSION_REQD
#define N_RECURSION_REQD 2
#endif		
	mark_c_stack(0,N_RECURSION_REQD,mark_stack_carefully);

}

mark_c_stack(env1,n,fn)
     jmp_buf *env1;
     int n;
     int (*fn)();
{jmp_buf env;
 int where;
 if (n > 0 )
   {  setjmp(env);
      mark_c_stack(env,n - 1,fn);}
 else
   {
	 
     /* If the locals of type object in a C function could be
	aligned other than on multiples of sizeof (char *)
	then define this.  At the moment 2 is the only other
	legitimate value besides 0 */
	 
#ifndef C_GC_OFFSET
#define C_GC_OFFSET 0
#endif
     if (&where > cs_org)
      (*fn)(0,cs_org,C_GC_OFFSET);
     else
       (*fn)(cs_org,0,C_GC_OFFSET);}

}

 


sweep_phase()
{
	STATIC int i, j, k;
	STATIC object x;
	STATIC char *p;
	STATIC int *ip;
	STATIC struct typemanager *tm;
	STATIC object f;

	Cnil->s.m = FALSE;
	Ct->s.m = FALSE;

#ifdef DEBUG
	if (debug)
		printf("type map\n");
#endif
	for (i = 0;  i < maxpage;  i++) {
		if (type_map[i] == (int)t_contiguous) {
			if (debug) {
				printf("-");
			/*
				fflush(stdout);
			*/
				continue;
			}
		}
		if (type_map[i] >= (int)t_end)
			continue;

		tm = tm_of((enum type)type_map[i]);

	/*
		general sweeper
	*/

#ifdef DEBUG
		if (debug) {
			printf("%c", tm->tm_name[0]);
		/*
			fflush(stdout);
		*/
		}
#endif
		p = pagetochar(i);
		f = tm->tm_free;
		k = 0;
		for (j = tm->tm_nppage; j > 0; --j, p += tm->tm_size) {
			x = (object)p;
			if (x->d.m == FREE)
				continue;
			else if (x->d.m) {
				x->d.m = FALSE;
				continue;
			}
			/*   Since we now mark forwards and backwards on displaced
			     arrays, this is not necessary.
			switch (x->d.t) {
			case t_array:
			case t_vector:
			case t_string:
			case t_bitvector:
				if (x->a.a_displaced->c.c_car != Cnil)
				  {undisplace(x);
				 }
			}
			*/
			((struct freelist *)x)->f_link = f;
			x->d.m = FREE;
			f = x;
			k++;
		}
		tm->tm_free = f;
		tm->tm_nfree += k;

	NEXT_PAGE:
		;
	}
#ifdef DEBUG
	if (debug) {
		putchar('\n');
		fflush(stdout);
	}
#endif
}

contblock_sweep_phase()
{
	STATIC int i, j;
	STATIC char *s, *e, *p, *q;
	STATIC struct contblock *cbp;

	cb_pointer = NULL;
	ncb = 0;
	for (i = 0;  i < maxpage;) {
		if (type_map[i] != (int)t_contiguous) {
			i++;
			continue;
		}
		for (j = i+1;
		     j < maxpage && type_map[j] == (int)t_contiguous;
		     j++)
			;	
		s = pagetochar(i);
		e = pagetochar(j);
		for (p = s;  p < e;) {
			if (get_mark_bit((int *)p)) {
				p += 4;
				continue;
			}
			q = p + 4;
			while (q < e) {
				if (!get_mark_bit((int *)q)) {
					q += 4;
					continue;
				}
				break;
			}
			insert_contblock(p, q - p);
			p = q + 4;
		}
		i = j + 1;
	}
#ifdef DEBUG
	if (debug) {
		for (cbp = cb_pointer; cbp != NULL; cbp = cbp->cb_link)
			printf("%d-byte contblock\n", cbp->cb_size);
		fflush(stdout);
	}
#endif
}


int (*GBC_enter_hook)() = NULL;
int (*GBC_exit_hook)() = NULL;

GBC(t)
enum type t;
{
	int i, j;
	struct apage *pp, *qq;
	int in_sgc = sgc_enabled;

#ifdef DEBUG
	int tm;
#endif

	if (GBC_enter_hook != NULL)
		(*GBC_enter_hook)();

	if (!GBC_enable)
             error("GBC is not enabled");
	interrupt_enable = FALSE;

	if (saving_system)
		{t = t_contiguous; gc_time = -1;
		 if(sgc_enabled) sgc_quit();

	       }


#ifdef DEBUG
	debug = symbol_value(siVgbc_message) != Cnil;
#endif

	what_to_collect = t;

	if (t == t_contiguous)
		cbgbccount++;
	else if (t == t_relocatable)
		rbgbccount++;
	else
		tm_table[(int)t].tm_gbccount++;

#ifdef DEBUG
	if (debug || (siVnotify_gbc->s.s_dbind != Cnil)) {

	  if (gc_time < 0) gc_time=0;
	  printf("[%s for %d %s pages..",
		 (sgc_enabled ? "SGC" : "GC"),
		 (sgc_enabled ? sgc_count_type(t) : tm_of(t)->tm_npage),
		 (tm_table[(int)t].tm_name)+1);
#ifdef SGC
	  if(sgc_enabled)
	    printf("(%d writable)..",sgc_count_writable(page(core_end)));
#endif	  
	  fflush(stdout);
	}
#endif
        if (gc_time >=0) {gc_start=runtime();}

	maxpage = page(heap_end);

	if ((int)t >= (int)t_contiguous) {
		j = maxpage*(PAGESIZE/(sizeof(int)*sizeof(int)*CHAR_SIZE)) ;
		/*
		    (PAGESIZE / sizeof(int)) = x * (sizeof(int)*CHAR_SIZE)
		    eg if PAGESIZE = 2048  x=16
			1 page = 512 long word
			512 bit = 16 long word
		*/

		if (t == t_relocatable)
			j = 0;
	       /* if in sgc we don't need more pages below hole
		  just more relocatable or cleaning it */
		if (sgc_enabled ==0 && holepage < new_holepage)
			holepage = new_holepage;

		i = rb_pointer - rb_start;

		if (nrbpage > (real_maxpage-page(heap_end)
		               -holepage-real_maxpage/32)/2) {
			if (i > nrbpage*PAGESIZE)
				error("Can't allocate.  Good-bye!.");
			else
				nrbpage =
				(real_maxpage-page(heap_end)
				 -holepage-real_maxpage/32)/2;
		}

		if (saving_system)
			rb_start = heap_end;
		else
		  if (sgc_enabled==0)
		    {rb_start = heap_end + PAGESIZE*holepage;}

		rb_end = heap_end + (holepage + nrbpage) *PAGESIZE;

		if (rb_start < rb_pointer)
			rb_start1 = (char *)
			((int)(rb_pointer + PAGESIZE-1) & -PAGESIZE);
		else
			rb_start1 = rb_start;

		rb_pointer = rb_start;
		rb_pointer1 = rb_start1;

		mark_table = (int *)(rb_start1 + i);

		if (rb_end < (char *)&mark_table[j])
			i = (char *)&mark_table[j] - heap_end;
		else
			i = rb_end - heap_end;
		alloc_page(-(i + PAGESIZE - 1)/PAGESIZE);

		for (i = 0;  i < j; i++)
			mark_table[i] = 0;
	}

#ifdef DEBUG
	if (debug) {
		printf("mark phase\n");
		fflush(stdout);
		tm = runtime();
	}
#endif
#ifdef SGC
	if(sgc_enabled)
	  { if (t < t_end && tm_of(t)->tm_sgc == 0)
	      {sgc_quit();
	       	if (siVnotify_gbc->s.s_dbind != Cnil)
		  {fprintf(stdout, " (doing full gc)");
		   fflush(stdout);}
	       mark_phase();}
	    else
	  sgc_mark_phase();}
	else
#endif	
	mark_phase();
#ifdef DEBUG
	if (debug) {
		printf("mark ended (%d)\n", runtime() - tm);
		fflush(stdout);
	}
#endif

#ifdef DEBUG
	if (debug) {
		printf("sweep phase\n");
		fflush(stdout);
		tm = runtime();
	}
#endif
#ifdef SGC
	if(sgc_enabled)
	  sgc_sweep_phase();
	else
#endif	
	sweep_phase();
#ifdef DEBUG
	if (debug) {
		printf("sweep ended (%d)\n", runtime() - tm);
		fflush(stdout);
	}
#endif

	if (t == t_contiguous) {
#ifdef DEBUG
		if (debug) {
			printf("contblock sweep phase\n");
			fflush(stdout);
			tm = runtime();
		}
#endif

#ifdef SGC
	if (sgc_enabled)
	  sgc_contblock_sweep_phase();
	else
#endif
	  contblock_sweep_phase();
#ifdef DEBUG
		if (debug)
			printf("contblock sweep ended (%d)\n",
			       runtime() - tm);
#endif
	}

	if ((int)t >= (int)t_contiguous) {

		if (rb_start < rb_start1) {
			j = (rb_pointer-rb_start + PAGESIZE - 1)/PAGESIZE;
			pp = (struct apage *)rb_start;
			qq = (struct apage *)rb_start1;
			for (i = 0;  i < j;  i++)
				*pp++ = *qq++;
		}

#ifdef SGC
		/* we don't know which pages have relblock on them */
		 if(sgc_enabled)
                  make_writable(page(rb_start),
                                (rb_pointer-rb_start + PAGESIZE - 1)/PAGESIZE);

#endif		
		rb_limit = rb_end - 2*RB_GETA;

	}

#ifdef DEBUG
	if (debug) {
		for (i = 0, j = 0;  i < (int)t_end;  i++) {
			if (tm_table[i].tm_type == (enum type)i) {
			    printf("%13s: %8d used %8d free %4d/%d pages\n",
				       tm_table[i].tm_name,
				       TM_NUSED(tm_table[i]),
				       tm_table[i].tm_nfree,
				       tm_table[i].tm_npage,
				       tm_table[i].tm_maxpage);
				j += tm_table[i].tm_npage;
			} else
				printf("%13s: linked to %s\n",
				       tm_table[i].tm_name,
				       tm_table[(int)tm_table[i].tm_type].tm_name);
		}
		printf("contblock: %d blocks %d pages\n", ncb, ncbpage);
		printf("hole: %d pages\n", holepage);
		printf("relblock: %d bytes used %d bytes free %d pages\n",
		       rb_pointer - rb_start, rb_end - rb_pointer, nrbpage);
		printf("GBC ended\n");
		fflush(stdout);
	}
#endif

	interrupt_enable = TRUE;

	if (saving_system) {
		j = (rb_pointer-rb_start+PAGESIZE-1) / PAGESIZE;

		heap_end += PAGESIZE*j;

		core_end = heap_end;

		for (i = 0;  i < maxpage;  i++)
			if ((enum type)type_map[i] == t_contiguous)
				type_map[i] = (char)t_other;
		cb_pointer = NULL;
		maxcbpage -= ncbpage;
		if (maxcbpage < 100)
		  maxcbpage = 100;
		ncbpage = 0;
		ncb = 0;

		if (sgc_enabled==0) holepage = new_holepage;

		nrbpage -= j;
		if (nrbpage < 0)
			error("no relocatable pages left");

		rb_start = heap_end + PAGESIZE*holepage;
		rb_end = rb_start + PAGESIZE*nrbpage;
		rb_limit = rb_end - 2*RB_GETA;
		rb_pointer = rb_start;
	}

	if (GBC_exit_hook != NULL)
		(*GBC_exit_hook)();


	if (in_sgc && sgc_enabled==0)
	  sgc_start();

        if(gc_time>=0) {gc_time=gc_time+(gc_start=(runtime()-gc_start));}

	if (siVnotify_gbc->s.s_dbind != Cnil) {

	  fprintf(stdout, "(T=%d).GC finished]\n",
		  gc_start
		  );
		fflush(stdout);
	}


	CHECK_FOR_INTERRUPT;
}

siLroom_report()
{
	int i;

	check_arg(0);

/*
	GBC(t_contiguous);
*/

	vs_check_push(make_fixnum(real_maxpage));
	vs_push(make_fixnum(available_pages));
	vs_push(make_fixnum(ncbpage));
	vs_push(make_fixnum(maxcbpage));
	vs_push(make_fixnum(ncb));
	vs_push(make_fixnum(cbgbccount));
	vs_push(make_fixnum(holepage));
	vs_push(make_fixnum(rb_pointer - rb_start));
	vs_push(make_fixnum(rb_end - rb_pointer));
	vs_push(make_fixnum(nrbpage));
	vs_push(make_fixnum(rbgbccount));
	for (i = 0;  i < (int)t_end;  i++) {
		if (tm_table[i].tm_type == (enum type)i) {
			vs_check_push(make_fixnum(TM_NUSED(tm_table[i])));
			vs_push(make_fixnum(tm_table[i].tm_nfree));
			vs_push(make_fixnum(tm_table[i].tm_npage));
			vs_push(make_fixnum(tm_table[i].tm_maxpage));
			vs_push(make_fixnum(tm_table[i].tm_gbccount));
		} else {
			vs_check_push(Cnil);
			vs_push(make_fixnum(tm_table[i].tm_type));
			vs_push(Cnil);
			vs_push(Cnil);
			vs_push(Cnil);
		}
	}
}

siLreset_gbc_count()
{
	int i;

	check_arg(0);
	cbgbccount = 0;
	rbgbccount = 0;
	for (i = 0;  i < (int)t_end;  i++)
		tm_table[i].tm_gbccount = 0;
}

/* copy S bytes starting at P to beyond rb_pointer1 (temporarily)
 but return a pointer to where this will be copied back to,
 when gc is done.  alignment of rb_pointer is kept at a multiple
 of sizeof(char *);
 */
      
char *
copy_relblock(p, s)
char *p;
int s;
{ char *res = rb_pointer;
  char *q = rb_pointer1;
  s = round_up(s);
  rb_pointer += s;
  rb_pointer1 += s;
  
  while (--s >= 0)
    { *q++ = *p++;}

  return res;
}

  
mark_contblock(p, s)
char *p;
int s;
{
	STATIC char *q;
	STATIC int *x, *y;

	if (!MAYBE_DATA_P(p) || (enum type)type_map[page(p)] != t_contiguous)
		return;
	q = p + s;
	x = (int *)(char *)((int)p&~3);
	y = (int *)(char *)(((int)q+3)&~3);
	for (;  x < y;  x++)
		set_mark_bit(x);
}

Lgbc()
{
	check_arg(1);

	if (vs_base[0] == Ct)
		GBC(t_contiguous);
	else if (vs_base[0] == Cnil)
		GBC(t_cons);
	else
		GBC(t_relocatable);
}

siLgbc_time()
{if (vs_top>vs_base)
   gc_time=fix(vs_base[0]);
 else
   {vs_base[0]=make_fixnum(gc_time);
    vs_top=vs_base+1;}
}

#ifdef SGC
#include "sgbc.c"
#endif

init_GBC()
{
	make_si_function("ROOM-REPORT", siLroom_report);
	make_si_function("RESET-GBC-COUNT", siLreset_gbc_count);
	make_si_function("GBC-TIME",siLgbc_time);

	siVnotify_gbc = make_si_special("*NOTIFY-GBC*", Cnil);

#ifdef DEBUG
	siVgbc_message = make_si_special("*GBC-MESSAGE*", Cnil);
#endif

	make_function("GBC", Lgbc);
#ifdef SGC
	/* we use that maxpage is a power of 2 in this
	   case, to quickly be able to look in our table */ 
	{int i ;
	 for(i=1 ; i< 32 ; i++)
	   {if (MAXPAGE == (1 <<i))
	      goto ok;}
	 perror("MAXPAGE is not a power of 2.  Recompile");
	 exit(1);
       ok:;}
	make_si_function("SGC-ON",siLsgc_on);
#endif	
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.