/*
 * @doc MODULE
 * @module garbage.c |
 *
 * Procedures for implementing the memory management for objects and arrays
 * and the mark-and-sweep-style garbage collection thereof. The only two
 * external procedures are GARBAGE_Malloc which is caled when memory is
 * required and GARBAGE_gc which does garbage collection and frees memory
 * that is finds is no longer required.
 *
 */

/*
   Sun Jan 30 01:20:51 SAST 2000 - Jewel, I moved all the PERSISTENCE / EVICTIONS stuff into a file called persist.c
 
   That leaves only 2000 lines in garbage, and about 1600 in persist.c
   
   Sat Jan 29 20:36:39 SAST 2000 - Jewel
 
   I have to read through this code and figure out how it works. This is to facilitate native threading and also to get persistence functional again.
 
   Init -	calls NewHeapBlock and assigns it to pstHeapList
		sets pointers into heap for highest / lowest
		sets lowest / highest handle value
		sets up pointers to the finalize UID
 
   NewHeapBlock - takes the size of bytes required and number of handles to allocate
		  mallocs the memory for a tHeapBlock, 
		  stores size inside the allocated memory
		  makes a bitfield, which is 1/32th of the heap size
		  stores BF size 
		  allocates the memory for the actual heap (pstHeap->pi32Heap)
		  allocates the memory for the bitfield, zeroes it (pstHeap->pi32BitField)
		  update high/low heap pointers if neccessary
 
		  figure out how many handles are in this block (round) (pstHeap->i32NumHandles)
		  decrease the BF size by the amount taken up by handles
		  
		  initialise the handles, set them all to point the next one,
		  these are all the int32s at the back end of the heap (a handle block)
		  the last handle points to 0
 
		  then the pstHeap->hFirstFreeHandle points to last word in heap
		  
		  now set pstHeap->pi32FirstFree to point to pstHeap->pi32Heap (ie the Heap itself)
		  and pstHeap->pi32Heap[0] = i32HeapSize - i32NumHandles; first word of free block
                                 is size of heap minus space for handles
                                 both given in 32-bit words 
 
		 the second word points to next heap block (?) (NULL)
		 pstHeap->pstNext = NULL;
 
PrintObjects-	Hmm, just a rough summary
 
		loops through all tHeapBlocks
		iterates through each bitfield
		find out which bits are set
		print out address and type of each object
 
GARBAGE_Alloc_Handle-
		iterate through all the tHeapBlocks (linked from pstHeapList)
		call AllocHandle( iterated block )
		if it succeds, return the tOBREF, else continue iterating
 
Alloc_Handle-	gets passed a tHeapBlock pstTempHB
		if pstTempHB does not have a valid hFirstFreeHandle then
			
		see if there are enough words free to allocate more handles
		if not then force a GC
 
		now we are increasing the handle area
		we move pi32FirstFree[0] back to accomodate more handles
		then set all the handles to point to the next one
		set last one to 0
		set hFirstFreeHandle to point to the first new handle
		increment the handle count
		adjust the size of the bitfield (make it smaller)
 
	        end if
 
		get the first free handle from pstTempHB->hFirstFreeHandle
		make sure hFirstFreeHandle gets moved on
		
		return the new handle (tOBREF)
 
InternalMallocFunc -	gets passed a tHeapBlock and the amount of int32s we need to free up
		        also gets a parameter indicating whether or not to allocate a handle
 
			if the iUseHandle is true, then hNewHandle is assigned from AllocHandle( pstTempHB)
 
			
			check if there is enough space to grant request for memory
 
			if not, do a GC now
 
			now set a pointer to Free Space pi32TempFS to pstTempHB->pi32FirstFree
			(this is the beginning of a new object)
			shift the free space pointer forward
			pstTempHB->pi32FirstFree += i32Size
			update the size of the free space
			record how much we allocated in pi32TempFS[0]
			mark this space in the bitfield
			if useHandle
 set the hNewHandle to point to this new free space 
 update the objects reference to the handle
			  return the handle
			else
			 set the object s handle to NULL
			return a pointer to the space
			
ItemInHeap -	Takes an tOBREF and checks if it points into the heap
 
		cycle through all tHeapBlocks
		if the pointer points into the heap block, return the tHeapBlock
 
MarkReachableFromMachine - (no evictions)
				Get the first thread stack with THREAD_FirstThreadStack
				go through all the stacks by calling NextThreadStack
				 for this frame, iterate through all the ancestor frames
				  if the frame has a pstCurrObject then 
				   call recursivelyMark with the pstCurrObject, 0, GARBAGE_REACHABLE
 
				  now we go through the java operand stack
				   for each of the up to 256 stack variables
				    if that operand is a handle
				     do recursivelyMark with that handle, 1, GARBAGE_REACHABLE
			           end for
				  
				   go through local variables
				   for each local var
				     if it is a handle
				      recursivelyMark( handle, 0, GARBAGE_REACHABLE
				   end for
 
				   Get the pstJNIData with THREAD_GetCurrentJNIData
				   for each of pstJNIData->ppstLocalRefs[i]
				    recursivelyMark( handle, 0, GARBAGE_REACHABLE)
				   end for
 
				   for each of the JNI global refs
				    do the same
				   end for
 
				   Now we examine the C stack for more objects
				   Start at INTERP_pi32MainStack, go down to the i variable's address
				    if the pointer is a handle
				     recursivelyMark( handle, 1, GARBAGE_REACHABLE)
				    else
				     if it is HEAP BOUND we have a problem
				   
				   Now iterate through the list of classes
				   for each class
				    for each static variable
				     if it is a handle
				      recursivelyMark ( handle, 1, GARBAGE_REACHABLE)
				    end for
 
				  if the class has a pstClassObject then
				   recursivelyMark( handle, 0, GARBAGE_REACHABLE)
 
				   that's it
 
SweepAndCompact -		iterate through all tHeapBlocks
				 set a pointer to the base of the block
				  loop through all the BitField ints
				   check if a block is marked
				    if so
				     check if it is GARBAGE_REACHABLE, if so reset the flag
				     
				    grab its location and see if its at the top of the heap
				    if not, then clear its bit in the bitfield
				     check its size
				     check how big our hole is
				    if they don't overlap, memcpy the object to the new pi32NewTop
				    else do it int by int
				    
				    now set the bit in the BF for the new position
				    update the objects handle
				    update the objects pi32Vars or  pvElements pointer
 
				    //some persistence stuff
				    
				    move up pi32NewTop
			      else if object not reachable
			       clear its bitfield
			       check if it has a finalize method
			        call the finalize method
 
				//persistence stuff
				update the free memory handle (reuse the handle)
				
			   end iteration through bitfield
			  
			   set the pi32FirstFree to pi32NewTop
			   set the size
			   finished
 
RecursivelyMark -		Takes an object handle, flag whether to check the BF, garbage flag
 
			if bitfield check
				Work out distance of object from start of heap block
				check the bitfield to see if is the start of an object
				return if there is no bit set
			end if
 
			check if item has been marked
			 if yes return, else mark it
			 
			if it is an object
			 then for all instances fields
			  if it is an array or object mark it
			   if it's null or pid, then skip
			   else if the instance field is a handle
			    markrecursively 0, flag
 
			go up to the super class
 
			end if object
 
		        if array then iterate through elements
			  if HEAPBOUND then recursivelyMark , 0, flag
		      end all
 
GARBAGE_malloc (int32 i32Size) size of mem required in bytes
 
			if not initialized then Init()
			 round size up to 4 bytes
			 make it in terms of int32's
			 get space and ask for a handle from
			   InternalMallocFunc( pstHeapList, i32Size, 1);
			 return handle
 
GARBAGE_MallocPtr, takes i32Size ... called from RPOT_FaultObject
 
GARBAGE_Finish -	go through pstHeapList
			free all the heaps
			free bitfields
			free tHeapBlock structs
			remove pstHeapList
			set initialized to false
			
GARBAGE_gc - Calls MarkReachableFromMachine
		   MarkReachableFromRPOT
		   SweepAndCompactx
 */


/*
 * @doc TOPIC
 * @topic Garbage Collection |
 *
 * THIS MUST BE UPDATED!!
 *
 * Garbage collection is needed so that memory that is no longer needed can
 * automatically be freed for reuse. A special memory allocation procedure is
 * supplied to allocate memory that is eligible for garbage collection. This
 * procedure is GARBAGE_Malloc. It behaves in the same way as malloc,
 * returning a pointer to the required amount of available memory. This
 * memory does not have to be freed explicitly by the programmer. When the
 * GARBAGE_gc procedure is called, it runs through all the memory that has
 * been allocated and determines which of these allocated items are no longer
 * accessible by the program and they are freed.
 *
 * The first time GARBAGE_Malloc is called, the system is initialised with
 * a call to Init. Init then allocates the amount of memory that is
 * specified in the GARBAGE_INITIALHEAPSIZE definition. Information about
 * this block of memory is kept in a tHeapBlock structure (including a pointer
 * to the actual block of memory). When GARBAGE_Malloc is called, a section
 * of this block of memory is allocated for use. Should the block become full,
 * a new block is allocated. This new block will be twice the size of the
 * old block. The old tHeapBlock structure's pstNext pointer is set to point
 * to the new tHeapBlock structure. In this way, a linked list of heap blocks
 * is created. The granularity of the memory in these heap blocks is 32 bits
 * (int32s).
 *
 * In between the allocated spaces in a heap block will be free spaces. These
 * free spaces are organised into a linked list. Some of the actual space in
 * the free spaces is used to construct this list. The first int32 of a free
 * space is used to store the size (in int32s) of that free space. The next
 * int32 of the free space is used to store a pointer (an int32*) to the
 * next free space in the current heap block. If a particular free space is
 * the last free space in its heap block then its next pointer is NULL. A
 * pointer to the first free space in a heap block is stored in its
 * tHeapBlock structure.
 *
 * As with free spaces, some of an allocated space is used to store system
 * information. The first int32 of an allocated space is used to store the
 * size of that allocated space.
 *
 * When an allocation is requested, the list of heap blocks must be searched
 * for a big enough free space. The linked list of free spaces is traversed
 * (starting with the pi32FirstFree pointer in a heap block's tHeapBlock
 * structure). When a large enough free space is found, the size of the
 * allocated space is stored in its first int32. The size of the remaining
 * _free_ space is calculated and stored at its beginning (ie just after the
 * end of the allocated space) along with the pointer to the next free
 * space (which will be the same as the old big free space's "next" pointer).
 * If the free space that we're using is the first free space in a heap block
 * then we have to update that heap block's pi32FirstFree pointer. If a free
 * space is found that is big enough but will have a remaining free space less
 * than the size specified in GARBAGE_MINFREESIZE then that space is combined
 * into the allocated space so that it can be freed with it. The type of an
 * allocated space (ie object or array) is stored in the i32Flags field of
 * the object or array along with a magic number.
 *
 * When GARBAGE_gc() is called, all the currently reachable objects and arrays
 * have to be found. Those that are not currently reachable can then be
 * discarded and their memory reused. GARBAGE_gc() is called if
 * GARBAGE_Malloc() cannot find a large enough free space. If, after calling
 * GARBAGE_gc() it still cannot find a large enough free space then a new
 * heap block is allocated.
 *
 * First, we have to check each entry in the operand stack and each of the
 * local variables in the current stack frame. If any of these are objects
 * or arrays then they need to be marked as reachable. This procedure is
 * repeated for all the previous Java environment frames as well. If an
 * object is found then all of its fields have to be marked as well if they
 * are objects or arrays (same with arrays of arrays or arrays of objects).
 * Next, the C stack is examined for possible objects or arrays. This is
 * necessary because there could be objects or arrays that have been
 * allocated but not yet stored on the stack or in local variables by the
 * interpreter. When possible object or array pointers are found on the C
 * stack or the Java stack then a check is done to see if the space pointed to
 * is the beginning of a object by checking the bit field for the relevant
 * heap block. This is required since there can be some pointers to arbitrary
 * places in our heap blocks on the C stack and we need to make sure that they
 * are genuine. If a native method is currently being executed then we need
 * to check the JNI local references. We also have to check the JNI global
 * references. Finally, the static fields of all classes that contain them
 * are checked and marked if appropriate. If an object or array is found
 * that has already been marked then it is ignored as it has already been
 * found and we don't want to end up looping infinitely.
 *
 * A procedure called RecursivelyMark() is used to mark objects and arrays
 * as reachable (and in turn mark their appropriate fields, etc...). A macro
 * HEAPBOUND() is supplied to make a quick check to see if a value could be
 * a pointer into one of the heap blocks. This is a very rough check which
 * just compares the pointer to the current highest and current lowest
 * boundaries of any of the heap blocks. A more accurate check is made inside
 * RecursivelyMark() if the HEAPBOUND() check passes.
 *
 * When all the reachable objects and arrays have been marked, the sweeping
 * phase begins. With each heap block, a bit field is kept. This bit field
 * stores the start addresses of all allocated spaces in the heap block. We
 * use this bit field to find the start addresses of all the allocated spaces
 * and then we check to see if the spaces have been marked as reachable. If
 * a space is marked then we unmark it (so that it'll be clear for the next
 * garbage collection) and forget about it. If a space is unmarked when we
 * get to it then it is unreachable and is freed for future use.
 *
 * When a space is freed, its bit field entry is cleared and it is added to
 * the linked list of free spaces. Should this new free space border on
 * another free space then the two are combined to keep fragmentation down.
 * Compaction of allocated spaces is not used.
 *
 */