/* object.c 
 
   Basic object manipulation routines used during collection.

 */

#include "header.h"
#include "prototypes.h"
#include "pageHeader.h"
#include "machine.h"
#include <assert.h>
#include <stdlib.h>

/* processes the Child.(i.e. Enqueues it and/or forwards the child
   appropriately.) If need be it also pins the pages the child resides on. */
INLINE static void processChild(Word **source, Deque *explicitQueue)
{
 Word childHeader;
 Word *pChild;

 pChild = *source;
 childHeader = OBJECT_HEADER(*source);

 assert(childHeader!=GC_EMPTY);

 /* Don't trace if in an older generation. */
 GEN(if(PAGE_AGED(PAGE_TO_PI(pChild)->header)) { \
		assert((GC_EXTRACT_STATUS(childHeader)==GC_NORMAL) || \
		       (GC_EXTRACT_STATUS(childHeader)==GC_PINNED)); \
		return; }); 

 assert(((PAGE_TO_PI(pChild)->header) & PAGE_USER) != 0);

 switch(GC_EXTRACT_STATUS(childHeader))
   {
   case GC_NORMAL:
     {
       assert(!GC_END_LARGE(childHeader));

       assert(GC_OBJECT_SIZE(childHeader) <= COPYABLE_OBJECT);
       assert(OBJECT_VALID(pChild));
       
       *source = iqEnqueue(pChild, childHeader); 
       /* The above line updates the parents pointer to childs new
	  location. */
       
       OBJECT_FORWARD(pChild,*source); /* This line forwards the child to its
					 new location. */
       return;
     }
   case GC_TRAVERSED:
     {
       return;
     }
   case GC_MOVED:
     {
       UPDATE_POINTER(source,childHeader);
       return;
     }     
   case GC_PINNED:
     {
       enqueue(explicitQueue,(Word)pChild);

       OBJECT_TRAVERSE(pChild);
       STATS(gcInfo.nTraversedObjects++);
       
       pinObjectPages(pChild,childHeader);

       return;
     }
   }
}

void processCObject(Word *cObject, Word header, Deque *explicitQueue)
{
 Word *ptr,*ptrEnd;
 Word *child;
 Word childHeader;
 unsigned int size;
 SIMPLE_PTR_TEST_SETUP;

 if(GC_POINTER_FREE_COBJ(header)) return;

 enqueue(gcInfo.cObjects,(Word)cObject);

 size = GC_SIZE_COBJ(header);

 ptr = cObject;
 ptrEnd = ptr + size;

 for(;ptr<ptrEnd;ptr++)
   {
     if(SIMPLE_PTR_TEST(*ptr))
	{
	  child = pointerQueryLate(*ptr);

	  if(child!=NULL)
	    {
	      childHeader = OBJECT_HEADER(child);
	      assert(OBJECT_VALID(child));
	      assert(OBJECT_PINNED(child) || OBJECT_TRAVERSED(child));
	      assert(!GC_END_LARGE(childHeader));
	      
	      if(!OBJECT_TRAVERSED(child))
		{
		  OBJECT_TRAVERSE(child);
		  STATS(gcInfo.nTraversedObjects++);
		  
		  enqueue(explicitQueue,(Word) child); 
		  pinObjectPages(child,childHeader);
		}
	    }
	}
   }
}

void processCObjectEarly(Word *cObject, Word header, Deque *explicitQueue)
{
 Word *ptr,*ptrEnd;
 Word *child;
 Word childHeader;
 unsigned int size;
 SIMPLE_PTR_TEST_SETUP;

 if(GC_POINTER_FREE_COBJ(header)) return;

 enqueue(gcInfo.cObjects,(Word)cObject);

 size = GC_SIZE_COBJ(header);

 ptr = cObject;
 ptrEnd = ptr + size;

 for(;ptr<ptrEnd;ptr++)
   {
     if(SIMPLE_PTR_TEST(*ptr))
	{
	  child = pointerQueryEarly(*ptr);

	  if(child!=NULL)
	    {
	      childHeader = OBJECT_HEADER(child);
	      assert(OBJECT_VALID(child));
	      assert(!GC_END_LARGE(childHeader));
	      
	      if(!OBJECT_TRAVERSED(child))
		{
		  OBJECT_TRAVERSE(child);
		  STATS(gcInfo.nTraversedObjects++);
		  
		  enqueue(explicitQueue,(Word) child); 
		  pinObjectPages(child,childHeader);
		}
	    }
	}
   }
}

INLINE void processObject(Word *object, Deque *explicitQueue)
{
 Word header = OBJECT_HEADER(object);
 Word type = GC_EXTRACT_TYPE(header);

 STATS(gcInfo.nLiveWords += GC_OBJECT_SIZE(header));
 STATS(gcInfo.nLiveObjects++);

 assert(GC_EXTRACT_STATUS(header) != GC_MOVED);

 if(type==GC_RECORD)
   {
     Word bitmask;
     bitmask = GC_BITMASK_SMALL(header); 
     for(;bitmask!=0; bitmask >>=1, object++)
       {
	 if((bitmask & 0x1) && IS_POINTER(*object))
	   {
	     processChild((Word **) object,explicitQueue);
	   }
       }
     return;
   }
 else
   {
     switch(type)
       {
	 /*
       case GC_RECORD:
	 {
	   Word bitmask;
	   bitmask = GC_BITMASK_SMALL(header); 
	   for(;bitmask!=0; bitmask >>=1, object++)
	     {
	       if((bitmask & 0x1) && IS_POINTER(*object))
		 {
		   processChild((Word **) object,explicitQueue);
		 }
	     }
	   return;
	 }
	 */
       case GC_ARRAY:
	 {
	   Word *objectEnd;
	   if(GC_POINTER_ARRAY(header))
	     {
	       objectEnd = object+GC_SIZE_ARRAY(header);
	       for(;object<objectEnd;object++)
		 {
		   if(IS_POINTER(*object)) 
		     {
		       processChild((Word **) object,explicitQueue);
		     }
		 }
	     }
	   return;
	 }
       case GC_COBJ:
	 {
	   STATS(gcInfo.nCObjects++);
	   processCObject(object, header, explicitQueue);
	   return;
	 }
       case GC_LARGE_RECORD: /* Only large records should reach here. */
	 {
	   unsigned int i;
	   unsigned int size;
	   Word bitmask;
	   Word *bitmaskPtr;
       
	   size = GC_SIZE_LARGE(header);
	   bitmaskPtr = (object-2);
	   bitmask = 0;
	   for(i=0;i<size;i++,object++,bitmask>>=1)
	     {
	       if((i%WORD_SIZE) == 0) 
		 {
		   bitmask = *bitmaskPtr;
		   bitmaskPtr--;
		 }
	   
	       if((bitmask & 0x1) && IS_POINTER(*object))
		 {
		   processChild((Word **) object,explicitQueue);
		 }
	     }
	   return;
	 }
       default:
	 {
	   LOG_MESSAGE("Unexpected type found in processObject.\n");
	   assert(0);
	   exit(0); /* Unexpected type found here. */
	 }
       }
   }
}

/* Pin all the pages object resides on.  Assumes object has not been forwarded,
   and has a header word. */
void pinObjectPages(Word *object, Word header)
{
  PageInfo *pi,*piEnd;
  unsigned int size;

  size = GC_OBJECT_SIZE(header);

  if(size<=COPYABLE_OBJECT)
    {
      pi = PAGE_TO_PI(object);
      if(!PAGE_IS_PINNED(pi->header))
	{
	  PAGE_PIN(pi->header);
	  LIST_CUT(pi);
	  LIST_INSERT_BEGIN(&gcInfo.pinnedPageList,pi);

	  pinPagesObjects(pi);       
	}      
    }
  else
    {
      unsigned int headerWords;
      headerWords = GC_HEADER_WORDS(header);

      pi = PAGE_TO_PI(object - headerWords);
      piEnd = PAGE_TO_PI(object + size);
      
      for(;pi<=piEnd;pi++)
	{
	  if(!PAGE_IS_PINNED(pi->header))
	    {
	      PAGE_PIN(pi->header);
	      LIST_CUT(pi);
	      LIST_INSERT_END(&gcInfo.pinnedPageList,pi);
	      
	      pinPagesObjects(pi);       
	    }
	}
    }
}

/* EOF: object.c */

/* (c) Frederick Smith, Greg Morrisett.
 *     October 1998, all rights reserved.
 *
 *
 *              Copyright 1990-1993 Digital Equipment Corporation
 *                         All Rights Reserved
 *
 * Permission to use, copy, and modify this software and its documentation is
 * hereby granted only under the following terms and conditions.  Both the
 * above copyright notice and this permission notice must appear in all copies
 * of the software, derivative works or modified versions, and any portions
 * thereof, and both notices must appear in supporting documentation.
 *
 * Users of this software agree to the terms and conditions set forth herein,
 * and hereby grant back to Digital a non-exclusive, unrestricted, royalty-free
 * right and license under any changes, enhancements or extensions made to the
 * core functions of the software, including but not limited to those affording
 * compatibility with other hardware or software environments, but excluding
 * applications which incorporate this software.  Users further agree to use
 * their best efforts to return to Digital any such changes, enhancements or
 * extensions that they make and inform Digital of noteworthy uses of this
 * software.  Correspondence should be provided to Digital at:
 * 
 *                       Director of Licensing
 *                       Western Research Laboratory
 *                       Digital Equipment Corporation
 *                       250 University Avenue
 *                       Palo Alto, California  94301  
 * 
 * This software may be distributed (but not offered for sale or transferred
 * for compensation) to third parties, provided such third parties agree to
 * abide by the terms and conditions of this notice.  
 * 
 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */
