1 /* -----------------------------------------------------------------------------
2 * $Id: HeapStackCheck.hc,v 1.16 2001/03/23 16:36:21 simonmar Exp $
4 * (c) The GHC Team, 1998-1999
6 * Canned Heap-Check and Stack-Check sequences.
8 * ---------------------------------------------------------------------------*/
12 #include "Storage.h" /* for CurrentTSO */
13 #include "StgRun.h" /* for StgReturn and register saving */
14 #include "Schedule.h" /* for context_switch */
15 #include "HeapStackCheck.h"
17 /* Stack/Heap Check Failure
18 * ------------------------
20 * On discovering that a stack or heap check has failed, we do the following:
22 * - If the context_switch flag is set, indicating that there are more
23 * threads waiting to run, we yield to the scheduler
24 * (return ThreadYielding).
26 * - If Hp > HpLim, we've had a heap check failure. This means we've
27 * come to the end of the current heap block, so we try to chain
28 * another block on with ExtendNursery().
30 * - If this succeeds, we carry on without returning to the
33 * - If it fails, we return to the scheduler claiming HeapOverflow
34 * so that a garbage collection can be performed.
36 * - If Hp <= HpLim, it must have been a stack check that failed. In
37 * which case, we return to the scheduler claiming StackOverflow, the
38 * scheduler will either increase the size of our stack, or flag
39 * an error if the stack is already too big.
41 * The effect of checking for context switch only in the heap/stack check
42 * failure code is that we'll switch threads after the current thread has
43 * reached the end of its heap block. If a thread isn't allocating
44 * at all, it won't yield. Hopefully this won't be a problem in practice.
47 /* Remember that the return address is *removed* when returning to a
48 * ThreadRunGHC thread.
54 if (ExtendNursery(Hp,HpLim)) { \
55 if (context_switch) { \
56 R1.i = ThreadYielding; \
59 JMP_(ENTRY_CODE(Sp[-1])); \
62 R1.i = HeapOverflow; \
65 R1.i = StackOverflow; \
68 CurrentTSO->what_next = ThreadRunGHC; \
73 if (ExtendNursery(Hp,HpLim)) { \
74 if (context_switch) { \
75 R1.i = ThreadYielding; \
79 JMP_(ENTRY_CODE(*R1.p)); \
82 R1.i = HeapOverflow; \
85 R1.i = StackOverflow; \
88 CurrentTSO->what_next = ThreadEnterGHC; \
93 CurrentTSO->what_next = ThreadRunGHC; \
94 R1.i = HeapOverflow; \
99 CurrentTSO->what_next = ThreadRunGHC; \
100 R1.i = StackOverflow; \
103 #define YIELD_GENERIC \
105 CurrentTSO->what_next = ThreadRunGHC; \
106 R1.i = ThreadYielding; \
109 #define YIELD_TO_INTERPRETER \
111 CurrentTSO->what_next = ThreadEnterInterp; \
112 R1.i = ThreadYielding; \
115 #define BLOCK_GENERIC \
117 CurrentTSO->what_next = ThreadRunGHC; \
118 R1.i = ThreadBlocked; \
121 #define BLOCK_ENTER \
123 CurrentTSO->what_next = ThreadEnterGHC;\
124 R1.i = ThreadBlocked; \
128 /* -----------------------------------------------------------------------------
130 -------------------------------------------------------------------------- */
133 * This one is used when we want to *enter* the top thing on the stack
134 * when we return, instead of the just returning to an address. See
135 * UpdatePAP for an example.
138 EXTFUN(stg_gc_entertop)
145 /* -----------------------------------------------------------------------------
146 Heap checks in non-top-level thunks/functions.
148 In these cases, node always points to the function closure. This gives
149 us an easy way to return to the function: just leave R1 on the top of
150 the stack, and have the scheduler enter it to return.
152 There are canned sequences for 'n' pointer values in registers.
153 -------------------------------------------------------------------------- */
155 EXTFUN(stg_gc_enter_1)
164 EXTFUN(stg_gc_enter_1_hponly)
171 CurrentTSO->what_next = ThreadEnterGHC;
176 /*- 2 Regs--------------------------------------------------------------------*/
178 EXTFUN(stg_gc_enter_2)
188 /*- 3 Regs -------------------------------------------------------------------*/
190 EXTFUN(stg_gc_enter_3)
201 /*- 4 Regs -------------------------------------------------------------------*/
203 EXTFUN(stg_gc_enter_4)
215 /*- 5 Regs -------------------------------------------------------------------*/
217 EXTFUN(stg_gc_enter_5)
230 /*- 6 Regs -------------------------------------------------------------------*/
232 EXTFUN(stg_gc_enter_6)
246 /*- 7 Regs -------------------------------------------------------------------*/
248 EXTFUN(stg_gc_enter_7)
263 /*- 8 Regs -------------------------------------------------------------------*/
265 EXTFUN(stg_gc_enter_8)
283 ToDo: merge the block and yield macros, calling something like BLOCK(N)
288 Should we actually ever do a yield in such a case?? -- HWL
294 CurrentTSO->what_next = ThreadEnterGHC;
295 R1.i = ThreadYielding;
306 CurrentTSO->what_next = ThreadEnterGHC;
307 R1.i = ThreadYielding;
312 /*- 2 Regs--------------------------------------------------------------------*/
321 CurrentTSO->what_next = ThreadEnterGHC;
322 R1.i = ThreadYielding;
327 /*- 3 Regs -------------------------------------------------------------------*/
337 CurrentTSO->what_next = ThreadEnterGHC;
338 R1.i = ThreadYielding;
343 /*- 4 Regs -------------------------------------------------------------------*/
354 CurrentTSO->what_next = ThreadEnterGHC;
355 R1.i = ThreadYielding;
360 /*- 5 Regs -------------------------------------------------------------------*/
372 CurrentTSO->what_next = ThreadEnterGHC;
373 R1.i = ThreadYielding;
378 /*- 6 Regs -------------------------------------------------------------------*/
391 CurrentTSO->what_next = ThreadEnterGHC;
392 R1.i = ThreadYielding;
397 /*- 7 Regs -------------------------------------------------------------------*/
411 CurrentTSO->what_next = ThreadEnterGHC;
412 R1.i = ThreadYielding;
417 /*- 8 Regs -------------------------------------------------------------------*/
432 CurrentTSO->what_next = ThreadEnterGHC;
433 R1.i = ThreadYielding;
438 // the same routines but with a block rather than a yield
446 CurrentTSO->what_next = ThreadEnterGHC;
447 R1.i = ThreadBlocked;
452 /*- 2 Regs--------------------------------------------------------------------*/
461 CurrentTSO->what_next = ThreadEnterGHC;
462 R1.i = ThreadBlocked;
467 /*- 3 Regs -------------------------------------------------------------------*/
477 CurrentTSO->what_next = ThreadEnterGHC;
478 R1.i = ThreadBlocked;
483 /*- 4 Regs -------------------------------------------------------------------*/
494 CurrentTSO->what_next = ThreadEnterGHC;
495 R1.i = ThreadBlocked;
500 /*- 5 Regs -------------------------------------------------------------------*/
512 CurrentTSO->what_next = ThreadEnterGHC;
513 R1.i = ThreadBlocked;
518 /*- 6 Regs -------------------------------------------------------------------*/
531 CurrentTSO->what_next = ThreadEnterGHC;
532 R1.i = ThreadBlocked;
537 /*- 7 Regs -------------------------------------------------------------------*/
551 CurrentTSO->what_next = ThreadEnterGHC;
552 R1.i = ThreadBlocked;
557 /*- 8 Regs -------------------------------------------------------------------*/
572 CurrentTSO->what_next = ThreadEnterGHC;
573 R1.i = ThreadBlocked;
580 #if 0 && defined(PAR)
583 Similar to stg_block_1 (called via StgMacro BLOCK_NP) but separates the
584 saving of the thread state from the actual jump via an StgReturn.
585 We need this separation because we call RTS routines in blocking entry codes
586 before jumping back into the RTS (see parallel/FetchMe.hc).
589 EXTFUN(par_block_1_no_jump)
601 CurrentTSO->what_next = ThreadEnterGHC;
602 R1.i = ThreadBlocked;
609 /* -----------------------------------------------------------------------------
610 For a case expression on a polymorphic or function-typed object, if
611 the default branch (there can only be one branch) of the case fails
612 a heap-check, instead of using stg_gc_enter_1 as normal, we must
613 push a new SEQ frame on the stack, followed by the object returned.
615 Otherwise, if the object is a function, it won't return to the
616 correct activation record on returning from garbage collection. It will
617 assume it has some arguments and apply itself.
618 -------------------------------------------------------------------------- */
623 Sp -= 1 + sizeofW(StgSeqFrame);
624 PUSH_SEQ_FRAME(Sp+1);
630 /* -----------------------------------------------------------------------------
631 Heap checks in Primitive case alternatives
633 A primitive case alternative is entered with a value either in
634 R1, FloatReg1 or D1 depending on the return convention. All the
635 cases are covered below.
636 -------------------------------------------------------------------------- */
638 /*-- No regsiters live (probably a void return) ----------------------------- */
640 /* If we change the policy for thread startup to *not* remove the
641 * return address from the stack, we can get rid of this little
642 * function/info table...
644 INFO_TABLE_SRT_BITMAP(stg_gc_noregs_ret_info, stg_gc_noregs_ret, 0/*BITMAP*/,
645 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
646 RET_SMALL,, EF_, 0, 0);
648 EXTFUN(stg_gc_noregs_ret)
651 JMP_(ENTRY_CODE(Sp[0]));
655 EXTFUN(stg_gc_noregs)
659 Sp[0] = (W_)&stg_gc_noregs_ret_info;
664 /*-- R1 is boxed/unpointed -------------------------------------------------- */
666 INFO_TABLE_SRT_BITMAP(stg_gc_unpt_r1_info, stg_gc_unpt_r1_entry, 0/*BITMAP*/,
667 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
668 RET_SMALL,, EF_, 0, 0);
670 EXTFUN(stg_gc_unpt_r1_entry)
675 JMP_(ENTRY_CODE(Sp[0]));
679 EXTFUN(stg_gc_unpt_r1)
684 Sp[0] = (W_)&stg_gc_unpt_r1_info;
689 /*-- R1 is unboxed -------------------------------------------------- */
691 INFO_TABLE_SRT_BITMAP(stg_gc_unbx_r1_info, stg_gc_unbx_r1_entry, 1/*BITMAP*/,
692 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
693 RET_SMALL,, EF_, 0, 0);
694 /* the 1 is a bitmap - i.e. 1 non-pointer word on the stack. */
696 EXTFUN(stg_gc_unbx_r1_entry)
701 JMP_(ENTRY_CODE(Sp[0]));
705 EXTFUN(stg_gc_unbx_r1)
710 Sp[0] = (W_)&stg_gc_unbx_r1_info;
715 /*-- F1 contains a float ------------------------------------------------- */
717 INFO_TABLE_SRT_BITMAP(stg_gc_f1_info, stg_gc_f1_entry, 1/*BITMAP*/,
718 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
719 RET_SMALL,, EF_, 0, 0);
721 EXTFUN(stg_gc_f1_entry)
726 JMP_(ENTRY_CODE(Sp[0]));
734 ASSIGN_FLT(Sp+1, F1);
735 Sp[0] = (W_)&stg_gc_f1_info;
740 /*-- D1 contains a double ------------------------------------------------- */
742 /* we support doubles of either 1 or 2 words in size */
744 #if SIZEOF_DOUBLE == SIZEOF_VOID_P
745 # define DBL_BITMAP 1
747 # define DBL_BITMAP 3
750 INFO_TABLE_SRT_BITMAP(stg_gc_d1_info, stg_gc_d1_entry, DBL_BITMAP,
751 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
752 RET_SMALL,, EF_, 0, 0);
754 EXTFUN(stg_gc_d1_entry)
758 Sp += sizeofW(StgDouble);
759 JMP_(ENTRY_CODE(Sp[0]));
766 Sp -= 1 + sizeofW(StgDouble);
768 Sp[0] = (W_)&stg_gc_d1_info;
773 /* -----------------------------------------------------------------------------
774 Heap checks for unboxed tuple case alternatives
778 - for an unboxed tuple with n components, we rearrange the components
779 with pointers first followed by non-pointers. (NB: not done yet)
781 - The first k components are allocated registers, where k is the
782 number of components that will fit in real registers.
784 - The rest are placed on the stack, with space left for tagging
785 of the non-pointer block if necessary.
787 - On failure of a heap check:
788 - the tag is filled in if necessary,
789 - we load Ri with the address of the continuation,
790 where i is the lowest unused vanilla register.
791 - jump to 'stg_gc_ut_x_y' where x is the number of pointer
792 registers and y the number of non-pointers.
793 - if the required canned sequence isn't available, it will
794 have to be generated at compile-time by the code
795 generator (this will probably happen if there are
796 floating-point values, for instance).
798 For now, just deal with R1, hence R2 contains the sequel address.
799 -------------------------------------------------------------------------- */
801 /*---- R1 contains a pointer: ------ */
803 INFO_TABLE_SRT_BITMAP(stg_gc_ut_1_0_info, stg_gc_ut_1_0_entry, 1/*BITMAP*/,
804 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
805 RET_SMALL,, EF_, 0, 0);
807 EXTFUN(stg_gc_ut_1_0_entry)
812 JMP_(ENTRY_CODE(Sp[-2]));
816 EXTFUN(stg_gc_ut_1_0)
822 Sp[0] = (W_)&stg_gc_ut_1_0_info;
827 /*---- R1 contains a non-pointer: ------ */
829 INFO_TABLE_SRT_BITMAP(stg_gc_ut_0_1_info, stg_gc_ut_0_1_entry, 3/*BITMAP*/,
830 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
831 RET_SMALL,, EF_, 0, 0);
833 EXTFUN(stg_gc_ut_0_1_entry)
838 JMP_(ENTRY_CODE(Sp[-2]));
842 EXTFUN(stg_gc_ut_0_1)
846 Sp[0] = (W_)&stg_gc_ut_0_1_info;
853 /* -----------------------------------------------------------------------------
854 Standard top-level fast-entry heap checks.
856 - we want to make the stack look like it should at the slow entry
857 point for the function. That way we can just push the slow
858 entry point on the stack and return using ThreadRunGHC.
860 - The compiler will generate code to fill in any tags on the stack,
861 in case we arrived directly at the fast entry point and these tags
864 - The rest is hopefully handled by jumping to a canned sequence.
865 We currently have canned sequences for 0-8 pointer registers. If
866 any registers contain non-pointers, we must reduce to an all-pointers
867 situation by pushing as many registers on the stack as necessary.
869 eg. if R1, R2 contain pointers and R3 contains a word, the heap check
870 failure sequence looks like this:
877 after pushing R3, we have pointers in R1 and R2 which corresponds
878 to the 2-pointer canned sequence.
880 -------------------------------------------------------------------------- */
882 /*- 0 Regs -------------------------------------------------------------------*/
893 /*- 1 Reg --------------------------------------------------------------------*/
905 /*- 1 Reg (non-ptr) ----------------------------------------------------------*/
912 Sp[1] = WORD_TAG; /* ToDo: or maybe its an int? */
918 /*- 2 Regs--------------------------------------------------------------------*/
931 /*- 3 Regs -------------------------------------------------------------------*/
945 /*- 4 Regs -------------------------------------------------------------------*/
960 /*- 5 Regs -------------------------------------------------------------------*/
976 /*- 6 Regs -------------------------------------------------------------------*/
993 /*- 7 Regs -------------------------------------------------------------------*/
1011 /*- 8 Regs -------------------------------------------------------------------*/
1030 /* -----------------------------------------------------------------------------
1031 Generic Heap Check Code.
1033 Called with Liveness mask in R9, Return address in R10.
1034 Stack must be consistent (tagged, and containing all necessary info pointers
1037 We also define an stg_gen_yield here, because it's very similar.
1038 -------------------------------------------------------------------------- */
1040 #if SIZEOF_DOUBLE > SIZEOF_VOID_P
1042 #define RESTORE_EVERYTHING \
1043 D2 = PK_DBL(Sp+16); \
1044 D1 = PK_DBL(Sp+14); \
1045 F4 = PK_FLT(Sp+13); \
1046 F3 = PK_FLT(Sp+12); \
1047 F2 = PK_FLT(Sp+11); \
1048 F1 = PK_FLT(Sp+10); \
1059 #define RET_OFFSET (-17)
1061 #define SAVE_EVERYTHING \
1062 ASSIGN_DBL(Sp-2,D2); \
1063 ASSIGN_DBL(Sp-4,D1); \
1064 ASSIGN_FLT(Sp-5,F4); \
1065 ASSIGN_FLT(Sp-6,F3); \
1066 ASSIGN_FLT(Sp-7,F2); \
1067 ASSIGN_FLT(Sp-8,F1); \
1076 Sp[-17] = R10.w; /* return address */ \
1077 Sp[-18] = R9.w; /* liveness mask */ \
1078 Sp[-19] = (W_)&stg_gen_chk_info; \
1083 #define RESTORE_EVERYTHING \
1084 D2 = PK_DBL(Sp+15); \
1085 D1 = PK_DBL(Sp+14); \
1086 F4 = PK_FLT(Sp+13); \
1087 F3 = PK_FLT(Sp+12); \
1088 F2 = PK_FLT(Sp+11); \
1089 F1 = PK_FLT(Sp+10); \
1100 #define RET_OFFSET (-15)
1102 #define SAVE_EVERYTHING \
1103 ASSIGN_DBL(Sp-1,D2); \
1104 ASSIGN_DBL(Sp-2,D1); \
1105 ASSIGN_FLT(Sp-3,F4); \
1106 ASSIGN_FLT(Sp-4,F3); \
1107 ASSIGN_FLT(Sp-5,F2); \
1108 ASSIGN_FLT(Sp-6,F1); \
1117 Sp[-15] = R10.w; /* return address */ \
1118 Sp[-16] = R9.w; /* liveness mask */ \
1119 Sp[-17] = (W_)&stg_gen_chk_info; \
1124 INFO_TABLE_SRT_BITMAP(stg_gen_chk_info, stg_gen_chk_ret, 0,
1125 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
1126 RET_DYN,, EF_, 0, 0);
1128 /* bitmap in the above info table is unused, the real one is on the stack.
1131 FN_(stg_gen_chk_ret)
1135 JMP_(Sp[RET_OFFSET]); /* NO ENTRY_CODE() - this is a direct ret address */
1148 * stg_gen_hp is used by MAYBE_GC, where we can't use GC_GENERIC
1149 * because we've just failed doYouWantToGC(), not a standard heap
1150 * check. GC_GENERIC would end up returning StackOverflow.
1160 /* -----------------------------------------------------------------------------
1162 -------------------------------------------------------------------------- */
1172 FN_(stg_yield_noregs)
1176 Sp[0] = (W_)&stg_gc_noregs_ret_info;
1181 FN_(stg_yield_to_interpreter)
1184 /* No need to save everything - no live registers */
1185 YIELD_TO_INTERPRETER
1189 /* -----------------------------------------------------------------------------
1191 -------------------------------------------------------------------------- */
1201 FN_(stg_block_noregs)
1205 Sp[0] = (W_)&stg_gc_noregs_ret_info;