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 -> Int -> ExplArgs -> RValT m HpPtr
explStkAllocFrameM r2n sl lev 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 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 -> ExplArgs -> RValT m ()
explStkPushAllocFrameM r2n sl lev sz as = do
p <- explStkAllocFrameM r2n sl lev sz as
explStkPushFrameM p
explStkReplaceAllocFrameM :: (RunSem RValCxt RValEnv RVal m x) => Ref2Nm -> HpPtr -> Int -> Int -> ExplArgs -> RValT m ()
explStkReplaceAllocFrameM r2n sl lev sz as = do
p <- explStkAllocFrameM r2n sl lev 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 {lev_Exp_Lam=l, 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 l sz as
rsemExp b
v <- renvFrStkPop1
explStkPopFrameM
renvFrStkPush1 v
else do
explStkReplaceAllocFrameM r2n sl l 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
case e of
Exp_App f as -> do
f' <- mustReturn $ do
vecReverseForM_ as rsemExp
rsemExp f
rsemPop f' >>= ptr2valM >>= \f' -> rvalExplStkApp f' (emptyExplArgs {eaStk=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, mbNm_Exp_Lam=mn}
| na == 0 -> mk RVal_Thunk
| otherwise -> mk RVal_Lam
where mk rv = do
sl <- renvTopFrameM
slref <- liftIO $ newIORef sl
heapAllocAsPtrM (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_Node {rvalTag=tg} -> rsemAlt $ as V.! tg
_ -> err $ "CoreRun.Run.Val.RunExplStk.rvalExplStkExp.Case: scrutinee:" >#< v
Exp_Force e -> rsemExp e >>= rsemPop >>= rsemEvl
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 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 = 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