[Git][ghc/ghc][wip/romes/27461] 35 commits: Eliminate STM_AWOKEN
Hannes Siebenhandl pushed to branch wip/romes/27461 at Glasgow Haskell Compiler / GHC Commits: 4d798b17 by Duncan Coutts at 2026-07-23T17:26:18-04:00 Eliminate STM_AWOKEN It was used as nullary closure for the block_info.closure in the case of a thread being awoken after an STM transaction. However, while it was written, it was never read, so contributed nothing to the behaviour. Furthermore, in the only place it was set (in tryWakeupThread) the why_blocked was immediately overwritten by the NotBlocked status, and the block_info was updated accordingly (by appendToRunQueue). So it didn't even serve a purpose of clarifying an intermediate state, there really was no such intermediate state. Cleaning this up will allow the BlockedOnSTM case to follow the same pattern as the other why_blocked cases that do not use the block_info, and in turn this reduces the number of different categories. - - - - - e1cece79 by Duncan Coutts at 2026-07-23T17:26:18-04:00 Document that eventlog thread stop code ThreadBlocked is no longer used It has not been used since GHC 7.0.x (2011). In 7.2 all the BlockedOn* codes were added, and these were and are used instead of ThreadBlocked. - - - - - 795db115 by Duncan Coutts at 2026-07-23T17:26:18-04:00 Add a proper mapping to eventlog external thread stop status That is the mapping from rts-internal codes, to the coes used in the status field in the eventlog EVENT_STOP_THREAD event. See issue #9003 for what goes wrong when we mess this up. In that ticket, people note that we should really not require the internal tso->why_blocked codes to leak into the external eventlog thread stop codes. The same principle applies to the StgThreadReturnCode. This change properly separates them, and explicitly maps between them using a pair of (compact, constant) tables. These tables are pretty small (with no alignment constraints) and will soon shrink so it seems a sensible tradeoff. We also introduce and use proper EVENT_STOP_THREAD constants in the event log format header. Previously there was not specification in the code for these (only in the docs): the values were encoded into the conversion code. This will allow us to renumber the internal why_blockd codes without breaking the eventlog output. - - - - - 6f1c8efa by Duncan Coutts at 2026-07-23T17:26:18-04:00 Remove unused tso->block_info.wakeup member Presumably it was used once, but not now. - - - - - 740b88a9 by Duncan Coutts at 2026-07-23T17:26:18-04:00 Document StgTSOBlockInfo to say what cases use what members In principle, tso->why_blocked is the tag for the StgTSOBlockInfo union, so we should be able to say for each union member the why_blocked cases that use that member. - - - - - 5b92eae2 by Duncan Coutts at 2026-07-23T17:26:18-04:00 Add a tso->block_info.mvar member and use it in preference to the generic block_info.closure union member, with casts. The plan is that when we know what case we're in (via tso->why_blocked) then we can always access the correct union member, and so we will only need to access block_info.closure for generic cases where we don't know or don't care. - - - - - d931715f by Duncan Coutts at 2026-07-23T17:26:18-04:00 Add a tso->block_info.unused member and use it in preference to the generic block_info.closure union member, with casts. The plan is that when we know what case we're in (via tso->why_blocked) then we can always access the correct union member, and so we will only need to access block_info.closure for generic cases where we don't know or don't care. - - - - - 47e28ebb by Duncan Coutts at 2026-07-23T17:26:18-04:00 Avoid storing to tso->block_info.closure In one case we can use a specific union member (.prev) instead. In several cases the stores were in fact redundant because of subsequent overwrites. In scavengeTSO we replace setting tso->block_info.closure to a valid closure, with an assertion that the block_info.unused is already set to END_TSO_QUEUE which is a valid (static) closure. - - - - - 96e4749d by Duncan Coutts at 2026-07-23T17:26:18-04:00 Renumber the tso->why_blocked constants We can do this now because we have separated the internal values from the external ones used in the eventlog. This lets us put them back into a deliberate order and consolodate some gaps. More importantly, it is a prepation for a slightly more sophisticated encoding. - - - - - 8f62661c by Duncan Coutts at 2026-07-23T17:26:18-04:00 Define constants for the existing stg_threadStatuszh return codes The stg_threadStatuszh reuses the internal tso->why_blocked codes but also extends them with a couple previously magic values. This is awkward since we need to know what those magic values are so we don't accidentally use those values to mean something else. By pulling a definition up to where the why_blocked codes are defined we will be able to avoid mistakenly assining those codes some meaning (or just changing the BlockedThreadComplete, BlockedThreadKilled code if necessary). - - - - - 42c69ae2 by Duncan Coutts at 2026-07-23T17:26:18-04:00 Extend the tso->why_blocked encoding to indicate block_info closures We use some bit tricks to cheaply and generically test if a tso->why_blocked tag implies that the corresponding tso->block_info will contain a non-trivial valid closure (i.e. not just block_info.unused set to END_TSO_QUEUE). In particular we arrange for most why_blocked values to naturally have a distinguishing bit, but for the BlockedOn{Read,Write,Delay} cases, they can come in either non-closure or closure forms. We allow an additional bit to distinguish these cases. The non-closure forms are only from legacy I/O managers: select and win32-legacy. So this extra bit mechanism will be able to be retired once the legacy I/O managers are themselves retired. This means in a few places we need to untag the why_blocked value before inspecting it, but in most places we do not. - - - - - 7c64632b by Duncan Coutts at 2026-07-23T17:26:18-04:00 Use BlockInfoForceNonClosure in the select I/O manager - - - - - 8fd7104a by Duncan Coutts at 2026-07-23T17:26:18-04:00 Use BlockInfoForceNonClosure in the win32-legacy I/O manager for the BlockedOn{Read,Write} since these use the non-heap allocated StgAsyncIOResult. - - - - - e0da603b by Duncan Coutts at 2026-07-23T17:26:18-04:00 Enforce the why_blocked and block_info rules in checkTSO We now check the cases wher IsBlockInfoClosure should hold, the cases that are supposed to use block_info.unused == END_TSO_QUEUE, and which cases are allowed to use BlockInfoForceNonClosure. This partially enforces the use of why_blocked as a tag for the block_info union. We could be stricter and check for the correct expected info table for the closure cases. - - - - - 1dd0f381 by Duncan Coutts at 2026-07-23T17:26:18-04:00 Use IsBlockInfoClosure to simplify several tests In GC and generic traversal we need to know if we should look at the block_info.closure or not. Now we can do just that using a cheap bit test on the why_blocked tag. This fixes issue 26717, where the problem was that some GC modes did not know when to look at block_info.closure, because the poll I/O manager uses a closure for BlockedOn{Read,Write} while the select I/O manager uses a non-closure. Now this information is in the why_blocked tag itself. - - - - - 7a00ffbc by Duncan Coutts at 2026-07-23T17:26:18-04:00 Remove the now-unused scavengeTSOIOManager The GC no longer has to delegate to the I/O manager, since it can use IsBlockInfoClosure to decide things itself. - - - - - 522a481f by Duncan Coutts at 2026-07-23T17:26:18-04:00 Remove duplicate assertion - - - - - 0874d965 by Duncan Coutts at 2026-07-23T17:26:18-04:00 Follow atomic access rules more consistently for tso->why_blocked The rule is this: store block_info *before* why_blocked store why_blocked using store release load why_blocked using load acquire load block_info *after* why_blocked This is a an atomic store release / load acquire pair and (if the reads are in a separate thread to the writes, and the read receives the value stored) then this guarantees a full "happens before" relationship of these stores and loads. In some cases, we do not need a full load acquire, because we don't read the block_info at all and so do not need any ordering. In this case we just need an atomic relaxed load. This was being followed in most places, but not all. If there's good reason in any case that we don't need atomic access, then we should document that in a comment. In the absence of that I think it's easier to follow the rule everywhere. - - - - - 8f0bdbe1 by Duncan Coutts at 2026-07-23T17:26:19-04:00 Add a changelog entry - - - - - 4fdfe757 by Alan Zimmerman at 2026-07-23T17:27:06-04:00 EPA: Keep decls together in ClassDecl Similar to 1718230f4d3d19d8c49c0e5d496cb0fb6f399528 for HsValBindsLR, this commit updates ClassDecl so that it no longer splits out the assorted `LHsDecl GhcPs` until the renamer. It does this by inserting a type family (separate from the classic TTG one) for this. So data TyClDecl ... | ClassDecl { ... tcdDecls :: XClassDecls pass with type instance XClassDecls GhcPs = [LHsDecl GhcPs] type instance XClassDecls GhcRn = ClassDeclX GhcRn type instance XClassDecls GhcTc = ClassDeclX GhcTc data ClassDeclX pass = ClassDeclX { tcdSigs :: [LSig pass], -- ^ Methods' signatures tcdMeths :: LHsBinds pass, -- ^ Default methods tcdATs :: [LFamilyDecl pass], -- ^ Associated types; tcdATDefs :: [LTyFamDefltDecl pass], -- ^ Associated type defaults tcdDocs :: [LDocDecl pass] -- ^ Haddock docs } - - - - - f586c885 by Simon Jakobi at 2026-07-24T18:05:00-04:00 ci: Use shallow submodule clones by default Limit submodule clones to depth one to reduce CI checkout costs. Keep fetching full submodule history for the submodule lint jobs, which inspect commits across a range. Assisted-by: gpt-5.6-sol via Codex CLI - - - - - 306120d2 by Duncan Coutts at 2026-07-24T18:05:43-04:00 Fix flaky test T3994 on FreeBSD On current FreeBSD versions, calling getpgid on a zombie process fails. In T3994, if we're really unlucky with delays and scheduling then we can end up in exactly that situation. Just catch that specific exception and ignore it. It's rare, and not our fault. - - - - - 7b116a0b by Cheng Shao at 2026-07-24T18:06:24-04:00 ci: add missing workaround for docker permissions in lint jobs Some lint jobs use ci-images with default user `ghc`, and the gitlab ci docker executor requires the `sudo chown` workaround to fix workspace directory permission issue. This patch adds the missing workarounds for the lint jobs. Fixes #27554. Co-authored-by: Codex <codex@openai.com> - - - - - 815149f3 by Andrzej Rybczak at 2026-07-25T15:06:43+00:00 Add -Wdefaulted-callstack Adds a new warning, -Wdefaulted-callstack, which warns when an implicit CallStack parameter is defaulted to the empty stack. In particular, this includes call sites where a function with a HasCallStack constraint is called from a definition that does *not* provide one. At such call sites the call stack is cut off and does not include the enclosing definition's callers, which can be a source of surprise if the user wants complete call stacks. Closes #27077. - - - - - f6f2343f by Zubin Duggal at 2026-07-25T17:40:51-04:00 UniqueDFM: alter should preserve insertion order Before it always inserting new elements at the end. This is problematic because instances get inserted into the map with `alterF`, which can change ordering of how instances are printed with `:info` depending on the order in which we consult interfaces I expect `alter id k = id` and `alter (fmap f) k = adjust f k`. Moving keys to the end breaks that (`adjust` already preserves position). Fixes #27532 - - - - - 293da2e1 by Rodrigo Mesquita at 2026-07-27T10:51:23+02:00 loopImports: Don't dup ms_uid in summary imports We were writing the ms_unitid of the mod summary with every single import of that module That complicated the code (as though the UnitId in that list could ever be something else) and also allocates unnecessarily per every mod import. Very slight allocation decrease measured locally in a few tests: (MultiComponentModulesRecomp: -0.06%; MultiComponentModulesRecomp100: -0.05%) Purely a clean up. - - - - - 74dc56a1 by Rodrigo Mesquita at 2026-07-27T10:51:23+02:00 downsweep: make control flow simpler and cache correct This refactor extracts the control flow of downsweep into a single function `dfsBuild`, which takes care of iteratively expanding and traversing all nodes of the in-construction module graph necessary to build a full `ModuleGraph`. There are three levels of caching going on, all of which are necessary to make sure we don't do repeated work (notably, NEVER summarise the same module twice). 1. `dfsBuild` accumulates the final module graph and never revisits the same node of the module graph. Cache is keyed by the final `ModuleGraph`s `NodeKey`s. 2. For Module A in home-unit u1, each import in the list of imports needs to be *found* (call to `findImportedModuleWithIsBoot`): at this point, we only have the `ModuleName` of the import, not the `Module`. This *finding* is somewhat expensive, so we cache it as well (`ImportsCache`). The cache key is the home-unit to which the module belongs~[1], the import package qualifier, and the ModuleName. [1] Different home-units will have different package flags, which means potentially different `Module` resolution for the same `ModuleName`. 3. The most expensive operation we want to avoid is summarising a `Module` into a `ModSummary`, which notably involves parsing the module header from scratch. The third cache, in essence, maps a `Module` to its `ModSummary` (named `ModSummaryCache`). This cache upholds the invariant: we NEVER summarise the same module twice. In practice, the cache key is the Module's UnitId and the Source path; the reason is we need to distinguish between `.hs` and `.hs-boot` files, as their summaries will differ. Note that (2) can't guarantee this alone: Two ModuleName imports in separate units can (and likely do) map to the same `Module`. Note that the previous implementation failed to achieve the no-duplicate-work summarisation invariant, and we ended up doing a quadratic amount of processing in scenarios like test `MultiComponentModules100`. See also Note [Downsweep Control Flow and Caching] Fixes #27461 Perf changes: MultiComponentModules(normal) ghc/alloc 2,097,389,264 1,992,186,736 -5.0% GOOD MultiComponentModules100(normal) ghc/alloc 24,310,173,770 21,293,867,360 -12.4% GOOD MultiComponentModulesRecomp(normal) ghc/alloc 602,761,394 498,543,984 -17.3% GOOD MultiComponentModulesRecomp100(normal) ghc/alloc 11,885,968,240 8,895,404,864 -25.2% GOOD ------------------------- Metric Decrease: MultiComponentModules MultiComponentModules100 MultiComponentModulesRecomp MultiComponentModulesRecomp100 ------------------------- - - - - - 28c819c9 by Rodrigo Mesquita at 2026-07-27T10:51:23+02:00 implicitRequirementsShallow can never reach HoleUnit findImportedModule will never return `HoleUnit` for a `ModuleName` (a `HoleUnit` can only be found as a signature instantiation, never as a directly *imported* thing) Therefore, we can drop `[ModuleName]` returned by `implicitRequirementsShallow`, which makes many things dead code. Namely, the call to `implicitRequirementsShallow` from GHC.Driver.Downsweep which was a performance bottleneck (for doing lots of duplicate work in findImportedModule) is now entirely gone. Fixes #27053 In an MR with this patch and the downsweep refactor (previous commit), CI says: MultiComponentModules(normal) ghc/alloc 2,097,396,728 1,943,662,304 -7.3% GOOD MultiComponentModules100(normal) ghc/alloc 24,310,182,136 17,227,574,440 -29.1% GOOD MultiComponentModulesRecomp(normal) ghc/alloc 602,769,518 449,973,656 -25.3% GOOD MultiComponentModulesRecomp100(normal) ghc/alloc 11,885,976,408 4,828,894,160 -59.4% GOOD and the Cabal test (building Cabal with ghc --make) improves in the total time reported by +RTS -s from 54s to 40s reliably on my machine with default+profiled_ghc flavour. That's a 25% reduction in total run time! ------------------------- Metric Decrease: MultiComponentModules MultiComponentModules100 MultiComponentModulesRecomp MultiComponentModulesRecomp100 ------------------------- - - - - - 35ddb38b by Rodrigo Mesquita at 2026-07-27T10:51:23+02:00 downsweep: Cache negative results When traversing a module graph structure, a uniquely identified node should always expand to the same thing. I don't see how visiting the same node which failed to be expanded a first time would ever successfully expand the second time we try to expand it (eg. when coming from a different edge to it -- it is still the same node!). The node expansion is local, based just based on the node itself, not on the path to get there. Therefore, this patch removes the weird behavior and commentary of `dfsBuild` wrt to `Nothing` not being cached and being potentially expanded a second time around to something different, which was misleading and, ultimately, incorrect. Now, we have a `MGRes`, which is more explicit about a node being Skipped just being a node that is ignored whenever it is found (and that skip is cached) -- and we may want to do this due to failures or due to just trying nodes which might not work on purpose, like hs-boots. We uniformly cache positive and negative results and remove the assumption that there might be an ordering in which the same node visited at a later time might be expanded differently. This makes it possible to traverse the module nodes in parallel without a change in behavior, since there's no longer a hidden ordering requirement. - - - - - 077678ca by Rodrigo Mesquita at 2026-07-27T10:51:23+02:00 Organize and clean-up GHC.Driver.Downsweep Simply some cosmetic changes, moving definitions around to structure the module better into its relevant sections (In go (ns ++ ss), it's not a problem to use ++ because it's a good producer and we won't have to append fully before processing the next item in go) - - - - - 7d089874 by Rodrigo Mesquita at 2026-07-27T10:51:23+02:00 fixup! Organize and clean-up GHC.Driver.Downsweep - - - - - 3ef8d34b by fendor at 2026-07-27T10:51:23+02:00 Fixup: fix note name - - - - - cf7de7aa by fendor at 2026-07-27T10:51:24+02:00 Fixup: changelog - - - - - 52f12516 by fendor at 2026-07-27T10:51:24+02:00 Fixup: remove redundant chagenlog.d entry - - - - - fca7e6e0 by fendor at 2026-07-27T10:51:24+02:00 Fixup: Update note references - - - - - 125 changed files: - .gitlab-ci.yml - + changelog.d/27532 - + changelog.d/T26716 - + changelog.d/downsweep-refactor - + changelog.d/warn-defaulted-callstack - compiler/GHC/Driver/Backpack.hs - compiler/GHC/Driver/Downsweep.hs - compiler/GHC/Driver/Env.hs - compiler/GHC/Driver/Flags.hs - compiler/GHC/Driver/Session.hs - compiler/GHC/Hs/Decls.hs - compiler/GHC/Hs/Instances.hs - compiler/GHC/Hs/Stats.hs - compiler/GHC/Hs/Utils.hs - compiler/GHC/HsToCore/Docs.hs - compiler/GHC/HsToCore/Quote.hs - compiler/GHC/Iface/Ext/Ast.hs - compiler/GHC/Parser/PostProcess.hs - compiler/GHC/Parser/PostProcess/Haddock.hs - compiler/GHC/Rename/Module.hs - compiler/GHC/Tc/Errors/Ppr.hs - compiler/GHC/Tc/Errors/Types.hs - compiler/GHC/Tc/Solver/Default.hs - compiler/GHC/Tc/Solver/Dict.hs - compiler/GHC/Tc/TyCl.hs - compiler/GHC/Tc/TyCl/Class.hs - compiler/GHC/Tc/Types/Evidence.hs - compiler/GHC/Tc/Types/Origin.hs - compiler/GHC/Tc/Utils/Backpack.hs - compiler/GHC/Tc/Utils/Unify.hs - compiler/GHC/ThToHs.hs - compiler/GHC/Types/Error/Codes.hs - compiler/GHC/Types/Unique/DFM.hs - compiler/GHC/Unit/Env.hs - compiler/Language/Haskell/Syntax/Binds.hs - compiler/Language/Haskell/Syntax/Decls.hs - docs/users_guide/eventlog-formats.rst - docs/users_guide/using-warnings.rst - libraries/base/changelog.md - libraries/base/src/GHC/Stack.hs - libraries/ghc-heap/GHC/Exts/Heap/FFIClosures_ProfilingDisabled.hsc - libraries/ghc-heap/GHC/Exts/Heap/FFIClosures_ProfilingEnabled.hsc - libraries/ghc-internal/src/GHC/Internal/Conc/Sync.hs - libraries/ghc-internal/src/GHC/Internal/Stack.hs - rts/IOManager.c - rts/IOManager.h - rts/Messages.c - rts/PrimOps.cmm - rts/RaiseAsync.c - rts/RaiseAsync.h - rts/STM.c - rts/Schedule.c - rts/StgMiscClosures.cmm - rts/Threads.c - rts/Trace.c - rts/Trace.h - rts/TraverseHeap.c - rts/include/Cmm.h - rts/include/rts/Constants.h - rts/include/rts/EventLogFormat.h - rts/include/rts/storage/TSO.h - rts/include/stg/MiscClosures.h - rts/posix/Poll.c - rts/posix/Select.c - rts/posix/Timeout.c - rts/sm/Compact.c - rts/sm/NonMovingMark.c - rts/sm/Sanity.c - rts/sm/Scav.c - rts/win32/AsyncMIO.c - testsuite/tests/ghc-api/fixed-nodes/FixedNodes.hs - testsuite/tests/ghc-api/fixed-nodes/InterfaceModuleGraph.hs - testsuite/tests/ghc-api/fixed-nodes/ModuleGraphInvariants.hs - testsuite/tests/ghci/T16793/T16793.stdout - testsuite/tests/ghci/T18060/T18060.stdout - + testsuite/tests/ghci/T27532/Makefile - + testsuite/tests/ghci/T27532/T27532.stdout - + testsuite/tests/ghci/T27532/T27532j4.stdout - + testsuite/tests/ghci/T27532/a.script - + testsuite/tests/ghci/T27532/all.T - + testsuite/tests/ghci/T27532/b.script - + testsuite/tests/ghci/T27532/genT27532Modules - testsuite/tests/ghci/scripts/ListTuplePunsPpr.stdout - testsuite/tests/ghci/scripts/T4175.stdout - testsuite/tests/ghci/scripts/T8469.stdout - testsuite/tests/ghci/scripts/T8535.stdout - testsuite/tests/ghci/scripts/T9881.stdout - testsuite/tests/ghci/scripts/ghci020.stdout - testsuite/tests/ghci/scripts/ghci064.stdout - testsuite/tests/ghci/should_run/T10145.stdout - testsuite/tests/ghci/should_run/T18594.stdout - testsuite/tests/haddock/haddock_examples/haddock.Test.stderr - testsuite/tests/haddock/should_compile_flag_haddock/T17544.stderr - testsuite/tests/haddock/should_compile_flag_haddock/T17544_kw.stderr - testsuite/tests/interface-stability/base-exports.stdout - testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs - testsuite/tests/interface-stability/base-exports.stdout-mingw32 - testsuite/tests/parser/should_compile/DumpRenamedAst.stderr - testsuite/tests/parser/should_compile/DumpSemis.stderr - testsuite/tests/parser/should_compile/T20452.stderr - testsuite/tests/partial-sigs/should_compile/ExtraConstraints3.stderr - testsuite/tests/printer/Test24533.stdout - testsuite/tests/process/T3994.hs - testsuite/tests/roles/should_compile/Roles14.stderr - testsuite/tests/roles/should_compile/Roles3.stderr - testsuite/tests/roles/should_compile/Roles4.stderr - testsuite/tests/roles/should_compile/T8958.stderr - testsuite/tests/splice-imports/SI35.hs - testsuite/tests/typecheck/should_compile/T18406b.stderr - testsuite/tests/typecheck/should_compile/T18529.stderr - + testsuite/tests/typecheck/should_compile/WarnDefaultedCallStack.hs - + testsuite/tests/typecheck/should_compile/WarnDefaultedCallStack.stderr - testsuite/tests/typecheck/should_compile/all.T - testsuite/tests/typecheck/should_fail/T5300.stderr - utils/check-exact/ExactPrint.hs - utils/check-exact/Utils.hs - utils/check-ppr/Main.hs - utils/haddock/haddock-api/src/Haddock/Backends/Hoogle.hs - utils/haddock/haddock-api/src/Haddock/Backends/LaTeX.hs - utils/haddock/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs - utils/haddock/haddock-api/src/Haddock/Convert.hs - utils/haddock/haddock-api/src/Haddock/GhcUtils.hs - utils/haddock/haddock-api/src/Haddock/Interface/Create.hs - utils/haddock/haddock-api/src/Haddock/Interface/Rename.hs - utils/haddock/haddock-api/src/Haddock/Types.hs The diff was not included because it is too large. View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/88c8b9461d57df7bb892bfc52ce44c2... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/88c8b9461d57df7bb892bfc52ce44c2... You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
participants (1)
-
Hannes Siebenhandl (@fendor)