/* macros.h 

   Commonly used macros.  Automatically included with prototypes.h

 */

#ifndef __MACROS_H
#define __MACROS_H

#include "pageHeader.h"

/* Settings. ................................................................*/

#ifdef SCAN_ALL_OLD
#define SCAN_OLD(X) X
#else
#define SCAN_OLD(X)
#endif 

/* Define PAGE_BITMASKS if these are desired. */
#ifdef PAGE_BITMASKS
#define FOR_BITMASKS(X) X
#else
#define FOR_BITMASKS(X)
#endif

#ifdef GENERATIONS
#define GEN(X) X
#else
#define GEN(X)
#undef SCAN_ALL_OLD
#endif

#ifdef HEADER_IN_CLASS
#define ADJ_HEADER(X)
#else
/* ADJ = adjacent */
#define ADJ_HEADER(X) X
#endif

#ifdef INLINE_INNER_LOOP
#define INLINE inline
#define INLINE_STATIC static inline
#else
#define INLINE
#define INLINE_STATIC
#endif 

#ifdef PAGE_BLACKLISTING
#define BLACKLIST(X) X
#else
#define BLACKLIST(X) 
#endif

/* Required/Useful Macros ...................................................*/
#include "object.h"
#include "header.h"
#include "pageHeader.h"

/* Test whether X is really a pointer when its header word suggests it should
   be. We need this since sometimes although the word should be a pointer it may
   be NULL or contain some small tag(0-255, or -1) or point into the static
   area. */
#define IS_POINTER(X) (((unsigned int)(((int)(X))+2) > 0xFFF) && \
		       ((Word *)(X)>STATIC_TOP))

/*
#define IS_POINTER(X) (((Word *)X) >= gcInfo.heap && ((Word *)X) < gcInfo.heapEnd)
*/
/* Returns true if the pointer X is doubleword aligned. */
#define DOUBLEWORD_ALIGNED(X) ((((Word)(X)) & 0x7) == 0)

/* Bitmask Macros...............................*/

/* Determines the word offset for the Xth element in a bitmask */
#define BITMASK_WORD_OFFSET(X) (((X) & (ALL_ONES << LOG_WORD_SIZE)) >> \
				LOG_WORD_SIZE)

/* Returns the bit offset for the Xth element in a bitmask */
#define BITMASK_BIT_OFFSET(X)   ((X) & ~(ALL_ONES << LOG_WORD_SIZE))

/* Deque Macros.................................*/

/* For X of type Deque * returns non-zero if X is empty. */
#define DEQUE_EMPTY(X) ((X)->start == (X)->end)

/* Pops an element off a deque Q */
#define POP(Q) pop(Q)

/* Pushes an element onto a deque Q */
#define PUSH(Q,X) enqueue((Q),(X))

/* Block Macros.................................*/

/* P & GC_BLOCK_MASK is the pointer to the heap block for P */
#define GC_BLOCK_MASK (ALL_ONES << (LOG_BLOCK_SIZE_BYTES))

/* Returns the address of the HeapBlock X points to. */
#define BLOCK(X) (((Word)(X)) & GC_BLOCK_MASK)

/* Returns the number of the block X points to, for any pointer X */
#define BLOCK_NUMBER(X) ( ((Word)X) >> LOG_BLOCK_SIZE_BYTES )

#define BLOCK_NEXT(X) (((HeapBlock *)(X))->next)

/* Returns the address one past the last pageInfo in the current block. */
#define BLOCK_PAGE_INFO_END(X) (((PageInfo *)(X)) + PAGES_PER_BLOCK)

/* Page Macros..................................*/

/* GC_PAGE_MASK & P for any pointer P returns a pointer to the page P resides
   on. */
#define GC_PAGE_MASK (ALL_ONES << (LOG_PAGE_SIZE + LOG_WORD_SIZE - 3))

#define PAGE(X) (((Word)(X)) & GC_PAGE_MASK)

/* GC_LIMIT_PTR returns the value of the current limit ptr */
#define GC_LIMIT_PTR (((Word *)(((Word)gcAllocPtr) & GC_PAGE_MASK)) + PAGE_SIZE)

/* Returns the number of the page X points to w.r.t. this heap block. */
#define PAGE_NUMBER(X) (( ((Word)(X)) & (~GC_BLOCK_MASK & GC_PAGE_MASK)) >> \
			LOG_PAGE_SIZE_BYTES)

/* Returns the PageInfo(PI for short) structure associated with any pointer in
   the heap. */
#define PAGE_TO_PI(X) ((PageInfo *)(BLOCK(X) | \
				    ((((Word)(X))&(~GC_BLOCK_MASK&GC_PAGE_MASK)) \
				    >> (LOG_PAGE_SIZE_BYTES - \
					LOG_PI_SIZE_BYTES))))

#define PI_TO_PAGE(X) ((Word *)((Word)BLOCK(X) | \
				 (((Word)(X) & ~GC_BLOCK_MASK) << \
				  (LOG_PAGE_SIZE_BYTES - LOG_PI_SIZE_BYTES))))

/* Circular List Macros.........................*/

#define LIST_INIT(H) { (H)->next = (H); \
                       (H)->prev = (H); \
		       (H)->reserved = 0; \
                       (H)->header = 1; }

/* For a list with head H.  Returns true if H is empty. */
#define LIST_EMPTY(H) ((H)->next == (H))

/* Cut X out of the list it is in.  Assumes X is not the dummy element. */
#define LIST_CUT(X) { (X)->next->prev = (X)->prev; \
                      (X)->prev->next = (X)->next; }

/* Insert X onto the beginning of the list with dummy element H */ 
#define LIST_INSERT_BEGIN(H,X) { (X)->prev = (H); \
                                 (X)->next = (H)->next; \
				 (H)->next->prev = (X); \
				 (H)->next = (X); }

#define LIST_INSERT_END(H,X) { (X)->prev = (H)->prev; \
                               (X)->next = (H); \
                               (H)->prev->next = (X); \
			       (H)->prev = (X); }

/* Append a doubly linked (non-circular) list with head H and tail T to the 
   "end" of a circular doubly linked list L. */
#define LIST_APPEND_DOUBLY_LINKED(L,H,T)  { (H)->prev = (L)->prev; \
                                            (T)->next = (L); \
                                            (L)->prev->next = (H); \
					    (L)->prev = (T); }

/* Merge the victim list V into the list L.  V is the dummy element so is just
   thrown away. */
#define LIST_MERGE(L,V) if((V)->next!=(V)) { \
                              (L)->next->prev = (V)->prev; \
                              (V)->prev->next = (L)->next; \
                              (V)->next->prev = (L); \
                              (L)->next = (V)->next; \
			      (V)->next = (V); \
			      (V)->prev = (V); }
                              

#define FREELIST_PREV(X) ((X)->prev)

/* As above but returns the next element. */
#define FREELIST_NEXT(X) ((X)->next)

/* Pointer Macros...............................*/

/* A simple test to see if a word is a potential pointer */
#define SIMPLE_PTR_TEST_SETUP Word heapBottom = (Word)gcInfo.heap; \
                              Word heapTop = (Word)gcInfo.heapEnd;

#define SIMPLE_PTR_TEST(X) (((X) >= heapBottom) && (((X) & 0x3) == 0) \
     && ((X) < heapTop))

/* Macros for users. ........................................................*/

/* Returns a pointer one past the end of the page for pointer X. */
#define GC_PAGE_END(X) (((Word *)(((Word)(X)) & GC_PAGE_MASK)) + PAGE_SIZE)

/* Returns true if allocating an object of X words would overflow the current
   page. */
#define GC_NEED_SPACE(X) ((Word *)((((Word)(gcAllocPtr+(X))) & GC_PAGE_MASK)) \
			  > gcAllocPtr)


#ifdef GENERATIONS
/* Takes a pointer X and marks the page it is on. */
#define        GC_PAGE_MARK(X) (PAGE_MARK(PAGE_TO_PI(X)->header))

#define        GC_POP_VOLATILE pop(gcInfo.volatileObjects)
#define        GC_PUSH_VOLATILE(X) enqueue(gcInfo.volatileObjects,(Word)(X))
#else
#define        GC_PAGE_MARK(X)
#define        GC_POP_VOLATILE
#define        GC_PUSH_VOLATILE(X)
#endif

#endif

/* EOF: macros.h */
/* (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.
 */
