[project @ 1999-11-05 12:28:05 by simonmar]
[ghc-hetmet.git] / ghc / includes / StgMacros.h
1 /* -----------------------------------------------------------------------------
2  * $Id: StgMacros.h,v 1.16 1999/11/05 12:28:05 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
184 #define HP_STK_CHK(stk_headroom,hp_headroom,ret,r,layout,tag_assts) \
185         if (Sp - stk_headroom < SpLim || (Hp += hp_headroom) > HpLim) { \
186             EXTFUN_RTS(stg_chk_##layout);                       \
187             tag_assts                                           \
188             (r) = (P_)ret;                                      \
189             JMP_(stg_chk_##layout);                             \
190         }
191
192 /* -----------------------------------------------------------------------------
193    A Heap Check in a case alternative are much simpler: everything is
194    on the stack and covered by a liveness mask already, and there is
195    even a return address with an SRT info table there as well.  
196
197    Just push R1 and return to the scheduler saying 'EnterGHC'
198
199    {STK,HP,HP_STK}_CHK_NP are the various checking macros for
200    bog-standard case alternatives, thunks, and non-top-level
201    functions.  In all these cases, node points to a closure that we
202    can just enter to restart the heap check (the NP stands for 'node points').
203
204    HpLim points to the LAST WORD of valid allocation space.
205    -------------------------------------------------------------------------- */
206
207 #define STK_CHK_NP(headroom,ptrs,tag_assts)                     \
208         if ((Sp - (headroom)) < SpLim) {                        \
209             EXTFUN_RTS(stg_gc_enter_##ptrs);                    \
210             tag_assts                                           \
211             JMP_(stg_gc_enter_##ptrs);                          \
212         }
213
214 #define HP_CHK_NP(headroom,ptrs,tag_assts)                      \
215         if ((Hp += (headroom)) > HpLim) {                       \
216             EXTFUN_RTS(stg_gc_enter_##ptrs);                    \
217             tag_assts                                           \
218             JMP_(stg_gc_enter_##ptrs);                          \
219         }
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
228 #define HP_STK_CHK_NP(stk_headroom, hp_headroom, ptrs, tag_assts) \
229         if ((Sp - (stk_headroom)) < SpLim || (Hp += (hp_headroom)) > HpLim) { \
230             EXTFUN_RTS(stg_gc_enter_##ptrs);                    \
231             tag_assts                                           \
232             JMP_(stg_gc_enter_##ptrs);                          \
233         }
234
235
236 /* Heap checks for branches of a primitive case / unboxed tuple return */
237
238 #define GEN_HP_CHK_ALT(headroom,lbl,tag_assts)                  \
239         if ((Hp += (headroom)) > HpLim) {                       \
240             EXTFUN_RTS(lbl);                                    \
241             tag_assts                                           \
242             JMP_(lbl);                                          \
243         }
244
245 #define HP_CHK_NOREGS(headroom,tag_assts) \
246     GEN_HP_CHK_ALT(headroom,stg_gc_noregs,tag_assts);
247 #define HP_CHK_UNPT_R1(headroom,tag_assts)  \
248     GEN_HP_CHK_ALT(headroom,stg_gc_unpt_r1,tag_assts);
249 #define HP_CHK_UNBX_R1(headroom,tag_assts)  \
250     GEN_HP_CHK_ALT(headroom,stg_gc_unbx_r1,tag_assts);
251 #define HP_CHK_F1(headroom,tag_assts)       \
252     GEN_HP_CHK_ALT(headroom,stg_gc_f1,tag_assts);
253 #define HP_CHK_D1(headroom,tag_assts)       \
254     GEN_HP_CHK_ALT(headroom,stg_gc_d1,tag_assts);
255
256 #define HP_CHK_L1(headroom,tag_assts)       \
257     GEN_HP_CHK_ALT(headroom,stg_gc_d1,tag_assts);
258
259 #define HP_CHK_UT_ALT(headroom, ptrs, nptrs, r, ret, tag_assts) \
260     GEN_HP_CHK_ALT(headroom, stg_gc_ut_##ptrs##_##nptrs, \
261                      tag_assts r = (P_)ret;)
262
263 /* -----------------------------------------------------------------------------
264    Generic Heap checks.
265
266    These are slow, but have the advantage of being usable in a variety
267    of situations.  
268
269    The one restriction is that any relevant SRTs must already be pointed
270    to from the stack.  The return address doesn't need to have an info
271    table attached: hence it can be any old code pointer.
272
273    The liveness mask is a logical 'XOR' of NO_PTRS and zero or more
274    Rn_PTR constants defined below.  All registers will be saved, but
275    the garbage collector needs to know which ones contain pointers.
276
277    Good places to use a generic heap check: 
278
279         - case alternatives (the return address with an SRT is already
280           on the stack).
281
282         - primitives (no SRT required).
283
284    The stack layout is like this:
285
286           DblReg1-2
287           FltReg1-4
288           R1-8
289           return address
290           liveness mask
291           stg_gen_chk_info
292
293    so the liveness mask depends on the size of an StgDouble (FltRegs
294    and R<n> are guaranteed to be 1 word in size).
295
296    -------------------------------------------------------------------------- */
297
298 /* VERY MAGIC CONSTANTS! 
299  * must agree with code in HeapStackCheck.c, stg_gen_chk
300  */
301
302 #if SIZEOF_DOUBLE > SIZEOF_VOID_P
303 #define ALL_NON_PTRS   0xffff
304 #else /* SIZEOF_DOUBLE == SIZEOF_VOID_P */
305 #define ALL_NON_PTRS   0x3fff
306 #endif
307
308 #define LIVENESS_MASK(ptr_regs)  (ALL_NON_PTRS ^ (ptr_regs))
309
310 #define NO_PTRS   0
311 #define R1_PTR    1<<0
312 #define R2_PTR    1<<1
313 #define R3_PTR    1<<2
314 #define R4_PTR    1<<3
315 #define R5_PTR    1<<4
316 #define R6_PTR    1<<5
317 #define R7_PTR    1<<6
318 #define R8_PTR    1<<7
319
320 #define HP_CHK_GEN(headroom,liveness,reentry,tag_assts) \
321    if ((Hp += (headroom)) > HpLim ) {                   \
322         EF_(stg_gen_chk);                               \
323         tag_assts                                       \
324         R9.w = (W_)LIVENESS_MASK(liveness);             \
325         R10.w = (W_)reentry;                            \
326         JMP_(stg_gen_chk);                              \
327    }
328
329 #define HP_CHK_GEN_TICKY(headroom,liveness,reentry,tag_assts)   \
330    HP_CHK_GEN(headroom,liveness,reentry,tag_assts);             \
331    TICK_ALLOC_HEAP_NOCTR(headroom)
332
333 #define STK_CHK_GEN(headroom,liveness,reentry,tag_assts)        \
334    if ((Sp - (headroom)) < SpLim) {                             \
335         EF_(stg_gen_chk);                                       \
336         tag_assts                                               \
337         R9.w = (W_)LIVENESS_MASK(liveness);                     \
338         R10.w = (W_)reentry;                                    \
339         JMP_(stg_gen_chk);                                      \
340    }
341
342 #define MAYBE_GC(liveness,reentry)              \
343    if (doYouWantToGC()) {                       \
344         EF_(stg_gen_hp);                        \
345         R9.w = (W_)LIVENESS_MASK(liveness);     \
346         R10.w = (W_)reentry;                    \
347         JMP_(stg_gen_hp);                       \
348    }
349
350 /* -----------------------------------------------------------------------------
351    Voluntary Yields/Blocks
352
353    We only have a generic version of this at the moment - if it turns
354    out to be slowing us down we can make specialised ones.
355    -------------------------------------------------------------------------- */
356
357 EF_(stg_gen_yield);
358 EF_(stg_gen_block);
359
360 #define YIELD(liveness,reentry)                 \
361   {                                             \
362    R9.w  = (W_)LIVENESS_MASK(liveness);         \
363    R10.w = (W_)reentry;                         \
364    JMP_(stg_gen_yield);                         \
365   }
366
367 #define BLOCK(liveness,reentry)                 \
368   {                                             \
369    R9.w  = (W_)LIVENESS_MASK(liveness);         \
370    R10.w = (W_)reentry;                         \
371    JMP_(stg_gen_block);                         \
372   }
373
374 #define BLOCK_NP(ptrs)                          \
375   {                                             \
376     EF_(stg_block_##ptrs);                      \
377     JMP_(stg_block_##ptrs);                     \
378   }
379
380 /* -----------------------------------------------------------------------------
381    CCall_GC needs to push a dummy stack frame containing the contents
382    of volatile registers and variables.  
383
384    We use a RET_DYN frame the same as for a dynamic heap check.
385    ------------------------------------------------------------------------- */
386
387 #if COMPILING_RTS
388 EI_(stg_gen_chk_info);
389 #else
390 EDI_(stg_gen_chk_info);
391 #endif
392 /* -----------------------------------------------------------------------------
393    Vectored Returns
394
395    RETVEC(p,t) where 'p' is a pointer to the info table for a
396    vectored return address, returns the address of the return code for
397    tag 't'.
398
399    Return vectors are placed in *reverse order* immediately before the info
400    table for the return address.  Hence the formula for computing the
401    actual return address is (addr - sizeof(InfoTable) - tag - 1).
402    The extra subtraction of one word is because tags start at zero.
403    -------------------------------------------------------------------------- */
404
405 #ifdef TABLES_NEXT_TO_CODE
406 #define RET_VEC(p,t) (*((P_)(p) - sizeofW(StgInfoTable) - t - 1))
407 #else
408 #define RET_VEC(p,t) (((StgInfoTable *)p)->vector[t])
409 #endif
410
411 /* -----------------------------------------------------------------------------
412    Misc
413    -------------------------------------------------------------------------- */
414
415
416 /* set the tag register (if we have one) */
417 #define SET_TAG(t)  /* nothing */
418
419 #ifdef EAGER_BLACKHOLING
420 #  ifdef SMP
421 #    define UPD_BH_UPDATABLE(info)              \
422         TICK_UPD_BH_UPDATABLE();                \
423         LOCK_THUNK(info);                       \
424         SET_INFO(R1.cl,&BLACKHOLE_info)
425 #    define UPD_BH_SINGLE_ENTRY(info)           \
426         TICK_UPD_BH_SINGLE_ENTRY();             \
427         LOCK_THUNK(info);                       \
428         SET_INFO(R1.cl,&BLACKHOLE_info)
429 #  else
430 #    define UPD_BH_UPDATABLE(info)              \
431         TICK_UPD_BH_UPDATABLE();                \
432         SET_INFO(R1.cl,&BLACKHOLE_info)
433 #    define UPD_BH_SINGLE_ENTRY(info)           \
434         TICK_UPD_BH_SINGLE_ENTRY();             \
435         SET_INFO(R1.cl,&SE_BLACKHOLE_info)
436 #  endif
437 #else /* !EAGER_BLACKHOLING */
438 #  define UPD_BH_UPDATABLE(thunk)    /* nothing */
439 #  define UPD_BH_SINGLE_ENTRY(thunk) /* nothing */
440 #endif /* EAGER_BLACKHOLING */
441
442 #define UPD_FRAME_UPDATEE(p)  (((StgUpdateFrame *)(p))->updatee)
443 #define UPDATE_SU_FROM_UPD_FRAME(p) (Su=((StgUpdateFrame *)(p))->link)
444
445 /* -----------------------------------------------------------------------------
446    Moving Floats and Doubles
447
448    ASSIGN_FLT is for assigning a float to memory (usually the
449               stack/heap).  The memory address is guaranteed to be
450               StgWord aligned (currently == sizeof(long)).
451
452    PK_FLT     is for pulling a float out of memory.  The memory is
453               guaranteed to be StgWord aligned.
454    -------------------------------------------------------------------------- */
455
456 static inline void        ASSIGN_FLT (W_ [], StgFloat);
457 static inline StgFloat    PK_FLT     (W_ []);
458
459 #if ALIGNMENT_FLOAT <= ALIGNMENT_LONG
460
461 static inline void     ASSIGN_FLT(W_ p_dest[], StgFloat src) { *(StgFloat *)p_dest = src; }
462 static inline StgFloat PK_FLT    (W_ p_src[])                { return *(StgFloat *)p_src; }
463
464 #else  /* ALIGNMENT_FLOAT > ALIGNMENT_UNSIGNED_INT */
465
466 static inline void ASSIGN_FLT(W_ p_dest[], StgFloat src)
467 {
468     float_thing y;
469     y.f = src;
470     *p_dest = y.fu;
471 }
472
473 static inline StgFloat PK_FLT(W_ p_src[])
474 {
475     float_thing y;
476     y.fu = *p_src;
477     return(y.f);
478 }
479
480 #endif /* ALIGNMENT_FLOAT > ALIGNMENT_LONG */
481
482 #if ALIGNMENT_DOUBLE <= ALIGNMENT_LONG
483
484 static inline void        ASSIGN_DBL (W_ [], StgDouble);
485 static inline StgDouble   PK_DBL     (W_ []);
486
487 static inline void      ASSIGN_DBL(W_ p_dest[], StgDouble src) { *(StgDouble *)p_dest = src; }
488 static inline StgDouble PK_DBL    (W_ p_src[])                 { return *(StgDouble *)p_src; }
489
490 #else   /* ALIGNMENT_DOUBLE > ALIGNMENT_LONG */
491
492 /* Sparc uses two floating point registers to hold a double.  We can
493  * write ASSIGN_DBL and PK_DBL by directly accessing the registers
494  * independently - unfortunately this code isn't writable in C, we
495  * have to use inline assembler.
496  */
497 #if sparc_TARGET_ARCH
498
499 #define ASSIGN_DBL(dst0,src) \
500     { StgPtr dst = (StgPtr)(dst0); \
501       __asm__("st %2,%0\n\tst %R2,%1" : "=m" (((P_)(dst))[0]), \
502         "=m" (((P_)(dst))[1]) : "f" (src)); \
503     }
504
505 #define PK_DBL(src0) \
506     ( { StgPtr src = (StgPtr)(src0); \
507         register double d; \
508       __asm__("ld %1,%0\n\tld %2,%R0" : "=f" (d) : \
509         "m" (((P_)(src))[0]), "m" (((P_)(src))[1])); d; \
510     } )
511
512 #else /* ! sparc_TARGET_ARCH */
513
514 static inline void        ASSIGN_DBL (W_ [], StgDouble);
515 static inline StgDouble   PK_DBL     (W_ []);
516
517 typedef struct
518   { StgWord dhi;
519     StgWord dlo;
520   } unpacked_double;
521
522 typedef union
523   { StgDouble d;
524     unpacked_double du;
525   } double_thing;
526
527 static inline void ASSIGN_DBL(W_ p_dest[], StgDouble src)
528 {
529     double_thing y;
530     y.d = src;
531     p_dest[0] = y.du.dhi;
532     p_dest[1] = y.du.dlo;
533 }
534
535 /* GCC also works with this version, but it generates
536    the same code as the previous one, and is not ANSI
537
538 #define ASSIGN_DBL( p_dest, src ) \
539         *p_dest = ((double_thing) src).du.dhi; \
540         *(p_dest+1) = ((double_thing) src).du.dlo \
541 */
542
543 static inline StgDouble PK_DBL(W_ p_src[])
544 {
545     double_thing y;
546     y.du.dhi = p_src[0];
547     y.du.dlo = p_src[1];
548     return(y.d);
549 }
550
551 #endif /* ! sparc_TARGET_ARCH */
552
553 #endif /* ALIGNMENT_DOUBLE > ALIGNMENT_UNSIGNED_INT */
554
555 #ifdef SUPPORT_LONG_LONGS
556
557 typedef struct
558   { StgWord dhi;
559     StgWord dlo;
560   } unpacked_double_word;
561
562 typedef union
563   { StgInt64 i;
564     unpacked_double_word iu;
565   } int64_thing;
566
567 typedef union
568   { StgWord64 w;
569     unpacked_double_word wu;
570   } word64_thing;
571
572 static inline void ASSIGN_Word64(W_ p_dest[], StgWord64 src)
573 {
574     word64_thing y;
575     y.w = src;
576     p_dest[0] = y.wu.dhi;
577     p_dest[1] = y.wu.dlo;
578 }
579
580 static inline StgWord64 PK_Word64(W_ p_src[])
581 {
582     word64_thing y;
583     y.wu.dhi = p_src[0];
584     y.wu.dlo = p_src[1];
585     return(y.w);
586 }
587
588 static inline void ASSIGN_Int64(W_ p_dest[], StgInt64 src)
589 {
590     int64_thing y;
591     y.i = src;
592     p_dest[0] = y.iu.dhi;
593     p_dest[1] = y.iu.dlo;
594 }
595
596 static inline StgInt64 PK_Int64(W_ p_src[])
597 {
598     int64_thing y;
599     y.iu.dhi = p_src[0];
600     y.iu.dlo = p_src[1];
601     return(y.i);
602 }
603 #endif
604
605 /* -----------------------------------------------------------------------------
606    Catch frames
607    -------------------------------------------------------------------------- */
608
609 extern DLL_IMPORT_DATA const StgPolyInfoTable catch_frame_info;
610
611 /* -----------------------------------------------------------------------------
612    Seq frames
613
614    A seq frame is very like an update frame, except that it doesn't do
615    an update...
616    -------------------------------------------------------------------------- */
617
618 extern DLL_IMPORT_DATA const StgPolyInfoTable seq_frame_info;
619
620 #define PUSH_SEQ_FRAME(sp)                                      \
621         {                                                       \
622                 StgSeqFrame *__frame;                           \
623                 TICK_SEQF_PUSHED();                             \
624                 __frame = (StgSeqFrame *)(sp);                  \
625                 SET_HDR_(__frame,&seq_frame_info,CCCS);         \
626                 __frame->link = Su;                             \
627                 Su = (StgUpdateFrame *)__frame;                 \
628         }
629
630 /* -----------------------------------------------------------------------------
631    Split markers
632    -------------------------------------------------------------------------- */
633
634 #if defined(USE_SPLIT_MARKERS)
635 #define __STG_SPLIT_MARKER(n) FN_(__stg_split_marker##n) { }
636 #else
637 #define __STG_SPLIT_MARKER(n) /* nothing */
638 #endif
639
640 /* -----------------------------------------------------------------------------
641    Closure and Info Macros with casting.
642
643    We don't want to mess around with casts in the generated C code, so
644    we use these casting versions of the closure/info tables macros.
645    -------------------------------------------------------------------------- */
646
647 #define SET_HDR_(c,info,ccs) \
648    SET_HDR((StgClosure *)(c),(StgInfoTable *)(info),ccs)
649
650 /* -----------------------------------------------------------------------------
651    Saving context for exit from the STG world, and loading up context
652    on entry to STG code.
653
654    We save all the STG registers (that is, the ones that are mapped to
655    machine registers) in their places in the TSO.  
656
657    The stack registers go into the current stack object, and the
658    current nursery is updated from the heap pointer.
659
660    These functions assume that BaseReg is loaded appropriately (if
661    we have one).
662    -------------------------------------------------------------------------- */
663
664 #ifdef IN_STG_CODE
665
666 static __inline__ void
667 SaveThreadState(void)
668 {
669   /* Don't need to save REG_Base, it won't have changed. */
670
671   CurrentTSO->sp       = Sp;
672   CurrentTSO->su       = Su;
673   CurrentTSO->splim    = SpLim;
674   CloseNursery(Hp);
675
676 #ifdef REG_CurrentTSO
677   SAVE_CurrentTSO = CurrentTSO;
678 #endif
679 #ifdef REG_CurrentNursery
680   SAVE_CurrentNursery = CurrentNursery;
681 #endif
682 #if defined(PROFILING)
683   CurrentTSO->prof.CCCS = CCCS;
684 #endif
685 }
686
687 static __inline__ void 
688 LoadThreadState (void)
689 {
690   Sp    = CurrentTSO->sp;
691   Su    = CurrentTSO->su;
692   SpLim = CurrentTSO->splim;
693   OpenNursery(Hp,HpLim);
694
695 #ifdef REG_CurrentTSO
696   CurrentTSO = SAVE_CurrentTSO;
697 #endif
698 #ifdef REG_CurrentNursery
699   CurrentNursery = SAVE_CurrentNursery;
700 #endif
701 # if defined(PROFILING)
702   CCCS = CurrentTSO->prof.CCCS;
703 # endif
704 }
705
706 #endif
707
708 /* -----------------------------------------------------------------------------
709    Support for _ccall_GC_ and _casm_GC.
710    -------------------------------------------------------------------------- */
711
712 /* 
713  * Suspending/resuming threads for doing external C-calls (_ccall_GC).
714  * These functions are defined in rts/Schedule.c.
715  */
716 StgInt        suspendThread ( StgRegTable *cap );
717 StgRegTable * resumeThread  ( StgInt );
718
719 #define SUSPEND_THREAD(token)                   \
720    SaveThreadState();                           \
721    token = suspendThread(BaseReg);
722
723 #ifdef SMP
724 #define RESUME_THREAD(token)                    \
725    BaseReg = resumeThread(token);               \
726    LoadThreadState();
727 #else
728 #define RESUME_THREAD(token)                    \
729    (void)resumeThread(token);                   \
730    LoadThreadState();
731 #endif
732
733 #endif /* STGMACROS_H */
734