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