363531055e93beb709201f590295dbe559d38f71
[ghc-hetmet.git] / ghc / rts / HeapStackCheck.cmm
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 1998-2004
4  *
5  * Canned Heap-Check and Stack-Check sequences.
6  *
7  * This file is written in a subset of C--, extended with various
8  * features specific to GHC.  It is compiled by GHC directly.  For the
9  * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y.
10  *
11  * ---------------------------------------------------------------------------*/
12
13 #include "Cmm.h"
14
15 /* Stack/Heap Check Failure
16  * ------------------------
17  *
18  * On discovering that a stack or heap check has failed, we do the following:
19  *
20  *    - If the context_switch flag is set, indicating that there are more
21  *      threads waiting to run, we yield to the scheduler 
22  *      (return ThreadYielding).
23  *
24  *    - If Hp > HpLim, we've had a heap check failure.  This means we've
25  *      come to the end of the current heap block, so we try to chain
26  *      another block on with ExtendNursery().  
27  *
28  *           - If this succeeds, we carry on without returning to the 
29  *             scheduler.  
30  *
31  *           - If it fails, we return to the scheduler claiming HeapOverflow
32  *             so that a garbage collection can be performed.
33  *
34  *    - If Hp <= HpLim, it must have been a stack check that failed.  In
35  *      which case, we return to the scheduler claiming StackOverflow, the
36  *      scheduler will either increase the size of our stack, or raise
37  *      an exception if the stack is already too big.
38  *
39  * The effect of checking for context switch only in the heap/stack check
40  * failure code is that we'll switch threads after the current thread has
41  * reached the end of its heap block.  If a thread isn't allocating
42  * at all, it won't yield.  Hopefully this won't be a problem in practice.
43  */
44  
45 /* Remember that the return address is *removed* when returning to a
46  * ThreadRunGHC thread.
47  */
48
49 #define GC_GENERIC                                              \
50     DEBUG_ONLY(foreign "C" heapCheckFail());                    \
51     if (Hp > HpLim) {                                           \
52         Hp = Hp - HpAlloc/*in bytes*/;                          \
53         if (HpAlloc <= BLOCK_SIZE                               \
54             && bdescr_link(CurrentNursery) != NULL) {           \
55             CLOSE_NURSERY();                                    \
56             CurrentNursery = bdescr_link(CurrentNursery);       \
57             OPEN_NURSERY();                                     \
58             if (CInt[context_switch] != 0 :: CInt) {            \
59                 R1 = ThreadYielding;                            \
60                 goto sched;                                     \
61             } else {                                            \
62                 jump %ENTRY_CODE(Sp(0));                        \
63             }                                                   \
64         } else {                                                \
65             R1 = HeapOverflow;                                  \
66             goto sched;                                         \
67         }                                                       \
68     } else {                                                    \
69         R1 = StackOverflow;                                     \
70     }                                                           \
71   sched:                                                        \
72     StgTSO_what_next(CurrentTSO) = ThreadRunGHC::I16;           \
73     jump stg_returnToSched;
74
75 #define PRE_RETURN(why,what_next)                       \
76   StgTSO_what_next(CurrentTSO) = what_next::I16;        \
77   R1 = why;
78
79 #define HP_GENERIC                              \
80    PRE_RETURN(HeapOverflow, ThreadRunGHC)       \
81   jump stg_returnToSched;
82
83 #define BLOCK_GENERIC                           \
84    PRE_RETURN(ThreadBlocked,  ThreadRunGHC)     \
85   jump stg_returnToSched;
86
87 #define YIELD_GENERIC                           \
88   PRE_RETURN(ThreadYielding, ThreadRunGHC)      \
89   jump stg_returnToSched;
90
91 #define BLOCK_BUT_FIRST(c)                      \
92   PRE_RETURN(ThreadBlocked, ThreadRunGHC)       \
93   R2 = c;                                       \
94   jump stg_returnToSchedButFirst;
95
96 #define YIELD_TO_INTERPRETER                    \
97   PRE_RETURN(ThreadYielding, ThreadInterpret)   \
98   jump stg_returnToSchedNotPaused;
99
100 /* -----------------------------------------------------------------------------
101    Heap checks in thunks/functions.
102
103    In these cases, node always points to the function closure.  This gives
104    us an easy way to return to the function: just leave R1 on the top of
105    the stack, and have the scheduler enter it to return.
106
107    There are canned sequences for 'n' pointer values in registers.
108    -------------------------------------------------------------------------- */
109
110 INFO_TABLE_RET( stg_enter, 1/*framesize*/, 0/*bitmap*/, RET_SMALL)
111 {
112     R1 = Sp(1);
113     Sp_adj(2);
114     ENTER();
115 }
116
117 __stg_gc_enter_1
118 {
119     Sp_adj(-2);
120     Sp(1) = R1;
121     Sp(0) = stg_enter_info;
122     GC_GENERIC
123 }
124
125 #if defined(GRAN)
126 /*
127   ToDo: merge the block and yield macros, calling something like BLOCK(N)
128         at the end;
129 */
130
131 /* 
132    Should we actually ever do a yield in such a case?? -- HWL
133 */
134 gran_yield_0
135 {
136     SAVE_THREAD_STATE();                                        
137     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
138     R1 = ThreadYielding;
139     jump StgReturn;
140 }
141
142 gran_yield_1
143 {
144     Sp_adj(-1);
145     Sp(0) = R1;
146     SAVE_THREAD_STATE();                                        
147     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
148     R1 = ThreadYielding;
149     jump StgReturn;
150 }
151
152 /*- 2 Regs--------------------------------------------------------------------*/
153
154 gran_yield_2
155 {
156     Sp_adj(-2);
157     Sp(1) = R2;
158     Sp(0) = R1;
159     SAVE_THREAD_STATE();                                        
160     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
161     R1 = ThreadYielding;
162     jump StgReturn;
163 }
164
165 /*- 3 Regs -------------------------------------------------------------------*/
166
167 gran_yield_3
168 {
169     Sp_adj(-3);
170     Sp(2) = R3;
171     Sp(1) = R2;
172     Sp(0) = R1;
173     SAVE_THREAD_STATE();                                        
174     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
175     R1 = ThreadYielding;
176     jump StgReturn;
177 }
178
179 /*- 4 Regs -------------------------------------------------------------------*/
180
181 gran_yield_4
182 {
183     Sp_adj(-4);
184     Sp(3) = R4;
185     Sp(2) = R3;
186     Sp(1) = R2;
187     Sp(0) = R1;
188     SAVE_THREAD_STATE();                                        
189     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
190     R1 = ThreadYielding;
191     jump StgReturn;
192 }
193
194 /*- 5 Regs -------------------------------------------------------------------*/
195
196 gran_yield_5
197 {
198     Sp_adj(-5);
199     Sp(4) = R5;
200     Sp(3) = R4;
201     Sp(2) = R3;
202     Sp(1) = R2;
203     Sp(0) = R1;
204     SAVE_THREAD_STATE();                                        
205     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
206     R1 = ThreadYielding;
207     jump StgReturn;
208 }
209
210 /*- 6 Regs -------------------------------------------------------------------*/
211
212 gran_yield_6
213 {
214     Sp_adj(-6);
215     Sp(5) = R6;
216     Sp(4) = R5;
217     Sp(3) = R4;
218     Sp(2) = R3;
219     Sp(1) = R2;
220     Sp(0) = R1;
221     SAVE_THREAD_STATE();                                        
222     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
223     R1 = ThreadYielding;
224     jump StgReturn;
225 }
226
227 /*- 7 Regs -------------------------------------------------------------------*/
228
229 gran_yield_7
230 {
231     Sp_adj(-7);
232     Sp(6) = R7;
233     Sp(5) = R6;
234     Sp(4) = R5;
235     Sp(3) = R4;
236     Sp(2) = R3;
237     Sp(1) = R2;
238     Sp(0) = R1;
239     SAVE_THREAD_STATE();                                        
240     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
241     R1 = ThreadYielding;
242     jump StgReturn;
243 }
244
245 /*- 8 Regs -------------------------------------------------------------------*/
246
247 gran_yield_8
248 {
249     Sp_adj(-8);
250     Sp(7) = R8;
251     Sp(6) = R7;
252     Sp(5) = R6;
253     Sp(4) = R5;
254     Sp(3) = R4;
255     Sp(2) = R3;
256     Sp(1) = R2;
257     Sp(0) = R1;
258     SAVE_THREAD_STATE();                                        
259     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
260     R1 = ThreadYielding;
261     jump StgReturn;
262 }
263
264 // the same routines but with a block rather than a yield
265
266 gran_block_1
267 {
268     Sp_adj(-1);
269     Sp(0) = R1;
270     SAVE_THREAD_STATE();                                        
271     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
272     R1 = ThreadBlocked;
273     jump StgReturn;
274 }
275
276 /*- 2 Regs--------------------------------------------------------------------*/
277
278 gran_block_2
279 {
280     Sp_adj(-2);
281     Sp(1) = R2;
282     Sp(0) = R1;
283     SAVE_THREAD_STATE();                                        
284     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
285     R1 = ThreadBlocked;
286     jump StgReturn;
287 }
288
289 /*- 3 Regs -------------------------------------------------------------------*/
290
291 gran_block_3
292 {
293     Sp_adj(-3);
294     Sp(2) = R3;
295     Sp(1) = R2;
296     Sp(0) = R1;
297     SAVE_THREAD_STATE();                                        
298     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
299     R1 = ThreadBlocked;
300     jump StgReturn;
301 }
302
303 /*- 4 Regs -------------------------------------------------------------------*/
304
305 gran_block_4
306 {
307     Sp_adj(-4);
308     Sp(3) = R4;
309     Sp(2) = R3;
310     Sp(1) = R2;
311     Sp(0) = R1;
312     SAVE_THREAD_STATE();                                        
313     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
314     R1 = ThreadBlocked;
315     jump StgReturn;
316 }
317
318 /*- 5 Regs -------------------------------------------------------------------*/
319
320 gran_block_5
321 {
322     Sp_adj(-5);
323     Sp(4) = R5;
324     Sp(3) = R4;
325     Sp(2) = R3;
326     Sp(1) = R2;
327     Sp(0) = R1;
328     SAVE_THREAD_STATE();                                        
329     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
330     R1 = ThreadBlocked;
331     jump StgReturn;
332 }
333
334 /*- 6 Regs -------------------------------------------------------------------*/
335
336 gran_block_6
337 {
338     Sp_adj(-6);
339     Sp(5) = R6;
340     Sp(4) = R5;
341     Sp(3) = R4;
342     Sp(2) = R3;
343     Sp(1) = R2;
344     Sp(0) = R1;
345     SAVE_THREAD_STATE();                                        
346     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
347     R1 = ThreadBlocked;
348     jump StgReturn;
349 }
350
351 /*- 7 Regs -------------------------------------------------------------------*/
352
353 gran_block_7
354 {
355     Sp_adj(-7);
356     Sp(6) = R7;
357     Sp(5) = R6;
358     Sp(4) = R5;
359     Sp(3) = R4;
360     Sp(2) = R3;
361     Sp(1) = R2;
362     Sp(0) = R1;
363     SAVE_THREAD_STATE();                                        
364     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
365     R1 = ThreadBlocked;
366     jump StgReturn;
367 }
368
369 /*- 8 Regs -------------------------------------------------------------------*/
370
371 gran_block_8
372 {
373     Sp_adj(-8);
374     Sp(7) = R8;
375     Sp(6) = R7;
376     Sp(5) = R6;
377     Sp(4) = R5;
378     Sp(3) = R4;
379     Sp(2) = R3;
380     Sp(1) = R2;
381     Sp(0) = R1;
382     SAVE_THREAD_STATE();                                        
383     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
384     R1 = ThreadBlocked;
385     jump StgReturn;
386 }
387
388 #endif
389
390 #if 0 && defined(PAR)
391
392 /*
393   Similar to stg_block_1 (called via StgMacro BLOCK_NP) but separates the
394   saving of the thread state from the actual jump via an StgReturn.
395   We need this separation because we call RTS routines in blocking entry codes
396   before jumping back into the RTS (see parallel/FetchMe.hc).
397 */
398
399 par_block_1_no_jump
400 {
401     Sp_adj(-1);
402     Sp(0) = R1;
403     SAVE_THREAD_STATE();                                        
404 }
405
406 par_jump
407 {
408     TSO_what_next(CurrentTSO) = ThreadRunGHC;           
409     R1 = ThreadBlocked;
410     jump StgReturn;
411 }
412
413 #endif
414
415 /* -----------------------------------------------------------------------------
416    Heap checks in Primitive case alternatives
417
418    A primitive case alternative is entered with a value either in 
419    R1, FloatReg1 or D1 depending on the return convention.  All the
420    cases are covered below.
421    -------------------------------------------------------------------------- */
422
423 /*-- No Registers live ------------------------------------------------------ */
424
425 stg_gc_noregs
426 {
427     GC_GENERIC
428 }
429
430 /*-- void return ------------------------------------------------------------ */
431
432 INFO_TABLE_RET( stg_gc_void, 0/*framesize*/, 0/*bitmap*/, RET_SMALL)
433 {
434     Sp_adj(1);
435     jump %ENTRY_CODE(Sp(0));
436 }
437
438 /*-- R1 is boxed/unpointed -------------------------------------------------- */
439
440 INFO_TABLE_RET( stg_gc_unpt_r1, 1/*framesize*/, 0/*bitmap*/, RET_SMALL)
441 {
442     R1 = Sp(1);
443     Sp_adj(2);
444     jump %ENTRY_CODE(Sp(0));
445 }
446
447 stg_gc_unpt_r1
448 {
449     Sp_adj(-2);
450     Sp(1) = R1;
451     Sp(0) = stg_gc_unpt_r1_info;
452     GC_GENERIC
453 }
454
455 /*-- R1 is unboxed -------------------------------------------------- */
456
457 /* the 1 is a bitmap - i.e. 1 non-pointer word on the stack. */
458 INFO_TABLE_RET( stg_gc_unbx_r1, 1/*framesize*/, 1/*bitmap*/, RET_SMALL )
459 {
460     R1 = Sp(1);
461     Sp_adj(2);
462     jump %ENTRY_CODE(Sp(0));
463 }
464
465 stg_gc_unbx_r1
466 {
467     Sp_adj(-2);
468     Sp(1) = R1;
469     Sp(0) = stg_gc_unbx_r1_info;
470     GC_GENERIC
471 }
472
473 /*-- F1 contains a float ------------------------------------------------- */
474
475 INFO_TABLE_RET( stg_gc_f1, 1/*framesize*/, 1/*bitmap*/, RET_SMALL )
476 {
477     F1 = F_[Sp+WDS(1)];
478     Sp_adj(2);
479     jump %ENTRY_CODE(Sp(0));
480 }
481
482 stg_gc_f1
483 {
484     Sp_adj(-2);
485     F_[Sp + WDS(1)] = F1;
486     Sp(0) = stg_gc_f1_info;
487     GC_GENERIC
488 }
489
490 /*-- D1 contains a double ------------------------------------------------- */
491
492 /* we support doubles of either 1 or 2 words in size */
493
494 #if SIZEOF_DOUBLE == SIZEOF_VOID_P
495 #  define DBL_BITMAP 1
496 #  define DBL_WORDS  1
497 #else
498 #  define DBL_BITMAP 3
499 #  define DBL_WORDS  2
500 #endif 
501
502 INFO_TABLE_RET( stg_gc_d1, DBL_WORDS/*framesize*/, DBL_BITMAP/*bitmap*/, RET_SMALL )
503 {
504     D1 = D_[Sp + WDS(1)];
505     Sp = Sp + WDS(1) + SIZEOF_StgDouble;
506     jump %ENTRY_CODE(Sp(0));
507 }
508
509 stg_gc_d1
510 {
511     Sp = Sp - WDS(1) - SIZEOF_StgDouble;
512     D_[Sp + WDS(1)] = D1;
513     Sp(0) = stg_gc_d1_info;
514     GC_GENERIC
515 }
516
517
518 /*-- L1 contains an int64 ------------------------------------------------- */
519
520 /* we support int64s of either 1 or 2 words in size */
521
522 #if SIZEOF_VOID_P == 8
523 #  define LLI_BITMAP 1
524 #  define LLI_WORDS  1
525 #else
526 #  define LLI_BITMAP 3
527 #  define LLI_WORDS  2
528 #endif 
529
530 INFO_TABLE_RET( stg_gc_l1, LLI_WORDS/*framesize*/, LLI_BITMAP/*bitmap*/, RET_SMALL )
531 {
532     L1 = L_[Sp + WDS(1)];
533     Sp_adj(1) + SIZEOF_StgWord64;
534     jump %ENTRY_CODE(Sp(0));
535 }
536
537 stg_gc_l1
538 {
539     Sp_adj(-1) - SIZEOF_StgWord64;
540     L_[Sp + WDS(1)] = L1;
541     Sp(0) = stg_gc_l1_info;
542     GC_GENERIC
543 }
544
545 /*-- Unboxed tuple return, one pointer (unregisterised build only) ---------- */
546
547 INFO_TABLE_RET( stg_ut_1_0_unreg, 1/*size*/, 0/*BITMAP*/, RET_SMALL )
548 {
549     Sp_adj(1);
550     // one ptr is on the stack (Sp(0))
551     jump %ENTRY_CODE(Sp(1));
552 }
553
554 /* -----------------------------------------------------------------------------
555    Generic function entry heap check code.
556
557    At a function entry point, the arguments are as per the calling convention,
558    i.e. some in regs and some on the stack.  There may or may not be 
559    a pointer to the function closure in R1 - if there isn't, then the heap
560    check failure code in the function will arrange to load it.
561
562    The function's argument types are described in its info table, so we
563    can just jump to this bit of generic code to save away all the
564    registers and return to the scheduler.
565
566    This code arranges the stack like this:
567          
568          |        ....         |
569          |        args         |
570          +---------------------+
571          |      f_closure      |
572          +---------------------+
573          |        size         |
574          +---------------------+
575          |   stg_gc_fun_info   |
576          +---------------------+
577
578    The size is the number of words of arguments on the stack, and is cached
579    in the frame in order to simplify stack walking: otherwise the size of
580    this stack frame would have to be calculated by looking at f's info table.
581
582    -------------------------------------------------------------------------- */
583
584 __stg_gc_fun
585 {
586     W_ size;
587     W_ info;
588     W_ type;
589
590     info = %GET_FUN_INFO(R1);
591
592     // cache the size
593     type = TO_W_(StgFunInfoExtra_fun_type(info));
594     if (type == ARG_GEN) {
595         size = BITMAP_SIZE(StgFunInfoExtra_bitmap(info));
596     } else { 
597         if (type == ARG_GEN_BIG) {
598 #ifdef TABLES_NEXT_TO_CODE
599             // bitmap field holds an offset
600             size = StgLargeBitmap_size( StgFunInfoExtra_bitmap(info)
601                                         + %GET_ENTRY(R1) /* ### */ );
602 #else
603             size = StgLargeBitmap_size( StgFunInfoExtra_bitmap(info) );
604 #endif
605         } else {
606             size = BITMAP_SIZE(W_[stg_arg_bitmaps + WDS(type)]);
607         }
608     }
609     
610 #ifdef NO_ARG_REGS
611     // we don't have to save any registers away
612     Sp_adj(-3);
613     Sp(2) = R1;
614     Sp(1) = size;
615     Sp(0) = stg_gc_fun_info;
616     GC_GENERIC
617 #else
618     W_ type;
619     type = TO_W_(StgFunInfoExtra_fun_type(info));
620     // cache the size
621     if (type == ARG_GEN || type == ARG_GEN_BIG) {
622         // regs already saved by the heap check code
623         Sp_adj(-3);
624         Sp(2) = R1;
625         Sp(1) = size;
626         Sp(0) = stg_gc_fun_info;
627         // DEBUG_ONLY(foreign "C" debugBelch("stg_fun_gc_gen(ARG_GEN)"););
628         GC_GENERIC
629     } else { 
630         jump W_[stg_stack_save_entries + WDS(type)];
631             // jumps to stg_gc_noregs after saving stuff
632     }
633 #endif /* !NO_ARG_REGS */
634 }
635
636 /* -----------------------------------------------------------------------------
637    Generic Apply (return point)
638
639    The dual to stg_fun_gc_gen (above): this fragment returns to the
640    function, passing arguments in the stack and in registers
641    appropriately.  The stack layout is given above.
642    -------------------------------------------------------------------------- */
643
644 INFO_TABLE_RET( stg_gc_fun, 0/*framesize*/, 0/*bitmap*/, RET_FUN )
645 {
646     R1 = Sp(2);
647     Sp_adj(3);
648 #ifdef NO_ARG_REGS
649     // Minor optimisation: there are no argument registers to load up,
650     // so we can just jump straight to the function's entry point.
651     jump %GET_ENTRY(R1);
652 #else
653     W_ info;
654     W_ type;
655     
656     info = %GET_FUN_INFO(R1);
657     type = TO_W_(StgFunInfoExtra_fun_type(info));
658     if (type == ARG_GEN || type == ARG_GEN_BIG) {
659         jump StgFunInfoExtra_slow_apply(info);
660     } else { 
661         if (type == ARG_BCO) {
662             // cover this case just to be on the safe side
663             Sp_adj(-2);
664             Sp(1) = R1;
665             Sp(0) = stg_apply_interp_info;
666             jump stg_yield_to_interpreter;
667         } else {
668             jump W_[stg_ap_stack_entries + WDS(type)];
669         }
670     }
671 #endif
672 }
673
674 /* -----------------------------------------------------------------------------
675    Generic Heap Check Code.
676
677    Called with Liveness mask in R9,  Return address in R10.
678    Stack must be consistent (containing all necessary info pointers
679    to relevant SRTs).
680
681    See StgMacros.h for a description of the RET_DYN stack frame.
682
683    We also define an stg_gen_yield here, because it's very similar.
684    -------------------------------------------------------------------------- */
685
686 // For simplicity, we assume that SIZEOF_DOUBLE == 2*SIZEOF_VOID_P
687 // on a 64-bit machine, we'll end up wasting a couple of words, but
688 // it's not a big deal.
689
690 #define RESTORE_EVERYTHING                      \
691     L1   = L_[Sp + WDS(19)];                    \
692     D2   = D_[Sp + WDS(17)];                    \
693     D1   = D_[Sp + WDS(15)];                    \
694     F4   = F_[Sp + WDS(14)];                    \
695     F3   = F_[Sp + WDS(13)];                    \
696     F2   = F_[Sp + WDS(12)];                    \
697     F1   = F_[Sp + WDS(11)];                    \
698     R8 = Sp(10);                                \
699     R7 = Sp(9);                                 \
700     R6 = Sp(8);                                 \
701     R5 = Sp(7);                                 \
702     R4 = Sp(6);                                 \
703     R3 = Sp(5);                                 \
704     R2 = Sp(4);                                 \
705     R1 = Sp(3);                                 \
706     Sp_adj(21);
707
708 #define RET_OFFSET (-19)
709
710 #define SAVE_EVERYTHING                         \
711     Sp_adj(-21);                                \
712     L_[Sp + WDS(19)] = L1;                      \
713     D_[Sp + WDS(17)] = D2;                      \
714     D_[Sp + WDS(15)] = D1;                      \
715     F_[Sp + WDS(14)] = F4;                      \
716     F_[Sp + WDS(13)] = F3;                      \
717     F_[Sp + WDS(12)] = F2;                      \
718     F_[Sp + WDS(11)] = F1;                      \
719     Sp(10) = R8;                                \
720     Sp(9) = R7;                                 \
721     Sp(8) = R6;                                 \
722     Sp(7) = R5;                                 \
723     Sp(6) = R4;                                 \
724     Sp(5) = R3;                                 \
725     Sp(4) = R2;                                 \
726     Sp(3) = R1;                                 \
727     Sp(2) = R10;    /* return address */        \
728     Sp(1) = R9;     /* liveness mask  */        \
729     Sp(0) = stg_gc_gen_info;
730
731 INFO_TABLE_RET( stg_gc_gen, 0/*framesize*/, 0/*bitmap*/, RET_DYN )
732 /* bitmap in the above info table is unused, the real one is on the stack. */
733 {
734     RESTORE_EVERYTHING;
735     jump Sp(RET_OFFSET); /* No %ENTRY_CODE( - this is an actual code ptr */
736 }
737
738 stg_gc_gen
739 {
740     SAVE_EVERYTHING;
741     GC_GENERIC
742 }         
743
744 // A heap check at an unboxed tuple return point.  The return address
745 // is on the stack, and we can find it by using the offsets given
746 // to us in the liveness mask.
747 stg_gc_ut
748 {
749     R10 = %ENTRY_CODE(Sp(RET_DYN_NONPTRS(R9) + RET_DYN_PTRS(R9)));
750     SAVE_EVERYTHING;
751     GC_GENERIC
752 }
753
754 /*
755  * stg_gen_hp is used by MAYBE_GC, where we can't use GC_GENERIC
756  * because we've just failed doYouWantToGC(), not a standard heap
757  * check.  GC_GENERIC would end up returning StackOverflow.
758  */
759 stg_gc_gen_hp
760 {
761     SAVE_EVERYTHING;
762     HP_GENERIC
763 }         
764
765 /* -----------------------------------------------------------------------------
766    Yields
767    -------------------------------------------------------------------------- */
768
769 stg_gen_yield
770 {
771     SAVE_EVERYTHING;
772     YIELD_GENERIC
773 }
774
775 stg_yield_noregs
776 {
777     YIELD_GENERIC;
778 }
779
780 /* -----------------------------------------------------------------------------
781    Yielding to the interpreter... top of stack says what to do next.
782    -------------------------------------------------------------------------- */
783
784 stg_yield_to_interpreter
785 {
786     YIELD_TO_INTERPRETER;
787 }
788
789 /* -----------------------------------------------------------------------------
790    Blocks
791    -------------------------------------------------------------------------- */
792
793 stg_gen_block
794 {
795     SAVE_EVERYTHING;
796     BLOCK_GENERIC;
797 }
798
799 stg_block_noregs
800 {
801     BLOCK_GENERIC;
802 }
803
804 stg_block_1
805 {
806     Sp_adj(-2);
807     Sp(1) = R1;
808     Sp(0) = stg_enter_info;
809     BLOCK_GENERIC;
810 }
811
812 /* -----------------------------------------------------------------------------
813  * takeMVar/putMVar-specific blocks
814  *
815  * Stack layout for a thread blocked in takeMVar:
816  *      
817  *       ret. addr
818  *       ptr to MVar   (R1)
819  *       stg_block_takemvar_info
820  *
821  * Stack layout for a thread blocked in putMVar:
822  *      
823  *       ret. addr
824  *       ptr to Value  (R2)
825  *       ptr to MVar   (R1)
826  *       stg_block_putmvar_info
827  *
828  * See PrimOps.hc for a description of the workings of take/putMVar.
829  * 
830  * -------------------------------------------------------------------------- */
831
832 INFO_TABLE_RET( stg_block_takemvar, 1/*framesize*/, 0/*bitmap*/, RET_SMALL )
833 {
834     R1 = Sp(1);
835     Sp_adj(2);
836     jump takeMVarzh_fast;
837 }
838
839 // code fragment executed just before we return to the scheduler
840 stg_block_takemvar_finally
841 {
842 #ifdef SMP
843     foreign "C" unlockClosure(R3 "ptr", stg_EMPTY_MVAR_info);
844 #endif
845     jump StgReturn;
846 }
847
848 stg_block_takemvar
849 {
850     Sp_adj(-2);
851     Sp(1) = R1;
852     Sp(0) = stg_block_takemvar_info;
853     R3 = R1;
854     BLOCK_BUT_FIRST(stg_block_takemvar_finally);
855 }
856
857 INFO_TABLE_RET( stg_block_putmvar, 2/*framesize*/, 0/*bitmap*/, RET_SMALL )
858 {
859     R2 = Sp(2);
860     R1 = Sp(1);
861     Sp_adj(3);
862     jump putMVarzh_fast;
863 }
864
865 // code fragment executed just before we return to the scheduler
866 stg_block_putmvar_finally
867 {
868 #ifdef SMP
869     foreign "C" unlockClosure(R3 "ptr", stg_FULL_MVAR_info);
870 #endif
871     jump StgReturn;
872 }
873
874 stg_block_putmvar
875 {
876     Sp_adj(-3);
877     Sp(2) = R2;
878     Sp(1) = R1;
879     Sp(0) = stg_block_putmvar_info;
880     R3 = R1;
881     BLOCK_BUT_FIRST(stg_block_putmvar_finally);
882 }
883
884 #ifdef mingw32_HOST_OS
885 INFO_TABLE_RET( stg_block_async, 0/*framesize*/, 0/*bitmap*/, RET_SMALL )
886 {
887     W_ ares;
888     W_ len, errC;
889
890     ares = StgTSO_block_info(CurrentTSO);
891     len = StgAsyncIOResult_len(ares);
892     errC = StgAsyncIOResult_errCode(ares);
893     StgTSO_block_info(CurrentTSO) = NULL;
894     foreign "C" free(ares "ptr");
895     R1 = len;
896     Sp(0) = errC;
897     jump %ENTRY_CODE(Sp(1));
898 }
899
900 stg_block_async
901 {
902     Sp_adj(-1);
903     Sp(0) = stg_block_async_info;
904     BLOCK_GENERIC;
905 }
906
907 /* Used by threadDelay implementation; it would be desirable to get rid of
908  * this free()'ing void return continuation.
909  */
910 INFO_TABLE_RET( stg_block_async_void, 0/*framesize*/, 0/*bitmap*/, RET_SMALL )
911 {
912     W_ ares;
913
914     ares = StgTSO_block_info(CurrentTSO);
915     StgTSO_block_info(CurrentTSO) = NULL;
916     foreign "C" free(ares "ptr");
917     Sp_adj(1);
918     jump %ENTRY_CODE(Sp(0));
919 }
920
921 stg_block_async_void
922 {
923     Sp_adj(-1);
924     Sp(0) = stg_block_async_void_info;
925     BLOCK_GENERIC;
926 }
927
928 #endif