@@ -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
@@ -405,6 +474,13 @@ let generate_start_function ~to_link ~out_file =
405
474
Generate. wasm_output ch ~context ;
406
475
if times () then Format. eprintf " generate start: %a@." Timer. print t1
407
476
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
+
408
484
let output_js js =
409
485
Code.Var. reset () ;
410
486
let b = Buffer. create 1024 in
@@ -665,17 +741,20 @@ let compute_dependencies ~files_to_link ~files =
665
741
666
742
let compute_missing_primitives (runtime_intf , intfs ) =
667
743
let provided_primitives = StringSet. of_list runtime_intf.Wasm_binary. exports in
668
- StringSet. elements
744
+ StringMap. bindings
669
745
@@ List. fold_left
670
- ~f: (fun s { Wasm_binary. imports; _ } ->
746
+ ~f: (fun s { Wasm_binary. imports; types; _ } ->
671
747
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)
676
755
~init: s
677
756
imports)
678
- ~init: StringSet . empty
757
+ ~init: StringMap . empty
679
758
intfs
680
759
681
760
let load_information files =
@@ -711,6 +790,72 @@ let gen_dir dir f =
711
790
remove_directory d_tmp;
712
791
raise exc
713
792
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
+ Fs. with_intermediate_file (Filename. temp_file " start" " .wasm" )
834
+ @@ fun start_module ->
835
+ generate_start_function ~to_link ~out_file: start_module;
836
+ let start =
837
+ { Wasm_link. module_name = " OCaml"
838
+ ; file = start_module
839
+ ; code = None
840
+ ; opt_source_map = None
841
+ }
842
+ in
843
+ Fs. with_intermediate_file (Filename. temp_file " stubs" " .wasm" )
844
+ @@ fun stubs_module ->
845
+ generate_missing_primitives ~missing_primitives ~out_file: stubs_module;
846
+ let missing_primitives =
847
+ { Wasm_link. module_name = " env"
848
+ ; file = stubs_module
849
+ ; code = None
850
+ ; opt_source_map = None
851
+ }
852
+ in
853
+ ignore
854
+ (Wasm_link. f
855
+ (runtime :: prelude :: missing_primitives :: start :: List. map ~f: fst lst)
856
+ ~filter_export: (fun nm -> String. equal nm " _start" || String. equal nm " memory" )
857
+ ~output_file: (Filename. concat dir " code.wasm" ))
858
+
714
859
let link ~output_file ~linkall ~enable_source_maps ~files =
715
860
if times () then Format. eprintf " linking@." ;
716
861
let t = Timer. make () in
@@ -801,30 +946,35 @@ let link ~output_file ~linkall ~enable_source_maps ~files =
801
946
if times () then Format. eprintf " finding what to link: %a@." Timer. print t1;
802
947
if times () then Format. eprintf " scan: %a@." Timer. print t;
803
948
let t = Timer. make () in
804
- let interfaces , wasm_dir, link_spec =
949
+ let missing_primitives , wasm_dir, link_spec =
805
950
let dir = Filename. chop_extension output_file ^ " .assets" in
806
951
gen_dir dir
807
952
@@ fun tmp_dir ->
808
953
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 ] )
954
+ if not (Config.Flag. wasi () )
955
+ then (
956
+ let start_module =
957
+ " start-"
958
+ ^ String. sub
959
+ (Digest. to_hex (Digest. string (String. concat ~sep: " /" to_link)))
960
+ ~pos: 0
961
+ ~len: 8
962
+ in
963
+ let module_names, interfaces =
964
+ link_to_directory ~files_to_link ~files ~enable_source_maps ~dir: tmp_dir
965
+ in
966
+ let missing_primitives = compute_missing_primitives interfaces in
967
+ generate_start_function
968
+ ~to_link
969
+ ~out_file: (Filename. concat tmp_dir (start_module ^ " .wasm" ));
970
+ ( List. map ~f: fst missing_primitives
971
+ , dir
972
+ , let to_link = compute_dependencies ~files_to_link ~files in
973
+ List. combine module_names (None :: None :: to_link) @ [ start_module, None ] ))
974
+ else (
975
+ link_to_module ~to_link ~files_to_link ~files ~enable_source_maps ~dir: tmp_dir;
976
+ [] , dir, [ " code" , None ])
826
977
in
827
- let missing_primitives = compute_missing_primitives interfaces in
828
978
if times () then Format. eprintf " copy wasm files: %a@." Timer. print t;
829
979
let t1 = Timer. make () in
830
980
let js_runtime =
0 commit comments