use ExceptT transformer to clarify interpreter code

This commit is contained in:
Ilya Rezvov
2018-04-25 10:49:58 -07:00
parent 70f207d02d
commit fc2eb97647
+37 -40
View File
@@ -50,6 +50,8 @@ import Data.Bits (
countTrailingZeros countTrailingZeros
) )
import Numeric.IEEE (IEEE, copySign, minNum, maxNum, identicalIEEE) import Numeric.IEEE (IEEE, copySign, minNum, maxNum, identicalIEEE)
import Control.Monad.Except (ExceptT, runExceptT, throwError)
import Control.Monad.IO.Class (liftIO)
import Debug.Trace as Debug import Debug.Trace as Debug
@@ -484,28 +486,26 @@ allocMems mems = Vector.fromList <$> mapM allocMem mems
memory memory
} }
initialize :: ModuleInstance -> Module -> Store -> IO (Either String Store) type Initialize = ExceptT String IO
initialize :: ModuleInstance -> Module -> Store -> Initialize Store
initialize inst Module {elems, datas, start} store = do initialize inst Module {elems, datas, start} store = do
checkedMems <- Monad.foldM checkData (Right store) datas checkedMems <- Monad.foldM checkData store datas
checkedTables <- Monad.foldM checkElem checkedMems elems checkedTables <- Monad.foldM checkElem checkedMems elems
storeWithTables <- Monad.foldM initElem checkedMems elems storeWithTables <- Monad.foldM initElem checkedMems elems
storeWithMems <- Monad.foldM initData storeWithTables datas st <- Monad.foldM initData storeWithTables datas
case storeWithMems of case start of
Right st -> do Just (StartFunction idx) -> do
case start of let funInst = funcInstances store ! (funcaddrs inst ! fromIntegral idx)
Just (StartFunction idx) -> do mainRes <- liftIO $ eval defaultBudget st funInst []
let funInst = funcInstances store ! (funcaddrs inst ! fromIntegral idx) case mainRes of
mainRes <- eval defaultBudget st funInst [] Just [] -> return st
case mainRes of _ -> throwError "Start function terminated with trap"
Just [] -> return $ Right st Nothing -> return st
_ -> return $ Left "Start function terminated with trap"
Nothing -> return $ Right st
Left reason -> return $ Left reason
where where
checkElem :: Either String Store -> ElemSegment -> IO (Either String Store) checkElem :: Store -> ElemSegment -> Initialize Store
checkElem (Left err) _ = return $ Left err checkElem st ElemSegment {tableIndex, offset, funcIndexes} = do
checkElem (Right st) ElemSegment {tableIndex, offset, funcIndexes} = do VI32 val <- liftIO $ evalConstExpr inst st offset
VI32 val <- evalConstExpr inst st offset
let from = fromIntegral val let from = fromIntegral val
let funcs = map ((funcaddrs inst !) . fromIntegral) funcIndexes let funcs = map ((funcaddrs inst !) . fromIntegral) funcIndexes
let idx = tableaddrs inst ! fromIntegral tableIndex let idx = tableaddrs inst ! fromIntegral tableIndex
@@ -513,13 +513,12 @@ initialize inst Module {elems, datas, start} store = do
let TableInstance lim elems = tableInstances st ! idx let TableInstance lim elems = tableInstances st ! idx
let len = Vector.length elems let len = Vector.length elems
if last > len if last > len
then return $ Left "elements segment does not fit" then throwError "elements segment does not fit"
else return $ Right st else return st
initElem :: Either String Store -> ElemSegment -> IO (Either String Store) initElem :: Store -> ElemSegment -> Initialize Store
initElem (Left err) _ = return $ Left err initElem st ElemSegment {tableIndex, offset, funcIndexes} = do
initElem (Right st) ElemSegment {tableIndex, offset, funcIndexes} = do VI32 val <- liftIO $ evalConstExpr inst st offset
VI32 val <- evalConstExpr inst st offset
let from = fromIntegral val let from = fromIntegral val
let funcs = map ((funcaddrs inst !) . fromIntegral) funcIndexes let funcs = map ((funcaddrs inst !) . fromIntegral) funcIndexes
let idx = tableaddrs inst ! fromIntegral tableIndex let idx = tableaddrs inst ! fromIntegral tableIndex
@@ -527,36 +526,34 @@ initialize inst Module {elems, datas, start} store = do
let TableInstance lim elems = tableInstances st ! idx let TableInstance lim elems = tableInstances st ! idx
let len = Vector.length elems let len = Vector.length elems
if last > len if last > len
then return $ Left "elements segment does not fit" then throwError "elements segment does not fit"
else do else do
let table = TableInstance lim (elems // zip [from..] (map Just funcs)) let table = TableInstance lim (elems // zip [from..] (map Just funcs))
return $ Right st { tableInstances = tableInstances st Vector.// [(idx, table)] } return st { tableInstances = tableInstances st Vector.// [(idx, table)] }
checkData :: Either String Store -> DataSegment -> IO (Either String Store) checkData :: Store -> DataSegment -> Initialize Store
checkData (Left err) _ = return $ Left err checkData st DataSegment {memIndex, offset, chunk} = do
checkData (Right st) DataSegment {memIndex, offset, chunk} = do VI32 val <- liftIO $ evalConstExpr inst st offset
VI32 val <- evalConstExpr inst st offset
let from = fromIntegral val let from = fromIntegral val
let idx = memaddrs inst ! fromIntegral memIndex let idx = memaddrs inst ! fromIntegral memIndex
let last = from + (fromIntegral $ LBS.length chunk) let last = from + (fromIntegral $ LBS.length chunk)
let MemoryInstance _ memory = memInstances st ! idx let MemoryInstance _ memory = memInstances st ! idx
mem <- readIORef memory mem <- liftIO $ readIORef memory
let len = IOVector.length mem let len = IOVector.length mem
if last > len if last > len
then return $ Left "data segment does not fit" then throwError "data segment does not fit"
else return $ Right st else return st
initData :: Either String Store -> DataSegment -> IO (Either String Store) initData :: Store -> DataSegment -> Initialize Store
initData (Left err) _ = return $ Left err initData st DataSegment {memIndex, offset, chunk} = do
initData (Right st) DataSegment {memIndex, offset, chunk} = do VI32 val <- liftIO $ evalConstExpr inst st offset
VI32 val <- evalConstExpr inst st offset
let from = fromIntegral val let from = fromIntegral val
let idx = memaddrs inst ! fromIntegral memIndex let idx = memaddrs inst ! fromIntegral memIndex
let last = from + (fromIntegral $ LBS.length chunk) let last = from + (fromIntegral $ LBS.length chunk)
let MemoryInstance _ memory = memInstances st ! idx let MemoryInstance _ memory = memInstances st ! idx
mem <- readIORef memory mem <- liftIO $ readIORef memory
mapM_ (\(i,b) -> IOVector.write mem i b) $ zip [from..] $ LBS.unpack chunk mapM_ (\(i,b) -> IOVector.write mem i b) $ zip [from..] $ LBS.unpack chunk
return $ Right st return st
instantiate :: Store -> Imports -> Module -> IO (Either String (ModuleInstance, Store)) instantiate :: Store -> Imports -> Module -> IO (Either String (ModuleInstance, Store))
instantiate st imps m = instantiate st imps m =
@@ -567,7 +564,7 @@ instantiate st imps m =
globals <- (globalInstances st <>) <$> (allocAndInitGlobals inst st $ Struct.globals m) globals <- (globalInstances st <>) <$> (allocAndInitGlobals inst st $ Struct.globals m)
let tables = tableInstances st <> (allocTables $ Struct.tables m) let tables = tableInstances st <> (allocTables $ Struct.tables m)
mems <- (memInstances st <>) <$> (allocMems $ Struct.mems m) mems <- (memInstances st <>) <$> (allocMems $ Struct.mems m)
st' <- initialize inst m $ st { st' <- runExceptT $ initialize inst m $ st {
funcInstances = functions, funcInstances = functions,
tableInstances = tables, tableInstances = tables,
memInstances = mems, memInstances = mems,