@@ -180,12 +180,13 @@ module Wasm_binary = struct
180180
181181 let reftype ch = reftype' (input_byte ch) ch
182182
183- let valtype ch =
184- let i = read_uint ch in
183+ let valtype' i ch =
185184 match i with
186- | 0x7b | 0x7c | 0x7d | 0x7e | 0x7f -> ()
185+ | 0x7B | 0x7C | 0x7D | 0x7E | 0x7F -> ()
187186 | _ -> reftype' i ch
188187
188+ let valtype ch = valtype' (read_uint ch) ch
189+
189190 let limits ch =
190191 match input_byte ch with
191192 | 0 -> ignore (read_uint ch)
@@ -200,32 +201,95 @@ module Wasm_binary = struct
200201 reftype ch;
201202 limits ch
202203
204+ type comptype =
205+ | Func of { arity : int }
206+ | Struct
207+ | Array
208+
209+ let supertype ch =
210+ match input_byte ch with
211+ | 0 -> ()
212+ | 1 -> ignore (read_uint ch)
213+ | _ -> assert false
214+
215+ let storagetype ch =
216+ let i = read_uint ch in
217+ match i with
218+ | 0x78 | 0x77 -> ()
219+ | _ -> valtype' i ch
220+
221+ let fieldtype ch =
222+ storagetype ch;
223+ ignore (input_byte ch)
224+
225+ let comptype i ch =
226+ match i with
227+ | 0x5E ->
228+ fieldtype ch;
229+ Array
230+ | 0x5F ->
231+ ignore (vec fieldtype ch);
232+ Struct
233+ | 0x60 ->
234+ let params = vec valtype ch in
235+ let _ = vec valtype ch in
236+ Func { arity = List. length params }
237+ | c -> failwith (Printf. sprintf " Unknown comptype %d" c)
238+
239+ let subtype i ch =
240+ match i with
241+ | 0x50 ->
242+ supertype ch;
243+ comptype (input_byte ch) ch
244+ | 0x4F ->
245+ supertype ch;
246+ comptype (input_byte ch) ch
247+ | _ -> comptype i ch
248+
249+ let rectype ch =
250+ match input_byte ch with
251+ | 0x4E -> vec (fun ch -> subtype (input_byte ch) ch) ch
252+ | i -> [ subtype i ch ]
253+
254+ type importdesc =
255+ | Func of int
256+ | Table
257+ | Mem
258+ | Global
259+ | Tag
260+
203261 type import =
204262 { module_ : string
205263 ; name : string
264+ ; desc : importdesc
206265 }
207266
208267 let import ch =
209268 let module_ = name ch in
210269 let name = name ch in
211270 let d = read_uint ch in
212- let _ =
271+ let desc =
213272 match d with
214- | 0 -> ignore (read_uint ch)
215- | 1 -> tabletype ch
216- | 2 -> memtype ch
273+ | 0 -> Func (read_uint ch)
274+ | 1 ->
275+ tabletype ch;
276+ Table
277+ | 2 ->
278+ memtype ch;
279+ Mem
217280 | 3 ->
218281 let _typ = valtype ch in
219282 let _mut = input_byte ch in
220- ()
283+ Global
221284 | 4 ->
222285 assert (read_uint ch = 0 );
223- ignore (read_uint ch)
286+ ignore (read_uint ch);
287+ Tag
224288 | _ ->
225289 Format. eprintf " Unknown import %x@." d;
226290 assert false
227291 in
228- { module_; name }
292+ { module_; name; desc }
229293
230294 let export ch =
231295 let name = name ch in
@@ -255,22 +319,27 @@ module Wasm_binary = struct
255319 type interface =
256320 { imports : import list
257321 ; exports : string list
322+ ; types : comptype array
258323 }
259324
260325 let read_interface ch =
261326 let rec find_sections i =
262327 match next_section ch with
263328 | None -> i
264329 | Some s ->
265- if s.id = 2
330+ if s.id = 1
331+ then
332+ find_sections
333+ { i with types = Array. of_list (List. flatten (vec rectype ch.ch)) }
334+ else if s.id = 2
266335 then find_sections { i with imports = vec import ch.ch }
267336 else if s.id = 7
268337 then { i with exports = vec export ch.ch }
269338 else (
270339 skip_section ch s;
271340 find_sections i)
272341 in
273- find_sections { imports = [] ; exports = [] }
342+ find_sections { imports = [] ; exports = [] ; types = [||] }
274343
275344 let append_source_map_section ~file ~url =
276345 let ch = open_out_gen [ Open_wronly ; Open_append ; Open_binary ] 0o666 file in
@@ -404,6 +473,13 @@ let generate_start_function ~to_link ~out_file =
404473 Generate. wasm_output ch ~context ;
405474 if times () then Format. eprintf " generate start: %a@." Timer. print t1
406475
476+ let generate_missing_primitives ~missing_primitives ~out_file =
477+ Filename. gen_file out_file
478+ @@ fun ch ->
479+ let context = Generate. start () in
480+ Generate. add_missing_primitives ~context missing_primitives;
481+ Generate. wasm_output ch ~context
482+
407483let output_js js =
408484 let js = Driver. simplify_js js in
409485 let js = Driver. name_variables js in
@@ -641,17 +717,20 @@ let compute_dependencies ~files_to_link ~files =
641717
642718let compute_missing_primitives (runtime_intf , intfs ) =
643719 let provided_primitives = StringSet. of_list runtime_intf.Wasm_binary. exports in
644- StringSet. elements
720+ StringMap. bindings
645721 @@ List. fold_left
646- ~f: (fun s { Wasm_binary. imports; _ } ->
722+ ~f: (fun s { Wasm_binary. imports; types; _ } ->
647723 List. fold_left
648- ~f: (fun s { Wasm_binary. module_; name; _ } ->
649- if String. equal module_ " env" && not (StringSet. mem name provided_primitives)
650- then StringSet. add name s
651- else s)
724+ ~f: (fun s { Wasm_binary. module_; name; desc } ->
725+ match module_, desc with
726+ | "env" , Func idx when not (StringSet. mem name provided_primitives) -> (
727+ match types.(idx) with
728+ | Func { arity } -> StringMap. add name arity s
729+ | _ -> s)
730+ | _ -> s)
652731 ~init: s
653732 imports)
654- ~init: StringSet . empty
733+ ~init: StringMap . empty
655734 intfs
656735
657736let load_information files =
@@ -687,6 +766,72 @@ let gen_dir dir f =
687766 remove_directory d_tmp;
688767 raise exc
689768
769+ let link_to_module ~to_link ~files_to_link ~files ~enable_source_maps :_ ~dir =
770+ let process_file ~name ~module_name file =
771+ Zip. with_open_in file
772+ @@ fun z ->
773+ let intf =
774+ let ch, pos, len, _ = Zip. get_entry z ~name in
775+ Wasm_binary. read_interface (Wasm_binary. from_channel ~name ch pos len)
776+ in
777+ ( { Wasm_link. module_name
778+ ; file
779+ ; code = Some (Zip. read_entry z ~name )
780+ ; opt_source_map = None
781+ }
782+ , intf )
783+ in
784+ let runtime_file = fst (List. hd files) in
785+ let z = Zip. open_in runtime_file in
786+ let runtime, runtime_intf =
787+ process_file ~name: " runtime.wasm" ~module_name: " env" runtime_file
788+ in
789+ let prelude =
790+ { Wasm_link. module_name = " OCaml"
791+ ; file = runtime_file
792+ ; code = Some (Zip. read_entry z ~name: " prelude.wasm" )
793+ ; opt_source_map = None
794+ }
795+ in
796+ Zip. close_in z;
797+ let lst =
798+ List. tl files
799+ |> List. filter_map ~f: (fun (file , _ ) ->
800+ if StringSet. mem file files_to_link
801+ then Some (process_file ~name: " code.wasm" ~module_name: " OCaml" file)
802+ else None )
803+ in
804+ let missing_primitives =
805+ if Config.Flag. genprim ()
806+ then compute_missing_primitives (runtime_intf, List. map ~f: snd lst)
807+ else []
808+ in
809+ Fs. with_intermediate_file (Filename. temp_file " start" " .wasm" )
810+ @@ fun start_module ->
811+ generate_start_function ~to_link ~out_file: start_module;
812+ let start =
813+ { Wasm_link. module_name = " OCaml"
814+ ; file = start_module
815+ ; code = None
816+ ; opt_source_map = None
817+ }
818+ in
819+ Fs. with_intermediate_file (Filename. temp_file " stubs" " .wasm" )
820+ @@ fun stubs_module ->
821+ generate_missing_primitives ~missing_primitives ~out_file: stubs_module;
822+ let missing_primitives =
823+ { Wasm_link. module_name = " env"
824+ ; file = stubs_module
825+ ; code = None
826+ ; opt_source_map = None
827+ }
828+ in
829+ ignore
830+ (Wasm_link. f
831+ (runtime :: prelude :: missing_primitives :: start :: List. map ~f: fst lst)
832+ ~filter_export: (fun nm -> String. equal nm " _start" || String. equal nm " memory" )
833+ ~output_file: (Filename. concat dir " code.wasm" ))
834+
690835let link ~output_file ~linkall ~enable_source_maps ~files =
691836 if times () then Format. eprintf " linking@." ;
692837 let t = Timer. make () in
@@ -777,30 +922,35 @@ let link ~output_file ~linkall ~enable_source_maps ~files =
777922 if times () then Format. eprintf " finding what to link: %a@." Timer. print t1;
778923 if times () then Format. eprintf " scan: %a@." Timer. print t;
779924 let t = Timer. make () in
780- let interfaces , wasm_dir, link_spec =
925+ let missing_primitives , wasm_dir, link_spec =
781926 let dir = Filename. chop_extension output_file ^ " .assets" in
782927 gen_dir dir
783928 @@ fun tmp_dir ->
784929 Sys. mkdir tmp_dir 0o777 ;
785- let start_module =
786- " start-"
787- ^ String. sub
788- (Digest. to_hex (Digest. string (String. concat ~sep: " /" to_link)))
789- ~pos: 0
790- ~len: 8
791- in
792- generate_start_function
793- ~to_link
794- ~out_file: (Filename. concat tmp_dir (start_module ^ " .wasm" ));
795- let module_names, interfaces =
796- link_to_directory ~files_to_link ~files ~enable_source_maps ~dir: tmp_dir
797- in
798- ( interfaces
799- , dir
800- , let to_link = compute_dependencies ~files_to_link ~files in
801- List. combine module_names (None :: None :: to_link) @ [ start_module, None ] )
930+ if not (Config.Flag. wasi () )
931+ then (
932+ let start_module =
933+ " start-"
934+ ^ String. sub
935+ (Digest. to_hex (Digest. string (String. concat ~sep: " /" to_link)))
936+ ~pos: 0
937+ ~len: 8
938+ in
939+ let module_names, interfaces =
940+ link_to_directory ~files_to_link ~files ~enable_source_maps ~dir: tmp_dir
941+ in
942+ let missing_primitives = compute_missing_primitives interfaces in
943+ generate_start_function
944+ ~to_link
945+ ~out_file: (Filename. concat tmp_dir (start_module ^ " .wasm" ));
946+ ( List. map ~f: fst missing_primitives
947+ , dir
948+ , let to_link = compute_dependencies ~files_to_link ~files in
949+ List. combine module_names (None :: None :: to_link) @ [ start_module, None ] ))
950+ else (
951+ link_to_module ~to_link ~files_to_link ~files ~enable_source_maps ~dir: tmp_dir;
952+ [] , dir, [ " code" , None ])
802953 in
803- let missing_primitives = compute_missing_primitives interfaces in
804954 if times () then Format. eprintf " copy wasm files: %a@." Timer. print t;
805955 let t1 = Timer. make () in
806956 let js_runtime =
0 commit comments