646f0fc61468a174e07737e41b56ab2aaaec45b2
[ghc-hetmet.git] / ghc / includes / StgMacros.h
1 /* -----------------------------------------------------------------------------
2  * $Id: StgMacros.h,v 1.5 1999/02/05 16:02:28 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    TICK_ALLOC_HEAP(headroom);
337
338 #define MAYBE_GC(liveness,reentry)              \
339    if (doYouWantToGC()) {                       \
340         EF_(stg_gen_hp);                        \
341         R9.w = (W_)LIVENESS_MASK(liveness);     \
342         R10.w = (W_)reentry;                    \
343         JMP_(stg_gen_hp);                       \
344    }
345
346 /* -----------------------------------------------------------------------------
347    Voluntary Yields/Blocks
348
349    We only have a generic version of this at the moment - if it turns
350    out to be slowing us down we can make specialised ones.
351    -------------------------------------------------------------------------- */
352
353 #define YIELD(liveness,reentry)                 \
354   {                                             \
355    EF_(stg_gen_yield);                          \
356    R9.w  = (W_)LIVENESS_MASK(liveness);         \
357    R10.w = (W_)reentry;                         \
358    JMP_(stg_gen_yield);                         \
359   }
360
361 #define BLOCK(liveness,reentry)                 \
362   {                                             \
363    EF_(stg_gen_block);                          \
364    R9.w  = (W_)LIVENESS_MASK(liveness);         \
365    R10.w = (W_)reentry;                         \
366    JMP_(stg_gen_block);                         \
367   }
368
369 #define BLOCK_NP(ptrs)                          \
370   {                                             \
371     EF_(stg_bock_##ptrs);                       \
372     JMP_(stg_block_##ptrs);                     \
373   }
374
375 /* -----------------------------------------------------------------------------
376    CCall_GC needs to push a dummy stack frame containing the contents
377    of volatile registers and variables.  
378
379    We use a RET_DYN frame the same as for a dynamic heap check.
380    ------------------------------------------------------------------------- */
381
382 EI_(stg_gen_chk_info);
383
384 /* -----------------------------------------------------------------------------
385    Vectored Returns
386
387    RETVEC(p,t) where 'p' is a pointer to the info table for a
388    vectored return address, returns the address of the return code for
389    tag 't'.
390
391    Return vectors are placed in *reverse order* immediately before the info
392    table for the return address.  Hence the formula for computing the
393    actual return address is (addr - sizeof(InfoTable) - tag - 1).
394    The extra subtraction of one word is because tags start at zero.
395    -------------------------------------------------------------------------- */
396
397 #ifdef USE_MINIINTERPRETER
398 #define RET_VEC(p,t) ((*(stgCast(StgInfoTable*,p)->vector))[t])
399 #else
400 #define RET_VEC(p,t) (*((P_)(p) - sizeofW(StgInfoTable) - t - 1))
401 #endif
402
403 /* -----------------------------------------------------------------------------
404    Misc
405    -------------------------------------------------------------------------- */
406
407 /* set the tag register (if we have one) */
408 #define SET_TAG(t)  /* nothing */
409
410 /* don't do eager blackholing for now */
411 #define UPD_BH_UPDATABLE(thunk)  /* nothing */
412 #define UPD_BH_SINGLE_ENTRY(thunk)  /* nothing */
413
414 /* -----------------------------------------------------------------------------
415    Moving Floats and Doubles
416
417    ASSIGN_FLT is for assigning a float to memory (usually the
418               stack/heap).  The memory address is guaranteed to be
419               StgWord aligned (currently == sizeof(long)).
420
421    PK_FLT     is for pulling a float out of memory.  The memory is
422               guaranteed to be StgWord aligned.
423    -------------------------------------------------------------------------- */
424
425 static inline void        ASSIGN_FLT (W_ [], StgFloat);
426 static inline StgFloat    PK_FLT     (W_ []);
427
428 #if ALIGNMENT_FLOAT <= ALIGNMENT_LONG
429
430 static inline void     ASSIGN_FLT(W_ p_dest[], StgFloat src) { *(StgFloat *)p_dest = src; }
431 static inline StgFloat PK_FLT    (W_ p_src[])                { return *(StgFloat *)p_src; }
432
433 #else  /* ALIGNMENT_FLOAT > ALIGNMENT_UNSIGNED_INT */
434
435 static inline void ASSIGN_FLT(W_ p_dest[], StgFloat src)
436 {
437     float_thing y;
438     y.f = src;
439     *p_dest = y.fu;
440 }
441
442 static inline StgFloat PK_FLT(W_ p_src[])
443 {
444     float_thing y;
445     y.fu = *p_src;
446     return(y.f);
447 }
448
449 #endif /* ALIGNMENT_FLOAT > ALIGNMENT_LONG */
450
451 #if ALIGNMENT_DOUBLE <= ALIGNMENT_LONG
452
453 static inline void        ASSIGN_DBL (W_ [], StgDouble);
454 static inline StgDouble   PK_DBL     (W_ []);
455
456 static inline void      ASSIGN_DBL(W_ p_dest[], StgDouble src) { *(StgDouble *)p_dest = src; }
457 static inline StgDouble PK_DBL    (W_ p_src[])                 { return *(StgDouble *)p_src; }
458
459 #else   /* ALIGNMENT_DOUBLE > ALIGNMENT_LONG */
460
461 /* Sparc uses two floating point registers to hold a double.  We can
462  * write ASSIGN_DBL and PK_DBL by directly accessing the registers
463  * independently - unfortunately this code isn't writable in C, we
464  * have to use inline assembler.
465  */
466 #if sparc_TARGET_ARCH
467
468 #define ASSIGN_DBL(dst,src) \
469       __asm__("st %2,%0\n\tst %R2,%1" : "=m" (((P_)(dst))[0]), \
470         "=m" (((P_)(dst))[1]) : "f" (src));
471
472 #define PK_DBL(src) \
473     ( { register double d; \
474       __asm__("ld %1,%0\n\tld %2,%R0" : "=f" (d) : \
475         "m" (((P_)(src))[0]), "m" (((P_)(src))[1])); d; \
476     } )
477
478 #else /* ! sparc_TARGET_ARCH */
479
480 static inline void        ASSIGN_DBL (W_ [], StgDouble);
481 static inline StgDouble   PK_DBL     (W_ []);
482
483 typedef struct
484   { StgWord dhi;
485     StgWord dlo;
486   } unpacked_double;
487
488 typedef union
489   { StgDouble d;
490     unpacked_double du;
491   } double_thing;
492
493 static inline void ASSIGN_DBL(W_ p_dest[], StgDouble src)
494 {
495     double_thing y;
496     y.d = src;
497     p_dest[0] = y.du.dhi;
498     p_dest[1] = y.du.dlo;
499 }
500
501 /* GCC also works with this version, but it generates
502    the same code as the previous one, and is not ANSI
503
504 #define ASSIGN_DBL( p_dest, src ) \
505         *p_dest = ((double_thing) src).du.dhi; \
506         *(p_dest+1) = ((double_thing) src).du.dlo \
507 */
508
509 static inline StgDouble PK_DBL(W_ p_src[])
510 {
511     double_thing y;
512     y.du.dhi = p_src[0];
513     y.du.dlo = p_src[1];
514     return(y.d);
515 }
516
517 #endif /* ! sparc_TARGET_ARCH */
518
519 #endif /* ALIGNMENT_DOUBLE > ALIGNMENT_UNSIGNED_INT */
520
521 #ifdef SUPPORT_LONG_LONGS
522
523 typedef struct
524   { StgWord dhi;
525     StgWord dlo;
526   } unpacked_double_word;
527
528 typedef union
529   { StgInt64 i;
530     unpacked_double_word iu;
531   } int64_thing;
532
533 typedef union
534   { StgNat64 w;
535     unpacked_double_word wu;
536   } word64_thing;
537
538 static inline void ASSIGN_Word64(W_ p_dest[], StgNat64 src)
539 {
540     word64_thing y;
541     y.w = src;
542     p_dest[0] = y.wu.dhi;
543     p_dest[1] = y.wu.dlo;
544 }
545
546 static inline StgNat64 PK_Word64(W_ p_src[])
547 {
548     word64_thing y;
549     y.wu.dhi = p_src[0];
550     y.wu.dlo = p_src[1];
551     return(y.w);
552 }
553
554 static inline void ASSIGN_Int64(W_ p_dest[], StgInt64 src)
555 {
556     int64_thing y;
557     y.i = src;
558     p_dest[0] = y.iu.dhi;
559     p_dest[1] = y.iu.dlo;
560 }
561
562 static inline StgInt64 PK_Int64(W_ p_src[])
563 {
564     int64_thing y;
565     y.iu.dhi = p_src[0];
566     y.iu.dlo = p_src[1];
567     return(y.i);
568 }
569 #endif
570
571 /* -----------------------------------------------------------------------------
572    Catch frames
573    -------------------------------------------------------------------------- */
574
575 extern const StgPolyInfoTable catch_frame_info;
576
577 /* -----------------------------------------------------------------------------
578    Seq frames
579
580    A seq frame is very like an update frame, except that it doesn't do
581    an update...
582    -------------------------------------------------------------------------- */
583
584 extern const StgPolyInfoTable seq_frame_info;
585
586 #define PUSH_SEQ_FRAME(sp)                                      \
587         {                                                       \
588                 StgSeqFrame *__frame;                           \
589                 TICK_SEQF_PUSHED();                             \
590                 __frame = (StgSeqFrame *)(sp);                  \
591                 SET_HDR_(__frame,&seq_frame_info,CCCS);         \
592                 __frame->link = Su;                             \
593                 Su = (StgUpdateFrame *)__frame;                 \
594         }
595
596 /* -----------------------------------------------------------------------------
597    Split markers
598    -------------------------------------------------------------------------- */
599
600 #if defined(USE_SPLIT_MARKERS)
601 #define __STG_SPLIT_MARKER(n) FN_(__stg_split_marker##n) { }
602 #else
603 #define __STG_SPLIT_MARKER(n) /* nothing */
604 #endif
605
606 /* -----------------------------------------------------------------------------
607    Closure and Info Macros with casting.
608
609    We don't want to mess around with casts in the generated C code, so
610    we use these casting versions of the closure/info tables macros.
611    -------------------------------------------------------------------------- */
612
613 #define SET_HDR_(c,info,ccs) \
614    SET_HDR((StgClosure *)(c),(StgInfoTable *)(info),ccs)
615
616 /* -----------------------------------------------------------------------------
617    Saving context for exit from the STG world, and loading up context
618    on entry to STG code.
619
620    We save all the STG registers (that is, the ones that are mapped to
621    machine registers) in their places in the TSO.  
622
623    The stack registers go into the current stack object, and the heap
624    registers are saved in global locations.
625    -------------------------------------------------------------------------- */
626
627 static __inline__ void
628 SaveThreadState(void)
629 {
630   /* Don't need to save REG_Base, it won't have changed. */
631
632   CurrentTSO->sp       = Sp;
633   CurrentTSO->su       = Su;
634   CurrentTSO->splim    = SpLim;
635   CloseNursery(Hp);
636
637 #if defined(PROFILING)
638   CurrentTSO->prof.CCCS = CCCS;
639 #endif
640 }
641
642 static __inline__ void 
643 LoadThreadState (void)
644 {
645 #ifdef REG_Base
646   BaseReg = &MainRegTable;
647 #endif
648
649   Sp    = CurrentTSO->sp;
650   Su    = CurrentTSO->su;
651   SpLim = CurrentTSO->splim;
652   OpenNursery(Hp,HpLim);
653
654 # if defined(PROFILING)
655   CCCS = CurrentTSO->prof.CCCS;
656 # endif
657 }
658
659 #endif /* STGMACROS_H */
660