Skip to content

Commit 8276905

Browse files
committed
add empty obj unit test (+2 squashed commits)
Squashed commits: [72476aa] fix {!Sys.max_string_length} [e628e34] micro-optimize band (when its inner is `|`) (+1 squashed commit) Squashed commits: [f9bf7d1] micro-optimize int32_lsr (+1 squashed commit) Squashed commits: [918fe00] now it works, there is a bug in precedence printer, tweak and micro-optimize it later (+3 squashed commits) Squashed commits: [6ed0c1b] using js integer semantics for js ir 1. this is consistent with what we did 2. easy for optimizations, we don't want to add another JS IR after all, if we do too much compilation in [js_dump], that will make some simple cases hard to optimize like [ (x >>> (i * 8) | 0 ) & 255] [935b94f] migrate div to int32_div [1120b77] prepare int 32 operation support
1 parent d83b6a7 commit 8276905

20 files changed

+312
-70
lines changed

jscomp/j.ml

+3
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ and expression_desc =
113113
| Seq of expression * expression
114114
| Cond of expression * expression * expression
115115
| Bin of binop * expression * expression
116+
117+
(* [int_op] will guarantee return [int32] bits
118+
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators *)
116119
(* | Int32_bin of int_op * expression * expression *)
117120
| FlatCall of expression * expression
118121
(* f.apply(null,args) -- Fully applied guaranteed

jscomp/j_helper.ml

+107-4
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ let oo = "Caml_oo"
4444

4545
let no_side_effect = Js_analyzer.no_side_effect_expression
4646

47+
type binary_op = ?comment:string -> J.expression -> J.expression -> J.expression
48+
type unary_op = ?comment:string -> J.expression -> J.expression
4749
(*
4850
remove pure part of the expression
4951
and keep the non-pure part while preserve the semantics
@@ -552,7 +554,23 @@ module Exp = struct
552554
553555
check: Re-association: avoid integer overflow
554556
*)
555-
let rec add ?comment (e1 : t) (e2 : t) =
557+
let rec to_int32 ?comment (e : J.expression) : J.expression =
558+
let expression_desc = e.expression_desc in
559+
match expression_desc with
560+
| Bin(Bor, a, {expression_desc = Number (Int {i = 0}); _})
561+
->
562+
to_int32 ?comment a
563+
| _ ->
564+
{ comment ;
565+
expression_desc = Bin (Bor, {comment = None; expression_desc }, int 0)
566+
}
567+
568+
let rec to_uint32 ?comment (e : J.expression) : J.expression =
569+
{ comment ;
570+
expression_desc = Bin (Lsr, e , int 0)
571+
}
572+
573+
let rec float_add ?comment (e1 : t) (e2 : t) =
556574
match e1.expression_desc, e2.expression_desc with
557575
| Number (Int {i;_}), Number (Int {i = j;_}) ->
558576
int ?comment (i + j)
@@ -577,15 +595,100 @@ module Exp = struct
577595
(* bin ?comment Plus e2 e1 *)
578596
| _ ->
579597
bin ?comment Plus e1 e2
598+
let int32_add ?comment e1 e2 =
599+
(* to_int32 @@ *)float_add ?comment e1 e2
580600

581-
and minus ?comment e1 e2 =
601+
let float_minus ?comment e1 e2 =
582602
bin ?comment Minus e1 e2
583603

584-
and mul ?comment e1 e2 =
604+
let int32_minus ?comment e1 e2 : J.expression =
605+
(* to_int32 @@ *) float_minus ?comment e1 e2
606+
607+
let float_mul ?comment e1 e2 =
585608
bin ?comment Mul e1 e2
586609

587-
and div ?comment e1 e2 =
610+
let float_div ?comment e1 e2 =
588611
bin ?comment Div e1 e2
612+
let float_notequal ?comment e1 e2 =
613+
bin ?comment NotEqEq e1 e2
614+
615+
let int32_div ?comment e1 e2 : J.expression =
616+
to_int32 (float_div ?comment e1 e2)
617+
618+
619+
(* TODO: call primitive *)
620+
let int32_mul ?comment e1 e2 : J.expression =
621+
{ comment ;
622+
expression_desc = Bin (Mul, e1,e2)
623+
}
624+
625+
626+
(* TODO: check division by zero *)
627+
let int32_mod ?comment e1 e2 : J.expression =
628+
{ comment ;
629+
expression_desc = Bin (Mod, e1,e2)
630+
}
631+
632+
let int32_lsl ?comment e1 e2 : J.expression =
633+
{ comment ;
634+
expression_desc = Bin (Lsl, e1,e2)
635+
}
636+
637+
(* TODO: optimization *)
638+
let int32_lsr ?comment
639+
(e1 : J.expression)
640+
(e2 : J.expression) : J.expression =
641+
match e1.expression_desc, e2.expression_desc with
642+
| Number (Int { i = i1}), Number( Int {i = i2})
643+
->
644+
int @@ Int32.to_int
645+
(Int32.shift_right_logical
646+
(Int32.of_int i1) i2)
647+
| _ , Number( Int {i = i2})
648+
->
649+
if i2 = 0 then
650+
e1
651+
else
652+
{ comment ;
653+
expression_desc = Bin (Lsr, e1,e2) (* uint32 *)
654+
}
655+
| _, _ ->
656+
to_int32 { comment ;
657+
expression_desc = Bin (Lsr, e1,e2) (* uint32 *)
658+
}
659+
660+
let int32_asr ?comment e1 e2 : J.expression =
661+
{ comment ;
662+
expression_desc = Bin (Asr, e1,e2)
663+
}
664+
665+
let int32_bxor ?comment e1 e2 : J.expression =
666+
{ comment ;
667+
expression_desc = Bin (Bxor, e1,e2)
668+
}
669+
670+
let rec int32_band ?comment (e1 : J.expression) (e2 : J.expression) : J.expression =
671+
match e1.expression_desc with
672+
| Bin (Bor ,a, {expression_desc = Number (Int {i = 0})})
673+
->
674+
(* Note that in JS
675+
{[ -1 >>> 0 & 0xffffffff = -1]} is the same as
676+
{[ (-1 >>> 0 | 0 ) & 0xffffff ]}
677+
*)
678+
int32_band a e2
679+
| _ ->
680+
{ comment ;
681+
expression_desc = Bin (Band, e1,e2)
682+
}
683+
684+
let int32_bor ?comment e1 e2 : J.expression =
685+
{ comment ;
686+
expression_desc = Bin (Bor, e1,e2)
687+
}
688+
689+
(* let int32_bin ?comment op e1 e2 : J.expression = *)
690+
(* {expression_desc = Int32_bin(op,e1, e2); comment} *)
691+
589692

590693
(* TODO -- alpha conversion
591694
remember to add parens..

jscomp/j_helper.mli

+28-15
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ val is_constant : J.expression -> bool
6363

6464
val extract_non_pure : J.expression -> J.expression option
6565

66+
type binary_op = ?comment:string -> J.expression -> J.expression -> J.expression
67+
68+
type unary_op = ?comment:string -> J.expression -> J.expression
69+
6670
module Exp : sig
6771
type t = J.expression
6872

@@ -139,15 +143,23 @@ module Exp : sig
139143

140144
val is_type_number : ?comment:string -> t -> t
141145

142-
val bin : ?comment:string -> Js_op.binop -> t -> t -> t
143-
144-
val int_plus : ?comment:string -> t -> t -> t
145-
146-
val int_minus : ?comment:string -> t -> t -> t
147-
148-
val float_plus : ?comment:string -> t -> t -> t
146+
(* val bin : ?comment:string -> Js_op.binary_op -> t -> t -> t *)
147+
val to_int32 : unary_op
148+
val to_uint32 : unary_op
149+
150+
val int_plus : binary_op
151+
val int_minus : binary_op
152+
val int32_lsl : binary_op
153+
val int32_lsr : binary_op
154+
val int32_asr : binary_op
155+
val int32_mod : binary_op
156+
val int32_bxor : binary_op
157+
val int32_band : binary_op
158+
val int32_bor : binary_op
159+
val float_plus : binary_op
160+
val float_minus : binary_op
161+
val float_notequal : binary_op
149162

150-
val float_minus : ?comment:string -> t -> t -> t
151163
(* val un : ?comment:string -> Js_op.unop -> t -> t *)
152164
val not : t -> t
153165

@@ -219,14 +231,15 @@ module Exp : sig
219231

220232
val stringcomp : ?comment:string -> Js_op.binop -> t -> t -> t
221233

222-
val add : ?comment:string -> t -> t -> t
223-
224-
val minus : ?comment:string -> t -> t -> t
225-
226-
val mul : ?comment:string -> t -> t -> t
227-
228-
val div : ?comment:string -> t -> t -> t
229234

235+
val float_add : ?comment:string -> t -> t -> t
236+
val float_minus : ?comment:string -> t -> t -> t
237+
val float_mul : ?comment:string -> t -> t -> t
238+
val float_div : ?comment:string -> t -> t -> t
239+
val int32_div : ?comment:string -> t -> t -> t
240+
val int32_add : ?comment:string -> t -> t -> t
241+
val int32_minus : ?comment:string -> t -> t -> t
242+
val int32_mul : ?comment:string -> t -> t -> t
230243
val of_block : ?comment:string -> J.statement list -> J.expression -> t
231244
end
232245

jscomp/js_fold.ml

+2
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ class virtual fold =
125125
val log3 : 'a -> 'b -> 'c -> unit
126126
*)
127127
(* TODO: Add some primitives so that [js inliner] can do a better job *)
128+
(* [int_op] will guarantee return [int32] bits
129+
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators *)
128130
(* | Int32_bin of int_op * expression * expression *)
129131
(* f.apply(null,args) -- Fully applied guaranteed
130132
TODO: once we know args's shape --

jscomp/js_map.ml

+2
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ class virtual map =
138138
val log3 : 'a -> 'b -> 'c -> unit
139139
*)
140140
(* TODO: Add some primitives so that [js inliner] can do a better job *)
141+
(* [int_op] will guarantee return [int32] bits
142+
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators *)
141143
(* | Int32_bin of int_op * expression * expression *)
142144
(* f.apply(null,args) -- Fully applied guaranteed
143145
TODO: once we know args's shape --

jscomp/js_op.ml

+42
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,41 @@ type binop =
5252
| Div
5353
| Mod
5454

55+
(**
56+
note that we don't need raise [Div_by_zero] in ocamlscript
57+
58+
{[
59+
let add x y = x + y (* | 0 *)
60+
let minus x y = x - y (* | 0 *)
61+
let mul x y = x * y (* caml_mul | Math.imul *)
62+
let div x y = x / y (* caml_div (x/y|0)*)
63+
let imod x y = x mod y (* caml_mod (x%y) (zero_divide)*)
64+
65+
let bor x y = x lor y (* x | y *)
66+
let bxor x y = x lxor y (* x ^ y *)
67+
let band x y = x land y (* x & y *)
68+
let ilnot y = lnot y (* let lnot x = x lxor (-1) *)
69+
let ilsl x y = x lsl y (* x << y*)
70+
let ilsr x y = x lsr y (* x >>> y | 0 *)
71+
let iasr x y = x asr y (* x >> y *)
72+
]}
73+
74+
75+
Note that js treat unsigned shift 0 bits in a special way
76+
Unsigned shifts convert their left-hand side to Uint32,
77+
signed shifts convert it to Int32.
78+
Shifting by 0 digits returns the converted value.
79+
{[
80+
function ToUint32(x) {
81+
return x >>> 0;
82+
}
83+
function ToInt32(x) {
84+
return x >> 0;
85+
}
86+
]}
87+
So in Js, [-1 >>>0] will be the largest Uint32, while [-1>>0] will remain [-1]
88+
and [-1 >>> 0 >> 0 ] will be [-1]
89+
*)
5590
type int_op =
5691

5792
| Bor
@@ -62,10 +97,17 @@ type int_op =
6297
| Asr
6398

6499
| Plus
100+
(* for [+], given two numbers
101+
x + y | 0
102+
*)
65103
| Minus
104+
(* x - y | 0 *)
66105
| Mul
106+
(* *)
67107
| Div
108+
(* x / y | 0 *)
68109
| Mod
110+
(* x % y *)
69111

70112
(* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Bitwise_operators
71113
{[

jscomp/js_op_util.ml

+20-4
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,34 @@ let op_int_prec (op : Js_op.int_op) =
5151

5252
let op_str (op : Js_op.binop) =
5353
match op with
54-
| Eq -> "="
55-
| Or -> "||"
56-
| And -> "&&"
5754
| Bor -> "|"
5855
| Bxor -> "^"
5956
| Band -> "&"
57+
| Lsl -> "<<"
58+
| Lsr -> ">>>"
59+
| Asr -> ">>"
60+
| Plus -> "+"
61+
| Minus -> "-"
62+
| Mul -> "*"
63+
| Div -> "/"
64+
| Mod -> "%"
65+
66+
| Eq -> "="
67+
| Or -> "||"
68+
| And -> "&&"
6069
| EqEqEq -> "==="
6170
| NotEqEq -> "!=="
6271
| Lt -> "<"
6372
| Le -> "<="
6473
| Gt -> ">"
6574
| Ge -> ">="
75+
76+
77+
let op_int_str (op : Js_op.int_op) =
78+
match op with
79+
| Bor -> "|"
80+
| Bxor -> "^"
81+
| Band -> "&"
6682
| Lsl -> "<<"
6783
| Lsr -> ">>>"
6884
| Asr -> ">>"
@@ -71,7 +87,7 @@ let op_str (op : Js_op.binop) =
7187
| Mul -> "*"
7288
| Div -> "/"
7389
| Mod -> "%"
74-
90+
7591
let str_of_used_stats = function
7692
| Js_op.Dead_pure -> "Dead_pure"
7793
| Dead_non_pure -> "Dead_non_pure"

jscomp/js_op_util.mli

+4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ val op_prec : Js_op.binop -> int * int * int
2626

2727
val op_str : Js_op.binop -> string
2828

29+
val op_int_prec : Js_op.int_op -> int * int * int
30+
31+
val op_int_str : Js_op.int_op -> string
32+
2933
val str_of_used_stats : Js_op.used_stats -> string
3034

3135
val update_used_stats : J.ident_info -> Js_op.used_stats -> unit

jscomp/lam_compile_group.ml

+6-2
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,13 @@ let compile_group ({filename = file_name; env;} as meta : Lam_stats.meta) (x : L
9595
J_helper.string "bytes_cat")
9696

9797
(** Special handling for values in [Sys] *)
98-
| Single(_, ({name="max_array_length";_} as id) ,_ ), "sys.ml" ->
99-
(* See [js_knowledge] Array size section, can not be expressed by OCaml int *)
98+
| Single(_, ({name="max_array_length" | "max_string_length";_} as id) ,_ ), "sys.ml" ->
99+
(* See [js_knowledge] Array size section, can not be expressed by OCaml int,
100+
note that casual handling of {!Sys.max_string_length} could result into
101+
negative value which could cause wrong behavior of {!Buffer.create}
102+
*)
100103
Js_output.of_stmt @@ S.const_variable id ~exp:(E.float "4_294_967_295.")
104+
101105
| Single(_, ({name="max_int";_} as id) ,_ ), ("sys.ml" | "nativeint.ml") ->
102106
(* See [js_knowledge] Max int section, (2. ** 53. -. 1.;;) can not be expressed by OCaml int *)
103107
Js_output.of_stmt @@ S.const_variable id ~exp:(E.float "9007199254740991.")

0 commit comments

Comments
 (0)