1 /* -----------------------------------------------------------------------------
2 * $Id: StgMacros.h,v 1.19 1999/11/22 16:44:30 sewardj Exp $
4 * (c) The GHC Team, 1998-1999
6 * Macros used for writing STG-ish C code.
8 * ---------------------------------------------------------------------------*/
13 /* -----------------------------------------------------------------------------
14 The following macros create function headers.
16 Each basic block is represented by a C function with no arguments.
17 We therefore always begin with either
25 The macros can be used either to define the function itself, or to provide
26 prototypes (by following with a ';').
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.
34 This might seem obvious, but it had me stumped as to why my info tables
35 were suddenly all filled with 0s.
39 --------------------------------------------------------------------------- */
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)
51 #define EDD_ extern DLLIMPORT
52 #define ED_RO_ extern const
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)[]
65 /* -----------------------------------------------------------------------------
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
71 -------------------------------------------------------------------------- */
73 #define ARGTAG_MAX 16 /* probably arbitrary */
74 #define ARG_TAG(n) (n)
75 #define ARG_SIZE(n) (StgWord)n
79 INT_TAG = sizeofW(StgInt),
80 INT64_TAG = sizeofW(StgInt64),
81 WORD_TAG = sizeofW(StgWord),
82 ADDR_TAG = sizeofW(StgAddr),
83 CHAR_TAG = sizeofW(StgChar),
84 FLOAT_TAG = sizeofW(StgFloat),
85 DOUBLE_TAG = sizeofW(StgDouble),
86 STABLE_TAG = sizeofW(StgWord),
89 static inline int IS_ARG_TAG( StgWord p );
90 static inline int IS_ARG_TAG( StgWord p ) { return p <= ARGTAG_MAX; }
92 /* -----------------------------------------------------------------------------
95 If (Sp + <n_args>) > Su { JMP_(stg_update_PAP); }
97 Sp points to the topmost used word on the stack, and Su points to
98 the most recently pushed update frame.
100 Remember that <n_args> must include any tagging of unboxed values.
102 ARGS_CHK_LOAD_NODE is for top-level functions, whose entry
103 convention doesn't require that Node is loaded with a pointer to
104 the closure. Thus we must load node before calling stg_updatePAP if
105 the argument check fails.
106 -------------------------------------------------------------------------- */
108 #define ARGS_CHK(n) \
109 if ((P_)(Sp + (n)) > (P_)Su) { \
110 JMP_(stg_update_PAP); \
113 #define ARGS_CHK_LOAD_NODE(n,closure) \
114 if ((P_)(Sp + (n)) > (P_)Su) { \
115 R1.p = (P_)closure; \
116 JMP_(stg_update_PAP); \
119 /* -----------------------------------------------------------------------------
122 When failing a check, we save a return address on the stack and
123 jump to a pre-compiled code fragment that saves the live registers
124 and returns to the scheduler.
126 The return address in most cases will be the beginning of the basic
127 block in which the check resides, since we need to perform the check
128 again on re-entry because someone else might have stolen the resource
130 ------------------------------------------------------------------------- */
132 #define STK_CHK(headroom,ret,r,layout,tag_assts) \
133 if (Sp - headroom < SpLim) { \
134 EXTFUN_RTS(stg_chk_##layout); \
137 JMP_(stg_chk_##layout); \
140 #define HP_CHK(headroom,ret,r,layout,tag_assts) \
141 if ((Hp += headroom) > HpLim) { \
142 EXTFUN_RTS(stg_chk_##layout); \
145 JMP_(stg_chk_##layout); \
148 #define HP_STK_CHK(stk_headroom,hp_headroom,ret,r,layout,tag_assts) \
149 if (Sp - stk_headroom < SpLim || (Hp += hp_headroom) > HpLim) { \
150 EXTFUN_RTS(stg_chk_##layout); \
153 JMP_(stg_chk_##layout); \
156 /* -----------------------------------------------------------------------------
157 A Heap Check in a case alternative are much simpler: everything is
158 on the stack and covered by a liveness mask already, and there is
159 even a return address with an SRT info table there as well.
161 Just push R1 and return to the scheduler saying 'EnterGHC'
163 {STK,HP,HP_STK}_CHK_NP are the various checking macros for
164 bog-standard case alternatives, thunks, and non-top-level
165 functions. In all these cases, node points to a closure that we
166 can just enter to restart the heap check (the NP stands for 'node points').
168 HpLim points to the LAST WORD of valid allocation space.
169 -------------------------------------------------------------------------- */
171 #define STK_CHK_NP(headroom,ptrs,tag_assts) \
172 if ((Sp - (headroom)) < SpLim) { \
173 EXTFUN_RTS(stg_gc_enter_##ptrs); \
175 JMP_(stg_gc_enter_##ptrs); \
178 #define HP_CHK_NP(headroom,ptrs,tag_assts) \
179 if ((Hp += (headroom)) > HpLim) { \
180 EXTFUN_RTS(stg_gc_enter_##ptrs); \
182 JMP_(stg_gc_enter_##ptrs); \
185 #define HP_CHK_SEQ_NP(headroom,ptrs,tag_assts) \
186 if ((Hp += (headroom)) > HpLim) { \
187 EXTFUN_RTS(stg_gc_seq_##ptrs); \
189 JMP_(stg_gc_seq_##ptrs); \
192 #define HP_STK_CHK_NP(stk_headroom, hp_headroom, ptrs, tag_assts) \
193 if ((Sp - (stk_headroom)) < SpLim || (Hp += (hp_headroom)) > HpLim) { \
194 EXTFUN_RTS(stg_gc_enter_##ptrs); \
196 JMP_(stg_gc_enter_##ptrs); \
200 /* Heap checks for branches of a primitive case / unboxed tuple return */
202 #define GEN_HP_CHK_ALT(headroom,lbl,tag_assts) \
203 if ((Hp += (headroom)) > HpLim) { \
209 #define HP_CHK_NOREGS(headroom,tag_assts) \
210 GEN_HP_CHK_ALT(headroom,stg_gc_noregs,tag_assts);
211 #define HP_CHK_UNPT_R1(headroom,tag_assts) \
212 GEN_HP_CHK_ALT(headroom,stg_gc_unpt_r1,tag_assts);
213 #define HP_CHK_UNBX_R1(headroom,tag_assts) \
214 GEN_HP_CHK_ALT(headroom,stg_gc_unbx_r1,tag_assts);
215 #define HP_CHK_F1(headroom,tag_assts) \
216 GEN_HP_CHK_ALT(headroom,stg_gc_f1,tag_assts);
217 #define HP_CHK_D1(headroom,tag_assts) \
218 GEN_HP_CHK_ALT(headroom,stg_gc_d1,tag_assts);
220 #define HP_CHK_L1(headroom,tag_assts) \
221 GEN_HP_CHK_ALT(headroom,stg_gc_d1,tag_assts);
223 #define HP_CHK_UT_ALT(headroom, ptrs, nptrs, r, ret, tag_assts) \
224 GEN_HP_CHK_ALT(headroom, stg_gc_ut_##ptrs##_##nptrs, \
225 tag_assts r = (P_)ret;)
227 /* -----------------------------------------------------------------------------
230 These are slow, but have the advantage of being usable in a variety
233 The one restriction is that any relevant SRTs must already be pointed
234 to from the stack. The return address doesn't need to have an info
235 table attached: hence it can be any old code pointer.
237 The liveness mask is a logical 'XOR' of NO_PTRS and zero or more
238 Rn_PTR constants defined below. All registers will be saved, but
239 the garbage collector needs to know which ones contain pointers.
241 Good places to use a generic heap check:
243 - case alternatives (the return address with an SRT is already
246 - primitives (no SRT required).
248 The stack layout is like this:
257 so the liveness mask depends on the size of an StgDouble (FltRegs
258 and R<n> are guaranteed to be 1 word in size).
260 -------------------------------------------------------------------------- */
262 /* VERY MAGIC CONSTANTS!
263 * must agree with code in HeapStackCheck.c, stg_gen_chk
266 #if SIZEOF_DOUBLE > SIZEOF_VOID_P
267 #define ALL_NON_PTRS 0xffff
268 #else /* SIZEOF_DOUBLE == SIZEOF_VOID_P */
269 #define ALL_NON_PTRS 0x3fff
272 #define LIVENESS_MASK(ptr_regs) (ALL_NON_PTRS ^ (ptr_regs))
284 #define HP_CHK_GEN(headroom,liveness,reentry,tag_assts) \
285 if ((Hp += (headroom)) > HpLim ) { \
288 R9.w = (W_)LIVENESS_MASK(liveness); \
289 R10.w = (W_)reentry; \
293 #define HP_CHK_GEN_TICKY(headroom,liveness,reentry,tag_assts) \
294 HP_CHK_GEN(headroom,liveness,reentry,tag_assts); \
295 TICK_ALLOC_HEAP_NOCTR(headroom)
297 #define STK_CHK_GEN(headroom,liveness,reentry,tag_assts) \
298 if ((Sp - (headroom)) < SpLim) { \
301 R9.w = (W_)LIVENESS_MASK(liveness); \
302 R10.w = (W_)reentry; \
306 #define MAYBE_GC(liveness,reentry) \
307 if (doYouWantToGC()) { \
309 R9.w = (W_)LIVENESS_MASK(liveness); \
310 R10.w = (W_)reentry; \
314 /* -----------------------------------------------------------------------------
315 Voluntary Yields/Blocks
317 We only have a generic version of this at the moment - if it turns
318 out to be slowing us down we can make specialised ones.
319 -------------------------------------------------------------------------- */
324 #define YIELD(liveness,reentry) \
326 R9.w = (W_)LIVENESS_MASK(liveness); \
327 R10.w = (W_)reentry; \
328 JMP_(stg_gen_yield); \
331 #define BLOCK(liveness,reentry) \
333 R9.w = (W_)LIVENESS_MASK(liveness); \
334 R10.w = (W_)reentry; \
335 JMP_(stg_gen_block); \
338 #define BLOCK_NP(ptrs) \
340 EF_(stg_block_##ptrs); \
341 JMP_(stg_block_##ptrs); \
344 /* -----------------------------------------------------------------------------
345 CCall_GC needs to push a dummy stack frame containing the contents
346 of volatile registers and variables.
348 We use a RET_DYN frame the same as for a dynamic heap check.
349 ------------------------------------------------------------------------- */
352 EI_(stg_gen_chk_info);
354 EDI_(stg_gen_chk_info);
356 /* -----------------------------------------------------------------------------
359 RETVEC(p,t) where 'p' is a pointer to the info table for a
360 vectored return address, returns the address of the return code for
363 Return vectors are placed in *reverse order* immediately before the info
364 table for the return address. Hence the formula for computing the
365 actual return address is (addr - sizeof(InfoTable) - tag - 1).
366 The extra subtraction of one word is because tags start at zero.
367 -------------------------------------------------------------------------- */
369 #ifdef TABLES_NEXT_TO_CODE
370 #define RET_VEC(p,t) (*((P_)(p) - sizeofW(StgInfoTable) - t - 1))
372 #define RET_VEC(p,t) (((StgInfoTable *)p)->vector[t])
375 /* -----------------------------------------------------------------------------
377 -------------------------------------------------------------------------- */
380 /* set the tag register (if we have one) */
381 #define SET_TAG(t) /* nothing */
383 #ifdef EAGER_BLACKHOLING
385 # define UPD_BH_UPDATABLE(info) \
386 TICK_UPD_BH_UPDATABLE(); \
388 bdescr *bd = Bdescr(R1.p); \
389 if (bd->back != (bdescr *)BaseReg) { \
390 if (bd->gen->no >= 1 || bd->step->no >= 1) { \
393 EXTFUN_RTS(stg_gc_enter_1_hponly); \
394 JMP_(stg_gc_enter_1_hponly); \
398 SET_INFO(R1.cl,&BLACKHOLE_info)
399 # define UPD_BH_SINGLE_ENTRY(info) \
400 TICK_UPD_BH_SINGLE_ENTRY(); \
402 bdescr *bd = Bdescr(R1.p); \
403 if (bd->back != (bdescr *)BaseReg) { \
404 if (bd->gen->no >= 1 || bd->step->no >= 1) { \
407 EXTFUN_RTS(stg_gc_enter_1_hponly); \
408 JMP_(stg_gc_enter_1_hponly); \
412 SET_INFO(R1.cl,&BLACKHOLE_info)
414 # define UPD_BH_UPDATABLE(info) \
415 TICK_UPD_BH_UPDATABLE(); \
416 SET_INFO(R1.cl,&BLACKHOLE_info)
417 # define UPD_BH_SINGLE_ENTRY(info) \
418 TICK_UPD_BH_SINGLE_ENTRY(); \
419 SET_INFO(R1.cl,&SE_BLACKHOLE_info)
421 #else /* !EAGER_BLACKHOLING */
422 # define UPD_BH_UPDATABLE(thunk) /* nothing */
423 # define UPD_BH_SINGLE_ENTRY(thunk) /* nothing */
424 #endif /* EAGER_BLACKHOLING */
426 #define UPD_FRAME_UPDATEE(p) (((StgUpdateFrame *)(p))->updatee)
427 #define UPDATE_SU_FROM_UPD_FRAME(p) (Su=((StgUpdateFrame *)(p))->link)
429 /* -----------------------------------------------------------------------------
430 Moving Floats and Doubles
432 ASSIGN_FLT is for assigning a float to memory (usually the
433 stack/heap). The memory address is guaranteed to be
434 StgWord aligned (currently == sizeof(long)).
436 PK_FLT is for pulling a float out of memory. The memory is
437 guaranteed to be StgWord aligned.
438 -------------------------------------------------------------------------- */
440 static inline void ASSIGN_FLT (W_ [], StgFloat);
441 static inline StgFloat PK_FLT (W_ []);
443 #if ALIGNMENT_FLOAT <= ALIGNMENT_LONG
445 static inline void ASSIGN_FLT(W_ p_dest[], StgFloat src) { *(StgFloat *)p_dest = src; }
446 static inline StgFloat PK_FLT (W_ p_src[]) { return *(StgFloat *)p_src; }
448 #else /* ALIGNMENT_FLOAT > ALIGNMENT_UNSIGNED_INT */
450 static inline void ASSIGN_FLT(W_ p_dest[], StgFloat src)
457 static inline StgFloat PK_FLT(W_ p_src[])
464 #endif /* ALIGNMENT_FLOAT > ALIGNMENT_LONG */
466 #if ALIGNMENT_DOUBLE <= ALIGNMENT_LONG
468 static inline void ASSIGN_DBL (W_ [], StgDouble);
469 static inline StgDouble PK_DBL (W_ []);
471 static inline void ASSIGN_DBL(W_ p_dest[], StgDouble src) { *(StgDouble *)p_dest = src; }
472 static inline StgDouble PK_DBL (W_ p_src[]) { return *(StgDouble *)p_src; }
474 #else /* ALIGNMENT_DOUBLE > ALIGNMENT_LONG */
476 /* Sparc uses two floating point registers to hold a double. We can
477 * write ASSIGN_DBL and PK_DBL by directly accessing the registers
478 * independently - unfortunately this code isn't writable in C, we
479 * have to use inline assembler.
481 #if sparc_TARGET_ARCH
483 #define ASSIGN_DBL(dst0,src) \
484 { StgPtr dst = (StgPtr)(dst0); \
485 __asm__("st %2,%0\n\tst %R2,%1" : "=m" (((P_)(dst))[0]), \
486 "=m" (((P_)(dst))[1]) : "f" (src)); \
489 #define PK_DBL(src0) \
490 ( { StgPtr src = (StgPtr)(src0); \
492 __asm__("ld %1,%0\n\tld %2,%R0" : "=f" (d) : \
493 "m" (((P_)(src))[0]), "m" (((P_)(src))[1])); d; \
496 #else /* ! sparc_TARGET_ARCH */
498 static inline void ASSIGN_DBL (W_ [], StgDouble);
499 static inline StgDouble PK_DBL (W_ []);
511 static inline void ASSIGN_DBL(W_ p_dest[], StgDouble src)
515 p_dest[0] = y.du.dhi;
516 p_dest[1] = y.du.dlo;
519 /* GCC also works with this version, but it generates
520 the same code as the previous one, and is not ANSI
522 #define ASSIGN_DBL( p_dest, src ) \
523 *p_dest = ((double_thing) src).du.dhi; \
524 *(p_dest+1) = ((double_thing) src).du.dlo \
527 static inline StgDouble PK_DBL(W_ p_src[])
535 #endif /* ! sparc_TARGET_ARCH */
537 #endif /* ALIGNMENT_DOUBLE > ALIGNMENT_UNSIGNED_INT */
539 #ifdef SUPPORT_LONG_LONGS
544 } unpacked_double_word;
548 unpacked_double_word iu;
553 unpacked_double_word wu;
556 static inline void ASSIGN_Word64(W_ p_dest[], StgWord64 src)
560 p_dest[0] = y.wu.dhi;
561 p_dest[1] = y.wu.dlo;
564 static inline StgWord64 PK_Word64(W_ p_src[])
572 static inline void ASSIGN_Int64(W_ p_dest[], StgInt64 src)
576 p_dest[0] = y.iu.dhi;
577 p_dest[1] = y.iu.dlo;
580 static inline StgInt64 PK_Int64(W_ p_src[])
589 /* -----------------------------------------------------------------------------
591 -------------------------------------------------------------------------- */
593 extern DLL_IMPORT_DATA const StgPolyInfoTable catch_frame_info;
595 /* -----------------------------------------------------------------------------
598 A seq frame is very like an update frame, except that it doesn't do
600 -------------------------------------------------------------------------- */
602 extern DLL_IMPORT_DATA const StgPolyInfoTable seq_frame_info;
604 #define PUSH_SEQ_FRAME(sp) \
606 StgSeqFrame *__frame; \
607 TICK_SEQF_PUSHED(); \
608 __frame = (StgSeqFrame *)(sp); \
609 SET_HDR_(__frame,&seq_frame_info,CCCS); \
610 __frame->link = Su; \
611 Su = (StgUpdateFrame *)__frame; \
614 /* -----------------------------------------------------------------------------
616 -------------------------------------------------------------------------- */
618 #if defined(USE_SPLIT_MARKERS)
619 #define __STG_SPLIT_MARKER(n) FN_(__stg_split_marker##n) { }
621 #define __STG_SPLIT_MARKER(n) /* nothing */
624 /* -----------------------------------------------------------------------------
625 Closure and Info Macros with casting.
627 We don't want to mess around with casts in the generated C code, so
628 we use these casting versions of the closure/info tables macros.
629 -------------------------------------------------------------------------- */
631 #define SET_HDR_(c,info,ccs) \
632 SET_HDR((StgClosure *)(c),(StgInfoTable *)(info),ccs)
634 /* -----------------------------------------------------------------------------
635 Saving context for exit from the STG world, and loading up context
636 on entry to STG code.
638 We save all the STG registers (that is, the ones that are mapped to
639 machine registers) in their places in the TSO.
641 The stack registers go into the current stack object, and the
642 current nursery is updated from the heap pointer.
644 These functions assume that BaseReg is loaded appropriately (if
646 -------------------------------------------------------------------------- */
650 static __inline__ void
651 SaveThreadState(void)
653 /* Don't need to save REG_Base, it won't have changed. */
657 CurrentTSO->splim = SpLim;
660 #ifdef REG_CurrentTSO
661 SAVE_CurrentTSO = CurrentTSO;
663 #ifdef REG_CurrentNursery
664 SAVE_CurrentNursery = CurrentNursery;
666 #if defined(PROFILING)
667 CurrentTSO->prof.CCCS = CCCS;
671 static __inline__ void
672 LoadThreadState (void)
676 SpLim = CurrentTSO->splim;
677 OpenNursery(Hp,HpLim);
679 #ifdef REG_CurrentTSO
680 CurrentTSO = SAVE_CurrentTSO;
682 #ifdef REG_CurrentNursery
683 CurrentNursery = SAVE_CurrentNursery;
685 # if defined(PROFILING)
686 CCCS = CurrentTSO->prof.CCCS;
692 /* -----------------------------------------------------------------------------
693 Support for _ccall_GC_ and _casm_GC.
694 -------------------------------------------------------------------------- */
697 * Suspending/resuming threads for doing external C-calls (_ccall_GC).
698 * These functions are defined in rts/Schedule.c.
700 StgInt suspendThread ( StgRegTable *cap );
701 StgRegTable * resumeThread ( StgInt );
703 #define SUSPEND_THREAD(token) \
705 token = suspendThread(BaseReg);
708 #define RESUME_THREAD(token) \
709 BaseReg = resumeThread(token); \
712 #define RESUME_THREAD(token) \
713 (void)resumeThread(token); \
717 #endif /* STGMACROS_H */