[project @ 2001-01-10 17:19:01 by sewardj]
[ghc-hetmet.git] / ghc / compiler / ghci / ByteCodeGen.lhs
index 915e404..295941f 100644 (file)
 \section[ByteCodeGen]{Generate bytecode from Core}
 
 \begin{code}
-module ByteCodeGen ( byteCodeGen, assembleBCO ) where
+module ByteCodeGen ( UnlinkedBCO, UnlinkedBCOExpr, ItblEnv, ClosureEnv, HValue,
+                    filterNameMap,
+                     byteCodeGen, coreExprToBCOs, 
+                    linkIModules, linkIExpr
+                  ) where
 
 #include "HsVersions.h"
 
 import Outputable
-import Name            ( Name, getName )
-import Id              ( Id, idType, isDataConId_maybe )
+import Name            ( Name, getName, nameModule, mkSysLocalName, toRdrName )
+import RdrName         ( rdrNameOcc, rdrNameModule )
+import OccName         ( occNameString )
+import Id              ( Id, idType, isDataConId_maybe, mkVanillaId )
 import OrdList         ( OrdList, consOL, snocOL, appOL, unitOL, 
                          nilOL, toOL, concatOL, fromOL )
-import FiniteMap       ( FiniteMap, addListToFM, listToFM, 
-                         addToFM, lookupFM, fmToList, emptyFM )
+import FiniteMap       ( FiniteMap, addListToFM, listToFM, filterFM,
+                         addToFM, lookupFM, fmToList, emptyFM, plusFM )
 import CoreSyn
-import Literal         ( Literal(..) )
+import PprCore         ( pprCoreExpr, pprCoreAlt )
+import Literal         ( Literal(..), literalPrimRep )
 import PrimRep         ( PrimRep(..) )
 import CoreFVs         ( freeVars )
 import Type            ( typePrimRep )
-import DataCon         ( DataCon, dataConTag, fIRST_TAG )
-import Util            ( zipEqual, zipWith4Equal, naturalMergeSortLe )
+import DataCon         ( DataCon, dataConTag, fIRST_TAG, dataConTyCon, 
+                         dataConRepArgTys )
+import TyCon           ( TyCon, tyConFamilySize, isDataTyCon, tyConDataCons )
+import Class           ( Class, classTyCon )
+import Util            ( zipEqual, zipWith4Equal, naturalMergeSortLe, nOfThem, global )
+import Var             ( isTyVar )
 import VarSet          ( VarSet, varSetElems )
 import PrimRep         ( getPrimRepSize, isFollowableRep )
 import Constants       ( wORD_SIZE )
+import CmdLineOpts     ( DynFlags, DynFlag(..) )
+import ErrUtils                ( showPass, dumpIfSet_dyn )
+import ClosureInfo     ( mkVirtHeapOffsets )
+import Module          ( ModuleName, moduleName, moduleNameFS )
+import Unique          ( mkPseudoUnique3 )
+import Linker          ( lookupSymbol )
+import FastString      ( FastString(..) )
 
-import Foreign         ( Addr, Word16, Word32, nullAddr )
+
+import List            ( intersperse )
+import Monad           ( foldM )
 import ST              ( runST )
-import MutableArray    ( readWord32Array,
+import MArray          ( castSTUArray, 
                          newFloatArray, writeFloatArray,
                          newDoubleArray, writeDoubleArray,
                          newIntArray, writeIntArray,
                          newAddrArray, writeAddrArray )
+import Foreign         ( Storable(..), Word8, Word16, Word32, Ptr(..), 
+                         malloc, castPtr, plusPtr, mallocBytes )
+import Addr            ( Word, addrToInt, writeCharOffAddr )
+import Bits            ( Bits(..), shiftR )
+import CTypes          ( CInt )
+
+import PrelBase                ( Int(..) )
+import PrelAddr                ( Addr(..) )
+import PrelGHC         ( BCO#, newBCO#, unsafeCoerce#, 
+                         ByteArray#, Array#, addrToHValue# )
+import IOExts          ( IORef, fixIO, unsafePerformIO )
+import ArrayBase       
+import PrelArr         ( Array(..) )
+import PrelIOBase      ( IO(..) )
+
 \end{code}
 
-Entry point.
+%************************************************************************
+%*                                                                     *
+\subsection{Functions visible from outside this module.}
+%*                                                                     *
+%************************************************************************
 
 \begin{code}
-byteCodeGen :: [CoreBind] -> [ProtoBCO Name]
-byteCodeGen binds
-   = let flatBinds = concatMap getBind binds
-         getBind (NonRec bndr rhs) = [(bndr, freeVars rhs)]
-         getBind (Rec binds)       = [(bndr, freeVars rhs) | (bndr,rhs) <- binds]
-         final_state = runBc (BcM_State [] 0) 
-                             (mapBc schemeR flatBinds `thenBc_` returnBc ())
-     in  
-         case final_state of
-            BcM_State bcos final_ctr -> bcos
-\end{code}
 
+byteCodeGen :: DynFlags
+            -> [CoreBind] 
+            -> [TyCon] -> [Class]
+            -> IO ([UnlinkedBCO], ItblEnv)
+byteCodeGen dflags binds local_tycons local_classes
+   = do showPass dflags "ByteCodeGen"
+        let tycs = local_tycons ++ map classTyCon local_classes
+        itblenv <- mkITbls tycs
+
+        let flatBinds = concatMap getBind binds
+            getBind (NonRec bndr rhs) = [(bndr, freeVars rhs)]
+            getBind (Rec binds)       = [(bndr, freeVars rhs) | (bndr,rhs) <- binds]
+            final_state = runBc (BcM_State [] 0) 
+                                (mapBc schemeR flatBinds `thenBc_` returnBc ())
+            (BcM_State proto_bcos final_ctr) = final_state
+
+        dumpIfSet_dyn dflags Opt_D_dump_BCOs
+           "Proto-bcos" (vcat (intersperse (char ' ') (map ppr proto_bcos)))
+
+        bcos <- mapM assembleBCO proto_bcos
+
+        return (bcos, itblenv)
+        
+
+-- Returns: (the root BCO for this expression, 
+--           a list of auxilary BCOs resulting from compiling closures)
+coreExprToBCOs :: DynFlags
+              -> CoreExpr
+               -> IO UnlinkedBCOExpr
+coreExprToBCOs dflags expr
+ = do showPass dflags "ByteCodeGen"
+
+      -- create a totally bogus name for the top-level BCO; this
+      -- should be harmless, since it's never used for anything
+      let invented_name = mkSysLocalName (mkPseudoUnique3 0) SLIT("Expr-Top-Level")
+      let invented_id   = mkVanillaId invented_name (panic "invented_id's type")
+
+      let (BcM_State all_proto_bcos final_ctr) 
+             = runBc (BcM_State [] 0) 
+                     (schemeR (invented_id, freeVars expr))
+      dumpIfSet_dyn dflags Opt_D_dump_BCOs
+         "Proto-bcos" (vcat (intersperse (char ' ') (map ppr all_proto_bcos)))
+
+      let root_proto_bco 
+             = case filter ((== invented_name).nameOfProtoBCO) all_proto_bcos of
+                  [root_bco] -> root_bco
+          auxiliary_proto_bcos
+             = filter ((/= invented_name).nameOfProtoBCO) all_proto_bcos
+
+      auxiliary_bcos <- mapM assembleBCO auxiliary_proto_bcos
+      root_bco <- assembleBCO root_proto_bco
+
+      return (root_bco, auxiliary_bcos)
+
+
+-- Linking stuff
+linkIModules :: ItblEnv    -- incoming global itbl env; returned updated
+            -> ClosureEnv -- incoming global closure env; returned updated
+            -> [([UnlinkedBCO], ItblEnv)]
+            -> IO ([HValue], ItblEnv, ClosureEnv)
+linkIModules gie gce mods 
+   = do let (bcoss, ies) = unzip mods
+            bcos = concat bcoss
+            final_gie = foldr plusFM gie ies
+        (final_gce, linked_bcos) <- linkSomeBCOs final_gie gce bcos
+        return (linked_bcos, final_gie, final_gce)
+
+
+linkIExpr :: ItblEnv -> ClosureEnv -> UnlinkedBCOExpr
+          -> IO HValue           -- IO BCO# really
+linkIExpr ie ce (root_ul_bco, aux_ul_bcos)
+   = do (aux_ce, _) <- linkSomeBCOs ie ce aux_ul_bcos
+        (_, [root_bco]) <- linkSomeBCOs ie aux_ce [root_ul_bco]
+        return root_bco
+
+-- Link a bunch of BCOs and return them + updated closure env.
+linkSomeBCOs :: ItblEnv -> ClosureEnv -> [UnlinkedBCO]
+                -> IO (ClosureEnv, [HValue])
+linkSomeBCOs ie ce_in ul_bcos
+   = do let nms = map nameOfUnlinkedBCO ul_bcos
+        hvals <- fixIO 
+                    ( \ hvs -> let ce_out = addListToFM ce_in (zipLazily nms hvs)
+                               in  mapM (linkBCO ie ce_out) ul_bcos )
+        let ce_out = addListToFM ce_in (zip nms hvals)
+        return (ce_out, hvals)
+     where
+        -- A lazier zip, in which no demand is propagated to the second
+        -- list unless some demand is propagated to the snd of one of the
+        -- result list elems.
+        zipLazily []     ys = []
+        zipLazily (x:xs) ys = (x, head ys) : zipLazily xs (tail ys)
+
+
+data UnlinkedBCO
+   = UnlinkedBCO Name
+                 (SizedSeq Word16)     -- insns
+                 (SizedSeq Word)       -- literals
+                 (SizedSeq Name)       -- ptrs
+                 (SizedSeq Name)       -- itbl refs
+
+nameOfUnlinkedBCO (UnlinkedBCO nm _ _ _ _) = nm
+
+-- When translating expressions, we need to distinguish the root
+-- BCO for the expression
+type UnlinkedBCOExpr = (UnlinkedBCO, [UnlinkedBCO])
+
+instance Outputable UnlinkedBCO where
+   ppr (UnlinkedBCO nm insns lits ptrs itbls)
+      = sep [text "BCO", ppr nm, text "with", 
+             int (sizeSS insns), text "insns",
+             int (sizeSS lits), text "lits",
+             int (sizeSS ptrs), text "ptrs",
+             int (sizeSS itbls), text "itbls"]
+
+
+-- these need a proper home
+type ItblEnv    = FiniteMap Name (Ptr StgInfoTable)
+type ClosureEnv = FiniteMap Name HValue
+data HValue     = HValue  -- dummy type, actually a pointer to some Real Code.
+
+-- remove all entries for a given set of modules from the environment
+filterNameMap :: [ModuleName] -> FiniteMap Name a -> FiniteMap Name a
+filterNameMap mods env 
+   = filterFM (\n _ -> moduleName (nameModule n) `notElem` mods) env
+\end{code}
 
 %************************************************************************
 %*                                                                     *
@@ -64,20 +217,32 @@ type LocalLabel = Int
 data BCInstr
    -- Messing with the stack
    = ARGCHECK  Int
-   | PUSH_L    Int{-size-} Int{-offset-}
+   -- Push locals (existing bits of the stack)
+   | PUSH_L    Int{-offset-}
+   | PUSH_LL   Int Int{-2 offsets-}
+   | PUSH_LLL  Int Int Int{-3 offsets-}
+   -- Push a ptr
    | PUSH_G    Name
-   | PUSHT_I   Int
-   | PUSHT_F   Float
-   | PUSHT_D   Double
-   | PUSHU_I   Int
-   | PUSHU_F   Float
-   | PUSHU_D   Double
+   -- Push an alt continuation
+   | PUSH_AS   Name PrimRep    -- push alts and BCO_ptr_ret_info
+                               -- PrimRep so we know which itbl
+   -- Pushing literals
+   | PUSH_UBX  Literal Int 
+                        -- push this int/float/double, NO TAG, on the stack
+                       -- Int is # of words to copy from literal pool
+   | PUSH_TAG  Int      -- push this tag on the stack
+
    | SLIDE     Int{-this many-} Int{-down by this much-}
    -- To do with the heap
-   | ALLOC     Int
-   | MKAP      Int{-place ptr to heap this far down stack-} Int{-# words-}
-   | UNPACK    Int
+   | ALLOC     Int     -- make an AP_UPD with this many payload words, zeroed
+   | MKAP      Int{-ptr to AP_UPD is this far down stack-} Int{-# words-}
+   | UNPACK    Int     -- unpack N ptr words from t.o.s Constr
+   | UPK_TAG   Int Int Int
+                       -- unpack N non-ptr words from offset M in constructor
+                       -- K words down the stack
    | PACK      DataCon Int
+                       -- after assembly, the DataCon is an index into the
+                       -- itbl array
    -- For doing case trees
    | LABEL     LocalLabel
    | TESTLT_I  Int    LocalLabel
@@ -86,33 +251,59 @@ data BCInstr
    | TESTEQ_F  Float  LocalLabel
    | TESTLT_D  Double LocalLabel
    | TESTEQ_D  Double LocalLabel
+
+   -- The Int value is a constructor number and therefore
+   -- stored in the insn stream rather than as an offset into
+   -- the literal pool.
    | TESTLT_P  Int    LocalLabel
    | TESTEQ_P  Int    LocalLabel
+
    | CASEFAIL
    -- To Infinity And Beyond
    | ENTER
+   | RETURN    PrimRep
+               -- unboxed value on TOS.  Use tag to find underlying ret itbl
+               -- and return as per that.
+
 
 instance Outputable BCInstr where
    ppr (ARGCHECK n)          = text "ARGCHECK" <+> int n
-   ppr (PUSH_L sz offset)    = text "PUSH_L  " <+> int sz <+> int offset
+   ppr (PUSH_L offset)       = text "PUSH_L  " <+> int offset
+   ppr (PUSH_LL o1 o2)       = text "PUSH_LL " <+> int o1 <+> int o2
+   ppr (PUSH_LLL o1 o2 o3)   = text "PUSH_LLL" <+> int o1 <+> int o2 <+> int o3
    ppr (PUSH_G nm)           = text "PUSH_G  " <+> ppr nm
-   ppr (PUSHT_I i)           = text "PUSHT_I " <+> int i
+   ppr (PUSH_AS nm pk)       = text "PUSH_AS " <+> ppr nm <+> ppr pk
+   ppr (PUSH_UBX lit nw)     = text "PUSH_UBX" <+> parens (int nw) <+> ppr lit
+   ppr (PUSH_TAG n)          = text "PUSH_TAG" <+> int n
    ppr (SLIDE n d)           = text "SLIDE   " <+> int n <+> int d
    ppr (ALLOC sz)            = text "ALLOC   " <+> int sz
-   ppr (MKAP offset sz)      = text "MKAP    " <+> int offset <+> int sz
+   ppr (MKAP offset sz)      = text "MKAP    " <+> int sz <+> text "words," 
+                                               <+> int offset <+> text "stkoff"
    ppr (UNPACK sz)           = text "UNPACK  " <+> int sz
+   ppr (UPK_TAG n m k)       = text "UPK_TAG " <+> int n <> text "words" 
+                                               <+> int m <> text "conoff"
+                                               <+> int k <> text "stkoff"
    ppr (PACK dcon sz)        = text "PACK    " <+> ppr dcon <+> ppr sz
+   ppr (LABEL     lab)       = text "__"       <> int lab <> colon
+   ppr (TESTLT_I  i lab)     = text "TESTLT_I" <+> int i <+> text "__" <> int lab
+   ppr (TESTEQ_I  i lab)     = text "TESTEQ_I" <+> int i <+> text "__" <> int lab
+   ppr (TESTLT_F  f lab)     = text "TESTLT_F" <+> float f <+> text "__" <> int lab
+   ppr (TESTEQ_F  f lab)     = text "TESTEQ_F" <+> float f <+> text "__" <> int lab
+   ppr (TESTLT_D  d lab)     = text "TESTLT_D" <+> double d <+> text "__" <> int lab
+   ppr (TESTEQ_D  d lab)     = text "TESTEQ_D" <+> double d <+> text "__" <> int lab
+   ppr (TESTLT_P  i lab)     = text "TESTLT_P" <+> int i <+> text "__" <> int lab
+   ppr (TESTEQ_P  i lab)     = text "TESTEQ_P" <+> int i <+> text "__" <> int lab
+   ppr CASEFAIL              = text "CASEFAIL"
    ppr ENTER                 = text "ENTER"
-
-pprAltCode discrs_n_codes
-   = vcat (map f discrs_n_codes)
-     where f (discr, code) = ppr discr <> colon <+> vcat (map ppr (fromOL code))
+   ppr (RETURN pk)           = text "RETURN  " <+> ppr pk
 
 instance Outputable a => Outputable (ProtoBCO a) where
-   ppr (ProtoBCO name instrs)
+   ppr (ProtoBCO name instrs origin)
       = (text "ProtoBCO" <+> ppr name <> colon)
-        $$ nest 6 (vcat (map ppr (fromOL instrs)))
-
+        $$ nest 6 (vcat (map ppr instrs))
+        $$ case origin of
+              Left alts -> vcat (map (pprCoreAlt.deAnnAlt) alts)
+              Right rhs -> pprCoreExpr (deAnnotate rhs)
 \end{code}
 
 %************************************************************************
@@ -125,7 +316,15 @@ instance Outputable a => Outputable (ProtoBCO a) where
 
 type BCInstrList = OrdList BCInstr
 
-data ProtoBCO a = ProtoBCO a BCInstrList
+data ProtoBCO a 
+   = ProtoBCO a                        -- name, in some sense
+              [BCInstr]                -- instrs
+                                       -- what the BCO came from
+              (Either [AnnAlt Id VarSet]
+                      (AnnExpr Id VarSet))
+
+nameOfProtoBCO (ProtoBCO nm insns origin) = nm
+
 
 type Sequel = Int      -- back off to this depth before ENTER
 
@@ -134,28 +333,65 @@ type Sequel = Int -- back off to this depth before ENTER
 type BCEnv = FiniteMap Id Int  -- To find vars on the stack
 
 
+-- Create a BCO and do a spot of peephole optimisation on the insns
+-- at the same time.
+mkProtoBCO nm instrs_ordlist origin
+   = ProtoBCO nm (id {-peep-} (fromOL instrs_ordlist)) origin
+     where
+        peep (PUSH_L off1 : PUSH_L off2 : PUSH_L off3 : rest)
+           = PUSH_LLL off1 (off2-1) (off3-2) : peep rest
+        peep (PUSH_L off1 : PUSH_L off2 : rest)
+           = PUSH_LL off1 off2 : peep rest
+        peep (i:rest)
+           = i : peep rest
+        peep []
+           = []
+
 
 -- Compile code for the right hand side of a let binding.
 -- Park the resulting BCO in the monad.  Also requires the
 -- variable to which this value was bound, so as to give the
 -- resulting BCO a name.
 schemeR :: (Id, AnnExpr Id VarSet) -> BcM ()
-schemeR (nm, rhs) = schemeR_wrk nm (collect [] rhs)
+schemeR (nm, rhs) 
+{-
+   | trace (showSDoc (
+              (char ' '
+               $$ (ppr.filter (not.isTyVar).varSetElems.fst) rhs
+               $$ pprCoreExpr (deAnnotate rhs)
+               $$ char ' '
+              ))) False
+   = undefined
+-}
+   | otherwise
+   = schemeR_wrk rhs nm (collect [] rhs)
+
 
-collect xs (_, AnnLam x e) = collect (x:xs) e
-collect xs not_lambda      = (reverse xs, not_lambda)
+collect xs (_, AnnNote note e)
+   = collect xs e
+collect xs (_, AnnLam x e) 
+   = collect (if isTyVar x then xs else (x:xs)) e
+collect xs not_lambda
+   = (reverse xs, not_lambda)
 
-schemeR_wrk nm (args, body)
-   = let fvs       = fst body
-         all_args  = varSetElems fvs ++ args
+schemeR_wrk original_body nm (args, body)
+   = let fvs       = filter (not.isTyVar) (varSetElems (fst original_body))
+         all_args  = reverse args ++ fvs --ORIG: fvs ++ reverse args
          szsw_args = map taggedIdSizeW all_args
          szw_args  = sum szsw_args
-         p_init    = listToFM (zip all_args (scanl (+) 0 szsw_args))
-         argcheck  = if null args then nilOL else unitOL (ARGCHECK szw_args)
+         p_init    = listToFM (zip all_args (mkStackOffsets 0 szsw_args))
+         argcheck  = --if null args then nilOL else
+                     unitOL (ARGCHECK szw_args)
      in
      schemeE szw_args 0 p_init body            `thenBc` \ body_code ->
-     emitBc (ProtoBCO (getName nm) (appOL argcheck body_code))
+     emitBc (mkProtoBCO (getName nm) (appOL argcheck body_code) (Right original_body))
 
+-- Let szsw be the sizes in words of some items pushed onto the stack,
+-- which has initial depth d'.  Return the values which the stack environment
+-- should map these items to.
+mkStackOffsets :: Int -> [Int] -> [Int]
+mkStackOffsets original_depth szsw
+   = map (subtract 1) (tail (scanl (+) original_depth szsw))
 
 -- Compile code to apply the given expression to the remaining args
 -- on the stack, returning a HNF.
@@ -165,35 +401,59 @@ schemeE :: Int -> Sequel -> BCEnv -> AnnExpr Id VarSet -> BcM BCInstrList
 schemeE d s p e@(fvs, AnnApp f a) 
    = returnBc (schemeT (should_args_be_tagged e) d s 0 p (fvs, AnnApp f a))
 schemeE d s p e@(fvs, AnnVar v)
+   | isFollowableRep v_rep
    = returnBc (schemeT (should_args_be_tagged e) d s 0 p (fvs, AnnVar v))
+   | otherwise
+   = -- returning an unboxed value.  Heave it on the stack, SLIDE, and RETURN.
+     let (push, szw) = pushAtom True d p (AnnVar v)
+     in  returnBc (push                        -- value onto stack
+                   `appOL`  mkSLIDE szw (d-s)  -- clear to sequel
+                   `snocOL` RETURN v_rep)      -- go
+   where
+      v_rep = typePrimRep (idType v)
+
+schemeE d s p (fvs, AnnLit literal)
+   = let (push, szw) = pushAtom True d p (AnnLit literal)
+         l_rep = literalPrimRep literal
+     in  returnBc (push                        -- value onto stack
+                   `appOL`  mkSLIDE szw (d-s)  -- clear to sequel
+                   `snocOL` RETURN l_rep)      -- go
 
 schemeE d s p (fvs, AnnLet binds b)
    = let (xs,rhss) = case binds of AnnNonRec x rhs  -> ([x],[rhs])
                                    AnnRec xs_n_rhss -> unzip xs_n_rhss
-     in
-     mapBc schemeR (zip xs rhss)                       `thenBc_`
-     let n     = length xs
-         fvss  = map (varSetElems.fst) rhss
+         n     = length xs
+         fvss  = map (filter (not.isTyVar).varSetElems.fst) rhss
+
+         -- Sizes of tagged free vars, + 1 for the fn
          sizes = map (\rhs_fvs -> 1 + sum (map taggedIdSizeW rhs_fvs)) fvss
-         p'    = addListToFM p (zipE xs [d .. d+n-1])
+
+         -- This p', d' defn is safe because all the items being pushed
+         -- are ptrs, so all have size 1.  d' and p' reflect the stack
+         -- after the closures have been allocated in the heap (but not
+         -- filled in), and pointers to them parked on the stack.
+         p'    = addListToFM p (zipE xs (mkStackOffsets d (nOfThem n 1)))
          d'    = d + n
+
          infos = zipE4 fvss sizes xs [n, n-1 .. 1]
          zipE  = zipEqual "schemeE"
          zipE4 = zipWith4Equal "schemeE" (\a b c d -> (a,b,c,d))
 
          -- ToDo: don't build thunks for things with no free variables
-         buildThunk (fvs, size, id, off)
-            = case unzip (map (pushAtom True d' p . AnnVar) (reverse fvs)) of
-                (push_codes, pushed_szsw) 
-                   -> ASSERT(sum pushed_szsw == size - 1)
-                            (toOL push_codes `snocOL` PUSH_G (getName id) 
-                                             `appOL` unitOL (MKAP off size))
-
-         thunkCode = concatOL (map buildThunk infos)
+         buildThunk dd ([], size, id, off)
+            = PUSH_G (getName id) 
+              `consOL` unitOL (MKAP (off+size-1) size)
+         buildThunk dd ((fv:fvs), size, id, off)
+            = case pushAtom True dd p' (AnnVar fv) of
+                 (push_code, pushed_szw)
+                    -> push_code `appOL`
+                       buildThunk (dd+pushed_szw) (fvs, size, id, off)
+
+         thunkCode = concatOL (map (buildThunk d') infos)
          allocCode = toOL (map ALLOC sizes)
      in
-     schemeE d' s p' b                                 `thenBc` \ bodyCode ->
-     mapBc schemeR (zip xs rhss)                       `thenBc` \_ ->
+     schemeE d' s p' b                                 `thenBc`  \ bodyCode ->
+     mapBc schemeR (zip xs rhss)                       `thenBc_`
      returnBc (allocCode `appOL` thunkCode `appOL` bodyCode)
 
 
@@ -208,25 +468,30 @@ schemeE d s p (fvs, AnnCase scrut bndr alts)
         -- Env and depth in which to compile the alts, not including
         -- any vars bound by the alts themselves
         d' = d + ret_frame_sizeW + taggedIdSizeW bndr
-        p' = addToFM p bndr d'
+        p' = addToFM p bndr (d' - 1)
 
+        scrut_primrep = typePrimRep (idType bndr)
         isAlgCase
-           = case typePrimRep (idType bndr) of
+           = case scrut_primrep of
+                CharRep -> False ; AddrRep -> False
                 IntRep -> False ; FloatRep -> False ; DoubleRep -> False
                 PtrRep -> True
                 other  -> pprPanic "ByteCodeGen.schemeE" (ppr other)
 
         -- given an alt, return a discr and code for it.
-        codeAlt alt@(discr, binds, rhs)
+        codeAlt alt@(discr, binds_f, rhs)
            | isAlgCase 
-           = let binds_szsw = map untaggedIdSizeW binds
-                 binds_szw  = sum binds_szsw
-                 p'' = addListToFM p' (zip binds (scanl (+) d' binds_szsw))
-                 d'' = d' + binds_szw
+           = let binds_r        = reverse binds_f
+                 binds_r_t_szsw = map taggedIdSizeW binds_r
+                 binds_t_szw    = sum binds_r_t_szsw
+                 p''            = addListToFM 
+                                   p' (zip binds_r (mkStackOffsets d' binds_r_t_szsw))
+                 d''            = d' + binds_t_szw
+                 unpack_code    = mkUnpackCode {-0 0-} (map (typePrimRep.idType) binds_f)
              in schemeE d'' s p'' rhs  `thenBc` \ rhs_code -> 
-                returnBc (my_discr alt, UNPACK binds_szw `consOL` rhs_code)
+                returnBc (my_discr alt, unpack_code `appOL` rhs_code)
            | otherwise 
-           = ASSERT(null binds) 
+           = ASSERT(null binds_f) 
              schemeE d' s p' rhs       `thenBc` \ rhs_code ->
              returnBc (my_discr alt, rhs_code)
 
@@ -237,18 +502,34 @@ schemeE d s p (fvs, AnnCase scrut bndr alts)
                        MachFloat r   -> DiscrF (fromRational r)
                        MachDouble r  -> DiscrD (fromRational r)
 
+        maybe_ncons 
+           | not isAlgCase = Nothing
+           | otherwise 
+           = case [dc | (DataAlt dc, _, _) <- alts] of
+                []     -> Nothing
+                (dc:_) -> Just (tyConFamilySize (dataConTyCon dc))
+
      in 
      mapBc codeAlt alts                                `thenBc` \ alt_stuff ->
-     mkMultiBranch alt_stuff                           `thenBc` \ alt_final ->
+     mkMultiBranch maybe_ncons alt_stuff               `thenBc` \ alt_final ->
      let 
+         alt_final_ac = ARGCHECK (taggedIdSizeW bndr) `consOL` alt_final
          alt_bco_name = getName bndr
-         alt_bco      = ProtoBCO alt_bco_name alt_final
+         alt_bco      = mkProtoBCO alt_bco_name alt_final_ac (Left alts)
      in
      schemeE (d + ret_frame_sizeW) 
              (d + ret_frame_sizeW) p scrut             `thenBc` \ scrut_code ->
 
      emitBc alt_bco                                    `thenBc_`
-     returnBc (PUSH_G alt_bco_name `consOL` scrut_code)
+     returnBc (PUSH_AS alt_bco_name scrut_primrep `consOL` scrut_code)
+
+
+schemeE d s p (fvs, AnnNote note body)
+   = schemeE d s p body
+
+schemeE d s p other
+   = pprPanic "ByteCodeGen.schemeE: unhandled case" 
+               (pprCoreExpr (deAnnotate other))
 
 
 -- Compile code to do a tail call.  Doesn't need to be monadic.
@@ -257,23 +538,32 @@ schemeT :: Bool   -- do tagging?
         -> Sequel      -- Sequel depth
         -> Int                 -- # arg words so far
         -> BCEnv       -- stack env
-        -> AnnExpr Id VarSet -> BCInstrList
+        -> AnnExpr Id VarSet 
+        -> BCInstrList
 
-schemeT enTag d s narg_words p (_, AnnApp f a) 
-   = let (push, arg_words) = pushAtom enTag d p (snd a)
-     in push 
-        `consOL` schemeT enTag (d+arg_words) s (narg_words+arg_words) p f
+schemeT enTag d s narg_words p (_, AnnApp f a)
+   = case snd a of
+        AnnType _ -> schemeT enTag d s narg_words p f
+        other
+           -> let (push, arg_words) = pushAtom enTag d p (snd a)
+              in push 
+                 `appOL` schemeT enTag (d+arg_words) s (narg_words+arg_words) p f
 
 schemeT enTag d s narg_words p (_, AnnVar f)
    | Just con <- isDataConId_maybe f
    = ASSERT(enTag == False)
-     PACK con narg_words `consOL` SLIDE 1 (d-s-1) `consOL` unitOL ENTER
+     --trace ("schemeT: d = " ++ show d ++ ", s = " ++ show s ++ ", naw = " ++ show narg_words) (
+     PACK con narg_words `consOL` (mkSLIDE 1 (d - narg_words - s) `snocOL` ENTER)
+     --)
    | otherwise
    = ASSERT(enTag == True)
      let (push, arg_words) = pushAtom True d p (AnnVar f)
-     in push 
-        `consOL` SLIDE (narg_words+arg_words) (d - s - narg_words)
-        `consOL` unitOL ENTER
+     in  push 
+         `appOL`  mkSLIDE (narg_words+arg_words) (d - s - narg_words)
+         `snocOL` ENTER
+
+mkSLIDE n d 
+   = if d == 0 then nilOL else unitOL (SLIDE n d)
 
 should_args_be_tagged (_, AnnVar v)
    = case isDataConId_maybe v of
@@ -283,6 +573,37 @@ should_args_be_tagged (_, AnnApp f a)
 should_args_be_tagged (_, other)
    = panic "should_args_be_tagged: tail call to non-con, non-var"
 
+
+-- Make code to unpack the top-of-stack constructor onto the stack, 
+-- adding tags for the unboxed bits.  Takes the PrimReps of the 
+-- constructor's arguments.  off_h and off_s are travelling offsets
+-- along the constructor and the stack.
+mkUnpackCode :: [PrimRep] -> BCInstrList
+mkUnpackCode reps
+   = all_code
+     where
+        all_code = ptrs_code `appOL` do_nptrs ptrs_szw ptrs_szw reps_nptr
+
+        reps_ptr  = filter isFollowableRep reps
+        reps_nptr = filter (not.isFollowableRep) reps
+        
+        ptrs_szw  = sum (map untaggedSizeW reps_ptr)
+        ptrs_code | null reps_ptr = nilOL
+                  | otherwise     = unitOL (UNPACK ptrs_szw)
+
+        do_nptrs off_h off_s [] = nilOL
+        do_nptrs off_h off_s (npr:nprs)
+           = case npr of
+                IntRep -> approved ; FloatRep -> approved
+                DoubleRep -> approved ; AddrRep -> approved
+                _ -> pprPanic "ByteCodeGen.mkUnpackCode" (ppr npr)
+             where
+                approved = UPK_TAG usizeW off_h off_s   `consOL` theRest
+                theRest  = do_nptrs (off_h + usizeW) (off_s + tsizeW) nprs
+                usizeW   = untaggedSizeW npr
+                tsizeW   = taggedSizeW npr
+
+
 -- Push an atom onto the stack, returning suitable code & number of
 -- stack words used.  Pushes it either tagged or untagged, since 
 -- pushAtom is used to set up the stack prior to copying into the
@@ -300,40 +621,108 @@ should_args_be_tagged (_, other)
 --
 -- Blargh.  JRS 001206
 --
-pushAtom True{-tagged-} d p (AnnVar v) 
-   = case lookupBCEnv_maybe p v of
-        Just offset -> (PUSH_L sz offset, sz)
-        Nothing     -> ASSERT(sz == 1) (PUSH_G nm, sz)
-     where
-        nm = getName v
-        sz = taggedIdSizeW v
-
-pushAtom False{-not tagged-} d p (AnnVar v) 
-   = case lookupBCEnv_maybe p v of
-        Just offset -> (PUSH_L sz (offset+1), sz-1)
-        Nothing     -> ASSERT(sz == 1) (PUSH_G nm, sz)
-     where
-        nm = getName v
-        sz = untaggedIdSizeW v
+-- NB (further) that the env p must map each variable to the highest-
+-- numbered stack slot for it.  For example, if the stack has depth 4 
+-- and we tagged-ly push (v :: Int#) on it, the value will be in stack[4],
+-- the tag in stack[5], the stack will have depth 6, and p must map v to
+-- 5 and not to 4.  Stack locations are numbered from zero, so a depth
+-- 6 stack has valid words 0 .. 5.
+
+pushAtom :: Bool -> Int -> BCEnv -> AnnExpr' Id VarSet -> (BCInstrList, Int)
+pushAtom tagged d p (AnnVar v) 
+   = let str = "\npushAtom " ++ showSDocDebug (ppr v) ++ ", depth = " ++ show d
+               ++ ", env =\n" ++ 
+               showSDocDebug (nest 4 (vcat (map ppr (fmToList p))))
+               ++ " -->\n" ++
+               showSDoc (nest 4 (vcat (map ppr (fromOL (fst result)))))
+               ++ "\nendPushAtom " ++ showSDocDebug (ppr v)
+         str' = if str == str then str else str
+
+         result
+            = case lookupBCEnv_maybe p v of
+                 Just d_v -> (toOL (nOfThem nwords (PUSH_L (d-d_v+sz_t-2))), sz_t)
+                 Nothing  -> ASSERT(sz_t == 1) (unitOL (PUSH_G nm), sz_t)
+
+         nm = case isDataConId_maybe v of
+                 Just c  -> getName c
+                 Nothing -> getName v
+
+         sz_t   = taggedIdSizeW v
+         sz_u   = untaggedIdSizeW v
+         nwords = if tagged then sz_t else sz_u
+     in
+         --trace str'
+         result
 
 pushAtom True d p (AnnLit lit)
-   = case lit of
-        MachInt i    -> (PUSHT_I (fromInteger i),  taggedSizeW IntRep)
-        MachFloat r  -> (PUSHT_F (fromRational r), taggedSizeW FloatRep)
-        MachDouble r -> (PUSHT_D (fromRational r), taggedSizeW DoubleRep)
+   = let (ubx_code, ubx_size) = pushAtom False d p (AnnLit lit)
+     in  (ubx_code `snocOL` PUSH_TAG ubx_size, 1 + ubx_size)
 
 pushAtom False d p (AnnLit lit)
    = case lit of
-        MachInt i    -> (PUSHU_I (fromInteger i),  untaggedSizeW IntRep)
-        MachFloat r  -> (PUSHU_F (fromRational r), untaggedSizeW FloatRep)
-        MachDouble r -> (PUSHU_D (fromRational r), untaggedSizeW DoubleRep)
+        MachInt i    -> code IntRep
+        MachFloat r  -> code FloatRep
+        MachDouble r -> code DoubleRep
+        MachChar c   -> code CharRep
+        MachStr s    -> pushStr s
+     where
+        code rep
+           = let size_host_words = untaggedSizeW rep
+             in (unitOL (PUSH_UBX lit size_host_words), size_host_words)
+
+        pushStr s 
+           = let mallocvilleAddr
+                    = case s of
+                         CharStr s i -> A# s
+
+                         FastString _ l ba -> 
+                            -- sigh, a string in the heap is no good to us.
+                            -- We need a static C pointer, since the type of 
+                            -- a string literal is Addr#.  So, copy the string 
+                            -- into C land and introduce a memory leak 
+                            -- at the same time.
+                            let n = I# l
+                            -- CAREFUL!  Chars are 32 bits in ghc 4.09+
+                            in  unsafePerformIO (
+                                   do a@(Ptr addr) <- mallocBytes (n+1)
+                                      strncpy a ba (fromIntegral n)
+                                      writeCharOffAddr addr n '\0'
+                                      return addr
+                                   )
+                         _ -> panic "StgInterp.lit2expr: unhandled string constant type"
+
+                 addrLit 
+                    = MachInt (toInteger (addrToInt mallocvilleAddr))
+             in
+                -- Get the addr on the stack, untaggedly
+                (unitOL (PUSH_UBX addrLit 1), 1)
+
+
+
+
+
+pushAtom tagged d p (AnnApp f (_, AnnType _))
+   = pushAtom tagged d p (snd f)
+
+pushAtom tagged d p (AnnNote note e)
+   = pushAtom tagged d p (snd e)
+
+pushAtom tagged d p other
+   = pprPanic "ByteCodeGen.pushAtom" 
+              (pprCoreExpr (deAnnotate (undefined, other)))
+
+foreign import "strncpy" strncpy :: Ptr a -> ByteArray# -> CInt -> IO ()
 
 
 -- Given a bunch of alts code and their discrs, do the donkey work
 -- of making a multiway branch using a switch tree.
 -- What a load of hassle!
-mkMultiBranch :: [(Discr, BCInstrList)] -> BcM BCInstrList
-mkMultiBranch raw_ways
+mkMultiBranch :: Maybe Int     -- # datacons in tycon, if alg alt
+                               -- a hint; generates better code
+                               -- Nothing is always safe
+              -> [(Discr, BCInstrList)] 
+              -> BcM BCInstrList
+mkMultiBranch maybe_ncons raw_ways
    = let d_way     = filter (isNoDiscr.fst) raw_ways
          notd_ways = naturalMergeSortLe 
                         (\w1 w2 -> leAlt (fst w1) (fst w2))
@@ -390,10 +779,15 @@ mkMultiBranch raw_ways
                             DiscrD maxD );
               DiscrP _ -> ( \(DiscrP i) fail_label -> TESTLT_P i fail_label,
                             \(DiscrP i) fail_label -> TESTEQ_P i fail_label,
-                            DiscrP minBound,
-                            DiscrP maxBound )
+                            DiscrP algMinBound,
+                            DiscrP algMaxBound )
               }
 
+         (algMinBound, algMaxBound)
+            = case maybe_ncons of
+                 Just n  -> (0, n - 1)
+                 Nothing -> (minBound, maxBound)
+
          (DiscrI i1) `eqAlt` (DiscrI i2) = i1 == i2
          (DiscrF f1) `eqAlt` (DiscrF f2) = f1 == f2
          (DiscrD d1) `eqAlt` (DiscrD d2) = d1 == d2
@@ -453,12 +847,13 @@ instance Outputable Discr where
 
 
 -- Find things in the BCEnv (the what's-on-the-stack-env)
-lookupBCEnv :: BCEnv -> Id -> Int
-lookupBCEnv env nm
-   = case lookupFM env nm of
-        Nothing -> pprPanic "lookupBCEnv" 
-                            (ppr nm $$ char ' ' $$ vcat (map ppr (fmToList env)))
-        Just xx -> xx
+-- See comment preceding pushAtom for precise meaning of env contents
+--lookupBCEnv :: BCEnv -> Id -> Int
+--lookupBCEnv env nm
+--   = case lookupFM env nm of
+--        Nothing -> pprPanic "lookupBCEnv" 
+--                            (ppr nm $$ char ' ' $$ vcat (map ppr (fmToList env)))
+--        Just xx -> xx
 
 lookupBCEnv_maybe :: BCEnv -> Id -> Maybe Int
 lookupBCEnv_maybe = lookupFM
@@ -497,9 +892,6 @@ data BcM_State
 
 type BcM result = BcM_State -> (result, BcM_State)
 
-mkBcM_State :: [ProtoBCO Name] -> Int -> BcM_State
-mkBcM_State = BcM_State
-
 runBc :: BcM_State -> BcM () -> BcM_State
 runBc init_st m = case m init_st of { (r,st) -> st }
 
@@ -545,250 +937,601 @@ index into the literal table (eg PUSH_I/D/L), or a bytecode address in
 this BCO.
 
 \begin{code}
--- An (almost) assembled BCO.
-data BCO a = BCO [Word16]      -- instructions
-                 [Word32]      -- literal pool
-                 [a]           -- Names or HValues
-
 -- Top level assembler fn.
-assembleBCO :: ProtoBCO Name -> BCO Name
-assembleBCO (ProtoBCO nm instrs_ordlist)
+assembleBCO :: ProtoBCO Name -> IO UnlinkedBCO
+
+assembleBCO (ProtoBCO nm instrs origin)
    = let
-         -- pass 1: collect up the offsets of the local labels
-         instrs = fromOL instrs_ordlist
-         label_env = mkLabelEnv emptyFM 0 instrs
+         -- pass 1: collect up the offsets of the local labels.
+         -- Remember that the first insn starts at offset 1 since offset 0
+         -- (eventually) will hold the total # of insns.
+         label_env = mkLabelEnv emptyFM 1 instrs
 
          mkLabelEnv env i_offset [] = env
          mkLabelEnv env i_offset (i:is)
             = let new_env 
                      = case i of LABEL n -> addToFM env n i_offset ; _ -> env
-              in  mkLabelEnv new_env (i_offset + instrSizeB i) is
+              in  mkLabelEnv new_env (i_offset + instrSize16s i) is
 
          findLabel lab
             = case lookupFM label_env lab of
                  Just bco_offset -> bco_offset
                  Nothing -> pprPanic "assembleBCO.findLabel" (int lab)
-
-         -- pass 2: generate the instruction, ptr and nonptr bits
-         (insnW16s, litW32s, ptrs) = mkBits findLabel [] 0 [] 0 [] 0 instrs
      in
-         BCO insnW16s litW32s ptrs
+     do  -- pass 2: generate the instruction, ptr and nonptr bits
+         insns <- return emptySS :: IO (SizedSeq Word16)
+         lits  <- return emptySS :: IO (SizedSeq Word)
+         ptrs  <- return emptySS :: IO (SizedSeq Name)
+         itbls <- return emptySS :: IO (SizedSeq Name)
+         let init_asm_state = (insns,lits,ptrs,itbls)
+         (final_insns, final_lits, final_ptrs, final_itbls) 
+            <- mkBits findLabel init_asm_state instrs         
+
+         return (UnlinkedBCO nm final_insns final_lits final_ptrs final_itbls)
+
+-- instrs nonptrs ptrs itbls
+type AsmState = (SizedSeq Word16, SizedSeq Word, SizedSeq Name, SizedSeq Name)
+
+data SizedSeq a = SizedSeq !Int [a]
+emptySS = SizedSeq 0 []
+addToSS (SizedSeq n r_xs) x = return (SizedSeq (n+1) (x:r_xs))
+addListToSS (SizedSeq n r_xs) xs 
+   = return (SizedSeq (n + length xs) (reverse xs ++ r_xs))
+sizeSS (SizedSeq n r_xs) = n
+listFromSS (SizedSeq n r_xs) = return (reverse r_xs)
 
 
 -- This is where all the action is (pass 2 of the assembler)
-mkBits :: (Int -> Int)                 -- label finder
-       -> [Word16] -> Int      -- reverse acc instr bits
-       -> [Word32] -> Int      -- reverse acc literal bits
-       -> [Name] -> Int                -- reverse acc ptrs
-       -> [BCInstr]            -- insns!
-       -> ([Word16], [Word32], [Name])
-
-mkBits findLabel r_is n_is r_lits n_lits r_ptrs n_ptrs []
-   = (reverse r_is, reverse r_lits, reverse r_ptrs)
-mkBits findLabel r_is n_is r_lits n_lits r_ptrs n_ptrs (instr:instrs)
-   = case instr of
-        ARGCHECK  n    -> boring2 i_ARGCHECK n
-        PUSH_L    sz off -> boring3 i_PUSH_L sz off
-        PUSH_G    nm   -> exciting2_P i_PUSH_G n_ptrs nm
-        PUSHT_I   i    -> exciting2_I i_PUSHT_I n_lits i
-        PUSHT_F   f    -> exciting2_F i_PUSHT_F n_lits f
-        PUSHT_D   d    -> exciting2_D i_PUSHT_D n_lits d
-        PUSHU_I   i    -> exciting2_I i_PUSHU_I n_lits i
-        PUSHU_F   f    -> exciting2_F i_PUSHU_F n_lits f
-        PUSHU_D   d    -> exciting2_D i_PUSHU_D n_lits d
-        SLIDE     n by -> boring3 i_SLIDE n by
-        ALLOC     n    -> boring2 i_ALLOC n
-        MKAP      off sz -> boring3 i_MKAP off sz
-        UNPACK    n    -> boring2 i_UNPACK n
-        PACK      dcon sz -> exciting3_A i_PACK sz n_lits nullAddr {-findItbl dcon-}
-        LABEL     lab  -> nop
-        TESTLT_I  i l  -> exciting3_I i_TESTLT_I n_lits (findLabel l) i
-        TESTEQ_I  i l  -> exciting3_I i_TESTEQ_I n_lits (findLabel l) i
-        TESTLT_F  f l  -> exciting3_F i_TESTLT_F n_lits (findLabel l) f
-        TESTEQ_F  f l  -> exciting3_F i_TESTEQ_F n_lits (findLabel l) f
-        TESTLT_D  d l  -> exciting3_D i_TESTLT_D n_lits (findLabel l) d
-        TESTEQ_D  d l  -> exciting3_D i_TESTEQ_D n_lits (findLabel l) d
-        TESTLT_P  i l  -> exciting3_I i_TESTLT_P n_lits (findLabel l) i
-        TESTEQ_P  i l  -> exciting3_I i_TESTEQ_P n_lits (findLabel l) i
-        CASEFAIL       -> boring1 i_CASEFAIL
-        ENTER          -> boring1 i_ENTER
-     where
-        r_mkILit = reverse . mkILit
-        r_mkFLit = reverse . mkFLit
-        r_mkDLit = reverse . mkDLit
-        r_mkALit = reverse . mkALit
-
-        mkw :: Int -> Word16
-        mkw = fromIntegral
-
-        nop
-           = mkBits findLabel r_is n_is r_lits n_lits r_ptrs n_ptrs instrs
-        boring1 i1
-           = mkBits findLabel (mkw i1 : r_is) (n_is+1) 
-                    r_lits n_lits r_ptrs n_ptrs instrs
-        boring2 i1 i2 
-           = mkBits findLabel (mkw i2 : mkw i1 : r_is) (n_is+2) 
-                    r_lits n_lits r_ptrs n_ptrs instrs
-        boring3 i1 i2 i3
-           = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3) 
-                    r_lits n_lits r_ptrs n_ptrs instrs
-
-        exciting2_P i1 i2 p
-           = mkBits findLabel (mkw i2 : mkw i1 : r_is) (n_is+2) r_lits n_lits
-                    (p:r_ptrs) (n_ptrs+1) instrs
-        exciting3_P i1 i2 i3 p
-           = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3) r_lits n_lits
-                    (p:r_ptrs) (n_ptrs+1) instrs
-
-        exciting2_I i1 i2 i
-           = mkBits findLabel (mkw i2 : mkw i1 : r_is) (n_is+2) 
-                    (r_mkILit i ++ r_lits) (n_lits + intLitSz32s)
-                    r_ptrs n_ptrs instrs
-        exciting3_I i1 i2 i3 i
-           = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3) 
-                    (r_mkILit i ++ r_lits) (n_lits + intLitSz32s)
-                    r_ptrs n_ptrs instrs
-
-        exciting2_F i1 i2 f
-           = mkBits findLabel (mkw i2 : mkw i1 : r_is) (n_is+2) 
-                    (r_mkFLit f ++ r_lits) (n_lits + floatLitSz32s)
-                    r_ptrs n_ptrs instrs
-        exciting3_F i1 i2 i3 f
-           = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3) 
-                    (r_mkFLit f ++ r_lits) (n_lits + floatLitSz32s)
-                    r_ptrs n_ptrs instrs
-
-        exciting2_D i1 i2 d
-           = mkBits findLabel (mkw i2 : mkw i1 : r_is) (n_is+2) 
-                    (r_mkDLit d ++ r_lits) (n_lits + doubleLitSz32s)
-                    r_ptrs n_ptrs instrs
-        exciting3_D i1 i2 i3 d
-           = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3) 
-                    (r_mkDLit d ++ r_lits) (n_lits + doubleLitSz32s)
-                    r_ptrs n_ptrs instrs
-
-        exciting3_A i1 i2 i3 d
-           = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3) 
-                    (r_mkALit d ++ r_lits) (n_lits + addrLitSz32s)
-                    r_ptrs n_ptrs instrs
-
-
--- The size in bytes of an instruction.
-instrSizeB :: BCInstr -> Int
-instrSizeB instr
+mkBits :: (Int -> Int)                         -- label finder
+       -> AsmState
+       -> [BCInstr]                    -- instructions (in)
+       -> IO AsmState
+
+mkBits findLabel st proto_insns
+  = foldM doInstr st proto_insns
+    where
+       doInstr :: AsmState -> BCInstr -> IO AsmState
+       doInstr st i
+          = case i of
+               ARGCHECK  n        -> instr2 st i_ARGCHECK n
+               PUSH_L    o1       -> instr2 st i_PUSH_L o1
+               PUSH_LL   o1 o2    -> instr3 st i_PUSH_LL o1 o2
+               PUSH_LLL  o1 o2 o3 -> instr4 st i_PUSH_LLL o1 o2 o3
+               PUSH_G    nm       -> do (p, st2) <- ptr st nm
+                                        instr2 st2 i_PUSH_G p
+               PUSH_AS   nm pk    -> do (p, st2)  <- ptr st nm
+                                        (np, st3) <- ctoi_itbl st2 pk
+                                        instr3 st3 i_PUSH_AS p np
+               PUSH_UBX  lit nws  -> do (np, st2) <- literal st lit
+                                        instr3 st2 i_PUSH_UBX np nws
+               PUSH_TAG  tag      -> instr2 st i_PUSH_TAG tag
+               SLIDE     n by     -> instr3 st i_SLIDE n by
+               ALLOC     n        -> instr2 st i_ALLOC n
+               MKAP      off sz   -> instr3 st i_MKAP off sz
+               UNPACK    n        -> instr2 st i_UNPACK n
+               UPK_TAG   n m k    -> instr4 st i_UPK_TAG n m k
+               PACK      dcon sz  -> do (itbl_no,st2) <- itbl st dcon
+                                        instr3 st2 i_PACK itbl_no sz
+               LABEL     lab      -> return st
+               TESTLT_I  i l      -> do (np, st2) <- int st i
+                                        instr3 st2 i_TESTLT_I np (findLabel l)
+               TESTEQ_I  i l      -> do (np, st2) <- int st i
+                                        instr3 st2 i_TESTEQ_I np (findLabel l)
+               TESTLT_F  f l      -> do (np, st2) <- float st f
+                                        instr3 st2 i_TESTLT_F np (findLabel l)
+               TESTEQ_F  f l      -> do (np, st2) <- float st f
+                                        instr3 st2 i_TESTEQ_F np (findLabel l)
+               TESTLT_D  d l      -> do (np, st2) <- double st d
+                                        instr3 st2 i_TESTLT_D np (findLabel l)
+               TESTEQ_D  d l      -> do (np, st2) <- double st d
+                                        instr3 st2 i_TESTEQ_D np (findLabel l)
+               TESTLT_P  i l      -> instr3 st i_TESTLT_P i (findLabel l)
+               TESTEQ_P  i l      -> instr3 st i_TESTEQ_P i (findLabel l)
+               CASEFAIL           -> instr1 st i_CASEFAIL
+               ENTER              -> instr1 st i_ENTER
+               RETURN rep         -> do (itbl_no,st2) <- itoc_itbl st rep
+                                        instr2 st2 i_RETURN itbl_no
+
+       i2s :: Int -> Word16
+       i2s = fromIntegral
+
+       instr1 (st_i0,st_l0,st_p0,st_I0) i1
+          = do st_i1 <- addToSS st_i0 (i2s i1)
+               return (st_i1,st_l0,st_p0,st_I0)
+
+       instr2 (st_i0,st_l0,st_p0,st_I0) i1 i2
+          = do st_i1 <- addToSS st_i0 (i2s i1)
+               st_i2 <- addToSS st_i1 (i2s i2)
+               return (st_i2,st_l0,st_p0,st_I0)
+
+       instr3 (st_i0,st_l0,st_p0,st_I0) i1 i2 i3
+          = do st_i1 <- addToSS st_i0 (i2s i1)
+               st_i2 <- addToSS st_i1 (i2s i2)
+               st_i3 <- addToSS st_i2 (i2s i3)
+               return (st_i3,st_l0,st_p0,st_I0)
+
+       instr4 (st_i0,st_l0,st_p0,st_I0) i1 i2 i3 i4
+          = do st_i1 <- addToSS st_i0 (i2s i1)
+               st_i2 <- addToSS st_i1 (i2s i2)
+               st_i3 <- addToSS st_i2 (i2s i3)
+               st_i4 <- addToSS st_i3 (i2s i4)
+               return (st_i4,st_l0,st_p0,st_I0)
+
+       float (st_i0,st_l0,st_p0,st_I0) f
+          = do let ws = mkLitF f
+               st_l1 <- addListToSS st_l0 ws
+               return (sizeSS st_l0, (st_i0,st_l1,st_p0,st_I0))
+
+       double (st_i0,st_l0,st_p0,st_I0) d
+          = do let ws = mkLitD d
+               st_l1 <- addListToSS st_l0 ws
+               return (sizeSS st_l0, (st_i0,st_l1,st_p0,st_I0))
+
+       int (st_i0,st_l0,st_p0,st_I0) i
+          = do let ws = mkLitI i
+               st_l1 <- addListToSS st_l0 ws
+               return (sizeSS st_l0, (st_i0,st_l1,st_p0,st_I0))
+
+       addr (st_i0,st_l0,st_p0,st_I0) a
+          = do let ws = mkLitA a
+               st_l1 <- addListToSS st_l0 ws
+               return (sizeSS st_l0, (st_i0,st_l1,st_p0,st_I0))
+
+       ptr (st_i0,st_l0,st_p0,st_I0) p
+          = do st_p1 <- addToSS st_p0 p
+               return (sizeSS st_p0, (st_i0,st_l0,st_p1,st_I0))
+
+       itbl (st_i0,st_l0,st_p0,st_I0) dcon
+          = do st_I1 <- addToSS st_I0 (getName dcon)
+               return (sizeSS st_I0, (st_i0,st_l0,st_p0,st_I1))
+
+       literal st (MachInt j)    = int st (fromIntegral j)
+       literal st (MachFloat r)  = float st (fromRational r)
+       literal st (MachDouble r) = double st (fromRational r)
+       literal st (MachChar c)   = int st c
+
+       ctoi_itbl st pk
+          = addr st ret_itbl_addr
+            where
+               ret_itbl_addr = case pk of
+                                  PtrRep    -> stg_ctoi_ret_R1_info
+                                  IntRep    -> stg_ctoi_ret_R1_info
+                                  CharRep   -> stg_ctoi_ret_R1_info
+                                  FloatRep  -> stg_ctoi_ret_F1_info
+                                  DoubleRep -> stg_ctoi_ret_D1_info
+                                  _ -> pprPanic "mkBits.ctoi_itbl" (ppr pk)
+
+       itoc_itbl st pk
+          = addr st ret_itbl_addr
+            where
+               ret_itbl_addr = case pk of
+                                  IntRep    -> stg_gc_unbx_r1_info
+                                  FloatRep  -> stg_gc_f1_info
+                                  DoubleRep -> stg_gc_d1_info
+                     
+foreign label "stg_ctoi_ret_R1_info" stg_ctoi_ret_R1_info :: Addr
+foreign label "stg_ctoi_ret_F1_info" stg_ctoi_ret_F1_info :: Addr
+foreign label "stg_ctoi_ret_D1_info" stg_ctoi_ret_D1_info :: Addr
+
+foreign label "stg_gc_unbx_r1_info" stg_gc_unbx_r1_info :: Addr
+foreign label "stg_gc_f1_info"      stg_gc_f1_info :: Addr
+foreign label "stg_gc_d1_info"      stg_gc_d1_info :: Addr
+
+-- The size in 16-bit entities of an instruction.
+instrSize16s :: BCInstr -> Int
+instrSize16s instr
    = case instr of
-        ARGCHECK _   -> 4
-        PUSH_L   _ _ -> 6
-        PUSH_G   _   -> 4
-        PUSHT_I  _   -> 4
-        PUSHT_F  _   -> 4
-        PUSHT_D  _   -> 4
-        PUSHU_I  _   -> 4
-        PUSHU_F  _   -> 4
-        PUSHU_D  _   -> 4
-        SLIDE    _ _ -> 6
-        ALLOC    _   -> 4
-        MKAP     _ _ -> 6
-        UNPACK   _   -> 4
-        PACK     _ _ -> 6
-        LABEL    _   -> 4
-        TESTLT_I _ _ -> 6
-        TESTEQ_I _ _ -> 6
-        TESTLT_F _ _ -> 6
-        TESTEQ_F _ _ -> 6
-        TESTLT_D _ _ -> 6
-        TESTEQ_D _ _ -> 6
-        TESTLT_P _ _ -> 6
-        TESTEQ_P _ _ -> 6
-        CASEFAIL     -> 2
-        ENTER        -> 2
-
-
--- Sizes of Int, Float and Double literals, in units of 32-bitses
-intLitSz32s, floatLitSz32s, doubleLitSz32s, addrLitSz32s :: Int
-intLitSz32s    = wORD_SIZE `div` 4
-floatLitSz32s  = 1     -- Assume IEEE floats
-doubleLitSz32s = 2
-addrLitSz32s   = intLitSz32s
-
--- Make lists of 32-bit words for literals, so that when the
+        ARGCHECK _     -> 2
+        PUSH_L   _     -> 2
+        PUSH_LL  _ _   -> 3
+        PUSH_LLL _ _ _ -> 4
+        PUSH_G   _     -> 2
+        PUSH_AS  _ _   -> 3
+        PUSH_UBX _ _   -> 3
+        PUSH_TAG _     -> 2
+        SLIDE    _ _   -> 3
+        ALLOC    _     -> 2
+        MKAP     _ _   -> 3
+        UNPACK   _     -> 2
+        UPK_TAG  _ _ _ -> 4
+        PACK     _ _   -> 3
+        LABEL    _     -> 0    -- !!
+        TESTLT_I _ _   -> 3
+        TESTEQ_I _ _   -> 3
+        TESTLT_F _ _   -> 3
+        TESTEQ_F _ _   -> 3
+        TESTLT_D _ _   -> 3
+        TESTEQ_D _ _   -> 3
+        TESTLT_P _ _   -> 3
+        TESTEQ_P _ _   -> 3
+        CASEFAIL       -> 1
+        ENTER          -> 1
+        RETURN   _     -> 2
+
+
+-- Make lists of host-sized words for literals, so that when the
 -- words are placed in memory at increasing addresses, the
 -- bit pattern is correct for the host's word size and endianness.
-mkILit :: Int    -> [Word32]
-mkFLit :: Float  -> [Word32]
-mkDLit :: Double -> [Word32]
-mkALit :: Addr   -> [Word32]
+mkLitI :: Int    -> [Word]
+mkLitF :: Float  -> [Word]
+mkLitD :: Double -> [Word]
+mkLitA :: Addr   -> [Word]
 
-mkFLit f
+mkLitF f
    = runST (do
         arr <- newFloatArray ((0::Int),0)
         writeFloatArray arr 0 f
-        w0 <- readWord32Array arr 0
+        f_arr <- castSTUArray arr
+        w0 <- readWordArray f_arr 0
         return [w0]
      )
 
-mkDLit d
+mkLitD d
+   | wORD_SIZE == 4
    = runST (do
-        arr <- newDoubleArray ((0::Int),0)
+        arr <- newDoubleArray ((0::Int),1)
         writeDoubleArray arr 0 d
-        w0 <- readWord32Array arr 0
-        w1 <- readWord32Array arr 1
+        d_arr <- castSTUArray arr
+        w0 <- readWordArray d_arr 0
+        w1 <- readWordArray d_arr 1
         return [w0,w1]
      )
-
-mkILit i
-   | wORD_SIZE == 4
+   | wORD_SIZE == 8
    = runST (do
-        arr <- newIntArray ((0::Int),0)
-        writeIntArray arr 0 i
-        w0 <- readWord32Array arr 0
+        arr <- newDoubleArray ((0::Int),0)
+        writeDoubleArray arr 0 d
+        d_arr <- castSTUArray arr
+        w0 <- readWordArray d_arr 0
         return [w0]
      )
-   | wORD_SIZE == 8
+
+mkLitI i
    = runST (do
         arr <- newIntArray ((0::Int),0)
         writeIntArray arr 0 i
-        w0 <- readWord32Array arr 0
-        w1 <- readWord32Array arr 1
-        return [w0,w1]
-     )
-   
-mkALit a
-   | wORD_SIZE == 4
-   = runST (do
-        arr <- newAddrArray ((0::Int),0)
-        writeAddrArray arr 0 a
-        w0 <- readWord32Array arr 0
+        i_arr <- castSTUArray arr
+        w0 <- readWordArray i_arr 0
         return [w0]
      )
-   | wORD_SIZE == 8
+
+mkLitA a
    = runST (do
         arr <- newAddrArray ((0::Int),0)
         writeAddrArray arr 0 a
-        w0 <- readWord32Array arr 0
-        w1 <- readWord32Array arr 1
-        return [w0,w1]
+        a_arr <- castSTUArray arr
+        w0 <- readWordArray a_arr 0
+        return [w0]
      )
-   
 
+\end{code}
+
+%************************************************************************
+%*                                                                     *
+\subsection{Linking interpretables into something we can run}
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+
+{- 
+data BCO# = BCO# ByteArray#            -- instrs   :: array Word16#
+                 ByteArray#            -- literals :: array Word32#
+                 PtrArray#             -- ptrs     :: Array HValue
+                 ByteArray#            -- itbls    :: Array Addr#
+-}
+
+GLOBAL_VAR(v_cafTable, [], [HValue])
+
+--addCAF :: HValue -> IO ()
+--addCAF x = do xs <- readIORef v_cafTable; writeIORef v_cafTable (x:xs)
+
+--bcosToHValue :: ItblEnv -> ClosureEnv -> UnlinkedBCOExpr -> IO HValue
+--bcosToHValue ie ce (root_bco, other_bcos)
+--   = do linked_expr <- linkIExpr ie ce (root_bco, other_bcos)
+--     return linked_expr
+
+linkBCO ie ce (UnlinkedBCO nm insnsSS literalsSS ptrsSS itblsSS)
+   = do insns    <- listFromSS insnsSS
+        literals <- listFromSS literalsSS
+        ptrs     <- listFromSS ptrsSS
+        itbls    <- listFromSS itblsSS
+
+        linked_ptrs  <- mapM (lookupCE ce) ptrs
+        linked_itbls <- mapM (lookupIE ie) itbls
+
+        let n_insns    = sizeSS insnsSS
+            n_literals = sizeSS literalsSS
+            n_ptrs     = sizeSS ptrsSS
+            n_itbls    = sizeSS itblsSS
+
+        let ptrs_arr = array (0, n_ptrs-1) (indexify linked_ptrs)
+                       :: Array Int HValue
+            ptrs_parr = case ptrs_arr of Array lo hi parr -> parr
+
+            itbls_arr = array (0, n_itbls-1) (indexify linked_itbls)
+                        :: UArray Int Addr
+            itbls_barr = case itbls_arr of UArray lo hi barr -> barr
+
+            insns_arr | n_insns > 65535
+                      = panic "linkBCO: >= 64k insns in BCO"
+                      | otherwise 
+                      = array (0, n_insns) 
+                              (indexify (fromIntegral n_insns:insns))
+                        :: UArray Int Word16
+            insns_barr = case insns_arr of UArray lo hi barr -> barr
+
+            literals_arr = array (0, n_literals-1) (indexify literals)
+                           :: UArray Int Word
+            literals_barr = case literals_arr of UArray lo hi barr -> barr
+
+            indexify :: [a] -> [(Int, a)]
+            indexify xs = zip [0..] xs
+
+        BCO bco# <- newBCO insns_barr literals_barr ptrs_parr itbls_barr
+
+        return (unsafeCoerce# bco#)
+
+
+data BCO = BCO BCO#
+
+newBCO :: ByteArray# -> ByteArray# -> Array# a -> ByteArray# -> IO BCO
+newBCO a b c d
+   = IO (\s -> case newBCO# a b c d s of (# s1, bco #) -> (# s1, BCO bco #))
+
+
+lookupCE :: ClosureEnv -> Name -> IO HValue
+lookupCE ce nm 
+   = case lookupFM ce nm of
+        Just aa -> return aa
+        Nothing 
+           -> do m <- lookupSymbol (nameToCLabel nm "closure")
+                 case m of
+                    Just (A# addr) -> case addrToHValue# addr of
+                                         (# hval #) -> return hval
+                    Nothing        -> pprPanic "ByteCodeGen.lookupCE" (ppr nm)
+
+lookupIE :: ItblEnv -> Name -> IO Addr
+lookupIE ie con_nm 
+   = case lookupFM ie con_nm of
+        Just (Ptr a) -> return a
+        Nothing
+           -> do -- try looking up in the object files.
+                 m <- lookupSymbol (nameToCLabel con_nm "con_info")
+                 case m of
+                    Just addr -> return addr
+                    Nothing 
+                       -> do -- perhaps a nullary constructor?
+                             n <- lookupSymbol (nameToCLabel con_nm "static_info")
+                             case n of
+                                Just addr -> return addr
+                                Nothing -> pprPanic "ByteCodeGen.lookupIE" (ppr con_nm)
+
+-- HACK!!!  ToDo: cleaner
+nameToCLabel :: Name -> String{-suffix-} -> String
+nameToCLabel n suffix
+   = _UNPK_(moduleNameFS (rdrNameModule rn)) 
+     ++ '_':occNameString(rdrNameOcc rn) ++ '_':suffix
+     where rn = toRdrName n
+
+\end{code}
+
+%************************************************************************
+%*                                                                     *
+\subsection{Manufacturing of info tables for DataCons}
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+
+#if __GLASGOW_HASKELL__ <= 408
+type ItblPtr = Addr
+#else
+type ItblPtr = Ptr StgInfoTable
+#endif
+
+-- Make info tables for the data decls in this module
+mkITbls :: [TyCon] -> IO ItblEnv
+mkITbls [] = return emptyFM
+mkITbls (tc:tcs) = do itbls  <- mkITbl tc
+                      itbls2 <- mkITbls tcs
+                      return (itbls `plusFM` itbls2)
+
+mkITbl :: TyCon -> IO ItblEnv
+mkITbl tc
+   | not (isDataTyCon tc) 
+   = return emptyFM
+   | n == length dcs  -- paranoia; this is an assertion.
+   = make_constr_itbls dcs
+     where
+        dcs = tyConDataCons tc
+        n   = tyConFamilySize tc
+
+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
+   = do is <- mapM mk_vecret_itbl (zip cons [0..])
+       return (listToFM is)
+   | otherwise
+   = do is <- mapM mk_dirret_itbl (zip cons [0..])
+       return (listToFM is)
+     where
+        mk_vecret_itbl (dcon, conNo)
+           = mk_itbl dcon conNo (vecret_entry conNo)
+        mk_dirret_itbl (dcon, conNo)
+           = mk_itbl dcon conNo stg_interp_constr_entry
+
+        mk_itbl :: DataCon -> Int -> Addr -> IO (Name,ItblPtr)
+        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 <- malloc
+                    --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 (getName dcon, addr `plusPtr` 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 = stg_interp_constr1_entry
+vecret_entry 1 = stg_interp_constr2_entry
+vecret_entry 2 = stg_interp_constr3_entry
+vecret_entry 3 = stg_interp_constr4_entry
+vecret_entry 4 = stg_interp_constr5_entry
+vecret_entry 5 = stg_interp_constr6_entry
+vecret_entry 6 = stg_interp_constr7_entry
+vecret_entry 7 = stg_interp_constr8_entry
+
+-- entry point for direct returns for created constr itbls
+foreign label "stg_interp_constr_entry" stg_interp_constr_entry :: Addr
+-- and the 8 vectored ones
+foreign label "stg_interp_constr1_entry" stg_interp_constr1_entry :: Addr
+foreign label "stg_interp_constr2_entry" stg_interp_constr2_entry :: Addr
+foreign label "stg_interp_constr3_entry" stg_interp_constr3_entry :: Addr
+foreign label "stg_interp_constr4_entry" stg_interp_constr4_entry :: Addr
+foreign label "stg_interp_constr5_entry" stg_interp_constr5_entry :: Addr
+foreign label "stg_interp_constr6_entry" stg_interp_constr6_entry :: Addr
+foreign label "stg_interp_constr7_entry" stg_interp_constr7_entry :: Addr
+foreign label "stg_interp_constr8_entry" stg_interp_constr8_entry :: Addr
+
+
+
+
+
+-- 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) (castPtr 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 (castPtr 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 -> Ptr a -> IO (Ptr b)
+store x addr = do poke addr x
+                  return (castPtr (addr `plusPtr` sizeOf x))
+
+load :: Storable a => Ptr a -> IO (Ptr b, a)
+load addr = do x <- peek addr
+               return (castPtr (addr `plusPtr` sizeOf x), x)
+
+\end{code}
+
+%************************************************************************
+%*                                                                     *
+\subsection{Connect to actual values for bytecode opcodes}
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
 
-#include "../rts/Bytecodes.h"
+#include "Bytecodes.h"
 
 i_ARGCHECK = (bci_ARGCHECK :: Int)
-i_PUSH_L   = (bci_PUSH_L   :: Int)
-i_PUSH_G   = (bci_PUSH_G   :: Int)
-i_PUSHT_I  = (bci_PUSHT_I  :: Int)
-i_PUSHT_F  = (bci_PUSHT_F  :: Int)
-i_PUSHT_D  = (bci_PUSHT_D  :: Int)
-i_PUSHU_I  = (bci_PUSHU_I  :: Int)
-i_PUSHU_F  = (bci_PUSHU_F  :: Int)
-i_PUSHU_D  = (bci_PUSHU_D  :: Int)
-i_SLIDE    = (bci_SLIDE    :: Int)
-i_ALLOC    = (bci_ALLOC    :: Int)
-i_MKAP     = (bci_MKAP     :: Int)
-i_UNPACK   = (bci_UNPACK   :: Int)
-i_PACK     = (bci_PACK     :: Int)
-i_LABEL    = (bci_LABEL    :: Int)
+i_PUSH_L   = (bci_PUSH_L :: Int)
+i_PUSH_LL  = (bci_PUSH_LL :: Int)
+i_PUSH_LLL = (bci_PUSH_LLL :: Int)
+i_PUSH_G   = (bci_PUSH_G :: Int)
+i_PUSH_AS  = (bci_PUSH_AS :: Int)
+i_PUSH_UBX = (bci_PUSH_UBX :: Int)
+i_PUSH_TAG = (bci_PUSH_TAG :: Int)
+i_SLIDE    = (bci_SLIDE :: Int)
+i_ALLOC    = (bci_ALLOC :: Int)
+i_MKAP     = (bci_MKAP :: Int)
+i_UNPACK   = (bci_UNPACK :: Int)
+i_UPK_TAG  = (bci_UPK_TAG :: Int)
+i_PACK     = (bci_PACK :: Int)
 i_TESTLT_I = (bci_TESTLT_I :: Int)
 i_TESTEQ_I = (bci_TESTEQ_I :: Int)
 i_TESTLT_F = (bci_TESTLT_F :: Int)
@@ -798,6 +1541,7 @@ i_TESTEQ_D = (bci_TESTEQ_D :: Int)
 i_TESTLT_P = (bci_TESTLT_P :: Int)
 i_TESTEQ_P = (bci_TESTEQ_P :: Int)
 i_CASEFAIL = (bci_CASEFAIL :: Int)
-i_ENTER    = (bci_ENTER    :: Int)
+i_ENTER    = (bci_ENTER :: Int)
+i_RETURN   = (bci_RETURN :: Int)
 
 \end{code}