[project @ 2000-09-11 12:20:56 by sewardj]
authorsewardj <unknown>
Mon, 11 Sep 2000 12:20:57 +0000 (12:20 +0000)
committersewardj <unknown>
Mon, 11 Sep 2000 12:20:57 +0000 (12:20 +0000)
First shot at a STG interpreter for GHCI.  Translates Stg syntax into a
form convenient for interpretation, and can then run that.  Most of the
translation stuff is there and works.  The interpreter framework is there
and partly filled in, and seems to work.  There are still quite a lot of
cases, etc, to fill in, but this should be straightforward given that
the framework exists.  This interpreter cannot handle (yet?) unboxed
tuples, but can deal with more or less everything else, including standard
unboxed Int, Double, etc, code.

ghc/compiler/Makefile
ghc/compiler/absCSyn/PprAbsC.lhs
ghc/compiler/main/Main.lhs
ghc/compiler/prelude/PrimOp.lhs
ghc/compiler/prelude/PrimRep.lhs
ghc/compiler/prelude/primops.txt
ghc/compiler/stgSyn/MCI_make_constr.hi-boot [new file with mode: 0644]
ghc/compiler/stgSyn/StgInterp.lhs [new file with mode: 0644]

index 34e0a3c..06abea1 100644 (file)
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# $Id: Makefile,v 1.91 2000/08/22 10:08:14 simonmar Exp $
+# $Id: Makefile,v 1.92 2000/09/11 12:20:56 sewardj Exp $
 
 TOP = ..
 include $(TOP)/mk/boilerplate.mk
@@ -222,6 +222,8 @@ utils/PrimPacked_HC_OPTS    = -fvia-C -monly-3-regs -optC-funfolding-interface-thre
 # separate bugfix to the fixpoint finder.
 simplStg/UpdAnal_HC_OPTS       = -fno-strictness
 
+stgSyn/StgInterp_HC_OPTS       = -fvia-C
+
 # ----------------------------------------------------------------------------
 #              C compilations
 
index 01952d4..b5221e9 100644 (file)
@@ -1306,6 +1306,7 @@ pprUnionTag ThreadIdRep           = char 't'
 
 pprUnionTag ArrayRep           = char 'p'
 pprUnionTag ByteArrayRep       = char 'b'
+pprUnionTag BCORep             = char 'p'
 
 pprUnionTag _                   = panic "pprUnionTag:Odd kind"
 \end{code}
index f19b445..78d1227 100644 (file)
@@ -46,6 +46,7 @@ import BSD
 import IOExts          ( unsafePerformIO )
 import NativeInfo       ( os, arch )
 #endif
+import StgInterp       ( runStgI )
 
 \end{code}
 
@@ -173,11 +174,17 @@ doIt (core_cmds, stg_cmds)
     in
 
        --------------------------  Simplify STG code -------------------------------
-    show_pass "Stg2Stg"                        >>
+    show_pass "Stg2Stg"                         >>
     _scc_     "Stg2Stg"
     stg2stg stg_cmds this_mod st_uniqs stg_binds >>= \ (stg_binds2, cost_centre_info) ->
 
+#ifdef GHCI
+    runStgI local_tycons local_classes 
+                         (map fst stg_binds2)    >>= \ i_result ->
+    putStr ("\nANSWER = " ++ show i_result ++ "\n\n")
+    >>
 
+#else
        --------------------------  Interface file -------------------------------
        -- Dump instance decls and type signatures into the interface file
     _scc_     "Interface"
@@ -211,6 +218,9 @@ doIt (core_cmds, stg_cmds)
        --------------------------  Final report -------------------------------
     reportCompile mod_name (showSDoc (ppSourceStats True rdr_module)) >>
 
+#endif
+
+
     ghcExit 0
     } }
   where
index 9e946d8..5d97207 100644 (file)
@@ -543,7 +543,8 @@ getPrimOpResultInfo op
        let rep = typePrimRep ty in
        case rep of
           PtrRep -> case splitAlgTyConApp_maybe ty of
-                       Nothing -> panic "getPrimOpResultInfo"
+                       Nothing -> pprPanic "getPrimOpResultInfo" 
+                                            (ppr ty <+> ppr op)
                        Just (tc,_,_) -> ReturnsAlg tc
           other -> ReturnsPrim other
 \end{code}
index ab6fdc4..2769a58 100644 (file)
@@ -241,6 +241,7 @@ showPrimRep ThreadIdRep        = "StgTSO*"
 showPrimRep WeakPtrRep     = "P_"
 showPrimRep ForeignObjRep  = "StgAddr"
 showPrimRep VoidRep       = "!!VOID_KIND!!"
+showPrimRep BCORep         = "P_"      -- not sure -- JRS 000708
 
 primRepString CharRep          = "Char"
 primRepString Int8Rep          = "Char" -- To have names like newCharArray#
index 91d2f0d..d021264 100644 (file)
@@ -1,5 +1,5 @@
 -----------------------------------------------------------------------
--- $Id: primops.txt,v 1.3 2000/09/11 11:17:09 sewardj Exp $
+-- $Id: primops.txt,v 1.4 2000/09/11 12:20:57 sewardj Exp $
 --
 -- Primitive Operations
 --
@@ -982,12 +982,17 @@ primop  NewBCOOp "newBCO#" GenPrimOp
    Int# -> Int# -> Int# -> a -> State# RealWorld -> (# State# RealWorld, BCO# #)
    with
    has_side_effects = True
-   out_of_line    = True
+   out_of_line      = True
+   strictness       = { \ arity -> StrictnessInfo 
+                                   [wwPrim, wwPrim, wwPrim, wwLazy, wwPrim] False }
+   usage            = { mangle NewBCOOp [mkP, mkP, mkP, mkM, mkP] mkR }
 
 primop  WriteBCOPtrOp "writeBCOPtr#" GenPrimOp
    BCO# -> Int# -> o -> State# RealWorld -> State# RealWorld
    with
-   usage            = { mangle WriteBCOPtrOp [mkP, mkP, mkM] mkR }
+   usage            = { mangle WriteBCOPtrOp [mkP, mkP, mkM, mkP] mkR }
+   strictness       = { \ arity -> StrictnessInfo 
+                                   [wwPrim, wwPrim, wwLazy, wwPrim] False }
    has_side_effects = True
 
 primop  WriteBCONonPtrOp "writeBCONonPtr#" GenPrimOp
@@ -1011,6 +1016,13 @@ primop  ReadBCONonPtrOp "readBCONonPtr#"  GenPrimOp
 primop  ReadBCOInstrOp "readBCOInstr#" GenPrimOp
    BCO# -> Int# -> State# RealWorld -> (# State# RealWorld, Word# #)
 
+primop  SameBCOOp "sameBCO#" GenPrimOp
+   BCO# -> BCO# -> Bool
+   with
+   -- is this usage right?
+   usage = { mangle SameMutableArrayOp [mkP, mkP] mkM }
+
+
 ------------------------------------------------------------------------
 --- Weak pointers                                                    ---
 ------------------------------------------------------------------------
diff --git a/ghc/compiler/stgSyn/MCI_make_constr.hi-boot b/ghc/compiler/stgSyn/MCI_make_constr.hi-boot
new file mode 100644 (file)
index 0000000..fc22ad5
--- /dev/null
@@ -0,0 +1,19 @@
+__interface MCIzumakezuconstr 1 409 where
+__export MCIzumakezuconstr 
+   mcizumakezuconstrI
+   mcizumakezuconstr
+   mcizumakezuconstrP
+   mcizumakezuconstrPP
+   mcizumakezuconstrPPP ;
+
+1 mcizumakezuconstrI 
+     :: __forall [a] => PrelGHC.Addrzh -> PrelGHC.Intzh -> a ;
+1 mcizumakezuconstr
+     :: __forall [a] => PrelGHC.Addrzh -> a ;
+1 mcizumakezuconstrP 
+     :: __forall [a a1] => PrelGHC.Addrzh -> a1 -> a ;
+1 mcizumakezuconstrPP 
+     :: __forall [a a1 a2] => PrelGHC.Addrzh -> a1 -> a2 -> a ;
+1 mcizumakezuconstrPPP 
+     :: __forall [a a1 a2 a3] => PrelGHC.Addrzh -> a1 -> a2 -> a3 -> a ;
+
diff --git a/ghc/compiler/stgSyn/StgInterp.lhs b/ghc/compiler/stgSyn/StgInterp.lhs
new file mode 100644 (file)
index 0000000..fb9893e
--- /dev/null
@@ -0,0 +1,1028 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-2000
+%
+\section[StgInterp]{Translates STG syntax to interpretable form, and run it}
+
+\begin{code}
+
+module StgInterp ( runStgI ) where
+
+#include "HsVersions.h"
+
+import StgSyn
+import Id              ( Id, idPrimRep )
+import Panic           ( panic )
+import Outputable
+import Var
+import PrimOp          ( PrimOp(..) )
+import PrimRep         ( PrimRep(..) )
+import Literal         ( Literal(..) )
+import Type            ( Type, typePrimRep, deNoteType, repType, funResultTy )
+import DataCon         ( DataCon, dataConTag, dataConRepArgTys )
+import TyCon           ( TyCon, isDataTyCon, tyConFamilySize, tyConDataCons )
+import ClosureInfo     ( mkVirtHeapOffsets )
+import Class           ( Class, classTyCon )
+
+-- giga-hack
+import {-# SOURCE #-} MCI_make_constr
+
+import PrelGHC         --( unsafeCoerce#, dataToTag#,
+                       --  indexPtrOffClosure#, indexWordOffClosure# )
+import IO              ( hPutStr, stderr )
+import PrelAddr        ( Addr(..) )
+import Addr            ( intToAddr, addrToInt )
+import Storable
+import Addr            -- again ...
+import Word
+import Bits
+
+-- the bindings need to have a binding for stgMain, and the
+-- body of it had better represent something of type Int# -> Int#
+runStgI :: [TyCon] -> [Class] -> [StgBinding] -> IO Int
+runStgI tycons classes stgbinds
+   = do itbl_env <- mkITbls (tycons ++ map classTyCon classes)
+        let binds = concatMap (stg2bind itbl_env) stgbinds
+        let dbg_txt 
+               = "-------------------- Binds --------------------\n" 
+                 ++ showSDoc (vcat (map (\bind -> pprBind bind $$ char ' ') binds))
+
+        hPutStr stderr dbg_txt
+
+        let stgMain
+               = case [rhs | Bind v rhs <- binds, showSDoc (ppr v) == "stgMain"] of
+                    (b:_) -> b
+                    []    -> error "\n\nCan't find `stgMain'.  Giving up.\n\n"        
+        let result 
+               = I# (evalI (AppII stgMain (LitI 0#))
+                           (mkInitialSEnv binds){-initial se (never changes)-}
+                           []{-initial de-}
+                    )
+        return result
+
+type ItblEnv = [(DataCon,Addr)]
+
+-- Make info tables for the data decls in this module
+mkITbls :: [TyCon] -> IO ItblEnv
+mkITbls [] = return []
+mkITbls (tc:tcs) = do itbls  <- mkITbl tc
+                      itbls2 <- mkITbls tcs
+                      return (itbls ++ itbls2)
+
+mkITbl :: TyCon -> IO ItblEnv
+mkITbl tc
+--   | trace ("TYCON: " ++ showSDoc (ppr tc)) False
+--   = error "?!?!"
+   | not (isDataTyCon tc) 
+   = return []
+   | n == length dcs  -- paranoia; this is an assertion.
+   = make_constr_itbls dcs
+     where
+        dcs = tyConDataCons tc
+        n   = tyConFamilySize tc
+
+
+stg2bind :: ItblEnv -> StgBinding -> [Bind]
+stg2bind ie (StgNonRec v e) = [Bind v (rhs2expr ie e)]
+stg2bind ie (StgRec vs_n_es) = [Bind v (rhs2expr ie e) | (v,e) <- vs_n_es]
+
+isRec (StgNonRec _ _) = False
+isRec (StgRec _)      = True
+
+rhs2expr :: ItblEnv -> StgRhs -> Expr
+rhs2expr ie (StgRhsClosure ccs binfo srt fvs uflag args rhs)
+   = mkLambdas args
+     where
+        rhsExpr = stg2expr ie rhs
+        rhsRep  = repOfStgExpr rhs
+        mkLambdas [] = rhsExpr
+        mkLambdas (v:vs) = mkLam (repOfId v) rhsRep v (mkLambdas vs)
+rhs2expr ie (StgRhsCon ccs dcon args)
+   = conapp2expr ie dcon args
+
+conapp2expr :: ItblEnv -> DataCon -> [StgArg] -> Expr
+conapp2expr ie dcon args
+   = mkAppCon itbl reps exprs
+     where
+        itbl        = findItbl ie dcon
+        exprs       = map arg2expr inHeapOrder
+        reps        = map repOfArg inHeapOrder
+        inHeapOrder = toHeapOrder args
+
+        toHeapOrder :: [StgArg] -> [StgArg]
+        toHeapOrder args
+           = let (_, _, rearranged_w_offsets) = mkVirtHeapOffsets getArgPrimRep args
+                 (rearranged, offsets) = unzip rearranged_w_offsets
+             in
+                 rearranged
+
+        findItbl [] dcon
+           -- Not in the list?  A bit of kludgery for testing purposes.
+           | dconIs dcon "std.PrelBase.Izh"
+           = prelbase_Izh_con_info
+           | otherwise
+           = pprPanic "StgInterp.findItbl for " (ppr dcon)
+        findItbl ((dc,itbl):rest) dcon
+           = if dc == dcon then itbl else findItbl rest dcon
+
+        dconIs dcon str 
+           = let cleaned = takeWhile (/= '{') (showSDocDebug (ppr dcon))
+             in --trace ("Cleaned = `" ++ cleaned ++ "'") (
+                str == cleaned
+                --)
+
+foreign label "PrelBase_Izh_con_info" prelbase_Izh_con_info :: Addr
+
+-- Handle most common cases specially; do the rest with a generic
+-- mechanism (deferred till later :)
+mkAppCon :: Addr -> [Rep] -> [Expr] -> Expr
+mkAppCon itbl []               []         = AppCon itbl
+mkAppCon itbl [RepI]           [a1]       = AppConI itbl a1
+mkAppCon itbl [RepP]           [a1]       = AppConP itbl a1
+mkAppCon itbl [RepP,RepP]      [a1,a2]    = AppConPP itbl a1 a2
+mkAppCon itbl [RepP,RepP,RepP] [a1,a2,a3] = AppConPPP itbl a1 a2 a3
+mkAppCon itbl reps args
+   = pprPanic "StgInterp.mkAppCon: unhandled reps" (hsep (map pprRep reps))
+
+
+mkLam RepP RepP = LamPP
+mkLam RepI RepP = LamIP
+mkLam RepP RepI = LamPI
+mkLam RepI RepI = LamII
+mkLam repa repr = pprPanic "StgInterp.mkLam" (pprRep repa <+> pprRep repr)
+
+mkApp RepP RepP = AppPP
+mkApp RepI RepP = AppIP
+mkApp RepP RepI = AppPI
+mkApp RepI RepI = AppII
+mkApp repa repr = pprPanic "StgInterp.mkApp" (pprRep repa <+> pprRep repr)
+
+repOfId :: Id -> Rep
+repOfId = primRep2Rep . idPrimRep
+
+primRep2Rep primRep
+   = case primRep of
+        PtrRep -> RepP
+        IntRep -> RepI
+        other -> pprPanic "primRep2Rep" (ppr other)
+
+repOfStgExpr :: StgExpr -> Rep
+repOfStgExpr stgexpr
+   = case stgexpr of
+        StgLit lit 
+           -> repOfLit lit
+        StgCase scrut live liveR bndr srt alts
+           -> case altRhss alts of
+                 (a:_) -> repOfStgExpr a
+                 []    -> panic "repOfStgExpr: no alts"
+        StgApp var []
+           -> repOfId var
+        StgApp var args
+           -> repOfApp ((deNoteType.repType.idType) var) (length args)
+
+        StgPrimApp op args res_ty
+           -> (primRep2Rep.typePrimRep) res_ty
+
+        StgLet binds body -> repOfStgExpr body
+        StgLetNoEscape live liveR binds body -> repOfStgExpr body
+
+        StgConApp con args -> RepP -- by definition
+
+        other 
+           -> pprPanic "repOfStgExpr" (ppr other)
+     where
+        altRhss (StgAlgAlts ty alts def)
+           = [rhs | (dcon,bndrs,uses,rhs) <- alts] ++ defRhs def
+        altRhss (StgPrimAlts ty alts def)
+           = [rhs | (lit,rhs) <- alts] ++ defRhs def
+        defRhs StgNoDefault 
+           = []
+        defRhs (StgBindDefault rhs)
+           = [rhs]
+
+        -- returns the Rep of the result of applying ty to n args.
+        repOfApp :: Type -> Int -> Rep
+        repOfApp ty 0 = (primRep2Rep.typePrimRep) ty
+        repOfApp ty n = repOfApp (funResultTy ty) (n-1)
+
+
+
+repOfLit lit
+   = case lit of
+        MachInt _ -> RepI
+        MachStr _ -> RepI   -- because it's a ptr outside the heap
+        other -> pprPanic "repOfLit" (ppr lit)
+
+lit2expr :: Literal -> Expr
+lit2expr lit
+   = case lit of
+        MachInt i -> case fromIntegral i of I# i# -> LitI i#
+        MachStr s -> LitS s
+        other -> pprPanic "lit2expr" (ppr lit)
+
+stg2expr :: ItblEnv -> StgExpr -> Expr
+stg2expr ie stgexpr
+   = case stgexpr of
+        StgApp var []
+           -> mkVar (repOfId var) var
+        StgApp var args
+           -> mkAppChain (repOfStgExpr stgexpr) (mkVar (repOfId var) var) args
+        StgLit lit
+           -> lit2expr lit
+
+        StgCase scrut live liveR bndr srt (StgPrimAlts ty alts def)
+           |  repOfStgExpr scrut /= RepP
+           -> mkCasePrim (repOfStgExpr stgexpr) 
+                         bndr (stg2expr ie scrut) 
+                              (map doPrimAlt alts) 
+                              (def2expr def)
+
+        StgCase scrut live liveR bndr srt (StgAlgAlts ty alts def)
+           |  repOfStgExpr scrut == RepP
+           -> mkCaseAlg (repOfStgExpr stgexpr) 
+                        bndr (stg2expr ie scrut) 
+                             (map doAlgAlt alts) 
+                             (def2expr def)
+
+        StgPrimApp op args res_ty
+           -> mkPrimOp (repOfStgExpr stgexpr)
+                       op (map arg2expr args)
+
+        StgConApp dcon args
+           -> conapp2expr ie dcon args
+
+        StgLet binds body
+           |  isRec binds 
+           -> mkRec (repOfStgExpr stgexpr) (stg2bind ie binds) (stg2expr ie body)
+           |  otherwise
+           -> mkNonRec (repOfStgExpr stgexpr) (head (stg2bind ie binds)) (stg2expr ie body)
+
+        other 
+           -> pprPanic "stg2expr" (ppr stgexpr)
+     where
+        doPrimAlt (lit,rhs) 
+           = AltPrim (lit2expr lit) (stg2expr ie rhs)
+        doAlgAlt (dcon,vars,uses,rhs) 
+           = AltAlg (dataConTag dcon - 1) 
+                    (map id2VaaRep (toHeapOrder vars)) (stg2expr ie rhs)
+
+        toHeapOrder vars
+           = let (_,_,rearranged_w_offsets) = mkVirtHeapOffsets idPrimRep vars
+                 (rearranged,offsets)       = unzip rearranged_w_offsets
+             in
+                 rearranged
+
+        def2expr StgNoDefault         = Nothing
+        def2expr (StgBindDefault rhs) = Just (stg2expr ie rhs)
+
+        mkAppChain result_rep so_far []
+           = panic "mkAppChain"
+        mkAppChain result_rep so_far [a]
+           = mkApp (repOfArg a) result_rep so_far (arg2expr a)
+        mkAppChain result_rep so_far (a:as)
+           = mkAppChain result_rep (mkApp (repOfArg a) RepP so_far (arg2expr a)) as
+
+mkCasePrim RepI = CasePrimI
+mkCasePrim RepP = CasePrimP
+
+mkCaseAlg RepI = CaseAlgI
+mkCaseAlg RepP = CaseAlgP
+
+mkVar RepI = VarI
+mkVar RepP = VarP
+
+mkRec RepI = RecI
+mkRec RepP = RecP
+mkNonRec RepI = NonRecI
+mkNonRec RepP = NonRecP
+
+mkPrimOp RepI = PrimOpI
+mkPrimOp RepP = PrimOpP        
+
+arg2expr :: StgArg -> Expr
+arg2expr (StgVarArg v)   = mkVar (repOfId v) v
+arg2expr (StgLitArg lit) = lit2expr lit
+arg2expr (StgTypeArg ty) = pprPanic "arg2expr" (ppr ty)
+
+
+
+repOfArg :: StgArg -> Rep
+repOfArg (StgVarArg v)   = repOfId v
+repOfArg (StgLitArg lit) = repOfLit lit
+repOfArg (StgTypeArg ty) = pprPanic "repOfArg" (ppr ty)
+
+id2VaaRep var = VaaRep var (repOfId var)
+
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+
+
+data Bind = Bind Vaa Expr
+
+pprBind :: Bind -> SDoc
+pprBind (Bind v e) = ppr v <+> char '=' <+> pprExpr e
+
+binder (Bind v e) = v
+bindee (Bind v e) = e
+
+
+data AltAlg = AltAlg Int{-tagNo-} [VaaRep] Expr
+
+pprAltAlg (AltAlg tag vars rhs)
+   = text "Tag_" <> int tag <+> hsep (map pprVaaRep vars)
+     <+> text "->" <+> pprExpr rhs
+
+
+data AltPrim = AltPrim Lit Expr
+
+pprAltPrim (AltPrim tag rhs)
+   = pprExpr tag <+> text "->" <+> pprExpr rhs
+
+
+-- HACK ALERT!  A Lit may *only* be one of LitI, LitL, LitF, LitD
+type Lit = Expr
+
+
+-- var, no rep info (inferrable from context)
+-- Vaa because Var conflicts with Var.Var
+--type Vaa = String
+type Vaa = Id
+
+data VaaRep = VaaRep Vaa Rep
+
+pprVaaRep (VaaRep v r) = ppr v <> text ":" <> pprRep r
+
+
+repOfVaa (VaaRep v r) = r
+varOfVaa (VaaRep v r) = v
+
+data Rep = RepI | RepP deriving Eq
+
+pprRep RepI = text "I"
+pprRep RepP = text "P"
+
+
+
+-- LambdaXY indicates a function of reps X -> Y
+-- ie var rep = X, result rep = Y
+-- NOTE: repOf (LambdaXY _ _) = RepI regardless of X and Y
+--
+-- AppXY means apply a fn (always of Ptr rep) to 
+-- an arg of rep X giving result of Rep Y
+-- therefore: repOf (AppXY _ _) = RepY
+
+-- index???OffClosure needs to traverse indirection nodes.
+
+-- You can always tell the representation of an Expr by examining
+-- its root node.
+data Expr
+   = CaseAlgP   Vaa Expr [AltAlg]  (Maybe Expr)
+   | CasePrimP  Vaa Expr [AltPrim] (Maybe Expr)
+
+   | CaseAlgI   Vaa Expr [AltAlg]  (Maybe Expr)
+   | CasePrimI  Vaa Expr [AltPrim] (Maybe Expr)
+
+   -- saturated constructor apps; args are in heap order.
+   -- The Addrs are the info table pointers.  Descriptors refer to the
+   -- arg reps; all constructor applications return pointer rep.
+   | AppCon    Addr
+   | AppConI   Addr Expr
+   | AppConP   Addr Expr
+   | AppConPP  Addr Expr Expr
+   | AppConPPP Addr Expr Expr Expr
+
+   | PrimOpI PrimOp [Expr]
+   | PrimOpP PrimOp [Expr]
+
+   | Native VoidStar
+
+   | NonRecP Bind Expr
+   | RecP    [Bind] Expr
+
+   | NonRecI Bind Expr
+   | RecI    [Bind] Expr
+
+   | LitI   Int#  -- and LitF Float# | LitD Double# | LitL Int64#
+   | LitS   FAST_STRING
+
+   | VarP   Vaa
+   | VarI   Vaa
+
+   | LamPP  Vaa Expr
+   | LamPI  Vaa Expr
+   | LamIP  Vaa Expr
+   | LamII  Vaa Expr
+
+   | AppPP  Expr Expr
+   | AppPI  Expr Expr
+   | AppIP  Expr Expr
+   | AppII  Expr Expr
+
+
+pprDefault Nothing = text "NO_DEFAULT"
+pprDefault (Just e) = text "DEFAULT ->" $$ nest 2 (pprExpr e)
+
+pprExpr expr
+   = case expr of
+        PrimOpI op args -> doPrimOp 'I' op args
+        PrimOpP op args -> doPrimOp 'P' op args
+
+        VarI v    -> ppr v
+        VarP v    -> ppr v
+        LitI i#   -> int (I# i#) <> char '#'
+        LitS s    -> char '"' <> ptext s <> char '"'
+
+        LamPP v e -> doLam "PP" v e
+        LamPI v e -> doLam "PI" v e
+        LamIP v e -> doLam "IP" v e
+        LamII v e -> doLam "II" v e
+
+        AppPP f a -> doApp "PP" f a
+        AppPI f a -> doApp "PI" f a
+        AppIP f a -> doApp "IP" f a
+        AppII f a -> doApp "II" f a
+
+        CasePrimI b sc alts def -> doCasePrim 'I' b sc alts def
+        CasePrimP b sc alts def -> doCasePrim 'P' b sc alts def
+
+        CaseAlgI b sc alts def -> doCaseAlg 'I' b sc alts def
+        CaseAlgP b sc alts def -> doCaseAlg 'P' b sc alts def
+
+        NonRecP bind body -> doNonRec 'P' bind body
+
+        AppCon    i          -> doAppCon "" i []
+        AppConI   i a1       -> doAppCon "" i [a1]
+        AppConP   i a1       -> doAppCon "" i [a1]
+        AppConPP  i a1 a2    -> doAppCon "" i [a1,a2]
+        AppConPPP i a1 a2 a3 -> doAppCon "" i [a1,a2,a3]
+
+        other     -> text "pprExpr: unimplemented tag:" 
+                     <+> text (showExprTag other)
+     where
+        doAppCon repstr itbl args
+           = text "Con" <> text repstr <> char '_' <> (int (addrToInt itbl)) 
+             <+> char '[' <> hsep (map pprExpr args) <> char ']'
+        doPrimOp repchar op args
+           = char repchar <> ppr op <+> char '[' <> hsep (map pprExpr args) <> char ']'
+        doNonRec repchr bind body
+           = vcat [text "let" <> char repchr <+> pprBind bind, text "in", pprExpr body]
+        doCasePrim repchr b sc alts def
+           = sep [text "CasePrim" <> char repchr 
+                     <+> pprExpr sc <+> text "of" <+> ppr b <+> char '{',
+                  nest 2 (vcat (map pprAltPrim alts) $$ pprDefault def),
+                  char '}'
+                 ]
+
+        doCaseAlg repchr b sc alts def
+           = sep [text "CaseAlg" <> char repchr 
+                     <+> pprExpr sc <+> text "of" <+> ppr b <+> char '{',
+                  nest 2 (vcat (map pprAltAlg alts) $$ pprDefault def),
+                  char '}'
+                 ]
+
+        doApp repstr f a
+           = text "(@" <> text repstr <+> pprExpr f <+> pprExpr a <> char ')'
+        doLam repstr v e 
+           = (char '\\' <> text repstr <+> ppr v <+> text "->") $$ pprExpr e
+
+data VoidStar 
+   = VoidStar
+
+
+
+showExprTag :: Expr -> String
+showExprTag expr
+   = case expr of
+        CaseAlgP  _ _ _ _ -> "CaseAlgP"
+        CasePrimP _ _ _ _ -> "CasePrimP"
+        CaseAlgI  _ _ _ _ -> "CaseAlgI"
+        CasePrimI _ _ _ _ -> "CasePrimI"
+        AppCon _          -> "AppCon"
+        AppConI _ _       -> "AppConI"
+        AppConP _ _       -> "AppConP"
+        AppConPP _ _ _    -> "AppConPP"
+        AppConPPP _ _ _ _ -> "AppConPPP"
+        PrimOpI _ _       -> "PrimOpI"
+        Native _          -> "Native"
+        NonRecP _ _       -> "NonRecP"
+        RecP _ _          -> "RecP"
+        NonRecI _ _       -> "NonRecI"
+        RecI _ _          -> "RecI"
+        LitI _            -> "LitI"
+        LitS _            -> "LitS"
+        VarP _            -> "VarP"
+        VarI _            -> "VarI"
+        LamPP _ _         -> "LamPP"
+        LamPI _ _         -> "LamPI"
+        LamIP _ _         -> "LamIP"
+        LamII _ _         -> "LamII"
+        AppPP _ _         -> "AppPP"
+        AppPI _ _         -> "AppPI"
+        AppIP _ _         -> "AppIP"
+        AppII _ _         -> "AppII"
+        other             -> "(showExprTag:unhandled case)"
+
+-- The dynamic environment contains everything boxed.
+-- eval* functions which look up values in it will know the
+-- representation of the thing they are looking up, so they
+-- can cast/unbox it as necessary.
+type DEnv a = [(Vaa, a)]
+
+-- whereas the static env contains trees for top-level binds.
+type SEnv = [(Vaa, Expr)]
+
+------------------------------------------------------------------------
+--- The interpreter proper                                           ---
+------------------------------------------------------------------------
+
+mkInitialSEnv :: [Bind] -> SEnv
+mkInitialSEnv binds
+   = unsafeCoerce# [(var,rhs) | Bind var rhs <- binds]
+
+
+--------------------------------------------------------
+--- Evaluator for things of boxed (pointer) representation
+--------------------------------------------------------
+
+evalP :: Expr -> SEnv -> DEnv boxed -> boxed
+
+evalP expr se de
+--   | trace ("evalP: " ++ showExprTag expr) False
+   | trace ("evalP:\n" ++ showSDoc (pprExpr expr) ++ "\n") False
+   = error "evalP: ?!?!"
+
+evalP (Native p) se de
+   = unsafeCoerce# p
+
+-- First try the dynamic env.  If that fails, assume it's a top-level
+-- binding and look in the static env.  That gives an Expr, which we
+-- must convert to a boxed thingy by applying evalP to it.  Because
+-- top-level bindings are always ptr-rep'd (either lambdas or boxed
+-- CAFs), it's always safe to use evalP.
+evalP (VarP v) se de 
+   = case lookupDeP de v of
+        Just xx -> xx
+        Nothing -> evalP (lookupSe se v) se de 
+
+
+-- Deal with application of a function returning a pointer rep
+-- to arguments of any persuasion.  Note that the function itself
+-- always has pointer rep.
+evalP (AppIP e1 e2) se de 
+   = unsafeCoerce# (evalP e1 se de) (evalI e2 se de)
+evalP (AppPP e1 e2) se de 
+   = unsafeCoerce# (evalP e1 se de) (evalP e2 se de)
+
+
+-- Lambdas always return P-rep, but we need to do different things
+-- depending on both the argument and result representations.
+evalP (LamPP x b) se de
+   = unsafeCoerce# 
+        (\ xP -> evalP b se (augment de x xP))
+evalP (LamPI x b) se de
+   = unsafeCoerce# 
+        (\ xP -> evalI b se (augment de x xP))
+evalP (LamIP x b) se de
+   = unsafeCoerce# 
+        (\ xI -> evalP b se (augment de x (unsafeCoerce# (I# xI))))
+evalP (LamII x b) se de
+   = unsafeCoerce#
+        (\ xI -> evalI b se (augment de x (unsafeCoerce# (I# xI))))
+
+
+-- NonRec, Rec, CaseAlg and CasePrim are the same for all result reps, 
+-- except in the sense that we go on and evaluate the body with whichever
+-- evaluator was used for the expression as a whole.
+evalP (NonRecP bind b) se de
+   = evalP b se (augment_nonrec bind se de)
+evalP (RecP binds b) se de
+   = evalP b se (augment_rec binds se de)
+evalP (CaseAlgP bndr expr alts def) se de
+   = case helper_caseAlg bndr expr alts def se de of
+        (rhs, de') -> evalP rhs se de'
+evalP (CasePrimP bndr expr alts def) se de
+   = case helper_casePrim bndr expr alts def se de of
+        (rhs, de') -> evalP rhs se de'
+
+{-
+-- AppCon can only be handled by evalP
+evalP (AppCon itbl args) se de
+   = loop args
+     where
+        -- This appalling hack suggested (gleefully) by SDM
+        -- It is not well typed (needless to say?)
+        loop :: [Expr] -> boxed
+        loop [] 
+           = trace "loop-empty" (
+             case itbl of A# addr# -> unsafeCoerce# (mci_make_constr addr#)
+             )
+        loop (a:as) 
+           = trace "loop-not-empty" (
+             case repOf a of
+                RepI -> case evalI a se de of i# -> loop as i#
+                RepP -> let p = evalP a se de in loop as p                
+             )
+-}
+
+evalP (AppConI (A# itbl) a1) se de
+   = case evalI a1 se de of i1 -> mci_make_constrI itbl i1
+
+evalP (AppCon (A# itbl)) se de
+   = mci_make_constr itbl
+
+evalP (AppConP (A# itbl) a1) se de
+   = let p1 = evalP a1 se de
+     in  mci_make_constrP itbl p1
+
+evalP (AppConPP (A# itbl) a1 a2) se de
+   = let p1 = evalP a1 se de
+         p2 = evalP a2 se de
+     in  mci_make_constrPP itbl p1 p2
+
+evalP (AppConPPP (A# itbl) a1 a2 a3) se de
+   = let p1 = evalP a1 se de
+         p2 = evalP a2 se de
+         p3 = evalP a3 se de
+     in  mci_make_constrPPP itbl p1 p2 p3
+
+
+
+evalP other se de
+   = error ("evalP: unhandled case: " ++ showExprTag other)
+
+--------------------------------------------------------
+--- Evaluator for things of Int# representation
+--------------------------------------------------------
+
+
+-- Evaluate something which has an unboxed Int rep
+evalI :: Expr -> SEnv -> DEnv boxed -> Int#
+
+evalI expr se de
+--   | trace ("evalI: " ++ showExprTag expr) False
+   | trace ("evalI:\n" ++ showSDoc (pprExpr expr) ++ "\n") False
+   = error "evalP: ?!?!"
+
+evalI (LitI i#) se de = i#
+
+evalI (VarI v) se de = lookupDeI de v
+
+-- Deal with application of a function returning an Int# rep
+-- to arguments of any persuasion.  Note that the function itself
+-- always has pointer rep.
+evalI (AppII e1 e2) se de 
+   = unsafeCoerce# (evalP e1 se de) (evalI e2 se de)
+evalI (AppPI e1 e2) se de
+   = unsafeCoerce# (evalP e1 se de) (evalP e2 se de)
+
+-- NonRec, Rec, CaseAlg and CasePrim are the same for all result reps, 
+-- except in the sense that we go on and evaluate the body with whichever
+-- evaluator was used for the expression as a whole.
+evalI (NonRecI bind b) se de
+   = evalI b se (augment_nonrec bind se de)
+evalI (RecI binds b) se de
+   = evalI b se (augment_rec binds se de)
+evalI (CaseAlgI bndr expr alts def) se de
+   = case helper_caseAlg bndr expr alts def se de of
+        (rhs, de') -> evalI rhs se de'
+evalI (CasePrimI bndr expr alts def) se de
+   = case helper_casePrim bndr expr alts def se de of
+        (rhs, de') -> evalI rhs se de'
+
+-- evalI can't be applied to a lambda term, by defn, since those
+-- are ptr-rep'd.
+
+evalI (PrimOpI IntAddOp [e1,e2]) se de  = evalI e1 se de +# evalI e2 se de
+evalI (PrimOpI IntSubOp [e1,e2]) se de  = evalI e1 se de -# evalI e2 se de
+
+--evalI (NonRec (Bind v e) b) se de
+--   = evalI b (augment se de v (eval e se de))
+
+evalI other se de
+   = error ("evalI: unhandled case: " ++ showExprTag other)
+
+
+--------------------------------------------------------
+--- Helper bits and pieces
+--------------------------------------------------------
+
+-- Find something in the dynamic environment.  The values are
+-- always boxed, but the caller of lookupDe* knows what representation
+-- the thing really is, so we unbox it accordingly here.
+
+lookupDeI :: DEnv boxed -> Var -> Int#
+lookupDeI []          v' = error ("lookupDeI: " ++ show v')
+lookupDeI ((v,u):vus) v' 
+   | v == v'   = case unsafeCoerce# u of I# i -> i 
+   | otherwise = lookupDeI vus v' 
+
+-- Here, we want to allow the lookup to fail, since in that
+-- case the caller (evalP VarP) will then need to search the
+-- static environment instead.
+lookupDeP :: DEnv boxed -> Var -> Maybe boxed
+lookupDeP []          v' = Nothing
+lookupDeP ((v,u):vus) v' 
+   | v == v'   = Just u
+   | otherwise = lookupDeP vus v' 
+
+-- Find something in the static (top-level-binds) environment.
+lookupSe :: SEnv -> Var -> Expr
+lookupSe []          v' = error ("lookupSe: " ++ show v')
+lookupSe ((v,u):vus) v' 
+   | v == v'   = u
+   | otherwise = lookupSe vus v' 
+
+
+-- Find the Rep of any Expr
+repOf :: Expr -> Rep
+
+repOf (LamII _ _)      = RepP    -- careful!  Lambdas are always P-rep
+repOf (LamPP _ _)      = RepP
+
+repOf (NonRecI _ _)    = RepI
+repOf (LitI _)         = RepI
+repOf (VarI _)         = RepI
+repOf (PrimOpI _ _)    = RepI
+
+repOf (AppII _ _)      = RepI
+repOf (AppPI _ _)      = RepI
+repOf (AppPP _ _)      = RepP
+
+repOf (AppConPP _ _ _) = RepP -- as are all AppCon's
+repOf other         
+   = error ("repOf: unhandled case: " ++ showExprTag other)
+
+-- how big (in words) is one of these
+repSizeW :: Rep -> Int
+repSizeW RepI = 1
+repSizeW RepP = 1
+
+
+-- Evaluate an expression, using the appropriate evaluator,
+-- then box up the result.  Note that it's only safe to use this 
+-- to create values to put in the environment.  You can't use it 
+-- to create a value which might get passed to native code since that
+-- code will have no idea that unboxed things have been boxed.
+eval :: Expr -> SEnv -> DEnv boxed -> boxed
+eval expr se de
+   = case repOf expr of
+        RepI -> unsafeCoerce# (I# (evalI expr se de))
+        RepP -> evalP expr se de
+
+
+-- Evaluate the scrutinee of a case, select an alternative,
+-- augment the environment appropriately, and return the alt
+-- and the augmented environment.
+helper_caseAlg :: Var -> Expr -> [AltAlg] -> Maybe Expr 
+                  -> SEnv -> DEnv boxed
+                  -> (Expr, DEnv boxed)
+helper_caseAlg bndr expr alts def se de
+   = let exprEv = evalP expr se de
+     in  
+     exprEv `seq` -- vitally important; otherwise exprEv is never eval'd
+     case select_altAlg (tagOf exprEv) alts def of
+        (vars,rhs) -> (rhs, augment_from_constr (augment de bndr exprEv) 
+                                                exprEv (vars,1))
+
+helper_casePrim :: Var -> Expr -> [AltPrim] -> Maybe Expr 
+                   -> SEnv -> DEnv boxed
+                   -> (Expr, DEnv boxed)
+helper_casePrim bndr expr alts def se de
+   = case repOf expr of
+        -- Umm, can expr have any other rep?  Yes ...
+        -- CharRep, DoubleRep, FloatRep.  What about string reps?
+        RepI -> case evalI expr se de of 
+                   i# -> (select_altPrim alts def (LitI i#), 
+                          augment de bndr (unsafeCoerce# (I# i#)))
+
+
+augment_from_constr :: DEnv boxed -> a -> ([VaaRep],Int) -> DEnv boxed
+augment_from_constr de con ([],offset) 
+   = de
+augment_from_constr de con (v:vs,offset)
+   = let v_binding
+            = case repOfVaa v of
+                 RepP -> indexPtrOffClosure con offset
+                 RepI -> unsafeCoerce# (I# (indexIntOffClosure con offset))
+     in
+         augment_from_constr ((varOfVaa v,v_binding):de) con 
+                             (vs,offset + repSizeW (repOfVaa v))
+
+-- Augment the environment for a non-recursive let.
+augment_nonrec :: Bind -> SEnv -> DEnv boxed -> DEnv boxed
+augment_nonrec (Bind v e) se de
+   = (v, eval e se de) : de
+
+-- Augment the environment for a recursive let.
+augment_rec :: [Bind] -> SEnv -> DEnv boxed -> DEnv boxed
+augment_rec binds se de
+   = let vars   = map binder binds
+         rhss   = map bindee binds
+         rhs_vs = map (\rhs -> eval rhs se de') rhss
+         de'    = zip vars rhs_vs ++ de
+     in
+         de'
+
+augment :: DEnv boxed -> Var -> boxed -> DEnv boxed
+augment de v e = ((v,e):de)
+
+
+-- a must be a constructor?
+tagOf :: a -> Int
+tagOf x = I# (dataToTag# x)
+
+select_altAlg :: Int -> [AltAlg] -> Maybe Expr -> ([VaaRep],Expr)
+select_altAlg tag [] Nothing = error "select_altAlg: no match and no default?!"
+select_altAlg tag [] (Just def) = ([],def)
+select_altAlg tag ((AltAlg tagNo vars rhs):alts) def
+   = if   tag == tagNo 
+     then (vars,rhs) 
+     else select_altAlg tag alts def
+
+-- literal may only be a literal, not an arbitrary expression
+select_altPrim :: [AltPrim] -> Maybe Expr -> Expr -> Expr
+select_altPrim [] Nothing    literal = error "select_altPrim: no match and no default?!"
+select_altPrim [] (Just def) literal = def
+select_altPrim ((AltPrim lit rhs):alts) def literal
+   = if eqLits lit literal
+     then rhs
+     else select_altPrim alts def literal
+
+eqLits (LitI i1#) (LitI i2#) = i1# ==# i2#
+
+
+-- a is a constructor
+indexPtrOffClosure :: a -> Int -> b
+indexPtrOffClosure con (I# offset)
+   = case indexPtrOffClosure# con offset of (# x #) -> x
+
+indexIntOffClosure :: a -> Int -> Int#
+indexIntOffClosure con (I# offset)
+   = case wordToInt (W# (indexWordOffClosure# con offset)) of I# i# -> i#
+
+
+------------------------------------------------------------------------
+--- Manufacturing of info tables for DataCons defined in this module ---
+------------------------------------------------------------------------
+
+cONSTR :: Int
+cONSTR = 1  -- as defined in ghc/includes/ClosureTypes.h
+
+-- Assumes constructors are numbered from zero, not one
+make_constr_itbls :: [DataCon] -> IO ItblEnv
+make_constr_itbls cons
+   | length cons <= 8
+   = mapM mk_vecret_itbl (zip cons [0..])
+   | otherwise
+   = mapM mk_dirret_itbl (zip cons [0..])
+     where
+        mk_vecret_itbl (dcon, conNo)
+           = mk_itbl dcon conNo (vecret_entry conNo)
+        mk_dirret_itbl (dcon, conNo)
+           = mk_itbl dcon conNo mci_constr_entry
+
+        mk_itbl :: DataCon -> Int -> Addr -> IO (DataCon,Addr)
+        mk_itbl dcon conNo entry_addr
+           = let (tot_wds, ptr_wds, _) 
+                    = mkVirtHeapOffsets typePrimRep (dataConRepArgTys dcon)
+                 ptrs = ptr_wds
+                 nptrs  = tot_wds - ptr_wds
+                 itbl  = StgInfoTable {
+                           ptrs = fromIntegral ptrs, nptrs = fromIntegral nptrs,
+                           tipe = fromIntegral cONSTR,
+                           srtlen = fromIntegral conNo,
+                           code0 = fromIntegral code0, code1 = fromIntegral code1,
+                           code2 = fromIntegral code2, code3 = fromIntegral code3,
+                           code4 = fromIntegral code4, code5 = fromIntegral code5,
+                           code6 = fromIntegral code6, code7 = fromIntegral code7 
+                        }
+                 -- Make a piece of code to jump to "entry_label".
+                 -- This is the only arch-dependent bit.
+                 -- On x86, if entry_label has an address 0xWWXXYYZZ,
+                 -- emit   movl $0xWWXXYYZZ,%eax  ;  jmp *%eax
+                 -- which is
+                 -- B8 ZZ YY XX WW FF E0
+                 (code0,code1,code2,code3,code4,code5,code6,code7)
+                    = (0xB8, byte 0 entry_addr_w, byte 1 entry_addr_w, 
+                             byte 2 entry_addr_w, byte 3 entry_addr_w, 
+                       0xFF, 0xE0, 
+                       0x90 {-nop-})
+
+                 entry_addr_w :: Word32
+                 entry_addr_w = fromIntegral (addrToInt entry_addr)
+             in
+                 do addr <- mallocElem itbl
+                    putStrLn ("SIZE of itbl is " ++ show (sizeOf itbl))
+                    putStrLn ("# ptrs  of itbl is " ++ show ptrs)
+                    putStrLn ("# nptrs of itbl is " ++ show nptrs)
+                    poke addr itbl
+                    return (dcon, intToAddr (addrToInt addr + 8))
+
+
+byte :: Int -> Word32 -> Word32
+byte 0 w = w .&. 0xFF
+byte 1 w = (w `shiftR` 8) .&. 0xFF
+byte 2 w = (w `shiftR` 16) .&. 0xFF
+byte 3 w = (w `shiftR` 24) .&. 0xFF
+
+
+vecret_entry 0 = mci_constr1_entry
+vecret_entry 1 = mci_constr2_entry
+vecret_entry 2 = mci_constr3_entry
+vecret_entry 3 = mci_constr4_entry
+vecret_entry 4 = mci_constr5_entry
+vecret_entry 5 = mci_constr6_entry
+vecret_entry 6 = mci_constr7_entry
+vecret_entry 7 = mci_constr8_entry
+
+-- entry point for direct returns for created constr itbls
+foreign label "mci_constr_entry" mci_constr_entry :: Addr
+-- and the 8 vectored ones
+foreign label "mci_constr1_entry" mci_constr1_entry :: Addr
+foreign label "mci_constr2_entry" mci_constr2_entry :: Addr
+foreign label "mci_constr3_entry" mci_constr3_entry :: Addr
+foreign label "mci_constr4_entry" mci_constr4_entry :: Addr
+foreign label "mci_constr5_entry" mci_constr5_entry :: Addr
+foreign label "mci_constr6_entry" mci_constr6_entry :: Addr
+foreign label "mci_constr7_entry" mci_constr7_entry :: Addr
+foreign label "mci_constr8_entry" mci_constr8_entry :: Addr
+
+
+
+data Constructor = Constructor Int{-ptrs-} Int{-nptrs-}
+
+
+-- Ultra-minimalist version specially for constructors
+data StgInfoTable = StgInfoTable {
+   ptrs :: Word16,
+   nptrs :: Word16,
+   srtlen :: Word16,
+   tipe :: Word16,
+   code0, code1, code2, code3, code4, code5, code6, code7 :: Word8
+}
+
+
+instance Storable StgInfoTable where
+
+   sizeOf itbl 
+      = (sum . map (\f -> f itbl))
+        [fieldSz ptrs, fieldSz nptrs, fieldSz srtlen, fieldSz tipe,
+         fieldSz code0, fieldSz code1, fieldSz code2, fieldSz code3, 
+         fieldSz code4, fieldSz code5, fieldSz code6, fieldSz code7]
+
+   alignment itbl 
+      = (sum . map (\f -> f itbl))
+        [fieldAl ptrs, fieldAl nptrs, fieldAl srtlen, fieldAl tipe,
+         fieldAl code0, fieldAl code1, fieldAl code2, fieldAl code3, 
+         fieldAl code4, fieldAl code5, fieldAl code6, fieldAl code7]
+
+   poke a0 itbl
+      = do a1 <- store (ptrs   itbl) a0
+           a2 <- store (nptrs  itbl) a1
+           a3 <- store (tipe   itbl) a2
+           a4 <- store (srtlen itbl) a3
+           a5 <- store (code0  itbl) a4
+           a6 <- store (code1  itbl) a5
+           a7 <- store (code2  itbl) a6
+           a8 <- store (code3  itbl) a7
+           a9 <- store (code4  itbl) a8
+           aA <- store (code5  itbl) a9
+           aB <- store (code6  itbl) aA
+           aC <- store (code7  itbl) aB
+           return ()
+
+   peek a0
+      = do (a1,ptrs)   <- load a0
+           (a2,nptrs)  <- load a1
+           (a3,tipe)   <- load a2
+           (a4,srtlen) <- load a3
+           (a5,code0)  <- load a4
+           (a6,code1)  <- load a5
+           (a7,code2)  <- load a6
+           (a8,code3)  <- load a7
+           (a9,code4)  <- load a8
+           (aA,code5)  <- load a9
+           (aB,code6)  <- load aA
+           (aC,code7)  <- load aB
+           return StgInfoTable { ptrs = ptrs, nptrs = nptrs, 
+                                 srtlen = srtlen, tipe = tipe,
+                                 code0 = code0, code1 = code1, code2 = code2,
+                                 code3 = code3, code4 = code4, code5 = code5,
+                                 code6 = code6, code7 = code7 }
+
+fieldSz :: (Storable a, Storable b) => (a -> b) -> a -> Int
+fieldSz sel x = sizeOf (sel x)
+
+fieldAl :: (Storable a, Storable b) => (a -> b) -> a -> Int
+fieldAl sel x = alignment (sel x)
+
+store :: Storable a => a -> Addr -> IO Addr
+store x addr = do poke addr x
+                  return (addr `plusAddr` fromIntegral (sizeOf x))
+
+load :: Storable a => Addr -> IO (Addr, a)
+load addr = do x <- peek addr
+               return (addr `plusAddr` fromIntegral (sizeOf x), x)
+
+
+\end{code}
+