GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2019-07-07T18:33:50Zhttps://gitlab.haskell.org/ghc/ghc/-/issues/10798Signatures with only types should not be included in unit keys2019-07-07T18:33:50ZEdward Z. YangSignatures with only types should not be included in unit keysSuppose we want to modularize the dependence on `p` in this program:
```
unit p where
module A where
data T = T
mkT = T
unit q where
include p
module B where
import A
bar = mkT
```
The obvious signature to write f...Suppose we want to modularize the dependence on `p` in this program:
```
unit p where
module A where
data T = T
mkT = T
unit q where
include p
module B where
import A
bar = mkT
```
The obvious signature to write for `A` is:
```
signature A where
data T
mkT :: T
```
But this presupposes an implementation of `A` which exports `T`. But `B` doesn't use any export of `T`, and an equally valid implementation would be if `T` was defined in some `Types` module and then imported here.
But suppose we change our signature to be:
```
signature A.Types where
data T
signature A where
import A.Types
mkT :: T
```
This is maximally general, but requires that the module which exports `T` be named `A.Types`. If someone puts the type anywhere else, we have to rename the signature to the real place it was defined, or make a dummy implementation module which reexports the type in question.
Now there is a curious thing, which is that the choice of module we use to fill these extra signature modules currently influences the type identity of anything else in the unit. But we never rely on any code from these signatures: if I make two distinct dummy modules to set `T` to the same type, this really shouldn't have any impact (at all!) on the code generated.
So, my suggestion is that if a signature contains only types (perhaps they could be named something else, like `tysignature`), they should not count towards the calculation of a unit key. This means that a user can freely create dummy modules to fill in these types when they are instantiating; all that is being done is helping Backpack figure out what the identities of types are. (If we wanted to be fancy, Backpack could even look inside type signatures to determine some types, but let's not go there for now.)
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.11 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Package system |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Signatures with only types should not be included in unit keys","status":"New","operating_system":"","component":"Package system","related":[],"milestone":"⊥","resolution":"Unresolved","owner":{"tag":"OwnedBy","contents":"ezyang"},"version":"7.11","keywords":["backpack"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"Suppose we want to modularize the dependence on `p` in this program:\r\n\r\n{{{\r\nunit p where\r\n module A where\r\n data T = T\r\n mkT = T\r\nunit q where\r\n include p\r\n module B where\r\n import A\r\n bar = mkT\r\n}}}\r\n\r\nThe obvious signature to write for `A` is:\r\n\r\n{{{\r\nsignature A where\r\n data T\r\n mkT :: T\r\n}}}\r\n\r\nBut this presupposes an implementation of `A` which exports `T`. But `B` doesn't use any export of `T`, and an equally valid implementation would be if `T` was defined in some `Types` module and then imported here.\r\n\r\nBut suppose we change our signature to be:\r\n\r\n{{{\r\nsignature A.Types where\r\n data T\r\nsignature A where\r\n import A.Types\r\n mkT :: T\r\n}}}\r\n\r\nThis is maximally general, but requires that the module which exports `T` be named `A.Types`. If someone puts the type anywhere else, we have to rename the signature to the real place it was defined, or make a dummy implementation module which reexports the type in question.\r\n\r\nNow there is a curious thing, which is that the choice of module we use to fill these extra signature modules currently influences the type identity of anything else in the unit. But we never rely on any code from these signatures: if I make two distinct dummy modules to set `T` to the same type, this really shouldn't have any impact (at all!) on the code generated.\r\n\r\nSo, my suggestion is that if a signature contains only types (perhaps they could be named something else, like `tysignature`), they should not count towards the calculation of a unit key. This means that a user can freely create dummy modules to fill in these types when they are instantiating; all that is being done is helping Backpack figure out what the identities of types are. (If we wanted to be fancy, Backpack could even look inside type signatures to determine some types, but let's not go there for now.)","type_of_failure":"OtherFailure","blocking":[]} -->⊥Edward Z. YangEdward Z. Yanghttps://gitlab.haskell.org/ghc/ghc/-/issues/7746Support loading/unloading profiled objects from a profiled executable2019-07-07T18:48:19ZEdward Z. YangSupport loading/unloading profiled objects from a profiled executableThis is closely related to #3360, but it is a bit less ambitious and should be possible to implement without too many extra changes to the byte code compiler and interpreter (e.g. we just have to teach the linker how to handle things). H...This is closely related to #3360, but it is a bit less ambitious and should be possible to implement without too many extra changes to the byte code compiler and interpreter (e.g. we just have to teach the linker how to handle things). Here is a simple test program off of 'plugins' to get working:
```
{-# LANGUAGE ScopedTypeVariables #-}
import System.Plugins.Make
import System.Plugins.Load
import Data.List
boot :: FilePath -> IO ()
boot path = do
r <- make path ["-prof"]
case r of
MakeSuccess _ p -> do
r' <- load p [] [] "result"
case r' of
LoadSuccess _ (v :: Int) -> print v
LoadFailure msg -> print msg
MakeFailure es -> putStrLn ("Failed: " ++ intercalate " " es)
main = do
boot "Foo.hs"
```
where Foo.hs is
```
module Foo where
result = 2 :: Int
```
Here are the things that, as far as I can tell, need to be handled:
- We should ensure consistency between the host and the object file being uploaded. For example, if you load an un-profiled object file into a profiled binary, GHC will eat all your puppies. A simple way to do this is look for a symbol (e.g. CC_LIST) which is only ever exported when something is profiled and barf it is encountered.
- This current code fails with `test: Foo.o: unknown symbol `CC_LIST'`, much the same way GHCi used to fail. This particular problem is (I think) that we don’t store CC_LIST and other externsymbols in our global hash table, so the linker thinks that they don’t exist, when they do. CC_LIST and friends should be special-cased or added to the table. I have a patch for that; it's pretty easy.
- We don’t run ctors which setup CC_LIST with all of the cost-centres from the loaded module; we need to teach the linker to do that. The relevant bug is #5435.
- We need to come up with some sensible way of unloading cost-centres from CC_LIST and friends; we could make CC_LIST doubly-linked and then just excise the cost-centre in a destructor, but freeing the actual allocated CostCentre is more difficult. For now, we might just live with the memory leak, but see wiki:"Commentary/ResourceLimits\#Memoryleaks" for a possible better implementation strategy. Whatever cleanup is done here should be registered as a destructor for the library. Maybe #8039 solves this problem.
- Tests!
But that’s it; everything else should work normally. Something similar should apply to ticky builds. Sans destructors, there is a good chance this shindig may already work for dynamically linked apps.⊥Edward Z. YangEdward Z. Yang