(*****************************************************************************) (* *) (* Open Source License *) (* Copyright (c) 2022 Nomadic Labs *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) (* to deal in the Software without restriction, including without limitation *) (* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) (* and/or sell copies of the Software, and to permit persons to whom the *) (* Software is furnished to do so, subject to the following conditions: *) (* *) (* The above copyright notice and this permission notice shall be included *) (* in all copies or substantial portions of the Software. *) (* *) (* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) (* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) (* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) (* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) (* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) (* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) (* DEALINGS IN THE SOFTWARE. *) (* *) (*****************************************************************************) open Tezos_webassembly_interpreter open Tezos_lazy_containers module V = Instance.Vector module M = Instance.NameMap module C = Chunked_byte_vector open Tezos_tree_encoding (* TODO: https://gitlab.com/tezos/tezos/-/issues/3566 Locations should either be dropped or not. *) let no_region_encoding enc = conv (fun s -> Source.(s @@ no_region)) (fun {it; _} -> it) enc let vector_encoding value_enc = int32_lazy_vector (value [] Data_encoding.int32) value_enc module Lazy_vec = struct let raw_encoding vector_encoding = let offset = value ["offset"] Data_encoding.int32 in let vector = scope ["vector"] vector_encoding in conv (fun (offset, vector) -> Decode.LazyVec {offset; vector}) (fun (LazyVec {offset; vector}) -> (offset, vector)) (tup2 ~flatten:true offset vector) let encoding value_encoding = raw_encoding (vector_encoding value_encoding) end module Lazy_stack = struct let encoding value_enc = (* TODO: https://gitlab.com/tezos/tezos/-/issues/3569 The stack can be probably encoded in a unique key in the tree, since it is never used concurrently. *) let offset = value ["length"] Data_encoding.int32 in let vector = scope ["vector"] (vector_encoding value_enc) in conv (fun (length, vector) -> Decode.LazyStack {length; vector}) (fun (LazyStack {length; vector}) -> (length, vector)) (tup2 ~flatten:true offset vector) end module Byte_vector = struct type t' = Decode.byte_vector_kont let vkstart_case = case "VKStart" (value [] Data_encoding.unit) (function Decode.VKStart -> Some () | _ -> None) (fun () -> Decode.VKStart) let vkread_case = let value_enc = let pos = value ["pos"] Data_encoding.int64 in let length = value ["length"] Data_encoding.int64 in let data_label = value ["data_label"] Interpreter_encodings.Ast.data_label_encoding in tup3 ~flatten:true data_label pos length in case "VKRead" value_enc (function Decode.VKRead (b, p, l) -> Some (b, p, l) | _ -> None) (fun (b, p, l) -> Decode.VKRead (b, p, l)) let vkstop_case = case "VKStop" (value ["data_label"] Interpreter_encodings.Ast.data_label_encoding) (function Decode.VKStop b -> Some b | _ -> None) (fun b -> Decode.VKStop b) let tag_encoding = value [] Data_encoding.string let encoding = tagged_union tag_encoding [vkstart_case; vkread_case; vkstop_case] end module Name = struct let buffer_encoding = value [] Data_encoding.( conv (fun b -> (Buffer.contents b, Buffer.length b)) (fun (content, length) -> let b = Buffer.create length in Buffer.add_string b content ; b) (tup2 string int31)) let nkstart_case = case "NKStart" (value [] Data_encoding.unit) (function Decode.NKStart -> Some () | _ -> None) (fun () -> Decode.NKStart) let nkparse_case = let value_enc = let pos = value ["pos"] Data_encoding.int31 in let buffer = scope ["buffer"] buffer_encoding in let length = value ["length"] Data_encoding.int31 in tup3 ~flatten:true pos buffer length in case "NKParse" value_enc (function Decode.NKParse (p, v, l) -> Some (p, v, l) | _ -> None) (fun (p, v, l) -> Decode.NKParse (p, v, l)) let nkstop_case = case "NKStop" (value [] Data_encoding.string) (function Decode.NKStop v -> Some v | _ -> None) (fun v -> Decode.NKStop v) let tag_encoding = value [] Data_encoding.string let encoding = tagged_union tag_encoding [nkstart_case; nkparse_case; nkstop_case] end module Func_type = struct type tags = FKStart | FKIns | FKOut | FKStop let value_type_encoding = value [] Interpreter_encodings.Types.value_type_encoding let fkstart_case = case "FKStart" (value [] Data_encoding.unit) (function Decode.FKStart -> Some () | _ -> None) (fun () -> FKStart) let fkins_case = let lazy_vec = scope ["ins_kont"] (Lazy_vec.encoding value_type_encoding) in case "FKIns" lazy_vec (function Decode.FKIns vec -> Some vec | _ -> None) (fun vec -> FKIns vec) let fkout_case = let params = scope ["params"] (vector_encoding value_type_encoding) in let lazy_vec = scope ["lazy_kont"] (Lazy_vec.encoding value_type_encoding) in case "FKOut" (tup2 ~flatten:true params lazy_vec) (function Decode.FKOut (p, vec) -> Some (p, vec) | _ -> None) (fun (p, vec) -> FKOut (p, vec)) let fkstop_case = case "FKStop" Wasm_encoding.func_type_encoding (function Decode.FKStop ft -> Some ft | _ -> None) (fun ft -> FKStop ft) let tag_encoding = Data_encoding.string |> value [] let encoding = tagged_union tag_encoding [fkstart_case; fkins_case; fkout_case; fkstop_case] end let name_encoding = value [] Data_encoding.string module Import = struct let impkstart_case = let tag = "ImpKStart" in case tag (value [] (Data_encoding.constant tag)) (function Decode.ImpKStart -> Some () | _ -> None) (fun () -> ImpKStart) let impkmodulename_case = case "ImpKModuleName" (scope ["module_name"] Name.encoding) (function Decode.ImpKModuleName n -> Some n | _ -> None) (fun n -> ImpKModuleName n) let impkitemname_case = case "ImpKItemName" (tup2 ~flatten:false (scope ["module_name"] name_encoding) (scope ["item_name"] Name.encoding)) (function Decode.ImpKItemName (m, i) -> Some (m, i) | _ -> None) (fun (m, i) -> ImpKItemName (m, i)) let import_encoding = conv (fun (module_name, item_name, idesc) -> Ast.{module_name; item_name; idesc}) (fun {module_name; item_name; idesc} -> (module_name, item_name, idesc)) (tup3 ~flatten:true (scope ["module_name"] name_encoding) (scope ["item_name"] name_encoding) (value ["idesc"] Interpreter_encodings.Ast.import_desc_encoding)) let impkstop_case = case "ImpKStop" import_encoding (function Decode.ImpKStop i -> Some i | _ -> None) (fun i -> ImpKStop i) let tag_encoding = value [] Data_encoding.string let encoding = tagged_union tag_encoding [impkstart_case; impkmodulename_case; impkitemname_case; impkstop_case] end module Export = struct let expkstart_case = let tag = "ExpKStart" in case tag (value [] (Data_encoding.constant tag)) (function Decode.ExpKStart -> Some () | _ -> None) (fun () -> ExpKStart) let expkname_case = case "ExpKName" Name.encoding (function Decode.ExpKName n -> Some n | _ -> None) (fun n -> ExpKName n) let export_encoding = conv (fun (name, edesc) -> Ast.{name; edesc}) (fun {name; edesc} -> (name, edesc)) (tup2 ~flatten:true (scope ["name"] name_encoding) (value ["edesc"] Interpreter_encodings.Ast.export_desc_encoding)) let expkstop_case = case "ExpKStop" export_encoding (function Decode.ExpKStop e -> Some e | _ -> None) (fun e -> ExpKStop e) let tags_encoding = value [] Data_encoding.string let encoding = tagged_union tags_encoding [expkstart_case; expkname_case; expkstop_case] end module Size = struct let encoding = conv (fun (size, start) -> Decode.{size; start}) (fun {size; start} -> (size, start)) (tup2 ~flatten:true (value ["size"] Data_encoding.int31) (value ["start"] Data_encoding.int31)) end module Instr_block = struct let stop_case = case "IKStop" (value [] Interpreter_encodings.Ast.block_label_encoding) (function Decode.IKStop lbl -> Some lbl | _ -> None) (fun lbl -> IKStop lbl) let next_case = case "IKNext" (value [] Interpreter_encodings.Ast.block_label_encoding) (function Decode.IKNext lbl -> Some lbl | _ -> None) (fun lbl -> IKNext lbl) let block_case = let encoding = tup2 ~flatten:true (value ["type"] Interpreter_encodings.Ast.block_type_encoding) (value ["pos"] Data_encoding.int31) in case "IKBlock" encoding (function Decode.IKBlock (ty, i) -> Some (ty, i) | _ -> None) (fun (ty, i) -> IKBlock (ty, i)) let loop_case = let encoding = tup2 ~flatten:true (value ["type"] Interpreter_encodings.Ast.block_type_encoding) (value ["pos"] Data_encoding.int31) in case "IKLoop" encoding (function Decode.IKLoop (ty, i) -> Some (ty, i) | _ -> None) (fun (ty, i) -> IKLoop (ty, i)) let if1_case = let encoding = tup2 ~flatten:true (value ["type"] Interpreter_encodings.Ast.block_type_encoding) (value ["pos"] Data_encoding.int31) in case "IKIf1" encoding (function Decode.IKIf1 (ty, i) -> Some (ty, i) | _ -> None) (fun (ty, i) -> IKIf1 (ty, i)) let if2_case = let encoding = tup3 ~flatten:true (value ["type"] Interpreter_encodings.Ast.block_type_encoding) (value ["pos"] Data_encoding.int31) (value ["else"] Interpreter_encodings.Ast.block_label_encoding) in case "IKIf2" encoding (function | Decode.IKIf2 (ty, i, else_lbl) -> Some (ty, i, else_lbl) | _ -> None) (fun (ty, i, else_lbl) -> IKIf2 (ty, i, else_lbl)) let encoding = tagged_union (value [] Data_encoding.string) [stop_case; next_case; block_case; loop_case; if1_case; if2_case] end module Block = struct let start_case = let tag = "BlockStart" in case tag (value [] (Data_encoding.constant tag)) (function Decode.BlockStart -> Some () | _ -> None) (fun _ -> BlockStart) let parse_case = case "BlockParse" (scope [] (Lazy_stack.encoding Instr_block.encoding)) (function Decode.BlockParse ik -> Some ik | _ -> None) (fun ik -> BlockParse ik) let stop_case = case "BlockStop" (value [] Interpreter_encodings.Ast.block_label_encoding) (function Decode.BlockStop lbl -> Some lbl | _ -> None) (fun lbl -> BlockStop lbl) let encoding = tagged_union (value [] Data_encoding.string) [start_case; parse_case; stop_case] end module Code = struct let value_type_acc_enc = let occurences = value ["occurences"] Data_encoding.int32 in let value_type = value ["type"] Interpreter_encodings.Types.value_type_encoding in tup2 ~flatten:true occurences value_type let ckstart_case = let tag = "CKStart" in case tag (value [] (Data_encoding.constant tag)) (function Decode.CKStart -> Some () | _ -> None) (fun () -> CKStart) let cklocalsparse_case = let left = value ["left"] Data_encoding.int31 in let size = scope ["size"] Size.encoding in let pos = value ["pos"] Data_encoding.int31 in let vec_kont = scope ["vec_kont"] (Lazy_vec.encoding value_type_acc_enc) in let locals_size = value ["locals_size"] Data_encoding.int64 in case "CKLocalsParse" (tup5 ~flatten:true left size pos vec_kont locals_size) (function | Decode.CKLocalsParse {left; size; pos; vec_kont; locals_size} -> Some (left, size, pos, vec_kont, locals_size) | _ -> None) (fun (left, size, pos, vec_kont, locals_size) -> Decode.CKLocalsParse {left; size; pos; vec_kont; locals_size}) let cklocalsaccumulate_case = let left = value ["left"] Data_encoding.int31 in let size = scope ["size"] Size.encoding in let pos = value ["pos"] Data_encoding.int31 in let type_vec = scope ["type_vec"] (Lazy_vec.encoding value_type_acc_enc) in let curr_type = scope ["curr_type"] (option value_type_acc_enc) in let vec_kont = scope ["vec_kont"] (Lazy_vec.encoding Func_type.value_type_encoding) in case "CKLocalsAccumulate" (tup6 ~flatten:true left size pos type_vec curr_type vec_kont) (function | Decode.CKLocalsAccumulate {left; size; pos; type_vec; curr_type; vec_kont} -> Some (left, size, pos, type_vec, curr_type, vec_kont) | _ -> None) (fun (left, size, pos, type_vec, curr_type, vec_kont) -> Decode.CKLocalsAccumulate {left; size; pos; type_vec; curr_type; vec_kont}) let ckbody_case = let left = value ["left"] Data_encoding.int31 in let size = scope ["size"] Size.encoding in let locals = scope ["locals"] (vector_encoding Func_type.value_type_encoding) in let const_kont = scope ["const_kont"] Block.encoding in case "CKBody" (tup4 ~flatten:true left size locals const_kont) (function | Decode.CKBody {left; size; locals; const_kont} -> Some (left, size, locals, const_kont) | _ -> None) (fun (left, size, locals, const_kont) -> CKBody {left; size; locals; const_kont}) let func_encoding = let ftype = value ["ftype"] Interpreter_encodings.Ast.var_encoding in let locals = scope ["locals"] (vector_encoding Func_type.value_type_encoding) in let body = value ["body"] Interpreter_encodings.Ast.block_label_encoding in conv (fun (ftype, locals, body) -> Source.(Ast.{ftype; locals; body} @@ no_region)) (fun {it = {ftype; locals; body}; _} -> (ftype, locals, body)) (tup3 ~flatten:true ftype locals body) let ckstop_case = case "CKStop" func_encoding (function Decode.CKStop func -> Some func | _ -> None) (fun func -> CKStop func) let encoding = tagged_union (value [] Data_encoding.string) [ ckstart_case; cklocalsparse_case; cklocalsaccumulate_case; ckbody_case; ckstop_case; ] end module Elem = struct let region enc = Data_encoding.conv (fun p -> p.Source.it) (fun v -> Source.(v @@ no_region)) enc let index_kind_encoding = Data_encoding.string_enum [("Indexed", Decode.Indexed); ("Const", Decode.Const)] let ekstart_case = let tag = "EKStart" in case tag (value [] (Data_encoding.constant "tag")) (function Decode.EKStart -> Some () | _ -> None) (fun () -> EKStart) let ekmode_case = let left = value ["left"] Data_encoding.int31 in let index = value ["index"] (Interpreter_encodings.Source.phrase_encoding Data_encoding.int32) in let index_kind = value ["index_kind"] index_kind_encoding in let early_ref_type = value_option ["early_ref_type"] Interpreter_encodings.Types.ref_type_encoding in let offset_kont = value ["offset_kont"] Data_encoding.int31 in let offset_kont_code = scope ["offset_kont_code"] Block.encoding in case "EKMode" (tup6 ~flatten:true left index index_kind early_ref_type offset_kont offset_kont_code) (function | Decode.EKMode { left; index; index_kind; early_ref_type; offset_kont = offset_kont, offset_kont_code; } -> Some ( left, index, index_kind, early_ref_type, offset_kont, offset_kont_code ) | _ -> None) (fun ( left, index, index_kind, early_ref_type, offset_kont, offset_kont_code ) -> EKMode { left; index; index_kind; early_ref_type; offset_kont = (offset_kont, offset_kont_code); }) let ekinitindexed_case = let mode = value ["mode"] Interpreter_encodings.Ast.segment_mode_encoding in let ref_type = value ["ref_type"] Interpreter_encodings.Types.ref_type_encoding in let einit_vec = scope ["einit_vec"] (Lazy_vec.encoding (value [] (Interpreter_encodings.Source.phrase_encoding Interpreter_encodings.Ast.block_label_encoding))) in case "EKInitIndexed" (tup3 ~flatten:true mode ref_type einit_vec) (function | Decode.EKInitIndexed {mode; ref_type; einit_vec} -> Some (mode, ref_type, einit_vec) | _ -> None) (fun (mode, ref_type, einit_vec) -> EKInitIndexed {mode; ref_type; einit_vec}) let ekinitconst_case = let mode = value ["mode"] Interpreter_encodings.Ast.segment_mode_encoding in let ref_type = value ["ref_type"] Interpreter_encodings.Types.ref_type_encoding in let einit_vec = scope ["einit_vec"] (Lazy_vec.encoding (value [] (Interpreter_encodings.Source.phrase_encoding Interpreter_encodings.Ast.block_label_encoding))) in let einit_kont_pos = value ["einit_kont_pos"] Data_encoding.int31 in let einit_kont_block = scope ["einit_kont_block"] Block.encoding in case "EKInitConst" (tup5 ~flatten:true mode ref_type einit_vec einit_kont_pos einit_kont_block) (function | Decode.EKInitConst {mode; ref_type; einit_vec; einit_kont = pos, block} -> Some (mode, ref_type, einit_vec, pos, block) | _ -> None) (fun (mode, ref_type, einit_vec, pos, block) -> EKInitConst {mode; ref_type; einit_vec; einit_kont = (pos, block)}) let elem_encoding = let etype = value ["ref_type"] Interpreter_encodings.Types.ref_type_encoding in let einit = scope ["einit"] (vector_encoding (value [] Interpreter_encodings.Ast.const_encoding)) in let emode = value ["mode"] Interpreter_encodings.Ast.segment_mode_encoding in conv (fun (etype, einit, emode) -> Ast.{etype; einit; emode}) (fun Ast.{etype; einit; emode} -> (etype, einit, emode)) (tup3 ~flatten:true etype einit emode) let ekstop_case = case "EKStop" elem_encoding (function Decode.EKStop elem -> Some elem | _ -> None) (fun elem -> EKStop elem) let encoding = tagged_union (value [] Data_encoding.string) [ ekstart_case; ekmode_case; ekinitindexed_case; ekinitconst_case; ekstop_case; ] end module Data = struct let dkstart_case = let tag = "DKStart" in case tag (value [] (Data_encoding.constant tag)) (function Decode.DKStart -> Some () | _ -> None) (fun () -> DKStart) let dkmode_case = let left = value ["left"] Data_encoding.int31 in let index = value ["index"] (Interpreter_encodings.Source.phrase_encoding Data_encoding.int32) in let offset_kont = value ["offset_kont"] Data_encoding.int31 in let offset_kont_code = scope ["offset_kont_code"] Block.encoding in case "DKMode" (tup4 ~flatten:true left index offset_kont offset_kont_code) (function | Decode.DKMode {left; index; offset_kont = pos, block} -> Some (left, index, pos, block) | _ -> None) (fun (left, index, pos, block) -> DKMode {left; index; offset_kont = (pos, block)}) let dkinit_case = let dmode = value ["dmode"] Interpreter_encodings.Ast.segment_mode_encoding in let init_kont = scope ["init_kont"] Byte_vector.encoding in case "DKInit" (tup2 ~flatten:true dmode init_kont) (function | Decode.DKInit {dmode; init_kont} -> Some (dmode, init_kont) | _ -> None) (fun (dmode, init_kont) -> DKInit {dmode; init_kont}) let data_segment_encoding = let dmode = value ["dmode"] Interpreter_encodings.Ast.segment_mode_encoding in let dinit = value ["dinit"] Interpreter_encodings.Ast.data_label_encoding in conv (fun (dinit, dmode) -> Ast.{dinit; dmode}) (fun {dinit; dmode} -> (dinit, dmode)) (tup2 ~flatten:true dinit dmode) let dkstop_case = case "DKStop" data_segment_encoding (function Decode.DKStop data_segment -> Some data_segment | _ -> None) (fun data_segment -> DKStop data_segment) let encoding = tagged_union (value [] Data_encoding.string) [dkstart_case; dkmode_case; dkinit_case; dkstop_case] end module Field = struct let type_field_encoding = scope ["module"; "types"] (vector_encoding (no_region_encoding Wasm_encoding.func_type_encoding)) let import_field_encoding = scope ["module"; "imports"] (vector_encoding (no_region_encoding Import.import_encoding)) let func_field_encoding = scope ["module"; "funcs"] (vector_encoding (value [] Interpreter_encodings.Ast.var_encoding)) let table_field_encoding = scope ["module"; "tables"] (vector_encoding (value [] Interpreter_encodings.Ast.table_encoding)) let memory_field_encoding = scope ["module"; "memories"] (vector_encoding (value [] Interpreter_encodings.Ast.memory_encoding)) let global_field_encoding = scope ["module"; "globals"] (vector_encoding (value [] Interpreter_encodings.Ast.global_encoding)) let export_field_encoding = scope ["module"; "exports"] (vector_encoding (no_region_encoding Export.export_encoding)) let start_field_encoding = value_option ["module"; "start"] Interpreter_encodings.Ast.start_encoding let elem_field_encoding = scope ["module"; "elem_segments"] (vector_encoding (no_region_encoding Elem.elem_encoding)) let data_count_field_encoding = value_option ["module"; "data_count"] Data_encoding.int32 let code_field_encoding = scope ["module"; "code"] (vector_encoding Code.func_encoding) let data_field_encoding = scope ["module"; "data_segments"] (vector_encoding (no_region_encoding Data.data_segment_encoding)) let building_state_encoding = conv (fun ( types, imports, vars, tables, memories, globals, exports, start, (elems, data_count, code, datas) ) -> Decode. { types; imports; vars; tables; memories; globals; exports; start; elems; data_count; code; datas; }) (fun Decode. { types; imports; vars; tables; memories; globals; exports; start; elems; data_count; code; datas; } -> ( types, imports, vars, tables, memories, globals, exports, start, (elems, data_count, code, datas) )) (tup9 ~flatten:true type_field_encoding import_field_encoding func_field_encoding table_field_encoding memory_field_encoding global_field_encoding export_field_encoding start_field_encoding (tup4 ~flatten:true elem_field_encoding data_count_field_encoding code_field_encoding data_field_encoding)) (* Only used to encode field_type. *) type packed_field_type = | FieldType : ('a, 'repr) Decode.field_type -> packed_field_type let packed_field_type_encoding = let open Decode in let type_field_encoding = let tag = "TypeField" in case tag (value [] (Data_encoding.constant tag)) (function FieldType TypeField -> Some () | _ -> None) (fun () -> FieldType TypeField) in let import_field_encoding = let tag = "ImportField" in case tag (value [] (Data_encoding.constant tag)) (function FieldType ImportField -> Some () | _ -> None) (fun () -> FieldType ImportField) in let func_field_encoding = let tag = "FuncField" in case tag (value [] (Data_encoding.constant tag)) (function FieldType FuncField -> Some () | _ -> None) (fun () -> FieldType FuncField) in let table_field_encoding = let tag = "TableField" in case tag (value [] (Data_encoding.constant tag)) (function FieldType TableField -> Some () | _ -> None) (fun () -> FieldType TableField) in let memory_field_encoding = let tag = "MemoryField" in case tag (value [] (Data_encoding.constant tag)) (function FieldType MemoryField -> Some () | _ -> None) (fun () -> FieldType MemoryField) in let global_field_encoding = let tag = "GlobalField" in case tag (value [] (Data_encoding.constant tag)) (function FieldType GlobalField -> Some () | _ -> None) (fun () -> FieldType GlobalField) in let export_field_encoding = let tag = "ExportField" in case tag (value [] (Data_encoding.constant tag)) (function FieldType ExportField -> Some () | _ -> None) (fun () -> FieldType ExportField) in let start_field_encoding = let tag = "StartField" in case tag (value [] (Data_encoding.constant tag)) (function FieldType StartField -> Some () | _ -> None) (fun () -> FieldType StartField) in let elem_field_encoding = let tag = "ElemField" in case tag (value [] (Data_encoding.constant tag)) (function FieldType ElemField -> Some () | _ -> None) (fun () -> FieldType ElemField) in let data_count_field_encoding = let tag = "DataCountField" in case tag (value [] (Data_encoding.constant tag)) (function FieldType DataCountField -> Some () | _ -> None) (fun () -> FieldType DataCountField) in let code_field_encoding = let tag = "CodeField" in case tag (value [] (Data_encoding.constant tag)) (function FieldType CodeField -> Some () | _ -> None) (fun () -> FieldType CodeField) in let data_field_encoding = let tag = "DataField" in case tag (value [] (Data_encoding.constant tag)) (function FieldType DataField -> Some () | _ -> None) (fun () -> FieldType DataField) in tagged_union (value [] Data_encoding.string) [ type_field_encoding; import_field_encoding; func_field_encoding; table_field_encoding; memory_field_encoding; global_field_encoding; export_field_encoding; start_field_encoding; elem_field_encoding; data_count_field_encoding; code_field_encoding; data_field_encoding; ] (* Only used to encode lazy vector parameterized by the field type in the continuation. *) type packed_typed_lazy_vec = | TypedLazyVec : ('a, Decode.vec_repr) Decode.field_type * 'a Decode.lazy_vec_kont -> packed_typed_lazy_vec let packed_typed_lazy_vec_encoding = let open Decode in let type_field_encoding = let tag = "TypeField" in case tag (Lazy_vec.raw_encoding type_field_encoding) (function TypedLazyVec (TypeField, vec) -> Some vec | _ -> None) (fun vec -> TypedLazyVec (TypeField, vec)) in let import_field_encoding = let tag = "ImportField" in case tag (Lazy_vec.raw_encoding import_field_encoding) (function TypedLazyVec (ImportField, vec) -> Some vec | _ -> None) (fun vec -> TypedLazyVec (ImportField, vec)) in let func_field_encoding = let tag = "FuncField" in case tag (Lazy_vec.raw_encoding func_field_encoding) (function TypedLazyVec (FuncField, vec) -> Some vec | _ -> None) (fun vec -> TypedLazyVec (FuncField, vec)) in let table_field_encoding = let tag = "TableField" in case tag (Lazy_vec.raw_encoding table_field_encoding) (function TypedLazyVec (TableField, vec) -> Some vec | _ -> None) (fun vec -> TypedLazyVec (TableField, vec)) in let memory_field_encoding = let tag = "MemoryField" in case tag (Lazy_vec.raw_encoding memory_field_encoding) (function TypedLazyVec (MemoryField, vec) -> Some vec | _ -> None) (fun vec -> TypedLazyVec (MemoryField, vec)) in let global_field_encoding = let tag = "GlobalField" in case tag (Lazy_vec.raw_encoding global_field_encoding) (function TypedLazyVec (GlobalField, vec) -> Some vec | _ -> None) (fun vec -> TypedLazyVec (GlobalField, vec)) in let export_field_encoding = let tag = "ExportField" in case tag (Lazy_vec.raw_encoding export_field_encoding) (function TypedLazyVec (ExportField, vec) -> Some vec | _ -> None) (fun vec -> TypedLazyVec (ExportField, vec)) in let elem_field_encoding = let tag = "ElemField" in case tag (Lazy_vec.raw_encoding elem_field_encoding) (function TypedLazyVec (ElemField, vec) -> Some vec | _ -> None) (fun vec -> TypedLazyVec (ElemField, vec)) in let code_field_encoding = let tag = "CodeField" in case tag (Lazy_vec.raw_encoding code_field_encoding) (function TypedLazyVec (CodeField, vec) -> Some vec | _ -> None) (fun vec -> TypedLazyVec (CodeField, vec)) in let data_field_encoding = let tag = "DataField" in case tag (Lazy_vec.raw_encoding data_field_encoding) (function TypedLazyVec (DataField, vec) -> Some vec | _ -> None) (fun vec -> TypedLazyVec (DataField, vec)) in tagged_union (value [] Data_encoding.string) [ type_field_encoding; import_field_encoding; func_field_encoding; table_field_encoding; memory_field_encoding; global_field_encoding; export_field_encoding; elem_field_encoding; code_field_encoding; data_field_encoding; ] end module Module = struct let mkstart_case = case "MKStart" (value [] Data_encoding.unit) (function Decode.MKStart -> Some () | _ -> None) (fun () -> Decode.MKStart) let mkskipcustom_case = case "MKSkipCustom" (option Field.packed_field_type_encoding) (function | Decode.MKSkipCustom (Some field_type) -> Some (Some (Field.FieldType field_type)) | Decode.MKSkipCustom None -> Some None | _ -> None) (function | None -> MKSkipCustom None | Some (FieldType ft) -> MKSkipCustom (Some ft)) let mkfieldstart_case = case "MKFieldStart" Field.packed_field_type_encoding (function | Decode.MKFieldStart field_type -> Some (Field.FieldType field_type) | _ -> None) (fun (FieldType ft) -> MKFieldStart ft) let mkfield_case = case "MKField" (tup2 ~flatten:true Field.packed_typed_lazy_vec_encoding Size.encoding) (function | Decode.MKField (field_type, size, vec) -> Some (Field.TypedLazyVec (field_type, vec), size) | _ -> None) (fun (TypedLazyVec (ft, vec), size) -> MKField (ft, size, vec)) let mkelaboratefunc_case = let func_types = Field.func_field_encoding in let func_bodies = Field.code_field_encoding in let func_kont = scope ["func_kont"] (Lazy_vec.encoding Code.func_encoding) in let instr_kont = scope ["instr_kont"] (option (Lazy_vec.encoding (Lazy_vec.encoding Wasm_encoding.instruction_encoding))) in let no_datas_in_func = value ["no-datas-in-funcs"] Data_encoding.bool in case "MKElaborateFunc" (tup5 ~flatten:true func_types func_bodies func_kont instr_kont no_datas_in_func) (function | Decode.MKElaborateFunc (func_types, func_bodies, func_kont, instr_kont, no_datas_in_func) -> Some (func_types, func_bodies, func_kont, instr_kont, no_datas_in_func) | _ -> None) (fun (func_types, func_bodies, func_kont, instr_kont, no_datas_in_func) -> MKElaborateFunc (func_types, func_bodies, func_kont, instr_kont, no_datas_in_func)) let module_funcs_encoding = scope ["module"; "funcs"] (vector_encoding Code.func_encoding) let mkbuild_case = let no_datas_in_func = value ["no-datas-in-funcs"] Data_encoding.bool in case "MKBuild" (tup2 ~flatten:true (option module_funcs_encoding) no_datas_in_func) (function | Decode.MKBuild (funcs, no_datas_in_func) -> Some (funcs, no_datas_in_func) | _ -> None) (fun (funcs, no_datas_in_func) -> MKBuild (funcs, no_datas_in_func)) let mktypes_case = let func_type_kont = scope ["func_type_kont"] Func_type.encoding in let pos = value ["pos"] Data_encoding.int31 in let size = scope ["size"] Size.encoding in let type_accumulator = Lazy_vec.raw_encoding Field.type_field_encoding in case "MKTypes" (tup4 ~flatten:true func_type_kont pos size type_accumulator) (function | Decode.MKTypes (func_type_kont, pos, size, types_acc) -> Some (func_type_kont, pos, size, types_acc) | _ -> None) (fun (func_type_kont, pos, size, types_acc) -> MKTypes (func_type_kont, pos, size, types_acc)) let mkimport_case = let import_kont = scope ["import_kont"] Import.encoding in let pos = value ["pos"] Data_encoding.int31 in let size = scope ["size"] Size.encoding in let import_accumulator = Lazy_vec.raw_encoding Field.import_field_encoding in case "MKImport" (tup4 ~flatten:true import_kont pos size import_accumulator) (function | Decode.MKImport (import_kont, pos, size, import_acc) -> Some (import_kont, pos, size, import_acc) | _ -> None) (fun (import_kont, pos, size, import_acc) -> MKImport (import_kont, pos, size, import_acc)) let mkexport_case = let export_kont = scope ["export_kont"] Export.encoding in let pos = value ["pos"] Data_encoding.int31 in let size = scope ["size"] Size.encoding in let export_accumulator = Lazy_vec.raw_encoding Field.export_field_encoding in case "MKExport" (tup4 ~flatten:true export_kont pos size export_accumulator) (function | Decode.MKExport (export_kont, pos, size, export_acc) -> Some (export_kont, pos, size, export_acc) | _ -> None) (fun (export_kont, pos, size, export_acc) -> MKExport (export_kont, pos, size, export_acc)) let mkglobal_case = let global_type = value ["global_type"] Interpreter_encodings.Types.global_type_encoding in let block_kont = scope ["block_kont"] Block.encoding in let pos = value ["pos"] Data_encoding.int31 in let size = scope ["size"] Size.encoding in let global_accumulator = Lazy_vec.raw_encoding Field.global_field_encoding in case "MKGlobal" (tup5 ~flatten:true global_type pos block_kont size global_accumulator) (function | Decode.MKGlobal (global_type, pos, block_kont, size, global_acc) -> Some (global_type, pos, block_kont, size, global_acc) | _ -> None) (fun (global_type, pos, block_kont, size, global_acc) -> MKGlobal (global_type, pos, block_kont, size, global_acc)) let mkdata_case = let data_kont = scope ["data_kont"] Data.encoding in let pos = value ["pos"] Data_encoding.int31 in let size = scope ["size"] Size.encoding in let data_accumulator = Lazy_vec.raw_encoding Field.data_field_encoding in case "MKData" (tup4 ~flatten:true data_kont pos size data_accumulator) (function | Decode.MKData (data_kont, pos, size, data_acc) -> Some (data_kont, pos, size, data_acc) | _ -> None) (fun (data_kont, pos, size, data_acc) -> MKData (data_kont, pos, size, data_acc)) let mkelem_case = let elem_kont = scope ["elem_kont"] Elem.encoding in let pos = value ["pos"] Data_encoding.int31 in let size = scope ["size"] Size.encoding in let elem_accumulator = Lazy_vec.raw_encoding Field.elem_field_encoding in case "MKElem" (tup4 ~flatten:true elem_kont pos size elem_accumulator) (function | Decode.MKElem (elem_kont, pos, size, elem_acc) -> Some (elem_kont, pos, size, elem_acc) | _ -> None) (fun (elem_kont, pos, size, elem_acc) -> MKElem (elem_kont, pos, size, elem_acc)) let mkcode_case = let code_kont = scope ["code_kont"] Code.encoding in let pos = value ["pos"] Data_encoding.int31 in let size = scope ["size"] Size.encoding in let code_accumulator = Lazy_vec.raw_encoding Field.code_field_encoding in case "MKCode" (tup4 ~flatten:true code_kont pos size code_accumulator) (function | Decode.MKCode (code_kont, pos, size, code_acc) -> Some (code_kont, pos, size, code_acc) | _ -> None) (fun (code_kont, pos, size, code_acc) -> MKCode (code_kont, pos, size, code_acc)) let module_encoding = let open Field in conv (fun ( types, globals, tables, memories, funcs, start, elems, datas, (imports, exports, allocations) ) -> Ast. { types; tables; memories; globals; funcs; imports; exports; elems; datas; start; allocations; }) (fun { types; tables; memories; globals; funcs; imports; exports; elems; datas; start; allocations; } -> ( types, globals, tables, memories, funcs, start, elems, datas, (imports, exports, allocations) )) (tup9 ~flatten:true type_field_encoding global_field_encoding table_field_encoding memory_field_encoding module_funcs_encoding start_field_encoding elem_field_encoding data_field_encoding (tup3 ~flatten:true import_field_encoding export_field_encoding Wasm_encoding.allocations_encoding)) let mkstop_case = case "MKStop" (no_region_encoding module_encoding) (function Decode.MKStop m -> Some m | _ -> None) (fun m -> MKStop m) let encoding = tagged_union (value [] Data_encoding.string) [ mkstart_case; mkskipcustom_case; mkfieldstart_case; mkfield_case; mkelaboratefunc_case; mkbuild_case; mkstop_case; mktypes_case; mkimport_case; mkexport_case; mkglobal_case; mkelem_case; mkdata_case; mkelem_case; mkcode_case; ] end module Building_state = struct let types_encoding = vector_encoding (no_region_encoding Wasm_encoding.func_type_encoding) let imports_encoding = vector_encoding (no_region_encoding Import.import_encoding) let vars_encoding = vector_encoding (value [] Interpreter_encodings.Ast.var_encoding) let tables_encoding = vector_encoding (value [] Interpreter_encodings.Ast.table_encoding) let memories_encoding = vector_encoding (value [] Interpreter_encodings.Ast.memory_encoding) let globals_encoding = vector_encoding (value [] Interpreter_encodings.Ast.global_encoding) let exports_encoding = vector_encoding (no_region_encoding Export.export_encoding) let start_encoding = value_option [] Interpreter_encodings.Ast.start_encoding let elems_encoding = vector_encoding (no_region_encoding Elem.elem_encoding) let code_encoding = vector_encoding (no_region_encoding Wasm_encoding.func'_encoding) let datas_encoding = vector_encoding (no_region_encoding Data.data_segment_encoding) let encoding = conv (fun ( types, imports, vars, tables, memories, globals, exports, start, (elems, data_count, code, datas) ) -> Decode. { types; imports; vars; tables; memories; globals; exports; start; elems; data_count; code; datas; }) (fun { types; imports; vars; tables; memories; globals; exports; start; elems; data_count; code; datas; } -> ( types, imports, vars, tables, memories, globals, exports, start, (elems, data_count, code, datas) )) (tup9 ~flatten:true (scope ["types"] types_encoding) (scope ["imports"] imports_encoding) (scope ["vars"] vars_encoding) (scope ["tables"] tables_encoding) (scope ["memories"] memories_encoding) (scope ["globals"] globals_encoding) (scope ["exports"] exports_encoding) (scope ["start"] start_encoding) (tup4 ~flatten:true (scope ["elems"] elems_encoding) (scope ["data_count"] (value_option [] Data_encoding.int32)) (scope ["code"] code_encoding) (scope ["datas"] datas_encoding))) end module Decode = struct let encoding = conv (fun ( building_state, module_kont, allocation_state, stream_pos, stream_name ) -> Decode. { building_state; module_kont; allocation_state; stream_pos; stream_name; }) (fun { building_state; module_kont; allocation_state; stream_pos; stream_name; } -> (building_state, module_kont, allocation_state, stream_pos, stream_name)) @@ tup5 ~flatten:true (scope ["building_state"] Building_state.encoding) (scope ["module_kont"] Module.encoding) (scope ["allocation_state"] Wasm_encoding.allocations_encoding) (value ["stream_pos"] Data_encoding.int31) (value ["stream_name"] Data_encoding.string) end