1 /* -----------------------------------------------------------------------------
2 * $Id: HeapStackCheck.hc,v 1.28 2003/02/21 05:34:15 sof 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 */
20 /* Stack/Heap Check Failure
21 * ------------------------
23 * On discovering that a stack or heap check has failed, we do the following:
25 * - If the context_switch flag is set, indicating that there are more
26 * threads waiting to run, we yield to the scheduler
27 * (return ThreadYielding).
29 * - If Hp > HpLim, we've had a heap check failure. This means we've
30 * come to the end of the current heap block, so we try to chain
31 * another block on with ExtendNursery().
33 * - If this succeeds, we carry on without returning to the
36 * - If it fails, we return to the scheduler claiming HeapOverflow
37 * so that a garbage collection can be performed.
39 * - If Hp <= HpLim, it must have been a stack check that failed. In
40 * which case, we return to the scheduler claiming StackOverflow, the
41 * scheduler will either increase the size of our stack, or flag
42 * an error if the stack is already too big.
44 * The effect of checking for context switch only in the heap/stack check
45 * failure code is that we'll switch threads after the current thread has
46 * reached the end of its heap block. If a thread isn't allocating
47 * at all, it won't yield. Hopefully this won't be a problem in practice.
50 /* Remember that the return address is *removed* when returning to a
51 * ThreadRunGHC thread.
55 DEBUG_ONLY(heapCheckFail()); \
58 if (HpAlloc <= BLOCK_SIZE_W && ExtendNursery(Hp,HpLim)) {\
59 if (context_switch) { \
60 R1.i = ThreadYielding; \
62 JMP_(ENTRY_CODE(Sp[0])); \
65 R1.i = HeapOverflow; \
68 R1.i = StackOverflow; \
71 CurrentTSO->what_next = ThreadRunGHC; \
76 CurrentTSO->what_next = ThreadRunGHC; \
77 R1.i = HeapOverflow; \
80 #define YIELD_GENERIC \
82 CurrentTSO->what_next = ThreadRunGHC; \
83 R1.i = ThreadYielding; \
86 #define YIELD_TO_INTERPRETER \
88 CurrentTSO->what_next = ThreadInterpret; \
89 R1.i = ThreadYielding; \
92 #define BLOCK_GENERIC \
94 CurrentTSO->what_next = ThreadRunGHC; \
95 R1.i = ThreadBlocked; \
98 /* -----------------------------------------------------------------------------
99 Heap checks in thunks/functions.
101 In these cases, node always points to the function closure. This gives
102 us an easy way to return to the function: just leave R1 on the top of
103 the stack, and have the scheduler enter it to return.
105 There are canned sequences for 'n' pointer values in registers.
106 -------------------------------------------------------------------------- */
108 INFO_TABLE_RET( stg_enter_info, stg_enter_ret,
109 MK_SMALL_BITMAP(1/*framesize*/, 0/*bitmap*/),
110 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
111 RET_SMALL,, EF_, 0, 0);
112 EXTFUN(stg_enter_ret)
121 EXTFUN(__stg_gc_enter_1)
126 Sp[0] = (W_)&stg_enter_info;
132 EXTFUN(stg_gc_enter_1_hponly)
139 CurrentTSO->what_next = ThreadRunGHC;
147 ToDo: merge the block and yield macros, calling something like BLOCK(N)
152 Should we actually ever do a yield in such a case?? -- HWL
158 CurrentTSO->what_next = ThreadRunGHC;
159 R1.i = ThreadYielding;
170 CurrentTSO->what_next = ThreadRunGHC;
171 R1.i = ThreadYielding;
176 /*- 2 Regs--------------------------------------------------------------------*/
185 CurrentTSO->what_next = ThreadRunGHC;
186 R1.i = ThreadYielding;
191 /*- 3 Regs -------------------------------------------------------------------*/
201 CurrentTSO->what_next = ThreadRunGHC;
202 R1.i = ThreadYielding;
207 /*- 4 Regs -------------------------------------------------------------------*/
218 CurrentTSO->what_next = ThreadRunGHC;
219 R1.i = ThreadYielding;
224 /*- 5 Regs -------------------------------------------------------------------*/
236 CurrentTSO->what_next = ThreadRunGHC;
237 R1.i = ThreadYielding;
242 /*- 6 Regs -------------------------------------------------------------------*/
255 CurrentTSO->what_next = ThreadRunGHC;
256 R1.i = ThreadYielding;
261 /*- 7 Regs -------------------------------------------------------------------*/
275 CurrentTSO->what_next = ThreadRunGHC;
276 R1.i = ThreadYielding;
281 /*- 8 Regs -------------------------------------------------------------------*/
296 CurrentTSO->what_next = ThreadRunGHC;
297 R1.i = ThreadYielding;
302 // the same routines but with a block rather than a yield
310 CurrentTSO->what_next = ThreadRunGHC;
311 R1.i = ThreadBlocked;
316 /*- 2 Regs--------------------------------------------------------------------*/
325 CurrentTSO->what_next = ThreadRunGHC;
326 R1.i = ThreadBlocked;
331 /*- 3 Regs -------------------------------------------------------------------*/
341 CurrentTSO->what_next = ThreadRunGHC;
342 R1.i = ThreadBlocked;
347 /*- 4 Regs -------------------------------------------------------------------*/
358 CurrentTSO->what_next = ThreadRunGHC;
359 R1.i = ThreadBlocked;
364 /*- 5 Regs -------------------------------------------------------------------*/
376 CurrentTSO->what_next = ThreadRunGHC;
377 R1.i = ThreadBlocked;
382 /*- 6 Regs -------------------------------------------------------------------*/
395 CurrentTSO->what_next = ThreadRunGHC;
396 R1.i = ThreadBlocked;
401 /*- 7 Regs -------------------------------------------------------------------*/
415 CurrentTSO->what_next = ThreadRunGHC;
416 R1.i = ThreadBlocked;
421 /*- 8 Regs -------------------------------------------------------------------*/
436 CurrentTSO->what_next = ThreadRunGHC;
437 R1.i = ThreadBlocked;
444 #if 0 && defined(PAR)
447 Similar to stg_block_1 (called via StgMacro BLOCK_NP) but separates the
448 saving of the thread state from the actual jump via an StgReturn.
449 We need this separation because we call RTS routines in blocking entry codes
450 before jumping back into the RTS (see parallel/FetchMe.hc).
453 EXTFUN(par_block_1_no_jump)
465 CurrentTSO->what_next = ThreadRunGHC;
466 R1.i = ThreadBlocked;
473 /* -----------------------------------------------------------------------------
474 Heap checks in Primitive case alternatives
476 A primitive case alternative is entered with a value either in
477 R1, FloatReg1 or D1 depending on the return convention. All the
478 cases are covered below.
479 -------------------------------------------------------------------------- */
481 /*-- No Registers live ------------------------------------------------------ */
483 EXTFUN(stg_gc_noregs)
490 /*-- void return ------------------------------------------------------------ */
492 INFO_TABLE_RET( stg_gc_void_info, stg_gc_void_ret,
493 MK_SMALL_BITMAP(0/*framesize*/, 0/*bitmap*/),
494 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
495 RET_SMALL,, EF_, 0, 0);
497 EXTFUN(stg_gc_void_ret)
501 JMP_(ENTRY_CODE(Sp[0]));
505 /*-- R1 is boxed/unpointed -------------------------------------------------- */
507 INFO_TABLE_RET( stg_gc_unpt_r1_info, stg_gc_unpt_r1_ret,
508 MK_SMALL_BITMAP(1/*framesize*/, 0/*bitmap*/),
509 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
510 RET_SMALL,, EF_, 0, 0);
512 EXTFUN(stg_gc_unpt_r1_ret)
517 JMP_(ENTRY_CODE(Sp[0]));
521 EXTFUN(stg_gc_unpt_r1)
526 Sp[0] = (W_)&stg_gc_unpt_r1_info;
531 /*-- R1 is unboxed -------------------------------------------------- */
533 INFO_TABLE_RET( stg_gc_unbx_r1_info, stg_gc_unbx_r1_ret,
534 MK_SMALL_BITMAP(1/*framesize*/, 1/*bitmap*/),
535 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
536 RET_SMALL,, EF_, 0, 0);
538 /* the 1 is a bitmap - i.e. 1 non-pointer word on the stack. */
540 EXTFUN(stg_gc_unbx_r1_ret)
545 JMP_(ENTRY_CODE(Sp[0]));
549 EXTFUN(stg_gc_unbx_r1)
554 Sp[0] = (W_)&stg_gc_unbx_r1_info;
559 /*-- F1 contains a float ------------------------------------------------- */
561 INFO_TABLE_RET( stg_gc_f1_info, stg_gc_f1_ret,
562 MK_SMALL_BITMAP(1/*framesize*/, 1/*bitmap*/),
563 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
564 RET_SMALL,, EF_, 0, 0);
566 EXTFUN(stg_gc_f1_ret)
571 JMP_(ENTRY_CODE(Sp[0]));
579 ASSIGN_FLT(Sp+1, F1);
580 Sp[0] = (W_)&stg_gc_f1_info;
585 /*-- D1 contains a double ------------------------------------------------- */
587 /* we support doubles of either 1 or 2 words in size */
589 #if SIZEOF_DOUBLE == SIZEOF_VOID_P
590 # define DBL_BITMAP 1
593 # define DBL_BITMAP 3
597 INFO_TABLE_RET( stg_gc_d1_info, stg_gc_d1_ret,
598 MK_SMALL_BITMAP(DBL_WORDS/*framesize*/, DBL_BITMAP/*bitmap*/),
599 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
600 RET_SMALL,, EF_, 0, 0);
602 EXTFUN(stg_gc_d1_ret)
606 Sp += 1 + sizeofW(StgDouble);
607 JMP_(ENTRY_CODE(Sp[0]));
614 Sp -= 1 + sizeofW(StgDouble);
616 Sp[0] = (W_)&stg_gc_d1_info;
622 /*-- L1 contains an int64 ------------------------------------------------- */
624 /* we support int64s of either 1 or 2 words in size */
626 #if SIZEOF_VOID_P == 8
627 # define LLI_BITMAP 1
630 # define LLI_BITMAP 3
634 INFO_TABLE_RET( stg_gc_l1_info, stg_gc_l1_ret,
635 MK_SMALL_BITMAP(LLI_WORDS/*framesize*/, LLI_BITMAP/*bitmap*/),
636 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
637 RET_SMALL,, EF_, 0, 0);
639 EXTFUN(stg_gc_l1_ret)
643 Sp += 1 + sizeofW(StgWord64);
644 JMP_(ENTRY_CODE(Sp[0]));
651 Sp -= 1 + sizeofW(StgWord64);
652 ASSIGN_Int64(Sp+1,L1);
653 Sp[0] = (W_)&stg_gc_l1_info;
658 /*-- Unboxed tuple return, one pointer (unregisterised build only) ---------- */
660 INFO_TABLE_RET( stg_ut_1_0_unreg_info, stg_ut_1_0_unreg_ret,
661 MK_SMALL_BITMAP(1/*size*/, 0/*BITMAP*/),
662 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
663 RET_SMALL,, EF_, 0, 0);
665 EXTFUN(stg_ut_1_0_unreg_ret)
669 /* one ptr is on the stack (Sp[0]) */
670 JMP_(ENTRY_CODE(Sp[1]));
674 /* -----------------------------------------------------------------------------
675 Generic function entry heap check code.
677 At a function entry point, the arguments are as per the calling convention,
678 i.e. some in regs and some on the stack. There may or may not be
679 a pointer to the function closure in R1 - if there isn't, then the heap
680 check failure code in the function will arrange to load it.
682 The function's argument types are described in its info table, so we
683 can just jump to this bit of generic code to save away all the
684 registers and return to the scheduler.
686 This code arranges the stack like this:
690 +---------------------+
692 +---------------------+
694 +---------------------+
696 +---------------------+
698 The size is the number of words of arguments on the stack, and is cached
699 in the frame in order to simplify stack walking: otherwise the size of
700 this stack frame would have to be calculated by looking at f's info table.
702 -------------------------------------------------------------------------- */
707 StgFunInfoTable *info;
710 info = get_fun_itbl(R1.cl);
713 if (info->fun_type == ARG_GEN) {
714 size = BITMAP_SIZE(info->bitmap);
715 } else if (info->fun_type == ARG_GEN_BIG) {
716 size = ((StgLargeBitmap *)info->bitmap)->size;
718 size = BITMAP_SIZE(stg_arg_bitmaps[info->fun_type]);
722 // we don't have to save any registers away
726 Sp[0] = (W_)&stg_gc_fun_info;
729 if (info->fun_type == ARG_GEN || info->fun_type == ARG_GEN_BIG) {
730 // regs already saved by the heap check code
734 Sp[0] = (W_)&stg_gc_fun_info;
735 DEBUG_ONLY(fprintf(stderr, "stg_fun_gc_gen(ARG_GEN)"););
738 JMP_(stg_stack_save_entries[info->fun_type]);
739 // jumps to stg_gc_noregs after saving stuff
741 #endif // !NO_ARG_REGS
746 /* -----------------------------------------------------------------------------
747 Generic Apply (return point)
749 The dual to stg_fun_gc_gen (above): this fragment returns to the
750 function, passing arguments in the stack and in registers
751 appropriately. The stack layout is given above.
752 -------------------------------------------------------------------------- */
754 INFO_TABLE_RET( stg_gc_fun_info,stg_gc_fun_ret,
755 MK_SMALL_BITMAP(0/*framesize*/, 0/*bitmap*/),
756 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
757 RET_FUN,, EF_, 0, 0);
759 EXTFUN(stg_gc_fun_ret)
765 // there are no argument registers to load up, so we can just jump
766 // straight to the function's entry point.
767 JMP_(GET_ENTRY(R1.cl));
770 StgFunInfoTable *info;
772 info = get_fun_itbl(R1.cl);
773 if (info->fun_type == ARG_GEN || info->fun_type == ARG_GEN_BIG) {
774 // regs already saved by the heap check code
775 DEBUG_ONLY(fprintf(stderr, "stg_gc_fun_ret(ARG_GEN)\n"););
776 JMP_(info->slow_apply);
777 } else if (info->fun_type == ARG_BCO) {
778 // cover this case just to be on the safe side
781 Sp[0] = (W_)&stg_apply_interp_info;
782 JMP_(stg_yield_to_interpreter);
784 JMP_(stg_ap_stack_entries[info->fun_type]);
791 /* -----------------------------------------------------------------------------
792 Generic Heap Check Code.
794 Called with Liveness mask in R9, Return address in R10.
795 Stack must be consistent (containing all necessary info pointers
798 See StgMacros.h for a description of the RET_DYN stack frame.
800 We also define an stg_gen_yield here, because it's very similar.
801 -------------------------------------------------------------------------- */
803 // For simplicity, we assume that SIZEOF_DOUBLE == 2*SIZEOF_VOID_P
804 // on a 64-bit machine, we'll end up wasting a couple of words, but
805 // it's not a big deal.
807 #define RESTORE_EVERYTHING \
808 D2 = PK_DBL(Sp+17); \
809 D1 = PK_DBL(Sp+15); \
810 F4 = PK_FLT(Sp+14); \
811 F3 = PK_FLT(Sp+13); \
812 F2 = PK_FLT(Sp+12); \
813 F1 = PK_FLT(Sp+11); \
824 #define RET_OFFSET (-17)
826 #define SAVE_EVERYTHING \
828 ASSIGN_DBL(Sp+17,D2); \
829 ASSIGN_DBL(Sp+15,D1); \
830 ASSIGN_FLT(Sp+14,F4); \
831 ASSIGN_FLT(Sp+13,F3); \
832 ASSIGN_FLT(Sp+12,F2); \
833 ASSIGN_FLT(Sp+11,F1); \
842 Sp[2] = R10.w; /* return address */ \
843 Sp[1] = R9.w; /* liveness mask */ \
844 Sp[0] = (W_)&stg_gc_gen_info; \
846 INFO_TABLE_RET( stg_gc_gen_info, stg_gc_gen_ret,
848 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
849 RET_DYN,, EF_, 0, 0);
851 /* bitmap in the above info table is unused, the real one is on the stack.
858 JMP_(Sp[RET_OFFSET]); /* No ENTRY_CODE() - this is an actual code ptr */
870 // A heap check at an unboxed tuple return point. The return address
871 // is on the stack, and we can find it by using the offsets given
872 // to us in the liveness mask.
876 R10.w = (W_)ENTRY_CODE(Sp[GET_NONPTRS(R9.w) + GET_PTRS(R9.w)]);
883 * stg_gen_hp is used by MAYBE_GC, where we can't use GC_GENERIC
884 * because we've just failed doYouWantToGC(), not a standard heap
885 * check. GC_GENERIC would end up returning StackOverflow.
895 /* -----------------------------------------------------------------------------
897 -------------------------------------------------------------------------- */
907 FN_(stg_yield_noregs)
914 /* -----------------------------------------------------------------------------
915 Yielding to the interpreter... top of stack says what to do next.
916 -------------------------------------------------------------------------- */
918 FN_(stg_yield_to_interpreter)
921 YIELD_TO_INTERPRETER;
925 /* -----------------------------------------------------------------------------
927 -------------------------------------------------------------------------- */
937 FN_(stg_block_noregs)
949 Sp[0] = (W_)&stg_enter_info;
954 /* -----------------------------------------------------------------------------
955 * takeMVar/putMVar-specific blocks
957 * Stack layout for a thread blocked in takeMVar:
961 * stg_block_takemvar_info
963 * Stack layout for a thread blocked in putMVar:
968 * stg_block_putmvar_info
970 * See PrimOps.hc for a description of the workings of take/putMVar.
972 * -------------------------------------------------------------------------- */
974 INFO_TABLE_RET( stg_block_takemvar_info, stg_block_takemvar_ret,
975 MK_SMALL_BITMAP(1/*framesize*/, 0/*bitmap*/),
976 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
977 RET_SMALL,, IF_, 0, 0);
979 IF_(stg_block_takemvar_ret)
984 JMP_(takeMVarzh_fast);
988 FN_(stg_block_takemvar)
993 Sp[0] = (W_)&stg_block_takemvar_info;
998 INFO_TABLE_RET( stg_block_putmvar_info, stg_block_putmvar_ret,
999 MK_SMALL_BITMAP(2/*framesize*/, 0/*bitmap*/),
1000 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
1001 RET_SMALL,, IF_, 0, 0);
1003 IF_(stg_block_putmvar_ret)
1009 JMP_(putMVarzh_fast);
1013 FN_(stg_block_putmvar)
1019 Sp[0] = (W_)&stg_block_putmvar_info;
1024 #ifdef mingw32_TARGET_OS
1025 INFO_TABLE_RET( stg_block_async_info, stg_block_async_ret,
1026 MK_SMALL_BITMAP(0/*framesize*/, 0/*bitmap*/),
1027 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
1028 RET_SMALL,, IF_, 0, 0);
1030 IF_(stg_block_async_ret)
1032 StgAsyncIOResult* ares;
1035 ares = CurrentTSO->block_info.async_result;
1037 errC = ares->errCode;
1038 CurrentTSO->block_info.async_result = NULL;
1039 STGCALL1(free,ares);
1042 JMP_(ENTRY_CODE(Sp[1]));
1046 FN_(stg_block_async)
1050 Sp[0] = (W_)&stg_block_async_info;