123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122(* Wasm_of_ocaml compiler
* http://www.ocsigen.org/js_of_ocaml/
*
* 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.
*)(*
Store some toplevel values into globals. Any variable which is used a
number of instructions after being defined is stored into a global
instead of a local. The goals are the following:
- Turn a large number of closures into constant closures, which has a
significant impact on performance
- Reduce the compilation time of the toplevel function in case the
Wasm engine decide to optimize it: reduce the register pressure by
avoiding long-lived registers in the toplevel function, and make
load elimination less expensive by reducing the number of constant
structures defined in this function.
*)openStdlibtypest={pos:int;visited_variables:intCode.Var.Map.t;globals:Code.Var.Set.t;closures:Closure_conversion.closureCode.Var.Map.t}letthreshold=1000letrecglobalizestx=ifCode.Var.Set.memxst.globalsthenstelseletst={stwithglobals=Code.Var.Set.addxst.globals}inglobalize_closurestxandglobalize_closurestx=(* If a function is stored in a global variable, its free variables
are also stored in a global variable, since they are retained
anyway. *)matchCode.Var.Map.findxst.closureswith|{free_variables;_}->List.fold_left~f:(funstx->ifCode.Var.Map.memxst.visited_variablesthenglobalizestxelsest)~init:stfree_variables|exceptionNot_found->stletusexst=matchCode.Var.Map.findxst.visited_variableswith|pos->ifst.pos>pos+thresholdthenglobalizestxelsest|exceptionNot_found->stletdeclarexst={stwithvisited_variables=Code.Var.Map.addxst.posst.visited_variables}lettraverse_expressionxest=matchewith|Code.Apply{f;args;_}->st|>usef|>funst->List.fold_left~f:(funstx->usexst)~init:stargs|Block(_,a,_,_)->Array.fold_right~f:usea~init:st|Field(x,_,_)->st|>usex|Closure_->List.fold_left~f:(funstx->usexst)~init:st(Code.Var.Map.findxst.closures).Closure_conversion.free_variables|Constant_|Special_->st|Prim(_,args)->List.fold_left~f:(funsta->matchawith|Code.Pvx->st|>usex|Pc_->st)~init:stargslettraverse_instructionsti=letst={stwithpos=st.pos+1}inmatchiwith|Code.Let(x,e)->st|>declarex|>traverse_expressionxe|Assign(_,x)|Offset_ref(x,_)->st|>usex|Set_field(x,_,_,y)->st|>usex|>usey|Array_set(x,y,z)->st|>usex|>usey|>usez|Event_->stlettraverse_blockpstpc=letb=Code.Addr.Map.findpcp.Code.blocksinletst=List.fold_left~f:(funstx->declarexst)~init:stb.Code.paramsinList.fold_left~f:(funsti->traverse_instructionsti)~init:stb.Code.bodyletfpgclosures=letl=Structure.blocks_in_reverse_post_orderginletin_loop=Freevars.find_loops_in_closurepp.Code.startinletst=List.fold_left~f:(funstpc->ifCode.Addr.Map.mempcin_loopthenstelsetraverse_blockpstpc)~init:{pos=0;visited_variables=Code.Var.Map.empty;globals=Code.Var.Set.empty;closures}linst.globals