123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261(* Js_of_ocaml compiler
* http://www.ocsigen.org/js_of_ocaml/
* Copyright (C) 2010 Jérôme Vouillon
* Laboratoire PPS - CNRS Université Paris Diderot
*
* 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, with linking exception;
* either version 2.1 of the License, or (at your option) any 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.
*)open!Stdliblettimes=Debug.find"times"openCode(****)letiter_cont_free_varsf(_,l)=List.iter~flletiter_expr_free_varsfe=matchewith|Constant_->()|Apply{f=x;args;_}->fx;List.iter~fargs|Block(_,a,_,_)->Array.iter~fa|Field(x,_,_)->fx|Closure_->()|Special_->()|Prim(_,l)->List.iterl~f:(funx->matchxwith|Pvx->fx|Pc_->())letiter_instr_free_varsfi=matchiwith|Let(_,e)->iter_expr_free_varsfe|Set_field(x,_,_,y)->fx;fy|Offset_ref(x,_)->fx|Array_set(x,y,z)->fx;fy;fz|Assign(_,y)->fy|Event_->()letiter_last_free_varfl=matchlwith|Returnx|Raise(x,_)->fx|Stop->()|Branchcont|Poptrapcont->iter_cont_free_varsfcont|Cond(x,cont1,cont2)->fx;iter_cont_free_varsfcont1;iter_cont_free_varsfcont2|Switch(x,a1)->fx;Array.itera1~f:(func->iter_cont_free_varsfc)|Pushtrap(cont1,_,cont2)->iter_cont_free_varsfcont1;iter_cont_free_varsfcont2letiter_block_free_varsfblock=List.iterblock.body~f:(funi->iter_instr_free_varsfi);iter_last_free_varfblock.branchletiter_instr_bound_varsfi=matchiwith|Let(x,_)->fx|Event_|Set_field_|Offset_ref_|Array_set_|Assign_->()letiter_last_bound_varsfl=matchlwith|Return_|Raise_|Stop|Branch_|Cond_|Switch_|Poptrap_->()|Pushtrap(_,x,_)->fxletiter_block_bound_varsfblock=List.iter~fblock.params;List.iterblock.body~f:(funi->iter_instr_bound_varsfi);iter_last_bound_varsfblock.branch(****)typest={index:int;mutablelowlink:int;mutablein_stack:bool;mutablerevisited:bool}letfind_loopspin_looppc=letin_loop=refin_loopinletindex=ref0inletstate=refAddr.Map.emptyinletstack=Stack.create()inletrectraversepc=letst={index=!index;lowlink=!index;in_stack=true;revisited=false}instate:=Addr.Map.addpcst!state;incrindex;Stack.pushpcstack;Code.fold_childrenp.blockspc(funpc'()->tryletst'=Addr.Map.findpc'!stateinifst'.in_stackthen(st'.revisited<-true;st.lowlink<-minst.lowlinkst'.index)withNot_found->traversepc';letst'=Addr.Map.findpc'!stateinst.lowlink<-minst.lowlinkst'.lowlink)();ifst.index=st.lowlinkthen(letl=ref[]inwhileletpc'=Stack.popstackinl:=pc'::!l;(Addr.Map.findpc'!state).in_stack<-false;pc'<>pcdo()done;(* If we revisit the top element of the stack, then we have a loop.
This work even for loops of size 1 *)ifst.revisitedthenList.iter!l~f:(funpc'->in_loop:=Addr.Map.addpc'pc!in_loop))intraversepc;!in_loopletfind_loops_in_closureppc=find_loopspAddr.Map.emptypcletfind_all_loopsp=Code.fold_closuresp(fun__(pc,_)(in_loop:_Addr.Map.t)->find_loopspin_looppc)Addr.Map.emptyletmark_variablesin_loopp=letvars=Var.Tbl.make()(-1)inletvisited=BitSet.create'p.free_pcinletrectraversepc=ifnot(BitSet.memvisitedpc)then(BitSet.setvisitedpc;letblock=Addr.Map.findpcp.blocksin(tryletpc'=Addr.Map.findpcin_loopiniter_block_bound_vars(funx->Var.Tbl.setvarsxpc')blockwithNot_found->());List.iterblock.body~f:(funi->matchiwith|Let(_,Closure(_,(pc',_)))->traversepc'|_->());Code.fold_childrenp.blockspc(funpc'()->traversepc')())intraversep.start;varsletfree_variablesvarsin_loopp=letall_freevars=refAddr.Map.emptyinletfreevars=refAddr.Map.emptyinletvisited=BitSet.create'p.free_pcinletrectraversepc=ifnot(BitSet.memvisitedpc)then(BitSet.setvisitedpc;letblock=Addr.Map.findpcp.blocksiniter_block_free_vars(funx->letpc'=Var.Tbl.getvarsxinifpc'<>-1thenletfv=tryAddr.Map.findpc'!all_freevarswithNot_found->Var.Set.emptyinlets=Var.Set.addxfvinall_freevars:=Addr.Map.addpc's!all_freevars)block;(tryletpc''=Addr.Map.findpcin_loopinall_freevars:=Addr.Map.removepc''!all_freevarswithNot_found->());List.iterblock.body~f:(funi->matchiwith|Let(_,Closure(_,(pc',_)))->(traversepc';tryletpc''=Addr.Map.findpcin_loopinletfv=tryAddr.Map.findpc''!all_freevarswithNot_found->Var.Set.emptyinfreevars:=Addr.Map.addpc'fv!freevars;all_freevars:=Addr.Map.removepc''!all_freevarswithNot_found->freevars:=Addr.Map.addpc'Var.Set.empty!freevars)|_->());Code.fold_childrenp.blockspc(funpc'()->traversepc')())intraversep.start;!freevarsletfp=Code.invariantp;lett=Timer.make()inletbound=Code.Var.ISet.empty()inletvisited=BitSet.create'p.free_pcinletfree_vars=Code.fold_closures_innermost_firstp(fun_name_optparams(pc,args)acc->letfree=refVar.Set.emptyinletusingx=ifCode.Var.ISet.memboundxthen()elsefree:=Var.Set.addx!freeinletrectraversepc=ifnot(BitSet.memvisitedpc)then(BitSet.setvisitedpc;letblock=Addr.Map.findpcp.blocksiniter_block_bound_vars(funx->Code.Var.ISet.addboundx)block;iter_block_free_varsusingblock;List.iterblock.body~f:(function|Let(_,Closure(_,(pc_clo,_)))->Code.Var.Set.iterusing(Code.Addr.Map.findpc_cloacc)|_->());Code.fold_childrenp.blockspc(funpc'()->traversepc')())inList.iterparams~f:(funx->Code.Var.ISet.addboundx);List.iterargs~f:using;traversepc;Code.Addr.Map.addpc!freeacc)Code.Addr.Map.emptyiniftimes()thenFormat.eprintf" free vars 2: %a@."Timer.printt;free_varsletf_mutablep=Code.invariantp;lett=Timer.make()inletin_loop=find_all_loopspinletvars=mark_variablesin_looppinletfree_vars=free_variablesvarsin_looppiniftimes()thenFormat.eprintf" free vars 1: %a@."Timer.printt;free_vars