diff --git a/.github/workflows/js_of_ocaml.yml b/.github/workflows/js_of_ocaml.yml index 9279802be6..e2241e1693 100644 --- a/.github/workflows/js_of_ocaml.yml +++ b/.github/workflows/js_of_ocaml.yml @@ -96,6 +96,13 @@ jobs: skip-effects: true skip-test: true skip-doc: true + - os: ubuntu-latest + os-name: Ubuntu + ocaml-name: "OxCaml" + ocaml-compiler: "ocaml-variants.5.2.0+ox" + skip-effects: false + skip-test: false + skip-doc: true runs-on: ${{ matrix.os }} @@ -133,6 +140,16 @@ jobs: uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} + if: matrix.ocaml-compiler != 'ocaml-variants.5.2.0+ox' + + - name: Set-up OxCaml ${{ matrix.ocaml-compiler }} + uses: ocaml/setup-ocaml@v3 + with: + ocaml-compiler: ${{ matrix.ocaml-compiler }} + opam-repositories: | + default: https://github.com/ocaml/opam-repository.git + ox: https://github.com/oxcaml/opam-repository.git + if: matrix.ocaml-compiler == 'ocaml-variants.5.2.0+ox' # Work-around a race between reinstalling mingw-w64-shims # (because of conf-pkg-config optional dep) and installing other @@ -152,10 +169,17 @@ jobs: - run: opam install . --best-effort --solver builtin-mccs+glpk if: ${{ matrix.skip-test }} + - name: Pin qcheck + run: opam pin add -n https://github.com/vouillon/qcheck.git#oxcaml + if: matrix.ocaml-compiler == 'ocaml-variants.5.2.0+ox' + - run: opam install . --deps-only --with-test # Install the test dependencies if: ${{ !matrix.skip-test }} + - name: Pin js_of_ocaml + run: opam pin . -n --with-version 6.0.1+ox + - run: opam install . # Install the packages (without running the tests) if: ${{ !matrix.skip-test }} diff --git a/.github/workflows/wasm_of_ocaml.yml b/.github/workflows/wasm_of_ocaml.yml index 17996aeb2f..2d301c5ceb 100644 --- a/.github/workflows/wasm_of_ocaml.yml +++ b/.github/workflows/wasm_of_ocaml.yml @@ -58,6 +58,12 @@ jobs: separate_compilation: false jane_street_tests: true all_jane_street_tests: false + - os: ubuntu-latest + os-name: Ubuntu + ocaml-compiler: "ocaml-variants.5.2.0+ox" + separate_compilation: true + jane_street_tests: true + all_jane_street_tests: true runs-on: ${{ matrix.os }} @@ -75,13 +81,20 @@ jobs: path: wasm_of_ocaml - name: Checkout Jane Street opam repository - if: matrix.jane_street_tests + if: matrix.jane_street_tests && matrix.ocaml-compiler != 'ocaml-variants.5.2.0+ox' uses: actions/checkout@v5 with: repository: janestreet/opam-repository ref: 2819773f29b6f6c14b918eae3cb40c8ff6b22d0e path: janestreet/opam-repository + - name: Checkout OxCaml opam repository + if: matrix.jane_street_tests && matrix.ocaml-compiler == 'ocaml-variants.5.2.0+ox' + uses: actions/checkout@v5 + with: + repository: oxcaml/opam-repository + path: janestreet/opam-repository + - name: Set-up Node.js uses: actions/setup-node@v5 with: @@ -91,6 +104,16 @@ jobs: uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} + if: matrix.ocaml-compiler != 'ocaml-variants.5.2.0+ox' + + - name: Set-up OxCaml ${{ matrix.ocaml-compiler }} + uses: ocaml/setup-ocaml@v3 + with: + ocaml-compiler: ${{ matrix.ocaml-compiler }} + opam-repositories: | + default: https://github.com/ocaml/opam-repository.git + ox: https://github.com/oxcaml/opam-repository.git + if: matrix.ocaml-compiler == 'ocaml-variants.5.2.0+ox' - name: Set-up Binaryen uses: Aandreba/setup-binaryen@v1.0.0 @@ -109,14 +132,23 @@ jobs: - name: Pin wasm_of_ocaml working-directory: ./wasm_of_ocaml - run: opam pin . -n --with-version dev + run: opam pin . -n --with-version 6.0.1+ox + + - name: Pin ppxlib + run: opam pin add ppxlib -n 0.35.0 + if: matrix.ocaml-compiler != 'ocaml-variants.5.2.0+ox' + + - name: Pin specific packages for OxCaml + run: | + opam pin add -n https://github.com/vouillon/qcheck.git#oxcaml + opam pin add -n zarith 1.12+ox + if: matrix.ocaml-compiler == 'ocaml-variants.5.2.0+ox' - name: Checkout Jane Street packages if: matrix.jane_street_tests run: | opam repo add js janestreet/opam-repository opam install opam-format - opam pin add ppxlib -n 0.35.0 opam exec -- dune exec --root wasm_of_ocaml tools/ci_setup.exe - name: Pin Jane Street packages diff --git a/compiler/bin-js_of_ocaml/check_runtime.ml b/compiler/bin-js_of_ocaml/check_runtime.ml index 2501c30e6c..0d3f61efec 100644 --- a/compiler/bin-js_of_ocaml/check_runtime.ml +++ b/compiler/bin-js_of_ocaml/check_runtime.ml @@ -43,6 +43,7 @@ let print_groups output l = output_string output (Printf.sprintf "%s\n" name))) let f (runtime_files, bytecode, target_env) = + Config.Flag.set "use-js-string" true; Config.set_target `JavaScript; Config.set_effects_backend `Disabled; Linker.reset (); diff --git a/compiler/bin-js_of_ocaml/compile.ml b/compiler/bin-js_of_ocaml/compile.ml index deb995b991..df088b4fc1 100644 --- a/compiler/bin-js_of_ocaml/compile.ml +++ b/compiler/bin-js_of_ocaml/compile.ml @@ -318,7 +318,7 @@ let run sm in let output_partial - (cmo : Cmo_format.compilation_unit) + (cmo : Ocaml_compiler.Cmo_format.t) ~standalone ~shapes ~source_map diff --git a/compiler/bin-js_of_ocaml/js_of_ocaml.ml b/compiler/bin-js_of_ocaml/js_of_ocaml.ml index f4203025e8..40ecbf79f3 100644 --- a/compiler/bin-js_of_ocaml/js_of_ocaml.ml +++ b/compiler/bin-js_of_ocaml/js_of_ocaml.ml @@ -43,6 +43,8 @@ let () = | _ -> argv in try + with_async_exns + @@ fun () -> match Cmdliner.Cmd.eval_value ~catch:false diff --git a/compiler/bin-jsoo_minify/jsoo_minify.ml b/compiler/bin-jsoo_minify/jsoo_minify.ml index f636ab50e0..e878479574 100644 --- a/compiler/bin-jsoo_minify/jsoo_minify.ml +++ b/compiler/bin-jsoo_minify/jsoo_minify.ml @@ -92,7 +92,7 @@ let main = Cmdliner.Cmd.v Cmd_arg.info t let (_ : int) = - try Cmdliner.Cmd.eval ~catch:false ~argv:Sys.argv main with + try with_async_exns @@ fun () -> Cmdliner.Cmd.eval ~catch:false ~argv:Sys.argv main with | (Match_failure _ | Assert_failure _ | Not_found) as exc -> let backtrace = Printexc.get_backtrace () in Format.eprintf diff --git a/compiler/bin-wasm_of_ocaml/wasm_of_ocaml.ml b/compiler/bin-wasm_of_ocaml/wasm_of_ocaml.ml index bc87e9ba75..adbd615f24 100644 --- a/compiler/bin-wasm_of_ocaml/wasm_of_ocaml.ml +++ b/compiler/bin-wasm_of_ocaml/wasm_of_ocaml.ml @@ -41,6 +41,8 @@ let () = | _ -> argv in try + with_async_exns + @@ fun () -> match Cmdliner.Cmd.eval_value ~catch:false diff --git a/compiler/lib-dynlink/js_of_ocaml_compiler_dynlink.ml b/compiler/lib-dynlink/js_of_ocaml_compiler_dynlink.ml index 941997b98d..b46c7f0daa 100644 --- a/compiler/lib-dynlink/js_of_ocaml_compiler_dynlink.ml +++ b/compiler/lib-dynlink/js_of_ocaml_compiler_dynlink.ml @@ -4,7 +4,7 @@ module J = Jsoo_runtime.Js type bytecode_sections = { symb : Ocaml_compiler.Symtable.GlobalMap.t - ; crcs : (string * Digest.t option) list + ; crcs : Ocaml_compiler.Import_info.table ; prim : string list ; dlpt : string list } diff --git a/compiler/lib-runtime-files/js_of_ocaml_compiler_runtime_files.ml b/compiler/lib-runtime-files/js_of_ocaml_compiler_runtime_files.ml index 41466846a2..abeec1a665 100644 --- a/compiler/lib-runtime-files/js_of_ocaml_compiler_runtime_files.ml +++ b/compiler/lib-runtime-files/js_of_ocaml_compiler_runtime_files.ml @@ -33,6 +33,7 @@ let runtime = ; graphics ; hash ; ieee_754 + ; float32 ; int64 ; ints ; io diff --git a/compiler/lib-runtime-files/tests/all.ml b/compiler/lib-runtime-files/tests/all.ml index 0896252226..2911e16bf9 100644 --- a/compiler/lib-runtime-files/tests/all.ml +++ b/compiler/lib-runtime-files/tests/all.ml @@ -21,6 +21,7 @@ let%expect_test _ = +dynlink.js +effect.js +fail.js + +float32.js +format.js +fs.js +fs_fake.js @@ -64,6 +65,7 @@ let%expect_test _ = +domain.js +effect.js +fail.js + +float32.js +format.js +fs.js +fs_fake.js diff --git a/compiler/lib-wasm/gc_target.ml b/compiler/lib-wasm/gc_target.ml index eaaa6b6498..ef4b6c95f4 100644 --- a/compiler/lib-wasm/gc_target.ml +++ b/compiler/lib-wasm/gc_target.ml @@ -168,6 +168,22 @@ module Type = struct ] }) + let float32_type = + register_type "float32" (fun () -> + let* custom_operations = custom_operations_type in + let* custom = custom_type in + return + { supertype = Some custom + ; final = true + ; typ = + W.Struct + [ { mut = false + ; typ = Value (Ref { nullable = false; typ = Type custom_operations }) + } + ; { mut = false; typ = Value F32 } + ] + }) + let int32_type = register_type "int32" (fun () -> let* custom_operations = custom_operations_type in @@ -884,6 +900,24 @@ module Memory = struct in if_mismatch + let make_float32 e = + let* custom_operations = Type.custom_operations_type in + let* float32_ops = + register_import + ~name:"float32_ops" + (Global + { mut = false; typ = Ref { nullable = false; typ = Type custom_operations } }) + in + let* ty = Type.float32_type in + let* e = e in + return (W.StructNew (ty, [ GlobalGet float32_ops; e ])) + + let box_float32 = make_float32 + + let unbox_float32 e = + let* ty = Type.float32_type in + wasm_struct_get ty (wasm_cast ty e) 1 + let make_int32 ~kind e = let* custom_operations = Type.custom_operations_type in let* int32_ops = @@ -1043,6 +1077,9 @@ module Constant = struct | Float f -> let* ty = Type.float_type in return (Const, W.StructNew (ty, [ Const (F64 (Int64.float_of_bits f)) ])) + | Float32 f -> + let* e = Memory.make_float32 (return (W.Const (F32 (Int64.float_of_bits f)))) in + return (Const, e) | Float_array l -> let l = Array.to_list l in let* ty = Type.float_array_type in @@ -1060,11 +1097,18 @@ module Constant = struct | NativeInt i -> let* e = Memory.make_int32 ~kind:`Nativeint (return (W.Const (I32 i))) in return (Const, e) + | Null_ -> + let* var = + register_import ~name:"null" (Global { mut = false; typ = Type.value }) + in + return (Const, W.GlobalGet var) let translate ~unboxed c = match c with | Code.Int i -> return (W.Const (I32 (Targetint.to_int32 i))) | Float f when unboxed -> return (W.Const (F64 (Int64.float_of_bits f))) + | ((Float32 f) [@if oxcaml]) when unboxed -> + return (W.Const (F32 (Int64.float_of_bits f))) | Int64 i when unboxed -> return (W.Const (I64 i)) | (Int32 i | NativeInt i) when unboxed -> return (W.Const (I32 i)) | _ -> ( @@ -1418,6 +1462,7 @@ module Bigarray = struct , fun x -> let* x = x in return (W.F64PromoteF32 x) ) + | Float32_t -> "dv_get_f32", F32, 2, Fun.id | Float64 -> "dv_get_f64", F64, 3, Fun.id | Int8_signed -> "dv_get_i8", I32, 0, Fun.id | Int8_unsigned -> "dv_get_ui8", I32, 0, Fun.id @@ -1471,6 +1516,7 @@ module Bigarray = struct let* ofs = Arith.(i lsl const (Int32.of_int size)) in match kind with | Float32 + | Float32_t | Float64 | Int8_signed | Int8_unsigned @@ -1503,6 +1549,7 @@ module Bigarray = struct , fun x -> let* x = x in return (W.F32DemoteF64 x) ) + | Float32_t -> "dv_set_f32", F32, 2, Fun.id | Float64 -> "dv_set_f64", F64, 3, Fun.id | Int8_signed | Int8_unsigned -> "dv_set_i8", I32, 0, Fun.id | Int16_signed | Int16_unsigned -> "dv_set_i16", I32, 1, Fun.id @@ -1517,7 +1564,7 @@ module Bigarray = struct , fun x -> let* conv = register_import - ~name:"caml_double_to_float16" + ~name:"caml_float16_of_double" (Fun { W.params = [ F64 ]; result = [ I32 ] }) in let* x = x in @@ -1555,6 +1602,7 @@ module Bigarray = struct in match kind with | Float32 + | Float32_t | Float64 | Int8_signed | Int8_unsigned diff --git a/compiler/lib-wasm/generate.ml b/compiler/lib-wasm/generate.ml index b2b38efcae..5e23cb29c5 100644 --- a/compiler/lib-wasm/generate.ml +++ b/compiler/lib-wasm/generate.ml @@ -72,6 +72,7 @@ module Generate (Target : Target_sig.S) = struct type repr = | Value | Float + | Float32 | Int of normalized | Int32 | Nativeint @@ -81,6 +82,7 @@ module Generate (Target : Target_sig.S) = struct match r with | Value -> None | Float -> Some (Number (Float, Unboxed)) + | Float32 -> Some (Number (Float32, Unboxed)) | Int Normalized -> Some (Int Normalized) | Int Unnormalized -> Some (Int Unnormalized) | Int32 -> Some (Number (Int32, Unboxed)) @@ -91,6 +93,7 @@ module Generate (Target : Target_sig.S) = struct match r with | Value -> Type.value | Float -> F64 + | Float32 -> F32 | Int _ | Int32 | Nativeint -> I32 | Int64 -> I64 @@ -110,20 +113,25 @@ module Generate (Target : Target_sig.S) = struct ; "caml_string_get16", (`Mutator, [ Value; Int Normalized ], Int Normalized) ; "caml_string_get32", (`Mutator, [ Value; Int Normalized ], Int32) ; "caml_string_get64", (`Mutator, [ Value; Int Normalized ], Int64) + ; "caml_string_getf32", (`Mutator, [ Value; Int Normalized ], Float32) ; "caml_bytes_get16", (`Mutator, [ Value; Int Normalized ], Int Normalized) ; "caml_bytes_get32", (`Mutator, [ Value; Int Normalized ], Int32) ; "caml_bytes_get64", (`Mutator, [ Value; Int Normalized ], Int64) + ; "caml_bytes_getf32", (`Mutator, [ Value; Int Normalized ], Float32) ; "caml_bytes_set16", (`Mutator, [ Value; Int Normalized; Int Unnormalized ], Value) ; "caml_bytes_set32", (`Mutator, [ Value; Int Normalized; Int32 ], Value) ; "caml_bytes_set64", (`Mutator, [ Value; Int Normalized; Int64 ], Value) + ; "caml_bytes_setf32", (`Mutator, [ Value; Int Normalized; Float32 ], Value) ; "caml_lxm_next", (`Mutable, [ Value ], Int64) ; "caml_ba_uint8_get16", (`Mutator, [ Value; Int Normalized ], Int Normalized) ; "caml_ba_uint8_get32", (`Mutator, [ Value; Int Normalized ], Int32) ; "caml_ba_uint8_get64", (`Mutator, [ Value; Int Normalized ], Int64) + ; "caml_ba_uint8_getf32", (`Mutator, [ Value; Int Normalized ], Float32) ; ( "caml_ba_uint8_set16" , (`Mutator, [ Value; Int Normalized; Int Unnormalized ], Value) ) ; "caml_ba_uint8_set32", (`Mutator, [ Value; Int Normalized; Int32 ], Value) ; "caml_ba_uint8_set64", (`Mutator, [ Value; Int Normalized; Int64 ], Value) + ; "caml_ba_uint8_setf32", (`Mutator, [ Value; Int Normalized; Float32 ], Value) ; "caml_round_float", (`Pure, [ Float ], Float) ; "caml_nextafter_float", (`Pure, [ Float; Float ], Float) ; "caml_classify_float", (`Pure, [ Float ], Int Normalized) @@ -131,6 +139,15 @@ module Generate (Target : Target_sig.S) = struct ; "caml_erf_float", (`Pure, [ Float ], Float) ; "caml_erfc_float", (`Pure, [ Float ], Float) ; "caml_float_compare", (`Pure, [ Float; Float ], Int Normalized) + ; "caml_round_float32_bytecode", (`Pure, [ Float32 ], Float32) + ; "caml_nextafter_float32_bytecode", (`Pure, [ Float32; Float32 ], Float32) + ; "caml_classify_float32_bytecode", (`Pure, [ Float32 ], Int Normalized) + ; "caml_ldexp_float32_bytecode", (`Pure, [ Float32; Int Normalized ], Float32) + ; "caml_erf_float32_bytecode", (`Pure, [ Float32 ], Float32) + ; "caml_erfc_float32_bytecode", (`Pure, [ Float32 ], Float32) + ; "caml_float32_compare", (`Pure, [ Float32; Float32 ], Int Normalized) + ; "caml_float16_of_double", (`Pure, [ Float ], Int32) + ; "caml_double_of_float16", (`Pure, [ Int32 ], Float) ]; h @@ -143,6 +160,15 @@ module Generate (Target : Target_sig.S) = struct let* f = f in return (W.UnOp (F64 op, f)) + let float32_bin_op op f g = + let* f = f in + let* g = g in + return (W.BinOp (F32 op, f, g)) + + let float32_un_op op f = + let* f = f in + return (W.UnOp (F32 op, f)) + let int32_bin_op op f g = let* f = f in let* g = g in @@ -179,6 +205,8 @@ module Generate (Target : Target_sig.S) = struct return (W.Const (I64 0L)) | Int (Unnormalized | Normalized), Number (Float, Unboxed) -> return (W.Const (F64 0.)) + | Int (Unnormalized | Normalized), Number (Float32, Unboxed) -> + return (W.Const (F32 0.)) | _, Int (Normalized | Unnormalized) -> Value.int_val e | Int (Unnormalized | Normalized), _ -> Value.val_int e | Number (_, Unboxed), Number (_, Unboxed) -> e @@ -186,10 +214,12 @@ module Generate (Target : Target_sig.S) = struct | _, Number (Int64, Unboxed) -> Memory.unbox_int64 e | _, Number (Nativeint, Unboxed) -> Memory.unbox_nativeint e | _, Number (Float, Unboxed) -> Memory.unbox_float e + | _, Number (Float32, Unboxed) -> Memory.unbox_float32 e | Number (Int32, Unboxed), _ -> Memory.box_int32 e | Number (Int64, Unboxed), _ -> Memory.box_int64 e | Number (Nativeint, Unboxed), _ -> Memory.box_nativeint e | Number (Float, Unboxed), _ -> Memory.box_float e + | Number (Float32, Unboxed), _ -> Memory.box_float32 e | _ -> e let load_and_box ctx x = convert ~from:(Typing.var_type ctx.types x) ~into:Top (load x) @@ -235,8 +265,8 @@ module Generate (Target : Target_sig.S) = struct (if negate then Value.phys_neq else Value.phys_eq) (transl_prim_arg ctx ~typ:Top x) (transl_prim_arg ctx ~typ:Top y) - | (Int _ | Number _ | Tuple _ | Bigarray _), _ - | _, (Int _ | Number _ | Tuple _ | Bigarray _) -> + | (Int _ | Number _ | Tuple _ | Bigarray _ | Null), _ + | _, (Int _ | Number _ | Tuple _ | Bigarray _ | Null) -> (* Only Top may contain JavaScript values *) (if negate then Value.phys_neq else Value.phys_eq) (transl_prim_arg ctx ~typ:Top x) @@ -275,6 +305,8 @@ module Generate (Target : Target_sig.S) = struct let float_u = Typing.Number (Float, Unboxed) + let float32_u = Typing.Number (Float32, Unboxed) + let int32_u = Typing.Number (Int32, Unboxed) let int64_u = Typing.Number (Int64, Unboxed) @@ -287,6 +319,12 @@ module Generate (Target : Target_sig.S) = struct | [ x ] -> f (transl_prim_arg ctx ?typ x) | l -> invalid_arity name l ~expected:1) + let register_un_prim_ctx name ?typ ?ret_typ f = + register_prim name `Mutator ~unbox:(is_unboxed typ) ?ret_typ (fun ctx context l -> + match l with + | [ x ] -> f context (transl_prim_arg ctx ?typ x) + | l -> invalid_arity name l ~expected:1) + let register_bin_prim name k ?tx ?ty ?ret_typ f = let unbox = is_unboxed tx || is_unboxed ty in register_prim name k ~unbox ?ret_typ (fun ctx _ l -> @@ -350,6 +388,10 @@ module Generate (Target : Target_sig.S) = struct let x = transl_prim_arg ctx ~typ:float_u x in let y = transl_prim_arg ctx ~typ:float_u y in float_bin_op cmp_float x y + | Number (Float32, _), Number (Float32, _) -> + let x = transl_prim_arg ctx ~typ:float32_u x in + let y = transl_prim_arg ctx ~typ:float32_u y in + float32_bin_op cmp_float x y | _ -> let* f = register_import @@ -361,6 +403,19 @@ module Generate (Target : Target_sig.S) = struct return (W.Call (f, [ x; y ]))) | _ -> invalid_arity name l ~expected:2) + let float_of_float32 f = + let* f = f in + return (W.F64PromoteF32 f) + + let float32_of_float f = + let* f = f in + return (W.F32DemoteF64 f) + + let lift_float_un_op op f = float32_of_float (op (float_of_float32 f)) + + let lift_float_bin_op op f g = + float32_of_float (op (float_of_float32 f) (float_of_float32 g)) + let () = register_bin_prim "caml_floatarray_unsafe_get" @@ -368,12 +423,44 @@ module Generate (Target : Target_sig.S) = struct ~ty:int_n ~ret_typ:float_u Memory.float_array_get; + register_bin_prim + "caml_array_unsafe_get_indexed_by_int32" + `Mutable + ~ty:int32_u + (fun x y -> Memory.gen_array_get x y); + register_bin_prim + "caml_array_unsafe_get_indexed_by_int64" + `Mutable + ~ty:int64_u + (fun x y -> + let y = + let* y = y in + return (W.I32WrapI64 y) + in + Memory.gen_array_get x y); + register_bin_prim + "caml_array_unsafe_get_indexed_by_nativeint" + `Mutable + ~ty:nativeint_u + (fun x y -> Memory.gen_array_get x y); register_tern_prim "caml_array_unsafe_set" ~ty:int_n (fun x y z -> seq (Memory.gen_array_set x y z) Value.unit); register_tern_prim "caml_array_unsafe_set_addr" ~ty:int_n (fun x y z -> seq (Memory.array_set x y z) Value.unit); register_tern_prim "caml_floatarray_unsafe_set" ~ty:int_n ~tz:float_u (fun x y z -> seq (Memory.float_array_set x y z) Value.unit); + register_tern_prim "caml_array_unsafe_set_indexed_by_int32" ~ty:int32_u (fun x y z -> + seq (Memory.gen_array_set x y z) Value.unit); + register_tern_prim "caml_array_unsafe_set_indexed_by_int64" ~ty:int64_u (fun x y z -> + let y = + let* y = y in + return (W.I32WrapI64 y) + in + seq (Memory.gen_array_set x y z) Value.unit); + register_tern_prim + "caml_array_unsafe_set_indexed_by_nativeint" + ~ty:nativeint_u + (fun x y z -> seq (Memory.gen_array_set x y z) Value.unit); register_bin_prim "caml_string_unsafe_get" `Pure @@ -467,6 +554,50 @@ module Generate (Target : Target_sig.S) = struct let* cond = Arith.uge y (Memory.float_array_length (load a)) in instr (W.Br_if (label, cond))) x); + register_un_prim_ctx + "caml_checked_int32_to_int" + ~typ:int32_u + ~ret_typ:int_n + (fun context x -> + let y = Code.Var.fresh () in + seq + (let* () = store y x in + let label = label_index context bound_error_pc in + let* cond = Arith.((load y lsl const 1l) asr const 1l <> load y) in + instr (W.Br_if (label, cond))) + (load y)); + register_un_prim_ctx + "caml_checked_nativeint_to_int" + ~typ:nativeint_u + ~ret_typ:int_n + (fun context x -> + let y = Code.Var.fresh () in + seq + (let* () = store y x in + let label = label_index context bound_error_pc in + let* cond = Arith.((load y lsl const 1l) asr const 1l <> load y) in + instr (W.Br_if (label, cond))) + (load y)); + register_un_prim_ctx + "caml_checked_int64_to_int" + ~typ:int64_u + ~ret_typ:int_n + (fun context x -> + let y = Code.Var.fresh () in + seq + (let* () = store y x in + let* y = load y in + let label = label_index context bound_error_pc in + let cond = + W.BinOp + ( I64 Ne + , y + , BinOp (I64 (Shr U), BinOp (I64 Shl, y, Const (I64 33L)), Const (I64 33L)) + ) + in + instr (W.Br_if (label, cond))) + (let* y = load y in + return (W.I32WrapI64 y))); register_arith_bin_prim "caml_add_float" `Pure ~typ:float_u (fun f g -> float_bin_op Add f g); register_arith_bin_prim "caml_sub_float" ~typ:float_u `Pure (fun f g -> @@ -538,7 +669,7 @@ module Generate (Target : Target_sig.S) = struct (fun f g -> float_bin_op Lt f g); register_un_prim "caml_int_of_float" `Pure ~typ:float_u ~ret_typ:int_u (fun f -> let* f = f in - return (W.UnOp (I32 (TruncSatF64 S), f))); + return (W.UnOp (I32 (TruncSat (`F64, S)), f))); register_un_prim "caml_float_of_int" `Pure ~typ:int_n ~ret_typ:float_u (fun n -> let* n = n in return (W.UnOp (F64 (Convert (`I32, S)), n))); @@ -566,6 +697,324 @@ module Generate (Target : Target_sig.S) = struct register_arith_bin_prim "caml_power_float" `Pure ~typ:float_u Math.power; register_arith_bin_prim "caml_hypot_float" `Pure ~typ:float_u Math.hypot; register_arith_bin_prim "caml_fmod_float" `Pure ~typ:float_u Math.fmod; + register_arith_bin_prim "caml_add_float32" `Pure ~typ:float32_u (fun f g -> + float32_bin_op Add f g); + register_arith_bin_prim "caml_sub_float32" `Pure ~typ:float32_u (fun f g -> + float32_bin_op Sub f g); + register_arith_bin_prim "caml_mul_float32" `Pure ~typ:float32_u (fun f g -> + float32_bin_op Mul f g); + register_arith_bin_prim "caml_div_float32" `Pure ~typ:float32_u (fun f g -> + float32_bin_op Div f g); + register_arith_bin_prim + "caml_copysign_float32_bytecode" + `Pure + ~typ:float32_u + (fun f g -> float32_bin_op CopySign f g); + register_un_prim + "caml_signbit_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:int_n + (fun f -> + let* f = f in + Arith.(return (W.UnOp (I32 ReinterpretF, f)) lsr const 31l)); + register_un_prim "caml_neg_float32" `Pure ~typ:float32_u ~ret_typ:float32_u (fun f -> + float32_un_op Neg f); + register_un_prim "caml_abs_float32" `Pure ~typ:float32_u ~ret_typ:float32_u (fun f -> + float32_un_op Abs f); + register_un_prim + "caml_ceil_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (fun f -> float32_un_op Ceil f); + register_un_prim + "caml_floor_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (fun f -> float32_un_op Floor f); + register_un_prim + "caml_trunc_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (fun f -> float32_un_op Trunc f); + register_un_prim + "caml_sqrt_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (fun f -> float32_un_op Sqrt f); + register_bin_prim + "caml_eq_float32" + `Pure + ~tx:float32_u + ~ty:float32_u + ~ret_typ:int_n + (fun f g -> float32_bin_op Eq f g); + register_bin_prim + "caml_neq_float32" + `Pure + ~tx:float32_u + ~ty:float32_u + ~ret_typ:int_n + (fun f g -> float32_bin_op Ne f g); + register_bin_prim + "caml_ge_float32" + `Pure + ~tx:float32_u + ~ty:float32_u + ~ret_typ:int_n + (fun f g -> float32_bin_op Ge f g); + register_bin_prim + "caml_le_float32" + `Pure + ~tx:float32_u + ~ty:float32_u + ~ret_typ:int_n + (fun f g -> float32_bin_op Le f g); + register_bin_prim + "caml_gt_float32" + `Pure + ~tx:float32_u + ~ty:float32_u + ~ret_typ:int_n + (fun f g -> float32_bin_op Gt f g); + register_bin_prim + "caml_lt_float32" + ~tx:float32_u + ~ty:float32_u + ~ret_typ:int_n + `Pure + (fun f g -> float32_bin_op Lt f g); + register_un_prim "caml_int_of_float32" `Pure ~typ:float32_u ~ret_typ:int_u (fun f -> + let* f = f in + return (W.UnOp (I32 (TruncSat (`F32, S)), f))); + register_un_prim "caml_float32_of_int" `Pure ~typ:int_n ~ret_typ:float32_u (fun n -> + float32_un_op (Convert (`I32, S)) n); + register_un_prim + "caml_cos_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.cos); + register_un_prim + "caml_sin_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.sin); + register_un_prim + "caml_tan_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.tan); + register_un_prim + "caml_acos_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.acos); + register_un_prim + "caml_asin_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.asin); + register_un_prim + "caml_atan_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.atan); + register_arith_bin_prim + "caml_atan2_float32_bytecode" + `Pure + ~typ:float32_u + (lift_float_bin_op Math.atan2); + register_un_prim + "caml_cosh_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.cosh); + register_un_prim + "caml_sinh_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.sinh); + register_un_prim + "caml_tanh_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.tanh); + register_un_prim + "caml_acosh_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.acosh); + register_un_prim + "caml_asinh_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.asinh); + register_un_prim + "caml_atanh_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.atanh); + register_un_prim + "caml_cbrt_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.cbrt); + register_un_prim + "caml_exp_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.exp); + register_un_prim + "caml_exp2_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.exp2); + register_un_prim + "caml_log_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.log); + register_un_prim + "caml_expm1_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.expm1); + register_un_prim + "caml_log1p_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.log1p); + register_un_prim + "caml_log2_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.log2); + register_un_prim + "caml_log10_float32_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (lift_float_un_op Math.log10); + register_arith_bin_prim + "caml_power_float32_bytecode" + `Pure + ~typ:float32_u + (lift_float_bin_op Math.power); + register_arith_bin_prim + "caml_hypot_float32_bytecode" + `Pure + ~typ:float32_u + (lift_float_bin_op Math.hypot); + register_arith_bin_prim + "caml_fmod_float32_bytecode" + `Pure + ~typ:float32_u + (lift_float_bin_op Math.fmod); + register_un_prim + "caml_float32_to_bits_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:int32_u + (fun f -> + let* f = f in + return (W.UnOp (I32 ReinterpretF, f))); + register_un_prim + "caml_float32_of_bits_bytecode" + `Pure + ~typ:int32_u + ~ret_typ:float32_u + (fun i -> float32_un_op ReinterpretI i); + register_un_prim + "caml_float_of_float32" + `Pure + ~typ:float32_u + ~ret_typ:float_u + float_of_float32; + register_un_prim + "caml_float32_of_float" + `Pure + ~typ:float_u + ~ret_typ:float32_u + float32_of_float; + register_un_prim + "caml_float32_to_int64_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:int64_u + (fun f -> + let* f = f in + return (W.UnOp (I64 (TruncSat (`F32, S)), f))); + register_un_prim + "caml_float32_of_int64_bytecode" + `Pure + ~typ:int64_u + ~ret_typ:float32_u + (fun n -> float32_un_op (Convert (`I64, S)) n); + register_un_prim + "caml_simd_cast_float32_int64_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:int64_u + (fun f -> + let* f = f in + return (W.UnOp (I64 (TruncSat (`F32, S)), W.UnOp (F32 Nearest, f)))); + register_un_prim + "caml_simd_float32_round_current_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (fun f -> float32_un_op Nearest f); + register_un_prim + "caml_simd_float32_round_neg_inf_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (fun f -> float32_un_op Floor f); + register_un_prim + "caml_simd_float32_round_pos_inf_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (fun f -> float32_un_op Ceil f); + register_un_prim + "caml_simd_float32_round_towards_zero_bytecode" + `Pure + ~typ:float32_u + ~ret_typ:float32_u + (fun f -> float32_un_op Trunc f); + register_arith_bin_prim + "caml_simd_float32_min_bytecode" + `Pure + ~typ:float32_u + (fun f g -> float32_bin_op Min f g); + register_arith_bin_prim + "caml_simd_float32_max_bytecode" + `Pure + ~typ:float32_u + (fun f g -> float32_bin_op Max f g); register_un_prim "caml_int32_bits_of_float" `Pure @@ -584,7 +1033,7 @@ module Generate (Target : Target_sig.S) = struct return (W.F64PromoteF32 (UnOp (F32 ReinterpretI, i)))); register_un_prim "caml_int32_of_float" `Pure ~typ:float_u ~ret_typ:int32_u (fun f -> let* f = f in - return (W.UnOp (I32 (TruncSatF64 S), f))); + return (W.UnOp (I32 (TruncSat (`F64, S)), f))); register_un_prim "caml_int32_to_float" `Pure ~typ:int32_u ~ret_typ:float_u (fun n -> let* n = n in return (W.UnOp (F64 (Convert (`I32, S)), n))); @@ -703,7 +1152,7 @@ module Generate (Target : Target_sig.S) = struct return (W.UnOp (F64 ReinterpretI, i))); register_un_prim "caml_int64_of_float" `Pure ~typ:float_u ~ret_typ:int64_u (fun f -> let* f = f in - return (W.UnOp (I64 (TruncSatF64 S), f))); + return (W.UnOp (I64 (TruncSat (`F64, S)), f))); register_un_prim "caml_int64_to_float" `Pure ~typ:int64_u ~ret_typ:float_u (fun n -> let* n = n in return (W.UnOp (F64 (Convert (`I64, S)), n))); @@ -844,7 +1293,7 @@ module Generate (Target : Target_sig.S) = struct ~ret_typ:nativeint_u (fun f -> let* f = f in - return (W.UnOp (I32 (TruncSatF64 S), f))); + return (W.UnOp (I32 (TruncSat (`F64, S)), f))); register_un_prim "caml_nativeint_to_float" `Pure @@ -1076,6 +1525,50 @@ module Generate (Target : Target_sig.S) = struct let* indices' = transl_prim_arg ctx indices in return (W.Call (f, [ ta'; indices' ]))) | _ -> invalid_arity "caml_ba_get_generic" l ~expected:2); + let caml_ba_float32_get_n ~ctx ~context ta indices = + match get_type ctx ta with + | Bigarray { layout; _ } -> + let indices = List.map ~f:(fun i -> transl_prim_arg ctx ~typ:int_n i) indices in + caml_ba_get ~ctx ~context ~kind:Float32_t ~layout ta indices + | _ -> + let n = List.length indices in + let* f = + register_import + ~name:(Printf.sprintf "caml_ba_float32_get_%d" n) + (Fun + { W.params = + Type.value :: List.init ~len:n ~f:(fun _ : W.value_type -> I32) + ; result = [ F32 ] + }) + in + let* ta' = transl_prim_arg ctx ta in + let* indices' = expression_list (transl_prim_arg ctx ~typ:int_n) indices in + return (W.Call (f, ta' :: indices')) + in + register_prim + "caml_ba_float32_get_1" + `Mutator + ~ret_typ:float32_u + (fun ctx context l -> + match l with + | [ ta; i ] -> caml_ba_float32_get_n ~ctx ~context ta [ i ] + | _ -> invalid_arity "caml_ba_float32_get_1" l ~expected:2); + register_prim + "caml_ba_float32_get_2" + `Mutator + ~ret_typ:float32_u + (fun ctx context l -> + match l with + | [ ta; i; j ] -> caml_ba_float32_get_n ~ctx ~context ta [ i; j ] + | _ -> invalid_arity "caml_ba_float32_get_2" l ~expected:3); + register_prim + "caml_ba_float32_get_3" + `Mutator + ~ret_typ:float32_u + (fun ctx context l -> + match l with + | [ ta; i; j; k ] -> caml_ba_float32_get_n ~ctx ~context ta [ i; j; k ] + | _ -> invalid_arity "caml_ba_float32_get_3" l ~expected:4); let caml_ba_set ~ctx ~context ~kind ~layout ta indices v = let ta' = transl_prim_arg ctx ta in let v' = transl_prim_arg ctx ~typ:(Typing.bigarray_element_type kind) v in @@ -1132,7 +1625,47 @@ module Generate (Target : Target_sig.S) = struct let* indices' = transl_prim_arg ctx indices in let* v' = transl_prim_arg ctx v in return (W.Call (f, [ ta'; indices'; v' ]))) - | _ -> invalid_arity "caml_ba_set_generic" l ~expected:3) + | _ -> invalid_arity "caml_ba_set_generic" l ~expected:3); + let caml_ba_float32_set_n ~ctx ~context ta indices v = + match get_type ctx ta with + | Bigarray { layout; _ } -> + let indices = List.map ~f:(fun i -> transl_prim_arg ctx ~typ:int_n i) indices in + caml_ba_set ~ctx ~context ~kind:Float32_t ~layout ta indices v + | _ -> + let n = List.length indices in + let* f = + register_import + ~name:(Printf.sprintf "caml_ba_float32_set_%d" n) + (Fun + { W.params = + (Type.value :: List.init ~len:n ~f:(fun _ : W.value_type -> I32)) + @ [ F32 ] + ; result = [ Type.value ] + }) + in + let* ta' = transl_prim_arg ctx ta in + let* indices' = expression_list (transl_prim_arg ctx ~typ:int_n) indices in + let* v' = transl_prim_arg ctx ~typ:float32_u v in + return (W.Call (f, ta' :: (indices' @ [ v' ]))) + in + register_prim "caml_ba_float32_set_1" `Mutator ~unbox:true (fun ctx context l -> + match l with + | [ ta; i; v ] -> caml_ba_float32_set_n ~ctx ~context ta [ i ] v + | _ -> invalid_arity "caml_ba_float32_set_1" l ~expected:3); + register_prim "caml_ba_float32_set_2" `Mutator ~unbox:true (fun ctx context l -> + match l with + | [ ta; i; j; v ] -> caml_ba_float32_set_n ~ctx ~context ta [ i; j ] v + | _ -> invalid_arity "caml_ba_float32_set_2" l ~expected:4); + register_prim "caml_ba_float32_set_3" `Mutator ~unbox:true (fun ctx context l -> + match l with + | [ ta; i; j; k; v ] -> caml_ba_float32_set_n ~ctx ~context ta [ i; j; k ] v + | _ -> invalid_arity "caml_ba_float32_set_3" l ~expected:5); + register_un_prim "caml_is_null" `Pure ~ret_typ:int_n (fun x -> + let* x = x in + let* null = + register_import ~name:"null" (Global { mut = false; typ = Type.value }) + in + return (W.RefEq (x, GlobalGet null))) let unboxed_type ty : W.value_type option = match ty with @@ -1140,6 +1673,7 @@ module Generate (Target : Target_sig.S) = struct Some I32 | Number (Int64, Unboxed) -> Some I64 | Number (Float, Unboxed) -> Some F64 + | Number (Float32, Unboxed) -> Some F32 | _ -> None let box_number_if_needed ctx x e = @@ -1278,6 +1812,12 @@ module Generate (Target : Target_sig.S) = struct Memory.array_get (transl_prim_arg ctx x) (transl_prim_arg ctx ~typ:int_n y) | Prim (Extern "caml_array_unsafe_get", [ x; y ]) -> Memory.gen_array_get (transl_prim_arg ctx x) (transl_prim_arg ctx ~typ:int_n y) + | Prim (Extern "caml_csel_value", [ y; z; t ]) -> + let typ = Typing.var_type ctx.types x in + let* y = transl_prim_arg ctx ~typ:int_u y in + let* z = transl_prim_arg ctx ~typ z in + let* t = transl_prim_arg ctx ~typ t in + return (W.IfExpr (Option.value ~default:Type.value (unboxed_type typ), y, z, t)) | Prim (p, l) -> ( match p with | Extern name when String.Hashtbl.mem internal_primitives name -> @@ -1433,14 +1973,23 @@ module Generate (Target : Target_sig.S) = struct | "caml_check_bound" | "caml_check_bound_gen" | "caml_check_bound_float" + | "caml_checked_int32_to_int" + | "caml_checked_nativeint_to_int" + | "caml_checked_int64_to_int" | "caml_ba_get_1" | "caml_ba_get_2" | "caml_ba_get_3" + | "caml_ba_float32_get_1" + | "caml_ba_float32_get_2" + | "caml_ba_float32_get_3" | "caml_ba_get_generic" | "caml_ba_set_1" | "caml_ba_set_2" | "caml_ba_set_3" - | "caml_ba_set_generic" ) + | "caml_ba_set_generic" + | "caml_ba_float32_set_1" + | "caml_ba_float32_set_2" + | "caml_ba_float32_set_3" ) , _ ) ) -> fst n, true | Let ( _ @@ -1867,6 +2416,7 @@ module Generate (Target : Target_sig.S) = struct Typing.reset (); Primitive.register "caml_make_array" `Mutable None None; Primitive.register "caml_array_of_uniform_array" `Mutable None None; + Typing.register_prim "caml_csel_value" ~unbox:true Top; String.Hashtbl.iter (fun name (k, unbox, typ, _) -> Primitive.register name k None None; @@ -1881,7 +2431,7 @@ module Generate (Target : Target_sig.S) = struct (List.exists ~f:(fun ty -> match ty with - | Int32 | Nativeint | Int64 | Float -> true + | Int32 | Nativeint | Int64 | Float | Float32 -> true | Value | Int _ -> false) param_types) (Option.value ~default:Typing.Top (repr_type typ))) diff --git a/compiler/lib-wasm/target_sig.ml b/compiler/lib-wasm/target_sig.ml index 307aba9a9a..f13e4aac5c 100644 --- a/compiler/lib-wasm/target_sig.ml +++ b/compiler/lib-wasm/target_sig.ml @@ -81,6 +81,10 @@ module type S = sig val unbox_float : expression -> expression + val box_float32 : expression -> expression + + val unbox_float32 : expression -> expression + val box_int32 : expression -> expression val unbox_int32 : expression -> expression diff --git a/compiler/lib-wasm/typing.ml b/compiler/lib-wasm/typing.ml index 90b8819c43..004f75f016 100644 --- a/compiler/lib-wasm/typing.ml +++ b/compiler/lib-wasm/typing.ml @@ -39,6 +39,7 @@ type boxed_number = | Int64 | Nativeint | Float + | Float32 type boxed_status = | Boxed @@ -48,6 +49,7 @@ module Bigarray = struct type kind = | Float16 | Float32 + | Float32_t | Float64 | Int8_signed | Int8_unsigned @@ -100,6 +102,7 @@ module Bigarray = struct "bigarray{%s,%s}" (match kind with | Float32 -> "float32" + | Float32_t -> "float32_t" | Float64 -> "float64" | Int8_signed -> "sint8" | Int8_unsigned -> "uint8" @@ -129,6 +132,7 @@ type typ = overapproximation of the possible values of each of its fields is given by the array of types *) | Bigarray of Bigarray.t + | Null | Bot module Domain = struct @@ -156,11 +160,12 @@ module Domain = struct else Array.init (max l l') ~f:(fun i -> if i < l then if i < l' then join t.(i) t'.(i) else t.(i) else t'.(i))) - | Int _, Tuple _ -> t' - | Tuple _, Int _ -> t + | (Int _ | Null), Tuple _ -> t' + | Tuple _, (Int _ | Null) -> t | Bigarray b, Bigarray b' when Bigarray.equal b b' -> t + | Null, Null -> Null | Top, _ | _, Top -> Top - | (Int _ | Number _ | Tuple _ | Bigarray _), _ -> Top + | (Int _ | Number _ | Tuple _ | Bigarray _ | Null), _ -> Top let join_set ?(others = false) f s = if others then Top else Var.Set.fold (fun x a -> join (f x) a) s Bot @@ -173,7 +178,8 @@ module Domain = struct | Tuple t, Tuple t' -> Array.length t = Array.length t' && Array.for_all2 ~f:equal t t' | Bigarray b, Bigarray b' -> Bigarray.equal b b' - | (Top | Tuple _ | Int _ | Number _ | Bigarray _ | Bot), _ -> false + | Null, Null -> true + | (Top | Tuple _ | Int _ | Number _ | Bigarray _ | Null | Bot), _ -> false let bot = Bot @@ -181,12 +187,12 @@ module Domain = struct let rec depth t = match t with - | Top | Bot | Number _ | Int _ | Bigarray _ -> 0 + | Top | Bot | Number _ | Int _ | Bigarray _ | Null -> 0 | Tuple l -> 1 + Array.fold_left ~f:(fun acc t' -> max (depth t') acc) l ~init:0 let rec truncate depth t = match t with - | Top | Bot | Number _ | Int _ | Bigarray _ -> t + | Top | Bot | Number _ | Int _ | Bigarray _ | Null -> t | Tuple l -> if depth = 0 then Top @@ -220,11 +226,13 @@ module Domain = struct | Int32 -> "int32" | Int64 -> "int64" | Nativeint -> "nativeint" - | Float -> "float") + | Float -> "float" + | Float32 -> "float32") (match b with | Boxed -> "boxed" | Unboxed -> "unboxed") | Bigarray b -> Bigarray.print f b + | Null -> Format.fprintf f "null" | Tuple t -> Format.fprintf f @@ -250,7 +258,8 @@ let update_deps st { blocks; _ } = | "caml_ba_get_1" | "caml_ba_get_2" | "caml_ba_get_3" - | "caml_ba_get_generic" ) + | "caml_ba_get_generic" + | "caml_csel_value" ) , lst ) ) -> (* The return type of these primitives depend on the input type *) List.iter @@ -289,7 +298,9 @@ let rec constant_type (c : constant) = | Int64 _ -> Number (Int64, Unboxed) | NativeInt _ -> Number (Nativeint, Unboxed) | Float _ -> Number (Float, Unboxed) + | Float32 _ -> Number (Float32, Unboxed) | Tuple (_, a, _) -> Tuple (Array.map ~f:(fun c' -> Domain.box (constant_type c')) a) + | Null_ -> Null | _ -> Top let arg_type ~approx arg = @@ -300,6 +311,7 @@ let arg_type ~approx arg = let bigarray_element_type (kind : Bigarray.kind) = match kind with | Float16 | Float32 | Float64 -> Number (Float, Unboxed) + | Float32_t -> Number (Float32, Unboxed) | Int8_signed | Int8_unsigned | Int16_signed | Int16_unsigned -> Int Normalized | Int -> Int Unnormalized | Int32 -> Number (Int32, Unboxed) @@ -346,6 +358,10 @@ let prim_type ~st ~approx prim args = | Expr (Block _) -> bigarray_type ~approx ba | _ -> Top) | [] | [ _ ] | _ :: Pc _ :: _ -> Top) + | "caml_csel_value" -> ( + match args with + | [ _; x; y ] -> Domain.join (arg_type ~approx x) (arg_type ~approx y) + | [] | [ _ ] | [ _; _ ] | _ :: _ :: _ :: _ :: _ -> Top) | _ -> ( try snd (String.Hashtbl.find primitive_types prim) with Not_found -> Top) let reset () = String.Hashtbl.reset primitive_types @@ -493,7 +509,8 @@ let type_specialized_primitive types global_flow_state name args = | [ Number (Int32, _); Number (Int32, _) ] | [ Number (Int64, _); Number (Int64, _) ] | [ Number (Nativeint, _); Number (Nativeint, _) ] - | [ Number (Float, _); Number (Float, _) ] -> true + | [ Number (Float, _); Number (Float, _) ] + | [ Number (Float32, _); Number (Float32, _) ] -> true | _ -> false) | "caml_ba_get_1" | "caml_ba_get_2" @@ -538,9 +555,17 @@ let box_numbers p st types = then let s = Var.Map.find g st.global_flow_info.info_return_vals in Var.Set.iter box s) + | Expr (Prim (Extern "caml_csel_value", [ _; y; z ])) -> + let box_arg arg = + match arg with + | Pv x -> box x + | Pc _ -> () + in + box_arg y; + box_arg z | Expr _ -> () | Phi { known; _ } -> Var.Set.iter box known) - | Number (_, Boxed) | Int _ | Tuple _ | Bigarray _ | Bot -> ()) + | Number (_, Boxed) | Int _ | Tuple _ | Bigarray _ | Null | Bot -> ()) in Code.fold_closures p diff --git a/compiler/lib-wasm/typing.mli b/compiler/lib-wasm/typing.mli index 40b02510e9..b14b23232e 100644 --- a/compiler/lib-wasm/typing.mli +++ b/compiler/lib-wasm/typing.mli @@ -10,6 +10,7 @@ type boxed_number = | Int64 | Nativeint | Float + | Float32 type boxed_status = | Boxed @@ -19,6 +20,7 @@ module Bigarray : sig type kind = | Float16 | Float32 + | Float32_t | Float64 | Int8_signed | Int8_unsigned @@ -47,6 +49,7 @@ type typ = | Number of boxed_number * boxed_status | Tuple of typ array | Bigarray of Bigarray.t + | Null | Bot val constant_type : Code.constant -> typ diff --git a/compiler/lib-wasm/wasm_ast.ml b/compiler/lib-wasm/wasm_ast.ml index 889117fceb..ef9f7a78ed 100644 --- a/compiler/lib-wasm/wasm_ast.ml +++ b/compiler/lib-wasm/wasm_ast.ml @@ -83,7 +83,7 @@ type int_un_op = | Ctz | Popcnt | Eqz - | TruncSatF64 of signage + | TruncSat of [ `F32 | `F64 ] * signage | ReinterpretF type int_bin_op = diff --git a/compiler/lib-wasm/wasm_output.ml b/compiler/lib-wasm/wasm_output.ml index 88595ca03a..65014689ca 100644 --- a/compiler/lib-wasm/wasm_output.ml +++ b/compiler/lib-wasm/wasm_output.ml @@ -370,12 +370,15 @@ end = struct | Ctz -> output_byte ch (arith + 1) | Popcnt -> output_byte ch (arith + 2) | Eqz -> output_byte ch comp - | TruncSatF64 signage -> + | TruncSat (size, signage) -> Feature.require nontrapping_fptoint; output_byte ch 0xFC; output_byte ch (trunc + + (match size with + | `F32 -> 0 + | `F64 -> 2) + match signage with | S -> 0 @@ -504,8 +507,8 @@ end = struct | UnOp (op, e') -> ( output_expression st ch e'; match op with - | I32 op -> int_un_op (0x67, 0x45, 2, 0xBC) ch op - | I64 op -> int_un_op (0x79, 0x50, 6, 0xBD) ch op + | I32 op -> int_un_op (0x67, 0x45, 0, 0xBC) ch op + | I64 op -> int_un_op (0x79, 0x50, 4, 0xBD) ch op | F32 op -> output_byte ch (float_un_op (0x8B, 0xB2, 0xBE) op) | F64 op -> output_byte ch (float_un_op (0x99, 0xB7, 0xBF) op)) | BinOp (op, e', e'') -> ( diff --git a/compiler/lib-wasm/wat_output.ml b/compiler/lib-wasm/wat_output.ml index 58d8250c05..3c5bd04c1f 100644 --- a/compiler/lib-wasm/wat_output.ml +++ b/compiler/lib-wasm/wat_output.ml @@ -253,7 +253,8 @@ let int_un_op sz op = | Ctz -> "ctz" | Popcnt -> "popcnt" | Eqz -> "eqz" - | TruncSatF64 s -> signage "trunc_sat_f64" s + | TruncSat (`F64, s) -> signage "trunc_sat_f64" s + | TruncSat (`F32, s) -> signage "trunc_sat_f32" s | ReinterpretF -> "reinterpret_f" ^ sz let int_bin_op _ (op : int_bin_op) = diff --git a/compiler/lib/code.ml b/compiler/lib/code.ml index 4399705188..f8a2370b55 100644 --- a/compiler/lib/code.ml +++ b/compiler/lib/code.ml @@ -322,12 +322,14 @@ type constant = | String of string | NativeString of Native_string.t | Float of Int64.t + | Float32 of Int64.t | Float_array of Int64.t array | Int of Targetint.t | Int32 of Int32.t | Int64 of Int64.t | NativeInt of Int32.t (* Native int are 32bit on all known backend *) | Tuple of int * constant array * array_or_not + | Null_ module Constant = struct type t = constant @@ -360,8 +362,12 @@ module Constant = struct b) | Float a, Float b -> Some (Float.ieee_equal (Int64.float_of_bits a) (Int64.float_of_bits b)) + | Float32 a, Float32 b -> + Some (Float.ieee_equal (Int64.float_of_bits a) (Int64.float_of_bits b)) + | Null_, Null_ -> Some true | String _, NativeString _ | NativeString _, String _ -> None | Int _, Float _ | Float _, Int _ -> None + | Int _, Float32 _ | Float32 _, Int _ -> None | Tuple ((0 | 254), _, _), Float_array _ -> None | Float_array _, Tuple ((0 | 254), _, _) -> None | ( Tuple _ @@ -372,6 +378,7 @@ module Constant = struct | Int32 _ | NativeInt _ | Float _ + | Float32 _ | Float_array _ ) ) -> Some false | ( Float_array _ , ( String _ @@ -381,13 +388,26 @@ module Constant = struct | Int32 _ | NativeInt _ | Float _ + | Float32 _ | Tuple _ ) ) -> Some false | ( String _ - , (Int64 _ | Int _ | Int32 _ | NativeInt _ | Float _ | Tuple _ | Float_array _) ) -> - Some false + , ( Int64 _ + | Int _ + | Int32 _ + | NativeInt _ + | Float _ + | Float32 _ + | Tuple _ + | Float_array _ ) ) -> Some false | ( NativeString _ - , (Int64 _ | Int _ | Int32 _ | NativeInt _ | Float _ | Tuple _ | Float_array _) ) -> - Some false + , ( Int64 _ + | Int _ + | Int32 _ + | NativeInt _ + | Float _ + | Float32 _ + | Tuple _ + | Float_array _ ) ) -> Some false | ( Int64 _ , ( String _ | NativeString _ @@ -395,19 +415,25 @@ module Constant = struct | Int32 _ | NativeInt _ | Float _ + | Float32 _ | Tuple _ | Float_array _ ) ) -> Some false - | Float _, (String _ | NativeString _ | Float_array _ | Int64 _ | Tuple (_, _, _)) -> - Some false + | ( Float _ + , (Float32 _ | String _ | NativeString _ | Float_array _ | Int64 _ | Tuple (_, _, _)) + ) -> Some false + | ( Float32 _ + , (Float _ | String _ | NativeString _ | Float_array _ | Int64 _ | Tuple (_, _, _)) + ) -> Some false | ( (Int _ | Int32 _ | NativeInt _) , (String _ | NativeString _ | Float_array _ | Int64 _ | Tuple (_, _, _)) ) -> Some false + | Null_, _ | _, Null_ -> Some false (* Note: the following cases should not occur when compiling to Javascript *) | Int _, (Int32 _ | NativeInt _) | Int32 _, (Int _ | NativeInt _) | NativeInt _, (Int _ | Int32 _) - | (Int32 _ | NativeInt _), Float _ - | Float _, (Int32 _ | NativeInt _) -> None + | (Int32 _ | NativeInt _), (Float _ | Float32 _) + | (Float _ | Float32 _), (Int32 _ | NativeInt _) -> None end type loc = @@ -494,6 +520,7 @@ module Print = struct | NativeString (Byte s) -> Format.fprintf f "%Sj" s | NativeString (Utf (Utf8 s)) -> Format.fprintf f "%Sj" s | Float fl -> Format.fprintf f "%.12g" (Int64.float_of_bits fl) + | Float32 fl -> Format.fprintf f "%.9g" (Int64.float_of_bits fl) | Float_array a -> Format.fprintf f "[|"; for i = 0 to Array.length a - 1 do @@ -521,6 +548,7 @@ module Print = struct constant f a.(i) done; Format.fprintf f ")") + | Null_ -> Format.fprintf f "null" let arg f a = match a with diff --git a/compiler/lib/code.mli b/compiler/lib/code.mli index bc9dcab0e8..1838ccdc9b 100644 --- a/compiler/lib/code.mli +++ b/compiler/lib/code.mli @@ -144,12 +144,14 @@ type constant = | String of string | NativeString of Native_string.t | Float of Int64.t + | Float32 of Int64.t | Float_array of Int64.t array | Int of Targetint.t | Int32 of Int32.t (** Only produced when compiling to WebAssembly. *) | Int64 of Int64.t | NativeInt of Int32.t (** Only produced when compiling to WebAssembly. *) | Tuple of int * constant array * array_or_not + | Null_ module Constant : sig type t = constant diff --git a/compiler/lib/config.ml b/compiler/lib/config.ml index 65c45d39ca..c897663d36 100644 --- a/compiler/lib/config.ml +++ b/compiler/lib/config.ml @@ -93,7 +93,7 @@ module Flag = struct let safe_string = o ~name:"safestring" ~default:true - let use_js_string = o ~name:"use-js-string" ~default:true + let use_js_string = o ~name:"use-js-string" ~default:false let check_magic = o ~name:"check-magic-number" ~default:true diff --git a/compiler/lib/eval.ml b/compiler/lib/eval.ml index 2954158960..c9ef7584fb 100644 --- a/compiler/lib/eval.ml +++ b/compiler/lib/eval.ml @@ -298,6 +298,17 @@ let eval_prim ~target x = | "caml_nativeint_compare", [ NativeInt i; NativeInt j ] -> Some (Int (Targetint.of_int_exn (Int32.compare i j))) | "caml_nativeint_to_int", [ Int32 i ] -> Some (Int (Targetint.of_int32_truncate i)) + | "caml_checked_int32_to_int", [ Int32 i ] + when Int32.equal i (Targetint.to_int32 (Targetint.of_int32_truncate i)) -> + Some (Int (Targetint.of_int32_truncate i)) + | "caml_checked_nativeint_to_int", [ Int32 i ] + when Int32.equal i (Targetint.to_int32 (Targetint.of_int32_truncate i)) -> + Some (Int (Targetint.of_int32_truncate i)) + | "caml_checked_int64_to_int", [ Int64 i ] + when let j = Int64.to_int32 i in + Int64.equal i (Int64.of_int32 j) + && Int32.equal j (Targetint.to_int32 (Targetint.of_int32_truncate j)) -> + Some (Int (Targetint.of_int32_truncate (Int64.to_int32 i))) | "caml_nativeint_of_int", [ Int i ] -> nativeint (Targetint.to_int32 i) (* int64 *) | "caml_int64_bits_of_float", [ Float f ] -> int64 f @@ -475,9 +486,13 @@ let constant_js_equal a b = | Int i, Int j -> Some (Targetint.equal i j) | Float a, Float b -> Some (Float.ieee_equal (Int64.float_of_bits a) (Int64.float_of_bits b)) + | Float32 a, Float32 b -> + Some (Float.ieee_equal (Int64.float_of_bits a) (Int64.float_of_bits b)) + | Float32 _, Float _ | Float _, Float32 _ -> None | NativeString a, NativeString b -> Some (Native_string.equal a b) | String a, String b when Config.Flag.use_js_string () -> Some (String.equal a b) - | Int _, Float _ | Float _, Int _ -> None + | Null_, Null_ -> Some true + | Int _, (Float _ | Float32 _) | (Float _ | Float32 _), Int _ -> None (* All other values may be distinct objects and thus different by [caml_js_equals]. *) | String _, _ | _, String _ @@ -492,22 +507,26 @@ let constant_js_equal a b = | NativeInt _, _ | _, NativeInt _ | Tuple _, _ - | _, Tuple _ -> None + | _, Tuple _ + | Null_, _ + | _, Null_ -> None (* [eval_prim] does not distinguish the two constants *) let constant_equal a b = match a, b with | Int i, Int j -> Targetint.equal i j | Float a, Float b -> Int64.equal a b + | Float32 a, Float32 b -> Int64.equal a b | NativeString a, NativeString b -> Native_string.equal a b | String a, String b -> String.equal a b | Int32 a, Int32 b -> Int32.equal a b | NativeInt a, NativeInt b -> Int32.equal a b | Int64 a, Int64 b -> Int64.equal a b + | Null_, Null_ -> true (* We don't need to compare other constants, so let's just return false. *) | Tuple _, Tuple _ -> false | Float_array _, Float_array _ -> false - | (Int _ | Float _ | Int64 _ | Int32 _ | NativeInt _), _ -> false + | (Int _ | Float _ | Float32 _ | Int64 _ | Int32 _ | NativeInt _ | Null_), _ -> false | (String _ | NativeString _), _ -> false | (Float_array _ | Tuple _), _ -> false @@ -712,11 +731,13 @@ let the_cond_of info x = (fun x -> match Flow.Info.def info x with | Some (Constant (Int x)) -> if Targetint.is_zero x then Zero else Non_zero + | Some (Constant Null_) -> Zero | Some (Constant ( Int32 _ | NativeInt _ | Float _ + | Float32 _ | Tuple _ | String _ | NativeString _ diff --git a/compiler/lib/flow.ml b/compiler/lib/flow.ml index 13de7ffb74..40c857bced 100644 --- a/compiler/lib/flow.ml +++ b/compiler/lib/flow.ml @@ -54,8 +54,9 @@ module Info = struct let possibly_mutable t x = Code.Var.ISet.mem t.info_possibly_mutable x let update_def { info_defs; _ } x exp = + (* [Specialize_js] can introduce fresh variables *) let idx = Code.Var.idx x in - info_defs.(idx) <- Expr exp + if idx < Array.length info_defs then info_defs.(idx) <- Expr exp end let undefined = Phi Var.Set.empty @@ -338,10 +339,11 @@ let get_approx top join x = - let s = Var.Tbl.get info_known_origins x in - if Var.Tbl.get info_maybe_unknown x + (* [Specialize_js] can introduce fresh variables *) + if Var.idx x >= Var.Tbl.length info_known_origins || Var.Tbl.get info_maybe_unknown x then top else + let s = Var.Tbl.get info_known_origins x in match Var.Set.cardinal s with | 0 -> top | 1 -> f (Var.Set.choose s) diff --git a/compiler/lib/generate.ml b/compiler/lib/generate.ml index bfbd93c5b9..6b755870cb 100644 --- a/compiler/lib/generate.ml +++ b/compiler/lib/generate.ml @@ -479,6 +479,7 @@ let rec constant_rec ~ctx x level instrs = | Byte x -> Share.get_byte_string str_js_byte x ctx.Ctx.share, instrs | Utf (Utf8 x) -> Share.get_utf_string str_js_utf8 x ctx.Ctx.share, instrs) | Float f -> float_const f, instrs + | Float32 f -> float_const f, instrs | Float_array a -> ( Mlvalue.Array.make ~tag:Obj.double_array_tag @@ -536,6 +537,7 @@ let rec constant_rec ~ctx x level instrs = Mlvalue.Block.make ~tag ~args:l, instrs) | Int i -> targetint i, instrs | Int32 i | NativeInt i -> targetint (Targetint.of_int32_exn i), instrs + | Null_ -> s_var "null", instrs let constant ~ctx x level = let expr, instr = constant_rec ~ctx x level [] in @@ -1257,6 +1259,8 @@ let _ = [ "caml_array_unsafe_get" ; "caml_array_unsafe_get_float" ; "caml_floatarray_unsafe_get" + ; "caml_array_unsafe_get_indexed_by_int32" + ; "caml_array_unsafe_get_indexed_by_nativeint" ] `Mutable (fun cx cy _ -> Mlvalue.Array.field cx cy); @@ -1273,6 +1277,10 @@ let _ = ] `Pure (fun cx _ -> cx); + register_un_prims + [ "caml_checked_nativeint_to_int"; "caml_checked_int32_to_int" ] + `Mutator + (fun cx _ -> cx); register_bin_prims [ "%int_add"; "caml_int32_add"; "caml_nativeint_add" ] `Pure @@ -1334,6 +1342,14 @@ let _ = register_bin_prim "caml_le_float" `Pure (fun cx cy _ -> bool (J.EBin (J.Le, cx, cy))); register_bin_prim "caml_gt_float" `Pure (fun cx cy _ -> bool (J.EBin (J.Lt, cy, cx))); register_bin_prim "caml_lt_float" `Pure (fun cx cy _ -> bool (J.EBin (J.Lt, cx, cy))); + register_bin_prim "caml_eq_float32" `Pure (fun cx cy _ -> + bool (J.EBin (J.EqEq, cx, cy))); + register_bin_prim "caml_neq_float32" `Pure (fun cx cy _ -> + bool (J.EBin (J.NotEq, cx, cy))); + register_bin_prim "caml_ge_float32" `Pure (fun cx cy _ -> bool (J.EBin (J.Le, cy, cx))); + register_bin_prim "caml_le_float32" `Pure (fun cx cy _ -> bool (J.EBin (J.Le, cx, cy))); + register_bin_prim "caml_gt_float32" `Pure (fun cx cy _ -> bool (J.EBin (J.Lt, cy, cx))); + register_bin_prim "caml_lt_float32" `Pure (fun cx cy _ -> bool (J.EBin (J.Lt, cx, cy))); register_bin_prim "caml_add_float" `Pure (fun cx cy _ -> J.EBin (J.Plus, cx, cy)); register_bin_prim "caml_sub_float" `Pure (fun cx cy _ -> J.EBin (J.Minus, cx, cy)); register_bin_prim "caml_mul_float" `Pure (fun cx cy _ -> J.EBin (J.Mul, cx, cy)); @@ -1345,11 +1361,15 @@ let _ = ; "caml_array_unsafe_set_float" ; "caml_floatarray_unsafe_set" ; "caml_array_unsafe_set_addr" + ; "caml_array_unsafe_set_indexed_by_int32" + ; "caml_array_unsafe_set_indexed_by_nativeint" ] `Mutator (fun cx cy cz _ -> J.EBin (J.Eq, Mlvalue.Array.field cx cy, cz)); - register_un_prims [ "caml_alloc_dummy"; "caml_alloc_dummy_float" ] `Pure (fun _ _ -> - J.array []); + register_un_prims + [ "caml_alloc_dummy"; "caml_alloc_dummy_float"; "caml_alloc_dummy_mixed" ] + `Pure + (fun _ _ -> J.array []); register_un_prims [ "caml_int_of_float" ; "caml_int32_of_float" @@ -1390,7 +1410,8 @@ let _ = bool (J.EBin (J.EqEqEq, cx, cy))); register_bin_prim "caml_js_instanceof" `Mutator (fun cx cy _ -> bool (J.EBin (J.InstanceOf, cx, cy))); - register_un_prim "caml_js_typeof" `Mutator (fun cx _ -> J.EUn (J.Typeof, cx)) + register_un_prim "caml_js_typeof" `Mutator (fun cx _ -> J.EUn (J.Typeof, cx)); + register_un_prim "caml_is_null" `Pure (fun cx _ -> J.EBin (EqEqEq, cx, s_var "null")) (****) (* when raising ocaml exception and [improved_stacktrace] is enabled, diff --git a/compiler/lib/instr.ml b/compiler/lib/instr.ml index 83528cc032..ecb2fdd4aa 100644 --- a/compiler/lib/instr.ml +++ b/compiler/lib/instr.ml @@ -173,6 +173,7 @@ type t = | RESUME | RESUMETERM | REPERFORMTERM + | MAKE_FAUX_MIXEDBLOCK | FIRST_UNIMPLEMENTED_OP let equal (a : t) b = Poly.equal a b @@ -360,6 +361,7 @@ let ops = ; RESUME, if_v500 KNullaryCall, "RESUME" ; RESUMETERM, if_v500 (KStop 1), "RESUMETERM" ; REPERFORMTERM, if_v500 (KStop 1), "REPERFORMTERM" + ; MAKE_FAUX_MIXEDBLOCK, KBinary, "MAKE_FAUX_MIXEDBLOCK" ; FIRST_UNIMPLEMENTED_OP, K_will_not_happen, "FIRST_UNIMPLEMENTED_OP" |] in diff --git a/compiler/lib/instr.mli b/compiler/lib/instr.mli index 43fe2cbfb8..69a5fbf3a6 100644 --- a/compiler/lib/instr.mli +++ b/compiler/lib/instr.mli @@ -172,6 +172,7 @@ type t = | RESUME | RESUMETERM | REPERFORMTERM + | MAKE_FAUX_MIXEDBLOCK | FIRST_UNIMPLEMENTED_OP type kind = diff --git a/compiler/lib/ocaml_compiler.ml b/compiler/lib/ocaml_compiler.ml index 0c4ed37a34..fb7dd36037 100644 --- a/compiler/lib/ocaml_compiler.ml +++ b/compiler/lib/ocaml_compiler.ml @@ -20,22 +20,46 @@ open! Stdlib let rec constant_of_const c : Code.constant = let open Lambda in - let open Asttypes in + let open! Asttypes in match c with | Const_base (Const_int i) -> Int (Targetint.of_int_warning_on_overflow i) + | ((Const_base + ( Const_int8 i + | Const_int16 i + | Const_untagged_int i + | Const_untagged_int8 i + | Const_untagged_int16 i )) + [@if oxcaml]) -> Int (Targetint.of_int_warning_on_overflow i) | Const_base (Const_char c) -> Int (Targetint.of_int_exn (Char.code c)) + | ((Const_base (Const_untagged_char c)) [@if oxcaml]) -> + Int (Targetint.of_int_warning_on_overflow (Char.code c)) | Const_base (Const_string (s, _, _)) -> String s | Const_base (Const_float s) -> Float (Int64.bits_of_float (float_of_string s)) + | ((Const_base (Const_unboxed_float s)) [@if oxcaml]) -> + Float (Int64.bits_of_float (float_of_string s)) + | ((Const_base (Const_float32 s | Const_unboxed_float32 s)) [@if oxcaml]) -> + Float32 (Int64.bits_of_float (Float32.of_string s |> Float32.to_float)) | Const_base (Const_int32 i) -> Int32 i + | ((Const_base (Const_unboxed_int32 i)) [@if oxcaml]) -> Int32 i | Const_base (Const_int64 i) -> Int64 i + | ((Const_base (Const_unboxed_int64 i)) [@if oxcaml]) -> Int64 i | Const_base (Const_nativeint i) -> NativeInt (Int32.of_nativeint_warning_on_overflow i) + | ((Const_base (Const_unboxed_nativeint i)) [@if oxcaml]) -> + NativeInt (Int32.of_nativeint_warning_on_overflow i) | Const_immstring s -> String s | Const_float_array sl -> let l = List.map ~f:(fun f -> Int64.bits_of_float (float_of_string f)) sl in Float_array (Array.of_list l) + | ((Const_float_block sl) [@if oxcaml]) -> + let l = List.map ~f:(fun f -> Int64.bits_of_float (float_of_string f)) sl in + Float_array (Array.of_list l) | Const_block (tag, l) -> let l = Array.of_list (List.map l ~f:constant_of_const) in Tuple (tag, l, Unknown) + | ((Const_mixed_block (tag, _, l)) [@if oxcaml]) -> + let l = Array.of_list (List.map l ~f:constant_of_const) in + Tuple (tag, l, Unknown) + | (Const_null [@if oxcaml]) -> Null_ type module_or_not = | Module @@ -47,9 +71,15 @@ let rec is_module_in_summary deep ident' summary = (* Unknown *) | Env.Env_empty -> deep, Unknown (* Module *) - | Env.Env_module (summary, ident, _, _) - | Env.Env_functor_arg (summary, ident) - | Env.Env_persistent (summary, ident) -> + | Env.Env_functor_arg (summary, ident) | Env.Env_persistent (summary, ident) -> + if Ident.same ident ident' + then deep, Module + else is_module_in_summary (deep + 1) ident' summary + | ((Env.Env_module (summary, ident, _, _)) [@if not oxcaml]) -> + if Ident.same ident ident' + then deep, Module + else is_module_in_summary (deep + 1) ident' summary + | ((Env.Env_module (summary, ident, _, _, _, _)) [@if oxcaml]) -> if Ident.same ident ident' then deep, Module else is_module_in_summary (deep + 1) ident' summary @@ -59,12 +89,17 @@ let rec is_module_in_summary deep ident' summary = then deep, Not_module else is_module_in_summary (deep + 1) ident' summary (* Lowercase ident *) - | Env.Env_value (summary, ident, _) | Env.Env_type (summary, ident, _) | Env.Env_class (summary, ident, _) | Env.Env_cltype (summary, ident, _) -> ignore (ident : Ident.t); is_module_in_summary (deep + 1) ident' summary + | ((Env.Env_value (summary, ident, _)) [@if not oxcaml]) -> + ignore (ident : Ident.t); + is_module_in_summary (deep + 1) ident' summary + | ((Env.Env_value (summary, ident, _, _)) [@if oxcaml]) -> + ignore (ident : Ident.t); + is_module_in_summary (deep + 1) ident' summary (* Other, no ident *) | Env.Env_open (summary, _) | Env.Env_constraints (summary, _) @@ -77,6 +112,17 @@ let is_module_in_summary ident summary = let _deep, b = is_module_in_summary 0 ident summary in b +module Compilation_unit = struct + type t = Cmo_format.compunit + + let name_as_string (Compunit x : t) = x + + let of_string x : t = Compunit x +end +[@@if (not oxcaml) && ocaml_version >= (5, 2, 0)] + +module Compilation_unit = Compilation_unit [@@if oxcaml] + module Symtable = struct (* Copied from ocaml/bytecomp/symtable.ml *) module Num_tbl (M : Map.S) = struct @@ -116,18 +162,22 @@ module Symtable = struct | Glob_compunit cu -> cu | Glob_predef exn -> exn + let is_global = Ident.global [@@if not oxcaml] + + let is_global = Ident.is_global [@@if oxcaml] + let of_ident id = let name = Ident.name id in if Ident.is_predef id then Some (Glob_predef name) - else if Ident.global id + else if is_global id then Some (Glob_compunit name) else None let to_ident = function | Glob_compunit x -> Ident.create_persistent x | Glob_predef x -> Ident.create_predef x - [@@ocaml.warning "-32"] + [@@if ocaml_version < (5, 2, 0)] end module GlobalMap = struct @@ -163,11 +213,13 @@ module Symtable = struct include GlobalMap let to_local = function - | Symtable.Global.Glob_compunit (Compunit x) -> Global.Glob_compunit x + | Symtable.Global.Glob_compunit x -> + Global.Glob_compunit (Compilation_unit.name_as_string x) | Symtable.Global.Glob_predef (Predef_exn x) -> Global.Glob_predef x let of_local = function - | Global.Glob_compunit x -> Symtable.Global.Glob_compunit (Compunit x) + | Global.Glob_compunit x -> + Symtable.Global.Glob_compunit (Compilation_unit.of_string x) | Global.Glob_predef x -> Symtable.Global.Glob_predef (Predef_exn x) let filter (p : Global.t -> bool) (gmap : t) = @@ -194,10 +246,12 @@ module Symtable = struct let reloc_set_of_string name = Cmo_format.Reloc_setglobal (Ident.create_persistent name) [@@if ocaml_version < (5, 2, 0)] - let reloc_get_of_string name = Cmo_format.Reloc_getcompunit (Compunit name) + let reloc_get_of_string name = + Cmo_format.Reloc_getcompunit (Compilation_unit.of_string name) [@@if ocaml_version >= (5, 2, 0)] - let reloc_set_of_string name = Cmo_format.Reloc_setcompunit (Compunit name) + let reloc_set_of_string name = + Cmo_format.Reloc_setcompunit (Compilation_unit.of_string name) [@@if ocaml_version >= (5, 2, 0)] let reloc_ident name = @@ -210,7 +264,7 @@ module Symtable = struct let get i = Char.code (Bytes.get buf i) in let n = get 0 + (get 1 lsl 8) + (get 2 lsl 16) + (get 3 lsl 24) in n - [@@if ocaml_version < (5, 2, 0)] + [@@if oxcaml || ocaml_version < (5, 2, 0)] let reloc_ident name = let buf = Bigarray.(Array1.create char c_layout 4) in @@ -222,7 +276,7 @@ module Symtable = struct let get i = Char.code (Bigarray.Array1.get buf i) in let n = get 0 + (get 1 lsl 8) + (get 2 lsl 16) + (get 3 lsl 24) in n - [@@if ocaml_version >= (5, 2, 0)] + [@@if (not oxcaml) && ocaml_version >= (5, 2, 0)] let current_state () : GlobalMap.t = let x : Symtable.global_map = Symtable.current_state () in @@ -247,6 +301,46 @@ module Symtable = struct [@@if ocaml_version >= (5, 2)] end +module Import_info = struct + type t = string * Digest.t option + + type table = t list + + let to_list l = l + + let of_list l = l + + let name (n, _) = n + + let crc (_, c) = c +end +[@@if not oxcaml] + +module Import_info = struct + type t = Import_info.t + + type table = t array + + let to_list = Array.to_list + + let of_list = Array.of_list + + let name i = Import_info.name i |> Compilation_unit.Name.to_string + + let crc = Import_info.crc +end +[@@if oxcaml] + +module Compilation_unit_descr = struct + type t = Cmo_format.compilation_unit +end +[@@if not oxcaml] + +module Compilation_unit_descr = struct + type t = Cmo_format.compilation_unit_descr +end +[@@if oxcaml] + module Cmo_format = struct type t = Cmo_format.compilation_unit @@ -284,3 +378,27 @@ module Cmo_format = struct let force_link (t : t) = t.cu_force_link end +[@@if not oxcaml] + +module Cmo_format = struct + type t = Cmo_format.compilation_unit_descr + + let name (t : t) = Compilation_unit.name_as_string t.cu_name + + let requires (t : t) = + List.map t.cu_required_compunits ~f:Compilation_unit.name_as_string + + let provides (t : t) = + List.filter_map t.cu_reloc ~f:(fun ((reloc : Cmo_format.reloc_info), _) -> + match reloc with + | Reloc_setcompunit u -> Some (Compilation_unit.name_as_string u) + | Reloc_getcompunit _ | Reloc_getpredef _ | Reloc_literal _ | Reloc_primitive _ -> + None) + + let primitives (t : t) = t.cu_primitives + + let imports (t : t) = Array.to_list t.cu_imports + + let force_link (t : t) = t.cu_force_link +end +[@@if oxcaml] diff --git a/compiler/lib/ocaml_compiler.mli b/compiler/lib/ocaml_compiler.mli index 0c4c31dd8a..f23031d69a 100644 --- a/compiler/lib/ocaml_compiler.mli +++ b/compiler/lib/ocaml_compiler.mli @@ -59,8 +59,46 @@ module Symtable : sig val all_primitives : unit -> string list end -module Cmo_format : sig +module Import_info : sig + type t + + type table + + val to_list : table -> t list + + val of_list : t list -> table + + val name : t -> string + + val crc : t -> Digest.t option +end + +module Compilation_unit : sig + type t = Cmo_format.compunit + + val name_as_string : t -> string +end +[@@if (not oxcaml) && ocaml_version >= (5, 2, 0)] + +module Compilation_unit : sig + type t = Compilation_unit.t + + val name_as_string : t -> string +end +[@@if oxcaml] + +module Compilation_unit_descr : sig type t = Cmo_format.compilation_unit +end +[@@if not oxcaml] + +module Compilation_unit_descr : sig + type t = Cmo_format.compilation_unit_descr +end +[@@if oxcaml] + +module Cmo_format : sig + type t = Compilation_unit_descr.t val name : t -> string @@ -72,5 +110,5 @@ module Cmo_format : sig val force_link : t -> bool - val imports : t -> (string * string option) list + val imports : t -> Import_info.t list end diff --git a/compiler/lib/parse_bytecode.ml b/compiler/lib/parse_bytecode.ml index 4f089e7f61..7575596977 100644 --- a/compiler/lib/parse_bytecode.ml +++ b/compiler/lib/parse_bytecode.ml @@ -70,11 +70,15 @@ module Debug : sig -> unit val read : - t -> crcs:(string * string option) list -> includes:string list -> in_channel -> unit + t + -> crcs:Ocaml_compiler.Import_info.t list + -> includes:string list + -> in_channel + -> unit val read_event_list : t - -> crcs:(string * string option) list + -> crcs:Ocaml_compiler.Import_info.t list -> includes:string list -> orig:int -> in_channel @@ -222,7 +226,11 @@ end = struct fun debug ~crcs ~includes ~orig ic -> let crcs = let t = String.Hashtbl.create 17 in - List.iter crcs ~f:(fun (m, crc) -> String.Hashtbl.add t m crc); + List.iter crcs ~f:(fun info -> + String.Hashtbl.add + t + (Ocaml_compiler.Import_info.name info) + (Ocaml_compiler.Import_info.crc info)); t in let evl : debug_event list = input_value ic in @@ -471,8 +479,18 @@ end = struct let ident_native = ident_of_custom (Obj.repr 0n) + let ident_f32 = ident_of_custom (Obj.repr 0.s) [@@if oxcaml] + + external is_null : Obj.t -> bool = "%is_null" [@@if oxcaml] + + let is_null obj = is_null (Sys.opaque_identity obj) [@@if oxcaml] + + let is_null _ = false [@@if not oxcaml] + let rec parse x = - if Obj.is_block x + if is_null x + then Null_ + else if Obj.is_block x then let tag = Obj.tag x in if tag = Obj.string_tag @@ -487,6 +505,8 @@ end = struct else if tag = Obj.custom_tag then match ident_of_custom x with + | ((Some name) [@if oxcaml]) when same_ident name ident_f32 -> + Float32 (Int64.bits_of_float ((Obj.magic x : float32) |> Float32.to_float)) | Some name when same_ident name ident_32 -> let i : int32 = Obj.magic x in Int32 i @@ -512,6 +532,7 @@ end = struct match c with | String _ | NativeString _ -> false | Float _ -> true + | Float32 _ -> true | Float_array _ -> false | Int64 _ -> false | Tuple _ -> false @@ -520,6 +541,7 @@ end = struct match target with | `JavaScript -> true | `Wasm -> false) + | Null_ -> true end let const32 i = Constant (Int (Targetint.of_int32_exn i)) @@ -1447,7 +1469,7 @@ and compile infos pc state (instrs : instr list) = if debug_parser () then Format.printf "%a = ATOM(%d)@." Var.print x i; let imm = is_immutable instr infos pc in compile infos (pc + 2) state (Let (x, Block (i, [||], Unknown, imm)) :: instrs) - | MAKEBLOCK -> + | MAKE_FAUX_MIXEDBLOCK | MAKEBLOCK -> let size = getu code (pc + 1) in let tag = getu code (pc + 2) in let state = State.push state in @@ -1873,6 +1895,8 @@ and compile infos pc state (instrs : instr list) = | "%identity", _ -> true | "caml_ensure_stack_capacity", _ -> true | "caml_process_pending_actions_with_root", _ -> true + | "caml_array_of_iarray", _ -> true + | "caml_iarray_of_array", _ -> true | "caml_make_array", `JavaScript -> true | "caml_array_of_uniform_array", `JavaScript -> true | "caml_js_from_float", `JavaScript -> true @@ -2594,7 +2618,7 @@ module Toc : sig val read_data : t -> in_channel -> Obj.t array - val read_crcs : t -> in_channel -> (string * Digest.t option) list + val read_crcs : t -> in_channel -> Ocaml_compiler.Import_info.t list val read_prim : t -> in_channel -> string @@ -2643,8 +2667,8 @@ end = struct let read_crcs toc ic = ignore (seek_section toc ic "CRCS"); - let orig_crcs : (string * Digest.t option) list = input_value ic in - orig_crcs + let orig_crcs : Ocaml_compiler.Import_info.table = input_value ic in + Ocaml_compiler.Import_info.to_list orig_crcs let read_prim toc ic = let prim_size = seek_section toc ic "PRIM" in @@ -2659,7 +2683,7 @@ let read_primitives toc ic = type bytesections = { symb : Ocaml_compiler.Symtable.GlobalMap.t - ; crcs : (string * Digest.t option) list + ; crcs : Ocaml_compiler.Import_info.table ; prim : string list ; dlpt : string list } @@ -2697,7 +2721,9 @@ let from_exe in String.Hashtbl.mem keeps in - let crcs = List.filter ~f:(fun (unit, _crc) -> keep unit) orig_crcs in + let crcs = + List.filter ~f:(fun info -> keep (Ocaml_compiler.Import_info.name info)) orig_crcs + in let symbols = Ocaml_compiler.Symtable.GlobalMap.filter (function @@ -2755,7 +2781,13 @@ let from_exe |> Array.of_list in (* Include linking information *) - let sections = { symb = symbols; crcs; prim = primitives; dlpt = [] } in + let sections = + { symb = symbols + ; crcs = Ocaml_compiler.Import_info.of_list crcs + ; prim = primitives + ; dlpt = [] + } + in let gdata = Var.fresh () in let need_gdata = ref false in let aliases = Primitive.aliases () in @@ -2917,9 +2949,10 @@ module Reloc = struct } let constant_of_const x = Ocaml_compiler.constant_of_const x - [@@if ocaml_version < (5, 1, 0)] + [@@if oxcaml || ocaml_version < (5, 1, 0)] - let constant_of_const x = Constants.parse x [@@if ocaml_version >= (5, 1, 0)] + let constant_of_const x = Constants.parse x + [@@if (not oxcaml) && ocaml_version >= (5, 1, 0)] (* We currently rely on constants to be relocated before globals. *) let step1 t compunit code = @@ -2964,12 +2997,12 @@ module Reloc = struct patch (slot_for_global (Ident.name id)) | ((Reloc_setglobal id) [@if ocaml_version < (5, 2, 0)]) -> patch (slot_for_global (Ident.name id)) - | ((Reloc_getcompunit (Compunit id)) [@if ocaml_version >= (5, 2, 0)]) -> - patch (slot_for_global id) + | ((Reloc_getcompunit id) [@if ocaml_version >= (5, 2, 0)]) -> + patch (slot_for_global (Ocaml_compiler.Compilation_unit.name_as_string id)) | ((Reloc_getpredef (Predef_exn id)) [@if ocaml_version >= (5, 2, 0)]) -> patch (slot_for_global id) - | ((Reloc_setcompunit (Compunit id)) [@if ocaml_version >= (5, 2, 0)]) -> - patch (slot_for_global id) + | ((Reloc_setcompunit id) [@if ocaml_version >= (5, 2, 0)]) -> + patch (slot_for_global (Ocaml_compiler.Compilation_unit.name_as_string id)) | _ -> ()) let primitives t = @@ -3098,7 +3131,7 @@ let from_channel ic = then raise Magic_number.(Bad_magic_version magic); let compunit_pos = input_binary_int ic in seek_in ic compunit_pos; - let compunit : Cmo_format.compilation_unit = input_value ic in + let compunit : Ocaml_compiler.Cmo_format.t = input_value ic in `Cmo compunit | `Cma -> if @@ -3193,7 +3226,13 @@ let link_info ~symbols ~primitives ~crcs = let body = [] in let body = (* Include linking information *) - let sections = { symb = symbols; crcs; prim = primitives; dlpt = [] } in + let sections = + { symb = symbols + ; crcs = Ocaml_compiler.Import_info.of_list crcs + ; prim = primitives + ; dlpt = [] + } + in let aliases = Primitive.aliases () in let infos = [ "sections", Constants.parse (Obj.repr sections) diff --git a/compiler/lib/parse_bytecode.mli b/compiler/lib/parse_bytecode.mli index 5eaa9c396f..b2ff03e5d3 100644 --- a/compiler/lib/parse_bytecode.mli +++ b/compiler/lib/parse_bytecode.mli @@ -58,7 +58,7 @@ val from_cmo : ?includes:string list -> ?include_cmis:bool -> ?debug:bool - -> Cmo_format.compilation_unit + -> Ocaml_compiler.Cmo_format.t -> in_channel -> one @@ -72,7 +72,7 @@ val from_cma : val from_channel : in_channel - -> [ `Cmo of Cmo_format.compilation_unit | `Cma of Cmo_format.library | `Exe ] + -> [ `Cmo of Ocaml_compiler.Cmo_format.t | `Cma of Cmo_format.library | `Exe ] val from_string : prims:string array -> debug:Instruct.debug_event list array -> string -> Code.program @@ -82,5 +82,5 @@ val predefined_exceptions : unit -> Code.program * Unit_info.t val link_info : symbols:Ocaml_compiler.Symtable.GlobalMap.t -> primitives:StringSet.t - -> crcs:(string * Digest.t option) list + -> crcs:Ocaml_compiler.Import_info.t list -> Code.program diff --git a/compiler/lib/specialize_js.ml b/compiler/lib/specialize_js.ml index dda64b1063..133500f6fb 100644 --- a/compiler/lib/specialize_js.ml +++ b/compiler/lib/specialize_js.ml @@ -283,6 +283,52 @@ let idx_equal (v1, c1) (v2, c2) = | `Var a, `Var b -> Code.Var.equal a b | `Cst _, `Var _ | `Var _, `Cst _ -> false +let indexing_primitives l = + let h = String.Hashtbl.create 16 in + List.iter l ~f:(fun prim -> + List.iter [ "int32"; "nativeint"; "int64" ] ~f:(fun int -> + String.Hashtbl.add + h + (prim ^ "_indexed_by_" ^ int) + ("caml_checked_" ^ int ^ "_to_int", prim))); + h + +let getters = + indexing_primitives + [ "caml_array_get" + ; "caml_string_get16" + ; "caml_string_get32" + ; "caml_string_get64" + ; "caml_string_getf32" + ; "caml_bytes_get16" + ; "caml_bytes_get32" + ; "caml_bytes_get64" + ; "caml_bytes_getf32" + ; "caml_ba_uint8_get16" + ; "caml_ba_uint8_get32" + ; "caml_ba_uint8_get64" + ; "caml_ba_uint8_getf32" + ] + +let setters = + indexing_primitives + [ "caml_array_set" + ; "caml_bytes_set16" + ; "caml_bytes_set32" + ; "caml_bytes_set64" + ; "caml_bytes_setf32" + ; "caml_ba_uint8_set16" + ; "caml_ba_uint8_set32" + ; "caml_ba_uint8_set64" + ; "caml_ba_uint8_setf32" + ] + +let make_vect x y constant acc = + let c = Var.fresh () in + Let (x, Prim (Extern "caml_make_vect", [ y; Pv c ])) + :: Let (c, Constant constant) + :: acc + let specialize_instrs ~target opt_count info l = let rec aux info checks l acc = match l with @@ -293,6 +339,18 @@ let specialize_instrs ~target opt_count info l = the array access. The bound checking function returns the array, which allows to produce more compact code. *) match i with + | Let (x, Prim (Extern prim, [ y; z ])) when String.Hashtbl.mem getters prim -> + let conv, access = String.Hashtbl.find getters prim in + let z' = Code.Var.fresh () in + let r = + Let (z', Prim (Extern conv, [ z ])) + (* The recursive call to [aux] will optimize + [caml_array_get] into a nominally "unsafe" (but + guarded) access. *) + :: Let (x, Prim (Extern access, [ y; Pv z' ])) + :: r + in + aux info checks r acc | Let ( x , Prim @@ -339,6 +397,18 @@ let specialize_instrs ~target opt_count info l = incr opt_count; let acc = instr y' :: Let (y', Prim (Extern check, [ Pv y; z ])) :: acc in aux info ((y, idx) :: checks) r acc + | Let (x, Prim (Extern prim, [ y; z; w ])) when String.Hashtbl.mem setters prim -> + let conv, setter = String.Hashtbl.find setters prim in + let z' = Code.Var.fresh () in + let r = + Let (z', Prim (Extern conv, [ z ])) + (* The recursive call to [aux] will optimize + [caml_array_set] into a nominally "unsafe" (but + guarded) access. *) + :: Let (x, Prim (Extern setter, [ y; Pv z'; w ])) + :: r + in + aux info checks r acc | Let ( x , Prim @@ -385,6 +455,14 @@ let specialize_instrs ~target opt_count info l = let acc = instr y' :: Let (y', Prim (Extern check, [ Pv y; z ])) :: acc in incr opt_count; aux info ((y, idx) :: checks) r acc + | Let (x, Prim (Extern "caml_make_unboxed_int32_vect_bytecode", [ y ])) -> + aux info checks r (make_vect x y (Int32 0l) acc) + | Let (x, Prim (Extern "caml_make_unboxed_int64_vect_bytecode", [ y ])) -> + aux info checks r (make_vect x y (Int64 0L) acc) + | Let (x, Prim (Extern "caml_make_unboxed_nativeint_vect_bytecode", [ y ])) -> + aux info checks r (make_vect x y (NativeInt 0l) acc) + | Let (x, Prim (Extern "caml_make_unboxed_float32_vect_bytecode", [ y ])) -> + aux info checks r (make_vect x y (Float32 0L) acc) | _ -> let i = specialize_instr ~target opt_count info i in aux info checks r (i :: acc)) diff --git a/compiler/lib/stdlib.ml b/compiler/lib/stdlib.ml index e0d85f7e31..84ea904363 100644 --- a/compiler/lib/stdlib.ml +++ b/compiler/lib/stdlib.ml @@ -356,6 +356,30 @@ module Float = struct external ( >= ) : t -> t -> bool = "%greaterequal" end +module Float32 = struct + type t + + let of_float _ = assert false + + let to_float _ = assert false + + let of_string _ = assert false +end +[@@if not oxcaml] + +module Float32 = struct + type t = float32 + + external of_float : float -> t = "%float32offloat" + + external to_float : t -> float = "%floatoffloat32" + + (* In javascript/wasm, we define float32 parsing as rounding the 64-bit result. + This is not equivalent to native code, which parses to 32 bits directly. *) + let of_string s = float_of_string s |> of_float +end +[@@if oxcaml] + module Bool = struct include Bool @@ -1204,3 +1228,7 @@ module Lexing = struct Printf.sprintf "File \"%s\", line %d, characters %d-%d:\n" file line char1 char2 (* use [char1 + 1] and [char2 + 1] if *not* using Caml mode *) end + +let with_async_exns = Sys.with_async_exns [@@if oxcaml] + +let with_async_exns f = f () [@@if not oxcaml] diff --git a/compiler/lib/unit_info.ml b/compiler/lib/unit_info.ml index 190ba2ea71..ba32d7cdfb 100644 --- a/compiler/lib/unit_info.ml +++ b/compiler/lib/unit_info.ml @@ -46,7 +46,7 @@ let of_primitives ~aliases l = ; effects_without_cps = false } -let of_cmo (cmo : Cmo_format.compilation_unit) = +let of_cmo (cmo : Ocaml_compiler.Cmo_format.t) = let open Ocaml_compiler in (* A packed librariy register global for packed modules. *) let provides = StringSet.of_list (Cmo_format.name cmo :: Cmo_format.provides cmo) in diff --git a/compiler/lib/unit_info.mli b/compiler/lib/unit_info.mli index dd616fda91..cb7f2e07a6 100644 --- a/compiler/lib/unit_info.mli +++ b/compiler/lib/unit_info.mli @@ -28,7 +28,7 @@ type t = ; effects_without_cps : bool } -val of_cmo : Cmo_format.compilation_unit -> t +val of_cmo : Ocaml_compiler.Cmo_format.t -> t val of_primitives : aliases:(string * string) list -> string list -> t diff --git a/compiler/ppx/ppx_optcomp_light.ml b/compiler/ppx/ppx_optcomp_light.ml index b4634230cc..aeffa528b3 100644 --- a/compiler/ppx/ppx_optcomp_light.ml +++ b/compiler/ppx/ppx_optcomp_light.ml @@ -24,7 +24,8 @@ ]} on module (Pstr_module), toplevel bindings (Pstr_value, Pstr_primitive) - and pattern in case (pc_lhs) + pattern in case (pc_lhs) + and module in signature (Psig_module) *) open StdLabels @@ -38,6 +39,12 @@ module Version : sig val compare : t -> t -> int val current : t + + type extra_prefix = + | Plus + | Tilde + + val extra : (extra_prefix * string) option end = struct type t = int list @@ -86,6 +93,23 @@ end = struct match compint x y with | 0 -> compare xs ys | n -> n) + + type extra_prefix = + | Plus + | Tilde + + type release_info = { extra : (extra_prefix * string) option } + + let extra = + let ocaml_release = { extra = None } in + ignore ocaml_release.extra; + match + let open! Sys in + ocaml_release.extra + with + | None -> None + | Some (Plus, tag) -> Some (Plus, tag) + | Some (Tilde, tag) -> Some (Tilde, tag) end exception Invalid of Location.t @@ -148,67 +172,84 @@ let keep loc (attrs : attributes) = | [] -> true | _ -> ( try - let keep_one { attr_payload; attr_loc; _ } = + let keep_one ({ attr_payload; attr_loc; _ } as attr) = + Ppxlib.Attribute.mark_as_handled_manually attr; let e = match attr_payload with | PStr [ { pstr_desc = Pstr_eval (e, []); _ } ] -> e | _ -> raise (Invalid attr_loc) in - let loc = e.pexp_loc in - let rec eval = function - | { pexp_desc = Pexp_ident { txt = Lident "ocaml_version"; _ }; _ } -> - Version Version.current - | { pexp_desc = Pexp_ident { txt = Lident "ast_version"; _ }; _ } -> - Int Ppxlib.Selected_ast.version - | { pexp_desc = Pexp_construct ({ txt = Lident "true"; _ }, None); _ } -> - Bool true - | { pexp_desc = Pexp_construct ({ txt = Lident "false"; _ }, None); _ } -> - Bool false - | { pexp_desc = Pexp_constant (Pconst_integer (d, None)); _ } -> - Int (int_of_string d) - | { pexp_desc = Pexp_tuple l; _ } -> Tuple (List.map l ~f:eval) - | { pexp_desc = Pexp_apply (op, [ (Nolabel, a); (Nolabel, b) ]); pexp_loc; _ } - -> ( - let op = get_bin_op op in - let a = eval a in - let b = eval b in - match op with - | LE | GE | LT | GT | NEQ | EQ -> - let comp = - match a, b with - | Version _, _ | _, Version _ -> - Version.compare (version a) (version b) - | Int a, Int b -> compare a b - | _ -> raise (Invalid pexp_loc) - in - let op = - match op with - | LE -> ( <= ) - | GE -> ( >= ) - | LT -> ( < ) - | GT -> ( > ) - | EQ -> ( = ) - | NEQ -> ( <> ) - | _ -> assert false - in - Bool (op comp 0) - | AND -> ( - match a, b with - | Bool a, Bool b -> Bool (a && b) - | _ -> raise (Invalid loc)) - | OR -> ( - match a, b with - | Bool a, Bool b -> Bool (a || b) - | _ -> raise (Invalid loc)) - | NOT -> raise (Invalid loc)) - | { pexp_desc = Pexp_apply (op, [ (Nolabel, a) ]); _ } -> ( - let op = get_un_op op in - let a = eval a in - match op, a with - | NOT, Bool b -> Bool (not b) - | NOT, _ -> raise (Invalid loc) - | _ -> raise (Invalid loc)) - | _ -> raise (Invalid loc) + let rec eval e = + let open Ppxlib.Ast_pattern in + let loc = e.pexp_loc in + match + (parse_res + (pexp_ident (lident (string "ocaml_version")) + >>| (fun () -> Version Version.current) + ||| (pexp_ident (lident (string "ast_version")) + >>| fun () -> Int Ppxlib.Selected_ast.version) + ||| (pexp_ident (lident (string "oxcaml")) + >>| fun () -> + Bool + (match Version.extra with + | Some (Plus, "ox") -> true + | _ -> false)) + ||| (pexp_construct (lident (string "true")) drop >>| fun () -> Bool true) + ||| (pexp_constant (pconst_integer __ none) + >>| fun () d -> Int (int_of_string d)) + ||| (pexp_construct (lident (string "false")) drop + >>| fun () -> Bool false) + ||| (pexp_tuple __ >>| fun () l -> Tuple (List.map l ~f:eval)) + ||| (pexp_apply __ __ + >>| fun () op l -> + match l with + | [ (Nolabel, a); (Nolabel, b) ] -> ( + let op = get_bin_op op in + let a = eval a in + let b = eval b in + match op with + | LE | GE | LT | GT | NEQ | EQ -> + let comp = + match a, b with + | Version _, _ | _, Version _ -> + Version.compare (version a) (version b) + | Int a, Int b -> compare a b + | _ -> raise (Invalid loc) + in + let op = + match op with + | LE -> ( <= ) + | GE -> ( >= ) + | LT -> ( < ) + | GT -> ( > ) + | EQ -> ( = ) + | NEQ -> ( <> ) + | _ -> assert false + in + Bool (op comp 0) + | AND -> ( + match a, b with + | Bool a, Bool b -> Bool (a && b) + | _ -> raise (Invalid loc)) + | OR -> ( + match a, b with + | Bool a, Bool b -> Bool (a || b) + | _ -> raise (Invalid loc)) + | NOT -> raise (Invalid loc)) + | [ (Nolabel, a) ] -> ( + let op = get_un_op op in + let a = eval a in + match op, a with + | NOT, Bool b -> Bool (not b) + | NOT, _ -> raise (Invalid loc) + | _ -> raise (Invalid loc)) + | _ -> raise (Invalid loc)))) + loc + e + () + with + | Ok res -> res + | Error _ -> raise (Invalid loc) in match eval e with | Bool b -> b @@ -251,7 +292,11 @@ let rec filter_pattern = function | None, Some p2 -> Some p2 | Some p1, Some p2 -> Some { p with ppat_desc = Ppat_or (p1, p2) }) | { ppat_attributes; ppat_loc; _ } as p -> - if keep ppat_loc ppat_attributes then Some p else None + if keep ppat_loc ppat_attributes + then Some p + else ( + Ppxlib.Attribute.explicitly_drop#pattern p; + None) let traverse = object @@ -262,13 +307,25 @@ let traverse = filter_map items ~f:(fun item -> match item.pstr_desc with | Pstr_module { pmb_attributes; pmb_loc; _ } -> - if keep pmb_loc pmb_attributes then Some item else None + if keep pmb_loc pmb_attributes + then Some item + else ( + Ppxlib.Attribute.explicitly_drop#structure_item item; + None) | Pstr_primitive { pval_attributes; pval_loc; _ } -> - if keep pval_loc pval_attributes then Some item else None + if keep pval_loc pval_attributes + then Some item + else ( + Ppxlib.Attribute.explicitly_drop#structure_item item; + None) | Pstr_value (r, l) -> ( let l = filter_map l ~f:(fun b -> - if keep b.pvb_loc b.pvb_attributes then Some b else None) + if keep b.pvb_loc b.pvb_attributes + then Some b + else ( + Ppxlib.Attribute.explicitly_drop#structure_item item; + None)) in match l with | [] -> None @@ -285,7 +342,22 @@ let traverse = | Some pattern -> Some { case with pc_lhs = pattern }) in super#cases cases + + method! signature_item item = + match item.psig_desc with + | Psig_module { pmd_attributes; pmd_loc; _ } -> + if keep pmd_loc pmd_attributes + then item + else ( + Ppxlib.Attribute.explicitly_drop#signature_item item; + let open Ppxlib.Ast_builder.Default in + let loc = Location.none in + psig_include ~loc (include_infos ~loc (pmty_signature ~loc []))) + | _ -> item end let () = - Ppxlib.Driver.register_transformation ~impl:traverse#structure "ppx_optcomp_light" + Ppxlib.Driver.register_transformation + ~impl:traverse#structure + ~intf:traverse#signature + "ppx_optcomp_light" diff --git a/compiler/tests-check-prim/dune.inc b/compiler/tests-check-prim/dune.inc index f587188599..6a8b57aeea 100644 --- a/compiler/tests-check-prim/dune.inc +++ b/compiler/tests-check-prim/dune.inc @@ -2,7 +2,7 @@ (targets main.4.14.output) (mode (promote (until-clean))) - (enabled_if (and (>= %{ocaml_version} 4.14)(< %{ocaml_version} 5.0))) + (enabled_if (and (>= %{ocaml_version} 4.14)(< %{ocaml_version} 5.0)(not %{oxcaml_supported}))) (action (with-stdout-to %{targets} @@ -17,7 +17,7 @@ (targets unix-Win32.4.14.output) (mode (promote (until-clean))) - (enabled_if (and (>= %{ocaml_version} 4.14)(< %{ocaml_version} 5.0)(= %{os_type} Win32))) + (enabled_if (and (>= %{ocaml_version} 4.14)(< %{ocaml_version} 5.0)(= %{os_type} Win32)(not %{oxcaml_supported}))) (action (with-stdout-to %{targets} @@ -32,7 +32,7 @@ (targets unix-Unix.4.14.output) (mode (promote (until-clean))) - (enabled_if (and (>= %{ocaml_version} 4.14)(< %{ocaml_version} 5.0)(= %{os_type} Unix))) + (enabled_if (and (>= %{ocaml_version} 4.14)(< %{ocaml_version} 5.0)(= %{os_type} Unix)(not %{oxcaml_supported}))) (action (with-stdout-to %{targets} @@ -47,7 +47,22 @@ (targets main.5.2.output) (mode (promote (until-clean))) - (enabled_if (and (>= %{ocaml_version} 5.2)(< %{ocaml_version} 5.3))) + (enabled_if (and (>= %{ocaml_version} 5.2)(< %{ocaml_version} 5.3)(not %{oxcaml_supported}))) + (action + (with-stdout-to + %{targets} + (run + %{bin:js_of_ocaml} + check-runtime + +dynlink.js + +toplevel.js + %{dep:main.bc})))) + +(rule + (targets main.5.2+ox.output) + (mode + (promote (until-clean))) + (enabled_if (and (>= %{ocaml_version} 5.2)(< %{ocaml_version} 5.3)%{oxcaml_supported})) (action (with-stdout-to %{targets} @@ -62,7 +77,22 @@ (targets unix-Win32.5.2.output) (mode (promote (until-clean))) - (enabled_if (and (>= %{ocaml_version} 5.2)(< %{ocaml_version} 5.3)(= %{os_type} Win32))) + (enabled_if (and (>= %{ocaml_version} 5.2)(< %{ocaml_version} 5.3)(= %{os_type} Win32)(not %{oxcaml_supported}))) + (action + (with-stdout-to + %{targets} + (run + %{bin:js_of_ocaml} + check-runtime + +dynlink.js + +toplevel.js + %{dep:unix.bc})))) + +(rule + (targets unix-Win32.5.2+ox.output) + (mode + (promote (until-clean))) + (enabled_if (and (>= %{ocaml_version} 5.2)(< %{ocaml_version} 5.3)(= %{os_type} Win32)%{oxcaml_supported})) (action (with-stdout-to %{targets} @@ -77,7 +107,22 @@ (targets unix-Unix.5.2.output) (mode (promote (until-clean))) - (enabled_if (and (>= %{ocaml_version} 5.2)(< %{ocaml_version} 5.3)(= %{os_type} Unix))) + (enabled_if (and (>= %{ocaml_version} 5.2)(< %{ocaml_version} 5.3)(= %{os_type} Unix)(not %{oxcaml_supported}))) + (action + (with-stdout-to + %{targets} + (run + %{bin:js_of_ocaml} + check-runtime + +dynlink.js + +toplevel.js + %{dep:unix.bc})))) + +(rule + (targets unix-Unix.5.2+ox.output) + (mode + (promote (until-clean))) + (enabled_if (and (>= %{ocaml_version} 5.2)(< %{ocaml_version} 5.3)(= %{os_type} Unix)%{oxcaml_supported})) (action (with-stdout-to %{targets} @@ -92,7 +137,7 @@ (targets main.5.3.output) (mode (promote (until-clean))) - (enabled_if (and (>= %{ocaml_version} 5.3)(< %{ocaml_version} 5.4))) + (enabled_if (and (>= %{ocaml_version} 5.3)(< %{ocaml_version} 5.4)(not %{oxcaml_supported}))) (action (with-stdout-to %{targets} @@ -107,7 +152,7 @@ (targets unix-Win32.5.3.output) (mode (promote (until-clean))) - (enabled_if (and (>= %{ocaml_version} 5.3)(< %{ocaml_version} 5.4)(= %{os_type} Win32))) + (enabled_if (and (>= %{ocaml_version} 5.3)(< %{ocaml_version} 5.4)(= %{os_type} Win32)(not %{oxcaml_supported}))) (action (with-stdout-to %{targets} @@ -122,7 +167,7 @@ (targets unix-Unix.5.3.output) (mode (promote (until-clean))) - (enabled_if (and (>= %{ocaml_version} 5.3)(< %{ocaml_version} 5.4)(= %{os_type} Unix))) + (enabled_if (and (>= %{ocaml_version} 5.3)(< %{ocaml_version} 5.4)(= %{os_type} Unix)(not %{oxcaml_supported}))) (action (with-stdout-to %{targets} @@ -137,7 +182,7 @@ (targets main.5.4.output) (mode (promote (until-clean))) - (enabled_if (and (>= %{ocaml_version} 5.4)(< %{ocaml_version} 5.5))) + (enabled_if (and (>= %{ocaml_version} 5.4)(< %{ocaml_version} 5.5)(not %{oxcaml_supported}))) (action (with-stdout-to %{targets} @@ -152,7 +197,7 @@ (targets unix-Win32.5.4.output) (mode (promote (until-clean))) - (enabled_if (and (>= %{ocaml_version} 5.4)(< %{ocaml_version} 5.5)(= %{os_type} Win32))) + (enabled_if (and (>= %{ocaml_version} 5.4)(< %{ocaml_version} 5.5)(= %{os_type} Win32)(not %{oxcaml_supported}))) (action (with-stdout-to %{targets} @@ -167,7 +212,7 @@ (targets unix-Unix.5.4.output) (mode (promote (until-clean))) - (enabled_if (and (>= %{ocaml_version} 5.4)(< %{ocaml_version} 5.5)(= %{os_type} Unix))) + (enabled_if (and (>= %{ocaml_version} 5.4)(< %{ocaml_version} 5.5)(= %{os_type} Unix)(not %{oxcaml_supported}))) (action (with-stdout-to %{targets} diff --git a/compiler/tests-check-prim/gen_dune.ml b/compiler/tests-check-prim/gen_dune.ml index 82d8707956..5882d9b1fb 100644 --- a/compiler/tests-check-prim/gen_dune.ml +++ b/compiler/tests-check-prim/gen_dune.ml @@ -39,7 +39,7 @@ let string_of_os_type = function | Unix -> "Unix" | Win32 -> "Win32" -let rule bc ocaml_version os_type = +let rule bc ocaml_version os_type oxcaml = let vl = [ Printf.sprintf "(>= %%{ocaml_version} %s)" (string_of_version ocaml_version) ] in @@ -53,7 +53,8 @@ let rule bc ocaml_version os_type = | None -> [] | Some os_type -> [ Printf.sprintf "(= %%{os_type} %s)" (string_of_os_type os_type) ] in - let enabled_if = Printf.sprintf "(and %s)" (String.concat "" (vl @ vu @ os)) in + let ox = [ (if oxcaml then "%{oxcaml_supported}" else "(not %{oxcaml_supported})") ] in + let enabled_if = Printf.sprintf "(and %s)" (String.concat "" (vl @ vu @ os @ ox)) in let target = Filename.chop_extension bc @@ -62,6 +63,7 @@ let rule bc ocaml_version os_type = | Some os_type -> "-" ^ string_of_os_type os_type) ^ "." ^ string_of_version ocaml_version + ^ (if oxcaml then "+ox" else "") ^ ".output" in Printf.sprintf @@ -90,6 +92,10 @@ let () = List.iter (fun ocaml_version -> List.iter - (fun (bc, os_type) -> print_endline (rule bc ocaml_version os_type)) + (fun (bc, os_type) -> + print_endline (rule bc ocaml_version os_type false); + match ocaml_version with + | `V5_2 -> print_endline (rule bc ocaml_version os_type true) + | _ -> ()) [ "main.bc", None; "unix.bc", Some Win32; "unix.bc", Some Unix ]) versions diff --git a/compiler/tests-check-prim/main.5.2+ox.output b/compiler/tests-check-prim/main.5.2+ox.output new file mode 100644 index 0000000000..424abbbdc4 --- /dev/null +++ b/compiler/tests-check-prim/main.5.2+ox.output @@ -0,0 +1,333 @@ +Missing +------- + +From main.bc: +caml_alloc_dummy_function +caml_alloc_stack_bind +caml_array_get_indexed_by_int32 +caml_array_get_indexed_by_int64 +caml_array_get_indexed_by_nativeint +caml_array_get_local +caml_array_of_iarray +caml_array_set_addr_local +caml_array_set_indexed_by_int32 +caml_array_set_indexed_by_int64 +caml_array_set_indexed_by_nativeint +caml_array_set_local +caml_array_unsafe_get_local +caml_array_unsafe_set_local +caml_assume_no_perform +caml_atomic_make +caml_ba_uint8_get16_indexed_by_int32 +caml_ba_uint8_get16_indexed_by_int64 +caml_ba_uint8_get16_indexed_by_nativeint +caml_ba_uint8_get32_indexed_by_int32 +caml_ba_uint8_get32_indexed_by_int64 +caml_ba_uint8_get32_indexed_by_nativeint +caml_ba_uint8_get64_indexed_by_int32 +caml_ba_uint8_get64_indexed_by_int64 +caml_ba_uint8_get64_indexed_by_nativeint +caml_ba_uint8_getf32_indexed_by_int32 +caml_ba_uint8_getf32_indexed_by_int64 +caml_ba_uint8_getf32_indexed_by_nativeint +caml_ba_uint8_set16_indexed_by_int32 +caml_ba_uint8_set16_indexed_by_int64 +caml_ba_uint8_set16_indexed_by_nativeint +caml_ba_uint8_set32_indexed_by_int32 +caml_ba_uint8_set32_indexed_by_int64 +caml_ba_uint8_set32_indexed_by_nativeint +caml_ba_uint8_set64_indexed_by_int32 +caml_ba_uint8_set64_indexed_by_int64 +caml_ba_uint8_set64_indexed_by_nativeint +caml_ba_uint8_setf32_indexed_by_int32 +caml_ba_uint8_setf32_indexed_by_int64 +caml_ba_uint8_setf32_indexed_by_nativeint +caml_bytes_get16_indexed_by_int32 +caml_bytes_get16_indexed_by_int64 +caml_bytes_get16_indexed_by_nativeint +caml_bytes_get32_indexed_by_int32 +caml_bytes_get32_indexed_by_int64 +caml_bytes_get32_indexed_by_nativeint +caml_bytes_get64_indexed_by_int32 +caml_bytes_get64_indexed_by_int64 +caml_bytes_get64_indexed_by_nativeint +caml_bytes_getf32_indexed_by_int32 +caml_bytes_getf32_indexed_by_int64 +caml_bytes_getf32_indexed_by_nativeint +caml_bytes_set16_indexed_by_int32 +caml_bytes_set16_indexed_by_int64 +caml_bytes_set16_indexed_by_nativeint +caml_bytes_set32_indexed_by_int32 +caml_bytes_set32_indexed_by_int64 +caml_bytes_set32_indexed_by_nativeint +caml_bytes_set64_indexed_by_int32 +caml_bytes_set64_indexed_by_int64 +caml_bytes_set64_indexed_by_nativeint +caml_bytes_setf32_indexed_by_int32 +caml_bytes_setf32_indexed_by_int64 +caml_bytes_setf32_indexed_by_nativeint +caml_continuation_use +caml_deepen_idx_bytecode +caml_drop_continuation +caml_dynamic_get +caml_dynamic_make +caml_dynamic_set_root +caml_floatarray_get_local +caml_floatarray_unsafe_get_local +caml_get_header +caml_iarray_of_array +caml_local_stack_offset +caml_make_array_local +caml_make_local_unboxed_float32_vect +caml_make_local_unboxed_float64_vect +caml_make_local_unboxed_int32_vect +caml_make_local_unboxed_int64_vect +caml_make_local_unboxed_nativeint_vect +caml_make_local_unboxed_vec128_vect +caml_make_local_unboxed_vec256_vect +caml_make_local_vect +caml_make_unboxed_float32_vect +caml_make_unboxed_float32_vect_bytecode +caml_make_unboxed_float64_vect +caml_make_unboxed_int32_vect +caml_make_unboxed_int32_vect_bytecode +caml_make_unboxed_int64_vect +caml_make_unboxed_int64_vect_bytecode +caml_make_unboxed_nativeint_vect +caml_make_unboxed_nativeint_vect_bytecode +caml_make_unboxed_vec128_vect +caml_make_unboxed_vec128_vect_bytecode +caml_make_unboxed_vec256_vect +caml_make_unboxed_vec256_vect_bytecode +caml_makearray_dynamic_non_scannable_unboxed_product +caml_makearray_dynamic_scannable_unboxed_product +caml_ml_domain_index +caml_ml_runtime_events_path +caml_no_bytecode_impl +caml_obj_make_forward +caml_reinterpret_tagged_int63_as_unboxed_int64 +caml_reinterpret_unboxed_int64_as_tagged_int63 +caml_reset_afl_instrumentation +caml_simd_bytecode_not_supported +caml_simd_cast_float64_int64_bytecode +caml_simd_float64_max_bytecode +caml_simd_float64_min_bytecode +caml_simd_float64_round_current_bytecode +caml_simd_float64_round_neg_inf_bytecode +caml_simd_float64_round_pos_inf_bytecode +caml_simd_float64_round_towards_zero_bytecode +caml_sqrt_float32 +caml_string_get16_indexed_by_int32 +caml_string_get16_indexed_by_int64 +caml_string_get16_indexed_by_nativeint +caml_string_get32_indexed_by_int32 +caml_string_get32_indexed_by_int64 +caml_string_get32_indexed_by_nativeint +caml_string_get64_indexed_by_int32 +caml_string_get64_indexed_by_int64 +caml_string_get64_indexed_by_nativeint +caml_string_getf32_indexed_by_int32 +caml_string_getf32_indexed_by_int64 +caml_string_getf32_indexed_by_nativeint +caml_unboxed_float32_vect_blit +caml_unboxed_int32_vect_blit +caml_unboxed_int64_vect_blit +caml_unboxed_nativeint_vect_blit +caml_unboxed_vec128_vect_blit +caml_unboxed_vec256_vect_blit +caml_unsafe_get_idx_bytecode +caml_unsafe_set_idx_bytecode +debugger + +Unused +------- + +From +array.js: +caml_check_bound + +From +bigarray.js: +caml_ba_create_from (deprecated) +caml_ba_init + +From +bigstring.js: +caml_bigstring_blit_ba_to_ba +caml_bigstring_blit_ba_to_bytes +caml_bigstring_blit_bytes_to_ba +caml_bigstring_blit_string_to_ba +caml_bigstring_memcmp +caml_hash_mix_bigstring + +From +effect.js: +jsoo_effect_not_supported + +From +fs.js: +caml_ba_map_file +caml_ba_map_file_bytecode +caml_fs_init +jsoo_create_file +jsoo_create_file_extern + +From +graphics.js: +caml_gr_arc_aux +caml_gr_blit_image +caml_gr_clear_graph +caml_gr_close_graph +caml_gr_close_subwindow +caml_gr_create_image +caml_gr_current_x +caml_gr_current_y +caml_gr_display_mode +caml_gr_doc_of_state +caml_gr_draw_arc +caml_gr_draw_char +caml_gr_draw_image +caml_gr_draw_rect +caml_gr_draw_str +caml_gr_draw_string +caml_gr_dump_image +caml_gr_fill_arc +caml_gr_fill_poly +caml_gr_fill_rect +caml_gr_lineto +caml_gr_make_image +caml_gr_moveto +caml_gr_open_graph +caml_gr_open_subwindow +caml_gr_plot +caml_gr_point_color +caml_gr_remember_mode +caml_gr_resize_window +caml_gr_set_color +caml_gr_set_font +caml_gr_set_line_width +caml_gr_set_text_size +caml_gr_set_window_title +caml_gr_sigio_handler +caml_gr_sigio_signal +caml_gr_size_x +caml_gr_size_y +caml_gr_state +caml_gr_state_create +caml_gr_state_get +caml_gr_state_init +caml_gr_state_set +caml_gr_synchronize +caml_gr_text_size +caml_gr_wait_event +caml_gr_window_id + +From +hash.js: +caml_hash_mix_int64 + +From +int64.js: +caml_checked_int64_to_int + +From +ints.js: +caml_div +caml_mod + +From +jslib.js: +caml_is_js +caml_trampoline +caml_trampoline_return +caml_wrap_exception + +From +marshal.js: +caml_marshal_constants + +From +mlBytes.js: +caml_array_of_bytes (deprecated) +caml_array_of_string (deprecated) +caml_bytes_of_utf16_jsstring +caml_new_string (deprecated) +caml_string_concat +caml_to_js_string (deprecated) + +From +runtime_events.js: +caml_runtime_events_create_cursor +caml_runtime_events_free_cursor +caml_runtime_events_read_poll +caml_runtime_events_user_resolve + +From +stdlib.js: +caml_is_printable +caml_maybe_print_stats + +From +sys.js: +caml_fatal_uncaught_exception +caml_format_exception +caml_is_special_exception +caml_set_static_env + +From +toplevel.js: +caml_get_section_table +jsoo_get_runtime_aliases +jsoo_toplevel_init_compile +jsoo_toplevel_init_reloc + +From +unix.js: +caml_strerror +caml_unix_access +caml_unix_chdir +caml_unix_chmod +caml_unix_cleanup +caml_unix_close +caml_unix_closedir +caml_unix_fchmod +caml_unix_filedescr_of_fd +caml_unix_findclose +caml_unix_findfirst +caml_unix_findnext +caml_unix_fstat +caml_unix_fstat_64 +caml_unix_fsync +caml_unix_ftruncate +caml_unix_ftruncate_64 +caml_unix_getegid +caml_unix_geteuid +caml_unix_getgid +caml_unix_getpwnam +caml_unix_gettimeofday +caml_unix_getuid +caml_unix_gmtime +caml_unix_has_symlink +caml_unix_inchannel_of_filedescr +caml_unix_inet_addr_of_string +caml_unix_isatty +caml_unix_link +caml_unix_localtime +caml_unix_lookup_file +caml_unix_lseek +caml_unix_lseek_64 +caml_unix_lstat +caml_unix_lstat_64 +caml_unix_mkdir +caml_unix_mktime +caml_unix_open +caml_unix_opendir +caml_unix_outchannel_of_filedescr +caml_unix_read +caml_unix_read_bigarray +caml_unix_readdir +caml_unix_readlink +caml_unix_rename +caml_unix_rewinddir +caml_unix_rmdir +caml_unix_single_write +caml_unix_startup +caml_unix_stat +caml_unix_stat_64 +caml_unix_symlink +caml_unix_time +caml_unix_times +caml_unix_truncate +caml_unix_truncate_64 +caml_unix_unlink +caml_unix_utimes +caml_unix_write +caml_unix_write_bigarray +unix_error_message + +From +zstd.js: +caml_zstd_initialize + diff --git a/compiler/tests-check-prim/main.5.2.output b/compiler/tests-check-prim/main.5.2.output index b3ac67d39d..45e2af7b80 100644 --- a/compiler/tests-check-prim/main.5.2.output +++ b/compiler/tests-check-prim/main.5.2.output @@ -6,7 +6,6 @@ caml_alloc_dummy_function caml_assume_no_perform caml_continuation_use caml_drop_continuation -caml_int_as_pointer caml_reset_afl_instrumentation debugger @@ -28,9 +27,96 @@ caml_bigstring_blit_string_to_ba caml_bigstring_memcmp caml_hash_mix_bigstring +From +domain.js: +caml_atomic_add +caml_atomic_add_field +caml_atomic_cas_field +caml_atomic_compare_exchange +caml_atomic_compare_exchange_field +caml_atomic_exchange_field +caml_atomic_fetch_add_field +caml_atomic_land +caml_atomic_land_field +caml_atomic_load_field +caml_atomic_lor +caml_atomic_lor_field +caml_atomic_lxor +caml_atomic_lxor_field +caml_atomic_set +caml_atomic_set_field +caml_atomic_sub +caml_atomic_sub_field + From +effect.js: jsoo_effect_not_supported +From +float32.js: +caml_abs_float32 +caml_acos_float32_bytecode +caml_acosh_float32_bytecode +caml_add_float32 +caml_asin_float32_bytecode +caml_asinh_float32_bytecode +caml_atan2_float32_bytecode +caml_atan_float32_bytecode +caml_atanh_float32_bytecode +caml_ba_uint8_getf32 +caml_ba_uint8_setf32 +caml_bytes_getf32 +caml_bytes_setf32 +caml_cbrt_float32_bytecode +caml_ceil_float32_bytecode +caml_classify_float32_bytecode +caml_copysign_float32_bytecode +caml_cos_float32_bytecode +caml_cosh_float32_bytecode +caml_div_float32 +caml_erf_float32_bytecode +caml_erfc_float32_bytecode +caml_exp2_float32_bytecode +caml_exp_float32_bytecode +caml_expm1_float32_bytecode +caml_float32_compare +caml_float32_of_bits_bytecode +caml_float32_of_float +caml_float32_of_int +caml_float32_of_int64_bytecode +caml_float32_of_string +caml_float32_to_bits_bytecode +caml_float32_to_int64_bytecode +caml_float_of_float32 +caml_floor_float32_bytecode +caml_fma_float32_bytecode +caml_fmod_float32_bytecode +caml_format_float32 +caml_frexp_float32 +caml_hypot_float32_bytecode +caml_int_of_float32 +caml_is_boot_compiler +caml_ldexp_float32_bytecode +caml_log10_float32_bytecode +caml_log1p_float32_bytecode +caml_log2_float32_bytecode +caml_log_float32_bytecode +caml_modf_float32 +caml_mul_float32 +caml_neg_float32 +caml_nextafter_float32_bytecode +caml_power_float32_bytecode +caml_round_float32_bytecode +caml_signbit_float32_bytecode +caml_simd_cast_float32_int64_bytecode +caml_simd_float32_max_bytecode +caml_simd_float32_min_bytecode +caml_sin_float32_bytecode +caml_sinh_float32_bytecode +caml_sqrt_float32_bytecode +caml_string_getf32 +caml_sub_float32 +caml_tan_float32_bytecode +caml_tanh_float32_bytecode +caml_trunc_float32_bytecode + From +fs.js: caml_ba_map_file caml_ba_map_file_bytecode @@ -38,6 +124,14 @@ caml_fs_init jsoo_create_file jsoo_create_file_extern +From +gc.js: +caml_eventlog_pause +caml_eventlog_resume +caml_gc_tweak_get +caml_gc_tweak_list_active +caml_gc_tweak_set +caml_memprof_participate + From +graphics.js: caml_gr_arc_aux caml_gr_blit_image @@ -88,11 +182,20 @@ caml_gr_wait_event caml_gr_window_id From +hash.js: +caml_hash_exn caml_hash_mix_int64 +From +int64.js: +caml_array_unsafe_get_indexed_by_int64 +caml_array_unsafe_set_indexed_by_int64 +caml_checked_int64_to_int + From +ints.js: caml_div +caml_int16_of_string +caml_int8_of_string caml_mod +caml_parse_small_int From +jslib.js: caml_is_js @@ -111,6 +214,11 @@ caml_new_string (deprecated) caml_string_concat caml_to_js_string (deprecated) +From +obj.js: +caml_obj_is_stack +caml_obj_uniquely_reachable_words +caml_succ_scannable_prefix_len + From +runtime_events.js: caml_runtime_events_create_cursor caml_runtime_events_free_cursor @@ -120,6 +228,7 @@ caml_runtime_events_user_resolve From +stdlib.js: caml_is_printable caml_maybe_print_stats +caml_with_async_exns From +sys.js: caml_fatal_uncaught_exception @@ -127,6 +236,7 @@ caml_format_exception caml_is_special_exception caml_set_static_env caml_sys_const_naked_pointers_checked +caml_sys_const_runtime5 From +toplevel.js: caml_get_section_table diff --git a/compiler/tests-check-prim/unix-Unix.5.2+ox.output b/compiler/tests-check-prim/unix-Unix.5.2+ox.output new file mode 100644 index 0000000000..f4d7e2f40e --- /dev/null +++ b/compiler/tests-check-prim/unix-Unix.5.2+ox.output @@ -0,0 +1,356 @@ +Missing +------- + +From unix.bc: +caml_alloc_dummy_function +caml_alloc_stack_bind +caml_array_get_indexed_by_int32 +caml_array_get_indexed_by_int64 +caml_array_get_indexed_by_nativeint +caml_array_get_local +caml_array_of_iarray +caml_array_set_addr_local +caml_array_set_indexed_by_int32 +caml_array_set_indexed_by_int64 +caml_array_set_indexed_by_nativeint +caml_array_set_local +caml_array_unsafe_get_local +caml_array_unsafe_set_local +caml_assume_no_perform +caml_atomic_make +caml_ba_uint8_get16_indexed_by_int32 +caml_ba_uint8_get16_indexed_by_int64 +caml_ba_uint8_get16_indexed_by_nativeint +caml_ba_uint8_get32_indexed_by_int32 +caml_ba_uint8_get32_indexed_by_int64 +caml_ba_uint8_get32_indexed_by_nativeint +caml_ba_uint8_get64_indexed_by_int32 +caml_ba_uint8_get64_indexed_by_int64 +caml_ba_uint8_get64_indexed_by_nativeint +caml_ba_uint8_getf32_indexed_by_int32 +caml_ba_uint8_getf32_indexed_by_int64 +caml_ba_uint8_getf32_indexed_by_nativeint +caml_ba_uint8_set16_indexed_by_int32 +caml_ba_uint8_set16_indexed_by_int64 +caml_ba_uint8_set16_indexed_by_nativeint +caml_ba_uint8_set32_indexed_by_int32 +caml_ba_uint8_set32_indexed_by_int64 +caml_ba_uint8_set32_indexed_by_nativeint +caml_ba_uint8_set64_indexed_by_int32 +caml_ba_uint8_set64_indexed_by_int64 +caml_ba_uint8_set64_indexed_by_nativeint +caml_ba_uint8_setf32_indexed_by_int32 +caml_ba_uint8_setf32_indexed_by_int64 +caml_ba_uint8_setf32_indexed_by_nativeint +caml_bytes_get16_indexed_by_int32 +caml_bytes_get16_indexed_by_int64 +caml_bytes_get16_indexed_by_nativeint +caml_bytes_get32_indexed_by_int32 +caml_bytes_get32_indexed_by_int64 +caml_bytes_get32_indexed_by_nativeint +caml_bytes_get64_indexed_by_int32 +caml_bytes_get64_indexed_by_int64 +caml_bytes_get64_indexed_by_nativeint +caml_bytes_getf32_indexed_by_int32 +caml_bytes_getf32_indexed_by_int64 +caml_bytes_getf32_indexed_by_nativeint +caml_bytes_set16_indexed_by_int32 +caml_bytes_set16_indexed_by_int64 +caml_bytes_set16_indexed_by_nativeint +caml_bytes_set32_indexed_by_int32 +caml_bytes_set32_indexed_by_int64 +caml_bytes_set32_indexed_by_nativeint +caml_bytes_set64_indexed_by_int32 +caml_bytes_set64_indexed_by_int64 +caml_bytes_set64_indexed_by_nativeint +caml_bytes_setf32_indexed_by_int32 +caml_bytes_setf32_indexed_by_int64 +caml_bytes_setf32_indexed_by_nativeint +caml_continuation_use +caml_deepen_idx_bytecode +caml_drop_continuation +caml_dynamic_get +caml_dynamic_make +caml_dynamic_set_root +caml_floatarray_get_local +caml_floatarray_unsafe_get_local +caml_get_header +caml_iarray_of_array +caml_local_stack_offset +caml_make_array_local +caml_make_local_unboxed_float32_vect +caml_make_local_unboxed_float64_vect +caml_make_local_unboxed_int32_vect +caml_make_local_unboxed_int64_vect +caml_make_local_unboxed_nativeint_vect +caml_make_local_unboxed_vec128_vect +caml_make_local_unboxed_vec256_vect +caml_make_local_vect +caml_make_unboxed_float32_vect +caml_make_unboxed_float32_vect_bytecode +caml_make_unboxed_float64_vect +caml_make_unboxed_int32_vect +caml_make_unboxed_int32_vect_bytecode +caml_make_unboxed_int64_vect +caml_make_unboxed_int64_vect_bytecode +caml_make_unboxed_nativeint_vect +caml_make_unboxed_nativeint_vect_bytecode +caml_make_unboxed_vec128_vect +caml_make_unboxed_vec128_vect_bytecode +caml_make_unboxed_vec256_vect +caml_make_unboxed_vec256_vect_bytecode +caml_makearray_dynamic_non_scannable_unboxed_product +caml_makearray_dynamic_scannable_unboxed_product +caml_ml_domain_index +caml_ml_runtime_events_path +caml_no_bytecode_impl +caml_obj_make_forward +caml_reinterpret_tagged_int63_as_unboxed_int64 +caml_reinterpret_unboxed_int64_as_tagged_int63 +caml_reset_afl_instrumentation +caml_simd_bytecode_not_supported +caml_simd_cast_float64_int64_bytecode +caml_simd_float64_max_bytecode +caml_simd_float64_min_bytecode +caml_simd_float64_round_current_bytecode +caml_simd_float64_round_neg_inf_bytecode +caml_simd_float64_round_pos_inf_bytecode +caml_simd_float64_round_towards_zero_bytecode +caml_sqrt_float32 +caml_string_get16_indexed_by_int32 +caml_string_get16_indexed_by_int64 +caml_string_get16_indexed_by_nativeint +caml_string_get32_indexed_by_int32 +caml_string_get32_indexed_by_int64 +caml_string_get32_indexed_by_nativeint +caml_string_get64_indexed_by_int32 +caml_string_get64_indexed_by_int64 +caml_string_get64_indexed_by_nativeint +caml_string_getf32_indexed_by_int32 +caml_string_getf32_indexed_by_int64 +caml_string_getf32_indexed_by_nativeint +caml_unboxed_float32_vect_blit +caml_unboxed_int32_vect_blit +caml_unboxed_int64_vect_blit +caml_unboxed_nativeint_vect_blit +caml_unboxed_vec128_vect_blit +caml_unboxed_vec256_vect_blit +caml_unix_accept +caml_unix_alarm +caml_unix_bind +caml_unix_chown +caml_unix_chroot +caml_unix_clear_close_on_exec +caml_unix_clear_nonblock +caml_unix_connect +caml_unix_dup +caml_unix_dup2 +caml_unix_environment +caml_unix_environment_unsafe +caml_unix_execv +caml_unix_execve +caml_unix_execvp +caml_unix_execvpe +caml_unix_fchown +caml_unix_fork +caml_unix_getaddrinfo +caml_unix_getgroups +caml_unix_gethostbyaddr +caml_unix_gethostbyname +caml_unix_gethostname +caml_unix_getitimer +caml_unix_getlogin +caml_unix_getnameinfo +caml_unix_getpeername +caml_unix_getpid +caml_unix_getppid +caml_unix_getprotobyname +caml_unix_getprotobynumber +caml_unix_getservbyname +caml_unix_getservbyport +caml_unix_getsockname +caml_unix_getsockopt +caml_unix_initgroups +caml_unix_kill +caml_unix_listen +caml_unix_lockf +caml_unix_map_file_bytecode +caml_unix_mkfifo +caml_unix_nice +caml_unix_pipe +caml_unix_putenv +caml_unix_realpath +caml_unix_recv +caml_unix_recvfrom +caml_unix_select +caml_unix_send +caml_unix_sendto +caml_unix_set_close_on_exec +caml_unix_set_nonblock +caml_unix_setgid +caml_unix_setgroups +caml_unix_setitimer +caml_unix_setsid +caml_unix_setsockopt +caml_unix_setuid +caml_unix_shutdown +caml_unix_sigpending +caml_unix_sigprocmask +caml_unix_sigsuspend +caml_unix_sleep +caml_unix_socket +caml_unix_socketpair +caml_unix_spawn +caml_unix_string_of_inet_addr +caml_unix_tcdrain +caml_unix_tcflow +caml_unix_tcflush +caml_unix_tcgetattr +caml_unix_tcsendbreak +caml_unix_tcsetattr +caml_unix_umask +caml_unix_wait +caml_unix_waitpid +caml_unsafe_get_idx_bytecode +caml_unsafe_set_idx_bytecode +debugger + +Unused +------- + +From +array.js: +caml_check_bound + +From +bigarray.js: +caml_ba_create_from (deprecated) +caml_ba_init + +From +bigstring.js: +caml_bigstring_blit_ba_to_ba +caml_bigstring_blit_ba_to_bytes +caml_bigstring_blit_bytes_to_ba +caml_bigstring_blit_string_to_ba +caml_bigstring_memcmp +caml_hash_mix_bigstring + +From +effect.js: +jsoo_effect_not_supported + +From +fs.js: +caml_ba_map_file +caml_ba_map_file_bytecode +caml_fs_init +jsoo_create_file +jsoo_create_file_extern + +From +graphics.js: +caml_gr_arc_aux +caml_gr_blit_image +caml_gr_clear_graph +caml_gr_close_graph +caml_gr_close_subwindow +caml_gr_create_image +caml_gr_current_x +caml_gr_current_y +caml_gr_display_mode +caml_gr_doc_of_state +caml_gr_draw_arc +caml_gr_draw_char +caml_gr_draw_image +caml_gr_draw_rect +caml_gr_draw_str +caml_gr_draw_string +caml_gr_dump_image +caml_gr_fill_arc +caml_gr_fill_poly +caml_gr_fill_rect +caml_gr_lineto +caml_gr_make_image +caml_gr_moveto +caml_gr_open_graph +caml_gr_open_subwindow +caml_gr_plot +caml_gr_point_color +caml_gr_remember_mode +caml_gr_resize_window +caml_gr_set_color +caml_gr_set_font +caml_gr_set_line_width +caml_gr_set_text_size +caml_gr_set_window_title +caml_gr_sigio_handler +caml_gr_sigio_signal +caml_gr_size_x +caml_gr_size_y +caml_gr_state +caml_gr_state_create +caml_gr_state_get +caml_gr_state_init +caml_gr_state_set +caml_gr_synchronize +caml_gr_text_size +caml_gr_wait_event +caml_gr_window_id + +From +hash.js: +caml_hash_mix_int64 + +From +int64.js: +caml_checked_int64_to_int + +From +ints.js: +caml_div +caml_mod + +From +jslib.js: +caml_is_js +caml_trampoline +caml_trampoline_return +caml_wrap_exception + +From +marshal.js: +caml_marshal_constants + +From +mlBytes.js: +caml_array_of_bytes (deprecated) +caml_array_of_string (deprecated) +caml_bytes_of_utf16_jsstring +caml_new_string (deprecated) +caml_string_concat +caml_to_js_string (deprecated) + +From +runtime_events.js: +caml_runtime_events_create_cursor +caml_runtime_events_free_cursor +caml_runtime_events_read_poll +caml_runtime_events_user_resolve + +From +stdlib.js: +caml_is_printable +caml_maybe_print_stats + +From +sys.js: +caml_fatal_uncaught_exception +caml_format_exception +caml_is_special_exception +caml_set_static_env + +From +toplevel.js: +caml_get_section_table +jsoo_get_runtime_aliases +jsoo_toplevel_init_compile +jsoo_toplevel_init_reloc + +From +unix.js: +caml_strerror +caml_unix_cleanup +caml_unix_filedescr_of_fd +caml_unix_findclose +caml_unix_findfirst +caml_unix_findnext +caml_unix_startup +unix_error_message + +From +zstd.js: +caml_zstd_initialize + diff --git a/compiler/tests-check-prim/unix-Unix.5.2.output b/compiler/tests-check-prim/unix-Unix.5.2.output index 2889e7d976..dcd27842f3 100644 --- a/compiler/tests-check-prim/unix-Unix.5.2.output +++ b/compiler/tests-check-prim/unix-Unix.5.2.output @@ -6,7 +6,6 @@ caml_alloc_dummy_function caml_assume_no_perform caml_continuation_use caml_drop_continuation -caml_int_as_pointer caml_reset_afl_instrumentation caml_unix_accept caml_unix_alarm @@ -104,9 +103,96 @@ caml_bigstring_blit_string_to_ba caml_bigstring_memcmp caml_hash_mix_bigstring +From +domain.js: +caml_atomic_add +caml_atomic_add_field +caml_atomic_cas_field +caml_atomic_compare_exchange +caml_atomic_compare_exchange_field +caml_atomic_exchange_field +caml_atomic_fetch_add_field +caml_atomic_land +caml_atomic_land_field +caml_atomic_load_field +caml_atomic_lor +caml_atomic_lor_field +caml_atomic_lxor +caml_atomic_lxor_field +caml_atomic_set +caml_atomic_set_field +caml_atomic_sub +caml_atomic_sub_field + From +effect.js: jsoo_effect_not_supported +From +float32.js: +caml_abs_float32 +caml_acos_float32_bytecode +caml_acosh_float32_bytecode +caml_add_float32 +caml_asin_float32_bytecode +caml_asinh_float32_bytecode +caml_atan2_float32_bytecode +caml_atan_float32_bytecode +caml_atanh_float32_bytecode +caml_ba_uint8_getf32 +caml_ba_uint8_setf32 +caml_bytes_getf32 +caml_bytes_setf32 +caml_cbrt_float32_bytecode +caml_ceil_float32_bytecode +caml_classify_float32_bytecode +caml_copysign_float32_bytecode +caml_cos_float32_bytecode +caml_cosh_float32_bytecode +caml_div_float32 +caml_erf_float32_bytecode +caml_erfc_float32_bytecode +caml_exp2_float32_bytecode +caml_exp_float32_bytecode +caml_expm1_float32_bytecode +caml_float32_compare +caml_float32_of_bits_bytecode +caml_float32_of_float +caml_float32_of_int +caml_float32_of_int64_bytecode +caml_float32_of_string +caml_float32_to_bits_bytecode +caml_float32_to_int64_bytecode +caml_float_of_float32 +caml_floor_float32_bytecode +caml_fma_float32_bytecode +caml_fmod_float32_bytecode +caml_format_float32 +caml_frexp_float32 +caml_hypot_float32_bytecode +caml_int_of_float32 +caml_is_boot_compiler +caml_ldexp_float32_bytecode +caml_log10_float32_bytecode +caml_log1p_float32_bytecode +caml_log2_float32_bytecode +caml_log_float32_bytecode +caml_modf_float32 +caml_mul_float32 +caml_neg_float32 +caml_nextafter_float32_bytecode +caml_power_float32_bytecode +caml_round_float32_bytecode +caml_signbit_float32_bytecode +caml_simd_cast_float32_int64_bytecode +caml_simd_float32_max_bytecode +caml_simd_float32_min_bytecode +caml_sin_float32_bytecode +caml_sinh_float32_bytecode +caml_sqrt_float32_bytecode +caml_string_getf32 +caml_sub_float32 +caml_tan_float32_bytecode +caml_tanh_float32_bytecode +caml_trunc_float32_bytecode + From +fs.js: caml_ba_map_file caml_ba_map_file_bytecode @@ -114,6 +200,14 @@ caml_fs_init jsoo_create_file jsoo_create_file_extern +From +gc.js: +caml_eventlog_pause +caml_eventlog_resume +caml_gc_tweak_get +caml_gc_tweak_list_active +caml_gc_tweak_set +caml_memprof_participate + From +graphics.js: caml_gr_arc_aux caml_gr_blit_image @@ -164,11 +258,20 @@ caml_gr_wait_event caml_gr_window_id From +hash.js: +caml_hash_exn caml_hash_mix_int64 +From +int64.js: +caml_array_unsafe_get_indexed_by_int64 +caml_array_unsafe_set_indexed_by_int64 +caml_checked_int64_to_int + From +ints.js: caml_div +caml_int16_of_string +caml_int8_of_string caml_mod +caml_parse_small_int From +jslib.js: caml_is_js @@ -187,6 +290,11 @@ caml_new_string (deprecated) caml_string_concat caml_to_js_string (deprecated) +From +obj.js: +caml_obj_is_stack +caml_obj_uniquely_reachable_words +caml_succ_scannable_prefix_len + From +runtime_events.js: caml_runtime_events_create_cursor caml_runtime_events_free_cursor @@ -196,6 +304,7 @@ caml_runtime_events_user_resolve From +stdlib.js: caml_is_printable caml_maybe_print_stats +caml_with_async_exns From +sys.js: caml_fatal_uncaught_exception @@ -203,6 +312,7 @@ caml_format_exception caml_is_special_exception caml_set_static_env caml_sys_const_naked_pointers_checked +caml_sys_const_runtime5 From +toplevel.js: caml_get_section_table diff --git a/compiler/tests-check-prim/unix-Win32.5.2.output b/compiler/tests-check-prim/unix-Win32.5.2.output deleted file mode 100644 index 931ab94600..0000000000 --- a/compiler/tests-check-prim/unix-Win32.5.2.output +++ /dev/null @@ -1,196 +0,0 @@ -Missing -------- - -From unix.bc: -caml_alloc_dummy_function -caml_assume_no_perform -caml_continuation_use -caml_drop_continuation -caml_int_as_pointer -caml_reset_afl_instrumentation -caml_unix_accept -caml_unix_bind -caml_unix_clear_close_on_exec -caml_unix_clear_nonblock -caml_unix_connect -caml_unix_create_process -caml_unix_dup -caml_unix_dup2 -caml_unix_environment -caml_unix_execv -caml_unix_execve -caml_unix_execvp -caml_unix_execvpe -caml_unix_filedescr_of_channel -caml_unix_getaddrinfo -caml_unix_gethostbyaddr -caml_unix_gethostbyname -caml_unix_gethostname -caml_unix_getnameinfo -caml_unix_getpeername -caml_unix_getpid -caml_unix_getprotobyname -caml_unix_getprotobynumber -caml_unix_getservbyname -caml_unix_getservbyport -caml_unix_getsockname -caml_unix_getsockopt -caml_unix_listen -caml_unix_lockf -caml_unix_map_file_bytecode -caml_unix_pipe -caml_unix_putenv -caml_unix_realpath -caml_unix_recv -caml_unix_recvfrom -caml_unix_select -caml_unix_send -caml_unix_sendto -caml_unix_set_close_on_exec -caml_unix_set_nonblock -caml_unix_setsockopt -caml_unix_shutdown -caml_unix_sleep -caml_unix_socket -caml_unix_socketpair -caml_unix_string_of_inet_addr -caml_unix_system -caml_unix_terminate_process -caml_unix_waitpid -debugger - -Unused -------- - -From +array.js: -caml_check_bound - -From +bigarray.js: -caml_ba_create_from (deprecated) -caml_ba_init - -From +bigstring.js: -caml_bigstring_blit_ba_to_ba -caml_bigstring_blit_ba_to_bytes -caml_bigstring_blit_bytes_to_ba -caml_bigstring_blit_string_to_ba -caml_bigstring_memcmp -caml_hash_mix_bigstring - -From +effect.js: -jsoo_effect_not_supported - -From +fs.js: -caml_ba_map_file -caml_ba_map_file_bytecode -caml_fs_init -jsoo_create_file -jsoo_create_file_extern - -From +graphics.js: -caml_gr_arc_aux -caml_gr_blit_image -caml_gr_clear_graph -caml_gr_close_graph -caml_gr_close_subwindow -caml_gr_create_image -caml_gr_current_x -caml_gr_current_y -caml_gr_display_mode -caml_gr_doc_of_state -caml_gr_draw_arc -caml_gr_draw_char -caml_gr_draw_image -caml_gr_draw_rect -caml_gr_draw_str -caml_gr_draw_string -caml_gr_dump_image -caml_gr_fill_arc -caml_gr_fill_poly -caml_gr_fill_rect -caml_gr_lineto -caml_gr_make_image -caml_gr_moveto -caml_gr_open_graph -caml_gr_open_subwindow -caml_gr_plot -caml_gr_point_color -caml_gr_remember_mode -caml_gr_resize_window -caml_gr_set_color -caml_gr_set_font -caml_gr_set_line_width -caml_gr_set_text_size -caml_gr_set_window_title -caml_gr_sigio_handler -caml_gr_sigio_signal -caml_gr_size_x -caml_gr_size_y -caml_gr_state -caml_gr_state_create -caml_gr_state_get -caml_gr_state_init -caml_gr_state_set -caml_gr_synchronize -caml_gr_text_size -caml_gr_wait_event -caml_gr_window_id - -From +hash.js: -caml_hash_mix_int64 - -From +ints.js: -caml_div -caml_mod - -From +jslib.js: -caml_is_js -caml_trampoline -caml_trampoline_return -caml_wrap_exception - -From +marshal.js: -caml_marshal_constants - -From +mlBytes.js: -caml_array_of_bytes (deprecated) -caml_array_of_string (deprecated) -caml_bytes_of_utf16_jsstring -caml_new_string (deprecated) -caml_string_concat -caml_to_js_string (deprecated) - -From +runtime_events.js: -caml_runtime_events_create_cursor -caml_runtime_events_free_cursor -caml_runtime_events_read_poll -caml_runtime_events_user_resolve - -From +stdlib.js: -caml_is_printable -caml_maybe_print_stats - -From +sys.js: -caml_fatal_uncaught_exception -caml_format_exception -caml_is_special_exception -caml_set_static_env -caml_sys_const_naked_pointers_checked - -From +toplevel.js: -caml_get_section_table -jsoo_get_runtime_aliases -jsoo_toplevel_init_compile -jsoo_toplevel_init_reloc - -From +unix.js: -caml_strerror -caml_unix_fchmod -caml_unix_getegid -caml_unix_geteuid -caml_unix_getgid -caml_unix_getpwnam -caml_unix_getuid -caml_unix_rewinddir -unix_error_message - diff --git a/compiler/tests-compiler/double-translation/dune.inc b/compiler/tests-compiler/double-translation/dune.inc index 1cecd7aa8b..7c0009916a 100644 --- a/compiler/tests-compiler/double-translation/dune.inc +++ b/compiler/tests-compiler/double-translation/dune.inc @@ -21,7 +21,7 @@ (modules effects_continuations) (libraries js_of_ocaml_compiler unix str jsoo_compiler_expect_tests_helper) (inline_tests - (enabled_if true) + (enabled_if (not %{oxcaml_supported})) (deps (file %{project_root}/compiler/bin-js_of_ocaml/js_of_ocaml.exe) (file %{project_root}/compiler/bin-jsoo_minify/jsoo_minify.exe))) @@ -36,7 +36,7 @@ (modules effects_exceptions) (libraries js_of_ocaml_compiler unix str jsoo_compiler_expect_tests_helper) (inline_tests - (enabled_if true) + (enabled_if (not %{oxcaml_supported})) (deps (file %{project_root}/compiler/bin-js_of_ocaml/js_of_ocaml.exe) (file %{project_root}/compiler/bin-jsoo_minify/jsoo_minify.exe))) diff --git a/compiler/tests-compiler/dune.inc b/compiler/tests-compiler/dune.inc index 15229507e1..ae3e86047e 100644 --- a/compiler/tests-compiler/dune.inc +++ b/compiler/tests-compiler/dune.inc @@ -96,7 +96,7 @@ (modules effects) (libraries js_of_ocaml_compiler unix str jsoo_compiler_expect_tests_helper) (inline_tests - (enabled_if true) + (enabled_if (not %{oxcaml_supported})) (deps (file %{project_root}/compiler/bin-js_of_ocaml/js_of_ocaml.exe) (file %{project_root}/compiler/bin-jsoo_minify/jsoo_minify.exe))) @@ -111,7 +111,7 @@ (modules effects_continuations) (libraries js_of_ocaml_compiler unix str jsoo_compiler_expect_tests_helper) (inline_tests - (enabled_if true) + (enabled_if (not %{oxcaml_supported})) (deps (file %{project_root}/compiler/bin-js_of_ocaml/js_of_ocaml.exe) (file %{project_root}/compiler/bin-jsoo_minify/jsoo_minify.exe))) @@ -126,7 +126,7 @@ (modules effects_exceptions) (libraries js_of_ocaml_compiler unix str jsoo_compiler_expect_tests_helper) (inline_tests - (enabled_if true) + (enabled_if (not %{oxcaml_supported})) (deps (file %{project_root}/compiler/bin-js_of_ocaml/js_of_ocaml.exe) (file %{project_root}/compiler/bin-jsoo_minify/jsoo_minify.exe))) @@ -156,7 +156,7 @@ (modules eliminate_exception_handler) (libraries js_of_ocaml_compiler unix str jsoo_compiler_expect_tests_helper) (inline_tests - (enabled_if true) + (enabled_if (not %{oxcaml_supported})) (deps (file %{project_root}/compiler/bin-js_of_ocaml/js_of_ocaml.exe) (file %{project_root}/compiler/bin-jsoo_minify/jsoo_minify.exe))) @@ -231,7 +231,7 @@ (modules exceptions) (libraries js_of_ocaml_compiler unix str jsoo_compiler_expect_tests_helper) (inline_tests - (enabled_if true) + (enabled_if (not %{oxcaml_supported})) (deps (file %{project_root}/compiler/bin-js_of_ocaml/js_of_ocaml.exe) (file %{project_root}/compiler/bin-jsoo_minify/jsoo_minify.exe))) @@ -336,7 +336,7 @@ (modules gh1354) (libraries js_of_ocaml_compiler unix str jsoo_compiler_expect_tests_helper) (inline_tests - (enabled_if true) + (enabled_if (not %{oxcaml_supported})) (deps (file %{project_root}/compiler/bin-js_of_ocaml/js_of_ocaml.exe) (file %{project_root}/compiler/bin-jsoo_minify/jsoo_minify.exe))) @@ -456,7 +456,7 @@ (modules gh1868) (libraries js_of_ocaml_compiler unix str jsoo_compiler_expect_tests_helper) (inline_tests - (enabled_if true) + (enabled_if (not %{oxcaml_supported})) (deps (file %{project_root}/compiler/bin-js_of_ocaml/js_of_ocaml.exe) (file %{project_root}/compiler/bin-jsoo_minify/jsoo_minify.exe))) @@ -486,7 +486,7 @@ (modules gh747) (libraries js_of_ocaml_compiler unix str jsoo_compiler_expect_tests_helper) (inline_tests - (enabled_if true) + (enabled_if (not %{oxcaml_supported})) (deps (file %{project_root}/compiler/bin-js_of_ocaml/js_of_ocaml.exe) (file %{project_root}/compiler/bin-jsoo_minify/jsoo_minify.exe))) @@ -516,7 +516,7 @@ (modules global_deadcode) (libraries js_of_ocaml_compiler unix str jsoo_compiler_expect_tests_helper) (inline_tests - (enabled_if true) + (enabled_if (not %{oxcaml_supported})) (deps (file %{project_root}/compiler/bin-js_of_ocaml/js_of_ocaml.exe) (file %{project_root}/compiler/bin-jsoo_minify/jsoo_minify.exe))) @@ -606,7 +606,7 @@ (modules loops) (libraries js_of_ocaml_compiler unix str jsoo_compiler_expect_tests_helper) (inline_tests - (enabled_if true) + (enabled_if (not %{oxcaml_supported})) (deps (file %{project_root}/compiler/bin-js_of_ocaml/js_of_ocaml.exe) (file %{project_root}/compiler/bin-jsoo_minify/jsoo_minify.exe))) @@ -681,7 +681,7 @@ (modules obj) (libraries js_of_ocaml_compiler unix str jsoo_compiler_expect_tests_helper) (inline_tests - (enabled_if (>= %{ocaml_version} 5)) + (enabled_if (and (>= %{ocaml_version} 5) (not %{oxcaml_supported}))) (deps (file %{project_root}/compiler/bin-js_of_ocaml/js_of_ocaml.exe) (file %{project_root}/compiler/bin-jsoo_minify/jsoo_minify.exe))) diff --git a/compiler/tests-compiler/error.ml b/compiler/tests-compiler/error.ml index 2faf9b1131..bf67ae1aa0 100644 --- a/compiler/tests-compiler/error.ml +++ b/compiler/tests-compiler/error.ml @@ -46,7 +46,9 @@ let%expect_test "uncaugh error" = let prog = {| let null = Array.unsafe_get [|1|] 1 -let () = Callback.register "Printexc.handle_uncaught_exception" null +let () = + (Callback.register [@ocaml.alert "-unsafe_multidomain"]) + "Printexc.handle_uncaught_exception" null exception C let _ = raise C |} in @@ -61,7 +63,9 @@ let _ = raise C |} let prog = {| let null = Array.unsafe_get [|1|] 1 -let () = Callback.register "Printexc.handle_uncaught_exception" null +let () = + (Callback.register [@ocaml.alert "-unsafe_multidomain"]) + "Printexc.handle_uncaught_exception" null exception D of int * string * Int64.t let _ = raise (D(2,"test",43L)) |} @@ -77,37 +81,45 @@ let _ = raise (D(2,"test",43L)) let prog = {| let null = Array.unsafe_get [|1|] 1 -let () = Callback.register "Printexc.handle_uncaught_exception" null +let () = + (Callback.register [@ocaml.alert "-unsafe_multidomain"]) + "Printexc.handle_uncaught_exception" null let _ = assert false |} in compile_and_run prog; print_endline (normalize [%expect.output]); [%expect {| - Fatal error: exception Assert_failure("test.ml", 4, 8) + Fatal error: exception Assert_failure("test.ml", 6, 8) process exited with error code 2 - %{NODE} test.js |}]; + %{NODE} test.js + |}]; let prog = {| let null = Array.unsafe_get [|1|] 1 -let () = Callback.register "Printexc.handle_uncaught_exception" null +let () = + (Callback.register [@ocaml.alert "-unsafe_multidomain"]) + "Printexc.handle_uncaught_exception" null [@@@ocaml.warning "-8"] let _ = match 3 with 2 -> () |} in compile_and_run prog; print_endline (normalize [%expect.output]); [%expect {| - Fatal error: exception Match_failure("test.ml", 4, 33) + Fatal error: exception Match_failure("test.ml", 6, 33) process exited with error code 2 - %{NODE} test.js |}]; + %{NODE} test.js + |}]; (* Uncaught javascript exception *) let prog = {| let null : _ -> _ -> _ = Array.unsafe_get [||] 0 -let () = Callback.register "Printexc.handle_uncaught_exception" null +let () = + (Callback.register [@ocaml.alert "-unsafe_multidomain"]) + "Printexc.handle_uncaught_exception" null exception D of int * string * Int64.t let _ = null 1 2 |} diff --git a/compiler/tests-compiler/gen-rules/gen.ml b/compiler/tests-compiler/gen-rules/gen.ml index 2595d3adac..44dd26d349 100644 --- a/compiler/tests-compiler/gen-rules/gen.ml +++ b/compiler/tests-compiler/gen-rules/gen.ml @@ -51,6 +51,8 @@ type enabled_if = | GE52 | LT52 | B64 + | NotOxCaml + | GE5NotOxCaml | Any let lib_enabled_if = function @@ -59,10 +61,21 @@ let lib_enabled_if = function | _ -> Any let test_enabled_if = function - | "obj" | "lazy" -> GE5 + | "obj" -> GE5NotOxCaml (* Some Obj functions are no longer primitives *) + | "lazy" -> GE5 | "gh1051" -> B64 | "rec52" -> GE52 | "rec" -> LT52 + | "gh1354" + | "gh1868" + | "exceptions" + | "effects_continuations" + | "effects_exceptions" + | "eliminate_exception_handler" + | "loops" + | "global_deadcode" -> NotOxCaml (* In OxCaml, raise is always reraise *) + | "effects" -> NotOxCaml (* Call to Printf.printf is somehow compiled differently *) + | "gh747" -> NotOxCaml (* More debug locations *) | _ -> Any let enabled_if = function @@ -71,6 +84,8 @@ let enabled_if = function | GE52 -> "(>= %{ocaml_version} 5.2)" | LT52 -> "(< %{ocaml_version} 5.2)" | B64 -> "%{arch_sixtyfour}" + | GE5NotOxCaml -> "(and (>= %{ocaml_version} 5) (not %{oxcaml_supported}))" + | NotOxCaml -> "(not %{oxcaml_supported})" let () = Array.to_list (Sys.readdir ".") diff --git a/compiler/tests-full/dune b/compiler/tests-full/dune index b609f1bd16..76a8951636 100644 --- a/compiler/tests-full/dune +++ b/compiler/tests-full/dune @@ -12,6 +12,8 @@ var --debuginfo %{lib:stdlib:stdlib.cma} + --enable + use-js-string -o %{targets}))) @@ -53,6 +55,8 @@ --pretty --debuginfo %{dep:shapes.cma} + --enable + use-js-string -o %{targets}))) diff --git a/compiler/tests-jsoo/bin/error1.ml b/compiler/tests-jsoo/bin/error1.ml index 2a2e6504ac..d773d7e068 100644 --- a/compiler/tests-jsoo/bin/error1.ml +++ b/compiler/tests-jsoo/bin/error1.ml @@ -8,7 +8,7 @@ let () = exception D of int * string * Int64.t let _ = - Printexc.register_printer (function + (Printexc.register_printer [@ocaml.alert "-unsafe_multidomain"]) (function | D _ -> Some "custom printer" | _ -> None) diff --git a/compiler/tests-jsoo/dune b/compiler/tests-jsoo/dune index 60c7a46832..cbaa22152e 100644 --- a/compiler/tests-jsoo/dune +++ b/compiler/tests-jsoo/dune @@ -20,7 +20,9 @@ (modules test_marshal_compressed) (libraries unix compiler-libs.common js_of_ocaml-compiler) (enabled_if - (>= %{ocaml_version} 5.1.1)) + (and + (>= %{ocaml_version} 5.1.1) + (not %{oxcaml_supported}))) (inline_tests (modes js wasm best)) (preprocess @@ -37,6 +39,26 @@ (preprocess (pps ppx_expect))) +(library + (name jsoo_testsuite_float32_js) + (modules test_marshal_float32_js) + (libraries unix compiler-libs.common js_of_ocaml-compiler) + (enabled_if %{oxcaml_supported}) + (inline_tests + (modes js)) + (preprocess + (pps ppx_expect))) + +(library + (name jsoo_testsuite_float32) + (modules test_marshal_float32) + (libraries unix compiler-libs.common js_of_ocaml-compiler) + (enabled_if %{oxcaml_supported}) + (inline_tests + (modes wasm best)) + (preprocess + (pps ppx_expect))) + (library (name jsoo_testsuite) (modules @@ -47,6 +69,8 @@ test_float16 test_bigarray test_marshal_compressed + test_marshal_float32 + test_marshal_float32_js test_parsing calc_parser calc_lexer)) diff --git a/compiler/tests-jsoo/gh_1307.ml b/compiler/tests-jsoo/gh_1307.ml index 6ac526d6e0..1d8de8c9eb 100644 --- a/compiler/tests-jsoo/gh_1307.ml +++ b/compiler/tests-jsoo/gh_1307.ml @@ -5,9 +5,7 @@ let test content = | n -> Printf.printf "%d\n" n; print_endline "success" - | exception e -> - print_endline (Printexc.to_string e); - print_endline "failure" + | exception Parsing.Parse_error -> print_endline "Parse_error" let%expect_test "parsing" = (* use [Parsing.set_trace true] once https://github.com/janestreet/ppx_expect/issues/43 is fixed *) @@ -15,8 +13,7 @@ let%expect_test "parsing" = test "a"; [%expect {| input: "a" - Stdlib.Parsing.Parse_error - failure |}]; + Parse_error |}]; test "aa"; [%expect {| input: "aa" @@ -25,7 +22,6 @@ let%expect_test "parsing" = test "aaa"; [%expect {| input: "aaa" - Stdlib.Parsing.Parse_error - failure |}]; + Parse_error |}]; let (_ : bool) = Parsing.set_trace old in () diff --git a/compiler/tests-jsoo/lib-effects/test_domain.ml b/compiler/tests-jsoo/lib-effects/test_domain.ml index a63b5c5ffb..163008fbb5 100644 --- a/compiler/tests-jsoo/lib-effects/test_domain.ml +++ b/compiler/tests-jsoo/lib-effects/test_domain.ml @@ -1,3 +1,5 @@ +[@@@ocaml.alert "-unsafe_parallelism-unsafe_multidomain-do_not_spawn_domains"] + let%expect_test _ = let d = Domain.spawn (fun () -> 1 + 2) in print_int (Domain.join d); diff --git a/compiler/tests-jsoo/test_marshal_float32.ml b/compiler/tests-jsoo/test_marshal_float32.ml new file mode 100644 index 0000000000..385e13bd2b --- /dev/null +++ b/compiler/tests-jsoo/test_marshal_float32.ml @@ -0,0 +1,32 @@ +(* In javascript, float32s are represented as floats. + In native code and wasm, float32s are custom blocks containing a float32 field. *) + +external float_of_float32 : float32 -> float = "%floatoffloat32" + +type float64s = + { a : float + ; b : float + } + +let%expect_test ("float64 wasm" [@tags "wasm-only"]) = + let f64 = Marshal.to_string { a = 123.; b = 456. } [] in + Printf.printf "%S" f64; + [%expect + {| "\132\149\166\190\000\000\000\018\000\000\000\001\000\000\000\005\000\000\000\003\014\002\000\000\000\000\000\192^@\000\000\000\000\000\128|@" |}]; + let f64 : float64s = Marshal.from_string f64 0 in + Printf.printf "%f %f" f64.a f64.b; + [%expect {| 123.000000 456.000000 |}] + +type float32s = + { a : float32 + ; b : float32 + } + +let%expect_test ("float32 wasm" [@tags "wasm-only"]) = + let f32 = Marshal.to_string { a = 123.s; b = 456.s } [] in + Printf.printf "%S" f32; + [%expect + {| "\132\149\166\190\000\000\000\021\000\000\000\003\000\000\000\t\000\000\000\t\160\025_f32\000B\246\000\000\025_f32\000C\228\000\000" |}]; + let f32 : float32s = Marshal.from_string f32 0 in + Printf.printf "%f %f" (float_of_float32 f32.a) (float_of_float32 f32.b); + [%expect {| 123.000000 456.000000 |}] diff --git a/compiler/tests-jsoo/test_marshal_float32_js.ml b/compiler/tests-jsoo/test_marshal_float32_js.ml new file mode 100644 index 0000000000..b2047b4fe7 --- /dev/null +++ b/compiler/tests-jsoo/test_marshal_float32_js.ml @@ -0,0 +1,32 @@ +(* In javascript, float32s are represented as floats. + In native code and wasm, float32s are custom blocks containing a float32 field. *) + +external float_of_float32 : float32 -> float = "%floatoffloat32" + +type float64s = + { a : float + ; b : float + } + +let%expect_test ("float64 javascript" [@tags "js-only", "no-wasm"]) = + let f64 = Marshal.to_string { a = 123.; b = 456. } [] in + Printf.printf "%S" f64; + [%expect + {| "\132\149\166\190\000\000\000\n\000\000\000\001\000\000\000\003\000\000\000\003\b\000\000\b\254\000{\001\001\200" |}]; + let f64 : float64s = Marshal.from_string f64 0 in + Printf.printf "%f %f" f64.a f64.b; + [%expect {| 123.000000 456.000000 |}] + +type float32s = + { a : float32 + ; b : float32 + } + +let%expect_test ("float32 javascript" [@tags "js-only", "no-wasm"]) = + let f32 = Marshal.to_string { a = 123.s; b = 456.s } [] in + Printf.printf "%S" f32; + [%expect + {| "\132\149\166\190\000\000\000\006\000\000\000\001\000\000\000\003\000\000\000\003\160\000{\001\001\200" |}]; + let f32 : float32s = Marshal.from_string f32 0 in + Printf.printf "%f %f" (float_of_float32 f32.a) (float_of_float32 f32.b); + [%expect {| 123.000000 456.000000 |}] diff --git a/compiler/tests-linkall/dune b/compiler/tests-linkall/dune index 5d1fd7d45f..dbfe6e4c78 100644 --- a/compiler/tests-linkall/dune +++ b/compiler/tests-linkall/dune @@ -5,6 +5,9 @@ (js_of_ocaml (compilation_mode separate)) (wasm_of_ocaml + ; dynlink not compiling + (enabled_if + (not %{oxcaml_supported})) (compilation_mode separate)))) (test diff --git a/compiler/tests-ocaml/basic-more/dune b/compiler/tests-ocaml/basic-more/dune index a92fb3ebc2..47e7802dfd 100644 --- a/compiler/tests-ocaml/basic-more/dune +++ b/compiler/tests-ocaml/basic-more/dune @@ -4,7 +4,6 @@ div_by_zero function_in_ref if_in_if - labels_evaluation_order morematch opaque_prim pr10294 @@ -24,3 +23,12 @@ (build_if (>= %{ocaml_version} 5.2)) (modes js wasm)) + +(tests + (names labels_evaluation_order) + (libraries ocaml_testing) + (build_if + (and + (>= %{ocaml_version} 5.2) + (not %{oxcaml_supported}))) + (modes js wasm)) diff --git a/compiler/tests-ocaml/basic/pr7253.ml b/compiler/tests-ocaml/basic/pr7253.ml index 23c51f21a5..cce90e148a 100644 --- a/compiler/tests-ocaml/basic/pr7253.ml +++ b/compiler/tests-ocaml/basic/pr7253.ml @@ -6,7 +6,7 @@ exception My_exception let () = - Printexc.set_uncaught_exception_handler (fun exn bt -> + (Printexc.set_uncaught_exception_handler [@ocaml.alert "-unsafe_multidomain"]) (fun exn bt -> match exn with | My_exception -> print_endline "Caught"; exit 0 | _ -> print_endline "Unexpected uncaught exception"); diff --git a/compiler/tests-ocaml/effects/test_lazy.ml b/compiler/tests-ocaml/effects/test_lazy.ml index 24f457f0af..4fdfb33173 100644 --- a/compiler/tests-ocaml/effects/test_lazy.ml +++ b/compiler/tests-ocaml/effects/test_lazy.ml @@ -3,6 +3,8 @@ open Effect open Effect.Deep +[@@@ocaml.alert "-unsafe_parallelism-unsafe_multidomain-do_not_spawn_domains"] + type _ t += Stop : unit t let f count = diff --git a/compiler/tests-ocaml/expect.ml b/compiler/tests-ocaml/expect.ml index 793f0968e3..809c31b1a5 100644 --- a/compiler/tests-ocaml/expect.ml +++ b/compiler/tests-ocaml/expect.ml @@ -1,7 +1,7 @@ let () = Js_of_ocaml_toplevel.JsooTop.initialize () -let () = Printexc.register_printer (fun x -> +let () = (Printexc.register_printer[@ocaml.alert "-unsafe_multidomain"]) (fun x -> match Js_of_ocaml.Js_error.of_exn x with | None -> None | Some e -> Some (Js_of_ocaml.Js_error.message e)) diff --git a/compiler/tests-ocaml/lazy/lazy2.ml b/compiler/tests-ocaml/lazy/lazy2.ml index e386b97d6a..0734d58eda 100644 --- a/compiler/tests-ocaml/lazy/lazy2.ml +++ b/compiler/tests-ocaml/lazy/lazy2.ml @@ -3,6 +3,7 @@ *) open Domain +[@@@ocaml.alert "-unsafe_multidomain-unsafe_parallelism-do_not_spawn_domains"] let () = let l = lazy (print_string "Lazy Forced\n") in diff --git a/compiler/tests-ocaml/lazy/lazy5.ml b/compiler/tests-ocaml/lazy/lazy5.ml index 4a8ac59fff..1c99dd17c1 100644 --- a/compiler/tests-ocaml/lazy/lazy5.ml +++ b/compiler/tests-ocaml/lazy/lazy5.ml @@ -1,6 +1,8 @@ (* TEST ocamlopt_flags += " -O3 "; *) +[@@@ocaml.alert "-unsafe_multidomain-unsafe_parallelism-do_not_spawn_domains"] + let rec safe_force l = try Lazy.force l with | Lazy.Undefined -> diff --git a/compiler/tests-ocaml/lazy/lazy8.ml b/compiler/tests-ocaml/lazy/lazy8.ml index 1ecf578fad..538f68bc11 100644 --- a/compiler/tests-ocaml/lazy/lazy8.ml +++ b/compiler/tests-ocaml/lazy/lazy8.ml @@ -1,6 +1,7 @@ (* TEST ocamlopt_flags += " -O3 "; *) +[@@@ocaml.alert "-unsafe_multidomain-unsafe_parallelism-do_not_spawn_domains"] exception E diff --git a/compiler/tests-ocaml/lib-marshal/dune b/compiler/tests-ocaml/lib-marshal/dune index d9abe8be7d..a361a821b5 100644 --- a/compiler/tests-ocaml/lib-marshal/dune +++ b/compiler/tests-ocaml/lib-marshal/dune @@ -2,7 +2,9 @@ (names compressed) (libraries compiler-libs.common) (build_if - (>= %{ocaml_version} 5.2)) + (and + (>= %{ocaml_version} 5.2) + (not %{oxcaml_supported}))) (modes js wasm)) (tests diff --git a/compiler/tests-ocaml/lib-marshal/intext_par.ml b/compiler/tests-ocaml/lib-marshal/intext_par.ml index f93c55c685..bb4da7f89d 100644 --- a/compiler/tests-ocaml/lib-marshal/intext_par.ml +++ b/compiler/tests-ocaml/lib-marshal/intext_par.ml @@ -9,6 +9,8 @@ } *) +[@@@ocaml.alert "-unsafe_multidomain-unsafe_parallelism-do_not_spawn_domains"] + (* Test for output_value / input_value *) let test_size = diff --git a/compiler/tests-oxcaml/lib-float32/.ocamlformat b/compiler/tests-oxcaml/lib-float32/.ocamlformat new file mode 100644 index 0000000000..593b6a1ffc --- /dev/null +++ b/compiler/tests-oxcaml/lib-float32/.ocamlformat @@ -0,0 +1 @@ +disable diff --git a/compiler/tests-oxcaml/lib-float32/dune b/compiler/tests-oxcaml/lib-float32/dune new file mode 100644 index 0000000000..52b7defa2c --- /dev/null +++ b/compiler/tests-oxcaml/lib-float32/dune @@ -0,0 +1,5 @@ +(tests + (names test float32_lib) + (build_if %{oxcaml_supported}) + (libraries stdlib_stable) + (modes byte js wasm)) diff --git a/compiler/tests-oxcaml/lib-float32/float32_lib.ml b/compiler/tests-oxcaml/lib-float32/float32_lib.ml new file mode 100644 index 0000000000..13d4a57715 --- /dev/null +++ b/compiler/tests-oxcaml/lib-float32/float32_lib.ml @@ -0,0 +1,651 @@ +[@@@ocaml.warning "-unused-value-declaration"] + +[@@@ocaml.warning "-unused-module"] + +(* Tests for the float32 otherlib *) + +module F32 = Stdlib_stable.Float32 + +module CF32 = struct + open F32 + let check_float32s f = + Random.set_state (Random.State.make [| 123456789 |]); + let neg_one = -1.s in + let neg_zero = -0.s in + f zero zero; + f zero one; + f one one; + f zero neg_one; + f neg_one neg_one; + f one neg_one; + f zero neg_zero; + f neg_zero zero; + f nan zero; + f infinity zero; + f neg_infinity zero; + f nan nan; + f infinity infinity; + f neg_infinity neg_infinity; + f neg_infinity infinity; + f infinity nan; + f neg_infinity nan; + f max_float infinity; + f max_float neg_infinity; + f min_float infinity; + f min_float neg_infinity; + f max_float max_float; + f min_float min_float; + f max_float min_float; + for _ = 0 to 100_000 do + let f0 = Random.int32 Int32.max_int in + let f1 = Random.int32 Int32.max_int in + f + ((if Random.bool () then f0 else Int32.neg f0) + |> Int32.float_of_bits |> F32.of_float) + ((if Random.bool () then f1 else Int32.neg f1) + |> Int32.float_of_bits |> F32.of_float) + done +end + +let bit_eq f1 f2 = + assert (F32.to_bits f1 = F32.to_bits f2 || (F32.is_nan f1 && F32.is_nan f2)) + +let () = + (* In glibc 2.25+, powf(nan, zero) returns one if the nan is non-signaling. *) + bit_eq (F32.pow F32.nan F32.zero) F32.one; + bit_eq (F32.pow F32.quiet_nan F32.zero) F32.one + +let () = + CF32.check_float32s (fun f _ -> + assert (F32.seeded_hash 42 f = Hashtbl.seeded_hash 42 f); + assert (F32.hash f = Hashtbl.hash f)) + +let () = + try + ignore (F32.of_string ""); + assert false + with Failure msg -> ( + assert (msg = "float32_of_string"); + try + ignore (F32.of_string "a"); + assert false + with Failure msg -> ( + assert (msg = "float32_of_string"); + try + ignore (F32.of_string "0.0.0"); + assert false + with Failure msg -> ( + assert (msg = "float32_of_string"); + try + ignore (F32.of_string "0xzz"); + assert false + with Failure msg -> ( + assert (msg = "float32_of_string"); + try + ignore (F32.of_string "1e10.0"); + assert false + with Failure msg -> + assert (msg = "float32_of_string"); + assert (Option.is_none (F32.of_string_opt "")); + assert (Option.is_none (F32.of_string_opt "a")); + assert (Option.is_none (F32.of_string_opt "0.0.0")); + assert (Option.is_none (F32.of_string_opt "0xzz")); + assert (Option.is_none (F32.of_string_opt "1e10.0")))))) + +external format : string -> float32 -> string = "caml_format_float32" + +(* [to_string] calls format with "%.9g"; these are some additional format string + tests. *) +let () = + assert (format "%.0g" 0.1234s = "0.1"); + assert (format "%.1g" 0.1234s = "0.1"); + assert (format "%.2g" 0.1234s = "0.12"); + assert (format "%.3g" 0.1234s = "0.123"); + assert (format "%f" 0.1234s = "0.123400"); + assert (format "%f" 1024.s = "1024.000000"); + assert (format "%f" 1e10s = "10000000000.000000"); + assert (format "%g" 1e20s = "1e+20"); + assert (format "%g" 1e-20s = "1e-20"); + assert (format "%f" F32.infinity = "inf"); + assert (format "%f" F32.neg_infinity = "-inf"); + assert (format "%f" F32.nan = "nan") + +let () = + CF32.check_float32s (fun f _ -> + bit_eq (F32.of_string (F32.to_string f)) f; + match F32.of_string_opt (F32.to_string f) with + | None -> assert false + | Some f' -> bit_eq f f'); + let check s f = bit_eq (F32.of_string s) f in + check "0.0" 0.0s; + check "1.0" 1.0s; + check "0.5" 0.5s; + check "1234.1234" 1234.1234s; + check "0." 0.s; + check "1e10" 1e10s; + check "1e-9_8" 1e-9_8s; + check "1e+1" 1e+1s; + check "1.12345e+12" 1.12345e+12s; + check "0x2_2p+0" 0x22p+0s; + check "0x2p+0" 0x2p+0s; + check "0x3p+0" 0x3p+0s; + check "0x5p+0" 0x5p+0s; + check "0x1.4p+0" 0x1.4p+0s; + check "0xcp-4" 0xcp-4s; + check "0x1p-4" 0x1p-4s; + check "0x1p+0" 0x1p+0s; + check "0x0p+0" 0x0p+0s; + check "0xf.f___ffffp+124" 0xf.fffffp+124s; + check "0xf.ffffffffffff8p+1020" 0xf.ffffffffffff8p+1020s; + check "0x4p-128" 0x4p-128s; + check "0x1p-252" 0x1p-252s; + check "0x4p-1024" 0x4p-1024s; + check "0x8p-972" 0x8p-972s; + check "0xf.fff_f_e_000001p+252" 0xf.ff_ffe_00_0001p+252s; + check "0x2.fffp+12" 0x2.fffp+12s; + check "0x1.ffffp-24" 0x1.ffffp-24s; + check "0x2._fff006p+12" 0x2._fff006p+12s; + check "0x1.fffp+0" 0x1.fffp+0s; + check "0x1.00001p+0" 0x1.00001p+0s; + check "0xc.d5e6fp+1_24" 0xc.d5e6fp+1_24s; + check "0x2.6af378p-128" 0x2.6af378p-128s; + check "0x5p-128" 0x5p-128s; + check "0x1____p-128" 0x1p-128s; + check "0x8p-152" 0x8p-152s; + check "0x8p-4" 0x8p-4s; + check "0x8p+124" 0x8p+124s; + check "0x1000002p+0" 0x1000002p+0s; + check "0x1000003p+0" 0x1000003p+0s; + check "0x100000fp+0" 0x100000fp+0s; + check "0x10000001p+0" 0x10000001p+0s; + check "0x10000002p+0" 0x10000002p+0s; + check "0x10000003p+0" 0x10000003p+0s; + check "0x1000000fp+0" 0x1000000fp+0s; + check "0x1000003fp+0" 0x1000003fp+0s; + check "0x1000002fp+0" 0x1000002fp+0s; + check "0x1.000002p+0" 0x1.000002p+0s; + check "0x1.000003p+0" 0x1.000003p+0s; + check "0x1.00000fp+0" 0x1.00000fp+0s; + check "0x1.0000001p+0" 0x1.0000001p+0s; + check "0x1.0000002p+0" 0x1.0000002p+0s; + check "0x1.0000003p+0" 0x1.0000003p+0s; + check "0x1.000000fp+0" 0x1.000000fp+0s; + check "0x1.000002fp+0" 0x1.000002fp+0s; + check "0x1.00000200p+0" 0x1.00000200p+0s; + check "0x1.000002001p+0" 0x1.000002001p+0s; + check "0x1.000002000000000p+0" 0x1.000002000000000p+0s; + check "0x1.000002000000001p+0" 0x1.000002000000001p+0s; + check "0x1.00000200000000000000p+0" 0x1.00000200000000000000p+0s; + check "0x1.00000200000000000001p+0" 0x1.00000200000000000001p+0s; + check "0x1.000003p+0" 0x1.000003p+0s + +module Bytes = struct + let data = Bytes.of_string "\x00\x01\x02\x03\x04\x05\x06\x07" + + let low = F32.of_bits 0x03020100l + + let high = F32.of_bits 0x07060504l + + (* Getters *) + + let () = + let v = F32.Bytes.get data ~pos:0 in + bit_eq low v; + let v = F32.Bytes.unsafe_get data ~pos:0 in + bit_eq low v; + let v = F32.Bytes.get data ~pos:4 in + bit_eq high v; + let v = F32.Bytes.unsafe_get data ~pos:4 in + bit_eq high v + + let () = + for bad = -4 to -1 do + try + let _ = F32.Bytes.get data ~pos:bad in + assert false + with Invalid_argument s when s = "index out of bounds" -> () + done; + for bad = 5 to 9 do + try + let _ = F32.Bytes.get data ~pos:bad in + assert false + with Invalid_argument s when s = "index out of bounds" -> () + done + + (* Setters *) + + let set f pos = + F32.Bytes.set data f ~pos; + let v = F32.Bytes.get data ~pos in + bit_eq f v + + let set_unsafe f pos = + F32.Bytes.unsafe_set data f ~pos; + let v = F32.Bytes.get data ~pos in + bit_eq f v + + let () = + set (F32.of_bits 0x10101010l) 0; + set (F32.of_bits 0x20202020l) 4; + set_unsafe (F32.of_bits 0x10101010l) 0; + set_unsafe (F32.of_bits 0x20202020l) 4; + Random.init 1234; + for _ = 1 to 1000 do + set (Random.int32 Int32.max_int |> F32.of_bits) (Random.int 5); + set_unsafe (Random.int32 Int32.max_int |> F32.of_bits) (Random.int 5) + done + + let () = + let set = F32.of_bits 0xFFFFFFFFl in + for bad = -4 to -1 do + try + let _ = F32.Bytes.set data set ~pos:bad in + assert false + with Invalid_argument s when s = "index out of bounds" -> () + done; + for bad = 5 to 9 do + try + let _ = F32.Bytes.set data set ~pos:bad in + assert false + with Invalid_argument s when s = "index out of bounds" -> () + done +end + +module String = struct + let data = "\x00\x01\x02\x03\x04\x05\x06\x07" + + let low = F32.of_bits 0x03020100l + + let high = F32.of_bits 0x07060504l + + (* Getters *) + + let () = + let v = F32.String.get data ~pos:0 in + bit_eq low v; + let v = F32.String.unsafe_get data ~pos:0 in + bit_eq low v; + let v = F32.String.get data ~pos:4 in + bit_eq high v; + let v = F32.String.unsafe_get data ~pos:4 in + bit_eq high v + + let () = + for bad = -4 to -1 do + try + let _ = F32.String.get data ~pos:bad in + assert false + with Invalid_argument s when s = "index out of bounds" -> () + done; + for bad = 5 to 9 do + try + let _ = F32.String.get data ~pos:bad in + assert false + with Invalid_argument s when s = "index out of bounds" -> () + done +end + +module Bigstring = struct + open Bigarray + + let bigstring_of_string s = + let open Stdlib in + let a = Array1.create char c_layout (String.length s) in + for i = 0 to String.length s - 1 do + a.{i} <- s.[i] + done; + a + + let data = bigstring_of_string "\x00\x01\x02\x03\x04\x05\x06\x07" + + let low = F32.of_bits 0x03020100l + + let high = F32.of_bits 0x07060504l + + (* Getters *) + + let () = + let v = F32.Bigstring.get data ~pos:0 in + bit_eq low v; + let v = F32.Bigstring.unsafe_get data ~pos:0 in + bit_eq low v; + let v = F32.Bigstring.get data ~pos:4 in + bit_eq high v; + let v = F32.Bigstring.unsafe_get data ~pos:4 in + bit_eq high v + + let () = + for bad = -4 to -1 do + try + let _ = F32.Bigstring.get data ~pos:bad in + assert false + with Invalid_argument s when s = "index out of bounds" -> () + done; + for bad = 5 to 9 do + try + let _ = F32.Bigstring.get data ~pos:bad in + assert false + with Invalid_argument s when s = "index out of bounds" -> () + done + + (* Setters *) + + let set f pos = + F32.Bigstring.set data f ~pos; + let v = F32.Bigstring.get data ~pos in + bit_eq f v + + let set_unsafe f pos = + F32.Bigstring.unsafe_set data f ~pos; + let v = F32.Bigstring.get data ~pos in + bit_eq f v + + let () = + set (F32.of_bits 0x10101010l) 0; + set (F32.of_bits 0x20202020l) 4; + set_unsafe (F32.of_bits 0x10101010l) 0; + set_unsafe (F32.of_bits 0x20202020l) 4; + Random.init 1234; + for _ = 1 to 1000 do + set (Random.int32 Int32.max_int |> F32.of_bits) (Random.int 5); + set_unsafe (Random.int32 Int32.max_int |> F32.of_bits) (Random.int 5) + done + + let () = + let set = F32.of_bits 0xFFFFFFFFl in + for bad = -4 to -1 do + try + let _ = F32.Bigstring.set data set ~pos:bad in + assert false + with Invalid_argument s when s = "index out of bounds" -> () + done; + for bad = 5 to 9 do + try + let _ = F32.Bigstring.set data set ~pos:bad in + assert false + with Invalid_argument s when s = "index out of bounds" -> () + done +end + +module Bigarray = struct + open Stdlib.Bigarray + + module A1 = struct + let c_array = Array1.init Float32 C_layout 4 Float.of_int + + let f_array = Array1.init Float32 Fortran_layout 4 Float.of_int + + let () = + let v = F32.Bigarray.Array1.get c_array 0 in + bit_eq 0.0s v; + let v = F32.Bigarray.Array1.unsafe_get c_array 0 in + bit_eq 0.0s v; + let v = F32.Bigarray.Array1.get c_array 3 in + bit_eq 3.0s v; + let v = F32.Bigarray.Array1.unsafe_get c_array 3 in + bit_eq 3.0s v + + let () = + let v = F32.Bigarray.Array1.get f_array 1 in + bit_eq 1.0s v; + let v = F32.Bigarray.Array1.unsafe_get f_array 1 in + bit_eq 1.0s v; + let v = F32.Bigarray.Array1.get f_array 4 in + bit_eq 4.0s v; + let v = F32.Bigarray.Array1.unsafe_get f_array 4 in + bit_eq 4.0s v + + let set array f pos = + F32.Bigarray.Array1.set array pos f; + let v = F32.Bigarray.Array1.get array pos in + bit_eq f v + + let set_unsafe array f pos = + F32.Bigarray.Array1.unsafe_set array pos f; + let v = F32.Bigarray.Array1.get array pos in + bit_eq f v + + let () = + set c_array (F32.of_bits 0x10101010l) 0; + set c_array (F32.of_bits 0x20202020l) 1; + set_unsafe c_array (F32.of_bits 0x10101010l) 2; + set_unsafe c_array (F32.of_bits 0x20202020l) 3; + Random.init 1234; + for _ = 1 to 1000 do + set c_array (Random.int32 Int32.max_int |> F32.of_bits) (Random.int 4); + set_unsafe c_array + (Random.int32 Int32.max_int |> F32.of_bits) + (Random.int 4) + done; + set f_array (F32.of_bits 0x10101010l) 1; + set f_array (F32.of_bits 0x20202020l) 2; + set_unsafe f_array (F32.of_bits 0x10101010l) 3; + set_unsafe f_array (F32.of_bits 0x20202020l) 4; + Random.init 1234; + for _ = 1 to 1000 do + set f_array + (Random.int32 Int32.max_int |> F32.of_bits) + (1 + Random.int 4); + set_unsafe f_array + (Random.int32 Int32.max_int |> F32.of_bits) + (1 + Random.int 4) + done + + let () = + let check f = + try + f () |> ignore; + assert false + with Invalid_argument s when s = "index out of bounds" -> () + in + check (fun () -> F32.Bigarray.Array1.get c_array (-1)); + check (fun () -> F32.Bigarray.Array1.set c_array (-1) 0.0s); + check (fun () -> F32.Bigarray.Array1.get c_array 4); + check (fun () -> F32.Bigarray.Array1.set c_array 4 0.0s); + check (fun () -> F32.Bigarray.Array1.get f_array 0); + check (fun () -> F32.Bigarray.Array1.set f_array 0 0.0s); + check (fun () -> F32.Bigarray.Array1.get f_array 5); + check (fun () -> F32.Bigarray.Array1.set f_array 5 0.0s) + end + + module A2 = struct + let c_array = + Array2.init Float32 C_layout 4 4 (fun i j -> Float.of_int ((i * 4) + j)) + + let f_array = + Array2.init Float32 Fortran_layout 4 4 (fun i j -> + Float.of_int ((i * 4) + j)) + + let () = + let v = F32.Bigarray.Array2.get c_array 0 1 in + bit_eq 1.0s v; + let v = F32.Bigarray.Array2.unsafe_get c_array 0 1 in + bit_eq 1.0s v; + let v = F32.Bigarray.Array2.get c_array 3 2 in + bit_eq 14.0s v; + let v = F32.Bigarray.Array2.unsafe_get c_array 3 2 in + bit_eq 14.0s v + + let () = + let v = F32.Bigarray.Array2.get f_array 1 2 in + bit_eq 6.0s v; + let v = F32.Bigarray.Array2.unsafe_get f_array 1 2 in + bit_eq 6.0s v; + let v = F32.Bigarray.Array2.get f_array 4 3 in + bit_eq 19.0s v; + let v = F32.Bigarray.Array2.unsafe_get f_array 4 3 in + bit_eq 19.0s v + + let set array f i j = + F32.Bigarray.Array2.set array i j f; + let v = F32.Bigarray.Array2.get array i j in + bit_eq f v + + let set_unsafe array f i j = + F32.Bigarray.Array2.unsafe_set array i j f; + let v = F32.Bigarray.Array2.get array i j in + bit_eq f v + + let () = + set c_array (F32.of_bits 0x10101010l) 0 1; + set c_array (F32.of_bits 0x20202020l) 1 0; + set_unsafe c_array (F32.of_bits 0x10101010l) 2 3; + set_unsafe c_array (F32.of_bits 0x20202020l) 3 2; + Random.init 1234; + for _ = 1 to 1000 do + set c_array + (Random.int32 Int32.max_int |> F32.of_bits) + (Random.int 4) (Random.int 4); + set_unsafe c_array + (Random.int32 Int32.max_int |> F32.of_bits) + (Random.int 4) (Random.int 4) + done; + set f_array (F32.of_bits 0x10101010l) 1 2; + set f_array (F32.of_bits 0x20202020l) 2 1; + set_unsafe f_array (F32.of_bits 0x10101010l) 3 4; + set_unsafe f_array (F32.of_bits 0x20202020l) 4 3; + Random.init 1234; + for _ = 1 to 1000 do + set f_array + (Random.int32 Int32.max_int |> F32.of_bits) + (1 + Random.int 4) + (1 + Random.int 4); + set_unsafe f_array + (Random.int32 Int32.max_int |> F32.of_bits) + (1 + Random.int 4) + (1 + Random.int 4) + done + + let () = + let check f = + try + f () |> ignore; + assert false + with Invalid_argument s when s = "index out of bounds" -> () + in + check (fun () -> F32.Bigarray.Array2.get c_array (-1) 0); + check (fun () -> F32.Bigarray.Array2.set c_array (-1) 0 0.0s); + check (fun () -> F32.Bigarray.Array2.get c_array 4 0); + check (fun () -> F32.Bigarray.Array2.set c_array 4 0 0.0s); + check (fun () -> F32.Bigarray.Array2.get c_array 0 (-1)); + check (fun () -> F32.Bigarray.Array2.set c_array 0 (-1) 0.0s); + check (fun () -> F32.Bigarray.Array2.get c_array 0 4); + check (fun () -> F32.Bigarray.Array2.set c_array 0 4 0.0s); + check (fun () -> F32.Bigarray.Array2.get f_array 0 1); + check (fun () -> F32.Bigarray.Array2.set f_array 0 1 0.0s); + check (fun () -> F32.Bigarray.Array2.get f_array 5 1); + check (fun () -> F32.Bigarray.Array2.set f_array 5 1 0.0s); + check (fun () -> F32.Bigarray.Array2.get f_array 1 0); + check (fun () -> F32.Bigarray.Array2.set f_array 1 0 0.0s); + check (fun () -> F32.Bigarray.Array2.get f_array 1 5); + check (fun () -> F32.Bigarray.Array2.set f_array 1 5 0.0s) + end + + module A3 = struct + let c_array = + Array3.init Float32 C_layout 4 4 4 (fun i j k -> + Float.of_int ((i * 16) + (j * 4) + k)) + + let f_array = + Array3.init Float32 Fortran_layout 4 4 4 (fun i j k -> + Float.of_int ((i * 16) + (j * 4) + k)) + + let () = + let v = F32.Bigarray.Array3.get c_array 0 1 2 in + bit_eq 6.0s v; + let v = F32.Bigarray.Array3.unsafe_get c_array 0 1 2 in + bit_eq 6.0s v; + let v = F32.Bigarray.Array3.get c_array 3 2 1 in + bit_eq 57.0s v; + let v = F32.Bigarray.Array3.unsafe_get c_array 3 2 1 in + bit_eq 57.0s v + + let () = + let v = F32.Bigarray.Array3.get f_array 1 2 3 in + bit_eq 27.0s v; + let v = F32.Bigarray.Array3.unsafe_get f_array 1 2 3 in + bit_eq 27.0s v; + let v = F32.Bigarray.Array3.get f_array 4 3 2 in + bit_eq 78.0s v; + let v = F32.Bigarray.Array3.unsafe_get f_array 4 3 2 in + bit_eq 78.0s v + + let set array f i j k = + F32.Bigarray.Array3.set array i j k f; + let v = F32.Bigarray.Array3.get array i j k in + bit_eq f v + + let set_unsafe array f i j k = + F32.Bigarray.Array3.unsafe_set array i j k f; + let v = F32.Bigarray.Array3.get array i j k in + bit_eq f v + + let () = + set c_array (F32.of_bits 0x10101010l) 0 1 2; + set c_array (F32.of_bits 0x20202020l) 2 1 0; + set_unsafe c_array (F32.of_bits 0x10101010l) 1 2 3; + set_unsafe c_array (F32.of_bits 0x20202020l) 3 2 1; + Random.init 1234; + for _ = 1 to 1000 do + set c_array + (Random.int32 Int32.max_int |> F32.of_bits) + (Random.int 4) (Random.int 4) (Random.int 4); + set_unsafe c_array + (Random.int32 Int32.max_int |> F32.of_bits) + (Random.int 4) (Random.int 4) (Random.int 4) + done; + set f_array (F32.of_bits 0x10101010l) 1 2 3; + set f_array (F32.of_bits 0x20202020l) 3 2 1; + set_unsafe f_array (F32.of_bits 0x10101010l) 2 3 4; + set_unsafe f_array (F32.of_bits 0x20202020l) 4 3 2; + Random.init 1234; + for _ = 1 to 1000 do + set f_array + (Random.int32 Int32.max_int |> F32.of_bits) + (1 + Random.int 4) + (1 + Random.int 4) + (1 + Random.int 4); + set_unsafe f_array + (Random.int32 Int32.max_int |> F32.of_bits) + (1 + Random.int 4) + (1 + Random.int 4) + (1 + Random.int 4) + done + + let () = + let check f = + try + f () |> ignore; + assert false + with Invalid_argument s when s = "index out of bounds" -> () + in + check (fun () -> F32.Bigarray.Array3.get c_array (-1) 0 0); + check (fun () -> F32.Bigarray.Array3.set c_array (-1) 0 0 0.0s); + check (fun () -> F32.Bigarray.Array3.get c_array 4 0 0); + check (fun () -> F32.Bigarray.Array3.set c_array 4 0 0 0.0s); + check (fun () -> F32.Bigarray.Array3.get c_array 0 (-1) 0); + check (fun () -> F32.Bigarray.Array3.set c_array 0 (-1) 0 0.0s); + check (fun () -> F32.Bigarray.Array3.get c_array 0 4 0); + check (fun () -> F32.Bigarray.Array3.set c_array 0 4 0 0.0s); + check (fun () -> F32.Bigarray.Array3.get c_array 0 0 (-1)); + check (fun () -> F32.Bigarray.Array3.set c_array 0 0 (-1) 0.0s); + check (fun () -> F32.Bigarray.Array3.get c_array 0 0 4); + check (fun () -> F32.Bigarray.Array3.set c_array 0 0 4 0.0s); + check (fun () -> F32.Bigarray.Array3.get f_array 0 1 1); + check (fun () -> F32.Bigarray.Array3.set f_array 0 1 1 0.0s); + check (fun () -> F32.Bigarray.Array3.get f_array 5 1 1); + check (fun () -> F32.Bigarray.Array3.set f_array 5 1 1 0.0s); + check (fun () -> F32.Bigarray.Array3.get f_array 1 0 1); + check (fun () -> F32.Bigarray.Array3.set f_array 1 0 1 0.0s); + check (fun () -> F32.Bigarray.Array3.get f_array 1 5 1); + check (fun () -> F32.Bigarray.Array3.set f_array 1 5 1 0.0s); + check (fun () -> F32.Bigarray.Array3.get f_array 1 1 0); + check (fun () -> F32.Bigarray.Array3.set f_array 1 1 0 0.0s); + check (fun () -> F32.Bigarray.Array3.get f_array 1 1 5); + check (fun () -> F32.Bigarray.Array3.set f_array 1 1 5 0.0s) + end +end + +let () = + let s = Marshal.to_string 1.234s [] in + assert (Marshal.from_string s 0 = 1.234s) diff --git a/compiler/tests-oxcaml/lib-float32/test.expected b/compiler/tests-oxcaml/lib-float32/test.expected new file mode 100644 index 0000000000..ee7db7c64a --- /dev/null +++ b/compiler/tests-oxcaml/lib-float32/test.expected @@ -0,0 +1,93 @@ +001: OK +002: OK +003: OK +004: OK +005: OK +006: OK +007: OK +008: OK +009: OK +010: OK +011: OK +012: OK +013: OK +014: OK +015: OK +016: OK +017: OK +018: OK +019: OK +020: OK +021: OK +022: OK +023: OK +024: OK +025: OK +026: OK +027: OK +028: OK +029: OK +030: OK +031: OK +032: OK +033: OK +034: OK +035: OK +036: OK +037: OK +038: OK +039: OK +040: OK +041: OK +042: OK +043: OK +044: OK +045: OK +046: OK +047: OK +048: OK +049: OK +050: OK +051: OK +052: OK +053: OK +054: OK +055: OK +056: OK +057: OK +058: OK +059: OK +060: OK +061: OK +062: OK +063: OK +064: OK +065: OK +066: OK +067: OK +068: OK +069: OK +070: OK +071: OK +072: OK +073: OK +074: OK +075: OK +076: OK +077: OK +078: OK +079: OK +080: OK +081: OK +082: OK +083: OK +084: OK +085: OK +086: OK +087: OK +088: OK +089: OK +090: OK +091: OK +092: OK +093: OK diff --git a/compiler/tests-oxcaml/lib-float32/test.ml b/compiler/tests-oxcaml/lib-float32/test.ml new file mode 100644 index 0000000000..8823f688e8 --- /dev/null +++ b/compiler/tests-oxcaml/lib-float32/test.ml @@ -0,0 +1,161 @@ +(* TEST *) + +open Stdlib_stable +open Float32.Operators + +let is_nan2 (x, y) = Float32.is_nan x && Float32.is_nan y + +type test = + | True of (unit -> bool) + | False of (unit -> bool) + | Equal of ((unit -> float32) * float32) + | Pair of ((unit -> float32 * float32) * (float32 * float32)) + +let cases = + [ 1, True (fun () -> Float32.is_finite 1.s) + ; 2, True (fun () -> Float32.is_finite Float32.pi) + ; 3, False (fun () -> Float32.is_finite Float32.infinity) + ; 4, False (fun () -> Float32.is_finite Float32.nan) + ; 5, True (fun () -> Float32.is_infinite Float32.infinity) + ; 6, False (fun () -> Float32.is_infinite 1.s) + ; 7, False (fun () -> Float32.is_infinite Float32.nan) + ; 8, True (fun () -> Float32.is_nan Float32.nan) + ; 9, False (fun () -> Float32.is_nan 1.s) + ; 10, False (fun () -> Float32.is_nan Float32.neg_infinity) + ; 11, True (fun () -> Float32.is_integer 1.s) + ; 12, True (fun () -> Float32.is_integer (-1e10s)) + ; 13, False (fun () -> Float32.is_integer 1.5s) + ; 14, False (fun () -> Float32.is_integer Float32.infinity) + ; 15, False (fun () -> Float32.is_integer Float32.nan) + ; 16, Equal ((fun () -> Float32.trunc 1.5s), 1.s) + ; 17, Equal ((fun () -> Float32.trunc (-1.5s)), -1.s) + ; 18, Equal Float32.((fun () -> trunc infinity), Float32.infinity) + ; 19, Equal Float32.((fun () -> trunc neg_infinity), Float32.neg_infinity) + ; 20, True (fun () -> Float32.(is_nan (trunc nan))) + ; 21, Equal ((fun () -> Float32.round 0.5s), 1.s) + ; 22, Equal ((fun () -> Float32.round (-0.5s)), -1.s) + ; 23, Equal ((fun () -> Float32.round 1.5s), 2.s) + ; 24, Equal ((fun () -> Float32.round (-1.5s)), -2.s) + ; ( 25 + , let x = 0x1.000002p+23s in + (* x + 0.5 rounds to x +. 1. *) + Equal ((fun () -> Float32.round x), x) ) + ; 26, Equal ((fun () -> Float32.round (Float32.next_after 0.5s 0.s)), 0.s) + ; 27, Equal Float32.((fun () -> round infinity), Float32.infinity) + ; 28, Equal Float32.((fun () -> round neg_infinity), Float32.neg_infinity) + ; 29, True (fun () -> Float32.(is_nan (round nan))) + ; 30, Equal ((fun () -> Float32.next_after 0x1.FFFFFEp-2s 1.s), 0.5s) + ; 31, Equal ((fun () -> Float32.next_after 0x1.FFFFFEp-2s 0.s), 0x1.FFFFFCp-2s) + ; 32, Equal Float32.((fun () -> next_after 0x1.FFFFFEp-2s infinity), 0.5s) + ; 33, Equal Float32.((fun () -> next_after 0x1.FFFFFEp-2s neg_infinity), 0x1.FFFFFCp-2s) + ; 34, Equal ((fun () -> Float32.next_after 1.s 1.s), 1.s) + ; 35, True (fun () -> Float32.(is_nan (next_after nan 1.s))) + ; 36, True (fun () -> Float32.(is_nan (next_after 3.s nan))) + ; 37, Equal Float32.((fun () -> succ 0x1.FFFFFEp-2s), 0.5s) + ; 38, Equal Float32.((fun () -> pred 0.5s), 0x1.FFFFFEp-2s) + ; 39, True Float32.(fun () -> succ 0.s > 0.s) + ; 40, True Float32.(fun () -> pred 0.s < 0.s) + ; 41, Equal Float32.((fun () -> succ max_float), infinity) + ; 42, Equal Float32.((fun () -> pred (-.max_float)), neg_infinity) + ; 43, True Float32.(fun () -> succ 0.s < min_float) + ; 44, Equal Float32.((fun () -> succ infinity), infinity) + ; 45, Equal Float32.((fun () -> pred neg_infinity), neg_infinity) + ; 46, True Float32.(fun () -> is_nan (succ nan)) + ; 47, True Float32.(fun () -> is_nan (pred nan)) + ; 48, False (fun () -> Float32.sign_bit 1.s) + ; 49, True (fun () -> Float32.sign_bit (-1.s)) + ; 50, False (fun () -> Float32.sign_bit 0.s) + ; 51, True (fun () -> Float32.sign_bit (-0.s)) + ; 52, False (fun () -> Float32.sign_bit Float32.infinity) + ; 53, True (fun () -> Float32.sign_bit Float32.neg_infinity) + ; 54, Equal ((fun () -> Float32.min 1.s 2.s), 1.s) + ; 55, Equal ((fun () -> Float32.min 2.s 1.s), 1.s) + ; 56, True (fun () -> Float32.(is_nan (min 1.s nan))) + ; 57, True (fun () -> Float32.(is_nan (min nan 2.s))) + ; 58, True (fun () -> Float32.(is_nan (min nan nan))) + ; 59, Equal ((fun () -> 1.s /. Float32.min (-0.s) 0.s), Float32.neg_infinity) + ; 60, Equal ((fun () -> 1.s /. Float32.min 0.s (-0.s)), Float32.neg_infinity) + ; 61, Equal ((fun () -> Float32.max 1.s 2.s), 2.s) + ; 62, Equal ((fun () -> Float32.max 2.s 1.s), 2.s) + ; 63, True (fun () -> Float32.(is_nan (max 1.s nan))) + ; 64, True (fun () -> Float32.(is_nan (max nan 2.s))) + ; 65, True (fun () -> Float32.(is_nan (max nan nan))) + ; 66, Equal ((fun () -> 1.s /. Float32.max (-0.s) 0.s), Float32.infinity) + ; 67, Equal ((fun () -> 1.s /. Float32.max 0.s (-0.s)), Float32.infinity) + ; 68, Pair ((fun () -> Float32.min_max 1.s 2.s), (1.s, 2.s)) + ; 69, Pair ((fun () -> Float32.min_max 2.s 1.s), (1.s, 2.s)) + ; 70, True (fun () -> Float32.(is_nan2 (min_max 1.s nan))) + ; 71, True (fun () -> Float32.(is_nan2 (min_max nan 2.s))) + ; 72, True (fun () -> Float32.(is_nan2 (min_max nan nan))) + ; ( 73 + , Pair + ( (fun () -> + let x, y = Float32.min_max (-0.s) 0.s in + 1.s /. x, 1.s /. y) + , (Float32.neg_infinity, Float32.infinity) ) ) + ; ( 74 + , Pair + ( (fun () -> + let x, y = Float32.min_max 0.s (-0.s) in + 1.s /. x, 1.s /. y) + , (Float32.neg_infinity, Float32.infinity) ) ) + ; 75, Equal ((fun () -> Float32.min_num 1.s 2.s), 1.s) + ; 76, Equal Float32.((fun () -> min_num 1.s nan), 1.s) + ; 77, Equal Float32.((fun () -> min_num nan 2.s), 2.s) + ; 78, True (fun () -> Float32.(is_nan (min_num nan nan))) + ; 79, Equal ((fun () -> 1.s /. Float32.min_num (-0.s) 0.s), Float32.neg_infinity) + ; 80, Equal ((fun () -> 1.s /. Float32.min_num 0.s (-0.s)), Float32.neg_infinity) + ; 81, Equal ((fun () -> Float32.max_num 1.s 2.s), 2.s) + ; 82, Equal Float32.((fun () -> max_num 1.s nan), 1.s) + ; 83, Equal Float32.((fun () -> max_num nan 2.s), 2.s) + ; 84, True (fun () -> Float32.(is_nan (max_num nan nan))) + ; 85, Equal ((fun () -> 1.s /. Float32.max_num (-0.s) 0.s), Float32.infinity) + ; 86, Equal ((fun () -> 1.s /. Float32.max_num 0.s (-0.s)), Float32.infinity) + ; 87, Pair ((fun () -> Float32.min_max_num 1.s 2.s), (1.s, 2.s)) + ; 88, Pair ((fun () -> Float32.min_max_num 2.s 1.s), (1.s, 2.s)) + ; 89, Pair ((fun () -> Float32.(min_max_num 1.s nan)), (1.s, 1.s)) + ; 90, Pair ((fun () -> Float32.(min_max_num nan 1.s)), (1.s, 1.s)) + ; 91, True (fun () -> Float32.(is_nan2 (min_max_num nan nan))) + ; ( 92 + , Pair + ( (fun () -> + let x, y = Float32.min_max_num (-0.s) 0.s in + 1.s /. x, 1.s /. y) + , (Float32.neg_infinity, Float32.infinity) ) ) + ; ( 93 + , Pair + ( (fun () -> + let x, y = Float32.min_max_num 0.s (-0.s) in + 1.s /. x, 1.s /. y) + , (Float32.neg_infinity, Float32.infinity) ) ) + ] + +let () = + let f (n, test) = + match test with + | True p -> Printf.printf "%03d: %s\n%!" n (if p () then "OK" else "FAIL") + | False p -> Printf.printf "%03d: %s\n%!" n (if p () then "FAIL" else "OK") + | Equal (f, result) -> + let v = f () in + if v = result + then Printf.printf "%03d: OK\n%!" n + else + Printf.printf + "%03d: FAIL (%h returned instead of %h)\n%!" + n + (Float32.to_float v) + (Float32.to_float result) + | Pair (f, ((l', r') as result)) -> + let ((l, r) as v) = f () in + if v = result + then Printf.printf "%03d: OK\n%!" n + else + Printf.printf + "%03d: FAIL ((%h, %h) returned instead of (%h, %h))\n%!" + n + (Float32.to_float l) + (Float32.to_float r) + (Float32.to_float l') + (Float32.to_float r') + in + List.iter f cases diff --git a/compiler/tests-oxcaml/lib-or-null/dune b/compiler/tests-oxcaml/lib-or-null/dune new file mode 100644 index 0000000000..3786c1708f --- /dev/null +++ b/compiler/tests-oxcaml/lib-or-null/dune @@ -0,0 +1,5 @@ +(tests + (names test more_tests) + (build_if %{oxcaml_supported}) + (libraries stdlib_stable) + (modes js wasm)) diff --git a/compiler/tests-oxcaml/lib-or-null/more_tests.ml b/compiler/tests-oxcaml/lib-or-null/more_tests.ml new file mode 100644 index 0000000000..dddd3aac87 --- /dev/null +++ b/compiler/tests-oxcaml/lib-or-null/more_tests.ml @@ -0,0 +1,142 @@ +(* TEST +*) + +let x = Null + +let () = + match x with + | Null -> () + | This _ -> assert false + +let y = This 3 + +let () = + match y with + | This 3 -> () + | _ -> assert false + +external int_as_pointer : int -> int or_null = "%int_as_pointer" + +let n = int_as_pointer 0 + +let () = + match n with + | Null -> () + | _ -> assert false + +external int_as_int : int -> int or_null = "%opaque" + +let m = int_as_int 5 + +let () = + match m with + | This 5 -> () + | This _ -> assert false + | Null -> assert false + +let x = Null, This "bar" + +let () = + match x with + | Null, This "foo" -> assert false + | Null, This "bar" -> () + | _, This "bar" -> assert false + | Null, _ -> assert false + | _, _ -> assert false + +let y a = fun () -> This a + +let d = y 5 + +let () = + match d () with + | This 5 -> () + | _ -> assert false + +let z = Marshal.to_bytes (This "foo") [] + +let () = + match Marshal.from_bytes z 0 with + | This "foo" -> () + | This _ -> assert false + | Null -> assert false + +let w = Marshal.to_bytes Null [] + +let () = + match Marshal.from_bytes w 0 with + | Null -> () + | This _ -> assert false + +external evil : 'a or_null -> 'a = "%opaque" + +let e = This (evil Null) + +let () = + match e with + | Null -> () + | This _ -> assert false + +let e' = evil (This 4) + +let () = + match e' with + | 4 -> () + | _ -> assert false + +let f a = + fun () -> + match a with + | This x -> x ^ "bar" + | Null -> "foo" + +let g = f (This "xxx") + +let () = + match g () with + | "xxxbar" -> () + | _ -> assert false + +let h = f Null + +let () = + match h () with + | "foo" -> () + | _ -> assert false + +let x = ref Null + +let () = + match !x with + | Null -> () + | _ -> assert false + +let () = x := This "foo" + +let () = + match !x with + | This "foo" -> () + | _ -> assert false + +let () = x := Null + +let () = + match !x with + | Null -> () + | _ -> assert false + +let () = + assert (Null = Null); + assert (This 4 = This 4); + assert (Null <> This 4); + assert (This 8 <> Null); + assert (This 4 <> This 5) + +let () = + assert (compare Null Null = 0); + assert (compare (This 4) (This 4) = 0); + assert (compare Null (This 4) < 0); + assert (compare (This 8) Null > 0); + assert (compare (This 4) (This 5) < 0); + assert (compare (This "abc") (This "xyz") <> 0); + assert (compare (This "xyz") (This "xyz") = 0) diff --git a/compiler/tests-oxcaml/lib-or-null/test.expected b/compiler/tests-oxcaml/lib-or-null/test.expected new file mode 100644 index 0000000000..d86bac9de5 --- /dev/null +++ b/compiler/tests-oxcaml/lib-or-null/test.expected @@ -0,0 +1 @@ +OK diff --git a/compiler/tests-oxcaml/lib-or-null/test.ml b/compiler/tests-oxcaml/lib-or-null/test.ml new file mode 100644 index 0000000000..59977e5017 --- /dev/null +++ b/compiler/tests-oxcaml/lib-or-null/test.ml @@ -0,0 +1,117 @@ +(* TEST *) + +open Stdlib_stable + +let assert_raise_invalid_argument f v = + assert ( + try + ignore (f v); + false + with Invalid_argument _ -> true); + () + +let test_null_this () = + assert (Or_null.null = Null); + assert (Or_null.this 2 = This 2); + () + +let test_value () = + assert (Or_null.value Null ~default:5 = 5); + assert (Or_null.value (This 3) ~default:5 = 3); + () + +let test_get () = + assert_raise_invalid_argument Or_null.get Null; + assert (Or_null.get (This 2) = 2); + () + +let test_bind () = + assert (Or_null.bind (This 3) (fun x -> This (succ x)) = This 4); + assert (Or_null.bind (This 3) (fun _ -> Null) = Null); + assert (Or_null.bind Null (fun x -> This (succ x)) = Null); + assert (Or_null.bind Null (fun _ -> Null) = Null); + () + +let test_map () = + assert (Or_null.map succ (This 3) = This 4); + assert (Or_null.map succ Null = Null); + () + +let test_fold () = + assert (Or_null.fold ~null:3 ~this:succ (This 1) = 2); + assert (Or_null.fold ~null:3 ~this:succ Null = 3); + (* + assert (Or_null.(fold ~null ~this) (This 1) = (This 1)); + assert (Or_null.(fold ~null ~this) Null = Null); +*) + () + +let test_iter () = + let count = ref 0 in + let set_count x = count := x in + assert (!count = 0); + Or_null.iter set_count (This 2); + assert (!count = 2); + Or_null.iter set_count Null; + assert (!count = 2); + () + +let test_is_null_this () = + assert (Or_null.is_null Null = true); + assert (Or_null.is_this Null = false); + assert (Or_null.is_null (This 2) = false); + assert (Or_null.is_this (This 2) = true); + () + +let test_equal () = + let eq v0 v1 = v0 mod 2 = v1 mod 2 in + let equal = Or_null.equal eq in + assert (not @@ equal (This 2) (This 3)); + assert (equal (This 2) (This 4)); + assert (not @@ equal (This 2) Null); + assert (not @@ equal Null (This 3)); + assert (not @@ equal Null (This 4)); + assert (equal Null Null); + () + +let test_compare () = + let compare v0 v1 = -compare v0 v1 in + let compare = Or_null.compare compare in + assert (compare (This 2) (This 1) = -1); + assert (compare (This 2) (This 2) = 0); + assert (compare (This 2) (This 3) = 1); + assert (compare (This 2) Null = 1); + assert (compare Null (This 1) = -1); + assert (compare Null (This 2) = -1); + assert (compare Null (This 3) = -1); + assert (compare Null Null = 0); + () + +let test_to_option_list_seq () = + assert (Or_null.to_result ~null:6 (This 3) = Ok 3); + assert (Or_null.to_result ~null:6 Null = Error 6); + assert (Or_null.to_list (This 3) = [ 3 ]); + assert (Or_null.to_list Null = []); + (match (Or_null.to_seq (This 3)) () with + | Seq.Cons (3, f) -> assert (f () = Seq.Nil) + | _ -> assert false); + assert ((Or_null.to_seq Null) () = Seq.Nil); + () + +let tests () = + test_null_this (); + test_value (); + test_get (); + test_bind (); + test_map (); + test_fold (); + test_iter (); + test_is_null_this (); + test_equal (); + test_compare (); + test_to_option_list_seq (); + () + +let () = + tests (); + print_endline "OK" diff --git a/compiler/tests-oxcaml/misc/.ocamlformat b/compiler/tests-oxcaml/misc/.ocamlformat new file mode 100644 index 0000000000..593b6a1ffc --- /dev/null +++ b/compiler/tests-oxcaml/misc/.ocamlformat @@ -0,0 +1 @@ +disable diff --git a/compiler/tests-oxcaml/misc/dune b/compiler/tests-oxcaml/misc/dune new file mode 100644 index 0000000000..0e2f38e07e --- /dev/null +++ b/compiler/tests-oxcaml/misc/dune @@ -0,0 +1,10 @@ +(env + (_ + (flags + (:standard + (-w -32-69))))) + +(tests + (names test) + (build_if %{oxcaml_supported}) + (modes byte js wasm)) diff --git a/compiler/tests-oxcaml/misc/test.ml b/compiler/tests-oxcaml/misc/test.ml new file mode 100644 index 0000000000..c021c58f61 --- /dev/null +++ b/compiler/tests-oxcaml/misc/test.ml @@ -0,0 +1,4 @@ + +type t = { x : t; y : float32# } + +let rec x = { x; y = #0.s } diff --git a/compiler/tests-oxcaml/small-ints/.ocamlformat b/compiler/tests-oxcaml/small-ints/.ocamlformat new file mode 100644 index 0000000000..593b6a1ffc --- /dev/null +++ b/compiler/tests-oxcaml/small-ints/.ocamlformat @@ -0,0 +1 @@ +disable diff --git a/compiler/tests-oxcaml/small-ints/dune b/compiler/tests-oxcaml/small-ints/dune new file mode 100644 index 0000000000..df813546fe --- /dev/null +++ b/compiler/tests-oxcaml/small-ints/dune @@ -0,0 +1,11 @@ +(env + (_ + (flags + (:standard + (-w -9-27-32))))) + +(tests + (names test_int8_u test_int16_u) + (build_if %{oxcaml_supported}) + (libraries stdlib_stable stdlib_upstream_compatible) + (modes js wasm)) diff --git a/compiler/tests-oxcaml/small-ints/test_int16_u.ml b/compiler/tests-oxcaml/small-ints/test_int16_u.ml new file mode 100644 index 0000000000..374ea55762 --- /dev/null +++ b/compiler/tests-oxcaml/small-ints/test_int16_u.ml @@ -0,0 +1,357 @@ +(* TEST + include stdlib_stable; + flags = "-extension layouts_beta"; +*) + +(* External declarations for unsigned comparison primitives *) +external unsigned_lt : int16# -> int16# -> bool = "%int16#_unsigned_lessthan" +external unsigned_gt : int16# -> int16# -> bool = "%int16#_unsigned_greaterthan" + +module Int16 = Stdlib_stable.Int16 +module Int16_u = Stdlib_stable.Int16_u + +(* Print all individual successful tests; used for debugging, as it will cause + this test to fail *) +let debug_tests = false + +(* Constant seed for repeatable random-testing properties *) +let () = Random.init 42 + +let to_ocaml_string s = "\"" ^ String.escaped s ^ "\"" + +type 'a result = { + expected : 'a; + actual : 'a; + equal : 'a -> 'a -> bool; + to_string : 'a -> string +} + +module type Result = sig + type t + val equal : t -> t -> bool + val to_string : t -> string +end + +let mk_result' equal to_string = fun ~expected ~actual -> + { expected; actual; equal; to_string } + +let mk_result (type a) (module M : Result with type t = a) = + mk_result' M.equal M.to_string + +let float_result = mk_result (module Float) +let bool_result = mk_result (module Bool) +let int_result = mk_result (module Int) +let int16_result = mk_result (module Int16) +let string_result = mk_result' String.equal to_ocaml_string + +let option_result (type a) (module M : Result with type t = a) = + mk_result' + (Option.equal M.equal) + (function + | None -> "None" + | Some x -> "Some (" ^ M.to_string x ^ ")") + +type 'a generator = + | Rand of (unit -> 'a) + | Const of 'a + +let map_generator f = function + | Rand r -> Rand (fun () -> f (r ())) + | Const c -> Const (f c) + +type 'a input = { + generators : 'a generator list; + to_string : 'a -> string +} + +module type Integer = sig + type t + (* Interesting constants *) + val zero : t + val one : t + val minus_one : t + val max_int : t + val min_int : t + (* String generation *) + val to_string : t -> string + (* Comparison (for zero-testing) *) + val equal : t -> t -> bool + (* Arithmetic (for generating small numbers) *) + val sub : t -> t -> t + val shift_left : t -> int -> t +end + +let one_thousand (type a) (module I : Integer with type t = a) = + let open I in + let i1024 = shift_left one 10 in + let i16 = shift_left one 4 in + let i8 = shift_left one 3 in + sub (sub i1024 i16) i8 + +let two_thousand (type a) (module I : Integer with type t = a) = + I.shift_left (one_thousand (module I)) 1 + +let unit_input = + { generators = [Const ()] + ; to_string = Unit.to_string + } + +let bool_input = + { generators = [Const false; Const true] + ; to_string = Bool.to_string + } + +let float_input = + { generators = [ Const 0. + ; Const 1. + ; Const (-1.) + ; Const Float.max_float + ; Const Float.min_float + ; Const Float.epsilon + ; Const Float.nan + ; Const Float.infinity + ; Const Float.neg_infinity + ; Rand (fun () -> Random.float 2000. -. 1000.) + ; Rand (fun () -> Int64.float_of_bits (Random.bits64 ())) + ] + ; to_string = Float.to_string + } + +let integer_input + (type a) (module I : Integer with type t = a) + rand_range rand_full = + let rand_small () = + let i0_to_2000 = rand_range (two_thousand (module I)) in + I.sub i0_to_2000 (one_thousand (module I)) + in + { generators = [ Const I.zero + ; Const I.one + ; Const I.minus_one + ; Const I.max_int + ; Const I.min_int + ; Rand rand_small + ; Rand rand_full + ] + ; to_string = I.to_string + } + +let nonzero_integer_input + (type a) (module I : Integer with type t = a) + rand_range rand_full = + let { generators; to_string } = + integer_input (module I) rand_range rand_full + in + let generators = + generators |> + List.filter_map + (function + | Const c -> + if I.equal c I.zero + then None + else Some (Const c) + | Rand r -> + Some (Rand (fun () -> + let n = ref I.zero in + while I.equal !n I.zero do + n := r () + done; + !n))) + in + { generators; to_string } + +let random_int16 x = Int16.of_int (Random.int (Int16.to_int x)) +let random_bits16 x = Int16.of_int (Random.bits ()) + +let int_input = integer_input (module Int) Random.int Random.bits +let int16_input = integer_input (module Int16) random_int16 random_bits16 +let nonzero_int16_input = + nonzero_integer_input (module Int16) random_int16 random_bits16 + +let int16_shift_amount_input = + { generators = List.init 16 (fun c -> Const c) + ; to_string = Int.to_string + } + +let int16_string_input = + { generators = List.map + (map_generator Int16.to_string) + int16_input.generators + ; to_string = to_ocaml_string + } + +let product2 ~f xs ys = + List.concat_map (fun x -> + List.map (fun y -> + f x y) + ys) + xs + +let two_inputs in1 in2 = + { generators = product2 in1.generators in2.generators ~f:(fun gen1 gen2 -> + match gen1, gen2 with + | Const c1, Const c2 -> Const (c1, c2) + | Const c1, Rand r2 -> Rand (fun () -> c1, r2 ()) + | Rand r1, Const c2 -> Rand (fun () -> r1 (), c2) + | Rand r1, Rand r2 -> Rand (fun () -> r1 (), r2 ()) + ) + ; to_string = fun (x1, x2) -> + Printf.sprintf "(%s, %s)" (in1.to_string x1) (in2.to_string x2) + } + +let passed { actual; expected; equal; _ } = equal actual expected + +let test ?(n=100) name prop { generators; to_string = input_to_string } = + let test input = + let {expected; actual; to_string} as result = prop input in + let print_test outcome = + Printf.printf "Test %s: %s. Input = %s; expected = %s; actual = %s\n" + outcome name + (input_to_string input) (to_string expected) (to_string actual) + in + if passed result then begin + if debug_tests then print_test "succeeded" + end + else + print_test "failed" + in + List.iter + (function + | Const c -> test c + | Rand r -> for _ = 1 to n do test (r ()) done) + generators + +let test_same + ~input ~result ~apply_expected ~apply_actual + ?n name expected actual = + test ?n name + (fun x -> + result + ~expected:(apply_expected expected x) + ~actual:(apply_actual actual x)) + input + +let test_constant ?n name expected actual result = + test ?n name (fun () -> result ~expected ~actual) unit_input + +let test_same_unary ?n name input result expected actual = + test_same + ~input + ~result + ~apply_expected:Fun.id + ~apply_actual:Fun.id + ?n name expected actual + +let test_same_binary ?n name input1 input2 result expected actual = + test_same + ~input:(two_inputs input1 input2) + ~result + ~apply_expected:(fun f (x,y) -> f x y) + ~apply_actual:(fun f (x,y) -> f x y) + ?n name expected actual + +let test_unary ?n name f fu = + test_same_unary ?n name int16_input int16_result f + (fun x -> Int16_u.to_int16 (fu (Int16_u.of_int16 x))) + +let test_unary_of ?n name f fu result = + test_same_unary ?n name int16_input result f + (fun x -> fu (Int16_u.of_int16 x)) + +let test_unary_to ?n name f fu input = + test_same_unary ?n name input int16_result f + (fun x -> Int16_u.to_int16 (fu x)) + +let test_binary' ~second_input ?n name f fu = + test_same_binary ?n name int16_input second_input int16_result f + (fun x y -> Int16_u.to_int16 + (fu + (Int16_u.of_int16 x) + (Int16_u.of_int16 y))) + +let test_binary = test_binary' ~second_input:int16_input + +let test_division = test_binary' ~second_input:nonzero_int16_input + +let test_binary_of ?n name f fu result = + test_same_binary ?n name int16_input int16_input result f + (fun x y -> fu + (Int16_u.of_int16 x) + (Int16_u.of_int16 y)) + +let test_shift ?n name shift shiftu = + test_same_binary + ?n name int16_input int16_shift_amount_input int16_result shift + (fun x y -> Int16_u.to_int16 + (shiftu + (Int16_u.of_int16 x) + y)) + +let () = + test_unary "neg" Int16.neg Int16_u.neg; + test_binary "add" Int16.add Int16_u.add; + test_binary "sub" Int16.sub Int16_u.sub; + test_binary "mul" Int16.mul Int16_u.mul; + test_division "div" Int16.div Int16_u.div; + test_division "unsigned_div" Int16.unsigned_div Int16_u.unsigned_div; + test_division "rem" Int16.rem Int16_u.rem; + test_division "unsigned_rem" Int16.unsigned_rem Int16_u.unsigned_rem; + test_unary "succ" Int16.succ Int16_u.succ; + test_unary "pred" Int16.pred Int16_u.pred; + test_unary "abs" Int16.abs Int16_u.abs; + test_binary "logand" Int16.logand Int16_u.logand; + test_binary "logor" Int16.logor Int16_u.logor; + test_binary "logxor" Int16.logxor Int16_u.logxor; + test_unary "lognot" Int16.lognot Int16_u.lognot; + test_shift "shift_left" Int16.shift_left Int16_u.shift_left; + test_shift "shift_right" Int16.shift_right Int16_u.shift_right; + test_shift "shift_right_logical" Int16.shift_right_logical Int16_u.shift_right_logical; + test_unary_to "of_int" Int16.of_int Int16_u.of_int int_input; + test_unary_of "to_int" Int16.to_int Int16_u.to_int int_result; + test_unary_of "unsigned_to_int" Int16.unsigned_to_int Int16_u.unsigned_to_int int_result; + test_unary_to "of_float" Int16.of_float Int16_u.of_float float_input; + test_unary_of "to_float" Int16.to_float Int16_u.to_float float_result; + test_unary_to "of_string" Int16.of_string Int16_u.of_string int16_string_input; + test_unary_of "to_string" Int16.to_string Int16_u.to_string string_result; + test_binary_of "compare" Int16.compare Int16_u.compare int_result; + test_binary_of "unsigned_compare" Int16.unsigned_compare Int16_u.unsigned_compare int_result; + test_binary_of "equal" Int16.equal Int16_u.equal bool_result; + test_binary "min" Int16.min Int16_u.min; + test_binary "max" Int16.max Int16_u.max; + + (* Explicit unsigned comparison tests with hardcoded expected values *) + let module I = Int16_u in + + (* Test that -1 (0xFFFF) > 0 when compared as unsigned *) + assert (I.unsigned_compare (I.minus_one ()) (I.zero ()) = 1); + assert (I.unsigned_compare (I.zero ()) (I.minus_one ()) = -1); + + (* Test that -32768 (0x8000) > 32767 (0x7FFF) when compared as unsigned *) + assert (I.unsigned_compare (I.min_int ()) (I.max_int ()) = 1); + assert (I.unsigned_compare (I.max_int ()) (I.min_int ()) = -1); + + (* Test ordering: when viewed as unsigned: + 0 < 1 < 32767 < 32768 (min_int) < 65535 (minus_one) *) + assert (I.unsigned_compare (I.zero ()) (I.one ()) = -1); + assert (I.unsigned_compare (I.one ()) (I.max_int ()) = -1); + assert (I.unsigned_compare (I.max_int ()) (I.min_int ()) = -1); + assert (I.unsigned_compare (I.min_int ()) (I.minus_one ()) = -1); + + (* Test equality *) + assert (I.unsigned_compare (I.zero ()) (I.zero ()) = 0); + assert (I.unsigned_compare (I.minus_one ()) (I.minus_one ()) = 0); + + (* Test the unsigned_lt primitive directly *) + assert (unsigned_lt (I.zero ()) (I.minus_one ()) = true); (* 0 < 65535 *) + assert (unsigned_lt (I.minus_one ()) (I.zero ()) = false); (* 65535 not < 0 *) + assert (unsigned_lt (I.max_int ()) (I.min_int ()) = true); (* 32767 < 32768 *) + assert (unsigned_lt (I.min_int ()) (I.max_int ()) + = false); (* 32768 not < 32767 *) + + (* Test unsigned greater than using primitive comparisons *) + assert (unsigned_gt (I.minus_one ()) (I.zero ()) = true); (* 65535 > 0 *) + assert (unsigned_gt (I.zero ()) (I.minus_one ()) = false); (* 0 not > 65535 *) + assert (unsigned_gt (I.min_int ()) (I.max_int ()) = true); (* 32768 > 32767 *) + assert (unsigned_gt (I.max_int ()) (I.min_int ()) + = false); (* 32767 not > 32768 *) + + () diff --git a/compiler/tests-oxcaml/small-ints/test_int8_u.ml b/compiler/tests-oxcaml/small-ints/test_int8_u.ml new file mode 100644 index 0000000000..bc617a5398 --- /dev/null +++ b/compiler/tests-oxcaml/small-ints/test_int8_u.ml @@ -0,0 +1,342 @@ +(* TEST + include stdlib_stable; + flags = "-extension layouts_beta"; +*) + +(* External declarations for unsigned comparison primitives *) +external unsigned_lt : int8# -> int8# -> bool = "%int8#_unsigned_lessthan" +external unsigned_gt : int8# -> int8# -> bool = "%int8#_unsigned_greaterthan" + +module Int8 = Stdlib_stable.Int8 +module Int8_u = Stdlib_stable.Int8_u + +(* Print all individual successful tests; used for debugging, as it will cause + this test to fail *) +let debug_tests = false + +(* Constant seed for repeatable random-testing properties *) +let () = Random.init 42 + +let to_ocaml_string s = "\"" ^ String.escaped s ^ "\"" + +type 'a result = { + expected : 'a; + actual : 'a; + equal : 'a -> 'a -> bool; + to_string : 'a -> string +} + +module type Result = sig + type t + val equal : t -> t -> bool + val to_string : t -> string +end + +let mk_result' equal to_string = fun ~expected ~actual -> + { expected; actual; equal; to_string } + +let mk_result (type a) (module M : Result with type t = a) = + mk_result' M.equal M.to_string + +let float_result = mk_result (module Float) +let bool_result = mk_result (module Bool) +let int_result = mk_result (module Int) +let int8_result = mk_result (module Int8) +let string_result = mk_result' String.equal to_ocaml_string + +let option_result (type a) (module M : Result with type t = a) = + mk_result' + (Option.equal M.equal) + (function + | None -> "None" + | Some x -> "Some (" ^ M.to_string x ^ ")") + +type 'a generator = + | Rand of (unit -> 'a) + | Const of 'a + +let map_generator f = function + | Rand r -> Rand (fun () -> f (r ())) + | Const c -> Const (f c) + +type 'a input = { + generators : 'a generator list; + to_string : 'a -> string +} + +module type Integer = sig + type t + (* Interesting constants *) + val zero : t + val one : t + val minus_one : t + val max_int : t + val min_int : t + (* String generation *) + val to_string : t -> string + (* Comparison (for zero-testing) *) + val equal : t -> t -> bool + (* Arithmetic (for generating small numbers) *) + val sub : t -> t -> t + val shift_left : t -> int -> t +end + +let unit_input = + { generators = [Const ()] + ; to_string = Unit.to_string + } + +let bool_input = + { generators = [Const false; Const true] + ; to_string = Bool.to_string + } + +let float_input = + { generators = [ Const 0. + ; Const 1. + ; Const (-1.) + ; Const Float.max_float + ; Const Float.min_float + ; Const Float.epsilon + ; Const Float.nan + ; Const Float.infinity + ; Const Float.neg_infinity + ; Rand (fun () -> Random.float 2000. -. 1000.) + ; Rand (fun () -> Int64.float_of_bits (Random.bits64 ())) + ] + ; to_string = Float.to_string + } + +let integer_input + (type a) (module I : Integer with type t = a) + _rand_range rand_full = + { generators = [ Const I.zero + ; Const I.one + ; Const I.minus_one + ; Const I.max_int + ; Const I.min_int + ; Rand rand_full + ] + ; to_string = I.to_string + } + +let nonzero_integer_input + (type a) (module I : Integer with type t = a) + rand_range rand_full = + let { generators; to_string } = + integer_input (module I) rand_range rand_full + in + let generators = + generators |> + List.filter_map + (function + | Const c -> + if I.equal c I.zero + then None + else Some (Const c) + | Rand r -> + Some (Rand (fun () -> + let n = ref I.zero in + while I.equal !n I.zero do + n := r () + done; + !n))) + in + { generators; to_string } + +let random_int8 x = Int8.of_int (Random.int (Int8.to_int x)) +let random_bits8 x = Int8.of_int (Random.bits ()) + +let int_input = integer_input (module Int) Random.int Random.bits +let int8_input = integer_input (module Int8) random_int8 random_bits8 +let nonzero_int8_input = + nonzero_integer_input (module Int8) random_int8 random_bits8 + +let int8_shift_amount_input = + { generators = List.init 8 (fun c -> Const c) + ; to_string = Int.to_string + } + +let int8_string_input = + { generators = List.map + (map_generator Int8.to_string) + int8_input.generators + ; to_string = to_ocaml_string + } + +let product2 ~f xs ys = + List.concat_map (fun x -> + List.map (fun y -> + f x y) + ys) + xs + +let two_inputs in1 in2 = + { generators = product2 in1.generators in2.generators ~f:(fun gen1 gen2 -> + match gen1, gen2 with + | Const c1, Const c2 -> Const (c1, c2) + | Const c1, Rand r2 -> Rand (fun () -> c1, r2 ()) + | Rand r1, Const c2 -> Rand (fun () -> r1 (), c2) + | Rand r1, Rand r2 -> Rand (fun () -> r1 (), r2 ()) + ) + ; to_string = fun (x1, x2) -> + Printf.sprintf "(%s, %s)" (in1.to_string x1) (in2.to_string x2) + } + +let passed { actual; expected; equal; _ } = equal actual expected + +let test ?(n=100) name prop { generators; to_string = input_to_string } = + let test input = + let {expected; actual; to_string} as result = prop input in + let print_test outcome = + Printf.printf "Test %s: %s. Input = %s; expected = %s; actual = %s\n" + outcome name + (input_to_string input) (to_string expected) (to_string actual) + in + if passed result then begin + if debug_tests then print_test "succeeded" + end + else + print_test "failed" + in + List.iter + (function + | Const c -> test c + | Rand r -> for _ = 1 to n do test (r ()) done) + generators + +let test_same + ~input ~result ~apply_expected ~apply_actual + ?n name expected actual = + test ?n name + (fun x -> + result + ~expected:(apply_expected expected x) + ~actual:(apply_actual actual x)) + input + +let test_constant ?n name expected actual result = + test ?n name (fun () -> result ~expected ~actual) unit_input + +let test_same_unary ?n name input result expected actual = + test_same + ~input + ~result + ~apply_expected:Fun.id + ~apply_actual:Fun.id + ?n name expected actual + +let test_same_binary ?n name input1 input2 result expected actual = + test_same + ~input:(two_inputs input1 input2) + ~result + ~apply_expected:(fun f (x,y) -> f x y) + ~apply_actual:(fun f (x,y) -> f x y) + ?n name expected actual + +let test_unary ?n name f fu = + test_same_unary ?n name int8_input int8_result f + (fun x -> Int8_u.to_int8 (fu (Int8_u.of_int8 x))) + +let test_unary_of ?n name f fu result = + test_same_unary ?n name int8_input result f + (fun x -> fu (Int8_u.of_int8 x)) + +let test_unary_to ?n name f fu input = + test_same_unary ?n name input int8_result f + (fun x -> Int8_u.to_int8 (fu x)) + +let test_binary' ~second_input ?n name f fu = + test_same_binary ?n name int8_input second_input int8_result f + (fun x y -> Int8_u.to_int8 + (fu + (Int8_u.of_int8 x) + (Int8_u.of_int8 y))) + +let test_binary = test_binary' ~second_input:int8_input + +let test_division = test_binary' ~second_input:nonzero_int8_input + +let test_binary_of ?n name f fu result = + test_same_binary ?n name int8_input int8_input result f + (fun x y -> fu + (Int8_u.of_int8 x) + (Int8_u.of_int8 y)) + +let test_shift ?n name shift shiftu = + test_same_binary + ?n name int8_input int8_shift_amount_input int8_result shift + (fun x y -> Int8_u.to_int8 + (shiftu + (Int8_u.of_int8 x) + y)) + +let () = + test_unary "neg" Int8.neg Int8_u.neg; + test_binary "add" Int8.add Int8_u.add; + test_binary "sub" Int8.sub Int8_u.sub; + test_binary "mul" Int8.mul Int8_u.mul; + test_division "div" Int8.div Int8_u.div; + test_division "unsigned_div" Int8.unsigned_div Int8_u.unsigned_div; + test_division "rem" Int8.rem Int8_u.rem; + test_division "unsigned_rem" Int8.unsigned_rem Int8_u.unsigned_rem; + test_unary "succ" Int8.succ Int8_u.succ; + test_unary "pred" Int8.pred Int8_u.pred; + test_unary "abs" Int8.abs Int8_u.abs; + test_binary "logand" Int8.logand Int8_u.logand; + test_binary "logor" Int8.logor Int8_u.logor; + test_binary "logxor" Int8.logxor Int8_u.logxor; + test_unary "lognot" Int8.lognot Int8_u.lognot; + test_shift "shift_left" Int8.shift_left Int8_u.shift_left; + test_shift "shift_right" Int8.shift_right Int8_u.shift_right; + test_shift "shift_right_logical" Int8.shift_right_logical Int8_u.shift_right_logical; + test_unary_to "of_int" Int8.of_int Int8_u.of_int int_input; + test_unary_of "to_int" Int8.to_int Int8_u.to_int int_result; + test_unary_of "unsigned_to_int" Int8.unsigned_to_int Int8_u.unsigned_to_int int_result; + test_unary_to "of_float" Int8.of_float Int8_u.of_float float_input; + test_unary_of "to_float" Int8.to_float Int8_u.to_float float_result; + test_unary_to "of_string" Int8.of_string Int8_u.of_string int8_string_input; + test_unary_of "to_string" Int8.to_string Int8_u.to_string string_result; + test_binary_of "compare" Int8.compare Int8_u.compare int_result; + test_binary_of "unsigned_compare" Int8.unsigned_compare Int8_u.unsigned_compare int_result; + test_binary_of "equal" Int8.equal Int8_u.equal bool_result; + test_binary "min" Int8.min Int8_u.min; + test_binary "max" Int8.max Int8_u.max; + + (* Explicit unsigned comparison tests with hardcoded expected values *) + let module I = Int8_u in + + (* Test that -1 (0xFF) > 0 when compared as unsigned *) + assert (I.unsigned_compare (I.minus_one ()) (I.zero ()) = 1); + assert (I.unsigned_compare (I.zero ()) (I.minus_one ()) = -1); + + (* Test that -128 (0x80) > 127 (0x7F) when compared as unsigned *) + assert (I.unsigned_compare (I.min_int ()) (I.max_int ()) = 1); + assert (I.unsigned_compare (I.max_int ()) (I.min_int ()) = -1); + + (* Test ordering: when viewed as unsigned: + 0 < 1 < 127 < 128 (min_int) < 255 (minus_one) *) + assert (I.unsigned_compare (I.zero ()) (I.one ()) = -1); + assert (I.unsigned_compare (I.one ()) (I.max_int ()) = -1); + assert (I.unsigned_compare (I.max_int ()) (I.min_int ()) = -1); + assert (I.unsigned_compare (I.min_int ()) (I.minus_one ()) = -1); + + (* Test equality *) + assert (I.unsigned_compare (I.zero ()) (I.zero ()) = 0); + assert (I.unsigned_compare (I.minus_one ()) (I.minus_one ()) = 0); + + (* Test the unsigned_lt primitive directly *) + assert (unsigned_lt (I.zero ()) (I.minus_one ()) = true); (* 0 < 255 *) + assert (unsigned_lt (I.minus_one ()) (I.zero ()) = false); (* 255 not < 0 *) + assert (unsigned_lt (I.max_int ()) (I.min_int ()) = true); (* 127 < 128 *) + assert (unsigned_lt (I.min_int ()) (I.max_int ()) + = false); (* 128 not < 127 *) + + (* Test unsigned greater than using primitive comparisons *) + assert (unsigned_gt (I.minus_one ()) (I.zero ()) = true); (* 255 > 0 *) + assert (unsigned_gt (I.zero ()) (I.minus_one ()) = false); (* 0 not > 255 *) + assert (unsigned_gt (I.min_int ()) (I.max_int ()) = true); (* 128 > 127 *) + assert (unsigned_gt (I.max_int ()) (I.min_int ()) + = false); (* 127 not > 128 *) + + () diff --git a/compiler/tests-oxcaml/unboxed_int/.ocamlformat b/compiler/tests-oxcaml/unboxed_int/.ocamlformat new file mode 100644 index 0000000000..593b6a1ffc --- /dev/null +++ b/compiler/tests-oxcaml/unboxed_int/.ocamlformat @@ -0,0 +1 @@ +disable diff --git a/compiler/tests-oxcaml/unboxed_int/array_indexing.ml b/compiler/tests-oxcaml/unboxed_int/array_indexing.ml new file mode 100644 index 0000000000..5a8b027d7a --- /dev/null +++ b/compiler/tests-oxcaml/unboxed_int/array_indexing.ml @@ -0,0 +1,155 @@ +(* TEST + flambda2; + include stdlib_upstream_compatible; + { + native; + }{ + bytecode; + }{ + flags = "-extension layouts_alpha"; + native; + }{ + flags = "-extension layouts_alpha"; + bytecode; + }{ + flags = "-extension layouts_beta"; + native; + }{ + flags = "-extension layouts_beta"; + bytecode; + } +*) + +module By_int64_u = struct + module I = Stdlib_upstream_compatible.Int64_u + module A = struct + external get : 'a array -> int64# -> 'a = + "%array_safe_get_indexed_by_int64#" + external set : 'a array -> int64# -> 'a -> unit = + "%array_safe_set_indexed_by_int64#" + external unsafe_get : 'a array -> int64# -> 'a = + "%array_unsafe_get_indexed_by_int64#" + external unsafe_set : 'a array -> int64# -> 'a -> unit = + "%array_unsafe_set_indexed_by_int64#" + end +end + +module By_int32_u = struct + module I = Stdlib_upstream_compatible.Int32_u + module A = struct + external get : 'a array -> int32# -> 'a = + "%array_safe_get_indexed_by_int32#" + external set : 'a array -> int32# -> 'a -> unit = + "%array_safe_set_indexed_by_int32#" + external unsafe_get : 'a array -> int32# -> 'a = + "%array_unsafe_get_indexed_by_int32#" + external unsafe_set : 'a array -> int32# -> 'a -> unit = + "%array_unsafe_set_indexed_by_int32#" + end +end + +module By_nativeint_u = struct + module I = Stdlib_upstream_compatible.Nativeint_u + + module A = struct + external get : 'a array -> nativeint# -> 'a = + "%array_safe_get_indexed_by_nativeint#" + external set : 'a array -> nativeint# -> 'a -> unit = + "%array_safe_set_indexed_by_nativeint#" + external unsafe_get : 'a array -> nativeint# -> 'a = + "%array_unsafe_get_indexed_by_nativeint#" + external unsafe_set : 'a array -> nativeint# -> 'a -> unit = + "%array_unsafe_set_indexed_by_nativeint#" + end +end + +let check_eq arr g = + for i = 0 to Array.length arr - 1 do + assert (g arr i = arr.(i)) + done + +let check_inval f = + try let _ = f () in assert false with + | Invalid_argument _ -> () + +let pp = Format.printf + +let test_get (g: 'a. 'a array -> int -> 'a) = + check_eq [| 1; 2; 3; 4; 5; 6; 7|] g; + check_eq [| "a"; "b"; "c"; "d"|] g; + check_eq [| 1.; 2.; 3.; 4.; 5.|] g; + () + +let test_set (g: 'a. 'a array -> int -> 'a -> unit) = + let fill arr v = + for i = 0 to Array.length arr - 1 do + g arr i v; assert(Array.get arr i = v) + done + in + let check_all_eq arr v = assert (Array.for_all (fun x -> x = v) arr) in + let arr = [| 1; 2; 3; 4; 5; 6; 7|] in + fill arr 0; check_all_eq arr 0; + let arr = [| "a"; "b"; "c"; "d"|] in + fill arr "aaa"; check_all_eq arr "aaa"; + let arr = [| 1.; 2.; 3.; 4.; 5.|] in + fill arr 0.; check_all_eq arr 0.; + () + +let test_int64_u () = + let open By_int64_u in + + test_get (fun arr i -> A.get arr (I.of_int i)); + test_get (fun arr i -> A.unsafe_get arr (I.of_int i)); + + test_set (fun arr i -> A.set arr (I.of_int i)); + test_set (fun arr i -> A.unsafe_set arr (I.of_int i)); + + (* This is + 0b1000000000000000000000000000000000000000000000000000000000000001 + in binary and should be out of bound. *) + check_inval (fun () -> A.get [| 1; 2; 3|] (-#9223372036854775807L)); + check_inval (fun () -> A.set [| 1; 2; 3|] (-#9223372036854775807L) 0); + (* no promises when using unsafe_get. int truncation happens. *) + let arr = [| 1; 2; 3|] in + assert (A.unsafe_get arr (-#9223372036854775807L) = 2); + A.unsafe_set arr (-#9223372036854775807L) 11111; + assert (A.unsafe_get arr #1L = 11111); + check_inval (fun () -> A.get [| 1; 2; 3|] (-#1L)); + check_inval (fun () -> A.set [| 1; 2; 3|] (-#1L) 1); + () + +let test_int32_u () = + let open By_int32_u in + + test_get (fun arr i -> A.get arr (I.of_int i)); + test_get (fun arr i -> A.unsafe_get arr (I.of_int i)); + + test_set (fun arr i -> A.set arr (I.of_int i)); + test_set (fun arr i -> A.unsafe_set arr (I.of_int i)); + + check_inval (fun () -> A.get [| 1; 2; 3|] (-#2147483647l)); + check_inval (fun () -> A.set [| 1; 2; 3|] (-#2147483647l) 0); + check_inval (fun () -> A.get [| 1; 2; 3|] (-#1l)); + check_inval (fun () -> A.set [| 1; 2; 3|] (-#1l) 1); + () + +let test_nativeint_u () = + let open By_nativeint_u in + + test_get (fun arr i -> A.get arr (I.of_int i)); + test_get (fun arr i -> A.unsafe_get arr (I.of_int i)); + + test_set (fun arr i -> A.set arr (I.of_int i)); + test_set (fun arr i -> A.unsafe_set arr (I.of_int i)); + + check_inval (fun () -> A.get [| 1; 2; 3|] (-#0x7fffffffn)); + check_inval (fun () -> A.set [| 1; 2; 3|] (-#0x7fffffffn) 0); + check_inval (fun () -> A.get [| 1; 2; 3|] (-#1n)); + check_inval (fun () -> A.set [| 1; 2; 3|] (-#1n) 1); + () + +let () = + test_int64_u (); + test_int32_u (); + test_nativeint_u (); + () diff --git a/compiler/tests-oxcaml/unboxed_int/dune b/compiler/tests-oxcaml/unboxed_int/dune new file mode 100644 index 0000000000..867140a438 --- /dev/null +++ b/compiler/tests-oxcaml/unboxed_int/dune @@ -0,0 +1,11 @@ +(env + (_ + (flags + (:standard + (-w -32))))) + +(tests + (names array_indexing stringlike_indexing) + (build_if %{oxcaml_supported}) + (libraries stdlib_stable stdlib_upstream_compatible) + (modes js wasm)) diff --git a/compiler/tests-oxcaml/unboxed_int/stringlike_indexing.ml b/compiler/tests-oxcaml/unboxed_int/stringlike_indexing.ml new file mode 100644 index 0000000000..2a46480d80 --- /dev/null +++ b/compiler/tests-oxcaml/unboxed_int/stringlike_indexing.ml @@ -0,0 +1,3968 @@ +(* TEST + flambda2; + include stdlib_upstream_compatible; + include stdlib_stable; + { + native; + }{ + flags = "-O3"; + native; + }{ + bytecode; + }{ + flags = "-extension layouts_alpha"; + native; + }{ + flags = "-extension layouts_alpha -O3"; + native; + }{ + flags = "-extension layouts_alpha"; + bytecode; + }{ + flags = "-extension layouts_beta"; + native; + }{ + flags = "-extension layouts_beta -O3"; + native; + }{ + flags = "-extension layouts_beta"; + bytecode; + } +*) + +let lengths = List.init 17 (fun x -> x) @ List.init 17 (fun x -> 300 + x) + +type exn += Test_failed + +let create_s length = + String.init length (fun i -> i * 7 mod 256 |> char_of_int) +;; + +let create_b length = create_s length |> Bytes.of_string + +open struct + open Bigarray + + type bigstring = (char, int8_unsigned_elt, c_layout) Array1.t + + let bigstring_of_string s = + let a = Array1.create char c_layout (String.length s) in + for i = 0 to String.length s - 1 do + a.{i} <- s.[i] + done; + a + + let create_bs length = create_s length |> bigstring_of_string +end + +module Tester (Primitives : sig + type boxed_index + type boxed_data + type container + + val create : int -> container + val generate_data : int -> boxed_data + val to_index : int -> boxed_index + val data_equal : boxed_data -> boxed_data -> bool + + type 'a getter := container -> 'a -> boxed_data + type 'a setter := container -> 'a -> boxed_data -> unit + + val get_reference : int getter + val get_safe : boxed_index getter + val get_unsafe : boxed_index getter + val set_reference : int setter + val set_safe : boxed_index setter + val set_unsafe : boxed_index setter + val extra_bounds_checks : boxed_index list + end) : sig end = struct + open Primitives + + let make_tester_functions length = + let for_reference = create length + and for_safe = create length + and for_unsafe = create length in + let check_get_bounds i = + try + let _ = get_safe for_safe i in + assert false + with + | Invalid_argument _ -> () + in + let check_set_bounds i x = + try + let _ = set_safe for_safe i x in + assert false + with + | Invalid_argument _ -> () + in + let check_get i = + let test_i = to_index i in + try + let res = get_reference for_reference i in + try + assert (data_equal res (get_safe for_safe test_i)); + assert (data_equal res (get_unsafe for_unsafe test_i)) + with + | _ -> raise Test_failed + with + | Test_failed -> assert false + | Invalid_argument _ -> check_get_bounds test_i + | _ -> + (try + let _ = get_safe for_safe test_i in + assert false + with + | Invalid_argument _ -> assert false + | _ -> ()) + in + let check_set i x = + let test_i = to_index i in + try + set_reference for_reference i x; + try + set_safe for_safe test_i x; + assert (data_equal x (get_reference for_safe i)); + set_unsafe for_unsafe test_i x; + assert (data_equal x (get_reference for_unsafe i)); + (* Check that we didn't ruin adjacent indices *) + check_get (i - 1); + check_get (i + 1) + with + | _ -> raise Test_failed + with + | Test_failed -> assert false + | Invalid_argument _ -> check_set_bounds test_i x + | _ -> + (try + set_safe for_safe test_i x; + assert false + with + | Invalid_argument _ -> assert false + | _ -> ()) + in + check_get_bounds, check_get, check_set_bounds, check_set + ;; + + let test length = + Random.init 1234; + let check_get_bounds, check_get, check_set_bounds, check_set = + make_tester_functions length + in + for i = -1 to length + 1 do + check_get i; + check_set i (generate_data i) + done; + List.iter + (fun bound -> + check_get_bounds bound; + check_set_bounds bound (generate_data 1)) + extra_bounds_checks + ;; + + let () = List.iter test lengths +end + +module Tester_no_set (Primitives : sig + type boxed_index + type boxed_data + type container + + val create : int -> container + val generate_data : int -> boxed_data + val to_index : int -> boxed_index + val data_equal : boxed_data -> boxed_data -> bool + + type 'a getter := container -> 'a -> boxed_data + + val get_reference : int getter + val get_safe : boxed_index getter + val get_unsafe : boxed_index getter + val extra_bounds_checks : boxed_index list + end) : sig end = struct + open Primitives + + let make_tester_functions length = + let for_reference = create length + and for_safe = create length + and for_unsafe = create length in + let check_get_bounds i = + try + let _ = get_safe for_safe i in + assert false + with + | Invalid_argument _ -> () + in + let check_get i = + let test_i = to_index i in + try + let res = get_reference for_reference i in + try + assert (data_equal res (get_safe for_safe test_i)); + assert (data_equal res (get_unsafe for_unsafe test_i)) + with + | _ -> raise Test_failed + with + | Test_failed -> assert false + | Invalid_argument _ -> check_get_bounds test_i + | _ -> + (try + let _ = get_safe for_safe test_i in + assert false + with + | Invalid_argument _ -> assert false + | _ -> ()) + in + check_get_bounds, check_get + ;; + + let test length = + Random.init 1234; + let check_get_bounds, check_get = make_tester_functions length in + for i = -1 to length + 1 do + check_get i; + done; + List.iter (fun bound -> check_get_bounds bound) extra_bounds_checks + ;; + + let () = List.iter test lengths +end + + +open struct + + type boxed_index = nativeint + type boxed_data = int + + let generate_data = + fun i -> + match i mod 4 with + | 0 -> Int.zero + | 1 -> (Int.(shift_left one) (16 - 1)) + | 2 -> + (let shift = 16 - 1 in + Int.(lognot (shift_left (shift_right (lognot zero) shift) shift))) + | _ -> Random.int_in_range ~min:Int.zero ~max:(Int.(shift_left one) (16 - 1)) + + + let to_index = Nativeint.of_int + let data_equal = Int.equal + let unbox_index = Stdlib_upstream_compatible.Nativeint_u.of_nativeint + let unbox_data = fun x -> x + let box_data = fun x -> x + let extra_bounds_checks = Nativeint.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> int + = "%caml_string_get16" + + external get_safe + : string + -> nativeint# + -> int + = "%caml_string_get16_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> nativeint# + -> int + = "%caml_string_get16u_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> int + = "%caml_bytes_get16" + + external get_safe + : bytes + -> nativeint# + -> int + = "%caml_bytes_get16_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> nativeint# + -> int + = "%caml_bytes_get16u_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> int + -> unit + = "%caml_bytes_set16" + + external set_safe + : bytes + -> nativeint# + -> int + -> unit + = "%caml_bytes_set16_indexed_by_nativeint#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> nativeint# + -> int + -> unit + = "%caml_bytes_set16u_indexed_by_nativeint#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> int + = "%caml_bigstring_get16" + + external get_safe + : bigstring + -> nativeint# + -> int + = "%caml_bigstring_get16_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> nativeint# + -> int + = "%caml_bigstring_get16u_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> int + -> unit + = "%caml_bigstring_set16" + + external set_safe + : bigstring + -> nativeint# + -> int + -> unit + = "%caml_bigstring_set16_indexed_by_nativeint#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> nativeint# + -> int + -> unit + = "%caml_bigstring_set16u_indexed_by_nativeint#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = nativeint + type boxed_data = int32 + + let generate_data = + fun i -> + match i mod 4 with + | 0 -> Int32.zero + | 1 -> Int32.min_int + | 2 -> Int32.max_int + | _ -> Random.int32_in_range ~min:Int32.min_int ~max:Int32.max_int + + + let to_index = Nativeint.of_int + let data_equal = Int32.equal + let unbox_index = Stdlib_upstream_compatible.Nativeint_u.of_nativeint + let unbox_data = fun x -> x + let box_data = fun x -> x + let extra_bounds_checks = Nativeint.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> int32 + = "%caml_string_get32" + + external get_safe + : string + -> nativeint# + -> int32 + = "%caml_string_get32_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> nativeint# + -> int32 + = "%caml_string_get32u_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> int32 + = "%caml_bytes_get32" + + external get_safe + : bytes + -> nativeint# + -> int32 + = "%caml_bytes_get32_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> nativeint# + -> int32 + = "%caml_bytes_get32u_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> int32 + -> unit + = "%caml_bytes_set32" + + external set_safe + : bytes + -> nativeint# + -> int32 + -> unit + = "%caml_bytes_set32_indexed_by_nativeint#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> nativeint# + -> int32 + -> unit + = "%caml_bytes_set32u_indexed_by_nativeint#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> int32 + = "%caml_bigstring_get32" + + external get_safe + : bigstring + -> nativeint# + -> int32 + = "%caml_bigstring_get32_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> nativeint# + -> int32 + = "%caml_bigstring_get32u_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> int32 + -> unit + = "%caml_bigstring_set32" + + external set_safe + : bigstring + -> nativeint# + -> int32 + -> unit + = "%caml_bigstring_set32_indexed_by_nativeint#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> nativeint# + -> int32 + -> unit + = "%caml_bigstring_set32u_indexed_by_nativeint#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = nativeint + type boxed_data = int64 + + let generate_data = + fun i -> + match i mod 4 with + | 0 -> Int64.zero + | 1 -> Int64.min_int + | 2 -> Int64.max_int + | _ -> Random.int64_in_range ~min:Int64.min_int ~max:Int64.max_int + + + let to_index = Nativeint.of_int + let data_equal = Int64.equal + let unbox_index = Stdlib_upstream_compatible.Nativeint_u.of_nativeint + let unbox_data = fun x -> x + let box_data = fun x -> x + let extra_bounds_checks = Nativeint.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> int64 + = "%caml_string_get64" + + external get_safe + : string + -> nativeint# + -> int64 + = "%caml_string_get64_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> nativeint# + -> int64 + = "%caml_string_get64u_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> int64 + = "%caml_bytes_get64" + + external get_safe + : bytes + -> nativeint# + -> int64 + = "%caml_bytes_get64_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> nativeint# + -> int64 + = "%caml_bytes_get64u_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> int64 + -> unit + = "%caml_bytes_set64" + + external set_safe + : bytes + -> nativeint# + -> int64 + -> unit + = "%caml_bytes_set64_indexed_by_nativeint#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> nativeint# + -> int64 + -> unit + = "%caml_bytes_set64u_indexed_by_nativeint#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> int64 + = "%caml_bigstring_get64" + + external get_safe + : bigstring + -> nativeint# + -> int64 + = "%caml_bigstring_get64_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> nativeint# + -> int64 + = "%caml_bigstring_get64u_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> int64 + -> unit + = "%caml_bigstring_set64" + + external set_safe + : bigstring + -> nativeint# + -> int64 + -> unit + = "%caml_bigstring_set64_indexed_by_nativeint#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> nativeint# + -> int64 + -> unit + = "%caml_bigstring_set64u_indexed_by_nativeint#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = nativeint + type boxed_data = int32 + + let generate_data = + fun i -> + match i mod 4 with + | 0 -> Int32.zero + | 1 -> Int32.min_int + | 2 -> Int32.max_int + | _ -> Random.int32_in_range ~min:Int32.min_int ~max:Int32.max_int + + + let to_index = Nativeint.of_int + let data_equal = Int32.equal + let unbox_index = Stdlib_upstream_compatible.Nativeint_u.of_nativeint + let unbox_data = Stdlib_upstream_compatible.Int32_u.of_int32 + let box_data = Stdlib_upstream_compatible.Int32_u.to_int32 + let extra_bounds_checks = Nativeint.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> int32 + = "%caml_string_get32" + + external get_safe + : string + -> nativeint# + -> int32# + = "%caml_string_get32#_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> nativeint# + -> int32# + = "%caml_string_get32u#_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> int32 + = "%caml_bytes_get32" + + external get_safe + : bytes + -> nativeint# + -> int32# + = "%caml_bytes_get32#_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> nativeint# + -> int32# + = "%caml_bytes_get32u#_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> int32 + -> unit + = "%caml_bytes_set32" + + external set_safe + : bytes + -> nativeint# + -> int32# + -> unit + = "%caml_bytes_set32#_indexed_by_nativeint#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> nativeint# + -> int32# + -> unit + = "%caml_bytes_set32u#_indexed_by_nativeint#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> int32 + = "%caml_bigstring_get32" + + external get_safe + : bigstring + -> nativeint# + -> int32# + = "%caml_bigstring_get32#_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> nativeint# + -> int32# + = "%caml_bigstring_get32u#_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> int32 + -> unit + = "%caml_bigstring_set32" + + external set_safe + : bigstring + -> nativeint# + -> int32# + -> unit + = "%caml_bigstring_set32#_indexed_by_nativeint#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> nativeint# + -> int32# + -> unit + = "%caml_bigstring_set32u#_indexed_by_nativeint#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = nativeint + type boxed_data = int64 + + let generate_data = + fun i -> + match i mod 4 with + | 0 -> Int64.zero + | 1 -> Int64.min_int + | 2 -> Int64.max_int + | _ -> Random.int64_in_range ~min:Int64.min_int ~max:Int64.max_int + + + let to_index = Nativeint.of_int + let data_equal = Int64.equal + let unbox_index = Stdlib_upstream_compatible.Nativeint_u.of_nativeint + let unbox_data = Stdlib_upstream_compatible.Int64_u.of_int64 + let box_data = Stdlib_upstream_compatible.Int64_u.to_int64 + let extra_bounds_checks = Nativeint.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> int64 + = "%caml_string_get64" + + external get_safe + : string + -> nativeint# + -> int64# + = "%caml_string_get64#_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> nativeint# + -> int64# + = "%caml_string_get64u#_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> int64 + = "%caml_bytes_get64" + + external get_safe + : bytes + -> nativeint# + -> int64# + = "%caml_bytes_get64#_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> nativeint# + -> int64# + = "%caml_bytes_get64u#_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> int64 + -> unit + = "%caml_bytes_set64" + + external set_safe + : bytes + -> nativeint# + -> int64# + -> unit + = "%caml_bytes_set64#_indexed_by_nativeint#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> nativeint# + -> int64# + -> unit + = "%caml_bytes_set64u#_indexed_by_nativeint#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> int64 + = "%caml_bigstring_get64" + + external get_safe + : bigstring + -> nativeint# + -> int64# + = "%caml_bigstring_get64#_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> nativeint# + -> int64# + = "%caml_bigstring_get64u#_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> int64 + -> unit + = "%caml_bigstring_set64" + + external set_safe + : bigstring + -> nativeint# + -> int64# + -> unit + = "%caml_bigstring_set64#_indexed_by_nativeint#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> nativeint# + -> int64# + -> unit + = "%caml_bigstring_set64u#_indexed_by_nativeint#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = nativeint + type boxed_data = float32 + + let generate_data = + fun _ -> + let f = + let f = Random.float Float.max_float in + if Random.bool () then Float.neg f else f + in + Stdlib_stable.Float32.of_float f + + let to_index = Nativeint.of_int + let data_equal = Stdlib_stable.Float32.equal + let unbox_index = Stdlib_upstream_compatible.Nativeint_u.of_nativeint + let unbox_data = fun x -> x + let box_data = fun x -> x + let extra_bounds_checks = Nativeint.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> float32 + = "%caml_string_getf32" + + external get_safe + : string + -> nativeint# + -> float32 + = "%caml_string_getf32_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> nativeint# + -> float32 + = "%caml_string_getf32u_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> float32 + = "%caml_bytes_getf32" + + external get_safe + : bytes + -> nativeint# + -> float32 + = "%caml_bytes_getf32_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> nativeint# + -> float32 + = "%caml_bytes_getf32u_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> float32 + -> unit + = "%caml_bytes_setf32" + + external set_safe + : bytes + -> nativeint# + -> float32 + -> unit + = "%caml_bytes_setf32_indexed_by_nativeint#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> nativeint# + -> float32 + -> unit + = "%caml_bytes_setf32u_indexed_by_nativeint#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> float32 + = "%caml_bigstring_getf32" + + external get_safe + : bigstring + -> nativeint# + -> float32 + = "%caml_bigstring_getf32_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> nativeint# + -> float32 + = "%caml_bigstring_getf32u_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> float32 + -> unit + = "%caml_bigstring_setf32" + + external set_safe + : bigstring + -> nativeint# + -> float32 + -> unit + = "%caml_bigstring_setf32_indexed_by_nativeint#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> nativeint# + -> float32 + -> unit + = "%caml_bigstring_setf32u_indexed_by_nativeint#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = nativeint + type boxed_data = float32 + + let generate_data = + fun _ -> + let f = + let f = Random.float Float.max_float in + if Random.bool () then Float.neg f else f + in + Stdlib_stable.Float32.of_float f + + let to_index = Nativeint.of_int + let data_equal = Stdlib_stable.Float32.equal + let unbox_index = Stdlib_upstream_compatible.Nativeint_u.of_nativeint + let unbox_data = Stdlib_stable.Float32_u.of_float32 + let box_data = Stdlib_stable.Float32_u.to_float32 + let extra_bounds_checks = Nativeint.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> float32 + = "%caml_string_getf32" + + external get_safe + : string + -> nativeint# + -> float32# + = "%caml_string_getf32#_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> nativeint# + -> float32# + = "%caml_string_getf32u#_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> float32 + = "%caml_bytes_getf32" + + external get_safe + : bytes + -> nativeint# + -> float32# + = "%caml_bytes_getf32#_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> nativeint# + -> float32# + = "%caml_bytes_getf32u#_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> float32 + -> unit + = "%caml_bytes_setf32" + + external set_safe + : bytes + -> nativeint# + -> float32# + -> unit + = "%caml_bytes_setf32#_indexed_by_nativeint#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> nativeint# + -> float32# + -> unit + = "%caml_bytes_setf32u#_indexed_by_nativeint#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> float32 + = "%caml_bigstring_getf32" + + external get_safe + : bigstring + -> nativeint# + -> float32# + = "%caml_bigstring_getf32#_indexed_by_nativeint#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> nativeint# + -> float32# + = "%caml_bigstring_getf32u#_indexed_by_nativeint#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> float32 + -> unit + = "%caml_bigstring_setf32" + + external set_safe + : bigstring + -> nativeint# + -> float32# + -> unit + = "%caml_bigstring_setf32#_indexed_by_nativeint#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> nativeint# + -> float32# + -> unit + = "%caml_bigstring_setf32u#_indexed_by_nativeint#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = int32 + type boxed_data = int + + let generate_data = + fun i -> + match i mod 4 with + | 0 -> Int.zero + | 1 -> (Int.(shift_left one) (16 - 1)) + | 2 -> + (let shift = 16 - 1 in + Int.(lognot (shift_left (shift_right (lognot zero) shift) shift))) + | _ -> Random.int_in_range ~min:Int.zero ~max:(Int.(shift_left one) (16 - 1)) + + + let to_index = Int32.of_int + let data_equal = Int.equal + let unbox_index = Stdlib_upstream_compatible.Int32_u.of_int32 + let unbox_data = fun x -> x + let box_data = fun x -> x + let extra_bounds_checks = Int32.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> int + = "%caml_string_get16" + + external get_safe + : string + -> int32# + -> int + = "%caml_string_get16_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> int32# + -> int + = "%caml_string_get16u_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> int + = "%caml_bytes_get16" + + external get_safe + : bytes + -> int32# + -> int + = "%caml_bytes_get16_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> int32# + -> int + = "%caml_bytes_get16u_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> int + -> unit + = "%caml_bytes_set16" + + external set_safe + : bytes + -> int32# + -> int + -> unit + = "%caml_bytes_set16_indexed_by_int32#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> int32# + -> int + -> unit + = "%caml_bytes_set16u_indexed_by_int32#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> int + = "%caml_bigstring_get16" + + external get_safe + : bigstring + -> int32# + -> int + = "%caml_bigstring_get16_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> int32# + -> int + = "%caml_bigstring_get16u_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> int + -> unit + = "%caml_bigstring_set16" + + external set_safe + : bigstring + -> int32# + -> int + -> unit + = "%caml_bigstring_set16_indexed_by_int32#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> int32# + -> int + -> unit + = "%caml_bigstring_set16u_indexed_by_int32#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = int32 + type boxed_data = int32 + + let generate_data = + fun i -> + match i mod 4 with + | 0 -> Int32.zero + | 1 -> Int32.min_int + | 2 -> Int32.max_int + | _ -> Random.int32_in_range ~min:Int32.min_int ~max:Int32.max_int + + + let to_index = Int32.of_int + let data_equal = Int32.equal + let unbox_index = Stdlib_upstream_compatible.Int32_u.of_int32 + let unbox_data = fun x -> x + let box_data = fun x -> x + let extra_bounds_checks = Int32.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> int32 + = "%caml_string_get32" + + external get_safe + : string + -> int32# + -> int32 + = "%caml_string_get32_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> int32# + -> int32 + = "%caml_string_get32u_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> int32 + = "%caml_bytes_get32" + + external get_safe + : bytes + -> int32# + -> int32 + = "%caml_bytes_get32_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> int32# + -> int32 + = "%caml_bytes_get32u_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> int32 + -> unit + = "%caml_bytes_set32" + + external set_safe + : bytes + -> int32# + -> int32 + -> unit + = "%caml_bytes_set32_indexed_by_int32#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> int32# + -> int32 + -> unit + = "%caml_bytes_set32u_indexed_by_int32#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> int32 + = "%caml_bigstring_get32" + + external get_safe + : bigstring + -> int32# + -> int32 + = "%caml_bigstring_get32_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> int32# + -> int32 + = "%caml_bigstring_get32u_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> int32 + -> unit + = "%caml_bigstring_set32" + + external set_safe + : bigstring + -> int32# + -> int32 + -> unit + = "%caml_bigstring_set32_indexed_by_int32#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> int32# + -> int32 + -> unit + = "%caml_bigstring_set32u_indexed_by_int32#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = int32 + type boxed_data = int64 + + let generate_data = + fun i -> + match i mod 4 with + | 0 -> Int64.zero + | 1 -> Int64.min_int + | 2 -> Int64.max_int + | _ -> Random.int64_in_range ~min:Int64.min_int ~max:Int64.max_int + + + let to_index = Int32.of_int + let data_equal = Int64.equal + let unbox_index = Stdlib_upstream_compatible.Int32_u.of_int32 + let unbox_data = fun x -> x + let box_data = fun x -> x + let extra_bounds_checks = Int32.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> int64 + = "%caml_string_get64" + + external get_safe + : string + -> int32# + -> int64 + = "%caml_string_get64_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> int32# + -> int64 + = "%caml_string_get64u_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> int64 + = "%caml_bytes_get64" + + external get_safe + : bytes + -> int32# + -> int64 + = "%caml_bytes_get64_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> int32# + -> int64 + = "%caml_bytes_get64u_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> int64 + -> unit + = "%caml_bytes_set64" + + external set_safe + : bytes + -> int32# + -> int64 + -> unit + = "%caml_bytes_set64_indexed_by_int32#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> int32# + -> int64 + -> unit + = "%caml_bytes_set64u_indexed_by_int32#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> int64 + = "%caml_bigstring_get64" + + external get_safe + : bigstring + -> int32# + -> int64 + = "%caml_bigstring_get64_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> int32# + -> int64 + = "%caml_bigstring_get64u_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> int64 + -> unit + = "%caml_bigstring_set64" + + external set_safe + : bigstring + -> int32# + -> int64 + -> unit + = "%caml_bigstring_set64_indexed_by_int32#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> int32# + -> int64 + -> unit + = "%caml_bigstring_set64u_indexed_by_int32#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = int32 + type boxed_data = int32 + + let generate_data = + fun i -> + match i mod 4 with + | 0 -> Int32.zero + | 1 -> Int32.min_int + | 2 -> Int32.max_int + | _ -> Random.int32_in_range ~min:Int32.min_int ~max:Int32.max_int + + + let to_index = Int32.of_int + let data_equal = Int32.equal + let unbox_index = Stdlib_upstream_compatible.Int32_u.of_int32 + let unbox_data = Stdlib_upstream_compatible.Int32_u.of_int32 + let box_data = Stdlib_upstream_compatible.Int32_u.to_int32 + let extra_bounds_checks = Int32.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> int32 + = "%caml_string_get32" + + external get_safe + : string + -> int32# + -> int32# + = "%caml_string_get32#_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> int32# + -> int32# + = "%caml_string_get32u#_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> int32 + = "%caml_bytes_get32" + + external get_safe + : bytes + -> int32# + -> int32# + = "%caml_bytes_get32#_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> int32# + -> int32# + = "%caml_bytes_get32u#_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> int32 + -> unit + = "%caml_bytes_set32" + + external set_safe + : bytes + -> int32# + -> int32# + -> unit + = "%caml_bytes_set32#_indexed_by_int32#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> int32# + -> int32# + -> unit + = "%caml_bytes_set32u#_indexed_by_int32#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> int32 + = "%caml_bigstring_get32" + + external get_safe + : bigstring + -> int32# + -> int32# + = "%caml_bigstring_get32#_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> int32# + -> int32# + = "%caml_bigstring_get32u#_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> int32 + -> unit + = "%caml_bigstring_set32" + + external set_safe + : bigstring + -> int32# + -> int32# + -> unit + = "%caml_bigstring_set32#_indexed_by_int32#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> int32# + -> int32# + -> unit + = "%caml_bigstring_set32u#_indexed_by_int32#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = int32 + type boxed_data = int64 + + let generate_data = + fun i -> + match i mod 4 with + | 0 -> Int64.zero + | 1 -> Int64.min_int + | 2 -> Int64.max_int + | _ -> Random.int64_in_range ~min:Int64.min_int ~max:Int64.max_int + + + let to_index = Int32.of_int + let data_equal = Int64.equal + let unbox_index = Stdlib_upstream_compatible.Int32_u.of_int32 + let unbox_data = Stdlib_upstream_compatible.Int64_u.of_int64 + let box_data = Stdlib_upstream_compatible.Int64_u.to_int64 + let extra_bounds_checks = Int32.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> int64 + = "%caml_string_get64" + + external get_safe + : string + -> int32# + -> int64# + = "%caml_string_get64#_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> int32# + -> int64# + = "%caml_string_get64u#_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> int64 + = "%caml_bytes_get64" + + external get_safe + : bytes + -> int32# + -> int64# + = "%caml_bytes_get64#_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> int32# + -> int64# + = "%caml_bytes_get64u#_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> int64 + -> unit + = "%caml_bytes_set64" + + external set_safe + : bytes + -> int32# + -> int64# + -> unit + = "%caml_bytes_set64#_indexed_by_int32#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> int32# + -> int64# + -> unit + = "%caml_bytes_set64u#_indexed_by_int32#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> int64 + = "%caml_bigstring_get64" + + external get_safe + : bigstring + -> int32# + -> int64# + = "%caml_bigstring_get64#_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> int32# + -> int64# + = "%caml_bigstring_get64u#_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> int64 + -> unit + = "%caml_bigstring_set64" + + external set_safe + : bigstring + -> int32# + -> int64# + -> unit + = "%caml_bigstring_set64#_indexed_by_int32#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> int32# + -> int64# + -> unit + = "%caml_bigstring_set64u#_indexed_by_int32#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = int32 + type boxed_data = float32 + + let generate_data = + fun _ -> + let f = + let f = Random.float Float.max_float in + if Random.bool () then Float.neg f else f + in + Stdlib_stable.Float32.of_float f + + let to_index = Int32.of_int + let data_equal = Stdlib_stable.Float32.equal + let unbox_index = Stdlib_upstream_compatible.Int32_u.of_int32 + let unbox_data = fun x -> x + let box_data = fun x -> x + let extra_bounds_checks = Int32.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> float32 + = "%caml_string_getf32" + + external get_safe + : string + -> int32# + -> float32 + = "%caml_string_getf32_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> int32# + -> float32 + = "%caml_string_getf32u_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> float32 + = "%caml_bytes_getf32" + + external get_safe + : bytes + -> int32# + -> float32 + = "%caml_bytes_getf32_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> int32# + -> float32 + = "%caml_bytes_getf32u_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> float32 + -> unit + = "%caml_bytes_setf32" + + external set_safe + : bytes + -> int32# + -> float32 + -> unit + = "%caml_bytes_setf32_indexed_by_int32#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> int32# + -> float32 + -> unit + = "%caml_bytes_setf32u_indexed_by_int32#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> float32 + = "%caml_bigstring_getf32" + + external get_safe + : bigstring + -> int32# + -> float32 + = "%caml_bigstring_getf32_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> int32# + -> float32 + = "%caml_bigstring_getf32u_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> float32 + -> unit + = "%caml_bigstring_setf32" + + external set_safe + : bigstring + -> int32# + -> float32 + -> unit + = "%caml_bigstring_setf32_indexed_by_int32#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> int32# + -> float32 + -> unit + = "%caml_bigstring_setf32u_indexed_by_int32#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = int32 + type boxed_data = float32 + + let generate_data = + fun _ -> + let f = + let f = Random.float Float.max_float in + if Random.bool () then Float.neg f else f + in + Stdlib_stable.Float32.of_float f + + let to_index = Int32.of_int + let data_equal = Stdlib_stable.Float32.equal + let unbox_index = Stdlib_upstream_compatible.Int32_u.of_int32 + let unbox_data = Stdlib_stable.Float32_u.of_float32 + let box_data = Stdlib_stable.Float32_u.to_float32 + let extra_bounds_checks = Int32.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> float32 + = "%caml_string_getf32" + + external get_safe + : string + -> int32# + -> float32# + = "%caml_string_getf32#_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> int32# + -> float32# + = "%caml_string_getf32u#_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> float32 + = "%caml_bytes_getf32" + + external get_safe + : bytes + -> int32# + -> float32# + = "%caml_bytes_getf32#_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> int32# + -> float32# + = "%caml_bytes_getf32u#_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> float32 + -> unit + = "%caml_bytes_setf32" + + external set_safe + : bytes + -> int32# + -> float32# + -> unit + = "%caml_bytes_setf32#_indexed_by_int32#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> int32# + -> float32# + -> unit + = "%caml_bytes_setf32u#_indexed_by_int32#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> float32 + = "%caml_bigstring_getf32" + + external get_safe + : bigstring + -> int32# + -> float32# + = "%caml_bigstring_getf32#_indexed_by_int32#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> int32# + -> float32# + = "%caml_bigstring_getf32u#_indexed_by_int32#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> float32 + -> unit + = "%caml_bigstring_setf32" + + external set_safe + : bigstring + -> int32# + -> float32# + -> unit + = "%caml_bigstring_setf32#_indexed_by_int32#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> int32# + -> float32# + -> unit + = "%caml_bigstring_setf32u#_indexed_by_int32#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = int64 + type boxed_data = int + + let generate_data = + fun i -> + match i mod 4 with + | 0 -> Int.zero + | 1 -> (Int.(shift_left one) (16 - 1)) + | 2 -> + (let shift = 16 - 1 in + Int.(lognot (shift_left (shift_right (lognot zero) shift) shift))) + | _ -> Random.int_in_range ~min:Int.zero ~max:(Int.(shift_left one) (16 - 1)) + + + let to_index = Int64.of_int + let data_equal = Int.equal + let unbox_index = Stdlib_upstream_compatible.Int64_u.of_int64 + let unbox_data = fun x -> x + let box_data = fun x -> x + let extra_bounds_checks = Int64.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> int + = "%caml_string_get16" + + external get_safe + : string + -> int64# + -> int + = "%caml_string_get16_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> int64# + -> int + = "%caml_string_get16u_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> int + = "%caml_bytes_get16" + + external get_safe + : bytes + -> int64# + -> int + = "%caml_bytes_get16_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> int64# + -> int + = "%caml_bytes_get16u_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> int + -> unit + = "%caml_bytes_set16" + + external set_safe + : bytes + -> int64# + -> int + -> unit + = "%caml_bytes_set16_indexed_by_int64#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> int64# + -> int + -> unit + = "%caml_bytes_set16u_indexed_by_int64#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> int + = "%caml_bigstring_get16" + + external get_safe + : bigstring + -> int64# + -> int + = "%caml_bigstring_get16_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> int64# + -> int + = "%caml_bigstring_get16u_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> int + -> unit + = "%caml_bigstring_set16" + + external set_safe + : bigstring + -> int64# + -> int + -> unit + = "%caml_bigstring_set16_indexed_by_int64#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> int64# + -> int + -> unit + = "%caml_bigstring_set16u_indexed_by_int64#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = int64 + type boxed_data = int32 + + let generate_data = + fun i -> + match i mod 4 with + | 0 -> Int32.zero + | 1 -> Int32.min_int + | 2 -> Int32.max_int + | _ -> Random.int32_in_range ~min:Int32.min_int ~max:Int32.max_int + + + let to_index = Int64.of_int + let data_equal = Int32.equal + let unbox_index = Stdlib_upstream_compatible.Int64_u.of_int64 + let unbox_data = fun x -> x + let box_data = fun x -> x + let extra_bounds_checks = Int64.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> int32 + = "%caml_string_get32" + + external get_safe + : string + -> int64# + -> int32 + = "%caml_string_get32_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> int64# + -> int32 + = "%caml_string_get32u_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> int32 + = "%caml_bytes_get32" + + external get_safe + : bytes + -> int64# + -> int32 + = "%caml_bytes_get32_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> int64# + -> int32 + = "%caml_bytes_get32u_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> int32 + -> unit + = "%caml_bytes_set32" + + external set_safe + : bytes + -> int64# + -> int32 + -> unit + = "%caml_bytes_set32_indexed_by_int64#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> int64# + -> int32 + -> unit + = "%caml_bytes_set32u_indexed_by_int64#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> int32 + = "%caml_bigstring_get32" + + external get_safe + : bigstring + -> int64# + -> int32 + = "%caml_bigstring_get32_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> int64# + -> int32 + = "%caml_bigstring_get32u_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> int32 + -> unit + = "%caml_bigstring_set32" + + external set_safe + : bigstring + -> int64# + -> int32 + -> unit + = "%caml_bigstring_set32_indexed_by_int64#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> int64# + -> int32 + -> unit + = "%caml_bigstring_set32u_indexed_by_int64#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = int64 + type boxed_data = int64 + + let generate_data = + fun i -> + match i mod 4 with + | 0 -> Int64.zero + | 1 -> Int64.min_int + | 2 -> Int64.max_int + | _ -> Random.int64_in_range ~min:Int64.min_int ~max:Int64.max_int + + + let to_index = Int64.of_int + let data_equal = Int64.equal + let unbox_index = Stdlib_upstream_compatible.Int64_u.of_int64 + let unbox_data = fun x -> x + let box_data = fun x -> x + let extra_bounds_checks = Int64.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> int64 + = "%caml_string_get64" + + external get_safe + : string + -> int64# + -> int64 + = "%caml_string_get64_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> int64# + -> int64 + = "%caml_string_get64u_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> int64 + = "%caml_bytes_get64" + + external get_safe + : bytes + -> int64# + -> int64 + = "%caml_bytes_get64_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> int64# + -> int64 + = "%caml_bytes_get64u_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> int64 + -> unit + = "%caml_bytes_set64" + + external set_safe + : bytes + -> int64# + -> int64 + -> unit + = "%caml_bytes_set64_indexed_by_int64#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> int64# + -> int64 + -> unit + = "%caml_bytes_set64u_indexed_by_int64#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> int64 + = "%caml_bigstring_get64" + + external get_safe + : bigstring + -> int64# + -> int64 + = "%caml_bigstring_get64_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> int64# + -> int64 + = "%caml_bigstring_get64u_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> int64 + -> unit + = "%caml_bigstring_set64" + + external set_safe + : bigstring + -> int64# + -> int64 + -> unit + = "%caml_bigstring_set64_indexed_by_int64#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> int64# + -> int64 + -> unit + = "%caml_bigstring_set64u_indexed_by_int64#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = int64 + type boxed_data = int32 + + let generate_data = + fun i -> + match i mod 4 with + | 0 -> Int32.zero + | 1 -> Int32.min_int + | 2 -> Int32.max_int + | _ -> Random.int32_in_range ~min:Int32.min_int ~max:Int32.max_int + + + let to_index = Int64.of_int + let data_equal = Int32.equal + let unbox_index = Stdlib_upstream_compatible.Int64_u.of_int64 + let unbox_data = Stdlib_upstream_compatible.Int32_u.of_int32 + let box_data = Stdlib_upstream_compatible.Int32_u.to_int32 + let extra_bounds_checks = Int64.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> int32 + = "%caml_string_get32" + + external get_safe + : string + -> int64# + -> int32# + = "%caml_string_get32#_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> int64# + -> int32# + = "%caml_string_get32u#_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> int32 + = "%caml_bytes_get32" + + external get_safe + : bytes + -> int64# + -> int32# + = "%caml_bytes_get32#_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> int64# + -> int32# + = "%caml_bytes_get32u#_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> int32 + -> unit + = "%caml_bytes_set32" + + external set_safe + : bytes + -> int64# + -> int32# + -> unit + = "%caml_bytes_set32#_indexed_by_int64#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> int64# + -> int32# + -> unit + = "%caml_bytes_set32u#_indexed_by_int64#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> int32 + = "%caml_bigstring_get32" + + external get_safe + : bigstring + -> int64# + -> int32# + = "%caml_bigstring_get32#_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> int64# + -> int32# + = "%caml_bigstring_get32u#_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> int32 + -> unit + = "%caml_bigstring_set32" + + external set_safe + : bigstring + -> int64# + -> int32# + -> unit + = "%caml_bigstring_set32#_indexed_by_int64#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> int64# + -> int32# + -> unit + = "%caml_bigstring_set32u#_indexed_by_int64#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = int64 + type boxed_data = int64 + + let generate_data = + fun i -> + match i mod 4 with + | 0 -> Int64.zero + | 1 -> Int64.min_int + | 2 -> Int64.max_int + | _ -> Random.int64_in_range ~min:Int64.min_int ~max:Int64.max_int + + + let to_index = Int64.of_int + let data_equal = Int64.equal + let unbox_index = Stdlib_upstream_compatible.Int64_u.of_int64 + let unbox_data = Stdlib_upstream_compatible.Int64_u.of_int64 + let box_data = Stdlib_upstream_compatible.Int64_u.to_int64 + let extra_bounds_checks = Int64.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> int64 + = "%caml_string_get64" + + external get_safe + : string + -> int64# + -> int64# + = "%caml_string_get64#_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> int64# + -> int64# + = "%caml_string_get64u#_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> int64 + = "%caml_bytes_get64" + + external get_safe + : bytes + -> int64# + -> int64# + = "%caml_bytes_get64#_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> int64# + -> int64# + = "%caml_bytes_get64u#_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> int64 + -> unit + = "%caml_bytes_set64" + + external set_safe + : bytes + -> int64# + -> int64# + -> unit + = "%caml_bytes_set64#_indexed_by_int64#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> int64# + -> int64# + -> unit + = "%caml_bytes_set64u#_indexed_by_int64#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> int64 + = "%caml_bigstring_get64" + + external get_safe + : bigstring + -> int64# + -> int64# + = "%caml_bigstring_get64#_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> int64# + -> int64# + = "%caml_bigstring_get64u#_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> int64 + -> unit + = "%caml_bigstring_set64" + + external set_safe + : bigstring + -> int64# + -> int64# + -> unit + = "%caml_bigstring_set64#_indexed_by_int64#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> int64# + -> int64# + -> unit + = "%caml_bigstring_set64u#_indexed_by_int64#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = int64 + type boxed_data = float32 + + let generate_data = + fun _ -> + let f = + let f = Random.float Float.max_float in + if Random.bool () then Float.neg f else f + in + Stdlib_stable.Float32.of_float f + + let to_index = Int64.of_int + let data_equal = Stdlib_stable.Float32.equal + let unbox_index = Stdlib_upstream_compatible.Int64_u.of_int64 + let unbox_data = fun x -> x + let box_data = fun x -> x + let extra_bounds_checks = Int64.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> float32 + = "%caml_string_getf32" + + external get_safe + : string + -> int64# + -> float32 + = "%caml_string_getf32_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> int64# + -> float32 + = "%caml_string_getf32u_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> float32 + = "%caml_bytes_getf32" + + external get_safe + : bytes + -> int64# + -> float32 + = "%caml_bytes_getf32_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> int64# + -> float32 + = "%caml_bytes_getf32u_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> float32 + -> unit + = "%caml_bytes_setf32" + + external set_safe + : bytes + -> int64# + -> float32 + -> unit + = "%caml_bytes_setf32_indexed_by_int64#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> int64# + -> float32 + -> unit + = "%caml_bytes_setf32u_indexed_by_int64#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> float32 + = "%caml_bigstring_getf32" + + external get_safe + : bigstring + -> int64# + -> float32 + = "%caml_bigstring_getf32_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> int64# + -> float32 + = "%caml_bigstring_getf32u_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> float32 + -> unit + = "%caml_bigstring_setf32" + + external set_safe + : bigstring + -> int64# + -> float32 + -> unit + = "%caml_bigstring_setf32_indexed_by_int64#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> int64# + -> float32 + -> unit + = "%caml_bigstring_setf32u_indexed_by_int64#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end + +open struct + + type boxed_index = int64 + type boxed_data = float32 + + let generate_data = + fun _ -> + let f = + let f = Random.float Float.max_float in + if Random.bool () then Float.neg f else f + in + Stdlib_stable.Float32.of_float f + + let to_index = Int64.of_int + let data_equal = Stdlib_stable.Float32.equal + let unbox_index = Stdlib_upstream_compatible.Int64_u.of_int64 + let unbox_data = Stdlib_stable.Float32_u.of_float32 + let box_data = Stdlib_stable.Float32_u.to_float32 + let extra_bounds_checks = Int64.[ min_int; max_int; add min_int one; sub zero one ] + + + module _ = Tester_no_set (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = string + + let create = create_s + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : string + -> int + -> float32 + = "%caml_string_getf32" + + external get_safe + : string + -> int64# + -> float32# + = "%caml_string_getf32#_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : string + -> int64# + -> float32# + = "%caml_string_getf32u#_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bytes + + let create = create_b + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bytes + -> int + -> float32 + = "%caml_bytes_getf32" + + external get_safe + : bytes + -> int64# + -> float32# + = "%caml_bytes_getf32#_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bytes + -> int64# + -> float32# + = "%caml_bytes_getf32u#_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bytes + -> int + -> float32 + -> unit + = "%caml_bytes_setf32" + + external set_safe + : bytes + -> int64# + -> float32# + -> unit + = "%caml_bytes_setf32#_indexed_by_int64#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bytes + -> int64# + -> float32# + -> unit + = "%caml_bytes_setf32u#_indexed_by_int64#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + module _ = Tester (struct + type nonrec boxed_index = boxed_index + type nonrec boxed_data = boxed_data + type container = bigstring + + let create = create_bs + let generate_data = generate_data + let to_index = to_index + let data_equal = data_equal + let extra_bounds_checks = extra_bounds_checks + + external get_reference + : bigstring + -> int + -> float32 + = "%caml_bigstring_getf32" + + external get_safe + : bigstring + -> int64# + -> float32# + = "%caml_bigstring_getf32#_indexed_by_int64#" + + let get_safe b i = box_data (get_safe b (unbox_index i)) + + external get_unsafe + : bigstring + -> int64# + -> float32# + = "%caml_bigstring_getf32u#_indexed_by_int64#" + + let get_unsafe b i = box_data (get_unsafe b (unbox_index i)) + + external set_reference + : bigstring + -> int + -> float32 + -> unit + = "%caml_bigstring_setf32" + + external set_safe + : bigstring + -> int64# + -> float32# + -> unit + = "%caml_bigstring_setf32#_indexed_by_int64#" + + let set_safe b i d = set_safe b (unbox_index i) (unbox_data d) + + external set_unsafe + : bigstring + -> int64# + -> float32# + -> unit + = "%caml_bigstring_setf32u#_indexed_by_int64#" + + let set_unsafe b i d = set_unsafe b (unbox_index i) (unbox_data d) + end) + + +end diff --git a/dune-project b/dune-project index 45b9ce66de..348a229970 100644 --- a/dune-project +++ b/dune-project @@ -1,5 +1,6 @@ -(lang dune 3.19) +(lang dune 3.20) (using menhir 3.0) +(using oxcaml 0.1) (name js_of_ocaml) (generate_opam_files true) (executables_implicit_empty_intf true) @@ -20,7 +21,7 @@ (ocaml (and (>= 4.13) (< 5.5))) (num :with-test) (ppx_expect (and (>= v0.16.1) :with-test)) - (ppxlib (>= 0.35)) + (ppxlib (or (>= 0.35) (= 0.33.0+ox))) (ocaml-compiler-libs (>= v0.12.4)) (re :with-test) (cmdliner (>= 1.1.0)) @@ -29,7 +30,10 @@ menhir menhirLib menhirSdk - (yojson (>= 2.1))) + (yojson (>= 2.1)) + ; Keep opam-dune-lint happy + (stdlib_stable (and :with-test (= os "never"))) + (stdlib_upstream_compatible (and :with-test (= os "never")))) (depopts ocamlfind) (conflicts @@ -49,7 +53,10 @@ (lwt (and (>= 2.4.4) (<> 5.9.2))) (num :with-test) (ppx_expect (and (>= v0.14.2) :with-test)) - (re (and (>= 1.9.0) :with-test))) + (re (and (>= 1.9.0) :with-test)) + ; Keep opam-dune-lint happy + (stdlib_stable (and :with-test (= os "never"))) + (stdlib_upstream_compatible (and :with-test (= os "never")))) (depopts graphics lwt_log @@ -63,10 +70,13 @@ (depends (ocaml (>= 4.13)) (js_of_ocaml (= :version)) - (ppxlib (>= 0.35)) + (ppxlib (or (>= 0.35) (= 0.33.0+ox))) (num :with-test) (ppx_expect (and (>= v0.14.2) :with-test)) (re (and (>= 1.9.0) :with-test)) + ; Keep opam-dune-lint happy + (stdlib_stable (and :with-test (= os "never"))) + (stdlib_upstream_compatible (and :with-test (= os "never"))) )) (package @@ -77,10 +87,13 @@ (depends (ocaml (>= 4.13)) (js_of_ocaml (= :version)) - (ppxlib (>= 0.35)) + (ppxlib (or (>= 0.35) (= 0.33.0+ox))) (num :with-test) (ppx_expect (and (>= v0.14.2) :with-test)) (re (and (>= 1.9.0) :with-test)) + ; Keep opam-dune-lint happy + (stdlib_stable (and :with-test (= os "never"))) + (stdlib_upstream_compatible (and :with-test (= os "never"))) )) (package @@ -96,8 +109,11 @@ (graphics :with-test) (num :with-test) (ppx_expect (and (>= v0.14.2) :with-test)) - (ppxlib (>= 0.35)) + (ppxlib (or (>= 0.35) (= 0.33.0+ox))) (re (and (>= 1.9.0) :with-test)) + ; Keep opam-dune-lint happy + (stdlib_stable (and :with-test (= os "never"))) + (stdlib_upstream_compatible (and :with-test (= os "never"))) )) (package @@ -115,6 +131,9 @@ (num :with-test) (ppx_expect (and (>= v0.14.2) :with-test)) (re (and (>= 1.9.0) :with-test)) + ; Keep opam-dune-lint happy + (stdlib_stable (and :with-test (= os "never"))) + (stdlib_upstream_compatible (and :with-test (= os "never"))) )) (package @@ -127,8 +146,11 @@ (js_of_ocaml-compiler (= :version)) (num :with-test) (ppx_expect (and (>= v0.14.2) :with-test)) - (ppxlib (>= 0.35)) + (ppxlib (or (>= 0.35) (= 0.33.0+ox))) (re (and (>= 1.9.0) :with-test)) + ; Keep opam-dune-lint happy + (stdlib_stable (and :with-test (= os "never"))) + (stdlib_upstream_compatible (and :with-test (= os "never"))) )) (package @@ -141,7 +163,7 @@ (js_of_ocaml (= :version)) (num :with-test) (ppx_expect (and (>= v0.14.2) :with-test)) - (ppxlib (>= 0.35)) + (ppxlib (or (>= 0.35) (= 0.33.0+ox))) (re :with-test) (cmdliner (>= 1.1.0)) (opam-format :with-test) @@ -150,7 +172,10 @@ menhirLib menhirSdk (yojson (>= 2.1)) - binaryen-bin) + binaryen-bin + ; Keep opam-dune-lint happy + (stdlib_stable (and :with-test (= os "never"))) + (stdlib_upstream_compatible (and :with-test (= os "never")))) (depopts ocamlfind) (conflicts diff --git a/js_of_ocaml-compiler.opam b/js_of_ocaml-compiler.opam index 4d3cbdde9c..34ba74d11e 100644 --- a/js_of_ocaml-compiler.opam +++ b/js_of_ocaml-compiler.opam @@ -12,11 +12,11 @@ homepage: "https://ocsigen.org/js_of_ocaml/latest/manual/overview" doc: "https://ocsigen.org/js_of_ocaml/latest/manual/overview" bug-reports: "https://github.com/ocsigen/js_of_ocaml/issues" depends: [ - "dune" {>= "3.19"} + "dune" {>= "3.20"} "ocaml" {>= "4.13" & < "5.5"} "num" {with-test} "ppx_expect" {>= "v0.16.1" & with-test} - "ppxlib" {>= "0.35"} + "ppxlib" {>= "0.35" | = "0.33.0+ox"} "ocaml-compiler-libs" {>= "v0.12.4"} "re" {with-test} "cmdliner" {>= "1.1.0"} @@ -26,6 +26,8 @@ depends: [ "menhirLib" "menhirSdk" "yojson" {>= "2.1"} + "stdlib_stable" {with-test & "os" = "never"} + "stdlib_upstream_compatible" {with-test & "os" = "never"} "odoc" {with-doc} ] depopts: ["ocamlfind"] diff --git a/js_of_ocaml-lwt.opam b/js_of_ocaml-lwt.opam index 8f821e5f52..6b884f2890 100644 --- a/js_of_ocaml-lwt.opam +++ b/js_of_ocaml-lwt.opam @@ -12,7 +12,7 @@ homepage: "https://ocsigen.org/js_of_ocaml/latest/manual/overview" doc: "https://ocsigen.org/js_of_ocaml/latest/manual/overview" bug-reports: "https://github.com/ocsigen/js_of_ocaml/issues" depends: [ - "dune" {>= "3.19"} + "dune" {>= "3.20"} "ocaml" {>= "4.13"} "js_of_ocaml" {= version} "js_of_ocaml-ppx" {= version} @@ -20,6 +20,8 @@ depends: [ "num" {with-test} "ppx_expect" {>= "v0.14.2" & with-test} "re" {>= "1.9.0" & with-test} + "stdlib_stable" {with-test & "os" = "never"} + "stdlib_upstream_compatible" {with-test & "os" = "never"} "odoc" {with-doc} ] depopts: ["graphics" "lwt_log"] diff --git a/js_of_ocaml-ppx.opam b/js_of_ocaml-ppx.opam index 65872d8ecf..d384b95743 100644 --- a/js_of_ocaml-ppx.opam +++ b/js_of_ocaml-ppx.opam @@ -12,13 +12,15 @@ homepage: "https://ocsigen.org/js_of_ocaml/latest/manual/overview" doc: "https://ocsigen.org/js_of_ocaml/latest/manual/overview" bug-reports: "https://github.com/ocsigen/js_of_ocaml/issues" depends: [ - "dune" {>= "3.19"} + "dune" {>= "3.20"} "ocaml" {>= "4.13"} "js_of_ocaml" {= version} - "ppxlib" {>= "0.35"} + "ppxlib" {>= "0.35" | = "0.33.0+ox"} "num" {with-test} "ppx_expect" {>= "v0.14.2" & with-test} "re" {>= "1.9.0" & with-test} + "stdlib_stable" {with-test & "os" = "never"} + "stdlib_upstream_compatible" {with-test & "os" = "never"} "odoc" {with-doc} ] dev-repo: "git+https://github.com/ocsigen/js_of_ocaml.git" diff --git a/js_of_ocaml-ppx_deriving_json.opam b/js_of_ocaml-ppx_deriving_json.opam index 65872d8ecf..d384b95743 100644 --- a/js_of_ocaml-ppx_deriving_json.opam +++ b/js_of_ocaml-ppx_deriving_json.opam @@ -12,13 +12,15 @@ homepage: "https://ocsigen.org/js_of_ocaml/latest/manual/overview" doc: "https://ocsigen.org/js_of_ocaml/latest/manual/overview" bug-reports: "https://github.com/ocsigen/js_of_ocaml/issues" depends: [ - "dune" {>= "3.19"} + "dune" {>= "3.20"} "ocaml" {>= "4.13"} "js_of_ocaml" {= version} - "ppxlib" {>= "0.35"} + "ppxlib" {>= "0.35" | = "0.33.0+ox"} "num" {with-test} "ppx_expect" {>= "v0.14.2" & with-test} "re" {>= "1.9.0" & with-test} + "stdlib_stable" {with-test & "os" = "never"} + "stdlib_upstream_compatible" {with-test & "os" = "never"} "odoc" {with-doc} ] dev-repo: "git+https://github.com/ocsigen/js_of_ocaml.git" diff --git a/js_of_ocaml-toplevel.opam b/js_of_ocaml-toplevel.opam index 6244f14f77..1671ea7d68 100644 --- a/js_of_ocaml-toplevel.opam +++ b/js_of_ocaml-toplevel.opam @@ -12,15 +12,17 @@ homepage: "https://ocsigen.org/js_of_ocaml/latest/manual/overview" doc: "https://ocsigen.org/js_of_ocaml/latest/manual/overview" bug-reports: "https://github.com/ocsigen/js_of_ocaml/issues" depends: [ - "dune" {>= "3.19"} + "dune" {>= "3.20"} "ocaml" {>= "4.13"} "js_of_ocaml-compiler" {= version} "ocamlfind" {>= "1.5.1"} "graphics" {with-test} "num" {with-test} "ppx_expect" {>= "v0.14.2" & with-test} - "ppxlib" {>= "0.35"} + "ppxlib" {>= "0.35" | = "0.33.0+ox"} "re" {>= "1.9.0" & with-test} + "stdlib_stable" {with-test & "os" = "never"} + "stdlib_upstream_compatible" {with-test & "os" = "never"} "odoc" {with-doc} ] dev-repo: "git+https://github.com/ocsigen/js_of_ocaml.git" diff --git a/js_of_ocaml-tyxml.opam b/js_of_ocaml-tyxml.opam index 1228c707d4..ee85d57c30 100644 --- a/js_of_ocaml-tyxml.opam +++ b/js_of_ocaml-tyxml.opam @@ -12,7 +12,7 @@ homepage: "https://ocsigen.org/js_of_ocaml/latest/manual/overview" doc: "https://ocsigen.org/js_of_ocaml/latest/manual/overview" bug-reports: "https://github.com/ocsigen/js_of_ocaml/issues" depends: [ - "dune" {>= "3.19"} + "dune" {>= "3.20"} "ocaml" {>= "4.13"} "js_of_ocaml" {= version} "js_of_ocaml-ppx" {= version} @@ -22,6 +22,8 @@ depends: [ "num" {with-test} "ppx_expect" {>= "v0.14.2" & with-test} "re" {>= "1.9.0" & with-test} + "stdlib_stable" {with-test & "os" = "never"} + "stdlib_upstream_compatible" {with-test & "os" = "never"} "odoc" {with-doc} ] dev-repo: "git+https://github.com/ocsigen/js_of_ocaml.git" diff --git a/js_of_ocaml.opam b/js_of_ocaml.opam index 6a04b51e3f..90911ad107 100644 --- a/js_of_ocaml.opam +++ b/js_of_ocaml.opam @@ -12,13 +12,15 @@ homepage: "https://ocsigen.org/js_of_ocaml/latest/manual/overview" doc: "https://ocsigen.org/js_of_ocaml/latest/manual/overview" bug-reports: "https://github.com/ocsigen/js_of_ocaml/issues" depends: [ - "dune" {>= "3.19"} + "dune" {>= "3.20"} "ocaml" {>= "4.13"} "js_of_ocaml-compiler" {= version} "num" {with-test} "ppx_expect" {>= "v0.14.2" & with-test} - "ppxlib" {>= "0.35"} + "ppxlib" {>= "0.35" | = "0.33.0+ox"} "re" {>= "1.9.0" & with-test} + "stdlib_stable" {with-test & "os" = "never"} + "stdlib_upstream_compatible" {with-test & "os" = "never"} "odoc" {with-doc} ] dev-repo: "git+https://github.com/ocsigen/js_of_ocaml.git" diff --git a/lib/js_of_ocaml/js.ml b/lib/js_of_ocaml/js.ml index afdbffa93a..8d04dd4247 100644 --- a/lib/js_of_ocaml/js.ml +++ b/lib/js_of_ocaml/js.ml @@ -815,7 +815,7 @@ let parseFloat (s : js_string t) : number_t = if isNaN s then failwith "parseFloat" else s let _ = - Printexc.register_printer (fun e -> + (Printexc.register_printer [@ocaml.alert "-unsafe_multidomain"]) (fun e -> if instanceof (Obj.magic e : < .. > t) error_constr then let e = Js_error.of_error (Obj.magic e : error t) in diff --git a/lib/lwt/graphics/graphics_js.ml b/lib/lwt/graphics/graphics_js.ml index 516099a576..c68d08bf2d 100644 --- a/lib/lwt/graphics/graphics_js.ml +++ b/lib/lwt/graphics/graphics_js.ml @@ -28,7 +28,10 @@ end type context = context_ Js.t -let _ = Callback.register_exception "Graphics.Graphic_failure" (Graphic_failure "") +let _ = + (Callback.register_exception + "Graphics.Graphic_failure" [@ocaml.alert "-unsafe_multidomain"]) + (Graphic_failure "") let ( >>= ) = Lwt.bind diff --git a/lib/runtime/jsoo_runtime.ml b/lib/runtime/jsoo_runtime.ml index 4dee5f64a9..06e096b429 100644 --- a/lib/runtime/jsoo_runtime.ml +++ b/lib/runtime/jsoo_runtime.ml @@ -175,7 +175,10 @@ end = struct exception Exn of t - let _ = Callback.register_exception "jsError" (Exn (Obj.magic [||])) + let _ = + (Callback.register_exception [@ocaml.alert "-unsafe_multidomain"]) + "jsError" + (Exn (Obj.magic [||])) external raise_ : t -> 'a = "caml_throw_js_exception" diff --git a/lib/tests/test_fun_call.ml b/lib/tests/test_fun_call.ml index e236435b38..bddeb09b9a 100644 --- a/lib/tests/test_fun_call.ml +++ b/lib/tests/test_fun_call.ml @@ -422,9 +422,7 @@ let%expect_test _ = let f = Js.wrap_callback (fun s -> print_endline s) in Js.export "f" f; let () = - Js.Unsafe.fun_call - (Js.Unsafe.pure_js_expr "jsoo_exports")##.f - [| Js.Unsafe.coerce (Js.string "hello") |] + Js.Unsafe.fun_call (Js.Unsafe.pure_js_expr "jsoo_exports")##.f [| Obj.magic "hello" |] in (); [%expect {| hello |}] diff --git a/lib/tests/test_poly_compare.ml b/lib/tests/test_poly_compare.ml index 734c97c90e..5f9c89cf04 100644 --- a/lib/tests/test_poly_compare.ml +++ b/lib/tests/test_poly_compare.ml @@ -105,7 +105,7 @@ let%expect_test "null/undefined comparison" = assert (s1 = s1); assert (compare s1 s1 = 0); assert (compare s1 s2 = 1); - assert (compare s2 s1 = 1) + assert (compare s2 s1 = -1) let%expect_test "poly compare" = let l = @@ -124,11 +124,11 @@ let%expect_test "poly compare" = List.iter (fun (i, _) -> Printf.printf "%d\n" i) l'; print_endline ""; [%expect {| + 7 1 3 2 0 - 7 6 5 4 @@ -138,6 +138,7 @@ let%expect_test "poly compare" = List.iter (fun (i, _) -> Printf.printf "%d\n" i) l'; print_endline ""; [%expect {| + 7 3 1 2 @@ -145,16 +146,15 @@ let%expect_test "poly compare" = 4 5 6 - 7 |}]; List.iter (fun (i, _) -> Printf.printf "%d\n" i) l''; print_endline ""; [%expect {| + 7 1 3 2 0 4 5 - 6 - 7 |}] + 6 |}] diff --git a/ppx/ppx_deriving_json/lib/dune b/ppx/ppx_deriving_json/lib/dune index 62c8f7e705..edbabc70eb 100644 --- a/ppx/ppx_deriving_json/lib/dune +++ b/ppx/ppx_deriving_json/lib/dune @@ -6,4 +6,4 @@ (ppx_runtime_libraries js_of_ocaml.deriving) (kind ppx_deriver) (preprocess - (pps ppxlib.metaquot))) + (pps ppx_optcomp_light ppxlib.metaquot))) diff --git a/ppx/ppx_deriving_json/lib/ppx_deriving_json.ml b/ppx/ppx_deriving_json/lib/ppx_deriving_json.ml index 22df5a8a01..d84e84b2fb 100644 --- a/ppx/ppx_deriving_json/lib/ppx_deriving_json.ml +++ b/ppx/ppx_deriving_json/lib/ppx_deriving_json.ml @@ -23,6 +23,8 @@ open Ppxlib.Ast open Ppxlib.Ast_helper open Ppxlib.Parsetree +[@@@ocaml.alert "-prefer_jane_syntax"] + let nolabel = Nolabel let unflatten l = @@ -132,30 +134,28 @@ let core_type_of_type_decl { ptype_name = name; ptype_params; _ } = let name = mkloc (Longident.Lident name.txt) name.loc in Typ.constr name (List.map ~f:fst ptype_params) +let wrap fn = + fun (param, _) accum -> + match param with + | ({ ptyp_desc = Ptyp_any; _ } [@if not oxcaml]) -> accum + | ({ ptyp_desc = Ptyp_any _; _ } [@if oxcaml]) -> accum + | ({ ptyp_desc = Ptyp_var name; _ } [@if not oxcaml]) -> + let name = mkloc name param.ptyp_loc in + fn name accum + | ({ ptyp_desc = Ptyp_var (name, _); _ } [@if oxcaml]) -> + let name = mkloc name param.ptyp_loc in + fn name accum + | _ -> assert false + let fold_right_type_params fn params accum = - List.fold_right - ~f:(fun (param, _) accum -> - match param with - | { ptyp_desc = Ptyp_any; _ } -> accum - | { ptyp_desc = Ptyp_var name; _ } -> - let name = mkloc name param.ptyp_loc in - fn name accum - | _ -> assert false) - params - ~init:accum + List.fold_right ~f:(wrap fn) params ~init:accum let fold_right_type_decl fn { ptype_params; _ } accum = fold_right_type_params fn ptype_params accum let fold_left_type_params fn accum params = List.fold_left - ~f:(fun accum (param, _) -> - match param with - | { ptyp_desc = Ptyp_any; _ } -> accum - | { ptyp_desc = Ptyp_var name; _ } -> - let name = mkloc name param.ptyp_loc in - fn accum name - | _ -> assert false) + ~f:(fun accum param -> wrap (fun accum name -> fn name accum) param accum) ~init:accum params @@ -338,10 +338,14 @@ and write_body_of_type y ~(arg : string) ~poly = | [%type: [%t? y] array] -> let e = write_of_type y ~poly in [%expr [%e rt "write_array"] [%e e] buf [%e arg]] - | { Parsetree.ptyp_desc = Ptyp_var v; _ } when poly -> + | ({ Parsetree.ptyp_desc = Ptyp_var v; _ } [@if not oxcaml]) when poly -> + [%expr [%e evar ("poly_" ^ v)] buf [%e arg]] + | ({ Parsetree.ptyp_desc = Ptyp_var (v, _); _ } [@if oxcaml]) when poly -> [%expr [%e evar ("poly_" ^ v)] buf [%e arg]] - | { Parsetree.ptyp_desc = Ptyp_tuple l; _ } -> + | ({ Parsetree.ptyp_desc = Ptyp_tuple l; _ } [@if not oxcaml]) -> write_body_of_tuple_type l ~arg ~poly ~tag:0 + | ({ Parsetree.ptyp_desc = Ptyp_tuple l; _ } [@if oxcaml]) -> + write_body_of_tuple_type (List.map ~f:snd l) ~arg ~poly ~tag:0 | { Parsetree.ptyp_desc = Ptyp_variant (l, _, _); _ } -> Exp.match_ arg (List.map ~f:(write_poly_case ~arg:arg' ~poly) l) | { Parsetree.ptyp_desc = Ptyp_constr (lid, l); _ } -> @@ -498,7 +502,10 @@ and read_body_of_type ?decl y = | [%type: [%t? y] ref] -> [%expr [%e rt "read_ref"] [%e read_of_type ?decl y] buf] | [%type: [%t? y] option] -> [%expr [%e rt "read_option"] [%e read_of_type ?decl y] buf] | [%type: [%t? y] array] -> [%expr [%e rt "read_array"] [%e read_of_type ?decl y] buf] - | { Parsetree.ptyp_desc = Ptyp_tuple l; _ } -> read_body_of_tuple_type l ?decl + | ({ Parsetree.ptyp_desc = Ptyp_tuple l; _ } [@if not oxcaml]) -> + read_body_of_tuple_type l ?decl + | ({ Parsetree.ptyp_desc = Ptyp_tuple l; _ } [@if oxcaml]) -> + read_body_of_tuple_type (List.map ~f:snd l) ?decl | { Parsetree.ptyp_desc = Ptyp_variant (l, _, _); ptyp_loc = loc; _ } -> let e = match decl with @@ -513,7 +520,9 @@ and read_body_of_type ?decl y = | Some _ | None -> read_of_poly_variant l y ~loc and tag = [%expr [%e lexer "read_vcase"] buf] in [%expr [%e e] buf [%e tag]] - | { Parsetree.ptyp_desc = Ptyp_var v; _ } when poly -> + | ({ Parsetree.ptyp_desc = Ptyp_var v; _ } [@if not oxcaml]) when poly -> + [%expr [%e evar ("poly_" ^ v)] buf] + | ({ Parsetree.ptyp_desc = Ptyp_var (v, _); _ } [@if oxcaml]) when poly -> [%expr [%e evar ("poly_" ^ v)] buf] | { Parsetree.ptyp_desc = Ptyp_constr (lid, l); _ } -> let e = suffix_lid lid ~suffix:"of_json" @@ -624,16 +633,25 @@ let json_decls_of_type decl y = in write_decl_of_type decl y, read_decl_of_type decl y, json_str decl, recognize, read_tag +let constructor_argument_type ca = ca.Parsetree.pca_type [@@if oxcaml] + +let constructor_argument_type typ = typ [@@if not oxcaml] + let write_case (i, i', l) { Parsetree.pcd_name; pcd_args; _ } = let i, i', lhs, rhs = match pcd_args with | Pcstr_tuple [] | Pcstr_record [] -> i + 1, i', None, [%expr [%e rt "Json_int.write"] buf [%e int i]] - | Pcstr_tuple ([ _ ] as args) -> + | Pcstr_tuple [ arg ] -> let v = fresh_var [] in - i, i' + 1, Some (pvar v), write_tuple_contents [ v ] args ~tag:i' ~poly:true + ( i + , i' + 1 + , Some (pvar v) + , write_tuple_contents [ v ] [ constructor_argument_type arg ] ~tag:i' ~poly:true + ) | Pcstr_tuple args -> let vars = fresh_vars (List.length args) in + let args = List.map ~f:constructor_argument_type args in ( i , i' + 1 , Some (var_ptuple vars) @@ -669,6 +687,7 @@ let read_case ?decl (i, i', l) { Parsetree.pcd_name; pcd_args; _ } = (Exp.construct (label_of_constructor pcd_name) None) :: l ) | Pcstr_tuple pcd_args -> + let pcd_args = List.map ~f:constructor_argument_type pcd_args in let expr = read_tuple_contents ?decl pcd_args ~f in let case = Exp.case [%pat? `NCst [%p pint i']] expr in i, i' + 1, case :: l diff --git a/ppx/ppx_js/lib_internal/ppx_js_internal.ml b/ppx/ppx_js/lib_internal/ppx_js_internal.ml index deadf746fc..0d95f343ac 100644 --- a/ppx/ppx_js/lib_internal/ppx_js_internal.ml +++ b/ppx/ppx_js/lib_internal/ppx_js_internal.ml @@ -23,6 +23,8 @@ open Ast_helper open Asttypes open Parsetree +[@@@ocaml.alert "-prefer_jane_syntax"] + let nolabel = Nolabel exception Syntax_error of Location.Error.t @@ -339,7 +341,7 @@ let method_call ~loc ~apply_loc obj (meth, meth_loc) args = in Exp.apply ~loc:apply_loc - { invoker with pexp_attributes = [ merlin_hide ] } + { invoker with pexp_attributes = invoker.pexp_attributes @ [ merlin_hide ] } ((app_arg obj :: args) @ [ app_arg (Exp.fun_ @@ -550,9 +552,10 @@ let filter_map f l = let rec create_meth_ty exp = match exp.pexp_desc with - | Pexp_fun (label, _, _, body) -> label :: create_meth_ty body + | ((Pexp_fun (label, _, _, body)) [@if not oxcaml]) -> label :: create_meth_ty body | Pexp_function _ -> [ nolabel ] - | Pexp_newtype (_, body) -> create_meth_ty body + | ((Pexp_newtype (_, body)) [@if not oxcaml]) -> create_meth_ty body + | ((Pexp_newtype (_, _, body)) [@if oxcaml]) -> create_meth_ty body | _ -> [] [@@if ast_version < 502] diff --git a/runtime/js/array.js b/runtime/js/array.js index 76e0773a0c..893aa5648c 100644 --- a/runtime/js/array.js +++ b/runtime/js/array.js @@ -18,6 +18,7 @@ ///////////// Array //Provides: caml_array_sub mutable +//Alias: caml_array_sub_local function caml_array_sub(a, i, len) { var a2 = new Array(len + 1); a2[0] = 0; @@ -42,6 +43,7 @@ function caml_uniform_array_sub(a, i, len) { } //Provides: caml_array_append mutable +//Alias: caml_array_append_local function caml_array_append(a1, a2) { var l1 = a1.length, l2 = a2.length; @@ -70,6 +72,7 @@ function caml_uniform_array_append(a1, a2) { } //Provides: caml_array_concat mutable +//Alias: caml_array_concat_local function caml_array_concat(l) { var a = [0]; while (l !== 0) { @@ -228,6 +231,7 @@ function caml_array_create_float(len) { } //Provides: caml_floatarray_create const (const) //Requires: caml_array_bound_error +//Alias: caml_floatarray_create_local function caml_floatarray_create(len) { if (len >>> 0 >= ((0x7fffffff / 8) | 0)) caml_array_bound_error(); var len = (len + 1) | 0; diff --git a/runtime/js/bigarray.js b/runtime/js/bigarray.js index 16a479a331..8677a022a6 100644 --- a/runtime/js/bigarray.js +++ b/runtime/js/bigarray.js @@ -42,8 +42,8 @@ function caml_ba_get_size(dims) { return size; } -//Provides: caml_unpackFloat16 -var caml_unpackFloat16 = (function () { +//Provides: caml_double_of_float16 pure +var caml_double_of_float16 = (function () { var pow = Math.pow; var EXP_MASK16 = 31; // 2 ** 5 - 1 @@ -72,8 +72,8 @@ var caml_unpackFloat16 = (function () { }; })(); -//Provides: caml_packFloat16 -var caml_packFloat16 = (function () { +//Provides: caml_float16_of_double pure +var caml_float16_of_double = (function () { const INVERSE_OF_EPSILON = 1 / Number.EPSILON; function roundTiesToEven(num) { @@ -252,7 +252,7 @@ var caml_ba_custom_name = "_bigarr02"; //Provides: Ml_Bigarray //Requires: caml_array_bound_error, caml_invalid_argument, caml_ba_custom_name //Requires: caml_int64_create_lo_hi, caml_int64_hi32, caml_int64_lo32 -//Requires: caml_packFloat16, caml_unpackFloat16 +//Requires: caml_float16_of_double, caml_double_of_float16 class Ml_Bigarray { constructor(kind, layout, dims, buffer) { this.kind = kind; @@ -299,7 +299,7 @@ class Ml_Bigarray { var i = this.data[ofs * 2 + 1]; return [254, r, i]; case 13: - return caml_unpackFloat16(this.data[ofs]); + return caml_double_of_float16(this.data[ofs]); default: return this.data[ofs]; } @@ -319,7 +319,7 @@ class Ml_Bigarray { this.data[ofs * 2 + 1] = v[2]; break; case 13: - this.data[ofs] = caml_packFloat16(v); + this.data[ofs] = caml_float16_of_double(v); break; default: this.data[ofs] = v; @@ -356,7 +356,7 @@ class Ml_Bigarray { } break; case 13: - this.data.fill(caml_packFloat16(v)); + this.data.fill(caml_float16_of_double(v)); break; default: this.data.fill(v); @@ -406,8 +406,8 @@ class Ml_Bigarray { break; case 13: for (var i = 0; i < this.data.length; i++) { - var aa = caml_unpackFloat16(this.data[i]); - var bb = caml_unpackFloat16(b.data[i]); + var aa = caml_double_of_float16(this.data[i]); + var bb = caml_double_of_float16(b.data[i]); if (aa < bb) return -1; if (aa > bb) return 1; } @@ -587,16 +587,19 @@ function caml_ba_uint8_get64(ba, i0) { } //Provides: caml_ba_get_1 +//Alias: caml_ba_float32_get_1 function caml_ba_get_1(ba, i0) { return ba.get(ba.offset(i0)); } //Provides: caml_ba_get_2 +//Alias: caml_ba_float32_get_2 function caml_ba_get_2(ba, i0, i1) { return ba.get(ba.offset([i0, i1])); } //Provides: caml_ba_get_3 +//Alias: caml_ba_float32_get_3 function caml_ba_get_3(ba, i0, i1, i2) { return ba.get(ba.offset([i0, i1, i2])); } @@ -641,18 +644,21 @@ function caml_ba_uint8_set64(ba, i0, v) { } //Provides: caml_ba_set_1 +//Alias: caml_ba_float32_set_1 function caml_ba_set_1(ba, i0, v) { ba.set(ba.offset(i0), v); return 0; } //Provides: caml_ba_set_2 +//Alias: caml_ba_float32_set_2 function caml_ba_set_2(ba, i0, i1, v) { ba.set(ba.offset([i0, i1]), v); return 0; } //Provides: caml_ba_set_3 +//Alias: caml_ba_float32_set_3 function caml_ba_set_3(ba, i0, i1, i2, v) { ba.set(ba.offset([i0, i1, i2]), v); return 0; @@ -763,7 +769,7 @@ function caml_ba_reshape(ba, vind) { //Provides: caml_ba_serialize //Requires: caml_int64_bits_of_float, caml_int64_to_bytes //Requires: caml_int32_bits_of_float -//Requires: caml_packFloat16 +//Requires: caml_float16_of_double function caml_ba_serialize(writer, ba, sz) { writer.write(32, ba.dims.length); writer.write(32, ba.kind | (ba.layout << 8)); @@ -853,7 +859,7 @@ function caml_ba_serialize(writer, ba, sz) { //Requires: caml_int64_of_bytes, caml_int64_float_of_bits //Requires: caml_int32_float_of_bits //Requires: caml_ba_create_buffer -//Requires: caml_unpackFloat16 +//Requires: caml_double_of_float16 function caml_ba_deserialize(reader, sz, name) { var num_dims = reader.read32s(); if (num_dims < 0 || num_dims > 16) @@ -979,7 +985,7 @@ function caml_ba_create_from(data1, data2, _jstyp, kind, layout, dims) { //Provides: caml_ba_hash const //Requires: caml_ba_get_size, caml_hash_mix_int, caml_hash_mix_float -//Requires: caml_unpackFloat16, caml_hash_mix_float16, caml_hash_mix_float32 +//Requires: caml_double_of_float16, caml_hash_mix_float16, caml_hash_mix_float32 function caml_ba_hash(ba) { var num_elts = caml_ba_get_size(ba.dims); var h = 0; diff --git a/runtime/js/compare.js b/runtime/js/compare.js index aba227499e..dfdd95b442 100644 --- a/runtime/js/compare.js +++ b/runtime/js/compare.js @@ -18,6 +18,7 @@ //Provides: caml_compare_val_tag //Requires: caml_is_ml_string, caml_is_ml_bytes function caml_compare_val_tag(a) { + if (a === null) return 1010; // null_tag if (typeof a === "number") return 1000; // int_tag (we use it for all numbers) else if (caml_is_ml_bytes(a)) @@ -93,6 +94,13 @@ function caml_compare_val(a, b, total) { // tags are different if (tag_a !== tag_b) { + if (tag_a === 1010) { + // Null is less than anything else + return -1; + } + if (tag_b === 1010) { + return 1; + } if (tag_a === 1000) { if (tag_b === 1255) { //immediate can compare against custom @@ -193,6 +201,8 @@ function caml_compare_val(a, b, total) { if (!Number.isNaN(b)) return -1; } break; + case 1010: // Null pointer + return 0; case 1001: // The rest // Here we can be in the following cases: // 1. JavaScript primitive types diff --git a/runtime/js/domain.js b/runtime/js/domain.js index 65823adb86..530ca084fa 100644 --- a/runtime/js/domain.js +++ b/runtime/js/domain.js @@ -57,6 +57,15 @@ function caml_atomic_cas_field(b, i, o, n) { return 0; } +//Provides: caml_atomic_compare_exchange +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_compare_exchange(ref, o, n) { + var old = ref[1]; + if (old === o) ref[1] = n; + return old; +} + //Provides: caml_atomic_fetch_add //Version: >= 5 function caml_atomic_fetch_add(ref, i) { @@ -73,6 +82,46 @@ function caml_atomic_fetch_add_field(b, i, n) { return old; } +//Provides: caml_atomic_add +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_add(ref, i) { + ref[1] += i; + return 0; +} + +//Provides: caml_atomic_sub +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_sub(ref, i) { + ref[1] -= i; + return 0; +} + +//Provides: caml_atomic_land +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_land(ref, i) { + ref[1] &= i; + return 0; +} + +//Provides: caml_atomic_lor +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_lor(ref, i) { + ref[1] |= i; + return 0; +} + +//Provides: caml_atomic_lxor +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_lxor(ref, i) { + ref[1] ^= i; + return 0; +} + //Provides: caml_atomic_exchange //Version: >= 5 function caml_atomic_exchange(ref, v) { @@ -89,6 +138,14 @@ function caml_atomic_exchange_field(b, i, v) { return r; } +//Provides: caml_atomic_set +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_set(ref, v) { + ref[1] = v; + return 0; +} + //Provides: caml_atomic_make_contended //Version: >= 5.2 function caml_atomic_make_contended(a) { @@ -165,3 +222,98 @@ function caml_ml_domain_id(_unit) { function caml_ml_domain_cpu_relax(_unit) { return 0; } + +//Provides: caml_atomic_load_field +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_load_field(ref, field) { + return ref[field + 1]; +} + +//Provides: caml_atomic_add_field +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_add_field(ref, field, i) { + ref[field + 1] += i; + return 0; +} + +//Provides: caml_atomic_fetch_add_field +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_fetch_add_field(ref, field, i) { + var old = ref[field + 1]; + ref[field + 1] += i; + return old; +} + +//Provides: caml_atomic_cas_field +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_cas_field(ref, field, o, n) { + if (ref[field + 1] === o) { + ref[field + 1] = n; + return 1; + } + return 0; +} + +//Provides: caml_atomic_compare_exchange_field +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_compare_exchange_field(ref, field, o, n) { + var old = ref[field + 1]; + if (old === o) { + ref[field + 1] = n; + } + return old; +} + +//Provides: caml_atomic_set_field +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_set_field(ref, field, v) { + ref[field + 1] = v; + return 0; +} + +//Provides: caml_atomic_exchange_field +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_exchange_field(ref, field, v) { + var old = ref[field + 1]; + ref[field + 1] = v; + return old; +} + +//Provides: caml_atomic_sub_field +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_sub_field(ref, field, i) { + ref[field + 1] -= i; + return 0; +} + +//Provides: caml_atomic_land_field +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_land_field(ref, field, i) { + ref[field + 1] &= i; + return 0; +} + +//Provides: caml_atomic_lor_field +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_lor_field(ref, field, i) { + ref[field + 1] |= i; + return 0; +} + +//Provides: caml_atomic_lxor_field +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atomic_lxor_field(ref, field, i) { + ref[field + 1] ^= i; + return 0; +} diff --git a/runtime/js/dune b/runtime/js/dune index 17b7db4117..73f28b7857 100644 --- a/runtime/js/dune +++ b/runtime/js/dune @@ -11,6 +11,7 @@ gc.js graphics.js ieee_754.js + float32.js int64.js io.js jslib.js diff --git a/runtime/js/float32.js b/runtime/js/float32.js new file mode 100644 index 0000000000..e213b40a02 --- /dev/null +++ b/runtime/js/float32.js @@ -0,0 +1,490 @@ +/* + 32-bit floats are represented as javascript numbers, i.e. 64-bit floats. + Each operation is performed in 64-bit precision and then rounded to the + nearest 32-bit float. This is not identical to using true 32-bit operations. + For example, if rounding an exact result to 64 bits places it halfway + between the two nearest 32-bit numbers, rounding it again to 32 bits + may not result in the closest 32-bit number to the exact result. + + Marshalled float32s therefore look like normal floats. This means that + javascript programs are not be able to read float32 data marshalled + by native programs and vice versa. +*/ + +//Provides: caml_float_of_float32 const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_float_of_float32(x) { + return x; +} + +//Provides: caml_float32_of_float const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_float32_of_float(x) { + return Math.fround(x); +} + +//Provides: caml_float32_of_int const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_float32_of_int(x) { + return Math.fround(x); +} + +//Provides: caml_int_of_float32 const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_int_of_float32(x) { + return x | 0; +} + +//Provides: caml_float32_of_bits_bytecode const +//Requires: caml_int32_float_of_bits +//Version: >= 5.2, < 5.3 +//OxCaml +const caml_float32_of_bits_bytecode = caml_int32_float_of_bits; + +//Provides: caml_float32_to_bits_bytecode const +//Requires: caml_int32_bits_of_float +//Version: >= 5.2, < 5.3 +//OxCaml +const caml_float32_to_bits_bytecode = caml_int32_bits_of_float; + +//Provides: caml_float32_of_int64_bytecode const +//Requires: caml_int64_to_float +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_float32_of_int64_bytecode(x) { + return Math.fround(caml_int64_to_float(x)); +} + +//Provides: caml_float32_to_int64_bytecode const +//Requires: caml_int64_of_float +//Version: >= 5.2, < 5.3 +//OxCaml +const caml_float32_to_int64_bytecode = caml_int64_of_float; + +//Provides: caml_float32_of_string (const) +//Requires: caml_parse_float +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_float32_of_string(x) { + return Math.fround(caml_parse_float(x, "float32_of_string")); +} + +//Provides: caml_format_float32 const +//Requires: caml_format_float +//Version: >= 5.2, < 5.3 +//OxCaml +const caml_format_float32 = caml_format_float; + +//Provides: caml_float32_compare const +//Requires: caml_float_compare +//Version: >= 5.2, < 5.3 +//OxCaml +const caml_float32_compare = caml_float_compare; + +//Provides: caml_add_float32 const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_add_float32(x, y) { + return Math.fround(x + y); +} + +//Provides: caml_sub_float32 const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_sub_float32(x, y) { + return Math.fround(x - y); +} + +//Provides: caml_mul_float32 const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_mul_float32(x, y) { + return Math.fround(x * y); +} + +//Provides: caml_div_float32 const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_div_float32(x, y) { + return Math.fround(x / y); +} + +//Provides: caml_fmod_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_fmod_float32_bytecode(x, y) { + return Math.fround(x % y); +} + +//Provides: caml_neg_float32 const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_neg_float32(x) { + return -x; // Result is exact +} + +//Provides: caml_abs_float32 const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_abs_float32(x) { + return Math.abs(x); // Result is exact +} + +//Provides: caml_modf_float32 const +//Requires: caml_modf_float +//Version: >= 5.2, < 5.3 +//OxCaml +const caml_modf_float32 = caml_modf_float; // Result is exact + +//Provides: caml_acos_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_acos_float32_bytecode(x) { + return Math.fround(Math.acos(x)); +} + +//Provides: caml_asin_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_asin_float32_bytecode(x) { + return Math.fround(Math.asin(x)); +} + +//Provides: caml_atan_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atan_float32_bytecode(x) { + return Math.fround(Math.atan(x)); +} + +//Provides: caml_atan2_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atan2_float32_bytecode(x, y) { + return Math.fround(Math.atan2(x, y)); +} + +//Provides: caml_ceil_float32_bytecode const +//Alias: caml_simd_float32_round_pos_inf_bytecode +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_ceil_float32_bytecode(x) { + return Math.fround(Math.ceil(x)); +} + +//Provides: caml_cos_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_cos_float32_bytecode(x) { + return Math.fround(Math.cos(x)); +} + +//Provides: caml_exp_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_exp_float32_bytecode(x) { + return Math.fround(Math.exp(x)); +} + +//Provides: caml_floor_float32_bytecode const +//Alias: caml_simd_float32_round_neg_inf_bytecode +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_floor_float32_bytecode(x) { + return Math.fround(Math.floor(x)); +} + +//Provides: caml_log_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_log_float32_bytecode(x) { + return Math.fround(Math.log(x)); +} + +//Provides: caml_power_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_power_float32_bytecode(x, y) { + return Math.fround(Math.pow(x, y)); +} + +//Provides: caml_sin_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_sin_float32_bytecode(x) { + return Math.fround(Math.sin(x)); +} + +//Provides: caml_sqrt_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_sqrt_float32_bytecode(x) { + return Math.fround(Math.sqrt(x)); +} + +//Provides: caml_tan_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_tan_float32_bytecode(x) { + return Math.fround(Math.tan(x)); +} + +//Provides: caml_nextafter_float32_bytecode const +//Requires: caml_int32_bits_of_float, caml_int32_float_of_bits +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_nextafter_float32_bytecode(x, y) { + if (Number.isNaN(x) || Number.isNaN(y)) return Number.NaN; + if (x === y) return y; + if (x === 0) { + if (y < 0) return -Math.pow(2, -149); + else return Math.pow(2, -149); + } + var bits = caml_int32_bits_of_float(x); + if (x < y === x > 0) bits++; + else bits--; + return caml_int32_float_of_bits(bits); +} + +//Provides: caml_trunc_float32_bytecode const +//Alias: caml_simd_float32_round_towards_zero_bytecode +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_trunc_float32_bytecode(x) { + return Math.fround(Math.trunc(x)); +} + +//Provides: caml_classify_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_classify_float32_bytecode(x) { + if (Number.isFinite(x)) { + if (Math.abs(x) >= 1.1754943508222875e-38) return 0; + if (x !== 0) return 1; + return 2; + } + return Number.isNaN(x) ? 4 : 3; +} + +//Provides: caml_ldexp_float32_bytecode const +//Requires: caml_ldexp_float +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_ldexp_float32_bytecode(x, y) { + return Math.fround(caml_ldexp_float(x, y)); +} + +//Provides: caml_frexp_float32 const +//Requires: caml_frexp_float +//Version: >= 5.2, < 5.3 +//OxCaml +const caml_frexp_float32 = caml_frexp_float; // Result is exact + +//Provides: caml_copysign_float32_bytecode const +//Requires: caml_copysign_float +//Version: >= 5.2, < 5.3 +//OxCaml +const caml_copysign_float32_bytecode = caml_copysign_float; // Result is exact + +//Provides: caml_signbit_float32_bytecode const +//Requires: caml_signbit_float +//Version: >= 5.2, < 5.3 +//OxCaml +const caml_signbit_float32_bytecode = caml_signbit_float; + +//Provides: caml_expm1_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_expm1_float32_bytecode(x) { + return Math.fround(Math.expm1(x)); +} + +//Provides: caml_exp2_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_exp2_float32_bytecode(x) { + return Math.fround(Math.pow(2, x)); +} + +//Provides: caml_log1p_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_log1p_float32_bytecode(x) { + return Math.fround(Math.log1p(x)); +} + +//Provides: caml_log2_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_log2_float32_bytecode(x) { + return Math.fround(Math.log2(x)); +} + +//Provides: caml_hypot_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_hypot_float32_bytecode(x, y) { + return Math.fround(Math.hypot(x, y)); +} + +//Provides: caml_log10_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_log10_float32_bytecode(x) { + return Math.fround(Math.log10(x)); +} + +//Provides: caml_cosh_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_cosh_float32_bytecode(x) { + return Math.fround(Math.cosh(x)); +} + +//Provides: caml_acosh_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_acosh_float32_bytecode(x) { + return Math.fround(Math.acosh(x)); +} + +//Provides: caml_sinh_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_sinh_float32_bytecode(x) { + return Math.fround(Math.sinh(x)); +} + +//Provides: caml_asinh_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_asinh_float32_bytecode(x) { + return Math.fround(Math.asinh(x)); +} + +//Provides: caml_tanh_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_tanh_float32_bytecode(x) { + return Math.fround(Math.tanh(x)); +} + +//Provides: caml_atanh_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_atanh_float32_bytecode(x) { + return Math.fround(Math.atanh(x)); +} + +//Provides: caml_round_float32_bytecode const +//Requires: caml_round_float +//Alias: caml_simd_float32_round_current_bytecode +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_round_float32_bytecode(x) { + return Math.fround(caml_round_float(x)); +} + +//Provides: caml_cbrt_float32_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_cbrt_float32_bytecode(x) { + return Math.fround(Math.cbrt(x)); +} + +//Provides: caml_erf_float32_bytecode const +//Requires: caml_erf_float +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_erf_float32_bytecode(x) { + return Math.fround(caml_erf_float(x)); +} + +//Provides: caml_erfc_float32_bytecode const +//Requires: caml_erfc_float +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_erfc_float32_bytecode(x) { + return Math.fround(caml_erfc_float(x)); +} + +//Provides: caml_fma_float32_bytecode const +//Requires: caml_fma_float +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_fma_float32_bytecode(x, y, z) { + return Math.fround(caml_fma_float(x, y, z)); +} + +//Provides: caml_simd_float32_min_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_simd_float32_min_bytecode(x, y) { + return Math.min(x, y); +} + +//Provides: caml_simd_float32_max_bytecode const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_simd_float32_max_bytecode(x, y) { + return Math.max(x, y); +} + +//Provides: caml_simd_cast_float32_int64_bytecode const +//Requires: caml_int64_of_float +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_simd_cast_float32_int64_bytecode(x) { + return caml_int64_of_float(Math.round(x)); +} + +//Provides: caml_ba_uint8_getf32 +//Requires: caml_ba_uint8_get32, caml_float32_of_bits_bytecode +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_ba_uint8_getf32(ba, i) { + return caml_float32_of_bits_bytecode(caml_ba_uint8_get32(ba, i)); +} + +//Provides: caml_ba_uint8_setf32 +//Requires: caml_ba_uint8_set32, caml_float32_to_bits_bytecode +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_ba_uint8_setf32(ba, i, v) { + return caml_ba_uint8_set32(ba, i, caml_float32_to_bits_bytecode(v)); +} + +//Provides: caml_string_getf32 +//Requires: caml_string_get32, caml_float32_of_bits_bytecode +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_string_getf32(ba, i) { + return caml_float32_of_bits_bytecode(caml_string_get32(ba, i)); +} + +//Provides: caml_bytes_getf32 +//Requires: caml_bytes_get32, caml_float32_of_bits_bytecode +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_bytes_getf32(ba, i) { + return caml_float32_of_bits_bytecode(caml_bytes_get32(ba, i)); +} + +//Provides: caml_bytes_setf32 +//Requires: caml_bytes_set32, caml_float32_to_bits_bytecode +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_bytes_setf32(ba, i, v) { + return caml_bytes_set32(ba, i, caml_float32_to_bits_bytecode(v)); +} + +//Provides: caml_is_boot_compiler +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_is_boot_compiler(_unit) { + return 0; +} diff --git a/runtime/js/gc.js b/runtime/js/gc.js index 183473f4a7..161343514f 100644 --- a/runtime/js/gc.js +++ b/runtime/js/gc.js @@ -86,14 +86,23 @@ function caml_memprof_discard(_t) { return 0; } +//Provides: caml_memprof_participate +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_memprof_participate(_config) { + return 0; +} + //Provides: caml_eventlog_resume -//Version: < 5.0 +//Version: <= 5.2 +//(actually < 5.0, but OxCaml still references it) function caml_eventlog_resume(_unit) { return 0; } //Provides: caml_eventlog_pause -//Version: < 5.0 +//Version: <= 5.2 +//(actually < 5.0, but OxCaml still references it) function caml_eventlog_pause(_unit) { return 0; } @@ -130,3 +139,26 @@ function caml_get_major_bucket(_n) { function caml_get_major_credit(_n) { return 0; } + +//Provides: caml_gc_tweak_get +//Requires: caml_invalid_argument +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_gc_tweak_get(_name) { + caml_invalid_argument("Gc.Tweak: parameter not found"); +} + +//Provides: caml_gc_tweak_set +//Requires: caml_invalid_argument +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_gc_tweak_set(_name, _value) { + caml_invalid_argument("Gc.Tweak: parameter not found"); +} + +//Provides: caml_gc_tweak_list_active +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_gc_tweak_list_active(_unit) { + return 0; +} diff --git a/runtime/js/hash.js b/runtime/js/hash.js index ae19898dae..09a85dd54e 100644 --- a/runtime/js/hash.js +++ b/runtime/js/hash.js @@ -221,6 +221,12 @@ function caml_hash(count, limit, seed, obj) { return h & 0x3fffffff; } +//Provides: caml_hash_exn +//Requires: caml_hash +//Version: >= 5.2, < 5.3 +//OxCaml +var caml_hash_exn = caml_hash; + //Provides: caml_string_hash //Requires: caml_hash_mix_final, caml_hash_mix_string //Version: >= 5.0 diff --git a/runtime/js/ieee_754.js b/runtime/js/ieee_754.js index c4e2137f4e..cb0df7b9b1 100644 --- a/runtime/js/ieee_754.js +++ b/runtime/js/ieee_754.js @@ -508,9 +508,9 @@ function caml_format_float(fmt, x) { return caml_finish_formatting(f, s); } -//Provides: caml_float_of_string (const) +//Provides: caml_parse_float //Requires: caml_failwith, caml_jsbytes_of_string -function caml_float_of_string(s) { +function caml_parse_float(s, err_msg) { var res; var r_float = /^ *[-+]?(?:\d*\.?\d+|\d+\.?\d*)(?:[eE][-+]?\d+)?$/; s = caml_jsbytes_of_string(s); @@ -532,5 +532,11 @@ function caml_float_of_string(s) { } if (/^\+?inf(inity)?$/i.test(s)) return Number.POSITIVE_INFINITY; if (/^-inf(inity)?$/i.test(s)) return Number.NEGATIVE_INFINITY; - caml_failwith("float_of_string"); + caml_failwith(err_msg); +} + +//Provides: caml_float_of_string (const) +//Requires: caml_parse_float +function caml_float_of_string(s) { + return caml_parse_float(s, "float_of_string"); } diff --git a/runtime/js/int64.js b/runtime/js/int64.js index 710198cddc..2f1639b06d 100644 --- a/runtime/js/int64.js +++ b/runtime/js/int64.js @@ -352,6 +352,31 @@ function caml_int64_to_int32(x) { return x.toInt(); } +//Provides: caml_checked_int64_to_int +//Requires: caml_int64_of_int32, caml_array_bound_error +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_checked_int64_to_int(x) { + var y = x.toInt(); + if (x.compare(caml_int64_of_int32(y)) !== 0) caml_array_bound_error(); + return y; +} + +//Provides: caml_array_unsafe_get_indexed_by_int64 mutable (mutable, const) +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_array_unsafe_get_indexed_by_int64(array, index) { + return array[index.toInt() + 1]; +} + +//Provides: caml_array_unsafe_set_indexed_by_int64 (mutable, const, mutable) +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_array_unsafe_set_indexed_by_int64(array, index, newval) { + array[index.toInt() + 1] = newval; + return 0; +} + //Provides: caml_int64_to_float const function caml_int64_to_float(x) { return x.toFloat(); diff --git a/runtime/js/ints.js b/runtime/js/ints.js index 961058f2f3..fd7924894d 100644 --- a/runtime/js/ints.js +++ b/runtime/js/ints.js @@ -132,6 +132,63 @@ function caml_int_of_string(s) { return res | 0; } +//Provides: caml_parse_small_int +//Requires: caml_ml_string_length, caml_string_unsafe_get +//Requires: caml_parse_sign_and_base, caml_parse_digit, caml_failwith +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_parse_small_int(err_msg, width, s) { + var r = caml_parse_sign_and_base(s); + var i = r[0], + sign = r[1], + base = r[2], + signedness = r[3]; + var len = caml_ml_string_length(s); + var threshold = (1 << width) - 1; + var c = i < len ? caml_string_unsafe_get(s, i) : 0; + var d = caml_parse_digit(c); + if (d < 0 || d >= base) caml_failwith(err_msg); + var res = d; + for (i++; i < len; i++) { + c = caml_string_unsafe_get(s, i); + if (c === 95) continue; + d = caml_parse_digit(c); + if (d < 0 || d >= base) break; + res = base * res + d; + if (res > threshold) caml_failwith(err_msg); + } + if (i !== len) caml_failwith(err_msg); + // For base different from 10, we expect an unsigned representation, + // hence any value of 'res' (less than 'threshold') is acceptable. + // But we have to convert the result back to a signed integer. + if (signedness) { + threshold = 1 << (width - 1); + if (sign >= 0) { + if (res >= threshold) caml_failwith(err_msg); + } else { + if (res > threshold) caml_failwith(err_msg); + } + } + res = sign * res; + return (res << (32 - width)) >> (32 - width); +} + +//Provides: caml_int8_of_string (const) +//Requires: caml_parse_small_int +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_int8_of_string(s) { + return caml_parse_small_int("Int8.of_string", 8, s); +} + +//Provides: caml_int16_of_string (const) +//Requires: caml_parse_small_int +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_int16_of_string(s) { + return caml_parse_small_int("Int16.of_string", 16, s); +} + //Provides: caml_mul const //Alias: caml_int32_mul //Alias: caml_nativeint_mul diff --git a/runtime/js/marshal.js b/runtime/js/marshal.js index c1c68af669..5a3847cbf5 100644 --- a/runtime/js/marshal.js +++ b/runtime/js/marshal.js @@ -44,6 +44,7 @@ var caml_marshal_constants = { CODE_CUSTOM: 0x12, CODE_CUSTOM_LEN: 0x18, CODE_CUSTOM_FIXED: 0x19, + CODE_NULL: 0x1f, }; //Provides: UInt8ArrayReader @@ -495,6 +496,8 @@ function caml_input_value_from_reader(reader) { } if (intern_obj_table) intern_obj_table[obj_counter++] = v; return v; + case 0x1f: //cst.CODE_NULL: + return null; default: caml_failwith("input_value: ill-formed message"); } @@ -687,7 +690,9 @@ var caml_output_val = (function () { } function extern_rec(v) { - if (v.caml_custom) { + if (v === null) { + writer.write(8, 0x1f /*cst.CODE_NULL*/); + } else if (v.caml_custom) { if (memo(v)) return; var name = v.caml_custom; var ops = caml_custom_ops[name]; diff --git a/runtime/js/mlBytes.js b/runtime/js/mlBytes.js index 6e724f0ff9..46800322bc 100644 --- a/runtime/js/mlBytes.js +++ b/runtime/js/mlBytes.js @@ -390,6 +390,7 @@ function caml_create_string(_len) { //Provides: caml_create_bytes const //Requires: MlBytes,caml_invalid_argument +//Alias: caml_create_local_bytes function caml_create_bytes(len) { if (len < 0) caml_invalid_argument("Bytes.create"); return new MlBytes(len ? 2 : 9, "", len); diff --git a/runtime/js/obj.js b/runtime/js/obj.js index c8c96f928c..51955f4ae7 100644 --- a/runtime/js/obj.js +++ b/runtime/js/obj.js @@ -64,10 +64,33 @@ function caml_update_dummy_lazy(dummy, newval) { return 0; } +//Provides: caml_obj_is_stack +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_obj_is_stack(_x) { + return 0; +} + +//Provides: caml_succ_scannable_prefix_len +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_succ_scannable_prefix_len(_x) { + return 0; +} + +//Provides: caml_obj_uniquely_reachable_words +//Requires: caml_failwith +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_obj_uniquely_reachable_words(_x) { + caml_failwith("Obj.uniquely_reachable_words is not available in javascript."); +} + //Provides: caml_obj_tag //Requires: caml_is_ml_bytes, caml_is_ml_string function caml_obj_tag(x) { - if (Array.isArray(x) && x[0] === x[0] >>> 0) return x[0]; + if (x === null) return 1010; + else if (Array.isArray(x) && x[0] === x[0] >>> 0) return x[0]; else if (caml_is_ml_bytes(x)) return 252; else if (caml_is_ml_string(x)) return 252; else if (x instanceof Function || typeof x === "function") return 247; @@ -306,3 +329,13 @@ function caml_ml_gc_ramp_up(f) { function caml_ml_gc_ramp_down(_suspended_collection_work) { return 0; } + +//Provides: caml_int_as_pointer +//Requires: caml_failwith +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_int_as_pointer(i) { + // Special-case null pointers for [or_null]. + if (i === 0) return null; + caml_failwith("%int_as_pointer is not supported in javascript."); +} diff --git a/runtime/js/stdlib.js b/runtime/js/stdlib.js index 5bfb024119..2fae5966db 100644 --- a/runtime/js/stdlib.js +++ b/runtime/js/stdlib.js @@ -300,3 +300,11 @@ function caml_is_printable(c) { function caml_maybe_print_stats(_unit) { return 0; } + +//Provides: caml_with_async_exns +//Requires: caml_callback +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_with_async_exns(body_callback) { + return caml_callback(body_callback, [0]); +} diff --git a/runtime/js/sys.js b/runtime/js/sys.js index 98a9ed5001..86e0f616c6 100644 --- a/runtime/js/sys.js +++ b/runtime/js/sys.js @@ -311,6 +311,13 @@ function caml_sys_isatty(_chan) { return 0; } +//Provides: caml_sys_const_runtime5 const +//Version: >= 5.2, < 5.3 +//OxCaml +function caml_sys_const_runtime5(_unit) { + return 1; +} + //Provides: caml_runtime_variant //Requires: caml_string_of_jsbytes function caml_runtime_variant(_unit) { diff --git a/runtime/js/toplevel.js b/runtime/js/toplevel.js index 3b65660823..09d68857fa 100644 --- a/runtime/js/toplevel.js +++ b/runtime/js/toplevel.js @@ -99,39 +99,32 @@ function jsoo_toplevel_init_reloc(f) { jsoo_toplevel_reloc = f; } -//Provides: caml_reify_bytecode -//Requires: caml_callback -//Requires: caml_string_of_uint8_array, caml_ba_to_typed_array -//Requires: jsoo_toplevel_compile, caml_failwith -//Version: >= 5.2 -function caml_reify_bytecode(code, debug, _digest) { - if (!jsoo_toplevel_compile) { - caml_failwith("Toplevel not initialized (jsoo_toplevel_compile)"); - } - code = caml_string_of_uint8_array(caml_ba_to_typed_array(code)); - return [0, 0, caml_callback(jsoo_toplevel_compile, [code, debug])]; -} - //Provides: caml_reify_bytecode //Requires: caml_callback //Requires: caml_string_of_uint8_array, caml_uint8_array_of_bytes +//Requires: caml_ba_to_typed_array //Requires: jsoo_toplevel_compile, caml_failwith -//Version: < 5.2 function caml_reify_bytecode(code, debug, _digest) { if (!jsoo_toplevel_compile) { caml_failwith("Toplevel not initialized (jsoo_toplevel_compile)"); } - var len = 0; - var all = []; - for (var i = 1; i < code.length; i++) { - var a = caml_uint8_array_of_bytes(code[i]); - all.push(a); - len += a.length; - } - code = new Uint8Array(len); - for (var i = 0, len = 0; i < all.length; i++) { - code.set(all[i], len); - len += all[i].length; + if (code.data) { + //Version: >= 5.2 + code = caml_ba_to_typed_array(code); + } else { + // Oxcaml or version < 5.2 + var len = 0; + var all = []; + for (var i = 1; i < code.length; i++) { + var a = caml_uint8_array_of_bytes(code[i]); + all.push(a); + len += a.length; + } + code = new Uint8Array(len); + for (var i = 0, len = 0; i < all.length; i++) { + code.set(all[i], len); + len += all[i].length; + } } code = caml_string_of_uint8_array(code); return [0, 0, caml_callback(jsoo_toplevel_compile, [code, debug])]; diff --git a/runtime/wasm/array.wat b/runtime/wasm/array.wat index 235a9aa52b..7d6be3c173 100644 --- a/runtime/wasm/array.wat +++ b/runtime/wasm/array.wat @@ -62,7 +62,7 @@ (func $caml_floatarray_create (export "caml_make_float_vect") (export "caml_floatarray_create") - (export "caml_array_create_float") + (export "caml_array_create_float") (export "caml_floatarray_create_local") (param $n (ref eq)) (result (ref eq)) (local $sz i32) (local.set $sz (i31.get_s (ref.cast (ref i31) (local.get $n)))) @@ -110,7 +110,7 @@ (struct.get $float 0 (ref.cast (ref $float) (local.get $v)))) (ref.i31 (i32.const 0))) - (func (export "caml_array_sub") + (func (export "caml_array_sub") (export "caml_array_sub_local") (param $a (ref eq)) (param $i (ref eq)) (param $vlen (ref eq)) (result (ref eq)) (local $a1 (ref $block)) (local $a2 (ref $block)) (local $len i32) @@ -163,7 +163,7 @@ (local.get $len)) (local.get $a')) - (func (export "caml_array_append") + (func (export "caml_array_append") (export "caml_array_append_local") (param $va1 (ref eq)) (param $va2 (ref eq)) (result (ref eq)) (local $a1 (ref $block)) (local $a2 (ref $block)) (local $a (ref $block)) (local $fa1 (ref $float_array)) (local $fa2 (ref $float_array)) @@ -235,7 +235,8 @@ (return (local.get $fa)))) (return_call $caml_floatarray_dup (local.get $fa1))) - (func (export "caml_array_concat") (param (ref eq)) (result (ref eq)) + (func (export "caml_array_concat") (export "caml_array_concat_local") + (param (ref eq)) (result (ref eq)) (local $i i32) (local $len i32) (local $l (ref eq)) (local $v (ref eq)) (local $isfloat i32) diff --git a/runtime/wasm/bigarray.wat b/runtime/wasm/bigarray.wat index 58d1b3984f..fb01fab784 100644 --- a/runtime/wasm/bigarray.wat +++ b/runtime/wasm/bigarray.wat @@ -184,7 +184,7 @@ (field $ba_kind i8) ;; kind (field $ba_layout i8)))) ;; layout - (func $double_to_float16 (export "caml_double_to_float16") + (func $double_to_float16 (export "caml_float16_of_double") (param $f f64) (result i32) (local $x i32) (local $sign i32) (local $o i32) (local.set $x (i32.reinterpret_f32 (f32.demote_f64 (local.get $f)))) @@ -1244,6 +1244,213 @@ (func (export "caml_ba_dim_3") (param (ref eq)) (result (ref eq)) (return_call $caml_ba_dim (local.get 0) (ref.i31 (i32.const 2)))) + (func $caml_ba_float32_get_at_offset + (param $ba (ref $bigarray)) (param $i i32) (result f32) + (local $view (ref extern)) + (local.set $view (struct.get $bigarray $ba_view (local.get $ba))) + (return + (call $dv_get_f32 + (local.get $view) (i32.shl (local.get $i) (i32.const 2)) + (global.get $littleEndian)))) + + (func $caml_ba_float32_set_at_offset + (param $ba (ref $bigarray)) (param $i i32) (param $v f32) + (local $view (ref extern)) + (local $b (ref $float_array)) (local $l i64) + (local.set $view (struct.get $bigarray $ba_view (local.get $ba))) + (call $dv_set_f32 + (local.get $view) (i32.shl (local.get $i) (i32.const 2)) (local.get $v) + (global.get $littleEndian))) + + (func (export "caml_ba_float32_get_1") + (param (ref eq)) (param $i i32) (result f32) + (local $ba (ref $bigarray)) + (local.set $ba (ref.cast (ref $bigarray) (local.get 0))) + (if (struct.get $bigarray $ba_layout (local.get $ba)) + (then (local.set $i (i32.sub (local.get $i) (i32.const 1))))) + (if (i32.ge_u (local.get $i) + (array.get $int_array (struct.get $bigarray $ba_dim (local.get $ba)) + (i32.const 0))) + (then (call $caml_bound_error))) + (return_call $caml_ba_float32_get_at_offset + (local.get $ba) (local.get $i))) + + (func (export "caml_ba_float32_set_1") + (param (ref eq)) (param $i i32) (param $v f32) (result (ref eq)) + (local $ba (ref $bigarray)) + (local.set $ba (ref.cast (ref $bigarray) (local.get 0))) + (if (struct.get $bigarray $ba_layout (local.get $ba)) + (then (local.set $i (i32.sub (local.get $i) (i32.const 1))))) + (if (i32.ge_u (local.get $i) + (array.get $int_array (struct.get $bigarray $ba_dim (local.get $ba)) + (i32.const 0))) + (then (call $caml_bound_error))) + (call $caml_ba_float32_set_at_offset + (local.get $ba) (local.get $i) (local.get $v)) + (ref.i31 (i32.const 0))) + + (func (export "caml_ba_float32_get_2") + (param $vba (ref eq)) (param $i i32) (param $j i32) (result f32) + (local $ba (ref $bigarray)) + (local $offset i32) + (local $dim (ref $int_array)) + (local.set $ba (ref.cast (ref $bigarray) (local.get $vba))) + (local.set $dim (struct.get $bigarray $ba_dim (local.get $ba))) + (if (struct.get $bigarray $ba_layout (local.get $ba)) + (then + (local.set $i (i32.sub (local.get $i) (i32.const 1))) + (local.set $j (i32.sub (local.get $j) (i32.const 1))) + (local.set $offset + (i32.add + (i32.mul (local.get $j) + (array.get $int_array (local.get $dim) (i32.const 0))) + (local.get $i)))) + (else + (local.set $offset + (i32.add + (i32.mul (local.get $i) + (array.get $int_array (local.get $dim) (i32.const 1))) + (local.get $j))))) + (if (i32.or + (i32.ge_u (local.get $i) + (array.get $int_array (local.get $dim) (i32.const 0))) + (i32.ge_u (local.get $j) + (array.get $int_array (local.get $dim) (i32.const 1)))) + (then + (call $caml_bound_error))) + (return_call $caml_ba_float32_get_at_offset + (local.get $ba) (local.get $offset))) + + (func (export "caml_ba_float32_set_2") + (param $vba (ref eq)) (param $i i32) (param $j i32) (param $v f32) + (result (ref eq)) + (local $ba (ref $bigarray)) + (local $offset i32) + (local $dim (ref $int_array)) + (local.set $ba (ref.cast (ref $bigarray) (local.get $vba))) + (local.set $dim (struct.get $bigarray $ba_dim (local.get $ba))) + (if (struct.get $bigarray $ba_layout (local.get $ba)) + (then + (local.set $i (i32.sub (local.get $i) (i32.const 1))) + (local.set $j (i32.sub (local.get $j) (i32.const 1))) + (local.set $offset + (i32.add + (i32.mul (local.get $j) + (array.get $int_array (local.get $dim) (i32.const 0))) + (local.get $i)))) + (else + (local.set $offset + (i32.add + (i32.mul (local.get $i) + (array.get $int_array (local.get $dim) (i32.const 1))) + (local.get $j))))) + (if (i32.or + (i32.ge_u (local.get $i) + (array.get $int_array (local.get $dim) (i32.const 0))) + (i32.ge_u (local.get $j) + (array.get $int_array (local.get $dim) (i32.const 1)))) + (then + (call $caml_bound_error))) + (call $caml_ba_float32_set_at_offset + (local.get $ba) (local.get $offset) (local.get $v)) + (ref.i31 (i32.const 0))) + + (func (export "caml_ba_float32_get_3") + (param $vba (ref eq)) (param $i i32) (param $j i32) (param $k i32) + (result f32) + (local $ba (ref $bigarray)) + (local $offset i32) + (local $dim (ref $int_array)) + (local.set $ba (ref.cast (ref $bigarray) (local.get $vba))) + (local.set $dim (struct.get $bigarray $ba_dim (local.get $ba))) + (if (struct.get $bigarray $ba_layout (local.get $ba)) + (then + (local.set $i (i32.sub (local.get $i) (i32.const 1))) + (local.set $j (i32.sub (local.get $j) (i32.const 1))) + (local.set $k (i32.sub (local.get $k) (i32.const 1))) + (local.set $offset + (i32.add + (i32.mul + (i32.add + (i32.mul + (local.get $k) + (array.get $int_array (local.get $dim) (i32.const 1))) + (local.get $j)) + (array.get $int_array (local.get $dim) (i32.const 0))) + (local.get $i)))) + (else + (local.set $offset + (i32.add + (i32.mul + (i32.add + (i32.mul + (local.get $i) + (array.get $int_array (local.get $dim) (i32.const 1))) + (local.get $j)) + (array.get $int_array (local.get $dim) (i32.const 2))) + (local.get $k))))) + (if (i32.or + (i32.ge_u (local.get $i) + (array.get $int_array (local.get $dim) (i32.const 0))) + (i32.or + (i32.ge_u (local.get $j) + (array.get $int_array (local.get $dim) (i32.const 1))) + (i32.ge_u (local.get $k) + (array.get $int_array (local.get $dim) (i32.const 2))))) + (then + (call $caml_bound_error))) + (return_call $caml_ba_float32_get_at_offset + (local.get $ba) (local.get $offset))) + + (func (export "caml_ba_float32_set_3") + (param $vba (ref eq)) (param $i i32) (param $j i32) (param $k i32) + (param $v f32) + (result (ref eq)) + (local $ba (ref $bigarray)) + (local $offset i32) + (local $dim (ref $int_array)) + (local.set $ba (ref.cast (ref $bigarray) (local.get $vba))) + (local.set $dim (struct.get $bigarray $ba_dim (local.get $ba))) + (if (struct.get $bigarray $ba_layout (local.get $ba)) + (then + (local.set $i (i32.sub (local.get $i) (i32.const 1))) + (local.set $j (i32.sub (local.get $j) (i32.const 1))) + (local.set $k (i32.sub (local.get $k) (i32.const 1))) + (local.set $offset + (i32.add + (i32.mul + (i32.add + (i32.mul + (local.get $k) + (array.get $int_array (local.get $dim) (i32.const 1))) + (local.get $j)) + (array.get $int_array (local.get $dim) (i32.const 0))) + (local.get $i)))) + (else + (local.set $offset + (i32.add + (i32.mul + (i32.add + (i32.mul + (local.get $i) + (array.get $int_array (local.get $dim) (i32.const 1))) + (local.get $j)) + (array.get $int_array (local.get $dim) (i32.const 2))) + (local.get $k))))) + (if (i32.or + (i32.ge_u (local.get $i) + (array.get $int_array (local.get $dim) (i32.const 0))) + (i32.or + (i32.ge_u (local.get $j) + (array.get $int_array (local.get $dim) (i32.const 1))) + (i32.ge_u (local.get $k) + (array.get $int_array (local.get $dim) (i32.const 2))))) + (then + (call $caml_bound_error))) + (call $caml_ba_float32_set_at_offset + (local.get $ba) (local.get $offset) (local.get $v)) + (ref.i31 (i32.const 0))) + (func $caml_ba_offset (param $b (ref $bigarray)) (param $index (ref $int_array)) (result i32) (local $dim (ref $int_array)) diff --git a/runtime/wasm/compare.wat b/runtime/wasm/compare.wat index a8b92f7e5c..ff4784b9d3 100644 --- a/runtime/wasm/compare.wat +++ b/runtime/wasm/compare.wat @@ -25,6 +25,7 @@ (func $caml_obj_tag (param (ref eq)) (result (ref eq)))) (import "obj" "caml_is_closure" (func $caml_is_closure (param (ref eq)) (result i32))) + (import "obj" "null" (global $null (ref eq))) (import "fail" "caml_invalid_argument" (func $caml_invalid_argument (param (ref eq)))) (import "effect" "caml_is_continuation" @@ -238,6 +239,13 @@ (if (local.get $total) (then (br_if $next_item (ref.eq (local.get $v1) (local.get $v2))))) + (if (ref.eq (local.get $v1) (global.get $null)) + (then + (if (ref.eq (local.get $v2) (global.get $null)) + (then (return (i32.const 0))) + (else (return (i32.const -1)))))) + (if (ref.eq (local.get $v2) (global.get $null)) + (then (return (i32.const 1)))) (drop (block $v1_is_not_int (result (ref eq)) (local.set $i1 (br_on_cast_fail $v1_is_not_int (ref eq) (ref i31) diff --git a/runtime/wasm/custom.wat b/runtime/wasm/custom.wat index 526d36ca62..337d0db4a6 100644 --- a/runtime/wasm/custom.wat +++ b/runtime/wasm/custom.wat @@ -16,6 +16,7 @@ ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. (module + (import "float32" "float32_ops" (global $float32_ops (ref $custom_operations))) (import "int32" "int32_ops" (global $int32_ops (ref $custom_operations))) (import "int32" "nativeint_ops" (global $nativeint_ops (ref $custom_operations))) @@ -137,6 +138,7 @@ (call $caml_register_custom_operations (global.get $nativeint_ops)) (call $caml_register_custom_operations (global.get $int64_ops)) (call $caml_register_custom_operations (global.get $bigarray_ops)) + (call $caml_register_custom_operations (global.get $float32_ops)) (global.set $initialized (i32.const 1))) (func (export "caml_custom_identifier") (param $v (ref eq)) (result (ref eq)) diff --git a/runtime/wasm/domain.wat b/runtime/wasm/domain.wat index 712486bbdd..b34a832601 100644 --- a/runtime/wasm/domain.wat +++ b/runtime/wasm/domain.wat @@ -55,6 +55,21 @@ (else (ref.i31 (i32.const 0))))) + (func (export "caml_atomic_compare_exchange") + (param $ref (ref eq)) (param $o (ref eq)) (param $n (ref eq)) + (result (ref eq)) + (local $b (ref $block)) + (local $old (ref eq)) + (local.set $b (ref.cast (ref $block) (local.get $ref))) + (local.set $old (array.get $block (local.get $b) (i32.const 1))) + (if (result (ref eq)) + (ref.eq (local.get $old) (local.get $o)) + (then + (array.set $block (local.get $b) (i32.const 1) (local.get $n)) + (local.get $old)) + (else + (local.get $old)))) + (func (export "caml_atomic_load") (param (ref eq)) (result (ref eq)) (array.get $block (ref.cast (ref $block) (local.get 0)) (i32.const 1))) @@ -89,6 +104,61 @@ (i31.get_s (ref.cast (ref i31) (local.get $n)))))) (local.get $old)) + (func (export "caml_atomic_add") + (param $ref (ref eq)) (param $i (ref eq)) (result (ref eq)) + (local $b (ref $block)) + (local $old (ref eq)) + (local.set $b (ref.cast (ref $block) (local.get $ref))) + (local.set $old (array.get $block (local.get $b) (i32.const 1))) + (array.set $block (local.get $b) (i32.const 1) + (ref.i31 (i32.add (i31.get_s (ref.cast (ref i31) (local.get $old))) + (i31.get_s (ref.cast (ref i31) (local.get $i)))))) + (ref.i31 (i32.const 0))) + + (func (export "caml_atomic_sub") + (param $ref (ref eq)) (param $i (ref eq)) (result (ref eq)) + (local $b (ref $block)) + (local $old (ref eq)) + (local.set $b (ref.cast (ref $block) (local.get $ref))) + (local.set $old (array.get $block (local.get $b) (i32.const 1))) + (array.set $block (local.get $b) (i32.const 1) + (ref.i31 (i32.sub (i31.get_s (ref.cast (ref i31) (local.get $old))) + (i31.get_s (ref.cast (ref i31) (local.get $i)))))) + (ref.i31 (i32.const 0))) + + (func (export "caml_atomic_land") + (param $ref (ref eq)) (param $i (ref eq)) (result (ref eq)) + (local $b (ref $block)) + (local $old (ref eq)) + (local.set $b (ref.cast (ref $block) (local.get $ref))) + (local.set $old (array.get $block (local.get $b) (i32.const 1))) + (array.set $block (local.get $b) (i32.const 1) + (ref.i31 (i32.and (i31.get_s (ref.cast (ref i31) (local.get $old))) + (i31.get_s (ref.cast (ref i31) (local.get $i)))))) + (ref.i31 (i32.const 0))) + + (func (export "caml_atomic_lor") + (param $ref (ref eq)) (param $i (ref eq)) (result (ref eq)) + (local $b (ref $block)) + (local $old (ref eq)) + (local.set $b (ref.cast (ref $block) (local.get $ref))) + (local.set $old (array.get $block (local.get $b) (i32.const 1))) + (array.set $block (local.get $b) (i32.const 1) + (ref.i31 (i32.or (i31.get_s (ref.cast (ref i31) (local.get $old))) + (i31.get_s (ref.cast (ref i31) (local.get $i)))))) + (ref.i31 (i32.const 0))) + + (func (export "caml_atomic_lxor") + (param $ref (ref eq)) (param $i (ref eq)) (result (ref eq)) + (local $b (ref $block)) + (local $old (ref eq)) + (local.set $b (ref.cast (ref $block) (local.get $ref))) + (local.set $old (array.get $block (local.get $b) (i32.const 1))) + (array.set $block (local.get $b) (i32.const 1) + (ref.i31 (i32.xor (i31.get_s (ref.cast (ref i31) (local.get $old))) + (i31.get_s (ref.cast (ref i31) (local.get $i)))))) + (ref.i31 (i32.const 0))) + (func (export "caml_atomic_exchange") (param $ref (ref eq)) (param $v (ref eq)) (result (ref eq)) (local $b (ref $block)) @@ -111,6 +181,15 @@ (array.set $block (local.get $b) (local.get $j) (local.get $v)) (local.get $r)) + (func (export "caml_atomic_set") + (param $ref (ref eq)) (param $v (ref eq)) (result (ref eq)) + (local $b (ref $block)) + (local $r (ref eq)) + (local.set $b (ref.cast (ref $block) (local.get $ref))) + (local.set $r (array.get $block (local.get $b) (i32.const 1))) + (array.set $block (local.get $b) (i32.const 1) (local.get $v)) + (ref.i31 (i32.const 0))) + (func (export "caml_atomic_make_contended") (param $v (ref eq)) (result (ref eq)) (array.new_fixed $block 2 (ref.i31 (i32.const 0)) (local.get $v))) @@ -200,4 +279,112 @@ (func (export "caml_ml_domain_cpu_relax") (param (ref eq)) (result (ref eq)) (ref.i31 (i32.const 0))) + + (func (export "caml_atomic_add_field") + (param $ref (ref eq)) (param $field (ref eq)) (param $i (ref eq)) + (result (ref eq)) + (local $b (ref $block)) + (local $idx i32) + (local $old (ref eq)) + (local.set $b (ref.cast (ref $block) (local.get $ref))) + (local.set $idx + (i32.add (i31.get_s (ref.cast (ref i31) (local.get $field))) + (i32.const 1))) + (local.set $old (array.get $block (local.get $b) (local.get $idx))) + (array.set $block (local.get $b) (local.get $idx) + (ref.i31 (i32.add (i31.get_s (ref.cast (ref i31) (local.get $old))) + (i31.get_s (ref.cast (ref i31) (local.get $i)))))) + (ref.i31 (i32.const 0))) + + (func (export "caml_atomic_sub_field") + (param $ref (ref eq)) (param $field (ref eq)) (param $i (ref eq)) + (result (ref eq)) + (local $b (ref $block)) + (local $idx i32) + (local $old (ref eq)) + (local.set $b (ref.cast (ref $block) (local.get $ref))) + (local.set $idx + (i32.add (i31.get_s (ref.cast (ref i31) (local.get $field))) + (i32.const 1))) + (local.set $old (array.get $block (local.get $b) (local.get $idx))) + (array.set $block (local.get $b) (local.get $idx) + (ref.i31 (i32.sub (i31.get_s (ref.cast (ref i31) (local.get $old))) + (i31.get_s (ref.cast (ref i31) (local.get $i)))))) + (ref.i31 (i32.const 0))) + + (func (export "caml_atomic_land_field") + (param $ref (ref eq)) (param $field (ref eq)) (param $i (ref eq)) + (result (ref eq)) + (local $b (ref $block)) + (local $idx i32) + (local $old (ref eq)) + (local.set $b (ref.cast (ref $block) (local.get $ref))) + (local.set $idx + (i32.add (i31.get_s (ref.cast (ref i31) (local.get $field))) + (i32.const 1))) + (local.set $old (array.get $block (local.get $b) (local.get $idx))) + (array.set $block (local.get $b) (local.get $idx) + (ref.i31 (i32.and (i31.get_s (ref.cast (ref i31) (local.get $old))) + (i31.get_s (ref.cast (ref i31) (local.get $i)))))) + (ref.i31 (i32.const 0))) + + (func (export "caml_atomic_lor_field") + (param $ref (ref eq)) (param $field (ref eq)) (param $i (ref eq)) + (result (ref eq)) + (local $b (ref $block)) + (local $idx i32) + (local $old (ref eq)) + (local.set $b (ref.cast (ref $block) (local.get $ref))) + (local.set $idx + (i32.add (i31.get_s (ref.cast (ref i31) (local.get $field))) + (i32.const 1))) + (local.set $old (array.get $block (local.get $b) (local.get $idx))) + (array.set $block (local.get $b) (local.get $idx) + (ref.i31 (i32.or (i31.get_s (ref.cast (ref i31) (local.get $old))) + (i31.get_s (ref.cast (ref i31) (local.get $i)))))) + (ref.i31 (i32.const 0))) + + (func (export "caml_atomic_lxor_field") + (param $ref (ref eq)) (param $field (ref eq)) (param $i (ref eq)) + (result (ref eq)) + (local $b (ref $block)) + (local $idx i32) + (local $old (ref eq)) + (local.set $b (ref.cast (ref $block) (local.get $ref))) + (local.set $idx + (i32.add (i31.get_s (ref.cast (ref i31) (local.get $field))) + (i32.const 1))) + (local.set $old (array.get $block (local.get $b) (local.get $idx))) + (array.set $block (local.get $b) (local.get $idx) + (ref.i31 (i32.xor (i31.get_s (ref.cast (ref i31) (local.get $old))) + (i31.get_s (ref.cast (ref i31) (local.get $i)))))) + (ref.i31 (i32.const 0))) + + (func (export "caml_atomic_compare_exchange_field") + (param $ref (ref eq)) (param $field (ref eq)) (param $o (ref eq)) + (param $n (ref eq)) (result (ref eq)) + (local $b (ref $block)) + (local $idx i32) + (local $old (ref eq)) + (local.set $b (ref.cast (ref $block) (local.get $ref))) + (local.set $idx + (i32.add (i31.get_s (ref.cast (ref i31) (local.get $field))) + (i32.const 1))) + (local.set $old (array.get $block (local.get $b) (local.get $idx))) + (if (ref.eq (local.get $old) (local.get $o)) + (then + (array.set $block (local.get $b) (local.get $idx) (local.get $n)))) + (local.get $old)) + + (func (export "caml_atomic_set_field") + (param $ref (ref eq)) (param $field (ref eq)) (param $v (ref eq)) + (result (ref eq)) + (local $b (ref $block)) + (local $idx i32) + (local.set $b (ref.cast (ref $block) (local.get $ref))) + (local.set $idx + (i32.add (i31.get_s (ref.cast (ref i31) (local.get $field))) + (i32.const 1))) + (array.set $block (local.get $b) (local.get $idx) (local.get $v)) + (ref.i31 (i32.const 0))) ) diff --git a/runtime/wasm/float.wat b/runtime/wasm/float.wat index 5c58371d9f..c205b7971c 100644 --- a/runtime/wasm/float.wat +++ b/runtime/wasm/float.wat @@ -216,21 +216,25 @@ (local.set $sign_style (i32.const 2)) (local.set $i (i32.add (local.get $i) (i32.const 1))))) (br_if $bad_format (i32.eq (local.get $i) (local.get $len))) - (br_if $bad_format - (i32.ne (array.get_u $bytes (local.get $s) (local.get $i)) - (@char "."))) - (loop $precision - (local.set $i (i32.add (local.get $i) (i32.const 1))) - (br_if $bad_format (i32.eq (local.get $i) (local.get $len))) - (local.set $c - (array.get_u $bytes (local.get $s) (local.get $i))) - (if (i32.and (i32.ge_u (local.get $c) (@char "0")) - (i32.le_u (local.get $c) (@char "9"))) - (then - (local.set $precision - (i32.add (i32.mul (local.get $precision) (i32.const 10)) + (if (i32.eq (array.get_u $bytes (local.get $s) (local.get $i)) + (@char ".")) + (then + (loop $precision + (local.set $i (i32.add (local.get $i) (i32.const 1))) + (br_if $bad_format + (i32.eq (local.get $i) (local.get $len))) + (local.set $c + (array.get_u $bytes (local.get $s) (local.get $i))) + (if (i32.and (i32.ge_u (local.get $c) (@char "0")) + (i32.le_u (local.get $c) (@char "9"))) + (then + (local.set $precision + (i32.add + (i32.mul (local.get $precision) (i32.const 10)) (i32.sub (local.get $c) (@char "0")))) - (br $precision)))) + (br $precision))))) + (else + (local.set $precision (i32.const 6)))) (br_if $bad_format (i32.ne (i32.add (local.get $i) (i32.const 1)) (local.get $len))) (local.set $uppercase (i32.lt_s (local.get $c) (@char "a"))) @@ -330,9 +334,9 @@ (br_if $uppercase (i32.lt_u (local.get $i) (local.get $len)))))) (local.get $s)) - (@string $float_of_string "float_of_string") - - (func $caml_float_of_hex (param $s (ref $bytes)) (param $i i32) (result f64) + (func $caml_float_of_hex + (param $err_msg (ref eq)) (param $s (ref $bytes)) (param $i i32) + (result f64) (local $len i32) (local $c i32) (local $d i32) (local $m i64) (local $f f64) (local $negative i32) (local $dec_point i32) (local $exp i32) (local $adj i32) @@ -471,7 +475,7 @@ (if (local.get $exp) (then (local.set $f (call $ldexp (local.get $f) (local.get $exp))))) (return (local.get $f))) - (call $caml_failwith (global.get $float_of_string)) + (call $caml_failwith (local.get $err_msg)) (f64.const 0)) (func $on_whitespace (param $s (ref $bytes)) (param $i i32) (result i32) @@ -480,12 +484,13 @@ (i32.or (i32.eq (local.get $c) (@char " ")) (i32.le_u (i32.sub (local.get $c) (i32.const 9)) (i32.const 4)))) - (func (export "caml_float_of_string") (param (ref eq)) (result (ref eq)) + (func $caml_parse_float (export "caml_parse_float") + (param $err_msg (ref eq)) (param (ref eq)) (result (ref eq)) (local $s (ref $bytes)) (local $len i32) (local $i i32) (local $j i32) (local $s' (ref $bytes)) (local $negative i32) (local $c i32) (local $f f64) - (local.set $s (ref.cast (ref $bytes) (local.get 0))) + (local.set $s (ref.cast (ref $bytes) (local.get 1))) (local.set $len (array.len (local.get $s))) (loop $count (if (i32.lt_u (local.get $i) (local.get $len)) @@ -551,7 +556,8 @@ (@char "X")) (then (local.set $f - (call $caml_float_of_hex (local.get $s) + (call $caml_float_of_hex (local.get $err_msg) + (local.get $s) (i32.add (local.get $i) (i32.const 2)))) (if (local.get $negative) (then (local.set $f (f64.neg (local.get $f))))) @@ -655,9 +661,15 @@ (call $parse_float (call $jsstring_of_bytes (local.get $s)))) (br_if $error (f64.ne (local.get $f) (local.get $f))) (return (struct.new $float (local.get $f)))) - (call $caml_failwith (global.get $float_of_string)) + (call $caml_failwith (local.get $err_msg)) (return (ref.i31 (i32.const 0)))) + (@string $float_of_string "float_of_string") + + (func (export "caml_float_of_string") (param $s (ref eq)) (result (ref eq)) + (return_call $caml_parse_float + (global.get $float_of_string) (local.get $s))) + (func (export "caml_nextafter_float") (param $x f64) (param $y f64) (result f64) (local $i i64) (local $j i64) diff --git a/runtime/wasm/float32.wat b/runtime/wasm/float32.wat new file mode 100644 index 0000000000..c72fcc82ee --- /dev/null +++ b/runtime/wasm/float32.wat @@ -0,0 +1,284 @@ +(module + (import "fail" "caml_failwith" + (func $caml_failwith (param (ref eq)))) + (import "marshal" "caml_serialize_int_4" + (func $caml_serialize_int_4 (param (ref eq)) (param i32))) + (import "marshal" "caml_deserialize_int_4" + (func $caml_deserialize_int_4 (param (ref eq)) (result i32))) + (import "float" "caml_parse_float" + (func $caml_parse_float (param (ref eq) (ref eq)) (result (ref eq)))) + (import "float" "caml_format_float" + (func $caml_format_float (param (ref eq)) (param (ref eq)) (result (ref eq)))) + (import "float" "caml_fma_float" + (func $caml_fma_float + (param (ref eq) (ref eq) (ref eq)) (result (ref eq)))) + (import "float" "caml_erf_float" + (func $caml_erf_float (param f64) (result f64))) + (import "float" "caml_erfc_float" + (func $caml_erfc_float (param f64) (result f64))) + (import "float" "caml_frexp_float" + (func $caml_frexp_float (param (ref eq)) (result (ref eq)))) + (import "float" "caml_ldexp_float" + (func $caml_ldexp_float (param f64) (param i32) (result f64))) + (import "bigarray" "caml_ba_uint8_get32" + (func $caml_ba_uint8_get32 (param (ref eq)) (param i32) (result i32))) + (import "bigarray" "caml_ba_uint8_set32" + (func $caml_ba_uint8_set32 (param (ref eq)) (param i32) (param i32) (result (ref eq)))) + (import "string" "caml_string_get32" + (func $caml_string_get32 (param (ref eq)) (param i32) (result i32))) + (import "string" "caml_bytes_get32" + (func $caml_bytes_get32 (param (ref eq)) (param i32) (result i32))) + (import "string" "caml_bytes_set32" + (func $caml_bytes_set32 (param (ref eq)) (param i32) (param i32) (result (ref eq)))) + (import "array" "caml_make_vect" + (func $caml_make_vect (param (ref eq)) (param (ref eq)) (result (ref eq)))) + + (type $float (struct (field f64))) + + (func $box_float (param $f f64) (result (ref eq)) + (struct.new $float (local.get $f))) + + (func $unbox_float (param $f (ref eq)) (result f64) + (struct.get $float 0 (ref.cast (ref $float) (local.get $f)))) + + (type $block (array (mut (ref eq)))) + (type $bytes (array (mut i8))) + (type $compare + (func (param (ref eq)) (param (ref eq)) (param i32) (result i32))) + (type $hash + (func (param (ref eq)) (result i32))) + (type $fixed_length (struct (field $bsize_32 i32) (field $bsize_64 i32))) + (type $serialize + (func (param (ref eq)) (param (ref eq)) (result i32) (result i32))) + (type $deserialize (func (param (ref eq)) (result (ref eq)) (result i32))) + (type $dup (func (param (ref eq)) (result (ref eq)))) + (type $custom_operations + (struct + (field $id (ref $bytes)) + (field $compare (ref null $compare)) + (field $compare_ext (ref null $compare)) + (field $hash (ref null $hash)) + (field $fixed_length (ref null $fixed_length)) + (field $serialize (ref null $serialize)) + (field $deserialize (ref null $deserialize)) + (field $dup (ref null $dup)))) + (type $custom (sub (struct (field (ref $custom_operations))))) + + (global $float32_ops (export "float32_ops") (ref $custom_operations) + (struct.new $custom_operations + (@string "_f32") + (ref.func $float32_cmp) + (ref.null $compare) + (ref.func $float32_hash) + (struct.new $fixed_length (i32.const 4) (i32.const 4)) + (ref.func $float32_serialize) + (ref.func $float32_deserialize) + (ref.func $float32_dup))) + + (type $float32 + (sub final $custom (struct (field (ref $custom_operations)) (field f32)))) + + (func $box_float32 (param $f f32) (result (ref eq)) + (struct.new $float32 (global.get $float32_ops) (local.get $f))) + + (func $unbox_float32 (param $f (ref eq)) (result f32) + (struct.get $float32 1 (ref.cast (ref $float32) (local.get $f)))) + + (func $float32_cmp + (param $v1 (ref eq)) (param $v2 (ref eq)) (param i32) (result i32) + (local $x f32) (local $y f32) + (local.set $x (call $unbox_float32 (local.get $v1))) + (local.set $y (call $unbox_float32 (local.get $v2))) + (i32.add + (i32.sub (f32.gt (local.get $x) (local.get $y)) + (f32.lt (local.get $x) (local.get $y))) + (i32.sub (f32.eq (local.get $x) (local.get $x)) + (f32.eq (local.get $y) (local.get $y))))) + + (func $float32_hash (param $v (ref eq)) (result i32) + (i32.reinterpret_f32 (call $unbox_float32 (local.get $v)))) + + (func $float32_serialize + (param $s (ref eq)) (param $v (ref eq)) (result i32) (result i32) + (call $caml_serialize_int_4 (local.get $s) + (i32.reinterpret_f32 (call $unbox_float32 (local.get $v)))) + (tuple.make 2 (i32.const 4) (i32.const 4))) + + (func $float32_deserialize (param $s (ref eq)) (result (ref eq) i32) + (tuple.make 2 + (call $box_float32 + (f32.reinterpret_i32 (call $caml_deserialize_int_4 (local.get $s)))) + (i32.const 4))) + + (func $float32_dup + (param $v (ref eq)) (result (ref eq)) + (local $d (ref $float32)) + (local.set $d (ref.cast (ref $float32) (local.get $v))) + (struct.new $float32 + (struct.get $float32 0 (local.get $d)) + (struct.get $float32 1 (local.get $d)))) + + (func $caml_float_of_float32 + (param $f32 (ref eq)) (result (ref eq)) + (call $box_float (f64.promote_f32 (call $unbox_float32 (local.get $f32))))) + + (func $caml_float32_of_float + (param $f64 (ref eq)) (result (ref eq)) + (call $box_float32 (f32.demote_f64 (call $unbox_float (local.get $f64))))) + + (func (export "caml_round_float32_bytecode") (param $x f32) (result f32) + (local $y f32) + (if (result f32) (f32.ge (local.get $x) (f32.const 0)) + (then + (local.set $y (f32.floor (local.get $x))) + (if (result f32) + (f32.ge (f32.sub (local.get $x) (local.get $y)) (f32.const 0.5)) + (then (f32.add (local.get $y) (f32.const 1))) + (else (local.get $y)))) + (else + (local.set $y (f32.ceil (local.get $x))) + (if (result f32) + (f32.ge (f32.sub (local.get $y) (local.get $x)) (f32.const 0.5)) + (then (f32.sub (local.get $y) (f32.const 1))) + (else (local.get $y)))))) + + (@string $float32_of_string "float32_of_string") + + (func (export "caml_float32_of_string") (param $s (ref eq)) (result (ref eq)) + (call $caml_float32_of_float + (call $caml_parse_float (global.get $float32_of_string) + (local.get $s)))) + + (func (export "caml_format_float32") + (param $s (ref eq)) (param $f (ref eq)) (result (ref eq)) + (call $caml_format_float + (local.get $s) (call $caml_float_of_float32 (local.get $f)))) + + (func (export "caml_float32_compare") + (param $x f32) (param $y f32) (result i32) + (i32.add + (i32.sub (f32.gt (local.get $x) (local.get $y)) + (f32.lt (local.get $x) (local.get $y))) + (i32.sub (f32.eq (local.get $x) (local.get $x)) + (f32.eq (local.get $y) (local.get $y))))) + + (func (export "caml_modf_float32") (param (ref eq)) (result (ref eq)) + (local $x f32) (local $a f32) (local $i f32) (local $f f32) + (local.set $x (call $unbox_float32 (local.get 0))) + (local.set $a (f32.abs (local.get $x))) + (if (f32.ge (local.get $a) (f32.const 0)) + (then + (if (f32.lt (local.get $a) (f32.const inf)) + (then ;; normal + (local.set $i (f32.floor (local.get $a))) + (local.set $f (f32.sub (local.get $a) (local.get $i))) + (local.set $i (f32.copysign (local.get $i) (local.get $x))) + (local.set $f (f32.copysign (local.get $f) (local.get $x)))) + (else ;; infinity + (local.set $i (local.get $x)) + (local.set $f (f32.copysign (f32.const 0) (local.get $x)))))) + (else ;; zero or nan + (local.set $i (local.get $x)) + (local.set $f (local.get $x)))) + (array.new_fixed $block 3 (ref.i31 (i32.const 0)) + (call $box_float32 (local.get $f)) (call $box_float32 (local.get $i)))) + + (func (export "caml_nextafter_float32_bytecode") + (param $x f32) (param $y f32) (result f32) + (local $i i32) (local $j i32) + (if (f32.ne (local.get $x) (local.get $x)) (then (return (local.get $x)))) + (if (f32.ne (local.get $y) (local.get $y)) (then (return (local.get $y)))) + (if (f32.eq (local.get $x) (local.get $y)) + (then (return (local.get 1)))) + (if (result f32) (f32.eq (local.get $x) (f32.const 0)) + (then + (if (f32.ge (local.get $y) (f32.const 0)) + (then (return (f32.const 0x1p-149))) + (else (return (f32.const -0x1p-149))))) + (else + (local.set $i (i32.reinterpret_f32 (local.get $x))) + (local.set $j (i32.reinterpret_f32 (local.get $y))) + (if (i32.and (i32.lt_s (local.get $i) (local.get $j)) + (i32.lt_u (local.get $i) (local.get $j))) + (then (local.set $i (i32.add (local.get $i) (i32.const 1)))) + (else (local.set $i (i32.sub (local.get $i) (i32.const 1))))) + (return (f32.reinterpret_i32 (local.get $i)))))) + + (func (export "caml_classify_float32_bytecode") + (param $a f32) (result i32) + (local.set $a (f32.abs (local.get $a))) + (if (result i32) (f32.ge (local.get $a) (f32.const 0x1p-126)) + (then + (if (result i32) (f32.lt (local.get $a) (f32.const inf)) + (then (i32.const 0)) ;; normal + (else (i32.const 3)))) ;; infinity + (else + (if (result i32) (f32.eq (local.get $a) (f32.const 0)) + (then (i32.const 2)) ;; zero + (else + (if (result i32) (f32.eq (local.get $a) (local.get $a)) + (then (i32.const 1)) ;; subnormal + (else (i32.const 4)))))))) ;; nan + + (func (export "caml_ldexp_float32_bytecode") + (param $x f32) (param $n i32) (result f32) + (f32.demote_f64 + (call $caml_ldexp_float + (f64.promote_f32 (local.get $x)) (local.get $n)))) + + (func (export "caml_frexp_float32") + (param (ref eq)) (result (ref eq)) + (local $frexp (ref $block)) + (local.set $frexp (ref.cast (ref $block) + (call $caml_frexp_float (call $caml_float_of_float32 (local.get 0))))) + (array.new_fixed $block 3 (ref.i31 (i32.const 0)) + (call $caml_float32_of_float + (array.get $block (local.get $frexp) (i32.const 1))) + (array.get $block (local.get $frexp) (i32.const 2)))) + + (func (export "caml_erf_float32_bytecode") (param $x f32) (result f32) + (f32.demote_f64 (call $caml_erf_float (f64.promote_f32 (local.get $x))))) + + (func (export "caml_erfc_float32_bytecode") (param $x f32) (result f32) + (f32.demote_f64 (call $caml_erfc_float (f64.promote_f32 (local.get $x))))) + + (func (export "caml_fma_float32_bytecode") + (param $x (ref eq)) (param $y (ref eq)) (param $z (ref eq)) + (result (ref eq)) + (call $caml_float32_of_float + (call $caml_fma_float + (call $caml_float_of_float32 (local.get $x)) + (call $caml_float_of_float32 (local.get $y)) + (call $caml_float_of_float32 (local.get $z))))) + + (global $zero (ref eq) + (struct.new $float32 (global.get $float32_ops) (f32.const 0))) + + (func (export "caml_ba_uint8_getf32") + (param $a (ref eq)) (param $i i32) (result f32) + (f32.reinterpret_i32 + (call $caml_ba_uint8_get32 (local.get $a) (local.get $i)))) + + (func (export "caml_ba_uint8_setf32") + (param $a (ref eq)) (param $i i32) (param $v f32) (result (ref eq)) + (call $caml_ba_uint8_set32 (local.get $a) (local.get $i) + (i32.reinterpret_f32 (local.get $v)))) + + (func (export "caml_string_getf32") + (param $a (ref eq)) (param $i i32) (result f32) + (f32.reinterpret_i32 + (call $caml_string_get32 (local.get $a) (local.get $i)))) + + (func (export "caml_bytes_getf32") + (param $a (ref eq)) (param $i i32) (result f32) + (f32.reinterpret_i32 + (call $caml_bytes_get32 (local.get $a) (local.get $i)))) + + (func (export "caml_bytes_setf32") + (param $a (ref eq)) (param $i i32) (param $v f32) (result (ref eq)) + (call $caml_bytes_set32 (local.get $a) (local.get $i) + (i32.reinterpret_f32 (local.get $v)))) + + (func (export "caml_is_boot_compiler") (param (ref eq)) (result (ref eq)) + (ref.i31 (i32.const 0))) +) diff --git a/runtime/wasm/gc.wat b/runtime/wasm/gc.wat index 3fba5782d3..8baff54e30 100644 --- a/runtime/wasm/gc.wat +++ b/runtime/wasm/gc.wat @@ -117,6 +117,9 @@ (func (export "caml_memprof_discard") (param (ref eq)) (result (ref eq)) (ref.i31 (i32.const 0))) + (func (export "caml_memprof_participate") (param (ref eq)) (result (ref eq)) + (ref.i31 (i32.const 0))) + (func (export "caml_eventlog_pause") (param (ref eq)) (result (ref eq)) (ref.i31 (i32.const 0))) diff --git a/runtime/wasm/hash.wat b/runtime/wasm/hash.wat index a7a78c9e49..cd826e536a 100644 --- a/runtime/wasm/hash.wat +++ b/runtime/wasm/hash.wat @@ -174,7 +174,7 @@ (global $caml_hash_queue (ref $block) (array.new $block (ref.i31 (i32.const 0)) (global.get $HASH_QUEUE_SIZE))) - (func (export "caml_hash") + (func (export "caml_hash") (export "caml_hash_exn") (param $count (ref eq)) (param $limit (ref eq)) (param $seed (ref eq)) (param $obj (ref eq)) (result (ref eq)) (local $sz i32) (local $num i32) (local $h i32) diff --git a/runtime/wasm/ints.wat b/runtime/wasm/ints.wat index a524ae9a77..bfb4ff6b4a 100644 --- a/runtime/wasm/ints.wat +++ b/runtime/wasm/ints.wat @@ -165,6 +165,24 @@ (call $parse_int (local.get $v) (i32.const 31) (global.get $INT_ERRMSG)))) + (@string $INT8_ERRMSG "Int8.of_string") + + (func (export "caml_int8_of_string") + (param $v (ref eq)) (result (ref eq)) + (ref.i31 + (i32.extend8_s + (call $parse_int + (local.get $v) (i32.const 8) (global.get $INT8_ERRMSG))))) + + (@string $INT16_ERRMSG "Int16.of_string") + + (func (export "caml_int16_of_string") + (param $v (ref eq)) (result (ref eq)) + (ref.i31 + (i32.extend16_s + (call $parse_int + (local.get $v) (i32.const 16) (global.get $INT16_ERRMSG))))) + (func (export "caml_bswap16") (param (ref eq)) (result (ref eq)) (local $x i32) (local.set $x (i31.get_s (ref.cast (ref i31) (local.get 0)))) diff --git a/runtime/wasm/io.wat b/runtime/wasm/io.wat index b74db04e88..f3ec81f89f 100644 --- a/runtime/wasm/io.wat +++ b/runtime/wasm/io.wat @@ -76,6 +76,8 @@ (tag $javascript_exception (param externref))) (import "sys" "caml_handle_sys_error" (func $caml_handle_sys_error (param externref))) + (import "fail" "caml_invalid_argument" + (func $caml_invalid_argument (param (ref eq)))) (import "custom" "custom_compare_id" (func $custom_compare_id (param (ref eq)) (param (ref eq)) (param i32) (result i32))) @@ -1020,4 +1022,13 @@ (ref.i31 (call $caml_getblock_typed_array (local.get $ch) (local.get $d) (local.get $pos) (local.get $len)))) + + (@string $caml_ml_set_channel_refill + "caml_ml_set_channel_refill not implemented") + + (func (export "caml_ml_set_channel_refill") + (param (ref eq)) (param (ref eq)) (result (ref eq)) + (call $caml_invalid_argument + (global.get $caml_ml_set_channel_refill)) + (ref.i31 (i32.const 0))) ) diff --git a/runtime/wasm/jslib.wat b/runtime/wasm/jslib.wat index 23542f08e5..400da18a2b 100644 --- a/runtime/wasm/jslib.wat +++ b/runtime/wasm/jslib.wat @@ -22,6 +22,7 @@ (import "bindings" "identity" (func $to_int32 (param anyref) (result i32))) (import "bindings" "identity" (func $from_int32 (param i32) (result anyref))) (import "bindings" "from_bool" (func $from_bool (param i32) (result anyref))) + (import "bindings" "eval" (func $eval (param anyref) (result anyref))) (import "bindings" "get" (func $get (param (ref extern)) (param anyref) (result anyref))) (import "bindings" "set" @@ -128,6 +129,13 @@ (ref.i31 (call $strict_equals (call $unwrap (local.get 0)) (call $unwrap (local.get 1))))) + (func (export "caml_js_expr") (export "caml_pure_js_expr") + (export "caml_js_var") (export "caml_js_eval_string") + (param (ref eq)) (result (ref eq)) + (local $s (ref $bytes)) + (local.set $s (ref.cast (ref $bytes) (local.get 0))) + (return_call $wrap (call $eval (call $jsstring_of_bytes (local.get $s))))) + (func (export "caml_js_global") (param (ref eq)) (result (ref eq)) (call $wrap (global.get $global_this))) diff --git a/runtime/wasm/marshal.wat b/runtime/wasm/marshal.wat index b25fff016e..bb1784e51b 100644 --- a/runtime/wasm/marshal.wat +++ b/runtime/wasm/marshal.wat @@ -21,6 +21,7 @@ (func $caml_invalid_argument (param (ref eq)))) (import "fail" "caml_raise_end_of_file" (func $caml_raise_end_of_file)) (import "obj" "object_tag" (global $object_tag i32)) + (import "obj" "null" (global $null (ref eq))) (import "obj" "caml_set_oo_id" (func $caml_set_oo_id (param (ref eq)) (result (ref eq)))) (import "string" "caml_string_concat" @@ -190,6 +191,7 @@ (global $CODE_CUSTOM i32 (i32.const 0x12)) (global $CODE_CUSTOM_LEN i32 (i32.const 0x18)) (global $CODE_CUSTOM_FIXED i32 (i32.const 0x19)) + (global $CODE_NULL i32 (i32.const 0x1F)) (type $intern_state (struct @@ -561,20 +563,26 @@ (block $DOUBLE_ARRAY32 (block $CODEPOINTER (block $CUSTOM - (block $default - (br_table $INT8 $INT16 $INT32 $INT64 - $SHARED8 $SHARED16 $SHARED32 - $DOUBLE_ARRAY32 $BLOCK32 $STRING8 - $STRING32 $DOUBLE $DOUBLE - $DOUBLE_ARRAY8 $DOUBLE_ARRAY8 - $DOUBLE_ARRAY32 $CODEPOINTER - $CODEPOINTER $CUSTOM $default - $default $default $default $default - $CUSTOM $CUSTOM $default - (local.get $code))) - ;; default - (call $caml_failwith - (global.get $ill_formed)) + (block $NULL + (block $default + (br_table $INT8 $INT16 $INT32 $INT64 + $SHARED8 $SHARED16 $SHARED32 + $DOUBLE_ARRAY32 $BLOCK32 $STRING8 + $STRING32 $DOUBLE $DOUBLE + $DOUBLE_ARRAY8 $DOUBLE_ARRAY8 + $DOUBLE_ARRAY32 $CODEPOINTER + $CODEPOINTER $CUSTOM $default + $default $default $default $default + $CUSTOM $CUSTOM $default $default + $default $default $default $NULL + $default + (local.get $code))) + ;; default + (call $caml_failwith + (global.get $ill_formed)) + (br $done)) + ;; NULL + (local.set $v (global.get $null)) (br $done)) ;; CUSTOM (local.set $v @@ -1272,6 +1280,10 @@ (local.get $sp))))) (local.set $v (array.get $block (local.get $b) (i32.const 1))) (br $loop))) + (if (ref.eq (local.get $v) (global.get $null)) + (then + (call $write (local.get $s) (global.get $CODE_NULL)) + (br $next_item))) (local.set $pos (call $extern_lookup_position (local.get $s) (local.get $v))) (if (i32.ge_s (local.get $pos) (i32.const 0)) diff --git a/runtime/wasm/obj.wat b/runtime/wasm/obj.wat index 4fc39ee904..b06c39f3f1 100644 --- a/runtime/wasm/obj.wat +++ b/runtime/wasm/obj.wat @@ -99,6 +99,22 @@ (global $double_array_tag (export "double_array_tag") i32 (i32.const 254)) (global $custom_tag i32 (i32.const 255)) + (func (export "caml_obj_is_stack") + (param (ref eq)) (result (ref eq)) + (ref.i31 (i32.const 0))) + + (func (export "caml_succ_scannable_prefix_len") + (param (ref eq)) (result (ref eq)) + (ref.i31 (i32.const 0))) + + (@string $unique_words_unsupported + "Obj.uniquely_reachable_words is not available in wasm.") + + (func (export "caml_obj_uniquely_reachable_words") + (param (ref eq)) (result (ref eq)) + (call $caml_failwith (global.get $unique_words_unsupported)) + (ref.i31 (i32.const 0))) + (func $caml_is_closure (export "caml_is_closure") (param $v (ref eq)) (result i32) (i32.or (ref.test (ref $closure) (local.get $v)) @@ -119,6 +135,12 @@ (array.new $float_array (f64.const 0) (i31.get_u (ref.cast (ref i31) (local.get $size))))) + (func (export "caml_alloc_dummy_mixed") + (param $size (ref eq)) (param (ref eq)) (result (ref eq)) + (array.new $block (ref.i31 (i32.const 0)) + (i32.add (i31.get_u (ref.cast (ref i31) (local.get $size))) + (i32.const 1)))) + (func (export "caml_update_dummy") (param $dummy (ref eq)) (param $newval (ref eq)) (result (ref eq)) (local $i i32) @@ -261,6 +283,8 @@ (local.get $res)) (func (export "caml_obj_tag") (param $v (ref eq)) (result (ref eq)) + (if (ref.eq (local.get $v) (global.get $null)) + (then (return (ref.i31 (i32.const 1010))))) (if (ref.test (ref i31) (local.get $v)) (then (return (ref.i31 (i32.const 1000))))) (drop (block $not_block (result (ref eq)) @@ -561,4 +585,16 @@ (call $caml_callback_1 (local.get $f) (local.get $x)) (local.get $y))) )) + + (type $null (struct)) + (global $null (export "null") (ref eq) (struct.new $null)) + + (@string $int_as_pointer_not_implemented + "caml_int_as_pointer is not supported") + + (func (export "caml_int_as_pointer") (param $x (ref eq)) (result (ref eq)) + (if (i32.eqz (ref.eq (local.get $x) (ref.i31 (i32.const 0)))) + (then + (call $caml_failwith (global.get $int_as_pointer_not_implemented)))) + (global.get $null)) ) diff --git a/runtime/wasm/runtime.js b/runtime/wasm/runtime.js index 9994c9b32d..a109de46f4 100644 --- a/runtime/wasm/runtime.js +++ b/runtime/wasm/runtime.js @@ -211,6 +211,8 @@ typeof: (x) => typeof x, // biome-ignore lint/suspicious/noDoubleEquals: equals: (x, y) => x == y, + // biome-ignore lint/security/noGlobalEval: + eval: (x) => globalThis.eval("(" + x + ")"), strict_equals: (x, y) => x === y, fun_call: (f, o, args) => f.apply(o, args), meth_call: (o, f, args) => o[f].apply(o, args), diff --git a/runtime/wasm/stdlib.wat b/runtime/wasm/stdlib.wat index 65dfa0c313..e47c64e3d6 100644 --- a/runtime/wasm/stdlib.wat +++ b/runtime/wasm/stdlib.wat @@ -234,4 +234,7 @@ (call $unwrap (call $caml_jsstring_of_string (local.get $msg))))) (call $exit (i32.const 2))))) + + (func (export "caml_with_async_exns") (param $f (ref eq)) (result (ref eq)) + (return_call $caml_callback_1 (local.get $f) (ref.i31 (i32.const 0)))) ) diff --git a/runtime/wasm/string.wat b/runtime/wasm/string.wat index b594de1206..f1e406f23d 100644 --- a/runtime/wasm/string.wat +++ b/runtime/wasm/string.wat @@ -121,7 +121,7 @@ (@string $Bytes_create "Bytes.create") - (func (export "caml_create_bytes") + (func (export "caml_create_bytes") (export "caml_create_local_bytes") (param $len (ref eq)) (result (ref eq)) (local $l i32) (local.set $l (i31.get_s (ref.cast (ref i31) (local.get $len)))) diff --git a/runtime/wasm/sys.wat b/runtime/wasm/sys.wat index ff904edd50..e9a1220071 100644 --- a/runtime/wasm/sys.wat +++ b/runtime/wasm/sys.wat @@ -174,6 +174,10 @@ (param $ch (ref eq)) (result (ref eq)) (return_call $isatty (call $caml_channel_descriptor (local.get $ch)))) + (func (export "caml_sys_const_runtime5") + (param (ref eq)) (result (ref eq)) + (ref.i31 (i32.const 1))) + (func (export "caml_runtime_variant") (param (ref eq)) (result (ref eq)) (@string "")) diff --git a/tools/ci_setup.ml b/tools/ci_setup-generic.ml similarity index 100% rename from tools/ci_setup.ml rename to tools/ci_setup-generic.ml diff --git a/tools/ci_setup-oxcaml.ml b/tools/ci_setup-oxcaml.ml new file mode 100644 index 0000000000..a0a9342755 --- /dev/null +++ b/tools/ci_setup-oxcaml.ml @@ -0,0 +1,437 @@ +module StringSet = Set.Make (String) + +(****) + +let jane_root, wasmoo_root = + match Sys.argv with + | [| _; jane_root; wasmoo_root |] -> jane_root, wasmoo_root + | _ -> "janestreet", "wasm_of_ocaml" + +let repo = Filename.concat jane_root "opam-repository/packages" + +let roots = + [ "bonsai_web_components" + ; "string_dict" + ; "ppx_html" + ; "bonsai_bench" + ; "float_array" + ; "unboxed" + ; "await" + ] + +let additional_others = StringSet.of_list [ "spawn" ] + +let omitted_others = StringSet.of_list [ "odoc" ] + +let omitted_js = StringSet.of_list [ "basement"; "sexplib0"; "ppxlib_jane"; "spawn" ] + +let do_pin = StringSet.of_list [ "bigstringaf" ] + +let forked_packages = + StringSet.of_list + [ "ocaml_intrinsics_kernel" + ; "base" + ; "core" + ; "bonsai_test" + ; "bonsai_web_components" + ; "bonsai_web_test" + ; "virtual_dom" + ] + +let dune_workspace = + {|(lang dune 3.17) +(env + (_ + (env-vars (TESTING_FRAMEWORK inline-test)) + (js_of_ocaml (enabled_if false)) + (ocamlopt_flags -zero-alloc-check none) + (flags :standard -alert -all -warn-error -7-8-27-30-32-34-37-49-52-55 -w -7-27-30-32-34-37-49-52-55-56-58-67-69))) +|} + +let node_wrapper = + [ ( "node_wrapper/dune" + , {|(executable + (public_name node) + (name node_wrapper) + (libraries unix))|} ) + ; "node_wrapper/node_wrapper_per_profile.ml", {|let args = []|} + ; "node_wrapper/dune-project", "(lang dune 3.17)" + ; "node_wrapper/node_wrapper.opam", "" + ] + +let patches = + [ ( "sexp_grammar" + , {| +diff --git a/sexp_grammar_validation.opam b/sexp_grammar_validation.opam +new file mode 100644 +index 0000000..e69de29 +diff --git a/validation/src/dune b/validation/src/dune +index 91933ec..849e4d7 100644 +--- a/validation/src/dune ++++ b/validation/src/dune +@@ -1,5 +1,6 @@ + (library + (name sexp_grammar_validation) ++ (public_name sexp_grammar_validation) + (libraries bignum.bigint core + expect_test_helpers_core.expect_test_helpers_base sexp_grammar) + (preprocess +|} + ) + ; ( "bignum" + , {bignum| +diff --git a/test/src/dune b/test/src/dune +index f93ae3f..3f00557 100644 +--- a/test/src/dune ++++ b/test/src/dune +@@ -2,5 +2,6 @@ + (name bignum_test) + (libraries bigint bignum core expect_test_helpers_core expectable + sexp_grammar_validation zarith) ++ (inline_tests (flags -drop-tag no-js -drop-tag no-wasm -drop-tag 64-bits-only) (modes js wasm)) + (preprocess + (pps ppx_jane))) +diff --git a/test/src/test_bignum.ml b/test/src/test_bignum.ml +index c6d09fb..61b1e5b 100644 +--- a/test/src/test_bignum.ml ++++ b/test/src/test_bignum.ml +@@ -3,6 +3,11 @@ open! Expect_test_helpers_core + open Bignum + open Bignum.For_testing + ++module Zarith = struct ++ module Q = Q ++ module Z = Z ++end ++ + let%expect_test "Bignum.abs" = + let test t = + let t' = require_no_allocation (fun () -> abs t) in +|bignum} + ) + ; ( "bin_prot" + , {bp| +diff --git a/test/dune b/test/dune +index 5a53c69..571e52e 100644 +--- a/test/dune ++++ b/test/dune +@@ -1,15 +1,8 @@ + (library + (name bin_prot_test) + (libraries base base_bigstring bin_prot +- expect_test_helpers_core.expect_test_helpers_base expect_test_patterns ++ expect_test_helpers_core.expect_test_helpers_base ; expect_test_patterns + float_array base.md5 re sexplib splittable_random stdio) ++ (inline_tests (flags -drop-tag no-js -drop-tag 64-bits-only -drop-tag 32-bits-only -drop-tag no-wasm) (modes js wasm)) + (preprocess + (pps ppx_jane))) +- +-(rule +- (deps core/blob_stability_tests.ml integers_repr_tests_64bit.ml +- integers_repr_tests_js.ml integers_repr_tests_wasm.ml) +- (action +- (bash +- "diff <(\necho '869e6b3143f14201f406eac9c05c4cdb core/blob_stability_tests.ml'\necho 'a9ed028fa16f307982c196f647d05afa integers_repr_tests_64bit.ml'\necho 'a17ffcd3bf1e15dbca0ee54ec5b95c58 integers_repr_tests_js.ml'\necho 'e747bd85320575c771fc62a0d3085d29 integers_repr_tests_wasm.ml'\n ) <(md5sum %{deps})")) +- (alias runtest)) +diff --git a/test/non_integers_repr.ml b/test/non_integers_repr.ml +index cbb9bd5..b5b5a03 100644 +--- a/test/non_integers_repr.ml ++++ b/test/non_integers_repr.ml +@@ -811,11 +811,12 @@ let%expect_test "Non-integer bin_prot size tests" = + 00 00 00 00 00 00 00 00 -> 0 + |}]; + gen_tests Tests.float_nan; ++ [%expect ++ {| 7f f8 00 00 00 00 00 01 -> NAN |}]; ++(* + Expect_test_patterns.require_match + [%here] +- {| +- 7f f{8,0} 00 00 00 00 00 01 -> NAN (glob) +- |}; ++*) + gen_tests Tests.vec; + [%expect + {| + |bp} + ) + ; ( "base_bigstring" + , {| +diff --git a/test/dune b/test/dune +index 8d23f86..21e83ba 100644 +--- a/test/dune ++++ b/test/dune +@@ -2,5 +2,6 @@ + (name base_bigstring_test) + (libraries base_bigstring core.base_for_tests core expect_test_helpers_core + stdio) ++ (inline_tests (flags -drop-tag no-js -drop-tag 64-bits-only -drop-tag no-wasm) (modes js wasm)) + (preprocess + (pps ppx_jane))) +|} + ) + ; ( "string_dict" + , {| +diff --git a/test/dune b/test/dune +index b145cb3..e5fc412 100644 +--- a/test/dune ++++ b/test/dune +@@ -1,5 +1,6 @@ + (library + (name string_dict_test) + (libraries base core expect_test_helpers_core string_dict) ++ (inline_tests (flags -drop-tag no-js -drop-tag 64-bits-only -drop-tag no-wasm) (modes js wasm)) + (preprocess + (pps ppx_jane))) +|} + ) + ; ( "zarith_stubs_js" + , {zs| +diff --git a/test/bitwise.ml b/test/bitwise.ml +index 5fd0ddc..4833923 100644 +--- a/test/bitwise.ml ++++ b/test/bitwise.ml +@@ -86,7 +86,7 @@ module Ml_z_popcount = struct + Static.quickcheck ~f:(fun x -> [%message (x : t) (popcount x : int)]) (); + (* Compression rate is low because our quickcheck implementation generates + integers with a bounded bitcount. *) +- [%expect {| ((hash 1e429706c701b111d98b6e6e858bbea4) (uniqueness_rate 42.96875)) |}] ++ [%expect {| ((hash d937e61f530ab9c27544e392922d286d) (uniqueness_rate 42.96875)) |}] + ;; + end + +@@ -102,7 +102,7 @@ module Ml_z_hamdist = struct + (); + (* Compression rate is low because our quickcheck implementation generates + integers with a bounded bitcount. *) +- [%expect {| ((hash 0a270232628736ee7d47c8b403250989) (uniqueness_rate 33.284457)) |}] ++ [%expect {| ((hash 0d36530b39292e2c31f13d10ec004a38) (uniqueness_rate 33.284457)) |}] + ;; + end + +diff --git a/test/dune b/test/dune +index 7996514..d0b463a 100644 +--- a/test/dune ++++ b/test/dune +@@ -1,7 +1,9 @@ + (library + (name zarith_stubs_js_test) +- (libraries zarith core base.md5 zarith_stubs_js) ++ (libraries zarith_wrapper core base.md5 zarith_stubs_js) + (flags :standard -w -60) ++ (inline_tests (flags -drop-tag no-js -drop-tag 64-bits-only -drop-tag no-wasm) (modes js wasm)) ++ (modules (:standard \ zarith)) + (preprocess + (pps ppx_jane))) + +@@ -35,10 +37,16 @@ + (deps implemented_externals.txt tested_externals.txt) + (action + (bash "diff %{deps}")) +- (alias runtest)) ++ (alias runtest-)) + + (rule + (deps implemented_externals.txt zarith_externals.txt) + (action + (bash "diff %{deps}")) +- (alias runtest)) ++ (alias runtest-)) ++ ++(subdir zarith ++ (copy_files (files ../zarith.ml)) ++ (library (name zarith_wrapper) ++ (wrapped false) ++ (libraries zarith))) +diff --git a/test/zarith.ml b/test/zarith.ml +index 059d011..b40264e 100644 +--- a/test/zarith.ml ++++ b/test/zarith.ml +@@ -1,5 +1,4 @@ + module Big_int_Z = Big_int_Z + module Q = Q + module Z = Z +-module Zarith = Zarith + module Zarith_version = Zarith_version +|zs} + ) + ] + +let removes = + [ "core/core/test/test_sys.ml" + ; "core/core/test/test_sys.mli" + ; "core/core/test/test_timezone.ml" + ; "core/core/test/test_timezone.mli" + ] +(****) + +let read_opam_file filename = + OpamPp.parse + OpamPp.Op.(OpamFormat.I.file -| OpamPp.map_snd OpamFile.OPAM.pp_raw_fields) + ~pos:{ filename; start = 0, 0; stop = 0, 0 } + (OpamParser.FullPos.file (Filename.concat (Filename.concat repo filename) "opam")) + +let dependencies (_, { OpamFile.OPAM.depends; _ }) = + let open OpamFormula in + depends + |> map (fun (nm, _) -> Atom (nm, None)) + |> of_atom_formula + |> atoms + |> List.map fst + |> List.map OpamPackage.Name.to_string + +let is_jane_street_package (_, (_, opam)) = + let url = OpamUrl.to_string (Option.get (OpamFile.OPAM.get_url opam)) in + String.starts_with ~prefix:"https://github.com/janestreet/" url + +let packages = + repo + |> Sys.readdir + |> Array.to_list + |> List.map (fun s -> + if String.contains s '.' + then String.sub s 0 (String.index s '.'), read_opam_file s + else + ( s + , read_opam_file + (Filename.concat + s + (List.find + (fun f -> String.starts_with ~prefix:s f) + (Array.to_list (Sys.readdir (Filename.concat repo s))))) )) + |> List.filter is_jane_street_package + +let rec traverse visited p = + if StringSet.mem p visited + then visited + else + let visited = StringSet.add p visited in + match List.assoc p packages with + | exception Not_found -> visited + | opam -> + let l = dependencies opam in + List.fold_left traverse visited l + +let is_forked p = StringSet.mem p forked_packages + +let exec_async cmd = + let p = Unix.open_process_out cmd in + fun () -> ignore (Unix.close_process_out p) + +let ( let* ) (f : unit -> 'a) (g : 'a -> unit -> 'b) : unit -> 'b = fun () -> g (f ()) () + +let sync_exec f l = + let l = List.map f l in + List.iter (fun f -> f ()) l + +let pin nm = + exec_async + (Printf.sprintf + "opam pin add -n %s https://github.com/ocaml-wasm/%s.git#wasm-oxcaml" + nm + nm) + +let pin_packages () = sync_exec pin (StringSet.elements do_pin) + +let install_others others = + let others = + StringSet.elements + (StringSet.union (StringSet.diff others omitted_others) additional_others) + in + ignore (Sys.command ("opam install -y " ^ String.concat " " others)) + +let clone ?branch ?(depth = 1) nm src = + exec_async + (Printf.sprintf + "git clone -q --depth %d %s%s %s/lib/%s" + depth + (match branch with + | None -> "" + | Some b -> Printf.sprintf "-b %s " b) + src + jane_root + nm) + +let clone' ?branch ?commit nm src = + match commit with + | None -> clone ?branch nm src + | Some commit -> + let* () = clone ?branch ~depth:100 nm src in + exec_async + (Printf.sprintf "cd %s/lib/%s && git checkout -b wasm %s" jane_root nm commit) + +let () = + let write f contents = + Out_channel.(with_open_bin f @@ fun ch -> output_string ch contents) + in + let copy f f' = + let contents = In_channel.(with_open_bin f @@ input_all) in + Out_channel.(with_open_bin f' @@ fun ch -> output_string ch contents) + in + write (Filename.concat jane_root "dune-workspace") dune_workspace; + Unix.mkdir (Filename.concat jane_root "node_wrapper") 0o755; + List.iter + (fun (f, contents) -> write (Filename.concat jane_root f) contents) + node_wrapper; + copy + (Filename.concat wasmoo_root "tools/node_wrapper.ml") + (Filename.concat jane_root "node_wrapper/node_wrapper.ml") + +let () = + let js, others = + List.fold_left traverse StringSet.empty roots + |> StringSet.partition (fun p -> List.mem_assoc p packages) + in + pin_packages (); + install_others others; + sync_exec (fun () -> clone "ocaml-uri" "https://github.com/mirage/ocaml-uri") [ () ]; + sync_exec (fun () -> exec_async "opam install uri --deps-only") [ () ]; + sync_exec + (fun nm -> + let branch = if is_forked nm then Some "wasm-oxcaml" else Some "with-extensions" in + let commit = + if is_forked nm + then None + else + Some + (let _, opam = List.assoc nm packages in + let url = OpamUrl.to_string (Option.get (OpamFile.OPAM.get_url opam)) in + let tar_file = Filename.basename url in + String.sub tar_file 0 (String.index tar_file '.')) + in + clone' + ?branch + ?commit + nm + (Printf.sprintf + "https://github.com/%s/%s" + (if is_forked nm then "ocaml-wasm" else "janestreet") + nm)) + (StringSet.elements (StringSet.diff js omitted_js)) + +let () = + List.iter + (fun (dir, patch) -> + let p = if Sys.win32 then "patch --binary" else "patch" in + let ch = + Unix.open_process_out + (Printf.sprintf "cd %s/lib/%s && %s -p 1 --" jane_root dir p) + in + let patch = + if Sys.win32 + then String.concat "\r\n" (String.split_on_char '\n' patch) + else patch + in + output_string ch patch; + match Unix.close_process_out ch with + | WEXITED 0 -> () + | e -> + let name, i = + match e with + | WEXITED n -> "exit", n + | WSIGNALED n -> "signal", n + | WSTOPPED n -> "stop", n + in + failwith (Printf.sprintf "%s %d while patching %s" name i dir)) + patches; + List.iter (fun p -> Sys.remove (Printf.sprintf "%s/lib/%s" jane_root p)) removes diff --git a/tools/dune b/tools/dune index 5953c6bc08..0fdd9bee07 100644 --- a/tools/dune +++ b/tools/dune @@ -8,6 +8,19 @@ (modules ci_setup) (libraries opam-format unix)) +(rule + (target ci_setup.ml) + (enabled_if + (not %{oxcaml_supported})) + (action + (copy ci_setup-generic.ml %{target}))) + +(rule + (target ci_setup.ml) + (enabled_if %{oxcaml_supported}) + (action + (copy ci_setup-oxcaml.ml %{target}))) + (executable (name sync_testsuite) (modules sync_testsuite) diff --git a/tools/toplevel_expect/gen.ml b/tools/toplevel_expect/gen.ml index 7bc9db25be..60d82092a3 100644 --- a/tools/toplevel_expect/gen.ml +++ b/tools/toplevel_expect/gen.ml @@ -30,29 +30,15 @@ let dump_file file = in loop () -let split_on_char sep s = - let r = ref [] in - let j = ref (String.length s) in - for i = String.length s - 1 downto 0 do - if String.unsafe_get s i = sep - then ( - r := String.sub s (i + 1) (!j - i - 1) :: !r; - j := i) - done; - String.sub s 0 !j :: !r - let () = - let version = Sys.ocaml_version in - let maj, min = - match split_on_char '.' version with - | maj :: min :: _ -> int_of_string maj, int_of_string min - | _ -> assert false - in - match maj, min with - | 4, min -> - assert (min >= 11); - dump_file "toplevel_expect_test.ml-4.11" - | 5, 0 | 5, 1 | 5, 2 -> dump_file "toplevel_expect_test.ml-4.11" - | 5, 3 -> dump_file "toplevel_expect_test.ml-5.3" - | 5, 4 -> dump_file "toplevel_expect_test.ml-5.4" - | _ -> failwith ("unsupported version " ^ Sys.ocaml_version) + match Sys.ocaml_release with + | { extra = Some (Plus, "ox"); _ } -> dump_file "toplevel_expect_test.ml-oxcaml" + | { major; minor; _ } -> ( + match major, minor with + | 4, min -> + assert (min >= 11); + dump_file "toplevel_expect_test.ml-4.11" + | 5, 0 | 5, 1 | 5, 2 -> dump_file "toplevel_expect_test.ml-4.11" + | 5, 3 -> dump_file "toplevel_expect_test.ml-5.3" + | 5, 4 -> dump_file "toplevel_expect_test.ml-5.4" + | _ -> failwith ("unsupported version " ^ Sys.ocaml_version)) diff --git a/tools/toplevel_expect/toplevel_expect_test.ml-oxcaml b/tools/toplevel_expect/toplevel_expect_test.ml-oxcaml new file mode 100644 index 0000000000..5e2f5ddd7c --- /dev/null +++ b/tools/toplevel_expect/toplevel_expect_test.ml-oxcaml @@ -0,0 +1,388 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Jeremie Dimino, Jane Street Europe *) +(* *) +(* Copyright 2016 Jane Street Group LLC *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Execute a list of phrases from a .ml file and compare the result to the + expected output, written inside [%%expect ...] nodes. At the end, create + a .corrected file containing the corrected expectations. The test is + successful if there is no differences between the two files. + + An [%%expect] node always contains both the expected outcome with and + without -principal. When the two differ the expectation is written as + follows: + + {[ + [%%expect {| + output without -principal + |}, Principal{| + output with -principal + |}] + ]} +*) + +[@@@ocaml.warning "-40"] + +open StdLabels + +(* representation of: {tag|str|tag} *) +type string_constant = + { str : string + ; tag : string + } + +type expectation = + { extid_loc : Location.t (* Location of "expect" in "[%%expect ...]" *) + ; payload_loc : Location.t (* Location of the whole payload *) + ; normal : string_constant (* expectation without -principal *) + ; principal : string_constant (* expectation with -principal *) + } + +(* A list of phrases with the expected toplevel output *) +type chunk = + { phrases : Parsetree.toplevel_phrase list + ; expectation : expectation + } + +type correction = + { corrected_expectations : expectation list + ; trailing_output : string + } + +let match_expect_extension (ext : Parsetree.extension) = + match ext with + | ({Asttypes.txt="expect"|"ocaml.expect"; loc = extid_loc}, payload) -> + let invalid_payload () = + Location.raise_errorf ~loc:extid_loc + "invalid [%%%%expect payload]" + in + let string_constant (e : Parsetree.expression) = + match e.pexp_desc with + | Pexp_constant (Pconst_string (str, _, Some tag)) -> + { str; tag } + | _ -> invalid_payload () + in + let expectation = + match payload with + | PStr [{ pstr_desc = Pstr_eval (e, []); _ }] -> + let normal, principal = + match e.pexp_desc with + | Pexp_tuple + [ None, a + ; None, { pexp_desc = Pexp_construct + ({ txt = Lident "Principal"; _ }, Some b); _ } + ] -> + (string_constant a, string_constant b) + | _ -> let s = string_constant e in (s, s) + in + { extid_loc + ; payload_loc = e.pexp_loc + ; normal + ; principal + } + | PStr [] -> + let s = { tag = ""; str = "" } in + { extid_loc + ; payload_loc = { extid_loc with loc_start = extid_loc.loc_end } + ; normal = s + ; principal = s + } + | _ -> invalid_payload () + in + Some expectation + | _ -> + None + +(* Split a list of phrases from a .ml file *) +let split_chunks phrases = + let rec loop (phrases : Parsetree.toplevel_phrase list) code_acc acc = + match phrases with + | [] -> + if code_acc = [] then + (List.rev acc, None) + else + (List.rev acc, Some (List.rev code_acc)) + | phrase :: phrases -> + match phrase with + | Ptop_def [] -> loop phrases code_acc acc + | Ptop_def [{pstr_desc = Pstr_extension(ext, []); _}] -> begin + match match_expect_extension ext with + | None -> loop phrases (phrase :: code_acc) acc + | Some expectation -> + let chunk = + { phrases = List.rev code_acc + ; expectation + } + in + loop phrases [] (chunk :: acc) + end + | _ -> loop phrases (phrase :: code_acc) acc + in + loop phrases [] [] + +module Compiler_messages = struct + let print_loc ppf (loc : Location.t) = + let startchar = loc.loc_start.pos_cnum - loc.loc_start.pos_bol in + let endchar = loc.loc_end.pos_cnum - loc.loc_start.pos_cnum + startchar in + Format.fprintf ppf "Line _"; + if startchar >= 0 then + Format.fprintf ppf ", characters %d-%d" startchar endchar; + Format.fprintf ppf ":@." + + let () = + let default = !Location.report_printer () in + Location.report_printer := (fun _ -> + { default with + Location.pp_main_loc = (fun _ _ fmt loc -> print_loc fmt loc); + Location.pp_submsg_loc = (fun _ _ fmt loc -> print_loc fmt loc); + }) + + let capture ppf ~f = + Misc.protect_refs + [ R (Location.formatter_for_warnings , ppf ) + ] + f +end + +let collect_formatters buf pps ~f = + List.iter ~f:(fun pp -> Format.pp_print_flush pp ()) pps; + let save = + List.map ~f:(fun pp -> Format.pp_get_formatter_out_functions pp ()) pps + in + let restore () = + List.iter2 + ~f:(fun pp out_functions -> + Format.pp_print_flush pp (); + Format.pp_set_formatter_out_functions pp out_functions) + pps save + in + let out_string str ofs len = Buffer.add_substring buf str ofs len + and out_flush = ignore + and out_newline () = Buffer.add_char buf '\n' + and out_spaces n = for _i = 1 to n do Buffer.add_char buf ' ' done + and out_indent n = for _i = 1 to n do Buffer.add_char buf ' ' done in + let out_functions = + { Format.out_string; out_flush; out_newline; out_spaces; out_indent } + in + List.iter + ~f:(fun pp -> Format.pp_set_formatter_out_functions pp out_functions) + pps; + match f () with + | x -> restore (); x + | exception exn -> restore (); raise exn + +(* Invariant: ppf = Format.formatter_of_buffer buf *) +let capture_everything buf ppf ~f = + collect_formatters buf [Format.std_formatter; Format.err_formatter] + ~f:(fun () -> Compiler_messages.capture ppf ~f) + +let exec_phrase ppf phrase = + if !Clflags.dump_parsetree then Printast. top_phrase ppf phrase; + if !Clflags.dump_source then Pprintast.top_phrase ppf phrase; + Toploop.execute_phrase true ppf phrase + +let parse_contents ~fname contents = + let lexbuf = Lexing.from_string contents in + Location.init lexbuf fname; + Location.input_name := fname; + Parse.use_file lexbuf + +let eval_expectation expectation ~output = + let s = + if !Clflags.principal then + expectation.principal + else + expectation.normal + in + if s.str = output then + None + else + let trimmed = String.trim output in + let normalized = if String.exists ~f:(function '\n' -> true | _ -> false) output + then "\n" ^ trimmed ^ "\n" + else trimmed + in + let s = { s with str = normalized } in + Some ( + if !Clflags.principal then + { expectation with principal = s } + else + { expectation with normal = s } + ) + +let preprocess_structure mappers str = + let open Ast_mapper in + List.fold_right + ~f:(fun ppx_rewriter str -> + let mapper : Ast_mapper.mapper = ppx_rewriter [] in + mapper.structure mapper str) + mappers + ~init:str + +let preprocess_phrase mappers phrase = + let open Parsetree in + match phrase with + | Ptop_def str -> Ptop_def (preprocess_structure mappers str) + | Ptop_dir _ as x -> x + + +let shift_lines delta = + let position (pos : Lexing.position) = + { pos with pos_lnum = pos.pos_lnum + delta } + in + let location _this (loc : Location.t) = + { loc with + loc_start = position loc.loc_start + ; loc_end = position loc.loc_end + } + in + fun _ -> { Ast_mapper.default_mapper with location } + +let rec min_line_number : Parsetree.toplevel_phrase list -> int option = +function + | [] -> None + | (Ptop_dir _ | Ptop_def []) :: l -> min_line_number l + | Ptop_def (st :: _) :: _ -> Some st.pstr_loc.loc_start.pos_lnum + +let eval_expect_file mapper fname ~file_contents = + Warnings.reset_fatal (); + let chunks, trailing_code = + parse_contents ~fname:fname file_contents |> split_chunks + in + let buf = Buffer.create 1024 in + let ppf = Format.formatter_of_buffer buf in + let out_fun = Format.pp_get_formatter_out_functions ppf () in + Format.pp_set_formatter_out_functions Format.std_formatter out_fun; + + let exec_phrases phrases = + + let mappers = + match min_line_number phrases with + | None -> [] + | Some lnum -> [shift_lines (1 - lnum)] + in + let mappers = mapper :: mappers in + let phrases = List.map ~f:(preprocess_phrase mappers) phrases in + + (* For formatting purposes *) + Buffer.add_char buf '\n'; + let _ : bool = + List.fold_left phrases ~init:true ~f:(fun acc phrase -> + acc && + try + Location.reset (); + exec_phrase ppf phrase + with exn -> + Location.report_exception ppf exn; + false) + in + Format.pp_print_flush ppf (); + let len = Buffer.length buf in + if len > 0 && Buffer.nth buf (len - 1) <> '\n' then + (* For formatting purposes *) + Buffer.add_char buf '\n'; + let s = Buffer.contents buf in + Buffer.clear buf; + Misc.delete_eol_spaces s + in + let corrected_expectations = + capture_everything buf ppf ~f:(fun () -> + List.fold_left chunks ~init:[] ~f:(fun acc chunk -> + let output = exec_phrases chunk.phrases in + match eval_expectation chunk.expectation ~output with + | None -> acc + | Some correction -> correction :: acc) + |> List.rev) + in + let trailing_output = + match trailing_code with + | None -> "" + | Some phrases -> + capture_everything buf ppf ~f:(fun () -> exec_phrases phrases) + in + { corrected_expectations; trailing_output } + +let output_slice oc s a b = + output_string oc (String.sub s ~pos:a ~len:(b - a)) + +let output_corrected oc ~file_contents correction = + let output_body oc { str; tag } = + Printf.fprintf oc "{%s|%s|%s}" tag str tag + in + let ofs = + List.fold_left correction.corrected_expectations ~init:0 + ~f:(fun ofs c -> + output_slice oc file_contents ofs c.payload_loc.loc_start.pos_cnum; + output_body oc c.normal; + if !Clflags.principal && c.normal.str <> c.principal.str then begin + output_string oc ", Principal"; + output_body oc c.principal + end; + c.payload_loc.loc_end.pos_cnum) + in + output_slice oc file_contents ofs (String.length file_contents); + match correction.trailing_output with + | "" -> () + | s -> Printf.fprintf oc "\n[%%%%expect{|%s|}]\n" s + +let write_corrected ~file ~file_contents correction = + let oc = open_out file in + output_corrected oc ~file_contents correction; + close_out oc + +let process_expect_file mapper fname = + let corrected_fname = fname ^ ".corrected" in + let file_contents = + let ic = open_in_bin fname in + match really_input_string ic (in_channel_length ic) with + | s -> close_in ic; Misc.normalise_eol s + | exception e -> close_in ic; raise e + in + let correction = eval_expect_file mapper fname ~file_contents in + write_corrected ~file:corrected_fname ~file_contents correction + +let repo_root = ref "" + +let main mapper fname = + Toploop.override_sys_argv + (Array.sub Sys.argv ~pos:!Arg.current + ~len:(Array.length Sys.argv - !Arg.current)); + (* Ignore OCAMLRUNPARAM=b to be reproducible *) + Printexc.record_backtrace false; + List.iter [ "stdlib" ] ~f:(fun s -> + Topdirs.dir_directory (Filename.concat !repo_root s)); + Toploop.initialize_toplevel_env (); + Sys.interactive := false; + process_expect_file mapper fname; + exit 0 + +let args = + Arg.align + [ "-repo-root", Set_string repo_root, + "