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 Data.List
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
-> RCxt
-> Int
-> ExplArgs
-> RValT m HpPtr
explStkAllocFrameM r2n cx 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
spref <- liftIO $ newIORef (eaNrArgs as)
p <- heapAllocM $ RVal_Frame r2n cx a spref
return p
explStkPushFrameM :: (RunSem RValCxt RValEnv RVal m x) => HpPtr -> RValT m ()
explStkPushFrameM frptr = do
(RValEnv {renvStack=st, renvTopFrame=tfref}) <- get
liftIO $ do
tf <- readIORef tfref
unless (isNullPtr tf) $ modifyIORef st (tf:)
writeIORef tfref frptr
explStkPushAllocFrameM
:: (RunSem RValCxt RValEnv RVal m x)
=> Ref2Nm
-> RCxt
-> Int
-> ExplArgs
-> RValT m HpPtr
explStkPushAllocFrameM r2n cx sz as = do
p <- explStkAllocFrameM r2n cx sz as
explStkPushFrameM p
return p
explStkReplaceAllocFrameM
:: (RunSem RValCxt RValEnv RVal m x)
=> Ref2Nm
-> RCxt
-> Int
-> ExplArgs
-> RValT m ()
explStkReplaceAllocFrameM r2n cx sz as = do
p <- explStkAllocFrameM r2n cx 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 {mbbody_Mod_Mod = Just e}) = do
mustReturn $ rsemExp e
cmodRun opts _ = return ()
rvalExplStkAppLam :: RunSem RValCxt RValEnv RVal m () => RCxt -> Exp -> ExplArgs -> (Int -> RValT m ()) -> RValT m ()
rvalExplStkAppLam cx 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 cx sz as
rsemExp b
v <- renvFrStkPop1
explStkPopFrameM
renvFrStkPush1 v
else do
explStkReplaceAllocFrameM r2n cx 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 {rvalCx=rcx, rvalBody=b} -> do
rvalExplStkAppLam rcx 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,fr) <- renvTopFramePtrAndFrameM
cx <- liftIO $ rcxtCloneWithNewFrame sl (rvalCx fr)
alloc (rv mn e cx) >>= 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
rsemTr $ "<E:" >#< (e)
rvalExplAddModule :: RunSem RValCxt RValEnv RVal m () => Mod -> RValT m HpPtr
rvalExplAddModule mod@(Mod_Mod {moduleNm_Mod_Mod=nm, ref2nm_Mod_Mod=r2n, binds_Mod_Mod=bs, stkDepth_Mod_Mod=sz, imports_Mod_Mod=imports}) = do
env@(RValEnv {renvModulesMV=mods}) <- get
mods' <- liftIO $ MV.grow mods 1
put $ env {renvModulesMV = mods'}
env@(RValEnv {renvModulesMV=mods, renvGlobalsMV=globs}) <- get
let nr = MV.length mods 1
imptbl <- renvResolveModNames [ nm | Import_Import {nm_Import_Import=nm} <- imports ]
cx <- liftIO $ mkRCxt nullPtr nullPtr
f <- explStkPushAllocFrameM r2n cx sz emptyExplArgs
fr <- liftIO $ newIORef f
m <- heapAllocM $ RVal_Module nm (crarrayFromList imptbl) fr
liftIO $ do
MV.write mods nr m
writeIORef (rcxtMdRef cx) m
V.forM_ bs rsemExp
explStkPopFrameM
where
instance
( Monad m, MonadIO m, Functor m
) => RunSem RValCxt RValEnv RVal m ()
where
rsemInitial = do
s <- liftIO $ newRValEnv 100000
return (emptyRValCxt, s, undefined)
rsemSetup opts modImpL mod@(Mod_Mod {moduleNr_Mod_Mod=mainModNr}) = do
let modAllL = modImpL ++ [mod]
modFrames <- forM modAllL $ \mod -> do
rvalExplAddModule mod
explStkPushFrameM (last modFrames)
rcxtUpdDatatypes modAllL
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, rvalCx=rcx, rvalBody=e} -> do
heapSetM' hp p RVal_BlackHole
v' <- rvalExplStkAppLam rcx 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_NodeMV 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