GHC 9.10.1 is now available!

Keep in mind the trick to use required type arguments in class methods:

class Storable a where
  sizeOf    :: forall a' -> a ~ a' => Int
  alignment :: forall a' -> a ~ a' => Int

From GHC 9.10の新機能

8 Likes

Oh, thanks. Why do we need to do that? (I don’t have GHC 9.10 downloaded to check what it error it throws.)

Edit: actually, that syntax confuses me a bit, since it seems we have an argument to the left of a constraint. I’ve got to play around with this :slight_smile:

For a type class variable, the (invisible) quantification must occur before the class head:

class forall a. Storable a where
  sizeOf :: Int

There is no way to quantify a differently, and a is already bound in the method. This trick gets around it by using a second (visible) quantifier, and then asserting their equality.

1 Like

Yes, the use of forall a' -> a ~ a' => ... is a workaround. Ideally we need a syntax to specify that some of class variables need to be quantified visibly in a method. I’ve known about this issue for a long time, here’s an old proposal of mine:

It needs to be refurbished and submitted to the committee. If you read the discussion there you can see the idea wasn’t received as well as I hoped it would, but I still believe it’s a solid approach.

4 Likes

First of all, thank you @bgamari and all GHC contribs for this release!

Do I understand correctly that GHCUP does not provide this version yet?

I made a quick attempt at running scotty CI with 9.10.1 and GHCUp fails with a mysterious

  Attempting to install ghc 9.10.1 using ghcup
  /opt/hostedtoolcache/ghcup/0.1.22.0/x64/ghcup install ghc 9.10.1
  [ Error ] [e

Also see full CI logs: Add 9.10.1 to CI · scotty-web/scotty@91b0bac · GitHub

4 Likes

It’s a nice trick. A lower technology approach would be to define a second function outside of the class:

class Storable a where
  sizeOfImpl :: Int

sizeOf :: forall a -> Storable a => Int
sizeOf t = sizeOfImpl @t

That way it’s also marginally easier to define instances (you don’t have to explicitly ignore the type variable).

instance Storable Int where
  sizeOfImpl = 8

EDIT: Oh, and I used something similar to the trick in withST in TypeAbstractions in GHC 9.10 - #5 by tomjaguarpaw

7 Likes

I have updated Stack’s default setup-info dictionary for these binary distributions, and added GHC 9.10.1’s global hints to global-hints.yaml .

1 Like

Thanks to all the GHC developers for this release. May I ask a couple of questions?

  1. I see the GHC 9.10.1 archive for Windows is 586 MB, compared to ~ 325 MB for GHC 9.6.3 to 9.8.2. Is there a reason for the 80% increase?

  2. I note the new GHC boot packages: ghc-experimental-0.1.0.0, ghc-internal-9.1001.0 (which seems an unusual version number, compared to other GHC boot packages), ghc-platform-0.1.0.0 and ghc-toolchain-0.1.0.0. None of them are documented at 2.1. Version 9.10.1 — Glasgow Haskell Compiler 9.10.1 User's Guide. Is that an oversight?

3 Likes

I think some files may have been duplicated in the packaging of GHC 9.10.1 for Windows:

  • GHC 9.8.2 lib\bin is 67 MB on disk. For GHC 9.10.1 it is 581 MB.
  • GHC 9.8.2 lib\lib does not exist. For GHC 9.10.1 it exists and is 1.08 GB on disk.
  • GHC 9.8.2 lib\doc is 132 KB on disk. For GHC 9.10.1 it is 775 MB.
3 Likes

This backtrace stuff is phenomenal!

11 Likes
9 Likes

BTW, I’ve just experimented a little with GHC 9.10.1 to see something interesting with the new exception backtraces, but I couldn’t see it in action in my toy examples. Here’s what I tried in the end:

Main.hs

import GHC.Internal.Exception.Backtrace
import GHC.Environment

import GHC.Stack

{-# NOINLINE f #-}
f :: HasCallStack => [String] -> [String]
f [x] = error "Some Pesky Error"
f xs = ("def" ++) <$> xs

{-# NOINLINE g #-}
g :: [String] -> IO [String]
g xs = return $ ("abc" ++) <$> f xs

main = do
  setBacktraceMechanismState CostCentreBacktrace True
  setBacktraceMechanismState HasCallStackBacktrace True
  setBacktraceMechanismState ExecutionBacktrace True 
  setBacktraceMechanismState IPEBacktrace True
  args <- getFullArgs
  print =<< g args

Here’s the output I got from this program:

$ ghc-9.10 Main.hs && ./Main
[1 of 2] Compiling Main             ( Main.hs, Main.o ) [Source file changed]
[2 of 2] Linking Main [Objects changed]
Main: Some Pesky Error
CallStack (from HasCallStack):
  error, called at Main.hs:8:9 in main:Main
  f, called at Main.hs:13:32 in main:Main
Cost-centre stack backtrace:
IPE backtrace:
HasCallStack backtrace:
  collectBacktraces, called at libraries/ghc-internal/src/GHC/Internal/Exception.hs:92:13 in ghc-internal:GHC.Internal.Exception
  toExceptionWithBacktrace, called at libraries/ghc-internal/src/GHC/Internal/Exception.hs:128:3 in ghc-internal:GHC.Internal.Exception

What do I need to do in order to observe something interesting in the backtrace lines?

5 Likes

Just to clarify, I think what you’re saying is that you have set

  setBacktraceMechanismState CostCentreBacktrace True
  setBacktraceMechanismState IPEBacktrace True

but

Cost-centre stack backtrace:
IPE backtrace:

are empty.

2 Likes

That’s right, but I’d say HasCallStack backtrace is also “empty”, because it only displays some stack entries internal to its implementation, it doesn’t even pick up on the HasCallStack constraint of my f (which I already see in the “old” output).

I’m interested in any way of observing the new backtraces feature in action (i.e. any output with some new information about my exception that we didn’t get pre 9.10).

3 Likes

setBacktraceMechanismState acts as a filter for what gets included in the exception annotation, but the backtrace mechanism itself might need additional setup to work.

  • For the HasCallStackBacktrace to work, all functions in your call stack need a HasCallStack constraint (in your example, g doesn’t have it).
  • For the CostCentreBacktrace to work, you need to build your program with profiling support: -prof.
  • For the ExecutionBacktrace to work, you need to be on Linux and build your program with DWARF support: -g3.
  • For the IPEBacktrace to work, you need to build your program with info-table provenance: -finfo-table-map.
7 Likes

I’ve added HasCallStack to g and main and I’ve added -g3 -finfo-table-map -prof arguments to ghc while building Main.hs, but I’m still not getting any result:

$ ghc-9.10 Main.hs -g3 -finfo-table-map -prof && ./Main
[1 of 2] Compiling Main             ( Main.hs, Main.o )
[2 of 2] Linking Main
Main: Some Pesky Error
CallStack (from HasCallStack):
  error, called at Main.hs:9:9 in main:Main
  f, called at Main.hs:14:32 in main:Main
  g, called at Main.hs:23:13 in main:Main
  main, called at Main.hs:17:1 in main:Main
Cost-centre stack backtrace:
IPE backtrace:
HasCallStack backtrace:
  collectBacktraces, called at libraries/ghc-internal/src/GHC/Internal/Exception.hs:92:13 in ghc-internal:GHC.Internal.Exception
  toExceptionWithBacktrace, called at libraries/ghc-internal/src/GHC/Internal/Exception.hs:128:3 in ghc-internal:GHC.Internal.Exception
1 Like

Indeed I hope to publish a blog post about this feature soon. I was hoping to have it ready for the release but unfortunately time has been very tight recently.

In short:

  • HasCallStackBacktrace requires that all functions of interest in the failing branch of the call-graph have a HasCallStack constraint. Unfortunately, it does look like something isn’t quite right in the behavior here. I’ve opened #24807 to track this (and have now fixed it)
  • CostCentreBacktrace requires not only -prof but also that cost-centres are added to the program (e.g. via a {-# CCS ... #-} pragma or -fprof-auto
  • ExecutionBacktrace requires DWARF support and that all libraries of your program (e.g. including base) are built with -g. As we see here, if any function in the call-chain does not have debug information the backtrace will be truncated at that frame.
  • IPEBacktrace requires -finfo-prov-map. In general the more packages that are built with IPE information, the more helpful this backtrace will be. However, unlike ExecutionBacktrace, absence of IPE information for a frame will not truncate the backtrace but rather will simply contribute no useful information.

With a GHC build with IPE and debug information enabled (and the fix noted above), I get the following output from your program:

$ _build-ipe/stage1/bin/ghc hi.hs -g3 -finfo-table-map -prof -fprof-auto -fforce-recomp
$ ./hi h
hi: Some Pesky Error
CallStack (from HasCallStack):
  error, called at hi.hs:8:9 in main:Main
  f, called at hi.hs:13:32 in main:Main
CallStack (from -prof):
  Main.f (hi.hs:(8,1)-(9,24))
  Main.g (hi.hs:13:1-35)
  Main.main.\ (hi.hs:21:3-18)
  Main.main (hi.hs:(15,1)-(21,18))
Cost-centre stack backtrace:
  Main.main (hi.hs:(15,1)-(21,18))
  Main.main.\ (hi.hs:21:3-18)
  Main.g (hi.hs:13:1-35)
  Main.f (hi.hs:(8,1)-(9,24))
Native stack backtrace:
  set_initial_registers (rts/Libdw.c:294.5) in /mnt/data/exp/ghc/ghc-9.10/hi
  dwfl_thread_getframes in 
  get_one_thread_cb in /nix/store/53nia34f1pqf89idqs4bbm86k0xfgydf-elfutils-0.189/lib/libdw-0.189.so
  dwfl_getthreads in /nix/store/53nia34f1pqf89idqs4bbm86k0xfgydf-elfutils-0.189/lib/libdw-0.189.so
  dwfl_getthread_frames in /nix/store/53nia34f1pqf89idqs4bbm86k0xfgydf-elfutils-0.189/lib/libdw-0.189.so
  libdwGetBacktrace (rts/Libdw.c:263.15) in /mnt/data/exp/ghc/ghc-9.10/hi
  _ghczminternal_GHCziInternalziExecutionStackziInternal_sat_s2QY_entry (libraries/ghc-internal/src/GHC/Internal/ExecutionStack/Internal.hsc:217.31) in /mnt/data/exp/ghc/ghc-9.10/hi
  stg_keepAlive_frame_info (rts/PrimOps.cmm:2954.1) in /mnt/data/exp/ghc/ghc-9.10/hi
  ghczminternal_GHCziInternalziExecutionStackziInternal_collectStackTrace1_info (libraries/ghc-internal/src/GHC/Internal/ExecutionStack/Internal.hsc:86.10) in /mnt/data/exp/ghc/ghc-9.10/hi
  ghczminternal_GHCziInternalziExceptionziBacktrace_zdwcollectBacktraces_info (libraries/ghc-internal/src/GHC/Internal/Exception/Backtrace.hs:145.54) in /mnt/data/exp/ghc/ghc-9.10/hi
  ghczminternal_GHCziInternalziExceptionziBacktrace_collectBacktraces1_info (libraries/ghc-internal/src/GHC/Internal/Exception/Backtrace.hs:43.9) in /mnt/data/exp/ghc/ghc-9.10/hi
  ghczminternal_GHCziInternalziException_errorCallWithCallStackException_info (libraries/ghc-internal/src/GHC/Internal/Exception.hs:122.1) in /mnt/data/exp/ghc/ghc-9.10/hi
  stg_marked_upd_frame_info (rts/Updates.cmm:56.1) in /mnt/data/exp/ghc/ghc-9.10/hi
  _ghczminternal_GHCziInternalziTopHandler_realzuhandler_r387_entry (libraries/ghc-internal/src/GHC/Internal/TopHandler.hs:188.1) in /mnt/data/exp/ghc/ghc-9.10/hi
  stg_catch_frame_info (rts/Exception.cmm:405.1) in /mnt/data/exp/ghc/ghc-9.10/hi
  stg_unmaskAsyncExceptionszh_ret_info (rts/Exception.cmm:87.1) in /mnt/data/exp/ghc/ghc-9.10/hi
  stg_stop_thread_info (rts/StgStartup.cmm:47.1) in /mnt/data/exp/ghc/ghc-9.10/hi
  StgRunIsImplementedInAssembler (rts/StgCRun.c:378.5) in /mnt/data/exp/ghc/ghc-9.10/hi
  schedule (rts/Schedule.c:481.13) in /mnt/data/exp/ghc/ghc-9.10/hi
  scheduleWaitThread (rts/Schedule.c:2675.11) in /mnt/data/exp/ghc/ghc-9.10/hi
  rts_evalLazyIO (rts/RtsAPI.c:565.1) in /mnt/data/exp/ghc/ghc-9.10/hi
  hs_main (rts/RtsMain.c:73.18) in /mnt/data/exp/ghc/ghc-9.10/hi
   in /mnt/data/exp/ghc/ghc-9.10/hi
  __libc_start_call_main in 
  __libc_start_main@@GLIBC_2.34 in /nix/store/46m4xx889wlhsdj72j38fnlyyvvvvbyb-glibc-2.37-8/lib/libc.so.6
  _start in /mnt/data/exp/ghc/ghc-9.10/hi
IPE backtrace:
    Cmm$rts/StgStartup.cmm. (:)
    Cmm$rts/Exception.cmm. (:)
    Cmm$rts/Exception.cmm. (:)
    GHC.Internal.TopHandler. (:)
    Cmm$rts/Updates.cmm. (:)
    GHC.Internal.Exception.bindIO (libraries/ghc-internal/src/GHC/Internal/Base.hs:2246:1-76)
    GHC.Internal.Exception.Backtrace. (:)
    GHC.Internal.Exception.Backtrace.$ (libraries/ghc-internal/src/GHC/Internal/Base.hs:2180:1-9)
HasCallStack backtrace:
  collectBacktraces, called at libraries/ghc-internal/src/GHC/Internal/Exception.hs:92:13 in ghc-internal:GHC.Internal.Exception
  toExceptionWithBacktrace, called at libraries/ghc-internal/src/GHC/Internal/Exception.hs:127:5 in ghc-internal:GHC.Internal.Exception
  error, called at hi.hs:8:9 in main:Main
  f, called at hi.hs:13:32 in main:Main

In this case, the trivial nature of the test program means that the execution backtraces aren’t particularly helpful. It may be that IPE coverage needs improvement in this case or that we should improve the stack decoder’s treatment of primitive stack frame types (e.g. update frames, see #24811, #24812). I haven’t looked closely enough at this program to see why that is but I don’t doubt that there are improvements that could be made here.

An aside: When interpreting IPE and DWARF “backtraces” one must remember that the execution stack tracks continuations and not call-sites. In contrast to C, where there is a very strong correspondence between continuations and call-sites, in Haskell tail calls are quite common and therefore you will often see the entries from the “future” of your program in the backtrace.

18 Likes

Thank you very much for the comprehensive response Ben! This looks great. I’m looking forward to your blog post.

1 Like

@mpilgrem GHC musl image glcr.b-data.ch/ghc/ghc-musl:9.10.1 is available now:

  • Base image updated to alpine:3.20
    • Package clang18 added
  • LLVM v18 backend forced by patch
  • cabal-install updated to v3.12.0.0-prerelease
    • i.e. cabal-install v3.11.0.0

Cross references:


I have created a pull request to update Stack’s Dev Containers.

Cross reference: Dev Container: Add 'GHC 9.10.1' by benz0li · Pull Request #6595 · commercialhaskell/stack · GitHub

4 Likes

Hi! Thank you for the awesome work on the exception backtraces. I have been playing around with them a bit and have encountered a few issues, so I went digging. Now that I did, I found that portions of the proposal seems to be missing, for example, I couldn’t find the rethrowing mechanisms (there seem to even be open CLC proposals on that topic) and while the toplevel handler of the RTS itself seem to be adjusted, this doesn’t seem to be the case for GHCi/ runghc. Is there some place where I can find out about the status of things?

2 Likes