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
data ExplArgs = ExplArgs
{ eaVec :: !RValV
, eaStk :: !Int
}
emptyExplArgs = ExplArgs V.empty 0
eaNrArgs :: ExplArgs -> Int
eaNrArgs (ExplArgs {eaVec=v, eaStk=na}) = V.length v + na
eaSetNrArgs :: ExplArgs -> Int -> ExplArgs
eaSetNrArgs ea@(ExplArgs {eaVec=v}) n = ea {eaStk = n V.length v}
renvFrStkEaPopMV :: RunSem RValCxt RValEnv RVal m x => ExplArgs -> RValT m RValMV
renvFrStkEaPopMV ea@(ExplArgs {eaVec=v}) = (liftIO $ mvecAlloc eaLen) >>= \vs -> liftIO (mvecFillFromV 0 vs v) >> renvFrStkReversePopInMV vLen (eaLenvLen) vs >> return vs
where vLen = V.length v
eaLen = eaNrArgs ea
explStkAllocFrameM :: (RunSem RValCxt RValEnv RVal m x) => Ref2Nm -> HpPtr -> Int -> ExplArgs -> RValT m HpPtr
explStkAllocFrameM r2n sl sz as@(ExplArgs {eaVec=vsArgs, eaStk=nrArgs}) = do
a <- liftIO $ mvecAllocInit sz
let vsLen = V.length vsArgs
when (vsLen > 0) $ liftIO $ mvecFillFromV 0 a vsArgs
when (nrArgs > 0) $ renvFrStkReversePopInMV vsLen nrArgs a
slref <- liftIO $ newIORef sl
spref <- liftIO $ newIORef (eaNrArgs as)
p <- heapAllocM $ RVal_Frame r2n slref 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 -> ExplArgs -> RValT m ()
explStkPushAllocFrameM r2n sl sz as = do
p <- explStkAllocFrameM r2n sl sz as
explStkPushFrameM p
explStkReplaceAllocFrameM :: (RunSem RValCxt RValEnv RVal m x) => Ref2Nm -> HpPtr -> Int -> ExplArgs -> RValT m ()
explStkReplaceAllocFrameM r2n sl sz as = do
p <- explStkAllocFrameM r2n sl sz as
(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
mustReturn $ rsemExp e
rvalExplStkAppLam :: RunSem RValCxt RValEnv RVal m () => HpPtr -> Exp -> ExplArgs -> (Int -> RValT m ()) -> RValT m ()
rvalExplStkAppLam sl f as failcont = do
let nrActualArgs = eaNrArgs as
case f of
Exp_Lam { mbNm_Exp_Lam=mn, nrArgs_Exp_Lam=nrRequiredArgs, stkDepth_Exp_Lam=sz, ref2nm_Exp_Lam=r2n, body_Exp_Lam=b}
| nrActualArgs == nrRequiredArgs -> do
needRet <- asks rcxtInRet
rvalTrEnterLam mn $
if needRet
then do
explStkPushAllocFrameM r2n sl sz as
rsemExp b
v <- renvFrStkPop1
explStkPopFrameM
renvFrStkPush1 v
else do
explStkReplaceAllocFrameM r2n sl sz as
mustReturn $ rsemExp b
| otherwise -> failcont nrRequiredArgs
_ -> err $ "CoreRun.Run.Val.rvalExplStkAppLam:" >#< f
rvalExplStkApp :: RunSem RValCxt RValEnv RVal m () => RVal -> ExplArgs -> RValT m ()
rvalExplStkApp f as = do
let nrActualArgs = eaNrArgs as
case f of
RVal_Lam {rvalSLRef=slref, rvalBody=b} -> do
sl <- liftIO $ readIORef slref
rvalExplStkAppLam sl b as $ \narg -> do
if nrActualArgs < narg
then do
renvFrStkEaPopMV as >>= \as -> heapAllocAsPtrM (RVal_App f as) >>= renvFrStkPush1
else do
ap <- mustReturn $ rvalExplStkApp f (eaSetNrArgs as narg) >>= rsemPop >>= rsemDeref >>= rsemPop
rvalExplStkApp ap (eaSetNrArgs emptyExplArgs (nrActualArgs narg))
RVal_App appf appas
| nrActualArgs > 0 -> do
appas' <- liftIO $ V.freeze appas
rvalExplStkApp appf (as {eaVec=appas' V.++ eaVec as})
_ -> err $ "CoreRun.Run.Val.rvalExplStkApp:" >#< f
rvalExplStkExp :: RunSem RValCxt RValEnv RVal m () => Exp -> RValT m ()
rvalExplStkExp e = do
rsemTr $ ">E:" >#< e
case e of
Exp_App f as -> do
vecReverseForM_ as rsemSExp
f' <- mustReturn $ rsemExp f
rsemPop f' >>= ptr2valM >>= \f' -> rvalExplStkApp f' (emptyExplArgs {eaStk=V.length as})
Exp_Tup t as -> do
V.forM_ as rsemSExp
renvFrStkPopMV (V.length as) >>= rsemNode t >>= rsemPush
Exp_Lam {nrArgs_Exp_Lam=na, mbNm_Exp_Lam=mn}
| na == 0 -> mk heapAllocAsPtrM RVal_Thunk
| otherwise -> mk return RVal_Lam
where mk alloc rv = do
sl <- renvTopFrameM
slref <- liftIO $ newIORef sl
alloc (rv mn e slref) >>= rsemPush
Exp_Let {firstOff_Exp_Let=fillFrom, ref2nm_Exp_Let=r2n, binds_Exp_Let=bs, body_Exp_Let=b} -> do
mustReturn $ V.forM_ bs rsemExp
rsemExp b
Exp_Case e as -> do
v <- ptr2valM =<< rsemPop =<< rsemSExp e
case v of
RVal_Int tg -> rsemAlt $ as V.! tg
_ -> err $ "CoreRun.Run.Val.RunExplStk.rvalExplStkExp.Case: scrutinee:" >#< v
Exp_Force e -> rsemExp e >>= rsemPop >>= rsemEvl
Exp_Tail e -> needNotReturn $ rsemExp e
Exp_SExp se -> rsemSExp se
Exp_FFI pr as -> V.mapM_ rsemSExp as >> renvFrStkPopMV (V.length as) >>= (liftIO . V.freeze) >>= rsemPrim pr
e -> err $ "CoreRun.Run.Val.RunExplStk.rvalExplStkExp:" >#< e
rsemTr $ "<E:" >#< (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 sz emptyExplArgs
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
rsemSetupTracing opts
rsemSetTrace doTrace doExtensive = modify $ \env ->
env {renvDoTrace = doTrace, renvDoTraceExt = doExtensive}
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 {rvalMbNm=mn, rvalSLRef=slref, rvalBody=e} -> do
sl <- liftIO $ readIORef slref
heapSetM' hp p RVal_BlackHole
v' <- rvalExplStkAppLam sl e (emptyExplArgs {eaStk=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 = return $ 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