IRBuilder.cpp 262 KB

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