/*
 * @(#)gc.h	1.10 97/01/24
 * 
 * Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * This software is the confidential and proprietary information of Sun
 * Microsystems, Inc. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Sun.
 * 
 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
 * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
 * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
 * THIS SOFTWARE OR ITS DERIVATIVES.
 * 
 * CopyrightVersion 1.1_beta
 * 
 */

#ifndef _GC_H_
#define _GC_H_

#include "gc_md.h"


/*
 * Lock against heap modification.
 */
extern sys_mon_t *_heap_lock;
#define HEAP_LOCK_INIT()    monitorRegister(_heap_lock, "Heap lock")
#define HEAP_LOCK()	    sysMonitorEnter(_heap_lock)
#define HEAP_UNLOCK()	    sysMonitorExit(_heap_lock)
#define HEAP_LOCKED()	    sysMonitorEntered( _heap_lock)

/*
 * Define this if you want the mark phase to detect pointers into the
 * interior of objects.
 */
/* #define CHECK_INTERIOR_POINTERS */

#define OBJECTGRAIN     8
#define HANDLEGRAIN     8
#define BITSPERCHAR     8

/*
 * Types of overflows: we might respond to an overflow of a particular
 * error differently, e.g. expanding only the overflowing area.
 */
#define OVERFLOW_NONE	 0
#define OVERFLOW_OBJECTS 1
#define OVERFLOW_HANDLES 2

/*
 * Possible actions to take on overflows.  manageAllocFailure()
 * decides between these.
 */
#define OVERFLOW_ACT_FAIL	0
#define OVERFLOW_ACT_GC		1
#define OVERFLOW_ACT_FINALIZE	2
#define OVERFLOW_ACT_REFS	3
#define OVERFLOW_ACT_EXPAND	4
#define OVERFLOW_ACT_DESPERATE	5

/*
 * Memory block header (bottom three bits are flags):
 *
 * -------------------------------------------------------------
 * | <--- length --->| pinned | <- obj swapped -> | <- free -> |
 * -------------------------------------------------------------
 * 31		     3	      2			  1	       0
 */
typedef long hdr;

#define obj_geth(p) (*((hdr *)(p)))
#define obj_seth(p, h) (*((hdr *)(p)) = (h))
#define h_len(h) ((h) & ~(OBJECTGRAIN-1))
#define h_free(h) ((h) & 1)
#define h_bumplen(h, l) ((h) += (l))

#define obj_len(p) (obj_geth(p)&~(OBJECTGRAIN-1))
#define obj_setlf(p, l, f) (obj_geth(p) = (l)|(f))
#define obj_bumplen(p, l) (obj_geth(p) += (l))
#define obj_free(p) (obj_geth(p)&1)
#define obj_setfree(p) (obj_geth(p) |= 1)
#define obj_clearfree(p) (obj_geth(p) &= ~1)
#define obj_pinned(p) (obj_geth(p) & 4)
#define obj_pin(p) (obj_geth(p) |= 4)
#define obj_unpin(p) (obj_geth(p) &= ~4)

/*
 * The marking code relies upon the values representing the three mark
 * states to be ordered numerically: NoMark < SoftMark < HardMark.
 */
#define NoMark   0
#define SoftMark 1
#define HardMark 3

#define MarkPtr(p, v) _MarkPtr(((unsigned int) (p) & ~(OBJECTGRAIN - 1)), v)
#define ClearMarkPtr(p, v) _ClearMarkPtr(((unsigned int)(p)&~(OBJECTGRAIN-1)),v)
#define IsMarked(p) _IsMarked((unsigned int) (p) & ~(OBJECTGRAIN - 1))

#define SOFTREFBAGSIZE 200  /* max number of soft refs to kill in one cycle */


#ifndef PAGED_HEAPS /************ CONTIGUOUS HEAPS: ********************/

#define ValidObject(p)	((((int)(p)) & (OBJECTGRAIN-1)) == 0 &&	    	\
			 (unsigned char *)(p) >= opmin &&	      	\
			 (unsigned char *)(p) <  opmax)
#define ValidHandle(p)	(((int) (p) & (sizeof(JHandle)-1)) == 0 &&  	\
			 (unsigned char *)(p) >= hpmin &&	        \
			 (unsigned char *)(p) <= hpmax)
/* ValidHorO() assumes OBJECTGRAIN=sizeof(JHandle)... */
#define ValidHorO(p)	(((int) (p) & (OBJECTGRAIN-1)) == 0 &&	    	\
			 (unsigned char *)(p) >= hpmin &&		\
			 (unsigned char *)(p) <= opmax)
#define SetLimits()							\
    register unsigned char *const opmin = opool,	    		\
                           *const opmax = opoollimit,	    		\
		           *const hpmin = hpool,	   	       	\
		           *const hpmax = hpoollimit-sizeof(JHandle)

#define POP_FREE_HANDLE(hp) 						\
    hp = (JHandle *)hpoolfreelist; 					\
    if (hp) {								\
        hpoolfreelist = (unsigned char *)hp->methods;			\
    }

#define PUSH_FREE_HANDLE(hp) \
    hp->methods = (struct methodtable *)hpoolfreelist; \
    hpoolfreelist = (unsigned char *)hp;

/* Mark bit access assumes contiguity of handles and objects */
#define MARKINDEX(p)	(((unsigned char *)(p) - hpmin) >> 7)
#define BITOFFSET(p)	((((unsigned char *)(p) - hpmin) >> 2) & 0x1e)

#define _MarkPtr(p, v)	(markbits[MARKINDEX(p)] |= (v) << BITOFFSET(p))
#define _ClearMarkPtr(p, v) (markbits[MARKINDEX(p)] &= ~((v) << BITOFFSET(p)))
#define _IsMarked(p)	((markbits[MARKINDEX(p)] >> BITOFFSET(p)) &3)

/* set the second word in an object (from ptr to header) to 0x55555555 */
#define CHECK_WORD_INDEX 1

#define MAP_OVER_HANDLES_FROM_START(MO_hp) {		\
    JHandle *MOH_limit = (JHandle *) hpmax;		\
    for (MO_hp = (JHandle *) hpool; MO_hp <= MOH_limit; MO_hp++) {

#define END_MAP_OVER_HANDLES_FROM_START			\
    } /* end for */					\
} /* end MAP_OVER_HANDLES_FROM_START */

#define MAP_OVER_OBJECTS_FROM_START(p) {		\
    unsigned char *MOO_limit = opmax;			\
    unsigned char *MOO_start = opmin;			\
    for (p = opmin;					\
	 p < MOO_limit;					\
	 p += obj_len(p)) {

#define END_MAP_OVER_OBJECTS_FROM_START			\
    } /* end for */					\
} /* end END_MAP_OVER_OBJECTS_FROM_START */


#else /************ PAGED HEAPS: ********************/

/* gc philosophy makes it necessary to detect if an arbitrary int is
 * (possibly) a handle or object ref.
 * A value is (possibly) valid if it is properly aligned, and it 
 * points into a page that has a page map entry of the proper type.
 */
/* assumes ValidHorO already */
#define GetPageMapEntry(p)					  	\
	     (page_map[((int)(p) - (int)mem_base) >> PTR_2_PAGE_SHIFT])

#define ValidObject(p)	((((int)(p)) & (OBJECTGRAIN-1)) == 0 &&	    	\
	     (void *)(p) >= mem_base &&		    			\
	     (void *)(p) <  mem_top &&			    		\
	     (GetPageMapEntry((p)).chunk_size > 0))
#define ValidHandle(p)	(((((int)(p)) & (HANDLEGRAIN-1)) == 0) &&   	\
	     ((void *)(p) >= mem_base) &&		    		\
	     ((void *)(p) <  mem_top) &&		    		\
	     (GetPageMapEntry((p)).chunk_size < 0))
/* ValidHorO() assumes OBJECTGRAIN == HANDLEGRAIN... */
#define ValidHorO(p)	((((int)(p)) & (HANDLEGRAIN-1)) == 0 &&	    	\
	     (void *)(p) >= mem_base &&		    			\
	     (void *)(p) <  mem_top &&			    		\
	     (GetPageMapEntry((p)).chunk_size != 0))

#define SetLimits() int SL_dufus = 0

/* assumes ValidHorO already */
#define ChunkBase(p)	(void *)				    	\
	     (((int)(p) & ~(PAGE_ALIGNMENT - 1)) -			\
	      (GetPageMapEntry((p)).page_number << PTR_2_PAGE_SHIFT))
	     
/* curHanBlkP must be set in advance!!! */
#define POP_FREE_HANDLE(hp) 						\
    hp = (JHandle *)curHanBlkP->freePtr; 			    	\
    if (hp) {							    	\
        curHanBlkP->freePtr = (unsigned char *)hp->methods;	    	\
    }

/* Can only be called within a MAP_OVER_HANDLES_FROM_START loop 
 * - uses MOH_chunk instead of curHanBlkP for efficiency.
 */
#define PUSH_FREE_HANDLE(hp) \
    hp->methods = (struct methodtable *)MOH_chunk->freePtr; \
    MOH_chunk->freePtr = (unsigned char *)hp;

#define MARKINDEX(p)	(((int)(p) & (PAGE_ALIGNMENT - 1)) >> 7)
#define BITOFFSET(p)	((((int)(p) & (PAGE_ALIGNMENT - 1)) >> 2) & 0x1e)

#define _MarkPtr(p, v)	(GetPageMapEntry(p).mark_bits[MARKINDEX(p)] |=	   \
                         (v) << BITOFFSET(p))
#define _ClearMarkPtr(p, v) (GetPageMapEntry(p).mark_bits[MARKINDEX(p)] &= \
                             ~((v) << BITOFFSET(p)))
#define _IsMarked(p)	((GetPageMapEntry(p).mark_bits[MARKINDEX(p)]	   \
                          >> BITOFFSET(p)) & 3)

/* # of bytes of markbits we need per page: */
#define MARK_BITS_SIZE	    ((PAGE_ALIGNMENT / (OBJECTGRAIN * BITSPERCHAR)) * 2)

/*
 * Part of Java memory management and garbage collection.
 *
 * This supports a discontiguous gcable heap, which is useful for the
 * Mac OS, or other platforms without good memory mapping support.
 *
 * CHUNKS:
 * Memory is requested from the OS in "Chunks" of n pages, which are
 * PAGE_ALIGNMENT aligned and sized. Handles and objects are allocated out of
 * different chunks.  When more memory is needed, additional chunks can be
 * allocated.  When chunks are free, they may be returned to  the OS.  Chunks
 * don't need to be contiguous.  Handle chunks and object chunks are linked 
 * into seperate, doubly linked lists, which are sorted by chunk address.  On
 * platforms without real "memalign" support, there may be unaligned (wasted)
 * space that precedes the true chunk that we can use for something else 
 * (markbits come to mind).
 */
 
/* fields marked ### MUST BE OBJECT AND/OR HANDLE GRAIN ALIGNED */
typedef struct CHUNK_BLK {	/* a chunk of pages */
    void* chunkHandle;		/* OS handle to this chunk */
    struct CHUNK_BLK *nextPtr;	/* ptr to next chunk header */
    struct CHUNK_BLK *prevPtr;	/* ptr to previous chunk header */
    long chunkFlags;		/* misc flags */
    long allocSize;		/* == (endPtr - startPtr)### */
    long freeCnt;		/* # of free bytes in this chunk */
    unsigned char *startPtr;	/* ptr to starting byte### */
    unsigned char *endPtr;	/* ptr past last byte### */
    unsigned char *freePtr;	/* ptr to first free space CANDIDATE 
	* (may not really be free), or it might be a ptr to a free list
	* of objects, depending on phase of the moon.
	*/
	/* users may modify start and end ptrs, but not this one: */
    unsigned char *physEndPtr;			    
#ifdef WASTED_SPACE_IN_LEADER
	/* WARNING:  clearLocalMarkBits assumes that only markbits are stored
     	 * in the waste !!!
     	 */
    unsigned char *wasteStartPtr; /* ptr to starting wasted byte */
    unsigned char *wasteFreePtr;  /* ptr to first free wasted byte */
    				  /* wasteEndPtr == the ChunkBlk pointer */
#endif /* WASTED_SPACE_IN_LEADER*/
} ChunkBlk, *ChunkBlkP;

/* CHUNK_BLK->chunkFlags bits: */
     /* set this bit in chunkFlags if any objects in the chunk are pinned */
#define CHUNK_PINNED 1		

/* doubly-linked list of handle chunks, in address order: */
extern ChunkBlkP firstHanBlkP;	  
extern ChunkBlkP lastHanBlkP;
extern ChunkBlkP curHanBlkP;
/* doubly-linked list of object chunks, in address order: */
extern ChunkBlkP firstObjBlkP;
extern ChunkBlkP lastObjBlkP;
extern ChunkBlkP curObjBlkP;

/* store this into the last two words of the chunk to detect overwrites */
/* Odd to make a poor pointer, 111 in the low bits looks like a swapped 
 * free block if a header! */
#define ALMOST_WORD    0x77777777
#define ULTIMATE_WORD  0xBAADDEED  /* Why not. */
/* set the third word in an object (from ptr to header) to 0x55555555 */
#define CHECK_WORD_INDEX 2	   

/* Macros to abstract out looping over all handles or objects.
 * Note that you can't "break" out of this loop. Use goto or return instead.
 */
#define MAP_OVER_HANDLES_FROM_START(MO_hp) {		\
    ChunkBlkP MOH_chunk = firstHanBlkP;			\
    JHandle *MOH_limit;					\
    do {						\
	for (MO_hp = (JHandle *)MOH_chunk->startPtr,	\
	     MOH_limit = (JHandle *)MOH_chunk->endPtr;	\
	     MO_hp < MOH_limit; MO_hp++) {

#define END_MAP_OVER_HANDLES_FROM_START			\
	}  /* end for */				\
	MOH_chunk = MOH_chunk->nextPtr;			\
    } while (MOH_chunk != firstHanBlkP);		\
} /* end MAP_OVER_HANDLES_FROM_START */

#define MAP_OVER_OBJECTS_FROM_START(MO_p)   {		\
    ChunkBlkP MOO_chunk = firstObjBlkP;			\
    unsigned char *MOO_limit;				\
    unsigned char *MOO_start;				\
    do {						\
	for ((MO_p) = MOO_chunk->startPtr, 		\
	     MOO_start = MOO_chunk->startPtr,		\
	     MOO_limit = MOO_chunk->endPtr;		\
	     (MO_p) < MOO_limit;			\
	     (MO_p) += obj_len(MO_p)) {

#define END_MAP_OVER_OBJECTS_FROM_START			\
	}  /* end for */				\
	MOO_chunk = MOO_chunk->nextPtr;			\
    } while (MOO_chunk != firstObjBlkP);		\
} /* end END_MAP_OVER_OBJECTS_FROM_START */

#endif /************ END PAGED HEAPS ********************/	


#ifdef WASTED_SPACE_IN_LEADER
/* following functions defined in gc_md.c: */
void initWastedSpaceInChunk(ChunkBlkP chunk);
void sysCheckWastedSpace(ChunkBlkP chunk);
void clearLocalMarkBits(void);
void* allocMarkBitsLocally(ChunkBlkP blkP);
#else
#define initWastedSpaceInChunk(xxx) 0
#define sysCheckWastedSpace(xxx) 0
#define clearLocalMarkBits() 0
#define allocMarkBitsLocally(xxx) 0
#endif

#endif /* !_GC_H_ */
