123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120(* Js_of_ocaml compiler
* http://www.ocsigen.org/js_of_ocaml/
* Copyright (C) 2019 Hugo Heuzard
*
* 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!StdlibmoduleJ=Javascriptletzero=J.ENum(J.Num.of_targetintTargetint.zero)letone=J.ENum(J.Num.of_targetintTargetint.one)letintn=J.ENum(J.Num.of_targetint(Targetint.of_int_exnn))(* JavaScript engines recognize the pattern 'typeof x==="number"'; if the string is
shared, less efficient code is generated. *)lettype_of_is_numberbinope=J.EBin(binop,J.EUn(J.Typeof,e),J.EStr(Utf8_string.of_string_exn"number"))letis_blocke=type_of_is_numberJ.NotEqEqeletis_immediatee=type_of_is_numberJ.EqEqEqe(* Introcaml: the reserved header bits of a block (its descriptor) are
stored in the header word, above the tag, so that blocks remain plain
arrays: [x[0] = tag | (bits << 8)]. With the 22 bits reserved by
Introcaml, the header fits in 30 bits: it stays non-negative under
bitwise operators, and a small integer in JavaScript engines. *)lettag_bits=8letreserved_bits=22lettag_mask=(1lsltag_bits)-1letreserved_mask=(1lslreserved_bits)-1letheader~tag~desc=int(ifConfig.Flag.introspection()thentaglor((Code.Block_desc.to_intdesclandreserved_mask)lsltag_bits)elsetag)moduleBlock=structletmake~tag~desc~args=J.EArr(J.Element(header~tag~desc)::args)letreserved_bits=reserved_bitsletshifted_reservedbits=J.EBin(J.Lsl,J.EBin(J.Band,bits,intreserved_mask),inttag_bits)letheader~tag~reserved=ifConfig.Flag.introspection()thenJ.EBin(J.Bor,tag,shifted_reservedreserved)elsetagletmax_header()=int(ifConfig.Flag.introspection()then(1lsl(tag_bits+reserved_bits))-1elsetag_mask)lettage=lethd=J.EAccess(e,ANormal,zero)inifConfig.Flag.introspection()thenJ.EBin(J.Band,hd,inttag_mask)elsehdletset_tagetag=lethd=J.EAccess(e,ANormal,zero)inifConfig.Flag.introspection()thenletreserved=J.EBin(J.Band,hd,int(lnottag_mask))inJ.EBin(J.Eq,hd,J.EBin(J.Bor,reserved,tag))elseJ.EBin(J.Eq,hd,tag)letreservede=J.EBin(J.Lsr,J.EAccess(e,ANormal,zero),inttag_bits)letset_reservedebits=lethd=J.EAccess(e,ANormal,zero)inlettag=J.EBin(J.Band,hd,inttag_mask)inJ.EBin(J.Eq,hd,matchbitswith|J.ENumnwhenTargetint.is_zero(J.Num.to_targetintn)->tag|_->J.EBin(J.Bor,tag,shifted_reservedbits))letfieldeidx=J.EAccess(e,ANormal,int(idx+1))endmoduleArray=structletmake=Block.makeletlengthe=letunderlying=J.EDot(e,ANormal,Utf8_string.of_string_exn"length")inJ.EBin(J.Minus,underlying,one)letfieldei=matchiwith|J.ENumn->letidx=J.Num.to_targetintninletadjusted=J.ENum(J.Num.of_targetint(Targetint.succidx))inJ.EAccess(e,ANormal,adjusted)|J.EUn(J.Neg,_)->failwith"Negative field indexes are not allowed"|_->letadjusted=J.EBin(J.Plus,i,one)inJ.EAccess(e,ANormal,adjusted)end