open Source open Ast module Set = Set.Make(Int32) type t = { types : Set.t; globals : Set.t; tables : Set.t; memories : Set.t; funcs : Set.t; elems : Set.t; datas : Set.t; locals : Set.t; labels : Set.t; } let empty : t = { types = Set.empty; globals = Set.empty; tables = Set.empty; memories = Set.empty; funcs = Set.empty; elems = Set.empty; datas = Set.empty; locals = Set.empty; labels = Set.empty; } let union (s1 : t) (s2 : t) : t = { types = Set.union s1.types s2.types; globals = Set.union s1.globals s2.globals; tables = Set.union s1.tables s2.tables; memories = Set.union s1.memories s2.memories; funcs = Set.union s1.funcs s2.funcs; elems = Set.union s1.elems s2.elems; datas = Set.union s1.datas s2.datas; locals = Set.union s1.locals s2.locals; labels = Set.union s1.labels s2.labels; } let types s = {empty with types = s} let globals s = {empty with globals = s} let tables s = {empty with tables = s} let memories s = {empty with memories = s} let funcs s = {empty with funcs = s} let elems s = {empty with elems = s} let datas s = {empty with datas = s} let locals s = {empty with locals = s} let labels s = {empty with labels = s} let var x = Set.singleton x.it let zero = Set.singleton 0l let shift s = Set.map (Int32.add (-1l)) (Set.remove 0l s) let (++) = union let list free xs = List.fold_left union empty (List.map free xs) let opt free xo = Lib.Option.get (Lib.Option.map free xo) empty let block_type = function | VarBlockType x -> types (var x) | ValBlockType _ -> empty let rec instr (e : instr) = match e.it with | Unreachable | Nop | Drop | Select _ -> empty | RefNull _ | RefIsNull -> empty | RefFunc x -> funcs (var x) | Const _ | Test _ | Compare _ | Unary _ | Binary _ | Convert _ -> empty | Block (bt, es) | Loop (bt, es) -> block_type bt ++ block es | If (bt, es1, es2) -> block_type bt ++ block es1 ++ block es2 | Br x | BrIf x -> labels (var x) | BrTable (xs, x) -> list (fun x -> labels (var x)) (x::xs) | Return -> empty | Call x -> funcs (var x) | CallIndirect (x, y) -> tables (var x) ++ types (var y) | LocalGet x | LocalSet x | LocalTee x -> locals (var x) | GlobalGet x | GlobalSet x -> globals (var x) | TableGet x | TableSet x | TableSize x | TableGrow x | TableFill x -> tables (var x) | TableCopy (x, y) -> tables (var x) ++ tables (var y) | TableInit (x, y) -> tables (var x) ++ elems (var y) | ElemDrop x -> elems (var x) | Load _ | Store _ | VecLoad _ | VecStore _ | VecLoadLane _ | VecStoreLane _ | MemorySize | MemoryGrow | MemoryCopy | MemoryFill -> memories zero | VecConst _ | VecTest _ | VecUnary _ | VecBinary _ | VecCompare _ | VecConvert _ | VecShift _ | VecBitmask _ | VecTestBits _ | VecUnaryBits _ | VecBinaryBits _ | VecTernaryBits _ | VecSplat _ | VecExtract _ | VecReplace _ -> memories zero | MemoryInit x -> memories zero ++ datas (var x) | DataDrop x -> datas (var x) and block (es : instr list) = let free = list instr es in {free with labels = shift free.labels} let const (c : const) = block c.it let global (g : global) = const g.it.ginit let func (f : func) = {(block f.it.body) with locals = Set.empty} let table (t : table) = empty let memory (m : memory) = empty let segment_mode f (m : segment_mode) = match m.it with | Passive | Declarative -> empty | Active {index; offset} -> f (var index) ++ const offset let elem (s : elem_segment) = list const s.it.einit ++ segment_mode tables s.it.emode let data (s : data_segment) = segment_mode memories s.it.dmode let type_ (t : type_) = empty let export_desc (d : export_desc) = match d.it with | FuncExport x -> funcs (var x) | TableExport x -> tables (var x) | MemoryExport x -> memories (var x) | GlobalExport x -> globals (var x) let import_desc (d : import_desc) = match d.it with | FuncImport x -> types (var x) | TableImport tt -> empty | MemoryImport mt -> empty | GlobalImport gt -> empty let export (e : export) = export_desc e.it.edesc let import (i : import) = import_desc i.it.idesc let start (s : start) = funcs (var s.it.sfunc) let module_ (m : module_) = list type_ m.it.types ++ list global m.it.globals ++ list table m.it.tables ++ list memory m.it.memories ++ list func m.it.funcs ++ opt start m.it.start ++ list elem m.it.elems ++ list data m.it.datas ++ list import m.it.imports ++ list export m.it.exports