1 /* -----------------------------------------------------------------------------
2 * $Id: StgMacros.h,v 1.37 2000/12/04 12:31:20 simonmar 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)
50 #define EXTINFO_RTS extern DLL_IMPORT_RTS INFO_TBL_CONST StgInfoTable
52 #define EDD_ extern DLLIMPORT
53 #define ED_RO_ extern const
55 #define ID_RO_ static const
56 #define EI_ extern INFO_TBL_CONST StgInfoTable
57 #define EDI_ extern DLLIMPORT INFO_TBL_CONST StgInfoTable
58 #define II_ static INFO_TBL_CONST StgInfoTable
59 #define EC_ extern StgClosure
60 #define EDC_ extern DLLIMPORT StgClosure
61 #define IC_ static StgClosure
62 #define ECP_(x) extern const StgClosure *(x)[]
63 #define EDCP_(x) extern DLLIMPORT StgClosure *(x)[]
64 #define ICP_(x) static const StgClosure *(x)[]
66 /* -----------------------------------------------------------------------------
69 For a block of non-pointer words on the stack, we precede the
70 block with a small-integer tag giving the number of non-pointer
72 -------------------------------------------------------------------------- */
74 #define ARGTAG_MAX 16 /* probably arbitrary */
75 #define ARG_TAG(n) (n)
76 #define ARG_SIZE(n) (StgWord)n
80 INT_TAG = sizeofW(StgInt),
81 INT64_TAG = sizeofW(StgInt64),
82 WORD_TAG = sizeofW(StgWord),
83 ADDR_TAG = sizeofW(StgAddr),
84 CHAR_TAG = sizeofW(StgChar),
85 FLOAT_TAG = sizeofW(StgFloat),
86 DOUBLE_TAG = sizeofW(StgDouble),
87 STABLE_TAG = sizeofW(StgWord),
90 static inline int IS_ARG_TAG( StgWord p );
91 static inline int IS_ARG_TAG( StgWord p ) { return p <= ARGTAG_MAX; }
93 /* -----------------------------------------------------------------------------
96 If (Sp + <n_args>) > Su { JMP_(stg_update_PAP); }
98 Sp points to the topmost used word on the stack, and Su points to
99 the most recently pushed update frame.
101 Remember that <n_args> must include any tagging of unboxed values.
103 ARGS_CHK_LOAD_NODE is for top-level functions, whose entry
104 convention doesn't require that Node is loaded with a pointer to
105 the closure. Thus we must load node before calling stg_updatePAP if
106 the argument check fails.
107 -------------------------------------------------------------------------- */
109 #define ARGS_CHK(n) \
110 if ((P_)(Sp + (n)) > (P_)Su) { \
111 JMP_(stg_update_PAP); \
114 #define ARGS_CHK_LOAD_NODE(n,closure) \
115 if ((P_)(Sp + (n)) > (P_)Su) { \
116 R1.p = (P_)closure; \
117 JMP_(stg_update_PAP); \
120 /* -----------------------------------------------------------------------------
123 When failing a check, we save a return address on the stack and
124 jump to a pre-compiled code fragment that saves the live registers
125 and returns to the scheduler.
127 The return address in most cases will be the beginning of the basic
128 block in which the check resides, since we need to perform the check
129 again on re-entry because someone else might have stolen the resource
131 ------------------------------------------------------------------------- */
133 #define STK_CHK(headroom,ret,r,layout,tag_assts) \
134 if (Sp - headroom < SpLim) { \
135 EXTFUN_RTS(stg_chk_##layout); \
138 JMP_(stg_chk_##layout); \
141 #define HP_CHK(headroom,ret,r,layout,tag_assts) \
142 DO_GRAN_ALLOCATE(headroom) \
143 if ((Hp += headroom) > HpLim) { \
144 EXTFUN_RTS(stg_chk_##layout); \
147 JMP_(stg_chk_##layout); \
150 #define HP_STK_CHK(stk_headroom,hp_headroom,ret,r,layout,tag_assts) \
151 DO_GRAN_ALLOCATE(hp_headroom) \
152 if (Sp - stk_headroom < SpLim || (Hp += hp_headroom) > HpLim) { \
153 EXTFUN_RTS(stg_chk_##layout); \
156 JMP_(stg_chk_##layout); \
159 /* -----------------------------------------------------------------------------
160 A Heap Check in a case alternative are much simpler: everything is
161 on the stack and covered by a liveness mask already, and there is
162 even a return address with an SRT info table there as well.
164 Just push R1 and return to the scheduler saying 'EnterGHC'
166 {STK,HP,HP_STK}_CHK_NP are the various checking macros for
167 bog-standard case alternatives, thunks, and non-top-level
168 functions. In all these cases, node points to a closure that we
169 can just enter to restart the heap check (the NP stands for 'node points').
171 In the NP case GranSim absolutely has to check whether the current node
172 resides on the current processor. Otherwise a FETCH event has to be
173 scheduled. All that is done in GranSimFetch. -- HWL
175 HpLim points to the LAST WORD of valid allocation space.
176 -------------------------------------------------------------------------- */
178 #define STK_CHK_NP(headroom,ptrs,tag_assts) \
179 if ((Sp - (headroom)) < SpLim) { \
180 EXTFUN_RTS(stg_gc_enter_##ptrs); \
182 JMP_(stg_gc_enter_##ptrs); \
185 #define HP_CHK_NP(headroom,ptrs,tag_assts) \
186 DO_GRAN_ALLOCATE(headroom) \
187 if ((Hp += (headroom)) > HpLim) { \
188 EXTFUN_RTS(stg_gc_enter_##ptrs); \
190 JMP_(stg_gc_enter_##ptrs); \
193 #define HP_CHK_SEQ_NP(headroom,ptrs,tag_assts) \
194 DO_GRAN_ALLOCATE(headroom) \
195 if ((Hp += (headroom)) > HpLim) { \
196 EXTFUN_RTS(stg_gc_seq_##ptrs); \
198 JMP_(stg_gc_seq_##ptrs); \
201 #define HP_STK_CHK_NP(stk_headroom, hp_headroom, ptrs, tag_assts) \
202 DO_GRAN_ALLOCATE(hp_headroom) \
203 if ((Sp - (stk_headroom)) < SpLim || (Hp += (hp_headroom)) > HpLim) { \
204 EXTFUN_RTS(stg_gc_enter_##ptrs); \
206 JMP_(stg_gc_enter_##ptrs); \
210 /* Heap checks for branches of a primitive case / unboxed tuple return */
212 #define GEN_HP_CHK_ALT(headroom,lbl,tag_assts) \
213 DO_GRAN_ALLOCATE(headroom) \
214 if ((Hp += (headroom)) > HpLim) { \
220 #define HP_CHK_NOREGS(headroom,tag_assts) \
221 GEN_HP_CHK_ALT(headroom,stg_gc_noregs,tag_assts);
222 #define HP_CHK_UNPT_R1(headroom,tag_assts) \
223 GEN_HP_CHK_ALT(headroom,stg_gc_unpt_r1,tag_assts);
224 #define HP_CHK_UNBX_R1(headroom,tag_assts) \
225 GEN_HP_CHK_ALT(headroom,stg_gc_unbx_r1,tag_assts);
226 #define HP_CHK_F1(headroom,tag_assts) \
227 GEN_HP_CHK_ALT(headroom,stg_gc_f1,tag_assts);
228 #define HP_CHK_D1(headroom,tag_assts) \
229 GEN_HP_CHK_ALT(headroom,stg_gc_d1,tag_assts);
231 #define HP_CHK_L1(headroom,tag_assts) \
232 GEN_HP_CHK_ALT(headroom,stg_gc_d1,tag_assts);
234 #define HP_CHK_UT_ALT(headroom, ptrs, nptrs, r, ret, tag_assts) \
235 GEN_HP_CHK_ALT(headroom, stg_gc_ut_##ptrs##_##nptrs, \
236 tag_assts r = (P_)ret;)
238 /* -----------------------------------------------------------------------------
241 These are slow, but have the advantage of being usable in a variety
244 The one restriction is that any relevant SRTs must already be pointed
245 to from the stack. The return address doesn't need to have an info
246 table attached: hence it can be any old code pointer.
248 The liveness mask is a logical 'XOR' of NO_PTRS and zero or more
249 Rn_PTR constants defined below. All registers will be saved, but
250 the garbage collector needs to know which ones contain pointers.
252 Good places to use a generic heap check:
254 - case alternatives (the return address with an SRT is already
257 - primitives (no SRT required).
259 The stack layout is like this:
268 so the liveness mask depends on the size of an StgDouble (FltRegs
269 and R<n> are guaranteed to be 1 word in size).
271 -------------------------------------------------------------------------- */
273 /* VERY MAGIC CONSTANTS!
274 * must agree with code in HeapStackCheck.c, stg_gen_chk
277 #if SIZEOF_DOUBLE > SIZEOF_VOID_P
278 #define ALL_NON_PTRS 0xffff
279 #else /* SIZEOF_DOUBLE == SIZEOF_VOID_P */
280 #define ALL_NON_PTRS 0x3fff
283 #define LIVENESS_MASK(ptr_regs) (ALL_NON_PTRS ^ (ptr_regs))
295 #define HP_CHK_GEN(headroom,liveness,reentry,tag_assts) \
296 if ((Hp += (headroom)) > HpLim ) { \
297 EXTFUN_RTS(stg_gen_chk); \
299 R9.w = (W_)LIVENESS_MASK(liveness); \
300 R10.w = (W_)reentry; \
304 #define HP_CHK_GEN_TICKY(headroom,liveness,reentry,tag_assts) \
305 HP_CHK_GEN(headroom,liveness,reentry,tag_assts); \
306 TICK_ALLOC_HEAP_NOCTR(headroom)
308 #define STK_CHK_GEN(headroom,liveness,reentry,tag_assts) \
309 if ((Sp - (headroom)) < SpLim) { \
310 EXTFUN_RTS(stg_gen_chk); \
312 R9.w = (W_)LIVENESS_MASK(liveness); \
313 R10.w = (W_)reentry; \
317 #define MAYBE_GC(liveness,reentry) \
318 if (doYouWantToGC()) { \
319 EXTFUN_RTS(stg_gen_hp); \
320 R9.w = (W_)LIVENESS_MASK(liveness); \
321 R10.w = (W_)reentry; \
325 /* -----------------------------------------------------------------------------
326 Voluntary Yields/Blocks
328 We only have a generic version of this at the moment - if it turns
329 out to be slowing us down we can make specialised ones.
330 -------------------------------------------------------------------------- */
332 EXTFUN_RTS(stg_gen_yield);
333 EXTFUN_RTS(stg_gen_block);
335 #define YIELD(liveness,reentry) \
337 R9.w = (W_)LIVENESS_MASK(liveness); \
338 R10.w = (W_)reentry; \
339 JMP_(stg_gen_yield); \
342 #define BLOCK(liveness,reentry) \
344 R9.w = (W_)LIVENESS_MASK(liveness); \
345 R10.w = (W_)reentry; \
346 JMP_(stg_gen_block); \
349 #define BLOCK_NP(ptrs) \
351 EXTFUN_RTS(stg_block_##ptrs); \
352 JMP_(stg_block_##ptrs); \
357 Similar to BLOCK_NP but separates the saving of the thread state from the
358 actual jump via an StgReturn
361 #define SAVE_THREAD_STATE(ptrs) \
367 #define THREAD_RETURN(ptrs) \
369 CurrentTSO->what_next = ThreadEnterGHC; \
370 R1.i = ThreadBlocked; \
374 /* -----------------------------------------------------------------------------
375 CCall_GC needs to push a dummy stack frame containing the contents
376 of volatile registers and variables.
378 We use a RET_DYN frame the same as for a dynamic heap check.
379 ------------------------------------------------------------------------- */
381 EXTINFO_RTS(stg_gen_chk_info);
383 /* -----------------------------------------------------------------------------
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
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 -------------------------------------------------------------------------- */
396 #ifdef TABLES_NEXT_TO_CODE
397 #define RET_VEC(p,t) (*((P_)(p) - sizeofW(StgInfoTable) - t - 1))
399 #define RET_VEC(p,t) (((StgInfoTable *)p)->vector[t])
402 /* -----------------------------------------------------------------------------
404 -------------------------------------------------------------------------- */
407 /* set the tag register (if we have one) */
408 #define SET_TAG(t) /* nothing */
410 #ifdef EAGER_BLACKHOLING
412 # define UPD_BH_UPDATABLE(info) \
413 TICK_UPD_BH_UPDATABLE(); \
415 bdescr *bd = Bdescr(R1.p); \
416 if (bd->back != (bdescr *)BaseReg) { \
417 if (bd->gen->no >= 1 || bd->step->no >= 1) { \
420 EXTFUN_RTS(stg_gc_enter_1_hponly); \
421 JMP_(stg_gc_enter_1_hponly); \
425 SET_INFO(R1.cl,&stg_BLACKHOLE_info)
426 # define UPD_BH_SINGLE_ENTRY(info) \
427 TICK_UPD_BH_SINGLE_ENTRY(); \
429 bdescr *bd = Bdescr(R1.p); \
430 if (bd->back != (bdescr *)BaseReg) { \
431 if (bd->gen->no >= 1 || bd->step->no >= 1) { \
434 EXTFUN_RTS(stg_gc_enter_1_hponly); \
435 JMP_(stg_gc_enter_1_hponly); \
439 SET_INFO(R1.cl,&stg_BLACKHOLE_info)
441 # define UPD_BH_UPDATABLE(info) \
442 TICK_UPD_BH_UPDATABLE(); \
443 SET_INFO(R1.cl,&stg_BLACKHOLE_info)
444 # define UPD_BH_SINGLE_ENTRY(info) \
445 TICK_UPD_BH_SINGLE_ENTRY(); \
446 SET_INFO(R1.cl,&stg_SE_BLACKHOLE_info)
448 #else /* !EAGER_BLACKHOLING */
449 # define UPD_BH_UPDATABLE(thunk) /* nothing */
450 # define UPD_BH_SINGLE_ENTRY(thunk) /* nothing */
451 #endif /* EAGER_BLACKHOLING */
453 #define UPD_FRAME_UPDATEE(p) ((P_)(((StgUpdateFrame *)(p))->updatee))
454 #define UPDATE_SU_FROM_UPD_FRAME(p) (Su=((StgUpdateFrame *)(p))->link)
456 /* -----------------------------------------------------------------------------
457 Moving Floats and Doubles
459 ASSIGN_FLT is for assigning a float to memory (usually the
460 stack/heap). The memory address is guaranteed to be
461 StgWord aligned (currently == sizeof(long)).
463 PK_FLT is for pulling a float out of memory. The memory is
464 guaranteed to be StgWord aligned.
465 -------------------------------------------------------------------------- */
467 static inline void ASSIGN_FLT (W_ [], StgFloat);
468 static inline StgFloat PK_FLT (W_ []);
470 #if ALIGNMENT_FLOAT <= ALIGNMENT_LONG
472 static inline void ASSIGN_FLT(W_ p_dest[], StgFloat src) { *(StgFloat *)p_dest = src; }
473 static inline StgFloat PK_FLT (W_ p_src[]) { return *(StgFloat *)p_src; }
475 #else /* ALIGNMENT_FLOAT > ALIGNMENT_UNSIGNED_INT */
477 static inline void ASSIGN_FLT(W_ p_dest[], StgFloat src)
484 static inline StgFloat PK_FLT(W_ p_src[])
491 #endif /* ALIGNMENT_FLOAT > ALIGNMENT_LONG */
493 #if ALIGNMENT_DOUBLE <= ALIGNMENT_LONG
495 static inline void ASSIGN_DBL (W_ [], StgDouble);
496 static inline StgDouble PK_DBL (W_ []);
498 static inline void ASSIGN_DBL(W_ p_dest[], StgDouble src) { *(StgDouble *)p_dest = src; }
499 static inline StgDouble PK_DBL (W_ p_src[]) { return *(StgDouble *)p_src; }
501 #else /* ALIGNMENT_DOUBLE > ALIGNMENT_LONG */
503 /* Sparc uses two floating point registers to hold a double. We can
504 * write ASSIGN_DBL and PK_DBL by directly accessing the registers
505 * independently - unfortunately this code isn't writable in C, we
506 * have to use inline assembler.
508 #if sparc_TARGET_ARCH
510 #define ASSIGN_DBL(dst0,src) \
511 { StgPtr dst = (StgPtr)(dst0); \
512 __asm__("st %2,%0\n\tst %R2,%1" : "=m" (((P_)(dst))[0]), \
513 "=m" (((P_)(dst))[1]) : "f" (src)); \
516 #define PK_DBL(src0) \
517 ( { StgPtr src = (StgPtr)(src0); \
519 __asm__("ld %1,%0\n\tld %2,%R0" : "=f" (d) : \
520 "m" (((P_)(src))[0]), "m" (((P_)(src))[1])); d; \
523 #else /* ! sparc_TARGET_ARCH */
525 static inline void ASSIGN_DBL (W_ [], StgDouble);
526 static inline StgDouble PK_DBL (W_ []);
538 static inline void ASSIGN_DBL(W_ p_dest[], StgDouble src)
542 p_dest[0] = y.du.dhi;
543 p_dest[1] = y.du.dlo;
546 /* GCC also works with this version, but it generates
547 the same code as the previous one, and is not ANSI
549 #define ASSIGN_DBL( p_dest, src ) \
550 *p_dest = ((double_thing) src).du.dhi; \
551 *(p_dest+1) = ((double_thing) src).du.dlo \
554 static inline StgDouble PK_DBL(W_ p_src[])
562 #endif /* ! sparc_TARGET_ARCH */
564 #endif /* ALIGNMENT_DOUBLE > ALIGNMENT_UNSIGNED_INT */
566 #ifdef SUPPORT_LONG_LONGS
571 } unpacked_double_word;
575 unpacked_double_word iu;
580 unpacked_double_word wu;
583 static inline void ASSIGN_Word64(W_ p_dest[], StgWord64 src)
587 p_dest[0] = y.wu.dhi;
588 p_dest[1] = y.wu.dlo;
591 static inline StgWord64 PK_Word64(W_ p_src[])
599 static inline void ASSIGN_Int64(W_ p_dest[], StgInt64 src)
603 p_dest[0] = y.iu.dhi;
604 p_dest[1] = y.iu.dlo;
607 static inline StgInt64 PK_Int64(W_ p_src[])
616 /* -----------------------------------------------------------------------------
618 -------------------------------------------------------------------------- */
620 extern DLL_IMPORT_RTS const StgPolyInfoTable stg_catch_frame_info;
622 /* -----------------------------------------------------------------------------
625 A seq frame is very like an update frame, except that it doesn't do
627 -------------------------------------------------------------------------- */
629 extern DLL_IMPORT_RTS const StgPolyInfoTable stg_seq_frame_info;
631 #define PUSH_SEQ_FRAME(sp) \
633 StgSeqFrame *__frame; \
634 TICK_SEQF_PUSHED(); \
635 __frame = (StgSeqFrame *)(sp); \
636 SET_HDR_(__frame,&stg_seq_frame_info,CCCS); \
637 __frame->link = Su; \
638 Su = (StgUpdateFrame *)__frame; \
641 /* -----------------------------------------------------------------------------
643 -------------------------------------------------------------------------- */
645 #if defined(USE_SPLIT_MARKERS)
646 #if defined(cygwin32_TARGET_OS) || defined(mingw32_TARGET_OS)
647 #define __STG_SPLIT_MARKER __asm__("\n___stg_split_marker:");
649 #define __STG_SPLIT_MARKER __asm__("\n__stg_split_marker:");
652 #define __STG_SPLIT_MARKER /* nothing */
655 /* -----------------------------------------------------------------------------
656 Closure and Info Macros with casting.
658 We don't want to mess around with casts in the generated C code, so
659 we use these casting versions of the closure/info tables macros.
660 -------------------------------------------------------------------------- */
662 #define SET_HDR_(c,info,ccs) \
663 SET_HDR((StgClosure *)(c),(StgInfoTable *)(info),ccs)
665 /* -----------------------------------------------------------------------------
666 Saving context for exit from the STG world, and loading up context
667 on entry to STG code.
669 We save all the STG registers (that is, the ones that are mapped to
670 machine registers) in their places in the TSO.
672 The stack registers go into the current stack object, and the
673 current nursery is updated from the heap pointer.
675 These functions assume that BaseReg is loaded appropriately (if
677 -------------------------------------------------------------------------- */
681 static __inline__ void
682 SaveThreadState(void)
686 /* Don't need to save REG_Base, it won't have changed. */
693 #ifdef REG_CurrentTSO
694 SAVE_CurrentTSO = tso;
696 #ifdef REG_CurrentNursery
697 SAVE_CurrentNursery = CurrentNursery;
699 #if defined(PROFILING)
700 CurrentTSO->prof.CCCS = CCCS;
704 static __inline__ void
705 LoadThreadState (void)
709 #ifdef REG_CurrentTSO
710 CurrentTSO = SAVE_CurrentTSO;
716 SpLim = (P_)&(tso->stack) + RESERVED_STACK_WORDS;
717 OpenNursery(Hp,HpLim);
719 #ifdef REG_CurrentNursery
720 CurrentNursery = SAVE_CurrentNursery;
722 # if defined(PROFILING)
723 CCCS = CurrentTSO->prof.CCCS;
729 /* -----------------------------------------------------------------------------
730 Module initialisation
731 -------------------------------------------------------------------------- */
733 #define PUSH_INIT_STACK(reg_function) \
734 *(Sp++) = (W_)reg_function
736 #define POP_INIT_STACK() \
739 #define START_MOD_INIT(reg_mod_name) \
740 static int _module_registered = 0; \
741 FN_(reg_mod_name) { \
743 if (! _module_registered) { \
744 _module_registered = 1; \
746 /* extern decls go here, followed by init code */
748 #define REGISTER_FOREIGN_EXPORT(reg_fe_binder) \
749 STGCALL1(getStablePtr,reg_fe_binder)
751 #define REGISTER_IMPORT(reg_mod_name) \
752 PUSH_INIT_STACK(reg_mod_name)
754 #define END_MOD_INIT() \
756 JMP_(POP_INIT_STACK()); \
759 /* -----------------------------------------------------------------------------
760 Support for _ccall_GC_ and _casm_GC.
761 -------------------------------------------------------------------------- */
764 * Suspending/resuming threads for doing external C-calls (_ccall_GC).
765 * These functions are defined in rts/Schedule.c.
767 StgInt suspendThread ( StgRegTable *cap );
768 StgRegTable * resumeThread ( StgInt );
770 #define SUSPEND_THREAD(token) \
772 token = suspendThread(BaseReg);
775 #define RESUME_THREAD(token) \
776 BaseReg = resumeThread(token); \
779 #define RESUME_THREAD(token) \
780 (void)resumeThread(token); \
784 #endif /* STGMACROS_H */