[project @ 2001-01-05 15:23:32 by sewardj]
[ghc-hetmet.git] / ghc / compiler / ghci / ByteCodeGen.lhs
index b044538..a5b10ca 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 PprCore         ( pprCoreExpr, pprCoreAlt )
-import Literal         ( Literal(..) )
+import Literal         ( Literal(..), literalPrimRep )
 import PrimRep         ( PrimRep(..) )
 import CoreFVs         ( freeVars )
 import Type            ( typePrimRep )
-import DataCon         ( DataCon, dataConTag, fIRST_TAG, dataConTyCon )
-import TyCon           ( tyConFamilySize )
-import Util            ( zipEqual, zipWith4Equal, naturalMergeSortLe, nOfThem )
+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, nullAddr, 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}
 
 %************************************************************************
 %*                                                                     *
@@ -67,26 +217,32 @@ type LocalLabel = Int
 data BCInstr
    -- Messing with the stack
    = ARGCHECK  Int
+   -- 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
-   | PUSH_AS   Name    -- push alts and BCO_ptr_ret_info
-   | 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-}
+   | 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
-   | UNPACK_I  Int     -- unpack and tag an Int, from t.o.s Constr @ offset
-   | UNPACK_F  Int     -- unpack and tag a Float, from t.o.s Constr @ offset
-   | UNPACK_D  Int     -- unpack and tag a Double, from t.o.s Constr @ offset
+   | 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
@@ -95,12 +251,18 @@ 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    -- unboxed value on TOS.  Use tag to find underlying ret itbl
+   | RETURN    PrimRep
+               -- unboxed value on TOS.  Use tag to find underlying ret itbl
                -- and return as per that.
 
 
@@ -110,15 +272,17 @@ instance Outputable BCInstr where
    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 (PUSH_AS nm)          = text "PUSH_AS " <+> 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 (UNPACK_I sz)         = text "UNPACK_I" <+> int sz
-   ppr (UNPACK_F sz)         = text "UNPACK_F" <+> int sz
-   ppr (UNPACK_D sz)         = text "UNPACK_D" <+> 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
@@ -131,11 +295,7 @@ instance Outputable BCInstr where
    ppr (TESTEQ_P  i lab)     = text "TESTEQ_P" <+> int i <+> text "__" <> int lab
    ppr CASEFAIL              = text "CASEFAIL"
    ppr ENTER                 = text "ENTER"
-   ppr RETURN                = text "RETURN"
-
-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 origin)
@@ -163,6 +323,8 @@ data ProtoBCO a
               (Either [AnnAlt Id VarSet]
                       (AnnExpr Id VarSet))
 
+nameOfProtoBCO (ProtoBCO nm insns origin) = nm
+
 
 type Sequel = Int      -- back off to this depth before ENTER
 
@@ -174,7 +336,7 @@ 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 (peep (fromOL 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
@@ -191,7 +353,19 @@ mkProtoBCO nm instrs_ordlist origin
 -- 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 rhs 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 (if isTyVar x then xs else (x:xs)) e
@@ -204,7 +378,7 @@ schemeR_wrk original_body nm (args, body)
          szsw_args = map taggedIdSizeW all_args
          szw_args  = sum szsw_args
          p_init    = listToFM (zip all_args (mkStackOffsets 0 szsw_args))
-         argcheck  = if null args then nilOL else unitOL (ARGCHECK szw_args)
+         argcheck  = {-if null args then nilOL else-} unitOL (ARGCHECK szw_args)
      in
      schemeE szw_args 0 p_init body            `thenBc` \ body_code ->
      emitBc (mkProtoBCO (getName nm) (appOL argcheck body_code) (Right original_body))
@@ -224,26 +398,31 @@ 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 (typePrimRep (idType 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
                    `snocOL` SLIDE szw (d-s)    -- clear to sequel
-                   `snocOL` RETURN)            -- go
+                   `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
                    `snocOL` SLIDE szw (d-s)    -- clear to sequel
-                   `snocOL` RETURN)            -- go
+                   `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
          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
 
          -- This p', d' defn is safe because all the items being pushed
@@ -288,8 +467,9 @@ schemeE d s p (fvs, AnnCase scrut bndr alts)
         d' = d + ret_frame_sizeW + taggedIdSizeW bndr
         p' = addToFM p bndr (d' - 1)
 
+        scrut_primrep = typePrimRep (idType bndr)
         isAlgCase
-           = case typePrimRep (idType bndr) of
+           = case scrut_primrep of
                 IntRep -> False ; FloatRep -> False ; DoubleRep -> False
                 PtrRep -> True
                 other  -> pprPanic "ByteCodeGen.schemeE" (ppr other)
@@ -303,7 +483,7 @@ schemeE d s p (fvs, AnnCase scrut bndr alts)
                  p''          = addListToFM 
                                    p' (zip binds_r (mkStackOffsets d' binds_r_szsw))
                  d''          = d' + binds_szw
-                 unpack_code  = mkUnpackCode 0 (map (typePrimRep.idType) binds_f)
+                 unpack_code  = mkUnpackCode 0 0 (map (typePrimRep.idType) binds_f)
              in schemeE d'' s p'' rhs  `thenBc` \ rhs_code -> 
                 returnBc (my_discr alt, unpack_code `appOL` rhs_code)
            | otherwise 
@@ -312,7 +492,7 @@ schemeE d s p (fvs, AnnCase scrut bndr alts)
              returnBc (my_discr alt, rhs_code)
 
         my_discr (DEFAULT, binds, rhs)  = NoDiscr
-        my_discr (DataAlt dc, binds, rhs) = DiscrP (dataConTag dc)
+        my_discr (DataAlt dc, binds, rhs) = DiscrP (dataConTag dc - fIRST_TAG)
         my_discr (LitAlt l, binds, rhs)
            = case l of MachInt i     -> DiscrI (fromInteger i)
                        MachFloat r   -> DiscrF (fromRational r)
@@ -329,14 +509,15 @@ schemeE d s p (fvs, AnnCase scrut bndr alts)
      mapBc codeAlt alts                                `thenBc` \ alt_stuff ->
      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      = mkProtoBCO alt_bco_name alt_final (Left alts)
+         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_AS 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)
@@ -353,7 +534,8 @@ 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)
    = case snd a of
@@ -366,7 +548,9 @@ schemeT enTag d s narg_words p (_, AnnApp f a)
 schemeT enTag d s narg_words p (_, AnnVar f)
    | Just con <- isDataConId_maybe f
    = ASSERT(enTag == False)
-     PACK con narg_words `consOL` (mkSLIDE 1 (d-s-1) `snocOL` 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)
@@ -388,22 +572,29 @@ should_args_be_tagged (_, other)
 
 -- Make code to unpack a constructor onto the stack, adding
 -- tags for the unboxed bits.  Takes the PrimReps of the constructor's
--- arguments, and a travelling offset along the *constructor*.
-mkUnpackCode :: Int -> [PrimRep] -> BCInstrList
-mkUnpackCode off [] = nilOL
-mkUnpackCode off (r:rs)
+-- arguments, and a travelling offset along both the constructor
+-- (off_h) and the stack (off_s).
+mkUnpackCode :: Int -> Int -> [PrimRep] -> BCInstrList
+mkUnpackCode off_h off_s [] = nilOL
+mkUnpackCode off_h off_s (r:rs)
    | isFollowableRep r
    = let (rs_ptr, rs_nptr) = span isFollowableRep (r:rs)
          ptrs_szw = sum (map untaggedSizeW rs_ptr) 
      in  ASSERT(ptrs_szw == length rs_ptr)
-         UNPACK ptrs_szw `consOL` mkUnpackCode (off+ptrs_szw) rs_nptr
+         ASSERT(off_h == 0)
+         ASSERT(off_s == 0)
+         UNPACK ptrs_szw 
+         `consOL` mkUnpackCode (off_h + ptrs_szw) (off_s + ptrs_szw) rs_nptr
    | otherwise
    = case r of
-        IntRep    -> UNPACK_I off `consOL` theRest
-        FloatRep  -> UNPACK_F off `consOL` theRest
-        DoubleRep -> UNPACK_D off `consOL` theRest
+        IntRep    -> approved
+        FloatRep  -> approved
+        DoubleRep -> approved
      where
-        theRest = mkUnpackCode (off+untaggedSizeW r) rs
+        approved = UPK_TAG usizeW off_h off_s   `consOL` theRest
+        theRest  = mkUnpackCode (off_h + usizeW) (off_s + tsizeW) rs
+        usizeW   = untaggedSizeW r
+        tsizeW   = taggedSizeW r
 
 -- Push an atom onto the stack, returning suitable code & number of
 -- stack words used.  Pushes it either tagged or untagged, since 
@@ -444,7 +635,10 @@ pushAtom tagged d p (AnnVar v)
                  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     = getName v
+         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
@@ -453,16 +647,51 @@ pushAtom tagged d p (AnnVar v)
          result
 
 pushAtom True d p (AnnLit lit)
-   = case lit of
-        MachInt i    -> (unitOL (PUSHT_I (fromInteger i)),  taggedSizeW IntRep)
-        MachFloat r  -> (unitOL (PUSHT_F (fromRational r)), taggedSizeW FloatRep)
-        MachDouble r -> (unitOL (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    -> (unitOL (PUSHU_I (fromInteger i)),  untaggedSizeW IntRep)
-        MachFloat r  -> (unitOL (PUSHU_F (fromRational r)), untaggedSizeW FloatRep)
-        MachDouble r -> (unitOL (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)
@@ -471,6 +700,8 @@ 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.
@@ -543,7 +774,7 @@ mkMultiBranch maybe_ncons raw_ways
 
          (algMinBound, algMaxBound)
             = case maybe_ncons of
-                 Just n  -> (fIRST_TAG, fIRST_TAG + n - 1)
+                 Just n  -> (0, n - 1)
                  Nothing -> (minBound, maxBound)
 
          (DiscrI i1) `eqAlt` (DiscrI i2) = i1 == i2
@@ -606,12 +837,12 @@ instance Outputable Discr where
 
 -- Find things in the BCEnv (the what's-on-the-stack-env)
 -- 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 :: 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
@@ -650,9 +881,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 }
 
@@ -698,261 +926,603 @@ 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 Name -> IO UnlinkedBCO
+
 assembleBCO (ProtoBCO nm instrs origin)
    = let
-         -- pass 1: collect up the offsets of the local labels
-         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    off      -> boring2 i_PUSH_L off
-        PUSH_LL   o1 o2    -> boring3 i_PUSH_LL o1 o2
-        PUSH_LLL  o1 o2 o3 -> boring4 i_PUSH_LLL o1 o2 o3
-        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
-        RETURN             -> boring1 i_RETURN
-     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
-        boring4 i1 i2 i3 i4
-           = mkBits findLabel (mkw i4 : mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+4) 
-                    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
+                                  FloatRep  -> stg_ctoi_ret_F1_info
+                                  DoubleRep -> stg_ctoi_ret_D1_info
+                                  _ -> pprPanic "mkBits.ctoi_itbl" (ppr pk)
+                               where  -- TEMP HACK
+                                  stg_ctoi_ret_F1_info = nullAddr
+                                  stg_ctoi_ret_D1_info = nullAddr
+
+       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   _     -> 4
-        PUSH_LL  _ _   -> 6
-        PUSH_LLL _ _ _ -> 8
-        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
-        RETURN         -> 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)
         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_LL  = (bci_PUSH_LL  :: 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_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_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)
@@ -962,7 +1532,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_RETURN   = (bci_RETURN   :: Int)
+i_ENTER    = (bci_ENTER :: Int)
+i_RETURN   = (bci_RETURN :: Int)
 
 \end{code}