[project @ 1999-08-25 16:11:43 by simonmar]
[ghc-hetmet.git] / ghc / rts / HeapStackCheck.hc
1 /* -----------------------------------------------------------------------------
2  * $Id: HeapStackCheck.hc,v 1.9 1999/08/25 16:11:48 simonmar Exp $
3  *
4  * (c) The GHC Team, 1998-1999
5  *
6  * Canned Heap-Check and Stack-Check sequences.
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #include "Rts.h"
11 #include "Storage.h"    /* for CurrentTSO */
12 #include "StgRun.h"     /* for StgReturn and register saving */
13 #include "Schedule.h"   /* for context_switch */
14 #include "HeapStackCheck.h"
15
16 /* Stack/Heap Check Failure
17  * ------------------------
18  *
19  * On discovering that a stack or heap check has failed, we do the following:
20  *
21  *    - If the context_switch flag is set, indicating that there are more
22  *      threads waiting to run, we yield to the scheduler 
23  *      (return ThreadYeilding).
24  *
25  *    - If Hp > HpLim, we've had a heap check failure.  This means we've
26  *      come to the end of the current heap block, so we try to chain
27  *      another block on with ExtendNursery().  
28  *
29  *           - If this succeeds, we carry on without returning to the 
30  *             scheduler.  
31  *
32  *           - If it fails, we return to the scheduler claiming HeapOverflow
33  *             so that a garbage collection can be performed.
34  *
35  *    - If Hp <= HpLim, it must have been a stack check that failed.  In
36  *      which case, we return to the scheduler claiming StackOverflow, the
37  *      scheduler will either increase the size of our stack, or flag
38  *      an error if the stack is already too big.
39  *
40  * The effect of checking for context switch only in the heap/stack check
41  * failure code is that we'll switch threads after the current thread has
42  * reached the end of its heap block.  If a thread isn't allocating
43  * at all, it won't yield.  Hopefully this won't be a problem in practice.
44  */
45  
46 /* Remember that the return address is *removed* when returning to a
47  * ThreadRunGHC thread.
48  */
49
50
51 #define GC_GENERIC                                      \
52   if (Hp > HpLim) {                                     \
53     if (ExtendNursery(Hp,HpLim)) {                      \
54         if (context_switch) {                           \
55             R1.i = ThreadYielding;                      \
56         } else {                                        \
57            Sp++;                                        \
58            JMP_(ENTRY_CODE(Sp[-1]));                    \
59         }                                               \
60     } else {                                            \
61       R1.i = HeapOverflow;                              \
62     }                                                   \
63   } else {                                              \
64     R1.i = StackOverflow;                               \
65   }                                                     \
66   SaveThreadState();                                    \
67   CurrentTSO->whatNext = ThreadRunGHC;                  \
68   JMP_(StgReturn);
69
70 #define GC_ENTER                                        \
71   if (Hp > HpLim) {                                     \
72     if (ExtendNursery(Hp,HpLim)) {                      \
73         if (context_switch) {                           \
74             R1.i = ThreadYielding;                      \
75         } else {                                        \
76            R1.w = *Sp;                                  \
77            Sp++;                                        \
78            JMP_(ENTRY_CODE(*R1.p));                     \
79         }                                               \
80     } else {                                            \
81       R1.i = HeapOverflow;                              \
82     }                                                   \
83   } else {                                              \
84     R1.i = StackOverflow;                               \
85   }                                                     \
86   SaveThreadState();                                    \
87   CurrentTSO->whatNext = ThreadEnterGHC;                \
88   JMP_(StgReturn);
89
90 #define HP_GENERIC                      \
91   SaveThreadState();                    \
92   CurrentTSO->whatNext = ThreadRunGHC;  \
93   R1.i = HeapOverflow;                  \
94   JMP_(StgReturn);
95
96 #define STK_GENERIC                     \
97   SaveThreadState();                    \
98   CurrentTSO->whatNext = ThreadRunGHC;  \
99   R1.i = StackOverflow;                 \
100   JMP_(StgReturn);
101
102 #define YIELD_GENERIC                   \
103   SaveThreadState();                    \
104   CurrentTSO->whatNext = ThreadRunGHC;  \
105   R1.i = ThreadYielding;                \
106   JMP_(StgReturn);
107
108 #define YIELD_TO_HUGS                     \
109   SaveThreadState();                      \
110   CurrentTSO->whatNext = ThreadEnterHugs; \
111   R1.i = ThreadYielding;                  \
112   JMP_(StgReturn);
113
114 #define BLOCK_GENERIC                   \
115   SaveThreadState();                    \
116   CurrentTSO->whatNext = ThreadRunGHC;  \
117   R1.i = ThreadBlocked;                 \
118   JMP_(StgReturn);
119
120 #define BLOCK_ENTER                     \
121   SaveThreadState();                    \
122   CurrentTSO->whatNext = ThreadEnterGHC;\
123   R1.i = ThreadBlocked;                 \
124   JMP_(StgReturn);
125
126 /* -----------------------------------------------------------------------------
127    Heap Checks
128    -------------------------------------------------------------------------- */
129
130 /*
131  * This one is used when we want to *enter* the top thing on the stack
132  * when we return, instead of the just returning to an address.  See
133  * UpdatePAP for an example.
134  */
135
136 EXTFUN(stg_gc_entertop)
137 {
138   FB_
139   GC_ENTER
140   FE_
141 }
142
143 /* -----------------------------------------------------------------------------
144    Heap checks in non-top-level thunks/functions.
145
146    In these cases, node always points to the function closure.  This gives
147    us an easy way to return to the function: just leave R1 on the top of
148    the stack, and have the scheduler enter it to return.
149
150    There are canned sequences for 'n' pointer values in registers.
151    -------------------------------------------------------------------------- */
152
153 EXTFUN(stg_gc_enter_1)
154 {
155   FB_
156   Sp -= 1;
157   Sp[0] = R1.w;
158   GC_ENTER
159   FE_
160 }
161
162 /*- 2 Regs--------------------------------------------------------------------*/
163
164 EXTFUN(stg_gc_enter_2)
165 {
166   FB_
167   Sp -= 2;
168   Sp[1] = R2.w;
169   Sp[0] = R1.w;
170   GC_ENTER;
171   FE_
172 }
173
174 /*- 3 Regs -------------------------------------------------------------------*/
175
176 EXTFUN(stg_gc_enter_3)
177 {
178   FB_
179   Sp -= 3;
180   Sp[2] = R3.w;
181   Sp[1] = R2.w;
182   Sp[0] = R1.w;
183   GC_ENTER;
184   FE_
185 }
186
187 /*- 4 Regs -------------------------------------------------------------------*/
188
189 EXTFUN(stg_gc_enter_4)
190 {
191   FB_
192   Sp -= 4;
193   Sp[3] = R4.w;
194   Sp[2] = R3.w;
195   Sp[1] = R2.w;
196   Sp[0] = R1.w;
197   GC_ENTER;
198   FE_
199 }
200
201 /*- 5 Regs -------------------------------------------------------------------*/
202
203 EXTFUN(stg_gc_enter_5)
204 {
205   FB_
206   Sp -= 5;
207   Sp[4] = R5.w;
208   Sp[3] = R4.w;
209   Sp[2] = R3.w;
210   Sp[1] = R2.w;
211   Sp[0] = R1.w;
212   GC_ENTER;
213   FE_
214 }
215
216 /*- 6 Regs -------------------------------------------------------------------*/
217
218 EXTFUN(stg_gc_enter_6)
219 {
220   FB_
221   Sp -= 6;
222   Sp[5] = R6.w;
223   Sp[4] = R5.w;
224   Sp[3] = R4.w;
225   Sp[2] = R3.w;
226   Sp[1] = R2.w;
227   Sp[0] = R1.w;
228   GC_ENTER;
229   FE_
230 }
231
232 /*- 7 Regs -------------------------------------------------------------------*/
233
234 EXTFUN(stg_gc_enter_7)
235 {
236   FB_
237   Sp -= 7;
238   Sp[6] = R7.w;
239   Sp[5] = R6.w;
240   Sp[4] = R5.w;
241   Sp[3] = R4.w;
242   Sp[2] = R3.w;
243   Sp[1] = R2.w;
244   Sp[0] = R1.w;
245   GC_ENTER;
246   FE_
247 }
248
249 /*- 8 Regs -------------------------------------------------------------------*/
250
251 EXTFUN(stg_gc_enter_8)
252 {
253   FB_
254   Sp -= 8;
255   Sp[7] = R8.w;
256   Sp[6] = R7.w;
257   Sp[5] = R6.w;
258   Sp[4] = R5.w;
259   Sp[3] = R4.w;
260   Sp[2] = R3.w;
261   Sp[1] = R2.w;
262   Sp[0] = R1.w;
263   GC_ENTER;
264   FE_
265 }
266
267 /* -----------------------------------------------------------------------------
268    For a case expression on a polymorphic or function-typed object, if
269    the default branch (there can only be one branch) of the case fails
270    a heap-check, instead of using stg_gc_enter_1 as normal, we must
271    push a new SEQ frame on the stack, followed by the object returned.  
272
273    Otherwise, if the object is a function, it won't return to the
274    correct activation record on returning from garbage collection.  It will
275    assume it has some arguments and apply itself.
276    -------------------------------------------------------------------------- */
277
278 EXTFUN(stg_gc_seq_1)
279 {
280   FB_
281   Sp -= 1 + sizeofW(StgSeqFrame);
282   PUSH_SEQ_FRAME(Sp+1);
283   *Sp = R1.w;
284   GC_ENTER;
285   FE_
286 }
287
288 /* -----------------------------------------------------------------------------
289    Heap checks in Primitive case alternatives
290
291    A primitive case alternative is entered with a value either in 
292    R1, FloatReg1 or D1 depending on the return convention.  All the
293    cases are covered below.
294    -------------------------------------------------------------------------- */
295
296 /*-- No regsiters live (probably a void return) ----------------------------- */
297
298 /* If we change the policy for thread startup to *not* remove the
299  * return address from the stack, we can get rid of this little
300  * function/info table...  
301  */
302 INFO_TABLE_SRT_BITMAP(stg_gc_noregs_ret_info, stg_gc_noregs_ret, 0/*BITMAP*/, 
303                       0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, 
304                       RET_SMALL,, EF_, 0, 0);
305
306 EXTFUN(stg_gc_noregs_ret)
307 {
308   FB_
309   JMP_(ENTRY_CODE(Sp[0]));
310   FE_
311 }
312
313 EXTFUN(stg_gc_noregs)
314 {
315   FB_
316   Sp -= 1;
317   Sp[0] = (W_)&stg_gc_noregs_ret_info;
318   GC_GENERIC
319   FE_
320 }
321
322 /*-- R1 is boxed/unpointed -------------------------------------------------- */
323
324 INFO_TABLE_SRT_BITMAP(stg_gc_unpt_r1_info, stg_gc_unpt_r1_entry, 0/*BITMAP*/, 
325                       0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, 
326                       RET_SMALL,, EF_, 0, 0);
327
328 EXTFUN(stg_gc_unpt_r1_entry)
329 {
330   FB_
331   R1.w = Sp[0];
332   Sp += 1;
333   JMP_(ENTRY_CODE(Sp[0]));
334   FE_
335 }
336
337 EXTFUN(stg_gc_unpt_r1)
338 {
339   FB_
340   Sp -= 2;
341   Sp[1] = R1.w;
342   Sp[0] = (W_)&stg_gc_unpt_r1_info;
343   GC_GENERIC
344   FE_
345 }
346
347 /*-- R1 is unboxed -------------------------------------------------- */
348
349 INFO_TABLE_SRT_BITMAP(stg_gc_unbx_r1_info, stg_gc_unbx_r1_entry, 1/*BITMAP*/,
350                       0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, 
351                       RET_SMALL,, EF_, 0, 0);
352 /* the 1 is a bitmap - i.e. 1 non-pointer word on the stack. */
353
354 EXTFUN(stg_gc_unbx_r1_entry)
355 {
356   FB_
357   R1.w = Sp[0];
358   Sp += 1;
359   JMP_(ENTRY_CODE(Sp[0]));
360   FE_
361 }
362
363 EXTFUN(stg_gc_unbx_r1)
364 {
365   FB_
366   Sp -= 2;
367   Sp[1] = R1.w;
368   Sp[0] = (W_)&stg_gc_unbx_r1_info;
369   GC_GENERIC
370   FE_
371 }
372
373 /*-- F1 contains a float ------------------------------------------------- */
374
375 INFO_TABLE_SRT_BITMAP(stg_gc_f1_info, stg_gc_f1_entry, 1/*BITMAP*/,
376                       0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, 
377                       RET_SMALL,, EF_, 0, 0);
378
379 EXTFUN(stg_gc_f1_entry)
380 {
381   FB_
382   F1 = PK_FLT(Sp);
383   Sp += 1;
384   JMP_(ENTRY_CODE(Sp[0]));
385   FE_
386 }
387
388 EXTFUN(stg_gc_f1)
389 {
390   FB_
391   Sp -= 2;
392   ASSIGN_FLT(Sp+1, F1);
393   Sp[0] = (W_)&stg_gc_f1_info;
394   GC_GENERIC
395   FE_
396 }
397
398 /*-- D1 contains a double ------------------------------------------------- */
399
400 /* we support doubles of either 1 or 2 words in size */
401
402 #if SIZEOF_DOUBLE == SIZEOF_VOID_P
403 #  define DBL_BITMAP 1
404 #else
405 #  define DBL_BITMAP 3
406 #endif 
407
408 INFO_TABLE_SRT_BITMAP(stg_gc_d1_info, stg_gc_d1_entry, DBL_BITMAP,
409                       0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, 
410                       RET_SMALL,, EF_, 0, 0);
411
412 EXTFUN(stg_gc_d1_entry)
413 {
414   FB_
415   D1 = PK_DBL(Sp);
416   Sp += sizeofW(StgDouble);
417   JMP_(ENTRY_CODE(Sp[0]));
418   FE_
419 }
420
421 EXTFUN(stg_gc_d1)
422 {
423   FB_
424   Sp -= 1 + sizeofW(StgDouble);
425   ASSIGN_DBL(Sp+1,D1);
426   Sp[0] = (W_)&stg_gc_d1_info;
427   GC_GENERIC
428   FE_
429 }
430
431 /* -----------------------------------------------------------------------------
432    Heap checks for unboxed tuple case alternatives
433
434    The story is: 
435
436       - for an unboxed tuple with n components, we rearrange the components
437         with pointers first followed by non-pointers. (NB: not done yet)
438  
439       - The first k components are allocated registers, where k is the
440         number of components that will fit in real registers.
441
442       - The rest are placed on the stack, with space left for tagging
443         of the non-pointer block if necessary.
444
445       - On failure of a heap check:
446                 - the tag is filled in if necessary,
447                 - we load Ri with the address of the continuation,
448                   where i is the lowest unused vanilla register.
449                 - jump to 'stg_gc_ut_x_y' where x is the number of pointer
450                   registers and y the number of non-pointers.
451                 - if the required canned sequence isn't available, it will
452                   have to be generated at compile-time by the code
453                   generator (this will probably happen if there are
454                   floating-point values, for instance).
455   
456    For now, just deal with R1, hence R2 contains the sequel address.
457    -------------------------------------------------------------------------- */
458
459 /*---- R1 contains a pointer: ------ */
460
461 INFO_TABLE_SRT_BITMAP(stg_gc_ut_1_0_info, stg_gc_ut_1_0_entry, 1/*BITMAP*/, 
462                       0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, 
463                       RET_SMALL,, EF_, 0, 0);
464
465 EXTFUN(stg_gc_ut_1_0_entry)
466 {
467   FB_
468   R1.w = Sp[1];
469   Sp += 2;
470   JMP_(ENTRY_CODE(Sp[-2]));
471   FE_
472 }
473
474 EXTFUN(stg_gc_ut_1_0)
475 {
476   FB_
477   Sp -= 3;
478   Sp[2] = R1.w;
479   Sp[1] = R2.w;
480   Sp[0] = (W_)&stg_gc_ut_1_0_info;
481   GC_GENERIC
482   FE_
483 }
484
485 /*---- R1 contains a non-pointer: ------ */
486
487 INFO_TABLE_SRT_BITMAP(stg_gc_ut_0_1_info, stg_gc_ut_0_1_entry, 3/*BITMAP*/, 
488                       0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, 
489                       RET_SMALL,, EF_, 0, 0);
490
491 EXTFUN(stg_gc_ut_0_1_entry)
492 {
493   FB_
494   R1.w = Sp[1];
495   Sp += 2;
496   JMP_(ENTRY_CODE(Sp[-2]));
497   FE_
498 }
499
500 EXTFUN(stg_gc_ut_0_1)
501 {
502   FB_
503   Sp -= 3;
504   Sp[0] = (W_)&stg_gc_ut_0_1_info;
505   Sp[1] = R2.w;
506   Sp[2] = R1.w;
507   GC_GENERIC
508   FE_
509 }
510
511 /* -----------------------------------------------------------------------------
512    Standard top-level fast-entry heap checks.
513
514    - we want to make the stack look like it should at the slow entry
515      point for the function.  That way we can just push the slow
516      entry point on the stack and return using ThreadRunGHC.
517
518    - The compiler will generate code to fill in any tags on the stack,
519      in case we arrived directly at the fast entry point and these tags
520      aren't present.
521
522    - The rest is hopefully handled by jumping to a canned sequence.
523      We currently have canned sequences for 0-8 pointer registers.  If
524      any registers contain non-pointers, we must reduce to an all-pointers
525      situation by pushing as many registers on the stack as necessary.
526
527      eg. if R1, R2 contain pointers and R3 contains a word, the heap check
528          failure sequence looks like this:
529
530                 Sp[-1] = R3.w;
531                 Sp[-2] = WORD_TAG;
532                 Sp -= 2;
533                 JMP_(stg_chk_2)
534
535           after pushing R3, we have pointers in R1 and R2 which corresponds
536           to the 2-pointer canned sequence.
537
538   -------------------------------------------------------------------------- */
539
540 /*- 0 Regs -------------------------------------------------------------------*/
541
542 EXTFUN(stg_chk_0)
543 {
544   FB_
545   Sp -= 1;
546   Sp[0] = R1.w;
547   GC_GENERIC;
548   FE_
549 }
550
551 /*- 1 Reg --------------------------------------------------------------------*/
552
553 EXTFUN(stg_chk_1)
554 {
555   FB_
556   Sp -= 2;
557   Sp[1] = R1.w;
558   Sp[0] = R2.w;
559   GC_GENERIC;
560   FE_
561 }
562
563 /*- 1 Reg (non-ptr) ----------------------------------------------------------*/
564
565 EXTFUN(stg_chk_1n)
566 {
567   FB_
568   Sp -= 3;
569   Sp[2] = R1.w;
570   Sp[1] = WORD_TAG; /* ToDo: or maybe its an int? */
571   Sp[0] = R2.w;
572   GC_GENERIC;
573   FE_
574 }
575
576 /*- 2 Regs--------------------------------------------------------------------*/
577
578 EXTFUN(stg_chk_2)
579 {
580   FB_
581   Sp -= 3;
582   Sp[2] = R2.w;
583   Sp[1] = R1.w;
584   Sp[0] = R3.w;
585   GC_GENERIC;
586   FE_
587 }
588
589 /*- 3 Regs -------------------------------------------------------------------*/
590
591 EXTFUN(stg_chk_3)
592 {
593   FB_
594   Sp -= 4;
595   Sp[3] = R3.w;
596   Sp[2] = R2.w;
597   Sp[1] = R1.w;
598   Sp[0] = R4.w;
599   GC_GENERIC;
600   FE_
601 }
602
603 /*- 4 Regs -------------------------------------------------------------------*/
604
605 EXTFUN(stg_chk_4)
606 {
607   FB_
608   Sp -= 5;
609   Sp[4] = R4.w;
610   Sp[3] = R3.w;
611   Sp[2] = R2.w;
612   Sp[1] = R1.w;
613   Sp[0] = R5.w;
614   GC_GENERIC;
615   FE_
616 }
617
618 /*- 5 Regs -------------------------------------------------------------------*/
619
620 EXTFUN(stg_chk_5)
621 {
622   FB_
623   Sp -= 6;
624   Sp[5] = R5.w;
625   Sp[4] = R4.w;
626   Sp[3] = R3.w;
627   Sp[2] = R2.w;
628   Sp[1] = R1.w;
629   Sp[0] = R6.w;
630   GC_GENERIC;
631   FE_
632 }
633
634 /*- 6 Regs -------------------------------------------------------------------*/
635
636 EXTFUN(stg_chk_6)
637 {
638   FB_
639   Sp -= 7;
640   Sp[6] = R6.w;
641   Sp[5] = R5.w;
642   Sp[4] = R4.w;
643   Sp[3] = R3.w;
644   Sp[2] = R2.w;
645   Sp[1] = R1.w;
646   Sp[0] = R7.w;
647   GC_GENERIC;
648   FE_
649 }
650
651 /*- 7 Regs -------------------------------------------------------------------*/
652
653 EXTFUN(stg_chk_7)
654 {
655   FB_
656   Sp -= 8;
657   Sp[7] = R7.w;
658   Sp[6] = R6.w;
659   Sp[5] = R5.w;
660   Sp[4] = R4.w;
661   Sp[3] = R3.w;
662   Sp[2] = R2.w;
663   Sp[1] = R1.w;
664   Sp[0] = R8.w;
665   GC_GENERIC;
666   FE_
667 }
668
669 /*- 8 Regs -------------------------------------------------------------------*/
670
671 EXTFUN(stg_chk_8)
672 {
673   FB_
674   Sp -= 9;
675   Sp[8] = R8.w;
676   Sp[7] = R7.w;
677   Sp[6] = R6.w;
678   Sp[5] = R5.w;
679   Sp[4] = R4.w;
680   Sp[3] = R3.w;
681   Sp[2] = R2.w;
682   Sp[1] = R1.w;
683   Sp[0] = R9.w;
684   GC_GENERIC;
685   FE_
686 }
687
688 /* -----------------------------------------------------------------------------
689    Generic Heap Check Code.
690
691    Called with Liveness mask in R9,  Return address in R10.
692    Stack must be consistent (tagged, and containing all necessary info pointers
693    to relevant SRTs).
694
695    We also define an stg_gen_yield here, because it's very similar.
696    -------------------------------------------------------------------------- */
697
698 #if SIZEOF_DOUBLE > SIZEOF_VOID_P
699
700 #define RESTORE_EVERYTHING                      \
701     D2   = PK_DBL(Sp+16);                       \
702     D1   = PK_DBL(Sp+14);                       \
703     F4   = PK_FLT(Sp+13);                       \
704     F3   = PK_FLT(Sp+12);                       \
705     F2   = PK_FLT(Sp+11);                       \
706     F1   = PK_FLT(Sp+10);                       \
707     R8.w = Sp[9];                               \
708     R7.w = Sp[8];                               \
709     R6.w = Sp[7];                               \
710     R5.w = Sp[6];                               \
711     R4.w = Sp[5];                               \
712     R3.w = Sp[4];                               \
713     R2.w = Sp[3];                               \
714     R1.w = Sp[2];                               \
715     Sp += 18;
716
717 #define RET_OFFSET (-17)
718
719 #define SAVE_EVERYTHING                         \
720     ASSIGN_DBL(Sp-2,D2);                        \
721     ASSIGN_DBL(Sp-4,D1);                        \
722     ASSIGN_FLT(Sp-5,F4);                        \
723     ASSIGN_FLT(Sp-6,F3);                        \
724     ASSIGN_FLT(Sp-7,F2);                        \
725     ASSIGN_FLT(Sp-8,F1);                        \
726     Sp[-9]  = R8.w;                             \
727     Sp[-10] = R7.w;                             \
728     Sp[-11] = R6.w;                             \
729     Sp[-12] = R5.w;                             \
730     Sp[-13] = R4.w;                             \
731     Sp[-14] = R3.w;                             \
732     Sp[-15] = R2.w;                             \
733     Sp[-16] = R1.w;                             \
734     Sp[-17] = R10.w;    /* return address */    \
735     Sp[-18] = R9.w;     /* liveness mask  */    \
736     Sp[-19] = (W_)&stg_gen_chk_info;            \
737     Sp -= 19;
738
739 #else
740
741 #define RESTORE_EVERYTHING                      \
742     D2   = PK_DBL(Sp+15);                       \
743     D1   = PK_DBL(Sp+14);                       \
744     F4   = PK_FLT(Sp+13);                       \
745     F3   = PK_FLT(Sp+12);                       \
746     F2   = PK_FLT(Sp+11);                       \
747     F1   = PK_FLT(Sp+10);                       \
748     R8.w = Sp[9];                               \
749     R7.w = Sp[8];                               \
750     R6.w = Sp[7];                               \
751     R5.w = Sp[6];                               \
752     R4.w = Sp[5];                               \
753     R3.w = Sp[4];                               \
754     R2.w = Sp[3];                               \
755     R1.w = Sp[2];                               \
756     Sp += 16;
757
758 #define RET_OFFSET (-15)
759
760 #define SAVE_EVERYTHING                         \
761     ASSIGN_DBL(Sp-1,D2);                        \
762     ASSIGN_DBL(Sp-2,D1);                        \
763     ASSIGN_FLT(Sp-3,F4);                        \
764     ASSIGN_FLT(Sp-4,F3);                        \
765     ASSIGN_FLT(Sp-5,F2);                        \
766     ASSIGN_FLT(Sp-6,F1);                        \
767     Sp[-7]  = R8.w;                             \
768     Sp[-8]  = R7.w;                             \
769     Sp[-9]  = R6.w;                             \
770     Sp[-10] = R5.w;                             \
771     Sp[-11] = R4.w;                             \
772     Sp[-12] = R3.w;                             \
773     Sp[-13] = R2.w;                             \
774     Sp[-14] = R1.w;                             \
775     Sp[-15] = R10.w;    /* return address */    \
776     Sp[-16] = R9.w;     /* liveness mask  */    \
777     Sp[-17] = (W_)&stg_gen_chk_info;            \
778     Sp -= 17;
779
780 #endif
781
782 INFO_TABLE_SRT_BITMAP(stg_gen_chk_info, stg_gen_chk_ret, 0,
783                       0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, 
784                       RET_DYN,, EF_, 0, 0);
785
786 /* bitmap in the above info table is unused, the real one is on the stack. 
787  */
788
789 FN_(stg_gen_chk_ret)
790 {
791   FB_
792   RESTORE_EVERYTHING;
793   JMP_(Sp[RET_OFFSET]); /* NO ENTRY_CODE() - this is a direct ret address */
794   FE_
795 }
796
797 FN_(stg_gen_chk)
798 {
799   FB_
800   SAVE_EVERYTHING;
801   GC_GENERIC
802   FE_
803 }         
804
805 /*
806  * stg_gen_hp is used by MAYBE_GC, where we can't use GC_GENERIC
807  * because we've just failed doYouWantToGC(), not a standard heap
808  * check.  GC_GENERIC would end up returning StackOverflow.
809  */
810 FN_(stg_gen_hp)
811 {
812   FB_
813   SAVE_EVERYTHING;
814   HP_GENERIC
815   FE_
816 }         
817
818 /* -----------------------------------------------------------------------------
819    Yields
820    -------------------------------------------------------------------------- */
821
822 FN_(stg_gen_yield)
823 {
824   FB_
825   SAVE_EVERYTHING;
826   YIELD_GENERIC
827   FE_
828 }
829
830 FN_(stg_yield_noregs)
831 {
832   FB_
833   Sp--;
834   Sp[0] = (W_)&stg_gc_noregs_ret_info;
835   YIELD_GENERIC;
836   FE_
837 }
838
839 FN_(stg_yield_to_Hugs)
840 {
841   FB_
842   /* No need to save everything - no live registers */
843   YIELD_TO_HUGS
844   FE_
845 }
846
847 /* -----------------------------------------------------------------------------
848    Blocks
849    -------------------------------------------------------------------------- */
850
851 FN_(stg_gen_block)
852 {
853   FB_
854   SAVE_EVERYTHING;
855   BLOCK_GENERIC
856   FE_
857 }
858
859 FN_(stg_block_noregs)
860 {
861   FB_
862   Sp--;
863   Sp[0] = (W_)&stg_gc_noregs_ret_info;
864   BLOCK_GENERIC;
865   FE_
866 }
867
868 FN_(stg_block_1)
869 {
870   FB_
871   Sp--;
872   Sp[0] = R1.w;
873   BLOCK_ENTER;
874   FE_
875 }