[Git][ghc/ghc][wip/T26930] 31 commits: Correct `hIsReadable` and `hIsWritable` for duplex handles
by Teo Camarasu (@teo) 10 Mar '26
by Teo Camarasu (@teo) 10 Mar '26
10 Mar '26
Teo Camarasu pushed to branch wip/T26930 at Glasgow Haskell Compiler / GHC
Commits:
598db847 by Wolfgang Jeltsch at 2026-03-06T06:25:25-05:00
Correct `hIsReadable` and `hIsWritable` for duplex handles
This contribution implements CLC proposal #371. It changes `hIsReadable`
and `hIsWritable` such that they always throw a respective exception
when encountering a closed or semi-closed handle, not just in the case
of a file handle.
- - - - -
b90201e5 by Wolfgang Jeltsch at 2026-03-06T06:25:25-05:00
Document `SemiClosedHandle`
- - - - -
c9df72b5 by Wolfgang Jeltsch at 2026-03-06T06:25:25-05:00
Tell users what “semi-closed” means for duplex handles
- - - - -
a8aa1868 by Ilias Tsitsimpis at 2026-03-06T06:26:29-05:00
Fix determinism of linker arguments
The switch from Data.Map to UniqMap in 3b5be05ac29 introduced
non-determinism in the order of packages passed to the linker.
This resulted in non-reproducible builds where the DT_NEEDED entries in
dynamic libraries were ordered differently across builds.
Fix the regression by explicitly sorting the package list derived from
UniqMap.
Fixes #26838
- - - - -
9b64ad3a by Matthew Pickering at 2026-03-06T06:27:16-05:00
determinism: Use a deterministic renaming when writing bytecode files
Now when writing the bytecode file, a counter and substitution are used
to provide deterministic keys to local variables (rather than relying on
uniques). This change ensures that `.gbc` are produced
deterministically.
Fixes #26499
- - - - -
d29800e0 by Teo Camarasu at 2026-03-06T06:28:46-05:00
ghc-internal: delete Version hs-boot loop
Version has a Read instance which needs Unicode but part of the Unicode interface is the unicode version. This is easy to resolve. We simply don't re-export the version from the Unicode module.
Resolves #26940
- - - - -
ad25af90 by Sylvain Henry at 2026-03-06T06:30:33-05:00
Linker: implement support for COMMON symbols (#6107)
Add some support for COMMON symbols. We don't support common symbols
having different sizes where the larger one is allocated after the
smaller one. The linker will fail with an appropriate error message if
it happens.
- - - - -
3b59f158 by Cheng Shao at 2026-03-06T06:31:16-05:00
compiler: fix redundant import of GHC.Hs.Lit
This patch removes a redundant import of `GHC.Hs.Lit` which causes a
ghc build failure with validate flavours when bootstrapping from 9.14.
Fixes #26972.
- - - - -
148d36f3 by Cheng Shao at 2026-03-06T06:32:01-05:00
compiler: avoid unneeded traversals in GHC.Unit.State
Following !15591, this patch avoids unneeded traversals in
`reportCycles`/`reportUnusable` when log verbosity is below given
threshold. Also applies `logVerbAtLeast` when appropriate.
Co-authored-by: Codex <codex(a)openai.com>
- - - - -
7e31367c by Cheng Shao at 2026-03-06T06:32:46-05:00
ghc-internal: fix redundant import in GHC.Internal.Event.Windows.ManagedThreadPool
This patch fixes redundant import in
`GHC.Internal.Event.Windows.ManagedThreadPool` that causes a
compilation error when building windows target with validate flavours
and bootstrapping from 9.14. Fixes #26976.
- - - - -
fc8b8e27 by sheaf at 2026-03-06T06:33:28-05:00
System.Info.fullCompilerVersion: add 'since' annot
Fixes #26973
- - - - -
c8238375 by Sylvain Henry at 2026-03-06T06:34:23-05:00
Hadrian: deprecate --bignum and automatically enable +native_bignum for JS
Deprecate --bignum=... to select the bignum backend. It's only used to
select the native backend, and this can be done with the +native_bignum
flavour transformer.
Additionally, we automatically enable +native_bignum for the JS target
because the GMP backend isn't supported.
- - - - -
a3ac7074 by Sylvain Henry at 2026-03-06T06:35:17-05:00
JS: fix putEnum/fromEnum (#24593)
Don't go through Word16 when serializing Enums.
- - - - -
0b36e96c by Andreas Klebinger at 2026-03-06T06:35:58-05:00
Docs: Document -fworker-wrapper-cbv default setting.
Fixes #26841
- - - - -
eca445e7 by mangoiv at 2026-03-07T05:02:36-05:00
drop deb9/10 from CI, add deb13
debian 9 and 10 are end of life, hence we drop them
from our CI, but we do add debian 13. Jobs that were
previously run on 9 and 10 run on 13, too, jobs that
were run on 10, are run on 11 now. Jobs that were
previously run on debian 12 are run on debian 13 now.
This MR also updates hadrian's bootstrap plans for that
reason.
Metric Decrease:
T9872d
- - - - -
12f8b829 by Luite Stegeman at 2026-03-07T05:03:33-05:00
Fix GHC.Internal.Prim haddock
Haddock used to parse Haskell source to generate documentation,
but switched to using interface files instead. This broke documentation
of the GHC.Internal.Prim module, since it's a wired-in interface that
didn't provide a document structure.
This patch adds the missing document structure and updates genprimopcode
to make the section headers and descriptions available.
fixes #26954
- - - - -
f87e5e57 by Luite Stegeman at 2026-03-07T05:03:33-05:00
Remove obsolete --make-haskell-source from genprimopcode
Now that haddock uses the wired-in interface for GHC.Internal.Prim,
the generated Haskell source file is no longer needed. Remove the
--make-haskell-source code generator from genprimopcode and replace
the generated GHC/Internal/Prim.hs with a minimal static source file.
- - - - -
4a7ddc7b by Sylvain Henry at 2026-03-07T05:04:59-05:00
JS: fix linking of exposed but non-preload units (#24886)
Units exposed in the unit database but not explicitly passed on the
command-line were not considered by the JS linker. This isn't an issue
for cabal which passes every unit explicitly but it is an issue when
using GHC directly (cf T24886 test).
- - - - -
689aafcd by mangoiv at 2026-03-07T05:05:52-05:00
testsuite: double foundation timeout multiplier
The runtime timeout in the foundation test was regularly hit by code
generated by the wasm backend - we increase the timout since the high
runtime is expected on the wasm backend for this rather complex test.
Resolves #26938
- - - - -
a46a1bb1 by Cheng Shao at 2026-03-09T04:50:30-04:00
compiler: add myCapabilityExpr to GHC.Cmm.Utils
This commit adds `myCapabilityExpr` to `GHC.Cmm.Utils` which is
computed from `BaseReg`. It's convenient for codegen logic where one
needs to pass the current Capability's pointer.
- - - - -
4afc65b1 by Cheng Shao at 2026-03-09T04:50:30-04:00
compiler: lower tryPutMVar# into a ccall directly
This patch addresses an old TODO of `stg_tryPutMVarzh` by removing it
completely and making the compiler lower `tryPutMVar#` into a ccall to
`performTryPutMVar` directly, without landing into an intermediate C
or Cmm function. `performTryPutMVar` is promoted to a public RTS
function with default visibility, and the compiler lowering logic
takes into account the C ABI of `performTryPutMVar` and converts from
C Bool to primop's `Int#` result properly.
- - - - -
9e3d6a58 by Simon Hengel at 2026-03-09T04:51:15-04:00
Don't use #line in haddocks
This confuses the parser. Haddock output is unaffected by this change.
(read: this still produces the same documentation)
- - - - -
f4e8fec2 by Wolfgang Jeltsch at 2026-03-09T04:52:01-04:00
Remove in-package dependencies on `GHC.Internal.System.IO`
This contribution eliminates all dependencies on
`GHC.Internal.System.IO` from within `ghc-internal`. It comprises the
following changes:
* Make `GHC.Internal.Fingerprint` independent of I/O support
* Tighten the dependencies of `GHC.Internal.Data.Version`
* Tighten the dependencies of `GHC.Internal.TH.Monad`
* Tighten the dependencies of `GHCi.Helpers`
* Move some code that needs `System.IO` to `template-haskell`
* Move the `GHC.ResponseFile` implementation into `base`
* Move the `System.Exit` implementation into `base`
* Move the `System.IO.OS` implementation into `base`
Metric Decrease:
size_hello_artifact
size_hello_artifact_gzip
size_hello_unicode
size_hello_unicode_gzip
- - - - -
91df4c82 by Sylvain Henry at 2026-03-09T04:53:20-04:00
T18832: fix Windows CI failure by dropping removeDirectoryRecursive
On Windows, open file handles prevent deletion. After killThread, the
closer thread may not have called hClose yet, causing removeDirectoryRecursive
to fail with "permission denied". The test harness cleans up the run
directory anyway, so the call is redundant.
- - - - -
d7fe9671 by Cheng Shao at 2026-03-09T04:54:04-04:00
compiler: fix redundant import in GHC.StgToJS.Object
This patch fixes a redundant import in GHC.StgToJS.Object that causes
a build failure when compiling head from 9.14 with validate flavours.
Fixes #26991.
- - - - -
0bfd29c3 by Cheng Shao at 2026-03-09T04:54:46-04:00
wasm: fix `Illegal foreign declaration` failure when ghci loads modules with JSFFI exports
This patch fixes a wasm ghci error when loading modules with JSFFI
exports; the `backendValidityOfCExport` check in `tcCheckFEType`
should only makes sense and should be performed when not checking the
JavaScript calling convention; otherwise, when the calling convention
is JavaScript, the codegen logic should be trusted to backends that
actually make use of it. Fixes #26998.
- - - - -
e659610c by Duncan Coutts at 2026-03-09T12:08:35-04:00
Apply NOINLINE pragmas to generated Typeable bindings
For context, see the existing Note [Grand plan for Typeable]
and the Note [NOINLINE on generated Typeable bindings] added in the
subsequent commit.
This is about reducing the number of exported top level names and
unfoldings, which reduces interface file sizes and reduces the number of
global/dynamic linker symbols.
Also accept the changed test output and metric decreases.
Tests that record the phase output for type checking or for simplifier
end up with different output: the generated bindings now have an
Inline [~] annotation, and many top level names are now local rather
than module-prefixed for export.
Also accept the numerous metric decreases in compile_time/bytes
allocated, and a few in compile_time/max_bytes_used.
There's also one instance of a decrease in runtime/max_bytes_used but
it's a ghci-way test and so presumably the reason is that it loads
smaller .hi files and/or links fewer symbols.
-------------------------
Metric Decrease:
CoOpt_Singletons
MultiLayerModulesTH_OneShot
MultilineStringsPerf
T10421
T10547
T12150
T12227
T12234
T12425
T13035
T13056
T13253
T13253-spj
T15304
T15703
T16875
T17836b
T17977b
T18140
T18223
T18282
T18304
T18698a
T18698b
T18730
T18923
T20049
T21839c
T24471
T24582
T24984
T3064
T4029
T5030
T5642
T5837
T6048
T9020
T9198
T9961
TcPlugin_RewritePerf
WWRec
hard_hole_fits
mhu-perf
-------------------------
- - - - -
67df5161 by Duncan Coutts at 2026-03-09T12:08:35-04:00
Add documentation Note [NOINLINE on generated Typeable bindings]
and refer to it from the code and existing documentation.
- - - - -
c4ad6167 by Duncan Coutts at 2026-03-09T12:08:35-04:00
Switch existing note to "named wrinkle" style, (GPT1)..(GPT7)
GPT = Grand plan for Typeable
- - - - -
dc84f8e2 by Cheng Shao at 2026-03-09T12:09:21-04:00
ci: only build deb13 for validate pipeline aarch64-linux jobs
This patch drops the redundant aarch64-linux deb12 job from validate pipelines
and only keeps deb13; it's still built in nightly/release pipelines. Closes #27004.
- - - - -
be4c2ec4 by Teo Camarasu at 2026-03-10T15:42:28+00:00
ghc-internal: Float Generics to near top of module graph
We remove GHC.Internal.Generics from the critical path of the
`ghc-internal` module graph. GHC.Internal.Generics used to be in the
middle of the module graph, but now it is nearer the top (built later).
This change thins out the module graph and allows us to get rid of the
ByteOrder hs-boot file.
We implement this by moving Generics instances from the module where the
datatype is defined to the GHC.Internal.Generics module. This trades off
increasing the compiled size of GHC.Internal.Generics with reducing the
dependency footprint of datatype modules.
Not all instances are moved to GHC.Internal.Generics. For instance,
`GHC.Internal.Control.Monad.Fix` keeps its instance as it is one of the
very last modules compiled in `ghc-internal` and so inverting the
relationship here would risk adding GHC.Internal.Generics back onto the
critical path.
We also don't change modules that are re-exported from the `template-haskell` or `ghc-heap`.
This is done to make it easy to eventually move `Generics` to `base`
once something like #26657 is implemented.
Resolves #26930
Metric Decrease:
T21839c
- - - - -
145 changed files:
- .gitlab-ci.yml
- .gitlab/generate-ci/gen_ci.hs
- .gitlab/jobs.yaml
- .gitlab/rel_eng/fetch-gitlab-artifacts/fetch_gitlab.py
- .gitlab/rel_eng/mk-ghcup-metadata/mk_ghcup_metadata.py
- compiler/GHC/Builtin/PrimOps.hs
- compiler/GHC/Builtin/Utils.hs
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/ByteCode/Serialize.hs
- compiler/GHC/Cmm/Utils.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/Hs/Type.hs
- compiler/GHC/Iface/Ext/Utils.hs
- compiler/GHC/Runtime/Interpreter/JS.hs
- compiler/GHC/StgToCmm/Prim.hs
- compiler/GHC/StgToJS/Object.hs
- compiler/GHC/Tc/Gen/Foreign.hs
- compiler/GHC/Tc/Instance/Typeable.hs
- compiler/GHC/Unit/State.hs
- compiler/GHC/Utils/Error.hs
- docs/users_guide/using-optimisation.rst
- hadrian/README.md
- hadrian/bootstrap/generate_bootstrap_plans
- hadrian/bootstrap/plan-9_10_1.json
- hadrian/bootstrap/plan-9_10_2.json
- + hadrian/bootstrap/plan-9_10_3.json
- hadrian/bootstrap/plan-bootstrap-9_10_1.json
- hadrian/bootstrap/plan-bootstrap-9_10_2.json
- + hadrian/bootstrap/plan-bootstrap-9_10_3.json
- hadrian/src/CommandLine.hs
- hadrian/src/Main.hs
- hadrian/src/Rules/Generate.hs
- hadrian/src/Settings.hs
- hadrian/src/Settings/Builders/GenPrimopCode.hs
- libraries/base/changelog.md
- libraries/base/src/GHC/Fingerprint.hs
- libraries/base/src/GHC/ResponseFile.hs
- libraries/base/src/GHC/Unicode.hs
- libraries/base/src/System/Exit.hs
- libraries/base/src/System/IO/OS.hs
- libraries/base/src/System/Info.hs
- libraries/base/tests/IO/T18832.hs
- libraries/ghc-heap/GHC/Exts/Heap/Closures.hs
- libraries/ghc-internal/ghc-internal.cabal.in
- libraries/ghc-internal/src/GHC/Internal/ByteOrder.hs
- − libraries/ghc-internal/src/GHC/Internal/ByteOrder.hs-boot
- libraries/ghc-internal/src/GHC/Internal/Data/Foldable.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Functor/Const.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Functor/Identity.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Monoid.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Semigroup/Internal.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Traversable.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Version.hs
- − libraries/ghc-internal/src/GHC/Internal/Data/Version.hs-boot
- libraries/ghc-internal/src/GHC/Internal/Event/Windows/ManagedThreadPool.hs
- libraries/ghc-internal/src/GHC/Internal/Fingerprint.hs
- libraries/ghc-internal/src/GHC/Internal/Functor/ZipList.hs
- libraries/ghc-internal/src/GHC/Internal/GHCi/Helpers.hs
- libraries/ghc-internal/src/GHC/Internal/Generics.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Exception.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Text.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Types.hs
- + libraries/ghc-internal/src/GHC/Internal/Prim.hs
- libraries/ghc-internal/src/GHC/Internal/Read.hs
- − libraries/ghc-internal/src/GHC/Internal/ResponseFile.hs
- − libraries/ghc-internal/src/GHC/Internal/System/Exit.hs
- − libraries/ghc-internal/src/GHC/Internal/System/IO/OS.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Monad.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Bits.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Version.hs
- libraries/ghc-internal/tools/ucd2haskell/exe/UCD2Haskell/ModuleGenerators.hs
- libraries/template-haskell/Language/Haskell/TH/Syntax.hs
- rts/Linker.c
- rts/LinkerInternals.h
- rts/PrimOps.cmm
- rts/RtsSymbols.c
- rts/Threads.c
- rts/Threads.h
- rts/include/rts/Threads.h
- rts/include/stg/MiscClosures.h
- rts/linker/Elf.c
- rts/linker/MachO.c
- rts/linker/PEi386.c
- testsuite/driver/perf_notes.py
- testsuite/tests/deSugar/should_compile/T16615.stderr
- testsuite/tests/deSugar/should_compile/T2431.stderr
- testsuite/tests/dmdanal/should_compile/T16029.stdout
- testsuite/tests/ffi/should_compile/all.T
- + testsuite/tests/ghci-wasm/T26998.hs
- testsuite/tests/ghci-wasm/all.T
- testsuite/tests/ghci/scripts/ListTuplePunsPpr.stdout
- testsuite/tests/ghci/scripts/T10963.stderr
- testsuite/tests/ghci/scripts/ghci064.stdout
- testsuite/tests/ghci/should_run/all.T
- 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/interface-stability/base-exports.stdout-ws-32
- + testsuite/tests/javascript/T24886.hs
- + testsuite/tests/javascript/T24886.stderr
- + testsuite/tests/javascript/T24886.stdout
- testsuite/tests/javascript/all.T
- testsuite/tests/numeric/should_compile/T14170.stdout
- testsuite/tests/numeric/should_compile/T14465.stdout
- testsuite/tests/numeric/should_compile/T7116.stdout
- testsuite/tests/numeric/should_run/all.T
- testsuite/tests/overloadedrecflds/should_compile/all.T
- testsuite/tests/overloadedrecflds/should_run/all.T
- testsuite/tests/pmcheck/should_compile/T11303.hs
- testsuite/tests/quasiquotation/qq005/test.T
- testsuite/tests/quasiquotation/qq006/test.T
- testsuite/tests/roles/should_compile/Roles1.stderr
- testsuite/tests/roles/should_compile/Roles13.stderr
- testsuite/tests/roles/should_compile/Roles14.stderr
- testsuite/tests/roles/should_compile/Roles2.stderr
- testsuite/tests/roles/should_compile/Roles3.stderr
- testsuite/tests/roles/should_compile/Roles4.stderr
- testsuite/tests/roles/should_compile/T8958.stderr
- testsuite/tests/rts/linker/Makefile
- + testsuite/tests/rts/linker/T6107.hs
- + testsuite/tests/rts/linker/T6107.stdout
- + testsuite/tests/rts/linker/T6107_sym1.s
- + testsuite/tests/rts/linker/T6107_sym2.s
- testsuite/tests/rts/linker/all.T
- testsuite/tests/saks/should_compile/all.T
- testsuite/tests/showIface/all.T
- testsuite/tests/simplCore/should_compile/OpaqueNoCastWW.stderr
- testsuite/tests/simplCore/should_compile/T3717.stderr
- testsuite/tests/simplCore/should_compile/T3772.stdout
- testsuite/tests/simplCore/should_compile/T4908.stderr
- testsuite/tests/simplCore/should_compile/T4930.stderr
- testsuite/tests/simplCore/should_compile/T7360.stderr
- testsuite/tests/simplCore/should_compile/T8274.stdout
- testsuite/tests/simplCore/should_compile/T9400.stderr
- testsuite/tests/simplCore/should_compile/noinline01.stderr
- testsuite/tests/simplCore/should_compile/par01.stderr
- testsuite/tests/th/TH_Roles2.stderr
- testsuite/tests/th/all.T
- testsuite/tests/typecheck/should_compile/T13032.stderr
- testsuite/tests/typecheck/should_compile/T18406b.stderr
- testsuite/tests/typecheck/should_compile/T18529.stderr
- testsuite/tests/vdq-rta/should_compile/all.T
- utils/genprimopcode/Main.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/a7eb4232369e76db5045014394666b…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/a7eb4232369e76db5045014394666b…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc] Pushed new branch wip/stack-cloning-segfault
by Matthew Pickering (@mpickering) 10 Mar '26
by Matthew Pickering (@mpickering) 10 Mar '26
10 Mar '26
Matthew Pickering pushed new branch wip/stack-cloning-segfault at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/wip/stack-cloning-segfault
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/T26985] ghc-internal: move bits Weak of finalizer interface to base
by Teo Camarasu (@teo) 10 Mar '26
by Teo Camarasu (@teo) 10 Mar '26
10 Mar '26
Teo Camarasu pushed to branch wip/T26985 at Glasgow Haskell Compiler / GHC
Commits:
eee470d3 by Teo Camarasu at 2026-03-10T13:35:21+00:00
ghc-internal: move bits Weak of finalizer interface to base
We move parts of the Weak finalizer interface to `base` only the parts
that the RTS needs to know about are kept in `ghc-internal`.
This lets us then prune our imports somewhat and get rid of some SOURCE imports.
Resolves #26985
- - - - -
9 changed files:
- libraries/base/src/GHC/Weak.hs
- libraries/base/src/GHC/Weak/Finalize.hs
- − libraries/base/src/GHC/Weak/Finalizehs
- libraries/base/src/System/Mem/Weak.hs
- − libraries/ghc-internal/src/GHC/Internal/Conc/Sync.hs-boot
- − libraries/ghc-internal/src/GHC/Internal/IO/Handle/Text.hs-boot
- libraries/ghc-internal/src/GHC/Internal/TopHandler.hs
- libraries/ghc-internal/src/GHC/Internal/Weak.hs
- libraries/ghc-internal/src/GHC/Internal/Weak/Finalize.hs
Changes:
=====================================
libraries/base/src/GHC/Weak.hs
=====================================
@@ -29,3 +29,5 @@ module GHC.Weak
) where
import GHC.Internal.Weak
+import GHC.Internal.Weak.Finalize
+import GHC.Weak.Finalize
=====================================
libraries/base/src/GHC/Weak/Finalize.hs
=====================================
@@ -14,9 +14,14 @@ module GHC.Weak.Finalize
import GHC.Internal.Weak.Finalize
--- These imports can be removed once runFinalizerBatch is removed,
--- as can MagicHash above.
-import GHC.Internal.Base (Int, Array#, IO, State#, RealWorld)
+import GHC.Internal.Base
+import GHC.Internal.Exception
+import GHC.Internal.IORef
+import GHC.Internal.Conc.Sync (labelThreadByteArray#, myThreadId)
+import GHC.Internal.IO (catchException, unsafePerformIO)
+import GHC.Internal.IO.Handle.Types (Handle)
+import GHC.Internal.IO.Handle.Text (hPutStrLn)
+import GHC.Internal.Encoding.UTF8 (utf8EncodeByteArray#)
{-# DEPRECATED runFinalizerBatch
@@ -36,3 +41,13 @@ runFinalizerBatch :: Int
-> Array# (State# RealWorld -> State# RealWorld)
-> IO ()
runFinalizerBatch = GHC.Internal.Weak.Finalize.runFinalizerBatch
+
+-- | An exception handler for 'Handle' finalization that prints the error to
+-- the given 'Handle', but doesn't rethrow it.
+--
+-- @since base-4.18.0.0
+printToHandleFinalizerExceptionHandler :: Handle -> SomeException -> IO ()
+printToHandleFinalizerExceptionHandler hdl se =
+ hPutStrLn hdl msg `catchException` (\(SomeException _) -> return ())
+ where
+ msg = "Exception during weak pointer finalization (ignored): " ++ displayException se ++ "\n"
=====================================
libraries/base/src/GHC/Weak/Finalizehs deleted
=====================================
=====================================
libraries/base/src/System/Mem/Weak.hs
=====================================
@@ -91,6 +91,7 @@ module System.Mem.Weak (
import Prelude
import GHC.Internal.Weak
+import GHC.Weak
-- | A specialised version of 'mkWeak', where the key and the value are
-- the same object:
=====================================
libraries/ghc-internal/src/GHC/Internal/Conc/Sync.hs-boot deleted
=====================================
@@ -1,70 +0,0 @@
-{-# LANGUAGE MagicHash, NoImplicitPrelude #-}
-{-# OPTIONS_HADDOCK not-home #-}
-
------------------------------------------------------------------------------
--- |
--- Module : GHC.Internal.Conc.Sync [boot]
--- Copyright : (c) The University of Glasgow, 1994-2002
--- License : see libraries/base/LICENSE
---
--- Maintainer : ghc-devs(a)haskell.org
--- Stability : internal
--- Portability : non-portable (GHC extensions)
---
--- Basic concurrency stuff.
---
------------------------------------------------------------------------------
-
-module GHC.Internal.Conc.Sync
- ( forkIO,
- ThreadId(..),
- myThreadId,
- showThreadId,
- ThreadStatus(..),
- threadStatus,
- sharedCAF,
- labelThreadByteArray#
- ) where
-
-import GHC.Internal.Base
-import GHC.Internal.Ptr
-
-forkIO :: IO () -> IO ThreadId
-
-data ThreadId = ThreadId ThreadId#
-
-data BlockReason
- = BlockedOnMVar
- -- ^blocked on 'MVar'
- {- possibly (see 'threadstatus' below):
- | BlockedOnMVarRead
- -- ^blocked on reading an empty 'MVar'
- -}
- | BlockedOnBlackHole
- -- ^blocked on a computation in progress by another thread
- | BlockedOnException
- -- ^blocked in 'throwTo'
- | BlockedOnSTM
- -- ^blocked in 'retry' in an STM transaction
- | BlockedOnForeignCall
- -- ^currently in a foreign call
- | BlockedOnOther
- -- ^blocked on some other resource. Without @-threaded@,
- -- I\/O and 'threadDelay' show up as 'BlockedOnOther', with @-threaded@
- -- they show up as 'BlockedOnMVar'.
-
-data ThreadStatus
- = ThreadRunning
- -- ^the thread is currently runnable or running
- | ThreadFinished
- -- ^the thread has finished
- | ThreadBlocked BlockReason
- -- ^the thread is blocked on some resource
- | ThreadDied
- -- ^the thread received an uncaught exception
-
-myThreadId :: IO ThreadId
-showThreadId :: ThreadId -> String
-threadStatus :: ThreadId -> IO ThreadStatus
-sharedCAF :: a -> (Ptr a -> IO (Ptr a)) -> IO a
-labelThreadByteArray# :: ThreadId -> ByteArray# -> IO ()
=====================================
libraries/ghc-internal/src/GHC/Internal/IO/Handle/Text.hs-boot deleted
=====================================
@@ -1,8 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-
-module GHC.Internal.IO.Handle.Text ( hPutStrLn ) where
-
-import GHC.Internal.Base (String, IO)
-import {-# SOURCE #-} GHC.Internal.IO.Handle.Types (Handle)
-
-hPutStrLn :: Handle -> String -> IO ()
=====================================
libraries/ghc-internal/src/GHC/Internal/TopHandler.hs
=====================================
@@ -50,6 +50,8 @@ import GHC.Internal.IO.Handle
import GHC.Internal.IO.StdHandles
import GHC.Internal.IO.Exception
import GHC.Internal.Weak
+import GHC.Internal.Weak.Finalize
+import GHC.Internal.IO.Handle.Types ()
#if defined(mingw32_HOST_OS)
import GHC.Internal.ConsoleHandler as GHC.ConsoleHandler
=====================================
libraries/ghc-internal/src/GHC/Internal/Weak.hs
=====================================
@@ -24,19 +24,9 @@ module GHC.Internal.Weak (
mkWeak,
deRefWeak,
finalize,
-
- -- * Handling exceptions
- -- | When an exception is thrown by a finalizer called by the
- -- garbage collector, GHC calls a global handler which can be set with
- -- 'setFinalizerExceptionHandler'. Note that any exceptions thrown by
- -- this handler will be ignored.
- setFinalizerExceptionHandler,
- getFinalizerExceptionHandler,
- printToHandleFinalizerExceptionHandler
) where
import GHC.Internal.Base
-import GHC.Internal.Weak.Finalize
{-|
A weak pointer object with a key and a value. The value has type @v@.
=====================================
libraries/ghc-internal/src/GHC/Internal/Weak/Finalize.hs
=====================================
@@ -4,26 +4,17 @@
{-# LANGUAGE Unsafe #-}
module GHC.Internal.Weak.Finalize
- ( -- * Handling exceptions
- -- | When an exception is thrown by a finalizer called by the
- -- garbage collector, GHC calls a global handler which can be set with
- -- 'setFinalizerExceptionHandler'. Note that any exceptions thrown by
- -- this handler will be ignored.
- setFinalizerExceptionHandler
- , getFinalizerExceptionHandler
- , printToHandleFinalizerExceptionHandler
- -- * Internal
+ ( getFinalizerExceptionHandler
+ , setFinalizerExceptionHandler
, runFinalizerBatch
) where
import GHC.Internal.Base
-import GHC.Internal.Exception
-import GHC.Internal.IORef
-import {-# SOURCE #-} GHC.Internal.Conc.Sync (labelThreadByteArray#, myThreadId)
-import GHC.Internal.IO (catchException, unsafePerformIO)
-import {-# SOURCE #-} GHC.Internal.IO.Handle.Types (Handle)
-import {-# SOURCE #-} GHC.Internal.IO.Handle.Text (hPutStrLn)
-import GHC.Internal.Encoding.UTF8 (utf8EncodeByteArray#)
+import GHC.Internal.Conc.Sync ( labelThreadByteArray#, myThreadId )
+import GHC.Internal.Encoding.UTF8 ( utf8EncodeByteArray# )
+import GHC.Internal.Exception ( SomeException(..) )
+import GHC.Internal.IO ( catchException, unsafePerformIO )
+import GHC.Internal.IORef ( IORef, newIORef, readIORef, writeIORef )
data ByteArray = ByteArray ByteArray#
@@ -82,13 +73,3 @@ getFinalizerExceptionHandler = readIORef finalizerExceptionHandler
-- @since base-4.18.0.0
setFinalizerExceptionHandler :: (SomeException -> IO ()) -> IO ()
setFinalizerExceptionHandler = writeIORef finalizerExceptionHandler
-
--- | An exception handler for 'Handle' finalization that prints the error to
--- the given 'Handle', but doesn't rethrow it.
---
--- @since base-4.18.0.0
-printToHandleFinalizerExceptionHandler :: Handle -> SomeException -> IO ()
-printToHandleFinalizerExceptionHandler hdl se =
- hPutStrLn hdl msg `catchException` (\(SomeException _) -> return ())
- where
- msg = "Exception during weak pointer finalization (ignored): " ++ displayException se ++ "\n"
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/eee470d32a6d4028101a8a45462c2ae…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/eee470d32a6d4028101a8a45462c2ae…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/T26985] ghc-internal: move bits Weak of finalizer interface to base
by Teo Camarasu (@teo) 10 Mar '26
by Teo Camarasu (@teo) 10 Mar '26
10 Mar '26
Teo Camarasu pushed to branch wip/T26985 at Glasgow Haskell Compiler / GHC
Commits:
c561d206 by Teo Camarasu at 2026-03-10T13:13:03+00:00
ghc-internal: move bits Weak of finalizer interface to base
We move parts of the Weak finalizer interface to `base` only the parts
that the RTS needs to know about are kept in `ghc-internal`.
This lets us then prune our imports somewhat and get rid of some SOURCE imports.
Resolves #26985
- - - - -
9 changed files:
- libraries/base/src/GHC/Weak.hs
- libraries/base/src/GHC/Weak/Finalize.hs
- − libraries/base/src/GHC/Weak/Finalizehs
- libraries/base/src/System/Mem/Weak.hs
- − libraries/ghc-internal/src/GHC/Internal/Conc/Sync.hs-boot
- − libraries/ghc-internal/src/GHC/Internal/IO/Handle/Text.hs-boot
- libraries/ghc-internal/src/GHC/Internal/TopHandler.hs
- libraries/ghc-internal/src/GHC/Internal/Weak.hs
- libraries/ghc-internal/src/GHC/Internal/Weak/Finalize.hs
Changes:
=====================================
libraries/base/src/GHC/Weak.hs
=====================================
@@ -29,3 +29,5 @@ module GHC.Weak
) where
import GHC.Internal.Weak
+import GHC.Internal.Weak.Finalize
+import GHC.Weak.Finalize
=====================================
libraries/base/src/GHC/Weak/Finalize.hs
=====================================
@@ -14,9 +14,14 @@ module GHC.Weak.Finalize
import GHC.Internal.Weak.Finalize
--- These imports can be removed once runFinalizerBatch is removed,
--- as can MagicHash above.
-import GHC.Internal.Base (Int, Array#, IO, State#, RealWorld)
+import GHC.Internal.Base
+import GHC.Internal.Exception
+import GHC.Internal.IORef
+import GHC.Internal.Conc.Sync (labelThreadByteArray#, myThreadId)
+import GHC.Internal.IO (catchException, unsafePerformIO)
+import GHC.Internal.IO.Handle.Types (Handle)
+import GHC.Internal.IO.Handle.Text (hPutStrLn)
+import GHC.Internal.Encoding.UTF8 (utf8EncodeByteArray#)
{-# DEPRECATED runFinalizerBatch
@@ -36,3 +41,13 @@ runFinalizerBatch :: Int
-> Array# (State# RealWorld -> State# RealWorld)
-> IO ()
runFinalizerBatch = GHC.Internal.Weak.Finalize.runFinalizerBatch
+
+-- | An exception handler for 'Handle' finalization that prints the error to
+-- the given 'Handle', but doesn't rethrow it.
+--
+-- @since base-4.18.0.0
+printToHandleFinalizerExceptionHandler :: Handle -> SomeException -> IO ()
+printToHandleFinalizerExceptionHandler hdl se =
+ hPutStrLn hdl msg `catchException` (\(SomeException _) -> return ())
+ where
+ msg = "Exception during weak pointer finalization (ignored): " ++ displayException se ++ "\n"
=====================================
libraries/base/src/GHC/Weak/Finalizehs deleted
=====================================
=====================================
libraries/base/src/System/Mem/Weak.hs
=====================================
@@ -91,6 +91,7 @@ module System.Mem.Weak (
import Prelude
import GHC.Internal.Weak
+import GHC.Weak
-- | A specialised version of 'mkWeak', where the key and the value are
-- the same object:
=====================================
libraries/ghc-internal/src/GHC/Internal/Conc/Sync.hs-boot deleted
=====================================
@@ -1,70 +0,0 @@
-{-# LANGUAGE MagicHash, NoImplicitPrelude #-}
-{-# OPTIONS_HADDOCK not-home #-}
-
------------------------------------------------------------------------------
--- |
--- Module : GHC.Internal.Conc.Sync [boot]
--- Copyright : (c) The University of Glasgow, 1994-2002
--- License : see libraries/base/LICENSE
---
--- Maintainer : ghc-devs(a)haskell.org
--- Stability : internal
--- Portability : non-portable (GHC extensions)
---
--- Basic concurrency stuff.
---
------------------------------------------------------------------------------
-
-module GHC.Internal.Conc.Sync
- ( forkIO,
- ThreadId(..),
- myThreadId,
- showThreadId,
- ThreadStatus(..),
- threadStatus,
- sharedCAF,
- labelThreadByteArray#
- ) where
-
-import GHC.Internal.Base
-import GHC.Internal.Ptr
-
-forkIO :: IO () -> IO ThreadId
-
-data ThreadId = ThreadId ThreadId#
-
-data BlockReason
- = BlockedOnMVar
- -- ^blocked on 'MVar'
- {- possibly (see 'threadstatus' below):
- | BlockedOnMVarRead
- -- ^blocked on reading an empty 'MVar'
- -}
- | BlockedOnBlackHole
- -- ^blocked on a computation in progress by another thread
- | BlockedOnException
- -- ^blocked in 'throwTo'
- | BlockedOnSTM
- -- ^blocked in 'retry' in an STM transaction
- | BlockedOnForeignCall
- -- ^currently in a foreign call
- | BlockedOnOther
- -- ^blocked on some other resource. Without @-threaded@,
- -- I\/O and 'threadDelay' show up as 'BlockedOnOther', with @-threaded@
- -- they show up as 'BlockedOnMVar'.
-
-data ThreadStatus
- = ThreadRunning
- -- ^the thread is currently runnable or running
- | ThreadFinished
- -- ^the thread has finished
- | ThreadBlocked BlockReason
- -- ^the thread is blocked on some resource
- | ThreadDied
- -- ^the thread received an uncaught exception
-
-myThreadId :: IO ThreadId
-showThreadId :: ThreadId -> String
-threadStatus :: ThreadId -> IO ThreadStatus
-sharedCAF :: a -> (Ptr a -> IO (Ptr a)) -> IO a
-labelThreadByteArray# :: ThreadId -> ByteArray# -> IO ()
=====================================
libraries/ghc-internal/src/GHC/Internal/IO/Handle/Text.hs-boot deleted
=====================================
@@ -1,8 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-
-module GHC.Internal.IO.Handle.Text ( hPutStrLn ) where
-
-import GHC.Internal.Base (String, IO)
-import {-# SOURCE #-} GHC.Internal.IO.Handle.Types (Handle)
-
-hPutStrLn :: Handle -> String -> IO ()
=====================================
libraries/ghc-internal/src/GHC/Internal/TopHandler.hs
=====================================
@@ -50,6 +50,8 @@ import GHC.Internal.IO.Handle
import GHC.Internal.IO.StdHandles
import GHC.Internal.IO.Exception
import GHC.Internal.Weak
+import GHC.Internal.Weak.Finalize
+import GHC.Internal.IO.Handle.Types ()
#if defined(mingw32_HOST_OS)
import GHC.Internal.ConsoleHandler as GHC.ConsoleHandler
=====================================
libraries/ghc-internal/src/GHC/Internal/Weak.hs
=====================================
@@ -24,19 +24,9 @@ module GHC.Internal.Weak (
mkWeak,
deRefWeak,
finalize,
-
- -- * Handling exceptions
- -- | When an exception is thrown by a finalizer called by the
- -- garbage collector, GHC calls a global handler which can be set with
- -- 'setFinalizerExceptionHandler'. Note that any exceptions thrown by
- -- this handler will be ignored.
- setFinalizerExceptionHandler,
- getFinalizerExceptionHandler,
- printToHandleFinalizerExceptionHandler
) where
import GHC.Internal.Base
-import GHC.Internal.Weak.Finalize
{-|
A weak pointer object with a key and a value. The value has type @v@.
=====================================
libraries/ghc-internal/src/GHC/Internal/Weak/Finalize.hs
=====================================
@@ -4,26 +4,18 @@
{-# LANGUAGE Unsafe #-}
module GHC.Internal.Weak.Finalize
- ( -- * Handling exceptions
- -- | When an exception is thrown by a finalizer called by the
- -- garbage collector, GHC calls a global handler which can be set with
- -- 'setFinalizerExceptionHandler'. Note that any exceptions thrown by
- -- this handler will be ignored.
- setFinalizerExceptionHandler
- , getFinalizerExceptionHandler
- , printToHandleFinalizerExceptionHandler
- -- * Internal
+ ( getFinalizerExceptionHandler
+ , setFinalizerExceptionHandler
, runFinalizerBatch
+ , finalizerExceptionHandler
) where
import GHC.Internal.Base
-import GHC.Internal.Exception
-import GHC.Internal.IORef
-import {-# SOURCE #-} GHC.Internal.Conc.Sync (labelThreadByteArray#, myThreadId)
-import GHC.Internal.IO (catchException, unsafePerformIO)
-import {-# SOURCE #-} GHC.Internal.IO.Handle.Types (Handle)
-import {-# SOURCE #-} GHC.Internal.IO.Handle.Text (hPutStrLn)
-import GHC.Internal.Encoding.UTF8 (utf8EncodeByteArray#)
+import GHC.Internal.Conc.Sync ( labelThreadByteArray#, myThreadId )
+import GHC.Internal.Encoding.UTF8 ( utf8EncodeByteArray# )
+import GHC.Internal.Exception ( SomeException(..) )
+import GHC.Internal.IO ( catchException, unsafePerformIO )
+import GHC.Internal.IORef ( IORef, newIORef, readIORef, writeIORef )
data ByteArray = ByteArray ByteArray#
@@ -82,13 +74,3 @@ getFinalizerExceptionHandler = readIORef finalizerExceptionHandler
-- @since base-4.18.0.0
setFinalizerExceptionHandler :: (SomeException -> IO ()) -> IO ()
setFinalizerExceptionHandler = writeIORef finalizerExceptionHandler
-
--- | An exception handler for 'Handle' finalization that prints the error to
--- the given 'Handle', but doesn't rethrow it.
---
--- @since base-4.18.0.0
-printToHandleFinalizerExceptionHandler :: Handle -> SomeException -> IO ()
-printToHandleFinalizerExceptionHandler hdl se =
- hPutStrLn hdl msg `catchException` (\(SomeException _) -> return ())
- where
- msg = "Exception during weak pointer finalization (ignored): " ++ displayException se ++ "\n"
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/c561d2064ca9ce75e1a9bc005df1d25…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/c561d2064ca9ce75e1a9bc005df1d25…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
Zubin pushed to branch wip/26416 at Glasgow Haskell Compiler / GHC
Commits:
7b4eb1a1 by Zubin Duggal at 2026-03-10T17:18:49+05:30
wip
- - - - -
3 changed files:
- compiler/GHC/Core/Opt/DmdAnal.hs
- compiler/GHC/Types/Demand.hs
- + testsuite/tests/dmdanal/should_run/T26416.stdout
Changes:
=====================================
compiler/GHC/Core/Opt/DmdAnal.hs
=====================================
@@ -1141,7 +1141,7 @@ dmdAnalRhsSig top_lvl rec_flag env let_sd id rhs
-- See Note [Absence analysis for stable unfoldings and RULES]
-- The unfolding FVs are already included in full_rhs_env via addUnfoldingDemands.
-- Here we only need demandRoots for RULES.
- rhs_env2 = rhs_env1 `plusDmdEnv` demandRootSet env (idRuleVars id)
+ rhs_env2 = rhs_env1 `plusDmdEnv` demandRootSet env (filterVarSet isId (idRuleVars id))
-- See Note [Lazy and unleashable free variables]
!(!sig_env, !weak_fvs) = splitWeakDmds rhs_env2
@@ -1160,7 +1160,7 @@ addUnfoldingDemands env rhs_sd id rhs_dmd_ty
, Just unf_body <- maybeUnfoldingTemplate unf
, let WithDmdType unf_dmd_ty _ = dmdAnal env rhs_sd unf_body
= -- pprTrace "addUnfoldingDemands" (ppr id $$ ppr rhs_dmd_ty $$ ppr unf_dmd_ty) $
- lubUBglbLBDmdType rhs_dmd_ty unf_dmd_ty
+ maxDmdType rhs_dmd_ty unf_dmd_ty
| otherwise
= rhs_dmd_ty -- No stable unfolding, nothing to do
@@ -1504,10 +1504,21 @@ and transform to
Now if f is subsequently inlined, we'll use 'g' and ... disaster.
-SOLUTION: if f has a stable unfolding, treat every free variable as a
-/demand root/, that is: Analyse it as if it was a variable occurring in a
+SOLUTION for stable unfoldings: in `dmdAnalRhsSig`, if the function has a
+stable unfolding, analyse it with `dmdAnal` and combine the resulting `DmdType`
+with the RHS's `DmdType`. This is done by `addUnfoldingDemands`, which uses
+`maxDmdType` to combine both argument demands and free variable demands.
+See Note [Combining demands for stable unfoldings] in GHC.Types.Demand for
+details of the combining operation.
+
+This handles both the free variables and arguments of stable unfoldings in one
+go. For example, in the scenario above, the unfolding's `DmdType` will mention
+`g` as a free variable, so `maxDmdType` will keep it alive.
+
+SOLUTION for RULES: treat every Id free in the RHS of a RULE as a
+/demand root/, that is: analyse it as if it was a variable occurring in a
'topDmd' context. This is done in `demandRoot` (which we also use for exported
-top-level ids). Do the same for Ids free in the RHS of any RULES for f.
+top-level ids).
Wrinkles:
@@ -1524,7 +1535,7 @@ Wrinkles:
this, that actually happened in practice.
(W2) You might wonder why we don't simply take the free vars of the
- unfolding/RULE and map them to topDmd. The reason is that any of the free vars
+ RULE and map them to topDmd. The reason is that any of the free vars
might have demand signatures themselves that in turn demand transitive free
variables and that we hence need to unleash! This came up in #23208.
Consider
@@ -1546,7 +1557,7 @@ Wrinkles:
for `sg`, failing to unleash the signature and hence observed an absent
error instead of the `really important message`.
- (W3) The SOLUTION above handles /free variables/ of stable unfoldings, but
+ (W3) The stable unfolding solution above handles /free variables/, but
what about /arguments/? Consider (#26416)
fromVector :: (Storable a, KnownNat n) => Vector a -> Vector a
@@ -1560,15 +1571,9 @@ Wrinkles:
worker's unfolding is inlined, it will use that rubbish value as a real
dictionary, leading to a segfault!
- SOLUTION: in `dmdAnalRhsSig`, if the function has a stable unfolding,
- analyse it with `dmdAnal` and combine the resulting `DmdType` with the
- RHS's `DmdType`. This is done by `addUnfoldingDemands`, which uses
- `lubUBglbLBDmdType` to combine both argument demands and free variable
- demands. See Note [Combining demands for stable unfoldings] in
- GHC.Types.Demand for details of the combining operation.
-
- This replaces the `demandRoots` approach for stable unfoldings (though
- we still use `demandRoots` for RULES via `idRuleVars`).
+ `addUnfoldingDemands` handles this too: since `maxDmdType` combines both
+ the argument demands and free variable demands from the unfolding's
+ `DmdType` with the RHS's, argument absence is correctly prevented.
Note [DmdAnal for DataCon wrappers]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2052,8 +2057,15 @@ finaliseArgBoxities :: AnalEnv -> Id -> Arity
-- If: (dmds', rhs') = finaliseArgBoxitities ... dmds .. rhs
-- Then:
-- dmds' is the same as dmds (including length), except for boxity info
--- rhs' is the same as rhs, except for dmd info on lambda binders
+-- rhs' is the same as rhs, except that the idDemandInfo on the outer
+-- lambda binders now includes the same finalised boxity info as dmds'
-- NB: For join points, length dmds might be greater than ww_arity
+--
+-- IMPORTANT: The lambda binders of rhs' must carry the final demand info,
+-- because worker/wrapper drives decisions from the idDemandInfo on the lambdas
+-- (see mkWwstr_one), NOT from the strictness signature of the function.
+-- So the demands must reflect both the unfolding combination (from
+-- addUnfoldingDemands) and the boxity finalisation done here.
finaliseArgBoxities env fn ww_arity arg_dmds div rhs
-- Check for an OPAQUE function: see Note [OPAQUE pragma]
@@ -2097,7 +2109,7 @@ finaliseArgBoxities env fn ww_arity arg_dmds div rhs
[ bndr | bndr <- bndrs, isRuntimeVar bndr ]
arg_dmds
where
- mk_triple bndr dmd = (idType bndr, NotMarkedStrict, get_dmd dmd)
+ mk_triple bndr arg_dmd = (idType bndr, NotMarkedStrict, get_dmd arg_dmd)
arg_dmds' = ww_arg_dmds ++ map trimBoxity (drop ww_arity arg_dmds)
-- If ww_arity < length arg_dmds, the leftover ones
=====================================
compiler/GHC/Types/Demand.hs
=====================================
@@ -23,8 +23,8 @@ module GHC.Types.Demand (
lubCard, lubDmd, lubSubDmd,
-- *** Greatest lower bound
glbCard,
- -- *** Unfolding combination (glb on strictness, lub on usage)
- lubUBglbLBDmd,
+ -- *** Maximum (glb on strictness, lub on usage)
+ maxCard, maxDmd,
-- *** Plus
plusCard, plusDmd, plusSubDmd,
-- *** Multiply
@@ -57,7 +57,7 @@ module GHC.Types.Demand (
DmdType(..), dmdTypeDepth,
-- ** Algebra
nopDmdType, botDmdType,
- lubDmdType, lubUBglbLBDmdType, plusDmdType, multDmdType, discardArgDmds,
+ lubDmdType, maxDmdType, plusDmdType, multDmdType, discardArgDmds,
-- ** Other operations
peelFV, findIdDemand, addDemand, splitDmdTy, deferAfterPreciseException,
@@ -899,43 +899,46 @@ See Note [Absence analysis for stable unfoldings and RULES] in GHC.Core.Opt.DmdA
for the broader context.
-}
--- | Combine demands for stable unfolding analysis.
+-- | Takes the maximum of both the lower and upper bound of two 'Card's.
+-- Semantically, this is glb on lower (strictness) and lub on upper (usage).
-- See Note [Combining demands for stable unfoldings].
-lubUBglbLBCard :: Card -> Card -> Card
+maxCard :: Card -> Card -> Card
-- Given Note [Bit vector representation for Card]:
-- * bit 0 (strictness): take AND (glb) - 0 means strict, so 0 wins
-- * bits 1,2 (usage): take OR (lub) - if either uses, result uses
-lubUBglbLBCard (Card a) (Card b) = Card ((a .&. b .&. 0b001) .|. ((a .|. b) .&. 0b110))
+maxCard (Card a) (Card b) = Card ((a .&. b .&. 0b001) .|. ((a .|. b) .&. 0b110))
--- | See Note [Combining demands for stable unfoldings].
-lubUBglbLBDmd :: Demand -> Demand -> Demand
-lubUBglbLBDmd BotDmd dmd2 = dmd2
-lubUBglbLBDmd dmd1 BotDmd = dmd1
-lubUBglbLBDmd (n1 :* sd1) (n2 :* sd2) =
- lubUBglbLBCard n1 n2 :* lubUBglbLBSubDmd sd1 sd2
+-- | Takes the maximum of both the lower and upper bounds of two 'Demand's.
+-- Semantically, glb on lower (strictness) and lub on upper (usage).
+-- See Note [Combining demands for stable unfoldings].
+maxDmd :: Demand -> Demand -> Demand
+maxDmd BotDmd dmd2 = dmd2
+maxDmd dmd1 BotDmd = dmd1
+maxDmd (n1 :* sd1) (n2 :* sd2) =
+ maxCard n1 n2 :* maxSubDmd sd1 sd2
-lubUBglbLBSubDmd :: SubDemand -> SubDemand -> SubDemand
+maxSubDmd :: SubDemand -> SubDemand -> SubDemand
-- Shortcuts for neutral and absorbing elements.
-lubUBglbLBSubDmd (Poly Unboxed C_10) sd = sd
-lubUBglbLBSubDmd sd (Poly Unboxed C_10) = sd
-lubUBglbLBSubDmd sd@(Poly Boxed C_0N) _ = sd
-lubUBglbLBSubDmd _ sd@(Poly Boxed C_0N) = sd
+maxSubDmd (Poly Unboxed C_00) sd = sd
+maxSubDmd sd (Poly Unboxed C_00) = sd
+maxSubDmd sd@(Poly Boxed C_1N) _ = sd
+maxSubDmd _ sd@(Poly Boxed C_1N) = sd
-- Prod
-lubUBglbLBSubDmd (Prod b1 ds1) (Poly b2 n2)
+maxSubDmd (Prod b1 ds1) (Poly b2 n2)
| let !d = polyFieldDmd b2 n2
- = mkProd (lubBoxity b1 b2) (strictMap (lubUBglbLBDmd d) ds1)
-lubUBglbLBSubDmd (Prod b1 ds1) (Prod b2 ds2)
+ = mkProd (lubBoxity b1 b2) (strictMap (maxDmd d) ds1)
+maxSubDmd (Prod b1 ds1) (Prod b2 ds2)
| equalLength ds1 ds2
- = mkProd (lubBoxity b1 b2) (strictZipWith lubUBglbLBDmd ds1 ds2)
+ = mkProd (lubBoxity b1 b2) (strictZipWith maxDmd ds1 ds2)
-- Handle Call
-lubUBglbLBSubDmd (Call n1 sd1) (viewCall -> Just (n2, sd2)) =
- mkCall (lubUBglbLBCard n1 n2) (lubUBglbLBSubDmd sd1 sd2)
+maxSubDmd (Call n1 sd1) (viewCall -> Just (n2, sd2)) =
+ mkCall (maxCard n1 n2) (maxSubDmd sd1 sd2)
-- Handle Poly
-lubUBglbLBSubDmd (Poly b1 n1) (Poly b2 n2) = Poly (lubBoxity b1 b2) (lubUBglbLBCard n1 n2)
+maxSubDmd (Poly b1 n1) (Poly b2 n2) = Poly (lubBoxity b1 b2) (maxCard n1 n2)
-- Other Poly case by commutativity
-lubUBglbLBSubDmd sd1@Poly{} sd2 = lubUBglbLBSubDmd sd2 sd1
--- Otherwise (Call `lubUBglbLB` Prod) return Top
-lubUBglbLBSubDmd _ _ = topSubDmd
+maxSubDmd sd1@Poly{} sd2 = maxSubDmd sd2 sd1
+-- Otherwise (Call `max` Prod) return Top
+maxSubDmd _ _ = topSubDmd
-- | Denotes '+' on 'Demand'.
plusDmd :: Demand -> Demand -> Demand
@@ -1909,22 +1912,22 @@ lubDmdType d1 d2 = DmdType lub_fv lub_ds
-- | Combine two 'DmdType's for stable unfolding analysis.
-- See Note [Combining demands for stable unfoldings].
-lubUBglbLBDmdType :: DmdType -> DmdType -> DmdType
-lubUBglbLBDmdType (DmdType fv1 ds1) (DmdType fv2 ds2)
+maxDmdType :: DmdType -> DmdType -> DmdType
+maxDmdType (DmdType fv1 ds1) (DmdType fv2 ds2)
= DmdType combined_fv combined_ds
where
- combined_fv = lubUBglbLBDmdEnv fv1 fv2
+ combined_fv = maxDmdEnv fv1 fv2
combined_ds = go ds1 ds2
-- If lists have different lengths, keep remaining ds1 (from RHS)
go rhs [] = rhs
go [] _ = []
- go (r:rhs) (u:unfs) = lubUBglbLBDmd r u : go rhs unfs
+ go (r:rhs) (u:unfs) = maxDmd r u : go rhs unfs
-- | See Note [Combining demands for stable unfoldings].
-lubUBglbLBDmdEnv :: DmdEnv -> DmdEnv -> DmdEnv
-lubUBglbLBDmdEnv (DE fv1 d1) (DE fv2 d2) = DE combined_fv combined_div
+maxDmdEnv :: DmdEnv -> DmdEnv -> DmdEnv
+maxDmdEnv (DE fv1 d1) (DE fv2 d2) = DE combined_fv combined_div
where
- combined_fv = plusVarEnv_CD lubUBglbLBDmd fv1 (defaultFvDmd d1) fv2 (defaultFvDmd d2)
+ combined_fv = plusVarEnv_CD maxDmd fv1 (defaultFvDmd d1) fv2 (defaultFvDmd d2)
combined_div = lubDivergence d1 d2
discardArgDmds :: DmdType -> DmdEnv
=====================================
testsuite/tests/dmdanal/should_run/T26416.stdout
=====================================
@@ -0,0 +1 @@
+4.0
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/7b4eb1a18a1cccc96785a4a0c514720…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/7b4eb1a18a1cccc96785a4a0c514720…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
Zubin pushed to branch wip/26416 at Glasgow Haskell Compiler / GHC
WARNING: The push did not contain any new commits, but force pushed to delete the commits and changes below.
Deleted commits:
046abdcd by Zubin Duggal at 2026-02-17T17:56:16+05:30
debug hash
- - - - -
2 changed files:
- hadrian/src/CommandLine.hs
- hadrian/src/Hadrian/Haskell/Hash.hs
Changes:
=====================================
hadrian/src/CommandLine.hs
=====================================
@@ -1,7 +1,7 @@
module CommandLine (
optDescrs, cmdLineArgsMap, cmdFlavour, lookupFreeze1, lookupFreeze2, lookupSkipDepends,
cmdBignum, cmdBignumCheck, cmdProgressInfo, cmdCompleteSetting,
- cmdDocsArgs, cmdUnitIdHash, lookupBuildRoot, TestArgs(..), TestSpeed(..), defaultTestArgs,
+ cmdDocsArgs, cmdUnitIdHash, cmdDebugHashInputs, lookupBuildRoot, TestArgs(..), TestSpeed(..), defaultTestArgs,
cmdPrefix, DocArgs(..), defaultDocArgs
) where
@@ -37,7 +37,8 @@ data CommandLineArgs = CommandLineArgs
, docsArgs :: DocArgs
, docTargets :: DocTargets
, prefix :: Maybe FilePath
- , completeStg :: Maybe String }
+ , completeStg :: Maybe String
+ , debugHashInputs :: Bool }
deriving (Eq, Show)
-- | Default values for 'CommandLineArgs'.
@@ -57,7 +58,8 @@ defaultCommandLineArgs = CommandLineArgs
, docsArgs = defaultDocArgs
, docTargets = Set.fromList [minBound..maxBound]
, prefix = Nothing
- , completeStg = Nothing }
+ , completeStg = Nothing
+ , debugHashInputs = False }
-- | These arguments are used by the `test` target.
data TestArgs = TestArgs
@@ -143,6 +145,9 @@ readUnitIdHash = Right $ \flags ->
trace "--hash-unit-ids is deprecated. It is enabled by release flavour or +hash_unit_ids flavour transformer" $
flags { unitIdHash = True }
+readDebugHashInputs :: Either String (CommandLineArgs -> CommandLineArgs)
+readDebugHashInputs = Right $ \flags -> flags { debugHashInputs = True }
+
readProgressInfo :: String -> Either String (CommandLineArgs -> CommandLineArgs)
readProgressInfo ms =
case lower ms of
@@ -278,6 +283,8 @@ optDescrs =
"Freeze Stage2 GHC."
, Option [] ["hash-unit-ids"] (NoArg readUnitIdHash)
"Include package hashes in unit ids."
+ , Option [] ["debug-hash-inputs"] (NoArg readDebugHashInputs)
+ "Debug: print and log hash inputs for each package."
, Option [] ["skip-depends"] (NoArg readSkipDepends)
"Skip rebuilding dependency information."
, Option [] ["bignum"] (OptArg readBignum "BACKEND")
@@ -401,5 +408,8 @@ cmdBignumCheck = bignumCheck <$> cmdLineArgs
cmdProgressInfo :: Action ProgressInfo
cmdProgressInfo = progressInfo <$> cmdLineArgs
+cmdDebugHashInputs :: Action Bool
+cmdDebugHashInputs = debugHashInputs <$> cmdLineArgs
+
cmdDocsArgs :: Action DocTargets
cmdDocsArgs = docTargets <$> cmdLineArgs
=====================================
hadrian/src/Hadrian/Haskell/Hash.hs
=====================================
@@ -34,6 +34,8 @@ import Control.Monad
import Base
import System.Directory.Extra (listFilesRecursive)
import Control.Arrow (first)
+import CommandLine (cmdDebugHashInputs)
+import System.Directory (createDirectoryIfMissing)
-- | Read a Cabal file and return the package identifier, e.g. @base-4.10.0.0-abcd@.
@@ -169,15 +171,25 @@ pkgHashOracle = void $ addOracleCache $ \(PkgHashKey (stag, pkg)) -> do
need files
files_hash <- liftIO (SHA256.finalize <$> hashFiles (SHA256.init) files)
- return $ BS.unpack $ Base16.encode $ SHA256.hash $
- renderPackageHashInputs $ PackageHashInputs
- {
- pkgHashPkgId = name
- , pkgHashComponent = pkgType pkg
- , pkgHashSourceHash = files_hash
- , pkgHashDirectDeps = Set.fromList depsHashes
- , pkgHashOtherConfig = other_config
- }
+ let hashInputs = PackageHashInputs
+ { pkgHashPkgId = name
+ , pkgHashComponent = pkgType pkg
+ , pkgHashSourceHash = files_hash
+ , pkgHashDirectDeps = Set.fromList depsHashes
+ , pkgHashOtherConfig = other_config
+ }
+ rendered = renderPackageHashInputs hashInputs
+
+ debugHash <- cmdDebugHashInputs
+ when debugHash $ do
+ root <- buildRoot
+ let debugDir = root -/- "hash-inputs"
+ debugFile = debugDir -/- name <.> "txt"
+ liftIO $ createDirectoryIfMissing True debugDir
+ liftIO $ BS.writeFile debugFile rendered
+ putNormal $ "Hash inputs for " ++ name ++ ":\n" ++ BS.unpack rendered
+
+ return $ BS.unpack $ Base16.encode $ SHA256.hash rendered
allFilesInDirectory :: FilePath -> Action [FilePath]
allFilesInDirectory dir = liftIO $ listFilesRecursive dir
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/046abdcdacda0a563bb1fa96f52f2e9…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/046abdcdacda0a563bb1fa96f52f2e9…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
Zubin pushed to branch wip/26416 at Glasgow Haskell Compiler / GHC
Commits:
046abdcd by Zubin Duggal at 2026-02-17T17:56:16+05:30
debug hash
- - - - -
2 changed files:
- hadrian/src/CommandLine.hs
- hadrian/src/Hadrian/Haskell/Hash.hs
Changes:
=====================================
hadrian/src/CommandLine.hs
=====================================
@@ -1,7 +1,7 @@
module CommandLine (
optDescrs, cmdLineArgsMap, cmdFlavour, lookupFreeze1, lookupFreeze2, lookupSkipDepends,
cmdBignum, cmdBignumCheck, cmdProgressInfo, cmdCompleteSetting,
- cmdDocsArgs, cmdUnitIdHash, lookupBuildRoot, TestArgs(..), TestSpeed(..), defaultTestArgs,
+ cmdDocsArgs, cmdUnitIdHash, cmdDebugHashInputs, lookupBuildRoot, TestArgs(..), TestSpeed(..), defaultTestArgs,
cmdPrefix, DocArgs(..), defaultDocArgs
) where
@@ -37,7 +37,8 @@ data CommandLineArgs = CommandLineArgs
, docsArgs :: DocArgs
, docTargets :: DocTargets
, prefix :: Maybe FilePath
- , completeStg :: Maybe String }
+ , completeStg :: Maybe String
+ , debugHashInputs :: Bool }
deriving (Eq, Show)
-- | Default values for 'CommandLineArgs'.
@@ -57,7 +58,8 @@ defaultCommandLineArgs = CommandLineArgs
, docsArgs = defaultDocArgs
, docTargets = Set.fromList [minBound..maxBound]
, prefix = Nothing
- , completeStg = Nothing }
+ , completeStg = Nothing
+ , debugHashInputs = False }
-- | These arguments are used by the `test` target.
data TestArgs = TestArgs
@@ -143,6 +145,9 @@ readUnitIdHash = Right $ \flags ->
trace "--hash-unit-ids is deprecated. It is enabled by release flavour or +hash_unit_ids flavour transformer" $
flags { unitIdHash = True }
+readDebugHashInputs :: Either String (CommandLineArgs -> CommandLineArgs)
+readDebugHashInputs = Right $ \flags -> flags { debugHashInputs = True }
+
readProgressInfo :: String -> Either String (CommandLineArgs -> CommandLineArgs)
readProgressInfo ms =
case lower ms of
@@ -278,6 +283,8 @@ optDescrs =
"Freeze Stage2 GHC."
, Option [] ["hash-unit-ids"] (NoArg readUnitIdHash)
"Include package hashes in unit ids."
+ , Option [] ["debug-hash-inputs"] (NoArg readDebugHashInputs)
+ "Debug: print and log hash inputs for each package."
, Option [] ["skip-depends"] (NoArg readSkipDepends)
"Skip rebuilding dependency information."
, Option [] ["bignum"] (OptArg readBignum "BACKEND")
@@ -401,5 +408,8 @@ cmdBignumCheck = bignumCheck <$> cmdLineArgs
cmdProgressInfo :: Action ProgressInfo
cmdProgressInfo = progressInfo <$> cmdLineArgs
+cmdDebugHashInputs :: Action Bool
+cmdDebugHashInputs = debugHashInputs <$> cmdLineArgs
+
cmdDocsArgs :: Action DocTargets
cmdDocsArgs = docTargets <$> cmdLineArgs
=====================================
hadrian/src/Hadrian/Haskell/Hash.hs
=====================================
@@ -34,6 +34,8 @@ import Control.Monad
import Base
import System.Directory.Extra (listFilesRecursive)
import Control.Arrow (first)
+import CommandLine (cmdDebugHashInputs)
+import System.Directory (createDirectoryIfMissing)
-- | Read a Cabal file and return the package identifier, e.g. @base-4.10.0.0-abcd@.
@@ -169,15 +171,25 @@ pkgHashOracle = void $ addOracleCache $ \(PkgHashKey (stag, pkg)) -> do
need files
files_hash <- liftIO (SHA256.finalize <$> hashFiles (SHA256.init) files)
- return $ BS.unpack $ Base16.encode $ SHA256.hash $
- renderPackageHashInputs $ PackageHashInputs
- {
- pkgHashPkgId = name
- , pkgHashComponent = pkgType pkg
- , pkgHashSourceHash = files_hash
- , pkgHashDirectDeps = Set.fromList depsHashes
- , pkgHashOtherConfig = other_config
- }
+ let hashInputs = PackageHashInputs
+ { pkgHashPkgId = name
+ , pkgHashComponent = pkgType pkg
+ , pkgHashSourceHash = files_hash
+ , pkgHashDirectDeps = Set.fromList depsHashes
+ , pkgHashOtherConfig = other_config
+ }
+ rendered = renderPackageHashInputs hashInputs
+
+ debugHash <- cmdDebugHashInputs
+ when debugHash $ do
+ root <- buildRoot
+ let debugDir = root -/- "hash-inputs"
+ debugFile = debugDir -/- name <.> "txt"
+ liftIO $ createDirectoryIfMissing True debugDir
+ liftIO $ BS.writeFile debugFile rendered
+ putNormal $ "Hash inputs for " ++ name ++ ":\n" ++ BS.unpack rendered
+
+ return $ BS.unpack $ Base16.encode $ SHA256.hash rendered
allFilesInDirectory :: FilePath -> Action [FilePath]
allFilesInDirectory dir = liftIO $ listFilesRecursive dir
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/046abdcdacda0a563bb1fa96f52f2e9…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/046abdcdacda0a563bb1fa96f52f2e9…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
10 Mar '26
Simon Peyton Jones pushed to branch wip/T26868 at Glasgow Haskell Compiler / GHC
Commits:
e1e28cd0 by Simon Peyton Jones at 2026-03-10T10:56:15+00:00
Comments only [skip ci]
- - - - -
1 changed file:
- compiler/GHC/Core/TyCo/FVs.hs
Changes:
=====================================
compiler/GHC/Core/TyCo/FVs.hs
=====================================
@@ -129,6 +129,10 @@ But we must take care (see #14880):
free variables. This is plain wrong. We must instead compute that b is free
and then conclude that b's kind is free.
+ BUT: there is no worry here any more because of Invariant (NoTypeShadowing).
+ in GHC.Core. In the example, the `forall k` shadows the `k` in
+ b's kind, which is now illegal and checked by Lint.
+
An obvious first approach is to compute the /shallow/ free variables of the type,
and /then/ close over kinds. But that turns out not to be very efficient.
Fortunately, there is a simpler way, which works with the accumulating
@@ -139,18 +143,20 @@ GHC.Types.Var.FV. At an occurrence of a variable (a::k)
* Check if `a` is already in the accumulator; if so, ignore it because we have
deal with its kind already. Also pre-checking set membership before inserting
- ends up not only being faster,
+ allocates less than just inserting, because the no-op case of insertion does
+ allocation.
* Otherwise add `a` to the accumulator,
AND add on the free vars of its kind `k`.
BUT in this latter step, start with an empty BoundVars set.
-This twist is implemented in `deepUnitFV`
-
-So now consider:
+The "start with an empty BoundVars set" is implemented in `deepUnitFV`. It's
+not /necessary/ to zap the BoundVars set, because of Invariant (NoTypeShadowing).
+But it's a tiny bit more efficient because the BoundVars set is smaller.
+Side note: the free-variable binder would still work even without (NoTypeShadowing).
+Consider:
forall k. b -> k
-
where b :: k->Type is free; but of course, it's a different k! When looking at
b -> k we'll have k in the bound-var set. So we'll ignore the k. But suppose
this is our first encounter with b; we want the free vars of its kind. But we
@@ -537,8 +543,6 @@ deepDetCoVarFolder = TyCoFolder { tcf_view = noView
* *
********************************************************************* -}
-------------- Closing over kinds -----------------
-
closeOverKinds :: TyCoVarSet -> TyCoVarSet
-- For each element of the input set,
-- add the deep free variables of its kind
@@ -553,60 +557,6 @@ closeOverKindsDSet vs = nonDetStrictFoldDVarSet do_one vs vs
where
do_one v = runFVAcc (deepDetTypeFV (varType v))
-{- --------------- Alternative version 1 (using FV) ------------
-closeOverKinds = fvVarSet . closeOverKindsFV . nonDetEltsUniqSet
--}
-
-{- ---------------- Alternative version 2 -------------
-
--- | Add the kind variables free in the kinds of the tyvars in the given set.
--- Returns a non-deterministic set.
-closeOverKinds :: TyCoVarSet -> TyCoVarSet
-closeOverKinds vs
- = go vs vs
- where
- go :: VarSet -- Work list
- -> VarSet -- Accumulator, always a superset of wl
- -> VarSet
- go wl acc
- | isEmptyVarSet wl = acc
- | otherwise = go wl_kvs (acc `unionVarSet` wl_kvs)
- where
- k v inner_acc = ty_co_vars_of_type (varType v) acc inner_acc
- wl_kvs = nonDetFoldVarSet k emptyVarSet wl
- -- wl_kvs = union of shallow free vars of the kinds of wl
- -- but don't bother to collect vars in acc
-
--}
-
-{- ---------------- Alternative version 3 -------------
--- | Add the kind variables free in the kinds of the tyvars in the given set.
--- Returns a non-deterministic set.
-closeOverKinds :: TyVarSet -> TyVarSet
-closeOverKinds vs = close_over_kinds vs emptyVarSet
-
-
-close_over_kinds :: TyVarSet -- Work list
- -> TyVarSet -- Accumulator
- -> TyVarSet
--- Precondition: in any call (close_over_kinds wl acc)
--- for every tv in acc, the shallow kind-vars of tv
--- are either in the work list wl, or in acc
--- Postcondition: result is the deep free vars of (wl `union` acc)
-close_over_kinds wl acc
- = nonDetFoldVarSet do_one acc wl
- where
- do_one :: Var -> TyVarSet -> TyVarSet
- -- (do_one v acc) adds v and its deep free-vars to acc
- do_one v acc | v `elemVarSet` acc
- = acc
- | otherwise
- = close_over_kinds (shallowTyCoVarsOfType (varType v)) $
- acc `extendVarSet` v
--}
-
-
-
{-
%************************************************************************
@@ -614,7 +564,6 @@ close_over_kinds wl acc
almostDevoidCoVarOfCo
%* *
%************************************************************************
-
-}
----- Whether a covar is /Almost Devoid/ in a type or coercion ----
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/e1e28cd0ef9baf22e4631d476d970b8…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/e1e28cd0ef9baf22e4631d476d970b8…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][ghc-9.12] 90 commits: wasm: prevent bundlers from resolving import("node:timers")
by Zubin (@wz1000) 10 Mar '26
by Zubin (@wz1000) 10 Mar '26
10 Mar '26
Zubin pushed to branch ghc-9.12 at Glasgow Haskell Compiler / GHC
Commits:
bac63be0 by amesgen at 2026-02-02T15:09:23+01:00
wasm: prevent bundlers from resolving import("node:timers")
This fixes the following esbuild error:
✘ [ERROR] Could not resolve "node:timers"
www/ghc_wasm_jsffi.js:66:25:
66 │ return (await import("node:timers")).setImmediate;
╵ ~~~~~~~~~~~~~
The package "node:timers" wasn't found on the file system but is built into node. Are you trying
to bundle for node? You can use "--platform=node" to do that, which will remove this error.
Previously (i.e. after !13503), one had to work around this by passing
`--external:node:timers`.
(cherry picked from commit f6493dbccc7bf95dcdf946b978e262f739e3e15a)
- - - - -
4a1e98c9 by Simon Peyton Jones at 2026-02-02T15:09:23+01:00
Fix in-scope set for CSE
Ticket #25468 showed an assertion failure in CSE because a top-level
Id was being used before it was defined. Reason: Note [Glomming] in
GHC.Core.Opt.OccurAnal.
Solution (used in many places): just put all the top-level bindings in
scope at the beginning of CSE.
Compile-time allocation wobbles up and down a tiny bit; geo mean is
zero. But MultiLayerModulesTH_OneShot and hard_hole_fits increase (on
some architectures only) by a bit oever 2% . I think these are just a
random fluctuations.
Metric Increase:
MultiLayerModulesTH_OneShot
hard_hole_fits
(cherry picked from commit c02b1e4620493eee1f6d6d71bead4af9d7246845)
- - - - -
cf8f041a by Sven Tennie at 2026-02-02T15:09:23+01:00
Add reproducer for dealloc instructions in switch table jump expressions (#25733)
Measures taken to make the test stable:
- Use 'a' as variable prefix, because X86 32bit stumbled over the
variable name 'i386'
- Flush stdout to make test output deterministic
- Use type annotations to support 32bit archs
(cherry picked from commit 39e51ddbc03afda71608bcef75c64f57c6175183)
- - - - -
5404575e by Matthew Pickering at 2026-02-02T15:09:23+01:00
testsuite: Add test for :steplocal performance
This adds a simple test which exercises #25779
(cherry picked from commit 7f358f25ad5604c6e6053f880ca7057690ebd864)
- - - - -
bccd7a3e by Andreas Klebinger at 2026-03-03T21:22:01+05:30
Interpreter: Add limited support for direct primop evaluation.
This commit adds support for a number of primops directly
to the interpreter. This avoids the indirection of going
through the primop wrapper for those primops speeding interpretation
of optimized code up massively.
Code involving IntSet runs about 25% faster with optimized core and these
changes. For core without breakpoints it's even more pronouced and I
saw reductions in runtime by up to 50%.
Running GHC itself in the interpreter was sped up by ~15% through this
change.
Additionally this comment does a few other related changes:
testsuite:
* Run foundation test in ghci and ghci-opt ways to test these
primops.
* Vastly expand the foundation test to cover all basic primops
by comparing result with the result of calling the wrapper.
Interpreter:
* When pushing arguments for interpreted primops extend each argument to
at least word with when pushing. This avoids some issues with big
endian. We can revisit this if it causes performance issues.
* Restructure the stack chunk check logic. There are now macros for
read accesses which might cross stack chunk boundries and macros which
omit the checks which are used when we statically know we access an
address in the current stack chunk.
(cherry picked from commit 202b201c968de68f864f4c8abbfec713f8ffd323)
- - - - -
63f04c09 by Ben Gamari at 2026-03-03T21:22:01+05:30
base: Expose Backtraces constructor and fields
This was specified in the proposal (CLC #199) yet somehow didn't make it
into the implementation.
Fixes #26049.
(cherry picked from commit 17db44c5b32fff82ea988fa4f1a233d1a27bdf57)
- - - - -
bf460d1f by Mario Blažević at 2026-03-03T21:22:01+05:30
Introduce parenBreakableList and use it in ppHsContext
(cherry picked from commit 7b64697c12fb3054067c98c41d6d26441cfa20e5)
- - - - -
4ce3a7fb by fendor at 2026-03-03T21:22:01+05:30
Bump GHC on darwin CI to 9.10.1
(cherry picked from commit 358bc4fc8324a0685f336142d0d608cbd51d54f9)
- - - - -
36516e6c by Simon Peyton Jones at 2026-03-03T21:22:02+05:30
Take more care in zonkEqTypes on AppTy/AppTy
This patch fixes #26256.
See Note [zonkEqTypes and the PKTI] in GHC.Tc.Solver.Equality
(cherry picked from commit 18036d5205ac648bb245217519fed2fd931a9982)
- - - - -
ead68b1d by fendor at 2026-03-03T21:22:02+05:30
Store `StackTrace` and `StackSnapshot` in `Backtraces`
Instead of decoding the stack traces when collecting the `Backtraces`,
defer this decoding until actually showing the `Backtraces`.
This allows users to customise how `Backtraces` are displayed by
using a custom implementation of `displayExceptionWithInfo`, overwriting
the default implementation for `Backtraces` (`displayBacktraces`).
(cherry picked from commit c91e26500ab0e1b8b67c1d374f657523c7c15f55)
- - - - -
230f93b6 by fendor at 2026-03-03T21:22:02+05:30
Allow users to customise the collection of exception annotations
Add a global `CollectExceptionAnnotationMechanism` which determines how
`ExceptionAnnotation`s are collected upon throwing an `Exception`.
This API is exposed via `ghc-experimental`.
By overriding how we collect `Backtraces`, we can control how the
`Backtraces` are displayed to the user by newtyping `Backtraces` and
giving a different instance for `ExceptionAnnotation`.
A concrete use-case for this feature is allowing us to experiment with
alternative stack decoders, without having to modify `base`, which take
additional information from the stack frames.
This commit does not modify how `Backtraces` are currently
collected or displayed.
(cherry picked from commit dee28cdd794652a3ebc271184e2ab3c866b5e219)
- - - - -
e829a12f by fendor at 2026-03-03T21:22:02+05:30
Expose Backtraces internals from ghc-experimental
Additionally, expose the same API `base:Control.Exception.Backtrace`
to make it easier to use as a drop-in replacement.
(cherry picked from commit 6602472273e1cdffcdb7753c9133047e571896bd)
- - - - -
b8c936fd by Zubin Duggal at 2026-03-03T21:22:02+05:30
testsuite: Be more permissive when filtering out GNU_PROPERTY_TYPE linker warnings
The warning text is slightly different with ld.bfd.
Fixes #26249
(cherry picked from commit 51c701fef034e2062809eed5de3a51bb0a4243ba)
- - - - -
08fdd10d by Cheng Shao at 2026-03-03T21:22:02+05:30
hadrian: enforce have_llvm=False for wasm32/js
This patch fixes hadrian to always pass have_llvm=False to the
testsuite driver for wasm32/js targets. These targets don't really
support the LLVM backend, and the optllvm test way doesn't work. We
used to special-case wasm32/js to avoid auto-adding optllvm way in
testsuite/config/ghc, but this is still problematic if someone writes
a new LLVM-related test and uses something like when(have_llvm(),
extra_ways(["optllvm"])). So better just enforce have_llvm=False for
these targets here.
(cherry picked from commit 1cdc6f46c4168dd92a8f5ea0c398b67fc59449a9)
- - - - -
e5e992aa by Cheng Shao at 2026-03-03T21:22:02+05:30
libffi: update to 3.5.2
Bumps libffi submodule.
(cherry picked from commit 45dbfa23f508f221b6aeb667783a928511a7654e)
- - - - -
6c53d508 by Cheng Shao at 2026-03-03T21:22:02+05:30
wasm: ensure setKeepCAFs() is called in ghci
This patch is a critical bugfix for #26106, see comment and linked
issue for details.
(cherry picked from commit 10f06163d9adcb3b6e6438f1524faaca3bf6c3b2)
- - - - -
71074efc by sheaf at 2026-03-03T21:22:02+05:30
Use tcMkScaledFunTys in matchExpectedFunTys
We should use tcMkScaledFunTys rather than mkScaledFunTys in
GHC.Tc.Utils.Unify.matchExpectedFunTys, as the latter crashes
when the kind of the result type is a bare metavariable.
We know the result is always Type-like, so we don't need scaledFunTys
to try to rediscover that from the kind.
Fixes #26277
(cherry picked from commit 624afa4a65caa8ec23f85e70574dfb606f90c173)
- - - - -
9adfadee by sheaf at 2026-03-03T21:22:02+05:30
Improve Notes about disambiguating record updates
This commit updates the notes [Disambiguating record updates] and
[Type-directed record disambiguation], in particular adding more
information about the deprecation status of type-directed disambiguation
of record updates.
(cherry picked from commit a2d9d7c2073867ee0cabb8d49f93246d95ec0b09)
- - - - -
618d313d by sheaf at 2026-03-03T21:22:02+05:30
Add test for #26216
(cherry picked from commit 2e73f3426ab6e3cf1938b53831005593f3fd351c)
- - - - -
6daa51da by Vladislav Zavialov at 2026-03-03T21:22:02+05:30
Fix PREP_MAYBE_LIBRARY in prep_target_file.m4
This change fixes a configure error introduced in:
commit 8235dd8c4945db9cb03e3be3c388d729d576ed1e
ghc-toolchain: Move UseLibdw to per-Target file
Now the build no longer fails with:
acghc-toolchain: Failed to read a valid Target value from hadrian/cfg/default.target
(cherry picked from commit 1480872af6b80db1b035a44409188416df041048)
- - - - -
be85e2f2 by Cheng Shao at 2026-03-03T21:22:02+05:30
rts: remove obsolete CC_SUPPORTS_TLS logic
This patch removes obsolete CC_SUPPORTS_TLS logic throughout the rts,
given __thread is now uniformly supported by C toolchains of all
platforms we currently support.
(cherry picked from commit 0f034942724233e1457549123b46880f7b93e805)
- - - - -
8d60d8cb by Cheng Shao at 2026-03-03T21:22:02+05:30
rts: remove obsolete HAS_VISIBILITY_HIDDEN logic
This patch removes obsolete HAS_VISIBILITY_HIDDEN logic throughout the
rts, given __attribute__((visibility("hidden"))) is uniformly
supported by C toolchains of all platforms we currently support.
(cherry picked from commit ef7056554df5603ec4d1e33193abe953970e6ab3)
- - - - -
00ff6203 by Cheng Shao at 2026-03-03T21:22:02+05:30
rts: remove -O3 pragma hack in Hash.c
This patch removes an obsolete gcc pragma to specify -O3 in Hash.c.
Hadrian already passes the right flag.
(cherry picked from commit 9fdc1f7d855cc61f90de909875f6ae0d6798dca7)
- - - - -
a932ffce by Cheng Shao at 2026-03-03T21:22:02+05:30
wasm: fix dyld handling for forward declared GOT.func items
This patch fixes wasm shared linker's handling of forward declared
GOT.func items, see linked issue for details. Also adds T26430 test to
witness the fix. Fixes #26430.
Co-authored-by: Codex <codex(a)openai.com>
(cherry picked from commit 867c26755e8855c6df949e65df0c2aebc9da64c3)
- - - - -
792c400d by Cheng Shao at 2026-03-03T21:22:02+05:30
rts: remove obsolete __GNUC__ related logic
This patch removes obsolete `__GNUC__` related logic, given on any
currently supported platform and toolchain, `__GNUC__ >= 4` is
universally true. Also pulls some other weeds and most notably, use
`__builtin___clear_cache` for clang as well, since clang has supported
this gcc intrinsic since 2014, see
https://github.com/llvm/llvm-project/commit/c491a8d4577052bc6b3b4c72a7db6a7….
(cherry picked from commit 67de53a6ced23caad640d2c7421089242f0dfb76)
- - - - -
05a2ea3a by Cheng Shao at 2026-03-03T21:22:02+05:30
hadrian: fix GHC.Platform.Host generation for cross stage1
This patch fixes incorrectly GHC.Platform.Host generation logic for
cross stage1 in hadrian (#26449). Also adds T26449 test case to
witness the fix.
Co-authored-by: Codex <codex(a)openai.com>
(cherry picked from commit 8cbe006ad09d5a64e4a3cdf4c91a8b81ff1511be)
- - - - -
b1b86f5e by Luite Stegeman at 2026-03-03T21:22:02+05:30
rts: Fix lost wakeups in threadPaused for threads blocked on black holes
The lazy blackholing code in threadPaused could overwrite closures
that were already eagerly blackholed, and as such wouldn't have a
marked update frame. If the black hole was overwritten by its
original owner, this would lead to an undetected collision, and
the contents of any existing blocking queue being lost.
This adds a check for eagerly blackholed closures and avoids
overwriting their contents.
Fixes #26324
(cherry picked from commit a1de535f762bc23d4cf23a5b1853591dda12cdc9)
- - - - -
ce70dd20 by Luite Stegeman at 2026-03-03T21:22:02+05:30
rts: push the correct update frame in stg_AP_STACK
The frame contains an eager black hole (__stg_EAGER_BLACKHOLE_info) so
we should push an stg_bh_upd_frame_info instead of an stg_upd_frame_info.
(cherry picked from commit b7e21e498d39e0ee764e3237544b4c39ddf98467)
- - - - -
49280208 by Cheng Shao at 2026-03-03T21:22:02+05:30
testsuite: remove unused expected output files
This patch removes unused expected output files in the testsuites on
platforms that we no longer support.
(cherry picked from commit 6992ac097b9da989f125f896afe21b75dba8b4c9)
- - - - -
728e0f04 by Ben Gamari at 2026-03-03T21:22:02+05:30
rts/posix: Enforce iteration limit on heap reservation logic
Previously we could loop indefinitely when attempting to get an address
space reservation for our heap. Limit the logic to 8 iterations to
ensure we instead issue a reasonable error message.
Addresses #26151.
(cherry picked from commit ff1650c96c61af02e193854312a9ccd303968e47)
- - - - -
ad59d234 by Ben Gamari at 2026-03-03T21:22:02+05:30
rts/posix: Hold on to low reservations when reserving heap
Previously when the OS gave us an address space reservation in low
memory we would immediately release it and try again. However, on some
platforms this meant that we would get the same allocation again in the
next iteration (since mmap's `hint` argument is just that, a hint).
Instead we now hold on to low reservations until we have found a
suitable heap reservation.
Fixes #26151.
(cherry picked from commit 0184455728f841a699648f879fdb29128081fc6b)
- - - - -
57b614ec by Julian Ospald at 2026-03-03T21:22:02+05:30
ghc-toolchain: Drop `ld.gold` from merge object command
It's deprecated.
Also see #25716
(cherry picked from commit c58f9a615f05e9d43629f6e846ae22cad2a6163d)
- - - - -
80e12dcc by Ben Gamari at 2026-03-03T21:22:02+05:30
gitlab-ci: Make RELEASE_JOB an input
Rather than an undocumented variable.
(cherry picked from commit f9790ca81deb8b14ff2eabf701aecbcfd6501963)
- - - - -
cc5186b0 by Cheng Shao at 2026-03-03T21:22:02+05:30
testsuite: fix T3586 for non-SSE3 platforms
`T3586.hs` contains `-fvia-C -optc-msse3` which I think is a
best-effort basis to harvest the C compiler's auto vectorization
optimizations via the C backend back when the test was added. The
`-fvia-C` part is now a deprecated no-op because GHC can't fall back
to the C backend on a non-unregisterised build, and `-optc-msse3`
might actually cause the test to fail on non x86/x64 platforms, e.g.
recent builds of wasi-sdk would report `wasm32-wasi-clang: error:
unsupported option '-msse3' for target 'wasm32-unknown-wasi'`.
So this patch cleans up this historical cruft. `-fvia-C` is removed,
and `-optc-msse3` is only passed when cpuid contains `pni` (which
indicates support of SSE3).
(cherry picked from commit 70ee825a516bcf7aac762bfedb4a017d35f8dcf3)
- - - - -
f24ff1de by Julian Ospald at 2026-03-03T21:22:02+05:30
Improve error handling in 'getPackageArchives'
When the library dirs in the package conf files are not set up correctly,
the JS linker will happily ignore such packages and not link against them,
although they're part of the link plan.
Fixes #26383
(cherry picked from commit 91b6be10bd58c2bfc1c7c22e81b06ab3be583228)
- - - - -
139ccc08 by Ben Gamari at 2026-03-03T21:22:02+05:30
rts: Annotate BCOs with their Name
This introduces a new bytecode instruction, `BCO_NAME`, to aid in debugging
bytecode execution. This instruction is injected by `mkProtoBCO` and
captures the Haskell name of the BCO. It is then printed by the
disassembler, allowing ready correlation with STG dumps.
(cherry picked from commit 5192a75fe9b272e8b1ef290fa834714c81bd1f79)
- - - - -
17275b20 by sheaf at 2026-03-03T21:22:02+05:30
Bad record update msg: allow out-of-scope datacons
This commit ensures that, when we encounter an invalid record update
(because no constructor exists which contains all of the record fields
mentioned in the record update), we graciously handle the situation in
which the constructors themselves are not in scope. In that case,
instead of looking up the constructors in the GlobalRdrEnv, directly
look up their GREInfo using the lookupGREInfo function.
Fixes #26391
(cherry picked from commit cef8938f3c0d22583f01d5ea29e6109bccd36040)
- - - - -
992ee39a by Cheng Shao at 2026-03-03T21:22:02+05:30
rts: remove obsolete COMPILING_WINDOWS_DLL logic
This patch removes obsolete COMPILING_WINDOWS_DLL logic throughout the
rts. They were once used for compiling to win32 DLLs, but we haven't
been able to compile Haskell units to win32 DLLs for many years now,
due to PE format's restriction of no more than 65536 exported symbols
in a single DLL.
(cherry picked from commit b8cfa8f741729ef123569fb321c4b2ab4a1a941c)
- - - - -
ba0ec0e8 by Julian Ospald at 2026-03-03T21:22:02+05:30
Skip uniques test if sources are not available
(cherry picked from commit 5dc2e9eaf60fd72771bf2e8112aec182665461a1)
- - - - -
edf8a6b0 by Julian Ospald at 2026-03-03T21:22:02+05:30
rts: remove unneccesary cabal flags
We perform those checks via proper autoconf macros
instead that do the right thing and then add those
libs to the rts buildinfo.
(cherry picked from commit 643ce801a8b559071683cad0e5adbc26b9fc8385)
- - - - -
b2b97d29 by Wang Xin at 2026-03-03T21:22:02+05:30
Add -mcmodel=medium moduleflag to generated LLVM IR on LoongArch platform
With the Medium code model, the jump range of the generated jump
instruction is larger than that of the Small code model. It's a
temporary fix of the problem descriped in https://gitlab.haskell
.org/ghc/ghc/-/issues/25495. This commit requires that the LLVM
used contains the code of commit 9dd1d451d9719aa91b3bdd59c0c6679
83e1baf05, i.e., version 8.0 and later. Actually we should not
rely on LLVM, so the only way to solve this problem is to implement
the LoongArch backend.
Add new type for codemodel
(cherry picked from commit e70d41406b5d5638b42c4d8222cd03e76bbfeb86)
- - - - -
092a603d by Peng Fan at 2026-03-03T21:22:02+05:30
Pass the mcmodel=medium parameter to CC via GHC
Ensure that GHC-driver builds default to mcmodel=medium, so that GHC
passes this default parameter to CC without having to add it to the
compiled project.
Commit e70d41406b5d5638b42c4d8222cd03e76bbfeb86 does not ensure that all
GHC-built object files have a default model of medium, and will raise an
R_LARCH_B26 overflow error.
(cherry picked from commit 1a3f11314cc7b8dbf9af03dd2ae2cb066a998d63)
- - - - -
e18faa95 by Ben Gamari at 2026-03-03T21:22:02+05:30
gitlab-ci: Run ghcup-metadata jobs on OpenCape runners
This significantly reduces our egress traffic
and makes the jobs significantly faster.
(cherry picked from commit ff3f0d09bce1c261638b572af2bac1d87f1f6df7)
- - - - -
f162eb8f by Luite Stegeman at 2026-03-03T21:22:02+05:30
rts: fix eager black holes: record mutated closure and fix assertion
This fixes two problems with handling eager black holes, introduced
by a1de535f762bc23d4cf23a5b1853591dda12cdc9.
- the closure mutation must be recorded even for eager black holes,
since the mutator has mutated it before calling threadPaused
- The assertion that an unmarked eager black hole must be owned by
the TSO calling threadPaused is incorrect, since multiple threads
can race to claim the black hole.
fixes #26495
(cherry picked from commit 3ba3d9f9db784c903ebe8fd617447ce62d30b7d3)
- - - - -
1b5d5d6e by ARATA Mizuki at 2026-03-03T21:22:03+05:30
LLVM backend: Pass the +evex512 attribute to LLVM 18+ if -mavx512f is set
The newer LLVM requires the +evex512 attribute to enable use of ZMM registers.
LLVM exhibits a backward-compatible behavior if the cpu is `x86-64`, but not if `penryn`.
Therefore, on macOS, where the cpu is set to `penryn`, we need to explicitly pass +evex512.
Fixes #26410
(cherry picked from commit b22777d4b7182f40a31eb430fa27f5fb9ef0f292)
- - - - -
2220a9b7 by Matthew Pickering at 2026-03-03T21:22:03+05:30
hadrian: Use a response file to invoke GHC for dep gathering.
In some cases we construct an argument list too long for GHC to
handle directly on windows. This happens when we generate
the dependency file because the command line will contain
references to a large number of .hs files.
To avoid this we now invoke GHC using a response file when
generating dependencies to sidestep length limitations.
Note that we only pass the actual file names in the dependency
file. Why? Because this side-steps #26560
(cherry picked from commit 9d371d23c526fd160d7e99bef2bc7da825cf3c0f)
- - - - -
cb56617c by Andreas Klebinger at 2026-03-03T21:22:03+05:30
Add hpc to release script
(cherry picked from commit 64ec82ffa7f48399e18fcec43051d2b7ddcb7cc2)
- - - - -
17dd9b2b by Matthew Pickering at 2026-03-03T21:22:03+05:30
rts: Fix a deadlock with eventlog flush interval and RTS shutdown
The ghc_ticker thread attempts to flush at the eventlog tick interval, this requires
waiting to take all capabilities.
At the same time, the main thread is shutting down, the schedule is
stopped and then we wait for the ticker thread to finish.
Therefore we are deadlocked.
The solution is to use `newBoundTask/exitMyTask`, so that flushing can
cooperate with the scheduler shutdown.
Fixes #26573
(cherry picked from commit b7fe744598b4569cd0236268e4f6f5b9d27e12b7)
- - - - -
85ffa1a5 by Julian Ospald at 2026-03-03T21:22:03+05:30
rts: Fix object file format detection in loadArchive
Commit 76d1041dfa4b96108cfdd22b07f2b3feb424dcbe seems to
have introduced this bug, ultimately leading to failure of
test T11788. I can only theorize that this test isn't run
in upstream's CI, because they don't build a static GHC.
The culprit is that we go through the thin archive, trying
to follow the members on the filesystem, but don't
re-identify the new object format of the member. This pins
`object_fmt` to `NotObject` from the thin archive.
Thanks to @angerman for spotting this.
(cherry picked from commit fc958fc9eb6f6f4db473cdda23c381da8f32163d)
- - - - -
e26515de by Simon Peyton Jones at 2026-03-03T21:22:03+05:30
Add missing InVar->OutVar lookup in SetLevels
As #26681 showed, the SetLevels pass was failing to map an InVar to
an OutVar. Very silly! I'm amazed it hasn't broken before now.
I have improved the type singatures (to mention InVar and OutVar)
so it's more obvious what needs to happen.
(cherry picked from commit 52d00c05e1d803b36c93295399fe931c871166bf)
- - - - -
dcf082dd by Cheng Shao at 2026-03-03T21:22:03+05:30
compiler: change sectionProtection to take SectionType argument
This commit changes `sectionProtection` to only take `SectionType`
argument instead of whole `Section`, since it doesn't need the Cmm
section content anyway, and it can then be called in parts of NCG
where we only have a `SectionType` in scope.
(cherry picked from commit 2433e91d41675d56f48f82d22430a8dee915e7a0)
- - - - -
19b88fab by Cheng Shao at 2026-03-03T21:22:03+05:30
compiler: change isInitOrFiniSection to take SectionType argument
This commit changes `isInitOrFiniSection` to only take `SectionType`
argument instead of whole `Section`, since it doesn't need the Cmm
section content anyway, and it can then be called in parts of NCG
where we only have a `SectionType` in scope. Also marks it as
exported.
(cherry picked from commit e5926fbebf341ee547227d41710d78471eecd09c)
- - - - -
b492c847 by Cheng Shao at 2026-03-03T21:22:03+05:30
compiler: fix split sections on windows
This patch fixes split sections on windows by emitting the right
COMDAT section header in NCG, see added comment for more explanation.
Fix #26696 #26494.
-------------------------
Metric Decrease:
LargeRecord
T9675
size_hello_artifact
size_hello_artifact_gzip
size_hello_unicode
size_hello_unicode_gzip
Metric Increase:
T13035
-------------------------
Co-authored-by: Codex <codex(a)openai.com>
(cherry picked from commit 244d57d79a555dcecc7590287bb14976d561291a)
- - - - -
133b829f by Matthew Pickering at 2026-03-03T21:22:03+05:30
rts: Use INFO_TABLE_CONSTR for stg_dummy_ret_closure
Since the closure type is CONSTR_NOCAF, we need to use INFO_TABLE_CONSTR
to populate the constructor description field (this crashes ghc-debug
when decoding AP_STACK frames sometimes)
Fixes #26745
(cherry picked from commit 322dd6726b11c7101c28ffb8aeb7cb4cee34ab56)
- - - - -
055db6f2 by Matthew Pickering at 2026-03-03T21:22:03+05:30
Evaluate backtraces for "error" exceptions at the moment they are thrown
See Note [Capturing the backtrace in throw] and
Note [Hiding precise exception signature in throw] which explain the
implementation.
This commit makes `error` and `throw` behave the same with regard to
backtraces. Previously, exceptions raised by `error` would not contain
useful IPE backtraces.
I did try and implement `error` in terms of `throw` but it started to
involve putting diverging functions into hs-boot files, which seemed to
risky if the compiler wouldn't be able to see if applying a function
would diverge.
CLC proposal: https://github.com/haskell/core-libraries-committee/issues/383
Fixes #26751
(cherry picked from commit 94dcd15e54146abecf9b4f5e47d258ca3cd40f1b)
- - - - -
bdeb6030 by fendor at 2026-03-03T21:22:03+05:30
Remove `traceId` from ghc-pkg executable
(cherry picked from commit d0966e64880e9fa30ce07c0fa5ea28108c6e8ad9)
- - - - -
59cc8e68 by sheaf at 2026-03-03T21:22:03+05:30
Don't re-use stack slots for growing registers
This commit avoids re-using a stack slot for a register that has grown
but already had a stack slot.
For example, suppose we have stack slot assigments
%v1 :: FF64 |-> StackSlot 0
%v2 :: FF64 |-> StackSlot 1
Later, we start using %v1 at a larger format (e.g. F64x2) and we need
to spill it again. Then we **must not** use StackSlot 0, as a spill
at format F64x2 would clobber the data in StackSlot 1.
This can cause some fragmentation of the `StackMap`, but that's probably
OK.
Fixes #26668
(cherry picked from commit 023c301c51e7346af3d4d773c448277ad3645ad2)
- - - - -
c75b616e by Cheng Shao at 2026-03-03T21:22:03+05:30
llvm: fix split sections for llvm backend
This patch fixes split sections for llvm backend:
- Pass missing `--data-sections`/`--function-sections` flags to
llc/opt.
- Use `(a)llvm.compiler.used` instead of `(a)llvm.used` to avoid sections
being unnecessarily retained at link-time.
Fixes #26770.
-------------------------
Metric Decrease:
libdir
size_hello_artifact
size_hello_unicode
-------------------------
Co-authored-by: Codex <codex(a)openai.com>
(cherry picked from commit b18b2c42c32488ad6d3480a56a1fcd753cad2023)
- - - - -
c7f7e692 by Matthew Pickering at 2026-03-03T21:22:03+05:30
Fix ghc-experimental GHC.Exception.Backtrace.Experimental module
This module wasn't added to the cabal file so it was never compiled or
included in the library.
(cherry picked from commit ee937134aa0ddf35c1a9dc7334c0aec0de13b719)
- - - - -
c16b52c5 by Sylvain Henry at 2026-03-03T21:22:03+05:30
GC: don't use CAS without PARALLEL_GC on
If we're not using the parallel GC, there is no reason to do a costly
CAS. This was flagged as taking time in a perf profile.
(cherry picked from commit 0491f08a965df0d6448bd9cd940d2b86fca2db5d)
- - - - -
03a8a5f9 by Sylvain Henry at 2026-03-03T21:22:03+05:30
GC: suffix parallel GC with "par" instead of "thr"
Avoid some potential confusion (see discussion in !15351).
(cherry picked from commit 211a8f5633f0a5069c0689171f60b57719a242be)
- - - - -
cd6a8dae by Cheng Shao at 2026-03-03T21:22:03+05:30
testsuite: avoid re.sub in favor of simple string replacements
This patch refactors the testsuite driver and avoids the usage of
re.sub in favor of simple string replacements when possible. The
changes are not comprehensive, and there are still a lot of re.sub
usages lingering around the tree, but this already addresses a major
performance bottleneck in the testsuite driver that might has to do
with quadratic or worse slowdown in cpython's regular expression
engine when handling certain regex patterns with large strings.
Especially on i386, and i386 jobs are the bottlenecks of all full-ci
validate pipelines!
Here are the elapsed times of testing x86_64/i386 with -j48 before
this patch:
x86_64: `Build completed in 6m06s`
i386: `Build completed in 1h36m`
And with this patch:
x86_64: `Build completed in 4m55s`
i386: `Build completed in 4m23s`
Fixes #26786.
Co-authored-by: Codex <codex(a)openai.com>
(cherry picked from commit ca79475f6b4dfba991e2c933bac9c22d54a4950d)
- - - - -
8f1dcca2 by Zubin Duggal at 2026-03-03T21:22:03+05:30
hadrian: Add ghc-{experimental,internal}.cabal to the list of dependencies of the doc target
We need these files to detect the version of these libraries
Fixes #26738
(cherry picked from commit 1b490f5a7bbdb1441948241e6089b31efba9db45)
- - - - -
1b6763b1 by Jessica Clarke at 2026-03-03T21:22:03+05:30
PPC NCG: Use libcall for 64-bit cmpxchg on 32-bit PowerPC
There is no native instruction for this, and even if there were a
register pair version we could use, the implementation here is assuming
the values fit in a single register, and we end up only using / defining
the low halves of the registers.
Fixes: b4d39adbb5 ("PrimOps: Add CAS op for all int sizes")
Fixes: #23969
(cherry picked from commit ce2d62fba69d2ea0c74c46c50628feb8b81719d2)
- - - - -
dd0e0021 by John Paul Adrian Glaubitz at 2026-03-03T21:22:03+05:30
rts: Switch prim to use modern atomic compiler builtins
The __sync_*() atomic compiler builtins have been deprecated in GCC
for a while now and also don't provide variants for 64-bit values
such as __sync_fetch_and_add_8().
Thus, replace them with the modern __atomic_*() compiler builtins and
while we're at it, also drop the helper macro CAS_NAND() which is now
no longer needed since we stopped using the __sync_*() compiler builtins
altogether.
Co-authored-by: Ilias Tsitsimpis <iliastsi(a)debian.org>
Fixes #26729
(cherry picked from commit 7c52c4f9bc8d6ae6404039ec02efe48fbf7a4778)
- - - - -
1d0e18e6 by sterni at 2026-03-03T21:22:03+05:30
users_guide: fix runtime error during build with Sphinx 9.1.0
Appears that pathto is stricter about what it accepts now.
Tested Sphinx 8.2.3 and 9.1.0 on the ghc-9.10 branch.
Resolves #26810.
Co-authored-by: Martin Weinelt <hexa(a)darmstadt.ccc.de>
(cherry picked from commit e8f5a45de561ec80c88cd3da2c66502deb32d4c3)
- - - - -
ef151f0d by Michael Karcher at 2026-03-03T21:22:03+05:30
NCG for PPC: add pattern for CmmRegOff to iselExpr64
Closes #26828
(cherry picked from commit 43d977619de65c0cf87695fa5d86f1a3ff3176c3)
- - - - -
50c6836b by Matthew Pickering at 2026-03-03T21:22:03+05:30
determinism: Use deterministic map for Strings in TyLitMap
When generating typeable evidence the types we need evidence for all
cached in a TypeMap, the order terms are retrieved from a type map
determines the order the bindings appear in the program.
A TypeMap is quite diligent to use deterministic maps, apart from in the
TyLitMap, which uses a UniqFM for storing strings, whose ordering
depends on the Unique of the FastString.
This can cause non-deterministic .hi and .o files.
An unexpected side-effect is the error message but RecordDotSyntaxFail8
changing. I looked into this with Sam and this change caused the
constraints to be solved in a different order which results in a
slightly different error message. I have accepted the new test, since
the output before was non-deterministic and the new output is consistent
with the other messages in that file.
Fixes #26846
(cherry picked from commit aeeb4a2034e80e26503eb88f5abde85e87a82f7b)
- - - - -
0a356c08 by Andrew Lelechenko at 2026-03-03T21:22:03+05:30
Upgrade text submodule to 2.1.4
(cherry picked from commit 9e4d70c2764d117c5cf753127f93056d66e4f0d7)
- - - - -
9d4e88a2 by Zubin Duggal at 2026-03-03T21:22:03+05:30
Bump transformers submodule to 0.6.3.0
Fixes #26790
(cherry picked from commit ea0d1317a630799a6b7bea12b24ef7e1ea6ed512)
- - - - -
bd510e4d by Matthew Pickering at 2026-03-03T21:22:03+05:30
determinism: Use a stable sort in WithHsDocIdentifiers binary instance
`WithHsDocIdentifiers` is defined as
```
71 data WithHsDocIdentifiers a pass = WithHsDocIdentifiers
72 { hsDocString :: !a
73 , hsDocIdentifiers :: ![Located (IdP pass)]
74 }
```
This list of names is populated from `rnHsDocIdentifiers`, which calls
`lookupGRE`, which calls `lookupOccEnv_AllNameSpaces`, which calls
`nonDetEltsUFM` and returns the results in an order depending on
uniques.
Sorting the list with a stable sort before returning the interface makes
the output deterministic and follows the approach taken by other fields
in `Docs`.
Fixes #26858
(cherry picked from commit 0020e38a021b5f0371c48fe73cddf8987acb1eb1)
- - - - -
03eb3918 by Simon Peyton Jones at 2026-03-03T21:22:03+05:30
Fix subtle bug in cast worker/wrapper
See (CWw4) in Note [Cast worker/wrapper].
The true payload is in the change to the definition of
GHC.Types.Id.Info.hasInlineUnfolding
Everthing else is just documentation.
There is a 2% compile time decrease for T13056;
I'll take the win!
Metric Decrease:
T13056
(cherry picked from commit 99d8c146c12146e1e21b1f2d31809845d4afe9d4)
- - - - -
c74d75f4 by Cheng Shao at 2026-03-03T21:22:03+05:30
wasm: use import.meta.main for proper distinction of nodejs main modules
This patch uses `import.meta.main` for proper distinction of nodejs
main modules, especially when the main module might be installed as a
symlink. Fixes #26916.
(cherry picked from commit 039f19778e35b193af0de2a2c6ed89556038627a)
- - - - -
451c6a43 by Simon Peyton Jones at 2026-03-04T12:15:09+05:30
Fix a horrible shadowing bug in implicit parameters
Fixes #26451. The change is in GHC.Tc.Solver.Monad.updInertDicts
where we now do /not/ delete /Wanted/ implicit-parameeter constraints.
This bug has been in GHC since 9.8! But it's quite hard to provoke;
I contructed a tests in T26451, but it was hard to do so.
(cherry picked from commit c052c724d2dfc994994b6548545836969aee8ed8)
- - - - -
85b0aae2 by Simon Peyton Jones at 2026-03-04T12:15:09+05:30
Fix subtle bug in GHC.Core.Utils.mkTick
This patch fixes a decade-old bug in `mkTick`, which
could generate type-incorrect code! See the diagnosis
in #26772.
The new code is simpler and easier to understand.
(As #26772 says, I think it could be improved further.)
(cherry picked from commit cbe4300ef586c8bee1800426624db12e0237c6b5)
- - - - -
55885e4b by Simon Peyton Jones at 2026-03-04T12:15:09+05:30
Fix long-standing interaction between ticks and casts
The code for Note [Eliminate Identity Cases] was simply wrong when
ticks and casts interacted. This patch fixes the interaction.
It was shown up when validating #26772, although it's not the exactly
the bug that's reported by #26772. Nor is it easy to reproduce, hence
no regression test.
(cherry picked from commit b579dfdc614e288b0fd754ac69ae7ff723d808be)
- - - - -
4fdab7ca by sheaf at 2026-03-04T12:15:09+05:30
NamedDefaults: require the class to be standard
We now only default type variables if they only appear in constraints
of the form `C v`, where `C` is either a standard class or a class with
an in-scope default declaration.
This rectifies an oversight in the original implementation of the
NamedDefault extensions that was remarked in #25775; that implementation
allowed type variables to appear in unary constraints which had arbitrary
classes at the head.
See the rewritten Note [How type-class constraints are defaulted] for
details of the implementation.
Fixes #25775
Fixes #25778
(cherry picked from commit f1acdd2c2b664ad0bdcaae4064b50e84aa7bc599)
- - - - -
cfbec95d by Rodrigo Mesquita at 2026-03-04T12:15:09+05:30
bytecode: Use 32bits for breakpoint index
Fixes #26325
(cherry picked from commit e368e24779f8a7bf110a025383db23521b313407)
- - - - -
2ee8a948 by Zubin Duggal at 2026-03-05T10:59:34+05:30
Bump Win32 submodule to 2.14.2.1.
- - - - -
928c81aa by Zubin Duggal at 2026-03-05T10:59:35+05:30
Bump directory submodule to 1.3.10.1.
- - - - -
7630ef4e by Zubin Duggal at 2026-03-05T11:56:26+05:30
Bump exceptions submodule to 0.10.12.
- - - - -
06f47576 by Zubin Duggal at 2026-03-05T11:56:26+05:30
Bump file-io submodule to 0.1.6.
- - - - -
8f6f0053 by Zubin Duggal at 2026-03-05T11:56:26+05:30
Bump filepath submodule to 1.5.5.0.
- - - - -
2129f6f1 by Zubin Duggal at 2026-03-05T11:56:26+05:30
Bump haskeline submodule to 0.8.4.1.
- - - - -
995cb006 by Zubin Duggal at 2026-03-05T11:56:26+05:30
Bump mtl submodule to 2.3.2.
- - - - -
4e021a4b by Zubin Duggal at 2026-03-05T11:56:26+05:30
Bump os-string submodule to 2.0.10.
- - - - -
58d74a0c by Zubin Duggal at 2026-03-05T11:56:26+05:30
Bump unix submodule to 2.8.8.0.
- - - - -
4d81dd7f by sheaf at 2026-03-06T11:21:09+05:30
Mark T26410_ffi as fragile on Windows
As seen in #26595, this test intermittently fails on Windows.
This commit marks it as fragile, until we get around to fixing it.
(cherry picked from commit 6b42232c34273137b194c41b3c968be4a377a68f)
- - - - -
309889a5 by Zubin Duggal at 2026-03-06T11:21:09+05:30
Prepare release 9.12.4
- - - - -
1070cf05 by Zubin Duggal at 2026-03-10T13:02:18+05:30
Fix warning for Werror due to mismatched pragma pop
- - - - -
250 changed files:
- .gitlab-ci.yml
- .gitlab/darwin/toolchain.nix
- .gitlab/rel_eng/upload_ghc_libs.py
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/ByteCode/Instr.hs
- compiler/GHC/Cmm.hs
- compiler/GHC/Cmm/InitFini.hs
- compiler/GHC/Cmm/Parser.y
- compiler/GHC/CmmToAsm/AArch64/Ppr.hs
- compiler/GHC/CmmToAsm/PPC/CodeGen.hs
- compiler/GHC/CmmToAsm/Ppr.hs
- compiler/GHC/CmmToAsm/Reg/Linear.hs
- compiler/GHC/CmmToAsm/Reg/Linear/StackMap.hs
- compiler/GHC/CmmToAsm/Wasm/FromCmm.hs
- compiler/GHC/CmmToAsm/X86/Ppr.hs
- compiler/GHC/CmmToC.hs
- compiler/GHC/CmmToLlvm.hs
- compiler/GHC/CmmToLlvm/Base.hs
- compiler/GHC/CmmToLlvm/Data.hs
- compiler/GHC/Core/Lint.hs
- compiler/GHC/Core/Map/Type.hs
- compiler/GHC/Core/Opt/CSE.hs
- compiler/GHC/Core/Opt/SetLevels.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/Opt/Simplify/Utils.hs
- compiler/GHC/Core/Opt/WorkWrap.hs
- compiler/GHC/Core/Utils.hs
- compiler/GHC/Driver/Config/Core/Lint.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Pipeline/Execute.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Hs/Doc.hs
- compiler/GHC/Rename/Env.hs
- compiler/GHC/Rename/Pat.hs
- compiler/GHC/StgToByteCode.hs
- compiler/GHC/StgToJS/Linker/Linker.hs
- compiler/GHC/Tc/Gen/Expr.hs
- compiler/GHC/Tc/Instance/Class.hs
- compiler/GHC/Tc/Solver.hs
- compiler/GHC/Tc/Solver/Dict.hs
- compiler/GHC/Tc/Types/Evidence.hs
- compiler/GHC/Tc/Utils/Unify.hs
- compiler/GHC/Types/DefaultEnv.hs
- compiler/GHC/Types/Id/Info.hs
- compiler/GHC/Unit/Info.hs
- compiler/ghc.cabal.in
- configure.ac
- + docs/users_guide/9.12.4-notes.rst
- docs/users_guide/debugging.rst
- docs/users_guide/release-notes.rst
- docs/users_guide/rtd-theme/layout.html
- hadrian/src/Builder.hs
- hadrian/src/Rules/Documentation.hs
- hadrian/src/Rules/Generate.hs
- hadrian/src/Rules/Rts.hs
- hadrian/src/Settings/Builders/Ghc.hs
- hadrian/src/Settings/Builders/RunTest.hs
- libffi-tarballs
- libraries/Win32
- libraries/base/base.cabal.in
- libraries/base/changelog.md
- libraries/base/src/Control/Exception/Backtrace.hs
- libraries/directory
- libraries/exceptions
- libraries/file-io
- libraries/filepath
- libraries/ghc-experimental/ghc-experimental.cabal.in
- + libraries/ghc-experimental/src/GHC/Exception/Backtrace/Experimental.hs
- libraries/ghc-internal/src/GHC/Internal/Err.hs
- libraries/ghc-internal/src/GHC/Internal/Exception.hs
- libraries/ghc-internal/src/GHC/Internal/Exception/Backtrace.hs
- libraries/ghc-internal/src/GHC/Internal/Exception/Backtrace.hs-boot
- + libraries/ghc-internal/tests/Makefile
- + libraries/ghc-internal/tests/all.T
- + libraries/ghc-internal/tests/backtraces/Makefile
- + libraries/ghc-internal/tests/backtraces/T14532a.hs
- + libraries/ghc-internal/tests/backtraces/T14532a.stdout
- + libraries/ghc-internal/tests/backtraces/T14532b.hs
- + libraries/ghc-internal/tests/backtraces/T14532b.stdout
- + libraries/ghc-internal/tests/backtraces/all.T
- + libraries/ghc-internal/tests/stack-annotation/ann_frame005.hs
- + libraries/ghc-internal/tests/stack-annotation/ann_frame005.stdout
- libraries/haskeline
- libraries/mtl
- libraries/os-string
- libraries/text
- libraries/transformers
- libraries/unix
- m4/fp_check_pthreads.m4
- − m4/fp_visibility_hidden.m4
- m4/fptools_set_c_ld_flags.m4
- m4/prep_target_file.m4
- rts/Apply.cmm
- rts/BeginPrivate.h
- rts/Disassembler.c
- rts/EndPrivate.h
- rts/Hash.c
- rts/Interpreter.c
- − rts/RtsDllMain.c
- − rts/RtsDllMain.h
- rts/RtsStartup.c
- rts/RtsSymbols.c
- rts/StgMiscClosures.cmm
- rts/Task.c
- rts/Task.h
- rts/ThreadPaused.c
- rts/configure.ac
- rts/eventlog/EventLog.c
- rts/include/Rts.h
- rts/include/RtsAPI.h
- rts/include/Stg.h
- rts/include/rts/Bytecodes.h
- rts/include/rts/OSThreads.h
- rts/include/rts/Types.h
- rts/include/stg/DLL.h
- rts/linker/LoadArchive.c
- rts/posix/OSMem.c
- rts/posix/OSThreads.c
- rts/prim/atomic.c
- rts/prim/ctz.c
- + rts/rts.buildinfo.in
- rts/rts.cabal
- rts/sm/BlockAlloc.c
- rts/sm/Evac.c
- rts/sm/Evac.h
- rts/sm/Evac_thr.c → rts/sm/Evac_par.c
- rts/sm/GCTDecl.h
- rts/sm/GCThread.h
- rts/sm/Scav_thr.c → rts/sm/Scav_par.c
- rts/sm/Storage.c
- rts/win32/OSThreads.c
- testsuite/config/ghc
- testsuite/driver/cpu_features.py
- testsuite/driver/runtests.py
- testsuite/driver/testlib.py
- testsuite/driver/testutil.py
- testsuite/tests/arrows/should_compile/T21301.stderr
- + testsuite/tests/bytecode/T26216.hs
- + testsuite/tests/bytecode/T26216.script
- + testsuite/tests/bytecode/T26216.stdout
- + testsuite/tests/bytecode/T26216_aux.hs
- testsuite/tests/bytecode/all.T
- + testsuite/tests/cmm/should_run/JumpTableNoStackDealloc.hs
- + testsuite/tests/cmm/should_run/JumpTableNoStackDealloc.stdout
- + testsuite/tests/cmm/should_run/JumpTableNoStackDeallocGen.hs
- + testsuite/tests/cmm/should_run/JumpTableNoStackDealloc_cmm.cmm
- testsuite/tests/cmm/should_run/all.T
- testsuite/tests/codeGen/should_run/all.T
- + testsuite/tests/cross/should_run/T26449.hs
- + testsuite/tests/cross/should_run/all.T
- testsuite/tests/deSugar/should_fail/DsStrictFail.stderr
- testsuite/tests/deSugar/should_run/T20024.stderr
- testsuite/tests/deSugar/should_run/dsrun005.stderr
- testsuite/tests/deSugar/should_run/dsrun007.stderr
- testsuite/tests/deSugar/should_run/dsrun008.stderr
- + testsuite/tests/default/T25775.hs
- + testsuite/tests/default/T25775.stderr
- testsuite/tests/default/all.T
- testsuite/tests/deriving/should_run/T9576.stderr
- + testsuite/tests/ghc-api/TypeMapStringLiteral.hs
- testsuite/tests/ghc-api/all.T
- testsuite/tests/ghc-e/should_fail/T9930fail.stderr
- + testsuite/tests/ghci-wasm/Makefile
- + testsuite/tests/ghci-wasm/T26430.hs
- + testsuite/tests/ghci-wasm/T26430A.c
- + testsuite/tests/ghci-wasm/T26430B.c
- + testsuite/tests/ghci-wasm/all.T
- testsuite/tests/ghci.debugger/scripts/T8487.stdout
- testsuite/tests/ghci.debugger/scripts/break011.stdout
- testsuite/tests/ghci.debugger/scripts/break017.stdout
- testsuite/tests/ghci.debugger/scripts/break025.stdout
- + testsuite/tests/ghci/all.T
- + testsuite/tests/ghci/ghci-mem-primops.hs
- + testsuite/tests/ghci/ghci-mem-primops.script
- + testsuite/tests/ghci/ghci-mem-primops.stdout
- testsuite/tests/ghci/scripts/Defer02.stderr
- testsuite/tests/ghci/scripts/T15325.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/interface-stability/base-exports.stdout-ws-32
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout-mingw32
- testsuite/tests/linters/all.T
- testsuite/tests/numeric/should_run/all.T
- testsuite/tests/numeric/should_run/foundation.hs
- testsuite/tests/numeric/should_run/foundation.stdout
- + testsuite/tests/overloadedrecflds/should_fail/T26391.hs
- + testsuite/tests/overloadedrecflds/should_fail/T26391.stderr
- testsuite/tests/overloadedrecflds/should_fail/all.T
- testsuite/tests/patsyn/should_run/ghci.stderr
- testsuite/tests/perf/compiler/all.T
- + testsuite/tests/perf/compiler/interpreter_steplocal.hs
- + testsuite/tests/perf/compiler/interpreter_steplocal.script
- + testsuite/tests/perf/compiler/interpreter_steplocal.stdout
- testsuite/tests/perf/should_run/T3586.hs
- testsuite/tests/perf/should_run/all.T
- − testsuite/tests/process/process010.stdout-i386-unknown-solaris2
- testsuite/tests/rts/all.T
- − testsuite/tests/rts/linker/T11223/T11223_link_order_a_b_2_fail.stderr-ws-32-mingw32
- − testsuite/tests/rts/linker/T11223/T11223_simple_duplicate_lib.stderr-ws-32-mingw32
- − testsuite/tests/rts/outofmem.stderr-i386-apple-darwin
- − testsuite/tests/rts/outofmem.stderr-i386-unknown-mingw32
- − testsuite/tests/rts/outofmem.stderr-powerpc-apple-darwin
- testsuite/tests/safeHaskell/safeLanguage/SafeLang15.stderr
- testsuite/tests/showIface/DocsInHiFile1.stdout
- testsuite/tests/showIface/HaddockSpanIssueT24378.stdout
- testsuite/tests/showIface/MagicHashInHaddocks.stdout
- + testsuite/tests/simd/should_run/T26410_ffi.hs
- + testsuite/tests/simd/should_run/T26410_ffi.stdout
- + testsuite/tests/simd/should_run/T26410_ffi_c.c
- + testsuite/tests/simd/should_run/T26410_prim.hs
- + testsuite/tests/simd/should_run/T26410_prim.stdout
- testsuite/tests/simd/should_run/all.T
- + testsuite/tests/simplCore/should_compile/T26681.hs
- + testsuite/tests/simplCore/should_compile/T26903.hs
- + testsuite/tests/simplCore/should_compile/T26903.stderr
- testsuite/tests/simplCore/should_compile/all.T
- testsuite/tests/th/T10279.hs
- testsuite/tests/th/T10279.stderr
- testsuite/tests/type-data/should_run/T22332a.stderr
- + testsuite/tests/typecheck/should_compile/T26277.hs
- + testsuite/tests/typecheck/should_compile/T26451.hs
- testsuite/tests/typecheck/should_compile/all.T
- testsuite/tests/typecheck/should_fail/T12921.stderr
- testsuite/tests/typecheck/should_run/T10284.stderr
- testsuite/tests/typecheck/should_run/T13838.stderr
- testsuite/tests/typecheck/should_run/T9497a-run.stderr
- testsuite/tests/typecheck/should_run/T9497b-run.stderr
- testsuite/tests/typecheck/should_run/T9497c-run.stderr
- testsuite/tests/unsatisfiable/T23816.stderr
- testsuite/tests/unsatisfiable/UnsatDefer.stderr
- utils/genprimopcode/Main.hs
- utils/genprimopcode/Syntax.hs
- utils/ghc-pkg/Main.hs
- utils/ghc-toolchain/src/GHC/Toolchain/Tools/MergeObjs.hs
- utils/haddock/haddock-api/resources/html/Linuwial.std-theme/linuwial.css
- utils/haddock/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs
- utils/haddock/haddock-api/src/Haddock/Backends/Xhtml/Utils.hs
- utils/haddock/html-test/ref/Bug1004.html
- utils/haddock/html-test/ref/Bug548.html
- utils/haddock/html-test/ref/Bug973.html
- utils/haddock/html-test/ref/Hash.html
- utils/haddock/html-test/ref/ImplicitParams.html
- utils/haddock/html-test/ref/Instances.html
- utils/haddock/html-test/ref/TypeOperators.html
- utils/jsffi/dyld.mjs
- utils/jsffi/post-link.mjs
- utils/jsffi/prelude.mjs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/65370007e2d9f1976fbcfbb514917f…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/65370007e2d9f1976fbcfbb514917f…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/io-manager-deadlock-detection] 2 commits: Move THREADED_RTS-conditional struct members to end of Capability
by Duncan Coutts (@dcoutts) 10 Mar '26
by Duncan Coutts (@dcoutts) 10 Mar '26
10 Mar '26
Duncan Coutts pushed to branch wip/io-manager-deadlock-detection at Glasgow Haskell Compiler / GHC
Commits:
bb63cf06 by Duncan Coutts at 2026-03-10T10:09:52+00:00
Move THREADED_RTS-conditional struct members to end of Capability
Accessing members of the Capability struct from CMM code rely on
accessor macros. (The macros are generated by deriveConstants).
These macros have a single definition. This means that the offsets of
all struct members must *not* vary based on THREADED_RTS vs
!THREADED_RTS. This requires that any struct members that are
conditional on THREADED_RTS must occur after the unconditional struct
members. Hence we move all the ones that are conditional on
THREADED_RTS to the end.
Add a deriveConstants entry for the iomgr member of the Capability
struct, which was the motivation for this change.
Add warning messages to help our future selves. Debugging this took me
a couple hours in gdb!
It is unclear why reordering the capability struct should make the
hello world program bigger, but perhaps it was just on the edge of the
+5% and this changed the size slightly. A last straw if you like.
-------------------------
Metric Increase:
size_hello_artifact
-------------------------
- - - - -
97cb8f22 by Duncan Coutts at 2026-03-10T10:11:14+00:00
Make the IOManager API use CapIOManager rather than Capability
This makes the API somewhat more self-contained and more consistent.
Now the IOManager API and each of the backends takes just the I/O
manager structure. Previously we had a bit of a mixture, depending on
whether the function needed access to the Capability or just the
CapIOManager.
We still need access to the cap, so we introduce a back reference to
reach the capability, via iomgr->cap.
Convert all uses in select and poll backends, but not win32 ones.
Convert callers in the scheduler and elsewhere.
Also convert the three CMM primops that call IOManager APIs. They just
need to use Capability_iomgr(MyCapability()).
- - - - -
15 changed files:
- rts/Capability.c
- rts/Capability.h
- rts/IOManager.c
- rts/IOManager.h
- rts/IOManagerInternals.h
- rts/PrimOps.cmm
- rts/RaiseAsync.c
- rts/Schedule.c
- rts/posix/Poll.c
- rts/posix/Poll.h
- rts/posix/Select.c
- rts/posix/Select.h
- rts/posix/Timeout.c
- rts/posix/Timeout.h
- utils/deriveConstants/Main.hs
Changes:
=====================================
rts/Capability.c
=====================================
@@ -286,7 +286,8 @@ initCapability (Capability *cap, uint32_t i)
#endif
cap->total_allocated = 0;
- initCapabilityIOManager(cap); /* initialises cap->iomgr */
+ cap->iomgr = allocCapabilityIOManager(cap);
+ initCapabilityIOManager(cap->iomgr);
cap->f.stgEagerBlackholeInfo = (W_)&__stg_EAGER_BLACKHOLE_info;
cap->f.stgGCEnter1 = (StgFunPtr)__stg_gc_enter_1;
@@ -1344,7 +1345,7 @@ markCapability (evac_fn evac, void *user, Capability *cap,
}
#endif
- markCapabilityIOManager(evac, user, cap);
+ markCapabilityIOManager(evac, user, cap->iomgr);
// Free STM structures for this Capability
stmPreGCHook(cap);
=====================================
rts/Capability.h
=====================================
@@ -139,6 +139,19 @@ struct Capability_ {
// See Note [allocation accounting] in Storage.c
uint64_t total_allocated;
+ // I/O manager data structures for this capability
+ CapIOManager *iomgr;
+
+ // Per-capability STM-related data
+ StgTVarWatchQueue *free_tvar_watch_queues;
+ StgTRecChunk *free_trec_chunks;
+ StgTRecHeader *free_trec_headers;
+ uint32_t transaction_tokens;
+
+ // WARNING: unconditional struct members must come before ones
+ // conditional on THREADED_RTS. Otherwise the CMM Capability_*
+ // accessor macros would have the wrong offsets.
+
#if defined(THREADED_RTS)
// Worker Tasks waiting in the wings. Singly-linked.
Task *spare_workers;
@@ -175,14 +188,9 @@ struct Capability_ {
SparkCounters spark_stats;
#endif
- // I/O manager data structures for this capability
- CapIOManager *iomgr;
+ // WARNING: No more unconditional struct members here, or they will
+ // have inconsistent CMM offset macros.
- // Per-capability STM-related data
- StgTVarWatchQueue *free_tvar_watch_queues;
- StgTRecChunk *free_trec_chunks;
- StgTRecHeader *free_trec_headers;
- uint32_t transaction_tokens;
} // typedef Capability is defined in RtsAPI.h
ATTRIBUTE_ALIGNED(CAPABILITY_ALIGNMENT)
;
=====================================
rts/IOManager.c
=====================================
@@ -316,22 +316,29 @@ char * showIOManager(void)
}
}
+/* Allocate a CapIOManager for a given Capability. Having this helps us keep
+ * struct CapIOManager opaque from most of the rest of the RTS.
+ */
+CapIOManager *allocCapabilityIOManager(Capability *cap)
+{
+ CapIOManager *iomgr = stgMallocBytes(sizeof(CapIOManager),
+ "allocCapabilityIOManager");
+ iomgr->cap = cap; /* link back */
+ return iomgr;
+}
+
-/* Allocate and initialise the per-capability CapIOManager that lives in each
- * Capability. Called from initCapability(), which is done in the RTS startup
- * in initCapabilities(), and later at runtime via setNumCapabilities().
+/* Initialise the per-capability CapIOManager that lives in each Capability.
+ * Called from initCapability(), which is done in the RTS startup in
+ * initCapabilities(), and later at runtime via setNumCapabilities().
*
* Note that during RTS startup this is called _before_ the storage manager
* is initialised, so this is not allowed to allocate on the GC heap.
*/
-void initCapabilityIOManager(Capability *cap)
+void initCapabilityIOManager(CapIOManager *iomgr)
{
debugTrace(DEBUG_iomanager, "initialising I/O manager %s for cap %d",
- showIOManager(), cap->no);
-
- CapIOManager *iomgr =
- (CapIOManager *) stgMallocBytes(sizeof(CapIOManager),
- "initCapabilityIOManager");
+ showIOManager(), iomgr->cap->no);
switch (iomgr_type) {
#if defined(IOMGR_ENABLED_SELECT)
@@ -363,8 +370,6 @@ void initCapabilityIOManager(Capability *cap)
default:
break;
}
-
- cap->iomgr = iomgr;
}
@@ -436,7 +441,7 @@ void initIOManager(void)
/* Called from forkProcess in the child process on the surviving capability.
*/
void
-initIOManagerAfterFork(Capability **pcap)
+initIOManagerAfterFork(CapIOManager *iomgr, Capability **pcap)
{
switch (iomgr_type) {
@@ -467,7 +472,7 @@ initIOManagerAfterFork(Capability **pcap)
/* Called from setNumCapabilities.
*/
-void notifyIOManagerCapabilitiesChanged(Capability **pcap)
+void notifyIOManagerCapabilitiesChanged(CapIOManager *iomgr, Capability **pcap)
{
switch (iomgr_type) {
#if defined(IOMGR_ENABLED_MIO_POSIX)
@@ -572,38 +577,29 @@ void wakeupIOManager(void)
}
}
-void markCapabilityIOManager(evac_fn evac, void *user, Capability *cap)
+void markCapabilityIOManager(evac_fn evac, void *user, CapIOManager *iomgr)
{
switch (iomgr_type) {
#if defined(IOMGR_ENABLED_SELECT)
case IO_MANAGER_SELECT:
- {
- CapIOManager *iomgr = cap->iomgr;
evac(user, (StgClosure **)(void *)&iomgr->blocked_queue_hd);
evac(user, (StgClosure **)(void *)&iomgr->blocked_queue_tl);
evac(user, (StgClosure **)(void *)&iomgr->sleeping_queue);
break;
- }
#endif
#if defined(IOMGR_ENABLED_POLL)
case IO_MANAGER_POLL:
- {
- CapIOManager *iomgr = cap->iomgr;
markClosureTable(evac, user, &iomgr->aiop_table);
evac(user, (StgClosure **)(void *)&iomgr->timeout_queue);
break;
- }
#endif
#if defined(IOMGR_ENABLED_WIN32_LEGACY)
case IO_MANAGER_WIN32_LEGACY:
- {
- CapIOManager *iomgr = cap->iomgr;
evac(user, (StgClosure **)(void *)&iomgr->blocked_queue_hd);
evac(user, (StgClosure **)(void *)&iomgr->blocked_queue_tl);
break;
- }
#endif
default:
break;
@@ -665,29 +661,23 @@ setIOManagerControlFd(uint32_t cap_no, int fd) {
#endif
-bool anyPendingTimeoutsOrIO(Capability *cap)
+bool anyPendingTimeoutsOrIO(CapIOManager *iomgr)
{
switch (iomgr_type) {
#if defined(IOMGR_ENABLED_SELECT)
case IO_MANAGER_SELECT:
- {
- CapIOManager *iomgr = cap->iomgr;
return (iomgr->blocked_queue_hd != END_TSO_QUEUE)
|| (iomgr->sleeping_queue != END_TSO_QUEUE);
- }
#endif
#if defined(IOMGR_ENABLED_POLL)
case IO_MANAGER_POLL:
- return anyPendingTimeoutsOrIOPoll(cap->iomgr);
+ return anyPendingTimeoutsOrIOPoll(iomgr);
#endif
#if defined(IOMGR_ENABLED_WIN32_LEGACY)
case IO_MANAGER_WIN32_LEGACY:
- {
- CapIOManager *iomgr = cap->iomgr;
return (iomgr->blocked_queue_hd != END_TSO_QUEUE);
- }
#endif
/* For the purpose of the scheduler, the threaded I/O managers never have
@@ -729,19 +719,19 @@ bool anyPendingTimeoutsOrIO(Capability *cap)
}
-void pollCompletedTimeoutsOrIO(Capability *cap)
+void pollCompletedTimeoutsOrIO(CapIOManager *iomgr)
{
debugTrace(DEBUG_iomanager, "polling for completed IO or timeouts");
switch (iomgr_type) {
#if defined(IOMGR_ENABLED_SELECT)
case IO_MANAGER_SELECT:
- awaitCompletedTimeoutsOrIOSelect(cap, false);
+ awaitCompletedTimeoutsOrIOSelect(iomgr, false);
break;
#endif
#if defined(IOMGR_ENABLED_POLL)
case IO_MANAGER_POLL:
- pollCompletedTimeoutsOrIOPoll(cap);
+ pollCompletedTimeoutsOrIOPoll(iomgr);
break;
#endif
@@ -753,7 +743,7 @@ void pollCompletedTimeoutsOrIO(Capability *cap)
#if defined(IOMGR_ENABLED_WINIO)
case IO_MANAGER_WINIO:
#endif
- awaitCompletedTimeoutsOrIOWin32(cap, false);
+ awaitCompletedTimeoutsOrIOWin32(iomgr->cap, false);
break;
#endif
default:
@@ -762,19 +752,19 @@ void pollCompletedTimeoutsOrIO(Capability *cap)
}
-void awaitCompletedTimeoutsOrIO(Capability *cap)
+void awaitCompletedTimeoutsOrIO(CapIOManager *iomgr)
{
debugTrace(DEBUG_iomanager, "waiting for completed IO or timeouts");
switch (iomgr_type) {
#if defined(IOMGR_ENABLED_SELECT)
case IO_MANAGER_SELECT:
- awaitCompletedTimeoutsOrIOSelect(cap, true);
+ awaitCompletedTimeoutsOrIOSelect(iomgr, true);
break;
#endif
#if defined(IOMGR_ENABLED_POLL)
case IO_MANAGER_POLL:
- awaitCompletedTimeoutsOrIOPoll(cap);
+ awaitCompletedTimeoutsOrIOPoll(iomgr);
break;
#endif
@@ -786,17 +776,18 @@ void awaitCompletedTimeoutsOrIO(Capability *cap)
#if defined(IOMGR_ENABLED_WINIO)
case IO_MANAGER_WINIO:
#endif
- awaitCompletedTimeoutsOrIOWin32(cap, true);
+ awaitCompletedTimeoutsOrIOWin32(iomgr->cap, true);
break;
#endif
default:
barf("pollCompletedTimeoutsOrIO not implemented");
}
- ASSERT(!emptyRunQueue(cap) || getSchedState() != SCHED_RUNNING);
+ ASSERT(!emptyRunQueue(iomgr->cap) || getSchedState() != SCHED_RUNNING);
}
-bool syncIOWaitReady(Capability *cap,
+/* CMM primop. Result is true on success, or false on allocation failure. */
+bool syncIOWaitReady(CapIOManager *iomgr,
StgTSO *tso,
IOReadOrWrite rw,
HsInt fd)
@@ -812,14 +803,14 @@ bool syncIOWaitReady(Capability *cap,
StgWord why_blocked = rw == IORead ? BlockedOnRead : BlockedOnWrite;
tso->block_info.fd = fd;
RELEASE_STORE(&tso->why_blocked, why_blocked);
- appendToIOBlockedQueue(cap, tso);
+ appendToIOBlockedQueue(iomgr, tso);
return true;
}
#endif
#if defined(IOMGR_ENABLED_POLL)
case IO_MANAGER_POLL:
ASSERT(tso->why_blocked == NotBlocked);
- return syncIOWaitReadyPoll(cap, tso, rw, fd);
+ return syncIOWaitReadyPoll(iomgr, tso, rw, fd);
#endif
default:
barf("waitRead# / waitWrite# not available for current I/O manager");
@@ -827,25 +818,29 @@ bool syncIOWaitReady(Capability *cap,
}
-void syncIOCancel(Capability *cap, StgTSO *tso)
+void syncIOCancel(CapIOManager *iomgr, StgTSO *tso)
{
debugTrace(DEBUG_iomanager, "cancelling I/O for thread %ld", (long) tso->id);
switch (iomgr_type) {
#if defined(IOMGR_ENABLED_SELECT)
case IO_MANAGER_SELECT:
- removeThreadFromDeQueue(cap, &cap->iomgr->blocked_queue_hd,
- &cap->iomgr->blocked_queue_tl, tso);
+ removeThreadFromDeQueue(iomgr->cap,
+ &iomgr->blocked_queue_hd,
+ &iomgr->blocked_queue_tl,
+ tso);
break;
#endif
#if defined(IOMGR_ENABLED_POLL)
case IO_MANAGER_POLL:
- syncIOCancelPoll(cap, tso);
+ syncIOCancelPoll(iomgr, tso);
break;
#endif
#if defined(IOMGR_ENABLED_WIN32_LEGACY)
case IO_MANAGER_WIN32_LEGACY:
- removeThreadFromDeQueue(cap, &cap->iomgr->blocked_queue_hd,
- &cap->iomgr->blocked_queue_tl, tso);
+ removeThreadFromDeQueue(iomgr->cap,
+ &iomgr->blocked_queue_hd,
+ &iomgr->blocked_queue_tl,
+ tso);
abandonWorkRequest(tso->block_info.async_result->reqID);
break;
#endif
@@ -856,11 +851,12 @@ void syncIOCancel(Capability *cap, StgTSO *tso)
#if defined(IOMGR_ENABLED_SELECT)
-static void insertIntoSleepingQueue(Capability *cap, StgTSO *tso, LowResTime target);
+static void insertIntoSleepingQueue(CapIOManager *iomgr, StgTSO *tso, LowResTime target);
#endif
-bool syncDelay(Capability *cap, StgTSO *tso, HsInt us_delay)
+/* CMM primop. Result is true on success, or false on allocation failure. */
+bool syncDelay(CapIOManager *iomgr, StgTSO *tso, HsInt us_delay)
{
debugTrace(DEBUG_iomanager, "thread %ld waiting for %lld us", tso->id, us_delay);
ASSERT(tso->why_blocked == NotBlocked);
@@ -871,13 +867,13 @@ bool syncDelay(Capability *cap, StgTSO *tso, HsInt us_delay)
LowResTime target = getDelayTarget(us_delay);
tso->block_info.target = target;
RELEASE_STORE(&tso->why_blocked, BlockedOnDelay);
- insertIntoSleepingQueue(cap, tso, target);
+ insertIntoSleepingQueue(iomgr, tso, target);
return true;
}
#endif
#if defined(IOMGR_ENABLED_POLL)
case IO_MANAGER_POLL:
- return syncDelayTimeout(cap, tso, us_delay);
+ return syncDelayTimeout(iomgr, tso, us_delay);
#endif
#if defined(IOMGR_ENABLED_WIN32_LEGACY)
case IO_MANAGER_WIN32_LEGACY:
@@ -897,7 +893,7 @@ bool syncDelay(Capability *cap, StgTSO *tso, HsInt us_delay)
* delayed thread on the blocked_queue.
*/
RELEASE_STORE(&tso->why_blocked, BlockedOnDoProc);
- appendToIOBlockedQueue(cap, tso);
+ appendToIOBlockedQueue(iomgr, tso);
return true;
}
#endif
@@ -907,18 +903,18 @@ bool syncDelay(Capability *cap, StgTSO *tso, HsInt us_delay)
}
-void syncDelayCancel(Capability *cap, StgTSO *tso)
+void syncDelayCancel(CapIOManager *iomgr, StgTSO *tso)
{
debugTrace(DEBUG_iomanager, "cancelling delay for thread %ld", (long) tso->id);
switch (iomgr_type) {
#if defined(IOMGR_ENABLED_SELECT)
case IO_MANAGER_SELECT:
- removeThreadFromQueue(cap, &cap->iomgr->sleeping_queue, tso);
+ removeThreadFromQueue(iomgr->cap, &iomgr->sleeping_queue, tso);
break;
#endif
#if defined(IOMGR_ENABLED_POLL)
case IO_MANAGER_POLL:
- syncDelayCancelTimeout(cap, tso);
+ syncDelayCancelTimeout(iomgr, tso);
break;
#endif
/* Note: no case for IO_MANAGER_WIN32_LEGACY despite it having a case
@@ -935,14 +931,13 @@ void syncDelayCancel(Capability *cap, StgTSO *tso)
#if defined(IOMGR_ENABLED_SELECT) || defined(IOMGR_ENABLED_WIN32_LEGACY)
-void appendToIOBlockedQueue(Capability *cap, StgTSO *tso)
+void appendToIOBlockedQueue(CapIOManager *iomgr, StgTSO *tso)
{
- CapIOManager *iomgr = cap->iomgr;
ASSERT(tso->_link == END_TSO_QUEUE);
if (iomgr->blocked_queue_hd == END_TSO_QUEUE) {
iomgr->blocked_queue_hd = tso;
} else {
- setTSOLink(cap, iomgr->blocked_queue_tl, tso);
+ setTSOLink(iomgr->cap, iomgr->blocked_queue_tl, tso);
}
iomgr->blocked_queue_tl = tso;
}
@@ -957,9 +952,8 @@ void appendToIOBlockedQueue(Capability *cap, StgTSO *tso)
* used. This is a wart that should be excised.
*/
// TODO: move to Select.c and rename
-static void insertIntoSleepingQueue(Capability *cap, StgTSO *tso, LowResTime target)
+static void insertIntoSleepingQueue(CapIOManager *iomgr, StgTSO *tso, LowResTime target)
{
- CapIOManager *iomgr = cap->iomgr;
StgTSO *prev = NULL;
StgTSO *t = iomgr->sleeping_queue;
while (t != END_TSO_QUEUE && t->block_info.target < target) {
@@ -971,7 +965,7 @@ static void insertIntoSleepingQueue(Capability *cap, StgTSO *tso, LowResTime tar
if (prev == NULL) {
iomgr->sleeping_queue = tso;
} else {
- setTSOLink(cap, prev, tso);
+ setTSOLink(iomgr->cap, prev, tso);
}
}
#endif
=====================================
rts/IOManager.h
=====================================
@@ -19,6 +19,7 @@
#pragma once
+#include "Capability.h"
#include "sm/GC.h" // for evac_fn
#include "BeginPrivate.h"
@@ -227,11 +228,19 @@ enum IOOpOutcome {
void selectIOManager(void);
-/* Allocate and initialise the per-capability CapIOManager that lives in each
- * Capability. Called from initCapability(), which is done in the RTS startup
- * in initCapabilities(), and later at runtime via setNumCapabilities().
+/* Allocate a CapIOManager for a given Capability. Having this helps us keep
+ * struct CapIOManager opaque from most of the rest of the RTS.
*/
-void initCapabilityIOManager(Capability *cap);
+CapIOManager *allocCapabilityIOManager(Capability *cap);
+
+/* Initialise the per-capability CapIOManager that lives in each Capability.
+ * Called from initCapability(), which is done in the RTS startup in
+ * initCapabilities(), and later at runtime via setNumCapabilities().
+ *
+ * This is separate from allocCapabilityIOManager so that we can re-initialise
+ * I/O managers after forkProcess.
+ */
+void initCapabilityIOManager(CapIOManager *iomgr);
/* Init hook: called from hs_init_ghc, very late in the startup after almost
@@ -243,10 +252,11 @@ void initIOManager(void);
/* Init hook: called from forkProcess in the child process on the surviving
* capability.
*
- * Note that this is synchronous and can run Haskell code, so can change the
- * given cap.
+ * This is synchronous and can run Haskell code, so can change the given cap.
+ * TODO: it would make for a cleaner API here if this were made asynchronous.
*/
-void initIOManagerAfterFork(/* inout */ Capability **pcap);
+void initIOManagerAfterFork(CapIOManager *iomgr,
+ /* inout */ Capability **pcap);
/* TODO: rationalise initIOManager and initIOManagerAfterFork into a single
per-capability init function.
@@ -254,8 +264,12 @@ void initIOManagerAfterFork(/* inout */ Capability **pcap);
/* Called from setNumCapabilities.
+ *
+ * This is synchronous and can run Haskell code, so can change the given cap.
+ * TODO: it would make for a cleaner API here if this were made asynchronous.
*/
-void notifyIOManagerCapabilitiesChanged(Capability **pcap);
+void notifyIOManagerCapabilitiesChanged(CapIOManager *iomgr,
+ /* inout */ Capability **pcap);
/* Shutdown hooks: called from hs_exit_ before and after the scheduler exits.
@@ -288,7 +302,7 @@ void wakeupIOManager(void);
/* GC hook: mark any per-capability GC roots the I/O manager uses.
*/
-void markCapabilityIOManager(evac_fn evac, void *user, Capability *cap);
+void markCapabilityIOManager(evac_fn evac, void *user, CapIOManager *iomgr);
/* GC hook: scavenge I/O related tso->block_info. Used by scavengeTSO.
@@ -305,21 +319,20 @@ typedef enum { IORead, IOWrite } IOReadOrWrite;
* necessarily operate on threads. The thread is suspended until the operation
* completes.
*
- * These are called from CMM primops. The ones returing int can perform heap
- * allocation, which might fail. They return 0 on success, or n > 0 on heap
- * allocation failure, needing n words. The CMM primops should invoke the
- * GC to free up at least n words and then retry the operation.
+ * Some of these are called from CMM primops. The primops returing bool can
+ * perform heap allocation, which might fail. They return true on success, or
+ * false on heap allocation failure.
*/
-/* Result is true on success, or false on allocation failure. */
-bool syncIOWaitReady(Capability *cap, StgTSO *tso, IOReadOrWrite rw, HsInt fd);
+/* Called from CMM primop */
+bool syncIOWaitReady(CapIOManager *iomgr, StgTSO *tso, IOReadOrWrite rw, HsInt fd);
-void syncIOCancel(Capability *cap, StgTSO *tso);
+void syncIOCancel(CapIOManager *iomgr, StgTSO *tso);
-/* Result is true on success, or false on allocation failure. */
-bool syncDelay(Capability *cap, StgTSO *tso, HsInt us_delay);
+/* Called from CMM primop */
+bool syncDelay(CapIOManager *iomgr, StgTSO *tso, HsInt us_delay);
-void syncDelayCancel(Capability *cap, StgTSO *tso);
+void syncDelayCancel(CapIOManager *iomgr, StgTSO *tso);
#if defined(IOMGR_ENABLED_SELECT) || defined(IOMGR_ENABLED_WIN32_LEGACY)
/* Add a thread to the end of the queue of threads blocked on I/O.
@@ -327,7 +340,7 @@ void syncDelayCancel(Capability *cap, StgTSO *tso);
* This is used by the select() and the Windows MIO non-threaded I/O manager
* implementation. Called from CMM code.
*/
-void appendToIOBlockedQueue(Capability *cap, StgTSO *tso);
+void appendToIOBlockedQueue(CapIOManager *iomgr, StgTSO *tso);
#endif
/* Check to see if there are any pending timeouts or I/O operations
@@ -336,7 +349,7 @@ void appendToIOBlockedQueue(Capability *cap, StgTSO *tso);
* This is used by the scheduler as part of deadlock-detection, and the
* "context switch as often as possible" test.
*/
-bool anyPendingTimeoutsOrIO(Capability *cap);
+bool anyPendingTimeoutsOrIO(CapIOManager *iomgr);
/* If there are any completed I/O operations or expired timers, process the
* completions as appropriate (which will typically unblock some waiting
@@ -344,7 +357,7 @@ bool anyPendingTimeoutsOrIO(Capability *cap);
*
* Called from schedule() both *before* and *after* scheduleDetectDeadlock().
*/
-void pollCompletedTimeoutsOrIO(Capability *cap);
+void pollCompletedTimeoutsOrIO(CapIOManager *iomgr);
/* If there are any completed I/O operations or expired timers, process the
* completions as appropriate. If there are none, wait until I/O or a timer
@@ -360,6 +373,6 @@ void pollCompletedTimeoutsOrIO(Capability *cap);
*
* Called from schedule() both *before* and *after* scheduleDetectDeadlock().
*/
-void awaitCompletedTimeoutsOrIO(Capability *cap);
+void awaitCompletedTimeoutsOrIO(CapIOManager *iomgr);
#include "EndPrivate.h"
=====================================
rts/IOManagerInternals.h
=====================================
@@ -24,7 +24,8 @@
/* The per-capability data structures belonging to the I/O manager.
*
- * It can be accessed as cap->iomgr.
+ * It can be accessed as cap->iomgr. Or given just the iomgr, you can access
+ * the owning cap as iomgr->cap.
*
* The content of the structure is defined conditionally so it is different for
* each I/O manager implementation.
@@ -33,6 +34,9 @@
*/
struct _CapIOManager {
+ /* Back reference to the containing capability */
+ Capability *cap;
+
#if defined(IOMGR_ENABLED_SELECT)
/* Thread queue for threads blocked on I/O completion. */
StgTSO *blocked_queue_hd;
=====================================
rts/PrimOps.cmm
=====================================
@@ -2279,7 +2279,8 @@ stg_waitReadzh ( W_ fd )
{
CBool ok; /* Ok, or heap alloc failure. */
- (ok) = ccall syncIOWaitReady(MyCapability() "ptr", CurrentTSO "ptr",
+ (ok) = ccall syncIOWaitReady(Capability_iomgr(MyCapability()) "ptr",
+ CurrentTSO "ptr",
/* IORead */ 0::I32, fd);
if (ok != 0::CBool) (likely: True) {
jump stg_block_noregs();
@@ -2292,7 +2293,8 @@ stg_waitWritezh ( W_ fd )
{
CBool ok; /* Ok, or heap alloc failure. */
- (ok) = ccall syncIOWaitReady(MyCapability() "ptr", CurrentTSO "ptr",
+ (ok) = ccall syncIOWaitReady(Capability_iomgr(MyCapability()) "ptr",
+ CurrentTSO "ptr",
/* IOWrite */ 1::I32, fd);
if (ok != 0::CBool) (likely: True) {
jump stg_block_noregs();
@@ -2305,7 +2307,8 @@ stg_delayzh ( W_ us_delay )
{
CBool ok; /* Ok, or heap alloc failure. */
- (ok) = ccall syncDelay(MyCapability() "ptr", CurrentTSO "ptr", us_delay);
+ (ok) = ccall syncDelay(Capability_iomgr(MyCapability()) "ptr",
+ CurrentTSO "ptr", us_delay);
if (ok != 0::CBool) (likely: True) {
/* Annoyingly, we cannot be consistent with how we wait and resume the
@@ -2348,7 +2351,8 @@ stg_asyncReadzh ( W_ fd, W_ is_sock, W_ len, W_ buf )
ASSERT(StgTSO_why_blocked(CurrentTSO) == NotBlocked::I32);
%release StgTSO_why_blocked(CurrentTSO) = BlockedOnRead::I32;
- ccall appendToIOBlockedQueue(MyCapability() "ptr", CurrentTSO "ptr");
+ ccall appendToIOBlockedQueue(Capability_iomgr(MyCapability()) "ptr",
+ CurrentTSO "ptr");
jump stg_block_async();
#endif
}
@@ -2374,7 +2378,8 @@ stg_asyncWritezh ( W_ fd, W_ is_sock, W_ len, W_ buf )
ASSERT(StgTSO_why_blocked(CurrentTSO) == NotBlocked::I32);
%release StgTSO_why_blocked(CurrentTSO) = BlockedOnWrite::I32;
- ccall appendToIOBlockedQueue(MyCapability() "ptr", CurrentTSO "ptr");
+ ccall appendToIOBlockedQueue(Capability_iomgr(MyCapability()) "ptr",
+ CurrentTSO "ptr");
jump stg_block_async();
#endif
}
@@ -2400,7 +2405,8 @@ stg_asyncDoProczh ( W_ proc, W_ param )
ASSERT(StgTSO_why_blocked(CurrentTSO) == NotBlocked::I32);
%release StgTSO_why_blocked(CurrentTSO) = BlockedOnDoProc::I32;
- ccall appendToIOBlockedQueue(MyCapability() "ptr", CurrentTSO "ptr");
+ ccall appendToIOBlockedQueue(Capability_iomgr(MyCapability()) "ptr",
+ CurrentTSO "ptr");
jump stg_block_async();
#endif
}
=====================================
rts/RaiseAsync.c
=====================================
@@ -708,12 +708,12 @@ removeFromQueues(Capability *cap, StgTSO *tso)
case BlockedOnWrite:
case BlockedOnDoProc:
// These blocking reasons are only used by some I/O managers
- syncIOCancel(cap, tso);
+ syncIOCancel(cap->iomgr, tso);
goto done;
case BlockedOnDelay:
// This blocking reasons is only used by some I/O managers
- syncDelayCancel(cap, tso);
+ syncDelayCancel(cap->iomgr, tso);
goto done;
default:
=====================================
rts/Schedule.c
=====================================
@@ -326,7 +326,7 @@ schedule (Capability *initialCapability, Task *task)
/* TODO: see if we can rationalise these two awaitCompletedTimeoutsOrIO
* calls before and after scheduleDetectDeadlock().
*/
- awaitCompletedTimeoutsOrIO(cap);
+ awaitCompletedTimeoutsOrIO(cap->iomgr);
#else
ASSERT(getSchedState() >= SCHED_INTERRUPTING);
#endif
@@ -409,7 +409,7 @@ schedule (Capability *initialCapability, Task *task)
*/
if (RtsFlags.ConcFlags.ctxtSwitchTicks == 0 &&
(!emptyRunQueue(cap) ||
- anyPendingTimeoutsOrIO(cap))) {
+ anyPendingTimeoutsOrIO(cap->iomgr))) {
RELAXED_STORE(&cap->context_switch, 1);
}
@@ -923,14 +923,14 @@ scheduleCheckBlockedThreads(Capability *cap USED_IF_NOT_THREADS)
* awaitCompletedTimeoutsOrIO below for the case of !defined(THREADED_RTS)
* && defined(mingw32_HOST_OS).
*/
- if (anyPendingTimeoutsOrIO(cap))
+ if (anyPendingTimeoutsOrIO(cap->iomgr))
{
if (emptyRunQueue(cap)) {
// block and wait
- awaitCompletedTimeoutsOrIO(cap);
+ awaitCompletedTimeoutsOrIO(cap->iomgr);
} else {
// poll but do not wait
- pollCompletedTimeoutsOrIO(cap);
+ pollCompletedTimeoutsOrIO(cap->iomgr);
}
}
#endif
@@ -950,7 +950,7 @@ scheduleDetectDeadlock (Capability **pcap, Task *task)
* other tasks are waiting for work, we must have a deadlock of
* some description.
*/
- if ( emptyRunQueue(cap) && !anyPendingTimeoutsOrIO(cap) )
+ if ( emptyRunQueue(cap) && !anyPendingTimeoutsOrIO(cap->iomgr) )
{
#if defined(THREADED_RTS)
/*
@@ -2232,7 +2232,7 @@ forkProcess(HsStablePtr *entry
// like startup event, capabilities, process info etc
traceTaskCreate(task, cap);
- initIOManagerAfterFork(&cap);
+ initIOManagerAfterFork(cap->iomgr, &cap);
// start timer after the IOManager is initialized
// (the idle GC may wake up the IOManager)
@@ -2392,7 +2392,7 @@ setNumCapabilities (uint32_t new_n_capabilities USED_IF_THREADS)
}
// Notify IO manager that the number of capabilities has changed.
- notifyIOManagerCapabilitiesChanged(&cap);
+ notifyIOManagerCapabilitiesChanged(cap->iomgr, &cap);
startTimer();
=====================================
rts/posix/Poll.c
=====================================
@@ -120,9 +120,9 @@ also allows the signal mask to be adjusted, but we do not make use of this.
******************************************************************************/
/* Forward declarations */
-static bool enlargeTables(Capability *cap, CapIOManager *iomgr);
-static void notifyIOCompletion(Capability *cap, StgAsyncIOOp *aiop);
-static void ioCancel(Capability *cap, StgAsyncIOOp *aiop);
+static bool enlargeTables(CapIOManager *iomgr);
+static void notifyIOCompletion(CapIOManager *iomgr, StgAsyncIOOp *aiop);
+static void ioCancel(CapIOManager *iomgr, StgAsyncIOOp *aiop);
static void reportPollError(int res, nfds_t nfds) STG_NORETURN;
@@ -136,32 +136,31 @@ void initCapabilityIOManagerPoll(CapIOManager *iomgr)
/* Used to implement syncIOWaitReady.
* Result is true on success, or false on allocation failure. */
-bool syncIOWaitReadyPoll(Capability *cap, StgTSO *tso,
+bool syncIOWaitReadyPoll(CapIOManager *iomgr, StgTSO *tso,
IOReadOrWrite rw, HsInt fd)
{
StgAsyncIOOp *aiop;
- aiop = (StgAsyncIOOp *)allocateMightFail(cap, sizeofW(StgAsyncIOOp));
+ aiop = (StgAsyncIOOp *)allocateMightFail(iomgr->cap, sizeofW(StgAsyncIOOp));
if (RTS_UNLIKELY(aiop == NULL)) return false;
- SET_HDR(aiop, &stg_ASYNCIOOP_info, cap->r.rCCCS);
+ SET_HDR(aiop, &stg_ASYNCIOOP_info, iomgr->cap->r.rCCCS);
aiop->notify.tso = tso;
aiop->notify_type = NotifyTSO;
aiop->live = &stg_ASYNCIO_LIVE0_closure;
tso->why_blocked = rw == IORead ? BlockedOnRead : BlockedOnWrite;
tso->block_info.aiop = aiop;
- return asyncIOWaitReadyPoll(cap, aiop, rw, fd);
+ return asyncIOWaitReadyPoll(iomgr, aiop, rw, fd);
}
/* Result is true on success, or false on allocation failure. */
-bool asyncIOWaitReadyPoll(Capability *cap, StgAsyncIOOp *aiop,
+bool asyncIOWaitReadyPoll(CapIOManager *iomgr, StgAsyncIOOp *aiop,
IOReadOrWrite rw, int fd)
{
- CapIOManager *iomgr = cap->iomgr;
if (RTS_UNLIKELY(isFullClosureTable(&iomgr->aiop_table))) {
- bool ok = enlargeTables(cap, iomgr);
+ bool ok = enlargeTables(iomgr);
if (RTS_UNLIKELY(!ok)) return false;
}
- int ix = insertClosureTable(cap, &iomgr->aiop_table, aiop);
+ int ix = insertClosureTable(iomgr->cap, &iomgr->aiop_table, aiop);
/* We use the aiop_table and aiop_poll_table densely. */
ASSERT(ix == sizeClosureTable(&iomgr->aiop_table) - 1);
@@ -169,7 +168,7 @@ bool asyncIOWaitReadyPoll(Capability *cap, StgAsyncIOOp *aiop,
/* The syncIO wrapper or CMM primop filled in the notify and live fields,
* we fill the rest.
*/
- aiop->capno = cap->no;
+ aiop->capno = iomgr->cap->no;
aiop->index = ix;
aiop->outcome = IOOpOutcomeInFlight;
@@ -183,12 +182,12 @@ bool asyncIOWaitReadyPoll(Capability *cap, StgAsyncIOOp *aiop,
}
-void syncIOCancelPoll(Capability *cap, StgTSO *tso)
+void syncIOCancelPoll(CapIOManager *iomgr, StgTSO *tso)
{
StgAsyncIOOp *aiop = tso->block_info.aiop;
ASSERT(aiop->notify_type == NotifyTSO);
- ASSERT(indexClosureTable(&cap->iomgr->aiop_table, aiop->index) == aiop);
- ioCancel(cap, aiop);
+ ASSERT(indexClosureTable(&iomgr->aiop_table, aiop->index) == aiop);
+ ioCancel(iomgr, aiop);
/* We cannot use the normal notifyIOCompletion here. We are in the context
* of throwTo, interrupting a thread blocked on IO via an async exception.
* We don't put the TSO back on the run queue or change the why_blocked
@@ -198,7 +197,7 @@ void syncIOCancelPoll(Capability *cap, StgTSO *tso)
}
-void asyncIOCancelPoll(Capability *cap, StgAsyncIOOp *aiop)
+void asyncIOCancelPoll(CapIOManager *iomgr, StgAsyncIOOp *aiop)
{
/* We can reliably determine if the aiop is still in progress by checking
* if the aiop_table still points to this aiop object. This is reliable
@@ -206,20 +205,18 @@ void asyncIOCancelPoll(Capability *cap, StgAsyncIOOp *aiop)
* is no longer retained by the application.
*/
ASSERT(aiop->notify_type != NotifyTSO);
- if (indexClosureTable(&cap->iomgr->aiop_table, aiop->index) == aiop) {
- ioCancel(cap, aiop);
- notifyIOCompletion(cap, aiop);
+ if (indexClosureTable(&iomgr->aiop_table, aiop->index) == aiop) {
+ ioCancel(iomgr, aiop);
+ notifyIOCompletion(iomgr, aiop);
}
}
-static void ioCancel(Capability *cap, StgAsyncIOOp *aiop)
+static void ioCancel(CapIOManager *iomgr, StgAsyncIOOp *aiop)
{
- CapIOManager *iomgr = cap->iomgr;
-
int ix = aiop->index;
int ix_from; int ix_to;
- removeCompactClosureTable(cap, &iomgr->aiop_table, ix,
+ removeCompactClosureTable(iomgr->cap, &iomgr->aiop_table, ix,
&ix_from, &ix_to);
if (ix_to != ix_from) {
StgAsyncIOOp *aiop_to = indexClosureTable(&iomgr->aiop_table, ix_to);
@@ -237,7 +234,7 @@ bool anyPendingTimeoutsOrIOPoll(CapIOManager *iomgr)
}
-static void notifyIOCompletion(Capability *cap, StgAsyncIOOp *aiop)
+static void notifyIOCompletion(CapIOManager *iomgr, StgAsyncIOOp *aiop)
{
ASSERT(aiop->outcome != IOOpOutcomeInFlight);
switch (aiop->notify_type) {
@@ -251,7 +248,8 @@ static void notifyIOCompletion(Capability *cap, StgAsyncIOOp *aiop)
debugTrace(DEBUG_iomanager,
"Raising exception in thread %" FMT_StgThreadID
" blocked on an invalid fd", tso->id);
- raiseAsync(cap, tso, (StgClosure *)blockedOnBadFD_closure,
+ raiseAsync(iomgr->cap, tso,
+ (StgClosure *)blockedOnBadFD_closure,
false, NULL);
break;
} else {
@@ -262,7 +260,7 @@ static void notifyIOCompletion(Capability *cap, StgAsyncIOOp *aiop)
StgTSO *tso = aiop->notify.tso;
tso->why_blocked = NotBlocked;
tso->_link = END_TSO_QUEUE;
- pushOnRunQueue(cap, tso);
+ pushOnRunQueue(iomgr->cap, tso);
}
break;
}
@@ -277,8 +275,7 @@ static void notifyIOCompletion(Capability *cap, StgAsyncIOOp *aiop)
}
-static void processIOCompletions(Capability *cap, CapIOManager *iomgr,
- int ncompletions)
+static void processIOCompletions(CapIOManager *iomgr, int ncompletions)
{
/* The scheme we use with poll is that we have a dense poll table, and a
* corresponding table that maps to the closure table index. The poll
@@ -320,7 +317,7 @@ static void processIOCompletions(Capability *cap, CapIOManager *iomgr,
* apply the same compacting to the aiop_poll_table.
*/
int ix_from; int ix_to;
- removeCompactClosureTable(cap, &iomgr->aiop_table, i,
+ removeCompactClosureTable(iomgr->cap, &iomgr->aiop_table, i,
&ix_from, &ix_to);
if (ix_to != ix_from) {
StgAsyncIOOp *aiop_to;
@@ -329,7 +326,7 @@ static void processIOCompletions(Capability *cap, CapIOManager *iomgr,
aiop_poll_table[ix_to] = aiop_poll_table[ix_from];
}
- notifyIOCompletion(cap, aiop);
+ notifyIOCompletion(iomgr, aiop);
n--;
} else {
/* You'd expect incrementing the poll table index to be
@@ -343,13 +340,11 @@ static void processIOCompletions(Capability *cap, CapIOManager *iomgr,
}
-void pollCompletedTimeoutsOrIOPoll(Capability *cap)
+void pollCompletedTimeoutsOrIOPoll(CapIOManager *iomgr)
{
- CapIOManager *iomgr = cap->iomgr;
-
if (!isEmptyTimeoutQueue(iomgr->timeout_queue)) {
Time now = getProcessElapsedTime();
- processTimeoutCompletions(cap, now);
+ processTimeoutCompletions(iomgr, now);
}
if (!isEmptyClosureTable(&iomgr->aiop_table)) {
@@ -379,7 +374,7 @@ void pollCompletedTimeoutsOrIOPoll(Capability *cap)
} else if (res > 0) {
int ncompletions = res;
ASSERT(ncompletions <= (int)nfds);
- processIOCompletions(cap, iomgr, ncompletions);
+ processIOCompletions(iomgr, ncompletions);
} else if (errno == EINTR) {
/* We got interrupted by a signal. This is unlikely since we asked
@@ -393,10 +388,8 @@ void pollCompletedTimeoutsOrIOPoll(Capability *cap)
}
-void awaitCompletedTimeoutsOrIOPoll(Capability *cap)
+void awaitCompletedTimeoutsOrIOPoll(CapIOManager *iomgr)
{
- CapIOManager *iomgr = cap->iomgr;
-
/* Loop until we've woken up some threads. This loop is needed because the
* poll() timing isn't accurate, we sometimes sleep for a while but not
* long enough to wake up a thread in a threadDelay. Or we may need to
@@ -409,14 +402,14 @@ void awaitCompletedTimeoutsOrIOPoll(Capability *cap)
!isEmptyClosureTable(&iomgr->aiop_table));
Time now = getProcessElapsedTime();
- processTimeoutCompletions(cap, now);
+ processTimeoutCompletions(iomgr, now);
/* If we didn't wake any threads due to expiring timeouts, then we need
* to wait on I/O. Or to put it another way, even if we did wake some
* threads, we'll still poll (but not wait) for I/O. This is to ensure
* we avoid starving threads blocked on I/O.
*/
- bool wait = emptyRunQueue(cap);
+ bool wait = emptyRunQueue(iomgr->cap);
/* Decide if we are going to wait if no I/O is ready, either:
* poll only, wait indefinitely, or wait until a timeout.
@@ -461,7 +454,7 @@ void awaitCompletedTimeoutsOrIOPoll(Capability *cap)
} else if (res > 0) {
int ncompletions = res;
ASSERT(ncompletions <= (int)nfds);
- processIOCompletions(cap, iomgr, ncompletions);
+ processIOCompletions(iomgr, ncompletions);
} else if (errno == EINTR) {
/* We got interrupted by a signal. In the non-threaded RTS, if the
@@ -471,7 +464,7 @@ void awaitCompletedTimeoutsOrIOPoll(Capability *cap)
* signal is serviced.
*/
#if defined(RTS_USER_SIGNALS)
- if (startPendingSignalHandlers(cap)) break;
+ if (startPendingSignalHandlers(iomgr->cap)) break;
#endif
/* We can also be interrupted by the shutdown signal handler, which
@@ -485,7 +478,7 @@ void awaitCompletedTimeoutsOrIOPoll(Capability *cap)
reportPollError(res, nfds);
}
- } while (emptyRunQueue(cap)
+ } while (emptyRunQueue(iomgr->cap)
&& (getSchedState() == SCHED_RUNNING));
}
@@ -507,12 +500,12 @@ static void reportPollError(int res, nfds_t nfds)
/* Helper function to double the size of the aiop_table and aiop_poll_table.
*/
-static bool enlargeTables(Capability *cap, CapIOManager *iomgr)
+static bool enlargeTables(CapIOManager *iomgr)
{
int oldcapacity = capacityClosureTable(&iomgr->aiop_table);
int newcapacity = (oldcapacity == 0) ? 1 : (oldcapacity * 2);
- bool ok = enlargeClosureTable(cap, &iomgr->aiop_table, newcapacity);
+ bool ok = enlargeClosureTable(iomgr->cap, &iomgr->aiop_table, newcapacity);
if (RTS_UNLIKELY(!ok)) return false;
/* Update the auxiliary aiop_poll_table to match */
=====================================
rts/posix/Poll.h
=====================================
@@ -19,19 +19,19 @@
void initCapabilityIOManagerPoll(CapIOManager *iomgr);
/* Synchronous I/O and timer operations */
-bool syncIOWaitReadyPoll(Capability *cap, StgTSO *tso,
+bool syncIOWaitReadyPoll(CapIOManager *iomgr, StgTSO *tso,
IOReadOrWrite rw, HsInt fd);
-void syncIOCancelPoll(Capability *cap, StgTSO *tso);
+void syncIOCancelPoll(CapIOManager *iomgr, StgTSO *tso);
/* Asynchronous operations */
-bool asyncIOWaitReadyPoll(Capability *cap, StgAsyncIOOp *aiop,
+bool asyncIOWaitReadyPoll(CapIOManager *iomgr, StgAsyncIOOp *aiop,
IOReadOrWrite rw, int fd);
-void asyncIOCancelPoll(Capability *cap, StgAsyncIOOp *aiop);
+void asyncIOCancelPoll(CapIOManager *iomgr, StgAsyncIOOp *aiop);
/* Scheduler operations */
bool anyPendingTimeoutsOrIOPoll(CapIOManager *iomgr);
-void pollCompletedTimeoutsOrIOPoll(Capability *cap);
-void awaitCompletedTimeoutsOrIOPoll(Capability *cap);
+void pollCompletedTimeoutsOrIOPoll(CapIOManager *iomgr);
+void awaitCompletedTimeoutsOrIOPoll(CapIOManager *iomgr);
#endif /* IOMGR_ENABLED_POLL */
=====================================
rts/posix/Select.c
=====================================
@@ -93,9 +93,8 @@ LowResTime getDelayTarget (HsInt us)
* if this is true, then our time has expired.
* (idea due to Andy Gill).
*/
-static bool wakeUpSleepingThreads (Capability *cap, LowResTime now)
+static bool wakeUpSleepingThreads (CapIOManager *iomgr, LowResTime now)
{
- CapIOManager *iomgr = cap->iomgr;
StgTSO *tso;
bool flag = false;
@@ -109,7 +108,7 @@ static bool wakeUpSleepingThreads (Capability *cap, LowResTime now)
tso->_link = END_TSO_QUEUE;
IF_DEBUG(scheduler, debugBelch("Waking up sleeping thread %"
FMT_StgThreadID "\n", tso->id));
- pushOnRunQueue(cap,tso);
+ pushOnRunQueue(iomgr->cap,tso);
flag = true;
}
return flag;
@@ -217,9 +216,8 @@ static enum FdState fdPollWriteState (int fd)
*
*/
void
-awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait)
+awaitCompletedTimeoutsOrIOSelect(CapIOManager *iomgr, bool wait)
{
- CapIOManager *iomgr = cap->iomgr;
StgTSO *tso, *prev, *next;
fd_set rfd,wfd;
int numFound;
@@ -244,7 +242,7 @@ awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait)
do {
now = getLowResTimeOfDay();
- if (wakeUpSleepingThreads(cap, now)) {
+ if (wakeUpSleepingThreads(iomgr, now)) {
return;
}
@@ -355,7 +353,7 @@ awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait)
*/
#if defined(RTS_USER_SIGNALS)
if (RtsFlags.MiscFlags.install_signal_handlers && signals_pending()) {
- startSignalHandlers(cap);
+ startSignalHandlers(iomgr->cap);
return; /* still hold the lock */
}
#endif
@@ -368,12 +366,12 @@ awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait)
/* check for threads that need waking up
*/
- wakeUpSleepingThreads(cap, getLowResTimeOfDay());
+ wakeUpSleepingThreads(iomgr, getLowResTimeOfDay());
/* If new runnable threads have arrived, stop waiting for
* I/O and run them.
*/
- if (!emptyRunQueue(cap)) {
+ if (!emptyRunQueue(iomgr->cap)) {
return; /* still hold the lock */
}
}
@@ -429,7 +427,7 @@ awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait)
IF_DEBUG(scheduler,
debugBelch("Killing blocked thread %" FMT_StgThreadID
" on bad fd=%i\n", tso->id, fd));
- raiseAsync(cap, tso,
+ raiseAsync(iomgr->cap, tso,
(StgClosure *)blockedOnBadFD_closure, false, NULL);
break;
case RTS_FD_IS_READY:
@@ -438,13 +436,13 @@ awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait)
tso->id));
tso->why_blocked = NotBlocked;
tso->_link = END_TSO_QUEUE;
- pushOnRunQueue(cap,tso);
+ pushOnRunQueue(iomgr->cap,tso);
break;
case RTS_FD_IS_BLOCKING:
if (prev == NULL)
iomgr->blocked_queue_hd = tso;
else
- setTSOLink(cap, prev, tso);
+ setTSOLink(iomgr->cap, prev, tso);
prev = tso;
break;
}
@@ -460,7 +458,7 @@ awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait)
}
} while (wait && getSchedState() == SCHED_RUNNING
- && emptyRunQueue(cap));
+ && emptyRunQueue(iomgr->cap));
}
#endif /* IOMGR_ENABLED_SELECT */
=====================================
rts/posix/Select.h
=====================================
@@ -15,7 +15,7 @@ typedef StgWord LowResTime;
LowResTime getDelayTarget (HsInt us);
-void awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait);
+void awaitCompletedTimeoutsOrIOSelect(CapIOManager *iomgr, bool wait);
#include "EndPrivate.h"
=====================================
rts/posix/Timeout.c
=====================================
@@ -26,7 +26,7 @@
*/
#if defined(IOMGR_ENABLED_POLL)
-bool syncDelayTimeout(Capability *cap, StgTSO *tso, HsInt us_delay)
+bool syncDelayTimeout(CapIOManager *iomgr, StgTSO *tso, HsInt us_delay)
{
Time now = getProcessElapsedTime();
Time target;
@@ -42,16 +42,16 @@ bool syncDelayTimeout(Capability *cap, StgTSO *tso, HsInt us_delay)
/* fill in a new timeout queue entry */
StgTimeout *timeout;
- timeout = (StgTimeout *)allocateMightFail(cap, sizeofW(StgTimeout));
+ timeout = (StgTimeout *)allocateMightFail(iomgr->cap, sizeofW(StgTimeout));
if (RTS_UNLIKELY(timeout == NULL)) { return false; }
union NotifyCompletion notify = { .tso = tso };
- initElemTimeoutQueue(timeout, notify, NotifyTSO, cap->r.rCCCS);
+ initElemTimeoutQueue(timeout, notify, NotifyTSO, iomgr->cap->r.rCCCS);
ASSERT(tso->why_blocked == NotBlocked);
tso->why_blocked = BlockedOnDelay;
tso->block_info.timeout = timeout;
- insertTimeoutQueue(&cap->iomgr->timeout_queue, timeout, target);
+ insertTimeoutQueue(&iomgr->timeout_queue, timeout, target);
debugTrace(DEBUG_iomanager,
"timer for delay of %lld usec installed at time %lld ns",
@@ -60,18 +60,18 @@ bool syncDelayTimeout(Capability *cap, StgTSO *tso, HsInt us_delay)
}
-void syncDelayCancelTimeout(Capability *cap, StgTSO *tso)
+void syncDelayCancelTimeout(CapIOManager *iomgr, StgTSO *tso)
{
ASSERT(tso->why_blocked == BlockedOnDelay);
StgTimeoutQueue *timeout = tso->block_info.timeout;
- deleteTimeoutQueue(&cap->iomgr->timeout_queue, timeout);
+ deleteTimeoutQueue(&iomgr->timeout_queue, timeout);
tso->block_info.closure = (StgClosure *)END_TSO_QUEUE;
/* the timeout is no longer accessible from anywhere (except here) */
IF_NONMOVING_WRITE_BARRIER_ENABLED {
- updateRemembSetPushClosure(cap, (StgClosure *)timeout);
+ updateRemembSetPushClosure(iomgr->cap, (StgClosure *)timeout);
}
/* We don't put the TSO back on the run queue or change the why_blocked
@@ -79,7 +79,7 @@ void syncDelayCancelTimeout(Capability *cap, StgTSO *tso)
*/
}
-static void notifyTimeoutCompletion(Capability *cap, StgTimeout *timeout);
+static void notifyTimeoutCompletion(CapIOManager *iomgr, StgTimeout *timeout);
/* We use the 64bit Time type from rts/Time.h so our max time (in nanosecond
* precision) is over 290 years from the epoch of the monotonic clock.
@@ -90,10 +90,8 @@ static void notifyTimeoutCompletion(Capability *cap, StgTimeout *timeout);
* With 64bit Time we do not need to worry about clock wraparound and can just
* use the simple formula.
*/
-void processTimeoutCompletions(Capability *cap, Time now)
+void processTimeoutCompletions(CapIOManager *iomgr, Time now)
{
- CapIOManager *iomgr = cap->iomgr;
-
/* Pop entries from the front of the sleeping queue that are past their
* wake time, and unblock the corresponding MVars.
*/
@@ -105,17 +103,17 @@ void processTimeoutCompletions(Capability *cap, Time now)
debugTrace(DEBUG_iomanager,"timer expired at %lld ns", waketime);
StgTimeout *timeout;
deleteMinTimeoutQueue(&iomgr->timeout_queue, &timeout);
- notifyTimeoutCompletion(cap, timeout);
+ notifyTimeoutCompletion(iomgr, timeout);
/* the timeout is no longer accessible from anywhere (except here) */
IF_NONMOVING_WRITE_BARRIER_ENABLED {
- updateRemembSetPushClosure(cap, (StgClosure *)timeout);
+ updateRemembSetPushClosure(iomgr->cap, (StgClosure *)timeout);
}
}
}
-static void notifyTimeoutCompletion(Capability *cap, StgTimeout *timeout)
+static void notifyTimeoutCompletion(CapIOManager *iomgr, StgTimeout *timeout)
{
switch (timeout->notify_type) {
case NotifyTSO:
@@ -123,11 +121,11 @@ static void notifyTimeoutCompletion(Capability *cap, StgTimeout *timeout)
StgTSO *tso = timeout->notify.tso;
tso->why_blocked = NotBlocked;
tso->_link = END_TSO_QUEUE;
- pushOnRunQueue(cap, tso);
+ pushOnRunQueue(iomgr->cap, tso);
break;
}
case NotifyMVar:
- performTryPutMVar(cap, timeout->notify.mvar, Unit_closure);
+ performTryPutMVar(iomgr->cap, timeout->notify.mvar, Unit_closure);
break;
case NotifyTVar:
=====================================
rts/posix/Timeout.h
=====================================
@@ -12,9 +12,9 @@
#include "BeginPrivate.h"
-bool syncDelayTimeout(Capability *cap, StgTSO *tso, HsInt us_delay);
+bool syncDelayTimeout(CapIOManager *iomgr, StgTSO *tso, HsInt us_delay);
-void syncDelayCancelTimeout(Capability *cap, StgTSO *tso);
+void syncDelayCancelTimeout(CapIOManager *iomgr, StgTSO *tso);
/* Process the completion of any timeouts that have expired: this means
* notifying whatever is waiting on the timeout, a thread, an MVar or TVar.
@@ -24,7 +24,7 @@ void syncDelayCancelTimeout(Capability *cap, StgTSO *tso);
* No result is returned: callers can check if there are now any runnable
* threads by consulting the scheduler's run queue.
*/
-void processTimeoutCompletions(Capability *cap, Time now);
+void processTimeoutCompletions(CapIOManager *iomgr, Time now);
/* Utility to compute the timeout wait time (in milliseconds) between now and
* the next timer expiry (if any), or no waiting (if !wait).
=====================================
utils/deriveConstants/Main.hs
=====================================
@@ -414,6 +414,7 @@ wanteds os = concat
,structField C "Capability" "weak_ptr_list_tl"
,structField C "Capability" "n_run_queue"
,structField C "Capability" "pinned_object_block"
+ ,structField C "Capability" "iomgr"
,structField Both "bdescr" "start"
,structField Both "bdescr" "free"
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/ac79161475ca41f462e6b1ff66e641…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/ac79161475ca41f462e6b1ff66e641…
You're receiving this email because of your account on gitlab.haskell.org.
1
0