123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225(* 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|Const_|Constant_->()|Apply(x,l,_)->fx;List.iter~fl|Block(_,a,_)->Array.iter~fa|Field(x,_)->fx|Closure_->()|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;fzletiter_last_free_varfl=matchlwith|Returnx|Raise(x,_)->fx|Stop->()|Branchcont|Poptrap(cont,_)->iter_cont_free_varsfcont|Cond(_,x,cont1,cont2)->fx;iter_cont_free_varsfcont1;iter_cont_free_varsfcont2|Switch(x,a1,a2)->fx;Array.itera1~f:(func->iter_cont_free_varsfc);Array.itera2~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|Set_field_|Offset_ref_|Array_set_->()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}letfind_loops((_,blocks,_)asprog)=letin_loop=refAddr.Map.emptyinletindex=ref0inletstate=refAddr.Map.emptyinletstack=Stack.create()inletrectraversepc=letst={index=!index;lowlink=!index;in_stack=true}instate:=Addr.Map.addpcst!state;incrindex;Stack.pushpcstack;Code.fold_childrenblockspc(funpc'()->tryletst'=Addr.Map.findpc'!stateinifst'.in_stackthenst.lowlink<-minst.lowlinkst'.indexwithNot_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;ifList.length!l>1thenList.iter!l~f:(funpc'->in_loop:=Addr.Map.addpc'pc!in_loop))inCode.fold_closuresprog(fun__(pc,_)()->traversepc)();!in_loopletmark_variablesin_loop(pc,blocks,free_pc)=letvars=Var.Tbl.make()(-1)inletvisited=Array.makefree_pcfalseinletrectraversepc=ifnotvisited.(pc)then(visited.(pc)<-true;letblock=Addr.Map.findpcblocksin(tryletpc'=Addr.Map.findpcin_loopiniter_block_bound_vars(funx->(*
Format.eprintf "!%a: %d@." Var.print x pc';
*)Var.Tbl.setvarsxpc')blockwithNot_found->());List.iterblock.body~f:(funi->matchiwith|Let(_,Closure(_,(pc',_)))->traversepc'|_->());Code.fold_childrenblockspc(funpc'()->traversepc')())intraversepc;varsletfree_variablesvarsin_loop(pc,blocks,free_pc)=letall_freevars=refAddr.Map.emptyinletfreevars=refAddr.Map.emptyinletvisited=Array.makefree_pcfalseinletrectraversepc=ifnotvisited.(pc)then(visited.(pc)<-true;letblock=Addr.Map.findpcblocksiniter_block_free_vars(funx->letpc'=Var.Tbl.getvarsxin(*
Format.eprintf "%a: %d@." Var.print x pc';
*)ifpc'<>-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_childrenblockspc(funpc'()->traversepc')())intraversepc;(*
Addr.Map.iter
(fun pc fv -> if Var.Set.cardinal fv > 0 then
Format.eprintf ">> %d: %d@." pc (Var.Set.cardinal fv))
!freevars;
*)!freevarsletfp=Code.invariantp;lett=Timer.make()inletin_loop=find_loopspinletvars=mark_variablesin_looppinletfree_vars=free_variablesvarsin_looppiniftimes()thenFormat.eprintf" free vars: %a@."Timer.printt;free_vars