Wolfgang Jeltsch pushed to branch wip/jeltsch/ghc-9-14-building-base at Glasgow Haskell Compiler / GHC

Commits:

28 changed files:

Changes:

  • .gitlab-ci.yml
    ... ... @@ -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
     ############################################################
    

  • .gitlab/base-ci.sh
    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

  • changelog.d/fix-parallel-gc-selector-race-27477
    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

  • compiler/GHC/Hs/Doc.hs
    ... ... @@ -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)
    

  • compiler/GHC/Hs/Extension/Pass.hs
    ... ... @@ -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
     
    

  • hadrian/src/Builder.hs
    ... ... @@ -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
     
    

  • libraries/base/base.cabal.in
    ... ... @@ -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
    

  • libraries/base/src/GHC/Stack.hs
    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

  • libraries/ghc-internal/src/GHC/Internal/Stack.hs
    ... ... @@ -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
     
    

  • rts/Continuation.c
    ... ... @@ -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;
    

  • rts/Interpreter.c
    ... ... @@ -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
     
    

  • rts/Schedule.c
    ... ... @@ -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
         }
    

  • rts/sm/Evac.c
    ... ... @@ -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
    

  • testsuite/tests/bytecode/T27633/Obj.hs
    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 #-}

  • testsuite/tests/bytecode/T27633/T27633a.hs
    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)

  • testsuite/tests/bytecode/T27633/T27633a.stdout
    1
    +300

  • testsuite/tests/bytecode/T27633/T27633b.hs
    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)

  • testsuite/tests/bytecode/T27633/T27633b.stdout
    1
    +300

  • testsuite/tests/bytecode/T27633/all.T
    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
    +    )

  • testsuite/tests/ghci.debugger/scripts/T27633c.hs
    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)

  • testsuite/tests/ghci.debugger/scripts/T27633c.script
    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

  • testsuite/tests/ghci.debugger/scripts/T27633c.stdout
    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

  • testsuite/tests/ghci.debugger/scripts/T27633c_obj.hs
    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 #-}

  • testsuite/tests/ghci.debugger/scripts/all.T
    ... ... @@ -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'])

  • testsuite/tests/rts/T27477.hs
    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"

  • testsuite/tests/rts/T27477.stdout
    1
    +OK

  • testsuite/tests/rts/all.T
    ... ... @@ -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
    +

  • utils/check-exact/ExactPrint.hs
    ... ... @@ -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