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