Skip to content

Commit 48060f3

Browse files
authored
Merge pull request #1200 from bloomberg/polymorphic_comparison_and_equal_fix
fix #1195
2 parents 644adea + 90dcf52 commit 48060f3

File tree

4 files changed

+656
-242
lines changed

4 files changed

+656
-242
lines changed

jscomp/runtime/caml_obj.ml

Lines changed: 99 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
6666
{[
6767
var u = caml_obj_dup (x)
68-
var new_record = u.slice ()
68+
var new_record = u.slice ()
6969
7070
]}
7171
*)
@@ -99,19 +99,19 @@ let caml_obj_truncate (x : Obj.t) (new_size : int) =
9999
let caml_lazy_make_forward x = lazy x
100100

101101
(**
102-
For the empty dummy object, whether it's
103-
`[]` or `{}` depends on how
104-
runtime encoding works, and will affect
105-
js polymorphic comparison(Js.(=)) (fine with caml polymoprhic comparison (Pervasives.equal))
106-
In most cases, rec value comes from record/modules,
107-
whose tag is 0, we optimize that case
108-
*)
102+
For the empty dummy object, whether it's
103+
`[]` or `{}` depends on how
104+
runtime encoding works, and will affect
105+
js polymorphic comparison(Js.(=)) (fine with caml polymoprhic comparison (Pervasives.equal))
106+
In most cases, rec value comes from record/modules,
107+
whose tag is 0, we optimize that case
108+
*)
109109
let caml_update_dummy x y =
110110
(* let len = Bs_obj.length y in
111-
for i = 0 to len - 1 do
112-
Array.unsafe_set x i (Obj.field y i)
113-
done;
114-
Obj.set_tag (Obj.magic x) (Obj.tag y)
111+
for i = 0 to len - 1 do
112+
Array.unsafe_set x i (Obj.field y i)
113+
done;
114+
Obj.set_tag (Obj.magic x) (Obj.tag y)
115115
*)
116116
let len = Bs_obj.length y in
117117
for i = 0 to len - 1 do
@@ -120,10 +120,10 @@ let caml_update_dummy x y =
120120
let y_tag = Obj.tag y in
121121
if y_tag <> 0 then
122122
Obj.set_tag x y_tag
123-
124-
(* Bs_obj.set_length x (Bs_obj.length y) *)
125-
(* [set_length] seems redundant here given that it is initialized as an array
126-
*)
123+
124+
(* Bs_obj.set_length x (Bs_obj.length y) *)
125+
(* [set_length] seems redundant here given that it is initialized as an array
126+
*)
127127
let caml_int_compare (x : int) (y: int) : int =
128128
if x < y then -1 else if x = y then 0 else 1
129129

@@ -153,45 +153,54 @@ let unsafe_js_compare x y =
153153
*)
154154
let rec caml_compare (a : Obj.t) (b : Obj.t) : int =
155155
(*front and formoest, we do not compare function values*)
156-
if Js.typeof a = "string" then
156+
let a_type = Js.typeof a in
157+
let b_type = Js.typeof b in
158+
if a_type = "string" then
157159
caml_string_compare (Obj.magic a) (Obj.magic b )
158-
else if Js.typeof a = "number" then
159-
caml_int_compare (Obj.magic a) (Obj.magic b )
160-
else if Js.typeof a = "boolean"
161-
|| Js.typeof a = "null"
162-
|| Js.typeof a = "undefined"
163-
then
164-
unsafe_js_compare a b
165-
else if Js.typeof a = "function" || Js.typeof b = "function"
166-
then raise (Invalid_argument "compare: functional value")
167-
else
168-
(* if js_is_instance_array a then *)
169-
(* 0 *)
170-
(* else *)
171-
let tag_a = Bs_obj.tag a in
172-
let tag_b = Bs_obj.tag b in
173-
(* double_array_tag: 254
174-
forward_tag:250
175-
*)
176-
if tag_a = 250 then
177-
caml_compare (Obj.field a 0) b
178-
else if tag_b = 250 then
179-
caml_compare a (Obj.field b 0)
180-
else if tag_a = 248 (* object/exception *) then
181-
caml_int_compare (Obj.magic @@ Obj.field a 1) (Obj.magic @@ Obj.field b 1 )
182-
else if tag_a = 251 (* abstract_tag *) then
183-
raise (Invalid_argument "equal: abstract value")
184-
else if tag_a <> tag_b then
185-
if tag_a < tag_b then (-1) else 1
186-
else
187-
let len_a = Bs_obj.length a in
188-
let len_b = Bs_obj.length b in
189-
if len_a = len_b then
190-
aux_same_length a b 0 len_a
191-
else if len_a < len_b then
192-
aux_length_a_short a b 0 len_a
160+
else
161+
let is_a_number = a_type = "number" in
162+
let is_b_number = b_type = "number" in
163+
match is_a_number , is_b_number with
164+
| true, true ->
165+
caml_int_compare (Obj.magic a) (Obj.magic b )
166+
| true , false -> -1 (* Integer < Block in OCaml runtime GPR #1195 *)
167+
| false, true -> 1
168+
| false, false ->
169+
if a_type = "boolean"
170+
|| a_type = "null"
171+
|| a_type = "undefined"
172+
then
173+
unsafe_js_compare a b
174+
else if a_type = "function" || b_type = "function"
175+
then raise (Invalid_argument "compare: functional value")
193176
else
194-
aux_length_b_short a b 0 len_b
177+
(* if js_is_instance_array a then *)
178+
(* 0 *)
179+
(* else *)
180+
let tag_a = Bs_obj.tag a in
181+
let tag_b = Bs_obj.tag b in
182+
(* double_array_tag: 254
183+
forward_tag:250
184+
*)
185+
if tag_a = 250 then
186+
caml_compare (Obj.field a 0) b
187+
else if tag_b = 250 then
188+
caml_compare a (Obj.field b 0)
189+
else if tag_a = 248 (* object/exception *) then
190+
caml_int_compare (Obj.magic @@ Obj.field a 1) (Obj.magic @@ Obj.field b 1 )
191+
else if tag_a = 251 (* abstract_tag *) then
192+
raise (Invalid_argument "equal: abstract value")
193+
else if tag_a <> tag_b then
194+
if tag_a < tag_b then (-1) else 1
195+
else
196+
let len_a = Bs_obj.length a in
197+
let len_b = Bs_obj.length b in
198+
if len_a = len_b then
199+
aux_same_length a b 0 len_a
200+
else if len_a < len_b then
201+
aux_length_a_short a b 0 len_a
202+
else
203+
aux_length_b_short a b 0 len_b
195204
and aux_same_length (a : Obj.t) (b : Obj.t) i same_length =
196205
if i = same_length then
197206
0
@@ -217,37 +226,43 @@ type eq = Obj.t -> Obj.t -> bool
217226
let rec caml_equal (a : Obj.t) (b : Obj.t) : bool =
218227
(*front and formoest, we do not compare function values*)
219228
if a == b then true
220-
else if Js.typeof a = "string"
221-
|| Js.typeof a = "number"
222-
|| Js.typeof a = "boolean"
223-
|| Js.typeof a = "undefined"
224-
|| Js.typeof a = "null"
225-
then false
226-
else if Js.typeof a = "function" || Js.typeof b = "function"
227-
then raise (Invalid_argument "equal: functional value")
228-
(* first, check using reference equality *)
229-
else
230-
let tag_a = Bs_obj.tag a in
231-
let tag_b = Bs_obj.tag b in
232-
(* double_array_tag: 254
233-
forward_tag:250
234-
*)
235-
if tag_a = 250 then
236-
caml_equal (Obj.field a 0) b
237-
else if tag_b = 250 then
238-
caml_equal a (Obj.field b 0)
239-
else if tag_a = 248 (* object/exception *) then
240-
(Obj.magic @@ Obj.field a 1) == (Obj.magic @@ Obj.field b 1 )
241-
else if tag_a = 251 (* abstract_tag *) then
242-
raise (Invalid_argument "equal: abstract value")
243-
else if tag_a <> tag_b then
244-
false
245-
else
246-
let len_a = Bs_obj.length a in
247-
let len_b = Bs_obj.length b in
248-
if len_a = len_b then
249-
aux_equal_length a b 0 len_a
250-
else false
229+
else
230+
let a_type = Js.typeof a in
231+
if a_type = "string"
232+
|| a_type = "number"
233+
|| a_type = "boolean"
234+
|| a_type = "undefined"
235+
|| a_type = "null"
236+
then false
237+
else
238+
let b_type = Js.typeof b in
239+
if a_type = "function" || b_type = "function"
240+
then raise (Invalid_argument "equal: functional value")
241+
(* first, check using reference equality *)
242+
else (* a_type = "object" || "symbol" *)
243+
if b_type = "number" || b_type = "null" || b_type = "undefined" then false
244+
else
245+
let tag_a = Bs_obj.tag a in
246+
let tag_b = Bs_obj.tag b in
247+
(* double_array_tag: 254
248+
forward_tag:250
249+
*)
250+
if tag_a = 250 then
251+
caml_equal (Obj.field a 0) b
252+
else if tag_b = 250 then
253+
caml_equal a (Obj.field b 0)
254+
else if tag_a = 248 (* object/exception *) then
255+
(Obj.magic @@ Obj.field a 1) == (Obj.magic @@ Obj.field b 1 )
256+
else if tag_a = 251 (* abstract_tag *) then
257+
raise (Invalid_argument "equal: abstract value")
258+
else if tag_a <> tag_b then
259+
false
260+
else
261+
let len_a = Bs_obj.length a in
262+
let len_b = Bs_obj.length b in
263+
if len_a = len_b then
264+
aux_equal_length a b 0 len_a
265+
else false
251266
and aux_equal_length (a : Obj.t) (b : Obj.t) i same_length =
252267
if i = same_length then
253268
true

0 commit comments

Comments
 (0)