Skip to content

Commit 4b6c1fa

Browse files
xclerchhugo
andauthored
Avoid polymorphic comparison over float values (#1048)
* Add a failing test. * Move `constant_equal` to `Code`. * Use `Code.constant_equal` instead of polymorphic equality in join. * Do not use polymorphic equality over `Code.constant` values. * Add changelog entry. * Do not use `Int64.equal` (not available in 4.02). * Do not use `Array.iter2` (not available in 4.0{2,3,4}). * Do not use `Int64.equal` (not available in 4.02). * Refmt * refactor Co-authored-by: Hugo Heuzard <[email protected]>
1 parent 7b4cbe2 commit 4b6c1fa

File tree

7 files changed

+87
-39
lines changed

7 files changed

+87
-39
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
when parsing constant in the from the bytecode
1313
* Compiler: make sure inline doesn't loop indefinitly (#1043)
1414
* Compiler: fix bug generating invalid javascript for if-then construct (#1046)
15+
* Compiler: do not use polymorphic comparison when joining float values (#1048)
1516
* Lib: Rename msg to message in Worker (#1037)
1617
* Lib: fix graphics_js when build with separate compilation (#1029)
1718

compiler/lib/code.ml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,43 @@ type constant =
266266
| Tuple of int * constant array * array_or_not
267267
| Int of int32
268268

269+
let rec constant_equal a b =
270+
match a, b with
271+
| String a, String b -> Some (String.equal a b)
272+
| IString a, IString b -> Some (String.equal a b)
273+
| Tuple (ta, a, _), Tuple (tb, b, _) ->
274+
if ta <> tb || Array.length a <> Array.length b
275+
then Some false
276+
else
277+
let same = ref (Some true) in
278+
for i = 0 to Array.length a - 1 do
279+
match !same, constant_equal a.(i) b.(i) with
280+
| None, _ -> ()
281+
| _, None -> same := None
282+
| Some s, Some c -> same := Some (s && c)
283+
done;
284+
!same
285+
| Int64 a, Int64 b -> Some (Int64.equal a b)
286+
| Float_array a, Float_array b -> Some (Array.equal Float.equal a b)
287+
| Int a, Int b -> Some (Int32.equal a b)
288+
| Float a, Float b -> Some (Float.equal a b)
289+
| String _, IString _ | IString _, String _ -> None
290+
| Int _, Float _ | Float _, Int _ -> None
291+
| Tuple ((0 | 254), _, _), Float_array _ -> None
292+
| Float_array _, Tuple ((0 | 254), _, _) -> None
293+
| Tuple _, (String _ | IString _ | Int64 _ | Int _ | Float _ | Float_array _) ->
294+
Some false
295+
| Float_array _, (String _ | IString _ | Int64 _ | Int _ | Float _ | Tuple _) ->
296+
Some false
297+
| String _, (Int64 _ | Int _ | Float _ | Tuple _ | Float_array _) -> Some false
298+
| IString _, (Int64 _ | Int _ | Float _ | Tuple _ | Float_array _) -> Some false
299+
| Int64 _, (String _ | IString _ | Int _ | Float _ | Tuple _ | Float_array _) ->
300+
Some false
301+
| Float _, (String _ | IString _ | Float_array _ | Int64 _ | Tuple (_, _, _)) ->
302+
Some false
303+
| Int _, (String _ | IString _ | Float_array _ | Int64 _ | Tuple (_, _, _)) ->
304+
Some false
305+
269306
type prim_arg =
270307
| Pv of Var.t
271308
| Pc of constant

compiler/lib/code.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ type constant =
149149
| Tuple of int * constant array * array_or_not
150150
| Int of int32
151151

152+
val constant_equal : constant -> constant -> bool option
153+
152154
type prim_arg =
153155
| Pv of Var.t
154156
| Pc of constant

compiler/lib/eval.ml

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -191,43 +191,6 @@ let is_int info x =
191191
| Pc (Int _) -> Y
192192
| Pc _ -> N
193193

194-
let rec constant_equal a b =
195-
match a, b with
196-
| String a, String b -> Some (String.equal a b)
197-
| IString a, IString b -> Some (String.equal a b)
198-
| Tuple (ta, a, _), Tuple (tb, b, _) ->
199-
if ta <> tb || Array.length a <> Array.length b
200-
then Some false
201-
else
202-
let same = ref (Some true) in
203-
for i = 0 to Array.length a - 1 do
204-
match !same, constant_equal a.(i) b.(i) with
205-
| None, _ -> ()
206-
| _, None -> same := None
207-
| Some s, Some c -> same := Some (s && c)
208-
done;
209-
!same
210-
| Int64 a, Int64 b -> Some (Poly.equal a b)
211-
| Float_array a, Float_array b -> Some Poly.(a = b)
212-
| Int a, Int b -> Some (Poly.equal a b)
213-
| Float a, Float b -> Some (Float.equal a b)
214-
| String _, IString _ | IString _, String _ -> None
215-
| Int _, Float _ | Float _, Int _ -> None
216-
| Tuple ((0 | 254), _, _), Float_array _ -> None
217-
| Float_array _, Tuple ((0 | 254), _, _) -> None
218-
| Tuple _, (String _ | IString _ | Int64 _ | Int _ | Float _ | Float_array _) ->
219-
Some false
220-
| Float_array _, (String _ | IString _ | Int64 _ | Int _ | Float _ | Tuple _) ->
221-
Some false
222-
| String _, (Int64 _ | Int _ | Float _ | Tuple _ | Float_array _) -> Some false
223-
| IString _, (Int64 _ | Int _ | Float _ | Tuple _ | Float_array _) -> Some false
224-
| Int64 _, (String _ | IString _ | Int _ | Float _ | Tuple _ | Float_array _) ->
225-
Some false
226-
| Float _, (String _ | IString _ | Float_array _ | Int64 _ | Tuple (_, _, _)) ->
227-
Some false
228-
| Int _, (String _ | IString _ | Float_array _ | Int64 _ | Tuple (_, _, _)) ->
229-
Some false
230-
231194
let eval_instr info i =
232195
match i with
233196
| Let (x, Prim (Extern ("caml_js_equals" | "caml_equal"), [ y; z ])) -> (

compiler/lib/flow.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ let the_const_of info x =
330330
None
331331
(fun u v ->
332332
match u, v with
333-
| Some i, Some j when Poly.(i = j) -> u
333+
| Some i, Some j when Poly.(Code.constant_equal i j = Some true) -> u
334334
| _ -> None)
335335
x
336336
| Pc c -> Some c

compiler/lib/stdlib.ml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,10 +239,17 @@ module Option = struct
239239
| Some s -> s
240240
end
241241

242+
module Int64 = struct
243+
include Int64
244+
245+
let equal (a : int64) (b : int64) = Poly.( = ) a b
246+
end
247+
242248
module Float = struct
243249
type t = float
244250

245-
let equal (a : float) (b : float) = Poly.compare a b = 0
251+
let equal (a : float) (b : float) =
252+
Int64.equal (Int64.bits_of_float a) (Int64.bits_of_float b)
246253

247254
(* Re-defined here to stay compatible with OCaml 4.02 *)
248255
external classify_float : float -> fpclass = "caml_classify_float"
@@ -564,6 +571,17 @@ module Array = struct
564571
r := f i (Array.unsafe_get a i) !r
565572
done;
566573
!r
574+
575+
let equal eq a b =
576+
let len_a = Array.length a in
577+
if len_a <> Array.length b
578+
then false
579+
else
580+
let i = ref 0 in
581+
while !i < len_a && eq a.(!i) b.(!i) do
582+
incr i
583+
done;
584+
!i = len_a
567585
end
568586

569587
module Filename = struct

compiler/tests-jsoo/test_floats.ml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
(* Js_of_ocaml compiler
2+
* http://www.ocsigen.org/js_of_ocaml/
3+
* Copyright (C) 2019 Hugo Heuzard
4+
*
5+
* This program is free software; you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as published by
7+
* the Free Software Foundation, with linking exception;
8+
* either version 2.1 of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18+
*)
19+
20+
let%expect_test _ =
21+
(* copied from https://github.com/ocaml/ocaml/pull/1794 *)
22+
let z =
23+
let x = -0. and y = 0. in
24+
if mod_float x 1. >= 0. then x else if false then x else y
25+
in
26+
Printf.printf "%g\n" (1. /. z);
27+
[%expect {|-inf|}]

0 commit comments

Comments
 (0)