@@ -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
@@ -397,6 +466,13 @@ let generate_start_function ~to_link ~out_file =
397466 Generate. wasm_output ch ~opt_source_map_file: None ~context ;
398467 if times () then Format. eprintf " generate start: %a@." Timer. print t1
399468
469+ let generate_missing_primitives ~missing_primitives ~out_file =
470+ Filename. gen_file out_file
471+ @@ fun ch ->
472+ let context = Generate. start () in
473+ Generate. add_missing_primitives ~context missing_primitives;
474+ Generate. wasm_output ch ~opt_source_map_file: None ~context
475+
400476let output_js js =
401477 let js = Driver. simplify_js js in
402478 let js = Driver. name_variables js in
@@ -630,17 +706,20 @@ let compute_dependencies ~files_to_link ~files =
630706
631707let compute_missing_primitives (runtime_intf , intfs ) =
632708 let provided_primitives = StringSet. of_list runtime_intf.Wasm_binary. exports in
633- StringSet. elements
709+ StringMap. bindings
634710 @@ List. fold_left
635- ~f: (fun s { Wasm_binary. imports; _ } ->
711+ ~f: (fun s { Wasm_binary. imports; types; _ } ->
636712 List. fold_left
637- ~f: (fun s { Wasm_binary. module_; name; _ } ->
638- if String. equal module_ " env" && not (StringSet. mem name provided_primitives)
639- then StringSet. add name s
640- else s)
713+ ~f: (fun s { Wasm_binary. module_; name; desc } ->
714+ match module_, desc with
715+ | "env" , Func idx when not (StringSet. mem name provided_primitives) -> (
716+ match types.(idx) with
717+ | Func { arity } -> StringMap. add name arity s
718+ | _ -> s)
719+ | _ -> s)
641720 ~init: s
642721 imports)
643- ~init: StringSet . empty
722+ ~init: StringMap . empty
644723 intfs
645724
646725let load_information files =
@@ -676,6 +755,72 @@ let gen_dir dir f =
676755 remove_directory d_tmp;
677756 raise exc
678757
758+ let link_to_module ~to_link ~files_to_link ~files ~enable_source_maps :_ ~dir =
759+ let process_file ~name ~module_name file =
760+ Zip. with_open_in file
761+ @@ fun z ->
762+ let intf =
763+ let ch, pos, len, _ = Zip. get_entry z ~name in
764+ Wasm_binary. read_interface (Wasm_binary. from_channel ~name ch pos len)
765+ in
766+ ( { Wasm_link. module_name
767+ ; file
768+ ; code = Some (Zip. read_entry z ~name )
769+ ; opt_source_map = None
770+ }
771+ , intf )
772+ in
773+ let runtime_file = fst (List. hd files) in
774+ let z = Zip. open_in runtime_file in
775+ let runtime, runtime_intf =
776+ process_file ~name: " runtime.wasm" ~module_name: " env" runtime_file
777+ in
778+ let prelude =
779+ { Wasm_link. module_name = " OCaml"
780+ ; file = runtime_file
781+ ; code = Some (Zip. read_entry z ~name: " prelude.wasm" )
782+ ; opt_source_map = None
783+ }
784+ in
785+ Zip. close_in z;
786+ let lst =
787+ List. tl files
788+ |> List. filter_map ~f: (fun (file , _ ) ->
789+ if StringSet. mem file files_to_link
790+ then Some (process_file ~name: " code.wasm" ~module_name: " OCaml" file)
791+ else None )
792+ in
793+ let missing_primitives =
794+ if Config.Flag. genprim ()
795+ then compute_missing_primitives (runtime_intf, List. map ~f: snd lst)
796+ else []
797+ in
798+ Fs. with_intermediate_file (Filename. temp_file " start" " .wasm" )
799+ @@ fun start_module ->
800+ generate_start_function ~to_link ~out_file: start_module;
801+ let start =
802+ { Wasm_link. module_name = " OCaml"
803+ ; file = start_module
804+ ; code = None
805+ ; opt_source_map = None
806+ }
807+ in
808+ Fs. with_intermediate_file (Filename. temp_file " stubs" " .wasm" )
809+ @@ fun stubs_module ->
810+ generate_missing_primitives ~missing_primitives ~out_file: stubs_module;
811+ let missing_primitives =
812+ { Wasm_link. module_name = " env"
813+ ; file = stubs_module
814+ ; code = None
815+ ; opt_source_map = None
816+ }
817+ in
818+ ignore
819+ (Wasm_link. f
820+ (runtime :: prelude :: missing_primitives :: start :: List. map ~f: fst lst)
821+ ~filter_export: (fun nm -> String. equal nm " _start" || String. equal nm " memory" )
822+ ~output_file: (Filename. concat dir " code.wasm" ))
823+
679824let link ~output_file ~linkall ~enable_source_maps ~files =
680825 if times () then Format. eprintf " linking@." ;
681826 let t = Timer. make () in
@@ -766,30 +911,35 @@ let link ~output_file ~linkall ~enable_source_maps ~files =
766911 if times () then Format. eprintf " finding what to link: %a@." Timer. print t1;
767912 if times () then Format. eprintf " scan: %a@." Timer. print t;
768913 let t = Timer. make () in
769- let interfaces , wasm_dir, link_spec =
914+ let missing_primitives , wasm_dir, link_spec =
770915 let dir = Filename. chop_extension output_file ^ " .assets" in
771916 gen_dir dir
772917 @@ fun tmp_dir ->
773918 Sys. mkdir tmp_dir 0o777 ;
774- let start_module =
775- " start-"
776- ^ String. sub
777- (Digest. to_hex (Digest. string (String. concat ~sep: " /" to_link)))
778- ~pos: 0
779- ~len: 8
780- in
781- generate_start_function
782- ~to_link
783- ~out_file: (Filename. concat tmp_dir (start_module ^ " .wasm" ));
784- let module_names, interfaces =
785- link_to_directory ~files_to_link ~files ~enable_source_maps ~dir: tmp_dir
786- in
787- ( interfaces
788- , dir
789- , let to_link = compute_dependencies ~files_to_link ~files in
790- List. combine module_names (None :: None :: to_link) @ [ start_module, None ] )
919+ if not (Config.Flag. wasi () )
920+ then (
921+ let start_module =
922+ " start-"
923+ ^ String. sub
924+ (Digest. to_hex (Digest. string (String. concat ~sep: " /" to_link)))
925+ ~pos: 0
926+ ~len: 8
927+ in
928+ let module_names, interfaces =
929+ link_to_directory ~files_to_link ~files ~enable_source_maps ~dir: tmp_dir
930+ in
931+ let missing_primitives = compute_missing_primitives interfaces in
932+ generate_start_function
933+ ~to_link
934+ ~out_file: (Filename. concat tmp_dir (start_module ^ " .wasm" ));
935+ ( List. map ~f: fst missing_primitives
936+ , dir
937+ , let to_link = compute_dependencies ~files_to_link ~files in
938+ List. combine module_names (None :: None :: to_link) @ [ start_module, None ] ))
939+ else (
940+ link_to_module ~to_link ~files_to_link ~files ~enable_source_maps ~dir: tmp_dir;
941+ [] , dir, [ " code" , None ])
791942 in
792- let missing_primitives = compute_missing_primitives interfaces in
793943 if times () then Format. eprintf " copy wasm files: %a@." Timer. print t;
794944 let t1 = Timer. make () in
795945 let js_runtime =
0 commit comments