Skip to content

Commit cc536ed

Browse files
committed
replace the hash algorithm with the one used in byterun/hash.c (#269)
* replace the hash algorithm with the one used in byterun/hash.c -- todo: test the block and some weird js values * clean up
1 parent ca95e06 commit cc536ed

21 files changed

+598
-95
lines changed

jscomp/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<!-- <script src="./async.js"></script> -->
1111
<script src="./require1k.js"></script>
1212
<script>
13-
R('./test/class_repr', function(err,v){
13+
R('./test/hash_test', function(err,v){
1414
window.v = v
1515
})
1616
</script>

jscomp/js_config.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ let format = "Caml_format"
163163
let string = "Caml_string"
164164

165165
let float = "Caml_float"
166-
166+
let hash = "Caml_hash"
167167
let oo = "Caml_oo"
168168
let curry = "Caml_curry"
169169
let internalMod = "Caml_internalMod"

jscomp/js_config.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,4 @@ val bigarray : string
6464
val unix : string
6565
val int64 : string
6666
val md5 : string
67+
val hash : string

jscomp/lam_dispatch_primitive.ml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,9 @@ let query (prim : Lam_compile_env.primitive_description)
791791
end
792792
| "caml_md5_string"
793793
-> E.runtime_call Js_config.md5 prim.prim_name args
794+
| "caml_hash"
795+
-> E.runtime_call Js_config.hash prim.prim_name args
796+
794797
| "caml_output_value_to_buffer"
795798
| "caml_marshal_data_size"
796799
| "caml_input_value_from_string"
@@ -799,7 +802,7 @@ let query (prim : Lam_compile_env.primitive_description)
799802
| "caml_output_value_to_string"
800803

801804
| "caml_md5_chan"
802-
| "caml_hash"
805+
803806
| "caml_hash_univ_param"
804807
| "caml_weak_set"
805808
| "caml_weak_create"

jscomp/runtime/.depend

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ caml_bigarray.cmi :
33
caml_builtin_exceptions.cmi :
44
caml_float.cmi :
55
caml_format.cmi :
6+
caml_hash.cmi :
67
caml_int64.cmi :
78
caml_lexer.cmi :
89
caml_md5.cmi :
910
caml_obj.cmi :
1011
caml_oo.cmi :
1112
caml_parser.cmi :
1213
caml_primitive.cmi :
14+
caml_queue.cmi :
1315
caml_string.cmi :
1416
caml_sys.cmi :
1517
caml_utils.cmi :
@@ -25,6 +27,8 @@ caml_float.cmo : typed_array.cmo js.cmo caml_float.cmi
2527
caml_float.cmx : typed_array.cmx js.cmx caml_float.cmi
2628
caml_format.cmo : js.cmo caml_utils.cmi caml_format.cmi
2729
caml_format.cmx : js.cmx caml_utils.cmx caml_format.cmi
30+
caml_hash.cmo : js.cmo caml_queue.cmi caml_hash.cmi
31+
caml_hash.cmx : js.cmx caml_queue.cmx caml_hash.cmi
2832
caml_int64.cmo : typed_array.cmo js.cmo caml_utils.cmi caml_int64.cmi
2933
caml_int64.cmx : typed_array.cmx js.cmx caml_utils.cmx caml_int64.cmi
3034
caml_io.cmo : js.cmo
@@ -41,6 +45,8 @@ caml_parser.cmo : caml_parser.cmi
4145
caml_parser.cmx : caml_parser.cmi
4246
caml_primitive.cmo : caml_primitive.cmi
4347
caml_primitive.cmx : caml_primitive.cmi
48+
caml_queue.cmo : caml_queue.cmi
49+
caml_queue.cmx : caml_queue.cmi
4450
caml_string.cmo : js.cmo caml_string.cmi
4551
caml_string.cmx : js.cmx caml_string.cmi
4652
caml_sys.cmo : js.cmo caml_sys.cmi
@@ -67,6 +73,8 @@ caml_float.cmo : typed_array.cmo js.cmo caml_float.cmi
6773
caml_float.cmj : typed_array.cmj js.cmj caml_float.cmi
6874
caml_format.cmo : js.cmo caml_utils.cmi caml_format.cmi
6975
caml_format.cmj : js.cmj caml_utils.cmj caml_format.cmi
76+
caml_hash.cmo : js.cmo caml_queue.cmi caml_hash.cmi
77+
caml_hash.cmj : js.cmj caml_queue.cmj caml_hash.cmi
7078
caml_int64.cmo : typed_array.cmo js.cmo caml_utils.cmi caml_int64.cmi
7179
caml_int64.cmj : typed_array.cmj js.cmj caml_utils.cmj caml_int64.cmi
7280
caml_io.cmo : js.cmo
@@ -83,6 +91,8 @@ caml_parser.cmo : caml_parser.cmi
8391
caml_parser.cmj : caml_parser.cmi
8492
caml_primitive.cmo : caml_primitive.cmi
8593
caml_primitive.cmj : caml_primitive.cmi
94+
caml_queue.cmo : caml_queue.cmi
95+
caml_queue.cmj : caml_queue.cmi
8696
caml_string.cmo : js.cmo caml_string.cmi
8797
caml_string.cmj : js.cmj caml_string.cmi
8898
caml_sys.cmo : js.cmo caml_sys.cmi

jscomp/runtime/caml_hash.js

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Generated CODE, PLEASE EDIT WITH CARE
2+
'use strict';
3+
4+
var Caml_builtin_exceptions = require("./caml_builtin_exceptions");
5+
var Caml_queue = require("./caml_queue");
6+
var Caml_primitive = require("./caml_primitive");
7+
8+
function rotl32(x, n) {
9+
return (x << n) | (x >>> (32 - n | 0));
10+
}
11+
12+
function mix(h, d) {
13+
var d$1 = d;
14+
d$1 = Caml_primitive.imul(d$1, 3432918353);
15+
d$1 = rotl32(d$1, 15);
16+
d$1 = Caml_primitive.imul(d$1, 461845907);
17+
var h$1 = h ^ d$1;
18+
h$1 = rotl32(h$1, 13);
19+
return (h$1 + (h$1 << 2) | 0) + 3864292196 | 0;
20+
}
21+
22+
function final_mix(h) {
23+
var h$1 = h ^ (h >>> 16);
24+
h$1 = Caml_primitive.imul(h$1, 2246822507);
25+
h$1 = h$1 ^ (h$1 >>> 13);
26+
h$1 = Caml_primitive.imul(h$1, 3266489909);
27+
return h$1 ^ (h$1 >>> 16);
28+
}
29+
30+
function caml_hash_mix_string(h, s) {
31+
var len = s.length;
32+
var block = (len / 4 | 0) - 1 | 0;
33+
var hash = h;
34+
for(var i = 0; i<= block; ++i){
35+
var j = (i << 2);
36+
var w = s.charCodeAt(j) | (s.charCodeAt(j + 1 | 0) << 8) | (s.charCodeAt(j + 2 | 0) << 16) | (s.charCodeAt(j + 3 | 0) << 24);
37+
hash = mix(hash, w);
38+
}
39+
var modulo = len & 3;
40+
if (modulo !== 0) {
41+
var w$1 = modulo === 3 ? (s.charCodeAt(len - 1 | 0) << 16) | (s.charCodeAt(len - 2 | 0) << 8) | s.charCodeAt(len - 3 | 0) : (
42+
modulo === 2 ? (s.charCodeAt(len - 1 | 0) << 8) | s.charCodeAt(len - 2 | 0) : s.charCodeAt(len - 1 | 0)
43+
);
44+
hash = mix(hash, w$1);
45+
}
46+
hash = hash ^ len;
47+
return hash;
48+
}
49+
50+
function caml_hash(count, _, seed, obj) {
51+
var hash = seed;
52+
if (typeof obj === "number") {
53+
var u = obj | 0;
54+
hash = mix(hash, (u + u | 0) + 1 | 0);
55+
return final_mix(hash);
56+
}
57+
else if (typeof obj === "string") {
58+
hash = caml_hash_mix_string(hash, obj);
59+
return final_mix(hash);
60+
}
61+
else {
62+
var queue = /* record */[
63+
0,
64+
/* None */0
65+
];
66+
var num = count;
67+
Caml_queue.push(obj, queue);
68+
num = num - 1 | 0;
69+
while(queue[/* length */0] !== 0 && num > 0) {
70+
var obj$1 = Caml_queue.unsafe_pop(queue);
71+
if (typeof obj$1 === "number") {
72+
hash = mix(hash, obj$1 | 0);
73+
num = num - 1 | 0;
74+
}
75+
else if (typeof obj$1 === "string") {
76+
hash = caml_hash_mix_string(hash, obj$1);
77+
num = num - 1 | 0;
78+
}
79+
else if (typeof obj$1 !== "boolean") {
80+
if (typeof obj$1 !== "undefined") {
81+
if (typeof obj$1 === "symbol") {
82+
throw [
83+
Caml_builtin_exceptions.assert_failure,
84+
[
85+
"caml_hash.ml",
86+
124,
87+
8
88+
]
89+
];
90+
}
91+
else if (typeof obj$1 !== "function") {
92+
var tag = obj$1.tag | 0;
93+
hash = mix(hash, tag);
94+
var v = obj$1.length - 1 | 0;
95+
var block = v < num ? v : num;
96+
for(var i = 0; i<= block; ++i){
97+
Caml_queue.push(obj$1[i], queue);
98+
}
99+
}
100+
101+
}
102+
103+
}
104+
105+
};
106+
return final_mix(hash);
107+
}
108+
}
109+
110+
exports.caml_hash = caml_hash;
111+
/* No side effect */

jscomp/runtime/caml_hash.ml

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
(* BuckleScript compiler
2+
* Copyright (C) 2015-2016 Bloomberg Finance L.P.
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU Lesser General Public License as published by
6+
* the Free Software Foundation, with linking exception;
7+
* either version 2.1 of the License, or (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17+
*)
18+
19+
(* Author: Hongbo Zhang *)
20+
21+
let (<< ) = Nativeint.shift_left
22+
let (>>>) = Nativeint.shift_right_logical
23+
let (|~) = Nativeint.logor
24+
let (^) = Nativeint.logxor
25+
26+
external ( *~ ) : nativeint -> nativeint -> nativeint = "caml_int32_mul"
27+
external ( +~ ) : nativeint -> nativeint -> nativeint = "caml_int32_add"
28+
29+
30+
31+
let rotl32 (x : nativeint) n =
32+
(x << n) |~ (x >>> (32 - n))
33+
34+
35+
let mix h d =
36+
let d = ref d in
37+
d := !d *~ 0xcc9e2d51n ;
38+
d := rotl32 !d 15 ;
39+
d := !d *~ 0x1b873593n ;
40+
let h = ref (h ^ !d) in
41+
h := rotl32 !h 13 ;
42+
!h +~ (!h << 2) +~ 0xe6546b64n
43+
44+
let final_mix h =
45+
let h = ref (h ^ (h >>> 16)) in
46+
h := !h *~ 0x85ebca6bn ;
47+
h := !h ^ (!h >>> 13);
48+
h := !h *~ 0xc2b2ae35n ;
49+
!h ^ (!h >>> 16)
50+
(* Nativeint.logand (!h ^ (!h >>> 16)) 0x3FFFFFFFn *)
51+
52+
let caml_hash_mix_string h s =
53+
let len = String.length s in
54+
let block = len / 4 - 1 in
55+
let hash = ref h in
56+
for i = 0 to block do
57+
let j = 4 * i in
58+
let w =
59+
Char.code s.[j] lor
60+
(Char.code s.[j+1] lsl 8) lor
61+
(Char.code s.[j+2] lsl 16) lor
62+
(Char.code s.[j+3] lsl 24)
63+
in
64+
hash := mix !hash (Nativeint.of_int w)
65+
done ;
66+
let modulo = len land 0b11 in
67+
if modulo <> 0 then
68+
begin
69+
let w =
70+
if modulo = 3 then
71+
(Char.code s.[len - 1] lsl 16) lor
72+
(Char.code s.[len - 2] lsl 8) lor
73+
(Char.code s.[len - 3])
74+
else if modulo = 2 then
75+
(Char.code s.[len -1] lsl 8) lor
76+
Char.code s.[len -2]
77+
else Char.code s.[len - 1]
78+
in
79+
hash := mix !hash (Nativeint.of_int w)
80+
end;
81+
hash := !hash ^ (Nativeint.of_int len) ;
82+
!hash
83+
84+
85+
let caml_hash count _limit seed obj =
86+
let hash = ref seed in
87+
if Js.typeof obj = "number" then
88+
begin
89+
let u = (Nativeint.of_float (Obj.magic obj)) in
90+
hash := mix !hash (u +~ u +~ 1n) ;
91+
final_mix !hash
92+
end
93+
else if Js.typeof obj = "string" then
94+
begin
95+
hash := caml_hash_mix_string !hash (Obj.magic obj : string);
96+
final_mix !hash
97+
end
98+
(* TODO: hash [null] [undefined] as well *)
99+
else
100+
101+
let queue = Caml_queue.create () in
102+
let num = ref count in
103+
let () =
104+
Caml_queue.push obj queue;
105+
decr num
106+
in
107+
while not @@ Caml_queue.is_empty queue && !num > 0 do
108+
let obj = Caml_queue.unsafe_pop queue in
109+
if Js.typeof obj = "number" then
110+
begin
111+
hash := mix !hash (Nativeint.of_float (Obj.magic obj));
112+
decr num ;
113+
end
114+
else if Js.typeof obj = "string" then
115+
begin
116+
hash := caml_hash_mix_string !hash (Obj.magic obj : string);
117+
decr num
118+
end
119+
else if Js.typeof obj = "boolean" then
120+
()
121+
else if Js.typeof obj = "undefined" then
122+
()
123+
else if Js.typeof obj = "symbol" then
124+
assert false (* TODO *)
125+
else if Js.typeof obj = "function" then
126+
()
127+
else
128+
let tag = Obj.tag obj in
129+
hash := mix !hash (Nativeint.of_int tag) ;
130+
let block =
131+
let v = Obj.size obj - 1 in if v < !num then v else !num in
132+
for i = 0 to block do
133+
Caml_queue.push (Obj.field obj i ) queue
134+
done
135+
done;
136+
final_mix !hash
137+

jscomp/runtime/caml_hash.mli

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
(* BuckleScript compiler
2+
* Copyright (C) 2015-2016 Bloomberg Finance L.P.
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU Lesser General Public License as published by
6+
* the Free Software Foundation, with linking exception;
7+
* either version 2.1 of the License, or (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17+
*)
18+
19+
(* Author: Hongbo Zhang *)
20+
21+
val caml_hash : int -> 'a -> nativeint -> Obj.t -> nativeint

0 commit comments

Comments
 (0)