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