From f8102ca7144c584a661f546a3e3248055ad93f23 Mon Sep 17 00:00:00 2001 From: epatrizio Date: Mon, 26 Feb 2024 15:11:42 +0100 Subject: [PATCH] Add a wat2wasm subcommand --- example/README.md | 6 +- example/wasm2wat/README.md | 4 +- src/bin/owi.ml | 16 ++- src/binary_to_text/binary_encoder.ml | 152 +++++++++++++++++++++++++++ src/cmd/cmd_wat2wasm.ml | 18 ++++ src/cmd/cmd_wat2wasm.mli | 5 + src/dune | 2 + test/help/help.t | 6 +- 8 files changed, 203 insertions(+), 6 deletions(-) create mode 100644 src/binary_to_text/binary_encoder.ml create mode 100644 src/cmd/cmd_wat2wasm.ml create mode 100644 src/cmd/cmd_wat2wasm.mli diff --git a/example/README.md b/example/README.md index 60bdb95c7..1e8191a2c 100644 --- a/example/README.md +++ b/example/README.md @@ -49,9 +49,13 @@ COMMANDS Validate a module wasm2wat [OPTION]… [ARG]… - Generate a text format file (.wat) file from a binary format file + Generate a text format file (.wat) from a binary format file (.wasm) + wat2wasm [OPTION]… [ARG]… + Generate a binary format file (.wasm) from a text format file + (.wat) + COMMON OPTIONS --help[=FMT] (default=auto) Show this help in format FMT. The value FMT must be one of auto, diff --git a/example/wasm2wat/README.md b/example/wasm2wat/README.md index 3d88d2477..41f8c8a08 100644 --- a/example/wasm2wat/README.md +++ b/example/wasm2wat/README.md @@ -22,8 +22,8 @@ $ owi wasm2wat ./42.wasm ```sh $ owi wasm2wat --help=plain NAME - owi-wasm2wat - Generate a text format file (.wat) file from a binary - format file (.wasm) + owi-wasm2wat - Generate a text format file (.wat) from a binary format + file (.wasm) SYNOPSIS owi wasm2wat [OPTION]… [ARG]… diff --git a/src/bin/owi.ml b/src/bin/owi.ml index 0f92310bb..0550129d3 100644 --- a/src/bin/owi.ml +++ b/src/bin/owi.ml @@ -191,14 +191,25 @@ let wasm2wat_cmd = let open Cmdliner in let info = let doc = - "Generate a text format file (.wat) file from a binary format file \ - (.wasm)" + "Generate a text format file (.wat) from a binary format file (.wasm)" in let man = [] @ shared_man in Cmd.info "wasm2wat" ~version ~doc ~sdocs ~man in Cmd.v info Term.(const Cmd_wasm2wat.cmd $ files) +let wat2wasm_cmd = + let open Cmdliner in + let info = + let doc = + "Generate a binary format file (.wasm) from a text format file (.wat)" + in + let man = [] @ shared_man in + Cmd.info "wat2wasm" ~version ~doc ~sdocs ~man + in + Cmd.v info + Term.(const Cmd_wat2wasm.cmd $ profiling $ debug $ unsafe $ optimize $ files) + let cli = let open Cmdliner in let info = @@ -219,6 +230,7 @@ let cli = ; sym_cmd ; validate_cmd ; wasm2wat_cmd + ; wat2wasm_cmd ] let exit_code = diff --git a/src/binary_to_text/binary_encoder.ml b/src/binary_to_text/binary_encoder.ml new file mode 100644 index 000000000..d19e70111 --- /dev/null +++ b/src/binary_to_text/binary_encoder.ml @@ -0,0 +1,152 @@ +(* SPDX-License-Identifier: AGPL-3.0-or-later *) +(* Copyright © 2021-2024 OCamlPro *) +(* Written by the Owi programmers *) + +open Binary +open Syntax +open Types + +let magic = "\x00\x61\x73\x6d" + +let version = "\x01\x00\x00\x00" + +(* passer out_channel et pas passer par buffer + int -> char + let char_of_int i = Char.chr (i land 0xff) + + int64 -> string ? + TODO : U64_encode -> string ? + + Idem : val_type -> char + let valtype_encode vt = + ... +*) + +let add_int i buf = + let c = Char.chr (i land 0xff) in + Buffer.add_char buf c + +let rec write_U64 i buf = + let b = Int64.to_int (Int64.logand i 0x7fL) in + if 0L <= i && i < 128L then add_int b buf + else ( + add_int (b lor 0x80) buf; + write_U64 (Int64.shift_right_logical i 7) buf ) + +let write_U32 i = write_U64 (Int64.logand (Int64.of_int32 i) 0xffffffffL) + +let indice_encode (id : Types.binary Types.indice) buf = + let (Raw id) = id in + write_U32 (Int32.of_int id) buf + +let valtype_encode vt buf = + let c = + match vt with + | Num_type I32 -> '\x7F' + | Num_type I64 -> '\x7E' + | Num_type F32 -> '\x7D' + | Num_type F64 -> '\x7C' + | Ref_type (Null, Func_ht) -> '\x70' + | Ref_type (Null, Extern_ht) -> '\x6F' + | _ -> assert false (* vecttype v128 '\x7B' *) + in + Buffer.add_char buf c + +let mut_encode mut buf = + let c = match mut with Const -> '\x00' | Var -> '\x01' in + Buffer.add_char buf c + +(* let vector_encode len fct_encode buf = + write_U32 (Int32.of_int len) buf; + iter fct_encode buf + TODO +*) + +let section_encode id encode_func data buf = + let section_buf = Buffer.create 16 in + encode_func data section_buf; + add_int id buf; + write_U32 (Int32.of_int (Buffer.length section_buf)) buf; + Buffer.add_buffer buf section_buf + +(* type: section 1 *) +(* let type_encode func = + let { Named.values; _ } = func in + let len = List.length values in + let buf = Buffer.create 32 in + write_U32 (Int32.of_int len) buf; + List.iter + (fun v -> + Buffer.add_char buf '\x60'; + let { Types.type_f = t; _ } = Indexed.get v in + match t with + | Bt_raw _t -> (* TODO *) + write_U32 0l buf; + write_U32 0l buf + | Bt_ind _ -> assert false + ) + values; + buf *) + +(* function: section 3 *) +let function_encode func buf = + let { Named.values; _ } = func in + let len = List.length values in + write_U32 (Int32.of_int len) buf; + List.iter + (fun v -> + let i = Indexed.get_index v in + write_U32 (Int32.of_int i) buf ) + values + +(* start: section 8 *) +let start_encode int_opt buf = + match int_opt with + | None -> () + | Some funcidx -> write_U32 (Int32.of_int funcidx) buf + +let encode (modul : Binary.modul) = + let buf = Buffer.create 256 in + Buffer.add_string buf magic; + Buffer.add_string buf version; + (* section_encode 1 type_encode modul.func buf; *) + section_encode 3 function_encode modul.func buf; + section_encode 8 start_encode modul.start buf; + + (* function_encode modul.func buf; *) + (* table_encode modul.table buf; *) + (* memory_encode modul.mem buf; *) + (* global_encode modul.global buf; *) + (* export_encode modul.exports buf; *) + (* start_encode modul.start buf; *) + (* element_encode modul.elem buf; *) + (* data_encode modul.data buf; *) + Buffer.contents buf + +(* + 0 custom section + 1 type section ?? dep autres + 2 import section ?? dep autres + 3 function section + 4 table section + 5 memory section + 6 global section + 7 export section + 8 start section + 9 element section + 10 code section ?? dep autres + 11 data section + 12 data count section -- *) + +let write_file filename content = + let filename = Fpath.filename filename in + let filename = filename ^ ".wasm" in + let oc = Out_channel.open_bin filename in + Out_channel.output_string oc content; + Out_channel.close oc + +let convert (filename : Fpath.t) ~unsafe ~optimize m = + let+ m = Compile.Text.until_optimize ~unsafe ~optimize m in + let content = encode m in + let () = write_file filename content in + () diff --git a/src/cmd/cmd_wat2wasm.ml b/src/cmd/cmd_wat2wasm.ml new file mode 100644 index 000000000..4192eaeb4 --- /dev/null +++ b/src/cmd/cmd_wat2wasm.ml @@ -0,0 +1,18 @@ +(* SPDX-License-Identifier: AGPL-3.0-or-later *) +(* Copyright © 2021-2024 OCamlPro *) +(* Written by the Owi programmers *) + +open Syntax + +let cmd_one ~unsafe ~optimize file = + let ext = Fpath.get_ext file in + match ext with + | ".wat" -> + let* modul = Parse.Text.Module.from_file file in + Binary_encoder.convert file ~unsafe ~optimize modul + | ext -> Error (`Unsupported_file_extension ext) + +let cmd profiling debug unsafe optimize files = + if profiling then Log.profiling_on := true; + if debug then Log.debug_on := true; + list_iter (cmd_one ~unsafe ~optimize) files diff --git a/src/cmd/cmd_wat2wasm.mli b/src/cmd/cmd_wat2wasm.mli new file mode 100644 index 000000000..5cef2e0c3 --- /dev/null +++ b/src/cmd/cmd_wat2wasm.mli @@ -0,0 +1,5 @@ +(* SPDX-License-Identifier: AGPL-3.0-or-later *) +(* Copyright © 2021-2024 OCamlPro *) +(* Written by the Owi programmers *) + +val cmd : bool -> bool -> bool -> bool -> Fpath.t list -> unit Result.t diff --git a/src/dune b/src/dune index 504901b43..c9afb1a09 100644 --- a/src/dune +++ b/src/dune @@ -8,6 +8,7 @@ binary_parser binary_to_text binary_types + binary_encoder c_instrumentor c_share c_share_site @@ -21,6 +22,7 @@ cmd_sym cmd_validate cmd_wasm2wat + cmd_wat2wasm compile concrete concrete_choice diff --git a/test/help/help.t b/test/help/help.t index 6b2e77088..827c9589b 100644 --- a/test/help/help.t +++ b/test/help/help.t @@ -29,9 +29,13 @@ no subcommand should print help Validate a module wasm2wat [OPTION]… [ARG]… - Generate a text format file (.wat) file from a binary format file + Generate a text format file (.wat) from a binary format file (.wasm) + wat2wasm [OPTION]… [ARG]… + Generate a binary format file (.wasm) from a text format file + (.wat) + COMMON OPTIONS --help[=FMT] (default=auto) Show this help in format FMT. The value FMT must be one of auto,