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