From 6e9c4d969acb09967f1152692e02753f4910c24a Mon Sep 17 00:00:00 2001 From: Ilya Rezvov Date: Tue, 15 Feb 2022 21:43:45 -0700 Subject: [PATCH] update initialization sequence for elems --- src/Language/Wasm/Interpreter.hs | 68 +++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/src/Language/Wasm/Interpreter.hs b/src/Language/Wasm/Interpreter.hs index f33e757..64ef2a5 100644 --- a/src/Language/Wasm/Interpreter.hs +++ b/src/Language/Wasm/Interpreter.hs @@ -216,11 +216,17 @@ data FunctionInstance = hostCode :: HostFunction } +data ElemInstance = ElemInstance ElemType (Vector Value) deriving (Eq, Show) + +data DataInstance = DataInstance + data Store = Store { funcInstances :: Vector FunctionInstance, tableInstances :: Vector TableInstance, memInstances :: Vector MemoryInstance, - globalInstances :: Vector GlobalInstance + globalInstances :: Vector GlobalInstance, + elemInstances :: Vector ElemInstance, + dataInstances :: Vector DataInstance } emptyStore :: Store @@ -308,6 +314,8 @@ data ModuleInstance = ModuleInstance { tableaddrs :: Vector Address, memaddrs :: Vector Address, globaladdrs :: Vector Address, + elemaddrs :: Vector Address, + dataaddrs :: Vector Address, exports :: Vector ExportInstance } deriving (Eq, Show) @@ -318,15 +326,20 @@ emptyModInstance = ModuleInstance { tableaddrs = Vector.empty, memaddrs = Vector.empty, globaladdrs = Vector.empty, + elemaddrs = Vector.empty, + dataaddrs = Vector.empty, exports = Vector.empty } calcInstance :: Store -> Imports -> Module -> Initialize ModuleInstance -calcInstance (Store fs ts ms gs) imps Module {functions, types, tables, mems, globals, exports, imports} = do +calcInstance (Store fs ts ms gs es ds) imps mod = do + let Module {functions, types, tables, mems, globals, exports, imports, elems, datas} = mod let funLen = length fs let tableLen = length ts let memLen = length ms let globalLen = length gs + let elemLen = length es + let dataLen = length ds funImps <- mapM checkImportType $ filter isFuncImport imports tableImps <- mapM checkImportType $ filter isTableImport imports memImps <- mapM checkImportType $ filter isMemImport imports @@ -350,6 +363,8 @@ calcInstance (Store fs ts ms gs) imps Module {functions, types, tables, mems, gl tableaddrs = tbls, memaddrs = memories, globaladdrs = globs, + elemaddrs = Vector.fromList [elemLen..elemLen + length elems - 1], + dataaddrs = Vector.fromList [dataLen..dataLen + length datas - 1], exports = Vector.fromList $ map refExport exports } where @@ -365,7 +380,7 @@ calcInstance (Store fs ts ms gs) imps Module {functions, types, tables, mems, gl funcAddr <- case idx of ExternFunction funcAddr -> return funcAddr other -> throwError "incompatible import type" - let expectedType = types !! fromIntegral typeIdx + let expectedType = types mod !! fromIntegral typeIdx let actualType = Language.Wasm.Interpreter.funcType $ fs ! funcAddr if expectedType == actualType then return idx @@ -451,7 +466,7 @@ allocAndInitGlobals inst store globs = Vector.fromList <$> mapM allocGlob globs GIMut vt <$> newIORef val allocTables :: [Table] -> Vector TableInstance -allocTables tables = Vector.fromList $ map allocTable tables +allocTables = Vector.fromList . map allocTable where allocTable :: Table -> TableInstance allocTable (Table (TableType lim@(Limit from to) _)) = @@ -480,12 +495,22 @@ allocMems mems = Vector.fromList <$> mapM allocMem mems memory } +allocElems :: ModuleInstance -> Store -> [ElemSegment] -> IO (Vector ElemInstance) +allocElems inst st = fmap Vector.fromList . mapM allocElem + where + allocElem :: ElemSegment -> IO ElemInstance + allocElem (ElemSegment t _mode refs) = + ElemInstance t . Vector.fromList <$> mapM (evalConstExpr inst st) refs + +allocDatas :: ModuleInstance -> Store -> [DataSegment] -> Vector DataInstance +allocDatas _inst _st = Vector.fromList . map (const DataInstance) + type Initialize = ExceptT String (State.StateT Store IO) initialize :: ModuleInstance -> Module -> Initialize () initialize inst Module {elems, datas, start} = do checkedMems <- mapM checkData datas - checkedTables <- mapM checkElem elems + checkedTables <- mapM checkElem $ filter isActiveElem elems mapM_ initData checkedMems mapM_ initElem checkedTables st <- State.get @@ -498,12 +523,21 @@ initialize inst Module {elems, datas, start} = do _ -> throwError "Start function terminated with trap" Nothing -> return () where - checkElem :: ElemSegment -> Initialize (Address, Int, [Address]) - checkElem ElemSegment {tableIndex, offset, funcIndexes} = do + isActiveElem :: ElemSegment -> Bool + isActiveElem (ElemSegment FuncRef (Active _ _) _) = True + isActiveElem _ = False + + checkElem :: ElemSegment -> Initialize (Address, Int, [Maybe Address]) + checkElem ElemSegment {elemType, mode, elements} = do + (tableIndex, offset) <- case mode of { + Active idx off -> return (idx, off); + _ -> throwError "only active mode element can be initialized" + } st <- State.get VI32 val <- liftIO $ evalConstExpr inst st offset let from = fromIntegral val - let funcs = map ((funcaddrs inst !) . fromIntegral) funcIndexes + refs <- liftIO $ mapM (evalConstExpr inst st) elements + let funcs = map (\(RF ref) -> (funcaddrs inst !) . fromIntegral <$> ref) refs let idx = tableaddrs inst ! fromIntegral tableIndex let last = from + length funcs let TableInstance lim elems = tableInstances st ! idx @@ -511,10 +545,10 @@ initialize inst Module {elems, datas, start} = do Monad.when (last > len) $ throwError "elements segment does not fit" return (idx, from, funcs) - initElem :: (Address, Int, [Address]) -> Initialize () + initElem :: (Address, Int, [Maybe Address]) -> Initialize () initElem (idx, from, funcs) = State.modify $ \st -> let TableInstance lim elems = tableInstances st ! idx in - let table = TableInstance lim (elems // zip [from..] (map Just funcs)) in + let table = TableInstance lim (elems // zip [from..] funcs) in st { tableInstances = tableInstances st Vector.// [(idx, table)] } checkData :: DataSegment -> Initialize (Int, MemoryStore, LBS.ByteString) @@ -538,15 +572,19 @@ instantiate :: Store -> Imports -> Valid.ValidModule -> IO (Either String Module instantiate st imps mod = flip State.runStateT st $ runExceptT $ do let m = Valid.getModule mod inst <- calcInstance st imps m - let functions = funcInstances st <> (allocFunctions inst $ Struct.functions m) - globals <- liftIO $ (globalInstances st <>) <$> (allocAndInitGlobals inst st $ Struct.globals m) - let tables = tableInstances st <> (allocTables $ Struct.tables m) - mems <- liftIO $ (memInstances st <>) <$> (allocMems $ Struct.mems m) + let functions = funcInstances st <> allocFunctions inst (Struct.functions m) + globals <- liftIO $ (globalInstances st <>) <$> allocAndInitGlobals inst st (Struct.globals m) + let tables = tableInstances st <> allocTables (Struct.tables m) + mems <- liftIO $ (memInstances st <>) <$> allocMems (Struct.mems m) + elems <- liftIO $ (elemInstances st <>) <$> allocElems inst st (Struct.elems m) + let datas = dataInstances st <> allocDatas inst st (Struct.datas m) State.put $ st { funcInstances = functions, tableInstances = tables, memInstances = mems, - globalInstances = globals + globalInstances = globals, + elemInstances = elems, + dataInstances = datas } initialize inst m return inst