/*$Header: /a/rathlin/disk/src/master/edml/EDML4/fam.src/UPTODATE/RCS/store.h,v 5.1 91/09/05 18:24:51 edml Exp $*/

#define TAGSHIFT    16
#define TagState     0
#define TagProcess   1
#define TagRec1      2
#define TagRec2      3
#define TagRecN      4
#define TagString    5
#define TagVariant   6
#define TagText      7
#define TagStack     8
#define TagUpRec1    9
#define TagUpRec2   10
#define TagUpRecN   11
#define TagBigInt   12    /* In the Arthur Norman version bignums are lists */
#define TagReal     13
#define TagBigVar   14
#define TagPlot     15
#define NUM_TYPES   16

/* The following typedefs describe data structures that are recognised
 * by the garbage collector.  The rest of the system may have differing
 * views of these structures.  For example an AMRec2 object may be treated
 * as a cons cell or a pair cell or a record.  The internal details of the
 * objects are unimportant.  The collector is only concerned with the length
 * of an object and the fields that can contain pointers.  For this purpose
 * the storage manager tags each object in the system.
 * The tag is always located in the longword immediately preceding the object.
 * Only the most significant word of this longword is used for tags and other
 * information used by the garbage collector.  The least significant word
 * contains information dependent on the type of the object such as the
 * length of the object if it can vary,  the particular variant an object
 * represents if it is a disjoint sum, or nothing at all in the other cases.
 */

#define PreObject_(a)  ((PreObject *)(((LWord *)(a))-1))
#define PreField_(a)   (PreObject_(a) -> prefield)
#define PreLWord_(a)   ((LWord *)(a))[-1]
#ifndef EMAS
#define MARKBIT 0x01000000  
#else
#  if (defined(MIPSEL) || defined(sgi)) /* Silicon Graphics Iris 4d */
#    define MARKBIT 0x20000000  /* ditto for dec mips */
#  else
#    define MARKBIT 0x10000000  /*emas has big virtual addresses*/
#  endif
#endif
#define TagSize 1
#define Tag_(a)        (PreObject_(a) -> tag)

/* AM: markbit below is no longer used due to portability problems. */
typedef struct PreObject {
#ifdef oddsex
   unsigned otherbits:7;
   unsigned markbit:1;
   Byte  tag;
   Word  prefield;
#else
#ifdef NOSHORTS
   unsigned prefield: 16, tag: 8, markbit: 1, otherbits: 7;
#else
   Word  prefield;
   Byte  tag;
   unsigned markbit:1;
   unsigned otherbits:7;
#endif
#endif
} PreObject;

#define AllocObject_(len,tag,presize) \
  { if ((MidOfASpace= ByteAdd_(tmpreg=(LWord)MidOfASpace,len)) > EndOfASpace) \
      { SaveRegs_, tmpreg = (LWord)Collect(len), RestoreRegs_; } \
    PreLWord_(tmpreg) = ((0xC000 + tag) << TAGSHIFT) | presize;  \
  }

#define TruncateAllocation(obj, lwordlen) \
   MidOfASpace = ((LWord *) (obj)) + (lwordlen)

/* the prefield entry is not used for this object */

#define SizeOfAMRec1_ 1 + TagSize
#define PtrsInAMRec1_ 1


#define AllAMRec1_(arg)                                    \
        AllocObject_(4+4,TagRec1,1);                       \
        ((AMRec1 *)tmpreg) -> field = (LWord *)arg

#define AllAMUpRec1_(arg)                                  \
        AllocObject_(4+4,TagUpRec1,1);                     \
        ((AMRec1 *)tmpreg) -> field = (LWord *)arg

typedef struct AMRec1 {
   LWord *field;
} AMRec1;


/* the prefield entry is not used for this object */

#define SizeOfAMRec2_  2 + TagSize
#define PtrsInAMRec2_  2

#define AllAMRec2_(arg1,arg2)                                \
        AllocObject_(8+4,TagRec2,2);                         \
        ((AMRec2 *)tmpreg) -> field1 = (LWord *)arg1;        \
        ((AMRec2 *)tmpreg) -> field2 = (LWord *)arg2

typedef struct AMRec2 {
   LWord *field1, *field2;
} AMRec2 ;


/* the prefield entry contains the number of fields in the record */

#define SizeOfAMRecN_(a) PreField_(a) + TagSize
#define PtrsInAMRecN_(a) PreField_(a)

/* RJG (int) cast for emas compiler bug */
#define AllAMRecN_(size)                                  \
        AllocObject_(((int)size * sizeof(LWord))+4,TagRecN,0); \
        PreField_(tmpreg) = size

#define AllAMUpRecN_(size)                                  \
        AllocObject_(((int)size * sizeof(LWord))+4,TagUpRecN,0); \
        PreField_(tmpreg) = size

typedef struct AMRecN {
   LWord  *firstfield;
   /* other fields may follow at this point */
} AMRecN;


/* the prefield entry contains the number of bytes of code in the text */

#define SizeOfAMText_(a) ((PreField_(a) + 3) >> 2) + 1 + TagSize
#define PtrsInAMText_ 1

/* RJG (int) cast for emas compiler bug */
#define AllAMText_(size)                                                      \
        AllocObject_( ((int)size + ((2*sizeof(LWord))-1)) & ~3 ,TagText,0);        \
        PreField_(tmpreg) = (int)size-4;                                           \
        ((AMText *)tmpreg) -> literals = NIL


typedef struct AMText {
   AMRecN    *literals;
#ifdef NOSHORTS
   unsigned ProfileVal: 16, PhiBC: 16;
#else
   SWord      ProfileVal;
   Word      PhiBC;
#endif
   Byte      firstbyte;
   /* other bytes may follow at this point */
} AMText;

/* the prefield entry contains the number of characters in the record */

#define SizeOfAMString_(a) ((PreField_(a) + 3) >> 2) + TagSize
#define PtrsInAMString_ 0

/* RJG (int) cast for emas compiler bug */
#define AllAMString_(size)                                                   \
        AllocObject_( (((LWord)((int)size + 4 + 3)) & ~3) ,TagString, 0);         \
        PreField_(tmpreg) = size

typedef struct AMString {
   char  firstchar;
   /* other characters may follow at this point   */
} AMString;

/* Reals look rather like tokens, but ImportState should look if
   they come from a different machine representation (via h.flags).
   Old Heaps may contain reals tagged as tokens!
   Make sure they are quad word aligned (groan)
   Test only works on byte addresses machines.
*/

#ifdef ALIGNREALS
#define AllAMReal_(val)                           \
        while ((LWord)MidOfASpace & 0x7) {AllocObject_(4,TagRecN,0);} \
        AllocObject_(4+8, TagReal, 8);            \
        real_(tmpreg) = val
#else
#define AllAMReal_(val)                           \
        AllocObject_(4+8, TagReal, 8);            \
        real_(tmpreg) = val
#endif

/* the prefield entry indicates which branch of the disjoint sum this object
   represents. Note that Plots are JUST like Variants */

#define SizeOfAMVariant_  1 + TagSize
#define PtrsInAMVariant_  1

#define AllAMVar_(arg,typ)                                    \
        AllocObject_(4+4,TagVariant,0);                       \
        PreField_(tmpreg) = typ;                              \
        ((AMVariant *)tmpreg) -> field = (LWord *)arg

typedef struct AMVariant {
   LWord *field;
} AMVariant;


/* RJG 03-Feb-89
 * the prefield entry is not used
 * the typ field indicates which branch of disjoint sum
 */

#define SizeOfAMBigVar_  3 + TagSize
#define PtrsInAMBigVar_  3 /*as the arg field is last*/

#define AllAMBigVar_(arg,type,str)                            \
        AllocObject_(4+12,TagBigVar,0);                       \
        ((AMBigVar *)tmpreg) -> xconname = (LWord *)str;      \
        ((AMBigVar *)tmpreg) -> typ = type;                   \
        ((AMBigVar *)tmpreg) -> field = (LWord *)arg

typedef struct AMBigVar {
   LWord *xconname;
   LWord typ;
   LWord *field;
} AMBigVar;

/* the prefield entry contains the number of number of stack entries (+ 1!) */

#define SizeOfAMStack_(a) PreField_(a)
#define PtrsInAMStack_(a,len) \
        (((a)+len-1) - ByteAdd_(a,((AMStack *)(a))->StkPos))
/* RJG (int) cast for emas compiler bug */
#define AllAMStack_(size) \
        AllocObject_(((int)size*4),TagStack,0); \
        (*((LWord *)tmpreg) = ((int)size * 4) - 4 ); \
        (((LWord *)tmpreg)[1] = 0 ); \
        PreField_(tmpreg) = size


typedef struct AMStack {
   LWord   StkPos;      /* Offset of stack bottom from beginning in bytes */
   /*   Rest of stack follows here */
} AMStack;


/* the prefield entry is not used for this object */

#define SizeOfAMState_ 17
#define PtrsInAMState_ 16
#define AllAMState_ \
        AllocObject_((SizeOfAMState_ * 4),TagState,SizeOfAMState_ - 1)

typedef struct AMState {
   LWord   *firstfield;
} AMState;


/* the prefield entry is not used for this object */

#define SizeOfAMProcess_  12
#define PtrsInAMProcess_   8
#define AllAMProcess_ \
        AllocObject_((SizeOfAMProcess_ * 4),TagProcess,SizeOfAMProcess_ - 1)

typedef struct AMProcess {
   LWord   *firstfield;
} AMProcess;

extern LWord *Collect();
extern LWord *ObjCollect();
extern LWord  GenerateHybridHeap(); 
