start instruction evaluator
This commit is contained in:
@@ -14,7 +14,7 @@ import Data.Vector (Vector, (!), (!?), (//))
|
||||
import Data.Vector.Storable.Mutable (IOVector)
|
||||
import qualified Data.Vector as Vector
|
||||
import qualified Data.Vector.Storable.Mutable as IOVector
|
||||
import Data.IORef (IORef, newIORef, readIORef)
|
||||
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
|
||||
import Data.Word (Word8, Word32, Word64)
|
||||
import Numeric.Natural (Natural)
|
||||
import qualified Control.Monad as Monad
|
||||
@@ -29,17 +29,7 @@ data Value =
|
||||
| VF64 Double
|
||||
deriving (Eq, Show)
|
||||
|
||||
data AdminInstr =
|
||||
I Instruction
|
||||
| Trap
|
||||
| Invoke Address
|
||||
| InitElem Address Word32 [Natural]
|
||||
| InitData Address Word32 LBS.ByteString
|
||||
| Label [AdminInstr] [AdminInstr]
|
||||
| IFrame Frame [AdminInstr]
|
||||
deriving (Show, Eq)
|
||||
|
||||
data Frame = Frame { locals :: Vector Value, mod :: ModuleInstance } deriving (Eq, Show)
|
||||
data Label = Label
|
||||
|
||||
type Address = Int
|
||||
|
||||
@@ -203,9 +193,15 @@ allocMems mems = Vector.fromList <$> mapM allocMem mems
|
||||
}
|
||||
|
||||
initialize :: ModuleInstance -> Module -> Store -> IO Store
|
||||
initialize inst Module {elems, datas} store = do
|
||||
store' <- Monad.foldM initElem store elems
|
||||
Monad.foldM initData store' datas
|
||||
initialize inst Module {elems, datas, start} store = do
|
||||
storeWithTables <- Monad.foldM initElem store elems
|
||||
storeWithMems <- Monad.foldM initData storeWithTables datas
|
||||
case start of
|
||||
Just (StartFunction idx) -> do
|
||||
let funInst = funcInstances store ! (funcaddrs inst ! fromIntegral idx)
|
||||
[] <- eval storeWithMems funInst []
|
||||
return storeWithMems
|
||||
Nothing -> return storeWithMems
|
||||
where
|
||||
initElem :: Store -> ElemSegment -> IO Store
|
||||
initElem st ElemSegment {tableIndex, offset, funcIndexes} = do
|
||||
@@ -235,9 +231,7 @@ initialize inst Module {elems, datas} store = do
|
||||
mapM_ (\(i,b) -> IOVector.write mem i b) $ zip [from..] $ LBS.unpack chunk
|
||||
return $ st { memInstances = memInstances st // [(idx, MemoryInstance mem maxLen)] }
|
||||
|
||||
data EvalContext = EvalContext ModuleInstance (IORef Store)
|
||||
|
||||
instantiate :: Store -> Imports -> Module -> IO EvalContext
|
||||
instantiate :: Store -> Imports -> Module -> IO (ModuleInstance, Store)
|
||||
instantiate st imps m = do
|
||||
let inst = calcInstance st imps m
|
||||
let functions = funcInstances st <> (allocFunctions inst $ Struct.functions m)
|
||||
@@ -250,8 +244,70 @@ instantiate st imps m = do
|
||||
memInstances = mems,
|
||||
globalInstances = globals
|
||||
}
|
||||
ref <- newIORef st'
|
||||
return $ EvalContext inst ref
|
||||
return (inst, st')
|
||||
|
||||
invoke :: EvalContext -> TL.Text -> [Value] -> IO [Value]
|
||||
invoke = undefined
|
||||
type Stack = [Value]
|
||||
|
||||
data EvalCtx = EvalCtx {
|
||||
locals :: Vector Value,
|
||||
labels :: [Label],
|
||||
stack :: Stack
|
||||
}
|
||||
|
||||
eval :: Store -> FunctionInstance -> [Value] -> IO [Value]
|
||||
eval store FunctionInstance { funcType, moduleInstance, code = Function { localTypes, body} } args = do
|
||||
let checkedArgs = zipWith checkArgType (params funcType) args
|
||||
let initialContext = EvalCtx {
|
||||
locals = Vector.fromList $ checkedArgs ++ map initLocal localTypes,
|
||||
labels = [],
|
||||
stack = []
|
||||
}
|
||||
result <- Monad.foldM step initialContext body
|
||||
return $ reverse $ stack result
|
||||
where
|
||||
checkArgType :: ValueType -> Value -> Value
|
||||
checkArgType I32 (VI32 v) = VI32 v
|
||||
checkArgType I64 (VI64 v) = VI64 v
|
||||
checkArgType F32 (VF32 v) = VF32 v
|
||||
checkArgType F64 (VF64 v) = VF64 v
|
||||
checkArgType _ _ = error "Argument types do not match function type"
|
||||
|
||||
initLocal :: ValueType -> Value
|
||||
initLocal I32 = VI32 0
|
||||
initLocal I64 = VI64 0
|
||||
initLocal F32 = VF32 0
|
||||
initLocal F64 = VF64 0
|
||||
|
||||
step :: EvalCtx -> Instruction -> IO EvalCtx
|
||||
step ctx (I32Const v) = return ctx { stack = VI32 v : stack ctx }
|
||||
step ctx (I64Const v) = return ctx { stack = VI64 v : stack ctx }
|
||||
step ctx (F32Const v) = return ctx { stack = VF32 v : stack ctx }
|
||||
step ctx (F64Const v) = return ctx { stack = VF64 v : stack ctx }
|
||||
step ctx (GetLocal i) = return ctx { stack = (locals ctx ! fromIntegral i) : stack ctx }
|
||||
step ctx@EvalCtx{ stack = (v:rest) } (SetLocal i) =
|
||||
return ctx { stack = rest, locals = locals ctx // [(fromIntegral i, v)] }
|
||||
step ctx@EvalCtx{ locals = ls, stack = (v:rest) } (TeeLocal i) =
|
||||
return ctx {
|
||||
stack = (ls ! fromIntegral i) : rest,
|
||||
locals = locals ctx // [(fromIntegral i, v)]
|
||||
}
|
||||
step ctx (GetGlobal i) = do
|
||||
let globalInst = globalInstances store ! (globaladdrs moduleInstance ! fromIntegral i)
|
||||
val <- case globalInst of
|
||||
GIConst v -> return v
|
||||
GIMut ref -> readIORef ref
|
||||
return ctx { stack = val : stack ctx }
|
||||
step ctx@EvalCtx{ stack = (v:rest) } (SetGlobal i) = do
|
||||
let globalInst = globalInstances store ! (globaladdrs moduleInstance ! fromIntegral i)
|
||||
case globalInst of
|
||||
GIConst v -> error "Attempt of mutation of constant global"
|
||||
GIMut ref -> writeIORef ref v
|
||||
return ctx { stack = rest }
|
||||
step _ _ = error "Error during evaluation"
|
||||
eval store HostInstance { funcType, tag } args = return args
|
||||
|
||||
invoke :: Store -> Address -> [Value] -> IO [Value]
|
||||
invoke st funcIdx = eval st $ funcInstances st ! funcIdx
|
||||
|
||||
invokeExport :: Store -> TL.Text -> [Value] -> IO [Value]
|
||||
invokeExport = undefined
|
||||
Reference in New Issue
Block a user