[Git][ghc/ghc][wip/unload-strategy] 9 commits: linker: refactor loader so that object suffixes get passed through in a sane way
Zubin pushed to branch wip/unload-strategy at Glasgow Haskell Compiler / GHC Commits: 8eea219f by Zubin Duggal at 2026-08-25T14:52:54+05:30 linker: refactor loader so that object suffixes get passed through in a sane way - - - - - e1c8030b by Zubin Duggal at 2026-08-25T14:52:54+05:30 Identify Linkable with fingerprints of their contents rather than modtimes - - - - - afdb51c2 by Zubin Duggal at 2026-08-25T14:52:54+05:30 Linker cleanup delete a bunch of unused functions - - - - - c7f64e7d by Zubin Duggal at 2026-08-25T14:52:54+05:30 Record constituent hashes for bytecode libraries A bytecode library now records the combined hash of its constituents, so relinking can be skipped when they haven't changed. - - - - - 8c6f94c5 by Zubin Duggal at 2026-08-25T14:52:54+05:30 linker: Automatically reload stale linkables Linked BCOs contain direct references to closures, so replacing only a changed module can leave stale references in other modules. Take -- A.hs f = 1 -- B.hs import A g = f + 1 After loading A and B, change A so that f = 2 and recompile it. B does not need to be recompiled, but its loaded BCO still refers to the old closure for f. The next splice should see f = 2 and g = 3. To get the correct result, we have to *reload* B, even though we didn't need to recompile it. The GHC driver calls unload before each upsweep, which unloads everything, so this does not arise during an ordinary GHCi reload. API clients such as HLS may instead want to keep the loader state while recompiling individual modules. Forcing them to unload everything or carefully keep track of what to unload is not ideal. Now we automatically reload stale linkables, so that if we are asked to link a module whose code has changed, the old code, and everything that refers to it, is dropped and reloaded. See Note [Automatically reloading stale linkables]. Dropped objects are now purged, not unloaded, so values built by the old code and computations still using it keep working. The object stays in memory, but new code will not be able to link against it. This is a change in behaviour, objects were previously only ever unloaded, all at once, in unload. See Note [Unloading vs purging objects] Fixes #27606 - - - - - c500df06 by Zubin Duggal at 2026-08-25T14:52:54+05:30 linker: Add unloadModules Drop the given modules and every loaded module that transitively refers to them. Reloading stale code does not need this, it happens automatically. This is for API clients dropping modules they no longer need. Interactive modules are ignored. See Note [Automatically reloading stale linkables] in GHC.Linker.Loader See Note [Unloading vs purging objects] in GHC.Runtime.Interpreter - - - - - d2e4f73e by Zubin Duggal at 2026-08-25T14:52:54+05:30 iserv: Add a PurgeObj message purgeObj no longer falls back to unloading on external interpreters. See Note [Unloading vs purging objects] in GHC.Runtime.Interpreter. - - - - - 8dc9fe7d by Zubin Duggal at 2026-08-25T14:52:54+05:30 linker: Remove static pointer table entries when dropping modules Entries were added by bytecode modules, but never removed. This meant that every reload of a module with static forms leaked its old entries and kept the old code alive, including in GHCi with :reload. loaded_spt_keys now records the keys each loaded bytecode module inserted. dropModules and unload remove them. We also add a new RemoveSptEntry message to support this operation with the external interpreter. Object code manages its own entries with initialisers and finalisers, so it was not changed. Fixes #27740 - - - - - eabe067a by Zubin Duggal at 2026-08-25T14:52:54+05:30 Introduce -funload-strategy When unloading object code, we have a choice to make. Do we call purgeObj or unloadObj? purgeObj clears the symbol tables associated with an object, so that future objects can't link against it, but the object stays in memory unloadObj does the above, but it also marks the object as needing to be unloaded, so at some point in a future GC, the RTS may notice that it is no longer used, and if so, unload it entirely, freeing up the memory. Ideally we would always unload, but a number of bugs with the implementation of unloadObj mean that it is fragile on many platforms. This is documented in Note [Unloading vs purging objects]. So on these platforms we purge instead. We introduce the -funload-strategy flag, so that users can opt into purging/unloading on platforms where we make the other choice by default. The distinction is moot when we are using the dynamic RTS, we don't do either then. Fixes #27741 - - - - - 42 changed files: - + changelog.d/unload-strategy - compiler/GHC.hs - compiler/GHC/ByteCode/Serialize.hs - compiler/GHC/Driver/Config/Interpreter.hs - compiler/GHC/Driver/DynFlags.hs - compiler/GHC/Driver/Main/Compile.hs - compiler/GHC/Driver/Main/Passes.hs - compiler/GHC/Driver/Pipeline.hs - compiler/GHC/Driver/Session.hs - compiler/GHC/Linker/ByteCode.hs - compiler/GHC/Linker/Deps.hs - compiler/GHC/Linker/Loader.hs - compiler/GHC/Linker/Types.hs - compiler/GHC/Runtime/Interpreter.hs - compiler/GHC/Runtime/Interpreter/Init.hs - compiler/GHC/Runtime/Interpreter/Types.hs - compiler/GHC/Unit/Finder.hs - docs/users_guide/ghci.rst - libraries/ghci/GHCi/Message.hs - libraries/ghci/GHCi/ObjLink.hs - libraries/ghci/GHCi/Run.hs - libraries/ghci/GHCi/StaticPtrTable.hs - + testsuite/tests/driver/recomp023/M.hs - + testsuite/tests/driver/recomp023/Makefile - + testsuite/tests/driver/recomp023/all.T - + testsuite/tests/driver/recomp023/recomp023.stdout - + testsuite/tests/ghc-api/T27606/B.hs - + testsuite/tests/ghc-api/T27606/T27606a.hs - + testsuite/tests/ghc-api/T27606/T27606a.stdout - + testsuite/tests/ghc-api/T27606/T27606b.hs - + testsuite/tests/ghc-api/T27606/T27606b.stdout - + testsuite/tests/ghc-api/T27606/T27606c.hs - + testsuite/tests/ghc-api/T27606/T27606c.stdout - + testsuite/tests/ghc-api/T27606/T27606c_purge.stdout - + testsuite/tests/ghc-api/T27606/T27606d.hs - + testsuite/tests/ghc-api/T27606/T27606d.stdout - + testsuite/tests/ghc-api/T27606/T27606e.hs - + testsuite/tests/ghc-api/T27606/T27606e.stdout - + testsuite/tests/ghc-api/T27606/all.T - + testsuite/tests/ghc-api/T27740.hs - + testsuite/tests/ghc-api/T27740.stdout - testsuite/tests/ghc-api/all.T The diff was not included because it is too large. View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/79f3073b4f9dd3e58959a6643e506c9... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/79f3073b4f9dd3e58959a6643e506c9... You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
participants (1)
-
Zubin (@wz1000)