| (* |
| * Throughout the implementation we use consistent naming conventions for |
| * syntactic elements, associated with the types defined here and in a few |
| * other places: |
| * |
| * x : var |
| * v : value |
| * e : instr |
| * f : func |
| * m : module_ |
| * |
| * t : value_type |
| * s : func_type |
| * c : context / config |
| * |
| * These conventions mostly follow standard practice in language semantics. |
| *) |
| |
| open Types |
| |
| type void = Lib.void |
| |
| |
| (* Operators *) |
| |
| module IntOp = |
| struct |
| type unop = Clz | Ctz | Popcnt | ExtendS of pack_size |
| type binop = Add | Sub | Mul | DivS | DivU | RemS | RemU |
| | And | Or | Xor | Shl | ShrS | ShrU | Rotl | Rotr |
| type testop = Eqz |
| type relop = Eq | Ne | LtS | LtU | GtS | GtU | LeS | LeU | GeS | GeU |
| type cvtop = ExtendSI32 | ExtendUI32 | WrapI64 |
| | TruncSF32 | TruncUF32 | TruncSF64 | TruncUF64 |
| | TruncSatSF32 | TruncSatUF32 | TruncSatSF64 | TruncSatUF64 |
| | ReinterpretFloat |
| end |
| |
| module FloatOp = |
| struct |
| type unop = Neg | Abs | Ceil | Floor | Trunc | Nearest | Sqrt |
| type binop = Add | Sub | Mul | Div | Min | Max | CopySign |
| type testop = | |
| type relop = Eq | Ne | Lt | Gt | Le | Ge |
| type cvtop = ConvertSI32 | ConvertUI32 | ConvertSI64 | ConvertUI64 |
| | PromoteF32 | DemoteF64 |
| | ReinterpretInt |
| end |
| |
| module I32Op = IntOp |
| module I64Op = IntOp |
| module F32Op = FloatOp |
| module F64Op = FloatOp |
| |
| module V128Op = |
| struct |
| type itestop = AllTrue |
| type iunop = Abs | Neg | Popcnt |
| type funop = Abs | Neg | Sqrt | Ceil | Floor | Trunc | Nearest |
| type ibinop = Add | Sub | Mul | MinS | MinU | MaxS | MaxU | AvgrU |
| | AddSatS | AddSatU | SubSatS | SubSatU | DotS | Q15MulRSatS |
| | ExtMulLowS | ExtMulHighS | ExtMulLowU | ExtMulHighU |
| | Swizzle | Shuffle of int list | NarrowS | NarrowU |
| type fbinop = Add | Sub | Mul | Div | Min | Max | Pmin | Pmax |
| type irelop = Eq | Ne | LtS | LtU | LeS | LeU | GtS | GtU | GeS | GeU |
| type frelop = Eq | Ne | Lt | Le | Gt | Ge |
| type icvtop = ExtendLowS | ExtendLowU | ExtendHighS | ExtendHighU |
| | ExtAddPairwiseS | ExtAddPairwiseU |
| | TruncSatSF32x4 | TruncSatUF32x4 |
| | TruncSatSZeroF64x2 | TruncSatUZeroF64x2 |
| type fcvtop = DemoteZeroF64x2 | PromoteLowF32x4 |
| | ConvertSI32x4 | ConvertUI32x4 |
| type ishiftop = Shl | ShrS | ShrU |
| type ibitmaskop = Bitmask |
| |
| type vtestop = AnyTrue |
| type vunop = Not |
| type vbinop = And | Or | Xor | AndNot |
| type vternop = Bitselect |
| |
| type testop = (itestop, itestop, itestop, itestop, void, void) V128.laneop |
| type unop = (iunop, iunop, iunop, iunop, funop, funop) V128.laneop |
| type binop = (ibinop, ibinop, ibinop, ibinop, fbinop, fbinop) V128.laneop |
| type relop = (irelop, irelop, irelop, irelop, frelop, frelop) V128.laneop |
| type cvtop = (icvtop, icvtop, icvtop, icvtop, fcvtop, fcvtop) V128.laneop |
| type shiftop = (ishiftop, ishiftop, ishiftop, ishiftop, void, void) V128.laneop |
| type bitmaskop = (ibitmaskop, ibitmaskop, ibitmaskop, ibitmaskop, void, void) V128.laneop |
| |
| type nsplatop = Splat |
| type 'a nextractop = Extract of int * 'a |
| type nreplaceop = Replace of int |
| |
| type splatop = (nsplatop, nsplatop, nsplatop, nsplatop, nsplatop, nsplatop) V128.laneop |
| type extractop = (extension nextractop, extension nextractop, unit nextractop, unit nextractop, unit nextractop, unit nextractop) V128.laneop |
| type replaceop = (nreplaceop, nreplaceop, nreplaceop, nreplaceop, nreplaceop, nreplaceop) V128.laneop |
| end |
| |
| type testop = (I32Op.testop, I64Op.testop, F32Op.testop, F64Op.testop) Values.op |
| type unop = (I32Op.unop, I64Op.unop, F32Op.unop, F64Op.unop) Values.op |
| type binop = (I32Op.binop, I64Op.binop, F32Op.binop, F64Op.binop) Values.op |
| type relop = (I32Op.relop, I64Op.relop, F32Op.relop, F64Op.relop) Values.op |
| type cvtop = (I32Op.cvtop, I64Op.cvtop, F32Op.cvtop, F64Op.cvtop) Values.op |
| |
| type vec_testop = (V128Op.testop) Values.vecop |
| type vec_relop = (V128Op.relop) Values.vecop |
| type vec_unop = (V128Op.unop) Values.vecop |
| type vec_binop = (V128Op.binop) Values.vecop |
| type vec_cvtop = (V128Op.cvtop) Values.vecop |
| type vec_shiftop = (V128Op.shiftop) Values.vecop |
| type vec_bitmaskop = (V128Op.bitmaskop) Values.vecop |
| type vec_vtestop = (V128Op.vtestop) Values.vecop |
| type vec_vunop = (V128Op.vunop) Values.vecop |
| type vec_vbinop = (V128Op.vbinop) Values.vecop |
| type vec_vternop = (V128Op.vternop) Values.vecop |
| type vec_splatop = (V128Op.splatop) Values.vecop |
| type vec_extractop = (V128Op.extractop) Values.vecop |
| type vec_replaceop = (V128Op.replaceop) Values.vecop |
| |
| type ('t, 'p) memop = {ty : 't; align : int; offset : int32; pack : 'p} |
| type loadop = (num_type, (pack_size * extension) option) memop |
| type storeop = (num_type, pack_size option) memop |
| |
| type vec_loadop = (vec_type, (pack_size * vec_extension) option) memop |
| type vec_storeop = (vec_type, unit) memop |
| type vec_laneop = (vec_type, pack_size) memop * int |
| |
| |
| (* Expressions *) |
| |
| type var = int32 Source.phrase |
| type num = Values.num Source.phrase |
| type vec = Values.vec Source.phrase |
| type name = Utf8.unicode |
| |
| type block_type = VarBlockType of var | ValBlockType of value_type option |
| |
| type instr = instr' Source.phrase |
| and instr' = |
| | Unreachable (* trap unconditionally *) |
| | Nop (* do nothing *) |
| | Drop (* forget a value *) |
| | Select of value_type list option (* branchless conditional *) |
| | Block of block_type * instr list (* execute in sequence *) |
| | Loop of block_type * instr list (* loop header *) |
| | If of block_type * instr list * instr list (* conditional *) |
| | Br of var (* break to n-th surrounding label *) |
| | BrIf of var (* conditional break *) |
| | BrTable of var list * var (* indexed break *) |
| | Return (* break from function body *) |
| | Call of var (* call function *) |
| | CallIndirect of var * var (* call function through table *) |
| | LocalGet of var (* read local variable *) |
| | LocalSet of var (* write local variable *) |
| | LocalTee of var (* write local variable and keep value *) |
| | GlobalGet of var (* read global variable *) |
| | GlobalSet of var (* write global variable *) |
| | TableGet of var (* read table element *) |
| | TableSet of var (* write table element *) |
| | TableSize of var (* size of table *) |
| | TableGrow of var (* grow table *) |
| | TableFill of var (* fill table range with value *) |
| | TableCopy of var * var (* copy table range *) |
| | TableInit of var * var (* initialize table range from segment *) |
| | ElemDrop of var (* drop passive element segment *) |
| | Load of loadop (* read memory at address *) |
| | Store of storeop (* write memory at address *) |
| | VecLoad of vec_loadop (* read memory at address *) |
| | VecStore of vec_storeop (* write memory at address *) |
| | VecLoadLane of vec_laneop (* read single lane at address *) |
| | VecStoreLane of vec_laneop (* write single lane to address *) |
| | MemorySize (* size of memory *) |
| | MemoryGrow (* grow memory *) |
| | MemoryFill (* fill memory range with value *) |
| | MemoryCopy (* copy memory ranges *) |
| | MemoryInit of var (* initialize memory range from segment *) |
| | DataDrop of var (* drop passive data segment *) |
| | RefNull of ref_type (* null reference *) |
| | RefFunc of var (* function reference *) |
| | RefIsNull (* null test *) |
| | Const of num (* constant *) |
| | Test of testop (* numeric test *) |
| | Compare of relop (* numeric comparison *) |
| | Unary of unop (* unary numeric operator *) |
| | Binary of binop (* binary numeric operator *) |
| | Convert of cvtop (* conversion *) |
| | VecConst of vec (* constant *) |
| | VecTest of vec_testop (* vector test *) |
| | VecCompare of vec_relop (* vector comparison *) |
| | VecUnary of vec_unop (* unary vector operator *) |
| | VecBinary of vec_binop (* binary vector operator *) |
| | VecConvert of vec_cvtop (* vector conversion *) |
| | VecShift of vec_shiftop (* vector shifts *) |
| | VecBitmask of vec_bitmaskop (* vector masking *) |
| | VecTestBits of vec_vtestop (* vector bit test *) |
| | VecUnaryBits of vec_vunop (* unary bit vector operator *) |
| | VecBinaryBits of vec_vbinop (* binary bit vector operator *) |
| | VecTernaryBits of vec_vternop (* ternary bit vector operator *) |
| | VecSplat of vec_splatop (* number to vector conversion *) |
| | VecExtract of vec_extractop (* extract lane from vector *) |
| | VecReplace of vec_replaceop (* replace lane in vector *) |
| |
| |
| (* Globals & Functions *) |
| |
| type const = instr list Source.phrase |
| |
| type global = global' Source.phrase |
| and global' = |
| { |
| gtype : global_type; |
| ginit : const; |
| } |
| |
| type func = func' Source.phrase |
| and func' = |
| { |
| ftype : var; |
| locals : value_type list; |
| body : instr list; |
| } |
| |
| |
| (* Tables & Memories *) |
| |
| type table = table' Source.phrase |
| and table' = |
| { |
| ttype : table_type; |
| } |
| |
| type memory = memory' Source.phrase |
| and memory' = |
| { |
| mtype : memory_type; |
| } |
| |
| type segment_mode = segment_mode' Source.phrase |
| and segment_mode' = |
| | Passive |
| | Active of {index : var; offset : const} |
| | Declarative |
| |
| type elem_segment = elem_segment' Source.phrase |
| and elem_segment' = |
| { |
| etype : ref_type; |
| einit : const list; |
| emode : segment_mode; |
| } |
| |
| type data_segment = data_segment' Source.phrase |
| and data_segment' = |
| { |
| dinit : string; |
| dmode : segment_mode; |
| } |
| |
| |
| (* Modules *) |
| |
| type type_ = func_type Source.phrase |
| |
| type export_desc = export_desc' Source.phrase |
| and export_desc' = |
| | FuncExport of var |
| | TableExport of var |
| | MemoryExport of var |
| | GlobalExport of var |
| |
| type export = export' Source.phrase |
| and export' = |
| { |
| name : name; |
| edesc : export_desc; |
| } |
| |
| type import_desc = import_desc' Source.phrase |
| and import_desc' = |
| | FuncImport of var |
| | TableImport of table_type |
| | MemoryImport of memory_type |
| | GlobalImport of global_type |
| |
| type import = import' Source.phrase |
| and import' = |
| { |
| module_name : name; |
| item_name : name; |
| idesc : import_desc; |
| } |
| |
| type start = start' Source.phrase |
| and start' = |
| { |
| sfunc : var; |
| } |
| |
| type module_ = module_' Source.phrase |
| and module_' = |
| { |
| types : type_ list; |
| globals : global list; |
| tables : table list; |
| memories : memory list; |
| funcs : func list; |
| start : start option; |
| elems : elem_segment list; |
| datas : data_segment list; |
| imports : import list; |
| exports : export list; |
| } |
| |
| |
| (* Auxiliary functions *) |
| |
| let empty_module = |
| { |
| types = []; |
| globals = []; |
| tables = []; |
| memories = []; |
| funcs = []; |
| start = None; |
| elems = []; |
| datas = []; |
| imports = []; |
| exports = []; |
| } |
| |
| open Source |
| |
| let func_type_for (m : module_) (x : var) : func_type = |
| (Lib.List32.nth m.it.types x.it).it |
| |
| let import_type (m : module_) (im : import) : extern_type = |
| let {idesc; _} = im.it in |
| match idesc.it with |
| | FuncImport x -> ExternFuncType (func_type_for m x) |
| | TableImport t -> ExternTableType t |
| | MemoryImport t -> ExternMemoryType t |
| | GlobalImport t -> ExternGlobalType t |
| |
| let export_type (m : module_) (ex : export) : extern_type = |
| let {edesc; _} = ex.it in |
| let its = List.map (import_type m) m.it.imports in |
| let open Lib.List32 in |
| match edesc.it with |
| | FuncExport x -> |
| let fts = |
| funcs its @ List.map (fun f -> func_type_for m f.it.ftype) m.it.funcs |
| in ExternFuncType (nth fts x.it) |
| | TableExport x -> |
| let tts = tables its @ List.map (fun t -> t.it.ttype) m.it.tables in |
| ExternTableType (nth tts x.it) |
| | MemoryExport x -> |
| let mts = memories its @ List.map (fun m -> m.it.mtype) m.it.memories in |
| ExternMemoryType (nth mts x.it) |
| | GlobalExport x -> |
| let gts = globals its @ List.map (fun g -> g.it.gtype) m.it.globals in |
| ExternGlobalType (nth gts x.it) |
| |
| let string_of_name n = |
| let b = Buffer.create 16 in |
| let escape uc = |
| if uc < 0x20 || uc >= 0x7f then |
| Buffer.add_string b (Printf.sprintf "\\u{%02x}" uc) |
| else begin |
| let c = Char.chr uc in |
| if c = '\"' || c = '\\' then Buffer.add_char b '\\'; |
| Buffer.add_char b c |
| end |
| in |
| List.iter escape n; |
| Buffer.contents b |
| |