Stg rewriter should create updatable closures
In !9874 (comment 518337) we noticed that the rewriteRhs
function is creating ReEntrant
closures, see the last line of this case:
rewriteRhs (_id, _tagSig) (StgRhsCon ccs con cn ticks args typ) = {-# SCC rewriteRhs_ #-} do
-- pprTraceM "rewriteRhs" (ppr _id)
-- Look up the nodes representing the constructor arguments.
fieldInfos <- mapM isArgTagged args
-- Filter out non-strict fields.
let strictFields =
getStrictConArgs con (zip args fieldInfos) :: [(StgArg,Bool)] -- (nth-argument, tagInfo)
-- Filter out already tagged arguments.
let needsEval = map fst . --get the actual argument
filter (not . snd) $ -- Keep untagged (False) elements.
strictFields :: [StgArg]
let evalArgs = [v | StgVarArg v <- needsEval] :: [Id]
if (null evalArgs)
then return $! (StgRhsCon ccs con cn ticks args typ)
else do
--assert not (isTaggedSig tagSig)
-- pprTraceM "CreatingSeqs for " $ ppr _id <+> ppr node_id
-- At this point iff we have possibly untagged arguments to strict fields
-- we convert the RHS into a RhsClosure which will evaluate the arguments
-- before allocating the constructor.
let ty_stub = panic "mkSeqs shouldn't use the type arg"
conExpr <- mkSeqs args evalArgs (\taggedArgs -> StgConApp con cn taggedArgs ty_stub)
fvs <- fvArgs args
-- lcls <- getFVs
-- pprTraceM "RhsClosureConversion" (ppr (StgRhsClosure fvs ccs ReEntrant [] $! conExpr) $$ text "lcls:" <> ppr lcls)
return $! (StgRhsClosure fvs ccs ReEntrant [] $! conExpr) typ
This means that all allocations from conExpr
could be repeated many times, which is especially painful if conExpr
is an infinite recursive data type. See for an example: !9874 (comment 517869).
If instead we mark this Updatable
then the allocations in conExpr
will only be performed once.
It would be nice to find a minimal reproducer for this to add to the test suite, but this rewriteRhs
function is only run in some very specific situations which are hard to reproduce.