diff --git a/jscomp/core/j.ml b/jscomp/core/j.ml index a214ae1014..d47bbd80e1 100644 --- a/jscomp/core/j.ml +++ b/jscomp/core/j.ml @@ -1,4 +1,4 @@ -(* Copyright (C) 2015-2016 Bloomberg Finance L.P. +(* Copyright (C) 2015- Authors of ReScript * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -70,7 +70,6 @@ and required_modules = module_id list currently we always use quote *) and property_name = Js_op.property_name -and jsint = int32 and ident = Ident.t and module_id = { id : ident; kind : Js_op.kind diff --git a/jscomp/core/js_analyzer.ml b/jscomp/core/js_analyzer.ml index b7075b5741..63240088e1 100644 --- a/jscomp/core/js_analyzer.ml +++ b/jscomp/core/js_analyzer.ml @@ -29,7 +29,13 @@ +type idents_stats = { + mutable used_idents : Set_ident.t ; + mutable defined_idents : Set_ident.t; +} +let add_defined_idents (x : idents_stats) ident = + x.defined_idents <- Set_ident.add x.defined_idents ident (* Assume that functions already calculated closure correctly Maybe in the future, we should add a dirty flag, to mark the calcuated @@ -38,48 +44,48 @@ Note such shaking is done in the toplevel, so that it requires us to flatten the statement first *) -let free_variables used_idents defined_idents = +let free_variables (stats : idents_stats) : Js_fold.fold = object (self) inherit Js_fold.fold as super - val defined_idents = defined_idents - val used_idents = used_idents method! variable_declaration st = - match st with - | { ident; value = None} + add_defined_idents stats st.ident; + match st.value with + | None + -> self + | Some v -> - {< defined_idents = Set_ident.add defined_idents ident >} - | { ident; value = Some v} - -> - {< defined_idents = Set_ident.add defined_idents ident >} # expression v + self # expression v method! ident id = - if Set_ident.mem defined_idents id then self - else {} + (if not (Set_ident.mem stats.defined_idents id )then + stats.used_idents <- Set_ident.add stats.used_idents id); + self method! expression exp = - match exp.expression_desc with | Fun(_, _,_, env) (** a optimization to avoid walking into funciton again if it's already comuted *) -> - {< used_idents = - Set_ident.union (Js_fun_env.get_unbounded env) used_idents >} + stats.used_idents <- + Set_ident.union (Js_fun_env.get_unbounded env) stats.used_idents; + self | _ -> super#expression exp - - method get_depenencies = - Set_ident.diff used_idents defined_idents - method get_used_idents = used_idents - method get_defined_idents = defined_idents end -let free_variables_of_statement used_idents defined_idents st = - ((free_variables used_idents defined_idents)#statement st) # get_depenencies +let free_variables_of_statement st = + let init = {used_idents = Set_ident.empty; + defined_idents = Set_ident.empty} in + let _ = (free_variables init)#statement st in + Set_ident.diff init.used_idents init.defined_idents -let free_variables_of_expression used_idents defined_idents st = - ((free_variables used_idents defined_idents)#expression st) # get_depenencies +let free_variables_of_expression st = + let init = {used_idents = Set_ident.empty; + defined_idents = Set_ident.empty} in + let _ = (free_variables init)#expression st in + Set_ident.diff init.used_idents init.defined_idents let rec no_side_effect_expression_desc (x : J.expression_desc) = match x with @@ -133,33 +139,33 @@ and no_side_effect (x : J.expression) = let no_side_effect_expression (x : J.expression) = no_side_effect x -let no_side_effect init = +let no_side_effect clean : Js_fold.fold = object (self) inherit Js_fold.fold as super - val no_side_effect = init - method get_no_side_effect = no_side_effect - method! statement s = - if not no_side_effect then self else + if not !clean then self else match s.statement_desc with | Throw _ | Debugger | Break | Variable _ | Continue _ -> - {< no_side_effect = false>} + clean := false ; self | Exp e -> self#expression e | Int_switch _ | String_switch _ | ForRange _ | If _ | While _ | Block _ | Return _ | Try _ -> super#statement s method! list f x = - if not self#get_no_side_effect then self else super#list f x + if not !clean then self else super#list f x method! expression s = - if not no_side_effect then self - else {< no_side_effect = no_side_effect_expression s >} - + (if !clean then + clean := no_side_effect_expression s); + self (** only expression would cause side effec *) end -let no_side_effect_statement st = ((no_side_effect true)#statement st)#get_no_side_effect +let no_side_effect_statement st = + let clean = ref true in + let _ : Js_fold.fold = ((no_side_effect clean)#statement st) in + !clean (* TODO: generate [fold2] This make sense, for example: diff --git a/jscomp/core/js_analyzer.mli b/jscomp/core/js_analyzer.mli index 35491a72c9..56216b09d8 100644 --- a/jscomp/core/js_analyzer.mli +++ b/jscomp/core/js_analyzer.mli @@ -35,10 +35,10 @@ *) val free_variables_of_statement : - Set_ident.t -> Set_ident.t -> J.statement -> Set_ident.t + J.statement -> Set_ident.t val free_variables_of_expression : - Set_ident.t -> Set_ident.t -> J.finish_ident_expression -> Set_ident.t + J.finish_ident_expression -> Set_ident.t (* val no_side_effect_expression_desc : J.expression_desc -> bool *) diff --git a/jscomp/core/js_fold.ml b/jscomp/core/js_fold.ml index 4b1e2fc10b..b444ff841e 100644 --- a/jscomp/core/js_fold.ml +++ b/jscomp/core/js_fold.ml @@ -28,7 +28,6 @@ method exports : exports -> 'self_type = o#unknown method tag_info : tag_info -> 'self_type = o#unknown method required_modules : required_modules -> 'self_type = o#list (fun o -> o#module_id) method property_name : property_name -> 'self_type = o#unknown -method jsint : jsint -> 'self_type = o#int32 method ident : ident -> 'self_type = o#unknown method module_id : module_id -> 'self_type = fun { id = _x0;kind = _x1} -> let o = o#ident _x0 in let o = o#unknown _x1 in o diff --git a/jscomp/core/js_fold_basic.ml b/jscomp/core/js_fold_basic.ml index 96191903ff..266ef8950e 100644 --- a/jscomp/core/js_fold_basic.ml +++ b/jscomp/core/js_fold_basic.ml @@ -24,36 +24,12 @@ -(* class count_deps (add : Ident.t -> unit ) = - object(self) - inherit Js_fold.fold as super - method! expression lam = - match lam.expression_desc with - | Fun (_, _, block, _) -> self#block block - (** Call - actually depends on parameter, - since closure - {[ - n = n - 1 - acc = () => n - ]} - should be - - {[ - acc = (function (n) {() => n} (n)) - n = n - 1 - ]} - *) - | _ -> super#expression lam - method! ident x = add x ; self - end *) let add_lam_module_ident = Lam_module_ident.Hash_set.add let create = Lam_module_ident.Hash_set.create -class count_hard_dependencies = +let count_hard_dependencies hard_dependencies = object(self : 'self_type) inherit Js_fold.fold as super - val hard_dependencies = create 17 method! module_id vid = add_lam_module_ident hard_dependencies vid; self method! expression x : 'self_type = @@ -65,11 +41,12 @@ class count_hard_dependencies = id) | _ -> ()); super#expression x - method get_hard_dependencies = hard_dependencies end let calculate_hard_dependencies block = - ((new count_hard_dependencies)#block block) # get_hard_dependencies + let hard_dependencies = create 17 in + let _ : Js_fold.fold = (count_hard_dependencies hard_dependencies)#block block in + hard_dependencies (* Given a set of [variables], count which variables [lam] will depend on diff --git a/jscomp/core/js_map.ml b/jscomp/core/js_map.ml index 93b48d8e7a..45e4478203 100644 --- a/jscomp/core/js_map.ml +++ b/jscomp/core/js_map.ml @@ -31,7 +31,6 @@ method exports : exports -> exports = o#unknown method tag_info : tag_info -> tag_info = o#unknown method required_modules : required_modules -> required_modules = o#list (fun o -> o#module_id) method property_name : property_name -> property_name = o#unknown -method jsint : jsint -> jsint = o#int32 method ident : ident -> ident = o#unknown method module_id : module_id -> module_id = fun { id = _x0;kind = _x1} -> let _x0 = o#ident _x0 in let _x1 = o#unknown _x1 in {id = _x0;kind = _x1} diff --git a/jscomp/core/js_of_lam_block.mli b/jscomp/core/js_of_lam_block.mli index 4741f9508f..73159f74ea 100644 --- a/jscomp/core/js_of_lam_block.mli +++ b/jscomp/core/js_of_lam_block.mli @@ -38,7 +38,7 @@ val make_block : val field : Lam_compat.field_dbg_info -> J.expression -> - J.jsint -> + int32 -> J.expression val field_by_exp : @@ -48,7 +48,7 @@ val field_by_exp : val set_field : Lam_compat.set_field_dbg_info -> - J.expression -> J.jsint -> J.expression -> J.expression + J.expression -> int32 -> J.expression -> J.expression val set_field_by_exp : J.expression -> diff --git a/jscomp/core/js_pass_flatten_and_mark_dead.ml b/jscomp/core/js_pass_flatten_and_mark_dead.ml index a48278a1af..48632126c4 100644 --- a/jscomp/core/js_pass_flatten_and_mark_dead.ml +++ b/jscomp/core/js_pass_flatten_and_mark_dead.ml @@ -32,34 +32,7 @@ module E = Js_exp_make module S = Js_stmt_make -(* class count var = object (self : 'self) - val mutable appears = 0 - inherit Js_fold.fold as super - method! ident x = - (if Ident.same x var then - appears <- appears + 1); - self - method get_appears = appears -end *) - -(* rewrite return for current block, but don't go into - inner function, mostly for inlinning - *) -(* class rewrite_return ?return_value ()= - let mk_return = - match return_value with - | None -> fun e -> S.exp e - | Some ident -> fun e -> - S.define_variable ~kind:Variable ident e in - object (self : 'self) - inherit Js_map.map as super - method! statement x = - match x.statement_desc with - | Return {return_value = e} -> - mk_return e - | _ -> super#statement x - method! expression x = x (* don't go inside *) - end *) + type meta_info = | Info of J.ident_info @@ -70,7 +43,7 @@ type meta_info = let mark_dead_code (js : J.program) : J.program = let ident_use_stats : meta_info Hash_ident.t = Hash_ident.create 17 in - let mark_dead = object (self) + let mark_dead : Js_fold.fold = object (self) inherit Js_fold.fold method! ident ident = (match Hash_ident.find_opt ident_use_stats ident with @@ -180,12 +153,12 @@ let mark_dead_code (js : J.program) : J.program = ]} *) -let subst_map () = object (self) +let subst_map (substitution : J.expression Hash_ident.t) = object (self) inherit Js_map.map as super - val mutable substitution : J.expression Hash_ident.t= Hash_ident.create 17 - method get_substitution = substitution + + method add_substitue (ident : Ident.t) (e:J.expression) = Hash_ident.replace substitution ident e @@ -264,7 +237,7 @@ let subst_map () = object (self) {expression_desc = Number (Int {i; _})}) | Static_index ({expression_desc = Var (Id (id))}, _, Some i) -> - (match Hash_ident.find_opt self#get_substitution id with + (match Hash_ident.find_opt substitution id with | Some {expression_desc = Caml_block (ls, Immutable, _, _) } -> (* user program can be wrong, we should not @@ -288,7 +261,7 @@ end let program (js : J.program) = js - |> (subst_map () )#program + |> (subst_map (Hash_ident.create 32) )#program |> mark_dead_code (* |> mark_dead_code *) (* mark dead code twice does have effect in some cases, however, we disabled it diff --git a/jscomp/core/js_pass_get_used.ml b/jscomp/core/js_pass_get_used.ml index fc4291ba34..0385090096 100644 --- a/jscomp/core/js_pass_get_used.ml +++ b/jscomp/core/js_pass_get_used.ml @@ -22,28 +22,41 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) - +let add_use stats id = + Hash_ident.add_or_update stats id 1 ~update:succ +let post_process_stats my_export_set (defined_idents : J.variable_declaration Hash_ident.t) stats = + Hash_ident.iter defined_idents (fun ident v -> + if Set_ident.mem my_export_set ident then + Js_op_util.update_used_stats v.ident_info Exported + else + let pure = + match v.value with + | None -> false (* can not happen *) + | Some x -> Js_analyzer.no_side_effect_expression x in + match Hash_ident.find_opt stats ident with + | None -> + Js_op_util.update_used_stats v.ident_info + (if pure then Dead_pure else Dead_non_pure) + | Some num -> + if num = 1 then + Js_op_util.update_used_stats v.ident_info + (if pure then Once_pure else Used) + ) ; defined_idents (** Update ident info use cases, it is a non pure function, it will annotate [program] with some meta data TODO: Ident Hash could be improved, since in this case it can not be global? *) -let count_collects () = +let count_collects + (* collect used status*) + (stats : int Hash_ident.t) + (* collect all def sites *) + (defined_idents : J.variable_declaration Hash_ident.t) : Js_fold.fold + = object (self) - inherit Js_fold.fold as super - (* collect used status*) - val stats : int Hash_ident.t = Hash_ident.create 83 - (* collect all def sites *) - val defined_idents : J.variable_declaration Hash_ident.t = Hash_ident.create 83 - - val mutable my_export_set : Set_ident.t = Set_ident.empty - - method add_use id = - Hash_ident.add_or_update stats id 1 ~update:succ - method! program x = - my_export_set <- x.export_set ; - super#program x + inherit Js_fold.fold + method! variable_declaration ({ident; value ; property = _ ; ident_info = _} as v) = @@ -53,28 +66,15 @@ let count_collects () = self | Some x -> self#expression x - method! ident id = self#add_use id; self - method get_stats = - Hash_ident.iter defined_idents (fun ident v -> - if Set_ident.mem my_export_set ident then - Js_op_util.update_used_stats v.ident_info Exported - else - let pure = - match v.value with - | None -> false (* can not happen *) - | Some x -> Js_analyzer.no_side_effect_expression x in - match Hash_ident.find_opt stats ident with - | None -> - Js_op_util.update_used_stats v.ident_info - (if pure then Dead_pure else Dead_non_pure) - | Some num -> - if num = 1 then - Js_op_util.update_used_stats v.ident_info - (if pure then Once_pure else Used) - ) ; defined_idents + method! ident id = add_use stats id; self + end let get_stats (program : J.program) : J.variable_declaration Hash_ident.t - = ((count_collects ()) #program program) #get_stats - \ No newline at end of file + = + let stats : int Hash_ident.t = Hash_ident.create 83 in + let defined_idents : J.variable_declaration Hash_ident.t = Hash_ident.create 83 in + let my_export_set = program.export_set in + let _ : Js_fold.fold = (count_collects stats defined_idents) #program program in + post_process_stats my_export_set defined_idents stats diff --git a/jscomp/core/js_shake.ml b/jscomp/core/js_shake.ml index 9f865e4a79..3827b4fcfb 100644 --- a/jscomp/core/js_shake.ml +++ b/jscomp/core/js_shake.ml @@ -46,7 +46,7 @@ let get_initial_exports TODO: add hashtbl for a cache *) Set_ident.( - union (Js_analyzer.free_variables_of_expression empty empty x) acc) + union (Js_analyzer.free_variables_of_expression x) acc) end else begin match value with @@ -55,14 +55,14 @@ let get_initial_exports if Js_analyzer.no_side_effect_expression x then acc else Set_ident.( - union (Js_analyzer.free_variables_of_expression empty empty x) + union (Js_analyzer.free_variables_of_expression x) (add acc ident)) end | _ -> (* recalcuate again and again ... *) if Js_analyzer.no_side_effect_statement st || (not count_non_variable_declaration_statement) then acc - else Set_ident.(union (Js_analyzer.free_variables_of_statement empty empty st) acc) + else Set_ident.(union (Js_analyzer.free_variables_of_statement st) acc) ) in result, Set_ident.(diff result export_set) let shake_program (program : J.program) = diff --git a/jscomp/tools/js_pass_beta.ml b/jscomp/tools/js_pass_beta.ml deleted file mode 100644 index 4a5b3db9df..0000000000 --- a/jscomp/tools/js_pass_beta.ml +++ /dev/null @@ -1,134 +0,0 @@ -(* Copyright (C) 2015-2016 Bloomberg Finance L.P. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * In addition to the permissions granted to you by the LGPL, you may combine - * or link a "work that uses the Library" with a publicly distributed version - * of this file to produce a combined library or application, then distribute - * that combined work under the terms of your choosing, with no requirement - * to comply with the obligations normally placed on you by section 4 of the - * LGPL version 3 (or the corresponding section of a later version of the LGPL - * should you choose to use a later version). - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) - - - - - - -(* When we inline a function call, if we don't do a beta-reduction immediately, there is - a chance that it is ignored, (we can not assume that each pass is robust enough) - - After we do inlining, it makes sense to do another constant folding and propogation - *) - -(* Check: shall we inline functions with while loop? if it is used only once, - it makes sense to inline it -*) - -module S = Js_stmt_make -module E = Js_exp_make - - -(** Update ident info use cases, it is a non pure function, - it will annotate [program] with some meta data - TODO: Ident Hash could be improved, - since in this case it can not be global? - - *) - -type inline_state = - | False - | Inline_ignore of bool (*indicate whether use [break] to replace [return] or not *) - | Inline_ret of J.expression * bool - | Inline_return - -let pass_beta = - object (self) - inherit Js_map.map as super - val inline_state = False - method with_inline_state x = - {} - method! block bs = - match bs with - | {statement_desc = Block bs ; _} :: rest - -> - self#block (bs @ rest ) - | {statement_desc = Exp ( - {expression_desc = Call ( - {expression_desc = Fun (false, params, body, env) }, - args, _info) ; _ }) ; _ } :: rest (* TODO: don't inline tailcall for method yet*) - when Ext_list.same_length args params -> - let body = self#block body in - (Ext_list.fold_right2 - (fun p a acc -> - S.define ~kind:Variable p a :: acc) params args - ((self#with_inline_state (Inline_ignore (Js_fun_env.is_tailcalled env))) #block body) ) @ - (self#block rest) - | {statement_desc = Exp ( - {expression_desc = Bin (Eq, - e, - {expression_desc = Call ( - {expression_desc = Fun (false, params, body, env) }, - args, _info) ; _ }); _ - }) ; _ } :: rest when Ext_list.same_length args params -> - - let body = self#block body in - (Ext_list.fold_right2 - (fun p a acc -> - S.define ~kind:Variable p a :: acc) params args - ((self#with_inline_state (Inline_ret (e, Js_fun_env.is_tailcalled env))) #block body) ) @ - (self#block rest) - - | {statement_desc = Return ( - {return_value = {expression_desc = Call ( - {expression_desc = Fun (false,params, body, _) }, - args, _info) ; _ }}) ; _ } :: rest - when Ext_list.same_length args params -> - let body = self#block body in - (Ext_list.fold_right2 - (fun p a acc -> - S.define ~kind:Variable p a :: acc) params args - ((self#with_inline_state Inline_return) #block body)) @ - (self#block rest) - - | {statement_desc = Return {return_value = e} } as st :: rest - -> - begin match inline_state with - | False - -> self#statement st :: self#block rest - | Inline_ignore b - -> - S.exp (self#expression e) :: - (if b then S.break () :: self#block rest else self#block rest) - | Inline_ret (v,b) -> - S.exp (E.assign v (self#expression e)) :: - (if b then S.break () :: self#block rest else self#block rest) - | Inline_return - -> - S.return_stmt (self#expression e ) :: self#block rest - end - | x :: xs -> self#statement x :: self#block xs - | [] -> [] - method! expression e = - match e.expression_desc with - | Fun (params, body,env) -> - (** only partial information of env is wrong, needs to be recomputed again, - but we can not simply discard it - *) - {e with expression_desc = Fun (params, ({< inline_state = False >}# block body), env)} - - (** so that we will not have inner [Return] *) - | _ -> super#expression e - end diff --git a/jscomp/tools/js_pass_beta.mli b/jscomp/tools/js_pass_beta.mli deleted file mode 100644 index 6d5613cf17..0000000000 --- a/jscomp/tools/js_pass_beta.mli +++ /dev/null @@ -1,30 +0,0 @@ -(* Copyright (C) 2015-2016 Bloomberg Finance L.P. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * In addition to the permissions granted to you by the LGPL, you may combine - * or link a "work that uses the Library" with a publicly distributed version - * of this file to produce a combined library or application, then distribute - * that combined work under the terms of your choosing, with no requirement - * to comply with the obligations normally placed on you by section 4 of the - * LGPL version 3 (or the corresponding section of a later version of the LGPL - * should you choose to use a later version). - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) - - - - - - -(** *) diff --git a/lib/4.06.1/unstable/js_compiler.ml b/lib/4.06.1/unstable/js_compiler.ml index 8aa760af74..2e0d8ceceb 100644 --- a/lib/4.06.1/unstable/js_compiler.ml +++ b/lib/4.06.1/unstable/js_compiler.ml @@ -85753,7 +85753,7 @@ end module J = struct #1 "j.ml" -(* Copyright (C) 2015-2016 Bloomberg Finance L.P. +(* Copyright (C) 2015- Authors of ReScript * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -85825,7 +85825,6 @@ and required_modules = module_id list currently we always use quote *) and property_name = Js_op.property_name -and jsint = int32 and ident = Ident.t and module_id = { id : ident; kind : Js_op.kind @@ -86535,7 +86534,6 @@ method exports : exports -> 'self_type = o#unknown method tag_info : tag_info -> 'self_type = o#unknown method required_modules : required_modules -> 'self_type = o#list (fun o -> o#module_id) method property_name : property_name -> 'self_type = o#unknown -method jsint : jsint -> 'self_type = o#int32 method ident : ident -> 'self_type = o#unknown method module_id : module_id -> 'self_type = fun { id = _x0;kind = _x1} -> let o = o#ident _x0 in let o = o#unknown _x1 in o @@ -86985,10 +86983,10 @@ module Js_analyzer : sig *) val free_variables_of_statement : - Set_ident.t -> Set_ident.t -> J.statement -> Set_ident.t + J.statement -> Set_ident.t val free_variables_of_expression : - Set_ident.t -> Set_ident.t -> J.finish_ident_expression -> Set_ident.t + J.finish_ident_expression -> Set_ident.t (* val no_side_effect_expression_desc : J.expression_desc -> bool *) @@ -87070,7 +87068,13 @@ end = struct +type idents_stats = { + mutable used_idents : Set_ident.t ; + mutable defined_idents : Set_ident.t; +} +let add_defined_idents (x : idents_stats) ident = + x.defined_idents <- Set_ident.add x.defined_idents ident (* Assume that functions already calculated closure correctly Maybe in the future, we should add a dirty flag, to mark the calcuated @@ -87079,22 +87083,21 @@ end = struct Note such shaking is done in the toplevel, so that it requires us to flatten the statement first *) -let free_variables used_idents defined_idents = +let free_variables (stats : idents_stats) : Js_fold.fold = object (self) inherit Js_fold.fold as super - val defined_idents = defined_idents - val used_idents = used_idents method! variable_declaration st = - match st with - | { ident; value = None} - -> - {< defined_idents = Set_ident.add defined_idents ident >} - | { ident; value = Some v} + add_defined_idents stats st.ident; + match st.value with + | None + -> self + | Some v -> - {< defined_idents = Set_ident.add defined_idents ident >} # expression v + self # expression v method! ident id = - if Set_ident.mem defined_idents id then self - else {} + (if not (Set_ident.mem stats.defined_idents id )then + stats.used_idents <- Set_ident.add stats.used_idents id); + self method! expression exp = match exp.expression_desc with @@ -87103,24 +87106,26 @@ let free_variables used_idents defined_idents = if it's already comuted *) -> - {< used_idents = - Set_ident.union (Js_fun_env.get_unbounded env) used_idents >} + stats.used_idents <- + Set_ident.union (Js_fun_env.get_unbounded env) stats.used_idents; + self | _ -> super#expression exp - - method get_depenencies = - Set_ident.diff used_idents defined_idents - method get_used_idents = used_idents - method get_defined_idents = defined_idents end -let free_variables_of_statement used_idents defined_idents st = - ((free_variables used_idents defined_idents)#statement st) # get_depenencies +let free_variables_of_statement st = + let init = {used_idents = Set_ident.empty; + defined_idents = Set_ident.empty} in + let _ = (free_variables init)#statement st in + Set_ident.diff init.used_idents init.defined_idents -let free_variables_of_expression used_idents defined_idents st = - ((free_variables used_idents defined_idents)#expression st) # get_depenencies +let free_variables_of_expression st = + let init = {used_idents = Set_ident.empty; + defined_idents = Set_ident.empty} in + let _ = (free_variables init)#expression st in + Set_ident.diff init.used_idents init.defined_idents let rec no_side_effect_expression_desc (x : J.expression_desc) = match x with @@ -87174,33 +87179,33 @@ and no_side_effect (x : J.expression) = let no_side_effect_expression (x : J.expression) = no_side_effect x -let no_side_effect init = +let no_side_effect clean : Js_fold.fold = object (self) inherit Js_fold.fold as super - val no_side_effect = init - method get_no_side_effect = no_side_effect - method! statement s = - if not no_side_effect then self else + if not !clean then self else match s.statement_desc with | Throw _ | Debugger | Break | Variable _ | Continue _ -> - {< no_side_effect = false>} + clean := false ; self | Exp e -> self#expression e | Int_switch _ | String_switch _ | ForRange _ | If _ | While _ | Block _ | Return _ | Try _ -> super#statement s method! list f x = - if not self#get_no_side_effect then self else super#list f x + if not !clean then self else super#list f x method! expression s = - if not no_side_effect then self - else {< no_side_effect = no_side_effect_expression s >} - + (if !clean then + clean := no_side_effect_expression s); + self (** only expression would cause side effec *) end -let no_side_effect_statement st = ((no_side_effect true)#statement st)#get_no_side_effect +let no_side_effect_statement st = + let clean = ref true in + let _ : Js_fold.fold = ((no_side_effect clean)#statement st) in + !clean (* TODO: generate [fold2] This make sense, for example: @@ -99247,36 +99252,12 @@ end = struct -(* class count_deps (add : Ident.t -> unit ) = - object(self) - inherit Js_fold.fold as super - method! expression lam = - match lam.expression_desc with - | Fun (_, _, block, _) -> self#block block - (** Call - actually depends on parameter, - since closure - {[ - n = n - 1 - acc = () => n - ]} - should be - - {[ - acc = (function (n) {() => n} (n)) - n = n - 1 - ]} - *) - | _ -> super#expression lam - method! ident x = add x ; self - end *) let add_lam_module_ident = Lam_module_ident.Hash_set.add let create = Lam_module_ident.Hash_set.create -class count_hard_dependencies = +let count_hard_dependencies hard_dependencies = object(self : 'self_type) inherit Js_fold.fold as super - val hard_dependencies = create 17 method! module_id vid = add_lam_module_ident hard_dependencies vid; self method! expression x : 'self_type = @@ -99288,11 +99269,12 @@ class count_hard_dependencies = id) | _ -> ()); super#expression x - method get_hard_dependencies = hard_dependencies end let calculate_hard_dependencies block = - ((new count_hard_dependencies)#block block) # get_hard_dependencies + let hard_dependencies = create 17 in + let _ : Js_fold.fold = (count_hard_dependencies hard_dependencies)#block block in + hard_dependencies (* Given a set of [variables], count which variables [lam] will depend on @@ -101528,7 +101510,6 @@ method exports : exports -> exports = o#unknown method tag_info : tag_info -> tag_info = o#unknown method required_modules : required_modules -> required_modules = o#list (fun o -> o#module_id) method property_name : property_name -> property_name = o#unknown -method jsint : jsint -> jsint = o#int32 method ident : ident -> ident = o#unknown method module_id : module_id -> module_id = fun { id = _x0;kind = _x1} -> let _x0 = o#ident _x0 in let _x1 = o#unknown _x1 in {id = _x0;kind = _x1} @@ -101963,34 +101944,7 @@ end = struct module E = Js_exp_make module S = Js_stmt_make -(* class count var = object (self : 'self) - val mutable appears = 0 - inherit Js_fold.fold as super - method! ident x = - (if Ident.same x var then - appears <- appears + 1); - self - method get_appears = appears -end *) - -(* rewrite return for current block, but don't go into - inner function, mostly for inlinning - *) -(* class rewrite_return ?return_value ()= - let mk_return = - match return_value with - | None -> fun e -> S.exp e - | Some ident -> fun e -> - S.define_variable ~kind:Variable ident e in - object (self : 'self) - inherit Js_map.map as super - method! statement x = - match x.statement_desc with - | Return {return_value = e} -> - mk_return e - | _ -> super#statement x - method! expression x = x (* don't go inside *) - end *) + type meta_info = | Info of J.ident_info @@ -102001,7 +101955,7 @@ type meta_info = let mark_dead_code (js : J.program) : J.program = let ident_use_stats : meta_info Hash_ident.t = Hash_ident.create 17 in - let mark_dead = object (self) + let mark_dead : Js_fold.fold = object (self) inherit Js_fold.fold method! ident ident = (match Hash_ident.find_opt ident_use_stats ident with @@ -102111,12 +102065,12 @@ let mark_dead_code (js : J.program) : J.program = ]} *) -let subst_map () = object (self) +let subst_map (substitution : J.expression Hash_ident.t) = object (self) inherit Js_map.map as super - val mutable substitution : J.expression Hash_ident.t= Hash_ident.create 17 - method get_substitution = substitution + + method add_substitue (ident : Ident.t) (e:J.expression) = Hash_ident.replace substitution ident e @@ -102195,7 +102149,7 @@ let subst_map () = object (self) {expression_desc = Number (Int {i; _})}) | Static_index ({expression_desc = Var (Id (id))}, _, Some i) -> - (match Hash_ident.find_opt self#get_substitution id with + (match Hash_ident.find_opt substitution id with | Some {expression_desc = Caml_block (ls, Immutable, _, _) } -> (* user program can be wrong, we should not @@ -102219,7 +102173,7 @@ end let program (js : J.program) = js - |> (subst_map () )#program + |> (subst_map (Hash_ident.create 32) )#program |> mark_dead_code (* |> mark_dead_code *) (* mark dead code twice does have effect in some cases, however, we disabled it @@ -102648,28 +102602,41 @@ end = struct * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) - +let add_use stats id = + Hash_ident.add_or_update stats id 1 ~update:succ +let post_process_stats my_export_set (defined_idents : J.variable_declaration Hash_ident.t) stats = + Hash_ident.iter defined_idents (fun ident v -> + if Set_ident.mem my_export_set ident then + Js_op_util.update_used_stats v.ident_info Exported + else + let pure = + match v.value with + | None -> false (* can not happen *) + | Some x -> Js_analyzer.no_side_effect_expression x in + match Hash_ident.find_opt stats ident with + | None -> + Js_op_util.update_used_stats v.ident_info + (if pure then Dead_pure else Dead_non_pure) + | Some num -> + if num = 1 then + Js_op_util.update_used_stats v.ident_info + (if pure then Once_pure else Used) + ) ; defined_idents (** Update ident info use cases, it is a non pure function, it will annotate [program] with some meta data TODO: Ident Hash could be improved, since in this case it can not be global? *) -let count_collects () = +let count_collects + (* collect used status*) + (stats : int Hash_ident.t) + (* collect all def sites *) + (defined_idents : J.variable_declaration Hash_ident.t) : Js_fold.fold + = object (self) - inherit Js_fold.fold as super - (* collect used status*) - val stats : int Hash_ident.t = Hash_ident.create 83 - (* collect all def sites *) - val defined_idents : J.variable_declaration Hash_ident.t = Hash_ident.create 83 - - val mutable my_export_set : Set_ident.t = Set_ident.empty - - method add_use id = - Hash_ident.add_or_update stats id 1 ~update:succ - method! program x = - my_export_set <- x.export_set ; - super#program x + inherit Js_fold.fold + method! variable_declaration ({ident; value ; property = _ ; ident_info = _} as v) = @@ -102679,31 +102646,19 @@ let count_collects () = self | Some x -> self#expression x - method! ident id = self#add_use id; self - method get_stats = - Hash_ident.iter defined_idents (fun ident v -> - if Set_ident.mem my_export_set ident then - Js_op_util.update_used_stats v.ident_info Exported - else - let pure = - match v.value with - | None -> false (* can not happen *) - | Some x -> Js_analyzer.no_side_effect_expression x in - match Hash_ident.find_opt stats ident with - | None -> - Js_op_util.update_used_stats v.ident_info - (if pure then Dead_pure else Dead_non_pure) - | Some num -> - if num = 1 then - Js_op_util.update_used_stats v.ident_info - (if pure then Once_pure else Used) - ) ; defined_idents + method! ident id = add_use stats id; self + end let get_stats (program : J.program) : J.variable_declaration Hash_ident.t - = ((count_collects ()) #program program) #get_stats - + = + let stats : int Hash_ident.t = Hash_ident.create 83 in + let defined_idents : J.variable_declaration Hash_ident.t = Hash_ident.create 83 in + let my_export_set = program.export_set in + let _ : Js_fold.fold = (count_collects stats defined_idents) #program program in + post_process_stats my_export_set defined_idents stats + end module Js_pass_tailcall_inline : sig #1 "js_pass_tailcall_inline.mli" @@ -103070,7 +103025,7 @@ let get_initial_exports TODO: add hashtbl for a cache *) Set_ident.( - union (Js_analyzer.free_variables_of_expression empty empty x) acc) + union (Js_analyzer.free_variables_of_expression x) acc) end else begin match value with @@ -103079,14 +103034,14 @@ let get_initial_exports if Js_analyzer.no_side_effect_expression x then acc else Set_ident.( - union (Js_analyzer.free_variables_of_expression empty empty x) + union (Js_analyzer.free_variables_of_expression x) (add acc ident)) end | _ -> (* recalcuate again and again ... *) if Js_analyzer.no_side_effect_statement st || (not count_non_variable_declaration_statement) then acc - else Set_ident.(union (Js_analyzer.free_variables_of_statement empty empty st) acc) + else Set_ident.(union (Js_analyzer.free_variables_of_statement st) acc) ) in result, Set_ident.(diff result export_set) let shake_program (program : J.program) = @@ -106028,7 +105983,7 @@ val make_block : val field : Lam_compat.field_dbg_info -> J.expression -> - J.jsint -> + int32 -> J.expression val field_by_exp : @@ -106038,7 +105993,7 @@ val field_by_exp : val set_field : Lam_compat.set_field_dbg_info -> - J.expression -> J.jsint -> J.expression -> J.expression + J.expression -> int32 -> J.expression -> J.expression val set_field_by_exp : J.expression -> diff --git a/lib/4.06.1/unstable/js_refmt_compiler.ml b/lib/4.06.1/unstable/js_refmt_compiler.ml index a032d294a9..9c990d4171 100644 --- a/lib/4.06.1/unstable/js_refmt_compiler.ml +++ b/lib/4.06.1/unstable/js_refmt_compiler.ml @@ -85753,7 +85753,7 @@ end module J = struct #1 "j.ml" -(* Copyright (C) 2015-2016 Bloomberg Finance L.P. +(* Copyright (C) 2015- Authors of ReScript * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -85825,7 +85825,6 @@ and required_modules = module_id list currently we always use quote *) and property_name = Js_op.property_name -and jsint = int32 and ident = Ident.t and module_id = { id : ident; kind : Js_op.kind @@ -86535,7 +86534,6 @@ method exports : exports -> 'self_type = o#unknown method tag_info : tag_info -> 'self_type = o#unknown method required_modules : required_modules -> 'self_type = o#list (fun o -> o#module_id) method property_name : property_name -> 'self_type = o#unknown -method jsint : jsint -> 'self_type = o#int32 method ident : ident -> 'self_type = o#unknown method module_id : module_id -> 'self_type = fun { id = _x0;kind = _x1} -> let o = o#ident _x0 in let o = o#unknown _x1 in o @@ -86985,10 +86983,10 @@ module Js_analyzer : sig *) val free_variables_of_statement : - Set_ident.t -> Set_ident.t -> J.statement -> Set_ident.t + J.statement -> Set_ident.t val free_variables_of_expression : - Set_ident.t -> Set_ident.t -> J.finish_ident_expression -> Set_ident.t + J.finish_ident_expression -> Set_ident.t (* val no_side_effect_expression_desc : J.expression_desc -> bool *) @@ -87070,7 +87068,13 @@ end = struct +type idents_stats = { + mutable used_idents : Set_ident.t ; + mutable defined_idents : Set_ident.t; +} +let add_defined_idents (x : idents_stats) ident = + x.defined_idents <- Set_ident.add x.defined_idents ident (* Assume that functions already calculated closure correctly Maybe in the future, we should add a dirty flag, to mark the calcuated @@ -87079,22 +87083,21 @@ end = struct Note such shaking is done in the toplevel, so that it requires us to flatten the statement first *) -let free_variables used_idents defined_idents = +let free_variables (stats : idents_stats) : Js_fold.fold = object (self) inherit Js_fold.fold as super - val defined_idents = defined_idents - val used_idents = used_idents method! variable_declaration st = - match st with - | { ident; value = None} - -> - {< defined_idents = Set_ident.add defined_idents ident >} - | { ident; value = Some v} + add_defined_idents stats st.ident; + match st.value with + | None + -> self + | Some v -> - {< defined_idents = Set_ident.add defined_idents ident >} # expression v + self # expression v method! ident id = - if Set_ident.mem defined_idents id then self - else {} + (if not (Set_ident.mem stats.defined_idents id )then + stats.used_idents <- Set_ident.add stats.used_idents id); + self method! expression exp = match exp.expression_desc with @@ -87103,24 +87106,26 @@ let free_variables used_idents defined_idents = if it's already comuted *) -> - {< used_idents = - Set_ident.union (Js_fun_env.get_unbounded env) used_idents >} + stats.used_idents <- + Set_ident.union (Js_fun_env.get_unbounded env) stats.used_idents; + self | _ -> super#expression exp - - method get_depenencies = - Set_ident.diff used_idents defined_idents - method get_used_idents = used_idents - method get_defined_idents = defined_idents end -let free_variables_of_statement used_idents defined_idents st = - ((free_variables used_idents defined_idents)#statement st) # get_depenencies +let free_variables_of_statement st = + let init = {used_idents = Set_ident.empty; + defined_idents = Set_ident.empty} in + let _ = (free_variables init)#statement st in + Set_ident.diff init.used_idents init.defined_idents -let free_variables_of_expression used_idents defined_idents st = - ((free_variables used_idents defined_idents)#expression st) # get_depenencies +let free_variables_of_expression st = + let init = {used_idents = Set_ident.empty; + defined_idents = Set_ident.empty} in + let _ = (free_variables init)#expression st in + Set_ident.diff init.used_idents init.defined_idents let rec no_side_effect_expression_desc (x : J.expression_desc) = match x with @@ -87174,33 +87179,33 @@ and no_side_effect (x : J.expression) = let no_side_effect_expression (x : J.expression) = no_side_effect x -let no_side_effect init = +let no_side_effect clean : Js_fold.fold = object (self) inherit Js_fold.fold as super - val no_side_effect = init - method get_no_side_effect = no_side_effect - method! statement s = - if not no_side_effect then self else + if not !clean then self else match s.statement_desc with | Throw _ | Debugger | Break | Variable _ | Continue _ -> - {< no_side_effect = false>} + clean := false ; self | Exp e -> self#expression e | Int_switch _ | String_switch _ | ForRange _ | If _ | While _ | Block _ | Return _ | Try _ -> super#statement s method! list f x = - if not self#get_no_side_effect then self else super#list f x + if not !clean then self else super#list f x method! expression s = - if not no_side_effect then self - else {< no_side_effect = no_side_effect_expression s >} - + (if !clean then + clean := no_side_effect_expression s); + self (** only expression would cause side effec *) end -let no_side_effect_statement st = ((no_side_effect true)#statement st)#get_no_side_effect +let no_side_effect_statement st = + let clean = ref true in + let _ : Js_fold.fold = ((no_side_effect clean)#statement st) in + !clean (* TODO: generate [fold2] This make sense, for example: @@ -99247,36 +99252,12 @@ end = struct -(* class count_deps (add : Ident.t -> unit ) = - object(self) - inherit Js_fold.fold as super - method! expression lam = - match lam.expression_desc with - | Fun (_, _, block, _) -> self#block block - (** Call - actually depends on parameter, - since closure - {[ - n = n - 1 - acc = () => n - ]} - should be - - {[ - acc = (function (n) {() => n} (n)) - n = n - 1 - ]} - *) - | _ -> super#expression lam - method! ident x = add x ; self - end *) let add_lam_module_ident = Lam_module_ident.Hash_set.add let create = Lam_module_ident.Hash_set.create -class count_hard_dependencies = +let count_hard_dependencies hard_dependencies = object(self : 'self_type) inherit Js_fold.fold as super - val hard_dependencies = create 17 method! module_id vid = add_lam_module_ident hard_dependencies vid; self method! expression x : 'self_type = @@ -99288,11 +99269,12 @@ class count_hard_dependencies = id) | _ -> ()); super#expression x - method get_hard_dependencies = hard_dependencies end let calculate_hard_dependencies block = - ((new count_hard_dependencies)#block block) # get_hard_dependencies + let hard_dependencies = create 17 in + let _ : Js_fold.fold = (count_hard_dependencies hard_dependencies)#block block in + hard_dependencies (* Given a set of [variables], count which variables [lam] will depend on @@ -101528,7 +101510,6 @@ method exports : exports -> exports = o#unknown method tag_info : tag_info -> tag_info = o#unknown method required_modules : required_modules -> required_modules = o#list (fun o -> o#module_id) method property_name : property_name -> property_name = o#unknown -method jsint : jsint -> jsint = o#int32 method ident : ident -> ident = o#unknown method module_id : module_id -> module_id = fun { id = _x0;kind = _x1} -> let _x0 = o#ident _x0 in let _x1 = o#unknown _x1 in {id = _x0;kind = _x1} @@ -101963,34 +101944,7 @@ end = struct module E = Js_exp_make module S = Js_stmt_make -(* class count var = object (self : 'self) - val mutable appears = 0 - inherit Js_fold.fold as super - method! ident x = - (if Ident.same x var then - appears <- appears + 1); - self - method get_appears = appears -end *) - -(* rewrite return for current block, but don't go into - inner function, mostly for inlinning - *) -(* class rewrite_return ?return_value ()= - let mk_return = - match return_value with - | None -> fun e -> S.exp e - | Some ident -> fun e -> - S.define_variable ~kind:Variable ident e in - object (self : 'self) - inherit Js_map.map as super - method! statement x = - match x.statement_desc with - | Return {return_value = e} -> - mk_return e - | _ -> super#statement x - method! expression x = x (* don't go inside *) - end *) + type meta_info = | Info of J.ident_info @@ -102001,7 +101955,7 @@ type meta_info = let mark_dead_code (js : J.program) : J.program = let ident_use_stats : meta_info Hash_ident.t = Hash_ident.create 17 in - let mark_dead = object (self) + let mark_dead : Js_fold.fold = object (self) inherit Js_fold.fold method! ident ident = (match Hash_ident.find_opt ident_use_stats ident with @@ -102111,12 +102065,12 @@ let mark_dead_code (js : J.program) : J.program = ]} *) -let subst_map () = object (self) +let subst_map (substitution : J.expression Hash_ident.t) = object (self) inherit Js_map.map as super - val mutable substitution : J.expression Hash_ident.t= Hash_ident.create 17 - method get_substitution = substitution + + method add_substitue (ident : Ident.t) (e:J.expression) = Hash_ident.replace substitution ident e @@ -102195,7 +102149,7 @@ let subst_map () = object (self) {expression_desc = Number (Int {i; _})}) | Static_index ({expression_desc = Var (Id (id))}, _, Some i) -> - (match Hash_ident.find_opt self#get_substitution id with + (match Hash_ident.find_opt substitution id with | Some {expression_desc = Caml_block (ls, Immutable, _, _) } -> (* user program can be wrong, we should not @@ -102219,7 +102173,7 @@ end let program (js : J.program) = js - |> (subst_map () )#program + |> (subst_map (Hash_ident.create 32) )#program |> mark_dead_code (* |> mark_dead_code *) (* mark dead code twice does have effect in some cases, however, we disabled it @@ -102648,28 +102602,41 @@ end = struct * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) - +let add_use stats id = + Hash_ident.add_or_update stats id 1 ~update:succ +let post_process_stats my_export_set (defined_idents : J.variable_declaration Hash_ident.t) stats = + Hash_ident.iter defined_idents (fun ident v -> + if Set_ident.mem my_export_set ident then + Js_op_util.update_used_stats v.ident_info Exported + else + let pure = + match v.value with + | None -> false (* can not happen *) + | Some x -> Js_analyzer.no_side_effect_expression x in + match Hash_ident.find_opt stats ident with + | None -> + Js_op_util.update_used_stats v.ident_info + (if pure then Dead_pure else Dead_non_pure) + | Some num -> + if num = 1 then + Js_op_util.update_used_stats v.ident_info + (if pure then Once_pure else Used) + ) ; defined_idents (** Update ident info use cases, it is a non pure function, it will annotate [program] with some meta data TODO: Ident Hash could be improved, since in this case it can not be global? *) -let count_collects () = +let count_collects + (* collect used status*) + (stats : int Hash_ident.t) + (* collect all def sites *) + (defined_idents : J.variable_declaration Hash_ident.t) : Js_fold.fold + = object (self) - inherit Js_fold.fold as super - (* collect used status*) - val stats : int Hash_ident.t = Hash_ident.create 83 - (* collect all def sites *) - val defined_idents : J.variable_declaration Hash_ident.t = Hash_ident.create 83 - - val mutable my_export_set : Set_ident.t = Set_ident.empty - - method add_use id = - Hash_ident.add_or_update stats id 1 ~update:succ - method! program x = - my_export_set <- x.export_set ; - super#program x + inherit Js_fold.fold + method! variable_declaration ({ident; value ; property = _ ; ident_info = _} as v) = @@ -102679,31 +102646,19 @@ let count_collects () = self | Some x -> self#expression x - method! ident id = self#add_use id; self - method get_stats = - Hash_ident.iter defined_idents (fun ident v -> - if Set_ident.mem my_export_set ident then - Js_op_util.update_used_stats v.ident_info Exported - else - let pure = - match v.value with - | None -> false (* can not happen *) - | Some x -> Js_analyzer.no_side_effect_expression x in - match Hash_ident.find_opt stats ident with - | None -> - Js_op_util.update_used_stats v.ident_info - (if pure then Dead_pure else Dead_non_pure) - | Some num -> - if num = 1 then - Js_op_util.update_used_stats v.ident_info - (if pure then Once_pure else Used) - ) ; defined_idents + method! ident id = add_use stats id; self + end let get_stats (program : J.program) : J.variable_declaration Hash_ident.t - = ((count_collects ()) #program program) #get_stats - + = + let stats : int Hash_ident.t = Hash_ident.create 83 in + let defined_idents : J.variable_declaration Hash_ident.t = Hash_ident.create 83 in + let my_export_set = program.export_set in + let _ : Js_fold.fold = (count_collects stats defined_idents) #program program in + post_process_stats my_export_set defined_idents stats + end module Js_pass_tailcall_inline : sig #1 "js_pass_tailcall_inline.mli" @@ -103070,7 +103025,7 @@ let get_initial_exports TODO: add hashtbl for a cache *) Set_ident.( - union (Js_analyzer.free_variables_of_expression empty empty x) acc) + union (Js_analyzer.free_variables_of_expression x) acc) end else begin match value with @@ -103079,14 +103034,14 @@ let get_initial_exports if Js_analyzer.no_side_effect_expression x then acc else Set_ident.( - union (Js_analyzer.free_variables_of_expression empty empty x) + union (Js_analyzer.free_variables_of_expression x) (add acc ident)) end | _ -> (* recalcuate again and again ... *) if Js_analyzer.no_side_effect_statement st || (not count_non_variable_declaration_statement) then acc - else Set_ident.(union (Js_analyzer.free_variables_of_statement empty empty st) acc) + else Set_ident.(union (Js_analyzer.free_variables_of_statement st) acc) ) in result, Set_ident.(diff result export_set) let shake_program (program : J.program) = @@ -106028,7 +105983,7 @@ val make_block : val field : Lam_compat.field_dbg_info -> J.expression -> - J.jsint -> + int32 -> J.expression val field_by_exp : @@ -106038,7 +105993,7 @@ val field_by_exp : val set_field : Lam_compat.set_field_dbg_info -> - J.expression -> J.jsint -> J.expression -> J.expression + J.expression -> int32 -> J.expression -> J.expression val set_field_by_exp : J.expression -> diff --git a/lib/4.06.1/whole_compiler.ml b/lib/4.06.1/whole_compiler.ml index 164cac7245..59d58a59ba 100644 --- a/lib/4.06.1/whole_compiler.ml +++ b/lib/4.06.1/whole_compiler.ml @@ -369994,7 +369994,7 @@ end module J = struct #1 "j.ml" -(* Copyright (C) 2015-2016 Bloomberg Finance L.P. +(* Copyright (C) 2015- Authors of ReScript * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -370066,7 +370066,6 @@ and required_modules = module_id list currently we always use quote *) and property_name = Js_op.property_name -and jsint = int32 and ident = Ident.t and module_id = { id : ident; kind : Js_op.kind @@ -376402,7 +376401,6 @@ method exports : exports -> 'self_type = o#unknown method tag_info : tag_info -> 'self_type = o#unknown method required_modules : required_modules -> 'self_type = o#list (fun o -> o#module_id) method property_name : property_name -> 'self_type = o#unknown -method jsint : jsint -> 'self_type = o#int32 method ident : ident -> 'self_type = o#unknown method module_id : module_id -> 'self_type = fun { id = _x0;kind = _x1} -> let o = o#ident _x0 in let o = o#unknown _x1 in o @@ -376852,10 +376850,10 @@ module Js_analyzer : sig *) val free_variables_of_statement : - Set_ident.t -> Set_ident.t -> J.statement -> Set_ident.t + J.statement -> Set_ident.t val free_variables_of_expression : - Set_ident.t -> Set_ident.t -> J.finish_ident_expression -> Set_ident.t + J.finish_ident_expression -> Set_ident.t (* val no_side_effect_expression_desc : J.expression_desc -> bool *) @@ -376937,7 +376935,13 @@ end = struct +type idents_stats = { + mutable used_idents : Set_ident.t ; + mutable defined_idents : Set_ident.t; +} +let add_defined_idents (x : idents_stats) ident = + x.defined_idents <- Set_ident.add x.defined_idents ident (* Assume that functions already calculated closure correctly Maybe in the future, we should add a dirty flag, to mark the calcuated @@ -376946,22 +376950,21 @@ end = struct Note such shaking is done in the toplevel, so that it requires us to flatten the statement first *) -let free_variables used_idents defined_idents = +let free_variables (stats : idents_stats) : Js_fold.fold = object (self) inherit Js_fold.fold as super - val defined_idents = defined_idents - val used_idents = used_idents method! variable_declaration st = - match st with - | { ident; value = None} - -> - {< defined_idents = Set_ident.add defined_idents ident >} - | { ident; value = Some v} + add_defined_idents stats st.ident; + match st.value with + | None + -> self + | Some v -> - {< defined_idents = Set_ident.add defined_idents ident >} # expression v + self # expression v method! ident id = - if Set_ident.mem defined_idents id then self - else {} + (if not (Set_ident.mem stats.defined_idents id )then + stats.used_idents <- Set_ident.add stats.used_idents id); + self method! expression exp = match exp.expression_desc with @@ -376970,24 +376973,26 @@ let free_variables used_idents defined_idents = if it's already comuted *) -> - {< used_idents = - Set_ident.union (Js_fun_env.get_unbounded env) used_idents >} + stats.used_idents <- + Set_ident.union (Js_fun_env.get_unbounded env) stats.used_idents; + self | _ -> super#expression exp - - method get_depenencies = - Set_ident.diff used_idents defined_idents - method get_used_idents = used_idents - method get_defined_idents = defined_idents end -let free_variables_of_statement used_idents defined_idents st = - ((free_variables used_idents defined_idents)#statement st) # get_depenencies +let free_variables_of_statement st = + let init = {used_idents = Set_ident.empty; + defined_idents = Set_ident.empty} in + let _ = (free_variables init)#statement st in + Set_ident.diff init.used_idents init.defined_idents -let free_variables_of_expression used_idents defined_idents st = - ((free_variables used_idents defined_idents)#expression st) # get_depenencies +let free_variables_of_expression st = + let init = {used_idents = Set_ident.empty; + defined_idents = Set_ident.empty} in + let _ = (free_variables init)#expression st in + Set_ident.diff init.used_idents init.defined_idents let rec no_side_effect_expression_desc (x : J.expression_desc) = match x with @@ -377041,33 +377046,33 @@ and no_side_effect (x : J.expression) = let no_side_effect_expression (x : J.expression) = no_side_effect x -let no_side_effect init = +let no_side_effect clean : Js_fold.fold = object (self) inherit Js_fold.fold as super - val no_side_effect = init - method get_no_side_effect = no_side_effect - method! statement s = - if not no_side_effect then self else + if not !clean then self else match s.statement_desc with | Throw _ | Debugger | Break | Variable _ | Continue _ -> - {< no_side_effect = false>} + clean := false ; self | Exp e -> self#expression e | Int_switch _ | String_switch _ | ForRange _ | If _ | While _ | Block _ | Return _ | Try _ -> super#statement s method! list f x = - if not self#get_no_side_effect then self else super#list f x + if not !clean then self else super#list f x method! expression s = - if not no_side_effect then self - else {< no_side_effect = no_side_effect_expression s >} - + (if !clean then + clean := no_side_effect_expression s); + self (** only expression would cause side effec *) end -let no_side_effect_statement st = ((no_side_effect true)#statement st)#get_no_side_effect +let no_side_effect_statement st = + let clean = ref true in + let _ : Js_fold.fold = ((no_side_effect clean)#statement st) in + !clean (* TODO: generate [fold2] This make sense, for example: @@ -381729,36 +381734,12 @@ end = struct -(* class count_deps (add : Ident.t -> unit ) = - object(self) - inherit Js_fold.fold as super - method! expression lam = - match lam.expression_desc with - | Fun (_, _, block, _) -> self#block block - (** Call - actually depends on parameter, - since closure - {[ - n = n - 1 - acc = () => n - ]} - should be - - {[ - acc = (function (n) {() => n} (n)) - n = n - 1 - ]} - *) - | _ -> super#expression lam - method! ident x = add x ; self - end *) let add_lam_module_ident = Lam_module_ident.Hash_set.add let create = Lam_module_ident.Hash_set.create -class count_hard_dependencies = +let count_hard_dependencies hard_dependencies = object(self : 'self_type) inherit Js_fold.fold as super - val hard_dependencies = create 17 method! module_id vid = add_lam_module_ident hard_dependencies vid; self method! expression x : 'self_type = @@ -381770,11 +381751,12 @@ class count_hard_dependencies = id) | _ -> ()); super#expression x - method get_hard_dependencies = hard_dependencies end let calculate_hard_dependencies block = - ((new count_hard_dependencies)#block block) # get_hard_dependencies + let hard_dependencies = create 17 in + let _ : Js_fold.fold = (count_hard_dependencies hard_dependencies)#block block in + hard_dependencies (* Given a set of [variables], count which variables [lam] will depend on @@ -384010,7 +383992,6 @@ method exports : exports -> exports = o#unknown method tag_info : tag_info -> tag_info = o#unknown method required_modules : required_modules -> required_modules = o#list (fun o -> o#module_id) method property_name : property_name -> property_name = o#unknown -method jsint : jsint -> jsint = o#int32 method ident : ident -> ident = o#unknown method module_id : module_id -> module_id = fun { id = _x0;kind = _x1} -> let _x0 = o#ident _x0 in let _x1 = o#unknown _x1 in {id = _x0;kind = _x1} @@ -384445,34 +384426,7 @@ end = struct module E = Js_exp_make module S = Js_stmt_make -(* class count var = object (self : 'self) - val mutable appears = 0 - inherit Js_fold.fold as super - method! ident x = - (if Ident.same x var then - appears <- appears + 1); - self - method get_appears = appears -end *) - -(* rewrite return for current block, but don't go into - inner function, mostly for inlinning - *) -(* class rewrite_return ?return_value ()= - let mk_return = - match return_value with - | None -> fun e -> S.exp e - | Some ident -> fun e -> - S.define_variable ~kind:Variable ident e in - object (self : 'self) - inherit Js_map.map as super - method! statement x = - match x.statement_desc with - | Return {return_value = e} -> - mk_return e - | _ -> super#statement x - method! expression x = x (* don't go inside *) - end *) + type meta_info = | Info of J.ident_info @@ -384483,7 +384437,7 @@ type meta_info = let mark_dead_code (js : J.program) : J.program = let ident_use_stats : meta_info Hash_ident.t = Hash_ident.create 17 in - let mark_dead = object (self) + let mark_dead : Js_fold.fold = object (self) inherit Js_fold.fold method! ident ident = (match Hash_ident.find_opt ident_use_stats ident with @@ -384593,12 +384547,12 @@ let mark_dead_code (js : J.program) : J.program = ]} *) -let subst_map () = object (self) +let subst_map (substitution : J.expression Hash_ident.t) = object (self) inherit Js_map.map as super - val mutable substitution : J.expression Hash_ident.t= Hash_ident.create 17 - method get_substitution = substitution + + method add_substitue (ident : Ident.t) (e:J.expression) = Hash_ident.replace substitution ident e @@ -384677,7 +384631,7 @@ let subst_map () = object (self) {expression_desc = Number (Int {i; _})}) | Static_index ({expression_desc = Var (Id (id))}, _, Some i) -> - (match Hash_ident.find_opt self#get_substitution id with + (match Hash_ident.find_opt substitution id with | Some {expression_desc = Caml_block (ls, Immutable, _, _) } -> (* user program can be wrong, we should not @@ -384701,7 +384655,7 @@ end let program (js : J.program) = js - |> (subst_map () )#program + |> (subst_map (Hash_ident.create 32) )#program |> mark_dead_code (* |> mark_dead_code *) (* mark dead code twice does have effect in some cases, however, we disabled it @@ -385130,28 +385084,41 @@ end = struct * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) - +let add_use stats id = + Hash_ident.add_or_update stats id 1 ~update:succ +let post_process_stats my_export_set (defined_idents : J.variable_declaration Hash_ident.t) stats = + Hash_ident.iter defined_idents (fun ident v -> + if Set_ident.mem my_export_set ident then + Js_op_util.update_used_stats v.ident_info Exported + else + let pure = + match v.value with + | None -> false (* can not happen *) + | Some x -> Js_analyzer.no_side_effect_expression x in + match Hash_ident.find_opt stats ident with + | None -> + Js_op_util.update_used_stats v.ident_info + (if pure then Dead_pure else Dead_non_pure) + | Some num -> + if num = 1 then + Js_op_util.update_used_stats v.ident_info + (if pure then Once_pure else Used) + ) ; defined_idents (** Update ident info use cases, it is a non pure function, it will annotate [program] with some meta data TODO: Ident Hash could be improved, since in this case it can not be global? *) -let count_collects () = +let count_collects + (* collect used status*) + (stats : int Hash_ident.t) + (* collect all def sites *) + (defined_idents : J.variable_declaration Hash_ident.t) : Js_fold.fold + = object (self) - inherit Js_fold.fold as super - (* collect used status*) - val stats : int Hash_ident.t = Hash_ident.create 83 - (* collect all def sites *) - val defined_idents : J.variable_declaration Hash_ident.t = Hash_ident.create 83 - - val mutable my_export_set : Set_ident.t = Set_ident.empty - - method add_use id = - Hash_ident.add_or_update stats id 1 ~update:succ - method! program x = - my_export_set <- x.export_set ; - super#program x + inherit Js_fold.fold + method! variable_declaration ({ident; value ; property = _ ; ident_info = _} as v) = @@ -385161,31 +385128,19 @@ let count_collects () = self | Some x -> self#expression x - method! ident id = self#add_use id; self - method get_stats = - Hash_ident.iter defined_idents (fun ident v -> - if Set_ident.mem my_export_set ident then - Js_op_util.update_used_stats v.ident_info Exported - else - let pure = - match v.value with - | None -> false (* can not happen *) - | Some x -> Js_analyzer.no_side_effect_expression x in - match Hash_ident.find_opt stats ident with - | None -> - Js_op_util.update_used_stats v.ident_info - (if pure then Dead_pure else Dead_non_pure) - | Some num -> - if num = 1 then - Js_op_util.update_used_stats v.ident_info - (if pure then Once_pure else Used) - ) ; defined_idents + method! ident id = add_use stats id; self + end let get_stats (program : J.program) : J.variable_declaration Hash_ident.t - = ((count_collects ()) #program program) #get_stats - + = + let stats : int Hash_ident.t = Hash_ident.create 83 in + let defined_idents : J.variable_declaration Hash_ident.t = Hash_ident.create 83 in + let my_export_set = program.export_set in + let _ : Js_fold.fold = (count_collects stats defined_idents) #program program in + post_process_stats my_export_set defined_idents stats + end module Js_pass_tailcall_inline : sig #1 "js_pass_tailcall_inline.mli" @@ -385552,7 +385507,7 @@ let get_initial_exports TODO: add hashtbl for a cache *) Set_ident.( - union (Js_analyzer.free_variables_of_expression empty empty x) acc) + union (Js_analyzer.free_variables_of_expression x) acc) end else begin match value with @@ -385561,14 +385516,14 @@ let get_initial_exports if Js_analyzer.no_side_effect_expression x then acc else Set_ident.( - union (Js_analyzer.free_variables_of_expression empty empty x) + union (Js_analyzer.free_variables_of_expression x) (add acc ident)) end | _ -> (* recalcuate again and again ... *) if Js_analyzer.no_side_effect_statement st || (not count_non_variable_declaration_statement) then acc - else Set_ident.(union (Js_analyzer.free_variables_of_statement empty empty st) acc) + else Set_ident.(union (Js_analyzer.free_variables_of_statement st) acc) ) in result, Set_ident.(diff result export_set) let shake_program (program : J.program) = @@ -388510,7 +388465,7 @@ val make_block : val field : Lam_compat.field_dbg_info -> J.expression -> - J.jsint -> + int32 -> J.expression val field_by_exp : @@ -388520,7 +388475,7 @@ val field_by_exp : val set_field : Lam_compat.set_field_dbg_info -> - J.expression -> J.jsint -> J.expression -> J.expression + J.expression -> int32 -> J.expression -> J.expression val set_field_by_exp : J.expression -> diff --git a/ocaml-tree/test.js b/ocaml-tree/test.js index b0b03acf12..b36f24f56c 100644 --- a/ocaml-tree/test.js +++ b/ocaml-tree/test.js @@ -49,7 +49,9 @@ var nodeFormatter = { // visual(new Node('hi','test',[1,2,3]),nodeFormatter) works var fs = require("fs"); -var y = p.parse(fs.readFileSync("j.ml", "utf8")); +var path = require("path"); +var j_dir = path.join(__dirname, "..", "jscomp", "core"); +var y = p.parse(fs.readFileSync(path.join(j_dir, "j.ml"), "utf8")); /** * mutual recursive types @@ -63,5 +65,6 @@ globalThis.devtoolsFormatters.push(nodeFormatter); var map_maker = require("./map_maker"); var fold_maker = require("./fold_maker"); -fs.writeFileSync("js_fold.ml", fold_maker.make(typedefs), "utf8"); -fs.writeFileSync("js_map.ml", map_maker.make(typedefs), "utf8"); +var fold = fold_maker.make(typedefs); +var map = map_maker.make(typedefs); +console.log(fold, map);