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