3687a8045b84b7e368c7ce1d88dd477210cf6211
[ghc-hetmet.git] / ghc / includes / StgMacros.h
1 /* -----------------------------------------------------------------------------
2  * $Id: StgMacros.h,v 1.7 1999/03/02 19:44:18 sof Exp $
3  *
4  * (c) The GHC Team, 1998-1999
5  *
6  * Macros used for writing STG-ish C code.
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #ifndef STGMACROS_H
11 #define STGMACROS_H
12
13 /* -----------------------------------------------------------------------------
14   The following macros create function headers.
15
16   Each basic block is represented by a C function with no arguments.
17   We therefore always begin with either
18
19   extern F_ f(void)
20
21   or
22   
23   static F_ f(void)
24
25   The macros can be used either to define the function itself, or to provide
26   prototypes (by following with a ';').
27
28   Note: the various I*_ shorthands in the second block below are used to
29   declare forward references to local symbols. These shorthands *have* to
30   use the 'extern' type specifier and not 'static'. The reason for this is
31   that 'static' declares a reference as being a static/local variable,
32   and *not* as a forward reference to a static variable.
33
34   This might seem obvious, but it had me stumped as to why my info tables
35   were suddenly all filled with 0s.
36
37     -- sof 1/99 
38
39   --------------------------------------------------------------------------- */
40
41 #define STGFUN(f)       StgFunPtr f(void)
42 #define EXTFUN(f)       extern StgFunPtr f(void)
43 #define EXTFUN_RTS(f)   extern DLL_IMPORT_RTS StgFunPtr f(void)
44 #define FN_(f)          F_ f(void)
45 #define IFN_(f)         static F_ f(void)
46 #define IF_(f)          static F_ f(void)
47 #define EF_(f)          extern F_ f(void)
48 #define EDF_(f)         extern DLLIMPORT F_ f(void)
49
50 #define ED_             extern
51 #define EDD_            extern DLLIMPORT 
52 #define ED_RO_          extern const
53 #define ID_             extern
54 #define ID_RO_          extern const
55 #define EI_             extern const StgInfoTable
56 #define EDI_            extern DLLIMPORT const StgInfoTable
57 #define II_             extern const StgInfoTable
58 #define EC_             extern StgClosure
59 #define EDC_            extern DLLIMPORT StgClosure
60 #define IC_             extern StgClosure
61
62 /* -----------------------------------------------------------------------------
63    Stack Tagging.
64
65    For a  block of non-pointer words on the stack, we precede the
66    block with a small-integer tag giving the number of non-pointer
67    words in the block.
68    -------------------------------------------------------------------------- */
69
70 #ifndef DEBUG_EXTRA
71 #define ARGTAG_MAX 16           /* probably arbitrary */
72 #define ARG_TAG(n)  (n)
73 #define ARG_SIZE(n) stgCast(StgWord,n)
74
75 typedef enum {
76     REALWORLD_TAG = 0,
77     INT_TAG    = sizeofW(StgInt), 
78     INT64_TAG  = sizeofW(StgInt64), 
79     WORD_TAG   = sizeofW(StgWord), 
80     ADDR_TAG   = sizeofW(StgAddr), 
81     CHAR_TAG   = sizeofW(StgChar),
82     FLOAT_TAG  = sizeofW(StgFloat), 
83     DOUBLE_TAG = sizeofW(StgDouble), 
84     STABLE_TAG = sizeofW(StgWord), 
85 } StackTag;
86
87 #else /* DEBUG_EXTRA */
88
89 typedef enum {
90     ILLEGAL_TAG,
91     REALWORLD_TAG,
92     INT_TAG    ,
93     INT64_TAG  ,
94     WORD_TAG   ,
95     ADDR_TAG   ,
96     CHAR_TAG   ,
97     FLOAT_TAG  ,
98     DOUBLE_TAG ,
99     STABLE_TAG ,
100     ARGTAG_MAX = DOUBLE_TAG
101 } StackTag;
102
103 /* putting this in a .h file generates many copies - but its only a 
104  * debugging build.
105  */
106 static StgWord stg_arg_size[] = {
107     [REALWORLD_TAG] = 0,
108     [INT_TAG   ] = sizeofW(StgInt), 
109     [INT64_TAG ] = sizeofW(StgInt64), 
110     [WORD_TAG  ] = sizeofW(StgWord), 
111     [ADDR_TAG  ] = sizeofW(StgAddr), 
112     [CHAR_TAG  ] = sizeofW(StgChar),
113     [FLOAT_TAG ] = sizeofW(StgFloat), 
114     [DOUBLE_TAG] = sizeofW(StgDouble),
115     [STABLE_TAG] = sizeofW(StgWord)
116 };
117
118 #define ARG_SIZE(tag) stg_arg_size[stgCast(StgWord,tag)]
119
120 #endif /* DEBUG_EXTRA */
121
122 static inline int IS_ARG_TAG( StgWord p );
123 static inline int IS_ARG_TAG( StgWord p ) { return p <= ARGTAG_MAX; }
124
125 /* -----------------------------------------------------------------------------
126    Argument checks.
127    
128    If (Sp + <n_args>) > Su { JMP_(stg_update_PAP); }
129    
130    Sp points to the topmost used word on the stack, and Su points to
131    the most recently pushed update frame.
132
133    Remember that <n_args> must include any tagging of unboxed values.
134
135    ARGS_CHK_LOAD_NODE is for top-level functions, whose entry
136    convention doesn't require that Node is loaded with a pointer to
137    the closure.  Thus we must load node before calling stg_updatePAP if
138    the argument check fails. 
139    -------------------------------------------------------------------------- */
140
141 #define ARGS_CHK(n)                             \
142         if ((P_)(Sp + (n)) > (P_)Su) {          \
143                 JMP_(stg_update_PAP);           \
144         }
145
146 #define ARGS_CHK_LOAD_NODE(n,closure)           \
147         if ((P_)(Sp + (n)) > (P_)Su) {          \
148                 R1.p = (P_)closure;             \
149                 JMP_(stg_update_PAP);           \
150         }
151
152 /* -----------------------------------------------------------------------------
153    Heap/Stack Checks.
154
155    When failing a check, we save a return address on the stack and
156    jump to a pre-compiled code fragment that saves the live registers
157    and returns to the scheduler.
158
159    The return address in most cases will be the beginning of the basic
160    block in which the check resides, since we need to perform the check
161    again on re-entry because someone else might have stolen the resource
162    in the meantime.
163    ------------------------------------------------------------------------- */
164
165 #define STK_CHK(headroom,ret,r,layout,tag_assts)                \
166         if (Sp - headroom < SpLim) {                            \
167             EXTFUN_RTS(stg_chk_##layout);                       \
168             tag_assts                                           \
169             (r) = (P_)ret;                                      \
170             JMP_(stg_chk_##layout);                             \
171         }
172        
173 #define HP_CHK(headroom,ret,r,layout,tag_assts)                 \
174         if ((Hp += headroom) > HpLim) {                         \
175             EXTFUN_RTS(stg_chk_##layout);                       \
176             tag_assts                                           \
177             (r) = (P_)ret;                                      \
178             JMP_(stg_chk_##layout);                             \
179         }                                                       \
180         TICK_ALLOC_HEAP(headroom);
181
182 #define HP_STK_CHK(stk_headroom,hp_headroom,ret,r,layout,tag_assts) \
183         if (Sp - stk_headroom < SpLim || (Hp += hp_headroom) > HpLim) { \
184             EXTFUN_RTS(stg_chk_##layout);                       \
185             tag_assts                                           \
186             (r) = (P_)ret;                                      \
187             JMP_(stg_chk_##layout);                             \
188         }                                                       \
189         TICK_ALLOC_HEAP(hp_headroom);
190
191 /* -----------------------------------------------------------------------------
192    A Heap Check in a case alternative are much simpler: everything is
193    on the stack and covered by a liveness mask already, and there is
194    even a return address with an SRT info table there as well.  
195
196    Just push R1 and return to the scheduler saying 'EnterGHC'
197
198    {STK,HP,HP_STK}_CHK_NP are the various checking macros for
199    bog-standard case alternatives, thunks, and non-top-level
200    functions.  In all these cases, node points to a closure that we
201    can just enter to restart the heap check (the NP stands for 'node points').
202
203    HpLim points to the LAST WORD of valid allocation space.
204    -------------------------------------------------------------------------- */
205
206 #define STK_CHK_NP(headroom,ptrs,tag_assts)                     \
207         if ((Sp - (headroom)) < SpLim) {                        \
208             EXTFUN_RTS(stg_gc_enter_##ptrs);                    \
209             tag_assts                                           \
210             JMP_(stg_gc_enter_##ptrs);                          \
211         }
212
213 #define HP_CHK_NP(headroom,ptrs,tag_assts)                      \
214         if ((Hp += (headroom)) > HpLim) {                       \
215             EXTFUN_RTS(stg_gc_enter_##ptrs);                    \
216             tag_assts                                           \
217             JMP_(stg_gc_enter_##ptrs);                          \
218         }                                                       \
219         TICK_ALLOC_HEAP(headroom);
220
221 #define HP_CHK_SEQ_NP(headroom,ptrs,tag_assts)                  \
222         if ((Hp += (headroom)) > HpLim) {                       \
223             EXTFUN_RTS(stg_gc_seq_##ptrs);                      \
224             tag_assts                                           \
225             JMP_(stg_gc_seq_##ptrs);                            \
226         }                                                       \
227         TICK_ALLOC_HEAP(headroom);
228
229 #define HP_STK_CHK_NP(stk_headroom, hp_headroom, ptrs, tag_assts) \
230         if ((Sp - (stk_headroom)) < SpLim || (Hp += (hp_headroom)) > HpLim) { \
231             EXTFUN_RTS(stg_gc_enter_##ptrs);                    \
232             tag_assts                                           \
233             JMP_(stg_gc_enter_##ptrs);                          \
234         }                                                       \
235         TICK_ALLOC_HEAP(hp_headroom);
236
237 /* Heap checks for branches of a primitive case / unboxed tuple return */
238
239 #define GEN_HP_CHK_ALT(headroom,lbl,tag_assts)                  \
240         if ((Hp += (headroom)) > HpLim) {                       \
241             EXTFUN_RTS(lbl);                                    \
242             tag_assts                                           \
243             JMP_(lbl);                                          \
244         }                                                       \
245         TICK_ALLOC_HEAP(headroom);
246
247 #define HP_CHK_NOREGS(headroom,tag_assts) \
248     GEN_HP_CHK_ALT(headroom,stg_gc_noregs,tag_assts);
249 #define HP_CHK_UNPT_R1(headroom,tag_assts)  \
250     GEN_HP_CHK_ALT(headroom,stg_gc_unpt_r1,tag_assts);
251 #define HP_CHK_UNBX_R1(headroom,tag_assts)  \
252     GEN_HP_CHK_ALT(headroom,stg_gc_unbx_r1,tag_assts);
253 #define HP_CHK_F1(headroom,tag_assts)       \
254     GEN_HP_CHK_ALT(headroom,stg_gc_f1,tag_assts);
255 #define HP_CHK_D1(headroom,tag_assts)       \
256     GEN_HP_CHK_ALT(headroom,stg_gc_d1,tag_assts);
257
258 #define HP_CHK_L1(headroom,tag_assts)       \
259     GEN_HP_CHK_ALT(headroom,stg_gc_d1,tag_assts);
260
261 #define HP_CHK_UT_ALT(headroom, ptrs, nptrs, r, ret, tag_assts) \
262     GEN_HP_CHK_ALT(headroom, stg_gc_ut_##ptrs##_##nptrs, \
263                      tag_assts r = (P_)ret;)
264
265 /* -----------------------------------------------------------------------------
266    Generic Heap checks.
267
268    These are slow, but have the advantage of being usable in a variety
269    of situations.  
270
271    The one restriction is that any relevant SRTs must already be pointed
272    to from the stack.  The return address doesn't need to have an info
273    table attached: hence it can be any old code pointer.
274
275    The liveness mask is a logical 'XOR' of NO_PTRS and zero or more
276    Rn_PTR constants defined below.  All registers will be saved, but
277    the garbage collector needs to know which ones contain pointers.
278
279    Good places to use a generic heap check: 
280
281         - case alternatives (the return address with an SRT is already
282           on the stack).
283
284         - primitives (no SRT required).
285
286    The stack layout is like this:
287
288           DblReg1-2
289           FltReg1-4
290           R1-8
291           return address
292           liveness mask
293           stg_gen_chk_info
294
295    so the liveness mask depends on the size of an StgDouble (FltRegs
296    and R<n> are guaranteed to be 1 word in size).
297
298    -------------------------------------------------------------------------- */
299
300 /* VERY MAGIC CONSTANTS! 
301  * must agree with code in HeapStackCheck.c, stg_gen_chk
302  */
303
304 #if SIZEOF_DOUBLE > SIZEOF_VOID_P
305 #define ALL_NON_PTRS   0xffff
306 #else /* SIZEOF_DOUBLE == SIZEOF_VOID_P */
307 #define ALL_NON_PTRS   0x3fff
308 #endif
309
310 #define LIVENESS_MASK(ptr_regs)  (ALL_NON_PTRS ^ (ptr_regs))
311
312 #define NO_PTRS   0
313 #define R1_PTR    1<<0
314 #define R2_PTR    1<<1
315 #define R3_PTR    1<<2
316 #define R4_PTR    1<<3
317 #define R5_PTR    1<<4
318 #define R6_PTR    1<<5
319 #define R7_PTR    1<<6
320 #define R8_PTR    1<<7
321
322 #define HP_CHK_GEN(headroom,liveness,reentry,tag_assts) \
323    if ((Hp += (headroom)) > HpLim ) {                   \
324         EF_(stg_gen_chk);                               \
325         tag_assts                                       \
326         R9.w = (W_)LIVENESS_MASK(liveness);             \
327         R10.w = (W_)reentry;                            \
328         JMP_(stg_gen_chk);                              \
329    }                                                    \
330    TICK_ALLOC_HEAP(headroom);
331
332 #define STK_CHK_GEN(headroom,liveness,reentry,tag_assts)        \
333    if ((Sp - (headroom)) < SpLim) {                             \
334         EF_(stg_gen_chk);                                       \
335         tag_assts                                               \
336         R9.w = (W_)LIVENESS_MASK(liveness);                     \
337         R10.w = (W_)reentry;                                    \
338         JMP_(stg_gen_chk);                                      \
339    }
340
341 #define MAYBE_GC(liveness,reentry)              \
342    if (doYouWantToGC()) {                       \
343         EF_(stg_gen_hp);                        \
344         R9.w = (W_)LIVENESS_MASK(liveness);     \
345         R10.w = (W_)reentry;                    \
346         JMP_(stg_gen_hp);                       \
347    }
348
349 /* -----------------------------------------------------------------------------
350    Voluntary Yields/Blocks
351
352    We only have a generic version of this at the moment - if it turns
353    out to be slowing us down we can make specialised ones.
354    -------------------------------------------------------------------------- */
355
356 EF_(stg_gen_yield);
357 EF_(stg_gen_block);
358
359 #define YIELD(liveness,reentry)                 \
360   {                                             \
361    R9.w  = (W_)LIVENESS_MASK(liveness);         \
362    R10.w = (W_)reentry;                         \
363    JMP_(stg_gen_yield);                         \
364   }
365
366 #define BLOCK(liveness,reentry)                 \
367   {                                             \
368    R9.w  = (W_)LIVENESS_MASK(liveness);         \
369    R10.w = (W_)reentry;                         \
370    JMP_(stg_gen_block);                         \
371   }
372
373 #define BLOCK_NP(ptrs)                          \
374   {                                             \
375     EF_(stg_block_##ptrs);                      \
376     JMP_(stg_block_##ptrs);                     \
377   }
378
379 /* -----------------------------------------------------------------------------
380    CCall_GC needs to push a dummy stack frame containing the contents
381    of volatile registers and variables.  
382
383    We use a RET_DYN frame the same as for a dynamic heap check.
384    ------------------------------------------------------------------------- */
385
386 #if COMPILING_RTS
387 EI_(stg_gen_chk_info);
388 #else
389 EDI_(stg_gen_chk_info);
390 #endif
391 /* -----------------------------------------------------------------------------
392    Vectored Returns
393
394    RETVEC(p,t) where 'p' is a pointer to the info table for a
395    vectored return address, returns the address of the return code for
396    tag 't'.
397
398    Return vectors are placed in *reverse order* immediately before the info
399    table for the return address.  Hence the formula for computing the
400    actual return address is (addr - sizeof(InfoTable) - tag - 1).
401    The extra subtraction of one word is because tags start at zero.
402    -------------------------------------------------------------------------- */
403
404 #ifdef USE_MINIINTERPRETER
405 #define RET_VEC(p,t) ((*(stgCast(StgInfoTable*,p)->vector))[t])
406 #else
407 #define RET_VEC(p,t) (*((P_)(p) - sizeofW(StgInfoTable) - t - 1))
408 #endif
409
410 /* -----------------------------------------------------------------------------
411    Misc
412    -------------------------------------------------------------------------- */
413
414 /* set the tag register (if we have one) */
415 #define SET_TAG(t)  /* nothing */
416
417 /* don't do eager blackholing for now */
418 #define UPD_BH_UPDATABLE(thunk)  /* nothing */
419 #define UPD_BH_SINGLE_ENTRY(thunk)  /* nothing */
420
421 /* -----------------------------------------------------------------------------
422    Moving Floats and Doubles
423
424    ASSIGN_FLT is for assigning a float to memory (usually the
425               stack/heap).  The memory address is guaranteed to be
426               StgWord aligned (currently == sizeof(long)).
427
428    PK_FLT     is for pulling a float out of memory.  The memory is
429               guaranteed to be StgWord aligned.
430    -------------------------------------------------------------------------- */
431
432 static inline void        ASSIGN_FLT (W_ [], StgFloat);
433 static inline StgFloat    PK_FLT     (W_ []);
434
435 #if ALIGNMENT_FLOAT <= ALIGNMENT_LONG
436
437 static inline void     ASSIGN_FLT(W_ p_dest[], StgFloat src) { *(StgFloat *)p_dest = src; }
438 static inline StgFloat PK_FLT    (W_ p_src[])                { return *(StgFloat *)p_src; }
439
440 #else  /* ALIGNMENT_FLOAT > ALIGNMENT_UNSIGNED_INT */
441
442 static inline void ASSIGN_FLT(W_ p_dest[], StgFloat src)
443 {
444     float_thing y;
445     y.f = src;
446     *p_dest = y.fu;
447 }
448
449 static inline StgFloat PK_FLT(W_ p_src[])
450 {
451     float_thing y;
452     y.fu = *p_src;
453     return(y.f);
454 }
455
456 #endif /* ALIGNMENT_FLOAT > ALIGNMENT_LONG */
457
458 #if ALIGNMENT_DOUBLE <= ALIGNMENT_LONG
459
460 static inline void        ASSIGN_DBL (W_ [], StgDouble);
461 static inline StgDouble   PK_DBL     (W_ []);
462
463 static inline void      ASSIGN_DBL(W_ p_dest[], StgDouble src) { *(StgDouble *)p_dest = src; }
464 static inline StgDouble PK_DBL    (W_ p_src[])                 { return *(StgDouble *)p_src; }
465
466 #else   /* ALIGNMENT_DOUBLE > ALIGNMENT_LONG */
467
468 /* Sparc uses two floating point registers to hold a double.  We can
469  * write ASSIGN_DBL and PK_DBL by directly accessing the registers
470  * independently - unfortunately this code isn't writable in C, we
471  * have to use inline assembler.
472  */
473 #if sparc_TARGET_ARCH
474
475 #define ASSIGN_DBL(dst,src) \
476       __asm__("st %2,%0\n\tst %R2,%1" : "=m" (((P_)(dst))[0]), \
477         "=m" (((P_)(dst))[1]) : "f" (src));
478
479 #define PK_DBL(src) \
480     ( { register double d; \
481       __asm__("ld %1,%0\n\tld %2,%R0" : "=f" (d) : \
482         "m" (((P_)(src))[0]), "m" (((P_)(src))[1])); d; \
483     } )
484
485 #else /* ! sparc_TARGET_ARCH */
486
487 static inline void        ASSIGN_DBL (W_ [], StgDouble);
488 static inline StgDouble   PK_DBL     (W_ []);
489
490 typedef struct
491   { StgWord dhi;
492     StgWord dlo;
493   } unpacked_double;
494
495 typedef union
496   { StgDouble d;
497     unpacked_double du;
498   } double_thing;
499
500 static inline void ASSIGN_DBL(W_ p_dest[], StgDouble src)
501 {
502     double_thing y;
503     y.d = src;
504     p_dest[0] = y.du.dhi;
505     p_dest[1] = y.du.dlo;
506 }
507
508 /* GCC also works with this version, but it generates
509    the same code as the previous one, and is not ANSI
510
511 #define ASSIGN_DBL( p_dest, src ) \
512         *p_dest = ((double_thing) src).du.dhi; \
513         *(p_dest+1) = ((double_thing) src).du.dlo \
514 */
515
516 static inline StgDouble PK_DBL(W_ p_src[])
517 {
518     double_thing y;
519     y.du.dhi = p_src[0];
520     y.du.dlo = p_src[1];
521     return(y.d);
522 }
523
524 #endif /* ! sparc_TARGET_ARCH */
525
526 #endif /* ALIGNMENT_DOUBLE > ALIGNMENT_UNSIGNED_INT */
527
528 #ifdef SUPPORT_LONG_LONGS
529
530 typedef struct
531   { StgWord dhi;
532     StgWord dlo;
533   } unpacked_double_word;
534
535 typedef union
536   { StgInt64 i;
537     unpacked_double_word iu;
538   } int64_thing;
539
540 typedef union
541   { StgWord64 w;
542     unpacked_double_word wu;
543   } word64_thing;
544
545 static inline void ASSIGN_Word64(W_ p_dest[], StgWord64 src)
546 {
547     word64_thing y;
548     y.w = src;
549     p_dest[0] = y.wu.dhi;
550     p_dest[1] = y.wu.dlo;
551 }
552
553 static inline StgWord64 PK_Word64(W_ p_src[])
554 {
555     word64_thing y;
556     y.wu.dhi = p_src[0];
557     y.wu.dlo = p_src[1];
558     return(y.w);
559 }
560
561 static inline void ASSIGN_Int64(W_ p_dest[], StgInt64 src)
562 {
563     int64_thing y;
564     y.i = src;
565     p_dest[0] = y.iu.dhi;
566     p_dest[1] = y.iu.dlo;
567 }
568
569 static inline StgInt64 PK_Int64(W_ p_src[])
570 {
571     int64_thing y;
572     y.iu.dhi = p_src[0];
573     y.iu.dlo = p_src[1];
574     return(y.i);
575 }
576 #endif
577
578 /* -----------------------------------------------------------------------------
579    Catch frames
580    -------------------------------------------------------------------------- */
581
582 extern DLL_IMPORT_DATA const StgPolyInfoTable catch_frame_info;
583
584 /* -----------------------------------------------------------------------------
585    Seq frames
586
587    A seq frame is very like an update frame, except that it doesn't do
588    an update...
589    -------------------------------------------------------------------------- */
590
591 extern DLL_IMPORT_DATA const StgPolyInfoTable seq_frame_info;
592
593 #define PUSH_SEQ_FRAME(sp)                                      \
594         {                                                       \
595                 StgSeqFrame *__frame;                           \
596                 TICK_SEQF_PUSHED();                             \
597                 __frame = (StgSeqFrame *)(sp);                  \
598                 SET_HDR_(__frame,&seq_frame_info,CCCS);         \
599                 __frame->link = Su;                             \
600                 Su = (StgUpdateFrame *)__frame;                 \
601         }
602
603 /* -----------------------------------------------------------------------------
604    Split markers
605    -------------------------------------------------------------------------- */
606
607 #if defined(USE_SPLIT_MARKERS)
608 #define __STG_SPLIT_MARKER(n) FN_(__stg_split_marker##n) { }
609 #else
610 #define __STG_SPLIT_MARKER(n) /* nothing */
611 #endif
612
613 /* -----------------------------------------------------------------------------
614    Closure and Info Macros with casting.
615
616    We don't want to mess around with casts in the generated C code, so
617    we use these casting versions of the closure/info tables macros.
618    -------------------------------------------------------------------------- */
619
620 #define SET_HDR_(c,info,ccs) \
621    SET_HDR((StgClosure *)(c),(StgInfoTable *)(info),ccs)
622
623 /* -----------------------------------------------------------------------------
624    Saving context for exit from the STG world, and loading up context
625    on entry to STG code.
626
627    We save all the STG registers (that is, the ones that are mapped to
628    machine registers) in their places in the TSO.  
629
630    The stack registers go into the current stack object, and the heap
631    registers are saved in global locations.
632    -------------------------------------------------------------------------- */
633
634 static __inline__ void
635 SaveThreadState(void)
636 {
637   /* Don't need to save REG_Base, it won't have changed. */
638
639   CurrentTSO->sp       = Sp;
640   CurrentTSO->su       = Su;
641   CurrentTSO->splim    = SpLim;
642   CloseNursery(Hp);
643
644 #if defined(PROFILING)
645   CurrentTSO->prof.CCCS = CCCS;
646 #endif
647 }
648
649 static __inline__ void 
650 LoadThreadState (void)
651 {
652 #ifdef REG_Base
653   BaseReg = (StgRegTable*)&MainRegTable;
654 #endif
655
656   Sp    = CurrentTSO->sp;
657   Su    = CurrentTSO->su;
658   SpLim = CurrentTSO->splim;
659   OpenNursery(Hp,HpLim);
660
661 # if defined(PROFILING)
662   CCCS = CurrentTSO->prof.CCCS;
663 # endif
664 }
665
666 #endif /* STGMACROS_H */
667