[project @ 2003-11-17 14:23:30 by simonmar]
[ghc-hetmet.git] / ghc / compiler / codeGen / ClosureInfo.lhs
index 3b7b5a1..2de8802 100644 (file)
@@ -1,7 +1,7 @@
 %
 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
-% $Id: ClosureInfo.lhs,v 1.38 1999/05/18 15:03:50 simonpj Exp $
+% $Id: ClosureInfo.lhs,v 1.61 2003/11/17 14:23:31 simonmar Exp $
 %
 \section[ClosureInfo]{Data structures which describe closures}
 
@@ -11,21 +11,20 @@ the STG paper.
 \begin{code}
 module ClosureInfo (
        ClosureInfo, LambdaFormInfo, SMRep,     -- all abstract
-       StandardFormInfo,
+       StandardFormInfo, ArgDescr(..),
 
-       EntryConvention(..),
+       CallingConvention(..),
 
        mkClosureLFInfo, mkConLFInfo, mkSelectorLFInfo,
        mkApLFInfo, mkLFImported, mkLFArgument, mkLFLetNoEscape,
-       UpdateFlag,
 
        closureSize, closureNonHdrSize,
        closureGoodStuffSize, closurePtrsSize,
        slopSize,
 
-       layOutDynClosure, layOutDynCon, layOutStaticClosure,
-       layOutStaticNoFVClosure,
-       mkVirtHeapOffsets,
+       layOutDynClosure, layOutStaticClosure, layOutStaticNoFVClosure,
+       layOutDynConstr, layOutStaticConstr,
+       mkVirtHeapOffsets, mkStaticClosure,
 
        nodeMustPointToIt, getEntryConvention, 
        FCode, CgInfoDownwards, CgState, 
@@ -33,15 +32,13 @@ module ClosureInfo (
        blackHoleOnEntry,
 
        staticClosureRequired,
-       slowFunEntryCodeRequired, funInfoTableRequired,
 
-       closureName, infoTableLabelFromCI, fastLabelFromCI,
-       closureLabelFromCI,
+       closureName, infoTableLabelFromCI,
+       closureLabelFromCI, closureSRT,
        entryLabelFromCI, 
        closureLFInfo, closureSMRep, closureUpdReqd,
        closureSingleEntry, closureReEntrant, closureSemiTag,
-       isStandardFormThunk,
-       GenStgArg,
+       closureFunInfo, isStandardFormThunk,
 
        isToplevClosure,
        closureTypeDescr,               -- profiling
@@ -49,58 +46,49 @@ module ClosureInfo (
        isStaticClosure,
        allocProfilingMsg,
        cafBlackHoleClosureInfo, seCafBlackHoleClosureInfo,
-       maybeSelectorInfo,
 
-       infoTblNeedsSRT,
        staticClosureNeedsLink,
-       getSRTInfo
+
+       mkInfoTable, mkRetInfoTable, mkVecInfoTable,
     ) where
 
+#include "../includes/config.h"
+#include "../includes/MachDeps.h"
 #include "HsVersions.h"
 
-import AbsCSyn         ( MagicId, node, VirtualHeapOffset, HeapOffset )
+import AbsCSyn         
 import StgSyn
 import CgMonad
 
-import Constants       ( mIN_UPD_SIZE, mIN_SIZE_NonUpdHeapObject,
-                         mAX_SPEC_FUN_SIZE, mAX_SPEC_THUNK_SIZE, mAX_SPEC_CONSTR_SIZE )
+import Constants       ( mIN_UPD_SIZE, mIN_SIZE_NonUpdHeapObject )
 import CgRetConv       ( assignRegs )
-import CLabel          ( CLabel, mkStdEntryLabel, mkFastEntryLabel,
-                         mkInfoTableLabel,
-                         mkConInfoTableLabel, mkStaticClosureLabel, 
-                         mkCAFBlackHoleInfoTableLabel, 
-                         mkSECAFBlackHoleInfoTableLabel, 
-                         mkStaticInfoTableLabel, mkStaticConEntryLabel,
-                         mkConEntryLabel, mkClosureLabel,
-                         mkSelectorInfoLabel, mkSelectorEntryLabel,
-                         mkApInfoTableLabel, mkApEntryLabel,
-                         mkReturnPtLabel
-                       )
+import CLabel
 import CmdLineOpts     ( opt_SccProfilingOn, opt_OmitBlackHoling,
-                         opt_Parallel, opt_DoTickyProfiling )
-import Id              ( Id, idType, getIdArity )
-import DataCon         ( DataCon, dataConTag, fIRST_TAG,
-                         isNullaryDataCon, isTupleCon, dataConName
+                         opt_Parallel, opt_DoTickyProfiling,
+                         opt_SMP, opt_Unregisterised )
+import Id              ( Id, idType, idArity, idName, idPrimRep )
+import DataCon         ( DataCon, dataConTag, fIRST_TAG, dataConTyCon,
+                         isNullaryDataCon, dataConName
                        )
-import IdInfo          ( ArityInfo(..) )
-import Name            ( Name, isExternallyVisibleName, nameUnique )
-import PprType         ( getTyDescription )
-import PrimRep         ( getPrimRepSize, separateByPtrFollowness, PrimRep )
+import Name            ( Name, nameUnique, getOccName, getName, getOccString )
+import OccName         ( occNameUserString )
+import PrimRep
 import SMRep           -- all of it
-import Type            ( isUnLiftedType, Type )
-import BasicTypes      ( TopLevelFlag(..), isNotTopLevel, isTopLevel )
-import Util            ( mapAccumL )
+import Type            ( isUnLiftedType, Type, repType, splitTyConApp_maybe )
+import TcType          ( tcSplitSigmaTy )
+import TyCon           ( isFunTyCon )
+import BasicTypes      ( TopLevelFlag(..), isNotTopLevel, isTopLevel, ipNameName )
+import Util            ( mapAccumL, listLengthCmp, lengthIs )
+import FastString
 import Outputable
-\end{code}
+import Literal
+import Constants
+import Bitmap
 
-The ``wrapper'' data type for closure information:
+import Maybe           ( isJust )
+import DATA_BITS
 
-\begin{code}
-data ClosureInfo
-  = MkClosureInfo
-       Name                    -- The thing bound to this closure
-       LambdaFormInfo          -- info derivable from the *source*
-       SMRep                   -- representation used by storage manager
+import TypeRep -- TEMP
 \end{code}
 
 %************************************************************************
@@ -109,51 +97,81 @@ data ClosureInfo
 %*                                                                     *
 %************************************************************************
 
+Information about a closure, from the code generator's point of view.
+
+A ClosureInfo decribes the info pointer of a closure.  It has
+enough information 
+  a) to construct the info table itself
+  b) to allocate a closure containing that info pointer (i.e.
+       it knows the info table label)
+
+We make a ClosureInfo for
+       - each let binding (both top level and not)
+       - each data constructor (for its shared static and
+               dynamic info tables)
+
+\begin{code}
+data ClosureInfo
+  = ClosureInfo {
+       closureName   :: !Name,           -- The thing bound to this closure
+       closureLFInfo :: !LambdaFormInfo, -- NOTE: not an LFCon (see below)
+       closureSMRep  :: !SMRep,          -- representation used by storage mgr
+       closureSRT    :: !C_SRT,          -- What SRT applies to this closure
+       closureType   :: !Type,           -- Type of closure (ToDo: remove)
+       closureDescr  :: !String          -- closure description (for profiling)
+    }
+
+  -- constructor closures don't have a unique info table label (they use
+  -- the constructor's info table), and they don't have an SRT.
+  | ConInfo {
+       closureCon       :: !DataCon,
+       closureSMRep     :: !SMRep
+    }
+\end{code}
+
 %************************************************************************
 %*                                                                     *
 \subsubsection[LambdaFormInfo-datatype]{@LambdaFormInfo@: source-derivable info}
 %*                                                                     *
 %************************************************************************
 
+Information about an identifier, from the code generator's point of
+view.  Every identifier is bound to a LambdaFormInfo in the
+environment, which gives the code generator enough info to be able to
+tail call or return that identifier.
+
+Note that a closure is usually bound to an identifier, so a
+ClosureInfo contains a LambdaFormInfo.
+
 \begin{code}
 data LambdaFormInfo
-  = LFReEntrant                -- Reentrant closure; used for PAPs too
-       Type            -- Type of closure    (ToDo: remove)
+  = LFReEntrant                -- Reentrant closure (a function)
        TopLevelFlag    -- True if top level
        !Int            -- Arity
        !Bool           -- True <=> no fvs
-       CLabel          -- SRT label
-       SRT             -- SRT info
+       ArgDescr        -- Argument descriptor (should reall be in ClosureInfo)
 
   | LFCon              -- Constructor
        DataCon         -- The constructor
-       Bool            -- True <=> zero arity
-
-  | LFTuple            -- Tuples
-       DataCon         -- The tuple constructor
-       Bool            -- True <=> zero arity
 
   | LFThunk            -- Thunk (zero arity)
-       Type            -- Type of the thunk   (ToDo: remove)
        TopLevelFlag
        !Bool           -- True <=> no free vars
-       Bool            -- True <=> updatable (i.e., *not* single-entry)
+       !Bool           -- True <=> updatable (i.e., *not* single-entry)
        StandardFormInfo
-       CLabel          -- SRT label
-       SRT             -- SRT info
+       !Bool           -- True <=> *might* be a function type
 
-  | LFArgument         -- Used for function arguments.  We know nothing about
-                       -- this closure.  Treat like updatable "LFThunk"...
-
-  | LFImported         -- Used for imported things.  We know nothing about this
-                       -- closure.  Treat like updatable "LFThunk"...
+  | LFUnknown          -- Used for function arguments and imported things.
+                       --  We know nothing about  this closure.  Treat like
+                       -- updatable "LFThunk"...
                        -- Imported things which we do know something about use
                        -- one of the other LF constructors (eg LFReEntrant for
                        -- known functions)
+       !Bool           -- True <=> *might* be a function type
 
   | LFLetNoEscape      -- See LetNoEscape module for precise description of
                        -- these "lets".
-       Int             -- arity;
+       !Int            -- arity;
 
   | LFBlackHole                -- Used for the closures allocated to hold the result
                        -- of a CAF.  We want the target of the update frame to
@@ -207,66 +225,53 @@ mkClosureLFInfo :: Id             -- The binder
                -> [Id]         -- Free vars
                -> UpdateFlag   -- Update flag
                -> [Id]         -- Args
-               -> CLabel       -- SRT label
-               -> SRT          -- SRT info
                -> LambdaFormInfo
 
-mkClosureLFInfo bndr top fvs upd_flag args@(_:_) srt_label srt -- Non-empty args
-  = LFReEntrant (idType bndr) top (length args) (null fvs) srt_label srt
-
-mkClosureLFInfo bndr top fvs ReEntrant [] srt_label srt
-  = LFReEntrant (idType bndr) top 0 (null fvs) srt_label srt
+mkClosureLFInfo bndr top fvs upd_flag args@(_:_) -- Non-empty args
+  = LFReEntrant top (length args) (null fvs) (mkArgDescr (getName bndr) args)
 
-mkClosureLFInfo bndr top fvs upd_flag [] srt_label srt
-#ifdef DEBUG
-  | isUnLiftedType ty = pprPanic "mkClosureLFInfo" (ppr bndr <+> ppr ty)
-#endif
-  | otherwise
-  = LFThunk ty top (null fvs) (isUpdatable upd_flag) NonStandardThunk
-       srt_label srt
+mkClosureLFInfo bndr top fvs upd_flag []
+  = ASSERT( not updatable || not (isUnLiftedType id_ty) )
+    LFThunk top (null fvs) updatable NonStandardThunk 
+       (might_be_a_function id_ty)
   where
-    ty = idType bndr
+       updatable = isUpdatable upd_flag
+       id_ty = idType bndr
+
+might_be_a_function :: Type -> Bool
+might_be_a_function ty
+  | Just (tc,_) <- splitTyConApp_maybe (repType ty), 
+    not (isFunTyCon tc) = False
+  | otherwise = True
 \end{code}
 
 @mkConLFInfo@ is similar, for constructors.
 
 \begin{code}
 mkConLFInfo :: DataCon -> LambdaFormInfo
+mkConLFInfo con = LFCon con
 
-mkConLFInfo con
-  = -- the isNullaryDataCon will do this: ASSERT(isDataCon con)
-    (if isTupleCon con then LFTuple else LFCon) con (isNullaryDataCon con)
-
-mkSelectorLFInfo rhs_ty offset updatable
-  = LFThunk rhs_ty NotTopLevel False updatable (SelectorThunk offset)
-       (error "mkSelectorLFInfo: no srt label")
-       (error "mkSelectorLFInfo: no srt")
+mkSelectorLFInfo id offset updatable
+  = LFThunk NotTopLevel False updatable (SelectorThunk offset) 
+       (might_be_a_function (idType id))
 
-mkApLFInfo rhs_ty upd_flag arity
-  = LFThunk rhs_ty NotTopLevel (arity == 0) (isUpdatable upd_flag) 
-       (ApThunk arity)
-       (error "mkApLFInfo: no srt label")
-       (error "mkApLFInfo: no srt")
+mkApLFInfo id upd_flag arity
+  = LFThunk NotTopLevel (arity == 0) (isUpdatable upd_flag) (ApThunk arity)
+       (might_be_a_function (idType id))
 \end{code}
 
 Miscellaneous LF-infos.
 
 \begin{code}
-mkLFArgument   = LFArgument
+mkLFArgument id = LFUnknown (might_be_a_function (idType id))
+
 mkLFLetNoEscape = LFLetNoEscape
 
 mkLFImported :: Id -> LambdaFormInfo
 mkLFImported id
-  = case getIdArity id of
-      ArityExactly 0   -> LFThunk (idType id)
-                               TopLevel True{-no fvs-}
-                               True{-updatable-} NonStandardThunk
-                               (error "mkLFImported: no srt label") 
-                               (error "mkLFImported: no srt")
-      ArityExactly n   -> LFReEntrant (idType id) TopLevel n True  -- n > 0
-                               (error "mkLFImported: no srt label") 
-                               (error "mkLFImported: no srt")
-      other            -> LFImported   -- Not sure of exact arity
+  = case idArity id of
+      n | n > 0 -> LFReEntrant TopLevel n True (panic "arg_descr")  -- n > 0
+      other -> mkLFArgument id -- Not sure of exact arity
 \end{code}
 
 %************************************************************************
@@ -277,32 +282,44 @@ mkLFImported id
 
 \begin{code}
 closureSize :: ClosureInfo -> HeapOffset
-closureSize cl_info@(MkClosureInfo _ _ sm_rep)
-  = fixedHdrSize + closureNonHdrSize cl_info
+closureSize cl_info = fixedHdrSize + closureNonHdrSize cl_info
 
 closureNonHdrSize :: ClosureInfo -> Int
-closureNonHdrSize cl_info@(MkClosureInfo _ lf_info sm_rep)
-  = tot_wds + computeSlopSize tot_wds sm_rep (closureUpdReqd cl_info) 
-    --ToDo: pass lf_info?
+closureNonHdrSize cl_info
+  = tot_wds + computeSlopSize tot_wds 
+                             (closureSMRep cl_info)
+                             (closureNeedsUpdSpace cl_info) 
   where
     tot_wds = closureGoodStuffSize cl_info
 
+-- we leave space for an update if either (a) the closure is updatable
+-- or (b) it is a static thunk.  This is because a static thunk needs
+-- a static link field in a predictable place (after the slop), regardless
+-- of whether it is updatable or not.
+closureNeedsUpdSpace (ClosureInfo { closureLFInfo = 
+                                       LFThunk TopLevel _ _ _ _ }) = True
+closureNeedsUpdSpace cl_info = closureUpdReqd cl_info
+
+slopSize :: ClosureInfo -> Int
+slopSize cl_info
+  = computeSlopSize (closureGoodStuffSize cl_info)
+                   (closureSMRep cl_info)
+                   (closureNeedsUpdSpace cl_info)
+
 closureGoodStuffSize :: ClosureInfo -> Int
-closureGoodStuffSize (MkClosureInfo _ _ sm_rep)
-  = let (ptrs, nonptrs) = sizes_from_SMRep sm_rep
+closureGoodStuffSize cl_info
+  = let (ptrs, nonptrs) = sizes_from_SMRep (closureSMRep cl_info)
     in ptrs + nonptrs
 
 closurePtrsSize :: ClosureInfo -> Int
-closurePtrsSize (MkClosureInfo _ _ sm_rep)
-  = let (ptrs, _) = sizes_from_SMRep sm_rep
+closurePtrsSize cl_info
+  = let (ptrs, _) = sizes_from_SMRep (closureSMRep cl_info)
     in ptrs
 
 -- not exported:
 sizes_from_SMRep :: SMRep -> (Int,Int)
-sizes_from_SMRep (GenericRep       ptrs nonptrs _)   = (ptrs, nonptrs)
-sizes_from_SMRep (StaticRep        ptrs nonptrs _)   = (ptrs, nonptrs)
-sizes_from_SMRep ConstantRep                         = (0, 0)
-sizes_from_SMRep BlackHoleRep                       = (0, 0)
+sizes_from_SMRep (GenericRep _ ptrs nonptrs _)   = (ptrs, nonptrs)
+sizes_from_SMRep BlackHoleRep                   = (0, 0)
 \end{code}
 
 Computing slop size.  WARNING: this looks dodgy --- it has deep
@@ -334,97 +351,142 @@ Static closures have an extra ``static link field'' at the end, but we
 don't bother taking that into account here.
 
 \begin{code}
-slopSize cl_info@(MkClosureInfo _ lf_info sm_rep)
-  = computeSlopSize (closureGoodStuffSize cl_info) sm_rep      
-         (closureUpdReqd cl_info)
-
 computeSlopSize :: Int -> SMRep -> Bool -> Int
 
-computeSlopSize tot_wds (StaticRep _ _ _) True         -- Updatable
+computeSlopSize tot_wds (GenericRep _ _ _ _) True              -- Updatable
   = max 0 (mIN_UPD_SIZE - tot_wds)
-computeSlopSize tot_wds (StaticRep _ _ _) False
-  = 0                                  -- non updatable, non-heap object
-computeSlopSize tot_wds (GenericRep _ _ _) True                -- Updatable
-  = max 0 (mIN_UPD_SIZE - tot_wds)
-computeSlopSize tot_wds (GenericRep _ _ _) False
-  = max 0 (mIN_SIZE_NonUpdHeapObject - tot_wds)
-computeSlopSize tot_wds ConstantRep _
-  = 0
+
+computeSlopSize tot_wds (GenericRep True _ _ _) False  -- Non updatable
+  = 0                                                  -- Static
+
+computeSlopSize tot_wds (GenericRep False _ _ _) False -- Non updatable
+  = max 0 (mIN_SIZE_NonUpdHeapObject - tot_wds)                -- Dynamic
+
 computeSlopSize tot_wds BlackHoleRep _                 -- Updatable
   = max 0 (mIN_UPD_SIZE - tot_wds)
 \end{code}
 
 %************************************************************************
 %*                                                                     *
-\subsection[layOutDynClosure]{Lay out a dynamic closure}
+\subsection[layOutDynClosure]{Lay out a closure}
 %*                                                                     *
 %************************************************************************
 
 \begin{code}
 layOutDynClosure, layOutStaticClosure
-       :: Name                     -- STG identifier of this closure
+       :: Id                       -- STG identifier of this closure
+       -> (a -> PrimRep)           -- how to get a PrimRep for the fields
+       -> [a]                      -- the "things" being layed out
+       -> LambdaFormInfo           -- what sort of closure it is
+       -> C_SRT                    -- its SRT
+       -> String                   -- closure description
+       -> (ClosureInfo,            -- info about the closure
+           [(a, VirtualHeapOffset)])   -- things w/ offsets pinned on them
+
+layOutDynClosure    = layOutClosure False
+layOutStaticClosure = layOutClosure True
+
+layOutStaticNoFVClosure id lf_info srt_info descr
+  = fst (layOutClosure True id (panic "kind_fn") [] lf_info srt_info descr)
+
+layOutClosure
+       :: Bool                     -- True <=> static closure
+       -> Id                       -- STG identifier of this closure
        -> (a -> PrimRep)           -- how to get a PrimRep for the fields
        -> [a]                      -- the "things" being layed out
        -> LambdaFormInfo           -- what sort of closure it is
+       -> C_SRT                    -- its SRT
+       -> String                   -- closure description
        -> (ClosureInfo,            -- info about the closure
            [(a, VirtualHeapOffset)])   -- things w/ offsets pinned on them
 
-layOutDynClosure name kind_fn things lf_info
-  = (MkClosureInfo name lf_info sm_rep,
+layOutClosure is_static id kind_fn things lf_info srt_info descr
+  = (ClosureInfo { closureName = name, 
+                  closureLFInfo = lf_info,
+                  closureSMRep = sm_rep, 
+                  closureSRT = srt_info,
+                  closureType = idType id,
+                  closureDescr = descr },
      things_w_offsets)
   where
+    name = idName id
     (tot_wds,           -- #ptr_wds + #nonptr_wds
      ptr_wds,           -- #ptr_wds
-     things_w_offsets) = mkVirtHeapOffsets sm_rep kind_fn things
-    sm_rep = chooseDynSMRep lf_info tot_wds ptr_wds
-\end{code}
+     things_w_offsets) = mkVirtHeapOffsets kind_fn things
+    sm_rep = chooseSMRep is_static lf_info tot_wds ptr_wds
 
-A wrapper for when used with data constructors:
 
-\begin{code}
-layOutDynCon :: DataCon
-            -> (a -> PrimRep)
-            -> [a]
-            -> (ClosureInfo, [(a,VirtualHeapOffset)])
+layOutDynConstr, layOutStaticConstr
+       :: DataCon      
+       -> (a -> PrimRep)
+       -> [a]
+       -> (ClosureInfo,
+           [(a,VirtualHeapOffset)])
+
+layOutDynConstr    = layOutConstr False
+layOutStaticConstr = layOutConstr True
 
-layOutDynCon con kind_fn args
-  = layOutDynClosure (dataConName con) kind_fn args (mkConLFInfo con)
+layOutConstr is_static data_con kind_fn args
+   = (ConInfo { closureSMRep = sm_rep,
+               closureCon = data_con },
+      things_w_offsets)
+  where
+    (tot_wds,           -- #ptr_wds + #nonptr_wds
+     ptr_wds,           -- #ptr_wds
+     things_w_offsets) = mkVirtHeapOffsets kind_fn args
+    sm_rep = chooseSMRep is_static (mkConLFInfo data_con) tot_wds ptr_wds
 \end{code}
 
 %************************************************************************
 %*                                                                     *
-\subsection[layOutStaticClosure]{Lay out a static closure}
+\subsection[mkStaticClosure]{Make a static closure}
 %*                                                                     *
 %************************************************************************
 
-layOutStaticClosure is only used for laying out static constructors at
-the moment.  
-
-Static closures for functions are laid out using
-layOutStaticNoFVClosure.
+Make a static closure, adding on any extra padding needed for CAFs,
+and adding a static link field if necessary.
 
 \begin{code}
-layOutStaticClosure name kind_fn things lf_info
-  = (MkClosureInfo name lf_info 
-       (StaticRep ptr_wds (tot_wds - ptr_wds) closure_type),
-     things_w_offsets)
-  where
-    (tot_wds,           -- #ptr_wds + #nonptr_wds
-     ptr_wds,           -- #ptr_wds
-     things_w_offsets) = mkVirtHeapOffsets (StaticRep bot bot bot) kind_fn things
-
-    -- constructors with no pointer fields will definitely be NOCAF things.
-    -- this is a compromise until we can generate both kinds of constructor
-    -- (a normal static kind and the NOCAF_STATIC kind).
-    closure_type = case lf_info of
-                       LFCon _ _ | ptr_wds == 0 -> CONSTR_NOCAF
-                       _ -> getStaticClosureType lf_info
-
-    bot = panic "layoutStaticClosure"
-
-layOutStaticNoFVClosure :: Name -> LambdaFormInfo -> ClosureInfo
-layOutStaticNoFVClosure name lf_info
-  = MkClosureInfo name lf_info (StaticRep 0 0 (getStaticClosureType lf_info))
+mkStaticClosure lbl cl_info ccs fields cafrefs
+  | opt_SccProfilingOn =
+            CStaticClosure
+               lbl
+               cl_info
+               (mkCCostCentreStack ccs)
+               all_fields
+  | otherwise =
+            CStaticClosure
+               lbl
+               cl_info
+               (panic "absent cc")
+               all_fields
+
+   where
+    all_fields = fields ++ padding_wds ++ static_link_field
+
+    upd_reqd = closureUpdReqd cl_info
+
+    -- for the purposes of laying out the static closure, we consider all
+    -- thunks to be "updatable", so that the static link field is always
+    -- in the same place.
+    padding_wds
+       | not upd_reqd = []
+       | otherwise    = replicate n (mkIntCLit 0) -- a bunch of 0s
+       where n = max 0 (mIN_UPD_SIZE - length fields)
+
+       -- We always have a static link field for a thunk, it's used to
+       -- save the closure's info pointer when we're reverting CAFs
+       -- (see comment in Storage.c)
+    static_link_field
+       | upd_reqd || staticClosureNeedsLink cl_info = [static_link_value]
+       | otherwise                                  = []
+
+       -- for a static constructor which has NoCafRefs, we set the
+       -- static link field to a non-zero value so the garbage
+       -- collector will ignore it.
+    static_link_value
+       | cafrefs       = mkIntCLit 0
+       | otherwise     = mkIntCLit 1
 \end{code}
 
 %************************************************************************
@@ -434,62 +496,33 @@ layOutStaticNoFVClosure name lf_info
 %************************************************************************
 
 \begin{code}
-chooseDynSMRep
-       :: LambdaFormInfo
+chooseSMRep
+       :: Bool                 -- True <=> static closure
+       -> LambdaFormInfo
        -> Int -> Int           -- Tot wds, ptr wds
        -> SMRep
 
-chooseDynSMRep lf_info tot_wds ptr_wds
+chooseSMRep is_static lf_info tot_wds ptr_wds
   = let
-        nonptr_wds = tot_wds - ptr_wds
-        closure_type = getClosureType tot_wds ptr_wds nonptr_wds lf_info
+        nonptr_wds   = tot_wds - ptr_wds
+        closure_type = getClosureType is_static tot_wds ptr_wds lf_info
     in
-    case lf_info of
-       LFTuple _ True -> ConstantRep
-       LFCon _ True   -> ConstantRep
-       _              -> GenericRep ptr_wds nonptr_wds closure_type    
-
-getStaticClosureType :: LambdaFormInfo -> ClosureType
-getStaticClosureType lf_info =
-    case lf_info of
-        LFCon con True            -> CONSTR_NOCAF
-       LFCon con False           -> CONSTR
-       LFReEntrant _ _ _ _ _ _   -> FUN
-       LFTuple _ _               -> CONSTR
-       LFThunk _ _ _ _ (SelectorThunk _) _ _ -> THUNK_SELECTOR
-       LFThunk _ _ _ True  _ _ _ -> THUNK
-       LFThunk _ _ _ False _ _ _ -> FUN
-       _                         -> panic "getClosureType"
+    GenericRep is_static ptr_wds nonptr_wds closure_type       
 
 -- we *do* get non-updatable top-level thunks sometimes.  eg. f = g
 -- gets compiled to a jump to g (if g has non-zero arity), instead of
 -- messing around with update frames and PAPs.  We set the closure type
 -- to FUN_STATIC in this case.
 
-getClosureType :: Int -> Int -> Int -> LambdaFormInfo -> ClosureType
-getClosureType tot_wds ptrs nptrs lf_info =
-    case lf_info of
-        LFCon con True       -> CONSTR_NOCAF
-
-       LFCon con False 
-               | tot_wds > 0 && tot_wds <= mAX_SPEC_CONSTR_SIZE -> CONSTR_p_n ptrs nptrs
-               | otherwise -> CONSTR
-
-       LFReEntrant _ _ _ _ _ _
-               | tot_wds > 0 && tot_wds <= mAX_SPEC_FUN_SIZE -> FUN_p_n ptrs nptrs
-               | otherwise -> FUN
-
-       LFTuple _ _
-               | tot_wds > 0 && tot_wds <= mAX_SPEC_CONSTR_SIZE -> CONSTR_p_n ptrs nptrs
-               | otherwise -> CONSTR
-
-       LFThunk _ _ _ _ (SelectorThunk _) _ _ -> THUNK_SELECTOR
-
-       LFThunk _ _ _ _ _ _ _
-               | tot_wds > 0 && tot_wds <= mAX_SPEC_THUNK_SIZE -> THUNK_p_n ptrs nptrs
-               | otherwise -> THUNK
-
-       _                    -> panic "getClosureType"
+getClosureType :: Bool -> Int -> Int -> LambdaFormInfo -> ClosureType
+getClosureType is_static tot_wds ptr_wds lf_info
+  = case lf_info of
+       LFCon con | is_static && ptr_wds == 0   -> ConstrNoCaf
+                 | otherwise                   -> Constr
+       LFReEntrant _ _ _ _                     -> Fun
+       LFThunk _ _ _ (SelectorThunk _) _       -> ThunkSelector
+       LFThunk _ _ _ _ _                       -> Thunk
+       _ -> panic "getClosureType"
 \end{code}
 
 %************************************************************************
@@ -503,8 +536,8 @@ smaller offsets than the unboxed things, and furthermore, the offsets in
 the result list
 
 \begin{code}
-mkVirtHeapOffsets :: SMRep     -- Representation to be used by storage manager
-         -> (a -> PrimRep)     -- To be able to grab kinds;
+mkVirtHeapOffsets :: 
+         (a -> PrimRep)        -- To be able to grab kinds;
                                --      w/ a kind, we can find boxedness
          -> [a]                -- Things to make offsets for
          -> (Int,              -- *Total* number of words allocated
@@ -515,7 +548,7 @@ mkVirtHeapOffsets :: SMRep  -- Representation to be used by storage manager
 
 -- First in list gets lowest offset, which is initial offset + 1.
 
-mkVirtHeapOffsets sm_rep kind_fun things
+mkVirtHeapOffsets kind_fun things
   = let (ptrs, non_ptrs)             = separateByPtrFollowness kind_fun things
        (wds_of_ptrs, ptrs_w_offsets) = mapAccumL computeOffset 0 ptrs
        (tot_wds, non_ptrs_w_offsets) = mapAccumL computeOffset wds_of_ptrs non_ptrs
@@ -541,7 +574,7 @@ nodeMustPointToIt :: LambdaFormInfo -> FCode Bool
 nodeMustPointToIt lf_info
 
   = case lf_info of
-       LFReEntrant ty top arity no_fvs _ _ -> returnFC (
+       LFReEntrant top _ no_fvs _ -> returnFC (
            not no_fvs ||   -- Certainly if it has fvs we need to point to it
            isNotTopLevel top
                    -- If it is not top level we will point to it
@@ -554,8 +587,7 @@ nodeMustPointToIt lf_info
                -- the  not top  case above ensures this is ok.
            )
 
-       LFCon   _ zero_arity -> returnFC True
-       LFTuple _ zero_arity -> returnFC True
+       LFCon _ -> returnFC True
 
        -- Strictly speaking, the above two don't need Node to point
        -- to it if the arity = 0.  But this is a *really* unlikely
@@ -568,7 +600,7 @@ nodeMustPointToIt lf_info
        -- having Node point to the result of an update.  SLPJ
        -- 27/11/92.
 
-       LFThunk _ _ no_fvs updatable NonStandardThunk _ _
+       LFThunk _ no_fvs updatable NonStandardThunk _
          -> returnFC (updatable || not no_fvs || opt_SccProfilingOn)
 
          -- For the non-updatable (single-entry case):
@@ -578,12 +610,11 @@ nodeMustPointToIt lf_info
          -- or profiling (in which case we need to recover the cost centre
          --             from inside it)
 
-       LFThunk _ _ no_fvs updatable some_standard_form_thunk _ _
+       LFThunk _ no_fvs updatable some_standard_form_thunk _
          -> returnFC True
          -- Node must point to any standard-form thunk.
 
-       LFArgument    -> returnFC True
-       LFImported    -> returnFC True
+       LFUnknown _   -> returnFC True
        LFBlackHole _ -> returnFC True
                    -- BH entry may require Node to point
 
@@ -619,10 +650,18 @@ When black-holing, single-entry closures could also be entered via node
 (rather than directly) to catch double-entry.
 
 \begin{code}
-data EntryConvention
-  = ViaNode                            -- The "normal" convention
+data CallingConvention
+  = EnterIt                            -- no args, not a function
+
+  | JumpToIt CLabel                    -- no args, not a function, but we
+                                       -- know what its entry code is
+
+  | ReturnIt                           -- it's a function, but we have
+                                       -- zero args to apply to it, so just
+                                       -- return it.
 
-  | StdEntry CLabel                    -- Jump to this code, with args on stack
+  | SlowCall                           -- Unknown fun, or known fun with
+                                       -- too few args.
 
   | DirectEntry                        -- Jump directly, with args in regs
        CLabel                          --   The code label
@@ -633,7 +672,7 @@ data EntryConvention
 getEntryConvention :: Name             -- Function being applied
                   -> LambdaFormInfo    -- Its info
                   -> [PrimRep]         -- Available arguments
-                  -> FCode EntryConvention
+                  -> FCode CallingConvention
 
 getEntryConvention name lf_info arg_kinds
  =  nodeMustPointToIt lf_info  `thenFC` \ node_points ->
@@ -642,7 +681,7 @@ getEntryConvention name lf_info arg_kinds
     -- if we're parallel, then we must always enter via node.  The reason
     -- is that the closure may have been fetched since we allocated it.
 
-    if (node_points && opt_Parallel) then ViaNode else
+    if (node_points && opt_Parallel) then EnterIt else
 
     -- Commented out by SDM after futher thoughts:
     --   - the only closure type that can be blackholed is a thunk
@@ -651,48 +690,57 @@ getEntryConvention name lf_info arg_kinds
 
     case lf_info of
 
-       LFReEntrant _ _ arity _ _ _ ->
-           if arity == 0 || (length arg_kinds) < arity then
-               StdEntry (mkStdEntryLabel name)
+       LFReEntrant _ arity _ _ ->
+           if null arg_kinds then
+               if arity == 0 then
+                  EnterIt              -- a non-updatable thunk
+               else 
+                  ReturnIt             -- no args at all
+           else if listLengthCmp arg_kinds arity == LT then
+               SlowCall                -- not enough args
            else
-               DirectEntry (mkFastEntryLabel name arity) arity arg_regs
+               DirectEntry (mkEntryLabel name) arity arg_regs
          where
-           (arg_regs, _) = assignRegs live_regs (take arity arg_kinds)
-           live_regs = if node_points then [node] else []
+           (arg_regs, _) = assignRegs [node] (take arity arg_kinds)
+               -- we don't use node to pass args now (SDM)
 
-       LFCon con True{-zero_arity-}
+       LFCon con
+           | isNullaryDataCon con
              -- a real constructor.  Don't bother entering it, just jump
              -- to the constructor entry code directly.
                          -> --false:ASSERT (null arg_kinds)    
                             -- Should have no args (meaning what?)
-                            StdEntry (mkStaticConEntryLabel (dataConName con))
+                            JumpToIt (mkStaticConEntryLabel (dataConName con))
 
-       LFCon con False{-non-zero_arity-}
+            | otherwise {- not nullary -}
                          -> --false:ASSERT (null arg_kinds)    
                             -- Should have no args (meaning what?)
-                            StdEntry (mkConEntryLabel (dataConName con))
-
-       LFTuple tup zero_arity
-                         -> --false:ASSERT (null arg_kinds)    
-                            -- Should have no args (meaning what?)
-                            StdEntry (mkConEntryLabel (dataConName tup))
-
-       LFThunk _ _ _ updatable std_form_info _ _
-         -> if updatable || opt_DoTickyProfiling  -- to catch double entry
-            then ViaNode
-             else StdEntry (thunkEntryLabel name std_form_info updatable)
-
-       LFArgument    -> ViaNode
-       LFImported    -> ViaNode
-       LFBlackHole _ -> ViaNode -- Presumably the black hole has by now
-                                -- been updated, but we don't know with
-                                -- what, so we enter via Node
+                            JumpToIt (mkConEntryLabel (dataConName con))
+
+       LFThunk _ _ updatable std_form_info is_fun
+         -- must always "call" a function-typed thing, cannot just enter it
+         | is_fun -> SlowCall
+         | updatable || opt_DoTickyProfiling  -- to catch double entry
+               || opt_SMP  -- always enter via node on SMP, since the
+                           -- thunk might have been blackholed in the 
+                           -- meantime.
+            -> ASSERT(null arg_kinds) EnterIt
+         | otherwise
+            -> ASSERT(null arg_kinds) 
+               JumpToIt (thunkEntryLabel name std_form_info updatable)
+
+       LFUnknown True  -> SlowCall -- might be a function
+       LFUnknown False -> ASSERT2 (null arg_kinds, ppr name <+> ppr arg_kinds) EnterIt -- not a function
+
+       LFBlackHole _ -> SlowCall -- Presumably the black hole has by now
+                                 -- been updated, but we don't know with
+                                 -- what, so we slow call it
 
        LFLetNoEscape 0
-         -> StdEntry (mkReturnPtLabel (nameUnique name))
+         -> JumpToIt (mkReturnPtLabel (nameUnique name))
 
        LFLetNoEscape arity
-         -> ASSERT(arity == length arg_kinds)
+         -> if (not (arg_kinds `lengthIs` arity)) then pprPanic "let-no-escape: " (ppr name <+> ppr arity) else
             DirectEntry (mkReturnPtLabel (nameUnique name)) arity arg_regs
         where
            (arg_regs, _) = assignRegs [] arg_kinds
@@ -708,13 +756,16 @@ blackHoleOnEntry :: ClosureInfo -> Bool
 -- Single-entry ones have no fvs to plug, and we trust they don't form part 
 -- of a loop.
 
-blackHoleOnEntry (MkClosureInfo _ _ (StaticRep _ _ _)) = False
+blackHoleOnEntry ConInfo{} = False
+blackHoleOnEntry (ClosureInfo { closureLFInfo = lf_info, closureSMRep = rep })
+  | isStaticRep rep
+  = False      -- Never black-hole a static closure
 
-blackHoleOnEntry (MkClosureInfo _ lf_info _)
+  | otherwise
   = case lf_info of
-       LFReEntrant _ _ _ _ _ _   -> False
+       LFReEntrant _ _ _ _       -> False
        LFLetNoEscape _           -> False
-       LFThunk _ _ no_fvs updatable _ _ _
+       LFThunk _ no_fvs updatable _ _
          -> if updatable
             then not opt_OmitBlackHoling
             else opt_DoTickyProfiling || not no_fvs
@@ -725,45 +776,32 @@ blackHoleOnEntry (MkClosureInfo _ lf_info _)
 
 isStandardFormThunk :: LambdaFormInfo -> Bool
 
-isStandardFormThunk (LFThunk _ _ _ _ (SelectorThunk _) _ _) = True
-isStandardFormThunk (LFThunk _ _ _ _ (ApThunk _) _ _)      = True
-isStandardFormThunk other_lf_info                          = False
+isStandardFormThunk (LFThunk _ _ _ (SelectorThunk _) _) = True
+isStandardFormThunk (LFThunk _ _ _ (ApThunk _) _)      = True
+isStandardFormThunk other_lf_info                      = False
 
-maybeSelectorInfo (MkClosureInfo _ (LFThunk _ _ _ _
-                       (SelectorThunk offset) _ _) _) = Just offset
-maybeSelectorInfo _ = Nothing
 \end{code}
 
 -----------------------------------------------------------------------------
 SRT-related stuff
 
-
 \begin{code}
-infoTblNeedsSRT :: ClosureInfo -> Bool
-infoTblNeedsSRT (MkClosureInfo _ info _) =
-  case info of
-    LFThunk _ _ _ _ _ _ NoSRT   -> False
-    LFThunk _ _ _ _ _ _ _       -> True
-
-    LFReEntrant _ _ _ _ _ NoSRT -> False
-    LFReEntrant _ _ _ _ _ _     -> True
-
-    _ -> False
-
 staticClosureNeedsLink :: ClosureInfo -> Bool
-staticClosureNeedsLink (MkClosureInfo _ info _) =
-  case info of
-    LFThunk _ _ _ _ _ _ NoSRT   -> False
-    LFReEntrant _ _ _ _ _ NoSRT -> False
-    LFCon _ True                -> False -- zero arity constructors
-    _ -> True
-
-getSRTInfo :: ClosureInfo -> (CLabel, SRT)
-getSRTInfo  (MkClosureInfo _ info _) =
-  case info of
-    LFThunk _ _ _ _ _ lbl srt   -> (lbl,srt)
-    LFReEntrant _ _ _ _ lbl srt -> (lbl,srt)
-    _ -> panic "getSRTInfo"
+-- A static closure needs a link field to aid the GC when traversing
+-- the static closure graph.  But it only needs such a field if either
+--     a) it has an SRT
+--     b) it's a constructor with one or more pointer fields
+-- In case (b), the constructor's fields themselves play the role
+-- of the SRT.
+staticClosureNeedsLink (ClosureInfo { closureSRT = srt })
+  = needsSRT srt
+staticClosureNeedsLink (ConInfo { closureSMRep = sm_rep, closureCon = con })
+  = not (isNullaryDataCon con) && not_nocaf_constr
+  where
+    not_nocaf_constr = 
+       case sm_rep of 
+          GenericRep _ _ _ ConstrNoCaf -> False
+          _other                       -> True
 \end{code}
 
 Avoiding generating entries and info tables
@@ -833,44 +871,13 @@ staticClosureRequired
        -> StgBinderInfo
        -> LambdaFormInfo
        -> Bool
-staticClosureRequired binder (StgBinderInfo arg_occ unsat_occ _ _ _)
-                     (LFReEntrant _ top_level _ _ _ _) -- It's a function
+staticClosureRequired binder bndr_info
+                     (LFReEntrant top_level _ _ _)     -- It's a function
   = ASSERT( isTopLevel top_level )
        -- Assumption: it's a top-level, no-free-var binding
-    arg_occ            -- There's an argument occurrence
-    || unsat_occ       -- There's an unsaturated call
-    || isExternallyVisibleName binder
+       not (satCallsOnly bndr_info)
 
 staticClosureRequired binder other_binder_info other_lf_info = True
-
-slowFunEntryCodeRequired       -- Assumption: it's a function, not a thunk.
-       :: Name
-       -> StgBinderInfo
-       -> EntryConvention
-       -> Bool
-slowFunEntryCodeRequired binder (StgBinderInfo arg_occ unsat_occ _ _ _) entry_conv
-  = arg_occ            -- There's an argument occurrence
-    || unsat_occ       -- There's an unsaturated call
-    || isExternallyVisibleName binder
-    || (case entry_conv of { DirectEntry _ _ _ -> False; other -> True })
-           {- The last case deals with the parallel world; a function usually
-              as a DirectEntry convention, but if it doesn't we must generate slow-entry code -}
-
-slowFunEntryCodeRequired binder NoStgBinderInfo _ = True
-
-funInfoTableRequired
-       :: Name
-       -> StgBinderInfo
-       -> LambdaFormInfo
-       -> Bool
-funInfoTableRequired  binder (StgBinderInfo arg_occ unsat_occ _ _ _)
-                    (LFReEntrant _ top_level _ _ _ _)
-  =    isNotTopLevel top_level
-    || arg_occ                 -- There's an argument occurrence
-    || unsat_occ       -- There's an unsaturated call
-    || isExternallyVisibleName binder
-
-funInfoTableRequired other_binder_info binder other_lf_info = True
 \end{code}
 
 %************************************************************************
@@ -882,117 +889,99 @@ funInfoTableRequired other_binder_info binder other_lf_info = True
 \begin{code}
 
 isStaticClosure :: ClosureInfo -> Bool
-isStaticClosure  (MkClosureInfo _ _ rep) = isStaticRep  rep
-
-closureName :: ClosureInfo -> Name
-closureName (MkClosureInfo name _ _) = name
-
-closureSMRep :: ClosureInfo -> SMRep
-closureSMRep (MkClosureInfo _ _ sm_rep) = sm_rep
-
-closureLFInfo :: ClosureInfo -> LambdaFormInfo
-closureLFInfo (MkClosureInfo _ lf_info _) = lf_info
+isStaticClosure cl_info = isStaticRep (closureSMRep cl_info)
 
 closureUpdReqd :: ClosureInfo -> Bool
-closureUpdReqd (MkClosureInfo _ (LFThunk _ _ _ upd _ _ _) _) = upd
-closureUpdReqd (MkClosureInfo _ (LFBlackHole _) _)           = True
+closureUpdReqd (ClosureInfo { closureLFInfo = LFThunk _ _ upd _ _ }) = upd
+closureUpdReqd (ClosureInfo { closureLFInfo = LFBlackHole _ })     = True
        -- Black-hole closures are allocated to receive the results of an
        -- alg case with a named default... so they need to be updated.
-closureUpdReqd other_closure                          = False
+closureUpdReqd other_closure = False
 
 closureSingleEntry :: ClosureInfo -> Bool
-closureSingleEntry (MkClosureInfo _ (LFThunk _ _ _ upd _ _ _) _) = not upd
-closureSingleEntry other_closure                          = False
+closureSingleEntry (ClosureInfo { closureLFInfo = LFThunk _ _ upd _ _}) = not upd
+closureSingleEntry other_closure = False
 
 closureReEntrant :: ClosureInfo -> Bool
-closureReEntrant (MkClosureInfo _ (LFReEntrant _ _ _ _ _ _) _) = True
+closureReEntrant (ClosureInfo { closureLFInfo = LFReEntrant _ _ _ _ }) = True
 closureReEntrant other_closure = False
-\end{code}
 
-\begin{code}
 closureSemiTag :: ClosureInfo -> Maybe Int
-closureSemiTag (MkClosureInfo _ lf_info _)
-  = case lf_info of
-      LFCon data_con _ -> Just (dataConTag data_con - fIRST_TAG)
-      LFTuple _ _      -> Just 0
-      _                       -> Nothing
+closureSemiTag (ConInfo { closureCon = data_con })
+      = Just (dataConTag data_con - fIRST_TAG)
+closureSemiTag _ = Nothing
+
+closureFunInfo :: ClosureInfo -> Maybe (Int, ArgDescr)
+closureFunInfo (ClosureInfo { closureLFInfo = LFReEntrant _ arity _ arg_desc})
+  = Just (arity, arg_desc)
+closureFunInfo _
+  = Nothing
 \end{code}
 
 \begin{code}
 isToplevClosure :: ClosureInfo -> Bool
-
-isToplevClosure (MkClosureInfo _ lf_info _)
+isToplevClosure (ClosureInfo { closureLFInfo = lf_info })
   = case lf_info of
-      LFReEntrant _ TopLevel _ _ _ _ -> True
-      LFThunk _ TopLevel _ _ _ _ _   -> True
+      LFReEntrant TopLevel _ _ _ -> True
+      LFThunk TopLevel _ _ _ _   -> True
       other -> False
-\end{code}
-
-\begin{code}
-isLetNoEscape :: ClosureInfo -> Bool
-
-isLetNoEscape (MkClosureInfo _ (LFLetNoEscape _) _) = True
-isLetNoEscape _ = False
+isToplevClosure _ = False
 \end{code}
 
 Label generation.
 
 \begin{code}
-fastLabelFromCI :: ClosureInfo -> CLabel
-fastLabelFromCI (MkClosureInfo name (LFReEntrant _ _ arity _ _ _) _)
-  = mkFastEntryLabel name arity
-
-fastLabelFromCI (MkClosureInfo name _ _)
-  = pprPanic "fastLabelFromCI" (ppr name)
-
 infoTableLabelFromCI :: ClosureInfo -> CLabel
-infoTableLabelFromCI (MkClosureInfo id lf_info rep)
+infoTableLabelFromCI (ClosureInfo { closureName = name,
+                                   closureLFInfo = lf_info, 
+                                   closureSMRep = rep })
   = case lf_info of
-       LFCon con _      -> mkConInfoPtr con rep
-       LFTuple tup _    -> mkConInfoPtr tup rep
-
        LFBlackHole info -> info
 
-       LFThunk _ _ _ upd_flag (SelectorThunk offset) _ _ -> 
+       LFThunk _ _ upd_flag (SelectorThunk offset) _ -> 
                mkSelectorInfoLabel upd_flag offset
 
-       LFThunk _ _ _ upd_flag (ApThunk arity) _ _ -> 
+       LFThunk _ _ upd_flag (ApThunk arity) _ -> 
                mkApInfoTableLabel upd_flag arity
 
-       other -> {-NO: if isStaticRep rep
-                then mkStaticInfoTableLabel id
-                else -} mkInfoTableLabel id
+       LFThunk{}      -> mkInfoTableLabel name
+
+       LFReEntrant _ _ _ (ArgGen _ _) -> mkInfoTableLabel name
+       LFReEntrant _ _ _ _             -> mkInfoTableLabel name
+
+       other -> panic "infoTableLabelFromCI"
+
+infoTableLabelFromCI (ConInfo { closureCon = con, closureSMRep = rep })
+  =  mkConInfoPtr con rep
+
 
 mkConInfoPtr :: DataCon -> SMRep -> CLabel
 mkConInfoPtr con rep
-  = case rep of
-      StaticRep _ _ _ -> mkStaticInfoTableLabel  name
-      _                      -> mkConInfoTableLabel     name
+  | isStaticRep rep = mkStaticInfoTableLabel  name
+  | otherwise      = mkConInfoTableLabel     name
   where
     name = dataConName con
 
 mkConEntryPtr :: DataCon -> SMRep -> CLabel
 mkConEntryPtr con rep
-  = case rep of
-      StaticRep _ _ _ -> mkStaticConEntryLabel (dataConName con)
-      _                      -> mkConEntryLabel       (dataConName con)
-  where
-    name = dataConName con
+  | isStaticRep rep = mkStaticConEntryLabel (dataConName con)
+  | otherwise       = mkConEntryLabel       (dataConName con)
 
-closureLabelFromCI (MkClosureInfo name _ rep) 
-       | isConstantRep rep
-       = mkStaticClosureLabel name
-       -- This case catches those pesky static closures for nullary constructors
-
-closureLabelFromCI (MkClosureInfo id _ other_rep)   = mkClosureLabel id
+closureLabelFromCI (ClosureInfo { closureName = nm }) = mkClosureLabel nm
+closureLabelFromCI _ = panic "closureLabelFromCI"
 
 entryLabelFromCI :: ClosureInfo -> CLabel
-entryLabelFromCI (MkClosureInfo id lf_info rep)
+entryLabelFromCI (ClosureInfo { closureName = id, 
+                               closureLFInfo = lf_info, 
+                               closureSMRep = rep })
   = case lf_info of
-       LFThunk _ _ _ upd_flag std_form_info _ _ -> thunkEntryLabel id std_form_info upd_flag
-       LFCon con _                          -> mkConEntryPtr con rep
-       LFTuple tup _                        -> mkConEntryPtr tup rep
-       other                                -> mkStdEntryLabel id
+       LFThunk _ _ upd_flag std_form_info _ -> 
+               thunkEntryLabel id std_form_info upd_flag
+       other -> mkEntryLabel id
+
+entryLabelFromCI (ConInfo { closureCon = con, closureSMRep = rep })
+  = mkConEntryPtr con rep
+
 
 -- thunkEntryLabel is a local help function, not exported.  It's used from both
 -- entryLabelFromCI and getEntryConvention.
@@ -1002,21 +991,19 @@ thunkEntryLabel thunk_id (ApThunk arity) is_updatable
 thunkEntryLabel thunk_id (SelectorThunk offset) upd_flag
   = mkSelectorEntryLabel upd_flag offset
 thunkEntryLabel thunk_id _ is_updatable
-  = mkStdEntryLabel thunk_id
+  = mkEntryLabel thunk_id
 \end{code}
 
 \begin{code}
-allocProfilingMsg :: ClosureInfo -> FAST_STRING
-
-allocProfilingMsg (MkClosureInfo _ lf_info _)
+allocProfilingMsg :: ClosureInfo -> FastString
+allocProfilingMsg ConInfo{} = FSLIT("TICK_ALLOC_CON")
+allocProfilingMsg ClosureInfo{ closureLFInfo = lf_info }
   = case lf_info of
-      LFReEntrant _ _ _ _ _ _  -> SLIT("TICK_ALLOC_FUN")
-      LFCon _ _                        -> SLIT("TICK_ALLOC_CON")
-      LFTuple _ _              -> SLIT("TICK_ALLOC_CON")
-      LFThunk _ _ _ True _ _ _  -> SLIT("TICK_ALLOC_UP_THK")  -- updatable
-      LFThunk _ _ _ False _ _ _ -> SLIT("TICK_ALLOC_SE_THK")  -- nonupdatable
-      LFBlackHole _            -> SLIT("TICK_ALLOC_BH")
-      LFImported               -> panic "TICK_ALLOC_IMP"
+      LFReEntrant _ _ _ _   -> FSLIT("TICK_ALLOC_FUN")
+      LFThunk _ _ True _ _  -> FSLIT("TICK_ALLOC_UP_THK")  -- updatable
+      LFThunk _ _ False _ _ -> FSLIT("TICK_ALLOC_SE_THK")  -- nonupdatable
+      LFBlackHole _        -> FSLIT("TICK_ALLOC_BH")
+      _                            -> panic "allocProfilingMsg"
 \end{code}
 
 We need a black-hole closure info to pass to @allocDynClosure@ when we
@@ -1025,11 +1012,25 @@ ways to build an LFBlackHole, maintaining the invariant that it really
 is a black hole and not something else.
 
 \begin{code}
-cafBlackHoleClosureInfo (MkClosureInfo name _ _)
-  = MkClosureInfo name (LFBlackHole mkCAFBlackHoleInfoTableLabel) BlackHoleRep
-
-seCafBlackHoleClosureInfo (MkClosureInfo name _ _)
-  = MkClosureInfo name (LFBlackHole mkSECAFBlackHoleInfoTableLabel) BlackHoleRep
+cafBlackHoleClosureInfo (ClosureInfo { closureName = nm,
+                                      closureType = ty })
+  = ClosureInfo { closureName   = nm,
+                 closureLFInfo = LFBlackHole mkCAFBlackHoleInfoTableLabel,
+                 closureSMRep  = BlackHoleRep,
+                 closureSRT    = NoC_SRT,
+                 closureType   = ty,
+                 closureDescr  = "" }
+cafBlackHoleClosureInfo _ = panic "cafBlackHoleClosureInfo"
+
+seCafBlackHoleClosureInfo (ClosureInfo { closureName = nm,
+                                        closureType = ty })
+  = ClosureInfo { closureName   = nm,
+                 closureLFInfo = LFBlackHole mkSECAFBlackHoleInfoTableLabel,
+                 closureSMRep  = BlackHoleRep,
+                 closureSRT    = NoC_SRT,
+                 closureType   = ty,
+                 closureDescr  = ""  }
+seCafBlackHoleClosureInfo _ = panic "seCafBlackHoleClosureInfo"
 \end{code}
 
 %************************************************************************
@@ -1049,11 +1050,295 @@ in the closure info using @closureTypeDescr@.
 
 \begin{code}
 closureTypeDescr :: ClosureInfo -> String
-closureTypeDescr (MkClosureInfo name (LFThunk ty _ _ _ _ _ _) _)
-  = getTyDescription ty
-closureTypeDescr (MkClosureInfo name (LFReEntrant ty _ _ _ _ _) _)
+closureTypeDescr (ClosureInfo { closureType = ty })
   = getTyDescription ty
-closureTypeDescr (MkClosureInfo name lf _)
-  = showSDoc (ppr name)
+closureTypeDescr (ConInfo { closureCon = data_con })
+  = occNameUserString (getOccName (dataConTyCon data_con))
+
+getTyDescription :: Type -> String
+getTyDescription ty
+  = case (tcSplitSigmaTy ty) of { (_, _, tau_ty) ->
+    case tau_ty of
+      TyVarTy _                     -> "*"
+      AppTy fun _                   -> getTyDescription fun
+      FunTy _ res                   -> '-' : '>' : fun_result res
+      NewTcApp tycon _              -> getOccString tycon
+      TyConApp tycon _              -> getOccString tycon
+      NoteTy (FTVNote _) ty  -> getTyDescription ty
+      NoteTy (SynNote ty1) _ -> getTyDescription ty1
+      PredTy sty            -> getPredTyDescription sty
+      ForAllTy _ ty          -> getTyDescription ty
+    }
+  where
+    fun_result (FunTy _ res) = '>' : fun_result res
+    fun_result other        = getTyDescription other
+
+getPredTyDescription (ClassP cl tys) = getOccString cl
+getPredTyDescription (IParam ip ty)  = getOccString (ipNameName ip)
 \end{code}
 
+%************************************************************************
+%*                                                                     *
+\subsection{Making argument bitmaps}
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+-- bring in ARG_P, ARG_N, etc.
+#include "../includes/StgFun.h"
+
+data ArgDescr
+  = ArgSpec
+       !Int            -- ARG_P, ARG_N, ...
+  | ArgGen 
+       CLabel          -- label for a slow-entry point
+       Liveness        -- the arg bitmap: describes pointedness of arguments
+
+mkArgDescr :: Name -> [Id] -> ArgDescr
+mkArgDescr nm args = argDescr nm (filter nonVoidRep (map idPrimRep args))
+  where nonVoidRep VoidRep = False
+       nonVoidRep _ = True
+
+argDescr nm [PtrRep]    = ArgSpec ARG_P
+argDescr nm [FloatRep]  = ArgSpec ARG_F
+argDescr nm [DoubleRep] = ArgSpec ARG_D
+argDescr nm [r] | is64BitRep r  = ArgSpec ARG_L
+argDescr nm [r] | isNonPtrRep r = ArgSpec ARG_N
+
+argDescr nm [r1,r2] | isNonPtrRep r1 && isNonPtrRep r2 = ArgSpec ARG_NN
+argDescr nm [r1,PtrRep] | isNonPtrRep r1 = ArgSpec ARG_NP
+argDescr nm [PtrRep,r1] | isNonPtrRep r1 = ArgSpec ARG_PN
+argDescr nm [PtrRep,PtrRep] = ArgSpec ARG_PP
+
+argDescr nm [r1,r2,r3] | isNonPtrRep r1 && isNonPtrRep r2 && isNonPtrRep r3 = ArgSpec ARG_NNN
+argDescr nm [r1,r2,PtrRep] | isNonPtrRep r1 && isNonPtrRep r2 = ArgSpec ARG_NNP
+argDescr nm [r1,PtrRep,r2] | isNonPtrRep r1 && isNonPtrRep r2 = ArgSpec ARG_NPN
+argDescr nm [r1,PtrRep,PtrRep] | isNonPtrRep r1 = ArgSpec ARG_NPP
+argDescr nm [PtrRep,r1,r2] | isNonPtrRep r1 && isNonPtrRep r2 = ArgSpec ARG_PNN
+argDescr nm [PtrRep,r1,PtrRep] | isNonPtrRep r1 = ArgSpec ARG_PNP
+argDescr nm [PtrRep,PtrRep,r1] | isNonPtrRep r1 = ArgSpec ARG_PPN
+argDescr nm [PtrRep,PtrRep,PtrRep] = ArgSpec ARG_PPP
+
+argDescr nm [PtrRep,PtrRep,PtrRep,PtrRep] = ArgSpec ARG_PPPP
+argDescr nm [PtrRep,PtrRep,PtrRep,PtrRep,PtrRep] = ArgSpec ARG_PPPPP
+argDescr nm [PtrRep,PtrRep,PtrRep,PtrRep,PtrRep,PtrRep] = ArgSpec ARG_PPPPPP
+
+argDescr name reps = ArgGen (mkSlowEntryLabel name) liveness
+ where bitmap = argBits reps
+       lbl = mkBitmapLabel name
+       liveness = Liveness lbl (length bitmap) (mkBitmap bitmap) 
+
+argBits [] = []
+argBits (rep : args)
+  | isFollowableRep rep = False : argBits args
+  | otherwise = take (getPrimRepSize rep) (repeat True) ++ argBits args
+\end{code}
+
+
+%************************************************************************
+%*                                                                     *
+\subsection{Generating info tables}
+%*                                                                     *
+%************************************************************************
+
+Here we make a concrete info table, represented as a list of CAddrMode
+(it can't be simply a list of Word, because the SRT field is
+represented by a label+offset expression).
+
+\begin{code}
+mkInfoTable :: ClosureInfo -> [CAddrMode]
+mkInfoTable cl_info
+ | tablesNextToCode = extra_bits ++ std_info
+ | otherwise        = std_info ++ extra_bits
+ where
+    std_info = mkStdInfoTable entry_amode
+                 ty_descr_amode cl_descr_amode cl_type srt_len layout_amode
+
+    entry_amode = CLbl (entryLabelFromCI cl_info) CodePtrRep 
+
+    closure_descr = 
+       case cl_info of
+         ClosureInfo { closureDescr = descr } -> descr
+         ConInfo { closureCon = con } -> occNameUserString (getOccName con)
+
+    ty_descr_amode = CLit (MachStr (mkFastString (closureTypeDescr cl_info)))
+    cl_descr_amode = CLit (MachStr (mkFastString closure_descr))
+
+    cl_type = getSMRepClosureTypeInt (closureSMRep cl_info)
+
+    srt = closureSRT cl_info        
+    needs_srt = needsSRT srt
+
+    semi_tag = closureSemiTag cl_info
+    is_con = isJust semi_tag
+
+    (srt_label,srt_len)
+       | Just tag <- semi_tag = (mkIntCLit 0, fromIntegral tag) -- constructor
+       | otherwise = 
+         case srt of
+           NoC_SRT -> (mkIntCLit 0, 0)
+           C_SRT lbl off bitmap -> 
+             (CAddr (CIndex (CLbl lbl DataPtrRep) (mkIntCLit off) WordRep),
+              bitmap)
+
+    ptrs  = closurePtrsSize cl_info
+    nptrs = size - ptrs
+    size  = closureNonHdrSize cl_info
+
+    layout_info :: StgWord
+#ifdef WORDS_BIGENDIAN
+    layout_info = (fromIntegral ptrs `shiftL` hALF_WORD) .|. fromIntegral nptrs
+#else 
+    layout_info = (fromIntegral ptrs) .|. (fromIntegral nptrs `shiftL` hALF_WORD)
+#endif      
+
+    layout_amode = mkWordCLit layout_info
+
+    extra_bits
+       | is_fun    = fun_extra_bits
+       | is_con    = []
+       | needs_srt = [srt_label]
+       | otherwise = []
+
+    maybe_fun_stuff = closureFunInfo cl_info
+    is_fun = isJust maybe_fun_stuff
+    (Just (arity, arg_descr)) = maybe_fun_stuff
+
+    fun_extra_bits
+       | tablesNextToCode = reg_fun_extra_bits
+       | otherwise        = reverse reg_fun_extra_bits
+
+    reg_fun_extra_bits
+       | ArgGen slow_lbl liveness <- arg_descr
+               = [
+                  CLbl slow_lbl CodePtrRep, 
+                  livenessToAddrMode liveness,
+                  srt_label,
+                  fun_amode
+                 ]
+       | needs_srt = [srt_label, fun_amode]
+       | otherwise = [fun_amode]
+
+#ifdef WORDS_BIGENDIAN
+    fun_desc = (fromIntegral fun_type `shiftL` hALF_WORD) .|. fromIntegral arity
+#else 
+    fun_desc = (fromIntegral fun_type) .|. (fromIntegral arity `shiftL` hALF_WORD)
+#endif
+
+    fun_amode = mkWordCLit fun_desc
+
+    fun_type = case arg_descr of
+               ArgSpec n -> n
+               ArgGen _ (Liveness _ size _)
+                       | size <= mAX_SMALL_BITMAP_SIZE -> ARG_GEN
+                       | otherwise                     -> ARG_GEN_BIG
+
+-- Return info tables come in two flavours: direct returns and
+-- vectored returns.
+
+mkRetInfoTable :: CLabel -> C_SRT -> Liveness -> [CAddrMode]
+mkRetInfoTable entry_lbl srt liveness
+ = mkBitmapInfoTable (CLbl entry_lbl CodePtrRep) srt liveness []
+
+mkVecInfoTable :: [CAddrMode] -> C_SRT -> Liveness -> [CAddrMode]
+mkVecInfoTable vector srt liveness
+ = mkBitmapInfoTable zero_amode srt liveness vector
+
+mkBitmapInfoTable
+   :: CAddrMode
+   -> C_SRT -> Liveness
+   -> [CAddrMode]
+   -> [CAddrMode]
+mkBitmapInfoTable entry_amode srt liveness vector
+ | tablesNextToCode = extra_bits ++ std_info
+ | otherwise        = std_info ++ extra_bits
+ where
+   std_info = mkStdInfoTable entry_amode zero_amode zero_amode 
+               cl_type srt_len liveness_amode
+
+   liveness_amode = livenessToAddrMode liveness
+
+   (srt_label,srt_len) =
+         case srt of
+           NoC_SRT -> (mkIntCLit 0, 0)
+           C_SRT lbl off bitmap -> 
+                   (CAddr (CIndex (CLbl lbl DataPtrRep) (mkIntCLit off) WordRep),
+                    bitmap)
+
+   cl_type = case (null vector, isBigLiveness liveness) of
+               (True, True)   -> rET_BIG
+               (True, False)  -> rET_SMALL
+               (False, True)  -> rET_VEC_BIG
+               (False, False) -> rET_VEC_SMALL
+
+   srt_bit | needsSRT srt || not (null vector) = [srt_label]
+          | otherwise = []
+
+   extra_bits | tablesNextToCode = reverse vector ++ srt_bit
+              | otherwise        = srt_bit ++ vector
+
+-- The standard bits of an info table.  This part of the info table
+-- corresponds to the StgInfoTable type defined in InfoTables.h.
+
+mkStdInfoTable
+   :: CAddrMode                                -- entry label
+   -> CAddrMode                                -- closure type descr (profiling)
+   -> CAddrMode                                -- closure descr (profiling)
+   -> Int                              -- closure type
+   -> StgHalfWord                      -- SRT length
+   -> CAddrMode                                -- layout field
+   -> [CAddrMode]
+mkStdInfoTable entry_lbl type_descr closure_descr cl_type srt_len layout_amode
+ = std_info
+ where  
+    std_info
+       | tablesNextToCode = std_info'
+       | otherwise        = entry_lbl : std_info'
+
+    std_info' =
+         -- par info
+         prof_info ++
+         -- ticky info
+         -- debug info
+         [layout_amode] ++
+         CLit (MachWord (fromIntegral type_info)) :
+         []
+
+    prof_info 
+       | opt_SccProfilingOn = [ type_descr, closure_descr ]
+       | otherwise = []
+
+    -- sigh: building up the info table is endian-dependent.
+    -- ToDo: do this using .byte and .word directives.
+    type_info :: StgWord
+#ifdef WORDS_BIGENDIAN
+    type_info = (fromIntegral cl_type `shiftL` hALF_WORD) .|.
+               (fromIntegral srt_len)
+#else 
+    type_info = (fromIntegral cl_type) .|.
+               (fromIntegral srt_len `shiftL` hALF_WORD)
+#endif
+
+isBigLiveness (Liveness _ size _) = size > mAX_SMALL_BITMAP_SIZE
+
+livenessToAddrMode :: Liveness -> CAddrMode
+livenessToAddrMode (Liveness lbl size bits)
+       | size <= mAX_SMALL_BITMAP_SIZE = small
+       | otherwise = CLbl lbl DataPtrRep
+       where
+         small = mkWordCLit (fromIntegral size .|. (small_bits `shiftL` bITMAP_BITS_SHIFT))
+         small_bits = case bits of 
+                       []  -> 0
+                       [b] -> fromIntegral b
+                       _   -> panic "livenessToAddrMode"
+
+zero_amode = mkIntCLit 0
+
+-- IA64 mangler doesn't place tables next to code
+tablesNextToCode :: Bool
+#ifdef ia64_TARGET_ARCH
+tablesNextToCode = False
+#else
+tablesNextToCode = not opt_Unregisterised
+#endif
+\end{code}