X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=rts%2FHeapStackCheck.cmm;h=ba672bf805895b4a872120ae718d5ea97cfb927b;hb=1e31c2960f7a9fc61119237d8a35b0516d6accca;hp=aae28cb77f0ba8ef185776d7a1cd7712ea92adf4;hpb=b1953bbb1ed3cb16497e5447db7487f0c2d9e41a;p=ghc-hetmet.git diff --git a/rts/HeapStackCheck.cmm b/rts/HeapStackCheck.cmm index aae28cb..ba672bf 100644 --- a/rts/HeapStackCheck.cmm +++ b/rts/HeapStackCheck.cmm @@ -12,13 +12,33 @@ #include "Cmm.h" +#ifdef __PIC__ +import pthread_mutex_unlock; +#endif +import EnterCriticalSection; +import LeaveCriticalSection; + /* Stack/Heap Check Failure * ------------------------ * * On discovering that a stack or heap check has failed, we do the following: * - * - If the context_switch flag is set, indicating that there are more - * threads waiting to run, we yield to the scheduler + * - If HpLim==0, indicating that we should context-switch, we yield + * to the scheduler (return ThreadYielding). + * + * Note that we must leave no slop in the heap (this is a requirement + * for LDV profiling, at least), so if we just had a heap-check + * failure, then we must retract Hp by HpAlloc. How do we know + * whether there was a heap-check failure? HpLim might be zero, and + * yet we got here as a result of a stack-check failure. Hence, we + * require that HpAlloc is only non-zero if there was a heap-check + * failure, otherwise it is zero, so we can always safely subtract + * HpAlloc from Hp. + * + * Hence, HpAlloc is zeroed in LOAD_THREAD_STATE(). + * + * - If the context_switch flag is set (the backup plan if setting HpLim + * to 0 didn't trigger a context switch), we yield to the scheduler * (return ThreadYielding). * * - If Hp > HpLim, we've had a heap check failure. This means we've @@ -55,12 +75,17 @@ DEBUG_ONLY(foreign "C" heapCheckFail()); \ if (Hp > HpLim) { \ Hp = Hp - HpAlloc/*in bytes*/; \ + if (HpLim == 0) { \ + R1 = ThreadYielding; \ + goto sched; \ + } \ if (HpAlloc <= BLOCK_SIZE \ && bdescr_link(CurrentNursery) != NULL) { \ + HpAlloc = 0; \ CLOSE_NURSERY(); \ CurrentNursery = bdescr_link(CurrentNursery); \ OPEN_NURSERY(); \ - if (CInt[context_switch] != 0 :: CInt) { \ + if (Capability_context_switch(MyCapability()) != 0 :: CInt) { \ R1 = ThreadYielding; \ goto sched; \ } else { \ @@ -108,7 +133,7 @@ There are canned sequences for 'n' pointer values in registers. -------------------------------------------------------------------------- */ -INFO_TABLE_RET( stg_enter, 1/*framesize*/, 0/*bitmap*/, RET_SMALL) +INFO_TABLE_RET( stg_enter, RET_SMALL, P_ unused) { R1 = Sp(1); Sp_adj(2); @@ -123,296 +148,6 @@ __stg_gc_enter_1 GC_GENERIC } -#if defined(GRAN) -/* - ToDo: merge the block and yield macros, calling something like BLOCK(N) - at the end; -*/ - -/* - Should we actually ever do a yield in such a case?? -- HWL -*/ -gran_yield_0 -{ - SAVE_THREAD_STATE(); - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadYielding; - jump StgReturn; -} - -gran_yield_1 -{ - Sp_adj(-1); - Sp(0) = R1; - SAVE_THREAD_STATE(); - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadYielding; - jump StgReturn; -} - -/*- 2 Regs--------------------------------------------------------------------*/ - -gran_yield_2 -{ - Sp_adj(-2); - Sp(1) = R2; - Sp(0) = R1; - SAVE_THREAD_STATE(); - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadYielding; - jump StgReturn; -} - -/*- 3 Regs -------------------------------------------------------------------*/ - -gran_yield_3 -{ - Sp_adj(-3); - Sp(2) = R3; - Sp(1) = R2; - Sp(0) = R1; - SAVE_THREAD_STATE(); - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadYielding; - jump StgReturn; -} - -/*- 4 Regs -------------------------------------------------------------------*/ - -gran_yield_4 -{ - Sp_adj(-4); - Sp(3) = R4; - Sp(2) = R3; - Sp(1) = R2; - Sp(0) = R1; - SAVE_THREAD_STATE(); - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadYielding; - jump StgReturn; -} - -/*- 5 Regs -------------------------------------------------------------------*/ - -gran_yield_5 -{ - Sp_adj(-5); - Sp(4) = R5; - Sp(3) = R4; - Sp(2) = R3; - Sp(1) = R2; - Sp(0) = R1; - SAVE_THREAD_STATE(); - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadYielding; - jump StgReturn; -} - -/*- 6 Regs -------------------------------------------------------------------*/ - -gran_yield_6 -{ - Sp_adj(-6); - Sp(5) = R6; - Sp(4) = R5; - Sp(3) = R4; - Sp(2) = R3; - Sp(1) = R2; - Sp(0) = R1; - SAVE_THREAD_STATE(); - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadYielding; - jump StgReturn; -} - -/*- 7 Regs -------------------------------------------------------------------*/ - -gran_yield_7 -{ - Sp_adj(-7); - Sp(6) = R7; - Sp(5) = R6; - Sp(4) = R5; - Sp(3) = R4; - Sp(2) = R3; - Sp(1) = R2; - Sp(0) = R1; - SAVE_THREAD_STATE(); - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadYielding; - jump StgReturn; -} - -/*- 8 Regs -------------------------------------------------------------------*/ - -gran_yield_8 -{ - Sp_adj(-8); - Sp(7) = R8; - Sp(6) = R7; - Sp(5) = R6; - Sp(4) = R5; - Sp(3) = R4; - Sp(2) = R3; - Sp(1) = R2; - Sp(0) = R1; - SAVE_THREAD_STATE(); - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadYielding; - jump StgReturn; -} - -// the same routines but with a block rather than a yield - -gran_block_1 -{ - Sp_adj(-1); - Sp(0) = R1; - SAVE_THREAD_STATE(); - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadBlocked; - jump StgReturn; -} - -/*- 2 Regs--------------------------------------------------------------------*/ - -gran_block_2 -{ - Sp_adj(-2); - Sp(1) = R2; - Sp(0) = R1; - SAVE_THREAD_STATE(); - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadBlocked; - jump StgReturn; -} - -/*- 3 Regs -------------------------------------------------------------------*/ - -gran_block_3 -{ - Sp_adj(-3); - Sp(2) = R3; - Sp(1) = R2; - Sp(0) = R1; - SAVE_THREAD_STATE(); - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadBlocked; - jump StgReturn; -} - -/*- 4 Regs -------------------------------------------------------------------*/ - -gran_block_4 -{ - Sp_adj(-4); - Sp(3) = R4; - Sp(2) = R3; - Sp(1) = R2; - Sp(0) = R1; - SAVE_THREAD_STATE(); - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadBlocked; - jump StgReturn; -} - -/*- 5 Regs -------------------------------------------------------------------*/ - -gran_block_5 -{ - Sp_adj(-5); - Sp(4) = R5; - Sp(3) = R4; - Sp(2) = R3; - Sp(1) = R2; - Sp(0) = R1; - SAVE_THREAD_STATE(); - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadBlocked; - jump StgReturn; -} - -/*- 6 Regs -------------------------------------------------------------------*/ - -gran_block_6 -{ - Sp_adj(-6); - Sp(5) = R6; - Sp(4) = R5; - Sp(3) = R4; - Sp(2) = R3; - Sp(1) = R2; - Sp(0) = R1; - SAVE_THREAD_STATE(); - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadBlocked; - jump StgReturn; -} - -/*- 7 Regs -------------------------------------------------------------------*/ - -gran_block_7 -{ - Sp_adj(-7); - Sp(6) = R7; - Sp(5) = R6; - Sp(4) = R5; - Sp(3) = R4; - Sp(2) = R3; - Sp(1) = R2; - Sp(0) = R1; - SAVE_THREAD_STATE(); - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadBlocked; - jump StgReturn; -} - -/*- 8 Regs -------------------------------------------------------------------*/ - -gran_block_8 -{ - Sp_adj(-8); - Sp(7) = R8; - Sp(6) = R7; - Sp(5) = R6; - Sp(4) = R5; - Sp(3) = R4; - Sp(2) = R3; - Sp(1) = R2; - Sp(0) = R1; - SAVE_THREAD_STATE(); - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadBlocked; - jump StgReturn; -} - -#endif - -#if 0 && defined(PAR) - -/* - Similar to stg_block_1 (called via StgMacro BLOCK_NP) but separates the - saving of the thread state from the actual jump via an StgReturn. - We need this separation because we call RTS routines in blocking entry codes - before jumping back into the RTS (see parallel/FetchMe.hc). -*/ - -par_block_1_no_jump -{ - Sp_adj(-1); - Sp(0) = R1; - SAVE_THREAD_STATE(); -} - -par_jump -{ - TSO_what_next(CurrentTSO) = ThreadRunGHC; - R1 = ThreadBlocked; - jump StgReturn; -} - -#endif - /* ----------------------------------------------------------------------------- Heap checks in Primitive case alternatives @@ -430,7 +165,7 @@ stg_gc_noregs /*-- void return ------------------------------------------------------------ */ -INFO_TABLE_RET( stg_gc_void, 0/*framesize*/, 0/*bitmap*/, RET_SMALL) +INFO_TABLE_RET( stg_gc_void, RET_SMALL) { Sp_adj(1); jump %ENTRY_CODE(Sp(0)); @@ -438,7 +173,7 @@ INFO_TABLE_RET( stg_gc_void, 0/*framesize*/, 0/*bitmap*/, RET_SMALL) /*-- R1 is boxed/unpointed -------------------------------------------------- */ -INFO_TABLE_RET( stg_gc_unpt_r1, 1/*framesize*/, 0/*bitmap*/, RET_SMALL) +INFO_TABLE_RET( stg_gc_unpt_r1, RET_SMALL, P_ unused) { R1 = Sp(1); Sp_adj(2); @@ -456,7 +191,7 @@ stg_gc_unpt_r1 /*-- R1 is unboxed -------------------------------------------------- */ /* the 1 is a bitmap - i.e. 1 non-pointer word on the stack. */ -INFO_TABLE_RET( stg_gc_unbx_r1, 1/*framesize*/, 1/*bitmap*/, RET_SMALL ) +INFO_TABLE_RET( stg_gc_unbx_r1, RET_SMALL, W_ unused ) { R1 = Sp(1); Sp_adj(2); @@ -473,7 +208,7 @@ stg_gc_unbx_r1 /*-- F1 contains a float ------------------------------------------------- */ -INFO_TABLE_RET( stg_gc_f1, 1/*framesize*/, 1/*bitmap*/, RET_SMALL ) +INFO_TABLE_RET( stg_gc_f1, RET_SMALL, F_ unused ) { F1 = F_[Sp+WDS(1)]; Sp_adj(2); @@ -490,17 +225,7 @@ stg_gc_f1 /*-- D1 contains a double ------------------------------------------------- */ -/* we support doubles of either 1 or 2 words in size */ - -#if SIZEOF_DOUBLE == SIZEOF_VOID_P -# define DBL_BITMAP 1 -# define DBL_WORDS 1 -#else -# define DBL_BITMAP 3 -# define DBL_WORDS 2 -#endif - -INFO_TABLE_RET( stg_gc_d1, DBL_WORDS/*framesize*/, DBL_BITMAP/*bitmap*/, RET_SMALL ) +INFO_TABLE_RET( stg_gc_d1, RET_SMALL, D_ unused ) { D1 = D_[Sp + WDS(1)]; Sp = Sp + WDS(1) + SIZEOF_StgDouble; @@ -518,17 +243,7 @@ stg_gc_d1 /*-- L1 contains an int64 ------------------------------------------------- */ -/* we support int64s of either 1 or 2 words in size */ - -#if SIZEOF_VOID_P == 8 -# define LLI_BITMAP 1 -# define LLI_WORDS 1 -#else -# define LLI_BITMAP 3 -# define LLI_WORDS 2 -#endif - -INFO_TABLE_RET( stg_gc_l1, LLI_WORDS/*framesize*/, LLI_BITMAP/*bitmap*/, RET_SMALL ) +INFO_TABLE_RET( stg_gc_l1, RET_SMALL, L_ unused ) { L1 = L_[Sp + WDS(1)]; Sp_adj(1) + SIZEOF_StgWord64; @@ -545,7 +260,7 @@ stg_gc_l1 /*-- Unboxed tuple return, one pointer (unregisterised build only) ---------- */ -INFO_TABLE_RET( stg_ut_1_0_unreg, 1/*size*/, 0/*BITMAP*/, RET_SMALL ) +INFO_TABLE_RET( stg_ut_1_0_unreg, RET_SMALL, P_ unused ) { Sp_adj(1); // one ptr is on the stack (Sp(0)) @@ -588,7 +303,7 @@ __stg_gc_fun W_ info; W_ type; - info = %GET_FUN_INFO(R1); + info = %GET_FUN_INFO(UNTAG(R1)); // cache the size type = TO_W_(StgFunInfoExtra_fun_type(info)); @@ -599,7 +314,7 @@ __stg_gc_fun #ifdef TABLES_NEXT_TO_CODE // bitmap field holds an offset size = StgLargeBitmap_size( StgFunInfoExtra_bitmap(info) - + %GET_ENTRY(R1) /* ### */ ); + + %GET_ENTRY(UNTAG(R1)) /* ### */ ); #else size = StgLargeBitmap_size( StgFunInfoExtra_bitmap(info) ); #endif @@ -642,19 +357,19 @@ __stg_gc_fun appropriately. The stack layout is given above. -------------------------------------------------------------------------- */ -INFO_TABLE_RET( stg_gc_fun, 0/*framesize*/, 0/*bitmap*/, RET_FUN ) +INFO_TABLE_RET( stg_gc_fun, RET_FUN ) { R1 = Sp(2); Sp_adj(3); #ifdef NO_ARG_REGS // Minor optimisation: there are no argument registers to load up, // so we can just jump straight to the function's entry point. - jump %GET_ENTRY(R1); + jump %GET_ENTRY(UNTAG(R1)); #else W_ info; W_ type; - info = %GET_FUN_INFO(R1); + info = %GET_FUN_INFO(UNTAG(R1)); type = TO_W_(StgFunInfoExtra_fun_type(info)); if (type == ARG_GEN || type == ARG_GEN_BIG) { jump StgFunInfoExtra_slow_apply(info); @@ -729,7 +444,7 @@ INFO_TABLE_RET( stg_gc_fun, 0/*framesize*/, 0/*bitmap*/, RET_FUN ) Sp(1) = R9; /* liveness mask */ \ Sp(0) = stg_gc_gen_info; -INFO_TABLE_RET( stg_gc_gen, 0/*framesize*/, 0/*bitmap*/, RET_DYN ) +INFO_TABLE_RET( stg_gc_gen, RET_DYN ) /* bitmap in the above info table is unused, the real one is on the stack. */ { RESTORE_EVERYTHING; @@ -830,18 +545,20 @@ stg_block_1 * * -------------------------------------------------------------------------- */ -INFO_TABLE_RET( stg_block_takemvar, 1/*framesize*/, 0/*bitmap*/, RET_SMALL ) +INFO_TABLE_RET( stg_block_takemvar, RET_SMALL, P_ unused ) { R1 = Sp(1); Sp_adj(2); - jump takeMVarzh_fast; + jump stg_takeMVarzh; } // code fragment executed just before we return to the scheduler stg_block_takemvar_finally { #ifdef THREADED_RTS - foreign "C" unlockClosure(R3 "ptr", stg_EMPTY_MVAR_info); + unlockClosure(R3, stg_MVAR_DIRTY_info); +#else + SET_INFO(R3, stg_MVAR_DIRTY_info); #endif jump StgReturn; } @@ -855,19 +572,21 @@ stg_block_takemvar BLOCK_BUT_FIRST(stg_block_takemvar_finally); } -INFO_TABLE_RET( stg_block_putmvar, 2/*framesize*/, 0/*bitmap*/, RET_SMALL ) +INFO_TABLE_RET( stg_block_putmvar, RET_SMALL, P_ unused1, P_ unused2 ) { R2 = Sp(2); R1 = Sp(1); Sp_adj(3); - jump putMVarzh_fast; + jump stg_putMVarzh; } // code fragment executed just before we return to the scheduler stg_block_putmvar_finally { #ifdef THREADED_RTS - foreign "C" unlockClosure(R3 "ptr", stg_FULL_MVAR_info); + unlockClosure(R3, stg_MVAR_DIRTY_info); +#else + SET_INFO(R3, stg_MVAR_DIRTY_info); #endif jump StgReturn; } @@ -889,7 +608,7 @@ stg_block_blackhole_finally // The last thing we do is release sched_lock, which is // preventing other threads from accessing blackhole_queue and // picking up this thread before we are finished with it. - foreign "C" RELEASE_LOCK(sched_mutex "ptr"); + RELEASE_LOCK(sched_mutex "ptr"); #endif jump StgReturn; } @@ -902,19 +621,22 @@ stg_block_blackhole BLOCK_BUT_FIRST(stg_block_blackhole_finally); } -INFO_TABLE_RET( stg_block_throwto, 2/*framesize*/, 0/*bitmap*/, RET_SMALL ) +INFO_TABLE_RET( stg_block_throwto, RET_SMALL, P_ unused, P_ unused ) { R2 = Sp(2); R1 = Sp(1); Sp_adj(3); - jump killThreadzh_fast; + jump stg_killThreadzh; } stg_block_throwto_finally { -#ifdef THREADED_RTS - foreign "C" throwToReleaseTarget (R3 "ptr"); -#endif + // unlock the throwto message, but only if it wasn't already + // unlocked. It may have been unlocked if we revoked the message + // due to an exception being raised during threadPaused(). + if (StgHeader_info(StgTSO_block_info(CurrentTSO)) == stg_WHITEHOLE_info) { + unlockClosure(StgTSO_block_info(CurrentTSO), stg_MSG_THROWTO_info); + } jump StgReturn; } @@ -928,7 +650,7 @@ stg_block_throwto } #ifdef mingw32_HOST_OS -INFO_TABLE_RET( stg_block_async, 0/*framesize*/, 0/*bitmap*/, RET_SMALL ) +INFO_TABLE_RET( stg_block_async, RET_SMALL ) { W_ ares; W_ len, errC; @@ -953,7 +675,7 @@ stg_block_async /* Used by threadDelay implementation; it would be desirable to get rid of * this free()'ing void return continuation. */ -INFO_TABLE_RET( stg_block_async_void, 0/*framesize*/, 0/*bitmap*/, RET_SMALL ) +INFO_TABLE_RET( stg_block_async_void, RET_SMALL ) { W_ ares;