X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=rts%2FHeapStackCheck.cmm;h=a1b6d65f34f6e611b67bb1cbd05dcba0683e041a;hb=c681514ad6151534062ff61c96a71e1c299977cc;hp=3c66e7806f853d517ce3238367ee13a4a7e73282;hpb=6015a94f9108a502150565577b66c23650796639;p=ghc-hetmet.git diff --git a/rts/HeapStackCheck.cmm b/rts/HeapStackCheck.cmm index 3c66e78..a1b6d65 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, RET_SMALL, "ptr" W_ unused) +INFO_TABLE_RET( stg_enter, RET_SMALL, P_ unused) { R1 = Sp(1); Sp_adj(2); @@ -438,7 +463,7 @@ INFO_TABLE_RET( stg_gc_void, RET_SMALL) /*-- R1 is boxed/unpointed -------------------------------------------------- */ -INFO_TABLE_RET( stg_gc_unpt_r1, RET_SMALL, "ptr" W_ unused) +INFO_TABLE_RET( stg_gc_unpt_r1, RET_SMALL, P_ unused) { R1 = Sp(1); Sp_adj(2); @@ -525,7 +550,7 @@ stg_gc_l1 /*-- Unboxed tuple return, one pointer (unregisterised build only) ---------- */ -INFO_TABLE_RET( stg_ut_1_0_unreg, RET_SMALL, "ptr" W_ unused ) +INFO_TABLE_RET( stg_ut_1_0_unreg, RET_SMALL, P_ unused ) { Sp_adj(1); // one ptr is on the stack (Sp(0)) @@ -551,8 +576,6 @@ INFO_TABLE_RET( stg_ut_1_0_unreg, RET_SMALL, "ptr" W_ unused ) +---------------------+ | f_closure | +---------------------+ - | tag | - +- - - - - - - - - - -+ | size | +---------------------+ | stg_gc_fun_info | @@ -569,10 +592,7 @@ __stg_gc_fun W_ size; W_ info; W_ type; - W_ tag; - W_ ret_fun; - tag = GETTAG(R1); info = %GET_FUN_INFO(UNTAG(R1)); // cache the size @@ -596,11 +616,9 @@ __stg_gc_fun #ifdef NO_ARG_REGS // we don't have to save any registers away Sp_adj(-3); + Sp(2) = R1; + Sp(1) = size; Sp(0) = stg_gc_fun_info; - ret_fun = Sp; - StgRetFun_size(ret_fun) = HALF_W_(size); - StgRetFun_tag(ret_fun) = HALF_W_(tag); - StgRetFun_fun(ret_fun) = R1; GC_GENERIC #else W_ type; @@ -609,11 +627,9 @@ __stg_gc_fun if (type == ARG_GEN || type == ARG_GEN_BIG) { // regs already saved by the heap check code Sp_adj(-3); + Sp(2) = R1; + Sp(1) = size; Sp(0) = stg_gc_fun_info; - ret_fun = Sp; - StgRetFun_size(ret_fun) = HALF_W_(size); - StgRetFun_tag(ret_fun) = HALF_W_(tag); - StgRetFun_fun(ret_fun) = R1; // DEBUG_ONLY(foreign "C" debugBelch("stg_fun_gc_gen(ARG_GEN)");); GC_GENERIC } else { @@ -633,12 +649,7 @@ __stg_gc_fun INFO_TABLE_RET( stg_gc_fun, RET_FUN ) { - // Grab the fun, but remember to add in the tag. The GC doesn't - // guarantee to retain the tag on the pointer, so we have to do - // it manually, because the function entry code assumes it. - W_ ret_fun; - ret_fun = Sp; - R1 = StgRetFun_fun(ret_fun) | TO_W_(StgRetFun_tag(ret_fun)); + R1 = Sp(2); Sp_adj(3); #ifdef NO_ARG_REGS // Minor optimisation: there are no argument registers to load up, @@ -824,7 +835,7 @@ stg_block_1 * * -------------------------------------------------------------------------- */ -INFO_TABLE_RET( stg_block_takemvar, RET_SMALL, "ptr" W_ unused ) +INFO_TABLE_RET( stg_block_takemvar, RET_SMALL, P_ unused ) { R1 = Sp(1); Sp_adj(2); @@ -835,7 +846,9 @@ INFO_TABLE_RET( stg_block_takemvar, RET_SMALL, "ptr" W_ unused ) stg_block_takemvar_finally { #ifdef THREADED_RTS - unlockClosure(R3, stg_EMPTY_MVAR_info); + unlockClosure(R3, stg_MVAR_DIRTY_info); +#else + SET_INFO(R3, stg_MVAR_DIRTY_info); #endif jump StgReturn; } @@ -849,7 +862,7 @@ stg_block_takemvar BLOCK_BUT_FIRST(stg_block_takemvar_finally); } -INFO_TABLE_RET( stg_block_putmvar, RET_SMALL, "ptr" W_ unused1, "ptr" W_ unused2 ) +INFO_TABLE_RET( stg_block_putmvar, RET_SMALL, P_ unused1, P_ unused2 ) { R2 = Sp(2); R1 = Sp(1); @@ -861,7 +874,9 @@ INFO_TABLE_RET( stg_block_putmvar, RET_SMALL, "ptr" W_ unused1, "ptr" W_ unused2 stg_block_putmvar_finally { #ifdef THREADED_RTS - unlockClosure(R3, stg_FULL_MVAR_info); + unlockClosure(R3, stg_MVAR_DIRTY_info); +#else + SET_INFO(R3, stg_MVAR_DIRTY_info); #endif jump StgReturn; } @@ -883,7 +898,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; } @@ -896,7 +911,7 @@ stg_block_blackhole BLOCK_BUT_FIRST(stg_block_blackhole_finally); } -INFO_TABLE_RET( stg_block_throwto, RET_SMALL, "ptr" W_ unused, "ptr" W_ unused ) +INFO_TABLE_RET( stg_block_throwto, RET_SMALL, P_ unused, P_ unused ) { R2 = Sp(2); R1 = Sp(1);