[project @ 1999-02-05 16:02:18 by simonm]
[ghc-hetmet.git] / ghc / rts / HeapStackCheck.hc
1 /* -----------------------------------------------------------------------------
2  * $Id: HeapStackCheck.hc,v 1.3 1999/02/05 16:02:43 simonm 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, return address already on the stack: ---------------- */
297
298 EXTFUN(stg_gc_noregs)
299 {
300   FB_
301   GC_GENERIC
302   FE_
303 }
304
305 /*-- R1 is boxed/unpointed -------------------------------------------------- */
306
307 INFO_TABLE_SRT_BITMAP(stg_gc_unpt_r1_info, stg_gc_unpt_r1_entry, 0/*BITMAP*/, 
308                       0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, 
309                       RET_SMALL, const, EF_, 0, 0);
310
311 EXTFUN(stg_gc_unpt_r1_entry)
312 {
313   FB_
314   R1.w = Sp[0];
315   Sp += 1;
316   JMP_(ENTRY_CODE(Sp[0]));
317   FE_
318 }
319
320 EXTFUN(stg_gc_unpt_r1)
321 {
322   FB_
323   Sp -= 2;
324   Sp[1] = R1.w;
325   Sp[0] = (W_)&stg_gc_unpt_r1_info;
326   GC_GENERIC
327   FE_
328 }
329
330 /*-- R1 is unboxed -------------------------------------------------- */
331
332 INFO_TABLE_SRT_BITMAP(stg_gc_unbx_r1_info, stg_gc_unbx_r1_entry, 1/*BITMAP*/,
333                       0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, 
334                       RET_SMALL, const, EF_, 0, 0);
335 /* the 1 is a bitmap - i.e. 1 non-pointer word on the stack. */
336
337 EXTFUN(stg_gc_unbx_r1_entry)
338 {
339   FB_
340   R1.w = Sp[0];
341   Sp += 1;
342   JMP_(ENTRY_CODE(Sp[0]));
343   FE_
344 }
345
346 EXTFUN(stg_gc_unbx_r1)
347 {
348   FB_
349   Sp -= 2;
350   Sp[1] = R1.w;
351   Sp[0] = (W_)&stg_gc_unbx_r1_info;
352   GC_GENERIC
353   FE_
354 }
355
356 /*-- F1 contains a float ------------------------------------------------- */
357
358 INFO_TABLE_SRT_BITMAP(stg_gc_f1_info, stg_gc_f1_entry, 1/*BITMAP*/,
359                       0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, 
360                       RET_SMALL, const, EF_, 0, 0);
361
362 EXTFUN(stg_gc_f1_entry)
363 {
364   FB_
365   F1 = PK_FLT(Sp);
366   Sp += 1;
367   JMP_(ENTRY_CODE(Sp[0]));
368   FE_
369 }
370
371 EXTFUN(stg_gc_f1)
372 {
373   FB_
374   Sp -= 2;
375   ASSIGN_FLT(Sp+1, F1);
376   Sp[0] = (W_)&stg_gc_f1_info;
377   GC_GENERIC
378   FE_
379 }
380
381 /*-- D1 contains a double ------------------------------------------------- */
382
383 /* we support doubles of either 1 or 2 words in size */
384
385 #if SIZEOF_DOUBLE == SIZEOF_VOID_P
386 #  define DBL_BITMAP 1
387 #else
388 #  define DBL_BITMAP 3
389 #endif 
390
391 INFO_TABLE_SRT_BITMAP(stg_gc_d1_info, stg_gc_d1_entry, DBL_BITMAP,
392                       0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, 
393                       RET_SMALL, const, EF_, 0, 0);
394
395 EXTFUN(stg_gc_d1_entry)
396 {
397   FB_
398   D1 = PK_DBL(Sp);
399   Sp += sizeofW(StgDouble);
400   JMP_(ENTRY_CODE(Sp[0]));
401   FE_
402 }
403
404 EXTFUN(stg_gc_d1)
405 {
406   FB_
407   Sp -= 1 + sizeofW(StgDouble);
408   ASSIGN_DBL(Sp+1,D1);
409   Sp[0] = (W_)&stg_gc_d1_info;
410   GC_GENERIC
411   FE_
412 }
413
414 /* -----------------------------------------------------------------------------
415    Heap checks for unboxed tuple case alternatives
416
417    The story is: 
418
419       - for an unboxed tuple with n components, we rearrange the components
420         with pointers first followed by non-pointers. (NB: not done yet)
421  
422       - The first k components are allocated registers, where k is the
423         number of components that will fit in real registers.
424
425       - The rest are placed on the stack, with space left for tagging
426         of the non-pointer block if necessary.
427
428       - On failure of a heap check:
429                 - the tag is filled in if necessary,
430                 - we load Ri with the address of the continuation,
431                   where i is the lowest unused vanilla register.
432                 - jump to 'stg_gc_ut_x_y' where x is the number of pointer
433                   registers and y the number of non-pointers.
434                 - if the required canned sequence isn't available, it will
435                   have to be generated at compile-time by the code
436                   generator (this will probably happen if there are
437                   floating-point values, for instance).
438   
439    For now, just deal with R1, hence R2 contains the sequel address.
440    -------------------------------------------------------------------------- */
441
442 /*---- R1 contains a pointer: ------ */
443
444 INFO_TABLE_SRT_BITMAP(stg_gc_ut_1_0_info, stg_gc_ut_1_0_entry, 1/*BITMAP*/, 
445                       0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, 
446                       RET_SMALL, const, EF_, 0, 0);
447
448 EXTFUN(stg_gc_ut_1_0_entry)
449 {
450   FB_
451   R1.w = Sp[1];
452   Sp += 2;
453   JMP_(Sp[-2]);
454   FE_
455 }
456
457 EXTFUN(stg_gc_ut_1_0)
458 {
459   FB_
460   Sp -= 3;
461   Sp[2] = R1.w;
462   Sp[1] = R2.w;
463   Sp[0] = (W_)&stg_gc_ut_1_0_info;
464   GC_GENERIC
465   FE_
466 }
467
468 /*---- R1 contains a non-pointer: ------ */
469
470 INFO_TABLE_SRT_BITMAP(stg_gc_ut_0_1_info, stg_gc_ut_0_1_entry, 3/*BITMAP*/, 
471                       0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, 
472                       RET_SMALL, const, EF_, 0, 0);
473
474 EXTFUN(stg_gc_ut_0_1_entry)
475 {
476   FB_
477   R1.w = Sp[1];
478   Sp += 2;
479   JMP_(Sp[-2]);
480   FE_
481 }
482
483 EXTFUN(stg_gc_ut_0_1)
484 {
485   FB_
486   Sp -= 3;
487   Sp[0] = (W_)&stg_gc_ut_0_1_info;
488   Sp[1] = R2.w;
489   Sp[2] = R1.w;
490   GC_GENERIC
491   FE_
492 }
493
494 /* -----------------------------------------------------------------------------
495    Standard top-level fast-entry heap checks.
496
497    - we want to make the stack look like it should at the slow entry
498      point for the function.  That way we can just push the slow
499      entry point on the stack and return using ThreadRunGHC.
500
501    - The compiler will generate code to fill in any tags on the stack,
502      in case we arrived directly at the fast entry point and these tags
503      aren't present.
504
505    - The rest is hopefully handled by jumping to a canned sequence.
506      We currently have canned sequences for 0-8 pointer registers.  If
507      any registers contain non-pointers, we must reduce to an all-pointers
508      situation by pushing as many registers on the stack as necessary.
509
510      eg. if R1, R2 contain pointers and R3 contains a word, the heap check
511          failure sequence looks like this:
512
513                 Sp[-1] = R3.w;
514                 Sp[-2] = WORD_TAG;
515                 Sp -= 2;
516                 JMP_(stg_chk_2)
517
518           after pushing R3, we have pointers in R1 and R2 which corresponds
519           to the 2-pointer canned sequence.
520
521   -------------------------------------------------------------------------- */
522
523 /*- 0 Regs -------------------------------------------------------------------*/
524
525 EXTFUN(stg_chk_0)
526 {
527   FB_
528   Sp -= 1;
529   Sp[0] = R1.w;
530   GC_GENERIC;
531   FE_
532 }
533
534 /*- 1 Reg --------------------------------------------------------------------*/
535
536 EXTFUN(stg_chk_1)
537 {
538   FB_
539   Sp -= 2;
540   Sp[1] = R1.w;
541   Sp[0] = R2.w;
542   GC_GENERIC;
543   FE_
544 }
545
546 /*- 1 Reg (non-ptr) ----------------------------------------------------------*/
547
548 EXTFUN(stg_chk_1n)
549 {
550   FB_
551   Sp -= 3;
552   Sp[2] = R1.w;
553   Sp[1] = WORD_TAG; /* ToDo: or maybe its an int? */
554   Sp[0] = R2.w;
555   GC_GENERIC;
556   FE_
557 }
558
559 /*- 2 Regs--------------------------------------------------------------------*/
560
561 EXTFUN(stg_chk_2)
562 {
563   FB_
564   Sp -= 3;
565   Sp[2] = R2.w;
566   Sp[1] = R1.w;
567   Sp[0] = R3.w;
568   GC_GENERIC;
569   FE_
570 }
571
572 /*- 3 Regs -------------------------------------------------------------------*/
573
574 EXTFUN(stg_chk_3)
575 {
576   FB_
577   Sp -= 4;
578   Sp[3] = R3.w;
579   Sp[2] = R2.w;
580   Sp[1] = R1.w;
581   Sp[0] = R4.w;
582   GC_GENERIC;
583   FE_
584 }
585
586 /*- 4 Regs -------------------------------------------------------------------*/
587
588 EXTFUN(stg_chk_4)
589 {
590   FB_
591   Sp -= 5;
592   Sp[4] = R4.w;
593   Sp[3] = R3.w;
594   Sp[2] = R2.w;
595   Sp[1] = R1.w;
596   Sp[0] = R5.w;
597   GC_GENERIC;
598   FE_
599 }
600
601 /*- 5 Regs -------------------------------------------------------------------*/
602
603 EXTFUN(stg_chk_5)
604 {
605   FB_
606   Sp -= 6;
607   Sp[5] = R5.w;
608   Sp[4] = R4.w;
609   Sp[3] = R3.w;
610   Sp[2] = R2.w;
611   Sp[1] = R1.w;
612   Sp[0] = R6.w;
613   GC_GENERIC;
614   FE_
615 }
616
617 /*- 6 Regs -------------------------------------------------------------------*/
618
619 EXTFUN(stg_chk_6)
620 {
621   FB_
622   Sp -= 7;
623   Sp[6] = R6.w;
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] = R7.w;
630   GC_GENERIC;
631   FE_
632 }
633
634 /*- 7 Regs -------------------------------------------------------------------*/
635
636 EXTFUN(stg_chk_7)
637 {
638   FB_
639   Sp -= 8;
640   Sp[7] = R7.w;
641   Sp[6] = R6.w;
642   Sp[5] = R5.w;
643   Sp[4] = R4.w;
644   Sp[3] = R3.w;
645   Sp[2] = R2.w;
646   Sp[1] = R1.w;
647   Sp[0] = R8.w;
648   GC_GENERIC;
649   FE_
650 }
651
652 /*- 8 Regs -------------------------------------------------------------------*/
653
654 EXTFUN(stg_chk_8)
655 {
656   FB_
657   Sp -= 9;
658   Sp[8] = R8.w;
659   Sp[7] = R7.w;
660   Sp[6] = R6.w;
661   Sp[5] = R5.w;
662   Sp[4] = R4.w;
663   Sp[3] = R3.w;
664   Sp[2] = R2.w;
665   Sp[1] = R1.w;
666   Sp[0] = R9.w;
667   GC_GENERIC;
668   FE_
669 }
670
671 /* -----------------------------------------------------------------------------
672    Generic Heap Check Code.
673
674    Called with Liveness mask in R9,  Return address in R10.
675    Stack must be consistent (tagged, and containing all necessary info pointers
676    to relevant SRTs).
677
678    We also define an stg_gen_yield here, because it's very similar.
679    -------------------------------------------------------------------------- */
680
681 #if SIZEOF_DOUBLE > SIZEOF_VOID_P
682
683 #define RESTORE_EVERYTHING                      \
684     D2   = PK_DBL(Sp+16);                       \
685     D1   = PK_DBL(Sp+14);                       \
686     F4   = PK_FLT(Sp+13);                       \
687     F3   = PK_FLT(Sp+12);                       \
688     F2   = PK_FLT(Sp+11);                       \
689     F1   = PK_FLT(Sp+10);                       \
690     R8.w = Sp[9];                               \
691     R7.w = Sp[8];                               \
692     R6.w = Sp[7];                               \
693     R5.w = Sp[6];                               \
694     R4.w = Sp[5];                               \
695     R3.w = Sp[4];                               \
696     R2.w = Sp[3];                               \
697     R1.w = Sp[2];                               \
698     Sp += 18;
699
700 #define RET_OFFSET (-17)
701
702 #define SAVE_EVERYTHING                         \
703     ASSIGN_DBL(Sp-2,D2);                        \
704     ASSIGN_DBL(Sp-4,D1);                        \
705     ASSIGN_FLT(Sp-5,F4);                        \
706     ASSIGN_FLT(Sp-6,F3);                        \
707     ASSIGN_FLT(Sp-7,F2);                        \
708     ASSIGN_FLT(Sp-8,F1);                        \
709     Sp[-9]  = R8.w;                             \
710     Sp[-10] = R7.w;                             \
711     Sp[-11] = R6.w;                             \
712     Sp[-12] = R5.w;                             \
713     Sp[-13] = R4.w;                             \
714     Sp[-14] = R3.w;                             \
715     Sp[-15] = R2.w;                             \
716     Sp[-16] = R1.w;                             \
717     Sp[-17] = R10.w;    /* return address */    \
718     Sp[-18] = R9.w;     /* liveness mask  */    \
719     Sp[-19] = (W_)&stg_gen_chk_info;            \
720     Sp -= 19;
721
722 #else
723
724 #define RESTORE_EVERYTHING                      \
725     D2   = PK_DBL(Sp+15);                       \
726     D1   = PK_DBL(Sp+14);                       \
727     F4   = PK_FLT(Sp+13);                       \
728     F3   = PK_FLT(Sp+12);                       \
729     F2   = PK_FLT(Sp+11);                       \
730     F1   = PK_FLT(Sp+10);                       \
731     R8.w = Sp[9];                               \
732     R7.w = Sp[8];                               \
733     R6.w = Sp[7];                               \
734     R5.w = Sp[6];                               \
735     R4.w = Sp[5];                               \
736     R3.w = Sp[4];                               \
737     R2.w = Sp[3];                               \
738     R1.w = Sp[2];                               \
739     Sp += 16;
740
741 #define RET_OFFSET (-15)
742
743 #define SAVE_EVERYTHING                         \
744     ASSIGN_DBL(Sp-1,D2);                        \
745     ASSIGN_DBL(Sp-2,D1);                        \
746     ASSIGN_FLT(Sp-3,F4);                        \
747     ASSIGN_FLT(Sp-4,F3);                        \
748     ASSIGN_FLT(Sp-5,F2);                        \
749     ASSIGN_FLT(Sp-6,F1);                        \
750     Sp[-7]  = R8.w;                             \
751     Sp[-8]  = R7.w;                             \
752     Sp[-9]  = R6.w;                             \
753     Sp[-10] = R5.w;                             \
754     Sp[-11] = R4.w;                             \
755     Sp[-12] = R3.w;                             \
756     Sp[-13] = R2.w;                             \
757     Sp[-14] = R1.w;                             \
758     Sp[-15] = R10.w;    /* return address */    \
759     Sp[-16] = R9.w;     /* liveness mask  */    \
760     Sp[-17] = (W_)&stg_gen_chk_info;            \
761     Sp -= 17;
762
763 #endif
764
765 INFO_TABLE_SRT_BITMAP(stg_gen_chk_info, stg_gen_chk_ret, 0,
766                       0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, 
767                       RET_DYN, const, EF_, 0, 0);
768
769 /* bitmap in the above info table is unused, the real one is on the stack. 
770  */
771
772 FN_(stg_gen_chk_ret)
773 {
774   FB_
775   RESTORE_EVERYTHING;
776   JMP_(Sp[RET_OFFSET]);
777   FE_
778 }
779
780 FN_(stg_gen_chk)
781 {
782   FB_
783   SAVE_EVERYTHING;
784   GC_GENERIC
785   FE_
786 }         
787
788 /*
789  * stg_gen_hp is used by MAYBE_GC, where we can't use GC_GENERIC
790  * because we've just failed doYouWantToGC(), not a standard heap
791  * check.  GC_GENERIC would end up returning StackOverflow.
792  */
793 FN_(stg_gen_hp)
794 {
795   FB_
796   SAVE_EVERYTHING;
797   HP_GENERIC
798   FE_
799 }         
800
801 FN_(stg_gen_yield)
802 {
803   FB_
804   SAVE_EVERYTHING;
805   YIELD_GENERIC
806   FE_
807 }
808
809 FN_(stg_yield_to_Hugs)
810 {
811   FB_
812   /* No need to save everything - no live registers */
813   YIELD_TO_HUGS
814   FE_
815 }
816
817 FN_(stg_gen_block)
818 {
819   FB_
820   SAVE_EVERYTHING;
821   BLOCK_GENERIC
822   FE_
823 }
824
825 FN_(stg_block_1)
826 {
827   FB_
828   Sp--;
829   Sp[0] = R1.w;
830   BLOCK_ENTER;
831   FE_
832 }