module UHC.Light.Compiler.CoreRun.Run.Val.RunExplStk
( cmodRun )
where
import UHC.Light.Compiler.Base.HsName.Builtin
import UHC.Light.Compiler.Base.Common
import UHC.Light.Compiler.Opts
import UHC.Light.Compiler.Ty
import UHC.Light.Compiler.Error
import UHC.Light.Compiler.Gam
import UHC.Light.Compiler.Gam.DataGam
import UHC.Light.Compiler.CoreRun
import UHC.Light.Compiler.CoreRun.Run
import UHC.Light.Compiler.CoreRun.Run.Val
import UHC.Light.Compiler.CoreRun.Run.Val.Prim
import UHC.Light.Compiler.CoreRun.Pretty
import UHC.Util.Pretty
import qualified Data.Vector as V
import qualified Data.Vector.Mutable as MV
import qualified Data.ByteString.Char8 as BSC8
explStkAllocFrameM :: (RunSem RValCxt RValEnv RVal m x) => Ref2Nm -> HpPtr -> Int -> Int -> Int -> RValT m HpPtr
explStkAllocFrameM r2n sl lev sz nrArgs = do
a <- liftIO $ mvecAllocInit (sz+10)
when (nrArgs > 0) $ renvFrStkReversePopInMV 0 nrArgs a
slref <- liftIO $ newIORef sl
spref <- liftIO $ newIORef nrArgs
p <- heapAllocM $ RVal_Frame r2n slref lev a spref
return p
explStkPushFrameM :: (RunSem RValCxt RValEnv RVal m x) => HpPtr -> RValT m ()
explStkPushFrameM frptr = do
(RValEnv {renvStack=st, renvTopFrame=tf}) <- get
liftIO $ do
t <- readIORef tf
unless (isNullPtr t) $ modifyIORef st (t:)
writeIORef tf frptr
explStkPushAllocFrameM :: (RunSem RValCxt RValEnv RVal m x) => Ref2Nm -> HpPtr -> Int -> Int -> Int -> RValT m ()
explStkPushAllocFrameM r2n sl lev sz nrArgs = do
p <- explStkAllocFrameM r2n sl lev sz nrArgs
explStkPushFrameM p
explStkReplaceAllocFrameM :: (RunSem RValCxt RValEnv RVal m x) => Ref2Nm -> HpPtr -> Int -> Int -> Int -> RValT m ()
explStkReplaceAllocFrameM r2n sl lev sz nrArgs = do
p <- explStkAllocFrameM r2n sl lev sz nrArgs
(RValEnv {renvTopFrame=tf}) <- get
liftIO $ writeIORef tf p
explStkPopFrameM :: (RunSem RValCxt RValEnv RVal m x) => RValT m HpPtr
explStkPopFrameM = do
(RValEnv {renvStack=stref, renvTopFrame=tfref}) <- get
liftIO $ do
tf <- readIORef tfref
stk <- readIORef stref
case stk of
[] -> writeIORef tfref nullPtr
(h:t) -> do
writeIORef tfref h
writeIORef stref t
return tf
cmodRun :: (RunSem RValCxt RValEnv RVal m ()) => EHCOpts -> Mod -> RValT m ()
cmodRun opts (Mod_Mod {body_Mod_Mod=e}) = do
rsemExp e
rvalExplStkAppLam :: RunSem RValCxt RValEnv RVal m () => HpPtr -> Exp -> Int -> (Int -> RValT m ()) -> RValT m ()
rvalExplStkAppLam sl f nrActualArgs failcont = do
case f of
Exp_Lam {lev_Exp_Lam=l, nrArgs_Exp_Lam=nrRequiredArgs, stkDepth_Exp_Lam=sz, ref2nm_Exp_Lam=r2n, body_Exp_Lam=b}
| nrActualArgs == nrRequiredArgs -> do
needRet <- asks rcxtInRet
if needRet
then do
explStkPushAllocFrameM r2n sl l sz nrActualArgs
rsemExp b
v <- renvFrStkPop1
explStkPopFrameM
renvFrStkPush1 v
else do
explStkReplaceAllocFrameM r2n sl l sz nrActualArgs
mustReturn $ rsemExp b
| otherwise -> failcont nrRequiredArgs
_ -> err $ "CoreRun.Run.Val.rvalExplStkAppLam:" >#< f
rvalExplStkApp :: RunSem RValCxt RValEnv RVal m () => RVal -> Int -> RValT m ()
rvalExplStkApp f nrActualArgs = do
case f of
RVal_Lam {rvalSLRef=slref, rvalBody=b} -> do
sl <- liftIO $ readIORef slref
rvalExplStkAppLam sl b nrActualArgs $ \narg -> do
if nrActualArgs < narg
then do
renvFrStkReversePopMV nrActualArgs >>= \as -> heapAllocAsPtrM (RVal_App f as) >>= renvFrStkPush1
else do
ap <- mustReturn $ rvalExplStkApp f narg >>= rsemPop >>= rsemDeref >>= rsemPop
rvalExplStkApp ap (nrActualArgs narg)
RVal_App appf appas
| nrActualArgs > 0 -> do
renvFrStkReversePushMV appas >> rvalExplStkApp appf (nrActualArgs + MV.length appas)
_ -> err $ "CoreRun.Run.Val.rvalExplStkApp:" >#< f
rvalExplStkExp :: RunSem RValCxt RValEnv RVal m () => Exp -> RValT m ()
rvalExplStkExp e = do
case e of
Exp_App f as -> do
vecReverseForM_ as rsemExp
rsemExp f >>= rsemPop >>= ptr2valM >>= \f' -> rvalExplStkApp f' (V.length as)
Exp_Tup t as -> do
V.forM_ as rsemExp
renvFrStkPopMV (V.length as) >>= rsemNode (ctagTag t) >>= rsemPush
Exp_Lam {nrArgs_Exp_Lam=na}
| na == 0 -> mk RVal_Thunk >>= heapAllocAsPtrM >>= rsemPush
| otherwise -> mk RVal_Lam >>= heapAllocAsPtrM >>= rsemPush
where mk rv = do
sl <- renvTopFrameM
slref <- liftIO $ newIORef sl
return $ rv e slref
Exp_Let {firstOff_Exp_Let=fillFrom, ref2nm_Exp_Let=r2n, binds_Exp_Let=bs, body_Exp_Let=b} -> do
V.forM_ bs rsemExp
rsemExp b
Exp_Case e as -> do
v <- ptr2valM =<< rsemPop =<< rsemSExp e
case v of
RVal_Node {rvalTag=tg} -> rsemAlt $ as V.! tg
_ -> err $ "CoreRun.Run.Val.RunExplStk.rvalExplStkExp.Case: scrutinee:" >#< v
Exp_Force e -> rsemExp e >>= rsemPop >>= rsemEvl
Exp_Ret e -> mustReturn $ rsemExp e
Exp_RetCase _ e -> rsemExp e
Exp_Tail e -> needNotReturn $ rsemExp e
Exp_SExp se -> rsemSExp se
Exp_FFI pr as -> V.mapM_ rsemExp as >> renvFrStkPopMV (V.length as) >>= (liftIO . V.freeze) >>= rsemPrim pr
e -> err $ "CoreRun.Run.Val.RunExplStk.rvalExplStkExp:" >#< e
instance
( Monad m, MonadIO m, Functor m
) => RunSem RValCxt RValEnv RVal m ()
where
rsemInitial = do
s <- liftIO $ newRValEnv 1000
return (emptyRValCxt, s, undefined)
rsemSetup opts modImpL mod@(Mod_Mod {moduleNr_Mod_Mod=mainModNr}) = do
rsemGcEnterRootLevel
let modAllL = modImpL ++ [mod]
ms <- liftIO $ MV.new (maximum (map moduleNr_Mod_Mod modAllL) + 1)
forM_ modAllL $ \(Mod_Mod {ref2nm_Mod_Mod=r2n, moduleNr_Mod_Mod=nr, binds_Mod_Mod=bs, stkDepth_Mod_Mod=sz}) -> do
explStkPushAllocFrameM r2n nullPtr 0 sz 0
V.forM_ bs rsemExp
p <- explStkPopFrameM
(liftIO $ MV.write ms nr p >> newIORef p) >>= \r -> rsemGcPushRoot (RVal_Ptr r)
ms' <- liftIO $ V.freeze ms
modify $ \env -> env {renvGlobals = ms'}
explStkPushFrameM $ ms' V.! mainModNr
rsemGcLeaveRootLevel
rsemSetTrace $ CoreOpt_RunTrace `elem` ehcOptCoreOpts opts
rsemSetTrace doTrace = modify $ \env ->
env {renvDoTrace = doTrace}
rsemExp = rvalExplStkExp
rsemSExp se = do
case se of
SExp_Int v -> rsemPush $ RVal_Int v
SExp_Char v -> rsemPush $ RVal_Char v
SExp_Var r -> do v <- ref2valM r
rsemPush v
SExp_String v -> rsemPush $ RVal_PackedString $ BSC8.pack v
_ -> rsemPush (RVal_Lit se)
rsemEvl v = do
case v of
RVal_Ptr {rvalPtrRef=pref} -> do
rsemGcEnterRootLevel
rsemGcPushRoot v
liftIO (readIORef pref) >>= evlPtr pref
rsemGcLeaveRootLevel
RVal_BlackHole -> err $ "CoreRun.Run.Val.rsemEvl.RVal_BlackHole:" >#< "Black hole"
_ -> return ()
rsemPush v
where
evlPtr pref p = do
hp <- gets renvHeap
v <- heapGetM' hp p
case v of
RVal_Thunk {rvalSLRef=slref, rvalBody=e} -> do
sl <- liftIO $ readIORef slref
heapSetM' hp p RVal_BlackHole
v' <- rvalExplStkAppLam sl e 0 $ \_ -> err $ "CoreRun.Run.Val.rsemEvl.RVal_Thunk:" >#< e
hp <- gets renvHeap
p <- liftIO (readIORef pref)
v'' <- rsemPop v'
heapSetM' hp p v''
return v''
RVal_Ptr {rvalPtrRef=pref} -> do
v' <- evlPtr pref =<< liftIO (readIORef pref)
hp <- gets renvHeap
p <- liftIO (readIORef pref)
heapSetM' hp p v'
return v'
v -> do
return v
rsemDeref v = do
v' <- ptr2valM v
rsemPush v'
rsemPrim = rvalPrim
rsemPush = renvFrStkPush1
rsemPop = \_ -> renvFrStkPop1
rsemNode t vs = heapAllocAsPtrM $ RVal_Node t vs
rsemGcEnterRootLevel = gets renvGcRootStack >>= \r -> liftIO $ modifyIORef r $ ([]:)
rsemGcPushRoot v = gets renvGcRootStack >>= \r -> liftIO $ modifyIORef r $ \(h:t) -> (v:h) : t
rsemGcLeaveRootLevel = gets renvGcRootStack >>= \r -> liftIO $ modifyIORef r tail