(F)SLIT -> (f)sLit in ByteCodeGen
[ghc-hetmet.git] / compiler / ghci / ByteCodeGen.lhs
index ca66250..b4d026a 100644 (file)
@@ -5,15 +5,23 @@
 ByteCodeGen: Generate bytecode from Core
 
 \begin{code}
+{-# OPTIONS -w #-}
+-- The above warning supression flag is a temporary kludge.
+-- While working on this module you are encouraged to remove it and fix
+-- any warnings in the module. See
+--     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
+-- for details
+
 module ByteCodeGen ( UnlinkedBCO, byteCodeGen, coreExprToBCOs ) where
 
 #include "HsVersions.h"
 
 import ByteCodeInstr
 import ByteCodeItbls
-import ByteCodeFFI
 import ByteCodeAsm
 import ByteCodeLink
+import ByteCodeFFI
+import LibFFI
 
 import Outputable
 import Name
@@ -48,8 +56,7 @@ import OrdList
 import Constants
 
 import Data.List       ( intersperse, sortBy, zip4, zip6, partition )
-import Foreign         ( Ptr, castPtr, mallocBytes, pokeByteOff, Word8,
-                         withForeignPtr, castFunPtrToPtr, nullPtr, plusPtr )
+import Foreign
 import Foreign.C
 import Control.Exception       ( throwDyn )
 
@@ -103,7 +110,7 @@ coreExprToBCOs dflags expr
 
       -- create a totally bogus name for the top-level BCO; this
       -- should be harmless, since it's never used for anything
-      let invented_name  = mkSystemVarName (mkPseudoUniqueE 0) FSLIT("ExprTopLevel")
+      let invented_name  = mkSystemVarName (mkPseudoUniqueE 0) (fsLit "ExprTopLevel")
           invented_id    = Id.mkLocalId invented_name (panic "invented_id's type")
          
       -- the uniques are needed to generate fresh variables when we introduce new
@@ -171,17 +178,19 @@ mkProtoBCO nm instrs_ordlist origin arity bitmap_size bitmap is_ret mallocd_bloc
         -- (hopefully rare) cases when the (overestimated) stack use
         -- exceeds iNTERP_STACK_CHECK_THRESH.
         maybe_with_stack_check
-          | is_ret = peep_d
-               -- don't do stack checks at return points;
+          | is_ret && stack_usage < aP_STACK_SPLIM = peep_d
+               -- don't do stack checks at return points,
                -- everything is aggregated up to the top BCO
-               -- (which must be a function)
-           | stack_overest >= iNTERP_STACK_CHECK_THRESH
-           = STKCHECK stack_overest : peep_d
+               -- (which must be a function).
+                -- That is, unless the stack usage is >= AP_STACK_SPLIM,
+                -- see bug #1466.
+           | stack_usage >= iNTERP_STACK_CHECK_THRESH
+           = STKCHECK stack_usage : peep_d
            | otherwise
            = peep_d    -- the supposedly common case
              
         -- We assume that this sum doesn't wrap
-        stack_overest = sum (map bciStackUse peep_d)
+        stack_usage = sum (map bciStackUse peep_d)
 
         -- Merge local pushes
         peep_d = peep (fromOL instrs_ordlist)
@@ -298,6 +307,7 @@ schemeER_wrk d p rhs
                         { breakInfo_module = tickInfo_module tickInfo
                         , breakInfo_number = tickNumber 
                         , breakInfo_vars = idOffSets
+                        , breakInfo_resty = exprType (deAnnotate' newRhs)
                         }
         let breakInstr = case arr of (BA arr#) -> BRK_FUN arr# tickNumber breakInfo 
         return $ breakInstr `consOL` code
@@ -417,9 +427,15 @@ schemeE d s p (AnnLet binds (_,body))
               return (push_code `appOL` more_push_code)
 
          alloc_code = toOL (zipWith mkAlloc sizes arities)
-          where mkAlloc sz 0     = ALLOC_AP sz
+          where mkAlloc sz 0
+                    | is_tick     = ALLOC_AP_NOUPD sz
+                    | otherwise   = ALLOC_AP sz
                 mkAlloc sz arity = ALLOC_PAP arity sz
 
+         is_tick = case binds of 
+                     AnnNonRec id _ -> occNameFS (getOccName id) == tickFS
+                     _other -> False
+
         compile_bind d' fvs x rhs size arity off = do
                bco <- schemeR fvs (x,rhs)
                build_thunk d' fvs size bco off arity
@@ -434,18 +450,24 @@ schemeE d s p (AnnLet binds (_,body))
      thunk_codes <- sequence compile_binds
      return (alloc_code `appOL` concatOL thunk_codes `appOL` body_code)
 
--- introduce a let binding for a ticked case expression. This rule *should* only fire when the
--- expression was not already let-bound (the code gen for let bindings should take care of that). 
--- Todo: we call exprFreeVars on a deAnnotated expression, this may not be the best way
--- to calculate the free vars but it seemed like the least intrusive thing to do
+-- introduce a let binding for a ticked case expression. This rule
+-- *should* only fire when the expression was not already let-bound
+-- (the code gen for let bindings should take care of that).  Todo: we
+-- call exprFreeVars on a deAnnotated expression, this may not be the
+-- best way to calculate the free vars but it seemed like the least
+-- intrusive thing to do
 schemeE d s p exp@(AnnCase {})
-   | Just (tickInfo, _exp) <- isTickedExp' exp = do 
-        let fvs = exprFreeVars $ deAnnotate' exp
-        let ty = exprType $ deAnnotate' exp
-        id <- newId ty
-        -- Todo: is emptyVarSet correct on the next line?
-        let letExp = AnnLet (AnnNonRec id (fvs, exp)) (emptyVarSet, AnnVar id)
-        schemeE d s p letExp
+   | Just (tickInfo,rhs) <- isTickedExp' exp
+   = if isUnLiftedType ty
+        then schemeE d s p (snd rhs)
+        else do
+          id <- newId ty
+          -- Todo: is emptyVarSet correct on the next line?
+          let letExp = AnnLet (AnnNonRec id (fvs, exp)) (emptyVarSet, AnnVar id)
+          schemeE d s p letExp
+   where exp' = deAnnotate' exp
+         fvs  = exprFreeVars exp'
+         ty   = exprType exp'
 
 schemeE d s p (AnnCase scrut bndr _ [(DataAlt dc, [bind1, bind2], rhs)])
    | isUnboxedTupleCon dc, VoidArg <- typeCgRep (idType bind1)
@@ -910,18 +932,18 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l
                     | t == arrayPrimTyCon || t == mutableArrayPrimTyCon
                        -> do rest <- pargs (d + addr_sizeW) az
                              code <- parg_ArrayishRep arrPtrsHdrSize d p a
-                             return ((code,NonPtrArg):rest)
+                             return ((code,AddrRep):rest)
 
                     | t == byteArrayPrimTyCon || t == mutableByteArrayPrimTyCon
                        -> do rest <- pargs (d + addr_sizeW) az
                              code <- parg_ArrayishRep arrWordsHdrSize d p a
-                             return ((code,NonPtrArg):rest)
+                             return ((code,AddrRep):rest)
 
                     -- Default case: push taggedly, but otherwise intact.
                     other
                        -> do (code_a, sz_a) <- pushAtom d p a
                              rest <- pargs (d+sz_a) az
-                             return ((code_a, atomRep a) : rest)
+                             return ((code_a, atomPrimRep a) : rest)
 
          -- Do magic for Ptr/Byte arrays.  Push a ptr to the array on
          -- the stack but then advance it over the headers, so as to
@@ -938,9 +960,9 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l
          (pushs_arg, a_reps_pushed_r_to_l) = unzip code_n_reps
 
          push_args    = concatOL pushs_arg
-         d_after_args = d0 + sum (map cgRepSizeW a_reps_pushed_r_to_l)
+         d_after_args = d0 + sum (map primRepSizeW a_reps_pushed_r_to_l)
          a_reps_pushed_RAW
-            | null a_reps_pushed_r_to_l || head a_reps_pushed_r_to_l /= VoidArg
+            | null a_reps_pushed_r_to_l || head a_reps_pushed_r_to_l /= VoidRep
             = panic "ByteCodeGen.generateCCall: missing or invalid World token?"
             | otherwise
             = reverse (tail a_reps_pushed_r_to_l)
@@ -952,7 +974,7 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l
          -- Get the result rep.
          (returns_void, r_rep)
             = case maybe_getCCallReturnRep (idType fn) of
-                 Nothing -> (True,  VoidArg)
+                 Nothing -> (True,  VoidRep)
                  Just rr -> (False, rr) 
          {-
          Because the Haskell stack grows down, the a_reps refer to 
@@ -1018,7 +1040,7 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l
 
          -- Push the return placeholder.  For a call returning nothing,
          -- this is a VoidArg (tag).
-         r_sizeW   = cgRepSizeW r_rep
+         r_sizeW   = primRepSizeW r_rep
          d_after_r = d_after_Addr + r_sizeW
          r_lit     = mkDummyLiteral r_rep
          push_r    = (if   returns_void 
@@ -1030,24 +1052,28 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l
          addr_offW    = r_sizeW
          arg1_offW    = r_sizeW + addr_sizeW
          args_offW    = map (arg1_offW +) 
-                            (init (scanl (+) 0 (map cgRepSizeW a_reps)))
-     -- in
-     addr_of_marshaller <- ioToBc (mkMarshalCode cconv
-                                (r_offW, r_rep) addr_offW
-                                (zip args_offW a_reps))
-     recordItblMallocBc (ItblPtr (castFunPtrToPtr addr_of_marshaller))
-     let
+                            (init (scanl (+) 0 (map primRepSizeW a_reps)))
+
         -- Offset of the next stack frame down the stack.  The CCALL
         -- instruction needs to describe the chunk of stack containing
         -- the ccall args to the GC, so it needs to know how large it
         -- is.  See comment in Interpreter.c with the CCALL instruction.
         stk_offset   = d_after_r - s
 
+     -- in
+     -- the only difference in libffi mode is that we prepare a cif
+     -- describing the call type by calling libffi, and we attach the
+     -- address of this to the CCALL instruction.
+     token <- ioToBc $ prepForeignCall cconv a_reps r_rep
+     let addr_of_marshaller = castPtrToFunPtr token
+
+     recordItblMallocBc (ItblPtr (castFunPtrToPtr addr_of_marshaller))
+     let
          -- do the call
          do_call      = unitOL (CCALL stk_offset (castFunPtrToPtr addr_of_marshaller))
          -- slide and return
          wrapup       = mkSLIDE r_sizeW (d_after_r - r_sizeW - s)
-                        `snocOL` RETURN_UBX r_rep
+                        `snocOL` RETURN_UBX (primRepToCgRep r_rep)
      --in
          --trace (show (arg1_offW, args_offW  ,  (map cgRepSizeW a_reps) )) $
      return (
@@ -1055,17 +1081,19 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l
          push_Addr `appOL` push_r `appOL` do_call `appOL` wrapup
          )
 
-
 -- Make a dummy literal, to be used as a placeholder for FFI return
 -- values on the stack.
-mkDummyLiteral :: CgRep -> Literal
+mkDummyLiteral :: PrimRep -> Literal
 mkDummyLiteral pr
    = case pr of
-        NonPtrArg -> MachWord 0
-        DoubleArg -> MachDouble 0
-        FloatArg  -> MachFloat 0
-        LongArg   -> MachWord64 0
-        _         -> moan64 "mkDummyLiteral" (ppr pr)
+        IntRep    -> MachInt 0
+        WordRep   -> MachWord 0
+        AddrRep   -> MachNullAddr
+        DoubleRep -> MachDouble 0
+        FloatRep  -> MachFloat 0
+        Int64Rep  -> MachInt64 0
+        Word64Rep -> MachWord64 0
+        _         -> panic "mkDummyLiteral"
 
 
 -- Convert (eg) 
@@ -1082,21 +1110,21 @@ mkDummyLiteral pr
 --
 -- to  Nothing
 
-maybe_getCCallReturnRep :: Type -> Maybe CgRep
+maybe_getCCallReturnRep :: Type -> Maybe PrimRep
 maybe_getCCallReturnRep fn_ty
    = let (a_tys, r_ty) = splitFunTys (dropForAlls fn_ty)
          maybe_r_rep_to_go  
             = if isSingleton r_reps then Nothing else Just (r_reps !! 1)
          (r_tycon, r_reps) 
             = case splitTyConApp_maybe (repType r_ty) of
-                      (Just (tyc, tys)) -> (tyc, map typeCgRep tys)
+                      (Just (tyc, tys)) -> (tyc, map typePrimRep tys)
                       Nothing -> blargh
-         ok = ( ( r_reps `lengthIs` 2 && VoidArg == head r_reps)
-                || r_reps == [VoidArg] )
+         ok = ( ( r_reps `lengthIs` 2 && VoidRep == head r_reps)
+                || r_reps == [VoidRep] )
               && isUnboxedTupleTyCon r_tycon
               && case maybe_r_rep_to_go of
                     Nothing    -> True
-                    Just r_rep -> r_rep /= PtrArg
+                    Just r_rep -> r_rep /= PtrRep
                                   -- if it was, it would be impossible 
                                   -- to create a valid return value 
                                   -- placeholder on the stack
@@ -1369,13 +1397,14 @@ lookupBCEnv_maybe = lookupFM
 idSizeW :: Id -> Int
 idSizeW id = cgRepSizeW (typeCgRep (idType id))
 
+-- See bug #1257
 unboxedTupleException :: a
 unboxedTupleException 
    = throwDyn 
-        (Panic 
-           ("Bytecode generator can't handle unboxed tuples.  Possibly due\n" ++
-            "\tto foreign import/export decls in source.  Workaround:\n" ++
-            "\tcompile this module to a .o file, then restart session."))
+        (ProgramError 
+           ("Error: bytecode compiler can't handle unboxed tuples.\n"++
+            "  Possibly due to foreign import/export decls in source.\n"++
+            "  Workaround: use -fobject-code, or compile this module to .o separately."))
 
 
 mkSLIDE n d = if d == 0 then nilOL else unitOL (SLIDE n d)
@@ -1397,19 +1426,22 @@ isTypeAtom (AnnType _) = True
 isTypeAtom _           = False
 
 isVoidArgAtom :: AnnExpr' id ann -> Bool
-isVoidArgAtom (AnnVar v)        = typeCgRep (idType v) == VoidArg
+isVoidArgAtom (AnnVar v)        = typePrimRep (idType v) == VoidRep
 isVoidArgAtom (AnnNote n (_,e)) = isVoidArgAtom e
 isVoidArgAtom (AnnCast (_,e) _) = isVoidArgAtom e
 isVoidArgAtom _                = False
 
+atomPrimRep :: AnnExpr' Id ann -> PrimRep
+atomPrimRep (AnnVar v)    = typePrimRep (idType v)
+atomPrimRep (AnnLit l)    = typePrimRep (literalType l)
+atomPrimRep (AnnNote n b) = atomPrimRep (snd b)
+atomPrimRep (AnnApp f (_, AnnType _)) = atomPrimRep (snd f)
+atomPrimRep (AnnLam x e) | isTyVar x = atomPrimRep (snd e)
+atomPrimRep (AnnCast b _) = atomPrimRep (snd b)
+atomPrimRep other = pprPanic "atomPrimRep" (ppr (deAnnotate (undefined,other)))
+
 atomRep :: AnnExpr' Id ann -> CgRep
-atomRep (AnnVar v)    = typeCgRep (idType v)
-atomRep (AnnLit l)    = typeCgRep (literalType l)
-atomRep (AnnNote n b) = atomRep (snd b)
-atomRep (AnnApp f (_, AnnType _)) = atomRep (snd f)
-atomRep (AnnLam x e) | isTyVar x = atomRep (snd e)
-atomRep (AnnCast b _) = atomRep (snd b)
-atomRep other = pprPanic "atomRep" (ppr (deAnnotate (undefined,other)))
+atomRep e = primRepToCgRep (atomPrimRep e)
 
 isPtrAtom :: AnnExpr' Id ann -> Bool
 isPtrAtom e = atomRep e == PtrArg
@@ -1446,7 +1478,7 @@ runBc :: UniqSupply -> ModBreaks -> BcM r -> IO (BcM_State, r)
 runBc us modBreaks (BcM m) 
    = m (BcM_State us 0 [] breakArray)   
    where
-   breakArray = modBreaks_array modBreaks
+   breakArray = modBreaks_flags modBreaks
 
 thenBc :: BcM a -> (a -> BcM b) -> BcM b
 thenBc (BcM expr) cont = BcM $ \st0 -> do
@@ -1502,5 +1534,7 @@ newUnique = BcM $
 newId :: Type -> BcM Id
 newId ty = do 
     uniq <- newUnique
-    return $ mkSysLocal FSLIT("ticked") uniq ty
+    return $ mkSysLocal tickFS uniq ty
+
+tickFS = fsLit "ticked"
 \end{code}