IRBuilder.cpp 291 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
  4. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  5. //-------------------------------------------------------------------------------------------------------
  6. #include "Backend.h"
  7. #include "Library/ForInObjectEnumerator.h"
  8. #pragma prefast(push)
  9. #pragma prefast(disable:28652, "Prefast complains that the OR are causing the compiler to emit dynamic initializers and the variable to be allocated in read/write mem...")
  10. static const IR::BailOutKind c_debuggerBailOutKindForCall =
  11. IR::BailOutForceByFlag | IR::BailOutStackFrameBase | IR::BailOutBreakPointInFunction | IR::BailOutLocalValueChanged | IR::BailOutIgnoreException | IR::BailOutStep;
  12. static const IR::BailOutKind c_debuggerBaseBailOutKindForHelper = IR::BailOutIgnoreException | IR::BailOutForceByFlag;
  13. #pragma prefast(pop)
  14. uint
  15. IRBuilder::AddStatementBoundary(uint statementIndex, uint offset)
  16. {
  17. // Under debugger we use full stmt map, so that we know exactly start and end of each user stmt.
  18. // We insert additional instrs in between statements, such as ProfiledLoopStart, for these bytecode reader acts as
  19. // there is "unknown" stmt boundary with statementIndex == -1. Don't add stmt boundary for that as later
  20. // it may cause issues, e.g. see WinBlue 218307.
  21. if (!(statementIndex == Js::Constants::NoStatementIndex && this->m_func->IsJitInDebugMode()))
  22. {
  23. IR::PragmaInstr* pragmaInstr = IR::PragmaInstr::New(Js::OpCode::StatementBoundary, statementIndex, m_func);
  24. this->AddInstr(pragmaInstr, offset);
  25. }
  26. #ifdef BAILOUT_INJECTION
  27. if (!this->m_func->IsOOPJIT())
  28. {
  29. // Don't inject bailout if the function have trys
  30. if (!this->m_func->GetTopFunc()->HasTry() && (statementIndex != Js::Constants::NoStatementIndex))
  31. {
  32. if (Js::Configuration::Global.flags.IsEnabled(Js::BailOutFlag) && !this->m_func->GetJITFunctionBody()->IsLibraryCode())
  33. {
  34. ULONG line;
  35. LONG col;
  36. // Since we're on a separate thread, don't allow the line cache to be allocated in the Recycler.
  37. if (((Js::FunctionBody*)m_func->GetJITFunctionBody()->GetAddr())->GetLineCharOffset(this->m_jnReader.GetCurrentOffset(), &line, &col, false /*canAllocateLineCache*/))
  38. {
  39. line++;
  40. if (Js::Configuration::Global.flags.BailOut.Contains(line, (uint32)col) || Js::Configuration::Global.flags.BailOut.Contains(line, (uint32)-1))
  41. {
  42. this->InjectBailOut(offset);
  43. }
  44. }
  45. }
  46. else if (Js::Configuration::Global.flags.IsEnabled(Js::BailOutAtEveryLineFlag))
  47. {
  48. this->InjectBailOut(offset);
  49. }
  50. }
  51. }
  52. #endif
  53. return m_statementReader.MoveNextStatementBoundary();
  54. }
  55. // Add conditional bailout for breaking into interpreter debug thunk - for fast F12.
  56. void
  57. IRBuilder::InsertBailOutForDebugger(uint byteCodeOffset, IR::BailOutKind kind, IR::Instr* insertBeforeInstr /* default nullptr */)
  58. {
  59. Assert(m_func->IsJitInDebugMode());
  60. Assert(byteCodeOffset != Js::Constants::NoByteCodeOffset);
  61. BailOutInfo * bailOutInfo = JitAnew(m_func->m_alloc, BailOutInfo, byteCodeOffset, m_func);
  62. IR::BailOutInstr * instr = IR::BailOutInstr::New(Js::OpCode::BailForDebugger, kind, bailOutInfo, bailOutInfo->bailOutFunc);
  63. if (insertBeforeInstr)
  64. {
  65. InsertInstr(instr, insertBeforeInstr);
  66. }
  67. else
  68. {
  69. this->AddInstr(instr, m_lastInstr->GetByteCodeOffset());
  70. }
  71. }
  72. bool
  73. IRBuilder::DoBailOnNoProfile()
  74. {
  75. if (PHASE_OFF(Js::BailOnNoProfilePhase, this->m_func->GetTopFunc()))
  76. {
  77. return false;
  78. }
  79. Func *const topFunc = m_func->GetTopFunc();
  80. if(topFunc->GetWorkItem()->GetProfiledIterations() == 0)
  81. {
  82. // The top function has not been profiled yet. Some switch must have been used to force jitting. This is not a
  83. // real-world case, but for the purpose of testing the JIT, it's beneficial to generate code in unprofiled paths.
  84. return false;
  85. }
  86. if (m_func->HasProfileInfo() && m_func->GetReadOnlyProfileInfo()->IsNoProfileBailoutsDisabled())
  87. {
  88. return false;
  89. }
  90. if (!m_func->DoGlobOpt())
  91. {
  92. return false;
  93. }
  94. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  95. if (this->m_func->GetTopFunc() != this->m_func && Js::Configuration::Global.flags.IsEnabled(Js::ForceJITLoopBodyFlag))
  96. {
  97. // No profile data for loop bodies with -force...
  98. return false;
  99. }
  100. #endif
  101. if (!this->m_func->HasProfileInfo())
  102. {
  103. return false;
  104. }
  105. if (m_func->GetTopFunc()->GetJITFunctionBody()->IsCoroutine())
  106. {
  107. return false;
  108. }
  109. return true;
  110. }
  111. void
  112. IRBuilder::InsertBailOnNoProfile(uint offset)
  113. {
  114. Assert(DoBailOnNoProfile());
  115. if (this->callTreeHasSomeProfileInfo)
  116. {
  117. return;
  118. }
  119. IR::Instr *startCall = nullptr;
  120. int count = 0;
  121. FOREACH_SLIST_ENTRY(IR::Instr *, argInstr, this->m_argStack)
  122. {
  123. if (argInstr->m_opcode == Js::OpCode::StartCall)
  124. {
  125. startCall = argInstr;
  126. count++;
  127. if (count > 1)
  128. {
  129. return;
  130. }
  131. }
  132. } NEXT_SLIST_ENTRY;
  133. AnalysisAssert(startCall);
  134. if (startCall->m_prev->m_opcode != Js::OpCode::BailOnNoProfile)
  135. {
  136. InsertBailOnNoProfile(startCall);
  137. }
  138. }
  139. void IRBuilder::InsertBailOnNoProfile(IR::Instr *const insertBeforeInstr)
  140. {
  141. Assert(DoBailOnNoProfile());
  142. IR::Instr *const bailOnNoProfileInstr = IR::Instr::New(Js::OpCode::BailOnNoProfile, m_func);
  143. InsertInstr(bailOnNoProfileInstr, insertBeforeInstr);
  144. }
  145. #ifdef BAILOUT_INJECTION
  146. void
  147. IRBuilder::InjectBailOut(uint offset)
  148. {
  149. if(m_func->IsSimpleJit())
  150. {
  151. return; // bailout injection is only applicable to full JIT
  152. }
  153. IR::IntConstOpnd * opnd = IR::IntConstOpnd::New(0, TyInt32, m_func);
  154. uint bailOutOffset = offset;
  155. if (bailOutOffset == Js::Constants::NoByteCodeOffset)
  156. {
  157. bailOutOffset = m_lastInstr->GetByteCodeOffset();
  158. }
  159. BailOutInfo * bailOutInfo = JitAnew(m_func->m_alloc, BailOutInfo, bailOutOffset, m_func);
  160. IR::BailOutInstr * instr = IR::BailOutInstr::New(Js::OpCode::BailOnEqual, IR::BailOutInjected, bailOutInfo, bailOutInfo->bailOutFunc);
  161. instr->SetSrc1(opnd);
  162. instr->SetSrc2(opnd);
  163. this->AddInstr(instr, offset);
  164. }
  165. void
  166. IRBuilder::CheckBailOutInjection(Js::OpCode opcode)
  167. {
  168. // Detect these sequence and disable Bailout injection between them:
  169. // LdStackArgPtr
  170. // LdArgCnt
  171. // ApplyArgs
  172. // This assumes that LdStackArgPtr, LdArgCnt and ApplyArgs can
  173. // only be emitted in these sequence. This will need to be modified if it changes.
  174. //
  175. // Also insert a single bailout before the beginning of a switch case block for all the case labels.
  176. switch(opcode)
  177. {
  178. case Js::OpCode::LdStackArgPtr:
  179. Assert(!seenLdStackArgPtr);
  180. Assert(!expectApplyArg);
  181. seenLdStackArgPtr = true;
  182. break;
  183. case Js::OpCode::LdArgCnt:
  184. Assert(seenLdStackArgPtr);
  185. Assert(!expectApplyArg);
  186. expectApplyArg = true;
  187. break;
  188. case Js::OpCode::ApplyArgs:
  189. Assert(seenLdStackArgPtr);
  190. Assert(expectApplyArg);
  191. seenLdStackArgPtr = false;
  192. expectApplyArg = false;
  193. break;
  194. case Js::OpCode::BeginSwitch:
  195. case Js::OpCode::ProfiledBeginSwitch:
  196. Assert(!seenProfiledBeginSwitch);
  197. seenProfiledBeginSwitch = true;
  198. break;
  199. case Js::OpCode::EndSwitch:
  200. Assert(seenProfiledBeginSwitch);
  201. seenProfiledBeginSwitch = false;
  202. break;
  203. default:
  204. Assert(!seenLdStackArgPtr);
  205. Assert(!expectApplyArg);
  206. break;
  207. }
  208. }
  209. #endif
  210. bool
  211. IRBuilder::IsLoopBody() const
  212. {
  213. return m_func->IsLoopBody();
  214. }
  215. bool
  216. IRBuilder::IsLoopBodyInTry() const
  217. {
  218. return m_func->IsLoopBodyInTry();
  219. }
  220. bool
  221. IRBuilder::IsLoopBodyReturnIPInstr(IR::Instr * instr) const
  222. {
  223. IR::Opnd * dst = instr->GetDst();
  224. return (dst && dst->IsRegOpnd() && dst->AsRegOpnd()->m_sym == m_loopBodyRetIPSym);
  225. }
  226. bool
  227. IRBuilder::IsLoopBodyOuterOffset(uint offset) const
  228. {
  229. if (!IsLoopBody())
  230. {
  231. return false;
  232. }
  233. return (offset >= m_func->m_workItem->GetLoopHeader()->endOffset || offset < m_func->m_workItem->GetLoopHeader()->startOffset);
  234. }
  235. uint
  236. IRBuilder::GetLoopBodyExitInstrOffset() const
  237. {
  238. // End of loop body, start of StSlot and Ret instruction at endOffset + 1
  239. return m_func->m_workItem->GetLoopHeader()->endOffset + 1;
  240. }
  241. Js::RegSlot
  242. IRBuilder::GetEnvReg() const
  243. {
  244. return m_func->GetJITFunctionBody()->GetEnvReg();
  245. }
  246. Js::RegSlot
  247. IRBuilder::GetEnvRegForInnerFrameDisplay() const
  248. {
  249. Js::RegSlot envReg = m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg();
  250. if (envReg == Js::Constants::NoRegister)
  251. {
  252. envReg = this->GetEnvReg();
  253. }
  254. return envReg;
  255. }
  256. void
  257. IRBuilder::AddEnvOpndForInnerFrameDisplay(IR::Instr *instr, uint offset)
  258. {
  259. Js::RegSlot envReg = this->GetEnvRegForInnerFrameDisplay();
  260. if (envReg != Js::Constants::NoRegister)
  261. {
  262. IR::RegOpnd *src2Opnd;
  263. if (envReg == m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg() &&
  264. m_func->DoStackFrameDisplay() &&
  265. m_func->IsTopFunc())
  266. {
  267. src2Opnd = IR::RegOpnd::New(TyVar, m_func);
  268. this->AddInstr(
  269. IR::Instr::New(
  270. Js::OpCode::LdSlot, src2Opnd,
  271. this->BuildFieldOpnd(Js::OpCode::LdSlot, m_func->GetLocalFrameDisplaySym()->m_id, 0, (Js::PropertyIdIndexType)-1, PropertyKindSlots),
  272. m_func),
  273. offset);
  274. }
  275. else
  276. {
  277. src2Opnd = this->BuildSrcOpnd(envReg);
  278. }
  279. instr->SetSrc2(src2Opnd);
  280. }
  281. }
  282. ///----------------------------------------------------------------------------
  283. ///
  284. /// IRBuilder::Build
  285. ///
  286. /// IRBuilder main entry point. Read the bytecode for this function and
  287. /// generate IR.
  288. ///
  289. ///----------------------------------------------------------------------------
  290. void
  291. IRBuilder::Build()
  292. {
  293. m_funcAlloc = m_func->m_alloc;
  294. NoRecoverMemoryJitArenaAllocator localAlloc(_u("BE-IRBuilder"), m_funcAlloc->GetPageAllocator(), Js::Throw::OutOfMemory);
  295. m_tempAlloc = &localAlloc;
  296. uint32 offset;
  297. uint32 statementIndex = m_statementReader.GetStatementIndex();
  298. m_argStack = JitAnew(m_tempAlloc, SList<IR::Instr *>, m_tempAlloc);
  299. this->branchRelocList = JitAnew(m_tempAlloc, SList<BranchReloc *>, m_tempAlloc);
  300. Func * topFunc = this->m_func->GetTopFunc();
  301. if (topFunc->HasTry() &&
  302. ((!topFunc->IsLoopBody() && !PHASE_OFF(Js::OptimizeTryCatchPhase, topFunc)) ||
  303. (topFunc->HasFinally() && !topFunc->IsLoopBody() && !PHASE_OFF(Js::OptimizeTryFinallyPhase, topFunc)) ||
  304. (topFunc->IsSimpleJit() && topFunc->GetJITFunctionBody()->DoJITLoopBody()) || // should be relaxed as more bailouts are added in Simple Jit
  305. topFunc->IsLoopBodyInTryFinally())) // We need accurate flow when we are full jitting loop bodies which have try finally
  306. {
  307. this->handlerOffsetStack = JitAnew(m_tempAlloc, SList<handlerStackElementType>, m_tempAlloc);
  308. }
  309. this->firstTemp = m_func->GetJITFunctionBody()->GetFirstTmpReg();
  310. Js::RegSlot tempCount = m_func->GetJITFunctionBody()->GetTempCount();
  311. if (tempCount > 0)
  312. {
  313. this->tempMap = AnewArrayZ(m_tempAlloc, SymID, tempCount);
  314. }
  315. else
  316. {
  317. this->tempMap = nullptr;
  318. }
  319. m_func->m_headInstr = IR::EntryInstr::New(Js::OpCode::FunctionEntry, m_func);
  320. m_func->m_exitInstr = IR::ExitInstr::New(Js::OpCode::FunctionExit, m_func);
  321. m_func->m_tailInstr = m_func->m_exitInstr;
  322. m_func->m_headInstr->InsertAfter(m_func->m_tailInstr);
  323. if (m_func->GetJITFunctionBody()->IsParamAndBodyScopeMerged() || this->IsLoopBody())
  324. {
  325. this->SetParamScopeDone();
  326. }
  327. if (m_func->GetJITFunctionBody()->GetLocalClosureReg() != Js::Constants::NoRegister)
  328. {
  329. m_func->InitLocalClosureSyms();
  330. }
  331. m_functionStartOffset = m_jnReader.GetCurrentOffset();
  332. m_lastInstr = m_func->m_headInstr;
  333. AssertMsg(sizeof(SymID) >= sizeof(Js::RegSlot), "sizeof(SymID) != sizeof(Js::RegSlot)!!");
  334. // Skip the last EndOfBlock opcode
  335. Assert(!OpCodeAttr::HasMultiSizeLayout(Js::OpCode::EndOfBlock));
  336. uint32 lastOffset = m_func->GetJITFunctionBody()->GetByteCodeLength() - Js::OpCodeUtil::EncodedSize(Js::OpCode::EndOfBlock, Js::SmallLayout);
  337. uint32 offsetToInstructionCount = lastOffset;
  338. if (this->IsLoopBody())
  339. {
  340. // LdSlot needs to cover all the register, including the temps, because we might treat
  341. // those as if they are local for the value of the with statement
  342. this->m_ldSlots = BVFixed::New<JitArenaAllocator>(m_func->GetJITFunctionBody()->GetLocalsCount(), m_tempAlloc);
  343. this->m_stSlots = BVFixed::New<JitArenaAllocator>(m_func->GetJITFunctionBody()->GetFirstTmpReg(), m_tempAlloc);
  344. this->m_loopBodyRetIPSym = StackSym::New(TyMachReg, this->m_func);
  345. #if DBG
  346. if (m_func->GetJITFunctionBody()->GetTempCount() != 0)
  347. {
  348. this->m_usedAsTemp = BVFixed::New<JitArenaAllocator>(m_func->GetJITFunctionBody()->GetTempCount(), m_tempAlloc);
  349. }
  350. #endif
  351. lastOffset = m_func->m_workItem->GetLoopHeader()->endOffset;
  352. AssertOrFailFast(lastOffset < m_func->GetJITFunctionBody()->GetByteCodeLength());
  353. // Ret is created at lastOffset + 1, so we need lastOffset + 2 entries
  354. offsetToInstructionCount = lastOffset + 2;
  355. // Compute the offset of the start of the locals array as a Var index.
  356. size_t localsOffset = Js::InterpreterStackFrame::GetOffsetOfLocals();
  357. Assert(localsOffset % sizeof(Js::Var) == 0);
  358. this->m_loopBodyLocalsStartSlot = (Js::PropertyId)(localsOffset / sizeof(Js::Var));
  359. }
  360. m_offsetToInstructionCount = offsetToInstructionCount;
  361. m_offsetToInstruction = JitAnewArrayZ(m_tempAlloc, IR::Instr *, offsetToInstructionCount);
  362. #ifdef BYTECODE_BRANCH_ISLAND
  363. longBranchMap = JitAnew(m_tempAlloc, LongBranchMap, m_tempAlloc);
  364. #endif
  365. m_switchBuilder.Init(m_func, m_tempAlloc, false);
  366. this->LoadNativeCodeData();
  367. this->BuildConstantLoads();
  368. if (!this->IsLoopBody() && m_func->GetJITFunctionBody()->HasImplicitArgIns())
  369. {
  370. this->BuildImplicitArgIns();
  371. }
  372. if (!this->IsLoopBody() && m_func->GetJITFunctionBody()->HasRestParameter())
  373. {
  374. this->BuildArgInRest();
  375. }
  376. // This is first bailout in the function, the locals at stack have not initialized to undefined, so do not restore them.
  377. // Note that for generators, we insert the bailout after the jump table to allow
  378. // the generator's execution to proceed before bailing out. Otherwise, we would always
  379. // bail to the beginning of the function in the interpreter, creating an infinite loop.
  380. if (m_func->IsJitInDebugMode() && !this->m_func->GetJITFunctionBody()->IsCoroutine())
  381. {
  382. this->InsertBailOutForDebugger(m_functionStartOffset, IR::BailOutForceByFlag | IR::BailOutBreakPointInFunction | IR::BailOutStep, nullptr);
  383. }
  384. #ifdef BAILOUT_INJECTION
  385. // Start bailout inject after the constant and arg load. We don't bailout before that
  386. IR::Instr * lastInstr = m_lastInstr;
  387. #endif
  388. offset = Js::Constants::NoByteCodeOffset;
  389. if (!this->IsLoopBody())
  390. {
  391. IR::Instr *instr;
  392. // Do the implicit operations LdEnv, NewScopeSlots, LdFrameDisplay, as indicated by function body attributes.
  393. Js::RegSlot envReg = m_func->GetJITFunctionBody()->GetEnvReg();
  394. if (envReg != Js::Constants::NoRegister && !this->RegIsConstant(envReg))
  395. {
  396. Js::OpCode newOpcode;
  397. Js::RegSlot thisReg = m_func->GetJITFunctionBody()->GetThisRegForEventHandler();
  398. IR::RegOpnd *srcOpnd = nullptr;
  399. IR::RegOpnd *dstOpnd = nullptr;
  400. if (thisReg != Js::Constants::NoRegister)
  401. {
  402. this->BuildArgIn0(offset, thisReg);
  403. srcOpnd = BuildSrcOpnd(thisReg);
  404. newOpcode = Js::OpCode::LdHandlerScope;
  405. }
  406. else
  407. {
  408. newOpcode = Js::OpCode::LdEnv;
  409. }
  410. dstOpnd = BuildDstOpnd(envReg);
  411. instr = IR::Instr::New(newOpcode, dstOpnd, m_func);
  412. if (srcOpnd)
  413. {
  414. instr->SetSrc1(srcOpnd);
  415. }
  416. if (dstOpnd->m_sym->m_isSingleDef)
  417. {
  418. dstOpnd->m_sym->m_isNotNumber = true;
  419. }
  420. this->AddInstr(instr, offset);
  421. }
  422. // The point at which we insert the generator resume jump table is important.
  423. // We want to insert it right *after* the environment and constants have
  424. // been loaded and *before* we create any other important objects
  425. // (e.g: FrameDisplay, LocalClosure) which will be passed on to the interpreter
  426. // frame when we bail out. Those values, if used when we resume, will be restored
  427. // by the bail-in code, therefore we don't want to unnecessarily create those new
  428. // objects every time we "resume" a generator
  429. //
  430. // Note: We need to make sure that all the values below are allocated on the heap.
  431. // so that they don't go away once this jit'd frame is popped off.
  432. #ifdef BAILOUT_INJECTION
  433. lastInstr = this->m_generatorJumpTable.BuildJumpTable();
  434. #else
  435. this->m_generatorJumpTable.BuildJumpTable();
  436. #endif
  437. // When debugging generators, insert bail-out after the jump table so that we can
  438. // get to the right point before going back to the interpreter.
  439. // This bailout is equivalent to the one inserted above for non-generator functions.
  440. // Additionally, we also need to insert bailouts on each resume point and right
  441. // after the bail-in code since this bailout is only for the very first time
  442. // we are in the generator.
  443. if (m_func->IsJitInDebugMode() && this->m_func->GetJITFunctionBody()->IsCoroutine())
  444. {
  445. this->InsertBailOutForDebugger(m_functionStartOffset, IR::BailOutForceByFlag | IR::BailOutBreakPointInFunction | IR::BailOutStep, nullptr);
  446. }
  447. Js::RegSlot funcExprScopeReg = m_func->GetJITFunctionBody()->GetFuncExprScopeReg();
  448. IR::RegOpnd *frameDisplayOpnd = nullptr;
  449. if (funcExprScopeReg != Js::Constants::NoRegister)
  450. {
  451. IR::RegOpnd *funcExprScopeOpnd = BuildDstOpnd(funcExprScopeReg);
  452. instr = IR::Instr::New(Js::OpCode::NewPseudoScope, funcExprScopeOpnd, m_func);
  453. this->AddInstr(instr, offset);
  454. }
  455. Js::RegSlot closureReg = m_func->GetJITFunctionBody()->GetLocalClosureReg();
  456. IR::RegOpnd *closureOpnd = nullptr;
  457. if (closureReg != Js::Constants::NoRegister)
  458. {
  459. Assert(!this->RegIsConstant(closureReg));
  460. if (m_func->DoStackScopeSlots())
  461. {
  462. closureOpnd = IR::RegOpnd::New(TyVar, m_func);
  463. }
  464. else
  465. {
  466. closureOpnd = this->BuildDstOpnd(closureReg);
  467. }
  468. if (m_func->GetJITFunctionBody()->HasScopeObject())
  469. {
  470. if (m_func->GetJITFunctionBody()->HasCachedScopePropIds())
  471. {
  472. this->BuildInitCachedScope(0, offset);
  473. }
  474. else
  475. {
  476. instr = IR::Instr::New(Js::OpCode::NewScopeObject, closureOpnd, m_func);
  477. this->AddInstr(instr, offset);
  478. }
  479. }
  480. else
  481. {
  482. Js::OpCode op =
  483. m_func->DoStackScopeSlots() ? Js::OpCode::NewStackScopeSlots : Js::OpCode::NewScopeSlots;
  484. uint size = m_func->GetJITFunctionBody()->IsParamAndBodyScopeMerged() ? m_func->GetJITFunctionBody()->GetScopeSlotArraySize() : m_func->GetJITFunctionBody()->GetParamScopeSlotArraySize();
  485. IR::Opnd * srcOpnd = IR::IntConstOpnd::New(size + Js::ScopeSlots::FirstSlotIndex, TyUint32, m_func);
  486. instr = IR::Instr::New(op, closureOpnd, srcOpnd, m_func);
  487. this->AddInstr(instr, offset);
  488. }
  489. if (closureOpnd->m_sym->m_isSingleDef)
  490. {
  491. closureOpnd->m_sym->m_isNotNumber = true;
  492. }
  493. if (m_func->DoStackScopeSlots())
  494. {
  495. // Init the stack closure sym and use it to save the scope slot pointer.
  496. this->AddInstr(
  497. IR::Instr::New(
  498. Js::OpCode::InitLocalClosure, this->BuildDstOpnd(m_func->GetLocalClosureSym()->m_id), m_func),
  499. offset);
  500. this->AddInstr(
  501. IR::Instr::New(
  502. Js::OpCode::StSlot,
  503. this->BuildFieldOpnd(
  504. Js::OpCode::StSlot, m_func->GetLocalClosureSym()->m_id, 0, (Js::PropertyIdIndexType)-1, PropertyKindSlots),
  505. closureOpnd, m_func),
  506. offset);
  507. }
  508. }
  509. Js::RegSlot frameDisplayReg = m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg();
  510. if (frameDisplayReg != Js::Constants::NoRegister)
  511. {
  512. Assert(!this->RegIsConstant(frameDisplayReg));
  513. Js::OpCode op = m_func->DoStackScopeSlots() ? Js::OpCode::NewStackFrameDisplay : Js::OpCode::LdFrameDisplay;
  514. if (funcExprScopeReg != Js::Constants::NoRegister)
  515. {
  516. // Insert the function expression scope ahead of any enclosing scopes.
  517. IR::RegOpnd * funcExprScopeOpnd = BuildSrcOpnd(funcExprScopeReg);
  518. frameDisplayOpnd = closureReg != Js::Constants::NoRegister ? IR::RegOpnd::New(TyVar, m_func) : BuildDstOpnd(frameDisplayReg);
  519. instr = IR::Instr::New(Js::OpCode::LdFrameDisplay, frameDisplayOpnd, funcExprScopeOpnd, m_func);
  520. if (envReg != Js::Constants::NoRegister)
  521. {
  522. instr->SetSrc2(this->BuildSrcOpnd(envReg));
  523. }
  524. this->AddInstr(instr, (uint)-1);
  525. }
  526. if (closureReg != Js::Constants::NoRegister)
  527. {
  528. IR::RegOpnd *dstOpnd;
  529. if (m_func->DoStackScopeSlots() && m_func->IsTopFunc())
  530. {
  531. dstOpnd = IR::RegOpnd::New(TyVar, m_func);
  532. }
  533. else
  534. {
  535. dstOpnd = this->BuildDstOpnd(frameDisplayReg);
  536. }
  537. instr = IR::Instr::New(op, dstOpnd, closureOpnd, m_func);
  538. if (frameDisplayOpnd != nullptr)
  539. {
  540. // We're building on an intermediate LdFrameDisplay result.
  541. instr->SetSrc2(frameDisplayOpnd);
  542. }
  543. else if (envReg != Js::Constants::NoRegister)
  544. {
  545. // We're building on the environment created by the enclosing function.
  546. instr->SetSrc2(this->BuildSrcOpnd(envReg));
  547. }
  548. this->AddInstr(instr, offset);
  549. if (dstOpnd->m_sym->m_isSingleDef)
  550. {
  551. dstOpnd->m_sym->m_isNotNumber = true;
  552. }
  553. if (m_func->DoStackFrameDisplay())
  554. {
  555. // Use the stack closure sym to save the frame display pointer.
  556. this->AddInstr(
  557. IR::Instr::New(
  558. Js::OpCode::InitLocalClosure, this->BuildDstOpnd(m_func->GetLocalFrameDisplaySym()->m_id), m_func),
  559. offset);
  560. this->AddInstr(
  561. IR::Instr::New(
  562. Js::OpCode::StSlot,
  563. this->BuildFieldOpnd(Js::OpCode::StSlot, m_func->GetLocalFrameDisplaySym()->m_id, 0, (Js::PropertyIdIndexType)-1, PropertyKindSlots),
  564. dstOpnd, m_func),
  565. offset);
  566. }
  567. }
  568. }
  569. }
  570. offset = m_functionStartOffset;
  571. if (m_statementReader.AtStatementBoundary(&m_jnReader))
  572. {
  573. statementIndex = this->AddStatementBoundary(statementIndex, offset);
  574. }
  575. // For label instr we can add bailout only after all labels were finalized. Put to list/add in the end.
  576. JsUtil::BaseDictionary<IR::Instr*, int, JitArenaAllocator> ignoreExBranchInstrToOffsetMap(m_tempAlloc);
  577. Js::LayoutSize layoutSize;
  578. IR::Instr* lastProcessedInstrForJITLoopBody = m_func->m_headInstr;
  579. for (Js::OpCode newOpcode = m_jnReader.ReadOp(layoutSize); (uint)m_jnReader.GetCurrentOffset() <= lastOffset; newOpcode = m_jnReader.ReadOp(layoutSize))
  580. {
  581. Assert(newOpcode != Js::OpCode::EndOfBlock);
  582. #ifdef BAILOUT_INJECTION
  583. if (!this->m_func->GetTopFunc()->HasTry()
  584. #ifdef BYTECODE_BRANCH_ISLAND
  585. && newOpcode != Js::OpCode::BrLong // Don't inject bailout on BrLong as they are just redirecting to a different offset anyways
  586. #endif
  587. )
  588. {
  589. if (!this->m_func->IsOOPJIT())
  590. {
  591. if (!seenLdStackArgPtr && !seenProfiledBeginSwitch)
  592. {
  593. if (Js::Configuration::Global.flags.IsEnabled(Js::BailOutByteCodeFlag))
  594. {
  595. ThreadContext * threadContext = this->m_func->GetScriptContext()->GetThreadContext();
  596. if (Js::Configuration::Global.flags.BailOutByteCode.Contains(threadContext->bailOutByteCodeLocationCount))
  597. {
  598. this->InjectBailOut(offset);
  599. }
  600. }
  601. else if (Js::Configuration::Global.flags.IsEnabled(Js::BailOutAtEveryByteCodeFlag))
  602. {
  603. this->InjectBailOut(offset);
  604. }
  605. }
  606. CheckBailOutInjection(newOpcode);
  607. }
  608. }
  609. #endif
  610. AssertOrFailFastMsg(Js::OpCodeUtil::IsValidByteCodeOpcode(newOpcode), "Error getting opcode from m_jnReader.Op()");
  611. uint layoutAndSize = layoutSize * Js::OpLayoutType::Count + Js::OpCodeUtil::GetOpCodeLayout(newOpcode);
  612. switch(layoutAndSize)
  613. {
  614. #define LAYOUT_TYPE(layout) \
  615. case Js::OpLayoutType::layout: \
  616. Assert(layoutSize == Js::SmallLayout); \
  617. this->Build##layout(newOpcode, offset); \
  618. break;
  619. #define LAYOUT_TYPE_WMS(layout) \
  620. case Js::SmallLayout * Js::OpLayoutType::Count + Js::OpLayoutType::layout: \
  621. this->Build##layout<Js::SmallLayoutSizePolicy>(newOpcode, offset); \
  622. break; \
  623. case Js::MediumLayout * Js::OpLayoutType::Count + Js::OpLayoutType::layout: \
  624. this->Build##layout<Js::MediumLayoutSizePolicy>(newOpcode, offset); \
  625. break; \
  626. case Js::LargeLayout * Js::OpLayoutType::Count + Js::OpLayoutType::layout: \
  627. this->Build##layout<Js::LargeLayoutSizePolicy>(newOpcode, offset); \
  628. break;
  629. #include "ByteCode/LayoutTypes.h"
  630. default:
  631. AssertMsg(0, "Unimplemented layout");
  632. break;
  633. }
  634. #ifdef BAILOUT_INJECTION
  635. if (!this->m_func->IsOOPJIT())
  636. {
  637. if (!this->m_func->GetTopFunc()->HasTry() && Js::Configuration::Global.flags.IsEnabled(Js::BailOutByteCodeFlag))
  638. {
  639. ThreadContext * threadContext = this->m_func->GetScriptContext()->GetThreadContext();
  640. if (lastInstr != m_lastInstr)
  641. {
  642. lastInstr = lastInstr->GetNextRealInstr();
  643. if (lastInstr->HasBailOutInfo())
  644. {
  645. lastInstr = lastInstr->m_next;
  646. }
  647. lastInstr->bailOutByteCodeLocation = threadContext->bailOutByteCodeLocationCount;
  648. lastInstr = m_lastInstr;
  649. }
  650. threadContext->bailOutByteCodeLocationCount++;
  651. }
  652. }
  653. #endif
  654. if (IsLoopBodyInTry() && lastProcessedInstrForJITLoopBody != m_lastInstr)
  655. {
  656. // traverse in backward so we get new/later value of given symId for storing instead of the earlier/stale
  657. // symId value. m_stSlots is used to prevent multiple stores to the same symId.
  658. FOREACH_INSTR_BACKWARD_EDITING_IN_RANGE(
  659. instr,
  660. instrPrev,
  661. m_lastInstr,
  662. lastProcessedInstrForJITLoopBody->m_next)
  663. {
  664. if (instr->GetDst() && instr->GetDst()->IsRegOpnd() && instr->GetDst()->GetStackSym()->HasByteCodeRegSlot())
  665. {
  666. StackSym * dstSym = instr->GetDst()->GetStackSym();
  667. Js::RegSlot dstRegSlot = dstSym->GetByteCodeRegSlot();
  668. if (!this->RegIsTemp(dstRegSlot) && !this->RegIsConstant(dstRegSlot))
  669. {
  670. SymID symId = dstSym->m_id;
  671. AssertOrFailFast(symId < m_stSlots->Length());
  672. if (this->m_stSlots->Test(symId))
  673. {
  674. // For jitted loop bodies that are in a try block, we consider any symbol that has a
  675. // non-temp bytecode reg slot, to be write-through. Hence, generating StSlots at all
  676. // defs for such symbols
  677. IR::Instr * stSlot = this->GenerateLoopBodyStSlot(dstRegSlot);
  678. AddInstr(stSlot, Js::Constants::NoByteCodeOffset);
  679. this->m_stSlots->Clear(symId);
  680. }
  681. else
  682. {
  683. Assert(dstSym->m_isCatchObjectSym);
  684. }
  685. }
  686. }
  687. } NEXT_INSTR_BACKWARD_EDITING_IN_RANGE;
  688. lastProcessedInstrForJITLoopBody = m_lastInstr;
  689. }
  690. offset = m_jnReader.GetCurrentOffset();
  691. if (m_func->IsJitInDebugMode())
  692. {
  693. bool needBailoutForHelper = CONFIG_FLAG(EnableContinueAfterExceptionWrappersForHelpers) &&
  694. (OpCodeAttr::NeedsPostOpDbgBailOut(newOpcode) ||
  695. (m_lastInstr->m_opcode == Js::OpCode::CallHelper && m_lastInstr->GetSrc1() &&
  696. HelperMethodAttributes::CanThrow(m_lastInstr->GetSrc1()->AsHelperCallOpnd()->m_fnHelper)));
  697. if (needBailoutForHelper)
  698. {
  699. // Insert bailout after return from a helper call.
  700. // For now use offset of next instr, when we get & ignore exception, we replace this with next statement offset.
  701. if (m_lastInstr->IsBranchInstr())
  702. {
  703. // Debugger bailout on branches goes to different block which can become dead. Keep bailout with real instr.
  704. // Can't convert to bailout at this time, can do that only after branches are finalized, remember for later.
  705. ignoreExBranchInstrToOffsetMap.Add(m_lastInstr, offset);
  706. }
  707. else if (
  708. m_lastInstr->m_opcode == Js::OpCode::Throw ||
  709. m_lastInstr->m_opcode == Js::OpCode::RuntimeReferenceError ||
  710. m_lastInstr->m_opcode == Js::OpCode::RuntimeTypeError)
  711. {
  712. uint32 lastInstrOffset = m_lastInstr->GetByteCodeOffset();
  713. AssertOrFailFast(lastInstrOffset < m_offsetToInstructionCount);
  714. #if DBG
  715. __analysis_assume(lastInstrOffset < this->m_offsetToInstructionCount);
  716. #endif
  717. bool isLastInstrUpdateNeeded = m_offsetToInstruction[lastInstrOffset] == m_lastInstr;
  718. BailOutInfo * bailOutInfo = JitAnew(this->m_func->m_alloc, BailOutInfo, offset, this->m_func);
  719. m_lastInstr = m_lastInstr->ConvertToBailOutInstr(bailOutInfo, c_debuggerBaseBailOutKindForHelper, true);
  720. if (isLastInstrUpdateNeeded)
  721. {
  722. m_offsetToInstruction[lastInstrOffset] = m_lastInstr;
  723. }
  724. }
  725. else
  726. {
  727. IR::BailOutKind bailOutKind = c_debuggerBaseBailOutKindForHelper;
  728. if (OpCodeAttr::HasImplicitCall(newOpcode) || OpCodeAttr::OpndHasImplicitCall(newOpcode))
  729. {
  730. // When we get out of e.g. valueOf called by a helper (e.g. Add_A) during stepping,
  731. // we need to bail out to continue debugging calling function in interpreter,
  732. // essentially this is similar to bail out on return from a method.
  733. bailOutKind |= c_debuggerBailOutKindForCall;
  734. }
  735. this->InsertBailOutForDebugger(offset, bailOutKind);
  736. }
  737. }
  738. }
  739. while (m_statementReader.AtStatementBoundary(&m_jnReader))
  740. {
  741. statementIndex = this->AddStatementBoundary(statementIndex, offset);
  742. }
  743. }
  744. if (Js::Constants::NoStatementIndex != statementIndex)
  745. {
  746. // If we are inside a user statement then create a trailing line pragma instruction
  747. statementIndex = this->AddStatementBoundary(statementIndex, Js::Constants::NoByteCodeOffset);
  748. }
  749. if (IsLoopBody())
  750. {
  751. // Insert the LdSlot/StSlot and Ret
  752. IR::Opnd * retOpnd = this->InsertLoopBodyReturnIPInstr(offset, offset);
  753. // Restore and Ret are at the last offset + 1
  754. GenerateLoopBodySlotAccesses(lastOffset + 1);
  755. InsertDoneLoopBodyLoopCounter(lastOffset);
  756. IR::Instr * retInstr = IR::Instr::New(Js::OpCode::Ret, m_func);
  757. retInstr->SetSrc1(retOpnd);
  758. this->AddInstr(retInstr, lastOffset + 1);
  759. }
  760. // Now fix up the targets for all the branches we've introduced.
  761. InsertLabels();
  762. Assert(!this->handlerOffsetStack || this->handlerOffsetStack->Empty());
  763. // Insert bailout for ignore exception for labels, after all labels were finalized.
  764. ignoreExBranchInstrToOffsetMap.Map([this](IR::Instr* instr, int byteCodeOffset) {
  765. BailOutInfo * bailOutInfo = JitAnew(this->m_func->m_alloc, BailOutInfo, byteCodeOffset, this->m_func);
  766. instr->ConvertToBailOutInstr(bailOutInfo, c_debuggerBaseBailOutKindForHelper, true);
  767. });
  768. // Now that we know whether the func is a leaf or not, decide whether we'll emit fast paths.
  769. // Do this once and for all, per-func, since the source size on the ThreadContext will be
  770. // changing while we JIT.
  771. if (this->m_func->IsTopFunc())
  772. {
  773. this->m_func->SetDoFastPaths();
  774. this->EmitClosureRangeChecks();
  775. }
  776. }
  777. void
  778. IRBuilder::EmitClosureRangeChecks()
  779. {
  780. if (m_func->frameDisplayCheckTable)
  781. {
  782. // Frame display checks. Again, chain to the instruction (LdEnv/LdSlot).
  783. FOREACH_HASHTABLE_ENTRY(FrameDisplayCheckRecord*, bucket, m_func->frameDisplayCheckTable)
  784. {
  785. StackSym *stackSym = m_func->m_symTable->FindStackSym(bucket.value);
  786. Assert(stackSym && stackSym->m_instrDef);
  787. IR::Instr *instrDef = stackSym->m_instrDef;
  788. IR::Instr *insertInstr = instrDef->m_next;
  789. IR::RegOpnd *dstOpnd = instrDef->UnlinkDst()->AsRegOpnd();
  790. IR::Instr *instr = IR::Instr::New(Js::OpCode::FrameDisplayCheck, dstOpnd, m_func);
  791. dstOpnd = IR::RegOpnd::New(TyVar, m_func);
  792. instrDef->SetDst(dstOpnd);
  793. instr->SetSrc1(dstOpnd);
  794. // Attach the two-dimensional check info.
  795. IR::AddrOpnd *recordOpnd = IR::AddrOpnd::New(bucket.element, IR::AddrOpndKindDynamicMisc, m_func, true);
  796. instr->SetSrc2(recordOpnd);
  797. insertInstr->InsertBefore(instr);
  798. }
  799. NEXT_HASHTABLE_ENTRY;
  800. }
  801. // If not a loop, but there are loops and trys, restore scope slot pointer and FD
  802. if (!m_func->IsLoopBody() && m_func->HasTry() && m_func->GetJITFunctionBody()->GetByteCodeInLoopCount() != 0)
  803. {
  804. BVSparse<JitArenaAllocator> * bv = nullptr;
  805. if (m_func->GetLocalClosureSym() && m_func->GetLocalClosureSym()->HasByteCodeRegSlot())
  806. {
  807. bv = JitAnew(m_func->m_alloc, BVSparse<JitArenaAllocator>, m_func->m_alloc);
  808. bv->Set(m_func->GetLocalClosureSym()->m_id);
  809. }
  810. if (m_func->GetLocalFrameDisplaySym() && m_func->GetLocalFrameDisplaySym()->HasByteCodeRegSlot())
  811. {
  812. if (!bv)
  813. {
  814. bv = JitAnew(m_func->m_alloc, BVSparse<JitArenaAllocator>, m_func->m_alloc);
  815. }
  816. bv->Set(m_func->GetLocalFrameDisplaySym()->m_id);
  817. }
  818. if (bv)
  819. {
  820. FOREACH_INSTR_IN_FUNC_BACKWARD(instr, m_func)
  821. {
  822. if (instr->m_opcode == Js::OpCode::Ret)
  823. {
  824. IR::ByteCodeUsesInstr * byteCodeUse = IR::ByteCodeUsesInstr::New(instr);
  825. byteCodeUse->SetBV(bv);
  826. instr->InsertBefore(byteCodeUse);
  827. break;
  828. }
  829. }
  830. NEXT_INSTR_IN_FUNC_BACKWARD;
  831. }
  832. }
  833. }
  834. ///----------------------------------------------------------------------------
  835. ///
  836. /// IRBuilder::InsertLabels
  837. ///
  838. /// Insert label instructions at the offsets recorded in the branch reloc list.
  839. ///
  840. ///----------------------------------------------------------------------------
  841. void
  842. IRBuilder::InsertLabels()
  843. {
  844. AssertMsg(this->branchRelocList, "Malformed branch reloc list");
  845. SList<BranchReloc *>::Iterator iter(this->branchRelocList);
  846. while (iter.Next())
  847. {
  848. IR::LabelInstr * labelInstr = nullptr;
  849. BranchReloc * reloc = iter.Data();
  850. IR::BranchInstr * branchInstr = reloc->GetBranchInstr();
  851. uint offset = reloc->GetOffset();
  852. uint const branchOffset = reloc->GetBranchOffset();
  853. Assert(!IsLoopBody() || offset <= GetLoopBodyExitInstrOffset());
  854. if(branchInstr->m_opcode == Js::OpCode::MultiBr)
  855. {
  856. IR::MultiBranchInstr * multiBranchInstr = branchInstr->AsBranchInstr()->AsMultiBrInstr();
  857. multiBranchInstr->UpdateMultiBrTargetOffsets([&](uint32 offset) -> IR::LabelInstr *
  858. {
  859. labelInstr = this->CreateLabel(branchInstr, offset);
  860. multiBranchInstr->ChangeLabelRef(nullptr, labelInstr);
  861. return labelInstr;
  862. });
  863. }
  864. else
  865. {
  866. labelInstr = this->CreateLabel(branchInstr, offset);
  867. branchInstr->SetTarget(labelInstr);
  868. }
  869. if (!reloc->IsNotBackEdge() && branchOffset >= offset)
  870. {
  871. bool wasLoopTop = labelInstr->m_isLoopTop;
  872. labelInstr->m_isLoopTop = true;
  873. if (m_func->IsJitInDebugMode())
  874. {
  875. // Add bailout for Async Break.
  876. IR::BranchInstr* backEdgeBranchInstr = reloc->GetBranchInstr();
  877. this->InsertBailOutForDebugger(backEdgeBranchInstr->GetByteCodeOffset(), IR::BailOutForceByFlag | IR::BailOutBreakPointInFunction, backEdgeBranchInstr);
  878. }
  879. if (!wasLoopTop && m_loopCounterSym)
  880. {
  881. this->InsertIncrLoopBodyLoopCounter(labelInstr);
  882. }
  883. }
  884. }
  885. }
  886. IR::LabelInstr *
  887. IRBuilder::CreateLabel(IR::BranchInstr * branchInstr, uint& offset)
  888. {
  889. IR::LabelInstr * labelInstr;
  890. IR::Instr * targetInstr;
  891. for (;;)
  892. {
  893. AssertOrFailFast(offset < m_offsetToInstructionCount);
  894. targetInstr = this->m_offsetToInstruction[offset];
  895. if (targetInstr != nullptr)
  896. {
  897. #ifdef BYTECODE_BRANCH_ISLAND
  898. // If we have a long branch, remap it to the target offset
  899. if (targetInstr == VirtualLongBranchInstr)
  900. {
  901. offset = ResolveVirtualLongBranch(branchInstr, offset);
  902. continue;
  903. }
  904. #endif
  905. break;
  906. }
  907. offset++;
  908. }
  909. IR::Instr *instrPrev = targetInstr->m_prev;
  910. if (instrPrev)
  911. {
  912. instrPrev = targetInstr->GetPrevRealInstrOrLabel();
  913. }
  914. if (instrPrev && instrPrev->IsLabelInstr() && instrPrev->GetByteCodeOffset() == offset)
  915. {
  916. // Found an existing label at the right offset. Just reuse it.
  917. labelInstr = instrPrev->AsLabelInstr();
  918. }
  919. else
  920. {
  921. // No label at the desired offset. Create one.
  922. labelInstr = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  923. labelInstr->SetByteCodeOffset(offset);
  924. if (instrPrev)
  925. {
  926. instrPrev->InsertAfter(labelInstr);
  927. }
  928. else
  929. {
  930. targetInstr->InsertBefore(labelInstr);
  931. }
  932. }
  933. return labelInstr;
  934. }
  935. void IRBuilder::InsertInstr(IR::Instr *instr, IR::Instr* insertBeforeInstr)
  936. {
  937. AssertOrFailFast(insertBeforeInstr->GetByteCodeOffset() < m_offsetToInstructionCount);
  938. instr->SetByteCodeOffset(insertBeforeInstr);
  939. uint32 offset = insertBeforeInstr->GetByteCodeOffset();
  940. if (m_offsetToInstruction[offset] == insertBeforeInstr)
  941. {
  942. m_offsetToInstruction[offset] = instr;
  943. }
  944. insertBeforeInstr->InsertBefore(instr);
  945. #if DBG_DUMP
  946. if (PHASE_TRACE(Js::IRBuilderPhase, m_func->GetTopFunc()))
  947. {
  948. instr->Dump();
  949. }
  950. #endif
  951. }
  952. ///----------------------------------------------------------------------------
  953. ///
  954. /// IRBuilder::AddInstr
  955. ///
  956. /// Add an instruction to the current instr list. Also add this instr to
  957. /// offsetToinstruction table to patch branches/labels afterwards.
  958. ///
  959. ///----------------------------------------------------------------------------
  960. void
  961. IRBuilder::AddInstr(IR::Instr *instr, uint32 offset)
  962. {
  963. m_lastInstr->InsertAfter(instr);
  964. if (offset != Js::Constants::NoByteCodeOffset)
  965. {
  966. AssertOrFailFast(offset < m_offsetToInstructionCount);
  967. if (m_offsetToInstruction[offset] == nullptr)
  968. {
  969. m_offsetToInstruction[offset] = instr;
  970. }
  971. else
  972. {
  973. Assert(m_lastInstr->GetByteCodeOffset() == offset);
  974. }
  975. if (instr->GetByteCodeOffset() == Js::Constants::NoByteCodeOffset)
  976. {
  977. instr->SetByteCodeOffset(offset);
  978. }
  979. }
  980. else
  981. {
  982. instr->SetByteCodeOffset(m_lastInstr->GetByteCodeOffset());
  983. }
  984. m_lastInstr = instr;
  985. Func *topFunc = this->m_func->GetTopFunc();
  986. if (!topFunc->GetHasTempObjectProducingInstr())
  987. {
  988. if (OpCodeAttr::TempObjectProducing(instr->m_opcode))
  989. {
  990. topFunc->SetHasTempObjectProducingInstr(true);
  991. }
  992. }
  993. #if DBG_DUMP
  994. if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::IRBuilderPhase, this->m_func->GetTopFunc()->GetSourceContextId(), this->m_func->GetTopFunc()->GetLocalFunctionId()))
  995. {
  996. instr->Dump();
  997. }
  998. #endif
  999. }
  1000. IR::IndirOpnd *
  1001. IRBuilder::BuildIndirOpnd(IR::RegOpnd *baseReg, IR::RegOpnd *indexReg)
  1002. {
  1003. IR::IndirOpnd *indirOpnd = IR::IndirOpnd::New(baseReg, indexReg, TyVar, m_func);
  1004. return indirOpnd;
  1005. }
  1006. IR::IndirOpnd *
  1007. IRBuilder::BuildIndirOpnd(IR::RegOpnd *baseReg, uint32 offset)
  1008. {
  1009. IR::IndirOpnd *indirOpnd = IR::IndirOpnd::New(baseReg, offset, TyVar, m_func);
  1010. return indirOpnd;
  1011. }
  1012. #if DBG_DUMP || defined(ENABLE_IR_VIEWER)
  1013. IR::IndirOpnd *
  1014. IRBuilder::BuildIndirOpnd(IR::RegOpnd *baseReg, uint32 offset, const char16 *desc)
  1015. {
  1016. IR::IndirOpnd *indirOpnd = IR::IndirOpnd::New(baseReg, offset, TyVar, desc, m_func);
  1017. return indirOpnd;
  1018. }
  1019. #endif
  1020. IR::SymOpnd *
  1021. IRBuilder::BuildFieldOpnd(Js::OpCode newOpcode, Js::RegSlot reg, Js::PropertyId propertyId, Js::PropertyIdIndexType propertyIdIndex, PropertyKind propertyKind, uint inlineCacheIndex)
  1022. {
  1023. AssertOrFailFast(inlineCacheIndex < m_func->GetJITFunctionBody()->GetInlineCacheCount() || inlineCacheIndex == Js::Constants::NoInlineCacheIndex);
  1024. PropertySym * propertySym = BuildFieldSym(reg, propertyId, propertyIdIndex, inlineCacheIndex, propertyKind);
  1025. IR::SymOpnd * symOpnd;
  1026. // If we plan to apply object type optimization to this instruction or if we intend to emit a fast path using an inline
  1027. // cache, we will need a property sym operand.
  1028. if (OpCodeAttr::FastFldInstr(newOpcode) || inlineCacheIndex != (uint)-1)
  1029. {
  1030. Assert(propertyKind == PropertyKindData);
  1031. symOpnd = IR::PropertySymOpnd::New(propertySym, inlineCacheIndex, TyVar, this->m_func);
  1032. if (inlineCacheIndex != (uint)-1 && propertySym->m_loadInlineCacheIndex == (uint)-1)
  1033. {
  1034. if (GlobOpt::IsPREInstrCandidateLoad(newOpcode))
  1035. {
  1036. propertySym->m_loadInlineCacheIndex = inlineCacheIndex;
  1037. propertySym->m_loadInlineCacheFunc = this->m_func;
  1038. }
  1039. }
  1040. }
  1041. else
  1042. {
  1043. symOpnd = IR::SymOpnd::New(propertySym, TyVar, this->m_func);
  1044. }
  1045. return symOpnd;
  1046. }
  1047. PropertySym *
  1048. IRBuilder::BuildFieldSym(Js::RegSlot reg, Js::PropertyId propertyId, Js::PropertyIdIndexType propertyIdIndex, uint inlineCacheIndex, PropertyKind propertyKind)
  1049. {
  1050. PropertySym * propertySym;
  1051. SymID symId = this->BuildSrcStackSymID(reg);
  1052. AssertMsg(m_func->m_symTable->FindStackSym(symId), "Tried to use an undefined stacksym?");
  1053. propertySym = PropertySym::FindOrCreate(symId, propertyId, propertyIdIndex, inlineCacheIndex, propertyKind, m_func);
  1054. return propertySym;
  1055. }
  1056. SymID
  1057. IRBuilder::BuildSrcStackSymID(Js::RegSlot regSlot)
  1058. {
  1059. SymID symID;
  1060. if (this->RegIsTemp(regSlot))
  1061. {
  1062. // This is a use of a temp. Map the reg slot to its sym ID.
  1063. // !!!NOTE: always process an instruction's temp uses before its temp defs!!!
  1064. symID = this->GetMappedTemp(regSlot);
  1065. if (symID == 0)
  1066. {
  1067. // We might have temps that are live through the loop body via "with" statement
  1068. // We need to treat those as if they are locals and don't remap them
  1069. Assert(this->IsLoopBody());
  1070. Assert(!this->m_usedAsTemp->Test(regSlot - m_func->GetJITFunctionBody()->GetFirstTmpReg()));
  1071. symID = static_cast<SymID>(regSlot);
  1072. this->SetMappedTemp(regSlot, symID);
  1073. this->EnsureLoopBodyLoadSlot(symID);
  1074. }
  1075. }
  1076. else
  1077. {
  1078. symID = static_cast<SymID>(regSlot);
  1079. if (IsLoopBody() && !this->RegIsConstant(regSlot))
  1080. {
  1081. this->EnsureLoopBodyLoadSlot(symID);
  1082. }
  1083. }
  1084. return symID;
  1085. }
  1086. IR::RegOpnd *
  1087. IRBuilder::EnsureLoopBodyForInEnumeratorArrayOpnd()
  1088. {
  1089. Assert(this->IsLoopBody());
  1090. IR::RegOpnd * loopBodyForInEnumeratorArrayOpnd = this->m_loopBodyForInEnumeratorArrayOpnd;
  1091. if (loopBodyForInEnumeratorArrayOpnd == nullptr)
  1092. {
  1093. loopBodyForInEnumeratorArrayOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
  1094. this->m_loopBodyForInEnumeratorArrayOpnd = loopBodyForInEnumeratorArrayOpnd;
  1095. StackSym *loopParamSym = m_func->EnsureLoopParamSym();
  1096. IR::RegOpnd *loopParamOpnd = IR::RegOpnd::New(loopParamSym, TyMachPtr, m_func);
  1097. IR::Instr * ldInstr = IR::Instr::New(Js::OpCode::Ld_A, loopBodyForInEnumeratorArrayOpnd,
  1098. IR::IndirOpnd::New(loopParamOpnd, Js::InterpreterStackFrame::GetOffsetOfForInEnumerators(), TyMachPtr, this->m_func),
  1099. this->m_func);
  1100. m_func->m_headInstr->InsertAfter(ldInstr);
  1101. }
  1102. return loopBodyForInEnumeratorArrayOpnd;
  1103. }
  1104. IR::Opnd *
  1105. IRBuilder::BuildForInEnumeratorOpnd(uint forInLoopLevel, uint32 offset)
  1106. {
  1107. Assert(forInLoopLevel < this->m_func->GetJITFunctionBody()->GetForInLoopDepth());
  1108. if (this->IsLoopBody())
  1109. {
  1110. return IR::IndirOpnd::New(
  1111. this->EnsureLoopBodyForInEnumeratorArrayOpnd(),
  1112. forInLoopLevel * sizeof(Js::ForInObjectEnumerator),
  1113. TyMachPtr,
  1114. this->m_func
  1115. );
  1116. }
  1117. else if (this->m_func->GetJITFunctionBody()->IsCoroutine())
  1118. {
  1119. return IR::IndirOpnd::New(
  1120. this->m_generatorJumpTable.BuildForInEnumeratorArrayOpnd(offset),
  1121. forInLoopLevel * sizeof(Js::ForInObjectEnumerator),
  1122. TyMachPtr,
  1123. this->m_func
  1124. );
  1125. }
  1126. else
  1127. {
  1128. StackSym* stackSym = StackSym::New(TyMisc, this->m_func);
  1129. stackSym->m_offset = forInLoopLevel;
  1130. return IR::SymOpnd::New(stackSym, TyMachPtr, this->m_func);
  1131. }
  1132. }
  1133. ///----------------------------------------------------------------------------
  1134. ///
  1135. /// IRBuilder::BuildSrcOpnd
  1136. ///
  1137. /// Create a StackSym and return a RegOpnd for this RegSlot.
  1138. ///
  1139. ///----------------------------------------------------------------------------
  1140. IR::RegOpnd *
  1141. IRBuilder::BuildSrcOpnd(Js::RegSlot srcRegSlot, IRType type)
  1142. {
  1143. StackSym * symSrc = m_func->m_symTable->FindStackSym(BuildSrcStackSymID(srcRegSlot));
  1144. AssertMsg(symSrc, "Tried to use an undefined stack slot?");
  1145. IR::RegOpnd *regOpnd = IR::RegOpnd::New(symSrc, type, m_func);
  1146. return regOpnd;
  1147. }
  1148. ///----------------------------------------------------------------------------
  1149. ///
  1150. /// IRBuilder::BuildDstOpnd
  1151. ///
  1152. /// Create a StackSym and return a RegOpnd for this RegSlot.
  1153. /// If the RegSlot is '0', it may have multiple defs, so use FindOrCreate.
  1154. ///
  1155. ///----------------------------------------------------------------------------
  1156. IR::RegOpnd *
  1157. IRBuilder::BuildDstOpnd(Js::RegSlot dstRegSlot, IRType type, bool isCatchObjectSym, bool reuseTemp)
  1158. {
  1159. StackSym * symDst;
  1160. SymID symID;
  1161. if (this->RegIsTemp(dstRegSlot))
  1162. {
  1163. #if DBG
  1164. if (this->IsLoopBody())
  1165. {
  1166. // If we are doing loop body, and a temp reg slot is loaded via LdSlot
  1167. // That means that we have detected that the slot is live coming in to the loop.
  1168. // This would only happen for the value of a "with" statement, so there shouldn't
  1169. // be any def for those
  1170. Assert(!this->m_ldSlots->Test(dstRegSlot));
  1171. this->m_usedAsTemp->Set(dstRegSlot - m_func->GetJITFunctionBody()->GetFirstTmpReg());
  1172. }
  1173. #endif
  1174. // This is a def of a temp. Create a new sym ID for it if it's been used since its last def.
  1175. // !!!NOTE: always process an instruction's temp uses before its temp defs!!!
  1176. symID = this->GetMappedTemp(dstRegSlot);
  1177. if (symID == 0)
  1178. {
  1179. // First time we've seen the temp. Just use the number that the front end gave it.
  1180. symID = static_cast<SymID>(dstRegSlot);
  1181. this->SetMappedTemp(dstRegSlot, symID);
  1182. }
  1183. else if (!reuseTemp)
  1184. {
  1185. // Byte code has not told us to reuse the mapped temp at this def, so don't. Make a new one.
  1186. symID = m_func->m_symTable->NewID();
  1187. this->SetMappedTemp(dstRegSlot, symID);
  1188. }
  1189. }
  1190. else
  1191. {
  1192. symID = static_cast<SymID>(dstRegSlot);
  1193. if (this->RegIsConstant(dstRegSlot))
  1194. {
  1195. // Don't need to track constant registers for bailout. Don't set the byte code register for constant.
  1196. dstRegSlot = Js::Constants::NoRegister;
  1197. }
  1198. else if (IsLoopBody())
  1199. {
  1200. // Loop body and not constants
  1201. this->SetLoopBodyStSlot(symID, isCatchObjectSym);
  1202. // We need to make sure that the symbols is loaded as well
  1203. // so that the sym will be defined on all path.
  1204. this->EnsureLoopBodyLoadSlot(symID, isCatchObjectSym);
  1205. }
  1206. }
  1207. symDst = StackSym::FindOrCreate(symID, dstRegSlot, m_func);
  1208. // Always reset isSafeThis to false. We'll set it to true for singleDef cases,
  1209. // but want to reset it to false if it is multi-def.
  1210. // NOTE: We could handle the multiDef if they are all safe, but it probably isn't very common.
  1211. symDst->m_isSafeThis = false;
  1212. IR::RegOpnd *regOpnd = IR::RegOpnd::New(symDst, type, m_func);
  1213. return regOpnd;
  1214. }
  1215. void
  1216. IRBuilder::BuildImplicitArgIns()
  1217. {
  1218. Js::RegSlot startReg = m_func->GetJITFunctionBody()->GetConstCount() - 1;
  1219. for (Js::ArgSlot i = 1; i < m_func->GetJITFunctionBody()->GetInParamsCount(); i++)
  1220. {
  1221. this->BuildArgIn((uint32)-1, startReg + i, i);
  1222. }
  1223. }
  1224. void
  1225. IRBuilder::LoadNativeCodeData()
  1226. {
  1227. if (m_func->IsOOPJIT() && m_func->IsTopFunc())
  1228. {
  1229. IR::RegOpnd * nativeDataOpnd = IR::RegOpnd::New(TyVar, m_func);
  1230. IR::Instr * instr = IR::Instr::New(Js::OpCode::LdNativeCodeData, nativeDataOpnd, m_func);
  1231. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  1232. m_func->SetNativeCodeDataSym(nativeDataOpnd->GetStackSym());
  1233. }
  1234. }
  1235. void
  1236. IRBuilder::BuildConstantLoads()
  1237. {
  1238. Js::RegSlot count = m_func->GetJITFunctionBody()->GetConstCount();
  1239. for (Js::RegSlot reg = Js::FunctionBody::FirstRegSlot; reg < count; reg++)
  1240. {
  1241. intptr_t varConst = m_func->GetJITFunctionBody()->GetConstantVar(reg);
  1242. Assert(varConst != 0);
  1243. Js::TypeId type = m_func->GetJITFunctionBody()->GetConstantType(reg);
  1244. IR::RegOpnd *dstOpnd = this->BuildDstOpnd(reg);
  1245. Assert(this->RegIsConstant(reg));
  1246. dstOpnd->m_sym->SetIsFromByteCodeConstantTable();
  1247. // TODO: be more precise about this
  1248. ValueType valueType;
  1249. IR::Instr *instr = nullptr;
  1250. switch (type)
  1251. {
  1252. case Js::TypeIds_Number:
  1253. valueType = ValueType::Number;
  1254. instr = IR::Instr::NewConstantLoad(dstOpnd, varConst, valueType, m_func
  1255. #if !FLOATVAR
  1256. , m_func->IsOOPJIT() ? m_func->GetJITFunctionBody()->GetConstAsT<Js::JavascriptNumber>(reg) : nullptr
  1257. #endif
  1258. );
  1259. break;
  1260. case Js::TypeIds_String:
  1261. {
  1262. valueType = ValueType::String;
  1263. if (m_func->IsOOPJIT())
  1264. {
  1265. // must be either PropertyString or LiteralString
  1266. JITRecyclableObject * jitObj = m_func->GetJITFunctionBody()->GetConstantContent(reg);
  1267. JITJavascriptString * constStr = JITJavascriptString::FromVar(jitObj);
  1268. instr = IR::Instr::NewConstantLoad(dstOpnd, varConst, valueType, m_func, constStr);
  1269. }
  1270. else
  1271. {
  1272. instr = IR::Instr::NewConstantLoad(dstOpnd, varConst, valueType, m_func);
  1273. }
  1274. break;
  1275. }
  1276. case Js::TypeIds_Limit:
  1277. valueType = ValueType::FromTypeId(type, false);
  1278. instr = IR::Instr::NewConstantLoad(dstOpnd, varConst, valueType, m_func);
  1279. break;
  1280. default:
  1281. valueType = ValueType::FromTypeId(type, false);
  1282. instr = IR::Instr::NewConstantLoad(dstOpnd, varConst, valueType, m_func,
  1283. m_func->IsOOPJIT() ? m_func->GetJITFunctionBody()->GetConstAsT<Js::RecyclableObject>(reg) : nullptr);
  1284. break;
  1285. }
  1286. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  1287. }
  1288. }
  1289. ///----------------------------------------------------------------------------
  1290. ///
  1291. /// IRBuilder::BuildReg1
  1292. ///
  1293. /// Build IR instr for a Reg1 instruction.
  1294. ///
  1295. ///----------------------------------------------------------------------------
  1296. template <typename SizePolicy>
  1297. void
  1298. IRBuilder::BuildReg1(Js::OpCode newOpcode, uint32 offset)
  1299. {
  1300. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  1301. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  1302. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg1<SizePolicy>>();
  1303. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  1304. {
  1305. this->DoClosureRegCheck(layout->R0);
  1306. }
  1307. BuildReg1(newOpcode, offset, layout->R0);
  1308. }
  1309. void
  1310. IRBuilder::BuildReg1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0)
  1311. {
  1312. if (newOpcode == Js::OpCode::ArgIn0)
  1313. {
  1314. this->BuildArgIn0(offset, R0);
  1315. return;
  1316. }
  1317. IR::Instr * instr;
  1318. Js::RegSlot srcRegOpnd, dstRegSlot;
  1319. srcRegOpnd = dstRegSlot = R0;
  1320. IR::Opnd * srcOpnd = nullptr;
  1321. bool isNotInt = false;
  1322. bool dstIsCatchObject = false;
  1323. bool reuseLoc = false;
  1324. ValueType dstValueType;
  1325. switch (newOpcode)
  1326. {
  1327. case Js::OpCode::LdLetHeapArguments:
  1328. {
  1329. this->m_func->SetHasNonSimpleParams();
  1330. //FallThrough to next case block!
  1331. }
  1332. case Js::OpCode::LdHeapArguments:
  1333. {
  1334. if (this->m_func->GetJITFunctionBody()->NeedScopeObjectForArguments(m_func->GetHasNonSimpleParams()))
  1335. {
  1336. Js::RegSlot regFrameObj = m_func->GetJITFunctionBody()->GetLocalClosureReg();
  1337. Assert(regFrameObj != Js::Constants::NoRegister);
  1338. srcOpnd = BuildSrcOpnd(regFrameObj);
  1339. if (m_func->GetJITFunctionBody()->GetInParamsCount() > 1)
  1340. {
  1341. m_func->SetScopeObjSym(srcOpnd->GetStackSym());
  1342. }
  1343. }
  1344. else
  1345. {
  1346. srcOpnd = IR::AddrOpnd::New(
  1347. m_func->GetScriptContextInfo()->GetNullAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
  1348. }
  1349. IR::RegOpnd * dstOpnd = BuildDstOpnd(R0);
  1350. instr = IR::Instr::New(newOpcode, dstOpnd, srcOpnd, m_func);
  1351. this->AddInstr(instr, offset);
  1352. StackSym * dstSym = dstOpnd->m_sym;
  1353. if (dstSym->m_isSingleDef)
  1354. {
  1355. dstSym->m_isSafeThis = true;
  1356. dstSym->m_isNotNumber = true;
  1357. }
  1358. return;
  1359. }
  1360. case Js::OpCode::LdLetHeapArgsCached:
  1361. {
  1362. this->m_func->SetHasNonSimpleParams();
  1363. //Fallthrough to next case block!
  1364. }
  1365. case Js::OpCode::LdHeapArgsCached:
  1366. if (!m_func->GetJITFunctionBody()->HasScopeObject())
  1367. {
  1368. Js::Throw::FatalInternalError();
  1369. }
  1370. srcOpnd = BuildSrcOpnd(m_func->GetJITFunctionBody()->GetLocalClosureReg());
  1371. if (m_func->GetJITFunctionBody()->GetInParamsCount() > 1)
  1372. {
  1373. m_func->SetScopeObjSym(srcOpnd->GetStackSym());
  1374. }
  1375. isNotInt = true;
  1376. break;
  1377. case Js::OpCode::LdLocalObj_ReuseLoc:
  1378. reuseLoc = true;
  1379. // fall through
  1380. case Js::OpCode::LdLocalObj:
  1381. if (!m_func->GetJITFunctionBody()->HasScopeObject())
  1382. {
  1383. Js::Throw::FatalInternalError();
  1384. }
  1385. srcOpnd = BuildSrcOpnd(m_func->GetJITFunctionBody()->GetLocalClosureReg());
  1386. isNotInt = true;
  1387. newOpcode = Js::OpCode::Ld_A;
  1388. break;
  1389. case Js::OpCode::LdParamObj:
  1390. if (!m_func->GetJITFunctionBody()->HasScopeObject())
  1391. {
  1392. Js::Throw::FatalInternalError();
  1393. }
  1394. srcOpnd = BuildSrcOpnd(m_func->GetJITFunctionBody()->GetParamClosureReg());
  1395. isNotInt = true;
  1396. newOpcode = Js::OpCode::Ld_A;
  1397. break;
  1398. case Js::OpCode::Throw:
  1399. {
  1400. srcOpnd = this->BuildSrcOpnd(srcRegOpnd);
  1401. if ((this->handlerOffsetStack && !this->handlerOffsetStack->Empty()) ||
  1402. finallyBlockLevel > 0)
  1403. {
  1404. newOpcode = Js::OpCode::EHThrow;
  1405. }
  1406. instr = IR::Instr::New(newOpcode, m_func);
  1407. instr->SetSrc1(srcOpnd);
  1408. this->AddInstr(instr, offset);
  1409. if(DoBailOnNoProfile())
  1410. {
  1411. //So optimistically assume it doesn't throw and introduce bailonnoprofile here.
  1412. //If there are continuous bailout bailonnoprofile will be disabled.
  1413. InsertBailOnNoProfile(instr);
  1414. }
  1415. return;
  1416. }
  1417. case Js::OpCode::LdC_A_Null:
  1418. {
  1419. const auto addrOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetNullAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
  1420. addrOpnd->SetValueType(ValueType::Null);
  1421. srcOpnd = addrOpnd;
  1422. newOpcode = Js::OpCode::Ld_A;
  1423. break;
  1424. }
  1425. case Js::OpCode::LdUndef:
  1426. {
  1427. const auto addrOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetUndefinedAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
  1428. addrOpnd->SetValueType(ValueType::Undefined);
  1429. srcOpnd = addrOpnd;
  1430. newOpcode = Js::OpCode::Ld_A;
  1431. break;
  1432. }
  1433. case Js::OpCode::LdInfinity:
  1434. {
  1435. const auto floatConstOpnd = IR::FloatConstOpnd::New(Js::JavascriptNumber::POSITIVE_INFINITY, TyFloat64, m_func);
  1436. srcOpnd = floatConstOpnd;
  1437. newOpcode = Js::OpCode::LdC_A_R8;
  1438. break;
  1439. }
  1440. case Js::OpCode::LdNaN:
  1441. {
  1442. const auto floatConstOpnd = IR::FloatConstOpnd::New(Js::JavascriptNumber::NaN, TyFloat64, m_func);
  1443. srcOpnd = floatConstOpnd;
  1444. newOpcode = Js::OpCode::LdC_A_R8;
  1445. break;
  1446. }
  1447. case Js::OpCode::LdBaseFncProto:
  1448. {
  1449. // reuseLoc set to true as this is only used when that is wanted - during class extension
  1450. reuseLoc = true;
  1451. srcOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetFunctionPrototypeAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
  1452. newOpcode = Js::OpCode::Ld_A;
  1453. break;
  1454. }
  1455. case Js::OpCode::LdFalse_ReuseLoc:
  1456. reuseLoc = true;
  1457. // fall through
  1458. case Js::OpCode::LdFalse:
  1459. {
  1460. const auto addrOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetFalseAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
  1461. addrOpnd->SetValueType(ValueType::Boolean);
  1462. srcOpnd = addrOpnd;
  1463. newOpcode = Js::OpCode::Ld_A;
  1464. break;
  1465. }
  1466. case Js::OpCode::LdTrue_ReuseLoc:
  1467. reuseLoc = true;
  1468. // fall through
  1469. case Js::OpCode::LdTrue:
  1470. {
  1471. const auto addrOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetTrueAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
  1472. addrOpnd->SetValueType(ValueType::Boolean);
  1473. srcOpnd = addrOpnd;
  1474. newOpcode = Js::OpCode::Ld_A;
  1475. break;
  1476. }
  1477. case Js::OpCode::NewScObjectSimple:
  1478. dstValueType = ValueType::GetObject(ObjectType::UninitializedObject);
  1479. // fall-through
  1480. case Js::OpCode::LdFuncExpr:
  1481. m_func->DisableCanDoInlineArgOpt();
  1482. break;
  1483. case Js::OpCode::LdEnv:
  1484. case Js::OpCode::LdHomeObj:
  1485. case Js::OpCode::LdFuncObj:
  1486. isNotInt = TRUE;
  1487. break;
  1488. case Js::OpCode::InitUndecl:
  1489. srcOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetUndeclBlockVarAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
  1490. srcOpnd->SetValueType(ValueType::PrimitiveOrObject);
  1491. newOpcode = Js::OpCode::Ld_A;
  1492. break;
  1493. case Js::OpCode::ChkUndecl:
  1494. srcOpnd = BuildSrcOpnd(srcRegOpnd);
  1495. instr = IR::Instr::New(Js::OpCode::ChkUndecl, m_func);
  1496. instr->SetSrc1(srcOpnd);
  1497. this->AddInstr(instr, offset);
  1498. return;
  1499. case Js::OpCode::Catch:
  1500. if (this->handlerOffsetStack)
  1501. {
  1502. AssertOrFailFast(!this->handlerOffsetStack->Empty());
  1503. AssertOrFailFast(this->handlerOffsetStack->Top().Second() == true);
  1504. this->handlerOffsetStack->Pop();
  1505. }
  1506. dstIsCatchObject = true;
  1507. break;
  1508. case Js::OpCode::LdChakraLib:
  1509. {
  1510. const auto addrOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetChakraLibAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
  1511. addrOpnd->SetValueType(ValueType::PrimitiveOrObject);
  1512. srcOpnd = addrOpnd;
  1513. newOpcode = Js::OpCode::Ld_A;
  1514. break;
  1515. }
  1516. }
  1517. IR::RegOpnd * dstOpnd = this->BuildDstOpnd(dstRegSlot, TyVar, dstIsCatchObject, reuseLoc);
  1518. dstOpnd->SetValueType(dstValueType);
  1519. StackSym * dstSym = dstOpnd->m_sym;
  1520. dstSym->m_isCatchObjectSym = dstIsCatchObject;
  1521. instr = IR::Instr::New(newOpcode, dstOpnd, m_func);
  1522. if (srcOpnd)
  1523. {
  1524. instr->SetSrc1(srcOpnd);
  1525. if (dstSym->m_isSingleDef)
  1526. {
  1527. if (srcOpnd->IsHelperCallOpnd())
  1528. {
  1529. // Don't do anything
  1530. }
  1531. else if (srcOpnd->IsIntConstOpnd())
  1532. {
  1533. dstSym->SetIsIntConst(srcOpnd->AsIntConstOpnd()->GetValue());
  1534. }
  1535. else if (srcOpnd->IsFloatConstOpnd())
  1536. {
  1537. dstSym->SetIsFloatConst();
  1538. }
  1539. else if (srcOpnd->IsAddrOpnd())
  1540. {
  1541. dstSym->m_isConst = true;
  1542. dstSym->m_isNotNumber = true;
  1543. }
  1544. }
  1545. }
  1546. if (isNotInt && dstSym->m_isSingleDef)
  1547. {
  1548. dstSym->m_isNotNumber = true;
  1549. }
  1550. this->AddInstr(instr, offset);
  1551. }
  1552. ///----------------------------------------------------------------------------
  1553. ///
  1554. /// IRBuilder::BuildReg2
  1555. ///
  1556. /// Build IR instr for a Reg2 instruction.
  1557. ///
  1558. ///----------------------------------------------------------------------------
  1559. template <typename SizePolicy>
  1560. void
  1561. IRBuilder::BuildReg2(Js::OpCode newOpcode, uint32 offset)
  1562. {
  1563. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  1564. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  1565. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg2<SizePolicy>>();
  1566. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  1567. {
  1568. this->DoClosureRegCheck(layout->R0);
  1569. this->DoClosureRegCheck(layout->R1);
  1570. }
  1571. BuildReg2(newOpcode, offset, layout->R0, layout->R1, m_jnReader.GetCurrentOffset());
  1572. }
  1573. void
  1574. IRBuilder::BuildReg2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, Js::RegSlot R1, uint32 nextOffset)
  1575. {
  1576. IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(R1);
  1577. StackSym * symSrc1 = src1Opnd->m_sym;
  1578. bool reuseLoc = false;
  1579. switch (newOpcode)
  1580. {
  1581. case Js::OpCode::Ld_A_ReuseLoc:
  1582. newOpcode = Js::OpCode::Ld_A;
  1583. reuseLoc = true;
  1584. break;
  1585. case Js::OpCode::Typeof_ReuseLoc:
  1586. newOpcode = Js::OpCode::Typeof;
  1587. reuseLoc = true;
  1588. break;
  1589. case Js::OpCode::UnwrapWithObj_ReuseLoc:
  1590. newOpcode = Js::OpCode::UnwrapWithObj;
  1591. reuseLoc = true;
  1592. break;
  1593. case Js::OpCode::SpreadObjectLiteral:
  1594. // fall through
  1595. case Js::OpCode::SetComputedNameVar:
  1596. {
  1597. IR::Instr *instr = IR::Instr::New(newOpcode, m_func);
  1598. instr->SetSrc1(this->BuildSrcOpnd(R0));
  1599. instr->SetSrc2(src1Opnd);
  1600. this->AddInstr(instr, offset);
  1601. return;
  1602. }
  1603. case Js::OpCode::LdFuncExprFrameDisplay:
  1604. {
  1605. IR::RegOpnd *dstOpnd = IR::RegOpnd::New(TyVar, m_func);
  1606. IR::Instr *instr = IR::Instr::New(Js::OpCode::LdFrameDisplay, dstOpnd, src1Opnd, m_func);
  1607. Js::RegSlot envReg = this->GetEnvReg();
  1608. if (envReg != Js::Constants::NoRegister)
  1609. {
  1610. instr->SetSrc2(BuildSrcOpnd(envReg));
  1611. }
  1612. this->AddInstr(instr, offset);
  1613. IR::RegOpnd *src2Opnd = dstOpnd;
  1614. src1Opnd = BuildSrcOpnd(R0);
  1615. dstOpnd = BuildDstOpnd(m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg());
  1616. instr = IR::Instr::New(Js::OpCode::LdFrameDisplay, dstOpnd, src1Opnd, src2Opnd, m_func);
  1617. dstOpnd->m_sym->m_isNotNumber = true;
  1618. this->AddInstr(instr, offset);
  1619. return;
  1620. }
  1621. }
  1622. IR::RegOpnd * dstOpnd = this->BuildDstOpnd(R0, TyVar, false, reuseLoc);
  1623. StackSym * dstSym = dstOpnd->m_sym;
  1624. IR::Instr * instr = nullptr;
  1625. switch (newOpcode)
  1626. {
  1627. case Js::OpCode::Ld_A:
  1628. if (symSrc1->m_builtInIndex != Js::BuiltinFunction::None)
  1629. {
  1630. // Note: don't set dstSym->m_builtInIndex to None here (see Win8 399972)
  1631. dstSym->m_builtInIndex = symSrc1->m_builtInIndex;
  1632. }
  1633. break;
  1634. case Js::OpCode::Delete_A:
  1635. dstOpnd->SetValueType(ValueType::Boolean);
  1636. break;
  1637. case Js::OpCode::BeginSwitch:
  1638. m_switchBuilder.BeginSwitch();
  1639. newOpcode = Js::OpCode::Ld_A;
  1640. break;
  1641. case Js::OpCode::LdArrHead:
  1642. src1Opnd->SetValueType(
  1643. ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(false).SetArrayTypeId(Js::TypeIds_Array));
  1644. src1Opnd->SetValueTypeFixed();
  1645. break;
  1646. case Js::OpCode::LdInnerFrameDisplayNoParent:
  1647. {
  1648. instr = IR::Instr::New(Js::OpCode::LdInnerFrameDisplay, dstOpnd, src1Opnd, m_func);
  1649. this->AddEnvOpndForInnerFrameDisplay(instr, offset);
  1650. if (dstSym->m_isSingleDef)
  1651. {
  1652. dstSym->m_isNotNumber = true;
  1653. }
  1654. this->AddInstr(instr, offset);
  1655. return;
  1656. }
  1657. case Js::OpCode::Conv_Str:
  1658. dstOpnd->SetValueType(ValueType::String);
  1659. break;
  1660. case Js::OpCode::Yield:
  1661. instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, m_func);
  1662. this->AddInstr(instr, offset);
  1663. IR::Instr* yieldInstr = instr->ConvertToBailOutInstr(instr, IR::BailOutForGeneratorYield);
  1664. this->m_lastInstr = yieldInstr;
  1665. // This label indicates the bail-in section that we will jump to from the generator jump table
  1666. auto* bailInLabel = IR::GeneratorBailInInstr::New(yieldInstr, m_func);
  1667. bailInLabel->m_hasNonBranchRef = true; // set to true so that we don't move this label around
  1668. LABELNAMESET(bailInLabel, "GeneratorBailInLabel");
  1669. this->AddInstr(bailInLabel, offset);
  1670. this->m_func->AddYieldOffsetResumeLabel(nextOffset, bailInLabel);
  1671. yieldInstr->GetBailOutInfo()->bailInInstr = bailInLabel;
  1672. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1673. if (PHASE_TRACE(Js::Phase::BailInPhase, this->m_func))
  1674. {
  1675. IR::LabelInstr* traceBailInLabel = IR::LabelInstr::New(Js::OpCode::GeneratorOutputBailInTraceLabel, m_func);
  1676. traceBailInLabel->m_hasNonBranchRef = true; // set to true so that we don't move this label around
  1677. LABELNAMESET(traceBailInLabel, "OutputBailInTrace");
  1678. this->AddInstr(traceBailInLabel, offset);
  1679. IR::Instr* traceBailIn = IR::Instr::New(Js::OpCode::GeneratorOutputBailInTrace, m_func);
  1680. this->AddInstr(traceBailIn, offset);
  1681. }
  1682. #endif
  1683. IR::Instr* resumeYield = IR::Instr::New(Js::OpCode::GeneratorResumeYield, dstOpnd, m_func);
  1684. this->AddInstr(resumeYield, offset);
  1685. if (this->m_func->IsJitInDebugMode())
  1686. {
  1687. this->InsertBailOutForDebugger(offset, IR::BailOutForceByFlag | IR::BailOutBreakPointInFunction | IR::BailOutStep);
  1688. }
  1689. return;
  1690. }
  1691. if (instr == nullptr)
  1692. {
  1693. instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, m_func);
  1694. }
  1695. this->AddInstr(instr, offset);
  1696. }
  1697. ///----------------------------------------------------------------------------
  1698. ///
  1699. /// IRBuilder::BuildProfiledReg2
  1700. ///
  1701. /// Build IR instr for a profiled Reg2 instruction.
  1702. ///
  1703. ///----------------------------------------------------------------------------
  1704. template <typename SizePolicy>
  1705. void
  1706. IRBuilder::BuildProfiledReg2(Js::OpCode newOpcode, uint32 offset)
  1707. {
  1708. Assert(OpCodeAttr::IsProfiledOp(newOpcode));
  1709. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  1710. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_Reg2<SizePolicy>>>();
  1711. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  1712. {
  1713. this->DoClosureRegCheck(layout->R0);
  1714. this->DoClosureRegCheck(layout->R1);
  1715. }
  1716. BuildProfiledReg2(newOpcode, offset, layout->R0, layout->R1, layout->profileId);
  1717. }
  1718. void
  1719. IRBuilder::BuildProfiledReg2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot srcRegSlot, Js::ProfileId profileId)
  1720. {
  1721. bool switchFound = false;
  1722. Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
  1723. Assert(newOpcode == Js::OpCode::BeginSwitch);
  1724. IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(srcRegSlot);
  1725. IR::RegOpnd * dstOpnd;
  1726. if(srcRegSlot == dstRegSlot)
  1727. {
  1728. //if the operands are the same for BeginSwitch, don't build a new operand in IR.
  1729. dstOpnd = src1Opnd;
  1730. }
  1731. else
  1732. {
  1733. dstOpnd = this->BuildDstOpnd(dstRegSlot);
  1734. }
  1735. m_switchBuilder.BeginSwitch();
  1736. switchFound = true;
  1737. newOpcode = Js::OpCode::Ld_A; // BeginSwitch is originally equivalent to Ld_A
  1738. IR::Instr *instr;
  1739. if (m_func->DoSimpleJitDynamicProfile())
  1740. {
  1741. // Since we're in simplejit, we want to keep track of the profileid:
  1742. IR::JitProfilingInstr *profiledInstr = IR::JitProfilingInstr::New(newOpcode, dstOpnd, src1Opnd, m_func);
  1743. profiledInstr->profileId = profileId;
  1744. profiledInstr->isBeginSwitch = newOpcode == Js::OpCode::Ld_A;
  1745. instr = profiledInstr;
  1746. }
  1747. else
  1748. {
  1749. IR::ProfiledInstr *profiledInstr = IR::ProfiledInstr::New(newOpcode, dstOpnd, src1Opnd, m_func);
  1750. instr = profiledInstr;
  1751. profiledInstr->u.FldInfo() = Js::FldInfo();
  1752. }
  1753. this->AddInstr(instr, offset);
  1754. if(switchFound && instr->IsProfiledInstr())
  1755. {
  1756. m_switchBuilder.SetProfiledInstruction(instr, profileId);
  1757. }
  1758. }
  1759. ///----------------------------------------------------------------------------
  1760. ///
  1761. /// IRBuilder::BuildReg3
  1762. ///
  1763. /// Build IR instr for a Reg3 instruction.
  1764. ///
  1765. ///----------------------------------------------------------------------------
  1766. template <typename SizePolicy>
  1767. void
  1768. IRBuilder::BuildReg3(Js::OpCode newOpcode, uint32 offset)
  1769. {
  1770. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  1771. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  1772. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg3<SizePolicy>>();
  1773. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func) && newOpcode != Js::OpCode::NewInnerScopeSlots)
  1774. {
  1775. this->DoClosureRegCheck(layout->R0);
  1776. this->DoClosureRegCheck(layout->R1);
  1777. this->DoClosureRegCheck(layout->R2);
  1778. }
  1779. BuildReg3(newOpcode, offset, layout->R0, layout->R1, layout->R2, Js::Constants::NoProfileId);
  1780. }
  1781. template <typename SizePolicy>
  1782. void
  1783. IRBuilder::BuildProfiledReg3(Js::OpCode newOpcode, uint32 offset)
  1784. {
  1785. Assert(OpCodeAttr::IsProfiledOp(newOpcode));
  1786. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  1787. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_Reg3<SizePolicy>>>();
  1788. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  1789. {
  1790. this->DoClosureRegCheck(layout->R0);
  1791. this->DoClosureRegCheck(layout->R1);
  1792. this->DoClosureRegCheck(layout->R2);
  1793. }
  1794. Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
  1795. BuildReg3(newOpcode, offset, layout->R0, layout->R1, layout->R2, layout->profileId);
  1796. }
  1797. void
  1798. IRBuilder::BuildReg3(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
  1799. Js::RegSlot src2RegSlot, Js::ProfileId profileId)
  1800. {
  1801. IR::Instr * instr;
  1802. if (newOpcode == Js::OpCode::NewInnerScopeSlots)
  1803. {
  1804. if (dstRegSlot >= m_func->GetJITFunctionBody()->GetInnerScopeCount())
  1805. {
  1806. Js::Throw::FatalInternalError();
  1807. }
  1808. newOpcode = Js::OpCode::NewScopeSlotsWithoutPropIds;
  1809. dstRegSlot += m_func->GetJITFunctionBody()->GetFirstInnerScopeReg();
  1810. instr = IR::Instr::New(newOpcode, BuildDstOpnd(dstRegSlot),
  1811. IR::IntConstOpnd::New(src1RegSlot, TyVar, m_func),
  1812. IR::IntConstOpnd::New(src2RegSlot, TyVar, m_func),
  1813. m_func);
  1814. if (instr->GetDst()->AsRegOpnd()->m_sym->m_isSingleDef)
  1815. {
  1816. instr->GetDst()->AsRegOpnd()->m_sym->m_isNotNumber = true;
  1817. }
  1818. this->AddInstr(instr, offset);
  1819. return;
  1820. }
  1821. IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(src1RegSlot);
  1822. IR::RegOpnd * src2Opnd = this->BuildSrcOpnd(src2RegSlot);
  1823. IR::RegOpnd * dstOpnd = this->BuildDstOpnd(dstRegSlot);
  1824. StackSym * dstSym = dstOpnd->m_sym;
  1825. bool isProfiledInstr = (profileId != Js::Constants::NoProfileId);
  1826. bool wasNotProfiled = false;
  1827. const Js::LdElemInfo * ldElemInfo = nullptr;
  1828. if (isProfiledInstr && newOpcode == Js::OpCode::IsIn)
  1829. {
  1830. if (!DoLoadInstructionArrayProfileInfo())
  1831. {
  1832. isProfiledInstr = false;
  1833. }
  1834. else
  1835. {
  1836. ldElemInfo = this->m_func->GetReadOnlyProfileInfo()->GetLdElemInfo(profileId);
  1837. ValueType arrayType = ldElemInfo->GetArrayType();
  1838. wasNotProfiled = !ldElemInfo->WasProfiled();
  1839. if (arrayType.IsLikelyNativeArray() && !AllowNativeArrayProfileInfo())
  1840. {
  1841. arrayType = arrayType.SetArrayTypeId(Js::TypeIds_Array);
  1842. // An opnd's value type will get replaced in the forward phase when it is not fixed. Store the array type in the ProfiledInstr.
  1843. Js::LdElemInfo *const newLdElemInfo = JitAnew(m_func->m_alloc, Js::LdElemInfo, *ldElemInfo);
  1844. newLdElemInfo->arrayType = arrayType;
  1845. ldElemInfo = newLdElemInfo;
  1846. }
  1847. src2Opnd->SetValueType(arrayType);
  1848. if (m_func->GetTopFunc()->HasTry() && !m_func->GetTopFunc()->DoOptimizeTry())
  1849. {
  1850. isProfiledInstr = false;
  1851. }
  1852. }
  1853. }
  1854. if (isProfiledInstr)
  1855. {
  1856. if (m_func->DoSimpleJitDynamicProfile())
  1857. {
  1858. instr = IR::JitProfilingInstr::New(newOpcode, dstOpnd, src1Opnd, src2Opnd, m_func);
  1859. instr->AsJitProfilingInstr()->profileId = profileId;
  1860. }
  1861. else
  1862. {
  1863. instr = IR::ProfiledInstr::New(newOpcode, dstOpnd, src1Opnd, src2Opnd, m_func);
  1864. if (newOpcode == Js::OpCode::IsIn)
  1865. {
  1866. instr->AsProfiledInstr()->u.ldElemInfo = ldElemInfo;
  1867. }
  1868. else
  1869. {
  1870. instr->AsProfiledInstr()->u.profileId = profileId;
  1871. }
  1872. }
  1873. }
  1874. else
  1875. {
  1876. instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, src2Opnd, m_func);
  1877. }
  1878. this->AddInstr(instr, offset);
  1879. if (wasNotProfiled && DoBailOnNoProfile())
  1880. {
  1881. InsertBailOnNoProfile(instr);
  1882. }
  1883. switch (newOpcode)
  1884. {
  1885. case Js::OpCode::LdHandlerScope:
  1886. case Js::OpCode::NewScopeSlotsWithoutPropIds:
  1887. if (dstSym->m_isSingleDef)
  1888. {
  1889. dstSym->m_isNotNumber = true;
  1890. }
  1891. break;
  1892. case Js::OpCode::LdInnerFrameDisplay:
  1893. if (dstSym->m_isSingleDef)
  1894. {
  1895. dstSym->m_isNotNumber = true;
  1896. }
  1897. break;
  1898. }
  1899. }
  1900. ///----------------------------------------------------------------------------
  1901. ///
  1902. /// IRBuilder::BuildReg3C
  1903. ///
  1904. /// Build IR instr for a Reg3C instruction.
  1905. ///
  1906. ///----------------------------------------------------------------------------
  1907. template <typename SizePolicy>
  1908. void
  1909. IRBuilder::BuildReg3C(Js::OpCode newOpcode, uint32 offset)
  1910. {
  1911. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  1912. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  1913. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg3C<SizePolicy>>();
  1914. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  1915. {
  1916. this->DoClosureRegCheck(layout->R0);
  1917. this->DoClosureRegCheck(layout->R1);
  1918. this->DoClosureRegCheck(layout->R2);
  1919. }
  1920. BuildReg3C(newOpcode, offset, layout->R0, layout->R1, layout->R2, layout->inlineCacheIndex);
  1921. }
  1922. void
  1923. IRBuilder::BuildReg3C(Js::OpCode newOpCode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
  1924. Js::RegSlot src2RegSlot, Js::CacheId inlineCacheIndex)
  1925. {
  1926. Assert(OpCodeAttr::HasMultiSizeLayout(newOpCode));
  1927. IR::Instr * instr;
  1928. IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(src1RegSlot);
  1929. IR::RegOpnd * src2Opnd = this->BuildSrcOpnd(src2RegSlot);
  1930. IR::RegOpnd * dstOpnd = this->BuildDstOpnd(dstRegSlot);
  1931. instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src2Opnd, m_func);
  1932. this->AddInstr(instr, offset);
  1933. instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src1Opnd, instr->GetDst(), m_func);
  1934. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  1935. instr = IR::Instr::New(newOpCode, dstOpnd, IR::IntConstOpnd::New(inlineCacheIndex, TyUint32, m_func), instr->GetDst(), m_func);
  1936. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  1937. }
  1938. void
  1939. IRBuilder::BuildReg2U(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, Js::RegSlot R1, uint index)
  1940. {
  1941. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  1942. switch (newOpcode)
  1943. {
  1944. case Js::OpCode::InitBaseClass:
  1945. {
  1946. IR::Opnd * opndProtoParent = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetObjectPrototypeAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
  1947. IR::Opnd * opndCtorParent = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetFunctionPrototypeAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
  1948. BuildInitClass(offset, R0, R1, opndProtoParent, opndCtorParent, GetEnvironmentOperand(offset), index);
  1949. break;
  1950. }
  1951. default:
  1952. AssertMsg(false, "Unknown Reg2U op");
  1953. break;
  1954. }
  1955. }
  1956. template <typename SizePolicy>
  1957. void
  1958. IRBuilder::BuildReg2U(Js::OpCode newOpcode, uint32 offset)
  1959. {
  1960. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  1961. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  1962. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg2U<SizePolicy>>();
  1963. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  1964. {
  1965. this->DoClosureRegCheck(layout->R0);
  1966. this->DoClosureRegCheck(layout->R1);
  1967. }
  1968. BuildReg2U(newOpcode, offset, layout->R0, layout->R1, layout->SlotIndex);
  1969. }
  1970. void
  1971. IRBuilder::BuildReg3U(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, Js::RegSlot R1, Js::RegSlot R2, uint index)
  1972. {
  1973. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  1974. switch (newOpcode)
  1975. {
  1976. case Js::OpCode::InitInnerBaseClass:
  1977. {
  1978. IR::Opnd * opndProtoParent = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetObjectPrototypeAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
  1979. IR::Opnd * opndCtorParent = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetFunctionPrototypeAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
  1980. BuildInitClass(offset, R0, R1, opndProtoParent, opndCtorParent, BuildSrcOpnd(R2), index);
  1981. break;
  1982. }
  1983. default:
  1984. AssertMsg(false, "Unknown Reg3U op");
  1985. break;
  1986. }
  1987. }
  1988. template <typename SizePolicy>
  1989. void
  1990. IRBuilder::BuildReg3U(Js::OpCode newOpcode, uint32 offset)
  1991. {
  1992. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  1993. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  1994. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg3U<SizePolicy>>();
  1995. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  1996. {
  1997. this->DoClosureRegCheck(layout->R0);
  1998. this->DoClosureRegCheck(layout->R1);
  1999. this->DoClosureRegCheck(layout->R2);
  2000. }
  2001. BuildReg3U(newOpcode, offset, layout->R0, layout->R1, layout->R2, layout->SlotIndex);
  2002. }
  2003. template <typename SizePolicy>
  2004. void
  2005. IRBuilder::BuildReg4U(Js::OpCode newOpcode, uint32 offset)
  2006. {
  2007. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  2008. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2009. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg4U<SizePolicy>>();
  2010. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  2011. {
  2012. this->DoClosureRegCheck(layout->R0);
  2013. this->DoClosureRegCheck(layout->R1);
  2014. this->DoClosureRegCheck(layout->R2);
  2015. this->DoClosureRegCheck(layout->R3);
  2016. }
  2017. BuildReg4U(newOpcode, offset, layout->R0, layout->R1, layout->R2, layout->R3, layout->SlotIndex);
  2018. }
  2019. void
  2020. IRBuilder::BuildReg4U(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, Js::RegSlot R1, Js::RegSlot R2, Js::RegSlot R3, uint slotIndex)
  2021. {
  2022. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2023. switch (newOpcode)
  2024. {
  2025. case Js::OpCode::InitClass:
  2026. {
  2027. BuildInitClass(offset, R0, R1, BuildSrcOpnd(R3), BuildSrcOpnd(R2), GetEnvironmentOperand(offset), slotIndex);
  2028. break;
  2029. }
  2030. default:
  2031. AssertMsg(false, "Unknown Reg4U opcode");
  2032. break;
  2033. }
  2034. }
  2035. template <typename SizePolicy>
  2036. void
  2037. IRBuilder::BuildReg5U(Js::OpCode newOpcode, uint32 offset)
  2038. {
  2039. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  2040. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2041. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg5U<SizePolicy>>();
  2042. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  2043. {
  2044. this->DoClosureRegCheck(layout->R0);
  2045. this->DoClosureRegCheck(layout->R1);
  2046. this->DoClosureRegCheck(layout->R2);
  2047. this->DoClosureRegCheck(layout->R3);
  2048. this->DoClosureRegCheck(layout->R4);
  2049. }
  2050. BuildReg5U(newOpcode, offset, layout->R0, layout->R1, layout->R2, layout->R3, layout->R4, layout->SlotIndex);
  2051. }
  2052. void
  2053. IRBuilder::BuildReg5U(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, Js::RegSlot R1, Js::RegSlot R2, Js::RegSlot R3, Js::RegSlot R4, uint slotIndex)
  2054. {
  2055. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2056. switch (newOpcode)
  2057. {
  2058. case Js::OpCode::InitInnerClass:
  2059. {
  2060. BuildInitClass(offset, R0, R1, BuildSrcOpnd(R3), BuildSrcOpnd(R2), BuildSrcOpnd(R4), slotIndex);
  2061. break;
  2062. }
  2063. default:
  2064. AssertMsg(false, "Unknown Reg5U opcode");
  2065. break;
  2066. }
  2067. }
  2068. void
  2069. IRBuilder::BuildInitClass(uint32 offset, Js::RegSlot regConstructor, Js::RegSlot regProto, IR::Opnd * opndProtoParent, IR::Opnd * opndConstructorParent, IR::Opnd * opndEnvironment, uint index)
  2070. {
  2071. IR::RegOpnd * opndProto = BuildDstOpnd(regProto);
  2072. opndProto->SetValueType(ValueType::GetObject(ObjectType::Object));
  2073. IR::Instr * instr = IR::Instr::New(Js::OpCode::NewClassProto, opndProto, opndProtoParent, m_func);
  2074. this->AddInstr(instr, offset);
  2075. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), opndConstructorParent, m_func);
  2076. this->AddInstr(instr, offset);
  2077. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), opndProto, instr->GetDst(), m_func);
  2078. this->AddInstr(instr, offset);
  2079. Js::FunctionInfoPtrPtr infoRef = m_func->GetJITFunctionBody()->GetNestedFuncRef(index);
  2080. IR::AddrOpnd * functionBodySlotOpnd = IR::AddrOpnd::New((Js::Var)infoRef, IR::AddrOpndKindDynamicMisc, m_func);
  2081. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), functionBodySlotOpnd, instr->GetDst(), m_func);
  2082. this->AddInstr(instr, offset);
  2083. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), opndEnvironment, instr->GetDst(), m_func);
  2084. this->AddInstr(instr, offset);
  2085. IR::RegOpnd * opndConstructor = BuildDstOpnd(regConstructor);
  2086. instr = IR::Instr::New(Js::OpCode::NewClassConstructor, opndConstructor, instr->GetDst(), m_func);
  2087. this->AddInstr(instr, offset);
  2088. Assert(opndConstructor->m_sym->m_isSingleDef);
  2089. opndConstructor->m_sym->m_isSafeThis = true;
  2090. opndConstructor->m_sym->m_isNotNumber = true;
  2091. }
  2092. ///----------------------------------------------------------------------------
  2093. ///
  2094. /// IRBuilder::BuildReg4
  2095. ///
  2096. /// Build IR instr for a Reg4 instruction.
  2097. ///
  2098. ///----------------------------------------------------------------------------
  2099. template <typename SizePolicy>
  2100. void
  2101. IRBuilder::BuildReg4(Js::OpCode newOpcode, uint32 offset)
  2102. {
  2103. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  2104. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2105. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg4<SizePolicy>>();
  2106. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  2107. {
  2108. this->DoClosureRegCheck(layout->R0);
  2109. this->DoClosureRegCheck(layout->R1);
  2110. this->DoClosureRegCheck(layout->R2);
  2111. this->DoClosureRegCheck(layout->R3);
  2112. }
  2113. BuildReg4(newOpcode, offset, layout->R0, layout->R1, layout->R2, layout->R3);
  2114. }
  2115. void
  2116. IRBuilder::BuildReg4(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
  2117. Js::RegSlot src2RegSlot, Js::RegSlot src3RegSlot)
  2118. {
  2119. IR::Instr * instr = nullptr;
  2120. Assert(newOpcode == Js::OpCode::Concat3 || newOpcode == Js::OpCode::Restify);
  2121. IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(src1RegSlot);
  2122. IR::RegOpnd * src2Opnd = this->BuildSrcOpnd(src2RegSlot);
  2123. IR::RegOpnd * src3Opnd = this->BuildSrcOpnd(src3RegSlot);
  2124. if (newOpcode == Js::OpCode::Restify)
  2125. {
  2126. IR::RegOpnd * src0Opnd = this->BuildSrcOpnd(dstRegSlot);
  2127. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), src3Opnd, m_func);
  2128. this->AddInstr(instr, offset);
  2129. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), src2Opnd, instr->GetDst(), m_func);
  2130. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2131. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), src1Opnd, instr->GetDst(), m_func);
  2132. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2133. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), src0Opnd, instr->GetDst(), m_func);
  2134. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2135. IR::Opnd *firstArg = instr->GetDst();
  2136. instr = IR::Instr::New(newOpcode, m_func);
  2137. instr->SetSrc1(firstArg);
  2138. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2139. return;
  2140. }
  2141. IR::RegOpnd * dstOpnd = this->BuildDstOpnd(dstRegSlot);
  2142. IR::RegOpnd * str1Opnd = InsertConvPrimStr(src1Opnd, offset, true);
  2143. IR::RegOpnd * str2Opnd = InsertConvPrimStr(src2Opnd, Js::Constants::NoByteCodeOffset, true);
  2144. IR::RegOpnd * str3Opnd = InsertConvPrimStr(src3Opnd, Js::Constants::NoByteCodeOffset, true);
  2145. // Need to insert a byte code use for src1/src2 that if ConvPrimStr of the src2/src3 bail out
  2146. // we will restore it.
  2147. bool src1HasByteCodeRegSlot = src1Opnd->m_sym->HasByteCodeRegSlot();
  2148. bool src2HasByteCodeRegSlot = src2Opnd->m_sym->HasByteCodeRegSlot();
  2149. if (src1HasByteCodeRegSlot || src2HasByteCodeRegSlot)
  2150. {
  2151. IR::ByteCodeUsesInstr * byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, Js::Constants::NoByteCodeOffset);
  2152. if (src1HasByteCodeRegSlot)
  2153. {
  2154. byteCodeUse->Set(src1Opnd);
  2155. }
  2156. if (src2HasByteCodeRegSlot)
  2157. {
  2158. byteCodeUse->Set(src2Opnd);
  2159. }
  2160. this->AddInstr(byteCodeUse, Js::Constants::NoByteCodeOffset);
  2161. }
  2162. if (!PHASE_OFF(Js::BackendConcatExprOptPhase, this->m_func))
  2163. {
  2164. IR::RegOpnd* tmpDstOpnd1 = IR::RegOpnd::New(StackSym::New(this->m_func), TyVar, this->m_func);
  2165. IR::RegOpnd* tmpDstOpnd2 = IR::RegOpnd::New(StackSym::New(this->m_func), TyVar, this->m_func);
  2166. IR::RegOpnd* tmpDstOpnd3 = IR::RegOpnd::New(StackSym::New(this->m_func), TyVar, this->m_func);
  2167. instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItemBE, tmpDstOpnd1, str1Opnd, m_func);
  2168. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2169. instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItemBE, tmpDstOpnd2, str2Opnd, tmpDstOpnd1, m_func);
  2170. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2171. instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItemBE, tmpDstOpnd3, str3Opnd, tmpDstOpnd2, m_func);
  2172. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2173. IR::IntConstOpnd * countIntConstOpnd = IR::IntConstOpnd::New(3, TyUint32, m_func, true);
  2174. instr = IR::Instr::New(Js::OpCode::NewConcatStrMultiBE, dstOpnd, countIntConstOpnd, tmpDstOpnd3, m_func);
  2175. dstOpnd->SetValueType(ValueType::String);
  2176. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2177. }
  2178. else
  2179. {
  2180. instr = IR::Instr::New(Js::OpCode::NewConcatStrMulti, dstOpnd, IR::IntConstOpnd::New(3, TyUint32, m_func, true), m_func);
  2181. dstOpnd->SetValueType(ValueType::String);
  2182. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2183. instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItem, IR::IndirOpnd::New(dstOpnd, 0, TyVar, m_func), str1Opnd, m_func);
  2184. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2185. instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItem, IR::IndirOpnd::New(dstOpnd, 1, TyVar, m_func), str2Opnd, m_func);
  2186. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2187. instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItem, IR::IndirOpnd::New(dstOpnd, 2, TyVar, m_func), str3Opnd, m_func);
  2188. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2189. }
  2190. }
  2191. IR::RegOpnd *
  2192. IRBuilder::InsertConvPrimStr(IR::RegOpnd * srcOpnd, uint offset, bool forcePreOpBailOutIfNeeded)
  2193. {
  2194. IR::RegOpnd * strOpnd = IR::RegOpnd::New(TyVar, this->m_func);
  2195. IR::Instr * instr = IR::Instr::New(Js::OpCode::Conv_PrimStr, strOpnd, srcOpnd, m_func);
  2196. instr->forcePreOpBailOutIfNeeded = forcePreOpBailOutIfNeeded;
  2197. strOpnd->SetValueType(ValueType::String);
  2198. strOpnd->SetValueTypeFixed();
  2199. this->AddInstr(instr, offset);
  2200. return strOpnd;
  2201. }
  2202. template <typename SizePolicy>
  2203. void
  2204. IRBuilder::BuildReg2B1(Js::OpCode newOpcode, uint32 offset)
  2205. {
  2206. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  2207. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2208. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg2B1<SizePolicy>>();
  2209. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  2210. {
  2211. this->DoClosureRegCheck(layout->R0);
  2212. this->DoClosureRegCheck(layout->R1);
  2213. }
  2214. BuildReg2B1(newOpcode, offset, layout->R0, layout->R1, layout->B2);
  2215. }
  2216. void
  2217. IRBuilder::BuildReg2B1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot srcRegSlot, byte index)
  2218. {
  2219. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2220. Assert(newOpcode == Js::OpCode::SetConcatStrMultiItem);
  2221. IR::Instr * instr;
  2222. IR::RegOpnd * srcOpnd = this->BuildSrcOpnd(srcRegSlot);
  2223. IR::RegOpnd * dstOpnd = this->BuildDstOpnd(dstRegSlot, TyVar, false, true);
  2224. IR::IndirOpnd * indir1Opnd = IR::IndirOpnd::New(dstOpnd, index, TyVar, m_func);
  2225. dstOpnd->SetValueType(ValueType::String);
  2226. instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItem, indir1Opnd, InsertConvPrimStr(srcOpnd, offset, true), m_func);
  2227. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2228. }
  2229. template <typename SizePolicy>
  2230. void
  2231. IRBuilder::BuildReg3B1(Js::OpCode newOpcode, uint32 offset)
  2232. {
  2233. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  2234. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2235. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg3B1<SizePolicy>>();
  2236. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  2237. {
  2238. this->DoClosureRegCheck(layout->R0);
  2239. this->DoClosureRegCheck(layout->R1);
  2240. this->DoClosureRegCheck(layout->R2);
  2241. }
  2242. BuildReg3B1(newOpcode, offset, layout->R0, layout->R1, layout->R2, layout->B3);
  2243. }
  2244. void
  2245. IRBuilder::BuildReg3B1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
  2246. Js::RegSlot src2RegSlot, uint8 index)
  2247. {
  2248. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2249. IR::Instr * instr;
  2250. IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(src1RegSlot);
  2251. IR::RegOpnd * src2Opnd = this->BuildSrcOpnd(src2RegSlot);
  2252. IR::RegOpnd * dstOpnd = nullptr;
  2253. IR::Instr * newConcatStrMulti = nullptr;
  2254. switch (newOpcode)
  2255. {
  2256. case Js::OpCode::NewConcatStrMulti:
  2257. dstOpnd = this->BuildDstOpnd(dstRegSlot);
  2258. newConcatStrMulti = IR::Instr::New(Js::OpCode::NewConcatStrMulti, dstOpnd, IR::IntConstOpnd::New(index, TyUint32, m_func), m_func);
  2259. index = 0;
  2260. break;
  2261. case Js::OpCode::SetConcatStrMultiItem2:
  2262. dstOpnd = this->BuildDstOpnd(dstRegSlot, TyVar, false, true);
  2263. break;
  2264. default:
  2265. Assert(false);
  2266. };
  2267. dstOpnd->SetValueType(ValueType::String);
  2268. IR::IndirOpnd * indir1Opnd = IR::IndirOpnd::New(dstOpnd, index, TyVar, m_func);
  2269. IR::IndirOpnd * indir2Opnd = IR::IndirOpnd::New(dstOpnd, index + 1, TyVar, m_func);
  2270. // Need to do the to str first, as they may have side effects.
  2271. IR::RegOpnd * str1Opnd = InsertConvPrimStr(src1Opnd, offset, true);
  2272. IR::RegOpnd * str2Opnd = InsertConvPrimStr(src2Opnd, Js::Constants::NoByteCodeOffset, true);
  2273. // Need to insert a byte code use for src1 so that if ConvPrimStr of the src2 bail out
  2274. // we will restore it.
  2275. if (src1Opnd->m_sym->HasByteCodeRegSlot())
  2276. {
  2277. IR::ByteCodeUsesInstr * byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, Js::Constants::NoByteCodeOffset);
  2278. byteCodeUse->Set(src1Opnd);
  2279. this->AddInstr(byteCodeUse, Js::Constants::NoByteCodeOffset);
  2280. }
  2281. if (newConcatStrMulti)
  2282. {
  2283. // Allocate the concat str after the ConvToStr
  2284. this->AddInstr(newConcatStrMulti, Js::Constants::NoByteCodeOffset);
  2285. }
  2286. instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItem, indir1Opnd, str1Opnd, m_func);
  2287. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2288. instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItem, indir2Opnd, str2Opnd, m_func);
  2289. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2290. }
  2291. ///----------------------------------------------------------------------------
  2292. ///
  2293. /// IRBuilder::BuildReg5
  2294. ///
  2295. /// Build IR instr for a Reg5 instruction.
  2296. ///
  2297. ///----------------------------------------------------------------------------
  2298. template <typename SizePolicy>
  2299. void
  2300. IRBuilder::BuildReg5(Js::OpCode newOpcode, uint32 offset)
  2301. {
  2302. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  2303. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2304. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg5<SizePolicy>>();
  2305. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  2306. {
  2307. this->DoClosureRegCheck(layout->R0);
  2308. this->DoClosureRegCheck(layout->R1);
  2309. this->DoClosureRegCheck(layout->R2);
  2310. this->DoClosureRegCheck(layout->R3);
  2311. this->DoClosureRegCheck(layout->R4);
  2312. }
  2313. BuildReg5(newOpcode, offset, layout->R0, layout->R1, layout->R2, layout->R3, layout->R4);
  2314. }
  2315. void
  2316. IRBuilder::BuildReg5(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
  2317. Js::RegSlot src2RegSlot, Js::RegSlot src3RegSlot, Js::RegSlot src4RegSlot)
  2318. {
  2319. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2320. IR::Instr * instr;
  2321. IR::RegOpnd * dstOpnd;
  2322. IR::RegOpnd * src1Opnd;
  2323. IR::RegOpnd * src2Opnd;
  2324. IR::RegOpnd * src3Opnd;
  2325. IR::RegOpnd * src4Opnd;
  2326. // We can't support instructions with more than 2 srcs. Instead create a CallHelper instructions,
  2327. // and pass the srcs as ArgOut_A instructions.
  2328. src1Opnd = this->BuildSrcOpnd(src1RegSlot);
  2329. src2Opnd = this->BuildSrcOpnd(src2RegSlot);
  2330. src3Opnd = this->BuildSrcOpnd(src3RegSlot);
  2331. src4Opnd = this->BuildSrcOpnd(src4RegSlot);
  2332. dstOpnd = this->BuildDstOpnd(dstRegSlot);
  2333. instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src4Opnd, m_func);
  2334. this->AddInstr(instr, offset);
  2335. instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src3Opnd, instr->GetDst(), m_func);
  2336. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2337. instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src2Opnd, instr->GetDst(), m_func);
  2338. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2339. instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src1Opnd, instr->GetDst(), m_func);
  2340. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2341. IR::HelperCallOpnd *helperOpnd;
  2342. switch (newOpcode) {
  2343. case Js::OpCode::ApplyArgs:
  2344. helperOpnd=IR::HelperCallOpnd::New(IR::HelperOp_OP_ApplyArgs, this->m_func);
  2345. break;
  2346. default:
  2347. AssertMsg(UNREACHED, "Unknown Reg5 opcode");
  2348. Fatal();
  2349. }
  2350. instr = IR::Instr::New(Js::OpCode::CallHelper, dstOpnd, helperOpnd, instr->GetDst(), m_func);
  2351. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  2352. }
  2353. void
  2354. IRBuilder::BuildW1(Js::OpCode newOpcode, uint32 offset)
  2355. {
  2356. Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2357. unsigned short C1;
  2358. const unaligned Js::OpLayoutW1 *regLayout = m_jnReader.W1();
  2359. C1 = regLayout->C1;
  2360. IR::Instr * instr;
  2361. IntConstType value = C1;
  2362. IR::IntConstOpnd * srcOpnd;
  2363. srcOpnd = IR::IntConstOpnd::New(value, TyInt32, m_func);
  2364. instr = IR::Instr::New(newOpcode, m_func);
  2365. instr->SetSrc1(srcOpnd);
  2366. this->AddInstr(instr, offset);
  2367. if (newOpcode == Js::OpCode::RuntimeReferenceError || newOpcode == Js::OpCode::RuntimeTypeError)
  2368. {
  2369. if (DoBailOnNoProfile())
  2370. {
  2371. // RuntimeReferenceError are extremely rare as they are guaranteed to throw. Insert BailonNoProfile to optimize this code path.
  2372. // If there are continues bailout bailonnoprofile will be disabled.
  2373. InsertBailOnNoProfile(instr);
  2374. }
  2375. }
  2376. }
  2377. template <typename SizePolicy>
  2378. void
  2379. IRBuilder::BuildUnsigned1(Js::OpCode newOpcode, uint32 offset)
  2380. {
  2381. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  2382. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2383. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Unsigned1<SizePolicy>>();
  2384. BuildUnsigned1(newOpcode, offset, layout->C1);
  2385. }
  2386. void
  2387. IRBuilder::BuildUnsigned1(Js::OpCode newOpcode, uint32 offset, uint32 num)
  2388. {
  2389. switch (newOpcode)
  2390. {
  2391. case Js::OpCode::EmitTmpRegCount:
  2392. // Note: EmitTmpRegCount is inserted when debugging, not needed for jit.
  2393. // It's only needed by the debugger to see how many tmp regs are active.
  2394. Assert(m_func->IsJitInDebugMode());
  2395. return;
  2396. case Js::OpCode::NewBlockScope:
  2397. case Js::OpCode::NewPseudoScope:
  2398. {
  2399. if (num >= m_func->GetJITFunctionBody()->GetInnerScopeCount())
  2400. {
  2401. Js::Throw::FatalInternalError();
  2402. }
  2403. Js::RegSlot dstRegSlot = num + m_func->GetJITFunctionBody()->GetFirstInnerScopeReg();
  2404. IR::RegOpnd * dstOpnd = BuildDstOpnd(dstRegSlot);
  2405. IR::Instr * instr = IR::Instr::New(newOpcode, dstOpnd, m_func);
  2406. this->AddInstr(instr, offset);
  2407. if (dstOpnd->m_sym->m_isSingleDef)
  2408. {
  2409. dstOpnd->m_sym->m_isNotNumber = true;
  2410. }
  2411. break;
  2412. }
  2413. case Js::OpCode::CloneInnerScopeSlots:
  2414. case Js::OpCode::CloneBlockScope:
  2415. {
  2416. if (num >= m_func->GetJITFunctionBody()->GetInnerScopeCount())
  2417. {
  2418. Js::Throw::FatalInternalError();
  2419. }
  2420. Js::RegSlot srcRegSlot = num + m_func->GetJITFunctionBody()->GetFirstInnerScopeReg();
  2421. IR::RegOpnd * srcOpnd = BuildSrcOpnd(srcRegSlot);
  2422. IR::Instr * instr = IR::Instr::New(newOpcode, m_func);
  2423. instr->SetSrc1(srcOpnd);
  2424. this->AddInstr(instr, offset);
  2425. break;
  2426. }
  2427. case Js::OpCode::ProfiledLoopBodyStart:
  2428. {
  2429. // This opcode is removed from the IR when we aren't doing Profiling SimpleJit or not jitting loop bodies
  2430. if (m_func->DoSimpleJitDynamicProfile() && m_func->GetJITFunctionBody()->DoJITLoopBody())
  2431. {
  2432. // Attach a register to the dest of this instruction to communicate whether we should bail out (the deciding of this is done in lowering)
  2433. IR::Opnd* fullJitExists = IR::RegOpnd::New(TyUint8, m_func);
  2434. auto start = m_lastInstr;
  2435. if (start->m_opcode == Js::OpCode::InitLoopBodyCount)
  2436. {
  2437. Assert(this->IsLoopBody());
  2438. start = start->m_prev;
  2439. }
  2440. Assert(start->m_opcode == Js::OpCode::ProfiledLoopStart && start->GetDst());
  2441. IR::JitProfilingInstr* instr = IR::JitProfilingInstr::New(Js::OpCode::ProfiledLoopBodyStart, fullJitExists, start->GetDst(), m_func);
  2442. // profileId is used here to represent the loop number
  2443. instr->loopNumber = num;
  2444. this->AddInstr(instr, offset);
  2445. // If fullJitExists isn't 0, bail out so that we can get the fulljitted version
  2446. BailOutInfo * bailOutInfo = JitAnew(m_func->m_alloc, BailOutInfo, instr->GetByteCodeOffset(), m_func);
  2447. IR::BailOutInstr * bailInstr = IR::BailOutInstr::New(Js::OpCode::BailOnNotEqual, IR::BailOnSimpleJitToFullJitLoopBody, bailOutInfo, bailOutInfo->bailOutFunc);
  2448. bailInstr->SetSrc1(fullJitExists);
  2449. bailInstr->SetSrc2(IR::IntConstOpnd::New(0, TyUint8, m_func, true));
  2450. this->AddInstr(bailInstr, offset);
  2451. }
  2452. Js::ImplicitCallFlags flags = Js::ImplicitCall_HasNoInfo;
  2453. Js::LoopFlags loopFlags;
  2454. if (this->m_func->HasProfileInfo())
  2455. {
  2456. flags = m_func->GetReadOnlyProfileInfo()->GetLoopImplicitCallFlags(num);
  2457. loopFlags = m_func->GetReadOnlyProfileInfo()->GetLoopFlags(num);
  2458. }
  2459. // Put a label the instruction stream to carry the profile info
  2460. IR::ProfiledLabelInstr * labelInstr = IR::ProfiledLabelInstr::New(Js::OpCode::Label, this->m_func, flags, loopFlags);
  2461. #if DBG
  2462. labelInstr->loopNum = num;
  2463. #endif
  2464. m_lastInstr->InsertAfter(labelInstr);
  2465. m_lastInstr = labelInstr;
  2466. // Set it to the offset to the start of the loop
  2467. labelInstr->SetByteCodeOffset(m_jnReader.GetCurrentOffset());
  2468. break;
  2469. }
  2470. case Js::OpCode::LoopBodyStart:
  2471. break;
  2472. case Js::OpCode::ProfiledLoopStart:
  2473. {
  2474. AssertOrFailFast(num < m_func->GetJITFunctionBody()->GetLoopCount());
  2475. // If we're in profiling SimpleJit and jitting loop bodies, we need to keep this until lowering.
  2476. if (m_func->DoSimpleJitDynamicProfile() && m_func->GetJITFunctionBody()->DoJITLoopBody())
  2477. {
  2478. // In order for the JIT engine to correctly allocate registers we need to have this set up before lowering.
  2479. // There may be 0 to many LoopEnds, but there will only ever be one LoopStart
  2480. Assert(!this->m_saveLoopImplicitCallFlags[num]);
  2481. const auto ty = Lowerer::GetImplicitCallFlagsType();
  2482. auto saveOpnd = IR::RegOpnd::New(ty, m_func);
  2483. this->m_saveLoopImplicitCallFlags[num] = saveOpnd;
  2484. // Note that we insert this instruction /before/ the actual ProfiledLoopStart opcode. This is because Lowering is backwards
  2485. // and this is just a fake instruction which is only used to pass on the saveOpnd; this instruction will eventually be removed.
  2486. auto instr = IR::JitProfilingInstr::New(Js::OpCode::Ld_A, saveOpnd, IR::MemRefOpnd::New((intptr_t)0, ty, m_func), m_func);
  2487. instr->isLoopHelper = true;
  2488. this->AddInstr(instr, offset);
  2489. instr = IR::JitProfilingInstr::New(Js::OpCode::ProfiledLoopStart, IR::RegOpnd::New(TyMachPtr, m_func), nullptr, m_func);
  2490. instr->loopNumber = num;
  2491. this->AddInstr(instr, offset);
  2492. }
  2493. if (this->IsLoopBody() && !m_loopCounterSym)
  2494. {
  2495. InsertInitLoopBodyLoopCounter(num);
  2496. }
  2497. break;
  2498. }
  2499. case Js::OpCode::ProfiledLoopEnd:
  2500. {
  2501. AssertOrFailFast(num < m_func->GetJITFunctionBody()->GetLoopCount());
  2502. // TODO: Decide whether we want the implicit loop call flags to be recorded in simplejitted loop bodies
  2503. if (m_func->DoSimpleJitDynamicProfile() && m_func->GetJITFunctionBody()->DoJITLoopBody())
  2504. {
  2505. Assert(this->m_saveLoopImplicitCallFlags[num]);
  2506. // In profiling simplejit we need this opcode in order to restore the implicit call flags
  2507. auto instr = IR::JitProfilingInstr::New(Js::OpCode::ProfiledLoopEnd, nullptr, this->m_saveLoopImplicitCallFlags[num], m_func);
  2508. this->AddInstr(instr, offset);
  2509. instr->loopNumber = num;
  2510. }
  2511. if (!this->IsLoopBody())
  2512. {
  2513. break;
  2514. }
  2515. // In the early exit case (return), we generated ProfiledLoopEnd for all the outer loop.
  2516. // If we see one of these profile loop, just load the IP of the immediate outer loop of the loop body being JIT'ed
  2517. // and then skip all the other loops using the fact that we have already loaded the return IP
  2518. if (IsLoopBodyReturnIPInstr(m_lastInstr))
  2519. {
  2520. // Already loaded the loop IP sym, skip
  2521. break;
  2522. }
  2523. // See we are ending an outer loop and load the return IP to the ProfiledLoopEnd opcode
  2524. // instead of following the normal branch
  2525. const JITLoopHeaderIDL * loopHeader = m_func->GetJITFunctionBody()->GetLoopHeaderData(num);
  2526. if (m_func->GetJITFunctionBody()->GetLoopHeaderAddr(num) != m_func->m_workItem->GetLoopHeaderAddr() &&
  2527. JITTimeFunctionBody::LoopContains(loopHeader, m_func->m_workItem->GetLoopHeader()))
  2528. {
  2529. this->InsertLoopBodyReturnIPInstr(offset, offset);
  2530. }
  2531. else
  2532. {
  2533. Assert(JITTimeFunctionBody::LoopContains(m_func->m_workItem->GetLoopHeader(), loopHeader));
  2534. }
  2535. break;
  2536. }
  2537. case Js::OpCode::InvalCachedScope:
  2538. {
  2539. // The reg and constant are both src operands.
  2540. IR::Instr* instr = IR::Instr::New(Js::OpCode::InvalCachedScope, m_func);
  2541. IR::RegOpnd *envOpnd = this->BuildSrcOpnd(m_func->GetJITFunctionBody()->GetEnvReg());
  2542. instr->SetSrc1(envOpnd);
  2543. IR::IntConstOpnd *envIndex = IR::IntConstOpnd::New(num, TyInt32, m_func, true);
  2544. instr->SetSrc2(envIndex);
  2545. this->AddInstr(instr, offset);
  2546. return;
  2547. }
  2548. default:
  2549. Assert(false);
  2550. __assume(false);
  2551. }
  2552. }
  2553. template <typename SizePolicy>
  2554. void
  2555. IRBuilder::BuildProfiledReg1Unsigned1(Js::OpCode newOpcode, uint32 offset)
  2556. {
  2557. Assert(OpCodeAttr::IsProfiledOp(newOpcode));
  2558. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2559. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_Reg1Unsigned1<SizePolicy>>>();
  2560. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  2561. {
  2562. this->DoClosureRegCheck(layout->R0);
  2563. }
  2564. BuildProfiledReg1Unsigned1(newOpcode, offset, layout->R0, layout->C1, layout->profileId);
  2565. }
  2566. void
  2567. IRBuilder::BuildProfiledReg1Unsigned1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, int32 C1, Js::ProfileId profileId)
  2568. {
  2569. Assert(newOpcode == Js::OpCode::ProfiledNewScArray || newOpcode == Js::OpCode::ProfiledInitForInEnumerator);
  2570. Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
  2571. if (newOpcode == Js::OpCode::InitForInEnumerator)
  2572. {
  2573. IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(R0);
  2574. IR::Opnd * src2Opnd = this->BuildForInEnumeratorOpnd(C1, offset);
  2575. IR::Instr *instr = IR::ProfiledInstr::New(Js::OpCode::InitForInEnumerator, nullptr, src1Opnd, src2Opnd, m_func);
  2576. instr->AsProfiledInstr()->u.profileId = profileId;
  2577. this->AddInstr(instr, offset);
  2578. return;
  2579. }
  2580. IR::Instr *instr;
  2581. Js::RegSlot dstRegSlot = R0;
  2582. IR::RegOpnd * dstOpnd = this->BuildDstOpnd(dstRegSlot);
  2583. StackSym * dstSym = dstOpnd->m_sym;
  2584. int32 value = C1;
  2585. IR::IntConstOpnd * srcOpnd;
  2586. srcOpnd = IR::IntConstOpnd::New(value, TyInt32, m_func);
  2587. if (m_func->DoSimpleJitDynamicProfile())
  2588. {
  2589. instr = IR::JitProfilingInstr::New(newOpcode, dstOpnd, srcOpnd, m_func);
  2590. instr->AsJitProfilingInstr()->profileId = profileId;
  2591. }
  2592. else
  2593. {
  2594. instr = IR::ProfiledInstr::New(newOpcode, dstOpnd, srcOpnd, m_func);
  2595. instr->AsProfiledInstr()->u.profileId = profileId;
  2596. }
  2597. this->AddInstr(instr, offset);
  2598. if (dstSym->m_isSingleDef)
  2599. {
  2600. dstSym->m_isSafeThis = true;
  2601. dstSym->m_isNotNumber = true;
  2602. }
  2603. // Undefined values in array literals ([0, undefined, 1]) are treated as missing values in some versions
  2604. Js::ArrayCallSiteInfo *arrayInfo = nullptr;
  2605. if (m_func->HasArrayInfo())
  2606. {
  2607. arrayInfo = m_func->GetReadOnlyProfileInfo()->GetArrayCallSiteInfo(profileId);
  2608. }
  2609. Js::TypeId arrayTypeId = Js::TypeIds_Array;
  2610. if (arrayInfo && !m_func->IsJitInDebugMode() && Js::JavascriptArray::HasInlineHeadSegment(value))
  2611. {
  2612. if (arrayInfo->IsNativeIntArray())
  2613. {
  2614. arrayTypeId = Js::TypeIds_NativeIntArray;
  2615. }
  2616. else if (arrayInfo->IsNativeFloatArray())
  2617. {
  2618. arrayTypeId = Js::TypeIds_NativeFloatArray;
  2619. }
  2620. }
  2621. dstOpnd->SetValueType(ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(true).SetArrayTypeId(arrayTypeId));
  2622. if (dstOpnd->GetValueType().HasVarElements())
  2623. {
  2624. dstOpnd->SetValueTypeFixed();
  2625. }
  2626. else
  2627. {
  2628. dstOpnd->SetValueType(dstOpnd->GetValueType().ToLikely());
  2629. }
  2630. }
  2631. template <typename SizePolicy>
  2632. void
  2633. IRBuilder::BuildReg1Unsigned1(Js::OpCode newOpcode, uint32 offset)
  2634. {
  2635. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  2636. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2637. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg1Unsigned1<SizePolicy>>();
  2638. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  2639. {
  2640. this->DoClosureRegCheck(layout->R0);
  2641. }
  2642. BuildReg1Unsigned1(newOpcode, offset, layout->R0, layout->C1);
  2643. }
  2644. void
  2645. IRBuilder::BuildReg1Unsigned1(Js::OpCode newOpcode, uint offset, Js::RegSlot R0, int32 C1)
  2646. {
  2647. switch (newOpcode)
  2648. {
  2649. case Js::OpCode::NewRegEx:
  2650. this->BuildRegexFromPattern(R0, C1, offset);
  2651. return;
  2652. case Js::OpCode::LdInnerScope:
  2653. {
  2654. IR::RegOpnd * srcOpnd = BuildSrcOpnd(this->InnerScopeIndexToRegSlot(C1));
  2655. IR::RegOpnd * dstOpnd = BuildDstOpnd(R0);
  2656. IR::Instr * instr = IR::Instr::New(Js::OpCode::Ld_A, dstOpnd, srcOpnd, m_func);
  2657. if (dstOpnd->m_sym->m_isSingleDef)
  2658. {
  2659. dstOpnd->m_sym->m_isNotNumber = true;
  2660. }
  2661. this->AddInstr(instr, offset);
  2662. return;
  2663. }
  2664. case Js::OpCode::LdIndexedFrameDisplayNoParent:
  2665. {
  2666. newOpcode = Js::OpCode::LdFrameDisplay;
  2667. IR::RegOpnd *srcOpnd = this->BuildSrcOpnd(this->InnerScopeIndexToRegSlot(C1));
  2668. IR::RegOpnd *dstOpnd = this->BuildDstOpnd(R0);
  2669. IR::Instr *instr = IR::Instr::New(newOpcode, dstOpnd, srcOpnd, m_func);
  2670. this->AddEnvOpndForInnerFrameDisplay(instr, offset);
  2671. if (dstOpnd->m_sym->m_isSingleDef)
  2672. {
  2673. dstOpnd->m_sym->m_isNotNumber = true;
  2674. }
  2675. this->AddInstr(instr, offset);
  2676. return;
  2677. }
  2678. case Js::OpCode::GetCachedFunc:
  2679. {
  2680. IR::RegOpnd *src1Opnd = this->BuildSrcOpnd(m_func->GetJITFunctionBody()->GetLocalClosureReg());
  2681. IR::Opnd *src2Opnd = IR::IntConstOpnd::New(C1, TyUint32, m_func);
  2682. IR::RegOpnd *dstOpnd = this->BuildDstOpnd(R0);
  2683. IR::Instr *instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, src2Opnd, m_func);
  2684. if (dstOpnd->m_sym->m_isSingleDef)
  2685. {
  2686. dstOpnd->m_sym->m_isNotNumber = true;
  2687. }
  2688. this->AddInstr(instr, offset);
  2689. return;
  2690. }
  2691. case Js::OpCode::InitForInEnumerator:
  2692. {
  2693. IR::Instr *instr = IR::Instr::New(Js::OpCode::InitForInEnumerator, m_func);
  2694. instr->SetSrc1(this->BuildSrcOpnd(R0));
  2695. instr->SetSrc2(this->BuildForInEnumeratorOpnd(C1, offset));
  2696. this->AddInstr(instr, offset);
  2697. return;
  2698. }
  2699. }
  2700. IR::RegOpnd * dstOpnd = this->BuildDstOpnd(R0);
  2701. StackSym * dstSym = dstOpnd->m_sym;
  2702. IntConstType value = C1;
  2703. IR::IntConstOpnd * srcOpnd = IR::IntConstOpnd::New(value, TyInt32, m_func);
  2704. IR::Instr * instr = IR::Instr::New(newOpcode, dstOpnd, srcOpnd, m_func);
  2705. this->AddInstr(instr, offset);
  2706. if (newOpcode == Js::OpCode::NewScopeSlots)
  2707. {
  2708. this->AddInstr(
  2709. IR::Instr::New(
  2710. Js::OpCode::Ld_A, IR::RegOpnd::New(m_func->GetLocalClosureSym(), TyVar, m_func), dstOpnd, m_func),
  2711. (uint32)-1);
  2712. }
  2713. if (dstSym->m_isSingleDef)
  2714. {
  2715. switch (newOpcode)
  2716. {
  2717. case Js::OpCode::NewScArray:
  2718. case Js::OpCode::NewScArrayWithMissingValues:
  2719. dstSym->m_isSafeThis = true;
  2720. dstSym->m_isNotNumber = true;
  2721. break;
  2722. }
  2723. }
  2724. if (newOpcode == Js::OpCode::NewScArray || newOpcode == Js::OpCode::NewScArrayWithMissingValues)
  2725. {
  2726. // Undefined values in array literals ([0, undefined, 1]) are treated as missing values in some versions
  2727. dstOpnd->SetValueType(
  2728. ValueType::GetObject(ObjectType::Array)
  2729. .SetHasNoMissingValues(newOpcode == Js::OpCode::NewScArray)
  2730. .SetArrayTypeId(Js::TypeIds_Array));
  2731. dstOpnd->SetValueTypeFixed();
  2732. }
  2733. }
  2734. ///----------------------------------------------------------------------------
  2735. ///
  2736. /// IRBuilder::BuildReg2Int1
  2737. ///
  2738. /// Build IR instr for a Reg2I4 instruction.
  2739. ///
  2740. ///----------------------------------------------------------------------------
  2741. template <typename SizePolicy>
  2742. void
  2743. IRBuilder::BuildReg2Int1(Js::OpCode newOpcode, uint32 offset)
  2744. {
  2745. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2746. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg2Int1<SizePolicy>>();
  2747. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  2748. {
  2749. this->DoClosureRegCheck(layout->R0);
  2750. this->DoClosureRegCheck(layout->R1);
  2751. }
  2752. BuildReg2Int1(newOpcode, offset, layout->R0, layout->R1, layout->C1);
  2753. }
  2754. void
  2755. IRBuilder::BuildReg2Int1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot srcRegSlot, int32 value)
  2756. {
  2757. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2758. IR::Instr * instr;
  2759. if (newOpcode == Js::OpCode::LdIndexedFrameDisplay)
  2760. {
  2761. newOpcode = Js::OpCode::LdFrameDisplay;
  2762. if ((uint)value >= m_func->GetJITFunctionBody()->GetInnerScopeCount())
  2763. {
  2764. Js::Throw::FatalInternalError();
  2765. }
  2766. IR::RegOpnd *src1Opnd = this->BuildSrcOpnd(value + m_func->GetJITFunctionBody()->GetFirstInnerScopeReg());
  2767. IR::RegOpnd *src2Opnd = this->BuildSrcOpnd(srcRegSlot);
  2768. IR::RegOpnd *dstOpnd = this->BuildDstOpnd(dstRegSlot);
  2769. instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, src2Opnd, m_func);
  2770. if (dstOpnd->m_sym->m_isSingleDef)
  2771. {
  2772. dstOpnd->m_sym->m_isNotNumber = true;
  2773. }
  2774. this->AddInstr(instr, offset);
  2775. return;
  2776. }
  2777. IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(srcRegSlot);
  2778. IR::IntConstOpnd * src2Opnd = IR::IntConstOpnd::New(value, TyInt32, m_func);
  2779. IR::RegOpnd * dstOpnd = this->BuildDstOpnd(dstRegSlot);
  2780. switch (newOpcode)
  2781. {
  2782. case Js::OpCode::ProfiledLdThis:
  2783. newOpcode = Js::OpCode::LdThis;
  2784. if(m_func->HasProfileInfo())
  2785. {
  2786. dstOpnd->SetValueType(m_func->GetReadOnlyProfileInfo()->GetThisInfo().valueType);
  2787. }
  2788. if(m_func->DoSimpleJitDynamicProfile())
  2789. {
  2790. instr = IR::JitProfilingInstr::New(newOpcode, dstOpnd, src1Opnd, src2Opnd, m_func);
  2791. // Break out since we just made the instr
  2792. break;
  2793. }
  2794. // fall-through
  2795. default:
  2796. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  2797. instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, src2Opnd, m_func);
  2798. break;
  2799. }
  2800. this->AddInstr(instr, offset);
  2801. }
  2802. ///----------------------------------------------------------------------------
  2803. ///
  2804. /// IRBuilder::BuildElementC
  2805. ///
  2806. /// Build IR instr for an ElementC instruction.
  2807. ///
  2808. ///----------------------------------------------------------------------------
  2809. template <typename SizePolicy>
  2810. void
  2811. IRBuilder::BuildElementScopedC(Js::OpCode newOpcode, uint32 offset)
  2812. {
  2813. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  2814. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2815. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementScopedC<SizePolicy>>();
  2816. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  2817. {
  2818. this->DoClosureRegCheck(layout->Value);
  2819. }
  2820. BuildElementScopedC(newOpcode, offset, layout->Value, layout->PropertyIdIndex);
  2821. }
  2822. void
  2823. IRBuilder::BuildElementScopedC(Js::OpCode newOpcode, uint32 offset, Js::RegSlot regSlot, Js::PropertyIdIndexType propertyIdIndex)
  2824. {
  2825. IR::Instr * instr;
  2826. Js::PropertyId propertyId = m_func->GetJITFunctionBody()->GetReferencedPropertyId(propertyIdIndex);
  2827. PropertyKind propertyKind = PropertyKindData;
  2828. IR::RegOpnd * regOpnd;
  2829. Js::RegSlot fieldRegSlot = this->GetEnvRegForEvalCode();
  2830. IR::SymOpnd * fieldSymOpnd = this->BuildFieldOpnd(newOpcode, fieldRegSlot, propertyId, propertyIdIndex, propertyKind);
  2831. switch (newOpcode)
  2832. {
  2833. case Js::OpCode::ScopedEnsureNoRedeclFld:
  2834. {
  2835. regOpnd = this->BuildSrcOpnd(regSlot);
  2836. instr = IR::Instr::New(newOpcode, fieldSymOpnd, regOpnd, m_func);
  2837. break;
  2838. }
  2839. case Js::OpCode::ScopedDeleteFld:
  2840. case Js::OpCode::ScopedDeleteFldStrict:
  2841. {
  2842. Assert(this->m_func->GetScriptContextInfo()->GetAddr() == this->m_func->GetTopFunc()->GetScriptContextInfo()->GetAddr());
  2843. regOpnd = this->BuildDstOpnd(regSlot);
  2844. instr = IR::Instr::New(newOpcode, regOpnd, fieldSymOpnd, m_func);
  2845. break;
  2846. }
  2847. case Js::OpCode::ScopedInitFunc:
  2848. {
  2849. // Implicit root object as default instance
  2850. IR::Opnd * instance2Opnd = this->BuildSrcOpnd(Js::FunctionBody::RootObjectRegSlot);
  2851. regOpnd = this->BuildSrcOpnd(regSlot);
  2852. instr = IR::Instr::New(newOpcode, fieldSymOpnd, regOpnd, instance2Opnd, m_func);
  2853. break;
  2854. }
  2855. default:
  2856. AssertMsg(UNREACHED, "Unknown ElementScopedC opcode");
  2857. Fatal();
  2858. }
  2859. this->AddInstr(instr, offset);
  2860. }
  2861. template <typename SizePolicy>
  2862. void
  2863. IRBuilder::BuildElementC(Js::OpCode newOpcode, uint32 offset)
  2864. {
  2865. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  2866. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2867. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementC<SizePolicy>>();
  2868. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  2869. {
  2870. this->DoClosureRegCheck(layout->Value);
  2871. this->DoClosureRegCheck(layout->Instance);
  2872. }
  2873. BuildElementC(newOpcode, offset, layout->Instance, layout->Value, layout->PropertyIdIndex);
  2874. }
  2875. void
  2876. IRBuilder::BuildElementC(Js::OpCode newOpcode, uint32 offset, Js::RegSlot fieldRegSlot, Js::RegSlot regSlot, Js::PropertyIdIndexType propertyIdIndex)
  2877. {
  2878. IR::Instr * instr;
  2879. Js::PropertyId propertyId = m_func->GetJITFunctionBody()->GetReferencedPropertyId(propertyIdIndex);
  2880. PropertyKind propertyKind = PropertyKindData;
  2881. IR::SymOpnd * fieldSymOpnd = this->BuildFieldOpnd(newOpcode, fieldRegSlot, propertyId, propertyIdIndex, propertyKind);
  2882. IR::RegOpnd * regOpnd;
  2883. bool reuseLoc = false;
  2884. switch (newOpcode)
  2885. {
  2886. case Js::OpCode::DeleteFld_ReuseLoc:
  2887. newOpcode = Js::OpCode::DeleteFld;
  2888. reuseLoc = true;
  2889. // fall through
  2890. case Js::OpCode::DeleteFld:
  2891. case Js::OpCode::DeleteRootFld:
  2892. case Js::OpCode::DeleteFldStrict:
  2893. case Js::OpCode::DeleteRootFldStrict:
  2894. // Load
  2895. regOpnd = this->BuildDstOpnd(regSlot, TyVar, false, reuseLoc);
  2896. instr = IR::Instr::New(newOpcode, regOpnd, fieldSymOpnd, m_func);
  2897. break;
  2898. case Js::OpCode::InitSetFld:
  2899. case Js::OpCode::InitGetFld:
  2900. case Js::OpCode::InitClassMemberGet:
  2901. case Js::OpCode::InitClassMemberSet:
  2902. case Js::OpCode::InitProto:
  2903. case Js::OpCode::StFuncExpr:
  2904. // Store
  2905. regOpnd = this->BuildSrcOpnd(regSlot);
  2906. instr = IR::Instr::New(newOpcode, fieldSymOpnd, regOpnd, m_func);
  2907. break;
  2908. default:
  2909. AssertMsg(UNREACHED, "Unknown ElementC opcode");
  2910. Fatal();
  2911. }
  2912. this->AddInstr(instr, offset);
  2913. }
  2914. ///----------------------------------------------------------------------------
  2915. ///
  2916. /// IRBuilder::BuildElementSlot
  2917. ///
  2918. /// Build IR instr for an ElementSlot instruction.
  2919. ///
  2920. ///----------------------------------------------------------------------------
  2921. IR::Instr *
  2922. IRBuilder::BuildProfiledSlotLoad(Js::OpCode loadOp, IR::RegOpnd *dstOpnd, IR::SymOpnd *srcOpnd, Js::ProfileId profileId, bool *pUnprofiled)
  2923. {
  2924. IR::Instr * instr = nullptr;
  2925. if (m_func->DoSimpleJitDynamicProfile())
  2926. {
  2927. instr = IR::JitProfilingInstr::New(loadOp, dstOpnd, srcOpnd, m_func);
  2928. instr->AsJitProfilingInstr()->profileId = profileId;
  2929. }
  2930. else if(this->m_func->HasProfileInfo())
  2931. {
  2932. instr = IR::ProfiledInstr::New(loadOp, dstOpnd, srcOpnd, m_func);
  2933. instr->AsProfiledInstr()->u.FldInfo().valueType =
  2934. this->m_func->GetReadOnlyProfileInfo()->GetSlotLoad(profileId);
  2935. *pUnprofiled = instr->AsProfiledInstr()->u.FldInfo().valueType.IsUninitialized();
  2936. #if ENABLE_DEBUG_CONFIG_OPTIONS
  2937. if(Js::Configuration::Global.flags.TestTrace.IsEnabled(Js::DynamicProfilePhase))
  2938. {
  2939. const ValueType valueType(instr->AsProfiledInstr()->u.FldInfo().valueType);
  2940. char valueTypeStr[VALUE_TYPE_MAX_STRING_SIZE];
  2941. valueType.ToString(valueTypeStr);
  2942. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  2943. Output::Print(_u("TestTrace function %s (#%s) ValueType = %S "), m_func->GetJITFunctionBody()->GetDisplayName(), m_func->GetDebugNumberSet(debugStringBuffer), valueTypeStr);
  2944. instr->DumpTestTrace();
  2945. }
  2946. #endif
  2947. }
  2948. return instr;
  2949. }
  2950. template <typename SizePolicy>
  2951. void
  2952. IRBuilder::BuildElementSlot(Js::OpCode newOpcode, uint32 offset)
  2953. {
  2954. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  2955. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2956. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementSlot<SizePolicy>>();
  2957. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  2958. {
  2959. this->DoClosureRegCheck(layout->Value);
  2960. this->DoClosureRegCheck(layout->Instance);
  2961. }
  2962. BuildElementSlot(newOpcode, offset, layout->Instance, layout->Value, layout->SlotIndex, Js::Constants::NoProfileId);
  2963. }
  2964. template <typename SizePolicy>
  2965. void
  2966. IRBuilder::BuildProfiledElementSlot(Js::OpCode newOpcode, uint32 offset)
  2967. {
  2968. Assert(OpCodeAttr::IsProfiledOp(newOpcode));
  2969. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2970. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_ElementSlot<SizePolicy>>>();
  2971. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  2972. {
  2973. this->DoClosureRegCheck(layout->Value);
  2974. this->DoClosureRegCheck(layout->Instance);
  2975. }
  2976. Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
  2977. BuildElementSlot(newOpcode, offset, layout->Instance, layout->Value, layout->SlotIndex, layout->profileId);
  2978. }
  2979. void
  2980. IRBuilder::BuildElementSlot(Js::OpCode newOpcode, uint32 offset, Js::RegSlot fieldRegSlot, Js::RegSlot regSlot,
  2981. int32 slotId, Js::ProfileId profileId)
  2982. {
  2983. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  2984. IR::Instr * instr;
  2985. IR::RegOpnd * regOpnd;
  2986. IR::SymOpnd * fieldSymOpnd;
  2987. PropertyKind propertyKind = PropertyKindSlots;
  2988. PropertySym * fieldSym;
  2989. StackSym * stackFuncPtrSym = nullptr;
  2990. bool isLdSlotThatWasNotProfiled = false;
  2991. switch (newOpcode)
  2992. {
  2993. case Js::OpCode::NewInnerStackScFunc:
  2994. stackFuncPtrSym = this->EnsureStackFuncPtrSym();
  2995. // fall through
  2996. case Js::OpCode::NewInnerScFunc:
  2997. newOpcode = Js::OpCode::NewScFunc;
  2998. goto NewScFuncCommon;
  2999. case Js::OpCode::NewInnerScGenFunc:
  3000. newOpcode = Js::OpCode::NewScGenFunc;
  3001. NewScFuncCommon:
  3002. {
  3003. IR::Opnd * functionBodySlotOpnd = IR::IntConstOpnd::New(slotId, TyInt32, m_func, true);
  3004. IR::Opnd * environmentOpnd = this->BuildSrcOpnd(fieldRegSlot);
  3005. regOpnd = this->BuildDstOpnd(regSlot);
  3006. if (stackFuncPtrSym)
  3007. {
  3008. IR::RegOpnd * dataOpnd = IR::RegOpnd::New(TyVar, m_func);
  3009. instr = IR::Instr::New(Js::OpCode::NewScFuncData, dataOpnd, environmentOpnd, IR::RegOpnd::New(stackFuncPtrSym, TyVar, m_func), m_func);
  3010. this->AddInstr(instr, offset);
  3011. instr = IR::Instr::New(newOpcode, regOpnd, functionBodySlotOpnd, dataOpnd, m_func);
  3012. }
  3013. else
  3014. {
  3015. instr = IR::Instr::New(newOpcode, regOpnd, functionBodySlotOpnd, environmentOpnd, m_func);
  3016. }
  3017. if (regOpnd->m_sym->m_isSingleDef)
  3018. {
  3019. regOpnd->m_sym->m_isSafeThis = true;
  3020. regOpnd->m_sym->m_isNotNumber = true;
  3021. }
  3022. this->AddInstr(instr, offset);
  3023. return;
  3024. }
  3025. case Js::OpCode::NewScFuncHomeObj:
  3026. case Js::OpCode::NewScGenFuncHomeObj:
  3027. {
  3028. Js::FunctionInfoPtrPtr infoRef = m_func->GetJITFunctionBody()->GetNestedFuncRef(slotId);
  3029. IR::AddrOpnd * functionBodySlotOpnd = IR::AddrOpnd::New((Js::Var)infoRef, IR::AddrOpndKindDynamicMisc, m_func);
  3030. IR::Opnd * environmentOpnd = GetEnvironmentOperand(offset);
  3031. IR::Opnd * homeObjOpnd = this->BuildSrcOpnd(fieldRegSlot);
  3032. regOpnd = this->BuildDstOpnd(regSlot);
  3033. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), homeObjOpnd, m_func);
  3034. this->AddInstr(instr, offset);
  3035. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), functionBodySlotOpnd, instr->GetDst(), m_func);
  3036. this->AddInstr(instr, offset);
  3037. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), environmentOpnd, instr->GetDst(), m_func);
  3038. this->AddInstr(instr, offset);
  3039. instr = IR::Instr::New(newOpcode, regOpnd, instr->GetDst(), m_func);
  3040. if (regOpnd->m_sym->m_isSingleDef)
  3041. {
  3042. regOpnd->m_sym->m_isSafeThis = true;
  3043. regOpnd->m_sym->m_isNotNumber = true;
  3044. }
  3045. this->AddInstr(instr, offset);
  3046. return;
  3047. }
  3048. case Js::OpCode::LdObjSlot:
  3049. newOpcode = Js::OpCode::LdSlot;
  3050. goto ObjSlotCommon;
  3051. case Js::OpCode::StObjSlot:
  3052. newOpcode = Js::OpCode::StSlot;
  3053. goto ObjSlotCommon;
  3054. case Js::OpCode::StObjSlotChkUndecl:
  3055. newOpcode = Js::OpCode::StSlotChkUndecl;
  3056. ObjSlotCommon:
  3057. regOpnd = IR::RegOpnd::New(TyVar, m_func);
  3058. fieldSymOpnd = this->BuildFieldOpnd(newOpcode, fieldRegSlot, (Js::DynamicObject::GetOffsetOfAuxSlots())/sizeof(Js::Var), (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
  3059. instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldSymOpnd, m_func);
  3060. this->AddInstr(instr, offset);
  3061. fieldSym = PropertySym::New(regOpnd->m_sym, slotId, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
  3062. fieldSymOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
  3063. if (newOpcode == Js::OpCode::StSlot || newOpcode == Js::OpCode::StSlotChkUndecl)
  3064. {
  3065. goto StSlotCommon;
  3066. }
  3067. goto LdSlotCommon;
  3068. case Js::OpCode::LdSlotArr:
  3069. propertyKind = PropertyKindSlotArray;
  3070. case Js::OpCode::LdSlot:
  3071. // Load
  3072. fieldSymOpnd = this->BuildFieldOpnd(newOpcode, fieldRegSlot, slotId, (Js::PropertyIdIndexType)-1, propertyKind);
  3073. LdSlotCommon:
  3074. regOpnd = this->BuildDstOpnd(regSlot);
  3075. instr = nullptr;
  3076. if (profileId != Js::Constants::NoProfileId)
  3077. {
  3078. instr = this->BuildProfiledSlotLoad(newOpcode, regOpnd, fieldSymOpnd, profileId, &isLdSlotThatWasNotProfiled);
  3079. }
  3080. if (!instr)
  3081. {
  3082. instr = IR::Instr::New(newOpcode, regOpnd, fieldSymOpnd, m_func);
  3083. }
  3084. break;
  3085. case Js::OpCode::StSlot:
  3086. case Js::OpCode::StSlotChkUndecl:
  3087. // Store
  3088. fieldSymOpnd = this->BuildFieldOpnd(newOpcode, fieldRegSlot, slotId, (Js::PropertyIdIndexType)-1, propertyKind);
  3089. StSlotCommon:
  3090. regOpnd = this->BuildSrcOpnd(regSlot);
  3091. instr = IR::Instr::New(newOpcode, fieldSymOpnd, regOpnd, m_func);
  3092. if (newOpcode == Js::OpCode::StSlotChkUndecl)
  3093. {
  3094. // ChkUndecl includes an implicit read of the destination. Communicate the liveness by using the destination in src2.
  3095. instr->SetSrc2(fieldSymOpnd);
  3096. }
  3097. break;
  3098. case Js::OpCode::StPropIdArrFromVar:
  3099. {
  3100. IR::RegOpnd * src0Opnd = this->BuildSrcOpnd(fieldRegSlot);
  3101. IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(regSlot);
  3102. IntConstType value = slotId;
  3103. IR::IntConstOpnd * valOpnd = IR::IntConstOpnd::New(value, TyInt32, m_func);
  3104. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), src1Opnd, m_func);
  3105. this->AddInstr(instr, offset);
  3106. offset = Js::Constants::NoByteCodeOffset;
  3107. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), valOpnd, instr->GetDst(), m_func);
  3108. this->AddInstr(instr, offset);
  3109. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), src0Opnd, instr->GetDst(), m_func);
  3110. this->AddInstr(instr, offset);
  3111. IR::Opnd * firstArg = instr->GetDst();
  3112. instr = IR::Instr::New(newOpcode, m_func);
  3113. instr->SetSrc1(firstArg);
  3114. break;
  3115. }
  3116. default:
  3117. AssertMsg(UNREACHED, "Unknown ElementSlot opcode");
  3118. Fatal();
  3119. }
  3120. this->AddInstr(instr, offset);
  3121. if(isLdSlotThatWasNotProfiled && DoBailOnNoProfile())
  3122. {
  3123. InsertBailOnNoProfile(instr);
  3124. }
  3125. }
  3126. template <typename SizePolicy>
  3127. void
  3128. IRBuilder::BuildElementSlotI1(Js::OpCode newOpcode, uint32 offset)
  3129. {
  3130. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  3131. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  3132. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementSlotI1<SizePolicy>>();
  3133. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  3134. {
  3135. this->DoClosureRegCheck(layout->Value);
  3136. }
  3137. BuildElementSlotI1(newOpcode, offset, layout->Value, layout->SlotIndex, Js::Constants::NoProfileId);
  3138. }
  3139. template <typename SizePolicy>
  3140. void
  3141. IRBuilder::BuildProfiledElementSlotI1(Js::OpCode newOpcode, uint32 offset)
  3142. {
  3143. Assert(OpCodeAttr::IsProfiledOp(newOpcode));
  3144. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  3145. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_ElementSlotI1<SizePolicy>>>();
  3146. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  3147. {
  3148. this->DoClosureRegCheck(layout->Value);
  3149. }
  3150. Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
  3151. BuildElementSlotI1(newOpcode, offset, layout->Value, layout->SlotIndex, layout->profileId);
  3152. }
  3153. void
  3154. IRBuilder::BuildElementSlotI1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot regSlot,
  3155. int32 slotId, Js::ProfileId profileId)
  3156. {
  3157. IR::RegOpnd *regOpnd;
  3158. IR::SymOpnd *fieldOpnd;
  3159. IR::Instr *instr = nullptr;
  3160. IR::ByteCodeUsesInstr *byteCodeUse;
  3161. PropertySym *fieldSym = nullptr;
  3162. StackSym * stackFuncPtrSym = nullptr;
  3163. SymID symID = m_func->GetJITFunctionBody()->GetLocalClosureReg();
  3164. bool isLdSlotThatWasNotProfiled = false;
  3165. bool reuseLoc = false;
  3166. StackSym* closureSym = m_func->GetLocalClosureSym();
  3167. uint scopeSlotSize = this->IsParamScopeDone() ? m_func->GetJITFunctionBody()->GetScopeSlotArraySize() : m_func->GetJITFunctionBody()->GetParamScopeSlotArraySize();
  3168. switch (newOpcode)
  3169. {
  3170. case Js::OpCode::LdParamSlot:
  3171. scopeSlotSize = m_func->GetJITFunctionBody()->GetParamScopeSlotArraySize();
  3172. closureSym = m_func->GetParamClosureSym();
  3173. symID = m_func->GetJITFunctionBody()->GetParamClosureReg();
  3174. // Fall through
  3175. case Js::OpCode::LdLocalSlot:
  3176. if (!PHASE_OFF(Js::ClosureRangeCheckPhase, m_func))
  3177. {
  3178. if ((uint32)slotId >= scopeSlotSize + Js::ScopeSlots::FirstSlotIndex)
  3179. {
  3180. Js::Throw::FatalInternalError();
  3181. }
  3182. }
  3183. if (closureSym->HasByteCodeRegSlot())
  3184. {
  3185. byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
  3186. byteCodeUse->SetNonOpndSymbol(closureSym->m_id);
  3187. this->AddInstr(byteCodeUse, offset);
  3188. }
  3189. // Read the scope slot pointer back using the stack closure sym.
  3190. newOpcode = Js::OpCode::LdSlot;
  3191. if (m_func->DoStackFrameDisplay())
  3192. {
  3193. // Read the scope slot pointer back using the stack closure sym.
  3194. fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, closureSym->m_id, 0, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
  3195. regOpnd = IR::RegOpnd::New(TyVar, m_func);
  3196. instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func);
  3197. this->AddInstr(instr, offset);
  3198. symID = regOpnd->m_sym->m_id;
  3199. if (IsLoopBody())
  3200. {
  3201. fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, closureSym->m_id, slotId, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
  3202. }
  3203. }
  3204. else if (IsLoopBody())
  3205. {
  3206. this->EnsureLoopBodyLoadSlot(symID);
  3207. }
  3208. fieldSym = PropertySym::FindOrCreate(symID, slotId, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
  3209. fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
  3210. regOpnd = this->BuildDstOpnd(regSlot);
  3211. instr = nullptr;
  3212. if (profileId != Js::Constants::NoProfileId)
  3213. {
  3214. instr = this->BuildProfiledSlotLoad(Js::OpCode::LdSlot, regOpnd, fieldOpnd, profileId, &isLdSlotThatWasNotProfiled);
  3215. }
  3216. if (!instr)
  3217. {
  3218. instr = IR::Instr::New(Js::OpCode::LdSlot, regOpnd, fieldOpnd, m_func);
  3219. }
  3220. this->AddInstr(instr, offset);
  3221. break;
  3222. case Js::OpCode::LdParamObjSlot:
  3223. closureSym = m_func->GetParamClosureSym();
  3224. symID = m_func->GetJITFunctionBody()->GetParamClosureReg();
  3225. newOpcode = Js::OpCode::LdLocalObjSlot;
  3226. // Fall through
  3227. case Js::OpCode::LdLocalObjSlot:
  3228. if (closureSym->HasByteCodeRegSlot())
  3229. {
  3230. byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
  3231. byteCodeUse->SetNonOpndSymbol(closureSym->m_id);
  3232. this->AddInstr(byteCodeUse, offset);
  3233. }
  3234. fieldOpnd = this->BuildFieldOpnd(newOpcode, symID, (Js::DynamicObject::GetOffsetOfAuxSlots()) / sizeof(Js::Var), (Js::PropertyIdIndexType) - 1, PropertyKindSlotArray);
  3235. regOpnd = IR::RegOpnd::New(TyVar, m_func);
  3236. instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func);
  3237. this->AddInstr(instr, offset);
  3238. fieldSym = PropertySym::New(regOpnd->m_sym, slotId, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
  3239. fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
  3240. regOpnd = this->BuildDstOpnd(regSlot);
  3241. instr = nullptr;
  3242. newOpcode = Js::OpCode::LdSlot;
  3243. if (profileId != Js::Constants::NoProfileId)
  3244. {
  3245. instr = this->BuildProfiledSlotLoad(newOpcode, regOpnd, fieldOpnd, profileId, &isLdSlotThatWasNotProfiled);
  3246. }
  3247. if (!instr)
  3248. {
  3249. instr = IR::Instr::New(newOpcode, regOpnd, fieldOpnd, m_func);
  3250. }
  3251. this->AddInstr(instr, offset);
  3252. break;
  3253. case Js::OpCode::StParamSlot:
  3254. case Js::OpCode::StParamSlotChkUndecl:
  3255. scopeSlotSize = m_func->GetJITFunctionBody()->GetParamScopeSlotArraySize();
  3256. closureSym = m_func->GetParamClosureSym();
  3257. symID = m_func->GetJITFunctionBody()->GetParamClosureReg();
  3258. newOpcode = newOpcode == Js::OpCode::StParamSlot ? Js::OpCode::StLocalSlot : Js::OpCode::StLocalSlotChkUndecl;
  3259. // Fall through
  3260. case Js::OpCode::StLocalSlot:
  3261. case Js::OpCode::StLocalSlotChkUndecl:
  3262. if (!PHASE_OFF(Js::ClosureRangeCheckPhase, m_func))
  3263. {
  3264. if ((uint32)slotId >= scopeSlotSize + Js::ScopeSlots::FirstSlotIndex)
  3265. {
  3266. Js::Throw::FatalInternalError();
  3267. }
  3268. }
  3269. if (closureSym->HasByteCodeRegSlot())
  3270. {
  3271. byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
  3272. byteCodeUse->SetNonOpndSymbol(closureSym->m_id);
  3273. this->AddInstr(byteCodeUse, offset);
  3274. }
  3275. newOpcode = newOpcode == Js::OpCode::StLocalSlot ? Js::OpCode::StSlot : Js::OpCode::StSlotChkUndecl;
  3276. if (m_func->DoStackFrameDisplay())
  3277. {
  3278. regOpnd = IR::RegOpnd::New(TyVar, m_func);
  3279. // Read the scope slot pointer back using the stack closure sym.
  3280. fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, closureSym->m_id, 0, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
  3281. instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func);
  3282. this->AddInstr(instr, offset);
  3283. symID = regOpnd->m_sym->m_id;
  3284. if (IsLoopBody())
  3285. {
  3286. fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, closureSym->m_id, slotId, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
  3287. }
  3288. }
  3289. else
  3290. {
  3291. if (IsLoopBody())
  3292. {
  3293. this->EnsureLoopBodyLoadSlot(symID);
  3294. }
  3295. }
  3296. fieldSym = PropertySym::FindOrCreate(symID, slotId, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
  3297. fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
  3298. regOpnd = this->BuildSrcOpnd(regSlot);
  3299. instr = IR::Instr::New(newOpcode, fieldOpnd, regOpnd, m_func);
  3300. this->AddInstr(instr, offset);
  3301. if (newOpcode == Js::OpCode::StSlotChkUndecl)
  3302. {
  3303. instr->SetSrc2(fieldOpnd);
  3304. }
  3305. break;
  3306. case Js::OpCode::StParamObjSlot:
  3307. case Js::OpCode::StParamObjSlotChkUndecl:
  3308. closureSym = m_func->GetParamClosureSym();
  3309. symID = m_func->GetJITFunctionBody()->GetParamClosureReg();
  3310. newOpcode = newOpcode == Js::OpCode::StParamObjSlot ? Js::OpCode::StLocalObjSlot : Js::OpCode::StLocalObjSlotChkUndecl;
  3311. // Fall through
  3312. case Js::OpCode::StLocalObjSlot:
  3313. case Js::OpCode::StLocalObjSlotChkUndecl:
  3314. if (closureSym->HasByteCodeRegSlot())
  3315. {
  3316. byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
  3317. byteCodeUse->SetNonOpndSymbol(closureSym->m_id);
  3318. this->AddInstr(byteCodeUse, offset);
  3319. }
  3320. regOpnd = IR::RegOpnd::New(TyVar, m_func);
  3321. fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, symID, (Js::DynamicObject::GetOffsetOfAuxSlots())/sizeof(Js::Var), (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
  3322. instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func);
  3323. this->AddInstr(instr, offset);
  3324. newOpcode = newOpcode == Js::OpCode::StLocalObjSlot ? Js::OpCode::StSlot : Js::OpCode::StSlotChkUndecl;
  3325. fieldSym = PropertySym::New(regOpnd->m_sym, slotId, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
  3326. fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
  3327. regOpnd = this->BuildSrcOpnd(regSlot);
  3328. instr = IR::Instr::New(newOpcode, fieldOpnd, regOpnd, m_func);
  3329. if (newOpcode == Js::OpCode::StSlotChkUndecl)
  3330. {
  3331. // ChkUndecl includes an implicit read of the destination. Communicate the liveness by using the destination in src2.
  3332. instr->SetSrc2(fieldOpnd);
  3333. }
  3334. this->AddInstr(instr, offset);
  3335. break;
  3336. case Js::OpCode::LdEnvObj_ReuseLoc:
  3337. reuseLoc = true;
  3338. // fall through
  3339. case Js::OpCode::LdEnvObj:
  3340. fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, this->GetEnvReg(), slotId, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
  3341. regOpnd = this->BuildDstOpnd(regSlot, TyVar, false, reuseLoc);
  3342. instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func);
  3343. this->AddInstr(instr, offset);
  3344. m_func->GetTopFunc()->AddFrameDisplayCheck(fieldOpnd);
  3345. break;
  3346. case Js::OpCode::NewStackScFunc:
  3347. stackFuncPtrSym = this->EnsureStackFuncPtrSym();
  3348. newOpcode = Js::OpCode::NewScFunc;
  3349. // fall through
  3350. case Js::OpCode::NewScFunc:
  3351. goto NewScFuncCommon;
  3352. case Js::OpCode::NewScGenFunc:
  3353. newOpcode = Js::OpCode::NewScGenFunc;
  3354. NewScFuncCommon:
  3355. {
  3356. IR::Opnd * functionBodySlotOpnd = IR::IntConstOpnd::New(slotId, TyInt32, m_func, true);
  3357. IR::Opnd *environmentOpnd = GetEnvironmentOperand(offset);
  3358. regOpnd = this->BuildDstOpnd(regSlot);
  3359. if (stackFuncPtrSym)
  3360. {
  3361. IR::RegOpnd * dataOpnd = IR::RegOpnd::New(TyVar, m_func);
  3362. instr = IR::Instr::New(Js::OpCode::NewScFuncData, dataOpnd, environmentOpnd,
  3363. IR::RegOpnd::New(stackFuncPtrSym, TyVar, m_func), m_func);
  3364. this->AddInstr(instr, offset);
  3365. instr = IR::Instr::New(newOpcode, regOpnd, functionBodySlotOpnd, dataOpnd, m_func);
  3366. }
  3367. else
  3368. {
  3369. instr = IR::Instr::New(newOpcode, regOpnd, functionBodySlotOpnd, environmentOpnd, m_func);
  3370. }
  3371. if (regOpnd->m_sym->m_isSingleDef)
  3372. {
  3373. regOpnd->m_sym->m_isSafeThis = true;
  3374. regOpnd->m_sym->m_isNotNumber = true;
  3375. }
  3376. this->AddInstr(instr, offset);
  3377. return;
  3378. }
  3379. default:
  3380. Assert(0);
  3381. }
  3382. if(isLdSlotThatWasNotProfiled && DoBailOnNoProfile())
  3383. {
  3384. InsertBailOnNoProfile(instr);
  3385. }
  3386. }
  3387. IR::Opnd*
  3388. IRBuilder::GetEnvironmentOperand(uint32 offset)
  3389. {
  3390. StackSym* sym = nullptr;
  3391. // The byte code doesn't refer directly to a closure environment. Get the implicit one
  3392. // that's pointed to by the function body.
  3393. if (m_func->DoStackFrameDisplay() && m_func->GetLocalFrameDisplaySym())
  3394. {
  3395. // Read the scope slot pointer back using the stack closure sym.
  3396. IR::Opnd *fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, m_func->GetLocalFrameDisplaySym()->m_id, 0, (Js::PropertyIdIndexType) - 1, PropertyKindSlotArray);
  3397. IR::RegOpnd *regOpnd = IR::RegOpnd::New(TyVar, m_func);
  3398. this->AddInstr(
  3399. IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func),
  3400. offset);
  3401. sym = regOpnd->m_sym;
  3402. }
  3403. else
  3404. {
  3405. SymID symID;
  3406. symID = this->GetEnvRegForInnerFrameDisplay();
  3407. Assert(symID != Js::Constants::NoRegister);
  3408. if (IsLoopBody() && !RegIsConstant(symID))
  3409. {
  3410. this->EnsureLoopBodyLoadSlot(symID);
  3411. }
  3412. if (m_func->DoStackNestedFunc() && symID == GetEnvReg())
  3413. {
  3414. // Environment is not guaranteed constant during this function because it could become boxed during execution,
  3415. // so load the environment every time you need it.
  3416. IR::RegOpnd *regOpnd = IR::RegOpnd::New(TyVar, m_func);
  3417. this->AddInstr(
  3418. IR::Instr::New(Js::OpCode::LdEnv, regOpnd, m_func),
  3419. offset);
  3420. sym = regOpnd->m_sym;
  3421. }
  3422. else
  3423. {
  3424. sym = StackSym::FindOrCreate(symID, (Js::RegSlot)symID, m_func);
  3425. }
  3426. }
  3427. return IR::RegOpnd::New(sym, TyVar, m_func);
  3428. }
  3429. template <typename SizePolicy>
  3430. void
  3431. IRBuilder::BuildElementSlotI2(Js::OpCode newOpcode, uint32 offset)
  3432. {
  3433. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  3434. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  3435. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementSlotI2<SizePolicy>>();
  3436. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  3437. {
  3438. this->DoClosureRegCheck(layout->Value);
  3439. }
  3440. BuildElementSlotI2(newOpcode, offset, layout->Value, layout->SlotIndex1, layout->SlotIndex2, Js::Constants::NoProfileId);
  3441. }
  3442. template <typename SizePolicy>
  3443. void
  3444. IRBuilder::BuildProfiledElementSlotI2(Js::OpCode newOpcode, uint32 offset)
  3445. {
  3446. Assert(OpCodeAttr::IsProfiledOp(newOpcode));
  3447. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  3448. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_ElementSlotI2<SizePolicy>>>();
  3449. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  3450. {
  3451. this->DoClosureRegCheck(layout->Value);
  3452. }
  3453. Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
  3454. BuildElementSlotI2(newOpcode, offset, layout->Value, layout->SlotIndex1, layout->SlotIndex2, layout->profileId);
  3455. }
  3456. void
  3457. IRBuilder::BuildElementSlotI2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot regSlot,
  3458. int32 slotId1, int32 slotId2, Js::ProfileId profileId)
  3459. {
  3460. IR::RegOpnd *regOpnd;
  3461. IR::SymOpnd *fieldOpnd;
  3462. IR::Instr *instr;
  3463. PropertySym *fieldSym;
  3464. bool isLdSlotThatWasNotProfiled = false;
  3465. switch (newOpcode)
  3466. {
  3467. case Js::OpCode::LdModuleSlot:
  3468. case Js::OpCode::StModuleSlot:
  3469. {
  3470. Field(Js::Var)* moduleExportVarArrayAddr = Js::JavascriptOperators::OP_GetModuleExportSlotArrayAddress(slotId1, slotId2, m_func->GetScriptContextInfo());
  3471. IR::AddrOpnd* addrOpnd = IR::AddrOpnd::New(moduleExportVarArrayAddr, IR::AddrOpndKindConstantAddress, m_func, true);
  3472. regOpnd = IR::RegOpnd::New(TyVar, m_func);
  3473. instr = IR::Instr::New(Js::OpCode::Ld_A, regOpnd, addrOpnd, m_func);
  3474. this->AddInstr(instr, offset);
  3475. fieldSym = PropertySym::New(regOpnd->m_sym, slotId2, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
  3476. fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
  3477. if (newOpcode == Js::OpCode::LdModuleSlot)
  3478. {
  3479. newOpcode = Js::OpCode::LdSlot;
  3480. regOpnd = this->BuildDstOpnd(regSlot);
  3481. instr = IR::Instr::New(newOpcode, regOpnd, fieldOpnd, m_func);
  3482. }
  3483. else
  3484. {
  3485. Assert(newOpcode == Js::OpCode::StModuleSlot);
  3486. newOpcode = Js::OpCode::StSlot;
  3487. regOpnd = this->BuildSrcOpnd(regSlot);
  3488. instr = IR::Instr::New(newOpcode, fieldOpnd, regOpnd, m_func);
  3489. }
  3490. this->AddInstr(instr, offset);
  3491. break;
  3492. }
  3493. case Js::OpCode::LdEnvSlot:
  3494. case Js::OpCode::LdEnvObjSlot:
  3495. case Js::OpCode::StEnvSlot:
  3496. case Js::OpCode::StEnvSlotChkUndecl:
  3497. case Js::OpCode::StEnvObjSlot:
  3498. case Js::OpCode::StEnvObjSlotChkUndecl:
  3499. fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, this->GetEnvReg(), slotId1, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
  3500. regOpnd = IR::RegOpnd::New(TyVar, m_func);
  3501. instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func);
  3502. this->AddInstr(instr, offset);
  3503. switch (newOpcode)
  3504. {
  3505. case Js::OpCode::LdEnvObjSlot:
  3506. case Js::OpCode::StEnvObjSlot:
  3507. case Js::OpCode::StEnvObjSlotChkUndecl:
  3508. m_func->GetTopFunc()->AddFrameDisplayCheck(fieldOpnd, (uint32)-1);
  3509. fieldSym = PropertySym::New(regOpnd->m_sym, (Js::DynamicObject::GetOffsetOfAuxSlots())/sizeof(Js::Var),
  3510. (uint32)-1, (uint)-1, PropertyKindSlotArray, m_func);
  3511. fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
  3512. regOpnd = IR::RegOpnd::New(TyVar, m_func);
  3513. instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func);
  3514. this->AddInstr(instr, offset);
  3515. break;
  3516. default:
  3517. m_func->GetTopFunc()->AddFrameDisplayCheck(fieldOpnd, slotId2);
  3518. break;
  3519. }
  3520. fieldSym = PropertySym::New(regOpnd->m_sym, slotId2, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
  3521. fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
  3522. switch (newOpcode)
  3523. {
  3524. case Js::OpCode::LdEnvSlot:
  3525. case Js::OpCode::LdEnvObjSlot:
  3526. newOpcode = Js::OpCode::LdSlot;
  3527. regOpnd = this->BuildDstOpnd(regSlot);
  3528. instr = nullptr;
  3529. if (profileId != Js::Constants::NoProfileId)
  3530. {
  3531. instr = this->BuildProfiledSlotLoad(newOpcode, regOpnd, fieldOpnd, profileId, &isLdSlotThatWasNotProfiled);
  3532. }
  3533. if (!instr)
  3534. {
  3535. instr = IR::Instr::New(newOpcode, regOpnd, fieldOpnd, m_func);
  3536. }
  3537. break;
  3538. default:
  3539. newOpcode =
  3540. newOpcode == Js::OpCode::StEnvSlot || newOpcode == Js::OpCode::StEnvObjSlot ? Js::OpCode::StSlot : Js::OpCode::StSlotChkUndecl;
  3541. regOpnd = this->BuildSrcOpnd(regSlot);
  3542. instr = IR::Instr::New(newOpcode, fieldOpnd, regOpnd, m_func);
  3543. if (newOpcode == Js::OpCode::StSlotChkUndecl)
  3544. {
  3545. // ChkUndecl includes an implicit read of the destination. Communicate the liveness by using the destination in src2.
  3546. instr->SetSrc2(fieldOpnd);
  3547. }
  3548. break;
  3549. }
  3550. this->AddInstr(instr, offset);
  3551. if(isLdSlotThatWasNotProfiled && DoBailOnNoProfile())
  3552. {
  3553. InsertBailOnNoProfile(instr);
  3554. }
  3555. break;
  3556. case Js::OpCode::StInnerObjSlot:
  3557. case Js::OpCode::StInnerObjSlotChkUndecl:
  3558. case Js::OpCode::StInnerSlot:
  3559. case Js::OpCode::StInnerSlotChkUndecl:
  3560. if ((uint)slotId1 >= m_func->GetJITFunctionBody()->GetInnerScopeCount())
  3561. {
  3562. Js::Throw::FatalInternalError();
  3563. }
  3564. regOpnd = this->BuildSrcOpnd(regSlot);
  3565. slotId1 += this->m_func->GetJITFunctionBody()->GetFirstInnerScopeReg();
  3566. if ((uint)slotId1 >= this->m_func->GetJITFunctionBody()->GetLocalsCount())
  3567. {
  3568. Js::Throw::FatalInternalError();
  3569. }
  3570. if (newOpcode == Js::OpCode::StInnerObjSlot || newOpcode == Js::OpCode::StInnerObjSlotChkUndecl)
  3571. {
  3572. IR::RegOpnd * slotOpnd = IR::RegOpnd::New(TyVar, m_func);
  3573. fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, slotId1, (Js::DynamicObject::GetOffsetOfAuxSlots())/sizeof(Js::Var), (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
  3574. instr = IR::Instr::New(Js::OpCode::LdSlotArr, slotOpnd, fieldOpnd, m_func);
  3575. this->AddInstr(instr, offset);
  3576. PropertySym *propertySym = PropertySym::New(slotOpnd->m_sym, slotId2, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
  3577. fieldOpnd = IR::PropertySymOpnd::New(propertySym, (Js::CacheId)-1, TyVar, m_func);
  3578. }
  3579. else
  3580. {
  3581. fieldOpnd = this->BuildFieldOpnd(Js::OpCode::StSlot, slotId1, slotId2, (Js::PropertyIdIndexType)-1, PropertyKindSlots);
  3582. }
  3583. newOpcode =
  3584. newOpcode == Js::OpCode::StInnerObjSlot || newOpcode == Js::OpCode::StInnerSlot ?
  3585. Js::OpCode::StSlot : Js::OpCode::StSlotChkUndecl;
  3586. instr = IR::Instr::New(newOpcode, fieldOpnd, regOpnd, m_func);
  3587. if (newOpcode == Js::OpCode::StSlotChkUndecl)
  3588. {
  3589. // ChkUndecl includes an implicit read of the destination. Communicate the liveness by using the destination in src2.
  3590. instr->SetSrc2(fieldOpnd);
  3591. }
  3592. this->AddInstr(instr, offset);
  3593. break;
  3594. case Js::OpCode::LdInnerSlot:
  3595. case Js::OpCode::LdInnerObjSlot:
  3596. if ((uint)slotId1 >= m_func->GetJITFunctionBody()->GetInnerScopeCount())
  3597. {
  3598. Js::Throw::FatalInternalError();
  3599. }
  3600. slotId1 += this->m_func->GetJITFunctionBody()->GetFirstInnerScopeReg();
  3601. if ((uint)slotId1 >= this->m_func->GetJITFunctionBody()->GetLocalsCount())
  3602. {
  3603. Js::Throw::FatalInternalError();
  3604. }
  3605. if (newOpcode == Js::OpCode::LdInnerObjSlot)
  3606. {
  3607. IR::RegOpnd * slotOpnd = IR::RegOpnd::New(TyVar, m_func);
  3608. fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, slotId1, (Js::DynamicObject::GetOffsetOfAuxSlots())/sizeof(Js::Var), (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
  3609. instr = IR::Instr::New(Js::OpCode::LdSlotArr, slotOpnd, fieldOpnd, m_func);
  3610. this->AddInstr(instr, offset);
  3611. PropertySym *propertySym = PropertySym::New(slotOpnd->m_sym, slotId2, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
  3612. fieldOpnd = IR::PropertySymOpnd::New(propertySym, (Js::CacheId)-1, TyVar, m_func);
  3613. }
  3614. else
  3615. {
  3616. fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlot, slotId1, slotId2, (Js::PropertyIdIndexType)-1, PropertyKindSlots);
  3617. }
  3618. regOpnd = this->BuildDstOpnd(regSlot);
  3619. instr = IR::Instr::New(Js::OpCode::LdSlot, regOpnd, fieldOpnd, m_func);
  3620. this->AddInstr(instr, offset);
  3621. break;
  3622. default:
  3623. AssertMsg(false, "Unsupported opcode in BuildElementSlotI2");
  3624. break;
  3625. }
  3626. }
  3627. template <typename SizePolicy>
  3628. void
  3629. IRBuilder::BuildElementSlotI3(Js::OpCode newOpcode, uint32 offset)
  3630. {
  3631. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  3632. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  3633. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementSlotI3<SizePolicy>>();
  3634. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  3635. {
  3636. this->DoClosureRegCheck(layout->Value);
  3637. this->DoClosureRegCheck(layout->Instance);
  3638. this->DoClosureRegCheck(layout->HomeObj);
  3639. }
  3640. BuildElementSlotI3(newOpcode, offset, layout->Instance, layout->Value, layout->SlotIndex, layout->HomeObj, Js::Constants::NoProfileId);
  3641. }
  3642. template <typename SizePolicy>
  3643. void
  3644. IRBuilder::BuildProfiledElementSlotI3(Js::OpCode newOpcode, uint32 offset)
  3645. {
  3646. Assert(OpCodeAttr::IsProfiledOp(newOpcode));
  3647. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  3648. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_ElementSlotI3<SizePolicy>>>();
  3649. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  3650. {
  3651. this->DoClosureRegCheck(layout->Value);
  3652. this->DoClosureRegCheck(layout->Instance);
  3653. this->DoClosureRegCheck(layout->HomeObj);
  3654. }
  3655. Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
  3656. BuildElementSlotI3(newOpcode, offset, layout->Instance, layout->Value, layout->SlotIndex, layout->HomeObj, layout->profileId);
  3657. }
  3658. void
  3659. IRBuilder::BuildElementSlotI3(Js::OpCode newOpcode, uint32 offset, Js::RegSlot fieldRegSlot, Js::RegSlot regSlot,
  3660. int32 slotId, Js::RegSlot homeObj, Js::ProfileId profileId)
  3661. {
  3662. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  3663. IR::Instr * instr;
  3664. IR::RegOpnd * regOpnd;
  3665. switch (newOpcode)
  3666. {
  3667. case Js::OpCode::NewInnerScFuncHomeObj:
  3668. newOpcode = Js::OpCode::NewScFuncHomeObj;
  3669. goto NewScFuncCommon;
  3670. case Js::OpCode::NewInnerScGenFuncHomeObj:
  3671. newOpcode = Js::OpCode::NewScGenFuncHomeObj;
  3672. NewScFuncCommon:
  3673. {
  3674. Js::FunctionInfoPtrPtr infoRef = m_func->GetJITFunctionBody()->GetNestedFuncRef(slotId);
  3675. IR::AddrOpnd * functionBodySlotOpnd = IR::AddrOpnd::New((Js::Var)infoRef, IR::AddrOpndKindDynamicMisc, m_func);
  3676. IR::Opnd * environmentOpnd = this->BuildSrcOpnd(fieldRegSlot);
  3677. IR::Opnd * homeObjOpnd = this->BuildSrcOpnd(homeObj);
  3678. regOpnd = this->BuildDstOpnd(regSlot);
  3679. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), homeObjOpnd, m_func);
  3680. this->AddInstr(instr, offset);
  3681. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), functionBodySlotOpnd, instr->GetDst(), m_func);
  3682. this->AddInstr(instr, offset);
  3683. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), environmentOpnd, instr->GetDst(), m_func);
  3684. this->AddInstr(instr, offset);
  3685. instr = IR::Instr::New(newOpcode, regOpnd, instr->GetDst(), m_func);
  3686. if (regOpnd->m_sym->m_isSingleDef)
  3687. {
  3688. regOpnd->m_sym->m_isSafeThis = true;
  3689. regOpnd->m_sym->m_isNotNumber = true;
  3690. }
  3691. this->AddInstr(instr, offset);
  3692. return;
  3693. }
  3694. default:
  3695. AssertMsg(UNREACHED, "Unknown ElementSlotI3 opcode");
  3696. Fatal();
  3697. }
  3698. }
  3699. IR::SymOpnd *
  3700. IRBuilder::BuildLoopBodySlotOpnd(SymID symId)
  3701. {
  3702. Assert(!this->RegIsConstant((Js::RegSlot)symId));
  3703. // Get the interpreter frame instance that was passed in.
  3704. StackSym *loopParamSym = m_func->EnsureLoopParamSym();
  3705. PropertySym * fieldSym = PropertySym::FindOrCreate(loopParamSym->m_id, (Js::PropertyId)(symId + this->m_loopBodyLocalsStartSlot), (uint32)-1, (uint)-1, PropertyKindLocalSlots, m_func);
  3706. return IR::SymOpnd::New(fieldSym, TyVar, m_func);
  3707. }
  3708. void
  3709. IRBuilder::EnsureLoopBodyLoadSlot(SymID symId, bool isCatchObjectSym)
  3710. {
  3711. // No need to emit LdSlot for a catch object. In fact, if we do, we might be loading an uninitialized value from the slot.
  3712. if (isCatchObjectSym)
  3713. {
  3714. return;
  3715. }
  3716. StackSym * symDst = StackSym::FindOrCreate(symId, (Js::RegSlot)symId, m_func);
  3717. if (symDst->m_isCatchObjectSym)
  3718. {
  3719. return;
  3720. }
  3721. AssertOrFailFast(symId < m_ldSlots->Length());
  3722. if (this->m_ldSlots->TestAndSet(symId))
  3723. {
  3724. return;
  3725. }
  3726. IR::SymOpnd * fieldSymOpnd = this->BuildLoopBodySlotOpnd(symId);
  3727. IR::RegOpnd * dstOpnd = IR::RegOpnd::New(symDst, TyVar, m_func);
  3728. IR::Instr * ldSlotInstr;
  3729. ValueType symValueType;
  3730. if(m_func->GetWorkItem()->HasSymIdToValueTypeMap() && m_func->GetWorkItem()->TryGetValueType(symId, &symValueType))
  3731. {
  3732. ldSlotInstr = IR::ProfiledInstr::New(Js::OpCode::LdSlot, dstOpnd, fieldSymOpnd, m_func);
  3733. ldSlotInstr->AsProfiledInstr()->u.FldInfo().valueType = symValueType;
  3734. }
  3735. else
  3736. {
  3737. ldSlotInstr = IR::Instr::New(Js::OpCode::LdSlot, dstOpnd, fieldSymOpnd, m_func);
  3738. }
  3739. m_func->m_headInstr->InsertAfter(ldSlotInstr);
  3740. if (m_lastInstr == m_func->m_headInstr)
  3741. {
  3742. m_lastInstr = ldSlotInstr;
  3743. }
  3744. }
  3745. void
  3746. IRBuilder::SetLoopBodyStSlot(SymID symID, bool isCatchObjectSym)
  3747. {
  3748. if (this->m_func->HasTry() && !PHASE_OFF(Js::JITLoopBodyInTryCatchPhase, this->m_func))
  3749. {
  3750. // No need to emit StSlot for a catch object. In fact, if we do, we might be storing an uninitialized value to the slot.
  3751. if (isCatchObjectSym)
  3752. {
  3753. return;
  3754. }
  3755. StackSym * dstSym = StackSym::FindOrCreate(symID, (Js::RegSlot)symID, m_func);
  3756. Assert(dstSym);
  3757. if (dstSym->m_isCatchObjectSym)
  3758. {
  3759. return;
  3760. }
  3761. }
  3762. AssertOrFailFast(symID < m_stSlots->Length());
  3763. this->m_stSlots->Set(symID);
  3764. }
  3765. ///----------------------------------------------------------------------------
  3766. ///
  3767. /// IRBuilder::BuildElementCP
  3768. ///
  3769. /// Build IR instr for an ElementCP or ElementRootCP instruction.
  3770. ///
  3771. ///----------------------------------------------------------------------------
  3772. IR::Instr *
  3773. IRBuilder::BuildProfiledFieldLoad(Js::OpCode loadOp, IR::RegOpnd *dstOpnd, IR::SymOpnd *srcOpnd, Js::CacheId inlineCacheIndex, bool *pUnprofiled)
  3774. {
  3775. IR::Instr * instr = nullptr;
  3776. // Prefer JitProfilingInstr if we're in simplejit
  3777. if (m_func->DoSimpleJitDynamicProfile())
  3778. {
  3779. instr = IR::JitProfilingInstr::New(loadOp, dstOpnd, srcOpnd, m_func);
  3780. }
  3781. else if (this->m_func->HasProfileInfo())
  3782. {
  3783. instr = IR::ProfiledInstr::New(loadOp, dstOpnd, srcOpnd, m_func);
  3784. instr->AsProfiledInstr()->u.FldInfo() = *(m_func->GetReadOnlyProfileInfo()->GetFldInfo(inlineCacheIndex));
  3785. *pUnprofiled = !instr->AsProfiledInstr()->u.FldInfo().WasLdFldProfiled();
  3786. dstOpnd->SetValueType(instr->AsProfiledInstr()->u.FldInfo().valueType);
  3787. #if ENABLE_DEBUG_CONFIG_OPTIONS
  3788. if(Js::Configuration::Global.flags.TestTrace.IsEnabled(Js::DynamicProfilePhase))
  3789. {
  3790. const ValueType valueType(instr->AsProfiledInstr()->u.FldInfo().valueType);
  3791. char valueTypeStr[VALUE_TYPE_MAX_STRING_SIZE];
  3792. valueType.ToString(valueTypeStr);
  3793. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  3794. Output::Print(_u("TestTrace function %s (%s) ValueType = %i "), m_func->GetJITFunctionBody()->GetDisplayName(), m_func->GetDebugNumberSet(debugStringBuffer), valueTypeStr);
  3795. instr->DumpTestTrace();
  3796. }
  3797. #endif
  3798. }
  3799. return instr;
  3800. }
  3801. Js::RegSlot IRBuilder::GetEnvRegForEvalCode() const
  3802. {
  3803. if (m_func->GetJITFunctionBody()->IsStrictMode() && m_func->GetJITFunctionBody()->IsGlobalFunc())
  3804. {
  3805. return m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg();
  3806. }
  3807. else
  3808. {
  3809. return GetEnvReg();
  3810. }
  3811. }
  3812. template <typename SizePolicy>
  3813. void
  3814. IRBuilder::BuildElementP(Js::OpCode newOpcode, uint32 offset)
  3815. {
  3816. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  3817. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementP<SizePolicy>>();
  3818. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  3819. {
  3820. this->DoClosureRegCheck(layout->Value);
  3821. }
  3822. BuildElementP(newOpcode, offset, layout->Value, layout->inlineCacheIndex);
  3823. }
  3824. void
  3825. IRBuilder::BuildElementP(Js::OpCode newOpcode, uint32 offset, Js::RegSlot regSlot, Js::CacheId inlineCacheIndex)
  3826. {
  3827. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  3828. IR::Instr * instr;
  3829. IR::RegOpnd * regOpnd;
  3830. IR::Opnd * srcOpnd;
  3831. IR::SymOpnd * fieldSymOpnd;
  3832. Js::PropertyId propertyId;
  3833. bool isProfiled = OpCodeAttr::IsProfiledOp(newOpcode);
  3834. bool isLdFldThatWasNotProfiled = false;
  3835. if (isProfiled)
  3836. {
  3837. Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
  3838. }
  3839. propertyId = this->m_func->GetJITFunctionBody()->GetPropertyIdFromCacheId(inlineCacheIndex);
  3840. Js::RegSlot instance = this->GetEnvRegForEvalCode();
  3841. bool reuseLoc = false;
  3842. switch (newOpcode)
  3843. {
  3844. case Js::OpCode::LdLocalFld_ReuseLoc:
  3845. reuseLoc = true;
  3846. newOpcode = Js::OpCode::LdLocalFld;
  3847. // fall through
  3848. case Js::OpCode::LdLocalFld:
  3849. if (m_func->GetLocalClosureSym()->HasByteCodeRegSlot())
  3850. {
  3851. IR::ByteCodeUsesInstr * byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
  3852. byteCodeUse->SetNonOpndSymbol(m_func->GetLocalClosureSym()->m_id);
  3853. this->AddInstr(byteCodeUse, offset);
  3854. }
  3855. newOpcode = Js::OpCode::LdFld;
  3856. fieldSymOpnd = this->BuildFieldOpnd(newOpcode, m_func->GetJITFunctionBody()->GetLocalClosureReg(), propertyId, (Js::PropertyIdIndexType)-1, PropertyKindData, inlineCacheIndex);
  3857. if (fieldSymOpnd->IsPropertySymOpnd())
  3858. {
  3859. fieldSymOpnd->AsPropertySymOpnd()->TryDisableRuntimePolymorphicCache();
  3860. }
  3861. regOpnd = this->BuildDstOpnd(regSlot, TyVar, false, reuseLoc);
  3862. instr = nullptr;
  3863. if (isProfiled)
  3864. {
  3865. instr = this->BuildProfiledFieldLoad(newOpcode, regOpnd, fieldSymOpnd, inlineCacheIndex, &isLdFldThatWasNotProfiled);
  3866. }
  3867. // If it hasn't been set yet
  3868. if (!instr)
  3869. {
  3870. instr = IR::Instr::New(newOpcode, regOpnd, fieldSymOpnd, m_func);
  3871. }
  3872. break;
  3873. case Js::OpCode::StLocalFld:
  3874. if (m_func->GetLocalClosureSym()->HasByteCodeRegSlot())
  3875. {
  3876. IR::ByteCodeUsesInstr * byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
  3877. byteCodeUse->SetNonOpndSymbol(m_func->GetLocalClosureSym()->m_id);
  3878. this->AddInstr(byteCodeUse, offset);
  3879. }
  3880. fieldSymOpnd = this->BuildFieldOpnd(newOpcode, m_func->GetJITFunctionBody()->GetLocalClosureReg(), propertyId, (Js::PropertyIdIndexType)-1, PropertyKindData, inlineCacheIndex);
  3881. if (fieldSymOpnd->IsPropertySymOpnd())
  3882. {
  3883. fieldSymOpnd->AsPropertySymOpnd()->TryDisableRuntimePolymorphicCache();
  3884. }
  3885. srcOpnd = this->BuildSrcOpnd(regSlot);
  3886. newOpcode = Js::OpCode::StFld;
  3887. goto stCommon;
  3888. case Js::OpCode::InitLocalFld:
  3889. case Js::OpCode::InitLocalLetFld:
  3890. case Js::OpCode::InitUndeclLocalLetFld:
  3891. case Js::OpCode::InitUndeclLocalConstFld:
  3892. {
  3893. if (m_func->GetLocalClosureSym()->HasByteCodeRegSlot())
  3894. {
  3895. IR::ByteCodeUsesInstr * byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
  3896. byteCodeUse->SetNonOpndSymbol(m_func->GetLocalClosureSym()->m_id);
  3897. this->AddInstr(byteCodeUse, offset);
  3898. }
  3899. fieldSymOpnd = this->BuildFieldOpnd(newOpcode, m_func->GetJITFunctionBody()->GetLocalClosureReg(), propertyId, (Js::PropertyIdIndexType)-1, PropertyKindData, inlineCacheIndex);
  3900. // Store
  3901. if (newOpcode == Js::OpCode::InitUndeclLocalLetFld)
  3902. {
  3903. srcOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetUndeclBlockVarAddr(), IR::AddrOpndKindDynamicVar, this->m_func, true);
  3904. srcOpnd->SetValueType(ValueType::PrimitiveOrObject);
  3905. newOpcode = Js::OpCode::InitLetFld;
  3906. }
  3907. else if (newOpcode == Js::OpCode::InitUndeclLocalConstFld)
  3908. {
  3909. srcOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetUndeclBlockVarAddr(), IR::AddrOpndKindDynamicVar, this->m_func, true);
  3910. srcOpnd->SetValueType(ValueType::PrimitiveOrObject);
  3911. newOpcode = Js::OpCode::InitConstFld;
  3912. }
  3913. else
  3914. {
  3915. srcOpnd = this->BuildSrcOpnd(regSlot);
  3916. newOpcode = newOpcode == Js::OpCode::InitLocalFld ? Js::OpCode::InitFld : Js::OpCode::InitLetFld;
  3917. }
  3918. stCommon:
  3919. instr = nullptr;
  3920. if (isProfiled)
  3921. {
  3922. if (m_func->DoSimpleJitDynamicProfile())
  3923. {
  3924. instr = IR::JitProfilingInstr::New(newOpcode, fieldSymOpnd, srcOpnd, m_func);
  3925. }
  3926. else if (this->m_func->HasProfileInfo())
  3927. {
  3928. instr = IR::ProfiledInstr::New(newOpcode, fieldSymOpnd, srcOpnd, m_func);
  3929. instr->AsProfiledInstr()->u.FldInfo() = *(m_func->GetReadOnlyProfileInfo()->GetFldInfo(inlineCacheIndex));
  3930. }
  3931. }
  3932. // If it hasn't been set yet
  3933. if (!instr)
  3934. {
  3935. instr = IR::Instr::New(newOpcode, fieldSymOpnd, srcOpnd, m_func);
  3936. }
  3937. break;
  3938. }
  3939. case Js::OpCode::ScopedLdFld:
  3940. case Js::OpCode::ScopedLdFldForTypeOf:
  3941. {
  3942. Assert(!isProfiled);
  3943. Assert(this->m_func->GetScriptContextInfo()->GetAddr() == this->m_func->GetTopFunc()->GetScriptContextInfo()->GetAddr());
  3944. fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instance, propertyId, (Js::PropertyIdIndexType)-1, PropertyKindData, inlineCacheIndex);
  3945. regOpnd = this->BuildDstOpnd(regSlot);
  3946. instr = IR::Instr::New(newOpcode, regOpnd, fieldSymOpnd, m_func);
  3947. break;
  3948. }
  3949. case Js::OpCode::ScopedStFld:
  3950. case Js::OpCode::ConsoleScopedStFld:
  3951. case Js::OpCode::ScopedStFldStrict:
  3952. case Js::OpCode::ConsoleScopedStFldStrict:
  3953. {
  3954. Assert(!isProfiled);
  3955. fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instance, propertyId, (Js::PropertyIdIndexType)-1, PropertyKindData, inlineCacheIndex);
  3956. // Implicit root object as default instance
  3957. IR::Opnd * instance2Opnd = this->BuildSrcOpnd(Js::FunctionBody::RootObjectRegSlot);
  3958. regOpnd = this->BuildSrcOpnd(regSlot);
  3959. instr = IR::Instr::New(newOpcode, fieldSymOpnd, regOpnd, instance2Opnd, m_func);
  3960. break;
  3961. }
  3962. default:
  3963. AssertMsg(UNREACHED, "Unknown ElementP opcode");
  3964. Fatal();
  3965. }
  3966. this->AddInstr(instr, offset);
  3967. if(isLdFldThatWasNotProfiled && DoBailOnNoProfile())
  3968. {
  3969. InsertBailOnNoProfile(instr);
  3970. }
  3971. }
  3972. template <typename SizePolicy>
  3973. void
  3974. IRBuilder::BuildElementPIndexed(Js::OpCode newOpcode, uint32 offset)
  3975. {
  3976. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  3977. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementPIndexed<SizePolicy>>();
  3978. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  3979. {
  3980. this->DoClosureRegCheck(layout->Value);
  3981. }
  3982. switch (newOpcode)
  3983. {
  3984. case Js::OpCode::InitInnerFld:
  3985. newOpcode = Js::OpCode::InitFld;
  3986. goto initinnerfldcommon;
  3987. case Js::OpCode::InitInnerLetFld:
  3988. newOpcode = Js::OpCode::InitLetFld;
  3989. // fall through
  3990. initinnerfldcommon:
  3991. case Js::OpCode::InitUndeclLetFld:
  3992. case Js::OpCode::InitUndeclConstFld:
  3993. BuildElementCP(newOpcode, offset, InnerScopeIndexToRegSlot(layout->scopeIndex), layout->Value, layout->inlineCacheIndex);
  3994. break;
  3995. default:
  3996. AssertMsg(false, "Unknown opcode for ElementPIndexed");
  3997. break;
  3998. }
  3999. }
  4000. template <typename SizePolicy>
  4001. void
  4002. IRBuilder::BuildElementCP(Js::OpCode newOpcode, uint32 offset)
  4003. {
  4004. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4005. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementCP<SizePolicy>>();
  4006. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  4007. {
  4008. this->DoClosureRegCheck(layout->Value);
  4009. this->DoClosureRegCheck(layout->Instance);
  4010. }
  4011. BuildElementCP(newOpcode, offset, layout->Instance, layout->Value, layout->inlineCacheIndex);
  4012. }
  4013. template <typename SizePolicy>
  4014. void
  4015. IRBuilder::BuildElementRootCP(Js::OpCode newOpcode, uint32 offset)
  4016. {
  4017. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4018. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementRootCP<SizePolicy>>();
  4019. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  4020. {
  4021. this->DoClosureRegCheck(layout->Value);
  4022. }
  4023. BuildElementCP(newOpcode, offset, Js::FunctionBody::RootObjectRegSlot, layout->Value, layout->inlineCacheIndex);
  4024. }
  4025. void
  4026. IRBuilder::BuildElementCP(Js::OpCode newOpcode, uint32 offset, Js::RegSlot instance, Js::RegSlot regSlot, Js::CacheId inlineCacheIndex)
  4027. {
  4028. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4029. Js::PropertyId propertyId;
  4030. bool isProfiled = OpCodeAttr::IsProfiledOp(newOpcode);
  4031. if (isProfiled)
  4032. {
  4033. Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
  4034. }
  4035. propertyId = m_func->GetJITFunctionBody()->GetPropertyIdFromCacheId(inlineCacheIndex);
  4036. IR::SymOpnd * fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instance, propertyId, (Js::PropertyIdIndexType)-1, PropertyKindData, inlineCacheIndex);
  4037. IR::RegOpnd * regOpnd;
  4038. IR::Instr * instr = nullptr;
  4039. bool isLdFldThatWasNotProfiled = false;
  4040. bool reuseLoc = false;
  4041. switch (newOpcode)
  4042. {
  4043. case Js::OpCode::LdFld_ReuseLoc:
  4044. reuseLoc = true;
  4045. newOpcode = Js::OpCode::LdFld;
  4046. // fall through
  4047. case Js::OpCode::LdFldForTypeOf:
  4048. case Js::OpCode::LdFld:
  4049. case Js::OpCode::LdLen_A:
  4050. if (fieldSymOpnd->IsPropertySymOpnd())
  4051. {
  4052. fieldSymOpnd->AsPropertySymOpnd()->TryDisableRuntimePolymorphicCache();
  4053. }
  4054. case Js::OpCode::LdFldForCallApplyTarget:
  4055. case Js::OpCode::LdRootFldForTypeOf:
  4056. case Js::OpCode::LdRootFld:
  4057. case Js::OpCode::LdMethodFld:
  4058. case Js::OpCode::LdRootMethodFld:
  4059. case Js::OpCode::ScopedLdMethodFld:
  4060. // Load
  4061. // LdMethodFromFlags is backend only. Don't need to be added here.
  4062. regOpnd = this->BuildDstOpnd(regSlot, TyVar, false, reuseLoc);
  4063. if (isProfiled)
  4064. {
  4065. instr = this->BuildProfiledFieldLoad(newOpcode, regOpnd, fieldSymOpnd, inlineCacheIndex, &isLdFldThatWasNotProfiled);
  4066. }
  4067. // If it hasn't been set yet
  4068. if (!instr)
  4069. {
  4070. instr = IR::Instr::New(newOpcode, regOpnd, fieldSymOpnd, m_func);
  4071. }
  4072. if (newOpcode == Js::OpCode::LdFld ||
  4073. newOpcode == Js::OpCode::LdFldForCallApplyTarget ||
  4074. newOpcode == Js::OpCode::LdMethodFld ||
  4075. newOpcode == Js::OpCode::LdRootMethodFld ||
  4076. newOpcode == Js::OpCode::ScopedLdMethodFld)
  4077. {
  4078. // Check whether we're loading (what appears to be) a built-in method.
  4079. Js::BuiltinFunction builtInIndex = Js::BuiltinFunction::None;
  4080. PropertySym *fieldSym = fieldSymOpnd->m_sym->AsPropertySym();
  4081. this->CheckBuiltIn(fieldSym, &builtInIndex);
  4082. regOpnd->m_sym->m_builtInIndex = builtInIndex;
  4083. }
  4084. break;
  4085. case Js::OpCode::StFld:
  4086. if (fieldSymOpnd->IsPropertySymOpnd())
  4087. {
  4088. fieldSymOpnd->AsPropertySymOpnd()->TryDisableRuntimePolymorphicCache();
  4089. }
  4090. case Js::OpCode::InitFld:
  4091. case Js::OpCode::InitRootFld:
  4092. case Js::OpCode::InitLetFld:
  4093. case Js::OpCode::InitRootLetFld:
  4094. case Js::OpCode::InitConstFld:
  4095. case Js::OpCode::InitRootConstFld:
  4096. case Js::OpCode::InitUndeclLetFld:
  4097. case Js::OpCode::InitUndeclConstFld:
  4098. case Js::OpCode::InitClassMember:
  4099. case Js::OpCode::StRootFld:
  4100. case Js::OpCode::StFldStrict:
  4101. case Js::OpCode::StRootFldStrict:
  4102. {
  4103. IR::Opnd *srcOpnd;
  4104. // Store
  4105. if (newOpcode == Js::OpCode::InitUndeclLetFld)
  4106. {
  4107. srcOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetUndeclBlockVarAddr(), IR::AddrOpndKindDynamicVar, this->m_func, true);
  4108. srcOpnd->SetValueType(ValueType::PrimitiveOrObject);
  4109. newOpcode = Js::OpCode::InitLetFld;
  4110. }
  4111. else if (newOpcode == Js::OpCode::InitUndeclConstFld)
  4112. {
  4113. srcOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetUndeclBlockVarAddr(), IR::AddrOpndKindDynamicVar, this->m_func, true);
  4114. srcOpnd->SetValueType(ValueType::PrimitiveOrObject);
  4115. newOpcode = Js::OpCode::InitConstFld;
  4116. }
  4117. else
  4118. {
  4119. srcOpnd = this->BuildSrcOpnd(regSlot);
  4120. }
  4121. if (isProfiled)
  4122. {
  4123. if (m_func->DoSimpleJitDynamicProfile())
  4124. {
  4125. instr = IR::JitProfilingInstr::New(newOpcode, fieldSymOpnd, srcOpnd, m_func);
  4126. }
  4127. else if (this->m_func->HasProfileInfo())
  4128. {
  4129. instr = IR::ProfiledInstr::New(newOpcode, fieldSymOpnd, srcOpnd, m_func);
  4130. instr->AsProfiledInstr()->u.FldInfo() = *(m_func->GetReadOnlyProfileInfo()->GetFldInfo(inlineCacheIndex));
  4131. }
  4132. }
  4133. // If it hasn't been set yet
  4134. if (!instr)
  4135. {
  4136. instr = IR::Instr::New(newOpcode, fieldSymOpnd, srcOpnd, m_func);
  4137. }
  4138. break;
  4139. }
  4140. default:
  4141. AssertMsg(UNREACHED, "Unknown ElementCP opcode");
  4142. Fatal();
  4143. }
  4144. this->AddInstr(instr, offset);
  4145. if(isLdFldThatWasNotProfiled && DoBailOnNoProfile())
  4146. {
  4147. InsertBailOnNoProfile(instr);
  4148. }
  4149. }
  4150. template <typename SizePolicy>
  4151. void
  4152. IRBuilder::BuildProfiledElementCP(Js::OpCode newOpcode, uint32 offset)
  4153. {
  4154. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4155. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_ElementCP<SizePolicy>>>();
  4156. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  4157. {
  4158. this->DoClosureRegCheck(layout->Value);
  4159. this->DoClosureRegCheck(layout->Instance);
  4160. }
  4161. BuildProfiledElementCP(newOpcode, offset, layout->Instance, layout->Value, layout->inlineCacheIndex, layout->profileId);
  4162. }
  4163. void
  4164. IRBuilder::BuildProfiledElementCP(Js::OpCode newOpcode, uint32 offset, Js::RegSlot instance, Js::RegSlot regSlot, Js::CacheId inlineCacheIndex, Js::ProfileId profileId)
  4165. {
  4166. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4167. Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
  4168. Assert(newOpcode == Js::OpCode::LdLen_A);
  4169. Js::PropertyId propertyId = m_func->GetJITFunctionBody()->GetPropertyIdFromCacheId(inlineCacheIndex);
  4170. IR::SymOpnd * fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instance, propertyId, (Js::PropertyIdIndexType) - 1, PropertyKindData, inlineCacheIndex);
  4171. IR::RegOpnd * dstOpnd = this->BuildDstOpnd(regSlot);
  4172. bool isProfiled = (profileId != Js::Constants::NoProfileId);
  4173. ValueType arrayType = ValueType::Uninitialized;
  4174. const Js::LdLenInfo * ldLenInfo = nullptr;
  4175. if (m_func->HasProfileInfo())
  4176. {
  4177. ldLenInfo = m_func->GetReadOnlyProfileInfo()->GetLdLenInfo(profileId);
  4178. arrayType = (ldLenInfo->GetArrayType());
  4179. if (arrayType.IsLikelyNativeArray() && !AllowNativeArrayProfileInfo())
  4180. {
  4181. // An opnd's value type will get replaced in the forward phase when it is not fixed. Store the array type in the ProfiledInstr.
  4182. arrayType = arrayType.SetArrayTypeId(Js::TypeIds_Array);
  4183. }
  4184. fieldSymOpnd->SetValueType(arrayType);
  4185. if (m_func->GetTopFunc()->HasTry() && !m_func->GetTopFunc()->DoOptimizeTry())
  4186. {
  4187. isProfiled = false;
  4188. }
  4189. }
  4190. else
  4191. {
  4192. isProfiled = false;
  4193. }
  4194. bool wasNotProfiled = false;
  4195. IR::Instr *instr = nullptr;
  4196. if (isProfiled)
  4197. {
  4198. instr = this->BuildProfiledFieldLoad(newOpcode, dstOpnd, fieldSymOpnd, inlineCacheIndex, &wasNotProfiled);
  4199. }
  4200. if (instr == nullptr)
  4201. {
  4202. instr = IR::Instr::New(newOpcode, dstOpnd, fieldSymOpnd, m_func);
  4203. }
  4204. else if (instr->IsJitProfilingInstr())
  4205. {
  4206. instr->AsJitProfilingInstr()->profileId = profileId;
  4207. }
  4208. else if (instr->IsProfiledInstr())
  4209. {
  4210. instr->AsProfiledInstr()->u.LdLenInfo() = *ldLenInfo;
  4211. instr->AsProfiledInstr()->u.LdLenInfo().arrayType = arrayType;
  4212. }
  4213. this->AddInstr(instr, offset);
  4214. if (wasNotProfiled && DoBailOnNoProfile())
  4215. {
  4216. InsertBailOnNoProfile(instr);
  4217. }
  4218. }
  4219. ///----------------------------------------------------------------------------
  4220. ///
  4221. /// IRBuilder::BuildElementC2
  4222. ///
  4223. /// Build IR instr for an ElementC2 instruction.
  4224. ///
  4225. ///----------------------------------------------------------------------------
  4226. template <typename SizePolicy>
  4227. void
  4228. IRBuilder::BuildElementScopedC2(Js::OpCode newOpcode, uint32 offset)
  4229. {
  4230. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4231. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementScopedC2<SizePolicy>>();
  4232. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  4233. {
  4234. this->DoClosureRegCheck(layout->Value);
  4235. this->DoClosureRegCheck(layout->Value2);
  4236. }
  4237. BuildElementScopedC2(newOpcode, offset, layout->Value2, layout->Value, layout->PropertyIdIndex);
  4238. }
  4239. void
  4240. IRBuilder::BuildElementScopedC2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot value2Slot,
  4241. Js::RegSlot regSlot, Js::PropertyIdIndexType propertyIdIndex)
  4242. {
  4243. IR::Instr * instr = nullptr;
  4244. Js::PropertyId propertyId;
  4245. IR::RegOpnd * regOpnd;
  4246. IR::RegOpnd * value2Opnd;
  4247. IR::SymOpnd * fieldSymOpnd;
  4248. Js::RegSlot instanceSlot = this->GetEnvRegForEvalCode();
  4249. switch (newOpcode)
  4250. {
  4251. case Js::OpCode::ScopedLdInst:
  4252. {
  4253. propertyId = m_func->GetJITFunctionBody()->GetReferencedPropertyId(propertyIdIndex);
  4254. fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instanceSlot, propertyId, propertyIdIndex, PropertyKindData);
  4255. regOpnd = this->BuildDstOpnd(regSlot);
  4256. value2Opnd = this->BuildDstOpnd(value2Slot);
  4257. IR::Instr *newInstr = IR::Instr::New(Js::OpCode::Unused, value2Opnd, m_func);
  4258. this->AddInstr(newInstr, offset);
  4259. instr = IR::Instr::New(newOpcode, regOpnd, fieldSymOpnd, newInstr->GetDst(), m_func);
  4260. this->AddInstr(instr, offset);
  4261. }
  4262. break;
  4263. default:
  4264. AssertMsg(UNREACHED, "Unknown ElementC2 opcode");
  4265. Fatal();
  4266. }
  4267. }
  4268. template <typename SizePolicy>
  4269. void
  4270. IRBuilder::BuildElementC2(Js::OpCode newOpcode, uint32 offset)
  4271. {
  4272. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4273. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementC2<SizePolicy>>();
  4274. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  4275. {
  4276. this->DoClosureRegCheck(layout->Value);
  4277. this->DoClosureRegCheck(layout->Value2);
  4278. this->DoClosureRegCheck(layout->Instance);
  4279. }
  4280. BuildElementC2(newOpcode, offset, layout->Instance, layout->Value2, layout->Value, layout->PropertyIdIndex);
  4281. }
  4282. void
  4283. IRBuilder::BuildElementC2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot instanceSlot, Js::RegSlot value2Slot,
  4284. Js::RegSlot regSlot, Js::PropertyIdIndexType propertyIdIndex)
  4285. {
  4286. IR::Instr * instr = nullptr;
  4287. Js::PropertyId propertyId;
  4288. IR::RegOpnd * regOpnd;
  4289. IR::RegOpnd * value2Opnd;
  4290. IR::SymOpnd * fieldSymOpnd;
  4291. switch (newOpcode)
  4292. {
  4293. case Js::OpCode::ProfiledLdSuperFld:
  4294. Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
  4295. // fall-through
  4296. case Js::OpCode::LdSuperFld:
  4297. {
  4298. propertyId = m_func->GetJITFunctionBody()->GetPropertyIdFromCacheId(propertyIdIndex);
  4299. fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instanceSlot, propertyId, (Js::PropertyIdIndexType) - 1, PropertyKindData, propertyIdIndex);
  4300. if (fieldSymOpnd->IsPropertySymOpnd())
  4301. {
  4302. fieldSymOpnd->AsPropertySymOpnd()->TryDisableRuntimePolymorphicCache();
  4303. }
  4304. value2Opnd = this->BuildSrcOpnd(value2Slot);
  4305. regOpnd = this->BuildDstOpnd(regSlot);
  4306. instr = IR::ProfiledInstr::New(newOpcode, regOpnd, fieldSymOpnd, value2Opnd, m_func);
  4307. instr->AsProfiledInstr()->u.FldInfo() = *(m_func->GetReadOnlyProfileInfo()->GetFldInfo(propertyIdIndex));
  4308. this->AddInstr(instr, offset);
  4309. }
  4310. break;
  4311. case Js::OpCode::ProfiledStSuperFld:
  4312. case Js::OpCode::ProfiledStSuperFldStrict:
  4313. Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
  4314. // fall-through
  4315. case Js::OpCode::StSuperFld:
  4316. case Js::OpCode::StSuperFldStrict:
  4317. {
  4318. propertyId = m_func->GetJITFunctionBody()->GetPropertyIdFromCacheId(propertyIdIndex);
  4319. fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instanceSlot, propertyId, (Js::PropertyIdIndexType) - 1, PropertyKindData, propertyIdIndex);
  4320. if (fieldSymOpnd->IsPropertySymOpnd())
  4321. {
  4322. fieldSymOpnd->AsPropertySymOpnd()->TryDisableRuntimePolymorphicCache();
  4323. }
  4324. regOpnd = this->BuildSrcOpnd(regSlot);
  4325. value2Opnd = this->BuildSrcOpnd(value2Slot);
  4326. instr = IR::ProfiledInstr::New(newOpcode, fieldSymOpnd, regOpnd, value2Opnd, m_func);
  4327. instr->AsProfiledInstr()->u.FldInfo() = *(m_func->GetReadOnlyProfileInfo()->GetFldInfo(propertyIdIndex));
  4328. this->AddInstr(instr, offset);
  4329. break;
  4330. }
  4331. default:
  4332. AssertMsg(UNREACHED, "Unknown ElementC2 opcode");
  4333. Fatal();
  4334. }
  4335. }
  4336. ///----------------------------------------------------------------------------
  4337. ///
  4338. /// IRBuilder::BuildElementU
  4339. ///
  4340. /// Build IR instr for an ElementU or ElementRootU instruction.
  4341. ///
  4342. ///----------------------------------------------------------------------------
  4343. template <typename SizePolicy>
  4344. void
  4345. IRBuilder::BuildElementU(Js::OpCode newOpcode, uint32 offset)
  4346. {
  4347. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  4348. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4349. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementU<SizePolicy>>();
  4350. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  4351. {
  4352. this->DoClosureRegCheck(layout->Instance);
  4353. }
  4354. BuildElementU(newOpcode, offset, layout->Instance, layout->PropertyIdIndex);
  4355. }
  4356. template <typename SizePolicy>
  4357. void
  4358. IRBuilder::BuildElementRootU(Js::OpCode newOpcode, uint32 offset)
  4359. {
  4360. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  4361. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4362. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementRootU<SizePolicy>>();
  4363. BuildElementU(newOpcode, offset, Js::FunctionBody::RootObjectRegSlot, layout->PropertyIdIndex);
  4364. }
  4365. template <typename SizePolicy>
  4366. void
  4367. IRBuilder::BuildElementScopedU(Js::OpCode newOpcode, uint32 offset)
  4368. {
  4369. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  4370. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4371. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementScopedU<SizePolicy>>();
  4372. BuildElementU(newOpcode, offset, GetEnvReg(), layout->PropertyIdIndex);
  4373. }
  4374. void
  4375. IRBuilder::BuildElementU(Js::OpCode newOpcode, uint32 offset, Js::RegSlot instance, Js::PropertyIdIndexType propertyIdIndex)
  4376. {
  4377. IR::Instr * instr;
  4378. IR::RegOpnd * regOpnd;
  4379. IR::SymOpnd * fieldSymOpnd;
  4380. Js::PropertyId propertyId = m_func->GetJITFunctionBody()->GetReferencedPropertyId(propertyIdIndex);
  4381. bool reuseLoc = false;
  4382. switch (newOpcode)
  4383. {
  4384. case Js::OpCode::LdLocalElemUndef:
  4385. if (m_func->GetLocalClosureSym()->HasByteCodeRegSlot())
  4386. {
  4387. IR::ByteCodeUsesInstr * byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
  4388. byteCodeUse->SetNonOpndSymbol(m_func->GetLocalClosureSym()->m_id);
  4389. this->AddInstr(byteCodeUse, offset);
  4390. }
  4391. instance = m_func->GetJITFunctionBody()->GetLocalClosureReg();
  4392. newOpcode = Js::OpCode::LdElemUndef;
  4393. fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instance, propertyId, propertyIdIndex, PropertyKindData);
  4394. instr = IR::Instr::New(newOpcode, fieldSymOpnd, m_func);
  4395. break;
  4396. // fall through
  4397. case Js::OpCode::LdElemUndefScoped:
  4398. {
  4399. // Store
  4400. PropertyKind propertyKind = PropertyKindData;
  4401. fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instance, propertyId, propertyIdIndex, propertyKind);
  4402. // Implicit root object as default instance
  4403. regOpnd = this->BuildSrcOpnd(Js::FunctionBody::RootObjectRegSlot);
  4404. instr = IR::Instr::New(newOpcode, fieldSymOpnd, regOpnd, m_func);
  4405. break;
  4406. }
  4407. case Js::OpCode::ClearAttributes:
  4408. {
  4409. instr = IR::Instr::New(newOpcode, m_func);
  4410. IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(instance);
  4411. IR::IntConstOpnd * src2Opnd = IR::IntConstOpnd::New(propertyId, TyInt32, m_func);
  4412. instr->SetSrc1(src1Opnd);
  4413. instr->SetSrc2(src2Opnd);
  4414. break;
  4415. }
  4416. case Js::OpCode::StLocalFuncExpr:
  4417. fieldSymOpnd = this->BuildFieldOpnd(newOpcode, m_func->GetJITFunctionBody()->GetLocalClosureReg(), propertyId, propertyIdIndex, PropertyKindData);
  4418. regOpnd = this->BuildSrcOpnd(instance);
  4419. newOpcode = Js::OpCode::StFuncExpr;
  4420. instr = IR::Instr::New(newOpcode, fieldSymOpnd, regOpnd, m_func);
  4421. break;
  4422. case Js::OpCode::DeleteLocalFld_ReuseLoc:
  4423. newOpcode = Js::OpCode::DeleteLocalFld;
  4424. reuseLoc = true;
  4425. // fall through
  4426. case Js::OpCode::DeleteLocalFld:
  4427. newOpcode = Js::OpCode::DeleteFld;
  4428. fieldSymOpnd = BuildFieldOpnd(newOpcode, m_func->GetJITFunctionBody()->GetLocalClosureReg(), propertyId, propertyIdIndex, PropertyKindData);
  4429. regOpnd = BuildDstOpnd(instance, TyVar, false, reuseLoc);
  4430. instr = IR::Instr::New(newOpcode, regOpnd, fieldSymOpnd, m_func);
  4431. break;
  4432. default:
  4433. {
  4434. fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instance, propertyId, propertyIdIndex, PropertyKindData);
  4435. instr = IR::Instr::New(newOpcode, fieldSymOpnd, m_func);
  4436. break;
  4437. }
  4438. }
  4439. this->AddInstr(instr, offset);
  4440. }
  4441. ///----------------------------------------------------------------------------
  4442. ///
  4443. /// IRBuilder::BuildAuxiliary
  4444. ///
  4445. /// Build IR instr for an Auxiliary instruction.
  4446. ///
  4447. ///----------------------------------------------------------------------------
  4448. void
  4449. IRBuilder::BuildAuxNoReg(Js::OpCode newOpcode, uint32 offset)
  4450. {
  4451. Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4452. IR::Instr * instr;
  4453. const unaligned Js::OpLayoutAuxNoReg *auxInsn = m_jnReader.AuxNoReg();
  4454. switch (newOpcode)
  4455. {
  4456. case Js::OpCode::InitCachedFuncs:
  4457. {
  4458. IR::Opnd *src1Opnd = this->BuildSrcOpnd(m_func->GetJITFunctionBody()->GetLocalClosureReg());
  4459. IR::Opnd *src2Opnd = this->BuildSrcOpnd(m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg());
  4460. IR::Opnd *src3Opnd = this->BuildAuxArrayOpnd(AuxArrayValue::AuxFuncInfoArray, auxInsn->Offset);
  4461. instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src3Opnd, m_func);
  4462. this->AddInstr(instr, offset);
  4463. instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src2Opnd, instr->GetDst(), m_func);
  4464. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  4465. instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src1Opnd, instr->GetDst(), m_func);
  4466. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  4467. IR::HelperCallOpnd *helperOpnd;
  4468. helperOpnd = IR::HelperCallOpnd::New(IR::HelperOP_InitCachedFuncs, this->m_func);
  4469. src2Opnd = instr->GetDst();
  4470. instr = IR::Instr::New(Js::OpCode::CallHelper, m_func);
  4471. instr->SetSrc1(helperOpnd);
  4472. instr->SetSrc2(src2Opnd);
  4473. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  4474. return;
  4475. }
  4476. default:
  4477. {
  4478. AssertMsg(UNREACHED, "Unknown AuxNoReg opcode");
  4479. Fatal();
  4480. break;
  4481. }
  4482. }
  4483. }
  4484. void
  4485. IRBuilder::BuildAuxiliary(Js::OpCode newOpcode, uint32 offset)
  4486. {
  4487. Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4488. const unaligned Js::OpLayoutAuxiliary *auxInsn = m_jnReader.Auxiliary();
  4489. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  4490. {
  4491. this->DoClosureRegCheck(auxInsn->R0);
  4492. }
  4493. IR::Instr *instr;
  4494. switch (newOpcode)
  4495. {
  4496. case Js::OpCode::NewScObjectLiteral:
  4497. {
  4498. int literalObjectId = auxInsn->C1;
  4499. IR::RegOpnd * dstOpnd;
  4500. IR::Opnd* srcOpnd;
  4501. Js::RegSlot dstRegSlot = auxInsn->R0;
  4502. // The property ID array needs to be both relocatable and available (so we can
  4503. // get the slot capacity), so we need to just pass the offset to lower and let
  4504. // lower take it from there...
  4505. srcOpnd = IR::IntConstOpnd::New(auxInsn->Offset, TyUint32, m_func);
  4506. dstOpnd = this->BuildDstOpnd(dstRegSlot);
  4507. dstOpnd->SetValueType(ValueType::GetObject(ObjectType::UninitializedObject));
  4508. instr = IR::Instr::New(newOpcode, dstOpnd, srcOpnd, m_func);
  4509. // Because we're going to be making decisions based off the value, we have to defer
  4510. // this until we get to lowering.
  4511. instr->SetSrc2(IR::IntConstOpnd::New(literalObjectId, TyUint32, m_func));
  4512. if (dstOpnd->m_sym->m_isSingleDef)
  4513. {
  4514. dstOpnd->m_sym->m_isSafeThis = true;
  4515. }
  4516. break;
  4517. }
  4518. case Js::OpCode::LdPropIds:
  4519. {
  4520. IR::RegOpnd * dstOpnd;
  4521. IR::Opnd* srcOpnd;
  4522. Js::RegSlot dstRegSlot = auxInsn->R0;
  4523. srcOpnd = this->BuildAuxArrayOpnd(AuxArrayValue::AuxPropertyIdArray, auxInsn->Offset);
  4524. dstOpnd = this->BuildDstOpnd(dstRegSlot);
  4525. instr = IR::Instr::New(newOpcode, dstOpnd, srcOpnd, m_func);
  4526. if (dstOpnd->m_sym->m_isSingleDef)
  4527. {
  4528. dstOpnd->m_sym->m_isNotNumber = true;
  4529. }
  4530. break;
  4531. }
  4532. case Js::OpCode::NewScIntArray:
  4533. {
  4534. IR::RegOpnd* dstOpnd;
  4535. IR::Opnd* src1Opnd;
  4536. src1Opnd = this->BuildAuxArrayOpnd(AuxArrayValue::AuxIntArray, auxInsn->Offset);
  4537. dstOpnd = this->BuildDstOpnd(auxInsn->R0);
  4538. instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, m_func);
  4539. const Js::TypeId arrayTypeId = m_func->IsJitInDebugMode() ? Js::TypeIds_Array : Js::TypeIds_NativeIntArray;
  4540. dstOpnd->SetValueType(
  4541. ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(true).SetArrayTypeId(arrayTypeId));
  4542. dstOpnd->SetValueTypeFixed();
  4543. break;
  4544. }
  4545. case Js::OpCode::NewScFltArray:
  4546. {
  4547. IR::RegOpnd* dstOpnd;
  4548. IR::Opnd* src1Opnd;
  4549. src1Opnd = this->BuildAuxArrayOpnd(AuxArrayValue::AuxFloatArray, auxInsn->Offset);
  4550. dstOpnd = this->BuildDstOpnd(auxInsn->R0);
  4551. instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, m_func);
  4552. const Js::TypeId arrayTypeId = m_func->IsJitInDebugMode() ? Js::TypeIds_Array : Js::TypeIds_NativeFloatArray;
  4553. dstOpnd->SetValueType(
  4554. ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(true).SetArrayTypeId(arrayTypeId));
  4555. dstOpnd->SetValueTypeFixed();
  4556. break;
  4557. }
  4558. case Js::OpCode::StArrSegItem_A:
  4559. {
  4560. IR::RegOpnd* src1Opnd;
  4561. IR::Opnd* src2Opnd;
  4562. src1Opnd = this->BuildSrcOpnd(auxInsn->R0);
  4563. src2Opnd = this->BuildAuxArrayOpnd(AuxArrayValue::AuxVarsArray, auxInsn->Offset);
  4564. instr = IR::Instr::New(newOpcode, m_func);
  4565. instr->SetSrc1(src1Opnd);
  4566. instr->SetSrc2(src2Opnd);
  4567. break;
  4568. }
  4569. case Js::OpCode::NewScObject_A:
  4570. {
  4571. const Js::VarArrayVarCount *vars = (Js::VarArrayVarCount *)m_func->GetJITFunctionBody()->ReadFromAuxContextData(auxInsn->Offset);
  4572. int count = Js::TaggedInt::ToInt32(vars->count);
  4573. StackSym * symDst;
  4574. IR::SymOpnd * dstOpnd;
  4575. IR::Opnd * src1Opnd;
  4576. //
  4577. // PUSH all the parameters on the auxiliary context, to the stack
  4578. //
  4579. for (int i=0;i<count; i++)
  4580. {
  4581. m_argsOnStack++;
  4582. symDst = m_func->m_symTable->GetArgSlotSym((uint16)(i + 2));
  4583. if (symDst == nullptr || (uint16)(i + 2) != (i + 2))
  4584. {
  4585. AssertMsg(UNREACHED, "Arg count too big...");
  4586. Fatal();
  4587. }
  4588. dstOpnd = IR::SymOpnd::New(symDst, TyVar, m_func);
  4589. src1Opnd = IR::AddrOpnd::New(vars->elements[i], IR::AddrOpndKindDynamicVar, this->m_func, true);
  4590. instr = IR::Instr::New(Js::OpCode::ArgOut_A, dstOpnd, src1Opnd, m_func);
  4591. this->AddInstr(instr, offset);
  4592. m_argStack->Push(instr);
  4593. }
  4594. BuildCallI_Helper(Js::OpCode::NewScObject, offset, (Js::RegSlot)auxInsn->R0, (Js::RegSlot)auxInsn->C1, (Js::ArgSlot)count+1, Js::Constants::NoProfileId);
  4595. return;
  4596. }
  4597. default:
  4598. {
  4599. AssertMsg(UNREACHED, "Unknown Auxiliary opcode");
  4600. Fatal();
  4601. break;
  4602. }
  4603. }
  4604. this->AddInstr(instr, offset);
  4605. }
  4606. void
  4607. IRBuilder::BuildProfiledAuxiliary(Js::OpCode newOpcode, uint32 offset)
  4608. {
  4609. Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4610. const unaligned Js::OpLayoutDynamicProfile<Js::OpLayoutAuxiliary> *auxInsn = m_jnReader.ProfiledAuxiliary();
  4611. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  4612. {
  4613. this->DoClosureRegCheck(auxInsn->R0);
  4614. }
  4615. switch (newOpcode)
  4616. {
  4617. case Js::OpCode::ProfiledNewScIntArray:
  4618. {
  4619. Js::ProfileId profileId = static_cast<Js::ProfileId>(auxInsn->profileId);
  4620. IR::RegOpnd* dstOpnd;
  4621. IR::Opnd* src1Opnd;
  4622. src1Opnd = this->BuildAuxArrayOpnd(AuxArrayValue::AuxIntArray, auxInsn->Offset);
  4623. dstOpnd = this->BuildDstOpnd(auxInsn->R0);
  4624. Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
  4625. IR::Instr *instr;
  4626. Js::ArrayCallSiteInfo *arrayInfo = nullptr;
  4627. Js::TypeId arrayTypeId = Js::TypeIds_Array;
  4628. if (m_func->DoSimpleJitDynamicProfile())
  4629. {
  4630. instr = IR::JitProfilingInstr::New(newOpcode, dstOpnd, src1Opnd, m_func);
  4631. instr->AsJitProfilingInstr()->profileId = profileId;
  4632. }
  4633. else if (m_func->HasArrayInfo())
  4634. {
  4635. instr = IR::ProfiledInstr::New(newOpcode, dstOpnd, src1Opnd, m_func);
  4636. instr->AsProfiledInstr()->u.profileId = profileId;
  4637. arrayInfo = m_func->GetReadOnlyProfileInfo()->GetArrayCallSiteInfo(profileId);
  4638. if (arrayInfo && !m_func->IsJitInDebugMode())
  4639. {
  4640. if (arrayInfo->IsNativeIntArray())
  4641. {
  4642. arrayTypeId = Js::TypeIds_NativeIntArray;
  4643. }
  4644. else if (arrayInfo->IsNativeFloatArray())
  4645. {
  4646. arrayTypeId = Js::TypeIds_NativeFloatArray;
  4647. }
  4648. }
  4649. }
  4650. else
  4651. {
  4652. instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, m_func);
  4653. }
  4654. ValueType dstValueType(
  4655. ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(true).SetArrayTypeId(arrayTypeId));
  4656. if (dstValueType.IsLikelyNativeArray())
  4657. {
  4658. dstOpnd->SetValueType(dstValueType.ToLikely());
  4659. }
  4660. else
  4661. {
  4662. dstOpnd->SetValueType(dstValueType);
  4663. dstOpnd->SetValueTypeFixed();
  4664. }
  4665. StackSym *dstSym = dstOpnd->AsRegOpnd()->m_sym;
  4666. if (dstSym->m_isSingleDef)
  4667. {
  4668. dstSym->m_isSafeThis = true;
  4669. dstSym->m_isNotNumber = true;
  4670. }
  4671. this->AddInstr(instr, offset);
  4672. break;
  4673. }
  4674. case Js::OpCode::ProfiledNewScFltArray:
  4675. {
  4676. Js::ProfileId profileId = static_cast<Js::ProfileId>(auxInsn->profileId);
  4677. IR::RegOpnd* dstOpnd;
  4678. IR::Opnd* src1Opnd;
  4679. src1Opnd = this->BuildAuxArrayOpnd(AuxArrayValue::AuxFloatArray, auxInsn->Offset);
  4680. dstOpnd = this->BuildDstOpnd(auxInsn->R0);
  4681. Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
  4682. IR::Instr *instr;
  4683. Js::ArrayCallSiteInfo *arrayInfo = nullptr;
  4684. if (m_func->DoSimpleJitDynamicProfile())
  4685. {
  4686. instr = IR::JitProfilingInstr::New(newOpcode, dstOpnd, src1Opnd, m_func);
  4687. instr->AsJitProfilingInstr()->profileId = profileId;
  4688. // Keep arrayInfo null because we aren't using profile data in profiling simplejit
  4689. }
  4690. else
  4691. {
  4692. instr = IR::ProfiledInstr::New(newOpcode, dstOpnd, src1Opnd, m_func);
  4693. instr->AsProfiledInstr()->u.profileId = profileId;
  4694. if (m_func->HasArrayInfo()) {
  4695. arrayInfo = m_func->GetReadOnlyProfileInfo()->GetArrayCallSiteInfo(profileId);
  4696. }
  4697. }
  4698. Js::TypeId arrayTypeId;
  4699. if (arrayInfo && arrayInfo->IsNativeFloatArray())
  4700. {
  4701. arrayTypeId = Js::TypeIds_NativeFloatArray;
  4702. }
  4703. else
  4704. {
  4705. arrayTypeId = Js::TypeIds_Array;
  4706. }
  4707. ValueType dstValueType(
  4708. ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(true).SetArrayTypeId(arrayTypeId));
  4709. if (dstValueType.IsLikelyNativeArray())
  4710. {
  4711. dstOpnd->SetValueType(dstValueType.ToLikely());
  4712. }
  4713. else
  4714. {
  4715. dstOpnd->SetValueType(dstValueType);
  4716. dstOpnd->SetValueTypeFixed();
  4717. }
  4718. StackSym *dstSym = dstOpnd->AsRegOpnd()->m_sym;
  4719. if (dstSym->m_isSingleDef)
  4720. {
  4721. dstSym->m_isSafeThis = true;
  4722. dstSym->m_isNotNumber = true;
  4723. }
  4724. this->AddInstr(instr, offset);
  4725. break;
  4726. }
  4727. default:
  4728. {
  4729. AssertMsg(UNREACHED, "Unknown Auxiliary opcode");
  4730. Fatal();
  4731. break;
  4732. }
  4733. }
  4734. }
  4735. ///----------------------------------------------------------------------------
  4736. ///
  4737. /// IRBuilder::BuildReg2Aux
  4738. ///
  4739. /// Build IR instr for a Reg2Aux instruction.
  4740. ///
  4741. ///----------------------------------------------------------------------------
  4742. void IRBuilder::BuildInitCachedScope(int auxOffset, int offset)
  4743. {
  4744. IR::Instr * instr;
  4745. IR::RegOpnd * dstOpnd;
  4746. IR::RegOpnd * src1Opnd;
  4747. IR::AddrOpnd * src2Opnd;
  4748. IR::Opnd* src3Opnd;
  4749. IR::Opnd* formalsAreLetDeclOpnd;
  4750. src2Opnd = IR::AddrOpnd::New(m_func->GetJITFunctionBody()->GetFormalsPropIdArrayAddr(), IR::AddrOpndKindDynamicMisc, m_func);
  4751. Js::PropertyIdArray * propIds = m_func->GetJITFunctionBody()->GetFormalsPropIdArray();
  4752. src3Opnd = this->BuildAuxObjectLiteralTypeRefOpnd(Js::ActivationObjectEx::GetLiteralObjectRef(propIds));
  4753. dstOpnd = this->BuildDstOpnd(m_func->GetJITFunctionBody()->GetLocalClosureReg());
  4754. formalsAreLetDeclOpnd = IR::IntConstOpnd::New(propIds->hasNonSimpleParams, TyUint8, m_func);
  4755. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), formalsAreLetDeclOpnd, m_func);
  4756. this->AddInstr(instr, offset);
  4757. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), src3Opnd, instr->GetDst(), m_func);
  4758. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  4759. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), src2Opnd, instr->GetDst(), m_func);
  4760. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  4761. // Disable opt that normally gets disabled when we see LdFuncExpr in the byte code.
  4762. m_func->DisableCanDoInlineArgOpt();
  4763. src1Opnd = IR::RegOpnd::New(TyVar, m_func);
  4764. IR::Instr * instrLdFuncExpr = IR::Instr::New(Js::OpCode::LdFuncExpr, src1Opnd, m_func);
  4765. this->AddInstr(instrLdFuncExpr, Js::Constants::NoByteCodeOffset);
  4766. instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), src1Opnd, instr->GetDst(), m_func);
  4767. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  4768. instr = IR::Instr::New(Js::OpCode::InitCachedScope, dstOpnd, instr->GetDst(), m_func);
  4769. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  4770. }
  4771. void
  4772. IRBuilder::BuildReg2Aux(Js::OpCode newOpcode, uint32 offset)
  4773. {
  4774. Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4775. const unaligned Js::OpLayoutReg2Aux *auxInsn = m_jnReader.Reg2Aux();
  4776. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  4777. {
  4778. this->DoClosureRegCheck(auxInsn->R0);
  4779. this->DoClosureRegCheck(auxInsn->R1);
  4780. }
  4781. IR::Instr *instr;
  4782. switch (newOpcode)
  4783. {
  4784. case Js::OpCode::SpreadArrayLiteral:
  4785. {
  4786. IR::RegOpnd * dstOpnd;
  4787. IR::RegOpnd * src1Opnd;
  4788. IR::Opnd* src2Opnd;
  4789. Js::RegSlot dstRegSlot = auxInsn->R0;
  4790. Js::RegSlot srcRegSlot = auxInsn->R1;
  4791. src1Opnd = this->BuildSrcOpnd(srcRegSlot);
  4792. src2Opnd = this->BuildAuxArrayOpnd(AuxArrayValue::AuxIntArray, auxInsn->Offset);
  4793. dstOpnd = this->BuildDstOpnd(dstRegSlot);
  4794. instr = IR::Instr::New(Js::OpCode::SpreadArrayLiteral, dstOpnd, src1Opnd, src2Opnd, m_func);
  4795. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  4796. if (dstOpnd->m_sym->m_isSingleDef)
  4797. {
  4798. dstOpnd->m_sym->m_isNotNumber = true;
  4799. }
  4800. break;
  4801. }
  4802. default:
  4803. {
  4804. AssertMsg(UNREACHED, "Unknown Reg2Aux opcode");
  4805. Fatal();
  4806. break;
  4807. }
  4808. }
  4809. }
  4810. ///----------------------------------------------------------------------------
  4811. ///
  4812. /// IRBuilder::BuildElementI
  4813. ///
  4814. /// Build IR instr for an ElementI instruction.
  4815. ///
  4816. ///----------------------------------------------------------------------------
  4817. template <typename SizePolicy>
  4818. void
  4819. IRBuilder::BuildElementI(Js::OpCode newOpcode, uint32 offset)
  4820. {
  4821. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  4822. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4823. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementI<SizePolicy>>();
  4824. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  4825. {
  4826. this->DoClosureRegCheck(layout->Value);
  4827. this->DoClosureRegCheck(layout->Instance);
  4828. this->DoClosureRegCheck(layout->Element);
  4829. }
  4830. BuildElementI(newOpcode, offset, layout->Instance, layout->Element, layout->Value, Js::Constants::NoProfileId);
  4831. }
  4832. template <typename SizePolicy>
  4833. void
  4834. IRBuilder::BuildProfiledElementI(Js::OpCode newOpcode, uint32 offset)
  4835. {
  4836. Assert(OpCodeAttr::IsProfiledOp(newOpcode));
  4837. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4838. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_ElementI<SizePolicy>>>();
  4839. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  4840. {
  4841. this->DoClosureRegCheck(layout->Value);
  4842. this->DoClosureRegCheck(layout->Instance);
  4843. this->DoClosureRegCheck(layout->Element);
  4844. }
  4845. Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
  4846. BuildElementI(newOpcode, offset, layout->Instance, layout->Element, layout->Value, layout->profileId);
  4847. }
  4848. void
  4849. IRBuilder::BuildElementI(Js::OpCode newOpcode, uint32 offset, Js::RegSlot baseRegSlot, Js::RegSlot indexRegSlot,
  4850. Js::RegSlot regSlot, Js::ProfileId profileId)
  4851. {
  4852. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4853. ValueType arrayType;
  4854. const Js::LdElemInfo *ldElemInfo = nullptr;
  4855. const Js::StElemInfo *stElemInfo = nullptr;
  4856. bool isProfiledLoad = false;
  4857. bool isProfiledStore = false;
  4858. bool isProfiledInstr = (profileId != Js::Constants::NoProfileId);
  4859. bool isLdElemOrStElemThatWasNotProfiled = false;
  4860. if (isProfiledInstr)
  4861. {
  4862. switch (newOpcode)
  4863. {
  4864. case Js::OpCode::LdElemI_A:
  4865. if (!DoLoadInstructionArrayProfileInfo())
  4866. {
  4867. break;
  4868. }
  4869. ldElemInfo = this->m_func->GetReadOnlyProfileInfo()->GetLdElemInfo(profileId);
  4870. arrayType = ldElemInfo->GetArrayType();
  4871. isLdElemOrStElemThatWasNotProfiled = !ldElemInfo->WasProfiled();
  4872. isProfiledLoad = true;
  4873. break;
  4874. case Js::OpCode::StElemI_A:
  4875. case Js::OpCode::StElemI_A_Strict:
  4876. if (!DoLoadInstructionArrayProfileInfo())
  4877. {
  4878. break;
  4879. }
  4880. isProfiledStore = true;
  4881. stElemInfo = this->m_func->GetReadOnlyProfileInfo()->GetStElemInfo(profileId);
  4882. arrayType = stElemInfo->GetArrayType();
  4883. isLdElemOrStElemThatWasNotProfiled = !stElemInfo->WasProfiled();
  4884. break;
  4885. }
  4886. }
  4887. IR::Instr * instr;
  4888. IR::RegOpnd * regOpnd;
  4889. IR::IndirOpnd * indirOpnd;
  4890. indirOpnd = this->BuildIndirOpnd(this->BuildSrcOpnd(baseRegSlot), this->BuildSrcOpnd(indexRegSlot));
  4891. if (isProfiledLoad || isProfiledStore)
  4892. {
  4893. if(arrayType.IsLikelyNativeArray() && !AllowNativeArrayProfileInfo())
  4894. {
  4895. arrayType = arrayType.SetArrayTypeId(Js::TypeIds_Array);
  4896. // An opnd's value type will get replaced in the forward phase when it is not fixed. Store the array type in the
  4897. // ProfiledInstr.
  4898. if(isProfiledLoad)
  4899. {
  4900. Js::LdElemInfo *const newLdElemInfo = JitAnew(m_func->m_alloc, Js::LdElemInfo, *ldElemInfo);
  4901. newLdElemInfo->arrayType = arrayType;
  4902. ldElemInfo = newLdElemInfo;
  4903. }
  4904. else
  4905. {
  4906. Js::StElemInfo *const newStElemInfo = JitAnew(m_func->m_alloc, Js::StElemInfo, *stElemInfo);
  4907. newStElemInfo->arrayType = arrayType;
  4908. stElemInfo = newStElemInfo;
  4909. }
  4910. }
  4911. indirOpnd->GetBaseOpnd()->SetValueType(arrayType);
  4912. if (m_func->GetTopFunc()->HasTry() && !m_func->GetTopFunc()->DoOptimizeTry())
  4913. {
  4914. isProfiledLoad = false;
  4915. isProfiledStore = false;
  4916. }
  4917. }
  4918. switch (newOpcode)
  4919. {
  4920. case Js::OpCode::LdMethodElem:
  4921. case Js::OpCode::LdElemI_A:
  4922. case Js::OpCode::DeleteElemI_A:
  4923. case Js::OpCode::DeleteElemIStrict_A:
  4924. case Js::OpCode::TypeofElem:
  4925. {
  4926. // Evaluate to register
  4927. regOpnd = this->BuildDstOpnd(regSlot);
  4928. if (m_func->DoSimpleJitDynamicProfile() && isProfiledInstr)
  4929. {
  4930. instr = IR::JitProfilingInstr::New(newOpcode, regOpnd, indirOpnd, m_func);
  4931. instr->AsJitProfilingInstr()->profileId = profileId;
  4932. }
  4933. else if (isProfiledLoad)
  4934. {
  4935. instr = IR::ProfiledInstr::New(newOpcode, regOpnd, indirOpnd, m_func);
  4936. instr->AsProfiledInstr()->u.ldElemInfo = ldElemInfo;
  4937. }
  4938. else
  4939. {
  4940. instr = IR::Instr::New(newOpcode, regOpnd, indirOpnd, m_func);
  4941. }
  4942. break;
  4943. }
  4944. case Js::OpCode::StElemI_A:
  4945. case Js::OpCode::StElemI_A_Strict:
  4946. {
  4947. // Store
  4948. regOpnd = this->BuildSrcOpnd(regSlot);
  4949. if (m_func->DoSimpleJitDynamicProfile() && isProfiledInstr)
  4950. {
  4951. instr = IR::JitProfilingInstr::New(newOpcode, indirOpnd, regOpnd, m_func);
  4952. instr->AsJitProfilingInstr()->profileId = profileId;
  4953. }
  4954. else if (isProfiledStore)
  4955. {
  4956. instr = IR::ProfiledInstr::New(newOpcode, indirOpnd, regOpnd, m_func);
  4957. instr->AsProfiledInstr()->u.stElemInfo = stElemInfo;
  4958. }
  4959. else
  4960. {
  4961. instr = IR::Instr::New(newOpcode, indirOpnd, regOpnd, m_func);
  4962. }
  4963. break;
  4964. }
  4965. case Js::OpCode::InitSetElemI:
  4966. case Js::OpCode::InitGetElemI:
  4967. case Js::OpCode::InitComputedProperty:
  4968. case Js::OpCode::InitClassMemberComputedName:
  4969. case Js::OpCode::InitClassMemberGetComputedName:
  4970. case Js::OpCode::InitClassMemberSetComputedName:
  4971. {
  4972. regOpnd = this->BuildSrcOpnd(regSlot);
  4973. instr = IR::Instr::New(newOpcode, indirOpnd, regOpnd, m_func);
  4974. break;
  4975. }
  4976. default:
  4977. AssertMsg(false, "Unknown ElementI opcode");
  4978. return;
  4979. }
  4980. this->AddInstr(instr, offset);
  4981. if(isLdElemOrStElemThatWasNotProfiled && DoBailOnNoProfile())
  4982. {
  4983. InsertBailOnNoProfile(instr);
  4984. }
  4985. }
  4986. ///----------------------------------------------------------------------------
  4987. ///
  4988. /// IRBuilder::BuildElementUnsigned1
  4989. ///
  4990. /// Build IR instr for an ElementUnsigned1 instruction.
  4991. ///
  4992. ///----------------------------------------------------------------------------
  4993. template <typename SizePolicy>
  4994. void
  4995. IRBuilder::BuildElementUnsigned1(Js::OpCode newOpcode, uint32 offset)
  4996. {
  4997. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  4998. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  4999. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementUnsigned1<SizePolicy>>();
  5000. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5001. {
  5002. this->DoClosureRegCheck(layout->Value);
  5003. this->DoClosureRegCheck(layout->Instance);
  5004. }
  5005. BuildElementUnsigned1(newOpcode, offset, layout->Instance, layout->Element, layout->Value);
  5006. }
  5007. void
  5008. IRBuilder::BuildElementUnsigned1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot baseRegSlot, uint32 index, Js::RegSlot regSlot)
  5009. {
  5010. // This is an array-style access with a constant (integer) index.
  5011. // Embed the index in the indir opnd as a constant offset.
  5012. IR::Instr * instr;
  5013. const bool simpleJit = m_func->DoSimpleJitDynamicProfile();
  5014. IR::RegOpnd * regOpnd;
  5015. IR::IndirOpnd * indirOpnd;
  5016. IR::RegOpnd * baseOpnd;
  5017. Js::OpCode opcode;
  5018. switch (newOpcode)
  5019. {
  5020. case Js::OpCode::StArrItemI_CI4:
  5021. {
  5022. baseOpnd = this->BuildSrcOpnd(baseRegSlot);
  5023. // This instruction must not create missing values in the array
  5024. baseOpnd->SetValueType(
  5025. ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(false).SetArrayTypeId(Js::TypeIds_Array));
  5026. baseOpnd->SetValueTypeFixed();
  5027. // In the case of simplejit, we won't know the exact type of array used until run time. Due to this,
  5028. // we must use the specialized version of StElemC in Lowering.
  5029. opcode = simpleJit ? Js::OpCode::StElemC : Js::OpCode::StElemI_A;
  5030. break;
  5031. }
  5032. case Js::OpCode::StArrItemC_CI4:
  5033. {
  5034. baseOpnd = IR::RegOpnd::New(TyVar, m_func);
  5035. // Insert LdArrHead as the next instr and clear the offset to avoid duplication.
  5036. IR::RegOpnd *const arrayOpnd = this->BuildSrcOpnd(baseRegSlot);
  5037. // This instruction must not create missing values in the array
  5038. arrayOpnd->SetValueType(
  5039. ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(false).SetArrayTypeId(Js::TypeIds_Array));
  5040. arrayOpnd->SetValueTypeFixed();
  5041. this->AddInstr(IR::Instr::New(Js::OpCode::LdArrHead, baseOpnd, arrayOpnd, m_func), offset);
  5042. offset = Js::Constants::NoByteCodeOffset;
  5043. opcode = Js::OpCode::StArrSegElemC;
  5044. break;
  5045. }
  5046. case Js::OpCode::StArrSegItem_CI4:
  5047. {
  5048. baseOpnd = this->BuildSrcOpnd(baseRegSlot, TyVar);
  5049. // This instruction must not create missing values in the array
  5050. opcode = Js::OpCode::StArrSegElemC;
  5051. break;
  5052. }
  5053. case Js::OpCode::StArrInlineItem_CI4:
  5054. {
  5055. baseOpnd = this->BuildSrcOpnd(baseRegSlot);
  5056. IR::Opnd *defOpnd = baseOpnd->m_sym->m_instrDef ? baseOpnd->m_sym->m_instrDef->GetDst() : nullptr;
  5057. if (!defOpnd)
  5058. {
  5059. // The array sym may be multi-def because of oddness in the renumbering of temps -- for instance,
  5060. // if there's a loop increment expression whose result is unused (ExprGen only, probably).
  5061. FOREACH_INSTR_BACKWARD(tmpInstr, m_func->m_exitInstr->m_prev)
  5062. {
  5063. if (tmpInstr->GetDst())
  5064. {
  5065. if (tmpInstr->GetDst()->IsEqual(baseOpnd))
  5066. {
  5067. defOpnd = tmpInstr->GetDst();
  5068. break;
  5069. }
  5070. else if (tmpInstr->m_opcode == Js::OpCode::StElemC &&
  5071. tmpInstr->GetDst()->AsIndirOpnd()->GetBaseOpnd()->IsEqual(baseOpnd))
  5072. {
  5073. defOpnd = tmpInstr->GetDst()->AsIndirOpnd()->GetBaseOpnd();
  5074. break;
  5075. }
  5076. }
  5077. }
  5078. NEXT_INSTR_BACKWARD;
  5079. }
  5080. AnalysisAssert(defOpnd);
  5081. // This instruction must not create missing values in the array
  5082. baseOpnd->SetValueType(defOpnd->GetValueType());
  5083. opcode = Js::OpCode::StElemC;
  5084. break;
  5085. }
  5086. default:
  5087. AssertMsg(false, "Unknown ElementUnsigned1 opcode");
  5088. return;
  5089. }
  5090. indirOpnd = this->BuildIndirOpnd(baseOpnd, index);
  5091. regOpnd = this->BuildSrcOpnd(regSlot);
  5092. if (simpleJit)
  5093. {
  5094. instr = IR::JitProfilingInstr::New(opcode, indirOpnd, regOpnd, m_func);
  5095. }
  5096. else if(opcode == Js::OpCode::StElemC && !baseOpnd->GetValueType().IsUninitialized())
  5097. {
  5098. // An opnd's value type will get replaced in the forward phase when it is not fixed. Store the array type in the
  5099. // ProfiledInstr.
  5100. IR::ProfiledInstr *const profiledInstr = IR::ProfiledInstr::New(opcode, indirOpnd, regOpnd, m_func);
  5101. Js::StElemInfo *const stElemInfo = JitAnew(m_func->m_alloc, Js::StElemInfo);
  5102. stElemInfo->arrayType = baseOpnd->GetValueType();
  5103. profiledInstr->u.stElemInfo = stElemInfo;
  5104. instr = profiledInstr;
  5105. }
  5106. else
  5107. {
  5108. instr = IR::Instr::New(opcode, indirOpnd, regOpnd, m_func);
  5109. }
  5110. this->AddInstr(instr, offset);
  5111. }
  5112. ///----------------------------------------------------------------------------
  5113. ///
  5114. /// IRBuilder::BuildArgIn
  5115. ///
  5116. /// Build IR instr for an ArgIn instruction.
  5117. ///
  5118. ///----------------------------------------------------------------------------
  5119. void
  5120. IRBuilder::BuildArgIn0(uint32 offset, Js::RegSlot dstRegSlot)
  5121. {
  5122. Assert(OpCodeAttr::HasMultiSizeLayout(Js::OpCode::ArgIn0));
  5123. BuildArgIn(offset, dstRegSlot, 0);
  5124. }
  5125. void
  5126. IRBuilder::BuildArgIn(uint32 offset, Js::RegSlot dstRegSlot, uint16 argument)
  5127. {
  5128. IR::Instr * instr;
  5129. IR::SymOpnd * srcOpnd;
  5130. IR::RegOpnd * dstOpnd;
  5131. StackSym * symSrc = StackSym::NewParamSlotSym(argument + 1, m_func);
  5132. this->m_func->SetArgOffset(symSrc, (argument + LowererMD::GetFormalParamOffset()) * MachPtr);
  5133. srcOpnd = IR::SymOpnd::New(symSrc, TyVar, m_func);
  5134. dstOpnd = this->BuildDstOpnd(dstRegSlot);
  5135. if (!this->m_func->IsLoopBody() && this->m_func->HasProfileInfo())
  5136. {
  5137. // Skip "this" pointer; "this" profile data is captured by ProfiledLdThis.
  5138. // Subtract 1 to skip "this" pointer, subtract 1 again to get the index to index into profileData->parameterInfo.
  5139. int paramSlotIndex = symSrc->GetParamSlotNum() - 2;
  5140. if (paramSlotIndex >= 0)
  5141. {
  5142. ValueType profiledValueType;
  5143. profiledValueType = this->m_func->GetReadOnlyProfileInfo()->GetParameterInfo(static_cast<Js::ArgSlot>(paramSlotIndex));
  5144. dstOpnd->SetValueType(profiledValueType);
  5145. }
  5146. }
  5147. instr = IR::Instr::New(Js::OpCode::ArgIn_A, dstOpnd, srcOpnd, m_func);
  5148. this->AddInstr(instr, offset);
  5149. }
  5150. void
  5151. IRBuilder::BuildArgInRest()
  5152. {
  5153. IR::RegOpnd * dstOpnd = this->BuildDstOpnd(m_func->GetJITFunctionBody()->GetRestParamRegSlot());
  5154. IR::Instr *instr = IR::Instr::New(Js::OpCode::ArgIn_Rest, dstOpnd, m_func);
  5155. this->AddInstr(instr, (uint32)-1);
  5156. }
  5157. ///----------------------------------------------------------------------------
  5158. ///
  5159. /// IRBuilder::BuildArg
  5160. ///
  5161. /// Build IR instr for an ArgOut instruction.
  5162. ///
  5163. ///----------------------------------------------------------------------------
  5164. template <typename SizePolicy>
  5165. void
  5166. IRBuilder::BuildArgNoSrc(Js::OpCode newOpcode, uint32 offset)
  5167. {
  5168. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  5169. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5170. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ArgNoSrc<SizePolicy>>();
  5171. BuildArg(Js::OpCode::ArgOut_A, offset, layout->Arg, this->GetEnvRegForInnerFrameDisplay());
  5172. }
  5173. template <typename SizePolicy>
  5174. void
  5175. IRBuilder::BuildArg(Js::OpCode newOpcode, uint32 offset)
  5176. {
  5177. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  5178. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5179. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Arg<SizePolicy>>();
  5180. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5181. {
  5182. this->DoClosureRegCheck(layout->Reg);
  5183. }
  5184. BuildArg(newOpcode, offset, layout->Arg, layout->Reg);
  5185. }
  5186. template <typename SizePolicy>
  5187. void
  5188. IRBuilder::BuildProfiledArg(Js::OpCode newOpcode, uint32 offset)
  5189. {
  5190. Assert(OpCodeAttr::IsProfiledOp(newOpcode));
  5191. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5192. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_Arg<SizePolicy>>>();
  5193. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5194. {
  5195. this->DoClosureRegCheck(layout->Reg);
  5196. }
  5197. newOpcode = Js::OpCode::ArgOut_A;
  5198. BuildArg(newOpcode, offset, layout->Arg, layout->Reg);
  5199. }
  5200. void
  5201. IRBuilder::BuildArg(Js::OpCode newOpcode, uint32 offset, Js::ArgSlot argument, Js::RegSlot srcRegSlot)
  5202. {
  5203. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5204. IR::Instr * instr;
  5205. IRType type = TyVar;
  5206. if (newOpcode == Js::OpCode::ArgOut_ANonVar)
  5207. {
  5208. newOpcode = Js::OpCode::ArgOut_A;
  5209. type = TyMachPtr;
  5210. }
  5211. m_argsOnStack++;
  5212. StackSym * symDst;
  5213. Assert(argument < USHRT_MAX);
  5214. symDst = m_func->m_symTable->GetArgSlotSym((uint16)(argument+1));
  5215. if (symDst == nullptr || (uint16)(argument + 1) != (argument + 1))
  5216. {
  5217. AssertMsg(UNREACHED, "Arg count too big...");
  5218. Fatal();
  5219. }
  5220. IR::SymOpnd * dstOpnd = IR::SymOpnd::New(symDst, type, m_func);
  5221. IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(srcRegSlot, type);
  5222. instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, m_func);
  5223. this->AddInstr(instr, offset);
  5224. m_argStack->Push(instr);
  5225. }
  5226. ///----------------------------------------------------------------------------
  5227. ///
  5228. /// IRBuilder::BuildStartCall
  5229. ///
  5230. /// Build IR instr for a StartCall instruction.
  5231. ///
  5232. ///----------------------------------------------------------------------------
  5233. void
  5234. IRBuilder::BuildStartCall(Js::OpCode newOpcode, uint32 offset)
  5235. {
  5236. Assert(newOpcode == Js::OpCode::StartCall);
  5237. const unaligned Js::OpLayoutStartCall * regLayout = m_jnReader.StartCall();
  5238. Js::ArgSlot ArgCount = regLayout->ArgCount;
  5239. IR::Instr * instr;
  5240. IR::RegOpnd * dstOpnd;
  5241. // Dst of StartCall is always r0... Let's give it a new dst such that it can
  5242. // be singleDef.
  5243. dstOpnd = IR::RegOpnd::New(TyVar, m_func);
  5244. #if DBG
  5245. m_callsOnStack++;
  5246. #endif
  5247. IntConstType value = ArgCount;
  5248. IR::IntConstOpnd * srcOpnd;
  5249. srcOpnd = IR::IntConstOpnd::New(value, TyInt32, m_func);
  5250. instr = IR::Instr::New(newOpcode, dstOpnd, srcOpnd, m_func);
  5251. this->AddInstr(instr, offset);
  5252. // Keep a stack of arg instructions such that we can link them up once we see
  5253. // the call that consumes them.
  5254. m_argStack->Push(instr);
  5255. }
  5256. ///----------------------------------------------------------------------------
  5257. ///
  5258. /// IRBuilder::BuildCallI
  5259. ///
  5260. /// Build IR instr for a CallI instruction.
  5261. ///
  5262. ///----------------------------------------------------------------------------
  5263. template <typename SizePolicy>
  5264. void
  5265. IRBuilder::BuildCallI(Js::OpCode newOpcode, uint32 offset)
  5266. {
  5267. Assert(Js::OpCodeUtil::IsCallOp(newOpcode) || newOpcode == Js::OpCode::NewScObject || newOpcode == Js::OpCode::NewScObjArray);
  5268. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5269. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_CallI<SizePolicy>>();
  5270. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5271. {
  5272. this->DoClosureRegCheck(layout->Return);
  5273. this->DoClosureRegCheck(layout->Function);
  5274. }
  5275. BuildCallI_Helper(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, Js::Constants::NoProfileId);
  5276. }
  5277. template <typename SizePolicy>
  5278. void
  5279. IRBuilder::BuildCallIFlags(Js::OpCode newOpcode, uint32 offset)
  5280. {
  5281. Assert(Js::OpCodeUtil::IsCallOp(newOpcode) || newOpcode == Js::OpCode::NewScObject || newOpcode == Js::OpCode::NewScObjArray);
  5282. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5283. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_CallIFlags<SizePolicy>>();
  5284. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5285. {
  5286. this->DoClosureRegCheck(layout->Return);
  5287. this->DoClosureRegCheck(layout->Function);
  5288. }
  5289. IR::Instr* instr = BuildCallI_Helper(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, Js::Constants::NoProfileId, layout->callFlags);
  5290. Assert(instr->m_opcode == Js::OpCode::CallIFlags);
  5291. if (instr->m_opcode == Js::OpCode::CallIFlags)
  5292. {
  5293. instr->m_opcode =
  5294. layout->callFlags == (Js::CallFlags::CallFlags_NewTarget | Js::CallFlags::CallFlags_New | Js::CallFlags::CallFlags_ExtraArg) ? Js::OpCode::CallINewTargetNew :
  5295. layout->callFlags == Js::CallFlags::CallFlags_New ? Js::OpCode::CallINew :
  5296. instr->m_opcode;
  5297. }
  5298. }
  5299. void IRBuilder::BuildLdSpreadIndices(uint32 offset, uint32 spreadAuxOffset)
  5300. {
  5301. // Link up the LdSpreadIndices instr to be the first in the arg chain. This will allow us to find it in Lowerer easier.
  5302. IR::Opnd *auxArg = this->BuildAuxArrayOpnd(AuxArrayValue::AuxIntArray, spreadAuxOffset);
  5303. IR::Instr *instr = IR::Instr::New(Js::OpCode::LdSpreadIndices, m_func);
  5304. instr->SetSrc1(auxArg);
  5305. // Create the link to the first arg.
  5306. Js::RegSlot lastArg = m_argStack->Head()->GetDst()->AsSymOpnd()->GetStackSym()->GetArgSlotNum();
  5307. instr->SetDst(IR::SymOpnd::New(m_func->m_symTable->GetArgSlotSym((uint16) (lastArg + 1)), TyVar, m_func));
  5308. this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
  5309. m_argStack->Push(instr);
  5310. }
  5311. template <typename SizePolicy>
  5312. void
  5313. IRBuilder::BuildCallIExtended(Js::OpCode newOpcode, uint32 offset)
  5314. {
  5315. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5316. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_CallIExtended<SizePolicy>>();
  5317. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5318. {
  5319. this->DoClosureRegCheck(layout->Return);
  5320. this->DoClosureRegCheck(layout->Function);
  5321. }
  5322. BuildCallIExtended(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->Options, layout->SpreadAuxOffset);
  5323. }
  5324. IR::Instr*
  5325. IRBuilder::BuildCallIExtended(Js::OpCode newOpcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
  5326. Js::ArgSlot argCount, Js::CallIExtendedOptions options, uint32 spreadAuxOffset, Js::CallFlags flags)
  5327. {
  5328. if (options & Js::CallIExtended_SpreadArgs)
  5329. {
  5330. BuildLdSpreadIndices(offset, spreadAuxOffset);
  5331. }
  5332. return BuildCallI_Helper(newOpcode, offset, returnValue, function, argCount, Js::Constants::NoProfileId, flags);
  5333. }
  5334. template <typename SizePolicy>
  5335. void
  5336. IRBuilder::BuildCallIWithICIndex(Js::OpCode newOpcode, uint32 offset)
  5337. {
  5338. AssertMsg(false, "NYI");
  5339. }
  5340. template <typename SizePolicy>
  5341. void
  5342. IRBuilder::BuildCallIFlagsWithICIndex(Js::OpCode newOpcode, uint32 offset)
  5343. {
  5344. AssertMsg(false, "NYI");
  5345. }
  5346. template <typename SizePolicy>
  5347. void
  5348. IRBuilder::BuildCallIExtendedFlags(Js::OpCode newOpcode, uint32 offset)
  5349. {
  5350. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5351. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_CallIExtendedFlags<SizePolicy>>();
  5352. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5353. {
  5354. this->DoClosureRegCheck(layout->Return);
  5355. this->DoClosureRegCheck(layout->Function);
  5356. }
  5357. IR::Instr* instr = BuildCallIExtended(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->Options, layout->SpreadAuxOffset, layout->callFlags);
  5358. Assert(instr->m_opcode == Js::OpCode::CallIExtendedFlags);
  5359. if (instr->m_opcode == Js::OpCode::CallIExtendedFlags)
  5360. {
  5361. instr->m_opcode =
  5362. layout->callFlags == Js::CallFlags::CallFlags_ExtraArg ? Js::OpCode::CallIEval :
  5363. layout->callFlags == Js::CallFlags::CallFlags_New ? Js::OpCode::CallIExtendedNew :
  5364. layout->callFlags == (Js::CallFlags::CallFlags_New | Js::CallFlags::CallFlags_ExtraArg | Js::CallFlags::CallFlags_NewTarget) ? Js::OpCode::CallIExtendedNewTargetNew :
  5365. instr->m_opcode;
  5366. }
  5367. }
  5368. template <typename SizePolicy>
  5369. void
  5370. IRBuilder::BuildCallIExtendedWithICIndex(Js::OpCode newOpcode, uint32 offset)
  5371. {
  5372. AssertMsg(false, "NYI");
  5373. }
  5374. template <typename SizePolicy>
  5375. void
  5376. IRBuilder::BuildCallIExtendedFlagsWithICIndex(Js::OpCode newOpcode, uint32 offset)
  5377. {
  5378. AssertMsg(false, "NYI");
  5379. }
  5380. template <typename SizePolicy>
  5381. void
  5382. IRBuilder::BuildProfiledCallIFlagsWithICIndex(Js::OpCode newOpcode, uint32 offset)
  5383. {
  5384. Assert(OpCodeAttr::IsProfiledOpWithICIndex(newOpcode) || Js::OpCodeUtil::IsProfiledCallOpWithICIndex(newOpcode));
  5385. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5386. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIFlagsWithICIndex<SizePolicy>>>();
  5387. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5388. {
  5389. this->DoClosureRegCheck(layout->Return);
  5390. this->DoClosureRegCheck(layout->Function);
  5391. }
  5392. IR::Instr* instr = BuildProfiledCallIWithICIndex(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->inlineCacheIndex);
  5393. Assert(instr->m_opcode == Js::OpCode::CallIFlags);
  5394. if (instr->m_opcode == Js::OpCode::CallIFlags)
  5395. {
  5396. instr->m_opcode =
  5397. layout->callFlags == (Js::CallFlags::CallFlags_NewTarget | Js::CallFlags::CallFlags_New | Js::CallFlags::CallFlags_ExtraArg) ? Js::OpCode::CallINewTargetNew :
  5398. layout->callFlags == Js::CallFlags::CallFlags_New ? Js::OpCode::CallINew :
  5399. instr->m_opcode;
  5400. }
  5401. }
  5402. template <typename SizePolicy>
  5403. void
  5404. IRBuilder::BuildProfiledCallIWithICIndex(Js::OpCode newOpcode, uint32 offset)
  5405. {
  5406. Assert(OpCodeAttr::IsProfiledOpWithICIndex(newOpcode) || Js::OpCodeUtil::IsProfiledCallOpWithICIndex(newOpcode));
  5407. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5408. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<SizePolicy>>>();
  5409. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5410. {
  5411. this->DoClosureRegCheck(layout->Return);
  5412. this->DoClosureRegCheck(layout->Function);
  5413. }
  5414. BuildProfiledCallIWithICIndex(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->inlineCacheIndex);
  5415. }
  5416. IR::Instr*
  5417. IRBuilder::BuildProfiledCallIWithICIndex(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
  5418. Js::ArgSlot argCount, Js::ProfileId profileId, Js::InlineCacheIndex inlineCacheIndex)
  5419. {
  5420. return BuildProfiledCallI(opcode, offset, returnValue, function, argCount, profileId, Js::CallFlags_None, inlineCacheIndex);
  5421. }
  5422. template <typename SizePolicy>
  5423. void
  5424. IRBuilder::BuildProfiledCallIExtendedFlags(Js::OpCode newOpcode, uint32 offset)
  5425. {
  5426. Assert(OpCodeAttr::IsProfiledOp(newOpcode) || Js::OpCodeUtil::IsProfiledCallOp(newOpcode)
  5427. || Js::OpCodeUtil::IsProfiledReturnTypeCallOp(newOpcode));
  5428. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5429. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIExtendedFlags<SizePolicy>>>();
  5430. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5431. {
  5432. this->DoClosureRegCheck(layout->Return);
  5433. this->DoClosureRegCheck(layout->Function);
  5434. }
  5435. IR::Instr* instr = BuildProfiledCallIExtended(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->Options, layout->SpreadAuxOffset, layout->callFlags);
  5436. Assert(instr->m_opcode == Js::OpCode::CallIExtendedFlags);
  5437. if (instr->m_opcode == Js::OpCode::CallIExtendedFlags)
  5438. {
  5439. instr->m_opcode =
  5440. layout->callFlags == Js::CallFlags::CallFlags_ExtraArg ? Js::OpCode::CallIEval :
  5441. layout->callFlags == Js::CallFlags::CallFlags_New ? Js::OpCode::CallIExtendedNew :
  5442. layout->callFlags == (Js::CallFlags::CallFlags_New | Js::CallFlags::CallFlags_ExtraArg | Js::CallFlags::CallFlags_NewTarget) ? Js::OpCode::CallIExtendedNewTargetNew :
  5443. instr->m_opcode;
  5444. }
  5445. }
  5446. template <typename SizePolicy>
  5447. void
  5448. IRBuilder::BuildProfiledCallIExtendedWithICIndex(Js::OpCode newOpcode, uint32 offset)
  5449. {
  5450. Assert(OpCodeAttr::IsProfiledOpWithICIndex(newOpcode) || Js::OpCodeUtil::IsProfiledCallOpWithICIndex(newOpcode));
  5451. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5452. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIExtendedWithICIndex<SizePolicy>>>();
  5453. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5454. {
  5455. this->DoClosureRegCheck(layout->Return);
  5456. this->DoClosureRegCheck(layout->Function);
  5457. }
  5458. BuildProfiledCallIExtendedWithICIndex(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->Options, layout->SpreadAuxOffset);
  5459. }
  5460. void
  5461. IRBuilder::BuildProfiledCallIExtendedWithICIndex(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
  5462. Js::ArgSlot argCount, Js::ProfileId profileId, Js::CallIExtendedOptions options, uint32 spreadAuxOffset)
  5463. {
  5464. BuildProfiledCallIExtended(opcode, offset, returnValue, function, argCount, profileId, options, spreadAuxOffset);
  5465. }
  5466. template <typename SizePolicy>
  5467. void
  5468. IRBuilder::BuildProfiledCallIExtendedFlagsWithICIndex(Js::OpCode newOpcode, uint32 offset)
  5469. {
  5470. Assert(OpCodeAttr::IsProfiledOpWithICIndex(newOpcode) || Js::OpCodeUtil::IsProfiledCallOpWithICIndex(newOpcode));
  5471. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5472. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIExtendedFlagsWithICIndex<SizePolicy>>>();
  5473. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5474. {
  5475. this->DoClosureRegCheck(layout->Return);
  5476. this->DoClosureRegCheck(layout->Function);
  5477. }
  5478. IR::Instr* instr = BuildProfiledCallIExtended(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->Options, layout->SpreadAuxOffset);
  5479. Assert(instr->m_opcode == Js::OpCode::CallIExtendedFlags);
  5480. if (instr->m_opcode == Js::OpCode::CallIExtendedFlags)
  5481. {
  5482. instr->m_opcode =
  5483. layout->callFlags == Js::CallFlags::CallFlags_ExtraArg ? Js::OpCode::CallIEval :
  5484. layout->callFlags == Js::CallFlags::CallFlags_New ? Js::OpCode::CallIExtendedNew :
  5485. layout->callFlags == (Js::CallFlags::CallFlags_New | Js::CallFlags::CallFlags_ExtraArg | Js::CallFlags::CallFlags_NewTarget) ? Js::OpCode::CallIExtendedNewTargetNew :
  5486. instr->m_opcode;
  5487. }
  5488. }
  5489. template <typename SizePolicy>
  5490. void
  5491. IRBuilder::BuildProfiledCallI(Js::OpCode newOpcode, uint32 offset)
  5492. {
  5493. Assert(OpCodeAttr::IsProfiledOp(newOpcode) || Js::OpCodeUtil::IsProfiledCallOp(newOpcode)
  5494. || Js::OpCodeUtil::IsProfiledReturnTypeCallOp(newOpcode));
  5495. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5496. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallI<SizePolicy>>>();
  5497. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5498. {
  5499. this->DoClosureRegCheck(layout->Return);
  5500. this->DoClosureRegCheck(layout->Function);
  5501. }
  5502. BuildProfiledCallI(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId);
  5503. }
  5504. template <typename SizePolicy>
  5505. void
  5506. IRBuilder::BuildProfiledCallIFlags(Js::OpCode newOpcode, uint32 offset)
  5507. {
  5508. Assert(OpCodeAttr::IsProfiledOp(newOpcode) || Js::OpCodeUtil::IsProfiledCallOp(newOpcode)
  5509. || Js::OpCodeUtil::IsProfiledReturnTypeCallOp(newOpcode));
  5510. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5511. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIFlags<SizePolicy>>>();
  5512. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5513. {
  5514. this->DoClosureRegCheck(layout->Return);
  5515. this->DoClosureRegCheck(layout->Function);
  5516. }
  5517. IR::Instr* instr = BuildProfiledCallI(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->callFlags);
  5518. Assert(instr->m_opcode == Js::OpCode::CallIFlags);
  5519. if (instr->m_opcode == Js::OpCode::CallIFlags)
  5520. {
  5521. instr->m_opcode =
  5522. layout->callFlags == (Js::CallFlags::CallFlags_NewTarget | Js::CallFlags::CallFlags_New | Js::CallFlags::CallFlags_ExtraArg) ? Js::OpCode::CallINewTargetNew :
  5523. layout->callFlags == Js::CallFlags::CallFlags_New ? Js::OpCode::CallINew :
  5524. instr->m_opcode;
  5525. }
  5526. }
  5527. IR::Instr *
  5528. IRBuilder::BuildProfiledCallI(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
  5529. Js::ArgSlot argCount, Js::ProfileId profileId, Js::CallFlags flags, Js::InlineCacheIndex inlineCacheIndex)
  5530. {
  5531. Js::OpCode newOpcode;
  5532. ValueType returnType;
  5533. bool isProtectedByNoProfileBailout = false;
  5534. if (opcode == Js::OpCode::ProfiledNewScObject || opcode == Js::OpCode::ProfiledNewScObjectWithICIndex
  5535. || opcode == Js::OpCode::ProfiledNewScObjectSpread)
  5536. {
  5537. newOpcode = opcode;
  5538. Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
  5539. Assert(newOpcode == Js::OpCode::NewScObject || newOpcode == Js::OpCode::NewScObjectSpread);
  5540. if (!this->m_func->HasProfileInfo())
  5541. {
  5542. returnType = ValueType::GetObject(ObjectType::UninitializedObject);
  5543. }
  5544. else
  5545. {
  5546. // If we have profile data, make use of it
  5547. returnType = this->m_func->GetReadOnlyProfileInfo()->GetReturnType(opcode, profileId);
  5548. }
  5549. }
  5550. else
  5551. {
  5552. if (this->m_func->HasProfileInfo())
  5553. {
  5554. returnType = this->m_func->GetReadOnlyProfileInfo()->GetReturnType(opcode, profileId);
  5555. }
  5556. if (opcode < Js::OpCode::ProfiledReturnTypeCallI)
  5557. {
  5558. newOpcode = Js::OpCodeUtil::ConvertProfiledCallOpToNonProfiled(opcode);
  5559. if(DoBailOnNoProfile())
  5560. {
  5561. if(this->m_func->GetWorkItem()->GetJITTimeInfo())
  5562. {
  5563. const FunctionJITTimeInfo *inlinerData = this->m_func->GetWorkItem()->GetJITTimeInfo();
  5564. if (!(this->IsLoopBody() && PHASE_OFF(Js::InlineInJitLoopBodyPhase, this->m_func))
  5565. && inlinerData && inlinerData->GetInlineesBV())
  5566. {
  5567. AssertOrFailFast(profileId < inlinerData->GetInlineesBV()->Length());
  5568. if (!inlinerData->GetInlineesBV()->Test(profileId)
  5569. #if DBG
  5570. || (PHASE_STRESS(Js::BailOnNoProfilePhase, this->m_func->GetTopFunc())
  5571. && (CONFIG_FLAG(SkipFuncCountForBailOnNoProfile) < 0
  5572. || this->m_func->m_callSiteCount >= (uint)CONFIG_FLAG(SkipFuncCountForBailOnNoProfile)))
  5573. #endif
  5574. )
  5575. {
  5576. this->InsertBailOnNoProfile(offset);
  5577. isProtectedByNoProfileBailout = true;
  5578. }
  5579. }
  5580. if (!isProtectedByNoProfileBailout)
  5581. {
  5582. this->callTreeHasSomeProfileInfo = true;
  5583. }
  5584. }
  5585. #if DBG
  5586. this->m_func->m_callSiteCount++;
  5587. #endif
  5588. }
  5589. }
  5590. else
  5591. {
  5592. // Changing this opcode into a non ReturnTypeCall* opcode is done in BuildCallI_Helper
  5593. newOpcode = opcode;
  5594. }
  5595. }
  5596. IR::Instr * callInstr = BuildCallI_Helper(newOpcode, offset, returnValue, function, argCount, profileId, flags, inlineCacheIndex);
  5597. callInstr->isCallInstrProtectedByNoProfileBailout = isProtectedByNoProfileBailout;
  5598. if (callInstr->GetDst() && (callInstr->GetDst()->GetValueType().IsUninitialized() || callInstr->GetDst()->GetValueType() == ValueType::UninitializedObject))
  5599. {
  5600. callInstr->GetDst()->SetValueType(returnType);
  5601. }
  5602. return callInstr;
  5603. }
  5604. template <typename SizePolicy>
  5605. void
  5606. IRBuilder::BuildProfiledCallIExtended(Js::OpCode newOpcode, uint32 offset)
  5607. {
  5608. Assert(OpCodeAttr::IsProfiledOp(newOpcode) || Js::OpCodeUtil::IsProfiledCallOp(newOpcode)
  5609. || Js::OpCodeUtil::IsProfiledReturnTypeCallOp(newOpcode));
  5610. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5611. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIExtended<SizePolicy>>>();
  5612. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5613. {
  5614. this->DoClosureRegCheck(layout->Return);
  5615. this->DoClosureRegCheck(layout->Function);
  5616. }
  5617. BuildProfiledCallIExtended(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->Options, layout->SpreadAuxOffset);
  5618. }
  5619. IR::Instr *
  5620. IRBuilder::BuildProfiledCallIExtended(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
  5621. Js::ArgSlot argCount, Js::ProfileId profileId, Js::CallIExtendedOptions options,
  5622. uint32 spreadAuxOffset, Js::CallFlags flags)
  5623. {
  5624. if (options & Js::CallIExtended_SpreadArgs)
  5625. {
  5626. BuildLdSpreadIndices(offset, spreadAuxOffset);
  5627. }
  5628. return BuildProfiledCallI(opcode, offset, returnValue, function, argCount, profileId, flags);
  5629. }
  5630. template <typename SizePolicy>
  5631. void
  5632. IRBuilder::BuildProfiled2CallI(Js::OpCode newOpcode, uint32 offset)
  5633. {
  5634. Assert(OpCodeAttr::IsProfiledOp(newOpcode));
  5635. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5636. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile2<Js::OpLayoutT_CallI<SizePolicy>>>();
  5637. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5638. {
  5639. this->DoClosureRegCheck(layout->Return);
  5640. this->DoClosureRegCheck(layout->Function);
  5641. }
  5642. BuildProfiled2CallI(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->profileId2);
  5643. }
  5644. void
  5645. IRBuilder::BuildProfiled2CallI(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
  5646. Js::ArgSlot argCount, Js::ProfileId profileId, Js::ProfileId profileId2)
  5647. {
  5648. Assert(opcode == Js::OpCode::ProfiledNewScObjArray || opcode == Js::OpCode::ProfiledNewScObjArraySpread);
  5649. Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(opcode);
  5650. Js::OpCode useOpcode = opcode;
  5651. // We either want to provide the array profile id (profileId2) to the native array creation or the call profileid (profileId)
  5652. // to the call to NewScObject
  5653. Js::ProfileId useProfileId = profileId2;
  5654. Js::TypeId arrayTypeId = Js::TypeIds_Array;
  5655. if (returnValue != Js::Constants::NoRegister)
  5656. {
  5657. Js::ArrayCallSiteInfo *arrayCallSiteInfo = nullptr;
  5658. if (m_func->HasArrayInfo())
  5659. {
  5660. arrayCallSiteInfo = m_func->GetReadOnlyProfileInfo()->GetArrayCallSiteInfo(profileId2);
  5661. }
  5662. if (arrayCallSiteInfo && !m_func->IsJitInDebugMode())
  5663. {
  5664. if (arrayCallSiteInfo->IsNativeIntArray())
  5665. {
  5666. arrayTypeId = Js::TypeIds_NativeIntArray;
  5667. }
  5668. else if (arrayCallSiteInfo->IsNativeFloatArray())
  5669. {
  5670. arrayTypeId = Js::TypeIds_NativeFloatArray;
  5671. }
  5672. }
  5673. else
  5674. {
  5675. useOpcode = (opcode == Js::OpCode::NewScObjArraySpread) ? Js::OpCode::NewScObjectSpread : Js::OpCode::NewScObject;
  5676. useProfileId = profileId;
  5677. }
  5678. }
  5679. else
  5680. {
  5681. useOpcode = (opcode == Js::OpCode::NewScObjArraySpread) ? Js::OpCode::NewScObjectSpread : Js::OpCode::NewScObject;
  5682. useProfileId = profileId;
  5683. }
  5684. IR::Instr * callInstr = BuildCallI_Helper(useOpcode, offset, returnValue, function, argCount, useProfileId);
  5685. if (callInstr->GetDst())
  5686. {
  5687. callInstr->GetDst()->SetValueType(
  5688. ValueType::GetObject(ObjectType::Array).ToLikely().SetHasNoMissingValues(true).SetArrayTypeId(arrayTypeId));
  5689. }
  5690. if (callInstr->IsJitProfilingInstr())
  5691. {
  5692. // If we happened to decide in BuildCallI_Helper that this should be a jit profiling instr, then save the fact that it is
  5693. // a "new Array(args, ...)" call and also save the array profile id (profileId2)
  5694. callInstr->AsJitProfilingInstr()->isNewArray = true;
  5695. callInstr->AsJitProfilingInstr()->arrayProfileId = profileId2;
  5696. // Double check that this profileId made it to the JitProfilingInstr like we expect it to.
  5697. Assert(callInstr->AsJitProfilingInstr()->profileId == profileId);
  5698. }
  5699. }
  5700. template <typename SizePolicy>
  5701. void
  5702. IRBuilder::BuildProfiled2CallIExtended(Js::OpCode newOpcode, uint32 offset)
  5703. {
  5704. Assert(OpCodeAttr::IsProfiledOp(newOpcode));
  5705. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5706. auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile2<Js::OpLayoutT_CallIExtended<SizePolicy>>>();
  5707. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5708. {
  5709. this->DoClosureRegCheck(layout->Return);
  5710. this->DoClosureRegCheck(layout->Function);
  5711. }
  5712. BuildProfiled2CallIExtended(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->profileId2, layout->Options, layout->SpreadAuxOffset);
  5713. }
  5714. void
  5715. IRBuilder::BuildProfiled2CallIExtended(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
  5716. Js::ArgSlot argCount, Js::ProfileId profileId, Js::ProfileId profileId2,
  5717. Js::CallIExtendedOptions options, uint32 spreadAuxOffset)
  5718. {
  5719. if (options & Js::CallIExtended_SpreadArgs)
  5720. {
  5721. BuildLdSpreadIndices(offset, spreadAuxOffset);
  5722. }
  5723. BuildProfiled2CallI(opcode, offset, returnValue, function, argCount, profileId, profileId2);
  5724. }
  5725. IR::Instr *
  5726. IRBuilder::BuildCallI_Helper(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot Src1RegSlot, Js::ArgSlot ArgCount, Js::ProfileId profileId, Js::CallFlags flags, Js::InlineCacheIndex inlineCacheIndex)
  5727. {
  5728. IR::Instr * instr;
  5729. IR::RegOpnd * dstOpnd;
  5730. IR::RegOpnd * src1Opnd;
  5731. StackSym * symDst;
  5732. src1Opnd = this->BuildSrcOpnd(Src1RegSlot);
  5733. if (dstRegSlot == Js::Constants::NoRegister)
  5734. {
  5735. dstOpnd = nullptr;
  5736. symDst = nullptr;
  5737. }
  5738. else
  5739. {
  5740. dstOpnd = this->BuildDstOpnd(dstRegSlot);
  5741. symDst = dstOpnd->m_sym;
  5742. }
  5743. const bool jitProfiling = m_func->DoSimpleJitDynamicProfile();
  5744. bool profiledReturn = false;
  5745. if (Js::OpCodeUtil::IsProfiledReturnTypeCallOp(newOpcode))
  5746. {
  5747. profiledReturn = true;
  5748. newOpcode = Js::OpCodeUtil::ConvertProfiledReturnTypeCallOpToNonProfiled(newOpcode);
  5749. // If we're profiling in the jitted code we want to propagate the profileId
  5750. // If we're using profile data instead of collecting it, we don't want to
  5751. // use the profile data from a return type call (this was previously done in IRBuilder::BuildProfiledCallI)
  5752. if (!jitProfiling)
  5753. {
  5754. profileId = Js::Constants::NoProfileId;
  5755. }
  5756. }
  5757. if (profileId != Js::Constants::NoProfileId)
  5758. {
  5759. if (jitProfiling)
  5760. {
  5761. // In SimpleJit we want this call to be a profiled call after being jitted
  5762. instr = IR::JitProfilingInstr::New(newOpcode, dstOpnd, src1Opnd, m_func);
  5763. instr->AsJitProfilingInstr()->profileId = profileId;
  5764. instr->AsJitProfilingInstr()->isProfiledReturnCall = profiledReturn;
  5765. instr->AsJitProfilingInstr()->inlineCacheIndex = inlineCacheIndex;
  5766. }
  5767. else
  5768. {
  5769. instr = IR::ProfiledInstr::New(newOpcode, dstOpnd, src1Opnd, m_func);
  5770. instr->AsProfiledInstr()->u.profileId = profileId;
  5771. }
  5772. }
  5773. else
  5774. {
  5775. instr = IR::Instr::New(newOpcode, m_func);
  5776. instr->SetSrc1(src1Opnd);
  5777. if (dstOpnd != nullptr)
  5778. {
  5779. instr->SetDst(dstOpnd);
  5780. }
  5781. }
  5782. if (dstOpnd && newOpcode == Js::OpCode::NewScObject)
  5783. {
  5784. dstOpnd->SetValueType(ValueType::GetObject(ObjectType::UninitializedObject));
  5785. }
  5786. if (symDst && symDst->m_isSingleDef)
  5787. {
  5788. switch (instr->m_opcode)
  5789. {
  5790. case Js::OpCode::NewScObject:
  5791. case Js::OpCode::NewScObjectSpread:
  5792. case Js::OpCode::NewScObjectLiteral:
  5793. case Js::OpCode::NewScObjArray:
  5794. case Js::OpCode::NewScObjArraySpread:
  5795. symDst->m_isSafeThis = true;
  5796. symDst->m_isNotNumber = true;
  5797. break;
  5798. }
  5799. }
  5800. this->AddInstr(instr, offset);
  5801. this->BuildCallCommon(instr, symDst, ArgCount, flags);
  5802. return instr;
  5803. }
  5804. void
  5805. IRBuilder::BuildCallCommon(IR::Instr * instr, StackSym * symDst, Js::ArgSlot argCount, Js::CallFlags flags)
  5806. {
  5807. Js::OpCode newOpcode = instr->m_opcode;
  5808. IR::Instr * argInstr = nullptr;
  5809. IR::Instr * prevInstr = instr;
  5810. #if DBG
  5811. int count = 0;
  5812. #endif
  5813. // Link all the args of this call by creating a def/use chain through the src2.
  5814. AssertOrFailFast(!m_argStack->Empty());
  5815. for (argInstr = m_argStack->Pop();
  5816. argInstr && !m_argStack->Empty() && argInstr->m_opcode != Js::OpCode::StartCall;
  5817. argInstr = m_argStack->Pop())
  5818. {
  5819. prevInstr->SetSrc2(argInstr->GetDst());
  5820. prevInstr = argInstr;
  5821. #if DBG
  5822. count++;
  5823. #endif
  5824. }
  5825. AssertOrFailFast(argInstr == nullptr || argInstr->m_opcode == Js::OpCode::StartCall);
  5826. if (m_argStack->Empty())
  5827. {
  5828. this->callTreeHasSomeProfileInfo = false;
  5829. }
  5830. if (newOpcode == Js::OpCode::NewScObject || newOpcode == Js::OpCode::NewScObjArray
  5831. || newOpcode == Js::OpCode::NewScObjectSpread || newOpcode == Js::OpCode::NewScObjArraySpread)
  5832. {
  5833. #if DBG
  5834. count++;
  5835. #endif
  5836. m_argsOnStack++;
  5837. }
  5838. argCount = Js::CallInfo::GetArgCountWithExtraArgs(flags, argCount);
  5839. if (argInstr)
  5840. {
  5841. prevInstr->SetSrc2(argInstr->GetDst());
  5842. AssertMsg(instr->m_prev->m_opcode == Js::OpCode::LdSpreadIndices
  5843. // All non-spread calls need StartCall to have the same number of args
  5844. || (argInstr->GetSrc1()->IsIntConstOpnd()
  5845. && argInstr->GetSrc1()->AsIntConstOpnd()->GetValue() == count
  5846. && count == argCount), "StartCall has wrong number of arguments...");
  5847. }
  5848. else
  5849. {
  5850. AssertMsg(false, "Expect StartCall on other opcodes...");
  5851. }
  5852. // Update Func if this is the highest amount of stack we've used so far
  5853. // to push args.
  5854. #if DBG
  5855. m_callsOnStack--;
  5856. #endif
  5857. if (m_func->m_argSlotsForFunctionsCalled < m_argsOnStack)
  5858. m_func->m_argSlotsForFunctionsCalled = m_argsOnStack;
  5859. #if DBG
  5860. if (m_callsOnStack == 0)
  5861. Assert(m_argsOnStack == argCount);
  5862. #endif
  5863. m_argsOnStack -= argCount;
  5864. if (m_func->IsJitInDebugMode())
  5865. {
  5866. // Insert bailout after return from a call, script or library function call.
  5867. this->InsertBailOutForDebugger(
  5868. m_jnReader.GetCurrentOffset(), // bailout will resume at the offset of next instr.
  5869. c_debuggerBailOutKindForCall);
  5870. }
  5871. }
  5872. ///----------------------------------------------------------------------------
  5873. ///
  5874. /// IRBuilder::BuildBrReg1
  5875. ///
  5876. /// Build IR instr for a BrReg1 instruction.
  5877. /// This is a conditional branch with a single source operand (e.g., "if (x)" ...)
  5878. ///
  5879. ///----------------------------------------------------------------------------
  5880. template <typename SizePolicy>
  5881. void
  5882. IRBuilder::BuildBrReg1(Js::OpCode newOpcode, uint32 offset)
  5883. {
  5884. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  5885. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5886. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_BrReg1<SizePolicy>>();
  5887. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5888. {
  5889. this->DoClosureRegCheck(layout->R1);
  5890. }
  5891. BuildBrReg1(newOpcode, offset, m_jnReader.GetCurrentOffset() + layout->RelativeJumpOffset, layout->R1);
  5892. }
  5893. void
  5894. IRBuilder::BuildBrReg1(Js::OpCode newOpcode, uint32 offset, uint targetOffset, Js::RegSlot srcRegSlot)
  5895. {
  5896. IR::BranchInstr * branchInstr;
  5897. IR::RegOpnd * srcOpnd;
  5898. srcOpnd = this->BuildSrcOpnd(srcRegSlot);
  5899. if (newOpcode == Js::OpCode::BrNotUndecl_A) {
  5900. IR::AddrOpnd *srcOpnd2 = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetUndeclBlockVarAddr(),
  5901. IR::AddrOpndKindDynamicVar, this->m_func);
  5902. branchInstr = IR::BranchInstr::New(Js::OpCode::BrNotAddr_A, nullptr, srcOpnd, srcOpnd2, m_func);
  5903. } else {
  5904. branchInstr = IR::BranchInstr::New(newOpcode, nullptr, srcOpnd, m_func);
  5905. }
  5906. this->AddBranchInstr(branchInstr, offset, targetOffset);
  5907. }
  5908. ///----------------------------------------------------------------------------
  5909. ///
  5910. /// IRBuilder::BuildBrReg2
  5911. ///
  5912. /// Build IR instr for a BrReg2 instruction.
  5913. /// This is a conditional branch with a 2 source operands (e.g., "if (x == y)" ...)
  5914. ///
  5915. ///----------------------------------------------------------------------------
  5916. template <typename SizePolicy>
  5917. void
  5918. IRBuilder::BuildBrReg2(Js::OpCode newOpcode, uint32 offset)
  5919. {
  5920. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  5921. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5922. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_BrReg2<SizePolicy>>();
  5923. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5924. {
  5925. this->DoClosureRegCheck(layout->R1);
  5926. this->DoClosureRegCheck(layout->R2);
  5927. }
  5928. BuildBrReg2(newOpcode, offset, m_jnReader.GetCurrentOffset() + layout->RelativeJumpOffset, layout->R1, layout->R2);
  5929. }
  5930. template <typename SizePolicy>
  5931. void
  5932. IRBuilder::BuildBrReg1Unsigned1(Js::OpCode newOpcode, uint32 offset)
  5933. {
  5934. Assert(newOpcode == Js::OpCode::BrOnEmpty
  5935. /* || newOpcode == Js::OpCode::BrOnNotEmpty */ // BrOnNotEmpty not generate by the byte code
  5936. );
  5937. Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
  5938. Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
  5939. auto layout = m_jnReader.GetLayout<Js::OpLayoutT_BrReg1Unsigned1<SizePolicy>>();
  5940. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  5941. {
  5942. this->DoClosureRegCheck(layout->R1);
  5943. }
  5944. BuildBrBReturn(newOpcode, offset, layout->R1, layout->C2, m_jnReader.GetCurrentOffset() + layout->RelativeJumpOffset);
  5945. }
  5946. void
  5947. IRBuilder::BuildBrBReturn(Js::OpCode newOpcode, uint32 offset, Js::RegSlot DestRegSlot, uint32 forInLoopLevel, uint32 targetOffset)
  5948. {
  5949. IR::Opnd *srcOpnd = this->BuildForInEnumeratorOpnd(forInLoopLevel, offset);
  5950. IR::RegOpnd * destOpnd = this->BuildDstOpnd(DestRegSlot);
  5951. IR::BranchInstr * branchInstr = IR::BranchInstr::New(newOpcode, destOpnd, nullptr, srcOpnd, m_func);
  5952. this->AddBranchInstr(branchInstr, offset, targetOffset);
  5953. switch (newOpcode)
  5954. {
  5955. case Js::OpCode::BrOnEmpty:
  5956. destOpnd->SetValueType(ValueType::String);
  5957. break;
  5958. default:
  5959. Assert(false);
  5960. break;
  5961. };
  5962. }
  5963. void
  5964. IRBuilder::BuildBrReg2(Js::OpCode newOpcode, uint32 offset, uint targetOffset, Js::RegSlot R1, Js::RegSlot R2)
  5965. {
  5966. IR::BranchInstr * branchInstr;
  5967. if (newOpcode == Js::OpCode::BrOnEmpty
  5968. /* || newOpcode == Js::OpCode::BrOnNotEmpty */ // BrOnNotEmpty not generate by the byte code
  5969. )
  5970. {
  5971. BuildBrBReturn(newOpcode, offset, R1, R2, targetOffset);
  5972. return;
  5973. }
  5974. IR::RegOpnd * src1Opnd;
  5975. IR::RegOpnd * src2Opnd;
  5976. src1Opnd = this->BuildSrcOpnd(R1);
  5977. src2Opnd = this->BuildSrcOpnd(R2);
  5978. if (newOpcode == Js::OpCode::Case)
  5979. {
  5980. // generating branches for Cases is entirely handled
  5981. // by the SwitchIRBuilder
  5982. m_switchBuilder.OnCase(src1Opnd, src2Opnd, offset, targetOffset);
  5983. #ifdef BYTECODE_BRANCH_ISLAND
  5984. // Make sure that if there are branch island between the cases, we consume it first
  5985. EnsureConsumeBranchIsland();
  5986. #endif
  5987. // some instructions can't be optimized past, such as LdFld for objects. In these cases we have
  5988. // to inform the SwitchBuilder to flush any optimized cases that it has stored up to this point
  5989. // peeks the next opcode - to check if it is not a case statement (for example: the next instr can be a LdFld for objects)
  5990. Js::OpCode peekOpcode = m_jnReader.PeekOp();
  5991. if (peekOpcode != Js::OpCode::Case && peekOpcode != Js::OpCode::EndSwitch)
  5992. {
  5993. m_switchBuilder.FlushCases(m_jnReader.GetCurrentOffset());
  5994. }
  5995. }
  5996. else
  5997. {
  5998. branchInstr = IR::BranchInstr::New(newOpcode, nullptr, src1Opnd, src2Opnd, m_func);
  5999. this->AddBranchInstr(branchInstr, offset, targetOffset);
  6000. }
  6001. }
  6002. void
  6003. IRBuilder::BuildEmpty(Js::OpCode newOpcode, uint32 offset)
  6004. {
  6005. IR::Instr *instr;
  6006. m_jnReader.Empty();
  6007. instr = IR::Instr::New(newOpcode, m_func);
  6008. switch (newOpcode)
  6009. {
  6010. case Js::OpCode::CommitScope:
  6011. {
  6012. IR::RegOpnd * src1Opnd;
  6013. src1Opnd = this->BuildSrcOpnd(m_func->GetJITFunctionBody()->GetLocalClosureReg());
  6014. IR::LabelInstr *labelNull = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  6015. IR::RegOpnd * funcExprOpnd = IR::RegOpnd::New(TyVar, m_func);
  6016. instr = IR::Instr::New(Js::OpCode::LdFuncExpr, funcExprOpnd, m_func);
  6017. this->AddInstr(instr, offset);
  6018. IR::BranchInstr *branchInstr = IR::BranchInstr::New(Js::OpCode::BrFncCachedScopeNeq, labelNull,
  6019. funcExprOpnd, src1Opnd, this->m_func);
  6020. this->AddInstr(branchInstr, offset);
  6021. instr = IR::Instr::New(newOpcode, this->m_func);
  6022. instr->SetSrc1(src1Opnd);
  6023. this->AddInstr(instr, offset);
  6024. this->AddInstr(labelNull, Js::Constants::NoByteCodeOffset);
  6025. return;
  6026. }
  6027. case Js::OpCode::Ret:
  6028. {
  6029. IR::RegOpnd *regOpnd = BuildDstOpnd(0);
  6030. instr->SetSrc1(regOpnd);
  6031. this->AddInstr(instr, offset);
  6032. break;
  6033. }
  6034. case Js::OpCode::Leave:
  6035. {
  6036. IR::BranchInstr * branchInstr;
  6037. IR::LabelInstr * labelInstr;
  6038. if (this->handlerOffsetStack && !this->handlerOffsetStack->Empty() && this->handlerOffsetStack->Top().Second())
  6039. {
  6040. // If the try region has a break block, we don't want the Flowgraph to move all of that code out of the loop
  6041. // because an exception will bring the control back into the loop. The branch out of the loop (which is the
  6042. // reason for the code to be a break block) can still be moved out though.
  6043. //
  6044. // "BrOnException $catch" is inserted before Leave's in the try region to instrument flow from the try region
  6045. // to the catch region (which is in the loop).
  6046. IR::BranchInstr * brOnException = IR::BranchInstr::New(Js::OpCode::BrOnException, nullptr, this->m_func);
  6047. this->AddBranchInstr(brOnException, offset, this->handlerOffsetStack->Top().First());
  6048. }
  6049. labelInstr = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  6050. branchInstr = IR::BranchInstr::New(newOpcode, labelInstr, this->m_func);
  6051. this->AddInstr(branchInstr, offset);
  6052. this->AddInstr(labelInstr, Js::Constants::NoByteCodeOffset);
  6053. break;
  6054. }
  6055. case Js::OpCode::LeaveNull:
  6056. finallyBlockLevel--;
  6057. this->AddInstr(instr, offset);
  6058. break;
  6059. case Js::OpCode::Finally:
  6060. if (this->handlerOffsetStack)
  6061. {
  6062. AssertOrFailFast(!this->handlerOffsetStack->Empty());
  6063. AssertOrFailFast(this->handlerOffsetStack->Top().Second() == false);
  6064. this->handlerOffsetStack->Pop();
  6065. }
  6066. finallyBlockLevel++;
  6067. this->AddInstr(IR::Instr::New(Js::OpCode::Finally, this->m_func), offset);
  6068. break;
  6069. case Js::OpCode::Break:
  6070. if (m_func->IsJitInDebugMode())
  6071. {
  6072. // Add explicit bailout.
  6073. this->InsertBailOutForDebugger(offset, IR::BailOutExplicit);
  6074. }
  6075. else
  6076. {
  6077. // Default behavior, let's keep it for now, removed in lowerer.
  6078. this->AddInstr(instr, offset);
  6079. }
  6080. break;
  6081. case Js::OpCode::BeginBodyScope:
  6082. {
  6083. // This marks the end of a param scope which is not merged with body scope.
  6084. // So we have to first cache the closure so that we can use it to copy the initial values for
  6085. // body syms from corresponding param syms (LdParamSlot). Body should get its own scope slot.
  6086. Assert(!this->IsParamScopeDone());
  6087. this->SetParamScopeDone();
  6088. IR::Opnd * localClosureOpnd;
  6089. if (this->m_func->GetLocalClosureSym() != nullptr)
  6090. {
  6091. localClosureOpnd = IR::RegOpnd::New(this->m_func->GetLocalClosureSym(), TyVar, this->m_func);
  6092. }
  6093. else
  6094. {
  6095. AssertOrFailFast(this->m_func->GetJITFunctionBody()->GetScopeSlotArraySize() == 0 && !this->m_func->GetJITFunctionBody()->HasScopeObject());
  6096. localClosureOpnd = IR::IntConstOpnd::New(0, TyVar, this->m_func);
  6097. }
  6098. this->AddInstr(
  6099. IR::Instr::New(
  6100. Js::OpCode::Ld_A,
  6101. this->BuildDstOpnd(this->m_func->GetJITFunctionBody()->GetParamClosureReg()),
  6102. localClosureOpnd,
  6103. this->m_func),
  6104. offset);
  6105. // Create a new local closure for the body when either body scope has scope slots allocated or
  6106. // eval is present which can leak declarations.
  6107. if (this->m_func->GetJITFunctionBody()->GetScopeSlotArraySize() > 0 || this->m_func->GetJITFunctionBody()->HasScopeObject())
  6108. {
  6109. if (this->m_func->GetJITFunctionBody()->HasScopeObject())
  6110. {
  6111. if (this->m_func->GetJITFunctionBody()->HasCachedScopePropIds())
  6112. {
  6113. this->BuildInitCachedScope(0, Js::Constants::NoByteCodeOffset);
  6114. }
  6115. else
  6116. {
  6117. this->AddInstr(
  6118. IR::Instr::New(
  6119. Js::OpCode::NewScopeObject,
  6120. this->BuildDstOpnd(this->m_func->GetJITFunctionBody()->GetLocalClosureReg()),
  6121. m_func),
  6122. Js::Constants::NoByteCodeOffset);
  6123. }
  6124. }
  6125. else
  6126. {
  6127. this->AddInstr(
  6128. IR::Instr::New(
  6129. Js::OpCode::NewScopeSlots,
  6130. this->BuildDstOpnd(this->m_func->GetJITFunctionBody()->GetLocalClosureReg()),
  6131. IR::IntConstOpnd::New(this->m_func->GetJITFunctionBody()->GetScopeSlotArraySize() + Js::ScopeSlots::FirstSlotIndex, TyUint32, this->m_func),
  6132. m_func),
  6133. Js::Constants::NoByteCodeOffset);
  6134. }
  6135. IR::Instr* lfd = IR::Instr::New(
  6136. Js::OpCode::LdFrameDisplay,
  6137. this->BuildDstOpnd(this->m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg()),
  6138. this->BuildDstOpnd(this->m_func->GetJITFunctionBody()->GetLocalClosureReg()),
  6139. this->BuildDstOpnd(this->m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg()),
  6140. this->m_func);
  6141. this->AddInstr(
  6142. lfd,
  6143. Js::Constants::NoByteCodeOffset);
  6144. lfd->isNonFastPathFrameDisplay = true;
  6145. }
  6146. break;
  6147. }
  6148. default:
  6149. this->AddInstr(instr, offset);
  6150. break;
  6151. }
  6152. }
  6153. #ifdef BYTECODE_BRANCH_ISLAND
  6154. void
  6155. IRBuilder::EnsureConsumeBranchIsland()
  6156. {
  6157. if (m_jnReader.PeekOp() == Js::OpCode::Br)
  6158. {
  6159. // Save the old offset
  6160. uint offset = m_jnReader.GetCurrentOffset();
  6161. // Read the potentially a branch around
  6162. Js::LayoutSize layoutSize;
  6163. Js::OpCode opcode = m_jnReader.ReadOp(layoutSize);
  6164. Assert(opcode == Js::OpCode::Br);
  6165. Assert(layoutSize == Js::SmallLayout);
  6166. const unaligned Js::OpLayoutBr * playout = m_jnReader.Br();
  6167. unsigned int targetOffset = m_jnReader.GetCurrentOffset() + playout->RelativeJumpOffset;
  6168. uint branchIslandOffset = m_jnReader.GetCurrentOffset();
  6169. if (branchIslandOffset == targetOffset)
  6170. {
  6171. // branch to next, there is no long branch
  6172. m_jnReader.SetCurrentOffset(offset);
  6173. return;
  6174. }
  6175. // Ignore all the BrLong
  6176. while (m_jnReader.PeekOp() == Js::OpCode::BrLong)
  6177. {
  6178. opcode = m_jnReader.ReadOp(layoutSize);
  6179. Assert(opcode == Js::OpCode::BrLong);
  6180. Assert(layoutSize == Js::SmallLayout);
  6181. m_jnReader.BrLong();
  6182. }
  6183. // Confirm that is a branch around
  6184. if ((uint)m_jnReader.GetCurrentOffset() == targetOffset)
  6185. {
  6186. // Really consume the branch island
  6187. m_jnReader.SetCurrentOffset(branchIslandOffset);
  6188. ConsumeBranchIsland();
  6189. // Mark the virtual branch around as a redirect long branch as well
  6190. // so that if it is the target of another branch, it will just keep pass
  6191. // the branch island
  6192. Assert(longBranchMap);
  6193. Assert(offset < m_offsetToInstructionCount);
  6194. Assert(m_offsetToInstruction[offset] == nullptr);
  6195. m_offsetToInstruction[offset] = VirtualLongBranchInstr;
  6196. longBranchMap->Add(offset, targetOffset);
  6197. }
  6198. else
  6199. {
  6200. // Reset the offset
  6201. m_jnReader.SetCurrentOffset(offset);
  6202. }
  6203. }
  6204. }
  6205. IR::Instr * const IRBuilder::VirtualLongBranchInstr = (IR::Instr *)-1;
  6206. void
  6207. IRBuilder::ConsumeBranchIsland()
  6208. {
  6209. do
  6210. {
  6211. uint32 offset = m_jnReader.GetCurrentOffset();
  6212. Js::LayoutSize layoutSize;
  6213. Js::OpCode opcode = m_jnReader.ReadOp(layoutSize);
  6214. Assert(opcode == Js::OpCode::BrLong);
  6215. Assert(layoutSize == Js::SmallLayout);
  6216. BuildBrLong(Js::OpCode::BrLong, offset);
  6217. }
  6218. while (m_jnReader.PeekOp() == Js::OpCode::BrLong);
  6219. }
  6220. void
  6221. IRBuilder::BuildBrLong(Js::OpCode newOpcode, uint32 offset)
  6222. {
  6223. Assert(newOpcode == Js::OpCode::BrLong);
  6224. Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
  6225. Assert(offset != Js::Constants::NoByteCodeOffset);
  6226. const unaligned Js::OpLayoutBrLong *branchInsn = m_jnReader.BrLong();
  6227. unsigned int targetOffset = m_jnReader.GetCurrentOffset() + branchInsn->RelativeJumpOffset;
  6228. Assert(offset < m_offsetToInstructionCount);
  6229. Assert(m_offsetToInstruction[offset] == nullptr);
  6230. // BrLong are also just the target of another branch, just set a virtual long branch instr
  6231. // and remap the original branch to the actual destination in ResolveVirtualLongBranch
  6232. m_offsetToInstruction[offset] = VirtualLongBranchInstr;
  6233. longBranchMap->Add(offset, targetOffset);
  6234. }
  6235. uint
  6236. IRBuilder::ResolveVirtualLongBranch(IR::BranchInstr * branchInstr, uint offset)
  6237. {
  6238. Assert(longBranchMap);
  6239. uint32 targetOffset;
  6240. if (!longBranchMap->TryGetValue(offset, &targetOffset))
  6241. {
  6242. // If we see a VirtualLongBranchInstr, we must have a mapping to the real target offset
  6243. Assert(false);
  6244. Fatal();
  6245. }
  6246. // If this is a jump out of the loop body we need to load the return IP and jump to the loop exit instead
  6247. if (!IsLoopBodyOuterOffset(targetOffset))
  6248. {
  6249. return targetOffset;
  6250. }
  6251. // Multi branch shouldn't be exiting a loop
  6252. Assert(branchInstr->m_opcode != Js::OpCode::MultiBr);
  6253. // Don't load the return IP if it is already loaded (for the case of early exit)
  6254. if (!IsLoopBodyReturnIPInstr(branchInstr->m_prev))
  6255. {
  6256. IR::Instr * returnIPInstr = CreateLoopBodyReturnIPInstr(targetOffset, branchInstr->GetByteCodeOffset());
  6257. // Any jump to this branch to jump to the return IP load instr first
  6258. uint32 branchInstrByteCodeOffset = branchInstr->GetByteCodeOffset();
  6259. Assert(this->m_offsetToInstruction[branchInstrByteCodeOffset] == branchInstr ||
  6260. (this->m_offsetToInstruction[branchInstrByteCodeOffset]->HasBailOutInfo() &&
  6261. this->m_offsetToInstruction[branchInstrByteCodeOffset]->GetBailOutKind() == IR::BailOutInjected));
  6262. InsertInstr(returnIPInstr, branchInstr);
  6263. }
  6264. return GetLoopBodyExitInstrOffset();
  6265. }
  6266. #endif
  6267. ///----------------------------------------------------------------------------
  6268. ///
  6269. /// IRBuilder::BuildBr
  6270. ///
  6271. /// Build IR instr for a Br (unconditional branch) instruction.
  6272. /// or TryCatch/TryFinally
  6273. ///
  6274. ///----------------------------------------------------------------------------
  6275. void
  6276. IRBuilder::BuildBr(Js::OpCode newOpcode, uint32 offset)
  6277. {
  6278. Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
  6279. IR::BranchInstr * branchInstr;
  6280. const unaligned Js::OpLayoutBr *branchInsn = m_jnReader.Br();
  6281. unsigned int targetOffset = m_jnReader.GetCurrentOffset() + branchInsn->RelativeJumpOffset;
  6282. #ifdef BYTECODE_BRANCH_ISLAND
  6283. bool isLongBranchIsland = (m_jnReader.PeekOp() == Js::OpCode::BrLong);
  6284. if (isLongBranchIsland)
  6285. {
  6286. ConsumeBranchIsland();
  6287. }
  6288. #endif
  6289. if(newOpcode == Js::OpCode::EndSwitch)
  6290. {
  6291. m_switchBuilder.EndSwitch(offset, targetOffset);
  6292. return;
  6293. }
  6294. #ifdef PERF_HINT
  6295. else if (PHASE_TRACE1(Js::PerfHintPhase) && (newOpcode == Js::OpCode::TryCatch || newOpcode == Js::OpCode::TryFinally) )
  6296. {
  6297. WritePerfHint(PerfHints::HasTryBlock, this->m_func, offset);
  6298. }
  6299. #endif
  6300. #ifdef BYTECODE_BRANCH_ISLAND
  6301. if (isLongBranchIsland && (targetOffset == (uint)m_jnReader.GetCurrentOffset()))
  6302. {
  6303. // Branch to next (probably after consume branch island), try to not emit the branch
  6304. // Mark the jump around instruction as a virtual long branch as well so we can just
  6305. // fall through instead of branch to exit
  6306. Assert(offset < m_offsetToInstructionCount);
  6307. if (m_offsetToInstruction[offset] == nullptr)
  6308. {
  6309. m_offsetToInstruction[offset] = VirtualLongBranchInstr;
  6310. longBranchMap->Add(offset, targetOffset);
  6311. return;
  6312. }
  6313. // We may have already create an instruction on this offset as a statement boundary
  6314. // or in the bailout at every byte code case.
  6315. // The statement boundary case only happens if we have emitted the long branch island
  6316. // after an existing no fall through instruction, but that instruction also happen to be
  6317. // branch to next. We will just generate an actual branch to next instruction.
  6318. Assert(m_offsetToInstruction[offset]->m_opcode == Js::OpCode::StatementBoundary
  6319. || (Js::Configuration::Global.flags.IsEnabled(Js::BailOutAtEveryByteCodeFlag)
  6320. && m_offsetToInstruction[offset]->m_opcode == Js::OpCode::BailOnEqual));
  6321. }
  6322. #endif
  6323. if ((newOpcode == Js::OpCode::TryCatch) && this->handlerOffsetStack)
  6324. {
  6325. this->handlerOffsetStack->Push(Pair<uint, bool>(targetOffset, true));
  6326. }
  6327. else if ((newOpcode == Js::OpCode::TryFinally) && this->handlerOffsetStack)
  6328. {
  6329. this->handlerOffsetStack->Push(Pair<uint, bool>(targetOffset, false));
  6330. }
  6331. branchInstr = IR::BranchInstr::New(newOpcode, nullptr, m_func);
  6332. this->AddBranchInstr(branchInstr, offset, targetOffset);
  6333. }
  6334. void
  6335. IRBuilder::BuildBrS(Js::OpCode newOpcode, uint32 offset)
  6336. {
  6337. Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
  6338. IR::BranchInstr * branchInstr;
  6339. const unaligned Js::OpLayoutBrS *branchInsn = m_jnReader.BrS();
  6340. unsigned int targetOffset = m_jnReader.GetCurrentOffset() + branchInsn->RelativeJumpOffset;
  6341. branchInstr = IR::BranchInstr::New(newOpcode, nullptr,
  6342. IR::IntConstOpnd::New(branchInsn->val,
  6343. TyInt32, m_func),m_func);
  6344. this->AddBranchInstr(branchInstr, offset, targetOffset);
  6345. }
  6346. ///----------------------------------------------------------------------------
  6347. ///
  6348. /// IRBuilder::BuildBrProperty
  6349. ///
  6350. /// Build IR instr for a BrProperty instruction.
  6351. /// This is a conditional branch that tests whether the given property
  6352. /// is present on the given instance.
  6353. ///
  6354. ///----------------------------------------------------------------------------
  6355. void
  6356. IRBuilder::BuildBrProperty(Js::OpCode newOpcode, uint32 offset)
  6357. {
  6358. Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
  6359. const unaligned Js::OpLayoutBrProperty *branchInsn = m_jnReader.BrProperty();
  6360. if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
  6361. {
  6362. this->DoClosureRegCheck(branchInsn->Instance);
  6363. }
  6364. IR::BranchInstr * branchInstr;
  6365. Js::PropertyId propertyId =
  6366. m_func->GetJITFunctionBody()->GetReferencedPropertyId(branchInsn->PropertyIdIndex);
  6367. unsigned int targetOffset = m_jnReader.GetCurrentOffset() + branchInsn->RelativeJumpOffset;
  6368. IR::SymOpnd * fieldSymOpnd = this->BuildFieldOpnd(newOpcode, branchInsn->Instance, propertyId, branchInsn->PropertyIdIndex, PropertyKindData);
  6369. branchInstr = IR::BranchInstr::New(newOpcode, nullptr, fieldSymOpnd, m_func);
  6370. this->AddBranchInstr(branchInstr, offset, targetOffset);
  6371. }
  6372. void
  6373. IRBuilder::BuildBrLocalProperty(Js::OpCode newOpcode, uint32 offset)
  6374. {
  6375. Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
  6376. Assert(newOpcode == Js::OpCode::BrOnHasLocalProperty);
  6377. const unaligned Js::OpLayoutBrLocalProperty *branchInsn = m_jnReader.BrLocalProperty();
  6378. if (m_func->GetLocalClosureSym()->HasByteCodeRegSlot())
  6379. {
  6380. IR::ByteCodeUsesInstr * byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
  6381. byteCodeUse->SetNonOpndSymbol(m_func->GetLocalClosureSym()->m_id);
  6382. this->AddInstr(byteCodeUse, offset);
  6383. }
  6384. IR::BranchInstr * branchInstr;
  6385. Js::PropertyId propertyId =
  6386. m_func->GetJITFunctionBody()->GetReferencedPropertyId(branchInsn->PropertyIdIndex);
  6387. unsigned int targetOffset = m_jnReader.GetCurrentOffset() + branchInsn->RelativeJumpOffset;
  6388. IR::SymOpnd * fieldSymOpnd = this->BuildFieldOpnd(newOpcode, m_func->GetJITFunctionBody()->GetLocalClosureReg(), propertyId, branchInsn->PropertyIdIndex, PropertyKindData);
  6389. branchInstr = IR::BranchInstr::New(newOpcode, nullptr, fieldSymOpnd, m_func);
  6390. this->AddBranchInstr(branchInstr, offset, targetOffset);
  6391. }
  6392. void
  6393. IRBuilder::BuildBrEnvProperty(Js::OpCode newOpcode, uint32 offset)
  6394. {
  6395. Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
  6396. const unaligned Js::OpLayoutBrEnvProperty *branchInsn = m_jnReader.BrEnvProperty();
  6397. IR::Instr *instr;
  6398. IR::BranchInstr * branchInstr;
  6399. IR::RegOpnd *regOpnd;
  6400. IR::SymOpnd *fieldOpnd;
  6401. PropertySym *fieldSym;
  6402. fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, this->GetEnvReg(), branchInsn->SlotIndex, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
  6403. regOpnd = IR::RegOpnd::New(TyVar, m_func);
  6404. instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func);
  6405. this->AddInstr(instr, offset);
  6406. Js::PropertyId propertyId =
  6407. m_func->GetJITFunctionBody()->GetReferencedPropertyId(branchInsn->PropertyIdIndex);
  6408. unsigned int targetOffset = m_jnReader.GetCurrentOffset() + branchInsn->RelativeJumpOffset;\
  6409. fieldSym = PropertySym::New(regOpnd->m_sym, propertyId, branchInsn->PropertyIdIndex, (uint)-1, PropertyKindData, m_func);
  6410. fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
  6411. Assert(newOpcode == Js::OpCode::BrOnHasEnvProperty || newOpcode == Js::OpCode::BrOnHasLocalEnvProperty);
  6412. branchInstr = IR::BranchInstr::New(newOpcode == Js::OpCode::BrOnHasEnvProperty ? Js::OpCode::BrOnHasProperty : Js::OpCode::BrOnHasLocalProperty, nullptr, fieldOpnd, m_func);
  6413. this->AddBranchInstr(branchInstr, offset, targetOffset);
  6414. }
  6415. ///----------------------------------------------------------------------------
  6416. ///
  6417. /// IRBuilder::AddBranchInstr
  6418. ///
  6419. /// Create a branch/offset pair which will be fixed up at the end of the
  6420. /// IRBuilder phase and add the instruction
  6421. ///
  6422. ///----------------------------------------------------------------------------
  6423. BranchReloc *
  6424. IRBuilder::AddBranchInstr(IR::BranchInstr * branchInstr, uint32 offset, uint32 targetOffset)
  6425. {
  6426. AssertOrFailFast(targetOffset <= m_func->GetJITFunctionBody()->GetByteCodeLength());
  6427. //
  6428. // Loop jitting would be done only till the LoopEnd
  6429. // Any branches beyond that offset are for the return stmt
  6430. //
  6431. if (IsLoopBodyOuterOffset(targetOffset))
  6432. {
  6433. // if we have loaded the loop IP sym from the ProfiledLoopEnd then don't add it here
  6434. if (!IsLoopBodyReturnIPInstr(m_lastInstr))
  6435. {
  6436. this->InsertLoopBodyReturnIPInstr(targetOffset, offset);
  6437. }
  6438. // Jump the restore StSlot and Ret instruction
  6439. targetOffset = GetLoopBodyExitInstrOffset();
  6440. }
  6441. BranchReloc * reloc = nullptr;
  6442. reloc = this->CreateRelocRecord(branchInstr, offset, targetOffset);
  6443. this->AddInstr(branchInstr, offset);
  6444. return reloc;
  6445. }
  6446. BranchReloc *
  6447. IRBuilder::CreateRelocRecord(IR::BranchInstr * branchInstr, uint32 offset, uint32 targetOffset)
  6448. {
  6449. BranchReloc * reloc = JitAnew(this->m_tempAlloc, BranchReloc, branchInstr, offset, targetOffset);
  6450. this->branchRelocList->Prepend(reloc);
  6451. return reloc;
  6452. }
  6453. ///----------------------------------------------------------------------------
  6454. ///
  6455. /// IRBuilder::BuildRegexFromPattern
  6456. ///
  6457. /// Build a new RegEx instruction. Simply construct a var to hold the regex
  6458. /// and load it as an immediate into a register.
  6459. ///
  6460. ///----------------------------------------------------------------------------
  6461. void
  6462. IRBuilder::BuildRegexFromPattern(Js::RegSlot dstRegSlot, uint32 patternIndex, uint32 offset)
  6463. {
  6464. IR::Instr * instr;
  6465. IR::RegOpnd* dstOpnd = this->BuildDstOpnd(dstRegSlot);
  6466. dstOpnd->SetValueType(ValueType::GetObject(ObjectType::RegExp));
  6467. IR::Opnd * regexOpnd = IR::AddrOpnd::New(m_func->GetJITFunctionBody()->GetLiteralRegexAddr(patternIndex), IR::AddrOpndKindDynamicMisc, this->m_func);
  6468. instr = IR::Instr::New(Js::OpCode::NewRegEx, dstOpnd, regexOpnd, this->m_func);
  6469. this->AddInstr(instr, offset);
  6470. }
  6471. bool
  6472. IRBuilder::IsFloatFunctionCallsite(Js::BuiltinFunction index, size_t argc)
  6473. {
  6474. return Js::JavascriptLibrary::IsFloatFunctionCallsite(index, argc);
  6475. }
  6476. void
  6477. IRBuilder::CheckBuiltIn(PropertySym * propertySym, Js::BuiltinFunction *puBuiltInIndex)
  6478. {
  6479. Js::BuiltinFunction index = Js::BuiltinFunction::None;
  6480. // Check whether the propertySym appears to be a built-in.
  6481. if (propertySym->m_fieldKind != PropertyKindData)
  6482. {
  6483. return;
  6484. }
  6485. index = Js::JavascriptLibrary::GetBuiltinFunctionForPropId(propertySym->m_propertyId);
  6486. if (index == Js::BuiltinFunction::None)
  6487. {
  6488. return;
  6489. }
  6490. // If the target is one of the Math built-ins, see whether the stack sym is the
  6491. // global "Math".
  6492. if (Js::JavascriptLibrary::IsFltFunc(index))
  6493. {
  6494. if (!propertySym->m_stackSym->m_isSingleDef)
  6495. {
  6496. return;
  6497. }
  6498. IR::Instr *instr = propertySym->m_stackSym->m_instrDef;
  6499. AssertMsg(instr != nullptr, "Single-def stack sym w/o def instr?");
  6500. if (instr->m_opcode != Js::OpCode::LdRootFld && instr->m_opcode != Js::OpCode::LdRootFldForTypeOf)
  6501. {
  6502. return;
  6503. }
  6504. IR::Opnd * opnd = instr->GetSrc1();
  6505. AssertMsg(opnd != nullptr && opnd->IsSymOpnd() && opnd->AsSymOpnd()->m_sym->IsPropertySym(),
  6506. "LdRootFld w/o propertySym src?");
  6507. if (opnd->AsSymOpnd()->m_sym->AsPropertySym()->m_propertyId != Js::PropertyIds::Math)
  6508. {
  6509. return;
  6510. }
  6511. }
  6512. *puBuiltInIndex = index;
  6513. }
  6514. StackSym *
  6515. IRBuilder::EnsureStackFuncPtrSym()
  6516. {
  6517. StackSym * sym = this->m_stackFuncPtrSym;
  6518. if (sym)
  6519. {
  6520. return sym;
  6521. }
  6522. if (m_func->IsLoopBody() && m_func->DoStackNestedFunc())
  6523. {
  6524. Assert(m_func->IsTopFunc());
  6525. sym = StackSym::New(TyVar, m_func);
  6526. this->m_stackFuncPtrSym = sym;
  6527. }
  6528. return sym;
  6529. }
  6530. void
  6531. IRBuilder::GenerateLoopBodySlotAccesses(uint offset)
  6532. {
  6533. //
  6534. // The interpreter instance is passed as 0th argument to the JITted loop body function.
  6535. // Always load the argument, then use it to generate any necessary store-slots.
  6536. //
  6537. uint16 argument = 0;
  6538. StackSym *symSrc = StackSym::NewParamSlotSym(argument + 1, m_func);
  6539. symSrc->m_offset = (argument + LowererMD::GetFormalParamOffset()) * MachPtr;
  6540. symSrc->m_allocated = true;
  6541. m_func->SetHasImplicitParamLoad();
  6542. IR::SymOpnd *srcOpnd = IR::SymOpnd::New(symSrc, TyVar, m_func);
  6543. StackSym *loopParamSym = m_func->EnsureLoopParamSym();
  6544. IR::RegOpnd *loopParamOpnd = IR::RegOpnd::New(loopParamSym, TyMachPtr, m_func);
  6545. IR::Instr *instrArgIn = IR::Instr::New(Js::OpCode::ArgIn_A, loopParamOpnd, srcOpnd, m_func);
  6546. m_func->m_headInstr->InsertAfter(instrArgIn);
  6547. StackSym *stackFuncPtrSym = this->m_stackFuncPtrSym;
  6548. if (stackFuncPtrSym)
  6549. {
  6550. PropertySym * fieldSym = PropertySym::FindOrCreate(loopParamSym->m_id, (Js::PropertyId)(Js::InterpreterStackFrame::GetOffsetOfStackNestedFunctions() / sizeof(Js::Var)), (uint32)-1, (uint)-1, PropertyKindLocalSlots, m_func);
  6551. IR::SymOpnd * opndPtrRef = IR::SymOpnd::New(fieldSym, TyVar, m_func);
  6552. IR::Instr * instrPtrInit = IR::Instr::New(Js::OpCode::LdSlot, IR::RegOpnd::New(stackFuncPtrSym, TyVar, m_func), opndPtrRef, m_func);
  6553. instrArgIn->InsertAfter(instrPtrInit);
  6554. }
  6555. GenerateLoopBodyStSlots(loopParamSym->m_id, offset);
  6556. }
  6557. void
  6558. IRBuilder::GenerateLoopBodyStSlots(SymID loopParamSymId, uint offset)
  6559. {
  6560. if (this->m_stSlots->Count() == 0)
  6561. {
  6562. return;
  6563. }
  6564. FOREACH_BITSET_IN_FIXEDBV(regSlot, this->m_stSlots)
  6565. {
  6566. this->GenerateLoopBodyStSlot(regSlot, offset);
  6567. }
  6568. NEXT_BITSET_IN_FIXEDBV;
  6569. }
  6570. IR::Instr *
  6571. IRBuilder::GenerateLoopBodyStSlot(Js::RegSlot regSlot, uint offset)
  6572. {
  6573. Assert(!this->RegIsConstant((Js::RegSlot)regSlot));
  6574. StackSym *loopParamSym = m_func->EnsureLoopParamSym();
  6575. PropertySym * fieldSym = PropertySym::FindOrCreate(loopParamSym->m_id, (Js::PropertyId)(regSlot + this->m_loopBodyLocalsStartSlot), (uint32)-1, (uint)-1, PropertyKindLocalSlots, m_func);
  6576. IR::SymOpnd * fieldSymOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
  6577. IR::RegOpnd * regOpnd = this->BuildSrcOpnd((Js::RegSlot)regSlot);
  6578. #if !FLOATVAR
  6579. Js::OpCode opcode = Js::OpCode::StSlotBoxTemp;
  6580. #else
  6581. Js::OpCode opcode = Js::OpCode::StSlot;
  6582. #endif
  6583. IR::Instr * stSlotInstr = IR::Instr::New(opcode, fieldSymOpnd, regOpnd, m_func);
  6584. if (offset != Js::Constants::NoByteCodeOffset)
  6585. {
  6586. this->AddInstr(stSlotInstr, offset);
  6587. return nullptr;
  6588. }
  6589. else
  6590. {
  6591. return stSlotInstr;
  6592. }
  6593. }
  6594. IR::Instr *
  6595. IRBuilder::CreateLoopBodyReturnIPInstr(uint targetOffset, uint offset)
  6596. {
  6597. IR::RegOpnd * retOpnd = IR::RegOpnd::New(m_loopBodyRetIPSym, TyMachReg, m_func);
  6598. IR::IntConstOpnd * exitOffsetOpnd = IR::IntConstOpnd::New(targetOffset, TyMachReg, m_func);
  6599. return IR::Instr::New(Js::OpCode::Ld_I4, retOpnd, exitOffsetOpnd, m_func);
  6600. }
  6601. IR::Opnd *
  6602. IRBuilder::InsertLoopBodyReturnIPInstr(uint targetOffset, uint offset)
  6603. {
  6604. IR::Instr * setRetValueInstr = CreateLoopBodyReturnIPInstr(targetOffset, offset);
  6605. this->AddInstr(setRetValueInstr, offset);
  6606. return setRetValueInstr->GetDst();
  6607. }
  6608. void
  6609. IRBuilder::InsertDoneLoopBodyLoopCounter(uint32 lastOffset)
  6610. {
  6611. if (m_loopCounterSym == nullptr)
  6612. {
  6613. return;
  6614. }
  6615. IR::Instr * loopCounterStoreInstr = IR::Instr::New(Js::OpCode::StLoopBodyCount, m_func);
  6616. IR::RegOpnd *countRegOpnd = IR::RegOpnd::New(m_loopCounterSym, TyInt32, this->m_func);
  6617. countRegOpnd->SetIsJITOptimizedReg(true);
  6618. loopCounterStoreInstr->SetSrc1(countRegOpnd);
  6619. this->AddInstr(loopCounterStoreInstr, lastOffset + 1);
  6620. return;
  6621. }
  6622. void
  6623. IRBuilder::InsertIncrLoopBodyLoopCounter(IR::LabelInstr *loopTopLabelInstr)
  6624. {
  6625. Assert(this->IsLoopBody());
  6626. IR::RegOpnd *loopCounterOpnd = IR::RegOpnd::New(m_loopCounterSym, TyInt32, this->m_func);
  6627. IR::Instr * incr = IR::Instr::New(Js::OpCode::IncrLoopBodyCount, loopCounterOpnd, loopCounterOpnd, this->m_func);
  6628. loopCounterOpnd->SetIsJITOptimizedReg(true);
  6629. IR::Instr* nextRealInstr = loopTopLabelInstr->GetNextRealInstr();
  6630. InsertInstr(incr, nextRealInstr);
  6631. }
  6632. void
  6633. IRBuilder::InsertInitLoopBodyLoopCounter(uint loopNum)
  6634. {
  6635. Assert(this->IsLoopBody());
  6636. intptr_t loopHeader = m_func->GetJITFunctionBody()->GetLoopHeaderAddr(loopNum);
  6637. Assert(m_func->GetWorkItem()->GetLoopHeaderAddr() == loopHeader); //Init only once
  6638. m_loopCounterSym = StackSym::New(TyVar, this->m_func);
  6639. IR::RegOpnd* loopCounterOpnd = IR::RegOpnd::New(m_loopCounterSym, TyVar, this->m_func);
  6640. loopCounterOpnd->SetIsJITOptimizedReg(true);
  6641. IR::Instr * initInstr = IR::Instr::New(Js::OpCode::InitLoopBodyCount, loopCounterOpnd, this->m_func);
  6642. m_lastInstr->InsertAfter(initInstr);
  6643. m_lastInstr = initInstr;
  6644. initInstr->SetByteCodeOffset(m_jnReader.GetCurrentOffset());
  6645. }
  6646. IR::AddrOpnd *
  6647. IRBuilder::BuildAuxArrayOpnd(AuxArrayValue auxArrayType, uint32 auxArrayOffset)
  6648. {
  6649. switch (auxArrayType)
  6650. {
  6651. case AuxArrayValue::AuxPropertyIdArray:
  6652. case AuxArrayValue::AuxIntArray:
  6653. case AuxArrayValue::AuxFloatArray:
  6654. case AuxArrayValue::AuxVarsArray:
  6655. case AuxArrayValue::AuxFuncInfoArray:
  6656. case AuxArrayValue::AuxVarArrayVarCount:
  6657. {
  6658. IR::AddrOpnd * opnd = IR::AddrOpnd::New(m_func->GetJITFunctionBody()->GetAuxDataAddr(auxArrayOffset), IR::AddrOpndKindDynamicAuxBufferRef, m_func);
  6659. opnd->m_metadata = m_func->GetJITFunctionBody()->ReadFromAuxData(auxArrayOffset);
  6660. return opnd;
  6661. }
  6662. default:
  6663. Assert(UNREACHED);
  6664. return nullptr;
  6665. }
  6666. }
  6667. IR::Opnd *
  6668. IRBuilder::BuildAuxObjectLiteralTypeRefOpnd(int objectId)
  6669. {
  6670. return IR::AddrOpnd::New(m_func->GetJITFunctionBody()->GetObjectLiteralTypeRef(objectId), IR::AddrOpndKindDynamicMisc, this->m_func);
  6671. }
  6672. void
  6673. IRBuilder::DoClosureRegCheck(Js::RegSlot reg)
  6674. {
  6675. if (reg == Js::Constants::NoRegister)
  6676. {
  6677. return;
  6678. }
  6679. if (reg == m_func->GetJITFunctionBody()->GetEnvReg() ||
  6680. reg == m_func->GetJITFunctionBody()->GetLocalClosureReg() ||
  6681. reg == m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg() ||
  6682. reg == m_func->GetJITFunctionBody()->GetParamClosureReg())
  6683. {
  6684. Js::Throw::FatalInternalError();
  6685. }
  6686. }
  6687. Js::RegSlot
  6688. IRBuilder::InnerScopeIndexToRegSlot(uint32 index) const
  6689. {
  6690. if (index >= m_func->GetJITFunctionBody()->GetInnerScopeCount())
  6691. {
  6692. Js::Throw::FatalInternalError();
  6693. }
  6694. Js::RegSlot reg = m_func->GetJITFunctionBody()->GetFirstInnerScopeReg() + index;
  6695. if (reg >= m_func->GetJITFunctionBody()->GetLocalsCount())
  6696. {
  6697. Js::Throw::FatalInternalError();
  6698. }
  6699. return reg;
  6700. }
  6701. bool
  6702. IRBuilder::DoLoadInstructionArrayProfileInfo()
  6703. {
  6704. return !(!this->m_func->HasProfileInfo() ||
  6705. (
  6706. PHASE_OFF(Js::TypedArrayPhase, this->m_func->GetTopFunc()) &&
  6707. PHASE_OFF(Js::ArrayCheckHoistPhase, this->m_func)
  6708. ));
  6709. }
  6710. bool
  6711. IRBuilder::AllowNativeArrayProfileInfo()
  6712. {
  6713. return !((!(m_func->GetTopFunc()->HasTry() && !m_func->GetTopFunc()->DoOptimizeTry()) && m_func->GetWeakFuncRef() && !m_func->HasArrayInfo()) ||
  6714. m_func->IsJitInDebugMode());
  6715. }
  6716. #if DBG_DUMP || defined(ENABLE_IR_VIEWER)
  6717. #define POINTER_OFFSET(opnd, c, field) \
  6718. m_irBuilder->BuildIndirOpnd((opnd), c, _u(#c) _u(".") _u(#field))
  6719. #else
  6720. #define POINTER_OFFSET(opnd, c, field) \
  6721. m_irBuilder->BuildIndirOpnd((opnd), c)
  6722. #endif
  6723. IRBuilder::GeneratorJumpTable::GeneratorJumpTable(Func* func, IRBuilder* irBuilder) : m_func(func), m_irBuilder(irBuilder) {}
  6724. IR::Instr*
  6725. IRBuilder::GeneratorJumpTable::BuildJumpTable()
  6726. {
  6727. if (!this->m_func->GetJITFunctionBody()->IsCoroutine())
  6728. {
  6729. return this->m_irBuilder->m_lastInstr;
  6730. }
  6731. // Build code to check if the generator already has state and if it does then jump to the corresponding resume point.
  6732. // Otherwise jump to the start of the function. The generator object is the first argument by convention established
  6733. // in JavascriptGenerator::EntryNext/EntryReturn/EntryThrow.
  6734. // We also create the interpreter stack frame for generator if it doesn't already exist.
  6735. //
  6736. // s1 = Ld_A prm1
  6737. // s2 = Ld_A s1[offset of JavascriptGenerator::frame]
  6738. // BrNotAddr_A s2 !nullptr $jumpTable
  6739. //
  6740. // $createInterpreterStackFrame:
  6741. // call helper
  6742. //
  6743. // Br $startOfFunc
  6744. //
  6745. // $jumpTable:
  6746. //
  6747. // s3 = Ld_A s2[offset of InterpreterStackFrame::m_reader.m_currentLocation]
  6748. // s4 = Ld_A s2[offset of InterpreterStackFrame::m_reader.m_startLocation]
  6749. // s5 = Sub_I4 s3 s4
  6750. // GeneratorResumeJumpTable s5
  6751. //
  6752. // $startOfFunc:
  6753. //
  6754. // s1 = Ld_A prm1
  6755. StackSym* genParamSym = StackSym::NewParamSlotSym(1, this->m_func);
  6756. this->m_func->SetArgOffset(genParamSym, LowererMD::GetFormalParamOffset() * MachPtr);
  6757. IR::SymOpnd* genParamOpnd = IR::SymOpnd::New(genParamSym, TyMachPtr, this->m_func);
  6758. IR::RegOpnd* genRegOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
  6759. IR::Instr* instr = IR::Instr::New(Js::OpCode::Ld_A, genRegOpnd, genParamOpnd, this->m_func);
  6760. this->m_irBuilder->AddInstr(instr, this->m_irBuilder->m_functionStartOffset);
  6761. // s2 = Ld_A s1[offset of JavascriptGenerator::frame]
  6762. IR::RegOpnd* genFrameOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
  6763. instr = IR::Instr::New(
  6764. Js::OpCode::Ld_A,
  6765. genFrameOpnd,
  6766. POINTER_OFFSET(genRegOpnd, Js::JavascriptGenerator::GetFrameOffset(), GeneratorFrame),
  6767. this->m_func
  6768. );
  6769. this->m_irBuilder->AddInstr(instr, this->m_irBuilder->m_functionStartOffset);
  6770. IR::LabelInstr* functionBegin = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  6771. LABELNAMESET(functionBegin, "GeneratorFunctionBegin");
  6772. IR::LabelInstr* jumpTable = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  6773. LABELNAMESET(jumpTable, "GeneratorJumpTable");
  6774. // If there is already a stack frame, generator function has previously begun execution - don't recreate, skip down to jump table
  6775. // BrNotAddr_A s2 nullptr $jumpTable
  6776. IR::BranchInstr* skipCreateInterpreterFrame = IR::BranchInstr::New(Js::OpCode::BrNotAddr_A, jumpTable, genFrameOpnd, IR::AddrOpnd::NewNull(this->m_func), this->m_func);
  6777. this->m_irBuilder->AddInstr(skipCreateInterpreterFrame, this->m_irBuilder->m_functionStartOffset);
  6778. // Create interpreter stack frame
  6779. IR::Instr* createInterpreterFrame = IR::Instr::New(Js::OpCode::GeneratorCreateInterpreterStackFrame, genFrameOpnd /* dst */, genRegOpnd /* src */, this->m_func);
  6780. this->m_irBuilder->AddInstr(createInterpreterFrame, this->m_irBuilder->m_functionStartOffset);
  6781. // Having created the frame, skip over the jump table and start executing from the beginning of the function
  6782. IR::BranchInstr* skipJumpTable = IR::BranchInstr::New(Js::OpCode::Br, functionBegin, this->m_func);
  6783. this->m_irBuilder->AddInstr(skipJumpTable, this->m_irBuilder->m_functionStartOffset);
  6784. // Label for start of jumpTable - where we look for the correct Yield resume point
  6785. // $jumpTable:
  6786. this->m_irBuilder->AddInstr(jumpTable, this->m_irBuilder->m_functionStartOffset);
  6787. // s3 = Ld_A s2[offset of InterpreterStackFrame::m_reader.m_currentLocation]
  6788. IR::RegOpnd* curLocOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
  6789. instr = IR::Instr::New(
  6790. Js::OpCode::Ld_A,
  6791. curLocOpnd,
  6792. POINTER_OFFSET(genFrameOpnd, Js::InterpreterStackFrame::GetCurrentLocationOffset(), InterpreterCurrentLocation),
  6793. this->m_func
  6794. );
  6795. this->m_irBuilder->AddInstr(instr, this->m_irBuilder->m_functionStartOffset);
  6796. // s4 = Ld_A s2[offset of InterpreterStackFrame::m_reader.m_startLocation]
  6797. IR::RegOpnd* startLocOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
  6798. instr = IR::Instr::New(
  6799. Js::OpCode::Ld_A,
  6800. startLocOpnd,
  6801. POINTER_OFFSET(genFrameOpnd, Js::InterpreterStackFrame::GetStartLocationOffset(), InterpreterStartLocation),
  6802. this->m_func
  6803. );
  6804. this->m_irBuilder->AddInstr(instr, this->m_irBuilder->m_functionStartOffset);
  6805. // s5 = Sub_I4 s3 s4
  6806. IR::RegOpnd* curOffsetOpnd = IR::RegOpnd::New(TyUint32, this->m_func);
  6807. instr = IR::Instr::New(Js::OpCode::Sub_I4, curOffsetOpnd, curLocOpnd, startLocOpnd, this->m_func);
  6808. this->m_irBuilder->AddInstr(instr, this->m_irBuilder->m_functionStartOffset);
  6809. // GeneratorResumeJumpTable s5
  6810. instr = IR::Instr::New(Js::OpCode::GeneratorResumeJumpTable, this->m_func);
  6811. instr->SetSrc1(curOffsetOpnd);
  6812. this->m_irBuilder->AddInstr(instr, this->m_irBuilder->m_functionStartOffset);
  6813. this->m_func->m_bailOutForElidedYieldInsertionPoint = instr;
  6814. this->m_irBuilder->AddInstr(functionBegin, this->m_irBuilder->m_functionStartOffset);
  6815. // Save this value for later use
  6816. this->m_generatorFrameOpnd = genFrameOpnd;
  6817. this->m_func->SetGeneratorFrameSym(genFrameOpnd->GetStackSym());
  6818. return this->m_irBuilder->m_lastInstr;
  6819. }
  6820. IR::RegOpnd*
  6821. IRBuilder::GeneratorJumpTable::BuildForInEnumeratorArrayOpnd(uint32 offset)
  6822. {
  6823. Assert(this->m_generatorFrameOpnd != nullptr);
  6824. IR::RegOpnd* forInEnumeratorArrayOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
  6825. IR::Instr* instr = IR::Instr::New(Js::OpCode::Ld_A, forInEnumeratorArrayOpnd,
  6826. POINTER_OFFSET(this->m_generatorFrameOpnd, Js::InterpreterStackFrame::GetOffsetOfForInEnumerators(), ForInEnumerators),
  6827. this->m_func
  6828. );
  6829. this->m_irBuilder->AddInstr(instr, offset);
  6830. return forInEnumeratorArrayOpnd;
  6831. }