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