IRBuilder.cpp 279 KB

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