diff --git a/src/lib_scoru_wasm/host_funcs.ml b/src/lib_scoru_wasm/host_funcs.ml index 09a2fe2b3f3269f20ba326705a467542208c7506..9320566785d9c06e8b2e71474c3cbcae2c10b525 100644 --- a/src/lib_scoru_wasm/host_funcs.ml +++ b/src/lib_scoru_wasm/host_funcs.ml @@ -26,9 +26,6 @@ open Tezos_webassembly_interpreter open Instance -let lookup name = - Stdlib.failwith (Printf.sprintf "Unknown host function %s" name) - exception Bad_input let aux_write_input_in_memory ~input_buffer ~module_inst ~rtype_offset @@ -62,8 +59,7 @@ let aux_write_input_in_memory ~input_buffer ~module_inst ~rtype_offset in Lwt.return input_size -let read_input = - let open Lwt.Syntax in +let read_input_type = let input_types = Types. [ @@ -76,31 +72,47 @@ let read_input = |> Vector.of_list in let output_types = Types.[NumType I32Type] |> Vector.of_list in - let fun_type = Types.FuncType (input_types, output_types) in - let f input_buffer module_inst inputs = - match inputs with - | [ - Values.(Num (I32 rtype_offset)); - Values.(Num (I32 level_offset)); - Values.(Num (I32 id_offset)); - Values.(Num (I32 dst)); - Values.(Num (I32 max_bytes)); - ] -> - let* x = - aux_write_input_in_memory - ~input_buffer - ~module_inst - ~rtype_offset - ~level_offset - ~id_offset - ~dst - ~max_bytes - in - Lwt.return [Values.(Num (I32 (I32.of_int_s x)))] - | _ -> raise Bad_input - in - Func.HostFunc (fun_type, f) + Types.FuncType (input_types, output_types) + +let read_input_name = "tezos_read_input" + +let read_input = + Host_funcs.Host_func + (fun input_buffer module_inst inputs -> + let open Lwt.Syntax in + match inputs with + | [ + Values.(Num (I32 rtype_offset)); + Values.(Num (I32 level_offset)); + Values.(Num (I32 id_offset)); + Values.(Num (I32 dst)); + Values.(Num (I32 max_bytes)); + ] -> + let* x = + aux_write_input_in_memory + ~input_buffer + ~module_inst + ~rtype_offset + ~level_offset + ~id_offset + ~dst + ~max_bytes + in + Lwt.return [Values.(Num (I32 (I32.of_int_s x)))] + | _ -> raise Bad_input) + +let lookup name = + let open Lwt.Syntax in + let+ name = Utf8.encode name in + match name with + | "read_input" -> ExternFunc (HostFunc (read_input_type, read_input_name)) + | _ -> raise Not_found + +let register_host_funcs registry = + Host_funcs.register ~global_name:read_input_name read_input registry module Internal_for_tests = struct let aux_write_input_in_memory = aux_write_input_in_memory + + let read_input = Func.HostFunc (read_input_type, read_input_name) end diff --git a/src/lib_scoru_wasm/host_funcs.mli b/src/lib_scoru_wasm/host_funcs.mli index 48bdd7ef07e0ade3142cd334e04b944871de43f7..fb4ac90aa3f624136a9ac1d6c7d1917cc64bf307 100644 --- a/src/lib_scoru_wasm/host_funcs.mli +++ b/src/lib_scoru_wasm/host_funcs.mli @@ -23,25 +23,32 @@ (* *) (*****************************************************************************) -(** [lookup name] retrieves or instantiates a host function by the given - [name]. *) -val lookup : string -> ('input, 'inst) Tezos_webassembly_interpreter.Func.t +(** [lookup name] retrieves or instantiates a host function by the given [name]. + Currently dispatches [read_input] to {!read_input} using host function global + names as registered by {!register_host_funcs}. + Used to plug host function wrappers in the WASN interpreter linker. *) +val lookup : + Tezos_webassembly_interpreter.Ast.name -> + Tezos_webassembly_interpreter.Instance.extern Lwt.t -exception Bad_input +(** [register_host_funcs] registers all the PVMs host functions into a WASM + interpreter's registry, using the names expected by {!lookup}. + + Currently, the registered functions are: + - [read_input]: + It has to be invoked with a list + of 5 values representing rtype_offset, level_offset, id_offset, + dst and max_bytes, otherwise it raises the [Bad_input] exception. -(** [read_input] is a host function. It has to be invoked with a list - of 5 values representing rtype_offset, level_offset, id_offset, - dst and max_bytes, otherwise it raises the [Bad_input] exception. + When invoked, it write the content of an input message into the + memory of a [module_inst]. It also checks that the input payload + is no larger than the input is not too large. Finally, it returns + returns a singleton value list containing the size of the + input_buffer payload. *) +val register_host_funcs : + Tezos_webassembly_interpreter.Host_funcs.registry -> unit - When invoked, it write the content of an input message into the - memory of a [module_inst]. It also checks that the input payload - is no larger than the input is not too large. Finally, it returns - returns a singleton value list containing the size of the - input_buffer payload. *) -val read_input : - ( Tezos_webassembly_interpreter.Input_buffer.t, - Tezos_webassembly_interpreter.Instance.module_inst ref ) - Tezos_webassembly_interpreter.Func.func +exception Bad_input module Internal_for_tests : sig (** [aux_write_memory ~input_buffer ~module_inst ~rtype_offset @@ -60,4 +67,6 @@ module Internal_for_tests : sig dst:int32 -> max_bytes:int32 -> int Lwt.t + + val read_input : Tezos_webassembly_interpreter.Instance.func_inst end diff --git a/src/lib_scoru_wasm/test/test_input.ml b/src/lib_scoru_wasm/test/test_input.ml index 3dd99ca36b3c2d13b81ccb8fd4ff65035b263185..b13f1a5da16fd8a6e77cdf38a5be4e3589243cd9 100644 --- a/src/lib_scoru_wasm/test/test_input.ml +++ b/src/lib_scoru_wasm/test/test_input.ml @@ -153,8 +153,16 @@ let test_host_fun () = Num (I32 0l); Num (I32 4l); Num (I32 10l); Num (I32 50l); Num (I32 3600l); ] in + let host_funcs_registry = Tezos_webassembly_interpreter.Host_funcs.empty () in + Host_funcs.register_host_funcs host_funcs_registry ; + let* module_inst, result = - Eval.invoke ~module_inst ~input Host_funcs.read_input values + Eval.invoke + host_funcs_registry + ~module_inst + ~input + Host_funcs.Internal_for_tests.read_input + values in let* memory = Tezos_webassembly_interpreter.Lazy_vector.LwtInt32Vector.get diff --git a/src/lib_scoru_wasm/wasm_decodings.ml b/src/lib_scoru_wasm/wasm_decodings.ml index c8852b8c3c58bcbdb4828be11b2c5048300be239..286a73f1f0bb0dd6ab8429b557ebf0bec84203dd 100644 --- a/src/lib_scoru_wasm/wasm_decodings.ml +++ b/src/lib_scoru_wasm/wasm_decodings.ml @@ -427,8 +427,9 @@ module Make (T : Tree.S) = struct (Data_encoding.string_enum [("host", true); ("native", false)]) in if is_host_func then - let+ name = value ["name"] Data_encoding.string in - Host_funcs.lookup name + let* global_name = value ["global_name"] Data_encoding.string in + let+ func_type = scope ["func_type"] (func_type_decoding ()) in + Func.HostFunc (func_type, global_name) else let* type_ = func_type_decoding () in let* ftype = value ["ftype"] Interpreter_encodings.Ast.var_encoding in diff --git a/src/lib_scoru_wasm/wasm_pvm.ml b/src/lib_scoru_wasm/wasm_pvm.ml index f0ef2ead0084be1ec38f031d99b6141c4a82732a..846d19792d87e907465aec71224dcf730c3ad87e 100644 --- a/src/lib_scoru_wasm/wasm_pvm.ml +++ b/src/lib_scoru_wasm/wasm_pvm.ml @@ -39,7 +39,20 @@ module Make (T : Tree.S) : Wasm_pvm_sig.S with type tree = T.tree = struct module Decodings = Wasm_decodings.Make (T) - let compute_step = Lwt.return + let compute_step s = + let open Lwt.Syntax in + (* register the PVM host funcs wrappers in a module ["tezos"] into the WASM linker *) + let* () = + Tezos_webassembly_interpreter.( + Import.register ~module_name:(Utf8.decode "tezos")) + Host_funcs.lookup + in + (* build the registry of host functions (to be passed to the interpreter via its config *) + let host_funcs_registry = + Tezos_webassembly_interpreter.Host_funcs.empty () + in + Host_funcs.register_host_funcs host_funcs_registry ; + Lwt.return s (* TODO: https://gitlab.com/tezos/tezos/-/issues/3092 Implement handling of input logic. diff --git a/src/lib_webassembly/bin/main.ml b/src/lib_webassembly/bin/main.ml index 0c1e36ddaaddd201dafebdf340c30076dddc9b41..889c43eda17a658291e90df72f94cad706aba4f6 100644 --- a/src/lib_webassembly/bin/main.ml +++ b/src/lib_webassembly/bin/main.ml @@ -5,10 +5,11 @@ let version = "2.0" let configure () = let open Lwt.Syntax in let* () = - Import.register (Utf8.decode "spectest") (fun name type_ -> - Spectest.lookup name type_) + Import.register ~module_name:(Utf8.decode "spectest") Spectest.lookup in - Import.register (Utf8.decode "env") (fun name type_ -> Env.lookup name type_) + let+ () = Import.register ~module_name:(Utf8.decode "env") Env.lookup in + Spectest.register_host_funcs Run.host_funcs_registry ; + Env.register_host_funcs Run.host_funcs_registry let banner () = print_endline (name ^ " " ^ version ^ " reference interpreter") @@ -48,7 +49,7 @@ let run () = let open Lwt.Syntax in Lwt.catch (fun () -> - let* () = configure () in + let* registry = configure () in Arg.parse argspec (fun file -> add_arg ("(input " ^ quote file ^ ")")) diff --git a/src/lib_webassembly/bin/script/run.ml b/src/lib_webassembly/bin/script/run.ml index a5fc7ef8c4e343e23abe16f1c7dfbdef18af7859..165266bb9d2e15486d06bee96a724cb5742f231e 100644 --- a/src/lib_webassembly/bin/script/run.ml +++ b/src/lib_webassembly/bin/script/run.ml @@ -320,6 +320,8 @@ let print_results rs = (* Configuration *) +let host_funcs_registry = Host_funcs.empty () + module Map = Map.Make (String) let quote : script ref = ref [] @@ -351,7 +353,7 @@ let lookup_module = lookup "module" modules let lookup_instance = lookup "module" instances -let lookup_registry module_name item_name _t = +let lookup_registry module_name item_name = let* item_name = Lazy_vector.LwtInt32Vector.to_list item_name in let+ value = Instance.export (Map.find module_name !registry) item_name in match value with Some ext -> ext | None -> raise Not_found @@ -390,7 +392,9 @@ let run_action act : Values.value list Lwt.t = Script.error v.at "wrong type of argument") vs ins_l ; - let+ _, result = Eval.invoke f (List.map (fun v -> v.it) vs) in + let+ _, result = + Eval.invoke host_funcs_registry f (List.map (fun v -> v.it) vs) + in result | Some _ -> Assert.error act.at "export is not a function" | None -> Assert.error act.at "undefined export") @@ -509,7 +513,7 @@ let run_assertion ass : unit Lwt.t = Lwt.try_bind (fun () -> let* imports = Import.link m in - Eval.init m imports) + Eval.init host_funcs_registry m imports) (fun _ -> Assert.error ass.at "expected linking error") (function | Import.Unknown (_, msg) | Eval.Link (_, msg) -> @@ -524,7 +528,7 @@ let run_assertion ass : unit Lwt.t = Lwt.try_bind (fun () -> let* imports = Import.link m in - Eval.init m imports) + Eval.init host_funcs_registry m imports) (fun _ -> Assert.error ass.at "expected instantiation error") (function | Eval.Trap (_, msg) -> assert_message ass.at "instantiation" msg re @@ -572,7 +576,7 @@ let rec run_command cmd : unit Lwt.t = if not !Flags.dry then let* () = trace_lwt "Initializing..." in let* imports = Import.link m in - let+ inst = Eval.init m imports in + let+ inst = Eval.init host_funcs_registry m imports in bind instances x_opt inst else Lwt.return_unit | Register (name, x_opt) -> @@ -582,7 +586,7 @@ let rec run_command cmd : unit Lwt.t = let inst = lookup_instance x_opt cmd.at in let* utf8_name = Utf8.encode name in registry := Map.add utf8_name inst !registry ; - Import.register name (lookup_registry utf8_name)) + Import.register ~module_name:name (lookup_registry utf8_name)) else Lwt.return_unit | Action act -> quote := cmd :: !quote ; diff --git a/src/lib_webassembly/bin/script/run.mli b/src/lib_webassembly/bin/script/run.mli index 92fef80ba21fb1fb4a7f31a8845a8e5ed584cd22..fe92323f1016887c949805b9ec1616e2e2ff57b2 100644 --- a/src/lib_webassembly/bin/script/run.mli +++ b/src/lib_webassembly/bin/script/run.mli @@ -11,3 +11,5 @@ val run_string : string -> bool Lwt.t val run_file : string -> bool Lwt.t val run_stdin : unit -> unit Lwt.t + +val host_funcs_registry : Host_funcs.registry diff --git a/src/lib_webassembly/exec/eval.ml b/src/lib_webassembly/exec/eval.ml index 96ffa9119fe7ed40476f1a3ab4341617b341ffdf..f19f6d54fd5980a16c24032240bacfe25d240a6d 100644 --- a/src/lib_webassembly/exec/eval.ml +++ b/src/lib_webassembly/exec/eval.ml @@ -76,13 +76,14 @@ type config = { frame : frame; input : input_inst; code : code; + host_funcs : Host_funcs.registry; budget : int; (* to model stack overflow *) } let frame inst locals = {inst; locals} -let config ?(input = Input_buffer.alloc ()) inst vs es = - {frame = frame inst []; input; code = (vs, es); budget = 300} +let config ?(input = Input_buffer.alloc ()) host_funcs inst vs es = + {frame = frame inst []; input; code = (vs, es); budget = 300; host_funcs} let plain e = Plain e.it @@ e.at @@ -772,6 +773,7 @@ and step_resolved (c : config) frame vs e es : config Lwt.t = code = code'; budget = c.budget - 1; input = c.input; + host_funcs = c.host_funcs; } in (vs, [Frame (n, c'.frame, c'.code) @@ e.at]) @@ -800,10 +802,13 @@ and step_resolved (c : config) frame vs e es : config Lwt.t = ] in (vs', [Frame (n2, frame', ([], instr')) @@ e.at]) - | Func.HostFunc (t, f) -> + | Func.HostFunc (_, global_name) -> let inst = ref frame.inst in Lwt.catch (fun () -> + let (Host_funcs.Host_func f) = + Host_funcs.lookup ~global_name c.host_funcs + in let+ res = f c.input inst (List.rev args) in (List.rev res @ vs', [])) (function @@ -822,7 +827,8 @@ let rec eval (c : config) : value stack Lwt.t = (* Functions & Constants *) let invoke ?(module_inst = empty_module_inst) ?(input = Input_buffer.alloc ()) - (func : func_inst) (vs : value list) : (module_inst * value list) Lwt.t = + host_funcs (func : func_inst) (vs : value list) : + (module_inst * value list) Lwt.t = let at = match func with Func.AstFunc (_, _, f) -> f.at | _ -> no_region in let (FuncType (ins, out)) = Func.type_of func in let* ins_l = Lazy_vector.LwtInt32Vector.to_list ins in @@ -839,7 +845,12 @@ let invoke ?(module_inst = empty_module_inst) ?(input = Input_buffer.alloc ()) | Func.HostFunc _ -> Instance.Vector.create 0l in let c = - config ~input {module_inst with blocks} (List.rev vs) [Invoke func @@ at] + config + ~input + host_funcs + {module_inst with blocks} + (List.rev vs) + [Invoke func @@ at] in Lwt.catch (fun () -> @@ -850,7 +861,9 @@ let invoke ?(module_inst = empty_module_inst) ?(input = Input_buffer.alloc ()) | exn -> Lwt.fail exn) let eval_const (inst : module_inst) (const : const) : value Lwt.t = - let c = config inst [] [From_block (const.it, 0l) @@ const.at] in + let c = + config (Host_funcs.empty ()) inst [] [From_block (const.it, 0l) @@ const.at] + in let+ vs = eval c in match vs with | [v] -> v @@ -988,7 +1001,7 @@ let run_data inst i data = let run_start start = List.map plain [Call start.it.sfunc @@ start.at] -let init (m : module_) (exts : extern list) : module_inst Lwt.t = +let init host_funcs (m : module_) (exts : extern list) : module_inst Lwt.t = let open Lwt.Syntax in let { imports; @@ -1110,6 +1123,6 @@ let init (m : module_) (exts : extern list) : module_inst Lwt.t = let es_data = List.concat (Lib.List32.mapi (run_data inst) datas) in let es_start = Lib.Option.get (Lib.Option.map run_start start) [] in let+ (_ : Values.value stack) = - eval (config inst [] (es_elem @ es_data @ es_start)) + eval (config host_funcs inst [] (es_elem @ es_data @ es_start)) in inst diff --git a/src/lib_webassembly/exec/eval.mli b/src/lib_webassembly/exec/eval.mli index 5ef8ec7c897f5ec3318b4e539aaefe18141c6d70..cb39ff0619515e7e5e668b4a2a0bd9f822b38db1 100644 --- a/src/lib_webassembly/exec/eval.mli +++ b/src/lib_webassembly/exec/eval.mli @@ -10,11 +10,15 @@ exception Crash of Source.region * string exception Exhaustion of Source.region * string val init : - Ast.module_ -> extern list -> module_inst Lwt.t (* raises Link, Trap *) + Host_funcs.registry -> + Ast.module_ -> + extern list -> + module_inst Lwt.t (* raises Link, Trap *) val invoke : ?module_inst:module_inst -> ?input:Input_buffer.t -> + Host_funcs.registry -> func_inst -> value list -> (module_inst * value list) Lwt.t (* raises Trap *) diff --git a/src/lib_webassembly/host/env.ml b/src/lib_webassembly/host/env.ml index b4047753679679876ca8bcf1358f5256223fb6e7..e6200de05876c9f2dabb44a80df41d40196c30da 100644 --- a/src/lib_webassembly/host/env.ml +++ b/src/lib_webassembly/host/env.ml @@ -26,17 +26,36 @@ let int = function | Num (I32 i) -> Int32.to_int i | v -> type_error v (NumType I32Type) -let abort _input _mod_inst vs = - empty vs ; - print_endline "Abort!" ; - exit (-1) - -let exit _input (_mod_inst : module_inst ref) vs = exit (int (single vs)) - -let lookup name t = +let abort = + Host_funcs.Host_func + (fun _input _mod_inst vs -> + empty vs ; + print_endline "Abort!" ; + exit (-1)) + +let exit = + Host_funcs.Host_func + (fun _input (_mod_inst : module_inst ref) vs -> exit (int (single vs))) + +let register_host_funcs registry = + Host_funcs.register ~global_name:"abort" abort registry ; + Host_funcs.register ~global_name:"abort" exit registry + +let lookup name = let open Lwt.Syntax in let+ name = Utf8.encode name in - match (name, t) with - | "abort", ExternFuncType t -> ExternFunc (Func.alloc_host t abort) - | "exit", ExternFuncType t -> ExternFunc (Func.alloc_host t exit) + match name with + | "abort" -> + let global_name = "env_abort" in + ExternFunc + (Func.alloc_host + ~global_name + (FuncType (Vector.of_list [], Vector.of_list []))) + | "exit" -> + let global_name = "env_exit" in + ExternFunc + (Func.alloc_host + ~global_name + (FuncType + (Vector.of_list [Types.(NumType I32Type)], Vector.of_list []))) | _ -> raise Not_found diff --git a/src/lib_webassembly/host/spectest.ml b/src/lib_webassembly/host/spectest.ml index dd325d27f83664544061caa76543e6287c5e9303..556b18b87489a5b098a3d65220a600f294147627 100644 --- a/src/lib_webassembly/host/spectest.ml +++ b/src/lib_webassembly/host/spectest.ml @@ -26,23 +26,29 @@ let table = let memory = Memory.alloc (MemoryType {min = 1l; max = Some 2l}) -let func f t = Func.alloc_host t (f t) - let print_value v = Printf.printf "%s : %s\n" (Values.string_of_value v) (Types.string_of_value_type (Values.type_of_value v)) -let print (FuncType (_, out)) _m _v vs = - List.iter print_value vs ; - flush_all () ; - List.map - (fun (_, t) -> default_value t) - (Lazy_vector.LwtInt32Vector.loaded_bindings out) - |> Lwt.return +let print = + Host_funcs.Host_func + (fun _i _m vs -> + List.iter print_value vs ; + flush_all () ; + Lwt.return_nil) + +let register_host_funcs registry = + Host_funcs.register ~global_name:"spectest_print" print registry ; + Host_funcs.register ~global_name:"spectest_print_i32" print registry ; + Host_funcs.register ~global_name:"spectest_print_i64" print registry ; + Host_funcs.register ~global_name:"spectest_print_f32" print registry ; + Host_funcs.register ~global_name:"spectest_print_f64" print registry ; + Host_funcs.register ~global_name:"spectest_print_i32_f32" print registry ; + Host_funcs.register ~global_name:"spectest_print_f64_f64" print registry -let lookup name t = +let lookup name = let open Lwt.Syntax in let+ name = Utf8.encode name in let empty () = Lazy_vector.LwtInt32Vector.create 0l in @@ -50,34 +56,50 @@ let lookup name t = let two i j = Lazy_vector.LwtInt32Vector.(create 2l |> set 0l i |> set 1l j) in - match (name, t) with - | "print", _ -> ExternFunc (func print (FuncType (empty (), empty ()))) - | "print_i32", _ -> - ExternFunc (func print (FuncType (singleton (NumType I32Type), empty ()))) - | "print_i64", _ -> - ExternFunc (func print (FuncType (singleton (NumType I64Type), empty ()))) - | "print_f32", _ -> - ExternFunc (func print (FuncType (singleton (NumType F32Type), empty ()))) - | "print_f64", _ -> - ExternFunc (func print (FuncType (singleton (NumType F64Type), empty ()))) - | "print_i32_f32", _ -> + match name with + | "print" -> + ExternFunc + (Func.alloc_host + ~global_name:"spectest_print" + (FuncType (empty (), empty ()))) + | "print_i32" -> + ExternFunc + (Func.alloc_host + ~global_name:"spectest_print_i32" + (FuncType (singleton (NumType I32Type), empty ()))) + | "print_i64" -> + ExternFunc + (Func.alloc_host + ~global_name:"spectest_print_i64" + (FuncType (singleton (NumType I64Type), empty ()))) + | "print_f32" -> + ExternFunc + (Func.alloc_host + ~global_name:"spectest_print_f32" + (FuncType (singleton (NumType F32Type), empty ()))) + | "print_f64" -> + ExternFunc + (Func.alloc_host + ~global_name:"spectest_print_f64" + (FuncType (singleton (NumType F64Type), empty ()))) + | "print_i32_f32" -> ExternFunc - (func - print + (Func.alloc_host + ~global_name:"spectest_print_i32_f32" (FuncType (two (NumType I32Type) (NumType F32Type), empty ()))) - | "print_f64_f64", _ -> + | "print_f64_f64" -> ExternFunc - (func - print + (Func.alloc_host + ~global_name:"spectest_print_f64_f64" (FuncType (two (NumType F64Type) (NumType F64Type), empty ()))) - | "global_i32", _ -> + | "global_i32" -> ExternGlobal (global (GlobalType (NumType I32Type, Immutable))) - | "global_i64", _ -> + | "global_i64" -> ExternGlobal (global (GlobalType (NumType I64Type, Immutable))) - | "global_f32", _ -> + | "global_f32" -> ExternGlobal (global (GlobalType (NumType F32Type, Immutable))) - | "global_f64", _ -> + | "global_f64" -> ExternGlobal (global (GlobalType (NumType F64Type, Immutable))) - | "table", _ -> ExternTable table - | "memory", _ -> ExternMemory memory + | "table" -> ExternTable table + | "memory" -> ExternMemory memory | _ -> raise Not_found diff --git a/src/lib_webassembly/runtime/func.ml b/src/lib_webassembly/runtime/func.ml index 1ca262c8f16c15c1d5159e6c7f5a2da69bd792f6..775926d9fe8d6716f68a03ba77e451517e8e67f1 100644 --- a/src/lib_webassembly/runtime/func.ml +++ b/src/lib_webassembly/runtime/func.ml @@ -1,14 +1,13 @@ open Types -open Values -type ('input, 'inst) t = ('input, 'inst) func +type 'inst t = 'inst func -and ('input, 'inst) func = +and 'inst func = | AstFunc of func_type * 'inst * Ast.func - | HostFunc of func_type * ('input -> 'inst -> value list -> value list Lwt.t) + | HostFunc of func_type * string let alloc ft inst f = AstFunc (ft, inst, f) -let alloc_host ft f = HostFunc (ft, f) +let alloc_host ~global_name ft = HostFunc (ft, global_name) let type_of = function AstFunc (ft, _, _) -> ft | HostFunc (ft, _) -> ft diff --git a/src/lib_webassembly/runtime/func.mli b/src/lib_webassembly/runtime/func.mli index 3aa013d7f4f41aed02b3628bd6a514ec6efdef75..17eaf691cd5dcc8d38b1eb25b2b45d6aa1658884 100644 --- a/src/lib_webassembly/runtime/func.mli +++ b/src/lib_webassembly/runtime/func.mli @@ -1,17 +1,13 @@ open Types -open Values -type ('input, 'inst) t = ('input, 'inst) func +type 'inst t = 'inst func -and ('input, 'inst) func = +and 'inst func = | AstFunc of func_type * 'inst * Ast.func - | HostFunc of func_type * ('input -> 'inst -> value list -> value list Lwt.t) + | HostFunc of func_type * string -val alloc : func_type -> 'inst -> Ast.func -> ('input, 'inst) func +val alloc : func_type -> 'inst -> Ast.func -> 'inst func -val alloc_host : - func_type -> - ('input -> 'inst -> value list -> value list Lwt.t) -> - ('input, 'inst) func +val alloc_host : global_name:string -> func_type -> 'inst func -val type_of : ('input, 'inst) func -> func_type +val type_of : 'inst func -> func_type diff --git a/src/lib_webassembly/runtime/host_funcs.ml b/src/lib_webassembly/runtime/host_funcs.ml new file mode 100644 index 0000000000000000000000000000000000000000..e0e016cc21d8036eb532ada50b57efd56e64cff3 --- /dev/null +++ b/src/lib_webassembly/runtime/host_funcs.ml @@ -0,0 +1,18 @@ +type host_func = + | Host_func of + (Input_buffer.t -> + Instance.module_inst ref -> + Values.value list -> + Values.value list Lwt.t) +[@@ocaml.unboxed] + +module Registry = Map.Make (String) + +type registry = host_func Registry.t ref + +let empty () = ref Registry.empty + +let register ~global_name implem registry = + registry := Registry.add global_name implem !registry + +let lookup ~global_name registry = Registry.find global_name !registry diff --git a/src/lib_webassembly/runtime/host_funcs.mli b/src/lib_webassembly/runtime/host_funcs.mli new file mode 100644 index 0000000000000000000000000000000000000000..34e1cb30badb13f78cf8843baa51dd89db46f399 --- /dev/null +++ b/src/lib_webassembly/runtime/host_funcs.mli @@ -0,0 +1,23 @@ +(** The type of a Host function implementation *) +type host_func = + | Host_func of + (Input_buffer.t -> + Instance.module_inst ref -> + Values.value list -> + Values.value list Lwt.t) +[@@ocaml.unboxed] + +(** A (mutable) host function registry *) +type registry + +(** [empty ()] creates a new empty registry *) +val empty : unit -> registry + +(** [register ~func_name implem] registers the implementation of a + named host function in the global symbol table. Will erase a + previous implementation for the given name. *) +val register : global_name:string -> host_func -> registry -> unit + +(** [lookup ~func_name] looks for the implementation of a named host + function in the global symbol table. May raise [Not_found].*) +val lookup : global_name:string -> registry -> host_func diff --git a/src/lib_webassembly/runtime/instance.ml b/src/lib_webassembly/runtime/instance.ml index f0d6ca2b551cf9c054fd941136b462e6c38cda02..56e0a66045dff1bef4886a1035730ae00b3e5314 100644 --- a/src/lib_webassembly/runtime/instance.ml +++ b/src/lib_webassembly/runtime/instance.ml @@ -24,7 +24,7 @@ type module_inst = { blocks : Ast.block_table; } -and func_inst = (input_inst, module_inst ref) Func.t +and func_inst = module_inst ref Func.t and table_inst = Table.t diff --git a/src/lib_webassembly/script/import.ml b/src/lib_webassembly/script/import.ml index 213a47d41b146be96da775f5c181ec040d8f07e4..82b4724015054814bc6f2c29e133238b7d54db85 100644 --- a/src/lib_webassembly/script/import.ml +++ b/src/lib_webassembly/script/import.ml @@ -18,10 +18,10 @@ let registry = ref Registry.empty let from_ast_name name = Lazy_vector.LwtInt32Vector.to_list name -let register name lookup = +let register ~module_name lookup = let open Lwt.Syntax in let lookup name = lookup (Lazy_vector.LwtInt32Vector.of_list name) in - let* name = from_ast_name name in + let* name = from_ast_name module_name in registry := Registry.add name lookup !registry ; Lwt.return_unit @@ -30,9 +30,8 @@ let lookup (m : module_) (im : import) : Instance.extern Lwt.t = let {module_name; item_name; idesc} = im.it in let* module_name_l = from_ast_name module_name in let* item_name_l = from_ast_name item_name in - let* t = import_type m im in Lwt.catch - (fun () -> Registry.find module_name_l !registry item_name_l t) + (fun () -> Registry.find module_name_l !registry item_name_l) (function | Not_found -> Unknown.error diff --git a/src/lib_webassembly/script/import.mli b/src/lib_webassembly/script/import.mli index 221491fa696a0380a354e37682d67e4994d8d84e..11fbe73235aa66e3c7ae933ec19c3adad7e64dc8 100644 --- a/src/lib_webassembly/script/import.mli +++ b/src/lib_webassembly/script/import.mli @@ -3,8 +3,6 @@ exception Unknown of Source.region * string val link : Ast.module_ -> Instance.extern list Lwt.t (* raises Unknown *) val register : - Ast.name -> - (Ast.name -> - Types.extern_type -> - Instance.extern Lwt.t (* raises Not_found *)) -> + module_name:Ast.name -> + (Ast.name -> Instance.extern Lwt.t (* raises Not_found *)) -> unit Lwt.t