Ben Gamari pushed to branch wip/backports-9.14 at Glasgow Haskell Compiler / GHC
Commits:
-
4d8eec9a
by Ben Gamari at 2025-09-02T08:58:18-04:00
-
0980f3d6
by Ben Gamari at 2025-09-02T08:58:53-04:00
-
5f9c0b62
by Ben Gamari at 2025-09-02T08:58:53-04:00
7 changed files:
- docs/users_guide/9.14.1-notes.rst
- rts/PrimOps.cmm
- rts/RaiseAsync.c
- rts/STM.c
- − testsuite/tests/lib/stm/T26028.hs
- − testsuite/tests/lib/stm/T26028.stdout
- − testsuite/tests/lib/stm/all.T
Changes:
| ... | ... | @@ -25,6 +25,14 @@ Language |
| 25 | 25 | This deprecation is controlled by the newly introduced ``-Wdeprecated-pragmas``
|
| 26 | 26 | flag in ``-Wdefault``.
|
| 27 | 27 | |
| 28 | +* Visible ``GADT`` syntax can now be used in GADT data constructors (:ghc-ticket:`25127`) ::
|
|
| 29 | + |
|
| 30 | + data KindVal a where
|
|
| 31 | + K :: forall k.
|
|
| 32 | + forall (a::k) -> -- now allowed!
|
|
| 33 | + k ->
|
|
| 34 | + KindVal a
|
|
| 35 | + |
|
| 28 | 36 | * ``-Wincomplete-record-selectors`` is now part of `-Wall`, as specified
|
| 29 | 37 | by `GHC Proposal 516: add warning for incomplete record selectors <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0516-incomplete-record-selectors.rst>`_.
|
| 30 | 38 | Hence, if a library is compiled with ``-Werror``, compilation may now fail. Solution: fix the library.
|
| ... | ... | @@ -52,7 +60,7 @@ Language |
| 52 | 60 | |
| 53 | 61 | That will break the combination of :extension:`OverloadedRecordUpdate` with :extension:`RebindableSyntax`.
|
| 54 | 62 | |
| 55 | -* Multiline strings are now accepted in foreign imports. (#25157)
|
|
| 63 | +* Multiline strings are now accepted in ``foreign import``\ s. (#25157)
|
|
| 56 | 64 | |
| 57 | 65 | * GHC now does a better job at inferring types in calls to ``coerce``: instead of
|
| 58 | 66 | complaining about ambiguous type variables, GHC will consider that such type
|
| ... | ... | @@ -73,7 +81,7 @@ Language |
| 73 | 81 | * The ``-Wdata-kinds-tc`` warning has been deprecated, and the use of promoted
|
| 74 | 82 | data types in kinds is now an error (rather than a warning) unless the
|
| 75 | 83 | :extension:`DataKinds` extension is enabled. For example, the following code
|
| 76 | - will be rejected unless :extension:`DataKinds` is on:
|
|
| 84 | + will be rejected unless :extension:`DataKinds` is on: ::
|
|
| 77 | 85 | |
| 78 | 86 | import Data.Kind (Type)
|
| 79 | 87 | import GHC.TypeNats (Nat)
|
| ... | ... | @@ -99,6 +107,9 @@ Language |
| 99 | 107 | |
| 100 | 108 | See :ref:`visible-forall-in-gadts` for details.
|
| 101 | 109 | |
| 110 | +- Explicit level import support, allowing ``import`` declarations to explicitly
|
|
| 111 | + state which compilation stages they are are visible to.
|
|
| 112 | + |
|
| 102 | 113 | Compiler
|
| 103 | 114 | ~~~~~~~~
|
| 104 | 115 | |
| ... | ... | @@ -143,20 +154,27 @@ Compiler |
| 143 | 154 | were accessed using the generated record selector functions, marking the fields
|
| 144 | 155 | as covered in coverage reports (:ghc-ticket:`17834`).
|
| 145 | 156 | |
| 146 | -- SIMD support in the X86 native code generator has been extended with 128-bit
|
|
| 157 | +- SIMD support in the x86 native code generator has been extended with 128-bit
|
|
| 147 | 158 | integer operations. Also, ``shuffleFloatX4#`` and ``shuffleDoubleX2#`` no longer
|
| 148 | 159 | require ``-mavx``.
|
| 149 | 160 | |
| 161 | +- Initial native code generator support for the LoongArch CPU architecture.
|
|
| 162 | + |
|
| 163 | + |
|
| 150 | 164 | GHCi
|
| 151 | 165 | ~~~~
|
| 152 | 166 | |
| 153 | -- :ghci-cmd:`:info` now outputs type declarations with @-binders that are
|
|
| 167 | +- Multiple home unit support in GHCi
|
|
| 168 | + |
|
| 169 | +- :ghci-cmd:`:info` now outputs type declarations with ``@``-binders that are
|
|
| 154 | 170 | considered semantically significant. See the documentation for :ghci-cmd:`:info`
|
| 155 | 171 | itself for a more detailed explanation.
|
| 156 | 172 | |
| 157 | 173 | - GHCi errors and warnings now have their own numeric error codes that are
|
| 158 | 174 | displayed alongside the error.
|
| 159 | 175 | |
| 176 | +- Many performance and correctness improvements in the bytecode interpreter.
|
|
| 177 | + |
|
| 160 | 178 | Runtime system
|
| 161 | 179 | ~~~~~~~~~~~~~~
|
| 162 | 180 | |
| ... | ... | @@ -176,40 +194,40 @@ Cmm |
| 176 | 194 | ``ghc`` library
|
| 177 | 195 | ~~~~~~~~~~~~~~~
|
| 178 | 196 | |
| 179 | -* The `UnknownDiagnostic` constructor now takes an additional type argument
|
|
| 197 | +* The ``UnknownDiagnostic`` constructor now takes an additional type argument
|
|
| 180 | 198 | for the type of hints corresponding to the diagnostic, and an additional
|
| 181 | 199 | value-level argument used for existential wrapping of the hints of the inner
|
| 182 | 200 | diagnostic.
|
| 183 | 201 | |
| 184 | 202 | * Changes to the HPT and HUG interface:
|
| 185 | 203 | |
| 186 | - - `addToHpt` and `addListToHPT` were moved from `GHC.Unit.Home.ModInfo` to `GHC.Unit.Home.PackageTable` and deprecated in favour of `addHomeModInfoToHpt` and `addHomeModInfosToHpt`.
|
|
| 187 | - - `UnitEnvGraph` and operations `unitEnv_lookup_maybe`, `unitEnv_foldWithKey, `unitEnv_singleton`, `unitEnv_adjust`, `unitEnv_insert`, `unitEnv_new` were moved from `GHC.Unit.Env` to `GHC.Unit.Home.Graph`.
|
|
| 188 | - - The HomePackageTable (HPT) is now exported from `GHC.Unit.Home.PackageTable`,
|
|
| 204 | + - ``addToHpt`` and ``addListToHPT`` were moved from ``GHC.Unit.Home.ModInfo`` to ``GHC.Unit.Home.PackageTable`` and deprecated in favour of ``addHomeModInfoToHpt`` and ``addHomeModInfosToHpt``.
|
|
| 205 | + - ``UnitEnvGraph`` and operations ``unitEnv_lookup_maybe``, ``unitEnv_foldWithKey, ``unitEnv_singleton``, ``unitEnv_adjust``, ``unitEnv_insert``, ``unitEnv_new`` were moved from ``GHC.Unit.Env`` to ``GHC.Unit.Home.Graph``.
|
|
| 206 | + - The HomePackageTable (HPT) is now exported from ``GHC.Unit.Home.PackageTable``,
|
|
| 189 | 207 | and is now backed by an IORef to avoid by construction very bad memory leaks.
|
| 190 | 208 | This means the API to the HPT now is for the most part in IO. For instance,
|
| 191 | - `emptyHomePackageTable` and `addHomeModInfoToHpt` are now in IO.
|
|
| 192 | - - `mkHomeUnitEnv` was moved to `GHC.Unit.Home.PackageTable`, and now takes two
|
|
| 193 | - extra explicit arguments. To restore previous behaviour, pass `emptyUnitState`
|
|
| 194 | - and `Nothing` as the first two arguments additionally.
|
|
| 195 | - - `hugElts` was removed. Users should prefer `allUnits` to get the keys of the
|
|
| 196 | - HUG (the typical use case), or `traverse` or `unitEnv_foldWithKey` in other
|
|
| 209 | + ``emptyHomePackageTable`` and ``addHomeModInfoToHpt`` are now in IO.
|
|
| 210 | + - ``mkHomeUnitEnv`` was moved to ``GHC.Unit.Home.PackageTable``, and now takes two
|
|
| 211 | + extra explicit arguments. To restore previous behaviour, pass ``emptyUnitState``
|
|
| 212 | + and ``Nothing`` as the first two arguments additionally.
|
|
| 213 | + - ``hugElts`` was removed. Users should prefer ``allUnits`` to get the keys of the
|
|
| 214 | + HUG (the typical use case), or ``traverse`` or ``unitEnv_foldWithKey`` in other
|
|
| 197 | 215 | cases.
|
| 198 | 216 | |
| 199 | -* Changes to `Language.Haskell.Syntax.Expr`
|
|
| 217 | +* Changes to ``Language.Haskell.Syntax.Expr``
|
|
| 200 | 218 | |
| 201 | - - The `ParStmtBlock` list argument of the `ParStmt` constructor of `StmtLR` is now `NonEmpty`.
|
|
| 219 | + - The ``ParStmtBlock`` list argument of the ``ParStmt`` constructor of ``StmtLR`` is now ``NonEmpty``.
|
|
| 202 | 220 | |
| 203 | -* As part of the implementation of `GHC proposal 493 <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0493-specialise-expressions.rst>`_,
|
|
| 204 | - the `SpecSig` constructor of `Sig` has been deprecated. It is replaced by
|
|
| 205 | - the constructor `SpecSigE` which supports expressions at the head, rather than
|
|
| 221 | +* As part of the implementation of ``GHC proposal 493 <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0493-specialise-expressions.rst>``_,
|
|
| 222 | + the ``SpecSig`` constructor of ``Sig`` has been deprecated. It is replaced by
|
|
| 223 | + the constructor ``SpecSigE`` which supports expressions at the head, rather than
|
|
| 206 | 224 | a lone variable.
|
| 207 | 225 | |
| 208 | 226 | ``ghc-heap`` library
|
| 209 | 227 | ~~~~~~~~~~~~~~~~~~~~
|
| 210 | 228 | |
| 211 | -* The functions `getClosureInfoTbl_maybe`, `getClosureInfoTbl`,
|
|
| 212 | - `getClosurePtrArgs` and `getClosurePtrArgs_maybe` have been added to allow
|
|
| 229 | +* The functions ``getClosureInfoTbl_maybe``, ``getClosureInfoTbl``,
|
|
| 230 | + ``getClosurePtrArgs`` and ``getClosurePtrArgs_maybe`` have been added to allow
|
|
| 213 | 231 | reading of the relevant Closure attributes without reliance on incomplete
|
| 214 | 232 | selectors.
|
| 215 | 233 | |
| ... | ... | @@ -225,7 +243,6 @@ Cmm |
| 225 | 243 | ``ghc-experimental`` versions.
|
| 226 | 244 | |
| 227 | 245 | |
| 228 | - |
|
| 229 | 246 | ``template-haskell`` library
|
| 230 | 247 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 231 | 248 |
| ... | ... | @@ -1210,27 +1210,16 @@ INFO_TABLE_RET(stg_catch_retry_frame, CATCH_RETRY_FRAME, |
| 1210 | 1210 | gcptr trec, outer, arg;
|
| 1211 | 1211 | |
| 1212 | 1212 | trec = StgTSO_trec(CurrentTSO);
|
| 1213 | - if (running_alt_code != 1) {
|
|
| 1214 | - // When exiting the lhs code of catchRetry# lhs rhs, we need to cleanup
|
|
| 1215 | - // the nested transaction.
|
|
| 1216 | - // See Note [catchRetry# implementation]
|
|
| 1217 | - outer = StgTRecHeader_enclosing_trec(trec);
|
|
| 1218 | - (r) = ccall stmCommitNestedTransaction(MyCapability() "ptr", trec "ptr");
|
|
| 1219 | - if (r != 0) {
|
|
| 1220 | - // Succeeded in first branch
|
|
| 1221 | - StgTSO_trec(CurrentTSO) = outer;
|
|
| 1222 | - return (ret);
|
|
| 1223 | - } else {
|
|
| 1224 | - // Did not commit: abort and restart.
|
|
| 1225 | - StgTSO_trec(CurrentTSO) = outer;
|
|
| 1226 | - jump stg_abort();
|
|
| 1227 | - }
|
|
| 1228 | - }
|
|
| 1229 | - else {
|
|
| 1230 | - // nothing to do in the rhs code of catchRetry# lhs rhs, it's already
|
|
| 1231 | - // using the parent transaction (not a nested one).
|
|
| 1232 | - // See Note [catchRetry# implementation]
|
|
| 1233 | - return (ret);
|
|
| 1213 | + outer = StgTRecHeader_enclosing_trec(trec);
|
|
| 1214 | + (r) = ccall stmCommitNestedTransaction(MyCapability() "ptr", trec "ptr");
|
|
| 1215 | + if (r != 0) {
|
|
| 1216 | + // Succeeded (either first branch or second branch)
|
|
| 1217 | + StgTSO_trec(CurrentTSO) = outer;
|
|
| 1218 | + return (ret);
|
|
| 1219 | + } else {
|
|
| 1220 | + // Did not commit: abort and restart.
|
|
| 1221 | + StgTSO_trec(CurrentTSO) = outer;
|
|
| 1222 | + jump stg_abort();
|
|
| 1234 | 1223 | }
|
| 1235 | 1224 | }
|
| 1236 | 1225 | |
| ... | ... | @@ -1463,26 +1452,21 @@ retry_pop_stack: |
| 1463 | 1452 | outer = StgTRecHeader_enclosing_trec(trec);
|
| 1464 | 1453 | |
| 1465 | 1454 | if (frame_type == CATCH_RETRY_FRAME) {
|
| 1466 | - // The retry reaches a CATCH_RETRY_FRAME before the ATOMICALLY_FRAME
|
|
| 1467 | - |
|
| 1455 | + // The retry reaches a CATCH_RETRY_FRAME before the atomic frame
|
|
| 1456 | + ASSERT(outer != NO_TREC);
|
|
| 1457 | + // Abort the transaction attempting the current branch
|
|
| 1458 | + ccall stmAbortTransaction(MyCapability() "ptr", trec "ptr");
|
|
| 1459 | + ccall stmFreeAbortedTRec(MyCapability() "ptr", trec "ptr");
|
|
| 1468 | 1460 | if (!StgCatchRetryFrame_running_alt_code(frame) != 0) {
|
| 1469 | - // Retrying in the lhs of catchRetry# lhs rhs, i.e. in a nested
|
|
| 1470 | - // transaction. See Note [catchRetry# implementation]
|
|
| 1471 | - |
|
| 1472 | - // check that we have a parent transaction
|
|
| 1473 | - ASSERT(outer != NO_TREC);
|
|
| 1474 | - |
|
| 1475 | - // Abort the nested transaction
|
|
| 1476 | - ccall stmAbortTransaction(MyCapability() "ptr", trec "ptr");
|
|
| 1477 | - ccall stmFreeAbortedTRec(MyCapability() "ptr", trec "ptr");
|
|
| 1478 | - |
|
| 1479 | - // As we are retrying in the lhs code, we must now try the rhs code
|
|
| 1480 | - StgTSO_trec(CurrentTSO) = outer;
|
|
| 1461 | + // Retry in the first branch: try the alternative
|
|
| 1462 | + ("ptr" trec) = ccall stmStartTransaction(MyCapability() "ptr", outer "ptr");
|
|
| 1463 | + StgTSO_trec(CurrentTSO) = trec;
|
|
| 1481 | 1464 | StgCatchRetryFrame_running_alt_code(frame) = 1 :: CInt; // true;
|
| 1482 | 1465 | R1 = StgCatchRetryFrame_alt_code(frame);
|
| 1483 | 1466 | jump stg_ap_v_fast [R1];
|
| 1484 | 1467 | } else {
|
| 1485 | - // Retry in the rhs code: propagate the retry
|
|
| 1468 | + // Retry in the alternative code: propagate the retry
|
|
| 1469 | + StgTSO_trec(CurrentTSO) = outer;
|
|
| 1486 | 1470 | Sp = Sp + SIZEOF_StgCatchRetryFrame;
|
| 1487 | 1471 | goto retry_pop_stack;
|
| 1488 | 1472 | }
|
| ... | ... | @@ -1043,7 +1043,8 @@ raiseAsync(Capability *cap, StgTSO *tso, StgClosure *exception, |
| 1043 | 1043 | }
|
| 1044 | 1044 | |
| 1045 | 1045 | case CATCH_STM_FRAME:
|
| 1046 | - // CATCH_STM frame within an atomically block: abort the
|
|
| 1046 | + case CATCH_RETRY_FRAME:
|
|
| 1047 | + // CATCH frames within an atomically block: abort the
|
|
| 1047 | 1048 | // inner transaction and continue. Eventually we will
|
| 1048 | 1049 | // hit the outer transaction that will get frozen (see
|
| 1049 | 1050 | // above).
|
| ... | ... | @@ -1055,40 +1056,14 @@ raiseAsync(Capability *cap, StgTSO *tso, StgClosure *exception, |
| 1055 | 1056 | {
|
| 1056 | 1057 | StgTRecHeader *trec = tso -> trec;
|
| 1057 | 1058 | StgTRecHeader *outer = trec -> enclosing_trec;
|
| 1058 | - debugTraceCap(DEBUG_stm, cap, "raiseAsync: traversing CATCH_STM frame");
|
|
| 1059 | + debugTraceCap(DEBUG_stm, cap,
|
|
| 1060 | + "found atomically block delivering async exception");
|
|
| 1059 | 1061 | stmAbortTransaction(cap, trec);
|
| 1060 | 1062 | stmFreeAbortedTRec(cap, trec);
|
| 1061 | 1063 | tso -> trec = outer;
|
| 1062 | 1064 | break;
|
| 1063 | 1065 | };
|
| 1064 | 1066 | |
| 1065 | - case CATCH_RETRY_FRAME:
|
|
| 1066 | - // CATCH_RETY frame within an atomically block: if we're executing
|
|
| 1067 | - // the lhs code, abort the inner transaction and continue; if we're
|
|
| 1068 | - // executing thr rhs, continue (no nested transaction to abort. See
|
|
| 1069 | - // Note [catchRetry# implementation]). Eventually we will hit the
|
|
| 1070 | - // outer transaction that will get frozen (see above).
|
|
| 1071 | - //
|
|
| 1072 | - // As for the CATCH_STM_FRAME case above, we do not care
|
|
| 1073 | - // whether the transaction is valid or not because its
|
|
| 1074 | - // possible validity cannot have caused the exception
|
|
| 1075 | - // and will not be visible after the abort.
|
|
| 1076 | - {
|
|
| 1077 | - if (!((StgCatchRetryFrame *)frame) -> running_alt_code) {
|
|
| 1078 | - debugTraceCap(DEBUG_stm, cap, "raiseAsync: traversing CATCH_RETRY frame (lhs)");
|
|
| 1079 | - StgTRecHeader *trec = tso -> trec;
|
|
| 1080 | - StgTRecHeader *outer = trec -> enclosing_trec;
|
|
| 1081 | - stmAbortTransaction(cap, trec);
|
|
| 1082 | - stmFreeAbortedTRec(cap, trec);
|
|
| 1083 | - tso -> trec = outer;
|
|
| 1084 | - }
|
|
| 1085 | - else
|
|
| 1086 | - {
|
|
| 1087 | - debugTraceCap(DEBUG_stm, cap, "raiseAsync: traversing CATCH_RETRY frame (rhs)");
|
|
| 1088 | - }
|
|
| 1089 | - break;
|
|
| 1090 | - };
|
|
| 1091 | - |
|
| 1092 | 1067 | default:
|
| 1093 | 1068 | // see Note [Update async masking state on unwind] in Schedule.c
|
| 1094 | 1069 | if (*frame == (W_)&stg_unmaskAsyncExceptionszh_ret_info) {
|
| ... | ... | @@ -1505,30 +1505,3 @@ void stmWriteTVar(Capability *cap, |
| 1505 | 1505 | }
|
| 1506 | 1506 | |
| 1507 | 1507 | /*......................................................................*/ |
| 1508 | - |
|
| 1509 | - |
|
| 1510 | - |
|
| 1511 | -/*
|
|
| 1512 | - |
|
| 1513 | -Note [catchRetry# implementation]
|
|
| 1514 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1515 | -catchRetry# creates a nested transaction for its lhs:
|
|
| 1516 | -- if the lhs transaction succeeds:
|
|
| 1517 | - - the lhs transaction is committed
|
|
| 1518 | - - its read-variables are merged with those of the parent transaction
|
|
| 1519 | - - the rhs code is ignored
|
|
| 1520 | -- if the lhs transaction retries:
|
|
| 1521 | - - the lhs transaction is aborted
|
|
| 1522 | - - its read-variables are merged with those of the parent transaction
|
|
| 1523 | - - the rhs code is executed directly in the parent transaction (see #26028).
|
|
| 1524 | - |
|
| 1525 | -So note that:
|
|
| 1526 | -- lhs code uses a nested transaction
|
|
| 1527 | -- rhs code doesn't use a nested transaction
|
|
| 1528 | - |
|
| 1529 | -We have to take which case we're in into account (using the running_alt_code
|
|
| 1530 | -field of the catchRetry frame) in catchRetry's entry code, in retry#
|
|
| 1531 | -implementation, and also when an async exception is received (to cleanup the
|
|
| 1532 | -right number of transactions).
|
|
| 1533 | - |
|
| 1534 | -*/ |
| 1 | -module Main where
|
|
| 2 | - |
|
| 3 | -import GHC.Conc
|
|
| 4 | - |
|
| 5 | -forever :: IO String
|
|
| 6 | -forever = delay 10 >> forever
|
|
| 7 | - |
|
| 8 | -terminates :: IO String
|
|
| 9 | -terminates = delay 1 >> pure "terminates"
|
|
| 10 | - |
|
| 11 | -delay s = threadDelay (1000000 * s)
|
|
| 12 | - |
|
| 13 | -async :: IO a -> IO (STM a)
|
|
| 14 | -async a = do
|
|
| 15 | - var <- atomically (newTVar Nothing)
|
|
| 16 | - forkIO (a >>= atomically . writeTVar var . Just)
|
|
| 17 | - pure (readTVar var >>= maybe retry pure)
|
|
| 18 | - |
|
| 19 | -main :: IO ()
|
|
| 20 | -main = do
|
|
| 21 | - x <- mapM async $ terminates : replicate 50000 forever
|
|
| 22 | - r <- atomically (foldr1 orElse x)
|
|
| 23 | - print r |
| 1 | -"terminates" |
| 1 | -test('T26028', only_ways(['threaded1']), compile_and_run, ['-O2']) |