Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions jscomp/j.ml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ and expression_desc =
| Seq of expression * expression
| Cond of expression * expression * expression
| Bin of binop * expression * expression

(* [int_op] will guarantee return [int32] bits
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators *)
(* | Int32_bin of int_op * expression * expression *)
| FlatCall of expression * expression
(* f.apply(null,args) -- Fully applied guaranteed
Expand Down
111 changes: 107 additions & 4 deletions jscomp/j_helper.ml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ let oo = "Caml_oo"

let no_side_effect = Js_analyzer.no_side_effect_expression

type binary_op = ?comment:string -> J.expression -> J.expression -> J.expression
type unary_op = ?comment:string -> J.expression -> J.expression
(*
remove pure part of the expression
and keep the non-pure part while preserve the semantics
Expand Down Expand Up @@ -552,7 +554,23 @@ module Exp = struct

check: Re-association: avoid integer overflow
*)
let rec add ?comment (e1 : t) (e2 : t) =
let rec to_int32 ?comment (e : J.expression) : J.expression =
let expression_desc = e.expression_desc in
match expression_desc with
| Bin(Bor, a, {expression_desc = Number (Int {i = 0}); _})
->
to_int32 ?comment a
| _ ->
{ comment ;
expression_desc = Bin (Bor, {comment = None; expression_desc }, int 0)
}

let rec to_uint32 ?comment (e : J.expression) : J.expression =
{ comment ;
expression_desc = Bin (Lsr, e , int 0)
}

let rec float_add ?comment (e1 : t) (e2 : t) =
match e1.expression_desc, e2.expression_desc with
| Number (Int {i;_}), Number (Int {i = j;_}) ->
int ?comment (i + j)
Expand All @@ -577,15 +595,100 @@ module Exp = struct
(* bin ?comment Plus e2 e1 *)
| _ ->
bin ?comment Plus e1 e2
let int32_add ?comment e1 e2 =
(* to_int32 @@ *)float_add ?comment e1 e2

and minus ?comment e1 e2 =
let float_minus ?comment e1 e2 =
bin ?comment Minus e1 e2

and mul ?comment e1 e2 =
let int32_minus ?comment e1 e2 : J.expression =
(* to_int32 @@ *) float_minus ?comment e1 e2

let float_mul ?comment e1 e2 =
bin ?comment Mul e1 e2

and div ?comment e1 e2 =
let float_div ?comment e1 e2 =
bin ?comment Div e1 e2
let float_notequal ?comment e1 e2 =
bin ?comment NotEqEq e1 e2

let int32_div ?comment e1 e2 : J.expression =
to_int32 (float_div ?comment e1 e2)


(* TODO: call primitive *)
let int32_mul ?comment e1 e2 : J.expression =
{ comment ;
expression_desc = Bin (Mul, e1,e2)
}


(* TODO: check division by zero *)
let int32_mod ?comment e1 e2 : J.expression =
{ comment ;
expression_desc = Bin (Mod, e1,e2)
}

let int32_lsl ?comment e1 e2 : J.expression =
{ comment ;
expression_desc = Bin (Lsl, e1,e2)
}

(* TODO: optimization *)
let int32_lsr ?comment
(e1 : J.expression)
(e2 : J.expression) : J.expression =
match e1.expression_desc, e2.expression_desc with
| Number (Int { i = i1}), Number( Int {i = i2})
->
int @@ Int32.to_int
(Int32.shift_right_logical
(Int32.of_int i1) i2)
| _ , Number( Int {i = i2})
->
if i2 = 0 then
e1
else
{ comment ;
expression_desc = Bin (Lsr, e1,e2) (* uint32 *)
}
| _, _ ->
to_int32 { comment ;
expression_desc = Bin (Lsr, e1,e2) (* uint32 *)
}

let int32_asr ?comment e1 e2 : J.expression =
{ comment ;
expression_desc = Bin (Asr, e1,e2)
}

let int32_bxor ?comment e1 e2 : J.expression =
{ comment ;
expression_desc = Bin (Bxor, e1,e2)
}

let rec int32_band ?comment (e1 : J.expression) (e2 : J.expression) : J.expression =
match e1.expression_desc with
| Bin (Bor ,a, {expression_desc = Number (Int {i = 0})})
->
(* Note that in JS
{[ -1 >>> 0 & 0xffffffff = -1]} is the same as
{[ (-1 >>> 0 | 0 ) & 0xffffff ]}
*)
int32_band a e2
| _ ->
{ comment ;
expression_desc = Bin (Band, e1,e2)
}

let int32_bor ?comment e1 e2 : J.expression =
{ comment ;
expression_desc = Bin (Bor, e1,e2)
}

(* let int32_bin ?comment op e1 e2 : J.expression = *)
(* {expression_desc = Int32_bin(op,e1, e2); comment} *)


(* TODO -- alpha conversion
remember to add parens..
Expand Down
43 changes: 28 additions & 15 deletions jscomp/j_helper.mli
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ val is_constant : J.expression -> bool

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

type binary_op = ?comment:string -> J.expression -> J.expression -> J.expression

type unary_op = ?comment:string -> J.expression -> J.expression

module Exp : sig
type t = J.expression

Expand Down Expand Up @@ -139,15 +143,23 @@ module Exp : sig

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

val bin : ?comment:string -> Js_op.binop -> t -> t -> t

val int_plus : ?comment:string -> t -> t -> t

val int_minus : ?comment:string -> t -> t -> t

val float_plus : ?comment:string -> t -> t -> t
(* val bin : ?comment:string -> Js_op.binary_op -> t -> t -> t *)
val to_int32 : unary_op
val to_uint32 : unary_op

val int_plus : binary_op
val int_minus : binary_op
val int32_lsl : binary_op
val int32_lsr : binary_op
val int32_asr : binary_op
val int32_mod : binary_op
val int32_bxor : binary_op
val int32_band : binary_op
val int32_bor : binary_op
val float_plus : binary_op
val float_minus : binary_op
val float_notequal : binary_op

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

Expand Down Expand Up @@ -219,14 +231,15 @@ module Exp : sig

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

val add : ?comment:string -> t -> t -> t

val minus : ?comment:string -> t -> t -> t

val mul : ?comment:string -> t -> t -> t

val div : ?comment:string -> t -> t -> t

val float_add : ?comment:string -> t -> t -> t
val float_minus : ?comment:string -> t -> t -> t
val float_mul : ?comment:string -> t -> t -> t
val float_div : ?comment:string -> t -> t -> t
val int32_div : ?comment:string -> t -> t -> t
val int32_add : ?comment:string -> t -> t -> t
val int32_minus : ?comment:string -> t -> t -> t
val int32_mul : ?comment:string -> t -> t -> t
val of_block : ?comment:string -> J.statement list -> J.expression -> t
end

Expand Down
2 changes: 2 additions & 0 deletions jscomp/js_fold.ml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ class virtual fold =
val log3 : 'a -> 'b -> 'c -> unit
*)
(* TODO: Add some primitives so that [js inliner] can do a better job *)
(* [int_op] will guarantee return [int32] bits
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators *)
(* | Int32_bin of int_op * expression * expression *)
(* f.apply(null,args) -- Fully applied guaranteed
TODO: once we know args's shape --
Expand Down
2 changes: 2 additions & 0 deletions jscomp/js_map.ml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ class virtual map =
val log3 : 'a -> 'b -> 'c -> unit
*)
(* TODO: Add some primitives so that [js inliner] can do a better job *)
(* [int_op] will guarantee return [int32] bits
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators *)
(* | Int32_bin of int_op * expression * expression *)
(* f.apply(null,args) -- Fully applied guaranteed
TODO: once we know args's shape --
Expand Down
42 changes: 42 additions & 0 deletions jscomp/js_op.ml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,41 @@ type binop =
| Div
| Mod

(**
note that we don't need raise [Div_by_zero] in ocamlscript

{[
let add x y = x + y (* | 0 *)
let minus x y = x - y (* | 0 *)
let mul x y = x * y (* caml_mul | Math.imul *)
let div x y = x / y (* caml_div (x/y|0)*)
let imod x y = x mod y (* caml_mod (x%y) (zero_divide)*)

let bor x y = x lor y (* x | y *)
let bxor x y = x lxor y (* x ^ y *)
let band x y = x land y (* x & y *)
let ilnot y = lnot y (* let lnot x = x lxor (-1) *)
let ilsl x y = x lsl y (* x << y*)
let ilsr x y = x lsr y (* x >>> y | 0 *)
let iasr x y = x asr y (* x >> y *)
]}


Note that js treat unsigned shift 0 bits in a special way
Unsigned shifts convert their left-hand side to Uint32,
signed shifts convert it to Int32.
Shifting by 0 digits returns the converted value.
{[
function ToUint32(x) {
return x >>> 0;
}
function ToInt32(x) {
return x >> 0;
}
]}
So in Js, [-1 >>>0] will be the largest Uint32, while [-1>>0] will remain [-1]
and [-1 >>> 0 >> 0 ] will be [-1]
*)
type int_op =

| Bor
Expand All @@ -62,10 +97,17 @@ type int_op =
| Asr

| Plus
(* for [+], given two numbers
x + y | 0
*)
| Minus
(* x - y | 0 *)
| Mul
(* *)
| Div
(* x / y | 0 *)
| Mod
(* x % y *)

(* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Bitwise_operators
{[
Expand Down
24 changes: 20 additions & 4 deletions jscomp/js_op_util.ml
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,34 @@ let op_int_prec (op : Js_op.int_op) =

let op_str (op : Js_op.binop) =
match op with
| Eq -> "="
| Or -> "||"
| And -> "&&"
| Bor -> "|"
| Bxor -> "^"
| Band -> "&"
| Lsl -> "<<"
| Lsr -> ">>>"
| Asr -> ">>"
| Plus -> "+"
| Minus -> "-"
| Mul -> "*"
| Div -> "/"
| Mod -> "%"

| Eq -> "="
| Or -> "||"
| And -> "&&"
| EqEqEq -> "==="
| NotEqEq -> "!=="
| Lt -> "<"
| Le -> "<="
| Gt -> ">"
| Ge -> ">="


let op_int_str (op : Js_op.int_op) =
match op with
| Bor -> "|"
| Bxor -> "^"
| Band -> "&"
| Lsl -> "<<"
| Lsr -> ">>>"
| Asr -> ">>"
Expand All @@ -71,7 +87,7 @@ let op_str (op : Js_op.binop) =
| Mul -> "*"
| Div -> "/"
| Mod -> "%"

let str_of_used_stats = function
| Js_op.Dead_pure -> "Dead_pure"
| Dead_non_pure -> "Dead_non_pure"
Expand Down
4 changes: 4 additions & 0 deletions jscomp/js_op_util.mli
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ val op_prec : Js_op.binop -> int * int * int

val op_str : Js_op.binop -> string

val op_int_prec : Js_op.int_op -> int * int * int

val op_int_str : Js_op.int_op -> string

val str_of_used_stats : Js_op.used_stats -> string

val update_used_stats : J.ident_info -> Js_op.used_stats -> unit
Expand Down
8 changes: 6 additions & 2 deletions jscomp/lam_compile_group.ml
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,13 @@ let compile_group ({filename = file_name; env;} as meta : Lam_stats.meta) (x : L
J_helper.string "bytes_cat")

(** Special handling for values in [Sys] *)
| Single(_, ({name="max_array_length";_} as id) ,_ ), "sys.ml" ->
(* See [js_knowledge] Array size section, can not be expressed by OCaml int *)
| Single(_, ({name="max_array_length" | "max_string_length";_} as id) ,_ ), "sys.ml" ->
(* See [js_knowledge] Array size section, can not be expressed by OCaml int,
note that casual handling of {!Sys.max_string_length} could result into
negative value which could cause wrong behavior of {!Buffer.create}
*)
Js_output.of_stmt @@ S.const_variable id ~exp:(E.float "4_294_967_295.")

| Single(_, ({name="max_int";_} as id) ,_ ), ("sys.ml" | "nativeint.ml") ->
(* See [js_knowledge] Max int section, (2. ** 53. -. 1.;;) can not be expressed by OCaml int *)
Js_output.of_stmt @@ S.const_variable id ~exp:(E.float "9007199254740991.")
Expand Down
Loading