[project @ 2001-07-23 22:19:59 by ken]
[ghc-hetmet.git] / ghc / includes / StgMacros.h
index c4b1e52..444a5c2 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
 /* -----------------------------------------------------------------------------
- * $Id: StgMacros.h,v 1.12 1999/06/25 09:13:38 simonmar Exp $
+ * $Id: StgMacros.h,v 1.37 2000/12/04 12:31:20 simonmar Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
  *
  * (c) The GHC Team, 1998-1999
  *
 #define EF_(f)         extern F_ f(void)
 #define EDF_(f)                extern DLLIMPORT F_ f(void)
 
 #define EF_(f)         extern F_ f(void)
 #define EDF_(f)                extern DLLIMPORT F_ f(void)
 
+#define EXTINFO_RTS    extern DLL_IMPORT_RTS INFO_TBL_CONST StgInfoTable
 #define ED_            extern
 #define ED_            extern
-#define EDD_           extern DLLIMPORT 
+#define EDD_           extern DLLIMPORT
 #define ED_RO_         extern const
 #define ED_RO_         extern const
-#define ID_            extern
-#define ID_RO_         extern const
+#define ID_            static
+#define ID_RO_         static const
 #define EI_             extern INFO_TBL_CONST StgInfoTable
 #define EDI_            extern DLLIMPORT INFO_TBL_CONST StgInfoTable
 #define EI_             extern INFO_TBL_CONST StgInfoTable
 #define EDI_            extern DLLIMPORT INFO_TBL_CONST StgInfoTable
-#define II_             extern INFO_TBL_CONST StgInfoTable
+#define II_             static INFO_TBL_CONST StgInfoTable
 #define EC_            extern StgClosure
 #define EDC_           extern DLLIMPORT StgClosure
 #define EC_            extern StgClosure
 #define EDC_           extern DLLIMPORT StgClosure
-#define IC_            extern StgClosure
+#define IC_            static StgClosure
 #define ECP_(x)                extern const StgClosure *(x)[]
 #define EDCP_(x)       extern DLLIMPORT StgClosure *(x)[]
 #define ECP_(x)                extern const StgClosure *(x)[]
 #define EDCP_(x)       extern DLLIMPORT StgClosure *(x)[]
-#define ICP_(x)                extern const StgClosure *(x)[]
+#define ICP_(x)                static const StgClosure *(x)[]
 
 /* -----------------------------------------------------------------------------
    Stack Tagging.
 
 /* -----------------------------------------------------------------------------
    Stack Tagging.
    words in the block.
    -------------------------------------------------------------------------- */
 
    words in the block.
    -------------------------------------------------------------------------- */
 
-#ifndef DEBUG_EXTRA
 #define ARGTAG_MAX 16          /* probably arbitrary */
 #define ARG_TAG(n)  (n)
 #define ARGTAG_MAX 16          /* probably arbitrary */
 #define ARG_TAG(n)  (n)
-#define ARG_SIZE(n) stgCast(StgWord,n)
+#define ARG_SIZE(n) (StgWord)n
 
 typedef enum {
     REALWORLD_TAG = 0,
 
 typedef enum {
     REALWORLD_TAG = 0,
-    INT_TAG    = sizeofW(StgInt), 
-    INT64_TAG  = sizeofW(StgInt64), 
-    WORD_TAG   = sizeofW(StgWord), 
-    ADDR_TAG   = sizeofW(StgAddr), 
-    CHAR_TAG   = sizeofW(StgChar),
-    FLOAT_TAG  = sizeofW(StgFloat), 
-    DOUBLE_TAG = sizeofW(StgDouble), 
-    STABLE_TAG = sizeofW(StgWord), 
+    INT_TAG       = sizeofW(StgInt), 
+    INT64_TAG     = sizeofW(StgInt64), 
+    WORD_TAG      = sizeofW(StgWord), 
+    ADDR_TAG      = sizeofW(StgAddr), 
+    CHAR_TAG      = sizeofW(StgChar),
+    FLOAT_TAG     = sizeofW(StgFloat), 
+    DOUBLE_TAG    = sizeofW(StgDouble), 
+    STABLE_TAG    = sizeofW(StgWord), 
 } StackTag;
 
 } StackTag;
 
-#else /* DEBUG_EXTRA */
-
-typedef enum {
-    ILLEGAL_TAG,
-    REALWORLD_TAG,
-    INT_TAG    ,
-    INT64_TAG  ,
-    WORD_TAG   ,
-    ADDR_TAG   ,
-    CHAR_TAG   ,
-    FLOAT_TAG  ,
-    DOUBLE_TAG ,
-    STABLE_TAG ,
-    ARGTAG_MAX = DOUBLE_TAG
-} StackTag;
-
-/* putting this in a .h file generates many copies - but its only a 
- * debugging build.
- */
-static StgWord stg_arg_size[] = {
-    [REALWORLD_TAG] = 0,
-    [INT_TAG   ] = sizeofW(StgInt), 
-    [INT64_TAG ] = sizeofW(StgInt64), 
-    [WORD_TAG  ] = sizeofW(StgWord), 
-    [ADDR_TAG  ] = sizeofW(StgAddr), 
-    [CHAR_TAG  ] = sizeofW(StgChar),
-    [FLOAT_TAG ] = sizeofW(StgFloat), 
-    [DOUBLE_TAG] = sizeofW(StgDouble),
-    [STABLE_TAG] = sizeofW(StgWord)
-};
-
-#define ARG_SIZE(tag) stg_arg_size[stgCast(StgWord,tag)]
-
-#endif /* DEBUG_EXTRA */
-
 static inline int IS_ARG_TAG( StgWord p );
 static inline int IS_ARG_TAG( StgWord p ) { return p <= ARGTAG_MAX; }
 
 static inline int IS_ARG_TAG( StgWord p );
 static inline int IS_ARG_TAG( StgWord p ) { return p <= ARGTAG_MAX; }
 
@@ -174,22 +139,22 @@ static inline int IS_ARG_TAG( StgWord p ) { return p <= ARGTAG_MAX; }
        }
        
 #define HP_CHK(headroom,ret,r,layout,tag_assts)                        \
        }
        
 #define HP_CHK(headroom,ret,r,layout,tag_assts)                        \
+        DO_GRAN_ALLOCATE(headroom)                              \
        if ((Hp += headroom) > HpLim) {                         \
            EXTFUN_RTS(stg_chk_##layout);                       \
            tag_assts                                           \
            (r) = (P_)ret;                                      \
            JMP_(stg_chk_##layout);                             \
        if ((Hp += headroom) > HpLim) {                         \
            EXTFUN_RTS(stg_chk_##layout);                       \
            tag_assts                                           \
            (r) = (P_)ret;                                      \
            JMP_(stg_chk_##layout);                             \
-       }                                                       \
-        TICK_ALLOC_HEAP(headroom);
+       }
 
 #define HP_STK_CHK(stk_headroom,hp_headroom,ret,r,layout,tag_assts) \
 
 #define HP_STK_CHK(stk_headroom,hp_headroom,ret,r,layout,tag_assts) \
+        DO_GRAN_ALLOCATE(hp_headroom)                              \
        if (Sp - stk_headroom < SpLim || (Hp += hp_headroom) > HpLim) { \
            EXTFUN_RTS(stg_chk_##layout);                       \
            tag_assts                                           \
            (r) = (P_)ret;                                      \
            JMP_(stg_chk_##layout);                             \
        if (Sp - stk_headroom < SpLim || (Hp += hp_headroom) > HpLim) { \
            EXTFUN_RTS(stg_chk_##layout);                       \
            tag_assts                                           \
            (r) = (P_)ret;                                      \
            JMP_(stg_chk_##layout);                             \
-       }                                                       \
-        TICK_ALLOC_HEAP(hp_headroom);
+       }
 
 /* -----------------------------------------------------------------------------
    A Heap Check in a case alternative are much simpler: everything is
 
 /* -----------------------------------------------------------------------------
    A Heap Check in a case alternative are much simpler: everything is
@@ -203,6 +168,10 @@ static inline int IS_ARG_TAG( StgWord p ) { return p <= ARGTAG_MAX; }
    functions.  In all these cases, node points to a closure that we
    can just enter to restart the heap check (the NP stands for 'node points').
 
    functions.  In all these cases, node points to a closure that we
    can just enter to restart the heap check (the NP stands for 'node points').
 
+   In the NP case GranSim absolutely has to check whether the current node 
+   resides on the current processor. Otherwise a FETCH event has to be
+   scheduled. All that is done in GranSimFetch. -- HWL
+
    HpLim points to the LAST WORD of valid allocation space.
    -------------------------------------------------------------------------- */
 
    HpLim points to the LAST WORD of valid allocation space.
    -------------------------------------------------------------------------- */
 
@@ -214,38 +183,39 @@ static inline int IS_ARG_TAG( StgWord p ) { return p <= ARGTAG_MAX; }
        }
 
 #define HP_CHK_NP(headroom,ptrs,tag_assts)                     \
        }
 
 #define HP_CHK_NP(headroom,ptrs,tag_assts)                     \
+        DO_GRAN_ALLOCATE(headroom)                              \
        if ((Hp += (headroom)) > HpLim) {                       \
            EXTFUN_RTS(stg_gc_enter_##ptrs);                    \
             tag_assts                                          \
            JMP_(stg_gc_enter_##ptrs);                          \
        if ((Hp += (headroom)) > HpLim) {                       \
            EXTFUN_RTS(stg_gc_enter_##ptrs);                    \
             tag_assts                                          \
            JMP_(stg_gc_enter_##ptrs);                          \
-       }                                                       \
-        TICK_ALLOC_HEAP(headroom);
+       }
 
 #define HP_CHK_SEQ_NP(headroom,ptrs,tag_assts)                 \
 
 #define HP_CHK_SEQ_NP(headroom,ptrs,tag_assts)                 \
+        DO_GRAN_ALLOCATE(headroom)                              \
        if ((Hp += (headroom)) > HpLim) {                       \
            EXTFUN_RTS(stg_gc_seq_##ptrs);                      \
             tag_assts                                          \
            JMP_(stg_gc_seq_##ptrs);                            \
        if ((Hp += (headroom)) > HpLim) {                       \
            EXTFUN_RTS(stg_gc_seq_##ptrs);                      \
             tag_assts                                          \
            JMP_(stg_gc_seq_##ptrs);                            \
-       }                                                       \
-        TICK_ALLOC_HEAP(headroom);
+       }
 
 #define HP_STK_CHK_NP(stk_headroom, hp_headroom, ptrs, tag_assts) \
 
 #define HP_STK_CHK_NP(stk_headroom, hp_headroom, ptrs, tag_assts) \
+        DO_GRAN_ALLOCATE(hp_headroom)                              \
        if ((Sp - (stk_headroom)) < SpLim || (Hp += (hp_headroom)) > HpLim) { \
            EXTFUN_RTS(stg_gc_enter_##ptrs);                    \
             tag_assts                                          \
            JMP_(stg_gc_enter_##ptrs);                          \
        if ((Sp - (stk_headroom)) < SpLim || (Hp += (hp_headroom)) > HpLim) { \
            EXTFUN_RTS(stg_gc_enter_##ptrs);                    \
             tag_assts                                          \
            JMP_(stg_gc_enter_##ptrs);                          \
-       }                                                       \
-        TICK_ALLOC_HEAP(hp_headroom);
+       }
+
 
 /* Heap checks for branches of a primitive case / unboxed tuple return */
 
 #define GEN_HP_CHK_ALT(headroom,lbl,tag_assts)                 \
 
 /* Heap checks for branches of a primitive case / unboxed tuple return */
 
 #define GEN_HP_CHK_ALT(headroom,lbl,tag_assts)                 \
+        DO_GRAN_ALLOCATE(headroom)                              \
        if ((Hp += (headroom)) > HpLim) {                       \
            EXTFUN_RTS(lbl);                                    \
             tag_assts                                          \
            JMP_(lbl);                                          \
        if ((Hp += (headroom)) > HpLim) {                       \
            EXTFUN_RTS(lbl);                                    \
             tag_assts                                          \
            JMP_(lbl);                                          \
-       }                                                       \
-        TICK_ALLOC_HEAP(headroom);
+       }
 
 #define HP_CHK_NOREGS(headroom,tag_assts) \
     GEN_HP_CHK_ALT(headroom,stg_gc_noregs,tag_assts);
 
 #define HP_CHK_NOREGS(headroom,tag_assts) \
     GEN_HP_CHK_ALT(headroom,stg_gc_noregs,tag_assts);
@@ -324,17 +294,20 @@ static inline int IS_ARG_TAG( StgWord p ) { return p <= ARGTAG_MAX; }
 
 #define HP_CHK_GEN(headroom,liveness,reentry,tag_assts)        \
    if ((Hp += (headroom)) > HpLim ) {                  \
 
 #define HP_CHK_GEN(headroom,liveness,reentry,tag_assts)        \
    if ((Hp += (headroom)) > HpLim ) {                  \
-       EF_(stg_gen_chk);                               \
+       EXTFUN_RTS(stg_gen_chk);                                \
         tag_assts                                      \
        R9.w = (W_)LIVENESS_MASK(liveness);             \
         R10.w = (W_)reentry;                           \
         JMP_(stg_gen_chk);                             \
         tag_assts                                      \
        R9.w = (W_)LIVENESS_MASK(liveness);             \
         R10.w = (W_)reentry;                           \
         JMP_(stg_gen_chk);                             \
-   }                                                   \
-   TICK_ALLOC_HEAP(headroom);
+   }
+
+#define HP_CHK_GEN_TICKY(headroom,liveness,reentry,tag_assts)  \
+   HP_CHK_GEN(headroom,liveness,reentry,tag_assts);            \
+   TICK_ALLOC_HEAP_NOCTR(headroom)
 
 #define STK_CHK_GEN(headroom,liveness,reentry,tag_assts)       \
    if ((Sp - (headroom)) < SpLim) {                            \
 
 #define STK_CHK_GEN(headroom,liveness,reentry,tag_assts)       \
    if ((Sp - (headroom)) < SpLim) {                            \
-       EF_(stg_gen_chk);                                       \
+       EXTFUN_RTS(stg_gen_chk);                                        \
         tag_assts                                              \
        R9.w = (W_)LIVENESS_MASK(liveness);                     \
         R10.w = (W_)reentry;                                   \
         tag_assts                                              \
        R9.w = (W_)LIVENESS_MASK(liveness);                     \
         R10.w = (W_)reentry;                                   \
@@ -343,7 +316,7 @@ static inline int IS_ARG_TAG( StgWord p ) { return p <= ARGTAG_MAX; }
 
 #define MAYBE_GC(liveness,reentry)             \
    if (doYouWantToGC()) {                      \
 
 #define MAYBE_GC(liveness,reentry)             \
    if (doYouWantToGC()) {                      \
-       EF_(stg_gen_hp);                        \
+       EXTFUN_RTS(stg_gen_hp);                 \
        R9.w = (W_)LIVENESS_MASK(liveness);     \
         R10.w = (W_)reentry;                   \
         JMP_(stg_gen_hp);                      \
        R9.w = (W_)LIVENESS_MASK(liveness);     \
         R10.w = (W_)reentry;                   \
         JMP_(stg_gen_hp);                      \
@@ -356,8 +329,8 @@ static inline int IS_ARG_TAG( StgWord p ) { return p <= ARGTAG_MAX; }
    out to be slowing us down we can make specialised ones.
    -------------------------------------------------------------------------- */
 
    out to be slowing us down we can make specialised ones.
    -------------------------------------------------------------------------- */
 
-EF_(stg_gen_yield);
-EF_(stg_gen_block);
+EXTFUN_RTS(stg_gen_yield);
+EXTFUN_RTS(stg_gen_block);
 
 #define YIELD(liveness,reentry)                        \
   {                                            \
 
 #define YIELD(liveness,reentry)                        \
   {                                            \
@@ -375,10 +348,29 @@ EF_(stg_gen_block);
 
 #define BLOCK_NP(ptrs)                         \
   {                                            \
 
 #define BLOCK_NP(ptrs)                         \
   {                                            \
-    EF_(stg_block_##ptrs);                     \
+    EXTFUN_RTS(stg_block_##ptrs);                      \
     JMP_(stg_block_##ptrs);                    \
   }
 
     JMP_(stg_block_##ptrs);                    \
   }
 
+#if defined(PAR)
+/*
+  Similar to BLOCK_NP but separates the saving of the thread state from the
+  actual jump via an StgReturn
+*/
+
+#define SAVE_THREAD_STATE(ptrs)                  \
+  ASSERT(ptrs==1);                               \
+  Sp -= 1;                                       \
+  Sp[0] = R1.w;                                  \
+  SaveThreadState();                             
+
+#define THREAD_RETURN(ptrs)                      \
+  ASSERT(ptrs==1);                               \
+  CurrentTSO->what_next = ThreadEnterGHC;        \
+  R1.i = ThreadBlocked;                          \
+  JMP_(StgReturn);                               
+#endif
+
 /* -----------------------------------------------------------------------------
    CCall_GC needs to push a dummy stack frame containing the contents
    of volatile registers and variables.  
 /* -----------------------------------------------------------------------------
    CCall_GC needs to push a dummy stack frame containing the contents
    of volatile registers and variables.  
@@ -386,11 +378,8 @@ EF_(stg_gen_block);
    We use a RET_DYN frame the same as for a dynamic heap check.
    ------------------------------------------------------------------------- */
 
    We use a RET_DYN frame the same as for a dynamic heap check.
    ------------------------------------------------------------------------- */
 
-#if COMPILING_RTS
-EI_(stg_gen_chk_info);
-#else
-EDI_(stg_gen_chk_info);
-#endif
+EXTINFO_RTS(stg_gen_chk_info);
+
 /* -----------------------------------------------------------------------------
    Vectored Returns
 
 /* -----------------------------------------------------------------------------
    Vectored Returns
 
@@ -414,22 +403,54 @@ EDI_(stg_gen_chk_info);
    Misc
    -------------------------------------------------------------------------- */
 
    Misc
    -------------------------------------------------------------------------- */
 
+
 /* set the tag register (if we have one) */
 #define SET_TAG(t)  /* nothing */
 
 #ifdef EAGER_BLACKHOLING
 /* set the tag register (if we have one) */
 #define SET_TAG(t)  /* nothing */
 
 #ifdef EAGER_BLACKHOLING
-#  define UPD_BH_UPDATABLE(thunk)                        \
-        TICK_UPD_BH_UPDATABLE();                         \
-        SET_INFO((StgClosure *)thunk,&BLACKHOLE_info)
-#  define UPD_BH_SINGLE_ENTRY(thunk)                     \
-        TICK_UPD_BH_SINGLE_ENTRY();                      \
-        SET_INFO((StgClosure *)thunk,&SE_BLACKHOLE_info)
+#  ifdef SMP
+#    define UPD_BH_UPDATABLE(info)                             \
+        TICK_UPD_BH_UPDATABLE();                               \
+        {                                                      \
+         bdescr *bd = Bdescr(R1.p);                            \
+          if (bd->back != (bdescr *)BaseReg) {                 \
+             if (bd->gen->no >= 1 || bd->step->no >= 1) {      \
+                LOCK_THUNK(info);                              \
+             } else {                                          \
+                EXTFUN_RTS(stg_gc_enter_1_hponly);             \
+                JMP_(stg_gc_enter_1_hponly);                   \
+             }                                                 \
+          }                                                    \
+       }                                                       \
+        SET_INFO(R1.cl,&stg_BLACKHOLE_info)
+#    define UPD_BH_SINGLE_ENTRY(info)                          \
+        TICK_UPD_BH_SINGLE_ENTRY();                            \
+        {                                                      \
+         bdescr *bd = Bdescr(R1.p);                            \
+          if (bd->back != (bdescr *)BaseReg) {                 \
+             if (bd->gen->no >= 1 || bd->step->no >= 1) {      \
+                LOCK_THUNK(info);                              \
+             } else {                                          \
+                EXTFUN_RTS(stg_gc_enter_1_hponly);             \
+                JMP_(stg_gc_enter_1_hponly);                   \
+             }                                                 \
+          }                                                    \
+       }                                                       \
+        SET_INFO(R1.cl,&stg_BLACKHOLE_info)
+#  else
+#    define UPD_BH_UPDATABLE(info)             \
+        TICK_UPD_BH_UPDATABLE();               \
+        SET_INFO(R1.cl,&stg_BLACKHOLE_info)
+#    define UPD_BH_SINGLE_ENTRY(info)          \
+        TICK_UPD_BH_SINGLE_ENTRY();            \
+        SET_INFO(R1.cl,&stg_SE_BLACKHOLE_info)
+#  endif
 #else /* !EAGER_BLACKHOLING */
 #  define UPD_BH_UPDATABLE(thunk)    /* nothing */
 #  define UPD_BH_SINGLE_ENTRY(thunk) /* nothing */
 #endif /* EAGER_BLACKHOLING */
 
 #else /* !EAGER_BLACKHOLING */
 #  define UPD_BH_UPDATABLE(thunk)    /* nothing */
 #  define UPD_BH_SINGLE_ENTRY(thunk) /* nothing */
 #endif /* EAGER_BLACKHOLING */
 
-#define UPD_FRAME_UPDATEE(p)  (((StgUpdateFrame *)(p))->updatee)
+#define UPD_FRAME_UPDATEE(p)  ((P_)(((StgUpdateFrame *)(p))->updatee))
 #define UPDATE_SU_FROM_UPD_FRAME(p) (Su=((StgUpdateFrame *)(p))->link)
 
 /* -----------------------------------------------------------------------------
 #define UPDATE_SU_FROM_UPD_FRAME(p) (Su=((StgUpdateFrame *)(p))->link)
 
 /* -----------------------------------------------------------------------------
@@ -596,7 +617,7 @@ static inline StgInt64 PK_Int64(W_ p_src[])
    Catch frames
    -------------------------------------------------------------------------- */
 
    Catch frames
    -------------------------------------------------------------------------- */
 
-extern DLL_IMPORT_DATA const StgPolyInfoTable catch_frame_info;
+extern DLL_IMPORT_RTS const StgPolyInfoTable stg_catch_frame_info;
 
 /* -----------------------------------------------------------------------------
    Seq frames
 
 /* -----------------------------------------------------------------------------
    Seq frames
@@ -605,14 +626,14 @@ extern DLL_IMPORT_DATA const StgPolyInfoTable catch_frame_info;
    an update...
    -------------------------------------------------------------------------- */
 
    an update...
    -------------------------------------------------------------------------- */
 
-extern DLL_IMPORT_DATA const StgPolyInfoTable seq_frame_info;
+extern DLL_IMPORT_RTS const StgPolyInfoTable stg_seq_frame_info;
 
 #define PUSH_SEQ_FRAME(sp)                                     \
        {                                                       \
                StgSeqFrame *__frame;                           \
                TICK_SEQF_PUSHED();                             \
                __frame = (StgSeqFrame *)(sp);                  \
 
 #define PUSH_SEQ_FRAME(sp)                                     \
        {                                                       \
                StgSeqFrame *__frame;                           \
                TICK_SEQF_PUSHED();                             \
                __frame = (StgSeqFrame *)(sp);                  \
-               SET_HDR_(__frame,&seq_frame_info,CCCS);         \
+               SET_HDR_(__frame,&stg_seq_frame_info,CCCS);     \
                __frame->link = Su;                             \
                Su = (StgUpdateFrame *)__frame;                 \
        }
                __frame->link = Su;                             \
                Su = (StgUpdateFrame *)__frame;                 \
        }
@@ -622,9 +643,13 @@ extern DLL_IMPORT_DATA const StgPolyInfoTable seq_frame_info;
    -------------------------------------------------------------------------- */
 
 #if defined(USE_SPLIT_MARKERS)
    -------------------------------------------------------------------------- */
 
 #if defined(USE_SPLIT_MARKERS)
-#define __STG_SPLIT_MARKER(n) FN_(__stg_split_marker##n) { }
+#if defined(cygwin32_TARGET_OS) || defined(mingw32_TARGET_OS)
+#define __STG_SPLIT_MARKER __asm__("\n___stg_split_marker:");
+#else
+#define __STG_SPLIT_MARKER __asm__("\n__stg_split_marker:");
+#endif
 #else
 #else
-#define __STG_SPLIT_MARKER(n) /* nothing */
+#define __STG_SPLIT_MARKER /* nothing */
 #endif
 
 /* -----------------------------------------------------------------------------
 #endif
 
 /* -----------------------------------------------------------------------------
@@ -644,20 +669,33 @@ extern DLL_IMPORT_DATA const StgPolyInfoTable seq_frame_info;
    We save all the STG registers (that is, the ones that are mapped to
    machine registers) in their places in the TSO.  
 
    We save all the STG registers (that is, the ones that are mapped to
    machine registers) in their places in the TSO.  
 
-   The stack registers go into the current stack object, and the heap
-   registers are saved in global locations.
+   The stack registers go into the current stack object, and the
+   current nursery is updated from the heap pointer.
+
+   These functions assume that BaseReg is loaded appropriately (if
+   we have one).
    -------------------------------------------------------------------------- */
 
    -------------------------------------------------------------------------- */
 
+#if IN_STG_CODE
+
 static __inline__ void
 SaveThreadState(void)
 {
 static __inline__ void
 SaveThreadState(void)
 {
+  StgTSO *tso;
+
   /* Don't need to save REG_Base, it won't have changed. */
 
   /* Don't need to save REG_Base, it won't have changed. */
 
-  CurrentTSO->sp       = Sp;
-  CurrentTSO->su       = Su;
-  CurrentTSO->splim    = SpLim;
+  tso = CurrentTSO;
+  tso->sp       = Sp;
+  tso->su       = Su;
   CloseNursery(Hp);
 
   CloseNursery(Hp);
 
+#ifdef REG_CurrentTSO
+  SAVE_CurrentTSO = tso;
+#endif
+#ifdef REG_CurrentNursery
+  SAVE_CurrentNursery = CurrentNursery;
+#endif
 #if defined(PROFILING)
   CurrentTSO->prof.CCCS = CCCS;
 #endif
 #if defined(PROFILING)
   CurrentTSO->prof.CCCS = CCCS;
 #endif
@@ -666,19 +704,82 @@ SaveThreadState(void)
 static __inline__ void 
 LoadThreadState (void)
 {
 static __inline__ void 
 LoadThreadState (void)
 {
-#ifdef REG_Base
-  BaseReg = (StgRegTable*)&MainRegTable;
+  StgTSO *tso;
+
+#ifdef REG_CurrentTSO
+  CurrentTSO = SAVE_CurrentTSO;
 #endif
 
 #endif
 
-  Sp    = CurrentTSO->sp;
-  Su    = CurrentTSO->su;
-  SpLim = CurrentTSO->splim;
+  tso = CurrentTSO;
+  Sp    = tso->sp;
+  Su    = tso->su;
+  SpLim = (P_)&(tso->stack) + RESERVED_STACK_WORDS;
   OpenNursery(Hp,HpLim);
 
   OpenNursery(Hp,HpLim);
 
+#ifdef REG_CurrentNursery
+  CurrentNursery = SAVE_CurrentNursery;
+#endif
 # if defined(PROFILING)
   CCCS = CurrentTSO->prof.CCCS;
 # endif
 }
 
 # if defined(PROFILING)
   CCCS = CurrentTSO->prof.CCCS;
 # endif
 }
 
+#endif
+
+/* -----------------------------------------------------------------------------
+   Module initialisation
+   -------------------------------------------------------------------------- */
+
+#define PUSH_INIT_STACK(reg_function)          \
+       *(Sp++) = (W_)reg_function
+
+#define POP_INIT_STACK()                       \
+       *(--Sp)
+
+#define START_MOD_INIT(reg_mod_name)           \
+       static int _module_registered = 0;      \
+       FN_(reg_mod_name) {                     \
+           FB_;                                \
+           if (! _module_registered) {         \
+               _module_registered = 1;         \
+               { 
+           /* extern decls go here, followed by init code */
+
+#define REGISTER_FOREIGN_EXPORT(reg_fe_binder) \
+        STGCALL1(getStablePtr,reg_fe_binder)
+       
+#define REGISTER_IMPORT(reg_mod_name)          \
+        PUSH_INIT_STACK(reg_mod_name)
+
+#define END_MOD_INIT()                         \
+        }};                                    \
+       JMP_(POP_INIT_STACK());                 \
+       FE_ }
+
+/* -----------------------------------------------------------------------------
+   Support for _ccall_GC_ and _casm_GC.
+   -------------------------------------------------------------------------- */
+
+/* 
+ * Suspending/resuming threads for doing external C-calls (_ccall_GC).
+ * These functions are defined in rts/Schedule.c.
+ */
+StgInt        suspendThread ( StgRegTable *cap );
+StgRegTable * resumeThread  ( StgInt );
+
+#define SUSPEND_THREAD(token)                  \
+   SaveThreadState();                          \
+   token = suspendThread(BaseReg);
+
+#ifdef SMP
+#define RESUME_THREAD(token)                   \
+   BaseReg = resumeThread(token);              \
+   LoadThreadState();
+#else
+#define RESUME_THREAD(token)                   \
+   (void)resumeThread(token);                  \
+   LoadThreadState();
+#endif
+
 #endif /* STGMACROS_H */
 
 #endif /* STGMACROS_H */