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