summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2019-03-13 19:42:47 -0400
committerMarge Bot <ben+marge-bot@smart-cactus.org>2019-03-17 05:05:10 -0400
commitcb61371e3260e07be724a04b72a935133f66b514 (patch)
tree456e4f3fa84ab7f8fa94ed66f717f6ea949899f8
parent3f2291e47b8e00f1312c9be31484ceddd1289212 (diff)
downloadhaskell-cb61371e3260e07be724a04b72a935133f66b514.tar.gz
ghc-heap: Introduce closureSize
This function allows the user to compute the (non-transitive) size of a heap object in words. The "closure" in the name is admittedly confusing but we are stuck with this nomenclature at this point.
-rw-r--r--compiler/prelude/primops.txt.pp7
-rw-r--r--includes/stg/MiscClosures.h1
-rw-r--r--libraries/ghc-heap/GHC/Exts/Heap/Closures.hs14
-rw-r--r--libraries/ghc-heap/tests/all.T3
-rw-r--r--libraries/ghc-heap/tests/closure_size.hs34
-rw-r--r--libraries/ghc-heap/tests/closure_size.stdout0
-rw-r--r--libraries/ghc-prim/changelog.md8
-rw-r--r--rts/PrimOps.cmm7
-rw-r--r--rts/RtsSymbols.c1
9 files changed, 75 insertions, 0 deletions
diff --git a/compiler/prelude/primops.txt.pp b/compiler/prelude/primops.txt.pp
index 94de07f8e5..6a1be8a486 100644
--- a/compiler/prelude/primops.txt.pp
+++ b/compiler/prelude/primops.txt.pp
@@ -3208,6 +3208,13 @@ primop UnpackClosureOp "unpackClosure#" GenPrimOp
with
out_of_line = True
+primop ClosureSizeOp "closureSize#" GenPrimOp
+ a -> Int#
+ { {\tt closureSize\# closure} returns the size of the given closure in
+ machine words. }
+ with
+ out_of_line = True
+
primop GetApStackValOp "getApStackVal#" GenPrimOp
a -> Int# -> (# Int#, b #)
with
diff --git a/includes/stg/MiscClosures.h b/includes/stg/MiscClosures.h
index 8c4cb9fc8c..0fc904e770 100644
--- a/includes/stg/MiscClosures.h
+++ b/includes/stg/MiscClosures.h
@@ -470,6 +470,7 @@ RTS_FUN_DECL(stg_readTVarIOzh);
RTS_FUN_DECL(stg_writeTVarzh);
RTS_FUN_DECL(stg_unpackClosurezh);
+RTS_FUN_DECL(stg_closureSizzezh);
RTS_FUN_DECL(stg_getApStackValzh);
RTS_FUN_DECL(stg_getSparkzh);
RTS_FUN_DECL(stg_numSparkszh);
diff --git a/libraries/ghc-heap/GHC/Exts/Heap/Closures.hs b/libraries/ghc-heap/GHC/Exts/Heap/Closures.hs
index e624a17b78..2465014e48 100644
--- a/libraries/ghc-heap/GHC/Exts/Heap/Closures.hs
+++ b/libraries/ghc-heap/GHC/Exts/Heap/Closures.hs
@@ -13,6 +13,12 @@ module GHC.Exts.Heap.Closures (
, GenClosure(..)
, PrimType(..)
, allClosures
+#if __GLASGOW_HASKELL__ >= 809
+ -- The closureSize# primop is unsupported on earlier GHC releases but we
+ -- build ghc-heap as a boot library so it must be buildable. Drop this once
+ -- we are guaranteed to bootstsrap with GHC >= 8.9.
+ , closureSize
+#endif
-- * Boxes
, Box(..)
@@ -321,3 +327,11 @@ allClosures (FunClosure {..}) = ptrArgs
allClosures (BlockingQueueClosure {..}) = [link, blackHole, owner, queue]
allClosures (OtherClosure {..}) = hvalues
allClosures _ = []
+
+#if __GLASGOW_HASKELL__ >= 809
+-- | Get the size of a closure in words.
+--
+-- @since 8.10.1
+closureSize :: Box -> Int
+closureSize (Box x) = I# (closureSize# x)
+#endif
diff --git a/libraries/ghc-heap/tests/all.T b/libraries/ghc-heap/tests/all.T
index a676b4971a..595bd000d4 100644
--- a/libraries/ghc-heap/tests/all.T
+++ b/libraries/ghc-heap/tests/all.T
@@ -6,3 +6,6 @@ test('heap_all',
omit_ways(['ghci', 'hpc'])
],
compile_and_run, [''])
+test('closure_size',
+ omit_ways(['ghci', 'hpc', 'prof']),
+ compile_and_run, [''])
diff --git a/libraries/ghc-heap/tests/closure_size.hs b/libraries/ghc-heap/tests/closure_size.hs
new file mode 100644
index 0000000000..d77060779e
--- /dev/null
+++ b/libraries/ghc-heap/tests/closure_size.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+import Control.Monad
+import Type.Reflection
+import GHC.Stack
+
+import GHC.Exts.Heap.Closures
+
+assertSize :: forall a. (HasCallStack, Typeable a)
+ => a -> Int -> IO ()
+assertSize !x expected = do
+ let !size = closureSize (asBox x)
+ when (size /= expected) $ do
+ putStrLn $ "closureSize ("++show (typeRep @a)++") == "++show size++", expected "++show expected
+ putStrLn $ prettyCallStack callStack
+{-# NOINLINE assertSize #-}
+
+pap :: Int -> Char -> Int
+pap x _ = x
+{-# NOINLINE pap #-}
+
+main :: IO ()
+main = do
+ assertSize 'a' 2
+ assertSize (Just ()) 2
+ assertSize (Nothing :: Maybe ()) 2
+ assertSize ((1,2) :: (Int,Int)) 3
+ assertSize ((1,2,3) :: (Int,Int,Int)) 4
+ assertSize (id :: Int -> Int) 1
+ assertSize (fst :: (Int,Int) -> Int) 1
+ assertSize (pap 1) 2
+
diff --git a/libraries/ghc-heap/tests/closure_size.stdout b/libraries/ghc-heap/tests/closure_size.stdout
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/libraries/ghc-heap/tests/closure_size.stdout
diff --git a/libraries/ghc-prim/changelog.md b/libraries/ghc-prim/changelog.md
index ecbc93fea4..2298846cd1 100644
--- a/libraries/ghc-prim/changelog.md
+++ b/libraries/ghc-prim/changelog.md
@@ -1,3 +1,11 @@
+## 0.6.1
+
+- Shipped with GHC 8.10.1
+
+- Added to `GHC.Prim`:
+
+ closureSize# :: a -> Int#
+
## 0.6.0
- Shipped with GHC 8.8.1
diff --git a/rts/PrimOps.cmm b/rts/PrimOps.cmm
index 625f5f5ab3..bc89839aec 100644
--- a/rts/PrimOps.cmm
+++ b/rts/PrimOps.cmm
@@ -2041,6 +2041,13 @@ for:
return (info, dat_arr, ptrArray);
}
+stg_closureSizzezh (P_ clos)
+{
+ W_ len;
+ (len) = foreign "C" heap_view_closureSize(UNTAG(clos) "ptr");
+ return (len);
+}
+
/* -----------------------------------------------------------------------------
Thread I/O blocking primitives
-------------------------------------------------------------------------- */
diff --git a/rts/RtsSymbols.c b/rts/RtsSymbols.c
index 6966d6deb9..eb0322ed3e 100644
--- a/rts/RtsSymbols.c
+++ b/rts/RtsSymbols.c
@@ -631,6 +631,7 @@
SymI_HasProto(initLinker) \
SymI_HasProto(initLinker_) \
SymI_HasProto(stg_unpackClosurezh) \
+ SymI_HasProto(stg_closureSizzezh) \
SymI_HasProto(stg_getApStackValzh) \
SymI_HasProto(stg_getSparkzh) \
SymI_HasProto(stg_numSparkszh) \