Wolfgang Jeltsch pushed to branch wip/jeltsch/ghc-9-14-building-base at Glasgow Haskell Compiler / GHC
Commits:
-
192be0b6
by Luite Stegeman at 2026-09-07T19:43:36-04:00
-
604eb43c
by Simon Jakobi at 2026-09-07T19:44:15-04:00
-
06eee015
by Luite Stegeman at 2026-09-08T06:03:06+02:00
-
f8b2bd8f
by Alan Zimmerman at 2026-09-08T09:39:12-04:00
-
1ca7779f
by Wolfgang Jeltsch at 2026-09-09T18:36:39+03:00
-
513398d2
by Wolfgang Jeltsch at 2026-09-09T18:36:39+03:00
-
2725c438
by Wolfgang Jeltsch at 2026-09-09T18:36:39+03:00
-
9dd666d9
by Wolfgang Jeltsch at 2026-09-09T18:36:39+03:00
-
451374da
by Wolfgang Jeltsch at 2026-09-09T18:36:39+03:00
-
c8706244
by Wolfgang Jeltsch at 2026-09-09T18:36:39+03:00
-
50d76e7a
by Wolfgang Jeltsch at 2026-09-09T18:36:39+03:00
-
5304a399
by Wolfgang Jeltsch at 2026-09-09T18:36:39+03:00
-
9bf0096c
by Wolfgang Jeltsch at 2026-09-09T18:36:39+03:00
-
a105b512
by Wolfgang Jeltsch at 2026-09-09T18:36:39+03:00
-
800eefcc
by Wolfgang Jeltsch at 2026-09-09T18:36:39+03:00
-
89e3c08e
by Wolfgang Jeltsch at 2026-09-09T18:36:39+03:00
-
685b19d6
by Wolfgang Jeltsch at 2026-09-09T18:36:39+03:00
-
3b6990fe
by Wolfgang Jeltsch at 2026-09-09T18:36:39+03:00
-
ee663f66
by Wolfgang Jeltsch at 2026-09-09T18:36:39+03:00
-
595c5829
by Wolfgang Jeltsch at 2026-09-09T18:36:39+03:00
-
bdcd39aa
by Wolfgang Jeltsch at 2026-09-09T18:36:39+03:00
28 changed files:
- .gitlab-ci.yml
- + .gitlab/base-ci.sh
- + changelog.d/fix-parallel-gc-selector-race-27477
- compiler/GHC/Hs/Doc.hs
- compiler/GHC/Hs/Extension/Pass.hs
- hadrian/src/Builder.hs
- libraries/base/base.cabal.in
- libraries/base/src/GHC/Stack.hs
- libraries/ghc-internal/src/GHC/Internal/Stack.hs
- rts/Continuation.c
- rts/Interpreter.c
- rts/Schedule.c
- rts/sm/Evac.c
- + testsuite/tests/bytecode/T27633/Obj.hs
- + testsuite/tests/bytecode/T27633/T27633a.hs
- + testsuite/tests/bytecode/T27633/T27633a.stdout
- + testsuite/tests/bytecode/T27633/T27633b.hs
- + testsuite/tests/bytecode/T27633/T27633b.stdout
- + testsuite/tests/bytecode/T27633/all.T
- + testsuite/tests/ghci.debugger/scripts/T27633c.hs
- + testsuite/tests/ghci.debugger/scripts/T27633c.script
- + testsuite/tests/ghci.debugger/scripts/T27633c.stdout
- + testsuite/tests/ghci.debugger/scripts/T27633c_obj.hs
- testsuite/tests/ghci.debugger/scripts/all.T
- + testsuite/tests/rts/T27477.hs
- + testsuite/tests/rts/T27477.stdout
- testsuite/tests/rts/all.T
- utils/check-exact/ExactPrint.hs
Changes:
| ... | ... | @@ -69,7 +69,7 @@ stages: |
| 69 | 69 | - quick-build # A very quick smoke-test to weed out broken commits
|
| 70 | 70 | - full-build # Build all the things
|
| 71 | 71 | - packaging # Source distribution, etc.
|
| 72 | - - testing # head.hackage correctness and compiler performance testing
|
|
| 72 | + - testing # Various tests
|
|
| 73 | 73 | - deploy # push documentation
|
| 74 | 74 | |
| 75 | 75 | # Note [The CI Story]
|
| ... | ... | @@ -1162,6 +1162,44 @@ ghc-wasm-meta-unreg: |
| 1162 | 1162 | UPSTREAM_GHC_FLAVOUR: unreg
|
| 1163 | 1163 | UPSTREAM_GHC_JOB_NAME: x86_64-linux-alpine3_23-wasm-unreg-cross_wasm32-wasi-release+host_fully_static+text_simdutf
|
| 1164 | 1164 | |
| 1165 | +############################################################
|
|
| 1166 | +# Testing the compatibility of `base` with other GHCs
|
|
| 1167 | +############################################################
|
|
| 1168 | + |
|
| 1169 | +base-with-other-ghcs-linux:
|
|
| 1170 | + stage: testing
|
|
| 1171 | + needs:
|
|
| 1172 | + - job: x86_64-linux-deb13-validate
|
|
| 1173 | + optional: true
|
|
| 1174 | + - job: nightly-x86_64-linux-deb13-validate
|
|
| 1175 | + optional: true
|
|
| 1176 | + - job: release-x86_64-linux-deb13-release
|
|
| 1177 | + optional: true
|
|
| 1178 | + dependencies: null
|
|
| 1179 | + image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb12:$DOCKER_REV"
|
|
| 1180 | + tags:
|
|
| 1181 | + - x86_64-linux
|
|
| 1182 | + script: .gitlab/base-ci.sh x86_64-deb12-linux 9.14.1
|
|
| 1183 | + rules:
|
|
| 1184 | + - *full-ci
|
|
| 1185 | + |
|
| 1186 | +base-with-other-ghcs-windows:
|
|
| 1187 | + stage: testing
|
|
| 1188 | + needs:
|
|
| 1189 | + - job: x86_64-windows-validate
|
|
| 1190 | + optional: true
|
|
| 1191 | + - job: nightly-x86_64-windows-validate
|
|
| 1192 | + optional: true
|
|
| 1193 | + - job: release-x86_64-windows-release
|
|
| 1194 | + optional: true
|
|
| 1195 | + dependencies: null
|
|
| 1196 | + image: null
|
|
| 1197 | + tags:
|
|
| 1198 | + - new-x86_64-windows
|
|
| 1199 | + script: bash .gitlab/base-ci.sh x86_64-unknown-mingw32 9.14.1
|
|
| 1200 | + rules:
|
|
| 1201 | + - *full-ci
|
|
| 1202 | + |
|
| 1165 | 1203 | ############################################################
|
| 1166 | 1204 | # Documentation deployment via GitLab Pages
|
| 1167 | 1205 | ############################################################
|
| 1 | +#!/usr/bin/env bash
|
|
| 2 | + |
|
| 3 | +# This script supports testing the compatibility of the in-tree `base` with
|
|
| 4 | +# different non-in-tree GHCs. We deliberately use a script separate from
|
|
| 5 | +# `.gitlab/ci.sh` for this purspose, because such support is supposed to become
|
|
| 6 | +# part of the CI infrastructure of a separately maintained `base`.
|
|
| 7 | +#
|
|
| 8 | +# Currently, this script can only test that the in-tree `base` can be *built*
|
|
| 9 | +# with certain *released* GHCs.
|
|
| 10 | +#
|
|
| 11 | +# This script can run on both Unix and Windows. Since GHC’s infrastructure does
|
|
| 12 | +# not offer Cabal pre-installed on Windows, this script uses a `Setup.hs` file
|
|
| 13 | +# to build `base`, which works across operating systems.
|
|
| 14 | + |
|
| 15 | +# Establish error propagation
|
|
| 16 | +set -e -o pipefail
|
|
| 17 | + |
|
| 18 | +# Process arguments
|
|
| 19 | +if [ $# -lt 1 ]
|
|
| 20 | +then
|
|
| 21 | + echo 'Build `base` with released GHCs'
|
|
| 22 | + echo "Usage: base-ci ⟨platform⟩ ⟨ghc-version⟩ …"
|
|
| 23 | + exit 1
|
|
| 24 | +fi >&2
|
|
| 25 | +platform=$1
|
|
| 26 | +shift
|
|
| 27 | +ghc_versions=$*
|
|
| 28 | + |
|
| 29 | +# Save project root
|
|
| 30 | +project_root=$PWD
|
|
| 31 | + |
|
| 32 | +# Create directories for other GHCs
|
|
| 33 | +mkdir other-ghcs
|
|
| 34 | +mkdir other-ghcs/src
|
|
| 35 | +mkdir other-ghcs/opt
|
|
| 36 | + |
|
| 37 | +# Amend the `base` sources
|
|
| 38 | +cd libraries/base
|
|
| 39 | +sed -E -e 's/^( *ghc-internal)[^[:alnum:]-].*(,|$)/\1\2/' \
|
|
| 40 | + < base.cabal.in \
|
|
| 41 | + > base.cabal
|
|
| 42 | +cat <<. >Setup.hs
|
|
| 43 | +import Distribution.Simple
|
|
| 44 | +main = defaultMain
|
|
| 45 | +.
|
|
| 46 | +cd ${project_root}
|
|
| 47 | + |
|
| 48 | +# Build `base` with the different GHCs
|
|
| 49 | +for ghc_version in ${ghc_versions}
|
|
| 50 | +do
|
|
| 51 | + # Install the GHC
|
|
| 52 | + ghc_installation=${project_root}/other-ghcs/opt/${ghc_version}
|
|
| 53 | + cd other-ghcs/src
|
|
| 54 | + archive_file=ghc-${ghc_version}-${platform}.tar.xz
|
|
| 55 | + curl https://downloads.haskell.org/~ghc/${ghc_version}/${archive_file} \
|
|
| 56 | + >${ghc_version}.tar.xz
|
|
| 57 | + tar -xJf ${ghc_version}.tar.xz
|
|
| 58 | + if [ -f ghc-${ghc_version}-*/configure ]
|
|
| 59 | + then # Unix
|
|
| 60 | + cd ghc-${ghc_version}-*
|
|
| 61 | + ./configure --prefix "${ghc_installation}"
|
|
| 62 | + make install
|
|
| 63 | + else # Windows
|
|
| 64 | + mv ghc-${ghc_version}-* "${ghc_installation}"
|
|
| 65 | + fi
|
|
| 66 | + cd ${project_root}
|
|
| 67 | + |
|
| 68 | + # Build `base` with the installed GHC
|
|
| 69 | + cd libraries/base
|
|
| 70 | + "${ghc_installation}/bin/runghc" Setup.hs configure \
|
|
| 71 | + --with-compiler "${ghc_installation}/bin/ghc" \
|
|
| 72 | + -O0
|
|
| 73 | + "${ghc_installation}/bin/runghc" Setup.hs build
|
|
| 74 | + cd ${project_root}
|
|
| 75 | +done |
| 1 | +section: rts
|
|
| 2 | +synopsis: Fix a parallel GC race on weakly-ordered architectures (AArch64) that could crash or silently corrupt the heap
|
|
| 3 | +description:
|
|
| 4 | + On weakly-ordered architectures such as AArch64 programs using
|
|
| 5 | + could crash during parallel garbage collection (segmentation fault
|
|
| 6 | + or ``internal error: eval_thunk_selector: strange selectee <n>``) or
|
|
| 7 | + continue running with silently corrupted heap data, due to a missing
|
|
| 8 | + memory barrier in the parallel GC.
|
|
| 9 | +mrs: !16488
|
|
| 10 | +issues: #27477 |
| ... | ... | @@ -58,6 +58,7 @@ import Language.Haskell.Syntax.Doc |
| 58 | 58 | import Language.Haskell.Syntax.Extension
|
| 59 | 59 | import Language.Haskell.Syntax.Module.Name
|
| 60 | 60 | |
| 61 | +-- Exact print annotations ignore LHsDoc, so bare SrcSpan is fine
|
|
| 61 | 62 | type instance Anno (WithHsDocIdentifiers (HsDocString (GhcPass pass)) (GhcPass pass)) = SrcSpan
|
| 62 | 63 | |
| 63 | 64 | deriving instance (Data pass, Data (LIdP pass), Data a) => Data (WithHsDocIdentifiers a pass)
|
| ... | ... | @@ -46,6 +46,7 @@ type instance XRec (GhcPass p) a = XRecGhc a |
| 46 | 46 | -- but pass-independent, source location
|
| 47 | 47 | type XRecGhc a = GenLocated (Anno a) a
|
| 48 | 48 | |
| 49 | +-- Exact print annotations ignore LHsDoc, so bare SrcSpan is fine
|
|
| 49 | 50 | type instance Anno (HsDocString (GhcPass _)) = SrcSpan
|
| 50 | 51 | type instance Anno HsDocStringChunk = SrcSpan
|
| 51 | 52 |
| ... | ... | @@ -387,7 +387,7 @@ instance H.Builder Builder where |
| 387 | 387 | -- RunTest produces a very large amount of (colorised) output;
|
| 388 | 388 | -- Don't attempt to capture it.
|
| 389 | 389 | Testsuite RunTest -> do
|
| 390 | - Exit code <- cmd' prog buildArgs buildOptions
|
|
| 390 | + Exit code <- cmdExe prog buildArgs buildOptions
|
|
| 391 | 391 | when (code /= ExitSuccess) $ do
|
| 392 | 392 | fail "tests failed"
|
| 393 | 393 |
| ... | ... | @@ -33,9 +33,10 @@ Library |
| 33 | 33 | ghc-internal == @ProjectVersionForLib@.*,
|
| 34 | 34 | ghc-prim,
|
| 35 | 35 | |
| 36 | - -- Set -frebindable-known-names,
|
|
| 37 | - -- since GHC.Essentials isn't available yet
|
|
| 38 | - ghc-options: -frebindable-known-names
|
|
| 36 | + if impl(ghc >= 10.1)
|
|
| 37 | + -- Set -frebindable-known-names,
|
|
| 38 | + -- since GHC.Essentials isn't available yet
|
|
| 39 | + ghc-options: -frebindable-known-names
|
|
| 39 | 40 | |
| 40 | 41 | exposed-modules:
|
| 41 | 42 | Control.Applicative
|
| ... | ... | @@ -307,9 +308,11 @@ Library |
| 307 | 308 | |
| 308 | 309 | other-modules:
|
| 309 | 310 | Data.List.NubOrdSet
|
| 310 | - GHC.Essentials
|
|
| 311 | 311 | System.CPUTime.Unsupported
|
| 312 | 312 | System.CPUTime.Utils
|
| 313 | + if impl(ghc >= 10.1)
|
|
| 314 | + other-modules:
|
|
| 315 | + GHC.Essentials
|
|
| 313 | 316 | if os(windows)
|
| 314 | 317 | other-modules:
|
| 315 | 318 | System.CPUTime.Windows
|
| 1 | 1 | {-# LANGUAGE Safe #-}
|
| 2 | 2 | |
| 3 | +{-# LANGUAGE CPP #-}
|
|
| 4 | +{-# LANGUAGE RankNTypes #-}
|
|
| 5 | +{-# LANGUAGE ImplicitParams #-}
|
|
| 6 | + |
|
| 3 | 7 | -- |
|
| 4 | 8 | --
|
| 5 | 9 | -- Module : GHC.Stack
|
| ... | ... | @@ -51,3 +55,26 @@ module GHC.Stack |
| 51 | 55 | ) where
|
| 52 | 56 | |
| 53 | 57 | import GHC.Internal.Stack
|
| 58 | + |
|
| 59 | +#if __GLASGOW_HASKELL__ > 1000
|
|
| 60 | + |
|
| 61 | +import GHC.Essentials as Rebindable
|
|
| 62 | + |
|
| 63 | +#endif
|
|
| 64 | + |
|
| 65 | +-- | Explicitly bring the empty call stack into scope.
|
|
| 66 | +--
|
|
| 67 | +-- Mostly useful for silencing warnings generated by @-Wdefaulted-callstack@ in
|
|
| 68 | +-- places such as:
|
|
| 69 | +--
|
|
| 70 | +-- - The body of a class method in an instance of an externally defined type
|
|
| 71 | +-- class whose type signature doesn't contain a 'HasCallStack' constraint.
|
|
| 72 | +--
|
|
| 73 | +-- - The body of the @main@ function.
|
|
| 74 | +--
|
|
| 75 | +-- @since 4.24.0.0
|
|
| 76 | +withEmptyCallStack :: (HasCallStack => a) -> a
|
|
| 77 | +withEmptyCallStack do_this =
|
|
| 78 | + -- See Note [Warn about defaulted CallStacks]
|
|
| 79 | + let ?callStack = emptyCallStack
|
|
| 80 | + in do_this |
| ... | ... | @@ -29,7 +29,7 @@ module GHC.Internal.Stack ( |
| 29 | 29 | -- * HasCallStack call stacks
|
| 30 | 30 | CallStack, HasCallStack, callStack, emptyCallStack, freezeCallStack,
|
| 31 | 31 | fromCallSiteList, getCallStack, popCallStack,
|
| 32 | - pushCallStack, withFrozenCallStack, withEmptyCallStack,
|
|
| 32 | + pushCallStack, withFrozenCallStack,
|
|
| 33 | 33 | prettyCallStackLines, prettyCallStack,
|
| 34 | 34 | |
| 35 | 35 | -- * Source locations
|
| ... | ... | @@ -105,23 +105,6 @@ withFrozenCallStack do_this = |
| 105 | 105 | let ?callStack = freezeCallStack (popCallStack callStack)
|
| 106 | 106 | in do_this
|
| 107 | 107 | |
| 108 | --- | Explicitly bring the empty call stack into scope.
|
|
| 109 | ---
|
|
| 110 | --- Mostly useful for silencing warnings generated by @-Wdefaulted-callstack@ in
|
|
| 111 | --- places such as:
|
|
| 112 | ---
|
|
| 113 | --- - The body of a class method in an instance of an externally defined type
|
|
| 114 | --- class whose type signature doesn't contain a 'HasCallStack' constraint.
|
|
| 115 | ---
|
|
| 116 | --- - The body of the @main@ function.
|
|
| 117 | ---
|
|
| 118 | --- @since 4.24.0.0
|
|
| 119 | -withEmptyCallStack :: (HasCallStack => a) -> a
|
|
| 120 | -withEmptyCallStack do_this =
|
|
| 121 | - -- See Note [Warn about defaulted CallStacks]
|
|
| 122 | - let ?callStack = emptyCallStack
|
|
| 123 | - in do_this
|
|
| 124 | - |
|
| 125 | 108 | -- prettySrcLoc and prettyCallStack are defined here to avoid hs-boot
|
| 126 | 109 | -- files. See Note [Definition of CallStack]
|
| 127 | 110 |
| ... | ... | @@ -392,6 +392,10 @@ StgClosure *captureContinuationAndAbort(Capability *cap, StgTSO *tso, StgPromptT |
| 392 | 392 | const StgInfoTable *apply_mask_frame = NULL;
|
| 393 | 393 | StgWord mask_frame_offset = 0;
|
| 394 | 394 | |
| 395 | + // see Note [GHCi unboxed tuples stack spills]
|
|
| 396 | + bool seen_ctoi_tuple_frame = false;
|
|
| 397 | + StgWord ctoi_tuple_spill_words = 0;
|
|
| 398 | + |
|
| 395 | 399 | /* --- Phase 1: Find the matching prompt frame ---------------------------- */
|
| 396 | 400 | |
| 397 | 401 | IF_DEBUG(continuation,
|
| ... | ... | @@ -459,7 +463,8 @@ StgClosure *captureContinuationAndAbort(Capability *cap, StgTSO *tso, StgPromptT |
| 459 | 463 | |
| 460 | 464 | // see Note [GHCi unboxed tuples stack spills]
|
| 461 | 465 | if (info_ptr == &stg_ctoi_t_info) {
|
| 462 | - tso->ctoi_tuple_spill_words = frame[CTOI_OLD_TUPLE_SPILL_WORDS_OFFSET];
|
|
| 466 | + seen_ctoi_tuple_frame = true;
|
|
| 467 | + ctoi_tuple_spill_words = frame[CTOI_OLD_TUPLE_SPILL_WORDS_OFFSET];
|
|
| 463 | 468 | }
|
| 464 | 469 | |
| 465 | 470 | // Advance to the next frame.
|
| ... | ... | @@ -475,6 +480,11 @@ StgClosure *captureContinuationAndAbort(Capability *cap, StgTSO *tso, StgPromptT |
| 475 | 480 | dirty_TSO(cap, tso);
|
| 476 | 481 | dirty_STACK(cap, stack);
|
| 477 | 482 | |
| 483 | + // see Note [GHCi unboxed tuples stack spills] in StgMiscClosures.cmm
|
|
| 484 | + if (seen_ctoi_tuple_frame) {
|
|
| 485 | + tso->ctoi_tuple_spill_words = ctoi_tuple_spill_words;
|
|
| 486 | + }
|
|
| 487 | + |
|
| 478 | 488 | StgContinuation *cont = (StgContinuation *)allocate(cap, CONTINUATION_sizeW(total_words));
|
| 479 | 489 | SET_HDR(cont, &stg_CONTINUATION_info, stack->header.prof.ccs);
|
| 480 | 490 | cont->apply_mask_frame = apply_mask_frame;
|
| ... | ... | @@ -1982,6 +1982,20 @@ run_BCO: |
| 1982 | 1982 | for (i = 0; i < size_words; i++) {
|
| 1983 | 1983 | new_aps->payload[i] = (StgClosure *)ReadSpW(i);
|
| 1984 | 1984 | }
|
| 1985 | + |
|
| 1986 | + /* The stg_ctoi_t frame we copied is entered again when
|
|
| 1987 | + execution resumes, but tso->ctoi_tuple_spill_words
|
|
| 1988 | + holds the enclosing frame's count: it was restored
|
|
| 1989 | + from old_spill when this case continuation was entered
|
|
| 1990 | + (bci_RETURN_T). Put back the count belonging to this
|
|
| 1991 | + frame, so the invariant holds while the thread sits at
|
|
| 1992 | + the breakpoint.
|
|
| 1993 | + |
|
| 1994 | + See Note [GHCi unboxed tuples stack spills] */
|
|
| 1995 | + if (ReadSpW(size_returned_frame) == (W_)&stg_ctoi_t_info) {
|
|
| 1996 | + cap->r.rCurrentTSO->ctoi_tuple_spill_words =
|
|
| 1997 | + ReadSpW(size_returned_frame + CTOI_TUPLE_INFO_OFFSET) >> 24;
|
|
| 1998 | + }
|
|
| 1985 | 1999 | }
|
| 1986 | 2000 | else {
|
| 1987 | 2001 |
| ... | ... | @@ -3271,6 +3271,10 @@ findRetryFrameHelper (Capability *cap, StgTSO *tso) |
| 3271 | 3271 | default:
|
| 3272 | 3272 | ASSERT(info->i.type != CATCH_FRAME);
|
| 3273 | 3273 | ASSERT(info->i.type != STOP_FRAME);
|
| 3274 | + // see Note [GHCi unboxed tuples stack spills] in StgMiscClosures.cmm
|
|
| 3275 | + if (*p == (StgWord)&stg_ctoi_t_info) {
|
|
| 3276 | + tso->ctoi_tuple_spill_words = p[CTOI_OLD_TUPLE_SPILL_WORDS_OFFSET]; // restore old_spill
|
|
| 3277 | + }
|
|
| 3274 | 3278 | p = next;
|
| 3275 | 3279 | continue;
|
| 3276 | 3280 | }
|
| ... | ... | @@ -3332,6 +3336,10 @@ findAtomicallyFrameHelper (Capability *cap, StgTSO *tso) |
| 3332 | 3336 | default:
|
| 3333 | 3337 | ASSERT(info->i.type != CATCH_FRAME);
|
| 3334 | 3338 | ASSERT(info->i.type != STOP_FRAME);
|
| 3339 | + // see Note [GHCi unboxed tuples stack spills] in StgMiscClosures.cmm
|
|
| 3340 | + if (*p == (StgWord)&stg_ctoi_t_info) {
|
|
| 3341 | + tso->ctoi_tuple_spill_words = p[CTOI_OLD_TUPLE_SPILL_WORDS_OFFSET]; // restore old_spill
|
|
| 3342 | + }
|
|
| 3335 | 3343 | p = next;
|
| 3336 | 3344 | continue;
|
| 3337 | 3345 | }
|
| ... | ... | @@ -1361,7 +1361,11 @@ selector_loop: |
| 1361 | 1361 | // from-space during marking, for example. We rely on the property
|
| 1362 | 1362 | // that evacuate() doesn't mind if it gets passed a to-space pointer.
|
| 1363 | 1363 | |
| 1364 | - info = RELAXED_LOAD((StgInfoTable**) &selectee->header.info);
|
|
| 1364 | + // NB. this load must be ordered: the selectee may be updated
|
|
| 1365 | + // concurrently by another GC thread's unchain_thunk_selectors(),
|
|
| 1366 | + // which publishes an indirection by writing the indirectee and
|
|
| 1367 | + // then RELEASE-storing the info pointer. See #27477.
|
|
| 1368 | + info = ACQUIRE_LOAD((StgInfoTable**) &selectee->header.info);
|
|
| 1365 | 1369 | |
| 1366 | 1370 | if (IS_FORWARDING_PTR(info)) {
|
| 1367 | 1371 | // We don't follow pointers into to-space; the constructor
|
| 1 | +{-# OPTIONS_GHC -fobject-code #-}
|
|
| 2 | +{-# LANGUAGE UnboxedTuples, MagicHash #-}
|
|
| 3 | +module Obj where
|
|
| 4 | + |
|
| 5 | +import GHC.Exts
|
|
| 6 | + |
|
| 7 | +-- Compiled to object code; returns a large unboxed tuple, so the return
|
|
| 8 | +-- into an interpreted caller goes through the native stg_ctoi_t entry code,
|
|
| 9 | +-- which reads tso->ctoi_tuple_spill_words.
|
|
| 10 | +-- See Note [GHCi unboxed tuples stack spills] in rts/StgMiscClosures.cmm.
|
|
| 11 | +mkT :: State# RealWorld -> (# State# RealWorld, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int# #)
|
|
| 12 | +mkT s = (# s, 1#, 2#, 3#, 4#, 5#, 6#, 7#, 8#, 9#, 10#, 11#, 12#, 13#, 14#, 15#, 16#, 17#, 18#, 19#, 20#, 21#, 22#, 23#, 24# #)
|
|
| 13 | +{-# NOINLINE mkT #-} |
| 1 | +{-# LANGUAGE UnboxedTuples, MagicHash #-}
|
|
| 2 | +{-# OPTIONS_GHC -fbyte-code #-}
|
|
| 3 | + |
|
| 4 | +-- Regression test for #27633 (bug 1): a failed control0# capture must not
|
|
| 5 | +-- clobber tso->ctoi_tuple_spill_words while a generic stg_ctoi_t frame is
|
|
| 6 | +-- still live on the stack.
|
|
| 7 | +-- See Note [GHCi unboxed tuples stack spills] in rts/StgMiscClosures.cmm.
|
|
| 8 | + |
|
| 9 | +module Main where
|
|
| 10 | + |
|
| 11 | +import Control.Exception
|
|
| 12 | +import GHC.Exts
|
|
| 13 | +import GHC.IO (IO(..))
|
|
| 14 | +import Obj
|
|
| 15 | + |
|
| 16 | +unIO :: IO a -> State# RealWorld -> (# State# RealWorld, a #)
|
|
| 17 | +unIO (IO f) = f
|
|
| 18 | + |
|
| 19 | +-- control0# with a tag that has no matching prompt anywhere on the stack;
|
|
| 20 | +-- the resulting exception is caught right here, above the stg_ctoi_t frame,
|
|
| 21 | +-- so the unwind stops before reaching the frame.
|
|
| 22 | +failing :: IO ()
|
|
| 23 | +failing = IO (\s0 -> case newPromptTag# s0 of
|
|
| 24 | + (# s1, tag #) -> control0# tag (\_ s -> (# s, () #)) s1)
|
|
| 25 | + `catch` \(SomeException _) -> return ()
|
|
| 26 | + |
|
| 27 | +scrut :: State# RealWorld -> (# State# RealWorld, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int# #)
|
|
| 28 | +scrut s0 = case unIO failing s0 of (# s1, _ #) -> mkT s1
|
|
| 29 | +{-# NOINLINE scrut #-}
|
|
| 30 | + |
|
| 31 | +main :: IO ()
|
|
| 32 | +main = IO (\s0 -> case scrut s0 of
|
|
| 33 | + (# s1, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24 #) ->
|
|
| 34 | + unIO (print (I# (x1 +# x2 +# x3 +# x4 +# x5 +# x6 +# x7 +# x8 +# x9 +# x10 +# x11 +# x12 +# x13 +# x14 +# x15 +# x16 +# x17 +# x18 +# x19 +# x20 +# x21 +# x22 +# x23 +# x24))) s1) |
| 1 | +300 |
| 1 | +{-# LANGUAGE UnboxedTuples, MagicHash #-}
|
|
| 2 | +{-# OPTIONS_GHC -fbyte-code #-}
|
|
| 3 | + |
|
| 4 | +-- Regression test for #27633 (bug 2): STM retry unwinding
|
|
| 5 | +-- (findRetryFrameHelper/findAtomicallyFrameHelper) must restore
|
|
| 6 | +-- tso->ctoi_tuple_spill_words when it discards a generic stg_ctoi_t frame.
|
|
| 7 | +-- See Note [GHCi unboxed tuples stack spills] in rts/StgMiscClosures.cmm.
|
|
| 8 | + |
|
| 9 | +module Main where
|
|
| 10 | + |
|
| 11 | +import GHC.Conc (STM(..), atomically, orElse)
|
|
| 12 | +import GHC.Exts
|
|
| 13 | +import GHC.IO (IO(..))
|
|
| 14 | +import Obj
|
|
| 15 | + |
|
| 16 | +unIO :: IO a -> State# RealWorld -> (# State# RealWorld, a #)
|
|
| 17 | +unIO (IO f) = f
|
|
| 18 | + |
|
| 19 | +-- Inside the transaction: case on a 16-field tuple (different spill count
|
|
| 20 | +-- than the outer 24-field one), then retry. The generic stg_ctoi_t frame
|
|
| 21 | +-- pushed for this case is discarded by findRetryFrameHelper.
|
|
| 22 | +innerScrut :: State# RealWorld -> (# State# RealWorld, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int# #)
|
|
| 23 | +innerScrut s0 = case retry# s0 of (# s1, () #) -> (# s1, 1#, 2#, 3#, 4#, 5#, 6#, 7#, 8#, 9#, 10#, 11#, 12#, 13#, 14#, 15#, 16# #)
|
|
| 24 | +{-# NOINLINE innerScrut #-}
|
|
| 25 | + |
|
| 26 | +stmBody :: STM ()
|
|
| 27 | +stmBody = STM (\s0 -> case innerScrut s0 of
|
|
| 28 | + (# s1, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16 #) -> (# s1, () #))
|
|
| 29 | + |
|
| 30 | +outerScrut :: State# RealWorld -> (# State# RealWorld, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int# #)
|
|
| 31 | +outerScrut s0 =
|
|
| 32 | + case unIO (atomically (stmBody `orElse` return ())) s0 of
|
|
| 33 | + (# s1, _ #) -> mkT s1
|
|
| 34 | +{-# NOINLINE outerScrut #-}
|
|
| 35 | + |
|
| 36 | +main :: IO ()
|
|
| 37 | +main = IO (\s0 -> case outerScrut s0 of
|
|
| 38 | + (# s1, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24 #) ->
|
|
| 39 | + unIO (print (I# (x1 +# x2 +# x3 +# x4 +# x5 +# x6 +# x7 +# x8 +# x9 +# x10 +# x11 +# x12 +# x13 +# x14 +# x15 +# x16 +# x17 +# x18 +# x19 +# x20 +# x21 +# x22 +# x23 +# x24))) s1) |
| 1 | +300 |
| 1 | +test('T27633a',
|
|
| 2 | + [ extra_files(['Obj.hs']),
|
|
| 3 | + req_interp,
|
|
| 4 | + req_bco,
|
|
| 5 | + only_ways(ghci_ways),
|
|
| 6 | + extra_ways(ghci_ways),
|
|
| 7 | + ],
|
|
| 8 | + compile_and_run,
|
|
| 9 | + ['']
|
|
| 10 | + )
|
|
| 11 | + |
|
| 12 | +test('T27633b',
|
|
| 13 | + [ extra_files(['Obj.hs']),
|
|
| 14 | + req_interp,
|
|
| 15 | + req_bco,
|
|
| 16 | + only_ways(ghci_ways),
|
|
| 17 | + extra_ways(ghci_ways),
|
|
| 18 | + ],
|
|
| 19 | + compile_and_run,
|
|
| 20 | + ['']
|
|
| 21 | + ) |
| 1 | +{-# LANGUAGE UnboxedTuples, MagicHash #-}
|
|
| 2 | + |
|
| 3 | +-- Stopping at a breakpoint in the case continuation of a large unboxed
|
|
| 4 | +-- tuple return (generic stg_ctoi_t frame) and resuming must re-enter the
|
|
| 5 | +-- frame with the correct tso->ctoi_tuple_spill_words. The continuation
|
|
| 6 | +-- breakpoint is activated via :stepout.
|
|
| 7 | +-- See Note [GHCi unboxed tuples stack spills] in rts/StgMiscClosures.cmm.
|
|
| 8 | + |
|
| 9 | +module Main where
|
|
| 10 | + |
|
| 11 | +import GHC.Exts
|
|
| 12 | +import GHC.IO (IO(..))
|
|
| 13 | +import T27633c_obj
|
|
| 14 | + |
|
| 15 | +unIO :: IO a -> State# RealWorld -> (# State# RealWorld, a #)
|
|
| 16 | +unIO (IO f) = f
|
|
| 17 | + |
|
| 18 | +poke :: Int -> IO Int
|
|
| 19 | +poke x =
|
|
| 20 | + return (x + 1) -- line 20: initial breakpoint
|
|
| 21 | + |
|
| 22 | +scrut :: State# RealWorld -> (# State# RealWorld, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int# #)
|
|
| 23 | +scrut s0 = case unIO (poke 41) s0 of (# s1, _ #) -> mkT s1
|
|
| 24 | +{-# NOINLINE scrut #-}
|
|
| 25 | + |
|
| 26 | +main :: IO ()
|
|
| 27 | +main = IO (\s0 -> case scrut s0 of
|
|
| 28 | + (# s1, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24 #) ->
|
|
| 29 | + unIO (print (I# (x1 +# x2 +# x3 +# x4 +# x5 +# x6 +# x7 +# x8 +# x9 +# x10 +# x11 +# x12 +# x13 +# x14 +# x15 +# x16 +# x17 +# x18 +# x19 +# x20 +# x21 +# x22 +# x23 +# x24))) s1) |
| 1 | +:load T27633c.hs
|
|
| 2 | +-- break inside poke, while the generic stg_ctoi_t frame from main's
|
|
| 3 | +-- 24-field tuple case is live on the stack
|
|
| 4 | +:break 20
|
|
| 5 | +main
|
|
| 6 | +-- step out to the small case continuation in scrut
|
|
| 7 | +:stepout
|
|
| 8 | +-- step out again: activates the breakpoint of main's tuple case
|
|
| 9 | +-- continuation BCO, entered through the generic stg_ctoi_t frame
|
|
| 10 | +:stepout
|
|
| 11 | +-- resuming re-enters the stg_ctoi_t frame; with a stale
|
|
| 12 | +-- tso->ctoi_tuple_spill_words this segfaulted
|
|
| 13 | +:continue |
| 1 | +Breakpoint 0 activated at T27633c.hs:20:3-16
|
|
| 2 | +Stopped in Main.poke, T27633c.hs:20:3-16
|
|
| 3 | +_result :: IO Int = _
|
|
| 4 | +x :: Int = 41
|
|
| 5 | +Stopped in Main.scrut, T27633c.hs:23:17-33
|
|
| 6 | +_result :: (# State# RealWorld, Int #) = _
|
|
| 7 | +Stopped in Main.main, T27633c.hs:(27,19)-(29,193)
|
|
| 8 | +_result :: (# State# RealWorld, () #) = _
|
|
| 9 | +300 |
| 1 | +{-# OPTIONS_GHC -fobject-code #-}
|
|
| 2 | +{-# LANGUAGE UnboxedTuples, MagicHash #-}
|
|
| 3 | +module T27633c_obj where
|
|
| 4 | + |
|
| 5 | +import GHC.Exts
|
|
| 6 | + |
|
| 7 | +-- Compiled to object code; returns a large unboxed tuple, so the return
|
|
| 8 | +-- into an interpreted caller goes through the native stg_ctoi_t entry code,
|
|
| 9 | +-- which reads tso->ctoi_tuple_spill_words.
|
|
| 10 | +mkT :: State# RealWorld -> (# State# RealWorld, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int#, Int# #)
|
|
| 11 | +mkT s = (# s, 1#, 2#, 3#, 4#, 5#, 6#, 7#, 8#, 9#, 10#, 11#, 12#, 13#, 14#, 15#, 16#, 17#, 18#, 19#, 20#, 21#, 22#, 23#, 24# #)
|
|
| 12 | +{-# NOINLINE mkT #-} |
| ... | ... | @@ -153,3 +153,5 @@ test('T26042e', extra_files(['T26042e.hs']), ghci_script, ['T26042e.script']) |
| 153 | 153 | test('T26042f1', extra_files(['T26042f.hs', 'T26042f.script']), ghci_script, ['T26042f.script']) # >> is not inlined, so stepout has nowhere to stop
|
| 154 | 154 | test('T26042f2', [extra_hc_opts('-O -fno-unoptimized-core-for-interpreter'), extra_files(['T26042f.hs', 'T26042f.script'])], ghci_script, ['T26042f.script'])
|
| 155 | 155 | test('T26042g', extra_files(['T26042g.hs']), ghci_script, ['T26042g.script'])
|
| 156 | + |
|
| 157 | +test('T27633c', extra_files(['T27633c_obj.hs']), ghci_script, ['T27633c.script']) |
| 1 | +{-# LANGUAGE BangPatterns #-}
|
|
| 2 | + |
|
| 3 | +-- Stress test for #27477: missing ACQUIRE in eval_thunk_selector
|
|
| 4 | +-- (rts/sm/Evac.c).
|
|
| 5 | +--
|
|
| 6 | +-- With the bug present this test crashes or reports value mismatches
|
|
| 7 | +-- within a few seconds on AArch64; on strongly-ordered targets
|
|
| 8 | +-- it just passes.
|
|
| 9 | + |
|
| 10 | +module Main (main) where
|
|
| 11 | + |
|
| 12 | +import Control.Concurrent
|
|
| 13 | +import Control.Exception
|
|
| 14 | +import Control.Monad
|
|
| 15 | +import Data.IORef
|
|
| 16 | +import System.Environment
|
|
| 17 | +import System.Exit
|
|
| 18 | +import System.IO
|
|
| 19 | +import System.Mem (performMinorGC)
|
|
| 20 | + |
|
| 21 | +data T = T { nxt :: T, val :: !Int }
|
|
| 22 | + |
|
| 23 | +-- expected values and the cells that should evaluate to them
|
|
| 24 | +type Batch = ([Int], [T])
|
|
| 25 | + |
|
| 26 | +tailD, branchD, branchesPerCell :: Int
|
|
| 27 | +tailD = 12 -- shared tail length per cluster
|
|
| 28 | +branchD = 3 -- private branch length
|
|
| 29 | +branchesPerCell = 2
|
|
| 30 | +-- tailD + branchD must stay below MAX_THUNK_SELECTOR_DEPTH (16)
|
|
| 31 | + |
|
| 32 | +{-# NOINLINE spineEnd #-}
|
|
| 33 | +spineEnd :: T
|
|
| 34 | +spineEnd = errorWithoutStackTrace "spine end reached"
|
|
| 35 | + |
|
| 36 | +-- Fully evaluated spine of constructors; cell i from the head has val i+1.
|
|
| 37 | +buildSpine :: Int -> IO T
|
|
| 38 | +buildSpine len = evaluate (go len (T spineEnd 0))
|
|
| 39 | + where
|
|
| 40 | + go :: Int -> T -> T
|
|
| 41 | + go 0 acc = acc
|
|
| 42 | + go k acc = go (k - 1) (T acc k)
|
|
| 43 | + |
|
| 44 | +-- k selector thunks, shallow-first: cell i selects from cell i-1,
|
|
| 45 | +-- cell 0 selects from t. If t evaluates to spine cell m (val m+1),
|
|
| 46 | +-- cell i evaluates to spine cell m+1+i (val m+2+i).
|
|
| 47 | +{-# NOINLINE selChain #-}
|
|
| 48 | +selChain :: Int -> T -> [T]
|
|
| 49 | +selChain 0 _ = []
|
|
| 50 | +selChain k t = let t' = nxt t in t' : selChain (k - 1) t'
|
|
| 51 | + |
|
| 52 | +lenL :: [a] -> Int
|
|
| 53 | +lenL = go 0
|
|
| 54 | + where
|
|
| 55 | + go !n [] = n
|
|
| 56 | + go !n (_ : xs) = go (n + 1) xs
|
|
| 57 | + |
|
| 58 | +everyN :: Int -> [a] -> [a]
|
|
| 59 | +everyN _ [] = []
|
|
| 60 | +everyN n (x : xs) = x : everyN n (drop (n - 1) xs)
|
|
| 61 | + |
|
| 62 | +-- One branch hanging off tail cell tj (which evaluates to val jval):
|
|
| 63 | +-- branch cell i evaluates to jval+1+i. Returned deepest-first.
|
|
| 64 | +{-# NOINLINE mkBranch #-}
|
|
| 65 | +mkBranch :: Int -> T -> IO Batch
|
|
| 66 | +mkBranch jval tj = do
|
|
| 67 | + let cells = selChain branchD tj
|
|
| 68 | + _ <- evaluate (lenL cells)
|
|
| 69 | + let expected = [ jval + 1 + i | i <- [0 .. branchD - 1] ]
|
|
| 70 | + pure (reverse expected, reverse cells)
|
|
| 71 | + |
|
| 72 | +-- A cluster: one private spine, one shared tail of selectors over it,
|
|
| 73 | +-- branchesPerCell branches of selectors converging on every tail cell.
|
|
| 74 | +-- Neither the spine nor the tail is returned: they must stay reachable
|
|
| 75 | +-- only through the branch selectors.
|
|
| 76 | +buildCluster :: IO [Batch]
|
|
| 77 | +buildCluster = do
|
|
| 78 | + sp <- buildSpine (tailD + branchD + 4)
|
|
| 79 | + let tails = selChain tailD sp
|
|
| 80 | + _ <- evaluate (lenL tails)
|
|
| 81 | + bss <- forM (zip [0 ..] tails) $ \(j, tj) ->
|
|
| 82 | + replicateM branchesPerCell (mkBranch (j + 2) tj)
|
|
| 83 | + pure (concat bss)
|
|
| 84 | + |
|
| 85 | +verifyBatch :: IORef Int -> Int -> Batch -> IO ()
|
|
| 86 | +verifyBatch errs wid (es0, ts0) = go es0 ts0
|
|
| 87 | + where
|
|
| 88 | + go (e : es) (t : ts) = do
|
|
| 89 | + v <- evaluate (val t)
|
|
| 90 | + when (v /= e) $ do
|
|
| 91 | + hPutStrLn stderr $
|
|
| 92 | + "MISMATCH worker=" ++ show wid
|
|
| 93 | + ++ " expected=" ++ show e ++ " got=" ++ show v
|
|
| 94 | + modifyIORef' errs (+ 1)
|
|
| 95 | + go es ts
|
|
| 96 | + go _ _ = pure ()
|
|
| 97 | + |
|
| 98 | +-- simple cyclic barrier
|
|
| 99 | +newtype Barrier = Barrier (MVar (Int, [MVar ()]))
|
|
| 100 | + |
|
| 101 | +newBarrier :: IO Barrier
|
|
| 102 | +newBarrier = Barrier <$> newMVar (0, [])
|
|
| 103 | + |
|
| 104 | +awaitBarrier :: Barrier -> Int -> IO ()
|
|
| 105 | +awaitBarrier (Barrier st) total = do
|
|
| 106 | + w <- newEmptyMVar
|
|
| 107 | + join $ modifyMVar st $ \(k, ws) ->
|
|
| 108 | + if k + 1 == total
|
|
| 109 | + then pure ((0, []), mapM_ (\m -> putMVar m ()) ws)
|
|
| 110 | + else pure ((k + 1, w : ws), takeMVar w)
|
|
| 111 | + |
|
| 112 | +worker :: Int -> Int -> Int -> Barrier -> [IORef [Batch]] -> IORef Int -> Int -> IO ()
|
|
| 113 | +worker rounds clusters nWorkers bar slots errs wid =
|
|
| 114 | + forM_ [1 .. rounds] $ \(_r :: Int) -> do
|
|
| 115 | + -- build fresh selector clusters, publish them
|
|
| 116 | + batches <- concat <$> replicateM clusters buildCluster
|
|
| 117 | + writeIORef (slots !! wid) batches
|
|
| 118 | + awaitBarrier bar nWorkers
|
|
| 119 | + -- root each branch's deepest cell via fresh cons cells in our own
|
|
| 120 | + -- nursery (so our GC thread evacuates the shared cells itself), in
|
|
| 121 | + -- a per-worker interleaved order so that different GC threads
|
|
| 122 | + -- sweep different branches of the same shared tails concurrently
|
|
| 123 | + published <- mapM readIORef slots
|
|
| 124 | + let allBatches = concat published
|
|
| 125 | + ordered
|
|
| 126 | + | nWorkers > 1 =
|
|
| 127 | + concat [ everyN nWorkers (drop ((wid + k) `mod` nWorkers) allBatches)
|
|
| 128 | + | k <- [0 .. nWorkers - 1] ]
|
|
| 129 | + | otherwise = allBatches
|
|
| 130 | + deepTs = [ t | (_, t : _) <- ordered ]
|
|
| 131 | + deepEs = [ e | (e : _, _) <- ordered ]
|
|
| 132 | + _ <- evaluate (lenL deepTs)
|
|
| 133 | + _ <- evaluate (lenL deepEs)
|
|
| 134 | + awaitBarrier bar nWorkers
|
|
| 135 | + -- run a parallel GC with everything live
|
|
| 136 | + when (wid == 0) performMinorGC
|
|
| 137 | + awaitBarrier bar nWorkers
|
|
| 138 | + -- force everything and check the values
|
|
| 139 | + verifyBatch errs wid (deepEs, deepTs)
|
|
| 140 | + awaitBarrier bar nWorkers
|
|
| 141 | + |
|
| 142 | +main :: IO ()
|
|
| 143 | +main = do
|
|
| 144 | + hSetBuffering stderr LineBuffering
|
|
| 145 | + args <- getArgs
|
|
| 146 | + let atDef d i = if length args > i then read (args !! i) else d
|
|
| 147 | + rounds = atDef 600 0
|
|
| 148 | + clusters = atDef 48 1
|
|
| 149 | + n <- getNumCapabilities
|
|
| 150 | + bar <- newBarrier
|
|
| 151 | + slots <- replicateM n (newIORef [])
|
|
| 152 | + errs <- newIORef 0
|
|
| 153 | + dones <- forM [0 .. n - 1] $ \i -> do
|
|
| 154 | + done <- newEmptyMVar
|
|
| 155 | + _ <- forkOn i $
|
|
| 156 | + (worker rounds clusters n bar slots errs i >> putMVar done Nothing)
|
|
| 157 | + `catch` \e -> putMVar done (Just (e :: SomeException))
|
|
| 158 | + pure done
|
|
| 159 | + results <- mapM takeMVar dones
|
|
| 160 | + forM_ results $ \r -> case r of
|
|
| 161 | + Just e -> do
|
|
| 162 | + hPutStrLn stderr ("worker exception: " ++ show e)
|
|
| 163 | + exitWith (ExitFailure 2)
|
|
| 164 | + Nothing -> pure ()
|
|
| 165 | + ec <- readIORef errs
|
|
| 166 | + when (ec > 0) $ do
|
|
| 167 | + hPutStrLn stderr ("FAILED: " ++ show ec ++ " mismatches")
|
|
| 168 | + exitWith (ExitFailure 2)
|
|
| 169 | + putStrLn "OK" |
| 1 | +OK |
| ... | ... | @@ -720,3 +720,12 @@ test('T27585', |
| 720 | 720 | , extra_run_opts('+RTS -i0 -RTS')
|
| 721 | 721 | ],
|
| 722 | 722 | compile_and_run, ['-O -rtsopts'])
|
| 723 | + |
|
| 724 | +test('T27477',
|
|
| 725 | + [ extra_run_opts('600 24 +RTS -N4 -A1m -RTS')
|
|
| 726 | + , req_ghc_smp
|
|
| 727 | + , req_target_smp
|
|
| 728 | + , only_ways(['threaded1', 'threaded2'])
|
|
| 729 | + ],
|
|
| 730 | + compile_and_run, ['-O2'])
|
|
| 731 | + |
| ... | ... | @@ -3404,13 +3404,13 @@ instance ExactPrint (HsCmd GhcPs) where |
| 3404 | 3404 | e' <- markAnnotated e
|
| 3405 | 3405 | return (HsCmdLet (tkLet', tkIn') binds' e')
|
| 3406 | 3406 | |
| 3407 | - exact (HsCmdDo (an0,loc) (L l es)) = do
|
|
| 3407 | + exact (HsCmdDo (an0,loc) es) = do
|
|
| 3408 | 3408 | debugM $ "HsCmdDo"
|
| 3409 | 3409 | loc' <- printStringAtAA loc "do"
|
| 3410 | 3410 | (an1,es') <- markAnnList' an0 $ do
|
| 3411 | - ee <- mapM markAnnotated es
|
|
| 3411 | + ee <- markAnnotated es
|
|
| 3412 | 3412 | return ee
|
| 3413 | - return (HsCmdDo (an1,loc') (L l es'))
|
|
| 3413 | + return (HsCmdDo (an1,loc') es')
|
|
| 3414 | 3414 | |
| 3415 | 3415 | -- ---------------------------------------------------------------------
|
| 3416 | 3416 | |
| ... | ... | @@ -4508,10 +4508,10 @@ instance ExactPrint [LocatedA (StmtLR GhcPs GhcPs (LocatedA (HsCmd GhcPs)))] whe |
| 4508 | 4508 | Just (initStmts, ls@(L _ (LastStmt _ _body _ _))) -> do
|
| 4509 | 4509 | debugM $ "LocatedL [ExprLStmt: snocView"
|
| 4510 | 4510 | ls' <- markAnnotated ls
|
| 4511 | - initStmts' <- markAnnotated initStmts
|
|
| 4511 | + initStmts' <- mapM markAnnotated initStmts
|
|
| 4512 | 4512 | return (initStmts' ++ [ls'])
|
| 4513 | 4513 | _ -> do
|
| 4514 | - stmts' <- markAnnotated stmts
|
|
| 4514 | + stmts' <- mapM markAnnotated stmts
|
|
| 4515 | 4515 | return stmts'
|
| 4516 | 4516 | |
| 4517 | 4517 | instance ExactPrint [Located HsDocStringChunk] where
|