@@ -181,12 +181,13 @@ module Wasm_binary = struct
181
181
182
182
let reftype ch = reftype' (input_byte ch) ch
183
183
184
- let valtype ch =
185
- let i = read_uint ch in
184
+ let valtype' i ch =
186
185
match i with
187
- | 0x7b | 0x7c | 0x7d | 0x7e | 0x7f -> ()
186
+ | 0x7B | 0x7C | 0x7D | 0x7E | 0x7F -> ()
188
187
| _ -> reftype' i ch
189
188
189
+ let valtype ch = valtype' (read_uint ch) ch
190
+
190
191
let limits ch =
191
192
match input_byte ch with
192
193
| 0 -> ignore (read_uint ch)
@@ -201,32 +202,95 @@ module Wasm_binary = struct
201
202
reftype ch;
202
203
limits ch
203
204
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
+
204
262
type import =
205
263
{ module_ : string
206
264
; name : string
265
+ ; desc : importdesc
207
266
}
208
267
209
268
let import ch =
210
269
let module_ = name ch in
211
270
let name = name ch in
212
271
let d = read_uint ch in
213
- let _ =
272
+ let desc =
214
273
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
218
281
| 3 ->
219
282
let _typ = valtype ch in
220
283
let _mut = input_byte ch in
221
- ()
284
+ Global
222
285
| 4 ->
223
286
assert (read_uint ch = 0 );
224
- ignore (read_uint ch)
287
+ ignore (read_uint ch);
288
+ Tag
225
289
| _ ->
226
290
Format. eprintf " Unknown import %x@." d;
227
291
assert false
228
292
in
229
- { module_; name }
293
+ { module_; name; desc }
230
294
231
295
let export ch =
232
296
let name = name ch in
@@ -256,22 +320,27 @@ module Wasm_binary = struct
256
320
type interface =
257
321
{ imports : import list
258
322
; exports : string list
323
+ ; types : comptype array
259
324
}
260
325
261
326
let read_interface ch =
262
327
let rec find_sections i =
263
328
match next_section ch with
264
329
| None -> i
265
330
| 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
267
336
then find_sections { i with imports = vec import ch.ch }
268
337
else if s.id = 7
269
338
then { i with exports = vec export ch.ch }
270
339
else (
271
340
skip_section ch s;
272
341
find_sections i)
273
342
in
274
- find_sections { imports = [] ; exports = [] }
343
+ find_sections { imports = [] ; exports = [] ; types = [||] }
275
344
276
345
let append_source_map_section ~file ~url =
277
346
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 =
397
466
Generate. wasm_output ch ~opt_source_map_file: None ~context ;
398
467
if times () then Format. eprintf " generate start: %a@." Timer. print t1
399
468
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
+
400
476
let output_js js =
401
477
let js = Driver. simplify_js js in
402
478
let js = Driver. name_variables js in
@@ -630,17 +706,20 @@ let compute_dependencies ~files_to_link ~files =
630
706
631
707
let compute_missing_primitives (runtime_intf , intfs ) =
632
708
let provided_primitives = StringSet. of_list runtime_intf.Wasm_binary. exports in
633
- StringSet. elements
709
+ StringMap. bindings
634
710
@@ List. fold_left
635
- ~f: (fun s { Wasm_binary. imports; _ } ->
711
+ ~f: (fun s { Wasm_binary. imports; types; _ } ->
636
712
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)
641
720
~init: s
642
721
imports)
643
- ~init: StringSet . empty
722
+ ~init: StringMap . empty
644
723
intfs
645
724
646
725
let load_information files =
@@ -676,6 +755,72 @@ let gen_dir dir f =
676
755
remove_directory d_tmp;
677
756
raise exc
678
757
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
+
679
824
let link ~output_file ~linkall ~enable_source_maps ~files =
680
825
if times () then Format. eprintf " linking@." ;
681
826
let t = Timer. make () in
@@ -766,30 +911,35 @@ let link ~output_file ~linkall ~enable_source_maps ~files =
766
911
if times () then Format. eprintf " finding what to link: %a@." Timer. print t1;
767
912
if times () then Format. eprintf " scan: %a@." Timer. print t;
768
913
let t = Timer. make () in
769
- let interfaces , wasm_dir, link_spec =
914
+ let missing_primitives , wasm_dir, link_spec =
770
915
let dir = Filename. chop_extension output_file ^ " .assets" in
771
916
gen_dir dir
772
917
@@ fun tmp_dir ->
773
918
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 ])
791
942
in
792
- let missing_primitives = compute_missing_primitives interfaces in
793
943
if times () then Format. eprintf " copy wasm files: %a@." Timer. print t;
794
944
let t1 = Timer. make () in
795
945
let js_runtime =
0 commit comments