Simon Jakobi pushed to branch wip/sjakobi/mr16259 at Glasgow Haskell Compiler / GHC
Commits:
-
00a089fb
by Simon Jakobi at 2026-07-10T18:23:36+02:00
-
14141caa
by Simon Jakobi at 2026-07-10T18:23:36+02:00
8 changed files:
- compiler/GHC/StgToCmm.hs
- compiler/GHC/StgToCmm/Utils.hs
- rts/RtsMessages.c
- rts/RtsSymbols.c
- rts/StgMiscClosures.cmm
- rts/include/rts/Messages.h
- rts/include/stg/MiscClosures.h
- rts/sm/NonMovingShortcut.c
Changes:
| ... | ... | @@ -382,9 +382,11 @@ cgDataCon mn data_con |
| 382 | 382 | ; tickyReturnOldCon (length arg_reps)
|
| 383 | 383 | -- A taggable (small-family) normal form should never be entered:
|
| 384 | 384 | -- every reference to it carries the constructor's pointer tag, so
|
| 385 | - -- reaching this entry code is an invariant violation. We report it
|
|
| 386 | - -- (aborting under +RTS --fatal-enter-taggable, otherwise warning once)
|
|
| 387 | - -- and then self-return the value tagged with the constructor tag.
|
|
| 385 | + -- reaching this entry code is an invariant violation. We jump to
|
|
| 386 | + -- a shared RTS stub that reports it (aborting under +RTS
|
|
| 387 | + -- --fatal-enter-taggable, otherwise warning once) and self-returns
|
|
| 388 | + -- the value tagged with the constructor tag; sharing the stub keeps
|
|
| 389 | + -- the per-constructor entry code to a single tail-jump.
|
|
| 388 | 390 | -- Larger families have no spare tag, so their values are entered
|
| 389 | 391 | -- as normal and the entry returns them tagged with the
|
| 390 | 392 | -- family-saturating tag.
|
| ... | ... | @@ -392,9 +394,9 @@ cgDataCon mn data_con |
| 392 | 394 | -- LDV profiling relies on it to mark closures as used (ENTER()
|
| 393 | 395 | -- in rts/include/Cmm.h does not shortcut on the tag), so the
|
| 394 | 396 | -- check would fire on every constructor use.
|
| 395 | - ; when (taggable && not (profileIsProfiling profile)) $
|
|
| 396 | - emitCheckEnteredTaggable (showPprUnsafe data_con)
|
|
| 397 | - ; void $ emitReturn
|
|
| 398 | - [cmmOffsetB platform node (fromDynTag (tagForCon platform data_con))]
|
|
| 397 | + ; if taggable && not (profileIsProfiling profile)
|
|
| 398 | + then emitJumpEnteredTaggable node
|
|
| 399 | + else void $ emitReturn
|
|
| 400 | + [cmmOffsetB platform node (fromDynTag (tagForCon platform data_con))]
|
|
| 399 | 401 | }
|
| 400 | 402 | } |
| ... | ... | @@ -10,7 +10,7 @@ |
| 10 | 10 | module GHC.StgToCmm.Utils (
|
| 11 | 11 | emitDataLits, emitRODataLits,
|
| 12 | 12 | emitDataCon,
|
| 13 | - emitRtsCall, emitRtsCallWithResult, emitRtsCallGen, emitCheckEnteredTaggable,
|
|
| 13 | + emitRtsCall, emitRtsCallWithResult, emitRtsCallGen, emitJumpEnteredTaggable,
|
|
| 14 | 14 | emitBarf,
|
| 15 | 15 | assignTemp, newTemp,
|
| 16 | 16 | |
| ... | ... | @@ -193,11 +193,16 @@ emitBarf msg = do |
| 193 | 193 | -- Call from a taggable normal form's entry code (which the pointer-tagging
|
| 194 | 194 | -- invariant makes unreachable). It aborts under +RTS --fatal-enter-taggable and
|
| 195 | 195 | -- otherwise warns once; the entry then self-returns the tagged value.
|
| 196 | -emitCheckEnteredTaggable :: String -> FCode ()
|
|
| 197 | -emitCheckEnteredTaggable con = do
|
|
| 198 | - strLbl <- newStringCLit con
|
|
| 199 | - emitRtsCall rtsUnitId (fsLit "checkEnteredTaggable")
|
|
| 200 | - [(CmmLit strLbl, AddrHint)] False
|
|
| 196 | +-- Tail-jump to the RTS's shared entry code for taggable normal forms
|
|
| 197 | +-- (stg_enteredTaggable in rts/StgMiscClosures.cmm), which reports the
|
|
| 198 | +-- invariant violation and self-returns the value tagged with its
|
|
| 199 | +-- constructor tag (both derived from the info table).
|
|
| 200 | +emitJumpEnteredTaggable :: CmmExpr -> FCode ()
|
|
| 201 | +emitJumpEnteredTaggable node = do
|
|
| 202 | + profile <- getProfile
|
|
| 203 | + updfr_off <- getUpdFrameOff
|
|
| 204 | + let lbl = mkCmmCodeLabel rtsUnitId (fsLit "stg_enteredTaggable")
|
|
| 205 | + emit (mkJump profile NativeNodeCall (CmmLit (CmmLabel lbl)) [node] updfr_off)
|
|
| 201 | 206 | |
| 202 | 207 | emitRtsCall :: UnitId -> FastString -> [(CmmExpr,ForeignHint)] -> Bool -> FCode ()
|
| 203 | 208 | emitRtsCall pkg fun = emitRtsCallGen [] (mkCmmCodeLabel pkg fun) CmmMayReturn
|
| ... | ... | @@ -98,6 +98,16 @@ checkEnteredTaggable(const char *con) |
| 98 | 98 | }
|
| 99 | 99 | }
|
| 100 | 100 | |
| 101 | +// Backing for stg_enteredTaggable (StgMiscClosures.cmm), the shared entry
|
|
| 102 | +// code of taggable normal forms: report the violation and hand back the
|
|
| 103 | +// pointer retagged with its constructor tag so the entry can self-return.
|
|
| 104 | +StgClosure *
|
|
| 105 | +enteredTaggableClosure(StgClosure *p)
|
|
| 106 | +{
|
|
| 107 | + checkEnteredTaggable(GET_CON_DESC(get_con_itbl(p)));
|
|
| 108 | + return tagConstr(p);
|
|
| 109 | +}
|
|
| 110 | + |
|
| 101 | 111 | void
|
| 102 | 112 | _assertFail(const char*filename, unsigned int linenum)
|
| 103 | 113 | {
|
| ... | ... | @@ -542,7 +542,7 @@ extern char **environ; |
| 542 | 542 | SymI_HasProto(barf) \
|
| 543 | 543 | SymI_HasProto(sbarf) \
|
| 544 | 544 | SymI_HasProto(ssbarf) \
|
| 545 | - SymI_HasProto(checkEnteredTaggable) \
|
|
| 545 | + SymI_HasProto(stg_enteredTaggable) \
|
|
| 546 | 546 | SymI_HasProto(tagClosureIfConstr) \
|
| 547 | 547 | SymI_HasProto(startEventLogging) \
|
| 548 | 548 | SymI_HasProto(endEventLogging) \
|
| ... | ... | @@ -103,6 +103,19 @@ INFO_TABLE_RET (stg_restore_cccs_eval, RET_SMALL, W_ info_ptr, W_ cccs) |
| 103 | 103 | jump stg_ap_0_fast(ret);
|
| 104 | 104 | }
|
| 105 | 105 | |
| 106 | +/* Shared entry code for taggable normal forms, which the pointer-tagging
|
|
| 107 | + invariant makes unreachable: every taggable data constructor's entry code
|
|
| 108 | + tail-jumps here (see cgDataCon in GHC.StgToCmm) instead of carrying its own
|
|
| 109 | + report call. Reports the violation (aborting under +RTS
|
|
| 110 | + --fatal-enter-taggable, otherwise warning once) and self-returns the value
|
|
| 111 | + tagged with its constructor tag; name and tag come from the info table. */
|
|
| 112 | +stg_enteredTaggable (P_ node)
|
|
| 113 | +{
|
|
| 114 | + P_ tagged;
|
|
| 115 | + (tagged) = ccall enteredTaggableClosure(node "ptr");
|
|
| 116 | + return (tagged);
|
|
| 117 | +}
|
|
| 118 | + |
|
| 106 | 119 | /* ----------------------------------------------------------------------------
|
| 107 | 120 | Support for the bytecode interpreter.
|
| 108 | 121 | ------------------------------------------------------------------------- */
|
| ... | ... | @@ -49,11 +49,15 @@ void pbarf(const char *fmt, void *p) |
| 49 | 49 | void ssbarf(const char *fmt, const char *s)
|
| 50 | 50 | STG_NORETURN;
|
| 51 | 51 | |
| 52 | -/* Called from a taggable normal form's entry code (which the pointer-tagging
|
|
| 53 | - invariant makes unreachable). Aborts under +RTS --fatal-enter-taggable, otherwise
|
|
| 54 | - warns once and lets the entry self-return the tagged value. */
|
|
| 52 | +/* Report that a taggable normal form was entered (its entry code is
|
|
| 53 | + unreachable under the pointer-tagging invariant). Aborts under +RTS
|
|
| 54 | + --fatal-enter-taggable, otherwise warns once. */
|
|
| 55 | 55 | void checkEnteredTaggable(const char *con);
|
| 56 | 56 | |
| 57 | +/* Backing for stg_enteredTaggable: report the violation and return the
|
|
| 58 | + closure pointer retagged with its constructor tag. */
|
|
| 59 | +StgClosure *enteredTaggableClosure(StgClosure *p);
|
|
| 60 | + |
|
| 57 | 61 | // declared in Rts.h:
|
| 58 | 62 | // extern void _assertFail(const char *filename, unsigned int linenum)
|
| 59 | 63 | // STG_NORETURN;
|
| ... | ... | @@ -477,6 +477,7 @@ RTS_FUN_DECL(stg_raiseIOzh); |
| 477 | 477 | RTS_FUN_DECL(stg_paniczh);
|
| 478 | 478 | RTS_FUN_DECL(stg_keepAlivezh);
|
| 479 | 479 | RTS_FUN_DECL(stg_absentErrorzh);
|
| 480 | +RTS_FUN_DECL(stg_enteredTaggable);
|
|
| 480 | 481 | |
| 481 | 482 | RTS_FUN_DECL(stg_newPromptTagzh);
|
| 482 | 483 | RTS_FUN_DECL(stg_promptzh);
|
| ... | ... | @@ -225,6 +225,15 @@ selectee_changed: |
| 225 | 225 | default:
|
| 226 | 226 | // Found a value, add the current selector to the chain and
|
| 227 | 227 | // update it.
|
| 228 | + // Re-establish the pointer tag for an evaluated constructor,
|
|
| 229 | + // as in eval_thunk_selector (rts/sm/Evac.c): the indirectees
|
|
| 230 | + // and the origin field installed by update_selector_chain
|
|
| 231 | + // must carry the tag.
|
|
| 232 | + ;
|
|
| 233 | + const StgInfoTable *val_info = get_itbl(val);
|
|
| 234 | + if (val_info->type >= CONSTR && val_info->type <= CONSTR_NOCAF) {
|
|
| 235 | + val = TAG_CLOSURE(stg_min(TAG_MASK, 1 + val_info->srt), val);
|
|
| 236 | + }
|
|
| 228 | 237 | p->payload[0] = chain;
|
| 229 | 238 | chain = p;
|
| 230 | 239 | update_selector_chain(chain, origin, p0, val);
|