123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694(* 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!StdlibmoduleAddr=structtypet=intmoduleSet=Set.Make(Int)moduleMap=Map.Make(Int)letto_string=string_of_intletzero=0letpred=predletsucc=succendmoduleDebugAddr:sigtypet=privateAddr.tvalof_addr:Addr.t->tvalto_addr:t->Addr.tvalno:tend=structtypet=intletof_addr(x:Addr.t):t=xletno=0letto_addr(x:t):Addr.t=xendmoduleVar:sigtypetvalprint:Format.formatter->t->unitvalequal:t->t->boolvalidx:t->intvalof_idx:int->tvalto_string:?origin:t->t->stringvalfresh:unit->tvalfresh_n:string->tvalfork:t->tvalcount:unit->intvalcompare:t->t->intvalget_loc:t->Parse_info.toptionvalloc:t->Parse_info.t->unitvalname:t->string->unitvalget_name:t->stringoptionvalpropagate_name:t->t->unitvalreset:unit->unitvalset_pretty:bool->unitvalset_stable:bool->unitmoduleSet:Set.Swithtypeelt=tmoduleMap:Map.Swithtypekey=tmoduleTbl:sigtypekey=ttype'attypesize=unitvalget:'at->key->'avalset:'at->key->'a->unitvalmake:size->'a->'atendmoduleISet:sigtypeelt=ttypetvalempty:unit->tvaliter:(elt->unit)->t->unitvalmem:t->elt->boolvaladd:t->elt->unitvalremove:t->elt->unitvalcopy:t->tendend=structmoduleT=structtypet=intletcompare:t->t->int=compareletequal(a:t)(b:t)=a=bendincludeTletprinter=Var_printer.createVar_printer.Alphabet.javascriptletlocations=Hashtbl.create17letlast_var=ref0letreset()=last_var:=0;Hashtbl.clearlocations;Var_printer.resetprinterletto_string?origini=Var_printer.to_stringprinter?originiletprintfx=Format.fprintff"v%d"x(* Format.fprintf f "%s" (to_string x) *)letnameinm=Var_printer.nameprinterinmletlocipi=Hashtbl.addlocationsipi(*;
Format.eprintf "loc for %d : %d-%d\n%!"
i pi.Parse_info.line pi.Parse_info.col
*)letget_loci=trySome(Hashtbl.findlocationsi)withNot_found->Noneletfresh()=incrlast_var;!last_varletfresh_nnm=incrlast_var;name!last_varnm;!last_varletcount()=!last_var+1letidxv=vletof_idxv=vletget_namei=Var_printer.get_nameprinteriletpropagate_nameij=Var_printer.propagate_nameprinterij;matchget_lociwith|None->()|Somel->locjlletset_prettyb=Var_printer.set_prettyprinterbletset_stableb=Var_printer.set_stableprinterbletforko=letn=fresh()inpropagate_nameon;nletdummy=-1moduleSet=Set.Make(T)moduleMap=Map.Make(T)moduleTbl=structtype'at='aarraytypekey=T.ttypesize=unitletgettx=t.(x)letsettxv=t.(x)<-vletmake()v=Array.make(count())vendmoduleISet=structtypet=T.tarraytypeelt=T.tletiterft=fori=0toArray.lengtht-1doletx=t.(i)inifcomparexdummy<>0thenfxdoneletmemtx=comparet.(x)dummy<>0letaddtx=t.(x)<-xletremovetx=t.(x)<-dummyletcopy=Array.copyletempty_v=Array.make(count())dummyendendtypecont=Addr.t*Var.tlisttypeprim=|Vectlength|Array_get|Externofstring|Not|IsInt|Eq|Neq|Lt|Le|Ulttypearray_or_not=|Array|NotArray|Unknowntypeconstant=|Stringofstring|NativeStringofstring|Floatoffloat|Float_arrayoffloatarray|Int64ofint64|Tupleofint*constantarray*array_or_not|Intofint32letrecconstant_equalab=matcha,bwith|Stringa,Stringb->Some(String.equalab)|NativeStringa,NativeStringb->Some(String.equalab)|Tuple(ta,a,_),Tuple(tb,b,_)->ifta<>tb||Array.lengtha<>Array.lengthbthenSomefalseelseletsame=ref(Sometrue)infori=0toArray.lengtha-1domatch!same,constant_equala.(i)b.(i)with|None,_->()|_,None->same:=None|Somes,Somec->same:=Some(s&&c)done;!same|Int64a,Int64b->Some(Int64.equalab)|Float_arraya,Float_arrayb->Some(Array.equalFloat.equalab)|Inta,Intb->Some(Int32.equalab)|Floata,Floatb->Some(Float.equalab)|String_,NativeString_|NativeString_,String_->None|Int_,Float_|Float_,Int_->None|Tuple((0|254),_,_),Float_array_->None|Float_array_,Tuple((0|254),_,_)->None|Tuple_,(String_|NativeString_|Int64_|Int_|Float_|Float_array_)->Somefalse|Float_array_,(String_|NativeString_|Int64_|Int_|Float_|Tuple_)->Somefalse|String_,(Int64_|Int_|Float_|Tuple_|Float_array_)->Somefalse|NativeString_,(Int64_|Int_|Float_|Tuple_|Float_array_)->Somefalse|Int64_,(String_|NativeString_|Int_|Float_|Tuple_|Float_array_)->Somefalse|Float_,(String_|NativeString_|Float_array_|Int64_|Tuple(_,_,_))->Somefalse|Int_,(String_|NativeString_|Float_array_|Int64_|Tuple(_,_,_))->Somefalsetypeprim_arg=|PvofVar.t|Pcofconstanttypeexpr=|Applyof{f:Var.t;args:Var.tlist;exact:bool}|Blockofint*Var.tarray*array_or_not|FieldofVar.t*int|ClosureofVar.tlist*cont|Constantofconstant|Primofprim*prim_arglisttypeinstr=|LetofVar.t*expr|AssignofVar.t*Var.t|Set_fieldofVar.t*int*Var.t|Offset_refofVar.t*int|Array_setofVar.t*Var.t*Var.ttypelast=|ReturnofVar.t|RaiseofVar.t*[`Normal|`Notrace|`Reraise]|Stop|Branchofcont|CondofVar.t*cont*cont|SwitchofVar.t*contarray*contarray|Pushtrapofcont*Var.t*cont*Addr.Set.t|Poptrapofconttypeblock={params:Var.tlist;body:instrlist;branch:last}typeprogram={start:Addr.t;blocks:blockAddr.Map.t;free_pc:Addr.t}(****)modulePrint=structletreclistprfl=matchlwith|[]->()|[x]->prfx|x::r->Format.fprintff"%a, %a"prx(listpr)rletvar_list=listVar.printletcontf(pc,args)=Format.fprintff"%d (%a)"pcvar_listargsletrecconstantfx=matchxwith|Strings->Format.fprintff"%S"s|NativeStrings->Format.fprintff"%Sj"s|Floatfl->Format.fprintff"%.12g"fl|Float_arraya->Format.fprintff"[|";fori=0toArray.lengtha-1doifi>0thenFormat.fprintff", ";Format.fprintff"%.12g"a.(i)done;Format.fprintff"|]"|Int64i->Format.fprintff"%LdL"i|Tuple(tag,a,_)->(Format.fprintff"<%d>"tag;matchArray.lengthawith|0->()|1->Format.fprintff"(";constantfa.(0);Format.fprintff")"|n->Format.fprintff"(";constantfa.(0);fori=1ton-1doFormat.fprintff", ";constantfa.(i)done;Format.fprintff")")|Inti->Format.fprintff"%ld"iletargfa=matchawith|Pvx->Var.printfx|Pcc->constantfcletbinops=matchswith|"%int_add"->"+"|"%int_sub"->"-"|"%int_mul"->"*"|"%int_div"->"/"|"%int_mod"->"%"|"%int_and"->"&"|"%int_or"->"|"|"%int_xor"->"^"|"%int_lsl"->"<<"|"%int_lsr"->">>>"|"%int_asr"->">>"|_->raiseNot_foundletunops=matchswith|"%int_neg"->"-"|_->raiseNot_foundletprimfpl=matchp,lwith|Vectlength,[x]->Format.fprintff"%a.length"argx|Array_get,[x;y]->Format.fprintff"%a[%a]"argxargy|Externs,[x;y]->(tryFormat.fprintff"%a %s %a"argx(binops)argywithNot_found->Format.fprintff"\"%s\"(%a)"s(listarg)l)|Externs,[x]->(tryFormat.fprintff"%s %a"(unops)argxwithNot_found->Format.fprintff"\"%s\"(%a)"s(listarg)l)|Externs,_->Format.fprintff"\"%s\"(%a)"s(listarg)l|Not,[x]->Format.fprintff"!%a"argx|IsInt,[x]->Format.fprintff"is_int(%a)"argx|Eq,[x;y]->Format.fprintff"%a === %a"argxargy|Neq,[x;y]->Format.fprintff"!(%a === %a)"argxargy|Lt,[x;y]->Format.fprintff"%a < %a"argxargy|Le,[x;y]->Format.fprintff"%a <= %a"argxargy|Ult,[x;y]->Format.fprintff"%a <= %a"argxargy|_->assertfalseletexprfe=matchewith|Apply{f=g;args;exact}->ifexactthenFormat.fprintff"%a!(%a)"Var.printgvar_listargselseFormat.fprintff"%a(%a)"Var.printgvar_listargs|Block(t,a,_)->Format.fprintff"{tag=%d"t;fori=0toArray.lengtha-1doFormat.fprintff"; %d = %a"iVar.printa.(i)done;Format.fprintff"}"|Field(x,i)->Format.fprintff"%a[%d]"Var.printxi|Closure(l,c)->Format.fprintff"fun(%a){%a}"var_listlcontc|Constantc->Format.fprintff"CONST{%a}"constantc|Prim(p,l)->primfplletinstrfi=matchiwith|Let(x,e)->Format.fprintff"%a = %a"Var.printxexpre|Assign(x,y)->Format.fprintff"(assign) %a = %a"Var.printxVar.printy|Set_field(x,i,y)->Format.fprintff"%a[%d] = %a"Var.printxiVar.printy|Offset_ref(x,i)->Format.fprintff"%a[0] += %d"Var.printxi|Array_set(x,y,z)->Format.fprintff"%a[%a] = %a"Var.printxVar.printyVar.printzletlastfl=matchlwith|Returnx->Format.fprintff"return %a"Var.printx|Raise(x,`Normal)->Format.fprintff"raise %a"Var.printx|Raise(x,`Reraise)->Format.fprintff"reraise %a"Var.printx|Raise(x,`Notrace)->Format.fprintff"raise_notrace %a"Var.printx|Stop->Format.fprintff"stop"|Branchc->Format.fprintff"branch %a"contc|Cond(x,cont1,cont2)->Format.fprintff"if %a then %a else %a"Var.printxcontcont1contcont2|Switch(x,a1,a2)->Format.fprintff"switch %a {"Var.printx;Array.iteria1~f:(funic->Format.fprintff"int %d -> %a; "icontc);Array.iteria2~f:(funic->Format.fprintff"tag %d -> %a; "icontc);Format.fprintff"}"|Pushtrap(cont1,x,cont2,pcs)->Format.fprintff"pushtrap %a handler %a => %a continuation %s"contcont1Var.printxcontcont2(String.concat~sep:", "(List.map(Addr.Set.elementspcs)~f:string_of_int))|Poptrapc->Format.fprintff"poptrap %a"contctypexinstr=|Instrofinstr|Lastoflastletblockannotpcblock=Format.eprintf"==== %d (%a) ====@."pcvar_listblock.params;List.iterblock.body~f:(funi->Format.eprintf" %s %a@."(annotpc(Instri))instri);Format.eprintf" %s %a@."(annotpc(Lastblock.branch))lastblock.branch;Format.eprintf"@."letprogramannot{start;blocks;_}=Format.eprintf"Entry point: %d@.@."start;Addr.Map.iter(blockannot)blocksend(****)letfold_closurespfaccu=Addr.Map.fold(fun_blockaccu->List.fold_leftblock.body~init:accu~f:(funaccui->matchiwith|Let(x,Closure(params,cont))->f(Somex)paramscontaccu|_->accu))p.blocks(fNone[](p.start,[])accu)(****)letprepend({start;blocks;free_pc}asp)body=matchbodywith|[]->p|_->(matchAddr.Map.findstartblockswith|block->{pwithblocks=Addr.Map.addstart{blockwithbody=body@block.body}blocks}|exceptionNot_found->letnew_start=free_pcinletblocks=Addr.Map.addnew_start{params=[];body;branch=Stop}blocksinletfree_pc=free_pc+1in{start=new_start;blocks;free_pc})letempty_block={params=[];body=[];branch=Stop}letempty=letstart=0inletblocks=Addr.Map.singletonstartempty_blockin{start;blocks;free_pc=start+1}letis_emptyp=matchAddr.Map.cardinalp.blockswith|0->true|1->(let_,v=Addr.Map.choosep.blocksinmatchvwith|{body;branch=Stop;params=_}->(matchbodywith|([]|[Let(_,Prim(Extern"caml_get_global_data",_))])whentrue->true|_->false)|_->false)|_->falseletfold_childrenblockspcfaccu=letblock=Addr.Map.findpcblocksinmatchblock.branchwith|Return_|Raise_|Stop->accu|Branch(pc',_)|Poptrap(pc',_)->fpc'accu|Pushtrap((pc',_),_,(pc_h,_),_)->letaccu=fpc'accuinletaccu=fpc_haccuinaccu|Cond(_,(pc1,_),(pc2,_))->letaccu=fpc1accuinletaccu=fpc2accuinaccu|Switch(_,a1,a2)->letaccu=Array.fold_right~init:accu~f:(fun(pc,_)accu->fpcaccu)a1inletaccu=Array.fold_right~init:accu~f:(fun(pc,_)accu->fpcaccu)a2inaccutype'cfold_blocs=blockAddr.Map.t->Addr.t->(Addr.t->'c->'c)->'c->'ctypefold_blocs_poly={fold:'a.'afold_blocs}[@@unboxed]letrectraverse'{fold}fpcvisitedblocksacc=ifnot(Addr.Set.mempcvisited)thenletvisited=Addr.Set.addpcvisitedinletvisited,acc=foldblockspc(funpc(visited,acc)->letvisited,acc=traverse'{fold}fpcvisitedblocksaccinvisited,acc)(visited,acc)inletacc=fpcaccinvisited,accelsevisited,acclettraversefoldfpcblocksacc=snd(traverse'foldfpcAddr.Set.emptyblocksacc)letrecpreorder_traverse'{fold}fpcvisitedblocksacc=ifnot(Addr.Set.mempcvisited)thenletvisited=Addr.Set.addpcvisitedinletacc=fpcaccinfoldblockspc(funpc(visited,acc)->letvisited,acc=preorder_traverse'{fold}fpcvisitedblocksaccinvisited,acc)(visited,acc)elsevisited,accletpreorder_traversefoldfpcblocksacc=snd(preorder_traverse'foldfpcAddr.Set.emptyblocksacc)leteqp1p2=p1.start=p2.start&&Addr.Map.cardinalp1.blocks=Addr.Map.cardinalp2.blocks&&Addr.Map.fold(funpcblock1b->b&&tryletblock2=Addr.Map.findpcp2.blocksinPoly.(block1.params=block2.params)&&Poly.(block1.branch=block2.branch)&&Poly.(block1.body=block2.body)withNot_found->false)p1.blockstrueletwith_invariant=Debug.find"invariant"letcheck_defs=falseletinvariant{blocks;start;_}=ifwith_invariant()then(assert(Addr.Map.memstartblocks);letdefs=Array.make(Var.count())falseinletcheck_cont(cont,args)=letb=Addr.Map.findcontblocksinassert(List.lengthargs>=List.lengthb.params)inletdefinex=ifcheck_defsthen(assert(notdefs.(Var.idxx));defs.(Var.idxx)<-true)inletcheck_expr=function|Apply_->()|Block(_,_,_)->()|Field(_,_)->()|Closure(l,cont)->List.iterl~f:define;check_contcont|Constant_->()|Prim(_,_)->()inletcheck_instr=function|Let(x,e)->definex;check_expre|Assign_->()|Set_field(_,_i,_)->()|Offset_ref(_x,_i)->()|Array_set(_x,_y,_z)->()inletcheck_last=function|Return_->()|Raise_->()|Stop->()|Branchcont->check_contcont|Cond(_x,cont1,cont2)->check_contcont1;check_contcont2|Switch(_x,a1,a2)->Array.iteria1~f:(fun_cont->check_contcont);Array.iteria2~f:(fun_cont->check_contcont)|Pushtrap(cont1,_x,cont2,_pcs)->check_contcont1;check_contcont2|Poptrapcont->check_contcontinAddr.Map.iter(fun_pcblock->List.iterblock.params~f:define;List.iterblock.body~f:check_instr;check_lastblock.branch)blocks)