Ejemplo n.º 1
0
static size_t gc_sweep2(GcManager *mng)
{
    GC_SWEEP(2);
}
Ejemplo n.º 2
0
static size_t gc_sweep0(GcManager *mng)
{
    GC_SWEEP(0);
}
Ejemplo n.º 3
0
static size_t gc_sweep1(GcManager *mng)
{
    GC_SWEEP(1);
}
Ejemplo n.º 4
0
void Agc_sweep(SEGCTLPTR *heap_segments)
{
  SEGCTLPTR segctlp, *segctlpp;
  ELPTR elp;
  CODEDPTR *elpp;
  
  GC_SWEEP();

  for ( segctlpp = heap_segments; (segctlp = *segctlpp) != NIL; )
    /*  At end of loop so it can be skipped by continue: segctlpp = &((segctlp)->next ) */
  {
    PTR		elstart, elend;
    BITMAPPTR	bitmap = segctlp->bitmap;
    PTR		old_elend;
    ASSERT_DECL( PTR last_freestart )


      REPORT6(5,"Agc_collect{free list reconstruct}: segctlp=0x%p, elsize=%d, start=0x%p, end=0x%p, size=%d,els=%d\n",
	      (void *)segctlp,SEGELSIZE(segctlp),(void *)SEGSTART(segctlp),(void *)SEGEND(segctlp),SEGSIZE(segctlp),SEGELS(segctlp));


    /*
     ** First, clear bitmap (to indicate unused) from free list.
     ** This is essential for the freelist reconstruction algorithm to work.
     ** It ensures that all free list elements are enclosed in an unused heap area
     ** as identified by the bitmap.
     */

    /*
     ** Note that sweeping algorithm relies on the fact that the free list elements are
     ** in ascending address order, and there is some allocated space between elements.
     */

    ASSERT(bitmap == segctlp->bitmap,Agc_collect,'bitmap' out of sync);
    ASSERT(TSTMARK(bitmap,SEGELS(segctlp)+0),Agc_collect,bitmap trailer clear);
    ASSERT(!TSTMARK(bitmap,SEGELS(segctlp)+1),Agc_collect,bitmap trailer set);
    ASSERT(TSTMARK(bitmap,SEGELS(segctlp)+2),Agc_collect,bitmap trailer clear);

    elpp = &segctlp->free;
    elp = DECODEPTR(*elpp);
    old_elend = SEGSTART( segctlp );
    ASSERT_INIT( last_freestart = SEGSTART(segctlp) - 1 );
    if ( elp != NIL )
    {
      elstart = (PTR)elp;
      elend = (PTR)ELEND( elp, segctlp );
		
      CHECK_EL( segctlp, elp, elend );
    }
    else
    {
      elstart = elend = (char *)(SEGEND( segctlp )) + 1; /* well beyond any free space */
    }
		
    for (;;)
    {
		
      PTR		freestart, freeend;
      SIZE	freed_bytes;
		
      ASSERT(elp == DECODEPTR(*elpp),Agc_collect,elpp and elp out of step);
		
      ASSERT(elp == NIL || ((PTR)elp >= (PTR)SEGSTART(segctlp) && (PTR)elp < (PTR)SEGEND(segctlp))
	     ,Agc_collect,elp not within segment);
      ASSERT(elp == NIL || ((PTR)ELEND(elp,segctlp) <= (PTR)SEGEND(segctlp))
	     ,Agc_collect,elp end not within segment);
      ASSERT(elp == NIL || elend > elstart,Agc_collect,empty free list element);
		
      /*
       ** First, set 'freestart' to be the start of either the next:
       **
       **	free space starting outside a free list element
       ** or
       **	free space starting at the start of a free list element
       **	but finishing beyond the end of that element
       ** or
       **	an adress beyond the end of the segment
       */
		
      SCAN_TO_CLR( freestart, segctlp, bitmap, old_elend, elstart );
		
      ASSERT( freestart > last_freestart,Agc_collect,not progressing in sweep);
      ASSERT_INIT( last_freestart = freestart );
		
      if ( freestart >= SEGEND( segctlp ) ) break;
		
      while ( freestart == elstart && TSTMARK( bitmap, ELNUM( elend, segctlp ) ) )
      {
	/*
	 ** Freespace is identical to free list element.
	 ** Skip on to next free list element.
	 */
		
	ASSERT(freestart <= SEGEND(segctlp),Agc_collect,freestart beyond segend);
		
	/* step on to next free list element */
		
	ASSERT(elp != NIL,Agc_collect,elp nil at elpp update);
	elpp = &elp->next;
	elp = DECODEPTR(*elpp);
	old_elend = elend;
	if ( elp != NIL )
	{
	  elstart = (PTR)elp;
	  elend = (PTR)ELEND( elp, segctlp );

	  CHECK_EL( segctlp, elp, elend );
		
	  ASSERT(elend > elstart,Agc_collect,empty free list element);
	}
	else
	{
	  elstart = elend = (char *)(SEGEND( segctlp )) + 1; /* well beyond any free space */
	}
	ASSERT(old_elend < elstart,Agc_collect,free list not in order);
		
	SCAN_TO_CLR( freestart, segctlp, bitmap, old_elend, elstart );
      }
		
      if ( freestart >= SEGEND( segctlp ) ) break;
		
      ASSERT(freestart == (PTR)SEGSTART( segctlp ) || freestart > old_elend,Agc_collect,freestart before old_elend);
		
      ASSERT(freestart <= elstart,Agc_collect,freestart > elstart);
		
      ASSERT(elp == NIL || elstart == (PTR)DECODEPTR(*elpp),Agc_collect,elstart != *elpp);
		
		
      /*
       ** Secondly, set 'freeend' to be the end of the freespace
       */

      if ( freestart < elstart )
      {
	SCAN_TO_SET( freeend, segctlp, bitmap, freestart, elstart );
		
	freed_bytes = (char *)freeend - (char *)freestart;
	CLR_AT_FREE( freestart, SEGELSIZE(segctlp), freed_bytes );
      }
      else
      {
	ASSERT(freestart == elstart,Agc_collect,freestart == elstart);
		
	freed_bytes = 0;
	freeend = freestart;
      }

      while ( freeend == elstart )
      {
	/* step on to next free list element */
		
	ASSERT(freeend <= SEGEND(segctlp),Agc_collect,freeend beyond segend);
		
	elp = DECODEPTR(elp->next);
	old_elend = elend;
		
	if ( elp != NIL )
	{
	  elend = (PTR)ELEND( elp, segctlp );
	  CLR_ELHEADER_AT_FREE( (ELPTR)elstart, SEGELSIZE(segctlp) );
	  elstart = (PTR)elp;
		
	  CHECK_EL( segctlp, elp, elend );
		
	  ASSERT(elend > elstart,Agc_collect,empty free list element);
	}
	else
	{
	  CLR_ELHEADER_AT_FREE( (ELPTR)elstart, SEGELSIZE(segctlp) );
	  elstart = elend = (char *)(SEGEND( segctlp )) + 1; /* well beyond any free space */
	}
	ASSERT(old_elend < elstart,Agc_collect,free list not in order);
		
	ASSERT(freeend < elstart,Agc_collect,freeend not less than elstart);
		
	SCAN_TO_SET( freeend, segctlp, bitmap, old_elend, elstart );
		
	ASSERT(freeend >= old_elend,Agc_collect,freeend before old_elend);
	ASSERT(freeend <= elstart,Agc_collect,freeend beyond elstart limit);
	ASSERT(freeend <= SEGEND(segctlp),Agc_collect,freeend beyond segend);
		
	if ( freeend != old_elend )
	{
	  freed_bytes += (char *)freeend - (char *)old_elend;
	  CLR_AT_FREE( old_elend, SEGELSIZE(segctlp), (char *)freeend-(char *)old_elend );
	}
      }
		
      ASSERT(freeend < elstart,Agc_collect,freeend beyond elstart);
		
		
      /* freestart -> freeend is the new element */
      /* elp is freelist element beyond freeend, or NIL */
      /* elpp points to el pointer before freestart */
		
      ASSERT(freeend > freestart,Agc_collect,empty bitmap area);
      ASSERT(elp == NIL || (PTR)elp > freeend,Agc_collect,elp before freeend);
      ASSERT(freeend <= SEGEND(segctlp),Agc_collect,freeend beyond segend);
		
      ASSERT((PTR)elpp < freestart,Agc_collect,elpp beyond freestart);

      ASSERT(bitmap == segctlp->bitmap,Agc_collect,'bitmap' out of sync);
      ASSERT(TSTMARK(bitmap,SEGELS(segctlp)+0),Agc_collect,bitmap trailer clear);
      ASSERT(!TSTMARK(bitmap,SEGELS(segctlp)+1),Agc_collect,bitmap trailer set);
      ASSERT(TSTMARK(bitmap,SEGELS(segctlp)+2),Agc_collect,bitmap trailer clear);
		
      if ( freestart == SEGSTART( segctlp ) && freeend == SEGEND( segctlp ) )
      {
	/* Whole segment is free */
	/* +++ put segment at end of list rather than freeing */
		
	REPORT1(3,"Agc_collect: freeing seg=0x%p\n",(void *)segctlp);
		
	ASSERT(bitmap == segctlp->bitmap,Agc_collect,'bitmap' out of sync);

	FREE_BITMAP( bitmap, SEGELS( segctlp ) + 3 );
		
	ASSERT_INIT( segctlp->bitmap = bitmap = NIL );
		
	*segctlpp = segctlp->next; /* remove segctlp from list */
		
	Agc_b_allocated -= freed_bytes;
	Agc_s_grabbed--;
	Agc_b_grabbed -= SEGSIZE(segctlp);
		
	REP_DO(Agc_s_freed++);
		
	FREE_SEG( segctlp );
		
	ASSERT_INIT( segctlp = NIL );
		
	goto sweep_next_seg;
      }
      else if ( ELPTRENOUGH( freestart, freeend ) )
      {
#define				freeelp	((ELPTR)freestart)
		
	/* care needed because of possible overlap between new and old element header */
		
	REPORT5(6,"Agc_collect: adding free list element (0x%p -> 0x%p : size %d) after elpp 0x%p, before 0x%p\n",
		(void *)freestart,(void *)freeend,(char *)freeend-(char *)freestart,(void *)elpp,(void *)elp);
		
	ASSERT( IS_CLR(freestart,SEGELSIZE(segctlp),(char *)freeend-(char *)freestart)
	       ,Agc_collect,recreated free list element not clear);
		
	ASSERT( ((char *)freeend - (char *)freestart) % SEGELSIZE( segctlp ) == 0,Agc_collect,space recovered not multiple of elsize);
		
	freeelp->next = ENCODEPTR( elp );
	freeelp->elements = ((char *)freeend - (char *)freestart) / SEGELSIZE( segctlp );
		
	ASSERT(DECODEPTR(*elpp) == NIL || (PTR)DECODEPTR(*elpp) >= freestart,Agc_collect,discarding space already in free list);
		
	*elpp = ENCODEPTR( freestart );
		
	/* elp is still correct as next element, we have just inserted preceding it */
	/* however elpp now needs to point at new element */
	elpp = &freeelp->next;
		
	Agc_b_allocated -= freed_bytes;
		
	ASSERT( freeend == (PTR)ELEND(freeelp,segctlp)
	       ,Agc_collect,freeend not ELEND);
	ASSERT( freeelp->next == CODEDNIL || DECODEPTR(freeelp->next) > ELEND(freeelp,segctlp)
	       ,Agc_collect,free list elements overlap);
	ASSERT( freeelp->next == CODEDNIL || (PTR)DECODEPTR(freeelp->next) > freeend
	       ,Agc_collect,freeelp->next not past freeend);
		
#undef				freeelp
      }
      /* else ( ! ELPTRENOUGH( freestart, freeend ) )			*/
      /* 	do nothing, forget the few bytes of free space we found */
		
      old_elend = freeend;
		
    }

#ifdef	A_DEBUG
    if ( ELPTRENOUGH( (PTR)NIL, (char *)NIL+SEGELSIZE(segctlp) ) )
      /* if ( SEGELSIZE(segctlp) >= sizeof( EL ) ) */
    {
      SIZE	i;

      elp = DECODEPTR( segctlp->free );

      for ( i = 0; i < SEGELS(segctlp); i++ )
      {
	if ( !TSTMARK(bitmap,i) )
	{
	  while ( i > ELNUM( ELEND( elp, segctlp ), segctlp ) )
	  {
	    elp = DECODEPTR( elp->next );
	    ASSERT( elp != NIL,Agc_collect,free element beyond free list end at end of sweep);
	  }
	  ASSERT( i >= ELNUM( elp, segctlp ) && i < ELNUM( ELEND( elp, segctlp ), segctlp ),Agc_collect,free element not in free list at end of sweep);
	}
      }
    }
#endif

    ASSERT(bitmap == segctlp->bitmap,Agc_collect,'bitmap' out of sync);

    FREE_BITMAP( bitmap, SEGELS( segctlp ) + 3 );

    ASSERT_INIT( segctlp->bitmap = bitmap = NIL );

    segctlpp = &((segctlp)->next);

  sweep_next_seg:	;

  }

}