mkTopTickyCtrLabel,
mkCAFBlackHoleInfoTableLabel,
- mkSECAFBlackHoleInfoTableLabel,
mkRtsPrimOpLabel,
mkRtsSlowTickyCtrLabel,
mkTopTickyCtrLabel = RtsLabel (RtsData (sLit "top_ct"))
mkCAFBlackHoleInfoTableLabel = RtsLabel (RtsInfo (sLit "stg_CAF_BLACKHOLE"))
-mkSECAFBlackHoleInfoTableLabel = if opt_DoTickyProfiling then
- RtsLabel (RtsInfo (sLit "stg_SE_CAF_BLACKHOLE"))
- else -- RTS won't have info table unless -ticky is on
- panic "mkSECAFBlackHoleInfoTableLabel requires -ticky"
mkRtsPrimOpLabel primop = RtsLabel (RtsPrimOp primop)
moduleRegdLabel = ModuleRegdLabel
-- We keep the address of some commonly-called
-- functions in the register table, to keep code
-- size down:
+ | EagerBlackholeInfo -- stg_EAGER_BLACKHOLE_info
| GCEnter1 -- stg_gc_enter_1
| GCFun -- stg_gc_fun
CurrentNursery -> ptext (sLit "CurrentNursery")
HpAlloc -> ptext (sLit "HpAlloc")
BaseReg -> ptext (sLit "BaseReg")
+ EagerBlackholeInfo -> ptext (sLit "stg_EAGER_BLACKHOLE_info")
GCEnter1 -> ptext (sLit "stg_gc_enter_1")
GCFun -> ptext (sLit "stg_gc_fun")
CurrentTSO -> ptext (sLit "CurrentTSO")
CurrentNursery -> ptext (sLit "CurrentNursery")
HpAlloc -> ptext (sLit "HpAlloc")
+ EagerBlackholeInfo -> ptext (sLit "stg_EAGER_BLACKHOLE_info")
GCEnter1 -> ptext (sLit "stg_gc_enter_1")
GCFun -> ptext (sLit "stg_gc_fun")
BaseReg -> ptext (sLit "BaseReg")
import ListSetOps
import Util
import BasicTypes
+import StaticFlags
+import DynFlags
import Constants
import Outputable
import FastString
blackHoleIt closure_info = emitBlackHoleCode (closureSingleEntry closure_info)
emitBlackHoleCode :: Bool -> Code
-emitBlackHoleCode is_single_entry
- | eager_blackholing = do
- tickyBlackHole (not is_single_entry)
- stmtC (CmmStore (CmmReg nodeReg) (CmmLit (CmmLabel bh_lbl)))
- | otherwise =
- nopC
- where
- bh_lbl | is_single_entry = mkRtsDataLabel (sLit "stg_SE_BLACKHOLE_info")
- | otherwise = mkRtsDataLabel (sLit "stg_BLACKHOLE_info")
+emitBlackHoleCode is_single_entry = do
+
+ dflags <- getDynFlags
-- If we wanted to do eager blackholing with slop filling,
-- we'd need to do it at the *end* of a basic block, otherwise
-- to bring back minimal ticky-ticky, so now EAGER_BLACKHOLING
-- is unconditionally disabled. -- krc 1/2007
- eager_blackholing = False
+ let eager_blackholing = not opt_SccProfilingOn
+ && dopt Opt_EagerBlackHoling dflags
+
+ if eager_blackholing
+ then do
+ tickyBlackHole (not is_single_entry)
+ let bh_info = CmmReg (CmmGlobal EagerBlackholeInfo)
+ stmtC (CmmStore (CmmReg nodeReg) bh_info)
+ else
+ nopC
\end{code}
\begin{code}
; returnFC hp_rel }
where
bh_cl_info :: ClosureInfo
- bh_cl_info | is_upd = cafBlackHoleClosureInfo cl_info
- | otherwise = seCafBlackHoleClosureInfo cl_info
+ bh_cl_info = cafBlackHoleClosureInfo cl_info
ind_static_info :: CmmExpr
ind_static_info = mkLblExpr mkIndStaticInfoLabel
baseRegOffset CurrentTSO = oFFSET_StgRegTable_rCurrentTSO
baseRegOffset CurrentNursery = oFFSET_StgRegTable_rCurrentNursery
baseRegOffset HpAlloc = oFFSET_StgRegTable_rHpAlloc
+baseRegOffset EagerBlackholeInfo = oFFSET_stgEagerBlackholeInfo
baseRegOffset GCEnter1 = oFFSET_stgGCEnter1
baseRegOffset GCFun = oFFSET_stgGCFun
baseRegOffset BaseReg = panic "baseRegOffset:BaseReg"
closureValDescr, closureTypeDescr, -- profiling
isStaticClosure,
- cafBlackHoleClosureInfo, seCafBlackHoleClosureInfo,
+ cafBlackHoleClosureInfo,
staticClosureNeedsLink,
) where
closureType = ty,
closureDescr = "" }
cafBlackHoleClosureInfo _ = panic "cafBlackHoleClosureInfo"
-
-seCafBlackHoleClosureInfo (ClosureInfo { closureName = nm,
- closureType = ty })
- = ClosureInfo { closureName = nm,
- closureLFInfo = LFBlackHole mkSECAFBlackHoleInfoTableLabel,
- closureSMRep = BlackHoleRep,
- closureSRT = NoC_SRT,
- closureType = ty,
- closureDescr = "" }
-seCafBlackHoleClosureInfo _ = panic "seCafBlackHoleClosureInfo"
\end{code}
%************************************************************************
| Opt_DryRun
| Opt_DoAsmMangling
| Opt_ExcessPrecision
+ | Opt_EagerBlackHoling
| Opt_ReadUserPackageConf
| Opt_NoHsMain
| Opt_SplitObjs
( "dicts-cheap", Opt_DictsCheap, const Supported ),
( "inline-if-enough-args", Opt_InlineIfEnoughArgs, const Supported ),
( "excess-precision", Opt_ExcessPrecision, const Supported ),
+ ( "eager-blackholing", Opt_EagerBlackHoling, const Supported ),
( "asm-mangling", Opt_DoAsmMangling, const Supported ),
( "print-bind-result", Opt_PrintBindResult, const Supported ),
( "force-recomp", Opt_ForceRecomp, const Supported ),
-- On powerpc (non-PIC), it's easier to jump directly to a label than
-- to use the register table, so we replace these registers
-- with the corresponding labels:
+ CmmReg (CmmGlobal EagerBlackholeInfo)
+ | not opt_PIC
+ -> cmmExprConFold referenceKind $
+ CmmLit (CmmLabel (mkRtsCodeLabel (sLit "__stg_EAGER_BLACKHOLE_INFO")))
CmmReg (CmmGlobal GCEnter1)
| not opt_PIC
-> cmmExprConFold referenceKind $
#define STOP_FRAME 40
#define CAF_BLACKHOLE 41
#define BLACKHOLE 42
-#define SE_BLACKHOLE 43
-#define SE_CAF_BLACKHOLE 44
-#define MVAR_CLEAN 45
-#define MVAR_DIRTY 46
-#define ARR_WORDS 47
-#define MUT_ARR_PTRS_CLEAN 48
-#define MUT_ARR_PTRS_DIRTY 49
-#define MUT_ARR_PTRS_FROZEN0 50
-#define MUT_ARR_PTRS_FROZEN 51
-#define MUT_VAR_CLEAN 52
-#define MUT_VAR_DIRTY 53
-#define WEAK 54
-#define STABLE_NAME 55
-#define TSO 56
-#define BLOCKED_FETCH 57
-#define FETCH_ME 58
-#define FETCH_ME_BQ 59
-#define RBH 60
-#define REMOTE_REF 62
-#define TVAR_WATCH_QUEUE 63
-#define INVARIANT_CHECK_QUEUE 64
-#define ATOMIC_INVARIANT 65
-#define TVAR 66
-#define TREC_CHUNK 67
-#define TREC_HEADER 68
-#define ATOMICALLY_FRAME 69
-#define CATCH_RETRY_FRAME 70
-#define CATCH_STM_FRAME 71
-#define WHITEHOLE 72
-#define N_CLOSURE_TYPES 73
+#define MVAR_CLEAN 43
+#define MVAR_DIRTY 44
+#define ARR_WORDS 45
+#define MUT_ARR_PTRS_CLEAN 46
+#define MUT_ARR_PTRS_DIRTY 47
+#define MUT_ARR_PTRS_FROZEN0 48
+#define MUT_ARR_PTRS_FROZEN 49
+#define MUT_VAR_CLEAN 50
+#define MUT_VAR_DIRTY 51
+#define WEAK 52
+#define STABLE_NAME 53
+#define TSO 54
+#define BLOCKED_FETCH 55
+#define FETCH_ME 56
+#define FETCH_ME_BQ 57
+#define RBH 58
+#define REMOTE_REF 59
+#define TVAR_WATCH_QUEUE 60
+#define INVARIANT_CHECK_QUEUE 61
+#define ATOMIC_INVARIANT 62
+#define TVAR 63
+#define TREC_CHUNK 64
+#define TREC_HEADER 65
+#define ATOMICALLY_FRAME 66
+#define CATCH_RETRY_FRAME 67
+#define CATCH_STM_FRAME 68
+#define WHITEHOLE 69
+#define N_CLOSURE_TYPES 70
#endif /* CLOSURETYPES_H */
#define REGS_H
typedef struct {
+ StgWord stgEagerBlackholeInfo;
StgFunPtr stgGCEnter1;
StgFunPtr stgGCFun;
} StgFunTable;
#define FunReg ((StgFunTable *)((void *)BaseReg - sizeof(StgFunTable)))
-#define stg_gc_enter_1 (FunReg->stgGCEnter1)
-#define stg_gc_fun (FunReg->stgGCFun)
+#define stg_EAGER_BLACKHOLE_info (FunReg->stgEagerBlackholeInfo)
+#define stg_gc_enter_1 (FunReg->stgGCEnter1)
+#define stg_gc_fun (FunReg->stgGCFun)
/* -----------------------------------------------------------------------------
For any registers which are denoted "caller-saves" by the C calling
#define USING_LIBBFD 1
#endif
-/* Turn lazy blackholing and eager blackholing on/off.
- *
- * Using eager blackholing makes things easier to debug because
- * the blackholes are more predictable - but it's slower and less sexy.
- *
- * For now, do lazy and not eager.
- */
-
-/* TICKY_TICKY needs EAGER_BLACKHOLING to verify no double-entries of
- * single-entry thunks.
- */
-/* #if defined(TICKY_TICKY) || defined(THREADED_RTS) */
-#if defined(TICKY_TICKY)
-# define EAGER_BLACKHOLING
-#else
-# define LAZY_BLACKHOLING
-#endif
-
/* -----------------------------------------------------------------------------
Labels - entry labels & info labels point to the same place in
TABLES_NEXT_TO_CODE, so we only generate the _info label. Jumps
RTS_INFO(stg_CAF_ENTERED_info);
RTS_INFO(stg_WHITEHOLE_info);
RTS_INFO(stg_BLACKHOLE_info);
+RTS_INFO(__stg_EAGER_BLACKHOLE_info);
RTS_INFO(stg_CAF_BLACKHOLE_info);
-#ifdef TICKY_TICKY
-RTS_INFO(stg_SE_BLACKHOLE_info);
-RTS_INFO(stg_SE_CAF_BLACKHOLE_info);
-#endif
#if defined(PAR) || defined(GRAN)
RTS_INFO(stg_RBH_info);
RTS_ENTRY(stg_CAF_ENTERED_entry);
RTS_ENTRY(stg_WHITEHOLE_entry);
RTS_ENTRY(stg_BLACKHOLE_entry);
+RTS_ENTRY(__stg_EAGER_BLACKHOLE_entry);
RTS_ENTRY(stg_CAF_BLACKHOLE_entry);
-#ifdef TICKY_TICKY
-RTS_ENTRY(stg_SE_BLACKHOLE_entry);
-RTS_ENTRY(stg_SE_CAF_BLACKHOLE_entry);
-#endif
#if defined(PAR) || defined(GRAN)
RTS_ENTRY(stg_RBH_entry);
#endif
field_offset(StgRegTable, rmp_result1);
field_offset(StgRegTable, rmp_result2);
+ def_offset("stgEagerBlackholeInfo", FUN_OFFSET(stgEagerBlackholeInfo));
def_offset("stgGCEnter1", FUN_OFFSET(stgGCEnter1));
def_offset("stgGCFun", FUN_OFFSET(stgGCFun));
cap->sparks_pruned = 0;
#endif
+ cap->f.stgEagerBlackholeInfo = (W_)&__stg_EAGER_BLACKHOLE_info;
cap->f.stgGCEnter1 = (F_)__stg_gc_enter_1;
cap->f.stgGCFun = (F_)__stg_gc_fun;
/* STOP_FRAME = */ ( _BTM ),
/* CAF_BLACKHOLE = */ ( _BTM|_NS| _UPT ),
/* BLACKHOLE = */ ( _NS| _UPT ),
-/* SE_BLACKHOLE = */ ( _NS| _UPT ),
-/* SE_CAF_BLACKHOLE = */ ( _NS| _UPT ),
/* MVAR_CLEAN = */ (_HNF| _NS| _MUT|_UPT ),
/* MVAR_DIRTY = */ (_HNF| _NS| _MUT|_UPT ),
/* ARR_WORDS = */ (_HNF| _NS| _UPT ),
/* FETCH_ME = */ (_HNF| _NS| _MUT|_UPT ),
/* FETCH_ME_BQ = */ ( _NS| _MUT|_UPT ),
/* RBH = */ ( _NS| _MUT|_UPT ),
-/* EVACUATED = */ ( 0 ),
/* REMOTE_REF = */ (_HNF| _NS| _UPT ),
/* TVAR_WATCH_QUEUE = */ ( _NS| _MUT|_UPT ),
/* INVARIANT_CHECK_QUEUE= */ ( _NS| _MUT|_UPT ),
/* WHITEHOLE = */ ( 0 )
};
-#if N_CLOSURE_TYPES != 73
+#if N_CLOSURE_TYPES != 70
#error Closure types changed: update ClosureFlags.c!
#endif
break;
case CAF_BLACKHOLE:
- case SE_CAF_BLACKHOLE:
- case SE_BLACKHOLE:
+ case EAGER_BLACKHOLE:
case BLACKHOLE:
/* case BLACKHOLE_BQ: FIXME: case does not exist */
size = sizeW_fromITBL(info);
case FUN_1_1:
case FUN_0_2:
case BLACKHOLE:
- case SE_BLACKHOLE:
case CAF_BLACKHOLE:
- case SE_CAF_BLACKHOLE:
case IND_PERM:
case IND_OLDGEN_PERM:
/*
SymI_HasProto(stable_ptr_table) \
SymI_HasProto(stackOverflow) \
SymI_HasProto(stg_CAF_BLACKHOLE_info) \
+ SymI_HasProto(__stg_EAGER_BLACKHOLE_info) \
SymI_HasProto(awakenBlockedQueue) \
SymI_HasProto(startTimer) \
SymI_HasProto(stg_CHARLIKE_closure) \
debugBelch("BH\n");
break;
- case SE_BLACKHOLE:
- debugBelch("SE_BH\n");
- break;
-
- case SE_CAF_BLACKHOLE:
- debugBelch("SE_CAF_BH\n");
- break;
-
case ARR_WORDS:
{
StgWord i;
"STOP_FRAME",
"CAF_BLACKHOLE",
"BLACKHOLE",
- "SE_BLACKHOLE",
- "SE_CAF_BLACKHOLE",
"MVAR_CLEAN",
"MVAR_DIRTY",
"ARR_WORDS",
"FETCH_ME",
"FETCH_ME_BQ",
"RBH",
- "EVACUATED",
"REMOTE_REF",
"TVAR_WATCH_QUEUE",
"INVARIANT_CHECK_QUEUE",
"ATOMICALLY_FRAME",
"CATCH_RETRY_FRAME",
"CATCH_STM_FRAME",
+ "WHITEHOLE",
"N_CLOSURE_TYPES"
};
#endif
case IND_OLDGEN:
case IND_OLDGEN_PERM:
case CAF_BLACKHOLE:
- case SE_CAF_BLACKHOLE:
- case SE_BLACKHOLE:
case BLACKHOLE:
case FUN_1_0:
case FUN_0_1:
case CONSTR_0_2:
case CAF_BLACKHOLE:
case BLACKHOLE:
- case SE_BLACKHOLE:
- case SE_CAF_BLACKHOLE:
case ARR_WORDS:
*first_child = NULL;
return;
case CONSTR_0_2:
case CAF_BLACKHOLE:
case BLACKHOLE:
- case SE_BLACKHOLE:
- case SE_CAF_BLACKHOLE:
case ARR_WORDS:
// one child (fixed), no SRT
case MUT_VAR_CLEAN:
// blackholes
case CAF_BLACKHOLE:
case BLACKHOLE:
- case SE_BLACKHOLE:
- case SE_CAF_BLACKHOLE:
// indirection
case IND_PERM:
case IND_OLDGEN_PERM:
case IND_PERM:
case IND_OLDGEN:
case IND_OLDGEN_PERM:
-#ifdef TICKY_TICKY
- case SE_BLACKHOLE:
- case SE_CAF_BLACKHOLE:
-#endif
case BLACKHOLE:
case CAF_BLACKHOLE:
case STABLE_NAME:
jump stg_block_blackhole;
}
-#ifdef EAGER_BLACKHOLING
-INFO_TABLE(stg_SE_BLACKHOLE,0,1,SE_BLACKHOLE,"SE_BLACKHOLE","SE_BLACKHOLE")
-{ foreign "C" barf("SE_BLACKHOLE object entered!") never returns; }
+INFO_TABLE(__stg_EAGER_BLACKHOLE,0,1,BLACKHOLE,"EAGER_BLACKHOLE","EAGER_BLACKHOLE")
+{
+ TICK_ENT_BH();
+
+#ifdef THREADED_RTS
+ // foreign "C" debugBelch("BLACKHOLE entry\n");
+#endif
-INFO_TABLE(stg_SE_CAF_BLACKHOLE,0,1,SE_CAF_BLACKHOLE,"SE_CAF_BLACKHOLE","SE_CAF_BLACKHOLE")
-{ foreign "C" barf("SE_CAF_BLACKHOLE object entered!") never returns; }
+ /* Actually this is not necessary because R1 is about to be destroyed. */
+ LDV_ENTER(R1);
+
+#if defined(THREADED_RTS)
+ ACQUIRE_LOCK(sched_mutex "ptr");
+ // released in stg_block_blackhole_finally
#endif
+ /* Put ourselves on the blackhole queue */
+ StgTSO__link(CurrentTSO) = W_[blackhole_queue];
+ W_[blackhole_queue] = CurrentTSO;
+
+ /* jot down why and on what closure we are blocked */
+ StgTSO_why_blocked(CurrentTSO) = BlockedOnBlackHole::I16;
+ StgTSO_block_info(CurrentTSO) = R1;
+
+ jump stg_block_blackhole;
+}
+
/* ----------------------------------------------------------------------------
Whiteholes are used for the "locked" state of a closure (see lockClosure())
------------------------------------------------------------------------- */
}
if (bh->header.info != &stg_CAF_BLACKHOLE_info) {
-#if (!defined(LAZY_BLACKHOLING)) && defined(DEBUG)
- debugBelch("Unexpected lazy BHing required at 0x%04lx\n",(long)bh);
-#endif
// zero out the slop so that the sanity checker can tell
// where the next closure is.
DEBUG_FILL_SLOP(bh);
// We pretend that bh is now dead.
LDV_recordDead_FILL_SLOP_DYNAMIC((StgClosure *)bh);
#endif
-
+ // an EAGER_BLACKHOLE gets turned into a BLACKHOLE here.
#ifdef THREADED_RTS
cur_bh_info = (const StgInfoTable *)
cas((StgVolatilePtr)&bh->header.info,
case MUT_VAR_CLEAN:
case MUT_VAR_DIRTY:
case CAF_BLACKHOLE:
- case SE_CAF_BLACKHOLE:
- case SE_BLACKHOLE:
case BLACKHOLE:
{
StgPtr end;
return;
case CAF_BLACKHOLE:
- case SE_CAF_BLACKHOLE:
- case SE_BLACKHOLE:
case BLACKHOLE:
copyPart(p,q,BLACKHOLE_sizeW(),sizeofW(StgHeader),stp);
return;
case THUNK_0_2:
case THUNK_STATIC:
case CAF_BLACKHOLE:
- case SE_CAF_BLACKHOLE:
- case SE_BLACKHOLE:
case BLACKHOLE:
// not evaluated yet
goto bale_out;
break;
case CAF_BLACKHOLE:
- case SE_CAF_BLACKHOLE:
- case SE_BLACKHOLE:
case BLACKHOLE:
p += BLACKHOLE_sizeW();
break;
}
case CAF_BLACKHOLE:
- case SE_CAF_BLACKHOLE:
- case SE_BLACKHOLE:
case BLACKHOLE:
case ARR_WORDS:
break;
}
case CAF_BLACKHOLE:
- case SE_CAF_BLACKHOLE:
- case SE_BLACKHOLE:
case BLACKHOLE:
break;
text " AP_STACK,",
text " CAF_BLACKHOLE,",
text " BLACKHOLE,",
- text " SE_BLACKHOLE,",
- text " SE_CAF_BLACKHOLE,",
text " THUNK,",
text " THUNK_1_0,",
text " THUNK_0_1,",