[project @ 2001-08-08 14:40:01 by sewardj]
[ghc-hetmet.git] / ghc / compiler / ghci / ByteCodeLink.lhs
index 22a083e..310f6c4 100644 (file)
@@ -5,7 +5,9 @@
 
 \begin{code}
 module ByteCodeLink ( UnlinkedBCO, UnlinkedBCOExpr, assembleBCO,
-                     ClosureEnv, HValue, linkSomeBCOs, filterNameMap
+                     ClosureEnv, HValue, filterNameMap,
+                     linkIModules, linkIExpr,
+                     iNTERP_STACK_CHECK_THRESH
                   ) where
 
 #include "HsVersions.h"
@@ -28,22 +30,26 @@ import ByteCodeInstr        ( BCInstr(..), ProtoBCO(..) )
 import ByteCodeItbls   ( ItblEnv, ItblPtr )
 
 
-import Monad           ( foldM )
+import Monad           ( when, foldM )
 import ST              ( runST )
+import IArray          ( array )
 import MArray          ( castSTUArray, 
                          newFloatArray, writeFloatArray,
                          newDoubleArray, writeDoubleArray,
                          newIntArray, writeIntArray,
-                         newAddrArray, writeAddrArray )
-import Foreign         ( Word16, Ptr(..) )
-import Addr            ( Word, Addr )
+                         newAddrArray, writeAddrArray,
+                         readWordArray )
+import Foreign         ( Word16, Ptr(..), free )
+import Addr            ( Word, Addr(..), nullAddr )
+import Weak            ( addFinalizer )
+import FiniteMap
 
 import PrelBase                ( Int(..) )
 import PrelGHC         ( BCO#, newBCO#, unsafeCoerce#, 
                          ByteArray#, Array#, addrToHValue#, mkApUpd0# )
 import IOExts          ( fixIO )
-import ArrayBase       
 import PrelArr         ( Array(..) )
+import ArrayBase       ( UArray(..) )
 import PrelIOBase      ( IO(..) )
 
 \end{code}
@@ -55,6 +61,25 @@ import PrelIOBase    ( IO(..) )
 %************************************************************************
 
 \begin{code}
+-- 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 True 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 False ie ce aux_ul_bcos
+        (_, [root_bco]) <- linkSomeBCOs False ie aux_ce [root_ul_bco]
+        return root_bco
 
 -- Link a bunch of BCOs and return them + updated closure env.
 linkSomeBCOs :: Bool   -- False <=> add _all_ BCOs to returned closure env
@@ -73,7 +98,10 @@ linkSomeBCOs toplevs_only ie ce_in ul_bcos
             ce_top_additions = filter (isGlobalName.fst) ce_all_additions
             ce_additions     = if toplevs_only then ce_top_additions 
                                                else ce_all_additions
-            ce_out = addListToFM ce_in ce_additions
+            ce_out = -- make sure we're not inserting duplicate names into the 
+                    -- closure environment, which leads to trouble.
+                    ASSERT (all (not . (`elemFM` ce_in)) (map fst ce_additions))
+                    addListToFM ce_in ce_additions
         return (ce_out, hvals)
      where
         -- A lazier zip, in which no demand is propagated to the second
@@ -109,11 +137,13 @@ instance Outputable UnlinkedBCO where
 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
+-- remove all entries for a given set of modules from the environment;
+-- note that this removes all local names too (ie. temporary bindings from
+-- the command line).
 filterNameMap :: [ModuleName] -> FiniteMap Name a -> FiniteMap Name a
 filterNameMap mods env 
-   = filterFM (\n _ -> moduleName (nameModule n) `notElem` mods) env
-
+   = filterFM (\n _ -> isGlobalName n && 
+                       moduleName (nameModule n) `elem` mods) env
 \end{code}
 
 %************************************************************************
@@ -133,7 +163,7 @@ this BCO.
 -- Top level assembler fn.
 assembleBCO :: ProtoBCO Name -> IO UnlinkedBCO
 
-assembleBCO (ProtoBCO nm instrs origin)
+assembleBCO (ProtoBCO nm instrs origin malloced)
    = let
          -- pass 1: collect up the offsets of the local labels.
          -- Remember that the first insn starts at offset 1 since offset 0
@@ -158,9 +188,14 @@ assembleBCO (ProtoBCO nm instrs origin)
          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         
+            <- mkBits findLabel init_asm_state instrs
 
-         return (UnlinkedBCO nm final_insns final_lits final_ptrs final_itbls)
+         let ul_bco = UnlinkedBCO nm final_insns final_lits final_ptrs final_itbls
+         when (not (null malloced)) (addFinalizer ul_bco (mapM_ zonk malloced))
+         return ul_bco
+     where
+         zonk (A# a#) = do -- putStrLn ("freeing malloc'd block at " ++ show (A# a#))
+                           free (Ptr a#)
 
 -- instrs nonptrs ptrs itbls
 type AsmState = (SizedSeq Word16, SizedSeq Word, 
@@ -188,6 +223,7 @@ mkBits findLabel st proto_insns
        doInstr st i
           = case i of
                ARGCHECK  n        -> instr2 st i_ARGCHECK n
+               STKCHECK  n        -> instr2 st i_STKCHECK 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
@@ -196,8 +232,13 @@ mkBits findLabel st proto_insns
                PUSH_AS   nm pk    -> do (p, st2)  <- ptr st (Left nm)
                                         (np, st3) <- ctoi_itbl st2 pk
                                         instr3 st3 i_PUSH_AS p np
-               PUSH_UBX  lit nws  -> do (np, st2) <- literal st lit
+               PUSH_UBX  (Left lit) nws  
+                                  -> do (np, st2) <- literal st lit
                                         instr3 st2 i_PUSH_UBX np nws
+               PUSH_UBX  (Right aa) nws  
+                                  -> do (np, st2) <- addr st aa
+                                        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
@@ -222,9 +263,12 @@ mkBits findLabel st proto_insns
                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
+               JMP       l        -> instr2 st i_JMP (findLabel l)
                ENTER              -> instr1 st i_ENTER
-               RETURN rep         -> do (itbl_no,st2) <- itoc_itbl st rep
+               RETURN    rep      -> do (itbl_no,st2) <- itoc_itbl st rep
                                         instr2 st2 i_RETURN itbl_no
+               CCALL     m_addr   -> do (np, st2) <- addr st m_addr
+                                        instr2 st2 i_CCALL np
 
        i2s :: Int -> Word16
        i2s = fromIntegral
@@ -284,42 +328,52 @@ mkBits findLabel st proto_insns
        literal st (MachFloat r)  = float st (fromRational r)
        literal st (MachDouble r) = double st (fromRational r)
        literal st (MachChar c)   = int st c
+       literal st other          = pprPanic "ByteCodeLink.literal" (ppr other)
 
        ctoi_itbl st pk
           = addr st ret_itbl_addr
             where
-               ret_itbl_addr = case pk of
-                                  PtrRep    -> stg_ctoi_ret_R1p_info
-                                  WordRep   -> stg_ctoi_ret_R1n_info
-                                  IntRep    -> stg_ctoi_ret_R1n_info
-                                  AddrRep   -> stg_ctoi_ret_R1n_info
-                                  CharRep   -> stg_ctoi_ret_R1n_info
-                                  FloatRep  -> stg_ctoi_ret_F1_info
-                                  DoubleRep -> stg_ctoi_ret_D1_info
-                                  _ -> pprPanic "mkBits.ctoi_itbl" (ppr pk)
+               ret_itbl_addr 
+                  = case pk of
+                       PtrRep    -> stg_ctoi_ret_R1p_info
+                       WordRep   -> stg_ctoi_ret_R1n_info
+                       IntRep    -> stg_ctoi_ret_R1n_info
+                       AddrRep   -> stg_ctoi_ret_R1n_info
+                       CharRep   -> stg_ctoi_ret_R1n_info
+                       FloatRep  -> stg_ctoi_ret_F1_info
+                       DoubleRep -> stg_ctoi_ret_D1_info
+                       VoidRep   -> stg_ctoi_ret_V_info
+                       other     -> pprPanic "ByteCodeLink.ctoi_itbl" (ppr pk)
 
        itoc_itbl st pk
           = addr st ret_itbl_addr
             where
-               ret_itbl_addr = case pk of
-                                  CharRep   -> stg_gc_unbx_r1_info
-                                  IntRep    -> stg_gc_unbx_r1_info
-                                  FloatRep  -> stg_gc_f1_info
-                                  DoubleRep -> stg_gc_d1_info
+               ret_itbl_addr 
+                  = case pk of
+                       CharRep   -> stg_gc_unbx_r1_ret_info
+                       IntRep    -> stg_gc_unbx_r1_ret_info
+                       AddrRep   -> stg_gc_unbx_r1_ret_info
+                       FloatRep  -> stg_gc_f1_ret_info
+                       DoubleRep -> stg_gc_d1_ret_info
+                       VoidRep   -> nullAddr  
+                       -- Interpreter.c spots this special case
+                       other     -> pprPanic "ByteCodeLink.itoc_itbl" (ppr pk)
                      
 foreign label "stg_ctoi_ret_R1p_info" stg_ctoi_ret_R1p_info :: Addr
 foreign label "stg_ctoi_ret_R1n_info" stg_ctoi_ret_R1n_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_ctoi_ret_V_info"   stg_ctoi_ret_V_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
+foreign label "stg_gc_unbx_r1_ret_info" stg_gc_unbx_r1_ret_info :: Addr
+foreign label "stg_gc_f1_ret_info"      stg_gc_f1_ret_info :: Addr
+foreign label "stg_gc_d1_ret_info"      stg_gc_d1_ret_info :: Addr
 
 -- The size in 16-bit entities of an instruction.
 instrSize16s :: BCInstr -> Int
 instrSize16s instr
    = case instr of
+        STKCHECK _     -> 2
         ARGCHECK _     -> 2
         PUSH_L   _     -> 2
         PUSH_LL  _ _   -> 3
@@ -343,6 +397,7 @@ instrSize16s instr
         TESTEQ_D _ _   -> 3
         TESTLT_P _ _   -> 3
         TESTEQ_P _ _   -> 3
+        JMP      _     -> 2
         CASEFAIL       -> 1
         ENTER          -> 1
         RETURN   _     -> 2
@@ -413,8 +468,8 @@ mkLitA a
 \begin{code}
 
 {- 
-data BCO# = BCO# ByteArray#            -- instrs   :: array Word16#
-                 ByteArray#            -- literals :: array Word32#
+data BCO# = BCO# ByteArray#            -- instrs   :: Array Word16#
+                 ByteArray#            -- literals :: Array Word32#
                  PtrArray#             -- ptrs     :: Array HValue
                  ByteArray#            -- itbls    :: Array Addr#
 -}
@@ -476,7 +531,7 @@ lookupCE ce (Right primop)
         case m of
            Just (Ptr addr) -> case addrToHValue# addr of
                                  (# hval #) -> return hval
-           Nothing -> pprPanic "ByteCodeGen.lookupCE(primop)" (ppr primop)
+           Nothing -> pprPanic "ByteCodeLink.lookupCE(primop)" (ppr primop)
 lookupCE ce (Left nm)
    = case lookupFM ce nm of
         Just aa -> return aa
@@ -485,7 +540,7 @@ lookupCE ce (Left nm)
                  case m of
                     Just (Ptr addr) -> case addrToHValue# addr of
                                           (# hval #) -> return hval
-                    Nothing        -> pprPanic "ByteCodeGen.lookupCE" (ppr nm)
+                    Nothing        -> pprPanic "ByteCodeLink.lookupCE" (ppr nm)
 
 lookupIE :: ItblEnv -> Name -> IO (Ptr a)
 lookupIE ie con_nm 
@@ -501,7 +556,7 @@ lookupIE ie con_nm
                              n <- lookupSymbol (nameToCLabel con_nm "static_info")
                              case n of
                                 Just addr -> return addr
-                                Nothing -> pprPanic "ByteCodeGen.lookupIE" (ppr con_nm)
+                                Nothing -> pprPanic "ByteCodeLink.lookupIE" (ppr con_nm)
 
 -- HACKS!!!  ToDo: cleaner
 nameToCLabel :: Name -> String{-suffix-} -> String
@@ -553,5 +608,14 @@ i_TESTEQ_P = (bci_TESTEQ_P :: Int)
 i_CASEFAIL = (bci_CASEFAIL :: Int)
 i_ENTER    = (bci_ENTER :: Int)
 i_RETURN   = (bci_RETURN :: Int)
+i_STKCHECK = (bci_STKCHECK :: Int)
+i_JMP      = (bci_JMP :: Int)
+#ifdef bci_CCALL
+i_CCALL    = (bci_CCALL :: Int)
+#else
+i_CCALL    = error "Sorry pal, you need to bootstrap to use i_CCALL."
+#endif
+
+iNTERP_STACK_CHECK_THRESH = (INTERP_STACK_CHECK_THRESH :: Int)
 
 \end{code}