Skip to content

`atomicModifyIORef'` is subtly lazier than expected

Summary

I would expect the value in an IORef to be in head-normal form after calling atomicallyModifyIORef'. Yet, this is not always the case.

atomicModifyIORef' ref f works by first calculating x = f old. x is a tuple of the new value and the returned value. It then switches out the value in ref for the selector thunk fst x. Finally, it forces the components of x.

This leaves ref holding a selection thunk, be it one that points at a head-normal form value.

My issue is that this makes finding unwanted thunks with ghc-heap or nothunks tricky. It becomes unclear whether the thunk held by the IORef is a genuine one or merely one of these selection thunks pointing at something evaluated.

It would be better if atomicModifyIORef' directly evaluated the value in the IORef, hence forcing both the selection thunk and the first component of x. The primop and a couple of functions in GHC.IORef would have to be modified to make this value available in the definition of atomicModifyIORef' where it could be forced.

Steps to reproduce

See https://gitlab.haskell.org/teo/t20823-repro

Expected behavior

The program shouldn't find a thunk

Environment

  • GHC version used: 8.8.4, 8.10.7, but as far as I can see, the IORef code hasn't been touched since then
Edited by Teo Camarasu
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information