1 /* -----------------------------------------------------------------------------
2 * $Id: HeapStackCheck.hc,v 1.31 2003/05/14 09:13:59 simonmar Exp $
4 * (c) The GHC Team, 1998-2002
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 */
21 #ifdef mingw32_TARGET_OS
25 /* Stack/Heap Check Failure
26 * ------------------------
28 * On discovering that a stack or heap check has failed, we do the following:
30 * - If the context_switch flag is set, indicating that there are more
31 * threads waiting to run, we yield to the scheduler
32 * (return ThreadYielding).
34 * - If Hp > HpLim, we've had a heap check failure. This means we've
35 * come to the end of the current heap block, so we try to chain
36 * another block on with ExtendNursery().
38 * - If this succeeds, we carry on without returning to the
41 * - If it fails, we return to the scheduler claiming HeapOverflow
42 * so that a garbage collection can be performed.
44 * - If Hp <= HpLim, it must have been a stack check that failed. In
45 * which case, we return to the scheduler claiming StackOverflow, the
46 * scheduler will either increase the size of our stack, or flag
47 * an error if the stack is already too big.
49 * The effect of checking for context switch only in the heap/stack check
50 * failure code is that we'll switch threads after the current thread has
51 * reached the end of its heap block. If a thread isn't allocating
52 * at all, it won't yield. Hopefully this won't be a problem in practice.
55 /* Remember that the return address is *removed* when returning to a
56 * ThreadRunGHC thread.
60 DEBUG_ONLY(heapCheckFail()); \
63 if (HpAlloc <= BLOCK_SIZE_W && ExtendNursery(Hp,HpLim)) {\
64 if (context_switch) { \
65 R1.i = ThreadYielding; \
67 JMP_(ENTRY_CODE(Sp[0])); \
70 R1.i = HeapOverflow; \
73 R1.i = StackOverflow; \
76 CurrentTSO->what_next = ThreadRunGHC; \
81 CurrentTSO->what_next = ThreadRunGHC; \
82 R1.i = HeapOverflow; \
85 #define YIELD_GENERIC \
87 CurrentTSO->what_next = ThreadRunGHC; \
88 R1.i = ThreadYielding; \
91 #define YIELD_TO_INTERPRETER \
93 CurrentTSO->what_next = ThreadInterpret; \
94 R1.i = ThreadYielding; \
97 #define BLOCK_GENERIC \
99 CurrentTSO->what_next = ThreadRunGHC; \
100 R1.i = ThreadBlocked; \
103 /* -----------------------------------------------------------------------------
104 Heap checks in thunks/functions.
106 In these cases, node always points to the function closure. This gives
107 us an easy way to return to the function: just leave R1 on the top of
108 the stack, and have the scheduler enter it to return.
110 There are canned sequences for 'n' pointer values in registers.
111 -------------------------------------------------------------------------- */
113 INFO_TABLE_RET( stg_enter_info, stg_enter_ret,
114 MK_SMALL_BITMAP(1/*framesize*/, 0/*bitmap*/),
115 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/,
116 RET_SMALL,, EF_, 0, 0);
117 EXTFUN(stg_enter_ret)
126 EXTFUN(__stg_gc_enter_1)
131 Sp[0] = (W_)&stg_enter_info;
137 EXTFUN(stg_gc_enter_1_hponly)
144 CurrentTSO->what_next = ThreadRunGHC;
152 ToDo: merge the block and yield macros, calling something like BLOCK(N)
157 Should we actually ever do a yield in such a case?? -- HWL
163 CurrentTSO->what_next = ThreadRunGHC;
164 R1.i = ThreadYielding;
175 CurrentTSO->what_next = ThreadRunGHC;
176 R1.i = ThreadYielding;
181 /*- 2 Regs--------------------------------------------------------------------*/
190 CurrentTSO->what_next = ThreadRunGHC;
191 R1.i = ThreadYielding;
196 /*- 3 Regs -------------------------------------------------------------------*/
206 CurrentTSO->what_next = ThreadRunGHC;
207 R1.i = ThreadYielding;
212 /*- 4 Regs -------------------------------------------------------------------*/
223 CurrentTSO->what_next = ThreadRunGHC;
224 R1.i = ThreadYielding;
229 /*- 5 Regs -------------------------------------------------------------------*/
241 CurrentTSO->what_next = ThreadRunGHC;
242 R1.i = ThreadYielding;
247 /*- 6 Regs -------------------------------------------------------------------*/
260 CurrentTSO->what_next = ThreadRunGHC;
261 R1.i = ThreadYielding;
266 /*- 7 Regs -------------------------------------------------------------------*/
280 CurrentTSO->what_next = ThreadRunGHC;
281 R1.i = ThreadYielding;
286 /*- 8 Regs -------------------------------------------------------------------*/
301 CurrentTSO->what_next = ThreadRunGHC;
302 R1.i = ThreadYielding;
307 // the same routines but with a block rather than a yield
315 CurrentTSO->what_next = ThreadRunGHC;
316 R1.i = ThreadBlocked;
321 /*- 2 Regs--------------------------------------------------------------------*/
330 CurrentTSO->what_next = ThreadRunGHC;
331 R1.i = ThreadBlocked;
336 /*- 3 Regs -------------------------------------------------------------------*/
346 CurrentTSO->what_next = ThreadRunGHC;
347 R1.i = ThreadBlocked;
352 /*- 4 Regs -------------------------------------------------------------------*/
363 CurrentTSO->what_next = ThreadRunGHC;
364 R1.i = ThreadBlocked;
369 /*- 5 Regs -------------------------------------------------------------------*/
381 CurrentTSO->what_next = ThreadRunGHC;
382 R1.i = ThreadBlocked;
387 /*- 6 Regs -------------------------------------------------------------------*/
400 CurrentTSO->what_next = ThreadRunGHC;
401 R1.i = ThreadBlocked;
406 /*- 7 Regs -------------------------------------------------------------------*/
420 CurrentTSO->what_next = ThreadRunGHC;
421 R1.i = ThreadBlocked;
426 /*- 8 Regs -------------------------------------------------------------------*/
441 CurrentTSO->what_next = ThreadRunGHC;
442 R1.i = ThreadBlocked;
449 #if 0 && defined(PAR)
452 Similar to stg_block_1 (called via StgMacro BLOCK_NP) but separates the
453 saving of the thread state from the actual jump via an StgReturn.
454 We need this separation because we call RTS routines in blocking entry codes
455 before jumping back into the RTS (see parallel/FetchMe.hc).
458 EXTFUN(par_block_1_no_jump)
470 CurrentTSO->what_next = ThreadRunGHC;
471 R1.i = ThreadBlocked;
478 /* -----------------------------------------------------------------------------
479 Heap checks in Primitive case alternatives
481 A primitive case alternative is entered with a value either in
482 R1, FloatReg1 or D1 depending on the return convention. All the
483 cases are covered below.
484 -------------------------------------------------------------------------- */
486 /*-- No Registers live ------------------------------------------------------ */
488 EXTFUN(stg_gc_noregs)
495 /*-- void return ------------------------------------------------------------ */
497 INFO_TABLE_RET( stg_gc_void_info, stg_gc_void_ret,
498 MK_SMALL_BITMAP(0/*framesize*/, 0/*bitmap*/),
499 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/,
500 RET_SMALL,, EF_, 0, 0);
502 EXTFUN(stg_gc_void_ret)
506 JMP_(ENTRY_CODE(Sp[0]));
510 /*-- R1 is boxed/unpointed -------------------------------------------------- */
512 INFO_TABLE_RET( stg_gc_unpt_r1_info, stg_gc_unpt_r1_ret,
513 MK_SMALL_BITMAP(1/*framesize*/, 0/*bitmap*/),
514 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/,
515 RET_SMALL,, EF_, 0, 0);
517 EXTFUN(stg_gc_unpt_r1_ret)
522 JMP_(ENTRY_CODE(Sp[0]));
526 EXTFUN(stg_gc_unpt_r1)
531 Sp[0] = (W_)&stg_gc_unpt_r1_info;
536 /*-- R1 is unboxed -------------------------------------------------- */
538 INFO_TABLE_RET( stg_gc_unbx_r1_info, stg_gc_unbx_r1_ret,
539 MK_SMALL_BITMAP(1/*framesize*/, 1/*bitmap*/),
540 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/,
541 RET_SMALL,, EF_, 0, 0);
543 /* the 1 is a bitmap - i.e. 1 non-pointer word on the stack. */
545 EXTFUN(stg_gc_unbx_r1_ret)
550 JMP_(ENTRY_CODE(Sp[0]));
554 EXTFUN(stg_gc_unbx_r1)
559 Sp[0] = (W_)&stg_gc_unbx_r1_info;
564 /*-- F1 contains a float ------------------------------------------------- */
566 INFO_TABLE_RET( stg_gc_f1_info, stg_gc_f1_ret,
567 MK_SMALL_BITMAP(1/*framesize*/, 1/*bitmap*/),
568 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/,
569 RET_SMALL,, EF_, 0, 0);
571 EXTFUN(stg_gc_f1_ret)
576 JMP_(ENTRY_CODE(Sp[0]));
584 ASSIGN_FLT(Sp+1, F1);
585 Sp[0] = (W_)&stg_gc_f1_info;
590 /*-- D1 contains a double ------------------------------------------------- */
592 /* we support doubles of either 1 or 2 words in size */
594 #if SIZEOF_DOUBLE == SIZEOF_VOID_P
595 # define DBL_BITMAP 1
598 # define DBL_BITMAP 3
602 INFO_TABLE_RET( stg_gc_d1_info, stg_gc_d1_ret,
603 MK_SMALL_BITMAP(DBL_WORDS/*framesize*/, DBL_BITMAP/*bitmap*/),
604 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/,
605 RET_SMALL,, EF_, 0, 0);
607 EXTFUN(stg_gc_d1_ret)
611 Sp += 1 + sizeofW(StgDouble);
612 JMP_(ENTRY_CODE(Sp[0]));
619 Sp -= 1 + sizeofW(StgDouble);
621 Sp[0] = (W_)&stg_gc_d1_info;
627 /*-- L1 contains an int64 ------------------------------------------------- */
629 /* we support int64s of either 1 or 2 words in size */
631 #if SIZEOF_VOID_P == 8
632 # define LLI_BITMAP 1
635 # define LLI_BITMAP 3
639 INFO_TABLE_RET( stg_gc_l1_info, stg_gc_l1_ret,
640 MK_SMALL_BITMAP(LLI_WORDS/*framesize*/, LLI_BITMAP/*bitmap*/),
641 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/,
642 RET_SMALL,, EF_, 0, 0);
644 EXTFUN(stg_gc_l1_ret)
648 Sp += 1 + sizeofW(StgWord64);
649 JMP_(ENTRY_CODE(Sp[0]));
656 Sp -= 1 + sizeofW(StgWord64);
657 ASSIGN_Int64(Sp+1,L1);
658 Sp[0] = (W_)&stg_gc_l1_info;
663 /*-- Unboxed tuple return, one pointer (unregisterised build only) ---------- */
665 INFO_TABLE_RET( stg_ut_1_0_unreg_info, stg_ut_1_0_unreg_ret,
666 MK_SMALL_BITMAP(1/*size*/, 0/*BITMAP*/),
667 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/,
668 RET_SMALL,, EF_, 0, 0);
670 EXTFUN(stg_ut_1_0_unreg_ret)
674 /* one ptr is on the stack (Sp[0]) */
675 JMP_(ENTRY_CODE(Sp[1]));
679 /* -----------------------------------------------------------------------------
680 Generic function entry heap check code.
682 At a function entry point, the arguments are as per the calling convention,
683 i.e. some in regs and some on the stack. There may or may not be
684 a pointer to the function closure in R1 - if there isn't, then the heap
685 check failure code in the function will arrange to load it.
687 The function's argument types are described in its info table, so we
688 can just jump to this bit of generic code to save away all the
689 registers and return to the scheduler.
691 This code arranges the stack like this:
695 +---------------------+
697 +---------------------+
699 +---------------------+
701 +---------------------+
703 The size is the number of words of arguments on the stack, and is cached
704 in the frame in order to simplify stack walking: otherwise the size of
705 this stack frame would have to be calculated by looking at f's info table.
707 -------------------------------------------------------------------------- */
712 StgFunInfoTable *info;
715 info = get_fun_itbl(R1.cl);
718 if (info->fun_type == ARG_GEN) {
719 size = BITMAP_SIZE(info->bitmap);
720 } else if (info->fun_type == ARG_GEN_BIG) {
721 size = ((StgLargeBitmap *)info->bitmap)->size;
723 size = BITMAP_SIZE(stg_arg_bitmaps[info->fun_type]);
727 // we don't have to save any registers away
731 Sp[0] = (W_)&stg_gc_fun_info;
734 if (info->fun_type == ARG_GEN || info->fun_type == ARG_GEN_BIG) {
735 // regs already saved by the heap check code
739 Sp[0] = (W_)&stg_gc_fun_info;
740 DEBUG_ONLY(fprintf(stderr, "stg_fun_gc_gen(ARG_GEN)"););
743 JMP_(stg_stack_save_entries[info->fun_type]);
744 // jumps to stg_gc_noregs after saving stuff
746 #endif // !NO_ARG_REGS
751 /* -----------------------------------------------------------------------------
752 Generic Apply (return point)
754 The dual to stg_fun_gc_gen (above): this fragment returns to the
755 function, passing arguments in the stack and in registers
756 appropriately. The stack layout is given above.
757 -------------------------------------------------------------------------- */
759 INFO_TABLE_RET( stg_gc_fun_info,stg_gc_fun_ret,
760 MK_SMALL_BITMAP(0/*framesize*/, 0/*bitmap*/),
761 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/,
762 RET_FUN,, EF_, 0, 0);
764 EXTFUN(stg_gc_fun_ret)
770 // there are no argument registers to load up, so we can just jump
771 // straight to the function's entry point.
772 JMP_(GET_ENTRY(R1.cl));
775 StgFunInfoTable *info;
777 info = get_fun_itbl(R1.cl);
778 if (info->fun_type == ARG_GEN || info->fun_type == ARG_GEN_BIG) {
779 // regs already saved by the heap check code
780 DEBUG_ONLY(fprintf(stderr, "stg_gc_fun_ret(ARG_GEN)\n"););
781 JMP_(info->slow_apply);
782 } else if (info->fun_type == ARG_BCO) {
783 // cover this case just to be on the safe side
786 Sp[0] = (W_)&stg_apply_interp_info;
787 JMP_(stg_yield_to_interpreter);
789 JMP_(stg_ap_stack_entries[info->fun_type]);
796 /* -----------------------------------------------------------------------------
797 Generic Heap Check Code.
799 Called with Liveness mask in R9, Return address in R10.
800 Stack must be consistent (containing all necessary info pointers
803 See StgMacros.h for a description of the RET_DYN stack frame.
805 We also define an stg_gen_yield here, because it's very similar.
806 -------------------------------------------------------------------------- */
808 // For simplicity, we assume that SIZEOF_DOUBLE == 2*SIZEOF_VOID_P
809 // on a 64-bit machine, we'll end up wasting a couple of words, but
810 // it's not a big deal.
812 #define RESTORE_EVERYTHING \
813 L1 = PK_Word64(Sp+19); \
814 D2 = PK_DBL(Sp+17); \
815 D1 = PK_DBL(Sp+15); \
816 F4 = PK_FLT(Sp+14); \
817 F3 = PK_FLT(Sp+13); \
818 F2 = PK_FLT(Sp+12); \
819 F1 = PK_FLT(Sp+11); \
830 #define RET_OFFSET (-19)
832 #define SAVE_EVERYTHING \
834 ASSIGN_Word64(Sp+19,L1); \
835 ASSIGN_DBL(Sp+17,D2); \
836 ASSIGN_DBL(Sp+15,D1); \
837 ASSIGN_FLT(Sp+14,F4); \
838 ASSIGN_FLT(Sp+13,F3); \
839 ASSIGN_FLT(Sp+12,F2); \
840 ASSIGN_FLT(Sp+11,F1); \
849 Sp[2] = R10.w; /* return address */ \
850 Sp[1] = R9.w; /* liveness mask */ \
851 Sp[0] = (W_)&stg_gc_gen_info; \
853 INFO_TABLE_RET( stg_gc_gen_info, stg_gc_gen_ret,
855 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/,
856 RET_DYN,, EF_, 0, 0);
858 /* bitmap in the above info table is unused, the real one is on the stack.
865 JMP_(Sp[RET_OFFSET]); /* No ENTRY_CODE() - this is an actual code ptr */
877 // A heap check at an unboxed tuple return point. The return address
878 // is on the stack, and we can find it by using the offsets given
879 // to us in the liveness mask.
883 R10.w = (W_)ENTRY_CODE(Sp[GET_NONPTRS(R9.w) + GET_PTRS(R9.w)]);
890 * stg_gen_hp is used by MAYBE_GC, where we can't use GC_GENERIC
891 * because we've just failed doYouWantToGC(), not a standard heap
892 * check. GC_GENERIC would end up returning StackOverflow.
902 /* -----------------------------------------------------------------------------
904 -------------------------------------------------------------------------- */
914 FN_(stg_yield_noregs)
921 /* -----------------------------------------------------------------------------
922 Yielding to the interpreter... top of stack says what to do next.
923 -------------------------------------------------------------------------- */
925 FN_(stg_yield_to_interpreter)
928 YIELD_TO_INTERPRETER;
932 /* -----------------------------------------------------------------------------
934 -------------------------------------------------------------------------- */
944 FN_(stg_block_noregs)
956 Sp[0] = (W_)&stg_enter_info;
961 /* -----------------------------------------------------------------------------
962 * takeMVar/putMVar-specific blocks
964 * Stack layout for a thread blocked in takeMVar:
968 * stg_block_takemvar_info
970 * Stack layout for a thread blocked in putMVar:
975 * stg_block_putmvar_info
977 * See PrimOps.hc for a description of the workings of take/putMVar.
979 * -------------------------------------------------------------------------- */
981 INFO_TABLE_RET( stg_block_takemvar_info, stg_block_takemvar_ret,
982 MK_SMALL_BITMAP(1/*framesize*/, 0/*bitmap*/),
983 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/,
984 RET_SMALL,, IF_, 0, 0);
986 IF_(stg_block_takemvar_ret)
991 JMP_(takeMVarzh_fast);
995 FN_(stg_block_takemvar)
1000 Sp[0] = (W_)&stg_block_takemvar_info;
1005 INFO_TABLE_RET( stg_block_putmvar_info, stg_block_putmvar_ret,
1006 MK_SMALL_BITMAP(2/*framesize*/, 0/*bitmap*/),
1007 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/,
1008 RET_SMALL,, IF_, 0, 0);
1010 IF_(stg_block_putmvar_ret)
1016 JMP_(putMVarzh_fast);
1020 FN_(stg_block_putmvar)
1026 Sp[0] = (W_)&stg_block_putmvar_info;
1031 #ifdef mingw32_TARGET_OS
1032 INFO_TABLE_RET( stg_block_async_info, stg_block_async_ret,
1033 MK_SMALL_BITMAP(0/*framesize*/, 0/*bitmap*/),
1034 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/,
1035 RET_SMALL,, IF_, 0, 0);
1037 IF_(stg_block_async_ret)
1039 StgAsyncIOResult* ares;
1042 ares = CurrentTSO->block_info.async_result;
1044 errC = ares->errCode;
1045 CurrentTSO->block_info.async_result = NULL;
1046 STGCALL1(free,ares);
1049 JMP_(ENTRY_CODE(Sp[1]));
1053 FN_(stg_block_async)
1057 Sp[0] = (W_)&stg_block_async_info;