@@ -180,12 +180,13 @@ module Wasm_binary = struct
180
180
181
181
let reftype ch = reftype' (input_byte ch) ch
182
182
183
- let valtype ch =
184
- let i = read_uint ch in
183
+ let valtype' i ch =
185
184
match i with
186
- | 0x7b | 0x7c | 0x7d | 0x7e | 0x7f -> ()
185
+ | 0x7B | 0x7C | 0x7D | 0x7E | 0x7F -> ()
187
186
| _ -> reftype' i ch
188
187
188
+ let valtype ch = valtype' (read_uint ch) ch
189
+
189
190
let limits ch =
190
191
match input_byte ch with
191
192
| 0 -> ignore (read_uint ch)
@@ -200,32 +201,95 @@ module Wasm_binary = struct
200
201
reftype ch;
201
202
limits ch
202
203
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
+
203
261
type import =
204
262
{ module_ : string
205
263
; name : string
264
+ ; desc : importdesc
206
265
}
207
266
208
267
let import ch =
209
268
let module_ = name ch in
210
269
let name = name ch in
211
270
let d = read_uint ch in
212
- let _ =
271
+ let desc =
213
272
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
217
280
| 3 ->
218
281
let _typ = valtype ch in
219
282
let _mut = input_byte ch in
220
- ()
283
+ Global
221
284
| 4 ->
222
285
assert (read_uint ch = 0 );
223
- ignore (read_uint ch)
286
+ ignore (read_uint ch);
287
+ Tag
224
288
| _ ->
225
289
Format. eprintf " Unknown import %x@." d;
226
290
assert false
227
291
in
228
- { module_; name }
292
+ { module_; name; desc }
229
293
230
294
let export ch =
231
295
let name = name ch in
@@ -255,22 +319,27 @@ module Wasm_binary = struct
255
319
type interface =
256
320
{ imports : import list
257
321
; exports : string list
322
+ ; types : comptype array
258
323
}
259
324
260
325
let read_interface ch =
261
326
let rec find_sections i =
262
327
match next_section ch with
263
328
| None -> i
264
329
| 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
266
335
then find_sections { i with imports = vec import ch.ch }
267
336
else if s.id = 7
268
337
then { i with exports = vec export ch.ch }
269
338
else (
270
339
skip_section ch s;
271
340
find_sections i)
272
341
in
273
- find_sections { imports = [] ; exports = [] }
342
+ find_sections { imports = [] ; exports = [] ; types = [||] }
274
343
275
344
let append_source_map_section ~file ~url =
276
345
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 =
404
473
Generate. wasm_output ch ~context ;
405
474
if times () then Format. eprintf " generate start: %a@." Timer. print t1
406
475
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
+
407
483
let output_js js =
408
484
let js = Driver. simplify_js js in
409
485
let js = Driver. name_variables js in
@@ -641,17 +717,20 @@ let compute_dependencies ~files_to_link ~files =
641
717
642
718
let compute_missing_primitives (runtime_intf , intfs ) =
643
719
let provided_primitives = StringSet. of_list runtime_intf.Wasm_binary. exports in
644
- StringSet. elements
720
+ StringMap. bindings
645
721
@@ List. fold_left
646
- ~f: (fun s { Wasm_binary. imports; _ } ->
722
+ ~f: (fun s { Wasm_binary. imports; types; _ } ->
647
723
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)
652
731
~init: s
653
732
imports)
654
- ~init: StringSet . empty
733
+ ~init: StringMap . empty
655
734
intfs
656
735
657
736
let load_information files =
@@ -687,6 +766,72 @@ let gen_dir dir f =
687
766
remove_directory d_tmp;
688
767
raise exc
689
768
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
+
690
835
let link ~output_file ~linkall ~enable_source_maps ~files =
691
836
if times () then Format. eprintf " linking@." ;
692
837
let t = Timer. make () in
@@ -777,30 +922,35 @@ let link ~output_file ~linkall ~enable_source_maps ~files =
777
922
if times () then Format. eprintf " finding what to link: %a@." Timer. print t1;
778
923
if times () then Format. eprintf " scan: %a@." Timer. print t;
779
924
let t = Timer. make () in
780
- let interfaces , wasm_dir, link_spec =
925
+ let missing_primitives , wasm_dir, link_spec =
781
926
let dir = Filename. chop_extension output_file ^ " .assets" in
782
927
gen_dir dir
783
928
@@ fun tmp_dir ->
784
929
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 ])
802
953
in
803
- let missing_primitives = compute_missing_primitives interfaces in
804
954
if times () then Format. eprintf " copy wasm files: %a@." Timer. print t;
805
955
let t1 = Timer. make () in
806
956
let js_runtime =
0 commit comments