IRBuilder.cpp 273 KB

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