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