@@ -181,12 +181,13 @@ module Wasm_binary = struct
181181
182182 let reftype ch = reftype' (input_byte ch) ch
183183
184- let valtype ch =
185- let i = read_uint ch in
184+ let valtype' i ch =
186185 match i with
187- | 0x7b | 0x7c | 0x7d | 0x7e | 0x7f -> ()
186+ | 0x7B | 0x7C | 0x7D | 0x7E | 0x7F -> ()
188187 | _ -> reftype' i ch
189188
189+ let valtype ch = valtype' (read_uint ch) ch
190+
190191 let limits ch =
191192 match input_byte ch with
192193 | 0 -> ignore (read_uint ch)
@@ -201,32 +202,95 @@ module Wasm_binary = struct
201202 reftype ch;
202203 limits ch
203204
205+ type comptype =
206+ | Func of { arity : int }
207+ | Struct
208+ | Array
209+
210+ let supertype ch =
211+ match input_byte ch with
212+ | 0 -> ()
213+ | 1 -> ignore (read_uint ch)
214+ | _ -> assert false
215+
216+ let storagetype ch =
217+ let i = read_uint ch in
218+ match i with
219+ | 0x78 | 0x77 -> ()
220+ | _ -> valtype' i ch
221+
222+ let fieldtype ch =
223+ storagetype ch;
224+ ignore (input_byte ch)
225+
226+ let comptype i ch =
227+ match i with
228+ | 0x5E ->
229+ fieldtype ch;
230+ Array
231+ | 0x5F ->
232+ ignore (vec fieldtype ch);
233+ Struct
234+ | 0x60 ->
235+ let params = vec valtype ch in
236+ let _ = vec valtype ch in
237+ Func { arity = List. length params }
238+ | c -> failwith (Printf. sprintf " Unknown comptype %d" c)
239+
240+ let subtype i ch =
241+ match i with
242+ | 0x50 ->
243+ supertype ch;
244+ comptype (input_byte ch) ch
245+ | 0x4F ->
246+ supertype ch;
247+ comptype (input_byte ch) ch
248+ | _ -> comptype i ch
249+
250+ let rectype ch =
251+ match input_byte ch with
252+ | 0x4E -> vec (fun ch -> subtype (input_byte ch) ch) ch
253+ | i -> [ subtype i ch ]
254+
255+ type importdesc =
256+ | Func of int
257+ | Table
258+ | Mem
259+ | Global
260+ | Tag
261+
204262 type import =
205263 { module_ : string
206264 ; name : string
265+ ; desc : importdesc
207266 }
208267
209268 let import ch =
210269 let module_ = name ch in
211270 let name = name ch in
212271 let d = read_uint ch in
213- let _ =
272+ let desc =
214273 match d with
215- | 0 -> ignore (read_uint ch)
216- | 1 -> tabletype ch
217- | 2 -> memtype ch
274+ | 0 -> Func (read_uint ch)
275+ | 1 ->
276+ tabletype ch;
277+ Table
278+ | 2 ->
279+ memtype ch;
280+ Mem
218281 | 3 ->
219282 let _typ = valtype ch in
220283 let _mut = input_byte ch in
221- ()
284+ Global
222285 | 4 ->
223286 assert (read_uint ch = 0 );
224- ignore (read_uint ch)
287+ ignore (read_uint ch);
288+ Tag
225289 | _ ->
226290 Format. eprintf " Unknown import %x@." d;
227291 assert false
228292 in
229- { module_; name }
293+ { module_; name; desc }
230294
231295 let export ch =
232296 let name = name ch in
@@ -256,22 +320,27 @@ module Wasm_binary = struct
256320 type interface =
257321 { imports : import list
258322 ; exports : string list
323+ ; types : comptype array
259324 }
260325
261326 let read_interface ch =
262327 let rec find_sections i =
263328 match next_section ch with
264329 | None -> i
265330 | Some s ->
266- if s.id = 2
331+ if s.id = 1
332+ then
333+ find_sections
334+ { i with types = Array. of_list (List. flatten (vec rectype ch.ch)) }
335+ else if s.id = 2
267336 then find_sections { i with imports = vec import ch.ch }
268337 else if s.id = 7
269338 then { i with exports = vec export ch.ch }
270339 else (
271340 skip_section ch s;
272341 find_sections i)
273342 in
274- find_sections { imports = [] ; exports = [] }
343+ find_sections { imports = [] ; exports = [] ; types = [||] }
275344
276345 let append_source_map_section ~file ~url =
277346 let ch = open_out_gen [ Open_wronly ; Open_append ; Open_binary ] 0o666 file in
@@ -405,6 +474,13 @@ let generate_start_function ~to_link ~out_file =
405474 Generate. wasm_output ch ~context ;
406475 if times () then Format. eprintf " generate start: %a@." Timer. print t1
407476
477+ let generate_missing_primitives ~missing_primitives ~out_file =
478+ Filename. gen_file out_file
479+ @@ fun ch ->
480+ let context = Generate. start () in
481+ Generate. add_missing_primitives ~context missing_primitives;
482+ Generate. wasm_output ch ~context
483+
408484let output_js js =
409485 Code.Var. reset () ;
410486 let b = Buffer. create 1024 in
@@ -665,17 +741,20 @@ let compute_dependencies ~files_to_link ~files =
665741
666742let compute_missing_primitives (runtime_intf , intfs ) =
667743 let provided_primitives = StringSet. of_list runtime_intf.Wasm_binary. exports in
668- StringSet. elements
744+ StringMap. bindings
669745 @@ List. fold_left
670- ~f: (fun s { Wasm_binary. imports; _ } ->
746+ ~f: (fun s { Wasm_binary. imports; types; _ } ->
671747 List. fold_left
672- ~f: (fun s { Wasm_binary. module_; name; _ } ->
673- if String. equal module_ " env" && not (StringSet. mem name provided_primitives)
674- then StringSet. add name s
675- else s)
748+ ~f: (fun s { Wasm_binary. module_; name; desc } ->
749+ match module_, desc with
750+ | "env" , Func idx when not (StringSet. mem name provided_primitives) -> (
751+ match types.(idx) with
752+ | Func { arity } -> StringMap. add name arity s
753+ | _ -> s)
754+ | _ -> s)
676755 ~init: s
677756 imports)
678- ~init: StringSet . empty
757+ ~init: StringMap . empty
679758 intfs
680759
681760let load_information files =
@@ -711,6 +790,69 @@ let gen_dir dir f =
711790 remove_directory d_tmp;
712791 raise exc
713792
793+ let link_to_module ~to_link ~files_to_link ~files ~enable_source_maps :_ ~dir =
794+ let process_file ~name ~module_name file =
795+ Zip. with_open_in file
796+ @@ fun z ->
797+ let intf =
798+ let ch, pos, len, _ = Zip. get_entry z ~name in
799+ Wasm_binary. read_interface (Wasm_binary. from_channel ~name ch pos len)
800+ in
801+ ( { Wasm_link. module_name
802+ ; file
803+ ; code = Some (Zip. read_entry z ~name )
804+ ; opt_source_map = None
805+ }
806+ , intf )
807+ in
808+ let runtime_file = fst (List. hd files) in
809+ let z = Zip. open_in runtime_file in
810+ let runtime, runtime_intf =
811+ process_file ~name: " runtime.wasm" ~module_name: " env" runtime_file
812+ in
813+ let prelude =
814+ { Wasm_link. module_name = " OCaml"
815+ ; file = runtime_file
816+ ; code = Some (Zip. read_entry z ~name: " prelude.wasm" )
817+ ; opt_source_map = None
818+ }
819+ in
820+ Zip. close_in z;
821+ let lst =
822+ List. tl files
823+ |> List. filter_map ~f: (fun (file , _ ) ->
824+ if StringSet. mem file files_to_link
825+ then Some (process_file ~name: " code.wasm" ~module_name: " OCaml" file)
826+ else None )
827+ in
828+ let missing_primitives =
829+ if Config.Flag. genprim ()
830+ then compute_missing_primitives (runtime_intf, List. map ~f: snd lst)
831+ else []
832+ in
833+ let start_module = Filename. concat dir " start.wasm" in
834+ generate_start_function ~to_link ~out_file: start_module;
835+ let start =
836+ { Wasm_link. module_name = " OCaml"
837+ ; file = start_module
838+ ; code = None
839+ ; opt_source_map = None
840+ }
841+ in
842+ generate_missing_primitives ~missing_primitives ~out_file: " stubs.wasm" ;
843+ let missing_primitives =
844+ { Wasm_link. module_name = " env"
845+ ; file = " stubs.wasm"
846+ ; code = None
847+ ; opt_source_map = None
848+ }
849+ in
850+ ignore
851+ (Wasm_link. f
852+ (runtime :: prelude :: missing_primitives :: start :: List. map ~f: fst lst)
853+ ~filter_export: (fun nm -> String. equal nm " _start" || String. equal nm " memory" )
854+ ~output_file: (Filename. concat dir " code.wasm" ))
855+
714856let link ~output_file ~linkall ~enable_source_maps ~files =
715857 if times () then Format. eprintf " linking@." ;
716858 let t = Timer. make () in
@@ -801,30 +943,35 @@ let link ~output_file ~linkall ~enable_source_maps ~files =
801943 if times () then Format. eprintf " finding what to link: %a@." Timer. print t1;
802944 if times () then Format. eprintf " scan: %a@." Timer. print t;
803945 let t = Timer. make () in
804- let interfaces , wasm_dir, link_spec =
946+ let missing_primitives , wasm_dir, link_spec =
805947 let dir = Filename. chop_extension output_file ^ " .assets" in
806948 gen_dir dir
807949 @@ fun tmp_dir ->
808950 Sys. mkdir tmp_dir 0o777 ;
809- let start_module =
810- " start-"
811- ^ String. sub
812- (Digest. to_hex (Digest. string (String. concat ~sep: " /" to_link)))
813- ~pos: 0
814- ~len: 8
815- in
816- generate_start_function
817- ~to_link
818- ~out_file: (Filename. concat tmp_dir (start_module ^ " .wasm" ));
819- let module_names, interfaces =
820- link_to_directory ~files_to_link ~files ~enable_source_maps ~dir: tmp_dir
821- in
822- ( interfaces
823- , dir
824- , let to_link = compute_dependencies ~files_to_link ~files in
825- List. combine module_names (None :: None :: to_link) @ [ start_module, None ] )
951+ if not (Config.Flag. wasi () )
952+ then (
953+ let start_module =
954+ " start-"
955+ ^ String. sub
956+ (Digest. to_hex (Digest. string (String. concat ~sep: " /" to_link)))
957+ ~pos: 0
958+ ~len: 8
959+ in
960+ let module_names, interfaces =
961+ link_to_directory ~files_to_link ~files ~enable_source_maps ~dir: tmp_dir
962+ in
963+ let missing_primitives = compute_missing_primitives interfaces in
964+ generate_start_function
965+ ~to_link
966+ ~out_file: (Filename. concat tmp_dir (start_module ^ " .wasm" ));
967+ ( List. map ~f: fst missing_primitives
968+ , dir
969+ , let to_link = compute_dependencies ~files_to_link ~files in
970+ List. combine module_names (None :: None :: to_link) @ [ start_module, None ] ))
971+ else (
972+ link_to_module ~to_link ~files_to_link ~files ~enable_source_maps ~dir: tmp_dir;
973+ [] , dir, [ " code" , None ])
826974 in
827- let missing_primitives = compute_missing_primitives interfaces in
828975 if times () then Format. eprintf " copy wasm files: %a@." Timer. print t;
829976 let t1 = Timer. make () in
830977 let js_runtime =
0 commit comments