1 /* -----------------------------------------------------------------------------
2 * $Id: HeapStackCheck.hc,v 1.10 1999/11/09 15:46:51 simonmar Exp $
4 * (c) The GHC Team, 1998-1999
6 * Canned Heap-Check and Stack-Check sequences.
8 * ---------------------------------------------------------------------------*/
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"
16 /* Stack/Heap Check Failure
17 * ------------------------
19 * On discovering that a stack or heap check has failed, we do the following:
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).
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().
29 * - If this succeeds, we carry on without returning to the
32 * - If it fails, we return to the scheduler claiming HeapOverflow
33 * so that a garbage collection can be performed.
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.
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.
46 /* Remember that the return address is *removed* when returning to a
47 * ThreadRunGHC thread.
53 if (ExtendNursery(Hp,HpLim)) { \
54 if (context_switch) { \
55 R1.i = ThreadYielding; \
58 JMP_(ENTRY_CODE(Sp[-1])); \
61 R1.i = HeapOverflow; \
64 R1.i = StackOverflow; \
67 CurrentTSO->whatNext = ThreadRunGHC; \
72 if (ExtendNursery(Hp,HpLim)) { \
73 if (context_switch) { \
74 R1.i = ThreadYielding; \
78 JMP_(ENTRY_CODE(*R1.p)); \
81 R1.i = HeapOverflow; \
84 R1.i = StackOverflow; \
87 CurrentTSO->whatNext = ThreadEnterGHC; \
92 CurrentTSO->whatNext = ThreadRunGHC; \
93 R1.i = HeapOverflow; \
98 CurrentTSO->whatNext = ThreadRunGHC; \
99 R1.i = StackOverflow; \
102 #define YIELD_GENERIC \
104 CurrentTSO->whatNext = ThreadRunGHC; \
105 R1.i = ThreadYielding; \
108 #define YIELD_TO_HUGS \
110 CurrentTSO->whatNext = ThreadEnterHugs; \
111 R1.i = ThreadYielding; \
114 #define BLOCK_GENERIC \
116 CurrentTSO->whatNext = ThreadRunGHC; \
117 R1.i = ThreadBlocked; \
120 #define BLOCK_ENTER \
122 CurrentTSO->whatNext = ThreadEnterGHC;\
123 R1.i = ThreadBlocked; \
126 /* -----------------------------------------------------------------------------
128 -------------------------------------------------------------------------- */
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.
136 EXTFUN(stg_gc_entertop)
143 /* -----------------------------------------------------------------------------
144 Heap checks in non-top-level thunks/functions.
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.
150 There are canned sequences for 'n' pointer values in registers.
151 -------------------------------------------------------------------------- */
153 EXTFUN(stg_gc_enter_1)
162 EXTFUN(stg_gc_enter_1_hponly)
169 CurrentTSO->whatNext = ThreadEnterGHC;
174 /*- 2 Regs--------------------------------------------------------------------*/
176 EXTFUN(stg_gc_enter_2)
186 /*- 3 Regs -------------------------------------------------------------------*/
188 EXTFUN(stg_gc_enter_3)
199 /*- 4 Regs -------------------------------------------------------------------*/
201 EXTFUN(stg_gc_enter_4)
213 /*- 5 Regs -------------------------------------------------------------------*/
215 EXTFUN(stg_gc_enter_5)
228 /*- 6 Regs -------------------------------------------------------------------*/
230 EXTFUN(stg_gc_enter_6)
244 /*- 7 Regs -------------------------------------------------------------------*/
246 EXTFUN(stg_gc_enter_7)
261 /*- 8 Regs -------------------------------------------------------------------*/
263 EXTFUN(stg_gc_enter_8)
279 /* -----------------------------------------------------------------------------
280 For a case expression on a polymorphic or function-typed object, if
281 the default branch (there can only be one branch) of the case fails
282 a heap-check, instead of using stg_gc_enter_1 as normal, we must
283 push a new SEQ frame on the stack, followed by the object returned.
285 Otherwise, if the object is a function, it won't return to the
286 correct activation record on returning from garbage collection. It will
287 assume it has some arguments and apply itself.
288 -------------------------------------------------------------------------- */
293 Sp -= 1 + sizeofW(StgSeqFrame);
294 PUSH_SEQ_FRAME(Sp+1);
300 /* -----------------------------------------------------------------------------
301 Heap checks in Primitive case alternatives
303 A primitive case alternative is entered with a value either in
304 R1, FloatReg1 or D1 depending on the return convention. All the
305 cases are covered below.
306 -------------------------------------------------------------------------- */
308 /*-- No regsiters live (probably a void return) ----------------------------- */
310 /* If we change the policy for thread startup to *not* remove the
311 * return address from the stack, we can get rid of this little
312 * function/info table...
314 INFO_TABLE_SRT_BITMAP(stg_gc_noregs_ret_info, stg_gc_noregs_ret, 0/*BITMAP*/,
315 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
316 RET_SMALL,, EF_, 0, 0);
318 EXTFUN(stg_gc_noregs_ret)
321 JMP_(ENTRY_CODE(Sp[0]));
325 EXTFUN(stg_gc_noregs)
329 Sp[0] = (W_)&stg_gc_noregs_ret_info;
334 /*-- R1 is boxed/unpointed -------------------------------------------------- */
336 INFO_TABLE_SRT_BITMAP(stg_gc_unpt_r1_info, stg_gc_unpt_r1_entry, 0/*BITMAP*/,
337 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
338 RET_SMALL,, EF_, 0, 0);
340 EXTFUN(stg_gc_unpt_r1_entry)
345 JMP_(ENTRY_CODE(Sp[0]));
349 EXTFUN(stg_gc_unpt_r1)
354 Sp[0] = (W_)&stg_gc_unpt_r1_info;
359 /*-- R1 is unboxed -------------------------------------------------- */
361 INFO_TABLE_SRT_BITMAP(stg_gc_unbx_r1_info, stg_gc_unbx_r1_entry, 1/*BITMAP*/,
362 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
363 RET_SMALL,, EF_, 0, 0);
364 /* the 1 is a bitmap - i.e. 1 non-pointer word on the stack. */
366 EXTFUN(stg_gc_unbx_r1_entry)
371 JMP_(ENTRY_CODE(Sp[0]));
375 EXTFUN(stg_gc_unbx_r1)
380 Sp[0] = (W_)&stg_gc_unbx_r1_info;
385 /*-- F1 contains a float ------------------------------------------------- */
387 INFO_TABLE_SRT_BITMAP(stg_gc_f1_info, stg_gc_f1_entry, 1/*BITMAP*/,
388 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
389 RET_SMALL,, EF_, 0, 0);
391 EXTFUN(stg_gc_f1_entry)
396 JMP_(ENTRY_CODE(Sp[0]));
404 ASSIGN_FLT(Sp+1, F1);
405 Sp[0] = (W_)&stg_gc_f1_info;
410 /*-- D1 contains a double ------------------------------------------------- */
412 /* we support doubles of either 1 or 2 words in size */
414 #if SIZEOF_DOUBLE == SIZEOF_VOID_P
415 # define DBL_BITMAP 1
417 # define DBL_BITMAP 3
420 INFO_TABLE_SRT_BITMAP(stg_gc_d1_info, stg_gc_d1_entry, DBL_BITMAP,
421 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
422 RET_SMALL,, EF_, 0, 0);
424 EXTFUN(stg_gc_d1_entry)
428 Sp += sizeofW(StgDouble);
429 JMP_(ENTRY_CODE(Sp[0]));
436 Sp -= 1 + sizeofW(StgDouble);
438 Sp[0] = (W_)&stg_gc_d1_info;
443 /* -----------------------------------------------------------------------------
444 Heap checks for unboxed tuple case alternatives
448 - for an unboxed tuple with n components, we rearrange the components
449 with pointers first followed by non-pointers. (NB: not done yet)
451 - The first k components are allocated registers, where k is the
452 number of components that will fit in real registers.
454 - The rest are placed on the stack, with space left for tagging
455 of the non-pointer block if necessary.
457 - On failure of a heap check:
458 - the tag is filled in if necessary,
459 - we load Ri with the address of the continuation,
460 where i is the lowest unused vanilla register.
461 - jump to 'stg_gc_ut_x_y' where x is the number of pointer
462 registers and y the number of non-pointers.
463 - if the required canned sequence isn't available, it will
464 have to be generated at compile-time by the code
465 generator (this will probably happen if there are
466 floating-point values, for instance).
468 For now, just deal with R1, hence R2 contains the sequel address.
469 -------------------------------------------------------------------------- */
471 /*---- R1 contains a pointer: ------ */
473 INFO_TABLE_SRT_BITMAP(stg_gc_ut_1_0_info, stg_gc_ut_1_0_entry, 1/*BITMAP*/,
474 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
475 RET_SMALL,, EF_, 0, 0);
477 EXTFUN(stg_gc_ut_1_0_entry)
482 JMP_(ENTRY_CODE(Sp[-2]));
486 EXTFUN(stg_gc_ut_1_0)
492 Sp[0] = (W_)&stg_gc_ut_1_0_info;
497 /*---- R1 contains a non-pointer: ------ */
499 INFO_TABLE_SRT_BITMAP(stg_gc_ut_0_1_info, stg_gc_ut_0_1_entry, 3/*BITMAP*/,
500 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
501 RET_SMALL,, EF_, 0, 0);
503 EXTFUN(stg_gc_ut_0_1_entry)
508 JMP_(ENTRY_CODE(Sp[-2]));
512 EXTFUN(stg_gc_ut_0_1)
516 Sp[0] = (W_)&stg_gc_ut_0_1_info;
523 /* -----------------------------------------------------------------------------
524 Standard top-level fast-entry heap checks.
526 - we want to make the stack look like it should at the slow entry
527 point for the function. That way we can just push the slow
528 entry point on the stack and return using ThreadRunGHC.
530 - The compiler will generate code to fill in any tags on the stack,
531 in case we arrived directly at the fast entry point and these tags
534 - The rest is hopefully handled by jumping to a canned sequence.
535 We currently have canned sequences for 0-8 pointer registers. If
536 any registers contain non-pointers, we must reduce to an all-pointers
537 situation by pushing as many registers on the stack as necessary.
539 eg. if R1, R2 contain pointers and R3 contains a word, the heap check
540 failure sequence looks like this:
547 after pushing R3, we have pointers in R1 and R2 which corresponds
548 to the 2-pointer canned sequence.
550 -------------------------------------------------------------------------- */
552 /*- 0 Regs -------------------------------------------------------------------*/
563 /*- 1 Reg --------------------------------------------------------------------*/
575 /*- 1 Reg (non-ptr) ----------------------------------------------------------*/
582 Sp[1] = WORD_TAG; /* ToDo: or maybe its an int? */
588 /*- 2 Regs--------------------------------------------------------------------*/
601 /*- 3 Regs -------------------------------------------------------------------*/
615 /*- 4 Regs -------------------------------------------------------------------*/
630 /*- 5 Regs -------------------------------------------------------------------*/
646 /*- 6 Regs -------------------------------------------------------------------*/
663 /*- 7 Regs -------------------------------------------------------------------*/
681 /*- 8 Regs -------------------------------------------------------------------*/
700 /* -----------------------------------------------------------------------------
701 Generic Heap Check Code.
703 Called with Liveness mask in R9, Return address in R10.
704 Stack must be consistent (tagged, and containing all necessary info pointers
707 We also define an stg_gen_yield here, because it's very similar.
708 -------------------------------------------------------------------------- */
710 #if SIZEOF_DOUBLE > SIZEOF_VOID_P
712 #define RESTORE_EVERYTHING \
713 D2 = PK_DBL(Sp+16); \
714 D1 = PK_DBL(Sp+14); \
715 F4 = PK_FLT(Sp+13); \
716 F3 = PK_FLT(Sp+12); \
717 F2 = PK_FLT(Sp+11); \
718 F1 = PK_FLT(Sp+10); \
729 #define RET_OFFSET (-17)
731 #define SAVE_EVERYTHING \
732 ASSIGN_DBL(Sp-2,D2); \
733 ASSIGN_DBL(Sp-4,D1); \
734 ASSIGN_FLT(Sp-5,F4); \
735 ASSIGN_FLT(Sp-6,F3); \
736 ASSIGN_FLT(Sp-7,F2); \
737 ASSIGN_FLT(Sp-8,F1); \
746 Sp[-17] = R10.w; /* return address */ \
747 Sp[-18] = R9.w; /* liveness mask */ \
748 Sp[-19] = (W_)&stg_gen_chk_info; \
753 #define RESTORE_EVERYTHING \
754 D2 = PK_DBL(Sp+15); \
755 D1 = PK_DBL(Sp+14); \
756 F4 = PK_FLT(Sp+13); \
757 F3 = PK_FLT(Sp+12); \
758 F2 = PK_FLT(Sp+11); \
759 F1 = PK_FLT(Sp+10); \
770 #define RET_OFFSET (-15)
772 #define SAVE_EVERYTHING \
773 ASSIGN_DBL(Sp-1,D2); \
774 ASSIGN_DBL(Sp-2,D1); \
775 ASSIGN_FLT(Sp-3,F4); \
776 ASSIGN_FLT(Sp-4,F3); \
777 ASSIGN_FLT(Sp-5,F2); \
778 ASSIGN_FLT(Sp-6,F1); \
787 Sp[-15] = R10.w; /* return address */ \
788 Sp[-16] = R9.w; /* liveness mask */ \
789 Sp[-17] = (W_)&stg_gen_chk_info; \
794 INFO_TABLE_SRT_BITMAP(stg_gen_chk_info, stg_gen_chk_ret, 0,
795 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
796 RET_DYN,, EF_, 0, 0);
798 /* bitmap in the above info table is unused, the real one is on the stack.
805 JMP_(Sp[RET_OFFSET]); /* NO ENTRY_CODE() - this is a direct ret address */
818 * stg_gen_hp is used by MAYBE_GC, where we can't use GC_GENERIC
819 * because we've just failed doYouWantToGC(), not a standard heap
820 * check. GC_GENERIC would end up returning StackOverflow.
830 /* -----------------------------------------------------------------------------
832 -------------------------------------------------------------------------- */
842 FN_(stg_yield_noregs)
846 Sp[0] = (W_)&stg_gc_noregs_ret_info;
851 FN_(stg_yield_to_Hugs)
854 /* No need to save everything - no live registers */
859 /* -----------------------------------------------------------------------------
861 -------------------------------------------------------------------------- */
871 FN_(stg_block_noregs)
875 Sp[0] = (W_)&stg_gc_noregs_ret_info;