#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
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 { \
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);
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
/*-- 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));
/*-- 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);
/*-- 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);
/*-- 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);
/*-- 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;
/*-- 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;
/*-- 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))
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));
#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
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);
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;
*
* -------------------------------------------------------------------------- */
-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
- unlockClosure(R3, stg_EMPTY_MVAR_info);
+ unlockClosure(R3, stg_MVAR_DIRTY_info);
+#else
+ SET_INFO(R3, stg_MVAR_DIRTY_info);
#endif
jump StgReturn;
}
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
- unlockClosure(R3, stg_FULL_MVAR_info);
+ unlockClosure(R3, stg_MVAR_DIRTY_info);
+#else
+ SET_INFO(R3, stg_MVAR_DIRTY_info);
#endif
jump StgReturn;
}
// 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;
}
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 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;
/* 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;